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,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 getBoundaryNodesPositions(self, tag_name="bound"): """ get a dictionary contains FE boundary node IDs and corresponding positions use data on "Solution" FunctionSpace to export FE node IDs (DataPoint IDs) note that though "ContinousFunction" and "Solution" FunctionSpace have save number of DataPoints, their numbering order are not the same!!! Therefore, always use coordiates and IDs of DataPoints on "Solution" for data communication """ tag = self.getDomain().getTag(tag_name) # get "Solution" FunctinonSpace fs = escript.Solution(self.getDomain()) # get coordinates with "Solution" FunctionSpace numbering order # fs and fs.getX().getFunctionSpace() are the same x = fs.getX() # get domain FunctionSpace, note below is different from fs.getX().getFunctionSpace() domFS = fs.getDomain().getX().getFunctionSpace() num = x.getNumberOfDataPoints() pos = {} for i in xrange(num): refId = fs.getReferenceIDFromDataPointNo(i) # domain FunctionSpace DataPoint IDs = RefId-1 if domFS.getTagFromDataPointNo(refId - 1) == tag: pos[i] = x.getTupleForDataPoint(i) return pos
def __init__(self, domain, mode, freq_def, tags, rho, rho_1d, ifc_1d, xstep=100, zstep=100, maps=None, plot=False, limits=None): """ DESCRIPTION: ------------ Constructor which initialises the 2D magnetotelluric class: (*) check for argument type (*) check for valid argument values (*) initialises required values ARGUMENTS: ---------- param domain :: the 2d mesh domain type domain :: ``escript data object`` param mode :: TE or TM mode type mode :: ``string`` param freq_def :: highest/lowest frequency & points per decade type freq_def :: ``dictionary`` param tags :: the tag names of the regions defined in the mesh type tags :: ``list`` param rho :: the resistivity values of the regions in the mesh type rho :: ``list`` param rho_1d :: the resistivity values at the left & right boundary type rho_1d :: ``dictionary`` param ifc_1d :: the layer interface depths of the left & right boundary type ifc_1d :: ``dictionary`` param xstep :: user-defined step size for horizontal sample list type xstep :: ``number`` (optional) param zstep :: user-defined step size for vertical sample list type zstep :: ``number`` (optional) param maps :: list with user-defined functions which map the resistivity for each region type maps :: ``list`` (optional) param plot :: user-defined flag to show a plot of apparent resistivity and phase at each frequency type plot :: ``boolean`` (optional) DATA ATTRIBUTES: ---------------- self.domain :: escript data object of mesh self.X :: escript data object with all mesh coordinates self.mode :: string with TE or TM mode self.xmin :: float with x-coordinate minimum self.xmax :: float with x-coordinate maximum self.zmin :: float with z-coordinate minimum self.zmax :: float with z-coordinate maximum self.zstep :: number with sample step in vertical direction self.xstep :: number with sample step in horizontal direction self.rho :: list with resistivity values of all regions self.rho_1d :: dictionary with resistivity values at boundaries left/right self.ifc_1d :: dictionary with interface depths at boundaries left/right self.plot :: boolean flag to show plots of apparent resistivity and phase self.sigma :: escript data object with the conductivity model (based on 'rho' and 'maps') self.frequencies :: list of sounding frequencies self.boundary_mask :: Dirichlet mask at boundaries """ if not HAVE_FINLEY: raise ImportError("Finley module not available") #make python3 compatible, since long disappeared in python 3 if sys.version_info[0] == 3: long_type = int else: long_type = long # --- # Checks # --- # Types: if not isinstance(domain, escript.Domain): raise ValueError("Input parameter DOMAIN must be an Escript mesh") if not isinstance(mode, str): raise ValueError("Input parameter MODE must be a string") if not isinstance(freq_def, dict) or len(freq_def) != 3: raise ValueError( "Input parameter FREQ_DEF must be a dictionary with length 3") if not isinstance(tags, list) or not all( isinstance(t, str) for t in tags): raise ValueError("Input parameter TAGS must be a list of strings") if not isinstance(rho, list) or not all( isinstance(d, (int, long_type, float)) for d in rho): raise ValueError("Input parameter RHO must be a list of numbers") if not isinstance(rho_1d, dict) or len(rho_1d) != 2: raise ValueError( "Input parameter RHO_1D must be a dictionary with length 2") if not isinstance(ifc_1d, dict) or len(ifc_1d) != 2: raise ValueError( "Input parameter IFC_1D must be a dictionary with length 2") if not isinstance(xstep, (int, long_type, float)): raise ValueError("Optional input parameter XSTEP must be a number") if not isinstance(zstep, (int, long_type, float)): raise ValueError("Optional input parameter ZSTEP must be a number") if maps is not None: if not isinstance(maps, list) or not all( isinstance(m, (types.FunctionType, types.NoneType)) for m in maps): raise ValueError( "Optional input parameter MAPS must be a list of Functions or Nones" ) if plot is not None: if not isinstance(plot, bool): raise ValueError( "Optional input parameter PLOT must be True or False") # Values: if mode.upper() != "TE" and mode.upper() != "TM": # Check mode: raise ValueError( "Input parameter mode must be either 'TE' or 'TM'") if not 'high' in freq_def and not 'low' in freq_def and not 'step' in freq_def: raise ValueError( "Input dictionary FREQ_DEF must have keys 'high', 'low' and 'step' defined" ) if freq_def['high'] < freq_def['low']: raise ValueError( "High frequency value is smaller than low frequency value in input parameter FREQ_DEF" ) if freq_def['step'] < 1: raise ValueError( "Step frequency value is smaller than 1 in input parameter FREQ_DEF" ) if not all(r > 0 for r in rho): # Check resistivity values: raise ValueError("Input parameter RHO must be all positive") if len(rho) != len(tags): # Check resistivity list-length: raise ValueError( "Input parameter RHO must have the same length as input parameter TAGS" ) if not 'left' in rho_1d and not 'right' in rho_1d: raise ValueError( "Input dictionary RHO_1D must have keys 'left' and 'right' defined" ) if not 'left' in ifc_1d and not 'right' in ifc_1d: raise ValueError( "Input dictionary IFC_1D must have keys 'left' and 'right' defined" ) if len(ifc_1d['left']) - 1 != len(rho_1d['left']) and len( ifc_1d['right']) - 1 != len(rho_1d['right']): raise ValueError( "Lists with values in input dictionary RHO_1D must have length equal to IFC_1D" ) if xstep < 0.5: # Step size should be non-zero but should not be smaller than 0.5m: raise ValueError("Input parameter XSTEP must be at least 0.5") if zstep < 0.5: # Step size should be non-zero but should not be smaller than 0.5m: raise ValueError("Input parameter ZSTEP must be at least 0.5") # --- # Domain coordinates & tags: # --- # Extract the model coordinates.. X = escript.Solution(domain).getX() # Get the Min/Max coordinates: xmin = escript.inf(X[0]) xmax = escript.sup(X[0]) zmin = escript.inf(X[1]) zmax = escript.sup(X[1]) # Get the tag names from the mesh file mesh_tags = escript.getTagNames(domain) if xmin >= xmax or zmin >= zmax: raise ValueError("The mesh limits are not valid (min >= max)") if zmin >= 0: raise ValueError( "The mesh must be defined with a negative vertical axis") if not set(mesh_tags) == set(tags): print("user-tags:", tags) print("mesh-tags:", mesh_tags) raise ValueError( "Input parameter TAGS does not match the tags defined in the mesh" ) # --- # Define the boundary mask: # --- boundary_mask = self.__setBoundaryMask(X) # --- # Calculate list of sounding frequencies: # --- frequencies = self.__getSoundingFrequencies(freq_def) # --- # Tag the domain with conductivity maps: # --- sigma_model = self.__tagDomain(domain, X, tags, rho, maps) # Check for valid values if escript.inf(sigma_model) < 0 or escript.sup(sigma_model) < 0: raise ValueError("Negative conductivity encountered") if cmath.isnan( escript.inf(sigma_model) ) or \ cmath.isnan( escript.sup(sigma_model) ) or \ cmath.isinf( escript.sup(sigma_model) ): raise ValueError("The conductivity model contains NaNs or INFs") # --- # Projector and Locator objects. # --- print("Setting up Escript Locator and Projector objects...") # Setup a list with sample points along the vertical mesh extent, bottom to top: xsample = self.__getSamplePoints(escript.inf(X[0]), escript.sup(X[0]), xstep, constant=0.0) # Get the locations of mesh points at the surface via the Locator object # operating on the continuous function-space (i.e. nodes) of the domain. loc = pdetools.Locator(escript.ContinuousFunction(domain), xsample) # Instantiate the Projector class with smoothing on (fast=False); # the Projector is used to calculate the gradient correctly. proj = pdetools.Projector(domain, reduce=False, fast=False) # --- # Print information: # --- print("") print("=" * 72) print("Escript MT2D, version", self.__version) print("=" * 72) print("Mesh XMin/XMax : ", xmin, xmax) print("Mesh ZMin/ZMax : ", zmin, zmax) print("Number of Tags : ", len(tags)) print("Mapping : ", { True: 'Yes', False: 'No' }[maps is not None]) print("Conductivity Model : ", sigma_model) print("Nr of Frequencies : ", len(frequencies)) print("Start/End/Step (Hz) : ", freq_def["high"], freq_def["low"], freq_def["step"]) print("Mode : ", mode.upper()) print("Solver : ", MT_2D._solver) print("Show plots : ", plot) print("=" * 72) print("") if self._debug: print("Mesh-Info : ") print(domain.print_mesh_info(full=False)) # --- # Set all required variables as data attributes # --- self.domain = domain self.X = X self.mode = mode self.xmin = xmin self.xmax = xmax self.zmin = zmin self.zmax = zmax self.zstep = zstep self.xstep = xstep self.rho = rho self.rho_1d = rho_1d self.ifc_1d = ifc_1d self.plot = plot self.limits = limits self.sigma = sigma_model self.frequencies = frequencies self.boundary_mask = boundary_mask self.proj = proj self.loc = loc
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 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))))