simsopt._core package

class simsopt._core.Derivative(data={})

Bases: object

This class stores the derivative of a scalar output wrt to the individual Optimizable classes that are required to compute this output.

The idea of this class is as follows:

Consider a situation

inA = OptimA()
inB = OptimB()
inter1 = Intermediate1(inA, inB)
inter2 = Intermediate2(inA, inB)
obj = Objective(inter1, inter2)

Then obj.dJ(partials=True) will return a Derivative object containing a dictionary

{
    inA : dobj/dinA,
    inB : dobj/dinB,
}

with

dobj/dinA = dobj/dinter1 * dinter1/dinA + dobj/dinter2 * dinter2/dinA
dobj/dinB = dobj/dinter1 * dinter1/dinB + dobj/dinter2 * dinter2/dinB

SIMSOPT computes these derivatives by first computing dobj/dinter1 and dobj/dinter2 and then passing this vector to Intermediate1.vjp and Intermediate2.vjp, which returns

{
    inA: dobj/dinter1 * dinter1/dinA
    inB: dobj/dinter1 * dinter1/dinB
}

and

{
    inA: dobj/dinter2 * dinter2/dinA
    inB: dobj/dinter2 * dinter2/dinB
}

respectively. Due to the overloaded __add__ and __iadd__ functions adding the Derivative objects than results in the desired

{
    inA: dobj/dinter1 * dinter1/dinA + dobj/dinter2 * dinter2/dinA
    inB: dobj/dinter1 * dinter1/dinB + dobj/dinter2 * dinter2/dinB
}

This Derivative can then be used to obtain partial derivatives or the full gradient of J, via

dJ = obj.dJ(partials=True)
dJ_by_dinA = dJ(inA) # derivative of Objective w.r.t. to OptimA
dJ_by_dinB = dJ(inB) # derivative of Objective w.r.t. to OptimB
gradJ = dJ(obj) # gradient of Objective

For the common case in which you just want the gradient of obj.J and do not need the individual partial derivatives, the argument partials=True can be omitted in obj.dJ(). In this case, obj.dJ() directly returns the gradient rather than returning the Derivative object, acting as a shorthand for obj.dJ(partials=True)(obj). This behavior is implemented with the decorator derivative_dec.

__call__(optim, as_derivative=False)

Get the derivative with respect to all DOFs that optim depends on.

Parameters:

optim – An Optimizable object

exception simsopt._core.ObjectiveFailure

Bases: Exception

Defines a custom exception used to indicate failure when evaluating the objective function. For example, if Vmec or Spec fail to converge, this exception will be thrown. The simsopt solvers will catch this specific exception (not others) and set the objective function to a large number.

class simsopt._core.Optimizable(x0: Sequence[Real] | NDArray[Any, float64] | None = None, names: Sequence[str] | None = None, fixed: Sequence[bool] | NDArray[Any, bool_] | None = None, lower_bounds: Sequence[Real] | NDArray[Any, float64] | None = None, upper_bounds: Sequence[Real] | NDArray[Any, float64] | None = None, *, dofs: DOFs | None = None, external_dof_setter: Callable[[...], None] | None = None, depends_on: Sequence[Optimizable] | None = None, opt_return_fns: Sequence[Sequence[str]] | None = None, funcs_in: Sequence[Callable[[...], Sequence[Real] | NDArray[Any, float64] | Real]] | None = None, **kwargs)

Bases: Callable, Hashable, GSONable

Experimental callable ABC that provides lego-like optimizable objects that can be used to partition the optimization problem into a graph.

