Exemplo n.º 1
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")
Exemplo n.º 2
0
    def __setBoundaryMask(self, X):
        """
    DESCRIPTION:
    -----------
    Define Dirichlet model boundaries conditions.

    ARGUMENTS:
    ----------
    X :: escript object with all coordinates

    RETURNS:
    --------
    boundary_mask :: escript object with mask values at boundaries

    """
        # Boundaries are defined as masks (1 or 0) for all mesh coordinates;
        # values at the boundary are '1', whereas all other values are '0'.
        mask_l = escript.whereZero(X[0] - escript.inf(X[0]))
        mask_r = escript.whereZero(X[0] - escript.sup(X[0]))
        mask_t = escript.whereZero(X[1] - escript.inf(X[1]))
        mask_b = escript.whereZero(X[1] - escript.sup(X[1]))

        # Combine the mask for all boundaries:
        boundary_mask = mask_t + mask_b + mask_l + mask_r

        return boundary_mask
Exemplo n.º 3
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")
Exemplo n.º 4
0
    def getInverse(self, s):
        """
        returns the value of the inverse of the mapping for s
        """
        if not (inf(s) > self.s_min and sup(s) < self.s_max):
            raise ValueError("s is out of range [%f,%f]" % (inf(s), sup(s)))

        return 1. / 2. * log((s - self.s_min) / (self.s_max - s))
Exemplo n.º 5
0
    def getInverse(self, s):
        """
        returns the value of the inverse of the mapping for s
        """
        if not (inf(s) > self.s_min and sup(s) < self.s_max):
            raise ValueError("s is out of range [%f,%f]" % (inf(s), sup(s)))

        return 1.0 / 2.0 * log((s - self.s_min) / (self.s_max - s))
    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 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 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 checkBounds(self):
     X = ContinuousFunction(self.domain).getX()
     xDim=[inf(X[0]),sup(X[0])]
     yDim=[inf(X[1]),sup(X[1])]
     zDim=[inf(X[2]),sup(X[2])]
     for i in range(self.numElectrodes):
         if (self.electrodes[i][0] < xDim[0] or self.electrodes[i][0] > xDim[1]
                 or self.electrodes[i][1] < yDim[0] or self.electrodes[i][1] > yDim[1]):
             print (self.electrodes[i])
             raise ValueError("Electrode setup extents past domain dimentions")
 def checkBounds(self):
     X = es.ContinuousFunction(self.domain).getX()
     xDim=[es.inf(X[0]),es.sup(X[0])]
     yDim=[es.inf(X[1]),es.sup(X[1])]
     zDim=[es.inf(X[2]),es.sup(X[2])]
     for i in range(self.numElectrodes):
         if (self.electrodes[i][0] < xDim[0] or self.electrodes[i][0] > xDim[1]
                 or self.electrodes[i][1] < yDim[0] or self.electrodes[i][1] > yDim[1]):
             print (self.electrodes[i])
             raise ValueError("Electrode setup extents past domain dimentions")
Exemplo n.º 12
0
 def getValue(self, m):
     print("in get value inf(m)=", inf(m), " sup(m)=", sup(m))
     # s=self.__sigma0 + (self.__sigma0 * self.__k*m)
     # s=self.__sigma0*exp(self.__k*m)
     #### use sigmoid mapping
     s = (self.__sigma0 * self.a / (1 + exp(-self.__k * m))) + self.minVal
     print("in get value inf(s)=", inf(s), " sup(s)=", sup(s))
     if sup(s) != 0 and inf(s) != 0:
         print("in get value 1/inf(s)=", 1.0 / inf(s), " 1/sup(s)=", 1.0 / sup(s))
     return s
Exemplo n.º 13
0
 def __setOutput(self):
     x = self.domain.getX()
     self.__location_of_constraint = es.Scalar(0, x.getFunctionSpace())
     if self.domain.getDim() == 3:
         vertex = [es.inf(x[0]), es.inf(x[1]), es.inf(x[2])]
     else:
         vertex = [es.inf(x[0]), es.inf(x[1])]
     self.__location_of_constraint = es.whereZero(es.length(x - vertex),
                                                  self.tol)
     if not self.value is None:
         self.__value_of_constraint = self.__location_of_constraint * self.value
Exemplo n.º 14
0
 def getValue(self, m):
     print("in get value inf(m)=", inf(m), " sup(m)=", sup(m))
     # s=self.__sigma0 + (self.__sigma0 * self.__k*m)
     # s=self.__sigma0*exp(self.__k*m)
     #### use sigmoid mapping
     s = (self.__sigma0 * self.a / (1 + exp(-self.__k * m))) + self.minVal
     print("in get value inf(s)=", inf(s), " sup(s)=", sup(s))
     if sup(s) != 0 and inf(s) != 0:
         print("in get value 1/inf(s)=", 1. / inf(s), " 1/sup(s)=",
               1. / sup(s))
     return s
