def define_function_assigners(self):
        """
        Create function assigners to update the current and previous time
        values of all field variables. This is specific to incompressible
        simulations since the mixed function space formulation requires the
        handling of the mixed functions and the copies of its subcomponents
        in a specific manner.


        """

        W = self.functionSpace
        v = self.velocity
        p = self.pressure

        self.assigner_sys2v = dlf.FunctionAssigner(
            [v.function_space(), p.function_space()], W)
        self.assigner_v2sys = dlf.FunctionAssigner(
            W, [v.function_space(), p.function_space()])

        if self.config['formulation']['time']['unsteady']:
            v0 = self.velocity0
            p0 = self.pressure0

            self.assigner_v02sys = dlf.FunctionAssigner(
                W,
                [v0.function_space(), p0.function_space()])
            self.assigner_sys2v0 = dlf.FunctionAssigner(
                [v0.function_space(), p0.function_space()], W)

        return None
Beispiel #2
0
    def __init__(
        self,
        *,
        brain: CoupledBrainModel,
        parameters: CoupledSplittingSolverParameters,
    ) -> None:
        """Create solver from given Model and (optional) parameters."""
        self._brain = brain
        self._parameters = parameters

        # Create ODE solver and extract solution fields
        self.ode_solver = self.create_ode_solver()
        self.vs_prev, self.vs = self.ode_solver.solution_fields()
        self.VS = self.vs.function_space()

        # Create PDE solver and extract solution fields
        self.pde_solver = self.create_pde_solver()
        self.v_prev, self.vur = self.pde_solver.solution_fields()

        # # Create function assigner for merging v from self.vur into self.vs[0]
        if self.vur.function_space().num_sub_spaces() > 1:
            V = self.vur.function_space().sub(0)
        else:
            V = self.vur.function_space()
        self.merger = df.FunctionAssigner(self.VS.sub(0), V)
Beispiel #3
0
 def _init_states(self, src4init='map_solution'):
     """
     Initialize the states from existing solution or DNS data.
     """
     # Initialize the state variable using the DNS data or existing solution
     self.states_fwd = dl.Function(self.Vh_STATE)
     f_name = src4init + '.h5'
     self.from_file = os.path.isfile(f_name)
     if self.from_file:
         input_file = dl.HDF5File(self.mpi_comm, f_name, "r")
         input_file.read(self.states_fwd, "state")
         input_file.close()
     elif src4init is 'DNS' or not self.from_file:
         upke_init = [self.u_fun, self._scalar_zero, self.k_fun, self.e_fun]
         upkefun = [
             dl.interpolate(fi, Vi)
             for (fi, Vi) in zip(upke_init, self.Vhs)
         ]
         assigner_upke = dl.FunctionAssigner(self.Vh_STATE, self.Vhs)
         assigner_upke.assign(self.states_fwd, upkefun)
         self.from_file = False
     else:
         self.from_file = False
         if self.rank == 0:
             print(
                 'States have initialized at zero. Please provide data source if you want otherwise.'
             )
Beispiel #4
0
    def setup(self):
        """
        Create mesh velocity and deformation functions
        """
        sim = self.simulation
        assert self.active is False, 'Trying to setup mesh morphing twice in the same simulation'

        # Store previous cell volumes
        mesh = sim.data['mesh']
        Vcvol = dolfin.FunctionSpace(mesh, 'DG', 0)
        sim.data['cvolp'] = dolfin.Function(Vcvol)

        # The function spaces for mesh velocities and displacements
        Vmesh = dolfin.FunctionSpace(mesh, 'CG', 1)
        Vmesh_vec = dolfin.VectorFunctionSpace(mesh, 'CG', 1)
        sim.data['Vmesh'] = Vmesh

        # Create mesh velocity functions
        u_mesh = []
        for d in range(sim.ndim):
            umi = dolfin.Function(Vmesh)
            sim.data['u_mesh%d' % d] = umi
            u_mesh.append(umi)
        u_mesh = dolfin.as_vector(u_mesh)
        sim.data['u_mesh'] = u_mesh

        # Create mesh displacement vector function
        self.displacement = dolfin.Function(Vmesh_vec)
        self.assigners = [
            dolfin.FunctionAssigner(Vmesh_vec.sub(d), Vmesh)
            for d in range(sim.ndim)
        ]
        self.active = True
Beispiel #5
0
    def functionspace(self):
        if self.options["is_projection"]:
            dim_Local = self.particle.dimension
            dim_Global = self.particle.dimension*self.particle.number_particles_all
            self.Vh_Global = dl.VectorFunctionSpace(self.particle.Vh_COEFF.mesh(), "R", degree=0,
                                                    dim=dim_Global)
            self.Vh_Local = dl.VectorFunctionSpace(self.particle.Vh_COEFF.mesh(), "R", degree=0,
                                                   dim=dim_Local)
            # dim_Universal = self.nproc*self.particle.dimension*self.particle.number_particles_all
            # self.Vh_Universal = dl.VectorFunctionSpace(self.particle.Vh_COEFF.mesh(), "R", degree=0,
            #                                         dim=dim_Universal)

        else:
            if self.options["type_parameter"] is 'field':
                if self.particle.number_particles_all == 1:
                    self.Vh_Global = dl.FunctionSpace(self.model.problem.Vh[PARAMETER].mesh(),
                                  'Lagrange', self.model.problem.Vh[PARAMETER].ufl_element().degree())
                    self.Vh_Local = dl.FunctionSpace(self.model.problem.Vh[PARAMETER].mesh(),
                                  'Lagrange', self.model.problem.Vh[PARAMETER].ufl_element().degree())
                    # if self.nproc == 1:
                    #     self.Vh_Universal = dl.FunctionSpace(self.model.problem.Vh[PARAMETER].mesh(),
                    #                                       'Lagrange',
                    #                                       self.model.problem.Vh[PARAMETER].ufl_element().degree())
                    # else:
                    #     self.Vh_Universal = dl.VectorFunctionSpace(self.model.problem.Vh[PARAMETER].mesh(),
                    #                            'Lagrange', self.model.problem.Vh[PARAMETER].ufl_element().degree(),
                    #                            dim=self.nproc)
                else:
                    self.Vh_Global = dl.VectorFunctionSpace(self.model.problem.Vh[PARAMETER].mesh(),
                                                             'Lagrange', self.model.problem.Vh[PARAMETER].ufl_element().degree(),
                                                             dim=self.particle.number_particles_all)
                    self.Vh_Local = self.Vh_Global.sub(0).collapse()
                    # self.Vh_Universal = dl.VectorFunctionSpace(self.model.problem.Vh[PARAMETER].mesh(),
                    #                        'Lagrange', self.model.problem.Vh[PARAMETER].ufl_element().degree(),
                    #                        dim=self.nproc*self.particle.number_particles_all)

                    self.local_spaces = [self.Vh_Local for m in range(self.particle.number_particles_all)]
                    self.global_space = self.Vh_Global
                    self.to_sub = dl.FunctionAssigner(self.local_spaces, self.global_space)
                    self.from_sub = dl.FunctionAssigner(self.global_space, self.local_spaces)
            elif self.options["type_parameter"] is 'vector':
                dim_Local = self.model.prior.dim
                dim_Global = self.model.prior.dim*self.particle.number_particles_all
                self.Vh_Global = dl.VectorFunctionSpace(self.model.problem.Vh[PARAMETER].mesh(), "R", degree=0,
                                                        dim=dim_Global)
                self.Vh_Local = dl.VectorFunctionSpace(self.model.problem.Vh[PARAMETER].mesh(), "R", degree=0,
                                                       dim=dim_Local)
