Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/getting_started/CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
OpenCMP Changelog
=================

June 2, 2023 (v1.0.3)

* Added ability for a simulation to resume from the last saved .sol file.

August 11, 2022 (v1.0.2)

* Implemented the DG version fo the multi-component INS code.
Expand Down
5 changes: 1 addition & 4 deletions opencmp/config_functions/base_config_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class ConfigFunctions:
"""

def __init__(self, config_rel_path: str, import_dir: str, mesh: Mesh, t_param: List[Parameter],
new_variables: List[Dict[str, Union[float, CoefficientFunction, GridFunction]]] = None) -> None:
new_variables: List[Dict[str, Union[float, CoefficientFunction, GridFunction]]] = [{}]) -> None:
"""
Initializer

Expand All @@ -43,9 +43,6 @@ def __init__(self, config_rel_path: str, import_dir: str, mesh: Mesh, t_param: L
# Set the run directory for the config functions.
# Files could get accessed at run_dir + '/' + <path>. Make sure that if the config file is in the current
# directory run_dir is specified such that this will still work.
if new_variables is None:
new_variables = [{}]

if '/' in config_rel_path:
idx = config_rel_path[::-1].index('/')
self.run_dir = config_rel_path[:len(config_rel_path) - idx - 1]
Expand Down
9 changes: 2 additions & 7 deletions opencmp/config_functions/boundary_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,8 @@ class BCFunctions(ConfigFunctions):
"""

def __init__(self, config_rel_path: str, import_dir: str, mesh: Mesh, bc_types: List[str],
t_param: List[Parameter] = None,
new_variables: List[Dict[str, Union[float, CoefficientFunction, GridFunction]]] = None) -> None:
if t_param is None:
t_param = [Parameter(0.0)]
if new_variables is None:
new_variables = [{}]

t_param: List[Parameter] = [Parameter(0.0)],
new_variables: List[Dict[str, Union[float, CoefficientFunction, GridFunction]]] = [{}]) -> None:
bc_types = [type.upper() for type in bc_types]
super().__init__(config_rel_path, import_dir, mesh, t_param)

Expand Down
4 changes: 1 addition & 3 deletions opencmp/config_functions/controller_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ class ControllerFunctions(ConfigFunctions):
"""

def __init__(self, config_rel_path: str, import_dir: str, mesh: Mesh, t_param: List[Parameter],
new_variables: List[Dict[str, Union[float, CoefficientFunction, GridFunction]]] = None) -> None:
if new_variables is None:
new_variables = [{}]
new_variables: List[Dict[str, Union[float, CoefficientFunction, GridFunction]]] = [{}]) -> None:
super().__init__(config_rel_path, import_dir, mesh, t_param, new_variables)

