fol.controls#

Control strategies provided by FoLax.

Identity control#

Authors: Reza Najian Asl, RezaNajian Date: October, 2024 License: FOL/LICENSE

class fol.controls.identity_control.IdentityControl(control_name, control_settings, num_vars)[source]#

Bases: Control

Identity control mapping control variables directly to controlled variables.

This control implements a trivial identity mapping in which the input control vector is returned unchanged as the controlled variable vector. It is primarily intended for cases where no spatial or functional parameterization is required, such as debugging, testing, or optimization workflows where the control variables already represent the desired physical quantities.

The number of control variables and the number of controlled variables are both equal to num_vars and are fixed at construction time.

Parameters:
  • control_name (str) – Name identifier for the control instance.

  • control_settings (dict) – Configuration dictionary. This argument is accepted for interface consistency but is not used by the identity mapping.

  • num_vars (int) – Number of control variables and controlled variables.

ComputeControlledVariables(variable_vector)[source]#

Return the controlled variables corresponding to the input vector.

This identity mapping returns the input control vector unchanged.

Parameters:

variable_vector (jax.numpy.ndarray) – Control variable vector of length num_control_vars.

Returns:

Controlled variable vector equal to variable_vector.

Return type:

jax.numpy.ndarray

Initialize(reinitialize=False)[source]#

Initialize the identity control.

This method sets the number of control variables and controlled variables to num_vars. Initialization is idempotent and may be forced to re-run by setting reinitialize=True.

Parameters:

reinitialize (bool, optional) – If True, forces reinitialization even if already initialized. Default is False.

Returns:

None

Dirichlet boundary control#

Authors: Kianoosh Taghikhani, Kianoosh1989 Date: August, 2025 License: FOL/LICENSE

class fol.controls.dirichlet_control.DirichletControl(control_name, control_settings, fe_mesh, fe_loss)[source]#

Bases: Control

Dirichlet boundary-condition control for finite element problems.

This control maps a user-defined set of learnable Dirichlet boundary DOFs to the global Dirichlet arrays owned by a fol.loss_functions.fe_loss.FiniteElementLoss. It provides a JAX-friendly mechanism to overwrite selected Dirichlet values from a vector of control variables (e.g., during optimization or inverse problems).

The control settings define which DOF components (e.g., "Ux", "Uy", "T") are controlled on which boundary node sets. During Initialize(), the class:

  1. Ensures the associated FE loss is initialized.

  2. Reads the global Dirichlet indices and values from the FE loss.

  3. Builds a flattened index map (into the FE loss Dirichlet arrays) for the subset of Dirichlet DOFs that are controlled.

  4. Stores segment offsets and sizes so the control vector can be broadcast to the corresponding controlled DOFs efficiently.

Parameters:
  • control_name (str) – Name identifier for the control instance.

  • control_settings (dict) –

    Control configuration dictionary. Must contain the key "learning_boundary" mapping DOF names to a list of boundary node-set names. Example:

    {
        "learning_boundary": {
            "Ux": ["left", "right"],
            "Uy": ["top"]
        }
    }
    

  • fe_mesh (Mesh) – Finite element mesh used to resolve boundary node sets via fol.mesh_input_output.mesh.Mesh.GetNodeSet().

  • fe_loss (FiniteElementLoss) – FE loss providing the global Dirichlet index/value arrays and the DOF ordering used to compute DOF indices per node.

settings#

Control configuration dictionary.

Type:

dict

fe_mesh#

Mesh reference used for boundary node set queries.

Type:

Mesh

loss_function#

Associated FE loss object.

Type:

FiniteElementLoss

dirichlet_values#

Copy of the FE loss Dirichlet values array (one value per Dirichlet DOF).

Type:

jax.numpy.ndarray

dirichlet_indices#

Copy of the FE loss Dirichlet global DOF indices.

Type:

jax.numpy.ndarray

learning_dirichlet_indices#

Indices into dirichlet_indices / dirichlet_values for the subset of Dirichlet DOFs that are controlled.

Type:

jax.numpy.ndarray

learning_dirichlet_starts#

Segment start offsets for each (dof, boundary) block appended into learning_dirichlet_indices during initialization.

Type:

jax.numpy.ndarray

learning_dirichlet_sizes#

Segment sizes (number of controlled Dirichlet DOFs) for each (dof, boundary) block appended into learning_dirichlet_indices.

Type:

jax.numpy.ndarray

num_control_vars#

