示例#1
0
文件: saver.py 项目: jakobes/xalpost
    def store_mesh(self,
                   mesh: dolfin.Mesh,
                   cell_domains: dolfin.MeshFunction = None,
                   facet_domains: dolfin.MeshFunction = None) -> None:
        """Save the mesh, and cellfunction and facet function if provided."""
        with dolfin.XDMFFile(mesh.mpi_comm(),
                             str(self._casedir / "mesh.xdmf")) as meshfile:
            meshfile.write(mesh)

            # if cell_domains is not None:
            #     meshfile.write(cell_domains, "cell_domains")
            # if facet_domains is not None:
            #     meshfile.write(facet_domains, "facet_domains")

        if cell_domains is not None:
            with df.XDMFFile(mesh.mpi_comm(),
                             str(self._casedir /
                                 "cell_function.xdmf")) as cf_file:
                cf_file.write(mesh)
                cf_file.write(cell_domains)

        if facet_domains is not None:
            with df.XDMFFile(mesh.mpi_comm(),
                             str(self._casedir /
                                 "facet_function.xdmf")) as ff_file:
                ff_file.write(mesh)
                ff_file.write(facet_domains)
def readmesh(mesh_file):
    ''' read HDF5 or DOLFIN XML mesh '''
    # TODO: exceptions, files exist?
    from dolfin import Mesh, MeshFunction, CellFunction, HDF5File, \
        FacetFunction
    tmp = mesh_file.split('/')[-1].split('.')
    mesh_type = tmp[-1]
    mesh_name = '.'.join(tmp[0:-1])
    if mesh_type == 'xml':
        mesh = Mesh(mesh_file)
        rank = mesh.mpi_comm().Get_rank()
        try:
            subdomains = MeshFunction("size_t", mesh,
                                      mesh_name+"_physical_region.xml")
        except:
	    if rank == 0:
	      print('no subdomain file found (%s)' %
		    (mesh_name+"_physical_region.xml"))
            subdomains = CellFunction("size_t", mesh)
        try:
            boundaries = MeshFunction("size_t", mesh,
                                      mesh_name+"_facet_region.xml")
        except:
	    if rank == 0:
	      print('no boundary file found (%s)' %
		    (mesh_name+"_physical_region.xml"))
            boundaries = FacetFunction("size_t", mesh)
    elif mesh_type == 'h5':
        mesh = Mesh()
        rank = mesh.mpi_comm().Get_rank()
        hdf = HDF5File(mesh.mpi_comm(), mesh_file, "r")
        hdf.read(mesh, "/mesh", False)
        subdomains = CellFunction("size_t", mesh)
        boundaries = FacetFunction("size_t", mesh)
        if hdf.has_dataset('subdomains'):
            hdf.read(subdomains, "/subdomains")
        else:
	    if rank == 0:
	      print('no <subdomains> datasets found in file %s' % mesh_file)
        if hdf.has_dataset('boundaries'):
            hdf.read(boundaries, "/boundaries")
        else:
	    if rank == 0:
	      print('no <boundaries> datasets found in file %s' % mesh_file)

    elif mesh_type in ['xdmf', 'xmf']:
        import sys
        sys.exit('XDMF not supported yet. Use HDF5 instead!')
    else:
        import sys
        sys.exit('mesh format not recognized. try XML (serial) or HDF5')

# NOTE http://fenicsproject.org/qa/5337/importing-marked-mesh-for-parallel-use
    # see file xml2xdmf.py
    return mesh, subdomains, boundaries
示例#3
0
文件: tile.py 项目: MiroK/tieler
def make_mesh(coordinates, cells, tdim, gdim):
    '''Mesh by MeshEditor from vertices and cells'''
    mesh = Mesh()
    # FEniCS 2017
    try: 
        assert mesh.mpi_comm().tompi4py().size == 1
    # FEniCS 2018
    except AttributeError:
        assert mesh.mpi_comm().size == 1

    coordinates.shape = (np.prod(coordinates.shape), )
    cells.shape = (np.prod(cells.shape), )
    fill_mesh(coordinates, cells, tdim, gdim, mesh)
    
    return mesh
示例#4
0
    def __init__(self,
                 mesh: df.Mesh,
                 time: df.Constant,
                 M_i: tp.Union[df.Expression, tp.Dict[int, df.Expression]],
                 I_s: tp.Union[df.Expression, tp.Dict[int,
                                                      df.Expression]] = None,
                 v_: df.Function = None,
                 cell_domains: df.MeshFunction = None,
                 facet_domains: df.MeshFunction = None,
                 parameters: df.Parameters = None) -> None:
        super().__init__(mesh,
                         time,
                         M_i,
                         I_s=I_s,
                         v_=v_,
                         cell_domains=cell_domains,
                         facet_domains=facet_domains,
                         parameters=parameters)

        # Create variational forms
        self._timestep = df.Constant(self.parameters["default_timestep"])
        self._lhs, self._rhs, self._prec = self.variational_forms(
            self._timestep)

        # Preassemble left-hand side (will be updated if time-step changes)
        self._lhs_matrix = df.assemble(self._lhs)
        self._rhs_vector = df.Vector(mesh.mpi_comm(), self._lhs_matrix.size(0))
        self._lhs_matrix.init_vector(self._rhs_vector, 0)

        # Create linear solver (based on parameter choices)
        self._linear_solver = self._create_linear_solver()
示例#5
0
def convert(msh_file, h5_file):
    '''Temporary version of convert from msh to h5'''
    root, _ = os.path.splitext(msh_file)
    assert os.path.splitext(msh_file)[1] == '.msh'
    assert os.path.splitext(h5_file)[1] == '.h5'

    # Get the xml mesh
    xml_file = '.'.join([root, 'xml'])
    subprocess.call(['dolfin-convert %s %s' % (msh_file, xml_file)], shell=True)
    # Success?
    assert os.path.exists(xml_file)

    mesh = Mesh(xml_file)
    out = HDF5File(mesh.mpi_comm(), h5_file, 'w')
    out.write(mesh, 'mesh')

    info('Mesh has %d cells' % mesh.num_cells())
    info('Mesh size %g %g' % (mesh.hmin(), mesh.hmax()))

    outputs = [mesh]
    # Save ALL data as facet_functions
    names = ('surfaces', 'volumes')
    for name, region in zip(names, ('facet_region.xml', 'physical_region.xml')):
        r_xml_file = '_'.join([root, region])

        f = MeshFunction('size_t', mesh, r_xml_file)
        out.write(f, name)
        
        outputs.append(f)
        
    return outputs
