import numpy import sys import copy from fielddisplay import fielddisplay from EnumDefinitions import * from checkfield import * from WriteData import * class diagnostic(object): """ DIAGNOSTIC class definition Usage: diagnostic=diagnostic(); """ def __init__(self): # {{{ self.spcvx = float('NaN') self.spcvy = float('NaN') self.spcvz = float('NaN') self.restol = 0 self.reltol = 0 self.abstol = 0 self.isnewton = 0 self.stokesreconditioning = 0 self.viscosity_overshoot = 0 self.icefront = float('NaN') self.maxiter = 0 self.shelf_dampening = 0 self.vertex_pairing = float('NaN') self.penalty_factor = float('NaN') self.rift_penalty_lock = float('NaN') self.rift_penalty_threshold = 0 self.referential = float('NaN') self.loadingforce = float('NaN') self.requested_outputs = float('NaN') #set defaults self.setdefaultparameters() #}}} def __repr__(self): # {{{ string=' Diagnostic solution parameters:' string="%s\n%s"%(string,' Convergence criteria:') string="%s\n%s"%(string,fielddisplay(self,'restol','mechanical equilibrium residual convergence criterion')) string="%s\n%s"%(string,fielddisplay(self,'reltol','velocity relative convergence criterion, NaN: not applied')) string="%s\n%s"%(string,fielddisplay(self,'abstol','velocity absolute convergence criterion, NaN: not applied')) string="%s\n%s"%(string,fielddisplay(self,'isnewton',"0: Picard's fixed point, 1: Newton's method, 2: hybrid")) string="%s\n%s"%(string,fielddisplay(self,'maxiter','maximum number of nonlinear iterations')) string="%s\n%s"%(string,fielddisplay(self,'viscosity_overshoot','over-shooting constant new=new+C*(new-old)')) string="%s\n%s"%(string,'\n boundary conditions:') string="%s\n%s"%(string,fielddisplay(self,'spcvx','x-axis velocity constraint (NaN means no constraint) [m/yr]')) string="%s\n%s"%(string,fielddisplay(self,'spcvy','y-axis velocity constraint (NaN means no constraint) [m/yr]')) string="%s\n%s"%(string,fielddisplay(self,'spcvz','z-axis velocity constraint (NaN means no constraint) [m/yr]')) string="%s\n%s"%(string,fielddisplay(self,'icefront','segments on ice front list (last column 0: Air, 1: Water, 2: Ice')) string="%s\n%s"%(string,'\n Rift options:') string="%s\n%s"%(string,fielddisplay(self,'rift_penalty_threshold','threshold for instability of mechanical constraints')) string="%s\n%s"%(string,fielddisplay(self,'rift_penalty_lock','number of iterations before rift penalties are locked')) string="%s\n%s"%(string,'\n Penalty options:') string="%s\n%s"%(string,fielddisplay(self,'penalty_factor','offset used by penalties: penalty = Kmax*10^offset')) string="%s\n%s"%(string,fielddisplay(self,'vertex_pairing','pairs of vertices that are penalized')) string="%s\n%s"%(string,'\n Other:') string="%s\n%s"%(string,fielddisplay(self,'shelf_dampening','use dampening for floating ice ? Only for Stokes model')) string="%s\n%s"%(string,fielddisplay(self,'stokesreconditioning','multiplier for incompressibility equation. Only for Stokes model')) string="%s\n%s"%(string,fielddisplay(self,'referential','local referential')) string="%s\n%s"%(string,fielddisplay(self,'loadingforce','loading force applied on each point [N/m^3]')) string="%s\n%s"%(string,fielddisplay(self,'requested_outputs','additional outputs requested')) return string #}}} def setdefaultparameters(self): # {{{ #maximum of non-linear iterations. self.maxiter=100 #Convergence criterion: absolute, relative and residual self.restol=10**-4 self.reltol=0.01 self.abstol=10 self.stokesreconditioning=10**13 self.shelf_dampening=0 #Penalty factor applied kappa=max(stiffness matrix)*10^penalty_factor self.penalty_factor=3 #coefficient to update the viscosity between each iteration of #a diagnostic according to the following formula #viscosity(n)=viscosity(n)+viscosity_overshoot(viscosity(n)-viscosity(n-1)) self.viscosity_overshoot=0 #Stop the iterations of rift if below a threshold self.rift_penalty_threshold=0 #in some solutions, it might be needed to stop a run when only #a few constraints remain unstable. For thermal computation, this #parameter is often used. self.rift_penalty_lock=10 return self #}}} def checkconsistency(self,md,solution,analyses): # {{{ #Early return if DiagnosticHorizAnalysisEnum() not in analyses: return md #if (DiagnosticHorizAnalysisEnum() not in analyses) | (solution==TransientSolutionEnum() and not md.transient.isdiagnostic): # return md md = checkfield(md,'diagnostic.spcvx','forcing',1) md = checkfield(md,'diagnostic.spcvy','forcing',1) if md.mesh.dimension==3: md = checkfield(md,'diagnostic.spcvz','forcing',1) md = checkfield(md,'diagnostic.restol','size',[1],'>',0) md = checkfield(md,'diagnostic.reltol','size',[1]) md = checkfield(md,'diagnostic.abstol','size',[1]) md = checkfield(md,'diagnostic.isnewton','numel',[1],'values',[0,1,2]) md = checkfield(md,'diagnostic.stokesreconditioning','size',[1],'NaN',1) md = checkfield(md,'diagnostic.viscosity_overshoot','size',[1],'NaN',1) if md.mesh.dimension==2: md = checkfield(md,'diagnostic.icefront','size',[float('NaN'),4],'NaN',1) else: md = checkfield(md,'diagnostic.icefront','size',[float('NaN'),6],'NaN',1) md = checkfield(md,'diagnostic.icefront[:,-1]','values',[0,1,2]) md = checkfield(md,'diagnostic.maxiter','size',[1],'>=',1) md = checkfield(md,'diagnostic.referential','size',[md.mesh.numberofvertices,6]) md = checkfield(md,'diagnostic.loadingforce','size',[md.mesh.numberofvertices,3]) if not md.diagnostic.requested_outputs: md = checkfield(md,'diagnostic.requested_outputs','size',[float('NaN'),1]) #singular solution # if ~any((~isnan(md.diagnostic.spcvx)+~isnan(md.diagnostic.spcvy))==2), if not numpy.any(numpy.logical_and(numpy.logical_not(numpy.isnan(md.diagnostic.spcvx)),numpy.logical_not(numpy.isnan(md.diagnostic.spcvy)))): md.checkmessage("model is not well posed (singular). You need at least one node with fixed velocity!") #CHECK THAT EACH LINES CONTAINS ONLY NAN VALUES OR NO NAN VALUES # if any(sum(isnan(md.diagnostic.referential),2)~=0 & sum(isnan(md.diagnostic.referential),2)~=6), if numpy.any(numpy.logical_and(numpy.sum(numpy.isnan(md.diagnostic.referential),axis=1)!=0,numpy.sum(numpy.isnan(md.diagnostic.referential),axis=1)!=6)): md.checkmessage("Each line of diagnostic.referential should contain either only NaN values or no NaN values") #CHECK THAT THE TWO VECTORS PROVIDED ARE ORTHOGONAL # if any(sum(isnan(md.diagnostic.referential),2)==0), if numpy.any(numpy.sum(numpy.isnan(md.diagnostic.referential),axis=1)==0): pos=[i for i,item in enumerate(numpy.sum(numpy.isnan(md.diagnostic.referential),axis=1)) if item==0] # numpy.inner (and numpy.dot) calculate all the dot product permutations, resulting in a full matrix multiply # if numpy.any(numpy.abs(numpy.inner(md.diagnostic.referential[pos,0:2],md.diagnostic.referential[pos,3:5]).diagonal())>sys.float_info.epsilon): # md.checkmessage("Vectors in diagnostic.referential (columns 1 to 3 and 4 to 6) must be orthogonal") for item in md.diagnostic.referential[pos,:]: if numpy.abs(numpy.inner(item[0:2],item[3:5]))>sys.float_info.epsilon: md.checkmessage("Vectors in diagnostic.referential (columns 1 to 3 and 4 to 6) must be orthogonal") #CHECK THAT NO rotation specified for FS Grounded ice at base # if md.mesh.dimension==3 & md.flowequation.isstokes, if md.mesh.dimension==3 and md.flowequation.isstokes: pos=numpy.nonzero(numpy.logical_and(md.mask.vertexongroundedice,md.mesh.vertexonbed)) if numpy.any(numpy.logical_not(numpy.isnan(md.diagnostic.referential[pos,:]))): md.checkmessage("no referential should be specified for basal vertices of grounded ice") return md # }}} def marshall(self,md,fid): # {{{ WriteData(fid,'object',self,'fieldname','spcvx','format','DoubleMat','mattype',1,'forcinglength',md.mesh.numberofvertices+1) WriteData(fid,'object',self,'fieldname','spcvy','format','DoubleMat','mattype',1,'forcinglength',md.mesh.numberofvertices+1) WriteData(fid,'object',self,'fieldname','spcvz','format','DoubleMat','mattype',1,'forcinglength',md.mesh.numberofvertices+1) WriteData(fid,'object',self,'fieldname','restol','format','Double') WriteData(fid,'object',self,'fieldname','reltol','format','Double') WriteData(fid,'object',self,'fieldname','abstol','format','Double') WriteData(fid,'object',self,'fieldname','isnewton','format','Integer') WriteData(fid,'object',self,'fieldname','stokesreconditioning','format','Double') WriteData(fid,'object',self,'fieldname','viscosity_overshoot','format','Double') WriteData(fid,'object',self,'fieldname','maxiter','format','Integer') WriteData(fid,'object',self,'fieldname','shelf_dampening','format','Integer') WriteData(fid,'object',self,'fieldname','vertex_pairing','format','DoubleMat','mattype',3) WriteData(fid,'object',self,'fieldname','penalty_factor','format','Double') WriteData(fid,'object',self,'fieldname','rift_penalty_lock','format','Integer') WriteData(fid,'object',self,'fieldname','rift_penalty_threshold','format','Integer') WriteData(fid,'object',self,'fieldname','referential','format','DoubleMat','mattype',1) WriteData(fid,'data',self.loadingforce[:,0],'format','DoubleMat','mattype',1,'enum',LoadingforceXEnum()) WriteData(fid,'data',self.loadingforce[:,1],'format','DoubleMat','mattype',1,'enum',LoadingforceYEnum()) WriteData(fid,'data',self.loadingforce[:,2],'format','DoubleMat','mattype',1,'enum',LoadingforceZEnum()) WriteData(fid,'object',self,'fieldname','requested_outputs','format','DoubleMat','mattype',3) #marshall ice front data=copy.deepcopy(self.icefront) data[numpy.nonzero(data[:,-1]==0),-1]=AirEnum() data[numpy.nonzero(data[:,-1]==1),-1]=WaterEnum() data[numpy.nonzero(data[:,-1]==2),-1]=IceEnum() WriteData(fid,'data',data,'enum',DiagnosticIcefrontEnum(),'format','DoubleMat','mattype',3) # }}}