Dipole Moments and Polarizabilities with MACE
Using MACE-MDP: Pretrained Model for Dipole Moments and Polarizabilities
If you need ready-to-use predictions of molecular dipole moments and fully anisotropic polarizability tensors for organic systems, the pretrained MACE-MDP model is the recommended starting point. It is trained on the SPICE-α dataset (>1.8 million electric-field response calculations across molecular and condensed-phase environments) and achieves first-principles accuracy at a fraction of the cost. See the Foundation models page for the full model listing.
Warning
Fine-tuning of MACE-MDP is not available at this time.
The model is available via the mace_mdp convenience function, which
automatically downloads and caches the model on first use:
from mace.calculators import mace_mdp
from ase import build
calc = mace_mdp(device="cuda", default_dtype="float64")
atoms = build.molecule("H2O")
atoms.calc = calc
Getting Dipole Moments
Use ASE’s standard get_dipole_moment() after attaching the calculator:
mu = atoms.get_dipole_moment() # returns array of shape (3,) in e·Å
print("Dipole moment (e·Å):", mu)
Getting Polarizability
Use get_property with the "polarizability" key to obtain the full 3×3
tensor:
import numpy as np
alpha = np.asarray(calc.get_property("polarizability", atoms)).reshape(3, 3)
print("Polarizability tensor (ų):\n", alpha)
Tip:
For the spherical (irreducible) polarizability components, useful for
Raman spectra, use the "polarizability_sh" property:
spherical_alpha = calc.get_property("polarizability_sh", atoms)
Tutorial Jupyter notebooks for IR spectra, Raman spectra, and dipole/polarizability extraction are provided in the examples/ directory of the MACE-MDP repository.
If you use MACE-MDP in your work, please cite [1].
Training Your Own Model
Training Example
A typical training command for an AtomicDielectric MACE model looks like:
python /../mace/mace/cli/run_train.py \
--name="mace_mu_alpha" \
--train_file="train.xyz" \
--valid_file="val.xyz" \
--test_dir="test.xyz" \
--model="AtomicDielectricMACE" \
--E0s="average" \
--num_interactions=2 \
--num_channels=128 \
--max_L=2 \
--correlation=3 \
--MLP_irreps="16x0e+16x1o+16x2e" \
--dipole_key="REF_dipole" \
--polarizability_key="REF_polarizability" \
--loss="dipole_polar" \
--weight_decay=5e-10 \
--polarizability_weight=2000 \
--dipole_weight=1000 \
--clip_grad=1.0 \
--batch_size=128 \
--valid_batch_size=128 \
--max_num_epochs=40 \
--scheduler_patience=15 \
--patience=15 \
--eval_interval=1 \
--ema \
--error_table="DipolePolarRMSE" \
--default_dtype="float64" \
--device=cuda \
--seed=123 \
--restart_latest \
--save_cpu
Setting –MLP_irreps=”16x0e+16x1o+16x2e” and –max_L=2 are crutial for predicting polarizability correctly. Compared to a MACE - MLIP these models usually need less epochs to converge.
Extracting Polarizability Using ASE
Once training is complete and you have your model file (e.g., mace_mu_alpha.model), you can extract polarizability tensors from a trajectory.
Example extraction script:
import numpy as np
from ase.io import Trajectory
from mace.calculators.mace import MACECalculator
# Setup calculator
polar_calc = MACECalculator(
model_paths="mace_mu_alpha.model",
model_type="DipolePolarizabilityMACE",
device="cuda",
default_dtype="float64"
)
traj = Trajectory("test.traj", "r")
n_frames=len(traj)
alpha = np.empty((n_frames, 3, 3), dtype=float)
for i, atoms in enumerate(traj):
atoms.calc = polar_calc
alpha[i] = np.asarray(atoms.calc.get_property("polarizability", atoms)).reshape(3, 3)
print(f"Frame {i} Polarizability: ", alpha[i])
traj.close()
Tip:
To get the spherical polarizability (e.g. for Raman spectra), use the property "polarizability_sh" with get_property:
spherical_alpha = atoms.calc.get_property("polarizability_sh", atoms)