# Optimize

The optimization seam: parameterizations that build configs, objectives that score results, and the searches that drive them.

## femforge.optimize

Optimization seam: a `Parameterization` turns a point into a `SimulationConfig`, an `Objective` scores its `Result`, and `GridSearch` records each point in a `Study`.

Modules:

- **`max_current`** –

  Max-current search: a closed-form I² seed plus a bracketed regula-falsi search for the largest current whose steady temperature stays at or below the limit.
- **`objective`** –

  Objectives: a typed `Result` reduced to a scalar to optimize, converted to SI before its units are stripped.
- **`parameterization`** –

  The free variables: a point in parameter space -\> a concrete SimulationConfig, through the knobs a study declares.
- **`search`** –

  A naive grid search: walk the Cartesian product of the grid through the driver and record everything in a `Study`.
- **`study`** –

  The Study: a queryable log of (point, result, objective, run\_id) records across an optimization run.

Classes:

- **`Parameterization`** –

  Maps a point in parameter space -\> a concrete `SimulationConfig`.
- **`ParamSpec`** –

  The declared closed `[low, high]` bounds of one free variable — the schema entry `Parameterization.space` returns, not the sample set.
- **`Knob`** –

  Base: one free variable that maps a scalar onto a field of a `SimulationConfig`.
- **`GlobalMeshSize`** –

  Knob over `MeshConfig.global_mesh_size` — the domain-wide target element size (in metres; the pipeline is SI).
- **`RegionMeshSize`** –

  Knob over one tagged region's `EntityTag.mesh_size`, such as a finer air gap than the bulk.
- **`Objective`** –

  A result → scalar contract.
- **`NetForceMagnitude`** –

  Maximize the net force magnitude on the moving array (`|force|` in N).
- **`PhaseResistanceFromPower`** –

  The mean per-phase resistance (Ω) of a current-conduction run, from the Joule volume integral: R = phases·V²/P.
- **`Study`** –

  The queryable log of an optimization run: one `StudyRecord` per evaluated point.
- **`StudyRecord`** –

  One evaluated point: where in parameter space, the run it produced, the objective scalar, and the full typed result.
- **`GridSearch`** –

  Walk the full Cartesian product of `grid` (knob name -\> sweep values) through the driver, recording one `StudyRecord` per point.
- **`DriverLike`** –

  The slice of `run.Driver` a grid search needs: `evaluate`.

### Parameterization

Bases: `BaseModel`

Maps a point in parameter space -\> a concrete `SimulationConfig`.

Holds a fixed `base` config plus the `Knob`s that perturb it — the single place that encodes which knobs vary.

Config:

- `arbitrary_types_allowed`: `True`
- `use_attribute_docstrings`: `True`

Fields:

- `base` (`SimulationConfig`)
- `knobs` (`list[SerializeAsAny[Knob]]`)

#### base

```python
base: SimulationConfig
```

The fixed config the knobs perturb; everything not driven by a knob comes from here.

#### knobs

```python
knobs: list[SerializeAsAny[Knob]]
```

The free variables, each writing one named scalar onto the config; any `Knob` subclass, from any package.

#### to\_config

```python
to_config(point: dict[str, float]) -> SimulationConfig
```

Build the `SimulationConfig` for one parameter-space `point` (knob name -\> value), leaving the base untouched.

The point's keys must be exactly the knob names; a missing or unknown key raises.

#### space

```python
space() -> dict[str, ParamSpec]
```

The free variables keyed by name, each with its declared bounds — the schema a search walks (or a future optimizer samples).

### ParamSpec

Bases: `BaseModel`

The declared closed `[low, high]` bounds of one free variable — the schema entry `Parameterization.space` returns, not the sample set.

Config:

- `use_attribute_docstrings`: `True`

Fields:

- `low` (`float`)
- `high` (`float`)

#### low

```python
low: float
```

Inclusive lower bound of the free variable.

#### high

```python
high: float
```

Inclusive upper bound of the free variable.

### Knob

Bases: `BaseModel`

Base: one free variable that maps a scalar onto a field of a `SimulationConfig`.

Subclasses pin a `kind` discriminator and implement `apply`; never instantiated directly.

Config:

- `arbitrary_types_allowed`: `True`
- `use_attribute_docstrings`: `True`

Fields:

- `name` (`str`)
- `low` (`float`)
- `high` (`float`)

#### name

```python
name: str
```

Parameter-space key this knob reads from a point dict (unique within a Parameterization).

#### low

```python
low: float
```

Inclusive lower bound of the knob's value.

#### high

```python
high: float
```

Inclusive upper bound of the knob's value.

#### spec

```python
spec() -> ParamSpec
```

The declared range of this knob, for `Parameterization.space`.

#### apply

```python
apply(config: SimulationConfig, value: float) -> SimulationConfig
```

Return a copy of `config` with this knob set to `value`; implementations must not mutate `config` (the base config is shared across every grid point). The base raises.

### GlobalMeshSize

Bases: `Knob`

Knob over `MeshConfig.global_mesh_size` — the domain-wide target element size (in metres; the pipeline is SI).