The class provides many features that simplify defining the optimization problem.

  1. Optimizable and its subclasses define the optimization problem. The optimization problem can be thought of as a directed acycling graph (DAG), with each instance of Optimizable being a vertex (node) in the DAG. Each Optimizable object can take other Optimizable objects as inputs and through this container logic, the edges of the DAG are defined.

    Alternatively, the input Optimizable objects can be thought of as parents to the current Optimizable object. In this approach, the last grand-child defines the optimization problem by embodying all the elements of the parents and grand-parents.

    Each call to child instance gets in turn propagated to the parent. In this way, the last child acts as the final optimization problem to be solved. For an example of the final optimization node, refer to simsopt.objectives.least_squares.LeastSquaresProblem

  2. The class automatically partitions degrees of freedoms (DOFs) of the optimization problem to the associated Optimizable nodes. Each DOF defined in a parent gets passed down to the children as a needed DOF for the child. So a DOF needed by parent node can be given as an input to the methods in the child node. Any of the DOFs could be fixed in which case, it should be removed as an argument to the call-back function from the final Optimizable node.

  3. The class implements a callable hook that provides minimal caching. All derived classes have to register methods that return objective function type values. This is done by implementing the following class attribute in the class definition: .. code-block:: python

    return_fn_map = {‘name1’: method1, ‘name2’: method, …}

    The Optimizable class maintains the list of return functions needed by each of the calling Optimizable objects either during child initialization or later using the provided methods. The calling optimizable object could then call the Optimizable object directly using the __call__ hook or could call the individual methods.

    This back and forth propagation of DOFs partitioning and function calls happens dynamically.

  4. The class is hashable and the names of the instances are unique. So instances of Optimizable class can be used as keys.

Note

  1. If the Optimizable object is called using the __call__ hook, make sure to supply the argument child=self

  2. __init__ takes instances of subclasses of Optimizable as input and modifies them to add the current object as a child for input objects. The return fns of the parent object needed by the child could be specified by using opt_return_fns argument

__add__(other)

Add two Optimizable objects

__eq__(other: Optimizable) bool

Checks the equality condition

Parameters:

other – Another object of subclass of Optimizable

Returns: True only if both are the same objects.

__init__(x0: Sequence[Real] | NDArray[Any, float64] | None = None, names: Sequence[str] | None = None, fixed: Sequence[bool] | NDArray[Any, bool_] | None = None, lower_bounds: Sequence[Real] | NDArray[Any, float64] | None = None, upper_bounds: Sequence[Real] | NDArray[Any, float64] | None = None, *, dofs: DOFs | None = None, external_dof_setter: Callable[[...], None] | None = None, depends_on: Sequence[Optimizable] | None = None, opt_return_fns: Sequence[Sequence[str]] | None = None, funcs_in: Sequence[Callable[[...], Sequence[Real] | NDArray[Any, float64] | Real]] | None = None, **kwargs)
Parameters:
  • x0 – Initial state (or initial values of DOFs)

  • names – Human identifiable names for the DOFs

  • fixed – Array describing whether the DOFs are free or fixed

  • lower_bounds – Lower bounds for the DOFs

  • upper_bounds – Upper bounds for the DOFs

  • dofs – Degrees of freedoms as DOFs object

  • external_dof_setter – Function used by derivative classes to handle DOFs outside of the dofs object within the class. Mainly used when the DOFs are primarily handled by C++ code. In that case, for all intents and purposes, the internal dofs object is a duplication of the DOFs stored elsewhere. In such cases, the internal dofs object is used to handle the dof partitioning, but external dofs are used for computation of the objective function.

  • depends_on – Sequence of Optimizable objects on which the current Optimizable object depends on to define the optimization problem in conjuction with the DOFs. If the optimizable problem can be thought of as a direct acyclic graph based on dependencies, the optimizable objects supplied with depends_on act as parent nodes to the current Optimizable object in such an optimization graph

  • opt_return_fns – Specifies the return value for each of the Optimizable object. Used in the case, where Optimizable object can return different return values. Typically return values are computed by different functions defined in the Optimizable object. The return values are selected by choosing the functions. To know the various return values, use the Optimizable.get_return_fn_names function. If the list is empty, default return value is used. If the Optimizable object can return multiple values, the default is the array of all possible return values.

  • funcs_in – Instead of specifying depends_on and opt_return_fns, specify the methods of the Optimizable objects directly. The parent objects are identified automatically. Doesn’t work with funcs_in with a property decorator

__mul__(other)

Multiply an Optimizable object by a scalar

__rmul__(other)

Multiply an Optimizable object by a scalar

_abc_impl = <_abc_data object>
_add_child(child: Optimizable) None

