Fitting ACE

Top-level overview

The most minimal way of generating an ACE potential is

using ACE1pack
params = ... # see below 
fit_ace()

In the first instance, the parameters' dictionary (params) is generated by the *params() functions described in the rest of these pages. It can also be read from a .json or .yaml file.

fit_ace() takes the dictionary generated by fit_params()

ACE1pack.fit_aceFunction

fit_ace(params::Dict) -> IP, lsqinfo

Function to set up and fit the least-squares problem of "atoms' positions" -> "energy, forces, virials". Takes in a dictionary with all the parameters. See ?fit_params for details.

source
ACE1pack.fit_paramsFunction

fit_params(; kwargs...)

Returns a dictionary containing all of the parameters needed to make an ACE potential. All parameters are passed as keyword argumts.

Parameters

  • data : data parameters, see ?data_params for details (mandatory)
  • basis : dictionary containing dictionaries that specify the basis used in fitting. For example
basis = Dict(
    "pair_short" => Dict( "type" => "pair", ...), 
    "pair_long" => Dict("type" => "pair", ...), 
    "manybody" => Dict("type" => "ace", ...), 
    "nospecies" => Dict("type" => "ace", species = ["X",], ...)

keys of basis are ignored, so that multiple basis with different specifications (e.g. smaller and larger cutoffs) can be combined. See ?basis_params for more detail.

  • solver : dictionary containing parameters that specify the solver for least squares problem (mandatory). See ?solver_params.
  • e0 : Dict{String, Float} containing reference values for isolated atoms' energies (mandatory).
  • weights : dictionary of Dict("config_type" => Dict("E" => Float, "F => Float))entries specifying fitting weights. "default" is set to1.0` for all of "E", "F", and "V" weights.
  • P : regularizer parameters (optional), see ?regularizer_params.
  • ACE_fname = "ACE_fit.json" : filename to save ACE to. Potential & info do not get saved if ACE_fname isnothing() or is set to "". Files already parseentry are renamed and not overwritten.
  • LSQ_DB_fname_stem = "" : stem to save LsqDB to. Doesn't get saved if set to an empty string (""). If the file is already present, but fit_from_LSQ_DB is set to false, the old database is renamed, a new one constructed and saved under the given name.
  • fit_from_LSQ_DB = false: whether to fit from a least squares database specified with LSQ_DB_fname_stem. If LSQ_DB_fname_stem * "_kron.h5" file is not present, LsqDB is constructed from scratch and saved.
source

Parameters LSQ_DB_fname_stem and fit_from_LSQ_DB determine if the least-squares gets saved and/or where/how it gets fit from.

  • LSQ_DB_fname_stem is set to "": LsqDB is neither saved to nor read from file;
  • LSQ_DB_fname_stem is given:
    • file not present: LsqDB saved to disk and fit to;
    • file present:
      • fit_from_LSQ_DB is true: fit to the LsqDB on disk;
      • fit_from_LSQ_DB is false: rename old LsqDB; make, save and fit to a new LsqDB.

Create LsqDB & fit it separately

It is also possible to decouple making the least-squares database from fitting to it.

ACE1pack.make_ace_dbFunction

make_ace_db(params::Dict) -> LsqDB

Makes a LsqDB from given parameters' dictionary. For params see ?db_params; parameters from fit_params also work, except unnecessary entries will be ignored. Returns IPFitting.LsqDB

source
Missing docstring.

Missing docstring for fit_ace_db. Check Documenter's build log for details.

In fact, fit_ace() just calls both of these in one go.

Reading parameters in from file

Dictionaries may be read in from file with

params = load_dict("params.json")
# or 
params = load_dict("params.yaml")

There is a convenience function fill_defaults() that recursively fills in any missing values with defaults, so that only mandatory or non-default values have to be saved in the files.

ACE1pack.fill_defaultsFunction

fill_defaults(params::Dict; param_key = "fit_params") -> params

Recursively updates any missing entries with default parameters. Accepted param_key values and corresponding functions:

    "fit_params" => ACE1pack.fit_params,
    "data" => ACE1pack.data_params,
    "solver" => ACE1pack.solver_params,
    "basis" => ACE1pack.basis_params,
    "ace" => ACE1pack.ace_basis_params,  
    "pair" => ACE1pack.pair_basis_params,
    "radial" => ACE1pack.radial_basis_params,
    "transform" => ACE1pack.transform_params, 
    "degree" => ACE1pack.degree_params,
    "P" => ACE1pack.regularizer_params
source

Examples of minimal set of parameters

Minimal set

To give an overview of the structure of the parameters' dictionary below is an example with only the mandatory values filled in.

mandatory_params = Dict(
    "data" => Dict(
        "fname" => "training_set.xyz"),
    "basis" => Dict(
        "main_ace" => Dict(
            "species" => ["Ti", "Al"],  
            "N" => 2,                   # correlation order
            "maxdeg" => 10,             # polynomial degree
            "type" => "ace"),           # specifies many-body/ace basis functions 
        "main_pair" => Dict(
            "species" => ["Ti", "Al"],  
            "maxdeg" => 4,              # polynomial degree for the 2-body functions
            "type" => "pair"            # specify 2-body basis
            ),),
    "solver" => Dict(
        "type" => "rrqr"),              # use rank-revealing QR factorisation 
    "e0" => Dict(                       # isolated atom energies, eV
        "Ti" => -1586.0195,
        "Al" => -105.5954))

With all default values

The following is the full set of parameters, including the default values.

params_with_defaults = Dict(
    "data" => Dict(
        "fname" => "training_set.xyz", # mandatory
        "energy_key" => "dft_energy",
        "force_key" => "dft_force",
        "virial_key" => "dft_virial"),
    "basis" => Dict(
        "main_ace" => Dict(
            "species" => ["Ti", "Al"],  # mandatory
            "N" => 2,                   # mandatory 
            "maxdeg" => 10,             # mandatory 
            "type" => "ace",            # mandatory/defines this as the many-body basis & params
            "r0" => 2.5,                # poly transform parameter, Å
            "radial" => Dict(           # parameters for radial basis of ACE 
                "r0" => 2.5,            # from "main_ace" dictionary
                "rcut" => 5.0,          # outter cutoff, Å
                "rin" => 0.5 * r0,      # inner cutoff, Å
                "pcut" => 2,            # outter cutoff parameter
                "pin" => 2,             # inner cutoff parameter
                "type" => "radial" ),   # mandatory/defines this as radial basis
            "transform" => Dict(        # radial transform to use
                "type" => "polynomial", # of 1/(1+r/r0)^2 - type
                "p" => 2, 
                "r0" => 2.5),
            "degree" => ...),           # way to specify the total polynomial degree
        "main_pair" => Dict(
            "species" => ["Ti", "Al"],  # mandatory 
            "maxdeg" => 4,              # mandatory 
            "type" => "pair",           # mandatory/defines this as pair basis 
            "r0" => 2.5,                # poly transform parameter, Å
            "rcut" => 5.0,              # outer cutoff, Å
            "rin" => 0.0,               # inner cutoff, Å
            "pcut" => 2,                # outter cutoff parameter 
            "pin" => 0,                 # inner cutoff parameter
            "transform" => Dict(        # radial transform to use
                "type" => "polynomial", # of 1/(1+r/r0)^2 - type
                "p" => 2, 
                "r0" => 2.5),),),
    "solver" => Dict(
        "type" => "rrqr",               # mandatory/defines this as rrqr solver
        "rrqr_tol" => 1e-5),            # convergence tolerance parameter
    "e0" => Dict(                       # mandatory
        "Ti" => -1586.0195,
        "Al" => -105.5954), 
    "weights" => Dict(                  # defines relative importance of energy vs weight vs virial observations
        "default" => Dict(              
            "E" => 1.0,
            "F" => 1.0, 
            "V" => 1.0)),
    "P" => nothing,                     # additional regularizer/prior
    "ACE_fname" => "ACE_fit.json",      # filename to save ACE model to
    "LSQ_DB_fname_stem" => "",          # do not save ACE LsqDB
    "fit_from_LSQ_DB" => false          # do not refit to a present database
    )