tmp_vc_dict = _convert_dict_entries_to_list(self.config.get_one_level_dict('CONTROL_VARIABLES',
Expand Down
29 changes: 10 additions & 19 deletions opencmp/config_functions/expanded_config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@
'component_names': [],
'parameter_names': [],
'velocity_fixed': False,
'run_dir': 'REQUIRED'},
'run_dir': 'REQUIRED',
'resume_from_previous': False},
'VISUALIZATION': {'save_to_file': False,
'save_type': '.sol',
'save_frequency': ['1', 'numit'],
Expand Down Expand Up @@ -103,9 +104,9 @@ def __init__(self, config_file_path: str) -> None:

def get_one_level_dict(self, config_section: str, import_dir: str, mesh: Mesh,
t_param: Optional[List[Parameter]] = None,
new_variables: List[Dict[str,
Union[int, str, float, CoefficientFunction, GridFunction, None]]]
= None,
new_variables: List[Dict[str, Union[int, str, float, CoefficientFunction, GridFunction,
None]]]
= [{}],
all_str: bool = False) -> Tuple[Dict, Dict]:
"""
Function to load parameters from a config file into a single-level dictionary.
Expand Down Expand Up @@ -135,12 +136,10 @@ def get_one_level_dict(self, config_section: str, import_dir: str, mesh: Mesh,
- re_parse_dict: Dictionary containing only parameter values that may need to be re-parsed in the
future.
"""
if new_variables is None:
new_variables = [{}]

dict_one: Dict[str, Union[str, float, CoefficientFunction, list]] = {}
re_parse_dict: Dict[str, Union[str, Callable]] = {}
val_str_lst: Union[str, List] # Just for type-hinting.
val_str_lst: Union[str, List] # Just for type-hinting.
for key in self[config_section]:
if all_str:
# If all_str option is passed none of the parameters should ever need to be re-parsed.
Expand All @@ -167,7 +166,7 @@ def get_two_level_dict(self, config_section: str, import_dir: str, mesh: Mesh,
t_param: Optional[List[Parameter]] = None,
new_variables: List[Dict[str, Union[int, str, float, CoefficientFunction, GridFunction,
None]]]
= None) \
= [{}]) \
-> Tuple[Dict, Dict]:
"""
Function to load parameters from a config file into a two-level dictionary.
Expand Down Expand Up @@ -195,8 +194,6 @@ def get_two_level_dict(self, config_section: str, import_dir: str, mesh: Mesh,
- re_parse_dict: Dictionary containing only parameter values that may need to be re-parsed in the
future.
"""
if new_variables is None:
new_variables = [{}]

# Top level dictionaries.
dict_one: Dict[str, Dict[str, Union[str, float, CoefficientFunction, list]]] = {}
Expand All @@ -214,9 +211,9 @@ def get_two_level_dict(self, config_section: str, import_dir: str, mesh: Mesh,
def get_three_level_dict(self, import_dir: str, mesh: Mesh, t_param: Optional[List[Parameter]] = None,
new_variables: List[Dict[str, Union[int, str, float, CoefficientFunction, GridFunction,
None]]]
= None,
white_list: List[str] = None,
ignore: List[str] = None) -> Tuple[Dict, Dict]:
= [{}],
white_list: List[str] = [],
ignore: List[str] = []) -> Tuple[Dict, Dict]:
"""
Function to load parameters from a config file into a three-level dictionary.

Expand Down Expand Up @@ -249,12 +246,6 @@ def get_three_level_dict(self, import_dir: str, mesh: Mesh, t_param: Optional[Li
- re_parse_dict: Dictionary containing only parameter values that may need to be re-parsed in the
future.
"""
if new_variables is None:
new_variables = [{}]
if white_list is None:
white_list = []
if ignore is None:
ignore = []