Beispiel #6
0
    def solve_coupled(self):
        """
        Solve the coupled equations
        """
        # Assemble the equation system
        A = self.eqs.assemble_lhs()
        b = self.eqs.assemble_rhs()

        if self.fix_pressure_dof:
            A.ident(self.pressure_row_to_fix)
        elif self.remove_null_space:
            if self.pressure_null_space is None:
                # Create null space vector in Vp Space
                null_func = dolfin.Function(self.simulation.data['Vp'])
                null_vec = null_func.vector()
                null_vec[:] = 1
                null_vec *= 1 / null_vec.norm("l2")

                # Convert null space vector to coupled space
                null_func2 = dolfin.Function(self.simulation.data['Vcoupled'])
                ndim = self.simulation.ndim
                fa = dolfin.FunctionAssigner(self.subspaces[ndim],
                                             self.simulation.data['Vp'])
                fa.assign(null_func2.sub(ndim), null_func)

                # Create the null space basis
                self.pressure_null_space = dolfin.VectorSpaceBasis(
                    [null_func2.vector()])

            # Make sure the null space is set on the matrix
            dolfin.as_backend_type(A).set_nullspace(self.pressure_null_space)

            # Orthogonalize b with respect to the null space
            self.pressure_null_space.orthogonalize(b)

        # Solve the equation system
        self.simulation.hooks.matrix_ready('Coupled', A, b)
        self.coupled_solver.solve(A, self.coupled_func.vector(), b)

        # Assign into the regular (split) functions from the coupled function
        funcs = [self.simulation.data[name] for name in self.subspace_names]
        self.assigner.assign(funcs, self.coupled_func)

        # If we remove the null space of the matrix system this will not be the exact same as
        # removing the proper null space of the equation, so we fix this here
        if self.fix_pressure_dof:
            p = self.simulation.data['p']
            dx2 = dolfin.dx(domain=p.function_space().mesh())
            vol = dolfin.assemble(dolfin.Constant(1) * dx2)
            # Perform correction multiple times due to round-of error. The first correction
            # can be i.e 1e14 while the next correction is around unity
            pavg = 1e10
            while abs(pavg) > 1000:
                pavg = dolfin.assemble(p * dx2) / vol
                p.vector()[:] -= pavg
Beispiel #7
0
 def create_vec_func(V):
     "Create a vector function from the components"
     family = V.ufl_element().family()
     degree = V.ufl_element().degree()
     cd = sim.data['constrained_domain']
     V_vec = dolfin.VectorFunctionSpace(
         sim.data['mesh'], family, degree, constrained_domain=cd
     )
     vec_func = dolfin.Function(V_vec)
     assigner = dolfin.FunctionAssigner(V_vec, [V] * sim.ndim)
     return vec_func, assigner
Beispiel #8
0
    def create_functions(self):
        """
        Create functions to hold solutions
        """
        sim = self.simulation

        # Function spaces
        Vu = sim.data['Vu']
        Vp = sim.data['Vp']
        cd = sim.data['constrained_domain']

        # Create coupled mixed function space and mixed function to hold results
        func_spaces = [Vu] * sim.ndim + [Vp]
        self.subspace_names = ['u%d' % d for d in range(sim.ndim)] + ['p']

        # Create stress tensor space
        P = Vu.ufl_element().degree()
        Vs = dolfin.FunctionSpace(sim.data['mesh'],
                                  'DG',
                                  P,
                                  constrained_domain=cd)
        for i in range(sim.ndim**2):
            stress_name = 'stress_%d' % i
            sim.data[stress_name] = dolfin.Function(Vs)
            func_spaces.append(Vs)
            self.subspace_names.append(stress_name)

        # Create mixed space
        e_mixed = dolfin.MixedElement([fs.ufl_element() for fs in func_spaces])
        Vcoupled = dolfin.FunctionSpace(sim.data['mesh'], e_mixed)
        sim.data['Vcoupled'] = Vcoupled

        # Create function assigner
        Nspace = len(func_spaces)
        self.subspaces = [Vcoupled.sub(i) for i in range(Nspace)]
        sim.data['coupled'] = self.coupled_func = dolfin.Function(Vcoupled)
        self.assigner = dolfin.FunctionAssigner(func_spaces, Vcoupled)

        # Create segregated functions on component and vector form
        u_list, up_list, upp_list, u_conv = [], [], [], []
        for d in range(sim.ndim):
            sim.data['u%d' % d] = u = dolfin.Function(Vu)
            sim.data['up%d' % d] = up = dolfin.Function(Vu)
            sim.data['upp%d' % d] = upp = dolfin.Function(Vu)
            sim.data['u_conv%d' % d] = uc = dolfin.Function(Vu)
            u_list.append(u)
            up_list.append(up)
            upp_list.append(upp)
            u_conv.append(uc)
        sim.data['u'] = dolfin.as_vector(u_list)
        sim.data['up'] = dolfin.as_vector(up_list)
        sim.data['upp'] = dolfin.as_vector(upp_list)
        sim.data['u_conv'] = dolfin.as_vector(u_conv)
        sim.data['p'] = dolfin.Function(Vp)
 def __init__(self, u, name="Assigned Vector Function"):
     self.u = u
     assert isinstance(u, ListTensor)
     V = u[0].function_space()
     mesh = V.mesh()
     family = V.ufl_element().family()
     degree = V.ufl_element().degree()
     constrained_domain = V.dofmap().constrained_domain
     Vv = df.VectorFunctionSpace(mesh,
                                 family,
                                 degree,
                                 constrained_domain=constrained_domain)
     df.Function.__init__(self, Vv, name=name)
     self.fa = [df.FunctionAssigner(Vv.sub(i), V) for i, _u in enumerate(u)]
Beispiel #10
0
def make_unit_vector(V, VV, dofs_x, fill_coordinates, foc=None):
    e_c_x = dolfin.Function(V)
    e_c_y = dolfin.Function(V)
    e_c_z = dolfin.Function(V)

    for i, coord in enumerate(dofs_x):
        fill_coordinates(i, e_c_x, e_c_y, e_c_z, coord, foc)

    e = dolfin.Function(VV)

    fa = [dolfin.FunctionAssigner(VV.sub(i), V) for i in range(3)]
    for i, e_c_comp in enumerate([e_c_x, e_c_y, e_c_z]):
        fa[i].assign(e.split()[i], e_c_comp)
    return e