Number of DOF components listed in control_settings["learning_boundary"].

Type:

int

num_controlled_vars#

Total number of individual Dirichlet DOFs affected by this controller.

Type:

int

initialized#

Whether Initialize() has been executed.

Type:

bool

Notes

  • The control vector passed to ComputeControlledVariables() is expanded by repeating each control entry according to learning_dirichlet_sizes. This implies the control vector is interpreted as one scalar per controlled (dof, boundary) block, broadcast to all nodes in that block.

  • This class does not modify the FE loss object directly. It returns an updated Dirichlet value array that can be used by downstream code.

ComputeControlledVariables(variable_vector)[source]#

Compute an updated Dirichlet value array from control variables.

The returned array has the same shape as dirichlet_values. Only the entries corresponding to learning_dirichlet_indices are overwritten.

Broadcasting rule:

Each entry in variable_vector is repeated according to learning_dirichlet_sizes and assigned to the corresponding segment in learning_dirichlet_indices.

Parameters:

variable_vector (jax.numpy.ndarray) – Control variables to assign. Expected to be a 1D array whose length matches the number of (dof, boundary) blocks created during initialization (i.e., len(learning_dirichlet_sizes)).

Returns:

Updated Dirichlet values array with controlled entries overwritten.

Return type:

jax.numpy.ndarray

Raises:

ValueError – If Initialize has not been called, or if variable_vector has an incompatible length for the configured segments.

Initialize(reinitialize=False)[source]#

Initialize index mappings for learnable Dirichlet DOFs.

This method constructs the internal flattened index structures that map controlled Dirichlet DOFs to entries of the FE loss Dirichlet arrays.

It populates: - learning_dirichlet_indices: flattened indices into the FE loss Dirichlet list - learning_dirichlet_starts: start offsets per (dof, boundary) block - learning_dirichlet_sizes: sizes per (dof, boundary) block

Parameters:

reinitialize (bool, optional) – If True, forces rebuilding the mappings even if already initialized. Defaults to False.

Returns:

None

Raises:
  • KeyError – If "learning_boundary" is missing from control_settings.

  • ValueError – If a DOF name in "learning_boundary" is not present in fe_loss.GetDOFs().

Fourier-based control#

Authors: Reza Najian Asl, RezaNajian Date: April, 2024 License: FOL/LICENSE

class fol.controls.fourier_control.FourierControl(control_name, control_settings, fe_mesh)[source]#

Bases: Control

Fourier-based parametric control defined over a finite element mesh.

This control maps a compact set of design variables (Fourier coefficients) to a spatially varying scalar field evaluated at mesh nodes. The nodal field is represented as a truncated cosine Fourier series in the x-, y-, and z-directions, then smoothly projected to user-defined bounds using a sigmoid-based scaling.

Formulation#

Let the mesh contain nodes with coordinates (x_i, y_i, z_i). The user provides one-dimensional frequency arrays x_freqs, y_freqs, and z_freqs. A Cartesian product of these arrays defines a collection of frequency triplets (f_x, f_y, f_z), constructed by calling meshgrid(x_freqs, y_freqs, z_freqs, indexing="ij") and flattening the result. Each triplet corresponds to exactly one cosine basis function.

Given a control vector a of length len(x_freqs) * len(y_freqs) * len(z_freqs) + 1, the unbounded nodal field value at node i is computed as:

  • The first entry a[0] defines a constant (mean) mode and contributes a[0] / 2 to every node.

  • Each remaining entry a[j] multiplies one cosine basis function associated with a frequency triplet (f_x, f_y, f_z) and contributes

    a[j] * cos(pi * f_x * x_i) * cos(pi * f_y * y_i) * cos(pi * f_z * z_i)

    to the nodal value.

The unbounded nodal field K_i is obtained by summing the constant contribution and all cosine-mode contributions.

The nodal field is then mapped to user-defined bounds via a smooth sigmoid projection:

u_i = (max - min) * sigmoid(beta * (K_i - 0.5)) + min

This projection enforces u_i in [min, max] while preserving differentiability for gradient-based optimization.

param control_name:

Name identifier for the control instance.

type control_name:

str

param control_settings:

Dictionary defining the Fourier parameterization. Required keys: "beta", "x_freqs", "y_freqs", "z_freqs". Optional keys: "min" and "max" defining output bounds.

type control_settings:

dict

param fe_mesh:

Finite element mesh providing nodal coordinates via GetNodesX(), GetNodesY(), and GetNodesZ().

