> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ionworks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# データフィッティング概要

> iws.DataFit を使って、実験データへのフィッティングによりバッテリーモデルのパラメータを推定する方法を説明します

`iws.DataFit` はパラメータフィッティングを記述します。どの実験と比較するか、どのパラメータを自由にするか、どう探索するかを指定し、パイプラインの 1 要素として送信します。理論(コスト関数、識別可能性、マルチスタート)は [データフィッティング (英語ガイド)](/guide/data-fitting/overview) を参照してください。

## 最小構成のフィット

```python theme={null}
import pybamm
import ionworks_schema as iws
from ionworks import Ionworks

# 既知パラメータ(フィットしない全項目)
known = iws.direct_entries.DirectEntry(
    parameters={"Ambient temperature [K]": 298.15},
)

# 目的関数: 電流駆動 SPMe シミュレーションと測定電圧を比較
obj_1C = iws.objectives.CurrentDriven(
    data_input="file:examples/data/chen_synthetic_1C/time_series.csv",
    options={"model": pybamm.lithium_ion.SPMe()},
)

# 自由パラメータ
parameters = {
    "Negative particle diffusivity [m2.s-1]": iws.Parameter(
        "Negative particle diffusivity [m2.s-1]",
        initial_value=2e-14,
        bounds=(1e-14, 1e-13),
    ),
    "Positive particle diffusivity [m2.s-1]": iws.Parameter(
        "Positive particle diffusivity [m2.s-1]",
        initial_value=2e-15,
        bounds=(1e-15, 1e-14),
    ),
}

fit = iws.DataFit(
    objectives={"test_1C": obj_1C},
    parameters=parameters,
    cost=iws.costs.SSE(),
    optimizer=iws.optimizers.DifferentialEvolution(),
)

pipeline = iws.Pipeline({"known": known, "fit": fit})

client = Ionworks()
submission = client.pipeline.create(pipeline)
client.pipeline.wait_for_completion(submission.id)
result = client.pipeline.result(submission.id)
print(result.element_results["fit"])
```

<Note>
  `DataFit` 内の設定ミス(誤ったパラメータ名、不正な目的関数など)は `UserConfigurationError` として表面化します。ジョブ分類器はこれを Studio 上の **Configuration error** にマッピングするため、ソルバー失敗と簡単に区別できます。
</Note>

## 複数の目的関数

複数の目的関数を渡せば、複数の実験(異なる C レートや温度での放電など)に同時にフィットできます。

```python theme={null}
import pybamm

fit = iws.DataFit(
    objectives={
        "1C": iws.objectives.CurrentDriven(
            data_input="file:.../1C.csv",
            options={"model": pybamm.lithium_ion.SPMe()},
        ),
        "0.5C": iws.objectives.CurrentDriven(
            data_input="file:.../0.5C.csv",
            options={"model": pybamm.lithium_ion.SPMe()},
        ),
    },
    parameters=parameters,
)
```

各目的関数は単一の結合コストに寄与します。

## オプティマイザ

`iws.optimizers` は `DataFit` で利用可能なオプティマイザを提供します。問題に合うものを選んでください。

| スキーマ                                              | 用途                                                                             |
| ------------------------------------------------- | ------------------------------------------------------------------------------ |
| `iws.optimizers.ScipyMinimize(method="L-BFGS-B")` | 滑らかな問題、高速な局所最適化                                                                |
| `iws.optimizers.ScipyLeastSquares()`              | 残差ベースの最小二乗、事前分布と相性が良い。モデルが提供する場合は解析的なパラメータ Jacobian を使用します。                    |
| `iws.optimizers.ScipyLsqLinear()`                 | 境界付き**線形**最小二乗(単発の BVLS/TRF 解)。内側残差がパラメータについて線形な `Nested` フィットの内側ソルバーとして使用します。 |
| `iws.optimizers.DifferentialEvolution()`          | 大域探索、勾配不要                                                                      |
| `iws.optimizers.CMAES()`                          | 大域探索、多数の局所最小、デフォルトが堅牢                                                          |
| `iws.optimizers.PSO()`                            | 大域探索、並列化可能な集団探索                                                                |
| `iws.optimizers.BayesianOptimization()`           | 高コストな評価、パラメータ約 10 個以下、評価予算が小さい場合                                               |
| `iws.optimizers.TuRBO()`                          | 並列バッチで実行される高コストな評価; 高次元の問題                                                     |
| `iws.optimizers.SOBER()`                          | 求積スタイルの再結合を使用した広い並列バッチ                                                         |