Beispiel #11
0
    def create_functions(self):
        """
        Create functions to hold solutions
        """
        sim = self.simulation

        # Function spaces
        Vu = sim.data['Vu']
        Vp = sim.data['Vp']

        # Create velocity functions on component and vector form
        create_vector_functions(sim, 'u', 'u%d', Vu)
        create_vector_functions(sim, 'up', 'up%d', Vu)
        create_vector_functions(sim, 'upp', 'upp%d', Vu)
        create_vector_functions(sim, 'u_conv', 'u_conv%d', Vu)
        create_vector_functions(sim, 'up_conv', 'up_conv%d', Vu)
        create_vector_functions(sim, 'upp_conv', 'upp_conv%d', Vu)
        create_vector_functions(sim, 'u_unlim', 'u_unlim%d', Vu)
        sim.data['ui_tmp'] = dolfin.Function(Vu)

        # Create coupled vector function
        ue = Vu.ufl_element()
        e_mixed = dolfin.MixedElement([ue] * sim.ndim)
        Vcoupled = dolfin.FunctionSpace(Vu.mesh(), e_mixed)
        sim.data['uvw_star'] = dolfin.Function(Vcoupled)
        sim.data['uvw_temp'] = dolfin.Function(Vcoupled)
        sim.ndofs += Vcoupled.dim() + Vp.dim()

        # Create assigner to extract split function from uvw and vice versa
        self.assigner_split = dolfin.FunctionAssigner([Vu] * sim.ndim,
                                                      Vcoupled)
        self.assigner_merge = dolfin.FunctionAssigner(Vcoupled,
                                                      [Vu] * sim.ndim)

        # Create pressure function
        sim.data['p'] = dolfin.Function(Vp)
        sim.data['p_hat'] = dolfin.Function(Vp)
Beispiel #12
0
    def __init__(self, Vh_STATE, Vhs, weights, geo, bcs0, datafile, variance_u,
                 variance_g):
        if hasattr(geo, "dx"):
            self.dx = geo.dx(geo.PHYSICAL)
        else:
            self.dx = dl.dx

        self.ds = geo.ds(geo.AXIS)

        x, y, U, V, uu, vv, ww, uv, k = np.loadtxt(datafile,
                                                   skiprows=2,
                                                   unpack=True)
        u_fun_data = VelocityDNS(x=x,
                                 y=y,
                                 U=U,
                                 V=V,
                                 symmetrize=True,
                                 coflow=0.)

        u_data = dl.interpolate(u_fun_data, Vhs[0])

        if Vh_STATE.num_sub_spaces() == 3:
            u_trial, p_trial, g_trial = dl.TrialFunctions(Vh_STATE)
            u_test, p_test, g_test = dl.TestFunctions(Vh_STATE)
        else:
            raise InputError()

        Wform = dl.Constant(1./variance_u)*dl.inner(u_trial, u_test)*self.dx +\
                dl.Constant(1./variance_g)*g_trial*g_test*self.ds

        self.W = dl.assemble(Wform)
        dummy = dl.Vector()
        self.W.init_vector(dummy, 0)
        [bc.zero(self.W) for bc in bcs0]
        Wt = Transpose(self.W)
        [bc.zero(Wt) for bc in bcs0]
        self.W = Transpose(Wt)

        xfun = dl.Function(Vh_STATE)
        assigner = dl.FunctionAssigner(Vh_STATE, Vhs)
        assigner.assign(xfun, [
            u_data,
            dl.Function(Vhs[1]),
            dl.interpolate(dl.Constant(1.), Vhs[2])
        ])

        self.d = xfun.vector()

        self.w = (weights * 0.5)
Beispiel #13
0
    def __init__(self, Vh_STATE, Vhs, bcs0, datafile, dx=dl.dx):
        self.dx = dx
        x, y, U, V, uu, vv, ww, uv, k = np.loadtxt(datafile,
                                                   skiprows=2,
                                                   unpack=True)
        u_fun_mean = VelocityDNS(x=x,
                                 y=y,
                                 U=U,
                                 V=V,
                                 symmetrize=True,
                                 coflow=0.)
        u_fun_data = VelocityDNS(x=x,
                                 y=y,
                                 U=U,
                                 V=V,
                                 symmetrize=False,
                                 coflow=0.)
        k_fun_mean = KDNS(x=x, y=y, k=k, symmetrize=True)
        k_fun_data = KDNS(x=x, y=y, k=k, symmetrize=False)

        u_data = dl.interpolate(u_fun_data, Vhs[0])
        k_data = dl.interpolate(k_fun_data, Vhs[2])

        noise_var_u = dl.assemble(
            dl.inner(u_data - u_fun_mean, u_data - u_fun_mean) * self.dx)
        noise_var_k = dl.assemble(
            dl.inner(k_data - k_fun_mean, k_data - k_fun_mean) * self.dx)

        u_trial, p_trial, k_trial, e_trial = dl.TrialFunctions(Vh_STATE)
        u_test, p_test, k_test, e_test = dl.TestFunctions(Vh_STATE)

        Wform = dl.Constant(1./noise_var_u)*dl.inner(u_trial, u_test)*self.dx + \
                dl.Constant(1./noise_var_k)*dl.inner(k_trial, k_test)*self.dx

        self.W = dl.assemble(Wform)
        dummy = dl.Vector()
        self.W.init_vector(dummy, 0)
        [bc.zero(self.W) for bc in bcs0]
        Wt = Transpose(self.W)
        [bc.zero(Wt) for bc in bcs0]
        self.W = Transpose(Wt)

        xfun = dl.Function(Vh_STATE)
        assigner = dl.FunctionAssigner(Vh_STATE, Vhs)
        assigner.assign(
            xfun,
            [u_data, dl.Function(Vhs[1]), k_data,
             dl.Function(Vhs[3])])
        self.d = xfun.vector()
Beispiel #14
0
def assign_ic(func, data):
    mixed_func_space = func.function_space()

    functions = func.split(deepcopy=True)
    V = df.FunctionSpace(mixed_func_space.mesh(), "CG", 1)
    ic_indices = np.random.randint(0,
                                   data.shape[0],
                                   size=functions[0].vector().local_size())
    _data = data[ic_indices]

    for i, f in enumerate(functions):
        ic_func = df.Function(V)
        ic_func.vector()[:] = np.array(_data[:, i])

        assigner = df.FunctionAssigner(mixed_func_space.sub(i), V)
        assigner.assign(func.sub(i), ic_func)
Beispiel #15
0
def assign_restart_ic(receiving_function: df.Function,
                      assigning_func_iterator: Iterable[df.Function]) -> None:
    """Assign a seriess of functions to the `receiving_function`.

    This function is indended for use when restarting simulations, using previously computed
    solutions as initial conditions.
    """
    # Get receiving function space
    mixed_function_space = receiving_function.function_space()
    assigning_function_space = df.FunctionSpace(mixed_function_space.mesh(),
                                                "CG", 1)

    for subfunc_idx, assigning_sub_function in enumerate(
            assigning_func_iterator):
        assigner = df.FunctionAssigner(mixed_function_space.sub(subfunc_idx),
                                       assigning_function_space)
        assigner.assign(receiving_function.sub(subfunc_idx),
                        assigning_sub_function)