Adds another Optimizable object as child. All the required processing of the dependencies is done in the child node. This method is used mainly to maintain 2-way link between parent and child.

Parameters:

child – Direct dependent (child) of the Optimizable object

_get_ancestors() list[Optimizable]

Get all the ancestors of the current Optimizable object

Returns:

List of Optimizable objects that are parents of current Optimizable objects

_ids = count(1)
_remove_child(other: Optimizable) None

Remove the specific Optimizable object from the children list.

Parameters:

child – Direct dependent (child) of the Optimizable object

_update_full_dof_size_indices() None

Updates the full DOFs lengths for this instance and those of the children. Updates the ancestors attribute as well.

Call this function whenever parents are added or removed. Recursively calls the same function in children.

add_parent(index: int, other: Optimizable) None

Adds another Optimizable object as parent at specified index.

Parameters:
  • int – Index of the parent’s list

  • other – Another Optimizable object to be added as parent

add_return_fn(child: Optimizable, fn: str | Callable) None

Add return function to the list of the return functions called by the child Optimizable object

Parameters:
  • child – an Optimizable object that is direct dependent of the current Optimizable instance

  • fn – method of the Optimizable object needed by the child

append_parent(other: Optimizable) None

Appends another Optimizable object to parents list

Parameters:

other – New parent Optimizable object

as_dict(serial_objs_dict=None) dict

A JSON serializable dict representation of an object.

property bounds: Tuple[Sequence[Real] | NDArray[Any, float64], Sequence[Real] | NDArray[Any, float64]]

Lower and upper bounds of the free DOFs associated with the current Optimizable object and those of its ancestors

property dof_names: Sequence[str]

Names (Identifiers) of the DOFs associated with the current Optimizable object and those of its ancestors

property dof_size: Integral

Total number of free DOFs associated with the Optimizable object as well as parent Optimizable objects.

property dofs: DOFs

Return all the attributes of local degrees of freedom via DOFs object. Mainly used to conform with the default as_dict method of GSONable and to share DOFs object between multiple Optimizable objects

property dofs_free_status: Sequence[bool] | NDArray[Any, bool_]

Boolean array denoting whether the DOFs associated with the current and ancestors Optimizable objects are free or not

fix(key: Integral | str) None

Set the fixed attribute for the given degree of freedom.

Parameters:

key – DOF identifier

fix_all() None

Set the ‘fixed’ attribute for all the degrees of freedom associated with the current Optimizable object including those of ancestors.

classmethod from_file(filename: str)
classmethod from_str(input_str: str, fmt='json')
property full_bounds: Tuple[Sequence[Real] | NDArray[Any, float64], Sequence[Real] | NDArray[Any, float64]]

Lower and upper bounds of the fixed and free DOFs associated with the current Optimizable object and those of its ancestors

property full_dof_names: Sequence[str]

Names (Identifiers) of the DOFs associated with the current Optimizable object and those of its ancestors

property full_dof_size: Integral

Total number of all (free and fixed) DOFs associated with the Optimizable object as well as parent Optimizable objects.

property full_lower_bounds: Sequence[Real] | NDArray[Any, float64]

Lower bounds of the fixed and free DOFs associated with the current Optimizable object and those of its ancestors

property full_upper_bounds: Sequence[Real] | NDArray[Any, float64]

Upper bounds of the fixed and free DOFs associated with the current Optimizable object and those of its ancestors

property full_x: Sequence[Real] | NDArray[Any, float64]

Numeric values of all the DOFs (both free and fixed) associated with the current Optimizable object and those of its ancestors

get(key: Integral | str) Real

Get the value of specified DOF. Even fixed dofs can be obtained individually.

Parameters:

key – DOF identifier

get_parent_return_fns_list() List[List[Callable]]

Get a list of the funcs returned by the parents as list of lists

Returns:

The funcs returned by all the parents of the Optimizable object

get_return_fn_list() List[List[Callable]]

Gets return functions from this Optimizable object used by all the child Optimizable objects

Returns:

List of methods that return a value when the current Optimizable object is called from the children.

get_return_fn_names() List[str]

Return the names of the functions that could be used as objective functions.

Returns:

List of function names that could be used as objective functions

