Optimization Capabilities

MITIM can be used to optimize any custom function (Optimize a custom function) or simulations that have already been developed in the code (Fusion applications), such as VITALS and PORTALS. Make sure you follow the Installation tutorial for information on how to get MITIM working and how to configure your setup.

Once setup has been successful, the following regression test should run smoothly:

python3 MITIM-fusion/tests/OPT_workflow.py

Fusion applications

Optimize a custom function

Optimizing any function (mathematical or a simulation) with MITIM is very easy.

For this tutorial we will need the following modules:

import torch
import numpy as np
from pathlib import Path
from mitim_tools.opt_tools     import STRATEGYtools

Select the location of the MITIM namelist (see Understanding the MITIM namelist to understand how to construct the namelist file) and the folder to work on:

folder    = Path('MITIM-fusion/tests/scratch/mitim_tut')
namelist  = Path('MITIM-fusion/templates/namelist.optimization.yaml')

Then create your custom optimization object as a child of the parent STRATEGYtools.opt_evaluator class. You only need to modify what operations need to occur inside the run() (where operations/simulations happen) and scalarized_objective() (to define what is the target to maximize) methods. In this example, we are using x**2 as our function with a 2% evaluation error, to find x such that x**2=15:

class opt_class(STRATEGYtools.opt_evaluator):
   def __init__(self, folder, namelist):
      # Store folder, namelist. Read namelist
      super().__init__(folder, namelist=namelist)
      # ----------------------------------------

      # Problem description (rest of problem parameters are taken from namelist)
      self.optimization_options["problem_options"]["dvs"] = ["x"]
      self.optimization_options["problem_options"]["dvs_min"] = [0.0]
      self.optimization_options["problem_options"]["dvs_max"] = [20.0]

      self.optimization_options["problem_options"]["ofs"] = ["z", "zval"]
      self.name_objectives = ["zval_match"]

   def run(self, paramsfile, resultsfile):
      # Read stuff
      folderEvaluation, numEval, dictDVs, dictOFs = self.read(paramsfile, resultsfile)

      # Operations
      dictOFs["z"]["value"] = dictDVs["x"]["value"] ** 2
      dictOFs["z"]["error"] = dictOFs["z"]["value"] * 2e-2

      dictOFs["zval"]["value"] = 15.0
      dictOFs["zval"]["error"] = 0.0

      # Write stuff
      self.write(dictOFs, resultsfile)

   def scalarized_objective(self, Y):
      ofs_ordered_names = np.array(self.optimization_options["problem_options"]["ofs"])

      of = Y[..., ofs_ordered_names == "z"]
      cal = Y[..., ofs_ordered_names == "zval"]

      # Residual is defined as the negative (bc it's maximization) normalized (1/N) norm of radial & channel residuals -> L1
      res = -1 / of.shape[-1] * torch.norm((of - cal), p=1, dim=-1)

      return of, cal, res

Then, create an object from the previously defined class:

opt_fun1D  = opt_class(folder,namelist=namelist)

Tip

Note that at this point, you can pass any parameter that you want, just changing the __init__() method as appropriate.

Now we can create and launch the MITIM optimization process from the beginning (i.e. cold_start = True):

MITIM_BO = STRATEGYtools.MITIM_BO( opt_fun1D, cold_start = True )
MITIM_BO.run()

Once finished, we can plot the results easily with:

opt_fun1D.plot_optimization_results(analysis_level=2)

Understanding the MITIM namelist

Checkout file MITIM-fusion/templates/namelist.optimization.yaml, which has comprehensive comments.

Under development

Understanding the MITIM outputs

As a result of the last step of Optimize a custom function, optimization results are plotted…

Under development