#!/usr/bin/python

import sys
from   ..Hurricane        import *
from   ..CRL              import *
from   ..helpers.io       import ErrorMessage as Error
from   ..helpers          import staticInitialization, trace
from   .                  import getRules
from   .capacitorunit     import CapacitorUnit
from   .capacitormatrix   import CapacitorStack
from   .capacitorvrtracks import VerticalRoutingTracks


def toPhY    ( l ): return DbU.toPhysical  ( l, DbU.UnitPowerMicro )

def doBreak( level, message ):
    UpdateSession.close()
    Breakpoint.stop( level, message )
    UpdateSession.open()

staticInitialization( True )


## Routs two matched capacitors, C1 and C2, drawn in a capacitor matrix. Connections are put in place with reference to a given matching scheme. Elementary capacitor units are connected to horizontal and vertical routing tracks that represent top plates and bottom plates nets of C1 and C2 . Supported types of capacitors are Poly-Poly and Metal-Metal. Technologycal rules are provided by 350 nm AMS CMOS technology with three-four metal layers. Metal layers that are used for routing are placed similarly to horziontal-vertical (HV) symbolic Alliance CAD tool router, where horizontal metal channels are drawn in metal 2 and the vertical ones are in metal 3. Given a matrix of dimensions \f$ R*C \f$, the total number of vertical tracks is \f$ 2C+2 \f$ equivalent to \f$ C+1 \f$ couples, ensuring that every elementary capacitor is positioned between four vertical tracks, two from each side. In fact, every adjacent couple of these tracks represent top plates and bottom plates of C1 or C2 as shown in Figure 1.
#  \image html Layout.png "Layout" width=.1\linewidth
#  An elementary capacitor unit can be a part of C1 or C2 according to the matching scheme. However, to respect common-centroid layout specifications, for C1 and C2 to be equal, the matrix number of colums and number of rows must be both even. Addionnally, the number of elementary capacitors dedicated to C1 must be equal to those dedicated to C2. These two conditions are tested in one of the class methods. An exception is raised if at least one of the two is not respected.