Exemplo n.º 15
0
 def __setOutput(self):
     if self.__location_of_constraint is None:
         x = self.domain.getX()
         val = self.value
         if isinstance(val, int) or isinstance(val, float):
             shape = ()
         elif isinstance(val, list) or isinstance(val, tuple):
             shape = (len(val), )
         elif isinstance(val, numpy.ndarray):
             shape = val.shape
         elif val is None:
             shape = ()
         else:
             shape = val.getShape()
         self.__location_of_constraint = Data(0, shape,
                                              x.getFunctionSpace())
         if self.domain.getDim() == 3:
             x0, x1, x2 = x[0], x[1], x[2]
             if self.left:
                 self.__location_of_constraint += es.whereZero(
                     x0 - es.inf(x0), self.tol)
             if self.right:
                 self.__location_of_constraint += es.whereZero(
                     x0 - es.sup(x0), self.tol)
             if self.front:
                 self.__location_of_constraint += es.whereZero(
                     x1 - es.inf(x1), self.tol)
             if self.back:
                 self.__location_of_constraint += es.whereZero(
                     x1 - es.sup(x1), self.tol)
             if self.bottom:
                 self.__location_of_constraint += es.whereZero(
                     x2 - es.inf(x2), self.tol)
             if self.top:
                 self.__location_of_constraint += es.whereZero(
                     x2 - es.sup(x2), self.tol)
         else:
             x0, x1 = x[0], x[1]
             if self.left:
                 self.__location_of_constraint += es.whereZero(
                     x0 - es.inf(x0), self.tol)
             if self.right:
                 self.__location_of_constraint += es.whereZero(
                     x0 - es.sup(x0), self.tol)
             if self.bottom:
                 self.__location_of_constraint += es.whereZero(
                     x1 - es.inf(x1), self.tol)
             if self.top:
                 self.__location_of_constraint += es.whereZero(
                     x1 - es.sup(x1), self.tol)
         if not self.value is None:
             self.__value_of_constraint = self.__location_of_constraint * self.value
Exemplo n.º 16
0
def toRegGrid(u, nx=50, ny=50):
   """
   returns a nx x ny grid representation of the escript object u
   """
   xx=u.getDomain().getX()     
   x=u.getFunctionSpace().getX()     
   coordX, coordY = toXYTuple(x)
   utemp = u.toListOfTuples()
   # create regular grid
   xi = np.linspace(inf(xx[0]),sup(xx[0]),nx)
   yi = np.linspace(inf(xx[1]),sup(xx[1]),ny)

   # interpolate u to grid
   zi = pl.matplotlib.mlab.griddata(coordX,coordY,utemp,xi,yi, interp='linear')
   return xi, yi, zi
Exemplo n.º 17
0
    def __init__(self,
                 domain,
                 v_p,
                 wavelet,
                 source_tag,
                 dt=None,
                 p0=None,
                 p0_t=None,
                 absorption_zone=300 * U.m,
                 absorption_cut=1e-2,
                 lumping=True):
        """
           initialize the sonic wave solver

           :param domain: domain of the problem
           :type domain: `Domain`
           :param v_p: p-velocity field
           :type v_p: `escript.Scalar`
           :param wavelet: wavelet to describe the time evolution of source term
           :type wavelet: `Wavelet`
           :param source_tag: tag of the source location
           :type source_tag: 'str' or 'int'
           :param dt: time step size. If not present a suitable time step size is calculated.
           :param p0: initial solution. If not present zero is used.
           :param p0_t: initial solution change rate. If not present zero is used.
           :param absorption_zone: thickness of absorption zone
           :param absorption_cut: boundary value of absorption decay factor
           :param lumping: if True mass matrix lumping is being used. This is accelerates the computing but introduces some diffusion.
           """
        f = createAbsorptionLayerFunction(
            escript.Function(domain).getX(), absorption_zone, absorption_cut)
        v_p = v_p * f

        if p0 == None:
            p0 = escript.Scalar(0., escript.Solution(domain))
        else:
            p0 = escript.interpolate(p0, escript.Solution(domain))

        if p0_t == None:
            p0_t = escript.Scalar(0., escript.Solution(domain))
        else:
            p0_t = escript.interpolate(p0_t, escript.Solution(domain))

        if dt == None:
            dt = min(escript.inf((1. / 5.) * domain.getSize() / v_p),
                     wavelet.getTimeScale())

        super(SonicWave, self).__init__(dt, u0=p0, v0=p0_t, t0=0.)

        self.__wavelet = wavelet
        self.__mypde = lpde.LinearSinglePDE(domain)
        if lumping:
            self.__mypde.getSolverOptions().setSolverMethod(
                lpde.SolverOptions.HRZ_LUMPING)
        self.__mypde.setSymmetryOn()
        self.__mypde.setValue(D=1. / v_p**2)
        self.__source_tag = source_tag
        self.__r = escript.Scalar(
            0., escript.DiracDeltaFunctions(self.__mypde.getDomain()))
