Issue Description
When user-supplied data contains NaN — usually a sign of missing or bad input — linopy silently fills it with an operator-specific neutral element rather than surfacing it. The fill value differs per operator, and in every case a data error that should stop the run is absorbed without a trace.
Reproducible Example
import numpy as np
import pandas as pd
import xarray as xr
import linopy
m = linopy.Model()
x = m.add_variables(coords=[pd.RangeIndex(3, name="time")])
data = xr.DataArray([1.0, np.nan, 3.0], dims=["time"], coords={"time": range(3)})
print((x + data).const.sel(time=1).item()) # 0.0 — NaN -> 0
print((x * data).coeffs.squeeze().sel(time=1).item()) # 0.0 — NaN -> 0 (variable zeroed)
print((x / data).coeffs.squeeze().sel(time=1).item()) # 1.0 — NaN -> 1 (variable unchanged)
The NaN at time=1 is replaced — 0 for +, 0 for * (zeroing the variable out), 1 for / (leaving it unchanged). No exception, no warning.
Expected Behavior
NaN in user-supplied data should not be silently substituted. The user should say what it means (data.fillna(0), factor.fillna(1), …) — or linopy should raise.
Confirmed on linopy 0.7.0. Part of the arithmetic-convention work (#591).
Issue Description
When user-supplied data contains NaN — usually a sign of missing or bad input — linopy silently fills it with an operator-specific neutral element rather than surfacing it. The fill value differs per operator, and in every case a data error that should stop the run is absorbed without a trace.
Reproducible Example
The NaN at
time=1is replaced —0for+,0for*(zeroing the variable out),1for/(leaving it unchanged). No exception, no warning.Expected Behavior
NaN in user-supplied data should not be silently substituted. The user should say what it means (
data.fillna(0),factor.fillna(1), …) — or linopy should raise.Confirmed on linopy 0.7.0. Part of the arithmetic-convention work (#591).