Overview of mcasopt

The mcasopt package acts as an interface between MCAS and the numerical optimisation solvers provided by scipy.optimize.minimize. It uses Slurm to run MCAS simulations on the Spartan HPC system, and wraps this in a standard Python function that can be passed to the solver.

How to use mcasopt

  1. Define a starting MCAS parameters file, which we will call "n+12C.inp";

  2. Define a resonance criteria file, which we will call "n+12C.crit";

  3. Make sure you have a copy of the file "AMDC-masses.dat"; and

  4. Define all of the mcasopt settings in a TOML file, which we will call "n+12C.toml" (see the example below).

Listing 3 An example mcasopt settings file.
 1[experiment]
 2name = "n+12C"
 3input_file = "n+12C.inp"
 4criteria_file = "n+12C.crit"
 5mcas_path = "./mcas/mcas5.4"
 6amdc_masses_path = "AMDC-masses.dat"
 7
 8[solver]
 9# method = "Nelder-Mead"
10method = "BFGS"
11# bounds = []
12# sleep_duration = 60
13cache_file = "n+12C.cache"
14sleep_duration = 0
15log_level = "INFO"
16epsilon = 1e-3

Then write a Python script, which we will call "example.py", that performs the following steps:

  1. Defines a function that return the MCAS input for a given parameter vector x;

  2. Defines an initial parameter vector x_0;

  3. Loads the configuration settings from "n+12C.toml" with mcasopt.load_config();

  4. Starts the optimisation solver with mcasopt.minimise(); and

  5. Prints and/or the saves the solution returned by the solver.

Listing 4 An example mcasopt script.
 1#!/usr/bin/env python3
 2
 3import mcasopt
 4
 5
 6# Define a function that returns the MCAS input for parameter vector ``x``.
 7def input_fun(mcas_input, x):
 8    # Adjust the MCAS input according to the values in ``x``.
 9    mcas_input.model.v0 = [x[0], 0.0, x[1]]
10    return mcas_input
11
12
13def main():
14    # Define the initial parameter vector.
15    x_0 = [-49, -47.1]
16
17    # Load the experiment configuration.
18    config = mcasopt.load_config('n+12C.toml')
19
20    # Define an evaluator that runs MCAS simulations locally.
21    evaluator = mcasopt.McasEvaluator.run_locally(config, input_fun)
22
23    # Run the solver and obtain the approximate solution.
24    result = mcasopt.minimise(evaluator, x_0, config.solver)
25
26    # Print the solution vector.
27    print(f'Solution: {result.x}')
28
29
30if __name__ == "__main__":
31    main()

Note

See the next section, Running mcasopt on Spartan, for instructions on how to run mcasopt on Spartan.

What mcasopt.minimise() does

  1. Defines a function that takes a parameter vector \(x = [x_1 \ x_2 \ ... \ x_N]\) and:

    1. Use the MACS input function \(f\) (in this case, defined on lines 6-10 of the example script) to write the following MCAS input files:

    • An MCAS input file for \(f(x)\);

    • For each element \(x_i \in x\), an MCAS input file for \(f(x + \epsilon_i)\);

    • For each element \(x_i \in x\), an MCAS input file for \(f(x - \epsilon_i)\);

    1. Launches an MCAS simulation for each of these \(2N + 1\) input files, using the Slurm settings (in this case, defined in lines 18-25 of settings file);

    2. Waits until the \(2N + 1\) simulations have finished; and

    3. Returns the measure \(g(x)\) of how well the MCAS simulation at location \(x\) matches the optimisation criteria defined in the settings file, and an approximation of the Jacobian \(\mathbf{J}(x) = \left[\frac{g(x + \epsilon_i) - g(x - \epsilon_i)}{2 \epsilon_i}\right]\).

  2. Calls the solver, providing the function created in step #1, starting from the initial parameter vector x_0 (in this case, defined on line 13 of the example script), and using the solver settings (in this case, defined in lines 8-16 of the settings file).

What the solver does

The solver will perform the following loop:

  1. Evaluate the function at the current location \(x^k\). This launches a number of MCAS simulations (as described above), in order to evaluate:

    • The goodness of fit \(g(x^k)\); and

    • The Jacobian \(\mathbf{J}(x^k)\).

  2. When all of the MCAS simulations launched in step #1 have completed, the solver will either:

    • Accept \(x^k\) as the approximate solution, and return \(x^k\); or

    • Search for a new point \(x^{k+1}\) at which to evaluate the function, and return to step #1.