Exemplo n.º 18
0
 def getSafeTimeStepSize(self, dt):
     """
        returns new step size
        """
     h = self.domain.getSize()
     return self.safety_factor * inf(
         h**2 / (h * abs(self.heat_capacity * self.density) *
                 length(self.velocity) + self.thermal_permabilty))
Exemplo n.º 19
0
 def doStepPostprocessing(self,dt):
     """
     perform taylor galerkin step
     """
     T=self.temperature
     self.__rhocp=self.heat_capacity*self.density
     self.__fixed_T=self.fixed_temperature
     self.temperature=dt*self.G(dt/2*self.G(T,1./dt)+T,1./dt)+T
     self.trace("Temperature range is %e %e"%(inf(self.temperature),sup(self.temperature)))
Exemplo n.º 20
0
def toRegGrid(u, nx=50, ny=50):
    """
   returns a nx x ny grid representation of the escript object u
   """
    xx = u.getDomain().getX()
    x = u.getFunctionSpace().getX()
    coordX, coordY = toXYTuple(x)
    utemp = u.toListOfTuples()
    # create regular grid
    xi = np.linspace(inf(xx[0]), sup(xx[0]), nx)
    yi = np.linspace(inf(xx[1]), sup(xx[1]), ny)

    # interpolate u to grid
    #zi = pl.matplotlib.mlab.griddata(coordX,coordY,utemp,xi,yi, interp='linear')
    zi = interpolate.griddata((coordX, coordY),
                              utemp, (xi[None, :], yi[:, None]),
                              method='linear')
    return xi, yi, zi
Exemplo n.º 21
0
 def __setOutput(self):
     x = self.domain.getX()
     self.__location_of_constraint = es.Vector(0, x.getFunctionSpace())
     if self.domain.getDim() == 3:
         vertex = [es.inf(x[0]), es.inf(x[1]), es.inf(x[2])]
         msk = numpy.zeros((3, ))
         if self.comp_mask[0]: msk[0] = 1
         if self.comp_mask[1]: msk[1] = 1
         if self.comp_mask[2]: msk[2] = 1
     else:
         vertex = [es.inf(x[0]), es.inf(x[1])]
         msk = numpy.zeros((2, ))
         if self.comp_mask[0]: msk[0] = 1
         if self.comp_mask[1]: msk[1] = 1
     self.__location_of_constraint = es.whereZero(
         es.length(x - vertex), self.tol) * numpy.ones(shape)
     if not self.value is None:
         self.__value_of_constraint = self.__location_of_constraint * self.value
Exemplo n.º 22
0
 def __setOutput(self):
     x = self.domain.getX()
     self.__location_of_constraint = es.Scalar(0, x.getFunctionSpace())
     if self.domain.getDim() == 3:
         x0, x1, x2 = x[0], x[1], x[2]
         d = max(
             es.sup(x0) - es.inf(x0),
             sup(x1) - es.inf(x1),
             sup(x2) - es.inf(x2))
         if self.left:
             self.__location_of_constraint += es.whereZero(
                 x0 - es.inf(x0), self.tol * d)
         if self.right:
             self.__location_of_constraint += es.whereZero(
                 x0 - es.sup(x0), self.tol * d)
         if self.front:
             self.__location_of_constraint += es.whereZero(
                 x1 - es.inf(x1), self.tol * d)
         if self.back:
             self.__location_of_constraint += es.whereZero(
                 x1 - es.sup(x1), self.tol * d)
         if self.bottom:
             self.__location_of_constraint += es.whereZero(
                 x2 - es.inf(x2), self.tol * d)
         if self.top:
             self.__location_of_constraint += es.whereZero(
                 x2 - es.sup(x2), self.tol * d)
     else:
         x0, x1 = x[0], x[1]
         d = max(es.sup(x0) - es.inf(x0), es.sup(x1) - es.inf(x1))
         if self.left:
             self.__location_of_constraint += es.whereZero(
                 x0 - es.inf(x0), self.tol * d)
         if self.right:
             self.__location_of_constraint += es.whereZero(
                 x0 - es.sup(x0), self.tol * d)
         if self.bottom:
             self.__location_of_constraint += es.whereZero(
                 x1 - es.inf(x1), self.tol * d)
         if self.top:
             self.__location_of_constraint += es.whereZero(
                 x1 - es.sup(x1), self.tol * d)
     if not self.value is None:
         self.__value_of_constraint = self.__location_of_constraint * self.value
