优化 Jacobian 确定性复用并补充性能剖析与平台依赖文档
在单次 Jacobian 构建内按完整输入精确复用储气物性、PH 反算、密度和管路求根结果,保持原有求值副作用、差分政策与失败回退。八路模型求解 CPU 中位数减少 19.27%,循环和不循环的完整原始采样均与恢复基线一致。 增加独立的跨平台时间剖析工具,记录互斥阶段耗时、Newton/LU 统计、矩阵复用与内核复用,保存 UD00 两种工况的调查报告和机器可读汇总。 补充 Windows/Linux 运行、测试、原生编译和剖析所需依赖文档及索引,不修改依赖清单、版本锁或安装环境。 验证:8 项新增专项回归通过;2270 次完整 Jacobian 核对零差异;16 次剖析配对及预热运行保持完整数值一致。既有固定样本哈希失败和 Linux 实机验收限制见报告。
This commit is contained in:
1 parent
2b07d996cf
commit
1aac220084
26 files changed
+2293
-13
No files matched your search
@@ -6,6 +6,8 @@ MECMAS21 已支持静摩擦保持与脱离、高级低速区间和 Stribeck 过
|
||||
|
||||
平台相关修改遵循 [Windows 与 Linux 交付约定](../docs/standard/跨平台交付约定.md)。缓存时间戳更新按 `os.supports_follow_symlinks` 检测运行平台能力,Windows 不支持该可选操作时对已校验的普通缓存目录使用常规 `utime`。缓存集成回归可在两平台使用真实工具链执行:`python -m unittest tests.test_native_cache_storage tests.test_native_cache_platform -v`;设置 `SIMULATION_NATIVE_REQUIRE_TOOLCHAIN=1` 时工具链缺失将失败而不会跳过。
|
||||
|
||||
两平台所需 Python 包、GCC、SUNDIALS 库文件和测试/剖析依赖见 [平台依赖说明](../docs/standard/platform-dependencies.md)。本轮 Jacobian 复用继续使用现有五个原生链接库;时间剖析使用同一 SUNDIALS 7.4 公共接口,不需要额外的 Python profiler 或自动微分库。
|
||||
|
||||
## 启用网页后端
|
||||
|
||||
当前默认使用 `native`。也可在启动后端的 PowerShell 中显式设置:
|
||||
@@ -93,6 +95,8 @@ BDF 默认使用结构着色差分,无需环境变量或网页选项。修正
|
||||
|
||||
## 能力与限制
|
||||
|
||||
Jacobian 构建内现已按完整输入的浮点位复用储气物性、PH 温度反算、密度及管路求根结果,详见 [确定性复用说明](../docs/standard/native-jacobian-reuse.md)。独立耗时和求解计数调查工具见 [时间剖析说明](../docs/standard/native-solver-profiling.md);正常运行不加入该诊断插桩。
|
||||
|
||||
- 已实现当前注册的 27 类组件:22 类 Amesim 公开组件(含空气、氦气两种介质定义)和 5 类实验组件。完整清单及验证说明见 [组件覆盖记录](../docs/other/C内核组件库覆盖记录.md)。介质定义在编译期选择对应的 C 物性函数。
|
||||
- 管路覆盖 PNL00R、PNL0001/2/3;阀覆盖 PNOR001、固定/信号开度 PNVO001 及面积/Cv/Kv 模式;连接件覆盖 PN3NODE2、P4NODE2、LMECHN1。支持串联阻力的压力求解、节点焓混合及温度参考、刚性质量合并、兼容管路容腔的等密度状态投影。
|
||||
- MECMAS21 支持现有 Python 方程中的摩擦、风阻、柔性限位和 `stoptype=1/2/3/4`,含反弹系数与速度阈值;气腔和管路支持换热。LSTP00A 接受两种刚度模式及接触力符号模式,严格沿用当前组件方程。已有参数中尚未参与 Python 方程的物理效应不会在 C 端凭空补造,详见覆盖记录。
|
||||
|
||||
@@ -125,7 +125,15 @@ double native_pipe_flow_context(NativePropertyCache *cache,const NativeMedium *m
|
||||
if(4*lam/den<=1000) return sign*lam;
|
||||
}
|
||||
double base=area*p*cm/sqrt(T),K=pow(4*base/den,2)*d/length;
|
||||
return sign*native_pipe_resistance(K,rr,den/4,NULL)*den/4;
|
||||
double resistance;
|
||||
if(cache && cache->jacobian) {
|
||||
double key[]={K,rr,den/4};
|
||||
if(!native_jacobian_scalar_get(cache->jacobian,NATIVE_JACOBIAN_PIPE,0,key,3,&resistance)) {
|
||||
resistance=native_pipe_resistance(K,rr,den/4,NULL);
|
||||
native_jacobian_scalar_put(cache->jacobian,NATIVE_JACOBIAN_PIPE,0,key,3,resistance);
|
||||
}
|
||||
} else resistance=native_pipe_resistance(K,rr,den/4,NULL);
|
||||
return sign*resistance*den/4;
|
||||
}
|
||||
double native_pipe_flow_cached(NativePipeCache *cache, const NativeMedium *m,
|
||||
double p1, double p2, double T, double d,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "component_constants_internal.h"
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#define RU 8.31446261815324
|
||||
#define MOLAR_MASS 0.004002602
|
||||
@@ -25,6 +26,7 @@ NATIVE_COMPONENT_INTERNAL int same_medium(const NativeMedium *a,const NativeMedi
|
||||
void native_properties_init(NativePropertyCache *cache,NativePropertyState *states,size_t capacity) {
|
||||
cache->states=states;cache->count=0;cache->capacity=states?capacity:0;
|
||||
cache->temperatures=NULL;
|
||||
cache->jacobian=NULL;
|
||||
}
|
||||
static void observe_temperature(NativePropertyTemperatures *report,const NativeMedium *m,double T,unsigned domains) {
|
||||
if(!report || !m->real_helium || !isfinite(T))return;
|
||||
@@ -40,6 +42,7 @@ static NativePropertyState *property_new(NativePropertyCache *cache,const Native
|
||||
NativePropertyState *s=valid && cache && cache->count<cache->capacity ? &cache->states[cache->count++] : scratch;
|
||||
*s=(NativePropertyState){0};s->medium=*m;s->p=p;s->T=T;s->valid=valid?NATIVE_PROPERTY_PT:0;
|
||||
s->temperatures=cache?cache->temperatures:NULL;
|
||||
s->jacobian=cache?cache->jacobian:NULL;
|
||||
return s;
|
||||
}
|
||||
NATIVE_COMPONENT_INTERNAL NativePropertyState *property_pt(NativePropertyCache *cache,const NativeMedium *m,
|
||||
@@ -53,7 +56,14 @@ NATIVE_COMPONENT_INTERNAL NativePropertyState *property_pt(NativePropertyCache *
|
||||
NATIVE_COMPONENT_INTERNAL double property_density(NativePropertyState *s) {
|
||||
observe_temperature(s->temperatures,&s->medium,s->T,1);
|
||||
if(!(s->valid&NATIVE_PROPERTY_RHO)) {
|
||||
s->rho=native_density(&s->medium,s->p,s->T);
|
||||
if(s->jacobian) {
|
||||
const NativeMedium *m=&s->medium;
|
||||
double key[]={s->p,s->T,m->R,m->cp,m->Tref,m->slope,m->mu,m->muT,m->S};
|
||||
if(!native_jacobian_scalar_get(s->jacobian,NATIVE_JACOBIAN_DENSITY,m->real_helium,key,9,&s->rho)) {
|
||||
s->rho=native_density(m,s->p,s->T);
|
||||
native_jacobian_scalar_put(s->jacobian,NATIVE_JACOBIAN_DENSITY,m->real_helium,key,9,s->rho);
|
||||
}
|
||||
} else s->rho=native_density(&s->medium,s->p,s->T);
|
||||
if(s->rho>0 && isfinite(s->rho))s->valid|=NATIVE_PROPERTY_RHO;
|
||||
}
|
||||
return s->rho;
|
||||
@@ -85,7 +95,14 @@ double native_temperature_ph_context(NativePropertyCache *cache,const NativeMedi
|
||||
observe_temperature(cache->temperatures,m,s->T,3);return s->T;
|
||||
}
|
||||
}
|
||||
double T=native_temperature_ph(m,p,h);
|
||||
double T;
|
||||
if(cache && cache->jacobian) {
|
||||
double key[]={p,h,m->R,m->cp,m->Tref,m->slope,m->mu,m->muT,m->S};
|
||||
if(!native_jacobian_scalar_get(cache->jacobian,NATIVE_JACOBIAN_PH,m->real_helium,key,9,&T)) {
|
||||
T=native_temperature_ph(m,p,h);
|
||||
native_jacobian_scalar_put(cache->jacobian,NATIVE_JACOBIAN_PH,m->real_helium,key,9,T);
|
||||
}
|
||||
} else T=native_temperature_ph(m,p,h);
|
||||
observe_temperature(cache?cache->temperatures:NULL,m,T,3);
|
||||
if(cache && isfinite(h) && T>0 && isfinite(T) && p>0 && isfinite(p)) {
|
||||
NativePropertyState scratch,*s=property_pt(cache,m,p,T,&scratch);
|
||||
@@ -345,3 +362,68 @@ int native_polytropic_gas_context(NativePropertyCache *cache,const NativeMedium
|
||||
if(!(g->p>0 && g->rho>0 && isfinite(g->p) && isfinite(g->h) && isfinite(g->u)))return 0;
|
||||
remember_gas(cache,m,g);return 1;
|
||||
}
|
||||
|
||||
int native_jacobian_gas(NativeJacobianGasMemo *memo,NativeCanonicalGas kernel,const NativeMedium *m,
|
||||
double mass,double thermal,double volume,NativeGas *g,NativeJacobianGasStats *stats) {
|
||||
double inputs[]={mass,thermal,volume,m->R,m->cp,m->Tref,m->slope,m->mu,m->muT,m->S};
|
||||
/* Bit keys also distinguish signed zero. No approximate lookup, pointer
|
||||
identity for medium data, or dependence on component names/state slots. */
|
||||
if(memo && memo->valid && memo->kernel==kernel && memo->medium_kind==m->real_helium &&
|
||||
memcmp(memo->inputs,inputs,sizeof(inputs))==0) {
|
||||
*g=memo->value;
|
||||
if(stats)stats->reuses++;
|
||||
return 1;
|
||||
}
|
||||
if(stats)stats->evaluations++;
|
||||
int ok=kernel(NULL,m,mass,thermal,volume,g);
|
||||
if(ok && memo && !memo->valid) {
|
||||
memo->kernel=kernel;memo->medium_kind=m->real_helium;
|
||||
memcpy(memo->inputs,inputs,sizeof(inputs));memo->value=*g;memo->valid=1;
|
||||
}
|
||||
/* A perturbed miss never evicts the unperturbed baseline. Failure is
|
||||
never cached; dense recovery can always evaluate the original kernel. */
|
||||
return ok;
|
||||
}
|
||||
|
||||
static NativeJacobianScalarEntry *jacobian_scalar_slot(NativeJacobianScalars *cache,int kind,int medium_kind,
|
||||
const double *inputs,size_t count,uint64_t *key_hash) {
|
||||
if(!cache || !cache->entries || !cache->capacity || (cache->capacity&(cache->capacity-1)) ||
|
||||
count>NATIVE_JACOBIAN_SCALAR_KEYS || kind<0 || kind>=NATIVE_JACOBIAN_SCALAR_KINDS)return NULL;
|
||||
uint64_t hash=UINT64_C(14695981039346656037)^(unsigned)kind;
|
||||
hash=(hash^(unsigned)medium_kind)*UINT64_C(1099511628211);
|
||||
for(size_t i=0;i<count;i++) {
|
||||
uint64_t bits;memcpy(&bits,&inputs[i],sizeof(bits));
|
||||
hash=(hash^bits)*UINT64_C(1099511628211);hash^=hash>>32;
|
||||
}
|
||||
if(!hash)hash=1;
|
||||
*key_hash=hash;
|
||||
/* A saturated table or an unlucky cluster must not turn every changed
|
||||
input into a scan of the whole cache. Insertion uses this same bound,
|
||||
so every stored entry remains reachable; all other keys fall back. */
|
||||
size_t probe_limit=cache->capacity<32?cache->capacity:32;
|
||||
for(size_t i=0;i<probe_limit;i++) {
|
||||
NativeJacobianScalarEntry *entry=&cache->entries[(hash+i)&(cache->capacity-1)];
|
||||
if(!entry->hash || (entry->hash==hash && entry->kind==kind && entry->medium_kind==medium_kind &&
|
||||
entry->input_count==count && !memcmp(entry->inputs,inputs,count*sizeof(double))))return entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
int native_jacobian_scalar_get(NativeJacobianScalars *cache,int kind,int medium_kind,
|
||||
const double *inputs,size_t count,double *value) {
|
||||
uint64_t hash;
|
||||
NativeJacobianScalarEntry *entry=jacobian_scalar_slot(cache,kind,medium_kind,inputs,count,&hash);
|
||||
if(entry && entry->hash) {
|
||||
*value=entry->value;cache->reuses[kind]++;return 1;
|
||||
}
|
||||
if(cache && kind>=0 && kind<NATIVE_JACOBIAN_SCALAR_KINDS)cache->evaluations[kind]++;
|
||||
return 0;
|
||||
}
|
||||
void native_jacobian_scalar_put(NativeJacobianScalars *cache,int kind,int medium_kind,
|
||||
const double *inputs,size_t count,double value) {
|
||||
if(!cache || !cache->recording || !isfinite(value))return;
|
||||
uint64_t hash;
|
||||
NativeJacobianScalarEntry *entry=jacobian_scalar_slot(cache,kind,medium_kind,inputs,count,&hash);
|
||||
if(!entry || entry->hash)return;
|
||||
entry->hash=hash;entry->kind=kind;entry->medium_kind=medium_kind;entry->input_count=count;
|
||||
memcpy(entry->inputs,inputs,count*sizeof(double));entry->value=value;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef NATIVE_KERNELS_H
|
||||
#define NATIVE_KERNELS_H
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
typedef struct { double p, T, rho, u, h; } NativeGas;
|
||||
typedef struct {
|
||||
int velocity_index;
|
||||
@@ -27,6 +28,7 @@ enum {
|
||||
/* Optional observer for one evaluation, independent of cache capacity.
|
||||
* Slots: EOS, ideal caloric data, dynamic viscosity; each has min/max T. */
|
||||
#define NATIVE_PROPERTY_DOMAINS 3
|
||||
typedef struct NativeJacobianScalars NativeJacobianScalars;
|
||||
typedef struct {
|
||||
unsigned seen;
|
||||
double minimum[NATIVE_PROPERTY_DOMAINS], maximum[NATIVE_PROPERTY_DOMAINS];
|
||||
@@ -36,16 +38,49 @@ typedef struct {
|
||||
double p, T, h, rho, mu, isentropic_factor, isentropic_exponent;
|
||||
unsigned valid;
|
||||
NativePropertyTemperatures *temperatures;
|
||||
NativeJacobianScalars *jacobian;
|
||||
} NativePropertyState;
|
||||
typedef struct {
|
||||
NativePropertyState *states;
|
||||
size_t count, capacity;
|
||||
NativePropertyTemperatures *temperatures;
|
||||
NativeJacobianScalars *jacobian;
|
||||
} NativePropertyCache;
|
||||
void native_properties_init(NativePropertyCache *, NativePropertyState *, size_t capacity);
|
||||
int native_gas_context(NativePropertyCache *, double m, double U, double V, NativeGas *);
|
||||
int native_medium_gas_context(NativePropertyCache *, const NativeMedium *, double m, double U, double V, NativeGas *);
|
||||
int native_polytropic_gas_context(NativePropertyCache *, const NativeMedium *, double mass, double T, double V, NativeGas *);
|
||||
/* Immutable baseline entries owned by ONE Jacobian construction. These
|
||||
* reviewed kernels are deterministic with a NULL property cache: no cache
|
||||
* seeds or temperature observations may be suppressed by a hit. */
|
||||
typedef int (*NativeCanonicalGas)(NativePropertyCache *,const NativeMedium *,double,double,double,NativeGas *);
|
||||
typedef struct {
|
||||
NativeCanonicalGas kernel;
|
||||
double inputs[10]; /* mass, thermal state, volume, and every medium double */
|
||||
NativeGas value;
|
||||
int medium_kind, valid;
|
||||
} NativeJacobianGasMemo;
|
||||
typedef struct { unsigned long evaluations, reuses; } NativeJacobianGasStats;
|
||||
int native_jacobian_gas(NativeJacobianGasMemo *,NativeCanonicalGas,const NativeMedium *,
|
||||
double mass,double thermal,double volume,NativeGas *,NativeJacobianGasStats *);
|
||||
enum { NATIVE_JACOBIAN_PH, NATIVE_JACOBIAN_DENSITY, NATIVE_JACOBIAN_PIPE, NATIVE_JACOBIAN_SCALAR_KINDS };
|
||||
#define NATIVE_JACOBIAN_SCALAR_KEYS 10
|
||||
typedef struct {
|
||||
uint64_t hash;
|
||||
double inputs[NATIVE_JACOBIAN_SCALAR_KEYS], value;
|
||||
int kind, medium_kind;
|
||||
size_t input_count;
|
||||
} NativeJacobianScalarEntry;
|
||||
struct NativeJacobianScalars {
|
||||
NativeJacobianScalarEntry *entries;
|
||||
size_t capacity; /* power of two; zero disables the optional cache */
|
||||
int recording;
|
||||
unsigned long evaluations[NATIVE_JACOBIAN_SCALAR_KINDS], reuses[NATIVE_JACOBIAN_SCALAR_KINDS];
|
||||
};
|
||||
int native_jacobian_scalar_get(NativeJacobianScalars *,int kind,int medium_kind,
|
||||
const double *inputs,size_t count,double *value);
|
||||
void native_jacobian_scalar_put(NativeJacobianScalars *,int kind,int medium_kind,
|
||||
const double *inputs,size_t count,double value);
|
||||
double native_temperature_ph_context(NativePropertyCache *, const NativeMedium *, double p, double h);
|
||||
double native_density_context(NativePropertyCache *, const NativeMedium *, double p, double T);
|
||||
int native_orifice_context(NativePropertyCache *, double p1, double p2, double h1, double h2,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#ifndef NFRICTIONS
|
||||
#define NFRICTIONS 0
|
||||
#endif
|
||||
#define NATIVE_JACOBIAN_STATS_COUNT 3
|
||||
typedef struct {
|
||||
double start, stop, sample_step, max_step, rtol, timeout;
|
||||
int bdf, record_samples;
|
||||
@@ -33,6 +34,9 @@ typedef struct {
|
||||
int jacobian_verify, jacobian_colored;
|
||||
unsigned long jacobian_rhs, jacobian_colored_evals, jacobian_fallbacks;
|
||||
unsigned long jacobian_checks, jacobian_mismatches, cvode_rhs, linear_rhs;
|
||||
unsigned long jacobian_gas_evaluations, jacobian_gas_reuses;
|
||||
/* PH, density, pipe. Keep runtime-only harnesses independent of kernels.h. */
|
||||
unsigned long jacobian_scalar_evaluations[NATIVE_JACOBIAN_STATS_COUNT], jacobian_scalar_reuses[NATIVE_JACOBIAN_STATS_COUNT];
|
||||
unsigned long same_time_returns, same_time_streak, max_same_time_streak;
|
||||
int stagnating, cvode_flag;
|
||||
double cvode_return_time, cvode_internal_time, cvode_last_step, cvode_next_step;
|
||||
|
||||
@@ -11,11 +11,15 @@
|
||||
#include <sunlinsol/sunlinsol_dense.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sundials/sundials_math.h>
|
||||
#ifndef MODEL_JACOBIAN_COLORED
|
||||
#define MODEL_JACOBIAN_COLORED 0
|
||||
#endif
|
||||
#ifndef MODEL_JACOBIAN_GAS_REUSE
|
||||
#define MODEL_JACOBIAN_GAS_REUSE 0
|
||||
#endif
|
||||
|
||||
typedef struct { void *solver; N_Vector scratch; } CvDense;
|
||||
static int cv_dense(void *context, double t, double *out) {
|
||||
@@ -30,6 +34,9 @@ typedef struct {
|
||||
N_Vector weights;
|
||||
SUNMatrix reference;
|
||||
int colored;
|
||||
#if MODEL_JACOBIAN_GAS_REUSE
|
||||
ModelJacobianWorkspace *jacobian_workspace;
|
||||
#endif
|
||||
} CvContext;
|
||||
static int cv_rhs(sunrealtype t, N_Vector y, N_Vector dy, void *context) {
|
||||
NativeRun *r=((CvContext *)context)->run;
|
||||
@@ -76,6 +83,28 @@ static int jac_rhs(CvContext *context, sunrealtype t, N_Vector y, N_Vector f) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MODEL_JACOBIAN_GAS_REUSE
|
||||
_Static_assert(NATIVE_JACOBIAN_STATS_COUNT==NATIVE_JACOBIAN_SCALAR_KINDS,"Jacobian counter layout must match the kernel tags");
|
||||
static int jac_rhs_reuse(CvContext *context,sunrealtype t,N_Vector y,N_Vector f) {
|
||||
if(!context->jacobian_workspace)return jac_rhs(context,t,y,f);
|
||||
NativeRun *r=context->run;
|
||||
if(!native_poll(r,r->final_time))return -1;
|
||||
r->jacobian_rhs++;r->nfev++;
|
||||
ModelJacobianWorkspace *workspace=context->jacobian_workspace;
|
||||
NativeJacobianGasStats before=workspace->stats;
|
||||
NativeJacobianScalars scalar_before=workspace->scalars;
|
||||
double outputs[NOUTPUTS];
|
||||
int ok=model_eval_jacobian_reuse(t,N_VGetArrayPointer(y),N_VGetArrayPointer(f),outputs,workspace);
|
||||
r->jacobian_gas_evaluations+=workspace->stats.evaluations-before.evaluations;
|
||||
r->jacobian_gas_reuses+=workspace->stats.reuses-before.reuses;
|
||||
for(int i=0;i<NATIVE_JACOBIAN_SCALAR_KINDS;i++) {
|
||||
r->jacobian_scalar_evaluations[i]+=workspace->scalars.evaluations[i]-scalar_before.evaluations[i];
|
||||
r->jacobian_scalar_reuses[i]+=workspace->scalars.reuses[i]-scalar_before.reuses[i];
|
||||
}
|
||||
return ok?0:1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Same perturbation and reciprocal-multiply order as SUNDIALS 7.4 dense DQ.
|
||||
* No constraints are set by this runtime. If that changes, carry their vector
|
||||
* into this context and apply CVODE's sign rule before enabling coloring. */
|
||||
@@ -119,7 +148,11 @@ static int colored_difference(CvContext *context, sunrealtype t, N_Vector y, N_V
|
||||
for (int color=0;color<MODEL_JACOBIAN_COLOR_COUNT;color++) {
|
||||
memcpy(test,state,NSTATES*sizeof(double));
|
||||
for (int j=0;j<NSTATES;j++) if (model_jacobian_column_color[j]==color) test[j]+=increments[j];
|
||||
#if MODEL_JACOBIAN_GAS_REUSE
|
||||
int flag=jac_rhs_reuse(context,t,trial,ftrial);
|
||||
#else
|
||||
int flag=jac_rhs(context,t,trial,ftrial);
|
||||
#endif
|
||||
if (flag) return flag;
|
||||
for (int j=0;j<NSTATES;j++) if (model_jacobian_column_color[j]==color) {
|
||||
double inverse=1.0/increments[j];
|
||||
@@ -146,7 +179,16 @@ static int cv_jacobian(sunrealtype t, N_Vector y, N_Vector fy, SUNMatrix matrix,
|
||||
/* The CVODE fy belongs to the ordinary RHS cache path. Recompute the
|
||||
baseline using the same deterministic path as every perturbed probe;
|
||||
mixing the two baselines would amplify cache roundoff by 1/increment. */
|
||||
#if MODEL_JACOBIAN_GAS_REUSE
|
||||
/* The baseline belongs only to this refresh. Events, later Newton
|
||||
iterations and another run must never inherit any of these entries. */
|
||||
if(context->colored) {
|
||||
if(context->jacobian_workspace)model_jacobian_begin(context->jacobian_workspace);
|
||||
flag=jac_rhs_reuse(context,t,y,tmp3);
|
||||
} else flag=jac_rhs(context,t,y,tmp3);
|
||||
#else
|
||||
flag=jac_rhs(context,t,y,tmp3);
|
||||
#endif
|
||||
if (flag) return flag;
|
||||
fy=tmp3;
|
||||
#endif
|
||||
@@ -245,6 +287,11 @@ int native_bdf(NativeRun *r) {
|
||||
CV_CHECK(CVodeSetMaxStep(solver,r->options.max_step));
|
||||
#if MODEL_JACOBIAN_COLORED
|
||||
if (valid_coloring()) {
|
||||
#if MODEL_JACOBIAN_GAS_REUSE
|
||||
/* Optional, caller-owned scratch. Allocation failure keeps the
|
||||
original canonical differences; large models do not grow stack. */
|
||||
context.jacobian_workspace=malloc(sizeof(*context.jacobian_workspace));
|
||||
#endif
|
||||
context.weights=N_VClone(y);
|
||||
allocation="N_VClone";
|
||||
if (!context.weights) goto allocation_failure;
|
||||
@@ -339,6 +386,9 @@ int native_bdf(NativeRun *r) {
|
||||
allocation_failure:
|
||||
native_fail(r,"allocation-failure",allocation,"Cannot allocate native solver resources.");
|
||||
cleanup:
|
||||
#if MODEL_JACOBIAN_GAS_REUSE
|
||||
free(context.jacobian_workspace);
|
||||
#endif
|
||||
if (initialized) cv_snapshot(r,solver);
|
||||
if (solver) { counters(r,solver); CVodeFree(&solver); }
|
||||
if (context.reference) SUNMatDestroy(context.reference);
|
||||
|
||||
@@ -52,6 +52,12 @@ static int write_result(NativeRun *r, const char *path, const char *index_path)
|
||||
json_string(f,r->status==0?"completed":r->status==1?"cancelled":"failed");
|
||||
fprintf(f,",\"message\":"); json_string(f,r->message);
|
||||
fprintf(f,",\"propertyWarnings\":"); native_property_warnings_json(r,f);
|
||||
fprintf(f,",\"jacobianReuse\":{\"gasEvaluations\":%lu,\"gasReuses\":%lu",
|
||||
r->jacobian_gas_evaluations,r->jacobian_gas_reuses);
|
||||
const char *reuse_names[]={"ph","density","pipe"};
|
||||
for(int i=0;i<NATIVE_JACOBIAN_SCALAR_KINDS;i++)
|
||||
fprintf(f,",\"%sEvaluations\":%lu,\"%sReuses\":%lu",reuse_names[i],r->jacobian_scalar_evaluations[i],reuse_names[i],r->jacobian_scalar_reuses[i]);
|
||||
fputc('}',f);
|
||||
fprintf(f,",\"solverControl\":{\"reason\":"); json_string(f,r->failure_reason?r->failure_reason:"");
|
||||
fprintf(f,",\"operation\":"); json_string(f,r->failure_operation?r->failure_operation:"");
|
||||
fprintf(f,",\"returnCode\":%d,\"sameTimeReturns\":%lu,\"maxSameTimeStreak\":%lu",
|
||||
|
||||
Reference in new issue
Block a user