def __init__(self, f_dom=40, t_dom=None): """ Sets up a Ricker wavelet wih dominant frequence `f_dom` and center at time `t_dom`. If `t_dom` is not given an estimate for suitable `t_dom` is calculated so f(0)~0. :note: maximum frequence is about 2 x the dominant frequence. """ drop = 18 self.__f = f_dom self.__f_max = escript.sqrt(7) * f_dom self.__s = math.pi * self.__f if t_dom == None: t_dom = escript.sqrt(drop) / self.__s self.__t0 = t_dom
def rescaleWeights(self, scale=1., sigma_scale=1.): """ rescales the weights such that :math: integrate( ( w omega**2 * sigma_scale * data * ((1/L_j)**2)**-1) +1 )/(data*omega**2 * ((1/L_j)**2)**-1) * sigma_scale )=scale :param scale: scale of data weighting factors :type scale: positive ``float`` :param sigma_scale: scale of 1/vp**2 velocity. :type sigma_scale: ``Scalar`` """ raise Warning("rescaleWeights is not tested yet.") if not scale > 0: raise ValueError("Value for scale must be positive.") if not sigma_scale * omega**2 * d > 0: raise ValueError( "Rescaling of weights failed due to zero denominator.") # copy back original weights before rescaling #self.__weight=[1.*ow for ow in self.__origweight] L2 = 1 / escript.length(1 / self.edge_length)**2 d = Lsup(escript.length(data)) A = escript.integrate(self.__weight * (sigma_scale * omega**2 * d + 1) / (sigma_scale * omega**2 * d)) if A > 0: self.__weight *= 1. / A if self.scaleF: self.__data *= escript.sqrt(A) else: raise ValueError("Rescaling of weights failed.")
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 getNorm(self, m): """ returns the norm of ``m``. :param m: level set function :type m: `Data` :rtype: ``float`` """ return sqrt(integrate(length(m) ** 2) / self.__vol_d)
def getNorm(self, m): """ returns the norm of ``m``. :param m: level set function :type m: `Data` :rtype: ``float`` """ return sqrt(integrate(length(m)**2) / self.__vol_d)
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 __init__(self, V_prior, Q_prior): """ initializes the mapping :param V_prior: a-priori p-wave velocity :param Q_prior: a-priori Q-index (must be positive) """ over2Q = 1.0 / (2 * Q_prior) # sigma_prior=1/(V_prior*(1-I*over2Q))**2 = 1/( V_prior * (1+over2Q**2)) **2 * ( (1-over2Q**2) + I * 2* over2Q ) self.Mr = log(sqrt((1 - over2Q ** 2) ** 2 + (2 * over2Q) ** 2) / (V_prior * (1 + over2Q ** 2)) ** 2) self.Mi = atan2(2 * over2Q, 1 - over2Q ** 2)
def __init__(self, V_prior, Q_prior): """ initializes the mapping :param V_prior: a-priori p-wave velocity :param Q_prior: a-priori Q-index (must be positive) """ over2Q = 1. / (2 * Q_prior) # sigma_prior=1/(V_prior*(1-I*over2Q))**2 = 1/( V_prior * (1+over2Q**2)) **2 * ( (1-over2Q**2) + I * 2* over2Q ) self.Mr = log( sqrt((1 - over2Q**2)**2 + (2 * over2Q)**2) / (V_prior * (1 + over2Q**2))**2) self.Mi = atan2(2 * over2Q, 1 - over2Q**2)
def calculate_concentration(solute_mass, rho_f_0, gamma): """ Calculate solute concentration using total solute mass and a concentration-density function. :param solute_mass: :param rho_f_0: :param gamma: :return: """ # calculate new concentration, assuming no change in density: #concentration = u / rho_f a = rho_f_0 * gamma b = rho_f_0 c = -solute_mass d = b**2 - 4 * a * c concentration = (-b + es.sqrt(d)) / (2 * a) return concentration
def cubicinterpolate(alpha_lo, alpha_hi, old_alpha, old_phi, very_old_alpha, very_old_phi): if very_old_alpha is None: return quadinterpolate(alpha_lo, alpha_hi, old_alpha, old_phi) a0s, a1s = very_old_alpha * very_old_alpha, old_alpha * old_alpha denom = a0s * a1s * (old_alpha - very_old_alpha) if denom == 0: return quadinterpolate(alpha_lo, alpha_hi, old_alpha, old_phi) a0c, a1c = a0s * very_old_alpha, a1s * old_alpha tmpA = old_phi - phi0 - gphi0 * old_alpha tmpB = very_old_phi - phi0 - gphi0 * very_old_alpha a = (a0s * tmpA - a1s * tmpB) / denom b = (-a0c * tmpA + a1c * tmpB) / denom deter = b * b - 3.0 * a * gphi0 if deter < 0: return quadinterpolate(alpha_lo, alpha_hi, old_alpha, old_phi) alpha = (-b + sqrt(deter)) / (3.0 * a) if np.abs(alpha - old_alpha) < tol_df or np.abs( alpha) < tol_sm * np.abs(old_alpha): alpha = 0.5 * old_alpha if abs(alpha) < 1e-8: return quadinterpolate(alpha_lo, alpha_hi, old_alpha, old_phi) return alpha
def f4(x,z,r): return escript.sqrt(escript.sqrt(x*x+z*z))/r maps = [None, None, None, None, f4, None]
def f4(x, z, r): return escript.sqrt(escript.sqrt(x * x + z * z)) / r
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
from test_simplesolve import SimpleSolveTestCase import esys.escriptcore.utestselect as unittest from esys.escriptcore.testing import * from esys.escript import getMPISizeWorld, hasFeature, sqrt from esys.ripley import Rectangle, Brick from esys.escript.linearPDEs import SolverOptions HAVE_PASO = hasFeature('paso') # number of elements in the spatial directions NE0=12 NE1=12 NE2=8 mpiSize=getMPISizeWorld() for x in [int(sqrt(mpiSize)),2,3,5,7,1]: NX=x NY=mpiSize//x if NX*NY == mpiSize: break for x in [(int(mpiSize**(1/3.)),int(mpiSize**(1/3.))),(2,3),(2,2),(1,2),(1,1)]: NXb=x[0] NYb=x[1] NZb=mpiSize//(x[0]*x[1]) if NXb*NYb*NZb == mpiSize: break @unittest.skipIf(not HAVE_PASO, "PASO not available") class SimpleSolveOnPaso(SimpleSolveTestCase): pass
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 __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()
import esys.escriptcore.utestselect as unittest from esys.escriptcore.testing import * from esys.escript import getMPISizeWorld, hasFeature, sqrt from esys.ripley import Rectangle, Brick from esys.escript.linearPDEs import SolverOptions SOLVER = "mkl" HAVE_REQUESTED_SOLVER = hasFeature(SOLVER) # number of elements in the spatial directions NE0 = 12 NE1 = 12 NE2 = 8 mpiSize = getMPISizeWorld() for x in [int(sqrt(mpiSize)), 2, 3, 5, 7, 1]: NX = x NY = mpiSize // x if NX * NY == mpiSize: break for x in [(int(mpiSize**(1 / 3.)), int(mpiSize**(1 / 3.))), (2, 3), (2, 2), (1, 2), (1, 1)]: NXb = x[0] NYb = x[1] NZb = mpiSize // (x[0] * x[1]) if NXb * NYb * NZb == mpiSize: break @unittest.skipIf(not HAVE_REQUESTED_SOLVER, "%s not available" % SOLVER)
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)