Changeset 23787


Ignore:
Timestamp:
03/11/19 03:04:31 (6 years ago)
Author:
bdef
Message:

CHG pep8 ompliance and treatment of hydrology colapse

Location:
issm/trunk-jpl/src/m
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • issm/trunk-jpl/src/m/classes/model.py

    r23771 r23787  
    7171#}}}
    7272
     73
    7374class model(object):
    74         #properties
    75         def __init__(self):#{{{
    76 
    77                 # classtype=model.properties
    78 
    79                 # for classe in dict.keys(classtype):
    80                 #       print classe
    81                 #       self.__dict__[classe] = classtype[str(classe)]
    82 
    83                 self.mesh           = mesh2d()
    84                 self.mask           = mask()
    85                 self.geometry       = geometry()
    86                 self.constants      = constants()
    87                 self.smb            = SMBforcing()
    88                 self.basalforcings  = basalforcings()
    89                 self.materials      = matice()
    90                 self.damage         = damage()
    91                 self.friction       = friction()
    92                 self.flowequation   = flowequation()
    93                 self.timestepping   = timestepping()
    94                 self.initialization = initialization()
    95                 self.rifts          = rifts()
    96                 self.slr            = slr()
    97 
    98                 self.debug    = debug()
    99                 self.verbose  = verbose()
    100                 self.settings = issmsettings()
    101                 self.toolkits = toolkits()
    102                 self.cluster  = generic()
    103 
    104                 self.balancethickness = balancethickness()
    105                 self.stressbalance    = stressbalance()
    106                 self.groundingline    = groundingline()
    107                 self.hydrology        = hydrologyshreve()
    108                 self.masstransport    = masstransport()
    109                 self.thermal          = thermal()
    110                 self.steadystate      = steadystate()
    111                 self.transient        = transient()
    112                 self.levelset         = levelset()
    113                 self.calving          = calving()
    114                 self.frontalforcings  = frontalforcings()
    115                 self.gia              = giaivins()
    116                 self.love                                                       = fourierlove()
    117                 self.esa                                                        = esa()
    118                 self.autodiff                                   = autodiff()
    119                 self.inversion                          = inversion()
    120                 self.qmu                                                        = qmu()
    121                 self.amr                                                        = amr()
    122 
    123                 self.results          = results()
    124                 self.outputdefinition = outputdefinition()
    125                 self.radaroverlay     = radaroverlay()
    126                 self.miscellaneous    = miscellaneous()
    127                 self.private          = private()
    128                 #}}}
    129         def properties(self):    # {{{
    130                 # ordered list of properties since vars(self) is random
    131                 return ['mesh',
    132                         'mask',
    133                         'geometry',
    134                         'constants',
    135                         'smb',
    136                         'basalforcings',
    137                         'materials',
    138                         'damage',
    139                         'friction',
    140                         'flowequation',
    141                         'timestepping',
    142                         'initialization',
    143                         'rifts',
    144                         'slr',
    145                         'debug',
    146                         'verbose',
    147                         'settings',
    148                         'toolkits',
    149                         'cluster',
    150                         'balancethickness',
    151                         'stressbalance',
    152                         'groundingline',
    153                         'hydrology',
    154                         'masstransport',
    155                         'thermal',
    156                         'steadystate',
    157                         'transient',
    158                         'levelset',
    159                         'calving',
    160                                                 'frontalforcings',
    161                                                 'love',
    162                                                 'gia',
    163                                                 'esa',
    164                         'autodiff',
    165                         'inversion',
    166                         'qmu',
    167                         'amr',
    168                         'outputdefinition',
    169                         'results',
    170                         'radaroverlay',
    171                         'miscellaneous',
    172                         'private']
    173         # }}}
    174         def __repr__(obj): #{{{
    175                 #print "Here %s the number: %d" % ("is", 37)
    176                 string="%19s: %-22s -- %s" % ("mesh","[%s,%s]" % ("1x1",obj.mesh.__class__.__name__),"mesh properties")
    177                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("mask","[%s,%s]" % ("1x1",obj.mask.__class__.__name__),"defines grounded and floating elements"))
    178                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("geometry","[%s,%s]" % ("1x1",obj.geometry.__class__.__name__),"surface elevation, bedrock topography, ice thickness,..."))
    179                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("constants","[%s,%s]" % ("1x1",obj.constants.__class__.__name__),"physical constants"))
    180                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("smb","[%s,%s]" % ("1x1",obj.smb.__class__.__name__),"surface mass balance"))
    181                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("basalforcings","[%s,%s]" % ("1x1",obj.basalforcings.__class__.__name__),"bed forcings"))
    182                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("materials","[%s,%s]" % ("1x1",obj.materials.__class__.__name__),"material properties"))
    183                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("damage","[%s,%s]" % ("1x1",obj.damage.__class__.__name__),"damage propagation laws"))
    184                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("friction","[%s,%s]" % ("1x1",obj.friction.__class__.__name__),"basal friction/drag properties"))
    185                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("flowequation","[%s,%s]" % ("1x1",obj.flowequation.__class__.__name__),"flow equations"))
    186                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("timestepping","[%s,%s]" % ("1x1",obj.timestepping.__class__.__name__),"time stepping for transient models"))
    187                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("initialization","[%s,%s]" % ("1x1",obj.initialization.__class__.__name__),"initial guess/state"))
    188                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("rifts","[%s,%s]" % ("1x1",obj.rifts.__class__.__name__),"rifts properties"))
    189                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("slr","[%s,%s]" % ("1x1",obj.slr.__class__.__name__),"slr forcings"))
    190                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("debug","[%s,%s]" % ("1x1",obj.debug.__class__.__name__),"debugging tools (valgrind, gprof)"))
    191                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("verbose","[%s,%s]" % ("1x1",obj.verbose.__class__.__name__),"verbosity level in solve"))
    192                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("settings","[%s,%s]" % ("1x1",obj.settings.__class__.__name__),"settings properties"))
    193                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("toolkits","[%s,%s]" % ("1x1",obj.toolkits.__class__.__name__),"PETSc options for each solution"))
    194                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("cluster","[%s,%s]" % ("1x1",obj.cluster.__class__.__name__),"cluster parameters (number of cpus...)"))
    195                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("balancethickness","[%s,%s]" % ("1x1",obj.balancethickness.__class__.__name__),"parameters for balancethickness solution"))
    196                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("stressbalance","[%s,%s]" % ("1x1",obj.stressbalance.__class__.__name__),"parameters for stressbalance solution"))
    197                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("groundingline","[%s,%s]" % ("1x1",obj.groundingline.__class__.__name__),"parameters for groundingline solution"))
    198                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("hydrology","[%s,%s]" % ("1x1",obj.hydrology.__class__.__name__),"parameters for hydrology solution"))
    199                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("masstransport","[%s,%s]" % ("1x1",obj.masstransport.__class__.__name__),"parameters for masstransport solution"))
    200                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("thermal","[%s,%s]" % ("1x1",obj.thermal.__class__.__name__),"parameters for thermal solution"))
    201                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("steadystate","[%s,%s]" % ("1x1",obj.steadystate.__class__.__name__),"parameters for steadystate solution"))
    202                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("transient","[%s,%s]" % ("1x1",obj.transient.__class__.__name__),"parameters for transient solution"))
    203                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("levelset","[%s,%s]" % ("1x1",obj.levelset.__class__.__name__),"parameters for moving boundaries (level-set method)"))
    204                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("calving","[%s,%s]" % ("1x1",obj.calving.__class__.__name__),"parameters for calving"))
    205                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("frontalforcings","[%s,%s]" % ("1x1",obj.frontalforcings.__class__.__name__),"parameters for frontalforcings"))
    206                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("gia","[%s,%s]" % ("1x1",obj.gia.__class__.__name__),"parameters for gia solution"))
    207                 string="%s\n%s" % (string,'%19s: %-22s -- %s' % ("love","[%s,%s]" % ("1x1",obj.love.__class__.__name__),"parameters for love solution"))
    208                 string="%s\n%s" % (string,'%19s: %-22s -- %s' % ("esa","[%s,%s]" % ("1x1",obj.esa.__class__.__name__),"parameters for elastic adjustment solution"))
    209                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("autodiff","[%s,%s]" % ("1x1",obj.autodiff.__class__.__name__),"automatic differentiation parameters"))
    210                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("inversion","[%s,%s]" % ("1x1",obj.inversion.__class__.__name__),"parameters for inverse methods"))
    211                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("qmu","[%s,%s]" % ("1x1",obj.qmu.__class__.__name__),"dakota properties"))
    212                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("amr","[%s,%s]" % ("1x1",obj.amr.__class__.__name__),"adaptive mesh refinement properties"))
    213                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("outputdefinition","[%s,%s]" % ("1x1",obj.outputdefinition.__class__.__name__),"output definition"))
    214                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("results","[%s,%s]" % ("1x1",obj.results.__class__.__name__),"model results"))
    215                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("radaroverlay","[%s,%s]" % ("1x1",obj.radaroverlay.__class__.__name__),"radar image for plot overlay"))
    216                 string="%s\n%s" % (string,"%19s: %-22s -- %s" % ("miscellaneous","[%s,%s]" % ("1x1",obj.miscellaneous.__class__.__name__),"miscellaneous fields"))
    217                 return string
    218         # }}}
    219         def checkmessage(self,string):    # {{{
    220                 print(("model not consistent: ", string))
    221                 self.private.isconsistent=False
    222                 return self
    223         # }}}
    224         #@staticmethod
    225         def extract(self,area):    # {{{
    226                 """
    227                 extract - extract a model according to an Argus contour or flag list
    228 
    229                    This routine extracts a submodel from a bigger model with respect to a given contour
    230                    md must be followed by the corresponding exp file or flags list
    231                    It can either be a domain file (argus type, .exp extension), or an array of element flags.
    232                    If user wants every element outside the domain to be
    233                    extract2d, add '~' to the name of the domain file (ex: '~HO.exp')
    234                    an empty string '' will be considered as an empty domain
    235                    a string 'all' will be considered as the entire domain
    236 
    237                    Usage:
    238                       md2=extract(md,area)
    239 
    240                    Examples:
    241                       md2=extract(md,'Domain.exp')
    242 
    243                    See also: EXTRUDE, COLLAPSE
    244                 """
    245 
    246                 #copy model
    247                 md1=copy.deepcopy(self)
    248 
    249                 #get elements that are inside area
    250                 flag_elem=FlagElements(md1,area)
    251                 if not np.any(flag_elem):
    252                         raise RuntimeError("extracted model is empty")
    253 
    254                 #kick out all elements with 3 dirichlets
    255                 spc_elem=np.nonzero(np.logical_not(flag_elem))[0]
    256                 spc_node=np.unique(md1.mesh.elements[spc_elem,:])-1
    257                 flag=np.ones(md1.mesh.numberofvertices)
    258                 flag[spc_node]=0
    259                 pos=np.nonzero(np.logical_not(np.sum(flag[md1.mesh.elements-1],axis=1)))[0]
    260                 flag_elem[pos]=0
    261 
    262                 #extracted elements and nodes lists
    263                 pos_elem=np.nonzero(flag_elem)[0]
    264                 pos_node=np.unique(md1.mesh.elements[pos_elem,:])-1
    265 
    266                 #keep track of some fields
    267                 numberofvertices1=md1.mesh.numberofvertices
    268                 numberofelements1=md1.mesh.numberofelements
    269                 numberofvertices2=np.size(pos_node)
    270                 numberofelements2=np.size(pos_elem)
    271                 flag_node=np.zeros(numberofvertices1)
    272                 flag_node[pos_node]=1
    273 
    274                 #Create Pelem and Pnode (transform old nodes in new nodes and same thing for the elements)
    275                 Pelem=np.zeros(numberofelements1,int)
    276                 Pelem[pos_elem]=np.arange(1,numberofelements2+1)
    277                 Pnode=np.zeros(numberofvertices1,int)
    278                 Pnode[pos_node]=np.arange(1,numberofvertices2+1)
    279 
    280                 #renumber the elements (some node won't exist anymore)
    281                 elements_1=copy.deepcopy(md1.mesh.elements)
    282                 elements_2=elements_1[pos_elem,:]
    283                 elements_2[:,0]=Pnode[elements_2[:,0]-1]
    284                 elements_2[:,1]=Pnode[elements_2[:,1]-1]
    285                 elements_2[:,2]=Pnode[elements_2[:,2]-1]
    286                 if md1.mesh.__class__.__name__=='mesh3dprisms':
    287                         elements_2[:,3]=Pnode[elements_2[:,3]-1]
    288                         elements_2[:,4]=Pnode[elements_2[:,4]-1]
    289                         elements_2[:,5]=Pnode[elements_2[:,5]-1]
    290 
    291                 #OK, now create the new model!
    292 
    293                 #take every field from model
    294                 md2=copy.deepcopy(md1)
    295 
    296                 #automatically modify fields
    297 
    298                 #loop over model fields
    299                 model_fields=vars(md1)
    300                 for fieldi in model_fields:
    301                         #get field
    302                         field=getattr(md1,fieldi)
    303                         fieldsize=np.shape(field)
    304                         if hasattr(field,'__dict__') and not fieldi in ['results']:    #recursive call
    305                                 object_fields=vars(field)
    306                                 for fieldj in object_fields:
    307                                         #get field
    308                                         field=getattr(getattr(md1,fieldi),fieldj)
    309                                         fieldsize=np.shape(field)
    310                                         if len(fieldsize):
    311                                                 #size = number of nodes * n
    312                                                 if fieldsize[0]==numberofvertices1:
    313                                                         setattr(getattr(md2,fieldi),fieldj,field[pos_node])
    314                                                 elif fieldsize[0]==numberofvertices1+1:
    315                                                         setattr(getattr(md2,fieldi),fieldj,np.vstack((field[pos_node],field[-1,:])))
    316                                                 #size = number of elements * n
    317                                                 elif fieldsize[0]==numberofelements1:
    318                                                         setattr(getattr(md2,fieldi),fieldj,field[pos_elem])
    319                         else:
    320                                 if len(fieldsize):
    321                                         #size = number of nodes * n
    322                                         if fieldsize[0]==numberofvertices1:
    323                                                 setattr(md2,fieldi,field[pos_node])
    324                                         elif fieldsize[0]==numberofvertices1+1:
    325                                                 setattr(md2,fieldi,np.hstack((field[pos_node],field[-1,:])))
    326                                         #size = number of elements * n
    327                                         elif fieldsize[0]==numberofelements1:
    328                                                 setattr(md2,fieldi,field[pos_elem])
    329 
    330                 #modify some specific fields
    331 
    332                 #Mesh
    333                 md2.mesh.numberofelements=numberofelements2
    334                 md2.mesh.numberofvertices=numberofvertices2
    335                 md2.mesh.elements=elements_2
    336 
    337                 #mesh.uppervertex mesh.lowervertex
    338                 if md1.mesh.__class__.__name__=='mesh3dprisms':
    339                         md2.mesh.uppervertex=md1.mesh.uppervertex[pos_node]
    340                         pos=np.where(~np.isnan(md2.mesh.uppervertex))[0]
    341                         md2.mesh.uppervertex[pos]=Pnode[md2.mesh.uppervertex[pos].astype(int)-1]
    342 
    343                         md2.mesh.lowervertex=md1.mesh.lowervertex[pos_node]
    344                         pos=np.where(~np.isnan(md2.mesh.lowervertex))[0]
    345                         md2.mesh.lowervertex[pos]=Pnode[md2.mesh.lowervertex[pos].astype(int)-1]
    346 
    347                         md2.mesh.upperelements=md1.mesh.upperelements[pos_elem]
    348                         pos=np.where(~np.isnan(md2.mesh.upperelements))[0]
    349                         md2.mesh.upperelements[pos]=Pelem[md2.mesh.upperelements[pos].astype(int)-1]
    350 
    351                         md2.mesh.lowerelements=md1.mesh.lowerelements[pos_elem]
    352                         pos=np.where(~np.isnan(md2.mesh.lowerelements))[0]
    353                         md2.mesh.lowerelements[pos]=Pelem[md2.mesh.lowerelements[pos].astype(int)-1]
    354 
    355                 #Initial 2d mesh
    356                 if md1.mesh.__class__.__name__=='mesh3dprisms':
    357                         flag_elem_2d=flag_elem[np.arange(0,md1.mesh.numberofelements2d)]
    358                         pos_elem_2d=np.nonzero(flag_elem_2d)[0]
    359                         flag_node_2d=flag_node[np.arange(0,md1.mesh.numberofvertices2d)]
    360                         pos_node_2d=np.nonzero(flag_node_2d)[0]
    361 
    362                         md2.mesh.numberofelements2d=np.size(pos_elem_2d)
    363                         md2.mesh.numberofvertices2d=np.size(pos_node_2d)
    364                         md2.mesh.elements2d=md1.mesh.elements2d[pos_elem_2d,:]
    365                         md2.mesh.elements2d[:,0]=Pnode[md2.mesh.elements2d[:,0]-1]
    366                         md2.mesh.elements2d[:,1]=Pnode[md2.mesh.elements2d[:,1]-1]
    367                         md2.mesh.elements2d[:,2]=Pnode[md2.mesh.elements2d[:,2]-1]
    368 
    369                         md2.mesh.x2d=md1.mesh.x[pos_node_2d]
    370                         md2.mesh.y2d=md1.mesh.y[pos_node_2d]
    371 
    372                 #Edges
    373                 if md1.mesh.domaintype()=='2Dhorizontal':
    374                         if np.ndim(md2.mesh.edges)>1 and np.size(md2.mesh.edges,axis=1)>1:    #do not use ~isnan because there are some np.nans...
    375                                 #renumber first two columns
    376                                 pos=np.nonzero(md2.mesh.edges[:,3]!=-1)[0]
    377                                 md2.mesh.edges[:,0]=Pnode[md2.mesh.edges[:,0]-1]
    378                                 md2.mesh.edges[:,1]=Pnode[md2.mesh.edges[:,1]-1]
    379                                 md2.mesh.edges[:,2]=Pelem[md2.mesh.edges[:,2]-1]
    380                                 md2.mesh.edges[pos,3]=Pelem[md2.mesh.edges[pos,3]-1]
    381                                 #remove edges when the 2 vertices are not in the domain.
    382                                 md2.mesh.edges=md2.mesh.edges[np.nonzero(np.logical_and(md2.mesh.edges[:,0],md2.mesh.edges[:,1]))[0],:]
    383                                 #Replace all zeros by -1 in the last two columns
    384                                 pos=np.nonzero(md2.mesh.edges[:,2]==0)[0]
    385                                 md2.mesh.edges[pos,2]=-1
    386                                 pos=np.nonzero(md2.mesh.edges[:,3]==0)[0]
    387                                 md2.mesh.edges[pos,3]=-1
    388                                 #Invert -1 on the third column with last column (Also invert first two columns!!)
    389                                 pos=np.nonzero(md2.mesh.edges[:,2]==-1)[0]
    390                                 md2.mesh.edges[pos,2]=md2.mesh.edges[pos,3]
    391                                 md2.mesh.edges[pos,3]=-1
    392                                 values=md2.mesh.edges[pos,1]
    393                                 md2.mesh.edges[pos,1]=md2.mesh.edges[pos,0]
    394                                 md2.mesh.edges[pos,0]=values
    395                                 #Finally remove edges that do not belong to any element
    396                                 pos=np.nonzero(np.logical_and(md2.mesh.edges[:,1]==-1,md2.mesh.edges[:,2]==-1))[0]
    397                                 md2.mesh.edges=np.delete(md2.mesh.edges,pos,axis=0)
    398 
    399                 #Penalties
    400                 if np.any(np.logical_not(np.isnan(md2.stressbalance.vertex_pairing))):
    401                         for i in range(np.size(md1.stressbalance.vertex_pairing,axis=0)):
    402                                 md2.stressbalance.vertex_pairing[i,:]=Pnode[md1.stressbalance.vertex_pairing[i,:]]
    403                         md2.stressbalance.vertex_pairing=md2.stressbalance.vertex_pairing[np.nonzero(md2.stressbalance.vertex_pairing[:,0])[0],:]
    404                 if np.any(np.logical_not(np.isnan(md2.masstransport.vertex_pairing))):
    405                         for i in range(np.size(md1.masstransport.vertex_pairing,axis=0)):
    406                                 md2.masstransport.vertex_pairing[i,:]=Pnode[md1.masstransport.vertex_pairing[i,:]]
    407                         md2.masstransport.vertex_pairing=md2.masstransport.vertex_pairing[np.nonzero(md2.masstransport.vertex_pairing[:,0])[0],:]
    408 
    409                 #recreate segments
    410                 if md1.mesh.__class__.__name__=='mesh2d':
    411                         md2.mesh.vertexconnectivity=NodeConnectivity(md2.mesh.elements,md2.mesh.numberofvertices)[0]
    412                         md2.mesh.elementconnectivity=ElementConnectivity(md2.mesh.elements,md2.mesh.vertexconnectivity)[0]
    413                         md2.mesh.segments=contourenvelope(md2)
    414                         md2.mesh.vertexonboundary=np.zeros(numberofvertices2,bool)
    415                         md2.mesh.vertexonboundary[md2.mesh.segments[:,0:2]-1]=True
    416                 else:
    417                         #First do the connectivity for the contourenvelope in 2d
    418                         md2.mesh.vertexconnectivity=NodeConnectivity(md2.mesh.elements2d,md2.mesh.numberofvertices2d)[0]
    419                         md2.mesh.elementconnectivity=ElementConnectivity(md2.mesh.elements2d,md2.mesh.vertexconnectivity)[0]
    420                         segments=contourenvelope(md2)
    421                         md2.mesh.vertexonboundary=np.zeros(int(numberofvertices2/md2.mesh.numberoflayers),bool)
    422                         md2.mesh.vertexonboundary[segments[:,0:2]-1]=True
    423                         md2.mesh.vertexonboundary=np.tile(md2.mesh.vertexonboundary,md2.mesh.numberoflayers)
    424                         #Then do it for 3d as usual
    425                         md2.mesh.vertexconnectivity=NodeConnectivity(md2.mesh.elements,md2.mesh.numberofvertices)[0]
    426                         md2.mesh.elementconnectivity=ElementConnectivity(md2.mesh.elements,md2.mesh.vertexconnectivity)[0]
    427 
    428                 #Boundary conditions: Dirichlets on new boundary
    429                 #Catch the elements that have not been extracted
    430                 orphans_elem=np.nonzero(np.logical_not(flag_elem))[0]
    431                 orphans_node=np.unique(md1.mesh.elements[orphans_elem,:])-1
    432                 #Figure out which node are on the boundary between md2 and md1
    433                 nodestoflag1=np.intersect1d(orphans_node,pos_node)
    434                 nodestoflag2=Pnode[nodestoflag1].astype(int)-1
    435                 if np.size(md1.stressbalance.spcvx)>1 and np.size(md1.stressbalance.spcvy)>1 and np.size(md1.stressbalance.spcvz)>1:
    436                         if np.size(md1.inversion.vx_obs)>1 and np.size(md1.inversion.vy_obs)>1:
    437                                 md2.stressbalance.spcvx[nodestoflag2]=md2.inversion.vx_obs[nodestoflag2]
    438                                 md2.stressbalance.spcvy[nodestoflag2]=md2.inversion.vy_obs[nodestoflag2]
    439                         else:
    440                                 md2.stressbalance.spcvx[nodestoflag2]=np.nan
    441                                 md2.stressbalance.spcvy[nodestoflag2]=np.nan
    442                                 print("\n!! extract warning: spc values should be checked !!\n\n")
    443                         #put 0 for vz
    444                         md2.stressbalance.spcvz[nodestoflag2]=0
    445                 if np.any(np.logical_not(np.isnan(md1.thermal.spctemperature))):
    446                         md2.thermal.spctemperature[nodestoflag2]=1
    447 
    448                 #Results fields
    449                 if md1.results:
    450                         md2.results=results()
    451                         for solutionfield,field in list(md1.results.__dict__.items()):
    452                                 if   isinstance(field,list):
    453                                         setattr(md2.results,solutionfield,[])
    454                                         #get time step
    455                                         for i,fieldi in enumerate(field):
    456                                                 if isinstance(fieldi,results) and fieldi:
    457                                                         getattr(md2.results,solutionfield).append(results())
    458                                                         fieldr=getattr(md2.results,solutionfield)[i]
    459                                                         #get subfields
    460                                                         for solutionsubfield,subfield in list(fieldi.__dict__.items()):
    461                                                                 if   np.size(subfield)==numberofvertices1:
    462                                                                         setattr(fieldr,solutionsubfield,subfield[pos_node])
    463                                                                 elif np.size(subfield)==numberofelements1:
    464                                                                         setattr(fieldr,solutionsubfield,subfield[pos_elem])
    465                                                                 else:
    466                                                                         setattr(fieldr,solutionsubfield,subfield)
    467                                                 else:
    468                                                         getattr(md2.results,solutionfield).append(None)
    469                                 elif isinstance(field,results):
    470                                         setattr(md2.results,solutionfield,results())
    471                                         if isinstance(field,results) and field:
    472                                                 fieldr=getattr(md2.results,solutionfield)
    473                                                 #get subfields
    474                                                 for solutionsubfield,subfield in list(field.__dict__.items()):
    475                                                         if   np.size(subfield)==numberofvertices1:
    476                                                                 setattr(fieldr,solutionsubfield,subfield[pos_node])
    477                                                         elif np.size(subfield)==numberofelements1:
    478                                                                 setattr(fieldr,solutionsubfield,subfield[pos_elem])
    479                                                         else:
    480                                                                 setattr(fieldr,solutionsubfield,subfield)
    481 
    482                 #OutputDefinitions fields
    483                 if md1.outputdefinition.definitions:
    484                         for solutionfield,field in list(md1.outputdefinition.__dict__.items()):
    485                                 if isinstance(field,list):
    486                                         #get each definition
    487                                         for i,fieldi in enumerate(field):
    488                                                 if fieldi:
    489                                                         fieldr=getattr(md2.outputdefinition,solutionfield)[i]
    490                                                         #get subfields
    491                                                         for solutionsubfield,subfield in list(fieldi.__dict__.items()):
    492                                                                 if   np.size(subfield)==numberofvertices1:
    493                                                                         setattr(fieldr,solutionsubfield,subfield[pos_node])
    494                                                                 elif np.size(subfield)==numberofelements1:
    495                                                                         setattr(fieldr,solutionsubfield,subfield[pos_elem])
    496                                                                 else:
    497                                                                         setattr(fieldr,solutionsubfield,subfield)
    498 
    499                 #Keep track of pos_node and pos_elem
    500                 md2.mesh.extractedvertices=pos_node+1
    501                 md2.mesh.extractedelements=pos_elem+1
    502 
    503                 return md2
    504         # }}}
    505         def extrude(md,*args):    # {{{
    506                 """
    507                 EXTRUDE - vertically extrude a 2d mesh
    508 
    509                    vertically extrude a 2d mesh and create corresponding 3d mesh.
    510                    The vertical distribution can:
    511                     - follow a polynomial law
    512                     - follow two polynomial laws, one for the lower part and one for the upper part of the mesh
    513                     - be discribed by a list of coefficients (between 0 and 1)
    514 
    515 
    516                    Usage:
    517                       md=extrude(md,numlayers,extrusionexponent)
    518                       md=extrude(md,numlayers,lowerexponent,upperexponent)
    519                       md=extrude(md,listofcoefficients)
    520 
    521                    Example:
    522                                 md=extrude(md,15,1.3);
    523                                 md=extrude(md,15,1.3,1.2);
    524                                 md=extrude(md,[0 0.2 0.5 0.7 0.9 0.95 1])
    525 
    526                    See also: MODELEXTRACT, COLLAPSE
    527                 """
    528 
    529                 #some checks on list of arguments
    530                 if len(args)>3 or len(args)<1:
    531                         raise RuntimeError("extrude error message")
    532 
    533                 #Extrude the mesh
    534                 if   len(args)==1:    #list of coefficients
    535                         clist=args[0]
    536                         if any(clist<0) or any(clist>1):
    537                                 raise TypeError("extrusioncoefficients must be between 0 and 1")
    538                         clist.extend([0.,1.])
    539                         clist.sort()
    540                         extrusionlist=list(set(clist))
    541                         numlayers=len(extrusionlist)
    542 
    543                 elif len(args)==2:    #one polynomial law
    544                         if args[1]<=0:
    545                                 raise TypeError("extrusionexponent must be >=0")
    546                         numlayers=args[0]
    547                         extrusionlist=(np.arange(0.,float(numlayers-1)+1.,1.)/float(numlayers-1))**args[1]
    548 
    549                 elif len(args)==3:    #two polynomial laws
    550                         numlayers=args[0]
    551                         lowerexp=args[1]
    552                         upperexp=args[2]
    553 
    554                         if args[1]<=0 or args[2]<=0:
    555                                 raise TypeError("lower and upper extrusionexponents must be >=0")
    556 
    557                         lowerextrusionlist=(np.arange(0.,1.+2./float(numlayers-1),2./float(numlayers-1)))**lowerexp/2.
    558                         upperextrusionlist=(np.arange(0.,1.+2./float(numlayers-1),2./float(numlayers-1)))**upperexp/2.
    559                         extrusionlist=np.unique(np.concatenate((lowerextrusionlist,1.-upperextrusionlist)))
    560 
    561                 if numlayers<2:
    562                         raise TypeError("number of layers should be at least 2")
    563                 if md.mesh.__class__.__name__=='mesh3dprisms':
    564                         raise TypeError("Cannot extrude a 3d mesh (extrude cannot be called more than once)")
    565 
    566                 #Initialize with the 2d mesh
    567                 mesh2d = md.mesh
    568                 md.mesh=mesh3dprisms()
    569                 md.mesh.x                           = mesh2d.x
    570                 md.mesh.y                           = mesh2d.y
    571                 md.mesh.elements                    = mesh2d.elements
    572                 md.mesh.numberofelements            = mesh2d.numberofelements
    573                 md.mesh.numberofvertices            = mesh2d.numberofvertices
    574 
    575                 md.mesh.lat                         = mesh2d.lat
    576                 md.mesh.long                        = mesh2d.long
    577                 md.mesh.epsg                        = mesh2d.epsg
    578                 md.mesh.scale_factor                = mesh2d.scale_factor
    579 
    580                 md.mesh.vertexonboundary            = mesh2d.vertexonboundary
    581                 md.mesh.vertexconnectivity          = mesh2d.vertexconnectivity
    582                 md.mesh.elementconnectivity         = mesh2d.elementconnectivity
    583                 md.mesh.average_vertex_connectivity = mesh2d.average_vertex_connectivity
    584 
    585                 md.mesh.extractedvertices           = mesh2d.extractedvertices
    586                 md.mesh.extractedelements           = mesh2d.extractedelements
    587 
    588                 x3d=np.empty((0))
    589                 y3d=np.empty((0))
    590                 z3d=np.empty((0))    #the lower node is on the bed
    591                 thickness3d=md.geometry.thickness    #thickness and bed for these nodes
    592                 bed3d=md.geometry.base
    593 
    594                 #Create the new layers
    595                 for i in range(numlayers):
    596                         x3d=np.concatenate((x3d,md.mesh.x))
    597                         y3d=np.concatenate((y3d,md.mesh.y))
    598                         #nodes are distributed between bed and surface accordingly to the given exponent
    599                         z3d=np.concatenate((z3d,(bed3d+thickness3d*extrusionlist[i]).reshape(-1)))
    600                 number_nodes3d=np.size(x3d)    #number of 3d nodes for the non extruded part of the mesh
    601 
    602                 #Extrude elements
    603                 elements3d=np.empty((0,6),int)
    604                 for i in range(numlayers-1):
    605                         elements3d=np.vstack((elements3d,np.hstack((md.mesh.elements+i*md.mesh.numberofvertices,md.mesh.elements+(i+1)*md.mesh.numberofvertices))))    #Create the elements of the 3d mesh for the non extruded part
    606                 number_el3d=np.size(elements3d,axis=0)    #number of 3d nodes for the non extruded part of the mesh
    607 
    608                 #Keep a trace of lower and upper nodes
    609                 lowervertex=np.nan*np.ones(number_nodes3d,int)
    610                 uppervertex=np.nan*np.ones(number_nodes3d,int)
    611                 lowervertex[md.mesh.numberofvertices:]=np.arange(1,(numlayers-1)*md.mesh.numberofvertices+1)
    612                 uppervertex[:(numlayers-1)*md.mesh.numberofvertices]=np.arange(md.mesh.numberofvertices+1,number_nodes3d+1)
    613                 md.mesh.lowervertex=lowervertex
    614                 md.mesh.uppervertex=uppervertex
    615 
    616                 #same for lower and upper elements
    617                 lowerelements=np.nan*np.ones(number_el3d,int)
    618                 upperelements=np.nan*np.ones(number_el3d,int)
    619                 lowerelements[md.mesh.numberofelements:]=np.arange(1,(numlayers-2)*md.mesh.numberofelements+1)
    620                 upperelements[:(numlayers-2)*md.mesh.numberofelements]=np.arange(md.mesh.numberofelements+1,(numlayers-1)*md.mesh.numberofelements+1)
    621                 md.mesh.lowerelements=lowerelements
    622                 md.mesh.upperelements=upperelements
    623 
    624                 #Save old mesh
    625                 md.mesh.x2d=md.mesh.x
    626                 md.mesh.y2d=md.mesh.y
    627                 md.mesh.elements2d=md.mesh.elements
    628                 md.mesh.numberofelements2d=md.mesh.numberofelements
    629                 md.mesh.numberofvertices2d=md.mesh.numberofvertices
    630 
    631                 #Build global 3d mesh
    632                 md.mesh.elements=elements3d
    633                 md.mesh.x=x3d
    634                 md.mesh.y=y3d
    635                 md.mesh.z=z3d
    636                 md.mesh.numberofelements=number_el3d
    637                 md.mesh.numberofvertices=number_nodes3d
    638                 md.mesh.numberoflayers=numlayers
    639 
    640                 #Ok, now deal with the other fields from the 2d mesh:
    641 
    642                 #bedinfo and surface info
    643                 md.mesh.vertexonbase=project3d(md,'vector',np.ones(md.mesh.numberofvertices2d,bool),'type','node','layer',1)
    644                 md.mesh.vertexonsurface=project3d(md,'vector',np.ones(md.mesh.numberofvertices2d,bool),'type','node','layer',md.mesh.numberoflayers)
    645                 md.mesh.vertexonboundary=project3d(md,'vector',md.mesh.vertexonboundary,'type','node')
    646 
    647                 #lat long
    648                 md.mesh.lat=project3d(md,'vector',md.mesh.lat,'type','node')
    649                 md.mesh.long=project3d(md,'vector',md.mesh.long,'type','node')
    650                 md.mesh.scale_factor=project3d(md,'vector',md.mesh.scale_factor,'type','node')
    651 
    652                 md.geometry.extrude(md)
    653                 md.friction.extrude(md)
    654                 md.inversion.extrude(md)
    655                 md.smb.extrude(md)
    656                 md.initialization.extrude(md)
    657                 md.flowequation.extrude(md)
    658 
    659                 md.stressbalance.extrude(md)
    660                 md.thermal.extrude(md)
    661                 md.masstransport.extrude(md)
    662 
    663                 # Calving variables
    664                 md.hydrology.extrude(md)
    665                 md.levelset.extrude(md)
    666                 md.calving.extrude(md)
    667                 md.frontalforcings.extrude(md)
    668 
    669                 #connectivity
    670                 md.mesh.elementconnectivity=np.tile(md.mesh.elementconnectivity,(numlayers-1,1))
    671                 md.mesh.elementconnectivity[np.nonzero(md.mesh.elementconnectivity==0)]=-sys.maxsize-1
    672                 if not np.isnan(md.mesh.elementconnectivity).all():
    673                         for i in range(1,numlayers-1):
    674                                 md.mesh.elementconnectivity[i*md.mesh.numberofelements2d:(i+1)*md.mesh.numberofelements2d,:] \
    675                                                 =md.mesh.elementconnectivity[i*md.mesh.numberofelements2d:(i+1)*md.mesh.numberofelements2d,:]+md.mesh.numberofelements2d
    676                                 md.mesh.elementconnectivity[np.nonzero(md.mesh.elementconnectivity<0)]=0
    677 
    678                 md.materials.extrude(md)
    679                 if md.damage.isdamage==1:
    680                         md.damage.extrude(md)
    681                 md.gia.extrude(md)
    682                 md.mask.extrude(md)
    683                 md.qmu.extrude(md)
    684                 md.basalforcings.extrude(md)
    685                 md.outputdefinition.extrude(md)
    686 
    687                 #increase connectivity if less than 25:
    688                 if md.mesh.average_vertex_connectivity<=25:
    689                         md.mesh.average_vertex_connectivity=100
    690 
    691                 return md
    692                 # }}}
    693         def collapse(md): #{{{
    694                 '''
    695                 collapses a 3d mesh into a 2d mesh
    696 
    697                 This routine collapses a 3d model into a 2d model and collapses all
    698                 the fileds of the 3d model by taking their depth-averaged values
    699 
    700                 Usage:
    701                         md=collapse(md)
    702                 '''
    703 
    704                 #Check that the model is really a 3d model
    705                 if md.mesh.domaintype().lower() != '3d':
    706                         raise Exception("only a 3D model can be collapsed")
    707 
    708                 #dealing with the friction law
    709                 #drag is limited to nodes that are on the bedrock.
    710                 if hasattr(md.friction,'coefficient'):
    711                         md.friction.coefficient=project2d(md,md.friction.coefficient,1)
    712 
    713                 #p and q (same deal, except for element that are on the bedrock: )
    714                 if hasattr(md.friction,'p'):
    715                         md.friction.p=project2d(md,md.friction.p,1)
    716                 if hasattr(md.friction,'q'):
    717                         md.friction.q=project2d(md,md.friction.q,1)
    718 
    719                 if hasattr(md.friction,'coefficientcoulomb'):
    720                         md.friction.coefficientcoulomb=project2d(md,md.friction.coefficientcoulomb,1)
    721                 if hasattr(md.friction,'C'):
    722                         md.friction.C=project2d(md,md.friction.C,1)
    723                 if hasattr(md.friction,'As'):
    724                         md.friction.As=project2d(md,md.friction.As,1)
    725                 if hasattr(md.friction,'effective_pressure') and not np.isnan(md.friction.effective_pressure).all():
    726                         md.friction.effective_pressure=project2d(md,md.friction.effective_pressure,1)
    727                 if hasattr(md.friction,'water_layer'):
    728                         md.friction.water_layer=project2d(md,md.friction.water_layer,1)
    729                 if hasattr(md.friction,'m'):
    730                         md.friction.m=project2d(md,md.friction.m,1)
    731 
    732                 #observations
    733                 if not np.isnan(md.inversion.vx_obs).all():
    734                         md.inversion.vx_obs=project2d(md,md.inversion.vx_obs,md.mesh.numberoflayers)
    735                 if not np.isnan(md.inversion.vy_obs).all():
    736                         md.inversion.vy_obs=project2d(md,md.inversion.vy_obs,md.mesh.numberoflayers)
    737                 if not np.isnan(md.inversion.vel_obs).all():
    738                         md.inversion.vel_obs=project2d(md,md.inversion.vel_obs,md.mesh.numberoflayers)
    739                 if not np.isnan(md.inversion.cost_functions_coefficients).all():
    740                         md.inversion.cost_functions_coefficients=project2d(md,md.inversion.cost_functions_coefficients,md.mesh.numberoflayers)
    741                 if isinstance(md.inversion.min_parameters,np.ndarray):
    742                         if md.inversion.min_parameters.size>1:
    743                                 md.inversion.min_parameters=project2d(md,md.inversion.min_parameters,md.mesh.numberoflayers)
    744                 if isinstance(md.inversion.max_parameters,np.ndarray):
    745                         if md.inversion.max_parameters.size>1:
    746                                 md.inversion.max_parameters=project2d(md,md.inversion.max_parameters,md.mesh.numberoflayers)
    747                 if not np.isnan(md.smb.mass_balance).all():
    748                         md.smb.mass_balance=project2d(md,md.smb.mass_balance,md.mesh.numberoflayers)
    749 
    750                 #results
    751                 if not np.isnan(md.initialization.vx).all():
    752                         md.initialization.vx=DepthAverage(md,md.initialization.vx)
    753                 if not np.isnan(md.initialization.vy).all():
    754                         md.initialization.vy=DepthAverage(md,md.initialization.vy)
    755                 if not np.isnan(md.initialization.vz).all():
    756                         md.initialization.vz=DepthAverage(md,md.initialization.vz)
    757                 if not np.isnan(md.initialization.vel).all():
    758                         md.initialization.vel=DepthAverage(md,md.initialization.vel)
    759                 if not np.isnan(md.initialization.temperature).all():
    760                         md.initialization.temperature=DepthAverage(md,md.initialization.temperature)
    761                 if not np.isnan(md.initialization.pressure).all():
    762                         md.initialization.pressure=project2d(md,md.initialization.pressure,1)
    763                 if not np.isnan(md.initialization.sediment_head).all():
    764                         md.initialization.sediment_head=project2d(md,md.initialization.sediment_head,1)
    765                 if not np.isnan(md.initialization.epl_head).all():
    766                         md.initialization.epl_head=project2d(md,md.initialization.epl_head,1)
    767                 if not np.isnan(md.initialization.epl_thickness).all():
    768                         md.initialization.epl_thickness=project2d(md,md.initialization.epl_thickness,1)
    769 
    770                 #giaivins
    771                 if not np.isnan(md.gia.mantle_viscosity).all():
    772                         md.gia.mantle_viscosity=project2d(md,md.gia.mantle_viscosity,1)
    773                 if not np.isnan(md.gia.lithosphere_thickness).all():
    774                         md.gia.lithosphere_thickness=project2d(md,md.gia.lithosphere_thickness,1)
    775 
    776                 #elementstype
    777                 if not np.isnan(md.flowequation.element_equation).all():
    778                         md.flowequation.element_equation=project2d(md,md.flowequation.element_equation,1)
    779                         md.flowequation.vertex_equation=project2d(md,md.flowequation.vertex_equation,1)
    780                         md.flowequation.borderSSA=project2d(md,md.flowequation.borderSSA,1)
    781                         md.flowequation.borderHO=project2d(md,md.flowequation.borderHO,1)
    782                         md.flowequation.borderFS=project2d(md,md.flowequation.borderFS,1)
    783 
    784                 # Hydrologydc variables
    785                 if type(md.hydrology) is 'hydrologydc':
    786                         md.hydrology.spcsediment_head=project2d(md,md.hydrology.spcsediment_head,1)
    787                         md.hydrology.sediment_transmitivity=project2d(md,md.hydrology.sediment_transmitivity,1)
    788                         md.hydrology.basal_moulin_input=project2d(md,md.hydrology.basal_moulin_input,1)
    789                         md.hydrology.mask_thawed_node=project2d(md,md.hydrology.mask_thawed_node,1)
    790                         if md.hydrology.isefficientlayer == 1:
    791                                 md.hydrology.mask_eplactive_node=project2d(md,md.hydrology.mask_eplactive_node,1)
    792                                 md.hydrology.spcepl_head=project2d(md,md.hydrology.spcepl_head,1)
    793 
    794                 #boundary conditions
    795                 md.stressbalance.spcvx=project2d(md,md.stressbalance.spcvx,md.mesh.numberoflayers)
    796                 md.stressbalance.spcvy=project2d(md,md.stressbalance.spcvy,md.mesh.numberoflayers)
    797                 md.stressbalance.spcvz=project2d(md,md.stressbalance.spcvz,md.mesh.numberoflayers)
    798                 md.stressbalance.referential=project2d(md,md.stressbalance.referential,md.mesh.numberoflayers)
    799                 md.stressbalance.loadingforce=project2d(md,md.stressbalance.loadingforce,md.mesh.numberoflayers)
    800                 md.masstransport.spcthickness=project2d(md,md.masstransport.spcthickness,md.mesh.numberoflayers)
    801                 md.thermal.spctemperature=project2d(md,md.thermal.spctemperature,md.mesh.numberoflayers-1)
    802                 if not np.isnan(md.damage.spcdamage).all():
    803                         md.damage.spcdamage=project2d(md,md.damage.spcdamage,md.mesh.numberoflayers-1)
    804 
    805                 #materials
    806                 md.materials.rheology_B=DepthAverage(md,md.materials.rheology_B)
    807                 md.materials.rheology_n=project2d(md,md.materials.rheology_n,1)
    808 
    809                 #damage:
    810                 if md.damage.isdamage:
    811                         md.damage.D=DepthAverage(md,md.damage.D)
    812 
    813                 #special for thermal modeling:
    814                 md.basalforcings.groundedice_melting_rate=project2d(md,md.basalforcings.groundedice_melting_rate,1)
    815                 md.basalforcings.floatingice_melting_rate=project2d(md,md.basalforcings.floatingice_melting_rate,1)
    816                 md.basalforcings.geothermalflux=project2d(md,md.basalforcings.geothermalflux,1) #bedrock only gets geothermal flux
    817 
    818                 #update of connectivity matrix
    819                 md.mesh.average_vertex_connectivity=25
    820 
    821                 #Collapse the mesh
    822                 nodes2d=md.mesh.numberofvertices2d
    823                 elements2d=md.mesh.numberofelements2d
    824 
    825                 #parameters
    826                 md.geometry.surface=project2d(md,md.geometry.surface,1)
    827                 md.geometry.thickness=project2d(md,md.geometry.thickness,1)
    828                 md.geometry.base=project2d(md,md.geometry.base,1)
    829                 if isinstance(md.geometry.bed,np.ndarray):
    830                         md.geometry.bed=project2d(md,md.geometry.bed,1)
    831                 md.mask.groundedice_levelset=project2d(md,md.mask.groundedice_levelset,1)
    832                 md.mask.ice_levelset=project2d(md,md.mask.ice_levelset,1)
    833 
    834                 #OutputDefinitions
    835                 if md.outputdefinition.definitions:
    836                         for solutionfield,field in list(md.outputdefinition.__dict__.items()):
    837                                 if isinstance(field,list):
    838                                         #get each definition
    839                                         for i,fieldi in enumerate(field):
    840                                                 if fieldi:
    841                                                         fieldr=getattr(md.outputdefinition,solutionfield)[i]
    842                                                         #get subfields
    843                                                         for solutionsubfield,subfield in list(fieldi.__dict__.items()):
    844                                                                 if   np.size(subfield)==md.mesh.numberofvertices:
    845                                                                         setattr(fieldr,solutionsubfield,project2d(md,subfield,1))
    846                                                                 elif np.size(subfield)==md.mesh.numberofelements:
    847                                                                         setattr(fieldr,solutionsubfield,project2d(md,subfield,1))
    848 
    849 
    850                 #Initialize with the 2d mesh
    851                 mesh=mesh2d()
    852                 mesh.x=md.mesh.x2d
    853                 mesh.y=md.mesh.y2d
    854                 mesh.numberofvertices=md.mesh.numberofvertices2d
    855                 mesh.numberofelements=md.mesh.numberofelements2d
    856                 mesh.elements=md.mesh.elements2d
    857                 if not np.isnan(md.mesh.vertexonboundary).all():
    858                         mesh.vertexonboundary=project2d(md,md.mesh.vertexonboundary,1)
    859                 if not np.isnan(md.mesh.elementconnectivity).all():
    860                         mesh.elementconnectivity=project2d(md,md.mesh.elementconnectivity,1)
    861                 if isinstance(md.mesh.lat,np.ndarray):
    862                         if md.mesh.lat.size==md.mesh.numberofvertices:
    863                                 mesh.lat=project2d(md,md.mesh.lat,1)
    864                 if isinstance(md.mesh.long,np.ndarray):
    865                         if md.mesh.long.size==md.mesh.numberofvertices:
    866                                 md.mesh.long=project2d(md,md.mesh.long,1)
    867                 mesh.epsg=md.mesh.epsg
    868                 if isinstance(md.mesh.scale_factor,np.ndarray):
    869                         if md.mesh.scale_factor.size==md.mesh.numberofvertices:
    870                                 md.mesh.scale_factor=project2d(md,md.mesh.scale_factor,1)
    871                 md.mesh=mesh
    872                 md.mesh.vertexconnectivity=NodeConnectivity(md.mesh.elements,md.mesh.numberofvertices)[0]
    873                 md.mesh.elementconnectivity=ElementConnectivity(md.mesh.elements,md.mesh.vertexconnectivity)[0]
    874                 md.mesh.segments=contourenvelope(md)
    875 
    876                 return md
     75    #properties
     76    def __init__(self):  #{{{
     77
     78        # classtype = model.properties
     79
     80        # for classe in dict.keys(classtype):
     81        #       print classe
     82        #       self.__dict__[classe] = classtype[str(classe)]
     83
     84        self.mesh = mesh2d()
     85        self.mask = mask()
     86        self.geometry = geometry()
     87        self.constants = constants()
     88        self.smb = SMBforcing()
     89        self.basalforcings = basalforcings()
     90        self.materials = matice()
     91        self.damage = damage()
     92        self.friction = friction()
     93        self.flowequation = flowequation()
     94        self.timestepping = timestepping()
     95        self.initialization = initialization()
     96        self.rifts = rifts()
     97        self.slr = slr()
     98
     99        self.debug = debug()
     100        self.verbose = verbose()
     101        self.settings = issmsettings()
     102        self.toolkits = toolkits()
     103        self.cluster = generic()
     104
     105        self.balancethickness = balancethickness()
     106        self.stressbalance = stressbalance()
     107        self.groundingline = groundingline()
     108        self.hydrology = hydrologyshreve()
     109        self.masstransport = masstransport()
     110        self.thermal = thermal()
     111        self.steadystate = steadystate()
     112        self.transient = transient()
     113        self.levelset = levelset()
     114        self.calving = calving()
     115        self.frontalforcings = frontalforcings()
     116        self.gia = giaivins()
     117        self.love = fourierlove()
     118        self.esa = esa()
     119        self.autodiff = autodiff()
     120        self.inversion = inversion()
     121        self.qmu = qmu()
     122        self.amr = amr()
     123
     124        self.results = results()
     125        self.outputdefinition = outputdefinition()
     126        self.radaroverlay = radaroverlay()
     127        self.miscellaneous = miscellaneous()
     128        self.private = private()
     129    #}}}
     130
     131    def properties(self):  # {{{
     132        # ordered list of properties since vars(self) is random
     133        return ['mesh',
     134                'mask',
     135                'geometry',
     136                'constants',
     137                'smb',
     138                'basalforcings',
     139                'materials',
     140                'damage',
     141                'friction',
     142                'flowequation',
     143                'timestepping',
     144                'initialization',
     145                'rifts',
     146                'slr',
     147                'debug',
     148                'verbose',
     149                'settings',
     150                'toolkits',
     151                'cluster',
     152                'balancethickness',
     153                'stressbalance',
     154                'groundingline',
     155                'hydrology',
     156                'masstransport',
     157                'thermal',
     158                'steadystate',
     159                'transient',
     160                'levelset',
     161                'calving',
     162                'frontalforcings',
     163                'love',
     164                'gia',
     165                'esa',
     166                'autodiff',
     167                'inversion',
     168                'qmu',
     169                'amr',
     170                'outputdefinition',
     171                'results',
     172                'radaroverlay',
     173                'miscellaneous',
     174                'private']
     175    # }}}
     176
     177    def __repr__(obj):  #{{{
     178        #print "Here %s the number: %d" % ("is",  37)
     179        string = "%19s: %-22s -- %s" % ("mesh", "[%s, %s]" % ("1x1", obj.mesh.__class__.__name__), "mesh properties")
     180        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("mask", "[%s, %s]" % ("1x1", obj.mask.__class__.__name__), "defines grounded and floating elements"))
     181        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("geometry", "[%s, %s]" % ("1x1", obj.geometry.__class__.__name__), "surface elevation,  bedrock topography,  ice thickness, ..."))
     182        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("constants", "[%s, %s]" % ("1x1", obj.constants.__class__.__name__), "physical constants"))
     183        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("smb", "[%s, %s]" % ("1x1", obj.smb.__class__.__name__), "surface mass balance"))
     184        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("basalforcings", "[%s, %s]" % ("1x1", obj.basalforcings.__class__.__name__), "bed forcings"))
     185        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("materials", "[%s, %s]" % ("1x1", obj.materials.__class__.__name__), "material properties"))
     186        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("damage", "[%s, %s]" % ("1x1", obj.damage.__class__.__name__), "damage propagation laws"))
     187        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("friction", "[%s, %s]" % ("1x1", obj.friction.__class__.__name__), "basal friction/drag properties"))
     188        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("flowequation", "[%s, %s]" % ("1x1", obj.flowequation.__class__.__name__), "flow equations"))
     189        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("timestepping", "[%s, %s]" % ("1x1", obj.timestepping.__class__.__name__), "time stepping for transient models"))
     190        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("initialization", "[%s, %s]" % ("1x1", obj.initialization.__class__.__name__), "initial guess/state"))
     191        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("rifts", "[%s, %s]" % ("1x1", obj.rifts.__class__.__name__), "rifts properties"))
     192        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("slr", "[%s, %s]" % ("1x1", obj.slr.__class__.__name__), "slr forcings"))
     193        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("debug", "[%s, %s]" % ("1x1", obj.debug.__class__.__name__), "debugging tools (valgrind,  gprof)"))
     194        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("verbose", "[%s, %s]" % ("1x1", obj.verbose.__class__.__name__), "verbosity level in solve"))
     195        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("settings", "[%s, %s]" % ("1x1", obj.settings.__class__.__name__), "settings properties"))
     196        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("toolkits", "[%s, %s]" % ("1x1", obj.toolkits.__class__.__name__), "PETSc options for each solution"))
     197        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("cluster", "[%s, %s]" % ("1x1", obj.cluster.__class__.__name__), "cluster parameters (number of cpus...)"))
     198        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("balancethickness", "[%s, %s]" % ("1x1", obj.balancethickness.__class__.__name__), "parameters for balancethickness solution"))
     199        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("stressbalance", "[%s, %s]" % ("1x1", obj.stressbalance.__class__.__name__), "parameters for stressbalance solution"))
     200        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("groundingline", "[%s, %s]" % ("1x1", obj.groundingline.__class__.__name__), "parameters for groundingline solution"))
     201        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("hydrology", "[%s, %s]" % ("1x1", obj.hydrology.__class__.__name__), "parameters for hydrology solution"))
     202        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("masstransport", "[%s, %s]" % ("1x1", obj.masstransport.__class__.__name__), "parameters for masstransport solution"))
     203        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("thermal", "[%s, %s]" % ("1x1", obj.thermal.__class__.__name__), "parameters for thermal solution"))
     204        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("steadystate", "[%s, %s]" % ("1x1", obj.steadystate.__class__.__name__), "parameters for steadystate solution"))
     205        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("transient", "[%s, %s]" % ("1x1", obj.transient.__class__.__name__), "parameters for transient solution"))
     206        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("levelset", "[%s, %s]" % ("1x1", obj.levelset.__class__.__name__), "parameters for moving boundaries (level-set method)"))
     207        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("calving", "[%s, %s]" % ("1x1", obj.calving.__class__.__name__), "parameters for calving"))
     208        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("frontalforcings", "[%s, %s]" % ("1x1", obj.frontalforcings.__class__.__name__), "parameters for frontalforcings"))
     209        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("gia", "[%s, %s]" % ("1x1", obj.gia.__class__.__name__), "parameters for gia solution"))
     210        string = "%s\n%s" % (string, '%19s: %-22s -- %s' % ("love", "[%s, %s]" % ("1x1", obj.love.__class__.__name__), "parameters for love solution"))
     211        string = "%s\n%s" % (string, '%19s: %-22s -- %s' % ("esa", "[%s, %s]" % ("1x1", obj.esa.__class__.__name__), "parameters for elastic adjustment solution"))
     212        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("autodiff", "[%s, %s]" % ("1x1", obj.autodiff.__class__.__name__), "automatic differentiation parameters"))
     213        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("inversion", "[%s, %s]" % ("1x1", obj.inversion.__class__.__name__), "parameters for inverse methods"))
     214        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("qmu", "[%s, %s]" % ("1x1", obj.qmu.__class__.__name__), "dakota properties"))
     215        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("amr", "[%s, %s]" % ("1x1", obj.amr.__class__.__name__), "adaptive mesh refinement properties"))
     216        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("outputdefinition", "[%s, %s]" % ("1x1", obj.outputdefinition.__class__.__name__), "output definition"))
     217        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("results", "[%s, %s]" % ("1x1", obj.results.__class__.__name__), "model results"))
     218        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("radaroverlay", "[%s, %s]" % ("1x1", obj.radaroverlay.__class__.__name__), "radar image for plot overlay"))
     219        string = "%s\n%s" % (string, "%19s: %-22s -- %s" % ("miscellaneous", "[%s, %s]" % ("1x1", obj.miscellaneous.__class__.__name__), "miscellaneous fields"))
     220        return string
     221    # }}}
     222
     223    def checkmessage(self, string):    # {{{
     224        print("model not consistent: {}".format(string))
     225        self.private.isconsistent = False
     226        return self
     227    # }}}
     228    #@staticmethod
     229
     230    def extract(self, area):    # {{{
     231        """
     232        extract - extract a model according to an Argus contour or flag list
     233
     234           This routine extracts a submodel from a bigger model with respect to a given contour
     235           md must be followed by the corresponding exp file or flags list
     236           It can either be a domain file (argus type,  .exp extension),  or an array of element flags.
     237           If user wants every element outside the domain to be
     238           extract2d,  add '~' to the name of the domain file (ex: '~HO.exp')
     239           an empty string '' will be considered as an empty domain
     240           a string 'all' will be considered as the entire domain
     241
     242           Usage:
     243              md2 = extract(md, area)
     244
     245           Examples:
     246              md2 = extract(md, 'Domain.exp')
     247
     248           See also: EXTRUDE,  COLLAPSE
     249        """
     250
     251        #copy model
     252        md1 = copy.deepcopy(self)
     253
     254        #get elements that are inside area
     255        flag_elem = FlagElements(md1, area)
     256        if not np.any(flag_elem):
     257            raise RuntimeError("extracted model is empty")
     258
     259        #kick out all elements with 3 dirichlets
     260        spc_elem = np.nonzero(np.logical_not(flag_elem))[0]
     261        spc_node = np.unique(md1.mesh.elements[spc_elem, :]) - 1
     262        flag = np.ones(md1.mesh.numberofvertices)
     263        flag[spc_node] = 0
     264        pos = np.nonzero(np.logical_not(np.sum(flag[md1.mesh.elements - 1], axis=1)))[0]
     265        flag_elem[pos] = 0
     266
     267        #extracted elements and nodes lists
     268        pos_elem = np.nonzero(flag_elem)[0]
     269        pos_node = np.unique(md1.mesh.elements[pos_elem, :]) - 1
     270
     271        #keep track of some fields
     272        numberofvertices1 = md1.mesh.numberofvertices
     273        numberofelements1 = md1.mesh.numberofelements
     274        numberofvertices2 = np.size(pos_node)
     275        numberofelements2 = np.size(pos_elem)
     276        flag_node = np.zeros(numberofvertices1)
     277        flag_node[pos_node] = 1
     278
     279        #Create Pelem and Pnode (transform old nodes in new nodes and same thing for the elements)
     280        Pelem = np.zeros(numberofelements1, int)
     281        Pelem[pos_elem] = np.arange(1, numberofelements2 + 1)
     282        Pnode = np.zeros(numberofvertices1, int)
     283        Pnode[pos_node] = np.arange(1, numberofvertices2 + 1)
     284
     285        #renumber the elements (some node won't exist anymore)
     286        elements_1 = copy.deepcopy(md1.mesh.elements)
     287        elements_2 = elements_1[pos_elem, :]
     288        elements_2[:, 0] = Pnode[elements_2[:, 0] - 1]
     289        elements_2[:, 1] = Pnode[elements_2[:, 1] - 1]
     290        elements_2[:, 2] = Pnode[elements_2[:, 2] - 1]
     291        if md1.mesh.__class__.__name__ == 'mesh3dprisms':
     292            elements_2[:, 3] = Pnode[elements_2[:, 3] - 1]
     293            elements_2[:, 4] = Pnode[elements_2[:, 4] - 1]
     294            elements_2[:, 5] = Pnode[elements_2[:, 5] - 1]
     295
     296        #OK,  now create the new model!
     297
     298        #take every field from model
     299        md2 = copy.deepcopy(md1)
     300
     301        #automatically modify fields
     302
     303        #loop over model fields
     304        model_fields = vars(md1)
     305        for fieldi in model_fields:
     306            #get field
     307            field = getattr(md1, fieldi)
     308            fieldsize = np.shape(field)
     309            if hasattr(field, '__dict__') and fieldi not in ['results']:  #recursive call
     310                object_fields = vars(field)
     311                for fieldj in object_fields:
     312                    #get field
     313                    field = getattr(getattr(md1, fieldi), fieldj)
     314                    fieldsize = np.shape(field)
     315                    if len(fieldsize):
     316                        #size = number of nodes * n
     317                        if fieldsize[0] == numberofvertices1:
     318                            setattr(getattr(md2, fieldi), fieldj, field[pos_node])
     319                        elif fieldsize[0] == numberofvertices1 + 1:
     320                            setattr(getattr(md2, fieldi), fieldj, np.vstack((field[pos_node], field[-1, :])))
     321                        #size = number of elements * n
     322                        elif fieldsize[0] == numberofelements1:
     323                            setattr(getattr(md2, fieldi), fieldj, field[pos_elem])
     324            else:
     325                if len(fieldsize):
     326                    #size = number of nodes * n
     327                    if fieldsize[0] == numberofvertices1:
     328                        setattr(md2, fieldi, field[pos_node])
     329                    elif fieldsize[0] == numberofvertices1 + 1:
     330                        setattr(md2, fieldi, np.hstack((field[pos_node], field[-1, :])))
     331                    #size = number of elements * n
     332                    elif fieldsize[0] == numberofelements1:
     333                        setattr(md2, fieldi, field[pos_elem])
     334
     335        #modify some specific fields
     336
     337        #Mesh
     338        md2.mesh.numberofelements = numberofelements2
     339        md2.mesh.numberofvertices = numberofvertices2
     340        md2.mesh.elements = elements_2
     341
     342        #mesh.uppervertex mesh.lowervertex
     343        if md1.mesh.__class__.__name__ == 'mesh3dprisms':
     344            md2.mesh.uppervertex = md1.mesh.uppervertex[pos_node]
     345            pos = np.where(~np.isnan(md2.mesh.uppervertex))[0]
     346            md2.mesh.uppervertex[pos] = Pnode[md2.mesh.uppervertex[pos].astype(int) - 1]
     347
     348            md2.mesh.lowervertex = md1.mesh.lowervertex[pos_node]
     349            pos = np.where(~np.isnan(md2.mesh.lowervertex))[0]
     350            md2.mesh.lowervertex[pos] = Pnode[md2.mesh.lowervertex[pos].astype(int) - 1]
     351
     352            md2.mesh.upperelements = md1.mesh.upperelements[pos_elem]
     353            pos = np.where(~np.isnan(md2.mesh.upperelements))[0]
     354            md2.mesh.upperelements[pos] = Pelem[md2.mesh.upperelements[pos].astype(int) - 1]
     355
     356            md2.mesh.lowerelements = md1.mesh.lowerelements[pos_elem]
     357            pos = np.where(~np.isnan(md2.mesh.lowerelements))[0]
     358            md2.mesh.lowerelements[pos] = Pelem[md2.mesh.lowerelements[pos].astype(int) - 1]
     359
     360        #Initial 2d mesh
     361        if md1.mesh.__class__.__name__ == 'mesh3dprisms':
     362            flag_elem_2d = flag_elem[np.arange(0, md1.mesh.numberofelements2d)]
     363            pos_elem_2d = np.nonzero(flag_elem_2d)[0]
     364            flag_node_2d = flag_node[np.arange(0, md1.mesh.numberofvertices2d)]
     365            pos_node_2d = np.nonzero(flag_node_2d)[0]
     366
     367            md2.mesh.numberofelements2d = np.size(pos_elem_2d)
     368            md2.mesh.numberofvertices2d = np.size(pos_node_2d)
     369            md2.mesh.elements2d = md1.mesh.elements2d[pos_elem_2d, :]
     370            md2.mesh.elements2d[:, 0] = Pnode[md2.mesh.elements2d[:, 0] - 1]
     371            md2.mesh.elements2d[:, 1] = Pnode[md2.mesh.elements2d[:, 1] - 1]
     372            md2.mesh.elements2d[:, 2] = Pnode[md2.mesh.elements2d[:, 2] - 1]
     373
     374            md2.mesh.x2d = md1.mesh.x[pos_node_2d]
     375            md2.mesh.y2d = md1.mesh.y[pos_node_2d]
     376
     377        #Edges
     378        if md1.mesh.domaintype() == '2Dhorizontal':
     379            if np.ndim(md2.mesh.edges) > 1 and np.size(md2.mesh.edges, axis=1) > 1:    #do not use ~isnan because there are some np.nans...
     380                #renumber first two columns
     381                pos = np.nonzero(md2.mesh.edges[:, 3] != -1)[0]
     382                md2.mesh.edges[:, 0] = Pnode[md2.mesh.edges[:, 0] - 1]
     383                md2.mesh.edges[:, 1] = Pnode[md2.mesh.edges[:, 1] - 1]
     384                md2.mesh.edges[:, 2] = Pelem[md2.mesh.edges[:, 2] - 1]
     385                md2.mesh.edges[pos, 3] = Pelem[md2.mesh.edges[pos, 3] - 1]
     386                #remove edges when the 2 vertices are not in the domain.
     387                md2.mesh.edges = md2.mesh.edges[np.nonzero(np.logical_and(md2.mesh.edges[:, 0], md2.mesh.edges[:, 1]))[0], :]
     388                #Replace all zeros by -1 in the last two columns
     389                pos = np.nonzero(md2.mesh.edges[:, 2] == 0)[0]
     390                md2.mesh.edges[pos, 2] = -1
     391                pos = np.nonzero(md2.mesh.edges[:, 3] == 0)[0]
     392                md2.mesh.edges[pos, 3] = -1
     393                #Invert -1 on the third column with last column (Also invert first two columns!!)
     394                pos = np.nonzero(md2.mesh.edges[:, 2] == -1)[0]
     395                md2.mesh.edges[pos, 2] = md2.mesh.edges[pos, 3]
     396                md2.mesh.edges[pos, 3] = - 1
     397                values = md2.mesh.edges[pos, 1]
     398                md2.mesh.edges[pos, 1] = md2.mesh.edges[pos, 0]
     399                md2.mesh.edges[pos, 0] = values
     400                #Finally remove edges that do not belong to any element
     401                pos = np.nonzero(np.logical_and(md2.mesh.edges[:, 1] == - 1, md2.mesh.edges[:, 2] == - 1))[0]
     402                md2.mesh.edges = np.delete(md2.mesh.edges, pos, axis=0)
     403
     404        #Penalties
     405        if np.any(np.logical_not(np.isnan(md2.stressbalance.vertex_pairing))):
     406            for i in range(np.size(md1.stressbalance.vertex_pairing, axis=0)):
     407                md2.stressbalance.vertex_pairing[i, :] = Pnode[md1.stressbalance.vertex_pairing[i, :]]
     408            md2.stressbalance.vertex_pairing = md2.stressbalance.vertex_pairing[np.nonzero(md2.stressbalance.vertex_pairing[:, 0])[0], :]
     409        if np.any(np.logical_not(np.isnan(md2.masstransport.vertex_pairing))):
     410            for i in range(np.size(md1.masstransport.vertex_pairing, axis=0)):
     411                md2.masstransport.vertex_pairing[i, :] = Pnode[md1.masstransport.vertex_pairing[i, :]]
     412            md2.masstransport.vertex_pairing = md2.masstransport.vertex_pairing[np.nonzero(md2.masstransport.vertex_pairing[:, 0])[0], :]
     413
     414        #recreate segments
     415        if md1.mesh.__class__.__name__ == 'mesh2d':
     416            md2.mesh.vertexconnectivity = NodeConnectivity(md2.mesh.elements, md2.mesh.numberofvertices)[0]
     417            md2.mesh.elementconnectivity = ElementConnectivity(md2.mesh.elements, md2.mesh.vertexconnectivity)[0]
     418            md2.mesh.segments = contourenvelope(md2)
     419            md2.mesh.vertexonboundary = np.zeros(numberofvertices2, bool)
     420            md2.mesh.vertexonboundary[md2.mesh.segments[:, 0:2] - 1] = True
     421        else:
     422            #First do the connectivity for the contourenvelope in 2d
     423            md2.mesh.vertexconnectivity = NodeConnectivity(md2.mesh.elements2d, md2.mesh.numberofvertices2d)[0]
     424            md2.mesh.elementconnectivity = ElementConnectivity(md2.mesh.elements2d, md2.mesh.vertexconnectivity)[0]
     425            segments = contourenvelope(md2)
     426            md2.mesh.vertexonboundary = np.zeros(int(numberofvertices2 / md2.mesh.numberoflayers), bool)
     427            md2.mesh.vertexonboundary[segments[:, 0:2] - 1] = True
     428            md2.mesh.vertexonboundary = np.tile(md2.mesh.vertexonboundary, md2.mesh.numberoflayers)
     429            #Then do it for 3d as usual
     430            md2.mesh.vertexconnectivity = NodeConnectivity(md2.mesh.elements, md2.mesh.numberofvertices)[0]
     431            md2.mesh.elementconnectivity = ElementConnectivity(md2.mesh.elements, md2.mesh.vertexconnectivity)[0]
     432
     433        #Boundary conditions: Dirichlets on new boundary
     434        #Catch the elements that have not been extracted
     435        orphans_elem = np.nonzero(np.logical_not(flag_elem))[0]
     436        orphans_node = np.unique(md1.mesh.elements[orphans_elem, :]) - 1
     437        #Figure out which node are on the boundary between md2 and md1
     438        nodestoflag1 = np.intersect1d(orphans_node, pos_node)
     439        nodestoflag2 = Pnode[nodestoflag1].astype(int) - 1
     440        if np.size(md1.stressbalance.spcvx) > 1 and np.size(md1.stressbalance.spcvy) > 2 and np.size(md1.stressbalance.spcvz) > 2:
     441            if np.size(md1.inversion.vx_obs) > 1 and np.size(md1.inversion.vy_obs) > 1:
     442                md2.stressbalance.spcvx[nodestoflag2] = md2.inversion.vx_obs[nodestoflag2]
     443                md2.stressbalance.spcvy[nodestoflag2] = md2.inversion.vy_obs[nodestoflag2]
     444            else:
     445                md2.stressbalance.spcvx[nodestoflag2] = np.nan
     446                md2.stressbalance.spcvy[nodestoflag2] = np.nan
     447                print("\n!! extract warning: spc values should be checked !!\n\n")
     448            #put 0 for vz
     449            md2.stressbalance.spcvz[nodestoflag2] = 0
     450        if np.any(np.logical_not(np.isnan(md1.thermal.spctemperature))):
     451            md2.thermal.spctemperature[nodestoflag2] = 1
     452
     453        #Results fields
     454        if md1.results:
     455            md2.results = results()
     456            for solutionfield, field in list(md1.results.__dict__.items()):
     457                if isinstance(field, list):
     458                    setattr(md2.results, solutionfield, [])
     459                    #get time step
     460                    for i, fieldi in enumerate(field):
     461                        if isinstance(fieldi, results) and fieldi:
     462                            getattr(md2.results, solutionfield).append(results())
     463                            fieldr = getattr(md2.results, solutionfield)[i]
     464                            #get subfields
     465                            for solutionsubfield, subfield in list(fieldi.__dict__.items()):
     466                                if np.size(subfield) == numberofvertices1:
     467                                    setattr(fieldr, solutionsubfield, subfield[pos_node])
     468                                elif np.size(subfield) == numberofelements1:
     469                                    setattr(fieldr, solutionsubfield, subfield[pos_elem])
     470                                else:
     471                                    setattr(fieldr, solutionsubfield, subfield)
     472                        else:
     473                            getattr(md2.results, solutionfield).append(None)
     474                elif isinstance(field, results):
     475                    setattr(md2.results, solutionfield, results())
     476                    if isinstance(field, results) and field:
     477                        fieldr = getattr(md2.results, solutionfield)
     478                        #get subfields
     479                        for solutionsubfield, subfield in list(field.__dict__.items()):
     480                            if np.size(subfield) == numberofvertices1:
     481                                setattr(fieldr, solutionsubfield, subfield[pos_node])
     482                            elif np.size(subfield) == numberofelements1:
     483                                setattr(fieldr, solutionsubfield, subfield[pos_elem])
     484                            else:
     485                                setattr(fieldr, solutionsubfield, subfield)
     486
     487        #OutputDefinitions fields
     488        if md1.outputdefinition.definitions:
     489            for solutionfield, field in list(md1.outputdefinition.__dict__.items()):
     490                if isinstance(field, list):
     491                    #get each definition
     492                    for i, fieldi in enumerate(field):
     493                        if fieldi:
     494                            fieldr = getattr(md2.outputdefinition, solutionfield)[i]
     495                            #get subfields
     496                            for solutionsubfield, subfield in list(fieldi.__dict__.items()):
     497                                if np.size(subfield) == numberofvertices1:
     498                                    setattr(fieldr, solutionsubfield, subfield[pos_node])
     499                                elif np.size(subfield) == numberofelements1:
     500                                    setattr(fieldr, solutionsubfield, subfield[pos_elem])
     501                                else:
     502                                    setattr(fieldr, solutionsubfield, subfield)
     503
     504        #Keep track of pos_node and pos_elem
     505        md2.mesh.extractedvertices = pos_node + 1
     506        md2.mesh.extractedelements = pos_elem + 1
     507
     508        return md2
     509    # }}}
     510
     511    def extrude(md, *args):   # {{{
     512        """
     513        EXTRUDE - vertically extrude a 2d mesh
     514
     515           vertically extrude a 2d mesh and create corresponding 3d mesh.
     516           The vertical distribution can:
     517            - follow a polynomial law
     518            - follow two polynomial laws,  one for the lower part and one for the upper part of the mesh
     519            - be discribed by a list of coefficients (between 0 and 1)
     520
     521
     522           Usage:
     523              md = extrude(md, numlayers, extrusionexponent)
     524              md = extrude(md, numlayers, lowerexponent, upperexponent)
     525              md = extrude(md, listofcoefficients)
     526
     527           Example:
     528                        md = extrude(md, 15, 1.3);
     529                        md = extrude(md, 15, 1.3, 1.2);
     530                        md = extrude(md, [0 0.2 0.5 0.7 0.9 0.95 1])
     531
     532           See also: MODELEXTRACT,  COLLAPSE
     533        """
     534
     535        #some checks on list of arguments
     536        if len(args) > 3 or len(args) < 1:
     537            raise RuntimeError("extrude error message")
     538
     539        #Extrude the mesh
     540        if len(args) == 1:    #list of coefficients
     541            clist = args[0]
     542            if any(clist < 0) or any(clist > 1):
     543                raise TypeError("extrusioncoefficients must be between 0 and 1")
     544            clist.extend([0., 1.])
     545            clist.sort()
     546            extrusionlist = list(set(clist))
     547            numlayers = len(extrusionlist)
     548
     549        elif len(args) == 2:    #one polynomial law
     550            if args[1] <= 0:
     551                raise TypeError("extrusionexponent must be >=0")
     552            numlayers = args[0]
     553            extrusionlist = (np.arange(0., float(numlayers - 1) + 1., 1.) / float(numlayers - 1))**args[1]
     554
     555        elif len(args) == 3:    #two polynomial laws
     556            numlayers = args[0]
     557            lowerexp = args[1]
     558            upperexp = args[2]
     559
     560            if args[1] <= 0 or args[2] <= 0:
     561                raise TypeError("lower and upper extrusionexponents must be >=0")
     562
     563            lowerextrusionlist = (np.arange(0., 1. + 2. / float(numlayers - 1), 2. / float(numlayers - 1)))**lowerexp / 2.
     564            upperextrusionlist = (np.arange(0., 1. + 2. / float(numlayers - 1), 2. / float(numlayers - 1)))**upperexp / 2.
     565            extrusionlist = np.unique(np.concatenate((lowerextrusionlist, 1. - upperextrusionlist)))
     566
     567        if numlayers < 2:
     568            raise TypeError("number of layers should be at least 2")
     569        if md.mesh.__class__.__name__ == 'mesh3dprisms':
     570            raise TypeError("Cannot extrude a 3d mesh (extrude cannot be called more than once)")
     571
     572        #Initialize with the 2d mesh
     573        mesh2d = md.mesh
     574        md.mesh = mesh3dprisms()
     575        md.mesh.x = mesh2d.x
     576        md.mesh.y = mesh2d.y
     577        md.mesh.elements = mesh2d.elements
     578        md.mesh.numberofelement = mesh2d.numberofelements
     579        md.mesh.numberofvertice = mesh2d.numberofvertices
     580
     581        md.mesh.lat = mesh2d.lat
     582        md.mesh.long = mesh2d.long
     583        md.mesh.epsg = mesh2d.epsg
     584        md.mesh.scale_factor = mesh2d.scale_factor
     585
     586        md.mesh.vertexonboundary = mesh2d.vertexonboundary
     587        md.mesh.vertexconnectivity = mesh2d.vertexconnectivity
     588        md.mesh.elementconnectivity = mesh2d.elementconnectivity
     589        md.mesh.average_vertex_connectivity = mesh2d.average_vertex_connectivity
     590
     591        md.mesh.extractedvertices = mesh2d.extractedvertices
     592        md.mesh.extractedelements = mesh2d.extractedelements
     593
     594        x3d = np.empty((0))
     595        y3d = np.empty((0))
     596        z3d = np.empty((0))    #the lower node is on the bed
     597        thickness3d = md.geometry.thickness    #thickness and bed for these nodes
     598        bed3d = md.geometry.base
     599
     600        #Create the new layers
     601        for i in range(numlayers):
     602            x3d = np.concatenate((x3d, md.mesh.x))
     603            y3d = np.concatenate((y3d, md.mesh.y))
     604            #nodes are distributed between bed and surface accordingly to the given exponent
     605            z3d = np.concatenate((z3d, (bed3d + thickness3d * extrusionlist[i]).reshape(-1)))
     606        number_nodes3d = np.size(x3d)    #number of 3d nodes for the non extruded part of the mesh
     607
     608        #Extrude elements
     609        elements3d = np.empty((0, 6), int)
     610        for i in range(numlayers - 1):
     611            elements3d = np.vstack((elements3d, np.hstack((md.mesh.elements + i * md.mesh.numberofvertices,
     612                                                           md.mesh.elements + (i + 1) * md.mesh.numberofvertices))))    #Create the elements of the 3d mesh for the non extruded part
     613        number_el3d = np.size(elements3d, axis=0)    #number of 3d nodes for the non extruded part of the mesh
     614
     615        #Keep a trace of lower and upper nodes
     616        lowervertex = np.nan * np.ones(number_nodes3d, int)
     617        uppervertex = np.nan * np.ones(number_nodes3d, int)
     618        lowervertex[md.mesh.numberofvertices:] = np.arange(1, (numlayers - 1) * md.mesh.numberofvertices + 1)
     619        uppervertex[:(numlayers - 1) * md.mesh.numberofvertices] = np.arange(md.mesh.numberofvertices + 1, number_nodes3d + 1)
     620        md.mesh.lowervertex = lowervertex
     621        md.mesh.uppervertex = uppervertex
     622
     623        #same for lower and upper elements
     624        lowerelements = np.nan * np.ones(number_el3d, int)
     625        upperelements = np.nan * np.ones(number_el3d, int)
     626        lowerelements[md.mesh.numberofelements:] = np.arange(1, (numlayers - 2) * md.mesh.numberofelements + 1)
     627        upperelements[:(numlayers - 2) * md.mesh.numberofelements] = np.arange(md.mesh.numberofelements + 1, (numlayers - 1) * md.mesh.numberofelements + 1)
     628        md.mesh.lowerelements = lowerelements
     629        md.mesh.upperelements = upperelements
     630
     631        #Save old mesh
     632        md.mesh.x2d = md.mesh.x
     633        md.mesh.y2d = md.mesh.y
     634        md.mesh.elements2d = md.mesh.elements
     635        md.mesh.numberofelements2d = md.mesh.numberofelements
     636        md.mesh.numberofvertices2d = md.mesh.numberofvertices
     637
     638        #Build global 3d mesh
     639        md.mesh.elements = elements3d
     640        md.mesh.x = x3d
     641        md.mesh.y = y3d
     642        md.mesh.z = z3d
     643        md.mesh.numberofelements = number_el3d
     644        md.mesh.numberofvertices = number_nodes3d
     645        md.mesh.numberoflayers = numlayers
     646
     647        #Ok,  now deal with the other fields from the 2d mesh:
     648
     649        #bedinfo and surface info
     650        md.mesh.vertexonbase = project3d(md, 'vector', np.ones(md.mesh.numberofvertices2d, bool), 'type', 'node', 'layer', 1)
     651        md.mesh.vertexonsurface = project3d(md, 'vector', np.ones(md.mesh.numberofvertices2d, bool), 'type', 'node', 'layer', md.mesh.numberoflayers)
     652        md.mesh.vertexonboundary = project3d(md, 'vector', md.mesh.vertexonboundary, 'type', 'node')
     653
     654        #lat long
     655        md.mesh.lat = project3d(md, 'vector', md.mesh.lat, 'type', 'node')
     656        md.mesh.long = project3d(md, 'vector', md.mesh.long, 'type', 'node')
     657        md.mesh.scale_factor = project3d(md, 'vector', md.mesh.scale_factor, 'type', 'node')
     658
     659        md.geometry.extrude(md)
     660        md.friction.extrude(md)
     661        md.inversion.extrude(md)
     662        md.smb.extrude(md)
     663        md.initialization.extrude(md)
     664        md.flowequation.extrude(md)
     665
     666        md.stressbalance.extrude(md)
     667        md.thermal.extrude(md)
     668        md.masstransport.extrude(md)
     669
     670        # Calving variables
     671        md.hydrology.extrude(md)
     672        md.levelset.extrude(md)
     673        md.calving.extrude(md)
     674        md.frontalforcings.extrude(md)
     675
     676        #connectivity
     677        md.mesh.elementconnectivity = np.tile(md.mesh.elementconnectivity, (numlayers - 1, 1))
     678        md.mesh.elementconnectivity[np.nonzero(md.mesh.elementconnectivity == 0)] = -sys.maxsize - 1
     679        if not np.isnan(md.mesh.elementconnectivity).all():
     680            for i in range(1, numlayers - 1):
     681                connect1 = i * md.mesh.numberofelements2d
     682                connect2 = (i + 1) * md.mesh.numberofelements2d
     683                md.mesh.elementconnectivity[connect1:connect2, :] = md.mesh.elementconnectivity[connect1:connect2, :] + md.mesh.numberofelements2d
     684                md.mesh.elementconnectivity[np.nonzero(md.mesh.elementconnectivity < 0)] = 0
     685
     686        md.materials.extrude(md)
     687        if md.damage.isdamage == 1:
     688            md.damage.extrude(md)
     689        md.gia.extrude(md)
     690        md.mask.extrude(md)
     691        md.qmu.extrude(md)
     692        md.basalforcings.extrude(md)
     693        md.outputdefinition.extrude(md)
     694
     695        #increase connectivity if less than 25:
     696        if md.mesh.average_vertex_connectivity <= 25:
     697            md.mesh.average_vertex_connectivity = 100
     698
     699        return md
     700        # }}}
     701
     702    def collapse(md):  #{{{
     703        '''
     704        collapses a 3d mesh into a 2d mesh
     705
     706        This routine collapses a 3d model into a 2d model and collapses all
     707        the fileds of the 3d model by taking their depth-averaged values
     708
     709        Usage:
     710                md = collapse(md)
     711        '''
     712
     713        #Check that the model is really a 3d model
     714        if md.mesh.domaintype().lower() != '3d':
     715            raise Exception("only a 3D model can be collapsed")
     716
     717        #dealing with the friction law
     718        #drag is limited to nodes that are on the bedrock.
     719        if hasattr(md.friction, 'coefficient'):
     720            md.friction.coefficient = project2d(md, md.friction.coefficient, 1)
     721
     722        #p and q (same deal,  except for element that are on the bedrock: )
     723        if hasattr(md.friction, 'p'):
     724            md.friction.p = project2d(md, md.friction.p, 1)
     725        if hasattr(md.friction, 'q'):
     726            md.friction.q = project2d(md, md.friction.q, 1)
     727
     728        if hasattr(md.friction, 'coefficientcoulomb'):
     729            md.friction.coefficientcoulomb = project2d(md, md.friction.coefficientcoulomb, 1)
     730        if hasattr(md.friction, 'C'):
     731            md.friction.C = project2d(md, md.friction.C, 1)
     732        if hasattr(md.friction, 'As'):
     733            md.friction.As = project2d(md, md.friction.As, 1)
     734        if hasattr(md.friction, 'effective_pressure') and not np.isnan(md.friction.effective_pressure).all():
     735            md.friction.effective_pressure = project2d(md, md.friction.effective_pressure, 1)
     736        if hasattr(md.friction, 'water_layer'):
     737            md.friction.water_layer = project2d(md, md.friction.water_layer, 1)
     738        if hasattr(md.friction, 'm'):
     739            md.friction.m = project2d(md, md.friction.m, 1)
     740
     741        #observations
     742        if not np.isnan(md.inversion.vx_obs).all():
     743            md.inversion.vx_obs = project2d(md, md.inversion.vx_obs, md.mesh.numberoflayers)
     744        if not np.isnan(md.inversion.vy_obs).all():
     745            md.inversion.vy_obs = project2d(md, md.inversion.vy_obs, md.mesh.numberoflayers)
     746        if not np.isnan(md.inversion.vel_obs).all():
     747            md.inversion.vel_obs = project2d(md, md.inversion.vel_obs, md.mesh.numberoflayers)
     748        if not np.isnan(md.inversion.cost_functions_coefficients).all():
     749            md.inversion.cost_functions_coefficients = project2d(md, md.inversion.cost_functions_coefficients, md.mesh.numberoflayers)
     750        if isinstance(md.inversion.min_parameters, np.ndarray):
     751            if md.inversion.min_parameters.size > 1:
     752                md.inversion.min_parameters = project2d(md, md.inversion.min_parameters, md.mesh.numberoflayers)
     753        if isinstance(md.inversion.max_parameters, np.ndarray):
     754            if md.inversion.max_parameters.size > 1:
     755                md.inversion.max_parameters = project2d(md, md.inversion.max_parameters, md.mesh.numberoflayers)
     756        if not np.isnan(md.smb.mass_balance).all():
     757            md.smb.mass_balance = project2d(md, md.smb.mass_balance, md.mesh.numberoflayers)
     758
     759        #results
     760        if not np.isnan(md.initialization.vx).all():
     761            md.initialization.vx = DepthAverage(md, md.initialization.vx)
     762        if not np.isnan(md.initialization.vy).all():
     763            md.initialization.vy = DepthAverage(md, md.initialization.vy)
     764        if not np.isnan(md.initialization.vz).all():
     765            md.initialization.vz = DepthAverage(md, md.initialization.vz)
     766        if not np.isnan(md.initialization.vel).all():
     767            md.initialization.vel = DepthAverage(md, md.initialization.vel)
     768        if not np.isnan(md.initialization.temperature).all():
     769            md.initialization.temperature = DepthAverage(md, md.initialization.temperature)
     770        if not np.isnan(md.initialization.pressure).all():
     771            md.initialization.pressure = project2d(md, md.initialization.pressure, 1)
     772        if not np.isnan(md.initialization.sediment_head).all():
     773            md.initialization.sediment_head = project2d(md, md.initialization.sediment_head, 1)
     774        if not np.isnan(md.initialization.epl_head).all():
     775            md.initialization.epl_head = project2d(md, md.initialization.epl_head, 1)
     776        if not np.isnan(md.initialization.epl_thickness).all():
     777            md.initialization.epl_thickness = project2d(md, md.initialization.epl_thickness, 1)
     778
     779        #giaivins
     780        if not np.isnan(md.gia.mantle_viscosity).all():
     781            md.gia.mantle_viscosity = project2d(md, md.gia.mantle_viscosity, 1)
     782        if not np.isnan(md.gia.lithosphere_thickness).all():
     783            md.gia.lithosphere_thickness = project2d(md, md.gia.lithosphere_thickness, 1)
     784
     785        #elementstype
     786        if not np.isnan(md.flowequation.element_equation).all():
     787            md.flowequation.element_equation = project2d(md, md.flowequation.element_equation, 1)
     788            md.flowequation.vertex_equation = project2d(md, md.flowequation.vertex_equation, 1)
     789            md.flowequation.borderSSA = project2d(md, md.flowequation.borderSSA, 1)
     790            md.flowequation.borderHO = project2d(md, md.flowequation.borderHO, 1)
     791            md.flowequation.borderFS = project2d(md, md.flowequation.borderFS, 1)
     792
     793        # Hydrologydc variables
     794        hydrofields = md.hydrology.__dict__.keys()
     795        for field in hydrofields:
     796            try:
     797                isvector = np.logical_or(np.shape(md.hydrology.__dict__[field])[0] == md.mesh.numberofelements,
     798                                         np.shape(md.hydrology.__dict__[field])[0] == md.mesh.numberofvertices)
     799            except IndexError:
     800                isvector = False
     801            #we colpase only fields that are vertices or element based
     802            if isvector:
     803                md.hydrology.__dict__[field] = project2d(md, md.hydrology.__dict__[field], 1)
     804
     805
     806        #boundary conditions
     807        md.stressbalance.spcvx = project2d(md, md.stressbalance.spcvx, md.mesh.numberoflayers)
     808        md.stressbalance.spcvy = project2d(md, md.stressbalance.spcvy, md.mesh.numberoflayers)
     809        md.stressbalance.spcvz = project2d(md, md.stressbalance.spcvz, md.mesh.numberoflayers)
     810        md.stressbalance.referential = project2d(md, md.stressbalance.referential, md.mesh.numberoflayers)
     811        md.stressbalance.loadingforce = project2d(md, md.stressbalance.loadingforce, md.mesh.numberoflayers)
     812        md.masstransport.spcthickness = project2d(md, md.masstransport.spcthickness, md.mesh.numberoflayers)
     813        md.thermal.spctemperature = project2d(md, md.thermal.spctemperature, md.mesh.numberoflayers - 1)
     814        if not np.isnan(md.damage.spcdamage).all():
     815            md.damage.spcdamage = project2d(md, md.damage.spcdamage, md.mesh.numberoflayers - 1)
     816
     817        #materials
     818        md.materials.rheology_B = DepthAverage(md, md.materials.rheology_B)
     819        md.materials.rheology_n = project2d(md, md.materials.rheology_n, 1)
     820
     821        #damage:
     822        if md.damage.isdamage:
     823            md.damage.D = DepthAverage(md, md.damage.D)
     824
     825        #special for thermal modeling:
     826        md.basalforcings.groundedice_melting_rate = project2d(md, md.basalforcings.groundedice_melting_rate, 1)
     827        md.basalforcings.floatingice_melting_rate = project2d(md, md.basalforcings.floatingice_melting_rate, 1)
     828        md.basalforcings.geothermalflux = project2d(md, md.basalforcings.geothermalflux, 1)  #bedrock only gets geothermal flux
     829
     830        #update of connectivity matrix
     831        md.mesh.average_vertex_connectivity = 25
     832
     833        #parameters
     834        md.geometry.surface = project2d(md, md.geometry.surface, 1)
     835        md.geometry.thickness = project2d(md, md.geometry.thickness, 1)
     836        md.geometry.base = project2d(md, md.geometry.base, 1)
     837        if isinstance(md.geometry.bed, np.ndarray):
     838            md.geometry.bed = project2d(md, md.geometry.bed, 1)
     839        md.mask.groundedice_levelset = project2d(md, md.mask.groundedice_levelset, 1)
     840        md.mask.ice_levelset = project2d(md, md.mask.ice_levelset, 1)
     841
     842        #OutputDefinitions
     843        if md.outputdefinition.definitions:
     844            for solutionfield, field in list(md.outputdefinition.__dict__.items()):
     845                if isinstance(field, list):
     846                    #get each definition
     847                    for i, fieldi in enumerate(field):
     848                        if fieldi:
     849                            fieldr = getattr(md.outputdefinition, solutionfield)[i]
     850                            #get subfields
     851                            for solutionsubfield, subfield in list(fieldi.__dict__.items()):
     852                                if np.size(subfield) == md.mesh.numberofvertices:
     853                                    setattr(fieldr, solutionsubfield, project2d(md, subfield, 1))
     854                                elif np.size(subfield) == md.mesh.numberofelements:
     855                                    setattr(fieldr, solutionsubfield, project2d(md, subfield, 1))
     856
     857        #Initialize with the 2d mesh
     858        mesh = mesh2d()
     859        mesh.x = md.mesh.x2d
     860        mesh.y = md.mesh.y2d
     861        mesh.numberofvertices = md.mesh.numberofvertices2d
     862        mesh.numberofelements = md.mesh.numberofelements2d
     863        mesh.elements = md.mesh.elements2d
     864        if not np.isnan(md.mesh.vertexonboundary).all():
     865            mesh.vertexonboundary = project2d(md, md.mesh.vertexonboundary, 1)
     866        if not np.isnan(md.mesh.elementconnectivity).all():
     867            mesh.elementconnectivity = project2d(md, md.mesh.elementconnectivity, 1)
     868        if isinstance(md.mesh.lat, np.ndarray):
     869            if md.mesh.lat.size == md.mesh.numberofvertices:
     870                mesh.lat = project2d(md, md.mesh.lat, 1)
     871        if isinstance(md.mesh.long, np.ndarray):
     872            if md.mesh.long.size == md.mesh.numberofvertices:
     873                md.mesh.long = project2d(md, md.mesh.long, 1)
     874        mesh.epsg = md.mesh.epsg
     875        if isinstance(md.mesh.scale_factor, np.ndarray):
     876            if md.mesh.scale_factor.size == md.mesh.numberofvertices:
     877                md.mesh.scale_factor = project2d(md, md.mesh.scale_factor, 1)
     878        md.mesh = mesh
     879        md.mesh.vertexconnectivity = NodeConnectivity(md.mesh.elements, md.mesh.numberofvertices)[0]
     880        md.mesh.elementconnectivity = ElementConnectivity(md.mesh.elements, md.mesh.vertexconnectivity)[0]
     881        md.mesh.segments = contourenvelope(md)
     882
     883        return md
    877884
    878885#}}}
  • issm/trunk-jpl/src/m/extrusion/DepthAverage.py

    r23716 r23787  
    1 import numpy as  np
     1import numpy as np
    22from project2d import project2d
    33
    4 def DepthAverage(md,vector):
    5         '''
    6         computes depth average of 3d vector using the trapezoidal rule, and returns
    7         the value on the 2d mesh.
    8        
    9         Usage:
    10                 vector_average=DepthAverage(md,vector)
    11        
    12         Example:
    13                 vel_bar=DepthAverage(md,md.initialization.vel)
    14         '''
    154
    16         #check that the model given in input is 3d
    17         if md.mesh.elementtype() != 'Penta':
    18                 raise TypeError('DepthAverage error message: the model given in input must be 3d')
     5def DepthAverage(md, vector):
     6    '''
     7    computes depth average of 3d vector using the trapezoidal rule, and returns
     8    the value on the 2d mesh.
    199
    20         # coerce to array in case float is passed
    21         if type(vector)!=np.ndarray:
    22                 print('coercing array')
    23                 vector=np.array(value)
     10    Usage:
     11            vector_average=DepthAverage(md,vector)
    2412
    25         vec2d=False
    26         if vector.ndim==2:
    27                 vec2d=True
    28                 vector=vector.reshape(-1,)
     13    Example:
     14            vel_bar=DepthAverage(md,md.initialization.vel)
     15    '''
    2916
    30         #nods data
    31         if vector.shape[0]==md.mesh.numberofvertices:
    32                 vector_average=np.zeros(md.mesh.numberofvertices2d)
    33                 for i in range(1,md.mesh.numberoflayers):
    34                         vector_average=vector_average+(project2d(md,vector,i)+project2d(md,vector,i+1))/2.*(project2d(md,md.mesh.z,i+1)-project2d(md,md.mesh.z,i))
    35                 vector_average=vector_average/project2d(md,md.geometry.thickness,1)
    36        
    37         #element data
    38         elif vector.shape[0]==md.mesh.numberofelements:
    39                 vector_average=np.zeros(md.mesh.numberofelements2d)
    40                 for i in range(1,md.mesh.numberoflayers):
    41                         vector_average=vector_average+project2d(md,vector,i)*(project2d(md,md.mesh.z,i+1)-project2d(md,md.mesh.z,i))
    42                 vector_average=vector_average/project2d(md,md.geometry.thickness,1)
    43        
    44         else:
    45                 raise ValueError('vector size not supported yet');
     17    #check that the model given in input is 3d
     18    if md.mesh.elementtype() != 'Penta':
     19        raise TypeError('DepthAverage error message: the model given in input must be 3d')
    4620
    47         if vec2d:
    48                 vector_average=vector_average.reshape(-1,)
     21    # coerce to array in case float is passed
     22    if type(vector) not in [np.ndarray, np.ma.core.MaskedArray]:
     23        print('coercing array')
     24        vector = np.array(vector)
    4925
    50         return vector_average
     26    vec2d = False
     27    if vector.ndim == 2:
     28        vec2d = True
     29        vector = vector.reshape(-1,)
     30
     31    #nods data
     32    if vector.shape[0] == md.mesh.numberofvertices:
     33        vector_average = np.zeros(md.mesh.numberofvertices2d)
     34        for i in range(1, md.mesh.numberoflayers):
     35            vector_average = vector_average + (project2d(md, vector, i) + project2d(md, vector, i + 1)) / 2. * (project2d(md, md.mesh.z, i + 1) - project2d(md, md.mesh.z, i))
     36        vector_average = vector_average / project2d(md, md.geometry.thickness, 1)
     37
     38    #element data
     39    elif vector.shape[0] == md.mesh.numberofelements:
     40        vector_average = np.zeros(md.mesh.numberofelements2d)
     41        for i in range(1, md.mesh.numberoflayers):
     42            vector_average = vector_average + project2d(md, vector, i) * (project2d(md, md.mesh.z, i + 1) - project2d(md, md.mesh.z, i))
     43        vector_average = vector_average / project2d(md, md.geometry.thickness, 1)
     44
     45    else:
     46        raise ValueError('vector size not supported yet')
     47
     48    if vec2d:
     49        vector_average = vector_average.reshape(-1,)
     50
     51    return vector_average
  • issm/trunk-jpl/src/m/extrusion/project2d.py

    r23716 r23787  
    1 import numpy as  np
     1import numpy as np
    22
    33def project2d(md3d,value,layer):
    4         '''
    5         returns the value of a field for a given layer of the mesh
    6        
     4    '''
     5        returns the value of a field for a given layer of the mesh
    76
    8    returns the value of a vector for a given layer from extruded mesh onto the 2d mesh
    9    used to do the extrusion. This function is used to compare values between different
    10    layers of a 3d mesh.
     7    returns the value of a vector for a given layer from extruded mesh onto the 2d mesh
     8    used to do the extrusion. This function is used to compare values between different
     9    layers of a 3d mesh.
    1110
    12    Usage:
     11    Usage:
    1312      projection_value=project2d(md3d,value,layer)
    1413
    15    Example:
     14    Example:
    1615      vel2=project2d(md3d,md3d.initialization.vel,2);
    1716      returns the velocity of the second layer (1 is the base)
    18         '''
     17        '''
    1918
    20         if md3d.mesh.domaintype().lower() != '3d':
    21                 raise Exception("model passed to project2d function should be 3D")
     19    if md3d.mesh.domaintype().lower() != '3d':
     20        raise Exception("model passed to project2d function should be 3D")
    2221
    23         if layer<1 or layer>md3d.mesh.numberoflayers:
    24                 raise ValueError("layer must be between 0 and %i" % md3d.mesh.numberoflayers)
    25        
    26         # coerce to array in case float is passed
    27         if type(value)!=np.ndarray:
    28                 print('coercing array')
    29                 value=np.array(value)
     22    if layer < 1 or layer > md3d.mesh.numberoflayers:
     23        raise ValueError("layer must be between 0 and {}".format(md3d.mesh.numberoflayers))
    3024
    31         vec2d=False
    32         if value.ndim==2 and value.shape[1]==1:
    33                 value=value.reshape(-1,)
    34                 vec2d=True
     25    # coerce to array in case float is passed
     26    if type(value) not in [np.ndarray, np.ma.core.MaskedArray]:
     27        print('coercing array')
     28        value = np.array(value)
    3529
    36         if value.size==1:
    37                 projection_value=value[(layer-1)*md3d.mesh.numberofelements2d:layer*md3d.mesh.numberofelements2d]
    38         elif value.shape[0]==md3d.mesh.numberofvertices:
    39                 #print 'indices: ', (layer-1)*md3d.mesh.numberofvertices2d, layer*md3d.mesh.numberofvertices2d
    40                 projection_value=value[(layer-1)*md3d.mesh.numberofvertices2d:layer*md3d.mesh.numberofvertices2d]
    41         elif value.shape[0]==md3d.mesh.numberofvertices+1:
    42                 projection_value=[value[(layer-1)*md3d.mesh.numberofvertices2d:layer*md3d.mesh.numberofvertices2d], value[-1]]
    43         else:
    44                 projection_value=value[(layer-1)*md3d.mesh.numberofelements2d:layer*md3d.mesh.numberofelements2d]
     30    vec2d = False
     31    if value.ndim == 2 and value.shape[1] == 1:
     32        value = value.reshape(-1,)
     33        vec2d = True
    4534
    46         if vec2d:
    47                 projection_value=projection_value.reshape(-1,)
     35    if value.size == 1:
     36        projection_value = value[(layer - 1) * md3d.mesh.numberofelements2d:layer * md3d.mesh.numberofelements2d]
     37    elif value.shape[0] == md3d.mesh.numberofvertices:
     38        #print 'indices: ', (layer-1)*md3d.mesh.numberofvertices2d, layer*md3d.mesh.numberofvertices2d
     39        projection_value = value[(layer - 1) * md3d.mesh.numberofvertices2d:layer * md3d.mesh.numberofvertices2d]
     40    elif value.shape[0] == md3d.mesh.numberofvertices + 1:
     41        projection_value = [value[(layer - 1) * md3d.mesh.numberofvertices2d:layer * md3d.mesh.numberofvertices2d], value[-1]]
     42    else:
     43        projection_value = value[(layer - 1) * md3d.mesh.numberofelements2d:layer * md3d.mesh.numberofelements2d]
    4844
    49         return projection_value
     45    if vec2d:
     46        projection_value = projection_value.reshape(-1,)
     47
     48    return projection_value
Note: See TracChangeset for help on using the changeset viewer.