def test_Helmholtz(self): """ d² u / d x² + k u + f = 0 k = 2 a) P1(exact) u = x f = -2x b) P2(exact) u = x*x f = -(2 + 2x*x) """ h = np.pi / 2 / 21 x = np.arange(0.0, np.pi / 2, h) mesh = pg.createGrid(x) ### test a) k = 2.0 u = lambda _x: _x f = lambda _x: -(k * u(_x)) x = pg.x(mesh) dirichletBC = [[1, u(min(x))], [2, u(max(x))]] uFEM = pg.solve(mesh, a=1, b=k, f=f(x), bc={'Dirichlet': dirichletBC}) np.testing.assert_allclose(uFEM, u(x)) ### test b) u = lambda _x: _x * _x f = lambda _x: -(2. + k * u(_x)) mesh = mesh.createP2() x = pg.x(mesh) dirichletBC = [[1, u(min(x))], [2, u(max(x))]] uFEM = pg.solve(mesh, a=1, b=k, f=f(x), bc={'Dirichlet': dirichletBC}) np.testing.assert_allclose(uFEM, u(x), atol=1e-6)
def test_Helmholtz(self): """ d² u / d x² + k u + f = 0 k = 2 a) P1(exact) u = x f = -2x b) P2(exact) u = x*x f = -(2 + 2x*x) """ h = np.pi/2 / 21 x = np.arange(0.0, np.pi/2, h) mesh = pg.createGrid(x) ### test a) k = 2.0 u = lambda _x: _x f = lambda _x: -(k * u(_x)) x = pg.x(mesh) dirichletBC = [[1, u(min(x))], [2, u(max(x))]] uFEM = pg.solve(mesh, a=1, b=k, f=f(x), bc={'Dirichlet': dirichletBC}) np.testing.assert_allclose(uFEM, u(x)) ### test b) u = lambda _x: _x * _x f = lambda _x: -(2. + k *u(_x)) mesh = mesh.createP2() x = pg.x(mesh) dirichletBC = [[1, u(min(x))], [2, u(max(x))]] uFEM = pg.solve(mesh, a=1, b=k, f=f(x), bc={'Dirichlet': dirichletBC}) np.testing.assert_allclose(uFEM, u(x), atol=1e-6)
def _testP1_(mesh, show=False, followP2=True): """ Laplace u = 0 with u = x and u(x=min)=0 and u(x=max)=1 Test for u == exact x for P1 base functions """ #print('b', mesh, mesh.cell(0)) u = pg.solve(mesh, a=1, b=0, f=0, bc={'Dirichlet': {1: 0, 2: 1}}) if show: if mesh.dim()==1: pg.plt.figure() x = pg.x(mesh) ix = np.argsort(x) pg.plt.plot(x[ix], u[ix]) elif mesh.dim() > 1: pg.show(mesh, u, label='u') xMin = mesh.xMin() xSpan = (mesh.xMax() - xMin) np.testing.assert_allclose(u, (pg.x(mesh)-xMin) / xSpan) if followP2: _testP2_(mesh, show) return u
def _testP2_(mesh, show=False): """ Laplace u = 2 solves u = x² for u(r=0)=0 and u(r=1)=1 Test for u == exact x² for P2 base functions """ meshp2 = mesh.createP2() u = pg.solve(meshp2, f=-2, bc={'Dirichlet': [[1, 0], [2, 1]]}) # find test pos different from node pos meshTests = mesh.createH2() meshTests = meshTests.createH2() c = [c.center() for c in meshTests.cells()] startPos = meshTests.node(0).pos() if mesh.dim() == 2: c = [b.center() for b in meshTests.boundaries(meshTests.boundaryMarkers()==4)] c.sort(key=lambda c_: c_.distance(startPos)) ui = pg.interpolate(meshp2, u, c) xi = pg.utils.cumDist(c) + startPos.distance(c[0]) if show: pg.plt.plot(xi, ui) pg.plt.plot(xi, xi**2) pg.wait() np.testing.assert_allclose(ui, xi**2)
def _testP2_(mesh, show=False): """ Laplace u - 2 = 0 with u(x) = x² + x/(xMax-xMin) + xMin/(xMax-xMin) and u(xMin)=0 and u(xMax)=1 Test for u_h === u(x) for P2 base functions """ meshP2 = mesh.createP2() u = pg.solve( meshP2, f=-2, bc={'Dirichlet': { '1,2': 2 }}, ) xMin = mesh.xMin() xSpan = (mesh.xMax() - xMin) if show: if mesh.dim() == 1: pg.plt.figure() x = pg.x(mesh) ix = np.argsort(x) pg.plt.plot(x[ix], x[ix]**2 - (xSpan / 2)**2 + 2) elif mesh.dim() > 1: pg.show(meshP2, u, label='u = x**2') np.testing.assert_allclose(u, pg.x(meshP2)**2 - (xSpan / 2)**2 + 2)
def test_Helmholtz(self): """ d² u / d x² + k u + f = 0 k = 2 a) P1(exact) u = x f = -k x b) P2(exact) u = x*x f = -(2 + 2x*x) """ h = np.pi / 2 / 21 x = np.arange(0.0, np.pi / 2, h) mesh = pg.createGrid(x) ### test a) k = 2.0 u = lambda _x: _x f = lambda _x, _k: -_k * u(_x) x = pg.x(mesh) dirichletBC = {1: u(min(x)), 2: u(max(x))} uFEM = pg.solve(mesh, a=1, b=k, f=f(x, k), bc={'Dirichlet': dirichletBC}) # pg.plt.plot(x, uFEM, '.') # pg.plt.plot(pg.sort(x), u(pg.sort(x))) # pg.wait() np.testing.assert_allclose(uFEM, u(x)) ### test b) u = lambda _x: _x * _x f = lambda _x, _k: -(2. + k * u(_x)) mesh = mesh.createP2() x = pg.x(mesh) dirichletBC = {1: u(min(x)), 2: u(max(x))} uFEM = pg.solve(mesh, a=1, b=k, f=f(x, k), bc={'Dirichlet': dirichletBC}) np.testing.assert_allclose(uFEM, u(x), atol=1e-6)
def _test_(mesh): vTest = 0.1 u = pg.solve(mesh, a=1, bc={ 'Node': [mesh.findNearestNode([0.0, 0.0]), 0.], 'Neumann': [[1, -vTest], [2, vTest]] }) v = pg.solver.grad(mesh, u) #print("|v|:", min(pg.abs(v)), max(pg.abs(v)), pg.mean(pg.abs(v))) np.testing.assert_allclose(pg.abs(v), np.ones(mesh.cellCount()) * vTest) return v
def _test_(mesh, show=False): vTest = 0.1 u = pg.solve(mesh, a=1, f=0, bc={'Node': [mesh.findNearestNode([0.0, 0.0]), 0.], 'Neumann': [[1, -vTest], [2, vTest]]}, verbose=0) if show: if mesh.dim() == 1: pg.plt.plot(pg.x(mesh), u) elif mesh.dim() == 2: pg.show(grid, pg.abs(v)) pg.show(grid, v, showMesh=1) pg.wait() v = pg.solver.grad(mesh, u) #print("|v|:", min(pg.abs(v)), max(pg.abs(v)), pg.mean(pg.abs(v))) np.testing.assert_allclose(pg.abs(v), np.ones(mesh.cellCount())*vTest) return v
def _testP1_(mesh, show=False): """ Laplace u = 0 solves u = x for u(r=0)=0 and u(r=1)=1 Test for u == exact x for P1 base functions """ u = pg.solve(mesh, a=1, b=0, f=0, bc={'Dirichlet': [[1, 0], [2, 1]]}) if show: if mesh.dim()==1: pg.plt.plot(pg.x(mesh), u) pg.wait() elif mesh.dim()==2: pg.show(mesh, u, label='u') pg.wait() xMin = mesh.xmin() xSpan = (mesh.xmax() - xMin) np.testing.assert_allclose(u, (pg.x(mesh)-xMin)/ xSpan) return u
def _test_(mesh, p2=False, show=False): """ \Laplace u = 0 x = [0, -1], y, z int_0^1 u = 0 du/dn = 1 (xMin) (inflow on -x) du/dn = -1 (xMax) (outflow on +x) du/dn = 0 (rest) u = 0.5 -x linear solution, i.e., exact with p1 du/dn = -1 (xMin) (outflow -x) du/dn = -1 (xMax) (outflow +x) du/dn = 0 (rest) u = -1/6 + x -x² quadratic solution, i.e., exact with p2 """ uExact = lambda x, a, b, c: a + b * x + c * x**2 bc = {'Neumann': {1: 1.0, 2: -1.0}} uE = uExact(pg.x(mesh), 0.5, -1.0, 0.0) if p2 is True: mesh = mesh.createP2() bc['Neumann'][1] = -1.0 uE = uExact(pg.x(mesh), -1 / 6, 1.0, -1.0) u = pg.solve(mesh, a=1, f=0, bc=bc, verbose=0) v = pg.solver.grad(mesh, u) if show: if mesh.dim() == 1: idx = np.argsort(pg.x(mesh)) fig, ax = pg.plt.subplots() ax.plot(pg.x(mesh)[idx], uE[idx], label='exact') ax.plot(pg.x(mesh)[idx], u[idx], 'o', label='FEM') model, response = pg.frameworks.fit(uExact, u[idx], x=pg.x(mesh)[idx]) print(model) ax.plot(pg.x(mesh)[idx], response, 'x', label='FIT') ax.grid(True) ax.legend() elif mesh.dim() == 2: pg.show(mesh, u, label='u') ax, _ = pg.show(mesh, pg.abs(v), label='abs(grad(u))') pg.show(mesh, v, showMesh=1, ax=ax) pg.info("int Domain:", pg.solver.intDomain(u, mesh)) pg.info("int Domain:", pg.solver.intDomain([1.0] * mesh.nodeCount(), mesh), sum(mesh.cellSizes())) pg.wait() ## test du/dn of solution and compare with Neumann BC for m, val in bc['Neumann'].items(): for b in mesh.boundaries(mesh.boundaryMarkers() == m): ## for non Tailor Hood Elements, the gradient is only # known at the cell center so the accuracy for the # gradient depends on the distance boundary to cell # center. Accuracy = du/dx(dx) = 1-2x = 2 * dx c = b.leftCell() dx = c.center().dist(b.center()) dudn = b.norm(c).dot(v[c.id()]) if p2: np.testing.assert_allclose(dudn, val, atol=2 * dx) #print(dudn, val) else: np.testing.assert_allclose(dudn, val) np.testing.assert_allclose(pg.solver.intDomain([1.0]*\ mesh.nodeCount(), mesh), sum(mesh.cellSizes())) np.testing.assert_allclose(pg.solver.intDomain(u, mesh), 0.0, atol=1e-8) np.testing.assert_allclose(np.linalg.norm(u - uE), 0.0, atol=1e-8) return v
def test_Robin_BC(self): """ Linear function should result in exact solution with linear base u(x) = Ax + B on x = [0, .. ,1] Dirichlet BC: u(x) = g ---------------------- u(0) = B u(1) = A + B Neumann BC: du/dn(x) = f (non unique, needs calibration point) ------------------------------------------------------------ du/dn(0) = -A (n = [-1, 0, 0]) du/dn(1) = A (n = [ 1, 0, 0]) Robin BC v1: du/dn(x) = a(u0-u(x)) ---------------------------------- du/dn(0) = -A = a (u0 - B) (a=1, u0=-A/a +B) du/dn(1) = A = a (u0 - (A+B)) (a=1, u0= A/a +A+B) Robin BC v2: b du/dn(x) + a u(x) = g ------------------------------------ du/dn(0) = -A + a B = g (a=1, b=1.0, g=-A+a*B) du/dn(1) = A + a (A+B) = g (a=1, b=1.0, g= A + a*(A+B)) """ return show = False A = 1 B = 3 x = np.linspace(0, 1, 11) uExact = lambda x: A * x + B if show: pg.plt.plot(x, uExact(x), label='uExact') mesh = pg.createGrid(x=x) u = pg.solve(mesh, bc={'Dirichlet': {1: B, 2: A + B}}) np.testing.assert_allclose(u, uExact(x)) if show: pg.plt.plot(x, u, 'o', label='u Dirichlet') n = mesh.findNearestNode([0.2, 0.0]) u = pg.solve(mesh, bc={ 'Node': [n, uExact(mesh.node(n).x())], 'Neumann': { 1: -A, 2: A } }) np.testing.assert_allclose(u, uExact(x)) if show: pg.plt.plot(x, u, '.', label='u Neumann') a = 0.5 u1 = -A / a + B u2 = A / a + A + B u = pg.solve(mesh, bc={ 'Robin': { 1: [a, u1], 2: [a, u2] }, }) np.testing.assert_allclose(u, uExact(x)) if show: pg.plt.plot(x, u, '-^', label='u Robin-v1') al = 0.5 ga1 = -A + al * B ga2 = A + al * (A + B) u = pg.solve(mesh, bc={'Robin': { 1: [al, 1.0, ga1], 2: [al, 1.0, ga2], }}) np.testing.assert_allclose(u, uExact(x)) if show: pg.plt.plot(x, u, 'v', label='u Robin-v2') pg.plt.legend()
mesh = pg.createGrid(x=np.linspace(-10.0, 10.0, 41), y=np.linspace(-15.0, 0.0, 31)) mesh = mesh.createP2() sourcePosA = [-5.25, -3.75] sourcePosB = [+5.25, -3.75] k = 1e-2 sigma = 1.0 bc = {'Robin': {'1,2,3': mixedBC}} u = pg.solve(mesh, a=sigma, b=-sigma * k * k, rhs=rhsPointSource(mesh, sourcePosA), bc=bc, userData={ 'sourcePos': sourcePosA, 'k': k, 's': sigma }, verbose=True) u -= pg.solve(mesh, a=sigma, b=-sigma * k * k, rhs=rhsPointSource(mesh, sourcePosB), bc=bc, userData={ 'sourcePos': sourcePosB, 'k': k, 's': sigma
def response(self, model): """Solve forward task. Create apparent resistivity values for a given resistivity distribution for self.mesh. """ mesh = self.mesh() nDof = mesh.nodeCount() nEle = len(self.electrodes) nData = self.data.size() self.resistivity = res = self.createMappedModel(model, -1.0) if self.verbose(): print("Calculate response for model:", min(res), max(res)) rMin = self.electrodes[0].dist(self.electrodes[1]) / 2.0 rMax = self.electrodes[0].dist(self.electrodes[-1]) * 2.0 k, w = self.getIntegrationWeights(rMin, rMax) self.k = k self.w = w rhs = self.createRHS(mesh, self.electrodes) # store all potential fields u = np.zeros((nEle, nDof)) self.subPotentials = [pg.RMatrix(nEle, nDof) for i in range(len(k))] for i, ki in enumerate(k): ws = {'u': self.subPotentials[i]} uE = pg.solve(mesh, a=1./res, b=-(ki * ki)/res, f=rhs, bc={'Robin': self.mixedBC}, userData={'sourcePos': self.electrodes, 'k': ki}, verbose=self.verbose(), stats=0, debug=False, ws=ws, ) u += w[i] * uE # collect potential matrix, # i.e., potential for all electrodes and all injections pM = np.zeros((nEle, nEle)) for i in range(nEle): pM[i] = pg.interpolate(mesh, u[i, :], destPos=self.electrodes) # collect resistivity values for all 4 pole measurements r = np.zeros(nData) for i in range(nData): iA = int(self.data('a')[i]) iB = int(self.data('b')[i]) iM = int(self.data('m')[i]) iN = int(self.data('n')[i]) uAB = pM[iA] - pM[iB] r[i] = uAB[iM] - uAB[iN] self.lastResponse = r * self.data('k') if self.verbose(): print("Resp: ", min(self.lastResponse), max(self.lastResponse)) return self.lastResponse
def response(self, model): """Solve forward task. Create apparent resistivity values for a given resistivity distribution for self.mesh. """ ### NOTE TODO can't be MT until mixed boundary condition depends on ### self.resistivity pg.tic() if not self.data.allNonZero('k'): pg.error('Need valid geometric factors: "k".') pg.warn('Fallback "k" values to -sign("rhoa")') self.data.set('k', -pg.math.sign(self.data('rhoa'))) mesh = self.mesh() nDof = mesh.nodeCount() elecs = self.data.sensorPositions() nEle = len(elecs) nData = self.data.size() self.resistivity = res = self.createMappedModel(model, -1.0) if self.verbose: print("Calculate response for model:", min(res), max(res)) rMin = elecs[0].dist(elecs[1]) / 2.0 rMax = elecs[0].dist(elecs[-1]) * 2.0 k, w = self.getIntegrationWeights(rMin, rMax) self.k = k self.w = w # pg.show(mesh, res, label='res') # pg.wait() rhs = self.createRHS(mesh, elecs) # store all potential fields u = np.zeros((nEle, nDof)) self.subPotentials = [pg.Matrix(nEle, nDof) for i in range(len(k))] for i, ki in enumerate(k): ws = dict() uE = pg.solve(mesh, a=1. / res, b=-(ki * ki) / res, f=rhs, bc={'Robin': ['*', self.mixedBC]}, userData={ 'sourcePos': elecs, 'k': ki }, verbose=False, stats=0, debug=False) self.subPotentials[i] = uE u += w[i] * uE # collect potential matrix, # i.e., potential for all electrodes and all injections pM = np.zeros((nEle, nEle)) for i in range(nEle): pM[i] = pg.interpolate(mesh, u[i, :], destPos=elecs) # collect resistivity values for all 4 pole measurements r = np.zeros(nData) for i in range(nData): iA = int(self.data('a')[i]) iB = int(self.data('b')[i]) iM = int(self.data('m')[i]) iN = int(self.data('n')[i]) uAB = pM[iA] - pM[iB] r[i] = uAB[iM] - uAB[iN] self.lastResponse = r * self.data('k') if self.verbose: print("Resp min/max: {0} {1} {2}s".format(min(self.lastResponse), max(self.lastResponse), pg.dur())) return self.lastResponse
def response(self, model): """Solve forward task. Create apparent resistivity values for a given resistivity distribution for self.mesh. """ mesh = self.mesh() nDof = mesh.nodeCount() nEle = len(self.electrodes) nData = self.data.size() self.resistivity = res = self.createMappedModel(model, -1.0) if self.verbose(): print("Calculate response for model:", min(res), max(res)) rMin = self.electrodes[0].dist(self.electrodes[1]) / 2.0 rMax = self.electrodes[0].dist(self.electrodes[-1]) * 2.0 k, w = self.getIntegrationWeights(rMin, rMax) self.k = k self.w = w rhs = self.createRHS(mesh, self.electrodes) # store all potential fields u = np.zeros((nEle, nDof)) self.subPotentials = [pg.RMatrix(nEle, nDof) for i in range(len(k))] for i, ki in enumerate(k): uE = pg.solve(mesh, a=1. / res, b=(ki * ki) / res, f=rhs, bc={'Robin': self.mixedBC}, userData={ 'sourcePos': self.electrodes, 'k': ki }, verbose=False, stat=0, debug=False, ret=self.subPotentials[i]) u += w[i] * uE # collect potential matrix, # i.e., potential for all electrodes and all injections pM = np.zeros((nEle, nEle)) for i in range(nEle): pM[i] = pg.interpolate(mesh, u[i, :], destPos=self.electrodes) # collect resistivity values for all 4 pole measurements r = np.zeros(nData) for i in range(nData): iA = int(self.data('a')[i]) iB = int(self.data('b')[i]) iM = int(self.data('m')[i]) iN = int(self.data('n')[i]) uAB = pM[iA] - pM[iB] r[i] = uAB[iM] - uAB[iN] self.lastResponse = r * self.data('k') if self.verbose(): print("Resp: ", min(self.lastResponse), max(self.lastResponse)) return self.lastResponse
############################################################################### # For analyzing the accuracy for the approximation we apply the # L2 norm for the finite element space :py:mod:`pygimli.solver.normL2` for a # set of different solutions with decreasing cell size. Instead of using the # the single assembling steps again, we apply our Finite Element shortcut function # :py:mod:`pygimli.solver.solve`. # domain = pg.createGrid(x=np.linspace(0.0, 2 * np.pi, 3), y=np.linspace(0.0, 2 * np.pi, 3)) h = [] l2 = [] for i in range(5): domain = domain.createH2() u_h = pg.solve(domain, f=f, bc={'Dirichlet': {'1:5': 0}}) u = np.array([uExact(_) for _ in domain.positions()]) l2.append(pg.solver.normL2(u - u_h, domain)) h.append(min(domain.boundarySizes())) print("NodeCount: {0}, h:{1}m, L2:{2}%".format(domain.nodeCount(), h[-1], l2[-1])) ax, _ = pg.show() ax.loglog(h, l2, 'o-') ax.set_ylabel('Approximation error: $L_2$ norm') ax.set_xlabel('Cell size $h$ (m)') ax.grid() ############################################################################### # We calculated the examples before for a homogeneous material parameter a=1, # but we can apply any heterogeneous values to0. One way is to create a list of