From d812de874ddeb39aa4d0771add7d4241bd370e05 Mon Sep 17 00:00:00 2001 From: David Seus <david.seus@ians.uni-stuttgart.de> Date: Tue, 7 May 2019 12:45:32 +0200 Subject: [PATCH] bevor iterationszahl im Solver von 1 losgeht. --- LDDsimulation/LDDsimulation.py | 166 +++++++++++++------- LDDsimulation/domainPatch.py | 26 ++- RR-2-patch-test-case/RR-2-patch-test.py | 8 +- TP-TP-patch-test-case/TP-TP-2-patch-test.py | 18 +-- 4 files changed, 134 insertions(+), 84 deletions(-) diff --git a/LDDsimulation/LDDsimulation.py b/LDDsimulation/LDDsimulation.py index 764ac95..5442a2d 100644 --- a/LDDsimulation/LDDsimulation.py +++ b/LDDsimulation/LDDsimulation.py @@ -162,7 +162,7 @@ class LDDsimulation(object): 'report': False } - self.debug_solver = False + self.debug_solver = True # Dictionaries needed by the LDD Solver # dictionary holding bool variables for each subdomain indicating wether # minimal error has been achieved, i.e. the calculation can be considered @@ -358,63 +358,30 @@ class LDDsimulation(object): """ calulate the solution on all patches for the next timestep The heart of the simulation. The function LDDsolver implements the LDD - iteration, that is solves the problem given the initial data at timestep + iteration, that solves the problem given the initial data at timestep time. + + PARAMATERS + --------------------- + time float, optional time at which to run the solver. This is internally + set to self.t if no time is given. This variable + is there for development purposes. + debug bool, optional debug flag used to toggle the amount of output + being displayed. + analyse_timestep bool, optional, flag to toggle wether or not to run + routines designed to output data within one timestep + iteration. """ # in case no time is given, use the time of the class. if time is None: time = self.t error_criterion = 1E-8#min(1E-9, subdomain.mesh.hmax()**2*subdomain.timestep_size) - - if analyse_timestep: - # dictionary holding filename strings for each subdomain to store - # iterations in, used to analyse the behaviour of the iterates within - # the current time step. - solution_over_iteration_within_timestep = 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(): - # create xdmf files for writing out iterations if analyse_timestep is - # given. - if analyse_timestep: - filename = self.output_dir+self.output_filename_parameter_part[ind]\ - + "solution_iterations_at_t"\ - + "{number:.{digits}f}".format(number=time, digits=2) +".xdmf" - solution_over_iteration_within_timestep.update( # - {ind: SolutionFile(self._mpi_communicator, filename)} - ) - - 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() - self.update_DirichletBC_dictionary(time = time, # - subdomain_index = ind, - ) - # # this is the beginning of the solver, so iteration must be set - # # to 0. - subdomain.iteration_number = 0 - for phase in subdomain.has_phases: - # 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}) - - subdomain.calc_gl0_term() - + # in case analyse_timestep is None, solution_over_iteration_within_timestep is None + solution_over_iteration_within_timestep = self.prepare_LDDsolver(analyse_timestep = analyse_timestep) ### actual iteration starts here - # gobal stopping criterion for the iteration. iteration = 0 + # gobal stopping criterion for the iteration. all_subdomains_are_done = False 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 @@ -426,10 +393,10 @@ class LDDsimulation(object): if not self._calc_isdone_for_subdomain[sd_index]: # set subdomain iteration to current iteration subdomain.iteration_number = iteration - if debug: - print(f"On subdomain{sd_index}: Entering iteration {iteration}\n") - print(f"subdomain{sd_index}.isRichards = {subdomain.isRichards}.") - print(f"subdomain{sd_index}.has_phases = {subdomain.has_phases}.") + # if debug: + # print(f"On subdomain{sd_index}: Entering iteration {iteration}\n") + # print(f"subdomain{sd_index}.isRichards = {subdomain.isRichards}.") + # print(f"subdomain{sd_index}.has_phases = {subdomain.has_phases}.") # solve the problem on subdomain self.Lsolver_step(subdomain_index = sd_index,# debug = debug, @@ -517,6 +484,97 @@ class LDDsimulation(object): iteration += 1 # end iteration while loop. + def prepare_LDDsolver(self, time: float = None, # + debug: bool = False, # + analyse_timestep: bool = False) -> analysing_solution_file_dict: tp.Dict[ind, SolutionFile]: + """ initialise LDD iteration for current time time. + + This method executes a few prelininary steps before actually starting + the L-iteration. Namely, + - create solution files for analysing time step if analyse_timestep == True + - the dictionries self._calc_isdone_for_subdomain are set to False + - Dirichlet boundary condition terms are evaluated to the current time + - all subdomain iteration numbers on interfaces are set to 0. + - all subdomain iteration numbers subdomain.iteration_number are set + to 0. + - source terms are evaluated to the current time. + - the calculated solution pressure from the previous timestep + is assigned to pressure_prev for each subdomain. + - The self._calc_isdone_for_phase dictionary for each phase on each + subdomain are set to False + - gl0 terms are calculated. + + PARAMETERS + ------------------------------------ + time float, optional time at which to run the solver. This is internally + set to self.t if no time is given. This variable + is there for development purposes. + debug bool, optional debug flag used to toggle the amount of output + being displayed. + analyse_timestep bool, optional, flag to toggle wether or not to run + routines designed to output data within one timestep + iteration. + + OUTPUT + ------------------------------------ + analysing_solution_file_dict tp.Dict[ind, SolutionFile] dictionary + containing the solution file for analysing the + timestep if analyse_timestep == True, else None. + """ + # in case no time is given, use the time of the class. + if time is None: + time = self.t + + if analyse_timestep: + # dictionary holding filename strings for each subdomain to store + # iterations in, used to analyse the behaviour of the iterates within + # the current time step. + solution_over_iteration_within_timestep = dict() + else: + solution_over_iteration_within_timestep = None + # 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(): + # create xdmf files for writing out iterations if analyse_timestep is + # given. + if analyse_timestep: + filename = self.output_dir+self.output_filename_parameter_part[ind]\ + + "solution_iterations_at_t"\ + + "{number:.{digits}f}".format(number=time, digits=2) +".xdmf" + solution_over_iteration_within_timestep.update( # + {ind: SolutionFile(self._mpi_communicator, filename)} + ) + + 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() + self.update_DirichletBC_dictionary(time = time, # + subdomain_index = ind, + ) + # # this is the beginning of the solver, so iteration must be set + # # to 0. + subdomain.iteration_number = 0 + for phase in subdomain.has_phases: + # evaluate the sources to the current time. + subdomain.source[phase].t = time + # set the solution of the previous timestep as new prev_timestep pressure + if debug: + 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] + ) + if debug: + 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}) + + subdomain.calc_gl0_term() + + return solution_over_iteration_within_timestep def Lsolver_step(self, subdomain_index: int,# debug: bool = False) -> None: @@ -796,7 +854,7 @@ class LDDsimulation(object): 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 suddomains and + """ generate interfaces and interface marker functions for suddomains and set the internal lists used by the LDDsimulation class. This initialises a list of interfaces and global interface marker functions diff --git a/LDDsimulation/domainPatch.py b/LDDsimulation/domainPatch.py index 3c50a01..76832d4 100644 --- a/LDDsimulation/domainPatch.py +++ b/LDDsimulation/domainPatch.py @@ -368,28 +368,24 @@ class DomainPatch(df.SubDomain): 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']}") - n = df.FacetNormal(self.mesh) - pa_prev_timestep = self.pressure_prev_timestep - k = self.relative_permeability - S = self.saturation - mu = self.viscosity - if self.isRichards: # assuming that we normalised atmospheric pressure to zero, # pc = -pw in the Richards case. - pc_prev = -pa_prev_timestep['wetting'] + pc_prev = -self.pressure_prev_timestep['wetting'] else: - pw_prev = pa_prev_timestep['wetting'] - pnw_prev = pa_prev_timestep['nonwetting'] + pw_prev = self.pressure_prev_timestep['wetting'] + pnw_prev = self.pressure_prev_timestep['nonwetting'] pc_prev = pnw_prev - pw_prev + n = df.FacetNormal(self.mesh) + S = self.saturation for phase in self.has_phases: # viscosity - mu_a = mu[phase] + mu_a = self.viscosity[phase] # relative permeability - ka = k[phase] + ka = self.relative_permeability[phase] # previous timestep pressure - pa_prev = pa_prev_timestep[phase] + pa_prev = self.pressure_prev_timestep[phase] # testfunction phi_a = self.testfunction[phase] if phase == 'nonwetting' and interface.neighbour_isRichards[subdomain]: @@ -443,9 +439,6 @@ class DomainPatch(df.SubDomain): # save the result of the calculation to the subdomain and to the interface # dictionaries. for phase in self.has_phases: - # self.gli_assembled.update( - # {phase: gli_assembled_tmp[phase].copy()} - # ) for interf_ind in self.has_interface: # self._calc_gli_term_on(interface, iteration) interface = self.interface[interf_ind] @@ -516,8 +509,7 @@ class DomainPatch(df.SubDomain): # in case phase == 'nonwetting' only proceed if the neighbouring # subdomain does not assume a Richards model. if (phase == 'wetting') or (not interface.neighbour_isRichards[subdomain]): - # read gli_prev term from the neighbour and write it to - # the gli_assembled array of the subdomain + # read gli_prev term from the neighbour. # to be able to sum the gli terms of all interfaces together, # we need a dummy vector to hold the dofs read from the interface. gli_prev_of_neighbour = np.zeros(gli_assembled_tmp[phase].size, dtype = float) 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 728b86c..4cc538c 100755 --- a/RR-2-patch-test-case/RR-2-patch-test.py +++ b/RR-2-patch-test-case/RR-2-patch-test.py @@ -85,10 +85,10 @@ isRichards = { } ##################### MESH ##################################################### -mesh_resolution = 6 +mesh_resolution = 100 ##################### TIME ##################################################### timestep_size = 4*0.0001 -number_of_timesteps = 200 +number_of_timesteps = 3000 # 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 @@ -115,8 +115,8 @@ L = {# lambda_param = {# # subdom_num : lambda parameter for the L-scheme - 1 : {'wetting' :4},# - 2 : {'wetting' :4} + 1 : {'wetting' :100},# + 2 : {'wetting' :100} } ## relative permeabilty functions on subdomain 1 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 c078425..daf7b63 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 = 40 -timestep_size = 0.001 -number_of_timesteps = 2000 +mesh_resolution = 20 +timestep_size = 0.0001 +number_of_timesteps = 100 # 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 @@ -113,18 +113,18 @@ porosity = {# L = {# # subdom_num : subdomain L for L-scheme - 1 : {'wetting' :0.3, + 1 : {'wetting' :0.4, 'nonwetting': 0.8},# - 2 : {'wetting' :0.3, + 2 : {'wetting' :0.4, 'nonwetting': 0.8} } lambda_param = {# # subdom_num : lambda parameter for the L-scheme - 1 : {'wetting' :140, - 'nonwetting': 2400},# - 2 : {'wetting' :140, - 'nonwetting': 2400} + 1 : {'wetting' :10, + 'nonwetting': 100},# + 2 : {'wetting' :10, + 'nonwetting': 100} } ## relative permeabilty functions on subdomain 1 -- GitLab