get_return_fns(child: Optimizable) List[Callable]

Gets return functions from this Optimizable object used by the child Optimizable object

Parameters:

child – Dependent Optimizable object

Returns:

List of methods that return a value when the current Optimizable object is called from the child

is_fixed(key: Integral | str) bool

Checks if the specified dof is fixed

Parameters:

key – DOF identifier

is_free(key: Integral | str) bool

Checks if the specified dof is free

Parameters:

key – DOF identifier

property local_bounds: Tuple[Sequence[Real] | NDArray[Any, float64], Sequence[Real] | NDArray[Any, float64]]

Lower and upper bounds of the free DOFs associated with this Optimizable object

property local_dof_names: Sequence[str]

Names (Identifiers) of the DOFs associated with this Optimizable object

property local_dof_size: Integral

Number of free DOFs associated with the Optimizable object.

Returns:

Number of free DOFs associated with the Optimizable object.

property local_dofs_free_status: Sequence[bool] | NDArray[Any, bool_]

Boolean array denoting whether the DOFs associated with the current Optimizable object are free or not

local_fix_all() None

Set the ‘fixed’ attribute for all local degrees of freedom associated with the current Optimizable object.

property local_full_dof_names: Sequence[str]

Names (Identifiers) of the DOFs associated with this Optimizable object

property local_full_dof_size: Integral

Number of all (free and fixed) DOFs associated with the Optimizable object.

Returns:

Total number of free and fixed DOFs associated with the Optimizable object.

property local_full_lower_bounds: Sequence[Real] | NDArray[Any, float64]

Get the lower bounds of the free and fixed dofs of this Optimizable object.

property local_full_upper_bounds: Sequence[Real] | NDArray[Any, float64]

Get the upper bounds of the free and fixed dofs of this Optimizable object.

property local_full_x

Numeric values of all DOFs (both free and fixed) associated with this Optimizable object

property local_lower_bounds: Sequence[Real] | NDArray[Any, float64]

Lower bounds of the free DOFs associated with this Optimizable object

local_unfix_all() None

Unset the ‘fixed’ attribute for all local degrees of freedom associated with the current Optimizable object.

property local_upper_bounds: Sequence[Real] | NDArray[Any, float64]

Upper bounds of the free DOFs associated with this Optimizable object

property local_x: Sequence[Real] | NDArray[Any, float64]

Numeric values of the free DOFs associated with this Optimizable object

property lower_bounds: Sequence[Real] | NDArray[Any, float64]

Lower bounds of the free DOFs associated with the current Optimizable object and those of its ancestors

property parent_return_fns_no: int

Compute the total number of the return funcs of all the parents of the Optimizable object

Returns:

The total number of the return funcs of the Optimizable object’s parents.

plot_graph(show=True)

Plot the directed acyclical graph that represents the dependencies of an Optimizable on its parents. The workflow is as follows: generate a networkx DiGraph using the traversal function defined below. Next, call graphviz_layout which determines sensible positions for the nodes of the graph using the dot program of graphviz. Finally, networkx plots the graph using matplotlib.

Note that the tool network2tikz at https://github.com/hackl/network2tikz can be used to convert the networkx DiGraph and positions to a latex file for publication.

Parameters:

show – Whether to call the show() function of matplotlib.

Returns:

The networkx graph corresponding to this Optimizable’s directed acyclical graph and a dictionary of node names that map to sensible x, y positions determined by graphviz

pop_parent(index: int = -1) Optimizable

Removes the parent Optimizable object at specified index.

Parameters:

index – Index of the list of the parents

Returns:

The removed parent Optimizable object

recompute_bell(parent=None)

Function to be called whenever new DOFs input is given or if the parent Optimizable’s data changed, so the output from the current Optimizable object is invalid.

This method gets called by various DOF setters. If only the local DOFs of an object are being set, the recompute_bell method is called in that object and also in the descendent objects that have a dependency on the object, whose local DOFs are being changed. If gloabl DOFs of an object are being set, the recompute_bell method is called in the object, ancestors of the object, as well as the descendents of the object.

Need to be implemented by classes that provide a dof_setter for external handling of DOFs.

