优化 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,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;
|
||||
}
|
||||
Reference in new issue
Block a user