def __init__(self, domain, w, data, coordinates=None, fixPotentialAtBottom=False, tol=1e-8): """ initializes a new forward model with potential. :param domain: domain of the model :type domain: `Domain` :param w: data weighting factors :type w: ``Vector`` or list of ``Vector`` :param data: data :type data: ``Vector`` or list of ``Vector`` :param coordinates: defines coordinate system to be used :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation` :param fixPotentialAtBottom: if true potential is fixed to zero at the bottom of the domain in addition to the top. :type fixPotentialAtBottom: ``bool`` :param tol: tolerance of underlying PDE :type tol: positive ``float`` """ super(ForwardModelWithPotential, self).__init__() self.__domain = domain self.__trafo = makeTransformation(domain, coordinates) try: n=len(w) m=len(data) if not m == n: raise ValueError("Length of weight and data must be the same.") self.__weight = w self.__data = data except TypeError: self.__weight = [w] self.__data = [data] BX = boundingBox(domain) DIM = domain.getDim() x = domain.getX() self.__pde=LinearSinglePDE(domain) self.__pde.getSolverOptions().setTolerance(tol) self.__pde.setSymmetryOn() z=x[DIM-1] q0=whereZero(z-BX[DIM-1][1]) if fixPotentialAtBottom: q0+=whereZero(z-BX[DIM-1][0]) self.__pde.setValue(q=q0) self.edge_lengths=np.asarray(boundingBoxEdgeLengths(domain)) self.diameter=1./sqrt(sum(1./self.edge_lengths**2)) self.__origweight=[] for s in range(len(self.__weight)): # save a copy of the original weights in case of rescaling self.__origweight.append(1.*self.__weight[s]) if not self.__trafo.isCartesian(): fd=1./self.__trafo.getScalingFactors() fw=self.__trafo.getScalingFactors()*sqrt(self.__trafo.getVolumeFactor()) for s in range(len(self.__weight)): self.__weight[s] = fw * self.__weight[s] self.__data[s] = fd * self.__data[s]
def __init__(self, domain, locator, delphiIn, sampleTags, phiPrimary, sigmaPrimary, w=1., coordinates=None, tol=1e-8, saveMemory=True, b=None): """ setup new forward model :param domain: the domain of the model :type: escript domain :param locator: contains locator to the measurement pairs :type: `list` of ``Locator`` :param: delphiIn: this is v_pq, the potential difference for the current source and a set of measurement pairs. A list of measured potential differences is expected. Note this should be the secondary potential only. :type delphiIn: tuple :param sampleTags: tags of measurement points from which potential differences will be calculated. :type sampleTags: list of tuples :param phiPrimary: primary potential. :type phiPrimary: `Scalar` """ super(DcRes, self).__init__() if not isinstance(sampleTags, list): raise ValueError("sampleTags must be a list.") if not len(sampleTags) == len(delphiIn): raise ValueError("sampleTags and delphiIn must have the same length.") if not len(sampleTags)>0: raise ValueError("sampleTags list is empty.") if not isinstance(sampleTags[0], tuple) and not isinstance(sampleTags[0], list): raise ValueError("sampleTags must be a list of tuples or a list of lists.") if isinstance(w, float) or isinstance(w, int): w = [float(w) for z in delphiIn] self.__w = w else: self.__w = w if not len(w) == len(delphiIn): raise ValueError("Number of confidence factors and number of potential input values don't match.") self.__trafo = makeTransformation(domain, coordinates) if not self.getCoordinateTransformation().isCartesian(): raise ValueError("Non-Cartesian Coordinates are not supported yet.") if not isinstance(locator, Locator): raise ValueError("locator must be an escript locator object") self.__domain = domain self.__tol = tol self.__locator = locator self.delphiIn = delphiIn self.__sampleTags = sampleTags self.__sigmaPrimary = sigmaPrimary self.__phiPrimary = phiPrimary self.__pde = None if not saveMemory: self.__pde=self.setUpPDE()
def __init__(self, domain, p0=0., level0=0, gravity0=-9.81 * U.m * U.sec**(-2), background_density=2670 * U.kg * U.m**(-3), gravity_constant=U.Gravitational_Constant, coordinates=None, tol=1e-8): """ :param domain: domain of the model :type domain: `Domain` :param p0: pressure at level0 :type p0: scalar `Data` or ``float`` :param background_density: defines background_density in kg/m^3 :type background_density: ``float`` :param coordinates: defines coordinate system to be used :type coordinates: ReferenceSystem` or `SpatialCoordinateTransformation` :param tol: tolerance of underlying PDE :type tol: positive ``float`` :param level0: pressure for z>=`level0` is set to zero. :type level0: ``float`` :param gravity0: vertical background gravity at `level0` :type gravity0: ``float`` """ DIM = domain.getDim() self.__domain = domain self.__trafo = makeTransformation(domain, coordinates) self.__pde = LinearSinglePDE(domain) self.__pde.getSolverOptions().setTolerance(tol) self.__pde.setSymmetryOn() z = domain.getX()[DIM - 1] self.__pde.setValue(q=whereNonNegative(z - level0), r=p0) fw = self.__trafo.getScalingFactors( )**2 * self.__trafo.getVolumeFactor() A = self.__pde.createCoefficient("A") for i in range(DIM): A[i, i] = fw[i] self.__pde.setValue(A=A) z = Function(domain).getX()[DIM - 1] self.__g_b = 4 * PI * gravity_constant / self.__trafo.getScalingFactors( )[DIM - 1] * background_density * (level0 - z) + gravity0 self.__rho_b = background_density
def __init__(self, domain, p0=0., level0=0, gravity0=-9.81*U.m*U.sec**(-2), background_density=2670* U.kg*U.m**(-3), gravity_constant=U.Gravitational_Constant, coordinates=None, tol=1e-8): """ :param domain: domain of the model :type domain: `Domain` :param p0: pressure at level0 :type p0: scalar `Data` or ``float`` :param background_density: defines background_density in kg/m^3 :type background_density: ``float`` :param coordinates: defines coordinate system to be used :type coordinates: ReferenceSystem` or `SpatialCoordinateTransformation` :param tol: tolerance of underlying PDE :type tol: positive ``float`` :param level0: pressure for z>=`level0` is set to zero. :type level0: ``float`` :param gravity0: vertical background gravity at `level0` :type gravity0: ``float`` """ DIM=domain.getDim() self.__domain = domain self.__trafo=makeTransformation(domain, coordinates) self.__pde=LinearSinglePDE(domain) self.__pde.getSolverOptions().setTolerance(tol) self.__pde.setSymmetryOn() z = domain.getX()[DIM-1] self.__pde.setValue(q=whereNonNegative(z-level0), r=p0) fw = self.__trafo.getScalingFactors()**2 * self.__trafo.getVolumeFactor() A=self.__pde.createCoefficient("A") for i in range(DIM): A[i,i]=fw[i] self.__pde.setValue(A=A) z = Function(domain).getX()[DIM-1] self.__g_b= 4*PI*gravity_constant/self.__trafo.getScalingFactors()[DIM-1]*background_density*(level0-z) + gravity0 self.__rho_b=background_density
def __init__(self, domain, omega, w, data, F, coordinates=None, fixAtBottom=False, tol=1e-8, saveMemory=True, scaleF=True): """ initializes a new forward model with acoustic wave form inversion. :param domain: domain of the model :type domain: `Domain` :param w: weighting factors :type w: ``Scalar`` :param data: real and imaginary part of data :type data: ``Data`` of shape (2,) :param F: real and imaginary part of source given at Dirac points, on surface or at volume. :type F: ``Data`` of shape (2,) :param coordinates: defines coordinate system to be used (not supported yet) :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation` :param tol: tolerance of underlying PDE :type tol: positive ``float`` :param saveMemory: if true stiffness matrix is deleted after solution of PDE to minimize memory requests. This will require more compute time as the matrix needs to be reallocated. :type saveMemory: ``bool`` :param scaleF: if true source F is scaled to minimize defect. :type scaleF: ``bool`` :param fixAtBottom: if true pressure is fixed to zero at the bottom of the domain :type fixAtBottom: ``bool`` """ super(AcousticWaveForm, self).__init__() self.__trafo = makeTransformation(domain, coordinates) if not self.getCoordinateTransformation().isCartesian(): raise ValueError("Non-Cartesian Coordinates are not supported yet.") if not isinstance(data, Data): raise ValueError("data must be an escript.Data object.") if not data.getFunctionSpace() == FunctionOnBoundary(domain): raise ValueError("data must be defined on boundary") if not data.getShape() == (2,): raise ValueError("data must have shape (2,) (real and imaginary part).") if w is None: w = 1. if not isinstance(w, Data): w = Data(w, FunctionOnBoundary(domain)) else: if not w.getFunctionSpace() == FunctionOnBoundary(domain): raise ValueError("Weights must be defined on boundary.") if not w.getShape() == (): raise ValueError("Weights must be scalar.") self.__domain = domain self.__omega = omega self.__weight = w self.__data = data self.scaleF = scaleF if scaleF: A = integrate(self.__weight*length(self.__data)**2) if A > 0: self.__data*=1./sqrt(A) self.__BX = boundingBox(domain) self.edge_lengths = np.asarray(boundingBoxEdgeLengths(domain)) if not isinstance(F, Data): F=interpolate(F, DiracDeltaFunctions(domain)) if not F.getShape() == (2,): raise ValueError("Source must have shape (2,) (real and imaginary part).") self.__F=Data() self.__f=Data() self.__f_dirac=Data() if F.getFunctionSpace() == DiracDeltaFunctions(domain): self.__f_dirac=F elif F.getFunctionSpace() == FunctionOnBoundary(domain): self.__f=F else: self.__F=F self.__tol=tol self.__fixAtBottom=fixAtBottom self.__pde=None if not saveMemory: self.__pde=self.setUpPDE()
def __init__(self, domain, locator, delphiIn, sampleTags, phiPrimary, sigmaPrimary, w=1., coordinates=None, tol=1e-8, saveMemory=True, b=None): """ setup new forward model :param domain: the domain of the model :type: escript domain :param locator: contains locator to the measurement pairs :type: `list` of ``Locator`` :param: delphiIn: this is v_pq, the potential difference for the current source and a set of measurement pairs. A list of measured potential differences is expected. Note this should be the secondary potential only. :type delphiIn: tuple :param sampleTags: tags of measurement points from which potential differences will be calculated. :type sampleTags: list of tuples :param phiPrimary: primary potential. :type phiPrimary: `Scalar` """ super(DcRes, self).__init__() if not isinstance(sampleTags, list): raise ValueError("sampleTags must be a list.") if not len(sampleTags) == len(delphiIn): raise ValueError( "sampleTags and delphiIn must have the same length.") if not len(sampleTags) > 0: raise ValueError("sampleTags list is empty.") if not isinstance(sampleTags[0], tuple) and not isinstance( sampleTags[0], list): raise ValueError( "sampleTags must be a list of tuples or a list of lists.") if isinstance(w, float) or isinstance(w, int): w = [float(w) for z in delphiIn] self.__w = w else: self.__w = w if not len(w) == len(delphiIn): raise ValueError( "Number of confidence factors and number of potential input values don't match." ) self.__trafo = makeTransformation(domain, coordinates) if not self.getCoordinateTransformation().isCartesian(): raise ValueError( "Non-Cartesian Coordinates are not supported yet.") if not isinstance(locator, Locator): raise ValueError("locator must be an escript locator object") self.__domain = domain self.__tol = tol self.__locator = locator self.delphiIn = delphiIn self.__sampleTags = sampleTags self.__sigmaPrimary = sigmaPrimary self.__phiPrimary = phiPrimary self.__pde = None if not saveMemory: self.__pde = self.setUpPDE()
def __init__(self, domain, w, data, coordinates=None, fixPotentialAtBottom=False, tol=1e-8): """ initializes a new forward model with potential. :param domain: domain of the model :type domain: `Domain` :param w: data weighting factors :type w: ``Vector`` or list of ``Vector`` :param data: data :type data: ``Vector`` or list of ``Vector`` :param coordinates: defines coordinate system to be used :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation` :param fixPotentialAtBottom: if true potential is fixed to zero at the bottom of the domain in addition to the top. :type fixPotentialAtBottom: ``bool`` :param tol: tolerance of underlying PDE :type tol: positive ``float`` """ super(ForwardModelWithPotential, self).__init__() self.__domain = domain self.__trafo = makeTransformation(domain, coordinates) try: n = len(w) m = len(data) if not m == n: raise ValueError("Length of weight and data must be the same.") self.__weight = w self.__data = data except TypeError: self.__weight = [w] self.__data = [data] BX = boundingBox(domain) DIM = domain.getDim() x = domain.getX() self.__pde = LinearSinglePDE(domain) self.__pde.getSolverOptions().setTolerance(tol) self.__pde.setSymmetryOn() z = x[DIM - 1] q0 = whereZero(z - BX[DIM - 1][1]) if fixPotentialAtBottom: q0 += whereZero(z - BX[DIM - 1][0]) self.__pde.setValue(q=q0) self.edge_lengths = np.asarray(boundingBoxEdgeLengths(domain)) self.diameter = 1. / sqrt(sum(1. / self.edge_lengths**2)) self.__origweight = [] for s in range(len(self.__weight)): # save a copy of the original weights in case of rescaling self.__origweight.append(1. * self.__weight[s]) if not self.__trafo.isCartesian(): fd = 1. / self.__trafo.getScalingFactors() fw = self.__trafo.getScalingFactors() * sqrt( self.__trafo.getVolumeFactor()) for s in range(len(self.__weight)): self.__weight[s] = fw * self.__weight[s] self.__data[s] = fd * self.__data[s]
def __init__(self, domain, omega, x, Z, eta=None, w0=1., mu=4 * math.pi * 1e-7, sigma0=0.01, airLayerLevel=None, fixAirLayer=False, coordinates=None, tol=1e-8, saveMemory=False, directSolver=True): """ initializes a new forward model. :param domain: domain of the model :type domain: `Domain` :param omega: frequency :type omega: positive ``float`` :param x: coordinates of measurements :type x: ``list`` of ``tuple`` with ``float`` :param Z: measured impedance (possibly scaled) :type Z: ``list`` of ``complex`` :param eta: spatial confidence radius :type eta: positive ``float`` or ``list`` of positive ``float`` :param w0: confidence factors for meassurements. :type w0: ``None`` or a list of positive ``float`` :param mu: permeability :type mu: ``float`` :param sigma0: background conductivity :type sigma0: ``float`` :param airLayerLevel: position of the air layer from to bottom of the domain. If not set the air layer starts at the top of the domain :type airLayerLevel: ``float`` or ``None`` :param fixAirLayer: fix air layer (TM mode) :type fixAirLayer: ``bool`` :param coordinates: defines coordinate system to be used (not supported yet) :type coordinates: `ReferenceSystem` or `SpatialCoordinateTransformation` :param tol: tolerance of underlying PDE :type tol: positive ``float`` :param saveMemory: if true stiffness matrix is deleted after solution of the PDE to minimize memory use. This will require more compute time as the matrix needs to be reallocated at each iteration. :type saveMemory: ``bool`` :param directSolver: if true a direct solver (rather than an iterative solver) will be used to solve the PDE :type directSolver: ``bool`` """ super(MT2DBase, self).__init__() self.__trafo = coords.makeTransformation(domain, coordinates) if not self.getCoordinateTransformation().isCartesian(): raise ValueError( "Non-Cartesian coordinates are not supported yet.") if len(x) != len(Z): raise ValueError( "Number of data points and number of impedance values don't match." ) if eta is None: eta = escript.sup(domain.getSize()) * 0.45 if isinstance(eta, float) or isinstance(eta, int): eta = [float(eta)] * len(Z) elif not len(eta) == len(Z): raise ValueError( "Number of confidence radii and number of impedance values don't match." ) if isinstance(w0, float) or isinstance(w0, int): w0 = [float(w0)] * len(Z) elif not len(w0) == len(Z): raise ValueError( "Number of confidence factors and number of impedance values don't match." ) self.__domain = domain self._omega_mu = omega * mu self._ks = escript.sqrt(self._omega_mu * sigma0 / 2.) xx = escript.Function(domain).getX() totalS = 0 self._Z = [ escript.Scalar(0., escript.Function(domain)), escript.Scalar(0., escript.Function(domain)) ] self._weight = escript.Scalar(0., escript.Function(domain)) for s in range(len(Z)): chi = self.getWeightingFactor(xx, 1., x[s], eta[s]) f = escript.integrate(chi) if f < eta[s]**2 * 0.01: raise ValueError( "Zero weight (almost) for data point %s. Change eta or refine mesh." % (s, )) w02 = w0[s] / f totalS += w02 self._Z[0] += chi * Z[s].real self._Z[1] += chi * Z[s].imag self._weight += chi * w02 / (abs(Z[s])**2) if not totalS > 0: raise ValueError( "Scaling of weight factors failed as sum is zero.") DIM = domain.getDim() z = domain.getX()[DIM - 1] self._ztop = escript.sup(z) self._zbottom = escript.inf(z) if airLayerLevel is None: airLayerLevel = self._ztop self._airLayerLevel = airLayerLevel # botton: mask0 = escript.whereZero(z - self._zbottom) r = mask0 * [ escript.exp(self._ks * (self._zbottom - airLayerLevel)) * escript.cos(self._ks * (self._zbottom - airLayerLevel)), escript.exp(self._ks * (self._zbottom - airLayerLevel)) * escript.sin(self._ks * (self._zbottom - airLayerLevel)) ] #top: if fixAirLayer: mask1 = escript.whereNonNegative(z - airLayerLevel) r += mask1 * [1, 0] else: mask1 = escript.whereZero(z - self._ztop) r += mask1 * [ self._ks * (self._ztop - airLayerLevel) + 1, self._ks * (self._ztop - airLayerLevel) ] self._q = (mask0 + mask1) * [1, 1] self._r = r #==================================== self.__tol = tol self._directSolver = directSolver self._saveMemory = saveMemory self.__pde = None if not saveMemory: self.__pde = self.setUpPDE()