Beispiel #1
0
 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
Beispiel #2
0
    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
Beispiel #3
0
    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)
Beispiel #4
0
    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