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 createLevelSetFunction(self, *props): """ returns an instance of an object used to represent a level set function initialized with zeros. Components can be overwritten by physical properties `props`. If present entries must correspond to the `mappings` arguments in the constructor. Use ``None`` for properties for which no value is given. """ m=self.regularization.getPDE().createSolution() if len(props) > 0: for i in range(self.numMappings): if props[i]: mp, idx=self.mappings[i] m2=mp.getInverse(props[i]) if idx: if len(idx) == 1: m[idx[0]]=m2 else: for k in range(idx): m[idx[k]]=m2[k] else: if isinstance(m2, Data): m=interpolate(m2, m.getFunctionSpace()) else: m=Data(m2, m.getFunctionSpace()) return m
def getDefect(self, rho, Hx, g_Hx): """ Returns the defect value. :param rho: a suggestion for resistivity :type rho: ``Data`` of shape () :param Hx: magnetic field :type Hx: ``Data`` of shape (2,) :param g_Hx: gradient of magnetic field :type g_Hx: ``Data`` of shape (2,2) :rtype: ``float`` """ x = g_Hx.getFunctionSpace().getX() Hx = escript.interpolate(Hx, x.getFunctionSpace()) u0 = Hx[0] u1 = Hx[1] u01 = g_Hx[0, 1] u11 = g_Hx[1, 1] scale = rho / (u0**2 + u1**2) Z = self._Z A = escript.integrate( self._weight * (Z[0]**2 + Z[1]**2 + scale * (-2 * Z[0] * (u0 * u01 + u1 * u11) + 2 * Z[1] * (u1 * u01 - u0 * u11) + rho * (u01**2 + u11**2)))) return A / 2
def getDefect(self, sigma, Ex, dExdz): """ Returns the defect value. :param sigma: a suggestion for conductivity :type sigma: ``Data`` of shape () :param Ex: electric field :type Ex: ``Data`` of shape (2,) :param dExdz: vertical derivative of electric field :type dExdz: ``Data`` of shape (2,) :rtype: ``float`` """ x = dExdz.getFunctionSpace().getX() Ex = escript.interpolate(Ex, x.getFunctionSpace()) u0 = Ex[0] u1 = Ex[1] u01 = dExdz[0] u11 = dExdz[1] scale = self._weight / (u01**2 + u11**2) Z = self._Z A = escript.integrate( scale * ((Z[0]**2 + Z[1]**2) * (u01**2 + u11**2) + 2 * Z[1] * (u0 * u11 - u01 * u1) - 2 * Z[0] * (u0 * u01 + u11 * u1) + u0**2 + u1**2)) return A / 2
def getGradient(self, sigma, Ex, dExdz): """ Returns the gradient of the defect with respect to density. :param sigma: a suggestion for conductivity :type sigma: ``Data`` of shape () :param Ex: electric field :type Ex: ``Data`` of shape (2,) :param dExdz: vertical derivative of electric field :type dExdz: ``Data`` of shape (2,) """ pde = self.setUpPDE() DIM = self.getDomain().getDim() x = dExdz.getFunctionSpace().getX() Ex = escript.interpolate(Ex, x.getFunctionSpace()) u0 = Ex[0] u1 = Ex[1] u01 = dExdz[0] u11 = dExdz[1] D = pde.getCoefficient('D') Y = pde.getCoefficient('Y') X = pde.getCoefficient('X') A = pde.getCoefficient('A') A[0, :, 0, :] = escript.kronecker(DIM) A[1, :, 1, :] = escript.kronecker(DIM) f = self._omega_mu * sigma D[0, 1] = f D[1, 0] = -f Z = self._Z scale = 1. / (u01**2 + u11**2) scale2 = scale**2 scale *= self._weight scale2 *= self._weight Y[0] = scale * (u0 - u01 * Z[0] + u11 * Z[1]) Y[1] = scale * (u1 - u01 * Z[1] - u11 * Z[0]) X[0,1] = scale2 * (2*u01*u11*(Z[0]*u1-Z[1]*u0) \ + (Z[0]*u0+Z[1]*u1)*(u01**2-u11**2) - u01*(u0**2 + u1**2)) X[1,1] = scale2 * (2*u01*u11*(Z[1]*u1+Z[0]*u0) \ + (Z[1]*u0-Z[0]*u1)*(u01**2-u11**2) - u11*(u0**2 + u1**2)) pde.setValue(A=A, D=D, X=X, Y=Y) Zstar = pde.getSolution() return (-self._omega_mu) * (Zstar[1] * u0 - Zstar[0] * u1)
def getGradient(self, sigma, u, uTar, uTai, uTu): """ Returns the gradient of the defect with respect to density. :param sigma: a suggestion for complex 1/V**2 :type sigma: ``escript.Data`` of shape (2,) :param u: a u vector :type u: ``escript.Data`` of shape (2,) :param uTar: equals `integrate( w * (data[0]*u[0]+data[1]*u[1]))` :type uTar: `float` :param uTai: equals `integrate( w * (data[1]*u[0]-data[0]*u[1]))` :type uTa: `float` :param uTu: equals `integrate( w * (u,u))` :type uTu: `float` """ pde = self.setUpPDE() if self.scaleF and abs(uTu) > 0: Z = ((uTar**2 + uTai**2) / uTu**2) * escript.interpolate( u, self.__data.getFunctionSpace()) Z[0] += (-uTar / uTu) * self.__data[0] + (-uTai / uTu) * self.__data[1] Z[1] += (-uTar / uTu) * self.__data[1] + uTai / uTu * self.__data[0] else: Z = u - self.__data if Z.getFunctionSpace() == escript.DiracDeltaFunctions( self.getDomain()): pde.setValue(y_dirac=self.__weight * Z) else: pde.setValue(y=self.__weight * Z) D = pde.getCoefficient('D') D[0, 0] = -self.__omega**2 * sigma[0] D[0, 1] = -self.__omega**2 * sigma[1] D[1, 0] = self.__omega**2 * sigma[1] D[1, 1] = -self.__omega**2 * sigma[0] pde.setValue(D=D) ZTo2 = pde.getSolution() * self.__omega**2 return escript.inner( ZTo2, u) * [1, 0] + (ZTo2[1] * u[0] - ZTo2[0] * u[1]) * [0, 1]
def __init__(self, domain, numLevelSets=1, w0=None, w1=None, wc=None, location_of_set_m=escript.Data(), useDiagonalHessianApproximation=False, tol=1e-8, coordinates=None, scale=None, scale_c=None): """ initialization. :param domain: domain :type domain: `Domain` :param numLevelSets: number of level sets :type numLevelSets: ``int`` :param w0: weighting factor for the m**2 term. If not set zero is assumed. :type w0: ``Scalar`` if ``numLevelSets`` == 1 or `Data` object of shape (``numLevelSets`` ,) if ``numLevelSets`` > 1 :param w1: weighting factor for the grad(m_i) terms. If not set zero is assumed :type w1: ``Vector`` if ``numLevelSets`` == 1 or `Data` object of shape (``numLevelSets`` , DIM) if ``numLevelSets`` > 1 :param wc: weighting factor for the cross gradient terms. If not set zero is assumed. Used for the case if ``numLevelSets`` > 1 only. Only values ``wc[l,k]`` in the lower triangle (l<k) are used. :type wc: `Data` object of shape (``numLevelSets`` , ``numLevelSets``) :param location_of_set_m: marks location of zero values of the level set function ``m`` by a positive entry. :type location_of_set_m: ``Scalar`` if ``numLevelSets`` == 1 or `Data` object of shape (``numLevelSets`` ,) if ``numLevelSets`` > 1 :param useDiagonalHessianApproximation: if True cross gradient terms between level set components are ignored when calculating approximations of the inverse of the Hessian Operator. This can speed-up the calculation of the inverse but may lead to an increase of the number of iteration steps in the inversion. :type useDiagonalHessianApproximation: ``bool`` :param tol: tolerance when solving the PDE for the inverse of the Hessian Operator :type tol: positive ``float`` :param coordinates: defines coordinate system to be used :type coordinates: ReferenceSystem` or `SpatialCoordinateTransformation` :param scale: weighting factor for level set function variation terms. If not set one is used. :type scale: ``Scalar`` if ``numLevelSets`` == 1 or `Data` object of shape (``numLevelSets`` ,) if ``numLevelSets`` > 1 :param scale_c: scale for the cross gradient terms. If not set one is assumed. Used for the case if ``numLevelSets`` > 1 only. Only values ``scale_c[l,k]`` in the lower triangle (l<k) are used. :type scale_c: `Data` object of shape (``numLevelSets``,``numLevelSets``) """ if w0 is None and w1 is None: raise ValueError("Values for w0 or for w1 must be given.") if wc is None and numLevelSets > 1: raise ValueError("Values for wc must be given.") self.__pre_input = None self.__pre_args = None self.logger = logging.getLogger('inv.%s' % self.__class__.__name__) self.__domain = domain DIM = self.__domain.getDim() self.__numLevelSets = numLevelSets self.__trafo = makeTransformation(domain, coordinates) self.__pde = linearPDEs.LinearPDE(self.__domain, numEquations=self.__numLevelSets, numSolutions=self.__numLevelSets) self.__pde.getSolverOptions().setTolerance(tol) self.__pde.setSymmetryOn() self.__pde.setValue( A=self.__pde.createCoefficient('A'), D=self.__pde.createCoefficient('D'), ) try: self.__pde.setValue(q=location_of_set_m) except linearPDEs.IllegalCoefficientValue: raise ValueError( "Unable to set location of fixed level set function.") # =========== check the shape of the scales: ======================== if scale is None: if numLevelSets == 1: scale = 1. else: scale = np.ones((numLevelSets, )) else: scale = np.asarray(scale) if numLevelSets == 1: if scale.shape == (): if not scale > 0: raise ValueError("Value for scale must be positive.") else: raise ValueError("Unexpected shape %s for scale." % scale.shape) else: if scale.shape is (numLevelSets, ): if not min(scale) > 0: raise ValueError( "All values for scale must be positive.") else: raise ValueError("Unexpected shape %s for scale." % scale.shape) if scale_c is None or numLevelSets < 2: scale_c = np.ones((numLevelSets, numLevelSets)) else: scale_c = np.asarray(scale_c) if scale_c.shape == (numLevelSets, numLevelSets): if not all([[scale_c[l, k] > 0. for l in range(k)] for k in range(1, numLevelSets)]): raise ValueError( "All values in the lower triangle of scale_c must be positive." ) else: raise ValueError("Unexpected shape %s for scale." % scale_c.shape) # ===== check the shape of the weights: ============================= if w0 is not None: w0 = escript.interpolate( w0, self.__pde.getFunctionSpaceForCoefficient('D')) s0 = w0.getShape() if numLevelSets == 1: if not s0 == (): raise ValueError("Unexpected shape %s for weight w0." % (s0, )) else: if not s0 == (numLevelSets, ): raise ValueError("Unexpected shape %s for weight w0." % (s0, )) if not self.__trafo.isCartesian(): w0 *= self.__trafo.getVolumeFactor() if not w1 is None: w1 = escript.interpolate( w1, self.__pde.getFunctionSpaceForCoefficient('A')) s1 = w1.getShape() if numLevelSets == 1: if not s1 == (DIM, ): raise ValueError("Unexpected shape %s for weight w1." % (s1, )) else: if not s1 == (numLevelSets, DIM): raise ValueError("Unexpected shape %s for weight w1." % (s1, )) if not self.__trafo.isCartesian(): f = self.__trafo.getScalingFactors( )**2 * self.__trafo.getVolumeFactor() if numLevelSets == 1: w1 *= f else: for i in range(numLevelSets): w1[i, :] *= f if numLevelSets == 1: wc = None else: wc = escript.interpolate( wc, self.__pde.getFunctionSpaceForCoefficient('A')) sc = wc.getShape() if not sc == (numLevelSets, numLevelSets): raise ValueError("Unexpected shape %s for weight wc." % (sc, )) if not self.__trafo.isCartesian(): raise ValueError( "Non-cartesian coordinates for cross-gradient term is not supported yet." ) # ============= now we rescale weights: ============================= L2s = np.asarray(escript.boundingBoxEdgeLengths(domain))**2 L4 = 1 / np.sum(1 / L2s)**2 if numLevelSets == 1: A = 0 if w0 is not None: A = escript.integrate(w0) if w1 is not None: A += escript.integrate(inner(w1, 1 / L2s)) if A > 0: f = scale / A if w0 is not None: w0 *= f if w1 is not None: w1 *= f else: raise ValueError("Non-positive weighting factor detected.") else: # numLevelSets > 1 for k in range(numLevelSets): A = 0 if w0 is not None: A = escript.integrate(w0[k]) if w1 is not None: A += escript.integrate(inner(w1[k, :], 1 / L2s)) if A > 0: f = scale[k] / A if w0 is not None: w0[k] *= f if w1 is not None: w1[k, :] *= f else: raise ValueError( "Non-positive weighting factor for level set component %d detected." % k) # and now the cross-gradient: if wc is not None: for l in range(k): A = escript.integrate(wc[l, k]) / L4 if A > 0: f = scale_c[l, k] / A wc[l, k] *= f # else: # raise ValueError("Non-positive weighting factor for cross-gradient level set components %d and %d detected."%(l,k)) self.__w0 = w0 self.__w1 = w1 self.__wc = wc self.__pde_is_set = False if self.__numLevelSets > 1: self.__useDiagonalHessianApproximation = useDiagonalHessianApproximation else: self.__useDiagonalHessianApproximation = True self._update_Hessian = True self.__num_tradeoff_factors = numLevelSets + ( (numLevelSets - 1) * numLevelSets) // 2 self.setTradeOffFactors() self.__vol_d = escript.vol(self.__domain)
def __init__( self, domain, numLevelSets=1, w0=None, w1=None, wc=None, location_of_set_m=Data(), useDiagonalHessianApproximation=False, tol=1e-8, coordinates=None, scale=None, scale_c=None, ): """ initialization. :param domain: domain :type domain: `Domain` :param numLevelSets: number of level sets :type numLevelSets: ``int`` :param w0: weighting factor for the m**2 term. If not set zero is assumed. :type w0: ``Scalar`` if ``numLevelSets`` == 1 or `Data` object of shape (``numLevelSets`` ,) if ``numLevelSets`` > 1 :param w1: weighting factor for the grad(m_i) terms. If not set zero is assumed :type w1: ``Vector`` if ``numLevelSets`` == 1 or `Data` object of shape (``numLevelSets`` , DIM) if ``numLevelSets`` > 1 :param wc: weighting factor for the cross gradient terms. If not set zero is assumed. Used for the case if ``numLevelSets`` > 1 only. Only values ``wc[l,k]`` in the lower triangle (l<k) are used. :type wc: `Data` object of shape (``numLevelSets`` , ``numLevelSets``) :param location_of_set_m: marks location of zero values of the level set function ``m`` by a positive entry. :type location_of_set_m: ``Scalar`` if ``numLevelSets`` == 1 or `Data` object of shape (``numLevelSets`` ,) if ``numLevelSets`` > 1 :param useDiagonalHessianApproximation: if True cross gradient terms between level set components are ignored when calculating approximations of the inverse of the Hessian Operator. This can speed-up the calculation of the inverse but may lead to an increase of the number of iteration steps in the inversion. :type useDiagonalHessianApproximation: ``bool`` :param tol: tolerance when solving the PDE for the inverse of the Hessian Operator :type tol: positive ``float`` :param coordinates: defines coordinate system to be used :type coordinates: ReferenceSystem` or `SpatialCoordinateTransformation` :param scale: weighting factor for level set function variation terms. If not set one is used. :type scale: ``Scalar`` if ``numLevelSets`` == 1 or `Data` object of shape (``numLevelSets`` ,) if ``numLevelSets`` > 1 :param scale_c: scale for the cross gradient terms. If not set one is assumed. Used for the case if ``numLevelSets`` > 1 only. Only values ``scale_c[l,k]`` in the lower triangle (l<k) are used. :type scale_c: `Data` object of shape (``numLevelSets``,``numLevelSets``) """ if w0 is None and w1 is None: raise ValueError("Values for w0 or for w1 must be given.") if wc is None and numLevelSets > 1: raise ValueError("Values for wc must be given.") self.__pre_input = None self.__pre_args = None self.logger = logging.getLogger("inv.%s" % self.__class__.__name__) self.__domain = domain DIM = self.__domain.getDim() self.__numLevelSets = numLevelSets self.__trafo = makeTransformation(domain, coordinates) self.__pde = LinearPDE(self.__domain, numEquations=self.__numLevelSets, numSolutions=self.__numLevelSets) self.__pde.getSolverOptions().setTolerance(tol) self.__pde.setSymmetryOn() self.__pde.setValue(A=self.__pde.createCoefficient("A"), D=self.__pde.createCoefficient("D")) try: self.__pde.setValue(q=location_of_set_m) except IllegalCoefficientValue: raise ValueError("Unable to set location of fixed level set function.") # =========== check the shape of the scales: ======================== if scale is None: if numLevelSets == 1: scale = 1.0 else: scale = np.ones((numLevelSets,)) else: scale = np.asarray(scale) if numLevelSets == 1: if scale.shape == (): if not scale > 0: raise ValueError("Value for scale must be positive.") else: raise ValueError("Unexpected shape %s for scale." % scale.shape) else: if scale.shape is (numLevelSets,): if not min(scale) > 0: raise ValueError("All values for scale must be positive.") else: raise ValueError("Unexpected shape %s for scale." % scale.shape) if scale_c is None or numLevelSets < 2: scale_c = np.ones((numLevelSets, numLevelSets)) else: scale_c = np.asarray(scale_c) if scale_c.shape == (numLevelSets, numLevelSets): if not all([[scale_c[l, k] > 0.0 for l in range(k)] for k in range(1, numLevelSets)]): raise ValueError("All values in the lower triangle of scale_c must be positive.") else: raise ValueError("Unexpected shape %s for scale." % scale_c.shape) # ===== check the shape of the weights: ============================= if w0 is not None: w0 = interpolate(w0, self.__pde.getFunctionSpaceForCoefficient("D")) s0 = w0.getShape() if numLevelSets == 1: if not s0 == (): raise ValueError("Unexpected shape %s for weight w0." % (s0,)) else: if not s0 == (numLevelSets,): raise ValueError("Unexpected shape %s for weight w0." % (s0,)) if not self.__trafo.isCartesian(): w0 *= self.__trafo.getVolumeFactor() if not w1 is None: w1 = interpolate(w1, self.__pde.getFunctionSpaceForCoefficient("A")) s1 = w1.getShape() if numLevelSets == 1: if not s1 == (DIM,): raise ValueError("Unexpected shape %s for weight w1." % (s1,)) else: if not s1 == (numLevelSets, DIM): raise ValueError("Unexpected shape %s for weight w1." % (s1,)) if not self.__trafo.isCartesian(): f = self.__trafo.getScalingFactors() ** 2 * self.__trafo.getVolumeFactor() if numLevelSets == 1: w1 *= f else: for i in range(numLevelSets): w1[i, :] *= f if numLevelSets == 1: wc = None else: wc = interpolate(wc, self.__pde.getFunctionSpaceForCoefficient("A")) sc = wc.getShape() if not sc == (numLevelSets, numLevelSets): raise ValueError("Unexpected shape %s for weight wc." % (sc,)) if not self.__trafo.isCartesian(): raise ValueError("Non-cartesian coordinates for cross-gradient term is not supported yet.") # ============= now we rescale weights: ============================= L2s = np.asarray(boundingBoxEdgeLengths(domain)) ** 2 L4 = 1 / np.sum(1 / L2s) ** 2 if numLevelSets == 1: A = 0 if w0 is not None: A = integrate(w0) if w1 is not None: A += integrate(inner(w1, 1 / L2s)) if A > 0: f = scale / A if w0 is not None: w0 *= f if w1 is not None: w1 *= f else: raise ValueError("Non-positive weighting factor detected.") else: # numLevelSets > 1 for k in range(numLevelSets): A = 0 if w0 is not None: A = integrate(w0[k]) if w1 is not None: A += integrate(inner(w1[k, :], 1 / L2s)) if A > 0: f = scale[k] / A if w0 is not None: w0[k] *= f if w1 is not None: w1[k, :] *= f else: raise ValueError("Non-positive weighting factor for level set component %d detected." % k) # and now the cross-gradient: if wc is not None: for l in range(k): A = integrate(wc[l, k]) / L4 if A > 0: f = scale_c[l, k] / A wc[l, k] *= f # else: # raise ValueError("Non-positive weighting factor for cross-gradient level set components %d and %d detected."%(l,k)) self.__w0 = w0 self.__w1 = w1 self.__wc = wc self.__pde_is_set = False if self.__numLevelSets > 1: self.__useDiagonalHessianApproximation = useDiagonalHessianApproximation else: self.__useDiagonalHessianApproximation = True self._update_Hessian = True self.__num_tradeoff_factors = numLevelSets + ((numLevelSets - 1) * numLevelSets) // 2 self.setTradeOffFactors() self.__vol_d = vol(self.__domain)
def __init__(self, domain, v_p, wavelet, source_tag, source_vector=[1., 0.], eps=0., delta=0., azimuth=0., dt=None, p0=None, v0=None, absorption_zone=300 * U.m, absorption_cut=1e-2, lumping=True): """ initialize the HTI wave solver :param domain: domain of the problem :type domain: `Doamin` :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 azimuth: azimuth (rotation around verticle axis) :param gamma: third Thompsen parameter :param rho: density :param dt: time step size. If not present a suitable time step size is calculated. :param p0: initial solution (Q(t=0), P(t=0)). 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. """ DIM = domain.getDim() f = createAbsorptionLayerFunction(v_p.getFunctionSpace().getX(), absorption_zone, absorption_cut) self.v2_p = v_p**2 self.v2_t = self.v2_p * escript.sqrt(1 + 2 * delta) self.v2_n = self.v2_p * (1 + 2 * eps) if p0 == None: p0 = escript.Data(0., (2, ), escript.Solution(domain)) else: p0 = escript.interpolate(p0, escript.Solution(domain)) if v0 == None: v0 = escript.Data(0., (2, ), escript.Solution(domain)) else: v0 = escript.interpolate(v0, escript.Solution(domain)) if dt == None: dt = min( min(escript.inf(domain.getSize() / escript.sqrt(self.v2_p)), escript.inf(domain.getSize() / escript.sqrt(self.v2_t)), escript.inf(domain.getSize() / escript.sqrt(self.v2_n))), wavelet.getTimeScale()) * 0.2 super(SonicHTIWave, self).__init__(dt, u0=p0, 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=escript.kronecker(2), 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)
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, v_p, v_s, wavelet, source_tag, source_vector=[1., 0., 0.], 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 """ DIM = domain.getDim() self.fastAssembler = hasattr( domain, "createAssembler") and not disable_fast_assemblers f = createAbsorptionLayerFunction(v_p.getFunctionSpace().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(HTIWave, 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.c23 = self.c33 - 2 * self.c66 if self.fastAssembler: C = [("c11", self.c11), ("c23", self.c23), ("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, omega, w, data, F, coordinates=None, fixAtBottom=False, tol=1e-10, saveMemory=True, scaleF=True): """ initializes a new forward model with acoustic wave form inversion. :param domain: domain of the model :type domain: `Domain` :param w: weighting factors :type w: ``Scalar`` :param data: real and imaginary part of data :type data: ``escript.Data`` of shape (2,) :param F: real and imaginary part of source given at Dirac points, on surface or at volume. :type F: ``escript.Data`` of shape (2,) :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 PDE to minimize memory requests. This will require more compute time as the matrix needs to be reallocated. :type saveMemory: ``bool`` :param scaleF: if true source F is scaled to minimize defect. :type scaleF: ``bool`` :param fixAtBottom: if true pressure is fixed to zero at the bottom of the domain :type fixAtBottom: ``bool`` """ super(AcousticWaveForm, self).__init__() self.__trafo = edc.makeTransformation(domain, coordinates) if not self.getCoordinateTransformation().isCartesian(): raise ValueError( "Non-Cartesian Coordinates are not supported yet.") if not isinstance(data, escript.Data): raise ValueError("data must be an escript.Data object.") if not data.getFunctionSpace() == escript.FunctionOnBoundary(domain): raise ValueError("data must be defined on boundary") if not data.getShape() == (2, ): raise ValueError( "data must have shape (2,) (real and imaginary part).") if w is None: w = 1. if not isinstance(w, escript.Data): w = escript.Data(w, escript.FunctionOnBoundary(domain)) else: if not w.getFunctionSpace() == escript.FunctionOnBoundary(domain): raise ValueError("Weights must be defined on boundary.") if not w.getShape() == (): raise ValueError("Weights must be scalar.") self.__domain = domain self.__omega = omega self.__weight = w self.__data = data self.scaleF = scaleF if scaleF: A = escript.integrate(self.__weight * escript.length(self.__data)**2) if A > 0: self.__data *= 1. / escript.sqrt(A) self.__BX = escript.boundingBox(domain) self.edge_lengths = np.asarray(escript.boundingBoxEdgeLengths(domain)) if not isinstance(F, escript.Data): F = escript.interpolate(F, escript.DiracDeltaFunctions(domain)) if not F.getShape() == (2, ): raise ValueError( "Source must have shape (2,) (real and imaginary part).") self.__F = escript.Data() self.__f = escript.Data() self.__f_dirac = escript.Data() if F.getFunctionSpace() == escript.DiracDeltaFunctions(domain): self.__f_dirac = F elif F.getFunctionSpace() == escript.FunctionOnBoundary(domain): self.__f = F else: self.__F = F self.__tol = tol self.__fixAtBottom = fixAtBottom self.__pde = None if not saveMemory: self.__pde = self.setUpPDE()
def RegionalCalculation(reg_mask): """ Calculates the "regional" from the entire FEILDS model excluding the selected region and outputs gravity at the specified altitude... see above for the "residual" """ # read in a gravity data grid to define data computation space G_DATA = os.path.join(DATADIR,'Final_BouguerTC_UC15K_qrtdeg.nc') FS=ReducedFunction(dom) nValues=[NX, NY, 1] first = [0, 0, cell_at_altitude] multiplier = [1, 1, 1] reverse = [0, 0, 0] byteorder = BYTEORDER_NATIVE gdata = readBinaryGrid(G_DATA, FS, shape=(), fill=-999999, byteOrder=byteorder, dataType=DATATYPE_FLOAT32, first=first, numValues=nValues, multiplier=multiplier, reverse=reverse) print("Grid successfully read") # get the masking and units sorted out for the data-space g_mask = whereNonZero(gdata+999999) gdata=gdata*g_mask * GRAV_UNITS # if people choose to have air in their region we exclude it from the # specified gravity calculation region if h_top < 0.: reg_mask = reg_mask+mask_air live_model = initial_model* whereNonPositive(reg_mask) dead_model = initial_model* wherePositive(reg_mask) if UseMean is True: # calculate the mean density within the selected region BackgroundDensity = integrate(dead_model)/integrate(wherePositive(reg_mask)) print("Density mean for selected region equals = %s"%BackgroundDensity) live_model = live_model + BackgroundDensity * wherePositive(reg_mask) # create mapping rho_mapping = DensityMapping(dom, rho0=live_model) # invert sign of gravity field to account for escript's coordinate system gdata = -GRAV_UNITS * gdata # turn the scalars into vectors (vertical direction) d=kronecker(DIM)[DIM-1] w=safeDiv(1., g_mask) gravity_model=GravityModel(dom, w*d, gdata*d, fixPotentialAtBottom=False, coordinates=COORDINATES) gravity_model.rescaleWeights(rho_scale=rho_mapping.getTypicalDerivative()) phi,_ = gravity_model.getArguments(live_model) g_init = -gravity_model.getCoordinateTransformation().getGradient(phi) g_init = interpolate(g_init, gdata.getFunctionSpace()) print("Computed gravity: %s"%(g_init[2])) fn=os.path.join(OUTPUTDIR,'regional-gravity') if SiloOutput is True: saveSilo(fn, density=live_model, gravity_init=g_init, g_initz=-g_init[2], gravitymask=g_mask, modelmask=reg_mask) print('SILO file written with the following fields: density (kg/m^3), gravity vector (m/s^2), gz (m/s^2), gravitymask, modelmask') # to compare calculated data against input dataset. # Not used by default but should work if the input dataset is correct #gslice = g_init[2]*wherePositive(g_mask) #g_dash = integrate(gslice)/integrate(wherePositive(g_mask)) #gdataslice = gdata*wherePositive(g_mask) #gdata_dash = integrate(gdataslice)/integrate(wherePositive(g_mask)) #misfit=(gdataslice-gdata_dash)-(gslice-g_dash) saveDataCSV(fn+".csv", mask=g_mask, gz=-g_init[2], Long=datacoords[0], Lat=datacoords[1], h=datacoords[2]) print('CSV file written with the following fields: Longitude (degrees) Latitude (degrees), h (100km), gz (m/s^2)')
def getGradient(self, rho, Hx, g_Hx): """ Returns the gradient of the defect with respect to resistivity. :param rho: a suggestion for resistivity :type rho: ``Data`` of shape () :param Hx: magnetic field :type Hx: ``Data`` of shape (2,) :param g_Hx: gradient of magnetic field :type g_Hx: ``Data`` of shape (2,2) """ pde = self.setUpPDE() DIM = self.getDomain().getDim() x = g_Hx.getFunctionSpace().getX() Hx = escript.interpolate(Hx, x.getFunctionSpace()) u0 = Hx[0] u1 = Hx[1] u00 = g_Hx[0, 0] u10 = g_Hx[1, 0] u01 = g_Hx[0, 1] u11 = g_Hx[1, 1] A = pde.getCoefficient('A') D = pde.getCoefficient('D') Y = pde.getCoefficient('Y') X = pde.getCoefficient('X') for i in range(DIM): A[0, i, 0, i] = rho A[1, i, 1, i] = rho f = self._omega_mu D[0, 1] = f D[1, 0] = -f Z = self._Z scale = 1. / (u0**2 + u1**2) scale2 = scale**2 scale *= self._weight scale2 *= rho * self._weight rho_scale = rho * scale gscale = u01**2 + u11**2 Y[0] = scale2 * ((Z[0] * u01 + Z[1] * u11) * (u0**2 - u1**2) + 2 * u0 * u1 * (Z[0] * u11 - Z[1] * u01) - rho * u0 * gscale) Y[1] = scale2 * ((Z[0] * u11 - Z[1] * u01) * (u1**2 - u0**2) + 2 * u0 * u1 * (Z[0] * u01 + Z[1] * u11) - rho * u1 * gscale) X[0, 1] = rho_scale * (-Z[0] * u0 + Z[1] * u1 + rho * u01) X[1, 1] = rho_scale * (-Z[0] * u1 - Z[1] * u0 + rho * u11) pde.setValue(A=A, D=D, X=X, Y=Y) g = escript.grad(pde.getSolution()) Hstarr_x = g[0, 0] Hstari_x = g[1, 0] Hstarr_z = g[0, 1] Hstari_z = g[1, 1] return -scale*(u0*(Z[0]*u01+Z[1]*u11)+u1*(Z[0]*u11-Z[1]*u01)-rho*gscale)\ - Hstarr_x*u00 - Hstarr_z*u01 - Hstari_x*u10 - Hstari_z*u11