Пример #1
0
if problem is ProblemType.DIRICHLET:
    precice_dt = precice.initialize(coupling_subdomain=coupling_boundary,
                                    mesh=mesh,
                                    read_field=u_D_function,
                                    write_field=f_N_function,
                                    u_n=u_n)
elif problem is ProblemType.NEUMANN:
    precice_dt = precice.initialize(coupling_subdomain=coupling_boundary,
                                    mesh=mesh,
                                    read_field=f_N_function,
                                    write_field=u_D_function,
                                    u_n=u_n)

dt = Constant(0)
dt.assign(np.min([fenics_dt, precice_dt]))

# Define variational problem
u = TrialFunction(V)
v = TestFunction(V)
f = Expression(
    'beta + gamma * x[0] * x[0] - 2 * gamma * t - 2 * (1-gamma) - 2 * alpha',
    degree=2,
    alpha=alpha,
    beta=beta,
    gamma=gamma,
    t=0)
F = u * v / dt * dx + dot(grad(u), grad(v)) * dx - (u_n / dt + f) * v * dx

if problem is ProblemType.DIRICHLET:
    # apply Dirichlet boundary condition on coupling interface
Пример #2
0
u_n.rename("Temperature", "")

precice, precice_dt, initial_data = None, 0.0, None

# Initialize the adapter according to the specific participant
if problem is ProblemType.DIRICHLET:
    precice = Adapter(adapter_config_filename="precice-adapter-config-D.json")
    precice_dt = precice.initialize(coupling_boundary, read_function_space=V, write_object=f_N_function)
elif problem is ProblemType.NEUMANN:
    precice = Adapter(adapter_config_filename="precice-adapter-config-N.json")
    precice_dt = precice.initialize(coupling_boundary, read_function_space=V_g, write_object=u_D_function)

boundary_marker = False

dt = Constant(0)
dt.assign(np.min([fenics_dt, precice_dt]))

# Define variational problem
u = TrialFunction(V)
v = TestFunction(V)
f = Expression('beta + gamma*x[0]*x[0] - 2*gamma*t - 2*(1-gamma) - 2*alpha', degree=2, alpha=alpha,
               beta=beta, gamma=gamma, t=0)
F = u * v / dt * dx + dot(grad(u), grad(v)) * dx - (u_n / dt + f) * v * dx

bcs = [DirichletBC(V, u_D, remaining_boundary)]

# Set boundary conditions at coupling interface once wrt to the coupling expression
coupling_expression = precice.create_coupling_expression()
if problem is ProblemType.DIRICHLET:
    # modify Dirichlet boundary condition on coupling interface
    bcs.append(DirichletBC(V, coupling_expression, coupling_boundary))
Пример #3
0
def solve_linear_pde(
    u_D_array,
    T,
    D=1,
    C1=0,
    num_r=100,
    min_r=0.001,
    tol=1e-14,
    degree=1,
):
    # disable logging
    set_log_active(False)

    num_t = len(u_D_array)
    dt = T / num_t  # time step size

    mesh = IntervalMesh(num_r, min_r, 1)
    r = mesh.coordinates().flatten()
    r_args = np.argsort(r)
    V = FunctionSpace(mesh, "P", 1)

    # Define boundary conditions
    # Dirichlet condition at R
    def boundary_at_R(x, on_boundary):
        return on_boundary and near(x[0], 1, tol)

    D = Constant(D)
    u_D = Constant(u_D_array[0])
    bc_at_R = DirichletBC(V, u_D, boundary_at_R)

    # Define initial values for free c
    c_0 = Expression("C1", C1=C1, degree=degree)
    c_n = interpolate(c_0, V)

    # Define variational problem
    c = TrialFunction(V)
    v = TestFunction(V)

    # define Constants
    r_squ = Expression("4*pi*pow(x[0],2)", degree=degree)

    F_tmp = (D * dt * inner(grad(c), grad(v)) * r_squ * dx +
             c * v * r_squ * dx - c_n * v * r_squ * dx)
    a, L = lhs(F_tmp), rhs(F_tmp)
    u = Function(V)

    data_c = np.zeros((num_t, len(r)), dtype=np.double)

    for n in range(num_t):
        u_D.assign(u_D_array[n])

        # Compute solution
        solve(a == L, u, bc_at_R)
        data_c[n, :] = u.vector().vec().array

        c_n.assign(u)

    data_c = data_c[:, r_args[::-1]]
    r = r[r_args]

    return data_c, r