示例#6
0
def convert(msh_file):
    '''Temporary version of convertin from msh to h5'''
    root, _ = os.path.splitext(msh_file)
    assert os.path.splitext(msh_file)[1] == '.msh'

    # Get the xml mesh
    xml_file = '.'.join([root, 'xml'])

    # Convert to XML
    convert2xml(msh_file, xml_file)

    # Success?
    assert os.path.exists(xml_file)

    mesh = Mesh(xml_file)
    h5_file = '.'.join([root, 'h5'])
    out = HDF5File(mesh.mpi_comm(), h5_file, 'w')
    out.write(mesh, 'mesh')

    # Save ALL data as facet_functions
    data_sets = ('curves', 'surfaces', 'volumes')
    regions = ('curve_region.xml', 'facet_region.xml', 'volume_region.xml')

    for data_set, region in zip(data_sets, regions):
        r_xml_file = '_'.join([root, region])

        if os.path.exists(r_xml_file):
            f = MeshFunction('size_t', mesh, r_xml_file)
            out.write(f, data_set)
            # And clean
            os.remove(r_xml_file)
    # and clean
    os.remove(xml_file)

    return h5_file
def convert(msh_file, h5_file):
    '''Convert msh file to h5_file'''
    root, _ = os.path.splitext(msh_file)
    assert os.path.splitext(msh_file)[1] == '.msh'
    assert os.path.splitext(h5_file)[1] == '.h5'

    # Get the xml mesh
    xml_file = '.'.join([root, 'xml'])
    subprocess.call(['dolfin-convert %s %s' % (msh_file, xml_file)],
                    shell=True)
    # Success?
    assert os.path.exists(xml_file)

    mesh = Mesh(xml_file)
    out = HDF5File(mesh.mpi_comm(), h5_file, 'w')
    out.write(mesh, 'mesh')

    for region in ('facet_region.xml', ):
        name, _ = region.split('_')
        r_xml_file = '_'.join([root, region])

        f = MeshFunction('size_t', mesh, r_xml_file)
        out.write(f, name)

    # Sucess?
    assert os.path.exists(h5_file)

    return mesh
示例#8
0
def load_mesh(filename, subdir="mesh", use_partition_from_file=False):
    """ Loads the mesh specified by the argument filename. """
    info_cyan("Loading mesh: " + filename)
    mesh = Mesh()
    h5file = HDF5File(mesh.mpi_comm(), filename, "r")
    h5file.read(mesh, subdir, use_partition_from_file)
    h5file.close()
    return mesh
示例#9
0
def make_mesh(coordinates, cells, tdim, gdim):
    '''Mesh by MeshEditor from vertices and cells'''
    mesh = Mesh()
    assert mesh.mpi_comm().tompi4py().size == 1

    fill_mesh(coordinates.flatten(), cells.flatten(), tdim, gdim, mesh)
    
    return mesh
示例#10
0
def load_mesh(filename):
    """ Loads in the mesh specified by the argument filename. """
    info_cyan("Loading mesh: " + filename)
    mesh = Mesh()
    h5file = HDF5File(mesh.mpi_comm(), filename, "r")
    h5file.read(mesh, "mesh", False)
    h5file.close()
    return mesh
示例#11
0
def make_mesh(coordinates, cells, tdim, gdim, mesh=None):
    '''Mesh by MeshEditor from vertices and cells'''
    if mesh is None:
        mesh = Mesh()
        assert mesh.mpi_comm().size == 1

    module.fill_mesh(coordinates.flatten(), cells.flatten(), tdim, gdim, mesh)
    
    return mesh
示例#12
0
def make_mesh(coordinates, cells, tdim, gdim, mesh=None):
    '''Mesh by MeshEditor from vertices and cells'''
    if mesh is None:
        mesh = Mesh()
        assert mesh.mpi_comm().size == 1

    module.fill_mesh(coordinates.flatten(), cells.flatten(), tdim, gdim, mesh)

    return mesh
示例#13
0
def read_h5(h5Path):
    mesh = Mesh()
    hdf = HDF5File(mesh.mpi_comm(), h5Path, 'r')
    hdf.read(mesh, '/mesh', False)
    subdomains = MeshFunction('size_t', mesh, 3)
    boundaries = MeshFunction('size_t', mesh, 2)

    hdf.read(subdomains, '/subdomains')
    hdf.read(boundaries, '/boundaries')

    return mesh, subdomains, boundaries
示例#14
0
 def store_mesh(self,
                mesh: dolfin.Mesh,
                cell_domains: dolfin.MeshFunction = None,
                facet_domains: dolfin.MeshFunction = None) -> None:
     """Save the mesh, and cellfunction and facet function if provided."""
     filename = self.casedir / Path("mesh.hdf5")
     with dolfin.HDF5File(mesh.mpi_comm(), str(filename), "w") as meshfile:
         meshfile.write(mesh, "/Mesh")
         if cell_domains is not None:
             meshfile.write(cell_domains, "/CellDomains")
         if facet_domains is not None:
             meshfile.write(facet_domains, "/FacetDomains")
示例#15
0
def load_h5_mesh(h5_file, scale_factor=None):
    '''Unpack to mesh, volumes and surfaces'''
    mesh = Mesh()
    h5 = HDF5File(mesh.mpi_comm(), h5_file, 'r')
    h5.read(mesh, 'mesh', False)
    # Convert units
    if scale_factor is not None:
        assert scale_factor > 0, "Scale factor must be a positive real number!"
        mesh.coordinates()[:] *= scale_factor

    surfaces = MeshFunction('size_t', mesh, mesh.topology().dim() - 1)
    h5.read(surfaces, 'surfaces')

    volumes = MeshFunction('size_t', mesh, mesh.topology().dim())
    h5.read(volumes, 'volumes')

    return mesh, volumes, surfaces
示例#16
0
def as_pvd(h5_file):
    '''Store facet and cell function for pvd'''
    root, ext = os.path.splitext(h5_file)

    mesh = Mesh()
    hdf = HDF5File(mesh.mpi_comm(), h5_file, 'r')
    hdf.read(mesh, '/mesh', False)

    facet_markers = FacetFunction('size_t', mesh)
    hdf.read(facet_markers, '/facet_markers')

    cell_markers = CellFunction('size_t', mesh)
    hdf.read(cell_markers, '/cell_markers')

    File(root + 'facets' + '.pvd') << facet_markers
    File(root + 'volumes' + '.pvd') << cell_markers

    return True
