From 48b646f1aa95333f8128852ba8d77ff673b6073d Mon Sep 17 00:00:00 2001
From: David Seus <david.seus@ians.uni-stuttgart.de>
Date: Fri, 14 Jun 2019 19:02:42 +0200
Subject: [PATCH] rewrite calc_gli_term

---
 LDDsimulation/boundary_and_interface.py |   4 +
 LDDsimulation/domainPatch.py            | 339 ++++++++----------------
 2 files changed, 110 insertions(+), 233 deletions(-)

diff --git a/LDDsimulation/boundary_and_interface.py b/LDDsimulation/boundary_and_interface.py
index eb5033a..9d3a9f3 100644
--- a/LDDsimulation/boundary_and_interface.py
+++ b/LDDsimulation/boundary_and_interface.py
@@ -241,6 +241,8 @@ class Interface(BoundaryPart):
         # global index ob the subdomain
         self.global_index = global_index
         self.marker_value = self.global_index+1
+        # dictionary holding the facet objects
+        self.facets = dict()
         # dictionary containing for each facet belonging to the interface (with
         # respect to a subdomain mesh) the coordinates of the the vertices
         # belonging to that facet. This dictionary is created by
@@ -420,6 +422,7 @@ class Interface(BoundaryPart):
         """
         self.facet_to_vertex_coordinates.update({subdomain_index: dict()})
         self.outer_normals.update({subdomain_index: dict()})
+        self.facets.update({subdomain_index: dict()})
         # Get a subset iterator for mesh entities along the facets marked by
         # interface_marker and value interface_marker_value.
         mesh_entity_iterator = df.SubsetIterator(interface_marker, interface_marker_value)
@@ -442,6 +445,7 @@ class Interface(BoundaryPart):
             self.facet_to_vertex_coordinates[subdomain_index].update(
                 {facet.index(): facet_vertices}
             )
+            self.facets[subdomain_index].update({facet.index(): facet})
             if subdomain_index == 0:
                 self.outer_normals[subdomain_index].update(
                     {facet.index(): None}
diff --git a/LDDsimulation/domainPatch.py b/LDDsimulation/domainPatch.py
index bbf83b8..07f5f0e 100644
--- a/LDDsimulation/domainPatch.py
+++ b/LDDsimulation/domainPatch.py
@@ -452,7 +452,6 @@ class DomainPatch(df.SubDomain):
                         # the wetting phase is always present and we always need
                         # to calculate a gl0 term.
                         # TODO: add intrinsic permeabilty!!!!
-                        # TODO: add gravity term!!!!!
                         if self.include_gravity:
                             # z_a included the minus sign already, see self._calc_gravity_expressions
                             flux = -1/mu_a*ka(S(pc_prev))*df.grad(pa_prev + z_a)
@@ -465,202 +464,53 @@ class DomainPatch(df.SubDomain):
                             flux = -1/mu_a*ka(1-S(pc_prev))*df.grad(pa_prev + z_a)
                         else:
                             flux = -1/mu_a*ka(1-S(pc_prev))*df.grad(pa_prev)
-                    # we need to treat the flux part of gl0 and the robin (pressure)
-                    # part of gl0 seperately at the intersection points of two
-                    # interfaces (more details in comment below). Therefor we save
-                    # the robin pressure part and the neumann flux part separately
                     robin_pressure = Lambda[phase]*pa_prev.vector() #.vector()
-
                     flux_function = df.project(flux, self.function_space["flux"][phase])
                     flux_x, flux_y = flux_function.split()
-                    flux_x_coeficients = flux_x.vector()
-                    flux_y_coeficients = flux_y.vector()
-                    # print(f"flux_x coefficients: ", flux_x_coef[:])
-                    flux_x_dof_map =  flux_x.function_space().dofmap()
-                    flux_y_dof_map =  flux_y.function_space().dofmap()
-                    flux_dofmap = self.dofmap["flux"][phase]
-                    # flux_dofmap1 = flux_dofmap[0]
-                    # flux_dofmap2 = flux_dofmap[0]
-
-                    gli_dofmap = self.dofmap["gli"][phase]
                     gl0 = df.Function(self.function_space["gli"][phase])
 
-                    boundary_facets_and_cells = dict()
-                    interface_entity_iterator = df.SubsetIterator(self.interface_marker, interface.marker_value)
-                    for mesh_entity in interface_entity_iterator:
-                        # facet_index = mesh_entity.global_index()
-                        # global_facet_index = mesh_entity.global_index()
-                        # print(f"facet_index = {facet_index}\n",
-                        #     f"global_facet_index = {global_facet_index}\n")
-                        for f in df.facets(mesh_entity):
-                            facet = f
-                            # facet_index = f.global_index()
-                            # global_facet_index = f.global_index()
-                            # print(f"facet_index = {facet_index}\n",
-                            #     f"global_facet_index = {global_facet_index}\n")
-
-                        facet_cell_iterator = df.cells(facet)
-                        # only one cell of the mesh contains facet, but we still
-                        # have to loop, because df.cells(facet) returns an iterator
-                        # for cells.
-                        for facet_cell in facet_cell_iterator:
-                            boundary_facets_and_cells.update({facet: facet_cell})
-                    # for facet in df.facets(self.mesh):
-                    #     if facet.exterior():
-                    #         boundary_facets.update({facet: facet.normal()})
-
-                    flux_x_element = flux_x.function_space().element()
-                    flux_y_element = flux_y.function_space().element()
-                    gli_element = gl0.function_space().element()
-                    p_element = self.function_space["pressure"][phase].element()
-                    for facet, facet_cell in boundary_facets_and_cells.items():
-                        facet_cell_index = facet_cell.index()
-                        facet_index = facet.index()
-                        global_facet_cell_index = facet_cell.global_index()
-
-                        print(f"facet_cell_index = {facet_cell_index}\n",
-                              f"global_facet_cell_index = {global_facet_cell_index}")
-                        # since the flux is constant on each cell, we can take no
-                        # matter which dof to calculate F*n.
-                        n = facet.normal()[:]
-                        print(flux_x_element.tabulate_dof_coordinates(facet_cell))
-                        flux_x_facet_cell_dof_coordinates = flux_x_element.tabulate_dof_coordinates(facet_cell)
-                        flux_y_facet_cell_dof_coordinates = flux_y_element.tabulate_dof_coordinates(facet_cell)
-                        gli_facet_cell_dof_coordinates = gli_element.tabulate_dof_coordinates(facet_cell)
-                        p_facet_cell_dof_coordinates = p_element.tabulate_dof_coordinates(facet_cell)
-
-                        gli_cell_dofmap = gli_dofmap.cell_dofs(facet_cell_index)
-                        flux_x_cell_dofmap = flux_x_dof_map.cell_dofs(facet_cell_index)
-                        flux_dofmap1_cell = flux_dofmap.cell_dofs(facet_cell_index)
-
-                        flux_y_cell_dofmap = flux_y_dof_map.cell_dofs(facet_cell_index)
-                        print("flux_dofmap: ", flux_dofmap1_cell)
-                        print("flux_x_dofmap: ", flux_x_cell_dofmap)
-                        print("flux_y_dofmap: ", flux_y_cell_dofmap)
-                        p_cell_dofmap = p_dofmap.cell_dofs(facet_cell_index)
-                        print(f"gli_cell_dofmap = {gli_cell_dofmap}")
-
-                        facet_vertex_coordinates = []
-                        for vertex in df.vertices(facet):
-                            # we don't need the 3d coordinates only x and y.
-                            vertex_coord = vertex.point()[:][0:2]
-                            facet_vertex_coordinates.append(vertex_coord)
-                            print(f"type of vertex.point()[:]", type(vertex_coord))
-                            print('vertex is on interface:', interface._is_on_boundary_part(vertex_coord))
-                            print(vertex_coord)
-
-                        p_dofs_along_facet = dict()
-                        for local_dof_ind, dof_coord in enumerate(p_facet_cell_dof_coordinates):
-                            if interface._is_on_boundary_part(dof_coord):
-                                p_dofs_along_facet.update({local_dof_ind: dof_coord})
-                                print(p_dofs_along_facet.items())
-
-                        flux_x_dofs_along_facet = dict()
-                        for local_dof_ind, dof_coord in enumerate(flux_x_facet_cell_dof_coordinates):
-                            if interface._is_on_boundary_part(dof_coord):
-                                flux_x_dofs_along_facet.update({local_dof_ind: dof_coord})
-                                print(flux_x_dofs_along_facet.items())
-
-                        flux_y_dofs_along_facet = dict()
-                        for local_dof_ind, dof_coord in enumerate(flux_y_facet_cell_dof_coordinates):
-                            if interface._is_on_boundary_part(dof_coord):
-                                flux_y_dofs_along_facet.update({local_dof_ind: dof_coord})
-                                print(flux_y_dofs_along_facet.items())
-
-                        gli_dofs_along_facet = dict()
-                        for local_dof_ind, dof_coord in enumerate(gli_facet_cell_dof_coordinates):
-                            if interface._is_on_boundary_part(dof_coord):
-                                gli_dofs_along_facet.update({local_dof_ind: dof_coord})
-                                print(gli_dofs_along_facet.items())
-
-                        for local_dof_ind, gli_dof_coord in gli_dofs_along_facet.items():
-                            flux_x_dof_ind = -1
-                            for local_ind, coord in flux_x_dofs_along_facet.items():
-                                if np.array_equal(coord, gli_dof_coord):
-                                    flux_x_dof_ind = flux_x_cell_dofmap[local_ind]
-
-                            flux_y_dof_ind = -1
-                            for local_ind, coord in flux_y_dofs_along_facet.items():
-                                if np.array_equal(coord, gli_dof_coord):
-                                    flux_y_dof_ind = flux_y_cell_dofmap[local_ind]
-
-                            p_dof_ind = -1
-                            for local_ind, coord in p_dofs_along_facet.items():
-                                if np.array_equal(coord, gli_dof_coord):
-                                    p_dof_ind = p_cell_dofmap[local_ind]
-
-
-                            print(f"local_dof_ind = {local_dof_ind} and type is {type(local_dof_ind)}")
-                            print(f"cell_dof_map = {gli_cell_dofmap}")
-                            gli_dof_ind = gli_cell_dofmap[local_dof_ind]
-                            print(f"local_dof_ind = {local_dof_ind} and global ind is {gli_dof_ind}")
-                            print(f"nomal vector components = [{n[0]}, {n[1]}]")
-                            print(f"p_dof_ind = {p_dof_ind}")
-                            gl0.vector()[gli_dof_ind] = flux_x.vector()[flux_x_dof_ind]*n[0] + flux_y.vector()[flux_y_dof_ind]*n[1] - robin_pressure[p_dof_ind]
-                            print(f"gl0.vector()[gli_dof_ind] = {gl0.vector()[gli_dof_ind]}")
-
-
-
-                    #     print(cell_dofs_flux_x)
-                    #     cell_dofs_flux_y = flux_y_dof_map.cell_dofs(facet_cell_index)
-                    #     cell_dofs_gli = gli_dofmap.cell_dofs(facet_cell_index)
-                    # flux_x_coef = flux_x.vector()
-                    # # print(f"flux_x coefficients: ", flux_x_coef[:])
-                    # flux_space_dof_map =  flux_x.function_space().dofmap()
-                    # print("local to global dofs:", flux_space.dofmap().tabulate_local_to_global_dofs())
-                    # print("dofmap index map:", flux_space.dofmap().index_map())
-                    # print("entity dofs:", flux_space.dofmap().entity_dofs(self.mesh, 2))
-                    # print("block size of dofmap:", flux_space.dofmap().block_size())
-                    # interface_facets = df.SubsetIterator(self.interface_marker, interface.marker_value)
-                    # for facet in interface_facets:
-                    #     print(facet)
-                    #     print(facet.entities(0))
-                    #     how_many_cells = 0
-                    #     for cell in df.cells(facet):
-                    #         how_many_cells += 1
-                    #         print(f"Cell containing facet {facet} has dofs", flux_space_dof_map.cell_dofs(cell.index()))
-                    #         print("entity dofs of facet:", flux_space_dof_map.entity_dofs(self.mesh, 2, [facet.entities(0)[1]]))
-                    #         # print("entity dofs of facet:", flux_space_dof_map.entity_dofs(self.mesh, 2, [facet.entities(0)[1]]))
-                    #     print(f"the facet {facet.index()} has {how_many_cells} cells")
-                    #     for vertex in df.vertices(facet):
-                    #         print(vertex.point()[:])
-                    # print(f"dofmap flux_space:", flux_space.dofmap().dofs())
-                    # print(f"cell dof flux_space:", flux_space.dofmap().cell_dofs(0))
-
-                    # print(flux_space.tabulate_dof_coordinates())
-                    # print("Mesh Cells that contain a boundary facet (alt)")
-                    # for mesh_cell in df.cells(self.mesh):
-                    #     for facet in df.facets(mesh_cell):
-                    #         if facet.exterior():
-                    #             print(facet.entities(0))
-                    #             for vertex in df.vertices(facet):
-                    #                 print(vertex.point()[:])
-                    #             print(mesh_cell, mesh_cell.get_vertex_coordinates())
-
-
-
-
-                    # flux_function = df.project(flux_x, W)
-                    # Project the normal flux onto V so that we can
-                    # gl0 = df.project(df.dot(flux_function,n) - robin_pressure, gli_space)
-                    ds = self.ds
-                    marker_value = interface.marker_value
-                    phi_a  = self.testfunction[phase]
-                    gl0_form = gl0*phi_a*ds(marker_value)
-                    gl0_assembled = df.assemble(gl0_form)
-                    # # flux_x, flux_y = flux_FEM.split(deepcopy=True)
-                    # normal_flux = normal_flux_FEM.vector()
-                    # interface_dofs = self._dof_indices_of_interface[interf_ind][phase]
-                    # parent = self.parent_mesh_index
-                    # d2v = self.dof2vertex[phase]
-                    # for dof_index in interface_dofs:
-                    #     gli = normal_flux[dof_index] - robin_pressure[dof_index]
-                    #     # from_array is orderd by dof and not by vertex numbering of the mesh.
-                    #     # parent needs a mesh vertex index of the submesh, therefore d2v is needed.
-                    #     interface.gli_term_prev[subdomain_ind][phase].update(
-                    #         {parent[d2v[dof_index]]: gli}
-                    #         )
-
+                    gli_dof_coordinates = self.interface_dof_indices_and_coordinates["gli"][interf_ind][phase]
+                    p_dof_coordinates = self.interface_dof_indices_and_coordinates["pressure"][interf_ind][phase]
+                    flux_dof_coordinates = self.interface_dof_indices_and_coordinates["flux"][interf_ind][phase]
+
+                    local2global_facet = interface.local_to_global_facet_map[subdomain]
+                    for local_facet_ind, normal in interface.outer_normals[subdomain].items():
+                        gli_dofs_along_facet = gli_dof_coordinates[local_facet_ind]
+                        p_dofs_along_facet = p_dof_coordinates[local_facet_ind]
+                        flux_x_dofs_along_facet = flux_dof_coordinates["x"][local_facet_ind]
+                        flux_y_dofs_along_facet = flux_dof_coordinates["y"][local_facet_ind]
+
+                        # for each gli dof with index gli_dof_ind, we need the
+                        # dof indices for the flux and the pressure corresponding
+                        # to the coordinates of the dof, in order to calculate gl0
+                        # dof wise.
+                        for gli_dof_index, gli_dof_coord in gli_dofs_along_facet.items():
+                            flux_x_dof_index = -1
+                            for flux_x_dof_ind, dof_coord in flux_x_dofs_along_facet.items():
+                                if np.array_equal(dof_coord, gli_dof_coord):
+                                    flux_x_dof_index = flux_x_dof_ind
+
+                            flux_y_dof_index = -1
+                            for flux_y_dof_ind, dof_coord in flux_y_dofs_along_facet.items():
+                                if np.array_equal(dof_coord, gli_dof_coord):
+                                    flux_y_dof_index = flux_y_dof_ind
+
+                            p_dof_index = -1
+                            for p_dof_ind, dof_coord in p_dofs_along_facet.items():
+                                if np.array_equal(dof_coord, gli_dof_coord):
+                                    p_dof_index = p_dof_ind
+
+                            gl0.vector()[gli_dof_index] = flux_x.vector()[flux_x_dof_index]*normal[0] \
+                                + flux_y.vector()[flux_y_dof_index]*normal[1] - robin_pressure[p_dof_index]
+                            print(f"gl0.vector()[gli_dof_ind] = {gl0.vector()[gli_dof_index]}")
+
+                            # save this newly calculated dof to the interface
+                            # dictionary gli_term_prev
+                            global_facet_ind = local2global_facet[local_facet_ind]
+                            dof_coord_tupel = (gli_dof_coord[0], gli_dof_coord[1])
+                            interface.gli_term_prev[subdomain][phase][global_facet_ind].update(
+                                {dof_coord_tupel: gl0.vector()[gli_dof_index]}
+                                )
     ### END calc_gl0_term
 
 
@@ -681,7 +531,7 @@ class DomainPatch(df.SubDomain):
         subdomain = self.subdomain_index
         interface = self.interface[interface_index]
         # gli should be initialised by zero.
-        gli = df.Function(self.function_space["pressure"][phase])
+        gli = df.Function(self.function_space["gli"][phase])
         # neighbour index
         neighbour = interface.neighbour[subdomain]
         # update the current_iteration number of subdomain stored in the interface
@@ -689,19 +539,6 @@ class DomainPatch(df.SubDomain):
         interface.current_iteration[subdomain] = iteration
         # save the iteration number of the neighbour
         neighbour_iter_num = interface.current_iteration[neighbour]
-        # needed for the read_gli_dofs() functions
-        interface_dofs = self._dof_indices_of_interface[interface_index][phase]
-        # for each interface, the following is a list of dofs indices belonging to another
-        # interface. The dofs corresponding to these indices must be multiplied
-        # by 1/2 to to get an average of the gli terms for dofs belonging to
-        # two different interfaces.
-        dofs_in_common_with_other_interfaces = self._interface_has_common_dof_indices[interface_index]
-        if debug:
-            print(f"On subdomain{subdomain}, we have:\n",
-                  f"Interface{interface_index}, Neighbour index = {neighbour}\n",
-                  f"dofs on interface:\n{interface_dofs['wetting']}\n",
-                  f"dof2global_vertex_map:\n{self.parent_mesh_index[self.dof2vertex['wetting'][interface_dofs['wetting']]]}\n"
-                  f"and dofs common with other interfaces:\n{dofs_in_common_with_other_interfaces['wetting']}")
 
         if (phase == 'wetting') or (not interface.neighbour_isRichards[subdomain]):
             # read previous neighbouring pressure values from interface.
@@ -745,32 +582,51 @@ class DomainPatch(df.SubDomain):
                 "and iteration = " + "{} on subdomain".format(iteration)+ "{}".format(subdomain)\
                 + "You suck! Revisite DomainPatch.calc_gli_term() and LDDsimulation.LDDsolver ASAP.")
 
-            parent = self.parent_mesh_index
-            d2v = self.dof2vertex[phase]
-            # read gli_prev term from the neighbour.
-            gli_prev = interface.gli_term_prev[neighbour][phase]
             dt = self.timestep_size
             Lambda = self.lambda_param[phase]
-            for dof_index in interface_dofs:
-                glob_vert_ind = parent[d2v[dof_index]]
-                gli_value = -2*Lambda*pressure_prev[glob_vert_ind] - gli_prev[glob_vert_ind]
-                gli.vector()[dof_index] = gli_value
-                gli_save_dictionary[glob_vert_ind] = gli_value
-
-
-            # In the following case, the gli_term of the neighbour is saved to
-            # gli_term currently and will be overwritten in the next step,
-            # if we don't save it to gli_term_prev of the neighbour.
-            # similarly for the pressure values.
-            if iteration == neighbour_iter_num:
-                # print(f"we are on subdomain{subdomain} and interface{interface.global_index} (alt index:{ind}) has neighbouring \n",
-                #       f"subdomains: subdomain{subdomain} and subdomain{neighbour}")
-                interface.gli_term_prev[neighbour].update(#
-                    {phase: interface.gli_term[neighbour][phase].copy()}
+
+            gli_interface_dofs = self.interface_dof_indices_and_coordinates["gli"][interface_index][phase]
+            p_interface_dofs = self.interface_dof_indices_and_coordinates["pressure"][interface_index][phase]
+            local2global_facet = interface.local_to_global_facet_map[subdomain]
+            for facet_ind in interface.facets[subdomain].keys():
+                global_facet_ind = local2global_facet[facet_ind]
+                # read gli_prev term from the neighbour.
+                gli_prev = interface.gli_term_prev[neighbour][phase][global_facet_ind]
+                p_prev = pressure_prev[global_facet_ind]
+                gli_save_dict = gli_save_dictionary[global_facet_ind]
+                for gli_dof_index, gli_dof_coord in gli_interface_dofs[facet_ind].items():
+                    # find the right previous pressure dof of the interface
+                    # dictionary to use for the calculation.
+                    p_previous_dof = -9999999.9999
+                    for p_dof_coord_tupel, p_prev_dof in p_prev.items():
+                        p_coord = np.array([p_dof_coord_tupel[0], p_dof_coord_tupel[1]])
+                        if np.array_equal(gli_dof_coord, p_coord):
+                            p_previous_dof = p_prev_dof
+                    # same with the gli_previous_dof
+                    gli_previous_dof = -9999999.9999
+                    for gli_prev_coord_tupel, gli_prev_dof in gli_prev.items():
+                        gli_prev_coord = np.array([gli_prev_coord_tupel[0], gli_prev_coord_tupel[1]])
+                        if np.array_equal(gli_dof_coord, gli_prev_coord):
+                            gli_previous_dof = gli_prev_dof
+
+                    gli_value = -2*Lambda*p_previous_dof - gli_previous_dof
+                    gli.vector()[gli_dof_index] = gli_value
+                    gli_dof_coord_tupel = (gli_dof_coord[0], gli_dof_coord[1])
+                    gli_save_dictionary[gli_dof_coord_tupel] = gli_value
+
+                # In the following case, the gli_term of the neighbour is saved to
+                # gli_term currently and will be overwritten in the next step,
+                # if we don't save it to gli_term_prev of the neighbour.
+                # similarly for the pressure values.
+                if iteration == neighbour_iter_num:
+                    # print(f"we are on subdomain{subdomain} and interface{interface.global_index} (alt index:{ind}) has neighbouring \n",
+                    #       f"subdomains: subdomain{subdomain} and subdomain{neighbour}")
+                    interface.gli_term_prev[neighbour][phase].update(#
+                        {global_facet_ind: interface.gli_term[neighbour][phase][global_facet_ind].copy()}
+                        )
+                    interface.pressure_values_prev[neighbour][phase].update(
+                        {global_facet_ind: interface.pressure_values[neighbour][phase][global_facet_ind].copy()}
                     )
-                interface.pressure_values_prev[neighbour][phase].update(
-                    {phase: interface.pressure_values[neighbour][phase].copy()}
-                )
 
         return gli
     ### END calc_gli_term
@@ -850,7 +706,13 @@ class DomainPatch(df.SubDomain):
                 {phase: self.function_space["gli"][phase].dofmap()}
                 )
             self.dofmap["flux"].update(
-                {phase: self.function_space["flux"][phase].dofmap()}
+                {phase: dict()}
+                )
+            self.dofmap["flux"][phase].update(
+                {"x": self.function_space["flux"][phase].sub(0).dofmap()}
+                )
+            self.dofmap["flux"][phase].update(
+                {"y": self.function_space["flux"][phase].sub(1).dofmap()}
                 )
 
     def _init_markers(self) -> None:
@@ -932,9 +794,20 @@ class DomainPatch(df.SubDomain):
                     {interface_index: dict()}
                     )
                 for phase in self.has_phases:
-                    self.interface_dof_indices_and_coordinates[function][interface_index].update(#
-                        {phase: interface.dofs_and_coordinates(function_space[phase], marker, marker_value)}
-                    )
+                    if function == "flux":
+                        self.interface_dof_indices_and_coordinates[function][interface_index].update(#
+                            {phase: dict()}
+                        )
+                        self.interface_dof_indices_and_coordinates[function][interface_index][phase].update(#
+                            {"x": interface.dofs_and_coordinates(function_space[phase].sub(0), marker, marker_value)}
+                        )
+                        self.interface_dof_indices_and_coordinates[function][interface_index][phase].update(#
+                            {"y": interface.dofs_and_coordinates(function_space[phase].sub(1), marker, marker_value)}
+                        )
+                    else:
+                        self.interface_dof_indices_and_coordinates[function][interface_index].update(#
+                            {phase: interface.dofs_and_coordinates(function_space[phase], marker, marker_value)}
+                        )
 
 
     def _init_interface_values(self):
-- 
GitLab