class RoutMatchedCapacitor( VerticalRoutingTracks ):

    rules = getRules()


    ## A special method used to customize the class instance to an initial state in which :
    #  - the class attirbutes describing positions and dimensions of the layout are computed in dedicated class methods,
    #  - the attributes related to the capacitor matrix are copied from the \c CapacitorStack instance.
    #
    #  Position and dimensions attributes, also refered by layout variables,  in Figure 2, are defined below :
    # \param   device                     The Hurricane AMS device onto which the layout is drawn.
    # \param   capacitorInstance          Instance of \c CapacitorStack class.
    # \param   capacitor                  A nested list containing the matrix elements, which are \c CapacitorUnit objects.
    # \param   matchingScheme             A nested list, with equal dimensions as \c capacitor attribute, containing assignements of matrix elementary units to C1 and C2, identified by 1 and 2, respectively. Therefore, \c self.matchingScheme content is a succession of 1 and 2 values, defined as \ capacitor identifiers. For example, given a matrix of dimensions 2x2, the matching scheme can be \f$ [ [1,2], [1,2] ] or [ [2,1], [2,1] ] \f$. The first sub-list dictates that the first elementary capacitor, \f$ C_{00} \f$. The second element \f$ C_{01} \f$ is affected to C2 and so on. An immediate and obvious consequence to this, is that an error is raised if \c self.matchingSchem and \c self.capacitor dimensions are not identical or if \c self.matchingScheme content is different from supported capacitor identifiers, '1' and '2'.
    #
    # \param   capacitorType              Supported types of capacitors are MIM and PIP only. An exception is raised otherwise.
    # \param   abutmentBox                The matrix's abutment box.
    # \param   matrxiDim                  The matrix dimensions, also equal to \c self.matchingScheme nested list dimensions.
    # \param   abutmentBox_spacing        The spacing between elementary units in the matrix.
    #                                     It is computed in \c CapacitorStack and is reloaded
    #                                     in \c RoutMatchedCapacitor. \c self.abutmentBox_spacing
    #                                     includes, vertical routing tracks width and minimum
    #                                     allowed spacing between two adjacent ones.
    # \param   hRoutingLayer_width        The width of horizontal routing layers in metal 2, which connect capacitors plates to vertical routing tracks.
    # \param   vRoutingTrack_width        The width of vertical routing tracks in metal 3, which connects identical nets together ( ie : bottom plates of C1, top plates of C2, bottom plates of C2 and top plates of C2 ).
    # \param   hRoutingTrack_width        The width of horizontal routing tracks in metal 2, which connect identical vertical routing tracks together.
    # \param   minSpacing_hRoutingTrack   Minimum spacing between horizontal routing tracks.
    #                                     Wide metal 2 specifications are considered since metal 2
    #                                     dimensions may exceed 10 \f$ m\f$.
    #
    # \remark For more information about wide metal specifications, refer to ENG-183_rev8.pdf technology manual.
    #
    # \param   minimumPosition            The ordinate of the top plate's routing layer's
    #                                     bottom extremity after stretching.
    # \param   maximumPosition            The ordinate of the top plate's routing layer's
    #                                     top extremity, also equivalent to the top plate's
    #                                     top extremity.
    # \param   vRoutingTrackXCenter       A nested list of ordered dictionaries, with dimensions
    #                                     equal to \c self.matrixDim, containing abcissas of vertical
    #                                     routing tracks. All sub-lists' lengths are identical and
    #                                     are equal to 2. The first and second elements describe
    #                                     position of top plate track and bottom plate track,
    #                                     respectively.  For example, given a matrix of dimensions
    #                                     2x2, \c self.vRoutingTrackXCenter can be
    #                                     [[0, 2], [4,6], [8,10]] \f$ \mu m\f$.
    #                                     Elements of this nested list have particular indexing as
    #                                     described in Figure 2.
    #
    # \param   hRoutingtrackYCenter       A nested dictonary containing two keys, \c topTracks
    #                                     and \c bottomTracks. Each key contains as value a dictionary
    #                                     describing centers' ordinates of four parallel horizontal
    #                                     tracks. The reason why four tracks are needed on top and
    #                                     bottom positions of the matrix is that four nets are used,
    #                                     two for every capacitor \c Ci, were \c i is in [1,2].
    # \param   hRoutingLayerYCenter       A nested dicitonary containing two keys, \c top and
    #                                     \c bottom. Each key contains as value a dictionary
    #                                     describing centers' ordinates of horizontal routing layers.
    # \param   vRoutingTrackDict          A dictionary of routing tracks top and bottom extremities ordinates.
    # \param   topPlateStretching         Since not only the same metal 2 layer is used to draw top/bottom plates connections to vertical tracks but also the two plates are superimposed, the top plate's routing tracks is stretched. \c self.topPlateStretching is therefore the length added to top plate's routing layer in order to avoid short circuits between top and bottom plates routing to vertical tracks since the same metal is used for both.

    def __init__( self, vRTInstance ) :

        VerticalRoutingTracks.__init__( self, vRTInstance.capacitorInstance, vRTInstance.capacitor )

        if self.dummyRing == True :
            self.capacitor = [vRTInstance.capacitor[1][1:len(vRTInstance.capacitor[1])-1]]

            for i in range(2,self.matrixDim["rows"]+1):
                self.capacitor.append(vRTInstance.capacitor[i][1:len(vRTInstance.capacitor[1])-1])

            self.dummyRingCapacitor      = [ vRTInstance.capacitor[0], vRTInstance.capacitor[-1] ]
           #self.dummyRingVRLayersDict   = {}

        self.hRoutingLayer_width         =   0
        self.hRoutingTrack_width         =   vRTInstance.hRoutingTrack_width
        self.minSpacing_hRoutingTrack    =   0
        self.minimumPosition             =   0
        self.maximumPosition             =   0
        self.hRoutingtrackYCenter        = { "topTracks" : {} , "bottomTracks" : {} }
        self.hRoutingLayerYCenter        = { "topPlate"  : [] , "bottomPlate"  : [] }

        self.vRTInstance                 =   vRTInstance
        self.topPlateStretching          =   0

        return



    ## Draws the complete layout given the capacitor matrix. \c route method is succession
    #  of calls to user-defined methods inside a newly created \c Updatesession.
    #  The following tasks are excecuted :
    #  -# A nex \c UpdateSession is created,
    #  -# all required physical layers are loaded,
    #  -# technology rules are defined according to capacitor type,
    #  -# layout dimension parameters are computed,
    #  -# routing tracks and layers are drawn,
    #  -# top plates are stretched,
    #  -# all required cuts are drawn,
    #  -# The \c UpdateSession is closed.
    #
    # Meanwhile, an exception is raised when the entered \c capacitor is not a
    # capacitor matrix or if the capacitor type is unsupported.

    def route( self, bbMode=False ):

        UpdateSession.open()

        self.setRules()

        if not self.capacitorInstance.__isUnitCap__():
          if CapacitorStack.__isMatchingSchemeOK__(self):
            layersDict = self.setLayers        ()
            bondingBox = self.computeDimensions( bbMode )

            ab      = self.device.getAbutmentBox()
            trackNb = len(self.hRoutingtrackYCenter["topTracks"].keys())
            dY      = self.hpitch * trackNb

            trace( 101, '\tHeight before tracks enclosure: {0}\n'.format( DbU.getValueString(self.maximumPosition - self.minimumPosition) ))
            trace( 101, '\tHeight before tracks enclosure: {0}\n'.format( DbU.getValueString(ab.getHeight()) ))
            trace( 101, '\tminimum before adjust: {0}\n'.format( DbU.getValueString(self.minimumPosition) ))
            trace( 101, '\tdY: {0}\n'.format( DbU.getValueString(dY) ))

            firstVRTId = 't0'
            lastVRTId  = list(self.vRoutingTrackXCenter[-1].keys())[-1]
            firstIndex = int(firstVRTId[1])
            lastIndex  = int( lastVRTId[1])
            print( lastVRTId )
            if self.dummyRing:
              xMin = self.abutmentBox.getXMin()
              xMax = self.abutmentBox.getXMax()
            else:
              trackSpacing = (self.vRoutingTrack_width + self.vpitch + self.metal3Width)/2
              if firstIndex > len(self.vRoutingTrackXCenter[0]):
                  xMin = self.abutmentBox.getXMin() - trackSpacing
              else:
                  xMin = self.vRoutingTrackXCenter[0][firstVRTId] - trackSpacing

              if lastIndex > len(self.vRoutingTrackXCenter[-1]):
                  xMax = self.abutmentBox.getXMax() + trackSpacing
              else:
                  xMax = self.vRoutingTrackXCenter[-1][lastVRTId] + trackSpacing

            width       = xMax - xMin
            widthAdjust = width % (2*self.vpitch)
            if widthAdjust:
              widthAdjust = 2*self.vpitch - widthAdjust
              xMax += widthAdjust//2
              xMin -= widthAdjust//2

            self.device.setAbutmentBox( Box( int(xMin)
                                           , int(self.minimumPosition - dY)
                                           , int(xMax)
                                           , int(self.maximumPosition + dY )) )
            trace( 101, '\tHeight after tracks enclosure: {0}\n'.format( DbU.getValueString(self.device.getAbutmentBox().getHeight()) ))

            if not bbMode :
              self.drawHRLayers        ( layersDict["xPlateHRLayer" ] )
              self.drawHRoutingTracks  ( layersDict["hRoutingTracks"] )
              self.__stretchTopPlates__( self.capacitor
                                       , layersDict["xPlateRLayer"                     ] )
              self.drawCuts            ( layersDict["cut_hRoutingLayer_vRoutingTracks" ]
                                       , layersDict["cut_hRoutingTracks_vRoutingTracks"]
                                       , layersDict["cut_hRoutingLayer_topPlate"       ] )
              if self.dummyRing:
                self.routeDummyRing( layersDict ["xPlateVRLayer_dummyRing"         ]
                                   , layersDict["cut_hRoutingTracks_vRoutingTracks"] )
          else:
            raise Error( 1, [ 'RouteMatchedCapacitor.route(): Invalid matching scheme.'
                            , '(${0})'.format( self.matchingScheme ) ] )

        else:
          raise Error( 1, [ 'RouteMatchedCapacitor.route(): Input matrix parameter is incorrect.'
                          , '({0})'.format( self.matrixDim ) ] )

        UpdateSession.close  ()

        return bondingBox



    def routeDummyRing( self, routingLayer, cutLayer ):

        net                               = self.nets[-1][1]
        bottomPlateRLayer_width           = self.dummyRingCapacitor[0][0].getBotPlateRLayerWidth()
        topPlateRLayer_width              = self.dummyRingCapacitor[0][0].getTopPlateRLayerWidth()
       #self.computeDummyRingDimensions   ()
        self.routeLeftAndRightSides       (net, routingLayer, bottomPlateRLayer_width, topPlateRLayer_width                         )
        self.routeTopOrBottomSide         (net, "topSide"    , routingLayer          , bottomPlateRLayer_width, topPlateRLayer_width)
        self.routeTopOrBottomSide         (net, "bottomSide" , routingLayer          , bottomPlateRLayer_width, topPlateRLayer_width)
        self.drawDummyRing_hRTracks_Cuts  (net, "topSide"    , cutLayer                                                              )
        self.drawDummyRing_hRTracks_Cuts  (net, "bottomSide" , cutLayer                                                              )

        return



    def routeLeftAndRightSides( self, dummyNet, routingLayer, bottomPlateRLayer_width, topPlateRLayer_width ) :

        for i in range(0,2):
          bottomPlateLeftRLayerXCenter  = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateLeftRLayerXCenter()
          bottomPlateRightRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].getBotPlateRightRLayerXCenter()
          Vertical.create( dummyNet
                         , routingLayer
                         , bottomPlateLeftRLayerXCenter
                         , bottomPlateRLayer_width
                         , self.getVTrackYMin()
                         , self.getVTrackYMax() )
          Vertical.create( dummyNet
                         , routingLayer
                         , bottomPlateRightRLayerXCenter
                         , bottomPlateRLayer_width
                         , self.getVTrackYMin()
                         , self.getVTrackYMax() )

        for i in range(0,2):
          topPlateRLayerXCenter = self.dummyRingCapacitor[0][0 + i*(-1)].topPlateRLayerDict["XCenter"]
          Vertical.create( dummyNet
                         , routingLayer
                         , topPlateRLayerXCenter
                         , topPlateRLayer_width
                         , self.getVTrackYMin()
                         , self.getVTrackYMax() )

        return




    def routeTopOrBottomSide( self, dummyNet, side, routingLayer, bottomPlateRLayer_width, topPlateRLayer_width):

        if   side == "topSide" :
            dummyRingElement = self.dummyRingCapacitor[-1]
            dyTarget         = self.getVTrackYMax()
        elif side == "bottomSide" :
            dummyRingElement = self.dummyRingCapacitor[0]
            dyTarget         = self.getVTrackYMin()
        else : raise Error(1,'routeTopOrBottomSide() : side parameter must be either "topSide" or "bottomSide" : %s' %side)

        for j in range(1,len(self.dummyRingCapacitor[0])-1):
          bottomPlateLeftRLayerXCenter  = dummyRingElement[j].getBotPlateLeftRLayerXCenter()
          bottomPlateRightRLayerXCenter = dummyRingElement[j].getBotPlateRightRLayerXCenter()
          Vertical.create( dummyNet
                         , routingLayer
                         , bottomPlateLeftRLayerXCenter
                         , bottomPlateRLayer_width
                         , dummyRingElement[j].getBotPlateRLayerYMin()
                         , dyTarget )
          Vertical.create( dummyNet
                         , routingLayer
                         , bottomPlateRightRLayerXCenter
                         , bottomPlateRLayer_width
                         , dummyRingElement[j].getBotPlateRLayerYMin()
                         , dyTarget )

          topPlateRLayerXCenter = dummyRingElement[j].topPlateRLayerDict["XCenter"]
          Vertical.create( dummyNet
                         , routingLayer
                         , topPlateRLayerXCenter
                         , topPlateRLayer_width
                         , dummyRingElement[j].getTopPlateRLayerYMin()
                         , dyTarget )


        return



    ## Defines technology rules used to draw the layout. Some of the rules,
    #  namely those describing routing layers and tracks are applicable for
    #  both MIM and PIP capacitors. However, cuts rules are different.
    #
    #  \remark All \c CapacitorStack class rules are also reloaded in this class.
    #          An exception is raised if the entered capacitor type is unsupported.
    #
    #  \return a dictionary  with rules labels as keys and rules content as values.

    def setRules ( self ):

        VerticalRoutingTracks.setRules( self )

        self.minSpacing_hRoutingLayer                   = RoutMatchedCapacitor.rules.minSpacing_metbot
        self.minSpacing_hRoutingTrackCut                = RoutMatchedCapacitor.rules.minSpacing_cut2
        self.minSpacing_vRoutingTrackCut                = RoutMatchedCapacitor.rules.minSpacing_cut2
        self.minSpacing_hRoutingLayer_vRoutingTrack_cut = RoutMatchedCapacitor.rules.minSpacing_cut2

        if self.capacitorType == 'MIMCap':
          self.minWidth_hRoutingLayer_topPlate_cut     = RoutMatchedCapacitor.rules.minWidth_cut2
          self.minSpacing_hRoutingLayer_topPlate_cut   = RoutMatchedCapacitor.rules.minSpacing_cut2
          self.minEnclosure_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minEnclosure_metal2_cut2
        elif self.capacitorType == 'PIPCap':
          self.minWidth_hRoutingLayer_topPlate_cut     = RoutMatchedCapacitor.rules.minWidth_cut1
          self.minSpacing_hRoutingLayer_topPlate_cut   = RoutMatchedCapacitor.rules.minSpacing_cut1
          self.minEnclosure_hRoutingLayer_topPlate_cut = RoutMatchedCapacitor.rules.minEnclosure_metal2_cut1

        return


    ## Defines all physical layers used to draw the layout. Layers are loaded using \c DataBase API. The same routing layers are used for both capacitor types except cuts layers that connect top plates to vertical routing tracks. Basicaly, metal 2, meta 3, cut 1 and cut 2 are the ones defined.
    #  \return a dictionary composed of layers labels as keys and layers as values.

    def setLayers( self ):

        layersDict = {}

        layersDict["hRoutingTracks"                   ]  =  DataBase.getDB().getTechnology().getLayer("metal2" )
        layersDict["xPlateHRLayer"                    ]  =  DataBase.getDB().getTechnology().getLayer("metal2" )
        layersDict["xPlateRLayer"                     ]  =  CapacitorUnit.getLayers( self )["bottomPlateRLayer"]
        layersDict["cut_hRoutingTracks_vRoutingTracks"]  =  DataBase.getDB().getTechnology().getLayer("cut2"   )
        layersDict["cut_hRoutingLayer_vRoutingTracks" ]  =  DataBase.getDB().getTechnology().getLayer("cut2"   )
        layersDict["cut_hRoutingLayer_topPlate"       ]  =  DataBase.getDB().getTechnology().getLayer("cut2"   ) if self.capacitorType == 'MIMCap' else DataBase.getDB().getTechnology().getLayer("cut1")

        if self.dummyRing == True:
            layersDict["xPlateVRLayer_dummyRing"      ] =   DataBase.getDB().getTechnology().getLayer("metal3" ) if self.capacitorType == 'MIMCap' else DataBase.getDB().getTechnology().getLayer("metal1")

        return layersDict


    ## Computes, through simple instructions and functions calls, layout variables detailed in Figure 2.

    def computeDimensions ( self, bbMode ) :

        bondingBoxDimensions           =  {}
        self.hRoutingLayer_width       =  max( self.minWidth_hRoutingLayer, self.minWidth_hRoutingLayer_vRoutingTrack_cut + 2*self.minEnclosure_hRoutingLayer_vRoutingTrack_cut, self.minWidth_hRoutingLayer_topPlate_cut + 2*self.minEnclosure_hRoutingLayer_topPlate_cut )

        self.abutmentBox_spacing       = self.capacitorInstance.abutmentBox_spacing
        self.vRoutingTrack_spacing     = self.capacitorInstance.getVRoutingTrack_spacing()

        abutmentBoxXMin                = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["XMin"] #getAbutmentBox_spacing()
        abutmentBoxYMin                = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["YMin"] #getAbutmentBox_spacing()
        abutmentBoxYMax                = abutmentBoxYMin  + self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["height"] #getAbutmentBox_spacing()

        self.minimumPosition           =  self.vRTInstance.minimumPosition #abutmentBoxYMin - self.__setStretching__()
        self.maximumPosition           =  self.vRTInstance.maximumPosition #abutmentBoxYMax + self.__setStretching__()
        self.vRoutingTrackDict         =  self.vRTInstance.vRoutingTrackDict #self.minimumPosition - 4*self.hRoutingTrack_width - 4*self.minSpacing_hRoutingTrack

        translation1                   = self.vRoutingTrack_width/2 + self.vRoutingTrack_spacing
        translation2                   = translation1 + self.vRoutingTrack_width/2

        self.vRoutingTrackXCenter      = self.vRTInstance.vRoutingTrackXCenter #getvRoutingTrackXCenter()
       #print("vRoutingTrackXCenter",self.vRoutingTrackXCenter)
        if   bbMode == True :
            bondingBoxDimensions = self.computeBondingBoxDimInbbMode()

        elif bbMode == False :
            self.computeHRoutingTrackYCenter()
            self.computeHRLayerYCenter()

        else :raise Error(1, 'computeDimensions(): The bonding box mode parameter, "bbMode" must be either True or False : %s.' %bbMode )

       #print 'BOUNDING BOX:', bondingBoxDimensions
        return bondingBoxDimensions



    def computeBondingBoxDimInbbMode( self ):

        bondingBoxDimensions = {}

        abutmentBoxXMin                 = self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["XMin"]
        abutmentBoxXMax                 = abutmentBoxXMin + self.capacitorInstance.computeAbutmentBoxDimensions( self.abutmentBox_spacing )["width" ]

        bondingBoxDimensions["XMin"   ] = self.vRoutingTrackXCenter[0]["t0"] - self.vRoutingTrack_width/2

        if self.capacitorsNumber % 2 == 0 :
            factor                      = self.capacitorsNumber
        if self.capacitorsNumber % 2 != 0 :
            factor                      = self.capacitorsNumber + 1 if self.matrixDim["columns"] % 2 == 0 else self.capacitorsNumber - 1

        bondingBoxXMax                  = abutmentBoxXMax + factor*(self.vRoutingTrack_width + self.vRoutingTrack_spacing)
        bondingBoxDimensions["YMin"   ] = self.vRoutingTrackDict["YMin"]
        bondingBoxYMax                  = self.vRoutingTrackDict["YMax"]
        bondingBoxDimensions["width"  ] = bondingBoxXMax - bondingBoxDimensions["XMin"]
        bondingBoxDimensions["height" ] = bondingBoxYMax - bondingBoxDimensions["YMin"]
        bondingBoxDimensions["surface"] = bondingBoxDimensions["width"]*bondingBoxDimensions["height"]

        #bondingBox = Box( bondingBoxDimensions["XMin"], bondingBoxDimensions["YMin"], bondingBoxXMax, bondingBoxYMax )
        #self.device.setAbutmentBox( bondingBox )

        return bondingBoxDimensions


    ## Computes centers' ordinates of the eight horizontal routing tracks.
    #  The tracks include four on top and four on bottom of the matrix.
    #  To do the computations, fist, center of the first bottom or top track,
    #  given in Figure 2, is computed. Then, all adjacent three centers are
    #  deduced by simples translation of the first one. Translation quantity
    #  is equal to the sum of distance between adjacent routing tracks,
    #  self.hRoutingTracks_spacing, and half width of the routing track itself,
    #  \c self.hRoutingTrack_width.

    def computeHRoutingTrackYCenter( self ):

        self.hRoutingtrackYCenter                        = { "topTracks" : {} , "bottomTracks" : {} }
       #self.hRoutingtrackYCenter["topTracks"    ]["t0"] = self.maximumPosition \
       #                                                 + self.hRoutingTrack_width/2 + self.minSpacing_hRoutingTrack
       #self.hRoutingtrackYCenter["bottomTracks" ]["t0"] = self.minimumPosition \
       #                                                 - self.hRoutingTrack_width/2 - self.minSpacing_hRoutingTrack
        self.hRoutingtrackYCenter["topTracks"    ]["t0"] = self.maximumPosition
        self.hRoutingtrackYCenter["bottomTracks" ]["t0"] = self.minimumPosition

        keys = self.__setPlatesIds__()
        for k in range(1, len(keys)):
          trace( 101, '\tkeys[{0}] = {1}\n'.format( k, keys[k] ))
         #self.hRoutingtrackYCenter["topTracks"][keys[k]]         \
         #    = self.hRoutingtrackYCenter["topTracks"][keys[k-1]] \
         #    + (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
         #self.hRoutingtrackYCenter["bottomTracks" ][keys[k]]        \
         #    = self.hRoutingtrackYCenter["bottomTracks"][keys[k-1]] \
         #    - (self.hRoutingTrack_width + self.minSpacing_hRoutingTrack)
          self.hRoutingtrackYCenter["topTracks"][keys[k]]         \
              = self.hRoutingtrackYCenter["topTracks"][keys[k-1]] + self.hpitch
          self.hRoutingtrackYCenter["bottomTracks" ][keys[k]]        \
              = self.hRoutingtrackYCenter["bottomTracks"][keys[k-1]] - self.hpitch

        return


    ## Sets the stretching value of top plates. Then iteratively computes the centers of horizontal routing layer regarding top and bottom plates.

    def computeHRLayerYCenter ( self ):

        shortCircuitLists       = self.__findPossibleShortCircuits__()
        self.topPlateStretching = self.__setStretching__( )
       #print('        shortCircuitLists',        shortCircuitLists)
        for i in range( 0,self.matrixDim["rows"] ):
           #print("i",i)
           #print("rows", self.matrixDim["rows"])
           #print("rowsCap", len(self.capacitor))

            if shortCircuitLists[i][0] == 0 :
                self.hRoutingLayerYCenter["bottomPlate"].append( [self.capacitor[i][0].getBottomPlateRightCutYMax ()] )
            else :
                bottomPlateYCenter0                   = [(self.capacitor[i][0].getBottomPlateRightCutYMax () + self.capacitor[i][0].getBottomPlateRightCutYMin() ) /2 ]
                self.hRoutingLayerYCenter["bottomPlate"].append(bottomPlateYCenter0)

            topPlateYCenter                           = self.__setStretchingDySourceDyTarget__( self.capacitor[i][0], self.topPlateStretching )[1] + self.hRoutingLayer_width/2
            self.hRoutingLayerYCenter["topPlate"   ].append( [topPlateYCenter ] )

            for j in range( 1,self.matrixDim["columns"] ):
                topPlateYCenter                       = self.__setStretchingDySourceDyTarget__( self.capacitor[i][j], self.topPlateStretching )[1] + self.hRoutingLayer_width/2
                if shortCircuitLists[i][j] == 0 :
                    self.hRoutingLayerYCenter["bottomPlate"][i].append( self.capacitor[i][j].getBottomPlateRightCutYMax () )
                    self.hRoutingLayerYCenter["topPlate"   ][i].append( topPlateYCenter )
                else :
                   bottomPlateYCenter                 = (self.capacitor[i][j].getBottomPlateRightCutYMax() + self.capacitor[i][j].getBottomPlateRightCutYMin()) /2
                   topPlateYCenter2                   = topPlateYCenter + self.minSpacing_hRoutingLayer + self.hRoutingLayer_width
                   self.hRoutingLayerYCenter["bottomPlate"][i].append(bottomPlateYCenter)
                   self.hRoutingLayerYCenter["topPlate"   ][i].append(topPlateYCenter2)

       #print('self.hRoutingLayerYCenter',self.hRoutingLayerYCenter)
        return

    def computeLayoutDimensionsInbbMode( self ):

        bondingBoxDict            = {}
        bondingBoxDict["YMin"   ] =  self.hRoutingtrackYCenter["bottomTracks"]["botB"] - self.hRoutingTrack_width/2
        bondingBoxDict["XMin"   ] =  self.vRoutingTrackXCenter[0 ][0]                  - self.vRoutingTrack_width/2
        bondingBoxDict["height" ] =  self.hRoutingtrackYCenter["topTracks"   ]["botB"] + self.hRoutingTrack_width/2 - bondingBoxDict["YMin"]
        bondingBoxDict["width"  ] =  self.vRoutingTrackXCenter[-1][1]                  + self.vRoutingTrack_width/2 - bondingBoxDict["XMin"]

        self.bondingBox           = Box( bondingBoxDict["XMin"], bondingBoxDict["YMin"], bondingBoxDict["XMin"] + bondingBoxDict["width"], bondingBoxDict["YMin"] + bondingBoxDict["height"] )

        return bondingBoxDict


   #def computeDummyRingDimensions( self ):
   #    for key in self.vRoutingTrackDict.keys():
   #      self.dummyRingVRLayersDict[key] = self.vRoutingTrackDict[key]
   #    return


    ##  Iteratively draws horizontal routing tracks on top and bottom positions of the matrix
    #   using physical layer \c routingTracksLayer.

    def drawHRoutingTracks( self , routingTracksLayer ):

        lastVRTId   = list(self.vRoutingTrackXCenter[-1].keys())[-1]
        firstVRTId  = "t0"
       #doDummyRing = 1 if self.dummyRing == True else 0
       #dxSource    = self.vRoutingTrackXCenter[0][firstVRTId] - self.vRoutingTrack_width/2 if not self.dummyRing else self.abutmentBox.getXMin()
       #dxTarget    = self.vRoutingTrackXCenter[-1][lastVRTId] + self.vRoutingTrack_width/2 if not self.dummyRing else self.abutmentBox.getXMax()
        dxSource    = self.device.getAbutmentBox().getXMin()
        dxTarget    = self.device.getAbutmentBox().getXMax()

        for i in self.hRoutingtrackYCenter.keys():
          for j in self.hRoutingtrackYCenter[i].keys():
            if   j[0] == 't' : net = self.nets[ int(j[1]) ][ 0 ]
            elif j[0] == 'b' : net = self.nets[ int(j[1]) ][ 1 ]
            else:              net = self.nets[ -1        ][ 1 ]

            horizontal = Horizontal.create( net
                                          , routingTracksLayer
                                          , int(self.hRoutingtrackYCenter[i][j])
                                          , int(self.hRoutingTrack_width)
                                          , int(dxSource)
                                          , int(dxTarget) )
            NetExternalComponents.setExternal( horizontal )
        return


    ## Iteratively draws the horizontal routing layers starting with bottom left elementary capacitor \f$ C_{00} \f$.

    def drawHRLayers( self, xPlateRLayer ) :

        for i in range( 0,self.matrixDim["rows"] ):
            for j in range( 0,self.matrixDim["columns"] ):

                [ t , b ] = [  self.nets[self.matchingScheme[i][j]][0], self.nets[self.matchingScheme[i][j]][1] ]
                dxDict                           =    self.__computeConnections__( i,j, self.matchingScheme[i][j] )

                Horizontal.create ( t
                                  , xPlateRLayer
                                  , int(self.hRoutingLayerYCenter["topPlate"   ][i][j])
                                  , int(self.hRoutingLayer_width)
                                  , int(dxDict["topPlate"    ][ "source" ])
                                  , int(dxDict["topPlate"    ][ "target" ]) )
                Horizontal.create ( b
                                  , xPlateRLayer
                                  , int(self.hRoutingLayerYCenter["bottomPlate"][i][j])
                                  , int(self.hRoutingLayer_width)
                                  , int(dxDict["bottomPlate" ][ "source" ])
                                  , int(dxDict["bottomPlate" ][ "target" ]) )

        return


    ## Draws all required cuts using physical layers :
    # - \c layer_hRTrack_hRLayer to connect bottom plates to vertical routing tracks,
    # - \c layer_tracksCut to connect vertical routing tracks to horizontal ones,
    # - \c layer_topPlateCut to connect top plates to vertical routing tracks.
    #  ALso in \c drawCuts, nUmber of maximum cuts number on every layer is computed and cuts enclosure is adjusted according to layer's width.

    def drawCuts( self, layer_hRTrack_hRLayer, layer_tracksCut, layer_topPlateCut ):

        cutNumber                   =  CapacitorUnit.cutMaxNumber( self, self.vRoutingTrack_width, self.minWidth_vRoutingTrackCut, self.minSpacing_vRoutingTrackCut , self.minEnclosure_vRoutingTrackCut  )
        enclosure_hRoutingTrack_cut = (self.vRoutingTrack_width - cutNumber*self.minWidth_hRoutingTrackCut - (cutNumber - 1)*self.minSpacing_hRoutingTrackCut)/2

        self.drawCuts_vRoutingTrack_HRLayer       ( layer_hRTrack_hRLayer, cutNumber, enclosure_hRoutingTrack_cut )
        self.drawCuts_vRoutingTrack_hRoutingTrack ( layer_tracksCut      , cutNumber, enclosure_hRoutingTrack_cut )
        self.drawCuts_stretchedTopPlate           ( layer_topPlateCut                                             )

        return



    def drawCuts_vRoutingTrack_HRLayer( self, cutLayer, cutNumber, enclosure_cut  ):

        [ vRoutingTrackXCenter, cutXMin ] = [{}, {}]

        for i in range( 0, self.matrixDim["rows"] ):
            for j in range( 0, self.matrixDim["columns"] ):

                if ( j % 2 == 0 ):
                    leftVRTIds   = self.capacitorIds[0:self.capacitorsNumber//2]                       if (self.capacitorsNumber % 2 == 0)        else self.capacitorIds[0: int(self.capacitorsNumber//2+1)]
                    rightVRTIds  = self.capacitorIds[self.capacitorsNumber//2 : self.capacitorsNumber] if (self.capacitorsNumber % 2 == 0)        else self.capacitorIds[int(self.capacitorsNumber//2+1) : self.capacitorsNumber]

                else:
                    leftVRTIds   = self.capacitorIds[self.capacitorsNumber//2 : self.capacitorsNumber] if (self.capacitorsNumber % 2 == 0)        else self.capacitorIds[int(self.capacitorsNumber//2+1) : self.capacitorsNumber]
                    rightVRTIds  = self.capacitorIds[0:self.capacitorsNumber//2]                       if (self.capacitorsNumber % 2 == 0)        else self.capacitorIds[0: int(self.capacitorsNumber//2+1)]

                index1           = j                                                                  if self.matchingScheme[i][j] in leftVRTIds else j+1

                [topPlateLabel, bottomPlateLabel  ]     = [self.__setPlatesLabels__(i,j)["t"] , self.__setPlatesLabels__(i,j)["b"]]
                vRoutingTrackXCenter["topPlate"   ]     =  self.vRoutingTrackXCenter[index1][topPlateLabel + str( self.matchingScheme[i][j] )]
                vRoutingTrackXCenter["bottomPlate"]     =  self.vRoutingTrackXCenter[index1][bottomPlateLabel + str( self.matchingScheme[i][j] )]

                cutXMin["topPlate"   ]                  =  vRoutingTrackXCenter["topPlate"   ] - self.vRoutingTrack_width/2 + enclosure_cut + self.minWidth_hRoutingTrackCut/2
                cutXMin["bottomPlate"]                  =  vRoutingTrackXCenter["bottomPlate"] - self.vRoutingTrack_width/2 + enclosure_cut + self.minWidth_hRoutingTrackCut/2
                [ t , b ]        = [ self.nets[self.matchingScheme[i][j]][0] , self.nets[self.matchingScheme[i][j]][1] ]

                self.drawOneCut_vRoutingTrack_HRLayer( t, cutLayer, cutXMin["topPlate"   ],  self.hRoutingLayerYCenter["topPlate"   ][i][j], cutNumber )
                self.drawOneCut_vRoutingTrack_HRLayer( b, cutLayer, cutXMin["bottomPlate"],  self.hRoutingLayerYCenter["bottomPlate"][i][j], cutNumber )

        return



    ## Draws one cut, in layer \c cutLayer, in order to connect a vertical routing track, at position \c cutXMin in metal 2, and a horizontal routing track, at position \c cutYMin in metal 3.
    def drawOneCut_vRoutingTrack_HRLayer( self, net, cutLayer, cutXMin, cutYMin, cutNumber ):

        CapacitorUnit.cutLine(self,net,cutLayer,cutXMin,cutYMin,self.minWidth_hRoutingLayer_vRoutingTrack_cut,self.minWidth_hRoutingLayer_vRoutingTrack_cut,self.minSpacing_hRoutingLayer_vRoutingTrack_cut,cutNumber,'horizontal')
        return



    ## Draws cuts to connect vertical routing tracks in metal 2 and horizontal routing tracks in metal 3.
    def drawCuts_vRoutingTrack_hRoutingTrack( self,cutLayer, cutNumber, enclosure_cut ):

        keysList   = list(self.hRoutingtrackYCenter.keys())

        for i in range(0, len(self.vRoutingTrackXCenter) ):
            for k in self.vRoutingTrackXCenter[i]:
                if self.vRoutingTrackXCenter[i][k] != None :
                    for l in range(0, 2) :
                        net     = self.nets[ int(k[1]) ][0] if k[0] == 't' else self.nets[ int(k[1]) ][1]
                        cutXMin = self.vRoutingTrackXCenter[i][k] - self.vRoutingTrack_width/2 + enclosure_cut + self.minWidth_hRoutingTrackCut/2
                        CapacitorUnit.cutLine(self,net,cutLayer,cutXMin,self.hRoutingtrackYCenter[keysList[l]][k],self.minWidth_hRoutingTrackCut,self.minWidth_hRoutingTrackCut,self.minSpacing_hRoutingTrackCut,cutNumber,'horizontal')

        return



    #  \param     cutLayer
    def drawCuts_stretchedTopPlate( self, cutLayer ):

        layer_width                 = self.capacitor[0][0].getTopPlateRLayerWidth()
        cutNumber                   = CapacitorUnit.cutMaxNumber( self, layer_width , self.minWidth_hRoutingLayer_topPlate_cut, self.minSpacing_hRoutingLayer_topPlate_cut , self.minEnclosure_hRoutingLayer_topPlate_cut  )
        enclosure_hRoutingTrack_cut = (layer_width - cutNumber*self.minWidth_hRoutingLayer_topPlate_cut - (cutNumber - 1)*self.minSpacing_hRoutingLayer_topPlate_cut)/2

        for i in range(0, self.matrixDim["rows"] ):
            for j in range(0, self.matrixDim["columns"] ):

                tNet  = self.nets[self.matchingScheme[i][j]][0]
                cutXMin      = self.capacitor[i][j].getTopPlateRLayerXMin() + enclosure_hRoutingTrack_cut + self.minWidth_hRoutingLayer_topPlate_cut/2
                CapacitorUnit.cutLine( self, tNet, cutLayer, cutXMin , self.hRoutingLayerYCenter["topPlate"][i][j] , self.minWidth_hRoutingLayer_topPlate_cut, self.minWidth_hRoutingLayer_topPlate_cut, self.minSpacing_hRoutingLayer_topPlate_cut, cutNumber, 'horizontal' )

        return


    def drawDummyRing_hRTracks_Cuts( self, dummyNet, side, cutLayer ):

        if   side == "topSide" :
            dummyRingElement = self.dummyRingCapacitor[-1]
            key              = "topTracks"
        elif side == "bottomSide" :
            dummyRingElement = self.dummyRingCapacitor[0]
            key              = "bottomTracks"
        else : raise Error(1,'routeTopOrBottomSide() : side parameter must be either "topSide" or "bottomSide" : %s' %side)

        topPlateLayer_width        = dummyRingElement[0].getTopPlateRLayerWidth()
        bottomPlateLayer_width     = dummyRingElement[0].getBotPlateRLayerWidth()

        topPlateCutNumber          =  CapacitorUnit.cutMaxNumber( self, topPlateLayer_width   , self.minWidth_vRoutingTrackCut, self.minSpacing_vRoutingTrackCut , self.minEnclosure_vRoutingTrackCut  )
        bottomPlateCutNumber       =  CapacitorUnit.cutMaxNumber( self, bottomPlateLayer_width, self.minWidth_vRoutingTrackCut, self.minSpacing_vRoutingTrackCut , self.minEnclosure_vRoutingTrackCut  )

        topPlateCutEnclosure       = (topPlateLayer_width    - topPlateCutNumber   *self.minWidth_vRoutingTrackCut - (topPlateCutNumber    - 1)*self.minSpacing_vRoutingTrackCut)/2
#        bottomPlateCutEnclosure    = (bottomPlateLayer_width - bottomPlateCutNumber*self.minWidth_vRoutingTrackCut - (bottomPlateCutNumber - 1)*self.minSpacing_vRoutingTrackCut)/2

        netsDistribution           = self.__setPlatesIds__()

       #print("netsDistribution2",netsDistribution)
       #print("self.hRoutingtrackYCenter",self.hRoutingtrackYCenter)
        for j in range(0,len(dummyRingElement)):
            topPlateCutXCenter         = dummyRingElement[j].getTopPlateRLayerXMin     () + topPlateCutEnclosure    + self.minWidth_vRoutingTrackCut/2
            bottomPlateLeftCutXCenter  = dummyRingElement[j].getBottomPlateLeftCutXMin() #dummyRingElement[j].getBotPlateLeftRLayerXMin () + bottomPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2
            bottomPlateRightCutXCenter = dummyRingElement[j].getBottomPlateRightCutXMin() #dummyRingElement[j].getBotPlateRightRLayerXMin() + bottomPlateCutEnclosure + self.minWidth_vRoutingTrackCut/2f

            CapacitorUnit.cutLine( self, dummyNet, cutLayer, topPlateCutXCenter        , self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_vRoutingTrackCut,self.minWidth_vRoutingTrackCut,self.minSpacing_vRoutingTrackCut,topPlateCutNumber,'horizontal')
            CapacitorUnit.cutLine( self, dummyNet, cutLayer, bottomPlateLeftCutXCenter , self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_vRoutingTrackCut,self.minWidth_vRoutingTrackCut,self.minSpacing_vRoutingTrackCut,bottomPlateCutNumber,'horizontal')
            CapacitorUnit.cutLine( self, dummyNet, cutLayer, bottomPlateRightCutXCenter, self.hRoutingtrackYCenter[key][netsDistribution[-1]] , self.minWidth_hRoutingTrackCut,self.minWidth_hRoutingTrackCut,self.minSpacing_hRoutingTrackCut,bottomPlateCutNumber,'horizontal')

        return



    ## Iteratively performs top plates stretching for the capacitor matrix.
    #  Vertical segments are connected to top plate routing layer.
    #  \param    capacitor    Capacitor matrix.
    #  \param    rlayer       Layer of the drawn vertical rectangle.
    def __stretchTopPlates__( self, capacitor, rlayer ):

        for i in range( 0, self.matrixDim["rows"] ):
            for j in range( 0, self.matrixDim["columns"] ):

                t = self.nets[self.matchingScheme[i][j]][0]
               #print('t',t)
                self.__stretchTopPlateCompactCap__( t , capacitor[i][j], rlayer, j )

        return



    ## Draws vertical stretched layers for a given elementary capacitor.
    def __stretchTopPlateCompactCap__( self, net, capacitor, routingLayer, j = 0 ):

        topPlateRLayer_width    = capacitor.getTopPlateRLayerWidth()
        topPlateRLayerXCenter   = capacitor.getTopPlateRLayerXCenter()
        [ dySource , dyTarget ] = self.__setStretchingDySourceDyTarget__( capacitor, self.topPlateStretching )

        Vertical.create( net
                       , routingLayer
                       , int(topPlateRLayerXCenter)
                       , int(topPlateRLayer_width)
                       , int(dySource)
                       , int(dyTarget) )
        return



    ## Sets the abcissas of the extremities of the vertical stretching to be applied to capacitor's top plates for a given elementary capacitor in the matrix.
    #  \param    capacitor  .values()  Elementary unit capacitor.
    #  \param    deltay       Stretching value.
    #  \return A list that contains \c dySource and \c dyTarget as top extremity and bottom extermity, respectively.
    def __setStretchingDySourceDyTarget__( self, capacitor, deltay ):

        dySource = capacitor.getTopPlateRLayerYMin()
        dyTarget = dySource - deltay

        return [ dySource , dyTarget ]


    ## Computes horizontal routing layers source and target abcissas for top and bottom plates connections to its associated routing track.
    #  \param    (i,j)                 row and column indexes, respectively, in the matrix which describe the elementary capacitor position in the matrix.
    #  \param    capacitorIdentifier   equal to '1' if C1 and '2' if C2.
    #  \return   A nested dicitionary. The overal dictionary is composed of keys equal to \c topPlate and \d bottomPlate and values equal to sub-dictionaries. The sub-dictionaries, are in their turn composed of two keys standing for the abcissa of the source and the abcissa of the target.
    #  \remark   Naturally, an exception is raised if an unsupported capacitor identifier is given.

    def __computeConnections__( self, i,j, capacitorIdentifier ):

        if capacitorIdentifier in self.capacitorIds :

            dxDict = { "bottomPlate": {}, "topPlate": {} }

            if ( j % 2 == 0 ):
                leftVRTIds   = self.capacitorIds[0                       :self.capacitorsNumber//2] if (self.capacitorsNumber % 2 == 0)          else self.capacitorIds[0                              : int(self.capacitorsNumber/2+1)]
                rightVRTIds  = self.capacitorIds[self.capacitorsNumber//2 : self.capacitorsNumber  ] if (self.capacitorsNumber % 2 == 0)          else self.capacitorIds[int(self.capacitorsNumber//2+1) : self.capacitorsNumber         ]

            else:
                leftVRTIds   = self.capacitorIds[self.capacitorsNumber//2 : self.capacitorsNumber   ] if (self.capacitorsNumber % 2 == 0)          else self.capacitorIds[int(self.capacitorsNumber//2+1) : self.capacitorsNumber         ]
                rightVRTIds  = self.capacitorIds[0                       : self.capacitorsNumber//2 ] if (self.capacitorsNumber % 2 == 0)          else self.capacitorIds[0                              : int(self.capacitorsNumber//2+1)]


            [topPlateLabel, bottomPlateLabel  ] = [self.__setPlatesLabels__(i,j)["t"] , self.__setPlatesLabels__(i,j)["b"]]

            dxDict["topPlate"    ][ "source" ]  =  self.capacitor[i][j].getTopPlateRLayerXMax     ()  if  self.matchingScheme[i][j] in leftVRTIds  else  self.capacitor[i][j].getTopPlateRLayerXMin()
            dxDict["topPlate"    ][ "target" ]  =  self.__findHRLDyTrarget__( i,j, topPlateLabel, leftVRTIds, rightVRTIds )

            dxDict["bottomPlate" ][ "source" ]  =  self.capacitor[i][j].getBotPlateLeftRLayerXMax ()  if  self.matchingScheme[i][j] in leftVRTIds  else  self.capacitor[i][j].getBotPlateRightRLayerXMin ()
#            bottomPlateLabel = 'b' if self.dummyElement == False or not( self.__isCapacitorAdummy__(capacitorIdentifier) ) else 't'
           #print("bottomPlateLabel",bottomPlateLabel)
            dxDict["bottomPlate" ][ "target" ]  =  self.__findHRLDyTrarget__( i, j, bottomPlateLabel, leftVRTIds, rightVRTIds )

        else : raise Error(1, '__computeConnections__(): Unknown capacitor Id : %s.' %capacitorIdentifier )

       #print('dxDict',dxDict)
        return dxDict


    def __isCapacitorAdummy__( self, capacitorIdentifier ) :

        state = False
        if self.dummyElement == True :
            if capacitorIdentifier == self.capacitorIds[-1] : state = True
        else : raise Error(1,'The matrix contains no dummies because dummy element is "False".')

        return state



    def __setPlatesLabels__( self, i, j ):

        platesLabels        = {}
        capacitorIdentifier = self.matchingScheme[i][j]
        platesLabels["t"]   = 't'
        platesLabels["b"]   = 'b' if self.dummyElement == False or not( self.__isCapacitorAdummy__(capacitorIdentifier) ) else 't'

        return platesLabels


    def __findHRLDyTrarget__( self, i,j, plateLabel, leftVRTIds, rightVRTIds  ):

        if plateLabel in ['t','b'] :
            plateIndex = self.matchingScheme[i][j]

            [ doLeft , doRight ] = [1,0]      if   self.matchingScheme[i][j] in leftVRTIds else [0,1]
            xCenterList          = leftVRTIds if [ doLeft , doRight ] == [1,0]             else rightVRTIds
            index1               = j          if [ doLeft , doRight ] == [1,0]             else j+1

            for key in self.vRoutingTrackXCenter[index1].keys() :
                if key == plateLabel + str(plateIndex) :
                    index2 = key
                    break

        else : raise Error(1,'__findHRLDyTrarget__() : Plate label must be "t" for top plate and "b" for bottom plate. The given label is : %s.' %plateLabel)

        return self.vRoutingTrackXCenter[index1][index2] - doLeft*self.vRoutingTrack_width/2 + doRight*self.vRoutingTrack_width/2



    def __setPlatesIds__( self ):

        keys = []
        for k in range(0, len(self.nets)):
            keys.append( 't' + str(k) )
            keys.append( 'b' + str(k) )

        if self.dummyRing == True or self.dummyElement == True : keys = keys[0:len(keys)-1]

        return keys


    def __findPossibleShortCircuits__( self ):

        shortCircuitLists = []
        self.vRTsDistribution = self.vRTInstance.vRTsDistribution
        for i in range(0, self.matrixDim["rows"]):
            shortCircuitLists.append([0])

            for j in range(0, self.matrixDim["columns"]):
                shortCircuitLists[i].append(0)
        for i in range(0, self.matrixDim["rows"]):
            for j in range(0, self.matrixDim["columns"]-1):
               #print('self.vRTsDistribution',self.vRTsDistribution)
                if self.matchingScheme[i][j] in self.vRTsDistribution[j+1] and self.matchingScheme[i][j+1] in self.vRTsDistribution[j+1] and self.matchingScheme[i][j] > self.matchingScheme[i][j+1] : shortCircuitLists[i][j] = 1

        return shortCircuitLists




def scriptMain( **kw ):

    editor = None
    if 'editor' in kw and kw['editor']:
        editor = kw['editor']

    UpdateSession.open()
    Device = AllianceFramework.get().createCell( 'capacitor' )
    Device.setTerminal( True )

    bottomPlate_net0 = Net.create( Device, 'b0' )
    bottomPlate_net1 = Net.create( Device, 'b1' )
    bottomPlate_net2 = Net.create( Device, 'b2' )
    bottomPlate_net3 = Net.create( Device, 'b3' )
    bottomPlate_net0.setExternal( True )
    bottomPlate_net1.setExternal( True )
    bottomPlate_net2.setExternal( True )
    bottomPlate_net3.setExternal( True )
    b0  = Device.getNet("b0")
    b1  = Device.getNet("b1")
    b2  = Device.getNet("b2")
    b3  = Device.getNet("b3")

    topPlate_net0    = Net.create( Device, 't0' )
    topPlate_net1    = Net.create( Device, 't1' )
    topPlate_net2    = Net.create( Device, 't2' )
    topPlate_net3    = Net.create( Device, 't3' )
    topPlate_net0.setExternal( True )
    topPlate_net1.setExternal( True )
    topPlate_net2.setExternal( True )
    topPlate_net3.setExternal( True )
    t0     = Device.getNet("t0")
    t1     = Device.getNet("t1")
    t2     = Device.getNet("t2")
    t3     = Device.getNet("t3")

    if editor:
        UpdateSession.close()
        editor.setCell( Device )
        editor.fit()
        UpdateSession.open()

    nets   = [[t0, b0] , [t1, b1], [t2, b2] ] # [t3, b3] ]
    capacitorInstance = CapacitorStack( Device, [372,1116], 'MIMCap', [0,0], nets, unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme =  [ [1,1,1,0] , [0,1,1,1] , [1,1,1,0] , [0,1,1,1] ] , dummyRing = True )#dummyRing = True)

  #  capacitorInstance = CapacitorStack( Device, [279,1023, 186], 'MIMCap', [0,0], nets, unitCap = 93, matrixDim = [4,4], matchingMode = True, matchingScheme =  [ [1,1,1,0] , [0,1,2,1] , [1,1,1,0] , [2,1,1,1] ], dummyElement = True, dummyRing = True )#dummyRing = True)
  #  capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, unitCap = 50, matchingMode = True, matchingScheme =  [ ['C2','C1','C2','C1','C1'] , ['C1','C2','C1','C2','C2'] , ['C1','C2','C2','C2', 'C1'] , ['C1','C2','C2','C1', 'C1'], ['C2','C2','C2','C2','C2'] ] )
  #  capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, unitCap = 93, matchingMode = True, matchingScheme =  [ ['C2','C2','C2','C2'] , ['C1','C2','C2','C2'] , ['C1','C2','C2','C2'] , ['C1','C2','C2','C1'] ] )
  #  capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, unitCap = 93, matchingMode = True, matchingScheme =  [ ['C2','C2','C1','C2'] , ['C1','C2','C2','C1'] , ['C1','C1','C2','C3'] , ['C1','C1','C2','C3'] ] )
  #  capacitorInstance = CapacitorStack( Device, capacitance, 'MIMCap', [0,0], nets, matrixDim = [5,5] , matchingMode = True, matchingScheme =  [ ['C2','C1','C2','C3','C1'] , ['C1','C2','C4','C3','C2'] , ['C4','C2','C2','C3', 'C1'] , ['C1','C2','C2','C1', 'C1'], ['C2','C2','C3','C2','C4'] ] )

    capacitor         = capacitorInstance.create()
   #print('capa',capacitor)

    capWithVRT        = VerticalRoutingTracks( capacitorInstance, capacitor, True )
    capWithVRT.create()

    routedCap         = RoutMatchedCapacitor( capWithVRT )
    surface           = routedCap.route()
   #print('routeMatchedCap bbMode', surface)
   #print('width', toPhY(surface["width"]))
   #print('height', toPhY(surface["height"]))

    AllianceFramework.get().saveCell( Device, Catalog.State.Views )

    return True