Exemple #1
0
    def setUpPDE(self):
        """
        Creates and returns the underlying PDE.

        :rtype: `lpde.LinearPDE`
        """
        if self.__pde is None:
            if not HAVE_DIRECT:
                raise ValueError(
                    "Either this build of escript or the current MPI configuration does not support direct solvers."
                )
            pde = lpde.LinearPDE(self.__domain, numEquations=2)
            D = pde.createCoefficient('D')
            A = pde.createCoefficient('A')
            A[0, :, 0, :] = escript.kronecker(self.__domain.getDim())
            A[1, :, 1, :] = escript.kronecker(self.__domain.getDim())
            pde.setValue(A=A, D=D)
            if self.__fixAtBottom:
                DIM = self.__domain.getDim()
                z = self.__domain.getX()[DIM - 1]
                pde.setValue(q=whereZero(z - self.__BX[DIM - 1][0]) * [1, 1])

            pde.getSolverOptions().setSolverMethod(lpde.SolverOptions.DIRECT)
            pde.getSolverOptions().setTolerance(self.__tol)
            pde.setSymmetryOff()
        else:
            pde = self.__pde
            pde.resetRightHandSideCoefficients()
        return pde
    def _setCoefficients(self, pde, system):
        """sets PDE coefficients"""
        FAC_DIAG = 1.
        FAC_OFFDIAG = -0.4
        x = Solution(self.domain).getX()
        mask = whereZero(x[0])
        dim = self.domain.getDim()
        u_ex = self._getSolution(system)
        g_ex = self._getGrad(system)

        if system:
            A = Tensor4(0., Function(self.domain))
            for i in range(dim):
                A[i,:,i,:] = kronecker(dim)

            Y = Vector(0., Function(self.domain))
            if dim == 2:
                Y[0] = u_ex[0]*FAC_DIAG+u_ex[1]*FAC_OFFDIAG
                Y[1] = u_ex[1]*FAC_DIAG+u_ex[0]*FAC_OFFDIAG
            else:
                Y[0] = u_ex[0]*FAC_DIAG+u_ex[2]*FAC_OFFDIAG+u_ex[1]*FAC_OFFDIAG
                Y[1] = u_ex[1]*FAC_DIAG+u_ex[0]*FAC_OFFDIAG+u_ex[2]*FAC_OFFDIAG
                Y[2] = u_ex[2]*FAC_DIAG+u_ex[1]*FAC_OFFDIAG+u_ex[0]*FAC_OFFDIAG
            pde.setValue(r=u_ex, q=mask*numpy.ones(dim,),
                         A=A,
                         D=kronecker(dim)*(FAC_DIAG-FAC_OFFDIAG)+numpy.ones((dim,dim))*FAC_OFFDIAG,
                         Y=Y,
                         y=matrixmult(g_ex,self.domain.getNormal()))
        else:
            pde.setValue(r=u_ex, q=mask, A=kronecker(dim),
                         y=inner(g_ex, self.domain.getNormal()))
    def setCoefficients(self, pde, system):
        """sets PDE coefficients"""        
        FAC_DIAG = self.FAC_DIAG
        FAC_OFFDIAG =self.FAC_OFFDIAG
        x = Solution(self.domain).getX()
        mask = whereZero(x[0])
        dim = self.domain.getDim()
        u_ex = self.getSolution(system)
        g_ex = self.getGrad(system)

        if system:
            A = Tensor4(0., Function(self.domain))
            for i in range(dim):
                A[i,:,i,:] = kronecker(dim)

            Y = Vector(0., Function(self.domain))
            if dim == 2:
                Y[0] = u_ex[0]*FAC_DIAG+u_ex[1]*FAC_OFFDIAG-20
                Y[1] = u_ex[1]*FAC_DIAG+u_ex[0]*FAC_OFFDIAG-10
            else:
                Y[0] = u_ex[0]*FAC_DIAG+u_ex[2]*FAC_OFFDIAG+u_ex[1]*FAC_OFFDIAG-60
                Y[1] = u_ex[1]*FAC_DIAG+u_ex[0]*FAC_OFFDIAG+u_ex[2]*FAC_OFFDIAG-20
                Y[2] = u_ex[2]*FAC_DIAG+u_ex[1]*FAC_OFFDIAG+u_ex[0]*FAC_OFFDIAG-22
            pde.setValue(r=u_ex, q=mask*numpy.ones(dim,),
                         A=A,
                         D=kronecker(dim)*(FAC_DIAG-FAC_OFFDIAG)+numpy.ones((dim,dim))*FAC_OFFDIAG,
                         Y=Y,
                         y=matrixmult(g_ex,self.domain.getNormal()))
        else:
            pde.setValue(r=u_ex, q=mask, A=kronecker(dim),
                         y=inner(g_ex, self.domain.getNormal()))
            if dim == 2:
                pde.setValue(Y=-20.)
            else:
                pde.setValue(Y=-60.)
    def getPotentialNumeric(self):
        """
        Returns 3 list each made up of a number of list containing primary, secondary and total
        potentials diferences. Each of the lists contain a list for each value of n.
        """
        primCon=self.primaryConductivity
        coords=self.domain.getX()
        tol=1e-8
        pde=LinearPDE(self.domain, numEquations=1)
        pde.getSolverOptions().setTolerance(tol)
        pde.setSymmetryOn()
        primaryPde=LinearPDE(self.domain, numEquations=1)
        primaryPde.getSolverOptions().setTolerance(tol)
        primaryPde.setSymmetryOn()
        DIM=self.domain.getDim()
        x=self.domain.getX()
        q=whereZero(x[DIM-1]-inf(x[DIM-1]))
        for i in xrange(DIM-1):
            xi=x[i]
            q+=whereZero(xi-inf(xi))+whereZero(xi-sup(xi))
        A = self.secondaryConductivity * kronecker(self.domain)
        APrimary = self.primaryConductivity * kronecker(self.domain)
        pde.setValue(A=A,q=q)
        primaryPde.setValue(A=APrimary,q=q)

        delPhiSecondaryList = []
        delPhiPrimaryList = []
        delPhiTotalList = []
        for i in range(1,self.n+1): # 1 to n
            maxR = self.numElectrodes - 1 - (2*i) #max amount of readings that will fit in the survey
            delPhiSecondary = []
            delPhiPrimary = []
            delPhiTotal = []
            for j in range(maxR):
                y_dirac=Scalar(0,DiracDeltaFunctions(self.domain))
                y_dirac.setTaggedValue(self.electrodeTags[j],self.current)
                y_dirac.setTaggedValue(self.electrodeTags[j + ((2*i) + 1)],-self.current)
                self.sources.append([self.electrodeTags[j], self.electrodeTags[j + ((2*i) + 1)]])
                primaryPde.setValue(y_dirac=y_dirac)
                numericPrimaryPot = primaryPde.getSolution()
                X=(primCon-self.secondaryConductivity) * grad(numericPrimaryPot)
                pde.setValue(X=X)
                u=pde.getSolution()
                loc=Locator(self.domain,[self.electrodes[j+i],self.electrodes[j+i+1]])
                self.samples.append([self.electrodeTags[j+i],self.electrodeTags[j+i+1]])
                valPrimary=loc.getValue(numericPrimaryPot)
                valSecondary=loc.getValue(u)
                delPhiPrimary.append(valPrimary[1]-valPrimary[0])
                delPhiSecondary.append(valSecondary[1]-valSecondary[0])
                delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j])
            delPhiPrimaryList.append(delPhiPrimary)
            delPhiSecondaryList.append(delPhiSecondary)
            delPhiTotalList.append(delPhiTotal)

        self.delPhiPrimaryList=delPhiPrimaryList
        self.delPhiSecondaryList=delPhiSecondaryList
        self.delPhiTotalList = delPhiTotalList
        return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
    def getPotentialNumeric(self):
        """
        Returns 3 list each made up of a number of list containing primary, secondary and total
        potentials diferences. Each of the lists contain a list for each value of n.
        """
        primCon=self.primaryConductivity
        coords=self.domain.getX()
        tol=1e-8
        pde=LinearPDE(self.domain, numEquations=1)
        pde.getSolverOptions().setTolerance(tol)
        pde.setSymmetryOn()
        primaryPde=LinearPDE(self.domain, numEquations=1)
        primaryPde.getSolverOptions().setTolerance(tol)
        primaryPde.setSymmetryOn()
        DIM=self.domain.getDim()
        x=self.domain.getX()
        q=es.whereZero(x[DIM-1]-es.inf(x[DIM-1]))
        for i in xrange(DIM-1):
            xi=x[i]
            q+=es.whereZero(xi-es.inf(xi))+es.whereZero(xi-es.sup(xi))
        A = self.secondaryConductivity * es.kronecker(self.domain)
        APrimary = self.primaryConductivity * es.kronecker(self.domain)
        pde.setValue(A=A,q=q)
        primaryPde.setValue(A=APrimary,q=q)

        delPhiSecondaryList = []
        delPhiPrimaryList = []
        delPhiTotalList = []
        for i in range(1,self.n+1): # 1 to n
            maxR = self.numElectrodes - 1 - (2*i) #max amount of readings that will fit in the survey
            delPhiSecondary = []
            delPhiPrimary = []
            delPhiTotal = []
            for j in range(maxR):
                y_dirac=es.Scalar(0,es.DiracDeltaFunctions(self.domain))
                y_dirac.setTaggedValue(self.electrodeTags[j],self.current)
                y_dirac.setTaggedValue(self.electrodeTags[j + ((2*i) + 1)],-self.current)
                self.sources.append([self.electrodeTags[j], self.electrodeTags[j + ((2*i) + 1)]])
                primaryPde.setValue(y_dirac=y_dirac)
                numericPrimaryPot = primaryPde.getSolution()
                X=(primCon-self.secondaryConductivity) * es.grad(numericPrimaryPot)
                pde.setValue(X=X)
                u=pde.getSolution()
                loc=Locator(self.domain,[self.electrodes[j+i],self.electrodes[j+i+1]])
                self.samples.append([self.electrodeTags[j+i],self.electrodeTags[j+i+1]])
                valPrimary=loc.getValue(numericPrimaryPot)
                valSecondary=loc.getValue(u)
                delPhiPrimary.append(valPrimary[1]-valPrimary[0])
                delPhiSecondary.append(valSecondary[1]-valSecondary[0])
                delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j])
            delPhiPrimaryList.append(delPhiPrimary)
            delPhiSecondaryList.append(delPhiSecondary)
            delPhiTotalList.append(delPhiTotal)

        self.delPhiPrimaryList=delPhiPrimaryList
        self.delPhiSecondaryList=delPhiSecondaryList
        self.delPhiTotalList = delPhiTotalList
        return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
    def getGradient(self, sigma, Ex, dExdz):
        """
        Returns the gradient of the defect with respect to density.

        :param sigma: a suggestion for conductivity
        :type sigma: ``Data`` of shape ()
        :param Ex: electric field
        :type Ex: ``Data`` of shape (2,)
        :param dExdz: vertical derivative of electric field
        :type dExdz: ``Data`` of shape (2,)
        """
        pde = self.setUpPDE()
        DIM = self.getDomain().getDim()

        x = dExdz.getFunctionSpace().getX()
        Ex = escript.interpolate(Ex, x.getFunctionSpace())
        u0 = Ex[0]
        u1 = Ex[1]
        u01 = dExdz[0]
        u11 = dExdz[1]

        D = pde.getCoefficient('D')
        Y = pde.getCoefficient('Y')
        X = pde.getCoefficient('X')
        A = pde.getCoefficient('A')

        A[0, :, 0, :] = escript.kronecker(DIM)
        A[1, :, 1, :] = escript.kronecker(DIM)

        f = self._omega_mu * sigma
        D[0, 1] = f
        D[1, 0] = -f

        Z = self._Z
        scale = 1. / (u01**2 + u11**2)
        scale2 = scale**2
        scale *= self._weight
        scale2 *= self._weight

        Y[0] = scale * (u0 - u01 * Z[0] + u11 * Z[1])
        Y[1] = scale * (u1 - u01 * Z[1] - u11 * Z[0])
        X[0,1] = scale2 * (2*u01*u11*(Z[0]*u1-Z[1]*u0) \
                + (Z[0]*u0+Z[1]*u1)*(u01**2-u11**2)
                - u01*(u0**2 + u1**2))
        X[1,1] = scale2 * (2*u01*u11*(Z[1]*u1+Z[0]*u0) \
                + (Z[1]*u0-Z[0]*u1)*(u01**2-u11**2)
                - u11*(u0**2 + u1**2))

        pde.setValue(A=A, D=D, X=X, Y=Y)
        Zstar = pde.getSolution()
        return (-self._omega_mu) * (Zstar[1] * u0 - Zstar[0] * u1)
