Allow the Lyapunov computation to be interrupted

This commit is contained in:
Ian Jauslin 2025-01-31 21:58:54 -05:00
parent 53a0a0ae4c
commit 06e5b0e0da
5 changed files with 217 additions and 15 deletions

View File

@ -51,6 +51,30 @@ int write_vec_bin(_Complex double* vec, int K1, int K2, FILE* file){
return 0; return 0;
} }
// write complex vector (stored as 2 doubles) indexed by k1,k2 to file in binary format
int write_vec2_bin(double* vec, int K1, int K2, FILE* file){
// do nothing if there is no file
if(file==NULL){
return 0;
}
fwrite(vec, sizeof(double), 2*K1*(2*K2+1)+K2, file);
return 0;
}
// write complex matrix (stored as 2 doubles) indexed by k1,k2 to file in binary format
int write_mat2_bin(double* mat, int K1, int K2, FILE* file){
// do nothing if there is no file
if(file==NULL){
return 0;
}
fwrite(mat, sizeof(double), 4*(K1*(2*K2+1)+K2)*(K1*(2*K2+1)+K2), file);
return 0;
}
// read complex vector indexed by k1,k2 from file // read complex vector indexed by k1,k2 from file
int read_vec(_Complex double* out, int K1, int K2, FILE* file){ int read_vec(_Complex double* out, int K1, int K2, FILE* file){
int kx,ky; int kx,ky;
@ -149,15 +173,53 @@ int read_vec(_Complex double* out, int K1, int K2, FILE* file){
// read complex vector indexed by k1,k2 from file in binary format // read complex vector indexed by k1,k2 from file in binary format
int read_vec_bin(_Complex double* out, int K1, int K2, FILE* file){ int read_vec_bin(_Complex double* out, int K1, int K2, FILE* file){
char c;
int ret;
// do nothing if there is no file // do nothing if there is no file
if(file==NULL){ if(file==NULL){
return 0; return 0;
} }
// seek past initial comments // seek past initial comments
seek_past_initial_comments(file);
fread(out, sizeof(_Complex double), K1*(2*K2+1)+K2, file);
return 0;
}
// read complex vector (represented as 2 doubles) indexed by k1,k2 from file in binary format
int read_vec2_bin(double* out, int K1, int K2, FILE* file){
if(file==NULL){
return 0;
}
// seek past initial comments
seek_past_initial_comments(file);
fread(out, sizeof(double), 2*(K1*(2*K2+1)+K2), file);
return 0;
}
// read complex matrix (represented as 2 doubles) indexed by k1,k2 from file in binary format
int read_mat2_bin(double* out, int K1, int K2, FILE* file){
if(file==NULL){
return 0;
}
// seek past initial comments
seek_past_initial_comments(file);
fread(out, sizeof(double), 4*(K1*(2*K2+1)+K2)*(K1*(2*K2+1)+K2), file);
return 0;
}
// ignore comments at beginning of file
int seek_past_initial_comments(FILE* file){
char c;
int ret;
if(file==NULL){
return 0;
}
while(true){ while(true){
ret=fscanf(file, "%c", &c); ret=fscanf(file, "%c", &c);
if (ret==1 && c=='#'){ if (ret==1 && c=='#'){
@ -184,8 +246,6 @@ int read_vec_bin(_Complex double* out, int K1, int K2, FILE* file){
} }
} }
fread(out, sizeof(_Complex double), K1*(2*K2+1)+K2, file);
return 0; return 0;
} }
@ -275,6 +335,10 @@ int save_state(
if(savefile==stderr || savefile==stdout){ if(savefile==stderr || savefile==stdout){
fprintf(savefile,";starting_time=%.15e", time); fprintf(savefile,";starting_time=%.15e", time);
} }
// instruction to read init flow from file if computation is lyapunov
if(command==COMMAND_LYAPUNOV){
fprintf(savefile,";init_flow=file");
}
fprintf(savefile,"\""); fprintf(savefile,"\"");
} }

View File

@ -22,10 +22,21 @@ limitations under the License.
// write complex vector indexed by k1,k2 to file // write complex vector indexed by k1,k2 to file
int write_vec(_Complex double* u, int K1, int K2, FILE* file); int write_vec(_Complex double* u, int K1, int K2, FILE* file);
int write_vec_bin(_Complex double* u, int K1, int K2, FILE* file); int write_vec_bin(_Complex double* u, int K1, int K2, FILE* file);
// write complex vector (stored as 2 doubles) indexed by k1,k2 to file in binary format
int write_vec2_bin(double* vec, int K1, int K2, FILE* file);
// write complex matrix (stored as 2 doubles) indexed by k1,k2 to file in binary format
int write_mat2_bin(double* mat, int K1, int K2, FILE* file);
// read complex vector indexed by k1,k2 from file // read complex vector indexed by k1,k2 from file
int read_vec(_Complex double* u, int K1, int K2, FILE* file); int read_vec(_Complex double* u, int K1, int K2, FILE* file);
int read_vec_bin(_Complex double* u, int K1, int K2, FILE* file); int read_vec_bin(_Complex double* u, int K1, int K2, FILE* file);
// read complex vector (represented as 2 doubles) indexed by k1,k2 from file in binary format
int read_vec2_bin(double* out, int K1, int K2, FILE* file);
// read complex matrix (represented as 2 doubles) indexed by k1,k2 from file in binary format
int read_mat2_bin(double* out, int K1, int K2, FILE* file);
// ignore comments at beginning of file
int seek_past_initial_comments(FILE* file);
// remove an entry from params string (inplace) // remove an entry from params string (inplace)
int remove_entry(char* param_str, char* entry); int remove_entry(char* param_str, char* entry);

View File

@ -16,6 +16,7 @@ limitations under the License.
#include "constants.cpp" #include "constants.cpp"
#include "lyapunov.h" #include "lyapunov.h"
#include "io.h"
#include <openblas64/cblas.h> #include <openblas64/cblas.h>
#include <openblas64/lapacke.h> #include <openblas64/lapacke.h>
#include <math.h> #include <math.h>
@ -48,7 +49,16 @@ int lyapunov(
unsigned int algorithm, unsigned int algorithm,
unsigned int algorithm_lyapunov, unsigned int algorithm_lyapunov,
double starting_time, double starting_time,
unsigned int nthreads unsigned int nthreads,
double* flow0,
double* lyapunov_avg0,
FILE* savefile,
FILE* utfile,
// for interrupt recovery
const char* cmd_string,
const char* params_string,
const char* savefile_string,
const char* utfile_string
){ ){
double* lyapunov; double* lyapunov;
double* lyapunov_avg; double* lyapunov_avg;
@ -82,15 +92,13 @@ int lyapunov(
// copy initial condition // copy initial condition
copy_u(u, u0, K1, K2); copy_u(u, u0, K1, K2);
// initialize flow with identity matrix
// initialize flow and averages
for (i=0;i<MATSIZE;i++){ for (i=0;i<MATSIZE;i++){
for (j=0;j<MATSIZE;j++){ for (j=0;j<MATSIZE;j++){
if(i!=j){ flow[i*MATSIZE+j]=flow0[i*MATSIZE+j];
flow[i*MATSIZE+j]=0.;
} else {
flow[i*MATSIZE+j]=1.;
}
} }
lyapunov_avg[i]=lyapunov_avg0[i];
} }
// store step (useful for adaptive step methods) // store step (useful for adaptive step methods)
@ -168,9 +176,27 @@ int lyapunov(
// reset prevtime // reset prevtime
prevtime=time; prevtime=time;
// catch abort signal
if (g_abort){
// print u to stderr if no savefile
if (savefile==NULL){
savefile=stderr;
}
break;
}
} }
} }
if(savefile!=NULL){
lyapunov_save_state(flow, u, lyapunov_avg, savefile, K1, K2, cmd_string, params_string, savefile_string, utfile_string, utfile, COMMAND_LYAPUNOV, algorithm, step, time, nthreads);
}
// save final u to utfile in txt format
if(utfile!=NULL){
write_vec(u, K1, K2, utfile);
}
lyapunov_free_tmps(lyapunov, lyapunov_avg, flow, u, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, tmp11, fftu1, fftu2, fftu3, fftu4, fft1, ifft, algorithm, algorithm_lyapunov); lyapunov_free_tmps(lyapunov, lyapunov_avg, flow, u, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, tmp11, fftu1, fftu2, fftu3, fftu4, fft1, ifft, algorithm, algorithm_lyapunov);
return(0); return(0);
} }
@ -749,3 +775,35 @@ int lyapunov_free_tmps(
return(0); return(0);
} }
// save state of lyapunov computation
int lyapunov_save_state(
double* flow,
_Complex double* u,
double* lyapunov_avg,
FILE* savefile,
int K1,
int K2,
const char* cmd_string,
const char* params_string,
const char* savefile_string,
const char* utfile_string,
FILE* utfile,
unsigned int command,
unsigned int algorithm,
double step,
double time,
unsigned int nthreads
){
// save u and step
save_state(u, savefile, K1, K2, cmd_string, params_string, savefile_string, utfile_string, utfile, command, algorithm, step, time, nthreads);
if(savefile!=stderr && savefile!=stdout){
// save tangent flow
write_mat2_bin(flow,K1,K2,savefile);
// save lyapunov averages
write_vec2_bin(lyapunov_avg,K1,K2,savefile);
}
return 0;
}

