From 1c85ad3325d109c15971c920630faaee853e58a3 Mon Sep 17 00:00:00 2001 From: Marnik Bercx Date: Wed, 13 Dec 2023 21:17:43 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20`occupancy=5Ftolerance`=20inp?= =?UTF-8?q?ut?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../functions/primitive_structure_from_cif.py | 12 ++++++++++-- src/aiida_codtools/cli/workflows/cif_clean.py | 9 ++++++--- src/aiida_codtools/workflows/cif_clean.py | 4 ++++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/aiida_codtools/calculations/functions/primitive_structure_from_cif.py b/src/aiida_codtools/calculations/functions/primitive_structure_from_cif.py index 5fae4ee..05f7a74 100644 --- a/src/aiida_codtools/calculations/functions/primitive_structure_from_cif.py +++ b/src/aiida_codtools/calculations/functions/primitive_structure_from_cif.py @@ -9,7 +9,8 @@ @calcfunction -def primitive_structure_from_cif(cif, parse_engine, symprec, site_tolerance): +def primitive_structure_from_cif(cif, parse_engine, symprec, site_tolerance, occupancy_tolerance): + # pylint: disable=too-many-return-statements """Attempt to parse the given `CifData` and create a `StructureData` from it. First the raw CIF file is parsed with the given `parse_engine`. The resulting `StructureData` is then passed through @@ -21,12 +22,19 @@ def primitive_structure_from_cif(cif, parse_engine, symprec, site_tolerance): :param symprec: a `Float` node with symmetry precision for determining primitive cell in SeeKpath :param site_tolerance: a `Float` node with the fractional coordinate distance tolerance for finding overlapping sites. This will only be used if the parse_engine is pymatgen + :param occupancy_tolerance: a `Float` node with the occupancy tolerance below which occupancies will be scaled down + to 1. This will only be used if the parse_engine is pymatgen :return: the primitive `StructureData` as determined by SeeKpath """ CifCleanWorkChain = WorkflowFactory('codtools.cif_clean') # pylint: disable=invalid-name try: - structure = cif.get_structure(converter=parse_engine.value, site_tolerance=site_tolerance.value, store=False) + structure = cif.get_structure( + converter=parse_engine.value, + site_tolerance=site_tolerance.value, + occupancy_tolerance=occupancy_tolerance.value, + store=False + ) except exceptions.UnsupportedSpeciesError: return CifCleanWorkChain.exit_codes.ERROR_CIF_HAS_UNKNOWN_SPECIES except InvalidOccupationsError: diff --git a/src/aiida_codtools/cli/workflows/cif_clean.py b/src/aiida_codtools/cli/workflows/cif_clean.py index 0ad0ffc..bf64b41 100644 --- a/src/aiida_codtools/cli/workflows/cif_clean.py +++ b/src/aiida_codtools/cli/workflows/cif_clean.py @@ -39,12 +39,15 @@ @click.option( '-p', '--parse-engine', type=click.Choice(['ase', 'pymatgen']), default='pymatgen', show_default=True, help='Select the parse engine for parsing the structure from the cleaned cif if requested.') +@click.option( + '-O', '--occupancy-tolerance', type=click.FLOAT, default=1.0, show_default=True, + help='If total occupancy of a site is between 1 and occupancy_tolerance, the occupancies will be scaled down to 1.') @click.option( '-d', '--daemon', is_flag=True, default=False, show_default=True, help='Submit the process to the daemon instead of running it locally.') @decorators.with_dbenv() def launch_cif_clean(cif_filter, cif_select, group_cif_raw, group_cif_clean, group_structure, group_workchain, node, - max_entries, skip_check, parse_engine, daemon): + max_entries, skip_check, parse_engine, occupancy_tolerance, daemon): """Run the `CifCleanWorkChain` on the entries in a group with raw imported CifData nodes. It will use the `cif_filter` and `cif_select` scripts of `cod-tools` to clean the input cif file. Additionally, if @@ -132,8 +135,7 @@ def launch_cif_clean(cif_filter, cif_select, group_cif_raw, group_cif_clean, gro }) node_parse_engine = get_input_node(orm.Str, parse_engine) - node_site_tolerance = get_input_node(orm.Float, 5E-4) - node_symprec = get_input_node(orm.Float, 5E-3) + node_occupancy_tolerance = get_input_node(orm.Float, occupancy_tolerance) for cif in nodes: @@ -155,6 +157,7 @@ def launch_cif_clean(cif_filter, cif_select, group_cif_raw, group_cif_clean, gro }, 'parse_engine': node_parse_engine, 'site_tolerance': node_site_tolerance, + 'occupancy_tolerance': node_occupancy_tolerance, 'symprec': node_symprec, } diff --git a/src/aiida_codtools/workflows/cif_clean.py b/src/aiida_codtools/workflows/cif_clean.py index d19dee5..e654309 100644 --- a/src/aiida_codtools/workflows/cif_clean.py +++ b/src/aiida_codtools/workflows/cif_clean.py @@ -34,6 +34,9 @@ def define(cls, spec): help='The symmetry precision used by SeeKpath for crystal symmetry refinement.') spec.input('site_tolerance', valid_type=orm.Float, default=lambda: orm.Float(5E-4), help='The fractional coordinate distance tolerance for finding overlapping sites (pymatgen only).') + spec.input('occupancy_tolerance', valid_type=orm.Float, default=orm.Float(1.0), + help='If total occupancy of a site is between 1 and occupancy_tolerance, the occupancies will be scaled'\ + + 'down to 1 (pymatgen only).') spec.input('group_cif', valid_type=orm.Group, required=False, non_db=True, help='An optional Group to which the final cleaned CifData node will be added.') spec.input('group_structure', valid_type=orm.Group, required=False, non_db=True, @@ -141,6 +144,7 @@ def parse_cif_structure(self): 'cif': self.ctx.cif, 'parse_engine': self.inputs.parse_engine, 'site_tolerance': self.inputs.site_tolerance, + 'occupancy_tolerance': self.inputs.occupancy_tolerance, 'symprec': self.inputs.symprec, 'metadata': { 'call_link_label': 'primitive_structure_from_cif'