# Keys for the top level dictionaries
keys_one = [item for item in self.sections() if item not in ignore]
Expand Down
9 changes: 2 additions & 7 deletions opencmp/config_functions/initial_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,8 @@ class ICFunctions(ConfigFunctions):
Class to hold the initial condition functions.
"""

def __init__(self, config_rel_path: str, import_dir: str, mesh: Mesh, t_param: List[Parameter] = None,
new_variables: List[Dict[str, Union[float, CoefficientFunction, GridFunction]]] = None) -> None:
if t_param is None:
t_param = [Parameter(0.0)]
if new_variables is None:
new_variables = [{}]

def __init__(self, config_rel_path: str, import_dir: str, mesh: Mesh, t_param: List[Parameter] = [Parameter(0.0)],
new_variables: List[Dict[str, Union[float, CoefficientFunction, GridFunction]]] = [{}]) -> None:
super().__init__(config_rel_path, import_dir, mesh, t_param)

# Load the IC dict from the IC configfile.
Expand Down
16 changes: 4 additions & 12 deletions opencmp/config_functions/load_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@


def parse_str(string: str, import_dir: str, t_param: Optional[List[Parameter]],
new_variables: List[Dict[str, Union[int, str, float, CoefficientFunction, GridFunction]]] = None,
filetypes: List[str] = None, mesh: Optional[Mesh] = None) \
new_variables: List[Dict[str, Union[int, str, float, CoefficientFunction, GridFunction]]] = [{}],
filetypes: List[str] = ['.vol', '.sol', '.vtk'], mesh: Optional[Mesh] = None) \
-> Tuple[Union[str, float, CoefficientFunction, list], Union[str, bool, Callable]]:
"""
Checks if a string appears to be a path to a file and if not parses the string into Python code.
Expand All @@ -45,10 +45,6 @@ def parse_str(string: str, import_dir: str, t_param: Optional[List[Parameter]],
- variable_eval: Whether or not the expression contains any of the new model variables (would need to be
re-parsed if their values change).
"""
if new_variables is None:
new_variables = [{}]
if filetypes is None:
filetypes = ['.vol', '.sol', '.vtk']

if not isinstance(string, str):
# Likely got a default value from config_defaults.
Expand Down Expand Up @@ -82,8 +78,8 @@ def parse_str(string: str, import_dir: str, t_param: Optional[List[Parameter]],


def convert_str_to_dict(string: str, import_dir: str, t_param: Optional[List[Parameter]], mesh: Mesh,
new_variables: List[Dict[str, Union[int, str, float, CoefficientFunction, GridFunction]]] = None,
filetypes: List[str] = None, all_str: bool = False) -> Tuple[Dict, Dict]:
new_variables: List[Dict[str, Union[int, str, float, CoefficientFunction, GridFunction]]] = [{}],
filetypes: List[str] = ['.vol', '.sol', '.vtk'], all_str: bool = False) -> Tuple[Dict, Dict]:
"""
Function to convert a string into a dict. The values of the dict may be parsed into Python
code or left as strings.
Expand All @@ -105,10 +101,6 @@ def convert_str_to_dict(string: str, import_dir: str, t_param: Optional[List[Par
- param_dict: Dictionary of the parameters from the string.
- re_parse_dict: Dictionary containing only parameter values that may need to be re-parsed in the future.
"""
if new_variables is None:
new_variables = [{}]
if filetypes is None:
filetypes = ['.vol', '.sol', '.vtk']

# Replace extraneous whitespace characters.
param_tmp = string.replace('\t', '')
Expand Down
9 changes: 2 additions & 7 deletions opencmp/config_functions/model_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,9 @@ class ModelFunctions(ConfigFunctions):
Class to hold the model functions and parameters.
"""

def __init__(self, config_rel_path: str, import_dir: str, mesh: Mesh, t_param: List[Parameter] = None,
new_variables: List[Dict[str, Union[int, str, float, CoefficientFunction, GridFunction, None]]] = None)\
def __init__(self, config_rel_path: str, import_dir: str, mesh: Mesh, t_param: List[Parameter] = [Parameter(0.0)],
new_variables: List[Dict[str, Union[int, str, float, CoefficientFunction, GridFunction, None]]] = [{}])\
-> None:
if t_param is None:
t_param = [Parameter(0.0)]
if new_variables is None:
new_variables = [{}]

super().__init__(config_rel_path, import_dir, mesh, t_param)

# Load the model functions/parameters/components dict from the main config file.
Expand Down
4 changes: 1 addition & 3 deletions opencmp/config_functions/parse_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ def eval_item(string: str, import_dir: str, t_param: Optional[List[Parameter]],
return val, variable_eval


def eval_python(string: str, import_dir: str, mesh: Optional[Mesh] = None, new_variables: List[Dict[str, Any]] = None,
def eval_python(string: str, import_dir: str, mesh: Optional[Mesh] = None, new_variables: List[Dict[str, Any]] = {},
t_param: Optional[List[Parameter]] = None, time_step: Optional[int] = None) \
-> Tuple[Union[str, float, CoefficientFunction, bool, None], Union[str, bool, Callable]]:
"""
Expand All @@ -328,8 +328,6 @@ def eval_python(string: str, import_dir: str, mesh: Optional[Mesh] = None, new_v
in its place. If the expression involved importing a Python function that Python function is returned in
place of variable_eval.
"""
if new_variables is None:
new_variables = {}

# Remove whitespace in case the string ends up being parsed manually.
string = string.replace(' ', '')
Expand Down
9 changes: 2 additions & 7 deletions opencmp/config_functions/reference_solutions.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,8 @@ class RefSolFunctions(ConfigFunctions):
Class to hold the reference solutions.
"""

def __init__(self, config_rel_path: str, import_dir: str, mesh: Mesh, t_param: List[Parameter] = None,
new_variables: List[Dict[str, Union[float, CoefficientFunction, GridFunction]]] = None) -> None:
if t_param is None:
t_param = [Parameter(0.0)]
if new_variables is None:
new_variables = [{}]

def __init__(self, config_rel_path: str, import_dir: str, mesh: Mesh, t_param: List[Parameter] = [Parameter(0.0)],
new_variables: List[Dict[str, Union[float, CoefficientFunction, GridFunction]]] = [{}]) -> None:
super().__init__(config_rel_path, import_dir, mesh, t_param)

# Load the reference solution dict from the reference solution configfile.
Expand Down
8 changes: 2 additions & 6 deletions opencmp/diffuse_interface/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ def nonconformal_subdomain_2d(boundary_lst: List, vertices: List, N: List[int],

def split_nonconformal_subdomains_2d(boundary_lst: List, vertices: Dict, N: List[int], scale: List[float],
offset: List[float], lmbda_overlap: Union[float, bool] = False,
remainder: bool = False, centroid: Dict = None) -> Dict[str, ndarray]:
remainder: bool = False, centroid: Dict = {}) -> Dict[str, ndarray]:
"""
Function to generate all BC masks for a 2D diffuse interface simulation.

Expand All @@ -293,8 +293,6 @@ def split_nonconformal_subdomains_2d(boundary_lst: List, vertices: Dict, N: List
Returns:
Dictionary of numpy array masks.
"""
if centroid is None:
centroid = {}

shape = (int(N[0] + 1), int(N[1] + 1))

Expand Down Expand Up @@ -416,7 +414,7 @@ def nonconformal_subdomain_3d(face_lst: ndarray, vertices: str, N: List[int], sc

def split_nonconformal_subdomains_3d(face_lst: List, vertices: Dict[str, str], N: List[int], scale: List[float],
offset: List[float], lmbda_overlap: Union[float, bool] = False,
remainder: bool = False, centroid: Dict = None) -> Dict[str, ndarray]:
remainder: bool = False, centroid: Dict = {}) -> Dict[str, ndarray]:
"""
Function to generate all BC masks for a 3D diffuse interface simulation.

Expand All @@ -440,8 +438,6 @@ def split_nonconformal_subdomains_3d(face_lst: List, vertices: Dict[str, str], N
Returns:
Dictionary of numpy array masks.
"""
if centroid is None:
centroid = {}

shape = (int(N[0] + 1), int(N[1] + 1), int(N[2] + 1))

Expand Down
10 changes: 5 additions & 5 deletions opencmp/helpers/saving.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ def __init__(self, model: Model, quiet: bool = False) -> None:
print('Can\'t output to file type {}.'.format(base_type))

self.save_dir = model.config.get_item(['OTHER', 'run_dir'], str, quiet) + '/output/'
self.save_dir_sol = model.config.get_item(['OTHER', 'run_dir'], str, quiet) + '/output/' + model.name + '_sol/'
self.save_dir_vtu = model.config.get_item(['OTHER', 'run_dir'], str, quiet) + '/output/' + model.name + '_vtu/'
self.save_dir_sol = model.config.get_item(['OTHER', 'run_dir'], str, quiet) + '/output/' + model.name() + '_sol/'
self.save_dir_vtu = model.config.get_item(['OTHER', 'run_dir'], str, quiet) + '/output/' + model.name() + '_vtu/'

# Specifically for diffuse interface rigid body motion.
self.save_dir_phi = model.config.get_item(['OTHER', 'run_dir'], str, quiet) + '/output_phi/'
self.save_dir_phi_sol = model.config.get_item(['OTHER', 'run_dir'], str, quiet) + '/output_phi/' + model.name + '_sol/'
self.save_dir_phi_vtu = model.config.get_item(['OTHER', 'run_dir'], str, quiet) + '/output_phi/' + model.name + '_vtu/'
self.save_dir_phi_sol = model.config.get_item(['OTHER', 'run_dir'], str, quiet) + '/output_phi/' + model.name() + '_sol/'
self.save_dir_phi_vtu = model.config.get_item(['OTHER', 'run_dir'], str, quiet) + '/output_phi/' + model.name() + '_vtu/'

self.base_filename_sol = self.save_dir_sol + model.name + '_'
self.base_filename_sol = self.save_dir_sol + model.name() + '_'
self.base_filename_phi_sol = self.save_dir_phi_sol + 'phi' + '_'
self.base_subdivision = model.config.get_item(['VISUALIZATION', 'subdivision'], int, quiet)

Expand Down
32 changes: 20 additions & 12 deletions opencmp/models/base_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,7 @@ def __init__(self, config: ConfigParser, t_param: List[Parameter]) -> None:
config: A configparser object loaded with config file.
t_param: List of parameters representing the current and previous timestep times.
"""
# The name of the model (helper variable). It is the name of the class.
self.name = self.__class__.__name__.lower()

logging.info('Initializing model: ' + self.name)

# Remove the trailing "dim" from the model name if the Diffuse Interface Method version is used
# Lets us continue using "Poisson" or "INS" in config files without adding the DIM
if "dim" == self.name[-3:]:
self.name = self.name[:-3]

logging.info('Initializing model: ' + self.name())
# Set config file.
self.config = config

Expand Down Expand Up @@ -223,7 +214,7 @@ def __init__(self, config: ConfigParser, t_param: List[Parameter]) -> None:

# Load initial condition.
self.IC = self.construct_gfu_ic()
self.ic_functions.set_initial_conditions(self.IC, self.mesh, self.name, self.model_components_ic)
self.ic_functions.set_initial_conditions(self.IC, self.mesh, self.name(), self.model_components_ic)

# 2/2: Create BCs
# Now that we have the FES, we can load in the bc gridfunctions
Expand Down Expand Up @@ -631,7 +622,7 @@ def update_model_variables(self, updated_gfu: Union[GridFunction, List[ProxyFunc
# Update the initial conditions.
self.ic_functions.update_initial_conditions(self.t_param, self.update_variables, self.mesh)
self.IC = self.construct_gfu_ic()
self.ic_functions.set_initial_conditions(self.IC, self.mesh, self.name, self.model_components)
self.ic_functions.set_initial_conditions(self.IC, self.mesh, self.name(), self.model_components)

if ref_sol_update:
# Update the reference solutions.
Expand All @@ -649,6 +640,23 @@ def update_timestep(self, gfu: GridFunction, gfu_0: GridFunction) -> None:

gfu_0.vec.data = gfu.vec

@classmethod
def name(cls):
"""
Helper function to generate a readable version of the class model name.

:return:
The formatted name of this model class.
"""
name = cls.__name__.lower()

# Remove the trailing "dim" from the model name if the Diffuse Interface Method version is used
# Lets us continue using "Poisson" or "INS" in config files without adding the DIM
if "dim" == name[-3:]:
name = name[:-3]

return name

@staticmethod
@abstractmethod
def allows_explicit_schemes() -> bool:
Expand Down
Loading