Beispiel #16
0
    def create_functions(self):
        """
        Create functions to hold solutions
        """
        sim = self.simulation

        # Function spaces
        Vu = sim.data['Vu']
        Vp = sim.data['Vp']
        cd = sim.data['constrained_domain']

        # Create coupled mixed function space and mixed function to hold results
        func_spaces = [Vu] * sim.ndim + [Vp]
        self.subspace_names = ['u%d' % d for d in range(sim.ndim)] + ['p']

        if self.use_lagrange_multiplicator:
            Vl = dolfin.FunctionSpace(sim.data['mesh'],
                                      "R",
                                      0,
                                      constrained_domain=cd)
            sim.data['l'] = dolfin.Function(Vl)
            func_spaces.append(Vl)
            self.subspace_names.append('l')

        e_mixed = dolfin.MixedElement([fs.ufl_element() for fs in func_spaces])
        Vcoupled = dolfin.FunctionSpace(sim.data['mesh'], e_mixed)
        sim.data['Vcoupled'] = Vcoupled
        sim.ndofs += Vcoupled.dim()

        Nspace = len(func_spaces)
        self.subspaces = [Vcoupled.sub(i) for i in range(Nspace)]
        sim.data['coupled'] = self.coupled_func = dolfin.Function(Vcoupled)
        self.assigner = dolfin.FunctionAssigner(func_spaces, Vcoupled)

        # Create segregated functions on component and vector form
        create_vector_functions(sim, 'u', 'u%d', Vu)
        create_vector_functions(sim, 'up', 'up%d', Vu)
        create_vector_functions(sim, 'upp', 'upp%d', Vu)
        create_vector_functions(sim, 'u_conv', 'u_conv%d', Vu)
        create_vector_functions(sim, 'up_conv', 'up_conv%d', Vu)
        create_vector_functions(sim, 'upp_conv', 'upp_conv%d', Vu)
        create_vector_functions(sim, 'u_unlim', 'u_unlim%d', Vu)
        sim.data['p'] = dolfin.Function(Vp)
        sim.data['ui_tmp'] = dolfin.Function(Vu)
Beispiel #17
0
def normalize_vector_field(u):
    dim = len(u)
    S = u.function_space().sub(0).collapse()

    components = vectorfield_to_components(u, S, dim)
    normarray = np.sqrt(
        sum(gather_broadcast(components[i].vector().array()) ** 2 for i in range(dim))
    )

    for i in range(dim):
        assign_to_vector(
            components[i].vector(),
            gather_broadcast(components[i].vector().array()) / normarray,
        )

    assigners = [df.FunctionAssigner(u.function_space().sub(i), S) for i in range(dim)]
    for i, comp, assigner in zip(list(range(dim)), components, assigners):
        assigner.assign(u.sub(i), comp)
    return u
Beispiel #18
0
def assign_ic_subdomain(
        *,
        brain: CoupledBrainModel,
        vs_prev: df.Function,
        value: float,
        subdomain_id: int,
        subfunction_index: int
) -> None:
    """
    Compute a function with `value` in the subdomain corresponding to `subdomain_id`.
    Assign this function to subfunction `subfunction_index` of vs_prev.
    """
    mesh = brain._mesh
    cell_function = brain._cell_function

    dX = df.Measure("dx", domain=mesh, subdomain_data=cell_function)

    V = df.FunctionSpace(mesh, "DG", 0)
    u = df.TrialFunction(V)
    v = df.TestFunction(V)
    sol = df.Function(V)
    sol.vector().zero()     # Make sure it is initialised to zero

    F = -u*v*dX(subdomain_id) + df.Constant(value)*v*dX(subdomain_id)
    a = df.lhs(F)
    L = df.rhs(F)

    A = df.assemble(a, keep_diagonal=True)
    A.ident_zeros()
    b = df.assemble(L)
    solver = df.KrylovSolver("cg", "petsc_amg")
    solver.set_operator(A)
    solver.solve(sol.vector(), b)

    VCG = df.FunctionSpace(mesh, "CG", 1)
    v_new = df.Function(VCG)
    v_new.interpolate(sol)

    Vp = vs_prev.function_space().sub(subfunction_index)
    merger = df.FunctionAssigner(Vp, VCG)
    merger.assign(vs_prev.sub(subfunction_index), v_new)
Beispiel #19
0
def new_assign_ic(receiving_function: df.Function,
                  ic_generator: NonuniformIC,
                  degree: int = 1) -> None:
    """
    Assign receiving_function(x, y) <- `ic_function`(x, y), for x, in the mesh.

    Arguments:
        receiving_function: The function which is assigned the initial condition.
        ic_function_tuple: A tuple of python callables which return the initial condition for each
            point (x, y). The number of functions must match the number of subfunctions 
            in `receiving_function`.
    """
    mixed_func_space = receiving_function.function_space()
    mesh = mixed_func_space.mesh()
    V = df.FunctionSpace(mesh, "CG", 1)  # TODO: infer this somehow

    class InitialConditionInterpolator(df.UserExpression):
        def __init__(self, **kwargs):
            super().__init__(kwargs)
            self._ic_func = None

        def set_interpolator(self, interpolation_function):
            self._ic_func = interpolation_function

        def eval(self, value, x):
            value[0] = self._ic_func(x[0])  # TODO: 1D for now

    ic_interpolator = InitialConditionInterpolator()

    # Copy functions to be able to assign to them
    functions = receiving_function.split(deepcopy=True)

    for i, (f, ic_func) in enumerate(zip(functions, ic_generator())):

        class IC(df.Expression):
            def eval(self, value, x):
                value[0] = ic_func(x[0])  # TODO: 1D for now

        ic = IC(degree=degree)
        assigner = df.FunctionAssigner(mixed_func_space.sub(i), V)
        assigner.assign(receiving_function.sub(i), df.project(ic, V))
Beispiel #20
0
    def __init__(self,
                 model: Model,
                 ode_timestep: float = None,
                 periodic_domain: df.SubDomain = None,
                 parameters: df.Parameters = None) -> None:
        """Create solver from given Cardiac Model and (optional) parameters."""
        assert isinstance(model, Model), "Expecting Model as first argument"

        self.periodic_domain = periodic_domain

        self._parameters = self.default_parameters()
        if parameters is not None:
            self._parameters.update(parameters)

        self._ode_timestep = ode_timestep

        # Set model and parameters
        self._model = model

        # Extract solution domain
        self._domain = self._model.mesh
        self._time = self._model.time
        self._cell_function = self._model.cell_domains

        # Create ODE solver and extract solution fields
        self.ode_solver = self._create_ode_solver()
        self.vs_, self.vs = self.ode_solver.solution_fields()
        self.VS = self.vs.function_space()

        # Create PDE solver and extract solution fields
        self.pde_solver = self._create_pde_solver()
        self.v_, self.vur = self.pde_solver.solution_fields()

        # # Create function assigner for merging v from self.vur into self.vs[0]
        if self._parameters["pde_solver"] == "bidomain":
            V = self.vur.function_space().sub(0)
        else:
            V = self.vur.function_space()
        self.merger = df.FunctionAssigner(self.VS.sub(0), V)
Beispiel #21
0
def interpolate_ic(time: Sequence[float],
                   data: np.ndarray,
                   receiving_function: df.Function,
                   boundaries: Iterable[np.ndarray],
                   wavespeed: float = 1.0) -> None:
    mixed_func_space = receiving_function.function_space()
    mesh = mixed_func_space.mesh()
    V = df.FunctionSpace(mesh, "CG", 1)  # TODO: infer this somehow

    class InitialConditionInterpolator(df.UserExpression):
        def __init__(self, **kwargs):
            super().__init__(kwargs)
            self._ic_func = None

            self._nearest_edge_interpolator = NearestEdgeTree(boundaries)

        def set_interpolator(self, interpolation_function):
            self._ic_func = interpolation_function

        def eval(self, value, x):
            _, r = self._nearest_edge_interpolator.query(x)
            value[0] = self._ic_func(r / wavespeed)  # TODO: 1D for now
            # value[0] = r
            # value[0] = self._ic_func(x[0]/wavespeed)    # TODO: 1D for now

    ic_interpolator = InitialConditionInterpolator()

    # Copy functions to be able to assign to them
    subfunction_copy = receiving_function.split(deepcopy=True)
    for i, f in enumerate(subfunction_copy):
        # from IPython import embed; embed()
        # assert False
        ic_interpolator.set_interpolator(
            lambda x: np.interp(x, time, data[i, :]))
        assigner = df.FunctionAssigner(mixed_func_space.sub(i), V)
        assigner.assign(receiving_function.sub(i),
                        df.project(ic_interpolator, V))
