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 __init__(self, domain, pore0=0., perm=1.e-5, kf=2.2e9, dt=0.001, ng=1, useMPI=False, np=1, rtol=1.e-2): """ initialization of the problem, i.e. model constructor :param domain: type Domain, domain of the problem :param pore0: type float, initial pore pressure :param perm: type float, d^2/(150 mu_f) in KC equation :param kf: type float, bulk modulus of the fluid :param dt: type float, time step for calculation :param ng: type integer, number of Gauss points :param useMPI: type boolean, use MPI or not :param np: type integer, number of processors :param rtol: type float, relevative tolerance for global convergence """ self.__domain = domain self.__upde = LinearPDE(domain, numEquations=domain.getDim(), numSolutions=domain.getDim()) self.__ppde = LinearPDE(domain, numEquations=1, numSolutions=1) # use reduced interpolation for pore pressure self.__ppde.setReducedOrderOn() self.__upde.getSolverOptions().setSolverMethod(SolverOptions.DIRECT) self.__ppde.getSolverOptions().setSolverMethod(SolverOptions.DIRECT) self.__upde.setSymmetryOn() self.__ppde.setSymmetryOn() self.__dt = dt self.__bulkFluid = kf self.__numGaussPoints = ng self.__rtol = rtol self.__stress = escript.Tensor(0, escript.Function(domain)) self.__S = escript.Tensor4(0, escript.Function(domain)) self.__pool = get_pool(mpi=useMPI, threads=np) self.__scenes = self.__pool.map(initLoad, range(ng)) st = self.__pool.map(getStressAndTangent2D, self.__scenes) for i in xrange(ng): self.__stress.setValueOfDataPoint(i, st[i][0]) self.__S.setValueOfDataPoint(i, st[i][1]) self.__strain = escript.Tensor(0, escript.Function(domain)) self.__pore = escript.Scalar(pore0, escript.ReducedSolution(domain)) self.__pgauss = util.interpolate(pore0, escript.Function(domain)) self.__permeability = perm self.__meanStressRate = escript.Scalar(0, escript.Function(domain)) self.__r = escript.Vector( 0, escript.Solution(domain)) #Dirichlet BC for u
def __tagDomain(self, domain, X, tags, rho, maps): """ DESCRIPTION: ----------- Defines the conductivity model. Conductivities of tagged regions can be mapped via user-defined functions passed in 'maps'. If no user-defined functions are passed, a constant value is applied as provided in list 'rho' for each region. User-defined functions have 3 arguments: x-coordinate, z-coordinate, resistivity. ARGUMENTS: ---------- domain :: escript object of mesh X :: escript object with all coordinates tags :: list with domain tags rho :: list with domain resistivities maps :: list with user-defined resistivity mappings RETURNS: -------- sigma :: escript object of conductivity model """ # Setup the conductivity structure (acts on elements and can be discontinuous). sigma = escript.Scalar(0, escript.Function(domain)) # Setup conductivity domains. for i in range(len(tags)): # Default: assign conductivity which is the inverse of resistivity: m = 1.0 / rho[i] # Map a user-defined conductivity distribution if given: if maps is not None: # Guard against undefined elements: if maps[i] is not None: # Map the conductivity according to the defined functions: m = maps[i](X[0], X[1], rho[i]) # Tag the mesh with the conductivity distributions at each iteration: sigma += m * escript.insertTaggedValues( escript.Scalar(0, escript.Function(domain)), **{tags[i]: 1}) if self._debug == True: sigma.expand() mydir = os.getcwd() dbgfl = mydir + os.sep + "mt2d_sigma_dbg.silo" print("") print("DEBUG: writing SILO debug output of conductivity model:") print(dbgfl) print("") weipa.saveSilo(dbgfl, sigma=sigma) # All done: return sigma
def applyStrain_getStressTangentDEM(self, st=escript.Data()): st = st.toListOfTuples() st = numpy.array(st).reshape(-1, 9) stress = escript.Tensor(0, escript.Function(self.__domain)) S = escript.Tensor4(0, escript.Function(self.__domain)) scenes = self.__pool.map(shear, zip(self.__scenes, st)) st = self.__pool.map(getStressAndTangent, scenes) for i in xrange(self.__numGaussPoints): stress.setValueOfDataPoint(i, st[i][0]) S.setValueOfDataPoint(i, st[i][1]) return stress, S, scenes
def __init__(self, domain, ng=1, useMPI=False, np=1, random=False, rtol=1.e-2, usePert=False, pert=-2.e-6, verbose=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 random: type boolean, if or not use random density field :param rtol: type float, relevative tolerance for global convergence :param usePert: type boolean, if or not use perturbation method :param pert: type float, perturbated strain applied to DEM to obtain tangent operator :param verbose: type boolean, if or not print messages during calculation """ self.__domain = domain self.__pde = LinearPDE(domain, numEquations=self.__domain.getDim(), numSolutions=self.__domain.getDim()) self.__pde.getSolverOptions().setSolverMethod(SolverOptions.DIRECT) self.__pde.setSymmetryOn() #self.__pde.getSolverOptions().setTolerance(rtol**2) #self.__pde.getSolverOptions().setPackage(SolverOptions.UMFPACK) self.__numGaussPoints = ng self.__rtol = rtol self.__usepert = usePert self.__pert = pert self.__verbose = verbose 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.__S = escript.Tensor4(0, escript.Function(self.__domain)) if self.__usepert: s = self.__pool.map(getStressTensor, self.__scenes) t = self.__pool.map(getTangentOperator, zip(self.__scenes, repeat(pert))) for i in xrange(ng): self.__stress.setValueOfDataPoint(i, s[i]) self.__S.setValueOfDataPoint(i, t[i]) else: st = self.__pool.map(getStressAndTangent2D, self.__scenes) for i in xrange(ng): self.__stress.setValueOfDataPoint(i, st[i][0]) self.__S.setValueOfDataPoint(i, st[i][1])
def __init__(self, domain, ng=1, useMPI=False, np=1, random=False, rtol=1.e-2, verbose=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 random: type boolean, if or not use random density field :param rtol: type float, relevant tolerance for global convergence :param verbose: type boolean, if or not print messages during calculation """ self.__domain = domain self.__pde = LinearPDE(domain, numEquations=self.__domain.getDim(), numSolutions=self.__domain.getDim()) try: self.__pde.getSolverOptions().setSolverMethod(SolverOptions.DIRECT) except: #import time print( "=======================================================================" ) print( "For better performance compile python-escript with direct solver method" ) print( "=======================================================================" ) input("Press Enter to continue...") #time.sleep(5) self.__pde.setSymmetryOn() #self.__pde.getSolverOptions().setTolerance(rtol**2) #self.__pde.getSolverOptions().setPackage(SolverOptions.UMFPACK) self.__numGaussPoints = ng self.__rtol = rtol self.__verbose = verbose self.__pool = get_pool(mpi=useMPI, threads=np) self.__scenes = self.__pool.map(initLoad, list(range(ng))) self.__strain = escript.Tensor(0, escript.Function(self.__domain)) self.__stress = escript.Tensor(0, escript.Function(self.__domain)) self.__S = escript.Tensor4(0, escript.Function(self.__domain)) st = self.__pool.map(getStressAndTangent, self.__scenes) for i in range(ng): self.__stress.setValueOfDataPoint(i, st[i][0]) self.__S.setValueOfDataPoint(i, st[i][1])
def __init__(self, domain, reference=CartesianReferenceSystem()): """ set up the orthogonal coordinate transformation. :param domain: domain in the domain of the coordinate transformation :type domain: `esys.escript.AbstractDomain` :param reference: the reference system :type reference: `ReferenceSystem` """ self.__domain = domain self.__reference_system = reference self._volumefactor = esc.Scalar(1., esc.Function(domain)) self._scaling_factors = esc.Vector(1., esc.Function(domain))
def solve(self, globalIter=10, solidIter=50): """ solve the coupled PDE using fixed-stress split method, call solveSolid to get displacement """ rtol = self.__rtol x_safe = self.__domain.getX() k = util.kronecker(self.__domain) kdr = util.inner(k, util.tensor_mult(self.__S, k)) / 4. n = self.getEquivalentPorosity() perm = self.__permeability * n**3 / (1. - n)**2 * k kf = self.__bulkFluid dt = self.__dt self.__ppde.setValue(A=perm, D=(n / kf + 1. / kdr) / dt, Y=(n / kf + 1. / kdr) / dt * self.__pgauss - self.__meanStressRate / kdr) p_iter_old = self.__ppde.getSolution() p_iter_gauss = util.interpolate(p_iter_old, escript.Function(self.__domain)) u_old, D, sig, s, scene = self.solveSolid(p_iter_gauss=p_iter_gauss, iter_max=solidIter) converge = False iterate = 0 while (not converge) and (iterate < globalIter): iterate += 1 self.__ppde.setValue(Y=n / kf / dt * self.__pgauss + 1. / kdr / dt * p_iter_gauss - util.trace(D) / dt) p_iter = self.__ppde.getSolution() p_err = util.L2(p_iter - p_iter_old) / util.L2(p_iter) p_iter_old = p_iter p_iter_gauss = util.interpolate(p_iter, escript.Function(self.__domain)) u, D, sig, s, scene = self.solveSolid(p_iter_gauss=p_iter_gauss, iter_max=solidIter) u_err = util.L2(u - u_old) / util.L2(u) u_old = u converge = (u_err <= rtol and p_err <= rtol * .1) self.__meanStressRate = (util.trace(sig - self.__stress) / 2. - p_iter_gauss + self.__pgauss) / dt self.__pore = p_iter_old self.__pgauss = p_iter_gauss self.__domain.setX(x_safe + u_old) self.__strain += D self.__stress = sig self.__S = s self.__scenes = scene return u_old
def __init__(self, domain, v_p, wavelet, source_tag, dt=None, p0=None, p0_t=None, absorption_zone=300 * U.m, absorption_cut=1e-2, lumping=True): """ initialize the sonic wave solver :param domain: domain of the problem :type domain: `Domain` :param v_p: p-velocity field :type v_p: `escript.Scalar` :param wavelet: wavelet to describe the time evolution of source term :type wavelet: `Wavelet` :param source_tag: tag of the source location :type source_tag: 'str' or 'int' :param dt: time step size. If not present a suitable time step size is calculated. :param p0: initial solution. If not present zero is used. :param p0_t: initial solution change rate. If not present zero is used. :param absorption_zone: thickness of absorption zone :param absorption_cut: boundary value of absorption decay factor :param lumping: if True mass matrix lumping is being used. This is accelerates the computing but introduces some diffusion. """ f = createAbsorptionLayerFunction( escript.Function(domain).getX(), absorption_zone, absorption_cut) v_p = v_p * f if p0 == None: p0 = escript.Scalar(0., escript.Solution(domain)) else: p0 = escript.interpolate(p0, escript.Solution(domain)) if p0_t == None: p0_t = escript.Scalar(0., escript.Solution(domain)) else: p0_t = escript.interpolate(p0_t, escript.Solution(domain)) if dt == None: dt = min(escript.inf((1. / 5.) * domain.getSize() / v_p), wavelet.getTimeScale()) super(SonicWave, self).__init__(dt, u0=p0, v0=p0_t, t0=0.) self.__wavelet = wavelet self.__mypde = lpde.LinearSinglePDE(domain) if lumping: self.__mypde.getSolverOptions().setSolverMethod( lpde.SolverOptions.HRZ_LUMPING) self.__mypde.setSymmetryOn() self.__mypde.setValue(D=1. / v_p**2) self.__source_tag = source_tag self.__r = escript.Scalar( 0., escript.DiracDeltaFunctions(self.__mypde.getDomain()))
def __init__(self, domain, reference=WGS84ReferenceSystem()): """ set up the orthogonal coordinate transformation. :param domain: domain in the domain of the coordinate transformation :type domain: `esys.escript.AbstractDomain` :param reference: the reference system :type reference: `ReferenceSystem` """ DIM = domain.getDim() super(GeodeticCoordinateTransformation, self).__init__(domain, reference) a = reference.getSemiMajorAxis() f = reference.getFlattening() f_a = reference.getAngularUnit() f_h = reference.getHeightUnit() x = esc.Function(domain).getX() if DIM == 2: phi = 0. else: phi = x[1] * f_a h = x[DIM - 1] * f_h e = esc.sqrt(2 * f - f**2) N = a / esc.sqrt(1 - e**2 * esc.sin(phi)**2) M = (a * (1 - e**2)) / esc.sqrt(1 - e**2 * esc.sin(phi)**2)**3 v_phi = f_a * (M + h) v_lam = f_a * (N + h) * esc.cos(phi) v_h = f_h s = esc.Vector(1., esc.Function(domain)) if DIM == 2: v = v_phi * v_h s[0] = 1 / v_lam s[1] = 1 / v_h else: v = v_phi * v_lam * v_h s[0] = 1 / v_lam s[1] = 1 / v_phi s[2] = 1 / v_h self._volumefactor = v self._scaling_factors = s
def _getAcceleration(self, t, u): """ returns the acceleraton for time t and solution u at time t """ self.__r.setTaggedValue(self.__source_tag, self.__wavelet.getValue(t)) self.__mypde.setValue( X=-escript.grad(u, escript.Function(self.__mypde.getDomain())), y_dirac=self.__r) return self.__mypde.getSolution()
def applyStrain_getStressTangentDEM(self,st=escript.Data()): st = st.toListOfTuples() st = numpy.array(st).reshape(-1,4) #-1 means the num of rows if determined by column num 4(strain tensor of each GP has 4 values) stress = escript.Tensor(0,escript.Function(self.__domain)) S = escript.Tensor4(0,escript.Function(self.__domain)) scenes = self.__pool.map(shear2D,zip(self.__scenes,st)) #zip is from python; shear2D is the key part of DEM if self.__usepert: s = self.__pool.map(getStressTensor,scenes) t = self.__pool.map(getTangentOperator,zip(scenes,repeat(self.__pert))) for i in xrange(self.__numGaussPoints): stress.setValueOfDataPoint(i,s[i]) S.setValueOfDataPoint(i,t[i]) else: ST = self.__pool.map(getStressAndTangent2D,scenes) for i in xrange(self.__numGaussPoints): stress.setValueOfDataPoint(i,ST[i][0]) S.setValueOfDataPoint(i,ST[i][1]) return stress,S,scenes #stress is sigma. S means tangent operator. scenes??
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 applyStrain_getStressTangentDEM(self, st=escript.Data()): st = st.toListOfTuples() st = numpy.array(st).reshape(-1, 4) stress = escript.Tensor(0, escript.Function(self.__domain)) S = escript.Tensor4(0, escript.Function(self.__domain)) scenes = self.__pool.map(shear2D, list(zip(self.__scenes, st))) if self.__usepert: s = self.__pool.map(getStressTensor, scenes) t = self.__pool.map(getTangentOperator, list(zip(scenes, repeat(self.__pert)))) for i in range(self.__numGaussPoints): stress.setValueOfDataPoint(i, s[i]) S.setValueOfDataPoint(i, t[i]) else: ST = self.__pool.map(getStressAndTangent2D, scenes) for i in range(self.__numGaussPoints): stress.setValueOfDataPoint(i, ST[i][0]) S.setValueOfDataPoint(i, ST[i][1]) return stress, S, scenes
def __init__(self,domain,ng=1,np=1,random=False,rtol=1.e-2,usePert=False,pert=-2.e-6,verbose=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 np: type integer, number of processors :param random: type boolean, if or not use random density field :param rtol: type float, relevative tolerance for global convergence :param usePert: type boolean, if or not use perturbation method :param pert: type float, perturbated strain applied to DEM to obtain tangent operator :param verbose: type boolean, if or not print messages during calculation """ self.__domain=domain self.__pde=LinearPDE(domain,numEquations=self.__domain.getDim(),numSolutions=self.__domain.getDim()) self.__pde.getSolverOptions().setSolverMethod(SolverOptions.DIRECT) #self.__pde.getSolverOptions().setTolerance(rtol**2) #self.__pde.getSolverOptions().setPackage(SolverOptions.UMFPACK) self.__numGaussPoints=ng self.__rtol=rtol self.__usepert=usePert self.__pert=pert self.__verbose=verbose self.__pool=Pool(processes=np) self.__scenes=self.__pool.map(initLoad,range(ng))#where is initLoad???from simDEM.py,to load RVEs; map(function, iterable) self.__strain=escript.Tensor(0,escript.Function(self.__domain)) '''Tensor(value=0., what=FunctionSpace(), expanded=False) returns a Data object of shape (d,d) in the FunctionSpace what, where d is the spatial dimension of the Domain of what. Values are initialized with value, a double precision quantity(here is 0). If expanded is True the Data object is represented in expanded form. ''' self.__stress=escript.Tensor(0,escript.Function(self.__domain)) #Function(domain): returns the general FunctionSpace on the Domain domain. Data objects in this type of general FunctionSpace are defined over the whole geometric region defined by domain. self.__S=escript.Tensor4(0,escript.Function(self.__domain)) #Tensor4 is similar to Tensor, which returns a Data object of shape (d,d,d,d) #simDEM part if self.__usepert: #here usepert=false, so this is not invoked. s = self.__pool.map(getStressTensor,self.__scenes) #getstresstensor is defined in simDEM, but here it is not invoked. t = self.__pool.map(getTangentOperator,zip(self.__scenes,repeat(pert)))#to get initial D and sigma for i in xrange(ng): self.__stress.setValueOfDataPoint(i,s[i]) self.__S.setValueOfDataPoint(i,t[i]) else: st = self.__pool.map(getStressAndTangent2D,self.__scenes) for i in xrange(ng): self.__stress.setValueOfDataPoint(i,st[i][0]) self.__S.setValueOfDataPoint(i,st[i][1])
def getGradientAtPoint(self): """ returns the gradient of the cost function J with respect to m. :note: This implementation returns Y_k=dPsi/dm_k and X_kj=dPsi/dm_kj """ # Using cached values m = self.__pre_input grad_m = self.__pre_args mu = self.__mu mu_c = self.__mu_c DIM = self.getDomain().getDim() numLS = self.getNumLevelSets() grad_m = escript.grad(m, escript.Function(m.getDomain())) if self.__w0 is not None: Y = m * self.__w0 * mu else: if numLS == 1: Y = escript.Scalar(0, grad_m.getFunctionSpace()) else: Y = escript.Data(0, (numLS, ), grad_m.getFunctionSpace()) if self.__w1 is not None: if numLS == 1: X = grad_m * self.__w1 * mu else: X = grad_m * self.__w1 for k in range(numLS): X[k, :] *= mu[k] else: X = escript.Data(0, grad_m.getShape(), grad_m.getFunctionSpace()) # cross gradient terms: if numLS > 1: for k in range(numLS): grad_m_k = grad_m[k, :] l2_grad_m_k = escript.length(grad_m_k)**2 for l in range(k): grad_m_l = grad_m[l, :] l2_grad_m_l = escript.length(grad_m_l)**2 grad_m_lk = inner(grad_m_l, grad_m_k) f = mu_c[l, k] * self.__wc[l, k] X[l, :] += f * (l2_grad_m_k * grad_m_l - grad_m_lk * grad_m_k) X[k, :] += f * (l2_grad_m_l * grad_m_k - grad_m_lk * grad_m_l) return pdetools.ArithmeticTuple(Y, X)
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 getLocalAvgRotation(self): rot = escript.Vector(0, escript.Function(self.__domain)) r = self.__pool.map(avgRotation, self.__scenes) for i in xrange(self.__numGaussPoints): rot.setValueOfDataPoint(i, r[i]) return rot
def getLocalVoidRatio(self): void = escript.Scalar(0, escript.Function(self.__domain)) e = self.__pool.map(getVoidRatio, self.__scenes) for i in xrange(self.__numGaussPoints): void.setValueOfDataPoint(i, e[i]) return void
def getLocalDebondNum(self): num=escript.Scalar(0,escript.Function(self.__domain)) n = self.__pool.map(DebondNum,self.__scenes) for i in xrange(self.__numGaussPoints): num.setValueOfDataPoint(i,n[i]) return num
def getEquivalentPorosity(self): porosity=escript.Scalar(0,escript.Function(self.__domain)) p = self.__pool.map(getEquivalentPorosity,self.__scenes) for i in range(self.__numGaussPoints): porosity.setValueOfDataPoint(i,p[i]) return porosity
def getLocalFabric(self): fabric = escript.Tensor(0, escript.Function(self.__domain)) f = self.__pool.map(getFabric, self.__scenes) for i in xrange(self.__numGaussPoints): fabric.setValueOfDataPoint(i, f[i]) return fabric
def setup(self, domainbuilder, rho0=None, drho=None, rho_z0=None, rho_beta=None, k0=None, dk=None, k_z0=None, k_beta=None, w0=None, w1=None, w_gc=None, rho_at_depth=None, k_at_depth=None): """ Sets up the inversion from an instance ``domainbuilder`` of a `DomainBuilder`. Gravity and magnetic data attached to the ``domainbuilder`` are considered in the inversion. If magnetic data are given as scalar it is assumed that values are collected in direction of the background magnetic field. :param domainbuilder: Domain builder object with gravity source(s) :type domainbuilder: `DomainBuilder` :param rho0: reference density, see `DensityMapping`. If not specified, zero is used. :type rho0: ``float`` or `Scalar` :param drho: density scale, see `DensityMapping`. If not specified, 2750kg/m^3 is used. :type drho: ``float`` or `Scalar` :param rho_z0: reference depth for depth weighting for density, see `DensityMapping`. If not specified, zero is used. :type rho_z0: ``float`` or `Scalar` :param rho_beta: exponent for depth weighting for density, see `DensityMapping`. If not specified, zero is used. :type rho_beta: ``float`` or `Scalar` :param k0: reference susceptibility, see `SusceptibilityMapping`. If not specified, zero is used. :type k0: ``float`` or `Scalar` :param dk: susceptibility scale, see `SusceptibilityMapping`. If not specified, 2750kg/m^3 is used. :type dk: ``float`` or `Scalar` :param k_z0: reference depth for depth weighting for susceptibility, see `SusceptibilityMapping`. If not specified, zero is used. :type k_z0: ``float`` or `Scalar` :param k_beta: exponent for depth weighting for susceptibility, see `SusceptibilityMapping`. If not specified, zero is used. :type k_beta: ``float`` or `Scalar` :param w0: weighting factors for level set term regularization, see `Regularization`. If not set zero is assumed. :type w0: `es.Data` or ``ndarray`` of shape (2,) :param w1: weighting factor for the gradient term in the regularization see `Regularization`. If not set zero is assumed :type w1: `es.Data` or ``ndarray`` of shape (2,DIM) :param w_gc: weighting factor for the cross gradient term in the regularization, see `Regularization`. If not set one is assumed :type w_gc: `Scalar` or `float` :param k_at_depth: value for susceptibility at depth, see `DomainBuilder`. :type k_at_depth: ``float`` or ``None`` :param rho_at_depth: value for density at depth, see `DomainBuilder`. :type rho_at_depth: ``float`` or ``None`` """ self.logger.info('Retrieving domain...') dom = domainbuilder.getDomain() DIM = dom.getDim() trafo = makeTransformation(dom, domainbuilder.getReferenceSystem()) #======================== self.logger.info('Creating mappings ...') rho_mask = domainbuilder.getSetDensityMask() if rho_at_depth: rho2 = rho_mask * rho_at_depth + (1 - rho_mask) * rho0 elif rho0: rho2 = (1 - rho_mask) * rho0 else: rho2 = 0 k_mask = domainbuilder.getSetSusceptibilityMask() if k_at_depth: k2 = k_mask * k_at_depth + (1 - k_mask) * k0 elif k0: k2 = (1 - k_mask) * k0 else: k2 = 0 rho_mapping = DensityMapping(dom, rho0=rho2, drho=drho, z0=rho_z0, beta=rho_beta) rho_scale_mapping = rho_mapping.getTypicalDerivative() self.logger.debug("rho_scale_mapping = %s" % rho_scale_mapping) k_mapping = SusceptibilityMapping(dom, k0=k2, dk=dk, z0=k_z0, beta=k_beta) k_scale_mapping = k_mapping.getTypicalDerivative() self.logger.debug("k_scale_mapping = %s" % k_scale_mapping) #======================== self.logger.info("Setting up regularization...") if w1 is None: w1 = np.ones((2, DIM)) wc = es.Data(0., (2, 2), es.Function(dom)) if w_gc is None: wc[0, 1] = 1 else: wc[0, 1] = w_gc reg_mask = es.Data(0., (2, ), es.Solution(dom)) reg_mask[self.DENSITY] = rho_mask reg_mask[self.SUSCEPTIBILITY] = k_mask regularization=Regularization(dom, numLevelSets=2,\ w0=w0, w1=w1,wc=wc, location_of_set_m=reg_mask, coordinates=trafo) #==================================================================== self.logger.info("Retrieving gravity surveys...") surveys = domainbuilder.getGravitySurveys() g = [] w = [] for g_i, sigma_i in surveys: w_i = es.safeDiv(1., sigma_i) if g_i.getRank() == 0: g_i = g_i * es.kronecker(DIM)[DIM - 1] if w_i.getRank() == 0: w_i = w_i * es.kronecker(DIM)[DIM - 1] g.append(g_i) w.append(w_i) self.logger.debug("Added gravity survey:") self.logger.debug("g = %s" % g_i) self.logger.debug("sigma = %s" % sigma_i) self.logger.debug("w = %s" % w_i) self.logger.info("Setting up gravity model...") gravity_model = GravityModel( dom, w, g, fixPotentialAtBottom=self._fixGravityPotentialAtBottom, coordinates=trafo) gravity_model.rescaleWeights(rho_scale=rho_scale_mapping) #==================================================================== self.logger.info("Retrieving magnetic field surveys...") d_b = es.normalize(domainbuilder.getBackgroundMagneticFluxDensity()) surveys = domainbuilder.getMagneticSurveys() B = [] w = [] for B_i, sigma_i in surveys: w_i = es.safeDiv(1., sigma_i) if self.magnetic_intensity_data: if not B_i.getRank() == 0: B_i = es.length(B_i) if not w_i.getRank() == 0: w_i = length(w_i) else: if B_i.getRank() == 0: B_i = B_i * d_b if w_i.getRank() == 0: w_i = w_i * d_b B.append(B_i) w.append(w_i) self.logger.debug("Added magnetic survey:") self.logger.debug("B = %s" % B_i) self.logger.debug("sigma = %s" % sigma_i) self.logger.debug("w = %s" % w_i) self.logger.info("Setting up magnetic model...") if self.self_demagnetization: magnetic_model = SelfDemagnetizationModel( dom, w, B, domainbuilder.getBackgroundMagneticFluxDensity(), fixPotentialAtBottom=self._fixMagneticPotentialAtBottom, coordinates=trafo) else: if self.magnetic_intensity_data: magnetic_model = MagneticIntensityModel( dom, w, B, domainbuilder.getBackgroundMagneticFluxDensity(), fixPotentialAtBottom=self._fixMagneticPotentialAtBottom, coordinates=trafo) else: magnetic_model = MagneticModel( dom, w, B, domainbuilder.getBackgroundMagneticFluxDensity(), fixPotentialAtBottom=self._fixMagneticPotentialAtBottom, coordinates=trafo) magnetic_model.rescaleWeights(k_scale=k_scale_mapping) #==================================================================== self.logger.info("Setting cost function...") self.setCostFunction( InversionCostFunction(regularization, ((rho_mapping, self.DENSITY), (k_mapping, self.SUSCEPTIBILITY)), ((gravity_model, 0), (magnetic_model, 1))))
def __init__(self, domain, v_p, v_s, wavelet, source_tag, source_vector=[0., 0., 1.], eps=0., gamma=0., delta=0., rho=1., dt=None, u0=None, v0=None, absorption_zone=None, absorption_cut=1e-2, lumping=True, disable_fast_assemblers=False): """ initialize the VTI wave solver :param domain: domain of the problem :type domain: `Domain` :param v_p: vertical p-velocity field :type v_p: `escript.Scalar` :param v_s: vertical s-velocity field :type v_s: `escript.Scalar` :param wavelet: wavelet to describe the time evolution of source term :type wavelet: `Wavelet` :param source_tag: tag of the source location :type source_tag: 'str' or 'int' :param source_vector: source orientation vector :param eps: first Thompsen parameter :param delta: second Thompsen parameter :param gamma: third Thompsen parameter :param rho: density :param dt: time step size. If not present a suitable time step size is calculated. :param u0: initial solution. If not present zero is used. :param v0: initial solution change rate. If not present zero is used. :param absorption_zone: thickness of absorption zone :param absorption_cut: boundary value of absorption decay factor :param lumping: if True mass matrix lumping is being used. This is accelerates the computing but introduces some diffusion. :param disable_fast_assemblers: if True, forces use of slower and more general PDE assemblers :type disable_fast_assemblers: `boolean` """ DIM = domain.getDim() self.fastAssembler = hasattr( domain, "createAssembler") and not disable_fast_assemblers f = createAbsorptionLayerFunction( escript.Function(domain).getX(), absorption_zone, absorption_cut) f = escript.interpolate(f, escript.Function(domain)) v_p = v_p * f v_s = v_s * f if u0 == None: u0 = escript.Vector(0., escript.Solution(domain)) else: u0 = escript.interpolate(p0, escript.Solution(domain)) if v0 == None: v0 = escript.Vector(0., escript.Solution(domain)) else: v0 = escript.interpolate(v0, escript.Solution(domain)) if dt == None: dt = min((1. / 5.) * min(escript.inf(domain.getSize() / v_p), escript.inf(domain.getSize() / v_s)), wavelet.getTimeScale()) super(VTIWave, self).__init__(dt, u0=u0, v0=v0, t0=0.) self.__wavelet = wavelet self.c33 = v_p**2 * rho self.c44 = v_s**2 * rho self.c11 = (1 + 2 * eps) * self.c33 self.c66 = (1 + 2 * gamma) * self.c44 self.c13 = escript.sqrt(2 * self.c33 * (self.c33 - self.c44) * delta + (self.c33 - self.c44)**2) - self.c44 self.c12 = self.c11 - 2 * self.c66 if self.fastAssembler: C = [("c11", self.c11), ("c12", self.c12), ("c13", self.c13), ("c33", self.c33), ("c44", self.c44), ("c66", self.c66)] if "speckley" in domain.getDescription().lower(): C = [(n, escript.interpolate(d, escript.ReducedFunction(domain))) for n, d in C] self.__mypde = lpde.WavePDE(domain, C) else: self.__mypde = lpde.LinearPDESystem(domain) self.__mypde.setValue(X=self.__mypde.createCoefficient('X')) if lumping: self.__mypde.getSolverOptions().setSolverMethod( lpde.SolverOptions.HRZ_LUMPING) self.__mypde.setSymmetryOn() self.__mypde.setValue(D=rho * escript.kronecker(DIM)) self.__source_tag = source_tag if DIM == 2: source_vector = [source_vector[0], source_vector[2]] self.__r = escript.Vector( 0, escript.DiracDeltaFunctions(self.__mypde.getDomain())) self.__r.setTaggedValue(self.__source_tag, source_vector)
def __init__(self, domain, v_p, v_s, wavelet, source_tag, source_vector=[0., 1.], eps=0., delta=0., theta=0., rho=1., dt=None, u0=None, v0=None, absorption_zone=300 * U.m, absorption_cut=1e-2, lumping=True): """ initialize the TTI wave solver :param domain: domain of the problem :type domain: `Domain` :param v_p: vertical p-velocity field :type v_p: `escript.Scalar` :param v_s: vertical s-velocity field :type v_s: `escript.Scalar` :param wavelet: wavelet to describe the time evolution of source term :type wavelet: `Wavelet` :param source_tag: tag of the source location :type source_tag: 'str' or 'int' :param source_vector: source orientation vector :param eps: first Thompsen parameter :param delta: second Thompsen parameter :param theta: tilting (in Rad) :param rho: density :param dt: time step size. If not present a suitable time step size is calculated. :param u0: initial solution. If not present zero is used. :param v0: initial solution change rate. If not present zero is used. :param absorption_zone: thickness of absorption zone :param absorption_cut: boundary value of absorption decay factor :param lumping: if True mass matrix lumping is being used. This is accelerates the computing but introduces some diffusion. """ cos = escript.cos sin = escript.sin DIM = domain.getDim() if not DIM == 2: raise ValueError("Only 2D is supported.") f = createAbsorptionLayerFunction( escript.Function(domain).getX(), absorption_zone, absorption_cut) v_p = v_p * f v_s = v_s * f if u0 == None: u0 = escript.Vector(0., escript.Solution(domain)) else: u0 = escript.interpolate(p0, escript.Solution(domain)) if v0 == None: v0 = escript.Vector(0., escript.Solution(domain)) else: v0 = escript.interpolate(v0, escript.Solution(domain)) if dt == None: dt = min((1. / 5.) * min(escript.inf(domain.getSize() / v_p), escript.inf(domain.getSize() / v_s)), wavelet.getTimeScale()) super(TTIWave, self).__init__(dt, u0=u0, v0=v0, t0=0.) self.__wavelet = wavelet self.__mypde = lpde.LinearPDESystem(domain) if lumping: self.__mypde.getSolverOptions().setSolverMethod( lpde.SolverOptions.HRZ_LUMPING) self.__mypde.setSymmetryOn() self.__mypde.setValue(D=rho * escript.kronecker(DIM), X=self.__mypde.createCoefficient('X')) self.__source_tag = source_tag self.__r = escript.Vector( 0, escript.DiracDeltaFunctions(self.__mypde.getDomain())) self.__r.setTaggedValue(self.__source_tag, source_vector) c0_33 = v_p**2 * rho c0_66 = v_s**2 * rho c0_11 = (1 + 2 * eps) * c0_33 c0_13 = escript.sqrt(2 * c0_33 * (c0_33 - c0_66) * delta + (c0_33 - c0_66)**2) - c0_66 self.c11 = c0_11 * cos(theta)**4 - 2 * c0_13 * cos( theta)**4 + 2 * c0_13 * cos(theta)**2 + c0_33 * sin( theta)**4 - 4 * c0_66 * cos(theta)**4 + 4 * c0_66 * cos( theta)**2 self.c13 = -c0_11 * cos(theta)**4 + c0_11 * cos( theta)**2 + c0_13 * sin(theta)**4 + c0_13 * cos( theta)**4 - c0_33 * cos(theta)**4 + c0_33 * cos( theta)**2 + 4 * c0_66 * cos(theta)**4 - 4 * c0_66 * cos( theta)**2 self.c16 = (-2 * c0_11 * cos(theta)**2 - 4 * c0_13 * sin(theta)**2 + 2 * c0_13 + 2 * c0_33 * sin(theta)**2 - 8 * c0_66 * sin(theta)**2 + 4 * c0_66) * sin(theta) * cos(theta) / 2 self.c33 = c0_11 * sin(theta)**4 - 2 * c0_13 * cos( theta)**4 + 2 * c0_13 * cos(theta)**2 + c0_33 * cos( theta)**4 - 4 * c0_66 * cos(theta)**4 + 4 * c0_66 * cos( theta)**2 self.c36 = (2 * c0_11 * cos(theta)**2 - 2 * c0_11 + 4 * c0_13 * sin(theta)**2 - 2 * c0_13 + 2 * c0_33 * cos(theta)**2 + 8 * c0_66 * sin(theta)**2 - 4 * c0_66) * sin(theta) * cos(theta) / 2 self.c66 = -c0_11 * cos(theta)**4 + c0_11 * cos( theta)**2 + 2 * c0_13 * cos(theta)**4 - 2 * c0_13 * cos( theta)**2 - c0_33 * cos(theta)**4 + c0_33 * cos( theta)**2 + c0_66 * sin(theta)**4 + 3 * c0_66 * cos( theta)**4 - 2 * c0_66 * cos(theta)**2
def __init__(self, domain, omega, x, Z, eta=None, w0=1., mu=4 * math.pi * 1e-7, sigma0=0.01, airLayerLevel=None, fixAirLayer=False, coordinates=None, tol=1e-8, saveMemory=False, directSolver=True): """ initializes a new forward model. :param domain: domain of the model :type domain: `Domain` :param omega: frequency :type omega: positive ``float`` :param x: coordinates of measurements :type x: ``list`` of ``tuple`` with ``float`` :param Z: measured impedance (possibly scaled) :type Z: ``list`` of ``complex`` :param eta: spatial confidence radius :type eta: positive ``float`` or ``list`` of positive ``float`` :param w0: confidence factors for meassurements. :type w0: ``None`` or a list of positive ``float`` :param mu: permeability :type mu: ``float`` :param sigma0: background conductivity :type sigma0: ``float`` :param airLayerLevel: position of the air layer from to bottom of the domain. If not set the air layer starts at the top of the domain :type airLayerLevel: ``float`` or ``None`` :param fixAirLayer: fix air layer (TM mode) :type fixAirLayer: ``bool`` :param coordinates: defines coordinate system to be used (not supported yet) :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation` :param tol: tolerance of underlying PDE :type tol: positive ``float`` :param saveMemory: if true stiffness matrix is deleted after solution of the PDE to minimize memory use. This will require more compute time as the matrix needs to be reallocated at each iteration. :type saveMemory: ``bool`` :param directSolver: if true a direct solver (rather than an iterative solver) will be used to solve the PDE :type directSolver: ``bool`` """ super(MT2DBase, self).__init__() self.__trafo = coords.makeTransformation(domain, coordinates) if not self.getCoordinateTransformation().isCartesian(): raise ValueError( "Non-Cartesian coordinates are not supported yet.") if len(x) != len(Z): raise ValueError( "Number of data points and number of impedance values don't match." ) if eta is None: eta = escript.sup(domain.getSize()) * 0.45 if isinstance(eta, float) or isinstance(eta, int): eta = [float(eta)] * len(Z) elif not len(eta) == len(Z): raise ValueError( "Number of confidence radii and number of impedance values don't match." ) if isinstance(w0, float) or isinstance(w0, int): w0 = [float(w0)] * len(Z) elif not len(w0) == len(Z): raise ValueError( "Number of confidence factors and number of impedance values don't match." ) self.__domain = domain self._omega_mu = omega * mu self._ks = escript.sqrt(self._omega_mu * sigma0 / 2.) xx = escript.Function(domain).getX() totalS = 0 self._Z = [ escript.Scalar(0., escript.Function(domain)), escript.Scalar(0., escript.Function(domain)) ] self._weight = escript.Scalar(0., escript.Function(domain)) for s in range(len(Z)): chi = self.getWeightingFactor(xx, 1., x[s], eta[s]) f = escript.integrate(chi) if f < eta[s]**2 * 0.01: raise ValueError( "Zero weight (almost) for data point %s. Change eta or refine mesh." % (s, )) w02 = w0[s] / f totalS += w02 self._Z[0] += chi * Z[s].real self._Z[1] += chi * Z[s].imag self._weight += chi * w02 / (abs(Z[s])**2) if not totalS > 0: raise ValueError( "Scaling of weight factors failed as sum is zero.") DIM = domain.getDim() z = domain.getX()[DIM - 1] self._ztop = escript.sup(z) self._zbottom = escript.inf(z) if airLayerLevel is None: airLayerLevel = self._ztop self._airLayerLevel = airLayerLevel # botton: mask0 = escript.whereZero(z - self._zbottom) r = mask0 * [ escript.exp(self._ks * (self._zbottom - airLayerLevel)) * escript.cos(self._ks * (self._zbottom - airLayerLevel)), escript.exp(self._ks * (self._zbottom - airLayerLevel)) * escript.sin(self._ks * (self._zbottom - airLayerLevel)) ] #top: if fixAirLayer: mask1 = escript.whereNonNegative(z - airLayerLevel) r += mask1 * [1, 0] else: mask1 = escript.whereZero(z - self._ztop) r += mask1 * [ self._ks * (self._ztop - airLayerLevel) + 1, self._ks * (self._ztop - airLayerLevel) ] self._q = (mask0 + mask1) * [1, 1] self._r = r #==================================== self.__tol = tol self._directSolver = directSolver self._saveMemory = saveMemory self.__pde = None if not saveMemory: self.__pde = self.setUpPDE()