def displayunit(offset, name, characterization, comment): # {{{ #take care of name if len(name) > 23: name = "%s..." % name[:20] #take care of characterization if m.strcmp(characterization, "''") or m.strcmp( characterization, '""') or m.strcmpi(characterization, 'nan'): characterization = "N/A" if len(characterization) > 15: characterization = "%s..." % characterization[:12] #print if not comment: string = "%s%-23s: %-15s" % (offset, name, characterization) else: if isinstance(comment, (str, unicode)): string = "%s%-23s: %-15s -- %s" % (offset, name, characterization, comment) elif isinstance(comment, list): string = "%s%-23s: %-15s -- %s" % (offset, name, characterization, comment[0]) for commenti in comment: string += "\n%s%-23s %-15s %s" % (offset, '', '', commenti) else: raise RuntimeError( "fielddisplay error message: format for comment not supported yet" ) return string
def FormatToCode(format): # {{{ """ This routine takes the format string, and hardcodes it into an integer, which is passed along the record, in order to identify the nature of the dataset being sent. """ if m.strcmpi(format, 'Boolean'): code = 1 elif m.strcmpi(format, 'Integer'): code = 2 elif m.strcmpi(format, 'Double'): code = 3 elif m.strcmpi(format, 'String'): code = 4 elif m.strcmpi(format, 'BooleanMat'): code = 5 elif m.strcmpi(format, 'IntMat'): code = 6 elif m.strcmpi(format, 'DoubleMat'): code = 7 elif m.strcmpi(format, 'MatArray'): code = 8 elif m.strcmpi(format, 'StringArray'): code = 9 elif m.strcmpi(format, 'CompressedMat'): code = 10 else: raise InputError( 'FormatToCode error message: data type not supported yet!') return code
def list_display(offset, name, field, comment): # {{{ #initialization if isinstance(field, list): sbeg = '[' send = ']' elif isinstance(field, tuple): sbeg = '(' send = ')' string = sbeg #go through the cell and fill string if len(field) < 5: for fieldi in field: if isinstance(fieldi, (str, unicode)): string += "'%s'," % fieldi elif isinstance(fieldi, (bool, int, long, float)): string += "%s," % str(fieldi) else: string = sbeg break if m.strcmp(string, sbeg): string = "%s%dx1%s" % (sbeg, len(field), send) else: string = string[:-1] + send #call displayunit return displayunit(offset, name, string, comment)
def checkconsistency(self, md, solution, analyses): # {{{ md = checkfield(md, 'fieldname', 'mesh.x', 'NaN', 1, 'Inf', 1, 'size', [md.mesh.numberofvertices]) md = checkfield(md, 'fieldname', 'mesh.y', 'NaN', 1, 'Inf', 1, 'size', [md.mesh.numberofvertices]) md = checkfield(md, 'fieldname', 'mesh.z', 'NaN', 1, 'Inf', 1, 'size', [md.mesh.numberofvertices]) md = checkfield(md, 'fieldname', 'mesh.elements', 'NaN', 1, 'Inf', 1, '>', 0, 'values', np.arange(1, md.mesh.numberofvertices + 1)) md = checkfield(md, 'fieldname', 'mesh.elements', 'size', [md.mesh.numberofelements, 6]) if np.any( np.logical_not( m.ismember(np.arange(1, md.mesh.numberofvertices + 1), md.mesh.elements))): md.checkmessage( "orphan nodes have been found. Check the mesh3dprisms outline") md = checkfield(md, 'fieldname', 'mesh.numberoflayers', '>=', 0) md = checkfield(md, 'fieldname', 'mesh.numberofelements', '>', 0) md = checkfield(md, 'fieldname', 'mesh.numberofvertices', '>', 0) md = checkfield(md, 'fieldname', 'mesh.vertexonbase', 'size', [md.mesh.numberofvertices], 'values', [0, 1]) md = checkfield(md, 'fieldname', 'mesh.vertexonsurface', 'size', [md.mesh.numberofvertices], 'values', [0, 1]) md = checkfield( md, 'fieldname', 'mesh.average_vertex_connectivity', '>=', 24, 'message', "'mesh.average_vertex_connectivity' should be at least 24 in 3d") return md
def Download(self, dirname, filelist): # {{{ if m.ispc(): #do nothing return #copy files from cluster to current directory directory = '%s/%s/' % (self.executionpath, dirname) issmscpin(self.hostname, self.login, self.port, directory, filelist)
def __init__(self, *args): # {{{ self._currentstep = 0 self.repository = './' self.prefix = 'model.' self.trunkprefix = '' self.steps = [] self.requestedsteps = [0] #process options options = pairoptions.pairoptions(*args) #Get prefix prefix = options.getfieldvalue('prefix', 'model.') if not isinstance(prefix, (str, unicode)): raise TypeError("prefix is not a string") if not m.strcmp(prefix, prefix.strip()) or len(prefix.split()) > 1: raise TypeError("prefix should not have any white space") self.prefix = prefix #Get repository repository = options.getfieldvalue('repository', './') if not isinstance(repository, (str, unicode)): raise TypeError("repository is not a string") if not os.path.isdir(repository): raise IOError("Directory '%s' not found" % repository) self.repository = repository #Get steps self.requestedsteps = options.getfieldvalue('steps', [0]) #Get trunk prefix (only if provided by user) if options.exist('trunkprefix'): trunkprefix = options.getfieldvalue('trunkprefix', '') if not isinstance(trunkprefix, (str, unicode)): raise TypeError("trunkprefix is not a string") if not m.strcmp(trunkprefix, trunkprefix.strip()) or len( trunkprefix.split()) > 1: raise TypeError("trunkprefix should not have any white space") self.trunkprefix = trunkprefix
def BuildKrigingQueueScript(self, modelname, solution, io_gather, isvalgrind, isgprof): # {{{ #write queuing script if not m.ispc(): fid = open(modelname + '.queue', 'w') fid.write('#!/bin/sh\n') if not isvalgrind: if self.interactive: fid.write('srun -np %i %s/kriging.exe %s/%s %s ' % (self.np, self.codepath, self.executionpath, modelname, modelname)) else: fid.write( 'srun -np %i %s/kriging.exe %s/%s %s 2> %s.errlog >%s.outlog ' % (self.np, self.codepath, self.executionpath, modelname, modelname, modelname, modelname)) elif isgprof: fid.write('\n gprof %s/kriging.exe gmon.out > %s.performance' & (self.codepath, modelname)) else: #Add --gen-suppressions=all to get suppression lines fid.write('LD_PRELOAD=%s \\\n' % self.valgrindlib) fid.write('mpiexec -np %i %s --leak-check=full --suppressions=%s %s/kriging.exe %s/%s %s 2> %s.errlog >%s.outlog ' % \ (self.np,self.valgrind,self.valgrindsup,self.codepath,self.executionpath,modelname,modelname,modelname,modelname)) if not io_gather: #concatenate the output files: fid.write('\ncat %s.outbin.* > %s.outbin' % (modelname, modelname)) fid.close() else: # Windows fid = open(modelname + '.bat', 'w') fid.write('@echo off\n') if self.interactive: fid.write('"%s/issm.exe" %s "%s/%s" %s ' % (self.codepath, solution, self.executionpath, modelname, modelname)) else: fid.write('"%s/issm.exe" %s "%s/%s" %s 2> %s.errlog >%s.outlog' % \ (self.codepath,solution,self.executionpath,modelname,modelname,modelname,modelname)) fid.close() #in interactive mode, create a run file, and errlog and outlog file if self.interactive: fid = open(modelname + '.errlog', 'w') fid.close() fid = open(modelname + '.outlog', 'w') fid.close()
def checkconsistency(self,md,solution,analyses): # {{{ md = checkfield(md,'fieldname','mask.groundedice_levelset','size',[md.mesh.numberofvertices]) md = checkfield(md,'fieldname','mask.ice_levelset' ,'size',[md.mesh.numberofvertices]) md = checkfield(md,'fieldname','mask.ocean_levelset','size',[md.mesh.numberofvertices]) md = checkfield(md,'fieldname','mask.land_levelset','size',[md.mesh.numberofvertices]) isice=(md.mask.ice_levelset<=0) if sum(isice)==0: print('no ice present in the domain') if max(md.mask.ice_levelset)<0: print('no ice front provided') elements=md.mesh.elements-1; elements=elements.astype(np.int32, copy=False); icefront=np.sum(md.mask.ice_levelset[elements]==0,axis=1) if (max(icefront)==3 & m.strcmp(md.mesh.elementtype(),'Tria')) or (max(icefront==6) & m.strcmp(md.mesh.elementtype(),'Penta')): raise RuntimeError('At least one element has all nodes on ice front, change md.mask.ice_levelset to fix it') return md
def BuildQueueScript(self, dirname, modelname, solution, io_gather, isvalgrind, isgprof, isdakota, isoceancoupling): # {{{ executable = 'issm.exe' if isdakota: version = IssmConfig('_DAKOTA_VERSION_')[0:2] version = float(version) if version >= 6: executable = 'issm_dakota.exe' if isoceancoupling: executable = 'issm_ocean.exe' #write queuing script if not m.ispc(): fid = open(modelname + '.queue', 'w') #fid.write('#!/bin/bash -l\n\n') #fid.write('#SBATCH -N 1\n') #fid.write('#SBATCH -J my_job\n') #fid.write('#SBATCH --export=ALL\n\n') fid.write('#!/bin/bash\n') fid.write('#SBATCH --nodes=%i\n' % 1) #self.np) fid.write('#SBATCH --ntasks=%i\n' % 1) fid.write('#SBATCH --ntasks-per-node=%i\n' % 1) fid.write('#SBATCH --cpus-per-task=%i\n' % 1) fid.write('#SBATCH --job-name=%s\n' % modelname) #fid.write('#SBATCH -t %i\n',cluster.time*60); fid.write('#SBATCH -p smp \n') fid.write('#SBATCH -o %s.outlog \n' % modelname) fid.write('#SBATCH -e %s.errlog \n' % modelname) fid.write('#SBATCH --get-user-env \n') #fid.write('## Enlarge the stacksize. OpenMP-codes usually need a large stack. \n') #fid.write('ulimit -s unlimited\n') #fid.write('## This binds each thread to one core \n') #fid.write('export OMP_PROC_BIND=TRUE \n') #fid.write('## Number of threads as given by -c / --cpus-per-task \n') #fid.write('export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK \n') #fid.write('## This code snippet checks the task and thread distribution on the cores. \n') #fid.write('srun /global/AWIsoft/xthi/xthi.intel | sort -n -k4,4 -k6,6 > xthi.log \n') pth = self.executionpath + '/' + dirname fid.write('srun %s/issm.exe %s %s %s > %s.log\n' % (self.codepath, solution, pth, modelname, modelname))
def perform(self, string): # {{{ bool = False #Some checks if not isinstance(string, (str, unicode)): raise TypeError("Step provided should be a string") if not m.strcmp(string, string.strip()) or len(string.split()) > 1: raise TypeError("Step provided should not have any white space") if self._currentstep > 0 and string in [ step['string'] for step in self.steps ]: raise RuntimeError("Step '%s' already present. Change name" % string) #Add step self.steps.append(OrderedDict()) self.steps[-1]['id'] = len(self.steps) self.steps[-1]['string'] = string self._currentstep += 1 #if requestedsteps = 0, print all steps in self if 0 in self.requestedsteps: if self._currentstep == 1: print " prefix: %s" % self.prefix print " step #%i : %s" % ( self.steps[self._currentstep - 1]['id'], self.steps[self._currentstep - 1]['string']) #Ok, now if _currentstep is a member of steps, return true if self._currentstep in self.requestedsteps: print "\n step #%i : %s\n" % ( self.steps[self._currentstep - 1]['id'], self.steps[self._currentstep - 1]['string']) bool = True #assign self back to calling workspace # (no need, since Python modifies class instance directly) return bool
def checkconsistency(self, md, solution, analyses): # {{{ #Early return if ('StressbalanceAnalysis' not in analyses and 'StressbalanceSIAAnalysis' not in analyses) or (solution == 'TransientSolution' and not md.transient.isstressbalance): return md md = checkfield(md, 'fieldname', 'flowequation.isSIA', 'numel', [1], 'values', [0, 1]) md = checkfield(md, 'fieldname', 'flowequation.isSSA', 'numel', [1], 'values', [0, 1]) md = checkfield(md, 'fieldname', 'flowequation.isL1L2', 'numel', [1], 'values', [0, 1]) md = checkfield(md, 'fieldname', 'flowequation.isHO', 'numel', [1], 'values', [0, 1]) md = checkfield(md, 'fieldname', 'flowequation.isFS', 'numel', [1], 'values', [0, 1]) md = checkfield( md, 'fieldname', 'flowequation.fe_SSA', 'values', ['P1', 'P1bubble', 'P1bubblecondensed', 'P2', 'P2bubble']) md = checkfield(md, 'fieldname', 'flowequation.fe_HO', 'values', [ 'P1', 'P1bubble', 'P1bubblecondensed', 'P1xP2', 'P2xP1', 'P2', 'P2bubble', 'P1xP3', 'P2xP4' ]) md = checkfield(md, 'fieldname', 'flowequation.fe_FS', 'values', [ 'P1P1', 'P1P1GLS', 'MINIcondensed', 'MINI', 'TaylorHood', 'XTaylorHood', 'OneLayerP4z', 'CrouzeixRaviart' ]) md = checkfield(md, 'fieldname', 'flowequation.borderSSA', 'size', [md.mesh.numberofvertices], 'values', [0, 1]) md = checkfield(md, 'fieldname', 'flowequation.borderHO', 'size', [md.mesh.numberofvertices], 'values', [0, 1]) md = checkfield(md, 'fieldname', 'flowequation.borderFS', 'size', [md.mesh.numberofvertices], 'values', [0, 1]) md = checkfield(md, 'fieldname', 'flowequation.augmented_lagrangian_r', 'numel', [1], '>', 0.) md = checkfield(md, 'fieldname', 'flowequation.augmented_lagrangian_rhop', 'numel', [1], '>', 0.) md = checkfield(md, 'fieldname', 'flowequation.augmented_lagrangian_rlambda', 'numel', [1], '>', 0.) md = checkfield(md, 'fieldname', 'flowequation.augmented_lagrangian_rholambda', 'numel', [1], '>', 0.) md = checkfield(md, 'fieldname', 'flowequation.XTH_theta', 'numel', [1], '>=', 0., '<', .5) if m.strcmp(md.mesh.domaintype(), '2Dhorizontal'): md = checkfield(md, 'fieldname', 'flowequation.vertex_equation', 'size', [md.mesh.numberofvertices], 'values', [1, 2]) md = checkfield(md, 'fieldname', 'flowequation.element_equation', 'size', [md.mesh.numberofelements], 'values', [1, 2]) elif m.strcmp(md.mesh.domaintype(), '3D'): md = checkfield(md, 'fieldname', 'flowequation.vertex_equation', 'size', [md.mesh.numberofvertices], 'values', np.arange(0, 8 + 1)) md = checkfield(md, 'fieldname', 'flowequation.element_equation', 'size', [md.mesh.numberofelements], 'values', np.arange(0, 8 + 1)) else: raise RuntimeError('mesh type not supported yet') if not (self.isSIA or self.isSSA or self.isL1L2 or self.isHO or self.isFS): md.checkmessage("no element types set for this model") if 'StressbalanceSIAAnalysis' in analyses: if any(self.element_equation == 1): if np.any( np.logical_and(self.vertex_equation, md.mask.groundedice_levelset)): print "\n !!! Warning: SIA's model is not consistent on ice shelves !!!\n" return md
def ComputeHessian(index, x, y, field, type): """ COMPUTEHESSIAN - compute hessian matrix from a field Compute the hessian matrix of a given field return the three components Hxx Hxy Hyy for each element or each node Usage: hessian=ComputeHessian(index,x,y,field,type) Example: hessian=ComputeHessian(md.mesh.elements,md.mesh.x,md.mesh.y,md.inversion.vel_obs,'node') """ #some variables numberofnodes = np.size(x) numberofelements = np.size(index, axis=0) #some checks if np.size(field) != numberofnodes and np.size(field) != numberofelements: raise TypeError( "ComputeHessian error message: the given field size not supported yet" ) if not m.strcmpi(type, 'node') and not m.strcmpi(type, 'element'): raise TypeError( "ComputeHessian error message: only 'node' or 'element' type supported yet" ) #initialization line = index.reshape(-1, order='F') linesize = 3 * numberofelements #get areas and nodal functions coefficients N(x,y)=alpha x + beta y + gamma [alpha, beta, dum] = GetNodalFunctionsCoeff(index, x, y) areas = GetAreas(index, x, y) #compute weights that hold the volume of all the element holding the node i weights = m.sparse(line, np.ones((linesize, 1)), np.tile(areas.reshape(-1, ), (3, 1)), numberofnodes, 1) #compute field on nodes if on elements if np.size(field, axis=0) == numberofelements: field = m.sparse(line, np.ones( (linesize, 1)), np.tile(areas * field, (3, 1)), numberofnodes, 1) / weights #Compute gradient for each element grad_elx = np.sum(field[index - 1, 0] * alpha, axis=1) grad_ely = np.sum(field[index - 1, 0] * beta, axis=1) #Compute gradient for each node (average of the elements around) gradx = m.sparse(line, np.ones((linesize, 1)), np.tile((areas * grad_elx).reshape(-1, ), (3, 1)), numberofnodes, 1) grady = m.sparse(line, np.ones((linesize, 1)), np.tile((areas * grad_ely).reshape(-1, ), (3, 1)), numberofnodes, 1) gradx = gradx / weights grady = grady / weights #Compute hessian for each element hessian = np.vstack( (np.sum(gradx[index - 1, 0] * alpha, axis=1).reshape(-1, ), np.sum(grady[index - 1, 0] * alpha, axis=1).reshape(-1, ), np.sum(grady[index - 1, 0] * beta, axis=1).reshape(-1, ))).T if m.strcmpi(type, 'node'): #Compute Hessian on the nodes (average of the elements around) hessian = np.hstack( (m.sparse(line, np.ones((linesize, 1)), np.tile((areas * hessian[:, 0]).reshape(-1, ), (3, 1)), numberofnodes, 1) / weights, m.sparse(line, np.ones((linesize, 1)), np.tile((areas * hessian[:, 1]).reshape(-1, ), (3, 1)), numberofnodes, 1) / weights, m.sparse(line, np.ones((linesize, 1)), np.tile((areas * hessian[:, 2]).reshape(-1, ), (3, 1)), numberofnodes, 1) / weights)) return hessian
def BuildQueueScript(self, dirname, modelname, solution, io_gather, isvalgrind, isgprof, isdakota, isoceancoupling): # {{{ executable = 'issm.exe' if isdakota: version = IssmConfig('_DAKOTA_VERSION_')[0:2] version = float(version) if version >= 6: executable = 'issm_dakota.exe' if isoceancoupling: executable = 'issm_ocean.exe' #write queuing script if not m.ispc(): fid = open(modelname + '.queue', 'w') fid.write('#!/bin/sh\n') if not isvalgrind: if self.interactive: if IssmConfig('_HAVE_MPI_')[0]: fid.write( 'mpiexec -np %i %s/%s %s %s/%s %s ' % (self.np, self.codepath, executable, solution, self.executionpath, dirname, modelname)) else: fid.write('%s/%s %s %s/%s %s ' % (self.codepath, executable, solution, self.executionpath, dirname, modelname)) else: if IssmConfig('_HAVE_MPI_')[0]: fid.write( 'mpiexec -np %i %s/%s %s %s/%s %s 2> %s.errlog >%s.outlog ' % (self.np, self.codepath, executable, solution, self.executionpath, dirname, modelname, modelname, modelname)) else: fid.write( '%s/%s %s %s/%s %s 2> %s.errlog >%s.outlog ' % (self.codepath, executable, solution, self.executionpath, dirname, modelname, modelname, modelname)) elif isgprof: fid.write('\n gprof %s/%s gmon.out > %s.performance' % (self.codepath, executable, modelname)) else: #Add --gen-suppressions=all to get suppression lines fid.write('LD_PRELOAD=%s \\\n' % self.valgrindlib) if IssmConfig('_HAVE_MPI_')[0]: fid.write('mpiexec -np %i %s --leak-check=full --suppressions=%s %s/%s %s %s/%s %s 2> %s.errlog >%s.outlog ' % \ (self.np,self.valgrind,self.valgrindsup,self.codepath,executable,solution,self.executionpath,dirname,modelname,modelname,modelname)) else: fid.write('%s --leak-check=full --suppressions=%s %s/%s %s %s/%s %s 2> %s.errlog >%s.outlog ' % \ (self.valgrind,self.valgrindsup,self.codepath,executable,solution,self.executionpath,dirname,modelname,modelname,modelname)) if not io_gather: #concatenate the output files: fid.write('\ncat %s.outbin.* > %s.outbin' % (modelname, modelname)) fid.close() else: # Windows fid = open(modelname + '.bat', 'w') fid.write('@echo off\n') if self.interactive: fid.write('"%s/%s" %s "%s/%s" %s ' % (self.codepath, executable, solution, self.executionpath, dirname, modelname)) else: fid.write('"%s/%s" %s "%s/%s" %s 2> %s.errlog >%s.outlog' % \ (self.codepath,executable,solution,self.executionpath,dirname,modelname,modelname,modelname)) fid.close() #in interactive mode, create a run file, and errlog and outlog file if self.interactive: fid = open(modelname + '.errlog', 'w') fid.close() fid = open(modelname + '.outlog', 'w') fid.close()
def loadresultsfromdisk(md, filename): """ LOADRESULTSFROMDISK - load results of solution sequence from disk file "filename" Usage: md=loadresultsfromdisk(md=False,filename=False); """ #check number of inputs/outputs if not md or not filename: raise ValueError("loadresultsfromdisk: error message.") if not md.qmu.isdakota: #Check that file exists if not os.path.exists(filename): raise OSError("binary file '%s' not found." % filename) #initialize md.results if not a structure yet if not isinstance(md.results, results): md.results = results() #load results onto model structure = parseresultsfromdisk(md, filename, not md.settings.io_gather) if not len(structure): raise RuntimeError( "No result found in binary file '%s'. Check for solution crash." % filename) setattr(md.results, structure[0].SolutionType, structure) #recover solution_type from results md.private.solution = structure[0].SolutionType #read log files onto fields if os.path.exists(md.miscellaneous.name + '.errlog'): with open(md.miscellaneous.name + '.errlog', 'r') as f: setattr( getattr(md.results, structure[0].SolutionType)[0], 'errlog', [line[:-1] for line in f]) else: setattr( getattr(md.results, structure[0].SolutionType)[0], 'errlog', []) if os.path.exists(md.miscellaneous.name + '.outlog'): with open(md.miscellaneous.name + '.outlog', 'r') as f: setattr( getattr(md.results, structure[0].SolutionType)[0], 'outlog', [line[:-1] for line in f]) else: setattr( getattr(md.results, structure[0].SolutionType)[0], 'outlog', []) if len(getattr(md.results, structure[0].SolutionType)[0].errlog): print( "loadresultsfromcluster info message: error during solution. Check your errlog and outlog model fields." ) #if only one solution, extract it from list for user friendliness if len(structure) == 1 and not m.strcmp(structure[0].SolutionType, 'TransientSolution'): setattr(md.results, structure[0].SolutionType, structure[0]) #post processes qmu results if necessary else: md = postqmu(md) os.chdir('..') return md
def bamg(md,*args): """ BAMG - mesh generation Available options (for more details see ISSM website http://issm.jpl.nasa.gov/): - domain : followed by an ARGUS file that prescribes the domain outline - hmin : minimum edge length (default is 10^-100) - hmax : maximum edge length (default is 10^100) - hVertices : imposed edge length for each vertex (geometry or mesh) - hminVertices : minimum edge length for each vertex (mesh) - hmaxVertices : maximum edge length for each vertex (mesh) - anisomax : maximum ratio between the smallest and largest edges (default is 10^30) - coeff : coefficient applied to the metric (2-> twice as many elements, default is 1) - cutoff : scalar used to compute the metric when metric type 2 or 3 are applied - err : error used to generate the metric from a field - errg : geometric error (default is 0.1) - field : field of the model that will be used to compute the metric to apply several fields, use one column per field - gradation : maximum ratio between two adjacent edges - Hessiantype : 0 -> use double P2 projection (default) 1 -> use Green formula - KeepVertices : try to keep initial vertices when adaptation is done on an existing mesh (default 1) - MaxCornerAngle : maximum angle of corners in degree (default is 10) - maxnbv : maximum number of vertices used to allocate memory (default is 10^6) - maxsubdiv : maximum subdivision of exisiting elements (default is 10) - metric : matrix (numberofnodes x 3) used as a metric - Metrictype : 1 -> absolute error c/(err coeff^2) * Abs(H) (default) 2 -> relative error c/(err coeff^2) * Abs(H)/max(s,cutoff*max(s)) 3 -> rescaled absolute error c/(err coeff^2) * Abs(H)/(smax-smin) - nbjacoby : correction used by Hessiantype=1 (default is 1) - nbsmooth : number of metric smoothing procedure (default is 3) - omega : relaxation parameter of the smoothing procedure (default is 1.8) - power : power applied to the metric (default is 1) - splitcorners : split triangles whuch have 3 vertices on the outline (default is 1) - geometricalmetric : take the geometry into account to generate the metric (default is 0) - verbose : level of verbosity (default is 1) - rifts : followed by an ARGUS file that prescribes the rifts - toltip : tolerance to move tip on an existing point of the domain outline - tracks : followed by an ARGUS file that prescribes the tracks that the mesh will stick to - RequiredVertices : mesh vertices that are required. [x,y,ref]; ref is optional - tol : if the distance between 2 points of the domain outline is less than tol, they will be merged Examples: md=bamg(md,'domain','DomainOutline.exp','hmax',3000); md=bamg(md,'field',[md.inversion.vel_obs md.geometry.thickness],'hmax',20000,'hmin',1000); md=bamg(md,'metric',A,'hmin',1000,'hmax',20000,'gradation',3,'anisomax',1); """ #process options options=pairoptions(*args) # options=deleteduplicates(options,1); #initialize the structures required as input of Bamg bamg_options=OrderedDict() bamg_geometry=bamggeom() bamg_mesh=bamgmesh() # Bamg Geometry parameters {{{ if options.exist('domain'): #Check that file exists domainfile=options.getfieldvalue('domain') if not os.path.exists(domainfile): raise IOError("bamg error message: file '%s' not found" % domainfile) domain=expread(domainfile) #Build geometry count=0 for i,domaini in enumerate(domain): #Check that the domain is closed if (domaini['x'][0]!=domaini['x'][-1] or domaini['y'][0]!=domaini['y'][-1]): raise RuntimeError("bamg error message: all contours provided in ''domain'' should be closed") #Checks that all holes are INSIDE the principle domain outline if i: flags=ContourToNodes(domaini['x'],domaini['y'],domainfile,0)[0] if np.any(np.logical_not(flags)): raise RuntimeError("bamg error message: All holes should be strictly inside the principal domain") #Add all points to bamg_geometry nods=domaini['nods']-1 #the domain are closed 0=end bamg_geometry.Vertices=np.vstack((bamg_geometry.Vertices,np.vstack((domaini['x'][0:nods],domaini['y'][0:nods],np.ones((nods)))).T)) bamg_geometry.Edges =np.vstack((bamg_geometry.Edges,np.vstack((np.arange(count+1,count+nods+1),np.hstack((np.arange(count+2,count+nods+1),count+1)),1.*np.ones((nods)))).T)) if i: bamg_geometry.SubDomains=np.vstack((bamg_geometry.SubDomains,[2,count+1,1,1])) # bamg_geometry.Vertices=np.hstack((bamg_geometry.Vertices,np.vstack((domaini['x'][0:nods].reshape(-1),domaini['y'][0:nods].reshape(-1),np.ones((nods)))))) # bamg_geometry.Edges =np.vstack((bamg_geometry.Edges,np.hstack((np.arange(count+1,count+nods+1).reshape(-1,),np.hstack((np.arange(count+2,count+nods+1),count+1)).reshape(-1,),1.*np.ones((nods,)))))) # if i: # bamg_geometry.SubDomains=np.vstack((bamg_geometry.SubDomains,[2,count+1,1,1])) #update counter count+=nods #take care of rifts if options.exist('rifts'): #Check that file exists riftfile=options.getfieldvalue('rifts') if not os.path.exists(riftfile): raise IOError("bamg error message: file '%s' not found" % riftfile) rift=expread(riftfile) for i,rifti in enumerate(rift): #detect whether all points of the rift are inside the domain flags=ContourToNodes(rifti['x'],rifti['y'],domain[0],0)[0] if np.all(np.logical_not(flags)): raise RuntimeError("one rift has all its points outside of the domain outline") elif np.any(np.logical_not(flags)): #We LOTS of work to do print "Rift tip outside of or on the domain has been detected and is being processed..." #check that only one point is outside (for now) if np.sum(np.logical_not(flags).astype(int))!=1: raise RuntimeError("bamg error message: only one point outside of the domain is supported yet") #Move tip outside to the first position if not flags[0]: #OK, first point is outside (do nothing), pass elif not flags[-1]: rifti['x']=np.flipud(rifti['x']) rifti['y']=np.flipud(rifti['y']) else: raise RuntimeError("bamg error message: only a rift tip can be outside of the domain") #Get cordinate of intersection point x1=rifti['x'][0] y1=rifti['y'][0] x2=rifti['x'][1] y2=rifti['y'][1] for j in xrange(0,np.size(domain[0]['x'])-1): if SegIntersect(np.array([[x1,y1],[x2,y2]]),np.array([[domain[0]['x'][j],domain[0]['y'][j]],[domain[0]['x'][j+1],domain[0]['y'][j+1]]])): #Get position of the two nodes of the edge in domain i1=j i2=j+1 #rift is crossing edge [i1 i2] of the domain #Get coordinate of intersection point (http://mathworld.wolfram.com/Line-LineIntersection.html) x3=domain[0]['x'][i1] y3=domain[0]['y'][i1] x4=domain[0]['x'][i2] y4=domain[0]['y'][i2] # x=det([det([x1 y1; x2 y2]) x1-x2;det([x3 y3; x4 y4]) x3-x4])/det([x1-x2 y1-y2;x3-x4 y3-y4]); # y=det([det([x1 y1; x2 y2]) y1-y2;det([x3 y3; x4 y4]) y3-y4])/det([x1-x2 y1-y2;x3-x4 y3-y4]); x=np.linalg.det(np.array([[np.linalg.det(np.array([[x1,y1],[x2,y2]])),x1-x2],[np.linalg.det(np.array([[x3,y3],[x4,y4]])),x3-x4]]))/np.linalg.det(np.array([[x1-x2,y1-y2],[x3-x4,y3-y4]])) y=np.linalg.det(np.array([[np.linalg.det(np.array([[x1,y1],[x2,y2]])),y1-y2],[np.linalg.det(np.array([[x3,y3],[x4,y4]])),y3-y4]]))/np.linalg.det(np.array([[x1-x2,y1-y2],[x3-x4,y3-y4]])) segdis= sqrt((x4-x3)**2+(y4-y3)**2) tipdis=np.array([sqrt((x-x3)**2+(y-y3)**2),sqrt((x-x4)**2+(y-y4)**2)]) if np.min(tipdis)/segdis < options.getfieldvalue('toltip',0): print "moving tip-domain intersection point" #Get position of the closer point if tipdis[0]>tipdis[1]: pos=i2 else: pos=i1 #This point is only in Vertices (number pos). #OK, now we can add our own rift nods=rifti['nods']-1 bamg_geometry.Vertices=np.vstack((bamg_geometry.Vertices,np.hstack((rifti['x'][1:].reshape(-1,),rifti['y'][1:].reshape(-1,),np.ones((nods,1)))))) bamg_geometry.Edges=np.vstack((bamg_geometry.Edges,\ np.array([[pos,count+1,(1+i)]]),\ np.hstack((np.arange(count+1,count+nods).reshape(-1,),np.arange(count+2,count+nods+1).reshape(-1,),(1+i)*np.ones((nods-1,1)))))) count+=nods break else: #Add intersection point to Vertices bamg_geometry.Vertices=np.vstack((bamg_geometry.Vertices,np.array([[x,y,1]]))) count+=1 #Decompose the crossing edge into 2 subedges pos=np.nonzero(np.logical_and(bamg_geometry.Edges[:,0]==i1,bamg_geometry.Edges[:,1]==i2))[0] if not pos: raise RuntimeError("bamg error message: a problem occurred...") bamg_geometry.Edges=np.vstack((bamg_geometry.Edges[0:pos-1,:],\ np.array([[bamg_geometry.Edges[pos,0],count ,bamg_geometry.Edges[pos,2]]]),\ np.array([[count ,bamg_geometry.Edges[pos,1],bamg_geometry.Edges[pos,2]]]),\ bamg_geometry.Edges[pos+1:,:])) #OK, now we can add our own rift nods=rifti['nods']-1 bamg_geometry.Vertices=np.vstack((bamg_geometry.Vertices,np.hstack((rifti['x'][1:].reshape(-1,),rifti['y'][1:].reshape(-1,),np.ones((nods,1)))))) bamg_geometry.Edges=np.vstack((bamg_geometry.Edges,\ np.array([[count,count+1,2]]),\ np.hstack((np.arange(count+1,count+nods).reshape(-1,),np.arange(count+2,count+nods+1).reshape(-1,),(1+i)*np.ones((nods-1,1)))))) count+=nods break else: nods=rifti['nods']-1 bamg_geometry.Vertices=np.vstack(bamg_geometry.Vertices, np.hstack(rifti['x'][:],rifti['y'][:],np.ones((nods+1,1)))) bamg_geometry.Edges =np.vstack(bamg_geometry.Edges, np.hstack(np.arange(count+1,count+nods).reshape(-1,),np.arange(count+2,count+nods+1).reshape(-1,),i*np.ones((nods,1)))) count=+nods+1 #Deal with tracks if options.exist('tracks'): #read tracks track=options.getfieldvalue('tracks') if all(isinstance(track,(str,unicode))): A=expread(track) track=np.hstack((A.x.reshape(-1,),A.y.reshape(-1,))) else: track=float(track) #for some reason, it is of class "single" if np.size(track,axis=1)==2: track=np.hstack((track,3.*np.ones((size(track,axis=0),1)))) #only keep those inside flags=ContourToNodes(track[:,0],track[:,1],domainfile,0)[0] track=track[np.nonzero(flags),:] #Add all points to bamg_geometry nods=np.size(track,axis=0) bamg_geometry.Vertices=np.vstack((bamg_geometry.Vertices,track)) bamg_geometry.Edges =np.vstack((bamg_geometry.Edges,np.hstack((np.arange(count+1,count+nods).reshape(-1,),np.arange(count+2,count+nods+1).reshape(-1,),3.*np.ones((nods-1,1)))))) #update counter count+=nods #Deal with vertices that need to be kept by mesher if options.exist('RequiredVertices'): #recover RequiredVertices requiredvertices=options.getfieldvalue('RequiredVertices') #for some reason, it is of class "single" if np.size(requiredvertices,axis=1)==2: requiredvertices=np.hstack((requiredvertices,4.*np.ones((np.size(requiredvertices,axis=0),1)))) #only keep those inside flags=ContourToNodes(requiredvertices[:,0],requiredvertices[:,1],domainfile,0)[0] requiredvertices=requiredvertices[np.nonzero(flags)[0],:] #Add all points to bamg_geometry nods=np.size(requiredvertices,axis=0) bamg_geometry.Vertices=np.vstack((bamg_geometry.Vertices,requiredvertices)) #update counter count+=nods #process geom #bamg_geometry=processgeometry(bamg_geometry,options.getfieldvalue('tol',float(nan)),domain[0]) elif isinstance(md.private.bamg,dict) and 'geometry' in md.private.bamg: bamg_geometry=bamggeom(md.private.bamg['geometry'].__dict__) else: #do nothing... pass #}}} # Bamg Mesh parameters {{{ if not options.exist('domain') and md.mesh.numberofvertices and m.strcmp(md.mesh.elementtype(),'Tria'): if isinstance(md.private.bamg,dict) and 'mesh' in md.private.bamg: bamg_mesh=bamgmesh(md.private.bamg['mesh'].__dict__) else: bamg_mesh.Vertices=np.vstack((md.mesh.x,md.mesh.y,np.ones((md.mesh.numberofvertices)))).T #bamg_mesh.Vertices=np.hstack((md.mesh.x.reshape(-1,),md.mesh.y.reshape(-1,),np.ones((md.mesh.numberofvertices,1)))) bamg_mesh.Triangles=np.hstack((md.mesh.elements,np.ones((md.mesh.numberofelements,1)))) if isinstance(md.rifts.riftstruct,dict): raise TypeError("bamg error message: rifts not supported yet. Do meshprocessrift AFTER bamg") #}}} # Bamg Options {{{ bamg_options['Crack']=options.getfieldvalue('Crack',0) bamg_options['anisomax']=options.getfieldvalue('anisomax',10.**30) bamg_options['coeff']=options.getfieldvalue('coeff',1.) bamg_options['cutoff']=options.getfieldvalue('cutoff',10.**-5) bamg_options['err']=options.getfieldvalue('err',np.array([[0.01]])) bamg_options['errg']=options.getfieldvalue('errg',0.1) bamg_options['field']=options.getfieldvalue('field',np.empty((0,1))) bamg_options['gradation']=options.getfieldvalue('gradation',1.5) bamg_options['Hessiantype']=options.getfieldvalue('Hessiantype',0) bamg_options['hmin']=options.getfieldvalue('hmin',10.**-100) bamg_options['hmax']=options.getfieldvalue('hmax',10.**100) bamg_options['hminVertices']=options.getfieldvalue('hminVertices',np.empty((0,1))) bamg_options['hmaxVertices']=options.getfieldvalue('hmaxVertices',np.empty((0,1))) bamg_options['hVertices']=options.getfieldvalue('hVertices',np.empty((0,1))) bamg_options['KeepVertices']=options.getfieldvalue('KeepVertices',1) bamg_options['MaxCornerAngle']=options.getfieldvalue('MaxCornerAngle',10.) bamg_options['maxnbv']=options.getfieldvalue('maxnbv',10**6) bamg_options['maxsubdiv']=options.getfieldvalue('maxsubdiv',10.) bamg_options['metric']=options.getfieldvalue('metric',np.empty((0,1))) bamg_options['Metrictype']=options.getfieldvalue('Metrictype',0) bamg_options['nbjacobi']=options.getfieldvalue('nbjacobi',1) bamg_options['nbsmooth']=options.getfieldvalue('nbsmooth',3) bamg_options['omega']=options.getfieldvalue('omega',1.8) bamg_options['power']=options.getfieldvalue('power',1.) bamg_options['splitcorners']=options.getfieldvalue('splitcorners',1) bamg_options['geometricalmetric']=options.getfieldvalue('geometricalmetric',0) bamg_options['random']=options.getfieldvalue('rand',True) bamg_options['verbose']=options.getfieldvalue('verbose',1) #}}} #call Bamg bamgmesh_out,bamggeom_out=BamgMesher(bamg_mesh.__dict__,bamg_geometry.__dict__,bamg_options) # plug results onto model md.private.bamg=OrderedDict() md.private.bamg['mesh']=bamgmesh(bamgmesh_out) md.private.bamg['geometry']=bamggeom(bamggeom_out) md.mesh = mesh2d() md.mesh.x=bamgmesh_out['Vertices'][:,0].copy() md.mesh.y=bamgmesh_out['Vertices'][:,1].copy() md.mesh.elements=bamgmesh_out['Triangles'][:,0:3].astype(int) md.mesh.edges=bamgmesh_out['IssmEdges'].astype(int) md.mesh.segments=bamgmesh_out['IssmSegments'][:,0:3].astype(int) md.mesh.segmentmarkers=bamgmesh_out['IssmSegments'][:,3].astype(int) #Fill in rest of fields: md.mesh.numberofelements=np.size(md.mesh.elements,axis=0) md.mesh.numberofvertices=np.size(md.mesh.x) md.mesh.numberofedges=np.size(md.mesh.edges,axis=0) md.mesh.vertexonboundary=np.zeros(md.mesh.numberofvertices,bool) md.mesh.vertexonboundary[md.mesh.segments[:,0:2]-1]=True md.mesh.elementconnectivity=md.private.bamg['mesh'].ElementConnectivity md.mesh.elementconnectivity[np.nonzero(np.isnan(md.mesh.elementconnectivity))]=0 md.mesh.elementconnectivity=md.mesh.elementconnectivity.astype(int) #Check for orphan if np.any(np.logical_not(np.in1d(np.arange(1,md.mesh.numberofvertices+1),md.mesh.elements.flat))): raise RuntimeError("Output mesh has orphans. Decrease MaxCornerAngle to prevent outside points (ex: 0.01)") return md
def checkfield(md,*args): """ CHECKFIELD - check field consistency Used to check model consistency., Requires: 'field' or 'fieldname' option. If 'fieldname' is provided, it will retrieve it from the model md. (md.(fieldname)) If 'field' is provided, it will assume the argument following 'field' is a numeric array. Available options: - NaN: 1 if check that there is no NaN - size: [lines cols], NaN for non checked dimensions - >: greater than provided value - >=: greater or equal to provided value - <: smallerthan provided value - <=: smaller or equal to provided value - < vec: smallerthan provided values on each vertex - timeseries: 1 if check time series consistency (size and time) - values: cell of strings or vector of acceptable values - numel: list of acceptable number of elements - cell: 1 if check that is cell - empty: 1 if check that non empty - message: overloaded error message Usage: md = checkfield(md,fieldname,options); """ #get options options=pairoptions(*args) #get field from model if options.exist('field'): field=options.getfieldvalue('field') fieldname=options.getfieldvalue('fieldname','no fieldname') else: fieldname=options.getfieldvalue('fieldname') exec("field=md.{}".format(fieldname)) if isinstance(field,(bool,int,long,float)): field=np.array([field]) #check empty if options.exist('empty'): if not field: md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' is empty" % fieldname)) #Check size if options.exist('size'): fieldsize=options.getfieldvalue('size') if len(fieldsize) == 1: if np.isnan(fieldsize[0]): pass elif np.ndim(field)==1: if not np.size(field)==fieldsize[0]: md = md.checkmessage(options.getfieldvalue('message',"field {} size should be {}".format(fieldname,fieldsize[0]))) else: try: exec("md.{}=field[:,0]".format(fieldname)) print('{} had a bad dimension, we fixed it but you should check it'.format(fieldname)) except IndexError: md = md.checkmessage(options.getfieldvalue('message',"field {} should have {} dimension".format(fieldname,len(fieldsize)))) elif len(fieldsize) == 2: if np.isnan(fieldsize[0]): if not np.size(field,1)==fieldsize[1]: md = md.checkmessage(options.getfieldvalue('message',"field '%s' should have %d columns" % (fieldname,fieldsize[1]))) elif np.isnan(fieldsize[1]): if not np.size(field,0)==fieldsize[0]: md = md.checkmessage(options.getfieldvalue('message',"field '%s' should have %d lines" % (fieldname,fieldsize[0]))) elif fieldsize[1]==1: if (not np.size(field,0)==fieldsize[0]): md = md.checkmessage(options.getfieldvalue('message',"field '%s' size should be %d x %d" % (fieldname,fieldsize[0],fieldsize[1]))) else: if (not np.size(field,0)==fieldsize[0]) or (not np.size(field,1)==fieldsize[1]): md = md.checkmessage(options.getfieldvalue('message',"field '%s' size should be %d x %d" % (fieldname,fieldsize[0],fieldsize[1]))) #Check numel if options.exist('numel'): fieldnumel=options.getfieldvalue('numel') if np.size(field) not in fieldnumel: if len(fieldnumel)==1: md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' size should be %d" % (fieldname,fieldnumel))) elif len(fieldnumel)==2: md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' size should be %d or %d" % (fieldname,fieldnumel[0],fieldnumel[1]))) else: md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' size should be %s" % (fieldname,fieldnumel))) #check NaN if options.getfieldvalue('NaN',0): if np.any(np.isnan(field)): md = md.checkmessage(options.getfieldvalue('message',\ "NaN values found in field '%s'" % fieldname)) #check Inf if options.getfieldvalue('Inf',0): if np.any(np.isinf(field)): md = md.checkmessage(options.getfieldvalue('message',\ "Inf values found in field '%s'" % fieldname)) #check cell if options.getfieldvalue('cell',0): if not isinstance(field,(tuple,list,dict)): md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' should be a cell" % fieldname)) #check values if options.exist('values'): fieldvalues=options.getfieldvalue('values') if False in m.ismember(field,fieldvalues): if len(fieldvalues)==1: md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' value should be '%s'" % (fieldname,fieldvalues[0]))) elif len(fieldvalues)==2: md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' values should be '%s' or '%s'" % (fieldname,fieldvalues[0],fieldvalues[1]))) else: md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' should have values in %s" % (fieldname,fieldvalues))) #check greater if options.exist('>='): lowerbound=options.getfieldvalue('>=') if np.any(field<lowerbound): md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' should have values above %d" % (fieldname,lowerbound))) if options.exist('>'): lowerbound=options.getfieldvalue('>') if np.any(field<=lowerbound): md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' should have values above %d" % (fieldname,lowerbound))) #check smaller if options.exist('<='): upperbound=options.getfieldvalue('<=') if np.any(field>upperbound): md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' should have values below %d" % (fieldname,upperbound))) if options.exist('<'): upperbound=options.getfieldvalue('<') if np.any(field>=upperbound): md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' should have values below %d" % (fieldname,upperbound))) #check file if options.getfieldvalue('file',0): if not os.path.exists(field): md = md.checkmessage("file provided in '%s': '%s' does not exist" % (fieldname,field)) #Check row of strings if options.exist('stringrow'): if not isinstance(field,list): md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' should be a list" %fieldname)) #Check forcings (size and times) if options.getfieldvalue('timeseries',0): if np.size(field,0)==md.mesh.numberofvertices: if np.ndim(field)>1 and not np.size(field,1)==1: md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' should have only one column as there are md.mesh.numberofvertices lines" % fieldname)) elif np.size(field,0)==md.mesh.numberofvertices+1 or np.size(field,0)==2: if not all(field[-1,:]==np.sort(field[-1,:])): md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' columns should be sorted chronologically" % fieldname)) if any(field[-1,0:-1]==field[-1,1:]): md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' columns must not contain duplicate timesteps" % fieldname)) else: md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' should have md.mesh.numberofvertices or md.mesh.numberofvertices+1 lines" % fieldname)) #Check single value forcings (size and times) if options.getfieldvalue('singletimeseries',0): if np.size(field,0)==2: if not all(field[-1,:]==np.sort(field[-1,:])): md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' columns should be sorted chronologically" % fieldname)) if any(field[-1,0:-1]==field[-1,1:]): md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' columns must not contain duplicate timesteps" % fieldname)) else: md = md.checkmessage(options.getfieldvalue('message',\ "field '%s' should have 2 lines" % fieldname)) return md
def FlagElements(md, region): """ FLAGELEMENTS - flag the elements in an region The region can be given with an exp file, a list of elements or vertices Usage: flag=FlagElements(md,region); Example: flag=FlagElements(md,'all'); flag=FlagElements(md,''); flag=FlagElements(md,'Domain.exp'); flag=FlagElements(md,'~Domain.exp'); """ if isinstance(region, (str, unicode)): if not region: flag = np.zeros(md.mesh.numberofelements, bool) invert = 0 elif m.strcmpi(region, 'all'): flag = np.ones(md.mesh.numberofelements, bool) invert = 0 else: #make sure that we actually don't want the elements outside the domain outline! if m.strcmpi(region[0], '~'): region = region[1:] invert = 1 else: invert = 0 #does the region domain outline exist or do we have to look for xlim,ylim in basinzoom? if not os.path.exists(region): if len(region) > 3 and not m.strcmp(region[-4:], '.exp'): raise IOError("Error: File 'region' not found!" % region) raise RuntimeError( "FlagElements.py calling basinzoom.py is not complete.") xlim, ylim = basinzoom('basin', region) flag_nodes = p.logical_and_n(md.mesh.x < xlim[1], md.mesh.x > xlim[0], md.mesh.y < ylim[1], md.mesh.y > ylim[0]) flag = np.prod(flag_nodes[md.mesh.elements], axis=1).astype(bool) else: #ok, flag elements flag = ContourToMesh(md.mesh.elements[:, 0:3].copy(), md.mesh.x, md.mesh.y, region, 'element', 1) flag = flag.astype(bool) if invert: flag = np.logical_not(flag) elif isinstance(region, np.ndarray) or isinstance(region, bool): if np.size(region, 0) == md.mesh.numberofelements: flag = region elif np.size(region, 0) == md.mesh.numberofvertices: flag = (np.sum(region[md.mesh.elements - 1] > 0, axis=1) == np.size(md.mesh.elements, 1)) else: raise TypeError( "Flaglist for region must be of same size as number of elements in model." ) else: raise TypeError("Invalid region option") return flag
def processgeometry(geom,tol,outline): # {{{ raise RuntimeError("bamg.py/processgeometry is not complete.") #Deal with edges print "Checking Edge crossing..." i=0 while (i<np.size(geom.Edges,axis=0)): #edge counter i+=1 #Get coordinates x1=geom.Vertices[geom.Edges[i,0],0] y1=geom.Vertices[geom.Edges[i,0],1] x2=geom.Vertices[geom.Edges[i,1],0] y2=geom.Vertices[geom.Edges[i,1],1] color1=geom.Edges[i,2] j=i #test edges located AFTER i only while (j<np.size(geom.Edges,axis=0)): #edge counter j+=1 #Skip if the two edges already have a vertex in common if any(m.ismember(geom.Edges[i,0:2],geom.Edges[j,0:2])): continue #Get coordinates x3=geom.Vertices[geom.Edges[j,0],0] y3=geom.Vertices[geom.Edges[j,0],1] x4=geom.Vertices[geom.Edges[j,1],0] y4=geom.Vertices[geom.Edges[j,1],1] color2=geom.Edges[j,2] #Check if the two edges are crossing one another if SegIntersect(np.array([[x1,y1],[x2,y2]]),np.array([[x3,y3],[x4,y4]])): #Get coordinate of intersection point (http://mathworld.wolfram.com/Line-LineIntersection.html) x=np.linalg.det(np.array([np.linalg.det(np.array([[x1,y1],[x2,y2]])),x1-x2],[np.linalg.det(np.array([[x3,y3],[x4,y4]])),x3-x4])/np.linalg.det(np.array([[x1-x2,y1-y2],[x3-x4,y3-y4]]))) y=np.linalg.det(np.array([np.linalg.det(np.array([[x1,y1],[x2,y2]])),y1-y2],[np.linalg.det(np.array([[x3,y3],[x4,y4]])),y3-y4])/np.linalg.det(np.array([[x1-x2,y1-y2],[x3-x4,y3-y4]]))) #Add vertex to the list of vertices geom.Vertices=np.vstack((geom.Vertices,[x,y,min(color1,color2)])) id=np.size(geom.Vertices,axis=0) #Update edges i and j edgei=geom.Edges[i,:].copy() edgej=geom.Edges[j,:].copy() geom.Edges[i,:] =[edgei(0),id ,edgei(2)] geom.Edges=np.vstack((geom.Edges,[id ,edgei(1),edgei(2)])) geom.Edges[j,:] =[edgej(0),id ,edgej(2)] geom.Edges=np.vstack((geom.Edges,[id ,edgej(1),edgej(2)])) #update current edge second tip x2=x y2=y #Check point outside print "Checking for points outside the domain..." i=0 num=0 while (i<np.size(geom.Vertices,axis=0)): #vertex counter i+=1 #Get coordinates x=geom.Vertices[i,0] y=geom.Vertices[i,1] color=geom.Vertices[i,2] #Check that the point is inside the domain if color!=1 and not ContourToNodes(x,y,outline[0],1): #Remove points from list of Vertices num+=1 geom.Vertices[i,:]=[] #update edges posedges=np.nonzero(geom.Edges==i) geom.Edges[posedges[0],:]=[] posedges=np.nonzero(geom.Edges>i) geom.Edges[posedges]=geom.Edges[posedges]-1 #update counter i-=1 if num: print "WARNING: %d points outside the domain outline have been removed" % num """ %Check point spacing if ~isnan(tol), disp('Checking point spacing...'); i=0; while (i<size(geom.Vertices,1)), %vertex counter i=i+1; %Get coordinates x1=geom.Vertices(i,1); y1=geom.Vertices(i,2); j=i; %test edges located AFTER i only while (j<size(geom.Vertices,1)), %vertex counter j=j+1; %Get coordinates x2=geom.Vertices(j,1); y2=geom.Vertices(j,2); %Check whether the two vertices are too close if ((x2-x1)**2+(y2-y1)**2<tol**2) %Remove points from list of Vertices geom.Vertices(j,:)=[]; %update edges posedges=find(m.ismember(geom.Edges,j)); geom.Edges(posedges)=i; posedges=find(geom.Edges>j); geom.Edges(posedges)=geom.Edges(posedges)-1; %update counter j=j-1; end end end end %remove empty edges geom.Edges(find(geom.Edges(:,1)==geom.Edges(:,2)),:)=[]; """ return geom
def contourenvelope(md, *args): """ CONTOURENVELOPE - build a set of segments enveloping a contour .exp Usage: segments=contourenvelope(md,varargin) Example: segments=contourenvelope(md,'Stream.exp'); segments=contourenvelope(md); """ #some checks if len(args) > 1: raise RuntimeError("contourenvelope error message: bad usage") if len(args) == 1: flags = args[0] if isinstance(flags, (str, unicode)): file = flags if not os.path.exists(file): raise IOError( "contourenvelope error message: file '%s' not found" % file) isfile = 1 elif isinstance(flags, (bool, int, long, float)): #do nothing for now isfile = 0 else: raise TypeError( "contourenvelope error message: second argument should be a file or an elements flag" ) #Now, build the connectivity tables for this mesh. #Computing connectivity if np.size(md.mesh.vertexconnectivity, axis=0) != md.mesh.numberofvertices and np.size( md.mesh.vertexconnectivity, axis=0) != md.mesh.numberofvertices2d: md.mesh.vertexconnectivity = NodeConnectivity( md.mesh.elements, md.mesh.numberofvertices)[0] if np.size(md.mesh.elementconnectivity, axis=0) != md.mesh.numberofelements and np.size( md.mesh.elementconnectivity, axis=0) != md.mesh.numberofelements2d: md.mesh.elementconnectivity = ElementConnectivity( md.mesh.elements, md.mesh.vertexconnectivity)[0] #get nodes inside profile elementconnectivity = copy.deepcopy(md.mesh.elementconnectivity) if md.mesh.dimension() == 2: elements = copy.deepcopy(md.mesh.elements) x = copy.deepcopy(md.mesh.x) y = copy.deepcopy(md.mesh.y) numberofvertices = copy.deepcopy(md.mesh.numberofvertices) numberofelements = copy.deepcopy(md.mesh.numberofelements) else: elements = copy.deepcopy(md.mesh.elements2d) x = copy.deepcopy(md.mesh.x2d) y = copy.deepcopy(md.mesh.y2d) numberofvertices = copy.deepcopy(md.mesh.numberofvertices2d) numberofelements = copy.deepcopy(md.mesh.numberofelements2d) if len(args) == 1: if isfile: #get flag list of elements and nodes inside the contour nodein = ContourToMesh(elements, x, y, file, 'node', 1) elemin = (np.sum(nodein(elements), axis=1) == np.size(elements, axis=1)) #modify element connectivity elemout = np.nonzero(np.logical_not(elemin))[0] elementconnectivity[elemout, :] = 0 elementconnectivity[np.nonzero( m.ismember(elementconnectivity, elemout + 1))] = 0 else: #get flag list of elements and nodes inside the contour nodein = np.zeros(numberofvertices) elemin = np.zeros(numberofelements) pos = np.nonzero(flags) elemin[pos] = 1 nodein[elements[pos, :] - 1] = 1 #modify element connectivity elemout = np.nonzero(np.logical_not(elemin))[0] elementconnectivity[elemout, :] = 0 elementconnectivity[np.nonzero( m.ismember(elementconnectivity, elemout + 1))] = 0 #Find element on boundary #First: find elements on the boundary of the domain flag = copy.deepcopy(elementconnectivity) if len(args) == 1: flag[np.nonzero(flag)] = elemin[flag[np.nonzero(flag)]] elementonboundary = np.logical_and( np.prod(flag, axis=1) == 0, np.sum(flag, axis=1) > 0) #Find segments on boundary pos = np.nonzero(elementonboundary)[0] num_segments = np.size(pos) segments = np.zeros((num_segments * 3, 3), int) count = 0 for el1 in pos: els2 = elementconnectivity[ el1, np.nonzero(elementconnectivity[el1, :])[0]] - 1 if np.size(els2) > 1: flag = np.intersect1d( np.intersect1d(elements[els2[0], :], elements[els2[1], :]), elements[el1, :]) nods1 = elements[el1, :] nods1 = np.delete(nods1, np.nonzero(nods1 == flag)) segments[count, :] = [nods1[0], nods1[1], el1 + 1] ord1 = np.nonzero(nods1[0] == elements[el1, :])[0][0] ord2 = np.nonzero(nods1[1] == elements[el1, :])[0][0] #swap segment nodes if necessary if ((ord1 == 0 and ord2 == 1) or (ord1 == 1 and ord2 == 2) or (ord1 == 2 and ord2 == 0)): temp = segments[count, 0] segments[count, 0] = segments[count, 1] segments[count, 1] = temp segments[count, 0:2] = np.flipud(segments[count, 0:2]) count += 1 else: nods1 = elements[el1, :] flag = np.setdiff1d(nods1, elements[els2, :]) for j in xrange(0, 3): nods = np.delete(nods1, j) if np.any(m.ismember(flag, nods)): segments[count, :] = [nods[0], nods[1], el1 + 1] ord1 = np.nonzero(nods[0] == elements[el1, :])[0][0] ord2 = np.nonzero(nods[1] == elements[el1, :])[0][0] if ((ord1 == 0 and ord2 == 1) or (ord1 == 1 and ord2 == 2) or (ord1 == 2 and ord2 == 0)): temp = segments[count, 0] segments[count, 0] = segments[count, 1] segments[count, 1] = temp segments[count, 0:2] = np.flipud(segments[count, 0:2]) count += 1 segments = segments[0:count, :] return segments
def WriteData(fid, prefix, *args): """ WRITEDATA - write model field in binary file Usage: WriteData(fid,varargin) """ #process options options = pairoptions(*args) #Get data properties if options.exist('object'): #This is an object field, construct enum and data obj = options.getfieldvalue('object') fieldname = options.getfieldvalue('fieldname') classname = options.getfieldvalue( 'class', str(type(obj)).rsplit('.')[-1].split("'")[0]) name = options.getfieldvalue('name', prefix + '.' + fieldname) if options.exist('data'): data = options.getfieldvalue('data') else: data = getattr(obj, fieldname) else: #No processing required data = options.getfieldvalue('data') name = options.getfieldvalue('name') format = options.getfieldvalue('format') mattype = options.getfieldvalue('mattype', 0) #only required for matrices timeserieslength = options.getfieldvalue('timeserieslength', -1) #Process sparse matrices # if issparse(data), # data=full(data); # end #Scale data if necesarry if options.exist('scale'): scale = options.getfieldvalue('scale') if np.size(data) > 1: if np.size(data, 0) == timeserieslength: data = np.array(data) data[0:-1, :] = scale * data[0:-1, :] else: data = scale * data else: data = scale * data if np.size(data) > 1: if np.size(data, 0) == timeserieslength: yts = options.getfieldvalue('yts') data[-1, :] = yts * data[-1, :] #Step 1: write the enum to identify this record uniquely fid.write(struct.pack('i', len(name))) fid.write(struct.pack('%ds' % len(name), name)) #Step 2: write the data itself. if m.strcmpi(format, 'Boolean'): # {{{ # if len(data) !=1: # raise ValueError('field %s cannot be marshalled as it has more than one element!' % name[0]) #first write length of record fid.write(struct.pack('i', 4 + 4)) #1 bool (disguised as an int)+code #write data code: fid.write(struct.pack('i', FormatToCode(format))) #now write integer fid.write(struct.pack( 'i', int(data))) #send an int, not easy to send a bool # }}} elif m.strcmpi(format, 'Integer'): # {{{ # if len(data) !=1: # raise ValueError('field %s cannot be marshalled as it has more than one element!' % name[0]) #first write length of record fid.write(struct.pack('i', 4 + 4)) #1 integer + code #write data code: fid.write(struct.pack('i', FormatToCode(format))) #now write integer fid.write(struct.pack('i', data)) # }}} elif m.strcmpi(format, 'Double'): # {{{ # if len(data) !=1: # raise ValueError('field %s cannot be marshalled as it has more than one element!' % name[0]) #first write length of record fid.write(struct.pack('i', 8 + 4)) #1 double+code #write data code: fid.write(struct.pack('i', FormatToCode(format))) #now write double fid.write(struct.pack('d', data)) # }}} elif m.strcmpi(format, 'String'): # {{{ #first write length of record fid.write(struct.pack('i', len(data) + 4 + 4)) #string + string size + code #write data code: fid.write(struct.pack('i', FormatToCode(format))) #now write string fid.write(struct.pack('i', len(data))) fid.write(struct.pack('%ds' % len(data), data)) # }}} elif m.strcmpi(format, 'BooleanMat'): # {{{ if isinstance(data, bool): data = np.array([data]) elif isinstance(data, (list, tuple)): data = np.array(data).reshape(-1, ) if np.ndim(data) == 1: if np.size(data): data = data.reshape(np.size(data), ) else: data = data.reshape(0, 0) #Get size s = data.shape #if matrix = NaN, then do not write anything if np.ndim(data) == 2 and np.product(s) == 1 and np.all( np.isnan(data)): s = (0, 0) #first write length of record fid.write(struct.pack( 'i', 4 + 4 + 8 * np.product(s) + 4 + 4)) #2 integers (32 bits) + the double matrix + code + matrix type #write data code and matrix type: fid.write(struct.pack('i', FormatToCode(format))) fid.write(struct.pack('i', mattype)) #now write matrix if np.ndim(data) == 1: fid.write(struct.pack('i', s[0])) fid.write(struct.pack('i', 1)) for i in xrange(s[0]): fid.write(struct.pack('d', float( data[i]))) #get to the "c" convention, hence the transpose else: fid.write(struct.pack('i', s[0])) fid.write(struct.pack('i', s[1])) for i in xrange(s[0]): for j in xrange(s[1]): fid.write(struct.pack('d', float( data[i] [j]))) #get to the "c" convention, hence the transpose # }}} elif m.strcmpi(format, 'IntMat'): # {{{ if isinstance(data, (int, long)): data = np.array([data]) elif isinstance(data, (list, tuple)): data = np.array(data).reshape(-1, ) if np.ndim(data) == 1: if np.size(data): data = data.reshape(np.size(data), ) else: data = data.reshape(0, 0) #Get size s = data.shape #if matrix = NaN, then do not write anything if np.ndim(data) == 2 and np.product(s) == 1 and np.all( np.isnan(data)): s = (0, 0) #first write length of record fid.write(struct.pack( 'i', 4 + 4 + 8 * np.product(s) + 4 + 4)) #2 integers (32 bits) + the double matrix + code + matrix type #write data code and matrix type: fid.write(struct.pack('i', FormatToCode(format))) fid.write(struct.pack('i', mattype)) #now write matrix if np.ndim(data) == 1: fid.write(struct.pack('i', s[0])) fid.write(struct.pack('i', 1)) for i in xrange(s[0]): fid.write(struct.pack('d', float( data[i]))) #get to the "c" convention, hence the transpose else: fid.write(struct.pack('i', s[0])) fid.write(struct.pack('i', s[1])) for i in xrange(s[0]): for j in xrange(s[1]): fid.write(struct.pack('d', float( data[i] [j]))) #get to the "c" convention, hence the transpose # }}} elif m.strcmpi(format, 'DoubleMat'): # {{{ if isinstance(data, (bool, int, long, float)): data = np.array([data]) elif isinstance(data, (list, tuple)): data = np.array(data).reshape(-1, ) if np.ndim(data) == 1: if np.size(data): data = data.reshape(np.size(data), ) else: data = data.reshape(0, 0) #Get size s = data.shape #if matrix = NaN, then do not write anything if np.ndim(data) == 1 and np.product(s) == 1 and np.all( np.isnan(data)): s = (0, 0) #first write length of record recordlength = 4 + 4 + 8 * np.product(s) + 4 + 4 #2 integers (32 bits) + the double matrix + code + matrix type if recordlength > 4**31: raise ValueError( 'field %s cannot be marshalled because it is larger than 4^31 bytes!' % enum) fid.write( struct.pack('i', recordlength) ) #2 integers (32 bits) + the double matrix + code + matrix type #write data code and matrix type: fid.write(struct.pack('i', FormatToCode(format))) fid.write(struct.pack('i', mattype)) #now write matrix if np.ndim(data) == 1: fid.write(struct.pack('i', s[0])) fid.write(struct.pack('i', 1)) for i in xrange(s[0]): fid.write(struct.pack('d', float( data[i]))) #get to the "c" convention, hence the transpose else: fid.write(struct.pack('i', s[0])) fid.write(struct.pack('i', s[1])) for i in xrange(s[0]): for j in xrange(s[1]): fid.write(struct.pack('d', float( data[i] [j]))) #get to the "c" convention, hence the transpose # }}} elif m.strcmpi(format, 'CompressedMat'): # {{{ if isinstance(data, (bool, int, long, float)): data = np.array([data]) elif isinstance(data, (list, tuple)): data = np.array(data).reshape(-1, ) if np.ndim(data) == 1: if np.size(data): data = data.reshape(np.size(data), ) else: data = data.reshape(0, 0) #Get size s = data.shape if np.ndim(data) == 1: n2 = 1 else: n2 = s[1] #if matrix = NaN, then do not write anything if np.ndim(data) == 1 and np.product(s) == 1 and np.all( np.isnan(data)): s = (0, 0) n2 = 0 #first write length of record recordlength = 4 + 4 + 8 + 8 + 1 * ( s[0] - 1 ) * n2 + 8 * n2 + 4 + 4 #2 integers (32 bits) + the matrix + code + matrix type if recordlength > 4**31: raise ValueError( 'field %s cannot be marshalled because it is larger than 4^31 bytes!' % enum) fid.write(struct.pack('i', recordlength) ) #2 integers (32 bits) + the matrix + code + matrix type #write data code and matrix type: fid.write(struct.pack('i', FormatToCode(format))) fid.write(struct.pack('i', mattype)) #Write offset and range A = data[0:s[0] - 1] offsetA = A.min() rangeA = A.max() - offsetA if rangeA == 0: A = A * 0 else: A = (A - offsetA) / rangeA * 255. #now write matrix if np.ndim(data) == 1: fid.write(struct.pack('i', s[0])) fid.write(struct.pack('i', 1)) fid.write(struct.pack('d', float(offsetA))) fid.write(struct.pack('d', float(rangeA))) for i in xrange(s[0] - 1): fid.write(struct.pack('B', int(A[i]))) fid.write(struct.pack('d', float( data[s[0] - 1]))) #get to the "c" convention, hence the transpose elif np.product(s) > 0: fid.write(struct.pack('i', s[0])) fid.write(struct.pack('i', s[1])) fid.write(struct.pack('d', float(offsetA))) fid.write(struct.pack('d', float(rangeA))) for i in xrange(s[0] - 1): for j in xrange(s[1]): fid.write(struct.pack('B', int( A[i] [j]))) #get to the "c" convention, hence the transpose for j in xrange(s[1]): fid.write(struct.pack('d', float(data[s[0] - 1][j]))) # }}} elif m.strcmpi(format, 'MatArray'): # {{{ #first get length of record recordlength = 4 + 4 #number of records + code for matrix in data: if isinstance(matrix, (bool, int, long, float)): matrix = np.array([matrix]) elif isinstance(matrix, (list, tuple)): matrix = np.array(matrix).reshape(-1, ) if np.ndim(matrix) == 1: if np.size(matrix): matrix = matrix.reshape(np.size(matrix), ) else: matrix = matrix.reshape(0, 0) s = matrix.shape recordlength += 4 * 2 + np.product( s) * 8 #row and col of matrix + matrix of doubles #write length of record fid.write(struct.pack('i', recordlength)) #write data code: fid.write(struct.pack('i', FormatToCode(format))) #write data, first number of records fid.write(struct.pack('i', len(data))) #write each matrix: for matrix in data: if isinstance(matrix, (bool, int, long, float)): matrix = np.array([matrix]) elif isinstance(matrix, (list, tuple)): matrix = np.array(matrix).reshape(-1, ) if np.ndim(matrix) == 1: matrix = matrix.reshape(np.size(matrix), ) s = matrix.shape if np.ndim(data) == 1: fid.write(struct.pack('i', s[0])) fid.write(struct.pack('i', 1)) for i in xrange(s[0]): fid.write( struct.pack('d', float(matrix[i])) ) #get to the "c" convention, hence the transpose else: fid.write(struct.pack('i', s[0])) fid.write(struct.pack('i', s[1])) for i in xrange(s[0]): for j in xrange(s[1]): fid.write(struct.pack('d', float(matrix[i][j]))) # }}} elif m.strcmpi(format, 'StringArray'): # {{{ #first get length of record recordlength = 4 + 4 #for length of array + code for string in data: recordlength += 4 + len(string) #for each string #write length of record fid.write(struct.pack('i', recordlength)) #write data code: fid.write(struct.pack('i', FormatToCode(format))) #now write length of string array fid.write(struct.pack('i', len(data))) #now write the strings for string in data: fid.write(struct.pack('i', len(string))) fid.write(struct.pack('%ds' % len(string), string)) # }}} else: # {{{ raise TypeError( 'WriteData error message: data type: %d not supported yet! (%s)' % (format, enum))
def extract(md, area): # {{{ """ extract - extract a model according to an Argus contour or flag list This routine extracts a submodel from a bigger model with respect to a given contour md must be followed by the corresponding exp file or flags list It can either be a domain file (argus type, .exp extension), or an array of element flags. If user wants every element outside the domain to be extract2d, add '~' to the name of the domain file (ex: '~HO.exp') an empty string '' will be considered as an empty domain a string 'all' will be considered as the entire domain Usage: md2=extract(md,area) Examples: md2=extract(md,'Domain.exp') See also: EXTRUDE, COLLAPSE """ #copy model md1 = copy.deepcopy(md) #get elements that are inside area flag_elem = FlagElements(md1, area) if not np.any(flag_elem): raise RuntimeError("extracted model is empty") #kick out all elements with 3 dirichlets spc_elem = np.nonzero(np.logical_not(flag_elem))[0] spc_node = np.unique(md1.mesh.elements[spc_elem, :]) - 1 flag = np.ones(md1.mesh.numberofvertices) flag[spc_node] = 0 pos = np.nonzero( np.logical_not(np.sum(flag[md1.mesh.elements - 1], axis=1)))[0] flag_elem[pos] = 0 #extracted elements and nodes lists pos_elem = np.nonzero(flag_elem)[0] pos_node = np.unique(md1.mesh.elements[pos_elem, :]) - 1 #keep track of some fields numberofvertices1 = md1.mesh.numberofvertices numberofelements1 = md1.mesh.numberofelements numberofvertices2 = np.size(pos_node) numberofelements2 = np.size(pos_elem) flag_node = np.zeros(numberofvertices1) flag_node[pos_node] = 1 #Create Pelem and Pnode (transform old nodes in new nodes and same thing for the elements) Pelem = np.zeros(numberofelements1, int) Pelem[pos_elem] = np.arange(1, numberofelements2 + 1) Pnode = np.zeros(numberofvertices1, int) Pnode[pos_node] = np.arange(1, numberofvertices2 + 1) #renumber the elements (some node won't exist anymore) elements_1 = copy.deepcopy(md1.mesh.elements) elements_2 = elements_1[pos_elem, :] elements_2[:, 0] = Pnode[elements_2[:, 0] - 1] elements_2[:, 1] = Pnode[elements_2[:, 1] - 1] elements_2[:, 2] = Pnode[elements_2[:, 2] - 1] if md1.mesh.__class__.__name__ == 'mesh3dprisms': elements_2[:, 3] = Pnode[elements_2[:, 3] - 1] elements_2[:, 4] = Pnode[elements_2[:, 4] - 1] elements_2[:, 5] = Pnode[elements_2[:, 5] - 1] #OK, now create the new model! #take every field from model md2 = copy.deepcopy(md1) #automatically modify fields #loop over model fields model_fields = vars(md1) for fieldi in model_fields: #get field field = getattr(md1, fieldi) fieldsize = np.shape(field) if hasattr(field, '__dict__') and not m.ismember( fieldi, ['results'])[0]: #recursive call object_fields = vars(field) for fieldj in object_fields: #get field field = getattr(getattr(md1, fieldi), fieldj) fieldsize = np.shape(field) if len(fieldsize): #size = number of nodes * n if fieldsize[0] == numberofvertices1: setattr(getattr(md2, fieldi), fieldj, field[pos_node]) elif fieldsize[0] == numberofvertices1 + 1: setattr(getattr(md2, fieldi), fieldj, np.vstack((field[pos_node], field[-1, :]))) #size = number of elements * n elif fieldsize[0] == numberofelements1: setattr(getattr(md2, fieldi), fieldj, field[pos_elem]) else: if len(fieldsize): #size = number of nodes * n if fieldsize[0] == numberofvertices1: setattr(md2, fieldi, field[pos_node]) elif fieldsize[0] == numberofvertices1 + 1: setattr(md2, fieldi, np.hstack((field[pos_node], field[-1, :]))) #size = number of elements * n elif fieldsize[0] == numberofelements1: setattr(md2, fieldi, field[pos_elem]) #modify some specific fields #Mesh md2.mesh.numberofelements = numberofelements2 md2.mesh.numberofvertices = numberofvertices2 md2.mesh.elements = elements_2 #mesh.uppervertex mesh.lowervertex if md1.mesh.__class__.__name__ == 'mesh3dprisms': md2.mesh.uppervertex = md1.mesh.uppervertex[pos_node] pos = np.where(~np.isnan(md2.mesh.uppervertex))[0] md2.mesh.uppervertex[pos] = Pnode[ md2.mesh.uppervertex[pos].astype(int) - 1] md2.mesh.lowervertex = md1.mesh.lowervertex[pos_node] pos = np.where(~np.isnan(md2.mesh.lowervertex))[0] md2.mesh.lowervertex[pos] = Pnode[ md2.mesh.lowervertex[pos].astype(int) - 1] md2.mesh.upperelements = md1.mesh.upperelements[pos_elem] pos = np.where(~np.isnan(md2.mesh.upperelements))[0] md2.mesh.upperelements[pos] = Pelem[ md2.mesh.upperelements[pos].astype(int) - 1] md2.mesh.lowerelements = md1.mesh.lowerelements[pos_elem] pos = np.where(~np.isnan(md2.mesh.lowerelements))[0] md2.mesh.lowerelements[pos] = Pelem[ md2.mesh.lowerelements[pos].astype(int) - 1] #Initial 2d mesh if md1.mesh.__class__.__name__ == 'mesh3dprisms': flag_elem_2d = flag_elem[np.arange(0, md1.mesh.numberofelements2d)] pos_elem_2d = np.nonzero(flag_elem_2d)[0] flag_node_2d = flag_node[np.arange(0, md1.mesh.numberofvertices2d)] pos_node_2d = np.nonzero(flag_node_2d)[0] md2.mesh.numberofelements2d = np.size(pos_elem_2d) md2.mesh.numberofvertices2d = np.size(pos_node_2d) md2.mesh.elements2d = md1.mesh.elements2d[pos_elem_2d, :] md2.mesh.elements2d[:, 0] = Pnode[md2.mesh.elements2d[:, 0] - 1] md2.mesh.elements2d[:, 1] = Pnode[md2.mesh.elements2d[:, 1] - 1] md2.mesh.elements2d[:, 2] = Pnode[md2.mesh.elements2d[:, 2] - 1] md2.mesh.x2d = md1.mesh.x[pos_node_2d] md2.mesh.y2d = md1.mesh.y[pos_node_2d] #Edges if m.strcmp(md.mesh.domaintype(), '2Dhorizontal'): 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... #renumber first two columns pos = np.nonzero(md2.mesh.edges[:, 3] != -1)[0] md2.mesh.edges[:, 0] = Pnode[md2.mesh.edges[:, 0] - 1] md2.mesh.edges[:, 1] = Pnode[md2.mesh.edges[:, 1] - 1] md2.mesh.edges[:, 2] = Pelem[md2.mesh.edges[:, 2] - 1] md2.mesh.edges[pos, 3] = Pelem[md2.mesh.edges[pos, 3] - 1] #remove edges when the 2 vertices are not in the domain. md2.mesh.edges = md2.mesh.edges[np.nonzero( np.logical_and(md2.mesh.edges[:, 0], md2.mesh.edges[:, 1]) )[0], :] #Replace all zeros by -1 in the last two columns pos = np.nonzero(md2.mesh.edges[:, 2] == 0)[0] md2.mesh.edges[pos, 2] = -1 pos = np.nonzero(md2.mesh.edges[:, 3] == 0)[0] md2.mesh.edges[pos, 3] = -1 #Invert -1 on the third column with last column (Also invert first two columns!!) pos = np.nonzero(md2.mesh.edges[:, 2] == -1)[0] md2.mesh.edges[pos, 2] = md2.mesh.edges[pos, 3] md2.mesh.edges[pos, 3] = -1 values = md2.mesh.edges[pos, 1] md2.mesh.edges[pos, 1] = md2.mesh.edges[pos, 0] md2.mesh.edges[pos, 0] = values #Finally remove edges that do not belong to any element pos = np.nonzero( np.logical_and(md2.mesh.edges[:, 1] == -1, md2.mesh.edges[:, 2] == -1))[0] md2.mesh.edges = np.delete(md2.mesh.edges, pos, axis=0) #Penalties if np.any(np.logical_not(np.isnan(md2.stressbalance.vertex_pairing))): for i in xrange(np.size(md1.stressbalance.vertex_pairing, axis=0)): md2.stressbalance.vertex_pairing[i, :] = Pnode[ md1.stressbalance.vertex_pairing[i, :]] md2.stressbalance.vertex_pairing = md2.stressbalance.vertex_pairing[ np.nonzero(md2.stressbalance.vertex_pairing[:, 0])[0], :] if np.any(np.logical_not(np.isnan(md2.masstransport.vertex_pairing))): for i in xrange(np.size(md1.masstransport.vertex_pairing, axis=0)): md2.masstransport.vertex_pairing[i, :] = Pnode[ md1.masstransport.vertex_pairing[i, :]] md2.masstransport.vertex_pairing = md2.masstransport.vertex_pairing[ np.nonzero(md2.masstransport.vertex_pairing[:, 0])[0], :] #recreate segments if md1.mesh.__class__.__name__ == 'mesh2d': md2.mesh.vertexconnectivity = NodeConnectivity( md2.mesh.elements, md2.mesh.numberofvertices)[0] md2.mesh.elementconnectivity = ElementConnectivity( md2.mesh.elements, md2.mesh.vertexconnectivity)[0] md2.mesh.segments = contourenvelope(md2) md2.mesh.vertexonboundary = np.zeros(numberofvertices2, bool) md2.mesh.vertexonboundary[md2.mesh.segments[:, 0:2] - 1] = True else: #First do the connectivity for the contourenvelope in 2d md2.mesh.vertexconnectivity = NodeConnectivity( md2.mesh.elements2d, md2.mesh.numberofvertices2d)[0] md2.mesh.elementconnectivity = ElementConnectivity( md2.mesh.elements2d, md2.mesh.vertexconnectivity)[0] segments = contourenvelope(md2) md2.mesh.vertexonboundary = np.zeros( numberofvertices2 / md2.mesh.numberoflayers, bool) md2.mesh.vertexonboundary[segments[:, 0:2] - 1] = True md2.mesh.vertexonboundary = np.tile(md2.mesh.vertexonboundary, md2.mesh.numberoflayers) #Then do it for 3d as usual md2.mesh.vertexconnectivity = NodeConnectivity( md2.mesh.elements, md2.mesh.numberofvertices)[0] md2.mesh.elementconnectivity = ElementConnectivity( md2.mesh.elements, md2.mesh.vertexconnectivity)[0] #Boundary conditions: Dirichlets on new boundary #Catch the elements that have not been extracted orphans_elem = np.nonzero(np.logical_not(flag_elem))[0] orphans_node = np.unique(md1.mesh.elements[orphans_elem, :]) - 1 #Figure out which node are on the boundary between md2 and md1 nodestoflag1 = np.intersect1d(orphans_node, pos_node) nodestoflag2 = Pnode[nodestoflag1].astype(int) - 1 if np.size(md1.stressbalance.spcvx) > 1 and np.size( md1.stressbalance.spcvy) > 2 and np.size( md1.stressbalance.spcvz) > 2: if np.size(md1.inversion.vx_obs) > 1 and np.size( md1.inversion.vy_obs) > 1: md2.stressbalance.spcvx[nodestoflag2] = md2.inversion.vx_obs[ nodestoflag2] md2.stressbalance.spcvy[nodestoflag2] = md2.inversion.vy_obs[ nodestoflag2] else: md2.stressbalance.spcvx[nodestoflag2] = np.nan md2.stressbalance.spcvy[nodestoflag2] = np.nan print "\n!! extract warning: spc values should be checked !!\n\n" #put 0 for vz md2.stressbalance.spcvz[nodestoflag2] = 0 if np.any(np.logical_not(np.isnan(md1.thermal.spctemperature))): md2.thermal.spctemperature[nodestoflag2] = 1 #Results fields if md1.results: md2.results = results() for solutionfield, field in md1.results.__dict__.iteritems(): if isinstance(field, list): setattr(md2.results, solutionfield, []) #get time step for i, fieldi in enumerate(field): if isinstance(fieldi, results) and fieldi: getattr(md2.results, solutionfield).append(results()) fieldr = getattr(md2.results, solutionfield)[i] #get subfields for solutionsubfield, subfield in fieldi.__dict__.iteritems( ): if np.size(subfield) == numberofvertices1: setattr(fieldr, solutionsubfield, subfield[pos_node]) elif np.size(subfield) == numberofelements1: setattr(fieldr, solutionsubfield, subfield[pos_elem]) else: setattr(fieldr, solutionsubfield, subfield) else: getattr(md2.results, solutionfield).append(None) elif isinstance(field, results): setattr(md2.results, solutionfield, results()) if isinstance(field, results) and field: fieldr = getattr(md2.results, solutionfield) #get subfields for solutionsubfield, subfield in field.__dict__.iteritems( ): if np.size(subfield) == numberofvertices1: setattr(fieldr, solutionsubfield, subfield[pos_node]) elif np.size(subfield) == numberofelements1: setattr(fieldr, solutionsubfield, subfield[pos_elem]) else: setattr(fieldr, solutionsubfield, subfield) #Keep track of pos_node and pos_elem md2.mesh.extractedvertices = pos_node + 1 md2.mesh.extractedelements = pos_elem + 1 return md2