def test_lambda_default(self): """Test that an input port can specify a lambda as a default.""" port_namespace = PortNamespace('base') # Defining lambda for default that returns incorrect type should not except at construction port_namespace['port'] = InputPort('port', valid_type=Int, default=lambda: 'string') # However, pre processing the namespace, which shall evaluate the default followed by validation will fail inputs = port_namespace.pre_process({}) self.assertIsNotNone(port_namespace.validate(inputs)) # Passing an explicit value for the port will forego the default and validation on returned inputs should pass inputs = port_namespace.pre_process({'port': Int(5)}) self.assertIsNone(port_namespace.validate(inputs)) # Redefining the port, this time with a correct default port_namespace['port'] = InputPort('port', valid_type=Int, default=lambda: Int(5)) # Pre processing the namespace shall evaluate the default and return the int node inputs = port_namespace.pre_process({}) self.assertIsInstance(inputs['port'], Int) self.assertEqual(inputs['port'].value, 5) # Passing an explicit value for the port will forego the default inputs = port_namespace.pre_process({'port': Int(3)}) self.assertIsInstance(inputs['port'], Int) self.assertEqual(inputs['port'].value, 3)
def test_immutable_input(self): """ Check that from within the WorkChain self.inputs returns an AttributesFrozendict which should be immutable """ test_class = self class Wf(WorkChain): @classmethod def define(cls, spec): super().define(spec) spec.input('a', valid_type=Int) spec.input('b', valid_type=Int) spec.outline( cls.step_one, cls.step_two, ) def step_one(self): # Attempt to manipulate the inputs dictionary which since it is a AttributesFrozendict should raise with test_class.assertRaises(TypeError): self.inputs['a'] = Int(3) with test_class.assertRaises(AttributeError): self.inputs.pop('b') with test_class.assertRaises(TypeError): self.inputs['c'] = Int(4) def step_two(self): # Verify that original inputs are still there with same value and no inputs were added test_class.assertIn('a', self.inputs) test_class.assertIn('b', self.inputs) test_class.assertNotIn('c', self.inputs) test_class.assertEqual(self.inputs['a'].value, 1) run_and_check_success(Wf, a=Int(1), b=Int(2))
def test_create(self): """Creating basic data objects.""" term_a = Float() # Check that initial value is zero self.assertAlmostEqual(term_a.value, 0.0) float_ = Float(6.0) self.assertAlmostEqual(float_.value, 6.) self.assertAlmostEqual(float_, Float(6.0)) int_ = Int() self.assertAlmostEqual(int_.value, 0) int_ = Int(6) self.assertAlmostEqual(int_.value, 6) self.assertAlmostEqual(float_, int_) bool_ = Bool() self.assertAlmostEqual(bool_.value, False) bool_ = Bool(False) self.assertAlmostEqual(bool_.value, False) self.assertAlmostEqual(bool_.value, get_false_node()) bool_ = Bool(True) self.assertAlmostEqual(bool_.value, True) self.assertAlmostEqual(bool_.value, get_true_node()) str_ = Str() self.assertAlmostEqual(str_.value, '') str_ = Str('Hello') self.assertAlmostEqual(str_.value, 'Hello')
def test_division(self): """Test the normal division operator.""" term_a = Int(3) term_b = Int(2) self.assertAlmostEqual(term_a / term_b, 1.5) self.assertIsInstance(term_a / term_b, Float)
def test_division_integer(self): """Test the integer division operator.""" a = Int(3) b = Int(2) self.assertAlmostEqual(a // b, 1) self.assertIsInstance(a // b, Int)
def test_immutable_input_groups(self): """ Check that namespaced inputs also return AttributeFrozendicts and are hence immutable """ test_class = self class Wf(WorkChain): @classmethod def define(cls, spec): super().define(spec) spec.input_namespace('subspace', dynamic=True) spec.outline( cls.step_one, cls.step_two, ) def step_one(self): # Attempt to manipulate the namespaced inputs dictionary which should raise with test_class.assertRaises(TypeError): self.inputs.subspace['one'] = Int(3) with test_class.assertRaises(AttributeError): self.inputs.subspace.pop('two') with test_class.assertRaises(TypeError): self.inputs.subspace['four'] = Int(4) def step_two(self): # Verify that original inputs are still there with same value and no inputs were added test_class.assertIn('one', self.inputs.subspace) test_class.assertIn('two', self.inputs.subspace) test_class.assertNotIn('four', self.inputs.subspace) test_class.assertEqual(self.inputs.subspace['one'].value, 1) run_and_check_success(Wf, subspace={'one': Int(1), 'two': Int(2)})
def test_create(self): a = Float() # Check that initial value is zero self.assertAlmostEqual(a.value, 0.0) f = Float(6.0) self.assertAlmostEqual(f.value, 6.) self.assertAlmostEqual(f, Float(6.0)) i = Int() self.assertAlmostEqual(i.value, 0) i = Int(6) self.assertAlmostEqual(i.value, 6) self.assertAlmostEqual(f, i) b = Bool() self.assertAlmostEqual(b.value, False) b = Bool(False) self.assertAlmostEqual(b.value, False) self.assertAlmostEqual(b.value, get_false_node()) b = Bool(True) self.assertAlmostEqual(b.value, True) self.assertAlmostEqual(b.value, get_true_node()) s = Str() self.assertAlmostEqual(s.value, '') s = Str('Hello') self.assertAlmostEqual(s.value, 'Hello')
def test_division(self): """Test the normal division operator.""" a = Int(3) b = Int(2) self.assertAlmostEqual(a / b, 1.5) self.assertIsInstance(a / b, Float)
def define(cls, spec): super(IterHarmonicApprox, cls).define(spec) spec.expose_inputs(PhonopyWorkChain, exclude=[ 'immigrant_calculation_folders', 'calculation_nodes', 'dry_run' ]) spec.input('max_iteration', valid_type=Int, required=False, default=Int(10)) spec.input('number_of_snapshots', valid_type=Int, required=False, default=Int(100)) spec.input('number_of_steps_for_fitting', valid_type=Int, required=False, default=Int(4)) spec.input('random_seed', valid_type=Int, required=False) spec.input('temperature', valid_type=Float, required=False, default=Float(300.0)) spec.input('initial_nodes', valid_type=Dict, required=False) spec.input('include_ratio', valid_type=Float, required=False) spec.outline( cls.initialize, if_(cls.import_initial_nodes)( cls.set_initial_nodes, cls.run_phonon, ).else_(cls.run_initial_phonon, ), while_(cls.is_loop_finished)(cls.run_phonon, ), )
def launch_aiida_bulk_modulus(structure, code_string, resources, label="AlN VASP relax calculation"): incar_dict = { 'PREC': 'Accurate', 'EDIFF': 1e-8, 'NELMIN': 5, 'NELM': 100, 'ENCUT': 500, 'IALGO': 38, 'ISMEAR': 0, 'SIGMA': 0.01, 'GGA': 'PS', 'LREAL': False, 'LCHARG': False, 'LWAVE': False, } kpoints = KpointsData() kpoints.set_kpoints_mesh([6, 6, 4], offset=[0, 0, 0.5]) options = {'resources': resources, 'max_wallclock_seconds': 3600 * 10} potential_family = 'PBE.54' potential_mapping = {'Al': 'Al', 'N': 'N'} parser_settings = { 'add_energies': True, 'add_forces': True, 'add_stress': True } code = Code.get_from_string(code_string) Workflow = WorkflowFactory('vasp_bm.bulkmodulus') builder = Workflow.get_builder() builder.code = code builder.parameters = Dict(dict=incar_dict) builder.structure = structure builder.settings = Dict(dict={'parser_settings': parser_settings}) builder.potential_family = Str(potential_family) builder.potential_mapping = Dict(dict=potential_mapping) builder.kpoints = kpoints builder.options = Dict(dict=options) builder.metadata.label = label builder.metadata.description = label builder.clean_workdir = Bool(False) builder.relax = Bool(True) builder.force_cutoff = Float(1e-8) builder.steps = Int(10) builder.positions = Bool(True) builder.shape = Bool(True) builder.volume = Bool(True) builder.convergence_on = Bool(True) builder.convergence_volume = Float(1e-8) builder.convergence_max_iterations = Int(2) builder.verbose = Bool(True) node = submit(builder) return node
def test_supercell(generate_structure): """Test to create a super cell""" from aiida_fleur.tools.StructureData_util import supercell from aiida_fleur.tools.StructureData_util import supercell_ncf from aiida.orm import Int from itertools import product structure = generate_structure() supercell = supercell(structure, Int(2), Int(3), Int(4)) assert (supercell.cell[0] == np.array(structure.cell[0]) * 2).all() assert (supercell.cell[1] == np.array(structure.cell[1]) * 3).all() assert (supercell.cell[2] == np.array(structure.cell[2]) * 4).all() assert len(supercell.sites) == 2 * 3 * 4 * len(structure.sites) positions_old = [x.position for x in structure.sites] positions_rescaled = [x.position for x in supercell.sites] for position in positions_old: for x, y, z in product(range(2), range(3), range(4)): test_pos = tuple( np.array(position) + x * np.array(structure.cell[0]) + y * np.array(structure.cell[1]) + z * np.array(structure.cell[2])) assert test_pos in positions_rescaled no_struc = Int(1) no_supercell = supercell_ncf(no_struc, 2, 3, 4) assert no_supercell is None
def test_calcfunction_caching(self): """Verify that a calcfunction can be cached.""" @calcfunction def test_calcfunction(data): global EXECUTION_COUNTER # pylint: disable=global-statement EXECUTION_COUNTER += 1 return Int(data.value + 1) self.assertEqual(EXECUTION_COUNTER, 0) _, original = test_calcfunction.run_get_node(Int(5)) self.assertEqual(EXECUTION_COUNTER, 1) # Caching a CalcFunctionNode should be possible with enable_caching(CalcFunctionNode): input_node = Int(5) result, cached = test_calcfunction.run_get_node(input_node) self.assertEqual( EXECUTION_COUNTER, 1) # Calculation function body should not have been executed self.assertTrue(result.is_stored) self.assertTrue(cached.is_created_from_cache) self.assertIn(cached.get_cache_source(), original.uuid) self.assertEqual(cached.get_incoming().one().node.uuid, input_node.uuid)
def test_sqs_process(ce_sqs_code): prim = bulk('Au') structure = StructureData(ase=prim) chemical_symbols = List(list=[['Au', 'Pd']]) # set up calculation inputs = { 'code': ce_sqs_code, 'structure': structure, 'chemical_symbols': chemical_symbols, 'pbc': List(list=[True, True, True]), 'cutoffs': List(list=[5.0]), 'max_size': Int(8), 'include_smaller_cells': Bool(True), 'n_steps': Int(2000), 'target_concentrations': Dict(dict={ 'Au': 0.5, 'Pd': 0.5 }), 'metadata': { 'options': { 'max_wallclock_seconds': 30, }, } } result = run(CalculationFactory('ce.gensqs'), **inputs) assert 'sqs' in result assert 'cluster_space' in result sqs = result['sqs'].get_ase() assert sqs.get_number_of_atoms() == 8
def test_enum_process(ce_enum_code): StructureSet = DataFactory('ce.structures') from ase.build import bulk prim = bulk('Ag') structure = StructureData(ase=prim) chemical_symbols = List(list=[['Au', 'Pd']]) # set up calculation inputs = { 'code': ce_enum_code, 'structure': structure, 'chemical_symbols': chemical_symbols, 'min_volume': Int(1), 'max_volume': Int(4), 'metadata': { 'options': { 'max_wallclock_seconds': 30 }, }, } result = run(CalculationFactory('ce.genenum'), **inputs) structures = result['enumerate_structures'] structure0 = structures.get_structure(0).get_ase() assert numpy.allclose(structure0.cell, prim.cell) assert numpy.allclose(structure0.positions, prim.positions) assert isinstance(structures, StructureSet) assert result['number_of_structures'] == 10
def test_division_integer(self): """Test the integer division operator.""" term_a = Int(3) term_b = Int(2) self.assertAlmostEqual(term_a // term_b, 1) self.assertIsInstance(term_a // term_b, Int)
def do_launch(): term_a = Int(5) term_b = Int(10) calc_node = submit(test_processes.AddProcess, a=term_a, b=term_b) yield self.wait_for_process(calc_node) self.assertTrue(calc_node.is_finished_ok) self.assertEqual(calc_node.process_state.value, plumpy.ProcessState.FINISHED.value)
def finalize(self): if self.should_submit(): self.report('Getting sub-workchain output.') sub_workchain = self.ctx.workchain[0] self.out('output', Int(sub_workchain.outputs.output + 1).store()) else: self.report('Bottom-level workchain reached.') self.out('output', Int(0).store())
def run_task(self): inputs = { 'x': Int(1), 'y': Int(2), 'code': self.inputs.code, } future = self.submit(ArithmeticAddCalculation, **inputs) return self.to_context(addition=future)
def step_one(self): # Attempt to manipulate the inputs dictionary which since it is a AttributesFrozendict should raise with test_class.assertRaises(TypeError): self.inputs['a'] = Int(3) with test_class.assertRaises(AttributeError): self.inputs.pop('b') with test_class.assertRaises(TypeError): self.inputs['c'] = Int(4)
def step_one(self): # Attempt to manipulate the namespaced inputs dictionary which should raise with test_class.assertRaises(TypeError): self.inputs.subspace['one'] = Int(3) with test_class.assertRaises(AttributeError): self.inputs.subspace.pop('two') with test_class.assertRaises(TypeError): self.inputs.subspace['four'] = Int(4)
def parse_optimize_calculation(calc): """Parse ths information from plugins nodes and set common units Stress in kB Force in eV/Angstrom """ import numpy as np plugin = calc.get_code().get_attr('input_plugin') if plugin == 'vasp.vasp': forces = calc.out.output_trajectory.get_array('forces')[-1] stress = calc.out.output_trajectory.get_array('stress')[-1] try: structure = calc.out.output_structure except: structure = structure_from_trajectory(calc.out.output_trajectory, Int(-1))['structure'] energy_wo_entrop = calc.out.output_trajectory.get_array( 'e_wo_entrp')[-1] pressure = np.average(np.diag(stress)) factor = 0.0006241509125883258 # kBar * A^3 -> eV energy = (energy_wo_entrop - structure.get_cell_volume() * pressure * factor) elif plugin == 'lammps.optimize': forces = calc.out.output_array.get_array('forces') stress = calc.out.output_array.get_array('stress') structure = calc.out.output_structure energy = calc.out.output_parameters.dict.energy elif plugin == 'quantumespresso.pw': forces = calc.out.output_trajectory.get_array('forces')[-1] # GPa to kBar stress = calc.out.output_trajectory.get_array('stress')[-1] * 10 energy = calc.out.output_parameters.dict.energy try: structure = calc.out.output_structure except: structure = structure_from_trajectory(calc.out.output_trajectory, Int(-1))['structure'] else: return Exception('Not supported plugin') output_data = Dict(dict={ 'energy': energy, 'forces': forces.tolist(), 'stress': stress.tolist() }) return {'output_structure': structure, 'output_data': output_data}
def test_parse_exit_code_priority( exit_status_scheduler, exit_status_retrieved, final, generate_calc_job, fixture_sandbox, aiida_local_code_factory, monkeypatch, ): # pylint: disable=too-many-arguments """Test the logic around exit codes in the `CalcJob.parse` method. The `parse` method will first call the `Scheduler.parse_output` method, which if implemented by the relevant scheduler plugin, will parse the scheduler output and potentially return an exit code. Next, the output parser plugin is called if defined in the inputs that can also optionally return an exit code. This test is designed to make sure the right logic is implemented in terms of which exit code should be dominant. Scheduler result | Retrieved result | Final result | Scenario -----------------|------------------|-----------------|----------------------------------------- `None` | `None` | `ExitCode(0)` | Neither parser found any problem `ExitCode(100)` | `None` | `ExitCode(100)` | Scheduler found issue, output parser does not override `None` | `ExitCode(400)` | `ExitCode(400)` | Only output parser found a problem `ExitCode(100)` | `ExitCode(400)` | `ExitCode(400)` | Scheduler found issue, but output parser overrides | | | with a more specific error code `ExitCode(100)` | `ExitCode(0)` | `ExitCode(0)` | Scheduler found issue but output parser overrides saying | | | that despite that the calculation should be considered | | | finished successfully. To test this, we just need to test the `CalcJob.parse` method and the easiest way is to simply mock the scheduler parser and output parser calls called `parse_scheduler_output` and `parse_retrieved_output`, respectively. We will just mock them by a simple method that returns `None` or an `ExitCode`. We then check that the final exit code returned by `CalcJob.parse` is the one we expect according to the table above. """ from aiida.orm import Int def parse_scheduler_output(_, __): if exit_status_scheduler is not None: return ExitCode(exit_status_scheduler) def parse_retrieved_output(_, __): if exit_status_retrieved is not None: return ExitCode(exit_status_retrieved) monkeypatch.setattr(CalcJob, 'parse_scheduler_output', parse_scheduler_output) monkeypatch.setattr(CalcJob, 'parse_retrieved_output', parse_retrieved_output) inputs = { 'code': aiida_local_code_factory('arithmetic.add', '/bin/bash'), 'x': Int(1), 'y': Int(2), } process = generate_calc_job(fixture_sandbox, 'arithmetic.add', inputs, return_process=True) retrieved = orm.FolderData().store() retrieved.add_incoming(process.node, link_label='retrieved', link_type=LinkType.CREATE) result = process.parse() assert isinstance(result, ExitCode) assert result.status == final
def test_run(): """Test running the work function.""" x = Int(1) y = Int(2) z = Int(3) result = add_multiply(x, y, z) assert isinstance(result, Int) assert result == (x + y) * z
def test_modulo(self): a = Int(12) b = Int(10) self.assertEqual(a % b, 2) self.assertIsInstance(a % b, NumericType) self.assertEqual(a % 10, 2) self.assertIsInstance(a % 10, NumericType) self.assertEqual(12 % b, 2) self.assertIsInstance(12 % b, NumericType)
def prepare_run(stage, deliverable, inputs): inputs["structure"] = StructureData(ase=graphene(vacuum=15)) inputs["year"] = Int(2050) if stage == 2: inputs["C_substitute"] = Str("N") elif stage in [3, 4]: inputs["C_substitute"] = Str("H") inputs["max_iterations"] = Int(1) inputs["batch_size"] = Int(3)
def test_modulo(self): """Test modulus operation.""" term_a = Int(12) term_b = Int(10) self.assertEqual(term_a % term_b, 2) self.assertIsInstance(term_a % term_b, NumericType) self.assertEqual(term_a % 10, 2) self.assertIsInstance(term_a % 10, NumericType) self.assertEqual(12 % term_b, 2) self.assertIsInstance(12 % term_b, NumericType)
def launch_calcfunction(inputval): """Launch workfunction to the daemon""" inputs = { 'x': Int(inputval), 'y': Int(inputval), } res = inputval + inputval expected_result = Int(res) process = submit(add, **inputs) print(f'launched calcfunction {process.uuid}, pk={process.pk}') return process, expected_result
def run_task(self): futures = {} for i in range(self.inputs.iterations.value): inputs = { 'x': Int(1), 'y': Int(2), 'code': self.inputs.code, } futures[f'addition{str(i)}'] = self.submit( ArithmeticAddCalculation, **inputs) return self.to_context(**futures)
def main(): a = Float(3.14) b = Int(4) c = Int(6) results = sum(a, b) print('Result of sum: {}'.format(results)) results = product(a, b) print('Result of product: {}'.format(results)) results = sumproduct(a, b, c) print('Result of sumproduct: {}'.format(results))
def run_base_restart_workchain(): """Run the `AddArithmeticBaseWorkChain` a few times for various inputs.""" code = load_code(CODENAME_ADD) inputs = { 'add': { 'x': Int(1), 'y': Int(2), 'code': code, 'settings': Dict(dict={'allow_negative': False}), 'metadata': { 'options': { 'resources': { 'num_machines': 1, 'num_mpiprocs_per_machine': 1 } } } } } # Normal inputs should run just fine results, node = run.get_node(ArithmeticAddBaseWorkChain, **inputs) assert node.is_finished_ok, node.exit_status assert len(node.called) == 1 assert 'sum' in results assert results['sum'].value == 3 # With one input negative, the sum will be negative which will fail the calculation, but the error handler should # fix it, so the second calculation should finish successfully inputs['add']['y'] = Int(-4) results, node = run.get_node(ArithmeticAddBaseWorkChain, **inputs) assert node.is_finished_ok, node.exit_status assert len(node.called) == 2 assert 'sum' in results assert results['sum'].value == 5 # The silly sanity check aborts the workchain if the sum is bigger than 10 inputs['add']['y'] = Int(10) results, node = run.get_node(ArithmeticAddBaseWorkChain, **inputs) assert not node.is_finished_ok, node.process_state assert node.exit_status == ArithmeticAddBaseWorkChain.exit_codes.ERROR_TOO_BIG.status, node.exit_status # pylint: disable=no-member assert len(node.called) == 1 # Check that overriding default handler enabled status works inputs['add']['y'] = Int(1) inputs['handler_overrides'] = Dict(dict={'disabled_handler': True}) results, node = run.get_node(ArithmeticAddBaseWorkChain, **inputs) assert not node.is_finished_ok, node.process_state assert node.exit_status == ArithmeticAddBaseWorkChain.exit_codes.ERROR_ENABLED_DOOM.status, node.exit_status # pylint: disable=no-member assert len(node.called) == 1