diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c53884ad..17d610d7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -64,7 +64,7 @@ repos: # Autoremoves unused Python imports - repo: https://github.com/hadialqattan/pycln - rev: v2.5.0 + rev: v2.6.0 hooks: - id: pycln name: pycln (python) diff --git a/doc/source/examples/bo_with_astra.rst b/doc/source/examples/bo_with_astra.rst index 8eec0cae..eadd7cd0 100644 --- a/doc/source/examples/bo_with_astra.rst +++ b/doc/source/examples/bo_with_astra.rst @@ -23,7 +23,7 @@ Two beam parameters are minimized: - the bunch_length, - and the transverse emittances ``'emittance'`` in :math:`\mathrm{µm}`, which are combined into one single parameter: :math:`\log \epsilon_{n,x} \epsilon_{n,y}` and where the logarithm is used for better optimization as the emittance can span over several orders of magnitude. -In addition, the transverse normalized emittances in :math:`x` and :math:`y` are stored as additional analyzed parameters ``'emittance_x'`` and ``'emittance_y'``. +In addition, the transverse normalized emittances in :math:`x` and :math:`y` are stored as observables ``'emittance_x'`` and ``'emittance_y'``. The optimization is carried out using an :class:`~optimas.generators.AxSingleFidelityGenerator` and a diff --git a/doc/source/examples/ps_grid_sampling.rst b/doc/source/examples/ps_grid_sampling.rst index fe164ba3..163723b6 100644 --- a/doc/source/examples/ps_grid_sampling.rst +++ b/doc/source/examples/ps_grid_sampling.rst @@ -25,9 +25,10 @@ analysis function. See see :ref:`optimas-with-simulations` for more details. The :class:`~optimas.generators.GridSamplingGenerator` generates a uniform multidimensional grid of samples to evaluate. The grid extends from the lower -to the upper bound of each :class:`~optimas.core.VaryingParameter` and is -divided in ``n_steps`` steps. In this case, -where :math:`l_b=0` and :math:`u_b=15`, the grid of sample looks like: +to the upper bound of each variable (as defined in the +:class:`~gest_api.vocs.VOCS` object) and is divided in ``n_steps`` steps. +In this case, where :math:`l_b=0` and :math:`u_b=15`, the grid of samples +looks like: .. plot:: diff --git a/doc/source/examples/ps_line_sampling.rst b/doc/source/examples/ps_line_sampling.rst index 2175b388..2bbf3248 100644 --- a/doc/source/examples/ps_line_sampling.rst +++ b/doc/source/examples/ps_line_sampling.rst @@ -25,13 +25,13 @@ analysis function. See see :ref:`optimas-with-simulations` for more details. The :class:`~optimas.generators.LineSamplingGenerator` generates a multidimensional distribution of samples where, as opposed to the -:class:`~optimas.generators.GridSamplingGenerator`, only one -:class:`~optimas.core.VaryingParameter` is varied at a time while the other -remain with their default values. Each parameter varies between its lower -and upper bound in ``n_steps`` equally-spaced steps. In this case, -where :math:`x_0` and :math:`x_1` have a default values of :math:`5` and -:math:`6`, respectively, and lower and upper bounds :math:`l_b=0` and -:math:`u_b=15`, the grid of samples look like: +:class:`~optimas.generators.GridSamplingGenerator`, only one variable +is varied at a time while the others remain at their default values. +Each variable varies between its lower and upper bound in ``n_steps`` +equally-spaced steps. In this case, where :math:`x_0` and :math:`x_1` +have default values of :math:`5` and :math:`6`, respectively, and lower +and upper bounds :math:`l_b=0` and :math:`u_b=15`, the grid of samples +looks like: .. plot:: diff --git a/doc/source/user_guide/basic_usage/analyze_output.rst b/doc/source/user_guide/basic_usage/analyze_output.rst index 40298b57..27f7caf2 100644 --- a/doc/source/user_guide/basic_usage/analyze_output.rst +++ b/doc/source/user_guide/basic_usage/analyze_output.rst @@ -20,16 +20,12 @@ In every run, the following log files are generated: numpy file that contains the `history array `_ of the run. This is a structured array that stores the data of each - evaluation, including the values of the - :class:`~optimas.core.VaryingParameter`\s, - :class:`~optimas.core.Objective`\s, analyzed - :class:`~optimas.core.Parameter`\s and other useful diagnostics. + evaluation, including the values of the variables, objectives, observables, + and other useful diagnostics. The periodicity with which this file is updated can be set with the ``history_save_period`` argument of the :class:`~optimas.explorations.Exploration`. - ``exploration_parameters.json``: JSON file containing a serialized - version of the :class:`~optimas.core.VaryingParameter`\s, - :class:`~optimas.core.Objective`\s and other - :class:`~optimas.core.Parameter`\s of the exploration. + version of the variables, objectives, and observables of the exploration. In addition, if the run is aborted for any reason, two additional files will be created: diff --git a/doc/source/user_guide/basic_usage/basic_setup.rst b/doc/source/user_guide/basic_usage/basic_setup.rst index 30234d22..38ed267d 100644 --- a/doc/source/user_guide/basic_usage/basic_setup.rst +++ b/doc/source/user_guide/basic_usage/basic_setup.rst @@ -5,9 +5,8 @@ This section covers the basic workflow of setting up an optimas :class:`~optimas.explorations.Exploration`, which is typically used to launch an optimization or parameter scan. This involves: -- Specifying the parameters that should be varied during the exploration. -- Specifying the optimization objectives and other parameters that should - analyzed for each evaluation. +- Specifying the variables, objectives, and observables via a + :class:`~gest_api.vocs.VOCS` object. - Choosing a generator. This determines the strategy with which new evaluations are generated. - Choosing an evaluator. This determines how the evaluations are performed and @@ -16,43 +15,36 @@ an optimization or parameter scan. This involves: criteria for ending the exploration. -Parameters to vary -~~~~~~~~~~~~~~~~~~ -The parameters to vary (:class:`~optimas.core.VaryingParameter`) are the -parameters that should be tuned or scanned during the exploration. -For example, if we want to see how the outcome of an evaluation depends on two -parameters named ``x0`` and ``x1`` that can vary in the ranges [0, 15] and -[-5, 5], we would define them as - -.. code-block:: python - - from optimas.core import VaryingParameter - - var_1 = VaryingParameter("x0", 0.0, 15.0) - var_2 = VaryingParameter("x1", -5.0, 5.0) +VOCS +~~~~ +The variables, objectives, constraints, and observables of an exploration are +all specified through a single :class:`~gest_api.vocs.VOCS` object. +- **Variables** are the parameters that should be tuned or scanned during the + exploration, together with their allowed range. +- **Objectives** define the outcomes of an evaluation that optimas should + optimize (maximize or minimize). +- **Observables** are optional quantities that do not play a role in the + optimization but that should be recorded at each evaluation (for example, + because they provide useful diagnostic information). -Objectives and other analyzed parameters -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The objectives (:class:`~optimas.core.Objective`) define the outcomes of an -evaluation that optimas should optimize (maximize or minimize) or scan. - -Optionally, a list of parameters (:class:`~optimas.core.Parameter`) that do not -play a role in the optimization but that should be analyzed at each evaluation -(for example, because they provide useful information about the evaluations) -can also be given. - -The following code shows how to define one objective ``'f'`` that -should be minimized and two diagnostics ``'diag_1'`` and ``'diag_2'`` that will -also be calculated for each evaluation. +For example, if we want to optimize an objective ``'f'`` (to be minimized) +over two parameters ``x0`` and ``x1`` in the ranges [0, 15] and [-5, 5], +while also recording two diagnostics ``'diag_1'`` and ``'diag_2'``, we would +define the VOCS as: .. code-block:: python - from optimas.core import Objective, Parameter + from gest_api.vocs import VOCS - obj = Objective("f", minimize=True) - diag_1 = Parameter("diag_1") - diag_2 = Parameter("diag_2") + vocs = VOCS( + variables={ + "x0": [0.0, 15.0], + "x1": [-5.0, 5.0], + }, + objectives={"f": "MINIMIZE"}, + observables=["diag_1", "diag_2"], + ) Generator @@ -62,9 +54,8 @@ during the exploration. There are multiple generators implemented in optimas (see :ref:`generators`) that allow for various optimization strategies or parameter scans. -In the example below, the varying parameters, objectives and diagnostics -defined in the previous sections are used to set up a single-fidelity Bayesian -optimizer based on `Ax `_. +In the example below, the VOCS defined above is used to set up a +single-fidelity Bayesian optimizer based on `Ax `_. ``n_init=4`` indicates that 4 random samples will be generated before the Bayesian optimization loop is started (see :class:`~optimas.generators.AxSingleFidelityGenerator` for more details). @@ -73,19 +64,13 @@ Bayesian optimization loop is started (see from optimas.generators import AxSingleFidelityGenerator - gen = AxSingleFidelityGenerator( - varying_parameters=[var_1, var_2], - objectives=[obj], - analyzed_parameters=[diag_1, diag_2], - n_init=4, - ) + gen = AxSingleFidelityGenerator(vocs=vocs, n_init=4) Evaluator ~~~~~~~~~ The evaluator is in charge of getting the trials suggested by the generator and -evaluating them, returning the value of the objectives and other analyzed -parameters. +evaluating them, returning the value of the objectives and other observables. There are two types of evaluators: @@ -101,7 +86,7 @@ There are two types of evaluators: Each evaluation is executed using MPI with the amount or resources (number of processes and GPUs) specified by the user. After executing the script, the output of the evaluation is analyzed with a user-defined function that - calculates the value of the objectives and other analyzed parameters. + calculates the value of the objectives and other observables. See :ref:`optimas-with-simulations` for more details about how to use a :class:`~optimas.evaluators.TemplateEvaluator`. diff --git a/doc/source/user_guide/basic_usage/running_with_simulations.rst b/doc/source/user_guide/basic_usage/running_with_simulations.rst index f90bd365..83c4095a 100644 --- a/doc/source/user_guide/basic_usage/running_with_simulations.rst +++ b/doc/source/user_guide/basic_usage/running_with_simulations.rst @@ -8,9 +8,9 @@ where each evaluation consists of running a simulation that is defined in an external file. This workflow requires: - A template of the simulation script that indicates where the values - of the :class:`~optimas.core.VaryingParameter`\s should be placed. + of the variables should be placed. - A function to analyze the simulation output and determine the value of the - :class:`~optimas.core.Objective`\s and other parameters. + objectives and other observables. This is all handled by defining a :class:`~optimas.evaluators.TemplateEvaluator` that, in it's most basic form, @@ -35,13 +35,13 @@ Creating a simulation template ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The scripts for each simulation are created from a template where the -values of the :class:`~optimas.core.VaryingParameter`\s -are introduced using `Jinja `_ syntax, that -is, using the double-bracket notation ``{{var_name}}``, where ``var_name`` is -the name of the :class:`~optimas.core.VaryingParameter`. +values of the variables are introduced using +`Jinja `_ syntax, that is, using the +double-bracket notation ``{{var_name}}``, where ``var_name`` is the name of +the variable as defined in the :class:`~gest_api.vocs.VOCS` object. As a basic example, a template for a Python script that takes in two -:class:`~optimas.core.VaryingParameter`\s called ``'x'`` and ``'y'``, +variables called ``'x'`` and ``'y'``, computes ``x + y``, and stores the result in a text file would look like: .. code-block:: python @@ -69,7 +69,7 @@ You can define this function directly in the main optimas script, or import it from another file. As an example, assuming that the result of ``x + y`` in the previous section -is an :class:`~optimas.core.Objective` called ``'f'``, the analysis function +is an objective called ``'f'``, the analysis function would look like: .. code-block:: python @@ -78,16 +78,16 @@ would look like: """Analyze the simulation output. This method analyzes the output generated by the simulation to - obtain the value of the optimization objective and other analyzed - parameters, if specified. The value of these parameters has to be - given to the `output_params` dictionary. + obtain the value of the optimization objective and other observables, + if specified. The value of these parameters has to be given to the + `output_params` dictionary. Parameters ---------- simulation_directory : str Path to the simulation folder where the output was generated. output_params : dict - Dictionary where the value of the objectives and analyzed parameters + Dictionary where the value of the objectives and observables will be stored. There is one entry per parameter, where the key is the name of the parameter given by the user.