pastas

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Pastas - Groundwater Time Series Analysis

Pastas - 地下水时间序列分析

Quick Reference

快速参考

python
import pastas as ps
import pandas as pd
python
import pastas as ps
import pandas as pd

Load data

Load data

head = pd.read_csv('well.csv', index_col=0, parse_dates=True).squeeze() precip = pd.read_csv('precip.csv', index_col=0, parse_dates=True).squeeze() evap = pd.read_csv('evap.csv', index_col=0, parse_dates=True).squeeze()
head = pd.read_csv('well.csv', index_col=0, parse_dates=True).squeeze() precip = pd.read_csv('precip.csv', index_col=0, parse_dates=True).squeeze() evap = pd.read_csv('evap.csv', index_col=0, parse_dates=True).squeeze()

Create model

Create model

ml = ps.Model(head, name='Well_001')
ml = ps.Model(head, name='Well_001')

Add recharge stress

Add recharge stress

sm = ps.RechargeModel(precip, evap, rfunc=ps.Gamma(), name='recharge') ml.add_stressmodel(sm)
sm = ps.RechargeModel(precip, evap, rfunc=ps.Gamma(), name='recharge') ml.add_stressmodel(sm)

Solve and plot

Solve and plot

ml.solve() ml.plot()
undefined
ml.solve() ml.plot()
undefined

Key Classes

核心类

ClassPurpose
ps.Model
Main model container
ps.StressModel
Response to external stress (pumping, river)
ps.RechargeModel
Recharge from precipitation minus evaporation
ps.Gamma
Gamma distribution response function
ps.Exponential
Simple exponential response function
用途
ps.Model
主模型容器
ps.StressModel
对外部应力(抽水、河流)的响应
ps.RechargeModel
降水减蒸发的补给量
ps.Gamma
伽马分布响应函数
ps.Exponential
简单指数响应函数

Essential Operations

核心操作

Create and Solve Model

创建并求解模型

python
ml = ps.Model(head, name='well')
ml.add_stressmodel(ps.RechargeModel(precip, evap, rfunc=ps.Gamma(), name='recharge'))
ml.solve()
python
ml = ps.Model(head, name='well')
ml.add_stressmodel(ps.RechargeModel(precip, evap, rfunc=ps.Gamma(), name='recharge'))
ml.solve()

Add Pumping Well

添加抽水井

python
pumping = pd.read_csv('pumping.csv', index_col=0, parse_dates=True).squeeze()
ml.add_stressmodel(ps.StressModel(pumping, rfunc=ps.Hantush(),
                                   name='pumping', up=False))  # up=False for drawdown
python
pumping = pd.read_csv('pumping.csv', index_col=0, parse_dates=True).squeeze()
ml.add_stressmodel(ps.StressModel(pumping, rfunc=ps.Hantush(),
                                   name='pumping', up=False))  # up=False代表水位下降

Model Diagnostics

模型诊断

python
print(f"EVP: {ml.stats.evp():.1f}%")      # Explained variance
print(f"RMSE: {ml.stats.rmse():.3f} m")   # Root mean square error
print(f"AIC: {ml.stats.aic():.1f}")       # Model selection criterion

ml.plots.diagnostics()                     # Diagnostic plots
ml.plots.acf()                            # Autocorrelation
python
print(f"EVP: {ml.stats.evp():.1f}%")      # 解释方差百分比
print(f"RMSE: {ml.stats.rmse():.3f} m")   # 均方根误差
print(f"AIC: {ml.stats.aic():.1f}")       # 模型选择准则

ml.plots.diagnostics()                     # 诊断图
ml.plots.acf()                            # 自相关图

Get Contributions

获取分量贡献

python
contributions = ml.get_contributions()
for name, contrib in contributions.items():
    print(f"{name}: mean={contrib.mean():.2f}")
python
contributions = ml.get_contributions()
for name, contrib in contributions.items():
    print(f"{name}: 均值={contrib.mean():.2f}")

Step and Impulse Response

阶跃与脉冲响应

python
step = ml.get_step_response('recharge')    # Step response
block = ml.get_block_response('recharge')  # Impulse response
python
step = ml.get_step_response('recharge')    # 阶跃响应
block = ml.get_block_response('recharge')  # 脉冲响应