Exemplo n.º 23
0
    def out(self):
        """
        values at domain locations by bilinear interpolation of the given values.

        Link against this method to get the output of this model.
        """
        x = self.domain.getX()
        if self.domain.getDim() == 2:
            x0, x1 = x[0], x[1]
            left_bottom_front0, right_top_back0 = inf(x0), sup(x0)
            left_bottom_front1, right_top_back1 = inf(x1), sup(x1)
            f_right = (x0 - left_bottom_front0) / (right_top_back0 -
                                                   left_bottom_front0)
            f_left = 1. - f_right
            f_top = (x1 - left_bottom_front1) / (right_top_back1 -
                                                 left_bottom_front1)
            f_bottom = 1. - f_top
            out = f_left * f_bottom * self.value_left_bottom_front \
                + f_right * f_bottom * self.value_right_bottom_front \
                + f_left * f_top * self.value_left_top_front \
                + f_right * f_top * self.value_right_top_front
        else:
            x0, x1, x2 = x[0], x[1], x[2]
            left_bottom_front0, right_top_back0 = inf(x0), sup(x0)
            left_bottom_front1, right_top_back1 = inf(x1), sup(x1)
            left_bottom_front2, right_top_back2 = inf(x2), sup(x2)
            f_right = (x0 - left_bottom_front0) / (right_top_back0 -
                                                   left_bottom_front0)
            f_left = 1. - f_right
            f_top = (x1 - left_bottom_front1) / (right_top_back1 -
                                                 left_bottom_front1)
            f_bottom = 1. - f_top
            f_back = (x2 - left_bottom_front1) / (right_top_back2 -
                                                  left_bottom_front2)
            f_front = 1. - f_back
            out = f_left * f_bottom * f_front * self.value_left_bottom_front\
                + f_right * f_bottom * f_front * self.value_right_bottom_front\
                + f_left * f_top * f_front * self.value_left_top_front\
                + f_right * f_top * f_front * self.value_right_top_front\
                + f_left * f_bottom * f_back * self.value_left_bottom_back\
                + f_right * f_bottom * f_back * self.value_right_bottom_back\
                + f_left * f_top * f_back * self.value_left_top_back\
                + f_right * f_top * f_back * self.value_right_top_back
        return out
Exemplo n.º 24
0
def subsample(u, nx=50, ny=50):
    """
    subsamples ```u``` over an ```nx``` x ```ny``` grid
    and returns ``numpy`` arrays for the values and locations
    used for subsampling.
    """
    xx = u.getDomain().getX()  # points of the domain
    x0 = inf(xx[0])
    y0 = inf(xx[1])
    dx = (sup(xx[0]) - x0) / nx  # x spacing
    dy = (sup(xx[1]) - y0) / ny  # y spacing
    grid = []
    for j in range(0, ny - 1):
        for i in range(0, nx - 1):
            grid.append([x0 + dx / 2 + dx * i, y0 + dy / 2 + dy * j])
    uLoc = Locator(u.getFunctionSpace(), grid)
    subu = uLoc(u)  # get data of u at sample points closests to grid points
    usublocs = uLoc.getX()  #returns actual locations from data
    return np.array(usublocs), np.array(subu)
Exemplo n.º 25
0
def subsample(u, nx=50, ny=50):
    """
    subsamples ```u``` over an ```nx``` x ```ny``` grid
    and returns ``numpy`` arrays for the values and locations
    used for subsampling.
    """
    xx=u.getDomain().getX()  # points of the domain
    x0=inf(xx[0])         
    y0=inf(xx[1])
    dx = (sup(xx[0])-x0)/nx # x spacing
    dy = (sup(xx[1])-y0)/ny # y spacing
    grid = [ ] 
    for j in range(0,ny-1):
        for i in range(0,nx-1):
               grid.append([x0+dx/2+dx*i,y0+dy/2+dy*j])
    uLoc = Locator(u.getFunctionSpace(),grid)
    subu= uLoc(u) # get data of u at sample points closests to grid points
    usublocs = uLoc.getX() #returns actual locations from data
    return np.array(usublocs), np.array(subu)
Exemplo n.º 26
0
 def getInverse(self, s):
     """
     returns the value of the inverse of the mapping for s
     """
     # return (s-self.__sigma0) / (self.__sigma0 * self.__k)
     if inf(((self.__sigma0 * self.a) / s)) <= 1.0:
         raise ValueError("sigma 0*a/s < 1 this is not valid as log cannot be 0 or negative")
     m = -1.0 / self.__k * log(((self.__sigma0 * self.a) / (s - self.minVal)) - 1)
     print("inv(s)=", m)
     return m
Exemplo n.º 27
0
 def doStepPostprocessing(self, dt):
     """
        perform taylor galerkin step
        """
     T = self.temperature
     self.__rhocp = self.heat_capacity * self.density
     self.__fixed_T = self.fixed_temperature
     self.temperature = dt * self.G(dt / 2 * self.G(T, 1. / dt) + T,
                                    1. / dt) + T
     self.trace("Temperature range is %e %e" %
                (inf(self.temperature), sup(self.temperature)))
Exemplo n.º 28
0
 def getInverse(self, s):
     """
     returns the value of the inverse of the mapping for s
     """
     # return (s-self.__sigma0) / (self.__sigma0 * self.__k)
     if inf(((self.__sigma0 * self.a) / s)) <= 1.:
         raise ValueError(
             "sigma 0*a/s < 1 this is not valid as log cannot be 0 or negative"
         )
     m = -1. / self.__k * log(((self.__sigma0 * self.a) /
                               (s - self.minVal)) - 1)
     print("inv(s)=", m)
     return m
