Nstrophy/src/main.c

999 lines
28 KiB
C
Raw Normal View History

2023-05-10 19:33:29 -04:00
/*
Copyright 2017-2023 Ian Jauslin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
2022-05-18 09:57:06 +02:00
#define VERSION "0.1"
2018-01-11 22:48:14 +00:00
2023-04-12 15:23:35 -04:00
#include <signal.h>
2018-01-11 22:48:14 +00:00
#include <string.h>
#include <stdlib.h>
2022-05-27 16:09:17 -04:00
#include <errno.h>
#include <wordexp.h>
2023-04-26 11:27:03 -04:00
#include "constants.cpp"
2022-05-18 09:57:06 +02:00
#include "driving.h"
2023-11-03 16:04:53 -04:00
#include "dstring.h"
2022-05-26 15:05:30 -04:00
#include "init.h"
#include "int_tools.h"
2023-04-26 11:27:03 -04:00
#include "navier-stokes.h"
2023-04-12 19:05:01 -04:00
2022-05-26 14:25:45 -04:00
// structure to store parameters, to make it easier to pass parameters to CLI functions
typedef struct nstrophy_parameters {
2023-04-05 22:41:19 -04:00
double init_en; // initial value for the energy for ins and enstrophy for rns
2023-04-05 20:33:38 -04:00
bool irreversible;
2022-05-26 14:25:45 -04:00
int K1;
int K2;
int N1;
int N2;
double final_time;
2022-05-26 14:25:45 -04:00
double nu;
double delta;
double L;
2023-05-15 20:29:06 -04:00
double adaptive_tolerance;
double adaptive_factor;
2023-06-13 18:45:19 -04:00
double max_delta;
2023-06-13 23:56:35 -04:00
unsigned int adaptive_norm;
double print_freq;
2022-05-26 15:05:30 -04:00
int seed;
2023-05-15 20:29:06 -04:00
double starting_time;
unsigned int driving;
unsigned int init;
2023-04-26 11:27:03 -04:00
unsigned int algorithm;
2023-06-29 16:58:33 -04:00
bool keep_en_cst;
FILE* initfile;
2023-04-24 12:22:29 -04:00
FILE* drivingfile;
2022-05-26 14:25:45 -04:00
} nstrophy_parameters;
2018-01-11 22:48:14 +00:00
// usage message
int print_usage();
// print parameters
2023-04-24 12:22:29 -04:00
int print_params(nstrophy_parameters parameters, char* initfile_str, char* drivingfile_str, FILE* file);
2022-05-18 09:57:06 +02:00
2018-01-11 22:48:14 +00:00
// read command line arguments
2023-11-03 16:04:53 -04:00
int read_args(int argc, const char* argv[], dstring* params, unsigned int* command, unsigned int* nthreads, dstring* savefile_str, dstring* utfile_str, dstring* resumefile_str);
int set_default_params(nstrophy_parameters* parameters);
2023-11-03 16:42:27 -04:00
int read_params(dstring param_str, nstrophy_parameters* parameters, dstring* initfile_str, dstring* drivingfile_str);
2023-11-03 16:04:53 -04:00
int set_parameter(char* lhs, char* rhs, nstrophy_parameters* parameters, bool* setN1, bool* setN2, dstring* initfile_str, dstring* drivingfile_str);
// read args from file
2023-11-03 16:04:53 -04:00
int args_from_file(dstring* params, unsigned int* command, unsigned int* nthreads, dstring* savefile_str, dstring* utfile_str, char* file_str);
2022-05-18 09:57:06 +02:00
// set driving force
_Complex double* set_driving(nstrophy_parameters parameters);
2022-05-26 15:05:30 -04:00
// set initial condition
2023-05-15 20:29:06 -04:00
_Complex double* set_init(nstrophy_parameters* parameters);
2022-05-26 15:05:30 -04:00
2023-04-12 15:23:35 -04:00
// signal handler
void sig_handler (int signo);
// global variable to handle interrupts
volatile bool g_abort = false;
// signal handler
void sig_handler (int signo){
if (signo == SIGINT){
fprintf(stderr,"received signal SIGINT, interrupting computation\n");
2023-04-12 15:23:35 -04:00
g_abort = true;
}
else if (signo == SIGTERM){
fprintf(stderr,"received signal SIGTERM, interrupting computation\n");
g_abort = true;
}
else{
fprintf(stderr,"received signal %d\n",signo);
}
2023-04-12 15:23:35 -04:00
}
2022-05-18 09:57:06 +02:00
int main (
int argc,
const char* argv[]
){
2023-11-03 16:04:53 -04:00
dstring param_str;
2022-05-26 14:25:45 -04:00
nstrophy_parameters parameters;
2018-01-11 22:48:14 +00:00
int ret;
unsigned int command;
2022-05-18 23:52:01 +02:00
unsigned int nthreads=1;
2022-05-26 15:05:30 -04:00
_Complex double* u0;
_Complex double *g;
2023-11-03 16:04:53 -04:00
dstring savefile_str;
dstring utfile_str;
dstring initfile_str;
dstring drivingfile_str;
dstring resumefile_str;
2022-05-27 16:09:17 -04:00
FILE* savefile=NULL;
2023-06-14 14:19:27 -04:00
FILE* utfile=NULL;
2018-01-11 22:48:14 +00:00
2022-05-18 09:57:06 +02:00
command=0;
2018-01-11 22:48:14 +00:00
2023-11-03 16:04:53 -04:00
// init strings
dstring_init(&param_str, 64);
dstring_init(&savefile_str, 64);
dstring_init(&utfile_str, 64);
dstring_init(&initfile_str, 64);
dstring_init(&drivingfile_str, 64);
dstring_init(&resumefile_str, 64);
2018-01-11 22:48:14 +00:00
// read command line arguments
ret=read_args(argc, argv, &param_str, &command, &nthreads, &savefile_str, &utfile_str, &resumefile_str);
2022-05-18 09:57:06 +02:00
if(ret<0){
2023-11-03 17:41:30 -04:00
dstring_free(param_str);
dstring_free(savefile_str);
dstring_free(utfile_str);
dstring_free(initfile_str);
dstring_free(drivingfile_str);
dstring_free(resumefile_str);
return(ret);
2022-05-18 09:57:06 +02:00
}
2022-05-26 15:05:30 -04:00
// set default params
set_default_params(&parameters);
2022-05-18 09:57:06 +02:00
// read params
2023-11-03 16:42:27 -04:00
ret=read_params(param_str, &parameters, &initfile_str, &drivingfile_str);
2018-01-11 22:48:14 +00:00
if(ret<0){
2023-11-03 17:41:30 -04:00
dstring_free(param_str);
dstring_free(savefile_str);
dstring_free(utfile_str);
dstring_free(initfile_str);
dstring_free(drivingfile_str);
dstring_free(resumefile_str);
return(ret);
2018-01-11 22:48:14 +00:00
}
2022-05-26 15:05:30 -04:00
// if command is 'resume', then read args from file
if(command==COMMAND_RESUME){
2023-11-03 16:04:53 -04:00
ret=args_from_file(&param_str, &command, &nthreads, &savefile_str, &utfile_str, dstring_to_str_noinit(&resumefile_str));
if(ret<0){
2023-11-03 17:41:30 -04:00
dstring_free(param_str);
dstring_free(savefile_str);
dstring_free(utfile_str);
dstring_free(initfile_str);
dstring_free(drivingfile_str);
dstring_free(resumefile_str);
return(ret);
}
// read params
2023-11-03 16:42:27 -04:00
ret=read_params(param_str, &parameters, &initfile_str, &drivingfile_str);
if(ret<0){
2023-11-03 17:41:30 -04:00
dstring_free(param_str);
dstring_free(savefile_str);
dstring_free(utfile_str);
dstring_free(initfile_str);
dstring_free(drivingfile_str);
dstring_free(resumefile_str);
return(ret);
}
// reread arguments (to allow overrides from the command line, but do not override the command)
unsigned int dummy_command;
read_args(argc, argv, &param_str, &dummy_command, &nthreads, &savefile_str, &utfile_str, &resumefile_str);
// reread params
2023-11-03 17:41:30 -04:00
read_params(param_str, &parameters, &initfile_str, &drivingfile_str);
}
2023-11-03 17:41:30 -04:00
// free strings
dstring_free(resumefile_str);
2022-05-27 16:09:17 -04:00
// open initfile
2023-11-03 16:04:53 -04:00
if(initfile_str.length!=0){
parameters.initfile=fopen(dstring_to_str_noinit(&initfile_str),"r");
if(parameters.initfile==NULL){
2023-11-03 16:04:53 -04:00
fprintf(stderr,"Error opening file '%s' for reading: %s\n", dstring_to_str_noinit(&initfile_str), strerror(errno));
2023-11-03 17:41:30 -04:00
dstring_free(param_str);
dstring_free(savefile_str);
dstring_free(utfile_str);
dstring_free(initfile_str);
dstring_free(drivingfile_str);
2022-05-27 16:09:17 -04:00
return(-1);
}
}
2023-04-24 12:22:29 -04:00
// open drivingfile
2023-11-03 16:04:53 -04:00
if(drivingfile_str.length!=0){
parameters.drivingfile=fopen(dstring_to_str_noinit(&drivingfile_str),"r");
2023-04-24 12:22:29 -04:00
if(parameters.drivingfile==NULL){
2023-11-03 16:04:53 -04:00
fprintf(stderr,"Error opening file '%s' for reading: %s\n", dstring_to_str_noinit(&drivingfile_str), strerror(errno));
2023-11-03 17:41:30 -04:00
dstring_free(param_str);
dstring_free(savefile_str);
dstring_free(utfile_str);
dstring_free(initfile_str);
dstring_free(drivingfile_str);
2023-04-24 12:22:29 -04:00
return(-1);
}
}
2022-05-27 16:09:17 -04:00
2022-05-18 09:57:06 +02:00
// set driving force
g=set_driving(parameters);
2022-05-26 15:05:30 -04:00
// set initial condition
2023-05-15 20:29:06 -04:00
u0=set_init(&parameters);
2022-05-27 16:09:17 -04:00
// close initfile (do this early, so that it is possible to use the same file for init and save)
if (parameters.initfile!=NULL){
fclose(parameters.initfile);
2022-05-27 16:09:17 -04:00
}
2023-04-24 12:22:29 -04:00
// close drivingfile
if (parameters.drivingfile!=NULL){
fclose(parameters.drivingfile);
}
2022-05-27 16:09:17 -04:00
// open savefile (do this after closing init file)
2023-11-03 16:04:53 -04:00
if(savefile_str.length!=0){
savefile=fopen(dstring_to_str_noinit(&savefile_str),"w");
2022-05-27 16:09:17 -04:00
if(savefile==NULL){
2023-11-03 16:04:53 -04:00
fprintf(stderr,"Error opening file '%s' for writing: %s\n", dstring_to_str_noinit(&savefile_str), strerror(errno));
2023-11-03 17:41:30 -04:00
dstring_free(param_str);
dstring_free(savefile_str);
dstring_free(utfile_str);
dstring_free(initfile_str);
dstring_free(drivingfile_str);
free(g);
free(u0);
2022-05-27 16:09:17 -04:00
return(-1);
}
}
2022-05-26 15:05:30 -04:00
2023-06-14 14:19:27 -04:00
// open utfile (do this after closing init file)
2023-11-03 16:04:53 -04:00
if(utfile_str.length!=0){
utfile=fopen(dstring_to_str_noinit(&utfile_str),"w");
2023-06-14 14:19:27 -04:00
if(utfile==NULL){
2023-11-03 16:04:53 -04:00
fprintf(stderr,"Error opening file '%s' for writing: %s\n", dstring_to_str_noinit(&utfile_str), strerror(errno));
2023-11-03 17:41:30 -04:00
dstring_free(param_str);
dstring_free(savefile_str);
dstring_free(utfile_str);
dstring_free(initfile_str);
dstring_free(drivingfile_str);
free(g);
free(u0);
2023-06-14 14:19:27 -04:00
return(-1);
}
}
// print parameters
2023-11-03 16:04:53 -04:00
print_params(parameters, dstring_to_str_noinit(&initfile_str), dstring_to_str_noinit(&drivingfile_str), stderr);
print_params(parameters, dstring_to_str_noinit(&initfile_str), dstring_to_str_noinit(&drivingfile_str), stdout);
2023-11-03 16:04:53 -04:00
// free strings
dstring_free(initfile_str);
dstring_free(drivingfile_str);
2023-04-12 19:05:01 -04:00
2022-05-18 09:57:06 +02:00
// run command
if (command==COMMAND_UK){
2023-06-29 16:58:33 -04:00
uk(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_norm, u0, g, parameters.irreversible, parameters.keep_en_cst, parameters.init_en, parameters.algorithm, parameters.print_freq, parameters.starting_time, nthreads, savefile);
2022-05-18 09:57:06 +02:00
}
else if(command==COMMAND_ENSTROPHY){
2023-04-12 15:23:35 -04:00
// register signal handler to handle aborts
signal(SIGINT, sig_handler);
2023-05-26 17:37:51 -04:00
signal(SIGTERM, sig_handler);
2023-11-03 16:04:53 -04:00
enstrophy(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_norm, u0, g, parameters.irreversible, parameters.keep_en_cst, parameters.init_en, parameters.algorithm, parameters.print_freq, parameters.starting_time, nthreads, savefile, utfile, (char*)argv[0], dstring_to_str_noinit(&param_str), dstring_to_str_noinit(&savefile_str), dstring_to_str_noinit(&utfile_str));
2022-05-18 09:57:06 +02:00
}
2022-05-18 22:22:42 +02:00
else if(command==COMMAND_QUIET){
2023-06-29 16:58:33 -04:00
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_norm, parameters.starting_time, u0, g, parameters.irreversible, parameters.keep_en_cst, parameters.init_en, parameters.algorithm, nthreads, savefile);
2022-05-18 22:22:42 +02:00
}
2022-05-18 09:57:06 +02:00
else if(command==0){
fprintf(stderr, "error: no command specified\n");
print_usage();
2018-01-11 22:48:14 +00:00
}
free(g);
2022-05-26 15:05:30 -04:00
free(u0);
2023-11-03 16:04:53 -04:00
// free strings
dstring_free(param_str);
dstring_free(savefile_str);
dstring_free(utfile_str);
2022-05-27 16:09:17 -04:00
// close savefile
if (savefile!=NULL){
fclose(savefile);
}
2023-06-14 14:19:27 -04:00
// close utfile
if (utfile!=NULL){
fclose(utfile);
}
2018-01-11 22:48:14 +00:00
return(0);
}
// usage message
int print_usage(){
fprintf(stderr, "usage:\n nstrophy [-t nthreads] [-p parameters] [-s savefile] [-u u_outfile] <command>\n where <command> is one of\n enstrophy\n uk\n quiet\n resume <resume_file>\n\n");
2018-01-11 22:48:14 +00:00
return(0);
}
// print parameters
int print_params(
nstrophy_parameters parameters,
2022-05-27 16:09:17 -04:00
char* initfile_str,
2023-04-24 12:22:29 -04:00
char* drivingfile_str,
FILE* file
){
2023-04-05 22:41:19 -04:00
fprintf(file,"# ");
if (parameters.irreversible){
fprintf(file,"equation=irreversible");
} else {
fprintf(file,"equation=reversible");
}
fprintf(file,", K1=%d, K2=%d, N1=%d, N2=%d, nu=%.15e, delta=%.15e, L=%.15e, init_en=%.15e", parameters.K1, parameters.K2, parameters.N1, parameters.N2, parameters.nu, parameters.delta, parameters.L, parameters.init_en);
switch(parameters.driving){
case DRIVING_TEST:
fprintf(file,", driving=test");
break;
case DRIVING_ZERO:
fprintf(file,", driving=zero");
break;
2023-04-24 12:22:29 -04:00
case DRIVING_FILE:
fprintf(file,", driving=file:%s", drivingfile_str);
break;
case DRIVING_FILE_TXT:
fprintf(file,", driving=file_txt:%s", drivingfile_str);
break;
default:
fprintf(file,", driving=test");
break;
}
switch(parameters.init){
case INIT_RANDOM:
fprintf(file,", init=random");
break;
case INIT_GAUSSIAN:
fprintf(file,", init=gaussian");
break;
2022-05-27 16:09:17 -04:00
case INIT_FILE:
fprintf(file,", init=file:%s", initfile_str);
break;
case INIT_FILE_TXT:
fprintf(file,", init=file_txt:%s", initfile_str);
break;
default:
fprintf(file,", init=gaussian");
break;
}
2023-04-26 11:27:03 -04:00
switch(parameters.algorithm){
case ALGORITHM_RK4:
fprintf(file,", algorithm=RK4");
break;
case ALGORITHM_RK2:
fprintf(file,", algorithm=RK2");
break;
2023-05-15 20:29:06 -04:00
case ALGORITHM_RKF45:
2023-06-13 18:45:19 -04:00
fprintf(file,", algorithm=RKF45, tolerance=%.15e",parameters.adaptive_tolerance);
2023-05-15 20:29:06 -04:00
break;
2023-05-17 17:41:00 -04:00
case ALGORITHM_RKDP54:
2023-06-13 18:45:19 -04:00
fprintf(file,", algorithm=RKDP54, tolerance=%.15e",parameters.adaptive_tolerance);
2023-05-17 17:41:00 -04:00
break;
2023-05-17 16:59:15 -04:00
case ALGORITHM_RKBS32:
2023-06-13 18:45:19 -04:00
fprintf(file,", algorithm=RKBS32, tolerance=%.15e",parameters.adaptive_tolerance);
2023-05-17 16:47:15 -04:00
break;
2023-04-26 11:27:03 -04:00
default:
fprintf(file,", algorithm=RK4");
break;
}
2023-06-13 23:56:35 -04:00
if(parameters.algorithm>ALGORITHM_ADAPTIVE_THRESHOLD){
switch(parameters.adaptive_norm){
case NORM_L1:
fprintf(file,", norm=L1");
break;
case NORM_k3:
fprintf(file,", norm=k3");
break;
case NORM_k32:
fprintf(file,", norm=k32");
break;
case NORM_ENSTROPHY:
fprintf(file,", norm=enstrophy");
break;
}
}
fprintf(file,"\n");
return 0;
}
2023-04-12 19:05:01 -04:00
2018-01-11 22:48:14 +00:00
// read command line arguments
2022-05-18 09:57:06 +02:00
#define CP_FLAG_PARAMS 1
#define CP_FLAG_NTHREADS 2
#define CP_FLAG_SAVEFILE 3
2023-06-14 14:19:27 -04:00
#define CP_FLAG_UTFILE 4
#define CP_FLAG_RESUME 5
2022-05-18 09:57:06 +02:00
int read_args(
int argc,
const char* argv[],
2023-11-03 16:04:53 -04:00
dstring* params,
2022-05-18 23:52:01 +02:00
unsigned int* command,
2022-05-27 16:09:17 -04:00
unsigned int* nthreads,
2023-11-03 16:04:53 -04:00
dstring* savefile_str,
dstring* utfile_str,
dstring* resumefile_str
2022-05-18 09:57:06 +02:00
){
2018-01-11 22:48:14 +00:00
int i;
2022-05-18 23:52:01 +02:00
int ret;
2018-01-11 22:48:14 +00:00
// pointers
char* ptr;
// flag that indicates what argument is being read
int flag=0;
// loop over arguments
for(i=1;i<argc;i++){
// flag
if(argv[i][0]=='-'){
for(ptr=((char*)argv[i])+1;*ptr!='\0';ptr++){
switch(*ptr){
2022-05-18 09:57:06 +02:00
case 'p':
flag=CP_FLAG_PARAMS;
2018-01-11 22:48:14 +00:00
break;
2022-05-18 23:52:01 +02:00
case 't':
flag=CP_FLAG_NTHREADS;
break;
2022-05-27 16:09:17 -04:00
case 's':
flag=CP_FLAG_SAVEFILE;
break;
2023-06-14 14:19:27 -04:00
case 'u':
flag=CP_FLAG_UTFILE;
break;
2018-01-11 22:48:14 +00:00
default:
fprintf(stderr, "unrecognized option '-%c'\n", *ptr);
print_usage();
return(-1);
break;
}
}
}
2022-05-18 09:57:06 +02:00
// params
else if(flag==CP_FLAG_PARAMS){
2023-11-03 16:04:53 -04:00
str_to_dstring_noinit((char*)argv[i], params);
2018-01-11 22:48:14 +00:00
flag=0;
}
2022-05-18 23:52:01 +02:00
// nthreads
else if(flag==CP_FLAG_NTHREADS){
ret=sscanf(argv[i],"%u",nthreads);
if(ret!=1){
fprintf(stderr, "error: '-t' should be followed by an unsigned integer\n got '%s'\n",argv[i]);
return(-1);
}
flag=0;
}
2022-05-27 16:09:17 -04:00
// savefile
else if(flag==CP_FLAG_SAVEFILE){
2023-11-03 16:04:53 -04:00
str_to_dstring_noinit((char*)argv[i], savefile_str);
2022-05-27 16:09:17 -04:00
flag=0;
}
2023-06-14 14:19:27 -04:00
// savefile
else if(flag==CP_FLAG_UTFILE){
2023-11-03 16:04:53 -04:00
str_to_dstring_noinit((char*)argv[i], utfile_str);
2023-06-14 14:19:27 -04:00
flag=0;
}
// resume file
else if(flag==CP_FLAG_RESUME){
2023-11-03 16:04:53 -04:00
str_to_dstring_noinit((char*)argv[i], resumefile_str);
flag=0;
}
2018-01-11 22:48:14 +00:00
// computation to run
else{
2022-05-18 09:57:06 +02:00
if(strcmp(argv[i], "uk")==0){
*command=COMMAND_UK;
}
else if(strcmp(argv[i], "enstrophy")==0){
*command=COMMAND_ENSTROPHY;
2018-01-11 22:48:14 +00:00
}
2022-05-18 22:22:42 +02:00
else if(strcmp(argv[i], "quiet")==0){
*command=COMMAND_QUIET;
}
else if(strcmp(argv[i], "resume")==0){
*command=COMMAND_RESUME;
flag=CP_FLAG_RESUME;
}
2018-01-11 22:48:14 +00:00
else{
2022-05-18 09:57:06 +02:00
fprintf(stderr, "error: unrecognized command: '%s'\n",argv[i]);
2018-01-11 22:48:14 +00:00
return(-1);
}
}
}
// check that if the command is 'resume', then resumefile has been set
2023-11-03 16:04:53 -04:00
if(*command==COMMAND_RESUME && resumefile_str->length==0){
fprintf(stderr, "error: 'resume' command used, but no resume file\n");
print_usage();
return(-1);
}
2018-01-11 22:48:14 +00:00
return(0);
}
// set default parameters
int set_default_params(
nstrophy_parameters* parameters
2022-05-18 09:57:06 +02:00
){
2023-04-05 22:41:19 -04:00
parameters->init_en=1.54511597324389e+02;
2023-04-05 20:33:38 -04:00
parameters->irreversible=true;
2022-05-26 14:25:45 -04:00
parameters->K1=16;
parameters->K2=parameters->K1;
2022-05-18 09:57:06 +02:00
//delta=2^-13
2022-05-26 14:25:45 -04:00
parameters->delta=0.0001220703125;
2022-05-18 09:57:06 +02:00
//nu=2^-11
2022-05-26 14:25:45 -04:00
parameters->nu=0.00048828125;
parameters->L=2*M_PI;
2023-05-15 20:29:06 -04:00
parameters->adaptive_tolerance=1e-11;
parameters->adaptive_factor=0.9;
2023-06-13 18:45:19 -04:00
parameters->max_delta=1e-2;
2023-06-13 23:56:35 -04:00
parameters->adaptive_norm=NORM_L1;
parameters->final_time=100000;
parameters->print_freq=1;
2022-05-27 17:06:38 -04:00
parameters->starting_time=0;
2022-05-26 15:05:30 -04:00
parameters->seed=17;
parameters->driving=DRIVING_TEST;
2023-04-24 12:22:29 -04:00
parameters->drivingfile=NULL;
parameters->init=INIT_GAUSSIAN;
parameters->initfile=NULL;
2023-04-26 11:27:03 -04:00
parameters->algorithm=ALGORITHM_RK4;
2023-06-29 16:58:33 -04:00
parameters->keep_en_cst=false;
return(0);
}
// read parameters string
int read_params(
2023-11-03 16:42:27 -04:00
dstring param_str,
nstrophy_parameters* parameters,
2023-11-03 16:04:53 -04:00
dstring* initfile_str,
dstring* drivingfile_str
){
int ret;
2023-11-03 16:42:27 -04:00
unsigned int i;
// buffer and associated pointer
2023-11-03 16:42:27 -04:00
dstring buffer_lhs;
dstring buffer_rhs;
// whether N was set explicitly
bool setN1=false;
bool setN2=false;
2023-11-03 16:42:27 -04:00
// which buffer to add to
dstring* buffer=&buffer_lhs;
2022-05-18 09:57:06 +02:00
2023-11-03 16:04:53 -04:00
// init
2023-11-03 16:42:27 -04:00
dstring_init(&buffer_lhs, param_str.length);
dstring_init(&buffer_rhs, param_str.length);
for(i=0;i<param_str.length;i++){
switch(param_str.string[i]){
2023-11-03 16:04:53 -04:00
case '=':
// reset buffer
2023-11-03 16:42:27 -04:00
buffer_rhs.length=0;
buffer=&buffer_rhs;
2023-11-03 16:04:53 -04:00
break;
case ';':
//set parameter
2023-11-03 16:42:27 -04:00
ret=set_parameter(dstring_to_str_noinit(&buffer_lhs), dstring_to_str_noinit(&buffer_rhs), parameters, &setN1, &setN2, initfile_str, drivingfile_str);
2022-05-18 09:57:06 +02:00
if(ret<0){
return ret;
}
2023-11-03 16:04:53 -04:00
// reset buffer
2023-11-03 16:42:27 -04:00
buffer_lhs.length=0;
buffer=&buffer_lhs;
2023-11-03 16:04:53 -04:00
break;
default:
// add to buffer
2023-11-03 16:42:27 -04:00
dstring_append(param_str.string[i],buffer);
2023-11-03 16:04:53 -04:00
break;
2022-05-18 09:57:06 +02:00
}
2023-11-03 16:04:53 -04:00
}
2018-01-11 22:48:14 +00:00
2023-11-03 16:04:53 -04:00
// set last param
2023-11-03 16:42:27 -04:00
if (param_str.length!=0){
ret=set_parameter(dstring_to_str_noinit(&buffer_lhs), dstring_to_str_noinit(&buffer_rhs), parameters, &setN1, &setN2, initfile_str, drivingfile_str);
2023-11-03 16:04:53 -04:00
if(ret<0){
return ret;
}
2022-05-18 09:57:06 +02:00
}
2018-02-19 16:00:07 +00:00
2023-11-03 16:04:53 -04:00
// free vects
2023-11-03 16:42:27 -04:00
dstring_free(buffer_lhs);
dstring_free(buffer_rhs);
2023-11-03 16:04:53 -04:00
// if N not set explicitly, set it to the smallest power of 2 that is >3*K+1 (the fft is faster on vectors whose length is a power of 2)
2022-05-18 09:57:06 +02:00
if (!setN1){
parameters->N1=smallest_pow2(3*(parameters->K1));
2018-02-19 16:00:07 +00:00
}
2022-05-18 09:57:06 +02:00
if (!setN2){
parameters->N2=smallest_pow2(3*(parameters->K2));
2018-02-19 16:00:07 +00:00
}
2022-05-18 09:57:06 +02:00
return(0);
}
// set a parameter from the parameter string
int set_parameter(
char* lhs,
char* rhs,
2022-05-26 14:25:45 -04:00
nstrophy_parameters* parameters,
2022-05-18 09:57:06 +02:00
bool* setN1,
2023-04-12 14:37:02 -04:00
bool* setN2,
2023-11-03 16:04:53 -04:00
dstring* initfile_str,
dstring* drivingfile_str
2022-05-18 09:57:06 +02:00
){
int ret;
2023-04-05 20:33:38 -04:00
if (strcmp(lhs,"equation")==0){
if (strcmp(rhs,"irreversible")==0){
parameters->irreversible=true;
}
else if (strcmp(rhs,"reversible")==0){
parameters->irreversible=false;
}
else {
fprintf(stderr, "error: 'equation' should be 'irreversible' or 'reversible'\n got '%s'\n",rhs);
return(-1);
}
}
2023-04-05 22:41:19 -04:00
else if (strcmp(lhs,"init_en")==0){
ret=sscanf(rhs,"%lf",&(parameters->init_en));
if(ret!=1){
fprintf(stderr, "error: parameter 'init_en' should be a double\n got '%s'\n",rhs);
return(-1);
}
}
2023-04-05 20:33:38 -04:00
else if (strcmp(lhs,"K1")==0){
2022-05-26 14:25:45 -04:00
ret=sscanf(rhs,"%d",&(parameters->K1));
2022-05-18 09:57:06 +02:00
if(ret!=1){
fprintf(stderr, "error: parameter 'K1' should be an integer\n got '%s'\n",rhs);
return(-1);
}
2018-02-19 16:00:07 +00:00
}
2022-05-18 09:57:06 +02:00
else if (strcmp(lhs,"K2")==0){
2022-05-26 14:25:45 -04:00
ret=sscanf(rhs,"%d",&(parameters->K2));
2022-05-18 09:57:06 +02:00
if(ret!=1){
fprintf(stderr, "error: parameter 'K2' should be an integer\n got '%s'\n",rhs);
return(-1);
2018-02-19 16:00:07 +00:00
}
}
2022-05-18 09:57:06 +02:00
else if (strcmp(lhs,"K")==0){
2022-05-26 14:25:45 -04:00
ret=sscanf(rhs,"%d",&(parameters->K1));
2022-05-18 09:57:06 +02:00
if(ret!=1){
fprintf(stderr, "error: parameter 'K' should be an integer\n got '%s'\n",rhs);
return(-1);
2018-02-19 16:00:07 +00:00
}
2022-05-26 14:25:45 -04:00
parameters->K2=parameters->K1;
2018-02-19 16:00:07 +00:00
}
2022-05-18 09:57:06 +02:00
else if (strcmp(lhs,"N1")==0){
2022-05-26 14:25:45 -04:00
ret=sscanf(rhs,"%d",&(parameters->N1));
2022-05-18 09:57:06 +02:00
if(ret!=1){
fprintf(stderr, "error: parameter 'N1' should be an integer\n got '%s'\n",rhs);
return(-1);
2018-02-19 16:00:07 +00:00
}
2022-05-18 09:57:06 +02:00
*setN1=true;
2018-02-19 16:00:07 +00:00
}
2022-05-18 09:57:06 +02:00
else if (strcmp(lhs,"N2")==0){
2022-05-26 14:25:45 -04:00
ret=sscanf(rhs,"%d",&(parameters->N2));
2022-05-18 09:57:06 +02:00
if(ret!=1){
fprintf(stderr, "error: parameter 'N2' should be an integer\n got '%s'\n",rhs);
return(-1);
2018-01-11 22:48:14 +00:00
}
2022-05-18 09:57:06 +02:00
*setN2=true;
2018-01-11 22:48:14 +00:00
}
2022-05-18 09:57:06 +02:00
else if (strcmp(lhs,"N")==0){
2022-05-26 14:25:45 -04:00
ret=sscanf(rhs,"%d",&(parameters->N1));
2022-05-18 09:57:06 +02:00
if(ret!=1){
fprintf(stderr, "error: parameter 'N' should be an integer\n got '%s'\n",rhs);
return(-1);
2022-05-17 14:31:22 +02:00
}
2022-05-26 14:25:45 -04:00
parameters->N2=parameters->N1;
2022-05-18 09:57:06 +02:00
*setN1=true;
*setN2=true;
2022-05-17 14:31:22 +02:00
}
else if (strcmp(lhs,"final_time")==0){
ret=sscanf(rhs,"%lf",&(parameters->final_time));
2022-05-18 09:57:06 +02:00
if(ret!=1){
fprintf(stderr, "error: parameter 'final_time' should be a double\n got '%s'\n",rhs);
2022-05-18 09:57:06 +02:00
return(-1);
2018-01-11 22:48:14 +00:00
}
}
2022-05-18 09:57:06 +02:00
else if (strcmp(lhs,"nu")==0){
2022-05-26 14:25:45 -04:00
ret=sscanf(rhs,"%lf",&(parameters->nu));
2022-05-18 09:57:06 +02:00
if(ret!=1){
fprintf(stderr, "error: parameter 'nu' should be a double\n got '%s'\n",rhs);
return(-1);
2018-01-11 22:48:14 +00:00
}
2022-05-18 09:57:06 +02:00
}
else if (strcmp(lhs,"delta")==0){
2022-05-26 14:25:45 -04:00
ret=sscanf(rhs,"%lf",&(parameters->delta));
2022-05-18 09:57:06 +02:00
if(ret!=1){
fprintf(stderr, "error: parameter 'delta' should be a double\n got '%s'\n",rhs);
return(-1);
2018-01-11 22:48:14 +00:00
}
2022-05-18 09:57:06 +02:00
}
2022-05-25 11:12:02 -04:00
else if (strcmp(lhs,"L")==0){
2022-05-26 14:25:45 -04:00
ret=sscanf(rhs,"%lf",&(parameters->L));
2022-05-25 11:12:02 -04:00
if(ret!=1){
fprintf(stderr, "error: parameter 'L' should be a double\n got '%s'\n",rhs);
return(-1);
}
}
2023-05-15 20:29:06 -04:00
else if (strcmp(lhs,"adaptive_tolerance")==0){
ret=sscanf(rhs,"%lf",&(parameters->adaptive_tolerance));
if(ret!=1){
fprintf(stderr, "error: parameter 'adaptive_tolerance' should be a double\n got '%s'\n",rhs);
return(-1);
}
}
else if (strcmp(lhs,"adaptive_factor")==0){
ret=sscanf(rhs,"%lf",&(parameters->adaptive_factor));
if(ret!=1){
fprintf(stderr, "error: parameter 'adaptive_factor' should be a double\n got '%s'\n",rhs);
return(-1);
}
}
2023-06-13 18:45:19 -04:00
else if (strcmp(lhs,"max_delta")==0){
ret=sscanf(rhs,"%lf",&(parameters->max_delta));
if(ret!=1){
fprintf(stderr, "error: parameter 'max_delta' should be a double\n got '%s'\n",rhs);
return(-1);
}
}
2023-06-13 23:56:35 -04:00
else if (strcmp(lhs,"adaptive_norm")==0){
if (strcmp(rhs,"L1")==0){
parameters->adaptive_norm=NORM_L1;
}
else if (strcmp(rhs,"k3")==0){
parameters->adaptive_norm=NORM_k3;
}
else if (strcmp(rhs,"k32")==0){
parameters->adaptive_norm=NORM_k32;
}
else if (strcmp(rhs,"enstrophy")==0){
parameters->adaptive_norm=NORM_ENSTROPHY;
}
else{
fprintf(stderr, "error: unrecognized adaptive_norm '%s'\n",rhs);
return(-1);
}
}
2022-05-18 09:57:06 +02:00
else if (strcmp(lhs,"print_freq")==0){
ret=sscanf(rhs,"%lf",&(parameters->print_freq));
2022-05-18 09:57:06 +02:00
if(ret!=1){
fprintf(stderr, "error: parameter 'print_freq' should be a double\n got '%s'\n",rhs);
2022-05-18 09:57:06 +02:00
return(-1);
2018-01-11 22:48:14 +00:00
}
}
2022-05-26 15:05:30 -04:00
else if (strcmp(lhs,"random_seed")==0){
ret=sscanf(rhs,"%d",&(parameters->seed));
if(ret!=1){
fprintf(stderr, "error: parameter 'random_seed' should be an integer\n got '%s'\n",rhs);
return(-1);
}
}
2022-05-27 17:06:38 -04:00
else if (strcmp(lhs,"starting_time")==0){
2023-05-15 20:29:06 -04:00
ret=sscanf(rhs,"%lf",&(parameters->starting_time));
2022-05-27 17:06:38 -04:00
if(ret!=1){
2023-05-15 20:29:06 -04:00
fprintf(stderr, "error: parameter 'starting_time' should be a double\n got '%s'\n",rhs);
2022-05-27 17:06:38 -04:00
return(-1);
}
}
else if (strcmp(lhs,"driving")==0){
if (strcmp(rhs,"zero")==0){
parameters->driving=DRIVING_ZERO;
}
else if (strcmp(rhs,"test")==0){
parameters->driving=DRIVING_TEST;
}
2023-04-24 12:22:29 -04:00
// matches any argument that starts with 'file:'
else if (strncmp(rhs,"file:",5)==0){
parameters->driving=DRIVING_FILE;
2023-11-03 16:04:53 -04:00
str_to_dstring_noinit(rhs+5,drivingfile_str);
2023-04-24 12:22:29 -04:00
}
// matches any argument that starts with 'file_txt:'
else if (strncmp(rhs,"file_txt:",9)==0){
parameters->driving=DRIVING_FILE_TXT;
2023-11-03 16:04:53 -04:00
str_to_dstring_noinit(rhs+9,drivingfile_str);
2023-04-24 12:22:29 -04:00
}
else{
fprintf(stderr, "error: unrecognized driving force '%s'\n",rhs);
return(-1);
}
}
// initial condition
else if (strcmp(lhs,"init")==0){
if (strcmp(rhs,"random")==0){
parameters->init=INIT_RANDOM;
}
else if (strcmp(rhs,"gaussian")==0){
parameters->init=INIT_GAUSSIAN;
}
// matches any argument that starts with 'file:'
else if (strncmp(rhs,"file:",5)==0){
parameters->init=INIT_FILE;
2023-11-03 16:04:53 -04:00
str_to_dstring_noinit(rhs+5,initfile_str);
}
// matches any argument that starts with 'file_txt:'
else if (strncmp(rhs,"file_txt:",9)==0){
parameters->init=INIT_FILE_TXT;
2023-11-03 16:04:53 -04:00
str_to_dstring_noinit(rhs+9,initfile_str);
}
else{
fprintf(stderr, "error: unrecognized initial condition '%s'\n",rhs);
return(-1);
}
}
2023-04-26 11:27:03 -04:00
// algorithm
else if (strcmp(lhs,"algorithm")==0){
if (strcmp(rhs,"RK4")==0){
parameters->algorithm=ALGORITHM_RK4;
}
else if (strcmp(rhs,"RK2")==0){
parameters->algorithm=ALGORITHM_RK2;
}
2023-05-15 20:29:06 -04:00
else if (strcmp(rhs,"RKF45")==0){
parameters->algorithm=ALGORITHM_RKF45;
}
2023-05-17 17:41:00 -04:00
else if (strcmp(rhs,"RKDP54")==0){
parameters->algorithm=ALGORITHM_RKDP54;
}
2023-05-17 16:59:15 -04:00
else if (strcmp(rhs,"RKBS32")==0){
parameters->algorithm=ALGORITHM_RKBS32;
2023-05-17 16:47:15 -04:00
}
2023-04-26 11:27:03 -04:00
else{
fprintf(stderr, "error: unrecognized algorithm '%s'\n",rhs);
return(-1);
}
}
2023-06-29 16:58:33 -04:00
else if (strcmp(lhs,"keep_en_cst")==0){
int tmp;
ret=sscanf(rhs,"%d",&tmp);
if(ret!=1 || (tmp!=0 && tmp!=1)){
fprintf(stderr, "error: parameter 'keep_en_cst' should be 0 or 1\n got '%s'\n",rhs);
return(-1);
}
parameters->keep_en_cst=(tmp==1);
}
2022-05-18 09:57:06 +02:00
else{
fprintf(stderr, "error: unrecognized parameter '%s'\n",lhs);
return(-1);
}
2018-01-11 22:48:14 +00:00
return(0);
}
2022-05-26 15:05:30 -04:00
// read args from file
int args_from_file(
2023-11-03 16:04:53 -04:00
dstring* params,
unsigned int* command,
unsigned int* nthreads,
2023-11-03 16:04:53 -04:00
dstring* savefile_str,
dstring* utfile_str,
char* file_str
){
2023-11-03 16:45:51 -04:00
dstring line;
char c;
// open file
FILE* file=fopen(file_str,"r");
if(file==NULL){
fprintf(stderr,"Error opening file '%s' for reading: %s\n", file_str, strerror(errno));
return(-1);
}
// allocate line buffer
2023-11-03 16:45:51 -04:00
dstring_init(&line,64);
while(1){
c=fgetc(file);
// end of file
if (feof(file)){
break;
}
// newline: read line and reset buffer
if(c=='\n' || c=='\r'){
// read entry
// ignore lines with fewer than three characters
2023-11-03 16:45:51 -04:00
if(line.length>=3){
// find line starting with "#!"
2023-11-03 16:45:51 -04:00
if(line.string[0]=='#' && line.string[1]=='!'){
wordexp_t pwordexp;
2023-11-03 16:45:51 -04:00
wordexp(line.string+2,&pwordexp,0);
// read arguments
read_args(pwordexp.we_wordc, (const char **)pwordexp.we_wordv, params, command, nthreads, savefile_str, utfile_str, NULL);
wordfree(&pwordexp);
// exit
break;
}
}
// reset buffer
2023-11-03 16:45:51 -04:00
line.length=0;
}
// add to buffer
else {
2023-11-03 16:45:51 -04:00
dstring_append(c,&line);
}
}
2023-11-03 16:45:51 -04:00
dstring_free(line);
// close file
fclose(file);
return(0);
}
// set driving force
_Complex double* set_driving(
nstrophy_parameters parameters
){
2023-04-25 17:51:14 -04:00
_Complex double* g=calloc(sizeof(_Complex double),parameters.K1*(2*parameters.K2+1)+parameters.K2);
switch(parameters.driving){
case DRIVING_ZERO:
g_zero(g, parameters.K1, parameters.K2);
break;
case DRIVING_TEST:
g_test(g, parameters.K1, parameters.K2);
break;
2023-04-24 12:22:29 -04:00
case DRIVING_FILE:
init_file_bin(g, parameters.K1, parameters.K2, parameters.drivingfile);
break;
case DRIVING_FILE_TXT:
init_file_txt(g, parameters.K1, parameters.K2, parameters.drivingfile);
break;
default:
g_test(g, parameters.K1, parameters.K2);
break;
}
return g;
}
2022-05-26 15:05:30 -04:00
// set initial condition
_Complex double* set_init(
2023-05-15 20:29:06 -04:00
nstrophy_parameters* parameters
2022-05-26 15:05:30 -04:00
){
2023-05-15 20:29:06 -04:00
_Complex double* u0=calloc(sizeof(_Complex double),parameters->K1*(2*parameters->K2+1)+parameters->K2);
2022-05-26 15:05:30 -04:00
2023-05-15 20:29:06 -04:00
switch(parameters->init){
2022-05-26 15:05:30 -04:00
case INIT_RANDOM:
2023-05-15 20:29:06 -04:00
init_random(u0, parameters->init_en, parameters->K1, parameters->K2, parameters->L, parameters->seed, parameters->irreversible);
2022-05-26 15:05:30 -04:00
break;
case INIT_GAUSSIAN:
2023-05-15 20:29:06 -04:00
init_gaussian(u0, parameters->init_en, parameters->K1, parameters->K2, parameters->L, parameters->irreversible);
2022-05-26 15:05:30 -04:00
break;
2022-05-27 16:09:17 -04:00
case INIT_FILE:
2023-05-15 20:29:06 -04:00
init_file_bin(u0, parameters->K1, parameters->K2, parameters->initfile);
// read start time
fread(&(parameters->starting_time), sizeof(double), 1, parameters->initfile);
2023-05-15 20:29:06 -04:00
if(parameters->algorithm>ALGORITHM_ADAPTIVE_THRESHOLD){
// read delta
fread(&(parameters->delta), sizeof(double), 1, parameters->initfile);
}
break;
case INIT_FILE_TXT:
2023-05-15 20:29:06 -04:00
init_file_txt(u0, parameters->K1, parameters->K2, parameters->initfile);
2022-05-27 16:09:17 -04:00
break;
2022-05-26 15:05:30 -04:00
default:
2023-05-15 20:29:06 -04:00
init_gaussian(u0, parameters->init_en, parameters->K1, parameters->K2, parameters->L, parameters->irreversible);
2022-05-26 15:05:30 -04:00
break;
}
return u0;
}