Beispiel #22
0
# Now we want to modify the vector function space
# to get the vector (2, 1, 1) in every vertex
vec = df.assemble(
    df.dot(df.as_vector((2 * f1, f1, f1)), df.TestFunction(space_S3)) * df.dP)
f3.vector().axpy(1, vec)

# Scalar space assign
g2 = df.Function(space_S1)
g2.assign(df.FunctionAXPY(f1, 2.))

g2.vector().axpy(-1, f2.vector())
assert df.near(g2.vector().norm('l2'), 0)

# Assigner for components of the vector space
S3_assigners = [
    df.FunctionAssigner(space_S3.sub(i), space_S1)
    for i in range(space_S3.num_sub_spaces())
]

g3 = df.Function(space_S3)
# Assign to components
comps = [f2, f1, f1]
[S3_assigners[i].assign(g3.sub(i), comp) for i, comp in enumerate(comps)]

g3.vector().axpy(-1, f3.vector())
assert df.near(g3.vector().norm('l2'), 0)

df.plot(f2)
df.plot(f3)
df.interactive()
Beispiel #23
0
    def __init__(
            self,
            energy,
            state,
            bcs,
            # rayleigh=None,
            Hessian=None,
            nullspace=None,
            parameters=None):
        """Solves second order stability problem
            - computes inertia
            - solves full eigenvalue problem

            * Parameters:
                - energy (form)
                - state (tuple)
                - bcs (list)

            Optional arguments: rayleigh (form), Hessian (form), 
            nullspace, parameters
        """
        OptDB = PETSc.Options()
        OptDB.view()

        self.i = 0

        self.u = state['u']
        self.alpha = state['alpha']
        self._u = dolfin.Vector(self.u.vector())
        self._alpha = dolfin.Vector(self.alpha.vector())
        self.mesh = state['alpha'].function_space().mesh()

        self.Z = dolfin.FunctionSpace(
            self.mesh,
            dolfin.MixedElement(
                [self.u.ufl_element(),
                 self.alpha.ufl_element()]))
        self.z = dolfin.Function(self.Z)
        self.z_old = dolfin.Function(self.Z)
        zeta = dolfin.TestFunction(self.Z)
        v, beta = dolfin.split(zeta)

        self.dm = self.Z.dofmap()
        self.ownership = self.Z.dofmap().ownership_range()

        Zu = self.Z.extract_sub_space([0])
        Za = self.Z.extract_sub_space([1])

        self.Xa = Za.collapse().tabulate_dof_coordinates()
        self.Xu = Zu.collapse().tabulate_dof_coordinates()

        (_, self.mapa) = Za.collapse(collapsed_dofs=True)
        (_, self.mapu) = Zu.collapse(collapsed_dofs=True)

        self.assigner = dolfin.FunctionAssigner(
            self.Z,  # receiving space
            [self.u.function_space(),
             self.alpha.function_space()])  # assigning spaces

        self.parameters = self.setParameters(parameters)

        self.ownership = self.Z.dofmap().ownership_range()

        self.assigner = dolfin.FunctionAssigner(
            self.Z,  # receiving space
            [self.u.function_space(),
             self.alpha.function_space()])  # assigning space

        dim = self.u.function_space().ufl_element().value_size()

        self.stable = ''
        self.negev = -1
        self.mineig = 1.

        self.Ealpha = derivative(
            energy, self.alpha,
            dolfin.TestFunction(self.alpha.ufl_function_space()))
        self.energy = energy

        (z_u, z_a) = dolfin.split(self.z)
        energy = ufl.replace(energy, {self.u: z_u, self.alpha: z_a})
        self.J = derivative(energy, self.z, dolfin.TestFunction(self.Z))
        self.H = derivative(self.J, self.z, dolfin.TrialFunction(self.Z))

        self.nullspace = nullspace

        if Hessian:
            self.Hessian = Hessian

        self.ownership_range = self.Z.dofmap().ownership_range()
        if len(bcs) > 0:
            self.bcs = bcs
            self.bc_dofs = self.get_bc_dofs(bcs)
        else:
            self.bcs = None
            self.bc_dofs = set()

        self.perturbation_v = dolfin.Function(self.Z.sub(0).collapse())
        self.perturbation_beta = dolfin.Function(self.Z.sub(1).collapse())

        self._Hessian = Hessian if Hessian.__class__ == ufl.form.Form else self.H
Beispiel #24
0
    def __init__(
        self,
        simulation,
        w,
        incompressibility_flux_type='central',
        D12=None,
        degree=None,
        use_bcs=True,
        use_nedelec=True,
    ):
        """
        Implement equation 4a and 4b in "Two new techniques for generating exactly
        incompressible approximate velocities" by Bernardo Cocburn (2009)

        For each element K in the mesh:

            <u⋅n, φ> = <û⋅n, φ>  ∀ ϕ ∈ P_{k}(F) for any face F ∈ ∂K
            (u, ϕ) = (w, ϕ)      ∀ φ ∈ P_{k-2}(K)^2
            (u, ϕ) = (w, ϕ)      ∀ φ ∈ {ϕ ∈ P_{k}(K)^2 : ∇⋅ϕ = 0 in K, ϕ⋅n = 0 on ∂K}

        Here w is the input velocity function in DG2 space and û is the flux at
        each face. P_{x} is the space of polynomials of order k

        The flux type can be 'central' or 'upwind'
        """
        self.simulation = simulation
        simulation.log.info('    Setting up velocity BDM projection')

        V = w[0].function_space()
        ue = V.ufl_element()
        gdim = w.ufl_shape[0]
        if degree is None:
            pdeg = ue.degree()
            Vout = V
        else:
            pdeg = degree
            Vout = FunctionSpace(V.mesh(), 'DG', degree)
        pg = (pdeg, gdim)

        assert ue.family() == 'Discontinuous Lagrange'
        assert incompressibility_flux_type in ('central', 'upwind')

        if use_nedelec and pdeg > 1:
            a, L, V = self._setup_projection_nedelec(
                w, incompressibility_flux_type, D12, use_bcs, pdeg, gdim)
        elif gdim == 2 and pdeg == 1:
            a, L, V = self._setup_dg1_projection_2D(
                w, incompressibility_flux_type, D12, use_bcs)
        elif gdim == 2 and pdeg == 2:
            a, L, V = self._setup_dg2_projection_2D(
                w, incompressibility_flux_type, D12, use_bcs)
        else:
            raise NotImplementedError('VelocityBDMProjection does not support '
                                      'degree %d and dimension %d' % pg)

        # Pre-factorize matrices and store for usage in projection
        self.local_solver = LocalSolver(a, L)
        self.local_solver.factorize()
        self.temp_function = Function(V)
        self.w = w

        # Create function assigners
        self.assigners = []
        for i in range(gdim):
            self.assigners.append(dolfin.FunctionAssigner(Vout, V.sub(i)))
