{
  "$defs": {
    "Axis": {
      "description": "A line through ``origin`` along ``direction``, in the authored model's frame.",
      "properties": {
        "origin": {
          "description": "`[mm]`: A point on the axis.",
          "properties": {
            "x": {
              "type": "number"
            },
            "y": {
              "type": "number"
            },
            "z": {
              "type": "number"
            }
          },
          "required": [
            "x",
            "y",
            "z"
          ],
          "title": "Origin",
          "type": "object"
        },
        "direction": {
          "description": "`[-]`: The axis direction; a scaled direction is the same axis.",
          "properties": {
            "x": {
              "type": "number"
            },
            "y": {
              "type": "number"
            },
            "z": {
              "type": "number"
            }
          },
          "required": [
            "x",
            "y",
            "z"
          ],
          "title": "Direction",
          "type": "object"
        }
      },
      "required": [
        "direction"
      ],
      "title": "Axis",
      "type": "object"
    },
    "Axisymmetric": {
      "description": "Solve the r\u2013z half-plane of a model symmetric about ``axis``: X = radial, Y = along the axis, Z = 0.",
      "properties": {
        "kind": {
          "const": "axisymmetric",
          "default": "axisymmetric",
          "description": "Discriminator that names this frame in a serialized config.",
          "title": "Kind",
          "type": "string"
        },
        "axis": {
          "$ref": "#/$defs/Axis",
          "default": {
            "origin": {
              "x": 0,
              "y": 0,
              "z": 0
            },
            "direction": {
              "x": 0.0,
              "y": 0.0,
              "z": 1.0
            }
          },
          "description": "The authored model's axis of symmetry."
        },
        "radial": {
          "anyOf": [
            {
              "description": "Unit direction {x, y, z}, normalized on load",
              "properties": {
                "x": {
                  "type": "number"
                },
                "y": {
                  "type": "number"
                },
                "z": {
                  "type": "number"
                }
              },
              "required": [
                "x",
                "y",
                "z"
              ],
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`[-]`: The direction from the axis toward the sectioned half-plane, stored as its unit part perpendicular to the\naxis; None picks the world axis least aligned with the symmetry axis.",
          "title": "Radial"
        }
      },
      "title": "Axisymmetric",
      "type": "object"
    },
    "CoilCurrentSolver": {
      "description": "Elmer's ``CoilSolver``: the divergence-conforming coil current distribution, the source stage of the ``COIL_MAGNETOSTATICS`` chain.\n\nIt acts only on [`CoilDrive`][femforge.physical.conditions.CoilDrive] bodies, because Elmer requires every body it covers to belong to a ``Component``.",
      "properties": {
        "steady_state_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Steady-state convergence tolerance.",
          "title": "Steady State Convergence Tolerance"
        },
        "nonlinear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Residual tolerance for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Convergence Tolerance"
        },
        "nonlinear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Iteration cap for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Max Iterations"
        },
        "nonlinear_system_newton_after_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Switch from Picard to Newton after this many outer iterations.",
          "title": "Nonlinear System Newton After Iterations"
        },
        "nonlinear_system_newton_after_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Switch from Picard to Newton once the residual drops below this.",
          "title": "Nonlinear System Newton After Tolerance"
        },
        "nonlinear_system_relaxation_factor": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Under/over-relaxation factor for the nonlinear update (1 = none).",
          "title": "Nonlinear System Relaxation Factor"
        },
        "nonlinear_system_convergence_measure": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Nonlinear residual measure (e.g. \"solution\"); None keeps Elmer's default.",
          "title": "Nonlinear System Convergence Measure"
        },
        "linear_system_solver": {
          "anyOf": [
            {
              "$ref": "#/$defs/LinearSolverType"
            },
            {
              "type": "null"
            }
          ],
          "default": "Direct",
          "description": "Iterative (Krylov) or Direct linear solve."
        },
        "linear_system_direct_method": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "umfpack",
          "description": "Factorization backend for a Direct solve (e.g. \"umfpack\"); None omits the keyword.",
          "title": "Linear System Direct Method"
        },
        "linear_system_iterative_method": {
          "anyOf": [
            {
              "$ref": "#/$defs/IterativeMethod"
            },
            {
              "type": "null"
            }
          ],
          "default": "BiCGStab",
          "description": "Krylov method when the solve is iterative."
        },
        "linear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 2000,
          "description": "Iteration cap for the linear solve.",
          "title": "Linear System Max Iterations"
        },
        "linear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-08,
          "description": "Residual tolerance for the linear solve.",
          "title": "Linear System Convergence Tolerance"
        },
        "linear_system_preconditioning": {
          "anyOf": [
            {
              "$ref": "#/$defs/Preconditioning"
            },
            {
              "type": "null"
            }
          ],
          "default": "ILU0",
          "description": "Preconditioner for the iterative solve."
        },
        "linear_system_residual_output": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Print the linear residual every N iterations; None omits it.",
          "title": "Linear System Residual Output"
        },
        "linear_system_abort_not_converged": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Abort the run if the linear solve doesn't converge; False lets a stalled gauge-non-unique AV solve proceed.",
          "title": "Linear System Abort Not Converged"
        },
        "bicgstabl_polynomial_degree": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Polynomial degree l for the BiCGStab(l) Krylov method.",
          "title": "Bicgstabl Polynomial Degree"
        },
        "extra_keywords": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "description": "Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into [`to_elmer`][] \u2014 any Elmer\nkeyword the typed fields don't model yet stays authorable without subclassing.",
          "title": "Extra Keywords",
          "type": "object"
        },
        "kind": {
          "const": "CoilCurrent",
          "default": "CoilCurrent",
          "description": "Discriminator that names this solver, doubling as its sif Solver label.",
          "title": "Kind",
          "type": "string"
        },
        "equation": {
          "default": "CoilSolver",
          "description": "Elmer equation/solver name.",
          "title": "Equation",
          "type": "string"
        },
        "procedure": {
          "default": "\"CoilSolver\" \"CoilSolver\"",
          "description": "Elmer Procedure: \"library\" \"function\".",
          "title": "Procedure",
          "type": "string"
        },
        "variable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Primary solver variable; None for solvers that declare none.",
          "title": "Variable"
        },
        "variable_dofs": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Degrees of freedom per node; None lets Elmer infer.",
          "title": "Variable Dofs"
        },
        "exec_solver": {
          "$ref": "#/$defs/ExecSolver",
          "default": "Before simulation",
          "description": "When Elmer runs this solver."
        },
        "stabilize": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Enable stabilization; None omits the keyword.",
          "title": "Stabilize"
        },
        "optimize_bandwidth": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": true,
          "description": "Reorder DOFs to reduce matrix bandwidth; None omits the keyword.",
          "title": "Optimize Bandwidth"
        },
        "coil_closed": {
          "default": false,
          "description": "False: an open coil whose ends are the ``Coil Start`` / ``Coil End`` electrode boundaries.",
          "title": "Coil Closed",
          "type": "boolean"
        },
        "normalize_coil_current": {
          "default": false,
          "description": "Must stay OFF for a massive coil: it rescales |J| to a UNIFORM magnitude, which on a varying cross-section\nauthors a non-conservative source that Jfix redistributes (silently reduced drive current in the winding).\n``Desired Coil Current`` scaling happens regardless, so the total current is still exact with this off.",
          "title": "Normalize Coil Current",
          "type": "boolean"
        },
        "calculate_elemental_fields": {
          "default": true,
          "description": "Export the DG ``CoilCurrent e`` field (what ``Use Elemental CoilCurrent`` reads); the nodal field stays too.",
          "title": "Calculate Elemental Fields",
          "type": "boolean"
        }
      },
      "title": "CoilCurrentSolver",
      "type": "object"
    },
    "CoilDrive": {
      "description": "A driven coil under ``COIL_MAGNETOSTATICS`` (body target): bodies sharing this condition become one massive CoilSolver ``Component`` normalized to ``current``.\n\nReverse the drive by swapping the terminal roles, not with a negative current.",
      "properties": {
        "physics": {
          "$ref": "#/$defs/Physics",
          "default": "coil_magnetostatics",
          "description": "The physics whose solve this condition feeds."
        },
        "target": {
          "$ref": "#/$defs/ConditionTarget",
          "default": "body",
          "description": "Whether the condition attaches to a body or a boundary."
        },
        "kind": {
          "const": "coil_drive",
          "default": "coil_drive",
          "description": "Discriminator that names this condition type in a serialized config.",
          "title": "Kind",
          "type": "string"
        },
        "current": {
          "description": "`I_coil` `[A]`: The total coil current CoilSolver normalizes this coil's solved distribution to.",
          "title": "Current",
          "type": "string",
          "x-unit-dimensionality": "[current]"
        }
      },
      "required": [
        "current"
      ],
      "title": "CoilDrive",
      "type": "object"
    },
    "CoilTerminal": {
      "description": "One end of an open coil's terminal pair, Elmer's ``Coil Start`` or ``Coil End`` marker (``COIL_MAGNETOSTATICS``, boundary target).\n\nThe electrode's end face must lie on the domain boundary (``GeometryConfig.terminate_electrodes``); positive coil current flows from start to end.",
      "properties": {
        "physics": {
          "$ref": "#/$defs/Physics",
          "default": "coil_magnetostatics",
          "description": "The physics whose solve this condition feeds."
        },
        "target": {
          "$ref": "#/$defs/ConditionTarget",
          "default": "boundary",
          "description": "Whether the condition attaches to a body or a boundary."
        },
        "kind": {
          "const": "coil_terminal",
          "default": "coil_terminal",
          "description": "Discriminator that names this condition type in a serialized config.",
          "title": "Kind",
          "type": "string"
        },
        "role": {
          "description": "Which end of the coil this electrode is; CoilSolver's normalized current flows start -> end.",
          "enum": [
            "start",
            "end"
          ],
          "title": "Role",
          "type": "string"
        }
      },
      "required": [
        "role"
      ],
      "title": "CoilTerminal",
      "type": "object"
    },
    "ConditionTarget": {
      "description": "Whether a condition attaches to a 3D body or a 2D boundary.",
      "enum": [
        "body",
        "boundary"
      ],
      "title": "ConditionTarget",
      "type": "string"
    },
    "Constants": {
      "description": "The Elmer ``Constants`` block: each constant is an optional field carrying its sif keyword; a physics sets only the constants it needs, and an unset one is omitted.",
      "properties": {
        "extra_keywords": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "description": "Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into [`to_elmer`][] \u2014 any Elmer\nkeyword the typed fields don't model yet stays authorable without subclassing.",
          "title": "Extra Keywords",
          "type": "object"
        },
        "permeability_of_vacuum": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`\u03bc\u2080` `[H/m]`: Needed by the magnetostatic solver.",
          "title": "Permeability Of Vacuum"
        },
        "permittivity_of_vacuum": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`\u03b5\u2080` `[F/m]`: Needed by the electrostatic solver.",
          "title": "Permittivity Of Vacuum"
        },
        "stefan_boltzmann": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`\u03c3_SB` `[W/(m\u00b2\u00b7K\u2074)]`: Needed for thermal radiation.",
          "title": "Stefan Boltzmann"
        }
      },
      "title": "Constants",
      "type": "object"
    },
    "Convection": {
      "description": "Convective (Newton-cooling) boundary condition (thermal, boundary target); ``external_only`` \u2014 a film BC on an interior interface would bypass the conduction path.",
      "properties": {
        "physics": {
          "$ref": "#/$defs/Physics",
          "default": "thermal",
          "description": "The physics whose solve this condition feeds."
        },
        "target": {
          "$ref": "#/$defs/ConditionTarget",
          "default": "boundary",
          "description": "Whether the condition attaches to a body or a boundary."
        },
        "kind": {
          "const": "convection",
          "default": "convection",
          "description": "Discriminator that names this condition type in a serialized config.",
          "title": "Kind",
          "type": "string"
        },
        "coefficient": {
          "description": "`h` `[W/(m\u00b2\u00b7K)]`: Convective heat-transfer coefficient.",
          "title": "Coefficient",
          "type": "string",
          "x-unit-dimensionality": "[power]/[length]**2/[temperature]"
        },
        "ext_temperature": {
          "description": "`T_amb` `[K]`: External (ambient) temperature the boundary exchanges with.",
          "title": "Ext Temperature",
          "type": "string",
          "x-unit-dimensionality": "[temperature]"
        }
      },
      "required": [
        "coefficient",
        "ext_temperature"
      ],
      "title": "Convection",
      "type": "object"
    },
    "CoordinateSystem": {
      "description": "Elmer's ``Coordinate System``.",
      "enum": [
        "Cartesian",
        "Cylindric",
        "Cylindric Symmetric",
        "Axi Symmetric",
        "Polar"
      ],
      "title": "CoordinateSystem",
      "type": "string"
    },
    "CurrentDensity": {
      "description": "Uniform signed azimuthal current density J = N\u00b7I/A over a winding window (axisymmetric magnetostatics, body target), the homogenized stranded-coil drive.\n\nRequires ``frame=Axisymmetric()``.",
      "properties": {
        "physics": {
          "$ref": "#/$defs/Physics",
          "default": "magnetostatics_2d",
          "description": "The physics whose solve this condition feeds."
        },
        "target": {
          "$ref": "#/$defs/ConditionTarget",
          "default": "body",
          "description": "Whether the condition attaches to a body or a boundary."
        },
        "kind": {
          "const": "current_density",
          "default": "current_density",
          "description": "Discriminator that names this condition type in a serialized config.",
          "title": "Kind",
          "type": "string"
        },
        "value": {
          "description": "`J` `[A/m\u00b2]`: Azimuthal current density (signed) imposed uniformly over the body.",
          "title": "Value",
          "type": "string",
          "x-unit-dimensionality": "[current]/[length]**2"
        }
      },
      "required": [
        "value"
      ],
      "title": "CurrentDensity",
      "type": "object"
    },
    "DomainConfig": {
      "description": "The materials the mesher matches to STEP parts, plus the per-region `EntityTag` overrides (conditions / mesh refinement).",
      "properties": {
        "materials": {
          "description": "The candidate materials; the mesher matches each STEP entity to one by `tag`.",
          "items": {
            "$ref": "#/$defs/MaterialProperties"
          },
          "title": "Materials",
          "type": "array"
        },
        "tags": {
          "description": "The per-region overrides, matched to mesh entities by name; each carries its `conditions` and optional `mesh_size`.",
          "items": {
            "$ref": "#/$defs/EntityTag"
          },
          "title": "Tags",
          "type": "array"
        }
      },
      "title": "DomainConfig",
      "type": "object"
    },
    "ElectricalProperties": {
      "description": "The electrical properties of a material.",
      "properties": {
        "conductivity": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [current]**2*[time]**3/[mass]/[length]**3",
              "type": "string",
              "x-unit-dimensionality": "[current]**2*[time]**3/[mass]/[length]**3"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`\u03c3` `[S/m]`: Electrical conductivity.",
          "title": "Conductivity"
        },
        "resistivity": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [mass]*[length]**3/[current]**2/[time]**3",
              "type": "string",
              "x-unit-dimensionality": "[mass]*[length]**3/[current]**2/[time]**3"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`\u03c1_e` `[\u03a9\u00b7m]`: Electrical resistivity.",
          "title": "Resistivity"
        },
        "permittivity": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [current]**2*[time]**4/[mass]/[length]**3",
              "type": "string",
              "x-unit-dimensionality": "[current]**2*[time]**4/[mass]/[length]**3"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`\u03b5` `[F/m]`: Absolute permittivity, emitted to Elmer as the relative \u03b5/\u03b5\u2080.",
          "title": "Permittivity"
        },
        "permeability": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [mass]*[length]/[current]**2/[time]**2",
              "type": "string",
              "x-unit-dimensionality": "[mass]*[length]/[current]**2/[time]**2"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`\u03bc` `[H/m]`: Absolute magnetic permeability.",
          "title": "Permeability"
        }
      },
      "title": "ElectricalProperties",
      "type": "object"
    },
    "ElectrostaticsSolver": {
      "description": "SCAFFOLD: electrostatics (StatElecSolver). No nonlinear iteration.",
      "properties": {
        "steady_state_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-05,
          "description": "Steady-state convergence tolerance.",
          "title": "Steady State Convergence Tolerance"
        },
        "linear_system_solver": {
          "anyOf": [
            {
              "$ref": "#/$defs/LinearSolverType"
            },
            {
              "type": "null"
            }
          ],
          "default": "Iterative",
          "description": "Iterative (Krylov) or Direct linear solve."
        },
        "linear_system_direct_method": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Factorization backend for a Direct solve (e.g. \"umfpack\"); None omits the keyword.",
          "title": "Linear System Direct Method"
        },
        "linear_system_iterative_method": {
          "anyOf": [
            {
              "$ref": "#/$defs/IterativeMethod"
            },
            {
              "type": "null"
            }
          ],
          "default": "BiCGStab",
          "description": "Krylov method when the solve is iterative."
        },
        "linear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 500,
          "description": "Iteration cap for the linear solve.",
          "title": "Linear System Max Iterations"
        },
        "linear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-10,
          "description": "Residual tolerance for the linear solve.",
          "title": "Linear System Convergence Tolerance"
        },
        "linear_system_preconditioning": {
          "anyOf": [
            {
              "$ref": "#/$defs/Preconditioning"
            },
            {
              "type": "null"
            }
          ],
          "default": "ILU0",
          "description": "Preconditioner for the iterative solve."
        },
        "linear_system_residual_output": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Print the linear residual every N iterations; None omits it.",
          "title": "Linear System Residual Output"
        },
        "linear_system_abort_not_converged": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Abort the run if the linear solve doesn't converge; False lets a stalled gauge-non-unique AV solve proceed.",
          "title": "Linear System Abort Not Converged"
        },
        "bicgstabl_polynomial_degree": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Polynomial degree l for the BiCGStab(l) Krylov method.",
          "title": "Bicgstabl Polynomial Degree"
        },
        "extra_keywords": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "description": "Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into [`to_elmer`][] \u2014 any Elmer\nkeyword the typed fields don't model yet stays authorable without subclassing.",
          "title": "Extra Keywords",
          "type": "object"
        },
        "kind": {
          "const": "Electrostatics",
          "default": "Electrostatics",
          "description": "Discriminator that names this solver, doubling as its sif Solver label.",
          "title": "Kind",
          "type": "string"
        },
        "equation": {
          "default": "Electrostatics",
          "description": "Elmer equation/solver name.",
          "title": "Equation",
          "type": "string"
        },
        "procedure": {
          "default": "\"StatElecSolve\" \"StatElecSolver\"",
          "description": "Elmer Procedure: \"library\" \"function\".",
          "title": "Procedure",
          "type": "string"
        },
        "variable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "Potential",
          "description": "Primary solver variable; None for solvers that declare none.",
          "title": "Variable"
        },
        "variable_dofs": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Degrees of freedom per node; None lets Elmer infer.",
          "title": "Variable Dofs"
        },
        "exec_solver": {
          "$ref": "#/$defs/ExecSolver",
          "default": "Always",
          "description": "When Elmer runs this solver."
        },
        "stabilize": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": true,
          "description": "Enable stabilization; None omits the keyword.",
          "title": "Stabilize"
        },
        "optimize_bandwidth": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Reorder DOFs to reduce matrix bandwidth; None omits the keyword.",
          "title": "Optimize Bandwidth"
        },
        "calculate_electric_field": {
          "default": true,
          "description": "Recover E from the potential.",
          "title": "Calculate Electric Field",
          "type": "boolean"
        }
      },
      "title": "ElectrostaticsSolver",
      "type": "object"
    },
    "EntityTag": {
      "description": "A per-region override matched to a mesh entity by its authored tags; carries the region's self-describing `conditions`.",
      "properties": {
        "selector": {
          "$ref": "#/$defs/TagDict",
          "description": "Compound-key selector: a mesh entity matches when its tag dict contains ALL of these key=value pairs (an empty selector matches every entity)."
        },
        "conditions": {
          "description": "Composable, self-describing conditions (body forces / boundary conditions) this region carries.",
          "items": {
            "discriminator": {
              "mapping": {
                "coil_drive": "#/$defs/CoilDrive",
                "coil_terminal": "#/$defs/CoilTerminal",
                "convection": "#/$defs/Convection",
                "current_density": "#/$defs/CurrentDensity",
                "fixed_potential": "#/$defs/FixedPotential",
                "fixed_temperature": "#/$defs/FixedTemperature",
                "force_component": "#/$defs/ForceComponent",
                "heat_flux": "#/$defs/HeatFlux",
                "heat_source": "#/$defs/HeatSource",
                "joule_heat": "#/$defs/JouleHeat",
                "magnetization": "#/$defs/Magnetization"
              },
              "propertyName": "kind"
            },
            "oneOf": [
              {
                "$ref": "#/$defs/Magnetization"
              },
              {
                "$ref": "#/$defs/CurrentDensity"
              },
              {
                "$ref": "#/$defs/FixedTemperature"
              },
              {
                "$ref": "#/$defs/HeatFlux"
              },
              {
                "$ref": "#/$defs/Convection"
              },
              {
                "$ref": "#/$defs/HeatSource"
              },
              {
                "$ref": "#/$defs/FixedPotential"
              },
              {
                "$ref": "#/$defs/JouleHeat"
              },
              {
                "$ref": "#/$defs/CoilDrive"
              },
              {
                "$ref": "#/$defs/CoilTerminal"
              },
              {
                "$ref": "#/$defs/ForceComponent"
              }
            ]
          },
          "title": "Conditions",
          "type": "array"
        },
        "mesh_size": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`h` `[m]`: Target mesh size for this region, such as a finer air gap; None inherits ``MeshConfig.global_mesh_size``.",
          "title": "Mesh Size"
        }
      },
      "title": "EntityTag",
      "type": "object"
    },
    "ExecSolver": {
      "description": "When Elmer executes a solver (the ``Exec Solver`` keyword).",
      "enum": [
        "Always",
        "Before simulation",
        "After simulation",
        "Before timestep",
        "After timestep",
        "Never"
      ],
      "title": "ExecSolver",
      "type": "string"
    },
    "FixedPotential": {
      "description": "Dirichlet electric-potential boundary condition (current conduction, boundary target), one electrode of a phase's terminal pair.",
      "properties": {
        "physics": {
          "$ref": "#/$defs/Physics",
          "default": "current_conduction",
          "description": "The physics whose solve this condition feeds."
        },
        "target": {
          "$ref": "#/$defs/ConditionTarget",
          "default": "boundary",
          "description": "Whether the condition attaches to a body or a boundary."
        },
        "kind": {
          "const": "fixed_potential",
          "default": "fixed_potential",
          "description": "Discriminator that names this condition type in a serialized config.",
          "title": "Kind",
          "type": "string"
        },
        "value": {
          "description": "`V` `[V]`: Electric potential imposed on the electrode boundary; the keyword is the solver variable's name (Elmer Dirichlet semantics), single-sourced via the enum.",
          "title": "Value",
          "type": "string",
          "x-unit-dimensionality": "[mass]*[length]**2/[current]/[time]**3"
        }
      },
      "required": [
        "value"
      ],
      "title": "FixedPotential",
      "type": "object"
    },
    "FixedTemperature": {
      "description": "Dirichlet temperature boundary condition (thermal, boundary target).",
      "properties": {
        "physics": {
          "$ref": "#/$defs/Physics",
          "default": "thermal",
          "description": "The physics whose solve this condition feeds."
        },
        "target": {
          "$ref": "#/$defs/ConditionTarget",
          "default": "boundary",
          "description": "Whether the condition attaches to a body or a boundary."
        },
        "kind": {
          "const": "fixed_temperature",
          "default": "fixed_temperature",
          "description": "Discriminator that names this condition type in a serialized config.",
          "title": "Kind",
          "type": "string"
        },
        "value": {
          "description": "`T` `[K]`: Fixed temperature imposed on the boundary.",
          "title": "Value",
          "type": "string",
          "x-unit-dimensionality": "[temperature]"
        }
      },
      "required": [
        "value"
      ],
      "title": "FixedTemperature",
      "type": "object"
    },
    "ForceComponent": {
      "description": "An Elmer ``Component`` lumping CalcFields' magnetic force and torque over the bodies this condition's tag matches (magnetic physics, body target).",
      "properties": {
        "physics": {
          "$ref": "#/$defs/Physics",
          "default": "magnetostatics",
          "description": "The physics whose solve this condition feeds."
        },
        "target": {
          "$ref": "#/$defs/ConditionTarget",
          "default": "body",
          "description": "Whether the condition attaches to a body or a boundary."
        },
        "kind": {
          "const": "force_component",
          "default": "force_component",
          "description": "Discriminator that names this condition type in a serialized config.",
          "title": "Kind",
          "type": "string"
        },
        "label": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "The Component's ``Name``; None uses the authoring tag's name.",
          "title": "Label"
        },
        "calculate_magnetic_force": {
          "default": true,
          "description": "Lump the nodal magnetic force over the master bodies.",
          "title": "Calculate Magnetic Force",
          "type": "boolean"
        },
        "calculate_magnetic_torque": {
          "default": false,
          "description": "Also lump the magnetic torque (requires ``torque_origin``/``torque_axis``).",
          "title": "Calculate Magnetic Torque",
          "type": "boolean"
        },
        "torque_origin": {
          "anyOf": [
            {
              "description": "3D vector {x, y, z}",
              "properties": {
                "x": {
                  "type": "number"
                },
                "y": {
                  "type": "number"
                },
                "z": {
                  "type": "number"
                }
              },
              "required": [
                "x",
                "y",
                "z"
              ],
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`r_0` `[m]`: Torque pivot point.",
          "title": "Torque Origin"
        },
        "torque_axis": {
          "anyOf": [
            {
              "description": "Unit direction {x, y, z}, normalized on load",
              "properties": {
                "x": {
                  "type": "number"
                },
                "y": {
                  "type": "number"
                },
                "z": {
                  "type": "number"
                }
              },
              "required": [
                "x",
                "y",
                "z"
              ],
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Torque axis direction.",
          "title": "Torque Axis"
        }
      },
      "title": "ForceComponent",
      "type": "object"
    },
    "GenericSolver": {
      "description": "Escape hatch: an arbitrary Elmer solver block for anything the typed hierarchy doesn't model yet \u2014 set\n``equation``/``procedure`` and author the rest through ``extra_keywords`` (plus the shared typed knobs).",
      "properties": {
        "steady_state_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Steady-state convergence tolerance.",
          "title": "Steady State Convergence Tolerance"
        },
        "nonlinear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Residual tolerance for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Convergence Tolerance"
        },
        "nonlinear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Iteration cap for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Max Iterations"
        },
        "nonlinear_system_newton_after_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Switch from Picard to Newton after this many outer iterations.",
          "title": "Nonlinear System Newton After Iterations"
        },
        "nonlinear_system_newton_after_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Switch from Picard to Newton once the residual drops below this.",
          "title": "Nonlinear System Newton After Tolerance"
        },
        "nonlinear_system_relaxation_factor": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Under/over-relaxation factor for the nonlinear update (1 = none).",
          "title": "Nonlinear System Relaxation Factor"
        },
        "nonlinear_system_convergence_measure": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Nonlinear residual measure (e.g. \"solution\"); None keeps Elmer's default.",
          "title": "Nonlinear System Convergence Measure"
        },
        "linear_system_solver": {
          "anyOf": [
            {
              "$ref": "#/$defs/LinearSolverType"
            },
            {
              "type": "null"
            }
          ],
          "default": "Iterative",
          "description": "Iterative (Krylov) or Direct linear solve."
        },
        "linear_system_direct_method": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Factorization backend for a Direct solve (e.g. \"umfpack\"); None omits the keyword.",
          "title": "Linear System Direct Method"
        },
        "linear_system_iterative_method": {
          "anyOf": [
            {
              "$ref": "#/$defs/IterativeMethod"
            },
            {
              "type": "null"
            }
          ],
          "default": "BiCGStab",
          "description": "Krylov method when the solve is iterative."
        },
        "linear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Iteration cap for the linear solve.",
          "title": "Linear System Max Iterations"
        },
        "linear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-08,
          "description": "Residual tolerance for the linear solve.",
          "title": "Linear System Convergence Tolerance"
        },
        "linear_system_preconditioning": {
          "anyOf": [
            {
              "$ref": "#/$defs/Preconditioning"
            },
            {
              "type": "null"
            }
          ],
          "default": "ILU0",
          "description": "Preconditioner for the iterative solve."
        },
        "linear_system_residual_output": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Print the linear residual every N iterations; None omits it.",
          "title": "Linear System Residual Output"
        },
        "linear_system_abort_not_converged": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Abort the run if the linear solve doesn't converge; False lets a stalled gauge-non-unique AV solve proceed.",
          "title": "Linear System Abort Not Converged"
        },
        "bicgstabl_polynomial_degree": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Polynomial degree l for the BiCGStab(l) Krylov method.",
          "title": "Bicgstabl Polynomial Degree"
        },
        "extra_keywords": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "description": "Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into [`to_elmer`][] \u2014 any Elmer\nkeyword the typed fields don't model yet stays authorable without subclassing.",
          "title": "Extra Keywords",
          "type": "object"
        },
        "kind": {
          "const": "Generic",
          "default": "Generic",
          "description": "Discriminator that names this solver, doubling as its sif Solver label.",
          "title": "Kind",
          "type": "string"
        },
        "equation": {
          "description": "Elmer equation/solver name.",
          "title": "Equation",
          "type": "string"
        },
        "procedure": {
          "description": "Elmer Procedure: \"library\" \"function\".",
          "title": "Procedure",
          "type": "string"
        },
        "variable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Primary solver variable; None for solvers that declare none.",
          "title": "Variable"
        },
        "variable_dofs": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Degrees of freedom per node; None lets Elmer infer.",
          "title": "Variable Dofs"
        },
        "exec_solver": {
          "$ref": "#/$defs/ExecSolver",
          "default": "Always",
          "description": "When Elmer runs this solver."
        },
        "stabilize": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Enable stabilization; None omits the keyword.",
          "title": "Stabilize"
        },
        "optimize_bandwidth": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Reorder DOFs to reduce matrix bandwidth; None omits the keyword.",
          "title": "Optimize Bandwidth"
        }
      },
      "required": [
        "equation",
        "procedure"
      ],
      "title": "GenericSolver",
      "type": "object"
    },
    "GeometryArea": {
      "additionalProperties": true,
      "description": "A parametric geometry the driver builds into a STEP in the authored frame; ``config.frame`` converts it for the solve.",
      "properties": {},
      "title": "GeometryArea",
      "type": "object"
    },
    "GmshOptions": {
      "description": "Typed gmsh meshing options; a knob left at None keeps gmsh's own default.",
      "properties": {
        "import_labels": {
          "default": true,
          "description": "Import STEP/OpenCASCADE entity labels (Geometry.OCCImportLabels); the mesher needs these to match parts to materials.",
          "title": "Import Labels",
          "type": "boolean"
        },
        "terminal_output": {
          "default": false,
          "description": "Print gmsh's progress to the terminal (General.Terminal); never changes the mesh, so it stays out of every identity.",
          "title": "Terminal Output",
          "type": "boolean"
        },
        "algorithm_2d": {
          "$ref": "#/$defs/MeshAlgorithm2D",
          "default": 6,
          "description": "2D meshing algorithm (Mesh.Algorithm); the default Frontal-Delaunay gives the all-triangle surface mesh HXT needs and meshes the bodies of a 2D model."
        },
        "algorithm_3d": {
          "$ref": "#/$defs/MeshAlgorithm3D",
          "default": 10,
          "description": "3D meshing algorithm (Mesh.Algorithm3D); the default HXT runs on ``num_threads`` and needs the all-triangle surface mesh ``recombine_all=False`` keeps."
        },
        "recombine_all": {
          "default": false,
          "description": "Recombine the simplex mesh into quads and hexes (Mesh.RecombineAll); keep it False, since WhitneyAVSolver needs tetrahedra and recombining makes 3D meshing fail.",
          "title": "Recombine All",
          "type": "boolean"
        },
        "mesh_size_min": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`h_min` `[m]`: Lower clamp on element size (Mesh.MeshSizeMin); None inherits gmsh's default.",
          "title": "Mesh Size Min"
        },
        "mesh_size_max": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`h_max` `[m]`: Upper clamp on element size (Mesh.MeshSizeMax); None inherits gmsh's default.",
          "title": "Mesh Size Max"
        },
        "optimize": {
          "default": true,
          "description": "Run mesh optimization after generation (Mesh.Optimize).",
          "title": "Optimize",
          "type": "boolean"
        },
        "smoothing": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Number of mesh smoothing steps (Mesh.Smoothing); None inherits gmsh's default.",
          "title": "Smoothing"
        },
        "num_threads": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "description": "Meshing threads (General.NumThreads): every physical core by default, None for gmsh's own default of one, and never part of an identity.",
          "title": "Num Threads"
        },
        "target_units": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "M",
          "description": "Length unit OpenCASCADE converts the imported STEP to (Geometry.OCCTargetUnit): ``\"M\"`` keeps the pipeline in metres, None keeps the STEP's own unit.",
          "title": "Target Units"
        }
      },
      "title": "GmshOptions",
      "type": "object"
    },
    "HeatFlux": {
      "description": "Prescribed heat flux boundary condition (thermal, boundary target).",
      "properties": {
        "physics": {
          "$ref": "#/$defs/Physics",
          "default": "thermal",
          "description": "The physics whose solve this condition feeds."
        },
        "target": {
          "$ref": "#/$defs/ConditionTarget",
          "default": "boundary",
          "description": "Whether the condition attaches to a body or a boundary."
        },
        "kind": {
          "const": "heat_flux",
          "default": "heat_flux",
          "description": "Discriminator that names this condition type in a serialized config.",
          "title": "Kind",
          "type": "string"
        },
        "value": {
          "description": "`q_s` `[W/m\u00b2]`: Heat flux through the boundary.",
          "title": "Value",
          "type": "string",
          "x-unit-dimensionality": "[power]/[length]**2"
        }
      },
      "required": [
        "value"
      ],
      "title": "HeatFlux",
      "type": "object"
    },
    "HeatSolver": {
      "description": "SCAFFOLD: steady heat conduction. Wire-ready; its boundary conditions land on the adjacency-derived surface groups via the condition-driven boundary loop.",
      "properties": {
        "steady_state_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-06,
          "description": "Steady-state convergence tolerance.",
          "title": "Steady State Convergence Tolerance"
        },
        "nonlinear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-06,
          "description": "Residual tolerance for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Convergence Tolerance"
        },
        "nonlinear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 50,
          "description": "Iteration cap for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Max Iterations"
        },
        "nonlinear_system_newton_after_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Switch from Picard to Newton after this many outer iterations.",
          "title": "Nonlinear System Newton After Iterations"
        },
        "nonlinear_system_newton_after_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Switch from Picard to Newton once the residual drops below this.",
          "title": "Nonlinear System Newton After Tolerance"
        },
        "nonlinear_system_relaxation_factor": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Under/over-relaxation factor for the nonlinear update (1 = none).",
          "title": "Nonlinear System Relaxation Factor"
        },
        "nonlinear_system_convergence_measure": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Nonlinear residual measure (e.g. \"solution\"); None keeps Elmer's default.",
          "title": "Nonlinear System Convergence Measure"
        },
        "linear_system_solver": {
          "anyOf": [
            {
              "$ref": "#/$defs/LinearSolverType"
            },
            {
              "type": "null"
            }
          ],
          "default": "Direct",
          "description": "Iterative (Krylov) or Direct linear solve."
        },
        "linear_system_direct_method": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "umfpack",
          "description": "Factorization backend for a Direct solve (e.g. \"umfpack\"); None omits the keyword.",
          "title": "Linear System Direct Method"
        },
        "linear_system_iterative_method": {
          "anyOf": [
            {
              "$ref": "#/$defs/IterativeMethod"
            },
            {
              "type": "null"
            }
          ],
          "default": "BiCGStab",
          "description": "Krylov method when the solve is iterative."
        },
        "linear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 1000,
          "description": "Iteration cap for the linear solve.",
          "title": "Linear System Max Iterations"
        },
        "linear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-08,
          "description": "Residual tolerance for the linear solve.",
          "title": "Linear System Convergence Tolerance"
        },
        "linear_system_preconditioning": {
          "anyOf": [
            {
              "$ref": "#/$defs/Preconditioning"
            },
            {
              "type": "null"
            }
          ],
          "default": "ILU",
          "description": "Preconditioner for the iterative solve."
        },
        "linear_system_residual_output": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Print the linear residual every N iterations; None omits it.",
          "title": "Linear System Residual Output"
        },
        "linear_system_abort_not_converged": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Abort the run if the linear solve doesn't converge; False lets a stalled gauge-non-unique AV solve proceed.",
          "title": "Linear System Abort Not Converged"
        },
        "bicgstabl_polynomial_degree": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Polynomial degree l for the BiCGStab(l) Krylov method.",
          "title": "Bicgstabl Polynomial Degree"
        },
        "extra_keywords": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "description": "Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into [`to_elmer`][] \u2014 any Elmer\nkeyword the typed fields don't model yet stays authorable without subclassing.",
          "title": "Extra Keywords",
          "type": "object"
        },
        "kind": {
          "const": "HeatSolver",
          "default": "HeatSolver",
          "description": "Discriminator that names this solver, doubling as its sif Solver label.",
          "title": "Kind",
          "type": "string"
        },
        "equation": {
          "default": "HeatSolver",
          "description": "Elmer equation/solver name.",
          "title": "Equation",
          "type": "string"
        },
        "procedure": {
          "default": "\"HeatSolve\" \"HeatSolver\"",
          "description": "Elmer Procedure: \"library\" \"function\".",
          "title": "Procedure",
          "type": "string"
        },
        "variable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "Temperature",
          "description": "Primary solver variable; None for solvers that declare none.",
          "title": "Variable"
        },
        "variable_dofs": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 1,
          "description": "Degrees of freedom per node; None lets Elmer infer.",
          "title": "Variable Dofs"
        },
        "exec_solver": {
          "$ref": "#/$defs/ExecSolver",
          "default": "Always",
          "description": "When Elmer runs this solver."
        },
        "stabilize": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": true,
          "description": "Enable stabilization; None omits the keyword.",
          "title": "Stabilize"
        },
        "optimize_bandwidth": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": true,
          "description": "Reorder DOFs to reduce matrix bandwidth; None omits the keyword.",
          "title": "Optimize Bandwidth"
        }
      },
      "title": "HeatSolver",
      "type": "object"
    },
    "HeatSource": {
      "description": "Volumetric heat source in W/m\u00b3 (thermal, body target).\n\nWith ``temperature_coefficient`` set, the source scales linearly with the local temperature, the \u03c3(T) Joule feedback of a prescribed-current winding.",
      "properties": {
        "physics": {
          "$ref": "#/$defs/Physics",
          "default": "thermal",
          "description": "The physics whose solve this condition feeds."
        },
        "target": {
          "$ref": "#/$defs/ConditionTarget",
          "default": "body",
          "description": "Whether the condition attaches to a body or a boundary."
        },
        "kind": {
          "const": "heat_source",
          "default": "heat_source",
          "description": "Discriminator that names this condition type in a serialized config.",
          "title": "Kind",
          "type": "string"
        },
        "power_density": {
          "description": "`q` `[W/m\u00b3]`: Heat generation density at ``reference_temperature`` when a coefficient is set, else the constant source.",
          "title": "Power Density",
          "type": "string",
          "x-unit-dimensionality": "[power]/[length]**3"
        },
        "temperature_coefficient": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`\u03b1` `[1/K]`: Linear coefficient in q(T) = power_density\u00b7(1 + \u03b1\u00b7(T \u2212 reference_temperature)); None emits the constant.",
          "title": "Temperature Coefficient"
        },
        "reference_temperature": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [temperature]",
              "type": "string",
              "x-unit-dimensionality": "[temperature]"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`T_ref` `[K]`: The temperature ``power_density`` holds at; required with ``temperature_coefficient``.",
          "title": "Reference Temperature"
        }
      },
      "required": [
        "power_density"
      ],
      "title": "HeatSource",
      "type": "object"
    },
    "IterativeMethod": {
      "description": "The Krylov method for an iterative linear solve (``Linear System Iterative Method``).",
      "enum": [
        "BiCGStab",
        "BiCGStabl",
        "CG",
        "CGS",
        "GMRES",
        "GCR",
        "TFQMR"
      ],
      "title": "IterativeMethod",
      "type": "string"
    },
    "JouleHeat": {
      "description": "Joule heat source body force (coupled current->thermal, body target): HeatSolve integrates StatCurrentSolve's loss density as the heat source.\n\nCarries no value \u2014 the magnitude is the solved current field itself.",
      "properties": {
        "physics": {
          "$ref": "#/$defs/Physics",
          "default": "joule_heating",
          "description": "The physics whose solve this condition feeds."
        },
        "target": {
          "$ref": "#/$defs/ConditionTarget",
          "default": "body",
          "description": "Whether the condition attaches to a body or a boundary."
        },
        "kind": {
          "const": "joule_heat",
          "default": "joule_heat",
          "description": "Discriminator that names this condition type in a serialized config.",
          "title": "Kind",
          "type": "string"
        }
      },
      "title": "JouleHeat",
      "type": "object"
    },
    "LinearSolverType": {
      "description": "The ``Linear System Solver`` strategy: an iterative Krylov method or a direct factorization.",
      "enum": [
        "Iterative",
        "Direct"
      ],
      "title": "LinearSolverType",
      "type": "string"
    },
    "MagneticProperties": {
      "description": "The magnetic properties of a material.",
      "properties": {
        "rel_permeability": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality ",
              "type": "string",
              "x-unit-dimensionality": ""
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`\u03bc_r` `[-]`: Relative permeability.",
          "title": "Rel Permeability"
        },
        "remanence": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [mass]/[current]/[time]**2",
              "type": "string",
              "x-unit-dimensionality": "[mass]/[current]/[time]**2"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`B_r` `[T]`: Remanent flux density.",
          "title": "Remanence"
        },
        "coercivity": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [current]/[length]",
              "type": "string",
              "x-unit-dimensionality": "[current]/[length]"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`H_c` `[A/m]`: Coercivity.",
          "title": "Coercivity"
        },
        "bh_curve": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [current]/[length]",
              "type": "string",
              "x-unit-dimensionality": "[current]/[length]"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`H(B)` `[A/m]`: Magnetization curve, a 1-D Calibration over ``flux_density`` emitted as Elmer's ``H-B Curve`` table.",
          "title": "Bh Curve"
        }
      },
      "title": "MagneticProperties",
      "type": "object"
    },
    "Magnetization": {
      "description": "Permanent-magnet body force (magnetostatics, body target).\n\nThe direction is per-region and lives here; the magnitude ``|M| = B\u1d63/\u03bc\u2080`` is a material property passed into ``to_elmer``.",
      "properties": {
        "physics": {
          "$ref": "#/$defs/Physics",
          "default": "magnetostatics",
          "description": "The physics whose solve this condition feeds."
        },
        "target": {
          "$ref": "#/$defs/ConditionTarget",
          "default": "body",
          "description": "Whether the condition attaches to a body or a boundary."
        },
        "kind": {
          "const": "magnetization",
          "default": "magnetization",
          "description": "Discriminator that names this condition type in a serialized config.",
          "title": "Kind",
          "type": "string"
        },
        "direction": {
          "anyOf": [
            {
              "description": "Unit direction {x, y, z}, normalized on load",
              "properties": {
                "x": {
                  "type": "number"
                },
                "y": {
                  "type": "number"
                },
                "z": {
                  "type": "number"
                }
              },
              "required": [
                "x",
                "y",
                "z"
              ],
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "description": "Magnetization direction in the authored model's frame, None for an unmagnetized body; magnitude comes from the material.",
          "title": "Direction"
        }
      },
      "required": [
        "direction"
      ],
      "title": "Magnetization",
      "type": "object"
    },
    "MagnetoDynamics2DSolver": {
      "description": "Axisymmetric magnetostatics (MagnetoDynamics2D): the scalar azimuthal potential A_phi under ``Coordinate System = Axi Symmetric``.\n\nThe mesh lies flat in the XY plane (Z = 0), with X the radial distance from the symmetry axis (X >= 0) and Y the position along it.",
      "properties": {
        "steady_state_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-06,
          "description": "Steady-state convergence tolerance.",
          "title": "Steady State Convergence Tolerance"
        },
        "nonlinear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-07,
          "description": "Residual tolerance for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Convergence Tolerance"
        },
        "nonlinear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 50,
          "description": "Iteration cap for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Max Iterations"
        },
        "nonlinear_system_newton_after_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Switch from Picard to Newton after this many outer iterations.",
          "title": "Nonlinear System Newton After Iterations"
        },
        "nonlinear_system_newton_after_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Switch from Picard to Newton once the residual drops below this.",
          "title": "Nonlinear System Newton After Tolerance"
        },
        "nonlinear_system_relaxation_factor": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1.0,
          "description": "Under/over-relaxation factor for the nonlinear update (1 = none).",
          "title": "Nonlinear System Relaxation Factor"
        },
        "nonlinear_system_convergence_measure": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "solution",
          "description": "Nonlinear residual measure (e.g. \"solution\"); None keeps Elmer's default.",
          "title": "Nonlinear System Convergence Measure"
        },
        "linear_system_solver": {
          "anyOf": [
            {
              "$ref": "#/$defs/LinearSolverType"
            },
            {
              "type": "null"
            }
          ],
          "default": "Direct",
          "description": "Iterative (Krylov) or Direct linear solve."
        },
        "linear_system_direct_method": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "umfpack",
          "description": "Factorization backend for a Direct solve (e.g. \"umfpack\"); None omits the keyword.",
          "title": "Linear System Direct Method"
        },
        "linear_system_iterative_method": {
          "anyOf": [
            {
              "$ref": "#/$defs/IterativeMethod"
            },
            {
              "type": "null"
            }
          ],
          "default": "BiCGStab",
          "description": "Krylov method when the solve is iterative."
        },
        "linear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Iteration cap for the linear solve.",
          "title": "Linear System Max Iterations"
        },
        "linear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-08,
          "description": "Residual tolerance for the linear solve.",
          "title": "Linear System Convergence Tolerance"
        },
        "linear_system_preconditioning": {
          "anyOf": [
            {
              "$ref": "#/$defs/Preconditioning"
            },
            {
              "type": "null"
            }
          ],
          "default": "ILU0",
          "description": "Preconditioner for the iterative solve."
        },
        "linear_system_residual_output": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Print the linear residual every N iterations; None omits it.",
          "title": "Linear System Residual Output"
        },
        "linear_system_abort_not_converged": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Abort the run if the linear solve doesn't converge; False lets a stalled gauge-non-unique AV solve proceed.",
          "title": "Linear System Abort Not Converged"
        },
        "bicgstabl_polynomial_degree": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Polynomial degree l for the BiCGStab(l) Krylov method.",
          "title": "Bicgstabl Polynomial Degree"
        },
        "extra_keywords": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "description": "Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into [`to_elmer`][] \u2014 any Elmer\nkeyword the typed fields don't model yet stays authorable without subclassing.",
          "title": "Extra Keywords",
          "type": "object"
        },
        "kind": {
          "const": "MagnetoDynamics2D",
          "default": "MagnetoDynamics2D",
          "description": "Discriminator that names this solver, doubling as its sif Solver label.",
          "title": "Kind",
          "type": "string"
        },
        "equation": {
          "default": "MgDyn2D",
          "description": "Elmer equation/solver name.",
          "title": "Equation",
          "type": "string"
        },
        "procedure": {
          "default": "\"MagnetoDynamics2D\" \"MagnetoDynamics2D\"",
          "description": "Elmer Procedure: \"library\" \"function\".",
          "title": "Procedure",
          "type": "string"
        },
        "variable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "Potential",
          "description": "Primary solver variable; None for solvers that declare none.",
          "title": "Variable"
        },
        "variable_dofs": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 1,
          "description": "Degrees of freedom per node; None lets Elmer infer.",
          "title": "Variable Dofs"
        },
        "exec_solver": {
          "$ref": "#/$defs/ExecSolver",
          "default": "Always",
          "description": "When Elmer runs this solver."
        },
        "stabilize": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Enable stabilization; None omits the keyword.",
          "title": "Stabilize"
        },
        "optimize_bandwidth": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": true,
          "description": "Reorder DOFs to reduce matrix bandwidth; None omits the keyword.",
          "title": "Optimize Bandwidth"
        }
      },
      "title": "MagnetoDynamics2DSolver",
      "type": "object"
    },
    "MagnetoDynamicsCalcFieldsSolver": {
      "description": "Post-processing: recover B, H, fluxes and nodal forces from the computed A. Inherits ``Linear System *`` because\nnodal-field recovery solves an (SPD, hence CG) mass-matrix system \u2014 without a linear solver Elmer aborts.",
      "properties": {
        "linear_system_solver": {
          "anyOf": [
            {
              "$ref": "#/$defs/LinearSolverType"
            },
            {
              "type": "null"
            }
          ],
          "default": "Iterative",
          "description": "Iterative (Krylov) or Direct linear solve."
        },
        "linear_system_direct_method": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Factorization backend for a Direct solve (e.g. \"umfpack\"); None omits the keyword.",
          "title": "Linear System Direct Method"
        },
        "linear_system_iterative_method": {
          "anyOf": [
            {
              "$ref": "#/$defs/IterativeMethod"
            },
            {
              "type": "null"
            }
          ],
          "default": "CG",
          "description": "Krylov method when the solve is iterative."
        },
        "linear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 500,
          "description": "Iteration cap for the linear solve.",
          "title": "Linear System Max Iterations"
        },
        "linear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-08,
          "description": "Residual tolerance for the linear solve.",
          "title": "Linear System Convergence Tolerance"
        },
        "linear_system_preconditioning": {
          "anyOf": [
            {
              "$ref": "#/$defs/Preconditioning"
            },
            {
              "type": "null"
            }
          ],
          "default": "ILU0",
          "description": "Preconditioner for the iterative solve."
        },
        "linear_system_residual_output": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Print the linear residual every N iterations; None omits it.",
          "title": "Linear System Residual Output"
        },
        "linear_system_abort_not_converged": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Abort the run if the linear solve doesn't converge; False lets a stalled gauge-non-unique AV solve proceed.",
          "title": "Linear System Abort Not Converged"
        },
        "bicgstabl_polynomial_degree": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Polynomial degree l for the BiCGStab(l) Krylov method.",
          "title": "Bicgstabl Polynomial Degree"
        },
        "extra_keywords": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "description": "Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into [`to_elmer`][] \u2014 any Elmer\nkeyword the typed fields don't model yet stays authorable without subclassing.",
          "title": "Extra Keywords",
          "type": "object"
        },
        "kind": {
          "const": "MagnetoDynamicsCalcFields",
          "default": "MagnetoDynamicsCalcFields",
          "description": "Discriminator that names this solver, doubling as its sif Solver label.",
          "title": "Kind",
          "type": "string"
        },
        "equation": {
          "default": "MgDynCalc",
          "description": "Elmer equation/solver name.",
          "title": "Equation",
          "type": "string"
        },
        "procedure": {
          "default": "\"MagnetoDynamics\" \"MagnetoDynamicsCalcFields\"",
          "description": "Elmer Procedure: \"library\" \"function\".",
          "title": "Procedure",
          "type": "string"
        },
        "variable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Primary solver variable; None for solvers that declare none.",
          "title": "Variable"
        },
        "variable_dofs": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Degrees of freedom per node; None lets Elmer infer.",
          "title": "Variable Dofs"
        },
        "exec_solver": {
          "$ref": "#/$defs/ExecSolver",
          "default": "Always",
          "description": "When Elmer runs this solver."
        },
        "stabilize": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Enable stabilization; None omits the keyword.",
          "title": "Stabilize"
        },
        "optimize_bandwidth": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": true,
          "description": "Reorder DOFs to reduce matrix bandwidth; None omits the keyword.",
          "title": "Optimize Bandwidth"
        },
        "potential_variable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "The vector-potential variable to post-process; None lets the solver pick up the (default-named) MgDyn variable.",
          "title": "Potential Variable"
        },
        "average_within_materials": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": true,
          "description": "Average recovered fields within each material so the B/H jump at a magnet surface is resolved cleanly.",
          "title": "Average Within Materials"
        },
        "calculate_magnetic_field_strength": {
          "default": true,
          "description": "Recover H.",
          "title": "Calculate Magnetic Field Strength",
          "type": "boolean"
        },
        "calculate_magnetic_flux_density": {
          "default": true,
          "description": "Recover B.",
          "title": "Calculate Magnetic Flux Density",
          "type": "boolean"
        },
        "calculate_nodal_forces": {
          "default": true,
          "description": "Recover nodal forces (drives the motor-force optimisation).",
          "title": "Calculate Nodal Forces",
          "type": "boolean"
        },
        "calculate_nodal_fields": {
          "default": false,
          "description": "Recover nodal field values.",
          "title": "Calculate Nodal Fields",
          "type": "boolean"
        },
        "calculate_joule_heating": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Recover the eddy/Joule loss field. Identically zero for a steady real-valued solve \u2014 set False there:\nthe zero-RHS projection it triggers when a Current Density body force is present segfaults CalcFields.",
          "title": "Calculate Joule Heating"
        },
        "calculate_electric_field": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Recover E = -dA/dt - grad V. Identically zero at steady state \u2014 set False for the chained coil solve,\nwhere its zero-RHS projection is what segfaults CalcFields after the B components.",
          "title": "Calculate Electric Field"
        },
        "calculate_magnetic_vector_potential": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Project the edge-element av onto a nodal A field; None keeps the solver default.",
          "title": "Calculate Magnetic Vector Potential"
        },
        "separate_magnetic_energy": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Export the magnetic field energy as SaveScalars-visible scalars (the ElmerCSC mgdyn_bh recipe) \u2014 the\nenergy-method inductance observable: L_eff = 2W/I\u00b2.",
          "title": "Separate Magnetic Energy"
        },
        "calculate_relative_permeability": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Recover the local relative permeability; the mgdyn_bh energy recipe enables it alongside the energy export.",
          "title": "Calculate Relative Permeability"
        },
        "calculate_elemental_fields": {
          "default": true,
          "description": "Recover elemental field values.",
          "title": "Calculate Elemental Fields",
          "type": "boolean"
        }
      },
      "title": "MagnetoDynamicsCalcFieldsSolver",
      "type": "object"
    },
    "MagnetoDynamicsSolver": {
      "description": "3D magnetostatics (WhitneyAVSolver), with each magnet's drive entering as ``Magnetization`` on its material rather than as a body force.\n\nLeave ``variable`` unset, so the far-field boundary condition can still name ``AV {e}``.",
      "properties": {
        "steady_state_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Steady-state convergence tolerance.",
          "title": "Steady State Convergence Tolerance"
        },
        "nonlinear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-10,
          "description": "Residual tolerance for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Convergence Tolerance"
        },
        "nonlinear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 50,
          "description": "Iteration cap for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Max Iterations"
        },
        "nonlinear_system_newton_after_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 3,
          "description": "Switch from Picard to Newton after this many outer iterations.",
          "title": "Nonlinear System Newton After Iterations"
        },
        "nonlinear_system_newton_after_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 0.001,
          "description": "Switch from Picard to Newton once the residual drops below this.",
          "title": "Nonlinear System Newton After Tolerance"
        },
        "nonlinear_system_relaxation_factor": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1.0,
          "description": "Under/over-relaxation factor for the nonlinear update (1 = none).",
          "title": "Nonlinear System Relaxation Factor"
        },
        "nonlinear_system_convergence_measure": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Nonlinear residual measure (e.g. \"solution\"); None keeps Elmer's default.",
          "title": "Nonlinear System Convergence Measure"
        },
        "linear_system_solver": {
          "anyOf": [
            {
              "$ref": "#/$defs/LinearSolverType"
            },
            {
              "type": "null"
            }
          ],
          "default": "Iterative",
          "description": "Iterative (Krylov) or Direct linear solve."
        },
        "linear_system_direct_method": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Factorization backend for a Direct solve (e.g. \"umfpack\"); None omits the keyword.",
          "title": "Linear System Direct Method"
        },
        "linear_system_iterative_method": {
          "anyOf": [
            {
              "$ref": "#/$defs/IterativeMethod"
            },
            {
              "type": "null"
            }
          ],
          "default": "BiCGStabl",
          "description": "Krylov method when the solve is iterative."
        },
        "linear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 500,
          "description": "Iteration cap for the linear solve.",
          "title": "Linear System Max Iterations"
        },
        "linear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-08,
          "description": "Residual tolerance for the linear solve.",
          "title": "Linear System Convergence Tolerance"
        },
        "linear_system_preconditioning": {
          "anyOf": [
            {
              "$ref": "#/$defs/Preconditioning"
            },
            {
              "type": "null"
            }
          ],
          "default": "None",
          "description": "Preconditioner for the iterative solve."
        },
        "linear_system_residual_output": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 10,
          "description": "Print the linear residual every N iterations; None omits it.",
          "title": "Linear System Residual Output"
        },
        "linear_system_abort_not_converged": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": false,
          "description": "Abort the run if the linear solve doesn't converge; False lets a stalled gauge-non-unique AV solve proceed.",
          "title": "Linear System Abort Not Converged"
        },
        "bicgstabl_polynomial_degree": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 4,
          "description": "Polynomial degree l for the BiCGStab(l) Krylov method.",
          "title": "Bicgstabl Polynomial Degree"
        },
        "extra_keywords": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "description": "Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into [`to_elmer`][] \u2014 any Elmer\nkeyword the typed fields don't model yet stays authorable without subclassing.",
          "title": "Extra Keywords",
          "type": "object"
        },
        "kind": {
          "const": "MagnetoDynamics",
          "default": "MagnetoDynamics",
          "description": "Discriminator that names this solver, doubling as its sif Solver label.",
          "title": "Kind",
          "type": "string"
        },
        "equation": {
          "default": "MgDyn",
          "description": "Elmer equation/solver name.",
          "title": "Equation",
          "type": "string"
        },
        "procedure": {
          "default": "\"MagnetoDynamics\" \"WhitneyAVSolver\"",
          "description": "Elmer Procedure: \"library\" \"function\".",
          "title": "Procedure",
          "type": "string"
        },
        "variable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Primary solver variable; None for solvers that declare none.",
          "title": "Variable"
        },
        "variable_dofs": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Degrees of freedom per node; None lets Elmer infer.",
          "title": "Variable Dofs"
        },
        "exec_solver": {
          "$ref": "#/$defs/ExecSolver",
          "default": "Always",
          "description": "When Elmer runs this solver."
        },
        "stabilize": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Enable stabilization; None omits the keyword.",
          "title": "Stabilize"
        },
        "optimize_bandwidth": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": true,
          "description": "Reorder DOFs to reduce matrix bandwidth; None omits the keyword.",
          "title": "Optimize Bandwidth"
        },
        "fix_input_current_density": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Project the source J onto a divergence-free field before the AV solve: the discrete J is not exactly solenoidal\nedge-element-wise, and an unfixed source makes the gauge-non-unique system inconsistent. None omits the keyword.",
          "title": "Fix Input Current Density"
        },
        "use_elemental_coilcurrent": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Read the source J from CoilSolver's *elemental* (DG) field instead of a nodal Body Force: nodal J is\nGalerkin-averaged across the conductor-air interface and silently dilutes the drive ~2x on thin traces.\nRequires a CoilSolver in the stack; None omits the keyword.",
          "title": "Use Elemental Coilcurrent"
        }
      },
      "title": "MagnetoDynamicsSolver",
      "type": "object"
    },
    "MaterialProperties": {
      "description": "A named material: its registry tag and its mechanical, thermal, magnetic and electrical properties.",
      "properties": {
        "name": {
          "default": "",
          "description": "The display name.",
          "title": "Name",
          "type": "string"
        },
        "tag": {
          "default": "",
          "description": "The registry key that a body's ``material`` tag names.",
          "title": "Tag",
          "type": "string"
        },
        "mechanical": {
          "$ref": "#/$defs/MechanicalProperties",
          "description": "The mechanical properties."
        },
        "thermal": {
          "$ref": "#/$defs/ThermalProperties",
          "description": "The thermal properties."
        },
        "magnetic": {
          "$ref": "#/$defs/MagneticProperties",
          "description": "The magnetic properties."
        },
        "electrical": {
          "$ref": "#/$defs/ElectricalProperties",
          "description": "The electrical properties."
        }
      },
      "title": "MaterialProperties",
      "type": "object"
    },
    "MechanicalProperties": {
      "description": "The mechanical properties of a material.",
      "properties": {
        "density": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [mass]/[length]**3",
              "type": "string",
              "x-unit-dimensionality": "[mass]/[length]**3"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`\u03c1` `[kg/m\u00b3]`: Mass density.",
          "title": "Density"
        },
        "elastic_modulus": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [pressure]",
              "type": "string",
              "x-unit-dimensionality": "[pressure]"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`E` `[Pa]`: Elastic (Young's) modulus.",
          "title": "Elastic Modulus"
        },
        "yield_strength": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [pressure]",
              "type": "string",
              "x-unit-dimensionality": "[pressure]"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`\u03c3_y` `[Pa]`: Yield strength.",
          "title": "Yield Strength"
        },
        "ultimate_tensile_strength": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [pressure]",
              "type": "string",
              "x-unit-dimensionality": "[pressure]"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`\u03c3_u` `[Pa]`: Ultimate tensile strength.",
          "title": "Ultimate Tensile Strength"
        }
      },
      "title": "MechanicalProperties",
      "type": "object"
    },
    "MeshAlgorithm2D": {
      "description": "A gmsh 2D meshing algorithm, valued as the integer ``Mesh.Algorithm`` takes.",
      "enum": [
        1,
        2,
        5,
        6
      ],
      "title": "MeshAlgorithm2D",
      "type": "integer"
    },
    "MeshAlgorithm3D": {
      "description": "A gmsh 3D meshing algorithm, valued as the integer ``Mesh.Algorithm3D`` takes.",
      "enum": [
        1,
        4,
        7,
        10
      ],
      "title": "MeshAlgorithm3D",
      "type": "integer"
    },
    "MeshConfig": {
      "additionalProperties": false,
      "description": "How the geometry is discretized for the gmsh backend: the STEP source, domain-wide element size, and typed gmsh knobs.",
      "properties": {
        "step": {
          "default": "data/geometry.step",
          "description": "Path to the STEP file the mesher imports; its build123d part names are parsed into materials and region tags (`MeshEntity`).",
          "title": "Step",
          "type": "string"
        },
        "global_mesh_size": {
          "default": 0.001,
          "description": "`h` `[m]`: Domain-wide target element size, which a region's [`EntityTag.mesh_size`][femforge.physical.domain.EntityTag.mesh_size] overrides.",
          "title": "Global Mesh Size",
          "type": "number"
        },
        "gmsh_options": {
          "$ref": "#/$defs/GmshOptions",
          "description": "Typed gmsh options applied before meshing."
        },
        "deterministic": {
          "default": false,
          "description": "Pin meshing to one thread, so HXT's multithreading cannot vary the result and the same STEP and sizes always yield the identical mesh; slower, and part of the run identity.",
          "title": "Deterministic",
          "type": "boolean"
        }
      },
      "title": "MeshConfig",
      "type": "object"
    },
    "OperatingPoint": {
      "description": "The point at which a material's property functions are evaluated when stripping to Elmer's bare SI floats.\n``Static`` properties ignore it; temperature-dependent properties consume it via [`as_mapping`][].",
      "properties": {
        "temperature": {
          "description": "`T` `[K]`: Evaluation temperature for material property functions.",
          "title": "Temperature",
          "type": "string",
          "x-unit-dimensionality": "[temperature]"
        }
      },
      "title": "OperatingPoint",
      "type": "object"
    },
    "Physics": {
      "description": "Which physics preset the sif writer wires; the string values double as the serialized spelling.",
      "enum": [
        "magnetostatics",
        "magnetostatics_2d",
        "thermal",
        "electrostatics",
        "current_conduction",
        "joule_heating",
        "coil_magnetostatics",
        "linear_elasticity"
      ],
      "title": "Physics",
      "type": "string"
    },
    "PhysicsConfig": {
      "description": "The fully populated, typed solver stack for one physics: ordered solvers plus simulation settings, activated constants and operating point.",
      "properties": {
        "solvers": {
          "description": "The ordered concrete solver instances Elmer runs for this physics.",
          "items": {
            "discriminator": {
              "mapping": {
                "CoilCurrent": "#/$defs/CoilCurrentSolver",
                "Electrostatics": "#/$defs/ElectrostaticsSolver",
                "Generic": "#/$defs/GenericSolver",
                "HeatSolver": "#/$defs/HeatSolver",
                "MagnetoDynamics": "#/$defs/MagnetoDynamicsSolver",
                "MagnetoDynamics2D": "#/$defs/MagnetoDynamics2DSolver",
                "MagnetoDynamicsCalcFields": "#/$defs/MagnetoDynamicsCalcFieldsSolver",
                "ResultOutputSolver": "#/$defs/ResultOutputSolver",
                "SaveScalars": "#/$defs/SaveScalarsSolver",
                "StatCurrent": "#/$defs/StatCurrentSolver",
                "StressSolver": "#/$defs/StressSolver"
              },
              "propertyName": "kind"
            },
            "oneOf": [
              {
                "$ref": "#/$defs/MagnetoDynamicsSolver"
              },
              {
                "$ref": "#/$defs/MagnetoDynamics2DSolver"
              },
              {
                "$ref": "#/$defs/MagnetoDynamicsCalcFieldsSolver"
              },
              {
                "$ref": "#/$defs/ResultOutputSolver"
              },
              {
                "$ref": "#/$defs/HeatSolver"
              },
              {
                "$ref": "#/$defs/StatCurrentSolver"
              },
              {
                "$ref": "#/$defs/CoilCurrentSolver"
              },
              {
                "$ref": "#/$defs/SaveScalarsSolver"
              },
              {
                "$ref": "#/$defs/ElectrostaticsSolver"
              },
              {
                "$ref": "#/$defs/StressSolver"
              },
              {
                "$ref": "#/$defs/GenericSolver"
              }
            ]
          },
          "title": "Solvers",
          "type": "array"
        },
        "simulation": {
          "$ref": "#/$defs/SimulationSettings",
          "description": "The Elmer Simulation block (run type, coordinate system, output files)."
        },
        "constants": {
          "$ref": "#/$defs/Constants",
          "description": "The physical constants this physics activates."
        },
        "operating_point": {
          "$ref": "#/$defs/OperatingPoint",
          "description": "Where material property functions are evaluated when stripping to SI."
        }
      },
      "required": [
        "solvers",
        "simulation",
        "constants",
        "operating_point"
      ],
      "title": "PhysicsConfig",
      "type": "object"
    },
    "PhysicsSelection": {
      "description": "Which physics the Elmer stage solves; ``SimulationConfig`` derives the solved stack from this selection and its frame.",
      "properties": {
        "selected": {
          "default": "magnetostatics",
          "description": "The physics as authored (magnetostatics / thermal / ...); the config's frame decides the form it solves as.",
          "enum": [
            "magnetostatics",
            "thermal",
            "electrostatics",
            "current_conduction",
            "joule_heating",
            "coil_magnetostatics",
            "linear_elasticity"
          ],
          "title": "Physics",
          "type": "string"
        },
        "overrides": {
          "anyOf": [
            {
              "$ref": "#/$defs/PhysicsConfig"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "The authored solver stack for this run (see ``SimulationConfig.customize_physics``); ``None`` solves the preset.\nPart of the config, so authored settings feed the run identity (``cache_key``) and the manifest."
        }
      },
      "title": "PhysicsSelection",
      "type": "object"
    },
    "Preconditioning": {
      "description": "The ``Linear System Preconditioning`` for an iterative solve.",
      "enum": [
        "None",
        "Diagonal",
        "ILU0",
        "ILU1",
        "ILU2",
        "ILU",
        "ILUT"
      ],
      "title": "Preconditioning",
      "type": "string"
    },
    "ResultOutputSolver": {
      "description": "Write VTU output for ParaView.",
      "properties": {
        "extra_keywords": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "description": "Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into [`to_elmer`][] \u2014 any Elmer\nkeyword the typed fields don't model yet stays authorable without subclassing.",
          "title": "Extra Keywords",
          "type": "object"
        },
        "kind": {
          "const": "ResultOutputSolver",
          "default": "ResultOutputSolver",
          "description": "Discriminator that names this solver, doubling as its sif Solver label.",
          "title": "Kind",
          "type": "string"
        },
        "equation": {
          "default": "ResultOutputSolver",
          "description": "Elmer equation/solver name.",
          "title": "Equation",
          "type": "string"
        },
        "procedure": {
          "default": "\"ResultOutputSolve\" \"ResultOutputSolver\"",
          "description": "Elmer Procedure: \"library\" \"function\".",
          "title": "Procedure",
          "type": "string"
        },
        "variable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Primary solver variable; None for solvers that declare none.",
          "title": "Variable"
        },
        "variable_dofs": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Degrees of freedom per node; None lets Elmer infer.",
          "title": "Variable Dofs"
        },
        "exec_solver": {
          "$ref": "#/$defs/ExecSolver",
          "default": "After timestep",
          "description": "When Elmer runs this solver."
        },
        "stabilize": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Enable stabilization; None omits the keyword.",
          "title": "Stabilize"
        },
        "optimize_bandwidth": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Reorder DOFs to reduce matrix bandwidth; None omits the keyword.",
          "title": "Optimize Bandwidth"
        },
        "vtu_format": {
          "default": true,
          "description": "Write VTU (ParaView) output.",
          "title": "Vtu Format",
          "type": "boolean"
        },
        "output_file_name": {
          "default": "File \"case\"",
          "description": "Stem of the written VTU (Elmer emits e.g. ``case_t0001.vtu``); pinned so the name never depends on Elmer defaults.",
          "title": "Output File Name",
          "type": "string"
        },
        "save_geometry_ids": {
          "default": true,
          "description": "Tag output cells with their gmsh geometry ids.",
          "title": "Save Geometry Ids",
          "type": "boolean"
        },
        "saved_scalar_fields": {
          "anyOf": [
            {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Scalar fields to save (each a full sif RHS, e.g. ``'String \"joule heating\"'``); None saves every active variable.",
          "title": "Saved Scalar Fields"
        },
        "saved_vector_fields": {
          "anyOf": [
            {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Vector fields to save; None saves every active variable.",
          "title": "Saved Vector Fields"
        },
        "discontinuous_bodies": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Average elemental fields body-wise onto a minimal discontinuous node set, so the VTU keeps cross-body discontinuities.",
          "title": "Discontinuous Bodies"
        }
      },
      "title": "ResultOutputSolver",
      "type": "object"
    },
    "RunMeta": {
      "description": "Searchable run metadata: a description and free key=value tags, recorded verbatim in the bundle manifest and\nNEVER part of the run identity \u2014 editing them re-labels a run without re-solving it.",
      "properties": {
        "description": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "One line on what this run is for (shown in the driver log, searchable via ``run.find_runs``).",
          "title": "Description"
        },
        "tags": {
          "$ref": "#/$defs/TagDict",
          "description": "Free key=value labels (the same tag-dict shape the geometry uses); ``find_runs`` matches by subset."
        }
      },
      "title": "RunMeta",
      "type": "object"
    },
    "SaveScalarsSolver": {
      "description": "SaveScalars (SaveData): export scalar reductions to ``scalars.dat`` and its ``.names`` sidecar.\n\nIts ``diffusive flux`` operator integrates each ``Save Scalars = True`` electrode's terminal current, the ``I`` in ``R = \u0394V / I``.",
      "properties": {
        "extra_keywords": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "description": "Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into [`to_elmer`][] \u2014 any Elmer\nkeyword the typed fields don't model yet stays authorable without subclassing.",
          "title": "Extra Keywords",
          "type": "object"
        },
        "kind": {
          "const": "SaveScalars",
          "default": "SaveScalars",
          "description": "Discriminator that names this solver, doubling as its sif Solver label.",
          "title": "Kind",
          "type": "string"
        },
        "equation": {
          "default": "SaveScalars",
          "description": "Elmer equation/solver name.",
          "title": "Equation",
          "type": "string"
        },
        "procedure": {
          "default": "\"SaveData\" \"SaveScalars\"",
          "description": "Elmer Procedure: \"library\" \"function\".",
          "title": "Procedure",
          "type": "string"
        },
        "variable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Primary solver variable; None for solvers that declare none.",
          "title": "Variable"
        },
        "variable_dofs": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Degrees of freedom per node; None lets Elmer infer.",
          "title": "Variable Dofs"
        },
        "exec_solver": {
          "$ref": "#/$defs/ExecSolver",
          "default": "After timestep",
          "description": "When Elmer runs this solver."
        },
        "stabilize": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Enable stabilization; None omits the keyword.",
          "title": "Stabilize"
        },
        "optimize_bandwidth": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Reorder DOFs to reduce matrix bandwidth; None omits the keyword.",
          "title": "Optimize Bandwidth"
        },
        "save_component_results": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Also export the scalars arising from Component sections.",
          "title": "Save Component Results"
        },
        "parallel_reduce": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Reduce a partitioned run's output to one ``scalars.dat`` instead of per-rank ``.dat.<rank>`` files.",
          "title": "Parallel Reduce"
        },
        "filename": {
          "default": "\"scalars.dat\"",
          "description": "The .dat the scalars land in (the run parser reads it, or its per-rank ``.dat.<rank>`` siblings, via the ``.names`` sidecar).",
          "title": "Filename",
          "type": "string"
        },
        "variable_1": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "Potential",
          "description": "The variable the operator reduces.",
          "title": "Variable 1"
        },
        "operator_1": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "diffusive flux",
          "description": "The reduction: boundary integral of the conjugate flux of ``variable_1``.",
          "title": "Operator 1"
        },
        "coefficient_1": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "Electric Conductivity",
          "description": "The material coefficient weighting the flux (\u03c3 \u2202\u03c6/\u2202n integrates to a current).",
          "title": "Coefficient 1"
        },
        "variable_2": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "Joule Heating",
          "description": "Second reduction: the Joule loss field (requires ``Calculate Joule Heating``).",
          "title": "Variable 2"
        },
        "operator_2": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "int",
          "description": "Volume integral: total dissipated power P (W), the flux-independent cross-check R = \u0394V\u00b2/P.",
          "title": "Operator 2"
        },
        "variable_3": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Third reduction; the coupled joule-heating stack sets ``Temperature`` here.",
          "title": "Variable 3"
        },
        "operator_3": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Reduction for ``variable_3``; the coupled stack uses ``max`` (peak temperature).",
          "title": "Operator 3"
        }
      },
      "title": "SaveScalarsSolver",
      "type": "object"
    },
    "SimulationSettings": {
      "description": "The Elmer ``Simulation`` block. Defaults are a 3D Cartesian steady-state run, used for magnetostatics and steady thermal.",
      "properties": {
        "extra_keywords": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "description": "Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into [`to_elmer`][] \u2014 any Elmer\nkeyword the typed fields don't model yet stays authorable without subclassing.",
          "title": "Extra Keywords",
          "type": "object"
        },
        "max_output_level": {
          "default": 5,
          "description": "Verbosity of ElmerSolver's console output (0-quiet \u2026 higher-noisier).",
          "title": "Max Output Level",
          "type": "integer"
        },
        "coordinate_system": {
          "$ref": "#/$defs/CoordinateSystem",
          "default": "Cartesian",
          "description": "The simulation coordinate system."
        },
        "coordinate_mapping": {
          "default": "1 2 3",
          "description": "Axis permutation for the coordinate system.",
          "title": "Coordinate Mapping",
          "type": "string"
        },
        "simulation_type": {
          "$ref": "#/$defs/SimulationType",
          "default": "Steady state",
          "description": "Steady-state, transient, or scanning run."
        },
        "steady_state_max_iterations": {
          "default": 1,
          "description": "Max steady-state (coupled-system) iterations.",
          "title": "Steady State Max Iterations",
          "type": "integer"
        },
        "output_intervals": {
          "default": 1,
          "description": "Write results every N steps.",
          "title": "Output Intervals",
          "type": "integer"
        },
        "timestepping_method": {
          "$ref": "#/$defs/TimesteppingMethod",
          "default": "BDF",
          "description": "Time integration scheme."
        },
        "bdf_order": {
          "default": 1,
          "description": "Order of the BDF timestepping method.",
          "title": "Bdf Order",
          "type": "integer"
        },
        "solver_input_file": {
          "default": "case.sif",
          "description": "Name of the generated .sif.",
          "title": "Solver Input File",
          "type": "string"
        },
        "post_file": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "ParaView/VTU post-processing output file; None (the default) leaves VTU output to the ResultOutputSolver \u2014\nsetting both trips Elmer's AddVtuOutputSolverHack and its log spam.",
          "title": "Post File"
        },
        "output_file": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "ElmerSolver restart/result file; None (the default) skips it \u2014 nothing downstream reads it and it grows to\nmulti-GB on large solves. Set a name only when a restart is wanted.",
          "title": "Output File"
        }
      },
      "title": "SimulationSettings",
      "type": "object"
    },
    "SimulationType": {
      "description": "Elmer's ``Simulation Type``.",
      "enum": [
        "Steady state",
        "Transient",
        "Scanning"
      ],
      "title": "SimulationType",
      "type": "string"
    },
    "Solid": {
      "description": "Solve the authored 3D model as-is.",
      "properties": {
        "kind": {
          "const": "solid",
          "default": "solid",
          "description": "Discriminator that names this frame in a serialized config.",
          "title": "Kind",
          "type": "string"
        }
      },
      "title": "Solid",
      "type": "object"
    },
    "StatCurrentSolver": {
      "description": "Static current conduction (Elmer's StatCurrentSolve): solves ``Potential`` from \u2207\u00b7(\u03c3\u2207\u03c6) = 0, excited by per-phase\n[`FixedPotential`][femforge.physical.conditions.FixedPotential] terminal pairs. The nonlinear block is inert while \u03c3 is Static.",
      "properties": {
        "steady_state_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-06,
          "description": "Steady-state convergence tolerance.",
          "title": "Steady State Convergence Tolerance"
        },
        "nonlinear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-08,
          "description": "Residual tolerance for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Convergence Tolerance"
        },
        "nonlinear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 20,
          "description": "Iteration cap for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Max Iterations"
        },
        "nonlinear_system_newton_after_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Switch from Picard to Newton after this many outer iterations.",
          "title": "Nonlinear System Newton After Iterations"
        },
        "nonlinear_system_newton_after_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Switch from Picard to Newton once the residual drops below this.",
          "title": "Nonlinear System Newton After Tolerance"
        },
        "nonlinear_system_relaxation_factor": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Under/over-relaxation factor for the nonlinear update (1 = none).",
          "title": "Nonlinear System Relaxation Factor"
        },
        "nonlinear_system_convergence_measure": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Nonlinear residual measure (e.g. \"solution\"); None keeps Elmer's default.",
          "title": "Nonlinear System Convergence Measure"
        },
        "linear_system_solver": {
          "anyOf": [
            {
              "$ref": "#/$defs/LinearSolverType"
            },
            {
              "type": "null"
            }
          ],
          "default": "Direct",
          "description": "Iterative (Krylov) or Direct linear solve."
        },
        "linear_system_direct_method": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "umfpack",
          "description": "Factorization backend for a Direct solve (e.g. \"umfpack\"); None omits the keyword.",
          "title": "Linear System Direct Method"
        },
        "linear_system_iterative_method": {
          "anyOf": [
            {
              "$ref": "#/$defs/IterativeMethod"
            },
            {
              "type": "null"
            }
          ],
          "default": "CG",
          "description": "Krylov method when the solve is iterative."
        },
        "linear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 5000,
          "description": "Iteration cap for the linear solve.",
          "title": "Linear System Max Iterations"
        },
        "linear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-06,
          "description": "Residual tolerance for the linear solve.",
          "title": "Linear System Convergence Tolerance"
        },
        "linear_system_preconditioning": {
          "anyOf": [
            {
              "$ref": "#/$defs/Preconditioning"
            },
            {
              "type": "null"
            }
          ],
          "default": "ILU0",
          "description": "Preconditioner for the iterative solve."
        },
        "linear_system_residual_output": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Print the linear residual every N iterations; None omits it.",
          "title": "Linear System Residual Output"
        },
        "linear_system_abort_not_converged": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Abort the run if the linear solve doesn't converge; False lets a stalled gauge-non-unique AV solve proceed.",
          "title": "Linear System Abort Not Converged"
        },
        "bicgstabl_polynomial_degree": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Polynomial degree l for the BiCGStab(l) Krylov method.",
          "title": "Bicgstabl Polynomial Degree"
        },
        "extra_keywords": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "description": "Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into [`to_elmer`][] \u2014 any Elmer\nkeyword the typed fields don't model yet stays authorable without subclassing.",
          "title": "Extra Keywords",
          "type": "object"
        },
        "kind": {
          "const": "StatCurrent",
          "default": "StatCurrent",
          "description": "Discriminator that names this solver, doubling as its sif Solver label.",
          "title": "Kind",
          "type": "string"
        },
        "equation": {
          "default": "Stat Current Solver",
          "description": "Elmer equation/solver name.",
          "title": "Equation",
          "type": "string"
        },
        "procedure": {
          "default": "\"StatCurrentSolve\" \"StatCurrentSolver\"",
          "description": "Elmer Procedure: \"library\" \"function\".",
          "title": "Procedure",
          "type": "string"
        },
        "variable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "Potential",
          "description": "Primary solver variable; None for solvers that declare none.",
          "title": "Variable"
        },
        "variable_dofs": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 1,
          "description": "Degrees of freedom per node; None lets Elmer infer.",
          "title": "Variable Dofs"
        },
        "exec_solver": {
          "$ref": "#/$defs/ExecSolver",
          "default": "Always",
          "description": "When Elmer runs this solver."
        },
        "stabilize": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": true,
          "description": "Enable stabilization; None omits the keyword.",
          "title": "Stabilize"
        },
        "optimize_bandwidth": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": true,
          "description": "Reorder DOFs to reduce matrix bandwidth; None omits the keyword.",
          "title": "Optimize Bandwidth"
        },
        "calculate_volume_current": {
          "default": true,
          "description": "Recover the volume current density J = -\u03c3\u2207\u03c6.",
          "title": "Calculate Volume Current",
          "type": "boolean"
        },
        "calculate_joule_heating": {
          "default": true,
          "description": "Recover the Joule loss density \u03c3|\u2207\u03c6|\u00b2 (the heat-solve coupling source).",
          "title": "Calculate Joule Heating",
          "type": "boolean"
        }
      },
      "title": "StatCurrentSolver",
      "type": "object"
    },
    "StressSolver": {
      "description": "SCAFFOLD: linear elasticity (Elmer's StressSolve). Consumes ``Youngs Modulus`` and ``Poisson Ratio`` material\nkeywords; the latter is not yet stored on MechanicalProperties.",
      "properties": {
        "steady_state_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-06,
          "description": "Steady-state convergence tolerance.",
          "title": "Steady State Convergence Tolerance"
        },
        "nonlinear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-07,
          "description": "Residual tolerance for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Convergence Tolerance"
        },
        "nonlinear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 1,
          "description": "Iteration cap for the nonlinear (outer) iteration.",
          "title": "Nonlinear System Max Iterations"
        },
        "nonlinear_system_newton_after_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Switch from Picard to Newton after this many outer iterations.",
          "title": "Nonlinear System Newton After Iterations"
        },
        "nonlinear_system_newton_after_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Switch from Picard to Newton once the residual drops below this.",
          "title": "Nonlinear System Newton After Tolerance"
        },
        "nonlinear_system_relaxation_factor": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Under/over-relaxation factor for the nonlinear update (1 = none).",
          "title": "Nonlinear System Relaxation Factor"
        },
        "nonlinear_system_convergence_measure": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Nonlinear residual measure (e.g. \"solution\"); None keeps Elmer's default.",
          "title": "Nonlinear System Convergence Measure"
        },
        "linear_system_solver": {
          "anyOf": [
            {
              "$ref": "#/$defs/LinearSolverType"
            },
            {
              "type": "null"
            }
          ],
          "default": "Iterative",
          "description": "Iterative (Krylov) or Direct linear solve."
        },
        "linear_system_direct_method": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Factorization backend for a Direct solve (e.g. \"umfpack\"); None omits the keyword.",
          "title": "Linear System Direct Method"
        },
        "linear_system_iterative_method": {
          "anyOf": [
            {
              "$ref": "#/$defs/IterativeMethod"
            },
            {
              "type": "null"
            }
          ],
          "default": "BiCGStab",
          "description": "Krylov method when the solve is iterative."
        },
        "linear_system_max_iterations": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 5000,
          "description": "Iteration cap for the linear solve.",
          "title": "Linear System Max Iterations"
        },
        "linear_system_convergence_tolerance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": 1e-08,
          "description": "Residual tolerance for the linear solve.",
          "title": "Linear System Convergence Tolerance"
        },
        "linear_system_preconditioning": {
          "anyOf": [
            {
              "$ref": "#/$defs/Preconditioning"
            },
            {
              "type": "null"
            }
          ],
          "default": "ILU0",
          "description": "Preconditioner for the iterative solve."
        },
        "linear_system_residual_output": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Print the linear residual every N iterations; None omits it.",
          "title": "Linear System Residual Output"
        },
        "linear_system_abort_not_converged": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Abort the run if the linear solve doesn't converge; False lets a stalled gauge-non-unique AV solve proceed.",
          "title": "Linear System Abort Not Converged"
        },
        "bicgstabl_polynomial_degree": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Polynomial degree l for the BiCGStab(l) Krylov method.",
          "title": "Bicgstabl Polynomial Degree"
        },
        "extra_keywords": {
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "number"
              },
              {
                "type": "boolean"
              }
            ]
          },
          "description": "Escape hatch: verbatim sif keyword/value pairs merged (last, so they win) into [`to_elmer`][] \u2014 any Elmer\nkeyword the typed fields don't model yet stays authorable without subclassing.",
          "title": "Extra Keywords",
          "type": "object"
        },
        "kind": {
          "const": "StressSolver",
          "default": "StressSolver",
          "description": "Discriminator that names this solver, doubling as its sif Solver label.",
          "title": "Kind",
          "type": "string"
        },
        "equation": {
          "default": "Linear elasticity",
          "description": "Elmer equation/solver name.",
          "title": "Equation",
          "type": "string"
        },
        "procedure": {
          "default": "\"StressSolve\" \"StressSolver\"",
          "description": "Elmer Procedure: \"library\" \"function\".",
          "title": "Procedure",
          "type": "string"
        },
        "variable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": "Displacement",
          "description": "Primary solver variable; None for solvers that declare none.",
          "title": "Variable"
        },
        "variable_dofs": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": 3,
          "description": "Degrees of freedom per node; None lets Elmer infer.",
          "title": "Variable Dofs"
        },
        "exec_solver": {
          "$ref": "#/$defs/ExecSolver",
          "default": "Always",
          "description": "When Elmer runs this solver."
        },
        "stabilize": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Enable stabilization; None omits the keyword.",
          "title": "Stabilize"
        },
        "optimize_bandwidth": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "default": true,
          "description": "Reorder DOFs to reduce matrix bandwidth; None omits the keyword.",
          "title": "Optimize Bandwidth"
        },
        "calculate_stresses": {
          "default": true,
          "description": "Recover the stress tensor from the displacement.",
          "title": "Calculate Stresses",
          "type": "boolean"
        }
      },
      "title": "StressSolver",
      "type": "object"
    },
    "TagDict": {
      "additionalProperties": {
        "type": "string"
      },
      "type": "object"
    },
    "ThermalProperties": {
      "description": "The thermal properties of a material.",
      "properties": {
        "conductivity": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [power]/[length]/[temperature]",
              "type": "string",
              "x-unit-dimensionality": "[power]/[length]/[temperature]"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`k` `[W/(m\u00b7K)]`: Thermal conductivity.",
          "title": "Conductivity"
        },
        "specific_heat_capacity": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [energy]/[mass]/[temperature]",
              "type": "string",
              "x-unit-dimensionality": "[energy]/[mass]/[temperature]"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`c_p` `[J/(kg\u00b7K)]`: Specific heat capacity.",
          "title": "Specific Heat Capacity"
        },
        "convective_heat_transfer_coefficient": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [power]/[length]**2/[temperature]",
              "type": "string",
              "x-unit-dimensionality": "[power]/[length]**2/[temperature]"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`h` `[W/(m\u00b2\u00b7K)]`: Convective heat transfer coefficient.",
          "title": "Convective Heat Transfer Coefficient"
        },
        "glass_transition_temperature": {
          "anyOf": [
            {
              "description": "pint quantity with dimensionality [temperature]",
              "type": "string",
              "x-unit-dimensionality": "[temperature]"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "`T_g` `[K]`: Glass transition temperature.",
          "title": "Glass Transition Temperature"
        }
      },
      "title": "ThermalProperties",
      "type": "object"
    },
    "TimesteppingMethod": {
      "description": "Elmer's ``Timestepping Method`` (paired with ``BDF Order`` for BDF).",
      "enum": [
        "BDF",
        "Newmark",
        "Runge-Kutta"
      ],
      "title": "TimesteppingMethod",
      "type": "string"
    }
  },
  "description": "The single config spanning the whole pipeline, one area model per concern; ``solved_physics`` / ``resolved_stack`` give what the run solves under ``frame``.",
  "properties": {
    "geometry": {
      "anyOf": [
        {
          "$ref": "#/$defs/GeometryArea"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional parametric geometry: when set, the driver calls its ``build_step`` into the run directory before\nmeshing and repoints ``mesh.step`` at it \u2014 the STEP is derived output, and the run identity comes from these\nparameters rather than an authored file."
    },
    "frame": {
      "description": "How the authored model maps onto the solve: as-is in 3D, or its axisymmetric r\u2013z half-plane.",
      "discriminator": {
        "mapping": {
          "axisymmetric": "#/$defs/Axisymmetric",
          "solid": "#/$defs/Solid"
        },
        "propertyName": "kind"
      },
      "oneOf": [
        {
          "$ref": "#/$defs/Solid"
        },
        {
          "$ref": "#/$defs/Axisymmetric"
        }
      ],
      "title": "Frame"
    },
    "mesh": {
      "$ref": "#/$defs/MeshConfig",
      "description": "The gmsh mesh settings: STEP source, global element size, gmsh options."
    },
    "domain": {
      "$ref": "#/$defs/DomainConfig",
      "description": "Materials + per-region tags."
    },
    "physics": {
      "$ref": "#/$defs/PhysicsSelection",
      "description": "Which physics the Elmer stage solves."
    },
    "meta": {
      "$ref": "#/$defs/RunMeta",
      "description": "Searchable description + tags; excluded from ``cache_key``, so labeling never re-identifies a run."
    }
  },
  "title": "SimulationConfig",
  "type": "object"
}
