From 508d3d0acda622e057134ad608fb84240d4aa60d Mon Sep 17 00:00:00 2001
From: David Seus <david.seus@ians.uni-stuttgart.de>
Date: Fri, 3 May 2019 13:25:35 +0200
Subject: [PATCH] before attempting to fix calculation of gli terms

---
 LDDsimulation/LDDsimulation.py              | 53 +++++++----------
 LDDsimulation/domainPatch.py                | 65 +++++++--------------
 RR-2-patch-test-case/RR-2-patch-test.py     | 27 +++++----
 TP-TP-patch-test-case/TP-TP-2-patch-test.py | 18 +++---
 4 files changed, 66 insertions(+), 97 deletions(-)

diff --git a/LDDsimulation/LDDsimulation.py b/LDDsimulation/LDDsimulation.py
index 1c2bf30..2b432b6 100644
--- a/LDDsimulation/LDDsimulation.py
+++ b/LDDsimulation/LDDsimulation.py
@@ -239,25 +239,25 @@ class LDDsimulation(object):
             raise RuntimeError('Parameters note set!\nYou forgott to run self.set_parameters(**kwds)')
         self._add_parameters_to_output_dirname()
         self._init_analyse_timesteps()
-        df.info(colored("initialise meshes and marker functions ...\n", "orange"))
+        df.info(colored("initialise meshes and marker functions ...\n", "yellow"))
         self._init_meshes_and_markers()
-        df.info(colored("initialise interfaces ...\n", "orange"))
+        df.info(colored("initialise interfaces ...\n", "yellow"))
         self._init_interfaces()
-        df.info(colored("initialise subdomains ...\n", "orange"))
+        df.info(colored("initialise subdomains ...\n", "yellow"))
         self._init_subdomains()
-        df.info(colored("creating xdmf files for each subdomain ...\n", "orange"))
+        df.info(colored("creating xdmf files for each subdomain ...\n", "yellow"))
         self._init_solution_files()
         # initial values get initialised here to be able to call the solver at different
         # timesteps without having to call self.run().
-        df.info(colored("create initial values ...", "orange"))
+        df.info(colored("create initial values ...", "yellow"))
         self._init_initial_values()
-        df.info(colored("create source Expressions ...", "orange"))
+        df.info(colored("create source Expressions ...", "yellow"))
         self._init_sources()
         # initialise exact solution expression dictionary if we have an exact
         # solution case.
         self._init_exact_solution_expression()
         if self.exact_solution:
-            df.info(colored("writing exact solution for all time steps to xdmf files ...", "orange"))
+            df.info(colored("writing exact solution for all time steps to xdmf files ...", "yellow"))
             self.write_exact_solution_to_xdmf()
         self._initialised = True
 
@@ -372,7 +372,6 @@ class LDDsimulation(object):
             # iterations in, used to analyse the behaviour of the iterates within
             # the current time step.
             solution_over_iteration_within_timestep = dict()
-            subsequent_errors_over_iteration = dict()
         # before the iteration gets started all iteration numbers must be nulled
         # and the self._calc_isdone_for_subdomain dictionary must be set to False
         for ind, subdomain in self.subdomain.items():
@@ -385,20 +384,11 @@ class LDDsimulation(object):
                 solution_over_iteration_within_timestep.update( #
                     {ind: SolutionFile(self._mpi_communicator, filename)}
                     )
-                subsequent_errors_over_iteration.update( {ind: dict()} )
-                # # we need a dictionries for each phase.
-                # for phase in subdomain.has_phases:
-                #     subsequent_errors_over_iteration[ind].update( {phase: dict()} )
-                #
 
             self._calc_isdone_for_subdomain.update({ind: False})
             # reset all interface[has_interface].current_iteration[ind] = 0, for
             # index has_interface in subdomain.has_interface
             subdomain.null_all_interface_iteration_numbers()