Exemplo n.º 29
0
 def __setOutput(self):
     if self.__location_of_constraint is None:
         x = self.domain.getX()
         val = self.value
         if isinstance(val, int) or isinstance(val, float):
             shape = ()
         elif isinstance(val, list) or isinstance(val, tuple):
             shape = (len(val), )
         elif isinstance(val, numpy.ndarray):
             shape = val.shape
         elif val is None:
             shape = ()
         else:
             shape = val.getShape()
         if self.domain.getDim() == 3:
             vertex = [es.inf(x[0]), es.inf(x[1]), es.inf(x[2])]
         else:
             vertex = [es.inf(x[0]), es.inf(x[1])]
         self.__location_of_constraint = es.whereZero(
             es.length(x - vertex), self.tol) * numpy.ones(shape)
         if not self.value is None:
             self.__value_of_constraint = self.__location_of_constraint * self.value
Exemplo n.º 30
0
    def out(self):
        """
        values at domain locations by bilinear interpolation of the given values.

        Link against this method to get the output of this model.
        """
        x = self.domain.getX()
        if self.domain.getDim() == 2:
            x0,x1=x[0],x[1]
            left_bottom_front0,right_top_back0=inf(x0),sup(x0)
            left_bottom_front1,right_top_back1=inf(x1),sup(x1)
            f_right = (x0 - left_bottom_front0)/(right_top_back0 -left_bottom_front0)
            f_left = 1. - f_right
            f_top = (x1 - left_bottom_front1)/(right_top_back1 - left_bottom_front1)
            f_bottom = 1. - f_top
            out = f_left * f_bottom * self.value_left_bottom_front \
                + f_right * f_bottom * self.value_right_bottom_front \
                + f_left * f_top * self.value_left_top_front \
                + f_right * f_top * self.value_right_top_front
        else:
            x0,x1,x2=x[0],x[1],x[2]
            left_bottom_front0,right_top_back0=inf(x0),sup(x0)
            left_bottom_front1,right_top_back1=inf(x1),sup(x1)
            left_bottom_front2,right_top_back2=inf(x2),sup(x2)
            f_right = (x0 - left_bottom_front0)/(right_top_back0 - left_bottom_front0)
            f_left = 1. - f_right
            f_top = (x1 - left_bottom_front1)/(right_top_back1 - left_bottom_front1)
            f_bottom = 1. - f_top
            f_back = (x2 - left_bottom_front1)/(right_top_back2 - left_bottom_front2)
            f_front = 1. - f_back
            out = f_left * f_bottom * f_front * self.value_left_bottom_front\
                + f_right * f_bottom * f_front * self.value_right_bottom_front\
                + f_left * f_top * f_front * self.value_left_top_front\
                + f_right * f_top * f_front * self.value_right_top_front\
                + f_left * f_bottom * f_back * self.value_left_bottom_back\
                + f_right * f_bottom * f_back * self.value_right_bottom_back\
                + f_left * f_top * f_back * self.value_left_top_back\
                + f_right * f_top * f_back * self.value_right_top_back
        return out
 def test_geodetic_domain(self):
     COORDINATES = WGS84ReferenceSystem()
     db = DomainBuilder(reference_system=COORDINATES)
     source1a = NetCdfData(DataSource.GRAVITY,
                           NC_DATA1,
                           scale_factor=1.,
                           reference_system=COORDINATES)
     db.addSource(source1a)
     db.setVerticalExtents(depth=20000., air_layer=30000., num_cells=10)
     dom = db.getDomain()
     x = dom.getX()
     self.assertAlmostEqual(inf(x[0]),
                            120.2,
                            delta=0.001,
                            msg="phi range wrong")
     self.assertAlmostEqual(inf(x[1]),
                            -29.2,
                            delta=0.0001,
                            msg="lambda range wrong")
     self.assertAlmostEqual(inf(x[2]),
                            -0.2,
                            msg="h range wrong" + str(x[2]))
     # Cannot check upper bounds of coordinates with more than 1 rank
     # because ripley may adjust internally.
     if getMPISizeWorld() == 1:
         self.assertAlmostEqual(sup(x[0]),
                                120.3,
                                delta=0.001,
                                msg="phi range wrong")
         self.assertAlmostEqual(sup(x[1]),
                                -29.1,
                                delta=0.0001,
                                msg="lambda range wrong")
         self.assertAlmostEqual(sup(x[2]),
                                0.3,
                                msg="h range wrong: " + str(x[2]))