Exemple #7
0
def update_solute_transport_pde(mesh,
                                solute_pde,
                                concentration_old,
                                v,
                                dt,
                                solute_source,
                                dispersion_tensor,
                                diffusivity,
                                l_disp,
                                t_disp,
                                rho_f,
                                verbose=False):
    """
    Solve the solute transport equation.
    """

    # calculate hydrodynamic dispersivity tensor from molecular diffusivity
    # and longitudinal and transverse dispersivity

    # calculate absolute velocity
    v_abs = (v[0]**2 + v[1]**2)**0.5

    # get rid of 0 values of velocity
    v_abs_1 = es.whereZero(v_abs) * 1e-20 + es.whereNonZero(v_abs) * v_abs

    Dxx = l_disp * (v[0]**2) / v_abs_1 + diffusivity
    Dyy = t_disp * (v[1]**2) / v_abs_1 + diffusivity

    # and set dispersion tensor to 0 where 0 absolute velocity
    Dxx = (Dxx * es.whereNonZero(v_abs) + es.whereZero(v_abs) * diffusivity)
    Dyy = (Dyy * es.whereNonZero(v_abs) + es.whereZero(v_abs) * diffusivity)

    # horizontal and vertical values of dispersion (Dxx and Dyy)
    dispersion_tensor[0, 0] = Dxx
    dispersion_tensor[1, 1] = Dyy

    # off-diagonal terms in tensor (Dxy and Dyx)
    # set to 0 for now, model becomes numerically unstable
    # testing with fixed values did not result in significant cahnges in solute conc...
    # todo, figure out why this is unstable or check the potential error
    dispersion_tensor[0, 1] = (l_disp - t_disp) * (v[0] * v[1]) / v_abs_1
    dispersion_tensor[1, 0] = (l_disp - t_disp) * (v[0] * v[1]) / v_abs_1

    u_old = concentration_old

    a_coeff = dt * dispersion_tensor * es.kronecker(mesh)
    c_coeff = dt * v
    d_coeff = 1
    y_coeff = u_old + solute_source * dt

    if verbose is True:
        print('solute transport coefficients')
        print('A: ', a_coeff.getShape(), a_coeff)
        print('C: ', c_coeff.getShape(), c_coeff)
        print('D: ', d_coeff)
        print('Y: ', y_coeff.getShape(), y_coeff)

    solute_pde.setValue(A=a_coeff, C=c_coeff, D=d_coeff, Y=y_coeff)

    return solute_pde
Exemple #8
0
       def doStep(self,dt):
          """

          performs an iteration step of the penalty method.
          IterationDivergenceError is raised if pressure error cannot be reduced or max_iter is reached.

          """
          penalty=self.viscosity/self.relaxation
          self.__pde.setValue(lame_mu=self.viscosity, \
                              lame_lambda=penalty, \
                              F=self.internal_force, \
                              sigma=self.pressure*kronecker(self.__pde.getDomain()), \
                              r=self.prescribed_velocity, \
                              q=self.location_prescribed_velocity)
          self.__pde.getSolverOptions().setTolerance(self.rel_tol/10.)
          self.velocity=self.__pde.getSolution()
          update=penalty*div(self.velocity)
          self.pressure=self.pressure-update
          self.__diff,diff_old=Lsup(update),self.__diff
          self.__iter+=1
          self.trace("velocity range %e:%e"%(inf(self.velocity),sup(self.velocity)))
          self.trace("pressure range %e:%e"%(inf(self.pressure),sup(self.pressure)))
          self.trace("pressure correction: %e"%self.__diff)
          if self.__iter>2 and diff_old<self.__diff:
              self.trace("Pressure iteration failed!")
              raise IterationDivergenceError("no improvement in pressure iteration")
          if self.__iter>self.max_iter:
              raise IterationDivergenceError("Maximum number of iterations steps reached")
