/install glm-lake-mendota-glm-output
GLM Output Guide
Overview
GLM produces NetCDF output containing simulated water temperature profiles. Processing this output requires understanding the coordinate system and matching with observations.
Output File
After running GLM, results are in output/output.nc:
| Variable | Description | Shape |
|---|---|---|
time |
Hours since simulation start | (n_times,) |
z |
Height from lake bottom (not depth!) | (n_times, n_layers, 1, 1) |
temp |
Water temperature (°C) | (n_times, n_layers, 1, 1) |
Reading Output with Python
from netCDF4 import Dataset
import numpy as np
import pandas as pd
from datetime import datetime
nc = Dataset('output/output.nc', 'r')
time = nc.variables['time'][:]
z = nc.variables['z'][:]
temp = nc.variables['temp'][:]
nc.close()
Coordinate Conversion
Important: GLM z is height from lake bottom, not depth from surface.
# Convert to depth from surface
# Set LAKE_DEPTH based on lake_depth in &init_profiles section of glm3.nml
LAKE_DEPTH = \x3Clake_depth_from_nml>
depth_from_surface = LAKE_DEPTH - z
Complete Output Processing
from netCDF4 import Dataset
import numpy as np
import pandas as pd
from datetime import datetime
def read_glm_output(nc_path, lake_depth):
nc = Dataset(nc_path, 'r')
time = nc.variables['time'][:]
z = nc.variables['z'][:]
temp = nc.variables['temp'][:]
start_date = datetime(2009, 1, 1, 12, 0, 0)
records = []
for t_idx in range(len(time)):
hours = float(time[t_idx])
date = pd.Timestamp(start_date) + pd.Timedelta(hours=hours)
heights = z[t_idx, :, 0, 0]
temps = temp[t_idx, :, 0, 0]
for d_idx in range(len(heights)):
h_val = heights[d_idx]
t_val = temps[d_idx]
if not np.ma.is_masked(h_val) and not np.ma.is_masked(t_val):
depth = lake_depth - float(h_val)
if 0 \x3C= depth \x3C= lake_depth:
records.append({
'datetime': date,
'depth': round(depth),
'temp_sim': float(t_val)
})
nc.close()
df = pd.DataFrame(records)
df = df.groupby(['datetime', 'depth']).agg({'temp_sim': 'mean'}).reset_index()
return df
Reading Observations
def read_observations(obs_path):
df = pd.read_csv(obs_path)
df['datetime'] = pd.to_datetime(df['datetime'])
df['depth'] = df['depth'].round().astype(int)
df = df.rename(columns={'temp': 'temp_obs'})
return df[['datetime', 'depth', 'temp_obs']]
Calculating RMSE
def calculate_rmse(sim_df, obs_df):
merged = pd.merge(obs_df, sim_df, on=['datetime', 'depth'], how='inner')
if len(merged) == 0:
return 999.0
rmse = np.sqrt(np.mean((merged['temp_sim'] - merged['temp_obs'])**2))
return rmse
# Usage: get lake_depth from glm3.nml &init_profiles section
sim_df = read_glm_output('output/output.nc', lake_depth=25)
obs_df = read_observations('field_temp_oxy.csv')
rmse = calculate_rmse(sim_df, obs_df)
print(f"RMSE: {rmse:.2f}C")
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| RMSE very high | Wrong depth conversion | Use lake_depth - z, not z directly |
| No matched observations | Datetime mismatch | Check datetime format consistency |
| Empty merged dataframe | Depth rounding issues | Round depths to integers |
Best Practices
- Check
lake_depthin&init_profilessection ofglm3.nml - Always convert z to depth from surface before comparing with observations
- Round depths to integers for matching
- Group by datetime and depth to handle duplicate records
- Check number of matched observations after merge
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install glm-lake-mendota-glm-output - 安装完成后,直接呼叫该 Skill 的名称或使用
/glm-lake-mendota-glm-output触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
glm-output 是什么?
Read and process GLM output files. Use when you need to extract temperature data from NetCDF output, convert depth coordinates, or calculate RMSE against obs... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 81 次。
如何安装 glm-output?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install glm-lake-mendota-glm-output」即可一键安装,无需额外配置。
glm-output 是免费的吗?
是的,glm-output 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。
glm-output 支持哪些平台?
glm-output 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 glm-output?
由 wu-uk(@wu-uk)开发并维护,当前版本 v0.1.0。