Fields:

- `name` (`str`)
- `low` (`float`)
- `high` (`float`)
- `kind` (`Literal['global_mesh_size']`)

#### kind

```python
kind: Literal['global_mesh_size'] = 'global_mesh_size'
```

The discriminator a serialized parameterization reads this knob back by.

#### apply

```python
apply(config: SimulationConfig, value: float) -> SimulationConfig
```

A copy of `config` with `global_mesh_size` set to `value`.

### RegionMeshSize

Bases: `Knob`

Knob over one tagged region's `EntityTag.mesh_size`, such as a finer air gap than the bulk.

Targets the region by `tag` name and raises when the base config has no such region.

Fields:

- `name` (`str`)
- `low` (`float`)
- `high` (`float`)
- `kind` (`Literal['region_mesh_size']`)
- `tag` (`str`)

#### kind

```python
kind: Literal['region_mesh_size'] = 'region_mesh_size'
```

The discriminator a serialized parameterization reads this knob back by.

#### tag

```python
tag: str
```

Derived `EntityTag.name` (e.g. `"Phase0"`) of the region whose mesh\_size this knob sets.

#### apply

```python
apply(config: SimulationConfig, value: float) -> SimulationConfig
```

A copy of `config` with the `mesh_size` of the region named `tag` set to `value`.

### Objective

Bases: `Protocol`

A result → scalar contract.

### NetForceMagnitude

Maximize the net force magnitude on the moving array (`|force|` in N).

A solve that produced no force scores `-inf`, so it never wins a maximization.

### PhaseResistanceFromPower

```python
PhaseResistanceFromPower(*, drive_volts: float, phases: int = 3)
```

The mean per-phase resistance (Ω) of a current-conduction run, from the Joule volume integral: R = phases·V²/P.

A run without a positive Joule power column scores `nan`.

### Study

Bases: `BaseModel`

The queryable log of an optimization run: one `StudyRecord` per evaluated point.

`best` is the argmax/argmin over the objective; `to_dataframe` flattens to a units-stripped table for analysis and plotting.

Config:

- `arbitrary_types_allowed`: `True`
- `use_attribute_docstrings`: `True`

Fields:

- `records` (`list[StudyRecord]`)

#### records

```python
records: list[StudyRecord]
```

Every evaluated point, in evaluation order.

#### record

```python
record(*, point: dict[str, float], run_id: str, result: Result, objective: float) -> StudyRecord
```

Append and return a `StudyRecord` for one evaluated point.

Parameters:

- **`point`** (`dict[str, float]`) –

  The parameter-space coordinate, by knob name.
- **`run_id`** (`str`) –

  The run bundle's content-addressed id.
- **`result`** (`Result`) –

  The run's typed result.
- **`objective`** (`float`) –

  The run's objective scalar.

#### best

```python
best(*, maximize: bool = True) -> StudyRecord
```

The record with the extremal objective: argmax by default, argmin when `maximize=False`.

#### to\_dataframe

```python
to_dataframe() -> DataFrame
```

Flatten the records to a pandas DataFrame, the units-stripping analysis boundary.

One row per record: the knob columns, then `objective`, `run_id`, `status` and the result quantities as bare SI floats.

### StudyRecord

Bases: `BaseModel`

One evaluated point: where in parameter space, the run it produced, the objective scalar, and the full typed result.

Config:

- `arbitrary_types_allowed`: `True`
- `use_attribute_docstrings`: `True`

Fields:

- `point` (`dict[str, float]`)
- `run_id` (`str`)
- `objective` (`float`)
- `result` (`Result`)

#### point

```python
point: dict[str, float]
```

The parameter-space coordinate (knob name → value) that produced this run.

#### run\_id

```python
run_id: str
```

Content-addressed id of the run bundle (== run.cache\_key of the evaluated config).

#### objective

```python
objective: float
```

The objective scalar for this run (the quantity the search optimizes).

#### result

```python
result: Result
```

The full typed result, units intact; stripped to floats only at to\_dataframe.

### GridSearch

```python
GridSearch(*, parameterization: Parameterization, grid: dict[str, list[float]], objective: Objective)
```

Walk the full Cartesian product of `grid` (knob name -\> sweep values) through the driver, recording one `StudyRecord` per point.

Parameters:

- **`parameterization`** (`Parameterization`) –

  Turns each grid point into a config.
- **`grid`** (`dict[str, list[float]]`) –

  The values to sweep, by knob name.
- **`objective`** (`Objective`) –

  Scores each result.

Methods:

- **`run`** –

  Evaluate every grid point and return the populated `Study`.

#### run

```python
run(driver: DriverLike) -> Study
```

Evaluate every grid point and return the populated `Study`.

Each record keeps the `run_id` the driver stamped, recomputed with `run.cache_key` when a stand-in stamps none.

### DriverLike

Bases: `Protocol`

The slice of `run.Driver` a grid search needs: `evaluate`.

Methods:

- **`evaluate`** –

  Solve `config` and return its result.

#### evaluate

```python
evaluate(config: SimulationConfig) -> Result
```

Solve `config` and return its result.
