Beispiel #1
0
    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.")
Beispiel #2
0
    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)
Beispiel #5
0
    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
Beispiel #7
0
 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)
Beispiel #10
0
 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
Beispiel #12
0
    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
Beispiel #13
0
    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
Beispiel #14
0
    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)
Beispiel #15
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
Beispiel #16
0
    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
Beispiel #17
0
 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
Beispiel #18
0
    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
Beispiel #19
0
 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))
Beispiel #20
0
    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()
Beispiel #21
0
    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))
Beispiel #22
0
    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()
Beispiel #24
0
    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()