diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3a7e94c3..e485b636 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,7 +8,7 @@ exclude: > repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: check-json - id: check-yaml @@ -16,7 +16,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.8.6 + rev: v0.16.8 hooks: - id: ruff args: [--fix] diff --git a/conftest.py b/conftest.py index 612c0bff..aaef9d03 100644 --- a/conftest.py +++ b/conftest.py @@ -64,8 +64,8 @@ def get_work_directory(config): def pytest_report_header(config): """Add header information for pytest execution.""" return [ - f'LAMMPS Executable: {shutil.which(config.getoption("lammps_exec") or "lammps")}', - f'LAMMPS Work Directory: {config.getoption("lammps_workdir") or ""}', + f"LAMMPS Executable: {shutil.which(config.getoption('lammps_exec') or 'lammps')}", + f"LAMMPS Work Directory: {config.getoption('lammps_workdir') or ''}", ] diff --git a/docs/source/conf.py b/docs/source/conf.py index 3e805203..754db62f 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -150,6 +150,6 @@ with open("nitpick-exceptions") as handle: nitpick_ignore = [ tuple(line.strip().split(None, 1)) - for line in handle.readlines() + for line in handle if line.strip() and not line.startswith("#") ] diff --git a/docs/source/getting_started/index.md b/docs/source/getting_started/index.md index 7157ac6b..63e22dec 100644 --- a/docs/source/getting_started/index.md +++ b/docs/source/getting_started/index.md @@ -99,11 +99,11 @@ from pathlib import Path # Create the node with the computer computer = Computer( - label='localhost', - hostname='localhost', - transport_type='core.local', - scheduler_type='core.direct', - workdir=Path('/home/my_username/aiida_workspace').resolve() + label="localhost", + hostname="localhost", + transport_type="core.local", + scheduler_type="core.direct", + workdir=Path("/home/my_username/aiida_workspace").resolve(), ) # Store the node in the database computer.store() @@ -143,14 +143,14 @@ To define the [InstalledCode](https://aiida.readthedocs.io/projects/aiida-core/e from aiida.orm import InstalledCode # Load the computer resource where LAMMPS is installed -computer = load_computer('localhost') +computer = load_computer("localhost") # Define the code node code = InstalledCode( - label='lammps', + label="lammps", computer=computer, - filepath_executable='/path/to/lammps/lmp', - default_calc_job_plugin='lammps.base' + filepath_executable="/path/to/lammps/lmp", + default_calc_job_plugin="lammps.base", ) # Store the code node in the database diff --git a/docs/source/topics/data/parameters.md b/docs/source/topics/data/parameters.md index 9c32174f..a77204b9 100644 --- a/docs/source/topics/data/parameters.md +++ b/docs/source/topics/data/parameters.md @@ -16,35 +16,35 @@ The behavior of the {{ aiida_lammps }} calculation can be controlled by collecti ```python parameters = { - 'md': { - 'velocity': [{'group': 'all', 'create': {'temp': 300}}], - 'integration': { - 'style': 'npt', - 'constraints': {'iso': [0.0, 0.0, 1000.0], 'temp': [300, 300, 100]} + "md": { + "velocity": [{"group": "all", "create": {"temp": 300}}], + "integration": { + "style": "npt", + "constraints": {"iso": [0.0, 0.0, 1000.0], "temp": [300, 300, 100]}, }, - 'max_number_steps': 5000 + "max_number_steps": 5000, }, - 'dump': {'dump_rate': 1000}, - 'thermo': { - 'printing_rate': 100, - 'thermo_printing': { - 'ke': True, - 'pe': True, - 'pxx': True, - 'pyy': True, - 'pzz': True, - 'step': True, - 'press': True - } + "dump": {"dump_rate": 1000}, + "thermo": { + "printing_rate": 100, + "thermo_printing": { + "ke": True, + "pe": True, + "pxx": True, + "pyy": True, + "pzz": True, + "step": True, + "press": True, + }, }, - 'compute': { - 'ke/atom': [{'type': [{'value': ' ', 'keyword': ' '}], 'group': 'all'}], - 'pe/atom': [{'type': [{'value': ' ', 'keyword': ' '}], 'group': 'all'}], - 'pressure': [{'type': ['thermo_temp'], 'group': 'all'}], - 'stress/atom': [{'type': ['NULL'], 'group': 'all'}] + "compute": { + "ke/atom": [{"type": [{"value": " ", "keyword": " "}], "group": "all"}], + "pe/atom": [{"type": [{"value": " ", "keyword": " "}], "group": "all"}], + "pressure": [{"type": ["thermo_temp"], "group": "all"}], + "stress/atom": [{"type": ["NULL"], "group": "all"}], }, - 'control': {'units': 'metal', 'timestep': 1e-05}, - 'structure': {'atom_style': 'atomic'} + "control": {"units": "metal", "timestep": 1e-05}, + "structure": {"atom_style": "atomic"}, } ``` diff --git a/docs/source/topics/data/potential.md b/docs/source/topics/data/potential.md index 5e426bf0..75bafa28 100644 --- a/docs/source/topics/data/potential.md +++ b/docs/source/topics/data/potential.md @@ -18,47 +18,49 @@ To demonstrate how this works one can [download](https://openkim.org/id/EAM_Dyna ```python potential_parameters = { - 'species': ['Fe'], # Which species can be treated by this potential (required) - 'atom_style': 'atomic', # Which kind of atomic style is associated with this potential (required) - 'pair_style': 'eam/fs', # LAMMPS pair style (required) - 'units': 'metal', # Default units of this potential (required) - 'extra_tags': { - 'content_origin': 'NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html', # Where the file was original found - 'content_other_locations': None, # If the file can be found somewhere else - 'data_method': 'unknown', # How was the data generated - 'description': """ + "species": ["Fe"], # Which species can be treated by this potential (required) + "atom_style": "atomic", # Which kind of atomic style is associated with this potential (required) + "pair_style": "eam/fs", # LAMMPS pair style (required) + "units": "metal", # Default units of this potential (required) + "extra_tags": { + "content_origin": "NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html", # Where the file was original found + "content_other_locations": None, # If the file can be found somewhere else + "data_method": "unknown", # How was the data generated + "description": """ This Fe EAM potential parameter file is from the NIST repository, \"Fe_2.eam.fs\" as of the March 9, 2009 update. It is similar to \"Fe_mm.eam.fs\" in the LAMMPS distribution dated 2007-06-11, but gives different results for very small interatomic distances (The LAMMPS potential is in fact the deprecated potential referred to in the March 9, 2009 update on the NIST repository). The file header includes a note from the NIST contributor: \"The potential was taken from v9_4_bcc (in C:\\SIMULATION.MD\\Fe\\Results\\ab_initio+Interstitials)\" - """, # Short description of the potential - 'developer': ['Ronald E. Miller'], # Name of the developer that uploaded it to OpenKIM - 'disclaimer': """ + """, # Short description of the potential + "developer": [ + "Ronald E. Miller" + ], # Name of the developer that uploaded it to OpenKIM + "disclaimer": """ According to the developer Giovanni Bonny (as reported by the NIST IPRP), this potential was not stiffened and cannot be used in its present form for collision cascades. - """, # Any known issues with the potential - 'properties': None, # If any specific properties are associated to the potential - 'publication_year': 2018, # Year of publication to OpenKIM - 'source_citations': [{ - 'abstract': None, - 'author': - 'Mendelev, MI and Han, S and Srolovitz, DJ and Ackland, GJ and Sun, DY and Asta, M', - 'doi': '10.1080/14786430310001613264', - 'journal': '{Phil. Mag.}', - 'number': '{35}', - 'pages': '{3977-3994}', - 'recordkey': 'MO_546673549085_000a', - 'recordprimary': 'recordprimary', - 'recordtype': 'article', - 'title': - '{Development of new interatomic potentials appropriate for crystalline and liquid iron}', - 'volume': '{83}', - 'year': '{2003}' - }], - 'title': 'EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000' # Title of the potential - } + """, # Any known issues with the potential + "properties": None, # If any specific properties are associated to the potential + "publication_year": 2018, # Year of publication to OpenKIM + "source_citations": [ + { + "abstract": None, + "author": "Mendelev, MI and Han, S and Srolovitz, DJ and Ackland, GJ and Sun, DY and Asta, M", + "doi": "10.1080/14786430310001613264", + "journal": "{Phil. Mag.}", + "number": "{35}", + "pages": "{3977-3994}", + "recordkey": "MO_546673549085_000a", + "recordprimary": "recordprimary", + "recordtype": "article", + "title": "{Development of new interatomic potentials appropriate for crystalline and liquid iron}", + "volume": "{83}", + "year": "{2003}", + } + ], + "title": "EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000", # Title of the potential + }, } ``` Certain tags are required, and must be provided to be able to upload the potential to the database. This is because they identify which {{ pair_style }} is associated with the potential, which atomic species can be treated with it, etc. The rest of the tags, in this example are filled so that they follow the [OpenKIM](https://openkim.org/doc/schema/kimspec/) standard as that is the place where the potential was obtained. If another database is used or if it is a homemade potential, these tags can be used to facilitate the querying of the potential. @@ -68,10 +70,9 @@ Then the potential can be uploaded to the database from aiida_lamps.data.potential import LammpsPotentialData potential = LammpsPotentialData.get_or_create( - source='Fe_2.eam.fs', # Relative path to the potential file - **potential_parameters, # Parameters to tag the potential + source="Fe_2.eam.fs", # Relative path to the potential file + **potential_parameters, # Parameters to tag the potential ) - ``` The {meth}`~aiida_lammps.data.potential.LammpsPotentialData.get_or_create` method is based on the one by [aiida-pseudo](https://github.com/aiidateam/aiida-pseudo/blob/master/aiida_pseudo/data/pseudo/pseudo.py), which will calculate the md5 sum of the file and check the database for another file with the same [md5 hash](https://en.wikipedia.org/wiki/MD5), if such entry is found, that potential is used instead. This avoids the unnecessary replication of potential data nodes whenever one tries to upload a previously uploaded potential. diff --git a/docs/source/tutorials/first_md.md b/docs/source/tutorials/first_md.md index d633c5c2..2b3b2df1 100644 --- a/docs/source/tutorials/first_md.md +++ b/docs/source/tutorials/first_md.md @@ -31,7 +31,7 @@ Then, load the code that was setup in AiiDA for `lmp` and get an instance of the ```python # Load the code configured for ``lmp``. Make sure to replace # this string with the label used in the code setup. -code = load_code('lammps@localhost') +code = load_code("lammps@localhost") builder = code.get_builder() ``` @@ -40,7 +40,8 @@ One can start by defining and assigning the structure to the builder: ```python from ase.build import bulk -structure = StructureData(ase=bulk('Fe', 'bcc', 2.87, cubic=True)) + +structure = StructureData(ase=bulk("Fe", "bcc", 2.87, cubic=True)) builder.structure = structure ``` @@ -60,24 +61,28 @@ import requests import io # Download the potential from the repository and store it as a BytesIO object -_stream = io.BytesIO(requests.get('https://openkim.org/files/MO_546673549085_000/Fe_2.eam.fs', timeout=20).text.encode('utf-8')) +_stream = io.BytesIO( + requests.get( + "https://openkim.org/files/MO_546673549085_000/Fe_2.eam.fs", timeout=20 + ).text.encode("utf-8") +) # Set the metadata for the potential potential_parameters = { - 'species': ['Fe'], - 'atom_style': 'atomic', - 'pair_style': 'eam/fs', - 'units': 'metal', - 'extra_tags': { - 'title': 'EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000', - 'content_origin': 'NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html', - 'developer': ['Ronald E. Miller'], - 'publication_year': 2018, - } + "species": ["Fe"], + "atom_style": "atomic", + "pair_style": "eam/fs", + "units": "metal", + "extra_tags": { + "title": "EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000", + "content_origin": "NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html", + "developer": ["Ronald E. Miller"], + "publication_year": 2018, + }, } # Store the potential in an AiiDA node -potential = LammpsPotentialData.get_or_create(source=_stream,**potential_parameters) +potential = LammpsPotentialData.get_or_create(source=_stream, **potential_parameters) builder.potential = potential ``` @@ -95,45 +100,42 @@ Then one needs to define the parameters which control how the input file for the For a structural minimization the minimal set of parameters is the following: ```python - # Parameters to control the input file generation -parameters = Dict({ - "control": { - "units": "metal", - "timestep": 1e-5 - }, - "compute":{ - "pe/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], - "ke/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], - "stress/atom": [{"type": ["NULL"], "group": "all"}], - "pressure": [{"type": ["thermo_temp"], "group": "all"}], - }, - - "structure":{"atom_style": "atomic"}, - "thermo":{ - "printing_rate": 100, - "thermo_printing": { - "step": True, - "pe": True, - "ke": True, - "press": True, - "pxx": True, - "pyy": True, - "pzz": True, - } - }, - "md":{ - "integration": { - "style": "npt", - "constraints": { - "temp": [300, 300, 100], - "iso": [0.0, 0.0, 1000.0], +parameters = Dict( + { + "control": {"units": "metal", "timestep": 1e-5}, + "compute": { + "pe/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], + "ke/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], + "stress/atom": [{"type": ["NULL"], "group": "all"}], + "pressure": [{"type": ["thermo_temp"], "group": "all"}], + }, + "structure": {"atom_style": "atomic"}, + "thermo": { + "printing_rate": 100, + "thermo_printing": { + "step": True, + "pe": True, + "ke": True, + "press": True, + "pxx": True, + "pyy": True, + "pzz": True, }, }, - "max_number_steps": 5000, - "velocity": [{"create": {"temp": 300}, "group": "all"}], - }, -}) + "md": { + "integration": { + "style": "npt", + "constraints": { + "temp": [300, 300, 100], + "iso": [0.0, 0.0, 1000.0], + }, + }, + "max_number_steps": 5000, + "velocity": [{"create": {"temp": 300}, "group": "all"}], + }, + } +) builder.parameters = parameters ``` The parameters have several sections which control different behavior of the calculation: @@ -154,11 +156,11 @@ Lastly one needs to define the computational resources needed to perform the cal # Run the calculation on 1 CPU and kill it if it runs longer than 1800 seconds. # Set ``withmpi`` to ``False`` if ``pw.x`` was compiled without MPI support. builder.metadata.options = { - 'resources': { - 'num_machines': 1, + "resources": { + "num_machines": 1, }, - 'max_wallclock_seconds': 1800, - 'withmpi': False, + "max_wallclock_seconds": 1800, + "withmpi": False, } ``` @@ -213,5 +215,5 @@ The `time_dependent_computes` contains a series of numpy arrays each one represe The complete output that was written by {{ LAMMPS }} to stdout, can be retrieved as follows: ```python -results['retrieved'].base.repository.get_object_content('aiida_lammps.out') +results["retrieved"].base.repository.get_object_content("aiida_lammps.out") ``` diff --git a/docs/source/tutorials/first_raw.md b/docs/source/tutorials/first_raw.md index 82dd4764..de9a1af3 100644 --- a/docs/source/tutorials/first_raw.md +++ b/docs/source/tutorials/first_raw.md @@ -36,7 +36,7 @@ Then, load the code that was setup in AiiDA for `lmp` and get an instance of the ```python # Load the code configured for ``lmp``. Make sure to replace # this string with the label used in the code setup. -code = load_code('lammps@localhost') +code = load_code("lammps@localhost") builder = CalculationFactory("lammps.raw").get_builder() builder.code = code ``` @@ -90,7 +90,10 @@ As one can notice the script wants to read a file named `data.rhodo` via the [`r ```python import requests -request = requests.get("https://raw.githubusercontent.com/lammps/lammps/develop/bench/data.rhodo") + +request = requests.get( + "https://raw.githubusercontent.com/lammps/lammps/develop/bench/data.rhodo" +) data = SinglefileData(io.StringIO(request.text)) builder.files = {"data": data} builder.filenames = {"data": "data.rhodo"} @@ -105,11 +108,11 @@ Lastly one needs to define the computational resources needed to perform the cal # Run the calculation on 1 CPU and kill it if it runs longer than 1800 seconds. # Set ``withmpi`` to ``False`` if ``pw.x`` was compiled without MPI support. builder.metadata.options = { - 'resources': { - 'num_machines': 1, + "resources": { + "num_machines": 1, }, - 'max_wallclock_seconds': 1800, - 'withmpi': False, + "max_wallclock_seconds": 1800, + "withmpi": False, } ``` @@ -145,21 +148,21 @@ The `results` node is a dictionary that will contain some basic parsed informati ```python -print(outputs['results'].get_dict()) +print(outputs["results"].get_dict()) { - 'compute_variables': { - 'bin': 'standard', - 'bins': [10, 13, 13], - 'errors': [], - 'binsize': 6, - 'warnings': [], - 'units_style': 'real', - 'total_wall_time': '0:00:20', - 'steps_per_second': 5.046, - 'ghost_atom_cutoff': 12, - 'max_neighbors_atom': 2000, - 'total_wall_time_seconds': 20, - 'master_list_distance_cutoff': 12 + "compute_variables": { + "bin": "standard", + "bins": [10, 13, 13], + "errors": [], + "binsize": 6, + "warnings": [], + "units_style": "real", + "total_wall_time": "0:00:20", + "steps_per_second": 5.046, + "ghost_atom_cutoff": 12, + "max_neighbors_atom": 2000, + "total_wall_time_seconds": 20, + "master_list_distance_cutoff": 12, } } ``` @@ -167,5 +170,5 @@ print(outputs['results'].get_dict()) The complete output that was written by {{ LAMMPS }} to stdout, can be retrieved as follows: ```python -results['retrieved'].base.repository.get_object_content('lammps.out') +results["retrieved"].base.repository.get_object_content("lammps.out") ``` diff --git a/docs/source/tutorials/first_relaxation.md b/docs/source/tutorials/first_relaxation.md index daf777c1..7d5de089 100644 --- a/docs/source/tutorials/first_relaxation.md +++ b/docs/source/tutorials/first_relaxation.md @@ -31,7 +31,7 @@ Then, load the code that was setup in AiiDA for `lmp` and get an instance of the ```python # Load the code configured for ``lmp``. Make sure to replace # this string with the label used in the code setup. -code = load_code('lammps@localhost') +code = load_code("lammps@localhost") builder = code.get_builder() ``` @@ -40,7 +40,8 @@ One can start by defining and assigning the structure to the builder: ```python from ase.build import bulk -structure = StructureData(ase=bulk('Fe', 'bcc', 2.87, cubic=True)) + +structure = StructureData(ase=bulk("Fe", "bcc", 2.87, cubic=True)) builder.structure = structure ``` @@ -60,24 +61,28 @@ import requests import io # Download the potential from the repository and store it as a BytesIO object -_stream = io.BytesIO(requests.get('https://openkim.org/files/MO_546673549085_000/Fe_2.eam.fs').text.encode('ascii')) +_stream = io.BytesIO( + requests.get( + "https://openkim.org/files/MO_546673549085_000/Fe_2.eam.fs" + ).text.encode("ascii") +) # Set the metadata for the potential potential_parameters = { - 'species': ['Fe'], - 'atom_style': 'atomic', - 'pair_style': 'eam/fs', - 'units': 'metal', - 'extra_tags': { - 'title': 'EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000', - 'content_origin': 'NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html', - 'developer': ['Ronald E. Miller'], - 'publication_year': 2018, - } + "species": ["Fe"], + "atom_style": "atomic", + "pair_style": "eam/fs", + "units": "metal", + "extra_tags": { + "title": "EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000", + "content_origin": "NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html", + "developer": ["Ronald E. Miller"], + "publication_year": 2018, + }, } # Store the potential in an AiiDA node -potential = LammpsPotentialData.get_or_create(source=_stream,**potential_parameters) +potential = LammpsPotentialData.get_or_create(source=_stream, **potential_parameters) builder.potential = potential ``` @@ -95,41 +100,38 @@ Then one needs to define the parameters which control how the input file for the For a structural minimization the minimal set of parameters is the following: ```python - # Parameters to control the input file generation -parameters = Dict({ - "control": { - "units": "metal", - "timestep": 1e-5 - }, - "compute":{ - "pe/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], - "ke/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], - "stress/atom": [{"type": ["NULL"], "group": "all"}], - "pressure": [{"type": ["thermo_temp"], "group": "all"}], - }, - - "structure":{"atom_style": "atomic"}, - "thermo":{ - "printing_rate": 100, - "thermo_printing": { - "step": True, - "pe": True, - "ke": True, - "press": True, - "pxx": True, - "pyy": True, - "pzz": True, - } - }, - "minimize":{ - "style": "cg", - "energy_tolerance": 1e-4, - "force_tolerance": 1e-4, - "max_iterations": 1000, - "max_evaluations": 1000, - }, -}) +parameters = Dict( + { + "control": {"units": "metal", "timestep": 1e-5}, + "compute": { + "pe/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], + "ke/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], + "stress/atom": [{"type": ["NULL"], "group": "all"}], + "pressure": [{"type": ["thermo_temp"], "group": "all"}], + }, + "structure": {"atom_style": "atomic"}, + "thermo": { + "printing_rate": 100, + "thermo_printing": { + "step": True, + "pe": True, + "ke": True, + "press": True, + "pxx": True, + "pyy": True, + "pzz": True, + }, + }, + "minimize": { + "style": "cg", + "energy_tolerance": 1e-4, + "force_tolerance": 1e-4, + "max_iterations": 1000, + "max_evaluations": 1000, + }, + } +) builder.parameters = parameters ``` The parameters have several sections which control different behavior of the calculation: @@ -151,11 +153,11 @@ Lastly one needs to define the computational resources needed to perform the cal # Run the calculation on 1 CPU and kill it if it runs longer than 1800 seconds. # Set ``withmpi`` to ``False`` if ``pw.x`` was compiled without MPI support. builder.metadata.options = { - 'resources': { - 'num_machines': 1, + "resources": { + "num_machines": 1, }, - 'max_wallclock_seconds': 1800, - 'withmpi': False, + "max_wallclock_seconds": 1800, + "withmpi": False, } ``` @@ -209,5 +211,5 @@ The `time_dependent_computes` contains a series of numpy arrays each one represe The complete output that was written by {{ LAMMPS }} to stdout, can be retrieved as follows: ```python -results['retrieved'].base.repository.get_object_content('aiida_lammps.out') +results["retrieved"].base.repository.get_object_content("aiida_lammps.out") ``` diff --git a/src/aiida_lammps/data/potential.py b/src/aiida_lammps/data/potential.py index 61e3d218..dd85f7bb 100644 --- a/src/aiida_lammps/data/potential.py +++ b/src/aiida_lammps/data/potential.py @@ -68,7 +68,7 @@ def _validate_string_list(data: Union[str, list[str]]) -> list[str]: return data -def _validate_datetime(data: Union[str, int, float, datetime.datetime]) -> int: +def _validate_datetime(data: Union[str, float, datetime.datetime]) -> int: """ Validate and transform dates into integers diff --git a/src/aiida_lammps/data/trajectory.py b/src/aiida_lammps/data/trajectory.py index 7f585717..0d81e3a5 100644 --- a/src/aiida_lammps/data/trajectory.py +++ b/src/aiida_lammps/data/trajectory.py @@ -195,7 +195,7 @@ def aliases(self): def get_step_string(self, step_idx): """Return the content string, for a specific trajectory step.""" step_idx = list(range(self.number_steps))[step_idx] - zip_name = f'{self.base.attributes.get("zip_prefix")}{step_idx}' + zip_name = f"{self.base.attributes.get('zip_prefix')}{step_idx}" with ( self.base.repository.open( self.base.attributes.get("trajectory_filename"), @@ -235,7 +235,7 @@ def iter_step_strings(self, steps=None): ) as zip_file, ): for step_idx in steps: - zip_name = f'{self.base.attributes.get("zip_prefix")}{step_idx}' + zip_name = f"{self.base.attributes.get('zip_prefix')}{step_idx}" with zip_file.open(zip_name) as step_file: content = step_file.read() yield content diff --git a/src/aiida_lammps/parsers/inputfile.py b/src/aiida_lammps/parsers/inputfile.py index 58949a1d..35443a20 100644 --- a/src/aiida_lammps/parsers/inputfile.py +++ b/src/aiida_lammps/parsers/inputfile.py @@ -201,13 +201,13 @@ def write_control_block(parameters_control: dict[str, Any]) -> str: _time = default_timestep[parameters_control.get("units", "si")] control_block = generate_header("Start of the Control information") control_block += "clear\n" - control_block += f'units {parameters_control.get("units", "si")}\n' - control_block += f'newton {parameters_control.get("newton", "on")}\n' + control_block += f"units {parameters_control.get('units', 'si')}\n" + control_block += f"newton {parameters_control.get('newton', 'on')}\n" if "processors" in parameters_control: control_block += ( - f'processors {join_keywords(parameters_control["processors"])}\n' + f"processors {join_keywords(parameters_control['processors'])}\n" ) - control_block += f'timestep {parameters_control.get("timestep", _time)}\n' + control_block += f"timestep {parameters_control.get('timestep', _time)}\n" control_block += generate_header("End of the Control information") return control_block @@ -245,27 +245,27 @@ def write_potential_block( potential_block = generate_header("Start of Potential information") potential_block += f"pair_style {potential.pair_style}" potential_block += ( - f' {" ".join(parameters_potential.get("potential_style_options", [""]))}\n' + f" {' '.join(parameters_potential.get('potential_style_options', ['']))}\n" ) if default_potential[potential.pair_style].get("read_from_file"): - potential_block += f'pair_coeff * * {potential_file} {" ".join(kind_symbols)}\n' + potential_block += f"pair_coeff * * {potential_file} {' '.join(kind_symbols)}\n" if not default_potential[potential.pair_style].get("read_from_file"): data = [ line for line in potential.get_content().split("\n") if not line.startswith("#") and line ] - potential_block += f'pair_coeff * * {" ".join(data)}\n' + potential_block += f"pair_coeff * * {' '.join(data)}\n" if "neighbor" in parameters_potential: potential_block += ( - f'neighbor {join_keywords(parameters_potential["neighbor"])}\n' + f"neighbor {join_keywords(parameters_potential['neighbor'])}\n" ) if "neighbor_modify" in parameters_potential: potential_block += "neigh_modify" potential_block += ( - f' {join_keywords(parameters_potential["neighbor_modify"])}\n' + f" {join_keywords(parameters_potential['neighbor_modify'])}\n" ) potential_block += generate_header("End of Potential information") return potential_block @@ -304,7 +304,7 @@ def write_structure_block( kind_name_id_map[site.kind_name] = len(kind_name_id_map) + 1 structure_block = generate_header("Start of the Structure information") - structure_block += f'box tilt {parameters_structure.get("box_tilt", "small")}\n' + structure_block += f"box tilt {parameters_structure.get('box_tilt', 'small')}\n" # Set the dimensions of the structure if "dimension" in parameters_structure: @@ -319,12 +319,12 @@ def write_structure_block( structure_block += f"boundary {' '.join(['p' if entry else 'f' for entry in structure.pbc])} \n" # Set the atom style for the structure - structure_block += f'atom_style {parameters_structure["atom_style"]}\n' + structure_block += f"atom_style {parameters_structure['atom_style']}\n" # Set the atom modify for the structure if "atom_modify" in parameters_structure: structure_block += "atom_modify" - structure_block += f' {parameters_structure["atom_modify"]}\n' + structure_block += f" {parameters_structure['atom_modify']}\n" # Write the command to read the structure from a file structure_block += f"read_data {structure_filename}\n" # Set the groups which will be used for the calculations @@ -338,7 +338,7 @@ def write_structure_block( raise ValueError("atom type not defined") # Set the current group structure_block += ( - f'group {_group["name"]} {join_keywords(_group["args"])}\n' + f"group {_group['name']} {join_keywords(_group['args'])}\n" ) # Store the name of the group for later usage group_names.append(_group["name"]) @@ -362,11 +362,11 @@ def write_minimize_block(parameters_minimize: dict[str, Union[str, float, int]]) """ minimize_block = generate_header("Start of the Minimization information") - minimize_block += f'min_style {parameters_minimize.get("style", "cg")}\n' - minimize_block += f'minimize {parameters_minimize.get("energy_tolerance", 1e-4)}' - minimize_block += f' {parameters_minimize.get("force_tolerance", 1e-4)}' - minimize_block += f' {parameters_minimize.get("max_iterations", 1000)}' - minimize_block += f' {parameters_minimize.get("max_evaluations", 1000)}\n' + minimize_block += f"min_style {parameters_minimize.get('style', 'cg')}\n" + minimize_block += f"minimize {parameters_minimize.get('energy_tolerance', 1e-4)}" + minimize_block += f" {parameters_minimize.get('force_tolerance', 1e-4)}" + minimize_block += f" {parameters_minimize.get('max_iterations', 1000)}" + minimize_block += f" {parameters_minimize.get('max_evaluations', 1000)}\n" minimize_block += generate_header("End of the Minimization information") return minimize_block @@ -403,18 +403,18 @@ def write_md_block(parameters_md: dict[str, Any]) -> str: md_block = generate_header("Start of the MD information") _key = parameters_md["integration"].get("style", "nve") - md_block += f'fix {generate_id_tag(_key, "all")} all {_key}{integration_options}\n' + md_block += f"fix {generate_id_tag(_key, 'all')} all {_key}{integration_options}\n" if "velocity" in parameters_md: md_block += ( - f'{generate_velocity_string(parameters_velocity=parameters_md["velocity"])}' + f"{generate_velocity_string(parameters_velocity=parameters_md['velocity'])}" ) md_block += f"reset_timestep {time_step}\n" if parameters_md.get("run_style", "verlet") == "respa": - md_block += f'run_style {parameters_md.get("run_style", "verlet")} ' - md_block += f'{join_keywords(parameters_md["respa_options"])}\n' + md_block += f"run_style {parameters_md.get('run_style', 'verlet')} " + md_block += f"{join_keywords(parameters_md['respa_options'])}\n" else: - md_block += f'run_style {parameters_md.get("run_style", "verlet")}\n' - md_block += f'run {parameters_md.get("max_number_steps", 100)}\n' + md_block += f"run_style {parameters_md.get('run_style', 'verlet')}\n" + md_block += f"run {parameters_md.get('max_number_steps', 100)}\n" md_block += generate_header("End of the MD information") return md_block @@ -476,29 +476,29 @@ def generate_velocity_string(parameters_velocity: list[dict[str, Any]]) -> str: for entry in parameters_velocity: _options = generate_velocity_options(entry) if "create" in entry: - options += f'velocity {entry.get("group", "all")} create' - options += f' {entry["create"].get("temp")}' + options += f"velocity {entry.get('group', 'all')} create" + options += f" {entry['create'].get('temp')}" options += ( - f' {entry["create"].get("seed", np.random.randint(10000))} {_options}\n' + f" {entry['create'].get('seed', np.random.randint(10000))} {_options}\n" ) if "set" in entry: - options += f'velocity {entry.get("group", "all")} set' - options += f' {entry["set"].get("vx", "NULL")}' - options += f' {entry["set"].get("vy", "NULL")}' - options += f' {entry["set"].get("vz", "NULL")} {_options}\n' + options += f"velocity {entry.get('group', 'all')} set" + options += f" {entry['set'].get('vx', 'NULL')}" + options += f" {entry['set'].get('vy', 'NULL')}" + options += f" {entry['set'].get('vz', 'NULL')} {_options}\n" if "scale" in entry: - options += f'velocity {entry.get("group", "all")} scale' - options += f' {entry["scale"]} {_options}\n' + options += f"velocity {entry.get('group', 'all')} scale" + options += f" {entry['scale']} {_options}\n" if "ramp" in entry: - options += f'velocity {entry.get("group", "all")} ramp' - options += f' {entry["ramp"].get("vdim")} {entry["ramp"].get("vlo")}' - options += f' {entry["ramp"].get("vhi")} {entry["ramp"].get("dim")}' + options += f"velocity {entry.get('group', 'all')} ramp" + options += f" {entry['ramp'].get('vdim')} {entry['ramp'].get('vlo')}" + options += f" {entry['ramp'].get('vhi')} {entry['ramp'].get('dim')}" options += ( - f' {entry["ramp"].get("clo")} {entry["ramp"].get("chi")} {_options}\n' + f" {entry['ramp'].get('clo')} {entry['ramp'].get('chi')} {_options}\n" ) if "zero" in entry: - options += f'velocity {entry.get("group", "all")} zero' - options += f' {entry["zero"]} {_options}\n' + options += f"velocity {entry.get('group', 'all')} zero" + options += f" {entry['zero']} {_options}\n" return options @@ -618,7 +618,7 @@ def generate_integration_options( _value = integration_parameters.get(_option) if _value: _value = [str(val) for val in _value] - options += f' {_option} {" ".join(_value) if isinstance(_value, list) else _value} ' + options += f" {_option} {' '.join(_value) if isinstance(_value, list) else _value} " # Set the options that depend on the pressure if style in pressure_dependent: for _option in pressure_options: @@ -626,7 +626,7 @@ def generate_integration_options( _value = integration_parameters.get(_option) if _value: _value = [str(val) for val in _value] - options += f' {_option} {" ".join(_value) if isinstance(_value, list) else _value} ' + options += f" {_option} {' '.join(_value) if isinstance(_value, list) else _value} " # Set the options that depend on the 'uef' parameters if style in uef_dependent: for _option in uef_options: @@ -634,15 +634,15 @@ def generate_integration_options( _value = integration_parameters.get(_option) if _value: _value = [str(val) for val in _value] - options += f' {_option} {" ".join(_value) if isinstance(_value, list) else _value} ' + options += f" {_option} {' '.join(_value) if isinstance(_value, list) else _value} " # Set the options that depend on the 'nve/limit' parameters if style in ["nve/limit"]: - options += f' {integration_parameters.get("xmax", 0.1)} ' + options += f" {integration_parameters.get('xmax', 0.1)} " # Set the options that depend on the 'langevin' parameters if style in ["nve/dotc/langevin"]: - options += f' {integration_parameters.get("temp")}' - options += f' {integration_parameters.get("seed")}' - options += f' angmom {integration_parameters.get("angmom")}' + options += f" {integration_parameters.get('temp')}" + options += f" {integration_parameters.get('seed')}" + options += f" angmom {integration_parameters.get('angmom')}" return options @@ -685,7 +685,7 @@ def write_fix_block( f'group name "{_group}" is not the defined groups {[*group_names, "all"]}' ) fix_block += f"fix {generate_id_tag(key, _group)} {_group} {key} " - fix_block += f'{join_keywords(entry["type"])}\n' + fix_block += f"{join_keywords(entry['type'])}\n" fix_block += generate_header("End of the Fix information") return fix_block @@ -721,7 +721,7 @@ def write_compute_block( if _group not in [*group_names, "all"]: raise ValueError(f'group name "{_group}" is not the defined groups') compute_block += f"compute {generate_id_tag(key, _group)} {_group} {key} " - compute_block += f'{join_keywords(entry["type"])}\n' + compute_block += f"{join_keywords(entry['type'])}\n" compute_block += generate_header("End of the Compute information") return compute_block @@ -780,12 +780,12 @@ def write_dump_block( if atom_style == "charge": num_double += 1 dump_block = generate_header("Start of the Dump information") - dump_block += f'dump aiida all custom {parameters_dump.get("dump_rate", 10)} ' + dump_block += f"dump aiida all custom {parameters_dump.get('dump_rate', 10)} " dump_block += f"{trajectory_filename} id type element x y z " - dump_block += f'{"q " if atom_style=="charge" else ""}' - dump_block += f'{" ".join(computes_list)}\n' + dump_block += f"{'q ' if atom_style == 'charge' else ''}" + dump_block += f"{' '.join(computes_list)}\n" dump_block += "dump_modify aiida sort id\n" - dump_block += f'dump_modify aiida element {" ".join(kind_symbols)}\n' + dump_block += f"dump_modify aiida element {' '.join(kind_symbols)}\n" dump_block += "dump_modify aiida format int ' %d ' \n" dump_block += "dump_modify aiida format float ' %16.10e ' \n" dump_block += generate_header("End of the Dump information") @@ -855,9 +855,9 @@ def write_thermo_block( thermo_block = generate_header("Start of the Thermo information") thermo_block += ( - f'thermo_style custom {" ".join(fixed_thermo)} {" ".join(computes_list)}\n' + f"thermo_style custom {' '.join(fixed_thermo)} {' '.join(computes_list)}\n" ) - thermo_block += f'thermo {parameters_thermo.get("printing_rate", 1000)}\n' + thermo_block += f"thermo {parameters_thermo.get('printing_rate', 1000)}\n" thermo_block += generate_header("End of the Thermo information") printing_variables = fixed_thermo + list( @@ -898,7 +898,7 @@ def write_restart_block( "Start of the intermediate write restart information" ) restart_block["intermediate"] += ( - f"restart {parameters_restart.get('num_steps', int(max_number_steps/10))} {restart_filename}\n" + f"restart {parameters_restart.get('num_steps', int(max_number_steps / 10))} {restart_filename}\n" ) restart_block["intermediate"] += generate_header( "End of the intermediate write restart information" @@ -1000,7 +1000,7 @@ def generate_id_tag(name: str, group: str) -> str: :rtype: str """ - return f"{name.replace('/','_')}_{group}_aiida" + return f"{name.replace('/', '_')}_{group}_aiida" def join_keywords(value: list[Any]) -> str: diff --git a/src/aiida_lammps/parsers/parse_raw/lammps_output.py b/src/aiida_lammps/parsers/parse_raw/lammps_output.py index d58463d5..8b95d1d7 100644 --- a/src/aiida_lammps/parsers/parse_raw/lammps_output.py +++ b/src/aiida_lammps/parsers/parse_raw/lammps_output.py @@ -3,14 +3,14 @@ # pylint: disable=fixme import ast import re -from typing import Optional, Union +from typing import Optional import numpy as np def parse_outputfile( filename: Optional[str] = None, file_contents: Optional[str] = None -) -> Union[dict, dict]: +) -> dict: """ Parse the lammps output file file, this is the redirected screen output. diff --git a/src/aiida_lammps/parsers/utils.py b/src/aiida_lammps/parsers/utils.py index b9ca0d9b..0b7fcfea 100644 --- a/src/aiida_lammps/parsers/utils.py +++ b/src/aiida_lammps/parsers/utils.py @@ -7,7 +7,7 @@ import numpy as np -def _transform_cell(cell) -> Union[np.array, np.array]: +def _transform_cell(cell) -> np.array: """Transform the cell to an orientation, compatible with LAMMPS LAMMPS requires the simulation cell to be in the format of a diff --git a/tests/test_calculations.py b/tests/test_calculations.py index dbb25558..14bf97e7 100644 --- a/tests/test_calculations.py +++ b/tests/test_calculations.py @@ -147,9 +147,9 @@ def test_lammps_base( ) ) - assert ( - "time_dependent_computes" in results - ), 'the "time_dependent_computes" node is not present' + assert "time_dependent_computes" in results, ( + 'the "time_dependent_computes" node is not present' + ) _msg = "No time dependent computes obtained even when expected" assert len(results["time_dependent_computes"].get_arraynames()) > 0, _msg @@ -232,9 +232,9 @@ def test_lammps_restart_generation( ), _msg else: # Check that if the file was not asked to be stored that it is not stored - assert ( - "restartfile" not in results - ), "The restartfile is stored even when it was not requested" + assert "restartfile" not in results, ( + "The restartfile is stored even when it was not requested" + ) if restart_parameters.restart.get("print_final", False): _msg = "The restartfile is in the retrieved folder even when it was not requested" assert ( diff --git a/tests/test_potential_data.py b/tests/test_potential_data.py index 738c5f10..eded8873 100644 --- a/tests/test_potential_data.py +++ b/tests/test_potential_data.py @@ -42,9 +42,9 @@ def test_lammps_potentials_init( for _attribute in _attributes: _msg = f'attribute "{_attribute}" does not match between reference and current value' - assert reference_values[_attribute] == node.base.attributes.get( - _attribute - ), _msg + assert reference_values[_attribute] == node.base.attributes.get(_attribute), ( + _msg + ) @pytest.mark.parametrize( diff --git a/tests/test_workflows.py b/tests/test_workflows.py index 61bb53a1..401667fa 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -422,9 +422,9 @@ def test_relax_workchain( ) ) - assert ( - "time_dependent_computes" in results - ), 'the "time_dependent_computes" node is not present' + assert "time_dependent_computes" in results, ( + 'the "time_dependent_computes" node is not present' + ) _msg = "No time dependent computes obtained even when expected" assert len(results["time_dependent_computes"].get_arraynames()) > 0, _msg diff --git a/tests/utils.py b/tests/utils.py index b3067a36..24b84a2f 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -82,7 +82,7 @@ def get_or_create_local_computer(work_directory, name="localhost"): computer = orm.Computer( label=name, hostname="localhost", - description=("localhost computer, " "set up by aiida_lammps tests"), + description=("localhost computer, set up by aiida_lammps tests"), transport_type="core.local", scheduler_type="core.direct", workdir=os.path.abspath(work_directory),