-            # update the time of the source terms before starting the iteration.
-            # The sources and sinks are the same throughout the iteration.
-            # self._eval_sources(time = time,
-            #                    subdomain_index = ind)
             self.update_DirichletBC_dictionary(time = time, #
                 subdomain_index = ind,
                 )
@@ -409,9 +399,14 @@ class LDDsimulation(object):
                 # evaluate the sources to the current time.
                 subdomain.source[phase].t = time
                 # set the solution of the previous timestep as new prev_timestep pressure
+                # print(colored(f"id(subdomain{subdomain.subdomain_index}.pressure_prev_timestep[{phase}])", "red"), " =\n", f"{id(subdomain.pressure_prev_timestep[phase])}")
+                # print(f"subdomain{subdomain.subdomain_index}.pressure_prev_timestep[{phase}].vector()[:]", " =\n", f"{subdomain.pressure_prev_timestep[phase].vector()[:]}")
+                # print(f"subdomain{subdomain.subdomain_index}.pressure[{phase}].vector()[:]", " =\n", f"{subdomain.pressure[phase].vector()[:]}")
                 subdomain.pressure_prev_timestep[phase].assign(
                     subdomain.pressure[phase]
                 )
+                # print(colored(f"id(subdomain{subdomain.subdomain_index}.pressure[{phase}])", "red"), " =\n", f"{id(subdomain.pressure[phase])}")
+                # print(f"subdomain{subdomain.subdomain_index}.pressure_prev_timestep[{phase}].vector()[:]", " =\n", f"{subdomain.pressure_prev_timestep[phase].vector()[:]}")
                 # All isdone flags need to be zero before we start iterating
                 self._calc_isdone_for_phase[ind].update({phase: False})
 
@@ -437,6 +432,7 @@ class LDDsimulation(object):
                     self.Lsolver_step(subdomain_index = sd_index,#
                                       debug = debug,
                                       )
+                    # bypass error checking for the first iteration.
                     if iteration > 0:
                         subsequent_iter_error = dict()
                         for phase in subdomain.has_phases:
@@ -446,17 +442,17 @@ class LDDsimulation(object):
                             subsequent_iter_error.update(
                                 {phase: error_calculated}
                                 )
+
                             # set flag to stop solving for that phase if error_criterion is met.
                             if subsequent_iter_error[phase] < error_criterion:
                                 self._calc_isdone_for_phase[sd_index].update({phase: True})
 
                             if debug:
-                                print(f"the subsequent error in iteration {iteration} for phase {phase} is {subsequent_iter_error[phase]}")
+                                print(f"t = {self.t}: subsequent error in iteration {iteration} for phase {phase} is {subsequent_iter_error[phase]}")
 
                         if analyse_timestep:
                             # save the calculated L2 errors to csv file for plotting
-                            # with pgfplots.
-                            print(f"t = {self.t} the subsequent error in iteration {iteration} is {subsequent_iter_error[phase]}")
+                            # with pgfplots
                             subsequent_error_filename = self.output_dir\
                                 +self.output_filename_parameter_part[sd_index]\
                                 +"subsequent_iteration_errors" +"_at_time"+\
@@ -467,28 +463,21 @@ class LDDsimulation(object):
                                 errors = subsequent_iter_error,
                                 time = time)
 
-                            # this saves the actual difference function between subsequent
-                            # iterations to analyse then in paraview later.
-                            subsequent_errors_over_iteration[sd_index].update(
-                                { phase: error })
-
-
                         # both phases should be done before we mark the subdomain as
                         # finished.
-                        print("max(subsequent_iter_error.values()): ", max(subsequent_iter_error.values()))
                         total_subsequent_iter_error = max(subsequent_iter_error.values())
                         # check if error criterion has been met
-
+                        # print(f" total_subsequent_error in iter {iteration} = {total_subsequent_iter_error }\n")
                         if debug:
-                            print(f" total_subsequent_error in iter {iteration} = {total_subsequent_iter_error }\n")
+                            # print(f" total_subsequent_error in iter {iteration} = {total_subsequent_iter_error }\n")
                             print(f"the maximum distance between any to points in a cell mesh.hmax() on subdomain{sd_index} is h={subdomain.mesh.hmax()}")