type fe_mesh:

Mesh

settings#

Control configuration dictionary provided at construction.

Type:

dict

fe_mesh#

Finite element mesh used to evaluate basis functions.

Type:

Mesh

min#

Lower bound of the controlled field (default: 1e-6 if not set).

Type:

float

max#

Upper bound of the controlled field (default: 1.0 if not set).

Type:

float

beta#

Sigmoid sharpness parameter controlling projection steepness.

Type:

float

x_freqs#

Frequency values in the x-direction.

Type:

jax.numpy.ndarray

y_freqs#

Frequency values in the y-direction.

Type:

jax.numpy.ndarray

z_freqs#

Frequency values in the z-direction.

Type:

jax.numpy.ndarray

frquencies_vec#

Flattened array of frequency triplets with shape (n_modes, 3), where n_modes = len(x_freqs) * len(y_freqs) * len(z_freqs).

Type:

jax.numpy.ndarray

num_control_vars#

Number of control variables (Fourier coefficients), equal to n_modes + 1.

Type:

int

num_controlled_vars#

Number of controlled variables, equal to the number of mesh nodes.

Type:

int

initialized#

Whether Initialize() has been called.

Type:

bool

Notes

The first coefficient a[0] is treated as a mean mode and scaled by 1/2 to match the implemented definition:

K = a[0]/2 + sum_j a[j] * cos_x * cos_y * cos_z

where each a[j] for j >= 1 corresponds to one frequency triplet.

ComputeControlledVariables(variable_vector)[source]#

Evaluate the controlled field at mesh nodes from Fourier coefficients.

This method maps the input control vector to a nodal scalar field by evaluating a truncated cosine Fourier series at each mesh node. The resulting field is passed through a sigmoid transformation to enforce lower and upper bounds.

The first entry of variable_vector corresponds to the constant (mean) mode. The remaining entries correspond to cosine modes defined by the Cartesian product of x_freqs, y_freqs, and z_freqs.

Parameters:

variable_vector (jax.numpy.ndarray) – One-dimensional array of Fourier coefficients. Its length must equal num_control_vars.

Returns:

Array of controlled values evaluated at mesh nodes, with shape (num_nodes,).

Return type:

jax.numpy.ndarray

Raises:

ValueError – If Initialize has not been called or if the input vector has an incompatible length.

Finalize()[source]#

Finalize the control.

This method is called once at the end of a training or optimization process. Derived classes may override it to release resources or perform cleanup. The default base class does not implement any finalization logic.

Returns:

None

Initialize(reinitialize=False)[source]#

Initialize the Fourier basis and control dimensions.

This method prepares the frequency grid, determines the number of control variables, and caches frequency combinations for efficient evaluation. Initialization is performed once unless reinitialize is set to True.

Parameters:

reinitialize (bool, optional) – If True, forces reinitialization even if already initialized. Default is False.

Returns:

None

Raises:

KeyError – If required frequency arrays or parameters are missing from control_settings.

Voronoi-based control (2D)#

Authors: Kianoosh Taghikhani, kianoosh1989 Date: October, 2024 License: FOL/LICENSE

class fol.controls.voronoi_control2D.VoronoiControl2D(control_name, control_settings, fe_mesh)[source]#

Bases: Control

Voronoi-based parametric control in two dimensions.

This control maps a vector of control variables to a nodal scalar field using a Voronoi tessellation defined by a set of seed points in the two-dimensional domain. Each mesh node is assigned the value associated with the nearest seed point, measured by Euclidean distance in the (x, y) plane.

The control variables consist of: - x-coordinates of the Voronoi seed points, - y-coordinates of the Voronoi seed points, - scalar values associated with each seed.

For each mesh node, the controlled value is selected from the seed whose coordinates are closest to the node coordinates. This produces a piecewise-constant field over the mesh, with discontinuities along Voronoi cell boundaries.

The number of control variables is three times the number of seeds, and the number of controlled variables equals the number of mesh nodes.

Parameters:
  • control_name (str) – Name identifier for the control instance.

  • control_settings (dict) – Dictionary defining the Voronoi parameterization. Required entries include "number_of_seeds" and "E_values". The length of "E_values" must match number_of_seeds.

  • fe_mesh (Mesh) – Finite element mesh providing nodal coordinates.

ComputeControlledVariables(variable_vector)[source]#

Compute the nodal field induced by the Voronoi control.

