def setUpPDE(self): """ Creates and returns the underlying PDE. :rtype: `lpde.LinearPDE` """ if self.__pde is None: if not HAVE_DIRECT: raise ValueError( "Either this build of escript or the current MPI configuration does not support direct solvers." ) pde = lpde.LinearPDE(self.__domain, numEquations=2) D = pde.createCoefficient('D') A = pde.createCoefficient('A') A[0, :, 0, :] = escript.kronecker(self.__domain.getDim()) A[1, :, 1, :] = escript.kronecker(self.__domain.getDim()) pde.setValue(A=A, D=D) if self.__fixAtBottom: DIM = self.__domain.getDim() z = self.__domain.getX()[DIM - 1] pde.setValue(q=whereZero(z - self.__BX[DIM - 1][0]) * [1, 1]) pde.getSolverOptions().setSolverMethod(lpde.SolverOptions.DIRECT) pde.getSolverOptions().setTolerance(self.__tol) pde.setSymmetryOff() else: pde = self.__pde pde.resetRightHandSideCoefficients() return pde
def _setCoefficients(self, pde, system): """sets PDE coefficients""" FAC_DIAG = 1. FAC_OFFDIAG = -0.4 x = Solution(self.domain).getX() mask = whereZero(x[0]) dim = self.domain.getDim() u_ex = self._getSolution(system) g_ex = self._getGrad(system) if system: A = Tensor4(0., Function(self.domain)) for i in range(dim): A[i,:,i,:] = kronecker(dim) Y = Vector(0., Function(self.domain)) if dim == 2: Y[0] = u_ex[0]*FAC_DIAG+u_ex[1]*FAC_OFFDIAG Y[1] = u_ex[1]*FAC_DIAG+u_ex[0]*FAC_OFFDIAG else: Y[0] = u_ex[0]*FAC_DIAG+u_ex[2]*FAC_OFFDIAG+u_ex[1]*FAC_OFFDIAG Y[1] = u_ex[1]*FAC_DIAG+u_ex[0]*FAC_OFFDIAG+u_ex[2]*FAC_OFFDIAG Y[2] = u_ex[2]*FAC_DIAG+u_ex[1]*FAC_OFFDIAG+u_ex[0]*FAC_OFFDIAG pde.setValue(r=u_ex, q=mask*numpy.ones(dim,), A=A, D=kronecker(dim)*(FAC_DIAG-FAC_OFFDIAG)+numpy.ones((dim,dim))*FAC_OFFDIAG, Y=Y, y=matrixmult(g_ex,self.domain.getNormal())) else: pde.setValue(r=u_ex, q=mask, A=kronecker(dim), y=inner(g_ex, self.domain.getNormal()))
def setCoefficients(self, pde, system): """sets PDE coefficients""" FAC_DIAG = self.FAC_DIAG FAC_OFFDIAG =self.FAC_OFFDIAG x = Solution(self.domain).getX() mask = whereZero(x[0]) dim = self.domain.getDim() u_ex = self.getSolution(system) g_ex = self.getGrad(system) if system: A = Tensor4(0., Function(self.domain)) for i in range(dim): A[i,:,i,:] = kronecker(dim) Y = Vector(0., Function(self.domain)) if dim == 2: Y[0] = u_ex[0]*FAC_DIAG+u_ex[1]*FAC_OFFDIAG-20 Y[1] = u_ex[1]*FAC_DIAG+u_ex[0]*FAC_OFFDIAG-10 else: Y[0] = u_ex[0]*FAC_DIAG+u_ex[2]*FAC_OFFDIAG+u_ex[1]*FAC_OFFDIAG-60 Y[1] = u_ex[1]*FAC_DIAG+u_ex[0]*FAC_OFFDIAG+u_ex[2]*FAC_OFFDIAG-20 Y[2] = u_ex[2]*FAC_DIAG+u_ex[1]*FAC_OFFDIAG+u_ex[0]*FAC_OFFDIAG-22 pde.setValue(r=u_ex, q=mask*numpy.ones(dim,), A=A, D=kronecker(dim)*(FAC_DIAG-FAC_OFFDIAG)+numpy.ones((dim,dim))*FAC_OFFDIAG, Y=Y, y=matrixmult(g_ex,self.domain.getNormal())) else: pde.setValue(r=u_ex, q=mask, A=kronecker(dim), y=inner(g_ex, self.domain.getNormal())) if dim == 2: pde.setValue(Y=-20.) else: pde.setValue(Y=-60.)
def getPotentialNumeric(self): """ Returns 3 list each made up of a number of list containing primary, secondary and total potentials diferences. Each of the lists contain a list for each value of n. """ primCon=self.primaryConductivity coords=self.domain.getX() tol=1e-8 pde=LinearPDE(self.domain, numEquations=1) pde.getSolverOptions().setTolerance(tol) pde.setSymmetryOn() primaryPde=LinearPDE(self.domain, numEquations=1) primaryPde.getSolverOptions().setTolerance(tol) primaryPde.setSymmetryOn() DIM=self.domain.getDim() x=self.domain.getX() q=whereZero(x[DIM-1]-inf(x[DIM-1])) for i in xrange(DIM-1): xi=x[i] q+=whereZero(xi-inf(xi))+whereZero(xi-sup(xi)) A = self.secondaryConductivity * kronecker(self.domain) APrimary = self.primaryConductivity * kronecker(self.domain) pde.setValue(A=A,q=q) primaryPde.setValue(A=APrimary,q=q) delPhiSecondaryList = [] delPhiPrimaryList = [] delPhiTotalList = [] for i in range(1,self.n+1): # 1 to n maxR = self.numElectrodes - 1 - (2*i) #max amount of readings that will fit in the survey delPhiSecondary = [] delPhiPrimary = [] delPhiTotal = [] for j in range(maxR): y_dirac=Scalar(0,DiracDeltaFunctions(self.domain)) y_dirac.setTaggedValue(self.electrodeTags[j],self.current) y_dirac.setTaggedValue(self.electrodeTags[j + ((2*i) + 1)],-self.current) self.sources.append([self.electrodeTags[j], self.electrodeTags[j + ((2*i) + 1)]]) primaryPde.setValue(y_dirac=y_dirac) numericPrimaryPot = primaryPde.getSolution() X=(primCon-self.secondaryConductivity) * grad(numericPrimaryPot) pde.setValue(X=X) u=pde.getSolution() loc=Locator(self.domain,[self.electrodes[j+i],self.electrodes[j+i+1]]) self.samples.append([self.electrodeTags[j+i],self.electrodeTags[j+i+1]]) valPrimary=loc.getValue(numericPrimaryPot) valSecondary=loc.getValue(u) delPhiPrimary.append(valPrimary[1]-valPrimary[0]) delPhiSecondary.append(valSecondary[1]-valSecondary[0]) delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j]) delPhiPrimaryList.append(delPhiPrimary) delPhiSecondaryList.append(delPhiSecondary) delPhiTotalList.append(delPhiTotal) self.delPhiPrimaryList=delPhiPrimaryList self.delPhiSecondaryList=delPhiSecondaryList self.delPhiTotalList = delPhiTotalList return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
def getPotentialNumeric(self): """ Returns 3 list each made up of a number of list containing primary, secondary and total potentials diferences. Each of the lists contain a list for each value of n. """ primCon=self.primaryConductivity coords=self.domain.getX() tol=1e-8 pde=LinearPDE(self.domain, numEquations=1) pde.getSolverOptions().setTolerance(tol) pde.setSymmetryOn() primaryPde=LinearPDE(self.domain, numEquations=1) primaryPde.getSolverOptions().setTolerance(tol) primaryPde.setSymmetryOn() DIM=self.domain.getDim() x=self.domain.getX() q=es.whereZero(x[DIM-1]-es.inf(x[DIM-1])) for i in xrange(DIM-1): xi=x[i] q+=es.whereZero(xi-es.inf(xi))+es.whereZero(xi-es.sup(xi)) A = self.secondaryConductivity * es.kronecker(self.domain) APrimary = self.primaryConductivity * es.kronecker(self.domain) pde.setValue(A=A,q=q) primaryPde.setValue(A=APrimary,q=q) delPhiSecondaryList = [] delPhiPrimaryList = [] delPhiTotalList = [] for i in range(1,self.n+1): # 1 to n maxR = self.numElectrodes - 1 - (2*i) #max amount of readings that will fit in the survey delPhiSecondary = [] delPhiPrimary = [] delPhiTotal = [] for j in range(maxR): y_dirac=es.Scalar(0,es.DiracDeltaFunctions(self.domain)) y_dirac.setTaggedValue(self.electrodeTags[j],self.current) y_dirac.setTaggedValue(self.electrodeTags[j + ((2*i) + 1)],-self.current) self.sources.append([self.electrodeTags[j], self.electrodeTags[j + ((2*i) + 1)]]) primaryPde.setValue(y_dirac=y_dirac) numericPrimaryPot = primaryPde.getSolution() X=(primCon-self.secondaryConductivity) * es.grad(numericPrimaryPot) pde.setValue(X=X) u=pde.getSolution() loc=Locator(self.domain,[self.electrodes[j+i],self.electrodes[j+i+1]]) self.samples.append([self.electrodeTags[j+i],self.electrodeTags[j+i+1]]) valPrimary=loc.getValue(numericPrimaryPot) valSecondary=loc.getValue(u) delPhiPrimary.append(valPrimary[1]-valPrimary[0]) delPhiSecondary.append(valSecondary[1]-valSecondary[0]) delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j]) delPhiPrimaryList.append(delPhiPrimary) delPhiSecondaryList.append(delPhiSecondary) delPhiTotalList.append(delPhiTotal) self.delPhiPrimaryList=delPhiPrimaryList self.delPhiSecondaryList=delPhiSecondaryList self.delPhiTotalList = delPhiTotalList return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
def getGradient(self, sigma, Ex, dExdz): """ Returns the gradient of the defect with respect to density. :param sigma: a suggestion for conductivity :type sigma: ``Data`` of shape () :param Ex: electric field :type Ex: ``Data`` of shape (2,) :param dExdz: vertical derivative of electric field :type dExdz: ``Data`` of shape (2,) """ pde = self.setUpPDE() DIM = self.getDomain().getDim() x = dExdz.getFunctionSpace().getX() Ex = escript.interpolate(Ex, x.getFunctionSpace()) u0 = Ex[0] u1 = Ex[1] u01 = dExdz[0] u11 = dExdz[1] D = pde.getCoefficient('D') Y = pde.getCoefficient('Y') X = pde.getCoefficient('X') A = pde.getCoefficient('A') A[0, :, 0, :] = escript.kronecker(DIM) A[1, :, 1, :] = escript.kronecker(DIM) f = self._omega_mu * sigma D[0, 1] = f D[1, 0] = -f Z = self._Z scale = 1. / (u01**2 + u11**2) scale2 = scale**2 scale *= self._weight scale2 *= self._weight Y[0] = scale * (u0 - u01 * Z[0] + u11 * Z[1]) Y[1] = scale * (u1 - u01 * Z[1] - u11 * Z[0]) X[0,1] = scale2 * (2*u01*u11*(Z[0]*u1-Z[1]*u0) \ + (Z[0]*u0+Z[1]*u1)*(u01**2-u11**2) - u01*(u0**2 + u1**2)) X[1,1] = scale2 * (2*u01*u11*(Z[1]*u1+Z[0]*u0) \ + (Z[1]*u0-Z[0]*u1)*(u01**2-u11**2) - u11*(u0**2 + u1**2)) pde.setValue(A=A, D=D, X=X, Y=Y) Zstar = pde.getSolution() return (-self._omega_mu) * (Zstar[1] * u0 - Zstar[0] * u1)
def update_solute_transport_pde(mesh, solute_pde, concentration_old, v, dt, solute_source, dispersion_tensor, diffusivity, l_disp, t_disp, rho_f, verbose=False): """ Solve the solute transport equation. """ # calculate hydrodynamic dispersivity tensor from molecular diffusivity # and longitudinal and transverse dispersivity # calculate absolute velocity v_abs = (v[0]**2 + v[1]**2)**0.5 # get rid of 0 values of velocity v_abs_1 = es.whereZero(v_abs) * 1e-20 + es.whereNonZero(v_abs) * v_abs Dxx = l_disp * (v[0]**2) / v_abs_1 + diffusivity Dyy = t_disp * (v[1]**2) / v_abs_1 + diffusivity # and set dispersion tensor to 0 where 0 absolute velocity Dxx = (Dxx * es.whereNonZero(v_abs) + es.whereZero(v_abs) * diffusivity) Dyy = (Dyy * es.whereNonZero(v_abs) + es.whereZero(v_abs) * diffusivity) # horizontal and vertical values of dispersion (Dxx and Dyy) dispersion_tensor[0, 0] = Dxx dispersion_tensor[1, 1] = Dyy # off-diagonal terms in tensor (Dxy and Dyx) # set to 0 for now, model becomes numerically unstable # testing with fixed values did not result in significant cahnges in solute conc... # todo, figure out why this is unstable or check the potential error dispersion_tensor[0, 1] = (l_disp - t_disp) * (v[0] * v[1]) / v_abs_1 dispersion_tensor[1, 0] = (l_disp - t_disp) * (v[0] * v[1]) / v_abs_1 u_old = concentration_old a_coeff = dt * dispersion_tensor * es.kronecker(mesh) c_coeff = dt * v d_coeff = 1 y_coeff = u_old + solute_source * dt if verbose is True: print('solute transport coefficients') print('A: ', a_coeff.getShape(), a_coeff) print('C: ', c_coeff.getShape(), c_coeff) print('D: ', d_coeff) print('Y: ', y_coeff.getShape(), y_coeff) solute_pde.setValue(A=a_coeff, C=c_coeff, D=d_coeff, Y=y_coeff) return solute_pde
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")
def doStep(self, dt): """ performs an iteration step of the penalty method. IterationDivergenceError is raised if pressure error cannot be reduced or max_iter is reached. """ penalty = self.viscosity / self.relaxation self.__pde.setValue(lame_mu=self.viscosity, \ lame_lambda=penalty, \ F=self.internal_force, \ sigma=self.pressure*es.kronecker(self.__pde.getDomain()), \ r=self.prescribed_velocity, \ q=self.location_prescribed_velocity) self.__pde.getSolverOptions().setTolerance(self.rel_tol / 10.) self.velocity = self.__pde.getSolution() update = penalty * es.div(self.velocity) self.pressure = self.pressure - update self.__diff, diff_old = es.Lsup(update), self.__diff self.__iter += 1 self.trace("velocity range %e:%e" % (es.inf(self.velocity), es.sup(self.velocity))) self.trace("pressure range %e:%e" % (es.inf(self.pressure), es.sup(self.pressure))) self.trace("pressure correction: %e" % self.__diff) if self.__iter > 2 and diff_old < self.__diff: self.trace("Pressure iteration failed!") raise esmf.IterationDivergenceError( "no improvement in pressure iteration") if self.__iter > self.max_iter: raise esmf.IterationDivergenceError( "Maximum number of iterations steps reached")
def getPotential(self): """ returns a list containing 3 lists one for each the primary, secondary and total potential. """ primCon=self.primaryConductivity coords=self.domain.getX() pde=LinearPDE(self.domain, numEquations=1) tol=1e-8 pde.getSolverOptions().setTolerance(tol) pde.setSymmetryOn() DIM=self.domain.getDim() x=self.domain.getX() q=whereZero(x[DIM-1]-inf(x[DIM-1])) for i in xrange(DIM-1): xi=x[i] q+=whereZero(xi-inf(xi))+whereZero(xi-sup(xi)) A = self.secondaryConductivity * kronecker(self.domain) pde.setValue(A=A,q=q) delPhiSecondary = [] delPhiPrimary = [] delPhiTotal = [] if(len(self.electrodes[0])==3): for i in range(self.numElectrodes-1): analyticRs=Data(0,(3,),ContinuousFunction(self.domain)) analyticRs[0]=(coords[0]-self.electrodes[i][0]) analyticRs[1]=(coords[1]-self.electrodes[i][1]) analyticRs[2]=(coords[2]) rsMag=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**0.5 analyticPrimaryPot=(self.current*(1./primCon))/(2*pi*(rsMag+(whereZero(rsMag)*0.0000001))) #the magic number 0.0000001 is to avoid devide by 0 analyticRsPolePower=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**1.5 analyticRsPolePower = analyticRsPolePower+(whereZero(analyticRsPolePower)*0.0000001) gradUPrimary = Data(0,(3,),ContinuousFunction(self.domain)) gradUPrimary[0] =(self.current/(2*pi*primCon)) * (analyticRs[0]/analyticRsPolePower) gradUPrimary[1] =(self.current/(2*pi*primCon)) * (analyticRs[1]/analyticRsPolePower) gradUPrimary[2] =(self.current/(2*pi*primCon)) * (analyticRs[2]/analyticRsPolePower) gradUPrimary=-gradUPrimary X=(primCon-self.secondaryConductivity) * gradUPrimary pde.setValue(X=X) u=pde.getSolution() loc=Locator(self.domain,self.electrodes[i+1]) delPhiSecondary.append(loc.getValue(u)) delPhiPrimary.append(loc.getValue(analyticPrimaryPot)) else: raise NotImplementedError("2d forward model is not yet implemented") self.delPhiSecondary = delPhiSecondary self.delPhiPrimary = delPhiPrimary for i in range(len(delPhiPrimary)): delPhiTotal.append(delPhiPrimary[i] + delPhiSecondary[i]) self.delPhiTotal=delPhiTotal return [delPhiPrimary, delPhiSecondary, delPhiTotal]
def getPotential(self): """ returns a list containing 3 lists one for each the primary, secondary and total potential. """ primCon=self.primaryConductivity coords=self.domain.getX() pde=LinearPDE(self.domain, numEquations=1) tol=1e-8 pde.getSolverOptions().setTolerance(tol) pde.setSymmetryOn() DIM=self.domain.getDim() x=self.domain.getX() q=es.whereZero(x[DIM-1]-es.inf(x[DIM-1])) for i in xrange(DIM-1): xi=x[i] q+=es.whereZero(xi-es.inf(xi))+es.whereZero(xi-es.sup(xi)) A = self.secondaryConductivity * es.kronecker(self.domain) pde.setValue(A=A,q=q) delPhiSecondary = [] delPhiPrimary = [] delPhiTotal = [] if(len(self.electrodes[0])==3): for i in range(self.numElectrodes-1): analyticRs=es.Data(0,(3,),es.ContinuousFunction(self.domain)) analyticRs[0]=(coords[0]-self.electrodes[i][0]) analyticRs[1]=(coords[1]-self.electrodes[i][1]) analyticRs[2]=(coords[2]) rsMag=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**0.5 analyticPrimaryPot=(self.current*(1./primCon))/(2*pi*(rsMag+(es.whereZero(rsMag)*0.0000001))) #the magic number 0.0000001 is to avoid devide by 0 analyticRsPolePower=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**1.5 analyticRsPolePower = analyticRsPolePower+(es.whereZero(analyticRsPolePower)*0.0000001) gradUPrimary = es.Data(0,(3,),es.ContinuousFunction(self.domain)) gradUPrimary[0] =(self.current/(2*pi*primCon)) * (analyticRs[0]/analyticRsPolePower) gradUPrimary[1] =(self.current/(2*pi*primCon)) * (analyticRs[1]/analyticRsPolePower) gradUPrimary[2] =(self.current/(2*pi*primCon)) * (analyticRs[2]/analyticRsPolePower) gradUPrimary=-gradUPrimary X=(primCon-self.secondaryConductivity) * gradUPrimary pde.setValue(X=X) u=pde.getSolution() loc=Locator(self.domain,self.electrodes[i+1]) delPhiSecondary.append(loc.getValue(u)) delPhiPrimary.append(loc.getValue(analyticPrimaryPot)) else: raise NotImplementedError("2d forward model is not yet implemented") self.delPhiSecondary = delPhiSecondary self.delPhiPrimary = delPhiPrimary for i in range(len(delPhiPrimary)): delPhiTotal.append(delPhiPrimary[i] + delPhiSecondary[i]) self.delPhiTotal=delPhiTotal return [delPhiPrimary, delPhiSecondary, delPhiTotal]
def getArguments(self, sigma): """ Returns precomputed values shared by `getDefect()` and `getGradient()`. :param sigma: conductivity :type sigma: ``Data`` of shape (2,) :return: E_x, E_z :rtype: ``Data`` of shape (2,) """ DIM = self.getDomain().getDim() pde = self.setUpPDE() D = pde.getCoefficient('D') f = self._omega_mu * sigma D[0, 1] = -f D[1, 0] = f A = pde.getCoefficient('A') A[0, :, 0, :] = escript.kronecker(DIM) A[1, :, 1, :] = escript.kronecker(DIM) pde.setValue(A=A, D=D, r=self._r) u = pde.getSolution() return u, escript.grad(u)[:, 1]
def getPotentialAnalytic(self): """ Returns 3 list each made up of a number of list containing primary, secondary and total potentials diferences. Each of the lists contain a list for each value of n. """ coords=self.domain.getX() pde=LinearPDE(self.domain, numEquations=1) tol=1e-8 pde.getSolverOptions().setTolerance(tol) pde.setSymmetryOn() primCon=self.primaryConductivity DIM=self.domain.getDim() x=self.domain.getX() q=es.whereZero(x[DIM-1]-es.inf(x[DIM-1])) for i in xrange(DIM-1): xi=x[i] q+=es.whereZero(xi-es.inf(xi))+es.whereZero(xi-es.sup(xi)) A = self.secondaryConductivity * es.kronecker(self.domain) pde.setValue(A=A,q=q) delPhiSecondaryList = [] delPhiPrimaryList = [] delPhiTotalList = [] for i in range(1,self.n+1): # 1 to n maxR = self.numElectrodes - 1 - (2*i) #max amount of readings that will fit in the survey delPhiSecondary = [] delPhiPrimary = [] delPhiTotal = [] for j in range(maxR): analyticRsOne=es.Data(0,(3,),es.ContinuousFunction(self.domain)) analyticRsOne[0]=(coords[0]-self.electrodes[j][0]) analyticRsOne[1]=(coords[1]-self.electrodes[j][1]) analyticRsOne[2]=(coords[2]) rsMagOne=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**0.5 analyticRsTwo=es.Data(0,(3,),es.ContinuousFunction(self.domain)) analyticRsTwo[0]=(coords[0]-self.electrodes[j + ((2*i) + 1)][0]) analyticRsTwo[1]=(coords[1]-self.electrodes[j + ((2*i) + 1)][1]) analyticRsTwo[2]=(coords[2]) rsMagTwo=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**0.5 self.sources.append([self.electrodeTags[j], self.electrodeTags[j + ((2*i) + 1)]]) rsMagOne+=(es.whereZero(rsMagOne)*0.0000001) rsMagTwo+=(es.whereZero(rsMagTwo)*0.0000001) analyticPrimaryPot=(self.current/(2*pi*primCon*rsMagOne))-(self.current/(2*pi*primCon*rsMagTwo)) analyticRsOnePower=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**1.5 analyticRsOnePower = analyticRsOnePower+(es.whereZero(analyticRsOnePower)*0.0001) analyticRsTwoPower=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**1.5 analyticRsTwoPower = analyticRsTwoPower+(es.whereZero(analyticRsTwoPower)*0.0001) gradAnalyticPrimaryPot = es.Data(0,(3,),es.ContinuousFunction(self.domain)) gradAnalyticPrimaryPot[0] =(self.current/(2*pi*primCon)) * ((-analyticRsOne[0]/analyticRsOnePower) + (analyticRsTwo[0]/analyticRsTwoPower)) gradAnalyticPrimaryPot[1] =(self.current/(2*pi*primCon)) * ((-analyticRsOne[1]/analyticRsOnePower) + (analyticRsTwo[1]/analyticRsTwoPower)) gradAnalyticPrimaryPot[2] =(self.current/(2*pi*primCon)) * ((-analyticRsOne[2]/analyticRsOnePower) + (analyticRsTwo[2]/analyticRsTwoPower)) X=(primCon-self.secondaryConductivity) * (gradAnalyticPrimaryPot) pde.setValue(X=X) u=pde.getSolution() loc=Locator(self.domain,[self.electrodes[j+i],self.electrodes[j+i+1]]) self.samples.append([self.electrodeTags[j+i],self.electrodeTags[j+i+1]]) valPrimary=loc.getValue(analyticPrimaryPot) valSecondary=loc.getValue(u) delPhiPrimary.append(valPrimary[1]-valPrimary[0]) delPhiSecondary.append(valSecondary[1]-valSecondary[0]) delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j]) delPhiPrimaryList.append(delPhiPrimary) delPhiSecondaryList.append(delPhiSecondary) delPhiTotalList.append(delPhiTotal) self.delPhiPrimaryList=delPhiPrimaryList self.delPhiSecondaryList=delPhiSecondaryList self.delPhiTotalList = delPhiTotalList return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
def setup(self, domainbuilder, rho0=None, drho=None, rho_z0=None, rho_beta=None, k0=None, dk=None, k_z0=None, k_beta=None, w0=None, w1=None, w_gc=None, rho_at_depth=None, k_at_depth=None): """ Sets up the inversion from an instance ``domainbuilder`` of a `DomainBuilder`. Gravity and magnetic data attached to the ``domainbuilder`` are considered in the inversion. If magnetic data are given as scalar it is assumed that values are collected in direction of the background magnetic field. :param domainbuilder: Domain builder object with gravity source(s) :type domainbuilder: `DomainBuilder` :param rho0: reference density, see `DensityMapping`. If not specified, zero is used. :type rho0: ``float`` or `Scalar` :param drho: density scale, see `DensityMapping`. If not specified, 2750 kg/m^3 is used. :type drho: ``float`` or `Scalar` :param rho_z0: reference depth for depth weighting for density, see `DensityMapping`. If not specified, zero is used. :type rho_z0: ``float`` or `Scalar` :param rho_beta: exponent for density depth weighting, see `DensityMapping`. If not specified, zero is used. :type rho_beta: ``float`` or `Scalar` :param k0: reference susceptibility, see `SusceptibilityMapping`. If not specified, zero is used. :type k0: ``float`` or `Scalar` :param dk: susceptibility scale, see `SusceptibilityMapping`. If not specified, 1. is used. :type dk: ``float`` or `Scalar` :param k_z0: reference depth for susceptibility depth weighting, see `SusceptibilityMapping`. If not specified, zero is used. :type k_z0: ``float`` or `Scalar` :param k_beta: exponent for susceptibility depth weighting, see `SusceptibilityMapping`. If not specified, zero is used. :type k_beta: ``float`` or `Scalar` :param w0: weighting factor for level set term in the regularization. If not set zero is assumed. :type w0: ``Scalar`` or ``float`` :param w1: weighting factor for the gradient term in the regularization see `Regularization`. If not set zero is assumed. :type w1: `es.Data` or ``ndarray`` of shape (DIM,) :param w_gc: weighting factor for the cross gradient term in the regularization, see `Regularization`. If not set one is assumed. :type w_gc: `Scalar` or `float` :param k_at_depth: value for susceptibility at depth, see `DomainBuilder`. :type k_at_depth: ``float`` or ``None`` :param rho_at_depth: value for density at depth, see `DomainBuilder`. :type rho_at_depth: ``float`` or ``None`` """ self.logger.info('Retrieving domain...') dom = domainbuilder.getDomain() DIM = dom.getDim() trafo = makeTransformation(dom, domainbuilder.getReferenceSystem()) rock_mask = wherePositive(domainbuilder.getSetDensityMask() + domainbuilder.getSetSusceptibilityMask()) #======================== self.logger.info('Creating mappings ...') if rho_at_depth: rho2 = rock_mask * rho_at_depth + (1 - rock_mask) * rho0 elif rho0: rho2 = (1 - rock_mask) * rho0 else: rho2 = 0 if k_at_depth: k2 = rock_mask * k_at_depth + (1 - rock_mask) * k0 elif k0: k2 = (1 - rock_mask) * k0 else: k2 = 0 rho_mapping = DensityMapping(dom, rho0=rho2, drho=drho, z0=rho_z0, beta=rho_beta) rho_scale_mapping = rho_mapping.getTypicalDerivative() self.logger.debug("rho_scale_mapping = %s" % rho_scale_mapping) k_mapping = SusceptibilityMapping(dom, k0=k2, dk=dk, z0=k_z0, beta=k_beta) k_scale_mapping = k_mapping.getTypicalDerivative() self.logger.debug("k_scale_mapping = %s" % k_scale_mapping) #======================== self.logger.info("Setting up regularization...") if w1 is None: w1 = [1.] * DIM regularization = Regularization(dom, numLevelSets=1, w0=w0, w1=w1, location_of_set_m=rock_mask, coordinates=trafo) #==================================================================== self.logger.info("Retrieving gravity surveys...") surveys = domainbuilder.getGravitySurveys() g = [] w = [] for g_i, sigma_i in surveys: w_i = es.safeDiv(1., sigma_i) if g_i.getRank() == 0: g_i = g_i * es.kronecker(DIM)[DIM - 1] if w_i.getRank() == 0: w_i = w_i * es.kronecker(DIM)[DIM - 1] g.append(g_i) w.append(w_i) self.logger.debug("Added gravity survey:") self.logger.debug("g = %s" % g_i) self.logger.debug("sigma = %s" % sigma_i) self.logger.debug("w = %s" % w_i) self.logger.info("Setting up gravity model...") gravity_model = GravityModel( dom, w, g, fixPotentialAtBottom=self._fixGravityPotentialAtBottom, coordinates=trafo) gravity_model.rescaleWeights(rho_scale=rho_scale_mapping) #==================================================================== self.logger.info("Retrieving magnetic field surveys...") d_b = es.normalize(domainbuilder.getBackgroundMagneticFluxDensity()) surveys = domainbuilder.getMagneticSurveys() B = [] w = [] for B_i, sigma_i in surveys: w_i = es.safeDiv(1., sigma_i) if self.magnetic_intensity_data: if not B_i.getRank() == 0: B_i = es.length(B_i) if not w_i.getRank() == 0: w_i = length(w_i) else: if B_i.getRank() == 0: B_i = B_i * d_b if w_i.getRank() == 0: w_i = w_i * d_b B.append(B_i) w.append(w_i) self.logger.debug("Added magnetic survey:") self.logger.debug("B = %s" % B_i) self.logger.debug("sigma = %s" % sigma_i) self.logger.debug("w = %s" % w_i) self.logger.info("Setting up magnetic model...") if self.self_demagnetization: magnetic_model = SelfDemagnetizationModel( dom, w, B, domainbuilder.getBackgroundMagneticFluxDensity(), fixPotentialAtBottom=self._fixMagneticPotentialAtBottom, coordinates=trafo) else: if self.magnetic_intensity_data: magnetic_model = MagneticIntensityModel( dom, w, B, domainbuilder.getBackgroundMagneticFluxDensity(), fixPotentialAtBottom=self._fixMagneticPotentialAtBottom, coordinates=trafo) else: magnetic_model = MagneticModel( dom, w, B, domainbuilder.getBackgroundMagneticFluxDensity(), fixPotentialAtBottom=self._fixMagneticPotentialAtBottom, coordinates=trafo) magnetic_model.rescaleWeights(k_scale=k_scale_mapping) #==================================================================== self.logger.info("Setting cost function...") self.setCostFunction( InversionCostFunction(regularization, (rho_mapping, k_mapping), ((gravity_model, 0), (magnetic_model, 1))))
def getInverseHessianApproximationAtPoint(self, r, solve=True): """ """ # substituting cached values m = self.__pre_input grad_m = self.__pre_args if self._new_mu or self._update_Hessian: self._new_mu = False self._update_Hessian = False mu = self.__mu mu_c = self.__mu_c DIM = self.getDomain().getDim() numLS = self.getNumLevelSets() if self.__w0 is not None: if numLS == 1: D = self.__w0 * mu else: D = self.getPDE().getCoefficient("D") D.setToZero() for k in range(numLS): D[k, k] = self.__w0[k] * mu[k] self.getPDE().setValue(D=D) A = self.getPDE().getCoefficient("A") A.setToZero() if self.__w1 is not None: if numLS == 1: for i in range(DIM): A[i, i] = self.__w1[i] * mu else: for k in range(numLS): for i in range(DIM): A[k, i, k, i] = self.__w1[k, i] * mu[k] if numLS > 1: # this could be make faster by creating caches for grad_m_k, l2_grad_m_k and o_kk for k in range(numLS): grad_m_k = grad_m[k, :] l2_grad_m_k = escript.length(grad_m_k)**2 o_kk = escript.outer(grad_m_k, grad_m_k) for l in range(k): grad_m_l = grad_m[l, :] l2_grad_m_l = escript.length(grad_m_l)**2 i_lk = escript.inner(grad_m_l, grad_m_k) o_lk = escript.outer(grad_m_l, grad_m_k) o_kl = escript.outer(grad_m_k, grad_m_l) o_ll = escript.outer(grad_m_l, grad_m_l) f = mu_c[l, k] * self.__wc[l, k] Z = f * (2 * o_lk - o_kl - i_lk * escript.kronecker(DIM)) A[l, :, l, :] += f * (l2_grad_m_k * escript.kronecker(DIM) - o_kk) A[l, :, k, :] += Z A[k, :, l, :] += escript.transpose(Z) A[k, :, k, :] += f * (l2_grad_m_l * escript.kronecker(DIM) - o_ll) self.getPDE().setValue(A=A) #self.getPDE().resetRightHandSideCoefficients() #self.getPDE().setValue(X=r[1]) #print "X only: ",self.getPDE().getSolution() #self.getPDE().resetRightHandSideCoefficients() #self.getPDE().setValue(Y=r[0]) #print "Y only: ",self.getPDE().getSolution() self.getPDE().resetRightHandSideCoefficients() self.getPDE().setValue(X=r[1], Y=r[0]) if not solve: return self.getPDE() return self.getPDE().getSolution()
def getInverseHessianApproximationAtPoint(self, r, solve=True): """ """ # substituting cached values m = self.__pre_input grad_m = self.__pre_args if self._new_mu or self._update_Hessian: self._new_mu = False self._update_Hessian = False mu = self.__mu mu_c = self.__mu_c DIM = self.getDomain().getDim() numLS = self.getNumLevelSets() if self.__w0 is not None: if numLS == 1: D = self.__w0 * mu else: D = self.getPDE().getCoefficient("D") D.setToZero() for k in range(numLS): D[k, k] = self.__w0[k] * mu[k] self.getPDE().setValue(D=D) A = self.getPDE().getCoefficient("A") A.setToZero() if self.__w1 is not None: if numLS == 1: for i in range(DIM): A[i, i] = self.__w1[i] * mu else: for k in range(numLS): for i in range(DIM): A[k, i, k, i] = self.__w1[k, i] * mu[k] if numLS > 1: # this could be make faster by creating caches for grad_m_k, l2_grad_m_k and o_kk for k in range(numLS): grad_m_k = grad_m[k, :] l2_grad_m_k = length(grad_m_k) ** 2 o_kk = outer(grad_m_k, grad_m_k) for l in range(k): grad_m_l = grad_m[l, :] l2_grad_m_l = length(grad_m_l) ** 2 i_lk = inner(grad_m_l, grad_m_k) o_lk = outer(grad_m_l, grad_m_k) o_kl = outer(grad_m_k, grad_m_l) o_ll = outer(grad_m_l, grad_m_l) f = mu_c[l, k] * self.__wc[l, k] Z = f * (2 * o_lk - o_kl - i_lk * kronecker(DIM)) A[l, :, l, :] += f * (l2_grad_m_k * kronecker(DIM) - o_kk) A[l, :, k, :] += Z A[k, :, l, :] += transpose(Z) A[k, :, k, :] += f * (l2_grad_m_l * kronecker(DIM) - o_ll) self.getPDE().setValue(A=A) # self.getPDE().resetRightHandSideCoefficients() # self.getPDE().setValue(X=r[1]) # print "X only: ",self.getPDE().getSolution() # self.getPDE().resetRightHandSideCoefficients() # self.getPDE().setValue(Y=r[0]) # print "Y only: ",self.getPDE().getSolution() self.getPDE().resetRightHandSideCoefficients() self.getPDE().setValue(X=r[1], Y=r[0]) if not solve: return self.getPDE() return self.getPDE().getSolution()
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)
def solve_steady_state_pressure_eq_new(mesh, topo_gradient, pressure_pde, rho_f, k_tensor, k_vector, viscosity, g_vector, fluid_source, rch_bnd_loc, recharge_mass_flux, specified_pressure_bnd, specified_pressure, drain_bnd_loc, fluid_density, proj, debug=True): """ Solve the steady-state fluid flow equation for fluid pressure using escript with optional seepage bnd condition. """ year = 365.25 * 24 * 60 * 60.0 # calculate boundary flux specified_flux = rch_bnd_loc * recharge_mass_flux a = rho_f * k_tensor / viscosity * es.kronecker(mesh) d = 0.0 x = rho_f**2 * k_vector / viscosity * g_vector y = fluid_source # pressure_pde.setValue(A=a, D=d, X=x, Y=y, y=specified_flux, q=specified_pressure_bnd, r=specified_pressure) # calculate pressure, without seepage bnd pressure = pressure_pde.getSolution() debug = True if debug is True: print('initial calculated steady-state pressure: ', pressure) if es.sup(drain_bnd_loc) == 0: print('no drain or seepage bnd') active_seepage_bnd = es.wherePositive(drain_bnd_loc) return pressure, active_seepage_bnd # check if h > surface elevation #pressure_threshold = 0.01 * 9.81 * 1000.0 pressure_threshold = 0.0 active_seepage_bnd = es.wherePositive(drain_bnd_loc * pressure - pressure_threshold) if debug is True: print('active seepage nodes: ', np.sum(np.array(active_seepage_bnd.toListOfTuples()))) print('potential seepage nodes: ', np.sum(np.array(drain_bnd_loc.toListOfTuples()))) n_seepage_change = 9999 n_seepage_nodes = 99999 n_iter = 0 max_seepage_iter = 2000 while n_seepage_change > 0 and n_iter < max_seepage_iter: # add seepage to specified pressure bnd and update bnd conditions specified_pressure_bnd_mod = \ es.wherePositive( specified_pressure_bnd + active_seepage_bnd) #active_rch_bnd = rch_bnd_loc * es.whereZero(specified_pressure_bnd) active_rch_bnd = rch_bnd_loc specified_flux = active_rch_bnd * recharge_mass_flux pressure_pde.setValue(r=specified_pressure, q=specified_pressure_bnd_mod, y=specified_flux) # recalculate pressure pressure = pressure_pde.getSolution() if debug is True: print('new pressure: ', pressure) # calculate flux q = calculate_q(k_vector, viscosity, pressure, fluid_density, g_vector) proj.setValue(D=es.kronecker(mesh), Y=q) try: nodal_q = proj.getSolution() except RuntimeError(msg): print('error, non-convergence') print(msg) non_convergence = True # calculate max vertical flux into the model domain at # drain bnd nodes # using outer norm to calculate correct bnd flux does not work because # flux cannot be interpolated to same functionspace as pressure variable #nodal_q_norm_bnd = nodal_q * nodal_q.getDomain().getNormal() #nodal_q_norm = es.interpolate(nodal_q_norm_bnd, active_seepage_bnd.getFunctionSpace()) nodal_q_norm = rotate_vector_escript(nodal_q, topo_gradient) flux_seepage_bnd = active_seepage_bnd * nodal_q_norm[1] # remove inlfow nodes that are <= recharge flux_seepage_bnd_corr = flux_seepage_bnd + recharge_mass_flux / fluid_density # changed back to old method to speed up seepage bnd calc #flux_seepage_bnd_corr = flux_seepage_bnd # and remove only the worst x % of seepage nodes to avoid oscillations: seepage_threshold = es.inf(flux_seepage_bnd_corr) * 0.5 #seepage_threshold = 0.0 seepage_inflow_nodes = \ es.whereNegative(flux_seepage_bnd_corr - seepage_threshold) removed_seepage_inflow_nodes = seepage_inflow_nodes if debug is True: print('number of seepage inflow nodes: ', \ np.sum(np.array(seepage_inflow_nodes.toListOfTuples()))) xmin_seep = es.inf(seepage_inflow_nodes * seepage_inflow_nodes.getDomain().getX()[0] + (1 - seepage_inflow_nodes) * 999999) xmax_seep = es.sup(seepage_inflow_nodes * seepage_inflow_nodes.getDomain().getX()[0]) print('from x= %0.2f m to x= %0.2f m' % (xmin_seep, xmax_seep)) # add boundary nodes with P>0 to seepage bnd new_seepage_nodes = \ es.wherePositive(drain_bnd_loc * (1 - active_seepage_bnd) * pressure) if debug is True: print('number of new seepage nodes: ', \ np.sum(np.array(new_seepage_nodes.toListOfTuples()))) # update the seepage bnd active_seepage_bnd = (active_seepage_bnd + new_seepage_nodes - removed_seepage_inflow_nodes) n_seepage_nodes_old = n_seepage_nodes n_seepage_nodes = np.sum(np.array(active_seepage_bnd.toListOfTuples())) n_seepage_change = np.abs(n_seepage_nodes_old - n_seepage_nodes) if debug is True: print('final active seepage nodes: ', np.sum(np.array(active_seepage_bnd.toListOfTuples()))) print('potential seepage nodes: ', np.sum(np.array(drain_bnd_loc.toListOfTuples()))) if n_seepage_nodes_old < n_seepage_nodes: print( 'lowest number of seepage nodes reached, stopping iterations') n_seepage_change = 0 print('seepage iteration %i' % n_iter) print('seepage threshold ', seepage_threshold * year) print('change in seepage nodes from %0.0f to %0.0f' % (n_seepage_nodes_old, n_seepage_nodes)) n_iter += 1 # update specified pressure bnd condition specified_pressure_bnd_mod = \ es.wherePositive( specified_pressure_bnd + active_seepage_bnd) #active_rch_bnd = rch_bnd_loc * es.whereZero(specified_pressure_bnd) active_rch_bnd = rch_bnd_loc specified_flux = active_rch_bnd * recharge_mass_flux pressure_pde.setValue(r=specified_pressure, q=specified_pressure_bnd_mod, y=specified_flux) # recalculate pressure pressure = pressure_pde.getSolution() if debug is True: print('final pressure: ', pressure) return pressure, active_seepage_bnd
def getPotential(self): """ Returns 3 list each made up of a number of list containing primary, secondary and total potentials diferences. Each of the lists contain a list for each value of n. """ coords=self.domain.getX() pde=LinearPDE(self.domain, numEquations=1) tol=1e-8 pde.getSolverOptions().setTolerance(tol) pde.setSymmetryOn() primCon=self.primaryConductivity DIM=self.domain.getDim() x=self.domain.getX() q=whereZero(x[DIM-1]-inf(x[DIM-1])) for i in xrange(DIM-1): xi=x[i] q+=whereZero(xi-inf(xi))+whereZero(xi-sup(xi)) A = self.secondaryConductivity * kronecker(self.domain) pde.setValue(A=A,q=q) delPhiSecondaryList = [] delPhiPrimaryList = [] delPhiTotalList = [] for i in range(1,self.n+1): # 1 to n maxR = self.numElectrodes - 2 - (i) #max amount of readings that will fit in the survey delPhiSecondary = [] delPhiPrimary = [] delPhiTotal = [] for j in range(maxR): analyticRsOne=Data(0,(3,),ContinuousFunction(self.domain)) analyticRsOne[0]=(coords[0]-self.electrodes[j][0]) analyticRsOne[1]=(coords[1]-self.electrodes[j][1]) analyticRsOne[2]=(coords[2]) rsMagOne=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**0.5 analyticRsTwo=Data(0,(3,),ContinuousFunction(self.domain)) analyticRsTwo[0]=(coords[0]-self.electrodes[j + 1][0]) analyticRsTwo[1]=(coords[1]-self.electrodes[j + 1][1]) analyticRsTwo[2]=(coords[2]) rsMagTwo=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**0.5 rsMagOne+=(whereZero(rsMagOne)*0.0000001) rsMagTwo+=(whereZero(rsMagTwo)*0.0000001) analyticPrimaryPot=(self.current/(2*pi*primCon*rsMagTwo))-(self.current/(2*pi*primCon*rsMagOne)) analyticRsOnePower=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**1.5 analyticRsOnePower = analyticRsOnePower+(whereZero(analyticRsOnePower)*0.0001) analyticRsTwoPower=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**1.5 analyticRsTwoPower = analyticRsTwoPower+(whereZero(analyticRsTwoPower)*0.0001) gradAnalyticPrimaryPot = Data(0,(3,),ContinuousFunction(self.domain)) gradAnalyticPrimaryPot[0] =(self.current/(2*pi*primCon)) * ((analyticRsOne[0]/analyticRsOnePower) - (analyticRsTwo[0]/analyticRsTwoPower)) gradAnalyticPrimaryPot[1] =(self.current/(2*pi*primCon)) * ((analyticRsOne[1]/analyticRsOnePower) - (analyticRsTwo[1]/analyticRsTwoPower)) gradAnalyticPrimaryPot[2] =(self.current/(2*pi*primCon)) * ((analyticRsOne[2]/analyticRsOnePower) - (analyticRsTwo[2]/analyticRsTwoPower)) X=(primCon-self.secondaryConductivity) * (gradAnalyticPrimaryPot) pde.setValue(X=X) u=pde.getSolution() loc=Locator(self.domain,[self.electrodes[1+j+i],self.electrodes[j+i+2]]) valPrimary=loc.getValue(analyticPrimaryPot) valSecondary=loc.getValue(u) delPhiPrimary.append(valPrimary[1]-valPrimary[0]) delPhiSecondary.append(valSecondary[1]-valSecondary[0]) delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j]) delPhiPrimaryList.append(delPhiPrimary) delPhiSecondaryList.append(delPhiSecondary) delPhiTotalList.append(delPhiTotal) self.delPhiPrimaryList=delPhiPrimaryList self.delPhiSecondaryList=delPhiSecondaryList self.delPhiTotalList = delPhiTotalList return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
def setup(self, domainbuilder, rho0=None, drho=None, z0=None, beta=None, w0=None, w1=None, rho_at_depth=None): """ Sets up the inversion parameters from a `DomainBuilder`. :param domainbuilder: Domain builder object with gravity source(s) :type domainbuilder: `DomainBuilder` :param rho0: reference density, see `DensityMapping`. If not specified, zero is used. :type rho0: ``float`` or ``Scalar`` :param drho: density scale, see `DensityMapping`. If not specified, 2750kg/m^3 is used. :type drho: ``float`` or ``Scalar`` :param z0: reference depth for depth weighting, see `DensityMapping`. If not specified, zero is used. :type z0: ``float`` or ``Scalar`` :param beta: exponent for depth weighting, see `DensityMapping`. If not specified, zero is used. :type beta: ``float`` or ``Scalar`` :param w0: weighting factor for level set term regularization. If not set zero is assumed. :type w0: ``Scalar`` or ``float`` :param w1: weighting factor for the gradient term in the regularization. If not set zero is assumed :type w1: ``Vector`` or list of ``float`` :param rho_at_depth: value for density at depth, see `DomainBuilder`. :type rho_at_depth: ``float`` or ``None`` """ self.logger.info('Retrieving domain...') dom = domainbuilder.getDomain() trafo = makeTransformation(dom, domainbuilder.getReferenceSystem()) DIM = dom.getDim() rho_mask = domainbuilder.getSetDensityMask() #======================== self.logger.info('Creating mapping...') if rho_at_depth: rho2 = rho_mask * rho_at_depth + (1 - rho_mask) * rho0 elif rho0: rho2 = (1 - rho_mask) * rho0 else: rho2 = 0. rho_mapping = DensityMapping(dom, rho0=rho2, drho=drho, z0=z0, beta=beta) scale_mapping = rho_mapping.getTypicalDerivative() #======================== self.logger.info("Setting up regularization...") if w1 is None: w1 = [1.] * DIM regularization=Regularization(dom, numLevelSets=1,\ w0=w0, w1=w1, location_of_set_m=rho_mask, coordinates=trafo) #==================================================================== self.logger.info("Retrieving gravity surveys...") surveys = domainbuilder.getGravitySurveys() g = [] w = [] for g_i, sigma_i in surveys: w_i = es.safeDiv(1., sigma_i) if g_i.getRank() == 0: g_i = g_i * es.kronecker(DIM)[DIM - 1] if w_i.getRank() == 0: w_i = w_i * es.kronecker(DIM)[DIM - 1] g.append(g_i) w.append(w_i) self.logger.debug("Added gravity survey:") self.logger.debug("g = %s" % g_i) self.logger.debug("sigma = %s" % sigma_i) self.logger.debug("w = %s" % w_i) #==================================================================== self.logger.info("Setting up model...") forward_model = GravityModel( dom, w, g, fixPotentialAtBottom=self._fixGravityPotentialAtBottom, coordinates=trafo) forward_model.rescaleWeights(rho_scale=scale_mapping) #==================================================================== self.logger.info("Setting cost function...") self.setCostFunction( InversionCostFunction(regularization, rho_mapping, forward_model))
def getPotential(self): """ returns a list containing 3 lists one for each the primary, secondary and total potential. """ primCon=self.primaryConductivity coords=self.domain.getX() pde=LinearPDE(self.domain, numEquations=1) tol=1e-8 pde.getSolverOptions().setTolerance(tol) pde.setSymmetryOn() DIM=self.domain.getDim() x=self.domain.getX() q=es.whereZero(x[DIM-1]-es.inf(x[DIM-1])) for i in xrange(DIM-1): xi=x[i] q+=es.whereZero(xi-es.inf(xi))+es.whereZero(xi-es.sup(xi)) A = self.secondaryConductivity * es.kronecker(self.domain) pde.setValue(A=A,q=q) delPhiSecondary = [] delPhiPrimary = [] delPhiTotal = [] if(len(self.electrodes[0])==3): for i in range(self.numElectrodes-3): analyticRsOne=es.Data(0,(3,),es.ContinuousFunction(self.domain)) analyticRsOne[0]=(coords[0]-self.electrodes[i][0]) analyticRsOne[1]=(coords[1]-self.electrodes[i][1]) analyticRsOne[2]=(coords[2]) rsMagOne=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**0.5 analyticRsTwo=es.Data(0,(3,),es.ContinuousFunction(self.domain)) analyticRsTwo[0]=(coords[0]-self.electrodes[i+3][0]) analyticRsTwo[1]=(coords[1]-self.electrodes[i+3][1]) analyticRsTwo[2]=(coords[2]) rsMagTwo=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**0.5 rsMagOne+=(es.whereZero(rsMagOne)*0.0000001) rsMagTwo+=(es.whereZero(rsMagTwo)*0.0000001) analyticPrimaryPot=(self.current/(2*pi*primCon*rsMagOne))-(self.current/(2*pi*primCon*rsMagTwo)) analyticRsOnePower=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**1.5 analyticRsOnePower = analyticRsOnePower+(es.whereZero(analyticRsOnePower)*0.0001) analyticRsTwoPower=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**1.5 analyticRsTwoPower = analyticRsTwoPower+(es.whereZero(analyticRsTwoPower)*0.0001) gradAnalyticPrimaryPot = es.Data(0,(3,),es.ContinuousFunction(self.domain)) gradAnalyticPrimaryPot[0] =(self.current/(2*pi*primCon)) \ * ((-analyticRsOne[0]/analyticRsOnePower) \ + (analyticRsTwo[0]/analyticRsTwoPower)) gradAnalyticPrimaryPot[1] =(self.current/(2*pi*primCon)) \ * ((-analyticRsOne[1]/analyticRsOnePower) \ + (analyticRsTwo[1]/analyticRsTwoPower)) gradAnalyticPrimaryPot[2] =(self.current/(2*pi*primCon)) \ * ((-analyticRsOne[2]/analyticRsOnePower) + (analyticRsTwo[2]/analyticRsTwoPower)) X=(primCon-self.secondaryConductivity) * (gradAnalyticPrimaryPot) pde.setValue(X=X) u=pde.getSolution() loc=Locator(self.domain,[self.electrodes[i+1],self.electrodes[i+2]]) valPrimary=loc.getValue(analyticPrimaryPot) valSecondary=loc.getValue(u) delPhiPrimary.append(valPrimary[1]-valPrimary[0]) delPhiSecondary.append(valSecondary[1]-valSecondary[0]) delPhiTotal.append(delPhiPrimary[i]+delPhiSecondary[i]) else: raise NotImplementedError("2d forward model is not yet implemented") self.delPhiSecondary = delPhiSecondary self.delPhiPrimary = delPhiPrimary self.delPhiTotal=delPhiTotal return [delPhiPrimary, delPhiSecondary, delPhiTotal]
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
def __init__(self, domain, v_p, v_s, wavelet, source_tag, source_vector=[1., 0., 0.], eps=0., gamma=0., delta=0., rho=1., dt=None, u0=None, v0=None, absorption_zone=None, absorption_cut=1e-2, lumping=True, disable_fast_assemblers=False): """ initialize the VTI wave solver :param domain: domain of the problem :type domain: `Domain` :param v_p: vertical p-velocity field :type v_p: `escript.Scalar` :param v_s: vertical s-velocity field :type v_s: `escript.Scalar` :param wavelet: wavelet to describe the time evolution of source term :type wavelet: `Wavelet` :param source_tag: tag of the source location :type source_tag: 'str' or 'int' :param source_vector: source orientation vector :param eps: first Thompsen parameter :param delta: second Thompsen parameter :param gamma: third Thompsen parameter :param rho: density :param dt: time step size. If not present a suitable time step size is calculated. :param u0: initial solution. If not present zero is used. :param v0: initial solution change rate. If not present zero is used. :param absorption_zone: thickness of absorption zone :param absorption_cut: boundary value of absorption decay factor :param lumping: if True mass matrix lumping is being used. This is accelerates the computing but introduces some diffusion. :param disable_fast_assemblers: if True, forces use of slower and more general PDE assemblers """ DIM = domain.getDim() self.fastAssembler = hasattr( domain, "createAssembler") and not disable_fast_assemblers f = createAbsorptionLayerFunction(v_p.getFunctionSpace().getX(), absorption_zone, absorption_cut) v_p = v_p * f v_s = v_s * f if u0 == None: u0 = escript.Vector(0., escript.Solution(domain)) else: u0 = escript.interpolate(p0, escript.Solution(domain)) if v0 == None: v0 = escript.Vector(0., escript.Solution(domain)) else: v0 = escript.interpolate(v0, escript.Solution(domain)) if dt == None: dt = min((1. / 5.) * min(escript.inf(domain.getSize() / v_p), escript.inf(domain.getSize() / v_s)), wavelet.getTimeScale()) super(HTIWave, self).__init__(dt, u0=u0, v0=v0, t0=0.) self.__wavelet = wavelet self.c33 = v_p**2 * rho self.c44 = v_s**2 * rho self.c11 = (1 + 2 * eps) * self.c33 self.c66 = (1 + 2 * gamma) * self.c44 self.c13 = escript.sqrt(2 * self.c33 * (self.c33 - self.c44) * delta + (self.c33 - self.c44)**2) - self.c44 self.c23 = self.c33 - 2 * self.c66 if self.fastAssembler: C = [("c11", self.c11), ("c23", self.c23), ("c13", self.c13), ("c33", self.c33), ("c44", self.c44), ("c66", self.c66)] if "speckley" in domain.getDescription().lower(): C = [(n, escript.interpolate(d, escript.ReducedFunction(domain))) for n, d in C] self.__mypde = lpde.WavePDE(domain, C) else: self.__mypde = lpde.LinearPDESystem(domain) self.__mypde.setValue(X=self.__mypde.createCoefficient('X')) if lumping: self.__mypde.getSolverOptions().setSolverMethod( lpde.SolverOptions.HRZ_LUMPING) self.__mypde.setSymmetryOn() self.__mypde.setValue(D=rho * escript.kronecker(DIM)) self.__source_tag = source_tag if DIM == 2: source_vector = [source_vector[0], source_vector[2]] self.__r = escript.Vector( 0, escript.DiracDeltaFunctions(self.__mypde.getDomain())) self.__r.setTaggedValue(self.__source_tag, source_vector)
def getPotential(self): """ Returns 3 list each made up of a number of list containing primary, secondary and total potentials diferences. Each of the lists contain a list for each value of n. """ primCon=self.primaryConductivity coords=self.domain.getX() pde=LinearPDE(self.domain, numEquations=1) tol=1e-8 pde.getSolverOptions().setTolerance(tol) pde.setSymmetryOn() DIM=self.domain.getDim() x=self.domain.getX() q=whereZero(x[DIM-1]-inf(x[DIM-1])) for i in xrange(DIM-1): xi=x[i] q+=whereZero(xi-inf(xi))+whereZero(xi-sup(xi)) A = self.secondaryConductivity * kronecker(self.domain) pde.setValue(A=A,q=q) delPhiSecondaryList = [] delPhiPrimaryList = [] delPhiTotalList = [] for i in range(1,self.n+1): # 1 to n maxR = self.numElectrodes - 1 - i #max amount of readings that will fit in the survey delPhiSecondary = [] delPhiPrimary = [] delPhiTotal = [] for j in range(maxR): analyticRs=Data(0,(3,),ContinuousFunction(self.domain)) analyticRs[0]=(coords[0]-self.electrodes[j][0]) analyticRs[1]=(coords[1]-self.electrodes[j][1]) analyticRs[2]=(coords[2]) rsMag=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**0.5 analyticPrimaryPot=(self.current*(1./primCon))/(2*pi*(rsMag+(whereZero(rsMag)*0.0000001))) #the magic number 0.0000001 is to avoid devide by 0 analyticRsPolePower=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**1.5 analyticRsPolePower = analyticRsPolePower+(whereZero(analyticRsPolePower)*0.0000001) gradUPrimary = Data(0,(3,),ContinuousFunction(self.domain)) gradUPrimary[0] =(self.current/(2*pi*primCon)) * (analyticRs[0]/analyticRsPolePower) gradUPrimary[1] =(self.current/(2*pi*primCon)) * (analyticRs[1]/analyticRsPolePower) gradUPrimary[2] =(self.current/(2*pi*primCon)) * (analyticRs[2]/analyticRsPolePower) gradUPrimary=-gradUPrimary X=(primCon-self.secondaryConductivity) * gradUPrimary pde.setValue(X=X) u=pde.getSolution() loc=Locator(self.domain,[self.electrodes[i+j],self.electrodes[i+j+1]]) valPrimary=loc.getValue(analyticPrimaryPot) valSecondary=loc.getValue(u) delPhiPrimary.append(valPrimary[1]-valPrimary[0]) delPhiSecondary.append(valSecondary[1]-valSecondary[0]) delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j]) delPhiPrimaryList.append(delPhiPrimary) delPhiSecondaryList.append(delPhiSecondary) delPhiTotalList.append(delPhiTotal) self.delPhiPrimaryList=delPhiPrimaryList self.delPhiSecondaryList=delPhiSecondaryList self.delPhiTotalList = delPhiTotalList return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
def RegionalCalculation(reg_mask): """ Calculates the "regional" from the entire FEILDS model excluding the selected region and outputs gravity at the specified altitude... see above for the "residual" """ # read in a gravity data grid to define data computation space G_DATA = os.path.join(DATADIR,'Final_BouguerTC_UC15K_qrtdeg.nc') FS=ReducedFunction(dom) nValues=[NX, NY, 1] first = [0, 0, cell_at_altitude] multiplier = [1, 1, 1] reverse = [0, 0, 0] byteorder = BYTEORDER_NATIVE gdata = readBinaryGrid(G_DATA, FS, shape=(), fill=-999999, byteOrder=byteorder, dataType=DATATYPE_FLOAT32, first=first, numValues=nValues, multiplier=multiplier, reverse=reverse) print("Grid successfully read") # get the masking and units sorted out for the data-space g_mask = whereNonZero(gdata+999999) gdata=gdata*g_mask * GRAV_UNITS # if people choose to have air in their region we exclude it from the # specified gravity calculation region if h_top < 0.: reg_mask = reg_mask+mask_air live_model = initial_model* whereNonPositive(reg_mask) dead_model = initial_model* wherePositive(reg_mask) if UseMean is True: # calculate the mean density within the selected region BackgroundDensity = integrate(dead_model)/integrate(wherePositive(reg_mask)) print("Density mean for selected region equals = %s"%BackgroundDensity) live_model = live_model + BackgroundDensity * wherePositive(reg_mask) # create mapping rho_mapping = DensityMapping(dom, rho0=live_model) # invert sign of gravity field to account for escript's coordinate system gdata = -GRAV_UNITS * gdata # turn the scalars into vectors (vertical direction) d=kronecker(DIM)[DIM-1] w=safeDiv(1., g_mask) gravity_model=GravityModel(dom, w*d, gdata*d, fixPotentialAtBottom=False, coordinates=COORDINATES) gravity_model.rescaleWeights(rho_scale=rho_mapping.getTypicalDerivative()) phi,_ = gravity_model.getArguments(live_model) g_init = -gravity_model.getCoordinateTransformation().getGradient(phi) g_init = interpolate(g_init, gdata.getFunctionSpace()) print("Computed gravity: %s"%(g_init[2])) fn=os.path.join(OUTPUTDIR,'regional-gravity') if SiloOutput is True: saveSilo(fn, density=live_model, gravity_init=g_init, g_initz=-g_init[2], gravitymask=g_mask, modelmask=reg_mask) print('SILO file written with the following fields: density (kg/m^3), gravity vector (m/s^2), gz (m/s^2), gravitymask, modelmask') # to compare calculated data against input dataset. # Not used by default but should work if the input dataset is correct #gslice = g_init[2]*wherePositive(g_mask) #g_dash = integrate(gslice)/integrate(wherePositive(g_mask)) #gdataslice = gdata*wherePositive(g_mask) #gdata_dash = integrate(gdataslice)/integrate(wherePositive(g_mask)) #misfit=(gdataslice-gdata_dash)-(gslice-g_dash) saveDataCSV(fn+".csv", mask=g_mask, gz=-g_init[2], Long=datacoords[0], Lat=datacoords[1], h=datacoords[2]) print('CSV file written with the following fields: Longitude (degrees) Latitude (degrees), h (100km), gz (m/s^2)')
def stress(self): """ returns current stress""" return 2*self.viscosity*self.stretching-self.pressure*kronecker(self.domain)
def getPotential(self): """ Returns 3 list each made up of a number of list containing primary, secondary and total potentials diferences. Each of the lists contain a list for each value of n. """ primCon=self.primaryConductivity coords=self.domain.getX() pde=LinearPDE(self.domain, numEquations=1) tol=1e-8 pde.getSolverOptions().setTolerance(tol) pde.setSymmetryOn() DIM=self.domain.getDim() x=self.domain.getX() q=es.whereZero(x[DIM-1]-es.inf(x[DIM-1])) for i in xrange(DIM-1): xi=x[i] q+=es.whereZero(xi-es.inf(xi))+es.whereZero(xi-es.sup(xi)) A = self.secondaryConductivity * es.kronecker(self.domain) pde.setValue(A=A,q=q) delPhiSecondaryList = [] delPhiPrimaryList = [] delPhiTotalList = [] for i in range(1,self.n+1): # 1 to n maxR = self.numElectrodes - 1 - i #max amount of readings that will fit in the survey delPhiSecondary = [] delPhiPrimary = [] delPhiTotal = [] for j in range(maxR): analyticRs=es.Data(0,(3,),es.ContinuousFunction(self.domain)) analyticRs[0]=(coords[0]-self.electrodes[j][0]) analyticRs[1]=(coords[1]-self.electrodes[j][1]) analyticRs[2]=(coords[2]) rsMag=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**0.5 analyticPrimaryPot=(self.current*(1./primCon))/(2*pi*(rsMag+(es.whereZero(rsMag)*0.0000001))) #the magic number 0.0000001 is to avoid devide by 0 analyticRsPolePower=(analyticRs[0]**2+analyticRs[1]**2+analyticRs[2]**2)**1.5 analyticRsPolePower = analyticRsPolePower+(es.whereZero(analyticRsPolePower)*0.0000001) gradUPrimary = es.Data(0,(3,),es.ContinuousFunction(self.domain)) gradUPrimary[0] =(self.current/(2*pi*primCon)) * (analyticRs[0]/analyticRsPolePower) gradUPrimary[1] =(self.current/(2*pi*primCon)) * (analyticRs[1]/analyticRsPolePower) gradUPrimary[2] =(self.current/(2*pi*primCon)) * (analyticRs[2]/analyticRsPolePower) gradUPrimary=-gradUPrimary X=(primCon-self.secondaryConductivity) * gradUPrimary pde.setValue(X=X) u=pde.getSolution() loc=Locator(self.domain,[self.electrodes[i+j],self.electrodes[i+j+1]]) valPrimary=loc.getValue(analyticPrimaryPot) valSecondary=loc.getValue(u) delPhiPrimary.append(valPrimary[1]-valPrimary[0]) delPhiSecondary.append(valSecondary[1]-valSecondary[0]) delPhiTotal.append(delPhiPrimary[j]+delPhiSecondary[j]) delPhiPrimaryList.append(delPhiPrimary) delPhiSecondaryList.append(delPhiSecondary) delPhiTotalList.append(delPhiTotal) self.delPhiPrimaryList=delPhiPrimaryList self.delPhiSecondaryList=delPhiSecondaryList self.delPhiTotalList = delPhiTotalList return [delPhiPrimaryList, delPhiSecondaryList, delPhiTotalList]
def getPotential(self): """ returns a list containing 3 lists one for each the primary, secondary and total potential. """ primCon=self.primaryConductivity coords=self.domain.getX() pde=LinearPDE(self.domain, numEquations=1) tol=1e-8 pde.getSolverOptions().setTolerance(tol) pde.setSymmetryOn() DIM=self.domain.getDim() x=self.domain.getX() q=whereZero(x[DIM-1]-inf(x[DIM-1])) for i in xrange(DIM-1): xi=x[i] q+=whereZero(xi-inf(xi))+whereZero(xi-sup(xi)) A = self.secondaryConductivity * kronecker(self.domain) pde.setValue(A=A,q=q) delPhiSecondary = [] delPhiPrimary = [] delPhiTotal = [] if(len(self.electrodes[0])==3): for i in range(self.numElectrodes-3): analyticRsOne=Data(0,(3,),ContinuousFunction(self.domain)) analyticRsOne[0]=(coords[0]-self.electrodes[i][0]) analyticRsOne[1]=(coords[1]-self.electrodes[i][1]) analyticRsOne[2]=(coords[2]) rsMagOne=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**0.5 analyticRsTwo=Data(0,(3,),ContinuousFunction(self.domain)) analyticRsTwo[0]=(coords[0]-self.electrodes[i+3][0]) analyticRsTwo[1]=(coords[1]-self.electrodes[i+3][1]) analyticRsTwo[2]=(coords[2]) rsMagTwo=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**0.5 rsMagOne+=(whereZero(rsMagOne)*0.0000001) rsMagTwo+=(whereZero(rsMagTwo)*0.0000001) analyticPrimaryPot=(self.current/(2*pi*primCon*rsMagOne))-(self.current/(2*pi*primCon*rsMagTwo)) analyticRsOnePower=(analyticRsOne[0]**2+analyticRsOne[1]**2+analyticRsOne[2]**2)**1.5 analyticRsOnePower = analyticRsOnePower+(whereZero(analyticRsOnePower)*0.0001) analyticRsTwoPower=(analyticRsTwo[0]**2+analyticRsTwo[1]**2+analyticRsTwo[2]**2)**1.5 analyticRsTwoPower = analyticRsTwoPower+(whereZero(analyticRsTwoPower)*0.0001) gradAnalyticPrimaryPot = Data(0,(3,),ContinuousFunction(self.domain)) gradAnalyticPrimaryPot[0] =(self.current/(2*pi*primCon)) \ * ((-analyticRsOne[0]/analyticRsOnePower) \ + (analyticRsTwo[0]/analyticRsTwoPower)) gradAnalyticPrimaryPot[1] =(self.current/(2*pi*primCon)) \ * ((-analyticRsOne[1]/analyticRsOnePower) \ + (analyticRsTwo[1]/analyticRsTwoPower)) gradAnalyticPrimaryPot[2] =(self.current/(2*pi*primCon)) \ * ((-analyticRsOne[2]/analyticRsOnePower) + (analyticRsTwo[2]/analyticRsTwoPower)) X=(primCon-self.secondaryConductivity) * (gradAnalyticPrimaryPot) pde.setValue(X=X) u=pde.getSolution() loc=Locator(self.domain,[self.electrodes[i+1],self.electrodes[i+2]]) valPrimary=loc.getValue(analyticPrimaryPot) valSecondary=loc.getValue(u) delPhiPrimary.append(valPrimary[1]-valPrimary[0]) delPhiSecondary.append(valSecondary[1]-valSecondary[0]) delPhiTotal.append(delPhiPrimary[i]+delPhiSecondary[i]) else: raise NotImplementedError("2d forward model is not yet implemented") self.delPhiSecondary = delPhiSecondary self.delPhiPrimary = delPhiPrimary self.delPhiTotal=delPhiTotal return [delPhiPrimary, delPhiSecondary, delPhiTotal]
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)
def setup(self, domainbuilder, rho0=None, drho=None, rho_z0=None, rho_beta=None, k0=None, dk=None, k_z0=None, k_beta=None, w0=None, w1=None, w_gc=None,rho_at_depth=None, k_at_depth=None): """ Sets up the inversion from an instance ``domainbuilder`` of a `DomainBuilder`. Gravity and magnetic data attached to the ``domainbuilder`` are considered in the inversion. If magnetic data are given as scalar it is assumed that values are collected in direction of the background magnetic field. :param domainbuilder: Domain builder object with gravity source(s) :type domainbuilder: `DomainBuilder` :param rho0: reference density, see `DensityMapping`. If not specified, zero is used. :type rho0: ``float`` or `Scalar` :param drho: density scale, see `DensityMapping`. If not specified, 2750 kg/m^3 is used. :type drho: ``float`` or `Scalar` :param rho_z0: reference depth for depth weighting for density, see `DensityMapping`. If not specified, zero is used. :type rho_z0: ``float`` or `Scalar` :param rho_beta: exponent for density depth weighting, see `DensityMapping`. If not specified, zero is used. :type rho_beta: ``float`` or `Scalar` :param k0: reference susceptibility, see `SusceptibilityMapping`. If not specified, zero is used. :type k0: ``float`` or `Scalar` :param dk: susceptibility scale, see `SusceptibilityMapping`. If not specified, 1. is used. :type dk: ``float`` or `Scalar` :param k_z0: reference depth for susceptibility depth weighting, see `SusceptibilityMapping`. If not specified, zero is used. :type k_z0: ``float`` or `Scalar` :param k_beta: exponent for susceptibility depth weighting, see `SusceptibilityMapping`. If not specified, zero is used. :type k_beta: ``float`` or `Scalar` :param w0: weighting factor for level set term in the regularization. If not set zero is assumed. :type w0: ``Scalar`` or ``float`` :param w1: weighting factor for the gradient term in the regularization see `Regularization`. If not set zero is assumed. :type w1: `es.Data` or ``ndarray`` of shape (DIM,) :param w_gc: weighting factor for the cross gradient term in the regularization, see `Regularization`. If not set one is assumed. :type w_gc: `Scalar` or `float` :param k_at_depth: value for susceptibility at depth, see `DomainBuilder`. :type k_at_depth: ``float`` or ``None`` :param rho_at_depth: value for density at depth, see `DomainBuilder`. :type rho_at_depth: ``float`` or ``None`` """ self.logger.info('Retrieving domain...') dom=domainbuilder.getDomain() DIM=dom.getDim() trafo=makeTransformation(dom, domainbuilder.getReferenceSystem()) rock_mask=wherePositive(domainbuilder.getSetDensityMask() + domainbuilder.getSetSusceptibilityMask()) #======================== self.logger.info('Creating mappings ...') if rho_at_depth: rho2= rock_mask * rho_at_depth + (1-rock_mask) * rho0 elif rho0: rho2= (1-rock_mask) * rho0 else: rho2=0 if k_at_depth: k2= rock_mask * k_at_depth + (1-rock_mask) * k0 elif k0: k2= (1-rock_mask) * k0 else: k2=0 rho_mapping=DensityMapping(dom, rho0=rho2, drho=drho, z0=rho_z0, beta=rho_beta) rho_scale_mapping=rho_mapping.getTypicalDerivative() self.logger.debug("rho_scale_mapping = %s"%rho_scale_mapping) k_mapping=SusceptibilityMapping(dom, k0=k2, dk=dk, z0=k_z0, beta=k_beta) k_scale_mapping=k_mapping.getTypicalDerivative() self.logger.debug("k_scale_mapping = %s"%k_scale_mapping) #======================== self.logger.info("Setting up regularization...") if w1 is None: w1=[1.]*DIM regularization=Regularization(dom, numLevelSets=1,w0=w0, w1=w1, location_of_set_m=rock_mask, coordinates=trafo) #==================================================================== self.logger.info("Retrieving gravity surveys...") surveys=domainbuilder.getGravitySurveys() g=[] w=[] for g_i,sigma_i in surveys: w_i=es.safeDiv(1., sigma_i) if g_i.getRank()==0: g_i=g_i*es.kronecker(DIM)[DIM-1] if w_i.getRank()==0: w_i=w_i*es.kronecker(DIM)[DIM-1] g.append(g_i) w.append(w_i) self.logger.debug("Added gravity survey:") self.logger.debug("g = %s"%g_i) self.logger.debug("sigma = %s"%sigma_i) self.logger.debug("w = %s"%w_i) self.logger.info("Setting up gravity model...") gravity_model=GravityModel(dom, w, g, fixPotentialAtBottom=self._fixGravityPotentialAtBottom, coordinates=trafo) gravity_model.rescaleWeights(rho_scale=rho_scale_mapping) #==================================================================== self.logger.info("Retrieving magnetic field surveys...") d_b=es.normalize(domainbuilder.getBackgroundMagneticFluxDensity()) surveys=domainbuilder.getMagneticSurveys() B=[] w=[] for B_i,sigma_i in surveys: w_i=es.safeDiv(1., sigma_i) if B_i.getRank()==0: B_i=B_i*d_b if w_i.getRank()==0: w_i=w_i*d_b B.append(B_i) w.append(w_i) self.logger.debug("Added magnetic survey:") self.logger.debug("B = %s"%B_i) self.logger.debug("sigma = %s"%sigma_i) self.logger.debug("w = %s"%w_i) self.logger.info("Setting up magnetic model...") magnetic_model=MagneticModel(dom, w, B, domainbuilder.getBackgroundMagneticFluxDensity(), fixPotentialAtBottom=self._fixMagneticPotentialAtBottom, coordinates=trafo) magnetic_model.rescaleWeights(k_scale=k_scale_mapping) #==================================================================== self.logger.info("Setting cost function...") self.setCostFunction(InversionCostFunction(regularization, (rho_mapping, k_mapping), ((gravity_model,0), (magnetic_model,1)) ))
def stress(self): """ returns current stress""" return 2 * self.viscosity * self.stretching - self.pressure * es.kronecker( self.domain)
def setup(self, domainbuilder, rho0=None, drho=None, z0=None, beta=None, w0=None, w1=None, rho_at_depth=None): """ Sets up the inversion parameters from a `DomainBuilder`. :param domainbuilder: Domain builder object with gravity source(s) :type domainbuilder: `DomainBuilder` :param rho0: reference density, see `DensityMapping`. If not specified, zero is used. :type rho0: ``float`` or ``Scalar`` :param drho: density scale, see `DensityMapping`. If not specified, 2750kg/m^3 is used. :type drho: ``float`` or ``Scalar`` :param z0: reference depth for depth weighting, see `DensityMapping`. If not specified, zero is used. :type z0: ``float`` or ``Scalar`` :param beta: exponent for depth weighting, see `DensityMapping`. If not specified, zero is used. :type beta: ``float`` or ``Scalar`` :param w0: weighting factor for level set term regularization. If not set zero is assumed. :type w0: ``Scalar`` or ``float`` :param w1: weighting factor for the gradient term in the regularization. If not set zero is assumed :type w1: ``Vector`` or list of ``float`` :param rho_at_depth: value for density at depth, see `DomainBuilder`. :type rho_at_depth: ``float`` or ``None`` """ self.logger.info('Retrieving domain...') dom=domainbuilder.getDomain() trafo=makeTransformation(dom, domainbuilder.getReferenceSystem()) DIM=dom.getDim() rho_mask = domainbuilder.getSetDensityMask() #======================== self.logger.info('Creating mapping...') if rho_at_depth: rho2 = rho_mask * rho_at_depth + (1-rho_mask) * rho0 elif rho0: rho2 = (1-rho_mask) * rho0 else: rho2 = 0. rho_mapping=DensityMapping(dom, rho0=rho2, drho=drho, z0=z0, beta=beta) scale_mapping=rho_mapping.getTypicalDerivative() #======================== self.logger.info("Setting up regularization...") if w1 is None: w1=[1.]*DIM regularization=Regularization(dom, numLevelSets=1,\ w0=w0, w1=w1, location_of_set_m=rho_mask, coordinates=trafo) #==================================================================== self.logger.info("Retrieving gravity surveys...") surveys=domainbuilder.getGravitySurveys() g=[] w=[] for g_i,sigma_i in surveys: w_i=es.safeDiv(1., sigma_i) if g_i.getRank()==0: g_i=g_i*es.kronecker(DIM)[DIM-1] if w_i.getRank()==0: w_i=w_i*es.kronecker(DIM)[DIM-1] g.append(g_i) w.append(w_i) self.logger.debug("Added gravity survey:") self.logger.debug("g = %s"%g_i) self.logger.debug("sigma = %s"%sigma_i) self.logger.debug("w = %s"%w_i) #==================================================================== self.logger.info("Setting up model...") forward_model=GravityModel(dom, w, g, fixPotentialAtBottom=self._fixGravityPotentialAtBottom, coordinates=trafo) forward_model.rescaleWeights(rho_scale=scale_mapping) #==================================================================== self.logger.info("Setting cost function...") self.setCostFunction(InversionCostFunction(regularization, rho_mapping, forward_model))