示例#17
0
def convert(msh_file, h5_file, save_mvc=False):
    '''Temporary version of convertin from msh to h5'''
    root, _ = os.path.splitext(msh_file)
    assert os.path.splitext(msh_file)[1] == '.msh'
    assert os.path.splitext(h5_file)[1] == '.h5'

    # Get the xml mesh
    xml_file = '.'.join([root, 'xml'])
    subprocess.call(['dolfin-convert %s %s' % (msh_file, xml_file)], shell=True)
    # Success?
    assert os.path.exists(xml_file)

    mesh = Mesh(xml_file)
    out = HDF5File(mesh.mpi_comm(), h5_file, 'w')
    out.write(mesh, 'mesh')

    print('Mesh has %d cells' % mesh.num_cells())
    print('Mesh size %g %g' % (mesh.hmin(), mesh.hmax()))
    
    # Save ALL data as facet_functions
    names = ('surfaces', 'volumes')
    if not save_mvc:
        for name, region in zip(names, ('facet_region.xml', 'physical_region.xml')):
            r_xml_file = '_'.join([root, region])

            f = MeshFunction('size_t', mesh, r_xml_file)
            print('%d %s with 1' % (sum(1 for _ in SubsetIterator(f, 1)), name))
            out.write(f, name)

        return True

    for name, region in zip(names, ('facet_region.xml', 'physical_region.xml')):
        r_xml_file = '_'.join([root, region])

        f = MeshFunction('size_t', mesh, r_xml_file)
        # With mesh value collection we only store nonzero tags
        mvc = MeshValueCollection('size_t', mesh, f.dim())
        # Fill
        fill_mvc_from_mf(f, mvc)
        # And save
        out.write(mvc, name)
                    
    return True
    for (nx, dt, pres, store_step) in zip(nx_list, dt_list, pres_list, storestep_list):
        if comm.Get_rank() == 0:
            print("Starting computation with grid resolution " + str(nx))

        # Compute num steps till completion
        num_steps = np.rint(Tend / float(dt))

        # Generate mesh
        mesh = Mesh("./../../meshes/circle_0.xml")
        n = nx
        while n > 1:
            mesh = refine(mesh)
            n /= 2

        output_field = XDMFFile(mesh.mpi_comm(), outdir + "psi_h_nx" + str(nx) + ".xdmf")

        # Velocity and initial condition
        V = VectorFunctionSpace(mesh, "DG", 3)
        uh = Function(V)
        uh.assign(Expression(("-Uh*x[1]", "Uh*x[0]"), Uh=Uh, degree=3))

        psi0_expression = GaussianPulse(
            center=(xc, yc), sigma=float(sigma), U=[Uh, Uh], time=0.0, height=1.0, degree=3
        )

        # Generate particles
        x = RandomCircle(Point(x0, y0), r).generate([pres, pres])
        s = np.zeros((len(x), 1), dtype=np.float_)

        # Initialize particles with position x and scalar property s at the mesh
