diff --git a/LDDsimulation/LDDsimulation.py b/LDDsimulation/LDDsimulation.py
index 16e7d366ee803bd55f7c6fa4c47a752d69024770..a0f597649f67254520f466268ea07ec4225fd5f7 100644
--- a/LDDsimulation/LDDsimulation.py
+++ b/LDDsimulation/LDDsimulation.py
@@ -90,8 +90,27 @@ class LDDsimulation(object):
self._parameters_set = False
# dictionary of objects of class DomainPatch initialised by self._init_subdomains()
self.subdomain = dict()
- # dictionary to store the dirichletBC in.
+ # dictionary to hold the input Expressions for the external boundary. These are
+ # turned into df.Expressions objects by the method update_DirichletBC_dictionaries()
+ # this is mostly in place when examples with exact solutions are calculated.
+ self.dirichletBC_Expressions = None
+ # dictionary to hold the df.Expressions for the external boundary created
+ # from the above self.dirichletBC_Expressions. These are
+ # turned into df.dirichletBC objects by the method update_DirichletBC_dictionaries()
+ self.dirichletBC_dfExpression = dict()
+ # dictionary to store the df.dirichletBC objects in. These are used by the
+ # solver to set the boundary conditions
self.outerBC = dict()
+ # Flag to toggle between a case with exact solution and a purely numerical
+ # simulation. This changes the behaviour of self.update_DirichletBC_dictionaries()
+ self.exact_solution_case = False
+ # dictionary holding the source expressions for each subdomain. These are
+ # saved to the respective subdomains by the self._init_subdomains() method.
+ self.sources = None#
+ # dictionary holding expressions for the initial conditions for each subdomain.
+ # These are interpolated and stored to each respective subdomain by
+ # self._init_initial_values()
+ self.initial_conditions = None
def set_parameters(self,#
output_dir: str,#
@@ -111,7 +130,8 @@ class LDDsimulation(object):
timestep_size: tp.Dict[int, float],#
sources: tp.Dict[int, tp.Dict[str, str]],#
initial_conditions: tp.Dict[int, tp.Dict[str, str]],#
- outer_dirichletBC: tp.Dict[int, tp.Dict[str, str]],#
+ dirichletBC_Expressions: tp.Dict[int, tp.Dict[str, str]],#
+ exact_solution_case: bool = False#
)-> None:
""" set parameters of an instance of class LDDsimulation"""
@@ -131,7 +151,8 @@ class LDDsimulation(object):
self.timestep_size = timestep_size
self.sources = sources
self.initial_conditions = initial_conditions
- self.outer_dirichletBC = outer_dirichletBC
+ self.dirichletBC_Expressions = dirichletBC_Expressions
+ self.exact_solution_case = exact_solution_case
self._parameters_set = True
def initialise(self) -> None:
@@ -153,24 +174,27 @@ class LDDsimulation(object):
iteration, that is solves the problem given the initial data at timestep
time.
"""
- iteration = 0
# dictionary holding bool variables for each subdomain indicating wether
# minimal error has been achieved, i.e. the calculation can be considered
# done or not.
subdomain_calc_isdone = dict()
# before the iteration gets started all iteration numbers must be nulled
- # and
+ # and the subdomain_calc_isdone dictionary must be set to False
for ind, subdomain in self.subdomain.items():
subdomain_calc_isdone.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(interpolation_degree = 2,
time = time,
subdomain_index = ind)
+ self.update_DirichletBC_dictionaries()
# the following only needs to be done when time is not equal 0 since
# our initialisation functions already took care of setting what follows
- # for the initial iteration step.
- if time > 0:
+ # for the initial iteration step at time = 0.
+ if time > self.tol:
# this is the beginning of the solver, so iteration must be set
# to 0.
subdomain.iteration_number = 0
@@ -182,8 +206,9 @@ class LDDsimulation(object):
### actual iteration starts here
# gobal stopping criterion for the iteration.
+ iteration = 0
all_subdomains_are_done = False
- while iteration < self._max_iter_num and not all_subdomains_are_done:
+ while iteration <= self._max_iter_num and not all_subdomains_are_done:
# we need to loop over the subdomains and solve an L-scheme type step
# on each subdomain. here it should be possible to parallelise in
# the future.
@@ -191,9 +216,10 @@ class LDDsimulation(object):
# check if the calculation on subdomain has already be marked as
# finished.
if not subdomain_calc_isdone[sd_index]:
+ # set subdomain iteration to current iteration
+ subdomain.iteration_number = iteration
# solve the problem on subdomain
self.Lsolver_step(subdomain_index = sd_index,#
- iteration = iteration,#
debug = True
)
subsequent_iterations_err = self.calc_iteration_error(
@@ -229,8 +255,7 @@ class LDDsimulation(object):
iteration += 1
# end iteration while loop.
- def Lsolver_step(subdomain_index: int],#
- iteration: int,#
+ def Lsolver_step(self, subdomain_index: int],#
debug: bool = False) -> None:
""" L-scheme solver iteration step for an object of class subdomain
@@ -246,6 +271,26 @@ class LDDsimulation(object):
debug: bool flag to toggle weather or not
to write out each iteration.
"""
+ subdomain = self.subdomain[subdomain_index]
+ iteration = subdomain.iteration_number
+ if subdomain.isRichards:
+ # extract L-scheme form and rhs (without gli term) from subdomain.
+ governing_problem = subdomain.governing_problem(phase = 'wetting')
+ form = governing_problem[form]
+ rhs_without_gli = governing_problem[rhs_without_gli]
+ # assemble the form and rhs
+ form_assembled = df.assemble(form)
+ rhs_without_gli_assembled = df.assemble(rhs_without_gli)
+ # calculate the gli term
+ gli_term_assembled = subdomain.calc_gli_term(iteration = iteration)
+ # subdomain.calc_gli_term() asslembles gli but on the left hand side
+ # so gli_term_assembled needs to actually be subtracted from the rhs.
+ rhs_assembled = rhs_without_gli_assembled - gli_term_assembled
+ # apply outer Dirichlet boundary conditions if present.
+
+
+ else:
+ print("implement two phase assembly")
@@ -446,32 +491,55 @@ class LDDsimulation(object):
# populate interface dictionaries with pressure values.
subdomain.write_pressure_to_interfaces(initial_values = True)
- def set_DirichletBC(self, interpolation_degree: int = 2, #
+ def update_DirichletBC_dictionary(self,
+ interpolation_degree: int = 2, #
time: float = 0,#
# exact_solution: bool = False,#
- first_init: bool = False):
- """ set dirichlet boundary values at time time.
- """
- for num, subdomain in self.subdomain.items():
- mesh = subdomain.mesh
- V = subdomain.function_space
- # if first_init==True we have not initialised the dictionary
- if first_init:
- self.outerBC.update({num: dict()})
+ subdomain_index: int):
+ """ update time of the dirichlet boundary object for subdomain with
+ index subdomain_index.
- pDC = self.outer_dirichletBC[num]
- boundary_marker = subdomain.outer_boundary_marker
- if subdomain.isRichards:
- # note that the default interpolation degree is 2
+ In case we don't have a case with an exact solution, we should have 0
+ expressions in self.dirichletBC_Expressions, so nothing should happen.
+ """
+ num = subdomain_index
+ subdomain = self.subdomain[num]
+ mesh = subdomain.mesh
+ V = subdomain.function_space
+ # Here the dictionary has to be created first because t = 0.
+ if np.abs(time) < self.tol :
+ self.outerBC.update({num: dict()})
+ self.dirichletBC_dfExpression.update({num: dict()})
+
+ pDC = self.dirichletBC_Expressions[num]
+ boundary_marker = subdomain.outer_boundary_marker
+ if subdomain.isRichards:
+ # note that the default interpolation degree is 2
+ if np.abs(time) < self.tol :
+ # time = 0 so the Dolfin Expression has to be created first.
pDCw = df.Expression(pDC['wetting'], domain = mesh, degree = interpolation_degree, t=time)
- self.outerBC[num].update({'wetting': df.DirichletBC(V['wetting'], pDCw, boundary_marker, 1)})
+ self.dirichletBC_dfExpression[num].update({'wetting': pDCw})
else:
+ pDCw = self.dirichletBC_dfExpression[num]['wetting'].t = time
+
+ self.outerBC[num].update({'wetting': df.DirichletBC(V['wetting'], pDCw, boundary_marker, 1)})
+ else:
+ if np.abs(time) < self.tol :
+ # time = 0 so the Dolfin Expression has to be created first.
pDCw = df.Expression(pDC['wetting'], domain = mesh, degree = interpolation_degree, t=time)
pDCnw = df.Expression(pDC['nonwetting'], domain = mesh, degree = interpolation_degree, t=time)
- self.outerBC[num].update(#
- {'wetting': df.DirichletBC(V['wetting'], pDCw, boundary_marker, 1)},#
- {'nonwetting': df.DirichletBC(V['nonwetting'], pDCnw, boundary_marker, 1)},#
- )
+ self.dirichletBC_dfExpression[num].update(
+ {'wetting': pDCw},#
+ {'nonwetting': pDCnw},#
+ )
+ else:
+ pDCw = self.dirichletBC_dfExpression[num]['wetting'].t = time
+ pDCnw = self.dirichletBC_dfExpression[num]['nonwetting'].t = time
+
+ self.outerBC[num].update(#
+ {'wetting': df.DirichletBC(V['wetting'], pDCw, boundary_marker, 1)},#
+ {'nonwetting': df.DirichletBC(V['nonwetting'], pDCnw, boundary_marker, 1)},#
+ )
def _eval_sources(self, interpolation_degree: int = 2, #
time: float = 0,