Beispiel #25
0
def reconstruction(
        localization_tensors: dict,
        macro_kinematic: dict,
        function_spaces: dict,
        localization_rules: dict = {},
        output_request=("u", "eps"),
        **kwargs,
):
    """
    One argument among localization_rules and trunc_order must be used.

    Parameters
    ----------
    localization_tensors : dictionnary
        Format : {
            [Macro_field] : {
                [micro_field] :
                    [list of lists : for each Macro_field component a list contains the components of the localization tensor field.]
            }
        }
    macro_kinematic : dictionnary of fields
        The macroscopic kinematic fields.
        Keys : 'U', 'EG', 'EGG',\\dots
        Values : lists of components.
        None can be used to indicate a component that is equal to 0 or irrelevant.
    function_spaces : dictionnary
        Function space into which each mechanical field have to be built.
            - keys : 'u', 'eps' or 'sigma'
            - values : FEniCS function space
    localization_rules : dict, optional
        The rules that have to be followed for the construction of the fluctuations.
        Defaults to {} i.e. the trunc_order parameter will be used.
    output_request : tuple of strings, optional
        Fields that have to be calculated.
        The request must be consistent with the keys of other parameters :
            - function_spaces
            - localization_rules
        outputs can be :
            =======  ===================
            name      Description
            =======  ===================
            'u'      displacement field
            'eps'    strain field
            'sigma'  stress field
            =======  ===================
        Defaults to ('u', 'eps').

    Return
    ------
    Dictionnary
        Mechanical fields with microscopic fluctuations.
        Keys are "eps", "sigma" and "u" respectively for the strain, stress and displacement fields.

    Other Parameters
    ----------------
    **kwargs :
        Valid kwargs are
            ===============  =====  =============================================
            Key              Type   Description
            ===============  =====  =============================================
            interp_fnct       str   The name of the desired function for the interpolations. Allowed values are : "dolfin.interpolate" and "interpolate_nonmatching_mesh_any"
            trunc_order       int    Order of truncation for the reconstruction of the displacement according to the notations used in ???. Override localization_rules parameter.
            ===============  ======  ============================================




    """
    # TODO : récupérer topo_dim à partir des tenseurs de localisation, ou mieux, à partir des espaces fonctionnels
    # TODO : choisir comment on fixe la len des listes correspondantes aux composantes de u et de epsilon.

    # TODO : permettre la translation du RVE par rapport à la structure macro autre part
    # TODO :  translation_microstructure: np.array, optional
    # TODO :         Vector, 1D array (shape (2,) or (3,)), position origin used for the description of the RVE with regards to the macroscopic origin.

    # Au choix, utilisation de trunc_order ou localization_rules dans les kargs
    trunc_order = kwargs.pop("trunc_order", None)
    if trunc_order:
        localization_rules = {
            "u": [(MACRO_FIELDS_NAMES[i], MACRO_FIELDS_NAMES[i])
                  for i in range(trunc_order + 1)],
            "eps": [(MACRO_FIELDS_NAMES[i], MACRO_FIELDS_NAMES[i])
                    for i in range(1, trunc_order + 1)],
        }
    # * Ex. for truncation order = 2:
    # * localization_rules = {
    # *    'u': [('U','U'), ('E','E'), ('EG','EG')],
    # *    'eps': [('E','E'), ('EG', 'EG')]
    # *}

    interpolate = kwargs.pop("interp_fnct", None)
    if interpolate:
        if interpolate == "dolfin.interpolate":
            interpolate = fe.interpolate
        elif interpolate == "interpolate_nonmatching_mesh_any":
            interpolate = interpolate_nonmatching_mesh_any
        else:
            interpolate = fe.interpolate
    else:
        interpolate = fe.interpolate

    reconstructed_fields = dict()

    for mecha_field in output_request:
        # * Prepare function spaces and assigner
        fspace = function_spaces[mecha_field]
        value_shape = fspace.ufl_element()._value_shape
        if len(value_shape) == 1:
            vector_dim = value_shape[0]
            mesh = fspace.mesh()
            element = fe.FiniteElement(
                fspace._ufl_element._family,
                mesh.ufl_cell(),
                fspace._ufl_element._degree,
            )
            element_family = element.family()
            constrain = fspace.dofmap().constrained_domain
            scalar_fspace = fe.FunctionSpace(mesh,
                                             element,
                                             constrained_domain=constrain)
            assigner = fe.FunctionAssigner(fspace,
                                           [scalar_fspace] * vector_dim)
            logger.debug(
                f"for reconstruction of {mecha_field}, vector_dim = {vector_dim}"
            )
        elif len(value_shape) == 0:
            logger.warning(
                "The value_shape attribute has not been found for the following function space. It is therefore assumed to be a scalar function space for the reconstruction : %s",
                fspace,
            )
            scalar_fspace = fspace
            vector_dim = 1
            element_family = fspace._ufl_element._family
            assigner = fe.FunctionAssigner(fspace, scalar_fspace)
        else:
            raise NotImplementedError(
                "Only vector fields are supported by the reconstruction function for now."
            )

        macro_kin_funct = dict()
        for key, field in macro_kinematic.items():
            macro_kin_funct[key] = list()
            for comp in field:
                if comp:
                    macro_kin_funct[key].append(
                        interpolate(comp, scalar_fspace))
                else:
                    macro_kin_funct[key].append(0)

        # * Reconstruction proper
        contributions = [list() for i in range(vector_dim)]
        for macro_key, localization_key in localization_rules[mecha_field]:
            macro_f = macro_kin_funct[macro_key]
            loc_tens = localization_tensors[localization_key][mecha_field]
            for macro_comp, loc_tens_comps in zip(macro_f, loc_tens):
                if not macro_comp:
                    continue
                for i in range(vector_dim):
                    loc_comp = interpolate(loc_tens_comps[i], scalar_fspace)
                    contributions[i].append((macro_comp, loc_comp))

        # components = [sum(compnt_contrib) for compnt_contrib in contributions]
        components = [fe.Function(scalar_fspace) for i in range(vector_dim)]
        for i in range(vector_dim):
            vec = components[i].vector()
            values = vec.get_local()
            new_val = np.zeros_like(values)
            for macro_kin, loc in contributions[i]:
                loc_local_val = loc.vector().get_local()
                kin_local_val = macro_kin.vector().get_local()
                new_val += loc_local_val * kin_local_val
            values[:] = new_val
            vec.set_local(values)
            vec.apply("insert")
        # TODO : Regarder si le passage par np array faire perdre du temps, et auquel cas si l'on peut s'en passer.
        # TODO : avec axpy par exemple.
        # https://fenicsproject.org/docs/dolfin/2016.2.0/cpp/programmers-reference/la/GenericVector.html #noqa

        # * Components -> vector field
        field = fe.Function(fspace)
        if len(value_shape) == 0:
            components = components[0]
        assigner.assign(field, components)
        reconstructed_fields[mecha_field] = field
    return reconstructed_fields
Beispiel #26
0
import dolfin as dl

mesh = dl.UnitSquareMesh(10, 10)
V1 = dl.VectorFunctionSpace(mesh, "CG", 2)
V2 = dl.FunctionSpace(mesh, "CG", 1)
V3 = dl.FunctionSpace(mesh, "CG", 1)
V = dl.MixedFunctionSpace([V1, V2, V3])