コスト関数の選択肢は [目的関数](/ja/pipelines/data-fitting/objective-functions) を参照してください。

<Note>
  サロゲートオプティマイザ（`BayesianOptimization`、`TuRBO`、`SOBER`）はオプションの `surrogate` インストールエクストラが必要で、`torch`、`botorch`、`gpytorch` が追加されます。

  ```bash theme={null}
  pip install "ionworkspipeline[surrogate]"
  ```

  これらは遅延インポートされるため、集団ベースまたは SciPy のオプティマイザのみを使用するインストールでは、この依存関係のコストは発生しません。
</Note>

### 高コストな並列問題向けの TuRBO

各評価が高コストで、利用可能なワーカーがある場合、`TuRBO` は 1 ラウンドごとに候補のバッチを提案し、現在の最良点の周囲に信頼領域を適応させます。ワーカー数は実行エンジンが所有するようになったため（下記の注記を参照）、最初のラウンドで利用可能なワーカーをすべて活用できるよう、ウォームアップ（`n_initial`）を `DataFit.run(execution=ExecutionConfig(...))` に渡すキャパシティに合わせてください。

```python theme={null}
import ionworks_schema as iws

fit = iws.DataFit(
    objectives=objectives,
    parameters=parameters,
    optimizer=iws.optimizers.TuRBO(
        max_iterations=12,
        population_size=64,
        algorithm_options={"noise_floor": "low", "n_initial": 64},
    ),
)
```

<Note>
  `DataFit` は `parallel`、`num_workers`、`max_batch_size` を受け付けなくなりました（また `AskTellOptimizer` は `async_mode` を受け付けません）。並列性は実行エンジンが所有し、実行時に `DataFit.run(execution=ExecutionConfig(...))` で構成します。削除されたフィールドを含む保存済みコンフィグはパース時に自動的に移行されるため、既存の保存済みフィットに対する対応は不要です。
</Note>

サロゲートオプティマイザで有用な `algorithm_options` のキーには、`n_initial`（ウォームアップサンプル数）、`noise_floor`（`"low"`、`"standard"`、または `(lo, hi)` の区間）、TuRBO 用の信頼領域制御（`tr_length_init`、`tr_length_min`、`tr_length_max`、`tr_success_tolerance`、`tr_failure_tolerance`、`n_candidates`）があります。

### 厳密なオプション検証

`algorithm_options` は選択したオプティマイザに対して検証されます。未知のキー（タイポを含む）はサイレントに無視されるのではなく、投入時に拒否されるため、誤設定されたフィットがデフォルト動作のまま実行されることはなく、早期に失敗します。

```python theme={null}
# 検証エラーになります: "noise_flor" は TuRBO の認識されるオプションではありません。
iws.optimizers.TuRBO(algorithm_options={"noise_flor": "low"})

# AskTellOptimizer は CMAES()、PSO()、XNES() などの背後にある低レベルのクラスです。
# 上記の名前付きオプティマイザは、`method` を設定するだけの薄いラッパーです。
# 検証エラーになります: CMAES のフィットに BO のオプションが渡されています。
iws.optimizers.AskTellOptimizer(
    method="CMAES",
    algorithm_options=iws.optimizers.BayesianOptimizationOptions(n_initial=32),
)
```

この検証は、生の辞書を渡しても型付きラッパー（`CMAESOptions`、`PSOOptions`、`DEOptions`、`XNESOptions`（`XNES` オプティマイザ用。`iws.optimizers.XNES()` / `AskTellOptimizer(method="XNES")` で利用可能）、`BayesianOptimizationOptions`、`SOBEROptions`、`TuRBOOptions`）を渡しても同じように適用されます。エディタの自動補完と各オプションのインラインドキュメントが利用できるため、型付きラッパーの使用を推奨します。唯一の例外は `CMAESOptions` で、こちらは pycma 自体のオプション体系へのパススルーのままです。

