Skip to content

Commit fdcd63f

Browse files
JaGeojanosh
andauthored
Improve documentation LOBSTER and PHONON workflow (#1117)
* add info on jobflow remote and lobster workflow * remove file and fix linting * add another phonon example * add tutorial for phonons including mock_vasp * add tutorial test * test tutorial test * test tutorial test * test tutorial test * test tutorial test * split up workflow again * split up workflow again * split up workflow again * split up workflow again * add automerge * add automerge * add mock lobster and a lobster tutorial * fix bug in tutorial and fix calc summary * add plot * fix linting * fix linting * more type hints * fix linting * fix linting * fix linting * fix linting * fix more linting * fix final linting * Update pyproject.toml * adapt tutorial * fix linting and add a tmp dir to tutorial execution * remove file * print ref and actual values in testing.lobster.verify_inputs ValueError --------- Co-authored-by: Janosh Riebesell <[email protected]>
1 parent e6231ad commit fdcd63f

File tree

11 files changed

+1030
-206
lines changed

11 files changed

+1030
-206
lines changed

.github/workflows/testing.yml

+78-2
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ jobs:
8989
micromamba activate a2
9090
pytest --splits 3 --group ${{ matrix.split }} --durations-path tests/.pytest-split-durations --splitting-algorithm least_duration --ignore=tests/ase --cov=atomate2 --cov-report=xml
9191
92+
9293
- uses: codecov/codecov-action@v1
9394
if: matrix.python-version == '3.10' && github.repository == 'materialsproject/atomate2'
9495
with:
@@ -150,7 +151,7 @@ jobs:
150151
- name: Test Notebooks
151152
run: |
152153
micromamba activate a2
153-
pytest --nbmake ./tutorials --ignore=./tutorials/openmm_tutorial.ipynb
154+
pytest --nbmake ./tutorials --ignore=./tutorials/openmm_tutorial.ipynb --ignore=./tutorials/force_fields
154155
155156
- name: Test ASE
156157
env:
@@ -165,6 +166,81 @@ jobs:
165166
token: ${{ secrets.CODECOV_TOKEN }}
166167
file: ./coverage.xml
167168

169+
test-force-field-notebook:
170+
# prevent this action from running on forks
171+
if: github.repository == 'materialsproject/atomate2'
172+
173+
services:
174+
local_mongodb:
175+
image: mongo:4.0
176+
ports:
177+
- 27017:27017
178+
179+
runs-on: ubuntu-latest
180+
defaults:
181+
run:
182+
shell: bash -l {0} # enables conda/mamba env activation by reading bash profile
183+
strategy:
184+
matrix:
185+
python-version: ["3.10", "3.11", "3.12"]
186+
187+
steps:
188+
- name: Check out repo
189+
uses: actions/checkout@v4
190+
191+
- name: Set up micromamba
192+
uses: mamba-org/setup-micromamba@main
193+
194+
- name: Create mamba environment
195+
run: |
196+
micromamba create -n a2 python=${{ matrix.python-version }} --yes
197+
198+
- name: Install uv
199+
run: micromamba run -n a2 pip install uv
200+
201+
- name: Install conda dependencies
202+
run: |
203+
micromamba install -n a2 -c conda-forge enumlib packmol bader openbabel openff-toolkit==0.16.2 openff-interchange==0.3.22 --yes
204+
205+
- name: Install dependencies
206+
run: |
207+
micromamba activate a2
208+
python -m pip install --upgrade pip
209+
mkdir -p ~/.abinit/pseudos
210+
cp -r tests/test_data/abinit/pseudos/ONCVPSP-PBE-SR-PDv0.4 ~/.abinit/pseudos
211+
uv pip install .[strict,strict-forcefields,tests,abinit]
212+
uv pip install torch-runstats
213+
uv pip install --no-deps nequip==0.5.6
214+
215+
- name: Install pymatgen from master if triggered by pymatgen repo dispatch
216+
if: github.event_name == 'repository_dispatch' && github.event.action == 'pymatgen-ci-trigger'
217+
run: |
218+
micromamba activate a2
219+
uv pip install --upgrade 'git+https://github.com/materialsproject/pymatgen@${{ github.event.client_payload.pymatgen_ref }}'
220+
221+
- name: Forcefield tutorial
222+
env:
223+
MP_API_KEY: ${{ secrets.MP_API_KEY }}
224+
225+
# regenerate durations file with `pytest --store-durations --durations-path tests/.pytest-split-durations`
226+
# Note the use of `--splitting-algorithm least_duration`.
227+
# This helps prevent a test split having no tests to run, and then the GH action failing, see:
228+
# https://github.com/jerry-git/pytest-split/issues/95
229+
# However this `splitting-algorithm` means that tests cannot depend sensitively on the order they're executed in.
230+
run: |
231+
micromamba activate a2
232+
pytest --nbmake ./tutorials/force_fields
233+
234+
235+
- uses: codecov/codecov-action@v1
236+
if: matrix.python-version == '3.10' && github.repository == 'materialsproject/atomate2'
237+
with:
238+
token: ${{ secrets.CODECOV_TOKEN }}
239+
name: coverage
240+
file: ./coverage.xml
241+
242+
243+
168244
docs:
169245
runs-on: ubuntu-latest
170246

@@ -186,7 +262,7 @@ jobs:
186262
run: sphinx-build docs docs_build
187263

188264
automerge:
189-
needs: [lint, test-non-ase, test-notebooks-and-ase, docs]
265+
needs: [lint, test-non-ase, test-notebooks-and-ase, test-force-field-notebook, docs]
190266
runs-on: ubuntu-latest
191267

192268
permissions:

docs/user/codes/vasp.md

+108-38
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,25 @@ adjust them if necessary. The default might not be strict enough
248248
for your specific case.
249249
```
250250

251+
You can use the following code to start the standard version of the workflow:
252+
```py
253+
from atomate2.vasp.flows.phonons import PhononMaker
254+
from pymatgen.core.structure import Structure
255+
256+
structure = Structure(
257+
lattice=[[0, 2.13, 2.13], [2.13, 0, 2.13], [2.13, 2.13, 0]],
258+
species=["Mg", "O"],
259+
coords=[[0, 0, 0], [0.5, 0.5, 0.5]],
260+
)
261+
262+
phonon_flow = PhononMaker(min_length=15.0, store_force_constants=False).make(
263+
structure=struct
264+
)
265+
```
266+
267+
268+
269+
251270
### Gruneisen parameter workflow
252271

253272
Calculates mode-dependent Grüneisen parameters with the help of Phonopy.
@@ -352,8 +371,85 @@ lobster = update_user_incar_settings(lobster, {"NPAR": 4})
352371
run_locally(lobster, create_folders=True, store=SETTINGS.JOB_STORE)
353372
```
354373

355-
It is, however, computationally very beneficial to define two different types of job scripts for the VASP and Lobster runs, as VASP and Lobster runs are parallelized differently (MPI vs. OpenMP).
356-
[FireWorks](https://github.com/materialsproject/fireworks) allows one to run the VASP and Lobster jobs with different job scripts. Please check out the [jobflow documentation on FireWorks](https://materialsproject.github.io/jobflow/tutorials/8-fireworks.html#setting-the-manager-configs) for more information.
374+
There are currently three different ways available to run the workflow efficiently, as VASP and LOBSTER rely on a different parallelization (MPI vs. OpenMP).
375+
One can use a job script (with some restrictions), or [Jobflow-remote](https://matgenix.github.io/jobflow-remote/) / [Fireworks](https://github.com/materialsproject/fireworks) for high-throughput runs.
376+
377+
378+
#### Running the LOBSTER workflow without database and with one job script only
379+
380+
It is possible to run the VASP-LOBSTER workflow efficiently with a minimal setup.
381+
In this case, you will run the VASP calculations on the same node as the LOBSTER calculations.
382+
In between, the different computations you will switch from MPI to OpenMP parallelization.
383+
384+
For example, for a node with 48 cores, you could use an adapted version of the following SLURM script:
385+
386+
```bash
387+
#!/bin/bash
388+
#SBATCH -J vasplobsterjob
389+
#SBATCH -o ./%x.%j.out
390+
#SBATCH -e ./%x.%j.err
391+
#SBATCH -D ./
392+
#SBATCH --mail-type=END
393+
394+
#SBATCH --time=24:00:00
395+
#SBATCH --nodes=1
396+
#This needs to be adapted if you run with different cores
397+
#SBATCH --ntasks=48
398+
399+
# ensure you load the modules to run VASP, e.g., module load vasp
400+
module load my_vasp_module
401+
# please activate the required conda environment
402+
conda activate my_environment
403+
cd my_folder
404+
# the following script needs to contain the workflow
405+
python xyz.py
406+
```
407+
408+
The `LOBSTER_CMD` now needs an additional export of the number of threads.
409+
410+
```yaml
411+
VASP_CMD: <<VASP_CMD>>
412+
LOBSTER_CMD: OMP_NUM_THREADS=48 <<LOBSTER_CMD>>
413+
```
414+
415+
416+
#### Jobflow-remote
417+
Please refer first to the general documentation of jobflow-remote: [https://matgenix.github.io/jobflow-remote/](https://matgenix.github.io/jobflow-remote/).
418+
419+
```py
420+
from atomate2.vasp.flows.lobster import VaspLobsterMaker
421+
from pymatgen.core.structure import Structure
422+
from jobflow_remote import submit_flow, set_run_config
423+
from atomate2.vasp.powerups import update_user_incar_settings
424+
425+
structure = Structure(
426+
lattice=[[0, 2.13, 2.13], [2.13, 0, 2.13], [2.13, 2.13, 0]],
427+
species=["Mg", "O"],
428+
coords=[[0, 0, 0], [0.5, 0.5, 0.5]],
429+
)
430+
431+
lobster = VaspLobsterMaker().make(structure)
432+
433+
resources = {"nodes": 3, "partition": "micro", "time": "00:55:00", "ntasks": 144}
434+
435+
resources_lobster = {"nodes": 1, "partition": "micro", "time": "02:55:00", "ntasks": 48}
436+
lobster = set_run_config(lobster, name_filter="lobster", resources=resources_lobster)
437+
438+
lobster = update_user_incar_settings(lobster, {"NPAR": 4})
439+
submit_flow(lobster, worker="my_worker", resources=resources, project="my_project")
440+
```
441+
442+
The `LOBSTER_CMD` also needs an export of the threads.
443+
444+
```yaml
445+
VASP_CMD: <<VASP_CMD>>
446+
LOBSTER_CMD: OMP_NUM_THREADS=48 <<LOBSTER_CMD>>
447+
```
448+
449+
450+
451+
#### Fireworks
452+
Please first refer to the general documentation on running atomate2 workflows with fireworks: [https://materialsproject.github.io/atomate2/user/fireworks.html](https://materialsproject.github.io/atomate2/user/fireworks.html)
357453
358454
Specifically, you might want to change the `_fworker` for the LOBSTER runs and define a separate `lobster` worker within FireWorks:
359455

@@ -389,6 +485,16 @@ lpad = LaunchPad.auto_load()
389485
lpad.add_wf(wf)
390486
```
391487

488+
489+
The `LOBSTER_CMD` can now be adapted to not include the number of threads:
490+
491+
```yaml
492+
VASP_CMD: <<VASP_CMD>>
493+
LOBSTER_CMD: <<LOBSTER_CMD>>
494+
```
495+
496+
#### Analyzing outputs
497+
392498
Outputs from the automatic analysis with LobsterPy can easily be extracted from the database and also plotted:
393499

394500
```py
@@ -425,42 +531,6 @@ for number, (key, cohp) in enumerate(
425531
plotter.save_plot(f"plots_cation_anion_bonds{number}.pdf")
426532
```
427533

428-
#### Running the LOBSTER workflow without database and with one job script only
429-
430-
It is also possible to run the VASP-LOBSTER workflow with a minimal setup.
431-
In this case, you will run the VASP calculations on the same node as the LOBSTER calculations.
432-
In between, the different computations you will switch from MPI to OpenMP parallelization.
433-
434-
For example, for a node with 48 cores, you could use an adapted version of the following SLURM script:
435-
436-
```bash
437-
#!/bin/bash
438-
#SBATCH -J vasplobsterjob
439-
#SBATCH -o ./%x.%j.out
440-
#SBATCH -e ./%x.%j.err
441-
#SBATCH -D ./
442-
#SBATCH --mail-type=END
443-
444-
#SBATCH --time=24:00:00
445-
#SBATCH --nodes=1
446-
#This needs to be adapted if you run with different cores
447-
#SBATCH --ntasks=48
448-
449-
# ensure you load the modules to run VASP, e.g., module load vasp
450-
module load my_vasp_module
451-
# please activate the required conda environment
452-
conda activate my_environment
453-
cd my_folder
454-
# the following script needs to contain the workflow
455-
python xyz.py
456-
```
457-
458-
The `LOBSTER_CMD` now needs an additional export of the number of threads.
459-
460-
```yaml
461-
VASP_CMD: <<VASP_CMD>>
462-
LOBSTER_CMD: OMP_NUM_THREADS=48 <<LOBSTER_CMD>>
463-
```
464534

465535
(modifying_input_sets)=
466536
Modifying input sets

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ strict = [
123123
strict-forcefields = [
124124
"calorine==3.0",
125125
"chgnet==0.4.0",
126-
"mace-torch>=0.3.6",
126+
"mace-torch==0.3.10",
127127
"matgl==1.1.3",
128128
"quippy-ase==0.9.14; python_version < '3.12'",
129129
"sevenn==0.10.3",

src/atomate2/lobster/schemas.py

+30-29
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ def from_directory(
597597
"bva_comp": True,
598598
**calc_quality_kwargs,
599599
}
600+
600601
cal_quality_dict = Analysis.get_lobster_calc_quality_summary(
601602
path_to_poscar=structure_path,
602603
path_to_vasprun=vasprun_path,
@@ -844,34 +845,32 @@ def from_directory(
844845
calc_quality_text = None
845846
describe = None
846847
describe_ionic = None
847-
if analyze_outputs:
848-
if (
849-
icohplist_path.exists()
850-
and cohpcar_path.exists()
851-
and charge_path.exists()
852-
):
853-
(
854-
condensed_bonding_analysis,
855-
describe,
856-
sb_all,
857-
) = CondensedBondingAnalysis.from_directory(
858-
dir_name,
859-
save_cohp_plots=save_cohp_plots,
860-
plot_kwargs=plot_kwargs,
861-
lobsterpy_kwargs=lobsterpy_kwargs,
862-
which_bonds="all",
863-
)
864-
(
865-
condensed_bonding_analysis_ionic,
866-
describe_ionic,
867-
sb_ionic,
868-
) = CondensedBondingAnalysis.from_directory(
869-
dir_name,
870-
save_cohp_plots=save_cohp_plots,
871-
plot_kwargs=plot_kwargs,
872-
lobsterpy_kwargs=lobsterpy_kwargs,
873-
which_bonds="cation-anion",
874-
)
848+
849+
if analyze_outputs and (
850+
icohplist_path.exists() and cohpcar_path.exists() and charge_path.exists()
851+
):
852+
(
853+
condensed_bonding_analysis,
854+
describe,
855+
sb_all,
856+
) = CondensedBondingAnalysis.from_directory(
857+
dir_name,
858+
save_cohp_plots=save_cohp_plots,
859+
plot_kwargs=plot_kwargs,
860+
lobsterpy_kwargs=lobsterpy_kwargs,
861+
which_bonds="all",
862+
)
863+
(
864+
condensed_bonding_analysis_ionic,
865+
describe_ionic,
866+
sb_ionic,
867+
) = CondensedBondingAnalysis.from_directory(
868+
dir_name,
869+
save_cohp_plots=save_cohp_plots,
870+
plot_kwargs=plot_kwargs,
871+
lobsterpy_kwargs=lobsterpy_kwargs,
872+
which_bonds="cation-anion",
873+
)
875874
# Get lobster calculation quality summary data
876875

877876
calc_quality_summary = CalcQualitySummary.from_directory(
@@ -971,7 +970,9 @@ def from_directory(
971970
if describe_ionic is not None
972971
else None,
973972
strongest_bonds_cation_anion=sb_ionic,
974-
calc_quality_summary=calc_quality_summary,
973+
calc_quality_summary=calc_quality_summary
974+
if calc_quality_summary is not None
975+
else None,
975976
calc_quality_text=" ".join(calc_quality_text)
976977
if calc_quality_text is not None
977978
else None,

0 commit comments

Comments
 (0)