Exemplo n.º 32
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)
Exemplo n.º 33
0
    def __getBoundaryValues(self, mode, X, rho_1d, ifc_1d, xstep, zstep,
                            frequency):
        """
    DESCRIPTION:
    -----------
    Returns a list with boundary values along each Dirichlet boundary.
    Values at the left and right side of the domain are evaluated at
    sample points and interpolated across the domain. The subroutine
    expects that layers at the right- and left-hand-side are defined.

    ARGUMENTS:
    ----------
    mode      :: string with TE or TM mode
    X         :: escript object with all coordinates
    rho_1d    :: dictionary with resistivities at the left/right boundary
    ifc_1d    :: dictionary with layer interfaces at the left/right boundary
    xstep     :: number with step size for horizontal sample list
    zstep     :: number with step size for vertical sample list
    frequency :: number with actual sounding frequency

    RETURNS:
    --------
    bondary_value :: dictionary with lists of boundary values at sample points
    """

        # ---
        # Sample lists at vertical and horizontal boundaries.
        # ---

        # Horizontal extents:
        xmin = escript.inf(X[0])
        xmax = escript.sup(X[0])

        # Vertical extents:
        zmin = escript.inf(X[1])
        zmax = escript.sup(X[1])

        # Setup a list with sample points along the vertical mesh extent, bottom to top:
        zsamples = self.__getSamplePoints(-zmax, -zmin, zstep)

        # ---
        # Calculate the 1D response at the left- and right-hand-side boundaries
        # ---

        # Instantiate an 'mt1d' object for the left- and right-hand-sides:
        mt1d_left = mt1d.MT_1D(frequency, ifc_1d['left'], rho_1d['left'],
                               zsamples)
        mt1d_rght = mt1d.MT_1D(frequency, ifc_1d['right'], rho_1d['right'],
                               zsamples)

        # Compute the 1D field values at the sample nodes:
        te1d_left, tm1d_left = mt1d_left.mt1d()
        te1d_rght, tm1d_rght = mt1d_rght.mt1d()

        # Distinguish TE and TM mode and save 1D values in dictionary:
        if mode.upper() == "TE":
            mt_1d = {"left": te1d_left, "right": te1d_rght}
        else:
            mt_1d = {"left": tm1d_left, "right": tm1d_rght}

        # ---
        # Interpolation across mesh.
        # ---

        # Now setup a 2D-table from left to right at each sampled depth for mesh-interpolation.
        table2d_real = []
        table2d_imag = []

        # 1D-interpolation of values from left to right at different depths 'i':
        for i in range(len(zsamples)):
            table2d_real.append(
                self.__interpolLinear(xstep, xmin, xmax, mt_1d["left"].real[i],
                                      mt_1d["right"].real[i]))
            table2d_imag.append(
                self.__interpolLinear(xstep, xmin, xmax, mt_1d["left"].imag[i],
                                      mt_1d["right"].imag[i]))

        # 2D-interpolation to map the values on the mesh coordinates:
        bondary_value_real = escript.interpolateTable(table2d_real, X,
                                                      (xmin, zmin),
                                                      (xstep, zstep))
        bondary_value_imag = escript.interpolateTable(table2d_imag, X,
                                                      (xmin, zmin),
                                                      (xstep, zstep))

        # Return the real and imaginary values as a dictionary:
        boundary_value = {
            "real": bondary_value_real,
            "imag": bondary_value_imag
        }

        return boundary_value