#### ネイティブオプティマイザは SciPy 形式のキーワード引数を受け付けません

ネイティブな ask/tell オプティマイザ（`CMAES`、`DifferentialEvolution`、`PSO`、`XNES`、`BayesianOptimization`、`TuRBO`、`SOBER`、および基盤となる `AskTellOptimizer`）は、コンストラクタの未知のトップレベルキーワード引数を拒否します。`maxiter`、`popsize`、`seed`、`tol` といった SciPy 形式のキーは**受け付けられません**。以前はこれらは何の効果もありませんでしたが、現在はコンストラクタで直ちに検証エラーになるため、設定ミスのあるフィットは黙って見過ごされず即座に表面化します:

```python theme={null}
# 検証エラーを発生: 未知のキー（maxiter、popsize、tol）ごとに "Extra inputs are not permitted"。
iws.optimizers.DifferentialEvolution(maxiter=10, popsize=5, tol=1e-6)

# 正しい使い方: ドキュメント化された ask/tell のパラメータを使います（tol -> population_convergence_tol）。
iws.optimizers.DifferentialEvolution(
    max_iterations=10,
    population_size=5,
    population_convergence_tol=1e-6,
)

# アルゴリズム固有の設定は `algorithm_options` に渡します。
iws.optimizers.CMAES(algorithm_options={"seed": 42})
```

SciPy 形式のキーは引き続き SciPy パススルーのオプティマイザ（`ScipyMinimize`、`ScipyLeastSquares`、`ScipyDifferentialEvolution`）に対して使用します。これらは内部の SciPy 呼び出しにそのまま転送されます:

```python theme={null}
# OK: ScipyDifferentialEvolution は maxiter/popsize/seed/tol を scipy.optimize に転送します。
iws.optimizers.ScipyDifferentialEvolution(maxiter=10, popsize=5, seed=0)
```

要点としては、反復回数・個体数・許容誤差の上限は名前付きの ask/tell 引数（`max_iterations`、`population_size`、`population_convergence_tol`）に、アルゴリズム内部の設定は `algorithm_options` に、SciPy のキーワードは `Scipy*` オプティマイザに、というように使い分けてください。

### 目的関数 (objective) の厳密な検証

`DataFit.objectives`（および `Validation.objectives`）は、各エントリを目的関数の `type` をキーとする判別共用体 (discriminated union) に対して検証します。設定ミスは送信時に明確な `ValidationError` として拒否され、黙って無視されたり、後続の不明瞭なランタイムクラッシュとして現れたりすることはありません。

目的関数の **インスタンス**（例: `iws.objectives.CurrentDriven(...)`）はこれまで通り動作します。位置引数・キーワード引数のどちらのコンストラクタも維持されています。厳密検証のルールは生の設定 **辞書** を渡したときに適用され、これは JSON からロードした設定や `to_config()` で生成した設定でよく使われます:

```python theme={null}
# OK — 具体的な type が指定され、すべてのキーが認識される。
fit = iws.DataFit(
    objectives={
        "1C": {
            "type": "CurrentDriven",
            "data": "file:.../1C.csv",
            "options": {"model": {"type": "SPMe"}},
        },
    },
    parameters=parameters,
)

# こちらも OK — 旧来の `objective` エイリアスやトップレベルの `model` ショートハンドは、
# 検証前に `type` と `options.model` に正規化されます。
fit = iws.DataFit(
    objectives={
        "1C": {
            "objective": "CurrentDriven",
            "model": {"type": "SPMe"},
            "data": "file:.../1C.csv",
        },
    },
    parameters=parameters,
)
```

以下のケースは送信前に拒否されるようになりました:

