def get_cif_node(self, store=False, parse_policy='lazy'): """ Creates a CIF node, that can be used in AiiDA workflow. :return: :py:class:`aiida.orm.nodes.data.cif.CifData` object """ from aiida.orm.nodes.data.cif import CifData import tempfile cifnode = None with tempfile.NamedTemporaryFile(mode='w+') as f: f.write(self.cif) f.flush() cifnode = CifData(file=f.name, source=self.source, parse_policy=parse_policy) # Maintaining backwards-compatibility. Parameter 'store' should # be removed in the future, as the new node can be stored later. if store: cifnode.store() return cifnode
def create_cif_data(cls): """Create CifData object.""" with tempfile.NamedTemporaryFile(mode='w+') as fhandle: filename = fhandle.name fhandle.write(cls.valid_sample_cif_str) fhandle.flush() a_cif = CifData(file=filename, source={ 'version': '1234', 'db_name': 'COD', 'id': '0000001' }) a_cif.store() g_ne = Group(label='non_empty_group') g_ne.store() g_ne.add_nodes(a_cif) g_e = Group(label='empty_group') g_e.store() cls.cif = a_cif return { DummyVerdiDataListable.NODE_ID_STR: a_cif.id, DummyVerdiDataListable.NON_EMPTY_GROUP_ID_STR: g_ne.id, DummyVerdiDataListable.EMPTY_GROUP_ID_STR: g_e.id }
def refine_inline(node): """ Refine (reduce) the cell of :py:class:`aiida.orm.nodes.data.cif.CifData`, find and remove symmetrically equivalent atoms. :param node: a :py:class:`aiida.orm.nodes.data.cif.CifData` instance. :return: dict with :py:class:`aiida.orm.nodes.data.cif.CifData` .. note:: can be used as inline calculation. """ from aiida.orm.nodes.data.structure import StructureData, ase_refine_cell if len(node.values.keys()) > 1: raise ValueError('CifData seems to contain more than one data ' 'block -- multiblock CIF files are not ' 'supported yet') name = list(node.values.keys())[0] original_atoms = node.get_ase(index=None) if len(original_atoms) > 1: raise ValueError('CifData seems to contain more than one crystal ' 'structure -- such refinement is not supported ' 'yet') original_atoms = original_atoms[0] refined_atoms, symmetry = ase_refine_cell(original_atoms) cif = CifData(ase=refined_atoms) if name != str(0): cif.values.rename(str(0), name) # Remove all existing symmetry tags before overwriting: for tag in symmetry_tags: cif.values[name].RemoveCifItem(tag) cif.values[name]['_symmetry_space_group_name_H-M'] = symmetry['hm'] cif.values[name]['_symmetry_space_group_name_Hall'] = symmetry['hall'] cif.values[name]['_symmetry_Int_Tables_number'] = symmetry['tables'] cif.values[name]['_symmetry_equiv_pos_as_xyz'] = \ [symop_string_from_symop_matrix_tr(symmetry['rotations'][i], symmetry['translations'][i]) for i in range(len(symmetry['rotations']))] # Summary formula has to be calculated from non-reduced set of atoms. cif.values[name]['_chemical_formula_sum'] = \ StructureData(ase=original_atoms).get_formula(mode='hill', separator=' ') # If the number of reduced atoms multiplies the number of non-reduced # atoms, the new Z value can be calculated. if '_cell_formula_units_Z' in node.values[name].keys(): old_Z = node.values[name]['_cell_formula_units_Z'] if len(original_atoms) % len(refined_atoms): new_Z = old_Z * len(original_atoms) // len(refined_atoms) cif.values[name]['_cell_formula_units_Z'] = new_Z return {'cif': cif}
def mg_mof74_cifdata(): """CifData for Mg MOF74 CIF.""" from aiida.orm import CifData # pylint: disable=import-outside-toplevel with open(os.path.join(DATA_DIR, 'Mg_MOF_74.cif'), 'rb') as handle: cif = CifData(file=handle) return cif
def _get_cif(name): from aiida.orm import CifData if name == "pyrite": with open_resource_binary("cif", "pyrite.cif") as handle: return CifData(file=handle) raise ValueError(name)
def parse_stdout(self, filelike): """Parse the content written by the script to standard out. The standard output will contain a list of relative filepaths where the generated CIF files have been written. :param filelike: filelike object of stdout :returns: an exit code in case of an error, None otherwise """ from aiida.orm import CifData content = filelike.read().strip() if not content: return self.exit_codes.ERROR_EMPTY_OUTPUT_FILE # The filelike should be in binary mode, so we should decode the bytes, assuming the content is in `utf-8` content = content.decode('utf-8') try: cifs = {} for line in content.split('\n'): filename = line.strip() output_name = os.path.splitext(os.path.basename(filename))[0] with self.retrieved.open(filename, 'rb') as handle: cifs[output_name] = CifData(file=handle) except Exception: # pylint: disable=broad-except self.logger.exception( 'Failed to open a generated from the stdout file\n%s', traceback.format_exc()) return self.exit_codes.ERROR_PARSING_OUTPUT_DATA self.out('cifs', cifs) return
def get_ase_structure(self): """ :return: ASE structure corresponding to the cif file. """ from aiida.orm import CifData cif = correct_cif(self.cif) return CifData.read_cif(io.StringIO(cif))
def aiida_cif_merge(aiida_cif_a, aiida_cif_b): """Merge the coordinates of two CifData into a sigle one. Note: the two unit cells must be the same.""" ase_a = aiida_cif_a.get_ase() ase_b = aiida_cif_b.get_ase() if not ase_cells_are_similar(ase_a, ase_b.cell): raise ValueError('Attempting to merge two CifData (<{}> and <{}>) with different unit cells.'.format( aiida_cif_a.pk, aiida_cif_b.pk)) ase_ab = ase.Atoms( #Maybe there is a more direct way... symbols=list(ase_a.symbols) + list(ase_b.symbols), cell=ase_a.cell, positions=list(ase_a.positions) + list(ase_b.positions), pbc=True) cif_ab = CifData(ase=ase_ab, filename='fragments_a_b.cif') #TODO: check why the filename is not assigned. # pylint: disable=fixme cif_ab.label = 'Loaded structure' cif_ab.description = 'Fragment A: {} atoms, fragment B: {} atoms.'.format(len(ase_a), len(ase_b)) return cif_ab
def cif_import(filename): """Import .cif file into CifData object.""" from aiida.orm import CifData try: node, _ = CifData.get_or_create(filename) echo.echo_success('imported {}'.format(str(node))) except ValueError as err: echo.echo_critical(err)
def get_ase_structure(self): """ Returns ASE representation of the CIF. .. note:: To be removed, as it is duplicated in :py:class:`aiida.orm.nodes.data.cif.CifData`. """ from aiida.orm import CifData return CifData.read_cif(StringIO(self.cif))
def _generate_cif_data(element): """Return `UpfData` node.""" from aiida.orm import CifData filename = os.path.join('tests', 'fixtures', 'cif', '{}.cif'.format(element)) filepath = os.path.abspath(filename) with io.open(filepath, 'r') as handle: cif = CifData(file=handle.name) return cif
def _on_file_upload(self, change=None): """When file upload button is pressed.""" for fname, item in change['new'].items(): frmt = fname.split('.')[-1] if frmt == 'cif': self.structure = CifData(file=io.BytesIO(item['content'])) else: self.structure = get_ase_from_file(io.StringIO( item['content'].decode()), format=frmt) self.file_upload.value.clear() break
def _get_cif_ase_inline(struct, parameters): """ Creates :py:class:`aiida.orm.nodes.data.cif.CifData` using ASE. .. note:: requires ASE module. """ from aiida.orm import CifData kwargs = {} if parameters is not None: kwargs = parameters.get_dict() cif = CifData(ase=struct.get_ase(**kwargs)) formula = struct.get_formula(mode='hill', separator=' ') for i in cif.values.keys(): cif.values[i]['_symmetry_space_group_name_H-M'] = 'P 1' cif.values[i]['_symmetry_space_group_name_Hall'] = 'P 1' cif.values[i]['_symmetry_Int_Tables_number'] = 1 cif.values[i]['_cell_formula_units_Z'] = 1 cif.values[i]['_chemical_formula_sum'] = formula return {'cif': cif}
def example_base_workchain_widom_2(raspa_code): """Run base workchain for widom insertion calculation (1 component).""" # pylint: disable=no-member print("Testing RASPA Xenon and Krypton widom insertion through RaspaBaseWorkChain ...") parameters = Dict( dict={ "GeneralSettings": { "SimulationType": "MonteCarlo", "NumberOfCycles": 50, "PrintEvery": 10, "Forcefield": "GenericMOFs", "EwaldPrecision": 1e-6, "CutOff": 12.0, }, "System": { "tcc1rs": { "type": "Framework", "ExternalTemperature": 300.0, } }, "Component": { "krypton": { "MoleculeDefinition": "TraPPE", "WidomProbability": 1.0, "CreateNumberOfMolecules": 0, "BlockPocketsFileName": "block_tcc1rs_methane", }, "xenon": { "MoleculeDefinition": "TraPPE", "WidomProbability": 1.0, "CreateNumberOfMolecules": 0, "BlockPocketsFileName": "block_tcc1rs_xenon", }, }, }) # framework pwd = os.path.dirname(os.path.realpath(__file__)) structure = CifData(file=os.path.join(pwd, '..', 'files', 'TCC1RS.cif')) structure_label = structure.filename[:-4].lower() block_pocket_node1 = SinglefileData(file=os.path.join(pwd, '..', 'files', 'block_pocket.block')).store() block_pocket_node2 = SinglefileData(file=os.path.join(pwd, '..', 'files', 'block_pocket.block')).store() # Constructing builder builder = RaspaBaseWorkChain.get_builder() # Specifying the code builder.raspa.code = raspa_code # Specifying the framework builder.raspa.framework = { structure_label: structure, } # Specifying the input parameters builder.raspa.parameters = parameters # Specifying the block pockets builder.raspa.block_pocket = { "block_tcc1rs_methane": block_pocket_node1, "block_tcc1rs_xenon": block_pocket_node2, } # Add fixers that could handle physics-related problems. builder.fixers = { 'fixer_001': ('aiida_raspa.utils', 'check_widom_convergence', 0.1, 2000), } # Specifying the scheduler options builder.raspa.metadata.options = { "resources": { "num_machines": 1, "num_mpiprocs_per_machine": 1, }, "max_wallclock_seconds": 1 * 30 * 60, # 30 min "withmpi": False, } run(builder)
def example_ff_files(raspa_code, submit=True): """Prepare and submit RASPA calculation with components mixture.""" # parameters parameters = Dict( dict={ "GeneralSettings": { "SimulationType": "MonteCarlo", "NumberOfInitializationCycles": 200, "NumberOfCycles": 300, "PrintEvery": 100, "Forcefield": "Local", "ChargeMethod": "Ewald", "EwaldPrecision": 1e-6, "CutOff": 12.0, }, "System": { "irmof_1": { "type": "Framework", "UnitCells": "1 1 1", "HeliumVoidFraction": 0.149, "ExternalTemperature": 300.0, "ExternalPressure": 1e5, } }, "Component": { "CO2": { "MoleculeDefinition": "Local", "MolFraction": 0.30, "TranslationProbability": 1.0, "RotationProbability": 1.0, "ReinsertionProbability": 1.0, "SwapProbability": 1.0, "CreateNumberOfMolecules": 0, }, "N2": { "MoleculeDefinition": "Local", "MolFraction": 0.70, "TranslationProbability": 1.0, "RotationProbability": 1.0, "ReinsertionProbability": 1.0, "SwapProbability": 1.0, "CreateNumberOfMolecules": 0, }, }, }) # Contructing builder pwd = os.path.dirname(os.path.realpath(__file__)) builder = raspa_code.get_builder() builder.framework = { "irmof_1": CifData(file=os.path.join(pwd, '..', 'files', 'IRMOF-1_eqeq.cif')), } # Note: Here the SinglefileData in the dict are stored otherwise the dry_run crashes. # However, this is not needed for real calculations (e.g., using --submit), since the work chains stores them. builder.file = { "file_1": SinglefileData(file=os.path.join( pwd, '..', 'files', 'force_field_mixing_rules.def')).store(), "file_2": SinglefileData( file=os.path.join(pwd, '..', 'files', 'pseudo_atoms.def')).store(), "file_3": SinglefileData( file=os.path.join(pwd, '..', 'files', 'CO2.def')).store(), "file_4": SinglefileData( file=os.path.join(pwd, '..', 'files', 'N2.def')).store(), } builder.parameters = parameters builder.metadata.options = { "resources": { "num_machines": 1, "num_mpiprocs_per_machine": 1, }, "max_wallclock_seconds": 1 * 30 * 60, # 30 min "withmpi": False, } builder.metadata.dry_run = False builder.metadata.store_provenance = True if submit: print( "Testing RASPA CO2/N2 adsorption in IRMOF-1, using Local force field ..." ) res, pk = run_get_pk(builder) print("calculation pk: ", pk) print("CO2/N2 uptake ({:s}): {:.2f}/{:.2f} ".format( res['output_parameters']["irmof_1"]["components"]['N2'] ["loading_absolute_unit"], res['output_parameters']["irmof_1"]["components"]['CO2'] ["loading_absolute_average"], res['output_parameters']["irmof_1"]["components"]['N2'] ["loading_absolute_average"], )) print("OK, calculation has completed successfully") else: print("Generating test input ...") builder.metadata.dry_run = True builder.metadata.store_provenance = False run(builder) print("Submission test successful") print("In order to actually submit, add '--submit'") print("-----")
def _generate_structure_cif(cif_filepath): """Return a `StructureData` from a cif file.""" from aiida.orm import CifData structure = CifData.get_or_create(cif_filepath)[0].get_structure() return structure
def test_extract_structure_info(clear_database_aiida_fleur, generate_structure, generate_work_chain_node, fixture_localhost): """ I do not test 'extras' here due to some kind of bug """ from aiida_fleur.tools.data_handling import extract_structure_info from aiida_fleur.tools.common_aiida import create_group from aiida_fleur.tools.read_cif_folder import wf_struc_from_cif from aiida.orm import CalcFunctionNode, load_node, CifData from aiida.common import LinkType pks = [] uuids = [] for i in range(3): structure_bulk = generate_structure() structure_bulk.append_atom(position=(i, 0., -1.99285), symbols='Se') structure_bulk.store() pks.append(structure_bulk.pk) uuids.append(structure_bulk.uuid) cif_data = CifData(file=TEST_CIF) cif_data.store() cif_structure = wf_struc_from_cif(cif_data) print(cif_structure.get_incoming().all()) # create CalcFunction having StructureData input calc_function = CalcFunctionNode() calc_function.set_attribute('process_label', 'test_label') calc_function.add_incoming(structure_bulk, link_type=LinkType.INPUT_CALC, link_label='test_calcfundtion') calc_function.store() # create WorkChainNode scf having StructureData input scf_wc = generate_work_chain_node(computer=fixture_localhost, entry_point_name='aiida_fleur.scf', inputs={'structure': load_node(pks[1])}) scf_wc.store() scf_wc.set_attribute('process_label', 'fleur_scf_wc') # create a group group = create_group(name='test_group', nodes=pks[:2], description='test_description') result = extract_structure_info(keys=[ 'uuid', 'formula', 'pk', 'symmetry', 'pbc', 'volume', 'total_energy', 'child_nodes', 'natoms', 'group', 'label', 'description', 'cif_file', 'cif_number', 'cif_uuid', 'cif_ref', 'calcfunctions', 'band', 'dos', 'eos', 'init_cls', 'corehole', 'primitive', 'cell', 'scf' ]) # print(result) # assert 0 correct_result = [ sorted({ 'formula': 'AlB2', 'pk': cif_structure.pk, 'uuid': cif_structure.uuid, 'natoms': 3, 'cell': '[[3.009, 0.0, 0.0], [-1.5045, 2.6058704399874, 0.0], [0.0, 0.0, 3.262]]', 'pbc': '(True, True, True)', 'label': '', 'description': '', # 'extras': "{{'_aiida_hash': {0}}}".format(cif_structure.get_hash()), 'symmetry': 'Amm2 (38)', 'volume': 25.57755127009385, 'child_nodes': 0, 'primitive': False, 'cif_file': ['AlB.cif', cif_data.uuid], 'group': [], 'scf': [], 'band': [], 'dos': [], 'eos': [], 'init_cls': [], 'corehole': [], 'calcfunctions': [[], []], }), sorted({ 'formula': 'SeSi2', 'pk': pks[2], 'uuid': uuids[2], 'natoms': 3, 'cell': '[[2.715, 2.715, 0.0], [2.715, 0.0, 2.715], [0.0, 2.715, 2.715]]', 'pbc': '(True, True, True)', 'label': '', 'description': '', # 'extras': "{{'_aiida_hash': {0}}}".format(load_node(pks[2]).get_hash()), 'symmetry': 'P1 (1)', 'volume': 40.02575174999999, 'child_nodes': 1, 'primitive': False, 'cif_file': ['', ''], 'group': [], 'scf': [], 'band': [], 'dos': [], 'eos': [], 'init_cls': [], 'corehole': [], 'calcfunctions': [[calc_function.uuid], ['test_label']], }), sorted({ 'formula': 'SeSi2', 'pk': pks[1], 'uuid': uuids[1], 'natoms': 3, 'cell': '[[2.715, 2.715, 0.0], [2.715, 0.0, 2.715], [0.0, 2.715, 2.715]]', 'pbc': '(True, True, True)', 'label': '', 'description': '', # 'extras': "{{'_aiida_hash': {0}}}".format(load_node(pks[1]).get_hash()), 'symmetry': 'P1 (1)', 'volume': 40.02575174999999, 'child_nodes': 1, 'primitive': False, 'cif_file': ['', ''], 'group': ['test_group'], 'scf': [scf_wc.uuid], 'band': [], 'dos': [], 'eos': [], 'init_cls': [], 'corehole': [], 'calcfunctions': [[], []], }), sorted({ 'formula': 'SeSi2', 'pk': pks[0], 'uuid': uuids[0], 'natoms': 3, 'cell': '[[2.715, 2.715, 0.0], [2.715, 0.0, 2.715], [0.0, 2.715, 2.715]]', 'pbc': '(True, True, True)', 'label': '', 'description': '', # 'extras': "{{'_aiida_hash': {0}}}".format(load_node(pks[0]).get_hash), 'symmetry': 'Imm2 (44)', 'volume': 40.02575174999999, 'child_nodes': 0, 'primitive': False, 'cif_file': ['', ''], 'group': ['test_group'], 'scf': [], 'band': [], 'dos': [], 'eos': [], 'init_cls': [], 'corehole': [], 'calcfunctions': [[], []], }) ] for i in result: assert sorted(i) in correct_result
def example_base_restart_timeout(raspa_code): """Run base workchain for GCMC with restart after timeout.""" # pylint: disable=no-member print("Testing RaspaBaseWorkChain restart after timeout...") print( "This long simulation will require ca. 3 iterations (i.e., 2 restarts)." ) parameters = Dict( dict={ "GeneralSettings": { "SimulationType": "MonteCarlo", "NumberOfInitializationCycles": 5000, # many, to pass timeout "NumberOfCycles": 5000, # many, to pass timeout "PrintEvery": 1000, "Forcefield": "GenericMOFs", "RemoveAtomNumberCodeFromLabel": True, "ChargeMethod": "None", "CutOff": 12.0, # WriteBinaryRestartFileEvery not needed: if missing RaspaBaseWorkChain will assign a default of 1000 }, "System": { "irmof_1": { "type": "Framework", "UnitCells": "1 1 1", "ExternalTemperature": 300.0, "ExternalPressure": 1e5, } }, "Component": { "krypton": { "MoleculeDefinition": "TraPPE", "TranslationProbability": 0.5, "ReinsertionProbability": 0.5, "SwapProbability": 1.0, "BlockPocketsFileName": { "irmof_1": "irmof_1_krypton", }, }, }, }) # framework pwd = os.path.dirname(os.path.realpath(__file__)) structure = CifData(file=os.path.join(pwd, '..', 'files', 'IRMOF-1.cif')) structure_label = "irmof_1" block_pocket_node1 = SinglefileData( file=os.path.join(pwd, '..', 'files', 'IRMOF-1_test.block')).store() # Constructing builder builder = RaspaBaseWorkChain.get_builder() # Specifying the code builder.raspa.code = raspa_code # Specifying the framework builder.raspa.framework = { structure_label: structure, } # Specifying the input parameters builder.raspa.parameters = parameters # Specifying the block pockets builder.raspa.block_pocket = { "irmof_1_krypton": block_pocket_node1, } # Specifying the scheduler options builder.raspa.metadata.options = { "resources": { "num_machines": 1, "num_mpiprocs_per_machine": 1, }, "max_wallclock_seconds": 1 * 30 * 60, # 30 min "withmpi": True, "mpirun_extra_params": ["timeout", "5"], # kill the calculation after 5 seconds, to test restart } # Specify RaspaBaseWorkChain options builder.max_iterations = Int( 8 ) # number of maximum iterations: prevent for infinite restart (default: 5) run(builder)
def example_base_workchain_gcmc(raspa_code): """Run base workchain for GCMC calculations with 2 components.""" # pylint: disable=no-member print("Testing RASPA Xenon:Krypton GCMC through RaspaBaseWorkChain ...") parameters = Dict( dict={ "GeneralSettings": { "SimulationType": "MonteCarlo", "NumberOfCycles": 2000, "NumberOfInitializationCycles": 2000, "PrintEvery": 200, "Forcefield": "GenericMOFs", "RemoveAtomNumberCodeFromLabel": True, "EwaldPrecision": 1e-6, "CutOff": 12.0, }, "System": { "irmof_1": { "type": "Framework", "UnitCells": "1 1 1", "HeliumVoidFraction": 0.149, "ExternalTemperature": 300.0, "ExternalPressure": 1e5, } }, "Component": { "krypton": { "MoleculeDefinition": "TraPPE", "TranslationProbability": 0.5, "ReinsertionProbability": 0.5, "SwapProbability": 1.0, "BlockPocketsFileName": { "irmof_1": "irmof_1_krypton", }, }, "xenon": { "MoleculeDefinition": "TraPPE", "TranslationProbability": 0.5, "ReinsertionProbability": 0.5, "SwapProbability": 1.0, "BlockPocketsFileName": { "irmof_1": "irmof_1_xenon", }, }, }, }) # framework pwd = os.path.dirname(os.path.realpath(__file__)) structure = CifData(file=os.path.join(pwd, '..', 'files', 'IRMOF-1.cif')) structure_label = "irmof_1" block_pocket_node1 = SinglefileData( file=os.path.join(pwd, '..', 'files', 'IRMOF-1_test.block')).store() block_pocket_node2 = SinglefileData( file=os.path.join(pwd, '..', 'files', 'IRMOF-1_test.block')).store() # Constructing builder builder = RaspaBaseWorkChain.get_builder() # Specifying the code builder.raspa.code = raspa_code # Specifying the framework builder.raspa.framework = { structure_label: structure, } # Specifying the input parameters builder.raspa.parameters = parameters # Specifying the block pockets builder.raspa.block_pocket = { "irmof_1_krypton": block_pocket_node1, "irmof_1_xenon": block_pocket_node2, } # Add fixers that could handle physics-related problems. builder.fixers = { 'fixer_001': ('aiida_raspa.utils', 'check_gcmc_convergence', 0.10, 2000, 2000), } # Specifying the scheduler options builder.raspa.metadata.options = { "resources": { "num_machines": 1, "num_mpiprocs_per_machine": 1, }, "max_wallclock_seconds": 1 * 30 * 60, # 30 min "withmpi": False, } run(builder)