Exemple #9
0
    def doStep(self, dt):
        """

          performs an iteration step of the penalty method.
          IterationDivergenceError is raised if pressure error cannot be reduced or max_iter is reached.

          """
        penalty = self.viscosity / self.relaxation
        self.__pde.setValue(lame_mu=self.viscosity, \
                            lame_lambda=penalty, \
                            F=self.internal_force, \
                            sigma=self.pressure*es.kronecker(self.__pde.getDomain()), \
                            r=self.prescribed_velocity, \
                            q=self.location_prescribed_velocity)
        self.__pde.getSolverOptions().setTolerance(self.rel_tol / 10.)
        self.velocity = self.__pde.getSolution()
        update = penalty * es.div(self.velocity)
        self.pressure = self.pressure - update
        self.__diff, diff_old = es.Lsup(update), self.__diff
        self.__iter += 1
        self.trace("velocity range %e:%e" %
                   (es.inf(self.velocity), es.sup(self.velocity)))
        self.trace("pressure range %e:%e" %
                   (es.inf(self.pressure), es.sup(self.pressure)))
        self.trace("pressure correction: %e" % self.__diff)
        if self.__iter > 2 and diff_old < self.__diff:
            self.trace("Pressure iteration failed!")
            raise esmf.IterationDivergenceError(
                "no improvement in pressure iteration")
        if self.__iter > self.max_iter:
            raise esmf.IterationDivergenceError(
                "Maximum number of iterations steps reached")
    def getPotential(self):
        """
        returns a list containing 3 lists one for each the primary, secondary
        and total potential.
        """


        primCon=self.primaryConductivity
        coords=self.domain.getX()
        pde=LinearPDE(self.domain, numEquations=1)
        tol=1e-8
        pde.getSolverOptions().setTolerance(tol)
        pde.setSymmetryOn()

        DIM=self.domain.getDim()
        x=self.domain.getX()
        q=whereZero(x[DIM-1]-inf(x[DIM-1]))
        for i in xrange(DIM-1):
            xi=x[i]
            q+=whereZero(xi-inf(xi))+whereZero(xi-sup(xi))
        A = self.secondaryConductivity * kronecker(self.domain)
        pde.setValue(A=A,q=q)

        delPhiSecondary = []
        delPhiPrimary = []
        delPhiTotal = []
        if(len(self.electrodes[0])==3):

            for i in range(self.numElectrodes-1):
                analyticRs=Data(0,(3,),ContinuousFunction(self.domain))
                analyticRs[0]=(coords[0]-self.electrodes[i][0])
                analyticRs[1]=(coords[1]-self.electrodes[i][1])
                analyticRs[2]=(coords[2])
                rsMag=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**0.5
                analyticPrimaryPot=(self.current*(1./primCon))/(2*pi*(rsMag+(whereZero(rsMag)*0.0000001))) #the magic number 0.0000001 is to avoid devide by 0
                analyticRsPolePower=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**1.5
                analyticRsPolePower = analyticRsPolePower+(whereZero(analyticRsPolePower)*0.0000001)
                gradUPrimary = Data(0,(3,),ContinuousFunction(self.domain))
                gradUPrimary[0] =(self.current/(2*pi*primCon)) * (analyticRs[0]/analyticRsPolePower)
                gradUPrimary[1] =(self.current/(2*pi*primCon)) * (analyticRs[1]/analyticRsPolePower)
                gradUPrimary[2] =(self.current/(2*pi*primCon)) * (analyticRs[2]/analyticRsPolePower)
                gradUPrimary=-gradUPrimary
                X=(primCon-self.secondaryConductivity) * gradUPrimary
                pde.setValue(X=X)
                u=pde.getSolution()
                loc=Locator(self.domain,self.electrodes[i+1])
                delPhiSecondary.append(loc.getValue(u))
                delPhiPrimary.append(loc.getValue(analyticPrimaryPot))
        else:
            raise NotImplementedError("2d forward model is not yet implemented")

        self.delPhiSecondary = delPhiSecondary
        self.delPhiPrimary = delPhiPrimary
        for i in range(len(delPhiPrimary)):
            delPhiTotal.append(delPhiPrimary[i] + delPhiSecondary[i])
        self.delPhiTotal=delPhiTotal
        return [delPhiPrimary, delPhiSecondary, delPhiTotal]
    def getPotential(self):
        """
        returns a list containing 3 lists one for each the primary, secondary
        and total potential.
        """


        primCon=self.primaryConductivity
        coords=self.domain.getX()
        pde=LinearPDE(self.domain, numEquations=1)
        tol=1e-8
        pde.getSolverOptions().setTolerance(tol)
        pde.setSymmetryOn()

        DIM=self.domain.getDim()
        x=self.domain.getX()
        q=es.whereZero(x[DIM-1]-es.inf(x[DIM-1]))
        for i in xrange(DIM-1):
            xi=x[i]
            q+=es.whereZero(xi-es.inf(xi))+es.whereZero(xi-es.sup(xi))
        A = self.secondaryConductivity * es.kronecker(self.domain)
        pde.setValue(A=A,q=q)

        delPhiSecondary = []
        delPhiPrimary = []
        delPhiTotal = []
        if(len(self.electrodes[0])==3):

            for i in range(self.numElectrodes-1):
                analyticRs=es.Data(0,(3,),es.ContinuousFunction(self.domain))
                analyticRs[0]=(coords[0]-self.electrodes[i][0])
                analyticRs[1]=(coords[1]-self.electrodes[i][1])
                analyticRs[2]=(coords[2])
                rsMag=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**0.5
                analyticPrimaryPot=(self.current*(1./primCon))/(2*pi*(rsMag+(es.whereZero(rsMag)*0.0000001))) #the magic number 0.0000001 is to avoid devide by 0
                analyticRsPolePower=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**1.5
                analyticRsPolePower = analyticRsPolePower+(es.whereZero(analyticRsPolePower)*0.0000001)
                gradUPrimary = es.Data(0,(3,),es.ContinuousFunction(self.domain))
                gradUPrimary[0] =(self.current/(2*pi*primCon)) * (analyticRs[0]/analyticRsPolePower)
                gradUPrimary[1] =(self.current/(2*pi*primCon)) * (analyticRs[1]/analyticRsPolePower)
                gradUPrimary[2] =(self.current/(2*pi*primCon)) * (analyticRs[2]/analyticRsPolePower)
                gradUPrimary=-gradUPrimary
                X=(primCon-self.secondaryConductivity) * gradUPrimary
                pde.setValue(X=X)
                u=pde.getSolution()
                loc=Locator(self.domain,self.electrodes[i+1])
                delPhiSecondary.append(loc.getValue(u))
                delPhiPrimary.append(loc.getValue(analyticPrimaryPot))
        else:
            raise NotImplementedError("2d forward model is not yet implemented")

        self.delPhiSecondary = delPhiSecondary
        self.delPhiPrimary = delPhiPrimary
        for i in range(len(delPhiPrimary)):
            delPhiTotal.append(delPhiPrimary[i] + delPhiSecondary[i])
        self.delPhiTotal=delPhiTotal
        return [delPhiPrimary, delPhiSecondary, delPhiTotal]
    def getArguments(self, sigma):
        """
        Returns precomputed values shared by `getDefect()` and `getGradient()`.

        :param sigma: conductivity
        :type sigma: ``Data`` of shape (2,)
        :return: E_x, E_z
        :rtype: ``Data`` of shape (2,)
        """
        DIM = self.getDomain().getDim()
        pde = self.setUpPDE()
        D = pde.getCoefficient('D')
        f = self._omega_mu * sigma
        D[0, 1] = -f
        D[1, 0] = f
        A = pde.getCoefficient('A')
        A[0, :, 0, :] = escript.kronecker(DIM)
        A[1, :, 1, :] = escript.kronecker(DIM)

        pde.setValue(A=A, D=D, r=self._r)
        u = pde.getSolution()
        return u, escript.grad(u)[:, 1]
    def getPotentialAnalytic(self):
        """
        Returns 3 list each made up of a number of list containing primary, secondary and total
        potentials diferences. Each of the lists contain a list for each value of n.
        """
        coords=self.domain.getX()
        pde=LinearPDE(self.domain, numEquations=1)
        tol=1e-8
        pde.getSolverOptions().setTolerance(tol)
        pde.setSymmetryOn()
        primCon=self.primaryConductivity
        DIM=self.domain.getDim()
        x=self.domain.getX()
        q=es.whereZero(x[DIM-1]-es.inf(x[DIM-1]))
        for i in xrange(DIM-1):
            xi=x[i]
            q+=es.whereZero(xi-es.inf(xi))+es.whereZero(xi-es.sup(xi))
        A = self.secondaryConductivity * es.kronecker(self.domain)
        pde.setValue(A=A,q=q)


        delPhiSecondaryList = []
        delPhiPrimaryList = []
        delPhiTotalList = []
        for i in range(1,self.n+1): # 1 to n
            maxR = self.numElectrodes - 1 - (2*i) #max amount of readings that will fit in the survey
            delPhiSecondary = []
            delPhiPrimary = []
            delPhiTotal = []
            for j in range(maxR):
                analyticRsOne=es.Data(0,(3,),es.ContinuousFunction(self.domain))
                analyticRsOne[0]=(coords[0]-self.electrodes[j][0])
                analyticRsOne[1]=(coords[1]-self.electrodes[j][1])
                analyticRsOne[2]=(coords[2])
                rsMagOne=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**0.5
                analyticRsTwo=es.Data(0,(3,),es.ContinuousFunction(self.domain))
                analyticRsTwo[0]=(coords[0]-self.electrodes[j + ((2*i) + 1)][0])
                analyticRsTwo[1]=(coords[1]-self.electrodes[j + ((2*i) + 1)][1])
                analyticRsTwo[2]=(coords[2])
                rsMagTwo=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**0.5
                self.sources.append([self.electrodeTags[j], self.electrodeTags[j + ((2*i) + 1)]])
                rsMagOne+=(es.whereZero(rsMagOne)*0.0000001)
                rsMagTwo+=(es.whereZero(rsMagTwo)*0.0000001)
                
                analyticPrimaryPot=(self.current/(2*pi*primCon*rsMagOne))-(self.current/(2*pi*primCon*rsMagTwo))
                analyticRsOnePower=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**1.5
                analyticRsOnePower = analyticRsOnePower+(es.whereZero(analyticRsOnePower)*0.0001)
                analyticRsTwoPower=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**1.5
                analyticRsTwoPower = analyticRsTwoPower+(es.whereZero(analyticRsTwoPower)*0.0001)

                gradAnalyticPrimaryPot = es.Data(0,(3,),es.ContinuousFunction(self.domain))
                gradAnalyticPrimaryPot[0] =(self.current/(2*pi*primCon)) * ((-analyticRsOne[0]/analyticRsOnePower) + (analyticRsTwo[0]/analyticRsTwoPower))
                gradAnalyticPrimaryPot[1] =(self.current/(2*pi*primCon)) * ((-analyticRsOne[1]/analyticRsOnePower) + (analyticRsTwo[1]/analyticRsTwoPower))
                gradAnalyticPrimaryPot[2] =(self.current/(2*pi*primCon)) * ((-analyticRsOne[2]/analyticRsOnePower) + (analyticRsTwo[2]/analyticRsTwoPower))
                X=(primCon-self.secondaryConductivity) * (gradAnalyticPrimaryPot)
                pde.setValue(X=X)
                u=pde.getSolution()
                loc=Locator(self.domain,[self.electrodes[j+i],self.electrodes[j+i+1]])
                self.samples.append([self.electrodeTags[j+i],self.electrodeTags[j+i+1]])
                valPrimary=loc.getValue(analyticPrimaryPot)
                valSecondary=loc.getValue(u)
                delPhiPrimary.append(valPrimary[1]-valPrimary[0])
                delPhiSecondary.append(valSecondary[1]-valSecondary[0])
                delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j])
            delPhiPrimaryList.append(delPhiPrimary)
            delPhiSecondaryList.append(delPhiSecondary)
            delPhiTotalList.append(delPhiTotal)

        self.delPhiPrimaryList=delPhiPrimaryList
        self.delPhiSecondaryList=delPhiSecondaryList
        self.delPhiTotalList = delPhiTotalList
        return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
Exemple #14
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))))
Exemple #15
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()
    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()
