def generate_context(wkchain_cls, inputs, outline_steps): """instantiate a WorkChain, call a list of methods (that should be part of `spec.outline`), then return a sanitized version of the workchain context for testing """ from aiida.common.extendeddicts import AttributeDict from aiida.engine import ProcessBuilder from aiida.engine.utils import instantiate_process from aiida.manage.manager import get_manager from aiida.orm import Node class ContextDumper(yaml.Dumper): """Custom yaml dumper for a process context.""" def represent_data(self, data): if isinstance(data, Node): data = str(data.__class__) if isinstance(data, AttributeDict): data = dict(data) return super(ContextDumper, self).represent_data(data) manager = get_manager() runner = manager.get_runner() if isinstance(inputs, ProcessBuilder): wkchain = instantiate_process(runner, inputs) else: wkchain = instantiate_process(runner, wkchain_cls, **inputs) step_outcomes = [] for step in outline_steps: step_outcomes.append(getattr(wkchain, step)()) context = yaml.dump(wkchain.ctx, Dumper=ContextDumper) return wkchain, step_outcomes, yaml.safe_load(context)
def generate_calcinfo(entry_point_name, folder, inputs=None): """Generate a `CalcInfo` instance for testing calculation jobs. A new `CalcJob` process instance is instantiated, and `prepare_for_submission` is called to populate the supplied folder, with raw inputs. Parameters ---------- entry_point_name: str folder: aiida.common.folders.Folder inputs: dict or None """ from aiida.engine.utils import instantiate_process from aiida.manage.manager import get_manager from aiida.plugins import CalculationFactory manager = get_manager() runner = manager.get_runner() process_class = CalculationFactory(entry_point_name) process = instantiate_process(runner, process_class, **inputs) calc_info = process.prepare_for_submission(folder) return calc_info
def inner(inputs=None, settings=None): if inputs is None: inputs = vasp_inputs(settings) manager = get_manager() runner = manager.get_runner() return instantiate_process(runner, VaspCalculation, **inputs)
def immigrate_existing(builder, remote_data, seal=True): """Immigrate a Calculation that was not run using AiiDa. :param builder: a populated builder instance for a CalcJob :type builder: aiida.engine.processes.builder.ProcessBuilder :param remote_data: a remote data folder, containing the output files required for parsing :type remote_data: aiida.orm.RemoteData :param seal: whether to seal the calc node, from further attribute changes :type seal: bool :rtype: aiida.orm.CalcJobNode """ # initialise calcjob runner = get_manager().get_runner() pw_calc_cls = builder._process_class process = instantiate_process(runner, pw_calc_cls, **builder) calc_node = process.node # prepare for submission with SandboxFolder() as temp_folder: calc_info = process.presubmit(temp_folder) # noqa F841 calc_node.put_object_from_tree(temp_folder.abspath, force=True) # link remote folder to calc_node if not remote_data.is_stored: remote_data.store() remote_data.add_incoming( calc_node, link_type=LinkType.CREATE, link_label="remote_folder" ) calc_node.set_remote_workdir(remote_data.get_remote_path()) transport = remote_data.computer.get_transport() with SandboxFolder() as temp_retrieved: # retrieved output files retrieve_calculation(calc_node, transport, temp_retrieved.abspath) # parse output calc_node.set_state(CalcJobState.PARSING) exit_code = process.parse(temp_retrieved.abspath) # link outgoing nodes process.update_outputs() # finalise calc node calc_node.delete_state() calc_node.delete_checkpoint() calc_node.set_process_state(ProcessState.FINISHED) calc_node.set_exit_status(exit_code.status) calc_node.set_exit_message(exit_code.message) if seal: calc_node.seal() # record that the node was created via immigration calc_node.set_extra("immigrated", True) calc_node.set_extra("immigration_func", __name__) return calc_node
def test_generate_base_calc(base_calc): """Test that it is possible to start the generatione of an instance of the base calculation class.""" from aiida_vasp.calcs.base import VaspCalcBase manager = get_manager() runner = manager.get_runner() inputs = AttributeDict() metadata = AttributeDict({ 'options': { 'resources': { 'num_machines': 1, 'num_mpiprocs_per_machine': 1 } } }) inputs.metadata = metadata # Need more input, so we will get an ValueError because we do not pass code with pytest.raises(ValueError): instantiate_process(runner, VaspCalcBase, **inputs)
def _generate_calc_job(entry_point_name, inputs=None): """Fixture to generate a mock `CalcInfo` for testing calculation jobs.""" from aiida.engine.utils import instantiate_process from aiida.manage.manager import get_manager from aiida.plugins import CalculationFactory manager = get_manager() runner = manager.get_runner() process_class = CalculationFactory(entry_point_name) process = instantiate_process(runner, process_class, **inputs) return process
def _generate_calc_job(folder, builder): """Fixture to generate a mock `CalcInfo` for testing calculation jobs.""" from aiida.engine.utils import instantiate_process from aiida.manage.manager import get_manager manager = get_manager() runner = manager.get_runner() process_class = builder._process_class # pylint: disable=protected-access process = instantiate_process(runner, process_class, **dict(builder)) calc_info = process.prepare_for_submission(folder) return calc_info
def _generate_workchain(entry_point, inputs): """Generate an instance of a `WorkChain` with the given entry point and inputs. :param entry_point: entry point name of the work chain subclass. :param inputs: inputs to be passed to process construction. :return: a `WorkChain` instance. """ from aiida.engine.utils import instantiate_process from aiida.manage.manager import get_manager from aiida.plugins import WorkflowFactory process_class = WorkflowFactory(entry_point) runner = get_manager().get_runner() process = instantiate_process(runner, process_class, **inputs) return process
def test_exposed_outputs(self): """Test the ``Process.exposed_outputs`` method.""" from aiida.common import AttributeDict from aiida.common.links import LinkType from aiida.engine.utils import instantiate_process from aiida.manage.manager import get_manager runner = get_manager().get_runner() class ChildProcess(Process): """Dummy process with normal output and output namespace.""" _node_class = orm.WorkflowNode @classmethod def define(cls, spec): super(ChildProcess, cls).define(spec) spec.input('input', valid_type=orm.Int) spec.output('output', valid_type=orm.Int) spec.output('name.space', valid_type=orm.Int) class ParentProcess(Process): """Dummy process that exposes the outputs of ``ChildProcess``.""" _node_class = orm.WorkflowNode @classmethod def define(cls, spec): super(ParentProcess, cls).define(spec) spec.input('input', valid_type=orm.Int) spec.expose_outputs(ChildProcess) node_child = orm.WorkflowNode().store() node_output = orm.Int(1).store() node_output.add_incoming(node_child, link_label='output', link_type=LinkType.RETURN) node_name_space = orm.Int(1).store() node_name_space.add_incoming(node_child, link_label='name__space', link_type=LinkType.RETURN) process = instantiate_process(runner, ParentProcess, input=orm.Int(1)) exposed_outputs = process.exposed_outputs(node_child, ChildProcess) expected = AttributeDict({ 'name': { 'space': node_name_space, }, 'output': node_output, }) self.assertEqual(exposed_outputs, expected)
def instantiate_process(self, state=CalcJobState.PARSING): """Instantiate a process with default inputs and return the `Process` instance.""" from aiida.engine.utils import instantiate_process from aiida.manage.manager import get_manager inputs = deepcopy(self.inputs) inputs['code'] = self.remote_code manager = get_manager() runner = manager.get_runner() process_class = CalculationFactory('arithmetic.add') process = instantiate_process(runner, process_class, **inputs) process.node.set_state(state) return process
def _generate_calc_job(folder, entry_point_name, inputs=None, return_process=False): """Fixture to generate a mock `CalcInfo` for testing calculation jobs.""" from aiida.engine.utils import instantiate_process from aiida.manage.manager import get_manager from aiida.plugins import CalculationFactory inputs = inputs or {} manager = get_manager() runner = manager.get_runner() process_class = CalculationFactory(entry_point_name) process = instantiate_process(runner, process_class, **inputs) if return_process: return process return process.prepare_for_submission(folder)
def base_calc(fresh_aiida_env, vasp_code): """An instance of a VaspCalcBase Process.""" from aiida_vasp.calcs.base import VaspCalcBase manager = get_manager() runner = manager.get_runner() inputs = AttributeDict() metadata = AttributeDict({ 'options': { 'resources': { 'num_machines': 1, 'num_mpiprocs_per_machine': 1 } } }) inputs.code = vasp_code inputs.metadata = metadata return instantiate_process(runner, VaspCalcBase, **inputs)
def process(aiida_local_code_factory): """Instantiate a process with default inputs and return the `Process` instance.""" from aiida.engine.utils import instantiate_process from aiida.manage.manager import get_manager inputs = { 'code': aiida_local_code_factory('arithmetic.add', '/bin/bash'), 'x': orm.Int(1), 'y': orm.Int(2), 'metadata': { 'options': {} } } manager = get_manager() runner = manager.get_runner() process_class = CalculationFactory('arithmetic.add') process = instantiate_process(runner, process_class, **inputs) process.node.set_state(CalcJobState.PARSING) return process
def _generate_process(inputs=None): base_inputs = { 'code': aiida_local_code_factory('arithmetic.add', '/bin/bash'), 'x': orm.Int(1), 'y': orm.Int(2), 'metadata': { 'options': {} } } if inputs is not None: base_inputs = {**base_inputs, **inputs} manager = get_manager() runner = manager.get_runner() process_class = CalculationFactory('arithmetic.add') process = instantiate_process(runner, process_class, **base_inputs) process.node.set_state(CalcJobState.PARSING) return process
def instantiate_process_builder(builder): """Instantiate a process, from a `ProcessBuilder`.""" manager = get_manager() runner = manager.get_runner() return instantiate_process(runner, builder)
def instantiate_process_cls(process_cls, inputs): """Instantiate a process, from its class and inputs.""" manager = get_manager() runner = manager.get_runner() return instantiate_process(runner, process_cls, **inputs)
def test_gaussian(fixture_code): geometry_file = os.path.join(tests.TEST_DIR, "data", 'ch4.xyz') expected_inp_file = os.path.join(tests.TEST_DIR, "data", 'gaussian_test.inp') # structure structure = StructureData( pymatgen_molecule=Molecule.from_file(geometry_file)) num_cores = 1 memory_mb = 1000 # Main parameters: geometry optimization parameters = { 'link0_parameters': { '%chk': 'aiida.chk', '%mem': "%dMB" % memory_mb, '%nprocshared': str(num_cores), }, 'functional': 'BLYP', 'basis_set': '6-31g', 'charge': 0, 'multiplicity': 1, 'route_parameters': { 'scf': { 'maxcycle': 512, 'cdiis': None }, 'nosymm': None, 'opt': None, }, } # Build the inputs dictionary with a "fake" executable inputs = { 'code': fixture_code('gaussian'), #load_code("gaussian09@localhost"), 'structure': structure, 'parameters': Dict(dict=parameters), 'metadata': { 'options': { 'resources': { 'num_machines': 1, 'tot_num_mpiprocs': 1, }, 'max_wallclock_seconds': 1800, 'withmpi': False } } } # Prepare the fake calculation for submission in a "sandbox folder" from aiida.engine.utils import instantiate_process from aiida.manage.manager import get_manager from aiida.common.folders import SandboxFolder manager = get_manager() runner = manager.get_runner() process_class = CalculationFactory('gaussian') process = instantiate_process(runner, process_class, **inputs) sandbox_folder = SandboxFolder() calc_info = process.prepare_for_submission(sandbox_folder) with sandbox_folder.open('aiida.inp') as handle: input_written = handle.read() with open(expected_inp_file, 'r') as f: expected_inp = f.read() assert (input_written == expected_inp)