| 問題              | 例                                                            | 拒否される理由                                                        |
| --------------- | ------------------------------------------------------------ | -------------------------------------------------------------- |
| 未知の objective 型 | `{"type": "NotAnObjective"}`                                 | type が共用体のメンバーではない。                                            |
| 判別キーの欠落         | `{"electrode": "positive", "data": "x.csv"}`                 | ディスパッチに使う `type`(または旧来の `objective`) がない。                      |
| 未知の内部キー         | `{"type": "OCPHalfCell", "definitely_not_a_field": 1}`       | スキーマは `extra="forbid"` を使用しており、タイポも早期に検出される。                   |
| 非具体型            | 具体的な目的関数名の代わりに汎用/基底名を指定                                      | 具体的な目的関数型（例: `OCPHalfCell`）のみが検証を通過する。                         |
| 判別キーの競合         | `{"type": "OCPHalfCell", "objective": "CurrentDriven", ...}` | `Conflicting objective discriminators` を発生 — どちらかのキーを修正してください。 |
| 辞書でもインスタンスでもない値 | `{"bad": "RMSE"}` / `{"bad": 123}`                           | objective の値は設定辞書または objective インスタンスである必要がある。                 |

<Note>
  生の設定辞書では、データのキーは `data_input` ではなく `data` です。Python コンストラクタは `data_input` キーワード引数として公開しますが、`to_config()` はこれを `data` にシリアライズします。そのため、手書きの辞書や JSON 設定では `data` を使用してください。辞書で `data_input` を渡すと、未知のキーとして拒否されるようになりました。
</Note>

`DesignObjective` の設定は `DataFit` のランタイムパスでは受け付けられません。これらは独立した design-optimization パイプラインで実行されます。`DesignObjective` 辞書を `DataFit.from_schema` に渡すと、後段でクラッシュする代わりに `UserConfigurationError` が発生し、design-optimization パイプラインを案内します。

## マルチスタート

複数の局所最小を持つ問題では、異なる初期点から複数回最適化を実行します。

```python theme={null}
fit = iws.DataFit(
    objectives=objectives,
    parameters=parameters,
    multistarts=20,
)
```

パイプラインが初期推測(デフォルトはラテン超方格法)を生成し、並列に実行し、コスト順に全結果を返します。

### 初期推測サンプラーの選択

デフォルトのマルチスタートはラテン超方格(Latin Hypercube)サンプリングを使い、パラメータ境界全体に初期推測を均等に分散させます。別のサンプリング方式に変えたい場合は、`initial_guess_sampler` でサンプラーを指定します。たとえばベースライン比較として一様サンプリングを使う場合:

```python theme={null}
fit = iws.DataFit(
    objectives=objectives,
    parameters=parameters,
    multistarts=20,
    initial_guess_sampler=iws.distribution_samplers.Uniform(),
)
```

利用可能なサンプラー:

| サンプラー                                        | 用途                                                  |
| -------------------------------------------- | --------------------------------------------------- |
| `iws.distribution_samplers.LatinHypercube()` | デフォルト。独立サンプリングよりパラメータ空間を均等に覆う層化サンプリング。ほとんどのフィットで推奨。 |
| `iws.distribution_samplers.Uniform()`        | 境界内で独立に一様分布から抽出。ベースラインや IID サンプルが必要な場合に有用。          |

サンプラーは送信時に識別ユニオン(discriminated union)で検証されます。未知のサンプラー `type` や認識されないキーを渡すと、ランの途中でなく送信時点で即座に `ValidationError` が送出されます。

## ネスト型(変数射影)フィット

`iws.optimizers.Nested` は二段構成のオプティマイザです。**外側**オプティマイザは選んだパラメータ部分集合を探索し、外側の各試行点ごとに**内側**オプティマイザが残りのパラメータについて最適化まで実行されます。これは変数射影(variable projection)の定式化で、外側は集約された目的関数 $g(x_\text{outer}) = \min_{x_\text{inner}} f(x_\text{outer}, x_\text{inner})$ を見ることになり、内側は条件付きで容易にフィットできるパラメータを吸収します。

`Nested` を使うのは以下のような場合です:

* あるパラメータ部分集合がモデルに**線形**(またはほぼ線形)に入り、境界付き最小二乗の内側ソルブで閉形式的に解けて、残りが非線形である場合。
* 完全な同時探索が悪条件で遅いが、縮約された外側問題は素直に振る舞う場合。
* 大域的な外側探索(例: CMA-ES や `Nelder-Mead`)と、各点における高速な局所内側改良を組み合わせたい場合。

```python theme={null}
import ionworks_schema as iws

fit = iws.DataFit(
    objectives=objectives,
    parameters=parameters,
    optimizer=iws.optimizers.Nested(
        parameters=["Negative particle diffusivity [m2.s-1]"],
        optimizer=iws.optimizers.ScipyMinimize(method="Nelder-Mead"),
        inner=iws.optimizers.ScipyLeastSquares(),
    ),
)
```