Exemple #17
0
def iterate_coupled_flow_eqs(mesh,
                             topo_gradient,
                             pressure_pde,
                             solute_pde,
                             pressure_convergence_criterion,
                             concentration_convergence_criterion,
                             min_iterations,
                             max_iterations,
                             dt,
                             g_vector,
                             pressure,
                             concentration,
                             rho_f,
                             phi,
                             diffusivity,
                             l_disp,
                             t_disp,
                             solute_source,
                             specific_storage,
                             k_tensor,
                             k_vector,
                             dispersion_tensor,
                             viscosity,
                             gamma,
                             alpha,
                             fluid_source,
                             rho_f_0,
                             specified_pressure_bnd,
                             specified_pressure,
                             specified_concentration_bnd,
                             specified_concentration,
                             specified_concentration_rho_f,
                             rch_bnd_loc,
                             recharge_mass_flux,
                             coupled_iterations=True,
                             solute_transport=True,
                             heat_transport=False,
                             steady_state=False,
                             proj=None,
                             drain_loc=None,
                             seepage_bnd=False,
                             recalculate_seepage_bnd=True,
                             active_seepage_bnd=None,
                             concentration_bnd_inflow_only=False,
                             concentration_bnd_inflow_direction='up',
                             max_allowed_CFL_number=None,
                             force_CFL_timestep=False,
                             dt_max=None,
                             calculate_viscosity=False,
                             verbose=False,
                             iterate_seepage_in_one_timestep=False,
                             max_seepage_iterations=50,
                             ignore_convergence_failure=False):
    """
    Iterative solve groundwater flow, solute transport and heat flow equations.
    
    solves either steady state or 1 timestep in implicit or explicit mode
    
    iterative coupling scheme of solute transport, pressure & flow eqs. and
    eqs of state follows Ackerer (2004), Geophysical Research Letters 31(12)
    
    Parameters
    ---------
    mesh : 
        escript mesh object
    pressure_pde : 
        groundwater flow PDE
    solute_pde
        solute transport PDE
    pressure_convergence_criterion : float
        convergence criterion groundwater flow eq. (Pa)
    concentration_convergence_criterion : float
        convergence criterion solute transport eq. (kg/kg)
    max_iterations : int
        max number of iterations
    dt : int
        timestep
    g_vector : 
        gravity vector (0,g)
    pressure : 
        pressure (Pa)
    concentration : 
        solute concentration (kg/kg)
    rho_f : 
        fluid density (kg / m3)
    phi :
        porosity
    D :
        solute diffusivity (...)
    l_disp :
        longitudinal dispersivity (...)
    t_disp :
        transverse dispersivity (...)
    solute_source :
        solute source (units...)
    specific_storage :
        specific storativity (...)
    k :
        permeability (m2)
    anisotropy :
        permeability anisotropy = horizontal/vertical permeability
        (dimensionless)
    viscosity : 
        viscosity (...)
    gamma :
        ?
    alpha :
        ?
    fluid_source :
        fluid source term (...)
    rho_f_0
        fluid density at solute concentration C=0 (kg/m3)
    specified_pressure_bnd
        location of specified pressure boundary
    specified_pressure
        specified pressure (Pa)
    specified_concentration_bnd
        location of specified concentration boundary
    specified_concentration
        specified concentration (kg/kg)
    rch_bnd_loc :

    recharge_mass_flux : float

    coupled_iterations : bool, optional
        couple groundwater and solute transport equations iteratively
        by adjusting density term
    solute_transport : bool, optional
        if True, simulate solute transport
    heat_transport : bool, optional
        if True, simulate heat transport
    steady_state : bool, optional
        True for steady state groundwater flow, False for transient
    verbose : bool, optional
        verbose text output
    drain_loc :
        location of drain boundary nodes
    debug : bool, optional
        debugging
    dt_max : float?
        =None                 ...
    proj : 
        escript PDE for projecting element data to nodes
    seepage_optimization_automated : boolean
        
    
    
    Returns 
    -------
    pressure_t2_i2 :
        pressure at next timestep (t2) and last iteration (i2)
    concentration_t2_i2 :
        solute concentration (kg/kg)
    rho_f_t2_i2 :
        fluid density
    iteration : int
        number of iterations
    dt_max :
        max timestep size
        
    """

    # calculate transverse dispersivity
    #t_disp = l_disp * disp_ratio

    year = 365.25 * 24 * 60 * 60.

    if verbose is True:
        print('running iterative solver for pressure and concentration PDEs')
        if coupled_iterations is False:
            print('pressure and concentration are not coupled')

    #pressure_new = pressure
    pressure_old_ts = pressure
    concentration_old_ts = concentration
    fluid_density_new = fluid_density_old = rho_f
    #pressure_t1 = pressure.copy()
    #concentration_t1 = concentration.copy()

    # added 22 jun 2016, not sure if this is ok:
    active_rch_bnd = rch_bnd_loc

    if coupled_iterations is True and calculate_viscosity is True:
        viscosity_new = calculate_viscosity_simple(concentration)
    else:
        viscosity_new = viscosity

    active_specified_concentration_bnd = specified_concentration_bnd

    iteration = 0
    converged = False
    non_convergence = False
    ele_size = None
    q = None
    v = None

    while converged is False and non_convergence is False:

        if verbose is True:
            print('iteration ', iteration)
            if iteration > 0:
                print('pressure convergence ', es.Lsup(pressure_conv))

        if solute_transport is True:

            # get flux
            q = calculate_q(k_vector, viscosity_new, pressure_old_ts,
                            fluid_density_new, g_vector)

            v = q / phi

            # calculate new solute concentration
            concentration_old_iteration = concentration

            # finite element solute transport
            if concentration_bnd_inflow_only is True and iteration == 0:
                # only apply concentration bnd for inflow into model domain
                # assumes a horizontal model bnd
                # TODO: calculate flux normal to model boundary to account
                # for non-horizontal upper boundaries

                proj.setValue(D=es.kronecker(mesh), Y=q)
                try:
                    nodal_q = proj.getSolution()
                except RuntimeError(msg):
                    print('error, non-convergence')
                    print(msg)
                    non_convergence = True

                nodal_q_norm = rotate_vector_escript(nodal_q, topo_gradient)

                nodal_v = nodal_q / phi

                if concentration_bnd_inflow_direction == 'up':
                    inflow_bnd = (es.whereNegative(nodal_q_norm[1]) *
                                  specified_concentration_bnd)
                elif concentration_bnd_inflow_direction == 'down':
                    inflow_bnd = (es.wherePositive(nodal_q_norm[1]) *
                                  specified_concentration_bnd)
                elif concentration_bnd_inflow_direction == 'left':
                    inflow_bnd = (es.wherePositive(nodal_q[0]) *
                                  specified_concentration_bnd)
                elif concentration_bnd_inflow_direction == 'right':
                    inflow_bnd = (es.whereNegative(nodal_q[0]) *
                                  specified_concentration_bnd)

                if es.sup(inflow_bnd) > 0:
                    active_specified_concentration_bnd = inflow_bnd
                else:
                    min_x = es.inf(
                        specified_concentration_bnd *
                        specified_concentration_bnd.getDomain().getX()[0])

                    active_specified_concentration_bnd = \
                        (specified_concentration_bnd *
                         es.whereZero(
                             specified_concentration_bnd.getDomain().getX()[0]
                             - min_x))

                    if verbose is True:
                        print('warning, outflow for all specified ' \
                              'concentration boundary nodes')
                        #print 'using entire bnd instead'
                        #active_specified_concentration_bnd = \
                        #    specified_concentration_bnd
                        print('using first node as fixed conc bnd instead')
                        print('number of active conc bnd nodes:')
                        print(
                            np.sum(
                                np.array(active_specified_concentration_bnd.
                                         toListOfTuples())))

                if verbose is True:
                    import grompy_lib

                    xyi, ia = grompy_lib.convert_to_array(
                        active_specified_concentration_bnd)
                    xyc, ca = grompy_lib.convert_to_array(
                        specified_concentration_bnd)
                    print('inflow conc bnd nodes = %0.0f / %0.0f' \
                          % (ia.sum(), ca.sum()))
                    print('x = %0.3f - %0.3f' %
                          (xyi[ia == 1, 0].min(), xyi[ia == 1, 0].max()))
                    print('qv conc bnd: ',
                          (nodal_q[1] * specified_concentration_bnd))

            #solute_pde.setValue(D=1,
            #                    r=specified_concentration_rho_f,
            #                    q=active_specified_concentration_bnd)
            solute_pde.setValue(D=1,
                                r=specified_concentration,
                                q=active_specified_concentration_bnd)

            solute_pde = update_solute_transport_pde(mesh, solute_pde,
                                                     concentration_old_ts, v,
                                                     dt, solute_source,
                                                     dispersion_tensor,
                                                     diffusivity, l_disp,
                                                     t_disp, fluid_density_old)

            try:
                #solute_mass = solute_pde.getSolution()
                concentration = solute_pde.getSolution()
            except RuntimeError(error_msg):
                print('!! runtime error ', error_msg)
                print('solver options: ')
                print(solute_pde.getSolverOptions().getSummary())

                non_convergence = True

                #raise RuntimeError(error_msg)

            # calculate concentration, using new solute mass and eq of state
            #concentration_new = calculate_concentration(
            #    solute_mass, rho_f_0, gamma)

            #concentration_new = solve_solute_transport_v2(
            #        solute_pde, mesh,
            #        steady_state,
            #        concentration_t1, v, dt, solute_source,
            #        diffusivity, l_disp, t_disp, fluid_density_old,
            #        rho_f_0, gamma)

            concentration_change_rate = \
                (concentration - concentration_old_ts) / dt

        else:
            # no solute transport:
            concentration_change_rate = 0

        if heat_transport is True:
            # no temperature in models yet:
            temperature_change_rate = 0
        else:
            # no heat transport:
            temperature_change_rate = 0

        if coupled_iterations is True:
            if verbose is True:
                print('recalculating fluid density and viscosity')
            # recalculate fluid density
            fluid_density_old = fluid_density_new
            fluid_density_new = \
                calculate_fluid_density(concentration, gamma, rho_f_0)

            if calculate_viscosity is True:
                viscosity_new = \
                    calculate_viscosity_simple(concentration)

        else:
            # leave fluid density unchanged
            concentration_change_rate = 0
            temperature_change_rate = 0

        # store old pressure
        pressure_old_iteration = pressure

        if drain_loc is None or es.sup(drain_loc) == 0:

            # calculate pressure, no drain or seepage bnd
            pressure_pde = \
                update_pressure_pde(pressure_pde,
                                    pressure_old_ts,
                                    phi, specific_storage,
                                    k_tensor, k_vector,
                                    fluid_density_new,
                                    viscosity_new, dt,
                                    rch_bnd_loc,
                                    recharge_mass_flux,
                                    fluid_source, g_vector,
                                    gamma, concentration_change_rate,
                                    alpha, temperature_change_rate)
            try:
                pressure = pressure_pde.getSolution()
            except RuntimeError(msg):
                print('error, non-convergence')
                print(msg)
                non_convergence = True
            #print 'no seepage bnd'
        else:
            # implement drain or seepage boundary
            if seepage_bnd is True:

                ## use seepage boundary:
                if active_seepage_bnd is None:
                    # calculate pressure without any drain boundary
                    pressure_pde.setValue(r=specified_pressure,
                                          q=specified_pressure_bnd)
                    active_rch_bnd = rch_bnd_loc
                else:
                    # incorporate active drain bnd of previous timestep
                    specified_pressure_bnd_mod = \
                        es.wherePositive(
                            specified_pressure_bnd + active_seepage_bnd)
                    pressure_pde.setValue(r=specified_pressure,
                                          q=specified_pressure_bnd_mod)

                    # do not change active rch bnd
                    active_rch_bnd = rch_bnd_loc

                    #active_rch_bnd = rch_bnd_loc * \
                    #                 es.whereZero(specified_pressure_bnd)
                    #specified_flux = rch_bnd_loc * dt * recharge_mass_flux

                # calculate pressure with existing seepage bnd
                pressure_pde = \
                    update_pressure_pde(pressure_pde,
                                        pressure_old_ts,
                                        phi, specific_storage,
                                        k_tensor, k_vector,
                                        fluid_density_new,
                                        viscosity_new, dt,
                                        active_rch_bnd, recharge_mass_flux,
                                        fluid_source, g_vector,
                                        gamma, concentration_change_rate,
                                        alpha, temperature_change_rate)
                try:
                    pressure = pressure_pde.getSolution()
                except RuntimeError:
                    print("error, pressure PDE solver failed")
                    converged = True
                    non_convergence = True
                    #if pressure_new not in locals():
                    #    pressure_new = pressure_t1

                # assign drain bnd nodes
                if active_seepage_bnd is None:
                    active_seepage_bnd = \
                        es.wherePositive(drain_loc * pressure)

                if iteration < max_seepage_iterations and recalculate_seepage_bnd is True:
                    # adjust seepage boundary, but only for first x iterations
                    # to avoid instability

                    if verbose is True:
                        seepage_xy = active_seepage_bnd.getDomain().getX()
                        seepage_nodes_xy = \
                            np.array(seepage_xy.toListOfTuples())
                        seepage_array = np.array(
                            active_seepage_bnd.toListOfTuples())
                        ind = seepage_array > 0
                        print('\tbefore adjustment:')
                        print('\tactive seepage bnd from x=%0.0f to %0.0f m' \
                              % (seepage_nodes_xy[ind, 0].min(),
                                 seepage_nodes_xy[ind, 0].max()))

                    # remove seepage nodes that have become source of water
                    q = calculate_q(k_vector, viscosity_new, pressure,
                                    fluid_density_new, g_vector)
                    proj.setValue(D=es.kronecker(mesh), Y=q)
                    try:
                        nodal_q = proj.getSolution()
                    except RuntimeError(msg):
                        print('error, non-convergence')
                        print(msg)
                        non_convergence = True

                    # calculate max vertical flux into the model domain at
                    # drain bnd nodes
                    # -> not possible, cannot mix face elements and normal elements
                    # later on to adjust seepage...
                    #nodal_q_norm = nodal_q * nodal_q.getDomain().getNormal()

                    #
                    nodal_q_norm = rotate_vector_escript(
                        nodal_q, topo_gradient)

                    #flux_seepage_bnd = active_seepage_bnd * nodal_q[1]
                    flux_seepage_bnd = active_seepage_bnd * nodal_q_norm[1]

                    #flux_seepage_bnd_corr = flux_seepage_bnd +

                    seepage_change_buffer = 1e-3 / year

                    seepage_inflow_nodes = \
                        es.whereNegative(flux_seepage_bnd
                                         + recharge_mass_flux
                                         / fluid_density_new)

                    if verbose is True:

                        print('\tflux seepage bnd (m/yr): ',
                              flux_seepage_bnd * year)
                        print('recharge ')
                        print('\tseepage inflow nodes: ', seepage_inflow_nodes)

                    #seepage_inflow_nodes = \
                    #    es.whereNegative(flux_seepage_bnd)

                    removed_seepage_inflow_nodes = seepage_inflow_nodes

                    # add boundary nodes with P>0 to seepage bnd
                    new_seepage_nodes = \
                        es.wherePositive(drain_loc
                                         * (1 - active_seepage_bnd)
                                         * pressure)

                    # update the seepage bnd
                    active_seepage_bnd = (active_seepage_bnd +
                                          new_seepage_nodes -
                                          removed_seepage_inflow_nodes)

                    if verbose is True:
                        seepage_xy = active_seepage_bnd.getDomain().getX()
                        seepage_nodes_xy = \
                            np.array(seepage_xy.toListOfTuples())
                        seepage_array = np.array(
                            active_seepage_bnd.toListOfTuples())
                        ind = np.array(seepage_array > 0)
                        print('\tafter adjustment:')
                        print('\tN=%i active seepage bnd x=%0.0f to %0.0f m' \
                              % (np.sum(ind.astype(int)),
                                 seepage_nodes_xy[ind, 0].min(),
                                 seepage_nodes_xy[ind, 0].max()))

                    if iterate_seepage_in_one_timestep is True:
                        # update the specified pressure boundary to include
                        # new seepage nodes
                        specified_pressure_bnd_mod = \
                            es.wherePositive(
                                specified_pressure_bnd + active_seepage_bnd)
                        #active_rch_bnd = rch_bnd_loc * es.whereZero(specified_pressure_bnd_mod)
                        # changed to have steady recharge bnd regardless of seepage bnd,
                        # 11 apr 2016, Elco
                        active_rch_bnd = rch_bnd_loc

                        # experiment, adjust recharge to have 0 rehcarge at seepage nodes
                        # not sure if this makes sense...
                        #specified_flux_adj = active_rch_bnd * dt * recharge_mass_flux
                        #
                        #pressure_pde.setValue(r=specified_pressure,
                        #                      q=specified_pressure_bnd_mod,
                        #                      y=specified_flux_adj)
                        pressure_pde.setValue(r=specified_pressure,
                                              q=specified_pressure_bnd_mod)

                        # recalculate pressure
                        #pressure_pde = \
                        #    update_pressure_pde(pressure_pde,
                        #                        pressure_t1,
                        #                        phi, specific_storage,
                        #                        k_tensor, k_vector,
                        #                        fluid_density_new,
                        #                        viscosity_new, dt,
                        #                        rch_bnd_loc, recharge_mass_flux,
                        #                        fluid_source, g_vector,
                        #                        gamma, concentration_change_rate,
                        #                        alpha, temperature_change_rate)

                        # recalculate pressure
                        try:
                            pressure = pressure_pde.getSolution()
                        except RuntimeError(msg):
                            print('error, non-convergence')
                            print(msg)
                            non_convergence = True

                        # remove inflow nodes again
                        #q = (k_vector / viscosity_new *
                        #     -(es.grad(pressure_new)
                        #       - fluid_density_new * g_vector)
                        #     / phi)
                        q = calculate_q(k_vector, viscosity_new, pressure,
                                        fluid_density_new, g_vector)
                        proj.setValue(D=es.kronecker(mesh), Y=q)
                        nodal_q = proj.getSolution()

                        # calculate max vertical flux into the model domain at
                        # drain bnd nodes
                        #nodal_q_norm = nodal_q * nodal_q.getDomain().getNormal()
                        nodal_q_norm = rotate_vector_escript(
                            nodal_q, topo_gradient)
                        flux_seepage_bnd = active_seepage_bnd * nodal_q_norm[1]

                        #removed_seepage_inflow_nodes = \
                        #    es.whereNegative(flux_seepage_bnd -
                        #                     seepage_inflow_threshold)
                        #removed_seepage_inflow_nodes = \
                        #    es.whereNegative(flux_seepage_bnd
                        #                     + recharge_mass_flux
                        #                     / fluid_density_new)

                        removed_seepage_inflow_nodes = \
                            es.whereNegative(flux_seepage_bnd)

                        active_seepage_bnd = (active_seepage_bnd -
                                              removed_seepage_inflow_nodes)

                        if verbose is True:
                            seepage_xy = active_seepage_bnd.getDomain().getX()
                            seepage_nodes_xy = \
                                np.array(seepage_xy.toListOfTuples())
                            seepage_array = np.array(
                                active_seepage_bnd.toListOfTuples())
                            ind = seepage_array > 0
                            print(
                                '\tafter 2nd adjustment (removing inflow nodes):'
                            )
                            print('\tN=%i active seepage bnd from ' \
                                  'x=%0.0f to %0.0f m' \
                                  % (np.sum(ind.astype(int)),
                                     seepage_nodes_xy[ind, 0].min(),
                                     seepage_nodes_xy[ind, 0].max()))

                if iterate_seepage_in_one_timestep is True:
                    # assign updated seepage nodes:
                    specified_pressure_bnd_mod = \
                        es.wherePositive(
                            specified_pressure_bnd + active_seepage_bnd)

                    #active_rch_bnd = rch_bnd_loc * es.whereZero(specified_pressure_bnd_mod)
                    active_rch_bnd = rch_bnd_loc

                    # experiment, adjust recharge to have 0 rehcarge at seepage nodes
                    # not sure if this makes sense...
                    # ! probably the source of long timescale instability of seepage/rch bnd

                    #specified_flux_adj = active_rch_bnd * dt * recharge_mass_flux

                    #pressure_pde.setValue(r=specified_pressure,
                    #                      q=specified_pressure_bnd_mod,
                    #                      y=specified_flux_adj)
                    pressure_pde.setValue(r=specified_pressure,
                                          q=specified_pressure_bnd_mod)

                    # recalculate final pressure
                    #pressure_pde = \
                    #    update_pressure_pde(pressure_pde,
                    #                        pressure_t1,
                    #                        phi, specific_storage,
                    #                        k_tensor, k_vector,
                    #                        fluid_density_new,
                    #                        viscosity_new, dt,
                    #                        rch_bnd_loc, recharge_mass_flux,
                    #                        fluid_source, g_vector,
                    #                        gamma, concentration_change_rate,
                    #                        alpha, temperature_change_rate)

                    try:
                        pressure = pressure_pde.getSolution()
                    except RuntimeError(msg):
                        print('error, non-convergence')
                        print(msg)
                        non_convergence = True

        # calculate convergence criteria
        pressure_conv = pressure - pressure_old_iteration

        if solute_transport is True:
            conc_conv = concentration - concentration_old_iteration
        else:
            conc_conv = 0.0

        # check whether iterations have converged or not:
        if (es.Lsup(pressure_conv) < pressure_convergence_criterion) and \
                (es.Lsup(conc_conv) < concentration_convergence_criterion)\
                and iteration + 1 >= min_iterations:
            if iteration > 0 and verbose is True:
                print('iterations converged after %i iterations' % iteration)
            converged = True
        else:
            if verbose is True:
                print('iteration %i, max. pressure change %0.3e ' \
                      % (iteration, es.Lsup(pressure_conv)))
                print('              max. C change %0.3e ' \
                      % (es.Lsup(conc_conv)))

        if iteration + 1 >= max_iterations:
            print('warning, reached maximum number of %i iterations' \
                  % (iteration + 1))
            print('iteration %i, max. pressure change %0.3e Pa, ' \
                  'convergence at %0.2e Pa' \
                  % (iteration, es.Lsup(pressure_conv),
                     pressure_convergence_criterion))
            print('              max. C change %0.3e kg/kg, ' \
                  'convergence at %0.2e kg/kg' \
                  % (es.Lsup(conc_conv), concentration_convergence_criterion))
            converged = True
            non_convergence = True

        # check CFL number
        #max_CFL_number = calculate_CFL_number(q, dt)
        if ele_size is None:
            ele_size = q.getDomain().getSize()
        #print ele_size - q.getDomain().getSize()

        CFL_number = q * dt / ele_size
        max_CFL_number = es.Lsup(CFL_number)

        if max_CFL_number > 0.5 and verbose is True:
            print('warning, max CFL number = %0.2f, exceeds 0.5' \
                  % max_CFL_number)

        # recaclulcate timestep if max timestep exceeds CFL number
        if (max_allowed_CFL_number is not None
                and max_CFL_number > max_allowed_CFL_number
                and iteration == 0) \
                or (force_CFL_timestep is True and iteration <= 1):

            # make sure iteration is repeated
            converged = False

            #CFL_number / flux * flux.getDomain().getSize() = dtc /

            dtc = max_allowed_CFL_number / q * ele_size
            new_timestep = es.inf((dtc**2)**0.5)
            if dt_max is not None and new_timestep > dt_max:
                new_timestep = dt_max

            dt = new_timestep

            if verbose is True:
                print('max CFL number = ', max_CFL_number)
                print('changing timestep from %0.2e sec to %0.2e sec' \
                      % (dt, new_timestep))

        if coupled_iterations is False:
            converged = True

        iteration += 1

    return (pressure, concentration, fluid_density_new, viscosity_new, q, v,
            active_specified_concentration_bnd, active_seepage_bnd,
            active_rch_bnd, iteration, es.Lsup(pressure_conv),
            es.Lsup(conc_conv), max_CFL_number, non_convergence, dt)
