<a id="guide-path"></a>

<a id="how-to-check-a-series-for-path-dependence"></a>

# How to check a series for path dependence

Fit the series with `direction="both"` and look for `SEQUENTIAL_PATH_DEPENDENT`, and pass `verify_discontinuities=True` so that each step the series flags is refitted from cold on its two patterns alone.

Each fit in a series starts from its neighbour’s answer.
An error in one pattern can therefore pass to every pattern after it and still draw a smooth curve.
These two checks separate a trend in the data from one the chain made.

<a id="run-the-chain-both-ways"></a>

## Run the chain both ways

This fits the seven synthetic LaB6 patterns of [How to fit a temperature series](series.html.md) from 300 K up to 900 K and again from 900 K down:

```python

from _lab6_ramp import TEMPERATURES, TRUE_A, ramp, simulate, starting_model

import rietx as rx

patterns = ramp()
series = rx.refine_sequential(patterns, *starting_model(), plan="mccusker_default",
                              x=TEMPERATURES, x_label="T (K)", direction="both")

print([d.code for d in series.diagnostics])
forward = series.trajectory("phases.0.cell.a")
backward = series.backward.trajectory("phases.0.cell.a")
gap = max(abs(f - b) / e for f, b, e in zip(forward.value, backward.value, forward.stderr))
print(f"largest forward-backward gap: {gap:.2f} esd")
```

```text
['SEQUENTIAL_PERSISTENT_FINDING', 'SEQUENTIAL_PERSISTENT_FINDING']
largest forward-backward gap: 0.00 esd
```

`series.backward` is the downward chain’s own `SeriesResult`, and the entries of `series` are the upward one’s.
A `SEQUENTIAL_PATH_DEPENDENT` diagnostic names each parameter whose two values differ by more than their esds allow, and its message quotes both values.
Read the two values rather than the multiple of σ, because a parameter near zero with an esd near zero can report a gap of thousands of σ that has no physical size.

No such diagnostic fired here, and the largest gap in the cell edge is under 0.01 esd.
`SEQUENTIAL_PATH_CHECK_INCOMPLETE` is absent too, so the comparison ran on every pattern.
The two checks together mean the comparison was made and found nothing.
Without the second, an empty list can also mean the downward chain was stopped or raised before it finished.

The downward chain repeats the work of the upward one, so `direction="both"` takes about twice as long.

<a id="check-a-step-against-two-independent-fits"></a>

## Check a step against two independent fits

`SEQUENTIAL_DISCONTINUITY` flags a step much larger than the series’ typical step.
Such a step is either in the data or made by the chain, and the diagnostic cannot tell which.
`verify_discontinuities=True` refits the step’s two patterns from your starting model, each on its own, and reports the step they give.
This replaces the 700 K pattern with one whose cell is 1.5 % larger:

```python
jumped = list(patterns)
jumped[4] = simulate(TRUE_A[4] * 1.015, seed=15)  # the 700 K cell 1.5 % larger
series = rx.refine_sequential(jumped, *starting_model(), plan="mccusker_default",
                              x=TEMPERATURES, x_label="T (K)", verify_discontinuities=True)

for d in series.diagnostics:
    if d.code == "SEQUENTIAL_DISCONTINUITY" and d.where == ["phases.0.cell.a"]:
        print(d.message)
for entry in series:
    print(f"{entry.label}  {entry.rung}")
```

```text
phases.0.cell.a steps by 0.06454 between p003 and p004 (T (K) 600 → 700), 31× its median step over the series. Refitted cold and independently, the two patterns step by 0.06454, 1.00× the chain's.
p000  cold
p001  warm
p002  warm
p003  warm
p004  warm_staged
p005  warm
p006  warm
```

The diagnostic’s `value` is the cold step over the chain’s.
Near 1 the step is in the data, as here.
Near 0 the chain made it, because the two patterns agree when nothing passes an error between them.
Near −1 the cold pair stepped the other way.
`series.discontinuities` holds the flagged pairs, with `SeriesStep.indices` and `SeriesStep.step`.

The check costs up to two full fits per flagged step, and nothing else in the result changes.
Here `cell.b` and `cell.c` are flagged at the same step as `cell.a`, because the cubic cell ties them to it, and the three flags share one pair of refits.

<a id="read-where-each-fit-started"></a>

## Read where each fit started

The jump also broke a warm start, at the jumped pattern.
The 700 K fit, started from the 600 K answer, reached an Rwp over 0.9, far above the rest of the series.
The series fitted it again with the whole plan, still from the 600 K answer, and reached 0.04.
The 800 K fit, started from that answer, needed no second attempt.
`entry.rwp_warm` keeps the Rwp the first attempt reached.

A `cold` entry after the first pattern means no warm start could be rescued, and the pattern was fitted from your starting model.
Its values do not continue the chain, so read them as a separate measurement.

The full script is `examples/guides/path.py`.

<a id="see-also"></a>

## See also

- [How to fit a temperature series](series.html.md) runs the chain these checks test.