f1 = dl.Expression(("A + B*x[1]*(1-x[1])", "0."), A=1., B=1.)
f2 = dl.Expression("A*x[0]", A=1.)
f3 = dl.Expression("A", A=-3.)

F1, F2, F3 = [
    dl.interpolate(fi, Vi) for fi, Vi in zip((f1, f2, f3), (V1, V2, V3))
]

assigner = dl.FunctionAssigner(V, [V1, V2, V3])
state = dl.Function(V)
assigner.assign(state, [F1, F2, F3])

print "|| state ||^2_L^(2) = ", dl.assemble(dl.inner(state, state) * dl.dx)

dl.plot(state.sub(0))
dl.plot(state.sub(1))
dl.plot(state.sub(2))

dl.interactive()
Beispiel #27
0
    def __init__(self,
                 mesh: df.Mesh,
                 time: df.Constant,
                 M_i: tp.Union[df.Expression, tp.Dict[int, df.Expression]],
                 M_e: tp.Union[df.Expression, tp.Dict[int, df.Expression]],
                 I_s: tp.Union[df.Expression, tp.Dict[int,
                                                      df.Expression]] = None,
                 I_a: tp.Union[df.Expression, tp.Dict[int,
                                                      df.Expression]] = None,
                 ect_current: tp.Dict[int, df.Expression] = None,
                 v_: df.Function = None,
                 cell_domains: df.MeshFunction = None,
                 facet_domains: df.MeshFunction = None,
                 dirichlet_bc: tp.List[tp.Tuple[df.Expression, int]] = None,
                 dirichlet_bc_v: tp.List[tp.Tuple[df.Expression, int]] = None,
                 periodic_domain: df.SubDomain = None,
                 parameters: df.Parameters = None) -> None:
        """Initialise solverand check all parametersare correct.

        NB! The periodic domain has to be set in the cellsolver too.
        """
        self._timestep = None

        comm = df.MPI.comm_world
        rank = df.MPI.rank(comm)

        msg = "Expecting mesh to be a Mesh instance, not {}".format(mesh)
        assert isinstance(mesh, df.Mesh), msg

        msg = "Expecting time to be a Constant instance (or None)."
        assert isinstance(time, df.Constant) or time is None, msg

        msg = "Expecting parameters to be a Parameters instance (or None)"
        assert isinstance(parameters, df.Parameters) or parameters is None, msg

        self._nullspace_basis = None

        # Store input
        self._mesh = mesh
        self._time = time

        # Initialize and update parameters if given
        self._parameters = self.default_parameters()
        if parameters is not None:
            self._parameters.update(parameters)

        if self._parameters["Chi"] == -1 or self._parameters["Cm"] == -1:
            raise ValueError(
                "Need Chi and Cm to be specified explicitly throug the parameters."
            )

        # Set-up function spaces
        k = self._parameters["polynomial_degree"]
        Ve = df.FiniteElement("CG", self._mesh.ufl_cell(), k)
        V = df.FunctionSpace(self._mesh,
                             "CG",
                             k,
                             constrained_domain=periodic_domain)
        Ue = df.FiniteElement("CG", self._mesh.ufl_cell(), k)

        if self._parameters["linear_solver_type"] == "direct":
            Re = df.FiniteElement("R", self._mesh.ufl_cell(), 0)
            _element = df.MixedElement((Ve, Ue, Re))
            self.VUR = df.FunctionSpace(mesh,
                                        _element,
                                        constrained_domain=periodic_domain)
        else:
            _element = df.MixedElement((Ve, Ue))
            self.VUR = df.FunctionSpace(mesh,
                                        _element,
                                        constrained_domain=periodic_domain)

        self.V = V

        if cell_domains is None:
            cell_domains = df.MeshFunction("size_t", mesh,
                                           self._mesh.geometry().dim())
            cell_domains.set_all(0)

        # Chech that it is indeed a cell function.
        cell_dim = cell_domains.dim()
        mesh_dim = self._mesh.geometry().dim()
        msg = "Got {cell_dim}, expected {mesh_dim}.".format(cell_dim=cell_dim,
                                                            mesh_dim=mesh_dim)
        assert cell_dim == mesh_dim, msg
        self._cell_domains = cell_domains

        if facet_domains is None:
            facet_domains = df.MeshFunction("size_t", mesh,
                                            self._mesh.geometry().dim() - 1)
            facet_domains.set_all(0)

        # Check that it is indeed a facet function.
        facet_dim = facet_domains.dim()
        msg = "Got {facet_dim}, expected {mesh_dim}.".format(
            facet_dim=facet_dim, mesh_dim=mesh_dim - 1)
        assert facet_dim == mesh_dim - 1, msg
        self._facet_domains = facet_domains

        # Gather all cell keys on all processes. Greatly simplifies things
        cell_keys = set(self._cell_domains.array())
        all_cell_keys = comm.allgather(cell_keys)
        all_cell_keys = reduce(or_, all_cell_keys)

        # If Mi is not dict, make dict
        if not isinstance(M_i, dict):
            M_i = {int(i): M_i for i in all_cell_keys}
        else:  # Check that the keys match the cell function
            M_i_keys = set(M_i.keys())
            msg = "Got {M_i_keys}, expected {cell_keys}.".format(
                M_i_keys=M_i_keys, cell_keys=all_cell_keys)
            assert M_i_keys == all_cell_keys, msg

        # If Me is not dict, make dict
        if not isinstance(M_e, dict):
            M_e = {int(i): M_e for i in all_cell_keys}
        else:  # Check that the keys match the cell function
            M_e_keys = set(M_e.keys())
            msg = "Got {M_e_keys}, expected {cell_keys}.".format(
                M_e_keys=M_e_keys, cell_keys=all_cell_keys)
            assert M_e_keys == all_cell_keys, msg
        self._M_i = M_i
        self._M_e = M_e

        # Store source terms
        if I_s is not None and not isinstance(I_s, dict):
            I_s = {key: I_s for key in all_cell_keys}
        self._I_s = I_s

        if I_a is not None and not isinstance(I_a, dict):
            I_a = {key: I_a for key in all_cell_keys}
        self._I_a = I_a

        # Set the ECT current, Note, it myst depend on `time` to be updated
        if ect_current is not None:
            ect_tags = set(ect_current.keys())
            facet_tags = set(self._facet_domains.array())
            msg = "{} not in facet domains ({}).".format(ect_tags, facet_tags)
            assert ect_tags <= facet_tags, msg
        self._ect_current = ect_current

        # Set-up solution fields:
        if v_ is None:
            self.merger = df.FunctionAssigner(V, self.VUR.sub(0))
            self.v_ = df.Function(V, name="v_")
        else:
            # df.debug("Experimental: v_ shipped from elsewhere.")
            self.merger = None
            self.v_ = v_
        self.vur = df.Function(self.VUR, name="vur")

        # Set Dirichlet bcs for the transmembrane potential
        self._bcs = []
        if dirichlet_bc_v is not None:
            for function, marker in dirichlet_bc_v:
                self._bcs.append(
                    df.DirichletBC(self.VUR.sub(0), function,
                                   self._facet_domains, marker))

        # Set Dirichlet bcs for the extra cellular potential
        if dirichlet_bc is not None:
            for function, marker in dirichlet_bc:
                self._bcs.append(
                    df.DirichletBC(self.VUR.sub(1), function,
                                   self._facet_domains, marker))