Exemple #18
0
def solve_steady_state_pressure_eq_new(mesh,
                                       topo_gradient,
                                       pressure_pde,
                                       rho_f,
                                       k_tensor,
                                       k_vector,
                                       viscosity,
                                       g_vector,
                                       fluid_source,
                                       rch_bnd_loc,
                                       recharge_mass_flux,
                                       specified_pressure_bnd,
                                       specified_pressure,
                                       drain_bnd_loc,
                                       fluid_density,
                                       proj,
                                       debug=True):
    """
    Solve the steady-state fluid flow equation for fluid pressure using escript with optional seepage bnd condition.
    """

    year = 365.25 * 24 * 60 * 60.0

    # calculate boundary flux
    specified_flux = rch_bnd_loc * recharge_mass_flux

    a = rho_f * k_tensor / viscosity * es.kronecker(mesh)
    d = 0.0
    x = rho_f**2 * k_vector / viscosity * g_vector
    y = fluid_source

    #
    pressure_pde.setValue(A=a,
                          D=d,
                          X=x,
                          Y=y,
                          y=specified_flux,
                          q=specified_pressure_bnd,
                          r=specified_pressure)

    # calculate pressure, without seepage bnd
    pressure = pressure_pde.getSolution()

    debug = True
    if debug is True:
        print('initial calculated steady-state pressure: ', pressure)

    if es.sup(drain_bnd_loc) == 0:
        print('no drain or seepage bnd')
        active_seepage_bnd = es.wherePositive(drain_bnd_loc)

        return pressure, active_seepage_bnd

    # check if h > surface elevation
    #pressure_threshold = 0.01 * 9.81 * 1000.0
    pressure_threshold = 0.0
    active_seepage_bnd = es.wherePositive(drain_bnd_loc * pressure -
                                          pressure_threshold)

    if debug is True:
        print('active seepage nodes: ',
              np.sum(np.array(active_seepage_bnd.toListOfTuples())))
        print('potential seepage nodes: ',
              np.sum(np.array(drain_bnd_loc.toListOfTuples())))

    n_seepage_change = 9999
    n_seepage_nodes = 99999
    n_iter = 0
    max_seepage_iter = 2000
    while n_seepage_change > 0 and n_iter < max_seepage_iter:

        # add seepage to specified pressure bnd and update bnd conditions
        specified_pressure_bnd_mod = \
        es.wherePositive(
            specified_pressure_bnd + active_seepage_bnd)

        #active_rch_bnd = rch_bnd_loc * es.whereZero(specified_pressure_bnd)
        active_rch_bnd = rch_bnd_loc
        specified_flux = active_rch_bnd * recharge_mass_flux
        pressure_pde.setValue(r=specified_pressure,
                              q=specified_pressure_bnd_mod,
                              y=specified_flux)

        # recalculate pressure
        pressure = pressure_pde.getSolution()

        if debug is True:
            print('new pressure: ', pressure)

        # calculate flux
        q = calculate_q(k_vector, viscosity, pressure, fluid_density, g_vector)
        proj.setValue(D=es.kronecker(mesh), Y=q)
        try:
            nodal_q = proj.getSolution()
        except RuntimeError(msg):
            print('error, non-convergence')
            print(msg)
            non_convergence = True

        # calculate max vertical flux into the model domain at
        # drain bnd nodes

        # using outer norm to calculate correct bnd flux does not work because
        # flux cannot be interpolated to same functionspace as pressure variable
        #nodal_q_norm_bnd = nodal_q * nodal_q.getDomain().getNormal()
        #nodal_q_norm = es.interpolate(nodal_q_norm_bnd, active_seepage_bnd.getFunctionSpace())

        nodal_q_norm = rotate_vector_escript(nodal_q, topo_gradient)

        flux_seepage_bnd = active_seepage_bnd * nodal_q_norm[1]

        # remove inlfow nodes that are <= recharge
        flux_seepage_bnd_corr = flux_seepage_bnd + recharge_mass_flux / fluid_density
        # changed back to old method to speed up seepage bnd calc
        #flux_seepage_bnd_corr = flux_seepage_bnd

        # and remove only the worst x % of seepage nodes to avoid oscillations:
        seepage_threshold = es.inf(flux_seepage_bnd_corr) * 0.5
        #seepage_threshold = 0.0

        seepage_inflow_nodes = \
            es.whereNegative(flux_seepage_bnd_corr - seepage_threshold)

        removed_seepage_inflow_nodes = seepage_inflow_nodes

        if debug is True:
            print('number of seepage inflow nodes: ', \
                np.sum(np.array(seepage_inflow_nodes.toListOfTuples())))

            xmin_seep = es.inf(seepage_inflow_nodes *
                               seepage_inflow_nodes.getDomain().getX()[0] +
                               (1 - seepage_inflow_nodes) * 999999)
            xmax_seep = es.sup(seepage_inflow_nodes *
                               seepage_inflow_nodes.getDomain().getX()[0])

            print('from x= %0.2f m to x= %0.2f m' % (xmin_seep, xmax_seep))

        # add boundary nodes with P>0 to seepage bnd
        new_seepage_nodes = \
            es.wherePositive(drain_bnd_loc
                             * (1 - active_seepage_bnd)
                             * pressure)

        if debug is True:
            print('number of new seepage nodes: ', \
                np.sum(np.array(new_seepage_nodes.toListOfTuples())))

        # update the seepage bnd
        active_seepage_bnd = (active_seepage_bnd + new_seepage_nodes -
                              removed_seepage_inflow_nodes)

        n_seepage_nodes_old = n_seepage_nodes
        n_seepage_nodes = np.sum(np.array(active_seepage_bnd.toListOfTuples()))

        n_seepage_change = np.abs(n_seepage_nodes_old - n_seepage_nodes)

        if debug is True:
            print('final active seepage nodes: ',
                  np.sum(np.array(active_seepage_bnd.toListOfTuples())))
            print('potential seepage nodes: ',
                  np.sum(np.array(drain_bnd_loc.toListOfTuples())))

        if n_seepage_nodes_old < n_seepage_nodes:
            print(
                'lowest number of seepage nodes reached, stopping iterations')
            n_seepage_change = 0

        print('seepage iteration %i' % n_iter)
        print('seepage threshold ', seepage_threshold * year)
        print('change in seepage nodes from %0.0f to %0.0f' %
              (n_seepage_nodes_old, n_seepage_nodes))

        n_iter += 1

    # update specified pressure bnd condition
    specified_pressure_bnd_mod = \
    es.wherePositive(
        specified_pressure_bnd + active_seepage_bnd)

    #active_rch_bnd = rch_bnd_loc * es.whereZero(specified_pressure_bnd)
    active_rch_bnd = rch_bnd_loc
    specified_flux = active_rch_bnd * recharge_mass_flux
    pressure_pde.setValue(r=specified_pressure,
                          q=specified_pressure_bnd_mod,
                          y=specified_flux)

    # recalculate pressure
    pressure = pressure_pde.getSolution()

    if debug is True:
        print('final pressure: ', pressure)

    return pressure, active_seepage_bnd
    def getPotential(self):
        """
        Returns 3 list each made up of a number of list containing primary, secondary and total
        potentials diferences. Each of the lists contain a list for each value of n.
        """
        coords=self.domain.getX()
        pde=LinearPDE(self.domain, numEquations=1)
        tol=1e-8
        pde.getSolverOptions().setTolerance(tol)
        pde.setSymmetryOn()
        primCon=self.primaryConductivity
        DIM=self.domain.getDim()
        x=self.domain.getX()
        q=whereZero(x[DIM-1]-inf(x[DIM-1]))
        for i in xrange(DIM-1):
            xi=x[i]
            q+=whereZero(xi-inf(xi))+whereZero(xi-sup(xi))
        A = self.secondaryConductivity * kronecker(self.domain)
        pde.setValue(A=A,q=q)


        delPhiSecondaryList = []
        delPhiPrimaryList = []
        delPhiTotalList = []
        for i in range(1,self.n+1): # 1 to n
            maxR = self.numElectrodes - 2 - (i) #max amount of readings that will fit in the survey
            delPhiSecondary = []
            delPhiPrimary = []
            delPhiTotal = []
            for j in range(maxR):
                analyticRsOne=Data(0,(3,),ContinuousFunction(self.domain))
                analyticRsOne[0]=(coords[0]-self.electrodes[j][0])
                analyticRsOne[1]=(coords[1]-self.electrodes[j][1])
                analyticRsOne[2]=(coords[2])
                rsMagOne=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**0.5
                analyticRsTwo=Data(0,(3,),ContinuousFunction(self.domain))
                analyticRsTwo[0]=(coords[0]-self.electrodes[j + 1][0])
                analyticRsTwo[1]=(coords[1]-self.electrodes[j + 1][1])
                analyticRsTwo[2]=(coords[2])
                rsMagTwo=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**0.5
                rsMagOne+=(whereZero(rsMagOne)*0.0000001)
                rsMagTwo+=(whereZero(rsMagTwo)*0.0000001)
                analyticPrimaryPot=(self.current/(2*pi*primCon*rsMagTwo))-(self.current/(2*pi*primCon*rsMagOne))

                analyticRsOnePower=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**1.5
                analyticRsOnePower = analyticRsOnePower+(whereZero(analyticRsOnePower)*0.0001)
                analyticRsTwoPower=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**1.5
                analyticRsTwoPower = analyticRsTwoPower+(whereZero(analyticRsTwoPower)*0.0001)

                gradAnalyticPrimaryPot = Data(0,(3,),ContinuousFunction(self.domain))
                gradAnalyticPrimaryPot[0] =(self.current/(2*pi*primCon)) * ((analyticRsOne[0]/analyticRsOnePower) - (analyticRsTwo[0]/analyticRsTwoPower))
                gradAnalyticPrimaryPot[1] =(self.current/(2*pi*primCon)) * ((analyticRsOne[1]/analyticRsOnePower) - (analyticRsTwo[1]/analyticRsTwoPower))
                gradAnalyticPrimaryPot[2] =(self.current/(2*pi*primCon)) * ((analyticRsOne[2]/analyticRsOnePower) - (analyticRsTwo[2]/analyticRsTwoPower))
                X=(primCon-self.secondaryConductivity) * (gradAnalyticPrimaryPot)
                pde.setValue(X=X)
                u=pde.getSolution()
                loc=Locator(self.domain,[self.electrodes[1+j+i],self.electrodes[j+i+2]])
                valPrimary=loc.getValue(analyticPrimaryPot)
                valSecondary=loc.getValue(u)
                delPhiPrimary.append(valPrimary[1]-valPrimary[0])
                delPhiSecondary.append(valSecondary[1]-valSecondary[0])
                delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j])
            delPhiPrimaryList.append(delPhiPrimary)
            delPhiSecondaryList.append(delPhiSecondary)
            delPhiTotalList.append(delPhiTotal)

        self.delPhiPrimaryList=delPhiPrimaryList
        self.delPhiSecondaryList=delPhiSecondaryList
        self.delPhiTotalList = delPhiTotalList
        return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