Export and Load

导出与加载

python
ml.to_json('model.pas')                    # Save model
ml_loaded = ps.io.load('model.pas')        # Load model

sim = ml.simulate()
sim.to_csv('simulation.csv')               # Export results
python
ml.to_json('model.pas')                    # 保存模型
ml_loaded = ps.io.load('model.pas')        # 加载模型

sim = ml.simulate()
sim.to_csv('simulation.csv')               # 导出结果

Model Statistics

模型统计指标

StatisticDescriptionGood Value
EVPExplained variance percentage>70%
RMSERoot mean square errorLow (context-dependent)
AICAkaike Information CriterionLower = better
BICBayesian Information CriterionLower = better
统计指标描述理想值
EVP解释方差百分比>70%
RMSE均方根误差越低越好(取决于具体场景)
AIC赤池信息准则数值越小越好
BIC贝叶斯信息准则数值越小越好

Common Patterns

常见模式

Compare Response Functions

比较响应函数

python
for rfunc in [ps.Gamma(), ps.Exponential(), ps.Hantush()]:
    ml = ps.Model(head)
    ml.add_stressmodel(ps.RechargeModel(precip, evap, rfunc=rfunc, name='r'))
    ml.solve(report=False)
    print(f"{rfunc.name}: EVP={ml.stats.evp():.1f}%, AIC={ml.stats.aic():.1f}")
python
for rfunc in [ps.Gamma(), ps.Exponential(), ps.Hantush()]:
    ml = ps.Model(head)
    ml.add_stressmodel(ps.RechargeModel(precip, evap, rfunc=rfunc, name='r'))
    ml.solve(report=False)
    print(f"{rfunc.name}: EVP={ml.stats.evp():.1f}%, AIC={ml.stats.aic():.1f}")

Forecast Future Levels

预测未来水位

python
ml.solve()
forecast = ml.simulate(tmin='2024-01-01', tmax='2025-12-31')
ml.plot(tmax='2025-12-31')
python
ml.solve()
forecast = ml.simulate(tmin='2024-01-01', tmax='2025-12-31')
ml.plot(tmax='2025-12-31')

River or Custom Stress

河流或自定义应力

python
river = pd.read_csv('river_stage.csv', index_col=0, parse_dates=True).squeeze()
sm = ps.StressModel(river, rfunc=ps.Exponential(), name='river',
                    settings='waterlevel')
ml.add_stressmodel(sm)
python
river = pd.read_csv('river_stage.csv', index_col=0, parse_dates=True).squeeze()
sm = ps.StressModel(river, rfunc=ps.Exponential(), name='river',
                    settings='waterlevel')
ml.add_stressmodel(sm)

When to Use vs Alternatives

适用场景与替代工具对比

Use CaseToolWhy
Groundwater time series analysisPastasPurpose-built transfer function models
Well response to recharge/pumpingPastasBuilt-in stress models and response functions
Numerical groundwater flow (MODFLOW)FloPyFull 3D finite-difference groundwater model
Simple exponential decay fittingCustom scipy
scipy.optimize.curve_fit
is sufficient
Regional groundwater flow modellingFloPySpatially distributed parameters and boundaries
Aquifer test analysis (pumping tests)Aqtesolv / customDedicated well test interpretation
Multi-well network analysisPastasModel each well independently, compare responses
Signal decompositionPastasSeparate recharge, pumping, and trend contributions
Choose Pastas when: You have groundwater level time series and want to model responses to precipitation, evaporation, or pumping using transfer function noise models. Excellent for rapid model building with diagnostics.
Choose FloPy when: You need spatially distributed groundwater flow modelling with MODFLOW, including multiple layers, boundary conditions, and transport.
Choose custom scipy when: You only need to fit a simple analytical model (e.g., Theis equation) to pumping test data without time series decomposition.
场景工具原因
地下水时间序列分析Pastas专为传递函数模型设计
水井对补给/抽水的响应Pastas内置应力模型与响应函数
数值地下水流动(MODFLOW)FloPy完整的3D有限差分地下水模型
简单指数衰减拟合自定义scipy实现
scipy.optimize.curve_fit
已足够
区域地下水流动建模FloPy支持空间分布参数与边界条件
含水层试验分析(抽水试验)Aqtesolv / 自定义实现专为水井试验解译设计
多水井网络分析Pastas可独立建模每口水井,对比响应
信号分解Pastas可分离补给、抽水与趋势分量
选择Pastas的场景:当你拥有地下水位时间序列,需要使用传递函数噪声模型模拟其对降水、蒸发或抽水的响应时。Pastas在快速建模与诊断方面表现出色。
选择FloPy的场景:当你需要基于MODFLOW进行空间分布的地下水流动建模,包括多层结构、边界条件与运移模拟时。
选择自定义scipy实现的场景:当你仅需为抽水试验数据拟合简单解析模型(如泰斯方程),无需时间序列分解时。

