1
0
Fork 0
mirror of https://github.com/cosmo-sims/monofonIC.git synced 2024-09-19 17:03:45 +02:00
monofonIC/external/panphasia_ho/high_order_panphasia_routines.c
2021-05-02 22:05:18 +02:00

1863 lines
58 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
#include <string.h>
#include <fftw3-mpi.h>
#include "PAN_FFTW3.h"
#include "panphasia_functions.h"
#include <gsl/gsl_sf_bessel.h>
#include <time.h>
#ifdef USE_OPENMP
#include <omp.h>
#endif
int verbose_warnings_only=0;
static int start_panph_method = 0;
static int panphasia_rel_origin_set = 0;
// Record descriptor parameters //
size_t descriptor_order;
size_t descriptor_base_level;
size_t descriptor_xorigin,descriptor_yorigin,descriptor_zorigin;
size_t descriptor_base_size;
size_t descriptor_kk_limit;
long long int descriptor_check_digit;
char descriptor_name[100];
char full_descriptor[300];
size_t descriptor_read_in;
// Record relative coordinates for a particular descriptor
size_t rel_level;
size_t rel_origin_x, rel_origin_y, rel_origin_z;
size_t rel_coord_max;
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//
// Matrix operations to solve for individual octree cells
//
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
#ifdef MATRICES_ORDER_1
#include "pan_matrices_order1.h"
#elif MATRICES_ORDER_2
#include "pan_matrices_order2.h"
#elif MATRICES_ORDER_3
#include "pan_matrices_order3.h"
#elif MATRICES_ORDER_4
#include "pan_matrices_order4.h"
#elif MATRICES_ORDER_5
#include "pan_matrices_order5.h"
#elif MATRICES_ORDER_0
#include "pan_matrices_order0.h"
#else
#include "pan_matrices_order6.h"
#endif
void solve_panphasia_cell_(PAN_REAL * input_vec_parent, PAN_REAL *input_vec_children, PAN_REAL *output_vec_children, int control_flag)
{
int iparity, iconst, irow, l,i,j;
PAN_REAL element;
PAN_REAL const norm = sqrt(0.125);
PAN_REAL parent_constraint[Nbasis]; //__assume_aligned(&parent_constraint, 64);
PAN_REAL proj_constraint[Nbasis]; //__assume_aligned(&proj_constraint, 64);
PAN_REAL work_vec1[8*Nbasis]; //__assume_aligned(&work_vec1, 64);
PAN_REAL work_vec2[8*Nbasis]; //__assume_aligned(&work_vec2, 64);
//===========================================================================
// Copy inputs and rearrange parent constraints in parity order and set proj_constraint to zero
for (i=0; i<8*Nbasis; i++) work_vec1[i]=input_vec_children[i];
for (i=0; i<Nbasis; i++) {
parent_constraint[i] = input_vec_parent[list_by_parity[i]];
proj_constraint[i]=0;
};
if (control_flag!=-999){ // Special value of -999 turns off linear parental constraint
//(1)=============================================================================
// Compute projection of the constraints on the free child cells by parity
for (iparity=0, irow=0 ; iparity<8; iparity++){
for (iconst=0; iconst<num_constr_by_parity[iparity]; iconst++,irow++){
element = 0;
for (i=0; i<Nbasis; i++){
element+=constraint_matrices[irow][i] * work_vec1[i+Nbasis*iparity];
};
proj_constraint[irow] = element;
// printf("iparity %d irow %d element %f \n",iparity,irow,element);
};
};
//(2)==============================================================================
// Apply parent constraint on children by parity
for (iparity=0, irow=0 ; iparity<8; iparity++){
for (iconst=0; iconst<num_constr_by_parity[iparity]; iconst++,irow++){
for (i=0; i<Nbasis; i++){
work_vec1[i+Nbasis*iparity] = work_vec1[i+Nbasis*iparity] +
constraint_matrices[irow][i] * (parent_constraint[irow]- proj_constraint[irow]);
};
};
};
}; // End control_flag
// Two versions for the 8x8 parity transformation - the latter appears faster
/*
//(3)==== Now apply Nbasis 8x8 parity tranformations ===========
for (l=0; l<Nbasis; l++){
for (i=0; i<8; i++){
element = 0;
for (j=0; j<8; j++) element+=oct_cell_matrices[l][i][j]*work_vec1[Nbasis*j+l];
work_vec2[Nbasis*i+l] = norm * element;
}
}
//(4) Copy back=====================================================================
for (i=0; i<8*Nbasis; i++) output_vec_children[i] = work_vec2[i];
*/
// Alternate version - is it faster? Reorder data to make matrix operation faster
// (3) - reorder the data and then evaluate the matrix multiplications
for (i=0, l=0; i<Nbasis; i++) for(j=0; j<8; j++, l++) work_vec2[l]=work_vec1[j*Nbasis+i];
for (l=0; l<Nbasis; l++){
for (i=0; i<8; i++){
element = 0;
for (j=0; j<8; j++) element+=oct_cell_matrices[l][i][j]*work_vec2[j+8*l];
work_vec1[i+8*l] = norm * element;
}
}
for (i=0, l=0; i<Nbasis; i++) for(j=0; j<8; j++, l++) output_vec_children[j*Nbasis+i] = work_vec1[l];
return;
}
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//
// Box-Mueller transformations
//
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
void box_muller_(PAN_REAL *unif_rand, PAN_REAL *gvar)
{
int i,j,k,count;
const PAN_REAL pi = 4.0*atan(1.0);
const PAN_REAL two_pi = 2.0 * pi;
PAN_REAL unif_real[8*Nbasis]; //__assume_aligned(&unif_real, 64);
PAN_REAL gauss_real[8*Nbasis]; //__assume_aligned(&gauss_real, 64);
// Copy input uniform random numbers to unif_real
for (i=0; i<8*Nbasis;i++) unif_real[i]=unif_rand[i];
count = 8*Nbasis;
//__assume(count % 8 == 0);
for (i=0; i<count; i+=2){
#ifndef PAN_DOUBLE_PRECISION
PAN_REAL radius = sqrtf(-2.f * logf(unif_real[i]));
PAN_REAL angle = two_pi * unif_real[i+1];
gauss_real[i] = radius*cosf(angle);
gauss_real[i+1] = radius*sinf(angle);
#else
PAN_REAL radius = sqrt(-2.0 * log(unif_real[i]));
PAN_REAL angle = two_pi * unif_real[i+1];
gauss_real[i] = radius*cos(angle);
gauss_real[i+1] = radius*sin(angle);
#endif
}
// Copy gauss_real to output
for (i=0; i<8*Nbasis;i++) gvar[i]=gauss_real[i];
return;
}
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//
// Misc routines
//
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
#define NUM_CELLS 1000000
void speed_test2_(){
size_t lev,j1,j2,j3;
size_t N_cells = 1e6;
PAN_REAL parent[Nbasis];
PAN_REAL child[8*Nbasis];
PAN_REAL output[8*Nbasis];
//ticks tick_start = getticks();
//ticks tic_total;
for (int i=0; i<Nbasis; i++) parent[i]=1.0;
threefry4x64_test_(1);
set_panphasia_key_(1);
j1=3530439;
j2=4530202;
lev = 47;
for (j3 =0;j3<N_cells;j3++) compute_all_properties_of_a_panphasia_cell_(&lev,&j1,&j2,&j3,parent,output);
//tic_total = getticks() - tick_start;
//printf("Computed %ld cells in time %.3f %s\n",N_cells,clocks_from_ticks(tic_total),clocks_getunit());
};
//===================================================================================
void compute_all_properties_of_a_panphasia_cell_(size_t *level, size_t *j1, size_t *j2, size_t *j3,
PAN_REAL *gauss_rand_parent,PAN_REAL *legendre_rand) {
// void compute_all_properties_of_a_panphasia_cell_(size_t *level, size_t *j3, size_t *j1, size_t *j2//,
// PAN_REAL *gauss_rand_parent, PAN_REAL *legendre_rand) {
PAN_REAL unif_randoms[8*Nbasis];
PAN_REAL gauss_rand_children[8*Nbasis];
size_t seed_value=0;
size_t allow_non_zero_seed_safety_catch=0;
return_uniform_pseudo_rands_threefry4x64_(*level, *j1, *j2, *j3, unif_randoms,seed_value,allow_non_zero_seed_safety_catch);
box_muller_(unif_randoms,gauss_rand_children);
// if (*level>17) { //ARJ for testing purposes only
// for(int i=0; i<8*Nbasis;i++)gauss_rand_children[i]=0; //ARJ for testing purposes only
// for(int i=56; i<Nbasis;i++)gauss_rand_parent[i]=0; //ARJ for testing purposes only
// };
// if (*level<23) for(int i=0; i<Nbasis;i++)gauss_rand_parent[i]=0; //ARJ for testing purposes only
solve_panphasia_cell_(gauss_rand_parent, gauss_rand_children, legendre_rand, 0);
// if ((*level==62)&&(*j1==0)&&(*j2==0)&&(*j3==2299)){
// if ((*level==61)&&(*j1==0)&&(*j2==0)&&(*j3==1149)){
// printf("Inside compute_all_properties ...\n");
// printf("Level %llu Cell:(%llu,%llu,%llu)\n",*level,*j1,*j2,*j3);
// printf("Start of parent info %f %f %f\n",gauss_rand_parent[0],gauss_rand_parent[1],
// gauss_rand_parent[2]);
// printf("Gauss vals:");for(int i=0;i<8;i++)printf("%f ",gauss_rand_children[Nbasis*i]);
// printf("\n");
// printf("Legendre vals:");for(int i=0;i<8;i++)printf("%f ",legendre_rand[Nbasis*i]);
// printf("\n");
//
//
// };
};
//==================================================================================
void test_random_dist_(size_t ishift) {
const size_t j2 = 988676, l = 62;
size_t j1 = 409 + ishift;
PAN_REAL unif_randoms[8*Nbasis];
PAN_REAL gauss_rand_children[8*Nbasis];
PAN_REAL legendre_rand[8*Nbasis];
PAN_REAL gauss_rand_parent[Nbasis];
size_t seed_value=0;
size_t allow_non_zero_seed_saftey_catch=0;
const size_t NC = 1000000;
double sum_squares=0;
double rms_value;
long long int nrand = 0;
long long int gauss_dist[100]={0};
long long int log_uniform_dist[100]={0};
const int array_offset = 50;
PAN_REAL g_expected;
printf("Generating random numbers...\n");
threefry4x64_test_(1);
set_panphasia_key_(1);
check_panphasia_key_(0);
printf("Nbasis: %d \n", Nbasis);
for (int i=0; i<Nbasis; i++) gauss_rand_parent[i] = 0;
for (int i=0; i<8*Nbasis; i++) gauss_rand_children[i] = 0;
char str1[100], str2[100];
sprintf(str1,"Gaussian_random_distribution_%llu.dat",ishift);
sprintf(str2,"Log_uniform_random_distribution_%llu.dat",ishift);
FILE *file = fopen(str1, "w");
FILE *file2 = fopen(str2, "w");
for(size_t j3=0; j3<NC; j3++) {
if (j3%10000000==0) printf("Looped over %lld\n",j3);
return_uniform_pseudo_rands_threefry4x64_(l,j1, j2, j3, unif_randoms,seed_value,allow_non_zero_seed_saftey_catch);
for(int i=0; i<8*Nbasis;i++){
int j = -logf(unif_randoms[i]);
log_uniform_dist[j]++;
};
box_muller_(unif_randoms,gauss_rand_children);
solve_panphasia_cell_(gauss_rand_parent, gauss_rand_children, legendre_rand, -999);
for(int i=0; i<8*Nbasis;i++,nrand++){
sum_squares += pow(legendre_rand[i],2);
int j = (legendre_rand[i]*5.0 + 0.5) + array_offset;
gauss_dist[j]++;
};
}
rms_value= sqrt(sum_squares/(double)nrand);
printf("Number of rands %ld RMS = %12.10lg Deviation %lg \n",
nrand,rms_value,(rms_value-1.0)*sqrt((double)nrand));
fprintf(file, "Number of rands %ld RMS = %12.10lg Deviation %lg \n",
nrand,rms_value,(rms_value-1.0)*sqrt((double)nrand));
for (int i=0; i<100;i++) {
if (gauss_dist[i]!=0){
g_expected = 0.5*(erf(0.2*sqrt(0.5)*((PAN_REAL)(i-array_offset)+0.5))-erf(0.2*sqrt(0.5)*((PAN_REAL)(i-array_offset)-0.5)))*(PAN_REAL)nrand;
printf("%d %ld %f %f \n",i-array_offset,gauss_dist[i],g_expected,(gauss_dist[i]-g_expected)/sqrt(gauss_dist[i]));
fprintf(file, "%d %ld %f %f \n",i-array_offset,gauss_dist[i],g_expected,(gauss_dist[i]-g_expected)/sqrt(gauss_dist[i]));
};
if (log_uniform_dist[i]!=0){
double expected = ((double)nrand)*(1.0-exp(-1.0))*exp(-(double)i);
fprintf(file2,"%d %llu %lf %lf \n",i,log_uniform_dist[i],expected, ((double)log_uniform_dist[i]-expected)/sqrt(expected) );
};
};
// fprintf(file, "%f %f %f \n", unif_randoms[i],gauss_rand_children[i],legendre_rand[i]);
fclose(file); fclose(file2);
}
//===================================================================================
void speed_test_() {
const size_t l = 61;
PAN_REAL unif_randoms[8*Nbasis];
PAN_REAL gauss_rand_children[8*Nbasis], legendre_rand[8*Nbasis];
PAN_REAL gauss_rand_parent[Nbasis];
size_t seed_value=0;
size_t allow_non_zero_seed_safety_catch=0;
printf("Generating random numbers...\n");
threefry4x64_test_(1);
set_panphasia_key_(1);
check_panphasia_key_(0);
printf("Nbasis: %d \n", Nbasis);
for(int i=0; i<Nbasis; i++) gauss_rand_parent[i]=0; /* Set parent info to zero */
//ticks tic;
//ticks tic_total = getticks();
//ticks uniform_total = 0;
//ticks box_muller_total = 0;
//ticks matrix_total = 0;
size_t j1,j2,j3;
// Time each individual call and sum
for(j1=609090235558, j2=9090000544443, j3=0; j3<NUM_CELLS; j3++,j1++,j2++) {
//tic = getticks();
return_uniform_pseudo_rands_threefry4x64_(l, j1, j2, j3, unif_randoms, seed_value, allow_non_zero_seed_safety_catch);
//uniform_total += getticks()-tic;
//tic = getticks();
box_muller_(unif_randoms,gauss_rand_children);
//box_muller_total += getticks() - tic;
//tic = getticks();
solve_panphasia_cell_(gauss_rand_parent, gauss_rand_children, legendre_rand, 0);
//matrix_total += getticks() - tic;
}
// printf("-------------------------------------------------\n");
// printf(" Timings for %d cells \n", (int)NUM_CELLS);
//printf("-------------------------------------------------\n");
//
//printf("Gen uniform rands: %.3f %s \n",
// clocks_from_ticks(uniform_total), clocks_getunit());
//printf("Box-Muller time: %.3f %s.\n",clocks_from_ticks(box_muller_total), clocks_getunit());
//
//printf("Matrix time: %.3f %s.\n",
// clocks_from_ticks(matrix_total), clocks_getunit());
//printf("Total time: %.3f %s.\n",
// clocks_from_ticks(getticks() - tic_total), clocks_getunit());
//printf("-------------------------------------------------\n");
//
//printf("CPU clock frequency %llu\n",clocks_get_cpufreq());
//
//printf("-------------------------------------------------\n");
FILE *file = fopen("ic_rand.dat", "w");
/* fprintf(file, "Gaussiany Random Numbers %d\n",8*Nbasis);*/
if (sizeof(PAN_REAL)==4) for(int i=0; i<8*Nbasis; i++) fprintf(file, "%15.12f\n", gauss_rand_children[i]);
if (sizeof(PAN_REAL)==8) for(int i=0; i<8*Nbasis; i++) fprintf(file, "%15.12lf\n", gauss_rand_children[i]);
/* fprintf(file, "\nLegendre Random Numbers\n");
fprintf(file, "-----------------------\n");
for(int i=0; i<8*Nbasis; i++) fprintf(file, "%f\n", legendre_rand[i]);*/
fclose(file);
}
//======================================================================================
void check_randoms_() {
const size_t j1 = 4, j2 = 9, l = 34;
PAN_REAL unif_randoms[8*Nbasis];
PAN_REAL gauss_rand_children[8*Nbasis], legendre_rand[8*Nbasis];
PAN_REAL gauss_rand_parent[Nbasis];
size_t seed_value=0;
size_t allow_non_zero_seed_saftey_catch=0;
const int NC = 500; // Not too big as results output to a file ...
printf("Generating random numbers...\n");
threefry4x64_test_(0);
set_panphasia_key_(0);
check_panphasia_key_(0);
printf("Nbasis: %d \n", Nbasis);
// ticks tic_total = getticks();
//ticks rng_total = 0;
//ticks matrix_total = 0;
FILE *file = fopen("ic_sample.dat", "w");
for(int i=0; i<Nbasis; i++) gauss_rand_parent[i]=0.0; /* Set random parent info */
for (int i=0; i<8*Nbasis; i++) gauss_rand_children[i]=0.0; /* Zero child info */
for (int i=0; i<8*Nbasis; i++) unif_randoms[i]=0; /* Zero child info */
for(size_t j3=0; j3<NC; j3++) {
return_uniform_pseudo_rands_threefry4x64_(l, j1, j2, j3, unif_randoms,seed_value,allow_non_zero_seed_saftey_catch);
box_muller_(unif_randoms,gauss_rand_children);
solve_panphasia_cell_(gauss_rand_parent, gauss_rand_children, legendre_rand, 0);
for(int i=0; i<8*Nbasis; i++)
fprintf(file, "%14.9f %14.9f %14.9f \n", unif_randoms[i],gauss_rand_children[i],legendre_rand[i]);
}
fclose(file);
check_panphasia_key_(0); // checks key is unchanged.
}
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//
// Further misc routines
//
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
#include <gsl/gsl_sort_ulong.h>
int demo_descriptor_(){
char str[200] = "[Panph6,L11,(2043,2045,2046),S5,CH-999,Testing_only]"; // xyz
//char str[200] = "[Panph6,L3,(2,3,4),S8,CH-999,Testing_only]"; // xyz
//char str[200] = "[Panph6,L3,(4,2,3),S8,CH-999,Testing_only]"; // xyz
//char str[200] = "[Panph6,L3,(3,4,5),S8,CH-999,Testing_only]"; // xyz
// char str[200] = "[Panph6,L56,(0,0,31),S5,CH-999,Testing_only]";
// char str[200] = "[Panph6,L21,(1136930,890765,1847934),S3,CH2414478110,Auriga_volume2]";
// char str[200] = "[Panph6,L21,(1136930,890765,1847934),S3,CH-999,Auriga_volume2]";
char copy[200];
const char s[20] = "[,L,(),S,CH,]";
char *token;
size_t desc_level, desc_x, desc_y, desc_z,desc_size;
long long int desc_ch;
char desc_name[100];
char desc_iden[8];
int error_code;
descriptor_read_in = 0;
if (error_code = parse_and_validate_descriptor_(str)){
printf("Invalid descriptor %s\n",str);
printf("Descriptor error code %d\n",error_code);
} else {
printf("Valid descriptor parsed %s\n",str);
};
if (descriptor_read_in){
printf("-----------------------------------------\n");
printf("Descriptor order: %llu\n",descriptor_order);
printf("Descriptor base level: %llu\n",descriptor_base_level);
printf("Descriptor x-origin: %llu\n",descriptor_xorigin);
printf("Descriptor y-origin: %llu\n",descriptor_yorigin);
printf("Descriptor z-origin: %llu\n",descriptor_zorigin);
printf("Descriptor base size: %llu\n",descriptor_base_size);
printf("Descriptor check digit:%lld\n",descriptor_check_digit);
printf("Descriptor name %s\n", descriptor_name);
printf("-----------------------------------------\n");
printf("Descriptor %s\n",full_descriptor);
printf("-----------------------------------------\n");
printf("Check digit %lld\n",compute_check_digit_());
};
int verbose=0;
int flag_output_mode=0;
PANPHASIA_init_descriptor_(str,&verbose);
size_t rel_lev = 3;
size_t rel_orig_x = 33; //xyz
size_t rel_orig_y = 17;
size_t rel_orig_z = 9;
//size_t rel_orig_x = 9; //zxy
//size_t rel_orig_y = 33;
//size_t rel_orig_z = 17;
// size_t rel_orig_x = 0;
// size_t rel_orig_y = 0;
// size_t rel_orig_z = 0;
verbose = 0;
if (error_code = PANPHASIA_init_level_(&rel_lev,
&rel_orig_x,&rel_orig_y,&rel_orig_z,&verbose)){
printf("Error %d in initialing PANPHASIA_init_level_\n",
error_code);
return(error_code);
};
size_t xstart = 3, ystart = 5, zstart = 4;
size_t xextent = 27, yextent = 29, zextent=40; // xyz
// size_t xstart = 4, ystart = 3, zstart = 5;
// size_t xextent = 40, yextent = 27, zextent=29;
// size_t xstart = 0, ystart = 0, zstart = 0;
// size_t xextent = 4, yextent = 4, zextent=4;
size_t copy_list[Nbasis];
size_t ncopy=28;
PAN_REAL *output_values = malloc(sizeof(PAN_REAL)*ncopy*xextent*yextent*zextent);
if (output_values==NULL){
printf("Unable to allocate output_values \n");
abort();
};
for (int i=0; i<Nbasis/3; i++) copy_list[i] = 3*i;
if (error_code = PANPHASIA_compute_coefficients_(&xstart,&ystart,&zstart,
&xextent,&yextent,&zextent, copy_list, &ncopy,
output_values, &flag_output_mode, &verbose)){
printf("Error %d in PANPHASIA_compute_coefficients \n",error_code);
return(error_code);
};
if (xextent*yextent*zextent<2097153){
FILE *file = fopen("Panphasia_sample.tex", "w");
for (size_t xco=0;xco<xextent;xco++)for (size_t yco =0;yco<yextent;yco++)for (size_t zco =0;zco<zextent;zco++)
fprintf(file, "%llu %llu %llu %f\n",xco,yco,zco,output_values[ncopy*(xco*yextent*zextent + yco*zextent + zco)]);
fclose(file);
};
return(0);
};
int PANPHASIA_init_descriptor_(char *descriptor,int *verbose)
{
int error;
int verb;
PANPHASIA_init_descriptor_checks();
if (*verbose!=2) {verb = 0;}else{verb=1;};
if (start_panph_method!=1){
printf("=========================================\n");
printf("Unable to start_panphasia_method until\nstart_panphasia_method has been called.\n");
printf("=========================================\n");
abort();
};
threefry4x64_test_(verb);
set_panphasia_key_(verb);
check_panphasia_key_(verb);
if (error = parse_and_validate_descriptor_(descriptor)){
printf("-----------------------------------------\n");
printf("Error initating start-up Panphasia routines \n");
printf("Error code %d\n",error);
printf("-----------------------------------------\n");
abort();
};
if (*verbose) printf("Sucessfully started Panphasia with the descriptor:\n%s\n",descriptor);
return (0);
};
/////////////////////////////////////////////////////////////////////////////////
void PANPHASIA_init_descriptor_checks(){
int verb = 0;
if (start_panph_method==1) return; //Only run these tests once
start_panph_method = 1;
// If any of these tests fail it is not safe to proceed to make initial conditions
// Check that Threefry4x64 reproduces correct results for 20 rounds.
// Takes 3 (counter,key) combinations and checks against the expected
// answer for 20 rounds.
threefry4x64_test_(verb);
// For additional tests below, first check the inverse function for the
// Threefry4x64 function works. The inverse only works up to and including
// 20 rounds.
inverse_threefry4x64_test_(verb);
// Complex test - testing two completely different aspects at the same time.
// The routine generates a series of random cells in the Panphasia
// field. For each random cell it then creates two random descriptors
// for this one cell, and computes the relative coordinates, and
// and relative levels for the cell. For one descriptor the cell
// itself is chosen, while for the second descriptor the children
// of the cell as chosen. The test is to compute the Nbasis
// Legendre coefficients for the random cell by directly evaluating
// the Panphasia field and using Gaussian quadrature to evaluate the
// integrals. The test is passed if the cell and its combined eight
// child cells yield the same Nbasis Legendre coefficients to single/double
// precision. This test both that the descriptor/relative coordinates
// do correctly point to the same cell, and that parent cell information is
// being accurately propograted to the child cells.
//
// The random descriptors are chosen with a minimum side length of
// 1 cell, up to the entire dimension of Panphasia at that level.
//
// The argument determines the number of tests:
//
// 0 - default fast test - choose the random cell at
// levels 0,5,10,...60. One test per level.
// Run time about 1.5 seconds.
//
// N>0 - Do N iterations of the test with 1.
// In May 2020 ran with N=8000 - all tested passed.
// This provides a good test that the doubly periodic
// boundaries (of Panphasia itself, and the region
// covered by the descriptor) are working correctly.
test_propogation_of_moments_(0);
printf("===================================================\n");
printf("Test of Threefry4x64 generator function - PASSED\n");
printf("Test of inverse Threefry4x64 function - PASSED\n");
printf("Test of propogation of moments - PASSED\n");
printf("===================================================\n");
panphasia_rel_origin_set = 0; // Force user to set rel origin themselves.
};
int PANPHASIA_init_level_(size_t *rel_lev,
size_t *rel_orig_x, size_t *rel_orig_y,
size_t *rel_orig_z, int *verbose){
if (*rel_lev>63) return(101);
if (descriptor_base_level+*rel_lev>63) return (102);
if (*rel_orig_x>=(descriptor_base_size<<*rel_lev)) return(103);
if (*rel_orig_y>=(descriptor_base_size<<*rel_lev)) return(104);
if (*rel_orig_z>=(descriptor_base_size<<*rel_lev)) return(105);
// Copy to global set of relative coordinates
rel_level = *rel_lev;
rel_origin_x = *rel_orig_x;
rel_origin_y = *rel_orig_y;
rel_origin_z = *rel_orig_z;
rel_coord_max= descriptor_base_size<<*rel_lev;
if (*verbose){
printf("-----------------------------------------------------------------\n");
printf("Initialising a Panphasia subgrid\n");
printf("Relative level %llu\n",rel_level);
printf("Relative origin (%llu,%llu,%llu)\n",rel_origin_x,rel_origin_y,rel_origin_z);
printf("The maximum possible extent of this subgrid is %llu cells\n",rel_coord_max);
printf("-----------------------------------------------------------------\n");
};
panphasia_rel_origin_set = 1;
return(0);
};
//======================================================================================
//======================================================================================
//======================================================================================
//======================================================================================
//======================================================================================
int PANPHASIA_compute_coefficients_(size_t *xstart, size_t *ystart, size_t*zstart,
size_t *xextent, size_t *yextent, size_t *zextent,
size_t *copy_list,
size_t *ncopy, void *output_values, int *flag_output_mode, int *verbose){
size_t cumulative_cell_index[Nbasis+1];
size_t level_max = descriptor_base_level+rel_level;
size_t cell_memory_to_allocate;
//ticks tic_tot;
//ticks tic_start = getticks();
//================== Basic error checking of input parameters ==========
if (panphasia_rel_origin_set!=1) return(200);
if (*xstart>=rel_coord_max) return(201);
if (*ystart>=rel_coord_max) return(202);
if (*zstart>=rel_coord_max) return(203);
if ((*xextent>rel_coord_max)||(*xextent==0)) return(204);
if ((*yextent>rel_coord_max)||(*yextent==0)) return(205);
if ((*zextent>rel_coord_max)||(*zextent==0)) return(206);
if ((*ncopy<0)||(*ncopy>Nbasis)) return(207);
if ((copy_list[0]<0)||(copy_list[*ncopy-1]>=Nbasis)) return(208);
for (int i=1; i<*ncopy; i++) if (copy_list[i]<=copy_list[i-1]) return(209);
//=======================================================================
// Allocate storage for one dimensional x,y,z cell coordinate lists
//=======================================================================
size_t nreturn_x = 2*(*xextent) + 200;
size_t nreturn_y = 2*(*yextent) + 200;
size_t nreturn_z = 2*(*zextent) + 200;
size_t *ret_x_list_coords = malloc(sizeof(size_t)*nreturn_x);
if (ret_x_list_coords==NULL) return(220);
size_t *ret_y_list_coords = malloc(sizeof(size_t)*nreturn_y);
if (ret_y_list_coords==NULL) return(221);
size_t *ret_z_list_coords = malloc(sizeof(size_t)*nreturn_z);
if (ret_z_list_coords==NULL) return(222);
long long int *child_pointer_x = malloc(sizeof(size_t)*2*nreturn_x);
if (child_pointer_x==NULL) return(223);
long long int *child_pointer_y = malloc(sizeof(size_t)*2*nreturn_y);
if (child_pointer_x==NULL) return(224);
long long int *child_pointer_z = malloc(sizeof(size_t)*2*nreturn_z);
if (child_pointer_z==NULL) return(225);
size_t level_begin_x[64],level_count_x[64];
size_t level_begin_y[64],level_count_y[64];
size_t level_begin_z[64],level_count_z[64];
size_t *index_perm_x = malloc(sizeof(size_t)*nreturn_x);
if (index_perm_x==NULL) return(226);
size_t *index_perm_y = malloc(sizeof(size_t)*nreturn_y);
if (index_perm_y==NULL) return(226);
size_t *index_perm_z = malloc(sizeof(size_t)*nreturn_z);
if (index_perm_z==NULL) return(226);
size_t *list_cell_x_coord = malloc(sizeof(size_t)*(*xextent));
if (list_cell_x_coord==NULL) return(227);
size_t *list_cell_y_coord = malloc(sizeof(size_t)*(*yextent));
if (list_cell_y_coord==NULL) return(228);
size_t *list_cell_z_coord = malloc(sizeof(size_t)*(*zextent));
if (list_cell_z_coord==NULL) return(229);
//================================================================
// Make x,y,z lists of cell coordinates //
//================================================================
{
for (size_t i =0; i<*xextent; i++){
size_t xabs,yabs,zabs;
calc_absolute_coordinates(*xstart+i,*ystart,*zstart,&xabs,&yabs,&zabs);
list_cell_x_coord[i] = xabs;
};
for (size_t i =0; i<*yextent; i++){
size_t xabs,yabs,zabs;
calc_absolute_coordinates(*xstart,*ystart+i,*zstart,&xabs,&yabs,&zabs);
list_cell_y_coord[i] = yabs;
};
for (size_t i =0; i<*zextent; i++){
size_t xabs,yabs,zabs;
calc_absolute_coordinates(*xstart,*ystart,*zstart+i,&xabs,&yabs,&zabs);
list_cell_z_coord[i] = zabs;
};
};
//================================================================
// Generate 1-D binary trees for each of the x,y,z cuboid dimensions
//================================================================
{
int error_code;
if (error_code = return_binary_tree_cell_lists(level_max, list_cell_x_coord,
*xextent, ret_x_list_coords, nreturn_x, child_pointer_x,
level_count_x, level_begin_x, index_perm_x)) return(error_code);
if (error_code = return_binary_tree_cell_lists(level_max, list_cell_y_coord,
*yextent, ret_y_list_coords, nreturn_y, child_pointer_y,
level_count_y, level_begin_y, index_perm_y)) return(error_code);
if (error_code = return_binary_tree_cell_lists(level_max, list_cell_z_coord,
*zextent, ret_z_list_coords, nreturn_z, child_pointer_z,
level_count_z, level_begin_z, index_perm_z)) return(error_code);
};
//===================================================================
// Allocate memory to store all the cell properties
//===================================================================
{
size_t number_of_cells = 0;
for(int i=level_max; i>=0; i--) {
cumulative_cell_index[i] = number_of_cells;
number_of_cells += level_count_x[i]*level_count_y[i]*level_count_z[i];
};
if (*verbose) printf("Total number cells: %llu \n",number_of_cells);
cell_memory_to_allocate = sizeof(PAN_REAL) * number_of_cells * Nbasis;
};
PAN_REAL *working_space = malloc(cell_memory_to_allocate);
if (working_space==NULL) return (210);
//========================================================================================
// Loop over octree starting at the root, for all relevant cells at each level
//========================================================================================
size_t total_number_cells=0;
size_t num_cell_compute=0;
size_t num_level_max_cells=0;
size_t total_num_children=0;
{
size_t cell_index,j1,j2,j3;
size_t child_cells[8];
size_t xoffset,yoffset,zoffset;
size_t ix,iy,iz;
size_t xco,yco,zco;
size_t child_index,work_index,selected_child_index;
size_t i;
PAN_REAL parent[Nbasis];
PAN_REAL children[8*Nbasis];
if (level_max==0) return_root_legendre_coefficients_(working_space); // Return root cell coefficients
#ifdef USE_OPENMP
double start, end;
start = omp_get_wtime();
if (*verbose) printf("Start ...\n");
#endif
for (size_t level=0; level < level_max; level++){
#ifdef USE_OPENMP
#pragma omp parallel for collapse(3) \
private (cell_index,xoffset,yoffset,zoffset,j1,j2,j3,ix,iy,iz, \
xco,yco,zco,child_index,work_index,selected_child_index,i, \
parent,children)
#endif
for (int cell_x=0; cell_x < level_count_x[level]; cell_x++)
for (int cell_y=0; cell_y < level_count_y[level]; cell_y++)
for (int cell_z = 0; cell_z < level_count_z[level]; cell_z++){
cell_index = cumulative_cell_index[level] + cell_x*level_count_y[level]*level_count_z[level]+
cell_y*level_count_z[level] + cell_z;
xoffset = level_begin_x[level] + cell_x;
yoffset = level_begin_y[level] + cell_y;
zoffset = level_begin_z[level] + cell_z;
j1 = ret_x_list_coords[xoffset];
j2 = ret_y_list_coords[yoffset];
j3 = ret_z_list_coords[zoffset];
if (level==0){ return_root_legendre_coefficients_(parent); // Root cell parent information
}else{
for(i=0; i<Nbasis;i++) parent[i]=working_space[(Nbasis*cell_index)+i]; // Copy parent information
};
//===================================================================================================
compute_all_properties_of_a_panphasia_cell_(&level,&j1,&j2,&j3,parent,children);
//===================================================================================================
// Determine which child information needs to be stored
for (ix=0; ix<2; ix++) for (iy=0; iy<2; iy++) for (iz=0; iz<2; iz++){
if ((child_pointer_x[2*xoffset+ix]!=-1)&&(child_pointer_y[2*yoffset+iy]!=-1)
&&(child_pointer_z[2*zoffset+iz]!=-1)){
xco = child_pointer_x[2*xoffset+ix] - level_begin_x[level+1];
yco = child_pointer_y[2*yoffset+iy] - level_begin_y[level+1];
zco = child_pointer_z[2*zoffset+iz] - level_begin_z[level+1];
child_index = cumulative_cell_index[level+1] + xco*level_count_y[level+1]*level_count_z[level+1] +
yco*level_count_z[level+1] + zco;
work_index = Nbasis*child_index;
selected_child_index = Nbasis*(4*ix + 2*iy + iz);
for (i=0; i<Nbasis;i++) working_space[work_index+i] = children[selected_child_index+i];
};
};// end loop over possible children
if (*verbose>1) printf("Cell: L%llu %llu %llu %llu\n",level,j1,j2,j3);
}; // z/y/x-coordinate/level
// if (flag_nochildren!=0) return(211); //All cells should have at least one child
}; // End loop over levels
#ifdef USE_OPENMP
end = omp_get_wtime();
if (*verbose) printf("End ...\n");
double cpu_time_used = ((double) (end - start));
if (*verbose) printf("Time in OMP Section = %lf seconds \n",cpu_time_used);
#endif
};
//========================================================================================
// Assign data from work_space to the input array
//========================================================================================
{
FFTW_REAL *ptr_real = output_values;
FFTW_COMPLEX *ptr_cmplx = output_values;
size_t zdimension = (*flag_output_mode==2) ? *zextent + 2 : *zextent; // For R2C pad by two in z-dimension
//printf("zdimension = %ld\n",zdimension);
// PAN_COMPLEX *ptr_cplx;
// *ptr_real =(* PAN_REAL) *output_values;
// *ptr_cplx = output_values
for (size_t xco=0;xco<*xextent;xco++)for(size_t yco=0;yco<*yextent;yco++)for(size_t zco=0; zco<*zextent;zco++){
size_t xloc = index_perm_x[xco], yloc = index_perm_y[yco], zloc = index_perm_z[zco];
size_t index = Nbasis*( xco*(*yextent)*(*zextent) + yco*(*zextent) + zco);
size_t out_v_index = *ncopy*(xloc*(*yextent)*zdimension + yloc*zdimension + zloc);
if (*flag_output_mode==1){
for (size_t i=0; i<*ncopy; i++) ptr_cmplx[out_v_index+i] = (FFTW_COMPLEX) working_space[index+copy_list[i]];
}else{
for (size_t i=0; i<*ncopy; i++) ptr_real[out_v_index+i] = working_space[index+copy_list[i]];
};
};
};
//===========================================(==============================================
// Free all memory (in order of calls to malloc above)
//=========================================================================================
free(ret_x_list_coords);
free(ret_y_list_coords);
free(ret_z_list_coords);
free(child_pointer_x);
free(child_pointer_y);
free(child_pointer_z);
free(index_perm_x);
free(index_perm_y);
free(index_perm_z);
free(list_cell_x_coord);
free(list_cell_y_coord);
free(list_cell_z_coord);
free(working_space);
//tic_tot = getticks()-tic_start;
// if (*verbose) printf("Total child cells at deepest level %llu \n",num_level_max_cells);
//if (*verbose) printf("Total number of cells computed %llu \n",num_cell_compute);
//if (*verbose) printf("Total number of child cells %llu \n",total_num_children);
//if (*verbose) printf("Time to compute %llu cells at level %llu: %.3f %s \n",num_level_max_cells,
// level_max, clocks_from_ticks(tic_tot), clocks_getunit());
//=======================================================================================
return(0);
//=======================================================================================
};
//======================================================================================
//======================================================================================
//======================================================================================
//======================================================================================
//======================================================================================
int parse_and_validate_descriptor_(char *descriptor){
char *token;
const char split[20] = "[,()]";
char copy[300];
size_t desc_order, desc_level, desc_x, desc_y, desc_z,desc_size;
char desc_name[100];
size_t desc_kk_limit = 0;
long long int desc_ch,comp_ch;
int kk_limit_set = 0;
int nelement = 0;
char descriptor_as_read[300];
strcpy(copy,descriptor);
token = strtok(copy, split);
while( token != NULL ) {
nelement++;
// Read in compulsory elements
switch(nelement){
case 1:
if (sscanf(token,"Panph%llu",&desc_order)!=1) return (440001);
break;
case 2:
if (sscanf(token,"L%llu",&desc_level)!=1) return 440002;
break;
case 3:
if (sscanf(token,"%llu",&desc_x)!=1) return 440003;
break;
case 4:
if (sscanf(token,"%llu",&desc_y)!=1) return 440004;
break;
case 5:
if (sscanf(token,"%llu",&desc_z)!=1) return 440005;
break;
case 6:
if (sscanf(token,"S%llu",&desc_size)!=1) return 440005;
break;
case 7:
if (sscanf(token,"KK%lld",&desc_kk_limit)==1) {
kk_limit_set=1;
token = strtok(NULL, split);
};
if (sscanf(token,"CH%lld",&desc_ch)!=1) return 440006;
break;
case 8:
if (sscanf(token,"%s",&desc_name)!=1) return 440007;
break;
};
token = strtok(NULL, split);
};
if (kk_limit_set==0){
sprintf(descriptor_as_read,"[Panph%d,L%llu,(%llu,%llu,%llu),S%llu,CH%lld,%s]",
desc_order,desc_level,desc_x,desc_y,desc_z,desc_size,desc_ch,desc_name);
} else{
sprintf(descriptor_as_read,"[Panph%d,L%llu,(%llu,%llu,%llu),S%llu,KK%lld,CH%lld,%s]",
desc_order,desc_level,desc_x,desc_y,desc_z,desc_size,desc_kk_limit,desc_ch,desc_name);
};
if (strcmp(descriptor,descriptor_as_read)){
printf("Error - descriptor mismatch\n");
printf("As read in: %s\n",descriptor_as_read);
printf(" %s\n",descriptor);
};
// Valid format descriptor has been passed - store values
descriptor_order = desc_order;
descriptor_base_level = desc_level;
descriptor_xorigin = desc_x;
descriptor_yorigin = desc_y;
descriptor_zorigin = desc_z;
descriptor_base_size = desc_size;
descriptor_kk_limit = desc_kk_limit;
descriptor_check_digit = desc_ch;
strcpy(descriptor_name, desc_name);
strcpy(full_descriptor,descriptor);
descriptor_read_in = 1;
comp_ch = compute_check_digit_(); // check the check digit
if ((desc_ch!=-999)&&(desc_ch!=comp_ch)){
descriptor_read_in = 0;
printf("Check digit read in %llu\n Check digit expected %llu\n",desc_ch,comp_ch);
return (44008);
};
return(0);
};
void calc_absolute_coordinates(size_t xrel, size_t yrel, size_t zrel,size_t *xabs, size_t *yabs,size_t *zabs){
*xabs = ((descriptor_xorigin<<rel_level) + ((rel_origin_x + xrel)
%rel_coord_max))%((size_t)1<<(descriptor_base_level+rel_level));
*yabs = ((descriptor_yorigin<<rel_level) + ((rel_origin_y + yrel)
%rel_coord_max))%((size_t)1<<(descriptor_base_level+rel_level));
*zabs = ((descriptor_zorigin<<rel_level) + ((rel_origin_z + zrel)
%rel_coord_max))%((size_t)1<<(descriptor_base_level+rel_level));
// printf("descriptor_zorigin %llu rel_level %llu zrel %llu rel_origin_z %llu rel_coord_max %llu \n descriptor_base_level %llu, zabs %llu\n",
//y descriptor_zorigin,rel_level,zrel,rel_origin_z,rel_coord_max,descriptor_base_level,*zabs);
};
int cell_information(size_t cell_id, size_t *cumulative_cell_index, size_t *cuboid_x_dimen,
size_t *cuboid_y_dimen,size_t *cuboid_z_dimen, size_t *cell_lev,
size_t *cell_x, size_t *cell_y, size_t *cell_z, size_t number_children,
size_t *child_cell_indices) {
if (cell_id>=cumulative_cell_index[descriptor_base_level+rel_level+1]) return(301);
size_t cell_level;
for (cell_level = descriptor_base_level+rel_level;
cell_id < cumulative_cell_index[cell_level];cell_level--);
size_t local_id = cell_id - cumulative_cell_index[cell_level];
*cell_x = local_id/(cuboid_y_dimen[cell_level]*cuboid_z_dimen[cell_level]);
*cell_y = (local_id - *cell_x*cuboid_y_dimen[cell_level]*cuboid_z_dimen[cell_level])/cuboid_z_dimen[cell_level];
*cell_z = local_id%cuboid_z_dimen[cell_level];
//printf("Cell level %llu x %llu y %llu z %llu\n",cell_level,*cell_x,*cell_y,*cell_z);
return(0);
};
int return_binary_tree_cell_lists(size_t level_max, size_t *list_cell_coordinates,
size_t extent, size_t *return_tree_list_coordinates, size_t nreturn,
long long int *child_pointer, size_t *level_count,
size_t *level_begin, size_t *index_perm){
if (extent==0) return(401);
if (nreturn<2*extent+192) return(402);
for (size_t i=0; i<2*nreturn;i++) child_pointer[i]=-1;
{ size_t stride=1;
for(size_t i=0; i<extent;i++) {
index_perm[i] = i;
return_tree_list_coordinates[i]=list_cell_coordinates[i];
};
gsl_sort2_ulong(return_tree_list_coordinates,stride,index_perm, stride,extent);
};
//----------------------------------------------------------------------------
level_begin[level_max] = 0;
level_count[level_max] = extent;
size_t offset,counter;
size_t abs_coord;
for (size_t level=level_max; level>0; level--){
offset =level_begin[level]+level_count[level];
counter = 0;
abs_coord = return_tree_list_coordinates[level_begin[level]];
return_tree_list_coordinates[offset] = abs_coord>>1;
child_pointer[2*offset + abs_coord%2] = level_begin[level];
for(size_t cell = 1; cell<level_count[level]; cell++){
abs_coord = return_tree_list_coordinates[level_begin[level]+cell];
if (abs_coord>>1 == return_tree_list_coordinates[offset+counter]){
child_pointer[2*offset + 2*counter + abs_coord%2] = level_begin[level]+cell;
}else{
counter++;
return_tree_list_coordinates[offset+counter] = abs_coord>>1;
child_pointer[2*offset + 2*counter + abs_coord%2] = level_begin[level]+cell;
};
}; //cell loop
level_count[level-1] = ++counter;
level_begin[level-1] = level_begin[level] + level_count[level];
}; // level loop
return(0);
};
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//
// Test code for checking the appropriate moments are preserved
// between levels in Panphasia
//
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
#include <gsl/gsl_sf_legendre.h>
void integrate_cell( int, int, int, size_t, size_t, size_t, FFTW_REAL * , double *);
int compute_panphasia_(double, double, double, size_t, size_t, size_t, FFTW_REAL *, double *);
void test_cell_moments(char *,size_t, size_t, size_t, size_t, size_t, double *);
////////////////////////////////////////////////////////////////////////////////
void test_moments_(){
int lev = 10;
char descriptor_demo[300]="Hello!";
printf("Demo string %s\n",descriptor_demo);
// descriptor_pair_generate_();//, descriptor_demo);
printf("Parameters: %s\n",descriptor_demo);
size_t nlevel=1;
double coefficients1[Nbasis];
double coefficients2[Nbasis];
double max_diff2=0.0;
double rms_diff2=0.0;
char descriptor[200];
size_t const xco_full = 0x7504f333f9de6497;
size_t const yco_full = 0x67ea73c992a3355c;
size_t const zco_full = 0x5ab50a5892e98768;
size_t xco = 0; size_t yco = 0; size_t zco=0;
verbose_warnings_only=1; // Minimize output to screen.
for (size_t level=0; level<63; level++){
xco = (xco_full)>>(63-level);
yco = (yco_full)>>(63-level);
zco = (zco_full)>>(63-level);
sprintf(descriptor,"[Panph6,L%ld,(%llu,%llu,%llu),S1,CH-999,test]",level,xco,yco,zco);
// printf("%s\n",descriptor);
test_cell_moments(descriptor,0,0,0,0,1,coefficients1);
test_cell_moments(descriptor,1,0,0,0,2,coefficients2);
for (int i=0; i<Nbasis;i++){
double diff2 = pow(coefficients2[i]-coefficients1[i],2);
if (diff2>max_diff2) max_diff2=diff2;
rms_diff2+=diff2;
};
rms_diff2/=(double)Nbasis;
// for (int i=0; i<Nbasis; i++) printf("X: %d %16.10f %16.10f %e \n",i,
// coefficients1[i],coefficients2[i],coefficients2[i]-coefficients1[i]);
if (sizeof(PAN_REAL)==4){
if ((max_diff2>1.e-12)||(rms_diff2>1.e-12)){
printf("Moments not accurately recovered at single precision\n"); abort();
};
}else{
if ((max_diff2>1.e-24)||(rms_diff2>1.e-24)){
printf("Moments not accurately recovered at double precision\n"); abort();
};
};
//printf("Acceptable differences: %e RMS difference %e\n",sqrt(max_diff2),sqrt(rms_diff2));
};
printf("Completed moment test successfully.\n");
};
void test_cell_moments(char root_descriptor[200], size_t rel_lev, size_t rel_orig_x,
size_t rel_orig_y, size_t rel_orig_z, size_t extent, double *coeff ){
int error_code;
int verbose = 0;
int flag_output_mode=0;
PANPHASIA_init_descriptor_(root_descriptor,&verbose);
verbose = 0;
if (error_code = PANPHASIA_init_level_(&rel_lev,
&rel_orig_x,&rel_orig_y,&rel_orig_z,&verbose)){
printf("Error %d in initialing PANPHASIA_init_level_\n",
error_code);
};
size_t xstart = 0, ystart = 0, zstart = 0;
size_t xextent, yextent, zextent;
xextent = extent; yextent=extent; zextent=extent;
size_t copy_list[Nbasis];
for (int i=0; i<Nbasis; i++) copy_list[i] = i;
size_t ncopy=Nbasis;
FFTW_REAL *output_values = malloc(sizeof(FFTW_REAL)*ncopy*xextent*yextent*zextent);
if (output_values==NULL){
printf("Unable to allocate output_values \n");
abort();
};
if (error_code = PANPHASIA_compute_coefficients_(&xstart,&ystart,&zstart,
&xextent,&yextent,&zextent, copy_list, &ncopy,
output_values, &flag_output_mode,&verbose)){
printf("Error %d in PANPHASIA_compute_coefficients_ \n",error_code);
};
/* // Plot Panphasia field ...
double panphasia_value;
FILE *file = fopen("Panphasia_function.tex","w");
for (int i=0; i<1000; i++){
double x = 0.0009*(double)(xextent*(i+1)); double y = 0.5; double z=0.5;
compute_panphasia_(x,y,z,xextent,yextent,zextent,output_values,&panphasia_value);
fprintf(file,"%12.6f %14.8f\n",x,panphasia_value);
}
fclose(file);
printf("Finished writing file ...\n");
*/
double sum_coefficients[Nbasis]={0.0};
double results[Nbasis];
size_t num_cells = 0;
for (int ix=0; ix<extent; ix++)
for (int iy=0; iy<extent; iy++)
for (int iz=0; iz<extent; iz++){
integrate_cell(ix,iy,iz,xextent,yextent,zextent,output_values,results);
for (int i=0; i<Nbasis; i++) sum_coefficients[i] +=results[i];
num_cells++;
};
for(int i=0; i<Nbasis; i++) coeff[i] = sum_coefficients[i]/sqrt(xextent*yextent*zextent);
free(output_values);
} ;
void integrate_cell( int ix, int iy, int iz, size_t xextent, size_t yextent, size_t zextent, FFTW_REAL *output_values, double *results){
/*/////////////////////////////////////////////////////////////////////////////
This function computes the integral over a cell of the product of the
Panphasia field with an 'analysing' Legendre polynomial. As the
integrand is a polynomial, Gaussian quadrature can be used for
integration as it is exact up to rounding error provide p_order
is less than 10.
/*////////////////////////////////////////////////////////////////////////////*/
const double GQ_weights[5] = {0.2955242247147529,0.2692667193099963,
0.2190863625159820,0.1494513491505806,
0.0666713443086881};
const double GQ_abscissa[5] = {0.1488743389816312,0.4333953941292472,
0.6794095682990244,0.8650633666889845,
0.9739065285171717};
double weights[10];
double abscissa[10];
for (int i=0; i<5; i++){
weights[i] = GQ_weights[4-i];
weights[i+5] = GQ_weights[i];
abscissa[i] = -GQ_abscissa[4-i];
abscissa[i+5] = GQ_abscissa[i];
};
if (yextent!=zextent){printf("Non-cubic domain in integrate cell\n");abort();};
if (p_order>=10){printf("Higher order Gaussian Quadrature needed!\n");abort();};
double a = 0.0;
double b = 1.0;
double middle = 0.5*(b+a);
double range = 0.5*(b-a);
double sum[Nbasis] = {0.0};
double test_sum = 0.0;
for (int i=0; i<10; i++){
double xp = middle + range*abscissa[i];
for (int j=0; j<10; j++){
double yp = middle + range*abscissa[j];
for (int k=0; k<10; k++){
double zp = middle + range*abscissa[k];
////////////////////////////////////////////////////////////////////////////////////////
double panphasia_value;
double xv = (double)ix + xp;
double yv = (double)iy + yp;
double zv = (double)iz + zp;
if (compute_panphasia_(xv,yv,zv,xextent,yextent,zextent,output_values,
&panphasia_value)==1){
printf("Call to compute_panphasia_ out of range \n");abort();
};
double uq,vq,wq;
uq = 2.0*(xv/(double)yextent)-1.0;
vq = 2.0*(yv/(double)yextent)-1.0;
wq = 2.0*(zv/(double)yextent)-1.0;
int p = p_order;
double lgp_uq[p_order+1];
double lgp_vq[p_order+1];
double lgp_wq[p_order+1];
gsl_sf_legendre_Pl_array(p,uq,lgp_uq);
gsl_sf_legendre_Pl_array(p,vq,lgp_vq);
gsl_sf_legendre_Pl_array(p,wq,lgp_wq);
for (int ii=0; ii<p+1; ii++){
lgp_uq[ii]*=sqrt(2*ii+1);
lgp_vq[ii]*=sqrt(2*ii+1);
lgp_wq[ii]*=sqrt(2*ii+1);
};
////////////////////////////////////////////////////////////////////////////////////////
double combined_weight = pow(range,3)*weights[i]*weights[j]*weights[k];
for (int jj=0; jj<Nbasis; jj++){
int lq = irank_p[0][jj]; int mq = irank_p[1][jj]; int nq = irank_p[2][jj];
double af = combined_weight*lgp_uq[lq]*lgp_vq[mq]*lgp_wq[nq];// Analysing function
sum[jj]+= af*panphasia_value;
////////////////////////////////////////////////////////////////////////////////////////
};
};
};
};
for (int i=0; i<Nbasis; i++) results[i] = sum[i];
};
int compute_panphasia_(double x, double y, double z, size_t xextent, size_t yextent,
size_t zextent, FFTW_REAL *output_values,double *panphasia_value){
if ((x<0)||(x>=(double)xextent)) return (1);
if ((y<0)||(y>=(double)yextent)) return (1);
if ((z<0)||(z>=(double)zextent)) return (1);
int ix = (int)x;
int iy = (int)y;
int iz = (int)z;
double up = 2.0*(x-ix)-1.0;
double vp = 2.0*(y-iy)-1.0;
double wp = 2.0*(z-iz)-1.0;
double lgp_up[p_order+1];
double lgp_vp[p_order+1];
double lgp_wp[p_order+1];
int p = p_order;
gsl_sf_legendre_Pl_array(p,up,lgp_up);
gsl_sf_legendre_Pl_array(p,vp,lgp_vp);
gsl_sf_legendre_Pl_array(p,wp,lgp_wp);
for (int i=0; i<p+1; i++){
lgp_up[i]*=sqrt(2*i+1);
lgp_vp[i]*=sqrt(2*i+1);
lgp_wp[i]*=sqrt(2*i+1);
};
*panphasia_value = 0;
for (int i=0; i<Nbasis; i++){
int lp = irank_p[0][i]; int mp = irank_p[1][i]; int np = irank_p[2][i];
*panphasia_value += output_values[Nbasis*(ix*yextent*zextent+iy*zextent+iz)+i]*
lgp_up[lp]*lgp_vp[mp]*lgp_wp[np];
};
return(0);
};
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
// Fortran wrapper for gsl function to evaluate Spherical Bessel functions
void spherical_bessel_(int *l, double *x, double *result){
*result = gsl_sf_bessel_jl(*l,*x);
};
void compute_sph_bessel_coeffs(int nfft, int pmax, int n4dimen, int fdim, double complex *sph_bessel_coeff){
const double pi = 4.0 * atan(1.0);
for (int l=0; l<=pmax; l++){
double norm = sqrt((double)(2*l+1)*fdim);
double complex phase_shift = cpow(-I,l);
for (int i=0; i<nfft;i++){
int j = (i<=nfft/2)? i: i-nfft;
int k = abs(j);
double sign = (j<0) ? pow(-1.0,l):1.0;
double x = pi*(double)k/(double)(nfft*fdim);
double result;
spherical_bessel_(&l,&x,&result);
if (i!=nfft/2){
sph_bessel_coeff[l*n4dimen + i] = norm*phase_shift*sign*result;
}else{
sph_bessel_coeff[l*n4dimen + i] = (l==0)? 1.0:0.0; //Treat Nyquist mode specially
};
};
};
};
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//
// End
//
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////