示例#19
0
class FBVP:
    def __init__(self, mesh_name, parameters, alpha_range=None):
        # LOAD MESH AND PARAMETERS
        self.parameters = parameters
        self.mesh_name = mesh_name
        if not alpha_range:
            self.alpha_range = parameters.alpha_range
        else:
            self.alpha_range = alpha_range
        mesh_path = self.parameters.get_mesh_path()

        self.mesh = Mesh()
        with XDMFFile(mesh_path) as f:
            f.read(self.mesh)
        print(f'Mesh size= {self.mesh.hmax()}')
        # dimension of approximation space
        self.dim = len(self.mesh.coordinates())
        print(f'Dimension of solution space is {self.dim}')
        self.V = FunctionSpace(self.mesh, 'CG', 1)  # CG =  P1
        self.coords = self.mesh.coordinates()[dof_to_vertex_map(self.V)]
        self.T = self.parameters.T  # final time
        self.w = TrialFunction(self.V)
        self.u = TestFunction(self.V)
        #######################################################################
        # CONTROL SET CREATION
        self.control_set = np.linspace(self.alpha_range[0],
                                       self.alpha_range[1],
                                       self.parameters.control_set_size)
        self.control_set_size = len(self.control_set)
        print(f'Discretized control set has size {self.control_set_size}')
        #######################################################################
        # BOUNDARY CONDITIONS
        parameters.set_boundary_conditions(self.mesh)
        self.boundary_markers = MeshFunction('size_t', self.mesh, 1)
        self.boundary_markers.set_all(4)  # pylint: disable=no-member

        for i, omega in self.parameters.omegas.items():
            omega.mark(self.boundary_markers, i)

        self.ds = Measure('ds',
                          domain=self.mesh,
                          subdomain_data=self.boundary_markers)

        self.dirichlet_bcs = [
            DirichletBC(self.V, parameters.RHS_bound[j], self.boundary_markers,
                        j) for j in self.parameters.regions["Dirichlet"]
        ]

        # Get indices of dirichlet and robin dofs
        self.dirichlet_nodes_list = set()
        self.dirichlet_nodes_dict = {}
        for j in self.parameters.regions["Dirichlet"]:
            bc = DirichletBC(self.V, Constant(0), self.boundary_markers, j)
            self.dirichlet_nodes_list |= set(bc.get_boundary_values().keys())
            self.dirichlet_nodes_dict[j] = list(
                bc.get_boundary_values().keys())

        self.robin_nodes_list = set()
        self.robin_nodes_dict = {}
        for j in self.parameters.regions["Robin"]:
            bc = DirichletBC(self.V, Constant(0), self.boundary_markers, j)
            self.robin_nodes_list |= set(bc.get_boundary_values().keys())
            self.robin_nodes_dict[j] = list(bc.get_boundary_values().keys())

        bc = DirichletBC(self.V, Constant(0), 'on_boundary')
        self.boundary_nodes_list = bc.get_boundary_values().keys()

        self.robint_nodes_list = set()
        self.robint_nodes_dict = {}
        for j in self.parameters.regions["RobinTime"]:
            bc = DirichletBC(self.V, Constant(0), self.boundary_markers, j)
            self.robint_nodes_list |= set(bc.get_boundary_values().keys())
            self.robint_nodes_dict[j] = list(bc.get_boundary_values().keys())
        #######################################################################
        # ASSEMBLY
        time_start = time.process_time()
        self.assemble_diagonal_matrix()  # auxilliary generic diagonal matrix
        # used for vector*matrix multiplication of dolfin matrices
        self.assemble_lumpedmm()  # lumped mass matrix
        # which serves the role of identity operator
        self.assemble_laplacian()  # discrete laplacian

        self.ad_data_path = f'out/{self.parameters.experiment}'
        Path(self.ad_data_path).mkdir(parents=True, exist_ok=True)

        self.timesteps = self.parameters.get_number_of_timesteps()
        self.assemble_HJBe()  # assembly of explicit operators
        self.assemble_HJBi()  # assembly of implicit operators
        self.assemble_RHS()  # assembly of forcing term
        print('Final time assembly complete')
        print(f'Assembly took {time.process_time() - time_start} seconds')

        print('===========================================================')

    def assemble_diagonal_matrix(self):
        print("Assembling auxilliary diagonal matrix")
        """ Operator assembled to get the right sparameterssity pattern
        (non-zero terms can only exist on diagonal)
        """
        mesh3 = UnitIntervalMesh(self.dim)
        V3 = FunctionSpace(mesh3, "DG", 0)
        wid = TrialFunction(V3)
        uid = TestFunction(V3)
        self.diag_matrix = assemble(uid * wid * dx)
        self.diag_matrix.zero()

    def assemble_lumpedmm(self):
        """ Assembly lumped mass matrix - equal to 0 on robin boundary since
            there is no time derivative there.
        """
        print("Assembling lumped mass matrix")
        mass_form = self.w * self.u * dx
        mass_action_form = action(mass_form, Constant(1))
        self.MM_terms = assemble(mass_action_form)

        for n in self.robint_nodes_list:
            self.MM_terms[n] = 1.0
        for n in self.robin_nodes_list:
            self.MM_terms[n] = 0.0

        self.mass_matrix = assemble(mass_form)
        self.mass_matrix.zero()
        self.mass_matrix.set_diagonal(self.MM_terms)
        self.scipy_mass_matrix = toscipy(self.mass_matrix)

    def assemble_laplacian(self):
        print("Assembling laplacians")
        # laplacian discretisation
        self.laplacian = assemble(dot(grad(self.w), grad(self.u)) * dx)

    def assemble_HJBe(self, t=None):
        """ Assembly explicit operator for every control in the control set,
        then apply artificial diffusion to all of them. Note that artificial
        diffusion is calculated differently on the boundary nodes.
        """
        self.explicit_matrices = np.empty(self.control_set_size, dtype=object)
        self.explicit_diffusion = np.empty([self.control_set_size, self.dim])
        diagonal_vector = Vector(self.mesh.mpi_comm(), self.dim)
        global_min_timestep = float('inf')
        # Create explicit operator for each control in control set
        for k, alpha in enumerate(self.control_set):
            if k % 10 == 0:
                print(f'Assembling explicit matrix under control {k}'
                      f' out of {self.control_set_size}')
            # coefficients in the interior
            advection_x = self.parameters.adv_x(alpha)
            advection_y = self.parameters.adv_y(alpha)
            reaction = self.parameters.lin(alpha)

            if t is not None:
                advection_x.t = t
                advection_y.t = t
                reaction.t = t

            # Discretize PDE (set values on boundary rows to zero)
            b = np.array([advection_x, advection_y])
            E_interior_form = (np.dot(b, grad(self.w)) +
                               reaction * self.w) * self.u * dx
            explicit_matrix = assemble(E_interior_form)
            set_zero_rows(explicit_matrix, self.boundary_nodes_list)

            # Calculate diffusion necessary to make explicit operator monotone
            min_diffusion = np.zeros(explicit_matrix.size(0))
            for rows, row_num in getrows(explicit_matrix,
                                         self.laplacian,
                                         ignore=self.boundary_nodes_list):
                min_diffusion[row_num] = calc_ad(rows, row_num)
            self.explicit_diffusion[k] = min_diffusion

            discrete_diffusion = apply_ad(self.laplacian, min_diffusion)
            explicit_matrix += discrete_diffusion

            for j in self.parameters.regions['RobinTime']:
                self.set_directional_derivative(
                    explicit_matrix,
                    region=j,
                    nodes=self.robint_nodes_dict[j],
                    control=alpha,
                    time=t)

            explicit_matrix.get_diagonal(diagonal_vector)
            current_min_timestep = get_min_timestep(
                diagonal_vector, self.MM_terms,
                self.dirichlet_nodes_list | self.robin_nodes_list)
            global_min_timestep = min(current_min_timestep,
                                      global_min_timestep)
            self.explicit_matrices[k] = toscipy(explicit_matrix)

        #######################################################################
        min_timesteps = int(self.T / global_min_timestep) + 1
        if not self.timesteps or self.timesteps < min_timesteps:
            self.timesteps = min_timesteps
        try:
            filename = (f'meshes/{self.parameters.domain}/'
                        f'Mvalues-{self.parameters.experiment}.json')
            with open(filename, 'r') as f:
                min_timesteps_dict = json.load(f)
        except FileNotFoundError:
            min_timesteps_dict = {}
        min_timesteps_dict[self.parameters.mesh_name] = self.timesteps
        with open(filename, 'w') as f:
            json.dump(min_timesteps_dict, f)

        self.timestep_size = self.T / self.timesteps  # time step size
        self.parameters.calculate_save_interval()
        self.explicit_matrices = self.timestep_size * self.explicit_matrices - \
            np.repeat(self.scipy_mass_matrix, self.control_set_size)

        print('Checking if the explicit operators satisfy'
              ' monotonicity conditions')
        for explicit_matrix in self.explicit_matrices:
            explicit_check(explicit_matrix, self.dirichlet_nodes_list)

    def assemble_RHS(self, t=None):
        """Assemble right hand side of the FBVP
        """
        print('Assembling RHS')
        self.forcing_terms = np.empty([self.control_set_size, self.dim])
        for i, alpha in enumerate(self.control_set):
            rhs = self.parameters.RHSt(alpha)
            if t is not None:
                rhs.t = t
            # Initialise forcing term
            F = np.array(assemble(rhs * self.u * dx)[:])

            for j in self.parameters.regions['RobinTime']:
                rhs = self.parameters.RHS_bound[j](alpha)
                if t is not None:
                    rhs.t = t
                bc = DirichletBC(self.V, rhs, self.boundary_markers, j)
                vals = bc.get_boundary_values()
                F[list(vals.keys())] = list(vals.values())

            for j in self.parameters.regions['Robin']:
                rhs = self.parameters.RHS_bound[j](alpha)
                if t is not None:
                    rhs.t = t
                bc = DirichletBC(self.V, rhs, self.boundary_markers, j)
                vals = bc.get_boundary_values()
                F[list(vals.keys())] = list(vals.values())

            self.forcing_terms[i] = self.timestep_size * F

    def assemble_HJBi(self, t=None):
        """ Assembly matrix discretizing second order terms after diffusion
        moved to the explicit operator is subtracted. Whenever amount of
        diffusion used to make some row of an explicit operator monotonic
        exceeds the amount of natural diffusion at that node we call it
        artificial diffusion. In such case, this row of the implicit operator
        is multiplied by zero
        """
        print('Assembling implicit operators')
        self.implicit_matrices = []
        remaining_diffusion = Function(self.V)
        max_art_dif = 0.0
        max_art_dif_loc = None
        diffusion_matrix = self.diag_matrix.copy()
        for explicit_diffusion, alpha in \
                zip(self.explicit_diffusion, self.control_set):

            diffusion = self.parameters.diffusion(alpha)
            if t is not None:
                diffusion.t = t

            diff = interpolate(diffusion, self.V).vector()
            if not np.all(diff >= 0):
                raise Exception("Choose non-negative diffusion")
            diff_vec = np.array([
                diff[i] if i not in self.boundary_nodes_list else 0.0
                for i in range(self.dim)
            ])

            artificial_diffusion = explicit_diffusion - diff_vec
            if np.amax(artificial_diffusion) > max_art_dif:
                max_art_dif = np.amax(artificial_diffusion)
                max_art_dif_loc = self.coords[np.argmax(artificial_diffusion)]

            # discretise second order terms
            remaining_diffusion.vector()[:] = np.maximum(
                -artificial_diffusion, [0] * self.dim)
            diffusion_matrix.set_diagonal(remaining_diffusion.vector())
            implicit_matrix = matmult(diffusion_matrix, self.laplacian)

            for j in self.parameters.regions['Robin']:
                self.set_directional_derivative(implicit_matrix,
                                                region=j,
                                                nodes=self.robin_nodes_dict[j],
                                                control=alpha,
                                                time=t)

            self.implicit_matrices.append(self.timestep_size *
                                          implicit_matrix + self.mass_matrix)

        self.scipy_implicit_matrices = [
            toscipy(mat) for mat in self.implicit_matrices
        ]
        print('Checking if the implicit operators satisfy'
              ' monotonicity conditions')
        for implicit_matrix in self.scipy_implicit_matrices:
            implicit_check(implicit_matrix)

        with open(self.ad_data_path + '/ad.txt', 'a') as f:
            time_str = f' at time {t}\n' if t is not None else '\n'
            f.write(f'For mesh {self.mesh_name} max value of artificial'
                    ' diffusion coefficient was'
                    f' {max_art_dif} at {max_art_dif_loc}' + time_str)

    def set_directional_derivative(self,
                                   operator,
                                   region,
                                   nodes,
                                   control,
                                   time=None):
        if region in self.parameters.regions['Robin']:
            adv_x = self.parameters.robin_adv_x[region](control)
            adv_y = self.parameters.robin_adv_y[region](control)
            lin = self.parameters.robin_lin[region](control)
        elif region in self.parameters.regions['RobinTime']:
            adv_x = self.parameters.robint_adv_x[region](control)
            adv_y = self.parameters.robint_adv_y[region](control)
            lin = self.parameters.robint_lin[region](control)

        if time is not None:
            adv_x.t = time
            adv_y.t = time
            lin.t = time
        b = (interpolate(adv_x, self.V), interpolate(adv_y, self.V))
        c = interpolate(lin, self.V)
        for n in nodes:
            # node coordinates
            x = self.coords[n]
            # evaluate advection at robin node
            b_x = np.array([b[0].vector()[n], b[1].vector()[n]])
            # denominator used to calculate directional derivative
            if np.linalg.norm(b_x) > 1:
                lamb = 0.1 * self.mesh.hmin() / np.linalg.norm(b_x)
            else:
                lamb = 0.1 * self.mesh.hmin()
            # position of first node of the stencil
            x_prev = x - lamb * b_x
            # Find cell containing first node of stencil and get its
            # dof/vertex coordinates
            try:
                cell_ind = self.mesh.bounding_box_tree(
                ).compute_entity_collisions(Point(x_prev))[0]
            except IndexError:
                i = 16
                while i > 2:
                    # sometimes Fenics does not detect nodes if boundary is
                    # parallel to the boundary advection due to rounding errors
                    # so try different precisions just to be sure
                    try:
                        cell_ind = self.mesh.bounding_box_tree(
                        ).compute_entity_collisions(Point(np.round(x_prev,
                                                                   i)))[0]
                        break
                    except IndexError:
                        i -= 1
                else:
                    raise Exception(
                        "Boundary advection outside tangential cone")
            cell_vertices = self.mesh.cells()[cell_ind]
            cell_dofs = vertex_to_dof_map(self.V)[cell_vertices]
            cell_coords = self.mesh.coordinates()[cell_vertices]
            # calculate weigth of each vertex in the cell (using
            #  barycentric coordinates)
            A = np.vstack((cell_coords.T, np.ones(3)))
            rhs = np.append(x_prev, np.ones(1))
            weights = np.linalg.solve(A, rhs)
            weights = [w if w > 1e-14 else 0 for w in weights]
            dof_to_weight = dict(zip(cell_dofs, weights))

            # calculate directional derivative at each node using
            # weights to interpolate value of numerical solution at
            # x_prev
            row = operator.getrow(n)
            indices = row[0]
            data = row[1]
            for dof in cell_dofs:
                pos = np.where(indices == dof)[0][0]
                if dof != n:
                    data[pos] = -dof_to_weight[dof] / lamb
                else:
                    c_n = c.vector()[dof]
                    # make sure reaction term is positive adding artificial
                    # constant if necessary
                    if region in self.parameters.regions['Robin']:
                        c_n = max(c_n, min(lamb, 1E-8))
                    data[pos] = (1 - dof_to_weight[dof]) / lamb + c_n
            operator.set([data], [n], indices)
            operator.apply('insert')