Beispiel #28
0
    def __init__(self, Vh_STATE, Vhs, bcs0, datafile, dx=dl.dx):
        self.dx = dx
        x, y, U, V, uu, vv, ww, uv, k = np.loadtxt(datafile,
                                                   skiprows=2,
                                                   unpack=True)
        u_fun_mean = VelocityDNS(x=x,
                                 y=y,
                                 U=U,
                                 V=V,
                                 symmetrize=True,
                                 coflow=0.)
        u_fun_data = VelocityDNS(x=x,
                                 y=y,
                                 U=U,
                                 V=V,
                                 symmetrize=False,
                                 coflow=0.)

        u_mean = dl.interpolate(u_fun_mean, Vhs[0])
        u_data = dl.interpolate(u_fun_data, Vhs[0])

        q_order = dl.parameters["form_compiler"]["quadrature_degree"]
        dl.parameters["form_compiler"]["quadrature_degree"] = 6
        noise_var_u = dl.assemble(
            dl.inner(u_fun_data - u_mean, u_fun_data - u_mean) * self.dx,
            form_compiler_parameters=dl.parameters["form_compiler"])
        dl.parameters["form_compiler"]["quadrature_degree"] = q_order

        noise_var_u = 1.e-3
        mpi_comm = Vh_STATE.mesh().mpi_comm()
        rank = dl.MPI.rank(mpi_comm)
        if rank == 0:
            print "Noise Variance = {0}".format(noise_var_u)

        if Vh_STATE.num_sub_spaces() == 2:
            u_trial, p_trial = dl.TrialFunctions(Vh_STATE)
            u_test, p_test = dl.TestFunctions(Vh_STATE)
        elif Vh_STATE.num_sub_spaces() == 3:
            u_trial, p_trial, g_trial = dl.TrialFunctions(Vh_STATE)
            u_test, p_test, g_test = dl.TestFunctions(Vh_STATE)
        else:
            raise InputError()

        Wform = dl.Constant(1. / noise_var_u) * dl.inner(u_trial,
                                                         u_test) * self.dx

        self.W = dl.assemble(Wform)
        dummy = dl.Vector()
        self.W.init_vector(dummy, 0)
        [bc.zero(self.W) for bc in bcs0]
        Wt = Transpose(self.W)
        [bc.zero(Wt) for bc in bcs0]
        self.W = Transpose(Wt)

        xfun = dl.Function(Vh_STATE)
        assigner = dl.FunctionAssigner(Vh_STATE, Vhs)
        if Vh_STATE.num_sub_spaces() == 2:
            assigner.assign(xfun, [u_data, dl.Function(Vhs[1])])
        elif Vh_STATE.num_sub_spaces() == 3:
            assigner.assign(
                xfun,
                [u_data, dl.Function(Vhs[1]),
                 dl.Function(Vhs[2])])

        self.d = xfun.vector()
Beispiel #29
0
def vectorfield_to_components(u, S, dim):
    components = [df.Function(S) for i in range(dim)]
    assigners = [df.FunctionAssigner(S, u.function_space().sub(i)) for i in range(dim)]
    for i, comp, assigner in zip(list(range(dim)), components, assigners):
        assigner.assign(comp, u.sub(i))
    return components
    def __init__(
        self,
        time: df.Constant,
        mesh: df.Mesh,
        intracellular_conductivity: Dict[int, df.Expression],
        extracellular_conductivity: Dict[int, df.Expression],
        cell_function: df.MeshFunction,
        cell_tags: CellTags,
        interface_function: df.MeshFunction,
        interface_tags: InterfaceTags,
        parameters: CoupledBidomainParameters,
        neumann_boundary_condition: Dict[int, df.Expression] = None,
        v_prev: df.Function = None,
        surface_to_volume_factor: Union[float, df.Constant] = None,
        membrane_capacitance: Union[float, df.Constant] = None,
    ) -> None:
        self._time = time
        self._mesh = mesh
        self._parameters = parameters

        # Strip none from cell tags
        cell_tags = set(cell_tags) - {None}

        if surface_to_volume_factor is None:
            surface_to_volume_factor = df.constant(1)

        if membrane_capacitance is None:
            membrane_capacitance = df.constant(1)

        # Set Chi*Cm
        self._chi_cm = df.Constant(surface_to_volume_factor) * df.Constant(
            membrane_capacitance)

        if not set(intracellular_conductivity.keys()) == {
                *tuple(extracellular_conductivity.keys())
        }:
            raise ValueError(
                "intracellular conductivity and lambda does not havemnatching keys."
            )
        if not set(cell_tags) == set(intracellular_conductivity.keys()):
            raise ValueError("Cell tags does not match conductivity keys")
        self._intracellular_conductivity = intracellular_conductivity
        self._extracellular_conductivity = extracellular_conductivity

        # Check cell tags
        _cell_function_tags = set(cell_function.array())
        if set(cell_tags) != _cell_function_tags:  # If not equal
            msg = "Mismatching cell tags. Expected {}, got {}"
            raise ValueError(msg.format(set(cell_tags), _cell_function_tags))
        self._cell_tags = set(cell_tags)
        self._cell_function = cell_function

        restrict_tags = self._parameters.restrict_tags
        if set(restrict_tags) >= self._cell_tags:
            msg = "restrict tags ({})is not a subset of cell tags ({})"
            raise ValueError(msg.format(set(restrict_tags), self._cell_tags))
        self._restrict_tags = set(restrict_tags)

        # Check interface tags
        _interface_function_tags = {*set(interface_function.array()), None}
        if not set(interface_tags
                   ) <= _interface_function_tags:  # if not subset of
            msg = "Mismatching interface tags. Expected {}, got {}"
            raise ValueError(
                msg.format(set(interface_tags), _interface_function_tags))
        self._interface_function = interface_function
        self._interface_tags = interface_tags

        # Set up function spaces
        self._transmembrane_function_space = df.FunctionSpace(
            self._mesh, "CG", 1)
        transmembrane_element = df.FiniteElement("CG", self._mesh.ufl_cell(),
                                                 1)
        extracellular_element = df.FiniteElement("CG", self._mesh.ufl_cell(),
                                                 1)

        if neumann_boundary_condition is None:
            self._neumann_bc: Dict[int, df.Expression] = dict()
        else:
            self._neumann_bc = neumann_boundary_condition

        if self._parameters.linear_solver_type == "direct":
            lagrange_element = df.FiniteElement("R", self._mesh.ufl_cell(), 0)
            mixed_element = df.MixedElement(
                (transmembrane_element, extracellular_element,
                 lagrange_element))
        else:
            mixed_element = df.MixedElement(
                (transmembrane_element, extracellular_element))
        self._VUR = df.FunctionSpace(
            mesh, mixed_element)  # TODO: rename to something sensible

        # Set-up solution fields:
        if v_prev is None:
            self._merger = df.FunctionAssigner(
                self._transmembrane_function_space, self._VUR.sub(0))
            self._v_prev = df.Function(self._transmembrane_function_space,
                                       name="v_prev")
        else:
            self._merger = None
            self._v_prev = v_prev
        self._vur = df.Function(self._VUR,
                                name="vur")  # TODO: Give sensible name

        # For normlising rhs_vector. TODO: Unsure about this. Check the nullspace from cbcbeat
        self._extracellular_dofs = np.asarray(self._VUR.sub(1).dofmap().dofs())

        # Mark first timestep
        self._timestep: df.Constant = None