Exemplo n.º 34
0
    def __init__(self,
                 domain,
                 mode,
                 freq_def,
                 tags,
                 rho,
                 rho_1d,
                 ifc_1d,
                 xstep=100,
                 zstep=100,
                 maps=None,
                 plot=False,
                 limits=None):
        """
    DESCRIPTION:
    ------------
    Constructor which initialises the 2D magnetotelluric class:
    (*) check for argument type
    (*) check for valid argument values
    (*) initialises required values

    ARGUMENTS:
    ----------
    param  domain       :: the 2d mesh domain
    type   domain       :: ``escript data object``

    param  mode         :: TE or TM mode
    type   mode         :: ``string``

    param  freq_def     :: highest/lowest frequency & points per decade
    type   freq_def     :: ``dictionary``

    param  tags         :: the tag names of the regions defined in the mesh
    type   tags         :: ``list``

    param  rho          :: the resistivity values of the regions in the mesh
    type   rho          :: ``list``

    param  rho_1d       :: the resistivity values at the left & right boundary
    type   rho_1d       :: ``dictionary``

    param  ifc_1d       :: the layer interface depths of the left & right boundary
    type   ifc_1d       :: ``dictionary``

    param  xstep        :: user-defined step size for horizontal sample list
    type   xstep        :: ``number``  (optional)

    param  zstep        :: user-defined step size for vertical sample list
    type   zstep        :: ``number``  (optional)

    param  maps         :: list with user-defined  functions which map the resistivity for each region
    type   maps         :: ``list``    (optional)

    param  plot         :: user-defined flag to show a plot of apparent resistivity and phase at each frequency
    type   plot         :: ``boolean`` (optional)



    DATA ATTRIBUTES:
    ----------------
    self.domain         :: escript data object of mesh
    self.X              :: escript data object with all mesh coordinates
    self.mode           :: string with TE or TM mode
    self.xmin           :: float with x-coordinate minimum
    self.xmax           :: float with x-coordinate maximum
    self.zmin           :: float with z-coordinate minimum
    self.zmax           :: float with z-coordinate maximum
    self.zstep          :: number with sample step in vertical direction
    self.xstep          :: number with sample step in horizontal direction
    self.rho            :: list with resistivity values of all regions
    self.rho_1d         :: dictionary with resistivity values at boundaries left/right
    self.ifc_1d         :: dictionary with interface depths at boundaries left/right
    self.plot           :: boolean flag to show plots of apparent resistivity and phase
    self.sigma          :: escript data object with the conductivity model (based on 'rho' and 'maps')
    self.frequencies    :: list of sounding frequencies
    self.boundary_mask  :: Dirichlet mask at boundaries
    """

        if not HAVE_FINLEY:
            raise ImportError("Finley module not available")
        #make python3 compatible, since long disappeared in python 3
        if sys.version_info[0] == 3:
            long_type = int
        else:
            long_type = long
        # ---
        # Checks
        # ---

        # Types:
        if not isinstance(domain, escript.Domain):
            raise ValueError("Input parameter DOMAIN must be an Escript mesh")
        if not isinstance(mode, str):
            raise ValueError("Input parameter MODE must be a string")
        if not isinstance(freq_def, dict) or len(freq_def) != 3:
            raise ValueError(
                "Input parameter FREQ_DEF must be a dictionary with length 3")
        if not isinstance(tags, list) or not all(
                isinstance(t, str) for t in tags):
            raise ValueError("Input parameter TAGS must be a list of strings")
        if not isinstance(rho, list) or not all(
                isinstance(d, (int, long_type, float)) for d in rho):
            raise ValueError("Input parameter RHO must be a list of numbers")
        if not isinstance(rho_1d, dict) or len(rho_1d) != 2:
            raise ValueError(
                "Input parameter RHO_1D must be a dictionary with length 2")
        if not isinstance(ifc_1d, dict) or len(ifc_1d) != 2:
            raise ValueError(
                "Input parameter IFC_1D must be a dictionary with length 2")
        if not isinstance(xstep, (int, long_type, float)):
            raise ValueError("Optional input parameter XSTEP must be a number")
        if not isinstance(zstep, (int, long_type, float)):
            raise ValueError("Optional input parameter ZSTEP must be a number")
        if maps is not None:
            if not isinstance(maps, list) or not all(
                    isinstance(m, (types.FunctionType, types.NoneType))
                    for m in maps):
                raise ValueError(
                    "Optional input parameter MAPS must be a list of Functions or Nones"
                )
        if plot is not None:
            if not isinstance(plot, bool):
                raise ValueError(
                    "Optional input parameter PLOT must be True or False")

        # Values:
        if mode.upper() != "TE" and mode.upper() != "TM":  # Check mode:
            raise ValueError(
                "Input parameter mode must be either 'TE' or 'TM'")
        if not 'high' in freq_def and not 'low' in freq_def and not 'step' in freq_def:
            raise ValueError(
                "Input dictionary FREQ_DEF must have keys 'high', 'low' and 'step' defined"
            )
        if freq_def['high'] < freq_def['low']:
            raise ValueError(
                "High frequency value is smaller than low frequency value in input parameter FREQ_DEF"
            )
        if freq_def['step'] < 1:
            raise ValueError(
                "Step frequency value is smaller than 1 in input parameter FREQ_DEF"
            )
        if not all(r > 0 for r in rho):  # Check resistivity values:
            raise ValueError("Input parameter RHO must be all positive")
        if len(rho) != len(tags):  # Check resistivity list-length:
            raise ValueError(
                "Input parameter RHO must have the same length as input parameter TAGS"
            )
        if not 'left' in rho_1d and not 'right' in rho_1d:
            raise ValueError(
                "Input dictionary RHO_1D must have keys 'left' and 'right' defined"
            )
        if not 'left' in ifc_1d and not 'right' in ifc_1d:
            raise ValueError(
                "Input dictionary IFC_1D must have keys 'left' and 'right' defined"
            )
        if len(ifc_1d['left']) - 1 != len(rho_1d['left']) and len(
                ifc_1d['right']) - 1 != len(rho_1d['right']):
            raise ValueError(
                "Lists with values in input dictionary RHO_1D must have length equal to IFC_1D"
            )
        if xstep < 0.5:  # Step size should be non-zero but should not be smaller than 0.5m:
            raise ValueError("Input parameter XSTEP must be at least 0.5")
        if zstep < 0.5:  # Step size should be non-zero but should not be smaller than 0.5m:
            raise ValueError("Input parameter ZSTEP must be at least 0.5")

        # ---
        # Domain coordinates & tags:
        # ---

        # Extract the model coordinates..
        X = escript.Solution(domain).getX()

        # Get the Min/Max coordinates:
        xmin = escript.inf(X[0])
        xmax = escript.sup(X[0])
        zmin = escript.inf(X[1])
        zmax = escript.sup(X[1])

        # Get the tag names from the mesh file
        mesh_tags = escript.getTagNames(domain)

        if xmin >= xmax or zmin >= zmax:
            raise ValueError("The mesh limits are not valid (min >= max)")
        if zmin >= 0:
            raise ValueError(
                "The mesh must be defined with a negative vertical axis")
        if not set(mesh_tags) == set(tags):
            print("user-tags:", tags)
            print("mesh-tags:", mesh_tags)
            raise ValueError(
                "Input parameter TAGS does not match the tags defined in the mesh"
            )

        # ---
        # Define the boundary mask:
        # ---

        boundary_mask = self.__setBoundaryMask(X)

        # ---
        # Calculate list of sounding frequencies:
        # ---

        frequencies = self.__getSoundingFrequencies(freq_def)

        # ---
        # Tag the domain with conductivity maps:
        # ---

        sigma_model = self.__tagDomain(domain, X, tags, rho, maps)

        # Check for valid values
        if escript.inf(sigma_model) < 0 or escript.sup(sigma_model) < 0:
            raise ValueError("Negative conductivity encountered")
        if cmath.isnan( escript.inf(sigma_model) ) or \
           cmath.isnan( escript.sup(sigma_model) ) or \
           cmath.isinf( escript.sup(sigma_model) ):
            raise ValueError("The conductivity model contains NaNs or INFs")

        # ---
        # Projector and Locator objects.
        # ---

        print("Setting up Escript Locator and Projector objects...")

        # Setup a list with sample points along the vertical mesh extent, bottom to top:
        xsample = self.__getSamplePoints(escript.inf(X[0]),
                                         escript.sup(X[0]),
                                         xstep,
                                         constant=0.0)

        # Get the locations of mesh points at the surface via the Locator object
        # operating on the continuous function-space (i.e. nodes) of the domain.
        loc = pdetools.Locator(escript.ContinuousFunction(domain), xsample)

        # Instantiate the Projector class with smoothing on (fast=False);
        # the Projector is used to calculate the gradient correctly.
        proj = pdetools.Projector(domain, reduce=False, fast=False)

        # ---
        # Print information:
        # ---

        print("")
        print("=" * 72)
        print("Escript MT2D, version", self.__version)
        print("=" * 72)
        print("Mesh XMin/XMax       : ", xmin, xmax)
        print("Mesh ZMin/ZMax       : ", zmin, zmax)
        print("Number of Tags       : ", len(tags))
        print("Mapping              : ", {
            True: 'Yes',
            False: 'No'
        }[maps is not None])
        print("Conductivity Model   : ", sigma_model)
        print("Nr of Frequencies    : ", len(frequencies))
        print("Start/End/Step (Hz)  : ", freq_def["high"], freq_def["low"],
              freq_def["step"])
        print("Mode                 : ", mode.upper())
        print("Solver               : ", MT_2D._solver)
        print("Show plots           : ", plot)
        print("=" * 72)
        print("")

        if self._debug:
            print("Mesh-Info     : ")
            print(domain.print_mesh_info(full=False))

        # ---
        # Set all required variables as data attributes
        # ---

        self.domain = domain
        self.X = X
        self.mode = mode
        self.xmin = xmin
        self.xmax = xmax
        self.zmin = zmin
        self.zmax = zmax
        self.zstep = zstep
        self.xstep = xstep
        self.rho = rho
        self.rho_1d = rho_1d
        self.ifc_1d = ifc_1d
        self.plot = plot
        self.limits = limits
        self.sigma = sigma_model
        self.frequencies = frequencies
        self.boundary_mask = boundary_mask
        self.proj = proj
        self.loc = loc
    def 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]
