def geneForwardMatrix(self, q_fun=fe.Constant(0.0), fR=fe.Constant(0.0), \ fI=fe.Constant(0.0)): if self.haveFunctionSpace == False: self.geneFunctionSpace() xx, yy, dPML, sig0_, p_ = self.domain.xx, self.domain.yy, self.domain.dPML,\ self.domain.sig0, self.domain.p # define the coefficents induced by PML sig1 = fe.Expression('x[0] > x1 && x[0] < x1 + dd ? sig0*pow((x[0]-x1)/dd, p) : (x[0] < 0 && x[0] > -dd ? sig0*pow((-x[0])/dd, p) : 0)', degree=3, x1=xx, dd=dPML, sig0=sig0_, p=p_) sig2 = fe.Expression('x[1] > x2 && x[1] < x2 + dd ? sig0*pow((x[1]-x2)/dd, p) : (x[1] < 0 && x[1] > -dd ? sig0*pow((-x[1])/dd, p) : 0)', degree=3, x2=yy, dd=dPML, sig0=sig0_, p=p_) sR = fe.as_matrix([[(1+sig1*sig2)/(1+sig1*sig1), 0.0], [0.0, (1+sig1*sig2)/(1+sig2*sig2)]]) sI = fe.as_matrix([[(sig2-sig1)/(1+sig1*sig1), 0.0], [0.0, (sig1-sig2)/(1+sig2*sig2)]]) cR = 1 - sig1*sig2 cI = sig1 + sig2 # define the coefficients with physical meaning angl_fre = self.kappa*np.pi angl_fre2 = fe.Constant(angl_fre*angl_fre) # define equations u_ = fe.TestFunction(self.V) du = fe.TrialFunction(self.V) u_R, u_I = fe.split(u_) duR, duI = fe.split(du) def sigR(v): return fe.dot(sR, fe.nabla_grad(v)) def sigI(v): return fe.dot(sI, fe.nabla_grad(v)) F1 = - fe.inner(sigR(duR)-sigI(duI), fe.nabla_grad(u_R))*(fe.dx) \ - fe.inner(sigR(duI)+sigI(duR), fe.nabla_grad(u_I))*(fe.dx) \ - fR*u_R*(fe.dx) - fI*u_I*(fe.dx) a2 = fe.inner(angl_fre2*q_fun*(cR*duR-cI*duI), u_R)*(fe.dx) \ + fe.inner(angl_fre2*q_fun*(cR*duI+cI*duR), u_I)*(fe.dx) \ # define boundary conditions def boundary(x, on_boundary): return on_boundary bc = [fe.DirichletBC(self.V.sub(0), fe.Constant(0.0), boundary), \ fe.DirichletBC(self.V.sub(1), fe.Constant(0.0), boundary)] a1, L1 = fe.lhs(F1), fe.rhs(F1) self.u = fe.Function(self.V) self.A1 = fe.assemble(a1) self.b1 = fe.assemble(L1) self.A2 = fe.assemble(a2) bc[0].apply(self.A1, self.b1) bc[1].apply(self.A1, self.b1) bc[0].apply(self.A2) bc[1].apply(self.A2) self.A = self.A1 + self.A2
def create_bilinear_form_and_rhs(self): # Define variational problem u = fe.TrialFunction(self.function_space) v = fe.TestFunction(self.function_space) if self.dimension == 1: diffusion_tensor = self.diffusion_matrix self.bilinear_form = (1 + self.lam * self.dt) * (u * v * fe.dx) +\ self.dt * (fe.dot(\ diffusion_tensor * fe.grad(u),\ fe.grad(v)) * fe.dx) if self.dimension == 2: diffusion_tensor = fe.as_matrix(self.diffusion_matrix) self.bilinear_form = (1 + self.lam * self.dt) * (u * v * fe.dx) +\ self.dt * (fe.dot(\ fe.dot(diffusion_tensor, fe.grad(u)),\ fe.grad(v)) * fe.dx) self.rhs = (self.u_n + self.dt * self.rhs_fun) * v * fe.dx
def __init__( self, mesh=None, width=1.0, dim=1, nelements=8, degree=2, parameters={}, V=(lambda U: U), U0=None, rho0=None, t0=0.0, debug=False, solver_type = 'lu', preconditioner_type = 'default', periodic=True, ligands=None ): """DG solver for the periodic Keller-Segel PDE system Keyword parameters: mesh=None: the mesh on which to solve the problem width=1.0: the width of the domain dim=1: # of spatial dimensions. nelements=8: If mesh is not supplied, one will be contructed using UnitIntervalMesh, UnitSquareMesh, or UnitCubeMesh (depending on dim). dim and nelements are not needed if mesh is supplied. degree=2: degree of the polynomial approximation parameters={}: a dict giving the values of scalar parameters of .V, U0, and rho0 Expressions. This dict needs to also define numerical parameters that appear in the PDE. Some of these have defaults: dim = dim: # of spatial dimensions sigma: organism movement rate s: attractant secretion rate gamma: attractant decay rate D: attractant diffusion constant rho_min=10.0**-7: minimum feasible worm density U_min=10.0**-7: minimum feasible attractant concentration rhopen=10: penalty for discontinuities in rho Upen=1: penalty for discontinuities in U grhopen=1, gUpen=1: penalties for discontinuities in gradients V=(lambda U: U): a callable taking two numerical arguments, U and rho, or a single argument, U, and returning a single number, V, the potential corresponding to U. Use fenics versions of mathematical functions, e.g. fe.ln, abs, fe.exp. U0, rho0: Expressions, Functions, or strs specifying the initial condition. t0=0.0: initial time solver_type='lu' preconditioner_type='default' periodic=True: Allowed for compatibility, but ignored ligands=None: ignored for compatibility """ logPERIODIC('creating KSDGSolverPeriodic') self.args = dict( mesh=mesh, width=width, dim=dim, nelements=nelements, degree=degree, parameters=parameters, V=V, U0=U0, rho0=rho0, t0=t0, debug=debug, solver_type = solver_type, preconditioner_type = preconditioner_type, periodic=True, ligands=ligands ) self.debug = debug self.solver_type = solver_type self.preconditioner_type = preconditioner_type self.periodic = True self.params = self.default_params.copy() # # Store the original mesh in self.omesh. self.mesh will be the # corner mesh. # if (mesh): self.omesh = mesh else: self.omesh = box_mesh(width=width, dim=dim, nelements=nelements) self.nelements = nelements try: comm = self.omesh.mpi_comm().tompi4py() except AttributeError: comm = self.omesh.mpi_comm() self.lmesh = gather_mesh(self.omesh) omeshstats = mesh_stats(self.omesh) logPERIODIC('omeshstats', omeshstats) self.xmin = omeshstats['xmin'] self.xmax = omeshstats['xmax'] self.xmid = omeshstats['xmid'] self.delta_ = omeshstats['dx'] self.mesh = corner_submesh(self.lmesh) meshstats = mesh_stats(self.mesh) logPERIODIC('meshstats', meshstats) logPERIODIC('self.omesh', self.omesh) logPERIODIC('self.mesh', self.mesh) logPERIODIC('self.mesh.mpi_comm().size', self.mesh.mpi_comm().size) self.nelements = nelements self.degree = degree self.dim = self.mesh.geometry().dim() self.params['dim'] = self.dim self.params.update(parameters) # # Solution spaces and Functions # # The solution function space is a vector space with # 2*(2**dim) elements. The first 2**dim components are even # and odd parts of rho; These are followed by even and # odd parts of U. The array self.evenodd identifies even # and odd components. Each row is a length dim sequence 0s and # 1s and represnts one component. For instance, if evenodd[i] # is [0, 1, 0], then component i of the vector space is even # in dimensions 0 and 2 (x and z conventionally) and off in # dimension 1 (y). # self.symmetries = evenodd_symmetries(self.dim) self.signs = [fe.as_matrix(np.diagflat(1.0 - 2.0*eo)) for eo in self.symmetries] self.eomat = evenodd_matrix(self.symmetries) fss = self.make_function_space() (self.SE, self.SS, self.VE, self.VS) = [ fss[fs] for fs in ('SE', 'SS', 'VE', 'VS') ] (self.SE, self.SS, self.VE, self.VS) = self.make_function_space() self.sol = Function(self.VS) # sol, current soln logPERIODIC('self.sol', self.sol) # srhos and sUs are fcuntions defiend on subspaces self.srhos = self.sol.split()[:2**self.dim] self.sUs = self.sol.split()[2**self.dim:] # irhos and iUs are Indexed UFL expressions self.irhos = fe.split(self.sol)[:2**self.dim] self.iUs = fe.split(self.sol)[2**self.dim:] self.wrhos = TestFunctions(self.VS)[: 2**self.dim] self.wUs = TestFunctions(self.VS)[2**self.dim :] self.tdsol = TrialFunction(self.VS) # time derivatives self.tdrhos = fe.split(self.tdsol)[: 2**self.dim] self.tdUs = fe.split(self.tdsol)[2**self.dim :] bc_method = 'geometric' if self.dim > 1 else 'pointwise' rhobcs = [DirichletBC( self.VS.sub(i), Constant(0), FacesDomain(self.mesh, self.symmetries[i]), method=bc_method ) for i in range(2**self.dim) if np.any(self.symmetries[i] != 0.0)] Ubcs = [DirichletBC( self.VS.sub(i + 2**self.dim), Constant(0), FacesDomain(self.mesh, self.symmetries[i]), method=bc_method ) for i in range(2**self.dim) if np.any(self.symmetries[i] != 0.0)] self.bcs = rhobcs + Ubcs self.n = FacetNormal(self.mesh) self.h = CellDiameter(self.mesh) self.havg = fe.avg(self.h) self.dx = fe.dx self.dS = fe.dS # # record initial state # if not U0: U0 = Constant(0.0) if isinstance(U0, ufl.coefficient.Coefficient): self.U0 = U0 else: self.U0 = Expression(U0, **self.params, degree=self.degree, domain=self.mesh) if not rho0: rho0 = Constant(0.0) if isinstance(rho0, ufl.coefficient.Coefficient): self.rho0 = rho0 else: self.rho0 = Expression(rho0, **self.params, degree=self.degree, domain=self.mesh) try: V(self.U0, self.rho0) def realV(U, rho): return V(U, rho) except TypeError: def realV(U, rho): return V(U) self.V = realV self.t0 = t0 # # initialize state # # cache assigners logPERIODIC('restarting') self.restart() logPERIODIC('restart returned') return(None)
def __init__(self, mesh=None, width=1.0, dim=1, nelements=8, degree=2, parameters={}, param_funcs={}, V=(lambda U, params={}: sum(U)), U0=[], rho0=None, t0=0.0, debug=False, solver_type='petsc', preconditioner_type='default', periodic=True, ligands=None): """Discontinuous Galerkin solver for the Keller-Segel PDE system Like KSDGSolverVariable, but with periodic boundary conditions. """ logVARIABLE('creating KSDGSolverVariablePeriodic') if not ligands: ligands = LigandGroups() else: ligands = copy.deepcopy(ligands) self.args = dict(mesh=mesh, width=width, dim=dim, nelements=nelements, degree=degree, parameters=parameters, param_funcs=param_funcs, V=V, U0=U0, rho0=rho0, t0=t0, debug=debug, solver_type=solver_type, preconditioner_type=preconditioner_type, periodic=True, ligands=ligands) self.t0 = t0 self.debug = debug self.solver_type = solver_type self.preconditioner_type = preconditioner_type self.periodic = True self.ligands = ligands self.nligands = ligands.nligands() self.init_params(parameters, param_funcs) if nelements is None: self.nelements = 8 else: self.nelements = nelements if (mesh): self.omesh = self.mesh = mesh else: self.omesh = self.mesh = box_mesh(width=width, dim=dim, nelements=self.nelements) self.nelements = nelements omeshstats = mesh_stats(self.omesh) try: comm = self.omesh.mpi_comm().tompi4py() except AttributeError: comm = self.omesh.mpi_comm() self.lmesh = gather_mesh(self.omesh) logVARIABLE('omeshstats', omeshstats) self.xmin = omeshstats['xmin'] self.xmax = omeshstats['xmax'] self.xmid = omeshstats['xmid'] self.delta_ = omeshstats['dx'] if nelements is None: self.nelements = (self.xmax - self.xmin) / self.delta_ self.mesh = corner_submesh(self.lmesh) meshstats = mesh_stats(self.mesh) self.degree = degree self.dim = self.mesh.geometry().dim() # # Solution spaces and Functions # self.symmetries = evenodd_symmetries(self.dim) self.signs = [ fe.as_matrix(np.diagflat(1.0 - 2.0 * eo)) for eo in self.symmetries ] self.eomat = evenodd_matrix(self.symmetries) fss = self.make_function_space() (self.SE, self.SS, self.VE, self.VS) = [fss[fs] for fs in ('SE', 'SS', 'VE', 'VS')] logVARIABLE('self.VS', self.VS) self.sol = Function(self.VS) # sol, current soln logVARIABLE('self.sol', self.sol) splitsol = self.sol.split() self.srhos = splitsol[:2**self.dim] self.sUs = splitsol[2**self.dim:] splitsol = list(fe.split(self.sol)) self.irhos = splitsol[:2**self.dim] self.iUs = splitsol[2**self.dim:] self.iPs = list(fe.split(self.PSf)) self.iparams = collections.OrderedDict(zip(self.param_names, self.iPs)) self.iligands = copy.deepcopy(self.ligands) self.iligand_params = ParameterList( [p for p in self.iligands.params() if p[0] in self.param_numbers]) for k in self.iligand_params.keys(): i = self.param_numbers[k] self.iligand_params[k] = self.iPs[i] tfs = list(TestFunctions(self.VS)) self.wrhos, self.wUs = tfs[:2**self.dim], tfs[2**self.dim:] tfs = list(TrialFunctions(self.VS)) self.tdrhos, self.tdUs = tfs[:2**self.dim], tfs[2**self.dim:] bc_method = 'geometric' if self.dim > 1 else 'pointwise' rhobcs = [ DirichletBC(self.VS.sub(i), Constant(0), FacesDomain(self.mesh, self.symmetries[i]), method=bc_method) for i in range(2**self.dim) if np.any(self.symmetries[i] != 0.0) ] Ubcs = list( itertools.chain(*[[ DirichletBC(self.VS.sub(i + (lig + 1) * 2**self.dim), Constant(0), FacesDomain(self.mesh, self.symmetries[i]), method=bc_method) for i in range(2**self.dim) if np.any(self.symmetries[i] != 0.0) ] for lig in range(self.nligands)])) self.bcs = rhobcs + Ubcs self.n = FacetNormal(self.mesh) self.h = CellDiameter(self.mesh) self.havg = fe.avg(self.h) self.dx = fe.dx self.dS = fe.dS # # record initial state # if not U0: U0 = [Constant(0.0)] * self.nligands self.U0s = [Constant(0.0)] * self.nligands for i, U0i in enumerate(U0): if isinstance(U0i, ufl.coefficient.Coefficient): self.U0s[i] = U0i else: self.U0s[i] = Expression(U0i, **self.params, degree=self.degree, domain=self.mesh) if not rho0: rho0 = Constant(0.0) if isinstance(rho0, ufl.coefficient.Coefficient): self.rho0 = rho0 else: self.rho0 = Expression(rho0, **self.params, degree=self.degree, domain=self.mesh) self.set_time(t0) # # work out how to call V # try: V(self.U0s, self.rho0, params=self.iparams) def realV(Us, rho): return V(Us, rho, params=self.iparams) except TypeError: def realV(Us, rho): return V(Us, self.iparams) self.V = realV # # initialize state # self.restart() return None