solution_out << u_n
ranks << mesh_rank

while precice.is_coupling_ongoing():

    # write checkpoint
    if precice.is_action_required(precice.action_write_iteration_checkpoint()):
        precice.store_checkpoint(u_n, t, n)

    read_data = precice.read_data()

    # Update the coupling expression with the new read data
    precice.update_coupling_expression(volume_term, read_data)
    f.assign(interpolate(volume_term, V))

    dt_inv.assign(1 / dt)

    # Compute solution u^n+1, use bcs u^n and coupling bcs
    a, L = lhs(F), rhs(F)
    solve(a == L, u_np1, bc)

    # Write data to preCICE according to which problem is being solved
    precice.write_data(u_np1)

    dt = precice.advance(dt)

    # roll back to checkpoint
    if precice.is_action_required(precice.action_read_iteration_checkpoint()):
        u_cp, t_cp, n_cp = precice.retrieve_checkpoint()
        u_n.assign(u_cp)
        t = t_cp
Пример #5
0
class KSDGSolverVariable(KSDGSolverMultiple):
    default_params = collections.OrderedDict(
        sigma=1.0,
        rhomin=1e-7,
        Umin=1e-7,
        width=1.0,
        rhopen=10.0,
        Upen=1.0,
        grhopen=1.0,
        gUpen=1.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=False,
                 ligands=None):
        """Discontinuous Galerkin solver for the 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 initial 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
            rhomin=10.0**-7: minimum feasible worm density
            Umin=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 nligands=1,
            number of ligands.
        V=(lambda Us, params={}: sum(Us)): a callable taking two
            arguments, Us and rho, or a single argument, Us. Us is a
            list of length nligands. rho is a single expression. V
            returns a single number, V, the potential corresponding to
            Us (and rho). Use ufl versions of mathematical functions,
            e.g. ufl.ln, abs, ufl.exp.
        rho0: Expressions, Functions, or strs specifying the
            initial condition for rho.
        U0: a list of nligands Expressions, Functions or strs
            specifying the initial conditions for the ligands.
        t0=0.0: initial time
        solver_type='gmres'
        preconditioner_type='default'
        ligands=LigandGroups(): ligand list
        periodic=False: ignored for compatibility
        """
        logVARIABLE('creating KSDGSolverVariable')
        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=periodic,
                         ligands=ligands)
        self.t0 = t0
        self.debug = debug
        self.solver_type = solver_type
        self.preconditioner_type = preconditioner_type
        self.periodic = False
        self.ligands = ligands
        self.nligands = ligands.nligands()
        self.init_params(parameters, param_funcs)
        if (mesh):
            self.omesh = self.mesh = mesh
        else:
            self.omesh = self.mesh = box_mesh(width=width,
                                              dim=dim,
                                              nelements=nelements)
            self.nelements = nelements
        logVARIABLE('self.mesh', self.mesh)
        logVARIABLE('self.mesh.mpi_comm().size', self.mesh.mpi_comm().size)
        self.nelements = nelements
        self.degree = degree
        self.dim = self.mesh.geometry().dim()
        #
        # Solution spaces and Functions
        #
        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.srho, self.sUs = splitsol[0], splitsol[1:]
        splitsol = list(fe.split(self.sol))
        self.irho, self.iUs = splitsol[0], splitsol[1:]
        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.wrho, self.wUs = tfs[0], tfs[1:]
        tfs = list(TrialFunctions(self.VS))
        self.tdrho, self.tdUs = tfs[0], tfs[1:]
        self.n = FacetNormal(self.mesh)
        self.h = CellDiameter(self.mesh)
        self.havg = fe.avg(self.h)
        self.dx = fe.dx
        #        self.dx = fe.dx(metadata={'quadrature_degree': min(degree, 10)})
        self.dS = fe.dS
        #        self.dS = fe.dS(metadata={'quadrature_degree': min(degree, 10)})
        #
        # record initial state
        #
        try:
            V(self.iUs, self.irho, 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
        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)
        #
        # initialize state
        #
        self.restart()
        return None

    def init_params(self, parameters, param_funcs):
        """Initialize parameter attributes from __init__ arguments

        The attributes initialized are:
        self.params0: a dict giving initial values of all parameters
        (not just floats). This is basically a copy of the parameters
        argument to __init__, with the insertion of 't' as a new
        parameter (always param_names[-1]).
        self.param_names: a list of the names of the time-varying
        parameters. This is the keys of params0 whose corrsponding
        values are of type float. The order is the order of the
        parameters in self.PSf.
        self.nparams: len(self.param_names)
        self.param_numbers: a dict mapping param names to numbers
        (ints) in the list param_names and the parameters subspace of
        the solution FunctionSpace.
        self.param_funcs: a dict whose keys are the param_names and
        whose values are functions to determine their values as a
        function of time, as explained above. These are copied from
        the param_funcs argument of __init__, except that the default
        initial value function is filled in for parameters not present
        in the argument. Also, the function defined for 't' always
        returns t.
        self.PSf: a Constant object of dimension self.nparams, holding
        the initial values of the parameters.
        """
        self.param_names = [
            n for n, v in parameters.items() if (type(v) is float and n != 't')
        ]
        self.param_names.append('t')
        self.nparams = len(self.param_names)
        logVARIABLE('self.param_names', self.param_names)
        logVARIABLE('self.nparams', self.nparams)
        self.param_numbers = collections.OrderedDict(
            zip(self.param_names, itertools.count()))
        self.params0 = collections.OrderedDict(parameters)
        self.params0['t'] = 0.0
        self.param_funcs = param_funcs.copy()

        def identity(t, params={}):
            return t

        self.param_funcs['t'] = identity
        for n in self.param_names:
            if n not in self.param_funcs:

                def value0(t, params={}, v0=self.params0[n]):
                    return v0

                self.param_funcs[n] = value0
        self.PSf = Constant([self.params0[n] for n in self.param_names])
        return

    def set_time(self, t):
        self.t = t
        params = collections.OrderedDict(
            zip(self.param_names, self.PSf.values()))
        self.PSf.assign(
            Constant([
                self.param_funcs[n](t, params=params) for n in self.param_names
            ]))
        logVARIABLE('self.t', self.t)
        logVARIABLE(
            'collections.OrderedDict(zip(self.param_names, self.PSf.values()))',
            collections.OrderedDict(zip(self.param_names, self.PSf.values())))

    def make_function_space(self, mesh=None, dim=None, degree=None):
        if not mesh: mesh = self.mesh
        if not dim: dim = self.dim
        if not degree: degree = self.degree
        SE = FiniteElement('DG', cellShapes[dim - 1], degree)
        SS = FunctionSpace(mesh, SE)  # scalar space
        elements = [SE] * (self.nligands + 1)
        VE = MixedElement(elements)
        VS = FunctionSpace(mesh, VE)  # vector space
        return dict(SE=SE, SS=SS, VE=VE, VS=VS)

    def restart(self):
        logVARIABLE('restart')
        self.set_time(self.t0)
        CE = FiniteElement('CG', cellShapes[self.dim - 1], self.degree)
        CS = FunctionSpace(self.mesh, CE)  # scalar space
        coords = gather_dof_coords(CS)
        fe.assign(self.sol.sub(0),
                  function_interpolate(self.rho0, self.SS, coords=coords))
        for i, U0i in enumerate(self.U0s):
            fe.assign(self.sol.sub(i + 1),
                      function_interpolate(U0i, self.SS, coords=coords))

    def setup_problem(self, t, debug=False):
        self.set_time(t)
        #
        # assemble the matrix, if necessary (once for all time points)
        #
        if not hasattr(self, 'A'):
            self.drho_integral = self.tdrho * self.wrho * self.dx
            self.dU_integral = sum([
                tdUi * wUi * self.dx for tdUi, wUi in zip(self.tdUs, self.wUs)
            ])
            logVARIABLE('assembling A')
            self.A = PETScMatrix()
            logVARIABLE('self.A', self.A)
            fe.assemble(self.drho_integral + self.dU_integral, tensor=self.A)
            logVARIABLE('A assembled. Applying BCs')
            self.dsol = Function(self.VS)
            dsolsplit = self.dsol.split()
            self.drho, self.dUs = dsolsplit[0], dsolsplit[1:]
        #
        # assemble RHS (for each time point, but compile only once)
        #
        if not hasattr(self, 'rho_terms'):
            self.sigma = self.iparams['sigma']
            self.s2 = self.sigma * self.sigma / 2
            self.rhomin = self.iparams['rhomin']
            self.rhopen = self.iparams['rhopen']
            self.grhopen = self.iparams['grhopen']
            self.v = -ufl.grad(
                self.V(self.iUs, ufl.max_value(self.irho, self.rhomin)) -
                (self.s2 * ufl.grad(self.irho) /
                 ufl.max_value(self.irho, self.rhomin)))
            self.flux = self.v * self.irho
            self.vn = ufl.max_value(ufl.dot(self.v, self.n), 0)
            self.facet_flux = ufl.jump(self.vn * ufl.max_value(self.irho, 0.0))
            self.rho_flux_jump = -self.facet_flux * ufl.jump(
                self.wrho) * self.dS
            self.rho_grad_move = ufl.dot(self.flux, ufl.grad(
                self.wrho)) * self.dx
            self.rho_penalty = -(
                (self.degree**2 / self.havg) *
                ufl.dot(ufl.jump(self.irho, self.n),
                        ufl.jump(self.rhopen * self.wrho, self.n)) * self.dS)
            self.grho_penalty = -(
                self.degree**2 *
                (ufl.jump(ufl.grad(self.irho), self.n) * ufl.jump(
                    ufl.grad(self.grhopen * self.wrho), self.n)) * self.dS)
            self.rho_terms = (self.rho_flux_jump + self.rho_grad_move +
                              self.rho_penalty + self.grho_penalty)
        if not hasattr(self, 'U_terms'):
            self.Umin = self.iparams['Umin']
            self.Upen = self.iparams['Upen']
            self.gUpen = self.iparams['gUpen']
            self.U_decay = sum([
                -lig.gamma * iUi * wUi * self.dx for lig, iUi, wUi in zip(
                    self.iligands.ligands(), self.iUs, self.wUs)
            ])
            self.U_secretion = sum([
                lig.s * self.irho * wUi * self.dx
                for lig, wUi in zip(self.iligands.ligands(), self.wUs)
            ])
            self.jump_gUw = sum([
                ufl.jump(lig.D * wUi * ufl.grad(iUi), self.n) * self.dS
                for lig, wUi, iUi in zip(self.iligands.ligands(), self.wUs,
                                         self.iUs)
            ])
            self.U_diffusion = sum([
                -lig.D * ufl.dot(ufl.grad(iUi), ufl.grad(wUi)) * self.dx
                for lig, iUi, wUi in zip(self.iligands.ligands(), self.iUs,
                                         self.wUs)
            ])
            self.U_penalty = sum([
                -(self.degree**2 / self.havg) * ufl.dot(
                    ufl.jump(iUi, self.n), ufl.jump(self.Upen * wUi, self.n)) *
                self.dS for iUi, wUi in zip(self.iUs, self.wUs)
            ])
            self.gU_penalty = sum([
                -self.degree**2 * ufl.jump(ufl.grad(iUi), self.n) *
                ufl.jump(ufl.grad(self.gUpen * wUi), self.n) * self.dS
                for iUi, wUi in zip(self.iUs, self.wUs)
            ])
            self.U_terms = (
                # decay and secretion
                self.U_decay + self.U_secretion +
                # diffusion
                self.jump_gUw + self.U_diffusion +
                # penalties (to enforce continuity)
                self.U_penalty + self.gU_penalty)
        if not hasattr(self, 'all_terms'):
            self.all_terms = self.rho_terms + self.U_terms
        if not hasattr(self, 'J_terms'):
            self.J_terms = fe.derivative(self.all_terms, self.sol)

    def ddt(self, t, debug=False):
        """Calculate time derivative of rho and U

        Results are left in self.dsol as a two-component vector function.
        """
        self.setup_problem(t, debug=debug)
        self.b = fe.assemble(self.all_terms)
        return fe.solve(self.A, self.dsol.vector(), self.b, self.solver_type)