#include "runtime.h" #include "json_numbers.h" #include #include #include #include #include static void json_string(FILE *f, const char *value) { fputc('"',f); for (const unsigned char *p=(const unsigned char *)value; *p; p++) { if (*p=='"' || *p=='\\') { fputc('\\',f); fputc(*p,f); } else if (*p<32) fprintf(f,"\\u%04x",*p); else fputc(*p,f); } fputc('"',f); } static void vector(FILE *f, const double *value, int count) { fputc('[',f); for (int i=0;i=0; if(ferror(index)) ok=0; if(fclose(index)) ok=0; return ok; } static int write_result(NativeRun *r, const char *path, const char *index_path) { if(index_path && !strcmp(path,index_path)) return 0; double dy[NSTATES], final[NOUTPUTS]; int final_ok=model_eval(r->final_time,r->final_state,dy,final); if (!native_samples_outputs(r)) return 0; FILE *f=fopen(path,"wb"); if (!f) return 0; fprintf(f,"{\"success\":%s,\"status\":",!r->status?"true":"false"); json_string(f,r->status==0?"completed":r->status==1?"cancelled":"failed"); fprintf(f,",\"message\":"); json_string(f,r->message); fprintf(f,",\"contactEvents\":{\"checks\":%lu,\"denseCalls\":%lu,\"rootIterations\":%lu,\"transitions\":%lu,\"forceClipTransitions\":%lu}", r->contact_checks,r->contact_dense,r->contact_roots,r->contact_transitions,r->contact_clipping); fprintf(f,",\"propertyWarnings\":"); native_property_warnings_json(r,f); fputs(",\"outputSemantics\":{\"version\":2," "\"regularSamples\":\"actual-time-no-snap\"," "\"internalTimeEvents\":\"left-adjacent-and-at-event\"," "\"stateEvents\":\"left-adjacent-when-available-and-post-reset\"," "\"sameTime\":\"last-accepted-state\"," "\"replay\":\"saved-time-and-state-including-discrete-modes\"}",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;ijacobian_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", r->cvode_flag,r->same_time_returns,r->max_same_time_streak); const char *names[]={"returnTime","internalTime","lastStep","nextStep"}; double diagnostic[]={r->cvode_return_time,r->cvode_internal_time,r->cvode_last_step,r->cvode_next_step}; for(int i=0;i<4;i++) { fprintf(f,",\"%s\":",names[i]); if(isfinite(diagnostic[i])) fprintf(f,"%.17g",diagnostic[i]); else fputs("null",f); } fputc('}',f); fprintf(f,",\"jacobianMode\":\"%s\",\"jacobianRhsCalls\":%lu," "\"jacobianColoredEvals\":%lu,\"jacobianFallbacks\":%lu," "\"jacobianChecks\":%lu,\"jacobianMismatches\":%lu," "\"cvodeRhsCalls\":%lu,\"cvodeLinearRhsCalls\":%lu", !r->options.bdf?"not-used":r->jacobian_colored?"colored-difference":"dense-difference", r->jacobian_rhs,r->jacobian_colored_evals,r->jacobian_fallbacks, r->jacobian_checks,r->jacobian_mismatches,r->cvode_rhs,r->linear_rhs); fprintf(f,",\"backend\":\"native-c\",\"method\":\"%s\",\"solver\":\"%s\",\"sundialsVersion\":\"%s\"," "\"simulatedUntil\":%.17g,\"solveSeconds\":%.17g,\"solveCpuSeconds\":%.17g," "\"nfev\":%lu,\"acceptedSteps\":%lu,\"rejectedSteps\":%lu,\"stateTransitions\":%lu," "\"solverStarts\":%lu,\"njev\":%lu,\"nlu\":%lu,\"maxAcceptedStep\":%.17g,\"series\":{", r->options.bdf?"BDF":"RK45",r->options.bdf?"CVODE":"Dormand-Prince 5(4)",SUNDIALS_VERSION, r->final_time,r->solve_seconds,r->solve_cpu_seconds,r->nfev,r->accepted,r->rejected, r->events,r->starts,r->njev,r->nlu,r->max_accepted_step); /* Binary-mode positions delimit the complete series object, including both braces. The optional index avoids scanning or parsing its values. */ int64_t series_start=-1,series_end=-1,result_bytes=-1; if(index_path) { series_start=native_file_tell(f); if(series_start>0) series_start--; else series_start=-1; } int output_ok=1; if (r->count) { fprintf(f,"\"time\":"); output_ok=native_samples_json(r,f,0); for (int j=0;jfinal_state,NSTATES,1); fprintf(f,"}\n"); int ok=output_ok && !ferror(f); if(index_path) { result_bytes=native_file_tell(f); if(series_start<0 || series_end<0 || result_bytes<0) ok=0; } if (fclose(f)) ok=0; /* Publish the index only after the complete result was successfully flushed and closed. An index I/O failure is a failed result write. */ if(ok && index_path) ok=write_result_index(index_path,series_start,series_end,result_bytes,r->count); return ok; } int main(int argc, char **argv) { NativeRun r={0}; r.options=(NativeOptions){0,10,.02,.001,1e-6,300,0,1,NULL}; const char *output="result.json", *index_path=NULL; for (int i=1;ir.options.start && r.options.sample_step>0 && r.options.max_step>0 && r.options.rtol>0 && r.options.timeout>0) || r.options.start+r.options.sample_step==r.options.start || r.options.start+r.options.max_step==r.options.start || !isfinite(r.options.stop-r.options.start)) return 64; if (r.options.record_samples && ((r.options.stop-r.options.start)/r.options.sample_step>1000000)) return 64; native_solve(&r); int saved=write_result(&r,output,index_path); int code=saved?(r.status==2?2:0):3; native_run_free(&r); return code; }