Compare commits

..

10 Commits

7 changed files with 230 additions and 233 deletions

View File

@@ -40,12 +40,14 @@ The available commands are
* `enstrophy`: to compute the enstrophy and various other observables. This * `enstrophy`: to compute the enstrophy and various other observables. This
command prints command prints
``` ```
step_index time average(alpha) average(energy) average(enstrophy) alpha energy enstrophy step_index time average(alpha) average(energy) average(enstrophy) alpha energy enstrophy Re(u(1,1)) Re(u(1,2))
``` ```
where the averages are running averages over `print_freq`. In addition, if where the averages are running averages over `print_freq`. In addition, if
the algorithm has an adaptive step, an extra column is printed with `delta`. the algorithm has an adaptive step, an extra column is printed with `delta`.
In addition, if alpha has a negative value (even in between `print_freq` In addition, if alpha has a negative value (even in between `print_freq`
intervals), a line is printed with the information. intervals), a line is printed with the information. The two components (1,1)
and (1,2) of u are included to more easily identify periodic trajectories, or
the presence of multiple attractors.
* `lyapunov`: to compute the Lyapunov exponents. This command prints * `lyapunov`: to compute the Lyapunov exponents. This command prints
``` ```
@@ -56,7 +58,14 @@ The available commands are
* `uk`: to compute the Fourier transform of the solution. * `uk`: to compute the Fourier transform of the solution.
* `quiet`: does not print anything, useful for debugging. * `quiet`: does not print anything (useful for debugging).
* `enstrophy_print_init`: to compute the enstrophy and various other
observables for the initial condition (useful for debugging). The command
prints
```
alpha energy enstrophy
```
# Parameters # Parameters
@@ -148,12 +157,12 @@ should be a `;` sperated list of `key=value` pairs. The possible keys are
is negative, its value is printed as a comment. is negative, its value is printed as a comment.
* `lyapunov_reset` (double, default: `print_freq`): if this is set, then, when * `lyapunov_reset` (double, default: `print_freq`): if this is set, then, when
computing the Lyapnuov exponents, the tangent flow will renormalize itself at computing the Lyapunov exponents, the tangent flow will renormalize itself at
times proportional to `lyapunov_reset`. This option is incompatible with times proportional to `lyapunov_reset`. This option is incompatible with
`lyapunov_maxu`. `lyapunov_maxu`.
* `lyapunov_maxu` (double, default: unset): if this is set, then, when * `lyapunov_maxu` (double, default: unset): if this is set, then, when
computing the Lyapnuov exponents, the tangent flow will renormalize itself computing the Lyapunov exponents, the tangent flow will renormalize itself
whenever the norm of the tangent flow exceeds `lyapunov_maxu`. This option whenever the norm of the tangent flow exceeds `lyapunov_maxu`. This option
is incompatible with `lyapunov_reset`. is incompatible with `lyapunov_reset`.
@@ -161,11 +170,6 @@ should be a `;` sperated list of `key=value` pairs. The possible keys are
be `RK4` for Runge-Kutta 4 (default) or `RK2` for Runge-Kutta 2. Adaptive be `RK4` for Runge-Kutta 4 (default) or `RK2` for Runge-Kutta 2. Adaptive
step algorithms cannot be used for the tangent flow. step algorithms cannot be used for the tangent flow.
* `init_flow` (`identity` or `file` (default)): if set to `file`, then read the
initial condition for the tangent flow (used for the Lyapunov exponent
computation) from the init file (the same as for `init`, which needs to be
specified). Otherwise, the flow is initialized as the identity matrix.
# Interrupting and resuming the computation # Interrupting and resuming the computation

View File

@@ -21,6 +21,7 @@ limitations under the License.
#define COMMAND_QUIET 3 #define COMMAND_QUIET 3
#define COMMAND_RESUME 4 #define COMMAND_RESUME 4
#define COMMAND_LYAPUNOV 5 #define COMMAND_LYAPUNOV 5
#define COMMAND_ENSTROPHY_PRINT_INIT 6
#define DRIVING_ZERO 1 #define DRIVING_ZERO 1
#define DRIVING_TEST 2 #define DRIVING_TEST 2

View File