Exemple #20
0
    def setup(self,
              domainbuilder,
              rho0=None,
              drho=None,
              z0=None,
              beta=None,
              w0=None,
              w1=None,
              rho_at_depth=None):
        """
        Sets up the inversion parameters from a `DomainBuilder`.

        :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 z0: reference depth for depth weighting, see `DensityMapping`. If not specified, zero is used.
        :type z0: ``float`` or ``Scalar``
        :param beta: exponent for  depth weighting, see `DensityMapping`. 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 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()
        trafo = makeTransformation(dom, domainbuilder.getReferenceSystem())
        DIM = dom.getDim()
        rho_mask = domainbuilder.getSetDensityMask()
        #========================
        self.logger.info('Creating mapping...')
        if rho_at_depth:
            rho2 = rho_mask * rho_at_depth + (1 - rho_mask) * rho0
        elif rho0:
            rho2 = (1 - rho_mask) * rho0
        else:
            rho2 = 0.

        rho_mapping = DensityMapping(dom,
                                     rho0=rho2,
                                     drho=drho,
                                     z0=z0,
                                     beta=beta)
        scale_mapping = rho_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=rho_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 model...")
        forward_model = GravityModel(
            dom,
            w,
            g,
            fixPotentialAtBottom=self._fixGravityPotentialAtBottom,
            coordinates=trafo)
        forward_model.rescaleWeights(rho_scale=scale_mapping)

        #====================================================================
        self.logger.info("Setting cost function...")
        self.setCostFunction(
            InversionCostFunction(regularization, rho_mapping, forward_model))
    def getPotential(self):
        """
        returns a list containing 3 lists one for each the primary, secondary
        and total potential.
        """

        primCon=self.primaryConductivity
        coords=self.domain.getX()
        pde=LinearPDE(self.domain, numEquations=1)
        tol=1e-8
        pde.getSolverOptions().setTolerance(tol)
        pde.setSymmetryOn()

        DIM=self.domain.getDim()
        x=self.domain.getX()
        q=es.whereZero(x[DIM-1]-es.inf(x[DIM-1]))
        for i in xrange(DIM-1):
            xi=x[i]
            q+=es.whereZero(xi-es.inf(xi))+es.whereZero(xi-es.sup(xi))
        A = self.secondaryConductivity * es.kronecker(self.domain)
        pde.setValue(A=A,q=q)

        delPhiSecondary = []
        delPhiPrimary = []
        delPhiTotal = []
        if(len(self.electrodes[0])==3):

            for i in range(self.numElectrodes-3):
                analyticRsOne=es.Data(0,(3,),es.ContinuousFunction(self.domain))
                analyticRsOne[0]=(coords[0]-self.electrodes[i][0])
                analyticRsOne[1]=(coords[1]-self.electrodes[i][1])
                analyticRsOne[2]=(coords[2])
                rsMagOne=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**0.5
                analyticRsTwo=es.Data(0,(3,),es.ContinuousFunction(self.domain))
                analyticRsTwo[0]=(coords[0]-self.electrodes[i+3][0])
                analyticRsTwo[1]=(coords[1]-self.electrodes[i+3][1])
                analyticRsTwo[2]=(coords[2])
                rsMagTwo=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**0.5
                rsMagOne+=(es.whereZero(rsMagOne)*0.0000001)
                rsMagTwo+=(es.whereZero(rsMagTwo)*0.0000001)
                analyticPrimaryPot=(self.current/(2*pi*primCon*rsMagOne))-(self.current/(2*pi*primCon*rsMagTwo))

                analyticRsOnePower=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**1.5
                analyticRsOnePower = analyticRsOnePower+(es.whereZero(analyticRsOnePower)*0.0001)
                analyticRsTwoPower=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**1.5
                analyticRsTwoPower = analyticRsTwoPower+(es.whereZero(analyticRsTwoPower)*0.0001)

                gradAnalyticPrimaryPot = es.Data(0,(3,),es.ContinuousFunction(self.domain))
                gradAnalyticPrimaryPot[0] =(self.current/(2*pi*primCon)) \
                        * ((-analyticRsOne[0]/analyticRsOnePower) \
                            + (analyticRsTwo[0]/analyticRsTwoPower))
                gradAnalyticPrimaryPot[1] =(self.current/(2*pi*primCon)) \
                        * ((-analyticRsOne[1]/analyticRsOnePower) \
                            + (analyticRsTwo[1]/analyticRsTwoPower))
                gradAnalyticPrimaryPot[2] =(self.current/(2*pi*primCon)) \
                        * ((-analyticRsOne[2]/analyticRsOnePower)
                            + (analyticRsTwo[2]/analyticRsTwoPower))
                X=(primCon-self.secondaryConductivity) * (gradAnalyticPrimaryPot)
                pde.setValue(X=X)
                u=pde.getSolution()
                loc=Locator(self.domain,[self.electrodes[i+1],self.electrodes[i+2]])
                valPrimary=loc.getValue(analyticPrimaryPot)
                valSecondary=loc.getValue(u)
                delPhiPrimary.append(valPrimary[1]-valPrimary[0])
                delPhiSecondary.append(valSecondary[1]-valSecondary[0])
                delPhiTotal.append(delPhiPrimary[i]+delPhiSecondary[i])
        else:
            raise NotImplementedError("2d forward model is not yet implemented")

        self.delPhiSecondary = delPhiSecondary
        self.delPhiPrimary = delPhiPrimary
        self.delPhiTotal=delPhiTotal
        return [delPhiPrimary, delPhiSecondary, delPhiTotal]
Exemple #22
0
    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
Exemple #23
0
    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 getPotential(self):
        """
        Returns 3 list each made up of a number of list containing primary, secondary and total
        potentials diferences. Each of the lists contain a list for each value of n.
        """

        primCon=self.primaryConductivity
        coords=self.domain.getX()
        pde=LinearPDE(self.domain, numEquations=1)
        tol=1e-8
        pde.getSolverOptions().setTolerance(tol)
        pde.setSymmetryOn()

        DIM=self.domain.getDim()
        x=self.domain.getX()
        q=whereZero(x[DIM-1]-inf(x[DIM-1]))
        for i in xrange(DIM-1):
            xi=x[i]
            q+=whereZero(xi-inf(xi))+whereZero(xi-sup(xi))
        A = self.secondaryConductivity * kronecker(self.domain)
        pde.setValue(A=A,q=q)

        delPhiSecondaryList = []
        delPhiPrimaryList = []
        delPhiTotalList = []
        for i in range(1,self.n+1): # 1 to n
            maxR = self.numElectrodes - 1 - i #max amount of readings that will fit in the survey
            delPhiSecondary = []
            delPhiPrimary = []
            delPhiTotal = []
            for j in range(maxR):
                analyticRs=Data(0,(3,),ContinuousFunction(self.domain))
                analyticRs[0]=(coords[0]-self.electrodes[j][0])
                analyticRs[1]=(coords[1]-self.electrodes[j][1])
                analyticRs[2]=(coords[2])
                rsMag=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**0.5
                analyticPrimaryPot=(self.current*(1./primCon))/(2*pi*(rsMag+(whereZero(rsMag)*0.0000001))) #the magic number 0.0000001 is to avoid devide by 0

                analyticRsPolePower=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**1.5
                analyticRsPolePower = analyticRsPolePower+(whereZero(analyticRsPolePower)*0.0000001)
                gradUPrimary = Data(0,(3,),ContinuousFunction(self.domain))
                gradUPrimary[0] =(self.current/(2*pi*primCon)) * (analyticRs[0]/analyticRsPolePower)
                gradUPrimary[1] =(self.current/(2*pi*primCon)) * (analyticRs[1]/analyticRsPolePower)
                gradUPrimary[2] =(self.current/(2*pi*primCon)) * (analyticRs[2]/analyticRsPolePower)
                gradUPrimary=-gradUPrimary
                X=(primCon-self.secondaryConductivity) * gradUPrimary
                pde.setValue(X=X)
                u=pde.getSolution()
                loc=Locator(self.domain,[self.electrodes[i+j],self.electrodes[i+j+1]])
                valPrimary=loc.getValue(analyticPrimaryPot)
                valSecondary=loc.getValue(u)
                delPhiPrimary.append(valPrimary[1]-valPrimary[0])
                delPhiSecondary.append(valSecondary[1]-valSecondary[0])
                delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j])

            delPhiPrimaryList.append(delPhiPrimary)
            delPhiSecondaryList.append(delPhiSecondary)
            delPhiTotalList.append(delPhiTotal)



        self.delPhiPrimaryList=delPhiPrimaryList
        self.delPhiSecondaryList=delPhiSecondaryList
        self.delPhiTotalList = delPhiTotalList

        return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
def RegionalCalculation(reg_mask):
    """
    Calculates the "regional" from the entire FEILDS model excluding the
    selected region and outputs gravity at the specified altitude...
    see above for the "residual"
    """

    # read in a gravity data grid to define data computation space
    G_DATA = os.path.join(DATADIR,'Final_BouguerTC_UC15K_qrtdeg.nc')
    FS=ReducedFunction(dom)
    nValues=[NX, NY, 1]
    first = [0, 0, cell_at_altitude]
    multiplier = [1, 1, 1]
    reverse = [0, 0, 0]
    byteorder = BYTEORDER_NATIVE
    gdata = readBinaryGrid(G_DATA, FS, shape=(),
                fill=-999999, byteOrder=byteorder,
                dataType=DATATYPE_FLOAT32, first=first, numValues=nValues,
                multiplier=multiplier, reverse=reverse)
    print("Grid successfully read")

    # get the masking and units sorted out for the data-space
    g_mask = whereNonZero(gdata+999999)

    gdata=gdata*g_mask * GRAV_UNITS

    # if people choose to have air in their region we exclude it from the
    # specified gravity calculation region
    if h_top < 0.:
        reg_mask = reg_mask+mask_air

    live_model = initial_model* whereNonPositive(reg_mask)
    dead_model = initial_model* wherePositive(reg_mask)

    if UseMean is True:
        # calculate the mean density within the selected region
        BackgroundDensity = integrate(dead_model)/integrate(wherePositive(reg_mask))
        print("Density mean for selected region equals = %s"%BackgroundDensity)

        live_model = live_model + BackgroundDensity * wherePositive(reg_mask)

    # create mapping
    rho_mapping = DensityMapping(dom, rho0=live_model)

    # invert sign of gravity field to account for escript's coordinate system
    gdata = -GRAV_UNITS * gdata

    # turn the scalars into vectors (vertical direction)
    d=kronecker(DIM)[DIM-1]
    w=safeDiv(1., g_mask)
    gravity_model=GravityModel(dom, w*d, gdata*d, fixPotentialAtBottom=False, coordinates=COORDINATES)
    gravity_model.rescaleWeights(rho_scale=rho_mapping.getTypicalDerivative())
    phi,_ = gravity_model.getArguments(live_model)
    g_init = -gravity_model.getCoordinateTransformation().getGradient(phi)
    g_init = interpolate(g_init, gdata.getFunctionSpace())
    print("Computed gravity: %s"%(g_init[2]))

    fn=os.path.join(OUTPUTDIR,'regional-gravity')
    if SiloOutput is True:
        saveSilo(fn, density=live_model, gravity_init=g_init, g_initz=-g_init[2], gravitymask=g_mask, modelmask=reg_mask)
        print('SILO file written with the following fields: density (kg/m^3), gravity vector (m/s^2), gz (m/s^2), gravitymask, modelmask')

    # to compare calculated data against input dataset.
    # Not used by default but should work if the input dataset is correct
    #gslice = g_init[2]*wherePositive(g_mask)
    #g_dash = integrate(gslice)/integrate(wherePositive(g_mask))
    #gdataslice = gdata*wherePositive(g_mask)
    #gdata_dash = integrate(gdataslice)/integrate(wherePositive(g_mask))
    #misfit=(gdataslice-gdata_dash)-(gslice-g_dash)
    saveDataCSV(fn+".csv", mask=g_mask, gz=-g_init[2], Long=datacoords[0], Lat=datacoords[1], h=datacoords[2])
    print('CSV file written with the following fields: Longitude (degrees) Latitude (degrees), h (100km), gz (m/s^2)')
Exemple #26
0
 def stress(self):
     """
     returns current stress"""
     return 2*self.viscosity*self.stretching-self.pressure*kronecker(self.domain)
    def getPotential(self):
        """
        Returns 3 list each made up of a number of list containing primary, secondary and total
        potentials diferences. Each of the lists contain a list for each value of n.
        """

        primCon=self.primaryConductivity
        coords=self.domain.getX()
        pde=LinearPDE(self.domain, numEquations=1)
        tol=1e-8
        pde.getSolverOptions().setTolerance(tol)
        pde.setSymmetryOn()

        DIM=self.domain.getDim()
        x=self.domain.getX()
        q=es.whereZero(x[DIM-1]-es.inf(x[DIM-1]))
        for i in xrange(DIM-1):
            xi=x[i]
            q+=es.whereZero(xi-es.inf(xi))+es.whereZero(xi-es.sup(xi))
        A = self.secondaryConductivity * es.kronecker(self.domain)
        pde.setValue(A=A,q=q)

        delPhiSecondaryList = []
        delPhiPrimaryList = []
        delPhiTotalList = []
        for i in range(1,self.n+1): # 1 to n
            maxR = self.numElectrodes - 1 - i #max amount of readings that will fit in the survey
            delPhiSecondary = []
            delPhiPrimary = []
            delPhiTotal = []
            for j in range(maxR):
                analyticRs=es.Data(0,(3,),es.ContinuousFunction(self.domain))
                analyticRs[0]=(coords[0]-self.electrodes[j][0])
                analyticRs[1]=(coords[1]-self.electrodes[j][1])
                analyticRs[2]=(coords[2])
                rsMag=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**0.5
                analyticPrimaryPot=(self.current*(1./primCon))/(2*pi*(rsMag+(es.whereZero(rsMag)*0.0000001))) #the magic number 0.0000001 is to avoid devide by 0

                analyticRsPolePower=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**1.5
                analyticRsPolePower = analyticRsPolePower+(es.whereZero(analyticRsPolePower)*0.0000001)
                gradUPrimary = es.Data(0,(3,),es.ContinuousFunction(self.domain))
                gradUPrimary[0] =(self.current/(2*pi*primCon)) * (analyticRs[0]/analyticRsPolePower)
                gradUPrimary[1] =(self.current/(2*pi*primCon)) * (analyticRs[1]/analyticRsPolePower)
                gradUPrimary[2] =(self.current/(2*pi*primCon)) * (analyticRs[2]/analyticRsPolePower)
                gradUPrimary=-gradUPrimary
                X=(primCon-self.secondaryConductivity) * gradUPrimary
                pde.setValue(X=X)
                u=pde.getSolution()
                loc=Locator(self.domain,[self.electrodes[i+j],self.electrodes[i+j+1]])
                valPrimary=loc.getValue(analyticPrimaryPot)
                valSecondary=loc.getValue(u)
                delPhiPrimary.append(valPrimary[1]-valPrimary[0])
                delPhiSecondary.append(valSecondary[1]-valSecondary[0])
                delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j])

            delPhiPrimaryList.append(delPhiPrimary)
            delPhiSecondaryList.append(delPhiSecondary)
            delPhiTotalList.append(delPhiTotal)



        self.delPhiPrimaryList=delPhiPrimaryList
        self.delPhiSecondaryList=delPhiSecondaryList
        self.delPhiTotalList = delPhiTotalList

        return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
    def getPotential(self):
        """
        returns a list containing 3 lists one for each the primary, secondary
        and total potential.
        """

        primCon=self.primaryConductivity
        coords=self.domain.getX()
        pde=LinearPDE(self.domain, numEquations=1)
        tol=1e-8
        pde.getSolverOptions().setTolerance(tol)
        pde.setSymmetryOn()

        DIM=self.domain.getDim()
        x=self.domain.getX()
        q=whereZero(x[DIM-1]-inf(x[DIM-1]))
        for i in xrange(DIM-1):
            xi=x[i]
            q+=whereZero(xi-inf(xi))+whereZero(xi-sup(xi))
        A = self.secondaryConductivity * kronecker(self.domain)
        pde.setValue(A=A,q=q)

        delPhiSecondary = []
        delPhiPrimary = []
        delPhiTotal = []
        if(len(self.electrodes[0])==3):

            for i in range(self.numElectrodes-3):
                analyticRsOne=Data(0,(3,),ContinuousFunction(self.domain))
                analyticRsOne[0]=(coords[0]-self.electrodes[i][0])
                analyticRsOne[1]=(coords[1]-self.electrodes[i][1])
                analyticRsOne[2]=(coords[2])
                rsMagOne=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**0.5
                analyticRsTwo=Data(0,(3,),ContinuousFunction(self.domain))
                analyticRsTwo[0]=(coords[0]-self.electrodes[i+3][0])
                analyticRsTwo[1]=(coords[1]-self.electrodes[i+3][1])
                analyticRsTwo[2]=(coords[2])
                rsMagTwo=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**0.5
                rsMagOne+=(whereZero(rsMagOne)*0.0000001)
                rsMagTwo+=(whereZero(rsMagTwo)*0.0000001)
                analyticPrimaryPot=(self.current/(2*pi*primCon*rsMagOne))-(self.current/(2*pi*primCon*rsMagTwo))

                analyticRsOnePower=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**1.5
                analyticRsOnePower = analyticRsOnePower+(whereZero(analyticRsOnePower)*0.0001)
                analyticRsTwoPower=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**1.5
                analyticRsTwoPower = analyticRsTwoPower+(whereZero(analyticRsTwoPower)*0.0001)

                gradAnalyticPrimaryPot = Data(0,(3,),ContinuousFunction(self.domain))
                gradAnalyticPrimaryPot[0] =(self.current/(2*pi*primCon)) \
                        * ((-analyticRsOne[0]/analyticRsOnePower) \
                            + (analyticRsTwo[0]/analyticRsTwoPower))
                gradAnalyticPrimaryPot[1] =(self.current/(2*pi*primCon)) \
                        * ((-analyticRsOne[1]/analyticRsOnePower) \
                            + (analyticRsTwo[1]/analyticRsTwoPower))
                gradAnalyticPrimaryPot[2] =(self.current/(2*pi*primCon)) \
                        * ((-analyticRsOne[2]/analyticRsOnePower)
                            + (analyticRsTwo[2]/analyticRsTwoPower))
                X=(primCon-self.secondaryConductivity) * (gradAnalyticPrimaryPot)
                pde.setValue(X=X)
                u=pde.getSolution()
                loc=Locator(self.domain,[self.electrodes[i+1],self.electrodes[i+2]])
                valPrimary=loc.getValue(analyticPrimaryPot)
                valSecondary=loc.getValue(u)
                delPhiPrimary.append(valPrimary[1]-valPrimary[0])
                delPhiSecondary.append(valSecondary[1]-valSecondary[0])
                delPhiTotal.append(delPhiPrimary[i]+delPhiSecondary[i])
        else:
            raise NotImplementedError("2d forward model is not yet implemented")

        self.delPhiSecondary = delPhiSecondary
        self.delPhiPrimary = delPhiPrimary
        self.delPhiTotal=delPhiTotal
        return [delPhiPrimary, delPhiSecondary, delPhiTotal]
Exemple #29
0
    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)
Exemple #30
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 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...")
        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)) ))
Exemple #31
0
 def stress(self):
     """
        returns current stress"""
     return 2 * self.viscosity * self.stretching - self.pressure * es.kronecker(
         self.domain)
Exemple #32
0
    def setup(self, domainbuilder,
                    rho0=None, drho=None, z0=None, beta=None,
                    w0=None, w1=None, rho_at_depth=None):
        """
        Sets up the inversion parameters from a `DomainBuilder`.

        :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 z0: reference depth for depth weighting, see `DensityMapping`. If not specified, zero is used.
        :type z0: ``float`` or ``Scalar``
        :param beta: exponent for  depth weighting, see `DensityMapping`. 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 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()
        trafo=makeTransformation(dom, domainbuilder.getReferenceSystem())
        DIM=dom.getDim()
        rho_mask = domainbuilder.getSetDensityMask()
        #========================
        self.logger.info('Creating mapping...')
        if rho_at_depth:
            rho2 = rho_mask * rho_at_depth + (1-rho_mask) * rho0
        elif rho0:
            rho2 = (1-rho_mask) * rho0
        else:
            rho2 = 0.

        rho_mapping=DensityMapping(dom, rho0=rho2, drho=drho, z0=z0, beta=beta)
        scale_mapping=rho_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=rho_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 model...")
        forward_model=GravityModel(dom, w, g, fixPotentialAtBottom=self._fixGravityPotentialAtBottom, coordinates=trafo)
        forward_model.rescaleWeights(rho_scale=scale_mapping)

        #====================================================================
        self.logger.info("Setting cost function...")
        self.setCostFunction(InversionCostFunction(regularization, rho_mapping, forward_model))