class SmoothScalarDistributionFromTags(ParameterSet): """ creates a smooth scalar distribution on a domain from region tags :ivar domain: domain :type domain: `esys.escript.Domain` :ivar default: default value :ivar tag0: tag 0 :type tag0: ``int`` :ivar value0: value for tag 0 :type value0: ``float`` :ivar tag1: tag 1 :type tag1: ``int`` :ivar value1: value for tag 1 :type value1: ``float`` :ivar tag2: tag 2 :type tag2: ``int`` :ivar value2: value for tag 2 :type value2: ``float`` :ivar tag3: tag 3 :type tag3: ``int`` :ivar value3: value for tag 3 :type value3: ``float`` :ivar tag4: tag 4 :type tag4: ``int`` :ivar value4: value for tag 4 :type value4: ``float`` :ivar tag5: tag 5 :type tag5: ``int`` :ivar value5: value for tag 5 :type value5: ``float`` :ivar tag6: tag 6 :type tag6: ``int`` :ivar value6: value for tag 6 :type value6: ``float`` :ivar tag7: tag 7 :type tag7: ``int`` :ivar value7: value for tag 7 :type value7: ``float`` :ivar tag8: tag 8 :type tag8: ``int`` :ivar value8: value for tag 8 :type value8: ``float`` :ivar tag9: tag 9 :type tag9: ``int`` :ivar value9: value for tag 9 :type value9: ``float`` """ def __init__(self, **kwargs): super(SmoothScalarDistributionFromTags, self).__init__(**kwargs) self.declareParameter(domain=None, default=0., tag0=None, value0=0., tag1=None, value1=0., tag2=None, value2=0., tag3=None, value3=0., tag4=None, value4=0., tag5=None, value5=0., tag6=None, value6=0., tag7=None, value7=0., tag8=None, value8=0., tag9=None, value9=0.) def __update(self, tag, tag_value, value): if self.__pde == None: self.__pde = LinearPDE(self.domain, numSolutions=1) mask = Scalar(0., Function(self.domain)) mask.setTaggedValue(tag, 1.) self.__pde.setValue(Y=mask) mask = wherePositive(abs(self.__pde.getRightHandSide())) value *= (1. - mask) value += tag_value * mask return value def out(self): """ returns a `esys.escript.Data` object Link against this method to get the output of this model. """ d = Scalar(self.default, Solution(self.domain)) self.__pde = None if not self.tag0 is None: d = self.__update(self.tag0, self.value0, d) if not self.tag1 is None: d = self.__update(self.tag1, self.value1, d) if not self.tag2 is None: d = self.__update(self.tag2, self.value2, d) if not self.tag3 is None: d = self.__update(self.tag3, self.value3, d) if not self.tag4 is None: d = self.__update(self.tag4, self.value4, d) if not self.tag5 is None: d = self.__update(self.tag5, self.value5, d) if not self.tag6 is None: d = self.__update(self.tag6, self.value6, d) if not self.tag7 is None: d = self.__update(self.tag7, self.value7, d) if not self.tag8 is None: d = self.__update(self.tag8, self.value8, d) if not self.tag9 is None: d = self.__update(self.tag9, self.value9, d) return d
class SmoothScalarDistributionFromTags(ParameterSet): """ creates a smooth scalar distribution on a domain from region tags :ivar domain: domain :type domain: `esys.escript.Domain` :ivar default: default value :ivar tag0: tag 0 :type tag0: ``int`` :ivar value0: value for tag 0 :type value0: ``float`` :ivar tag1: tag 1 :type tag1: ``int`` :ivar value1: value for tag 1 :type value1: ``float`` :ivar tag2: tag 2 :type tag2: ``int`` :ivar value2: value for tag 2 :type value2: ``float`` :ivar tag3: tag 3 :type tag3: ``int`` :ivar value3: value for tag 3 :type value3: ``float`` :ivar tag4: tag 4 :type tag4: ``int`` :ivar value4: value for tag 4 :type value4: ``float`` :ivar tag5: tag 5 :type tag5: ``int`` :ivar value5: value for tag 5 :type value5: ``float`` :ivar tag6: tag 6 :type tag6: ``int`` :ivar value6: value for tag 6 :type value6: ``float`` :ivar tag7: tag 7 :type tag7: ``int`` :ivar value7: value for tag 7 :type value7: ``float`` :ivar tag8: tag 8 :type tag8: ``int`` :ivar value8: value for tag 8 :type value8: ``float`` :ivar tag9: tag 9 :type tag9: ``int`` :ivar value9: value for tag 9 :type value9: ``float`` """ def __init__(self,**kwargs): super(SmoothScalarDistributionFromTags, self).__init__(**kwargs) self.declareParameter(domain=None, default=0., tag0=None, value0=0., tag1=None, value1=0., tag2=None, value2=0., tag3=None, value3=0., tag4=None, value4=0., tag5=None, value5=0., tag6=None, value6=0., tag7=None, value7=0., tag8=None, value8=0., tag9=None, value9=0.) def __update(self,tag,tag_value,value): if self.__pde==None: self.__pde=LinearPDE(self.domain,numSolutions=1) mask=Scalar(0.,Function(self.domain)) mask.setTaggedValue(tag,1.) self.__pde.setValue(Y=mask) mask=wherePositive(abs(self.__pde.getRightHandSide())) value*=(1.-mask) value+=tag_value*mask return value def out(self): """ returns a `esys.escript.Data` object Link against this method to get the output of this model. """ d=Scalar(self.default,Solution(self.domain)) self.__pde=None if not self.tag0 is None: d=self.__update(self.tag0,self.value0,d) if not self.tag1 is None: d=self.__update(self.tag1,self.value1,d) if not self.tag2 is None: d=self.__update(self.tag2,self.value2,d) if not self.tag3 is None: d=self.__update(self.tag3,self.value3,d) if not self.tag4 is None: d=self.__update(self.tag4,self.value4,d) if not self.tag5 is None: d=self.__update(self.tag5,self.value5,d) if not self.tag6 is None: d=self.__update(self.tag6,self.value6,d) if not self.tag7 is None: d=self.__update(self.tag7,self.value7,d) if not self.tag8 is None: d=self.__update(self.tag8,self.value8,d) if not self.tag9 is None: d=self.__update(self.tag9,self.value9,d) return d
class MultiScale(object): """ problem description: D_ij u_j = -X_{ij,j} + Y_i Neumann boundary: d_ij u_j = n_j X_{ij} + y_i Dirichlet boundary: u_i = r_i where q_i > 0 :var u: unknown vector, displacement :var X: old/current stress tensor :var Y: vector, body force :var y: vector, Neumann bc traction :var q: vector, Dirichlet bc mask :var r: vector, Dirichlet bc value """ def __init__(self,domain,dim,ng=1,useMPI=False,np=1,rho=2.35e3,mIds=False,\ FEDENodeMap=False,DE_ext=False,FEDEBoundMap=False,conf=False): """ initialization of the problem, i.e. model constructor :param domain: type Domain, domain of the problem :param ng: type integer, number of Gauss points :param useMPI: type boolean, use MPI or not :param np: type integer, number of processors :param rho: type float, density of material :param mIds: a list contains membrane node IDs :param FEDENodeMap: a dictionary with FE and DE boundary node IDs in keys and values :param DE_ext: name of file which saves initial state of exterior DE domain :param FEDEBoundMap: a dictionary with FE and DE boundary element IDs in keys and values (deprecated) :param conf: type float, conf pressure on membrane """ self.__domain = domain self.__pde = LinearPDE(self.__domain, numEquations=dim, numSolutions=dim) self.__pde.getSolverOptions().setSolverMethod( SolverOptions.HRZ_LUMPING) self.__pde.setSymmetryOn() self.__numGaussPoints = ng self.__rho = rho self.__mIds = mIds self.__FEDENodeMap = FEDENodeMap self.__FEDEBoundMap = FEDEBoundMap self.__conf = conf self.__pool = get_pool(mpi=useMPI, threads=np) self.__scenes = self.__pool.map(initLoad, range(ng)) self.__strain = escript.Tensor(0, escript.Function(self.__domain)) self.__stress = escript.Tensor(0, escript.Function(self.__domain)) self.__u = escript.Vector(0, escript.Solution(self.__domain)) self.__u_last = escript.Vector(0, escript.Solution(self.__domain)) self.__u_t = escript.Vector(0, escript.Solution(self.__domain)) self.__dt = 0 # ratio between timesteps in internal DE and FE domain self.__nsOfDE_int = 1 # if FEDENodeMap is given, employ exterior DE domain if self.__FEDENodeMap: self.__sceneExt = self.__pool.apply(initLoadExt, (DE_ext, )) # ratio between timesteps in external DE and FE domain self.__nsOfDE_ext = 1 # get interface nodal forces as boundary condition self.__FEf = self.__pool.apply( initNbc, (self.__sceneExt, self.__conf, mIds, FEDENodeMap)) """ # get interface nodal tractions as boundary condition (deprecated) self.__Nbc=escript.Vector(0,escript.Solution(self.__domain)) FENbc = self.__pool.apply(initNbc,(self.__sceneExt,self.__conf,mIds,FEDENodeMap)) for FEid in FENbc.keys(): self.__Nbc.setValueOfDataPoint(FEid,FENbc[FEid]) """ # get stress tensor at material points s = self.__pool.map(getStress2D, self.__scenes) for i in xrange(ng): self.__stress.setValueOfDataPoint(i, s[i]) def initialize(self, b=escript.Data(), f=escript.Data(), specified_u_mask=escript.Data(), specified_u_val=escript.Data(), dt=0): """ initialize the model for each time step, e.g. assign parameters :param b: type vector, body force on FunctionSpace, e.g. gravity :param f: type vector, boundary traction on FunctionSpace (FunctionOnBoundary) :param specified_u_mask: type vector, mask of location for Dirichlet boundary :param specified_u_val: type vector, specified displacement for Dirichlet boundary """ self.__pde.setValue(Y=b, y=f, q=specified_u_mask, r=specified_u_val) # if FEDENodeMap is given if self.__FEDENodeMap: # assign dt_FE/dt_DE_ext to self.__nsOfDE_ext dt_ext = self.__pool.apply(getScenetDt, (self.__sceneExt, )) self.__nsOfDE_ext = int(round(dt / dt_ext)) print "Ratio between time step in FE and exterior DE domain: %1.1e" % self.__nsOfDE_ext dt_int = self.__pool.map(getScenetDt, self.__scenes) # assign a list of dt_FE/dt_DE_int to self.__nsOfDE_int self.__nsOfDE_int = numpy.round(numpy.array(dt) / dt_int).astype(int) print "Maximum ratio between time step in FE and interior DE domains: %1.1e" % max( self.__nsOfDE_int) if dt == 0: raise RuntimeError, "Time step in FE domain is not given" self.__dt = dt print "Time step in FE domain:%1.1e" % self.__dt def getDomain(self): """ return model domain """ return self.__domain ## below is Ning Guo's original script ## def getCurrentPacking(self, pos=(), time=0, prefix=''): if len(pos) == 0: # output all Gauss points packings self.__pool.map(outputPack, zip(self.__scenes, repeat(time), repeat(prefix))) else: # output selected Gauss points packings scene = [self.__scenes[i] for i in pos] self.__pool.map(outputPack, zip(scene, repeat(time), repeat(prefix))) def getLocalVoidRatio(self): void = escript.Scalar(0, escript.Function(self.__domain)) e = self.__pool.map(getVoidRatio2D, self.__scenes) for i in xrange(self.__numGaussPoints): void.setValueOfDataPoint(i, e[i]) return void def getLocalAvgRotation(self): rot = escript.Scalar(0, escript.Function(self.__domain)) r = self.__pool.map(avgRotation2D, self.__scenes) for i in xrange(self.__numGaussPoints): rot.setValueOfDataPoint(i, r[i]) return rot def getLocalFabric(self): fabric = escript.Tensor(0, escript.Function(self.__domain)) f = self.__pool.map(getFabric2D, self.__scenes) for i in xrange(self.__numGaussPoints): fabric.setValueOfDataPoint(i, f[i]) return fabric def getCurrentStress(self): """ return current stress type: Tensor on FunctionSpace """ return self.__stress def getCurrentTangent(self): """ return current tangent operator type Tensor4 on FunctionSpace """ t = escript.Tensor4(0, escript.Function(self.__domain)) st = self.__pool.map(getStressAndTangent2D, self.__scenes) for i in xrange(self.__numGaussPoints): t.setValueOfDataPoint(i, st[i][1]) return t def getCurrentStrain(self): """ return current strain type: Tensor on FunctionSpace """ return self.__strain def exitSimulation(self): """finish the whole simulation, exit""" self.__pool.close() ## below is modified by Hongyang Cheng ## def setRHS(self, X, Y=escript.Data()): """ set right hande side of PDE, including X_{ij} and Y_i X: stress tensor at (n) time step Y: vector, (equivalent) body force at (n) time step Note that boundary force, if any, is set inhere """ # apply internal stress and equivalent body force self.__pde.setValue(X=X, Y=Y) # if exterior DE domain is given if self.__FEDENodeMap: FEf = self.getFEf() rhs = self.__pde.getRightHandSide() # !!!!!! apply boundary force to the right hande side of PDE for FEid in FEf.keys(): rhs_i = rhs.getTupleForDataPoint(FEid) rhs_i_new = [sum(f) for f in zip(rhs_i, FEf[FEid])] rhs.setValueOfDataPoint(FEid, rhs_i_new) # consider Neumann boundary conditions rhs -= rhs * self.__pde.getCoefficient('q') """ # !!!!!! apply boundary traction to the right hand side of PDE (deprecated) self.__pde.setValue(X=X, Y=Y, y=self.__Nbc) """ def solve(self, damp=.2, dynRelax=False): """ solve the equation of motion in centeral difference scheme """ # get initial coordinate x = self.getDomain().getX() # density matrix kron = util.kronecker(self.getDomain().getDim()) rho = self.__rho * kron # stress at (n) time step stress_last = self.getCurrentStress() # set coefficients for ODE self.__pde.setValue(D=rho) self.setRHS(X=-stress_last) # solve acceleration at (n) time step from ODE u_tt = self.__pde.getSolution() # update velocity at (n+1/2) time step self.__u_t = 1. / (2. + damp * self.__dt) * ( (2. - damp * self.__dt) * self.__u_t + 2. * self.__dt * u_tt) # get displacement increment du = self.__dt * self.__u_t # update strain D = util.grad(du) self.__strain += D # update displacement and domain geometry at (n+1) time step self.__u += du self.__domain.setX(x + du) # !!!!!! apply displacement increment and get boundary force from DE exterior domain, if any if self.__FEDENodeMap: DEdu = self.getBoundaryDisplacement(du) """ # apply boundary velocity and get boundary traction (deprecated) self.__Nbc,self.__sceneExt=self.applyDisplIncrement_getTractionDEM(DEdu=DEdu) """ # apply boundary velocity and return an asynResult object arFEfAndSceneExt = self.applyDisplIncrement_getForceDEM( DEdu=DEdu, dynRelax=dynRelax) # !!!!!! update stress and scenes from DEM part using strain at (n+1) time step self.__stress, self.__scenes = self.applyStrain_getStressDEM( st=D, dynRelax=dynRelax) """ # !!!!!! update scenes and return asynResult objects (deprecated) arScenes = self.applyStrain(st=D) # !!!!!! retrieve data from asyncResults # update interior DE scenes self.__scenes = arScenes.get() # assign new stresses to gauss points from interior DE scenes s = self.__pool.map(getStress2D,self.__scenes) for i in xrange(self.__numGaussPoints): self.__stress.setValueOfDataPoint(i,s[i]) """ # if exterior DE domain is given, update scene and boundary force if self.__FEDENodeMap: self.__FEf, self.__sceneExt = arFEfAndSceneExt.get() return self.__u, self.__u_t """ apply strain to DEM packing and return a result object """ def applyStrain(self, st=escript.Data()): st = st.toListOfTuples() st = numpy.array(st).reshape(-1, 4) # load DEM packing with strain arScenes = self.__pool.map_async( shear2D, zip(self.__scenes, st, self.__nsOfDE_int)) return arScenes """ apply strain to DEM packing and get stress """ def applyStrain_getStressDEM(self, st=escript.Data(), dynRelax=False): st = st.toListOfTuples() st = numpy.array(st).reshape(-1, 4) stress = escript.Tensor(0, escript.Function(self.__domain)) # load DEM packing with strain scenes = self.__pool.map( shear2D, zip(self.__scenes, st, self.__nsOfDE_int, repeat(dynRelax))) # return homogenized stress s = self.__pool.map(getStress2D, scenes) for i in xrange(self.__numGaussPoints): stress.setValueOfDataPoint(i, s[i]) return stress, scenes #~ def applyDisplIncrement_getTractionDEM(self,DEdu=escript.Data()): #~ """ #~ apply displacement increment to the external DE domain, #~ and get boundary traction from DE interface nodes #~ """ #~ FENbc, sceneExt = self.__pool.apply( \ #~ moveInterface_getTraction2D,(self.__sceneExt,self.__conf,DEdu, \ #~ self.__mIds,self.__FEDENodeMap,self.__nsOfDE_ext)) #~ Nbc=escript.Vector(0,escript.Solution(self.getDomain())) #~ for FEid in self.__FEDENodeMap.keys(): #~ Nbc.setValueOfDataPoint(FEid,FENbc[FEid]) #~ return Nbc, sceneExt def applyDisplIncrement_getForceDEM(self, DEdu=escript.Data(), dynRelax=False): """ apply displacement increment to the external DE domain, and get boundary force from DE interface nodes """ arFEfAndSceneExt = self.__pool.apply_async( \ moveInterface_getForce2D,(self.__sceneExt,self.__conf,DEdu,dynRelax, \ self.__mIds,self.__FEDENodeMap,self.__nsOfDE_ext)) return arFEfAndSceneExt def getBoundaryDisplacement(self, du): """ get a dictionary contains DE interface node ids and displacement increment """ # exchange FE-node ids (keys) with DE-node ids (values) DEdu = dict((v, k) for k, v in self.__FEDENodeMap.iteritems()) for key in DEdu.keys(): FEid = DEdu[key] DEdu[key] = du.getTupleForDataPoint(FEid) return DEdu def VTKExporter(self, vtkDir='./', t=0): """ export interactions in all DE scenes using vtk format """ # export interactions in RVEs #~ self.__pool.map(exportInt,zip(self.__scenes,repeat(vtkDir),repeat(t))) # export tensile forces in membrane self.__pool.apply(exportExt, (self.__sceneExt, self.__mIds, vtkDir, t)) def getPDE(self): """ return partial differential equation """ return self.__pde def getSceneExt(self): """ return scene of exterior DE domain, if any """ return self.__sceneExt def getNbc(self): """ return Neumann boundary condition converted from exterior DE domain """ if self.__FEDENodeMap: Nbc = self.__Nbc else: Nbc = self.__pde.getCoefficient("y") return Nbc def getFEf(self): """ return boundary forces converted from exterior DE domain """ if self.__FEDENodeMap: FEf = self.__FEf else: raise RuntimeError, "No exterior DE domain!" return FEf def getNsOfDE_int(self): """ return a list of numbers of interior DE simulations per FE domain simulation """ return self.__nsOfDE_int def getNsOfDE_ext(self): """ return number of exterior DE simulations per FE domain simulation """ return self.__nsOfDE_ext def getMaxEigenvalue(self): """ return the max eigenvalue of the model type: float """ dom = self.getDomain() dim = dom.getDim() pdeKu_P = LinearPDE(dom, numEquations=dim, numSolutions=dim) T = self.getCurrentTangent() pdeKu_P.setValue(A=T) pdeKu_P.getOperator().saveMM('tempMTX.mtx') mtx = mmread('tempMTX.mtx') maxEigVal = max(eigs(mtx, k=1, return_eigenvectors=False, which='LR')) return maxEigVal.real def getBoundaryNodesPositions(self, tag_name="bound"): """ get a dictionary contains FE boundary node IDs and corresponding positions use data on "Solution" FunctionSpace to export FE node IDs (DataPoint IDs) note that though "ContinousFunction" and "Solution" FunctionSpace have save number of DataPoints, their numbering order are not the same!!! Therefore, always use coordiates and IDs of DataPoints on "Solution" for data communication """ tag = self.getDomain().getTag(tag_name) # get "Solution" FunctinonSpace fs = escript.Solution(self.getDomain()) # get coordinates with "Solution" FunctionSpace numbering order # fs and fs.getX().getFunctionSpace() are the same x = fs.getX() # get domain FunctionSpace, note below is different from fs.getX().getFunctionSpace() domFS = fs.getDomain().getX().getFunctionSpace() num = x.getNumberOfDataPoints() pos = {} for i in xrange(num): refId = fs.getReferenceIDFromDataPointNo(i) # domain FunctionSpace DataPoint IDs = RefId-1 if domFS.getTagFromDataPointNo(refId - 1) == tag: pos[i] = x.getTupleForDataPoint(i) return pos def getBoundaryDataPointIDsAndRefIDs(self): """ get a dictionary contains data point IDs and reference IDs on BoundaryOnFunction numbering order of reference IDs and interface elements need to be consistent """ # get "FunctionOnBoundary" FunctionSpace bfs = escript.FunctionOnBoundary(self.getDomain()) # convert discrete reference IDs to continous numbers num = bfs.getX().getNumberOfDataPoints() FEDEBoundMap = {} n = 0 for i in xrange(num): refID = bfs.getReferenceIDFromDataPointNo(i) if n != refID: newID = 2 * (refID - 1) else: newID = 2 * (refID - 1) + 1 # save DataPoint IDs in keys and converted newIDs in values n = refID FEDEBoundMap[i] = newID return FEDEBoundMap """
class MultiScale(object): """ problem description: D_ij u_j = -X_{ij,j} + Y_i Neumann boundary: d_ij u_j = n_j X_{ij} + y_i Dirichlet boundary: u_i = r_i where q_i > 0 :var u: unknown vector, displacement :var X: old/current stress tensor :var Y: vector, body force :var y: vector, Neumann bc traction :var q: vector, Dirichlet bc mask :var r: vector, Dirichlet bc value """ def __init__(self,domain,dim,ng=1,useMPI=False,np=1,rho=2.35e3,mIds=False,\ FEDENodeMap=False,DE_ext=False,FEDEBoundMap=False,conf=False): """ initialization of the problem, i.e. model constructor :param domain: type Domain, domain of the problem :param ng: type integer, number of Gauss points :param useMPI: type boolean, use MPI or not :param np: type integer, number of processors :param rho: type float, density of material :param mIds: a list contains membrane node IDs :param FEDENodeMap: a dictionary with FE and DE boundary node IDs in keys and values :param DE_ext: name of file which saves initial state of exterior DE domain :param FEDEBoundMap: a dictionary with FE and DE boundary element IDs in keys and values (deprecated) :param conf: type float, conf pressure on membrane """ self.__domain=domain self.__pde=LinearPDE(self.__domain,numEquations=dim,numSolutions=dim) self.__pde.getSolverOptions().setSolverMethod(SolverOptions.HRZ_LUMPING) self.__pde.setSymmetryOn() self.__numGaussPoints=ng self.__rho=rho self.__mIds=mIds self.__FEDENodeMap=FEDENodeMap self.__FEDEBoundMap=FEDEBoundMap self.__conf=conf self.__pool=get_pool(mpi=useMPI,threads=np) self.__scenes=self.__pool.map(initLoad,range(ng)) self.__strain=escript.Tensor(0,escript.Function(self.__domain)) self.__stress=escript.Tensor(0,escript.Function(self.__domain)) self.__u=escript.Vector(0,escript.Solution(self.__domain)) self.__u_last=escript.Vector(0,escript.Solution(self.__domain)) self.__u_t=escript.Vector(0,escript.Solution(self.__domain)) self.__dt=0 # ratio between timesteps in internal DE and FE domain self.__nsOfDE_int=1 # if FEDENodeMap is given, employ exterior DE domain if self.__FEDENodeMap: self.__sceneExt=self.__pool.apply(initLoadExt,(DE_ext,)) # ratio between timesteps in external DE and FE domain self.__nsOfDE_ext=1 # get interface nodal forces as boundary condition self.__FEf = self.__pool.apply(initNbc,(self.__sceneExt,self.__conf,mIds,FEDENodeMap)) """ # get interface nodal tractions as boundary condition (deprecated) self.__Nbc=escript.Vector(0,escript.Solution(self.__domain)) FENbc = self.__pool.apply(initNbc,(self.__sceneExt,self.__conf,mIds,FEDENodeMap)) for FEid in FENbc.keys(): self.__Nbc.setValueOfDataPoint(FEid,FENbc[FEid]) """ # get stress tensor at material points s = self.__pool.map(getStress2D,self.__scenes) for i in xrange(ng): self.__stress.setValueOfDataPoint(i,s[i]) def initialize(self, b=escript.Data(), f=escript.Data(), specified_u_mask=escript.Data(), specified_u_val=escript.Data(), dt=0): """ initialize the model for each time step, e.g. assign parameters :param b: type vector, body force on FunctionSpace, e.g. gravity :param f: type vector, boundary traction on FunctionSpace (FunctionOnBoundary) :param specified_u_mask: type vector, mask of location for Dirichlet boundary :param specified_u_val: type vector, specified displacement for Dirichlet boundary """ self.__pde.setValue(Y=b,y=f,q=specified_u_mask,r=specified_u_val) # if FEDENodeMap is given if self.__FEDENodeMap: # assign dt_FE/dt_DE_ext to self.__nsOfDE_ext dt_ext = self.__pool.apply(getScenetDt,(self.__sceneExt,)) self.__nsOfDE_ext = int(round(dt/dt_ext)) print "Ratio between time step in FE and exterior DE domain: %1.1e"%self.__nsOfDE_ext dt_int = self.__pool.map(getScenetDt,self.__scenes) # assign a list of dt_FE/dt_DE_int to self.__nsOfDE_int self.__nsOfDE_int = numpy.round(numpy.array(dt)/dt_int).astype(int) print "Maximum ratio between time step in FE and interior DE domains: %1.1e"%max(self.__nsOfDE_int) if dt == 0: raise RuntimeError,"Time step in FE domain is not given" self.__dt = dt print "Time step in FE domain:%1.1e"%self.__dt def getDomain(self): """ return model domain """ return self.__domain ## below is Ning Guo's original script ## def getCurrentPacking(self,pos=(),time=0,prefix=''): if len(pos) == 0: # output all Gauss points packings self.__pool.map(outputPack,zip(self.__scenes,repeat(time),repeat(prefix))) else: # output selected Gauss points packings scene = [self.__scenes[i] for i in pos] self.__pool.map(outputPack,zip(scene,repeat(time),repeat(prefix))) def getLocalVoidRatio(self): void=escript.Scalar(0,escript.Function(self.__domain)) e = self.__pool.map(getVoidRatio2D,self.__scenes) for i in xrange(self.__numGaussPoints): void.setValueOfDataPoint(i,e[i]) return void def getLocalAvgRotation(self): rot=escript.Scalar(0,escript.Function(self.__domain)) r = self.__pool.map(avgRotation2D,self.__scenes) for i in xrange(self.__numGaussPoints): rot.setValueOfDataPoint(i,r[i]) return rot def getLocalFabric(self): fabric=escript.Tensor(0,escript.Function(self.__domain)) f = self.__pool.map(getFabric2D,self.__scenes) for i in xrange(self.__numGaussPoints): fabric.setValueOfDataPoint(i,f[i]) return fabric def getCurrentStress(self): """ return current stress type: Tensor on FunctionSpace """ return self.__stress def getCurrentTangent(self): """ return current tangent operator type Tensor4 on FunctionSpace """ t=escript.Tensor4(0,escript.Function(self.__domain)) st = self.__pool.map(getStressAndTangent2D,self.__scenes) for i in xrange(self.__numGaussPoints): t.setValueOfDataPoint(i,st[i][1]) return t def getCurrentStrain(self): """ return current strain type: Tensor on FunctionSpace """ return self.__strain def exitSimulation(self): """finish the whole simulation, exit""" self.__pool.close() ## below is modified by Hongyang Cheng ## def setRHS(self,X,Y=escript.Data()): """ set right hande side of PDE, including X_{ij} and Y_i X: stress tensor at (n) time step Y: vector, (equivalent) body force at (n) time step Note that boundary force, if any, is set inhere """ # apply internal stress and equivalent body force self.__pde.setValue(X=X, Y=Y) # if exterior DE domain is given if self.__FEDENodeMap: FEf = self.getFEf() rhs = self.__pde.getRightHandSide() # !!!!!! apply boundary force to the right hande side of PDE for FEid in FEf.keys(): rhs_i = rhs.getTupleForDataPoint(FEid) rhs_i_new = [sum(f) for f in zip(rhs_i,FEf[FEid])] rhs.setValueOfDataPoint(FEid,rhs_i_new) # consider Neumann boundary conditions rhs -= rhs*self.__pde.getCoefficient('q') """ # !!!!!! apply boundary traction to the right hand side of PDE (deprecated) self.__pde.setValue(X=X, Y=Y, y=self.__Nbc) """ def solve(self,damp=.2,dynRelax=False): """ solve the equation of motion in centeral difference scheme """ # get initial coordinate x = self.getDomain().getX() # density matrix kron = util.kronecker(self.getDomain().getDim()) rho = self.__rho*kron # stress at (n) time step stress_last = self.getCurrentStress() # set coefficients for ODE self.__pde.setValue(D=rho) self.setRHS(X=-stress_last) # solve acceleration at (n) time step from ODE u_tt = self.__pde.getSolution() # update velocity at (n+1/2) time step self.__u_t = 1./(2.+damp*self.__dt)*((2.-damp*self.__dt)*self.__u_t + 2.*self.__dt*u_tt) # get displacement increment du = self.__dt*self.__u_t # update strain D = util.grad(du) self.__strain += D # update displacement and domain geometry at (n+1) time step self.__u += du self.__domain.setX(x+du) # !!!!!! apply displacement increment and get boundary force from DE exterior domain, if any if self.__FEDENodeMap: DEdu = self.getBoundaryDisplacement(du) """ # apply boundary velocity and get boundary traction (deprecated) self.__Nbc,self.__sceneExt=self.applyDisplIncrement_getTractionDEM(DEdu=DEdu) """ # apply boundary velocity and return an asynResult object arFEfAndSceneExt=self.applyDisplIncrement_getForceDEM(DEdu=DEdu,dynRelax=dynRelax) # !!!!!! update stress and scenes from DEM part using strain at (n+1) time step self.__stress,self.__scenes = self.applyStrain_getStressDEM(st=D,dynRelax=dynRelax) """ # !!!!!! update scenes and return asynResult objects (deprecated) arScenes = self.applyStrain(st=D) # !!!!!! retrieve data from asyncResults # update interior DE scenes self.__scenes = arScenes.get() # assign new stresses to gauss points from interior DE scenes s = self.__pool.map(getStress2D,self.__scenes) for i in xrange(self.__numGaussPoints): self.__stress.setValueOfDataPoint(i,s[i]) """ # if exterior DE domain is given, update scene and boundary force if self.__FEDENodeMap: self.__FEf,self.__sceneExt = arFEfAndSceneExt.get() return self.__u, self.__u_t """ apply strain to DEM packing and return a result object """ def applyStrain(self,st=escript.Data()): st = st.toListOfTuples() st = numpy.array(st).reshape(-1,4) # load DEM packing with strain arScenes = self.__pool.map_async(shear2D,zip(self.__scenes,st,self.__nsOfDE_int)) return arScenes """ apply strain to DEM packing and get stress """ def applyStrain_getStressDEM(self,st=escript.Data(),dynRelax=False): st = st.toListOfTuples() st = numpy.array(st).reshape(-1,4) stress = escript.Tensor(0,escript.Function(self.__domain)) # load DEM packing with strain scenes = self.__pool.map(shear2D,zip(self.__scenes,st,self.__nsOfDE_int,repeat(dynRelax))) # return homogenized stress s = self.__pool.map(getStress2D,scenes) for i in xrange(self.__numGaussPoints): stress.setValueOfDataPoint(i,s[i]) return stress,scenes #~ def applyDisplIncrement_getTractionDEM(self,DEdu=escript.Data()): #~ """ #~ apply displacement increment to the external DE domain, #~ and get boundary traction from DE interface nodes #~ """ #~ FENbc, sceneExt = self.__pool.apply( \ #~ moveInterface_getTraction2D,(self.__sceneExt,self.__conf,DEdu, \ #~ self.__mIds,self.__FEDENodeMap,self.__nsOfDE_ext)) #~ Nbc=escript.Vector(0,escript.Solution(self.getDomain())) #~ for FEid in self.__FEDENodeMap.keys(): #~ Nbc.setValueOfDataPoint(FEid,FENbc[FEid]) #~ return Nbc, sceneExt def applyDisplIncrement_getForceDEM(self,DEdu=escript.Data(),dynRelax=False): """ apply displacement increment to the external DE domain, and get boundary force from DE interface nodes """ arFEfAndSceneExt = self.__pool.apply_async( \ moveInterface_getForce2D,(self.__sceneExt,self.__conf,DEdu,dynRelax, \ self.__mIds,self.__FEDENodeMap,self.__nsOfDE_ext)) return arFEfAndSceneExt def getBoundaryDisplacement(self,du): """ get a dictionary contains DE interface node ids and displacement increment """ # exchange FE-node ids (keys) with DE-node ids (values) DEdu = dict((v,k) for k,v in self.__FEDENodeMap.iteritems()) for key in DEdu.keys(): FEid = DEdu[key] DEdu[key] = du.getTupleForDataPoint(FEid) return DEdu def VTKExporter(self,vtkDir='./',t=0): """ export interactions in all DE scenes using vtk format """ # export interactions in RVEs #~ self.__pool.map(exportInt,zip(self.__scenes,repeat(vtkDir),repeat(t))) # export tensile forces in membrane self.__pool.apply(exportExt,(self.__sceneExt,self.__mIds,vtkDir,t)) def getPDE(self): """ return partial differential equation """ return self.__pde def getSceneExt(self): """ return scene of exterior DE domain, if any """ return self.__sceneExt def getNbc(self): """ return Neumann boundary condition converted from exterior DE domain """ if self.__FEDENodeMap: Nbc = self.__Nbc else: Nbc = self.__pde.getCoefficient("y") return Nbc def getFEf(self): """ return boundary forces converted from exterior DE domain """ if self.__FEDENodeMap: FEf = self.__FEf else: raise RuntimeError,"No exterior DE domain!" return FEf def getNsOfDE_int(self): """ return a list of numbers of interior DE simulations per FE domain simulation """ return self.__nsOfDE_int def getNsOfDE_ext(self): """ return number of exterior DE simulations per FE domain simulation """ return self.__nsOfDE_ext def getMaxEigenvalue(self): """ return the max eigenvalue of the model type: float """ dom = self.getDomain() dim = dom.getDim() pdeKu_P = LinearPDE(dom,numEquations=dim,numSolutions=dim) T = self.getCurrentTangent() pdeKu_P.setValue(A=T) pdeKu_P.getOperator().saveMM('tempMTX.mtx') mtx = mmread('tempMTX.mtx') maxEigVal = max(eigs(mtx,k=1,return_eigenvectors=False,which='LR')) return maxEigVal.real def getBoundaryNodesPositions(self,tag_name ="bound"): """ get a dictionary contains FE boundary node IDs and corresponding positions use data on "Solution" FunctionSpace to export FE node IDs (DataPoint IDs) note that though "ContinousFunction" and "Solution" FunctionSpace have save number of DataPoints, their numbering order are not the same!!! Therefore, always use coordiates and IDs of DataPoints on "Solution" for data communication """ tag = self.getDomain().getTag(tag_name) # get "Solution" FunctinonSpace fs = escript.Solution(self.getDomain()) # get coordinates with "Solution" FunctionSpace numbering order # fs and fs.getX().getFunctionSpace() are the same x = fs.getX() # get domain FunctionSpace, note below is different from fs.getX().getFunctionSpace() domFS = fs.getDomain().getX().getFunctionSpace() num = x.getNumberOfDataPoints() pos = {} for i in xrange(num): refId = fs.getReferenceIDFromDataPointNo(i) # domain FunctionSpace DataPoint IDs = RefId-1 if domFS.getTagFromDataPointNo(refId-1) == tag: pos[i] = x.getTupleForDataPoint(i) return pos def getBoundaryDataPointIDsAndRefIDs(self): """ get a dictionary contains data point IDs and reference IDs on BoundaryOnFunction numbering order of reference IDs and interface elements need to be consistent """ # get "FunctionOnBoundary" FunctionSpace bfs = escript.FunctionOnBoundary(self.getDomain()) # convert discrete reference IDs to continous numbers num = bfs.getX().getNumberOfDataPoints() FEDEBoundMap = {}; n = 0 for i in xrange(num): refID = bfs.getReferenceIDFromDataPointNo(i) if n != refID: newID = 2*(refID-1) else: newID = 2*(refID-1)+1 # save DataPoint IDs in keys and converted newIDs in values n = refID; FEDEBoundMap[i] = newID return FEDEBoundMap """