C内核流量计算方法优化,前端文件名称读取优化

This commit is contained in:
lujingze committed 2026-09-11 08:48:56 +00:00
1 parent 5d5a2e1843
commit 808c484f5b
94 files changed
+20163 -4418

No files matched your search

+18 -5
View File
@@ -1,6 +1,6 @@
# C 数值后端
后端 Python 校验 XML、检查连接、生成系统专用 C 并编译;独立 EXE 执行完整数值循环。原生运行不调用 Python。当前发布构建支持 Windows x64。
后端 Python 校验 XML、检查连接、生成系统专用 C 并编译;独立 EXE 执行完整数值循环。原生运行不调用 Python。当前构建支持 Windows x64 和 Linux x86_64;Linux 使用静态链接的 SUNDIALS。
## 启用网页后端
@@ -13,6 +13,15 @@ $env:SUNDIALS_ROOT = 'F:/Anaconda/Library'
.venv-win/Scripts/python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8000
```
Linux 使用现有 Python 虚拟环境,并将 C 依赖独立放在 `.venv/native/`:
```bash
bash bat/setup-native-linux.sh
.venv/bin/python -m uvicorn app.main:app --host 127.0.0.1 --port 8000
```
脚本下载并校验固定版本 SUNDIALS 7.4.0,在本地构建静态库;不会安装系统包。构建器先读取 `SUNDIALS_ROOT`,未指定时查找当前 Python 环境的 `native/sundials-7.4.0`、`/usr/local` 和 `/usr`。Linux 安装需包含静态 `.a` 库;生成的 ELF 程序名为 `model`,不依赖 SUNDIALS 共享库或 Python。`.venv/`、`app/data/` 和 `test/` 均在 Git 忽略范围。
沿用 `/api/system-xml/simulate` 与 `/api/system-xml/simulate-stream`。`native` 遇到不支持的组件或方法时报告错误,不静默切换。旧 Python 后端已退役,显式选择 `python` 会报错。
`bat/start-backend.bat`、`bat/start-backend.sh` 及其 `start-all` 上层入口默认设置 `native`,保留明确指定的环境变量覆盖。直接通过 uvicorn 启动也使用相同的默认选择。启动日志显示所选内核;C 模式只检查工具链与 XML Schema,不再预热 SciPy 积分/代数求解器。工具链检查失败会记录启动诊断,编辑器仍可使用,提交仿真时会明确报错,不会自动调用 Python 数值后端。
@@ -24,7 +33,7 @@ $env:SUNDIALS_ROOT = 'F:/Anaconda/Library'
## 独立生成与运行
```powershell
.venv-win/Scripts/python.exe -m app.simulation.native_codegen tests/data/native-skill-test.xml --output-dir test/native-v1/example-run --runs 3 --solve-only
.venv-win/Scripts/python.exe -m app.simulation.native_codegen tests/fixtures/native-skill-test.xml --output-dir test/native-v1/example-run --runs 3 --solve-only
```
输入支持 XML,或带普通算术表达式的工程 JSON。JSON 普通数字已经是 SI 值;算术表达式按编辑器所选单位换算,例如 `3.14*10**2/4 mm2` 转为 `0.0000785 m2`。较复杂的表达式应先在网页导出 XML。CLI 不执行任意 Python/JavaScript 表达式。
@@ -46,7 +55,7 @@ EXE 不需要 Python、SciPy、XML 或原工程文件。DLL 需要与 EXE 一同
- MECMAS21 支持现有 Python 方程中的摩擦、风阻、柔性限位和 `stoptype=1/2/3/4`,含反弹系数与速度阈值;气腔和管路支持换热。LSTP00A 接受两种刚度模式及接触力符号模式,严格沿用当前组件方程。已有参数中尚未参与 Python 方程的物理效应不会在 C 端凭空补造,详见覆盖记录。
- 扩展编译器上限 1024 状态、16384 输出;无连续状态的信号系统使用隐藏常量状态驱动输出。气动网络必须有压力状态锚点;独立气腔之间不能无阻力直接相连。兼容固定管路容腔是已实现的合并例外。闭合未收敛或方程欠定时明确失败,不静默回退。
- 支持原生 RK45 与 CVODE BDF。CVODE 继续使用默认数值雅可比和稠密线性求解;本次删除不改变 C 求解器的雅可比策略。
- 默认 `rtol=1e-6`、气体状态 `atol=1e-8`、机械状态 `atol=1e-12`。CLI 可覆盖 rtol;本版不支持自定义 atol 或 first_step。不同积分器相同局部容差不保证全局曲线误差完全相同。
- 网页和 Python CLI 默认 `rtol=1e-8`;生成的状态绝对误差限为质量 `1e-14 kg`、内能 `1e-8 J`、速度/位移 `1e-12`(各自 SI 单位)。独立 C 程序默认 `rtol=1e-6`,对照时应显式传入。CLI 可覆盖 rtol;本版不支持自定义 atol 或 first_step。不同积分器相同局部容差不保证全局曲线误差完全相同。
- 时间信号显式分段,塑性/反弹端挡用稠密插值定位并重启。试探 RHS 不修改已接受状态。柔性接触沿用现有分段力公式,不改变刚度或阻尼来提速。
- 每任务独立进程,支持进度、取消及超时。进程崩溃不会作为成功返回,受控失败保留最后接受状态。
- 编译缓存位于 `app/data/native-builds/`,校验模型、组件合同、源码、编译选项及依赖哈希。本版参数特化入 C,修改模型数值参数会重新编译;修改时间、步长、rtol、采样选项可复用 EXE。
@@ -71,6 +80,10 @@ EXE 不需要 Python、SciPy、XML 或原工程文件。DLL 需要与 EXE 一同
- `config.py`、`sampling.py`、`results.py`:配置、进度、采样合法性和结果合同。
- `performance.py`:Python 编排阶段计时,求解耗时读取 C 报告。
`solvers/`、`systems/generic.py`、旧示例、Python 物性/流量/机械公式和物性缓存已删除。数值回归读取 `tests/data/native-python-reference.json` 的 50 个网络、112 组冻结参考状态,不需要 Python 求解器。旧算法及历史对照资料可从 Git 历史找回。
`solvers/`、`systems/generic.py`、旧示例、Python 物性/流量/机械公式和物性缓存已删除。数值回归读取 `tests/baselines/native/native-python-reference.json` 的 50 个网络、112 组冻结参考状态,不需要 Python 求解器。旧算法及历史对照资料可从 Git 历史找回。
测试安装:`python -m pip install -r requirements-test.txt`。当前完整数值测试要求 Windows x64、GCC 与 SUNDIALS;Linux 尚不提供 EXE 构建。
测试安装:`python -m pip install -r requirements-test.txt`。完整数值测试需要 GCC 与 SUNDIALS;Windows x64 使用导入库/DLL,Linux x86_64 使用静态库。
## AME 对齐后的工程输入
当前用户运行请使用 `tests/data/test-mql-4-corrected.json` 或 `tests/data/test-mql-8-corrected.json`。四路执行 XML 位于 `tests/fixtures/amesim/`,与其 JSON 同步;原八路 JSON 已移入 `tests/fixtures/legacy/` 供差异审计。`test-mql-4-amesim-reference.json` 是曲线基准,不是工程输入。模型复核、P4 端口图形修正、默认 `rtol=1e-8` 的验收和速度记录见 [本轮验证报告](../docs/other/牛顿管流求根与四路网页验证-2026-09-11.md)。
+67 -15
View File
@@ -346,27 +346,79 @@ static double pipe_friction_derivative(double re,double rr,double rough,double *
double db=8.37293695*b*(1-b)/(re-89.96829989);
*df=dl*(1-b)+b*dt+db*(turb-lam);return lam+b*(turb-lam);
}
static double pipe_checked_solution(double re,double f,double K,double rr,double rough,
double flow_per_re,NativePipeSolve *status) {
double target=sqrt(K/f),change=fabs(target-re);
/* Separate the absolute and relative tests so a large flow scale cannot
make both sides overflow and accidentally satisfy the stopping test. */
if(!isfinite(target) || !isfinite(target*flow_per_re) ||
!(change<=re*1e-10 || change*flow_per_re<=1e-13))return NAN;
double value=target*target*pipe_friction_prepared(target,rr,rough);
status->relative_residual=fabs(value/K-1);
if(isfinite(value) && status->relative_residual<=1e-9) {
status->converged=1;return target;
}
return NAN;
}
double native_pipe_resistance(double K,double rr,double flow_per_re,NativePipeSolve *status) {
NativePipeSolve local={0,0,0,INFINITY};if(!status)status=&local;
*status=local;
if(!(K>=0 && rr>=0 && flow_per_re>0) || !isfinite(K) || !isfinite(rr) || !isfinite(flow_per_re))return NAN;
if(K/64<=89.96829989){status->converged=1;status->relative_residual=0;return K/64;}
double rough=pipe_rough_limit(rr),lo=0,hi=fmax(sqrt(K/.02),1),df;
for(int i=0;i<128 && hi*hi*pipe_friction_prepared(hi,rr,rough)<K;i++)hi*=2;
if(!isfinite(hi))return NAN;
double re=fmin(sqrt(K/.02),hi);
for(int i=0;i<80;i++) {
status->iterations=i+1;
double f=pipe_friction_derivative(re,rr,rough,&df),F=re*re*f-K;
double target=sqrt(K/f);
if(fabs(target-re)*flow_per_re<=fmax(1e-13,re*flow_per_re*1e-10)) {
/* Check the returned point, not just the change of successive guesses. */
status->relative_residual=fabs(target*target*pipe_friction_prepared(target,rr,rough)/K-1);
if(isfinite(target) && status->relative_residual<=1e-9){status->converged=1;return target;}
if(K==0){status->converged=1;status->relative_residual=0;return 0;}
if(K/64<=89.96829989) {
double re=K/64;
status->relative_residual=fabs(64*re/K-1);
if(re>0 && isfinite(re*flow_per_re) && status->relative_residual<=1e-9) {
status->converged=1;return re;
}
return NAN;
}
double rough=pipe_rough_limit(rr),lo=0,hi=fmax(sqrt(K/.02),1),df;
if(!isfinite(rough) || !isfinite(hi))return NAN;
int bracketed=0;
for(int i=0;i<128;i++) {
double value=hi*hi*pipe_friction_prepared(hi,rr,rough);
if(!isfinite(value))return NAN;
if(value>=K){bracketed=1;break;}
lo=hi;hi*=2;
if(!isfinite(hi))return NAN;
}
/* F(0)=-K; each positive lower endpoint was checked while expanding.
Never start iteration with an unchecked or non-finite upper residual. */
if(!bracketed)return NAN;
double re=fmax(lo,fmin(sqrt(K/.02),hi)),previous_residual=INFINITY;
int previous_newton=0;
for(int i=0;i<128;i++) {
status->iterations=i+1;
double f=pipe_friction_derivative(re,rr,rough,&df),value=re*re*f,F=value-K;
if(!(f>0) || !isfinite(f) || !isfinite(value))return NAN;
status->relative_residual=fabs(value/K-1);
double target=pipe_checked_solution(re,f,K,rr,rough,flow_per_re,status);
if(status->converged)return target;
if(F>0)hi=re;else lo=re;
double next=re-F/(2*re*f+re*re*df);
if(!isfinite(next) || next<=lo || next>=hi){next=.5*(lo+hi);status->bisections++;}
double slope=2*re*f+re*re*df;
double next=slope>0 && isfinite(slope) ? re-F/slope : NAN;
/* An in-bracket Newton step is useful only if it reduces |F|.
After a step that fails to halve it, bisect the retained bracket;
successive Newton steps therefore cannot stagnate near an endpoint. */
int bisect=(previous_newton && fabs(F)>.5*previous_residual) ||
!(slope>0) || !isfinite(slope) || !isfinite(next) || next<=lo || next>=hi;
if(bisect) {
next=lo+.5*(hi-lo);status->bisections++;
if(next<=lo || next>=hi) {
/* Adjacent floating-point endpoints: inspect both actual
candidates, then fail if neither meets the original tests. */
double endpoints[]={lo,hi};
for(int j=0;j<2;j++) {
double endpoint=endpoints[j];
target=pipe_checked_solution(endpoint,pipe_friction_prepared(endpoint,rr,rough),
K,rr,rough,flow_per_re,status);
if(status->converged)return target;
}
return NAN;
}
}
previous_newton=!bisect;previous_residual=fabs(F);
re=next;
}
return NAN;