`parameters` は、このレベルの外側オプティマイザが制御するフィットパラメータ名を並べます。`DataFit` の残りすべての自由パラメータは `inner` に委譲されます。`inner` はさらに深いネストのために、それ自体が `Nested` になっていても構いません。

<Note>
  集約目的関数は、内側最適解が一意でない箇所で非平滑になり得ます。そのため外側スロットには導関数フリーまたは有限差分のオプティマイザ(`Nelder-Mead`、`CMAES`、`DifferentialEvolution`)が推奨されます。サンプラーは構築時に拒否されます — 両スロットともオプティマイザである必要があります。
</Note>

### `ScipyLsqLinear` による境界付き線形内側ソルブ

内側パラメータが残差に**線形**に入る場合(例: 境界付き係数と基底関数の線形結合)には、`Nested` の内側ソルバーに `iws.optimizers.ScipyLsqLinear` を組み合わせます。Gauss-Newton で反復するのではなく、`scipy.optimize.lsq_linear` を一度呼ぶだけで境界付き最適解に到達し、連続する外側評価をまたいでアクティブ集合をウォームスタートするので、集約目的関数は平滑に保たれます:

```python theme={null}
optimizer=iws.optimizers.Nested(
    parameters=["k_nonlinear"],
    optimizer=iws.optimizers.CMAES(),
    inner=iws.optimizers.ScipyLsqLinear(
        method="bvls",       # または "trf"
        warm_start=True,      # 前回のアクティブ集合を再利用(デフォルト)
    ),
)
```

`ScipyLsqLinear` は残差が本当に内側パラメータについて線形なときにのみ使ってください。内側残差が非線形な場合は `ScipyLeastSquares` のままにしてください。

### 解析的パラメータ Jacobian

外側または内側スロットが最小二乗オプティマイザ(`ScipyLeastSquares` または `ScipyLsqLinear`)である場合、パイプラインはモデルのパラメータ感度から構築した**解析的な残差 Jacobian** $J(x) = \partial r / \partial x$ を供給します。これが SciPy の有限差分 Jacobian を置き換えるので、各イテレーションは $O(n_\text{params})$ 回のソルブではなく、1 回のソルブと 1 回の感度評価で済みます。実務上、これにより勾配ベースの最小二乗フィットは大幅に高速かつロバストになり、特に `Nested` の変数射影ループ内でノイジーな有限差分ステップの影響を受けにくくなります。

設定は不要です — 目的関数とモデルが対応している場合には解析的 Jacobian が自動的に使用され、そうでない場合はフィットが透過的に有限差分にフォールバックします。有効化されているかはフィットログの `using analytic residual Jacobian` で確認できます。

## ランタイムオプション

`iws.DataFit` はスキーマを変更せずに最適化ループを調整できる `options` dict を受け付けます。すべてのキーは任意です。

| キー                         | デフォルト                        | 説明                                                                               |
| -------------------------- | ---------------------------- | -------------------------------------------------------------------------------- |
| `seed`                     | `None`                       | マルチスタートの初期推測や確率的最適化を再現するための乱数シード。                                                |
| `low_memory`               | `False`                      | 最良コストを 0.1% 以上改善しないログ行を破棄します。反復回数の多い長時間ジョブに有効です。                                 |
| `max_iterations`           | `None`                       | ジョブごとの反復回数上限。モデルが `convert_to_format == 'casadi'` の場合にのみ適用されます。                  |
| `maxtime`                  | `None`                       | ジョブごとの実時間予算(秒)。マルチスタートでは多数のジョブが走るため、合計はこれを超えることがあります。                            |
| `skip_objective_callbacks` | ローカル: `False` / クラスタ: `True` | 初期推測と最適化後のパラメータでモデルを再シミュレートする目的関数コールバックをスキップします。性能は向上しますが、初期および最終フィット結果は格納されません。 |

```python theme={null}
fit = iws.DataFit(
    objectives=objectives,
    parameters=parameters,
    options={
        "seed": 42,
        "low_memory": True,
        "maxtime": 600,
        "skip_objective_callbacks": False,
    },
)
```

