Skip to content
Snippets Groups Projects
Select Git revision
  • 7a253fb2828ed7d5945896977a95b3245c3f729c
  • master default protected
  • parallelistation_of_subdomain_loop
  • parallelistation_test
  • nonzero_gli_term_for_nonwetting_in_TPR
  • testing_updating_pwi_as_pwiminus1_into_calculation_of_pnwi
  • v2.2
  • v2.1
  • v2.0
  • v1.0
10 results

boundary_and_interface.py

Blame
  • LDDsimulation.py 13.98 KiB
    """
    LDD simulation class
    """
    
    import os
    import dolfin as df
    import numpy as np
    import typing as tp
    import mshr
    import domainPatch as dp
    import helpers as hlp
    
    class LDDsimulation(object):
        """ Main Class of LDD simulation
    
        LDDsimulation is the main class for the LDD simulation. It contains methods for
        setting up and running the LDD simulation for different meshes and domains.
        """
    
        def __init__(self, dimension: int = 2,#
                     tol: float = None):
    
            hlp.print_once("Init LDD simulation...")
            # parameter as set in NSAC_simulation by  Lukas Ostrowski
            hlp.print_once("Set internal fenics parameter...")
            # calculation exactness for the whole simulation.
            if tol:
                self.tol = tol
            else:
                self.tol = df.DOLFIN_EPS
            # dimension of the simulation. This is by default 2 as I don't intend
            # to implement 3D.
            self.dim = dimension
            #Parameters
            # df.parameters["allow_extrapolation"] = True
            # df.parameters["refinement_algorithm"] = "plaza_with_parent_facets"
            df.parameters["form_compiler"]["quadrature_degree"] = 10
            # # To be able to run DG in parallel
            # df.parameters["ghost_mode"] = "shared_facet"
            # Form compiler options
            df.parameters["form_compiler"]["optimize"] = True
            df.parameters["form_compiler"]["cpp_optimize"] = True
            # df.parameters['std_out_all_processes'] = False
    
            df.set_log_level(df.LogLevel.PROGRESS)
            # df.set_log_level(df.LogLevel.INFO)
    
            # CRITICAL  = 50, // errors that may lead to data corruption and suchlike
            # ERROR     = 40, // things that go boom
            # WARNING   = 30, // things that may go boom later
            # INFO      = 20, // information of general interest
            # PROGRESS  = 16, // what's happening (broadly)
            # TRACE     = 13, // what's happening (in detail)
            # DBG       = 10  // sundry
    
            hlp.print_once("Set default parameter...")
            self.restart_file = None
            # # write checkpoints
            # self.write_checkpoints = True
            # # dont project solution to CG for visualization
            # self.project_to_cg = False
            # # no sponge zones
            # self.sponge = False
    
            ## Public variables.
            # directory to write files output to.
            self.output_dir = None
            # list of subdomain meshes. Is populated by self.init_meshes_and_markers()
            self.mesh_subdomain = []
            # global marker for subdomains and interfaces. Is set by self.init_meshes_and_markers()
            self.domain_marker  = None
            # List of interfaces of class Interface. This is populated by self.init_interfaces
            self.interface = []
            # The global interface marker. Gets initialised by self.init_interfaces().
            self.interface_marker = None
            # List of list of indices indicating subdomains adjacent to interfaces.
            # self.adjacent_subdomains[i] gives the two indices of subdomains which
            # are share the interface self.interface[i]. This gets populated by
            # self.init_interfaces()
            self.adjacent_subdomains = None
    
            ## Private variables
            # The number of subdomains are counted by self.init_meshes_and_markers()
            self._number_of_subdomains = 0
            # variable to check if self.set_parameters() has been called
            self._parameters_set = False
            # list of objects of class DomainPatch initialised by self._init_subdomains()
            self.subdomain = []
    
        def set_parameters(self,#
                           output_dir: str,#
                           subdomain_def_points: tp.List[tp.List[df.Point]],#
                           is_Richards: bool,#
                           interface_def_points: tp.List[tp.List[df.Point]],#
                           adjacent_subdomains: tp.List[np.ndarray],#
                           mesh_resolution: float,#
                           viscosity: tp.Dict[int, tp.List[float]],#
                           porosity: tp.Dict[int, float],#
                           L: tp.Dict[int, tp.List[float]],#
                           lambda_param: tp.Dict[int, tp.List[float]],#
                           relative_permeability: tp.Dict[int, tp.Callable[...,None]])-> None:
            """ set parameters of an instance of class LDDsimulation"""
            self.output_dir = output_dir
            self.subdomain_def_points = subdomain_def_points
            self.is_Richards = is_Richards
            self.mesh_resolution = mesh_resolution
            self.interface_def_points = interface_def_points
            self.adjacent_subdomains = adjacent_subdomains
            self.viscosity = viscosity
            self.porosity = porosity
            self.L = L
            self.lambda_param = lambda_param
            self.relative_permeability = relative_permeability
            self._parameters_set = True
    
        def initialise(self) -> None:
            """ initialise LDD simulation
    
            Public method to call all the init methods of the LDD simulation.
            """
            if not self._parameters_set:
                raise RuntimeError('Parameters note set!\nYou forgott to run self.set_parameters(**kwds)')
            self._init_meshes_and_markers()
            self._init_interfaces()
            self._init_subdomains()
    
    
        ## Private methods
        def _init_meshes_and_markers(self, subdomain_def_points: tp.List[tp.List[df.Point]] = None,#
                                    mesh_resolution: float = None) -> None:
            """ Generate meshes and markerfunctions for sudomains.
    
            This method generate meshes and markerfunctions for sudomains and
            sets the internal lists of meshes used by the LDDsimulation class.
            The following lists and variables are set:
    
            self.mesh_subdomain:        List of subdomain meshes. self.mesh_subdomain[0]
                                        is the whole simulation domain, self.mesh_subdomain[i]
                                        is the submesh of subdomain i.
            self.domain_marker:         Global marker function on self.mesh_subdomain[0]
                                        marking the subdomains by their respective number.
            self._number_of_subdomains  Internal variable holding the total number of
                                        actual subdomains (global domain not counted).
    
            The method is intended to be used by the self.initialise() method to set
            up the simulation but also accepts needed input parameters explicitly for
            greater debugging felxibility.
    
            # Parameters
            subdomain_def_points #type:  tp.List[tp.List[df.Point]]  The sub-
                                        domains are passed as list of lists of dolfin
                                        points forming the polygonal boundary of the
                                        subdomains. subdomain_def_points[0] is
                                        to contain the boundary polygon of the whole
                                        domain omega, whereas subdomain_def_points[i]
                                        is supposed to contain the boundary polygone
                                        of subdomain i.
            mesh_resolution             #type   float   positive number used by the
                                        mshr mesh generator to influence how coarse
                                        the mesh is. The higher the number, the finer
                                        the mesh.
            """
            if not subdomain_def_points:
                subdomain_def_points = self.subdomain_def_points
    
            if not mesh_resolution:
                mesh_resolution = self.mesh_resolution
            ### generate global mesh and subdomain meshes. Also count number of subdomains.
            # define the global simulation domain polygon first.
            domain = mshr.Polygon(subdomain_def_points[0])
            for num, subdomain_vertices in enumerate(subdomain_def_points[1:], 1):
                subdomain = mshr.Polygon(subdomain_vertices)
                domain.set_subdomain(num, subdomain)
                # count number of subdomains for further for loops
                self._number_of_subdomains = num
    
            # create global mesh. Submeshes still need to be extracted.
            mesh = mshr.generate_mesh(domain, mesh_resolution)
            self.mesh_subdomain.append(mesh)
            # define domainmarker on global mesh and set marker values to domain
            # number as assigned in the above for loop.
            self.domain_marker = df.MeshFunction('size_t', mesh, mesh.topology().dim(), mesh.domains())
            # extract subdomain meshes
            for num in range(1, self._number_of_subdomains+1):
                self.mesh_subdomain.append(df.SubMesh(mesh, self.domain_marker, num))
    
    
        def _init_interfaces(self, interface_def_points: tp.List[tp.List[df.Point]] = None,#
                                  adjacent_subdomains: tp.List[np.ndarray] = None) -> None:
            """ generate interfaces and interface markerfunctions for sudomains and
                set the internal lists used by the LDDsimulation class.
    
            This initialises a list of interfaces and global interface marker functions
            used by the LDDsimulation class.
            The following lists and variables are set:
    
            self.interface_marker       global interface marker
            self.interface              list containing interface objectso of class
                                        Interface.
    
            The method is intended to be used internally by the self.initialise()
            method to set up the simulation but also accepts needed input parameters
            explicitly for greater debugging felxibility. In case input parameters
            are provided, they override the ones set by self.initialise().
    
            # Parameters
            interface_def_points          #type:  tp.List[tp.List[df.Point]]  list of
                                        lists of dolfin points containing the internal
                                        interfaces dividing the domain omega into subdomains.
                                        the indices of this list introduce a numbering
                                        of the interfaces which will determin the list
                                        of neighbours attached to each subdomain.
            adjacent_subdomains         #type:  tp.List[tp.array[int]]  List of
                                        list of indices such that adjacent_subdomains[i]
                                        gives the indices of the subdomains that share
                                        the interface defined by the dolfin points in
                                        interface_def_points
            """
            if not interface_def_points:
                interface_def_points = self.interface_def_points
            else:
                # overwrite what has been set by init()
                self.adjacent_subdomains = adjacent_subdomains
            if not adjacent_subdomains:
                adjacent_subdomains = self.adjacent_subdomains
            else:
                # overwrite what has been set by init()
                self.adjacent_subdomains = adjacent_subdomains
    
            mesh = self.mesh_subdomain[0]
    
            # define global interface marker. This is a mesh function on edges of the mesh.
            self.interface_marker = df.MeshFunction('size_t', mesh, mesh.topology().dim()-1)
            self.interface_marker.set_all(0)
            for num, vertices in enumerate(interface_def_points):
                self.interface.append(dp.Interface(vertices=vertices, #
                                                    tol=mesh.hmin()/100,#
                                                    internal=True,#
                                                    adjacent_subdomains = adjacent_subdomains[num]))#
                # the marking number of each interface corresponds to the mathematical
                # numbering of the interfaces (starting with 1 not 0 for the first interface).
                # The reason is that we want to mark outer boundaries with the value 0.
                self.interface[num].mark(self.interface_marker, num+1)
                self.interface[num].init_interface_values(self.interface_marker, num+1)
    
        def _init_subdomains(self) -> None:
            """ generate list of opjects of class DomainPatch.
            """
            is_richards = self.is_Richards
    
            # The list is_richards has the same length as the nuber of subdomains.
            # Therefor it is used in the subdomain initialisation loop.
            for subdom_num, isR in enumerate(is_richards, 1):
                interface_list = self._get_interfaces(subdom_num)
                self.subdomain.append(dp.DomainPatch(#
                        isRichards = isR,#
                        mesh = self.mesh_subdomain[subdom_num],#
                        viscosity = self.viscosity[subdom_num],#
                        porosity = self.porosity[subdom_num],#
                        interfaces = self.interface,#
                        has_interface = interface_list,#
                        L = self.L[subdom_num],#
                        lambda_param = self.lambda_param[subdom_num],#
                        relative_permeability = self.relative_permeability[subdom_num]#
                        ))
    
    
    
        def _get_interfaces(self, subdomain_index: int, #
                            adjacent_subdomains: tp.List[np.ndarray] = None) -> np.ndarray:
            """ determin all (global) indices of interfaces belonging to subdomain
                with index subdomain_index.
    
            This method determins all (global) indices of interfaces belonging to
            subdomain with index subdomain_index from adjacent_subdomains.
            """
            if not adjacent_subdomains:
                adjacent_subdomains = self.adjacent_subdomains
            else:
                # overwrite what has been set by init()
                self.adjacent_subdomains = adjacent_subdomains
            interface_of_subdomain =[]
            for interface_ind, adj_doms in enumerate(adjacent_subdomains):
                # interface [i,j] and [j,i] are not counted seperately in adjacent_subdomains
                # therefor we don't care wether subdomain_index == adj_doms[0] or
                # subdomain_index == adj_doms[1]. if subdomain_index is one of either,
                # the interface belongs to the subdomain with this index.
                if np.isin(subdomain_index, adj_doms, assume_unique=True):
                    interface_of_subdomain.append(interface_ind)
    
            return interface_of_subdomain