"""This module is responsible for handling the creation of jobs in studies
"""
import typing
from abc import abstractmethod, ABC
[docs]
class JobCreationContext(ABC):
""" This class handles the creation of jobs in studies.
Creation of this class should happen through the API Gateway, see the example:
The variable 'job_setup' will hold a reference to an object of this class
.. 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
>>> print("Available general parameters: {}".format(job_setup.get_general_job_settings_description())) # To check which general settings are available
Available general parameters: "job_type": Job type parameter ...
>>> print("Available job parameters: {}".format(job_setup.get_job_type_specific_settings_description())) # To check which general settings are available
Available job parameters: "single_load_case_choice": Single list choice parameter ...
This class works by first preparing the job and then applying the changes to the study using the :meth:`~.create` method as in the example given:
.. admonition:: Example
:class: note
Assuming that the 'job_setup' variable holds the reference from the example above:
>>> lcc_setup = simulation_setup.create_load_case_container_setup().set_name('example_load_case_container')
..
>>> from more.api.simulation.load_cases.load_case_container_setup import LoadCaseContainerSetup
>>> isinstance(lcc_setup, LoadCaseContainerSetup)
True
>>> study_setup.add_tags(tags=['some_tag'])
<more...>
>>> job_setup = job_setup.set_general_job_settings_parameter(parameter_name='tags', value=['some_tag']) \\
... .set_general_job_settings_parameter(parameter_name='label', value='example_job') \\
... .set_job_specific_parameter(parameter_name='single_load_case_choice', value='example_load_case_container') \\
... .create()
..
>>> isinstance(job_setup, JobCreationContext)
True
>>> from more.design_parameters.utils import get_delegated_name_key_dict
>>> general_job_settings = proj.simulation.general_job_settings
>>> general_name_key_dict = get_delegated_name_key_dict(general_job_settings, as_uuid=True)
>>> label_id = general_name_key_dict['label']
>>> tags_id = general_name_key_dict['tags']
>>> job_type_id = general_name_key_dict['job_type']
>>> job_specific_name_key_dict = get_delegated_name_key_dict(job_setup._job_creation_pipeline.job_type_specific_settings, as_uuid=True)
>>> single_load_case_choice_id = job_specific_name_key_dict['single_load_case_choice']
>>> created_job_dict = proj.simulation.study_container.elements[0].get_study_table().study_parameters_setup.setup_collections[0]
>>> created_job_dict[label_id].value
'example_job'
>>> created_job_dict[tags_id].value
[Tag(name='some_tag')]
>>> created_job_dict[job_type_id].value
<class 'more.simulation_package.jobs.static_analysis.StaticJobBuilder'>
>>> created_job_dict[single_load_case_choice_id].value.name
'example_load_case_container'
>>> created_job_dict[single_load_case_choice_id].value
<more...>
>>> len(created_job_dict)
4
"""
def __init__(self, study_parameters_table_setup, job_name):
self._study_parameters_table_setup = study_parameters_table_setup
self._job_creation_pipeline = self._create_job_cretion_pipeline(study_parameters_table_setup=study_parameters_table_setup, job_name=job_name)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.create()
@abstractmethod
def _create_job_cretion_pipeline(self, study_parameters_table_setup, job_name):
pass
[docs]
@abstractmethod
def create(self) -> 'JobCreationContext':
""" Adds a job to the Study with the settings that were added before.
.. 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()
>>> job_setup = study_setup.create_job_setup(job_name='Static Job')
>>> job_setup.set_general_job_settings_parameter(parameter_name='label', value='first_job') \\
... .create()
<more...>
..
>>> isinstance(job_setup, JobCreationContext)
True
..
>>> setup_collections = study_setup._study.get_study_table().study_parameters_setup.setup_collections
>>> len(setup_collections)
1
>>> list(setup_collections[0].values())[0].value
'first_job'
Returns
-------
self: JobCreationContext
"""
pass
[docs]
@abstractmethod
def set_parameter(self, obj: typing.Any, parameter_name: str, value: typing.Any) -> 'JobCreationContext':
""" Adds a tunable parameter to this job
.. 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()
>>> job_setup = study_setup.create_job_setup(job_name='Static Job') # Adds a static job and returns a job creation pipeline object
..
>>> prop = proj.comp.add_link_properties(physics='mech')
>>> _ = prop.add_property(physics='mech', kind='elastic_joint')
>>> prop.name = 'property_name'
>>> particular_property = proj.comp.find_link_properties(linkpropname='property_name').properties[0] # Assumes that a link property with this names exists and has at least one particular property
>>> print(job_setup.get_tunable_parameters_description_for_object(obj=particular_property)) # Shows the parameters available to the supplied object
"ku": Float parameter - ...
>>> job_setup.set_parameter(obj=particular_property, parameter_name='ku', value=1e6) \\
... .create()
<more...>
>>> # Setup objects are interpreted as if they were their underlying objects
>>> load_setup = simulation_setup \\
... .create_load_case_container_setup() \\
... .create_load_case_setup(lc_type='Mechanical load case') \\
... .create_load_setup(load_type='Link load')
>>> job_setup.set_parameter(obj=load_setup, parameter_name='u', value=1e6)
<more...>
..
>>> from more.design_parameters.utils import get_delegated_name_key_dict
>>> general_job_settings = proj.simulation.general_job_settings
>>> general_name_key_dict = get_delegated_name_key_dict(general_job_settings, as_uuid=True)
>>> job_type_id = general_name_key_dict['job_type']
>>> particular_property_name_key_dict = get_delegated_name_key_dict(particular_property, as_uuid=True)
>>> ku_id = particular_property_name_key_dict['ku']
>>> created_job_dict = proj.simulation.study_container.elements[0].get_study_table().study_parameters_setup.setup_collections[0]
>>> created_job_dict[job_type_id].value
<class 'more.simulation_package.jobs.static_analysis.StaticJobBuilder'>
>>> created_job_dict[ku_id].value
1000000.0
>>> len(created_job_dict)
3
>>> job_setup.set_parameter(obj=particular_property, parameter_name='ku', value='a string is clearly not a float')
Traceback (most recent call last):
...
more.api.exceptions.api_exception.NotCompatibleError: ...
>>> job_setup.set_parameter(obj=None, parameter_name='ku', value=1e6)
Traceback (most recent call last):
...
more.api.exceptions.api_exception.NameNotFoundError: ...
Returns
-------
self: JobCreationContext
Raises
------
NotCompatibleError
Raised if a wrong value is given for the parameter
NameNotFoundError
Raised if the given object has no parameter with the given name
"""
pass
[docs]
@abstractmethod
def set_job_specific_parameter(self, parameter_name: str, value: typing.Any) -> 'JobCreationContext':
"""Sets a tunable job specific parameter to a specific value for this job
.. 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()
>>> job_setup = study_setup.create_job_setup(job_name='FRF Job')
>>> print("Available job parameters: {}".format(job_setup.get_job_type_specific_settings_description())) # To check which general settings are available
Available job parameters: ...
>>> job_setup.set_job_specific_parameter(parameter_name='n_points', value=100) \\
... .create()
<more...>
..
>>> setup_collections = study_setup._study.get_study_table().study_parameters_setup.setup_collections
>>> len(setup_collections)
1
>>> from more.design_parameters.utils import get_delegated_name_key_dict
>>> job_specific_name_key_dict = get_delegated_name_key_dict(job_setup._job_creation_pipeline.job_type_specific_settings, as_uuid=True)
>>> n_points_id = job_specific_name_key_dict['n_points']
>>> created_job_dict = proj.simulation.study_container.elements[0].get_study_table().study_parameters_setup.setup_collections[0]
>>> created_job_dict[n_points_id].value
100
>>> job_setup.set_job_specific_parameter(parameter_name='n_points', value='a string is clearly not an integer')
Traceback (most recent call last):
...
more.api.exceptions.api_exception.NotCompatibleError: ...
>>> job_setup.set_job_specific_parameter(parameter_name='some_property_that_does_not_exist', value=1e6)
Traceback (most recent call last):
...
more.api.exceptions.api_exception.NameNotFoundError: ...
Parameters
----------
parameter_name: str
The name of the job specific parameter to set
value: Any
The value to set for the job specific parameter
Returns
-------
self: JobCreationContext
Raises
------
NotCompatibleError
Raised if a wrong value type is given for the job type specific settings parameter
NameNotFoundError
Raised if the job type specific settings do not have a parameter with the given name
"""
pass
[docs]
@abstractmethod
def set_general_job_settings_parameter(self, parameter_name: str, value: typing.Any) -> 'JobCreationContext':
"""Sets a tunable parameter available in the 'Study settings' tab to a specific value for this job
.. 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()
>>> job_setup = study_setup.create_job_setup(job_name='FRF Job')
>>> print("Available general parameters: {}".format(job_setup.get_general_job_settings_description())) # To check which general settings are available
Available general parameters: "job_type": Job type parameter ...
>>> job_setup = job_setup.set_general_job_settings_parameter(parameter_name='save_result', value=False) \\
... .create()
..
>>> isinstance(job_setup, JobCreationContext)
True
>>> setup_collections = study_setup._study.get_study_table().study_parameters_setup.setup_collections
>>> len(setup_collections)
1
>>> from more.design_parameters.utils import get_delegated_name_key_dict
>>> general_job_settings = proj.simulation.general_job_settings
>>> general_name_key_dict = get_delegated_name_key_dict(general_job_settings, as_uuid=True)
>>> save_result_id = general_name_key_dict['save_result']
>>> created_job_dict = proj.simulation.study_container.elements[0].get_study_table().study_parameters_setup.setup_collections[0]
>>> created_job_dict[save_result_id].value
False
>>> job_setup.set_general_job_settings_parameter(parameter_name='some_property_that_does_not_exist', value=1e6)
Traceback (most recent call last):
...
more.api.exceptions.api_exception.NameNotFoundError: ...
Parameters
----------
parameter_name: str
The name of tunable parameter
value: Any
The value to set
Returns
-------
self: JobCreationContext
Raises
------
NotCompatibleError
Raised if a wrong value type is given for the general job settings
NameNotFoundError
Raised if the general job settings do not have a parameter with the given name
"""
pass
[docs]
@abstractmethod
def set_running_job_settings_parameter(self, parameter_name: str, value: typing.Any) -> 'JobCreationContext':
""" Deprecated version of :meth:`~.set_general_job_settings_parameter`
.. admonition:: Deprecated
:class: warning
`set_running_job_settings_parameter` will be removed in a future MORe release, it is replaced by :meth:`~.set_parameter`
"""
pass
[docs]
@abstractmethod
def get_general_job_settings_description(self) -> str:
""" Returns a description of which settings are available for this study in the 'Study settings' tab
.. 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()
>>> job_setup = study_setup.create_job_setup(job_name='FRF Job')
>>> print("Available general parameters: {}".format(job_setup.get_general_job_settings_description())) # To check which general settings are available
Available general parameters: "job_type": Job type parameter ...
Returns
-------
str
A description of the parameters available under the 'Study settings' tab including the names they have to be referenced by to use the :meth:`~.set_general_job_settings_parameter` method.
"""
pass
[docs]
@abstractmethod
def get_job_type_specific_settings_description(self) -> str:
""" Returns a description of which settings are available for the current job type
.. 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()
>>> job_setup = study_setup.create_job_setup(job_name='FRF Job')
>>> print("Available job parameters: {}".format(job_setup.get_job_type_specific_settings_description())) # To check which general settings are available
Available job parameters: ...
Returns
-------
str
A description of the parameters available for this job type including the names they have to be referenced by to use the :meth:`~.set_job_specific_parameter` method.
"""
pass
[docs]
@abstractmethod
def get_tunable_parameters_description_for_object(self, obj) -> str:
""" Returns a description of which tunable parameters are available for the given 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()
>>> job_setup = study_setup.create_job_setup(job_name='Static Job') # Adds a static job and returns a job creation pipeline object
..
>>> prop = proj.comp.add_link_properties(physics='mech')
>>> _ = prop.add_property(physics='mech', kind='elastic_joint')
>>> prop.name = 'property_name'
>>> particular_property = proj.comp.find_link_properties(linkpropname='property_name').properties[0] # Assumes that a link property with this names exists and has at least one particular property
>>> print(job_setup.get_tunable_parameters_description_for_object(obj=particular_property)) # Shows the parameters available to the supplied object
"ku": Float parameter - ...
..
>>> job_setup.get_tunable_parameters_description_for_object(None)
'Object "None" does not have any delegated parameters'
Returns
-------
str
A description of the tunable parameters available the given object including the names they have to be referenced by to use the :meth:`~.set_parameter` method.
"""
pass