<Note>
  Ionworks クラスタに送信されるパイプラインは、シミュレーション負荷を抑えるため `skip_objective_callbacks` をデフォルトで有効にします。初期および最終フィットのシミュレーション結果を取得したい場合は、`options` 内で明示的に `False` を指定してください。
</Note>

## 目的関数レベルの並列性

`DataFit` はトップレベルフィールドとして `objective_parallelism` を公開しており、目的関数レベルのスケジューリングをデバッグ用に上書きできます。これは `DataFit` の直接の引数であり、**`ランタイムオプション` の `options` キーではありません**。

| 値               | 挙動                                                                   |
| --------------- | -------------------------------------------------------------------- |
| `"auto"`（デフォルト） | 実行エンジンが判断します。複数の非自明な目的関数はフラット化されて並列評価され、単一目的のフィットは逐次のままになります。        |
| `"on"`          | 目的関数レベルの並列性を強制します。自動ヒューリスティックが目的関数あたりのコストを過小評価しているときに有用です。           |
| `"off"`         | 目的関数を逐次評価することを強制します。シングルスレッドのベースラインを再現したいときや、目的関数を単独でデバッグしたいときに有用です。 |

```python theme={null}
fit = iws.DataFit(
    objectives=objectives,
    parameters=parameters,
    objective_parallelism="off",  # デバッグ中は逐次評価を強制する
)
```

明確な理由がない限り `"auto"` のままにしてください。この設定はスケジューリングにのみ影響し、オプティマイザが受け取るコストは変わりません。

## モデル失敗のトラブルシューティング

フィット中に目的関数のモデルがセットアップできない、または評価に失敗した場合 — たとえばパラメータセットが不完全、カスタムモデルが離散化できない、初期 SOC 設定に失敗した、などの場合 — パイプラインは該当する目的関数名と原因を明示した `ModelError` を発生させます:

```text theme={null}
Failed to set up the model for objective 'test_1C':
Parameter 'Negative electrode thickness [m]' not found.
```

`ModelError` は汎用の `CONFIGURATION_ERROR` とは区別されます。失敗したジョブには専用の `MODEL_ERROR` コードが付与されるため、内部のエラーモニタリングを経由せず、メッセージをそのまま確認できます。修正は通常、欠落しているパラメータの追加、非現実的な境界の見直し、目的関数のモデルオプションの調整など、フィット設定側で行うものであり、Ionworks に報告するものではありません。

すでに分かりやすいエラーはそのまま伝播します: ソルバ側の数値的な失敗は引き続き `pybamm.SolverError` / `SOLVER_ERROR` として、パラメータルックアップの失敗は引き続き `ParameterNotFoundError` として表示されます。これらが評価中に発生した場合は、これまで通りオプティマイザのフォールバック(NaN コスト、ステップのスキップ)で処理されるため、一度の不正な反復でフィット全体が停止することはありません。

## 結果の取得

```python theme={null}
client.pipeline.wait_for_completion(submission.id)
result = client.pipeline.result(submission.id)
print(result.element_results["fit"])
```

`result.element_results["fit"]` はデータフィットの出力(最適パラメータ値、最終コスト、ログ化された軌跡など)をキーとする dict です。エンドツーエンドの例は [`packages/ionworks-api/examples/pipeline/datafit.py`](https://github.com/ionworks/ionworks-api/tree/main/examples/pipeline/datafit.py) を参照してください。

<CardGroup cols={2}>
  <Card title="データフィッティング (理論)" icon="chart-line" href="/guide/data-fitting/overview">
    コスト関数の数学、識別可能性、マルチスタート戦略 (英語ガイド)。
  </Card>

  <Card title="目的関数" icon="bullseye" href="/ja/pipelines/data-fitting/objective-functions">
    データ形状に応じたコストの選び方。
  </Card>

  <Card title="正則化" icon="scale-balanced" href="/ja/pipelines/data-fitting/regularization">
    ガウス事前分布でフィットを安定化。
  </Card>

  <Card title="感度解析" icon="chart-mixed" href="/ja/pipelines/data-fitting/sensitivity-analysis">
    実際に拘束されているパラメータを定量化。
  </Card>
</CardGroup>