示例#20
0
    for (nx, dt, pres, store_step) in zip(nx_list, dt_list, pres_list,
                                          storestep_list):
        if comm.Get_rank() == 0:
            print("Starting computation with grid resolution " + str(nx))

        # Compute num steps till completion
        num_steps = np.rint(Tend / float(dt))

        # Generate mesh
        mesh = Mesh("./../../meshes/circle_0.xml")
        n = nx
        while n > 1:
            mesh = refine(mesh)
            n /= 2

        output_field = XDMFFile(mesh.mpi_comm(),
                                outdir + "psi_h_nx" + str(nx) + ".xdmf")

        # Velocity and initial condition
        V = VectorFunctionSpace(mesh, "DG", 3)
        uh = Function(V)
        uh.assign(Expression(("-Uh*x[1]", "Uh*x[0]"), Uh=Uh, degree=3))

        psi0_expression = GaussianPulse(center=(xc, yc),
                                        sigma=float(sigma),
                                        U=[Uh, Uh],
                                        time=0.0,
                                        height=1.0,
                                        degree=3)

        # Generate particles
示例#21
0
def create_slice(basemesh, point, normal, closest_region=False, crinkle_clip=False):
    """Create a slicemesh from a basemesh.

    :param basemesh: Mesh to slice
    :param point: Point in slicing plane
    :param normal: Normal to slicing plane
    :param closest_region: Set to True to extract disjoint region closest to specified point
    :param crinkle_clip: Set to True to return mesh of same topological dimension as basemesh

    .. note::

        Only 3D-meshes currently supported for slicing.

    .. warning::

        Slice-instances are intended for visualization only, and may produce erronous
        results if used for computations.

    """
    assert basemesh.geometry().dim() == 3, "Can only slice 3D-meshes."

    P = np.array([point[0], point[1], point[2]], dtype=np.double)

    # Create unit normal
    n = np.array([normal[0],normal[1], normal[2]])
    n = n/np.linalg.norm(n)
    #self.n = Constant((n[0], n[1], n[2]))

    # Calculate the distribution of vertices around the plane
    # (sign of np.dot(p-P, n) determines which side of the plane p is on)
    vsplit = np.dot(basemesh.coordinates()-P, n)

    # Count each cells number of vertices on the "positive" side of the plane
    # Only cells with vertices on both sides of the plane intersect the plane
    operator = np.less
    npos = np.sum(vsplit[basemesh.cells()] < 0, 1)

    intersection_cells = basemesh.cells()[(npos > 0) & (npos < 4)]

    if len(intersection_cells) == 0:
        # Try to put "zeros" on other side of plane
        # FIXME: handle cells with vertices exactly intersecting the plane in a more robust manner.
        operator = np.greater
        npos = np.sum(vsplit[basemesh.cells()] > 0, 1)
        #cell_indices = (npos > 0) & (npos < 4)
        intersection_cells = basemesh.cells()[(npos > 0) & (npos < 4)]

    if crinkle_clip:
        cf = CellFunction("size_t", basemesh)
        cf.set_all(0)
        cf.array()[(npos>0) & (npos<4)] = 1
        mesh = create_submesh(basemesh, cf, 1)
    else:
        def add_cell(cells, cell):
            # Split cell into triangles
            for i in xrange(len(cell)-2):
                cells.append(cell[i:i+3])

        cells = []
        index = 0
        indexes = {}
        for c in intersection_cells:
            a = operator(vsplit[c], 0)
            positives = c[np.where(a==True)[0]]
            negatives = c[np.where(a==False)[0]]

            cell = []
            for pp_ind in positives:
                pp = basemesh.coordinates()[pp_ind]

                for pn_ind in negatives:
                    pn = basemesh.coordinates()[pn_ind]
                    if (pp_ind, pn_ind) not in indexes:
                        # Calculate intersection point with the plane
                        d = np.dot(P-pp, n)/np.dot(pp-pn, n)
                        ip = pp+(pp-pn)*d

                        indexes[(pp_ind, pn_ind)] = (index, ip)
                        index += 1

                    cell.append(indexes[(pp_ind, pn_ind)][0])


            add_cell(cells, cell)
        MPI.barrier(mpi_comm_world())

        # Assign global indices
        # TODO: Assign global indices properly
        dist = distribution(index)
        global_idx = sum(dist[:MPI.rank(mpi_comm_world())])
        vertices = {}
        for idx, p in indexes.values():
            vertices[idx] = (global_idx, p)
            global_idx += 1


        global_num_cells = MPI.sum(mpi_comm_world(), len(cells))
        global_num_vertices = MPI.sum(mpi_comm_world(), len(vertices))

        mesh = Mesh()

        # Return empty mesh if no intersections were found
        if global_num_cells == 0:
            mesh_editor = MeshEditor()
            mesh_editor.open(mesh, "triangle", 2, 3)

            mesh_editor.init_vertices(0)
            mesh_editor.init_cells(0)

            mesh_editor.close()
        else:

            # Distribute mesh if empty on any processors
            cells, vertices = distribute_meshdata(cells, vertices)

            # Build mesh
            mesh_editor = MeshEditor()
            mesh_editor.open(mesh, "triangle", 2, 3)

            mesh_editor.init_vertices(len(vertices))
            mesh_editor.init_cells(len(cells))

            for index, cell in enumerate(cells):
                mesh_editor.add_cell(index, cell[0], cell[1], cell[2])

            for local_index, (global_index, coordinates) in vertices.items():
                mesh_editor.add_vertex_global(int(local_index), int(global_index), coordinates)

            mesh_editor.close()
            mesh.topology().init(0, len(vertices), global_num_vertices)
            mesh.topology().init(2, len(cells), global_num_cells)


    if closest_region and mesh.size_global(0) > 0:
        assert MPI.size(mpi_comm_world())==1, "Extract closest region does not work in parallel"
        regions = compute_connectivity(mesh)
        i,d = mesh.bounding_box_tree().compute_closest_entity(Point(P))

        if d == MPI.min(mesh.mpi_comm(), d):
            v = regions[int(i)]
        else:
            v = 0

        v = MPI.max(mesh.mpi_comm(), v)
        mesh = create_submesh(mesh, regions, v)

    return mesh
