def parseMapToCellArray(attributeMap, mesh, default=0.0): """ Parse a value map to cell attributes. A map should consist of pairs of marker and value. A marker is an integer and corresponds to the cell.marker(). Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` For each cell of mesh a value will be returned. attributeMap : list | dict List of pairs [marker, value] ] || [[marker, value]], or dictionary with marker keys default : float [0.0] Fill all unmapped atts to this default. Returns ------- atts : array Array of length mesh.cellCount() """ atts = pg.RVector(mesh.cellCount(), default) if isinstance(attributeMap, dict): raise Exception("Please implement me!") elif hasattr(attributeMap, '__len__'): if not hasattr(attributeMap[0], '__len__'): # assuming [marker, value] attributeMap = [attributeMap] for pair in attributeMap: if hasattr(pair, '__len__'): idx = pg.find(mesh.cellMarkers() == pair[0]) if len(idx) == 0: print("Warning! parseMapToCellArray: cannot find marker " + str(pair[0]) + " within mesh.") else: #print('---------------------') #print(atts, idx, pair[1], type(pair[1]), float(pair[1])) if isinstance(pair[1], np.complex): #print('+++++++++++++++++') if not isinstance(atts, pg.CVector): atts = pg.toComplex(atts) atts[idx] = pair[1] else: atts[idx] = float(pair[1]) else: raise Exception("Please provide a list of [int, value] pairs" + str(pair)) else: print("attributeMap: ", attributeMap) raise Exception("Cannot interpret attributeMap!") return atts
def createJacobian(self, model): print('=' * 100) if self.complex(): modelRe = model[0:int(len(model) / 2)] modelIm = model[int(len(model) / 2):len(model)] modelC = pg.toComplex(modelRe, modelIm) print("Real", min(modelRe), max(modelRe)) print("Imag", min(modelIm), max(modelIm)) u = self.prepareJacobian_(modelC) if self._J.rows() == 0: #re(data)/re(mod) = im(data)/im(mod) # we need a local copy until we have a gimli internal reference counter FIXTHIS M1 = pg.RMatrix() M2 = pg.RMatrix() self.matrixHeap.append(M1) self.matrixHeap.append(M2) JRe = self._J.addMatrix(M1) JIm = self._J.addMatrix(M2) self._J.addMatrixEntry(JRe, 0, 0) self._J.addMatrixEntry(JIm, 0, len(modelRe), -1.0) self._J.addMatrixEntry(JIm, self.data().size(), 0, 1.0) self._J.addMatrixEntry(JRe, self.data().size(), len(modelRe)) else: self._J.clean() k = pg.RVector(self.data()('k')) self.data().set('k', k * 0.0 + 1.0) dMapResponse = pb.DataMap() dMapResponse.collect(self.electrodes(), self.solution()) respRe = dMapResponse.data(self.data(), False, False) respIm = dMapResponse.data(self.data(), False, True) #CVector resp(toComplex(respRe, respIm)); #RVector am(abs(resp) * dataContainer_->get("k")); #RVector ph(-phase(resp)); print("respRe", pg.median(respRe), min(respRe), max(respRe)) print("respIm", pg.median(respIm), min(respIm), max(respIm)) JC = pg.CMatrix() self.createJacobian_(modelC, u, JC) for i in range(JC.rows()): #JC[i] *= 1.0/(modelC*modelC) * k[i] JC[i] /= (modelC * modelC) / k[i] self._J.mat(0).copy(pg.real(JC)) self._J.mat(1).copy(pg.imag(JC)) #self.createJacobian_(modelRe*0.0+1.0, pg.real(u), self._J.mat(1)) #self.createJacobian_(modelRe*0.0+1.0, pg.imag(u), self._J.mat(2)) #self.createJacobian_(modelRe*0.0+1.0, pg.imag(u), self._J.mat(3)) sumsens0 = pg.RVector(self._J.mat(0).rows()) sumsens1 = pg.RVector(self._J.mat(0).rows()) sumsens2 = pg.RVector(self._J.mat(0).rows()) for i in range(self._J.mat(0).rows()): #self._J.mat(0)[i] *= 1./modelRe / respRe[i] #self._J.mat(1)[i] *= 1./modelIm / respRe[i] #self._J.mat(2)[i] *= 1./modelRe / respIm[i] #self._J.mat(3)[i] *= 1./modelIm / respIm[i] #self._J.mat(0)[i] *= 1./(modelRe * modelRe) * k[i] #self._J.mat(1)[i] *= 1./(modelRe * modelIm) * k[i] #self._J.mat(2)[i] *= 1./(modelIm * modelRe) * k[i] #self._J.mat(3)[i] *= 1./(modelIm * modelIm) * k[i] sumsens0[i] = sum(self._J.mat(0)[i]) sumsens1[i] = sum(self._J.mat(1)[i]) sumsens2[i] = abs(sum(JC[i])) print(pg.median(sumsens0), min(sumsens0), max(sumsens0)) print(pg.median(sumsens1), min(sumsens1), max(sumsens1)) print(pg.median(sumsens2), min(sumsens2), max(sumsens2)) self.data().set('k', k) self._J.recalcMatrixSize() else: # self.setVerbose(True) u = self.prepareJacobian_(model) #J = pg.RMatrix() if self._J.rows() == 0: print('#' * 100) M1 = pg.RMatrix() Jid = self._J.addMatrix(M1) self._J.addMatrixEntry(Jid, 0, 0) else: self._J.clean() self.createJacobian_(model, u, self._J.mat(0)) self._J.recalcMatrixSize()
def createJacobian(self, model): print('=' * 100) if self.complex(): modelRe = model[0:int(len(model)/2)] modelIm = model[int(len(model)/2):len(model)] modelC = pg.toComplex(modelRe, modelIm) print("Real", min(modelRe), max(modelRe)) print("Imag", min(modelIm), max(modelIm)) u = self.prepareJacobian_(modelC) if self._J.rows() == 0: #re(data)/re(mod) = im(data)/im(mod) # we need a local copy until we have a gimli internal reference counter FIXTHIS M1 = pg.RMatrix() M2 = pg.RMatrix() self.matrixHeap.append(M1) self.matrixHeap.append(M2) JRe = self._J.addMatrix(M1) JIm = self._J.addMatrix(M2) self._J.addMatrixEntry(JRe, 0, 0) self._J.addMatrixEntry(JIm, 0, len(modelRe), -1.0) self._J.addMatrixEntry(JIm, self.data().size(), 0, 1.0) self._J.addMatrixEntry(JRe, self.data().size(), len(modelRe)) else: self._J.clean() k = pg.RVector(self.data()('k')) self.data().set('k', k*0.0 + 1.0) dMapResponse = pb.DataMap() dMapResponse.collect(self.electrodes(), self.solution()) respRe = dMapResponse.data(self.data(), False, False) respIm = dMapResponse.data(self.data(), False, True) #CVector resp(toComplex(respRe, respIm)); #RVector am(abs(resp) * dataContainer_->get("k")); #RVector ph(-phase(resp)); print("respRe", pg.median(respRe), min(respRe), max(respRe)) print("respIm", pg.median(respIm), min(respIm), max(respIm)) JC = pg.CMatrix() self.createJacobian_(modelC, u, JC) for i in range(JC.rows()): #JC[i] *= 1.0/(modelC*modelC) * k[i] JC[i] /= (modelC * modelC) / k[i] self._J.mat(0).copy(pg.real(JC)) self._J.mat(1).copy(pg.imag(JC)) #self.createJacobian_(modelRe*0.0+1.0, pg.real(u), self._J.mat(1)) #self.createJacobian_(modelRe*0.0+1.0, pg.imag(u), self._J.mat(2)) #self.createJacobian_(modelRe*0.0+1.0, pg.imag(u), self._J.mat(3)) sumsens0 = pg.RVector(self._J.mat(0).rows()) sumsens1 = pg.RVector(self._J.mat(0).rows()) sumsens2 = pg.RVector(self._J.mat(0).rows()) for i in range(self._J.mat(0).rows()): #self._J.mat(0)[i] *= 1./modelRe / respRe[i] #self._J.mat(1)[i] *= 1./modelIm / respRe[i] #self._J.mat(2)[i] *= 1./modelRe / respIm[i] #self._J.mat(3)[i] *= 1./modelIm / respIm[i] #self._J.mat(0)[i] *= 1./(modelRe * modelRe) * k[i] #self._J.mat(1)[i] *= 1./(modelRe * modelIm) * k[i] #self._J.mat(2)[i] *= 1./(modelIm * modelRe) * k[i] #self._J.mat(3)[i] *= 1./(modelIm * modelIm) * k[i] sumsens0[i] = sum(self._J.mat(0)[i]) sumsens1[i] = sum(self._J.mat(1)[i]) sumsens2[i] = abs(sum(JC[i])) print(pg.median(sumsens0), min(sumsens0), max(sumsens0)) print(pg.median(sumsens1), min(sumsens1), max(sumsens1)) print(pg.median(sumsens2), min(sumsens2), max(sumsens2)) self.data().set('k', k) self._J.recalcMatrixSize() else: # self.setVerbose(True) u = self.prepareJacobian_(model) #J = pg.RMatrix() if self._J.rows() == 0: print('#' * 100) M1 = pg.RMatrix() Jid = self._J.addMatrix(M1) self._J.addMatrixEntry(Jid, 0, 0) else: self._J.clean() self.createJacobian_(model, u, self._J.mat(0)) self._J.recalcMatrixSize()
def solveFiniteElements(mesh, a=1.0, b=0.0, f=0.0, times=None, userData=None, verbose=False, stats=None, **kwargs): """ WRITEME short WRITEME long Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` Mesh represents spatial discretization of the calculation domain a : value | array | callable(cell, userData) Cell values b : value | array | callable(cell, userData) Cell values u0 : value | array | callable(pos, userData) Node values ub : value | array | callable(pos, userData) Dirichlet values for u at the boundary dub : value | array | callable(pos, userData) Neumann values for du/dn at the boundary f : value | array(cells) | array(nodes) | callable(args, kwargs) force values times : array [None] solve as time dependent problem for the given times theta : float [1] - `theta` = 0, explicit Euler, maybe stable for - `theta` = 0.5, Crank-Nicolsen, maybe instable - `theta` = 1, implicit Euler .. math:: \\Delta t \\quad\\text{near}\\quad h Time dependent equation is stable for: .. math:: 0.5 <= \\theta <= 1.0 If unsure choose 0.5 + epsilon, which is probably be stable. progress : bool Give some calculation progress. Returns ------- u : array Returns the solution u either 1,n array for stationary problems or for m,n array for m time steps Examples -------- >>> import pygimli as pg >>> from pygimli.meshtools import polytools as plc >>> from pygimli.mplviewer import drawField, drawMesh >>> import matplotlib.pyplot as plt >>> world = plc.createWorld(start=[-10, 0], end=[10, -10], marker=1, worldMarker=False) >>> c1 = plc.createCircle(pos=[0.0, -5.0], radius=3.0, area=.1, marker=2) >>> mesh = pg.meshtools.createMesh([world, c1], quality=34.3) >>> u = pg.solver.solveFiniteElements(mesh, a=[[1, 100], [2, 1]], uB=[[4, 1.0], [3, 0.0]]) >>> fig, ax = plt.subplots() >>> pc = drawField(ax, mesh, u) >>> drawMesh(ax, mesh) >>> plt.show() See Also -------- other solver TODO """ if 'uDirichlet' in kwargs or 'uBoundary' in kwargs: raise("use uB instead") if 'uBoundary' in kwargs: raise("use duB instead") debug = kwargs.pop('debug', False) if verbose: print("Mesh: ", str(mesh)) dof = mesh.nodeCount() swatch = pg.Stopwatch(True) swatch2 = pg.Stopwatch(True) # check for material parameter a = parseArgToArray(a, ndof=mesh.cellCount(), mesh=mesh, userData=userData) b = parseArgToArray(b, ndof=mesh.cellCount(), mesh=mesh, userData=userData) if debug: print("2: ", swatch2.duration(True)) # assemble the stiffness matrix A = createStiffnessMatrix(mesh, a) if debug: print("3: ", swatch2.duration(True)) M = createMassMatrix(mesh, b) if debug: print("4: ", swatch2.duration(True)) S = A + M if debug: print("5: ", swatch2.duration(True)) if times is None: rhs = assembleForceVector(mesh, f, userData=userData) if debug: print("6a: ", swatch2.duration(True)) if 'duB' in kwargs: print(userData) assembleNeumannBC(S, parseArgToBoundaries(kwargs['duB'], mesh), time=0.0, userData=userData, verbose=False) if debug: print("6b: ", swatch2.duration(True)) if 'uB' in kwargs: assembleDirichletBC(S, parseArgToBoundaries(kwargs['uB'], mesh), rhs, time=0.0, userData=userData, verbose=False) if debug: print("6c: ", swatch2.duration(True)) u = None if isinstance(a[0], complex): u = pg.CVector(rhs.size(), 0.0) rhs = pg.toComplex(rhs) else: u = pg.RVector(rhs.size(), 0.0) if debug: print("7: ", swatch2.duration(True)) assembleTime = swatch.duration(True) if stats: stats.assembleTime = assembleTime if verbose: print(("Asssemblation time: ", assembleTime)) # showSparseMatrix(S) solver = pg.LinSolver(False) solver.setMatrix(S, 0) u = solver.solve(rhs) solverTime = swatch.duration(True) if verbose: if stats: stats.solverTime = solverTime print(("Solving time: ", solverTime)) return u else: if debug: print("start TL", swatch.duration()) M = createMassMatrix(mesh) F = assembleForceVector(mesh, f) if 'u0' in kwargs: u0 = parseArgToArray(kwargs['u0'], dof, mesh, userData) theta = kwargs.pop('theta', 1) if not 'duB' in kwargs: A = createStiffnessMatrix(mesh, a) if 'uB' in kwargs: assembleDirichletBC(A, parseArgToBoundaries(kwargs['uB'], mesh), rhs=F) return crankNicolson(times, theta, A, M, F, u0=u0, verbose=verbose) rhs = np.zeros((len(times), dof)) # rhs kann zeitabhängig sein ..wird hier nicht berücksichtigt rhs[:] = F # this is slow: optimize if debug: print("rhs", swatch.duration()) U = np.zeros((len(times), dof)) U[0, :] = u0 # init state u = pg.RVector(dof, 0.0) if debug: print("u0", swatch.duration()) measure = 0. for n in range(1, len(times)): swatch.reset() dt = times[n] - times[n - 1] # previous timestep # print "i: ", i, dt, U[i - 1] if 'duB' in kwargs: # aufschreiben und checken ob neumann auf A oder auf S mit # skaliertem val*dt angewendet wird A = createStiffnessMatrix(mesh, a) assembleNeumannBC(A, parseArgToBoundaries(kwargs['duB'], mesh), time=times[n], userData=userData, verbose=False) swatch.reset() # (A + a*B)u is fastest, followed by A*u + (B*u)*a and finally A*u + a*B*u and b = (M + (dt * (theta - 1.)) * A ) * U[n - 1] + \ dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n]) #print ('a',swatch.duration(True)) # b = M * U[n - 1] - (A * U[n - 1]) * (dt*(1.0 - theta)) + \ #dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n]) #print ('b',swatch.duration(True)) # b = M * U[n - 1] - (dt*(1.0 - theta)) * A * U[n - 1] + \ #dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n]) #print ('c',swatch.duration(True)) measure += swatch.duration() S = M + A * dt * theta if 'uB' in kwargs: assembleDirichletBC(S, parseArgToBoundaries(kwargs['uB'], mesh), rhs=b, time=times[n], userData=userData, verbose=verbose) #u = S/b t_prep = swatch.duration(True) solver = pg.LinSolver(S, verbose) solver.solve(b, u) if 'plotTimeStep' in kwargs: kwargs['plotTimeStep'](u, times[n]) U[n, :] = np.asarray(u) if 'progress' in kwargs: if kwargs['progress']: print(("\t" + str(n) + "/" + str(len(times) - 1) + ": " + str(t_prep) + "/" + str(swatch.duration()))) if debug: print("Measure(" + str(len(times)) + "): ", measure, measure / len(times)) return U
def solveFiniteElements(mesh, a=1.0, b=0.0, f=0.0, times=None, userData=None, verbose=False, stats=None, **kwargs): r"""Solve partial differential equation with Finite Elements. This function is a syntactic sugar proxy for using the Finite Element functionality of the library core to solve elliptic and parabolic partial differential of the following type: .. math:: \frac{\partial u}{\partial t} & = \nabla\cdot(a \nabla u) + b u + f(\mathbf{r},t) \\ u(\mathbf{r}, t) & = u_B \quad\mathbf{r}\in\Gamma_{\text{Dirichlet}}\\ \frac{\partial u(\mathbf{r}, t)}{\partial \mathbf{n}} & = u_{\partial \text{B}} \quad\mathbf{r}\in\Gamma_{\text{Neumann}}\\ u(\mathbf{r}, t=0) & = u_0 \quad\text{with} \quad\mathbf{r}\in\Omega\quad\text{for}\quad t\neq 0 The Domain :math:`\Omega` and the Boundary :math:`\Gamma` are defined through the given mesh with appropriate boundary marker. The solution :math:`u(\mathbf{r}, t)` is given for each node in mesh. TODO: * unsteady ub and dub Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` Mesh represents spatial discretization of the calculation domain a : value | array | callable(cell, userData) Cell values b : value | array | callable(cell, userData) Cell values u0 : value | array | callable(pos, userData) Node values uB : value | array | callable(pos, userData) Dirichlet values for u at the boundary uN : list([node, value]) Dirichlet values for u at given nodes duB : value | array | callable(pos, userData) Neumann values for du/dn at the boundary f : value | array(cells) | array(nodes) | callable(args, kwargs) force values times : array [None] Solve as time dependent problem for the given times. theta : float [1] - :math:`theta = 0` means explicit Euler, maybe stable for :math:`\Delta t \quad\text{near}\quad h` - :math:`theta = 0.5`, Crank-Nicolsen, maybe instable - :math:`theta = 1`, implicit Euler If unsure choose :math:`\theta = 0.5 + \epsilon`, which is probably stable. progress : bool Give some calculation progress. ret : Workspace for results so no new memory will be allocated. Returns ------- u : array Returns the solution u either 1,n array for stationary problems or for m,n array for m time steps Examples -------- >>> import pygimli as pg >>> from pygimli.meshtools import polytools as plc >>> from pygimli.mplviewer import drawField, drawMesh >>> import matplotlib.pyplot as plt >>> world = plc.createWorld(start=[-10, 0], end=[10, -10], ... marker=1, worldMarker=False) >>> c1 = plc.createCircle(pos=[0.0, -5.0], radius=3.0, area=.1, marker=2) >>> mesh = pg.meshtools.createMesh([world, c1], quality=34.3) >>> u = pg.solver.solveFiniteElements(mesh, a=[[1, 100], [2, 1]], ... uB=[[4, 1.0], [2, 0.0]]) >>> fig, ax = plt.subplots() >>> pc = drawField(ax, mesh, u) >>> drawMesh(ax, mesh) >>> plt.show() See Also -------- other solver TODO """ if 'uDirichlet' in kwargs or 'uBoundary' in kwargs: raise BaseException("use uB instead") if 'uBoundary' in kwargs: raise BaseException("use duB instead") debug = kwargs.pop('debug', False) mesh.createNeighbourInfos() if verbose: print("Mesh: ", str(mesh)) dof = mesh.nodeCount() swatch = pg.Stopwatch(True) swatch2 = pg.Stopwatch(True) # check for material parameter a = parseArgToArray(a, ndof=mesh.cellCount(), mesh=mesh, userData=userData) b = parseArgToArray(b, ndof=mesh.cellCount(), mesh=mesh, userData=userData) if debug: print("2: ", swatch2.duration(True)) # assemble the stiffness matrix A = createStiffnessMatrix(mesh, a) if debug: print("3: ", swatch2.duration(True)) M = createMassMatrix(mesh, b) if debug: print("4: ", swatch2.duration(True)) S = A + M if debug: print("5: ", swatch2.duration(True)) if times is None: rhs = assembleForceVector(mesh, f, userData=userData) if debug: print("6a: ", swatch2.duration(True)) if 'duB' in kwargs: assembleNeumannBC(S, parseArgToBoundaries(kwargs['duB'], mesh), time=0.0, userData=userData) if debug: print("6b: ", swatch2.duration(True)) if 'uB' in kwargs: assembleDirichletBC(S, parseArgToBoundaries(kwargs['uB'], mesh), rhs, time=0.0, userData=userData) if 'uN' in kwargs: assembleDirichletBC(S, [], nodePairs=kwargs['uN'], rhs=rhs, time=0.0, userData=userData) if debug: print("6c: ", swatch2.duration(True)) # create result array u = kwargs.pop('ret', None) singleForce = True if hasattr(rhs, 'ndim'): if rhs.ndim == 2: singleForce = False if u is None: u = np.zeros(rhs.shape) else: if isinstance(a[0], complex): if u is None: u = pg.CVector(rhs.size(), 0.0) rhs = pg.toComplex(rhs) else: if u is None: u = pg.RVector(rhs.size(), 0.0) assembleTime = swatch.duration(True) if stats: stats.assembleTime = assembleTime if verbose: print(("Asssemblation time: ", assembleTime)) # showSparseMatrix(S) solver = pg.LinSolver(False) solver.setMatrix(S, 0) if singleForce: u = solver.solve(rhs) else: for i, r in enumerate(rhs): solver.solve(r, u[i]) solverTime = swatch.duration(True) if verbose: if stats: stats.solverTime = solverTime print(("Solving time: ", solverTime)) return u else: if debug: print("start TL", swatch.duration()) M = createMassMatrix(mesh) F = assembleForceVector(mesh, f) if 'u0' in kwargs: u0 = parseArgToArray(kwargs['u0'], dof, mesh, userData) theta = kwargs.pop('theta', 1) if 'duB' not in kwargs: A = createStiffnessMatrix(mesh, a) if 'uB' in kwargs: assembleDirichletBC(A, parseArgToBoundaries(kwargs['uB'], mesh), rhs=F) if 'uN' in kwargs: assembleDirichletBC(A, [], nodePairs=kwargs['uN'], rhs=F) return crankNicolson(times, theta, A, M, F, u0=u0, verbose=verbose) rhs = np.zeros((len(times), dof)) # rhs kann zeitabhängig sein ..wird hier nicht berücksichtigt rhs[:] = F # this is slow: optimize if debug: print("rhs", swatch.duration()) U = np.zeros((len(times), dof)) U[0, :] = u0 # init state u = pg.RVector(dof, 0.0) if debug: print("u0", swatch.duration()) measure = 0. for n in range(1, len(times)): swatch.reset() dt = times[n] - times[n - 1] # previous timestep # print "i: ", i, dt, U[i - 1] if 'duB' in kwargs: # aufschreiben und checken ob neumann auf A oder auf S mit # skaliertem val*dt angewendet wird A = createStiffnessMatrix(mesh, a) assembleNeumannBC(A, parseArgToBoundaries(kwargs['duB'], mesh), time=times[n], userData=userData) swatch.reset() # (A + a*B)u is fastest, # followed by A*u + (B*u)*a and finally A*u + a*B*u and b = (M + (dt * (theta - 1.)) * A) * U[n - 1] + \ dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n]) # print ('a',swatch.duration(True)) # b = M * U[n - 1] - (A * U[n - 1]) * (dt*(1.0 - theta)) + \ # dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n]) # print ('b',swatch.duration(True)) # b = M * U[n - 1] - (dt*(1.0 - theta)) * A * U[n - 1] + \ # dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n]) # print ('c',swatch.duration(True)) measure += swatch.duration() S = M + A * dt * theta if 'uB' in kwargs: assembleDirichletBC(S, parseArgToBoundaries(kwargs['uB'], mesh), rhs=b, time=times[n], userData=userData) if 'uN' in kwargs: assembleDirichletBC(S, [], nodePairs=kwargs['uN'], rhs=b, time=times[n], userData=userData) # u = S/b t_prep = swatch.duration(True) solver = pg.LinSolver(S, verbose) solver.solve(b, u) if 'plotTimeStep' in kwargs: kwargs['plotTimeStep'](u, times[n]) U[n, :] = np.asarray(u) if 'progress' in kwargs: if kwargs['progress']: print(("\t" + str(n) + "/" + str(len(times) - 1) + ": " + str(t_prep) + "/" + str(swatch.duration()))) if debug: print("Measure(" + str(len(times)) + "): ", measure, measure / len(times)) return U
def solvePoisson(mesh, a=1.0, b=0.0, f=0.0, times=None, userData=None, verbose=False, stats=None, *args, **kwargs): """ TODO The value of :math:`\omega` is larger than 5. Variable names are displayed in typewriter font, obtained by using \\mathtt{var}: We square the input parameter `a` to obtain :math:`\mathtt{alpha}^2`. Parameters ---------- a : value | array | callable(cell, userData) Cell values b : value | array | callable(cell, userData) Cell values u0 : value | array | callable(pos, userData) Node values f : value | array(cells) | array(nodes) | callable(args, kwargs) force values theta : float - `theta` = 0, explicit Euler, maybe stable for - `theta` = 0.5, Crank-Nicolsen, maybe instable - `theta` = 1, implicit Euler .. math:: \\Delta t \\quad\\text{near}\\quad h Time dependent equation is stable for: .. math:: 0.5 <= \\theta <= 1.0 If unsure choose 0.5 + epsilon, which is probably be stable. progress : bool Give some calculation progress. Returns ------- u : array Returns the solution u either 1,n array for stationary problems or for m,n array for m time steps See Also -------- other solver TODO """ if verbose: print(("Mesh: ", str(mesh))) dof = mesh.nodeCount() swatch = pg.Stopwatch(True) swatch2 = pg.Stopwatch(True) # check for material parameter a = parseArgToArray(a, mesh.cellCount(), mesh, userData) b = parseArgToArray(b, mesh.cellCount(), mesh, userData) print("2: ", swatch2.duration(True)) # assemble the stiffness matrix A = createStiffnessMatrix(mesh, a) print("3: ", swatch2.duration(True)) M = createMassMatrix(mesh, b) print("4: ", swatch2.duration(True)) S = A + M print("5: ", swatch2.duration(True)) if times == None: rhs = assembleForceVector(mesh, f, userData=userData) print("6a: ", swatch2.duration(True)) if 'duBoundary' in kwargs: assembleBoundaryConditions(mesh, S, rhs, kwargs['duBoundary'], assembleNeumannBC, userData=userData, verbose=verbose) print("6b: ", swatch2.duration(True)) if 'uBoundary' in kwargs: assembleBoundaryConditions(mesh, S, rhs, kwargs['uBoundary'], assembleDirichletBC, userData=userData, verbose=verbose) print("6c: ", swatch2.duration(True)) if 'uDirichlet' in kwargs: assembleUDirichlet_(S, rhs, kwargs['uDirichlet'][0], kwargs['uDirichlet'][1]) u = None if type(a[0]) is float: u = pg.RVector(rhs.size(), 0.0) else: u = pg.CVector(rhs.size(), 0.0) rhs = pg.toComplex(rhs) print("7: ", swatch2.duration(True)) assembleTime = swatch.duration(True) if stats: stats.assembleTime = assembleTime if verbose: print(("Asssemblation time: ", assembleTime)) #showSparseMatrix(S) solver = pg.LinSolver(1) solver.setMatrix(S, 0) u = solver.solve(rhs) solverTime = swatch.duration(True) if verbose: if stats: stats.solverTime = solverTime print(("Solving time: ", solverTime)) return u else: print("start TL", swatch.duration()) M = createMassMatrix(mesh, pg.RVector(mesh.cellCount(), 1.0)) rhs = np.zeros((len(times), dof)) # rhs kann zeitabhängig sein ..wird hier nicht berücksichtigt rhs[:] = assembleForceVector(mesh, f) # this is slow: optimize print("rhs", swatch.duration()) U = np.zeros((len(times), dof)) #init state u = pg.RVector(dof, 0.0) if 'u0' in kwargs: U[0, :] = parseArgToArray(kwargs['u0'], dof, mesh, userData) theta = 1.0 if 'theta' in kwargs: theta = float(kwargs['theta']) print("u0", swatch.duration()) measure = 0. for n in range(1, len(times)): swatch.reset() dt = times[n] - times[n - 1] #u[n] = u[n-1] + dt * theta * L(u[n]) + dt * (1-theta) * L(u[n-1]) # previous timestep #print "i: ", i, dt, U[i - 1] if 'duBoundary' in kwargs: # aufschreiben und checken ob neumann auf A oder auf S mit skaliertem val*dt angewendet wird A = createStiffnessMatrix(mesh, a) assembleBoundaryConditions(mesh, A, None, kwargs['duBoundary'], assembleNeumannBC, time=times[n], verbose=verbose) swatch.reset() # (A + a*B)u is fastest, followed by A*u + (B*u)*a and finally A*u + a*B*u and b = (M - (dt*(1.0 - theta)) * A) * U[n - 1] + \ dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n]) #print ('a',swatch.duration(True)) #b = M * U[n - 1] - (A * U[n - 1]) * (dt*(1.0 - theta)) + \ #dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n]) #print ('b',swatch.duration(True)) #b = M * U[n - 1] - (dt*(1.0 - theta)) * A * U[n - 1] + \ #dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n]) #print ('c',swatch.duration(True)) measure += swatch.duration() S = M + A * dt * theta if 'uBoundary' in kwargs: assembleBoundaryConditions(mesh, S, b, kwargs['uBoundary'], assembleDirichletBC, time=times[n], verbose=verbose) #u = S/b t_prep = swatch.duration(True) solver = pg.LinSolver(S, verbose) solver.solve(b, u) if 'plotTimeStep' in kwargs: kwargs['plotTimeStep'](u, times[n]) U[n,:] = np.asarray(u) if 'progress' in kwargs: if kwargs['progress']: print(("\t" + str(n) +"/" + str(len(times)-1) + ": " + str(t_prep) +"/" + str(swatch.duration()))) print( "Measure("+str(len(times))+"): ", measure, measure/len(times)) return U # def solvePoisson(..):