def __init__(self, domain, z0=None, k0=None, dk=None, beta=None): """ set up mapping :param domain: domain of the mapping :type domain: ``Domain`` :param z0: depth weighting offset. If not present no depth scaling is applied. :type z0: scalar :param k0: reference density, defaults to 0 :type k0: scalar :param dk: susceptibility scale, defaults to 1 :type dk: scalar :param beta: depth weighting exponent, defaults to 2 :type beta: ``float`` """ if k0 is None: k0 = 0.0 if beta is None: beta = 2.0 if dk is None: dk = 1.0 self.domain = domain if z0 is not None: DIM = self.domain.getDim() l_z = boundingBoxEdgeLengths(domain)[DIM - 1] a = dk * (clip(z0 - domain.getX()[DIM - 1], minval=0) / l_z) ** (beta / 2) else: a = dk super(SusceptibilityMapping, self).__init__(a=a, p0=k0)
def __init__(self, domain, z0=None, rho0=None, drho=None, beta=None): """ initializes the mapping :param domain: domain of the mapping :type domain: ``Domain`` :param z0: depth weighting offset. If not present no depth scaling is applied. :type z0: scalar :param rho0: reference density, defaults to 0 :type rho0: scalar :param drho: density scale. By default density of granite = 2750kg/m**3 is used. :type drho: scalar :param beta: depth weighting exponent, defaults to 2 :type beta: ``float`` """ if rho0 is None: rho0 = 0.0 if drho is None: drho = 2750 * U.kg / U.m ** 3 if beta is None: beta = 2.0 self.domain = domain if z0 is not None: DIM = self.domain.getDim() l_z = boundingBoxEdgeLengths(domain)[DIM - 1] a = drho * (clip(z0 - domain.getX()[DIM - 1], minval=0) / l_z) ** (beta / 2) else: a = drho super(DensityMapping, self).__init__(a=a, p0=rho0)
def __init__(self, domain, z0=None, k0=None, dk=None, beta=None): """ set up mapping :param domain: domain of the mapping :type domain: ``Domain`` :param z0: depth weighting offset. If not present no depth scaling is applied. :type z0: scalar :param k0: reference density, defaults to 0 :type k0: scalar :param dk: susceptibility scale, defaults to 1 :type dk: scalar :param beta: depth weighting exponent, defaults to 2 :type beta: ``float`` """ if k0 is None: k0 = 0. if beta is None: beta = 2. if dk is None: dk = 1. self.domain = domain if z0 is not None: DIM = self.domain.getDim() l_z = boundingBoxEdgeLengths(domain)[DIM - 1] a = dk * (clip(z0 - domain.getX()[DIM - 1], minval=0) / l_z)**(beta / 2) else: a = dk super(SusceptibilityMapping, self).__init__(a=a, p0=k0)
def __init__(self, domain, z0=None, rho0=None, drho=None, beta=None): """ initializes the mapping :param domain: domain of the mapping :type domain: ``Domain`` :param z0: depth weighting offset. If not present no depth scaling is applied. :type z0: scalar :param rho0: reference density, defaults to 0 :type rho0: scalar :param drho: density scale. By default density of granite = 2750kg/m**3 is used. :type drho: scalar :param beta: depth weighting exponent, defaults to 2 :type beta: ``float`` """ if rho0 is None: rho0 = 0. if drho is None: drho = 2750 * U.kg / U.m**3 if beta is None: beta = 2. self.domain = domain if z0 is not None: DIM = self.domain.getDim() l_z = boundingBoxEdgeLengths(domain)[DIM - 1] a = drho * (clip(z0 - domain.getX()[DIM - 1], minval=0) / l_z)**(beta / 2) else: a = drho super(DensityMapping, self).__init__(a=a, p0=rho0)
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, 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()