diff --git a/.gitignore b/.gitignore
index 558c4af..99a81e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -157,3 +157,6 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
+
+# ASIMTools results
+examples/*/*results*/
diff --git a/Building_docs.md b/Building_docs.md
new file mode 100644
index 0000000..36878ea
--- /dev/null
+++ b/Building_docs.md
@@ -0,0 +1,18 @@
+To build the documentation you will need the following packages:
+
+- sphinx
+- sphinx-apidoc
+- autodoc
+
+### Steps
+1. First, generate the autdoc sources for the API reference from the root using
+
+ sphinx-apidoc -f -o docs asimtools
+
+2. Then go into the docs directory and run
+
+ make html
+
+This will generate the docs in the `_build` directory
+
+
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index cd24d2d..f39ccba 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -5,10 +5,10 @@ When contributing to this repository, please first discuss the change you wish t
Please note we have a code of conduct, please follow it in all your interactions with the project.
There are two main ways to contribute. One is to make changes to the existing
-codes and scripts. In this case, please make sure your change passes tests or
-submit a test accordinly. The second way to contribute is to add a new script
-to the core set of scripts. Reviewers will work with you to make sure your new
-script follows best practice including using utils, syntax highlighting, docs
+codes and asimmodules. In this case, please make sure your change passes tests or
+submit a test accordinly. The second way to contribute is to add a new asimmodule
+to the core set of asimmodules. Reviewers will work with you to make sure your new
+asimmodule follows best practice including using utils, syntax highlighting, docs
and tests.
## Pull Request Process
diff --git a/README.md b/README.md
index f6f8006..261c627 100644
--- a/README.md
+++ b/README.md
@@ -1,166 +1,118 @@
+
+
+
+
+
+[Documentation](https://battmodels.github.io/asimtools/) | [GitHub](https://github.com/BattModels/asimtools)
+
# Atomic SIMulation Tools
This package is a lightweight workflow and simulation manager for reproducible
atomistic simulations that can be transferred across environments, calculators
-and structures. By using in-built or user-defined scripts and utilities, users
-can run/build their own simulation recipes and automagically scale them on
-slurm based clusters. The core idea is to separate the dependence of the
-atomistic potential/calculator and the simulations steps thereby allowing the
-same simulation to be run with multiple calculators and the same calculator to
-be used for multiple simulations. Input and output files must follow a strict
-format so that consistent analysis pipelines can be used across users
-
-** ASIMTools is going through some breaking changes for version 0.1.0, please use with caution **
-
-## Documentation
-Documentation is under construction [here](https://battmodels.github.io/asimtools/)
+and structures. By using in-built or user-defined asimmodules and utilities,
+users can run/build their own simulation recipes and automagically scale them
+locally or on slurm based clusters. The core idea is to separate the dependence
+of the atomistic potential/calculator and the simulations steps thereby
+allowing the same simulation to be run with multiple calculators and the same
+calculator to be used for multiple simulations without altering simulation
+code. Input and output files must follow a strict format so that consistent
+analysis pipelines can be used across users
## Developer philosophy
-The goal of asimtools is to push all the complexity of workflow
-management, best-practices, file management etc. into the backend such that the
-everyday user only has to handle input files for existing workflows and script
-files for workflows they want to implement. The following are the guiding
-principles for how asimtools should work:
-
-- Scripts should resemble boilerplate ASE code as much as possible.
-- Scripts should not explicitly depend on a calculator
-- Scripts should not explicitly depend on the context in which they run
-- It should be easy to debug individual scripts/parts in large workflows. In
- addition, it should always be possible to debug/resubmit jobs without using
- asimtools.
-- input file structure and format should be standard across all scripts. In
+The goal of asimtools is to push all the complexity of workflow management,
+best-practices, file management etc. into the backend such that the everyday
+user only has to handle input files for existing workflows and asimmodule files
+for workflows they want to implement. The following are the guiding principles
+for how asimtools should work:
+
+- Asimmodules should resemble boilerplate ASE code as much as possible.
+- Asimmodules should not explicitly depend on a calculator
+- Asimmodules should not explicitly depend on the context/environment in which
+ they run
+- It should be easy to debug individual asimmodules/parts in large workflows.
+ In addition, it should always be possible to debug/resubmit jobs without
+ using asimtools.
+- Input file structure and format should be standard across all asimmodules. In
addition all input parameters should match how they would like without
- asimtools i.e. do not provide an API! This means extensive use of importlib.
-- output file structure should be predictable across all scripts
+ asimtools i.e. do not provide an API!
- Job progress tracking must be incorporated
- Best practices should be built-in e.g. if multiple jobs of the same slurm
- context are submitted simulataneously, it must be a job array
+ context are submitted simulataneously, it must be a job array.
## Philosophy on User Experience
-The philosophy is to build "simulations" using building blocks of scripts.
-These scripts can be as complicated/efficient as you make them using any
-external packages you want and can be optimized with time but can still be run
-within the framework. This allows a test friendly way to transition from say a
-tutorial on the ASE/pymatgen website to an asimtools script. So while
-complicated wrappers are discouraged, they would still work as long as the
-script works. The benefit out of the box is that you can make your script
-independent of calculator or input structures and submit them easily.
+The philosophy is to build "simulations" using building blocks of asimmodules.
+Asimmodules are nothing but Python functions that return a dictionary, anything
+can be done in the function code. These asimmodules can be as
+complicated/efficient as you make them using any external packages you want and
+can be optimized with time but can still be run within the framework. This
+allows a test friendly way to transition from say a tutorial on the
+ASE/pymatgen website to an asimtools asimmodule. So while complicated wrappers
+are discouraged, they would still work as long as the asimmodule works. The
+benefit out of the box is that you can make your asimmodule independent of
+calculator or input structures and submit them easily.
## Getting Started
-These instructions will give you a copy of the project up and running on
-your local machine for development and testing purposes.
+These instructions will give you a copy of the project up and running.
### Installing
You can install asimtools in a new conda environment using:
```
-conda create -n asimtools python=3.9
+conda create -n asimtools python=3.7
conda activate asimtools
conda install ase -c conda-forge
git clone https://github.com/BattModels/asimtools.git
cd asimtools
-pip install -e .
+pip install .
```
-This installs the base package in developer mode so that you do not have to
-reinstall if you make changes to the core package.
-
Individual calculators may need external packages for loading those
-calculators. Similarly some scripts e.g. `lammps.py` might also need external packages to be used. It is up to the user to make sure those are installed.
+calculators. For example if you want to use Quantum Espresso or CASTEP, you
+will have to install them. Similarly some asimmodules e.g. `lammps.py` might
+also need external packages to be used. It is up to the user to make sure those
+are installed.
You will also need to setup some environment variables, these variables point
-to a `env_input.yaml` and `calc_input.yaml` with your favorite configs since
-these are commonly shared among simulations. You can also directly specify them
-when running `asim-execute` (See `asim-execute -h`).
-Examples of these files can be found in the examples.
+to global `env_input.yaml` and `calc_input.yaml` files with your favorite
+configurations since these are commonly shared among simulations. You can also
+directly specify them when running `asim-execute` (See `asim-execute -h`). You
+can also provide a directory for ASIMTools to search for your custom
+asimmodules. Examples of these files can be found in the examples.
Add the following to your `.bashrc`
```
export ASIMTOOLS_ENV_INPUT=/path/to/my/global/env_input.yaml
export ASIMTOOLS_CALC_INPUT=/path/to/my/global/calc_input.yaml
-export ASIMTOOLS_SCRIPT_DIR=/path/to/my/script/dir
+export ASIMTOOLS_ASIMMODULE_DIR=/path/to/my/asimmodule/dir
```
-
-
-
-
-
## Running the tests
-To run all tests from the tests directory, call:
+To run tests for the workflow tools, from the tests directory, call:
pytest
To run the test suite on a component `component.py` , call:
pytest test_component.py
-
-
+ source run_all.sh
+
+Or you can run a test for each individual example in its directory using:
+
+ source run.sh
+If no errors are reported, the tests have passed. These tests simply test the
+functionality of the code, not the validity of the simulations!
+
+To run tests for the provided asimmodules using slurm, you can similarly run
+the bash scripts ending with `_slurm.sh`.
+
## Contributing
Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code
diff --git a/asimtools/scripts/__init__.py b/asimtools/asimmodules/__init__.py
similarity index 100%
rename from asimtools/scripts/__init__.py
rename to asimtools/asimmodules/__init__.py
diff --git a/asimtools/scripts/eos/__init__.py b/asimtools/asimmodules/benchmarking/__init__.py
similarity index 100%
rename from asimtools/scripts/eos/__init__.py
rename to asimtools/asimmodules/benchmarking/__init__.py
diff --git a/asimtools/scripts/parity.py b/asimtools/asimmodules/benchmarking/parity.py
similarity index 99%
rename from asimtools/scripts/parity.py
rename to asimtools/asimmodules/benchmarking/parity.py
index 6b2c26b..9ded857 100644
--- a/asimtools/scripts/parity.py
+++ b/asimtools/asimmodules/benchmarking/parity.py
@@ -2,7 +2,7 @@
'''
Generates a parity plot and collects evaluation statistics comparing energy
and/or forces and/or stress to existing values in the provided dataset. This
-script can work in parallel based on the number of cores specified.
+asimmodule can work in parallel based on the number of cores specified.
Author: mkphuthi@github.com
diff --git a/asimtools/scripts/do_nothing.py b/asimtools/asimmodules/do_nothing.py
similarity index 84%
rename from asimtools/scripts/do_nothing.py
rename to asimtools/asimmodules/do_nothing.py
index 41a0567..843b8be 100755
--- a/asimtools/scripts/do_nothing.py
+++ b/asimtools/asimmodules/do_nothing.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
'''
-Script for unit tests and debugging, does nothing for specified duration
+asimmodule for unit tests and debugging, does nothing for specified duration
'''
from time import sleep
from typing import Dict, Optional
diff --git a/examples/ase_eos/env_input.yaml b/asimtools/asimmodules/elastic_constants/__init__.py
similarity index 100%
rename from examples/ase_eos/env_input.yaml
rename to asimtools/asimmodules/elastic_constants/__init__.py
diff --git a/asimtools/scripts/elastic_constants/cubic_energy_expansion.py b/asimtools/asimmodules/elastic_constants/cubic_energy_expansion.py
similarity index 85%
rename from asimtools/scripts/elastic_constants/cubic_energy_expansion.py
rename to asimtools/asimmodules/elastic_constants/cubic_energy_expansion.py
index 350cf5a..a7ea189 100755
--- a/asimtools/scripts/elastic_constants/cubic_energy_expansion.py
+++ b/asimtools/asimmodules/elastic_constants/cubic_energy_expansion.py
@@ -1,9 +1,9 @@
#!/usr/bin/env python
'''
-Describe the script briefly here. If this is a script that runs multiple steps,
+Describe the asimmodule briefly here. If this is a asimmodule that runs multiple steps,
describe it here using reStructuredText to generate autodocs
-Cite the papers where the method/script was first introduced here as well
+Cite the papers where the method/asimmodule was first introduced here as well
Author: mkphuthi@github.com
'''
@@ -17,10 +17,9 @@
from asimtools.utils import (
get_atoms,
)
-from asimtools.scripts.ase_cubic_eos_optimization import (
+from asimtools.asimmodules.geometry_optimization.ase_cubic_eos_optimization import (
ase_cubic_eos_optimization as eos
)
-from asimtools.scripts.cell_relax import cell_relax
def get_strained_atoms(atoms, strain: str, delta: float):
"""Returns a unit cell with atoms strained according to some useful types
@@ -84,7 +83,7 @@ def cubic_energy_expansion(
calc_id: str,
image: Dict,
deltas: Sequence[float] = (-0.01,-0.0075,-0.005,0.00,0.005,0.0075,0.01),
- ase_eos_args: Optional[Dict] = None,
+ ase_cubic_eos_args: Optional[Dict] = None,
) -> Dict:
'''
Calculates B, C11, C12 and C44 elastic constants of a structure with cubic
@@ -98,8 +97,8 @@ def cubic_energy_expansion(
# Start by getting the Bulk modulus and optimized cell from the EOS
logging.info('Calculating EOS')
eos_kwargs = {'image': image, 'calc_id': calc_id}
- if ase_eos_args is not None:
- eos_kwargs.update(ase_eos_args)
+ if ase_cubic_eos_args is not None:
+ eos_kwargs.update(ase_cubic_eos_args)
eos_results = eos(**eos_kwargs)
B = eos_results['B']
atoms = get_atoms(image_file='eos_image_output.xyz')
@@ -135,7 +134,7 @@ def cubic_energy_expansion(
c11min12_atoms.write(f's{delta:.4f}_c11min12.xyz')
def f(x, a, b, c):
- ''' Fitting function for Free energy expansion to second order'''
+ ''' Fitting function for free energy expansion to second order'''
return a*x**2 + b*x + c
logging.info('Fitting for C44')
@@ -152,13 +151,15 @@ def f(x, a, b, c):
anis = 2 * C44 / (C11 - C12)
results = {
- 'B': float(B / GPa),
- 'C11minC12': float(C11minC12 / GPa),
- 'C11': float(C11 / GPa),
- 'C12': float(C12 / GPa),
- 'C44': float(C44 / GPa),
- 'Anisotropy': float(anis),
- 'vol': float(atoms.get_volume()),
+ 'constants': {
+ 'B': float(B / GPa),
+ 'C11minC12': float(C11minC12 / GPa),
+ 'C11': float(C11 / GPa),
+ 'C12': float(C12 / GPa),
+ 'C44': float(C44 / GPa),
+ 'Anisotropy': float(anis),
+ 'vol': float(atoms.get_volume()),
+ },
}
return results # Always return a dictionary! Use {} if necessary
diff --git a/examples/eos/results/step-0/id-0_x0.95/stdout.txt b/asimtools/asimmodules/eos/__init__.py
similarity index 100%
rename from examples/eos/results/step-0/id-0_x0.95/stdout.txt
rename to asimtools/asimmodules/eos/__init__.py
diff --git a/asimtools/scripts/eos/postprocess.py b/asimtools/asimmodules/eos/postprocess.py
similarity index 100%
rename from asimtools/scripts/eos/postprocess.py
rename to asimtools/asimmodules/eos/postprocess.py
diff --git a/examples/eos/results/step-0/id-1_x0.97/stdout.txt b/asimtools/asimmodules/geometry_optimization/__init__.py
similarity index 100%
rename from examples/eos/results/step-0/id-1_x0.97/stdout.txt
rename to asimtools/asimmodules/geometry_optimization/__init__.py
diff --git a/asimtools/scripts/ase_cubic_eos_optimization.py b/asimtools/asimmodules/geometry_optimization/ase_cubic_eos_optimization.py
similarity index 64%
rename from asimtools/scripts/ase_cubic_eos_optimization.py
rename to asimtools/asimmodules/geometry_optimization/ase_cubic_eos_optimization.py
index ec3eaa4..5bf5d07 100644
--- a/asimtools/scripts/ase_cubic_eos_optimization.py
+++ b/asimtools/asimmodules/geometry_optimization/ase_cubic_eos_optimization.py
@@ -23,16 +23,21 @@ def ase_cubic_eos_optimization(
eps: Optional[float] = 0.04,
plot: Optional[bool] = True,
) -> Dict:
- """Calculate the equation of state, fit it and extract the equilibrium
- volume, energy and bulk modulus
+ """Generate the energy-volume equation of state (energy calculations not parallelized)
- :param image: image to use
+ :param image: Image input
:type image: Dict
- :param calc_id: calculator id
+ :param calc_id: calc_id
:type calc_id: str
- :param db_file: ASE database in which to store results
- :type db_file: bulk.db
- :return: results including equilibrium volume, energy and bulk modulus
+ :param npoints: Number of energy points to calculate, must be >5, defaults to 5
+ :type npoints: Optional[int], optional
+ :param eos_string: eos_string as specified for :func:`ase.eos.calculate_eos`, defaults to 'sj'
+ :type eos_string: Optional[str], optional
+ :param eps: eps as sepecified for, defaults to 0.04
+ :type eps: Optional[float], optional
+ :param plot: Whether to plot eos or not, defaults to True
+ :type plot: Optional[bool], optional
+ :return: Equilibrium energy, volume, bulk modulus and factor by which to scale lattice parameter to get equilibrium structure
:rtype: Dict
"""
calc = load_calc(calc_id)
@@ -44,15 +49,17 @@ def ase_cubic_eos_optimization(
eos.eos_string = eos_string
v0, e0, B = eos.fit() # find minimum
logging.info('Successfully fit EOS')
- # Do one more calculation at the minimum and write to database:
+ # Do one more calculation at the minimum and write to disk
new_cell = atoms.cell.copy()
- new_cell *= (v0 / atoms.get_volume())**(1 / 3)
+ x = (v0 / atoms.get_volume())**(1 / 3) # scale cell by this much
+ new_cell *= x
atoms.set_cell(new_cell, scale_atoms=True)
atoms.get_potential_energy()
atoms.info['B'] = B
atoms.info['v0'] = v0
+ atoms.info['scale'] = x
atoms.write('eos_image_output.xyz')
-
+
if plot:
eos.plot()
plt.savefig('eos.png')
@@ -67,7 +74,8 @@ def ase_cubic_eos_optimization(
for struct in traj:
eos_dict['energies'].append(struct.get_potential_energy())
eos_dict['volumes'].append(struct.get_volume())
- eos_dict['volume_scale_factors'].append(struct.get_volume() / v_init)
+ v_factor = struct.get_volume() / v_init
+ eos_dict['volume_scale_factors'].append(v_factor)
eos_df = pd.DataFrame(eos_dict)
eos_df.to_csv('eos.csv')
diff --git a/asimtools/scripts/atom_relax.py b/asimtools/asimmodules/geometry_optimization/atom_relax.py
similarity index 99%
rename from asimtools/scripts/atom_relax.py
rename to asimtools/asimmodules/geometry_optimization/atom_relax.py
index 17573b0..7620964 100755
--- a/asimtools/scripts/atom_relax.py
+++ b/asimtools/asimmodules/geometry_optimization/atom_relax.py
@@ -49,7 +49,7 @@ def atom_relax(
dyn = getattr(ase.optimize, optimizer)(atoms)
traj = Trajectory(
traj_file,
- 'w',
+ 'a',
atoms,
properties=properties
)
diff --git a/asimtools/scripts/cell_relax.py b/asimtools/asimmodules/geometry_optimization/cell_relax.py
similarity index 93%
rename from asimtools/scripts/cell_relax.py
rename to asimtools/asimmodules/geometry_optimization/cell_relax.py
index 93978c7..892f40a 100755
--- a/asimtools/scripts/cell_relax.py
+++ b/asimtools/asimmodules/geometry_optimization/cell_relax.py
@@ -50,12 +50,12 @@ def cell_relax(
else:
prefix = ''
- traj_file = join_names([prefix, 'cell_relax.traj'])
+ traj_file = join_names([prefix, 'cell_relax.traj'])[:-2] # Don't include __
sf = StrainFilter(atoms, mask=mask)
dyn = getattr(ase.optimize, optimizer)(sf)
traj = Trajectory(
traj_file,
- 'w',
+ 'a',
atoms,
properties=['energy', 'forces', 'stress'],
)
@@ -66,7 +66,7 @@ def cell_relax(
print('Failed to optimize atoms')
raise
- image_file = join_names([prefix, 'image_output.xyz'])
+ image_file = join_names([prefix, 'image_output.xyz'])[:-2]
atoms.write(image_file, format='extxyz')
energy = float(atoms.get_potential_energy())
diff --git a/asimtools/scripts/optimize_geometry.py b/asimtools/asimmodules/geometry_optimization/optimize.py
similarity index 94%
rename from asimtools/scripts/optimize_geometry.py
rename to asimtools/asimmodules/geometry_optimization/optimize.py
index eb0f4fd..e1a4492 100755
--- a/asimtools/scripts/optimize_geometry.py
+++ b/asimtools/asimmodules/geometry_optimization/optimize.py
@@ -12,7 +12,7 @@
from asimtools.calculators import load_calc
from asimtools.utils import get_atoms
-def optimize_geometry(
+def optimize(
calc_id: str,
image: Dict,
optimizer: str = 'BFGS',
@@ -47,10 +47,10 @@ def optimize_geometry(
ecf = ExpCellFilter(atoms, **expcellfilter_args)
dyn = getattr(ase.optimize, optimizer)(ecf)
- traj_file = 'cell_relax.traj'
+ traj_file = 'optimize.traj'
traj = Trajectory(
traj_file,
- 'w',
+ 'a', # If there are multiple relaxations, we keep all trajectories
atoms,
properties=['energy', 'forces', 'stress'],
)
diff --git a/asimtools/scripts/symmetric_cell_relax.py b/asimtools/asimmodules/geometry_optimization/symmetric_cell_relax.py
similarity index 99%
rename from asimtools/scripts/symmetric_cell_relax.py
rename to asimtools/asimmodules/geometry_optimization/symmetric_cell_relax.py
index c7e0caf..d647927 100755
--- a/asimtools/scripts/symmetric_cell_relax.py
+++ b/asimtools/asimmodules/geometry_optimization/symmetric_cell_relax.py
@@ -56,7 +56,7 @@ def symmetric_cell_relax(
traj_file = 'cell_relax.traj'
traj = Trajectory(
traj_file,
- 'w',
+ 'a',
atoms,
properties=['energy', 'forces', 'stress'],
)
diff --git a/examples/eos/results/step-0/id-2_x1.00/stdout.txt b/asimtools/asimmodules/lammps/__init__.py
similarity index 100%
rename from examples/eos/results/step-0/id-2_x1.00/stdout.txt
rename to asimtools/asimmodules/lammps/__init__.py
diff --git a/asimtools/scripts/lammps.py b/asimtools/asimmodules/lammps/lammps.py
similarity index 95%
rename from asimtools/scripts/lammps.py
rename to asimtools/asimmodules/lammps/lammps.py
index 7246a07..b9446b0 100755
--- a/asimtools/scripts/lammps.py
+++ b/asimtools/asimmodules/lammps/lammps.py
@@ -28,7 +28,7 @@ def lammps(
if variables is None:
variables = {}
- # Make sure the provided script follows standard for reading
+ # Make sure the provided asimmodule follows standard for reading
# in arbitrary image provided by asimtools
if image is not None:
atoms = get_atoms(**image)
@@ -63,7 +63,7 @@ def lammps(
assert 'read_data ' in lmp_txt, \
'Make sure "read_data image_input.lmpdat" command is used \
(with correct atom style) appropriately in lammps input \
- script if you specify image keyword'
+ file if you specify image keyword'
lmp_inp_file = join_names([prefix, 'input.lammps'])
with open(lmp_inp_file, 'w', encoding='utf-8') as f:
diff --git a/examples/eos/results/step-0/id-3_x1.02/stdout.txt b/asimtools/asimmodules/phonons/__init__.py
similarity index 100%
rename from examples/eos/results/step-0/id-3_x1.02/stdout.txt
rename to asimtools/asimmodules/phonons/__init__.py
diff --git a/asimtools/scripts/phonons/ase_phonons.py b/asimtools/asimmodules/phonons/ase_phonons.py
similarity index 100%
rename from asimtools/scripts/phonons/ase_phonons.py
rename to asimtools/asimmodules/phonons/ase_phonons.py
diff --git a/asimtools/scripts/singlepoint.py b/asimtools/asimmodules/singlepoint.py
similarity index 100%
rename from asimtools/scripts/singlepoint.py
rename to asimtools/asimmodules/singlepoint.py
diff --git a/examples/eos/results/step-0/id-4_x1.05/stdout.txt b/asimtools/asimmodules/surface_energies/__init__.py
similarity index 100%
rename from examples/eos/results/step-0/id-4_x1.05/stdout.txt
rename to asimtools/asimmodules/surface_energies/__init__.py
diff --git a/asimtools/scripts/surface_energies/surface_energies.py b/asimtools/asimmodules/surface_energies/surface_energies.py
similarity index 82%
rename from asimtools/scripts/surface_energies/surface_energies.py
rename to asimtools/asimmodules/surface_energies/surface_energies.py
index 87c8e01..ea73cd1 100755
--- a/asimtools/scripts/surface_energies/surface_energies.py
+++ b/asimtools/asimmodules/surface_energies/surface_energies.py
@@ -1,9 +1,9 @@
#!/usr/bin/env python
'''
-Describe the script briefly here. If this is a script that runs multiple steps,
+Describe the asimmodule briefly here. If this is a asimmodule that runs multiple steps,
describe it here using reStructuredText to generate autodocs
-Cite the papers where the method/script was first introduced here as well
+Cite the papers where the method/asimmodule was first introduced here as well
Author: mkphuthi@github.com
'''
@@ -15,7 +15,7 @@
from pymatgen.core.surface import generate_all_slabs
from pymatgen.io.ase import AseAtomsAdaptor as AAA
from asimtools.calculators import load_calc
-from asimtools.scripts.atom_relax import atom_relax
+from asimtools.asimmodules.geometry_optimization.atom_relax import atom_relax
from asimtools.utils import (
get_atoms,
)
@@ -35,7 +35,7 @@ def get_surface_energy(slab, calc, bulk_e_per_atom):
surf_en = (slab_en - nslab * bulk_e_per_atom) / (2 * area)
else:
surf_en = None
- return surf_en, slab, converged
+ return converged, surf_en, slab_en, area
def surface_energies(
image: Dict,
@@ -93,7 +93,7 @@ def surface_energies(
image={'atoms': atoms},
optimizer=atom_relax_args.get('optimizer', 'BFGS'),
properties=('energy','forces'),
- fmax=atom_relax_args.get('fmax', 0.02),
+ fmax=atom_relax_args.get('fmax', 0.01),
prefix=f'{miller}_relaxed'
)
atoms = get_atoms(
@@ -109,15 +109,20 @@ def surface_energies(
f'Multiple terminations for {miller}'
slab_dict[miller] = {}
- surf_en, slab_atoms, converged = get_surface_energy(
+ converged, surf_en, slab_en, area = get_surface_energy(
atoms, load_calc(calc_id), bulk_e_per_atom
)
if converged:
slab_dict[miller]['surf_energy'] = float(surf_en)
slab_dict[miller]['natoms'] = len(atoms)
- slab_atoms.write(f'{miller}.xyz')
+ slab_dict[miller]['slab_energy'] = float(slab_en)
+ slab_dict['bulk_energy_per_atom'] = float(bulk_e_per_atom)
+ slab_dict[miller]['area'] = float(area)
+ atoms.write(f'{miller}.xyz')
- results = slab_dict
+ results = {
+ 'surface_energies': slab_dict,
+ }
return results # Always return a dictionary! Use {} if necessary
diff --git a/asimtools/asimmodules/template.py b/asimtools/asimmodules/template.py
new file mode 100755
index 0000000..543741a
--- /dev/null
+++ b/asimtools/asimmodules/template.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+'''
+Describe the asimmodule briefly here. If this is a asimmodule that runs multiple steps,
+describe it here using reStructuredText to generate autodocs
+
+Cite the papers where the method/asimmodule was first introduced here as well
+
+Author: mkphuthi@github.com
+'''
+
+from typing import Dict
+# from asimtools.calculators import load_calc
+# from asimtools.utils import (
+# get_atoms,
+# get_images,
+# )
+
+def template(
+ # calc_id: str,
+ # image: Dict, # Optional: if using a structure
+ # images: Dict, # Optional: if using multiple structures
+) -> Dict:
+ '''
+ asimmodule does xyz specifically
+ '''
+
+ # Some useful lines
+ # calc = load_calc(calc_id)
+ # atoms = get_atoms(**image)
+ # images = get_images(**images)
+
+ #############################
+ # Do some cool science here #
+ #############################
+
+ results = {
+ 'my_result': 'placeholder_for_my_result',
+ 'files': {'file_description': 'placeholder_for_output_file'}
+ }
+ return results # Always return a dictionary! Use {} if necessary
diff --git a/examples/eos/results/step-1/stdout.txt b/asimtools/asimmodules/transformations/__init__.py
similarity index 100%
rename from examples/eos/results/step-1/stdout.txt
rename to asimtools/asimmodules/transformations/__init__.py
diff --git a/asimtools/scripts/scale_unit_cells.py b/asimtools/asimmodules/transformations/scale_unit_cells.py
similarity index 100%
rename from asimtools/scripts/scale_unit_cells.py
rename to asimtools/asimmodules/transformations/scale_unit_cells.py
diff --git a/asimtools/asimmodules/vacancy_formation_energy/__init__.py b/asimtools/asimmodules/vacancy_formation_energy/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/asimtools/asimmodules/vacancy_formation_energy/vacancy_formation_energy.py b/asimtools/asimmodules/vacancy_formation_energy/vacancy_formation_energy.py
new file mode 100755
index 0000000..58e6bce
--- /dev/null
+++ b/asimtools/asimmodules/vacancy_formation_energy/vacancy_formation_energy.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+'''
+Describe the asimmodule briefly here. If this is a asimmodule that runs multiple steps,
+describe it here using reStructuredText to generate autodocs
+
+Cite the papers where the method/asimmodule was first introduced here as well
+
+Author: mkphuthi@github.com
+'''
+
+from typing import Dict, Sequence, Optional
+import logging
+from asimtools.calculators import load_calc
+from asimtools.asimmodules.geometry_optimization.atom_relax import atom_relax
+from asimtools.utils import (
+ get_atoms,
+)
+
+def vacancy_formation_energy(
+ calc_id: str,
+ image: Dict,
+ vacancy_index: int = 0,
+ atom_relax_args: Optional[Dict] = None,
+ repeat: Optional[Sequence] = None
+) -> Dict:
+
+ calc = load_calc(calc_id)
+ bulk = get_atoms(**image).repeat(repeat)
+ bulk.set_calculator(calc)
+
+ vacant = bulk.copy()
+ del vacant[vacancy_index]
+
+ try:
+ bulk_e = calc.get_potential_energy(bulk)
+ logging.info('Finished bulk calculation')
+ except ValueError:
+ logging.error("Failed to calculate energy of bulk structure, "
+ "see calculator output")
+ raise
+
+ bulk.write('bulk_image_output.xyz')
+
+ try:
+ relax_results = atom_relax(
+ calc_id=calc_id,
+ image={'atoms': vacant},
+ optimizer=atom_relax_args.get('optimizer', 'BFGS'),
+ properties=('energy','forces'),
+ fmax=atom_relax_args.get('fmax', 0.01),
+ prefix=f'vacant_relaxed',
+ )
+ logging.info('Relaxed vacant structure')
+ except ValueError:
+ logging.error("Failed to calculate energy of bulk structure, "
+ "see calculator output")
+ raise
+
+ vacant_e = relax_results['energy']
+ vac_form_e = vacant_e - (len(vacant) / len(bulk) * bulk_e)
+
+ res_dict = {}
+ res_dict['bulk_e'] = float(bulk_e)
+ res_dict['vacant_e'] = float(vacant_e)
+ res_dict['bulk_n'] = len(bulk)
+ res_dict['vfe'] = float(vac_form_e)
+
+ results = {'vfe': res_dict}
+ return results
diff --git a/asimtools/asimmodules/workflows/__init__.py b/asimtools/asimmodules/workflows/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/asimtools/scripts/calc_array.py b/asimtools/asimmodules/workflows/calc_array.py
similarity index 51%
rename from asimtools/scripts/calc_array.py
rename to asimtools/asimmodules/workflows/calc_array.py
index 7aa400c..d299b1a 100755
--- a/asimtools/scripts/calc_array.py
+++ b/asimtools/asimmodules/workflows/calc_array.py
@@ -1,18 +1,23 @@
#!/usr/bin/env python
'''
-Apply the same script using multiple calculators
+Apply the same asimmodule using multiple calculators
Author: mkphuthi@github.com
'''
from typing import Dict, Sequence, Optional, Union
+from glob import glob
from copy import deepcopy
from asimtools.job import DistributedJob
-from asimtools.utils import get_calc_input, change_dict_value
+from asimtools.utils import (
+ get_calc_input,
+ change_dict_value,
+ get_str_btn,
+)
def calc_array(
- subscript_input: Dict,
+ subasimmodule_input: Dict,
calc_ids: Sequence[str] = None,
template_calc_id: Optional[str] = None,
key_sequence: Optional[Sequence[str]] = None,
@@ -20,17 +25,19 @@ def calc_array(
env_ids: Optional[Union[Sequence[str],str]] = None,
calc_input: Optional[Dict] = None,
env_input: Optional[Dict] = None,
- ids: Sequence = None,
+ file_pattern: Optional[str] = None,
+ labels: Optional[Union[Sequence,str]] = 'values',
+ str_btn_args: Optional[Dict] = None,
) -> Dict:
- """Apply the same script using different calculators and if necessary
+ """Apply the same asimmodule using different calculators and if necessary
different environments
:param calc_ids: Iterable with calc_ids, defaults to None
:type calc_ids: Sequence, optional
:param calc_input: Dictionary of calculator inputs
:type calc_input: Dictionary, optional
- :param ids: Iterable with custom ids for each calc, defaults to None
- :type ids: Sequence, optional
+ :param labels: Iterable with custom labels for each calc, defaults to None
+ :type labels: Sequence, optional
:return: Dictionary of results
:rtype: Dict
"""
@@ -38,16 +45,26 @@ def calc_array(
and template_calc_id is not None\
and array_values is not None
assert calc_ids is not None or using_array_values, \
- 'Specify either a sequence of calc_ids or all of key_sequence, \
- template_calc_id and array_values to iterate over'
+ 'Specify either an iterable of calc_ids or all of "key_sequence", \
+ "template_calc_id" and "array_values" to iterate over'
if using_array_values:
if calc_input is None:
calc_input = get_calc_input()
calc_params = calc_input[template_calc_id]
new_calc_input = {}
- if ids is None:
- ids = [f'{key_sequence[-1]}-{val}' for val in array_values]
+ if file_pattern is not None:
+ array_values = glob(file_pattern)
+
+ assert len(array_values) > 0, 'No array values or files found'
+ if labels == 'str_btn':
+ assert str_btn_args is not None, 'Provide str_btn_args for labels'
+ labels = [get_str_btn(s, *str_btn_args) for s in array_values]
+ elif labels == 'values':
+ labels = [f'{key_sequence[-1]}-{val}' for val in array_values]
+ elif labels is None:
+ labels = [str(i) for i in range(len(array_values))]
+
for i, val in enumerate(array_values):
new_calc_params = change_dict_value(
d=calc_params,
@@ -55,15 +72,17 @@ def calc_array(
key_sequence=key_sequence,
return_copy=True,
)
- new_calc_input[ids[i]] = new_calc_params
+ new_calc_input[labels[i]] = new_calc_params
calc_input = new_calc_input
- calc_ids = ids
+ calc_ids = labels
elif calc_ids is not None:
- if ids is None:
- ids = calc_ids
+ assert labels != 'get_str_btn', \
+ 'get_str_btn only works when using the key_sequence argument.'
+ if labels is None or labels == 'values':
+ labels = calc_ids
- assert len(ids) == len(calc_ids), \
- 'Num. of calc_ids or array_values must match num. of ids'
+ assert len(labels) == len(calc_ids), \
+ 'Num. of calc_ids or array_values must match num. of labels'
if env_ids is not None:
assert len(env_ids) == len(calc_ids) or isinstance(env_ids, str), \
@@ -73,15 +92,15 @@ def calc_array(
# Make individual sim_inputs for each calc
for i, calc_id in enumerate(calc_ids):
- new_subscript_input = deepcopy(subscript_input)
- new_subscript_input['args']['calc_id'] = calc_id
- array_sim_input[f'{ids[i]}'] = new_subscript_input
+ new_subasimmodule_input = deepcopy(subasimmodule_input)
+ new_subasimmodule_input['args']['calc_id'] = calc_id
+ array_sim_input[f'{labels[i]}'] = new_subasimmodule_input
if env_ids is not None:
if isinstance(env_ids, str):
- new_subscript_input['env_id'] = env_ids
+ new_subasimmodule_input['env_id'] = env_ids
else:
- new_subscript_input['env_id'] = env_ids[i]
+ new_subasimmodule_input['env_id'] = env_ids[i]
# Create a distributed job object
djob = DistributedJob(array_sim_input, env_input, calc_input)
diff --git a/asimtools/scripts/chained.py b/asimtools/asimmodules/workflows/chained.py
similarity index 83%
rename from asimtools/scripts/chained.py
rename to asimtools/asimmodules/workflows/chained.py
index 4779610..908989d 100755
--- a/asimtools/scripts/chained.py
+++ b/asimtools/asimmodules/workflows/chained.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
'''
-Submits a chain of scripts in the order specified by steps
+Submits a chain of asimmodules in the order specified by steps
in input
Author: mkphuthi@github.com
@@ -18,8 +18,8 @@ def chained(
) -> Dict:
"""Run a workflow using the provided sim_input.yaml one after the other,
The jobs will run one after the other, if slurm is used, job dependencies
- will be used. Note that if one of the subscripts internally launches another
- script e.g. image_array, calc_array etc, slurm job dependencies will not
+ will be used. Note that if one of the subasimmodules internally launches another
+ asimmodule e.g. image_array, calc_array etc, slurm job dependencies will not
work as expected. In those cases, we recommend running the steps one by one
or interactively
diff --git a/asimtools/scripts/distributed.py b/asimtools/asimmodules/workflows/distributed.py
similarity index 88%
rename from asimtools/scripts/distributed.py
rename to asimtools/asimmodules/workflows/distributed.py
index e921e06..6aed36f 100755
--- a/asimtools/scripts/distributed.py
+++ b/asimtools/asimmodules/workflows/distributed.py
@@ -10,7 +10,7 @@
from asimtools.job import DistributedJob
def distributed(
- subscripts: Dict,
+ subasimmodules: Dict,
env_input: Optional[Dict] = None,
calc_input: Optional[Dict] = None,
array_max: Optional[int] = None,
@@ -23,10 +23,9 @@ def distributed(
#. use_slurm: False, interactive: False, different env_ids -> Launches \
# multiple jobs.
-
- :param subscripts: Dictionary of scripts, each key is an ID and each \
+ :param subasimmodules: Dictionary of asimmodules, each key is an ID and each \
value is a sim_input file
- :type subscripts: Dict
+ :type subasimmodules: Dict
:param env_input: env_input that overrides global file, defaults to None
:type env_input: Optional[Dict], optional
:param calc_input: calc_input that overrides global file, defaults to None
@@ -37,7 +36,7 @@ def distributed(
:rtype: Dict
"""
djob = DistributedJob(
- sim_input=subscripts,
+ sim_input=subasimmodules,
env_input=env_input,
calc_input=calc_input
)
diff --git a/asimtools/scripts/image_array.py b/asimtools/asimmodules/workflows/image_array.py
similarity index 68%
rename from asimtools/scripts/image_array.py
rename to asimtools/asimmodules/workflows/image_array.py
index 1ff2265..e034440 100755
--- a/asimtools/scripts/image_array.py
+++ b/asimtools/asimmodules/workflows/image_array.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
'''
-Apply the same script on multiple images
+Apply the same asimmodule on multiple images
Author: mkphuthi@github.com
@@ -13,26 +13,26 @@
def image_array(
images: Dict,
- subscript_input: Dict,
+ subasimmodule_input: Dict,
calc_input: Optional[Dict] = None,
env_input: Optional[Dict] = None,
- ids: Sequence[str] = None,
+ labels: Sequence[str] = None,
env_ids: Sequence[str] = None,
array_max: Optional[int] = None,
) -> Dict:
- """Submit the same script on multiple images and if specified, use
+ """Submit the same asimmodule on multiple images and if specified, use
different env_ids
:param images: Image config, see :func:`asimtools.utils.get_atoms`
:type images: Dict
- :param subscript_input: sim_input of script to be run
- :type subscript_input: Dict
+ :param subasimmodule_input: sim_input of asimmodule to be run
+ :type subasimmodule_input: Dict
:param calc_input: calc_input to override global file, defaults to None
:type calc_input: Optional[Dict], optional
:param env_input: env_input to override global file, defaults to None
:type env_input: Optional[Dict], optional
- :param ids: Custom ids for each image, defaults to None
- :type ids: Sequence[str], optional
+ :param labels: Custom labels for each image, defaults to None
+ :type labels: Sequence[str], optional
:param env_ids: Sequence of envs for each image, must be the same length \
as the total number of images, defaults to None
:type env_ids: Sequence[str], optional
@@ -46,11 +46,11 @@ def image_array(
array_sim_input = {}
# Allow user to customize subdirectory names if needed
- if ids is None:
- ids = [str(i) for i in range(len(images))]
+ if labels is None:
+ labels = [str(i) for i in range(len(images))]
else:
- assert len(ids) == len(images), \
- 'Num. of images must match num. of ids'
+ assert len(labels) == len(images), \
+ 'Num. of images must match num. of labels'
if env_ids is not None:
assert len(env_ids) == len(images), \
@@ -58,14 +58,14 @@ def image_array(
# Make individual sim_inputs for each image
for i, image in enumerate(images):
- new_subscript_input = deepcopy(subscript_input)
- new_subscript_input['args']['image'] = {
+ new_subasimmodule_input = deepcopy(subasimmodule_input)
+ new_subasimmodule_input['args']['image'] = {
'atoms': image
}
- array_sim_input[f'{ids[i]}'] = new_subscript_input
+ array_sim_input[f'{labels[i]}'] = new_subasimmodule_input
if env_ids is not None:
- new_subscript_input['env_id'] = env_ids[i]
+ new_subasimmodule_input['env_id'] = env_ids[i]
# Create a distributed job object
djob = DistributedJob(array_sim_input, env_input, calc_input)
diff --git a/asimtools/scripts/sim_array.py b/asimtools/asimmodules/workflows/sim_array.py
similarity index 75%
rename from asimtools/scripts/sim_array.py
rename to asimtools/asimmodules/workflows/sim_array.py
index 594b2cc..51d843c 100755
--- a/asimtools/scripts/sim_array.py
+++ b/asimtools/asimmodules/workflows/sim_array.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
'''
-Runs the same script, iterating over multiple values of a specified argument
+Runs the same asimmodule, iterating over multiple values of a specified argument
based on a sim_input template provided by the user
Author: mkphuthi@github.com
@@ -21,10 +21,10 @@ def sim_array(
env_ids: Optional[Union[Sequence[str],str]] = None,
calc_input: Optional[Dict] = None,
env_input: Optional[Dict] = None,
- ids: Optional[Union[Sequence,str]] = 'values',
+ labels: Optional[Union[Sequence,str]] = 'values',
str_btn_args: Optional[Dict] = None,
) -> Dict:
- """Runs the same script, iterating over multiple values of a specified
+ """Runs the same asimmodule, iterating over multiple values of a specified
argument based on a sim_input template provided by the user
:param template_sim_input: sim_input containing all the default parameters
@@ -39,8 +39,8 @@ def sim_array(
:type calc_input: Optional[Dict], optional
:param env_input: env_input to use, defaults to None
:type env_input: Optional[Dict], optional
- :param ids: Custom ids to use for each simulation, defaults to None
- :type ids: Sequence, optional
+ :param labels: Custom labels to use for each simulation, defaults to None
+ :type labels: Sequence, optional
:return: Results
:rtype: Dict
"""
@@ -50,26 +50,26 @@ def sim_array(
if file_pattern is not None:
array_values = glob(file_pattern)
- print(array_values)
+
assert len(array_values) > 0, 'No array values or files found'
- if ids == 'str_btn':
- assert str_btn_args is not None, 'Provide str_btn_args for ids'
- ids = [get_str_btn(s, *str_btn_args) for s in array_values]
- elif ids == 'values':
- ids = [f'{key_sequence[-1]}-{val}' for val in array_values]
- elif ids is None:
- ids = [str(i) for i in range(len(array_values))]
+ if labels == 'str_btn':
+ assert str_btn_args is not None, 'Provide str_btn_args for labels'
+ labels = [get_str_btn(s, *str_btn_args) for s in array_values]
+ elif labels == 'values':
+ labels = [f'{key_sequence[-1]}-{val}' for val in array_values]
+ elif labels is None:
+ labels = [str(i) for i in range(len(array_values))]
- assert len(ids) == len(array_values), \
- 'Num. of array_values must match num. of ids'
+ assert len(labels) == len(array_values), \
+ 'Num. of array_values must match num. of labels'
if env_ids is None:
pass
elif isinstance(env_ids, str):
- env_ids = [env_ids for i in range(len(ids))]
+ env_ids = [env_ids for i in range(len(labels))]
else:
- assert len(env_ids) == len(ids) or isinstance(env_ids, str), \
+ assert len(env_ids) == len(labels) or isinstance(env_ids, str), \
'Provide one env_id or as many as there are array_values'
# Create sim_inputs for each array value and to create input for
@@ -84,11 +84,10 @@ def sim_array(
)
if env_ids is not None:
new_sim_input['env_id'] = env_ids[i]
- sim_inputs[ids[i]] = new_sim_input
+ sim_inputs[labels[i]] = new_sim_input
# Create a distributed job object
djob = DistributedJob(sim_inputs, env_input, calc_input)
- print('dist workdir', djob.workdir)
job_ids = djob.submit()
results = {'job_ids': job_ids}
diff --git a/asimtools/calculators.py b/asimtools/calculators.py
index d1af56f..363d8ef 100644
--- a/asimtools/calculators.py
+++ b/asimtools/calculators.py
@@ -116,6 +116,35 @@ def load_ase_calc(calc_params):
raise
return calc
+
+# def load_m3gnet(calc_params):
+# """Load and M3GNet calculator
+
+# :param calc_params: parameters to be passed to matgl.ext.ase.M3GNetCalculator. Must include a key "model" that points to the model used to instantiate the potential
+# :type calc_params: Dict
+# :return: M3GNet calculator
+# :rtype: :class:`matgl.ext.ase.M3GNetCalculator`
+# """
+# from matgl.ext.ase import M3GNetCalculator
+# import matgl
+
+# model = calc_params.pop("model")
+# try:
+# pot = matgl.load_model(model)
+# calc = M3GNetCalculator(
+# pot,
+# **calc_params,
+# )
+# except Exception:
+# logging.error("Failed to load M3GNet with parameters:\n %s", calc_params)
+# raise
+
+# return calc
+
+
+# def load_chgnet(calc_params):
+# pass
+
# def load_espresso(calc_params):
# '''
# Load the Espresso calculator as in newer versions of ASE. This is
@@ -137,5 +166,7 @@ def load_ase_calc(calc_params):
'NequIP': load_nequip,
'Allegro': load_nequip,
'DeepPotential': load_dp,
+ # 'ChgNet': load_chgnet,
+ # 'M3GNet': load_m3gnet,
# 'Espresso': load_espresso,
}
diff --git a/asimtools/job.py b/asimtools/job.py
index dfb120c..e069062 100644
--- a/asimtools/job.py
+++ b/asimtools/job.py
@@ -14,6 +14,7 @@
from glob import glob
from typing import List, TypeVar, Dict, Tuple, Union
from copy import deepcopy
+from colorama import Fore
import ase.io
from ase.parallel import paropen
import numpy as np
@@ -31,9 +32,11 @@
Atoms = TypeVar('Atoms')
+START_MESSAGE = '+' * 15 + ' ASIMTOOLS START' + '+' * 15 + '\n'
+STOP_MESSAGE = '+' * 15 + ' ASIMTOOLS STOP' + '+' * 15 + '\n'
+
class Job():
''' Abstract class for the job object '''
-
# pylint: disable=too-many-instance-attributes
def __init__(
self,
@@ -48,12 +51,12 @@ def __init__(
self.env_input = deepcopy(env_input)
self.calc_input = deepcopy(calc_input)
self.sim_input = deepcopy(sim_input)
- self.workdir = Path(
- sim_input.get('workdir', '.')
- ).resolve()
+ self.workdir = Path(sim_input.get('workdir', '.')).resolve()
- # Any subsequent input files should use the full path
- self.sim_input['workdir'] = str(self.workdir)
+ # sim_input will be in workdir from now on so set workdir as a relative
+ # path, but in this class/subclasses, always use self.workdir
+ # which is the full path to avoid confusion
+ self.sim_input['workdir'] = './'
self.launchdir = Path(os.getcwd())
if self.sim_input.get('src_dir', False):
self.sim_input['src_dir'] = self.launchdir
@@ -119,8 +122,7 @@ def get_env_input(self) -> Dict:
def get_output_yaml(self) -> Dict:
''' Get current output file '''
- prefix = ''
- out_fname = join_names([prefix, 'output.yaml'])
+ out_fname = 'output.yaml'
output_yaml = self.workdir / out_fname
return output_yaml
@@ -149,7 +151,7 @@ def update_env_input(self, new_params) -> None:
self.env_input.update(new_params)
def set_workdir(self, workdir) -> None:
- ''' Set working directory '''
+ ''' Set working directory both in sim_input and instance '''
workdir = Path(workdir)
self.sim_input['workdir'] = str(workdir.resolve())
self.workdir = workdir
@@ -169,7 +171,7 @@ def get_status(self, display=False) -> Tuple[bool,str]:
status = output.get('status', 'clean')
complete = status == 'complete'
if display:
- print(f'Current status in "{self.workdir}" is "{status}"')
+ print(f'Status: {status}')
return complete, status
def update_output(self, output_update: Dict) -> None:
@@ -208,7 +210,7 @@ def __init__(
}
}
- # Check if the script being called uses a calc_id to
+ # Check if the asimmodule being called uses a calc_id to
# get precommands, postcommands, run_prefixes and run_suffixes
self.calc_id = self.sim_input.get('args', {}).get('calc_id', None)
if self.calc_id is not None:
@@ -220,8 +222,8 @@ def gen_run_command(self) -> str:
'''
Generates the command to run the job, independent of slurm
'''
- script = self.sim_input.get('script', False)
- assert script, 'Specify a script in sim_input'
+ asimmodule = self.sim_input.get('asimmodule', False)
+ assert asimmodule, 'Specify a asimmodule in sim_input'
mode_params = self.env.get('mode', {
'use_slurm': False, 'interactive': True
@@ -237,10 +239,10 @@ def gen_run_command(self) -> str:
else:
debug_flag = ''
- # GPAW requires python script to be called with gpaw python
+ # GPAW requires python asimmodule to be called with gpaw python
# For now this is a work around but perhaps there exists a cleaner way
if self.calc_params.get('name', '') == 'GPAW':
- asloader = pkgutil.get_loader('asimtools.scripts.asim_run')
+ asloader = pkgutil.get_loader('asimtools.asimmodules.asim_run')
asfile = asloader.get_filename()
alias = f'gpaw python {asfile}'
else:
@@ -260,7 +262,22 @@ def _gen_slurm_script(self, write: bool = True) -> None:
calc_params = self.calc_params
txt = '#!/usr/bin/sh\n'
- for flag in slurm_params.get('flags'):
+ flags = slurm_params.get('flags')
+ if isinstance(flags, dict):
+ flag_list = []
+ for k, v in flags.items():
+ assert k.startswith('-'), \
+ 'Slurm flags must start with "-" or "--"'
+ if k.startswith('--'):
+ delim = '='
+ else:
+ delim = ' '
+
+ flag_list.append(delim.join([k, v]))
+
+ flags = flag_list
+
+ for flag in flags:
txt += f'#SBATCH {flag}\n'
txt += '\n'
for command in slurm_params.get('precommands', []):
@@ -292,9 +309,16 @@ def _gen_slurm_interactive_txt(self) -> str:
return txt
- def gen_input_files(self) -> None:
+ def gen_input_files(
+ self,
+ write_calc_input: bool = True,
+ write_env_input: bool = False,
+ ) -> None:
''' Write input files to working directory '''
workdir = self.workdir
+
+ # This is the sim_input that will be written to disk so it will have
+ # slightly different paths and the image(s) will be image_files
sim_input = deepcopy(self.sim_input)
# The sim_input file will already be in the work directory
sim_input['workdir'] = '.'
@@ -310,15 +334,16 @@ def gen_input_files(self) -> None:
if not workdir.exists():
workdir.mkdir()
elif output_file.exists() and sim_input_file.exists():
- complete = read_yaml(output_file).get('start_time', False)
+ complete = read_yaml(output_file).get('end_time', False)
if complete and not overwrite:
- txt = f'Skipped writing in {self.workdir}, files already '
- txt += 'written. Set overwrite=True to overwrite'
+ txt = f'Skipped writing in {self.workdir}, files/directory '
+ txt += 'already exist. Set overwrite=True to overwrite files '
+ txt += 'or delete results directory first (recommended)'
self.get_logger().warning(txt)
- print(txt)
+ print(Fore.RED + 'WARNING: ' + txt + Fore.WHITE)
return None
- # If the sim_input uses an image/images, we want to write it in
+ # If the sim_input uses an image/images, we want to write it in
# the workdir and point to it using a filename. This is so that
# there is a record of the input image for debugging and the input
# method is consistent with complex workflows
@@ -326,30 +351,36 @@ def gen_input_files(self) -> None:
if image:
atoms = get_atoms(**image)
- input_image_file = self.workdir.resolve() / 'input_image.xyz'
- atoms.write(input_image_file, format='extxyz')
- self.sim_input['args']['image'] = {
+ input_image_file = 'image_input.xyz' # Relative to workdir
+ # input_image_file = self.workdir.resolve() / 'image_input.xyz'
+ atoms.write(
+ self.workdir / input_image_file,
+ format='extxyz'
+ )
+ sim_input['args']['image'] = {
'image_file': str(input_image_file),
+ # 'image_file': str((self.workdir / input_image_file).resolve())
}
images = self.sim_input.get('args', {}).get('images', False)
if images:
- if images.get('images', False):
+ if images.get('images', False) or images.get('image_file', False):
images = get_images(**images)
- input_images_file = self.workdir / 'input_images.xyz'
- ase.io.write(input_images_file, images, format='extxyz')
- self.sim_input['args']['images'] = {
- 'image_file': str(input_images_file),
- }
- elif images.get('image_file', False):
- input_images_file = Path(images['image_file']).resolve()
- self.sim_input['args']['images'] = {
+ input_images_file = 'images_input.xyz' # Relative to workdir
+ ase.io.write(
+ self.workdir / input_images_file,
+ images,
+ format='extxyz'
+ )
+ sim_input['args']['images'] = {
'image_file': str(input_images_file),
}
- write_yaml(workdir / 'sim_input.yaml', self.sim_input)
- write_yaml(workdir / 'calc_input.yaml', self.calc_input)
- write_yaml(workdir / 'env_input.yaml', self.env_input)
+ write_yaml(workdir / 'sim_input.yaml', sim_input)
+ if write_calc_input:
+ write_yaml(workdir / 'calc_input.yaml', self.calc_input)
+ if write_env_input:
+ write_yaml(workdir / 'env_input.yaml', self.env_input)
write_yaml(self.get_output_yaml(), {'status': 'clean'})
if use_slurm and not interactive:
@@ -357,20 +388,32 @@ def gen_input_files(self) -> None:
return None
def submit(
- self, dependency: Union[List,None] = None
+ self,
+ dependency: Union[List,None] = None,
) -> Union[None,List[str]]:
'''
Submit a job using slurm, interactively or in the terminal
'''
+
+ msg = START_MESSAGE
+ msg += f'asimmodule: {self.sim_input["asimmodule"]}\n'
+ msg += f'Work directory: {self.workdir}'
+ logmsg = f'Submitting "{self.sim_input["asimmodule"]}" in "{self.workdir}"'
+ logging.info(logmsg)
+ print(msg) # For printing to console
+
self.gen_input_files()
logger = self.get_logger()
_, status = self.get_status(display=True)
- if status in ('discard'):
+ if status in ('discard', 'complete'):
txt = f'Current job status in "{self.workdir}" is "{status}", '
txt += 'skipping submission, set "overwrite=True" to ignore'
logger.warning(txt)
+ if status in ('complete'):
+ print('Job already completed, not submitting again')
+ print(STOP_MESSAGE)
return None
if not self.sim_input.get('submit', True):
@@ -378,9 +421,6 @@ def submit(
%s', self.workdir)
return None
- msg = f'Submitting "{self.sim_input["script"]}" in "{self.workdir}"'
- logging.info(msg)
- print(msg) # For printing to console, maybe can be cleaner
cur_dir = Path('.').resolve()
os.chdir(self.workdir)
mode_params = self.env.get('mode', {})
@@ -440,8 +480,10 @@ def submit(
self.update_output({'job_ids': job_ids})
return job_ids
- msg = f'Submitted "{self.sim_input["script"]}" in "{self.workdir}"'
- logger.info(msg)
+ logmsg = f'Submitted "{self.sim_input["asimmodule"]}" in "{self.workdir}"'
+ msg = 'Successfully submitted\n'
+ msg += STOP_MESSAGE
+ logger.info(logmsg)
print(msg)
return None
@@ -458,26 +500,35 @@ def __init__(
# Set a standard for all subdirectories to start
# with "id-{sim_id}" followed by user labels
new_sim_input = {}
- num_digits =len(str(len(sim_input)))
+ njobs = len(sim_input)
+ num_digits = 4
+ assert njobs < 1000, \
+ f'ASIMTools id_nums are limited to {num_digits} digits, found \
+ {njobs} jobs! Having that many jobs is not very storage efficient.'
+
sim_id_changed = False
for i, (sim_id, subsim_input) in enumerate(sim_input.items()):
- assert 'script' in subsim_input, 'Check sim_input format,\
- must have script and each job with a unique key'
+ assert 'asimmodule' in subsim_input, 'Check sim_input format,\
+ must have asimmodule and each job with a unique key'
# We set a fixed number of digits so that the slurm array ID
# matches the directory name for easy resubmission of arrays
prefix = 'id-'+f'{i}'.rjust(num_digits, '0')
if not sim_id.startswith(prefix):
sim_id_changed = True
- new_sim_id = join_names([prefix,sim_id])
- new_sim_input[new_sim_id] = deepcopy(sim_input[sim_id])
if sim_id_changed:
+ for i, (sim_id, subsim_input) in enumerate(sim_input.items()):
+ prefix = 'id-'+f'{i}'.rjust(num_digits, '0')
+ new_sim_id = join_names([prefix,sim_id])
+ new_subsim_input = deepcopy(sim_input[sim_id])
+ new_subsim_input['distributed_id'] = i
+ new_sim_input[new_sim_id] = new_subsim_input
sim_input = new_sim_input
unitjobs = []
for sim_id, subsim_input in sim_input.items():
- assert 'script' in subsim_input, 'Check sim_input format,\
- must have script and each job with a unique key'
+ assert 'asimmodule' in subsim_input, 'Check sim_input format,\
+ must have asimmodule and each job with a unique key'
subsim_input['workdir'] = sim_id
unitjob = UnitJob(subsim_input, env_input, calc_input)
@@ -652,7 +703,7 @@ def submit(self, **kwargs) -> None:
class ChainedJob(Job):
'''
Jobs made of smaller sequential unitjobs. Note that this only works
- well with unit jobs. If one of the UnitJobs calls scripts, internally,
+ well with unit jobs. If one of the UnitJobs calls asimmodules, internally,
slurm will fail to build the correct dependencies but the files will be
generated appropriately, you can submit them manually
'''
@@ -721,7 +772,7 @@ def submit(self, dependency: Union[List,None] = None) -> List:
if not cur_step_complete:
unitjob.env['slurm']['flags'].append(f'-J step-{step+i}')
# Get latest job_id if previous step output was updated with new IDs
- # This should allow scripts that run scripts to use correct dependencies
+ # This should allow asimmodules that run asimmodules to use correct dependencies
# print(f'Job id for step-{i} is {dependency}')
# if i > 0:
# dependency = self.unitjobs[i-1].get_output().get('job_ids', dependency)
@@ -772,4 +823,24 @@ def load_job_from_directory(workdir: str):
calc_input = None
job = Job(sim_input, env_input, calc_input)
+
+ # This makes sure that wherever we may be loading the job from, we refer
+ # to the correct input/output files. As of now, it does not seem necessary
+ # to also change the workdir in sim_input.yaml for consistency
+ job.workdir = Path(workdir)
return job
+
+def create_unitjob(sim_input, env_input, workdir, calc_input=None):
+ """Helper for making a generic UnitJob object, mostly for testing"""
+ env_id = list(env_input.keys())[0]
+ sim_input['env_id'] = env_id
+ if calc_input is not None:
+ calc_id = list(calc_input.keys())[0]
+ sim_input['calc_id'] = calc_id
+ sim_input['workdir'] = workdir
+ unitjob = UnitJob(
+ sim_input,
+ env_input,
+ calc_input
+ )
+ return unitjob
diff --git a/asimtools/scripts/asim_check.py b/asimtools/scripts/asim_check.py
index 36793c9..6869973 100755
--- a/asimtools/scripts/asim_check.py
+++ b/asimtools/scripts/asim_check.py
@@ -4,6 +4,7 @@
and pring out the progress
'''
import sys
+import os
from pathlib import Path
import argparse
from typing import Dict, Tuple
@@ -12,7 +13,7 @@
from asimtools.job import load_job_from_directory
-def parse_command_line(args) -> Tuple[Dict, str]:
+def parse_command_line(args) -> Tuple[Dict, os.PathLike]:
''' Parse command line input '''
parser = argparse.ArgumentParser()
parser.add_argument(
@@ -23,7 +24,8 @@ def parse_command_line(args) -> Tuple[Dict, str]:
)
args = parser.parse_args(args)
sim_input = read_yaml(args.sim_input_file)
- return sim_input
+ rootdir = Path('/'.join(args.sim_input_file.split('/')[:-1]))
+ return sim_input, rootdir
def main(args=None) -> None:
"""Main
@@ -31,9 +33,12 @@ def main(args=None) -> None:
:param args: cmdline args, defaults to None
:type args: _type_, optional
"""
- sim_input = parse_command_line(args)
- rootdir = sim_input['workdir']
- jobtree = load_job_tree(rootdir)
+ sim_input, rootdir = parse_command_line(args)
+ if not sim_input['workdir'].startswith('/'):
+ workdir = rootdir / sim_input['workdir']
+ else:
+ workdir = sim_input['workdir']
+ jobtree = load_job_tree(workdir)
print_job_tree(jobtree)
def get_subjobs(workdir):
@@ -61,7 +66,7 @@ def load_job_tree(
:return: dictionary mimicking the job tree
:rtype: Dict
"""
- workdir = Path(workdir)
+ workdir = Path(workdir).resolve()
subjob_dirs = get_subjobs(workdir)
if len(subjob_dirs) > 0:
@@ -73,7 +78,7 @@ def load_job_tree(
job = load_job_from_directory(workdir)
job_dict = {
- 'workdir': workdir.name,
+ 'workdir_name': workdir.name,
'job': job,
'subjobs': subjob_dict,
}
@@ -103,10 +108,10 @@ def print_job_tree(job_tree: Dict, indent_str='', level=0) -> None:
reset = Fore.WHITE
subjobs = job_tree['subjobs']
if subjobs is not None:
- workdir = job_tree['workdir']
+ workdir = job_tree['workdir_name']
status, color = get_status_and_color(job_tree['job'])
- script = job_tree['job'].sim_input['script']
- print(color + f'{indent_str}{workdir}, script: {script},' + \
+ asimmodule = job_tree['job'].sim_input['asimmodule']
+ print(color + f'{indent_str}{workdir}, asimmodule: {asimmodule},' + \
f'status: {status}' + reset)
if level > 0:
indent_str = '| ' + ' ' * level
@@ -119,11 +124,11 @@ def print_job_tree(job_tree: Dict, indent_str='', level=0) -> None:
subjob = job_tree['job']
else:
- subjob_dir = job_tree['workdir']
+ subjob_dir = job_tree['workdir_name']
subjob = job_tree['job']
- script = subjob.sim_input['script']
+ asimmodule = subjob.sim_input['asimmodule']
status, color = get_status_and_color(subjob)
- print(color + f'{indent_str}{subjob_dir}, script: {script}, '+\
+ print(color + f'{indent_str}{subjob_dir}, asimmodule: {asimmodule}, '+\
f'status: {status}' + reset)
if __name__ == "__main__":
diff --git a/asimtools/scripts/asim_execute.py b/asimtools/scripts/asim_execute.py
index 039fad4..95a45e6 100755
--- a/asimtools/scripts/asim_execute.py
+++ b/asimtools/scripts/asim_execute.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
'''
Execute a workflow given the sim_input.yaml and optionally,
-a calc_input.yaml and/or env_input.yaml. The called script will be run
+a calc_input.yaml and/or env_input.yaml. The called asimmodule will be run
in the specified workdir and env_id
Author: mkphuthi@github.com
@@ -60,18 +60,19 @@ def parse_command_line(args) -> Tuple[Dict, Dict]:
return sim_input, env_input, calc_input
-
def main(args=None) -> None:
- """Execute a workflow given the sim_input.yaml and optinally,
- a calc_input.yaml and/or env_input.yaml. The called script will be run
+ """Execute a workflow given the sim_input.yaml and optionally,
+ a calc_input.yaml and/or env_input.yaml. The called asimmodule will be run
in the specified workdir and env_id """
sim_input, env_input, calc_input = parse_command_line(args)
+ sim_input['workdir'] = sim_input.get('workdir', 'results')
+
job = UnitJob(
sim_input=sim_input,
env_input=env_input,
calc_input=calc_input
)
- job.gen_input_files()
+ job.gen_input_files(write_calc_input=True, write_env_input=True)
job.go_to_workdir()
try:
job.submit()
diff --git a/asimtools/scripts/asim_run.py b/asimtools/scripts/asim_run.py
index 95ef566..7de5860 100755
--- a/asimtools/scripts/asim_run.py
+++ b/asimtools/scripts/asim_run.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
'''
-Execute a script given the sim_input.yaml and optionally,
-a calc_input.yaml. The called script will be run directly in the current
+Execute a asimmodule given the sim_input.yaml and optionally,
+a calc_input.yaml. The called asimmodule will be run directly in the current
directory and environment
'''
@@ -64,7 +64,7 @@ def main(args=None) -> None:
if calc_input_file is not None:
assert Path(calc_input_file).exists(), 'Specify valid calc input file'
os.environ["ASIMTOOLS_CALC_INPUT"] = calc_input_file
- script = sim_input['script']
+ asimmodule = sim_input['asimmodule']
precommands = sim_input.get('precommands', [])
for precommand in precommands:
@@ -84,36 +84,36 @@ def main(args=None) -> None:
completed_process.check_returncode()
- module_name = script.split('/')[-1].split('.py')[0]
- func_name = module_name.split('.')[-1] # must match script name
+ module_name = asimmodule.split('/')[-1].split('.py')[0]
+ func_name = module_name.split('.')[-1] # must match asimmodule name
- # Check if the script is a core script
- spec = importlib.util.find_spec('.'+module_name,'asimtools.scripts')
+ # Check if the asimmodule is a core asimmodule
+ spec = importlib.util.find_spec('.'+module_name,'asimtools.asimmodules')
if spec is not None:
sim_module = importlib.import_module(
- '.'+module_name,'asimtools.scripts'
+ '.'+module_name,'asimtools.asimmodules'
)
- logger.debug('Loaded core script %s', module_name)
+ logger.debug('Loaded core asimmodule %s', module_name)
else:
- # Try and find a script from the set script directory
- script_dir = os.environ.get('ASIMTOOLS_SCRIPT_DIR', False)
- if script_dir:
- # script = script.replace('.', '/')
- script = Path(script_dir) / script
+ # Try and find a asimmodule from the set asimmodule directory
+ asimmodule_dir = os.environ.get('ASIMTOOLS_ASIMMODULE_DIR', False)
+ if asimmodule_dir:
+ # asimmodule = asimmodule.replace('.', '/')
+ asimmodule = Path(asimmodule_dir) / asimmodule
spec = importlib.util.spec_from_file_location(
- module_name, script
+ module_name, asimmodule
)
- logger.debug('Loading script from script directory %s', script)
+ logger.debug('Loading asimmodule from asimmodule directory %s', asimmodule)
if spec is None:
spec = importlib.util.spec_from_file_location(
- module_name, script
+ module_name, asimmodule
)
- logger.debug('Loading script from full path %s', script)
+ logger.debug('Loading asimmodule from full path %s', asimmodule)
try:
sim_module = importlib.util.module_from_spec(spec)
except Exception as exc:
- err_msg = f'Failed to load module for script: "{script}"'
+ err_msg = f'Failed to load module for asimmodule: "{asimmodule}"'
logger.error(err_msg)
raise AttributeError(err_msg) from exc
@@ -121,9 +121,9 @@ def main(args=None) -> None:
try:
spec.loader.exec_module(sim_module)
except Exception as exc:
- err_txt = f'Failed to load script: {script}. Check your '
- err_txt += 'ASIMTOOLS_SCRIPT_DIR environment variable, '
- err_txt += 'provide the full path and ensure the script works.'
+ err_txt = f'Failed to load asimmodule: {asimmodule}. Check your '
+ err_txt += 'ASIMTOOLS_ASIMMODULE_DIR environment variable, '
+ err_txt += 'provide the full path and ensure the asimmodule works.'
logger.error(err_txt)
raise FileNotFoundError(err_txt) from exc
@@ -136,9 +136,9 @@ def main(args=None) -> None:
try:
results = sim_func(**sim_input.get('args', {}))
- logger.info('Successfully ran script "%s" in "%s"', script, cwd)
+ logger.info('Successfully ran asimmodule "%s" in "%s"', asimmodule, cwd)
except:
- logger.info('Failed to run script "%s" in "%s"', script, cwd)
+ logger.info('Failed to run asimmodule "%s" in "%s"', asimmodule, cwd)
# Restore the CALC_INPUT environment variable
if old_calc_input_var is not None:
os.environ["ASIMTOOLS_CALC_INPUT"] = old_calc_input_var
@@ -157,9 +157,9 @@ def main(args=None) -> None:
if os.getenv("ASIMTOOLS_CALC_INPUT", None) is not None:
del os.environ["ASIMTOOLS_CALC_INPUT"]
- # Get job IDs from internally run scripts if any
+ # Get job IDs from internally run asimmodules if any
job_ids = results.get('job_ids', False)
- # Otherwise get job_ids from wherever this script is running
+ # Otherwise get job_ids from wherever this asimmodule is running
if not job_ids:
job_ids = os.getenv('SLURM_JOB_ID')
results['job_ids'] = job_ids
diff --git a/asimtools/scripts/env_array.py b/asimtools/scripts/env_array.py
deleted file mode 100755
index 76ed981..0000000
--- a/asimtools/scripts/env_array.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-'''
-Apply the same script using different envs
-
-Author: mkphuthi@github.com
-
-'''
-
-from typing import Dict, Sequence, Optional
-from copy import deepcopy
-from asimtools.job import DistributedJob
-
-def env_array(
- subscript_input: Dict,
- env_ids: Sequence[str],
- calc_input: Optional[Dict] = None,
- env_input: Optional[Dict] = None,
- ids: Sequence = None,
-) -> Dict:
- """Run the same script using multiple env_ids
-
- :param subscript_input: sim_input for the script to be run
- :type subscript_input: Dict
- :param env_ids: Sequence of env_ids to iterate over
- :type env_ids: Sequence[str]
- :param calc_input: calc_input to override global file, defaults to None
- :type calc_input: Optional[Dict], optional
- :param env_input: env_input defaults to overide global file, defaults to\
- None
- :type env_input: Optional[Dict], optional
- :param ids: Sequence of custom ids for each env_id, defaults to None
- :type ids: Sequence, optional
- :return: Dictionary of results
- :rtype: Dict
- """
- array_sim_input = {}
-
- # Allow user to customize subdirectory names if needed
- if ids is None:
- ids = [str(i) for i in range(len(env_ids))]
- else:
- assert len(ids) == len(env_ids), \
- 'Num. of env_ids must match num. of ids'
-
- # Make individual sim_inputs for each env
- for i, env_id in enumerate(env_ids):
- new_subscript_input = deepcopy(subscript_input)
- new_subscript_input['env_id'] = env_id
- array_sim_input[f'{ids[i]}'] = new_subscript_input
-
- # Create a distributed job object
- djob = DistributedJob(array_sim_input, env_input, calc_input)
- job_ids = djob.submit()
-
- results = {
- 'job_ids': job_ids,
- }
- return results
diff --git a/asimtools/scripts/eos/eos.py b/asimtools/scripts/eos/eos.py
deleted file mode 100644
index ab9758b..0000000
--- a/asimtools/scripts/eos/eos.py
+++ /dev/null
@@ -1,54 +0,0 @@
-'''.Xauthority'''
-
-from typing import Dict, Tuple
-from asimtools.job import ChainedJob
-
-def eos(
- image: dict,
- singlepoint_env_id: str,
- calc_id: str,
- preprocess_env_id: str,
- nimages: int = 5,
- scale_range: Tuple[float] = (0.95, 1.05),
- postprocess: bool = True,
-) -> Dict:
- ''' EOS calculation '''
-
- sim_input = {
- 'step-0': {
- 'script': 'eos.preprocess',
- 'env_id': preprocess_env_id,
- 'args': {
- 'image': image,
- 'nimages': nimages,
- 'scale_range': scale_range,
- }
- },
- 'step-1': {
- 'script': 'image_array',
- 'env_id': preprocess_env_id,
- 'args': {
- 'images': {'image_file': 'step-0/preprocess_images_output.xyz'},
- 'subscript_input': {
- 'script': 'singlepoint',
- 'env_id': singlepoint_env_id,
- 'args': {
- 'calc_id': calc_id,
- 'properties': ['energy'],
- }
- }
- }
- },
- 'step-2': {
- 'script': 'eos.postprocess',
- 'env_id': preprocess_env_id,
- 'submit': postprocess, #Fails if previous step is in a slurm queue
- 'args': {
- 'images': {'pattern': '../step-1/id-*/image_output.xyz'},
- }
- }
- }
-
- chain = ChainedJob(sim_input, env_input=None, calc_input=None)
- chain.submit()
- return chain.get_last_output()
diff --git a/asimtools/scripts/eos/preprocess.py b/asimtools/scripts/eos/preprocess.py
deleted file mode 100644
index 283663e..0000000
--- a/asimtools/scripts/eos/preprocess.py
+++ /dev/null
@@ -1,35 +0,0 @@
-'''.Xauthority'''
-
-from typing import Dict, Tuple
-import numpy as np
-from ase.io import write
-from asimtools.utils import (
- get_atoms,
-)
-
-def preprocess(
- image: Dict,
- nimages: int = 5,
- scale_range: Tuple[float,float] = (0.95, 1.05),
-) -> Dict:
- ''' Prepares structures for EOS calculation '''
-
- assert scale_range[0] < scale_range[1], 'x_scale[0] should be smaller than\
- x_scale[1]'
-
- atoms = get_atoms(**image)
-
- # Make a database of structures with the volumes scaled appropriately
- scales = np.linspace(scale_range[0], scale_range[1], nimages)
- scaled_images = []
- for scale in scales:
- new_cell = atoms.get_cell() * scale
- new_atoms = atoms.copy()
- new_atoms.set_cell(new_cell, scale_atoms=True)
- new_atoms.info['scale'] = f'{scale:.2f}'
- scaled_images.append(new_atoms)
-
- scaled_images_file = 'preprocess_images_output.xyz'
- write(scaled_images_file, scaled_images, format='extxyz')
-
- return {'files': {'images': scaled_images_file}}
diff --git a/asimtools/scripts/template.py b/asimtools/scripts/template.py
deleted file mode 100755
index c75a4a4..0000000
--- a/asimtools/scripts/template.py
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/env python
-'''
-Describe the script briefly here. If this is a script that runs multiple steps,
-describe it here using reStructuredText to generate autodocs
-
-Cite the papers where the method/script was first introduced here as well
-
-Author: mkphuthi@github.com
-'''
-
-from typing import Dict
-# from asimtools.calculators import load_calc
-from asimtools.utils import (
- get_atoms,
- # get_images,
-)
-
-def template(
- # calc_id: str,
- # image: Dict, # Optional: if using a structure
- # images: Dict, # Optional: if using multiple structures
-) -> Dict:
- '''
- Script does xyz specifically
- '''
-
- # calc = load_calc(calc_id) # Optional: Any code that loads a calculator is replaced by this one line!
- # atoms = get_atoms(**image) # Optional
- # images = get_images(**images) # Optional
- # atoms.set_calculator(calc) # Optional
-
- #############################
- # Do some cool science here #
- #############################
-
- results = {
- 'energy': 'Placeholder_for_my_result',
- 'files': {'image': 'placeholder_four_image_output'}
- }
- return results # Always return a dictionary! Use {} if necessary
diff --git a/asimtools/scripts/vacancy_formation_energy/vacancy_formation_energy.py b/asimtools/scripts/vacancy_formation_energy/vacancy_formation_energy.py
deleted file mode 100755
index 443c459..0000000
--- a/asimtools/scripts/vacancy_formation_energy/vacancy_formation_energy.py
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env python
-'''
-Describe the script briefly here. If this is a script that runs multiple steps,
-describe it here using reStructuredText to generate autodocs
-
-Cite the papers where the method/script was first introduced here as well
-
-Author: mkphuthi@github.com
-'''
-
-from typing import Dict, Sequence, Optional
-import logging
-from asimtools.calculators import load_calc
-from asimtools.utils import (
- get_atoms,
-)
-
-def vacancy_formation_energy(
- calc_id: str,
- image: Dict,
-) -> Dict:
- '''
-
- '''
- calc = load_calc(calc_id)
- atoms = get_atoms(**image)
- atoms.set_calculator(calc)
-
- results = {}
- return results
diff --git a/asimtools/utils.py b/asimtools/utils.py
index c6e9ad6..75deb00 100644
--- a/asimtools/utils.py
+++ b/asimtools/utils.py
@@ -121,7 +121,7 @@ def join_names(substrs: Sequence[str]) -> str:
for substr in new_substrs:
if len(substr) > 0:
final_substrs.append(substr)
- name = '_'.join(final_substrs)
+ name = '__'.join(final_substrs) + '__'
return name
def get_atoms(
@@ -160,6 +160,8 @@ def get_atoms(
"Specify atoms, image_file or use ase.build tools"
if image_file is not None:
+ assert Path(image_file).exists(), \
+ f'The image_file {image_file} does not exist from {os.getcwd()}'
atoms = read(image_file, **kwargs)
elif atoms is None:
builder_func = getattr(ase.build, builder)
@@ -242,7 +244,7 @@ def get_images(
image_file = Path(image_file).resolve()
images = read(image_file, index=index, **kwargs)
if not isinstance(images, list):
- images = [images]
+ images = [images]
elif pattern is not None:
image_files = glob(pattern)
assert len(image_files) > 0, \
@@ -275,14 +277,20 @@ def get_images(
for pattern in patterns:
image_files = glob(pattern)
assert len(image_files) > 0, \
- f'No images matching patterns "{pattern}" from "{os.getcwd()}"'
- images += get_images(pattern=pattern, index=index, **kwargs)
+ f'Don\'t include pattern "{pattern}" if no files match'
+ images += get_images(
+ pattern=pattern,
+ index=index,
+ skip_failed=skip_failed,
+ **kwargs
+ )
elif images is not None:
images = images[parse_slice(str(index))]
else:
images = []
- assert len(images) > 0, 'No images found'
+ if not skip_failed:
+ assert len(images) > 0, 'No images found'
return images
@@ -410,6 +418,31 @@ def change_dict_value(
d[key_sequence[0]] = new_d
return d
+def change_dict_values(
+ d: Dict,
+ new_values: Sequence,
+ key_sequences: Sequence,
+ return_copy: bool = True
+) -> Dict:
+ """Changes values in the specified dictionary given by following the
+ key sequences. Key-value pairs are set in the given order
+
+ :param d: dictionary to be changed
+ :type d: Dict
+ :param new_values: The new values that will replace the old one
+ :type new_values: Sequence
+ :param key_sequence: List of list of keys in the order in which they access the dictionary key
+ :type key_sequence: Sequence
+ :param return_copy: Whether to return a copy only or to modify the dictionary in-place as well, defaults to True
+ :type return_copy: bool, optional
+ :return: The changed dictionary
+ :rtype: Dict
+ """
+ for key_sequence, new_value in zip(key_sequences, new_values):
+ d = change_dict_value(d, new_value, key_sequence, return_copy)
+
+ return d
+
def get_logger(
logfile='job.log',
fstr='%(asctime)s |%(module)s|%(funcName)s| %(levelname)s: %(message)s',
@@ -432,16 +465,41 @@ def get_logger(
return logging.getLogger(__name__)
-def get_str_btn(s, s1, s2):
+def get_str_btn(
+ s: str,
+ s1: str,
+ s2: str,
+ start: int = 0,
+ end: int = 0
+):
''' Return substring between the first instance of s1 and the first
instance of s2 after s1 in s. None corresponds to beginning or end of
string for s1 and s2 respectively '''
+
if s1 is not None:
- i1 = s.index(s1) + len(s1)
+ i1 = s.index(s1, start) + len(s1)
else:
i1 = 0
if s2 is not None:
- i2 = s[i1:].index(s2) + i1
+ i2 = s[i1:].index(s2, end) + i1
else:
i2 = len(s)
return s[i1:i2]
+
+def find_nth(haystack: str, needle: str, n: int) -> int:
+ ''' Return index of nth occurence of substrin in string '''
+ start = haystack.find(needle)
+ while start >= 0 and n > 1:
+ start = haystack.find(needle, start+len(needle))
+ n -= 1
+ return start
+
+def get_nth_label(
+ s: str,
+ n: int = 1,
+):
+ ''' Return nth label in a string potentially containin multiple labels,
+ indexing starts from 0 '''
+ start = find_nth(s, '__', n=(n*2+1))
+ print('start', start)
+ return get_str_btn(s, '__', '__', start=start)
diff --git a/build/.doctrees/CONTRIBUTING.doctree b/build/.doctrees/CONTRIBUTING.doctree
new file mode 100644
index 0000000..24eae18
Binary files /dev/null and b/build/.doctrees/CONTRIBUTING.doctree differ
diff --git a/build/.doctrees/README.doctree b/build/.doctrees/README.doctree
new file mode 100644
index 0000000..1185b46
Binary files /dev/null and b/build/.doctrees/README.doctree differ
diff --git a/build/.doctrees/asimplify.doctree b/build/.doctrees/asimplify.doctree
new file mode 100644
index 0000000..68df9ae
Binary files /dev/null and b/build/.doctrees/asimplify.doctree differ
diff --git a/build/.doctrees/asimtools.doctree b/build/.doctrees/asimtools.doctree
new file mode 100644
index 0000000..a298e7d
Binary files /dev/null and b/build/.doctrees/asimtools.doctree differ
diff --git a/build/.doctrees/asimtools.scripts.doctree b/build/.doctrees/asimtools.scripts.doctree
new file mode 100644
index 0000000..77b0927
Binary files /dev/null and b/build/.doctrees/asimtools.scripts.doctree differ
diff --git a/build/.doctrees/asimtools.scripts.eos.doctree b/build/.doctrees/asimtools.scripts.eos.doctree
new file mode 100644
index 0000000..d6c7121
Binary files /dev/null and b/build/.doctrees/asimtools.scripts.eos.doctree differ
diff --git a/build/.doctrees/environment.pickle b/build/.doctrees/environment.pickle
new file mode 100644
index 0000000..d81c84f
Binary files /dev/null and b/build/.doctrees/environment.pickle differ
diff --git a/build/.doctrees/include_contributing.doctree b/build/.doctrees/include_contributing.doctree
new file mode 100644
index 0000000..21e26fb
Binary files /dev/null and b/build/.doctrees/include_contributing.doctree differ
diff --git a/build/.doctrees/include_readme.doctree b/build/.doctrees/include_readme.doctree
new file mode 100644
index 0000000..3e4df33
Binary files /dev/null and b/build/.doctrees/include_readme.doctree differ
diff --git a/build/.doctrees/index.doctree b/build/.doctrees/index.doctree
new file mode 100644
index 0000000..0e7da71
Binary files /dev/null and b/build/.doctrees/index.doctree differ
diff --git a/build/.doctrees/modules.doctree b/build/.doctrees/modules.doctree
new file mode 100644
index 0000000..286b722
Binary files /dev/null and b/build/.doctrees/modules.doctree differ
diff --git a/build/.doctrees/usage.doctree b/build/.doctrees/usage.doctree
new file mode 100644
index 0000000..f3e1029
Binary files /dev/null and b/build/.doctrees/usage.doctree differ
diff --git a/build/.doctrees/workflows.doctree b/build/.doctrees/workflows.doctree
new file mode 100644
index 0000000..abeb235
Binary files /dev/null and b/build/.doctrees/workflows.doctree differ
diff --git a/build/CONTRIBUTING.html b/build/CONTRIBUTING.html
deleted file mode 100644
index 28906fa..0000000
--- a/build/CONTRIBUTING.html
+++ /dev/null
@@ -1,198 +0,0 @@
-
-
-
When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change.
-
Please note we have a code of conduct, please follow it in all your interactions with the project.
-
There are two main ways to contribute. One is to make changes to the existing
-codes and scripts. In this case, please make sure your change passes tests or
-submit a test accordinly. The second way to contribute is to add a new script
-to the core set of scripts. Reviewers will work with you to make sure your new
-script follows best practice including using utils, syntax highlighting, docs
-and tests.
Ensure any install or build dependencies are removed before the end of the layer when doing a build.
-
Update the README.md with details of changes to the interface, this includes new environment variables, exposed ports, useful file locations and container parameters.
-
Increase the version numbers in any examples files and the README.md to the new version that this Pull Request would represent. The versioning scheme we use is SemVer.
-
You may merge the Pull Request in once you have the sign-off of one other developer, or if you do not have permission to do that, you may request the other reviewer to merge it for you.
In the interest of fostering an open and welcoming environment, we as
-contributors and maintainers pledge to making participation in our project and
-our community a harassment-free experience for everyone, regardless of age, body
-size, disability, ethnicity, gender identity and expression, level of experience,
-nationality, personal appearance, race, religion, or sexual identity and
-orientation.
Project maintainers are responsible for clarifying the standards of acceptable
-behavior and are expected to take appropriate and fair corrective action in
-response to any instances of unacceptable behavior.
-
Project maintainers have the right and responsibility to remove, edit, or
-reject comments, commits, code, wiki edits, issues, and other contributions
-that are not aligned to this Code of Conduct, or to ban temporarily or
-permanently any contributor for other behaviors that they deem inappropriate,
-threatening, offensive, or harmful.
This Code of Conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community. Examples of
-representing a project or community include using an official project e-mail
-address, posting via an official social media account, or acting as an appointed
-representative at an online or offline event. Representation of a project may be
-further defined and clarified by project maintainers.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
-complaints will be reviewed and investigated and will result in a response that
-is deemed necessary and appropriate to the circumstances. The project team is
-obligated to maintain confidentiality with regard to the reporter of an incident.
-Further details of specific enforcement policies may be posted separately.
-
Project maintainers who do not follow or enforce the Code of Conduct in good
-faith may face temporary or permanent repercussions as determined by other
-members of the project’s leadership.
This package is a lightweight workflow and simulation manager for reproducible
-atomistic simulations that can be transferred across environments, calculators
-and structures. By using in-built or user-defined scripts and utilities, users
-can run/build their own simulation recipes and automagically scale them on
-slurm based clusters. The core idea is to separate the dependence of the
-atomistic potential/calculator and the simulations steps thereby allowing the
-same simulation to be run with multiple calculators and the same calculator to
-be used for multiple simulations. Input and output files must follow a strict
-format so that consistent analysis pipelines can be used across users
The goal of asimtools is to push all the complexity of workflow
-management, best-practices, file management etc. into the backend such that the
-everyday user only has to handle input files for existing workflows and script
-files for workflows they want to implement. The following are the guiding
-principles for how asimtools should work:
-
-
Scripts should resemble boilerplate ASE code as much as possible.
-
Scripts should not explicitly depend on a calculator
-
Scripts should not explicitly depend on the context in which they run
-
It should be easy to debug individual scripts/parts in large workflows. In
-addition, it should always be possible to debug/resubmit jobs without using
-asimtools.
-
input file structure and format should be standard across all scripts. In
-addition all input parameters should match how they would like without
-asimtools i.e. do not provide an API! This means extensive use of importlib.
-
output file structure should be predictable across all scripts
-
Job progress tracking must be incorporated
-
Best practices should be built-in e.g. if multiple jobs of the same slurm
-context are submitted simulataneously, it must be a job array
The philosophy is to build “simulations” using building blocks of scripts.
-These scripts can be as complicated/efficient as you make them using any
-external packages you want and can be optimized with time but can still be run
-within the framework. This allows a test friendly way to transition from say a
-tutorial on the ASE/pymatgen website to an asimtools script. So while
-complicated wrappers are discouraged, they would still work as long as the
-script works. The benefit out of the box is that you can make your script
-independent of calculator or input structures and submit them easily.
This installs the base package in developer mode so that you do not have to
-reinstall if you make changes to the core package.
-
Individual calculators may need external packages for loading those
-calculators. Similarly some scripts e.g. lammps.py might also need external packages to be used. It is up to the user to make sure those are installed.
-
You will also need to setup some environment variables, these variables point
-to a env_input.yaml and calc_input.yaml with your favorite configs since
-these are commonly shared among simulations. You can also directly specify them
-when running asim-execute (See asim-execute-h).
-Examples of these files can be found in the examples.
-'''
-Tools for loading and returning ASE calculator objects for use in simulations
-'''
-importimportlib
-importlogging
-fromtypingimportDict,Optional
-fromasimtools.utilsimportget_calc_input
-
-# pylint: disable=import-outside-toplevel
-# pylint: disable=import-error
-
-
[docs]defload_calc(
- calc_id:str=None,
- calc_input:Optional[Dict]=None
-):
-"""Loads a calculator using given calc_id or calc_input
-
- :param calc_id: ID/key to use to load calculator from the supplied/global\
- calc_input file, defaults to None
- :type calc_id: str, optional
- :param calc_input: calc_input dictionary for a single calculator\
- , defaults to None
- :type calc_input: Optional[Dict], optional
- :return: ASE calculator instance
- :rtype: :class:`ase.calculators.calculators.Calculator`
- """
- ifcalc_idisnotNone:
- ifcalc_inputisNone:
- calc_input=get_calc_input()
- try:
- calc_params=calc_input[calc_id]
- exceptKeyErrorasexc:
- msg=f'Calculator with calc_id: {calc_id} not found in'
- msg+=f'calc_input {calc_input}'
- raiseKeyError(msg)fromexc
- exceptAttributeErrorasexc:
- raiseAttributeError('No calc_input found')fromexc
- name=calc_params.get('name',None)
-
- if'module'incalc_params:
- loader=load_ase_calc
- else:
- try:
- loader=external_calcs[name]
- exceptKeyErrorasexc:
- msg='Provide ASE module for calc or use'
- msg+=f' one of {external_calcs.keys()}'
- raiseKeyError(msg)fromexc
-
- calc=loader(calc_params=calc_params)
- label=calc_params.get('label',name)
- calc.label=label
- logging.debug('Loaded calculator %s',calc_id)
- returncalc
-
-
-
[docs]defload_nequip(calc_params):
-"""Load NequIP or Allegro calculator
-
- :param calc_params: args to pass to loader
- :type calc_params: Dict
- :return: NequIP ase calculator
- :rtype: :class:`nequip.ase.nequip_calculator.NequIPCalculator`
- """
- fromnequip.ase.nequip_calculatorimportNequIPCalculator
- ifcalc_params.get('float64',False):
- importtorch
- torch.set_default_dtype(torch.float64)
- try:
- calc=NequIPCalculator.from_deployed_model(**calc_params.get('args',{}))
- exceptExceptionasexc:
- msg=f"Failed to load NequIP with parameters:\n{calc_params}"
- raiseRuntimeError(msg)fromexc
-
- returncalc
-
-
-
[docs]defload_dp(calc_params):
-"""Load Deep Potential Calculator
-
- :param calc_params: args to pass to loader
- :type calc_params: Dict
- :return: DP calculator
- :rtype: :class:`deepmd.calculator.DP`
- """
- fromdeepmd.calculatorimportDP
-
- try:
- calc=DP(**calc_params['args'])
- exceptException:
- print(f"Failed to load DP with parameters:\n{calc_params}")
- raise
-
- returncalc
[docs]defmkworkdir(self)->None:
-''' Creates the work directory if it doesn't exist '''
- ifnotself.workdir.exists():
- self.workdir.mkdir()
-
-
[docs]defupdate_status(self,status:str)->None:
-''' Updates job status to specificied value '''
- self.update_output({'status':status})
-
-
[docs]defstart(self)->None:
-''' Updates the output to signal that the job was started '''
- self.update_output({
- 'start_time':datetime.now().strftime('%H:%M:%S, %m/%d/%y')
- })
- self.update_status('started')
-
-
[docs]defcomplete(self)->None:
-''' Updates the output to signal that the job was started '''
- self.update_output({
- 'end_time':datetime.now().strftime('%H:%M:%S, %m/%d/%y')
- })
- self.update_status('complete')
-
-
[docs]deffail(self)->None:
-''' Updates status to failed '''
- self.update_status('failed')
-
-
[docs]defdiscard(self)->None:
-''' Updates status to discarded '''
- self.update_status('discard')
-
-
[docs]defgo_to_workdir(self)->None:
-''' Go to workdir '''
- ifnotself.workdir.exists():
- self.mkworkdir()
- os.chdir(self.workdir)
-
-
[docs]defleave_workdir(self)->None:
-''' goes to directory from which job was launched '''
- os.chdir(self.launchdir)
-
-
[docs]defadd_output_files(self,file_dict:Dict)->None:
-''' Adds a file to the output file list '''
- files=self.get_output().get('files',{})
- files.update(file_dict)
- self.update_output({'files':file_dict})
-
-
[docs]defget_sim_input(self)->Dict:
-''' Get simulation input '''
- returndeepcopy(self.sim_input)
-
-
[docs]defget_calc_input(self)->Dict:
-''' Get calculator input '''
- returndeepcopy(self.calc_input)
-
-
[docs]defget_env_input(self)->Dict:
-''' Get environment input '''
- returndeepcopy(self.env_input)
-
-
[docs]defget_output_yaml(self)->Dict:
-''' Get current output file '''
- prefix=''
- out_fname=join_names([prefix,'output.yaml'])
- output_yaml=self.workdir/out_fname
- returnoutput_yaml
-
-
[docs]defget_workdir(self)->Path:
-''' Get working directory '''
- returnself.workdir
-
-
[docs]defget_output(self)->Dict:
-''' Get values in output.yaml '''
- output_yaml=self.get_output_yaml()
- ifoutput_yaml.exists():
- returnread_yaml(output_yaml)
- else:
- return{}
[docs]defupdate_output(self,output_update:Dict)->None:
-''' Update output.yaml if it exists or write a new one '''
- output=self.get_output()
- output.update(output_update)
- write_yaml(self.get_output_yaml(),output)
-
-
[docs]defget_logger(self,logfilename='job.log',level='info'):
-''' Get the logger '''
- assertself.workdir.exists(),'Work directory does not exist yet'
- logger=get_logger(logfile=self.workdir/logfilename,level=level)
- returnlogger
-
-
[docs]classUnitJob(Job):
-'''
- Unit job object with ability to submit a slurm/interactive job.
- Unit jobs run in a specific environment and if required, run a
- specific calculator. More complex workflows are built up of unit
- jobs
- '''
- def__init__(
- self,
- sim_input:Dict,
- env_input:Union[Dict,None]=None,
- calc_input:Union[Dict,None]=None,
- )->None:
- super().__init__(sim_input,env_input,calc_input)
- self.env_id=self.sim_input.get('env_id',None)
- ifself.env_idisnotNone:
- self.env=self.env_input[self.env_id]
- else:
- self.env={'mode':{
- 'use_slurm':False,
- 'interactive':True,
- }
- }
-
- # Check if the script being called uses a calc_id to
- # get precommands, postcommands, run_prefixes and run_suffixes
- self.calc_id=self.sim_input.get('args',{}).get('calc_id',None)
- ifself.calc_idisnotNone:
- self.calc_params=self.calc_input[self.calc_id]
- else:
- self.calc_params={}
-
-
[docs]defgen_run_command(self)->str:
-'''
- Generates the command to run the job, independent of slurm
- '''
- script=self.sim_input.get('script',False)
- assertscript,'Specify a script in sim_input'
-
- mode_params=self.env.get('mode',{
- 'use_slurm':False,'interactive':True
- })
- env_run_prefix=mode_params.get('run_prefix','')
- env_run_suffix=mode_params.get('run_suffix','')
-
- calc_run_prefix=self.calc_params.get('run_prefix','')
- calc_run_suffix=self.calc_params.get('run_suffix','')
-
- ifself.sim_input.get('debug',False):
- debug_flag=' -d'
- else:
- debug_flag=''
-
- txt=f'{env_run_prefix}{calc_run_prefix} '
- txt+='asim-run sim_input.yaml -c calc_input.yaml'+debug_flag
- txt+=f' {env_run_suffix}{calc_run_suffix} '
- returntxt
-
- def_gen_slurm_script(self,write:bool=True)->None:
-'''
- Generates a slurm job file and if necessary writes it in
- the work directory for the job
- '''
- slurm_params=self.env.get('slurm',{})
- calc_params=self.calc_params
-
- txt='#!/usr/bin/sh\n'
- forflaginslurm_params.get('flags'):
- txt+=f'#SBATCH {flag}\n'
- txt+='\n'
- forcommandinslurm_params.get('precommands',[]):
- txt+=command+'\n'
- forcommandincalc_params.get('precommands',[]):
- txt+=command+'\n'
- txt+='\n'
- txt+='echo "Job started on `hostname` at `date`"\n'
- txt+=self.gen_run_command()+'\n'
- forcommandinslurm_params.get('postcommands',[]):
- txt+=command+'\n'
- forcommandincalc_params.get('postcommands',[]):
- txt+=command+'\n'
- txt+='echo "Job ended at `date`"'
-
- ifwrite:
- slurm_file=self.workdir/'job.sh'
- slurm_file.write_text(txt)
-
- def_gen_slurm_interactive_txt(self)->str:
-'''
- Generates an srun command to run the job
- '''
- slurm_params=self.env.get('slurm',False)
-
- txt='salloc --unbuffered '# unbuffered to avoid IO lag
- txt+=' '.join(slurm_params.get('flags'))
- txt+=self.gen_run_command()
-
- returntxt
-
-
[docs]defgen_input_files(self)->None:
-''' Write input files to working directory '''
- workdir=self.workdir
- sim_input=deepcopy(self.sim_input)
- # The sim_input file will already be in the work directory
- sim_input['workdir']='.'
- # Collect useful variables
- mode_params=self.env.get('mode',{})
- use_slurm=mode_params.get('use_slurm',False)
- interactive=mode_params.get('interactive',True)
- overwrite=self.sim_input.get('overwrite',False)
- output_file=workdir/'output.yaml'
- sim_input_file=workdir/'sim_input.yaml'
-
- # Check if the job already exists or not and if to overwrite
- ifnotworkdir.exists():
- workdir.mkdir()
- elifoutput_file.exists()andsim_input_file.exists():
- complete=read_yaml(output_file).get('start_time',False)
- ifcompleteandnotoverwrite:
- txt=f'Skipped writing in {self.workdir}, files already '
- txt+='written. Set overwrite=True to overwrite'
- self.get_logger().warning(txt)
- returnNone
-
- # If the sim_input uses an image/images, we want to write it in
- # the workdir and point to it using a filename. This is so that
- # there is a record of the input image for debugging and the input
- # method is consistent with complex workflows
- image=self.sim_input.get('args',{}).get('image',False)
-
- ifimage:
- atoms=get_atoms(**image)
- input_image_file=self.workdir.resolve()/'input_image.xyz'
- atoms.write(input_image_file,format='extxyz')
- self.sim_input['args']['image']={
- 'image_file':str(input_image_file),
- }
-
- images=self.sim_input.get('args',{}).get('images',False)
- ifimages:
- ifimages.get('images',False):
- images=get_images(**images)
- input_images_file=self.workdir/'input_images.xyz'
- ase.io.write(input_images_file,images,format='extxyz')
- self.sim_input['args']['images']={
- 'image_file':str(input_images_file),
- }
- elifimages.get('image_file',False):
- input_images_file=Path(images['image_file']).resolve()
- self.sim_input['args']['images']={
- 'image_file':str(input_images_file),
- }
-
- write_yaml(workdir/'sim_input.yaml',self.sim_input)
- write_yaml(workdir/'calc_input.yaml',self.calc_input)
- write_yaml(workdir/'env_input.yaml',self.env_input)
- write_yaml(self.get_output_yaml(),{'status':'clean'})
-
- ifuse_slurmandnotinteractive:
- self._gen_slurm_script()
- returnNone
[docs]classDistributedJob(Job):
-''' Array job object with ability to submit simultaneous jobs '''
- def__init__(
- self,
- sim_input:Dict,
- env_input:Union[None,Dict]=None,
- calc_input:Union[None,Dict]=None,
- )->None:
- super().__init__(sim_input,env_input,calc_input)
- # Set a standard for all subdirectories to start
- # with "id-{sim_id}" followed by user labels
- new_sim_input={}
- num_digits=len(str(len(sim_input)))
- sim_id_changed=False
- fori,(sim_id,subsim_input)inenumerate(sim_input.items()):
- assert'script'insubsim_input,'Check sim_input format,\
- must have script and each job with a unique key'
-
- # We set a fixed number of digits so that the slurm array ID
- # matches the directory name for easy resubmission of arrays
- prefix='id-'+f'{i}'.rjust(num_digits,'0')
- ifnotsim_id.startswith(prefix):
- sim_id_changed=True
- new_sim_id=join_names([prefix,sim_id])
- new_sim_input[new_sim_id]=deepcopy(sim_input[sim_id])
-
- ifsim_id_changed:
- sim_input=new_sim_input
- unitjobs=[]
- forsim_id,subsim_inputinsim_input.items():
- assert'script'insubsim_input,'Check sim_input format,\
- must have script and each job with a unique key'
-
- subsim_input['workdir']=sim_id
- unitjob=UnitJob(subsim_input,env_input,calc_input)
- unitjobs.append(unitjob)
-
- # If all the jobs have the same config and use slurm, use a job array
- env_id=unitjobs[0].env_id
- same_env=np.all(
- [(uj.env_id==env_id)forujinunitjobs]
- )
-
- all_slurm=np.all(
- [uj.env['mode'].get('use_slurm',False)forujinunitjobs]
- )
-
- ifsame_envandall_slurm:
- self.use_array=True
- else:
- self.use_array=False
-
- self.unitjobs=unitjobs
-
-
[docs]defsubmit_jobs(
- self,
- **kwargs,# Necessary for compatibility with job.submit
- )->Union[None,List[str]]:
-'''
- Submits the jobs. If submitting lots of batch jobs, we
- recommend using DistributedJob.submit_array
- '''
- # It is possible to do an implementation where we limit
- # the number of simultaneous jobs like an array using job
- # dependencies but that can be implemented later
- job_ids=[]
- forunitjobinself.unitjobs:
- job_id=unitjob.submit()
- job_ids.append(job_id)
- returnjob_ids
-
-
[docs]defsubmit_array(
- self,
- array_max=None,
- dependency:Union[List[str],None]=None,
- **kwargs,# Necessary for compatibility with job.submit
- )->Union[None,List[str]]:
-'''
- Submits a job array if all the jobs have the same env and use slurm
- '''
- self.gen_input_files()
- logger=self.get_logger()
-
- njobs=len(self.unitjobs)
-
- # For limiting number of jobs launched in array
- ifarray_maxisnotNone:
- arr_max_str=f'%{array_max}'
- else:
- arr_max=self.unitjobs[0].env['mode'].get('array_max',False)
- ifarr_max:
- arr_max_str=f'%{arr_max}'
- else:
- arr_max_str=''
-
- ifdependencyisnotNone:
- dependstr=None
- fordepindependency:
- ifdependstrisNone:
- dependstr=str(dep)ifdepisnotNoneelseNone
- else:
- dependstr+=f':{dep}'ifdepisnotNoneelse''
-
- command=[
- 'sbatch',
- f'--array=[0-{njobs-1}]{arr_max_str}',
- '-d',f'afterok:{dependstr}',
- 'job_array.sh'
- ]
- else:
- command=[
- 'sbatch',
- f'--array=[0-{njobs-1}]{arr_max_str}',
- 'job_array.sh'
- ]
-
- completed_process=subprocess.run(
- command,check=False,capture_output=True,text=True,
- )
-
- withopen('stdout.txt','w',encoding='utf-8')asoutput_file:
- output_file.write(completed_process.stdout)
-
- # if completed_process.returncode != 0:
- # err_txt = 'ERROR: Failed to run array in '
- # err_txt += f'{self.workdir} with command:\n'
- # err_txt += f'{" ".join(command)}\n'
- # err_txt += f'See {self.workdir / "stderr.txt"} for details.'
- # print(err_txt)
- # with open('stderr.txt', 'w', encoding='utf-8') as err_file:
- # err_file.write(completed_process.stderr)
- # completed_process.check_returncode()
-
- ifcompleted_process.returncode!=0:
- err_msg=f'See {self.workdir/"stderr.txt"} for traceback.'
- logger.error(err_msg)
- withopen('stderr.txt','w',encoding='utf-8')aserr_file:
- err_file.write(completed_process.stderr)
- completed_process.check_returncode()
-
- job_ids=[int(completed_process.stdout.split(' ')[-1])]
- returnjob_ids
-
- def_gen_array_script(self,write:bool=True)->None:
-'''
- Generates a slurm job array file and if necessary
- writes it in the work directory for the job. Only works
- if there is one config_id for all jobs
- '''
- env_id=self.unitjobs[0].env_id
- env=self.env_input[env_id]
-
- slurm_params=env.get('slurm',{})
-
- txt='#!/usr/bin/sh\n'
- forflaginslurm_params.get('flags'):
- txt+=f'#SBATCH {flag}\n'
-
- txt+='if [[ ! -z ${SLURM_ARRAY_TASK_ID} ]]; then\n'
- txt+=' fls=( id-* )\n'
- txt+=' WORKDIR=${fls[${SLURM_ARRAY_TASK_ID}]}\n'
- txt+='fi\n\n'
- txt+='CUR_DIR=`pwd`\n'
- txt+='cd ${WORKDIR}\n'
- txt+='\n'
- txt+='\n'.join(slurm_params.get('precommands',[]))
- txt+='\n'
- txt+='\n'.join(self.unitjobs[0].calc_params.get('precommands',[]))
- txt+='\n'
- txt+='echo "LAUNCHDIR: ${CUR_DIR}"\n'
- txt+='echo "WORKDIR: ${WORKDIR}"\n'
- txt+='echo "Job started on `hostname` at `date`"\n'
- txt+=self.unitjobs[0].gen_run_command()+'\n'
- txt+='\n'.join(slurm_params.get('postcommands',[]))
- txt+='\n'
- txt+='cd ${CUR_DIR}\n'
- txt+='echo "Job ended at `date`"'
-
- ifwrite:
- slurm_file=self.workdir/'job_array.sh'
- slurm_file.write_text(txt)
-
-
[docs]defgen_input_files(self)->None:
-''' Write input files to working directory '''
-
- ifself.use_array:
- self._gen_array_script()
- forunitjobinself.unitjobs:
- unitjob.gen_input_files()
-
-
[docs]defsubmit(self,**kwargs)->None:
-'''
- Submit a job using slurm, interactively or in the terminal
- '''
-
- cur_dir=Path('.').resolve()
- os.chdir(self.workdir)
- job_ids=None
- ifself.use_array:
- job_ids=self.submit_array(**kwargs)
- else:
- job_ids=self.submit_jobs(**kwargs)
- self.update_output({'job_ids':job_ids})# For chained job
- os.chdir(cur_dir)
- returnjob_ids
-
-
[docs]classChainedJob(Job):
-'''
- Jobs made of smaller sequential unitjobs. Note that this only works
- well with unit jobs. If one of the UnitJobs calls scripts, internally,
- slurm will fail to build the correct dependencies but the files will be
- generated appropriately, you can submit them manually
- '''
- def__init__(
- self,
- sim_input:Dict,
- env_input:Union[None,Dict]=None,
- calc_input:Union[None,Dict]=None,
- )->None:
- super().__init__(sim_input,env_input,calc_input)
-
- forkeyinsim_input:
- assertkey.startswith('step-'), \
- f'Keys take the form "step-[step_id]" from id=0 not "{key}"'
-
- # Each key in sim_input should be in the form "step-id" where id
- # is replaced by the order in which the commands are run
- unitjobs=[]
- foriinrange(len(sim_input)):
- step_id=f'step-{i}'
- subsim_input=deepcopy(sim_input[step_id])
- unitjob=UnitJob(subsim_input,env_input,calc_input)
- unitjob.set_workdir(step_id)
- unitjobs.append(unitjob)
-
- self.unitjobs=unitjobs
-
-
[docs]defget_last_output(self)->Dict:
-''' Returns the output of the last job in the chain '''
- returnself.unitjobs[-1].get_output()
-
-
[docs]defsubmit(self,dependency:Union[List,None]=None)->List:
-'''
- Submit a job using slurm, interactively or in the terminal
- '''
-
- cur_dir=Path('.').resolve()
- os.chdir(self.workdir)
- logger=self.get_logger()
- step=0#self.get_current_step() TODO: This feature is not used yet
- are_interactive_jobs=[
- uj.env['mode'].get('interactive',False) \
- forujinself.unitjobs
- ]
- all_interactive=np.all(are_interactive_jobs)
- all_not_interactive=np.sum(are_interactive_jobs)==0
- assertall_interactiveorall_not_interactive, \
- 'Jobs in chain must all be interactive=True or interactive=False'
-
- are_using_slurm=[
- uj.env['mode'].get('use_slurm',False) \
- forujinself.unitjobs
- ]
- all_slurm=np.all(are_using_slurm)
- all_not_slurm=np.sum(are_using_slurm)==0
-
- assertall_slurmorall_not_slurm, \
- 'Jobs in chain must all have use_slurm=True or use_slurm=False'
-
- # Only use slurm dependencies if all the jobs are batch jobs
- ifall_slurmandall_not_interactive:
- ifstep!=len(self.unitjobs):
- dependency=None
- fori,unitjobinenumerate(self.unitjobs[step:]):
- cur_step_complete,status=unitjob.get_status()
- ifnotcur_step_complete:
- unitjob.env['slurm']['flags'].append(f'-J step-{step+i}')
- # Get latest job_id if previous step output was updated with new IDs
- # This should allow scripts that run scripts to use correct dependencies
- # print(f'Job id for step-{i} is {dependency}')
- # if i > 0:
- # dependency = self.unitjobs[i-1].get_output().get('job_ids', dependency)
- # print(f'Dependency for step-{i} is {dependency}')
- # print('===================')
- dependency=unitjob.submit(dependency=dependency)
- else:
- txt=f'Skipping step-{step+i} since '
- txt+=f'status is {status}'
- logger.warning(txt)
-
- job_ids=dependency
-
- # Otherwise just submit them one after the other
- else:
- forunitjobinself.unitjobs[step:]:
- job_ids=unitjob.submit()
-
- os.chdir(cur_dir)
-
- returnjob_ids
-
-
-
[docs]defload_job_from_directory(workdir:str):
-''' Loads a job from a given directory '''
- workdir=Path(workdir)
- assertworkdir.exists(),f'Work director {workdir} does not exist'
- logger=get_logger()
- sim_inputs=glob(str(workdir/'sim_input.yaml'))
- iflen(sim_inputs)!=1:
- logger('Multiple or no sim_input.yaml files in %s',{workdir})
- try:
- sim_input=read_yaml(glob(str(workdir/'sim_input.yaml'))[0])
- except:
- logger('sim_input.yaml not found in %s',{workdir})
- raise
-
- env_inputs=glob(str(workdir/'env_input.yaml'))
- iflen(env_inputs)==1:
- env_input=read_yaml(env_inputs[0])
- else:
- env_input=None
-
- calc_inputs=glob(str(workdir/'calc_input.yaml'))
- iflen(calc_inputs)==1:
- calc_input=read_yaml(calc_inputs[0])
- else:
- calc_input=None
-
- job=Job(sim_input,env_input,calc_input)
- returnjob
-#!/usr/bin/env python
-'''
-Recursively check progress of jobs starting from a specified sim_input.yaml
-and pring out the progress
-'''
-importsys
-frompathlibimportPath
-importargparse
-fromtypingimportDict,Tuple
-fromcoloramaimportFore
-fromasimtools.utilsimportread_yaml
-fromasimtools.jobimportload_job_from_directory
-
-
-
-#!/usr/bin/env python
-'''
-Execute a workflow given the sim_input.yaml and optionally,
-a calc_input.yaml and/or env_input.yaml. The called script will be run
-in the specified workdir and env_id
-
-Author: mkphuthi@github.com
-'''
-
-importsys
-importargparse
-fromtypingimportDict,Tuple
-fromasimtools.utilsimportread_yaml
-fromasimtools.jobimportUnitJob
-
-
-
[docs]defmain(args=None)->None:
-"""Execute a workflow given the sim_input.yaml and optinally,
- a calc_input.yaml and/or env_input.yaml. The called script will be run
- in the specified workdir and env_id """
- sim_input,env_input,calc_input=parse_command_line(args)
- job=UnitJob(
- sim_input=sim_input,
- env_input=env_input,
- calc_input=calc_input
- )
- job.gen_input_files()
- job.go_to_workdir()
- try:
- job.submit()
- except:
- job.fail()
- raise
- job.leave_workdir()
-#!/usr/bin/env python
-'''
-Execute a script given the sim_input.yaml and optionally,
-a calc_input.yaml. The called script will be run directly in the current
-directory and environment
-'''
-
-importimportlib
-importsys
-importos
-frompathlibimportPath
-importargparse
-importsubprocess
-fromtypingimportDict,Tuple
-fromasimtools.utilsimportread_yaml,get_logger
-fromasimtools.jobimportload_job_from_directory
-
-
-
-#!/usr/bin/env python
-'''
-Submits a chain of scripts in the order specified by steps
-in input
-
-Author: mkphuthi@github.com
-
-'''
-
-fromtypingimportDict,Optional
-fromasimtools.jobimportChainedJob
-
-
-
[docs]defchained(
- steps:Dict,
- env_input:Optional[Dict]=None,
- calc_input:Optional[Dict]=None,
-)->Dict:
-"""Run a workflow using the provided sim_input.yaml one after the other,
- The jobs will run one after the other, if slurm is used, job dependencies
- will be used. Note that if one of the subscripts internally launches another
- script e.g. image_array, calc_array etc, slurm job dependencies will not
- work as expected. In those cases, we recommend running the steps one by one
- or interactively
-
-
- :param steps: Dictionary where each key is an ID and the value is a \
- standard sim_input
- :type steps: Dict
- :param env_input: env_input that overrides global file, defaults to None
- :type env_input: Optional[Dict], optional
- :param calc_input: calc_input that overrides global file, defaults to None
- :type calc_input: Optional[Dict], optional
- :return: Dictionary of results
- :rtype: Dict
- """
- cjob=ChainedJob(
- sim_input=steps,env_input=env_input,calc_input=calc_input
- )
- job_ids=cjob.submit()
-
- results=cjob.unitjobs[-1].get_output()
- results.update({'job_ids':job_ids})
- returnresults
-#!/usr/bin/env python
-'''
-Distributes a number of simulations at the same time if possible
-
-Author: mkphuthi@github.com
-
-'''
-
-fromtypingimportDict,Optional
-fromasimtools.jobimportDistributedJob
-
-
[docs]defdistributed(
- subscripts:Dict,
- env_input:Optional[Dict]=None,
- calc_input:Optional[Dict]=None,
- array_max:Optional[int]=None,
-)->Dict:
-"""Distributes a set of jobs based on inpout parameter. The scnarios are
- as follows:
- #. use_slurm: False, interactive: True -> Runs one after the other.
- #. use_slurm: True, interactive: False, same env_id -> Launches a job \
- # array.
- #. use_slurm: False, interactive: False, different env_ids -> Launches \
- # multiple jobs.
-
-
- :param subscripts: Dictionary of scripts, each key is an ID and each \
- value is a sim_input file
- :type subscripts: Dict
- :param env_input: env_input that overrides global file, defaults to None
- :type env_input: Optional[Dict], optional
- :param calc_input: calc_input that overrides global file, defaults to None
- :type calc_input: Optional[Dict], optional
- :param array_max: Maximum number of jobs to run in array, defaults to None
- :type array_max: Optional[int], optional
- :return: Dictionary of results
- :rtype: Dict
- """
- djob=DistributedJob(
- sim_input=subscripts,
- env_input=env_input,
- calc_input=calc_input
- )
- job_ids=djob.submit(array_max=array_max)
-
- results={'job_ids':job_ids}
- returnresults
-#!/usr/bin/env python
-'''
-Script for unit tests and debugging, does nothing for specified duration
-'''
-fromtimeimportsleep
-fromtypingimportDict,Optional
-
-
[docs]defdo_nothing(duration:Optional[int]=5)->Dict:
-"""Sleep for the specified duration
-
- :param duration: time in seconds, defaults to 60
- :type duration: int, optional
- :return: Dictionary with duration slept for
- :rtype: Dict
- """
- sleep(duration)
- results={'duration':duration}
- returnresults
-#!/usr/bin/env python
-'''
-Apply the same script on multiple images
-
-Author: mkphuthi@github.com
-
-'''
-
-fromtypingimportDict,Sequence,Optional
-fromcopyimportdeepcopy
-fromasimtools.jobimportDistributedJob
-fromasimtools.utilsimportget_images
-
-
[docs]defimage_array(
- images:Dict,
- subscript_input:Dict,
- calc_input:Optional[Dict]=None,
- env_input:Optional[Dict]=None,
- ids:Sequence[str]=None,
- env_ids:Sequence[str]=None,
- array_max:Optional[int]=None,
-)->Dict:
-"""Submit the same script on multiple images and if specified, use
- different env_ids
-
- :param images: Image config, see :func:`asimtools.utils.get_atoms`
- :type images: Dict
- :param subscript_input: sim_input of script to be run
- :type subscript_input: Dict
- :param calc_input: calc_input to override global file, defaults to None
- :type calc_input: Optional[Dict], optional
- :param env_input: env_input to override global file, defaults to None
- :type env_input: Optional[Dict], optional
- :param ids: Custom ids for each image, defaults to None
- :type ids: Sequence[str], optional
- :param env_ids: Sequence of envs for each image, must be the same length \
- as the total number of images, defaults to None
- :type env_ids: Sequence[str], optional
- :param array_max: Maximum jobs to run simultanteously in job array, \
- defaults to None
- :type array_max: Optional[int], optional
- :return: Dictionary of results
- :rtype: Dict
- """
- images=get_images(**images)
- array_sim_input={}
-
- # Allow user to customize subdirectory names if needed
- ifidsisNone:
- ids=[str(i)foriinrange(len(images))]
- else:
- assertlen(ids)==len(images), \
- 'Num. of images must match num. of ids'
-
- ifenv_idsisnotNone:
- assertlen(env_ids)==len(images), \
- f'Num. images ({len(images)}) must match env_ids ({len(env_ids)})'
-
- # Make individual sim_inputs for each image
- fori,imageinenumerate(images):
- new_subscript_input=deepcopy(subscript_input)
- new_subscript_input['args']['image']={
- 'atoms':image
- }
- array_sim_input[f'{ids[i]}']=new_subscript_input
-
- ifenv_idsisnotNone:
- new_subscript_input['env_id']=env_ids[i]
-
- # Create a distributed job object
- djob=DistributedJob(array_sim_input,env_input,calc_input)
- job_ids=djob.submit(array_max=array_max)
-
- results={'job_ids':job_ids}
- returnresults
-#!/usr/bin/env python
-'''
-Generates a parity plot and collects evaluation statistics comparing energy
-and/or forces and/or stress to existing values in the provided dataset. This
-script can work in parallel based on the number of cores specified.
-
-Author: mkphuthi@github.com
-
-'''
-fromtypingimportDict,List,TypeVar,Sequence
-fromfunctoolsimportpartial
-frommultiprocessingimportPool
-importnumpyasnp
-importmatplotlib.pyplotasplt
-fromasimtools.calculatorsimportload_calc
-fromasimtools.utilsimport(
- write_csv_from_dict,
- get_images,
- parse_slice,
- get_axis_lims,
-)
-
-Calculator=TypeVar('Calculator')
-
[docs]defcalc_parity_data(
- subset:List,
- calc_id:str,
- properties:Sequence=('energy','forces','stress'),
- force_prob:float=1.0,
-)->Dict:
-"""Calculates parity data for each atoms instance in subset
-
- :param subset: List of atoms instances
- :type subset: List
- :param calc: ASE Cailculator instance
- :type calc: Calculator
- :param properties: Properties to evaluate, choose from "energy", \
- "forces" and "stress", defaults to ('energy', 'forces', 'stress')
- :type properties: List, optional
- :param force_prob: Fraction of forces to consider, may speed up sampling \
- large structures by subsampling forces randomly, defaults to 1.0
- :type force_prob: float, optional
- :return: Dictionary with reference and predicted values for each \
- property
- :rtype: Dict
- """
-
- res={prop:[]forpropinproperties}
- ervals=[]
- epvals=[]
- frvals=[]
- fpvals=[]
- srvals=[]
- spvals=[]
- fori,atomsinenumerate(subset):
- calc=load_calc(calc_id)
- n_atoms=len(atoms)
- if'energy'inproperties:
- prop='energy'
- ervals=np.hstack(
- [ervals,atoms.get_potential_energy()/n_atoms]
- )
- epvals=np.hstack(
- [epvals,float(calc.get_potential_energy(atoms)/n_atoms)]
- )
-
- if'forces'inproperties:
- ifnp.random.rand()<force_prob:
- prop='forces'
- frvals=np.hstack(
- [frvals,np.array(atoms.get_forces()).flatten()]
- )
-
- fpvals=np.hstack(
- [fpvals,np.array(calc.get_forces(atoms)).flatten()]
- )
-
- if'stress'inproperties:
- prop='stress'
- srvals=np.hstack(
- [srvals,np.array(atoms.get_stress()).flatten()]
- )
-
- spvals=np.hstack(
- [spvals,np.array(calc.get_stress(atoms)).flatten()]
- )
- res[prop]={'ref':srvals,'pred':spvals}
-
- ifi%20==0:
- print(f'Progress {i}/{len(subset)}')
-
- res['energy']={'ref':ervals,'pred':epvals}
- res['forces']={'ref':frvals,'pred':fpvals}
- res['stress']={'ref':srvals,'pred':spvals}
- returnres
-
-def_split_data(data:Sequence,chunks:int)->List:
-"""Splits data into equal chunks and tosses the remainder
-
- :param data: Sequence of datapoints
- :type data: Sequence
- :param chunks: Number of chunks to split the data into
- :type nprocs: int
- :return: List of split datasets
- :rtype: List
- """
- subsets=[]
- subset_len=int(np.ceil(len(data)//chunks))
- forsubset_idinrange(chunks):
- start=subset_id*subset_len
- stop=(subset_id+1)*subset_len
- subsets.append(data[start:stop])
-
- returnsubsets
-
-
-#!/usr/bin/env python
-'''
-Runs the same script, iterating over multiple values of a specified argument
-based on a sim_input template provided by the user
-
-Author: mkphuthi@github.com
-
-'''
-
-fromtypingimportDict,Sequence,Optional,Union
-fromasimtools.jobimportDistributedJob
-fromasimtools.utilsimportchange_dict_value
-
-
[docs]defsim_array(
- template_sim_input:Dict,
- key_sequence:Optional[Sequence[str]]=None,
- array_values:Optional[Sequence]=None,
- env_ids:Optional[Union[Sequence[str],str]]=None,
- calc_input:Optional[Dict]=None,
- env_input:Optional[Dict]=None,
- ids:Sequence=None,
-)->Dict:
-"""Runs the same script, iterating over multiple values of a specified
- argument based on a sim_input template provided by the user
-
- :param template_sim_input: sim_input containing all the default parameters
- :type template_sim_input: Dict
- :param key_sequence: Sequence of keys to access value to be iterated over, defaults to None
- :type key_sequence: Optional[Sequence[str]], optional
- :param array_values: values to be iterated over in each simulation, defaults to None
- :type array_values: Optional[Sequence], optional
- :param env_ids: Environment(s) to be used for each simulation, must either be a list with as many env_ids as array values or a string with the env_id to be used by all simulations, defaults to None
- :type env_ids: Optional[Union[Sequence[str],str]], optional
- :param calc_input: calc_input file to use, defaults to None
- :type calc_input: Optional[Dict], optional
- :param env_input: env_input to use, defaults to None
- :type env_input: Optional[Dict], optional
- :param ids: Custom ids to use for each simulation, defaults to None
- :type ids: Sequence, optional
- :return: Results
- :rtype: Dict
- """
- ifidsisNone:
- ids=[f'{key_sequence[-1]}-{val}'forvalinarray_values]
-
- assertlen(ids)==len(array_values), \
- 'Num. of array_values must match num. of ids'
-
- ifenv_idsisNone:
- pass
- elifisinstance(env_ids,str):
- env_ids=[env_idsforiinrange(len(ids))]
- else:
- assertlen(env_ids)==len(ids)orisinstance(env_ids,str), \
- 'Provide one env_id or as many as there are array_values'
-
- # Create sim_inputs for each array value and to create input for
- # a DistributedJob object
- sim_inputs={}
- fori,valinenumerate(array_values):
- new_sim_input=change_dict_value(
- d=template_sim_input,
- new_value=val,
- key_sequence=key_sequence,
- return_copy=True,
- )
- ifenv_idsisnotNone:
- new_sim_input['env_id']=env_ids[i]
- sim_inputs[ids[i]]=new_sim_input
-
- # Create a distributed job object
- djob=DistributedJob(sim_inputs,env_input,calc_input)
- job_ids=djob.submit()
-
- results={'job_ids':job_ids}
- returnresults
-#!/usr/bin/env python
-'''
-Describe the script briefly here. If this is a script that runs multiple steps,
-describe it here using reStructuredText to generate autodocs
-
-Cite the papers where the method/script was first introduced here as well
-
-Author: mkphuthi@github.com
-'''
-
-fromtypingimportDict
-# from asimtools.calculators import load_calc
-fromasimtools.utilsimport(
- get_atoms,
- # get_images,
-)
-
-
[docs]deftemplate(
- # calc_id: str,
- # image: Dict, # Optional: if using a structure
- # images: Dict, # Optional: if using multiple structures
-)->Dict:
-'''
- Script does xyz specifically
- '''
-
- # calc = load_calc(calc_id) # Optional: Any code that loads a calculator is replaced by this one line!
- # atoms = get_atoms(**image) # Optional
- # images = get_images(**images) # Optional
- # atoms.set_calculator(calc) # Optional
-
- #############################
- # Do some cool science here #
- #############################
-
- results={
- 'energy':'Placeholder_for_my_result',
- 'files':{'image':'placeholder_four_image_output'}
- }
- returnresults# Always return a dictionary! Use {} if necessary
[docs]defwrite_yaml(yaml_path:str,yaml_Dict:Dict)->None:
-"""Write a dictionary to a yaml file
-
- :param yaml_path: Path to write yaml to
- :type yaml_path: str
- :param yaml_Dict: Dictionary to write
- :type yaml_Dict: Dict
- """
- withopen(yaml_path,'w',encoding='utf-8')asf:
- yaml.dump(yaml_Dict,f)
-
-
[docs]defget_axis_lims(x:Sequence,y:Sequence,padding:float=0.1):
-"""Get an estimate of good limits for a plot axis"""
- data_min=np.min([x,y])
- data_max=np.max([x,y])
- diff=data_max-data_min
- lims=[data_min-padding*diff,data_max+padding*diff]
- returnlims
-
-
[docs]defwrite_csv_from_dict(
- fname:str,
- data:Dict,
- columns:Optional[Sequence]=None,
- header:str='',
- **kwargs
-)->pd.DataFrame:
-"""Write a tabulated csv to a file from a dictionary. The keys will
- become the columns and the values will be the columns, All columns used
- must have the same length. kwargs are passed to
- :func:`pandas.Dataframe.to_csv()`
-
- :param fname: File name to be return to
- :type fname: str
- :param data: Dictionary to write
- :type data: Dict
- :param columns: Keys to use as columns of csv, defaults to None
- :type columns: Iterable, optional
- :return: Pandas dataframe of results
- :rtype: pd.DataFrame
- """
- ifcolumnsisNone:
- columns=list(data.keys())
-
- csv_data=pd.DataFrame(data,columns=columns,**kwargs)
- withopen(fname,'w',encoding='utf-8')asf:
- f.write('#'+header+'\n')
-
- csv_data.to_csv(fname,index=False,header=True,mode='a')
- returncsv_data
-
-
[docs]defstrip_symbols(substr:str)->str:
-"""Helper function to format filenames using standard
-
- :param substr: substring
- :type substr: str
- :return: stripped string
- :rtype: str
- """
- bad_symbols=['_','-','.',' ']
- iflen(substr)==0:
- return''
- ifsubstr[0]inbad_symbolsorsubstr[-1]inbad_symbols:
- forbad_symbolinbad_symbols:
- substr=substr.strip(bad_symbol)
- returnstrip_symbols(substr)
- returnsubstr
[docs]defget_images(
- image_file:str=None,
- pattern:str=None,
- patterns:List[str]=None,
- images:Iterable[Atoms]=None,
- index:Union[str,int]=':',
- **kwargs
-)->List[Atoms]:
-"""Return a list of atoms objects based on the input arguments. Options \
- to specify are:
- #. image_file
- #. pattern
- #. images
-
- :param image_file: Path to ASE-readable file with one or more images, \
- defaults to None
- :type image_file: str, optional
- :param pattern: String pattern of paths from which to search for images, \
- defaults to None. This only gets one image from each file as in \
- :func:`ase.io.read` without specifying an index
- :type pattern: str, optional
- :param patterns: Sequence of string patterns/paths from which to search \
- for images, defaults to None. This only gets one image from each file \
- as in :func:`ase.io.read` without specifying an index
- :type pattern: str, optional
- :param images: A list of atoms objects, defaults to None
- :type images: Iterable[Atoms], optional
- :param index: Index to specify when using :func:`ase.io.read`, \
- defaults to ':'
- :type index: Union[str, int], optional
- :return: List of :class:`ase.Atoms`
- :rtype: List[Atoms]
- """
- assert(image_fileisnotNone)or \
- (patternisnotNone)or \
- (patternsisnotNone)or \
- (imagesisnotNone), \
- "Please specify file, pattern or iterable"
-
- ifimage_fileisnotNone:
- images=read(image_file,index=index,**kwargs)
- elifpatternisnotNone:
- image_files=glob(pattern)
- assertlen(image_files)>0, \
- f'No images matching pattern "{pattern}" from "{os.getcwd()}"'
-
- images=[]
- forimage_fileinimage_files:
- new_images=read(image_file,index=index,**kwargs)
- # Output of read can either be list of atoms or Atoms, depending on index
- ifnotisinstance(new_images,list):
- new_images=[new_images]
- images+=new_images
-
- elifpatternsisnotNone:
- images=[]
- forpatterninpatterns:
- image_files=glob(pattern)
- assertlen(image_files)>0, \
- f'No images matching patterns "{pattern}" from "{os.getcwd()}"'
- images+=get_images(pattern=pattern,index=index,**kwargs)
- elifimagesisnotNone:
- images=images[parse_slice(str(index))]
- else:
- images=[]
-
- assertlen(images)>0,'No images found'
-
- returnimages
-
-
[docs]defnew_db(dbname:str):
-"""Creates a new ASE database overwriting an old one
-
- :param dbname: Name for the new database
- :type dbname: str
- :return: Connection to database
- :rtype: :mod:`ase.db` connection
- """
- withopen(dbname,'w',encoding='utf-8')asf:
- f.write("")
- returnase.db.connect(dbname)
-
-
[docs]defget_env_input()->Dict:
-"""Gets the global env_input from the environment variable, then tries
- then ``.asimtools`` dotfile
-
- :return: env_input dictionary or empty dictionary if not found
- :rtype: Dict
- """
- env_input_file=os.getenv('ASIMTOOLS_ENV_INPUT')
- ifenv_input_fileisNone:
- dotfile=Path('~/.asimtools')
- ifdotfile.exists():
- withopen(dotfile,'r',encoding='utf-8')asf:
- lines=f.readlines()
- forlineinlines:
- ifline.startswith('ENV_INPUT_FILE'):
- env_input_file=Path(line.split('='))
- break
- ifenv_input_file.exists():
- try:
- env_input=read_yaml(env_input_file)
- returnenv_input
- exceptFileNotFoundError:
- print('WARNING: No env_input yaml found')
- else:
- env_input=read_yaml(env_input_file)
- returnenv_input
- return{}
-
-
[docs]defget_calc_input():
-"""Gets the global calc_input from the environment variable, then tries
- then ``.asimtools`` dotfile
-
- :return: calc_input dictionary or empty dictionary if not found
- :rtype: Dict
- """
- calc_input_file=os.getenv('ASIMTOOLS_CALC_INPUT')
- ifcalc_input_fileisNone:
- dotfile=Path('~/.asimtools')
- ifdotfile.exists():
- withopen(dotfile,'r',encoding='utf-8')asf:
- lines=f.readlines()
- forlineinlines:
- ifline.startswith('CALC_INPUT_FILE'):
- calc_input_file=Path(line.split('='))
- break
- ifcalc_input_file.exists():
- try:
- calc_input=read_yaml(calc_input_file)
- returncalc_input
- exceptFileNotFoundError:
- print('WARNING: No calc_input yaml found')
- else:
- calc_input=read_yaml(calc_input_file)
- returncalc_input
- return{}
-
-
[docs]defcheck_if_slurm_job_is_running(slurm_job_id:Union[str,int]):
-"""Checks if the slurm job with specifying job_id is running
-
- :param slurm_job_id: Job ID as str or int
- :type slurm_job_id: Union[str,int]
- :return: Whether job is running or not
- :rtype: bool
- """
- slurm_job_id=str(slurm_job_id)
- completed_process=subprocess.run(
- ['squeue','--job',slurm_job_id],
- check=False,
- capture_output=True,
- text=True,
- )
- stdout=completed_process.stdout
- ifstr(' '+slurm_job_id)instdout:
- returnTrue
- else:
- returnFalse
-
-
[docs]defchange_dict_value(
- d:Dict,
- new_value,
- key_sequence:Sequence,
- return_copy:bool=True
-)->Dict:
-"""Changes a value in the specified dictionary given by following the
- key sequence
-
- :param d: dictionary to be changed
- :type d: Dict
- :param new_value: The new value that will replace the old one
- :type new_value: _type_
- :param key_sequence: List of keys in the order in which they access the dictionary key
- :type key_sequence: Sequence
- :param return_copy: Whether to return a copy only or to modify the dictionary in-place as well, defaults to True
- :type return_copy: bool, optional
- :return: The changed dictionary
- :rtype: Dict
- """
- ifreturn_copy:
- d=deepcopy(d)
- iflen(key_sequence)==1:
- d[key_sequence[0]]=new_value
- returnd
- else:
- new_d=change_dict_value(
- d[key_sequence[0]],
- new_value,
- key_sequence[1:],
- return_copy=return_copy
- )
- d[key_sequence[0]]=new_d
- returnd
-
-
[docs]defget_logger(
- logfile='job.log',
- fstr='%(asctime)s |%(module)s|%(funcName)s| %(levelname)s: %(message)s',
- level='debug',
-):
-''' Get the logger '''
-
- level_dict={
- 'debug':logging.DEBUG,
- 'info':logging.INFO,
- 'warning':logging.WARNING,
- }
- assertlevelinlevel_dict,f'level must be one of {level_dict.keys()}'
-
- logging.basicConfig(
- filename=logfile,
- level=level_dict[level],
- format=fstr,
- )
- returnlogging.getLogger(__name__)
This section will guide you through taking your own in-house simulation and
-integrating it in to asimtools. The process is designed to be as
-straight-forward as reasonably possible.
-
As an example, we will ASIMplify the calculation of adsorption_energies as
-shown in ASE. To understand the code, visit the ASE tutorials page <https://wiki.fysik.dtu.dk/ase/tutorials/db/db.html>. Ultimately, the
-ASIMplified code will work with any element and , any calculator and any
-environment and be fully parallelized job submission in just a few steps!
-
Use toy example To make things easier, it is best to first replace the
-expensive parts of your workflow with toy examples e.g. use an empirical
-calculator like EAM instead of DFT, use a smaller/simpler structure, loop
-over fewer cases etc.
-
The ASE example already uses a simple EMT calculator and structure which is
-provided here for reference:
-
fromase.buildimportbulk
-fromase.calculators.emtimportEMT
-fromase.eosimportcalculate_eos
-fromase.dbimportconnect
-
-db=connect('bulk.db')
-forsymbin['Al','Ni','Cu','Pd','Ag','Pt','Au']:
- atoms=bulk(symb,'fcc')
- atoms.calc=EMT()
- eos=calculate_eos(atoms)
- v,e,B=eos.fit()# find minimum
- # Do one more calculation at the minimu and write to database:
- atoms.cell*=(v/atoms.get_volume())**(1/3)
- atoms.get_potential_energy()
- db.write(atoms,bm=B)
-
-
-
Wrap in a function The workhorse of ASIMTools is the function, any code
-wrapped in a function that returns a dictionary can be run within the
-ASIMTools framework. The easiest thing to do would be to take the code and
-copy and paste it in a function which is defined inside a script with the
-same name
-
fromase.buildimportbulk
-fromase.calculators.emtimportEMT
-fromase.eosimportcalculate_eos
-fromase.dbimportconnect
-
-defase_eos():
- db=connect('bulk.db')
- forsymbin['Al','Ni','Cu','Pd','Ag','Pt','Au']:
- atoms=bulk(symb,'fcc')
- atoms.calc=EMT()
- eos=calculate_eos(atoms)
- v,e,B=eos.fit()# find minimum
- # Do one more calculation at the minimu and write to database:
- atoms.cell*=(v/atoms.get_volume())**(1/3)
- atoms.get_potential_energy()
- db.write(atoms,bm=B)
-
- return{}
-
-
-
Immediately as it is, this script can be run in ASIMTools. You can run it with
-the following sim_input.yaml
Only a little bit more complicated than calling pythonase_eos.py
-This script however still depends on specific structures and a specific
-calculator. Let’s do the easy thing first, let’s make the script work with any
-calculator using a simple change.
-
fromase.buildimportbulk
-fromase.eosimportcalculate_eos
-fromase.dbimportconnect
-fromasimtools.calculatorsimportload_calc
-
-defase_eos(
- calc_id,
-):
- calc=load_calc(calc_id)
- db=connect('bulk.db')
- forsymbin['Al','Ni','Cu','Pd','Ag','Pt','Au']:
- atoms=bulk(symb,'fcc')
- atoms.calc=calc
- eos=calculate_eos(atoms)
- v,e,B=eos.fit()# find minimum
- # Do one more calculation at the minimu and write to database:
- atoms.cell*=(v/atoms.get_volume())**(1/3)
- atoms.get_potential_energy()
- db.write(atoms,bm=B)
-
- return{}
-
-
-
Just like that we can now run the script with any correctly configure
-calculator for the all the structures! We can even now run calc_array to
-iterate getting the results using different calculators.
-
The final change we will make is to parallelize over structures as below
-
fromase.buildimportbulk
-fromase.eosimportcalculate_eos
-fromase.dbimportconnect
-fromasimtools.calculatorsimportload_calc
-
-defase_eos(
- image,
- calc_id,
-):
- calc=load_calc(calc_id)
- db=connect('bulk.db')
- atoms=get_atoms(**image)
- atoms.calc=calc
- eos=calculate_eos(atoms)
- v,e,B=eos.fit()# find minimum
- # Do one more calculation at the minimu and write to database:
- atoms.cell*=(v/atoms.get_volume())**(1/3)
- atoms.get_potential_energy()
- db.write(atoms,bm=B)
-
- return{}
-
-
-
Easy-peasy. We now have a script that works with arbitrary environment,
-arbitrary calculator and arbitrary input structure (Of course the simulation
-will fail if we give a bad structure for example)
-
We can do some final cleanup of the script so that it sends outputs to
-output.yaml and logs some checkpoints. Additionally, any scripts added to
-the repository will need clear syntax highlighting and documentation.
-
fromtypingimportDict
-importlogging
-fromase.eosimportcalculate_eos
-fromase.dbimportconnect
-fromasimtools.calculatorsimportload_calc
-fromasimtools.utilsimportget_atoms
-
-defase_eos(
- image:Dict,
- calc_id:str,
- db_file:'bulk.db'
-)->Dict:
- calc=load_calc(calc_id)
- db=connect(db_file)
- atoms=get_atoms(**image)
- atoms.calc=calc
- eos=calculate_eos(atoms)
- v,e,B=eos.fit()# find minimum
- logging.info('Successfully fit EOS')
- # Do one more calculation at the minimu and write to database:
- atoms.cell*=(v/atoms.get_volume())**(1/3)
- atoms.get_potential_energy()
- db.write(atoms,bm=B)
-
- results={'v':float(v),'e':float(e),'B':float(B)}
- returnresults
-
-
-
To run this script on an arbitrary structure say Argon with say the
-LennardJones calculator, in a slurm job we can now use the following input
-files.
Going back to the original problem, we wanted to run the simulation of mulitple
-different elements with the EMT calculator. To achieve that in parallel, we can
-nest the ase_eos script in a asimtools.scripts.sim_array.sim_array() script as follows
You can then move the ase_eos.py script into a directory called ase_eos
-and place it in the script directory. This allows you to refer to scripts
-prepended with the script dir as below
Jobs made of smaller sequential unitjobs. Note that this only works
-well with unit jobs. If one of the UnitJobs calls scripts, internally,
-slurm will fail to build the correct dependencies but the files will be
-generated appropriately, you can submit them manually
Unit job object with ability to submit a slurm/interactive job.
-Unit jobs run in a specific environment and if required, run a
-specific calculator. More complex workflows are built up of unit
-jobs
Return an atoms object based on specified config. This is the
-recommended way to load atoms objects. There are three options to specify:
-#. image_file.
-#. builder, kwargs.
-#. atoms.
-
-
Parameters:
-
-
image_file (str, optional) – Path to an ASE-readable image file, defaults to None
-
builder (str, optional) – Builder to use from ase.build, defaults to ‘bulk’. Any extra keyword arguments specified are passed to the build
-
atoms (Atoms, optional) – ase.Atoms object, defaults to None
-
repeat (Tuple[int, int, int], optional) – Number of times to repeat input to create supercell, defaults to None
-
rattle_stdev (float, optional) – stdev to be provided to ase.Atoms.rattle(), defaults to None
Return a list of atoms objects based on the input arguments. Options to specify are:
-
image_file
-
pattern
-
images
-
-
-
-
-
Parameters:
-
-
image_file (str, optional) – Path to ASE-readable file with one or more images, defaults to None
-
pattern (str, optional) – String pattern of paths from which to search for images, defaults to None. This only gets one image from each file as in ase.io.read() without specifying an index
-
patterns – Sequence of string patterns/paths from which to search for images, defaults to None. This only gets one image from each file as in ase.io.read() without specifying an index
-
images (Iterable[Atoms], optional) – A list of atoms objects, defaults to None
-
index (Union[str, int], optional) – Index to specify when using ase.io.read(), defaults to ‘:’
Write a tabulated csv to a file from a dictionary. The keys will
-become the columns and the values will be the columns, All columns used
-must have the same length. kwargs are passed to
-pandas.Dataframe.to_csv()
Execute a workflow given the sim_input.yaml and optionally,
-a calc_input.yaml and/or env_input.yaml. The called script will be run
-in the specified workdir and env_id
Execute a workflow given the sim_input.yaml and optinally,
-a calc_input.yaml and/or env_input.yaml. The called script will be run
-in the specified workdir and env_id
Execute a script given the sim_input.yaml and optionally,
-a calc_input.yaml. The called script will be run directly in the current
-directory and environment
Run a workflow using the provided sim_input.yaml one after the other,
-The jobs will run one after the other, if slurm is used, job dependencies
-will be used. Note that if one of the subscripts internally launches another
-script e.g. image_array, calc_array etc, slurm job dependencies will not
-work as expected. In those cases, we recommend running the steps one by one
-or interactively
-
-
Parameters:
-
-
steps (Dict) – Dictionary where each key is an ID and the value is a standard sim_input
-
env_input (Optional[Dict], optional) – env_input that overrides global file, defaults to None
-
calc_input (Optional[Dict], optional) – calc_input that overrides global file, defaults to None
Distributes a set of jobs based on inpout parameter. The scnarios are
-as follows:
-#. use_slurm: False, interactive: True -> Runs one after the other.
-#. use_slurm: True, interactive: False, same env_id -> Launches a job # array.
-#. use_slurm: False, interactive: False, different env_ids -> Launches # multiple jobs.
-
-
Parameters:
-
-
subscripts (Dict) – Dictionary of scripts, each key is an ID and each value is a sim_input file
-
env_input (Optional[Dict], optional) – env_input that overrides global file, defaults to None
-
calc_input (Optional[Dict], optional) – calc_input that overrides global file, defaults to None
-
array_max (Optional[int], optional) – Maximum number of jobs to run in array, defaults to None
Generates a parity plot and collects evaluation statistics comparing energy
-and/or forces and/or stress to existing values in the provided dataset. This
-script can work in parallel based on the number of cores specified.
calc_id (str) – ID of calculator provided in calc_input or global file
-
force_prob (float, optional) – Fraction of forces to consider in force parity, can be used for speeding up large structures by only subsampling randomly, defaults to 1.0
-
nprocs (int, optional) – Number of process to parallelize over, must be less than number of datapoints, defaults to 1
-
unit (str, optional) – Unit to plot, choose from meV, eV or kcal/mol, defaults to ‘meV’
-
index (int, optional) – index of data to use from full dataset, defaults to ‘:’
-
properties (Sequence, optional) – Properties to evaluate, choose from “energy”, “forces” and “stress”, defaults to (‘energy’, ‘forces’, ‘stress’)
Runs the same script, iterating over multiple values of a specified
-argument based on a sim_input template provided by the user
-
-
Parameters:
-
-
template_sim_input (Dict) – sim_input containing all the default parameters
-
key_sequence (Optional[Sequence[str]], optional) – Sequence of keys to access value to be iterated over, defaults to None
-
array_values (Optional[Sequence], optional) – values to be iterated over in each simulation, defaults to None
-
env_ids (Optional[Union[Sequence[str],str]], optional) – Environment(s) to be used for each simulation, must either be a list with as many env_ids as array values or a string with the env_id to be used by all simulations, defaults to None
-
calc_input (Optional[Dict], optional) – calc_input file to use, defaults to None
-
env_input (Optional[Dict], optional) – env_input to use, defaults to None
-
ids (Sequence, optional) – Custom ids to use for each simulation, defaults to None
When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change.
-
Please note we have a code of conduct, please follow it in all your interactions with the project.
-
There are two main ways to contribute. One is to make changes to the existing
-codes and scripts. In this case, please make sure your change passes tests or
-submit a test accordinly. The second way to contribute is to add a new script
-to the core set of scripts. Reviewers will work with you to make sure your new
-script follows best practice including using utils, syntax highlighting, docs
-and tests.
Ensure any install or build dependencies are removed before the end of the layer when doing a build.
-
Update the README.md with details of changes to the interface, this includes new environment variables, exposed ports, useful file locations and container parameters.
-
Increase the version numbers in any examples files and the README.md to the new version that this Pull Request would represent. The versioning scheme we use is SemVer.
-
You may merge the Pull Request in once you have the sign-off of one other developer, or if you do not have permission to do that, you may request the other reviewer to merge it for you.
In the interest of fostering an open and welcoming environment, we as
-contributors and maintainers pledge to making participation in our project and
-our community a harassment-free experience for everyone, regardless of age, body
-size, disability, ethnicity, gender identity and expression, level of experience,
-nationality, personal appearance, race, religion, or sexual identity and
-orientation.
Project maintainers are responsible for clarifying the standards of acceptable
-behavior and are expected to take appropriate and fair corrective action in
-response to any instances of unacceptable behavior.
-
Project maintainers have the right and responsibility to remove, edit, or
-reject comments, commits, code, wiki edits, issues, and other contributions
-that are not aligned to this Code of Conduct, or to ban temporarily or
-permanently any contributor for other behaviors that they deem inappropriate,
-threatening, offensive, or harmful.
This Code of Conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community. Examples of
-representing a project or community include using an official project e-mail
-address, posting via an official social media account, or acting as an appointed
-representative at an online or offline event. Representation of a project may be
-further defined and clarified by project maintainers.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
-complaints will be reviewed and investigated and will result in a response that
-is deemed necessary and appropriate to the circumstances. The project team is
-obligated to maintain confidentiality with regard to the reporter of an incident.
-Further details of specific enforcement policies may be posted separately.
-
Project maintainers who do not follow or enforce the Code of Conduct in good
-faith may face temporary or permanent repercussions as determined by other
-members of the project’s leadership.
This package is a lightweight workflow and simulation manager for reproducible
-atomistic simulations that can be transferred across environments, calculators
-and structures. By using in-built or user-defined scripts and utilities, users
-can run/build their own simulation recipes and automagically scale them on
-slurm based clusters. The core idea is to separate the dependence of the
-atomistic potential/calculator and the simulations steps thereby allowing the
-same simulation to be run with multiple calculators and the same calculator to
-be used for multiple simulations. Input and output files must follow a strict
-format so that consistent analysis pipelines can be used across users
The goal of asimtools is to push all the complexity of workflow
-management, best-practices, file management etc. into the backend such that the
-everyday user only has to handle input files for existing workflows and script
-files for workflows they want to implement. The following are the guiding
-principles for how asimtools should work:
-
-
Scripts should resemble boilerplate ASE code as much as possible.
-
Scripts should not explicitly depend on a calculator
-
Scripts should not explicitly depend on the context in which they run
-
It should be easy to debug individual scripts/parts in large workflows. In
-addition, it should always be possible to debug/resubmit jobs without using
-asimtools.
-
input file structure and format should be standard across all scripts. In
-addition all input parameters should match how they would like without
-asimtools i.e. do not provide an API! This means extensive use of importlib.
-
output file structure should be predictable across all scripts
-
Job progress tracking must be incorporated
-
Best practices should be built-in e.g. if multiple jobs of the same slurm
-context are submitted simulataneously, it must be a job array
The philosophy is to build “simulations” using building blocks of scripts.
-These scripts can be as complicated/efficient as you make them using any
-external packages you want and can be optimized with time but can still be run
-within the framework. This allows a test friendly way to transition from say a
-tutorial on the ASE/pymatgen website to an asimtools script. So while
-complicated wrappers are discouraged, they would still work as long as the
-script works. The benefit out of the box is that you can make your script
-independent of calculator or input structures and submit them easily.
This installs the base package in developer mode so that you do not have to
-reinstall if you make changes to the core package.
-
Individual calculators may need external packages for loading those
-calculators. Similarly some scripts e.g. lammps.py might also need external packages to be used. It is up to the user to make sure those are installed.
-
You will also need to setup some environment variables, these variables point
-to a env_input.yaml and calc_input.yaml with your favorite configs since
-these are commonly shared among simulations. You can also directly specify them
-when running asim-execute (See asim-execute-h).
-Examples of these files can be found in the examples.
This section will guide you through running an already existing script whether
-it be one of the scripts provided in the main repository, from the script
-repository or a custom script you have written yourself.
-
To run a simulation, all you need to do is run either of the following
-commands:
In either case, providing calc_input.yaml or env_input.yaml is optional. If
-not provided, the globally configured files will be used. See env_input.yaml. For most
-cases, you will only ever use asim-execute. The differences between
-asim-execute and asim-run are explained in Usage of asim-execute and asim-run.
script: (str) name of core script or /path/to/my/script.py
-
env_id: (str, optional) Environment/context in which to run script
-configured in env_input.yaml, defaults to running in the current console
-
overwrite: (bool, optional) (bool) whether or not to overwrite work
-directories if they exist, defaults to false
-
submit: (bool, optional) whether or not to run the script or instead just
-write the files to run the script without running the script, defaults to true
-
workdir: (str, optional) The directory in which the script will be run,
-asim-execute will create the directory whereas asim-run ignores this
-parameter, defaults to ‘./’
-
precommands: (list, optional) a list of commands to run in the console
-before running the script, defaults to empty list
-
postcommands: (list, optional) a list of commands to run in the console
-after running the script, defaults to empty list
-
args: (dict) The arguments of the function being called in the script as
-key-value pairs. These are specific to the script being run.
-
-
All ASIMTools generated files are named sim_input.yaml but you can name
-user defined files as whatever you like
Additionally, one can provide an env_input.yaml file that details the kind of
-environments in which scripts can be run. This file can be provided with the
-asim-execute command using the -e flag or set globally. An example of an
-env_input.yaml file is given below
-
# template
-env_id:
-mode:
-use_slurm:true
-interactive:false
-run_prefix:...
-run_postfix:...
-slurm:
-flags:[flag1,flag2,...]
-precommands:[precommand1,precommand2,...]
-postcommands:[postcommand1,postcommand2,...]
-
-# Concrete examples below
-inline:# Run the script directly in the commandline
-mode:
-use_slurm:false
-interactive:true
-
-batch_job:# Submit a batch job using slurm with 2 tasks
-mode:
-use_slurm:true
-interactive:false
-slurm:
-flags:
---n 2
-precommands:
--source ~/.bashrc
--conda activate asimtools
-postcommands:
--conda deactivate asimtools
-
-interactive_job:# Submit an interactive job using slurm
-mode:
-use_slurm:true
-interactive:true
-slurm:
-flags:
---n 2
----gres:gpu=2
-precommands:
--module load lammps
-
-
-
The highest level key is the env_id which is specified in the
-sim_input.yaml. An env_input.yaml can have any number of env_id s. That
-way you can specify one global file if you use the same environments
-repeatedly. In particular, you can configure a global config file by setting
-the environment variable.
The parameters, required, shown in the template section are are described below
-
-
env_id: (str) unique key for identifying the environment, env_id in
-sim_input.yaml must match one of the env_id s defined in the provided
-env_input.yaml
-
env_id.mode.use_slurm: (bool) whether or not to request a slurm
-allocation to run the script
-
env_id.mode.interactive: (bool) whether or not to request a slurm
-allocation to run the script directly in the terminal (using salloc) or
-to submita batch job (using sbatch)
-
env_id.mode.run_prefix: (str) string to append before running the script
-e.g. if run_prefix=mpirun the script will be inkoked with the equivalent
-of mpirunpythonmy_script.py. run_prefix in env_input.yaml is
-always prepended before the one provided by calc_input.yaml.
-
env_id.mode.run_postfix: (str) string to append after running the script
-e.g. if run_postfix='&>out.txt' the script will be inkoked with the
-equivalent of pythonmy_script.py&>out.txt. run_postfix in
-env_input.yaml is always appended after the one provided by
-calc_input.yaml.
-
env_id.slurm.flags: (list, optional) The slurm flags for the allocation
-as a list of flags e.g. [-n4,-N1]
-
env_id.slurm.precommands: (list, optional) Commands to be run/added to
-the job script before running the script. A common use cas is loading a
-module or activating an environment
-
env_id.slurm.postcommands: (list, optional) Commands to be run/added to
-the job script after running the script.
or provided to asim-execute at run time. Note that if you launch a chained
-workflow with asim-run instead of asim-execute, scripts farther down
-the chain will use the global calc_input.yaml
-
# Template
-calc_id:
-name:...
-module:...
-precommands:[precommand1,...]
-postcommands:[postcommand1,...]
-run_prefix:...
-run_postfix:...
-args:
-arg1:value_1
-...
-
-# Concrete examples
-lj:
-name:LennardJones
-module:ase.calculators.lj
-args:
-sigma:3.54
-epsilon:0.00802236
-
-# GPAW needs a run_prefix to work in parallel using mpirun
-gpaw:
-name:GPAW
-module:gpaw.calculator
-run_prefix:mpirun
-args:
-kpts:[2,2,2]
-h:0.1
-xc:PBE
-txt:gpaw_output.txt
-
-
-
-
calc_id: (str) unique key for identifying the calculator, calc_id in
-sim_input.yaml must match one of the calc_id s defined in the
-provided calc_input.yaml
-
calc_id.name: (str) Either the name of the class or the reference to one
-of the provided BBBB external calculators.
-
calc_id.module: (str) The module from which the calculator class is
-imported. e.g. if name=LennardJones and module=ase.calculators.lj,
-then the calculator object is imported as fromase.calculators.ljimport
-LennardJones. This works if the calculator is available in ASE or follows
-ASE format for initialization such as GPAW. Any other ASE calculator will
-need to have the instantiation defined in :ref:calculators.py
-
calc_id.mode.run_prefix: (str) string to append before running the script
-e.g. if run_prefix=mpirun the script will be inkoked with the equivalent
-of mpirunpythonmy_script.py. run_prefix in env_input.yaml is
-always prepended before the one provided by calc_input.yaml.
-
calc_id.mode.run_postfix: (str) string to append after running the script
-e.g. if run_postfix='&>out.txt' the script will be inkoked with the
-equivalent of pythonmy_script.py&>out.txt. run_postfix in
-env_input.yaml is always appended after the one provided by
-calc_input.yaml.
-
calc_id.precommands: (list, optional) Commands to be run/added to the job
-script before running the script. A common use cas is loading a module or
-activating an environment
-
calc_id.postcommands: (list, optional) Commands to be run/added to the
-job script after running the script.
-
calc_id.args: (dict) key-value pairs to be passed as arguments for the
-initialization of the calculator class. e.g. if the class is LennardJones,
-the arguments are passed as calc=LennardJones(**{'sigma':3.2,
-'epsilon':3})
One of the most useful applications of ASIMTools is the unification of methods
-for setting up ASE atoms objects using the same interface. If a script requires
-a single or multiple atoms objects as input, they are provided as either an
-image dictionary for a single Atoms object or images for a list of
-Atoms objects as part of the args section. Below are all the different ways
-to get an atoms object. Downloading images from MaterialsProject and Generating
-them from Pymatgen will implemented in future.
# Reading a specific image from a structure file using ase.io.read
-image:
-image_file:/path/to/my/ASE-readable/image/file.xyz
-# Optional keyword argument passed to ase.io.read
-index:3
-
-# Building a bulk crystal using ase.build.bulk
-image:
-builder:bulk
-# Optional keyword arguments passed to the builder, must match ASE exactly
-name:Li
-crystalstructure:bcc
-a:4.3
-cubic:True
-
-# Building a surface using ase.build.fcc100
-image:
-builder:fcc100
-# Optional keyword arguments passed to the builder, must match ASE exactly
-symbol:Fe
-vacuum:8
-periodic:False
-
-# Building a 3x3x3 supercell of Ar using ase.build.bulk then
-# Atoms.repeat(repeat) and then applying Atoms.rattle(stdev=rattle_stdev)
-image:
-name:Ar
-repeat:[3,3,3]
-rattle_stdev:0.01
-
-# You can even supply an atoms object directly so that the interface is
-# universal. This is most useful in the script code itself.
-image:
-atoms:Atoms
-
-
-
Similarly, if the script requires multiple image inputs, there exists a
-universal interface. The keyword is strictly specified as images This is especially useful for distributing simulations
-across multiple structures or reading structures from multiple previous
-simulations.
# Reading specific images from a structure file using ase.io.read
-images:
-image_file:/path/to/my/ASE-readable/image/file.xyz
-# Optional keyword arguments passed to ase.io.read
-index:'3:8'
-format:extxyz
-
-# You can read all files matching a certain pattern using a wildcard
-images:
-pattern:/path/to/my/structure/files/*.cif
-# Optional keyword argument passed to ase.io.read
-index:-1
-
-# You can read all files matching a certain pattern using a wildcard
-images:
-patterns:
--/path/to/my/structure/files/*.cif
--/path/to/my/other/structure/files/*.cfg
-
-# You can even supply a list of atoms objects directly so that the interface
-# is universal. This is most useful in the script code itself.
-images:
-images:[Atoms1,Atoms2,...]
-
The major difference between asim-execute and asim-run is that,
-asim-execute takes into account the workdir and the env_id.
-asim-run will the script in the current directory and in the current
-console. In fact, asim-execute will create the workdir and then run
-asim-run in the correct environment/batch job. You can always for example,
-request a slurm allocation, go to the directory where you want the script to be
-run and call asim-run from there if you would like more control or to debug.
-If you want verbose logs for debugging, you can run with the -d or
---debug flag.
A job or script run through ASIMTools will always produce a standard set of
-output files in addition to whatever outputs the script produces. In particular
-the most important output are the output.yaml and the job.log file.
-
-
``output.yaml`` contains the status of the job being run in the current
-directory which can be one of clean,started,complete,failed,discard.
-The statuses are self-explanatory, the discard status is never written
-by ASIMTools but a user can edit an output.yaml file and change it’s
-status to discard to tell ASIMTools to ignore that job in any workflows.
-This is common for example if you launch multiple jobs and one of them fails
-irredemably. Deleting the directory for that job is also ok if nothing
-depends on it downstream. Importantly, any results returned by the function
-defined in the script are found in output.yaml. Script main functions
-should always return a dictionary for this purpose.
-
An example of an output.yaml file is shown below
-
-
-
# Successful output for singlepoint script
-end_time:2023-08-28 21:50:51.368025
-energy:13.77302319846367#This was added by the scinglepoint script
-files:
-image:image_output.xyz
-job_ids:'372919'
-start_time:2023-08-28 21:50:46.188300
-status:complete
-
-# Failed output
-start_time:14:29:55, 10/06/23
-status:failed
-
-
-
-
job.log captures the logged output of asim-run or scripts
-that use logging. It is extremely useful for debugging as following the logs
-starting from the base directory will usually lead you to the correct
-traceback that caused the failure.
-
stderr.txt captures errors and backtraces from running scripts. This is
-usually the most informative file for debugging. You can be directed to the
-correct one by noting errors in job.log
-
stdout.txt captures any stdout from running scripts. It is mostly a
-safety measure for catching anything that prints to stdout and rarely has
-useful information unless you write a script that uses print statements.
-
input_image.xyz and input_images.xyz capture the images input into
-the script. This makes sure there is a concrete artifact for the structure
-used in the script for the purposes of visualization and debugging. They are
-always in extxyz format as a flexible standar format
-
slurm* are slurm job files which can be named according to flags
-specified in env_input.yaml otherwise are named slurm_[job_id].out
To check the status of jobs, even complicated chains and distributed jobs, we
-provide the asim-check utility which can be run using:
-
asim-check /path/to/sim_input.yaml
-
-
-
This will print the job tree, including statuses and work directories of the
-jobs whose root directory is specified as workdir in sim_input.yaml.
-
In many cases, there may be mistakes in one of your configuration files leading to
-a failed workflow. In these cases there are a few ways you could resolve the
-issue:
-
-
Delete the workdirectory and restart the workflow. This is why it is
-recommended that the base sim_input.yaml has workdir set to a new
-directory that only has the results of the workflow.
-
Modify the ASIMTools generated sim_input.yaml to fix the problem. If
-there are downstream sim_input.yaml files in a chain, they will have to
-be deleted or set overwrite=True. Deleting is recommended for safety
-purposes.
-
Simply rerun asim-execute. This will rerun the jobs, skipping any jobs
-with a status of complete or discard. Note that error files are not
-deleted so you will have to clear those manually
Because scripts contain what are merely Python functions, you can always import
-them and use them in any other code for example, you can import
-asimtools.scripts.singlepoint() and use it as below.
ASIMTools offers some standard tools for performing common workflows. These
-are:
-
-
asimtools.scripts.sim_array.sim_array() - Run the same script with one
-specified argument of the script iterated over. This is the most useful
-script and captures all the others except chained
Examples for each type of workflow are given in the examples directory and
-documentation can be found in asimtools.scripts. They also serve as templates for
-you to build your own workflows directly using asimtools.job.Job()
-objects as an advanced user.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/asimplify.rst b/docs/asimplify.rst
index 07e9b16..5bc043f 100644
--- a/docs/asimplify.rst
+++ b/docs/asimplify.rst
@@ -1,13 +1,14 @@
-Developing Custom Scripts
-=========================
+Developing Custom asimmodules
+=============================
-This section will guide you through taking your own in-house simulation and
-integrating it in to asimtools. The process is designed to be as
+This section will guide you through taking your own in-house simulation and
+integrating it in to asimtools. The process is designed to be as
straight-forward as reasonably possible.
As an example, we will ASIMplify the calculation of adsorption_energies as
-shown in ASE. To understand the code, visit the ASE `tutorials page `. Ultimately, the
-ASIMplified code will work with any element and , any calculator and any
+shown in ASE. To understand the code, visit the ASE `tutorials page
+`. Ultimately, the
+ASIMplified code will work with any element and any calculator and any
environment and be fully parallelized job submission in just a few steps!
**Use toy example** To make things easier, it is best to first replace the
@@ -37,13 +38,12 @@ provided here for reference:
db.write(atoms, bm=B)
-**Wrap in a function** The workhorse of ASIMTools is the function, any code
+**Wrap in a function** The workhorse of ASIMTools is the asimmodule, any code
wrapped in a function that returns a dictionary can be run within the
ASIMTools framework. The easiest thing to do would be to take the code and
-copy and paste it in a function which is defined inside a script with the
+copy and paste it in a function which is defined inside an asimmodule with the
same name
-
.. code-block::
from ase.build import bulk
@@ -65,12 +65,12 @@ same name
return {}
-Immediately as it is, this script can be run in ASIMTools. You can run it with
-the following sim_input.yaml
+Immediately as it is, this is an asimmodule can be run in ASIMTools. You can
+run it with the following sim_input.yaml
.. code-block:: yaml
- script: /path/to/ase_eos.py
+ asimmodule: /path/to/ase_eos.py
env_id: inline
workdir: results
@@ -81,8 +81,8 @@ then call
asim-execute sim_input.yaml
Only a little bit more complicated than calling ``python ase_eos.py``
-This script however still depends on specific structures and a specific
-calculator. Let's do the easy thing first, let's make the script work with any
+This asimmodule however still depends on specific structures and a specific
+calculator. Let's do the easy thing first, let's make the asimmodule work with any
calculator using a simple change.
.. code-block::
@@ -109,8 +109,8 @@ calculator using a simple change.
return {}
-Just like that we can now run the script with any correctly configure
-calculator for the all the structures! We can even now run ``calc_array`` to
+Just like that we can now run the asimmodule with any correctly configured
+calculator for all the structures! We can even now run ``calc_array`` to
iterate getting the results using different calculators.
The final change we will make is to parallelize over structures as below
@@ -139,13 +139,13 @@ The final change we will make is to parallelize over structures as below
return {}
-Easy-peasy. We now have a script that works with arbitrary environment,
+Easy-peasy. We now have an asimmodule that works with arbitrary environment,
arbitrary calculator and arbitrary input structure (Of course the simulation
-will fail if we give a bad structure for example)
+will fail if we give a bad structure/calculator for example)
-We can do some final cleanup of the script so that it sends outputs to
-``output.yaml`` and logs some checkpoints. Additionally, any scripts added to
-the repository will need clear syntax highlighting and documentation.
+We can do some final cleanup of the asimmodule so that it sends outputs to
+``output.yaml`` and logs some checkpoints. Additionally, any asimmodules added
+to the repository will need clear syntax highlighting and documentation.
.. code-block::
@@ -176,7 +176,7 @@ the repository will need clear syntax highlighting and documentation.
results = {'v': float(v), 'e': float(e), 'B': float(B)}
return results
-To run this script on an arbitrary structure say Argon with say the
+To run this asimmodule on an arbitrary structure say Argon with say the
LennardJones calculator, in a slurm job we can now use the following input
files.
@@ -184,20 +184,20 @@ sim_input.yaml:
.. code-block:: yaml
- script: /path/to/ase_eos.py
+ asimmodule: /path/to/ase_eos.py
env_id: batch
workdir: results
args:
image:
builder: bulk
name: Ar
- calc_id: gpaw
+ calc_id: lj_Ar
calc_input.yaml:
.. code-block:: yaml
- lj:
+ lj_Ar:
name: LennardJones
module: ase.calculators.lj
args:
@@ -227,49 +227,50 @@ env_input.yaml:
use_slurm: false
interactive: true
-Going back to the original problem, we wanted to run the simulation of mulitple
+Going back to the original problem, we wanted to run the simulation of multiple
different elements with the EMT calculator. To achieve that in parallel, we can
-nest the ``ase_eos`` script in a :func:`asimtools.scripts.sim_array.sim_array` script as follows
+nest the ``ase_eos`` asimmodule in a
+:func:`asimtools.asimmodules.sim_array.sim_array` asimmodule as follows
sim_input.yaml:
.. code-block:: yaml
- script: sim_array
+ asimmodule: sim_array
workdir: results
args:
key_sequence: ['args', 'image', 'name']
array_values: ['Al', 'Ni', 'Cu', 'Pd', 'Ag', 'Pt', 'Au']
env_ids: 'batch'
template_sim_input:
- script: /path/to/ase_eos.py
+ asimmodule: /path/to/ase_eos.py
args:
calc_id: emt
image:
builder: bulk
crystalstructure: 'fcc'
-To make the script easier to access without having to use the full path, you
+To make the asimmodule easier to access without having to use the full path, you
can set the environment variable
.. code-block:: console
- export ASIMTOOLS_SCRIPT_DIR=/path/to/my/script/dir/
+ export ASIMTOOLS_ASIMMODULE_DIR=/path/to/my/asimmodule/dir/
-You can then move the ``ase_eos.py`` script into a directory called ``ase_eos``
-and place it in the script directory. This allows you to refer to scripts
-prepended with the script dir as below
+You can then move the ``ase_eos.py`` asimmodule to
+``/path/to/my/asimmodule/dir/`` i.e. the asimmodule directory. This allows you
+to refer to asimmodules prepended with the asimmodule dir as below
.. code-block:: yaml
- script: sim_array
+ asimmodule: sim_array
workdir: results
args:
key_sequence: ['args', 'image', 'name']
array_values: ['Al', 'Ni', 'Cu', 'Pd', 'Ag', 'Pt', 'Au']
env_ids: 'batch'
template_sim_input:
- script: ase_eos/ase_eos.py
+ asimmodule: ase_eos/ase_eos.py
args:
calc_id: emt
image:
diff --git a/docs/asimtools.asimmodules.benchmarking.rst b/docs/asimtools.asimmodules.benchmarking.rst
new file mode 100644
index 0000000..1582ba2
--- /dev/null
+++ b/docs/asimtools.asimmodules.benchmarking.rst
@@ -0,0 +1,20 @@
+asimtools.asimmodules.benchmarking package
+==========================================
+
+
+
+asimtools.asimmodules.benchmarking.parity module
+------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.benchmarking.parity
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: asimtools.asimmodules.benchmarking
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/asimtools.asimmodules.elastic_constants.rst b/docs/asimtools.asimmodules.elastic_constants.rst
new file mode 100644
index 0000000..d5619d4
--- /dev/null
+++ b/docs/asimtools.asimmodules.elastic_constants.rst
@@ -0,0 +1,20 @@
+asimtools.asimmodules.elastic\_constants package
+================================================
+
+
+
+asimtools.asimmodules.elastic\_constants.cubic\_energy\_expansion module
+------------------------------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.elastic_constants.cubic_energy_expansion
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: asimtools.asimmodules.elastic_constants
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/asimtools.asimmodules.eos.rst b/docs/asimtools.asimmodules.eos.rst
new file mode 100644
index 0000000..b79c880
--- /dev/null
+++ b/docs/asimtools.asimmodules.eos.rst
@@ -0,0 +1,20 @@
+asimtools.asimmodules.eos package
+=================================
+
+
+
+asimtools.asimmodules.eos.postprocess module
+--------------------------------------------
+
+.. automodule:: asimtools.asimmodules.eos.postprocess
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: asimtools.asimmodules.eos
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/asimtools.asimmodules.geometry_optimization.rst b/docs/asimtools.asimmodules.geometry_optimization.rst
new file mode 100644
index 0000000..2133eb5
--- /dev/null
+++ b/docs/asimtools.asimmodules.geometry_optimization.rst
@@ -0,0 +1,52 @@
+asimtools.asimmodules.geometry\_optimization package
+====================================================
+
+
+
+asimtools.asimmodules.geometry\_optimization.ase\_cubic\_eos\_optimization module
+---------------------------------------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.geometry_optimization.ase_cubic_eos_optimization
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+asimtools.asimmodules.geometry\_optimization.atom\_relax module
+---------------------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.geometry_optimization.atom_relax
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+asimtools.asimmodules.geometry\_optimization.cell\_relax module
+---------------------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.geometry_optimization.cell_relax
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+asimtools.asimmodules.geometry\_optimization.optimize module
+------------------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.geometry_optimization.optimize
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+asimtools.asimmodules.geometry\_optimization.symmetric\_cell\_relax module
+--------------------------------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.geometry_optimization.symmetric_cell_relax
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: asimtools.asimmodules.geometry_optimization
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/asimtools.asimmodules.lammps.rst b/docs/asimtools.asimmodules.lammps.rst
new file mode 100644
index 0000000..c4c7427
--- /dev/null
+++ b/docs/asimtools.asimmodules.lammps.rst
@@ -0,0 +1,20 @@
+asimtools.asimmodules.lammps package
+====================================
+
+
+
+asimtools.asimmodules.lammps.lammps module
+------------------------------------------
+
+.. automodule:: asimtools.asimmodules.lammps.lammps
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: asimtools.asimmodules.lammps
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/asimtools.asimmodules.phonons.rst b/docs/asimtools.asimmodules.phonons.rst
new file mode 100644
index 0000000..d7ac070
--- /dev/null
+++ b/docs/asimtools.asimmodules.phonons.rst
@@ -0,0 +1,20 @@
+asimtools.asimmodules.phonons package
+=====================================
+
+
+
+asimtools.asimmodules.phonons.ase\_phonons module
+-------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.phonons.ase_phonons
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: asimtools.asimmodules.phonons
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/asimtools.asimmodules.rst b/docs/asimtools.asimmodules.rst
new file mode 100644
index 0000000..74e4281
--- /dev/null
+++ b/docs/asimtools.asimmodules.rst
@@ -0,0 +1,52 @@
+asimtools.asimmodules package
+=============================
+
+
+
+.. toctree::
+ :maxdepth: 4
+
+ asimtools.asimmodules.benchmarking
+ asimtools.asimmodules.elastic_constants
+ asimtools.asimmodules.eos
+ asimtools.asimmodules.geometry_optimization
+ asimtools.asimmodules.lammps
+ asimtools.asimmodules.phonons
+ asimtools.asimmodules.surface_energies
+ asimtools.asimmodules.transformations
+ asimtools.asimmodules.vacancy_formation_energy
+ asimtools.asimmodules.workflows
+
+
+
+asimtools.asimmodules.do\_nothing module
+----------------------------------------
+
+.. automodule:: asimtools.asimmodules.do_nothing
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+asimtools.asimmodules.singlepoint module
+----------------------------------------
+
+.. automodule:: asimtools.asimmodules.singlepoint
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+asimtools.asimmodules.template module
+-------------------------------------
+
+.. automodule:: asimtools.asimmodules.template
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: asimtools.asimmodules
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/asimtools.asimmodules.surface_energies.rst b/docs/asimtools.asimmodules.surface_energies.rst
new file mode 100644
index 0000000..07cdae7
--- /dev/null
+++ b/docs/asimtools.asimmodules.surface_energies.rst
@@ -0,0 +1,20 @@
+asimtools.asimmodules.surface\_energies package
+===============================================
+
+
+
+asimtools.asimmodules.surface\_energies.surface\_energies module
+----------------------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.surface_energies.surface_energies
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: asimtools.asimmodules.surface_energies
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/asimtools.asimmodules.transformations.rst b/docs/asimtools.asimmodules.transformations.rst
new file mode 100644
index 0000000..52170fb
--- /dev/null
+++ b/docs/asimtools.asimmodules.transformations.rst
@@ -0,0 +1,20 @@
+asimtools.asimmodules.transformations package
+=============================================
+
+
+
+asimtools.asimmodules.transformations.scale\_unit\_cells module
+---------------------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.transformations.scale_unit_cells
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: asimtools.asimmodules.transformations
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/asimtools.asimmodules.vacancy_formation_energy.rst b/docs/asimtools.asimmodules.vacancy_formation_energy.rst
new file mode 100644
index 0000000..30cb7a8
--- /dev/null
+++ b/docs/asimtools.asimmodules.vacancy_formation_energy.rst
@@ -0,0 +1,20 @@
+asimtools.asimmodules.vacancy\_formation\_energy package
+========================================================
+
+
+
+asimtools.asimmodules.vacancy\_formation\_energy.vacancy\_formation\_energy module
+----------------------------------------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.vacancy_formation_energy.vacancy_formation_energy
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: asimtools.asimmodules.vacancy_formation_energy
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/asimtools.asimmodules.workflows.rst b/docs/asimtools.asimmodules.workflows.rst
new file mode 100644
index 0000000..137c318
--- /dev/null
+++ b/docs/asimtools.asimmodules.workflows.rst
@@ -0,0 +1,52 @@
+asimtools.asimmodules.workflows package
+=======================================
+
+
+
+asimtools.asimmodules.workflows.calc\_array module
+--------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.workflows.calc_array
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+asimtools.asimmodules.workflows.chained module
+----------------------------------------------
+
+.. automodule:: asimtools.asimmodules.workflows.chained
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+asimtools.asimmodules.workflows.distributed module
+--------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.workflows.distributed
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+asimtools.asimmodules.workflows.image\_array module
+---------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.workflows.image_array
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+asimtools.asimmodules.workflows.sim\_array module
+-------------------------------------------------
+
+.. automodule:: asimtools.asimmodules.workflows.sim_array
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: asimtools.asimmodules.workflows
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/asimtools.rst b/docs/asimtools.rst
index f555217..4e1ba28 100644
--- a/docs/asimtools.rst
+++ b/docs/asimtools.rst
@@ -6,7 +6,7 @@ asimtools package
.. toctree::
:maxdepth: 4
- asimtools.scripts
+ asimtools.asimmodules
diff --git a/docs/asimtools.scripts.eos.rst b/docs/asimtools.scripts.eos.rst
deleted file mode 100644
index 8aba0f2..0000000
--- a/docs/asimtools.scripts.eos.rst
+++ /dev/null
@@ -1,36 +0,0 @@
-asimtools.scripts.eos package
-=============================
-
-
-
-asimtools.scripts.eos.eos module
---------------------------------
-
-.. automodule:: asimtools.scripts.eos.eos
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.eos.postprocess module
-----------------------------------------
-
-.. automodule:: asimtools.scripts.eos.postprocess
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.eos.preprocess module
----------------------------------------
-
-.. automodule:: asimtools.scripts.eos.preprocess
- :members:
- :undoc-members:
- :show-inheritance:
-
-Module contents
----------------
-
-.. automodule:: asimtools.scripts.eos
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/docs/asimtools.scripts.rst b/docs/asimtools.scripts.rst
deleted file mode 100644
index 2cfbf33..0000000
--- a/docs/asimtools.scripts.rst
+++ /dev/null
@@ -1,147 +0,0 @@
-asimtools.scripts package
-=========================
-
-
-
-.. toctree::
- :maxdepth: 4
-
- asimtools.scripts.eos
-
-
-
-asimtools.scripts.asim\_check module
-------------------------------------
-
-.. automodule:: asimtools.scripts.asim_check
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.asim\_execute module
---------------------------------------
-
-.. automodule:: asimtools.scripts.asim_execute
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.asim\_run module
-----------------------------------
-
-.. automodule:: asimtools.scripts.asim_run
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.atom\_relax module
-------------------------------------
-
-.. automodule:: asimtools.scripts.atom_relax
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.calc\_array module
-------------------------------------
-
-.. automodule:: asimtools.scripts.calc_array
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.cell\_relax module
-------------------------------------
-
-.. automodule:: asimtools.scripts.cell_relax
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.chained module
---------------------------------
-
-.. automodule:: asimtools.scripts.chained
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.distributed module
-------------------------------------
-
-.. automodule:: asimtools.scripts.distributed
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.do\_nothing module
-------------------------------------
-
-.. automodule:: asimtools.scripts.do_nothing
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.env\_array module
------------------------------------
-
-.. automodule:: asimtools.scripts.env_array
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.image\_array module
--------------------------------------
-
-.. automodule:: asimtools.scripts.image_array
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.lammps module
--------------------------------
-
-.. automodule:: asimtools.scripts.lammps
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.parity module
--------------------------------
-
-.. automodule:: asimtools.scripts.parity
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.sim\_array module
------------------------------------
-
-.. automodule:: asimtools.scripts.sim_array
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.singlepoint module
-------------------------------------
-
-.. automodule:: asimtools.scripts.singlepoint
- :members:
- :undoc-members:
- :show-inheritance:
-
-asimtools.scripts.template module
----------------------------------
-
-.. automodule:: asimtools.scripts.template
- :members:
- :undoc-members:
- :show-inheritance:
-
-Module contents
----------------
-
-.. automodule:: asimtools.scripts
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/docs/index.rst b/docs/index.rst
index 06cd649..4e56338 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -11,8 +11,8 @@ Welcome to asimtools's documentation!
:caption: Contents:
README
- Running Scripts
- Custom Scripts
+ Running asimmodules
+ Custom asimmodules
Workflows
API Docs
Contributing
diff --git a/docs/usage.rst b/docs/usage.rst
index 6168305..2d6f701 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -1,9 +1,9 @@
-Running an existing script
-==========================
+Running an Existing asimmodule
+==============================
-This section will guide you through running an already existing script whether
-it be one of the scripts provided in the main repository, from the script
-repository or a custom script you have written yourself.
+This section will guide you through running an already existing asimmodule
+whether it be one of the asimmodules provided in the main repository, from the
+asimmodule repository or a custom asimmodule you have written yourself.
To run a simulation, all you need to do is run either of the following
commands:
@@ -12,16 +12,21 @@ commands:
asim-execute sim_input.yaml -c calc_input.yaml -e env_input.yaml
-or
+Providing ``calc_input.yaml`` or ``env_input.yaml`` is optional. If not
+provided, the globally configured files will be used. See :ref:`envinput`. This
+command will automatically run the specified simulation in the correct
+directory and environment.
+
+A different option is to use the following command:
.. code-block:: console
- asim-run sim_input.yaml -c calc_input.yaml
+ asim-execute sim_input.yaml -c calc_input.yaml -e env_input.yaml
-In either case, providing ``calc_input.yaml`` or ``env_input.yaml`` is optional. If
-not provided, the globally configured files will be used. See :ref:`envinput`. For most
-cases, you will only ever use ``asim-execute``. The differences between
-``asim-execute`` and ``asim-run`` are explained in :ref:`asimrunvsasimexecute`.
+This command will run the simulation in the current directory and environment.
+For most cases, you will only ever use ``asim-execute``. The differences
+between ``asim-execute`` and ``asim-run`` are explained in
+:ref:`asimrunvsasimexecute`.
.. _inputs:
@@ -33,12 +38,12 @@ Input files
sim_input.yaml
--------------
-The minimal requirement to run a script is to provide a ``sim_input.yaml`` file.
-An example of a ``sim_input.yaml`` is shown below:
+The minimal requirement to run an asimmodule is to provide a ``sim_input.yaml``
+file. An example of a ``sim_input.yaml`` is shown below:
.. code-block:: yaml
- script: singlepoint
+ asimmodule: singlepoint
env_id: inline
overwrite: false
submit: true
@@ -52,22 +57,27 @@ An example of a ``sim_input.yaml`` is shown below:
The parameters are:
-- **script**: (str) name of core script or /path/to/my/script.py
-- **env_id**: (str, optional) Environment/context in which to run script
+- **asimmodule**: (str) name of core asimmodule or /path/to/my/asimmodule.py.
+ Core asimmodules defined in the asimmodules directory can be simply referred
+ to using Python dot notation. E.g. to specify the
+ :func:`asimtools.asimmodules.workflows.sim_array` asimmodule, you would
+ specify `workflows.sim_array`. Any other asimmodule should be specified as
+ either a full path or a path relative to ``ASIMTOOLS_ASIMMODULE_DIR``
+ variable to a python file. E.g. ``my_asimmodules/asim_ple.py``
+- **env_id**: (str, optional) Environment/context in which to run asimmodule
configured in env_input.yaml, defaults to running in the current console
- **overwrite**: (bool, optional) (bool) whether or not to overwrite work
directories if they exist, defaults to false
-- **submit**: (bool, optional) whether or not to run the script or instead just
- write the files to run the script without running the script, defaults to true
-- **workdir**: (str, optional) The directory in which the script will be run,
- `asim-execute` will create the directory whereas `asim-run` ignores this
- parameter, defaults to './'
+- **submit**: (bool, optional) whether running the asimmodule, defaults to true
+- **workdir**: (str, optional) The directory in which the asimmodule will be
+ run, `asim-execute` will create the directory whereas `asim-run` ignores this
+ parameter, defaults to './results'
- **precommands**: (list, optional) a list of commands to run in the console
- before running the script, defaults to empty list
+ before running the asimmodule, defaults to empty list
- **postcommands**: (list, optional) a list of commands to run in the console
- after running the script, defaults to empty list
-- **args**: (dict) The arguments of the function being called in the script as
- key-value pairs. These are specific to the script being run.
+ after running the asimmodule, defaults to empty list
+- **args**: (dict) The arguments of the function being called in the asimmodule
+ as key-value pairs. These are specific to the asimmodule being run.
All ASIMTools generated files are named ``sim_input.yaml`` but you can name
user defined files as whatever you like
@@ -76,10 +86,10 @@ user defined files as whatever you like
env_input.yaml
--------------
-Additionally, one can provide an ``env_input.yaml`` file that details the kind of
-environments in which scripts can be run. This file can be provided with the
-asim-execute command using the ``-e`` flag or set globally. An example of an
-env_input.yaml file is given below
+Additionally, one can provide an ``env_input.yaml`` file that details the kind
+of environments in which asimmodules can be run. This file can be provided with
+the asim-execute command using the ``-e`` flag or set globally. An example of
+an env_input.yaml file is given below
.. code-block:: yaml
@@ -96,7 +106,7 @@ env_input.yaml file is given below
postcommands: [postcommand1, postcommand2, ...]
# Concrete examples below
- inline: # Run the script directly in the commandline
+ inline: # Run the asimmodule directly in the console
mode:
use_slurm: false
interactive: true
@@ -141,26 +151,28 @@ The parameters, required, shown in the template section are are described below
``sim_input.yaml`` must match one of the ``env_id`` s defined in the provided
``env_input.yaml``
- **env_id.mode.use_slurm**: (bool) whether or not to request a slurm
- allocation to run the script
+ allocation to run the asimmodule
- **env_id.mode.interactive**: (bool) whether or not to request a slurm
- allocation to run the script directly in the terminal (using ``salloc``) or
- to submita batch job (using ``sbatch``)
-- **env_id.mode.run_prefix**: (str) string to append before running the script
- e.g. if ``run_prefix=mpirun`` the script will be inkoked with the equivalent
- of ``mpirun python my_script.py``. ``run_prefix`` in ``env_input.yaml`` is
- always prepended before the one provided by ``calc_input.yaml``.
-- **env_id.mode.run_postfix**: (str) string to append after running the script
- e.g. if ``run_postfix=' &> out.txt'`` the script will be inkoked with the
- equivalent of ``python my_script.py &> out.txt``. ``run_postfix`` in
- ``env_input.yaml`` is always appended after the one provided by
+ allocation to run the asimmodule directly in the terminal (using ``salloc``)
+ or to submita batch job (using ``sbatch``)
+- **env_id.mode.run_prefix**: (str) string to append before running the
+ asimmodule e.g. if ``run_prefix=mpirun`` the asimmodule will be invoked with
+ the equivalent of ``mpirun python my_asimmodule.py``. ``run_prefix`` in
+ ``env_input.yaml`` is always prepended before the one provided by
``calc_input.yaml``.
-- **env_id.slurm.flags**: (list, optional) The slurm flags for the allocation
- as a list of flags e.g. ``[-n 4, -N 1]``
+- **env_id.mode.run_postfix**: (str) string to append after running the
+ asimmodule e.g. if ``run_postfix=' &> out.txt'`` the asimmodule will be
+ invoked with the equivalent of ``python my_asimmodule.py &> out.txt``.
+ ``run_postfix`` in ``env_input.yaml`` is always appended after the one
+ provided by ``calc_input.yaml``.
+- **env_id.slurm.flags**: (list/dict, optional) The slurm flags for the
+ allocation as a list of flags e.g. ``[-n 4, -N 1]``. One can also specify a
+ dictionary e.g. ``'{-n': 4, '-N': 1, '--mem':2G}``
- **env_id.slurm.precommands**: (list, optional) Commands to be run/added to
- the job script before running the script. A common use cas is loading a
- module or activating an environment
+ the job asimmodule before running the asimmodule. A common use cas is loading
+ a module or activating an environment
- **env_id.slurm.postcommands**: (list, optional) Commands to be run/added to
- the job script after running the script.
+ the job asimmodule after running the asimmodule.
.. _calcinput:
@@ -174,8 +186,9 @@ above, a global configuration file can be set using
export ASIMTOOLS_CALC_INPUT=/path/to/my/global/calc_input.yaml
or provided to asim-execute at run time. Note that if you launch a chained
-workflow with ``asim-run`` instead of ``asim-execute``, scripts farther down
-the chain will use the global ``calc_input.yaml``
+workflow with ``asim-run`` instead of ``asim-execute``, asimmodules farther
+down the chain will use the global ``calc_input.yaml``, so always use
+``asim-execute``
.. code-block:: yaml
@@ -211,32 +224,44 @@ the chain will use the global ``calc_input.yaml``
xc: PBE
txt: gpaw_output.txt
+The parameters for the calculators provided directly in ASE are specified under
+the assumption that the calculator will be initiated as follows:
+
+.. code-block::
+
+ from module import name
+ calc = name(**args)
+
+This works for all calculators defined in ASE v3.22 and below. For externally
+defined calculators, you can submit an issue and we will implement it. For
+example, calculators for NequIP and Deep Potential force fields are
+implemented.
- **calc_id**: (str) unique key for identifying the calculator, ``calc_id`` in
``sim_input.yaml`` must match one of the ``calc_id`` s defined in the
provided ``calc_input.yaml``
- **calc_id.name**: (str) Either the name of the class or the reference to one
- of the provided BBBB external calculators.
+ of the provided external calculators.
- **calc_id.module**: (str) The module from which the calculator class is
imported. e.g. if ``name=LennardJones`` and ``module=ase.calculators.lj``,
then the calculator object is imported as ``from ase.calculators.lj import
LennardJones``. This works if the calculator is available in ASE or follows
ASE format for initialization such as GPAW. Any other ASE calculator will
need to have the instantiation defined in :ref:calculators.py
-- **calc_id.mode.run_prefix**: (str) string to append before running the script
- e.g. if ``run_prefix=mpirun`` the script will be inkoked with the equivalent
- of ``mpirun python my_script.py``. ``run_prefix`` in ``env_input.yaml`` is
+- **calc_id.mode.run_prefix**: (str) string to append before running the asimmodule
+ e.g. if ``run_prefix=mpirun`` the asimmodule will be invoked with the equivalent
+ of ``mpirun python my_asimmodule.py``. ``run_prefix`` in ``env_input.yaml`` is
always prepended before the one provided by ``calc_input.yaml``.
-- **calc_id.mode.run_postfix**: (str) string to append after running the script
- e.g. if ``run_postfix=' &> out.txt'`` the script will be inkoked with the
- equivalent of ``python my_script.py &> out.txt``. ``run_postfix`` in
+- **calc_id.mode.run_postfix**: (str) string to append after running the asimmodule
+ e.g. if ``run_postfix=' &> out.txt'`` the asimmodule will be invoked with the
+ equivalent of ``python my_asimmodule.py &> out.txt``. ``run_postfix`` in
``env_input.yaml`` is always appended after the one provided by
``calc_input.yaml``.
- **calc_id.precommands**: (list, optional) Commands to be run/added to the job
- script before running the script. A common use cas is loading a module or
+ asimmodule before running the asimmodule. A common use cas is loading a module or
activating an environment
- **calc_id.postcommands**: (list, optional) Commands to be run/added to the
- job script after running the script.
+ job asimmodule after running the asimmodule.
- **calc_id.args**: (dict) key-value pairs to be passed as arguments for the
initialization of the calculator class. e.g. if the class is LennardJones,
the arguments are passed as ``calc = LennardJones(**{'sigma':3.2,
@@ -248,12 +273,12 @@ Specifying Images/Atoms
-----------------------
One of the most useful applications of ASIMTools is the unification of methods
-for setting up ASE atoms objects using the same interface. If a script requires
-a single or multiple atoms objects as input, they are provided as either an
-``image`` dictionary for a single Atoms object or ``images`` for a list of
-Atoms objects as part of the ``args`` section. Below are all the different ways
-to get an atoms object. Downloading images from MaterialsProject and Generating
-them from Pymatgen will implemented in future.
+for setting up ASE atoms objects using the same interface. If an asimmodule
+requires a single or multiple atoms objects as input, they are provided as
+either an ``image`` dictionary for a single Atoms object or ``images`` for a
+list of Atoms objects as part of the ``args`` section. Below are the
+different ways to get an atoms object. Downloading images from MaterialsProject
+and Generating them from Pymatgen will implemented in future.
For a detailed description of the API, see :func:`asimtools.utils.get_atoms`
@@ -290,14 +315,14 @@ For a detailed description of the API, see :func:`asimtools.utils.get_atoms`
rattle_stdev: 0.01
# You can even supply an atoms object directly so that the interface is
- # universal. This is most useful in the script code itself.
+ # universal. This is most useful in the asimmodule code itself.
image:
atoms: Atoms
-Similarly, if the script requires multiple image inputs, there exists a
-universal interface. The keyword is strictly specified as ``images`` This is especially useful for distributing simulations
-across multiple structures or reading structures from multiple previous
-simulations.
+Similarly, if the asimmodule requires multiple image inputs, there exists a
+universal interface. The keyword is strictly specified as ``images``. This is
+especially useful for distributing simulations across multiple structures or
+reading structures from multiple previous simulations.
For a detailed description of the API, see :func:`asimtools.utils.get_images`
@@ -316,14 +341,14 @@ For a detailed description of the API, see :func:`asimtools.utils.get_images`
# Optional keyword argument passed to ase.io.read
index: -1
- # You can read all files matching a certain pattern using a wildcard
+ # You can read all files matching certain patterns using a wildcard
images:
patterns:
- /path/to/my/structure/files/*.cif
- /path/to/my/other/structure/files/*.cfg
# You can even supply a list of atoms objects directly so that the interface
- # is universal. This is most useful in the script code itself.
+ # is universal. This is most useful in the asimmodule code itself.
images:
images: [Atoms1, Atoms2, ...]
@@ -333,21 +358,22 @@ Usage of asim-execute and asim-run
**********************************
The major difference between ``asim-execute`` and ``asim-run`` is that,
``asim-execute`` takes into account the ``workdir`` and the ``env_id``.
-``asim-run`` will the script in the current directory and in the current
-console. In fact, ``asim-execute`` will create the ``workdir`` and then run
-``asim-run`` in the correct environment/batch job. You can always for example,
-request a slurm allocation, go to the directory where you want the script to be
-run and call ``asim-run`` from there if you would like more control or to debug.
-If you want verbose logs for debugging, you can run with the ``-d`` or
-``--debug`` flag.
+``asim-run`` will run the asimmodule in the current directory and in the
+current console. In fact, ``asim-execute`` will create the ``workdir`` and then
+run ``asim-run`` in the correct environment/batch job. You can always for
+example, request a slurm allocation, go to the directory where you want the
+asimmodule to be run and call ``asim-run`` from there if you would like more
+control or to debug. If you want verbose logs for debugging, you can run with
+the ``-d`` or ``--debug`` flag.
.. _outputs:
Output files
-****************
-A job or script run through ASIMTools will always produce a standard set of
-output files in addition to whatever outputs the script produces. In particular
-the most important output are the ``output.yaml`` and the ``job.log`` file.
+************
+A job or asimmodule run through ASIMTools will always produce a standard set of
+output files in addition to whatever outputs the asimmodule produces. In
+particular the most important outputs are the ``output.yaml`` and the
+``job.log`` file.
#. \``output.yaml`` contains the status of the job being run in the current
directory which can be one of ``clean, started, complete, failed, discard``.
@@ -357,16 +383,16 @@ the most important output are the ``output.yaml`` and the ``job.log`` file.
This is common for example if you launch multiple jobs and one of them fails
irredemably. Deleting the directory for that job is also ok if nothing
depends on it downstream. Importantly, any results returned by the function
- defined in the script are found in ``output.yaml``. Script main functions
- should always return a dictionary for this purpose.
+ defined in the asimmodule are found in ``output.yaml``. Asimmodule main
+ functions should always return a dictionary for this purpose.
- An example of an ``output.yaml`` file is shown below
+ An example of an ``output.yaml`` file is shown below.
.. code-block:: yaml
- # Successful output for singlepoint script
+ # Successful output for singlepoint asimmodule
end_time: 2023-08-28 21:50:51.368025
- energy: 13.77302319846367 #This was added by the scinglepoint script
+ energy: 13.77302319846367 #This was added by the scinglepoint asimmodule
files:
image: image_output.xyz
job_ids: '372919'
@@ -377,23 +403,25 @@ the most important output are the ``output.yaml`` and the ``job.log`` file.
start_time: 14:29:55, 10/06/23
status: failed
-#. ``job.log`` captures the logged output of ``asim-run`` or scripts
+#. ``job.log`` captures the logged output of ``asim-run`` or asimmodules
that use logging. It is extremely useful for debugging as following the logs
starting from the base directory will usually lead you to the correct
traceback that caused the failure.
-#. ``stderr.txt`` captures errors and backtraces from running scripts. This is
- usually the most informative file for debugging. You can be directed to the
- correct one by noting errors in ``job.log``
+#. ``stderr.txt`` captures errors and backtraces from running asimmodules. This
+ is usually the most informative file for debugging. You can be directed to
+ the correct one by noting errors in ``job.log`` files.
-#. ``stdout.txt`` captures any stdout from running scripts. It is mostly a
+#. ``stdout.txt`` captures any stdout from running asimmodules. It is mostly a
safety measure for catching anything that prints to stdout and rarely has
- useful information unless you write a script that uses ``print`` statements.
+ useful information unless you write an asimmodule that uses ``print``
+ statements. In batch jobs, this output this goes to the slurm job output.
#. ``input_image.xyz`` and ``input_images.xyz`` capture the images input into
- the script. This makes sure there is a concrete artifact for the structure
- used in the script for the purposes of visualization and debugging. They are
- always in ``extxyz`` format as a flexible standar format
+ the asimmodule. This makes sure there is a concrete artifact for the
+ structure used by the asimmodule for the purposes of visualization and
+ debugging. They are always in ``extxyz`` format as a flexible standard
+ format
#. ``slurm*`` are slurm job files which can be named according to flags
specified in ``env_input.yaml`` otherwise are named ``slurm_[job_id].out``
@@ -402,7 +430,7 @@ the most important output are the ``output.yaml`` and the ``job.log`` file.
.. _restarting:
Checking job status and Restarting failed jobs
-**************************************************
+**********************************************
To check the status of jobs, even complicated chains and distributed jobs, we
provide the ``asim-check`` utility which can be run using:
@@ -413,8 +441,8 @@ provide the ``asim-check`` utility which can be run using:
This will print the job tree, including statuses and work directories of the
jobs whose root directory is specified as ``workdir`` in ``sim_input.yaml``.
-In many cases, there may be mistakes in one of your configuration files leading to
-a failed workflow. In these cases there are a few ways you could resolve the
+In many cases, there may be mistakes in one of your configuration files leading
+to a failed workflow. In these cases there are a few ways you could resolve the
issue:
* Delete the workdirectory and restart the workflow. This is why it is
@@ -428,16 +456,16 @@ issue:
with a status of ``complete`` or ``discard``. Note that error files are not
deleted so you will have to clear those manually
-Importing functions from scripts
-********************************
+Importing functions from asimmodules
+************************************
-Because scripts contain what are merely Python functions, you can always import
-them and use them in any other code for example, you can import
-:func:`asimtools.scripts.singlepoint` and use it as below.
+Because asimmodules contain what are merely Python functions, you can always
+import them and use them in any other code for example, you can import
+:func:`asimtools.asimmodules.singlepoint` and use it as below.
.. code-block:: python
- from asimtools.scripts.singlepoint import singlepoint
+ from asimtools.asimmodules.singlepoint import singlepoint
results = singlepoint(image={'name': 'Ar'}, calc_id='lj')
print(results)
diff --git a/docs/workflows.rst b/docs/workflows.rst
index 7e12001..d9fef05 100644
--- a/docs/workflows.rst
+++ b/docs/workflows.rst
@@ -4,23 +4,25 @@ Using built-in workflow tools
ASIMTools offers some standard tools for performing common workflows. These
are:
-#. :func:`asimtools.scripts.sim_array.sim_array` - Run the same script with one
- specified argument of the script iterated over. This is the most useful
- script and captures all the others except ``chained``
+#. :func:`asimtools.asimmodules.sim_array.sim_array` - Run the same asimmodule
+ with one or more specified arguments of the asimmodule iterated over. This
+ is the most useful asimmodule and can substitute all the others except
+ ``chained``
-#. :func:`asimtools.scripts.image_array.image_array` - Run the same script
- on multiple structures
+#. :func:`asimtools.asimmodules.image_array.image_array` - Run the same
+ asimmodule on multiple images
-#. :func:`asimtools.scripts.calc_array.calc_array` - Run the same script
- using different calculators
+#. :func:`asimtools.asimmodules.calc_array.calc_array` - Run the same
+ asimmodule using different calc_ids or calculator parameters based on a
+ template
-#. :func:`asimtools.scripts.distributed.distributed` - Run multiple
- sim_inputs in parallel
+#. :func:`asimtools.asimmodules.distributed.distributed` - Run multiple
+ sim_inputs in parallel
-#. :func:`asimtools.scripts.chained.chained` - Run scripts one after the
- other, e.g. if step 2 results depend on step 1 etc.
+#. :func:`asimtools.asimmodules.chained.chained` - Run asimmodules one after
+ the other, e.g. if step 2 results depend on step 1 etc.
Examples for each type of workflow are given in the examples directory and
-documentation can be found in :mod:`asimtools.scripts`. They also serve as templates for
-you to build your own workflows directly using :func:`asimtools.job.Job`
-objects as an advanced user.
+documentation can be found in :mod:`asimtools.asimmodules`. They also serve as
+templates for you to build your own workflows directly using
+:func:`asimtools.job.Job` objects as an advanced user.
diff --git a/examples/ase_cubic_eos/ase_cubic_eos_sim_input.yaml b/examples/ase_cubic_eos/ase_cubic_eos_sim_input.yaml
new file mode 100644
index 0000000..e175500
--- /dev/null
+++ b/examples/ase_cubic_eos/ase_cubic_eos_sim_input.yaml
@@ -0,0 +1,13 @@
+asimmodule: geometry_optimization.ase_cubic_eos_optimization
+workdir: eos_results
+args:
+ calc_id: emt
+ image:
+ name: Cu
+ a: 3.59
+ cubic: true
+ npoints: 5
+ eps: 0.02
+ plot: true
+ eos_string: vinet
+
diff --git a/examples/ase_cubic_eos/run.sh b/examples/ase_cubic_eos/run.sh
new file mode 100644
index 0000000..6f28a23
--- /dev/null
+++ b/examples/ase_cubic_eos/run.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of env_input.yaml and calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to specify
+# them.
+
+asim-execute ase_cubic_eos_sim_input.yaml -c ../calc_input.yaml
diff --git a/examples/ase_cubic_eos_custom/array_ase_eos_sim_input.yaml b/examples/ase_cubic_eos_custom/array_ase_eos_sim_input.yaml
new file mode 100644
index 0000000..4dbc5b9
--- /dev/null
+++ b/examples/ase_cubic_eos_custom/array_ase_eos_sim_input.yaml
@@ -0,0 +1,15 @@
+asimmodule: workflows.sim_array
+workdir: array_results
+args:
+ key_sequence: ['args', 'image', 'name']
+ array_values: ['Al', 'Ni', 'Cu', 'Pd', 'Ag', 'Pt', 'Au']
+ template_sim_input:
+ asimmodule: ../../ase_eos.py
+ args:
+ calc_id: emt
+ image:
+ builder: bulk
+ crystalstructure: fcc
+ cubic: true
+ db_file: bulk.db
+
diff --git a/examples/ase_eos/ase_eos.py b/examples/ase_cubic_eos_custom/ase_eos.py
similarity index 94%
rename from examples/ase_eos/ase_eos.py
rename to examples/ase_cubic_eos_custom/ase_eos.py
index 1285ea0..f99cbd0 100644
--- a/examples/ase_eos/ase_eos.py
+++ b/examples/ase_cubic_eos_custom/ase_eos.py
@@ -1,6 +1,6 @@
'''
Calculate the equation of state, fit it and extract the equilibrium
-volume, energy and bulk modulus. This script is based on the example provided
+volume, energy and bulk modulus. This asimmodule is based on the example provided
on the ASE website: https://wiki.fysik.dtu.dk/ase/tutorials/db/db.html
author: mkphuthi@github.com
diff --git a/examples/ase_cubic_eos_custom/ase_eos_sim_input.yaml b/examples/ase_cubic_eos_custom/ase_eos_sim_input.yaml
new file mode 100644
index 0000000..ee1f78c
--- /dev/null
+++ b/examples/ase_cubic_eos_custom/ase_eos_sim_input.yaml
@@ -0,0 +1,10 @@
+asimmodule: ../ase_eos.py
+env_id: inline
+workdir: Cu_results
+args:
+ calc_id: emt
+ image:
+ name: Cu
+ cubic: true
+ db_file: bulk.db
+
diff --git a/examples/ase_cubic_eos_custom/calc_input.yaml b/examples/ase_cubic_eos_custom/calc_input.yaml
new file mode 100644
index 0000000..1546fc1
--- /dev/null
+++ b/examples/ase_cubic_eos_custom/calc_input.yaml
@@ -0,0 +1,4 @@
+emt:
+ name: EMT
+ module: ase.calculators.emt
+ args: {}
diff --git a/examples/ase_cubic_eos_custom/run.sh b/examples/ase_cubic_eos_custom/run.sh
new file mode 100644
index 0000000..a2ac3fd
--- /dev/null
+++ b/examples/ase_cubic_eos_custom/run.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to specify
+# them.
+
+# Example 1: This example uses the custom defined script ase_eos.py to
+# calculate the eos for one strucuture
+
+export ASIMTOOLS_ASIMMODULE_DIR="./" # Set the directory to start looking for assimmodule
+asim-execute ase_eos_sim_input.yaml -c calc_input.yaml
+
+# Example 2: This recreates the ASE example for finding the eos for fcc
+# metals, but is now completely parallelized and can be used for any
+# structure with cubic symmetry
+
+asim-execute array_ase_eos_sim_input.yaml -c calc_input.yaml
diff --git a/examples/ase_eos/array_ase_eos_sim_input.yaml b/examples/ase_eos/array_ase_eos_sim_input.yaml
deleted file mode 100644
index a7c310b..0000000
--- a/examples/ase_eos/array_ase_eos_sim_input.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-script: sim_array
-workdir: results
-args:
- key_sequence: ['args', 'image', 'name']
- array_values: ['Al', 'Ni', 'Cu', 'Pd', 'Ag', 'Pt', 'Au']
- env_ids: 'batch'
- template_sim_input:
- script: /home/mphuthi/tests/asimtools/examples/ase_eos/ase_eos.py
- args:
- calc_id: emt
- image:
- builder: bulk
- crystalstructure: 'fcc'
- db_file: /home/mphuthi/tests/asimtools/examples/ase_eos/results/bulk.db
-
diff --git a/examples/ase_eos/ase_eos_sim_input.yaml b/examples/ase_eos/ase_eos_sim_input.yaml
deleted file mode 100644
index 21e4d29..0000000
--- a/examples/ase_eos/ase_eos_sim_input.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-script: ase_eo.py
-env_id: inline
-workdir: results
-args:
- calc_id: emt
- image:
- name: Cu
- db_file: /home/mphuthi/tests/asimtools/examples/ase_eos/results/bulk.db
-
diff --git a/examples/ase_eos/calc_input.yaml b/examples/ase_eos/calc_input.yaml
deleted file mode 100644
index 593b430..0000000
--- a/examples/ase_eos/calc_input.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-lj:
- name: LennardJones
- module: ase.calculators.lj
- args:
- sigma: 3.54
- epsilon: 0.00802236
-emt:
- name: EMT
- module: ase.calculators.emt
- args: {}
diff --git a/examples/atom_relax/atom_relax_sim_input.yaml b/examples/atom_relax/atom_relax_sim_input.yaml
index 0de60c3..36b32c6 100644
--- a/examples/atom_relax/atom_relax_sim_input.yaml
+++ b/examples/atom_relax/atom_relax_sim_input.yaml
@@ -1,11 +1,14 @@
-script: atom_relax
-env_id: srun
-workdir: 'results'
-overwrite: true
+asimmodule: geometry_optimization.atom_relax
+env_id:
+workdir: relax_results
args:
- calc_id: lj
+ calc_id: lj_Ar
image:
name: Ar
builder: bulk
- crystalstructure: 'fcc'
- fmax: 0.05
+ crystalstructure: fcc
+ a: 5.3
+ rattle_stdev: 0.03
+ repeat: [4,4,4]
+ fmax: 0.01
+ optimizer: GPMin
diff --git a/examples/atom_relax/run.sh b/examples/atom_relax/run.sh
new file mode 100644
index 0000000..80bad3c
--- /dev/null
+++ b/examples/atom_relax/run.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of env_input.yaml and calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to specify
+# them.
+
+asim-execute atom_relax_sim_input.yaml -c ../calc_input.yaml
diff --git a/examples/calc_array/calc_array_calc_id_sim_input.yaml b/examples/calc_array/calc_array_calc_id_sim_input.yaml
new file mode 100644
index 0000000..0b678b3
--- /dev/null
+++ b/examples/calc_array/calc_array_calc_id_sim_input.yaml
@@ -0,0 +1,13 @@
+asimmodule: workflows.calc_array
+overwrite: true
+workdir: calc_id_results
+args:
+ calc_ids: [emt, lj_Cu]
+ env_ids: [inline, inline]
+ subasimmodule_input:
+ asimmodule: geometry_optimization.atom_relax
+ args:
+ image:
+ name: Cu
+ rattle_stdev: 0.05
+ fmax: 0.03
diff --git a/examples/calc_array/calc_array_elastic_constant_sim_input.yaml b/examples/calc_array/calc_array_elastic_constant_sim_input.yaml
new file mode 100644
index 0000000..fc3e243
--- /dev/null
+++ b/examples/calc_array/calc_array_elastic_constant_sim_input.yaml
@@ -0,0 +1,16 @@
+asimmodule: workflows.calc_array
+workdir: env_results
+args:
+ calc_ids: [emt, lj_Cu]
+ env_ids: [inline, inline] # Must correspond to calc_id if list is given
+ subasimmodule_input:
+ asimmodule: elastic_constants.cubic_energy_expansion
+ args:
+ calc_id: emt
+ image:
+ name: Cu
+ a: 3.6
+ ase_cubic_eos_args: # The minimum for every calculator should be in the e-v range
+ npoints: 5
+ eps: 0.04
+ eos_string: sj
diff --git a/examples/calc_array/calc_array_keys_sim_input.yaml b/examples/calc_array/calc_array_keys_sim_input.yaml
deleted file mode 100644
index 9c7eaa6..0000000
--- a/examples/calc_array/calc_array_keys_sim_input.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-script: calc_array
-overwrite: true
-workdir: results_keys
-args:
- template_calc_id: 'lj'
- key_sequence: ['args', 'sigma']
- array_values: [2.30, 2.40, 2.50]
- env_ids: 'inline'
- subscript_input:
- script: eos.eos
- overwrite: true
- args:
- image:
- builder: bulk
- name: Cu
- nimages: 5
- scale_range: [0.95, 1.05]
- singlepoint_env_id: inline
- preprocess_env_id: inline
diff --git a/examples/calc_array/calc_array_sigma_sim_input.yaml b/examples/calc_array/calc_array_sigma_sim_input.yaml
new file mode 100644
index 0000000..4f5cb70
--- /dev/null
+++ b/examples/calc_array/calc_array_sigma_sim_input.yaml
@@ -0,0 +1,11 @@
+asimmodule: workflows.calc_array
+workdir: sigma_results
+args:
+ template_calc_id: lj_Cu
+ key_sequence: ['args', 'sigma']
+ array_values: [2.30, 2.33, 2.36]
+ subasimmodule_input:
+ asimmodule: singlepoint
+ args:
+ image:
+ name: Cu
diff --git a/examples/calc_array/calc_array_sim_input.yaml b/examples/calc_array/calc_array_sim_input.yaml
deleted file mode 100644
index f4c24a9..0000000
--- a/examples/calc_array/calc_array_sim_input.yaml
+++ /dev/null
@@ -1,30 +0,0 @@
-script: calc_array
-overwrite: true
-workdir: results
-args:
- calc_ids: ['emt', 'lj', 'nequip']
- env_ids: ['inline', 'batch', 'gpu']
- subscript_input:
- script: eos.eos
- overwrite: true
- args:
- image:
- builder: bulk
- name: Cu
- nimages: 5
- scale_range: [0.95, 1.05]
- singlepoint_env_id: batch
- preprocess_env_id: batch
- # calc_input:
- # emt:
- # name: EMT
- # module: ase.calculators.emt
- # args:
- # fixed_cutoff: True
- # lj:
- # name: LennardJones
- # module: ase.calculators.lj
- # args:
- # sigma: 2.338
- # epsilon: 0.409
-
diff --git a/examples/calc_array/calc_env_array/sim_input.yaml b/examples/calc_array/calc_env_array/sim_input.yaml
deleted file mode 100644
index e2f83a4..0000000
--- a/examples/calc_array/calc_env_array/sim_input.yaml
+++ /dev/null
@@ -1,29 +0,0 @@
-script: calc_array
-overwrite: true
-workdir: results
-args:
- calc_ids: ['emt', 'lj']
- subscript_input:
- script: eos.eos
- overwrite: true
- args:
- image:
- builder: bulk
- name: Cu
- nimages: 5
- scale_range: [0.95, 1.05]
- singlepoint_env_id: inline
- preprocess_env_id: inline
- calc_input:
- emt:
- name: EMT
- module: ase.calculators.emt
- args:
- fixed_cutoff: True
- lj:
- name: LennardJones
- module: ase.calculators.lj
- args:
- sigma: 2.338
- epsilon: 0.409
-
diff --git a/examples/calc_array/run.sh b/examples/calc_array/run.sh
new file mode 100644
index 0000000..f2a9815
--- /dev/null
+++ b/examples/calc_array/run.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of calc_input.yaml
+# If you want to use the globally set one instead, it is not necessary to
+# specify it.
+
+# Example 1:
+# This example runs the same simulation for Cu using different calc_id values
+# See sim_array examples for an alternative way to do this
+asim-execute calc_array_calc_id_sim_input.yaml -c ../calc_input.yaml
+
+# Example 2:
+# This example runs the same elastic constant simulation for Cu using different calc_id values
+asim-execute calc_array_elastic_constant_sim_input.yaml -c ../calc_input.yaml
+
+# Example 3:
+# This example runs the same simulation on Cu using different Lennard-Jones sigma parameters
+asim-execute calc_array_sigma_sim_input.yaml -c ../calc_input.yaml -e ../env_input.yaml
diff --git a/examples/calc_array/run_slurm.sh b/examples/calc_array/run_slurm.sh
new file mode 100644
index 0000000..c1e948c
--- /dev/null
+++ b/examples/calc_array/run_slurm.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to
+# specify them.
+
+# Example 1:
+# This example runs the same calculator on FCC Cu with different
+# lattice parameters (a).
+
+asim-execute sim_array_batch_lattice_parameters_sim_input.yaml -c ../calc_input.yaml
+
+# Example 2:
+# This example runs the same calculator on Cu with different
+# crystal structures
+asim-execute sim_array_batch_crystalstructure_sim_input.yaml -c ../calc_input.yaml
+
+# Example 3:
+# This example runs the same Cu FCC structure with different calculators.
+# Notice that you can individually specify the env_id for each calculator,
+# this allows for example to have one be DFT and another be a ML potential
+# which can have very different hardware and environment requirements.
+# For an alternative way to do this that allows iterating over the internal
+# calc_input parameters, see the workflows.calc_array asimmodule
+asim-execute sim_array_batch_calc_id_sim_input.yaml -c ../calc_input.yaml -e ../env_input.yaml
+
+# Example 4:
+# This example runs the same calculator on different input structure files.
+# It also autmatically names the result directories (ids) corresponding to the
+# name of the file. You can do this with any input file, not just structures
+asim-execute sim_array_batch_image_file_sim_input.yaml -c ../calc_input.yaml -e ../env_input.yaml
diff --git a/examples/calc_array/calc_input.yaml b/examples/calc_input.yaml
similarity index 60%
rename from examples/calc_array/calc_input.yaml
rename to examples/calc_input.yaml
index 71c59de..c6c3ab8 100644
--- a/examples/calc_array/calc_input.yaml
+++ b/examples/calc_input.yaml
@@ -1,14 +1,18 @@
-# Cu empirical potentials
-
emt:
name: EMT
module: ase.calculators.emt
args:
fixed_cutoff: True
-lj:
+lj_Cu:
name: LennardJones
module: ase.calculators.lj
args:
sigma: 2.338
epsilon: 0.409
+lj_Ar:
+ name: LennardJones
+ module: ase.calculators.lj
+ args:
+ sigma: 3.54
+ epsilon: 0.00802236
diff --git a/examples/cell_relax/cell_relax_sim_input.yaml b/examples/cell_relax/cell_relax_sim_input.yaml
index 5020536..fefaabe 100644
--- a/examples/cell_relax/cell_relax_sim_input.yaml
+++ b/examples/cell_relax/cell_relax_sim_input.yaml
@@ -1,13 +1,11 @@
-script: cell_relax
-env_id: inline
-workdir: 'results'
-overwrite: true
+asimmodule: geometry_optimization.cell_relax # The symmetry might change!
+workdir: cell_relax_results
args:
- calc_id: lj
+ calc_id: lj_Ar
image:
name: Ar
builder: bulk
- crystalstructure: 'fcc'
+ crystalstructure: fcc
a: 5.2
- smax: 0.005
+ fmax: 0.005 # See ASE docs StrainFilter for best choices for setting this
diff --git a/examples/cell_relax/run.sh b/examples/cell_relax/run.sh
new file mode 100644
index 0000000..5589152
--- /dev/null
+++ b/examples/cell_relax/run.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to specify
+# them.
+
+# Example 1: This relaxes all cell degrees of freedom using ase.filter.strainfilter
+# If you want to maintain symmetry, use
+# geometry_optimization.symmetric_cell_relax asimmodule
+asim-execute cell_relax_sim_input.yaml -c ../calc_input.yaml
diff --git a/examples/chained/chained_batch_sim_input.yaml b/examples/chained/chained_batch_sim_input.yaml
new file mode 100644
index 0000000..6dc0af9
--- /dev/null
+++ b/examples/chained/chained_batch_sim_input.yaml
@@ -0,0 +1,37 @@
+asimmodule: workflows.chained
+workdir: chained_results
+args:
+ steps:
+ step-0:
+ asimmodule: geometry_optimization.atom_relax
+ env_id: batch
+ args:
+ calc_id: lj_Ar
+ image:
+ name: Ar
+ crystalstructure: fcc
+ a: 4.0
+ repeat: [3,3,3]
+ rattle_stdev: 0.02
+ fmax: 0.01
+ optimizer: LBFGS
+ step-1:
+ asimmodule: geometry_optimization.cell_relax
+ env_id: batch
+ args:
+ calc_id: lj_Ar
+ image:
+ image_file: ../step-0/image_output.xyz
+ fmax: 0.006
+ step-2:
+ asimmodule: do_nothing
+ env_id: batch
+ args:
+ duration: 20 # To give you a chance to see the job dependencies
+ step-3:
+ asimmodule: geometry_optimization.ase_cubic_eos_optimization
+ env_id: batch
+ args:
+ calc_id: lj_Ar
+ image:
+ image_file: ../step-1/image_output.xyz
diff --git a/examples/chained/chained_sim_input.yaml b/examples/chained/chained_sim_input.yaml
index dd90dd0..374b4ac 100644
--- a/examples/chained/chained_sim_input.yaml
+++ b/examples/chained/chained_sim_input.yaml
@@ -1,34 +1,29 @@
-script: chained
-config_id: inline
+asimmodule: workflows.chained
+workdir: chained_results
args:
- workdir: results
steps:
step-0:
- script: singlepoint
- config_id: batch
+ asimmodule: geometry_optimization.atom_relax
args:
+ calc_id: lj_Ar
image:
- name: 'Ar'
- properties: ['energy', 'forces']
+ name: Ar
+ crystalstructure: fcc
+ a: 4.0
+ repeat: [3,3,3]
+ rattle_stdev: 0.02
+ fmax: 0.01
+ optimizer: LBFGS
step-1:
- script: singlepoint
- config_id: batch
+ asimmodule: geometry_optimization.cell_relax
args:
+ calc_id: lj_Ar
image:
- name: 'Ar'
- properties: ['energy', 'forces']
+ image_file: step-0/image_output.xyz
+ fmax: 0.006
step-2:
- script: singlepoint
- config_id: batch
+ asimmodule: geometry_optimization.ase_cubic_eos_optimization
args:
+ calc_id: lj_Ar
image:
- name: 'Ar'
- properties: ['energy', 'forces']
- step-3:
- script: singlepoint
- config_id: batch
- args:
- image:
- name: 'Ar'
- properties: ['energy', 'forces']
-
+ image_file: step-1/image_output.xyz
diff --git a/examples/chained/chained_srun_sim_input.yaml b/examples/chained/chained_srun_sim_input.yaml
new file mode 100644
index 0000000..2a9a975
--- /dev/null
+++ b/examples/chained/chained_srun_sim_input.yaml
@@ -0,0 +1,37 @@
+asimmodule: workflows.chained
+workdir: chained_results
+args:
+ steps:
+ step-0:
+ asimmodule: geometry_optimization.atom_relax
+ env_id: srun
+ args:
+ calc_id: lj_Ar
+ image:
+ name: Ar
+ crystalstructure: fcc
+ a: 4.0
+ repeat: [3,3,3]
+ rattle_stdev: 0.02
+ fmax: 0.01
+ optimizer: LBFGS
+ step-1:
+ asimmodule: geometry_optimization.cell_relax
+ env_id: srun
+ args:
+ calc_id: lj_Ar
+ image:
+ image_file: ../step-0/image_output.xyz
+ fmax: 0.006
+ step-2:
+ asimmodule: do_nothing
+ env_id: inline # You can mix env types
+ args:
+ duration: 20 # To give you a chance to see the job dependencies
+ step-3:
+ asimmodule: geometry_optimization.ase_cubic_eos_optimization
+ env_id: srun
+ args:
+ calc_id: lj_Ar
+ image:
+ image_file: ../step-1/image_output.xyz
diff --git a/examples/chained/lj_calc_input.yaml b/examples/chained/lj_calc_input.yaml
deleted file mode 100644
index ac18766..0000000
--- a/examples/chained/lj_calc_input.yaml
+++ /dev/null
@@ -1,51 +0,0 @@
-batch:
- submit: True
- overwrite: True
- calc:
- name: LennardJones
- module: ase.calculators.lj
- args:
- sigma: 3.54
- epsilon: 0.00802236
- job:
- use_slurm: true
- interactive: false
- slurm:
- flags:
- - -n 2
- - -p idle
- - -J chain
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
-srun:
- submit: True
- overwrite: True
- calc:
- name: LennardJones
- module: ase.calculators.lj
- args:
- sigma: 3.54
- epsilon: 0.00802236
- job:
- use_slurm: true
- interactive: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
-inline:
- submit: True
- overwrite: True
- job:
- use_slurm: false
- interactive: true
- calc:
- name: LennardJones
- module: ase.calculators.lj
- args:
- sigma: 3.54
- epsilon: 0.00802236
diff --git a/examples/chained/run.sh b/examples/chained/run.sh
new file mode 100644
index 0000000..095bd2a
--- /dev/null
+++ b/examples/chained/run.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of calc_input.yaml
+# If you want to use the globally set one instead, it is not necessary to
+# specify it.
+
+# Example 1:
+# This example runs multiple asimmodules one after the other, stopping on failure
+# You can fix the failed job in its workdir or set the output.yaml status to
+# "discard" or "complete" and rerun asim-execute to proceed
+asim-execute chained_sim_input.yaml -c ../calc_input.yaml
+
diff --git a/examples/chained/run_slurm.sh b/examples/chained/run_slurm.sh
new file mode 100644
index 0000000..f1276e5
--- /dev/null
+++ b/examples/chained/run_slurm.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of env_input.yaml and calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to specify
+# them.
+
+# Run the chain of asimmodules in a mix of interactive and inline jobs
+asim-execute chained_srun_sim_input.yaml -c ../calc_input.yaml
+
+# Run the chain of asimmodule modules in batch jobs with dependencies
+asim-execute chained_batch_sim_input.yaml -c ../calc_input.yaml
diff --git a/examples/clean_all.sh b/examples/clean_all.sh
new file mode 100644
index 0000000..f7fa121
--- /dev/null
+++ b/examples/clean_all.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+# This runs all the examples and might take a while, if any fail, feel free to
+# check issues on github or submit a new one
+
+RUNFILE="run.sh"
+
+for d in */; do
+ cd $d
+ rm -r *results
+ cd ../
+done
diff --git a/examples/distributed/distributed_batch_sim_input.yaml b/examples/distributed/distributed_batch_sim_input.yaml
index beb7805..4e3e234 100644
--- a/examples/distributed/distributed_batch_sim_input.yaml
+++ b/examples/distributed/distributed_batch_sim_input.yaml
@@ -1,26 +1,39 @@
-script: distributed
-env_id: inline
-workdir: results
+asimmodule: workflows.distributed
+workdir: distributed_results
args:
- subscripts:
- id-00: &id01
- script: singlepoint
+ array_max: 2 # You can limit how many slurm jobs are run at the same time here (only for job arrays)
+ subasimmodules:
+ id-0000:
+ asimmodule: singlepoint
+ env_id: batch #If all env_ids are slurm batch jobs using the same configuration, we automatically use arrays
+ args:
+ calc_id: lj_Ar
+ image:
+ name: Ar
+ id-0001:
+ # Doesn't have to be same asimmodule
+ asimmodule: geometry_optimization.atom_relax
env_id: batch
args:
- calc_id: lj
+ calc_id: lj_Ar
image:
name: Ar
- properties: ['energy', 'forces']
- id-01: *id01
- id-02: *id01
- id-03: *id01
- id-04: *id01
- id-05: *id01
- id-06: *id01
- id-07: *id01
- id-08: *id01
- id-09: *id01
- id-10: *id01
- id-11: *id01
- id-12: *id01
-
+ id-0002:
+ # This is just the calc_array example copied and pasted!
+ asimmodule: workflows.calc_array
+ env_id: batch
+ args:
+ calc_ids: [emt, lj_Cu]
+ env_ids: [inline, inline] # Must correspond to calc_id if list is given
+ subasimmodule_input:
+ asimmodule: elastic_constants.cubic_energy_expansion
+ args:
+ calc_id: emt
+ image:
+ name: Cu
+ a: 3.6
+ cubic: true
+ ase_cubic_eos_args: # The minimum for every calculator should be in the e-v range
+ npoints: 5
+ eps: 0.04
+ eos_string: sj
diff --git a/examples/distributed/distributed_mixed_sim_input.yaml b/examples/distributed/distributed_mixed_sim_input.yaml
new file mode 100644
index 0000000..938c76b
--- /dev/null
+++ b/examples/distributed/distributed_mixed_sim_input.yaml
@@ -0,0 +1,37 @@
+asimmodule: workflows.distributed
+workdir: distributed_results
+args:
+ subasimmodules:
+ id-0000:
+ asimmodule: singlepoint
+ env_id: inline # No array since one of them is not a slurm batch job
+ args:
+ calc_id: lj_Ar
+ image:
+ name: Ar
+ id-0001:
+ # Doesn't have to be same asimmodule
+ asimmodule: geometry_optimization.atom_relax
+ env_id: batch
+ args:
+ calc_id: lj_Ar
+ image:
+ name: Ar
+ id-0002:
+ # This is just the calc_array example copied and pasted!
+ asimmodule: workflows.calc_array
+ env_id: batch
+ args:
+ calc_ids: [emt, lj_Cu]
+ env_ids: [inline, inline] # Must correspond to calc_id if list is given
+ subasimmodule_input:
+ asimmodule: elastic_constants.cubic_energy_expansion
+ args:
+ calc_id: emt
+ image:
+ name: Cu
+ a: 3.6
+ ase_cubic_eos_args: # The minimum for every calculator should be in the e-v range
+ npoints: 5
+ eps: 0.04
+ eos_string: sj
diff --git a/examples/distributed/distributed_sim_input.yaml b/examples/distributed/distributed_sim_input.yaml
index 004a7ac..21a96b4 100644
--- a/examples/distributed/distributed_sim_input.yaml
+++ b/examples/distributed/distributed_sim_input.yaml
@@ -1,27 +1,36 @@
-script: distributed
-env_id: inline
-workdir: results
+asimmodule: workflows.distributed
+workdir: distributed_results
args:
- subscripts:
- id-00: &id01
- script: singlepoint
- env_id: inline
- config_id: inline
+ subasimmodules:
+ id-0000:
+ asimmodule: singlepoint
args:
- calc_id: lj
+ calc_id: lj_Ar
image:
name: Ar
- properties: ['energy', 'forces']
- id-01: *id01
- id-02: *id01
- id-03: *id01
- id-04: *id01
- id-05: *id01
- id-06: *id01
- id-07: *id01
- id-08: *id01
- id-09: *id01
- id-10: *id01
- id-11: *id01
- id-12: *id01
-
+ id-0001:
+ # Doesn't have to be same asimmodule
+ asimmodule: geometry_optimization.atom_relax
+ args:
+ calc_id: lj_Ar
+ image:
+ name: Ar
+ optimizer: BFGS
+ id-0002:
+ # This is just the calc_array example copied and pasted!
+ asimmodule: workflows.calc_array
+ args:
+ calc_ids: [emt, lj_Cu]
+ env_ids: [inline, inline] # Must correspond to calc_id if list is given
+ subasimmodule_input:
+ asimmodule: elastic_constants.cubic_energy_expansion
+ args:
+ calc_id: emt
+ image:
+ name: Cu
+ a: 3.6
+ cubic: true
+ ase_cubic_eos_args: # The minimum for every calculator should be in the e-v range
+ npoints: 5
+ eps: 0.04
+ eos_string: sj
diff --git a/examples/distributed/lj_calc_input.yaml b/examples/distributed/lj_calc_input.yaml
deleted file mode 100644
index 78b1867..0000000
--- a/examples/distributed/lj_calc_input.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-batch:
- submit: True
- overwrite: True
- calc:
- name: LennardJones
- module: ase.calculators.lj
- args:
- sigma: 3.54
- epsilon: 0.00802236
- job:
- use_slurm: true
- interactive: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
-srun:
- submit: True
- overwrite: True
- calc:
- name: LennardJones
- module: ase.calculators.lj
- args:
- sigma: 3.54
- epsilon: 0.00802236
- job:
- use_slurm: true
- interactive: false
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
-inline:
- submit: True
- overwrite: True
- job:
- use_slurm: false
- interactive: true
- calc:
- name: LennardJones
- module: ase.calculators.lj
- args:
- sigma: 3.54
- epsilon: 0.00802236
diff --git a/examples/distributed/run.sh b/examples/distributed/run.sh
new file mode 100644
index 0000000..5c79577
--- /dev/null
+++ b/examples/distributed/run.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of calc_input.yaml
+# If you want to use the globally set one instead, it is not necessary to
+# specify it.
+
+# Example 1:
+# This example runs multiple asimmodules one after the other, stopping on failure
+# You can fix the failed job in its workdir or set the output.yaml status to
+# "discard" or "complete" and rerun asim-execute to proceed
+asim-execute distributed_sim_input.yaml -c ../calc_input.yaml
+
diff --git a/examples/distributed/run_slurm.sh b/examples/distributed/run_slurm.sh
new file mode 100644
index 0000000..3b16c6d
--- /dev/null
+++ b/examples/distributed/run_slurm.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of env_input.yaml and calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to specify
+# them.
+
+# Run the asimmodule in an interactive job
+asim-execute distributed_batch_sim_input.yaml -c calc_input.yaml
+
+# Run the asimmodule in a batch job
+asim-execute distributed_mixed_sim_input.yaml -c calc_input.yaml
diff --git a/examples/do_nothing/do_nothing_sim_input.yaml b/examples/do_nothing/do_nothing_sim_input.yaml
new file mode 100644
index 0000000..7a27fe4
--- /dev/null
+++ b/examples/do_nothing/do_nothing_sim_input.yaml
@@ -0,0 +1,3 @@
+asimmodule: do_nothing
+args:
+ duration: 3
diff --git a/examples/do_nothing/run.sh b/examples/do_nothing/run.sh
new file mode 100644
index 0000000..637ba61
--- /dev/null
+++ b/examples/do_nothing/run.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+asim-execute do_nothing_sim_input.yaml
diff --git a/examples/elastic_constants/elastic_constants_sim_input.yaml b/examples/elastic_constants/elastic_constants_sim_input.yaml
new file mode 100644
index 0000000..3b935fb
--- /dev/null
+++ b/examples/elastic_constants/elastic_constants_sim_input.yaml
@@ -0,0 +1,13 @@
+asimmodule: elastic_constants.cubic_energy_expansion
+workdir: elastic_constant_results
+args:
+ calc_id: emt
+ image: # Does not need to be relaxed, will use energy minimum volume from eos
+ name: Cu
+ a: 3.59
+ cubic: true
+ ase_cubic_eos_args: # optional, defaults should be fine
+ npoints: 5
+ eps: 0.02
+ eos_string: sj
+
diff --git a/examples/elastic_constants/run.sh b/examples/elastic_constants/run.sh
new file mode 100644
index 0000000..582bf14
--- /dev/null
+++ b/examples/elastic_constants/run.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of env_input.yaml and calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to specify
+# them.
+
+asim-execute elastic_constants_sim_input.yaml -c ../calc_input.yaml
diff --git a/examples/env_array/env_array_sim_input.yaml b/examples/env_array/env_array_sim_input.yaml
deleted file mode 100644
index 002aeba..0000000
--- a/examples/env_array/env_array_sim_input.yaml
+++ /dev/null
@@ -1,59 +0,0 @@
-script: env_array
-overwrite: true
-workdir: results
-args:
- subscript_input:
- script: singlepoint
- calc_id: qe_li
- overwrite: true
- args:
- image:
- builder: bulk
- name: Li
- repeat: [2,2,2]
- rattle_stdev: 0.01
- calc_id: qe_li
- properties: ['energy', 'forces']
- ids: &id003 ['n1', 'n2', 'n4', 'n8', 'n16']
- env_ids: *id003
- env_input:
- n1:
- mode: &id001
- use_slurm: true
- interactive: false
- slurm:
- flags:
- - -n 1
- - --tmp=40G
- precommands: &id002
- - source ~/.bashrc
- - conda activate asimtools
- n2:
- mode: *id001
- slurm:
- flags:
- - -n 2
- - --tmp=40G
- precommands: *id002
- n4:
- mode: *id001
- slurm:
- flags:
- - -n 4
- - --tmp=40G
- precommands: *id002
- n8:
- mode: *id001
- slurm:
- flags:
- - -n 8
- - --tmp=40G
- precommands: *id002
- n16:
- mode: *id001
- slurm:
- flags:
- - -n 16
- - --tmp=40G
- precommands: *id002
-
diff --git a/examples/env_array/env_input.yaml b/examples/env_array/env_input.yaml
deleted file mode 100644
index 9e5565e..0000000
--- a/examples/env_array/env_input.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-batch:
- mode:
- use_slurm: true
- interactive: false
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
-srun:
- mode:
- use_slurm: true
- interactive: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
-inline:
- mode:
- use_slurm: false
- interactive: true
diff --git a/examples/env_input.yaml b/examples/env_input.yaml
new file mode 100644
index 0000000..0410b58
--- /dev/null
+++ b/examples/env_input.yaml
@@ -0,0 +1,30 @@
+batch:
+ mode:
+ use_slurm: true
+ interactive: false
+ slurm:
+ flags:
+ - -n 1
+ - -N 1
+ - -J my_batch_job
+ - --mem=1G
+ # You can do things like activate environments, set environment variables
+ # etc. before running the asimmodule using precommands using bash commands
+ precommands:
+ - export MY_ASIMTOOLS_ENV_VAR="Hello"
+ - echo $MY_ASIMTOOLS_ENV_VAR
+ # You can do things like delete files that take up space etc. after the
+ # asimmodule is run using postcommands using bash commands
+ postcommands:
+ - echo "Bye"
+srun:
+ mode:
+ use_slurm: true
+ interactive: true
+ slurm:
+ flags:
+ - -n 1
+inline:
+ mode:
+ use_slurm: false
+ interactive: true
diff --git a/examples/eos/eos_sim_input.yaml b/examples/eos/eos_sim_input.yaml
index 700fe65..7f6db6a 100644
--- a/examples/eos/eos_sim_input.yaml
+++ b/examples/eos/eos_sim_input.yaml
@@ -1,4 +1,4 @@
-script: eos.eos
+asimmodule: eos.eos
env_id: inline
workdir: results
args:
diff --git a/examples/eos/results/output.yaml b/examples/eos/results/output.yaml
deleted file mode 100644
index 4ec8f3d..0000000
--- a/examples/eos/results/output.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-bulk_modulus: 2.1450870527455046
-equilibrium_energy: -0.06369769932222447
-equilibrium_scale: 1.0042239008583418
-equilibrium_volume: 40.98467183640903
-status: complete
diff --git a/examples/eos/results/step-0/calc_input.yaml b/examples/eos/results/step-0/calc_input.yaml
deleted file mode 100644
index f2367f8..0000000
--- a/examples/eos/results/step-0/calc_input.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-batch:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
-inline:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: false
- overwrite: true
- submit: true
-srun:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: false
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
diff --git a/examples/eos/results/step-0/id-0_x0.95/calc_input.yaml b/examples/eos/results/step-0/id-0_x0.95/calc_input.yaml
deleted file mode 100644
index f2367f8..0000000
--- a/examples/eos/results/step-0/id-0_x0.95/calc_input.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-batch:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
-inline:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: false
- overwrite: true
- submit: true
-srun:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: false
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
diff --git a/examples/eos/results/step-0/id-0_x0.95/image_input.xyz b/examples/eos/results/step-0/id-0_x0.95/image_input.xyz
deleted file mode 100644
index 1fe3282..0000000
--- a/examples/eos/results/step-0/id-0_x0.95/image_input.xyz
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-Lattice="0.0 2.58875 2.58875 2.58875 0.0 2.58875 2.58875 2.58875 0.0" Properties=species:S:1:pos:R:3 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000
diff --git a/examples/eos/results/step-0/id-0_x0.95/image_output.xyz b/examples/eos/results/step-0/id-0_x0.95/image_output.xyz
deleted file mode 100644
index dd87c7a..0000000
--- a/examples/eos/results/step-0/id-0_x0.95/image_output.xyz
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-Lattice="0.0 2.58875 2.58875 2.58875 0.0 2.58875 2.58875 2.58875 0.0" Properties=species:S:1:pos:R:3:forces:R:3:stresses:R:6:energies:R:1 energy=-0.053201752990899645 stress="-0.004250892646061392 1.253593350375051e-19 1.2691183158014984e-19 1.253593350375051e-19 -0.004250892646061393 -2.2140478015060673e-19 1.2691183158014984e-19 -2.2140478015060673e-19 -0.004250892646061394" free_energy=-0.053201752990899645 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000 -0.00000000 -0.00000000 0.00000000 -0.00425089 -0.00425089 -0.00425089 -0.00000000 0.00000000 0.00000000 -0.05320175
diff --git a/examples/eos/results/step-0/id-0_x0.95/output.yaml b/examples/eos/results/step-0/id-0_x0.95/output.yaml
deleted file mode 100644
index 5204c6a..0000000
--- a/examples/eos/results/step-0/id-0_x0.95/output.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-energy: -0.053201752990899645
-files:
- image: image_output.xyz
-status: complete
diff --git a/examples/eos/results/step-0/id-0_x0.95/sim_input.yaml b/examples/eos/results/step-0/id-0_x0.95/sim_input.yaml
deleted file mode 100644
index 2c3b42d..0000000
--- a/examples/eos/results/step-0/id-0_x0.95/sim_input.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-args:
- image:
- image_file: image_input.xyz
- properties:
- - energy
-config_id: inline
-script: singlepoint
-workdir: id-0_x0.95
diff --git a/examples/eos/results/step-0/id-1_x0.97/calc_input.yaml b/examples/eos/results/step-0/id-1_x0.97/calc_input.yaml
deleted file mode 100644
index f2367f8..0000000
--- a/examples/eos/results/step-0/id-1_x0.97/calc_input.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-batch:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
-inline:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: false
- overwrite: true
- submit: true
-srun:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: false
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
diff --git a/examples/eos/results/step-0/id-1_x0.97/image_input.xyz b/examples/eos/results/step-0/id-1_x0.97/image_input.xyz
deleted file mode 100644
index ddb057c..0000000
--- a/examples/eos/results/step-0/id-1_x0.97/image_input.xyz
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-Lattice="0.0 2.656875 2.656875 2.656875 0.0 2.656875 2.656875 2.656875 0.0" Properties=species:S:1:pos:R:3 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000
diff --git a/examples/eos/results/step-0/id-1_x0.97/image_output.xyz b/examples/eos/results/step-0/id-1_x0.97/image_output.xyz
deleted file mode 100644
index 3963a91..0000000
--- a/examples/eos/results/step-0/id-1_x0.97/image_output.xyz
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-Lattice="0.0 2.656875 2.656875 2.656875 0.0 2.656875 2.656875 2.656875 0.0" Properties=species:S:1:pos:R:3:forces:R:3:stresses:R:6:energies:R:1 energy=-0.061137210662256664 stress="-0.001659447787586583 -1.7731142139050546e-20 -1.7394419032551887e-20 -1.7731142139050546e-20 -0.0016594477875865826 2.3586980259816617e-20 -1.7394419032551887e-20 2.3586980259816617e-20 -0.0016594477875865824" free_energy=-0.061137210662256664 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 -0.00000000 -0.00165945 -0.00165945 -0.00165945 0.00000000 -0.00000000 -0.00000000 -0.06113721
diff --git a/examples/eos/results/step-0/id-1_x0.97/output.yaml b/examples/eos/results/step-0/id-1_x0.97/output.yaml
deleted file mode 100644
index 2a3a74c..0000000
--- a/examples/eos/results/step-0/id-1_x0.97/output.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-energy: -0.061137210662256664
-files:
- image: image_output.xyz
-status: complete
diff --git a/examples/eos/results/step-0/id-1_x0.97/sim_input.yaml b/examples/eos/results/step-0/id-1_x0.97/sim_input.yaml
deleted file mode 100644
index c1c6164..0000000
--- a/examples/eos/results/step-0/id-1_x0.97/sim_input.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-args:
- image:
- image_file: image_input.xyz
- properties:
- - energy
-config_id: inline
-script: singlepoint
-workdir: id-1_x0.97
diff --git a/examples/eos/results/step-0/id-2_x1.00/calc_input.yaml b/examples/eos/results/step-0/id-2_x1.00/calc_input.yaml
deleted file mode 100644
index f2367f8..0000000
--- a/examples/eos/results/step-0/id-2_x1.00/calc_input.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-batch:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
-inline:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: false
- overwrite: true
- submit: true
-srun:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: false
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
diff --git a/examples/eos/results/step-0/id-2_x1.00/image_input.xyz b/examples/eos/results/step-0/id-2_x1.00/image_input.xyz
deleted file mode 100644
index 5cc63dd..0000000
--- a/examples/eos/results/step-0/id-2_x1.00/image_input.xyz
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-Lattice="0.0 2.725 2.725 2.725 0.0 2.725 2.725 2.725 0.0" Properties=species:S:1:pos:R:3 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000
diff --git a/examples/eos/results/step-0/id-2_x1.00/image_output.xyz b/examples/eos/results/step-0/id-2_x1.00/image_output.xyz
deleted file mode 100644
index bead419..0000000
--- a/examples/eos/results/step-0/id-2_x1.00/image_output.xyz
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-Lattice="0.0 2.725 2.725 2.725 0.0 2.725 2.725 2.725 0.0" Properties=species:S:1:pos:R:3:forces:R:3:stresses:R:6:energies:R:1 energy=-0.06363244367715234 stress="-0.00018204043822913946 -4.611716440476923e-20 -1.329158102790944e-19 -4.611716440476923e-20 -0.00018204043822913946 1.0810989963359191e-19 -1.329158102790944e-19 1.0810989963359191e-19 -0.00018204043822913946" free_energy=-0.06363244367715234 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 -0.00000000 -0.00018204 -0.00018204 -0.00018204 0.00000000 -0.00000000 -0.00000000 -0.06363244
diff --git a/examples/eos/results/step-0/id-2_x1.00/output.yaml b/examples/eos/results/step-0/id-2_x1.00/output.yaml
deleted file mode 100644
index 9801ab1..0000000
--- a/examples/eos/results/step-0/id-2_x1.00/output.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-energy: -0.06363244367715234
-files:
- image: image_output.xyz
-status: complete
diff --git a/examples/eos/results/step-0/id-2_x1.00/sim_input.yaml b/examples/eos/results/step-0/id-2_x1.00/sim_input.yaml
deleted file mode 100644
index 618fe6f..0000000
--- a/examples/eos/results/step-0/id-2_x1.00/sim_input.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-args:
- image:
- image_file: image_input.xyz
- properties:
- - energy
-config_id: inline
-script: singlepoint
-workdir: id-2_x1.00
diff --git a/examples/eos/results/step-0/id-3_x1.02/calc_input.yaml b/examples/eos/results/step-0/id-3_x1.02/calc_input.yaml
deleted file mode 100644
index f2367f8..0000000
--- a/examples/eos/results/step-0/id-3_x1.02/calc_input.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-batch:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
-inline:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: false
- overwrite: true
- submit: true
-srun:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: false
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
diff --git a/examples/eos/results/step-0/id-3_x1.02/image_input.xyz b/examples/eos/results/step-0/id-3_x1.02/image_input.xyz
deleted file mode 100644
index d983807..0000000
--- a/examples/eos/results/step-0/id-3_x1.02/image_input.xyz
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-Lattice="0.0 2.793125 2.793125 2.793125 0.0 2.793125 2.793125 2.793125 0.0" Properties=species:S:1:pos:R:3 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000
diff --git a/examples/eos/results/step-0/id-3_x1.02/image_output.xyz b/examples/eos/results/step-0/id-3_x1.02/image_output.xyz
deleted file mode 100644
index 108be98..0000000
--- a/examples/eos/results/step-0/id-3_x1.02/image_output.xyz
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-Lattice="0.0 2.793125 2.793125 2.793125 0.0 2.793125 2.793125 2.793125 0.0" Properties=species:S:1:pos:R:3:forces:R:3:stresses:R:6:energies:R:1 energy=-0.06280737756859853 stress="0.0006199639164565369 -1.506983292711994e-20 4.955010065276568e-21 -1.506983292711994e-20 0.0006199639164565369 4.103546990505632e-23 4.955010065276568e-21 4.103546990505632e-23 0.000619963916456537" free_energy=-0.06280737756859853 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000 0.00000000 -0.00000000 0.00000000 0.00061996 0.00061996 0.00061996 0.00000000 0.00000000 -0.00000000 -0.06280738
diff --git a/examples/eos/results/step-0/id-3_x1.02/output.yaml b/examples/eos/results/step-0/id-3_x1.02/output.yaml
deleted file mode 100644
index 66b3a4c..0000000
--- a/examples/eos/results/step-0/id-3_x1.02/output.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-energy: -0.06280737756859853
-files:
- image: image_output.xyz
-status: complete
diff --git a/examples/eos/results/step-0/id-3_x1.02/sim_input.yaml b/examples/eos/results/step-0/id-3_x1.02/sim_input.yaml
deleted file mode 100644
index 9ec37d0..0000000
--- a/examples/eos/results/step-0/id-3_x1.02/sim_input.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-args:
- image:
- image_file: image_input.xyz
- properties:
- - energy
-config_id: inline
-script: singlepoint
-workdir: id-3_x1.02
diff --git a/examples/eos/results/step-0/id-4_x1.05/calc_input.yaml b/examples/eos/results/step-0/id-4_x1.05/calc_input.yaml
deleted file mode 100644
index f2367f8..0000000
--- a/examples/eos/results/step-0/id-4_x1.05/calc_input.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-batch:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
-inline:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: false
- overwrite: true
- submit: true
-srun:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: false
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
diff --git a/examples/eos/results/step-0/id-4_x1.05/image_input.xyz b/examples/eos/results/step-0/id-4_x1.05/image_input.xyz
deleted file mode 100644
index 3b3ba9c..0000000
--- a/examples/eos/results/step-0/id-4_x1.05/image_input.xyz
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-Lattice="0.0 2.86125 2.86125 2.86125 0.0 2.86125 2.86125 2.86125 0.0" Properties=species:S:1:pos:R:3 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000
diff --git a/examples/eos/results/step-0/id-4_x1.05/image_output.xyz b/examples/eos/results/step-0/id-4_x1.05/image_output.xyz
deleted file mode 100644
index b1c36c6..0000000
--- a/examples/eos/results/step-0/id-4_x1.05/image_output.xyz
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-Lattice="0.0 2.86125 2.86125 2.86125 0.0 2.86125 2.86125 2.86125 0.0" Properties=species:S:1:pos:R:3:forces:R:3:stresses:R:6:energies:R:1 energy=-0.06009165705217707 stress="0.0009758698217740892 1.3936847276307408e-20 2.654811294380512e-21 1.3936847276307408e-20 0.0009758698217740892 -2.7533147049398793e-20 2.654811294380512e-21 -2.7533147049398793e-20 0.0009758698217740893" free_energy=-0.06009165705217707 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000 0.00000000 -0.00000000 -0.00000000 0.00097587 0.00097587 0.00097587 -0.00000000 0.00000000 0.00000000 -0.06009166
diff --git a/examples/eos/results/step-0/id-4_x1.05/output.yaml b/examples/eos/results/step-0/id-4_x1.05/output.yaml
deleted file mode 100644
index 9b44f71..0000000
--- a/examples/eos/results/step-0/id-4_x1.05/output.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-energy: -0.06009165705217707
-files:
- image: image_output.xyz
-status: complete
diff --git a/examples/eos/results/step-0/id-4_x1.05/sim_input.yaml b/examples/eos/results/step-0/id-4_x1.05/sim_input.yaml
deleted file mode 100644
index a27f929..0000000
--- a/examples/eos/results/step-0/id-4_x1.05/sim_input.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-args:
- image:
- image_file: image_input.xyz
- properties:
- - energy
-config_id: inline
-script: singlepoint
-workdir: id-4_x1.05
diff --git a/examples/eos/results/step-0/image_input.xyz b/examples/eos/results/step-0/image_input.xyz
deleted file mode 100644
index 5cc63dd..0000000
--- a/examples/eos/results/step-0/image_input.xyz
+++ /dev/null
@@ -1,3 +0,0 @@
-1
-Lattice="0.0 2.725 2.725 2.725 0.0 2.725 2.725 2.725 0.0" Properties=species:S:1:pos:R:3 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000
diff --git a/examples/eos/results/step-0/input_images.xyz b/examples/eos/results/step-0/input_images.xyz
deleted file mode 100644
index eafc58c..0000000
--- a/examples/eos/results/step-0/input_images.xyz
+++ /dev/null
@@ -1,15 +0,0 @@
-1
-Lattice="0.0 2.58875 2.58875 2.58875 0.0 2.58875 2.58875 2.58875 0.0" Properties=species:S:1:pos:R:3 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000
-1
-Lattice="0.0 2.656875 2.656875 2.656875 0.0 2.656875 2.656875 2.656875 0.0" Properties=species:S:1:pos:R:3 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000
-1
-Lattice="0.0 2.725 2.725 2.725 0.0 2.725 2.725 2.725 0.0" Properties=species:S:1:pos:R:3 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000
-1
-Lattice="0.0 2.793125 2.793125 2.793125 0.0 2.793125 2.793125 2.793125 0.0" Properties=species:S:1:pos:R:3 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000
-1
-Lattice="0.0 2.86125 2.86125 2.86125 0.0 2.86125 2.86125 2.86125 0.0" Properties=species:S:1:pos:R:3 pbc="T T T"
-Ar 0.00000000 0.00000000 0.00000000
diff --git a/examples/eos/results/step-0/output.yaml b/examples/eos/results/step-0/output.yaml
deleted file mode 100644
index 117cd08..0000000
--- a/examples/eos/results/step-0/output.yaml
+++ /dev/null
@@ -1 +0,0 @@
-status: complete
diff --git a/examples/eos/results/step-0/sim_input.yaml b/examples/eos/results/step-0/sim_input.yaml
deleted file mode 100644
index 4cda9d0..0000000
--- a/examples/eos/results/step-0/sim_input.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-args:
- ids:
- - x0.95
- - x0.97
- - x1.00
- - x1.02
- - x1.05
- images:
- image_file: input_images.xyz
- subscript_input:
- args:
- properties:
- - energy
- config_id: inline
- script: singlepoint
- workdir: .
-config_id: inline
-script: image_array
diff --git a/examples/eos/results/step-0/stdout.txt b/examples/eos/results/step-0/stdout.txt
deleted file mode 100644
index fe057ce..0000000
--- a/examples/eos/results/step-0/stdout.txt
+++ /dev/null
@@ -1 +0,0 @@
-{'image_file': 'image_input.xyz'}
diff --git a/examples/eos/results/step-1/calc_input.yaml b/examples/eos/results/step-1/calc_input.yaml
deleted file mode 100644
index f2367f8..0000000
--- a/examples/eos/results/step-1/calc_input.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-batch:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
-inline:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: true
- use_slurm: false
- overwrite: true
- submit: true
-srun:
- calc:
- args:
- epsilon: 0.00802236
- sigma: 3.54
- module: ase.calculators.lj
- name: LennardJones
- job:
- interactive: false
- use_slurm: true
- overwrite: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
- submit: true
diff --git a/examples/eos/results/step-1/eos.png b/examples/eos/results/step-1/eos.png
deleted file mode 100644
index 57c91d6..0000000
Binary files a/examples/eos/results/step-1/eos.png and /dev/null differ
diff --git a/examples/eos/results/step-1/output.yaml b/examples/eos/results/step-1/output.yaml
deleted file mode 100644
index 4ec8f3d..0000000
--- a/examples/eos/results/step-1/output.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-bulk_modulus: 2.1450870527455046
-equilibrium_energy: -0.06369769932222447
-equilibrium_scale: 1.0042239008583418
-equilibrium_volume: 40.98467183640903
-status: complete
diff --git a/examples/eos/results/step-1/sim_input.yaml b/examples/eos/results/step-1/sim_input.yaml
deleted file mode 100644
index d6c4d90..0000000
--- a/examples/eos/results/step-1/sim_input.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-args:
- scale_range:
- - 0.95
- - 1.05
- step0_dir: ../step-0
-config_id: inline
-script: eos.postprocess
-workdir: step-1
diff --git a/examples/image_array/image_array_batch_sim_input.yaml b/examples/image_array/image_array_batch_sim_input.yaml
new file mode 100644
index 0000000..428ceea
--- /dev/null
+++ b/examples/image_array/image_array_batch_sim_input.yaml
@@ -0,0 +1,13 @@
+asimmodule: workflows.image_array
+workdir: image_array_batch_results
+args:
+ images:
+ pattern: ../structures/Ar*.cif
+ array_max: 2
+ subasimmodule_input:
+ asimmodule: singlepoint
+ env_id: batch
+ args:
+ calc_id: lj_Ar
+ properties: ['energy', 'forces']
+
diff --git a/examples/image_array/image_array_sim_input.yaml b/examples/image_array/image_array_sim_input.yaml
index 88cc63c..9921f62 100644
--- a/examples/image_array/image_array_sim_input.yaml
+++ b/examples/image_array/image_array_sim_input.yaml
@@ -1,17 +1,12 @@
-script: image_array
-overwrite: true
-workdir: results
-env_id: batch
+asimmodule: workflows.image_array
+workdir: image_array_results
args:
images:
- pattern: /home/mphuthi/tests/asimtools/examples/image_array/structures/Ar*.cif
- ids: [2.5, 3.0, 3.5]
- array_max: 3
- subscript_input:
- script: singlepoint
- env_id: batch
- overwrite: true
+ pattern: ../structures/Ar*.cif
+ array_max: 2
+ subasimmodule_input:
+ asimmodule: singlepoint
args:
- calc_id: lj
+ calc_id: lj_Ar
properties: ['energy', 'forces']
diff --git a/examples/image_array/lj_calc_input.yaml b/examples/image_array/lj_calc_input.yaml
deleted file mode 100644
index 78b1867..0000000
--- a/examples/image_array/lj_calc_input.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-batch:
- submit: True
- overwrite: True
- calc:
- name: LennardJones
- module: ase.calculators.lj
- args:
- sigma: 3.54
- epsilon: 0.00802236
- job:
- use_slurm: true
- interactive: true
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
-srun:
- submit: True
- overwrite: True
- calc:
- name: LennardJones
- module: ase.calculators.lj
- args:
- sigma: 3.54
- epsilon: 0.00802236
- job:
- use_slurm: true
- interactive: false
- slurm:
- flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
-inline:
- submit: True
- overwrite: True
- job:
- use_slurm: false
- interactive: true
- calc:
- name: LennardJones
- module: ase.calculators.lj
- args:
- sigma: 3.54
- epsilon: 0.00802236
diff --git a/examples/image_array/run.sh b/examples/image_array/run.sh
new file mode 100644
index 0000000..5a707ce
--- /dev/null
+++ b/examples/image_array/run.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of calc_input.yaml
+# If you want to use the globally set one instead, it is not necessary to
+# specify it.
+
+# Example 1:
+# This example runs multiple asimmodules one after the other, stopping on failure
+# You can fix the failed job in its workdir or set the output.yaml status to
+# "discard" or "complete" and rerun asim-execute to proceed
+asim-execute image_array_sim_input.yaml -c ../calc_input.yaml
+
diff --git a/examples/image_array/run_slurm.sh b/examples/image_array/run_slurm.sh
new file mode 100644
index 0000000..90bd63f
--- /dev/null
+++ b/examples/image_array/run_slurm.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of env_input.yaml and calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to specify
+# them.
+
+# Run the asimmodule in an interactive job
+asim-execute image_array_batch_sim_input.yaml -c ../calc_input.yaml
diff --git a/examples/lammps/lj_npt_template.lammps b/examples/lammps/lj_npt_template.lammps
index f8f0dd8..05fa14a 100644
--- a/examples/lammps/lj_npt_template.lammps
+++ b/examples/lammps/lj_npt_template.lammps
@@ -4,8 +4,9 @@ atom_style atomic
neighbor 1.0 bin
-lattice fcc 5.26
-region box block 0 10 0 10 0 10
+# We explicitly epecify the initial structure and box in the template
+lattice fcc 5.26
+region box block 0 10 0 10 0 10
create_box 1 box
create_atoms 1 box
@@ -16,7 +17,6 @@ pair_coeff * * 0.00802236 3.54
thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz
thermo ${THERMO_FREQ}
-# dump 1 all custom ${DUMP_FREQ} traj/dump.lammpstrj id type x y z
fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P}
diff --git a/examples/lammps/lj_npt_template_with_image.lammps b/examples/lammps/lj_npt_template_with_image.lammps
index d38edb9..37fac82 100644
--- a/examples/lammps/lj_npt_template_with_image.lammps
+++ b/examples/lammps/lj_npt_template_with_image.lammps
@@ -3,6 +3,8 @@ atom_style atomic
neighbor 1.0 bin
boundary p p p
+
+# We read in the initial structure from a file
read_data image_input.lmpdat
mass 1 39.948
diff --git a/examples/lammps/npt_sim_input.yaml b/examples/lammps/npt_sim_input.yaml
index 5790077..bb6b4d3 100644
--- a/examples/lammps/npt_sim_input.yaml
+++ b/examples/lammps/npt_sim_input.yaml
@@ -1,18 +1,14 @@
-script: lammps
+asimmodule: lammps.lammps
env_id: inline
-workdir: 'results'
+workdir: image_results
overwrite: true
submit: true
args:
- lmp_cmd: 'lmp'
- # template needs full path right now
- template: /home/mphuthi/tests/asimtools/examples/lammps/lj_npt_template.lammps
- # image:
- # name: Ar
- # builder: bulk
- # crystalstructure: 'fcc'
- # a: 5.3
- variables:
+ lmp_cmd: lmp
+ # path relative to workdir, full path usually works best, you can put them
+ # in a directory and version control!
+ template: ../lj_npt_template.lammps
+ variables:
NSTEPS : 100
THERMO_FREQ: 10
DUMP_FREQ: 10
diff --git a/examples/lammps/npt_sim_input_with_image.yaml b/examples/lammps/npt_sim_input_with_image.yaml
index fc1a557..5d34893 100644
--- a/examples/lammps/npt_sim_input_with_image.yaml
+++ b/examples/lammps/npt_sim_input_with_image.yaml
@@ -1,11 +1,9 @@
-script: lammps
-env_id: inline
-workdir: 'results'
-overwrite: true
-submit: true
+asimmodule: lammps.lammps
+workdir: npt_results
args:
- lmp_cmd: 'lmp'
- # template needs full path right now
+ lmp_cmd: lmp
+ # path relative to workdir, full path usually works best, you can put them
+ # in a directory and version control!
template: /home/mphuthi/dev/asimtools/examples/lammps/lj_npt_template_with_image.lammps
image:
name: Ar
diff --git a/examples/optimize_geometry/optimize_sim_input.yaml b/examples/optimize_geometry/optimize_sim_input.yaml
new file mode 100644
index 0000000..c32268f
--- /dev/null
+++ b/examples/optimize_geometry/optimize_sim_input.yaml
@@ -0,0 +1,18 @@
+asimmodule: geometry_optimization.optimize
+workdir: optimize_results
+args:
+ calc_id: lj_Ar
+ image:
+ name: Ar
+ crystalstructure: fcc
+ a: 4.8
+ cubic: true
+ rattle_stdev: 0.02
+ optimizer: BFGS
+ optimizer_args: {}
+ fmax: 0.001
+ expcellfilter_args:
+ mask: null
+ hydrostatic_strain: false
+ constant_volume: false
+ scalar_pressure: 0.0
diff --git a/examples/optimize_geometry/run.sh b/examples/optimize_geometry/run.sh
new file mode 100644
index 0000000..529621f
--- /dev/null
+++ b/examples/optimize_geometry/run.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of env_input.yaml and calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to specify
+# them.
+
+asim-execute optimize_sim_input.yaml -c ../calc_input.yaml
diff --git a/examples/phonons/phonons_sim_input.yaml b/examples/phonons/phonons_sim_input.yaml
new file mode 100644
index 0000000..e53e9c4
--- /dev/null
+++ b/examples/phonons/phonons_sim_input.yaml
@@ -0,0 +1,11 @@
+asimmodule: phonons.ase_phonons
+workdir: phonons_results
+args:
+ calc_id: emt
+ image:
+ name: Cu
+ cubic: true
+ path: GXWXKGL
+ delta: 0.02
+ kpts: [20, 20, 20]
+ supercell: [10,10,10]
diff --git a/examples/run_all.sh b/examples/run_all.sh
new file mode 100644
index 0000000..0fa78e1
--- /dev/null
+++ b/examples/run_all.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+# This runs all the examples and might take a while, if any fail, feel free to
+# check issues on github or submit a new one
+
+source clean_all.sh
+
+RUNFILE="run.sh"
+
+for d in */; do
+ cd $d
+ if test -f ${RUNFILE}; then
+ source run.sh
+ fi
+ cd ../
+done
diff --git a/examples/run_all_slurm.sh b/examples/run_all_slurm.sh
new file mode 100644
index 0000000..7ed0759
--- /dev/null
+++ b/examples/run_all_slurm.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+# This runs all the examples that use slurm and will launch a number of very
+# short jobs, if any fail, feel free to check issues on github or
+# submit a new one
+
+source clean_all.sh
+
+RUNFILE="run.sh"
+
+for d in */; do
+ cd $d
+ if test -f ${RUNFILE}; then
+ source run_slurm.sh
+ fi
+ cd ../
+done
diff --git a/examples/sim_array/calc_input.yaml b/examples/sim_array/calc_input.yaml
deleted file mode 100644
index 71c59de..0000000
--- a/examples/sim_array/calc_input.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-# Cu empirical potentials
-
-emt:
- name: EMT
- module: ase.calculators.emt
- args:
- fixed_cutoff: True
-lj:
- name: LennardJones
- module: ase.calculators.lj
- args:
- sigma: 2.338
- epsilon: 0.409
-
diff --git a/examples/sim_array/run.sh b/examples/sim_array/run.sh
new file mode 100644
index 0000000..5080435
--- /dev/null
+++ b/examples/sim_array/run.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to
+# specify them.
+
+# Example 1:
+# This example runs the same calculator on FCC Cu with different
+# lattice parameters (a).
+
+asim-execute sim_array_lattice_parameters_sim_input.yaml -c ../calc_input.yaml
+
+# Example 2:
+# This example runs the same calculator on Cu with different
+# crystal structures
+asim-execute sim_array_crystalstructure_sim_input.yaml -c ../calc_input.yaml
+
+# Example 3:
+# This example runs the same Cu FCC structure with different calculators.
+# Notice that you can individually specify the env_id for each calculator,
+# this allows for example to have one be DFT and another be a ML potential
+# which can have very different hardware and environment requirements.
+# For an alternative way to do this that allows iterating over the internal
+# calc_input parameters, see the workflows.calc_array asimmodule
+asim-execute sim_array_calc_id_sim_input.yaml -c ../calc_input.yaml -e ../env_input.yaml
+
+# Example 4:
+# This example runs the same calculator on different input structure files.
+# It also autmatically names the result directories (ids) corresponding to the
+# name of the file. You can do this with any input file, not just structures
+asim-execute sim_array_image_file_sim_input.yaml -c ../calc_input.yaml -e ../env_input.yaml
diff --git a/examples/sim_array/run_slurm.sh b/examples/sim_array/run_slurm.sh
new file mode 100644
index 0000000..c1e948c
--- /dev/null
+++ b/examples/sim_array/run_slurm.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to
+# specify them.
+
+# Example 1:
+# This example runs the same calculator on FCC Cu with different
+# lattice parameters (a).
+
+asim-execute sim_array_batch_lattice_parameters_sim_input.yaml -c ../calc_input.yaml
+
+# Example 2:
+# This example runs the same calculator on Cu with different
+# crystal structures
+asim-execute sim_array_batch_crystalstructure_sim_input.yaml -c ../calc_input.yaml
+
+# Example 3:
+# This example runs the same Cu FCC structure with different calculators.
+# Notice that you can individually specify the env_id for each calculator,
+# this allows for example to have one be DFT and another be a ML potential
+# which can have very different hardware and environment requirements.
+# For an alternative way to do this that allows iterating over the internal
+# calc_input parameters, see the workflows.calc_array asimmodule
+asim-execute sim_array_batch_calc_id_sim_input.yaml -c ../calc_input.yaml -e ../env_input.yaml
+
+# Example 4:
+# This example runs the same calculator on different input structure files.
+# It also autmatically names the result directories (ids) corresponding to the
+# name of the file. You can do this with any input file, not just structures
+asim-execute sim_array_batch_image_file_sim_input.yaml -c ../calc_input.yaml -e ../env_input.yaml
diff --git a/examples/sim_array/sim_array_batch_calc_id_sim_input.yaml b/examples/sim_array/sim_array_batch_calc_id_sim_input.yaml
new file mode 100644
index 0000000..1ea9e36
--- /dev/null
+++ b/examples/sim_array/sim_array_batch_calc_id_sim_input.yaml
@@ -0,0 +1,18 @@
+asimmodule: workflows.sim_array
+workdir: results
+args:
+ key_sequence: ['args', 'image', 'a']
+ array_values: [3.50, 3.60, 3.70]
+ env_ids: inline
+ template_sim_input:
+ asimmodule: singlepoint
+ args:
+ calc_id: lj_Cu
+ image:
+ builder: bulk
+ name: Cu
+ crystalstructure: 'fcc'
+ a: {} # You can set a placeholder here or not specify.
+ # I usually put something that would cause an error to make sure
+ # it is substituted correctly
+
\ No newline at end of file
diff --git a/examples/sim_array/sim_array_batch_crystalstructure_sim_input.yaml b/examples/sim_array/sim_array_batch_crystalstructure_sim_input.yaml
new file mode 100644
index 0000000..71baba5
--- /dev/null
+++ b/examples/sim_array/sim_array_batch_crystalstructure_sim_input.yaml
@@ -0,0 +1,23 @@
+asimmodule: workflows.sim_array
+workdir: crystalstructure_results
+args:
+ key_sequence: ['args', 'image']
+ labels: [fcc, bcc] # Check what happens in this cas if you don't specify ids
+ array_values:
+ - builder: bulk
+ name: Cu
+ crystalstructure: fcc
+ a: 3.59
+ - builder: bulk
+ name: Cu
+ crystalstructure: bcc
+ a: 3.655
+ env_ids: inline
+ template_sim_input:
+ asimmodule: singlepoint
+ args:
+ calc_id: lj_Cu
+ image: {} # You can set a placeholder here or not specify.
+ # I usually put something that would cause an error to make sure
+ # it is substituted correctly
+
\ No newline at end of file
diff --git a/examples/sim_array/sim_array_batch_image_file_sim_input.yaml b/examples/sim_array/sim_array_batch_image_file_sim_input.yaml
new file mode 100644
index 0000000..f9cecfc
--- /dev/null
+++ b/examples/sim_array/sim_array_batch_image_file_sim_input.yaml
@@ -0,0 +1,14 @@
+asimmodule: workflows.sim_array
+workdir: image_file_results
+args:
+ key_sequence: ['args', 'image', 'image_file']
+ file_pattern: ../structures/*.cif # Relative to workdir
+ str_btn_args: [structures/Cu_, .cif] #The substring to label result directories is between the first instances of the these two strings in the file path
+ labels: str_btn
+ template_sim_input:
+ asimmodule: singlepoint
+ args:
+ calc_id: lj_Cu
+ image:
+ image_file: {}
+
\ No newline at end of file
diff --git a/examples/sim_array/sim_array_batch_lattice_parameters_sim_input.yaml b/examples/sim_array/sim_array_batch_lattice_parameters_sim_input.yaml
new file mode 100644
index 0000000..1ea9e36
--- /dev/null
+++ b/examples/sim_array/sim_array_batch_lattice_parameters_sim_input.yaml
@@ -0,0 +1,18 @@
+asimmodule: workflows.sim_array
+workdir: results
+args:
+ key_sequence: ['args', 'image', 'a']
+ array_values: [3.50, 3.60, 3.70]
+ env_ids: inline
+ template_sim_input:
+ asimmodule: singlepoint
+ args:
+ calc_id: lj_Cu
+ image:
+ builder: bulk
+ name: Cu
+ crystalstructure: 'fcc'
+ a: {} # You can set a placeholder here or not specify.
+ # I usually put something that would cause an error to make sure
+ # it is substituted correctly
+
\ No newline at end of file
diff --git a/examples/sim_array/sim_array_calc_id_sim_input.yaml b/examples/sim_array/sim_array_calc_id_sim_input.yaml
new file mode 100644
index 0000000..02357bf
--- /dev/null
+++ b/examples/sim_array/sim_array_calc_id_sim_input.yaml
@@ -0,0 +1,15 @@
+asimmodule: workflows.sim_array
+workdir: calc_id_results
+args:
+ key_sequence: [args, calc_id]
+ array_values: [emt, lj_Cu]
+ env_ids: [inline, inline]
+ template_sim_input:
+ asimmodule: singlepoint
+ args:
+ calc_id: {}
+ image:
+ builder: bulk
+ name: Cu
+ crystalstructure: fcc
+ a: 3.59
diff --git a/examples/sim_array/sim_array_crystalstructure_sim_input.yaml b/examples/sim_array/sim_array_crystalstructure_sim_input.yaml
new file mode 100644
index 0000000..93634a0
--- /dev/null
+++ b/examples/sim_array/sim_array_crystalstructure_sim_input.yaml
@@ -0,0 +1,23 @@
+asimmodule: workflows.sim_array
+workdir: crystalstructure_results
+args:
+ key_sequence: ['args', 'image']
+ labels: [fcc, bcc] # Check what happens in the results dir if you don't specify ids
+ array_values:
+ - builder: bulk
+ name: Cu
+ crystalstructure: fcc
+ a: 3.59
+ - builder: bulk
+ name: Cu
+ crystalstructure: bcc
+ a: 3.655
+ env_ids: inline
+ template_sim_input:
+ asimmodule: singlepoint
+ args:
+ calc_id: lj_Cu
+ image: {} # You can set a placeholder here or not specify.
+ # I usually put something that would cause an error to make sure
+ # it is substituted correctly
+
\ No newline at end of file
diff --git a/examples/sim_array/sim_array_image_file_sim_input.yaml b/examples/sim_array/sim_array_image_file_sim_input.yaml
new file mode 100644
index 0000000..f9cecfc
--- /dev/null
+++ b/examples/sim_array/sim_array_image_file_sim_input.yaml
@@ -0,0 +1,14 @@
+asimmodule: workflows.sim_array
+workdir: image_file_results
+args:
+ key_sequence: ['args', 'image', 'image_file']
+ file_pattern: ../structures/*.cif # Relative to workdir
+ str_btn_args: [structures/Cu_, .cif] #The substring to label result directories is between the first instances of the these two strings in the file path
+ labels: str_btn
+ template_sim_input:
+ asimmodule: singlepoint
+ args:
+ calc_id: lj_Cu
+ image:
+ image_file: {}
+
\ No newline at end of file
diff --git a/examples/sim_array/sim_array_lattice_parameters_sim_input.yaml b/examples/sim_array/sim_array_lattice_parameters_sim_input.yaml
new file mode 100644
index 0000000..bc10f1e
--- /dev/null
+++ b/examples/sim_array/sim_array_lattice_parameters_sim_input.yaml
@@ -0,0 +1,18 @@
+asimmodule: workflows.sim_array
+workdir: lattice_parameter_results
+args:
+ key_sequence: ['args', 'image', 'a']
+ array_values: [3.50, 3.60, 3.70]
+ env_ids: inline
+ template_sim_input:
+ asimmodule: singlepoint
+ args:
+ calc_id: lj_Cu
+ image:
+ builder: bulk
+ name: Cu
+ crystalstructure: 'fcc'
+ a: {} # You can set a placeholder here or not specify.
+ # I usually put something that would cause an error to make sure
+ # it is substituted correctly
+
\ No newline at end of file
diff --git a/examples/sim_array/sim_array_sim_input.yaml b/examples/sim_array/sim_array_sim_input.yaml
deleted file mode 100644
index 515d143..0000000
--- a/examples/sim_array/sim_array_sim_input.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-script: sim_array
-workdir: results
-args:
- key_sequence: ['args', 'image', 'a']
- array_values: [3.50, 3.60, 3.70]
- env_ids: 'batch'
- template_sim_input:
- script: singlepoint
- args:
- calc_id: 'lj'
- image:
- builder: bulk
- name: Cu
- crystalstructure: 'fcc'
- a: 3.50
-
\ No newline at end of file
diff --git a/examples/sim_array/structures/Cu_bcc.cif b/examples/sim_array/structures/Cu_bcc.cif
new file mode 100644
index 0000000..90ad229
--- /dev/null
+++ b/examples/sim_array/structures/Cu_bcc.cif
@@ -0,0 +1,26 @@
+data_image0
+_chemical_formula_structural Cu
+_chemical_formula_sum "Cu1"
+_cell_length_a 3.16532
+_cell_length_b 3.16532
+_cell_length_c 3.16532
+_cell_angle_alpha 109.471
+_cell_angle_beta 109.471
+_cell_angle_gamma 109.471
+
+_space_group_name_H-M_alt "P 1"
+_space_group_IT_number 1
+
+loop_
+ _space_group_symop_operation_xyz
+ 'x, y, z'
+
+loop_
+ _atom_site_type_symbol
+ _atom_site_label
+ _atom_site_symmetry_multiplicity
+ _atom_site_fract_x
+ _atom_site_fract_y
+ _atom_site_fract_z
+ _atom_site_occupancy
+ Cu Cu1 1.0 0.00000 0.00000 0.00000 1.0000
diff --git a/examples/sim_array/structures/Cu_fcc.cif b/examples/sim_array/structures/Cu_fcc.cif
new file mode 100644
index 0000000..bbf0ba2
--- /dev/null
+++ b/examples/sim_array/structures/Cu_fcc.cif
@@ -0,0 +1,26 @@
+data_image0
+_chemical_formula_structural Cu
+_chemical_formula_sum "Cu1"
+_cell_length_a 2.55266
+_cell_length_b 2.55266
+_cell_length_c 2.55266
+_cell_angle_alpha 60
+_cell_angle_beta 60
+_cell_angle_gamma 60
+
+_space_group_name_H-M_alt "P 1"
+_space_group_IT_number 1
+
+loop_
+ _space_group_symop_operation_xyz
+ 'x, y, z'
+
+loop_
+ _atom_site_type_symbol
+ _atom_site_label
+ _atom_site_symmetry_multiplicity
+ _atom_site_fract_x
+ _atom_site_fract_y
+ _atom_site_fract_z
+ _atom_site_occupancy
+ Cu Cu1 1.0 0.00000 0.00000 0.00000 1.0000
diff --git a/examples/singlepoint/calc_input.yaml b/examples/singlepoint/calc_input.yaml
index 2155520..f065d96 100644
--- a/examples/singlepoint/calc_input.yaml
+++ b/examples/singlepoint/calc_input.yaml
@@ -1,31 +1,10 @@
-lj:
+lj_Ar:
name: LennardJones
module: ase.calculators.lj
args:
sigma: 3.54
epsilon: 0.00802236
-qe:
- name: Espresso
- module: ase.calculators.espresso
- args:
- kspacing: 0.08
- pseudopotentials:
- Li: Li.pbe-s-kjpaw_psl.1.0.0.UPF
- input_data:
- ecutwfc: 60
- calculation: scf
- tstress: True
- tprnfor: True
- occupations: smearing
- smearing: mp
- degauss: 0.03
- outdir: ./out
- command: srun --mpi=pmix pw.x -in PREFIX.pwi > PREFIX.pwo
-gpaw:
- name: GPAW
- module: gpaw.calculator
- args:
- kpts: [2,2,2]
- h: 0.1
- xc: PBE
- txt: gpaw_output.txt
+emt:
+ name: EMT
+ module: ase.calculators.emt
+ args: {} # EMT calculator does not need any arguments
diff --git a/examples/singlepoint/env_input.yaml b/examples/singlepoint/env_input.yaml
index f23467d..5ff6cf5 100644
--- a/examples/singlepoint/env_input.yaml
+++ b/examples/singlepoint/env_input.yaml
@@ -4,23 +4,25 @@ batch:
interactive: false
slurm:
flags:
- - -n 2
- - -p idle
- - --gres:gpu=0
+ - -n 1
+ - -N 1
+ - -J my_batch_job
+ # You can do things like activate environments, set environment variables
+ # etc. before running the asimmodule using precommands using bash commands
precommands:
- - source ~/.bashrc
- - conda activate asimtools
+ - export MY_ASIMTOOLS_ENV_VAR="Hello"
+ - echo $MY_ASIMTOOLS_ENV_VAR
+ # You can do things like delete files that take up space etc. after the
+ # asimmodule is run using postcommands using bash commands
+ postcommands:
+ - echo "Bye"
srun:
mode:
use_slurm: true
interactive: true
slurm:
flags:
- - -n 2
- - -p idle
- precommands:
- - source ~/.bashrc
- - conda activate asimtools
+ - -n 1
inline:
mode:
use_slurm: false
diff --git a/examples/singlepoint/gpaw/gpaw_calc_input.yaml b/examples/singlepoint/gpaw_calc_input.yaml
similarity index 77%
rename from examples/singlepoint/gpaw/gpaw_calc_input.yaml
rename to examples/singlepoint/gpaw_calc_input.yaml
index 15468d0..c3a7df6 100644
--- a/examples/singlepoint/gpaw/gpaw_calc_input.yaml
+++ b/examples/singlepoint/gpaw_calc_input.yaml
@@ -1,4 +1,4 @@
-lj:
+lj_Ar:
name: LennardJones
module: ase.calculators.lj
args:
@@ -15,5 +15,4 @@ gpaw:
run_prefix: srun --mpi=pmix
precommands:
- source ~/.bashrc
- - conda activate py-gpaw
- - alias python="gpaw python"
+ - conda activate py-gpaw # You probably want to do something like this!
diff --git a/examples/singlepoint/gpaw_sim_input.yaml b/examples/singlepoint/gpaw_sim_input.yaml
new file mode 100644
index 0000000..5526cc9
--- /dev/null
+++ b/examples/singlepoint/gpaw_sim_input.yaml
@@ -0,0 +1,12 @@
+asimmodule: singlepoint
+env_id: batch
+workdir: gpaw_results
+overwrite: true
+args:
+ calc_id: gpaw
+ image:
+ name: Ar
+ builder: bulk
+ crystalstructure: fcc
+ a: 3.0
+ properties: [energy, forces]
diff --git a/examples/singlepoint/run.sh b/examples/singlepoint/run.sh
new file mode 100644
index 0000000..e9cceba
--- /dev/null
+++ b/examples/singlepoint/run.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of env_input.yaml and calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to specify
+# them.
+
+asim-execute singlepoint_sim_input.yaml -c calc_input.yaml -e env_input.yaml
diff --git a/examples/singlepoint/run_slurm.sh b/examples/singlepoint/run_slurm.sh
new file mode 100644
index 0000000..cbde62f
--- /dev/null
+++ b/examples/singlepoint/run_slurm.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of env_input.yaml and calc_input.yaml
+# If you want to use the globally set ones instead, it is not necessary to specify
+# them.
+
+# Run the asimmodule in an interactive job
+asim-execute singlepoint_srun_sim_input.yaml -c calc_input.yaml -e env_input.yaml
+
+# Run the asimmodule in a batch job
+asim-execute singlepoint_batch_sim_input.yaml -c calc_input.yaml -e env_input.yaml
diff --git a/examples/do_nothing/sim_input.yaml b/examples/singlepoint/singlepoint_batch_sim_input.yaml
similarity index 66%
rename from examples/do_nothing/sim_input.yaml
rename to examples/singlepoint/singlepoint_batch_sim_input.yaml
index 9ea399d..dc34214 100644
--- a/examples/do_nothing/sim_input.yaml
+++ b/examples/singlepoint/singlepoint_batch_sim_input.yaml
@@ -1,9 +1,8 @@
-script: singlepoint
+asimmodule: singlepoint
+workdir: batch_results
env_id: batch
-workdir: 'results'
-overwrite: true
args:
- calc_id: lj
+ calc_id: lj_Ar
image:
name: Ar
builder: bulk
diff --git a/examples/singlepoint/singlepoint_sim_input.yaml b/examples/singlepoint/singlepoint_sim_input.yaml
index 9ea399d..df4329e 100644
--- a/examples/singlepoint/singlepoint_sim_input.yaml
+++ b/examples/singlepoint/singlepoint_sim_input.yaml
@@ -1,9 +1,7 @@
-script: singlepoint
-env_id: batch
-workdir: 'results'
-overwrite: true
+asimmodule: singlepoint
+workdir: inline_results
args:
- calc_id: lj
+ calc_id: lj_Ar
image:
name: Ar
builder: bulk
diff --git a/examples/singlepoint/gpaw/gpaw_sim_input.yaml b/examples/singlepoint/singlepoint_srun_sim_input.yaml
similarity index 58%
rename from examples/singlepoint/gpaw/gpaw_sim_input.yaml
rename to examples/singlepoint/singlepoint_srun_sim_input.yaml
index cc25574..f9973f1 100644
--- a/examples/singlepoint/gpaw/gpaw_sim_input.yaml
+++ b/examples/singlepoint/singlepoint_srun_sim_input.yaml
@@ -1,9 +1,8 @@
-script: singlepoint
-env_id: batch
-workdir: 'results'
-overwrite: true
+asimmodule: singlepoint
+workdir: srun_results
+env_id: srun
args:
- calc_id: gpaw
+ calc_id: lj_Ar
image:
name: Ar
builder: bulk
diff --git a/examples/strong_scaling/sim_input.yaml b/examples/strong_scaling/sim_input.yaml
index c987d8f..0b9a271 100644
--- a/examples/strong_scaling/sim_input.yaml
+++ b/examples/strong_scaling/sim_input.yaml
@@ -1,10 +1,10 @@
-script: strong_scaling.strong_scaling.py
+asimmodule: strong_scaling.strong_scaling.py
overwrite: true
workdir: results
args:
ntasks: [1,2,4,8,16]
- subscript_input:
- script: singlepoint
+ subasimmodule_input:
+ asimmodule: singlepoint
overwrite: true
args:
image:
@@ -14,7 +14,7 @@ args:
rattle_stdev: 0.01
calc_id: qe_li
properties: ['energy', 'forces']
- subscript_env_input:
+ subasimmodule_env_input:
mode:
use_slurm: true
interactive: false
diff --git a/examples/surface_energies/surface_energies_sim_input.yaml b/examples/surface_energies/surface_energies_sim_input.yaml
new file mode 100644
index 0000000..55645a6
--- /dev/null
+++ b/examples/surface_energies/surface_energies_sim_input.yaml
@@ -0,0 +1,15 @@
+asimmodule: surface_energies.surface_energies
+workdir: surface_energies_results
+args:
+ calc_id: emt
+ image:
+ name: Cu
+ cubic: true # This is really important! You must use the conventional cell!
+ millers: ['100', '110', '111']
+ generate_all_slabs_args:
+ max_index: 2
+ min_slab_size: 15
+ min_vacuum_size: 10
+ atom_relax_args:
+ optimizer: BFGS
+ fmax: 0.01
diff --git a/examples/symmetric_cell_relax/run.sh b/examples/symmetric_cell_relax/run.sh
new file mode 100644
index 0000000..3a74832
--- /dev/null
+++ b/examples/symmetric_cell_relax/run.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+# These examples explicitly specify a choice of calc_input.yaml
+# If you want to use the globally set one instead, it is not necessary to
+# specify it.
+
+# Example 1: This example relaxes the cell to a hydrostatic external pressure
+# of 0.05eV/Ang^3
+asim-execute symmetric_cell_relax_sim_input.yaml -c ../calc_input.yaml
+
diff --git a/examples/symmetric_cell_relax/symmetric_cell_relax_sim_input.yaml b/examples/symmetric_cell_relax/symmetric_cell_relax_sim_input.yaml
index 849f27c..6fe30e6 100644
--- a/examples/symmetric_cell_relax/symmetric_cell_relax_sim_input.yaml
+++ b/examples/symmetric_cell_relax/symmetric_cell_relax_sim_input.yaml
@@ -1,10 +1,12 @@
-script: symmetric_cell_relax
-workdir: yh
-env_id: n16
+asimmodule: geometry_optimization.symmetric_cell_relax
+workdir: symmetric_cell_relax_results
args:
- calc_id: yh
+ calc_id: lj_Ar
image:
- image_file: input_image.xyz
+ name: Ar
+ crystalstructure: sc
+ a: 3
+ cubic: true
optimizer: BFGS
fixsymmetry_args:
symprec: 0.01
@@ -15,4 +17,3 @@ args:
hydrostatic_strain: false
constant_volume: false
scalar_pressure: 0.05
-
diff --git a/examples/vacancy_formation_energy/vfe_sim_input.yaml b/examples/vacancy_formation_energy/vfe_sim_input.yaml
new file mode 100644
index 0000000..efa55fb
--- /dev/null
+++ b/examples/vacancy_formation_energy/vfe_sim_input.yaml
@@ -0,0 +1,12 @@
+asimmodule: vacancy_formation_energy.vacancy_formation_energy
+workdir: vfe_results
+args:
+ calc_id: emt
+ image: # Does not need to be relaxed, will use energy minimum volume from eos
+ name: Cu
+ a: 3.59
+ cubic: true
+ atom_relax_args:
+ fmax: 0.01
+ repeat: [5,5,5]
+vacancy_index: 1
diff --git a/paper.md b/paper.md
index 4b60d9f..f4de2d2 100644
--- a/paper.md
+++ b/paper.md
@@ -35,31 +35,31 @@ Atomic simulations are a key component of modern day materials science in both a
# Statement of need
-Atomic SIMulation Tools (`ASIMTools`) is a lightweight workflow and simulation manager for reproducible atomistic simulations that can be transferred across environments, calculators and structures implemented in Python. By using in-built or user-defined scripts and utilities, users can run/build their own simulation recipes and automatically scale them on slurm based clusters or locally on their console. The core idea is to separate the dependence of the atomistic potential/calculator, the simulation environment and the simulation protocol thereby allowing the same simulation to be run with different calculators, structures or on different computers with just a change of parameter.Input and output yaml files follow a standard format based providing a simple interface that also acts as a record of the parameters used in a simulation without having to edit python scripts.
+Atomic SIMulation Tools (`ASIMTools`) is a lightweight workflow and simulation manager for reproducible atomistic simulations that can be transferred across environments, calculators and structures implemented in Python. By using in-built or user-defined asimmodules and utilities, users can run/build their own simulation recipes and automatically scale them on slurm based clusters or locally on their console. The core idea is to separate the dependence of the atomistic potential/calculator, the simulation environment and the simulation protocol thereby allowing the same simulation to be run with different calculators, structures or on different computers with just a change of parameter.Input and output yaml files follow a standard format based providing a simple interface that also acts as a record of the parameters used in a simulation without having to edit python asimmodules.
`ASIMTools` is for users interested in performing atomistic calculations on
UNIX-like operating systems and/or on slurm based High Performance Computing
-clusters. By defining simulation protocols as functions in "scripts",
-simulation protocols can be easily added to the library of provided scripts and
+clusters. By defining simulation protocols as functions in "asimmodules",
+simulation protocols can be easily added to the library of provided asimmodules and
iterated on. This will allow the community to develop a robust set of shareable
simulation protocols. The flexibility of ASIMTools allows integration of any
kind of simulation tools such as pymatgen, LAMMPS etc. with examples provided.
-With the scripts defined, users only need to provide a set of inputs in the form of yaml files that define the parameters used for each simulation and are therefore a record.
+With the asimmodules defined, users only need to provide a set of inputs in the form of yaml files that define the parameters used for each simulation and are therefore a record.
# State of the Field
There exist a number of popular workflow tools for atomistic simulations such as Aiida `[@author:2001]`, Fireworks `[@author:2001]` and many more. These tools provide frameworks for constructing complex workflows with different underlying principles. Some managers enforce strict rules that ensure that data obeys FAIR principles and emphasize data provenance and reproducibility. These methods however tend to be fairly large packages with steep learning curves. ASIMTools provides a simple interface as a starting point that can transform any code into ASIMTools compatible code by simply wrapping it in a function that returns a Python dictionary. Any such code can work in ASIMTools and with a few extra steps, the protocol can be made to support an arbitrary calculator and input structure.
-In some workflow managters, such as Atomic Simulation Recipes `[@author:2001]`. Once workflows are built, it can often be difficult to quickly change and iterate over key parameters such as the choice of atomistic calculator or structure as they are intrinsically built into the code. This is particularly challening in an age where machine learning models are becoming more popular. Workflows involving machine learning interaction potentials tend to require the ability to repeat the same calculations on different examples, using different calculators on different hardware iteratively. This is where the value of ASIMTools lies in contrast to more established workflows. ASIMTools is not designed to replace the more powerful workflow managers but rather to supplement them. This is achieved by providing unified inputs that can be easily integrated into, for example, Aiida as Python functions/scripts while also being a stand-alone lightweight workflow manager.
+In some workflow managters, such as Atomic Simulation Recipes `[@author:2001]`. Once workflows are built, it can often be difficult to quickly change and iterate over key parameters such as the choice of atomistic calculator or structure as they are intrinsically built into the code. This is particularly challening in an age where machine learning models are becoming more popular. Workflows involving machine learning interaction potentials tend to require the ability to repeat the same calculations on different examples, using different calculators on different hardware iteratively. This is where the value of ASIMTools lies in contrast to more established workflows. ASIMTools is not designed to replace the more powerful workflow managers but rather to supplement them. This is achieved by providing unified inputs that can be easily integrated into, for example, Aiida as Python functions/asimmodules while also being a stand-alone lightweight workflow manager.
# Example
We present two examples of simulation protocols, more can be found in the
ASIMTools documentation.
## Calculating the energy and forces of an atomic configuration
-Most atomic simulations invlolve evaluations of energies, forces, dipoles etc. of an atomic configuration. In Figure. \autoref{fig:singlepoint} we show how the `singlepoint` script, provided in
-ASIMTools can be used and the input files needed to run the script with arbitrary input structure, calculator or environment.
+Most atomic simulations invlolve evaluations of energies, forces, dipoles etc. of an atomic configuration. In Figure. \autoref{fig:singlepoint} we show how the `singlepoint` asimmodule, provided in
+ASIMTools can be used and the input files needed to run the asimmodule with arbitrary input structure, calculator or environment.
-![Schematic showing the connection between the modular input yaml files. The sim_input.yaml is the main imput file which specifies the environment, calculator (if used) and script to be run.\label{fig:singlepoint}](figures/singlepoint.pdf){ width=100% }
+![Schematic showing the connection between the modular input yaml files. The sim_input.yaml is the main imput file which specifies the environment, calculator (if used) and asimmodule to be run.\label{fig:singlepoint}](figures/singlepoint.pdf){ width=100% }
# Mathematics
@@ -87,7 +87,7 @@ Conceptualization by Keith Phuthi. Coding and development by Keith Phuthi and Em
# Acknowledgements
diff --git a/setup.py b/setup.py
index 6bb28d0..8e0ee8a 100644
--- a/setup.py
+++ b/setup.py
@@ -28,7 +28,7 @@
"pandas",
"pyyaml",
"pymatgen",
- "ase",
+ "ase<=3.22.1", # ASE redid how io calculators work beyond this version
"colorama",
"myst-parser",
"sphinx",
diff --git a/tests/asimmodules/test_distributed.py b/tests/asimmodules/test_distributed.py
new file mode 100644
index 0000000..9f10469
--- /dev/null
+++ b/tests/asimmodules/test_distributed.py
@@ -0,0 +1,33 @@
+"""
+Tests for running asimmodules using asim_run.py
+"""
+import os
+from glob import glob
+from pathlib import Path
+import pytest
+from asimtools.utils import write_yaml
+from asimtools.job import create_unitjob
+from asimtools.job import load_job_from_directory
+
+@pytest.mark.parametrize("calc_input",["lj_argon_calc_input"])
+@pytest.mark.parametrize("env_input",["inline_env_input"])
+@pytest.mark.parametrize("sim_input",["lj_distributed_sim_input"])
+def test_distributed(env_input, calc_input, sim_input, tmp_path, request):
+ env_input = request.getfixturevalue(env_input)
+ calc_input = request.getfixturevalue(calc_input)
+ sim_input = request.getfixturevalue(sim_input)
+ wdir = tmp_path / 'wdir'
+ unitjob = create_unitjob(sim_input, env_input, wdir, calc_input=calc_input)
+ unitjob.submit()
+
+ assert load_job_from_directory(wdir).get_status()[1] == 'complete'
+ dirs = glob(str(wdir / 'id*'))
+ assert len(dirs) == len(sim_input['args']['subasimmodules'])
+
+ for d in dirs:
+ assert str(d).rsplit('/', maxsplit=1)[-1].startswith('id-')
+
+ uj = load_job_from_directory(d)
+ assert uj.get_status()[1] == 'complete'
+
+ assert uj.get_sim_input()['workdir'] == './'
diff --git a/tests/conftest.py b/tests/conftest.py
index 02b1fa8..a0a51e0 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -68,7 +68,7 @@ def lj_argon_calc_input():
def singlepoint_argon_sim_input():
''' Sim input for singlepoint calculation '''
sim_input = {
- 'script': 'singlepoint',
+ 'asimmodule': 'singlepoint',
'prefix': 'test_',
'image': {
'name': 'Ar',
@@ -82,10 +82,10 @@ def singlepoint_argon_sim_input():
@pytest.fixture
def do_nothing_sim_input():
'''
- Sim imput for a script that just completes without doing anything
+ Sim imput for a asimmodule that just completes without doing anything
'''
sim_input = {
- 'script': './data/do_nothing.py',
+ 'asimmodule': './data/do_nothing.py',
'prefix': 'test_',
'args': {
'duration': 5,
@@ -94,12 +94,12 @@ def do_nothing_sim_input():
return sim_input
@pytest.fixture
-def do_nothing_distributed_sim_input():
+def lj_distributed_sim_input():
'''
- Sim imput for a script that just completes without doing anything
+ Sim input for a distributed job that does some lj calculations
'''
- subscript_input = {
- 'script': 'singlepoint',
+ subasimmodule_input = {
+ 'asimmodule': 'singlepoint',
'env_id': 'inline',
'args': {
'calc_id': 'lj',
@@ -110,23 +110,13 @@ def do_nothing_distributed_sim_input():
}
}
sim_input = {
- 'script': 'distributed',
+ 'asimmodule': 'workflows.distributed',
'env_id': 'inline',
'args': {
- 'subscripts': {
- 'id-00': subscript_input,
- 'id-01': subscript_input,
- 'id-02': subscript_input,
- 'id-03': subscript_input,
- 'id-04': subscript_input,
- 'id-05': subscript_input,
- 'id-06': subscript_input,
- 'id-07': subscript_input,
- 'id-08': subscript_input,
- 'id-09': subscript_input,
- 'id-10': subscript_input,
- 'id-11': subscript_input,
- 'id-12': subscript_input,
+ 'subasimmodules': {
+ 'id-0000': subasimmodule_input,
+ 'id-0001': subasimmodule_input,
+ 'id-0002': subasimmodule_input,
}
}
}
@@ -134,12 +124,12 @@ def do_nothing_distributed_sim_input():
return sim_input
@pytest.fixture
-def do_nothing_distributed_custom_name_sim_input():
+def lj_distributed_custom_name_sim_input():
'''
- Sim imput for a script that just completes without doing anything
+ Sim input for a distributed job that does some lj calculations
'''
- subscript_input = {
- 'script': 'singlepoint',
+ subasimmodule_input = {
+ 'asimmodule': 'singlepoint',
'env_id': 'inline',
'args': {
'calc_id': 'lj',
@@ -150,22 +140,14 @@ def do_nothing_distributed_custom_name_sim_input():
}
}
sim_input = {
- 'script': 'distributed',
+ 'asimmodule': 'workflows.distributed',
'env_id': 'inline',
'args': {
- 'subscripts': {
- 'first': subscript_input,
- 'second': subscript_input,
- 'third': subscript_input,'id-03': subscript_input,
- 'id-04': subscript_input,
- 'id-05': subscript_input,
- 'id-06': subscript_input,
- 'id-07': subscript_input,
- 'id-08': subscript_input,
- 'id-09': subscript_input,
- 'id-10': subscript_input,
- 'id-11': subscript_input,
- 'id-12': subscript_input,
+ 'subasimmodules': {
+ 'first': subasimmodule_input,
+ 'second': subasimmodule_input,
+ 'third': subasimmodule_input,
+ 'id-03': subasimmodule_input,
}
}
}
@@ -173,12 +155,12 @@ def do_nothing_distributed_custom_name_sim_input():
return sim_input
@pytest.fixture
-def do_nothing_distributed_batch_sim_input():
+def lj_distributed_batch_sim_input():
'''
- Sim imput for a script that just completes without doing anything
+ Sim input for a distributed job that does some lj calculations
'''
- subscript_input = {
- 'script': 'singlepoint',
+ subasimmodule_input = {
+ 'asimmodule': 'singlepoint',
'env_id': 'inline',
'args': {
'calc_id': 'lj',
@@ -189,23 +171,14 @@ def do_nothing_distributed_batch_sim_input():
}
}
sim_input = {
- 'script': 'distributed',
+ 'asimmodule': 'workflows.distributed',
'env_id': 'batch',
'args': {
- 'subscripts': {
- 'id-00': subscript_input,
- 'id-01': subscript_input,
- 'id-02': subscript_input,
- 'id-03': subscript_input,
- 'id-04': subscript_input,
- 'id-05': subscript_input,
- 'id-06': subscript_input,
- 'id-07': subscript_input,
- 'id-08': subscript_input,
- 'id-09': subscript_input,
- 'id-10': subscript_input,
- 'id-11': subscript_input,
- 'id-12': subscript_input,
+ 'subasimmodules': {
+ 'id-0000': subasimmodule_input,
+ 'id-0001': subasimmodule_input,
+ 'id-0002': subasimmodule_input,
+ 'id-0003': subasimmodule_input,
}
}
}
diff --git a/tests/data/scripts/do_nothing_script.py b/tests/data/scripts/do_nothing_script.py
index 4f408d1..352377e 100644
--- a/tests/data/scripts/do_nothing_script.py
+++ b/tests/data/scripts/do_nothing_script.py
@@ -1,6 +1,6 @@
from asimtools.job import Job
-def do_nothing_script(calc_input, **kwargs):
+def do_nothing_asimmodule(calc_input, **kwargs):
''' Does nothing but creates input and output files '''
job = Job(calc_input, {})
job.start()
diff --git a/tests/data/structures/bad_Li.xyz b/tests/data/structures/bad_Li.xyz
new file mode 100644
index 0000000..e69de29
diff --git a/tests/scripts/test_asim_check.py b/tests/scripts/test_asim_check.py
new file mode 100644
index 0000000..1bee387
--- /dev/null
+++ b/tests/scripts/test_asim_check.py
@@ -0,0 +1,65 @@
+"""
+Tests for running asimmodules using asim_run.py
+"""
+from pathlib import Path
+from glob import glob
+import pytest
+from asimtools.utils import write_yaml
+from asimtools.job import create_unitjob
+from asimtools.job import load_job_from_directory
+from asimtools.scripts.asim_check import (
+ get_subjobs,
+ load_job_tree,
+)
+from asimtools.scripts.asim_check import parse_command_line
+
+@pytest.mark.parametrize("sim_input",["do_nothing_sim_input"])
+def test_parse_command_line(sim_input, tmp_path):
+ ''' Tests commandline argument parsing '''
+ sim_input_file = str(tmp_path / 'sim_input.yaml')
+ write_yaml(sim_input_file, sim_input)
+
+ sim_config_parse, rootdir = parse_command_line(
+ [sim_input_file]
+ )
+
+ assert sim_input == sim_config_parse
+ assert Path(rootdir) == Path(tmp_path)
+
+@pytest.mark.parametrize("calc_input",["lj_argon_calc_input"])
+@pytest.mark.parametrize("env_input",["inline_env_input"])
+@pytest.mark.parametrize("sim_input",["lj_distributed_sim_input"])
+def test_get_subjobs(env_input, calc_input, sim_input, tmp_path, request):
+ env_input = request.getfixturevalue(env_input)
+ calc_input = request.getfixturevalue(calc_input)
+ sim_input = request.getfixturevalue(sim_input)
+ wdir = tmp_path / 'wdir'
+ unitjob = create_unitjob(sim_input, env_input, wdir, calc_input=calc_input)
+ unitjob.submit()
+
+ dirs = glob(str(wdir / 'id*'))
+ assert len(dirs) == len(sim_input['args']['subasimmodules'])
+
+ ac_dirs = get_subjobs(wdir)
+ assert len(ac_dirs) == len(sim_input['args']['subasimmodules'])
+ for d in ac_dirs:
+ assert load_job_from_directory(d).get_status()[1] == 'complete'
+
+@pytest.mark.parametrize("calc_input",["lj_argon_calc_input"])
+@pytest.mark.parametrize("env_input",["inline_env_input"])
+@pytest.mark.parametrize("sim_input",["lj_distributed_sim_input"])
+def test_load_job_tree(env_input, calc_input, sim_input, tmp_path, request):
+ env_input = request.getfixturevalue(env_input)
+ calc_input = request.getfixturevalue(calc_input)
+ sim_input = request.getfixturevalue(sim_input)
+ wdir = tmp_path / 'wdir'
+ unitjob = create_unitjob(sim_input, env_input, wdir, calc_input=calc_input)
+ unitjob.submit()
+
+ jd = load_job_tree(wdir)
+ print(jd)
+ assert jd['workdir_name'] == 'wdir'
+ assert len(jd['subjobs']) == len(sim_input['args']['subasimmodules'])
+ for sj in jd['subjobs']:
+ assert jd['subjobs'][sj]['subjobs'] is None
+ assert jd['subjobs'][sj].get('workdir_name', False)
diff --git a/tests/scripts/test_asim_execute.py b/tests/scripts/test_asim_execute.py
index 3d3e6ab..7632f1e 100644
--- a/tests/scripts/test_asim_execute.py
+++ b/tests/scripts/test_asim_execute.py
@@ -1,3 +1,3 @@
"""
-Tests for running scripts using asim_run.py
+Tests for running asimmodules using asim_run.py
"""
diff --git a/tests/scripts/test_asim_run.py b/tests/scripts/test_asim_run.py
index 3fc82cb..4fa8c8f 100644
--- a/tests/scripts/test_asim_run.py
+++ b/tests/scripts/test_asim_run.py
@@ -1,10 +1,11 @@
"""
-Tests for running scripts using asim_run.py
+Tests for running asimmodules using asim_run.py
"""
import os
from pathlib import Path
import pytest
from asimtools.utils import write_yaml, read_yaml
+from asimtools.job import create_unitjob
from asimtools.scripts.asim_run import main as asim_run
from asimtools.scripts.asim_run import parse_command_line
@@ -30,7 +31,7 @@ def test_parse_command_line(sim_input, calc_input, tmp_path):
])
def test_asim_run(inputs, tmp_path, request):
'''
- Test asim_run ability to launch and complete a script using LJ
+ Test asim_run ability to launch and complete a asimmodule using LJ
'''
os.chdir(tmp_path)
sim_input = request.getfixturevalue(inputs[0])
@@ -55,7 +56,7 @@ def test_asim_run(inputs, tmp_path, request):
])
def test_asim_run_commands(inputs, tmp_path, request):
'''
- Test asim_run ability to launch and complete a script using LJ and running
+ Test asim_run ability to launch and complete a asimmodule using LJ and running
commands before and after running the function
'''
os.chdir(tmp_path)
diff --git a/tests/scripts/test_distributed.py b/tests/scripts/test_distributed.py
deleted file mode 100644
index c66b950..0000000
--- a/tests/scripts/test_distributed.py
+++ /dev/null
@@ -1,34 +0,0 @@
-"""
-Tests for running scripts using asim_run.py
-"""
-import os
-import glob
-from pathlib import Path
-import pytest
-from asimtools.utils import write_yaml
-from asimtools.scripts.asim_execute import main as asim_execute
-
-@pytest.mark.parametrize("inputs",[
- ['do_nothing_distributed_sim_input', None],
-])
-def test_distributed(inputs, tmp_path, request):
- '''
- Test distributed ability to launch and complete distributed jobs
- '''
- os.chdir(tmp_path)
- sim_input = request.getfixturevalue(inputs[0])
- sim_input_file = 'sim_input.yaml'
- write_yaml(sim_input_file, sim_input)
- args = [sim_input_file]
-
- if inputs[1] is not None:
- calc_input_file = 'calc_input.yaml'
- calc_input = request.getfixturevalue(inputs[1])
- write_yaml(calc_input_file, calc_input)
- args += ['-c', calc_input_file]
-
- asim_execute(args)
- print(str(Path(tmp_path) / 'id-00')+'*')
- print(glob.glob(str(Path(tmp_path))+'/*'))
-
- assert len(glob.glob(str(Path(tmp_path) / 'id-00')+'*')) == 1
diff --git a/tests/unit/test_job.py b/tests/unit/test_job.py
index 36736fa..7a490f1 100644
--- a/tests/unit/test_job.py
+++ b/tests/unit/test_job.py
@@ -4,8 +4,10 @@
#pylint: disable=missing-function-docstring
#pylint: disable=redefined-outer-name
+from pathlib import Path
import pytest
from asimtools.job import UnitJob
+from asimtools.utils import read_yaml
def create_unitjob(sim_input, env_input, workdir, calc_input=None):
"""Helper for making a generic UnitJob object"""
@@ -23,21 +25,32 @@ def create_unitjob(sim_input, env_input, workdir, calc_input=None):
return unitjob
@pytest.mark.parametrize("env_input",[
- "inline_env_input", "batch_env_input", "salloc_env_input"
+ "inline_env_input",
+ "batch_env_input",
+ "salloc_env_input",
+])
+@pytest.mark.parametrize("sim_input",[
+ "do_nothing_sim_input", "singlepoint_argon_sim_input"
])
-@pytest.mark.parametrize("sim_input",["do_nothing_sim_input"])
def test_gen_input_files(env_input, sim_input, tmp_path, request):
env_input = request.getfixturevalue(env_input)
sim_input = request.getfixturevalue(sim_input)
wdir = tmp_path / 'wdir'
unitjob = create_unitjob(sim_input, env_input, wdir)
- unitjob.gen_input_files()
+ unitjob.gen_input_files(write_env_input=True, write_calc_input=True)
assert wdir.exists()
assert (wdir / 'sim_input.yaml').exists()
assert (wdir / 'calc_input.yaml').exists()
assert (wdir / 'env_input.yaml').exists()
assert (wdir / 'output.yaml').exists()
+ assert Path(read_yaml(wdir / 'sim_input.yaml')['workdir']) == Path('./')
+
+ # Test that we always write the input atomic structures
+ if "image" in sim_input.get('args', {}).get('image', []):
+ assert (wdir / 'image_input.xyz').exists()
+ if "images" in sim_input.get('args', {}).get('images', []):
+ assert (wdir / 'images_input.xyz').exists()
@pytest.mark.parametrize("env_input",[
"inline_env_input", "batch_env_input", "salloc_env_input"
@@ -109,10 +122,10 @@ def test_submit(
else:
assert new_start_time == old_start_time
-def test_slurm_script(tmp_path):
+def test_slurm_asimmodule(tmp_path):
wdir = tmp_path / 'results'
sim_input = {
- 'script': 'do_nothing',
+ 'asimmodule': 'do_nothing',
'env_id': 'test_batch',
'workdir': wdir,
'args': {'calc_id': 'test_calc_id'},
@@ -145,19 +158,19 @@ def test_slurm_script(tmp_path):
with open(wdir / 'job.sh', 'r', encoding='utf-8') as f:
lines = f.readlines()
- jscript_txt = ' '.join(lines)
-
- assert '#SBATCH -N 1' in jscript_txt
- assert 'test_env_precommand1' in jscript_txt
- assert 'test_env_precommand2' in jscript_txt
- assert 'test_env_postcommand1' in jscript_txt
- assert 'test_env_postcommand2' in jscript_txt
- assert 'test_calc_precommand1' in jscript_txt
- assert 'test_calc_precommand2' in jscript_txt
- assert 'test_calc_postcommand1' in jscript_txt
- assert 'test_calc_postcommand2' in jscript_txt
- assert 'test_run_prefix' in jscript_txt
- assert 'test_run_suffix' in jscript_txt
+ jasimmodule_txt = ' '.join(lines)
+
+ assert '#SBATCH -N 1' in jasimmodule_txt
+ assert 'test_env_precommand1' in jasimmodule_txt
+ assert 'test_env_precommand2' in jasimmodule_txt
+ assert 'test_env_postcommand1' in jasimmodule_txt
+ assert 'test_env_postcommand2' in jasimmodule_txt
+ assert 'test_calc_precommand1' in jasimmodule_txt
+ assert 'test_calc_precommand2' in jasimmodule_txt
+ assert 'test_calc_postcommand1' in jasimmodule_txt
+ assert 'test_calc_postcommand2' in jasimmodule_txt
+ assert 'test_run_prefix' in jasimmodule_txt
+ assert 'test_run_suffix' in jasimmodule_txt
for line in lines:
if 'test_run_prefix' in line:
diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py
index c556d22..1ae2c7f 100644
--- a/tests/unit/test_utils.py
+++ b/tests/unit/test_utils.py
@@ -4,12 +4,20 @@
from pathlib import Path
import os
import pytest
+from ase.io import read
from asimtools.utils import (
join_names,
get_atoms,
get_images,
change_dict_value,
+ change_dict_values,
parse_slice,
+ write_yaml,
+ read_yaml,
+ get_env_input,
+ get_calc_input,
+ find_nth,
+ get_nth_label,
)
import ase.build
@@ -20,12 +28,12 @@
))
@pytest.mark.parametrize("test_input, expected",[
- (['a', 'b'],'a_b'),
- (['a', 'b', 'c'],'a_b_c'),
- (['_a', 'b.c'],'a_b.c'),
- (['a', '-b.--'],'a_b'),
- ([' ', '-b', 'c '],'b_c'),
- (['', 'b'],'b'),
+ (['a', 'b'],'a__b__'),
+ (['a', 'b', 'c'],'a__b__c__'),
+ (['_a', 'b.c'],'a__b.c__'),
+ (['a', '-b.--'],'a__b__'),
+ ([' ', '-b', 'c '],'b__c__'),
+ (['', 'b'],'b__'),
])
def test_join_names(test_input, expected):
''' Test join_names '''
@@ -59,19 +67,41 @@ def test_get_atoms(test_input, expected):
@pytest.mark.parametrize("test_input, expected",[
({'image_file': str(STRUCT_DIR / 'images.xyz')},
[ase.build.bulk('Ar'), ase.build.bulk('Cu'), ase.build.bulk('Fe')]),
+ ({'image_file': str(STRUCT_DIR / 'images.xyz'), 'index': ':2'},
+ [ase.build.bulk('Ar'), ase.build.bulk('Cu')]),
({'image_file': str(STRUCT_DIR / 'Li1.xyz')},
[ase.build.bulk('Li').repeat((1,1,1))]),
({'pattern': str(STRUCT_DIR / 'Li*.xyz')},
- [ase.build.bulk('Li').repeat((1,1,1)),
- ase.build.bulk('Li').repeat((2,2,2)),
- ase.build.bulk('Li').repeat((3,3,3))]),
+ [read(str(STRUCT_DIR / 'Li1.xyz')),
+ read(str(STRUCT_DIR / 'Li2.xyz')),
+ read(str(STRUCT_DIR / 'Li3.xyz'))]),
+ ({'pattern': str(STRUCT_DIR / '*Li*.xyz'), 'skip_failed': True},
+ [read(str(STRUCT_DIR / 'Li1.xyz')),
+ read(str(STRUCT_DIR / 'Li2.xyz')),
+ read(str(STRUCT_DIR / 'Li3.xyz'))]),
+ ({'patterns': [str(STRUCT_DIR / 'Li1.xyz'), str(STRUCT_DIR / 'images.xyz')]},
+ [read(str(STRUCT_DIR / 'Li1.xyz')),
+ ase.build.bulk('Ar'),
+ ase.build.bulk('Cu'),
+ ase.build.bulk('Fe')]),
+ ({'patterns': [
+ str(STRUCT_DIR / 'bad_Li.xyz'), str(STRUCT_DIR / 'images.xyz')
+ ], 'skip_failed': True},
+ [ase.build.bulk('Ar'), ase.build.bulk('Cu'), ase.build.bulk('Fe')]),
+ ({'patterns': [
+ str(STRUCT_DIR / 'Li1.xyz'), str(STRUCT_DIR / 'images.xyz')
+ ], 'index': -1},
+ [read(str(STRUCT_DIR / 'Li1.xyz')), ase.build.bulk('Fe')]),
({'images': [ase.build.bulk('Ar'), ase.build.bulk('Fe')]},
[ase.build.bulk('Ar'), ase.build.bulk('Fe')]),
])
def test_get_images(test_input, expected):
''' Test getting iterable of atoms from different inputs '''
print(get_images(**test_input), expected, '*********')
- assert get_images(**test_input) == expected
+ input_images = get_images(**test_input)
+ assert len(input_images) == len(expected)
+ for image in input_images:
+ assert image in expected
@pytest.mark.parametrize("test_input, expected",[
(['l1', 'l2', 'l3'], {'l1': {'l2': {'l3': 'new_value'}}}),
@@ -87,6 +117,23 @@ def test_change_dict_value(test_input, expected):
assert new_d == expected
assert new_d != d
+@pytest.mark.parametrize("test_input, expected",[
+ ([['l1', 'l21', 'l31'], ['l1', 'l21', 'l32']],
+ {'l1': {'l21': {'l31': 'v1', 'l32': 'v2'}, 'l22': 'l22v'}}),
+ ([['l1', 'l21', 'l31'], ['l1', 'l22']],
+ {'l1': {'l21': {'l31': 'v1'}, 'l22': 'v2'}}),
+ ([['l1', 'l21'], ['l1', 'l22']],
+ {'l1': {'l21': 'v1', 'l22': 'v2'}}),
+])
+def test_change_dict_values(test_input, expected):
+ ''' Test getting iterable of atoms from different inputs '''
+ d = {'l1': {'l21': {'l31': 'l31v'}, 'l22': 'l22v'}}
+ new_d = change_dict_values(
+ d, ['v1', 'v2'], test_input, return_copy=True
+ )
+ assert new_d == expected
+ assert new_d != d
+
@pytest.mark.parametrize("test_input, expected",[
(':', slice(None, None, None)),
('1:', slice(1, None, None)),
@@ -97,6 +144,53 @@ def test_change_dict_value(test_input, expected):
])
def test_parse_slice(test_input, expected):
''' Test parsing a slice '''
-
assert parse_slice(test_input) == expected
+def test_write_and_read_yaml(tmp_path):
+ d = {'test_key': 'test_value'}
+ yaml_file = tmp_path / 'test.yaml'
+ write_yaml(yaml_file, d)
+ assert yaml_file.exists()
+ read_d = read_yaml(yaml_file)
+ assert read_d == d
+
+def test_get_env_input(tmp_path):
+ cur_env_input = os.environ.get('ASIMTOOLS_ENV_INPUT', None)
+ test_env_input = tmp_path / 'test_env_input.yaml'
+ d = {'test_env': {'mode': {'slurm': False, 'interactive': True}}}
+ write_yaml(test_env_input, d)
+ os.environ['ASIMTOOLS_ENV_INPUT'] = str(test_env_input)
+ env_input = get_env_input()
+ os.environ['ASIMTOOLS_ENV_INPUT'] = cur_env_input
+ assert env_input == d
+
+def test_get_calc_input(tmp_path):
+ cur_calc_input = os.environ.get('ASIMTOOLS_CALC_INPUT', None)
+ test_calc_input = tmp_path / 'test_calc_input.yaml'
+ d = {'test_calc': {
+ 'name': 'EMT', 'module': 'ase.calculators.emt', 'args': {}
+ }}
+ write_yaml(test_calc_input, d)
+ os.environ['ASIMTOOLS_CALC_INPUT'] = str(test_calc_input)
+ calc_input = get_calc_input()
+ os.environ['ASIMTOOLS_CALC_INPUT'] = cur_calc_input
+ assert calc_input == d
+
+@pytest.mark.parametrize("test_input, expected",[
+ (1, 0),
+ (2, 7),
+ (3, 13),
+])
+def test_find_nth(test_input, expected):
+ ''' Find nth occurence of substring in string '''
+ s = 'measdfamesdfamebtnrtyh'
+ assert find_nth(s, 'me', test_input) == expected
+
+@pytest.mark.parametrize("test_input, expected",[
+ (1, 'label2'),
+ (0, 'label1'),
+])
+def test_get_nth_label(test_input, expected):
+ ''' Find nth label in string '''
+ s = '/path/to/array/id-00__label1__/id-0045__label2__'
+ assert get_nth_label(s, test_input) == expected