The LDDsimulation Code
This folder contains the actual LDD simulation code. To facilitate development, we give a brief description of the files. As the code has been written with readability in mind, we only highlight certain methods. Other methods should be pretty self explanatory.
LDDsimulation.py
If you want to read the code, this is where you should
start.
This file defines the core and soul of the LDD simulation code.
It defines the class LDDsimulation that contains methods to setup the
simulation and run it.
Each usecase file in ../Usecases essentially
sets up an instance of this class and defines
all parameters needed by the LDDsimulation.set_parameters(kwrgs**) function
which gets called by the main() of each usecase (more precisely by
helpers.run_simulation()).
The LDDsimulation.initialise() method calls several functions that initialise
all subdomains, interfaces, meshes, markerfunctions, solution files and so on.
The LDDsimulation.run() method implements the timestepping and calls the solver, the LDDsimulation.LDDsolver(**kwrgs) method. Some postprocessing is implemented here to calculate some errors and part of the write out to disk
happens here.
The LDDsolver methods implements the L-iteration loop for each new timesten as well as the loop over the subdomains. The stopping criterion is implemented here aswell.
If you want to implement parallelisation, this is where it needs to happen.
Some attempts have been made to do this, but time was running short.
Some commented out code can be found here which might or might not be usefull for attempting to parallelise the code.
domainPatch.py
This file contain the class definition of the domainPatch class which is the main data structure of the LDD simulation code.
The programming paradigm was:
PARADIGM: Each subdomain contains all information need and is completely independent of other subdomains.
All information means:
- the model. Each subdomain not only knows which model it assumes, it also provides the methods to construct the linear form that is given to the linear solver. This is done in the
governing_problem(*kwrgs)method. This has been done because the L-linearised form is considered the discretised model. Methods in charge of communicating dofs to interfaces for exchange of information with neighbours is also implemente in this class. - the model data: All material parameters and fucntions.
- meshes and markes: Each subdomain holds their own submesh of the global mesh including dof maps etc.
- interfaces and boundaries: Each subdomain knows which parts of the boundary are outer boundaries or interfaces to other subdomains. Interface objects are also available to each subdomain, so that communication of dofs can happen the the interface objects. (See
class boundary_and_ineterface). - function spaces and functions: Each subdomain stores their functionspaces as well as functions in which to store iterates.
We briefly highlight some of the methods:
-
governing_problem(*kwrgs): This method gets called byLDDsimulation.Lsolver_step(*kwrgs)and assembles the form for the LDD solver inufllanguage. It also calls the methods that calculate the gli terms that decouple the problems. The models are hardcoded here. If you want to implement LDD methods for other models, this is were it needs to happen. -
calc_gli_term(*kwrgs): Method that gets calle by thegoverning_problem(*kwrgs)method and calculates the gli term of the current iteration step. This method also communicates dofs to the interface objects. Note that this method needs to be revisited if parallelisation is to be implemented. Similarly, if more general types of gli methods need to be considered, this is where it needs to happen. -
calc_gl0_term(*kwrgs): Method that gets called by theLDDsimulation.prepare_subdomain(*kwrgs)within theLDDsimulation.prepare_LDDsolver(*kwrgs)method to calculate the initial gl0 term at the beginning of the calculation of the solution of a new timestep. As the normal flux gets calculated explicitly here, parts of the model are hard coded in this method aswell. Bare that in mind, when implementing new models. A layer of abstraction for the flux might be usefull here.
boundary_and_interface.py
This files contains two classes a general BoundaryPart class and a derivative of that, the interface
-
BoundaryPart: This class basically implements aninsidemethod to mark marker functions on a mesh along a list of dolfin points forming a polygonal chain (which the interfaces are). -
interface: interface is a subclass ofBoundaryPartproviding methods to deterime which dofs of an FEM function space actually lie on the interface. In addition, dictionaries to save and communicate gli dofs are objects of this class. In an LDD simulation, each interface holds the information which two subdomains are adjacent to it and this can be queried by the subdomain.
A global list of all indices is saved as dictionary LDDsimulation.interfase in an instance of LDDsimulation and each subdomain of class domainPatch gets this list along with information which of these interfaces actually belong to that subdomain.
solutionFile.py
This file defines a class SolutionFile(dolfin.XDMFFile) around the dolfin
XDMFFile class and sets some parameters for the files in which the solution
gets saved.
domainSubstructuring.py
This file defines various subdomains and their subdomain substructurings to be used in the simulation. A lengthy explanation on how to define your own substructurings is given in the file itself. Most likely, you will learn how to to this by looking at the examples given in the file.
functions.py
This file defines data functions like relative permeabilities and pc-S relationships along with methods generate_relative_permeability_dicts and
generate_Spc_dicts to generate dictionaries of callables that get passed to
the simulation class.
This was done in an attempt to tidy the usecases and have a central place in which to define data functions.
New relative permeabilites and pc-S relationships must be specified here and
the corresponding generator functions
generate_relative_permeability_dicts and generate_Spc_dicts need to be adjusted accordingly.
helpers.py
This file contains some helper functions which are mostly used to keep the usecase files tidier. It should be clear from the function names what each function is used for. The following is noteworthy if you start developing:
-
run_simulation(**kwrgs): This function gets called by the main of each usecase and sets up and runs an instance ofclass LDDsimulation. Note that if you add features to the latter, say you add parameters or generally change the parameter structure, this function will most likely have to be changed accordingly. -
generate_exact_solution_expressions(**kwrgs): This function generates the initial condition, exact solution as well as corresponding source term dictionaries given a symbolic exact solution expression as input. This means that the models of the code are hardcoded in this function. If you want to add other models of the code and test with exact solutions, this function will have to be adjusted!