View File

@ -20,7 +20,7 @@ limitations under the License.
#include "navier-stokes.h" #include "navier-stokes.h"
// compute Lyapunov exponents // compute Lyapunov exponents
int lyapunov( int K1, int K2, int N1, int N2, double final_time, double lyapunov_reset, unsigned int lyapunov_trigger, double nu, double delta, double L, double adaptive_tolerance, double adaptive_factor, double max_delta, unsigned int adaptive_norm, _Complex double* u0, _Complex double* g, bool irreversible, bool keep_en_cst, double target_en, unsigned int algorithm, unsigned int algorithm_lyapunov, double starting_time, unsigned int nthreads); int lyapunov( int K1, int K2, int N1, int N2, double final_time, double lyapunov_reset, unsigned int lyapunov_trigger, double nu, double delta, double L, double adaptive_tolerance, double adaptive_factor, double max_delta, unsigned int adaptive_cost, _Complex double* u0, _Complex double* g, bool irreversible, bool keep_en_cst, double target_en, unsigned int algorithm, unsigned int algorithm_lyapunov, double starting_time, unsigned int nthreads, double* flow0, double* lyapunov_avg0, FILE* savefile, FILE* utfile, const char* cmd_string, const char* params_string, const char* savefile_string, const char* utfile_string);
// comparison function for qsort // comparison function for qsort
int compare_double(const void* x, const void* y); int compare_double(const void* x, const void* y);
@ -56,6 +56,9 @@ int lyapunov_init_tmps( double ** lyapunov, double ** lyapunov_avg, double ** fl
// release vectors // release vectors
int lyapunov_free_tmps( double * lyapunov, double * lyapunov_avg, double * flow, _Complex double * u, double * tmp1, double * tmp2, double * tmp3, _Complex double * tmp4, _Complex double * tmp5, _Complex double * tmp6, _Complex double * tmp7, _Complex double * tmp8, _Complex double * tmp9, _Complex double * tmp10, double * tmp11, fft_vect fftu1, fft_vect fftu2, fft_vect fftu3, fft_vect fftu4, fft_vect fft1, fft_vect ifft, unsigned int algorithm, unsigned int algorithm_lyapunov); int lyapunov_free_tmps( double * lyapunov, double * lyapunov_avg, double * flow, _Complex double * u, double * tmp1, double * tmp2, double * tmp3, _Complex double * tmp4, _Complex double * tmp5, _Complex double * tmp6, _Complex double * tmp7, _Complex double * tmp8, _Complex double * tmp9, _Complex double * tmp10, double * tmp11, fft_vect fftu1, fft_vect fftu2, fft_vect fftu3, fft_vect fftu4, fft_vect fft1, fft_vect ifft, unsigned int algorithm, unsigned int algorithm_lyapunov);
// save state of lyapunov computation
int lyapunov_save_state( double* flow, _Complex double* u, double* lyapunov_avg, FILE* savefile, int K1, int K2, const char* cmd_string, const char* params_string, const char* savefile_string, const char* utfile_string, FILE* utfile, unsigned int command, unsigned int algorithm, double step, double time, unsigned int nthreads);
#endif #endif

View File

@ -28,6 +28,7 @@ limitations under the License.
#include "dstring.h" #include "dstring.h"
#include "init.h" #include "init.h"
#include "int_tools.h" #include "int_tools.h"
#include "io.h"
#include "lyapunov.h" #include "lyapunov.h"
#include "navier-stokes.h" #include "navier-stokes.h"
@ -62,6 +63,7 @@ typedef struct nstrophy_parameters {
FILE* drivingfile; FILE* drivingfile;
double lyapunov_reset; double lyapunov_reset;
unsigned int lyapunov_trigger; unsigned int lyapunov_trigger;
bool init_flow_file;
bool print_alpha; bool print_alpha;
} nstrophy_parameters; } nstrophy_parameters;
@ -82,6 +84,8 @@ int args_from_file(dstring* params, unsigned int* command, unsigned int* nthread
_Complex double* set_driving(nstrophy_parameters parameters); _Complex double* set_driving(nstrophy_parameters parameters);
// set initial condition // set initial condition
_Complex double* set_init(nstrophy_parameters* parameters); _Complex double* set_init(nstrophy_parameters* parameters);
// set initial tangent flow for lyapunov exponents
int set_lyapunov_flow_init( double** lyapunov_flow0, double** lyapunov_avg0, nstrophy_parameters parameters);
// signal handler // signal handler
void sig_handler (int signo); void sig_handler (int signo);
@ -115,6 +119,8 @@ int main (
unsigned int nthreads=1; unsigned int nthreads=1;
_Complex double* u0; _Complex double* u0;
_Complex double *g; _Complex double *g;
double* lyapunov_flow0;
double* lyapunov_avg0;
dstring savefile_str; dstring savefile_str;
dstring utfile_str; dstring utfile_str;
dstring initfile_str; dstring initfile_str;
@ -224,6 +230,10 @@ int main (
g=set_driving(parameters); g=set_driving(parameters);
// set initial condition // set initial condition
u0=set_init(&parameters); u0=set_init(&parameters);
// set initial condition for the lyapunov flow
if (command==COMMAND_LYAPUNOV){
set_lyapunov_flow_init(&lyapunov_flow0, &lyapunov_avg0, parameters);
}
// if init_enstrophy is not set in the parameters, then compute it from the initial condition // if init_enstrophy is not set in the parameters, then compute it from the initial condition
if (parameters.init_enstrophy_or_energy!=FIX_ENSTROPHY){ if (parameters.init_enstrophy_or_energy!=FIX_ENSTROPHY){
@ -255,6 +265,10 @@ int main (
dstring_free(drivingfile_str); dstring_free(drivingfile_str);
free(g); free(g);
free(u0); free(u0);
if (command==COMMAND_LYAPUNOV){
free(lyapunov_flow0);
free(lyapunov_avg0);
}
return(-1); return(-1);
} }
} }
@ -271,6 +285,10 @@ int main (
dstring_free(drivingfile_str); dstring_free(drivingfile_str);
free(g); free(g);
free(u0); free(u0);
if (command==COMMAND_LYAPUNOV){
free(lyapunov_flow0);
free(lyapunov_avg0);
}
return(-1); return(-1);
} }
} }
@ -297,7 +315,7 @@ int main (
quiet(parameters.K1, parameters.K2, parameters.N1, parameters.N2, parameters.final_time, parameters.nu, parameters.delta, parameters.L, parameters.adaptive_tolerance, parameters.adaptive_factor, parameters.max_delta, parameters.adaptive_cost, parameters.starting_time, u0, g, parameters.irreversible, parameters.keep_en_cst, parameters.init_enstrophy, parameters.algorithm, nthreads, savefile); quiet(parameters.K1, parameters.K2, parameters.N1, parameters.N2, parameters.final_time, parameters.nu, parameters.delta, parameters.L, parameters.adaptive_tolerance, parameters.adaptive_factor, parameters.max_delta, parameters.adaptive_cost, parameters.starting_time, u0, g, parameters.irreversible, parameters.keep_en_cst, parameters.init_enstrophy, parameters.algorithm, nthreads, savefile);
} }
else if(command==COMMAND_LYAPUNOV){ else if(command==COMMAND_LYAPUNOV){
lyapunov(parameters.K1, parameters.K2, parameters.N1, parameters.N2, parameters.final_time, parameters.lyapunov_reset, parameters.lyapunov_trigger, parameters.nu, parameters.delta, parameters.L, parameters.adaptive_tolerance, parameters.adaptive_factor, parameters.max_delta, parameters.adaptive_cost, u0, g, parameters.irreversible, parameters.keep_en_cst, parameters.init_enstrophy, parameters.algorithm, parameters.algorithm_lyapunov, parameters.starting_time, nthreads); lyapunov(parameters.K1, parameters.K2, parameters.N1, parameters.N2, parameters.final_time, parameters.lyapunov_reset, parameters.lyapunov_trigger, parameters.nu, parameters.delta, parameters.L, parameters.adaptive_tolerance, parameters.adaptive_factor, parameters.max_delta, parameters.adaptive_cost, u0, g, parameters.irreversible, parameters.keep_en_cst, parameters.init_enstrophy, parameters.algorithm, parameters.algorithm_lyapunov, parameters.starting_time, nthreads, lyapunov_flow0, lyapunov_avg0, savefile, utfile, (char*)argv[0], dstring_to_str_noinit(&param_str), dstring_to_str_noinit(&savefile_str), dstring_to_str_noinit(&utfile_str));
} }
else if(command==0){ else if(command==0){
fprintf(stderr, "error: no command specified\n"); fprintf(stderr, "error: no command specified\n");
@ -306,6 +324,10 @@ int main (
free(g); free(g);
free(u0); free(u0);
if (command==COMMAND_LYAPUNOV){
free(lyapunov_flow0);
free(lyapunov_avg0);
}
// free strings // free strings
dstring_free(param_str); dstring_free(param_str);
@ -540,7 +562,7 @@ int read_args(
} }
// check that if the command is 'resume', then resumefile has been set // check that if the command is 'resume', then resumefile has been set
if(*command==COMMAND_RESUME && resumefile_str->length==0){ if(*command==COMMAND_RESUME && (resumefile_str==NULL || resumefile_str->length==0)){
fprintf(stderr, "error: 'resume' command used, but no resume file\n"); fprintf(stderr, "error: 'resume' command used, but no resume file\n");
print_usage(); print_usage();
return(-1); return(-1);
@ -580,6 +602,7 @@ int set_default_params(
parameters->algorithm_lyapunov=ALGORITHM_RK4; parameters->algorithm_lyapunov=ALGORITHM_RK4;
// default lyapunov_reset will be print_time (set later) for now set target to 0 to indicate it hasn't been set explicitly // default lyapunov_reset will be print_time (set later) for now set target to 0 to indicate it hasn't been set explicitly
parameters->lyapunov_trigger=0; parameters->lyapunov_trigger=0;
parameters->init_flow_file=false;
parameters->print_alpha=false; parameters->print_alpha=false;
@ -977,6 +1000,16 @@ int set_parameter(
return(-1); return(-1);
} }
} }
else if (strcmp(lhs,"init_flow")==0){
if(strcmp(rhs,"file")==0){
parameters->init_flow_file=true;
} else if (strcmp(rhs,"identity")==0){
parameters->init_flow_file=false;
} else {
fprintf(stderr, "error: parameter 'init_flow' should be 'file' or 'identity'\n got '%s'\n",rhs);
return(-1);
}
}
else{ else{
fprintf(stderr, "error: unrecognized parameter '%s'\n",lhs); fprintf(stderr, "error: unrecognized parameter '%s'\n",lhs);
return(-1); return(-1);
@ -1132,3 +1165,36 @@ _Complex double* set_init(
return u0; return u0;
} }
// set initial tangent flow for lyapunov exponents
int set_lyapunov_flow_init(
double** lyapunov_flow0,
double** lyapunov_avg0,
nstrophy_parameters parameters
){
*lyapunov_flow0=calloc(4*(parameters.K1*(2*parameters.K2+1)+parameters.K2)*(parameters.K1*(2*parameters.K2+1)+parameters.K2),sizeof(double));
*lyapunov_avg0=calloc(2*(parameters.K1*(2*parameters.K2+1)+parameters.K2),sizeof(double));
if(parameters.init_flow_file){
// read flow
read_mat2_bin(*lyapunov_flow0, parameters.K1, parameters.K2, parameters.initfile);
// read averages
read_vec2_bin(*lyapunov_avg0, parameters.K1, parameters.K2, parameters.initfile);
} else {
// init with identity
int i,j;
for (i=0;i<2*(parameters.K1*(2*parameters.K2+1)+parameters.K2);i++){
for (j=0;j<2*(parameters.K1*(2*parameters.K2+1)+parameters.K2);j++){
if(i!=j){
(*lyapunov_flow0)[i*2*(parameters.K1*(2*parameters.K2+1)+parameters.K2)+j]=0.;
} else {
(*lyapunov_flow0)[i*2*(parameters.K1*(2*parameters.K2+1)+parameters.K2)+j]=1.;
}
}
}
for(i=0;i<2*(parameters.K1*(2*parameters.K2+1)+parameters.K2);i++){
(*lyapunov_avg0)[i]=0;
}
}
return 0;
}