-                            print(f"the minimal distance between any to points in a cell mesh.hmin() on subdomain{sd_index} is h={subdomain.mesh.hmin()}")
+                            #print(f"the minimal distance between any to points in a cell mesh.hmin() on subdomain{sd_index} is h={subdomain.mesh.hmin()}")
                             print(f"the error criterion is tol = {error_criterion}")
                         # wetting_done = self._calc_isdone_for_phase[sd_index]['wetting']
                         # nonwetting_done = self._calc_isdone_for_phase[sd_index]['nonwetting']
                         if total_subsequent_iter_error < error_criterion:
-                            if debug:
-                                print(f"subdomain{sd_index} reachd error tol = {error_criterion} in iteration {iteration}.")
+                            # if debug:
+                            print(f"subdomain{sd_index} reached error = {total_subsequent_iter_error} < tol = {error_criterion} after {iteration} iterations.")
                             self._calc_isdone_for_subdomain[sd_index] = True
 
                     # prepare next iteration
diff --git a/LDDsimulation/domainPatch.py b/LDDsimulation/domainPatch.py
index 1ccbbb1..9fff677 100644
--- a/LDDsimulation/domainPatch.py
+++ b/LDDsimulation/domainPatch.py
@@ -21,6 +21,7 @@ import numpy as np
 import typing as tp
 import ufl as fl
 import LDDsimulation
+from termcolor import colored
 # Interface = tp.NewType('Interface', tp.any)
 # SolutionFile = tp.NewType('LDDsimulation.SolutionFile', tp.object)
 #import domainPatch as domainPatch
@@ -184,7 +185,7 @@ class DomainPatch(df.SubDomain):
         # Dictionary of FEM function of self.function_space holding the interface
         # dofs of the previous iteration of the neighbouring pressure. This is used
         # to assemble the gli terms in the method self.calc_gli_term().
-        self.neighbouring_interface_pressure = None
+        # self.neighbouring_interface_pressure = None
         # valiable holding a solver object of type df.KrylovSolver. It is set the
         # first time LDDsimulation.LDDsolver is run.
         self.linear_solver = None
@@ -256,8 +257,9 @@ class DomainPatch(df.SubDomain):
         porosity = self.porosity
         if self.isRichards:
             # this assumes that atmospheric pressure has been normalised to 0.
