Repository: Quantum-Accelerators/quacc
Pull request #1379 (2023-12-16 18:32:36)

Espresso: improved preset handler + more presets
## Requirements

### Checklist

- [x] I have read the [Contributing Guide](https://quantum-accelerators.github.io/quacc/dev/contributing.html). Don't lie! 😉
- [x] My PR is on a custom branch and is _not_ named `main`.
- [ ] I have added relevant unit tests.

### Notes

- Your PR will likely not be merged without proper and thorough tests, even if it's for a "simple" fix.
- If you are an external contributor, you will see a comment from [@buildbot-princeton](https://github.com/buildbot-princeton). This is solely for the maintainers.
- When your code is ready for review, ping one of the [active maintainers](https://quantum-accelerators.github.io/quacc/about/contributors.html#active-maintainers).

## Summary of Changes

More presets for the espresso calculator, I am not done yet but I open this PR to discuss a little bit more about presets. For now I created new presets for specific cases (metals, semiconductors) where I copied the pseudopotentials part from the previous two presets.

Should it be possible for the user to specify more than one preset i.e:

``` python

(..., preset = 'my-param-preset, pseudopotentials = 'my-pp-preset', ...)
(..., presets = ['my-param-preset, 'my-pp-preset'], ...)
(..., preset = 'my-big-preset-containing-both--pp--and-param', ...)

```

buildbot-princeton: Can one of the admins verify this patch?
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/Quantum-Accelerators/quacc/pull/1379?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Quantum-Accelerators) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Comparison is base [(`6bd21e6`)](https://app.codecov.io/gh/Quantum-Accelerators/quacc/commit/6bd21e63a760841f517792e78edb7bfa1b9d1cba?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Quantum-Accelerators) 98.90% compared to head [(`d6a6002`)](https://app.codecov.io/gh/Quantum-Accelerators/quacc/pull/1379?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Quantum-Accelerators) 98.91%.
> Report is 15 commits behind head on main.


<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main    #1379   +/-   ##
=======================================
  Coverage   98.90%   98.91%           
=======================================
  Files          76       76           
  Lines        2935     2951   +16     
=======================================
+ Hits         2903     2919   +16     
  Misses         32       32           
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/Quantum-Accelerators/quacc/pull/1379?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Quantum-Accelerators).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Quantum-Accelerators).

tomdemeyere: Thanks for the info, indeed the 'parent' mechanism is all I was looking for, I used it in pretty much every new presets. As you will see I changed the function the parse_pp_and_cutoff in espresso.utils to reflect the new changes in presets.

Something you might not like is the new ability to modify the Atoms object directly by a preset, If not I can probably find another way to do what I want.

I added a test to make sure everything is working correctly and that the priority between calc_default, user defined kwargs and presets kwargs is respected.
Andrew-S-Rosen: @tomdemeyere: Great! Glad that feature could help streamline things.

Would you be able to walk me through the logic for having the `pbc: [True, True, True]` in the preset? Maybe once I understand the context a bit more, I can help make a suggestion that is a bit less roundabout. It would indeed be nice to mess with the `Atoms` object if possible, but more-so I am looking to understand the use case you have in mind.  
tomdemeyere: Specifying pbc: [True, True, **False**] would make things work better with ase.io.write_espresso_in for example. If you specify the kspacing (which is a single float), the k-grid generated with the specified pbc's would have no k-point along the third dimension.

This is completely avoidable, for example by manually calling the function kspacing_to_grid from ase as a workaround. I just thought that changing Atoms inside presets might be an interesting idea that you might want to hear about, but after second thoughts changing it might raise a few other problems
Andrew-S-Rosen: Ah thanks for clarifying! Yeah, I think I'd prefer this to be taken care of outside the presets. After all, the user may set no preset and also this behavior is not immediately obvious to a new user. In general, I like to abide by the principle of least surprise. Let's keep setups to just input parameters to the calculator. 
tomdemeyere: @Andrew-S-Rosen Presets still contains atoms_info but it is not used to modify the Atoms object, instead, it creates an atoms copy and calls spacing_to_grid manually.

Creating an entire copy might be overkill for now, but will be useful in the future if other checks are performed

This should be pretty good to go as it is, I suspect there are some details you might want to check
Andrew-S-Rosen: > @Andrew-S-Rosen Presets still contains atoms_info but it is not used to modify the Atoms object, instead, it creates an atoms copy and calls spacing_to_grid manually.
> 
> Creating an entire copy might be overkill for now, but will be useful in the future if other checks are performed
> 
> This should be pretty good to go as it is, I suspect there are some details you might want to check
> 
> EDIT: re-reading your last comment I realise you probably want no "atoms_info" in presets at all, I will find a way to delete them

Thanks for the update!

One option that you might prefer is to create a separate module called `slabs.py` where the default preset is set to one of your slab presets, and in that recipe you could also set `atoms.pbc` as needed. See the [analogous module for VASP](https://github.com/Quantum-Accelerators/quacc/blob/main/src/quacc/recipes/vasp/slabs.py). This is entirely optional though. I just wanted to let you know of an alternate way to think about this.

Regarding the atoms info, a reason that I'm not a huge fan of the `atoms_info` key in the YAML file is that it is effectively a hidden feature. I try to ensure that the YAML parameters have 1:1 correspondence with calculator parameters, so it's obvious what can and can't be set. Here, the YAML is supporting some "hidden convenience magic". Also, one might think it would be `atoms.info` that is being set when in reality, that's not the case.

I'm not sure off-hand if there are other parameters behaving similarly, e.g. `kspacing`. If there are any parameters set in the YAML that are not direct arguments for the calculator, please take a moment to add them as defined, optional keyword arguments to the `Espresso` class that way they are documented and more generic.

Otherwise, this looks good and I'm happy to merge once that minor detail is sorted out. Thank you!

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4de2817b..ccd49479 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 
 ### Changed
 
+- Changed default `fmax` for `quacc.recipes.mlp.core.relax_job` to 0.05
+- Changed default `dtype` to `"float64"` when using `method="mace"` in `quacc.recipes.mlp.core.relax_job`
 - Renamed the `quacc.utils.dicts.merge_dicts` function to `._recursive_dict_pair_merge` to better reflect its functionality.
 - Renamed the `quacc.utils.dicts.merge_several_dicts` function to `.recursive_dict_merge` to better reflect its functionality.
 
diff --git a/src/quacc/calculators/espresso/espresso.py b/src/quacc/calculators/espresso/espresso.py
index 52d79419..d135551d 100644
--- a/src/quacc/calculators/espresso/espresso.py
+++ b/src/quacc/calculators/espresso/espresso.py
@@ -4,6 +4,7 @@ import os
 from pathlib import Path
 from typing import TYPE_CHECKING
 
+from ase import Atoms
 from ase.calculators.espresso import Espresso as Espresso_
 from ase.calculators.espresso import EspressoProfile
 from ase.calculators.espresso import EspressoTemplate as EspressoTemplate_
@@ -12,15 +13,13 @@ from ase.io.espresso import construct_namelist
 from quacc import SETTINGS
 from quacc.calculators.espresso.io import read, write
 from quacc.calculators.espresso.keys import ALL_KEYS
-from quacc.calculators.espresso.utils import parse_pp_and_cutoff
+from quacc.calculators.espresso.utils import parse_pw_preset
 from quacc.utils.dicts import recursive_dict_merge
 from quacc.utils.files import load_yaml_calc
 
 if TYPE_CHECKING:
     from typing import Any
 
-    from ase import Atoms
-
 
 class EspressoTemplate(EspressoTemplate_):
     """
@@ -216,8 +215,8 @@ class Espresso(Espresso_):
         None
         """
         self.preset = preset
-        self.input_atoms = input_atoms
-        self.calc_defaults = calc_defaults
+        self.input_atoms = input_atoms or Atoms()
+        self.calc_defaults = calc_defaults or {}
 
         template = template or EspressoTemplate("pw")
 
@@ -265,11 +264,28 @@ class Espresso(Espresso_):
         keys = ALL_KEYS[binary]
         kwargs["input_data"] = construct_namelist(kwargs.get("input_data"), keys=keys)
         self.calc_defaults["input_data"] = construct_namelist(
-            self.calc_defaults["input_data"], keys=keys
+            self.calc_defaults.get("input_data"), keys=keys
         )
 
+        kpts = kwargs.get("kpts")
+        kspacing = kwargs.get("kspacing")
+
+        if kpts and kspacing:
+            raise ValueError("Cannot specify both kpts and kspacing.")
+
         if self.preset:
             config = load_yaml_calc(SETTINGS.ESPRESSO_PRESET_DIR / f"{self.preset}")
-            preset_pp = parse_pp_and_cutoff(config, self.input_atoms)
-            kwargs = recursive_dict_merge(preset_pp, kwargs)
-        return recursive_dict_merge(self.calc_defaults, kwargs)
+            preset = parse_pw_preset(config, self.input_atoms)
+            kwargs = recursive_dict_merge(preset, kwargs)
+
+        if kpts:
+            kwargs.pop("kspacing", None)
+        elif kspacing:
+            kwargs.pop("kpts", None)
+
+        kwargs = recursive_dict_merge(self.calc_defaults, kwargs)
+
+        if kwargs.get("kpts") == "gamma":
+            kwargs["kpts"] = None
+
+        return kwargs
diff --git a/src/quacc/calculators/espresso/presets/esm_metal_slab_efficiency.yaml b/src/quacc/calculators/espresso/presets/esm_metal_slab_efficiency.yaml
new file mode 100644
index 00000000..b7671920
--- /dev/null
+++ b/src/quacc/calculators/espresso/presets/esm_metal_slab_efficiency.yaml
@@ -0,0 +1,15 @@
+# Last modified: 12-23-2023
+
+input_data:
+  system:
+    occupations: smearing
+    smearing: marzari-vanderbilt
+    degauss: 0.01
+    assume_isolated: esm
+    esm_bc: bc1
+  electrons:
+    conv_thr: 1.0e-9
+    mixing_mode: local-TF
+    mixing_beta: 0.35
+
+parent_pseudopotentials: sssp_1.3.0_pbe_efficiency.yaml
\ No newline at end of file
diff --git a/src/quacc/calculators/espresso/presets/esm_metal_slab_precision.yaml b/src/quacc/calculators/espresso/presets/esm_metal_slab_precision.yaml
new file mode 100644
index 00000000..6c9e1cbd
--- /dev/null
+++ b/src/quacc/calculators/espresso/presets/esm_metal_slab_precision.yaml
@@ -0,0 +1,15 @@
+# Last modified: 12-23-2023
+
+input_data:
+  system:
+    occupations: smearing
+    smearing: marzari-vanderbilt
+    degauss: 0.005
+    assume_isolated: esm
+    esm_bc: bc1
+  electrons:
+    conv_thr: 1.0e-10
+    mixing_mode: local-TF
+    mixing_beta: 0.35
+
+parent_pseudopotentials: sssp_1.3.0_pbe_precision.yaml
\ No newline at end of file
diff --git a/src/quacc/calculators/espresso/presets/esm_semiconductors_slab_efficiency.yaml b/src/quacc/calculators/espresso/presets/esm_semiconductors_slab_efficiency.yaml
new file mode 100644
index 00000000..203513fc
--- /dev/null
+++ b/src/quacc/calculators/espresso/presets/esm_semiconductors_slab_efficiency.yaml
@@ -0,0 +1,15 @@
+# Last modified: 12-23-2023
+
+input_data:
+  system:
+    occupations: smearing
+    smearing: gaussian
+    degauss: 0.005
+    assume_isolated: esm
+    esm_bc: bc1
+  electrons:
+    conv_thr: 1.0e-8
+    mixing_mode: local-TF
+    mixing_beta: 0.25
+
+parent_pseudopotentials: sssp_1.3.0_pbe_efficiency.yaml
\ No newline at end of file
diff --git a/src/quacc/calculators/espresso/presets/esm_semiconductors_slab_precision.yaml b/src/quacc/calculators/espresso/presets/esm_semiconductors_slab_precision.yaml
new file mode 100644
index 00000000..5a5d776f
--- /dev/null
+++ b/src/quacc/calculators/espresso/presets/esm_semiconductors_slab_precision.yaml
@@ -0,0 +1,15 @@
+# Last modified: 12-23-2023
+
+input_data:
+  system:
+    occupations: smearing
+    smearing: gaussian
+    degauss: 0.005
+    assume_isolated: esm
+    esm_bc: bc1
+  electrons:
+    conv_thr: 1.0e-9
+    mixing_mode: local-TF
+    mixing_beta: 0.25
+
+parent_pseudopotentials: sssp_1.3.0_pbe_precision.yaml
\ No newline at end of file
diff --git a/src/quacc/calculators/espresso/presets/metal_efficiency.yaml b/src/quacc/calculators/espresso/presets/metal_efficiency.yaml
new file mode 100644
index 00000000..1a83eab5
--- /dev/null
+++ b/src/quacc/calculators/espresso/presets/metal_efficiency.yaml
@@ -0,0 +1,15 @@
+# Last modified: 12-18-2023
+
+input_data:
+  system:
+    occupations: smearing
+    smearing: marzari-vanderbilt
+    degauss: 0.01
+  electrons:
+    conv_thr: 1.0e-10
+    mixing_mode: TF
+    mixing_beta: 0.7
+
+kspacing: 0.03
+
+parent_pseudopotentials: sssp_1.3.0_pbe_efficiency.yaml
\ No newline at end of file
diff --git a/src/quacc/calculators/espresso/presets/metal_precision.yaml b/src/quacc/calculators/espresso/presets/metal_precision.yaml
new file mode 100644
index 00000000..7c80c787
--- /dev/null
+++ b/src/quacc/calculators/espresso/presets/metal_precision.yaml
@@ -0,0 +1,15 @@
+# Last modified: 12-18-2023
+
+input_data:
+  system:
+    occupations: smearing
+    smearing: marzari-vanderbilt
+    degauss: 0.005
+  electrons:
+    conv_thr: 1.0e-12
+    mixing_mode: TF
+    mixing_beta: 0.7
+
+kspacing: 0.015
+
+parent_pseudopotentials: sssp_1.3.0_pbe_precision.yaml
\ No newline at end of file
diff --git a/src/quacc/calculators/espresso/presets/molecule_efficiency.yaml b/src/quacc/calculators/espresso/presets/molecule_efficiency.yaml
new file mode 100644
index 00000000..54794d8c
--- /dev/null
+++ b/src/quacc/calculators/espresso/presets/molecule_efficiency.yaml
@@ -0,0 +1,14 @@
+# Last modified: 12-18-2023
+
+input_data:
+  system:
+    occupations: fixed
+    assume_isolated: martyna-tuckerman
+  electrons:
+    conv_thr: 1.0e-9
+    mixing_mode: local-TF
+    mixing_beta: 0.35
+
+kpts: gamma
+
+parent_pseudopotentials: sssp_1.3.0_pbe_efficiency.yaml
\ No newline at end of file
diff --git a/src/quacc/calculators/espresso/presets/semiconductors_efficiency.yaml b/src/quacc/calculators/espresso/presets/semiconductors_efficiency.yaml
new file mode 100644
index 00000000..7960a6d2
--- /dev/null
+++ b/src/quacc/calculators/espresso/presets/semiconductors_efficiency.yaml
@@ -0,0 +1,15 @@
+# Last modified: 12-18-2023
+
+input_data:
+  system:
+    occupations: smearing
+    smearing: gaussian
+    degauss: 0.005
+  electrons:
+    conv_thr: 1.0e-10
+    mixing_mode: local-TF
+    mixing_beta: 0.6
+
+kspacing: 0.045
+
+parent_pseudopotentials: sssp_1.3.0_pbe_efficiency.yaml
\ No newline at end of file
diff --git a/src/quacc/calculators/espresso/presets/semiconductors_precision.yaml b/src/quacc/calculators/espresso/presets/semiconductors_precision.yaml
new file mode 100644
index 00000000..b9ee1988
--- /dev/null
+++ b/src/quacc/calculators/espresso/presets/semiconductors_precision.yaml
@@ -0,0 +1,15 @@
+# Last modified: 12-18-2023
+
+input_data:
+  system:
+    occupations: smearing
+    smearing: gaussian
+    degauss: 0.005
+  electrons:
+    conv_thr: 1.0e-12
+    mixing_mode: local-TF
+    mixing_beta: 0.6
+
+kspacing: 0.03
+
+parent_pseudopotentials: sssp_1.3.0_pbe_precision.yaml
\ No newline at end of file
diff --git a/src/quacc/calculators/espresso/presets/sssp_1.3.0_pbe_efficiency.yaml b/src/quacc/calculators/espresso/presets/sssp_1.3.0_pbe_efficiency.yaml
index 4a9cf390..58d6a5ea 100644
--- a/src/quacc/calculators/espresso/presets/sssp_1.3.0_pbe_efficiency.yaml
+++ b/src/quacc/calculators/espresso/presets/sssp_1.3.0_pbe_efficiency.yaml
@@ -431,6 +431,7 @@ pseudopotentials:
     pseudopotential: Wentzcovitch
   Pt:
     cutoff_rho: 280.0
+    cutoff_wfc: 35.0
     filename: pt_pbe_v1.4.uspp.F.UPF
     md5: f09d6de1a584b5a045c4fc126da2d0c4
     pseudopotential: GBRV-1.4
diff --git a/src/quacc/calculators/espresso/presets/sssp_1.3.0_pbe_precision.yaml b/src/quacc/calculators/espresso/presets/sssp_1.3.0_pbe_precision.yaml
new file mode 100644
index 00000000..8c7bf66b
--- /dev/null
+++ b/src/quacc/calculators/espresso/presets/sssp_1.3.0_pbe_precision.yaml
@@ -0,0 +1,623 @@
+# SSSP PBE Precision v1.3.0
+# https://doi.org/10.1038/s41524-018-0127-2
+# https://www.materialscloud.org/discover/sssp/table/efficiency
+
+pseudopotentials:
+  Ac:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Ac.us.z_11.ld1.psl.v1.0.0-high.upf
+    md5: 3a78bb30464666358a3ec0edb47f6656
+    pseudopotential: 100US
+  Ag:
+    cutoff_rho: 220.0
+    cutoff_wfc: 55.0
+    filename: Ag_ONCV_PBE-1.0.oncvpsp.upf
+    md5: 94f47bd0669c641108e45594df92fabc
+    pseudopotential: SG15
+  Al:
+    cutoff_rho: 240.0
+    cutoff_wfc: 30.0
+    filename: Al.pbe-n-kjpaw_psl.1.0.0.UPF
+    md5: cfc449ca30b5f3223ec38ddd88ac046d
+    pseudopotential: 100PAW
+  Am:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: Am.paw.z_17.ld1.uni-marburg.v0.upf
+    md5: b90604daea46e7f2635bfe47e71ce977
+    pseudopotential: MalteSachs
+  Ar:
+    cutoff_rho: 960.0
+    cutoff_wfc: 120.0
+    filename: Ar.paw.z_8.ld1.psl.v1.0.0-high.upf
+    md5: 86eb6412701852330f587daee5be6c21
+    pseudopotential: 100PAW
+  As:
+    cutoff_rho: 300.0
+    cutoff_wfc: 75.0
+    filename: As.nc.z_15.oncvpsp3.dojo.v4-std.upf
+    md5: bfe1a874457ce592347346129958e7cf
+    pseudopotential: Dojo
+  At:
+    cutoff_rho: 640.0
+    cutoff_wfc: 80.0
+    filename: At.us.z_17.ld1.psl.v1.0.0-high.upf
+    md5: 171e941146fbb8d42c50c0ba61055d18
+    pseudopotential: 100US
+  Au:
+    cutoff_rho: 200.0
+    cutoff_wfc: 50.0
+    filename: Au_ONCV_PBE-1.0.oncvpsp.upf
+    md5: d14007822ba0e19f0206237467fc06c2
+    pseudopotential: SG15
+  B:
+    cutoff_rho: 440.0
+    cutoff_wfc: 55.0
+    filename: B_pbe_v1.01.uspp.F.UPF
+    md5: d081ebb89d0c768e112975f650467a00
+    pseudopotential: GBRV-1.2
+  Ba:
+    cutoff_rho: 140.0
+    cutoff_wfc: 35.0
+    filename: Ba.nc.z_10.oncvpsp4.dojo.v4-sp.upf
+    md5: ecceda5fc736cf81896add41b7758c6c
+    pseudopotential: Dojo
+  Be:
+    cutoff_rho: 220.0
+    cutoff_wfc: 55.0
+    filename: Be_ONCV_PBE-1.0.oncvpsp.upf
+    md5: 28b8ff6b8130143f4fef2c47cbef089d
+    pseudopotential: SG15
+  Bi:
+    cutoff_rho: 400.0
+    cutoff_wfc: 50.0
+    filename: Bi_pbe_v1.uspp.F.UPF
+    md5: cceb9f28ec65b6d7ff33140f5b0b1758
+    pseudopotential: GBRV-1.2
+  Bk:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: Bk.paw.z_19.ld1.uni-marburg.v0.upf
+    md5: 34a5c1d9790ca2603c79955cdb099600
+    pseudopotential: MalteSachs
+  Br:
+    cutoff_rho: 720.0
+    cutoff_wfc: 90.0
+    filename: br_pbe_v1.4.uspp.F.UPF
+    md5: d3ffb7b29f6225aa16fe06858fb2a80b
+    pseudopotential: GBRV-1.4
+  C:
+    cutoff_rho: 360.0
+    cutoff_wfc: 45.0
+    filename: C.pbe-n-kjpaw_psl.1.0.0.UPF
+    md5: 5d2aebdfa2cae82b50a7e79e9516da0f
+    pseudopotential: 100PAW
+  Ca:
+    cutoff_rho: 240.0
+    cutoff_wfc: 30.0
+    filename: Ca_pbe_v1.uspp.F.UPF
+    md5: 403a4c14b9e4d4dfdc3024c9a3812218
+    pseudopotential: GBRV-1.2
+  Cd:
+    cutoff_rho: 800.0
+    cutoff_wfc: 100.0
+    filename: Cd.paw.z_20.ld1.psl.v1.0.0-high.upf
+    md5: 1f58be37c2dbf75aec6b05b1d77ccc80
+    pseudopotential: 100PAW
+  Ce:
+    cutoff_rho: 400.0
+    cutoff_wfc: 50.0
+    filename: Ce.paw.z_12.atompaw.wentzcovitch.v1.2.upf
+    md5: 2241420ff980c77e0c917a2dc8a7e08e
+    pseudopotential: Wentzcovitch
+  Cf:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: Cf.paw.z_20.ld1.uni-marburg.v0.upf
+    md5: 0e4adf7627c2d1305f26dd63271f2b94
+    pseudopotential: MalteSachs
+  Cl:
+    cutoff_rho: 800.0
+    cutoff_wfc: 100.0
+    filename: Cl.pbe-n-rrkjus_psl.1.0.0.UPF
+    md5: 18cc83b4be324290a879bee3176034ba
+    pseudopotential: 100US
+  Cm:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: Cm.paw.z_18.ld1.uni-marburg.v0.upf
+    md5: fa6219561ad2ecb899c96af402755927
+    pseudopotential: MalteSachs
+  Co:
+    cutoff_rho: 1080.0
+    cutoff_wfc: 90.0
+    filename: Co_pbe_v1.2.uspp.F.UPF
+    md5: 5f91765df6ddd3222702df6e7b74a16d
+    pseudopotential: GBRV-1.2
+  Cr:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: cr_pbe_v1.5.uspp.F.UPF
+    md5: 0d52af634a40206e4dee301ad30da4bf
+    pseudopotential: GBRV-1.5
+  Cs:
+    cutoff_rho: 180.0
+    cutoff_wfc: 45.0
+    filename: Cs.nc.z_9.oncvpsp3.dojo.v4-str.upf
+    md5: d01c53d012be9123745781bcb8b00a26
+    pseudopotential: Dojo
+  Cu:
+    cutoff_rho: 720.0
+    cutoff_wfc: 90.0
+    filename: Cu.paw.z_11.ld1.psl.v1.0.0-low.upf
+    md5: 619f40885d92a09a85a8b37550532d0c
+    pseudopotential: 100PAW-low
+  Dy:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Dy.paw.z_20.atompaw.wentzcovitch.v1.2.upf
+    md5: fad4f994dc38884d1fc17fd7bf5e13bf
+    pseudopotential: Wentzcovitch
+  Er:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Er.paw.z_22.atompaw.wentzcovitch.v1.2.upf
+    md5: 5ba6a5c626b1678e031aafe1da34e245
+    pseudopotential: Wentzcovitch
+  Es:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: Es.paw.z_21.ld1.uni-marburg.v0.upf
+    md5: 4bc7a67aee4e34db40c77f63d9e88986
+    pseudopotential: MalteSachs
+  Eu:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Eu.paw.z_17.atompaw.wentzcovitch.v1.2.upf
+    md5: 52b6e423bc4e840b6e0dc4248fa51623
+    pseudopotential: Wentzcovitch
+  F:
+    cutoff_rho: 360.0
+    cutoff_wfc: 90.0
+    filename: F.oncvpsp.upf
+    md5: dbf8367619a749999a0442b33b80a7e7
+    pseudopotential: Dojo
+  Fe:
+    cutoff_rho: 1080.0
+    cutoff_wfc: 90.0
+    filename: Fe.pbe-spn-kjpaw_psl.0.2.1.UPF
+    md5: e86618425769142926afa95317d90200
+    pseudopotential: 031PAW
+  Fm:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: Fm.paw.z_22.ld1.uni-marburg.v0.upf
+    md5: 2a5ec34d2abb196d3027bbefca4b5922
+    pseudopotential: MalteSachs
+  Fr:
+    cutoff_rho: 1200.0
+    cutoff_wfc: 150.0
+    filename: Fr.paw.z_19.ld1.psl.v1.0.0-high.upf
+    md5: 4e1baa83397213ef351c329de67c4222
+    pseudopotential: 100PAW
+  Ga:
+    cutoff_rho: 720.0
+    cutoff_wfc: 90.0
+    filename: Ga.pbe-dn-kjpaw_psl.1.0.0.UPF
+    md5: a27b4342b1af7e5f338de752e9ed7044
+    pseudopotential: 100PAW
+  Gd:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Gd.paw.z_18.atompaw.wentzcovitch.v1.2.upf
+    md5: a44f32af2ba180e1a67c5cef9ff7f39b
+    pseudopotential: Wentzcovitch
+  Ge:
+    cutoff_rho: 360.0
+    cutoff_wfc: 45.0
+    filename: ge_pbe_v1.4.uspp.F.UPF
+    md5: 9c9eaa91e581c3f09632fb3098b2c6b2
+    pseudopotential: GBRV-1.4
+  H:
+    cutoff_rho: 320.0
+    cutoff_wfc: 80.0
+    filename: H_ONCV_PBE-1.0.oncvpsp.upf
+    md5: 1790becc920ee074925cf490c71280fe
+    pseudopotential: SG15
+  He:
+    cutoff_rho: 220.0
+    cutoff_wfc: 55.0
+    filename: He_ONCV_PBE-1.0.oncvpsp.upf
+    md5: e7160162b946020f132a727efeb32d00
+    pseudopotential: SG15
+  Hf:
+    cutoff_rho: 220.0
+    cutoff_wfc: 55.0
+    filename: Hf-sp.oncvpsp.upf
+    md5: 417ed15784afe83d2e06dacf143de3f8
+    pseudopotential: Dojo
+  Hg:
+    cutoff_rho: 390.0
+    cutoff_wfc: 65.0
+    filename: Hg.us.z_12.uspp.gbrv.v1.upf
+    md5: 8f42caffe07f7fd9c0a564347f8c5498
+    pseudopotential: GBRV-v1.0
+  Ho:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Ho.paw.z_21.atompaw.wentzcovitch.v1.2.upf
+    md5: f900adcc49abc9ab8113872cdbacec3e
+    pseudopotential: Wentzcovitch
+  I:
+    cutoff_rho: 260.0
+    cutoff_wfc: 65.0
+    filename: I.nc.z_17.oncvpsp4.sg15.v0.upf
+    md5: 01aece6dfeaff728ece6f409764611b3
+    pseudopotential: SG15
+  In:
+    cutoff_rho: 400.0
+    cutoff_wfc: 50.0
+    filename: In.pbe-dn-rrkjus_psl.0.2.2.UPF
+    md5: 25e7c42c3b55b68f4bf926be2e7201a4
+    pseudopotential: 031US
+  Ir:
+    cutoff_rho: 720.0
+    cutoff_wfc: 90.0
+    filename: Ir.us.z_31.ld1.psl.v1.0.0-high.upf
+    md5: 38277204e703136c184b6a7dd74a78df
+    pseudopotential: 100US
+  K:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: K.pbe-spn-kjpaw_psl.1.0.0.UPF
+    md5: 7d58810084cac21f60fbe77ea2b688fd
+    pseudopotential: 100PAW
+  Kr:
+    cutoff_rho: 1200.0
+    cutoff_wfc: 200.0
+    filename: Kr.paw.z_18.ld1.psl.v1.0.0-high.upf
+    md5: cde63d6f6cf9ccadbd3dd23661d90f66
+    pseudopotential: 100PAW
+  La:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: La.paw.z_11.atompaw.wentzcovitch.v1.2.upf
+    md5: 754494e15ae71f30e5b5f678af019e01
+    pseudopotential: Wentzcovitch
+  Li:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: li_pbe_v1.4.uspp.F.UPF
+    md5: e912e257baa3777c20ea3d68f190483c
+    pseudopotential: GBRV-1.4
+  Lr:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: Lr.paw.z_25.ld1.uni-marburg.v0.upf
+    md5: f945946d0d1ec8347dc1259eb00091c8
+    pseudopotential: MalteSachs
+  Lu:
+    cutoff_rho: 360.0
+    cutoff_wfc: 45.0
+    filename: Lu.paw.z_25.atompaw.wentzcovitch.v1.2.upf
+    md5: a517b3205eadf2aa79773283867f4cbe
+    pseudopotential: Wentzcovitch
+  Md:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: Md.paw.z_23.ld1.uni-marburg.v0.upf
+    md5: e3e4fed06ac619855d80864afca10136
+    pseudopotential: MalteSachs
+  Mg:
+    cutoff_rho: 360.0
+    cutoff_wfc: 45.0
+    filename: mg_pbe_v1.4.uspp.F.UPF
+    md5: 8ffbd8f729fef71095aac5bd8316fb1f
+    pseudopotential: GBRV-1.4
+  Mn:
+    cutoff_rho: 1080.0
+    cutoff_wfc: 90.0
+    filename: mn_pbe_v1.5.uspp.F.UPF
+    md5: 82ef2b46521d7a7d9e736dc3972e4928
+    pseudopotential: GBRV-1.5
+  Mo:
+    cutoff_rho: 140.0
+    cutoff_wfc: 35.0
+    filename: Mo_ONCV_PBE-1.0.oncvpsp.upf
+    md5: 1b5d28e075c9ccadda658a603575cd1f
+    pseudopotential: SG15
+  N:
+    cutoff_rho: 320.0
+    cutoff_wfc: 80.0
+    filename: N.oncvpsp.upf
+    md5: 563d65bfb082928f0c9eb97172f6c357
+    pseudopotential: Dojo
+  Na:
+    cutoff_rho: 800.0
+    cutoff_wfc: 100.0
+    filename: Na.paw.z_9.ld1.psl.v1.0.0-low.upf
+    md5: 32bccecb13d7399e6c7dae6fe6685ff0
+    pseudopotential: 100PAW-low
+  Nb:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Nb.pbe-spn-kjpaw_psl.0.3.0.UPF
+    md5: 411d72ad547312f8017e2943ceca08cc
+    pseudopotential: 031PAW
+  Nd:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Nd.paw.z_14.atompaw.wentzcovitch.v1.2.upf
+    md5: 8a77231a7dfbac907351543c5ef6bfc9
+    pseudopotential: Wentzcovitch
+  Ne:
+    cutoff_rho: 720.0
+    cutoff_wfc: 120.0
+    filename: Ne.paw.z_8.ld1.psl.v1.0.0-high.upf
+    md5: 5567efd6d280a1ebb12a19bb24aae62b
+    pseudopotential: 100PAW
+  Ni:
+    cutoff_rho: 400.0
+    cutoff_wfc: 50.0
+    filename: ni_pbe_v1.4.uspp.F.UPF
+    md5: 1ee80287db30b12d2bc1f57a5b5d6409
+    pseudopotential: GBRV-1.4
+  'No':
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: No.paw.z_24.ld1.uni-marburg.v0.upf
+    md5: 75d6fcbe3c3afebd97ab105f1656d1c1
+    pseudopotential: MalteSachs
+  Np:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: Np.paw.z_15.ld1.uni-marburg.v0.upf
+    md5: 2b27845584d1ae013b107a04f9c09b5b
+    pseudopotential: MalteSachs
+  O:
+    cutoff_rho: 600.0
+    cutoff_wfc: 75.0
+    filename: O.pbe-n-kjpaw_psl.0.1.UPF
+    md5: 0234752ac141de4415c5fc33072bef88
+    pseudopotential: 031PAW
+  Os:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Os_pbe_v1.2.uspp.F.UPF
+    md5: a3fb40a04f0c37c25c34bbc47164c9a8
+    pseudopotential: GBRV-1.2
+  P:
+    cutoff_rho: 240.0
+    cutoff_wfc: 30.0
+    filename: P.pbe-n-rrkjus_psl.1.0.0.UPF
+    md5: 8b930f418f0a4573dca56cd030ffe088
+    pseudopotential: 100US
+  Pa:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: Pa.paw.z_13.ld1.uni-marburg.v0.upf
+    md5: d7b89857b2b2f446a6f8a94fd7fc0316
+    pseudopotential: MalteSachs
+  Pb:
+    cutoff_rho: 360.0
+    cutoff_wfc: 45.0
+    filename: Pb.pbe-dn-kjpaw_psl.0.2.2.UPF
+    md5: 9d431e6316058b74ade52399a6cf67da
+    pseudopotential: 031PAW
+  Pd:
+    cutoff_rho: 200.0
+    cutoff_wfc: 50.0
+    filename: Pd_ONCV_PBE-1.0.oncvpsp.upf
+    md5: eb77f42b51d86fb18e25f68156a31cf1
+    pseudopotential: SG15
+  Pm:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Pm.paw.z_15.atompaw.wentzcovitch.v1.2.upf
+    md5: 73dcdc0c9fe91f97d1fdb9924a622ccb
+    pseudopotential: Wentzcovitch
+  Po:
+    cutoff_rho: 640.0
+    cutoff_wfc: 80.0
+    filename: Po.pbe-dn-rrkjus_psl.1.0.0.UPF
+    md5: 3f8a5a8b7a531f42ca8381c21d3cd528
+    pseudopotential: 100US
+  Pr:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Pr.paw.z_13.atompaw.wentzcovitch.v1.2.upf
+    md5: e0f8e046fa815e336ba020f7e7bc75cb
+    pseudopotential: Wentzcovitch
+  Pt:
+    cutoff_rho: 800.0
+    cutoff_wfc: 100.0
+    filename: Pt.pbe-spfn-rrkjus_psl.1.0.0.UPF
+    md5: ed006ba81d2b6b3b17616bb61ae12f04
+    pseudopotential: 100US
+  Pu:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: Pu.paw.z_16.ld1.uni-marburg.v0.upf
+    md5: 566c3e560fb5ccfacef076b74913ab0c
+    pseudopotential: MalteSachs
+  Ra:
+    cutoff_rho: 720.0
+    cutoff_wfc: 90.0
+    filename: Ra.paw.z_20.ld1.psl.v1.0.0-high.upf
+    md5: d3f31cdfcb736122946f367071bad67a
+    pseudopotential: 100PAW
+  Rb:
+    cutoff_rho: 120.0
+    cutoff_wfc: 30.0
+    filename: Rb_ONCV_PBE-1.0.oncvpsp.upf
+    md5: 55a5172d6bfbce6759a58e35d43f6aa9
+    pseudopotential: SG15
+  Re:
+    cutoff_rho: 240.0
+    cutoff_wfc: 30.0
+    filename: Re_pbe_v1.2.uspp.F.UPF
+    md5: 85f993410f3e006da9d71c142b4ad953
+    pseudopotential: GBRV-1.2
+  Rh:
+    cutoff_rho: 220.0
+    cutoff_wfc: 55.0
+    filename: Rh_ONCV_PBE-1.0.oncvpsp.upf
+    md5: ba07c69523b14cacd10683cd4c4284c1
+    pseudopotential: SG15
+  Rn:
+    cutoff_rho: 1600.0
+    cutoff_wfc: 200.0
+    filename: Rn.paw.z_18.ld1.psl.v1.0.0-high.upf
+    md5: 2ee8f183081cd84b04ed791df1fb0731
+    pseudopotential: 100PAW
+  Ru:
+    cutoff_rho: 140.0
+    cutoff_wfc: 35.0
+    filename: Ru_ONCV_PBE-1.0.oncvpsp.upf
+    md5: be037bb81c227cfb9b1461a9f099f4bd
+    pseudopotential: SG15
+  S:
+    cutoff_rho: 280.0
+    cutoff_wfc: 35.0
+    filename: s_pbe_v1.4.uspp.F.UPF
+    md5: 88d86576ff6df21479756cfb9bdac1df
+    pseudopotential: GBRV-1.4
+  Sb:
+    cutoff_rho: 440.0
+    cutoff_wfc: 55.0
+    filename: sb_pbe_v1.4.uspp.F.UPF
+    md5: 9bc50dfb53373b713f5709b9110fe27f
+    pseudopotential: GBRV-1.4
+  Sc:
+    cutoff_rho: 720.0
+    cutoff_wfc: 90.0
+    filename: Sc.pbe-spn-kjpaw_psl.0.2.3.UPF
+    md5: 2c6607fffa759d1e5292e48f5ddd8baa
+    pseudopotential: 031PAW
+  Se:
+    cutoff_rho: 240.0
+    cutoff_wfc: 30.0
+    filename: Se_pbe_v1.uspp.F.UPF
+    md5: 1b3568f3a8ae88f9a2a0ad0698632c85
+    pseudopotential: GBRV-1.2
+  Si:
+    cutoff_rho: 240.0
+    cutoff_wfc: 30.0
+    filename: Si.pbe-n-rrkjus_psl.1.0.0.UPF
+    md5: 0b0bb1205258b0d07b9f9672cf965d36
+    pseudopotential: 100US
+  Sm:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Sm.paw.z_16.atompaw.wentzcovitch.v1.2.upf
+    md5: d38221e44bcfc3c784cbdb498a69732f
+    pseudopotential: Wentzcovitch
+  Sn:
+    cutoff_rho: 560.0
+    cutoff_wfc: 70.0
+    filename: Sn_pbe_v1.uspp.F.UPF
+    md5: 4cf58ce39ec5d5d420df3dd08604eb00
+    pseudopotential: GBRV-1.2
+  Sr:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Sr_pbe_v1.uspp.F.UPF
+    md5: 6b418c05fbe9db5448babca5e47b7a5b
+    pseudopotential: GBRV-1.2
+  Ta:
+    cutoff_rho: 400.0
+    cutoff_wfc: 50.0
+    filename: Ta_pbe_v1.uspp.F.UPF
+    md5: f8bbe9446314a3b8ea5d9f3e3836c939
+    pseudopotential: GBRV-1.2
+  Tb:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Tb.paw.z_19.atompaw.wentzcovitch.v1.2.upf
+    md5: 9e397ff4c8e7fcf344a3e57e25721bc0
+    pseudopotential: Wentzcovitch
+  Tc:
+    cutoff_rho: 160.0
+    cutoff_wfc: 40.0
+    filename: Tc_ONCV_PBE-1.0.oncvpsp.upf
+    md5: 1c2b1e6c8b361b656073c0c20ed4f60a
+    pseudopotential: SG15
+  Te:
+    cutoff_rho: 400.0
+    cutoff_wfc: 50.0
+    filename: Te.us.z_6.ld1.psl.v1.0.0-low.upf
+    md5: 44eeed7063cd65092dfe4811eda022ea
+    pseudopotential: US100-low
+  Th:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: Th.paw.z_12.ld1.uni-marburg.v0.upf
+    md5: c778f5c1781d25750cbff4a0d60de988
+    pseudopotential: MalteSachs
+  Ti:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: ti_pbe_v1.4.uspp.F.UPF
+    md5: 88a00a6731bd790ddea75d31a80cb452
+    pseudopotential: GBRV-1.4
+  Tl:
+    cutoff_rho: 560.0
+    cutoff_wfc: 70.0
+    filename: Tl_pbe_v1.2.uspp.F.UPF
+    md5: b76cf1f7e72655a2b2c53cf6385d7059
+    pseudopotential: GBRV-1.2
+  Tm:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Tm.paw.z_23.atompaw.wentzcovitch.v1.2.upf
+    md5: 65ac1a59d66520b67f41930ed0a84655
+    pseudopotential: Wentzcovitch
+  U:
+    cutoff_rho: 480.0
+    cutoff_wfc: 60.0
+    filename: U.paw.z_14.ld1.uni-marburg.v0.upf
+    md5: 0343693cc166857ace12183ecb4b0f49
+    pseudopotential: MalteSachs
+  V:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: v_pbe_v1.4.uspp.F.UPF
+    md5: 22b79981416ebb76fdaf5b1b8640f6fb
+    pseudopotential: GBRV-1.4
+  W:
+    cutoff_rho: 400.0
+    cutoff_wfc: 50.0
+    filename: W_pbe_v1.2.uspp.F.UPF
+    md5: 9c083fa34c2a2ea0f02f1f893e16e1c8
+    pseudopotential: GBRV-1.2
+  Xe:
+    cutoff_rho: 900.0
+    cutoff_wfc: 150.0
+    filename: Xe.paw.z_18.ld1.psl.v1.0.0-high.upf
+    md5: 337379db17a2c20b6c8cb601c639f0cd
+    pseudopotential: 100PAW
+  Y:
+    cutoff_rho: 280.0
+    cutoff_wfc: 35.0
+    filename: Y_pbe_v1.uspp.F.UPF
+    md5: 2cf71db95cafeb975fc457bd7f14888e
+    pseudopotential: GBRV-1.2
+  Yb:
+    cutoff_rho: 320.0
+    cutoff_wfc: 40.0
+    filename: Yb.paw.z_24.atompaw.wentzcovitch.v1.2.upf
+    md5: 2246be0c1287a90a9096a0c3416daab6
+    pseudopotential: Wentzcovitch
+  Zn:
+    cutoff_rho: 720.0
+    cutoff_wfc: 90.0
+    filename: Zn_pbe_v1.uspp.F.UPF
+    md5: df62231357ef9e81f77b2b3087fa5675
+    pseudopotential: GBRV-1.2
+  Zr:
+    cutoff_rho: 240.0
+    cutoff_wfc: 30.0
+    filename: Zr_pbe_v1.uspp.F.UPF
+    md5: 5db81b1e868ab7776c4564c113de050b
+    pseudopotential: GBRV-1.2
\ No newline at end of file
diff --git a/src/quacc/calculators/espresso/presets/tough_metal_clusters_efficiency.yaml b/src/quacc/calculators/espresso/presets/tough_metal_clusters_efficiency.yaml
new file mode 100644
index 00000000..6f983f3e
--- /dev/null
+++ b/src/quacc/calculators/espresso/presets/tough_metal_clusters_efficiency.yaml
@@ -0,0 +1,29 @@
+# Last modified: 12-18-2023
+# Presets for difficult isolated metallic clusters
+# with possible spin states (e.g. (Au, Pt, Pd) clusters + adsorbates)
+# relaxation starts with loose conv_thr but tightens as the calculation
+# progresses.
+
+input_data:
+  control:
+    calculation: relax
+    tprnfor: True
+  system:
+    occupations: smearing
+    smearing: marzari-vanderbilt
+    degauss: 0.015
+  electrons:
+    conv_thr: 1.0e-6
+    mixing_mode: local-TF
+    mixing_beta: 0.25
+    scf_must_converge: False
+    electron_maxstep: 70
+    startingwfc: random
+  ions:
+    ion_dynamics: bfgs
+    bfgs_ndim: 6
+    upscale : 1000
+
+kpts: gamma
+
+parent_pseudopotentials: sssp_1.3.0_pbe_efficiency.yaml
\ No newline at end of file
diff --git a/src/quacc/calculators/espresso/utils.py b/src/quacc/calculators/espresso/utils.py
index 52c95a03..9705795f 100644
--- a/src/quacc/calculators/espresso/utils.py
+++ b/src/quacc/calculators/espresso/utils.py
@@ -2,13 +2,15 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING
 
+from quacc.utils.dicts import recursive_dict_merge
+
 if TYPE_CHECKING:
     from typing import Any
 
     from ase.atoms import Atoms
 
 
-def parse_pp_and_cutoff(config: dict[str, Any], atoms: Atoms) -> dict[str, Any] | None:
+def parse_pw_preset(config: dict[str, Any], atoms: Atoms) -> dict[str, Any] | None:
     """
     Function that parses the pseudopotentials and cutoffs from a preset file.
     The cutoffs are taken from the largest value of the cutoffs among the elements
@@ -27,19 +29,31 @@ def parse_pp_and_cutoff(config: dict[str, Any], atoms: Atoms) -> dict[str, Any]
         A dictionary containing the pseudopotentials and cutoffs
     """
 
-    if "pseudopotentials" not in config:
-        return None
-
-    pp_dict = config["pseudopotentials"]
-    unique_elements = list(set(atoms.symbols))
-    wfc_cutoff, rho_cutoff = 0, 0
-    pseudopotentials = {}
-    for element in unique_elements:
-        if pp_dict[element]["cutoff_wfc"] > wfc_cutoff:
-            wfc_cutoff = pp_dict[element]["cutoff_wfc"]
-        if pp_dict[element]["cutoff_rho"] > rho_cutoff:
-            rho_cutoff = pp_dict[element]["cutoff_rho"]
-        pseudopotentials[element] = pp_dict[element]["filename"]
-    tmp_input_data = {"system": {"ecutwfc": wfc_cutoff, "ecutrho": rho_cutoff}}
-
-    return {"pseudopotentials": pseudopotentials, "input_data": tmp_input_data}
+    atoms_copy = atoms.copy()
+
+    if "pseudopotentials" in config:
+        pp_dict = config["pseudopotentials"]
+        unique_elements = list(set(atoms_copy.symbols))
+        wfc_cutoff, rho_cutoff = 0, 0
+        pseudopotentials = {}
+        for element in unique_elements:
+            if pp_dict[element]["cutoff_wfc"] > wfc_cutoff:
+                wfc_cutoff = pp_dict[element]["cutoff_wfc"]
+            if pp_dict[element]["cutoff_rho"] > rho_cutoff:
+                rho_cutoff = pp_dict[element]["cutoff_rho"]
+            pseudopotentials[element] = pp_dict[element]["filename"]
+        pp_input_data = {"system": {"ecutwfc": wfc_cutoff, "ecutrho": rho_cutoff}}
+
+    input_data = config.get("input_data")
+    input_data = recursive_dict_merge(pp_input_data, input_data)
+
+    kspacing = config.get("kspacing")
+
+    kpts = config.get("kpts")
+
+    return {
+        "input_data": input_data,
+        "pseudopotentials": pseudopotentials,
+        "kspacing": kspacing,
+        "kpts": kpts,
+    }
diff --git a/src/quacc/recipes/mlp/core.py b/src/quacc/recipes/mlp/core.py
index 2d9a7673..f1ef3819 100644
--- a/src/quacc/recipes/mlp/core.py
+++ b/src/quacc/recipes/mlp/core.py
@@ -43,7 +43,10 @@ def static_job(
     RunSchema
         Dictionary of results from [quacc.schemas.ase.summarize_run][]
     """
-    atoms.calc = _pick_calculator(method, **calc_kwargs)
+    calc_defaults = {"dtype": "float64"} if method == "mace" else {}
+    calc_flags = recursive_dict_merge(calc_defaults, calc_kwargs)
+
+    atoms.calc = _pick_calculator(method, **calc_flags)
     final_atoms = run_calc(atoms)
     return summarize_run(
         final_atoms, input_atoms=atoms, additional_fields={"name": f"{method} Static"}
@@ -85,11 +88,14 @@ def relax_job(
         Dictionary of results from [quacc.schemas.ase.summarize_opt_run][]
     """
 
-    atoms.calc = _pick_calculator(method, **calc_kwargs)
+    calc_defaults = {"dtype": "float64"} if method == "mace" else {}
+    calc_flags = recursive_dict_merge(calc_defaults, calc_kwargs)
 
-    opt_defaults = {"fmax": 0.1, "max_steps": 1000, "optimizer": FIRE}
+    opt_defaults = {"fmax": 0.05, "max_steps": 1000, "optimizer": FIRE}
     opt_flags = recursive_dict_merge(opt_defaults, opt_params)
 
+    atoms.calc = _pick_calculator(method, **calc_flags)
+
     dyn = run_opt(atoms, relax_cell=relax_cell, **opt_flags)
 
     return summarize_opt_run(dyn, additional_fields={"name": f"{method} Relax"})


Test patch:
diff --git a/tests/core/calculators/espresso/test_espresso.py b/tests/core/calculators/espresso/test_espresso.py
index e44b874b..3b5c9666 100644
--- a/tests/core/calculators/espresso/test_espresso.py
+++ b/tests/core/calculators/espresso/test_espresso.py
@@ -49,6 +49,83 @@ def test_espresso_kwargs_handler():
     assert calc.parameters == expected_parameters
 
 
+def test_espresso_presets():
+    calc_defaults = {
+        "input_data": {
+            "system": {"ecutwfc": 20, "ecutrho": 80, "occupations": "fixed"},
+            "electrons": {"scf_must_converge": False},
+        }
+    }
+
+    input_data = {"system": {"ecutwfc": 30}, "electrons": {"conv_thr": 1.0e-16}}
+
+    preset = "esm_metal_slab_efficiency"
+
+    atoms = Atoms(symbols="LiLaOZr")
+    atoms.set_cell([5, 2, 10])
+
+    calc = Espresso(
+        input_atoms=atoms,
+        preset=preset,
+        calc_defaults=calc_defaults,
+        input_data=input_data,
+        kpts=[7, 17, 1],
+    )
+
+    expected_parameters = {
+        "input_data": {
+            "control": {},
+            "system": {
+                "ecutwfc": 30,
+                "ecutrho": 400.0,
+                "occupations": "smearing",
+                "smearing": "marzari-vanderbilt",
+                "degauss": 0.01,
+                "assume_isolated": "esm",
+                "esm_bc": "bc1",
+            },
+            "electrons": {
+                "scf_must_converge": False,
+                "conv_thr": 1.0e-16,
+                "mixing_mode": "local-TF",
+                "mixing_beta": 0.35,
+            },
+            "ions": {},
+            "cell": {},
+            "rism": {},
+        },
+        "kpts": [7, 17, 1],
+        "pseudopotentials": {
+            "O": "O.pbe-n-kjpaw_psl.0.1.UPF",
+            "Zr": "Zr_pbe_v1.uspp.F.UPF",
+            "Li": "li_pbe_v1.4.uspp.F.UPF",
+            "La": "La.paw.z_11.atompaw.wentzcovitch.v1.2.upf",
+        },
+    }
+    assert calc.template.binary == "pw"
+    assert calc.parameters == expected_parameters
+
+
+def test_espresso_presets_gamma():
+    preset = "molecule_efficiency.yaml"
+
+    calc = Espresso(preset=preset)
+
+    assert calc.parameters["kpts"] is None
+
+
+def test_espresso_bad_kpts():
+    with pytest.raises(ValueError):
+        Espresso(kpts=(1, 1, 1), kspacing=0.5)
+
+
+def test_espresso_kpts():
+    calc = Espresso(kspacing=0.001, preset="metal_precision")
+
+    assert "kpts" not in calc.parameters
+    assert calc.parameters["kspacing"] == 0.001
+
+
 def test_outdir_handler(tmp_path, monkeypatch):
     monkeypatch.chdir(tmp_path)
 
diff --git a/tests/core/recipes/mlp_recipes/test_core_recipes.py b/tests/core/recipes/mlp_recipes/test_core_recipes.py
index 69794c9c..2856fe90 100644
--- a/tests/core/recipes/mlp_recipes/test_core_recipes.py
+++ b/tests/core/recipes/mlp_recipes/test_core_recipes.py
@@ -37,9 +37,9 @@ def test_static_job(tmp_path, monkeypatch, method):
 def test_relax_job(tmp_path, monkeypatch, method):
     monkeypatch.chdir(tmp_path)
     ref_energy = {
-        "chgnet": -32.662731,
-        "m3gnet": -32.747219,
-        "mace": -32.66752624511719,
+        "chgnet": -32.665626525878906,
+        "m3gnet": -32.749088287353516,
+        "mace": -32.670471191406259,
     }
     if method == "chgnet":
         pytestmark = pytest.importorskip("chgnet")
@@ -61,9 +61,9 @@ def test_relax_job(tmp_path, monkeypatch, method):
 def test_relax_cell_job(tmp_path, monkeypatch, method):
     monkeypatch.chdir(tmp_path)
     ref_energy = {
-        "chgnet": -32.664215087890625,
-        "m3gnet": -32.74749,
-        "mace": -32.67439270019531,
+        "chgnet": -32.6676139831543,
+        "m3gnet": -32.74995040893555,
+        "mace": -32.67771911621094,
     }
     if method == "chgnet":
         pytestmark = pytest.importorskip("chgnet")