Fixed-Point SCF ASE Calculator

The fixed-point ASE calculator is implemented in mace_scf/calculators/fixedpoint_scf.py.

Use this page as an API reference for constructing the calculator. For the SCF concepts behind num_scf_steps, mixing_parameter, Fermi levels, initial states, and restarts, read using fixed-point SCF models first.

Class

Use:

from mace_scf.calculators.fixedpoint_scf import MACEFixedPointSCF

MACEPolarizable is still available as a compatibility alias, but new code should use MACEFixedPointSCF.

Minimal Example

For a neutral constant-charge calculation with no applied external field, the calculator can be constructed with only the model path, device, boundary condition handling, and SCF options:

from mace_scf.calculators.fixedpoint_scf import MACEFixedPointSCF

calc = MACEFixedPointSCF(
    model_path="fit.model",
    device="cuda",
    pbc_handling="slab",
    scf_options={
        "num_scf_steps": 100,
        "scf_tolerance": 1.0e-6,
        "mixing_parameter": 0.2,
        "constant_charge": True,
        "use_autograd_forces": True,
    },
)

atoms.calc = calc
energy = atoms.get_potential_energy()
forces = atoms.get_forces()

If atoms.info["total_charge"] is absent, the calculator uses 0.0. If atoms.info["external_field"] is absent, the calculator uses a zero external field. If atoms.info["initial_fermi_level"] is absent, the calculator uses a zero Fermi-level input.

Constructor Arguments

Required arguments:

  • model_path path to the saved fixed-point model;

  • device device passed through the usual MACE/PyTorch device handling, such as "cpu" or "cuda".

Common optional arguments:

  • scf_options dictionary containing SCF runtime options;

  • pbc_handling boundary-condition mode used by the model electrostatics, for example "mixed_periodic", "slab", "pbc", "realspace", or "molecule_in_box";

  • total_charge_key name of the atoms.info field containing the requested total charge;

  • external_field_key name of the atoms.info field containing the applied homogeneous field;

  • fermi_level_key name of the atoms.info field containing the Fermi-level input;

  • ignore_nonconverged suppresses the non-convergence warning when the final density change is above scf_tolerance. Divergence and large constant-charge errors can still raise errors;

  • save_full_scf_history stores the full density history in calc.results["full_scf_history"].

Less common unit and dtype arguments:

  • energy_units_to_eV

  • length_units_to_A

  • default_dtype

Leave these at their defaults unless the saved model uses units or precision that differ from the normal ASE-facing workflow.

SCF Options

The calculator accepts these scf_options keys:

scf_options={
    "num_scf_steps": 100,
    "scf_tolerance": 1.0e-5,
    "mixing_parameter": 0.2,
    "constant_charge": True,
    "use_autograd_forces": True,
}

These are runtime options only. Architecture hyperparameters such as field feature widths, update blocks, density smearing widths, and nonlocal energy readout settings are already stored in the saved model and are not passed to the calculator.

You do not need to include initial_density or initial_fermi_level in calculator scf_options. The calculator uses the model’s local density guess for the initial multipoles. For the Fermi-level, the calculator reads the Fermi-level from the configured fermi_level_key. In constant charge simualtions this is the initial Fermi-level, and in constant chemical potential mode this is the fixed Fermi-level.

Input Keys

The calculator maps fields from atoms.info and atoms.arrays into the model input batch. The default key names are:

total_charge_key = "total_charge"
external_field_key = "external_field"
fermi_level_key = "initial_fermi_level"
atomic_multipoles_key = "initial_density_coefficients"

You only need to pass these key arguments when your Atoms objects use different names.

For example, if your input file stores the applied field as atoms.info["homogeneous_field"], pass:

calc = MACEFixedPointSCF(
    model_path="fit.model",
    device="cuda",
    external_field_key="homogeneous_field",
)

The meaning of the fields is:

  • total_charge_key used in constant-charge mode. If the field is absent, the target charge defaults to 0.0;

  • external_field_key applied homogeneous field. If absent, the field defaults to zero;

  • fermi_level_key Fermi-level input. In constant-Fermi mode this is the controlled Fermi level. In constant-charge mode it is the initial Fermi-level guess. If absent, it defaults to zero;

  • atomic_multipoles_key maps an optional atom array into density_coefficients. The standard calculator does not require this for normal energy and force calculations because it starts from the model’s local density guess. In the current calculator API, this is not the usual way to set the SCF initial density.

Arguments You Usually Do Not Need

For ordinary ASE use, do not pass:

  • atomic_multipoles_key unless your workflow deliberately stores multipoles in the input file;

  • external_field_key if there is no applied field or the default key name is already correct;

  • fermi_level_key if a zero Fermi-level input is acceptable or the default key name is already correct;

  • total_charge_key if the default key name is already correct. For neutral calculations, you usually do not need to put total_charge in atoms.info at all;

Constant Charge And Constant Fermi Level

For constant-charge calculations:

atoms.info["total_charge"] = 0.0

calc = MACEFixedPointSCF(
    model_path="fit.model",
    device="cuda",
    scf_options={
        "constant_charge": True,
        "num_scf_steps": 100,
        "scf_tolerance": 1.0e-6,
        "mixing_parameter": 0.2,
        "use_autograd_forces": True,
    },
)

For constant-Fermi calculations:

atoms.info["initial_fermi_level"] = -4.8

calc = MACEFixedPointSCF(
    model_path="fit.model",
    fermi_level_key="initial_fermi_level",
    device="cuda",
    scf_options={
        "constant_charge": False,
        "num_scf_steps": 100,
        "scf_tolerance": 1.0e-6,
        "mixing_parameter": 0.2,
        "use_autograd_forces": True,
    },
)

In constant-charge mode, fermi_level_key supplies an initial guess. In constant-Fermi mode, it supplies the fixed Fermi level.

Results

After a calculation, calc.results includes:

  • energy

  • free_energy

  • forces

  • density_coefficients

  • dipole

  • fermi_level

  • external_field

  • electrostatic_energy

  • electron_energy

  • convergence_history

  • num_scf_steps

  • electrostatic_features

  • electrostatic_potentials, if the model returns them

  • full_scf_history, if save_full_scf_history=True

The most useful diagnostic is usually:

calc.results["convergence_history"]

It records the mean absolute density change between SCF steps. Inspect this when a calculation is slow, oscillatory, or non-converged.

Developer Restart Options

The calculator has restart hooks:

  • scf_restart

  • restart_density

  • restart_fermi_level

These reuse state from the previous call to the same calculator object. They are currently developer-facing options and are not recommended as the default user workflow. Validate a model without restarts before relying on restarted calculations.