相较上一版 Jacobian 确定性复用更新,本次补齐事件边界一致性、结果两侧采样及接触事件定位;保留已有物性复用和组件力学公式。 - 统一 UD00 信号求值与下一事件查询的绝对时间边界,修复循环边界浮点舍入导致的阶段错位、重复或漏报,并覆盖零时长、多阶段及长周期场景。 - 引入原生输出语义 v2:保留规则网格真实时间,补充内部时间事件和状态事件的左邻及事件后采样,按保存时间、状态和离散模式重放结果。 - 两条代码生成路径均发出 LSTP 接触描述,默认定位间隙过零及非负力模式的力截断;仅在接受事件时更新防重复记录,增加 contactEvents 诊断计数。 - 补充 MASS/LSTP 独立事件实验、八路全曲线与驱动阶段配对评估,以及 Amesim 不连续点输出对照和力差定位报告;MASS 新增释放机制仍保留为独立实验。 - 保存局部 probe、context 访问与回退、shadow replay、R288 real skip/typed replay 及阀门数值尾部诊断工具和报告;未证明净收益的实验不启用为生产默认优化。 - 更新原生运行说明和元件建模规范,补充信号边界、输出语义、接触事件和实验依赖回归测试。 验证:五组专项回归共 34 项全部通过;37 个待提交 Python 文件语法检查通过;git diff --cached --check 通过。
134 lines
8.4 KiB
C
134 lines
8.4 KiB
C
/* Standalone experiment support; never linked by the production builder. */
|
|
#define _WIN32_WINNT 0x0600
|
|
#include "local_probe.h"
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
/* GENERATED_TABLES */
|
|
|
|
int lp_color=-1,lp_active=-1,lp_capture=0,lp_observe=LP_OBSERVE;
|
|
uint64_t lp_mask;
|
|
typedef struct {
|
|
size_t count,capacity;
|
|
NativePropertyTemperatures *temperatures;
|
|
NativeJacobianScalars *jacobian;
|
|
NativePropertyState states[LP_NPS];
|
|
NativePipeCache pipes[LP_NPC];
|
|
} Snapshot;
|
|
typedef struct {
|
|
Snapshot snapshots[LP_NB];
|
|
double p[LP_NP],h[LP_NQ],q[LP_NQ],w[NOUTPUTS],fb[LP_NFB];
|
|
double t,y[NSTATES];int ready;
|
|
} Workspace;
|
|
static Workspace *saved;
|
|
static unsigned char needed[LP_NB],captured[LP_NB];
|
|
static FILE *matrix_file,*event_file;
|
|
static uint64_t frequency,jac_ticks,jac_calls,newton_iterations,newton_failures,audit_count,audit_diff;
|
|
static uint64_t executed[LP_NC][LP_NO],skipped[LP_NC][LP_NO],kernel_calls[LP_NC+1][LP_NK];
|
|
static uint64_t attempts[LP_NC],hits[LP_NC],context_misses[LP_NC],invalid_trials[LP_NC];
|
|
static uint64_t compared_bytes,copied_bytes,model_calls[LP_NC+1];
|
|
|
|
uint64_t lp_tick(void){LARGE_INTEGER t;QueryPerformanceCounter(&t);return (uint64_t)t.QuadPart;}
|
|
void lp_jac_time(uint64_t start){jac_ticks+=lp_tick()-start;jac_calls++;}
|
|
void lp_newton(long iterations,long failures){newton_iterations+=(uint64_t)iterations;newton_failures+=(uint64_t)failures;}
|
|
void lp_start(void){
|
|
LARGE_INTEGER f;QueryPerformanceFrequency(&f);frequency=(uint64_t)f.QuadPart;
|
|
const char *mask=getenv("LOCAL_PROBE_MASK");lp_mask=mask?strtoull(mask,NULL,0):0;
|
|
if(lp_mask){saved=calloc(1,sizeof(*saved));if(!saved){fprintf(stderr,"local probe workspace allocation failed\n");abort();}}
|
|
for(int g=0;g<LP_NC;g++)if(lp_mask&(UINT64_C(1)<<g))for(int pos=0;pos<LP_NO;pos++){
|
|
int r=lp_plan[g][pos];if(r>=0){needed[lp_before[r]]=1;needed[lp_after[r]]=1;}
|
|
}
|
|
event_file=fopen("events.bin","wb");if(!event_file)abort();
|
|
if(lp_observe){matrix_file=fopen("jacobians.bin","wb");if(!matrix_file)abort();setvbuf(matrix_file,NULL,_IOFBF,1024*1024);}
|
|
}
|
|
void lp_begin(double t,const double *y){
|
|
if(saved){saved->ready=0;saved->t=t;memcpy(saved->y,y,sizeof(saved->y));memset(captured,0,sizeof(captured));}
|
|
}
|
|
void lp_ready(int ok){if(saved)saved->ready=ok;}
|
|
int lp_valid(double t,const double *y){
|
|
if(!saved || !saved->ready || memcmp(&t,&saved->t,sizeof(double)))return 0;
|
|
for(int i=0;i<NSTATES;i++)if(lp_colors[i]!=lp_color && memcmp(y+i,saved->y+i,sizeof(double))){invalid_trials[lp_color]++;return 0;}
|
|
return 1;
|
|
}
|
|
void lp_snapshot(int index,NativePropertyCache *properties,NativePipeCache *pipes){
|
|
if(!needed[index] || captured[index])return;
|
|
captured[index]=1;
|
|
Snapshot *s=&saved->snapshots[index];
|
|
if(properties->count>LP_NPS || properties->capacity!=LP_NPS || properties->temperatures){fprintf(stderr,"unsupported local property context\n");abort();}
|
|
s->count=properties->count;s->capacity=properties->capacity;s->temperatures=properties->temperatures;s->jacobian=properties->jacobian;
|
|
memcpy(s->states,properties->states,s->count*sizeof(*s->states));memcpy(s->pipes,pipes,sizeof(s->pipes));
|
|
copied_bytes+=s->count*sizeof(*s->states)+sizeof(s->pipes);
|
|
}
|
|
void lp_save(double *p,double *h,double *q,double *w,double *fb){
|
|
memcpy(saved->p,p,sizeof(saved->p));memcpy(saved->h,h,sizeof(saved->h));memcpy(saved->q,q,sizeof(saved->q));
|
|
memcpy(saved->w,w,sizeof(saved->w));memcpy(saved->fb,fb,sizeof(saved->fb));
|
|
}
|
|
int lp_reuse(int region,NativePropertyCache *properties,NativePipeCache *pipes,double *p,double *h,double *q,double *w,double *fb){
|
|
Snapshot *before=&saved->snapshots[lp_before[region]],*after=&saved->snapshots[lp_after[region]];
|
|
attempts[lp_color]++;
|
|
int contextual=lp_before[region]!=lp_after[region];
|
|
if(contextual && (properties->count!=before->count || properties->capacity!=before->capacity ||
|
|
properties->temperatures!=before->temperatures || properties->jacobian!=before->jacobian)){context_misses[lp_color]++;return 0;}
|
|
size_t n=before->count*sizeof(*before->states);
|
|
if(contextual){compared_bytes+=n+sizeof(before->pipes);
|
|
if(memcmp(properties->states,before->states,n) || memcmp(pipes,before->pipes,sizeof(before->pipes))){context_misses[lp_color]++;return 0;}
|
|
}
|
|
/* Preserve the exact baseline cache mutations, including seeded rho/h and
|
|
computed isentropic fields; never synthesize a context from (p,T) alone.
|
|
Jacobian scalar entries are immutable after baseline; only their telemetry
|
|
counters differ when actual kernel requests are avoided. */
|
|
if(contextual){properties->count=after->count;
|
|
memcpy(properties->states,after->states,after->count*sizeof(*after->states));memcpy(pipes,after->pipes,sizeof(after->pipes));
|
|
copied_bytes+=after->count*sizeof(*after->states)+sizeof(after->pipes);
|
|
}
|
|
double *dst[]={p,h,q,w,fb};double *src[]={saved->p,saved->h,saved->q,saved->w,saved->fb};
|
|
for(int i=lp_first_output[region];i<lp_last_output[region];i++)dst[lp_output_map[i][0]][lp_output_map[i][1]]=src[lp_output_map[i][0]][lp_output_map[i][1]];
|
|
hits[lp_color]++;
|
|
if(LP_OBSERVE)for(int i=lp_start_op[region];i<lp_end[region];i++)skipped[lp_color][lp_operation_id[i]]++;
|
|
return 1;
|
|
}
|
|
#if LP_OBSERVE
|
|
void lp_operation(int position){if(lp_active>0)executed[lp_active-1][lp_operation_id[position]]++;}
|
|
#endif
|
|
void lp_kernel(int kind){if(lp_active>=0 && lp_active<=LP_NC)kernel_calls[lp_active][kind]++;}
|
|
void lp_compare(int ok,const double *dy,const double *w,int expected_ok,const double *expected_dy,const double *expected_w){
|
|
audit_count++;
|
|
if(ok!=expected_ok || (ok && (memcmp(dy,expected_dy,NSTATES*sizeof(double)) || memcmp(w,expected_w,NOUTPUTS*sizeof(double))))){
|
|
audit_diff++;fprintf(stderr,"probe exact mismatch color=%d comparison=%llu\n",lp_color,(unsigned long long)audit_count);
|
|
for(int i=0;i<NSTATES;i++)if(memcmp(dy+i,expected_dy+i,8))fprintf(stderr,"dy[%d] %.17g != %.17g\n",i,dy[i],expected_dy[i]);
|
|
for(int i=0;i<NOUTPUTS;i++)if(memcmp(w+i,expected_w+i,8))fprintf(stderr,"w[%d] %.17g != %.17g\n",i,w[i],expected_w[i]);
|
|
abort();
|
|
}
|
|
}
|
|
void lp_matrix(double t,const double *y,const double *matrix){
|
|
if(matrix_file){fwrite(&t,8,1,matrix_file);fwrite(y,8,NSTATES,matrix_file);fwrite(matrix,8,NSTATES*NSTATES,matrix_file);}
|
|
}
|
|
void lp_event(double t,const double *y){if(event_file){fwrite(&t,8,1,event_file);fwrite(y,8,NSTATES,event_file);}}
|
|
void lp_note_eval(int local){
|
|
model_calls[lp_color+1]++;
|
|
/* Reference/disabled/invalid evaluations run every original operation. */
|
|
if(LP_OBSERVE && lp_color>=0 && !local)for(int i=0;i<LP_NO;i++)executed[lp_color][i]++;
|
|
}
|
|
static void vector(FILE *f,const uint64_t *a,int n){
|
|
fputc('[',f);for(int i=0;i<n;i++){fprintf(f,"%s%llu",i?",":"",(unsigned long long)a[i]);}fputc(']',f);
|
|
}
|
|
void lp_finish(void){
|
|
if(matrix_file){fclose(matrix_file);matrix_file=NULL;}if(event_file){fclose(event_file);event_file=NULL;}
|
|
FILE *f=fopen("probe.json","wb");if(!f)abort();
|
|
fprintf(f,"{\"mask\":%llu,\"workspaceBytes\":%llu,\"jacobianCalls\":%llu,\"jacobianSeconds\":%.9f,\"newtonIterations\":%llu,\"newtonConvergenceFailures\":%llu,\"auditComparisons\":%llu,\"auditDifferences\":%llu,\"contextComparedBytes\":%llu,\"contextCopiedBytes\":%llu,\"modelCalls\":",
|
|
(unsigned long long)lp_mask,(unsigned long long)(saved?sizeof(*saved):0),(unsigned long long)jac_calls,(double)jac_ticks/frequency,
|
|
(unsigned long long)newton_iterations,(unsigned long long)newton_failures,(unsigned long long)audit_count,(unsigned long long)audit_diff,
|
|
(unsigned long long)compared_bytes,(unsigned long long)copied_bytes);
|
|
vector(f,model_calls,LP_NC+1);fprintf(f,",\"groups\":[");
|
|
for(int g=0;g<LP_NC;g++){
|
|
fprintf(f,"%s{\"color\":%d,\"attempts\":%llu,\"hits\":%llu,\"contextMisses\":%llu,\"invalidTrials\":%llu,\"executed\":",g?",":"",g,(unsigned long long)attempts[g],(unsigned long long)hits[g],(unsigned long long)context_misses[g],(unsigned long long)invalid_trials[g]);
|
|
vector(f,executed[g],LP_NO);fprintf(f,",\"skipped\":");vector(f,skipped[g],LP_NO);fprintf(f,"}");
|
|
}
|
|
fprintf(f,"],\"kernelNames\":[");for(int i=0;i<LP_NK;i++){fprintf(f,"%s\"%s\"",i?",":"",lp_kernel_names[i]);}
|
|
fprintf(f,"],\"kernelCalls\":[");for(int g=0;g<=LP_NC;g++){if(g)fputc(',',f);vector(f,kernel_calls[g],LP_NK);}fprintf(f,"]}\n");fclose(f);
|
|
free(saved);saved=NULL;lp_mask=0;
|
|
}
|