#include "runtime.h" #include #include #include #include #include #ifdef _WIN32 #include #endif double native_wall_time(void) { #ifdef _WIN32 LARGE_INTEGER value, frequency; QueryPerformanceCounter(&value); QueryPerformanceFrequency(&frequency); return (double)value.QuadPart / (double)frequency.QuadPart; #else struct timespec value; clock_gettime(CLOCK_MONOTONIC, &value); return value.tv_sec + value.tv_nsec*1e-9; #endif } double native_cpu_time(void) { #ifdef _WIN32 FILETIME creation, exit_time, kernel, user; GetProcessTimes(GetCurrentProcess(), &creation, &exit_time, &kernel, &user); ULARGE_INTEGER k, u; k.LowPart=kernel.dwLowDateTime; k.HighPart=kernel.dwHighDateTime; u.LowPart=user.dwLowDateTime; u.HighPart=user.dwHighDateTime; return (double)(k.QuadPart+u.QuadPart)*1e-7; #else return (double)clock()/CLOCKS_PER_SEC; #endif } int native_poll(NativeRun *r, double t) { double now=native_wall_time(); if (r->status) return 0; if (r->options.timeout > 0 && now-r->wall_start > r->options.timeout) { r->status=2; r->message="Native solve exceeded its time limit."; return 0; } if (now-r->last_progress >= 0.1) { r->last_progress=now; if (r->options.cancel_path) { FILE *f=fopen(r->options.cancel_path,"rb"); if (f) { fclose(f); r->status=1; r->message="Simulation cancelled."; return 0; } } fprintf(stderr,"{\"phase\":\"integrating\",\"time\":%.17g,\"nfev\":%lu,\"acceptedSteps\":%lu}\n",t,r->nfev,r->accepted); fflush(stderr); } return 1; } int native_rhs(NativeRun *r, double t, const double *y, double *dy) { double w[NOUTPUTS]; r->nfev++; return model_eval(t,y,dy,w); } int native_append(NativeRun *r, double t, const double *y) { r->final_time=t; memcpy(r->final_state,y,NSTATES*sizeof(double)); if (!r->options.record_samples) return 1; if (r->count && r->times[r->count-1] == t) r->count--; if (r->count == r->capacity) { size_t cap=r->capacity ? r->capacity*2 : 1024; if (cap > 2000000 || cap > 268435456u / NSTATES / sizeof(double)) return 0; double *times=realloc(r->times,cap*sizeof(double)); if (!times) return 0; r->times=times; double *states=realloc(r->states,cap*NSTATES*sizeof(double)); if (!states) return 0; r->states=states; r->capacity=cap; } r->times[r->count]=t; memcpy(r->states+r->count*NSTATES,y,NSTATES*sizeof(double)); r->count++; return 1; } static double locate(int idx, double bound, int lower, double left, double right, NativeDense dense, void *context) { double state[NSTATES]; for (int i=0;i<60;i++) { double mid=.5*(left+right); if (!dense(context,mid,state)) return NAN; if (lower ? state[idx] <= bound : state[idx] >= bound) right=mid; else left=mid; } return right; } int native_accept(NativeRun *r, double t, double next, const double *old, const double *trial, NativeDense dense, void *context, double *accepted_time, double *accepted_state) { double when[2*(NSTOPS+1)], bounds[2*(NSTOPS+1)]; double restitution[2*(NSTOPS+1)], thresholds[2*(NSTOPS+1)]; int indices[2*(NSTOPS+1)], count=0; for (int j=0;j=bound-tol && old[v]>vt0)) at=t; else if (lower ? (old[x]>bound+tol && trial[x]<=bound) : (old[x]=bound)) at=locate(x,bound,lower,t,next,dense,context); else if (lower ? (old[x]<=bound && old[v]>vt0 && trial[v]<-vt1 && trial[x]<=bound) : (old[x]>=bound && old[v]<-vt0 && trial[v]>vt1 && trial[x]>=bound)) { double turn=locate(v,0,lower,t,next,dense,context); at=locate(x,bound,lower,turn,next,dense,context); } if (isfinite(at)) { when[count]=at; bounds[count]=bound; indices[count]=v; restitution[count]=lower?s.lower_restitution:s.upper_restitution; thresholds[count]=lower?s.lower_threshold:s.upper_threshold; count++; } } } double stop=next; for (int i=0;ioptions.record_samples) { double st=r->options.start+r->sample_index*r->options.sample_step; while (st<=r->options.stop && (count ? stsample_index++; st=r->options.start+r->sample_index*r->options.sample_step; } } if (count) { if (!dense(context,stop,accepted_state)) return -1; for (int i=0;ioptions.start+r->sample_index*r->options.sample_step<=stop) r->sample_index++; r->events++; } else memcpy(accepted_state,trial,NSTATES*sizeof(double)); *accepted_time=stop; r->final_time=stop; memcpy(r->final_state,accepted_state,NSTATES*sizeof(double)); return count ? 1 : 0; } int native_solve(NativeRun *r) { double y[NSTATES]; if (!model_init(y)) { r->status=2; r->message="Native model initialization failed."; return 0; } r->sample_index=1; if (!native_append(r,r->options.start,y)) { r->status=2; r->message="Cannot allocate samples."; return 0; } r->wall_start=native_wall_time(); r->cpu_start=native_cpu_time(); r->last_progress=r->wall_start-1; int ok=r->options.bdf ? native_bdf(r) : native_rk45(r); r->solve_seconds=native_wall_time()-r->wall_start; r->solve_cpu_seconds=native_cpu_time()-r->cpu_start; if (!ok && !r->status) { r->status=2; r->message="Native integration failed to advance."; } if (!native_append(r,r->final_time,r->final_state)) { r->status=2; r->message="Cannot save final state."; } if (!r->message) r->message=r->status ? "Native integration failed." : "Simulation completed."; return !r->status; } void native_run_free(NativeRun *r) { free(r->times); free(r->states); }