-            pc_prev_iter = self.pressure_prev_iter['wetting']
-            pc_prev_timestep = self.pressure_prev_timestep['wetting']
+            # and since
+            pc_prev_iter = -self.pressure_prev_iter['wetting']
+            pc_prev_timestep = -self.pressure_prev_timestep['wetting']
             if phase == 'nonwetting':
                 print("CAUTION: You invoked domainPatch.governing_problem() with\n", #
                 "Parameter phase = 'nonwetting'. But isRichards = True for",
@@ -365,7 +367,7 @@ class DomainPatch(df.SubDomain):
             ds = self.ds(interface.marker_value)
             # needed for the read_gli_dofs() functions
             interface_dofs = self._dof_indices_of_interface[ind]
-            # for each interface, this is a list of dofs indices belonging to another
+            # 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.
@@ -406,8 +408,8 @@ class DomainPatch(df.SubDomain):
 
                 if self.isRichards:
                     # assuming that we normalised atmospheric pressure to zero,
-                    # pc = pw in the Richards case.
-                    pc_prev = p_prev_iter['wetting']
+                    # pc = -pw in the Richards case.
+                    pc_prev = -p_prev_iter['wetting']
                 else:
                     pw_prev = p_prev_iter['wetting']
                     pnw_prev = p_prev_iter['nonwetting']
@@ -458,8 +460,8 @@ class DomainPatch(df.SubDomain):
                             # if the neighbour of our subdomain (with index self.subdomain_index)
                             # assumes a Richards model, we don't have gli terms for the
                             # nonwetting phase and assemble the terms as zero form.
-                            # pass
-                            gli_assembled_tmp[phase] += df.assemble(df.Constant(0)*ds).get_local()
+                            pass
+                            # gli_assembled_tmp[phase] += df.assemble(df.Constant(0)*ds).get_local()
                         else:
                             # in this case the neighbour assumes two-phase flow
                             # and we need to calculte a gl0 torm for the nonwetting
@@ -498,10 +500,12 @@ class DomainPatch(df.SubDomain):
                     if debug:
                         print(f"in iteration {iteration} and neighbour iteration = {neighbour_iter_num}:\n")
                         print(f"Interface{ind}.gli_term_prev[{subdomain}]['wetting']=\n",interface.gli_term_prev[subdomain]['wetting'])
+
                     interface.gli_term_prev[subdomain].update(#
                         {'wetting': interface.gli_term[neighbour]['wetting'].copy()}
                         )
-
+                    # print(colored(f"id(interface.gli_term_prev[{subdomain}][wetting])= {id(interface.gli_term_prev[subdomain]['wetting'])}","red"))
+                    # print(colored(f"id(interface.gli_term[{neighbour}][wetting])= {id(interface.gli_term[neighbour]['wetting'])}","red"))
                     if debug:
                         print(f"Interface{ind}.gli_term[{neighbour}]['wetting']=\n",interface.gli_term[neighbour]['wetting'])
                         print(f"Interface{ind}.gli_term_prev[{subdomain}]['wetting']=\n",interface.gli_term_prev[subdomain]['wetting'])
@@ -538,7 +542,8 @@ class DomainPatch(df.SubDomain):
 
                         # read neighbouring pressure values from interface and write them to
                         # the function self.neighbouring_interface_pressure
-                        interface.write_pressure_dofs(to_function = self.neighbouring_interface_pressure[phase], #
+                        pa_prev = df.interpolate(df.Constant(0), self.function_space[phase])
+                        interface.write_pressure_dofs(to_function = pa_prev,#self.neighbouring_interface_pressure[phase], #
                                        interface_dofs = interface_dofs[phase],#
                                        dof_to_vert_map = self.dof2vertex[phase],#
                                        local_to_parent_vertex_map = self.parent_mesh_index,#
@@ -548,7 +553,7 @@ class DomainPatch(df.SubDomain):
 
                         # use the above to calculate the gli update with
                         # in the paper p^{i-1}_{3-l}
-                        pa_prev = self.neighbouring_interface_pressure[phase]
+                        # pa_prev = self.neighbouring_interface_pressure[phase]
                         phi_a  = self.testfunction[phase]
                         gli_pressure_part = df.assemble(-2*dt*Lambda[phase]*pa_prev*phi_a*ds)
                         gli_p_part = gli_pressure_part.get_local()
@@ -634,44 +639,14 @@ class DomainPatch(df.SubDomain):
         self.function_space = dict()
         self.trialfunction = dict()
         self.testfunction = dict()
-        self.neighbouring_interface_pressure = dict()
+        # self.neighbouring_interface_pressure = dict()
         for phase in self.has_phases:
             self.function_space.update({phase: df.FunctionSpace(self.mesh, 'P', 1)})
             self.trialfunction.update({phase: df.TrialFunction(self.function_space[phase])})
             self.testfunction.update({phase: df.TestFunction(self.function_space[phase])})
-            self.neighbouring_interface_pressure.update(
-                {phase: df.interpolate(df.Constant(0), self.function_space[phase])}
-                )
-            print(f"Python id of self.neighbouring_interface_pressure[{phase}]", id(self.neighbouring_interface_pressure[phase]))
-
-        # if self.isRichards:
-        #     self.function_space = {'wetting': df.FunctionSpace(self.mesh, 'P', 1)}
-        #     self.trialfunction = {
-        #         'wetting': df.TrialFunction(self.function_space['wetting'])
-        #         }
-        #     self.testfunction = {
-        #         'wetting': df.TestFunction(self.function_space['wetting'])
-        #         }
-        #     self.neighbouring_interface_pressure = {
-        #         'wetting' : df.interpolate(df.Constant(0), self.function_space['wetting'])
-        #         }
-        # else:
-        #     self.function_space = {#
-        #         'wetting'    : df.FunctionSpace(self.mesh, 'P', 1),#
-        #         'nonwetting' : df.FunctionSpace(self.mesh, 'P', 1)#
-        #         }
-        #     self.trialfunction = {
-        #         'wetting'    : df.TrialFunction(self.function_space['wetting']),
-        #         'nonwetting' : df.TrialFunction(self.function_space['nonwetting'])
-        #         }
-        #     self.testfunction = {
-        #         'wetting'    : df.TestFunction(self.function_space['wetting']),
-        #         'nonwetting' : df.TestFunction(self.function_space['nonwetting'])
-        #         }
-        #     self.neighbouring_interface_pressure = {#
-        #         'wetting' : df.interpolate(df.Constant(0), self.function_space['wetting']),#
-        #         'nonwetting' : df.interpolate(df.Constant(0), self.function_space['nonwetting'])
-        #     }
+            # self.neighbouring_interface_pressure.update(
+            #     {phase: df.interpolate(df.Constant(0), self.function_space[phase])}
+            #     )
 
     def _init_dof_maps(self) -> None:
         """ calculate dof maps and the vertex to parent map.
diff --git a/RR-2-patch-test-case/RR-2-patch-test.py b/RR-2-patch-test-case/RR-2-patch-test.py
index 5370b0b..76d6a07 100755
--- a/RR-2-patch-test-case/RR-2-patch-test.py
+++ b/RR-2-patch-test-case/RR-2-patch-test.py
@@ -85,13 +85,13 @@ isRichards = {
     }
 
 ##################### MESH #####################################################
-mesh_resolution = 10
+mesh_resolution = 40
 ##################### TIME #####################################################
-timestep_size = 2*0.0001
-number_of_timesteps = 30
+timestep_size = 4*0.0001
+number_of_timesteps = 5000
 # decide how many timesteps you want analysed. Analysed means, that we write out
 # subsequent errors of the L-iteration within the timestep.
-number_of_timesteps_to_analise = 7
+number_of_timesteps_to_analyse = 11
 starttime = 0
 
 
@@ -115,8 +115,8 @@ L = {#
 
 lambda_param = {#
 # subdom_num : lambda parameter for the L-scheme
-    1 : {'wetting' :160},#
-    2 : {'wetting' :160}
+    1 : {'wetting' :100},#
+    2 : {'wetting' :100}
 }
 
 ## relative permeabilty functions on subdomain 1
@@ -147,9 +147,14 @@ relative_permeability = {#
     2: subdomain2_rel_perm
 }
 
-def saturation(pressure, subdomain_index):
+# this function needs to be monotonically decreasing in the capillary_pressure.
+# since in the richards case pc = -pw, this becomes as a function of pw a monotonically
+# INCREASING function like in our Richards-Richards paper. However, since we unify
+# the treatment in the code for Richards and two-phase, we need the same requierment
+# for both cases, two-phase and Richards.
+def saturation(capillary_pressure, subdomain_index):
     # inverse capillary pressure-saturation-relationship
-    return df.conditional(pressure < 0, 1/((1 - pressure)**(1/(subdomain_index + 1))), 1)
+    return df.conditional(capillary_pressure > 0, 1/((1 + capillary_pressure)**(1/(subdomain_index + 1))), 1)
 
 sat_pressure_relationship = {#
     1: ft.partial(saturation, subdomain_index = 1),#
@@ -197,7 +202,7 @@ write_to_file = {
 }
 
 # initialise LDD simulation class
-simulation = ldd.LDDsimulation(tol = 1E-12)
+simulation = ldd.LDDsimulation(tol = 1E-14)
 simulation.set_parameters(output_dir = "./output/",#
     subdomain_def_points = subdomain_def_points,#
     isRichards = isRichards,#
@@ -213,11 +218,11 @@ simulation.set_parameters(output_dir = "./output/",#
     saturation = sat_pressure_relationship,#
     starttime = starttime,#
     number_of_timesteps = number_of_timesteps,
-    number_of_timesteps_to_analise = number_of_timesteps_to_analise,
+    number_of_timesteps_to_analyse = number_of_timesteps_to_analyse,
     timestep_size = timestep_size,#
     sources = source_expression,#
     initial_conditions = initial_condition,#
-    dirichletBC_Expressions = dirichletBC,#
+    dirichletBC_expression_strings = dirichletBC,#
     exact_solution = exact_solution,#
     write2file = write_to_file,#
     )
diff --git a/TP-TP-patch-test-case/TP-TP-2-patch-test.py b/TP-TP-patch-test-case/TP-TP-2-patch-test.py
index 7ad8c97..c078425 100755
--- a/TP-TP-patch-test-case/TP-TP-2-patch-test.py
+++ b/TP-TP-patch-test-case/TP-TP-2-patch-test.py
@@ -89,9 +89,9 @@ isRichards = {
 
 
 ############ GRID ########################ΓΌ
-mesh_resolution = 100
-timestep_size = 2*0.001
-number_of_timesteps = 1000
+mesh_resolution = 40
+timestep_size = 0.001
+number_of_timesteps = 2000
 # decide how many timesteps you want analysed. Analysed means, that we write out
 # subsequent errors of the L-iteration within the timestep.
 number_of_timesteps_to_analyse = 11
@@ -122,9 +122,9 @@ L = {#
 lambda_param = {#
 # subdom_num : lambda parameter for the L-scheme
     1 : {'wetting' :140,
-         'nonwetting': 1000},#
+         'nonwetting': 2400},#
     2 : {'wetting' :140,
-         'nonwetting': 1000}
+         'nonwetting': 2400}
 }
 
 ## relative permeabilty functions on subdomain 1
@@ -147,7 +147,7 @@ def rel_perm2w(s):
     # relative permeabilty wetting on subdomain2
     return s**3
 def rel_perm2nw(s):
-    # relative permeabilty nonwetting on subdomain2
+    # relative permeabilty nonwetting on subdosym.cos(0.8*t - (0.8*x + 1/7*y))main2
     return (1-s)**2
 
 _rel_perm2w = ft.partial(rel_perm2w)
@@ -168,7 +168,7 @@ relative_permeability = {#
 # we set alpha = 0, assume m = 1-1/n (see Helmig) and assume that residual saturation is Sw
 def saturation(capillary_pressure, n_index, alpha):
     # inverse capillary pressure-saturation-relationship
-    return df.conditional(capillary_pressure < 0, 1/((1 + (alpha*capillary_pressure)**n_index)**((n_index - 1)/n_index)), 1)
+    return df.conditional(capillary_pressure > 0, 1/((1 + (alpha*capillary_pressure)**n_index)**((n_index - 1)/n_index)), 1)
 
 # S-pc-relation ship. We use the van Genuchten approach, i.e. pc = 1/alpha*(S^{-1/m} -1)^1/n, where
 # we set alpha = 0, assume m = 1-1/n (see Helmig) and assume that residual saturation is Sw
@@ -318,7 +318,7 @@ write_to_file = {
 
 
 # initialise LDD simulation class
-simulation = ldd.LDDsimulation(tol = 1E-12)
+simulation = ldd.LDDsimulation(tol = 1E-14)
 simulation.set_parameters(output_dir = "./output/",#
     subdomain_def_points = subdomain_def_points,#
     isRichards = isRichards,#
@@ -338,7 +338,7 @@ simulation.set_parameters(output_dir = "./output/",#
     timestep_size = timestep_size,#
     sources = source_expression,#
     initial_conditions = initial_condition,#
-    dirichletBC_Expressions = dirichletBC,#
+    dirichletBC_expression_strings = dirichletBC,#
     exact_solution = exact_solution,#
     write2file = write_to_file,#
     )
-- 
GitLab