@@ -258,23 +258,38 @@ int remove_entry(
char* rw_ptr; char* rw_ptr;
char* bfr; char* bfr;
char* entry_ptr=entry; char* entry_ptr=entry;
// whether to write the entry
int go=1; int go=1;
// whether the pointer is at the beginning of the entry
int at_top=1;
for(ptr=param_str, rw_ptr=ptr; *ptr!='\0'; ptr++){ for(ptr=param_str, rw_ptr=ptr; *ptr!='\0'; ptr++){
// only match entries if one is at the beginning of an entry
if(at_top==1){
// check that the entry under ptr matches entry
for(bfr=ptr,entry_ptr=entry; *bfr==*entry_ptr; bfr++, entry_ptr++){ for(bfr=ptr,entry_ptr=entry; *bfr==*entry_ptr; bfr++, entry_ptr++){
// check if reached end of entry // check if reached end of entry
if(*(bfr+1)=='=' && *(entry_ptr+1)=='\0'){ if(*(bfr+1)=='=' && *(entry_ptr+1)=='\0'){
// match: do not write entry
go=0; go=0;
break; break;
} }
} }
}
// write entry
if(go==1){ if(go==1){
*rw_ptr=*ptr; *rw_ptr=*ptr;
rw_ptr++; rw_ptr++;
} }
// next iterate will no longer be at the beginning of the entry
at_top=0;
//reset //reset
if(*ptr==';'){ if(*ptr==';'){
go=1; go=1;
at_top=1;
} }
} }
*rw_ptr='\0'; *rw_ptr='\0';
@@ -322,6 +337,8 @@ int save_state(
strcpy(params, params_string); strcpy(params, params_string);
remove_entry(params, "starting_time"); remove_entry(params, "starting_time");
remove_entry(params, "init"); remove_entry(params, "init");
remove_entry(params, "init_enstrophy");
remove_entry(params, "init_energy");
if(algorithm>ALGORITHM_ADAPTIVE_THRESHOLD){ if(algorithm>ALGORITHM_ADAPTIVE_THRESHOLD){
remove_entry(params, "delta"); remove_entry(params, "delta");
} }
@@ -335,10 +352,6 @@ 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

@@ -125,19 +125,20 @@ int lyapunov(
// size of flow (for reset) // size of flow (for reset)
for(i=0;i<MATSIZE;i++){ for(i=0;i<MATSIZE;i++){
for(j=0;j<MATSIZE;j++){ for(j=0;j<MATSIZE;j++){
norm+=fabs(flow[i*MATSIZE+j]); norm+=flow[i*MATSIZE+j]*flow[i*MATSIZE+j]/MATSIZE;
if(norm>lyapunov_reset){ if(sqrt(norm)>lyapunov_reset){
break; break;
} }
} }
if(norm>lyapunov_reset){ if(sqrt(norm)>lyapunov_reset){
break; break;
} }
} }
} }
// QR decomposition // QR decomposition
if((lyapunov_trigger==LYAPUNOV_TRIGGER_TIME && time>(n+1)*lyapunov_reset) || (lyapunov_trigger==LYAPUNOV_TRIGGER_SIZE && norm>lyapunov_reset)){ // Do it also if it is the last step
if((lyapunov_trigger==LYAPUNOV_TRIGGER_TIME && time>(n+1)*lyapunov_reset) || (lyapunov_trigger==LYAPUNOV_TRIGGER_SIZE && norm>lyapunov_reset) || time>=final_time){
n++; n++;
// QR decomposition // QR decomposition
@@ -148,8 +149,8 @@ int lyapunov(
lyapunov[i]=log(fabs(flow[i*MATSIZE+i]))/(time-prevtime); lyapunov[i]=log(fabs(flow[i*MATSIZE+i]))/(time-prevtime);
} }
// sort lyapunov exponents //// sort lyapunov exponents
qsort(lyapunov, MATSIZE, sizeof(double), compare_double); //qsort(lyapunov, MATSIZE, sizeof(double), compare_double);
// average lyapunov // average lyapunov
for(i=0; i<MATSIZE; i++){ for(i=0; i<MATSIZE; i++){
@@ -164,11 +165,11 @@ int lyapunov(
printf("% .15e % .15e % .15e\n",time, lyapunov[i], lyapunov_avg[i]); printf("% .15e % .15e % .15e\n",time, lyapunov[i], lyapunov_avg[i]);
} }
printf("\n"); printf("\n");
fprintf(stderr,"% .15e",time); fprintf(stderr,"% .15e\n",time);
// print largest and smallest lyapunov exponent to stderr //// print largest and smallest lyapunov exponent to stderr
if(MATSIZE>0){ //if(MATSIZE>0){
fprintf(stderr," % .15e % .15e\n", lyapunov[0], lyapunov[MATSIZE-1]); // fprintf(stderr," % .15e % .15e\n", lyapunov[0], lyapunov[MATSIZE-1]);
} //}
// set flow to Q: // set flow to Q:
LAPACKE_dorgqr(LAPACK_COL_MAJOR, MATSIZE, MATSIZE, MATSIZE, flow, MATSIZE, tmp11); LAPACKE_dorgqr(LAPACK_COL_MAJOR, MATSIZE, MATSIZE, MATSIZE, flow, MATSIZE, tmp11);

View File

@@ -63,7 +63,6 @@ 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;
@@ -85,7 +84,7 @@ _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 // set initial tangent flow for lyapunov exponents
int set_lyapunov_flow_init( double** lyapunov_flow0, double** lyapunov_avg0, double* lyapunov_prevtime, double* lyapunov_startingtime, nstrophy_parameters parameters); int set_lyapunov_flow_init( double** lyapunov_flow0, double** lyapunov_avg0, double* lyapunov_prevtime, double* lyapunov_startingtime, bool fromfile, nstrophy_parameters parameters);
// signal handler // signal handler
void sig_handler (int signo); void sig_handler (int signo);
@@ -130,6 +129,7 @@ int main (
dstring resumefile_str; dstring resumefile_str;
FILE* savefile=NULL; FILE* savefile=NULL;
FILE* utfile=NULL; FILE* utfile=NULL;
bool resume=false;
command=0; command=0;
@@ -169,6 +169,8 @@ int main (
// if command is 'resume', then read args from file // if command is 'resume', then read args from file
if(command==COMMAND_RESUME){ if(command==COMMAND_RESUME){
// remember that the original command was resume (to set values from init file)
resume=true;
ret=args_from_file(&param_str, &command, &nthreads, &savefile_str, &utfile_str, dstring_to_str_noinit(&resumefile_str)); ret=args_from_file(&param_str, &command, &nthreads, &savefile_str, &utfile_str, dstring_to_str_noinit(&resumefile_str));
if(ret<0){ if(ret<0){
dstring_free(param_str); dstring_free(param_str);
@@ -232,9 +234,19 @@ int main (
g=set_driving(parameters); g=set_driving(parameters);
// set initial condition // set initial condition
u0=set_init(&parameters); u0=set_init(&parameters);
// read extra values from init file when resuming a computation
if(resume){
// read start time
fread(&(parameters.starting_time), sizeof(double), 1, parameters.initfile);
// if adaptive step algorithm
if(parameters.algorithm>ALGORITHM_ADAPTIVE_THRESHOLD){
// read delta
fread(&(parameters.delta), sizeof(double), 1, parameters.initfile);
}
}
// set initial condition for the lyapunov flow // set initial condition for the lyapunov flow
if (command==COMMAND_LYAPUNOV){ if (command==COMMAND_LYAPUNOV){
set_lyapunov_flow_init(&lyapunov_flow0, &lyapunov_avg0, &lyapunov_prevtime, &lyapunov_startingtime, parameters); set_lyapunov_flow_init(&lyapunov_flow0, &lyapunov_avg0, &lyapunov_prevtime, &lyapunov_startingtime, resume, 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
@@ -305,7 +317,7 @@ int main (
// run command // run command
if (command==COMMAND_UK){ if (command==COMMAND_UK){
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_cost, u0, g, parameters.irreversible, parameters.keep_en_cst, parameters.init_enstrophy, parameters.algorithm, parameters.print_freq, parameters.starting_time, nthreads, savefile); 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_cost, u0, g, parameters.irreversible, parameters.keep_en_cst, parameters.init_enstrophy, 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));
} }
else if(command==COMMAND_ENSTROPHY){ else if(command==COMMAND_ENSTROPHY){
// register signal handler to handle aborts // register signal handler to handle aborts
@@ -313,6 +325,9 @@ int main (
signal(SIGTERM, sig_handler); signal(SIGTERM, sig_handler);
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_cost, u0, g, parameters.irreversible, parameters.keep_en_cst, parameters.init_enstrophy, parameters.algorithm, parameters.print_freq, parameters.starting_time, parameters.print_alpha, nthreads, savefile, utfile, (char*)argv[0], dstring_to_str_noinit(&param_str), dstring_to_str_noinit(&savefile_str), dstring_to_str_noinit(&utfile_str)); 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_cost, u0, g, parameters.irreversible, parameters.keep_en_cst, parameters.init_enstrophy, parameters.algorithm, parameters.print_freq, parameters.starting_time, parameters.print_alpha, nthreads, 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==COMMAND_ENSTROPHY_PRINT_INIT){
enstrophy_print_init(parameters.K1, parameters.K2, parameters.L, u0, g);
}
else if(command==COMMAND_QUIET){ else if(command==COMMAND_QUIET){
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);
} }
@@ -549,6 +564,9 @@ int read_args(
else if(strcmp(argv[i], "enstrophy")==0){ else if(strcmp(argv[i], "enstrophy")==0){
*command=COMMAND_ENSTROPHY; *command=COMMAND_ENSTROPHY;
} }
else if(strcmp(argv[i], "enstrophy_print_init")==0){
*command=COMMAND_ENSTROPHY_PRINT_INIT;
}
else if(strcmp(argv[i], "quiet")==0){ else if(strcmp(argv[i], "quiet")==0){
*command=COMMAND_QUIET; *command=COMMAND_QUIET;
} }
@@ -607,7 +625,6 @@ 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;
@@ -686,12 +703,6 @@ int read_params(
parameters->lyapunov_reset=parameters->print_freq; parameters->lyapunov_reset=parameters->print_freq;
} }
// check that if flow_init is used, then so is init
if(parameters->init_flow_file && parameters->init!=INIT_FILE){
fprintf(stderr, "error: cannot use 'init_flow:file' if 'init' is not a binary file\n");
return(-1);
}
return(0); return(0);
} }
@@ -1011,16 +1022,6 @@ 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);
@@ -1136,12 +1137,6 @@ _Complex double* set_init(
case INIT_FILE: case INIT_FILE:
init_file_bin(u0, parameters->K1, parameters->K2, parameters->initfile); init_file_bin(u0, parameters->K1, parameters->K2, parameters->initfile);
// read start time
fread(&(parameters->starting_time), sizeof(double), 1, parameters->initfile);
if(parameters->algorithm>ALGORITHM_ADAPTIVE_THRESHOLD){
// read delta
fread(&(parameters->delta), sizeof(double), 1, parameters->initfile);
}
break; break;
case INIT_FILE_TXT: case INIT_FILE_TXT:
@@ -1183,12 +1178,14 @@ int set_lyapunov_flow_init(
double** lyapunov_avg0, double** lyapunov_avg0,
double* lyapunov_prevtime, double* lyapunov_prevtime,
double* lyapunov_startingtime, double* lyapunov_startingtime,
bool fromfile, // whether to initialize from file
nstrophy_parameters parameters 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_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)); *lyapunov_avg0=calloc(2*(parameters.K1*(2*parameters.K2+1)+parameters.K2),sizeof(double));
if(parameters.init_flow_file){ // read from file or init from identity matrix
if(fromfile){
// read flow // read flow
read_mat2_bin(*lyapunov_flow0, parameters.K1, parameters.K2, parameters.initfile); read_mat2_bin(*lyapunov_flow0, parameters.K1, parameters.K2, parameters.initfile);
// read time of last QR decomposition // read time of last QR decomposition

View File

@@ -23,6 +23,8 @@ limitations under the License.
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define USIZE (K1*(2*K2+1)+K2)
// compute solution as a function of time // compute solution as a function of time
int uk( int uk(
int K1, int K1,
@@ -46,7 +48,13 @@ int uk(
double print_freq, double print_freq,
double starting_time, double starting_time,
unsigned int nthreads, unsigned int nthreads,
FILE* savefile FILE* savefile,
FILE* utfile,
// for interrupt recovery
const char* cmd_string,
const char* params_string,
const char* savefile_string,
const char* utfile_string
){ ){
_Complex double* u; _Complex double* u;
_Complex double* tmp1; _Complex double* tmp1;
@@ -93,7 +101,6 @@ int uk(
ns_step(algorithm, u, K1, K2, N1, N2, nu, &step, &next_step, adaptive_tolerance, adaptive_factor, max_delta, adaptive_cost, L, g, time, starting_time, fft1, fft2, ifft, &tmp1, &tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, irreversible, keep_en_cst, target_en); ns_step(algorithm, u, K1, K2, N1, N2, nu, &step, &next_step, adaptive_tolerance, adaptive_factor, max_delta, adaptive_cost, L, g, time, starting_time, fft1, fft2, ifft, &tmp1, &tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, irreversible, keep_en_cst, target_en);
time+=step; time+=step;
step=next_step;
if(time>(n+1)*print_freq){ if(time>(n+1)*print_freq){
n++; n++;
@@ -113,11 +120,25 @@ int uk(
fprintf(stderr,"\n"); fprintf(stderr,"\n");
printf("\n"); printf("\n");
} }
// get ready for next step
step=next_step;
// catch abort signal
if (g_abort){
break;
}
} }
// TODO: update handling of savefile // TODO: update handling of savefile
// save final entry to savefile if(savefile!=NULL){
write_vec_bin(u, K1, K2, savefile); save_state(u, savefile, K1, K2, cmd_string, params_string, savefile_string, utfile_string, utfile, COMMAND_UK, algorithm, step, time, nthreads);
}
// save final u to utfile in txt format
if(utfile!=NULL){
write_vec(u, K1, K2, utfile);
}
ns_free_tmps(u, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, fft1, fft2, ifft, algorithm); ns_free_tmps(u, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, fft1, fft2, ifft, algorithm);
return(0); return(0);
@@ -223,11 +244,19 @@ int enstrophy(
// print to stderr so user can follow along // print to stderr so user can follow along
if(algorithm>ALGORITHM_ADAPTIVE_THRESHOLD){ if(algorithm>ALGORITHM_ADAPTIVE_THRESHOLD){
fprintf(stderr,"% .8e % .8e % .8e % .8e % .8e % .8e % .8e % .8e\n",time, avg_a, avg_energy, avg_enstrophy, alpha, energy, enstrophy, step); fprintf(stderr,"% .8e % .8e % .8e % .8e % .8e % .8e % .8e % .8e\n",time, avg_a, avg_energy, avg_enstrophy, alpha, energy, enstrophy, step);
if(K1>=1 && K2>=2){
printf("% .15e % .15e % .15e % .15e % .15e % .15e % .15e % .15e % .15e % .15e\n",time, avg_a, avg_energy, avg_enstrophy, alpha, energy, enstrophy, step, __real__ u[klookup_sym(1,1,K2)], __real__ u[klookup_sym(1,2,K2)]);
}else{
printf("% .15e % .15e % .15e % .15e % .15e % .15e % .15e % .15e\n",time, avg_a, avg_energy, avg_enstrophy, alpha, energy, enstrophy, step); printf("% .15e % .15e % .15e % .15e % .15e % .15e % .15e % .15e\n",time, avg_a, avg_energy, avg_enstrophy, alpha, energy, enstrophy, step);
}
} else { } else {
fprintf(stderr,"% .8e % .8e % .8e % .8e % .8e % .8e % .8e\n",time, avg_a, avg_energy, avg_enstrophy, alpha, energy, enstrophy); fprintf(stderr,"% .8e % .8e % .8e % .8e % .8e % .8e % .8e\n",time, avg_a, avg_energy, avg_enstrophy, alpha, energy, enstrophy);
if(K1>=1 && K2>=2){
printf("% .15e % .15e % .15e % .15e % .15e % .15e % .15e % .15e % .15e\n",time, avg_a, avg_energy, avg_enstrophy, alpha, energy, enstrophy, __real__ u[klookup_sym(1,1,K2)], __real__ u[klookup_sym(1,2,K2)]);
}else{
printf("% .15e % .15e % .15e % .15e % .15e % .15e % .15e\n",time, avg_a, avg_energy, avg_enstrophy, alpha, energy, enstrophy); printf("% .15e % .15e % .15e % .15e % .15e % .15e % .15e\n",time, avg_a, avg_energy, avg_enstrophy, alpha, energy, enstrophy);
} }
}
// reset averages // reset averages
avg_a=0; avg_a=0;
@@ -268,6 +297,25 @@ int enstrophy(
return(0); return(0);
} }
// compute enstrophy, alpha for the initial condition (useful for debugging)
int enstrophy_print_init(
int K1,
int K2,
double L,
_Complex double* u0,
_Complex double* g
){
double alpha, enstrophy, energy;
alpha=compute_alpha(u0, K1, K2, g, L);
enstrophy=compute_enstrophy(u0, K1, K2, L);
energy=compute_energy(u0, K1, K2);
// print
printf("% .15e % .15e % .15e\n", alpha, energy, enstrophy);
return(0);
}
// compute solution as a function of time, but do not print anything (useful for debugging) // compute solution as a function of time, but do not print anything (useful for debugging)
int quiet( int quiet(
int K1, int K1,
@@ -353,30 +401,30 @@ int ns_init_tmps(
unsigned int algorithm unsigned int algorithm
){ ){
// velocity field // velocity field
*u=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *u=calloc(USIZE,sizeof(_Complex double));
// allocate tmp vectors for computation // allocate tmp vectors for computation
if(algorithm==ALGORITHM_RK2){ if(algorithm==ALGORITHM_RK2){
*tmp1=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp1=calloc(USIZE,sizeof(_Complex double));
*tmp2=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp2=calloc(USIZE,sizeof(_Complex double));
} else if (algorithm==ALGORITHM_RK4){ } else if (algorithm==ALGORITHM_RK4){
*tmp1=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp1=calloc(USIZE,sizeof(_Complex double));
*tmp2=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp2=calloc(USIZE,sizeof(_Complex double));
*tmp3=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp3=calloc(USIZE,sizeof(_Complex double));
} else if (algorithm==ALGORITHM_RKF45 || algorithm==ALGORITHM_RKDP54){ } else if (algorithm==ALGORITHM_RKF45 || algorithm==ALGORITHM_RKDP54){
*tmp1=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp1=calloc(USIZE,sizeof(_Complex double));
*tmp2=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp2=calloc(USIZE,sizeof(_Complex double));
*tmp3=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp3=calloc(USIZE,sizeof(_Complex double));
*tmp4=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp4=calloc(USIZE,sizeof(_Complex double));
*tmp5=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp5=calloc(USIZE,sizeof(_Complex double));
*tmp6=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp6=calloc(USIZE,sizeof(_Complex double));
*tmp7=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp7=calloc(USIZE,sizeof(_Complex double));
} else if (algorithm==ALGORITHM_RKBS32){ } else if (algorithm==ALGORITHM_RKBS32){
*tmp1=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp1=calloc(USIZE,sizeof(_Complex double));
*tmp2=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp2=calloc(USIZE,sizeof(_Complex double));
*tmp3=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp3=calloc(USIZE,sizeof(_Complex double));
*tmp4=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp4=calloc(USIZE,sizeof(_Complex double));
*tmp5=calloc(K1*(2*K2+1)+K2,sizeof(_Complex double)); *tmp5=calloc(USIZE,sizeof(_Complex double));
} else { } else {
fprintf(stderr,"bug: unknown algorithm: %u, contact ian.jauslin@rutgers,edu\n",algorithm); fprintf(stderr,"bug: unknown algorithm: %u, contact ian.jauslin@rutgers,edu\n",algorithm);
}; };
@@ -462,7 +510,7 @@ int copy_u(
){ ){
int i; int i;
for(i=0;i<K1*(2*K2+1)+K2;i++){ for(i=0;i<USIZE;i++){
u[i]=u0[i]; u[i]=u0[i];
} }
@@ -524,7 +572,6 @@ int ns_step(
return (0); return (0);
} }
// TODO: do not need to use klookup in any of the rk routines
// RK 4 algorithm // RK 4 algorithm
int ns_step_rk4( int ns_step_rk4(
_Complex double* u, _Complex double* u,
@@ -546,69 +593,53 @@ int ns_step_rk4(
bool keep_en_cst, bool keep_en_cst,
double target_en double target_en
){ ){
int kx,ky; int i;
// k1 // k1
ns_rhs(tmp1, u, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(tmp1, u, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// add to output // add to output
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp3[i]=u[i]+delta/6*tmp1[i];
tmp3[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+delta/6*tmp1[klookup_sym(kx,ky,K2)];
}
} }
// u+h*k1/2 // u+h*k1/2
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp2[i]=u[i]+delta/2*tmp1[i];
tmp2[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+delta/2*tmp1[klookup_sym(kx,ky,K2)];
}
} }
// k2 // k2
ns_rhs(tmp1, tmp2, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(tmp1, tmp2, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// add to output // add to output
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp3[i]+=delta/3*tmp1[i];
tmp3[klookup_sym(kx,ky,K2)]+=delta/3*tmp1[klookup_sym(kx,ky,K2)];
}
} }
// u+h*k2/2 // u+h*k2/2
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp2[i]=u[i]+delta/2*tmp1[i];
tmp2[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+delta/2*tmp1[klookup_sym(kx,ky,K2)];
}
} }
// k3 // k3
ns_rhs(tmp1, tmp2, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(tmp1, tmp2, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// add to output // add to output
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp3[i]+=delta/3*tmp1[i];
tmp3[klookup_sym(kx,ky,K2)]+=delta/3*tmp1[klookup_sym(kx,ky,K2)];
}
} }
// u+h*k3 // u+h*k3
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp2[i]=u[i]+delta*tmp1[i];
tmp2[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+delta*tmp1[klookup_sym(kx,ky,K2)];
}
} }
// k4 // k4
ns_rhs(tmp1, tmp2, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(tmp1, tmp2, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// add to output // add to output
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ u[i]=tmp3[i]+delta/6*tmp1[i];
u[klookup_sym(kx,ky,K2)]=tmp3[klookup_sym(kx,ky,K2)]+delta/6*tmp1[klookup_sym(kx,ky,K2)];
}
} }
// keep enstrophy constant // keep enstrophy constant
if(keep_en_cst){ if(keep_en_cst){
double en=compute_enstrophy(u, K1, K2, L); double en=compute_enstrophy(u, K1, K2, L);
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ u[i]*=sqrt(target_en/en);
u[klookup_sym(kx,ky,K2)]*=sqrt(target_en/en);
}
} }
} }
@@ -635,33 +666,27 @@ int ns_step_rk2(
bool keep_en_cst, bool keep_en_cst,
double target_en double target_en
){ ){
int kx,ky; int i;
// k1 // k1
ns_rhs(tmp1, u, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(tmp1, u, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// u+h*k1/2 // u+h*k1/2
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp2[i]=u[i]+delta/2*tmp1[i];
tmp2[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+delta/2*tmp1[klookup_sym(kx,ky,K2)];
}
} }
// k2 // k2
ns_rhs(tmp1, tmp2, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(tmp1, tmp2, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// add to output // add to output
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ u[i]+=delta*tmp1[i];
u[klookup_sym(kx,ky,K2)]+=delta*tmp1[klookup_sym(kx,ky,K2)];
}
} }
// keep enstrophy constant // keep enstrophy constant
if(keep_en_cst){ if(keep_en_cst){
double en=compute_enstrophy(u, K1, K2, L); double en=compute_enstrophy(u, K1, K2, L);
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ u[i]*=sqrt(target_en/en);
u[klookup_sym(kx,ky,K2)]*=sqrt(target_en/en);
}
} }
} }
@@ -701,7 +726,7 @@ int ns_step_rkf45(
// whether to compute k1 or leave it as is // whether to compute k1 or leave it as is
bool compute_k1 bool compute_k1
){ ){
int kx,ky; int i;
double cost; double cost;
// k1: u(t) // k1: u(t)
@@ -710,53 +735,41 @@ int ns_step_rkf45(
} }
// k2 : u(t+1/4*delta) // k2 : u(t+1/4*delta)
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp[i]=u[i]+(*delta)/4*k1[i];
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)/4*k1[klookup_sym(kx,ky,K2)];
}
} }
ns_rhs(k2, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(k2, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// k3 : u(t+3/8*delta) // k3 : u(t+3/8*delta)
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp[i]=u[i]+(*delta)*(3./32*k1[i]+9./32*k2[i]);
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(3./32*k1[klookup_sym(kx,ky,K2)]+9./32*k2[klookup_sym(kx,ky,K2)]);
}
} }
ns_rhs(k3, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(k3, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// k4 : u(t+12./13*delta) // k4 : u(t+12./13*delta)
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp[i]=u[i]+(*delta)*(1932./2197*k1[i]-7200./2197*k2[i]+7296./2197*k3[i]);
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(1932./2197*k1[klookup_sym(kx,ky,K2)]-7200./2197*k2[klookup_sym(kx,ky,K2)]+7296./2197*k3[klookup_sym(kx,ky,K2)]);
}
} }
ns_rhs(k4, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(k4, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// k5 : u(t+1*delta) // k5 : u(t+1*delta)
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp[i]=u[i]+(*delta)*(439./216*k1[i]-8*k2[i]+3680./513*k3[i]-845./4104*k4[i]);
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(439./216*k1[klookup_sym(kx,ky,K2)]-8*k2[klookup_sym(kx,ky,K2)]+3680./513*k3[klookup_sym(kx,ky,K2)]-845./4104*k4[klookup_sym(kx,ky,K2)]);
}
} }
ns_rhs(k5, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(k5, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// k6 : u(t+1./2*delta) // k6 : u(t+1./2*delta)
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp[i]=u[i]+(*delta)*(-8./27*k1[i]+2*k2[i]-3544./2565*k3[i]+1859./4104*k4[i]-11./40*k5[i]);
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(-8./27*k1[klookup_sym(kx,ky,K2)]+2*k2[klookup_sym(kx,ky,K2)]-3544./2565*k3[klookup_sym(kx,ky,K2)]+1859./4104*k4[klookup_sym(kx,ky,K2)]-11./40*k5[klookup_sym(kx,ky,K2)]);
}
} }
ns_rhs(k6, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(k6, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// next step // next step
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){
// u // u
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(25./216*k1[klookup_sym(kx,ky,K2)]+1408./2565*k3[klookup_sym(kx,ky,K2)]+2197./4104*k4[klookup_sym(kx,ky,K2)]-1./5*k5[klookup_sym(kx,ky,K2)]); tmp[i]=u[i]+(*delta)*(25./216*k1[i]+1408./2565*k3[i]+2197./4104*k4[i]-1./5*k5[i]);
// U: save to k6, which is no longer needed // U: save to k6, which is no longer needed
k6[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(16./135*k1[klookup_sym(kx,ky,K2)]+6656./12825*k3[klookup_sym(kx,ky,K2)]+28561./56430*k4[klookup_sym(kx,ky,K2)]-9./50*k5[klookup_sym(kx,ky,K2)]+2./55*k6[klookup_sym(kx,ky,K2)]); k6[i]=u[i]+(*delta)*(16./135*k1[i]+6656./12825*k3[i]+28561./56430*k4[i]-9./50*k5[i]+2./55*k6[i]);
}
} }
// cost function // cost function
@@ -765,10 +778,8 @@ int ns_step_rkf45(
// compare relative error with tolerance // compare relative error with tolerance
if(cost<tolerance){ if(cost<tolerance){
// copy to output // copy to output
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ u[i]=tmp[i];
u[klookup_sym(kx,ky,K2)]=tmp[klookup_sym(kx,ky,K2)];
}
} }
// next delta to use in future steps (do not exceed max_delta) // next delta to use in future steps (do not exceed max_delta)
*next_delta=fmin(max_delta, (*delta)*pow(tolerance/cost,0.2)); *next_delta=fmin(max_delta, (*delta)*pow(tolerance/cost,0.2));
@@ -776,10 +787,8 @@ int ns_step_rkf45(
// keep enstrophy constant // keep enstrophy constant
if(keep_en_cst){ if(keep_en_cst){
double en=compute_enstrophy(u, K1, K2, L); double en=compute_enstrophy(u, K1, K2, L);
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ u[i]*=sqrt(target_en/en);
u[klookup_sym(kx,ky,K2)]*=sqrt(target_en/en);
}
} }
} }
} }
@@ -826,7 +835,7 @@ int ns_step_rkbs32(
// whether to compute k1 // whether to compute k1
bool compute_k1 bool compute_k1
){ ){
int kx,ky; int i;
double cost; double cost;
// k1: u(t) // k1: u(t)
@@ -836,36 +845,28 @@ int ns_step_rkbs32(
} }
// k2 : u(t+1/4*delta) // k2 : u(t+1/4*delta)
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp[i]=u[i]+(*delta)/2*(*k1)[i];
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)/2*(*k1)[klookup_sym(kx,ky,K2)];
}
} }
ns_rhs(k2, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(k2, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// k3 : u(t+3/4*delta) // k3 : u(t+3/4*delta)
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp[i]=u[i]+(*delta)*(3./4*k2[i]);
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(3./4*k2[klookup_sym(kx,ky,K2)]);
}
} }
ns_rhs(k3, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(k3, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// k4 : u(t+delta) // k4 : u(t+delta)
// tmp computed here is the next step // tmp computed here is the next step
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp[i]=u[i]+(*delta)*(2./9*(*k1)[i]+1./3*k2[i]+4./9*k3[i]);
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(2./9*(*k1)[klookup_sym(kx,ky,K2)]+1./3*k2[klookup_sym(kx,ky,K2)]+4./9*k3[klookup_sym(kx,ky,K2)]);
}
} }
ns_rhs(*k4, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(*k4, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// next step // next step
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){
// U: store in k3, which is no longer needed // U: store in k3, which is no longer needed
k3[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(7./24*(*k1)[klookup_sym(kx,ky,K2)]+1./4*k2[klookup_sym(kx,ky,K2)]+1./3*k3[klookup_sym(kx,ky,K2)]+1./8*(*k4)[klookup_sym(kx,ky,K2)]); k3[i]=u[i]+(*delta)*(7./24*(*k1)[i]+1./4*k2[i]+1./3*k3[i]+1./8*(*k4)[i]);
}
} }
// compute cost // compute cost
@@ -874,10 +875,8 @@ int ns_step_rkbs32(
// compare cost with tolerance // compare cost with tolerance
if(cost<tolerance){ if(cost<tolerance){
// add to output // add to output
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ u[i]=tmp[i];
u[klookup_sym(kx,ky,K2)]=tmp[klookup_sym(kx,ky,K2)];
}
} }
// next delta to use in future steps (do not exceed max_delta) // next delta to use in future steps (do not exceed max_delta)
*next_delta=fmin(max_delta, (*delta)*pow(tolerance/cost,1./3)); *next_delta=fmin(max_delta, (*delta)*pow(tolerance/cost,1./3));
@@ -890,10 +889,8 @@ int ns_step_rkbs32(
// keep enstrophy constant // keep enstrophy constant
if(keep_en_cst){ if(keep_en_cst){
double en=compute_enstrophy(u, K1, K2, L); double en=compute_enstrophy(u, K1, K2, L);
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ u[i]*=sqrt(target_en/en);
u[klookup_sym(kx,ky,K2)]*=sqrt(target_en/en);
}
} }
} }
} }
@@ -941,7 +938,7 @@ int ns_step_rkdp54(
// whether to compute k1 // whether to compute k1
bool compute_k1 bool compute_k1
){ ){
int kx,ky; int i;
double cost; double cost;
// k1: u(t) // k1: u(t)
@@ -951,61 +948,47 @@ int ns_step_rkdp54(
} }
// k2 : u(t+1/5*delta) // k2 : u(t+1/5*delta)
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp[i]=u[i]+(*delta)/5*(*k1)[i];
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)/5*(*k1)[klookup_sym(kx,ky,K2)];
}
} }
ns_rhs(*k2, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(*k2, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// k3 : u(t+3/10*delta) // k3 : u(t+3/10*delta)
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp[i]=u[i]+(*delta)*(3./40*(*k1)[i]+9./40*(*k2)[i]);
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(3./40*(*k1)[klookup_sym(kx,ky,K2)]+9./40*(*k2)[klookup_sym(kx,ky,K2)]);
}
} }
ns_rhs(k3, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(k3, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// k4 : u(t+4/5*delta) // k4 : u(t+4/5*delta)
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp[i]=u[i]+(*delta)*(44./45*(*k1)[i]-56./15*(*k2)[i]+32./9*k3[i]);
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(44./45*(*k1)[klookup_sym(kx,ky,K2)]-56./15*(*k2)[klookup_sym(kx,ky,K2)]+32./9*k3[klookup_sym(kx,ky,K2)]);
}
} }
ns_rhs(k4, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(k4, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// k5 : u(t+8/9*delta) // k5 : u(t+8/9*delta)
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp[i]=u[i]+(*delta)*(19372./6561*(*k1)[i]-25360./2187*(*k2)[i]+64448./6561*k3[i]-212./729*k4[i]);
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(19372./6561*(*k1)[klookup_sym(kx,ky,K2)]-25360./2187*(*k2)[klookup_sym(kx,ky,K2)]+64448./6561*k3[klookup_sym(kx,ky,K2)]-212./729*k4[klookup_sym(kx,ky,K2)]);
}
} }
ns_rhs(k5, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(k5, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// k6 : u(t+delta) // k6 : u(t+delta)
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ tmp[i]=u[i]+(*delta)*(9017./3168*(*k1)[i]-355./33*(*k2)[i]+46732./5247*k3[i]+49./176*k4[i]-5103./18656*k5[i]);
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(9017./3168*(*k1)[klookup_sym(kx,ky,K2)]-355./33*(*k2)[klookup_sym(kx,ky,K2)]+46732./5247*k3[klookup_sym(kx,ky,K2)]+49./176*k4[klookup_sym(kx,ky,K2)]-5103./18656*k5[klookup_sym(kx,ky,K2)]);
}
} }
ns_rhs(k6, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(k6, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
// k7 : u(t+delta) // k7 : u(t+delta)
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){
// tmp computed here is the step // tmp computed here is the step
tmp[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(35./384*(*k1)[klookup_sym(kx,ky,K2)]+500./1113*k3[klookup_sym(kx,ky,K2)]+125./192*k4[klookup_sym(kx,ky,K2)]-2187./6784*k5[klookup_sym(kx,ky,K2)]+11./84*k6[klookup_sym(kx,ky,K2)]); tmp[i]=u[i]+(*delta)*(35./384*(*k1)[i]+500./1113*k3[i]+125./192*k4[i]-2187./6784*k5[i]+11./84*k6[i]);
}
} }
// store in k2, which is not needed anymore // store in k2, which is not needed anymore
ns_rhs(*k2, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible); ns_rhs(*k2, tmp, K1, K2, N1, N2, nu, L, g, fft1, fft2, ifft, irreversible);
//next step //next step
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){
// U: store in k6, which is not needed anymore // U: store in k6, which is not needed anymore
k6[klookup_sym(kx,ky,K2)]=u[klookup_sym(kx,ky,K2)]+(*delta)*(5179./57600*(*k1)[klookup_sym(kx,ky,K2)]+7571./16695*k3[klookup_sym(kx,ky,K2)]+393./640*k4[klookup_sym(kx,ky,K2)]-92097./339200*k5[klookup_sym(kx,ky,K2)]+187./2100*k6[klookup_sym(kx,ky,K2)]+1./40*(*k2)[klookup_sym(kx,ky,K2)]); k6[i]=u[i]+(*delta)*(5179./57600*(*k1)[i]+7571./16695*k3[i]+393./640*k4[i]-92097./339200*k5[i]+187./2100*k6[i]+1./40*(*k2)[i]);
}
} }
// compute cost // compute cost
@@ -1014,10 +997,8 @@ int ns_step_rkdp54(
// compare relative error with tolerance // compare relative error with tolerance
if(cost<tolerance){ if(cost<tolerance){
// add to output // add to output
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ u[i]=tmp[i];
u[klookup_sym(kx,ky,K2)]=tmp[klookup_sym(kx,ky,K2)];
}
} }
// next delta to use in future steps (do not exceed max_delta) // next delta to use in future steps (do not exceed max_delta)
*next_delta=fmin(max_delta, (*delta)*pow(tolerance/cost,0.2)); *next_delta=fmin(max_delta, (*delta)*pow(tolerance/cost,0.2));
@@ -1030,10 +1011,8 @@ int ns_step_rkdp54(
// keep enstrophy constant // keep enstrophy constant
if(keep_en_cst){ if(keep_en_cst){
double en=compute_enstrophy(u, K1, K2, L); double en=compute_enstrophy(u, K1, K2, L);
for(kx=0;kx<=K1;kx++){ for(i=0;i<USIZE;i++){
for(ky=(kx>0 ? -K2 : 1);ky<=K2;ky++){ u[i]*=sqrt(target_en/en);
u[klookup_sym(kx,ky,K2)]*=sqrt(target_en/en);
}
} }
} }
} }
@@ -1138,7 +1117,7 @@ int ns_rhs(
alpha=compute_alpha(u,K1,K2,g,L); alpha=compute_alpha(u,K1,K2,g,L);
} }
for(i=0; i<K1*(2*K2+1)+K2; i++){ for(i=0; i<USIZE; i++){
out[i]=0; out[i]=0;
} }
for(kx=0;kx<=K1;kx++){ for(kx=0;kx<=K1;kx++){

View File

@@ -31,10 +31,12 @@ typedef struct fft_vects {
} fft_vect; } fft_vect;
// compute u_k // compute u_k
int uk( int K1, int K2, int N1, int N2, double final_time, 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, double print_freq, double starting_time, unsigned int nthreadsl, FILE* savefile); int uk( int K1, int K2, int N1, int N2, double final_time, 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, double print_freq, double starting_time, unsigned int nthreadsl, FILE* savefile, FILE* utfile, const char* cmd_string, const char* params_string, const char* savefile_string, const char* utfile_string);
// compute enstrophy and alpha // compute enstrophy and alpha
int enstrophy( int K1, int K2, int N1, int N2, double final_time, 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, double print_freq, double starting_time, bool print_alpha, unsigned int nthreads, FILE* savefile, FILE* utfile, const char* cmd_string, const char* params_string, const char* savefile_string, const char* utfile_string); int enstrophy( int K1, int K2, int N1, int N2, double final_time, 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, double print_freq, double starting_time, bool print_alpha, unsigned int nthreads, FILE* savefile, FILE* utfile, const char* cmd_string, const char* params_string, const char* savefile_string, const char* utfile_string);
// compute enstrophy, alpha for the initial condition (useful for debugging)
int enstrophy_print_init( int K1, int K2, double L, _Complex double* u0, _Complex double* g);
// compute solution as a function of time, but do not print anything (useful for debugging) // compute solution as a function of time, but do not print anything (useful for debugging)
int quiet( int K1, int K2, int N1, int N2, double final_time, double nu, double delta, double L, double adaptive_tolerance, double adaptive_factor, double max_delta, unsigned int adaptive_cost, double starting_time, _Complex double* u0, _Complex double* g, bool irreversible, bool keep_en_cst, double target_en, unsigned int algorithm, unsigned int nthreads, FILE* savefile); int quiet( int K1, int K2, int N1, int N2, double final_time, double nu, double delta, double L, double adaptive_tolerance, double adaptive_factor, double max_delta, unsigned int adaptive_cost, double starting_time, _Complex double* u0, _Complex double* g, bool irreversible, bool keep_en_cst, double target_en, unsigned int algorithm, unsigned int nthreads, FILE* savefile);