remove_parent(other: Optimizable)

Removes the specified Optimizable object from the list of parents.

Parameters:

other – The Optimizable object to be removed from the list of parents

replace_dofs(dofs)

Calls all the required functions in correct order if the DOFs object is replaced manually by the user :param dofs: DOFs object

return_fn_map: Dict[str, Callable] = NotImplemented
save(filename=None, fmt=None, **kwargs)
set(key: Integral | str, new_val: Real) None

Update the value held the specified DOF. Even fixed dofs can be set this way

Parameters:
  • key – DOF identifier

  • new_val – New value of the DOF

set_lower_bound(key: Integral | str, new_val: Real) None

Update the value of the lower bound of a specified DOF. Even lower bounds of fixed dofs can be set this way

Parameters:
  • key – DOF identifier

  • new_val – New value of the lower bound

set_recompute_flag(parent=None)
set_upper_bound(key: Integral | str, new_val: Real) None

Update the value of the upper bound of a specified DOF. Even upper bounds of fixed dofs can be set this way

Parameters:
  • key – DOF identifier

  • new_val – New value of the upper bound

unfix(key: Integral | str) None

Unset the fixed attribute for the given degree of freedom

Parameters:

key – DOF identifier

unfix_all() None

Unset the ‘fixed’ attribute for all local degrees of freedom associated with the current Optimizable object including those of the ancestors.

property unique_dof_lineage
update_free_dof_size_indices() None

Updates the DOFs lengths for the Optimizable object as well as those of the descendent (dependent) Optimizable objects.

Call this function whenever DOFs are fixed or unfixed or when parents are added/deleted. Recursively calls the same function in children

property upper_bounds: Sequence[Real] | NDArray[Any, float64]

Upper bounds of the free DOFs associated with the current Optimizable object and those of its ancestors

property x: Sequence[Real] | NDArray[Any, float64]

Numeric values of the free DOFs associated with the current Optimizable object and those of its ancestors

property x0

Mimics dataclass behavior for Optimizable

class simsopt._core.OptimizableSum(opts)

Bases: Optimizable

Represents a sum of Optimizable objects. This class is useful for combining terms in an objective function. For now, this feature works on classes for which .J() returns an objective value and .dJ() returns the gradient, e.g. coil optimization.

Parameters:

opts – A python list of Optimizable object to sum.

J()
_abc_impl = <_abc_data object>
_ids = count(1)
dJ(*args, partials=False, **kwargs)
class simsopt._core.ScaledOptimizable(factor, opt)

Bases: Optimizable

Represents an Optimizable object scaled by a constant factor. This class is useful for including a weight in front of terms in an objective function. For now, this feature works on classes for which .J() returns an objective value and .dJ() returns the gradient, e.g. coil optimization.

Parameters:
  • factor – (float) The constant scale factor.

  • opt – An Optimizable object to scale.

J()
_abc_impl = <_abc_data object>
_ids = count(1)
dJ(*args, partials=False, **kwargs)
simsopt._core.load(filename, *args, **kwargs)

Function to load simsopt object from a file. Only JSON format is supported at this time. Support for additional formats will be added in future :param filename: Name of file from which simsopt object has to be initialized

Returns:

Simsopt object

simsopt._core.make_optimizable(func, *args, dof_indicators=None, **kwargs)

Factory function to generate an Optimizable instance from a function to be used with the graph framework.

Parameters:
  • func – Callable to be used in the optimization

  • args – Positional arguments to pass to “func”.

  • dof_indicators – List of strings that match with the length of the args and kwargs. Each string can be either of “opt” - to indicate the argument is optimizable object “dof” - argument that is a degree of freedom for optimization “non-dof” - argument that is not part of optimization. Here ordered property of the dict is used to map kwargs to dof_indicators. Another important thing to consider is dofs related to optimizable objects supplied as arguments should not be given.

  • kwargs – Keyword arguments to pass to “func”.

Returns:

Optimizable object to be used in the graph based optimization. This object has a bound function J() that calls the originally supplied func(). If obj is the returned object, pass obj.J to the LeastSquaresProblem

simsopt._core.save(simsopt_objects, filename, *args, **kwargs)