diff --git a/__init__.py b/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyiron/base/job/generic.py b/pyiron/base/job/generic.py index b32d2c2a7..4a08bc8d1 100644 --- a/pyiron/base/job/generic.py +++ b/pyiron/base/job/generic.py @@ -16,6 +16,7 @@ from pyiron.base.job.executable import Executable from pyiron.base.job.jobstatus import JobStatus from pyiron.base.job.core import JobCore +from pyiron.base.job.jobtype import static_isinstance from pyiron.base.server.generic import Server import subprocess import shutil @@ -739,6 +740,68 @@ def send_to_database(self): if self.server.send_to_db: pass + def create_job(self, job_type, job_name): + """ + Create one of the following jobs: + - 'StructureContainer’: + - ‘StructurePipeline’: + - ‘AtomisticExampleJob’: example job just generating random number + - ‘ExampleJob’: example job just generating random number + - ‘Lammps’: + - ‘KMC’: + - ‘Sphinx’: + - ‘Vasp’: + - ‘GenericMaster’: + - ‘SerialMaster’: series of jobs run in serial + - ‘AtomisticSerialMaster’: + - ‘ParallelMaster’: series of jobs run in parallel + - ‘KmcMaster’: + - ‘ThermoLambdaMaster’: + - ‘RandomSeedMaster’: + - ‘MeamFit’: + - ‘Murnaghan’: + - ‘MinimizeMurnaghan’: + - ‘ElasticMatrix’: + - ‘ConvergenceVolume’: + - ‘ConvergenceEncutParallel’: + - ‘ConvergenceKpointParallel’: + - ’PhonopyMaster’: + - ‘DefectFormationEnergy’: + - ‘LammpsASE’: + - ‘PipelineMaster’: + - ’TransformationPath’: + - ‘ThermoIntEamQh’: + - ‘ThermoIntDftEam’: + - ‘ScriptJob’: Python script or jupyter notebook job container + - ‘ListMaster': list of jobs + + Args: + job_type (str): job type can be ['StructureContainer’, ‘StructurePipeline’, ‘AtomisticExampleJob’, + ‘ExampleJob’, ‘Lammps’, ‘KMC’, ‘Sphinx’, ‘Vasp’, ‘GenericMaster’, + ‘SerialMaster’, ‘AtomisticSerialMaster’, ‘ParallelMaster’, ‘KmcMaster’, + ‘ThermoLambdaMaster’, ‘RandomSeedMaster’, ‘MeamFit’, ‘Murnaghan’, + ‘MinimizeMurnaghan’, ‘ElasticMatrix’, ‘ConvergenceVolume’, + ‘ConvergenceEncutParallel’, ‘ConvergenceKpointParallel’, ’PhonopyMaster’, + ‘DefectFormationEnergy’, ‘LammpsASE’, ‘PipelineMaster’, + ’TransformationPath’, ‘ThermoIntEamQh’, ‘ThermoIntDftEam’, ‘ScriptJob’, + ‘ListMaster'] + job_name (str): name of the job + + Returns: + GenericJob: job object depending on the job_type selected + """ + job = self.project.create_job(job_type=job_type, job_name=job_name) + if static_isinstance(obj=job.__class__, + obj_type=['pyiron.base.master.parallel.ParallelMaster', + 'pyiron.base.master.serial.SerialMasterBase', + 'pyiron.atomistic.job.interactivewrapper.InteractiveWrapper']): + job.ref_job = self + if self.server.run_mode.non_modal: + job.server.run_mode.non_modal = True + elif self.server.run_mode.interactive or self.server.run_mode.interactive_non_modal: + job.server.run_mode.interactive = True + return job + def update_master(self): """ After a job is finished it checks whether it is linked to any metajob - meaning the master ID is pointing to @@ -901,24 +964,6 @@ def restart(self, snapshot=-1, job_name=None, job_type=None): new_ham._restart_file_dict = dict() return new_ham - def create_job(self, job_type, job_name): - """ - Create one of the following jobs: - - 'ExampleJob': example job just generating random number - - 'SerialMaster': series of jobs run in serial - - 'ParallelMaster': series of jobs run in parallel - - 'ScriptJob': Python script or jupyter notebook job container - - 'ListMaster': list of jobs - - Args: - job_type (str): job type can be ['ExampleJob', 'SerialMaster', 'ParallelMaster', 'ScriptJob', 'ListMaster'] - job_name (str): name of the job - - Returns: - GenericJob: job object depending on the job_type selected - """ - return self.project.create_job(job_type=job_type, job_name=job_name) - def _copy_restart_files(self): """ Internal helper function to copy the files required for the restart job. diff --git a/pyiron/base/job/jobtype.py b/pyiron/base/job/jobtype.py index 01c016e40..462154a88 100644 --- a/pyiron/base/job/jobtype.py +++ b/pyiron/base/job/jobtype.py @@ -135,6 +135,16 @@ def __new__(cls, class_name, project, job_name, job_class_dict): @staticmethod def convert_str_to_class(job_class_dict, class_name): + """ + convert the name of a class to the corresponding class object - only for pyiron internal classes. + + Args: + job_class_dict (dict): + class_name (str): + + Returns: + (class): + """ job_type_lst = class_name.split(".") if len(job_type_lst) > 1: class_name = class_name.split()[-1][1:-2] @@ -150,4 +160,23 @@ def convert_str_to_class(job_class_dict, class_name): def static_isinstance(obj, obj_type): - return obj_type in ['.'.join([subcls.__module__, subcls.__name__]) for subcls in obj.__mro__] + """ + A static implementation of isinstance() - instead of comparing an object and a class, the object is compared to a + string, like 'pyiron.base.job.generic.GenericJob' or a list of strings. + + Args: + obj: the object to check + obj_type (str/list): object type as string or a list of object types as string. + + Returns: + bool: [True/False] + """ + if not hasattr(obj, '__mro__'): + obj = obj.__class__ + obj_class_lst = ['.'.join([subcls.__module__, subcls.__name__]) for subcls in obj.__mro__] + if isinstance(obj_type, list): + return any([obj_type_element in obj_class_lst for obj_type_element in obj_type]) + elif isinstance(obj_type, str): + return obj_type in obj_class_lst + else: + raise TypeError() diff --git a/tests/base/job/test_jobtype.py b/tests/base/job/test_jobtype.py new file mode 100644 index 000000000..295fe44a3 --- /dev/null +++ b/tests/base/job/test_jobtype.py @@ -0,0 +1,14 @@ +import unittest +from pyiron.base.job.jobtype import static_isinstance + + +class TestJobType(unittest.TestCase): + def test_static_isinstance(self): + self.assertTrue(static_isinstance(obj=list(), obj_type=['builtins.list', '__builtin__.list'])) + self.assertTrue(any([static_isinstance(obj=list(), obj_type='builtins.list'), + static_isinstance(obj=list(), obj_type='__builtin__.list')])) + self.assertRaises(TypeError, static_isinstance, list(), 1) + + +if __name__ == '__main__': + unittest.main()