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 getGradientAtPoint(self): """ returns the gradient of the cost function J with respect to m. :note: This implementation returns Y_k=dPsi/dm_k and X_kj=dPsi/dm_kj """ # Using cached values m = self.__pre_input grad_m = self.__pre_args mu = self.__mu mu_c = self.__mu_c DIM = self.getDomain().getDim() numLS = self.getNumLevelSets() grad_m = escript.grad(m, escript.Function(m.getDomain())) if self.__w0 is not None: Y = m * self.__w0 * mu else: if numLS == 1: Y = escript.Scalar(0, grad_m.getFunctionSpace()) else: Y = escript.Data(0, (numLS, ), grad_m.getFunctionSpace()) if self.__w1 is not None: if numLS == 1: X = grad_m * self.__w1 * mu else: X = grad_m * self.__w1 for k in range(numLS): X[k, :] *= mu[k] else: X = escript.Data(0, grad_m.getShape(), grad_m.getFunctionSpace()) # cross gradient terms: if numLS > 1: for k in range(numLS): grad_m_k = grad_m[k, :] l2_grad_m_k = escript.length(grad_m_k)**2 for l in range(k): grad_m_l = grad_m[l, :] l2_grad_m_l = escript.length(grad_m_l)**2 grad_m_lk = inner(grad_m_l, grad_m_k) f = mu_c[l, k] * self.__wc[l, k] X[l, :] += f * (l2_grad_m_k * grad_m_l - grad_m_lk * grad_m_k) X[k, :] += f * (l2_grad_m_l * grad_m_k - grad_m_lk * grad_m_l) return pdetools.ArithmeticTuple(Y, X)
def getGradientAtPoint(self): """ returns the gradient of the cost function J with respect to m. :note: This implementation returns Y_k=dPsi/dm_k and X_kj=dPsi/dm_kj """ # Using cached values m = self.__pre_input grad_m = self.__pre_args mu = self.__mu mu_c = self.__mu_c DIM = self.getDomain().getDim() numLS = self.getNumLevelSets() grad_m = grad(m, Function(m.getDomain())) if self.__w0 is not None: Y = m * self.__w0 * mu else: if numLS == 1: Y = Scalar(0, grad_m.getFunctionSpace()) else: Y = Data(0, (numLS,), grad_m.getFunctionSpace()) if self.__w1 is not None: if numLS == 1: X = grad_m * self.__w1 * mu else: X = grad_m * self.__w1 for k in range(numLS): X[k, :] *= mu[k] else: X = Data(0, grad_m.getShape(), grad_m.getFunctionSpace()) # cross gradient terms: if numLS > 1: for k in range(numLS): grad_m_k = grad_m[k, :] l2_grad_m_k = length(grad_m_k) ** 2 for l in range(k): grad_m_l = grad_m[l, :] l2_grad_m_l = length(grad_m_l) ** 2 grad_m_lk = inner(grad_m_l, grad_m_k) f = mu_c[l, k] * self.__wc[l, k] X[l, :] += f * (l2_grad_m_k * grad_m_l - grad_m_lk * grad_m_k) X[k, :] += f * (l2_grad_m_l * grad_m_k - grad_m_lk * grad_m_l) return ArithmeticTuple(Y, X)
def getWeightingFactor(self, x, wx0, x0, eta): """ returns the weighting factor """ try: origin, spacing, NE = x.getDomain().getGridParameters() cell = [int((x0[i] - origin[i]) / spacing[i]) for i in range(2)] midpoint = [ origin[i] + cell[i] * spacing[i] + spacing[i] / 2. for i in range(2) ] return wx0 * escript.whereNegative( escript.length(x - midpoint) - eta) except: return wx0 * escript.whereNegative(escript.length(x - x0) - eta)
def getValue(self, m, grad_m): """ returns the value of the cost function J with respect to m. This equation is specified in the inversion cookbook. :rtype: ``float`` """ if m != self.__pre_input: raise RuntimeError("Attempt to change point using getValue") # substituting cached values m = self.__pre_input grad_m = self.__pre_args mu = self.__mu mu_c = self.__mu_c DIM = self.getDomain().getDim() numLS = self.getNumLevelSets() A = 0 if self.__w0 is not None: r = inner(escript.integrate(m**2 * self.__w0), mu) self.logger.debug("J_R[m^2] = %e" % r) A += r if self.__w1 is not None: if numLS == 1: r = escript.integrate(inner(grad_m**2, self.__w1)) * mu self.logger.debug("J_R[grad(m)] = %e" % r) A += r else: for k in range(numLS): r = mu[k] * escript.integrate( inner(grad_m[k, :]**2, self.__w1[k, :])) self.logger.debug("J_R[grad(m)][%d] = %e" % (k, r)) A += r if numLS > 1: for k in range(numLS): gk = grad_m[k, :] len_gk = escript.length(gk) for l in range(k): gl = grad_m[l, :] r = mu_c[l, k] * escript.integrate(self.__wc[l, k] * ( (len_gk * escript.length(gl))**2 - inner(gk, gl)**2)) self.logger.debug("J_R[cross][%d,%d] = %e" % (l, k, r)) A += r return A / 2
def getValue(self, m, grad_m): """ returns the value of the cost function J with respect to m. This equation is specified in the inversion cookbook. :rtype: ``float`` """ if m != self.__pre_input: raise RuntimeError("Attempt to change point using getValue") # substituting cached values m = self.__pre_input grad_m = self.__pre_args mu = self.__mu mu_c = self.__mu_c DIM = self.getDomain().getDim() numLS = self.getNumLevelSets() A = 0 if self.__w0 is not None: r = inner(integrate(m ** 2 * self.__w0), mu) self.logger.debug("J_R[m^2] = %e" % r) A += r if self.__w1 is not None: if numLS == 1: r = integrate(inner(grad_m ** 2, self.__w1)) * mu self.logger.debug("J_R[grad(m)] = %e" % r) A += r else: for k in range(numLS): r = mu[k] * integrate(inner(grad_m[k, :] ** 2, self.__w1[k, :])) self.logger.debug("J_R[grad(m)][%d] = %e" % (k, r)) A += r if numLS > 1: for k in range(numLS): gk = grad_m[k, :] len_gk = length(gk) for l in range(k): gl = grad_m[l, :] r = mu_c[l, k] * integrate(self.__wc[l, k] * ((len_gk * length(gl)) ** 2 - inner(gk, gl) ** 2)) self.logger.debug("J_R[cross][%d,%d] = %e" % (l, k, r)) A += r return A / 2
def getSafeTimeStepSize(self, dt): """ returns new step size """ h = self.domain.getSize() return self.safety_factor * inf( h**2 / (h * abs(self.heat_capacity * self.density) * length(self.velocity) + self.thermal_permabilty))
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 __setOutput(self): x = self.domain.getX() self.__location_of_constraint = es.Scalar(0, x.getFunctionSpace()) if self.domain.getDim() == 3: vertex = [es.inf(x[0]), es.inf(x[1]), es.inf(x[2])] else: vertex = [es.inf(x[0]), es.inf(x[1])] self.__location_of_constraint = es.whereZero(es.length(x - vertex), self.tol) if not self.value is None: self.__value_of_constraint = self.__location_of_constraint * self.value
def getValue(self, m, grad_m): """ returns the value of the cost function J with respect to m. This equation is specified in the inversion cookbook. :rtype: ``float`` """ mu = self.__mu mu_c = self.__mu_c DIM = self.getDomain().getDim() numLS = self.getNumLevelSets() A = 0 if self.__w0 is not None: r = inner(integrate(m**2 * self.__w0), mu) self.logger.debug("J_R[m^2] = %e" % r) A += r if self.__w1 is not None: if numLS == 1: r = integrate(inner(grad_m**2, self.__w1)) * mu self.logger.debug("J_R[grad(m)] = %e" % r) A += r else: for k in range(numLS): r = mu[k] * integrate( inner(grad_m[k, :]**2, self.__w1[k, :])) self.logger.debug("J_R[grad(m)][%d] = %e" % (k, r)) A += r if numLS > 1: for k in range(numLS): gk = grad_m[k, :] len_gk = length(gk) for l in range(k): gl = grad_m[l, :] r = mu_c[l, k] * integrate(self.__wc[l, k] * ( (len_gk * length(gl))**2 - inner(gk, gl)**2)) self.logger.debug("J_R[cross][%d,%d] = %e" % (l, k, r)) A += r return A / 2
def out(self): """ Generate the Gaussian profile Link against this method to get the output of this model. """ x = self.domain.getX() dim = self.domain.getDim() l = length(x - self.x_c[:dim]) m = whereNegative(l - self.r) return (m + (1. - m) * exp(-log(2.) * (l / self.width)**2)) * self.A
def out(self): """ Generate the Gaussian profile Link against this method to get the output of this model. """ x = self.domain.getX() dim = self.domain.getDim() l = length(x-self.x_c[:dim]) m = whereNegative(l-self.r) return (m+(1.-m)*exp(-log(2.)*(l/self.width)**2))*self.A
def getSourceScaling(self, u): """ returns the scaling factor s required to rescale source F to minimize defect ``|s * u- data|^2`` :param u: value of pressure solution (real and imaginary part) :type u: ``escript.Data`` of shape (2,) :rtype: `complex` """ uTu = escript.integrate(self.__weight * escript.length(u)**2) uTar = escript.integrate(self.__weight * ( u[0]*self.__data[0]+u[1]*self.__data[1]) ) uTai = escript.integrate(self.__weight * ( u[0]*self.__data[1]-u[1]*self.__data[0]) ) if uTu > 0: return complex(uTar/uTu, uTai/uTu) else: return complex(1.,0)
def __setOutput(self): x = self.domain.getX() self.__location_of_constraint = es.Vector(0, x.getFunctionSpace()) if self.domain.getDim() == 3: vertex = [es.inf(x[0]), es.inf(x[1]), es.inf(x[2])] msk = numpy.zeros((3, )) if self.comp_mask[0]: msk[0] = 1 if self.comp_mask[1]: msk[1] = 1 if self.comp_mask[2]: msk[2] = 1 else: vertex = [es.inf(x[0]), es.inf(x[1])] msk = numpy.zeros((2, )) if self.comp_mask[0]: msk[0] = 1 if self.comp_mask[1]: msk[1] = 1 self.__location_of_constraint = es.whereZero( es.length(x - vertex), self.tol) * numpy.ones(shape) if not self.value is None: self.__value_of_constraint = self.__location_of_constraint * self.value
def getArguments(self, sigma): """ Returns precomputed values shared by `getDefect()` and `getGradient()`. :param sigma: a suggestion for complex 1/V**2 :type sigma: ``escript.Data`` of shape (2,) :return: solution, uTar, uTai, uTu :rtype: ``escript.Data`` of shape (2,), 3 x `float` """ pde=self.setUpPDE() 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, Y=self.__F, y=self.__f, y_dirac=self.__f_dirac) u=pde.getSolution() uTar=escript.integrate(self.__weight * ( u[0]*self.__data[0]+u[1]*self.__data[1]) ) uTai=escript.integrate(self.__weight * ( u[0]*self.__data[1]-u[1]*self.__data[0]) ) uTu = escript.integrate( self.__weight * escript.length(u)**2 ) return u, uTar, uTai, uTu
def __setOutput(self): if self.__location_of_constraint is None: x = self.domain.getX() val = self.value if isinstance(val, int) or isinstance(val, float): shape = () elif isinstance(val, list) or isinstance(val, tuple): shape = (len(val), ) elif isinstance(val, numpy.ndarray): shape = val.shape elif val is None: shape = () else: shape = val.getShape() if self.domain.getDim() == 3: vertex = [es.inf(x[0]), es.inf(x[1]), es.inf(x[2])] else: vertex = [es.inf(x[0]), es.inf(x[1])] self.__location_of_constraint = es.whereZero( es.length(x - vertex), self.tol) * numpy.ones(shape) if not self.value is None: self.__value_of_constraint = self.__location_of_constraint * self.value
def getDefect(self, sigma, u, uTar, uTai, uTu): """ Returns the defect value. :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` :rtype: ``float`` """ # assuming integrate(w * length(data)**2) =1 if self.scaleF and abs(uTu) >0: A = 1.-(uTar**2 + uTai**2)/uTu else: A = escript.integrate(self.__weight*escript.length(self.__data)**2)- 2 * uTar + uTu return A/2
def getSafeTimeStepSize(self,dt): """ returns new step size """ h=self.domain.getSize() return self.safety_factor*inf(h**2/(h*abs(self.heat_capacity*self.density)*length(self.velocity)+self.thermal_permabilty))
def getInverseHessianApproximationAtPoint(self, r, solve=True): """ """ # substituting cached values m = self.__pre_input grad_m = self.__pre_args if self._new_mu or self._update_Hessian: self._new_mu = False self._update_Hessian = False mu = self.__mu mu_c = self.__mu_c DIM = self.getDomain().getDim() numLS = self.getNumLevelSets() if self.__w0 is not None: if numLS == 1: D = self.__w0 * mu else: D = self.getPDE().getCoefficient("D") D.setToZero() for k in range(numLS): D[k, k] = self.__w0[k] * mu[k] self.getPDE().setValue(D=D) A = self.getPDE().getCoefficient("A") A.setToZero() if self.__w1 is not None: if numLS == 1: for i in range(DIM): A[i, i] = self.__w1[i] * mu else: for k in range(numLS): for i in range(DIM): A[k, i, k, i] = self.__w1[k, i] * mu[k] if numLS > 1: # this could be make faster by creating caches for grad_m_k, l2_grad_m_k and o_kk for k in range(numLS): grad_m_k = grad_m[k, :] l2_grad_m_k = escript.length(grad_m_k)**2 o_kk = escript.outer(grad_m_k, grad_m_k) for l in range(k): grad_m_l = grad_m[l, :] l2_grad_m_l = escript.length(grad_m_l)**2 i_lk = escript.inner(grad_m_l, grad_m_k) o_lk = escript.outer(grad_m_l, grad_m_k) o_kl = escript.outer(grad_m_k, grad_m_l) o_ll = escript.outer(grad_m_l, grad_m_l) f = mu_c[l, k] * self.__wc[l, k] Z = f * (2 * o_lk - o_kl - i_lk * escript.kronecker(DIM)) A[l, :, l, :] += f * (l2_grad_m_k * escript.kronecker(DIM) - o_kk) A[l, :, k, :] += Z A[k, :, l, :] += escript.transpose(Z) A[k, :, k, :] += f * (l2_grad_m_l * escript.kronecker(DIM) - o_ll) self.getPDE().setValue(A=A) #self.getPDE().resetRightHandSideCoefficients() #self.getPDE().setValue(X=r[1]) #print "X only: ",self.getPDE().getSolution() #self.getPDE().resetRightHandSideCoefficients() #self.getPDE().setValue(Y=r[0]) #print "Y only: ",self.getPDE().getSolution() self.getPDE().resetRightHandSideCoefficients() self.getPDE().setValue(X=r[1], Y=r[0]) if not solve: return self.getPDE() return self.getPDE().getSolution()
def setup(self, domainbuilder, k0=None, dk=None, z0=None, beta=None, w0=None, w1=None, k_at_depth=None): """ Sets up the inversion from a `DomainBuilder`. 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 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, 1. is used. :type dk: ``float`` or ``Scalar`` :param z0: reference depth for depth weighting, see `SusceptibilityMapping`. If not specified, zero is used. :type z0: ``float`` or ``Scalar`` :param beta: exponent for depth weighting, see `SusceptibilityMapping`. If not specified, zero is used. :type beta: ``float`` or ``Scalar`` :param w0: weighting factor for level set term regularization. If not set zero is assumed. :type w0: ``Scalar`` or ``float`` :param w1: weighting factor for the gradient term in the regularization. If not set zero is assumed :type w1: ``Vector`` or list of ``float`` :param k_at_depth: value for susceptibility at depth, see `DomainBuilder`. :type k_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 mapping ...') 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 k_mapping = SusceptibilityMapping(dom, k0=k2, dk=dk, z0=z0, beta=beta) scale_mapping = k_mapping.getTypicalDerivative() #======================== self.logger.info("Setting up regularization...") if w1 is None: w1 = [1.] * DIM regularization = Regularization(dom, numLevelSets=1, w0=w0, w1=w1, location_of_set_m=k_mask, coordinates=trafo) #==================================================================== 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 model...") if self.self_demagnetization: forward_model = SelfDemagnetizationModel( dom, w, B, domainbuilder.getBackgroundMagneticFluxDensity(), fixPotentialAtBottom=self._fixMagneticPotentialAtBottom, coordinates=trafo) else: if self.magnetic_intensity_data: forward_model = MagneticIntensityModel( dom, w, B, domainbuilder.getBackgroundMagneticFluxDensity(), fixPotentialAtBottom=self._fixMagneticPotentialAtBottom, coordinates=trafo) else: forward_model = MagneticModel( dom, w, B, domainbuilder.getBackgroundMagneticFluxDensity(), fixPotentialAtBottom=self._fixMagneticPotentialAtBottom, coordinates=trafo) forward_model.rescaleWeights(k_scale=scale_mapping) #==================================================================== self.logger.info("Setting cost function...") self.setCostFunction( InversionCostFunction(regularization, k_mapping, forward_model))
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, 2750 kg/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 density depth weighting, 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, 1. is used. :type dk: ``float`` or `Scalar` :param k_z0: reference depth for susceptibility depth weighting, see `SusceptibilityMapping`. If not specified, zero is used. :type k_z0: ``float`` or `Scalar` :param k_beta: exponent for susceptibility depth weighting, see `SusceptibilityMapping`. If not specified, zero is used. :type k_beta: ``float`` or `Scalar` :param w0: weighting factor for level set term in the regularization. If not set zero is assumed. :type w0: ``Scalar`` or ``float`` :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 (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()) rock_mask = wherePositive(domainbuilder.getSetDensityMask() + domainbuilder.getSetSusceptibilityMask()) #======================== self.logger.info('Creating mappings ...') if rho_at_depth: rho2 = rock_mask * rho_at_depth + (1 - rock_mask) * rho0 elif rho0: rho2 = (1 - rock_mask) * rho0 else: rho2 = 0 if k_at_depth: k2 = rock_mask * k_at_depth + (1 - rock_mask) * k0 elif k0: k2 = (1 - rock_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 = [1.] * DIM regularization = Regularization(dom, numLevelSets=1, w0=w0, w1=w1, location_of_set_m=rock_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, k_mapping), ((gravity_model, 0), (magnetic_model, 1))))
def getInverseHessianApproximationAtPoint(self, r, solve=True): """ """ # substituting cached values m = self.__pre_input grad_m = self.__pre_args if self._new_mu or self._update_Hessian: self._new_mu = False self._update_Hessian = False mu = self.__mu mu_c = self.__mu_c DIM = self.getDomain().getDim() numLS = self.getNumLevelSets() if self.__w0 is not None: if numLS == 1: D = self.__w0 * mu else: D = self.getPDE().getCoefficient("D") D.setToZero() for k in range(numLS): D[k, k] = self.__w0[k] * mu[k] self.getPDE().setValue(D=D) A = self.getPDE().getCoefficient("A") A.setToZero() if self.__w1 is not None: if numLS == 1: for i in range(DIM): A[i, i] = self.__w1[i] * mu else: for k in range(numLS): for i in range(DIM): A[k, i, k, i] = self.__w1[k, i] * mu[k] if numLS > 1: # this could be make faster by creating caches for grad_m_k, l2_grad_m_k and o_kk for k in range(numLS): grad_m_k = grad_m[k, :] l2_grad_m_k = length(grad_m_k) ** 2 o_kk = outer(grad_m_k, grad_m_k) for l in range(k): grad_m_l = grad_m[l, :] l2_grad_m_l = length(grad_m_l) ** 2 i_lk = inner(grad_m_l, grad_m_k) o_lk = outer(grad_m_l, grad_m_k) o_kl = outer(grad_m_k, grad_m_l) o_ll = outer(grad_m_l, grad_m_l) f = mu_c[l, k] * self.__wc[l, k] Z = f * (2 * o_lk - o_kl - i_lk * kronecker(DIM)) A[l, :, l, :] += f * (l2_grad_m_k * kronecker(DIM) - o_kk) A[l, :, k, :] += Z A[k, :, l, :] += transpose(Z) A[k, :, k, :] += f * (l2_grad_m_l * kronecker(DIM) - o_ll) self.getPDE().setValue(A=A) # self.getPDE().resetRightHandSideCoefficients() # self.getPDE().setValue(X=r[1]) # print "X only: ",self.getPDE().getSolution() # self.getPDE().resetRightHandSideCoefficients() # self.getPDE().setValue(Y=r[0]) # print "Y only: ",self.getPDE().getSolution() self.getPDE().resetRightHandSideCoefficients() self.getPDE().setValue(X=r[1], Y=r[0]) if not solve: return self.getPDE() return self.getPDE().getSolution()
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()