示例#22
0
class FBVP:
    def __init__(self,
                 mesh_name,
                 parameters,
                 alpha_range=None,
                 beta_range=None):
        # DEFINE MESH AND PARAMETERS
        self.parameters = parameters
        self.mesh_name = mesh_name
        if not alpha_range:
            self.alpha_range = parameters.alpha_range
        else:
            self.alpha_range = alpha_range
        if not beta_range:
            self.beta_range = parameters.beta_range
        else:
            self.beta_range = alpha_range
        meshname = \
            f'meshes/{parameters.domain}/{parameters.domain}_{self.mesh_name}.xdmf'

        self.mesh = Mesh()
        with XDMFFile(meshname) as f:
            f.read(self.mesh)
        print(f'Mesh size= {self.mesh.hmax()}')
        # dimension of approximation space
        self.dim = len(self.mesh.coordinates())
        print(f'Dimension of solution space is {self.dim}')
        self.V = FunctionSpace(self.mesh, 'CG', 1)  # CG =  P1
        self.coords = self.mesh.coordinates()[dof_to_vertex_map(self.V)]
        # self.t_V = FunctionSpace(self.t_mesh, 'CG', 1)
        self.T = self.parameters.T  # final time
        self.w = TrialFunction(self.V)
        self.u = TestFunction(self.V)
        #######################################################################
        # CONTROL SET CREATION
        self.ctrset_alpha = np.linspace(self.alpha_range[0],
                                        self.alpha_range[1],
                                        parameters.alpha_size)
        self.ctrset_beta = np.linspace(self.beta_range[0], self.beta_range[1],
                                       parameters.beta_size)
        self.csize_alpha = len(self.ctrset_alpha)
        self.csize_beta = len(self.ctrset_beta)
        print(f'Discretized control set has size'
              f' {self.csize_alpha * self.csize_beta}')
        #######################################################################
        # BOUNDARY CONDITIONS
        parameters.set_boundary_conditions(self.mesh)
        self.boundary_markers = MeshFunction('size_t', self.mesh, 1)
        self.boundary_markers.set_all(99)  # pylint: disable=no-member

        for i, omega in self.parameters.omegas.items():
            omega.mark(self.boundary_markers, i)

        self.ds = Measure('ds',
                          domain=self.mesh,
                          subdomain_data=self.boundary_markers)

        self.dirichlet_bcs = [
            DirichletBC(self.V, parameters.RHS_bound[i], self.boundary_markers,
                        i) for i in parameters.omegas
        ]

        # Get indices of dirichlet and dofs
        self.boundary_nodes_list = \
            DirichletBC(self.V, Constant('0.0'),
                        'on_boundary').get_boundary_values().keys()
        #######################################################################
        # ASSEMBLY
        time_start = time.process_time()
        self.assemble_diagonal_matrix()  # auxilliary generic diagonal matrix
        # used for vector*matrix multiplication of dolfin matrices
        self.assemble_lumpedmm()  # assembly lumped mass matrix
        # which serves the role of identity operator
        self.assemble_laplacian()  # assembly of discrete laplacian

        self.ad_data_path = f'out/{parameters.experiment}'
        Path(self.ad_data_path).mkdir(parents=True, exist_ok=True)

        # FIXME: value of timestep required to impose monotonity may be
        # different at different times, at this moment code assumes that
        # it won't be smaller than in case t=T
        self.timesteps = parameters.get_number_of_timesteps()
        self.assemble_HJBe()  # assembly of explicit operators
        self.assemble_HJBi()  # assembly of implicit operators
        self.assemble_RHS()  # assembly of forcing term

        print('Final time assembly complete')
        print(f'Assembly took {time.process_time() - time_start} seconds')
        print('===========================================================')

    def assemble_diagonal_matrix(self):
        print("Assembling auxilliary diagonal matrix")
        """ Operator assembled to get the right sparsity pattern
            (non-zero terms can only exist on diagonal)
            """
        mesh3 = UnitIntervalMesh(self.dim)
        V3 = FunctionSpace(mesh3, "DG", 0)
        wid = TrialFunction(V3)
        uid = TestFunction(V3)
        self.diag_matrix = assemble(uid * wid * dx)
        self.diag_matrix.zero()

    def assemble_lumpedmm(self):
        """ Assembly lumped mass matrix - plays role of identity matrix
        """
        print("Assembling lumped mass matrix")
        mass_form = self.w * self.u * dx
        self.mass_matrix = assemble(mass_form)

        mass_action_form = action(mass_form, Constant(1))
        self.MM_terms = assemble(mass_action_form)

        self.mass_matrix.zero()
        self.mass_matrix.set_diagonal(self.MM_terms)
        self.scipy_mass_matrix = toscipy(self.mass_matrix)

    def assemble_laplacian(self):
        print("Assembling laplacians")
        # laplacian discretisation
        self.laplacian = assemble(dot(grad(self.w), grad(self.u)) * dx)

    def assemble_HJBe(self, t=None):
        """ Assembly explicit operator for every control in the control set,
        then apply artificial diffusion to all of them. Note that artificial
        diffusion is calculated differently on the boundary nodes.
        """
        self.explicit_matrices = np.empty([self.csize_beta, self.csize_alpha],
                                          dtype=object)
        self.explicit_diffusion = np.empty([self.csize_beta, self.csize_alpha],
                                           dtype=object)
        diag_vector = Vector(self.mesh.mpi_comm(), self.dim)
        global_min_timestep = float('inf')
        # Create explicit operator for each control in control set
        for ind_a, a in enumerate(self.ctrset_alpha):
            for ind_b, b in enumerate(self.ctrset_beta):
                if (ind_a * self.csize_beta + ind_b) % 10 == 0:
                    print(f'Assembling explicit matrix under control '
                          f'{ind_a*self.csize_beta + ind_b} out of '
                          f'{self.csize_alpha*self.csize_beta}')
                # coefficients in the interior
                advection_x = self.parameters.adv_x(a, b)
                advection_y = self.parameters.adv_y(a, b)
                reaction = self.parameters.lin(a, b)

                if t is not None:
                    advection_x.t = t
                    advection_y.t = t
                    reaction.t = t

                # Discretize PDE (set values on boundary rows to zero)
                b = np.array([advection_x, advection_y])
                E_int_form = (np.dot(b, grad(self.w)) +
                              reaction * self.w) * self.u * dx
                explicit_matrix = assemble(E_int_form)

                # Calculate nodewise minimum diffusion required to
                # impose monotonicity
                min_diffusion = [0] * explicit_matrix.size(0)
                for rows, row_num in getrows(explicit_matrix,
                                             self.laplacian,
                                             ignore=self.boundary_nodes_list):
                    min_diffusion[row_num] = calc_ad(rows, row_num)
                self.explicit_diffusion[ind_b][ind_a] = min_diffusion

                diffusion_matrix = apply_ad(self.laplacian, min_diffusion)
                explicit_matrix += diffusion_matrix

                explicit_matrix.get_diagonal(diag_vector)
                current_min_timestep = get_min_timestep(
                    diag_vector, self.MM_terms, self.boundary_nodes_list)

                global_min_timestep = min(current_min_timestep,
                                          global_min_timestep)
                self.explicit_matrices[ind_b][ind_a] = toscipy(explicit_matrix)

        #######################################################################
        min_timesteps = int(self.T / global_min_timestep) + 1
        if not self.timesteps or self.timesteps < min_timesteps:
            self.timesteps = min_timesteps
            try:
                filename = (f'meshes/{self.parameters.domain}/'
                            f'Mvalues-{self.parameters.experiment}.json')
                with open(filename, 'r') as f:
                    min_timesteps_dict = json.load(f)
            except FileNotFoundError:
                min_timesteps_dict = {}
            min_timesteps_dict[self.parameters.mesh_name] = self.timesteps
            with open(filename, 'w') as f:
                json.dump(min_timesteps_dict, f)

        self.timestep_size = self.T / self.timesteps  # time step size
        self.parameters.calculate_save_interval()
        self.explicit_matrices = [[
            self.timestep_size * E - self.scipy_mass_matrix for E in Elist
        ] for Elist in self.explicit_matrices]

        print('Checking if the explicit operators satisfy'
              ' monotonicity conditions')
        for matrix_list in self.explicit_matrices:
            for matrix in matrix_list:
                explicit_check(matrix, self.boundary_nodes_list)

    def assemble_RHS(self, t=None):
        """Assemble right hand side of the FBVP
        """
        print('Assembling RHS')
        self.forcing_terms = np.empty(
            [self.csize_beta, self.csize_alpha, self.dim])
        for ind_a, alpha in enumerate(self.ctrset_alpha):
            for ind_b, beta in enumerate(self.ctrset_beta):
                rhs = self.parameters.RHSt(alpha, beta)
                if t is not None:
                    rhs.t = t
                # Initialise forcing term
                F = np.array(assemble(rhs * self.u * dx)[:])
                self.forcing_terms[ind_b][ind_a] = self.timestep_size * F

    def assemble_HJBi(self, t=None):
        """ Assembly matrix discretizing second order terms after diffusion
        moved to the explicit operator is subtracted. Whenever amount of
        diffusion used to make some row of an explicit operator monotonic
        exceeds the amount of natural diffusion at that node we call it
        artificial diffusion. In such case, this row of the implicit operator
        is multiplied by zero
        """
        print('Assembling implicit operators')
        self.implicit_matrices = np.empty([self.csize_beta, self.csize_alpha],
                                          dtype=object)
        remaining_diffusion = Function(self.V)
        max_art_dif = 0.0
        max_art_dif_loc = None
        diffusion_matrix = self.diag_matrix.copy()
        for ind_a, alpha in enumerate(self.ctrset_alpha):
            for ind_b, beta in enumerate(self.ctrset_beta):
                # TODO: Include assert making sure that diffusion is
                #  non-negative on all of the internal nodes
                diffusion = self.parameters.diffusion(alpha, beta)
                if t is not None:
                    diffusion.t = t
                diff = interpolate(diffusion, self.V).vector()
                if not np.all(diff >= 0):
                    raise Exception("Choose non-negative diffusion")

                diff_vec = np.array([
                    diff[i] if i not in self.boundary_nodes_list else 0.0
                    for i in range(self.dim)
                ])

                artdif = self.explicit_diffusion[ind_b][ind_a] - diff_vec
                if np.amax(artdif) > max_art_dif:
                    max_art_dif = np.amax(artdif)
                    max_art_dif_loc = self.coords[np.argmax(artdif)]

                # discretise second order terms
                remaining_diffusion.vector()[:] = np.maximum(
                    -artdif, [0] * self.dim)
                diffusion_matrix.set_diagonal(remaining_diffusion.vector())

                Iab = matmult(diffusion_matrix, self.laplacian)
                self.implicit_matrices[ind_b][ind_a] = self.timestep_size * \
                    Iab + self.mass_matrix

        self.scipy_implicit_matrices = [[toscipy(mat) for mat in Ialist]
                                        for Ialist in self.implicit_matrices]
        print('Checking if the implicit operators satisfy'
              ' monotonicity conditions')
        for matrix_list in self.scipy_implicit_matrices:
            for matrix in matrix_list:
                implicit_check(matrix)

        with open(self.ad_data_path + '/ad.txt', 'a') as f:
            time_str = f' at time {t}\n' if t is not None else '\n'
            f.write(f'For mesh {self.mesh_name} max value of artificial'
                    ' diffusion coefficient was'
                    f' {max_art_dif} at {max_art_dif_loc}' + time_str)
    def __init__(
        self,
        time: df.Constant,
        mesh: df.Mesh,
        conductivity: Dict[int, df.Expression],
        conductivity_ratio: Dict[int, df.Expression],
        cell_function: df.MeshFunction,
        cell_tags: CellTags,
        interface_function: df.MeshFunction,
        interface_tags: InterfaceTags,
        parameters: CoupledMonodomainParameters,
        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._conductivity = conductivity
        self._cell_function = cell_function
        self._cell_tags = cell_tags
        self._interface_function = interface_function
        self._interface_tags = interface_tags
        self._parameters = parameters

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

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

        self._chi_cm = df.Constant(surface_to_volume_factor) * df.Constant(
            membrane_capacitance)

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

        if not set(conductivity.keys()) == set(conductivity_ratio.keys()):
            raise ValueError(
                "intracellular conductivity and lambda does not have natching keys."
            )
        self._lambda = conductivity_ratio

        # Function spaces
        self._function_space = df.FunctionSpace(mesh, "CG", 1)

        # Test and trial and previous functions
        self._v_trial = df.TrialFunction(self._function_space)
        self._v_test = df.TestFunction(self._function_space)

        self._v = df.Function(self._function_space)
        if v_prev is None:
            self._v_prev = df.Function(self._function_space)
        else:
            # v_prev is shipped from an odesolver.
            self._v_prev = v_prev

        _cell_tags = set(self._cell_tags)
        _cell_function_values = set(self._cell_function.array())
        if not _cell_tags <= _cell_function_values.union({None}):
            msg = f"Cell function does not contain {_cell_tags - _cell_function_values}"
            raise ValueError(msg)

        _interface_tags = set(self._interface_tags)
        _interface_function_values = {
            *set(self._interface_function.array()), None
        }
        if not _interface_tags <= _interface_function_values.union({None}):
            msg = f"interface function does not contain {_interface_tags - _interface_function_values}."
            raise ValueError(msg)

        # Crete integration measures -- Interfaces
        self._dGamma = df.Measure("ds",
                                  domain=self._mesh,
                                  subdomain_data=self._interface_function)

        # Crete integration measures -- Cells
        self._dOmega = df.Measure("dx",
                                  domain=self._mesh,
                                  subdomain_data=self._cell_function)

        # Create variational forms
        self._timestep = df.Constant(self._parameters.timestep)
        self._lhs, self._rhs = self._variational_forms()

        # Preassemble left-hand side (will be updated if time-step changes)
        self._lhs_matrix = df.assemble(self._lhs)
        self._rhs_vector = df.Vector(mesh.mpi_comm(), self._lhs_matrix.size(0))
        self._lhs_matrix.init_vector(self._rhs_vector, 0)

        self._linear_solver = create_linear_solver(self._lhs_matrix,
                                                   self._parameters)
# Timestepping
Tend = 2.
dt = Constant(0.02)
num_steps = np.rint(Tend / float(dt))

# Output directory
store_step = 1
outdir = './../../results/SlottedDisk_Rotation_AddDelete/'

# Mesh
mesh = Mesh('./../../meshes/circle_0.xml')
mesh = refine(mesh)
mesh = refine(mesh)
mesh = refine(mesh)

outfile = XDMFFile(mesh.mpi_comm(), outdir + "psi_h.xdmf")

# Set slotted disk
psi0_expr = SlottedDisk(radius=rdisk,
                        center=[xc, yc],
                        width=rwidth,
                        depth=0.,
                        degree=3,
                        lb=lb,
                        ub=ub)

# Function space and velocity field
W = FunctionSpace(mesh, 'DG', k)
psi_h = Function(W)

V = VectorFunctionSpace(mesh, 'DG', 3)
示例#25
0
文件: ldrb.py 项目: finsberg/ldrb
def scalar_laplacians(
    mesh: df.Mesh,
    markers: Optional[Dict[str, int]] = None,
    ffun: Optional[MeshFunction] = None,
    use_krylov_solver: bool = False,
    krylov_solver_atol: Optional[float] = None,
    krylov_solver_rtol: Optional[float] = None,
    krylov_solver_max_its: Optional[int] = None,
    verbose: bool = False,
    strict: bool = False,
) -> Dict[str, df.Function]:
    """
    Calculate the laplacians

    Arguments
    ---------
    mesh : dolfin.Mesh
       A dolfin mesh
    markers : dict (optional)
        A dictionary with the markers for the
        different bondaries defined in the facet function
        or within the mesh itself.
        The follwing markers must be provided:
        'base', 'lv', 'epi, 'rv' (optional).
        If the markers are not provided the following default
        vales will be used: base = 10, rv = 20, lv = 30, epi = 40.
    fiber_space : str
        A string on the form {familiy}_{degree} which
        determines for what space the fibers should be calculated for.
    use_krylov_solver: bool
        If True use Krylov solver, by default False
    krylov_solver_atol: float (optional)
        If a Krylov solver is used, this option specifies a
        convergence criterion in terms of the absolute
        residual. Default: 1e-15.
    krylov_solver_rtol: float (optional)
        If a Krylov solver is used, this option specifies a
        convergence criterion in terms of the relative
        residual. Default: 1e-10.
    krylov_solver_max_its: int (optional)
        If a Krylov solver is used, this option specifies the
        maximum number of iterations to perform. Default: 10000.
    verbose: bool
        If true, print more info, by default False
    strict: bool
        If true raise RuntimeError if solutions does not sum to 1.0
    """

    if not isinstance(mesh, df.Mesh):
        raise TypeError("Expected a dolfin.Mesh as the mesh argument.")

    # Init connectivities
    mesh.init(2)
    if ffun is None:
        ffun = df.MeshFunction("size_t", mesh, 2, mesh.domains())

    # Boundary markers, solutions and cases
    cases, boundaries, markers = find_cases_and_boundaries(ffun, markers)
    markers_str = "\n".join(
        ["{}: {}".format(k, v) for k, v in markers.items()])
    df.info(("Compute scalar laplacian solutions with the markers: \n"
             "{}").format(markers_str, ), )

    check_boundaries_are_marked(
        mesh=mesh,
        ffun=ffun,
        markers=markers,
        boundaries=boundaries,
    )

    # Compte the apex to base solutons
    num_vertices = mesh.num_vertices()
    num_cells = mesh.num_cells()
    if mesh.mpi_comm().size > 1:
        num_vertices = mesh.mpi_comm().allreduce(num_vertices)
        num_cells = mesh.mpi_comm().allreduce(num_cells)
    df.info("  Num vertices: {0}".format(num_vertices))
    df.info("  Num cells: {0}".format(num_cells))

    if "mv" in cases and "av" in cases:
        # Use Doste approach
        pass

    # Else use the Bayer approach
    return bayer(
        cases=cases,
        mesh=mesh,
        markers=markers,
        ffun=ffun,
        verbose=verbose,
        use_krylov_solver=use_krylov_solver,
        strict=strict,
        krylov_solver_atol=krylov_solver_atol,
        krylov_solver_rtol=krylov_solver_rtol,
        krylov_solver_max_its=krylov_solver_max_its,
    )