""" Handling of studies """
import typing
from abc import abstractmethod, ABC
from more.api.simulation.studies.job_setup import JobCreationContext
from more.api.simulation.studies.result_writing_strategy_setup import ResultWritingStrategySetup
[docs]
class StudiesSetup(ABC):
""" Entry point for the studies API
You should create this object using the :class:`~api.simulation.simulation_setup.SimulationSetup` object.
"""
def __init__(self, item):
self._study = item
def _get_wrapped_object(self):
return self._study
[docs]
@abstractmethod
def set_study(self, study) -> 'StudiesSetup':
""" Sets the study being edited in this setup object.
.. admonition:: Deprecated
:class: warning
`set_study` will be removed in a future MORe release, it is replaced by
the :class:`~more.api.simulation.simulation_setup.SimulationSetup`
.. admonition:: Example
:class: note
This method is invoked internally when using the :class:`~api.simulation.simulation_setup.SimulationSetup`
..
>>> import more.project
>>> proj = more.project.Project()
>>> from more.api import ApiGateway
>>> api = ApiGateway(proj=proj)
>>> simulation_setup = api.create_simulation_setup()
..
>>> created_study_setup = simulation_setup.create_study_setup().set_name(name='study_name')
>>> study_setup = simulation_setup.get_study_setup(name='study_name') # invoked internally here, the study must already exist
..
>>> created_study_setup._study == study_setup._study
True
>>> study_setup.set_study(study=None)
Traceback (most recent call last):
...
ValueError: ...
Parameters
----------
study : StudyTable
A study instance
Returns
-------
self: StudiesSetup
Raises
------
ValueError
Raised if the given study is not an instance of a study
"""
pass
[docs]
@abstractmethod
def set_study_name(self, name: str) -> 'StudiesSetup':
""" Changes the name of the study
Parameters
----------
name: str
The new name of the study
Returns
-------
self: StudiesSetup
"""
pass
[docs]
@abstractmethod
def get_name(self) -> str:
""" Returns the name of the object
.. admonition:: Example
:class: note
..
>>> import more.project
>>> proj = more.project.Project()
>>> from more.api import ApiGateway
>>> api = ApiGateway(proj=proj)
>>> simulation_setup = api.create_simulation_setup()
>>> study_setup = simulation_setup.create_study_setup().set_name(name='study_name')
>>> study_setup.set_name(name='new_name')
<more...>
>>> study_setup.get_name()
'new_name'
Returns
-------
name: str
The name of the object
"""
pass
[docs]
@abstractmethod
def set_name(self, name: str, resolve_duplicate_name: bool = False) -> 'StudiesSetup':
""" Changes the name of the study
.. admonition:: Example
:class: note
..
>>> import more.project
>>> proj = more.project.Project()
>>> from more.api import ApiGateway
>>> api = ApiGateway(proj=proj)
>>> simulation_setup = api.create_simulation_setup()
>>> study_setup = simulation_setup.create_study_setup().set_name(name='study_name')
>>> study_setup.set_name(name='new_name')
<more...>
>>> second_study_setup = simulation_setup.create_study_setup() \\
... .set_name(name='new_name', resolve_duplicate_name=True)
>>> second_study_setup.get_name()
'new_name 1'
..
>>> study_setup._study.name
'new_name'
Trying to set the name to a non-string value
>>> study_setup.set_name(name=None)
Traceback (most recent call last):
...
TypeError: A name of a study ...
>>> study_setup.set_name('new_name')
Traceback (most recent call last):
...
more.api.exceptions.api_exception.NameNotUniqueError: ...
Parameters
----------
resolve_duplicate_name: bool
Whether to automatically assign a new name when the chosen one is already taken
name: str
The new name of the study
Returns
-------
self: StudiesSetup
Raises
------
TypeError
Raised if the given name is not a string
NameNotUniqueError
Raised if the given name is not unique
"""
pass
[docs]
@abstractmethod
def add_job(self, parameters_dict: dict) -> 'StudiesSetup':
""" Adds a job from a parameters dict
.. admonition:: Deprecated
:class: warning
`add_job` will be removed in a future MORe release, it is replaced by
:meth:`.create_job_setup` which streamlines the job creation process
Parameters
----------
parameters_dict: dict
The parameters dict consisting of parameter uuid's and parameters to add as a new job to the study
Returns
-------
self: StudiesSetup
"""
pass
[docs]
@abstractmethod
def remove_job(self, job_label: typing.Optional[str] = None) -> 'StudiesSetup':
""" Removes a job from the study
.. admonition:: Example
:class: note
To remove a job by label:
..
>>> import more.project
>>> proj = more.project.Project()
>>> from more.api import ApiGateway
>>> api = ApiGateway(proj=proj)
>>> simulation_setup = api.create_simulation_setup()
>>> study_setup = simulation_setup.create_study_setup()
>>> job_setup = study_setup.create_job_setup(job_name='Static Job')
>>> job_setup = job_setup.set_general_job_settings_parameter(parameter_name='label', value='first_job') \\
... .create() \\
... .set_general_job_settings_parameter(parameter_name='label', value='second_job') \\
... .create() \\
... .set_general_job_settings_parameter(parameter_name='label', value='third_job') \\
... .create()
..
>>> isinstance(job_setup, JobCreationContext)
True
>>> study_setup.remove_job(job_label='second_job') # Remove the second job
<more...>
..
>>> setup_collections = study_setup._study.get_study_table().study_parameters_setup.setup_collections
>>> len(setup_collections)
2
>>> list(setup_collections[0].values())[0].value
'first_job'
>>> list(setup_collections[1].values())[0].value
'third_job'
Trying to remove a job that does not exist:
>>> study_setup.remove_job(job_label='job_that_does_not_exist')
Traceback (most recent call last):
...
more.api.exceptions.api_exception.NameNotFoundError: ...
Parameters
----------
job_label: str, optional
The label of the job to remove, if none is specified then the last job will be removed
Returns
-------
self: StudiesSetup
Raises
------
NameNotFoundError
Raised if no job with the given label exists
"""
pass
[docs]
@abstractmethod
def create_job_setup(self, job_name: str) -> JobCreationContext:
""" Creates a :class:`~api.simulation.studies.job_setup.JobCreationContext` object for handling job creation for this study
.. admonition:: Example
:class: note
..
>>> import more.project
>>> proj = more.project.Project()
>>> from more.api import ApiGateway
>>> api = ApiGateway(proj=proj)
>>> simulation_setup = api.create_simulation_setup()
>>> study_setup = simulation_setup.create_study_setup()
>>> print(study_setup.get_available_job_type_names()) # Check which job type names are available
[...]
>>> job_setup = study_setup.create_job_setup(job_name='Static Job') # Adds a static job and returns a job creation pipeline object
..
>>> isinstance(job_setup, JobCreationContext)
True
Trying to add a non-existent job type
>>> study_setup.create_job_setup(job_name='non-existent-job-type')
Traceback (most recent call last):
...
more.api.exceptions.api_exception.NameNotFoundError: ...
Parameters
----------
job_name: str
The name of the job type to add
Returns
-------
:class:`~api.simulation.studies.job_setup.JobCreationContext`
An object for setting up the job
Raises
------
NameNotFoundError
Raised if no job type with the given name exists
"""
pass
[docs]
@abstractmethod
def get_available_job_type_names(self) -> typing.List[str]:
""" Get the available job type names
.. admonition:: Example
:class: note
..
>>> import more.project
>>> proj = more.project.Project()
>>> from more.api import ApiGateway
>>> api = ApiGateway(proj=proj)
>>> simulation_setup = api.create_simulation_setup()
>>> study_setup = simulation_setup.create_study_setup()
>>> study_setup.get_available_job_type_names()
[...]
..
>>> list_of_job_type_names = study_setup.get_available_job_type_names()
>>> standard_job_type_names = ['Modal Job', 'Static Job', 'Transient Thermal Job', 'Static Job Aggregation', 'Thermo Mechanical Job', 'Transient Mechanical Job', 'FRF Job', 'Thermal Steady State Job']
>>> all(job_name in list_of_job_type_names for job_name in standard_job_type_names)
True
Returns
-------
list of strings
The list of available job type names to use with the `create_job_setup` method
"""
pass
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
[docs]
@abstractmethod
def execute_study(self, create_simresult_object: bool, custom_data: typing.Optional[typing.Union[dict, list, str, int, float, bool]] = None):
""" Runs the study
.. admonition:: Experimental
:class: warning
'execute_study' returns internal MORe objects that are subject to change, do not use this method in stable code
Parameters
----------
create_simresult_object: bool
Whether to create a simresult object
custom_data: JSON serializable, optional
Custom data that will be stored in the results. Must be JSON serializable (dict, list, str, int, float, or bool).
Raises
------
BusyError
Raised if the study is already running
"""
pass
[docs]
@abstractmethod
def create_result_writing_strategy(self, strategy_type: str) -> ResultWritingStrategySetup:
""" Returns a setup object for a result writing strategy
Raises
------
NameNotFoundError
Raised if no result writing strategy type with the given name exists
"""
pass
[docs]
@abstractmethod
def get_available_results_writing_strategy_names(self) -> typing.List[str]:
""" Returns a list of available writing strategy names
"""
pass