This method interprets the input control vector as concatenated arrays of seed x-coordinates, seed y-coordinates, and seed values. For each mesh node, the nearest seed point is identified using Euclidean distance, and the corresponding seed value is assigned to the node.

Parameters:

variable_vector (jax.numpy.ndarray) – One-dimensional control vector of length 3 * number_of_seeds. The first third contains x-coordinates of the seeds, the second third contains y-coordinates, and the final third contains the scalar values associated with each seed.

Returns:

One-dimensional array of controlled values evaluated at mesh nodes, with length equal to the number of mesh nodes.

Return type:

jax.numpy.ndarray

Finalize()[source]#

Finalize the control.

This method is called once at the end of a training or optimization process. Derived classes may override it to release resources or perform cleanup. The default base class does not implement any finalization logic.

Returns:

None

Initialize(reinitialize=False)[source]#

Initialize Voronoi seed configuration and control dimensions.

This method reads the number of Voronoi seeds and their associated values from control_settings and sets the number of control and controlled variables. Initialization is performed once unless reinitialize is set to True.

Parameters:

reinitialize (bool, optional) – If True, forces reinitialization even if already initialized. Default is False.

Returns:

None

Raises:

ValueError – If E_values is not provided as a list or tuple, or if its length is incompatible with number_of_seeds.

Voronoi-based control (3D)#

Authors: Kianoosh Taghikhani, kianoosh1989 Date: October, 2024 License: FOL/License.txt

class fol.controls.voronoi_control3D.VoronoiControl3D(control_name, control_settings, fe_mesh)[source]#

Bases: Control

Voronoi-based parametric control in three dimensions.

This control maps a vector of design variables to a nodal scalar field defined over a three-dimensional finite element mesh. The mapping is based on a Voronoi tessellation induced by a set of seed points in the three-dimensional space.

The control variables represent: - x-coordinates of Voronoi seed points, - y-coordinates of Voronoi seed points, - z-coordinates of Voronoi seed points, - one scalar value associated with each seed.

For each mesh node with coordinates (X_i, Y_i, Z_i), the controlled value is taken from the seed point that is closest to the node in Euclidean distance. This produces a piecewise-constant field over the mesh, with discontinuities along Voronoi cell boundaries.

The number of control variables is four times the number of seeds, and the number of controlled variables equals the number of mesh nodes.

Parameters:
  • control_name (str) – Name identifier for the control instance.

  • control_settings (dict) – Dictionary defining the Voronoi parameterization. Expected keys include "number_of_seeds" and "E_values". The entry "E_values" is validated during initialization but is not used directly in the control mapping.

  • fe_mesh (Mesh) – Finite element mesh providing nodal coordinates.

ComputeControlledVariables(variable_vector)[source]#

Compute the nodal field induced by the 3D Voronoi control.

The input control vector is interpreted as a concatenation of:

  • x-coordinates of the Voronoi seeds,

  • y-coordinates of the Voronoi seeds,

  • z-coordinates of the Voronoi seeds,

  • scalar values associated with each seed.

For each mesh node coordinate (X_i, Y_i, Z_i), the nearest seed point is identified using Euclidean distance, and the corresponding seed value is assigned to the node.

Parameters:

variable_vector (jax.numpy.ndarray) – One-dimensional control vector of length 4 * number_of_seeds.

Returns:

One-dimensional array of controlled values evaluated at mesh nodes, with length equal to the number of mesh nodes.

Return type:

jax.numpy.ndarray

Notes

This method does not explicitly validate the length of variable_vector and does not explicitly raise exceptions. If the input vector has an incompatible length, indexing or shape errors may occur during JAX tracing or execution.

Finalize()[source]#

Finalize the control.

This method is called once at the end of a training or optimization process. Derived classes may override it to release resources or perform cleanup. The default base class does not implement any finalization logic.

Returns:

None

Initialize(reinitialize=False)[source]#

Initialize Voronoi seed configuration and control dimensions.

This method reads the number of Voronoi seeds from control_settings and sets the number of control variables and controlled variables. Initialization is performed once unless reinitialize is set to True.

The number of control variables is defined as:

  • 4 * number_of_seeds (x-coordinates, y-coordinates, z-coordinates, and one scalar value per seed)

The number of controlled variables equals the number of mesh nodes.

Parameters:

reinitialize (bool, optional) – If True, forces reinitialization even if already initialized. Default is False.

Returns:

None

Raises:

ValueError – If control_settings["E_values"] is not a tuple or a list.