Commit ba6b4425 by Jonathan Lambrechts

### initial import

parents
 import numpy as np import time import scipy.sparse import scipy.sparse.linalg class Steady : def __init__(self, law, dof, jac, ilu=True) : self.law = law self.meshJacobian = jac self.dof = dof self.preconditioner = None self.tspsolve = 0 self.tvt = 0 self.tas = 0 self.iterative = True self.ilu = ilu self.x = self.dof.new_vector() def solve(self, rtol = 1e-8, atol = 1e-10) : x = self.x self.dof.update_boundary_conditions(self.meshJacobian) x[self.dof._fixedidx] = self.dof._fixedval firstR = None newtonIter = 0 ttot = time.clock() while True : tic = time.clock() res, jac = self.law.volumeTerm(self.meshJacobian, x) self.tvt += time.clock() - tic tic = time.clock() for row in self.dof._fixedidx : a = slice(jac.indptr[row], jac.indptr[row +1]) jac.data[a] = np.where(jac.indices[a] == row, 1., 0.) jac.eliminate_zeros() self.tas += time.clock() - tic res[self.dof._fixedidx] = 0 resn = np.linalg.norm(res) if firstR : print("newton (%i) % 6.2e %.1f" % (newtonIter, resn, -np.log10(resn/firstR))) if (resn/firstR < rtol or resn < atol) : break else : firstR = resn print("newton (%i) % 6.2e" % (newtonIter, resn)) newtonIter += 1 if newtonIter > 10: break tic = time.clock() matrix = jac.tocsc() if not self.preconditioner : P = scipy.sparse.linalg.splu(matrix) self.preconditioner = scipy.sparse.linalg.LinearOperator(matrix.shape, lambda x: P.solve(x)) if self.iterative : info = 1 if self.preconditioner : #I think there is a bug in scipy, without the callback argument, maxiter as no effect dx, info = scipy.sparse.linalg.gmres(matrix, res, tol=1e-10, M=self.preconditioner, maxiter=50, callback=lambda x:None) #if info != 0 and self.ilu: # print("*** PRECOND ***") # P = scipy.sparse.linalg.spilu(matrix) # self.preconditioner = scipy.sparse.linalg.LinearOperator(matrix.shape, lambda x: P.solve(x)) # dx,info = scipy.sparse.linalg.gmres(matrix, res, tol=1e-10, M=self.preconditioner, maxiter=50, callback=lambda x:None) if info != 0 : print("*** PRECOND FULL LU***") P = scipy.sparse.linalg.splu(matrix) self.preconditioner = scipy.sparse.linalg.LinearOperator(matrix.shape, lambda x: P.solve(x)) dx,info = scipy.sparse.linalg.gmres(matrix, res, tol=1e-10, M=self.preconditioner, maxiter=15, callback=lambda x:None) else : dx = scipy.sparse.linalg.spsolve(matrix, res) x -= dx self.tspsolve += time.clock() - tic print("spsolve: %.3g term: %.3g assemble: %.3g" % (self.tspsolve, self.tvt, self.tas)) return x
 from .Brinkman import Brinkman from .Steady import Steady from .dofManager import DofManager from .meshJacobian import MeshJacobian from .legendre import * from .particleFluid import ParticleFluid from .fluidSolver import FluidSolver from .mesh import Mesh
 from . import mesh import numpy as np import scipy.sparse class DofManager : def get_n(self) : return self._ndof def get_field_basis(self, i) : return self._fields[i][2] def getField(self, i, v) : return v[self._fields[i][0]] def getElements(self, iField) : return self._fields[iField][1] def addToField(self, i, vf, v) : np.add.at(v, self._fields[i][0], vf) def setField(self, i, vf, v) : v[self._fields[i][0]] = vf def n_fields(self) : return len(self._fields) def add_field(self, basis) : field = [] elist = [] ifield = len(self._fields) vdof = self._dof_by_dimension[0] nV = basis.n(0) for v in self._mesh.vertices : vdof[(ifield, v[3])] = vdof.get((ifield, v[3]), ()) + tuple(range(self._ndof, self._ndof + nV)) self._ndof += nV for en in self._mesh.entities : n = basis.n(en.dimension) dof = self._dof_by_dimension[en.dimension] if en.dimension != basis.dimension() : continue for e in en.elements : dof[(ifield, e.tag)] = dof.get((ifield, e.tag), ()) + tuple(range(self._ndof, self._ndof + n)) self._ndof += n elist.append(e) cdof = () for v in e.vertices : cdof += vdof.get((ifield, v[3]), ()) cdof += dof[(ifield, e.tag)] field.append(cdof) self._fields.append((np.transpose(np.array(field, np.int)), elist, basis)) def add_boundary_condition(self, tag, field, val = None, cb = None) : if cb is not None : val = 0. vdof = self._dof_by_dimension[0] fixed_start = len(self._fixedidx) fixedvid = [] for en in self._mesh.entities : for ph in en.physicals : phname = self._mesh.getPhysicalName(en.dimension, ph) if phname != tag : continue for e in en.elements : for x, y, z, vid in e.vertices : for dof in vdof.get((field, vid), ()) : if not dof in self._fixed : self._fixed[dof] = len(self._fixedval) self._fixedval.append(val) self._fixedidx.append(dof) fixedvid.append(vid) if cb is not None : self._boundary_cb.append((cb, slice(fixed_start, len(self._fixedidx)), fixedvid)) class matrix(np.ndarray) : def __new__(cls, csrrows, slicedidx) : obj = np.zeros(csrrows.shape).view(cls) obj._csrrows = csrrows obj._slicedidx = slicedidx return obj def to_csr_matrix(self) : return scipy.sparse.csr_matrix((self.flat, (self._csrrows.flat, self._csrrows.swapaxes(1, 2).flat))) def add_to_field(self, f, g, v, els = None) : if els is None: self[:, self._slicedidx[f]:self._slicedidx[f+1], self._slicedidx[g]:self._slicedidx[g+1]] += v else : np.add.at(self[:, self._slicedidx[f]:self._slicedidx[f+1], self._slicedidx[g]:self._slicedidx[g+1]], els, v) class vector(np.ndarray) : def __new__(cls, dofmanager) : obj = np.zeros(dofmanager.get_n()).view(cls) obj._dofmanager = dofmanager return obj def dof_manager(self) : return self._dofmanager def at_qp(self, q) : dofmanager = self._dofmanager NE = len(dofmanager._fields[0][1]) val = np.ndarray((NE, q.shape[0], dofmanager.n_fields())) for i in range(dofmanager.n_fields()) : basis = dofmanager.get_field_basis(i) val[..., i] = np.tensordot(dofmanager.getField(i, self), basis.f(q), [0, 1]) return val def gradient_at_qp(self, q, j) : dofmanager = self._dofmanager NE = len(dofmanager._fields[0][1]) val = np.ndarray((NE, q.shape[0], dofmanager.n_fields(), j.dim)) for i in range(dofmanager.n_fields()) : basis = dofmanager.get_field_basis(i) valxi = np.tensordot(dofmanager.getField(i, self), basis.df(q) , [0, 1]) val[..., i, :] = j.multDXiDXRight(valxi, 2) return val def at_points(self, els, xi) : dofmanager = self._dofmanager val = np.ndarray((len(els), dofmanager.n_fields())) for i in range(dofmanager.n_fields()) : f = dofmanager.getField(i, self)[:, els] basis = dofmanager.get_field_basis(i) val[:, i] = (f * basis.f(xi).T).sum(0) return val def gradient_at_points(self, els, xi, j) : dofmanager = self._dofmanager val = np.ndarray((len(els), dofmanager.n_fields(), j.dim)) for i in range(dofmanager.n_fields()) : f = dofmanager.getField(i, self)[:, els] basis = dofmanager.get_field_basis(i) dxi = (basis.df(xi) * f.T[:, :, None]).sum(1) val[:, i, :] = j.multDXiDXRight(dxi, 1, els) return val def new_vector(self) : return self.vector(self) def new_matrix(self) : return self.matrix(self._jaccsrrows, self._slicedidx) def update_boundary_conditions(self, jac) : x = [jac.dofManager.new_vector() for i in range(jac.dim)] for i in range(jac.dim) : jac.dofManager.setField(0, jac.x[:, :, i].T, x[i]) for cb, idx, vid in self._boundary_cb : vidx = [jac.dofManager._dof_by_dimension[0][(0, i)][0] for i in vid] self._fixedval[idx] = cb(np.hstack((x[i][vidx, None] for i in range(jac.dim)))) def complete(self) : self._fixedidx = np.array(self._fixedidx) self._fixedval = np.array(self._fixedval) self._slicedidx = [0] * (self.n_fields() + 1) n_tot = sum((self.get_field_basis(i).n() for i in range(self.n_fields()))) self._jaccsrrows = np.ndarray((len(self.getElements(0)), n_tot, n_tot)) for f in range(self.n_fields()): self._slicedidx[f + 1] = self._slicedidx[f] + self.get_field_basis(f).n() self._jaccsrrows[:, self._slicedidx[f]:self._slicedidx[f + 1], :] = self._fields[f][0].T[..., None] def __init__(self, mesh) : self._dof_by_dimension = [{},{},{},{}] self._mesh = mesh self._ndof = 0 self._fields = [] self._fixedval = [] self._fixedidx = [] self._fixed = {} self._boundary_cb = []