Common Workflows

常见工作流

Groundwater Response Model with Diagnostics

带诊断的地下水响应模型

  • Load head time series and stress data (precipitation, evaporation, pumping)
  • Inspect data: check for gaps, outliers, and time coverage
  • Create
    ps.Model(head)
    with observation data
  • Add recharge stress with
    ps.RechargeModel(precip, evap, rfunc=ps.Gamma())
  • Add pumping or river stresses if applicable
  • Solve model with
    ml.solve()
  • Check EVP (>70%), RMSE, and AIC
  • Run
    ml.plots.diagnostics()
    to inspect residuals
  • Check residual autocorrelation; enable noise model if needed:
    ml.solve(noise=True)
  • Compare response functions (Gamma vs Exponential vs Hantush) using AIC
  • Extract step/block responses to interpret aquifer behavior
  • Decompose signal into individual stress contributions
  • Export model to JSON and simulation results to CSV
  • 加载水头时间序列与应力数据(降水、蒸发、抽水)
  • 检查数据:排查缺失值、异常值与时间覆盖范围
  • 使用观测数据创建
    ps.Model(head)
  • 通过
    ps.RechargeModel(precip, evap, rfunc=ps.Gamma())
    添加补给应力
  • 如有需要,添加抽水或河流应力
  • 使用
    ml.solve()
    求解模型
  • 检查EVP(>70%)、RMSE与AIC指标
  • 运行
    ml.plots.diagnostics()
    检查残差
  • 检查残差自相关性;如有需要启用噪声模型:
    ml.solve(noise=True)
  • 使用AIC对比响应函数(Gamma vs Exponential vs Hantush)
  • 提取阶跃/块响应以解读含水层行为
  • 将信号分解为各应力的单独贡献
  • 将模型导出为JSON,模拟结果导出为CSV

Tips

小贴士

  1. Start simple - Add stresses incrementally
  2. Check residuals - Should be white noise (use
    ml.plots.diagnostics()
    )
  3. Compare response functions - Use AIC/BIC to select best model
  4. Use daily data - Pastas works best with daily time series
  5. Normalize units - Precipitation in mm/day, head in meters
  1. 从简开始 - 逐步添加应力项
  2. 检查残差 - 残差应呈白噪声(使用
    ml.plots.diagnostics()
  3. 对比响应函数 - 使用AIC/BIC选择最优模型
  4. 使用日度数据 - Pastas对日度时间序列的支持最佳
  5. 统一单位 - 降水单位为毫米/天,水头单位为米

Common Issues

常见问题

IssueSolution
Poor fit (low EVP)Try different response functions
Residual autocorrelationAdd noise model:
ml.solve(noise=True)
Unstable parametersSet parameter bounds or fix values
Missing stress dataInterpolate or use
fillna()
before modeling
问题解决方案
拟合效果差(EVP低)尝试不同的响应函数
残差存在自相关性添加噪声模型:
ml.solve(noise=True)
参数不稳定设置参数边界或固定参数值
应力数据缺失建模前先插值或使用
fillna()
填充

References

参考文献

  • Stress Models - Available stress model types
  • Response Functions - Response function selection
  • Stress Models - 可用的应力模型类型
  • Response Functions - 响应函数选择指南

Scripts

脚本

  • scripts/groundwater_model.py - Complete groundwater modeling workflow
  • scripts/groundwater_model.py - 完整的地下水建模工作流