Source code for modsim_package.utilities
"""Python 3 utilities not compatible with Abaqus Python 2"""
import sys
import typing
import pathlib
import yaml
import waves
import pandas
import xarray
import matplotlib.pyplot
[docs]
def combine_data(input_files, group_path, concat_coord):
"""Combine input data files into one dataset
:param list input_files: list of path-like or file-like objects pointing to h5netcdf files
containing Xarray Datasets
:param str group_path: The h5netcdf group path locating the Xarray Dataset in the input files.
:param str concat_coord: Name of dimension
:returns: Combined data
:rtype: xarray.DataArray
"""
paths = [pathlib.Path(input_file).resolve() for input_file in input_files]
data_generator = (
xarray.open_dataset(path, group=group_path, engine="h5netcdf").assign_coords({concat_coord: path.parent.name})
for path in paths
)
combined_data = xarray.concat(data_generator, concat_coord)
combined_data.close()
return combined_data
[docs]
def merge_parameter_study(parameter_study_file, combined_data):
"""Merge parameter study to existing dataset
:param str parameter_study_file: path-like or file-like object containing the parameter study dataset. Assumes the
h5netcdf file contains only a single dataset at the root group path, .e.g. ``/``.
:param xarray.DataArray combined_data: XArray Dataset that will be merged.
:returns: Combined data
:rtype: xarray.DataArray
"""
parameter_study = xarray.open_dataset(parameter_study_file, engine="h5netcdf")
combined_data = combined_data.merge(parameter_study)
parameter_study.close()
return combined_data
[docs]
def save_plot(combined_data, x_var, y_var, selection_dict, concat_coord, output_file):
"""Save scatter plot with given x and y labels
:param xarray.DataArray combined_data: XArray Dataset that will be plotted.
:param str x_var: The independent (x-axis) variable key name for the Xarray Dataset "data variable"
:param str y_var: The dependent (y-axis) variable key name for the Xarray Dataset "data variable"
:param dict selection_dict: Dictionary to define the down selection of data to be plotted. Dictionary ``key: value``
pairs must match the data variables and coordinates of the expected Xarray Dataset object.
:param str concat_coord: Name of dimension for which you want multiple lines plotted.
:param str output_file: The plot file name. Relative or absolute path.
"""
# Plot
combined_data.sel(selection_dict).plot.scatter(x=x_var, y=y_var, hue=concat_coord)
matplotlib.pyplot.title(None)
matplotlib.pyplot.savefig(output_file)
[docs]
def save_table(combined_data, selection_dict, output_file):
"""Save csv table
:param xarray.DataArray combined_data: XArray Dataset to be written as a CSV.
:param dict selection_dict: Dictionary to define the down selection of data to be plotted. Dictionary ``key: value``
pairs must match the data variables and coordinates of the expected Xarray Dataset object.
:param str output_file: The CSV file name. Relative or absolute path.
"""
combined_data.sel(selection_dict).to_dataframe().to_csv(output_file)
[docs]
def sort_dataframe(dataframe, index_column="time", sort_columns=["time", "set_name"]):
"""Return a sorted dataframe and set an index
1. sort columns by column name
2. sort rows by column values ``sort_columns``
3. set an index
:returns: sorted and indexed dataframe
:rtype: pandas.DataFrame
"""
return dataframe.reindex(sorted(dataframe.columns), axis=1).sort_values(sort_columns).set_index(index_column)
[docs]
def csv_files_match(current_csv, expected_csv, index_column="time", sort_columns=["time", "set_name"]):
"""Compare two pandas DataFrame objects and determine if they match.
:param pandas.DataFrame current_csv: Current CSV data of generated plot.
:param pandas.DataFrame expected_csv: Expected CSV data.
:returns: True if the CSV files match, False otherwise.
:rtype: bool
"""
current = sort_dataframe(current_csv, index_column=index_column, sort_columns=sort_columns)
expected = sort_dataframe(expected_csv, index_column=index_column, sort_columns=sort_columns)
try:
pandas.testing.assert_frame_equal(current, expected)
except AssertionError as err:
print(
f"The CSV regression test failed. Data in expected CSV file and current CSV file do not match.\n{err}",
file=sys.stderr,
)
equal = False
else:
equal = True
return equal
[docs]
def write_study_definition(
study_definition: typing.Union[waves.parameter_generators.ParameterGenerator, dict],
path: pathlib.Path,
alias: str,
) -> None:
"""Write parameter study definition files to path
Calls parameter generator write function or writes a YAML dictionary
:param study_definition: Parameter study definition. WAVES parameter generator or dictionary.
:param path: Output directory
:param alias: Parameter study dictionary file name
"""
if isinstance(study_definition, waves.parameter_generators.ParameterGenerator):
study_definition.write()
elif isinstance(study_definition, dict):
study_path = path / f"{alias}.yaml"
study_path.parent.mkdir(parents=True, exist_ok=True)
with open(study_path, "w") as study_file:
study_file.write(yaml.safe_dump(study_definition))