Exemplo n.º 36
0
 def getSafeTimeStepSize(self,dt):
     """
     returns new step size
     """
     h=self.domain.getSize()
     return self.safety_factor*inf(h**2/(h*abs(self.heat_capacity*self.density)*length(self.velocity)+self.thermal_permabilty))
    def 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 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]
Exemplo n.º 39
0
        elif (NY+1)%(d1*f) == 0:
            d1 = d1 * f
            d2 = d2 / f
    else:
        if (NY+1)%(d1*f) == 0:
            d1 = d1 * f
            d2 = d2 / f
        elif (NX+1)%(d0*f) == 0:
            d0 = d0 * f
            d2 = d2 / f

# create domain
print("Domain subdivisions: %d x %d x %d"%(d0,d1,d2))
dom = Brick(NX, NY, n_cells_v, l0, l1, l2, d0, d1, d2)

dom_len = [sup(dom.getX()[i])-inf(dom.getX()[i]) for i in range(dom.getDim())]

# report domain setup
print("Domain size: "+str([NX, NY, n_cells_v]))
print("     length: "+str(dom_len))
print("     origin: "+str(dom_origin))

DIM = dom.getDim() # = 3

datacoords = ReducedFunction(dom).getX()

# create the output directory if not existing already
try:
    os.mkdir(OUTPUTDIR)
except:
    pass
Exemplo n.º 40
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=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=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]
    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]
Exemplo n.º 44
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
Exemplo n.º 45
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
Exemplo n.º 46
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)