TCT6UJJD7HTLS55CAV4MNVP5QKWKHIO5PZAWO7KDJFUB6DEVLH6AC Maxwell.oldStaticTrumpet.old
Cactus Code Thorn StaticTrumpetAuthor(s) : Erik Schnetter <schnetter@gmail.com>Maintainer(s): Erik Schnetter <schnetter@gmail.com>Licence : LGPL--------------------------------------------------------------------------1. PurposeGenerate source code for StaticTrumpet initial conditionsKenneth A. Dennison, Thomas W. Baumgarte: A Simple Family ofAnalytical Trumpet Slices of the Schwarzschild Spacetime,arXiv:1403.5484 [gr-qc], doi:10.1088/0264-9381/31/11/117001.https://github.com/zachetienne/nrpytutorial/blob/master/Tutorial-ADM_Initial_Data-StaticTrumpet.ipynb
/*Evaluate the Hamiltonian constraint*/void Hamiltonian_constraint(const paramstruct *restrict params, REAL *restrict xx[3],REAL *restrict in_gfs, REAL *restrict aux_gfs) {#include "set_Cparameters.h"#pragma omp parallel forfor(int i2=NGHOSTS; i2<NGHOSTS+Nxx2; i2++) {const REAL xx2 = xx[2][i2];for(int i1=NGHOSTS; i1<NGHOSTS+Nxx1; i1++) {const REAL xx1 = xx[1][i1];for(int i0=NGHOSTS; i0<NGHOSTS+Nxx0; i0++) {const REAL xx0 = xx[0][i0];{/** NRPy+ Finite Difference Code Generation, Step 1 of 2: Read from main memory and compute finite difference stencils:*/const double hDD00_i0m2_i1m2_i2 = in_gfs[IDX4S(HDD00GF, i0-2,i1-2,i2)];const double hDD00_i0m1_i1m2_i2 = in_gfs[IDX4S(HDD00GF, i0-1,i1-2,i2)];const double hDD00_i0_i1m2_i2 = in_gfs[IDX4S(HDD00GF, i0,i1-2,i2)];const double hDD00_i0p1_i1m2_i2 = in_gfs[IDX4S(HDD00GF, i0+1,i1-2,i2)];const double hDD00_i0p2_i1m2_i2 = in_gfs[IDX4S(HDD00GF, i0+2,i1-2,i2)];const double hDD00_i0m2_i1m1_i2 = in_gfs[IDX4S(HDD00GF, i0-2,i1-1,i2)];const double hDD00_i0m1_i1m1_i2 = in_gfs[IDX4S(HDD00GF, i0-1,i1-1,i2)];const double hDD00_i0_i1m1_i2 = in_gfs[IDX4S(HDD00GF, i0,i1-1,i2)];const double hDD00_i0p1_i1m1_i2 = in_gfs[IDX4S(HDD00GF, i0+1,i1-1,i2)];const double hDD00_i0p2_i1m1_i2 = in_gfs[IDX4S(HDD00GF, i0+2,i1-1,i2)];const double hDD00_i0m2_i1_i2 = in_gfs[IDX4S(HDD00GF, i0-2,i1,i2)];const double hDD00_i0m1_i1_i2 = in_gfs[IDX4S(HDD00GF, i0-1,i1,i2)];const double hDD00 = in_gfs[IDX4S(HDD00GF, i0,i1,i2)];const double hDD00_i0p1_i1_i2 = in_gfs[IDX4S(HDD00GF, i0+1,i1,i2)];const double hDD00_i0p2_i1_i2 = in_gfs[IDX4S(HDD00GF, i0+2,i1,i2)];const double hDD00_i0m2_i1p1_i2 = in_gfs[IDX4S(HDD00GF, i0-2,i1+1,i2)];const double hDD00_i0m1_i1p1_i2 = in_gfs[IDX4S(HDD00GF, i0-1,i1+1,i2)];const double hDD00_i0_i1p1_i2 = in_gfs[IDX4S(HDD00GF, i0,i1+1,i2)];const double hDD00_i0p1_i1p1_i2 = in_gfs[IDX4S(HDD00GF, i0+1,i1+1,i2)];const double hDD00_i0p2_i1p1_i2 = in_gfs[IDX4S(HDD00GF, i0+2,i1+1,i2)];const double hDD00_i0m2_i1p2_i2 = in_gfs[IDX4S(HDD00GF, i0-2,i1+2,i2)];const double hDD00_i0m1_i1p2_i2 = in_gfs[IDX4S(HDD00GF, i0-1,i1+2,i2)];const double hDD00_i0_i1p2_i2 = in_gfs[IDX4S(HDD00GF, i0,i1+2,i2)];const double hDD00_i0p1_i1p2_i2 = in_gfs[IDX4S(HDD00GF, i0+1,i1+2,i2)];const double hDD00_i0p2_i1p2_i2 = in_gfs[IDX4S(HDD00GF, i0+2,i1+2,i2)];const double hDD01_i0m2_i1m2_i2 = in_gfs[IDX4S(HDD01GF, i0-2,i1-2,i2)];const double hDD01_i0m1_i1m2_i2 = in_gfs[IDX4S(HDD01GF, i0-1,i1-2,i2)];const double hDD01_i0_i1m2_i2 = in_gfs[IDX4S(HDD01GF, i0,i1-2,i2)];const double hDD01_i0p1_i1m2_i2 = in_gfs[IDX4S(HDD01GF, i0+1,i1-2,i2)];const double hDD01_i0p2_i1m2_i2 = in_gfs[IDX4S(HDD01GF, i0+2,i1-2,i2)];const double hDD01_i0m2_i1m1_i2 = in_gfs[IDX4S(HDD01GF, i0-2,i1-1,i2)];const double hDD01_i0m1_i1m1_i2 = in_gfs[IDX4S(HDD01GF, i0-1,i1-1,i2)];const double hDD01_i0_i1m1_i2 = in_gfs[IDX4S(HDD01GF, i0,i1-1,i2)];const double hDD01_i0p1_i1m1_i2 = in_gfs[IDX4S(HDD01GF, i0+1,i1-1,i2)];const double hDD01_i0p2_i1m1_i2 = in_gfs[IDX4S(HDD01GF, i0+2,i1-1,i2)];const double hDD01_i0m2_i1_i2 = in_gfs[IDX4S(HDD01GF, i0-2,i1,i2)];const double hDD01_i0m1_i1_i2 = in_gfs[IDX4S(HDD01GF, i0-1,i1,i2)];const double hDD01 = in_gfs[IDX4S(HDD01GF, i0,i1,i2)];const double hDD01_i0p1_i1_i2 = in_gfs[IDX4S(HDD01GF, i0+1,i1,i2)];const double hDD01_i0p2_i1_i2 = in_gfs[IDX4S(HDD01GF, i0+2,i1,i2)];const double hDD01_i0m2_i1p1_i2 = in_gfs[IDX4S(HDD01GF, i0-2,i1+1,i2)];const double hDD01_i0m1_i1p1_i2 = in_gfs[IDX4S(HDD01GF, i0-1,i1+1,i2)];const double hDD01_i0_i1p1_i2 = in_gfs[IDX4S(HDD01GF, i0,i1+1,i2)];const double hDD01_i0p1_i1p1_i2 = in_gfs[IDX4S(HDD01GF, i0+1,i1+1,i2)];const double hDD01_i0p2_i1p1_i2 = in_gfs[IDX4S(HDD01GF, i0+2,i1+1,i2)];const double hDD01_i0m2_i1p2_i2 = in_gfs[IDX4S(HDD01GF, i0-2,i1+2,i2)];const double hDD01_i0m1_i1p2_i2 = in_gfs[IDX4S(HDD01GF, i0-1,i1+2,i2)];const double hDD01_i0_i1p2_i2 = in_gfs[IDX4S(HDD01GF, i0,i1+2,i2)];const double hDD01_i0p1_i1p2_i2 = in_gfs[IDX4S(HDD01GF, i0+1,i1+2,i2)];const double hDD01_i0p2_i1p2_i2 = in_gfs[IDX4S(HDD01GF, i0+2,i1+2,i2)];const double hDD02_i0m2_i1m2_i2 = in_gfs[IDX4S(HDD02GF, i0-2,i1-2,i2)];const double hDD02_i0m1_i1m2_i2 = in_gfs[IDX4S(HDD02GF, i0-1,i1-2,i2)];const double hDD02_i0_i1m2_i2 = in_gfs[IDX4S(HDD02GF, i0,i1-2,i2)];const double hDD02_i0p1_i1m2_i2 = in_gfs[IDX4S(HDD02GF, i0+1,i1-2,i2)];const double hDD02_i0p2_i1m2_i2 = in_gfs[IDX4S(HDD02GF, i0+2,i1-2,i2)];const double hDD02_i0m2_i1m1_i2 = in_gfs[IDX4S(HDD02GF, i0-2,i1-1,i2)];const double hDD02_i0m1_i1m1_i2 = in_gfs[IDX4S(HDD02GF, i0-1,i1-1,i2)];const double hDD02_i0_i1m1_i2 = in_gfs[IDX4S(HDD02GF, i0,i1-1,i2)];const double hDD02_i0p1_i1m1_i2 = in_gfs[IDX4S(HDD02GF, i0+1,i1-1,i2)];const double hDD02_i0p2_i1m1_i2 = in_gfs[IDX4S(HDD02GF, i0+2,i1-1,i2)];const double hDD02_i0m2_i1_i2 = in_gfs[IDX4S(HDD02GF, i0-2,i1,i2)];const double hDD02_i0m1_i1_i2 = in_gfs[IDX4S(HDD02GF, i0-1,i1,i2)];const double hDD02 = in_gfs[IDX4S(HDD02GF, i0,i1,i2)];const double hDD02_i0p1_i1_i2 = in_gfs[IDX4S(HDD02GF, i0+1,i1,i2)];const double hDD02_i0p2_i1_i2 = in_gfs[IDX4S(HDD02GF, i0+2,i1,i2)];const double hDD02_i0m2_i1p1_i2 = in_gfs[IDX4S(HDD02GF, i0-2,i1+1,i2)];const double hDD02_i0m1_i1p1_i2 = in_gfs[IDX4S(HDD02GF, i0-1,i1+1,i2)];const double hDD02_i0_i1p1_i2 = in_gfs[IDX4S(HDD02GF, i0,i1+1,i2)];const double hDD02_i0p1_i1p1_i2 = in_gfs[IDX4S(HDD02GF, i0+1,i1+1,i2)];const double hDD02_i0p2_i1p1_i2 = in_gfs[IDX4S(HDD02GF, i0+2,i1+1,i2)];const double hDD02_i0m2_i1p2_i2 = in_gfs[IDX4S(HDD02GF, i0-2,i1+2,i2)];const double hDD02_i0m1_i1p2_i2 = in_gfs[IDX4S(HDD02GF, i0-1,i1+2,i2)];const double hDD02_i0_i1p2_i2 = in_gfs[IDX4S(HDD02GF, i0,i1+2,i2)];const double hDD02_i0p1_i1p2_i2 = in_gfs[IDX4S(HDD02GF, i0+1,i1+2,i2)];const double hDD02_i0p2_i1p2_i2 = in_gfs[IDX4S(HDD02GF, i0+2,i1+2,i2)];const double hDD11_i0m2_i1m2_i2 = in_gfs[IDX4S(HDD11GF, i0-2,i1-2,i2)];const double hDD11_i0m1_i1m2_i2 = in_gfs[IDX4S(HDD11GF, i0-1,i1-2,i2)];const double hDD11_i0_i1m2_i2 = in_gfs[IDX4S(HDD11GF, i0,i1-2,i2)];const double hDD11_i0p1_i1m2_i2 = in_gfs[IDX4S(HDD11GF, i0+1,i1-2,i2)];const double hDD11_i0p2_i1m2_i2 = in_gfs[IDX4S(HDD11GF, i0+2,i1-2,i2)];const double hDD11_i0m2_i1m1_i2 = in_gfs[IDX4S(HDD11GF, i0-2,i1-1,i2)];const double hDD11_i0m1_i1m1_i2 = in_gfs[IDX4S(HDD11GF, i0-1,i1-1,i2)];const double hDD11_i0_i1m1_i2 = in_gfs[IDX4S(HDD11GF, i0,i1-1,i2)];const double hDD11_i0p1_i1m1_i2 = in_gfs[IDX4S(HDD11GF, i0+1,i1-1,i2)];const double hDD11_i0p2_i1m1_i2 = in_gfs[IDX4S(HDD11GF, i0+2,i1-1,i2)];const double hDD11_i0m2_i1_i2 = in_gfs[IDX4S(HDD11GF, i0-2,i1,i2)];const double hDD11_i0m1_i1_i2 = in_gfs[IDX4S(HDD11GF, i0-1,i1,i2)];const double hDD11 = in_gfs[IDX4S(HDD11GF, i0,i1,i2)];const double hDD11_i0p1_i1_i2 = in_gfs[IDX4S(HDD11GF, i0+1,i1,i2)];const double hDD11_i0p2_i1_i2 = in_gfs[IDX4S(HDD11GF, i0+2,i1,i2)];const double hDD11_i0m2_i1p1_i2 = in_gfs[IDX4S(HDD11GF, i0-2,i1+1,i2)];const double hDD11_i0m1_i1p1_i2 = in_gfs[IDX4S(HDD11GF, i0-1,i1+1,i2)];const double hDD11_i0_i1p1_i2 = in_gfs[IDX4S(HDD11GF, i0,i1+1,i2)];const double hDD11_i0p1_i1p1_i2 = in_gfs[IDX4S(HDD11GF, i0+1,i1+1,i2)];const double hDD11_i0p2_i1p1_i2 = in_gfs[IDX4S(HDD11GF, i0+2,i1+1,i2)];const double hDD11_i0m2_i1p2_i2 = in_gfs[IDX4S(HDD11GF, i0-2,i1+2,i2)];const double hDD11_i0m1_i1p2_i2 = in_gfs[IDX4S(HDD11GF, i0-1,i1+2,i2)];const double hDD11_i0_i1p2_i2 = in_gfs[IDX4S(HDD11GF, i0,i1+2,i2)];const double hDD11_i0p1_i1p2_i2 = in_gfs[IDX4S(HDD11GF, i0+1,i1+2,i2)];const double hDD11_i0p2_i1p2_i2 = in_gfs[IDX4S(HDD11GF, i0+2,i1+2,i2)];const double hDD12_i0m2_i1m2_i2 = in_gfs[IDX4S(HDD12GF, i0-2,i1-2,i2)];const double hDD12_i0m1_i1m2_i2 = in_gfs[IDX4S(HDD12GF, i0-1,i1-2,i2)];const double hDD12_i0_i1m2_i2 = in_gfs[IDX4S(HDD12GF, i0,i1-2,i2)];const double hDD12_i0p1_i1m2_i2 = in_gfs[IDX4S(HDD12GF, i0+1,i1-2,i2)];const double hDD12_i0p2_i1m2_i2 = in_gfs[IDX4S(HDD12GF, i0+2,i1-2,i2)];const double hDD12_i0m2_i1m1_i2 = in_gfs[IDX4S(HDD12GF, i0-2,i1-1,i2)];const double hDD12_i0m1_i1m1_i2 = in_gfs[IDX4S(HDD12GF, i0-1,i1-1,i2)];const double hDD12_i0_i1m1_i2 = in_gfs[IDX4S(HDD12GF, i0,i1-1,i2)];const double hDD12_i0p1_i1m1_i2 = in_gfs[IDX4S(HDD12GF, i0+1,i1-1,i2)];const double hDD12_i0p2_i1m1_i2 = in_gfs[IDX4S(HDD12GF, i0+2,i1-1,i2)];const double hDD12_i0m2_i1_i2 = in_gfs[IDX4S(HDD12GF, i0-2,i1,i2)];const double hDD12_i0m1_i1_i2 = in_gfs[IDX4S(HDD12GF, i0-1,i1,i2)];const double hDD12 = in_gfs[IDX4S(HDD12GF, i0,i1,i2)];const double hDD12_i0p1_i1_i2 = in_gfs[IDX4S(HDD12GF, i0+1,i1,i2)];const double hDD12_i0p2_i1_i2 = in_gfs[IDX4S(HDD12GF, i0+2,i1,i2)];const double hDD12_i0m2_i1p1_i2 = in_gfs[IDX4S(HDD12GF, i0-2,i1+1,i2)];const double hDD12_i0m1_i1p1_i2 = in_gfs[IDX4S(HDD12GF, i0-1,i1+1,i2)];const double hDD12_i0_i1p1_i2 = in_gfs[IDX4S(HDD12GF, i0,i1+1,i2)];const double hDD12_i0p1_i1p1_i2 = in_gfs[IDX4S(HDD12GF, i0+1,i1+1,i2)];const double hDD12_i0p2_i1p1_i2 = in_gfs[IDX4S(HDD12GF, i0+2,i1+1,i2)];const double hDD12_i0m2_i1p2_i2 = in_gfs[IDX4S(HDD12GF, i0-2,i1+2,i2)];const double hDD12_i0m1_i1p2_i2 = in_gfs[IDX4S(HDD12GF, i0-1,i1+2,i2)];const double hDD12_i0_i1p2_i2 = in_gfs[IDX4S(HDD12GF, i0,i1+2,i2)];const double hDD12_i0p1_i1p2_i2 = in_gfs[IDX4S(HDD12GF, i0+1,i1+2,i2)];const double hDD12_i0p2_i1p2_i2 = in_gfs[IDX4S(HDD12GF, i0+2,i1+2,i2)];const double hDD22_i0m2_i1m2_i2 = in_gfs[IDX4S(HDD22GF, i0-2,i1-2,i2)];const double hDD22_i0m1_i1m2_i2 = in_gfs[IDX4S(HDD22GF, i0-1,i1-2,i2)];const double hDD22_i0_i1m2_i2 = in_gfs[IDX4S(HDD22GF, i0,i1-2,i2)];const double hDD22_i0p1_i1m2_i2 = in_gfs[IDX4S(HDD22GF, i0+1,i1-2,i2)];const double hDD22_i0p2_i1m2_i2 = in_gfs[IDX4S(HDD22GF, i0+2,i1-2,i2)];const double hDD22_i0m2_i1m1_i2 = in_gfs[IDX4S(HDD22GF, i0-2,i1-1,i2)];const double hDD22_i0m1_i1m1_i2 = in_gfs[IDX4S(HDD22GF, i0-1,i1-1,i2)];const double hDD22_i0_i1m1_i2 = in_gfs[IDX4S(HDD22GF, i0,i1-1,i2)];const double hDD22_i0p1_i1m1_i2 = in_gfs[IDX4S(HDD22GF, i0+1,i1-1,i2)];const double hDD22_i0p2_i1m1_i2 = in_gfs[IDX4S(HDD22GF, i0+2,i1-1,i2)];const double hDD22_i0m2_i1_i2 = in_gfs[IDX4S(HDD22GF, i0-2,i1,i2)];const double hDD22_i0m1_i1_i2 = in_gfs[IDX4S(HDD22GF, i0-1,i1,i2)];const double hDD22 = in_gfs[IDX4S(HDD22GF, i0,i1,i2)];const double hDD22_i0p1_i1_i2 = in_gfs[IDX4S(HDD22GF, i0+1,i1,i2)];const double hDD22_i0p2_i1_i2 = in_gfs[IDX4S(HDD22GF, i0+2,i1,i2)];const double hDD22_i0m2_i1p1_i2 = in_gfs[IDX4S(HDD22GF, i0-2,i1+1,i2)];const double hDD22_i0m1_i1p1_i2 = in_gfs[IDX4S(HDD22GF, i0-1,i1+1,i2)];const double hDD22_i0_i1p1_i2 = in_gfs[IDX4S(HDD22GF, i0,i1+1,i2)];const double hDD22_i0p1_i1p1_i2 = in_gfs[IDX4S(HDD22GF, i0+1,i1+1,i2)];const double hDD22_i0p2_i1p1_i2 = in_gfs[IDX4S(HDD22GF, i0+2,i1+1,i2)];const double hDD22_i0m2_i1p2_i2 = in_gfs[IDX4S(HDD22GF, i0-2,i1+2,i2)];const double hDD22_i0m1_i1p2_i2 = in_gfs[IDX4S(HDD22GF, i0-1,i1+2,i2)];const double hDD22_i0_i1p2_i2 = in_gfs[IDX4S(HDD22GF, i0,i1+2,i2)];const double hDD22_i0p1_i1p2_i2 = in_gfs[IDX4S(HDD22GF, i0+1,i1+2,i2)];const double hDD22_i0p2_i1p2_i2 = in_gfs[IDX4S(HDD22GF, i0+2,i1+2,i2)];const double aDD00 = in_gfs[IDX4S(ADD00GF, i0,i1,i2)];const double aDD01 = in_gfs[IDX4S(ADD01GF, i0,i1,i2)];const double aDD02 = in_gfs[IDX4S(ADD02GF, i0,i1,i2)];const double aDD11 = in_gfs[IDX4S(ADD11GF, i0,i1,i2)];const double aDD12 = in_gfs[IDX4S(ADD12GF, i0,i1,i2)];const double aDD22 = in_gfs[IDX4S(ADD22GF, i0,i1,i2)];const double lambdaU0_i0_i1m2_i2 = in_gfs[IDX4S(LAMBDAU0GF, i0,i1-2,i2)];const double lambdaU0_i0_i1m1_i2 = in_gfs[IDX4S(LAMBDAU0GF, i0,i1-1,i2)];const double lambdaU0_i0m2_i1_i2 = in_gfs[IDX4S(LAMBDAU0GF, i0-2,i1,i2)];const double lambdaU0_i0m1_i1_i2 = in_gfs[IDX4S(LAMBDAU0GF, i0-1,i1,i2)];const double lambdaU0 = in_gfs[IDX4S(LAMBDAU0GF, i0,i1,i2)];const double lambdaU0_i0p1_i1_i2 = in_gfs[IDX4S(LAMBDAU0GF, i0+1,i1,i2)];const double lambdaU0_i0p2_i1_i2 = in_gfs[IDX4S(LAMBDAU0GF, i0+2,i1,i2)];const double lambdaU0_i0_i1p1_i2 = in_gfs[IDX4S(LAMBDAU0GF, i0,i1+1,i2)];const double lambdaU0_i0_i1p2_i2 = in_gfs[IDX4S(LAMBDAU0GF, i0,i1+2,i2)];const double lambdaU1_i0_i1m2_i2 = in_gfs[IDX4S(LAMBDAU1GF, i0,i1-2,i2)];const double lambdaU1_i0_i1m1_i2 = in_gfs[IDX4S(LAMBDAU1GF, i0,i1-1,i2)];const double lambdaU1_i0m2_i1_i2 = in_gfs[IDX4S(LAMBDAU1GF, i0-2,i1,i2)];const double lambdaU1_i0m1_i1_i2 = in_gfs[IDX4S(LAMBDAU1GF, i0-1,i1,i2)];const double lambdaU1 = in_gfs[IDX4S(LAMBDAU1GF, i0,i1,i2)];const double lambdaU1_i0p1_i1_i2 = in_gfs[IDX4S(LAMBDAU1GF, i0+1,i1,i2)];const double lambdaU1_i0p2_i1_i2 = in_gfs[IDX4S(LAMBDAU1GF, i0+2,i1,i2)];const double lambdaU1_i0_i1p1_i2 = in_gfs[IDX4S(LAMBDAU1GF, i0,i1+1,i2)];const double lambdaU1_i0_i1p2_i2 = in_gfs[IDX4S(LAMBDAU1GF, i0,i1+2,i2)];const double lambdaU2_i0_i1m2_i2 = in_gfs[IDX4S(LAMBDAU2GF, i0,i1-2,i2)];const double lambdaU2_i0_i1m1_i2 = in_gfs[IDX4S(LAMBDAU2GF, i0,i1-1,i2)];const double lambdaU2_i0m2_i1_i2 = in_gfs[IDX4S(LAMBDAU2GF, i0-2,i1,i2)];const double lambdaU2_i0m1_i1_i2 = in_gfs[IDX4S(LAMBDAU2GF, i0-1,i1,i2)];const double lambdaU2 = in_gfs[IDX4S(LAMBDAU2GF, i0,i1,i2)];const double lambdaU2_i0p1_i1_i2 = in_gfs[IDX4S(LAMBDAU2GF, i0+1,i1,i2)];const double lambdaU2_i0p2_i1_i2 = in_gfs[IDX4S(LAMBDAU2GF, i0+2,i1,i2)];const double lambdaU2_i0_i1p1_i2 = in_gfs[IDX4S(LAMBDAU2GF, i0,i1+1,i2)];const double lambdaU2_i0_i1p2_i2 = in_gfs[IDX4S(LAMBDAU2GF, i0,i1+2,i2)];const double trK = in_gfs[IDX4S(TRKGF, i0,i1,i2)];const double cf_i0m2_i1m2_i2 = in_gfs[IDX4S(CFGF, i0-2,i1-2,i2)];const double cf_i0m1_i1m2_i2 = in_gfs[IDX4S(CFGF, i0-1,i1-2,i2)];const double cf_i0_i1m2_i2 = in_gfs[IDX4S(CFGF, i0,i1-2,i2)];const double cf_i0p1_i1m2_i2 = in_gfs[IDX4S(CFGF, i0+1,i1-2,i2)];const double cf_i0p2_i1m2_i2 = in_gfs[IDX4S(CFGF, i0+2,i1-2,i2)];const double cf_i0m2_i1m1_i2 = in_gfs[IDX4S(CFGF, i0-2,i1-1,i2)];const double cf_i0m1_i1m1_i2 = in_gfs[IDX4S(CFGF, i0-1,i1-1,i2)];const double cf_i0_i1m1_i2 = in_gfs[IDX4S(CFGF, i0,i1-1,i2)];const double cf_i0p1_i1m1_i2 = in_gfs[IDX4S(CFGF, i0+1,i1-1,i2)];const double cf_i0p2_i1m1_i2 = in_gfs[IDX4S(CFGF, i0+2,i1-1,i2)];const double cf_i0m2_i1_i2 = in_gfs[IDX4S(CFGF, i0-2,i1,i2)];const double cf_i0m1_i1_i2 = in_gfs[IDX4S(CFGF, i0-1,i1,i2)];const double cf = in_gfs[IDX4S(CFGF, i0,i1,i2)];const double cf_i0p1_i1_i2 = in_gfs[IDX4S(CFGF, i0+1,i1,i2)];const double cf_i0p2_i1_i2 = in_gfs[IDX4S(CFGF, i0+2,i1,i2)];const double cf_i0m2_i1p1_i2 = in_gfs[IDX4S(CFGF, i0-2,i1+1,i2)];const double cf_i0m1_i1p1_i2 = in_gfs[IDX4S(CFGF, i0-1,i1+1,i2)];const double cf_i0_i1p1_i2 = in_gfs[IDX4S(CFGF, i0,i1+1,i2)];const double cf_i0p1_i1p1_i2 = in_gfs[IDX4S(CFGF, i0+1,i1+1,i2)];const double cf_i0p2_i1p1_i2 = in_gfs[IDX4S(CFGF, i0+2,i1+1,i2)];const double cf_i0m2_i1p2_i2 = in_gfs[IDX4S(CFGF, i0-2,i1+2,i2)];const double cf_i0m1_i1p2_i2 = in_gfs[IDX4S(CFGF, i0-1,i1+2,i2)];const double cf_i0_i1p2_i2 = in_gfs[IDX4S(CFGF, i0,i1+2,i2)];const double cf_i0p1_i1p2_i2 = in_gfs[IDX4S(CFGF, i0+1,i1+2,i2)];const double cf_i0p2_i1p2_i2 = in_gfs[IDX4S(CFGF, i0+2,i1+2,i2)];const double tmpFD0 = (1.0/12.0)*cf_i0m2_i1_i2;const double tmpFD1 = -1.0/12.0*cf_i0p2_i1_i2;const double tmpFD2 = (1.0/12.0)*cf_i0_i1m2_i2;const double tmpFD3 = -1.0/12.0*cf_i0_i1p2_i2;const double tmpFD4 = ((invdx0)*(invdx0));const double tmpFD5 = -5.0/2.0*cf;const double tmpFD6 = invdx0*invdx1;const double tmpFD7 = ((invdx1)*(invdx1));const double tmpFD8 = (1.0/12.0)*hDD00_i0m2_i1_i2;const double tmpFD9 = -1.0/12.0*hDD00_i0p2_i1_i2;const double tmpFD10 = (1.0/12.0)*hDD00_i0_i1m2_i2;const double tmpFD11 = -1.0/12.0*hDD00_i0_i1p2_i2;const double tmpFD12 = (1.0/12.0)*hDD01_i0m2_i1_i2;const double tmpFD13 = -1.0/12.0*hDD01_i0p2_i1_i2;const double tmpFD14 = (1.0/12.0)*hDD01_i0_i1m2_i2;const double tmpFD15 = -1.0/12.0*hDD01_i0_i1p2_i2;const double tmpFD16 = (1.0/12.0)*hDD02_i0m2_i1_i2;const double tmpFD17 = -1.0/12.0*hDD02_i0p2_i1_i2;const double tmpFD18 = (1.0/12.0)*hDD02_i0_i1m2_i2;const double tmpFD19 = -1.0/12.0*hDD02_i0_i1p2_i2;const double tmpFD20 = (1.0/12.0)*hDD11_i0m2_i1_i2;const double tmpFD21 = -1.0/12.0*hDD11_i0p2_i1_i2;const double tmpFD22 = (1.0/12.0)*hDD11_i0_i1m2_i2;const double tmpFD23 = -1.0/12.0*hDD11_i0_i1p2_i2;const double tmpFD24 = (1.0/12.0)*hDD12_i0m2_i1_i2;const double tmpFD25 = -1.0/12.0*hDD12_i0p2_i1_i2;const double tmpFD26 = (1.0/12.0)*hDD12_i0_i1m2_i2;const double tmpFD27 = -1.0/12.0*hDD12_i0_i1p2_i2;const double tmpFD28 = (1.0/12.0)*hDD22_i0m2_i1_i2;const double tmpFD29 = -1.0/12.0*hDD22_i0p2_i1_i2;const double tmpFD30 = (1.0/12.0)*hDD22_i0_i1m2_i2;const double tmpFD31 = -1.0/12.0*hDD22_i0_i1p2_i2;const double tmpFD32 = -5.0/2.0*hDD00;const double tmpFD33 = -5.0/2.0*hDD01;const double tmpFD34 = -5.0/2.0*hDD02;const double tmpFD35 = -5.0/2.0*hDD11;const double tmpFD36 = -5.0/2.0*hDD12;const double tmpFD37 = -5.0/2.0*hDD22;const double cf_dD0 = invdx0*(-2.0/3.0*cf_i0m1_i1_i2 + (2.0/3.0)*cf_i0p1_i1_i2 + tmpFD0 + tmpFD1);const double cf_dD1 = invdx1*(-2.0/3.0*cf_i0_i1m1_i2 + (2.0/3.0)*cf_i0_i1p1_i2 + tmpFD2 + tmpFD3);const double cf_dDD00 = tmpFD4*((4.0/3.0)*cf_i0m1_i1_i2 + (4.0/3.0)*cf_i0p1_i1_i2 - tmpFD0 + tmpFD1 + tmpFD5);const double cf_dDD01 = tmpFD6*((4.0/9.0)*cf_i0m1_i1m1_i2 - 1.0/18.0*cf_i0m1_i1m2_i2 - 4.0/9.0*cf_i0m1_i1p1_i2 + (1.0/18.0)*cf_i0m1_i1p2_i2 - 1.0/18.0*cf_i0m2_i1m1_i2 + (1.0/144.0)*cf_i0m2_i1m2_i2 + (1.0/18.0)*cf_i0m2_i1p1_i2 - 1.0/144.0*cf_i0m2_i1p2_i2 - 4.0/9.0*cf_i0p1_i1m1_i2 + (1.0/18.0)*cf_i0p1_i1m2_i2 + (4.0/9.0)*cf_i0p1_i1p1_i2 - 1.0/18.0*cf_i0p1_i1p2_i2 + (1.0/18.0)*cf_i0p2_i1m1_i2 - 1.0/144.0*cf_i0p2_i1m2_i2 - 1.0/18.0*cf_i0p2_i1p1_i2 + (1.0/144.0)*cf_i0p2_i1p2_i2);const double cf_dDD11 = tmpFD7*((4.0/3.0)*cf_i0_i1m1_i2 + (4.0/3.0)*cf_i0_i1p1_i2 - tmpFD2 + tmpFD3 + tmpFD5);const double hDD_dD000 = invdx0*(-2.0/3.0*hDD00_i0m1_i1_i2 + (2.0/3.0)*hDD00_i0p1_i1_i2 + tmpFD8 + tmpFD9);const double hDD_dD001 = invdx1*(-2.0/3.0*hDD00_i0_i1m1_i2 + (2.0/3.0)*hDD00_i0_i1p1_i2 + tmpFD10 + tmpFD11);const double hDD_dD010 = invdx0*(-2.0/3.0*hDD01_i0m1_i1_i2 + (2.0/3.0)*hDD01_i0p1_i1_i2 + tmpFD12 + tmpFD13);const double hDD_dD011 = invdx1*(-2.0/3.0*hDD01_i0_i1m1_i2 + (2.0/3.0)*hDD01_i0_i1p1_i2 + tmpFD14 + tmpFD15);const double hDD_dD020 = invdx0*(-2.0/3.0*hDD02_i0m1_i1_i2 + (2.0/3.0)*hDD02_i0p1_i1_i2 + tmpFD16 + tmpFD17);const double hDD_dD021 = invdx1*(-2.0/3.0*hDD02_i0_i1m1_i2 + (2.0/3.0)*hDD02_i0_i1p1_i2 + tmpFD18 + tmpFD19);const double hDD_dD110 = invdx0*(-2.0/3.0*hDD11_i0m1_i1_i2 + (2.0/3.0)*hDD11_i0p1_i1_i2 + tmpFD20 + tmpFD21);const double hDD_dD111 = invdx1*(-2.0/3.0*hDD11_i0_i1m1_i2 + (2.0/3.0)*hDD11_i0_i1p1_i2 + tmpFD22 + tmpFD23);const double hDD_dD120 = invdx0*(-2.0/3.0*hDD12_i0m1_i1_i2 + (2.0/3.0)*hDD12_i0p1_i1_i2 + tmpFD24 + tmpFD25);const double hDD_dD121 = invdx1*(-2.0/3.0*hDD12_i0_i1m1_i2 + (2.0/3.0)*hDD12_i0_i1p1_i2 + tmpFD26 + tmpFD27);const double hDD_dD220 = invdx0*(-2.0/3.0*hDD22_i0m1_i1_i2 + (2.0/3.0)*hDD22_i0p1_i1_i2 + tmpFD28 + tmpFD29);const double hDD_dD221 = invdx1*(-2.0/3.0*hDD22_i0_i1m1_i2 + (2.0/3.0)*hDD22_i0_i1p1_i2 + tmpFD30 + tmpFD31);const double hDD_dDD0000 = tmpFD4*((4.0/3.0)*hDD00_i0m1_i1_i2 + (4.0/3.0)*hDD00_i0p1_i1_i2 + tmpFD32 - tmpFD8 + tmpFD9);const double hDD_dDD0001 = tmpFD6*((4.0/9.0)*hDD00_i0m1_i1m1_i2 - 1.0/18.0*hDD00_i0m1_i1m2_i2 - 4.0/9.0*hDD00_i0m1_i1p1_i2 + (1.0/18.0)*hDD00_i0m1_i1p2_i2 - 1.0/18.0*hDD00_i0m2_i1m1_i2 + (1.0/144.0)*hDD00_i0m2_i1m2_i2 + (1.0/18.0)*hDD00_i0m2_i1p1_i2 - 1.0/144.0*hDD00_i0m2_i1p2_i2 - 4.0/9.0*hDD00_i0p1_i1m1_i2 + (1.0/18.0)*hDD00_i0p1_i1m2_i2 + (4.0/9.0)*hDD00_i0p1_i1p1_i2 - 1.0/18.0*hDD00_i0p1_i1p2_i2 + (1.0/18.0)*hDD00_i0p2_i1m1_i2 - 1.0/144.0*hDD00_i0p2_i1m2_i2 - 1.0/18.0*hDD00_i0p2_i1p1_i2 + (1.0/144.0)*hDD00_i0p2_i1p2_i2);const double hDD_dDD0011 = tmpFD7*((4.0/3.0)*hDD00_i0_i1m1_i2 + (4.0/3.0)*hDD00_i0_i1p1_i2 - tmpFD10 + tmpFD11 + tmpFD32);const double hDD_dDD0100 = tmpFD4*((4.0/3.0)*hDD01_i0m1_i1_i2 + (4.0/3.0)*hDD01_i0p1_i1_i2 - tmpFD12 + tmpFD13 + tmpFD33);const double hDD_dDD0101 = tmpFD6*((4.0/9.0)*hDD01_i0m1_i1m1_i2 - 1.0/18.0*hDD01_i0m1_i1m2_i2 - 4.0/9.0*hDD01_i0m1_i1p1_i2 + (1.0/18.0)*hDD01_i0m1_i1p2_i2 - 1.0/18.0*hDD01_i0m2_i1m1_i2 + (1.0/144.0)*hDD01_i0m2_i1m2_i2 + (1.0/18.0)*hDD01_i0m2_i1p1_i2 - 1.0/144.0*hDD01_i0m2_i1p2_i2 - 4.0/9.0*hDD01_i0p1_i1m1_i2 + (1.0/18.0)*hDD01_i0p1_i1m2_i2 + (4.0/9.0)*hDD01_i0p1_i1p1_i2 - 1.0/18.0*hDD01_i0p1_i1p2_i2 + (1.0/18.0)*hDD01_i0p2_i1m1_i2 - 1.0/144.0*hDD01_i0p2_i1m2_i2 - 1.0/18.0*hDD01_i0p2_i1p1_i2 + (1.0/144.0)*hDD01_i0p2_i1p2_i2);const double hDD_dDD0111 = tmpFD7*((4.0/3.0)*hDD01_i0_i1m1_i2 + (4.0/3.0)*hDD01_i0_i1p1_i2 - tmpFD14 + tmpFD15 + tmpFD33);const double hDD_dDD0200 = tmpFD4*((4.0/3.0)*hDD02_i0m1_i1_i2 + (4.0/3.0)*hDD02_i0p1_i1_i2 - tmpFD16 + tmpFD17 + tmpFD34);const double hDD_dDD0201 = tmpFD6*((4.0/9.0)*hDD02_i0m1_i1m1_i2 - 1.0/18.0*hDD02_i0m1_i1m2_i2 - 4.0/9.0*hDD02_i0m1_i1p1_i2 + (1.0/18.0)*hDD02_i0m1_i1p2_i2 - 1.0/18.0*hDD02_i0m2_i1m1_i2 + (1.0/144.0)*hDD02_i0m2_i1m2_i2 + (1.0/18.0)*hDD02_i0m2_i1p1_i2 - 1.0/144.0*hDD02_i0m2_i1p2_i2 - 4.0/9.0*hDD02_i0p1_i1m1_i2 + (1.0/18.0)*hDD02_i0p1_i1m2_i2 + (4.0/9.0)*hDD02_i0p1_i1p1_i2 - 1.0/18.0*hDD02_i0p1_i1p2_i2 + (1.0/18.0)*hDD02_i0p2_i1m1_i2 - 1.0/144.0*hDD02_i0p2_i1m2_i2 - 1.0/18.0*hDD02_i0p2_i1p1_i2 + (1.0/144.0)*hDD02_i0p2_i1p2_i2);const double hDD_dDD0211 = tmpFD7*((4.0/3.0)*hDD02_i0_i1m1_i2 + (4.0/3.0)*hDD02_i0_i1p1_i2 - tmpFD18 + tmpFD19 + tmpFD34);const double hDD_dDD1100 = tmpFD4*((4.0/3.0)*hDD11_i0m1_i1_i2 + (4.0/3.0)*hDD11_i0p1_i1_i2 - tmpFD20 + tmpFD21 + tmpFD35);const double hDD_dDD1101 = tmpFD6*((4.0/9.0)*hDD11_i0m1_i1m1_i2 - 1.0/18.0*hDD11_i0m1_i1m2_i2 - 4.0/9.0*hDD11_i0m1_i1p1_i2 + (1.0/18.0)*hDD11_i0m1_i1p2_i2 - 1.0/18.0*hDD11_i0m2_i1m1_i2 + (1.0/144.0)*hDD11_i0m2_i1m2_i2 + (1.0/18.0)*hDD11_i0m2_i1p1_i2 - 1.0/144.0*hDD11_i0m2_i1p2_i2 - 4.0/9.0*hDD11_i0p1_i1m1_i2 + (1.0/18.0)*hDD11_i0p1_i1m2_i2 + (4.0/9.0)*hDD11_i0p1_i1p1_i2 - 1.0/18.0*hDD11_i0p1_i1p2_i2 + (1.0/18.0)*hDD11_i0p2_i1m1_i2 - 1.0/144.0*hDD11_i0p2_i1m2_i2 - 1.0/18.0*hDD11_i0p2_i1p1_i2 + (1.0/144.0)*hDD11_i0p2_i1p2_i2);const double hDD_dDD1111 = tmpFD7*((4.0/3.0)*hDD11_i0_i1m1_i2 + (4.0/3.0)*hDD11_i0_i1p1_i2 - tmpFD22 + tmpFD23 + tmpFD35);const double hDD_dDD1200 = tmpFD4*((4.0/3.0)*hDD12_i0m1_i1_i2 + (4.0/3.0)*hDD12_i0p1_i1_i2 - tmpFD24 + tmpFD25 + tmpFD36);const double hDD_dDD1201 = tmpFD6*((4.0/9.0)*hDD12_i0m1_i1m1_i2 - 1.0/18.0*hDD12_i0m1_i1m2_i2 - 4.0/9.0*hDD12_i0m1_i1p1_i2 + (1.0/18.0)*hDD12_i0m1_i1p2_i2 - 1.0/18.0*hDD12_i0m2_i1m1_i2 + (1.0/144.0)*hDD12_i0m2_i1m2_i2 + (1.0/18.0)*hDD12_i0m2_i1p1_i2 - 1.0/144.0*hDD12_i0m2_i1p2_i2 - 4.0/9.0*hDD12_i0p1_i1m1_i2 + (1.0/18.0)*hDD12_i0p1_i1m2_i2 + (4.0/9.0)*hDD12_i0p1_i1p1_i2 - 1.0/18.0*hDD12_i0p1_i1p2_i2 + (1.0/18.0)*hDD12_i0p2_i1m1_i2 - 1.0/144.0*hDD12_i0p2_i1m2_i2 - 1.0/18.0*hDD12_i0p2_i1p1_i2 + (1.0/144.0)*hDD12_i0p2_i1p2_i2);const double hDD_dDD1211 = tmpFD7*((4.0/3.0)*hDD12_i0_i1m1_i2 + (4.0/3.0)*hDD12_i0_i1p1_i2 - tmpFD26 + tmpFD27 + tmpFD36);const double hDD_dDD2200 = tmpFD4*((4.0/3.0)*hDD22_i0m1_i1_i2 + (4.0/3.0)*hDD22_i0p1_i1_i2 - tmpFD28 + tmpFD29 + tmpFD37);const double hDD_dDD2201 = tmpFD6*((4.0/9.0)*hDD22_i0m1_i1m1_i2 - 1.0/18.0*hDD22_i0m1_i1m2_i2 - 4.0/9.0*hDD22_i0m1_i1p1_i2 + (1.0/18.0)*hDD22_i0m1_i1p2_i2 - 1.0/18.0*hDD22_i0m2_i1m1_i2 + (1.0/144.0)*hDD22_i0m2_i1m2_i2 + (1.0/18.0)*hDD22_i0m2_i1p1_i2 - 1.0/144.0*hDD22_i0m2_i1p2_i2 - 4.0/9.0*hDD22_i0p1_i1m1_i2 + (1.0/18.0)*hDD22_i0p1_i1m2_i2 + (4.0/9.0)*hDD22_i0p1_i1p1_i2 - 1.0/18.0*hDD22_i0p1_i1p2_i2 + (1.0/18.0)*hDD22_i0p2_i1m1_i2 - 1.0/144.0*hDD22_i0p2_i1m2_i2 - 1.0/18.0*hDD22_i0p2_i1p1_i2 + (1.0/144.0)*hDD22_i0p2_i1p2_i2);const double hDD_dDD2211 = tmpFD7*((4.0/3.0)*hDD22_i0_i1m1_i2 + (4.0/3.0)*hDD22_i0_i1p1_i2 - tmpFD30 + tmpFD31 + tmpFD37);const double lambdaU_dD00 = invdx0*(-2.0/3.0*lambdaU0_i0m1_i1_i2 + (1.0/12.0)*lambdaU0_i0m2_i1_i2 + (2.0/3.0)*lambdaU0_i0p1_i1_i2 - 1.0/12.0*lambdaU0_i0p2_i1_i2);const double lambdaU_dD01 = invdx1*(-2.0/3.0*lambdaU0_i0_i1m1_i2 + (1.0/12.0)*lambdaU0_i0_i1m2_i2 + (2.0/3.0)*lambdaU0_i0_i1p1_i2 - 1.0/12.0*lambdaU0_i0_i1p2_i2);const double lambdaU_dD10 = invdx0*(-2.0/3.0*lambdaU1_i0m1_i1_i2 + (1.0/12.0)*lambdaU1_i0m2_i1_i2 + (2.0/3.0)*lambdaU1_i0p1_i1_i2 - 1.0/12.0*lambdaU1_i0p2_i1_i2);const double lambdaU_dD11 = invdx1*(-2.0/3.0*lambdaU1_i0_i1m1_i2 + (1.0/12.0)*lambdaU1_i0_i1m2_i2 + (2.0/3.0)*lambdaU1_i0_i1p1_i2 - 1.0/12.0*lambdaU1_i0_i1p2_i2);const double lambdaU_dD20 = invdx0*(-2.0/3.0*lambdaU2_i0m1_i1_i2 + (1.0/12.0)*lambdaU2_i0m2_i1_i2 + (2.0/3.0)*lambdaU2_i0p1_i1_i2 - 1.0/12.0*lambdaU2_i0p2_i1_i2);const double lambdaU_dD21 = invdx1*(-2.0/3.0*lambdaU2_i0_i1m1_i2 + (1.0/12.0)*lambdaU2_i0_i1m2_i2 + (2.0/3.0)*lambdaU2_i0_i1p1_i2 - 1.0/12.0*lambdaU2_i0_i1p2_i2);/** NRPy+ Finite Difference Code Generation, Step 2 of 2: Evaluate SymPy expressions and write to main memory:*/const double tmp0 = ((xx0)*(xx0));const double tmp1 = sin(xx1);const double tmp2 = hDD02*tmp1;const double tmp3 = tmp0*tmp2;const double tmp4 = hDD00 + 1;const double tmp5 = hDD12*tmp1;const double tmp6 = tmp0*tmp5;const double tmp7 = hDD01*tmp3 - tmp4*tmp6;const double tmp8 = ((tmp7)*(tmp7));const double tmp9 = 2*hDD01;const double tmp10 = ((tmp1)*(tmp1));const double tmp11 = tmp10*((xx0)*(xx0)*(xx0)*(xx0));const double tmp12 = hDD02*hDD12;const double tmp13 = ((hDD12)*(hDD12))*tmp11;const double tmp14 = hDD11*tmp0;const double tmp15 = tmp0 + tmp14;const double tmp16 = tmp0*tmp10;const double tmp17 = ((hDD02)*(hDD02))*tmp16;const double tmp18 = hDD22*tmp16;const double tmp19 = tmp16 + tmp18;const double tmp20 = ((hDD01)*(hDD01))*tmp0;const double tmp21 = tmp15*tmp4;const double tmp22 = tmp11*tmp12*tmp9 - tmp13*tmp4 - tmp15*tmp17 - tmp19*tmp20 + tmp19*tmp21;const double tmp23 = (1.0/((tmp22)*(tmp22)));const double tmp24 = aDD11*tmp0;const double tmp25 = tmp23*tmp24;const double tmp26 = ((xx0)*(xx0)*(xx0));const double tmp27 = tmp2*xx0;const double tmp28 = hDD01*tmp26*tmp5 - tmp15*tmp27;const double tmp29 = ((tmp28)*(tmp28));const double tmp30 = aDD00*tmp23;const double tmp31 = -tmp20 + tmp21;const double tmp32 = aDD22*tmp16;const double tmp33 = tmp23*tmp32;const double tmp34 = 2*xx0;const double tmp35 = aDD01*tmp23;const double tmp36 = tmp34*tmp35;const double tmp37 = tmp28*tmp7;const double tmp38 = tmp0*tmp1;const double tmp39 = aDD12*tmp38;const double tmp40 = tmp23*tmp39;const double tmp41 = tmp31*tmp40;const double tmp42 = tmp1*tmp34;const double tmp43 = aDD02*tmp23;const double tmp44 = tmp42*tmp43;const double tmp45 = tmp28*tmp44;const double tmp46 = hDD01*xx0;const double tmp47 = tmp10*tmp12*tmp26 - tmp19*tmp46;const double tmp48 = ((tmp47)*(tmp47));const double tmp49 = -tmp17 + tmp19*tmp4;const double tmp50 = tmp47*tmp7;const double tmp51 = tmp49*tmp7;const double tmp52 = 2*tmp40;const double tmp53 = tmp36*tmp47;const double tmp54 = -tmp13 + tmp15*tmp19;const double tmp55 = tmp28*tmp47;const double tmp56 = tmp1*xx0;const double tmp57 = tmp43*tmp56;const double tmp58 = tmp31*tmp33;const double tmp59 = tmp35*xx0;const double tmp60 = tmp31*tmp47;const double tmp61 = tmp28*tmp49;const double tmp62 = tmp25*tmp47;const double tmp63 = tmp54*tmp59;const double tmp64 = tmp30*tmp54;const double tmp65 = tmp54*tmp57;const double tmp66 = ((cf)*(cf));const double tmp67 = (1.0/(tmp66));const double tmp68 = (1.0/(tmp22));const double tmp69 = tmp47*tmp68;const double tmp70 = ((cf_dD1)*(cf_dD1));const double tmp71 = tmp49*tmp68;const double tmp72 = 2*tmp67;const double tmp73 = ((cf_dD0)*(cf_dD0));const double tmp74 = tmp54*tmp68;const double tmp75 = tmp10*xx0;const double tmp76 = 2*tmp75;const double tmp77 = hDD22*tmp76;const double tmp78 = hDD_dD220*tmp16;const double tmp79 = tmp77 + tmp78;const double tmp80 = tmp76 + tmp79;const double tmp81 = tmp68*tmp7;const double tmp82 = (1.0/2.0)*tmp81;const double tmp83 = tmp80*tmp82;const double tmp84 = cos(xx1);const double tmp85 = hDD02*tmp84;const double tmp86 = tmp85*xx0;const double tmp87 = hDD_dD021*tmp1;const double tmp88 = tmp87*xx0;const double tmp89 = tmp34*tmp5;const double tmp90 = hDD_dD120*tmp38;const double tmp91 = tmp89 + tmp90;const double tmp92 = -tmp86 - tmp88 + tmp91;const double tmp93 = (1.0/2.0)*tmp71;const double tmp94 = tmp92*tmp93;const double tmp95 = (1.0/(cf));const double tmp96 = (1.0/2.0)*tmp95;const double tmp97 = cf_dD1*tmp96;const double tmp98 = tmp28*tmp68;const double tmp99 = (1.0/2.0)*tmp98;const double tmp100 = tmp80*tmp99;const double tmp101 = (1.0/2.0)*tmp69;const double tmp102 = tmp101*tmp92;const double tmp103 = cf_dD0*tmp95;const double tmp104 = (1.0/2.0)*tmp103;const double tmp105 = 2*xx1;const double tmp106 = sin(tmp105);const double tmp107 = tmp0*tmp106;const double tmp108 = hDD_dD221*tmp16;const double tmp109 = tmp38*tmp84;const double tmp110 = 2*tmp109;const double tmp111 = hDD22*tmp110;const double tmp112 = tmp108 + tmp111;const double tmp113 = tmp107 + tmp112;const double tmp114 = tmp113*tmp82;const double tmp115 = tmp86 + tmp88;const double tmp116 = tmp115 - tmp89 - tmp90;const double tmp117 = tmp101*tmp116;const double tmp118 = tmp113*tmp99;const double tmp119 = (1.0/2.0)*tmp74;const double tmp120 = tmp116*tmp119;const double tmp121 = -1.0/2.0*tmp76 - 1.0/2.0*tmp77 - 1.0/2.0*tmp78;const double tmp122 = tmp121*tmp69;const double tmp123 = -1.0/2.0*tmp107 - 1.0/2.0*tmp108 - 1.0/2.0*tmp111;const double tmp124 = tmp123*tmp71;const double tmp125 = tmp123*tmp69;const double tmp126 = tmp121*tmp74;const double tmp127 = tmp31*tmp68;const double tmp128 = 2*tmp2;const double tmp129 = hDD_dD020*tmp1;const double tmp130 = tmp128 + tmp129*tmp34;const double tmp131 = tmp130*tmp82;const double tmp132 = hDD_dD000*tmp101;const double tmp133 = -hDD_dD001 + hDD_dD010*tmp34 + tmp9;const double tmp134 = tmp133*tmp93;const double tmp135 = tmp130*tmp99;const double tmp136 = hDD_dD000*tmp119;const double tmp137 = tmp101*tmp133;const double tmp138 = hDD_dD001*tmp101;const double tmp139 = tmp115 + tmp91;const double tmp140 = tmp139*tmp82;const double tmp141 = hDD11*tmp34;const double tmp142 = hDD_dD110*tmp0;const double tmp143 = tmp141 + tmp142;const double tmp144 = tmp143 + tmp34;const double tmp145 = tmp144*tmp93;const double tmp146 = hDD_dD001*tmp119;const double tmp147 = tmp101*tmp144;const double tmp148 = tmp139*tmp99;const double tmp149 = 2*tmp0;const double tmp150 = tmp149*tmp84;const double tmp151 = hDD_dD121*tmp38;const double tmp152 = hDD12*tmp150 + 2*tmp151;const double tmp153 = tmp152*tmp82;const double tmp154 = hDD_dD111*tmp0;const double tmp155 = tmp154*tmp93;const double tmp156 = hDD_dD011*tmp34 - tmp141 - tmp142 - tmp34;const double tmp157 = tmp101*tmp156;const double tmp158 = tmp101*tmp154;const double tmp159 = tmp152*tmp99;const double tmp160 = tmp119*tmp156;const double tmp161 = (1.0/2.0)*tmp106;const double tmp162 = hDD12*xx0;const double tmp163 = (1.0/(xx0));const double tmp164 = lambdaU0*tmp163;const double tmp165 = (1.0/(tmp10));const double tmp166 = tmp161*tmp165;const double tmp167 = lambdaU1*tmp163*tmp166 + tmp164;const double tmp168 = ((tmp1)*(tmp1)*(tmp1));const double tmp169 = hDD_dD020*tmp168;const double tmp170 = hDD_dD120*tmp1;const double tmp171 = hDD02*tmp168;const double tmp172 = tmp107*tmp5 + tmp149*tmp171;const double tmp173 = tmp163*tmp172;const double tmp174 = -tmp173;const double tmp175 = hDD22*tmp10;const double tmp176 = tmp163*tmp79;const double tmp177 = tmp171*tmp34;const double tmp178 = tmp129*xx0 + tmp2;const double tmp179 = tmp106*tmp91;const double tmp180 = cos(tmp105);const double tmp181 = tmp149*tmp5;const double tmp182 = tmp0*tmp84;const double tmp183 = hDD12*tmp182 + tmp151;const double tmp184 = tmp106*tmp183;const double tmp185 = tmp106*tmp165;const double tmp186 = -tmp166*tmp172;const double tmp187 = tmp5*xx0;const double tmp188 = (1.0/(tmp1));const double tmp189 = tmp161*tmp188;const double tmp190 = -hDD02*tmp189*xx0 - tmp187;const double tmp191 = tmp115 + tmp190;const double tmp192 = tmp107*tmp188;const double tmp193 = (1.0/2.0)*hDD12;const double tmp194 = tmp183 - tmp192*tmp193 + tmp3;const double tmp195 = tmp106*tmp194;const double tmp196 = hDD22*tmp107;const double tmp197 = tmp112 - tmp196;const double tmp198 = tmp163*tmp197;const double tmp199 = 4*hDD22*tmp56*tmp84 + hDD_dD220*tmp110 + hDD_dD221*tmp76 + hDD_dDD2201*tmp16;const double tmp200 = hDD_dD220*tmp26;const double tmp201 = hDD00*tmp75 - hDD22*tmp75 + tmp161*tmp46;const double tmp202 = hDD01*tmp16 + tmp14*tmp161 - 1.0/2.0*tmp196;const double tmp203 = tmp106*tmp202;const double tmp204 = (1.0/2.0)*tmp127;const double tmp205 = -tmp198;const double tmp206 = tmp112*tmp163;const double tmp207 = hDD_dD220*tmp107;const double tmp208 = tmp165*tmp180;const double tmp209 = (1.0/(tmp168));const double tmp210 = tmp106*tmp209*tmp84;const double tmp211 = -tmp208 + tmp210;const double tmp212 = tmp18*tmp211;const double tmp213 = tmp208 - tmp210;const double tmp214 = -tmp18*tmp213;const double tmp215 = tmp121*tmp98 + tmp123*tmp81;const double tmp216 = tmp100 + tmp102;const double tmp217 = tmp83 + tmp94;const double tmp218 = -tmp163;const double tmp219 = tmp204*tmp80 + tmp218 + tmp82*tmp92;const double tmp220 = tmp19*tmp219;const double tmp221 = tmp216*tmp27 + tmp217*tmp6 + tmp220;const double tmp222 = tmp215*tmp221;const double tmp223 = 3*tmp98;const double tmp224 = tmp219*tmp221;const double tmp225 = 3*tmp74;const double tmp226 = tmp114 + tmp117;const double tmp227 = tmp118 + tmp120;const double tmp228 = tmp113*tmp204 + tmp116*tmp99 - tmp166;const double tmp229 = tmp19*tmp228;const double tmp230 = tmp226*tmp6 + tmp227*tmp27 + tmp229;const double tmp231 = tmp215*tmp230;const double tmp232 = 3*tmp81;const double tmp233 = tmp221*tmp228;const double tmp234 = 3*tmp69;const double tmp235 = tmp219*tmp230;const double tmp236 = tmp228*tmp230;const double tmp237 = 3*tmp71;const double tmp238 = tmp19*tmp215;const double tmp239 = tmp122 + tmp124 + tmp161;const double tmp240 = tmp125 + tmp126 + tmp75;const double tmp241 = tmp238 + tmp239*tmp6 + tmp240*tmp27;const double tmp242 = 3*tmp127;const double tmp243 = tmp219*tmp241;const double tmp244 = tmp228*tmp241;const double tmp245 = tmp216*tmp221;const double tmp246 = tmp215*tmp27 + tmp239*tmp46 + tmp240*tmp4;const double tmp247 = tmp216*tmp246;const double tmp248 = tmp221*tmp227;const double tmp249 = tmp227*tmp246;const double tmp250 = tmp226*tmp230;const double tmp251 = tmp15*tmp239 + tmp215*tmp6 + tmp240*tmp46;const double tmp252 = tmp226*tmp251;const double tmp253 = tmp217*tmp230;const double tmp254 = tmp217*tmp251;const double tmp255 = 2*tmp240;const double tmp256 = 2*tmp239;const double tmp257 = tmp216*tmp4;const double tmp258 = tmp217*tmp46 + tmp219*tmp27 + tmp257;const double tmp259 = tmp216*tmp258;const double tmp260 = hDD_dD000*tmp99 + tmp130*tmp204 + tmp133*tmp82;const double tmp261 = tmp131 + tmp132 + tmp134;const double tmp262 = tmp135 + tmp136 + tmp137;const double tmp263 = tmp19*tmp260 + tmp261*tmp6 + tmp262*tmp27;const double tmp264 = tmp216*tmp263;const double tmp265 = tmp227*tmp258;const double tmp266 = tmp227*tmp263;const double tmp267 = tmp240*tmp258;const double tmp268 = tmp15*tmp217 + tmp216*tmp46 + tmp219*tmp6;const double tmp269 = tmp226*tmp268;const double tmp270 = hDD_dD001*tmp99 + tmp139*tmp204 + tmp144*tmp82;const double tmp271 = tmp138 + tmp140 + tmp145 + tmp218;const double tmp272 = tmp146 + tmp147 + tmp148;const double tmp273 = tmp19*tmp270 + tmp27*tmp272 + tmp271*tmp6;const double tmp274 = tmp226*tmp273;const double tmp275 = tmp217*tmp268;const double tmp276 = tmp217*tmp273;const double tmp277 = tmp226*tmp46 + tmp227*tmp4 + tmp228*tmp27;const double tmp278 = tmp216*tmp277;const double tmp279 = tmp216*tmp273;const double tmp280 = tmp15*tmp226;const double tmp281 = tmp227*tmp46 + tmp228*tmp6 + tmp280;const double tmp282 = tmp217*tmp281;const double tmp283 = tmp152*tmp204 + tmp154*tmp82 + tmp156*tmp99;const double tmp284 = tmp153 + tmp155 + tmp157;const double tmp285 = tmp158 + tmp159 + tmp160 + xx0;const double tmp286 = tmp19*tmp283 + tmp27*tmp285 + tmp284*tmp6;const double tmp287 = tmp217*tmp286;const double tmp288 = tmp226*tmp281;const double tmp289 = tmp226*tmp286;const double tmp290 = tmp227*tmp277;const double tmp291 = tmp227*tmp273;const double tmp292 = tmp239*tmp268;const double tmp293 = tmp239*tmp281;const double tmp294 = tmp240*tmp277;const double tmp295 = tmp2*tmp34;const double tmp296 = tmp119*tmp260 + tmp204*tmp215 + tmp219*tmp98 + tmp228*tmp81 + tmp270*tmp69 + tmp283*tmp93;const double tmp297 = tmp119*tmp261 + tmp204*tmp239 + tmp217*tmp98 + tmp226*tmp81 + tmp271*tmp69 + tmp284*tmp93;const double tmp298 = tmp119*tmp262 + tmp204*tmp240 + tmp216*tmp98 + tmp227*tmp81 + tmp272*tmp69 + tmp285*tmp93;const double tmp299 = 2*hDD_dD010;const double tmp300 = hDD_dD001 - tmp9;const double tmp301 = hDD_dDD0001 - tmp163*tmp300;const double tmp302 = tmp163*tmp2;const double tmp303 = tmp163*tmp178;const double tmp304 = 2*hDD_dD011;const double tmp305 = hDD_dD000*xx0;const double tmp306 = hDD_dD011*xx0;const double tmp307 = hDD00*xx0 - hDD11*xx0 + tmp306;const double tmp308 = tmp163*tmp307;const double tmp309 = tmp305 - 2*tmp308;const double tmp310 = hDD_dD010*xx0;const double tmp311 = hDD01 + tmp310;const double tmp312 = tmp163*tmp311;const double tmp313 = tmp106*tmp188;const double tmp314 = hDD02*tmp313;const double tmp315 = tmp163*tmp191;const double tmp316 = -2*tmp315;const double tmp317 = tmp163*tmp201;const double tmp318 = hDD_dD000*tmp75;const double tmp319 = -2*tmp317 + tmp318;const double tmp320 = tmp115*tmp163;const double tmp321 = tmp163*tmp190;const double tmp322 = -2*tmp321;const double tmp323 = tmp258*tmp262;const double tmp324 = tmp258*tmp272;const double tmp325 = tmp262*tmp4;const double tmp326 = tmp260*tmp27 + tmp261*tmp46 + tmp325;const double tmp327 = tmp216*tmp326;const double tmp328 = tmp272*tmp4;const double tmp329 = tmp27*tmp270 + tmp271*tmp46 + tmp328;const double tmp330 = tmp216*tmp329;const double tmp331 = tmp272*tmp326;const double tmp332 = tmp262*tmp329;const double tmp333 = tmp272*tmp329;const double tmp334 = tmp217*tmp277;const double tmp335 = tmp219*tmp246;const double tmp336 = tmp261*tmp268;const double tmp337 = 2*tmp261;const double tmp338 = tmp221*tmp260;const double tmp339 = 2*tmp260;const double tmp340 = tmp221*tmp270;const double tmp341 = tmp246*tmp270;const double tmp342 = tmp268*tmp271;const double tmp343 = tmp271*tmp277;const double tmp344 = tmp219*tmp258;const double tmp345 = tmp219*tmp263;const double tmp346 = tmp219*tmp277;const double tmp347 = tmp219*tmp273;const double tmp348 = tmp258*tmp270;const double tmp349 = tmp263*tmp270;const double tmp350 = tmp260*tmp273;const double tmp351 = tmp270*tmp277;const double tmp352 = tmp270*tmp273;const double tmp353 = tmp15*tmp261 + tmp260*tmp6 + tmp262*tmp46;const double tmp354 = tmp217*tmp353;const double tmp355 = tmp217*tmp329;const double tmp356 = tmp27*tmp283 + tmp284*tmp46 + tmp285*tmp4;const double tmp357 = tmp217*tmp356;const double tmp358 = tmp15*tmp271;const double tmp359 = tmp270*tmp6 + tmp272*tmp46 + tmp358;const double tmp360 = tmp217*tmp359;const double tmp361 = tmp271*tmp353;const double tmp362 = tmp271*tmp329;const double tmp363 = tmp261*tmp359;const double tmp364 = tmp271*tmp356;const double tmp365 = tmp271*tmp359;const double tmp366 = hDD01*tmp34;const double tmp367 = -lambdaU1 + lambdaU_dD01;const double tmp368 = lambdaU_dD11*tmp163 + tmp164;const double tmp369 = tmp163*tmp188;const double tmp370 = lambdaU2*tmp163;const double tmp371 = lambdaU_dD21*tmp369 + tmp161*tmp209*tmp370 - tmp165*tmp370*tmp84;const double tmp372 = tmp162*tmp313;const double tmp373 = hDD_dD120*tmp192;const double tmp374 = hDD_dDD1101*tmp0;const double tmp375 = tmp0*tmp9 + tmp154;const double tmp376 = tmp163*tmp375;const double tmp377 = -tmp376;const double tmp378 = hDD_dD110*tmp26;const double tmp379 = tmp143*tmp163;const double tmp380 = tmp0*((tmp106)*(tmp106))*tmp193;const double tmp381 = tmp209*tmp380;const double tmp382 = tmp161*tmp375;const double tmp383 = -tmp165*tmp203;const double tmp384 = tmp211*tmp6;const double tmp385 = -tmp213*tmp6;const double tmp386 = tmp281*tmp284;const double tmp387 = tmp271*tmp281;const double tmp388 = tmp15*tmp284;const double tmp389 = tmp283*tmp6 + tmp285*tmp46 + tmp388;const double tmp390 = tmp226*tmp389;const double tmp391 = tmp226*tmp359;const double tmp392 = tmp284*tmp359;const double tmp393 = tmp271*tmp389;const double tmp394 = tmp227*tmp268;const double tmp395 = tmp228*tmp251;const double tmp396 = tmp268*tmp272;const double tmp397 = tmp272*tmp277;const double tmp398 = 2*tmp285;const double tmp399 = tmp277*tmp285;const double tmp400 = tmp230*tmp283;const double tmp401 = 2*tmp283;const double tmp402 = tmp230*tmp270;const double tmp403 = tmp251*tmp270;const double tmp404 = tmp228*tmp268;const double tmp405 = tmp228*tmp273;const double tmp406 = tmp228*tmp281;const double tmp407 = tmp228*tmp286;const double tmp408 = tmp273*tmp283;const double tmp409 = tmp268*tmp270;const double tmp410 = tmp270*tmp281;const double tmp411 = tmp270*tmp286;const double tmp412 = tmp227*tmp353;const double tmp413 = tmp227*tmp329;const double tmp414 = tmp227*tmp356;const double tmp415 = tmp227*tmp359;const double tmp416 = tmp285*tmp329;const double tmp417 = tmp272*tmp353;const double tmp418 = tmp272*tmp356;const double tmp419 = tmp272*tmp359;const double tmp420 = tmp215*tmp246;const double tmp421 = tmp239*tmp277 + tmp253;const double tmp422 = tmp228*tmp277;const double tmp423 = 2*tmp402;const double tmp424 = tmp272*tmp273;const double tmp425 = tmp397 + tmp424;const double tmp426 = tmp226*tmp356;const double tmp427 = tmp271*tmp286;const double tmp428 = tmp387 + tmp427;const double tmp429 = tmp261*tmp273 + tmp355;const double tmp430 = tmp262*tmp263;const double tmp431 = tmp215*tmp277;const double tmp432 = tmp215*tmp258;const double tmp433 = tmp230*tmp260;const double tmp434 = tmp241*tmp260;const double tmp435 = tmp228*tmp258;const double tmp436 = 2*tmp340;const double tmp437 = tmp228*tmp246;const double tmp438 = tmp241*tmp270;const double tmp439 = 2*tmp438;const double tmp440 = tmp261*tmp281;const double tmp441 = tmp261*tmp286 + tmp357;const double tmp442 = tmp227*tmp326;const double tmp443 = tmp263*tmp272;const double tmp444 = tmp324 + tmp443;const double tmp445 = tmp226*tmp329;const double tmp446 = tmp271*tmp273;const double tmp447 = tmp342 + tmp446;const double tmp448 = tmp262*tmp277;const double tmp449 = tmp262*tmp273;const double tmp450 = tmp239*tmp356 + tmp287;const double tmp451 = tmp221*tmp272;const double tmp452 = tmp246*tmp272 + tmp451;const double tmp453 = tmp226*tmp277;const double tmp454 = tmp230*tmp271;const double tmp455 = tmp251*tmp271 + tmp454;const double tmp456 = tmp240*tmp329;const double tmp457 = tmp230*tmp261 + tmp334;const double tmp458 = tmp239*tmp329 + tmp276;const double tmp459 = tmp240*tmp326;const double tmp460 = tmp221*tmp262;const double tmp461 = tmp163*tmp183;const double tmp462 = -tmp115*tmp166 - tmp461;const double tmp463 = -tmp213*tmp27 + tmp462;const double tmp464 = tmp0*tmp129;const double tmp465 = tmp34*tmp84;const double tmp466 = tmp163*tmp194;const double tmp467 = -tmp466;const double tmp468 = -tmp166*tmp191 + tmp467;const double tmp469 = hDD_dD021*tmp465 + hDD_dDD0211*tmp56 - tmp27 + tmp464 + tmp468;const double tmp470 = (1.0/2.0)*tmp4;const double tmp471 = lambdaU2*tmp1;const double tmp472 = tmp163*tmp91;const double tmp473 = -tmp166*tmp178 - tmp472 + tmp5;const double tmp474 = hDD_dD020*xx0;const double tmp475 = hDD_dDD0201*tmp56 + tmp474*tmp84 + tmp85 + tmp87;const double tmp476 = -tmp170*xx0 - tmp189*tmp474;const double tmp477 = tmp161*tmp307 - tmp166*tmp201;const double tmp478 = tmp163*tmp202;const double tmp479 = -tmp478;const double tmp480 = (1.0/2.0)*tmp27;const double tmp481 = (1.0/2.0)*lambdaU_dD10;const double tmp482 = (1.0/2.0)*lambdaU_dD20;const double tmp483 = (1.0/4.0)*lambdaU2;const double tmp484 = -hDD01*tmp313*tmp483 + lambdaU_dD00*tmp480 - tmp101*(tmp316 + tmp473 + tmp475) - tmp101*(-tmp315 - tmp320 + tmp475 + tmp476) - tmp119*(hDD_dDD0200*tmp56 + tmp129 + tmp302 - tmp303) + tmp167*tmp480 + tmp187*tmp481 + tmp19*tmp369*tmp482 - tmp204*(tmp0*tmp169 + tmp161*tmp190 + tmp161*tmp191 + tmp174 - tmp177) + tmp296*(tmp221 + tmp246) + tmp297*(tmp273 + tmp277) + tmp298*(tmp258 + tmp263) - tmp470*tmp471 - tmp82*(tmp205 + tmp300*tmp75 + tmp477) - tmp82*(hDD00*tmp1*tmp465 + hDD_dD001*tmp75 + tmp161*tmp306 + tmp180*tmp46 - tmp185*tmp201 - tmp206 + tmp479) - tmp99*(-hDD_dD220*tmp75 + tmp161*tmp310 - tmp317 + tmp318) - tmp99*(hDD00*tmp10 + tmp161*tmp311 + tmp175 - tmp176 + tmp319);const double tmp485 = tmp215*tmp251;const double tmp486 = tmp240*tmp268 + tmp248;const double tmp487 = tmp273*tmp285 + tmp415;const double tmp488 = tmp284*tmp286;const double tmp489 = tmp219*tmp268;const double tmp490 = tmp216*tmp353;const double tmp491 = tmp215*tmp268;const double tmp492 = tmp215*tmp281;const double tmp493 = tmp219*tmp281;const double tmp494 = tmp219*tmp251;const double tmp495 = tmp221*tmp283;const double tmp496 = tmp241*tmp283;const double tmp497 = tmp217*tmp389;const double tmp498 = tmp258*tmp285;const double tmp499 = tmp263*tmp285 + tmp412;const double tmp500 = tmp268*tmp284;const double tmp501 = tmp273*tmp284;const double tmp502 = tmp216*tmp359;const double tmp503 = tmp240*tmp359 + tmp291;const double tmp504 = tmp221*tmp285 + tmp394;const double tmp505 = tmp239*tmp389;const double tmp506 = tmp230*tmp284;const double tmp507 = tmp240*tmp353 + tmp266;const double tmp508 = tmp239*tmp359;const double tmp509 = tmp216*tmp268;const double tmp510 = hDD_dD121*tmp150 + hDD_dDD1211*tmp38 + tmp115*xx0 - tmp166*tmp183 - tmp166*tmp194 + tmp170*tmp26 + tmp191*xx0 - tmp6;const double tmp511 = (1.0/2.0)*tmp107;const double tmp512 = hDD_dD011*tmp16 + hDD_dD111*tmp511 + tmp109*tmp9 - tmp112*tmp166 + tmp14*tmp180 + tmp201*xx0 + tmp383;const double tmp513 = (1.0/2.0)*tmp371;const double tmp514 = hDD12*tmp465 + hDD_dD120*tmp182 + hDD_dD121*tmp42 + hDD_dDD1201*tmp38;const double tmp515 = hDD_dD010*tmp16 + tmp479;const double tmp516 = (1.0/2.0)*tmp6;const double tmp517 = (1.0/2.0)*tmp46;const double tmp518 = -tmp101*(-1.0/2.0*tmp373 - 2*tmp461 + tmp464 + tmp467 + tmp514) - tmp101*(-tmp166*tmp91 + tmp178*xx0 + tmp27 - 3*tmp466 + tmp514) - tmp106*tmp15*tmp369*tmp483 - tmp119*(hDD_dDD1200*tmp38 + tmp170*tmp34 - 2*tmp472 + 4*tmp5) + tmp167*tmp516 + tmp19*tmp513 - tmp204*(hDD_dD120*tmp168*tmp26 + tmp161*tmp194 + tmp186 - tmp188*tmp380 + tmp190*tmp75) + tmp296*(tmp230 + tmp251) + tmp297*(tmp281 + tmp286) + tmp298*(tmp268 + tmp273) + tmp367*tmp480 + tmp368*tmp516 - tmp471*tmp517 - tmp82*(-tmp166*tmp197 - tmp166*tmp202 + tmp307*tmp75 + tmp382) - tmp99*(hDD_dD110*tmp511 - 1.0/2.0*tmp207 + tmp515) - tmp99*(hDD01*tmp75 + tmp143*tmp161 - tmp166*tmp79 + tmp311*tmp75 - 3*tmp478);const double tmp519 = 2*tmp413;const double tmp520 = tmp391 + tmp426;const double tmp521 = 2*tmp265;const double tmp522 = 2*tmp442;const double tmp523 = tmp226*tmp353 + tmp445;const double tmp524 = tmp228*tmp263;const double tmp525 = tmp269 + tmp453;const double tmp526 = tmp215*tmp273;const double tmp527 = tmp211*tmp27 + tmp462;const double tmp528 = 2*tmp360;const double tmp529 = tmp330 + tmp490;const double tmp530 = 2*tmp282;const double tmp531 = 2*tmp497;const double tmp532 = tmp216*tmp356 + tmp502;const double tmp533 = tmp219*tmp286;const double tmp534 = tmp278 + tmp509;const double tmp535 = tmp437 + tmp494;const double tmp536 = tmp277*tmp283 + tmp410;const double tmp537 = tmp284*tmp356;const double tmp538 = tmp262*tmp353;const double tmp539 = tmp260*tmp268 + tmp348;const double tmp540 = tmp262*tmp268;const double tmp541 = tmp285*tmp326;const double tmp542 = tmp262*tmp359;const double tmp543 = tmp260*tmp281 + tmp351;const double tmp544 = tmp258*tmp283 + tmp409;const double tmp545 = tmp284*tmp329;const double tmp546 = tmp261*tmp389;const double tmp547 = tmp422 + tmp493;const double tmp548 = tmp277*tmp284;const double tmp549 = tmp246*tmp283 + tmp403;const double tmp550 = tmp435 + tmp489;const double tmp551 = tmp251*tmp260 + tmp341;const double tmp552 = -tmp166*tmp190;const double tmp553 = -tmp295 + tmp372 + tmp552;const double tmp554 = hDD_dDD0101*xx0;const double tmp555 = lambdaU_dD00*tmp517 - tmp101*(-hDD_dD110*xx0 + tmp305 - tmp308 + tmp554) - tmp101*(hDD00 + hDD11 + hDD_dD011 + tmp309 - tmp379 + tmp554) - tmp119*(hDD01*tmp163 + hDD_dD010 + hDD_dDD0100*xx0 - tmp312) + tmp15*tmp163*tmp481 + tmp162*tmp482 - tmp204*(tmp477 + tmp515) + tmp27*tmp513 + tmp296*(tmp268 + tmp277) + tmp297*(tmp356 + tmp359) + tmp298*(tmp329 + tmp353) + tmp367*tmp470 + tmp368*tmp517 - tmp82*(tmp468 + tmp552) - tmp93*(hDD_dD001*xx0 + hDD_dD010*tmp0 - hDD_dD111*xx0 + hDD_dDD0111*xx0 + tmp300*xx0 + tmp377) - tmp99*(-tmp321 + tmp476) - tmp99*(tmp322 + tmp473);aux_gfs[IDX4S(HGF, i0, i1, i2)] = -aDD00*(tmp25*tmp48 + tmp29*tmp33 + tmp30*((tmp54)*(tmp54)) + tmp45*tmp54 + tmp52*tmp55 + tmp53*tmp54) - aDD01*tmp34*(tmp33*tmp37 + tmp40*tmp50 + tmp40*tmp61 + tmp47*tmp64 + tmp48*tmp59 + tmp49*tmp62 + tmp49*tmp63 + tmp55*tmp57 + tmp65*tmp7) - aDD02*tmp42*(tmp28*tmp58 + tmp28*tmp64 + tmp29*tmp57 + tmp31*tmp65 + tmp37*tmp40 + tmp40*tmp60 + tmp55*tmp59 + tmp62*tmp7 + tmp63*tmp7) - tmp24*(tmp25*((tmp49)*(tmp49)) + tmp30*tmp48 + tmp33*tmp8 + tmp44*tmp50 + tmp49*tmp53 + tmp51*tmp52) - tmp32*(tmp25*tmp8 + tmp29*tmp30 + ((tmp31)*(tmp31))*tmp33 + tmp31*tmp45 + tmp36*tmp37 + 2*tmp41*tmp7) - 2*tmp39*(tmp25*tmp51 + tmp30*tmp55 + tmp37*tmp57 + tmp40*tmp8 + tmp41*tmp49 + tmp50*tmp59 + tmp57*tmp60 + tmp58*tmp7 + tmp59*tmp61) + tmp66*(-4*cf_dD0*cf_dD1*tmp67*tmp69 - 8*tmp127*(-tmp104*(-tmp125 - tmp126) - tmp97*(-tmp122 - tmp124)) + tmp127*(-hDD02*lambdaU2*tmp75 - lambdaU2*tmp161*tmp162 - tmp101*(-tmp185*tmp79 - 3*tmp198 + tmp199) - tmp101*(tmp199 + tmp205 - 2*tmp206 - tmp207) - tmp119*(hDD_dD220*tmp76 + hDD_dDD2200*tmp16 + 4*tmp175 - 2*tmp176) + tmp127*(tmp221*tmp255 + tmp240*tmp246) + tmp127*(tmp230*tmp256 + tmp239*tmp251) + tmp167*tmp19 - tmp204*(((tmp1)*(tmp1)*(tmp1)*(tmp1))*tmp200 + tmp161*tmp197 + tmp201*tmp76 + tmp203) + tmp215*tmp241*tmp242 + tmp222*tmp223 + tmp223*tmp243 + tmp224*tmp225 + tmp231*tmp232 + tmp232*tmp244 + tmp233*tmp234 + tmp234*tmp235 + tmp236*tmp237 + tmp296*(2*tmp238 + tmp240*tmp295 + tmp256*tmp6) + tmp297*(tmp181*tmp226 + tmp227*tmp295 + 2*tmp229) + tmp298*(tmp181*tmp217 + tmp216*tmp295 + 2*tmp220) + tmp69*(tmp265 + 2*tmp266) + tmp69*(tmp269 + 2*tmp274) + tmp69*(tmp278 + 2*tmp279) + tmp69*(tmp282 + 2*tmp287) + tmp71*(tmp288 + 2*tmp289) + tmp71*(tmp290 + 2*tmp291) + tmp74*(tmp259 + 2*tmp264) + tmp74*(tmp275 + 2*tmp276) + tmp81*(2*tmp248 + tmp249) + tmp81*(2*tmp250 + tmp252) + tmp81*(tmp255*tmp273 + tmp294) + tmp81*(tmp256*tmp286 + tmp293) - tmp82*(tmp186 + tmp191*tmp76 + tmp195) - tmp82*(tmp115*tmp76 + 4*tmp16*tmp85 - 3.0/2.0*tmp172*tmp185 + tmp180*tmp181 + tmp184) - tmp93*(hDD22*(tmp149*((tmp84)*(tmp84)) - 2*tmp16) + 4*hDD_dD221*tmp109 + hDD_dDD2211*tmp16 + tmp10*tmp200 - tmp112*tmp185 - tmp185*tmp197 + tmp212 + tmp214) + tmp98*(2*tmp245 + tmp247) + tmp98*(2*tmp253 + tmp254) + tmp98*(tmp255*tmp263 + tmp267) + tmp98*(tmp256*tmp273 + tmp292) - tmp99*(tmp107*tmp170 + tmp149*tmp169 + tmp174) - tmp99*(-3*tmp173 + tmp177 + tmp178*tmp76 + tmp179)) - 16*tmp69*(-tmp104*(-tmp146 - tmp147 - tmp148) + tmp96*(cf_dD1*tmp103 - cf_dDD01) - tmp97*(-tmp138 - tmp140 - tmp145)) + tmp69*(tmp127*(tmp233 + tmp535) + tmp127*(tmp282 + tmp525) + tmp127*(tmp509 + tmp521) + tmp555 + tmp69*(2*tmp333 + tmp542) + tmp69*(tmp352 + tmp543) + tmp69*(tmp417 + 2*tmp541) + tmp69*(tmp263*tmp283 + tmp544) + tmp69*(tmp364 + tmp365 + tmp546) + tmp69*(tmp284*tmp353 + tmp365 + tmp545) + tmp71*(tmp408 + tmp536) + tmp71*(2*tmp416 + tmp419) + tmp71*(tmp392 + tmp393 + tmp537) + tmp74*(2*tmp331 + tmp538) + tmp74*(tmp349 + tmp539) + tmp74*(tmp361 + tmp362 + tmp363) + tmp81*(tmp396 + 2*tmp498) + tmp81*(tmp405 + tmp547) + tmp81*(tmp495 + tmp549) + tmp81*(tmp497 + tmp520) + tmp81*(tmp502 + tmp519) + tmp81*(tmp387 + tmp500 + tmp548) - tmp82*(tmp527 + tmp553) + tmp98*(2*tmp324 + tmp540) + tmp98*(tmp340 + tmp551) + tmp98*(tmp360 + tmp523) + tmp98*(tmp490 + tmp522) + tmp98*(tmp524 + tmp550) + tmp98*(tmp342 + tmp343 + tmp440)) + tmp69*(tmp127*(tmp235 + tmp535) + tmp127*(tmp265 + tmp534) + tmp127*(tmp453 + tmp530) + tmp555 + tmp69*(tmp352 + tmp544) + tmp69*(tmp364 + 2*tmp546) + tmp69*(2*tmp365 + tmp545) + tmp69*(tmp260*tmp286 + tmp543) + tmp69*(tmp333 + tmp417 + tmp541) + tmp69*(tmp262*tmp356 + tmp333 + tmp542) + tmp71*(2*tmp393 + tmp537) + tmp71*(tmp411 + tmp536) + tmp71*(tmp416 + tmp418 + tmp419) + tmp74*(tmp350 + tmp539) + tmp74*(tmp362 + 2*tmp363) + tmp74*(tmp331 + tmp332 + tmp538) + tmp81*(2*tmp387 + tmp548) + tmp81*(tmp402 + tmp549) + tmp81*(tmp413 + tmp532) + tmp81*(tmp426 + tmp531) + tmp81*(tmp533 + tmp547) + tmp81*(tmp396 + tmp397 + tmp498) - tmp82*(tmp463 + tmp553) + tmp98*(tmp343 + 2*tmp440) + tmp98*(tmp347 + tmp550) + tmp98*(tmp433 + tmp551) + tmp98*(tmp442 + tmp529) + tmp98*(tmp445 + tmp528) + tmp98*(tmp324 + tmp448 + tmp540)) - tmp70*tmp71*tmp72 - 8*tmp71*(-tmp104*(-tmp158 - tmp159 - tmp160) + tmp96*(-cf_dDD11 + tmp70*tmp95) - tmp97*(-tmp153 - tmp155 - tmp157)) + tmp71*(-tmp101*(tmp0*tmp299 + tmp374 + tmp377) - tmp101*(hDD_dD111*tmp34 + tmp311*tmp34 + tmp366 + tmp374 - 3*tmp376) - tmp119*(4*hDD11 + hDD_dD110*tmp34 + hDD_dDD1100*tmp0 - 2*tmp379) + tmp127*(tmp236 + 2*tmp395) + tmp127*(tmp290 + 2*tmp394) + tmp15*tmp368 - tmp204*(tmp10*tmp378 + tmp382 + tmp383) + tmp223*tmp387 + tmp223*tmp391 + tmp225*tmp365 + tmp232*tmp386 + tmp232*tmp390 + tmp234*tmp392 + tmp234*tmp393 + tmp237*tmp284*tmp389 + tmp242*tmp288 + tmp296*(tmp181*tmp228 + tmp227*tmp366 + 2*tmp280) + tmp297*(tmp181*tmp283 + tmp285*tmp366 + 2*tmp388) + tmp298*(tmp181*tmp270 + tmp272*tmp366 + 2*tmp358) + tmp367*tmp46 + tmp371*tmp6 + tmp69*(2*tmp410 + tmp411) + tmp69*(tmp418 + 2*tmp419) + tmp69*(tmp268*tmp401 + tmp408) + tmp69*(tmp353*tmp398 + tmp416) + tmp71*(tmp281*tmp401 + tmp283*tmp286) + tmp71*(tmp285*tmp356 + tmp359*tmp398) + tmp74*(tmp333 + 2*tmp417) + tmp74*(tmp352 + 2*tmp409) + tmp81*(2*tmp406 + tmp407) + tmp81*(tmp414 + 2*tmp415) + tmp81*(tmp251*tmp401 + tmp400) + tmp81*(tmp268*tmp398 + tmp399) - tmp82*(-tmp165*tmp195 + tmp381) - tmp82*(-tmp165*tmp184 + tmp190*tmp34 + tmp381 + tmp384 + tmp385) - tmp93*(hDD_dDD1111*tmp0 + tmp0*tmp304 + tmp307*tmp34 + tmp378) + tmp98*(2*tmp396 + tmp397) + tmp98*(tmp402 + 2*tmp403) + tmp98*(2*tmp404 + tmp405) + tmp98*(2*tmp412 + tmp413) - tmp99*(tmp372 - tmp373) - tmp99*(-tmp165*tmp179 + 3*tmp372)) - tmp72*tmp73*tmp74 - 8*tmp74*(-tmp104*(-tmp135 - tmp136 - tmp137) + tmp96*(-cf_dDD00 + tmp73*tmp95) - tmp97*(-tmp131 - tmp132 - tmp134)) + tmp74*(hDD01*lambdaU_dD10 + hDD02*lambdaU_dD20 - hDD_dDD0000*tmp119 + lambdaU_dD00*tmp4 - tmp101*(-tmp299 + tmp301) - tmp101*(tmp163*tmp9 + tmp301 - 2*tmp312) + tmp127*(tmp224 + 2*tmp335) + tmp127*(tmp275 + 2*tmp334) - tmp204*(tmp161*tmp300 + tmp319) + tmp223*tmp323 + tmp223*tmp327 + tmp225*tmp262*tmp326 + tmp232*tmp324 + tmp232*tmp330 + tmp234*tmp331 + tmp234*tmp332 + tmp237*tmp333 + tmp242*tmp259 + tmp296*(tmp217*tmp366 + tmp219*tmp295 + 2*tmp257) + tmp297*(tmp270*tmp295 + tmp271*tmp366 + 2*tmp328) + tmp298*(tmp260*tmp295 + tmp261*tmp366 + 2*tmp325) + tmp69*(2*tmp348 + tmp349) + tmp69*(tmp361 + 2*tmp362) + tmp69*(tmp277*tmp339 + tmp350) + tmp69*(tmp337*tmp356 + tmp363) + tmp71*(2*tmp351 + tmp352) + tmp71*(2*tmp364 + tmp365) + tmp74*(tmp258*tmp339 + tmp260*tmp263) + tmp74*(tmp261*tmp353 + tmp329*tmp337) + tmp81*(tmp340 + 2*tmp341) + tmp81*(tmp342 + 2*tmp343) + tmp81*(2*tmp346 + tmp347) + tmp81*(2*tmp357 + tmp360) - tmp82*(tmp314 + tmp316) - tmp82*(tmp314 - 2*tmp320 + tmp322) - tmp93*(hDD_dDD0011 - tmp304 + tmp309) + tmp98*(2*tmp344 + tmp345) + tmp98*(tmp354 + 2*tmp355) + tmp98*(tmp246*tmp339 + tmp338) + tmp98*(tmp277*tmp337 + tmp336) - tmp99*(4*tmp302 - 2*tmp303) - tmp99*(tmp128*tmp163 - 2*tmp129)) - 16*tmp81*(-tmp104*(-tmp118 - tmp120) - tmp97*(-tmp114 - tmp117)) + tmp81*(tmp127*(2*tmp244 + tmp485) + tmp127*(tmp249 + tmp486) + tmp127*(tmp250 + tmp252 + tmp293) + tmp518 + tmp69*(tmp404 + 2*tmp495) + tmp69*(tmp423 + tmp493) + tmp69*(tmp425 + tmp502) + tmp69*(tmp428 + tmp497) + tmp69*(tmp498 + tmp499) + tmp69*(tmp391 + tmp500 + tmp501) + tmp71*(tmp399 + tmp487) + tmp71*(2*tmp400 + tmp406) + tmp71*(tmp386 + tmp390 + tmp488) + tmp74*(tmp360 + tmp447) + tmp74*(tmp436 + tmp489) + tmp74*(tmp444 + tmp490) + tmp81*(2*tmp236 + tmp492) + tmp81*(tmp290 + tmp503) + tmp81*(tmp395 + 2*tmp496) + tmp81*(tmp246*tmp285 + tmp504) + tmp81*(tmp288 + tmp289 + tmp505) + tmp81*(tmp251*tmp284 + tmp288 + tmp506) - tmp82*(tmp212 + tmp512) - tmp93*(tmp385 + tmp510) + tmp98*(2*tmp233 + tmp491) + tmp98*(tmp265 + tmp507) + tmp98*(tmp282 + tmp455) + tmp98*(tmp439 + tmp494) + tmp98*(tmp452 + tmp509) + tmp98*(tmp269 + tmp274 + tmp508)) + tmp81*(tmp127*(tmp250 + 2*tmp293) + tmp127*(tmp294 + tmp486) + tmp127*(tmp231 + tmp244 + tmp485) + tmp518 + tmp69*(2*tmp391 + tmp501) + tmp69*(tmp413 + tmp499) + tmp69*(tmp424 + tmp532) + tmp69*(tmp427 + tmp531) + tmp69*(tmp402 + tmp493 + tmp533) + tmp69*(tmp404 + tmp405 + tmp495) + tmp71*(2*tmp390 + tmp488) + tmp71*(tmp414 + tmp487) + tmp71*(tmp400 + tmp406 + tmp407) + tmp74*(tmp443 + tmp529) + tmp74*(tmp446 + tmp528) + tmp74*(tmp340 + tmp347 + tmp489) + tmp81*(2*tmp288 + tmp506) + tmp81*(tmp289 + 2*tmp505) + tmp81*(tmp290 + tmp504) + tmp81*(tmp240*tmp356 + tmp503) + tmp81*(tmp236 + tmp395 + tmp496) + tmp81*(tmp215*tmp286 + tmp236 + tmp492) - tmp82*(tmp214 + tmp512) - tmp93*(tmp384 + tmp510) + tmp98*(tmp274 + 2*tmp508) + tmp98*(tmp451 + tmp534) + tmp98*(tmp454 + tmp530) + tmp98*(tmp456 + tmp507) + tmp98*(tmp233 + tmp491 + tmp526) + tmp98*(tmp235 + tmp438 + tmp494)) - 16*tmp98*(-tmp104*(-tmp100 - tmp102) - tmp97*(-tmp83 - tmp94)) + tmp98*(tmp127*(2*tmp243 + tmp420) + tmp127*(tmp254 + tmp421) + tmp127*(tmp245 + tmp247 + tmp267) + tmp484 + tmp69*(tmp346 + 2*tmp433) + tmp69*(tmp435 + tmp436) + tmp69*(tmp440 + tmp441) + tmp69*(tmp442 + tmp444) + tmp69*(tmp445 + tmp447) + tmp69*(tmp330 + tmp448 + tmp449) + tmp71*(tmp413 + tmp425) + tmp71*(tmp422 + tmp423) + tmp71*(tmp426 + tmp428) + tmp74*(tmp336 + tmp429) + tmp74*(2*tmp338 + tmp344) + tmp74*(tmp323 + tmp327 + tmp430) + tmp81*(2*tmp235 + tmp431) + tmp81*(tmp265 + tmp452) + tmp81*(tmp282 + tmp450) + tmp81*(tmp437 + tmp439) + tmp81*(tmp453 + tmp455) + tmp81*(tmp278 + tmp279 + tmp456) - tmp93*(tmp463 + tmp469) + tmp98*(2*tmp224 + tmp432) + tmp98*(tmp275 + tmp458) + tmp98*(tmp335 + 2*tmp434) + tmp98*(tmp251*tmp261 + tmp457) + tmp98*(tmp259 + tmp264 + tmp459) + tmp98*(tmp246*tmp262 + tmp259 + tmp460)) + tmp98*(tmp127*(tmp245 + 2*tmp267) + tmp127*(tmp292 + tmp421) + tmp127*(tmp222 + tmp243 + tmp420) + tmp484 + tmp69*(2*tmp330 + tmp449) + tmp69*(tmp360 + tmp441) + tmp69*(tmp443 + tmp522) + tmp69*(tmp446 + tmp523) + tmp69*(tmp340 + tmp435 + tmp524) + tmp69*(tmp346 + tmp347 + tmp433) + tmp71*(tmp424 + tmp519) + tmp71*(tmp427 + tmp520) + tmp71*(tmp402 + tmp405 + tmp422) + tmp74*(2*tmp327 + tmp430) + tmp74*(tmp354 + tmp429) + tmp74*(tmp338 + tmp344 + tmp345) + tmp81*(tmp279 + 2*tmp456) + tmp81*(tmp450 + tmp508) + tmp81*(tmp451 + tmp521) + tmp81*(tmp454 + tmp525) + tmp81*(tmp233 + tmp437 + tmp438) + tmp81*(tmp235 + tmp431 + tmp526) - tmp93*(tmp469 + tmp527) + tmp98*(2*tmp259 + tmp460) + tmp98*(tmp264 + 2*tmp459) + tmp98*(tmp275 + tmp457) + tmp98*(tmp239*tmp353 + tmp458) + tmp98*(tmp224 + tmp335 + tmp434) + tmp98*(tmp215*tmp263 + tmp224 + tmp432))) + (2.0/3.0)*((trK)*(trK));}} // END LOOP: for(int i0=NGHOSTS; i0<NGHOSTS+Nxx0; i0++)} // END LOOP: for(int i1=NGHOSTS; i1<NGHOSTS+Nxx1; i1++)} // END LOOP: for(int i2=NGHOSTS; i2<NGHOSTS+Nxx2; i2++)}
// Step P0: Define REAL and NGHOSTS. This header is generated by NRPy+.#include "Initial_Data_Playground_REAL__NGHOSTS.h"#include "declare_Cparameters_struct.h"// Step P1: Import needed header files#include "stdio.h"#include "stdlib.h"#include "math.h"#ifndef M_PI#define M_PI 3.141592653589793238462643383279502884L#endif#ifndef M_SQRT1_2#define M_SQRT1_2 0.707106781186547524400844362104849039L#endif// Step P2: Declare the IDX4S(gf,i,j,k) macro, which enables us to store 4-dimensions of// data in a 1D array. In this case, consecutive values of "i"// (all other indices held to a fixed value) are consecutive in memory, where// consecutive values of "j" (fixing all other indices) are separated by// Nxx_plus_2NGHOSTS0 elements in memory. Similarly, consecutive values of// "k" are separated by Nxx_plus_2NGHOSTS0*Nxx_plus_2NGHOSTS1 in memory, etc.#define IDX4S(g,i,j,k) ( (i) + Nxx_plus_2NGHOSTS0 * ( (j) + Nxx_plus_2NGHOSTS1 * ( (k) + Nxx_plus_2NGHOSTS2 * (g) ) ) )#define IDX4ptS(g,idx) ( (idx) + (Nxx_plus_2NGHOSTS0*Nxx_plus_2NGHOSTS1*Nxx_plus_2NGHOSTS2) * (g) )#define IDX3S(i,j,k) ( (i) + Nxx_plus_2NGHOSTS0 * ( (j) + Nxx_plus_2NGHOSTS1 * ( (k) ) ) )#define LOOP_REGION(i0min,i0max, i1min,i1max, i2min,i2max) for(int i2=i2min;i2<i2max;i2++) for(int i1=i1min;i1<i1max;i1++) for(int i0=i0min;i0<i0max;i0++)#define LOOP_ALL_GFS_GPS(ii) _Pragma("omp parallel for") for(int (ii)=0;(ii)<Nxx_plus_2NGHOSTS_tot*NUM_EVOL_GFS;(ii)++)// Step P3: Set UUGF and VVGF macros, as well as xxCart()#include "boundary_conditions/gridfunction_defines.h"// Step P4: Set xxCart(const paramstruct *restrict params,// REAL *restrict xx[3],// const int i0,const int i1,const int i2,// REAL xCart[3]),// which maps xx->Cartesian via// {xx[0][i0],xx[1][i1],xx[2][i2]}->{xCart[0],xCart[1],xCart[2]}#include "xxCart.h"// Step P5: Defines set_Nxx_dxx_invdx_params__and__xx(const int EigenCoord, const int Nxx[3],// paramstruct *restrict params, REAL *restrict xx[3]),// which sets params Nxx,Nxx_plus_2NGHOSTS,dxx,invdx, and xx[] for// the chosen Eigen-CoordSystem if EigenCoord==1, or// CoordSystem if EigenCoord==0.#include "set_Nxx_dxx_invdx_params__and__xx.h"// Step P6: Include basic functions needed to impose curvilinear// parity and boundary conditions.#include "boundary_conditions/CurviBC_include_Cfunctions.h"// Step P8: Include function for enforcing detgammabar constraint.#include "enforce_detgammabar_constraint.h"// Step P10: Declare function necessary for setting up the initial data.// Step P10.a: Define BSSN_ID() for BrillLindquist initial data// Step P10.b: Set the generic driver function for setting up BSSN initial data#include "initial_data.h"// Step P11: Declare function for evaluating Hamiltonian constraint (diagnostic)#include "Hamiltonian_constraint.h"#include "momentum_constraint.h"// main() function:// Step 0: Read command-line input, set up grid structure, allocate memory for gridfunctions, set up coordinates// Step 1: Set up initial data to an exact solution// Step 2: Start the timer, for keeping track of how fast the simulation is progressing.// Step 3: Integrate the initial data forward in time using the chosen RK-like Method of// Lines timestepping algorithm, and output periodic simulation diagnostics// Step 3.a: Output 2D data file periodically, for visualization// Step 3.b: Step forward one timestep (t -> t+dt) in time using// chosen RK-like MoL timestepping algorithm// Step 3.c: If t=t_final, output conformal factor & Hamiltonian// constraint violation to 2D data file// Step 3.d: Progress indicator printing to stderr// Step 4: Free all allocated memoryint main(int argc, const char *argv[]) {paramstruct params;#include "set_Cparameters_default.h"// Step 0a: Read command-line input, error out if nonconformantif((argc != 4) || atoi(argv[1]) < NGHOSTS || atoi(argv[2]) < NGHOSTS || atoi(argv[3]) < 2 /* FIXME; allow for axisymmetric sims */) {fprintf(stderr,"Error: Expected three command-line arguments: ./BrillLindquist_Playground Nx0 Nx1 Nx2,");fprintf(stderr,"where Nx[0,1,2] is the number of grid points in the 0, 1, and 2 directions.");fprintf(stderr,"Nx[] MUST BE larger than NGHOSTS (= %d)",NGHOSTS);exit(1);}// Step 0b: Set up numerical grid structure, first in space...const int Nxx[3] = { atoi(argv[1]), atoi(argv[2]), atoi(argv[3]) };if(Nxx[0]%2 != 0 || Nxx[1]%2 != 0 || Nxx[2]%2 != 0) {fprintf(stderr,"Error: Cannot guarantee a proper cell-centered grid if number of grid cells not set to even number.");fprintf(stderr," For example, in case of angular directions, proper symmetry zones will not exist.");exit(1);}// Step 0c: Set free parameters, overwriting Cparameters defaults// by hand or with command-line input, as desired.#include "free_parameters.h"// Step 0d: Uniform coordinate grids are stored to *xx[3]REAL *xx[3];// Step 0d.i: Set bcstructbc_struct bcstruct;{int EigenCoord = 1;// Step 0d.ii: Call set_Nxx_dxx_invdx_params__and__xx(), which sets// params Nxx,Nxx_plus_2NGHOSTS,dxx,invdx, and xx[] for the// chosen Eigen-CoordSystem.set_Nxx_dxx_invdx_params__and__xx(EigenCoord, Nxx, ¶ms, xx);// Step 0d.iii: Set Nxx_plus_2NGHOSTS_tot#include "set_Cparameters-nopointer.h"const int Nxx_plus_2NGHOSTS_tot = Nxx_plus_2NGHOSTS0*Nxx_plus_2NGHOSTS1*Nxx_plus_2NGHOSTS2;// Step 0e: Find ghostzone mappings; set up bcstruct#include "boundary_conditions/driver_bcstruct.h"// Step 0e.i: Free allocated space for xx[][] arrayfor(int i=0;i<3;i++) free(xx[i]);}// Step 0f: Call set_Nxx_dxx_invdx_params__and__xx(), which sets// params Nxx,Nxx_plus_2NGHOSTS,dxx,invdx, and xx[] for the// chosen (non-Eigen) CoordSystem.int EigenCoord = 0;set_Nxx_dxx_invdx_params__and__xx(EigenCoord, Nxx, ¶ms, xx);// Step 0g: Set all C parameters "blah" for params.blah, including// Nxx_plus_2NGHOSTS0 = params.Nxx_plus_2NGHOSTS0, etc.#include "set_Cparameters-nopointer.h"const int Nxx_plus_2NGHOSTS_tot = Nxx_plus_2NGHOSTS0*Nxx_plus_2NGHOSTS1*Nxx_plus_2NGHOSTS2;// Step 0j: Error out if the number of auxiliary gridfunctions outnumber evolved gridfunctions.// This is a limitation of the RK method. You are always welcome to declare & allocate// additional gridfunctions by hand.if(NUM_AUX_GFS > NUM_EVOL_GFS) {fprintf(stderr,"Error: NUM_AUX_GFS > NUM_EVOL_GFS. Either reduce the number of auxiliary gridfunctions,");fprintf(stderr," or allocate (malloc) by hand storage for *diagnostic_output_gfs.");exit(1);}// Step 0k: Allocate memory for gridfunctions#include "MoLtimestepping/RK_Allocate_Memory.h"REAL *restrict auxevol_gfs = (REAL *)malloc(sizeof(REAL) * NUM_AUXEVOL_GFS * Nxx_plus_2NGHOSTS_tot);// Step 1: Set up initial data to an exact solutioninitial_data(¶ms, xx, y_n_gfs);// Step 1b: Apply boundary conditions, as initial data// are sometimes ill-defined in ghost zones.// E.g., spherical initial data might not be// properly defined at points where r=-1.apply_bcs_curvilinear(¶ms, &bcstruct, NUM_EVOL_GFS,evol_gf_parity, y_n_gfs);enforce_detgammabar_constraint(¶ms, xx, y_n_gfs);// Evaluate Hamiltonian & momentum constraint violationsHamiltonian_constraint(¶ms, xx, y_n_gfs, diagnostic_output_gfs);momentum_constraint( ¶ms, xx, y_n_gfs, diagnostic_output_gfs);/* Step 2: 2D output: Output conformal factor (CFGF) and constraint violations (HGF, MU0GF, MU1GF, MU2GF). */const int i0MIN=NGHOSTS; // In spherical, r=Delta r/2.const int i1mid=Nxx_plus_2NGHOSTS1/2;const int i2mid=Nxx_plus_2NGHOSTS2/2;LOOP_REGION(NGHOSTS,Nxx_plus_2NGHOSTS0-NGHOSTS, i1mid,i1mid+1, NGHOSTS,Nxx_plus_2NGHOSTS2-NGHOSTS) {REAL xCart[3];xxCart(¶ms, xx, i0,i1,i2, xCart);int idx = IDX3S(i0,i1,i2);printf("%e %e %e %e %e %e %e",xCart[0],xCart[1], y_n_gfs[IDX4ptS(CFGF,idx)],log10(fabs(diagnostic_output_gfs[IDX4ptS(HGF,idx)])),log10(fabs(diagnostic_output_gfs[IDX4ptS(MU0GF,idx)])+1e-200),log10(fabs(diagnostic_output_gfs[IDX4ptS(MU1GF,idx)])+1e-200),log10(fabs(diagnostic_output_gfs[IDX4ptS(MU2GF,idx)])+1e-200));}// Step 4: Free all allocated memory#include "boundary_conditions/bcstruct_freemem.h"#include "MoLtimestepping/RK_Free_Memory.h"free(auxevol_gfs);for(int i=0;i<3;i++) free(xx[i]);return 0;}
// Part P0.a: Set the number of ghost cells, from NRPy+'s FD_CENTDERIVS_ORDER#define NGHOSTS 3// Part P0.b: Set the numerical precision (REAL) to double, ensuring all floating point// numbers are stored to at least ~16 significant digits#define REAL double
// Code snippet allocating gridfunction memory for "Euler" method:REAL *restrict y_n_gfs = (REAL *)malloc(sizeof(REAL) * NUM_EVOL_GFS * Nxx_plus_2NGHOSTS_tot);REAL *restrict y_nplus1_running_total_gfs = (REAL *)malloc(sizeof(REAL) * NUM_EVOL_GFS * Nxx_plus_2NGHOSTS_tot);REAL *restrict diagnostic_output_gfs = y_nplus1_running_total_gfs;
// Code snippet freeing gridfunction memory for "Euler" method:free(y_n_gfs);free(y_nplus1_running_total_gfs);
// C code implementation of Euler Method of Lines timestepping.// ***Euler timestepping only requires one RHS evaluation***LOOP_ALL_GFS_GPS(i) {y_n_gfs[i] = y_n_gfs[i] + y_nplus1_running_total_gfs[i]*dt;}
typedef struct __ghostzone_map__ {short i0,i1,i2; // i0,i1,i2 stores values from -1 (used to indicate outer boundary)// to Nxx_plus_2NGHOSTS*. We assume that grid extents beyond the// limits of short (i.e., beyond about 32,000) are unlikely. This// can be easily extended if needed, though.} gz_map;const int8_t MAXFACE = -1;const int8_t NUL = +0;const int8_t MINFACE = +1;typedef struct __parity__ {int8_t parity[10]; // We store the 10 parity conditions in 10 int8_t integers,// one for each condition. Note that these conditions can// only take one of two values: +1 or -1, hence the use of// int8_t, the smallest C data type.} parity_condition;typedef struct __inner_bc__ {gz_map inner_bc_dest_pt;gz_map inner_bc_src_pt;int8_t parity[10]; // We store the 10 parity conditions in 10 int8_t integers,// one for each condition. Note that these conditions can// only take one of two values: +1 or -1, hence the use of// int8_t, the smallest C data type.} inner_bc;typedef struct __outer_bc__ {gz_map outer_bc_dest_pt;int8_t FACEi0,FACEi1,FACEi2; // FACEi* takes values of -1, 0, and +1 only,// corresponding to MAXFACE, NUL, and MINFACE// respectively.// Thus int8_t (one byte each, the smallest C// type) is sufficient.} outer_bc;typedef struct __bcstruct__ {outer_bc **outer; // Array of 1D arrays, of length// [NGHOSTS][num_ob_gz_pts[which_outer_ghostzone_point]]inner_bc **inner; // Array of 1D arrays, of length// [NGHOSTS][num_ib_gz_pts[which_inner_ghostzone_point]]// Arrays storing number of outer/inner boundary ghostzone points at each ghostzone,// of length NGHOSTS:int *num_ob_gz_pts;int *num_ib_gz_pts;} bc_struct;
#include "BCs_data_structs.h"#include "EigenCoord_xxCart.h"#include "set_up__bc_gz_map_and_parity_condns.h"#include "set_bcstruct.h"#include "apply_bcs_curvilinear.h"
/** Original SymPy expressions:* "[Cart_to_xx0_inbounds = sqrt(Cartx**2 + Carty**2 + Cartz**2),* Cart_to_xx1_inbounds = acos(Cartz/sqrt(Cartx**2 + Carty**2 + Cartz**2)),* Cart_to_xx2_inbounds = atan2(Carty, Cartx)]"*/{const double tmp0 = sqrt(((Cartx)*(Cartx)) + ((Carty)*(Carty)) + ((Cartz)*(Cartz)));Cart_to_xx0_inbounds = tmp0;Cart_to_xx1_inbounds = acos(Cartz/tmp0);Cart_to_xx2_inbounds = atan2(Carty, Cartx);}
inline void EigenCoord_xxCart(const paramstruct *restrict params, REAL *restrict xx[3],const int i0,const int i1,const int i2, REAL xCart[3]) {#include "../set_Cparameters.h"REAL xx0 = xx[0][i0];REAL xx1 = xx[1][i1];REAL xx2 = xx[2][i2];/** Original SymPy expressions:* "[xCart[0] = xx0*sin(xx1)*cos(xx2),* xCart[1] = xx0*sin(xx1)*sin(xx2),* xCart[2] = xx0*cos(xx1)]"*/{const double tmp0 = xx0*sin(xx1);xCart[0] = tmp0*cos(xx2);xCart[1] = tmp0*sin(xx2);xCart[2] = xx0*cos(xx1);}}
#include "..//set_Cparameters.h"
// Declare boundary condition BC_UPDATE_OUTER macro,// which updates a single outer boundary face// of the 3D grid cube using quadratic polynomial// extrapolation.#define BC_UPDATE_OUTER(which_gf, i0,i1,i2, FACEX0,FACEX1,FACEX2) { \const int idx3 = IDX3S(i0,i1,i2); \gfs[IDX4S(which_gf,i0,i1,i2)] = \+3.0*gfs[IDX4S(which_gf,i0+1*FACEX0,i1+1*FACEX1,i2+1*FACEX2)] \-3.0*gfs[IDX4S(which_gf,i0+2*FACEX0,i1+2*FACEX1,i2+2*FACEX2)] \+1.0*gfs[IDX4S(which_gf,i0+3*FACEX0,i1+3*FACEX1,i2+3*FACEX2)]; \}// Curvilinear boundary condition driver routine: Apply BCs to all six// boundary faces of the 3D numerical domain, filling in the// innermost ghost zone layer first, and moving outward.void apply_bcs_curvilinear(const paramstruct *restrict params, const bc_struct *restrict bcstruct,const int NUM_GFS, const int8_t *restrict gfs_parity, REAL *restrict gfs) {#pragma omp parallel forfor(int which_gf=0;which_gf<NUM_GFS;which_gf++) {#include "RELATIVE_PATH__set_Cparameters.h" /* Header file containing correct #include for set_Cparameters.h;* accounting for the relative path */for(int which_gz = 0; which_gz < NGHOSTS; which_gz++) {// First apply OUTER boundary conditions,// in case an INNER (parity) boundary point// needs data at the outer boundary:// After updating each face, adjust imin[] and imax[]// to reflect the newly-updated face extents.for(int pt=0;pt<bcstruct->num_ob_gz_pts[which_gz];pt++) {BC_UPDATE_OUTER(which_gf,bcstruct->outer[which_gz][pt].outer_bc_dest_pt.i0,bcstruct->outer[which_gz][pt].outer_bc_dest_pt.i1,bcstruct->outer[which_gz][pt].outer_bc_dest_pt.i2,bcstruct->outer[which_gz][pt].FACEi0,bcstruct->outer[which_gz][pt].FACEi1,bcstruct->outer[which_gz][pt].FACEi2);}// Then apply INNER (parity) boundary conditions:for(int pt=0;pt<bcstruct->num_ib_gz_pts[which_gz];pt++) {const int i0dest = bcstruct->inner[which_gz][pt].inner_bc_dest_pt.i0;const int i1dest = bcstruct->inner[which_gz][pt].inner_bc_dest_pt.i1;const int i2dest = bcstruct->inner[which_gz][pt].inner_bc_dest_pt.i2;const int i0src = bcstruct->inner[which_gz][pt].inner_bc_src_pt.i0;const int i1src = bcstruct->inner[which_gz][pt].inner_bc_src_pt.i1;const int i2src = bcstruct->inner[which_gz][pt].inner_bc_src_pt.i2;const int8_t *prty= bcstruct->inner[which_gz][pt].parity;// printf("%d\n",bcstruct->inner_bc_parity[which_gz][pt].parity[gfs_parity[which_gf]]);gfs[IDX4S(which_gf,i0dest,i1dest,i2dest)] =bcstruct->inner[which_gz][pt].parity[gfs_parity[which_gf]] * gfs[IDX4S(which_gf, i0src,i1src,i2src)];} // END for(int pt=0;pt<num_ib_gz_pts[which_gz];pt++)} // END for(int which_gz = 0; which_gz < NGHOSTS; which_gz++)} // END for(int which_gf=0;which_gf<NUM_GFS;which_gf++)} // END function
for(int i=0;i<NGHOSTS;i++) { free(bcstruct.outer[i]); free(bcstruct.inner[i]); }free(bcstruct.num_ob_gz_pts); free(bcstruct.num_ib_gz_pts);
// Step 1: Allocate memory storage for bc_gz_map, which// in the case a boundary point is a *parity*// boundary, is set to the interior, non-// boundary point corresponding to the same// Cartesian gridpoint. Otherwise bc_gz_map// is set to (i0,i1,i2) = (-1,-1,-1).gz_map *bc_gz_map = (gz_map *)malloc(sizeof(gz_map)*Nxx_plus_2NGHOSTS_tot);// Step 2: Allocate memory storage for bc_parity_conditions,// which store parity conditions for all 10// gridfunction types at all grid points.parity_condition *bc_parity_conditions = (parity_condition *)malloc(sizeof(parity_condition)*Nxx_plus_2NGHOSTS_tot);// Step 3: Set bc_gz_map and bc_parity_conditions at *all*// points; on the boundary and otherwise.set_up__bc_gz_map_and_parity_condns(¶ms, xx, bc_gz_map,bc_parity_conditions);// Step 4: Declare and allocate memory for bcstruct,// which will store all information needed for// applying the boundary conditions.bcstruct.outer = (outer_bc **)malloc(sizeof(outer_bc *)*NGHOSTS);bcstruct.inner = (inner_bc **)malloc(sizeof(inner_bc *)*NGHOSTS);bcstruct.num_ob_gz_pts = ( int *)malloc(sizeof(int)*NGHOSTS);bcstruct.num_ib_gz_pts = ( int *)malloc(sizeof(int)*NGHOSTS);// Step 4: Store all information needed to quickly and// efficiently apply boundary conditions. This// function transfers all information from// bc_gz_map (defined at *all gridpoints*) into// bcstruct (defined only at boundary points).// Thus when this function has finished,// bc_gz_map is no longer needed.set_bcstruct(¶ms,bc_gz_map,bc_parity_conditions,&bcstruct);// Step 5: As described in Step 4, bc_gz_map is no// longer needed at this point, so we free its// memory. Farewell, friend!free(bc_gz_map);free(bc_parity_conditions);
/* This file is automatically generated by NRPy+. Do not edit. *//* EVOLVED VARIABLES: */#define NUM_EVOL_GFS 24#define ADD00GF 0#define ADD01GF 1#define ADD02GF 2#define ADD11GF 3#define ADD12GF 4#define ADD22GF 5#define ALPHAGF 6#define BETU0GF 7#define BETU1GF 8#define BETU2GF 9#define CFGF 10#define HDD00GF 11#define HDD01GF 12#define HDD02GF 13#define HDD11GF 14#define HDD12GF 15#define HDD22GF 16#define LAMBDAU0GF 17#define LAMBDAU1GF 18#define LAMBDAU2GF 19#define TRKGF 20#define VETU0GF 21#define VETU1GF 22#define VETU2GF 23/* AUXILIARY VARIABLES: */#define NUM_AUX_GFS 4#define HGF 0#define MU0GF 1#define MU1GF 2#define MU2GF 3/* AUXEVOL VARIABLES: */#define NUM_AUXEVOL_GFS 0/* PARITY TYPES FOR ALL GRIDFUNCTIONS.SEE "Tutorial-Start_to_Finish-Curvilinear_BCs.ipynb" FOR DEFINITIONS. */const int8_t evol_gf_parity[24] = { 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 0, 4, 5, 6, 7, 8, 9, 1, 2, 3, 0, 1, 2, 3 };const int8_t aux_gf_parity[4] = { 0, 1, 2, 3 };
/** Original SymPy expressions:* "[parity[0] = 1,* parity[1] = sin(xx1)*sin(xx1_inbounds)*sin(xx2)*sin(xx2_inbounds) + sin(xx1)*sin(xx1_inbounds)*cos(xx2)*cos(xx2_inbounds) + cos(xx1)*cos(xx1_inbounds),* parity[2] = sin(xx1)*sin(xx1_inbounds) + sin(xx2)*sin(xx2_inbounds)*cos(xx1)*cos(xx1_inbounds) + cos(xx1)*cos(xx1_inbounds)*cos(xx2)*cos(xx2_inbounds),* parity[3] = sin(xx2)*sin(xx2_inbounds) + cos(xx2)*cos(xx2_inbounds),* parity[4] = (sin(xx1)*sin(xx1_inbounds)*sin(xx2)*sin(xx2_inbounds) + sin(xx1)*sin(xx1_inbounds)*cos(xx2)*cos(xx2_inbounds) + cos(xx1)*cos(xx1_inbounds))**2,* parity[5] = (sin(xx1)*sin(xx1_inbounds) + sin(xx2)*sin(xx2_inbounds)*cos(xx1)*cos(xx1_inbounds) + cos(xx1)*cos(xx1_inbounds)*cos(xx2)*cos(xx2_inbounds))*(sin(xx1)*sin(xx1_inbounds)*sin(xx2)*sin(xx2_inbounds) + sin(xx1)*sin(xx1_inbounds)*cos(xx2)*cos(xx2_inbounds) + cos(xx1)*cos(xx1_inbounds)),* parity[6] = (sin(xx2)*sin(xx2_inbounds) + cos(xx2)*cos(xx2_inbounds))*(sin(xx1)*sin(xx1_inbounds)*sin(xx2)*sin(xx2_inbounds) + sin(xx1)*sin(xx1_inbounds)*cos(xx2)*cos(xx2_inbounds) + cos(xx1)*cos(xx1_inbounds)),* parity[7] = (sin(xx1)*sin(xx1_inbounds) + sin(xx2)*sin(xx2_inbounds)*cos(xx1)*cos(xx1_inbounds) + cos(xx1)*cos(xx1_inbounds)*cos(xx2)*cos(xx2_inbounds))**2,* parity[8] = (sin(xx2)*sin(xx2_inbounds) + cos(xx2)*cos(xx2_inbounds))*(sin(xx1)*sin(xx1_inbounds) + sin(xx2)*sin(xx2_inbounds)*cos(xx1)*cos(xx1_inbounds) + cos(xx1)*cos(xx1_inbounds)*cos(xx2)*cos(xx2_inbounds)),* parity[9] = (sin(xx2)*sin(xx2_inbounds) + cos(xx2)*cos(xx2_inbounds))**2]"*/{const double tmp0 = cos(xx1)*cos(xx1_inbounds);const double tmp1 = sin(xx1)*sin(xx1_inbounds);const double tmp2 = sin(xx2)*sin(xx2_inbounds);const double tmp3 = cos(xx2)*cos(xx2_inbounds);const double tmp4 = tmp0 + tmp1*tmp2 + tmp1*tmp3;const double tmp5 = tmp0*tmp2 + tmp0*tmp3 + tmp1;const double tmp6 = tmp2 + tmp3;parity[0] = 1;parity[1] = tmp4;parity[2] = tmp5;parity[3] = tmp6;parity[4] = ((tmp4)*(tmp4));parity[5] = tmp4*tmp5;parity[6] = tmp4*tmp6;parity[7] = ((tmp5)*(tmp5));parity[8] = tmp5*tmp6;parity[9] = ((tmp6)*(tmp6));}
// set_bcstruct() loops from the innermost boundary// ghostzones on the cube ("which_gz==0",// corresponding to the single layer of ghostzones// closest to the interior data), and at each// ghostzone layer, we apply the following 5-step// algorithm:// Step 1: Count the number of outer and inner// boundary points, store to// num_ob_pts and num_ib_pts, respectively.// Step 2: Now that we know the number of outer// boundary points on this ghostzone layer,// allocate memory needed for storing the// outer and inner boundary condition data.// Step 2.a: At all outer boundary ghost zones, allocate// memory for a single member of the outer_bc// data type.// Step 2.b: At all inner boundary ghost zones, allocate// memory for a single member of the inner_bc// data type.// Step 3: Store the number of outer and inner boundary// points on each ghostzone layer, where e.g.,// which_gz==0 corresponds to the innermost// ghostzones on the numerical domain.// Step 4: Store information needed for outer boundary// conditions, to outer_bc_dest_pt and// outer_bc_face arrays.// Step 5: Store information needed for inner boundary// conditions, including interior point to which// inner ghost zone maps, and parity conditions// for all 10 gridfunction types.void set_bcstruct(const paramstruct *restrict params,gz_map *restrict bc_gz_map,parity_condition *bc_parity_conditions,bc_struct *restrict bcstruct) {#include "RELATIVE_PATH__set_Cparameters.h" /* Header file containing correct #include for set_Cparameters.h;* accounting for the relative path */int imin[3] = { NGHOSTS, NGHOSTS, NGHOSTS };int imax[3] = { Nxx_plus_2NGHOSTS0-NGHOSTS, Nxx_plus_2NGHOSTS1-NGHOSTS, Nxx_plus_2NGHOSTS2-NGHOSTS };// Loop from the innermost ghostzone on the cube (which_gz==0) and work outward.// This ordering is necessary, as ghostzones at which_gz==1 will generally// depend on ghostzones at which_gz==0 being already set.for(int which_gz = 0; which_gz < NGHOSTS; which_gz++) {// Step 1: Count the number of outer and inner// boundary points, store to// num_ob_pts and num_ib_pts, respectively.#define COUNT_INNER_OR_OUTER if(bc_gz_map[IDX3S(i0,i1,i2)].i0==-1) { num_ob_pts++;} else { num_ib_pts++; }int num_ob_pts = 0;int num_ib_pts = 0;LOOP_REGION(imin[0]-1,imin[0], imin[1],imax[1], imin[2],imax[2]) { COUNT_INNER_OR_OUTER } imin[0]--;LOOP_REGION(imax[0],imax[0]+1, imin[1],imax[1], imin[2],imax[2]) { COUNT_INNER_OR_OUTER } imax[0]++;LOOP_REGION(imin[0],imax[0], imin[1]-1,imin[1], imin[2],imax[2]) { COUNT_INNER_OR_OUTER } imin[1]--;LOOP_REGION(imin[0],imax[0], imax[1],imax[1]+1, imin[2],imax[2]) { COUNT_INNER_OR_OUTER } imax[1]++;LOOP_REGION(imin[0],imax[0], imin[1],imax[1], imin[2]-1,imin[2]) { COUNT_INNER_OR_OUTER } imin[2]--;LOOP_REGION(imin[0],imax[0], imin[1],imax[1], imax[2],imax[2]+1) { COUNT_INNER_OR_OUTER } imax[2]++;// Step 2: Now that we know the number of outer boundary points on this ghostzone// layer, we allocate memory needed for storing the outer and inner boundary// condition data.// Step 2.a: At all outer boundary ghost zones, allocate memory for a single member of the outer_bc// data type.bcstruct->outer[which_gz] = (outer_bc *)malloc(sizeof(outer_bc)*num_ob_pts);// Step 2.b: At all inner boundary ghost zones, allocate memory for a single member of the inner_bc// data type.bcstruct->inner[which_gz] = (inner_bc *)malloc(sizeof(inner_bc)*num_ib_pts);// Step 3: Store the number of outer and inner boundary points on each ghostzone layer, where e.g.,// which_gz==0 corresponds to the innermost ghostzones on the numerical domain.bcstruct->num_ob_gz_pts[which_gz] = num_ob_pts;bcstruct->num_ib_gz_pts[which_gz] = num_ib_pts;// Reset imin[] and imax[], to prepare for the next step.for(int ii=0;ii<3;ii++) {imin[ii]++; imax[ii]--;}// Step 4: Store information needed for outer boundary conditions, to outer_bc_dest_pt[which_gz][]// and outer_bc_face[which_gz][] arrays:#define OB_SET(facei0,facei1,facei2) if(bc_gz_map[IDX3S(i0,i1,i2)].i0==-1) { \bcstruct->outer[which_gz][pt].outer_bc_dest_pt.i0 = i0; \bcstruct->outer[which_gz][pt].outer_bc_dest_pt.i1 = i1; \bcstruct->outer[which_gz][pt].outer_bc_dest_pt.i2 = i2; \bcstruct->outer[which_gz][pt].FACEi0= facei0; \bcstruct->outer[which_gz][pt].FACEi1= facei1; \bcstruct->outer[which_gz][pt].FACEi2= facei2; \pt++; }int pt = 0;LOOP_REGION(imin[0]-1,imin[0], imin[1],imax[1], imin[2],imax[2]) {OB_SET(MINFACE,NUL,NUL)} imin[0]--;LOOP_REGION(imax[0],imax[0]+1, imin[1],imax[1], imin[2],imax[2]) {OB_SET(MAXFACE,NUL,NUL)} imax[0]++;LOOP_REGION(imin[0],imax[0], imin[1]-1,imin[1], imin[2],imax[2]) {OB_SET(NUL,MINFACE,NUL)} imin[1]--;LOOP_REGION(imin[0],imax[0], imax[1],imax[1]+1, imin[2],imax[2]) {OB_SET(NUL,MAXFACE,NUL)} imax[1]++;LOOP_REGION(imin[0],imax[0], imin[1],imax[1], imin[2]-1,imin[2]) {OB_SET(NUL,NUL,MINFACE)} imin[2]--;LOOP_REGION(imin[0],imax[0], imin[1],imax[1], imax[2],imax[2]+1) {OB_SET(NUL,NUL,MAXFACE)} imax[2]++;// fprintf(stderr,"num OB points with which_gz = %d: %d | should be: %d\n",which_gz,pt,num_ob_gz_pts[which_gz]);// Reset imin[] and imax[], to prepare for the next step.for(int ii=0;ii<3;ii++) {imin[ii]++; imax[ii]--;}// Step 5: Store information needed for inner boundary conditions, including interior point to which// inner ghost zone maps, and parity conditions for all 10 gridfunction types.#define IB_SET if(bc_gz_map[IDX3S(i0,i1,i2)].i0!=-1) { \bcstruct->inner[which_gz][pt].inner_bc_dest_pt.i0=i0; \bcstruct->inner[which_gz][pt].inner_bc_dest_pt.i1=i1; \bcstruct->inner[which_gz][pt].inner_bc_dest_pt.i2=i2; \bcstruct->inner[which_gz][pt].inner_bc_src_pt.i0 =bc_gz_map[IDX3S(i0,i1,i2)].i0; \bcstruct->inner[which_gz][pt].inner_bc_src_pt.i1 =bc_gz_map[IDX3S(i0,i1,i2)].i1; \bcstruct->inner[which_gz][pt].inner_bc_src_pt.i2 =bc_gz_map[IDX3S(i0,i1,i2)].i2; \for(int ii=0;ii<10;ii++) { \bcstruct->inner[which_gz][pt].parity[ii] = \(int8_t)bc_parity_conditions[IDX3S(i0,i1,i2)].parity[ii]; } \pt++; }pt = 0;LOOP_REGION(imin[0]-1,imin[0], imin[1],imax[1], imin[2],imax[2]) {IB_SET} imin[0]--;LOOP_REGION(imax[0],imax[0]+1, imin[1],imax[1], imin[2],imax[2]) {IB_SET} imax[0]++;LOOP_REGION(imin[0],imax[0], imin[1]-1,imin[1], imin[2],imax[2]) {IB_SET} imin[1]--;LOOP_REGION(imin[0],imax[0], imax[1],imax[1]+1, imin[2],imax[2]) {IB_SET} imax[1]++;LOOP_REGION(imin[0],imax[0], imin[1],imax[1], imin[2]-1,imin[2]) {IB_SET} imin[2]--;LOOP_REGION(imin[0],imax[0], imin[1],imax[1], imax[2],imax[2]+1) {IB_SET} imax[2]++;} // END for(int which_gz = 0; which_gz < NGHOSTS; which_gz++)} // END function
// set_parity_conditions_from_symbolic_dot_products():// Evaluate dot products needed for setting parity// conditions at a given point (xx0,xx1,xx2),// using C code generated by NRPy+ function// parity_conditions_symbolic_dot_products().void eval_symbolic_dot_products_to_set_parity_conditions(const paramstruct *restrict params, REAL parity[10],const REAL xx0,const REAL xx1,const REAL xx2,const REAL xx0_inbounds,const REAL xx1_inbounds,const REAL xx2_inbounds) {#include "RELATIVE_PATH__set_Cparameters.h" /* Header file containing correct #include for set_Cparameters.h;* accounting for the relative path */#include "parity_conditions_symbolic_dot_products.h"}void set_up__bc_gz_map_and_parity_condns(const paramstruct *restrict params,REAL *xx[3], gz_map *bc_gz_map,parity_condition *bc_parity_conditions) {#include "RELATIVE_PATH__set_Cparameters.h" /* Header file containing correct #include for set_Cparameters.h;* accounting for the relative path */// xx[0][j] = xxmin[0] + ((REAL)(j-NGHOSTS) + (1.0/2.0))*dxx0;// -> xxmin[0] = xx[0][0] - ((REAL)(0-NGHOSTS) + (1.0/2.0))*dxx0const REAL xxmin[3] = { xx[0][0] - ((REAL)(0-NGHOSTS) + (1.0/2.0))*dxx0,xx[1][0] - ((REAL)(0-NGHOSTS) + (1.0/2.0))*dxx1,xx[2][0] - ((REAL)(0-NGHOSTS) + (1.0/2.0))*dxx2 };//fprintf(stderr,"hey inside setbc: %e %e %e | %e %e\n",xxmin[0],xxmin[1],xxmin[2],xx[0][0],dxx0);LOOP_REGION(0,Nxx_plus_2NGHOSTS0,0,Nxx_plus_2NGHOSTS1,0,Nxx_plus_2NGHOSTS2) {// Step 1: Convert the (curvilinear) coordinate (x0,x1,x2) to Cartesian coordinatesREAL xCart[3];EigenCoord_xxCart(params, xx, i0,i1,i2, xCart);REAL Cartx = xCart[0];REAL Carty = xCart[1];REAL Cartz = xCart[2];// Step 2: Find the (i0_inbounds,i1_inbounds,i2_inbounds) corresponding to the above Cartesian coordinate.// If (i0_inbounds,i1_inbounds,i2_inbounds) is in a ghost zone, then it must equal (i0,i1,i2), and// the point is an outer boundary point.// Otherwise (i0_inbounds,i1_inbounds,i2_inbounds) is in the grid interior, and data at (i0,i1,i2)// must be replaced with data at (i0_inbounds,i1_inbounds,i2_inbounds), but multiplied by the// appropriate parity condition (+/- 1).REAL Cart_to_xx0_inbounds,Cart_to_xx1_inbounds,Cart_to_xx2_inbounds;#include "EigenCoord_Cart_to_xx.h"int i0_inbounds = (int)( (Cart_to_xx0_inbounds - xxmin[0] - (1.0/2.0)*dxx0 + ((REAL)NGHOSTS)*dxx0)/dxx0 + 0.5 );int i1_inbounds = (int)( (Cart_to_xx1_inbounds - xxmin[1] - (1.0/2.0)*dxx1 + ((REAL)NGHOSTS)*dxx1)/dxx1 + 0.5 );int i2_inbounds = (int)( (Cart_to_xx2_inbounds - xxmin[2] - (1.0/2.0)*dxx2 + ((REAL)NGHOSTS)*dxx2)/dxx2 + 0.5 );// Step 2.a: (Sanity/validation check) Convert the interior point// x0(i0_inbounds),x1(i1_inbounds),x2(i2_inbounds) to Cartesian coordinates,// make sure that the Cartesian coordinate matches the Cartesian coordinate of// x0(i0),x1(i1),x2(i2). If not, error out!REAL xCart_orig[3]; for(int ii=0;ii<3;ii++) xCart_orig[ii] = xCart[ii];EigenCoord_xxCart(params, xx, i0_inbounds,i1_inbounds,i2_inbounds, xCart);//fprintf(stderr,"Cartesian agreement: ( %.15e %.15e %.15e ) ?= ( %.15e %.15e %.15e )\n",// (double)xCart_orig[0],(double)xCart_orig[1],(double)xCart_orig[2],// (double)xCart[0],(double)xCart[1],(double)xCart[2]);#define EPS_ABS 1e-8if(fabs( (double)(xCart_orig[0] - xCart[0]) ) > EPS_ABS ||fabs( (double)(xCart_orig[1] - xCart[1]) ) > EPS_ABS ||fabs( (double)(xCart_orig[2] - xCart[2]) ) > EPS_ABS) {fprintf(stderr,"Error. Cartesian disagreement: ( %.15e %.15e %.15e ) != ( %.15e %.15e %.15e )\n",(double)xCart_orig[0],(double)xCart_orig[1],(double)xCart_orig[2],(double)xCart[0],(double)xCart[1],(double)xCart[2]);exit(1);}// Step 3: Set bc_gz_map and bc_parity_conditions.if(i0_inbounds-i0 == 0 && i1_inbounds-i1 == 0 && i2_inbounds-i2 == 0) {// Step 3.a: Iff we are on an outer boundary point or in the grid// interior, i0_inbounds==i0, i1_inbounds==i1, and// i2_inbounds==i2, and inner boundary conditions do not// apply: set bc_gz_map to -1, and parity=1.bc_gz_map[IDX3S(i0,i1,i2)].i0=-1;bc_gz_map[IDX3S(i0,i1,i2)].i1=-1;bc_gz_map[IDX3S(i0,i1,i2)].i2=-1;for(int which_parity=0; which_parity<10; which_parity++) {bc_parity_conditions[IDX3S(i0,i1,i2)].parity[which_parity] = 1;}} else {// Step 3.b: If we are on an *inner* boundary point:// 1. Set bc_gz_map at (i0,i1,i2) to the point// in the interior to which this boundary// point maps, and// 2. Perform the unit vector dot products// necessary to set all 10 possible parity// conditions, calling function// set_parity_from_unit_vector_dot_product()bc_gz_map[IDX3S(i0,i1,i2)].i0=i0_inbounds;bc_gz_map[IDX3S(i0,i1,i2)].i1=i1_inbounds;bc_gz_map[IDX3S(i0,i1,i2)].i2=i2_inbounds;const REAL xx0 = xx[0][i0];const REAL xx1 = xx[1][i1];const REAL xx2 = xx[2][i2];const REAL xx0_inbounds = xx[0][i0_inbounds];const REAL xx1_inbounds = xx[1][i1_inbounds];const REAL xx2_inbounds = xx[2][i2_inbounds];REAL REAL_parity_array[10];eval_symbolic_dot_products_to_set_parity_conditions(params, REAL_parity_array, xx0,xx1,xx2,xx0_inbounds,xx1_inbounds,xx2_inbounds);for(int whichparity=0;whichparity<10;whichparity++) {//printf("Good? Parity %d evaluated to %e\n",whichparity,(double)REAL_parity_array[whichparity]);// Perform sanity check on parity array output: should be +1 or -1 to within 8 significant digits:if( (REAL_parity_array[whichparity] > 0 && fabs(REAL_parity_array[whichparity] - (+1)) > 1e-8) ||(REAL_parity_array[whichparity] <= 0 && fabs(REAL_parity_array[whichparity] - (-1)) > 1e-8) ) {fprintf(stderr,"Error. Parity evaluated to %e , which is not within 8 significant digits of +1 or -1.",REAL_parity_array[whichparity]);exit(1);}if(REAL_parity_array[whichparity] < 0.0) bc_parity_conditions[IDX3S(i0,i1,i2)].parity[whichparity] = -1;if(REAL_parity_array[whichparity] > 0.0) bc_parity_conditions[IDX3S(i0,i1,i2)].parity[whichparity] = +1;}}}}
typedef struct __paramstruct__ {int Nxx0;int Nxx1;int Nxx2;int Nxx_plus_2NGHOSTS0;int Nxx_plus_2NGHOSTS1;int Nxx_plus_2NGHOSTS2;REAL xx0;REAL xx1;REAL xx2;REAL dxx0;REAL dxx1;REAL dxx2;REAL invdx0;REAL invdx1;REAL invdx2;REAL f0_of_xx0;REAL f1_of_xx1;REAL f2_of_xx0_xx1;REAL f3_of_xx0;REAL f4_of_xx2;REAL f0_of_xx0__D0;REAL f0_of_xx0__DD00;REAL f0_of_xx0__DDD000;REAL f1_of_xx1__D1;REAL f1_of_xx1__DD11;REAL f1_of_xx1__DDD111;REAL f2_of_xx0_xx1__D0;REAL f2_of_xx0_xx1__D1;REAL f2_of_xx0_xx1__DD00;REAL f2_of_xx0_xx1__DD11;REAL f3_of_xx0__D0;REAL f3_of_xx0__DD00;REAL f4_of_xx2__D2;REAL f4_of_xx2__DD22;REAL RMAX;REAL M;REAL a;REAL r0;} paramstruct;
/*Enforce det(gammabar) = det(gammahat) constraint.*/void enforce_detgammabar_constraint(const paramstruct *restrict params, REAL *restrict xx[3], REAL *restrict in_gfs) {#include "set_Cparameters.h"#pragma omp parallel forfor(int i2=0; i2<Nxx_plus_2NGHOSTS2; i2++) {const REAL xx2 = xx[2][i2];for(int i1=0; i1<Nxx_plus_2NGHOSTS1; i1++) {const REAL xx1 = xx[1][i1];for(int i0=0; i0<Nxx_plus_2NGHOSTS0; i0++) {const REAL xx0 = xx[0][i0];/** NRPy+ Finite Difference Code Generation, Step 1 of 1: Read from main memory and compute finite difference stencils:*/const double hDD00 = in_gfs[IDX4S(HDD00GF, i0,i1,i2)];const double hDD01 = in_gfs[IDX4S(HDD01GF, i0,i1,i2)];const double hDD02 = in_gfs[IDX4S(HDD02GF, i0,i1,i2)];const double hDD11 = in_gfs[IDX4S(HDD11GF, i0,i1,i2)];const double hDD12 = in_gfs[IDX4S(HDD12GF, i0,i1,i2)];const double hDD22 = in_gfs[IDX4S(HDD22GF, i0,i1,i2)];/** NRPy+ Finite Difference Code Generation, Step 2 of 1: Evaluate SymPy expressions and write to main memory:*/const double tmp0 = hDD00 + 1;const double tmp1 = ((sin(xx1))*(sin(xx1)));const double tmp2 = tmp1*((xx0)*(xx0)*(xx0)*(xx0));const double tmp3 = ((xx0)*(xx0));const double tmp4 = hDD11*tmp3 + tmp3;const double tmp5 = tmp1*tmp3;const double tmp6 = hDD22*tmp5 + tmp5;const double tmp7 = cbrt(fabs(tmp2)/(-((hDD01)*(hDD01))*tmp3*tmp6 + 2*hDD01*hDD02*hDD12*tmp2 - ((hDD02)*(hDD02))*tmp4*tmp5 - ((hDD12)*(hDD12))*tmp0*tmp2 + tmp0*tmp4*tmp6));in_gfs[IDX4S(HDD00GF, i0, i1, i2)] = tmp0*tmp7 - 1;in_gfs[IDX4S(HDD01GF, i0, i1, i2)] = hDD01*tmp7;in_gfs[IDX4S(HDD02GF, i0, i1, i2)] = hDD02*tmp7;in_gfs[IDX4S(HDD11GF, i0, i1, i2)] = tmp7*(hDD11 + 1) - 1;in_gfs[IDX4S(HDD12GF, i0, i1, i2)] = hDD12*tmp7;in_gfs[IDX4S(HDD22GF, i0, i1, i2)] = tmp7*(hDD22 + 1) - 1;} // END LOOP: for(int i0=0; i0<Nxx_plus_2NGHOSTS0; i0++)} // END LOOP: for(int i1=0; i1<Nxx_plus_2NGHOSTS1; i1++)} // END LOOP: for(int i2=0; i2<Nxx_plus_2NGHOSTS2; i2++)}
// Set free-parameter values.const REAL domain_size = 3.0;const REAL sinh_width = 0.4;const REAL sinhv2_const_dr= 0.05;const REAL SymTP_bScale = 0.5;params.RMAX = domain_size;
/*Set up the initial data at all points on the numerical grid.*/void initial_data(const paramstruct *restrict params,REAL *restrict xx[3], REAL *restrict in_gfs) {#include "set_Cparameters.h"#pragma omp parallel forfor(int i2=0; i2<Nxx_plus_2NGHOSTS2; i2++) {const REAL xx2 = xx[2][i2];for(int i1=0; i1<Nxx_plus_2NGHOSTS1; i1++) {const REAL xx1 = xx[1][i1];for(int i0=0; i0<Nxx_plus_2NGHOSTS0; i0++) {const REAL xx0 = xx[0][i0];{const double tmp0 = r0 + xx0;const double tmp1 = M*tmp0;const double tmp2 = 2*tmp1;const double tmp3 = 2*r0;const double tmp4 = 2*xx0;const double tmp5 = tmp3 + tmp4;const double tmp6 = tmp0*tmp5;const double tmp7 = ((a)*(a));const double tmp8 = 2*xx1;const double tmp9 = tmp7*cos(tmp8);const double tmp10 = tmp7 + tmp9;const double tmp11 = tmp10 + tmp6;const double tmp12 = 4*tmp1;const double tmp13 = (1.0/(tmp11 + tmp12));const double tmp14 = ((tmp0)*(tmp0));const double tmp15 = cos(xx1);const double tmp16 = ((tmp15)*(tmp15))*tmp7;const double tmp17 = tmp14 + tmp16;const double tmp18 = (1.0/(tmp17));const double tmp19 = tmp18*tmp2;const double tmp20 = tmp19 + 1;const double tmp21 = sqrt(tmp20);const double tmp22 = M*tmp21;const double tmp23 = tmp13*tmp22;const double tmp24 = (1.0/((tmp11)*(tmp11)));const double tmp25 = tmp24*(tmp10 - tmp6);const double tmp26 = 4*tmp25;const double tmp27 = tmp23*tmp26*(tmp11 + tmp2);const double tmp28 = tmp1*tmp18;const double tmp29 = sin(xx1);const double tmp30 = ((tmp29)*(tmp29)*(tmp29)*(tmp29));const double tmp31 = tmp30*tmp7;const double tmp32 = ((tmp20)*(tmp20));const double tmp33 = tmp31*tmp32;const double tmp34 = ((tmp29)*(tmp29));const double tmp35 = tmp34*tmp7;const double tmp36 = tmp14 + tmp19*tmp35 + tmp7;const double tmp37 = tmp34*tmp36;const double tmp38 = tmp20*tmp37;const double tmp39 = -tmp17*tmp33 + tmp17*tmp38;const double tmp40 = (1.0/(tmp39));const double tmp41 = tmp17*pow(tmp20, 3.0/2.0)*tmp40;const double tmp42 = 4*tmp14;const double tmp43 = tmp23*tmp42;const double tmp44 = ((a)*(a)*(a)*(a));const double tmp45 = -M;const double tmp46 = tmp2*tmp24*(8*((tmp0)*(tmp0)*(tmp0)*(tmp0)*(tmp0)) + 4*tmp0*tmp9*(tmp0*(M + tmp5) + tmp7) + tmp42*tmp7*(tmp45 + tmp5) + tmp44*(tmp0 + tmp45)*cos(4*xx1) + tmp44*(M + 3*r0 + 3*xx0));const double tmp47 = tmp17*tmp37;const double tmp48 = -M*tmp26*tmp31*tmp41 + tmp13*tmp34*tmp41*tmp46 + tmp27*tmp40*tmp47 + tmp40*tmp43*(-tmp33 + tmp38);const double tmp49 = fabs(xx0);const double tmp50 = pow(tmp49, 4.0/3.0);const double tmp51 = cbrt(tmp40);const double tmp52 = fabs(tmp29);const double tmp53 = tmp51*pow(tmp52, 2.0/3.0);const double tmp54 = tmp50*tmp53;const double tmp55 = (1.0/(xx0));const double tmp56 = tmp54*tmp55;const double tmp57 = tmp29*tmp7;const double tmp58 = tmp13*tmp21;const double tmp59 = 8*tmp15;const double tmp60 = tmp1*tmp59/tmp11;const double tmp61 = a*tmp34;const double tmp62 = 2*tmp61;const double tmp63 = (1.0/3.0)*tmp48;const double tmp64 = tmp20*tmp34;const double tmp65 = a*tmp64;const double tmp66 = ((xx0)*(xx0));const double tmp67 = (1.0/(tmp66));const double tmp68 = tmp54*tmp67;const double tmp69 = ((a)*(a)*(a));const double tmp70 = tmp34*tmp58;const double tmp71 = tmp67/tmp34;const double tmp72 = tmp40*((xx0)*(xx0)*(xx0)*(xx0));const double tmp73 = tmp17*tmp32*tmp7;const double tmp74 = tmp17*tmp20;const double tmp75 = tmp36*tmp74;const double tmp76 = -pow(tmp29, 6)*tmp72*tmp73 + tmp30*tmp72*tmp75;const double tmp77 = (1.0/(tmp76));const double tmp78 = tmp20*tmp54;const double tmp79 = a*tmp78;const double tmp80 = tmp17*tmp54;const double tmp81 = tmp37*tmp54;const double tmp82 = (1.0/((tmp76)*(tmp76)));const double tmp83 = cbrt(tmp49)*tmp53*(((xx0) > 0) - ((xx0) < 0));const double tmp84 = (4.0/3.0)*tmp83;const double tmp85 = tmp37*tmp84;const double tmp86 = M*tmp18;const double tmp87 = 2*tmp86;const double tmp88 = ((tmp17)*(tmp17));const double tmp89 = (1.0/(tmp88));const double tmp90 = tmp89*(-tmp3 - tmp4);const double tmp91 = tmp2*tmp90;const double tmp92 = tmp35*tmp87 + tmp35*tmp91 + tmp5;const double tmp93 = tmp34*tmp54;const double tmp94 = tmp92*tmp93;const double tmp95 = tmp87 + tmp91;const double tmp96 = tmp17*tmp64;const double tmp97 = tmp31*tmp74*(tmp12*tmp90 + 4*tmp86) + tmp33*tmp5 - tmp38*tmp5 - tmp47*tmp95 - tmp92*tmp96;const double tmp98 = (1.0/3.0)*tmp40;const double tmp99 = tmp97*tmp98;const double tmp100 = tmp81*tmp99;const double tmp101 = tmp100 + tmp85 + tmp94;const double tmp102 = pow(tmp40, 4.0/3.0)*pow(tmp49, 16.0/3.0)*pow(tmp52, 8.0/3.0)*tmp88;const double tmp103 = -tmp100 - tmp85 - tmp94;const double tmp104 = pow(tmp40, 2.0/3.0)*pow(tmp49, 8.0/3.0)*pow(tmp52, 4.0/3.0);const double tmp105 = tmp104*tmp77;const double tmp106 = tmp105*tmp47;const double tmp107 = (1.0/2.0)*tmp106;const double tmp108 = tmp105*tmp74;const double tmp109 = -tmp17*tmp84 - tmp5*tmp54 - tmp80*tmp99;const double tmp110 = -tmp104*tmp33 + tmp104*tmp38;const double tmp111 = tmp110*tmp77;const double tmp112 = tmp54*tmp95;const double tmp113 = tmp112 + tmp20*tmp84 + tmp78*tmp99;const double tmp114 = -tmp112*tmp62 - 2.0/3.0*tmp40*tmp61*tmp78*tmp97 - 8.0/3.0*tmp65*tmp83;const double tmp115 = a*tmp96;const double tmp116 = tmp105*tmp115;const double tmp117 = (1.0/2.0)*tmp116;const double tmp118 = 2*tmp15;const double tmp119 = tmp118*tmp29;const double tmp120 = tmp119*tmp54;const double tmp121 = (2.0/3.0)*tmp15*tmp50*tmp51*(((tmp29) > 0) - ((tmp29) < 0))/cbrt(tmp52);const double tmp122 = ((tmp29)*(tmp29)*(tmp29)*(tmp29)*(tmp29))*tmp44;const double tmp123 = ((tmp29)*(tmp29)*(tmp29));const double tmp124 = tmp123*tmp15;const double tmp125 = tmp123*tmp36*tmp7;const double tmp126 = tmp12*tmp15*tmp18;const double tmp127 = tmp12*tmp89;const double tmp128 = tmp124*tmp127;const double tmp129 = tmp126*tmp57 + tmp128*tmp44;const double tmp130 = tmp98*(-tmp118*tmp122*tmp32 + tmp118*tmp125*tmp20 - tmp119*tmp75 + tmp122*tmp20*tmp28*tmp59 + 4*tmp124*tmp73 - tmp125*tmp126 - tmp129*tmp96);const double tmp131 = (1.0/2.0)*tmp82;const double tmp132 = tmp130*tmp78;const double tmp133 = tmp104*tmp110;const double tmp134 = tmp131*tmp133;const double tmp135 = (1.0/2.0)*tmp108;in_gfs[IDX4S(ADD00GF,i0,i1,i2)] = tmp54*(tmp27 - tmp48*((2.0/3.0)*tmp28 + 1.0/3.0));in_gfs[IDX4S(ADD01GF,i0,i1,i2)] = tmp56*tmp57*tmp58*tmp60;in_gfs[IDX4S(ADD02GF,i0,i1,i2)] = tmp56*(-tmp22*tmp25*tmp62 + tmp63*tmp65)/tmp29;in_gfs[IDX4S(ADD11GF,i0,i1,i2)] = tmp68*(tmp43 - tmp48*((1.0/3.0)*tmp14 + (1.0/3.0)*tmp16));in_gfs[IDX4S(ADD12GF,i0,i1,i2)] = -tmp60*tmp68*tmp69*tmp70;in_gfs[IDX4S(ADD22GF,i0,i1,i2)] = tmp54*tmp71*(-tmp37*tmp63 + tmp46*tmp70);in_gfs[IDX4S(ALPHAGF,i0,i1,i2)] = (1.0/(tmp21));in_gfs[IDX4S(BETU0GF,i0,i1,i2)] = 0;in_gfs[IDX4S(BETU1GF,i0,i1,i2)] = 0;in_gfs[IDX4S(BETU2GF,i0,i1,i2)] = 0;in_gfs[IDX4S(CFGF,i0,i1,i2)] = pow(tmp39*tmp77, -1.0/6.0);in_gfs[IDX4S(HDD00GF,i0,i1,i2)] = tmp78 - 1;in_gfs[IDX4S(HDD01GF,i0,i1,i2)] = 0;in_gfs[IDX4S(HDD02GF,i0,i1,i2)] = -tmp29*tmp55*tmp79;in_gfs[IDX4S(HDD11GF,i0,i1,i2)] = tmp67*(-tmp66 + tmp80);in_gfs[IDX4S(HDD12GF,i0,i1,i2)] = 0;in_gfs[IDX4S(HDD22GF,i0,i1,i2)] = tmp71*(-tmp34*tmp66 + tmp81);in_gfs[IDX4S(LAMBDAU0GF,i0,i1,i2)] = tmp101*tmp102*tmp33*tmp82 + tmp106*(tmp107*tmp113 + tmp114*tmp117) + tmp108*(tmp103*tmp107 + tmp34*xx0) + tmp111*(tmp107*tmp109 + xx0);in_gfs[IDX4S(LAMBDAU1GF,i0,i1,i2)] = xx0*(tmp108*((1.0/2.0)*tmp111*(-tmp120*tmp36 - tmp121*tmp37 - tmp129*tmp93 - tmp130*tmp81) + (1.0/2.0)*sin(tmp8)) + ((tmp110)*(tmp110))*tmp131*(-tmp120*tmp7 + tmp121*tmp17 + tmp130*tmp80) + tmp115*tmp133*tmp82*(tmp119*tmp79 + tmp121*tmp65 + tmp128*tmp54*tmp69 + tmp132*tmp61) + tmp134*tmp47*(-tmp121*tmp20 - tmp127*tmp15*tmp54*tmp57 - tmp132));in_gfs[IDX4S(LAMBDAU2GF,i0,i1,i2)] = tmp29*xx0*(tmp102*tmp103*tmp131*tmp32*tmp61 + tmp106*(tmp113*tmp117 + tmp114*tmp135) + tmp109*tmp115*tmp134 + 2*tmp116*(tmp101*tmp135 - tmp55));in_gfs[IDX4S(TRKGF,i0,i1,i2)] = tmp48;in_gfs[IDX4S(VETU0GF,i0,i1,i2)] = tmp19/tmp20;in_gfs[IDX4S(VETU1GF,i0,i1,i2)] = 0;in_gfs[IDX4S(VETU2GF,i0,i1,i2)] = 0;}} // END LOOP: for(int i0=0; i0<Nxx_plus_2NGHOSTS0; i0++)} // END LOOP: for(int i1=0; i1<Nxx_plus_2NGHOSTS1; i1++)} // END LOOP: for(int i2=0; i2<Nxx_plus_2NGHOSTS2; i2++)}
/*Evaluate the momentum constraint*/void momentum_constraint(const paramstruct *restrict params, REAL *restrict xx[3],REAL *restrict in_gfs, REAL *restrict aux_gfs) {#include "set_Cparameters.h"#pragma omp parallel forfor(int i2=NGHOSTS; i2<NGHOSTS+Nxx2; i2++) {const REAL xx2 = xx[2][i2];for(int i1=NGHOSTS; i1<NGHOSTS+Nxx1; i1++) {const REAL xx1 = xx[1][i1];for(int i0=NGHOSTS; i0<NGHOSTS+Nxx0; i0++) {const REAL xx0 = xx[0][i0];{/** NRPy+ Finite Difference Code Generation, Step 1 of 2: Read from main memory and compute finite difference stencils:*/const double hDD00_i0_i1m2_i2 = in_gfs[IDX4S(HDD00GF, i0,i1-2,i2)];const double hDD00_i0_i1m1_i2 = in_gfs[IDX4S(HDD00GF, i0,i1-1,i2)];const double hDD00_i0m2_i1_i2 = in_gfs[IDX4S(HDD00GF, i0-2,i1,i2)];const double hDD00_i0m1_i1_i2 = in_gfs[IDX4S(HDD00GF, i0-1,i1,i2)];const double hDD00 = in_gfs[IDX4S(HDD00GF, i0,i1,i2)];const double hDD00_i0p1_i1_i2 = in_gfs[IDX4S(HDD00GF, i0+1,i1,i2)];const double hDD00_i0p2_i1_i2 = in_gfs[IDX4S(HDD00GF, i0+2,i1,i2)];const double hDD00_i0_i1p1_i2 = in_gfs[IDX4S(HDD00GF, i0,i1+1,i2)];const double hDD00_i0_i1p2_i2 = in_gfs[IDX4S(HDD00GF, i0,i1+2,i2)];const double hDD01_i0_i1m2_i2 = in_gfs[IDX4S(HDD01GF, i0,i1-2,i2)];const double hDD01_i0_i1m1_i2 = in_gfs[IDX4S(HDD01GF, i0,i1-1,i2)];const double hDD01_i0m2_i1_i2 = in_gfs[IDX4S(HDD01GF, i0-2,i1,i2)];const double hDD01_i0m1_i1_i2 = in_gfs[IDX4S(HDD01GF, i0-1,i1,i2)];const double hDD01 = in_gfs[IDX4S(HDD01GF, i0,i1,i2)];const double hDD01_i0p1_i1_i2 = in_gfs[IDX4S(HDD01GF, i0+1,i1,i2)];const double hDD01_i0p2_i1_i2 = in_gfs[IDX4S(HDD01GF, i0+2,i1,i2)];const double hDD01_i0_i1p1_i2 = in_gfs[IDX4S(HDD01GF, i0,i1+1,i2)];const double hDD01_i0_i1p2_i2 = in_gfs[IDX4S(HDD01GF, i0,i1+2,i2)];const double hDD02_i0_i1m2_i2 = in_gfs[IDX4S(HDD02GF, i0,i1-2,i2)];const double hDD02_i0_i1m1_i2 = in_gfs[IDX4S(HDD02GF, i0,i1-1,i2)];const double hDD02_i0m2_i1_i2 = in_gfs[IDX4S(HDD02GF, i0-2,i1,i2)];const double hDD02_i0m1_i1_i2 = in_gfs[IDX4S(HDD02GF, i0-1,i1,i2)];const double hDD02 = in_gfs[IDX4S(HDD02GF, i0,i1,i2)];const double hDD02_i0p1_i1_i2 = in_gfs[IDX4S(HDD02GF, i0+1,i1,i2)];const double hDD02_i0p2_i1_i2 = in_gfs[IDX4S(HDD02GF, i0+2,i1,i2)];const double hDD02_i0_i1p1_i2 = in_gfs[IDX4S(HDD02GF, i0,i1+1,i2)];const double hDD02_i0_i1p2_i2 = in_gfs[IDX4S(HDD02GF, i0,i1+2,i2)];const double hDD11_i0_i1m2_i2 = in_gfs[IDX4S(HDD11GF, i0,i1-2,i2)];const double hDD11_i0_i1m1_i2 = in_gfs[IDX4S(HDD11GF, i0,i1-1,i2)];const double hDD11_i0m2_i1_i2 = in_gfs[IDX4S(HDD11GF, i0-2,i1,i2)];const double hDD11_i0m1_i1_i2 = in_gfs[IDX4S(HDD11GF, i0-1,i1,i2)];const double hDD11 = in_gfs[IDX4S(HDD11GF, i0,i1,i2)];const double hDD11_i0p1_i1_i2 = in_gfs[IDX4S(HDD11GF, i0+1,i1,i2)];const double hDD11_i0p2_i1_i2 = in_gfs[IDX4S(HDD11GF, i0+2,i1,i2)];const double hDD11_i0_i1p1_i2 = in_gfs[IDX4S(HDD11GF, i0,i1+1,i2)];const double hDD11_i0_i1p2_i2 = in_gfs[IDX4S(HDD11GF, i0,i1+2,i2)];const double hDD12_i0_i1m2_i2 = in_gfs[IDX4S(HDD12GF, i0,i1-2,i2)];const double hDD12_i0_i1m1_i2 = in_gfs[IDX4S(HDD12GF, i0,i1-1,i2)];const double hDD12_i0m2_i1_i2 = in_gfs[IDX4S(HDD12GF, i0-2,i1,i2)];const double hDD12_i0m1_i1_i2 = in_gfs[IDX4S(HDD12GF, i0-1,i1,i2)];const double hDD12 = in_gfs[IDX4S(HDD12GF, i0,i1,i2)];const double hDD12_i0p1_i1_i2 = in_gfs[IDX4S(HDD12GF, i0+1,i1,i2)];const double hDD12_i0p2_i1_i2 = in_gfs[IDX4S(HDD12GF, i0+2,i1,i2)];const double hDD12_i0_i1p1_i2 = in_gfs[IDX4S(HDD12GF, i0,i1+1,i2)];const double hDD12_i0_i1p2_i2 = in_gfs[IDX4S(HDD12GF, i0,i1+2,i2)];const double hDD22_i0_i1m2_i2 = in_gfs[IDX4S(HDD22GF, i0,i1-2,i2)];const double hDD22_i0_i1m1_i2 = in_gfs[IDX4S(HDD22GF, i0,i1-1,i2)];const double hDD22_i0m2_i1_i2 = in_gfs[IDX4S(HDD22GF, i0-2,i1,i2)];const double hDD22_i0m1_i1_i2 = in_gfs[IDX4S(HDD22GF, i0-1,i1,i2)];const double hDD22 = in_gfs[IDX4S(HDD22GF, i0,i1,i2)];const double hDD22_i0p1_i1_i2 = in_gfs[IDX4S(HDD22GF, i0+1,i1,i2)];const double hDD22_i0p2_i1_i2 = in_gfs[IDX4S(HDD22GF, i0+2,i1,i2)];const double hDD22_i0_i1p1_i2 = in_gfs[IDX4S(HDD22GF, i0,i1+1,i2)];const double hDD22_i0_i1p2_i2 = in_gfs[IDX4S(HDD22GF, i0,i1+2,i2)];const double aDD00_i0_i1m2_i2 = in_gfs[IDX4S(ADD00GF, i0,i1-2,i2)];const double aDD00_i0_i1m1_i2 = in_gfs[IDX4S(ADD00GF, i0,i1-1,i2)];const double aDD00_i0m2_i1_i2 = in_gfs[IDX4S(ADD00GF, i0-2,i1,i2)];const double aDD00_i0m1_i1_i2 = in_gfs[IDX4S(ADD00GF, i0-1,i1,i2)];const double aDD00 = in_gfs[IDX4S(ADD00GF, i0,i1,i2)];const double aDD00_i0p1_i1_i2 = in_gfs[IDX4S(ADD00GF, i0+1,i1,i2)];const double aDD00_i0p2_i1_i2 = in_gfs[IDX4S(ADD00GF, i0+2,i1,i2)];const double aDD00_i0_i1p1_i2 = in_gfs[IDX4S(ADD00GF, i0,i1+1,i2)];const double aDD00_i0_i1p2_i2 = in_gfs[IDX4S(ADD00GF, i0,i1+2,i2)];const double aDD01_i0_i1m2_i2 = in_gfs[IDX4S(ADD01GF, i0,i1-2,i2)];const double aDD01_i0_i1m1_i2 = in_gfs[IDX4S(ADD01GF, i0,i1-1,i2)];const double aDD01_i0m2_i1_i2 = in_gfs[IDX4S(ADD01GF, i0-2,i1,i2)];const double aDD01_i0m1_i1_i2 = in_gfs[IDX4S(ADD01GF, i0-1,i1,i2)];const double aDD01 = in_gfs[IDX4S(ADD01GF, i0,i1,i2)];const double aDD01_i0p1_i1_i2 = in_gfs[IDX4S(ADD01GF, i0+1,i1,i2)];const double aDD01_i0p2_i1_i2 = in_gfs[IDX4S(ADD01GF, i0+2,i1,i2)];const double aDD01_i0_i1p1_i2 = in_gfs[IDX4S(ADD01GF, i0,i1+1,i2)];const double aDD01_i0_i1p2_i2 = in_gfs[IDX4S(ADD01GF, i0,i1+2,i2)];const double aDD02_i0_i1m2_i2 = in_gfs[IDX4S(ADD02GF, i0,i1-2,i2)];const double aDD02_i0_i1m1_i2 = in_gfs[IDX4S(ADD02GF, i0,i1-1,i2)];const double aDD02_i0m2_i1_i2 = in_gfs[IDX4S(ADD02GF, i0-2,i1,i2)];const double aDD02_i0m1_i1_i2 = in_gfs[IDX4S(ADD02GF, i0-1,i1,i2)];const double aDD02 = in_gfs[IDX4S(ADD02GF, i0,i1,i2)];const double aDD02_i0p1_i1_i2 = in_gfs[IDX4S(ADD02GF, i0+1,i1,i2)];const double aDD02_i0p2_i1_i2 = in_gfs[IDX4S(ADD02GF, i0+2,i1,i2)];const double aDD02_i0_i1p1_i2 = in_gfs[IDX4S(ADD02GF, i0,i1+1,i2)];const double aDD02_i0_i1p2_i2 = in_gfs[IDX4S(ADD02GF, i0,i1+2,i2)];const double aDD11_i0_i1m2_i2 = in_gfs[IDX4S(ADD11GF, i0,i1-2,i2)];const double aDD11_i0_i1m1_i2 = in_gfs[IDX4S(ADD11GF, i0,i1-1,i2)];const double aDD11_i0m2_i1_i2 = in_gfs[IDX4S(ADD11GF, i0-2,i1,i2)];const double aDD11_i0m1_i1_i2 = in_gfs[IDX4S(ADD11GF, i0-1,i1,i2)];const double aDD11 = in_gfs[IDX4S(ADD11GF, i0,i1,i2)];const double aDD11_i0p1_i1_i2 = in_gfs[IDX4S(ADD11GF, i0+1,i1,i2)];const double aDD11_i0p2_i1_i2 = in_gfs[IDX4S(ADD11GF, i0+2,i1,i2)];const double aDD11_i0_i1p1_i2 = in_gfs[IDX4S(ADD11GF, i0,i1+1,i2)];const double aDD11_i0_i1p2_i2 = in_gfs[IDX4S(ADD11GF, i0,i1+2,i2)];const double aDD12_i0_i1m2_i2 = in_gfs[IDX4S(ADD12GF, i0,i1-2,i2)];const double aDD12_i0_i1m1_i2 = in_gfs[IDX4S(ADD12GF, i0,i1-1,i2)];const double aDD12_i0m2_i1_i2 = in_gfs[IDX4S(ADD12GF, i0-2,i1,i2)];const double aDD12_i0m1_i1_i2 = in_gfs[IDX4S(ADD12GF, i0-1,i1,i2)];const double aDD12 = in_gfs[IDX4S(ADD12GF, i0,i1,i2)];const double aDD12_i0p1_i1_i2 = in_gfs[IDX4S(ADD12GF, i0+1,i1,i2)];const double aDD12_i0p2_i1_i2 = in_gfs[IDX4S(ADD12GF, i0+2,i1,i2)];const double aDD12_i0_i1p1_i2 = in_gfs[IDX4S(ADD12GF, i0,i1+1,i2)];const double aDD12_i0_i1p2_i2 = in_gfs[IDX4S(ADD12GF, i0,i1+2,i2)];const double aDD22_i0_i1m2_i2 = in_gfs[IDX4S(ADD22GF, i0,i1-2,i2)];const double aDD22_i0_i1m1_i2 = in_gfs[IDX4S(ADD22GF, i0,i1-1,i2)];const double aDD22_i0m2_i1_i2 = in_gfs[IDX4S(ADD22GF, i0-2,i1,i2)];const double aDD22_i0m1_i1_i2 = in_gfs[IDX4S(ADD22GF, i0-1,i1,i2)];const double aDD22 = in_gfs[IDX4S(ADD22GF, i0,i1,i2)];const double aDD22_i0p1_i1_i2 = in_gfs[IDX4S(ADD22GF, i0+1,i1,i2)];const double aDD22_i0p2_i1_i2 = in_gfs[IDX4S(ADD22GF, i0+2,i1,i2)];const double aDD22_i0_i1p1_i2 = in_gfs[IDX4S(ADD22GF, i0,i1+1,i2)];const double aDD22_i0_i1p2_i2 = in_gfs[IDX4S(ADD22GF, i0,i1+2,i2)];const double trK_i0_i1m2_i2 = in_gfs[IDX4S(TRKGF, i0,i1-2,i2)];const double trK_i0_i1m1_i2 = in_gfs[IDX4S(TRKGF, i0,i1-1,i2)];const double trK_i0m2_i1_i2 = in_gfs[IDX4S(TRKGF, i0-2,i1,i2)];const double trK_i0m1_i1_i2 = in_gfs[IDX4S(TRKGF, i0-1,i1,i2)];const double trK_i0p1_i1_i2 = in_gfs[IDX4S(TRKGF, i0+1,i1,i2)];const double trK_i0p2_i1_i2 = in_gfs[IDX4S(TRKGF, i0+2,i1,i2)];const double trK_i0_i1p1_i2 = in_gfs[IDX4S(TRKGF, i0,i1+1,i2)];const double trK_i0_i1p2_i2 = in_gfs[IDX4S(TRKGF, i0,i1+2,i2)];const double cf_i0_i1m2_i2 = in_gfs[IDX4S(CFGF, i0,i1-2,i2)];const double cf_i0_i1m1_i2 = in_gfs[IDX4S(CFGF, i0,i1-1,i2)];const double cf_i0m2_i1_i2 = in_gfs[IDX4S(CFGF, i0-2,i1,i2)];const double cf_i0m1_i1_i2 = in_gfs[IDX4S(CFGF, i0-1,i1,i2)];const double cf = in_gfs[IDX4S(CFGF, i0,i1,i2)];const double cf_i0p1_i1_i2 = in_gfs[IDX4S(CFGF, i0+1,i1,i2)];const double cf_i0p2_i1_i2 = in_gfs[IDX4S(CFGF, i0+2,i1,i2)];const double cf_i0_i1p1_i2 = in_gfs[IDX4S(CFGF, i0,i1+1,i2)];const double cf_i0_i1p2_i2 = in_gfs[IDX4S(CFGF, i0,i1+2,i2)];const double aDD_dD000 = invdx0*(-2.0/3.0*aDD00_i0m1_i1_i2 + (1.0/12.0)*aDD00_i0m2_i1_i2 + (2.0/3.0)*aDD00_i0p1_i1_i2 - 1.0/12.0*aDD00_i0p2_i1_i2);const double aDD_dD001 = invdx1*(-2.0/3.0*aDD00_i0_i1m1_i2 + (1.0/12.0)*aDD00_i0_i1m2_i2 + (2.0/3.0)*aDD00_i0_i1p1_i2 - 1.0/12.0*aDD00_i0_i1p2_i2);const double aDD_dD010 = invdx0*(-2.0/3.0*aDD01_i0m1_i1_i2 + (1.0/12.0)*aDD01_i0m2_i1_i2 + (2.0/3.0)*aDD01_i0p1_i1_i2 - 1.0/12.0*aDD01_i0p2_i1_i2);const double aDD_dD011 = invdx1*(-2.0/3.0*aDD01_i0_i1m1_i2 + (1.0/12.0)*aDD01_i0_i1m2_i2 + (2.0/3.0)*aDD01_i0_i1p1_i2 - 1.0/12.0*aDD01_i0_i1p2_i2);const double aDD_dD020 = invdx0*(-2.0/3.0*aDD02_i0m1_i1_i2 + (1.0/12.0)*aDD02_i0m2_i1_i2 + (2.0/3.0)*aDD02_i0p1_i1_i2 - 1.0/12.0*aDD02_i0p2_i1_i2);const double aDD_dD021 = invdx1*(-2.0/3.0*aDD02_i0_i1m1_i2 + (1.0/12.0)*aDD02_i0_i1m2_i2 + (2.0/3.0)*aDD02_i0_i1p1_i2 - 1.0/12.0*aDD02_i0_i1p2_i2);const double aDD_dD110 = invdx0*(-2.0/3.0*aDD11_i0m1_i1_i2 + (1.0/12.0)*aDD11_i0m2_i1_i2 + (2.0/3.0)*aDD11_i0p1_i1_i2 - 1.0/12.0*aDD11_i0p2_i1_i2);const double aDD_dD111 = invdx1*(-2.0/3.0*aDD11_i0_i1m1_i2 + (1.0/12.0)*aDD11_i0_i1m2_i2 + (2.0/3.0)*aDD11_i0_i1p1_i2 - 1.0/12.0*aDD11_i0_i1p2_i2);const double aDD_dD120 = invdx0*(-2.0/3.0*aDD12_i0m1_i1_i2 + (1.0/12.0)*aDD12_i0m2_i1_i2 + (2.0/3.0)*aDD12_i0p1_i1_i2 - 1.0/12.0*aDD12_i0p2_i1_i2);const double aDD_dD121 = invdx1*(-2.0/3.0*aDD12_i0_i1m1_i2 + (1.0/12.0)*aDD12_i0_i1m2_i2 + (2.0/3.0)*aDD12_i0_i1p1_i2 - 1.0/12.0*aDD12_i0_i1p2_i2);const double aDD_dD220 = invdx0*(-2.0/3.0*aDD22_i0m1_i1_i2 + (1.0/12.0)*aDD22_i0m2_i1_i2 + (2.0/3.0)*aDD22_i0p1_i1_i2 - 1.0/12.0*aDD22_i0p2_i1_i2);const double aDD_dD221 = invdx1*(-2.0/3.0*aDD22_i0_i1m1_i2 + (1.0/12.0)*aDD22_i0_i1m2_i2 + (2.0/3.0)*aDD22_i0_i1p1_i2 - 1.0/12.0*aDD22_i0_i1p2_i2);const double cf_dD0 = invdx0*(-2.0/3.0*cf_i0m1_i1_i2 + (1.0/12.0)*cf_i0m2_i1_i2 + (2.0/3.0)*cf_i0p1_i1_i2 - 1.0/12.0*cf_i0p2_i1_i2);const double cf_dD1 = invdx1*(-2.0/3.0*cf_i0_i1m1_i2 + (1.0/12.0)*cf_i0_i1m2_i2 + (2.0/3.0)*cf_i0_i1p1_i2 - 1.0/12.0*cf_i0_i1p2_i2);const double hDD_dD000 = invdx0*(-2.0/3.0*hDD00_i0m1_i1_i2 + (1.0/12.0)*hDD00_i0m2_i1_i2 + (2.0/3.0)*hDD00_i0p1_i1_i2 - 1.0/12.0*hDD00_i0p2_i1_i2);const double hDD_dD001 = invdx1*(-2.0/3.0*hDD00_i0_i1m1_i2 + (1.0/12.0)*hDD00_i0_i1m2_i2 + (2.0/3.0)*hDD00_i0_i1p1_i2 - 1.0/12.0*hDD00_i0_i1p2_i2);const double hDD_dD010 = invdx0*(-2.0/3.0*hDD01_i0m1_i1_i2 + (1.0/12.0)*hDD01_i0m2_i1_i2 + (2.0/3.0)*hDD01_i0p1_i1_i2 - 1.0/12.0*hDD01_i0p2_i1_i2);const double hDD_dD011 = invdx1*(-2.0/3.0*hDD01_i0_i1m1_i2 + (1.0/12.0)*hDD01_i0_i1m2_i2 + (2.0/3.0)*hDD01_i0_i1p1_i2 - 1.0/12.0*hDD01_i0_i1p2_i2);const double hDD_dD020 = invdx0*(-2.0/3.0*hDD02_i0m1_i1_i2 + (1.0/12.0)*hDD02_i0m2_i1_i2 + (2.0/3.0)*hDD02_i0p1_i1_i2 - 1.0/12.0*hDD02_i0p2_i1_i2);const double hDD_dD021 = invdx1*(-2.0/3.0*hDD02_i0_i1m1_i2 + (1.0/12.0)*hDD02_i0_i1m2_i2 + (2.0/3.0)*hDD02_i0_i1p1_i2 - 1.0/12.0*hDD02_i0_i1p2_i2);const double hDD_dD110 = invdx0*(-2.0/3.0*hDD11_i0m1_i1_i2 + (1.0/12.0)*hDD11_i0m2_i1_i2 + (2.0/3.0)*hDD11_i0p1_i1_i2 - 1.0/12.0*hDD11_i0p2_i1_i2);const double hDD_dD111 = invdx1*(-2.0/3.0*hDD11_i0_i1m1_i2 + (1.0/12.0)*hDD11_i0_i1m2_i2 + (2.0/3.0)*hDD11_i0_i1p1_i2 - 1.0/12.0*hDD11_i0_i1p2_i2);const double hDD_dD120 = invdx0*(-2.0/3.0*hDD12_i0m1_i1_i2 + (1.0/12.0)*hDD12_i0m2_i1_i2 + (2.0/3.0)*hDD12_i0p1_i1_i2 - 1.0/12.0*hDD12_i0p2_i1_i2);const double hDD_dD121 = invdx1*(-2.0/3.0*hDD12_i0_i1m1_i2 + (1.0/12.0)*hDD12_i0_i1m2_i2 + (2.0/3.0)*hDD12_i0_i1p1_i2 - 1.0/12.0*hDD12_i0_i1p2_i2);const double hDD_dD220 = invdx0*(-2.0/3.0*hDD22_i0m1_i1_i2 + (1.0/12.0)*hDD22_i0m2_i1_i2 + (2.0/3.0)*hDD22_i0p1_i1_i2 - 1.0/12.0*hDD22_i0p2_i1_i2);const double hDD_dD221 = invdx1*(-2.0/3.0*hDD22_i0_i1m1_i2 + (1.0/12.0)*hDD22_i0_i1m2_i2 + (2.0/3.0)*hDD22_i0_i1p1_i2 - 1.0/12.0*hDD22_i0_i1p2_i2);const double trK_dD0 = invdx0*(-2.0/3.0*trK_i0m1_i1_i2 + (1.0/12.0)*trK_i0m2_i1_i2 + (2.0/3.0)*trK_i0p1_i1_i2 - 1.0/12.0*trK_i0p2_i1_i2);const double trK_dD1 = invdx1*(-2.0/3.0*trK_i0_i1m1_i2 + (1.0/12.0)*trK_i0_i1m2_i2 + (2.0/3.0)*trK_i0_i1p1_i2 - 1.0/12.0*trK_i0_i1p2_i2);/** NRPy+ Finite Difference Code Generation, Step 2 of 2: Evaluate SymPy expressions and write to main memory:*/const double tmp0 = ((cf)*(cf));const double tmp1 = sin(xx1);const double tmp2 = ((tmp1)*(tmp1));const double tmp3 = hDD12*((xx0)*(xx0)*(xx0));const double tmp4 = ((xx0)*(xx0));const double tmp5 = tmp2*tmp4;const double tmp6 = hDD22*tmp5 + tmp5;const double tmp7 = -hDD01*tmp6*xx0 + hDD02*tmp2*tmp3;const double tmp8 = 2*hDD01;const double tmp9 = tmp2*((xx0)*(xx0)*(xx0)*(xx0));const double tmp10 = hDD00 + 1;const double tmp11 = ((hDD12)*(hDD12))*tmp9;const double tmp12 = hDD11*tmp4 + tmp4;const double tmp13 = ((hDD02)*(hDD02))*tmp5;const double tmp14 = ((hDD01)*(hDD01))*tmp4;const double tmp15 = tmp12*tmp6;const double tmp16 = hDD02*hDD12*tmp8*tmp9 - tmp10*tmp11 + tmp10*tmp15 - tmp12*tmp13 - tmp14*tmp6;const double tmp17 = (1.0/(tmp16));const double tmp18 = (2.0/3.0)*tmp17;const double tmp19 = tmp18*trK_dD1;const double tmp20 = -tmp11 + tmp15;const double tmp21 = tmp18*trK_dD0;const double tmp22 = (1.0/((tmp16)*(tmp16)));const double tmp23 = hDD02*tmp1;const double tmp24 = hDD01*tmp1*tmp3 - tmp12*tmp23*xx0;const double tmp25 = tmp22*((tmp24)*(tmp24));const double tmp26 = aDD22*tmp5;const double tmp27 = 6*tmp26;const double tmp28 = aDD11*tmp4;const double tmp29 = tmp22*((tmp7)*(tmp7));const double tmp30 = 6*tmp29;const double tmp31 = ((tmp20)*(tmp20))*tmp22;const double tmp32 = 6*aDD00;const double tmp33 = tmp22*tmp7;const double tmp34 = tmp24*tmp33;const double tmp35 = tmp1*tmp4;const double tmp36 = aDD12*tmp35;const double tmp37 = 12*tmp36;const double tmp38 = tmp20*tmp22;const double tmp39 = tmp24*tmp38;const double tmp40 = aDD02*tmp1;const double tmp41 = tmp40*xx0;const double tmp42 = 12*tmp41;const double tmp43 = tmp38*tmp7;const double tmp44 = aDD01*xx0;const double tmp45 = 12*tmp44;const double tmp46 = (1.0/2.0)/cf;const double tmp47 = cf_dD0*tmp46;const double tmp48 = 2*xx0;const double tmp49 = tmp2*tmp48;const double tmp50 = hDD01*tmp23*tmp4 - hDD12*tmp10*tmp35;const double tmp51 = cos(xx1);const double tmp52 = tmp51*xx0;const double tmp53 = hDD02*tmp52;const double tmp54 = tmp1*xx0;const double tmp55 = hDD_dD021*tmp54;const double tmp56 = hDD_dD120*tmp35;const double tmp57 = tmp1*tmp48;const double tmp58 = hDD12*tmp57;const double tmp59 = tmp56 + tmp58;const double tmp60 = (1.0/2.0)*tmp17;const double tmp61 = tmp60*(-tmp53 - tmp55 + tmp59);const double tmp62 = tmp10*tmp12 - tmp14;const double tmp63 = hDD22*tmp49;const double tmp64 = hDD_dD220*tmp5;const double tmp65 = tmp60*(tmp49 + tmp63 + tmp64);const double tmp66 = -tmp50*tmp61 - tmp62*tmp65;const double tmp67 = tmp26*tmp66;const double tmp68 = -tmp24*tmp65 - tmp61*tmp7;const double tmp69 = tmp40*tmp48;const double tmp70 = tmp10*tmp6 - tmp13;const double tmp71 = -tmp50*tmp65 - tmp61*tmp70;const double tmp72 = 2*tmp35;const double tmp73 = aDD12*tmp72;const double tmp74 = aDD22*tmp49 + aDD_dD220*tmp5 + 2*tmp67 + tmp68*tmp69 + tmp71*tmp73;const double tmp75 = aDD01*tmp48;const double tmp76 = aDD00*tmp68;const double tmp77 = tmp66*tmp69 + tmp71*tmp75 + 2*tmp76;const double tmp78 = tmp24*tmp77;const double tmp79 = tmp53 + tmp55;const double tmp80 = tmp60*(-tmp56 - tmp58 + tmp79);const double tmp81 = tmp4*sin(2*xx1);const double tmp82 = hDD_dD221*tmp5;const double tmp83 = tmp51*tmp72;const double tmp84 = hDD22*tmp83;const double tmp85 = tmp60*(tmp81 + tmp82 + tmp84);const double tmp86 = -tmp24*tmp80 - tmp62*tmp85;const double tmp87 = -tmp50*tmp85 - tmp7*tmp80;const double tmp88 = tmp28*tmp87;const double tmp89 = -tmp20*tmp80 - tmp24*tmp85;const double tmp90 = tmp73*tmp86 + tmp75*tmp89 + 2*tmp88;const double tmp91 = tmp50*tmp90;const double tmp92 = tmp26*tmp86;const double tmp93 = aDD22*tmp83 + aDD_dD221*tmp5 + tmp69*tmp89 + tmp73*tmp87 + 2*tmp92;const double tmp94 = tmp50*tmp93;const double tmp95 = tmp22*tmp24;const double tmp96 = tmp60*(-tmp81 - tmp82 - tmp84);const double tmp97 = tmp60*(-tmp49 - tmp63 - tmp64);const double tmp98 = -tmp24*tmp97 - tmp50*tmp96;const double tmp99 = -tmp7*tmp97 - tmp70*tmp96;const double tmp100 = -tmp20*tmp97 - tmp7*tmp96;const double tmp101 = tmp22*(tmp100*tmp69 + 2*tmp26*tmp98 + tmp73*tmp99);const double tmp102 = tmp101*tmp62;const double tmp103 = hDD_dD000*tmp60;const double tmp104 = tmp60*(-hDD_dD001 + hDD_dD010*tmp48 + tmp8);const double tmp105 = tmp60*(hDD_dD020*tmp57 + 2*tmp23);const double tmp106 = -tmp103*tmp24 - tmp104*tmp50 - tmp105*tmp62;const double tmp107 = -tmp103*tmp7 - tmp104*tmp70 - tmp105*tmp50;const double tmp108 = -tmp103*tmp20 - tmp104*tmp7 - tmp105*tmp24;const double tmp109 = 2*aDD00*tmp108 + aDD_dD000 + tmp106*tmp69 + tmp107*tmp75;const double tmp110 = hDD_dD001*tmp60;const double tmp111 = hDD11*tmp48;const double tmp112 = hDD_dD110*tmp4;const double tmp113 = tmp60*(tmp111 + tmp112 + tmp48);const double tmp114 = tmp60*(tmp59 + tmp79);const double tmp115 = -tmp110*tmp24 - tmp113*tmp50 - tmp114*tmp62;const double tmp116 = -tmp110*tmp7 - tmp113*tmp70 - tmp114*tmp50;const double tmp117 = tmp116*tmp28;const double tmp118 = -tmp110*tmp20 - tmp113*tmp7 - tmp114*tmp24;const double tmp119 = aDD11*tmp48 + aDD_dD110*tmp4 + tmp115*tmp73 + 2*tmp117 + tmp118*tmp75;const double tmp120 = aDD00*tmp118;const double tmp121 = aDD_dD001 + tmp115*tmp69 + tmp116*tmp75 + 2*tmp120;const double tmp122 = tmp50*tmp95;const double tmp123 = tmp33*tmp50;const double tmp124 = 6*tmp36;const double tmp125 = 6*tmp41;const double tmp126 = tmp38*tmp50;const double tmp127 = tmp22*tmp70;const double tmp128 = tmp127*tmp24;const double tmp129 = tmp127*tmp7;const double tmp130 = 6*tmp28;const double tmp131 = tmp127*tmp20;const double tmp132 = 6*tmp44;const double tmp133 = tmp122*tmp27 + tmp123*tmp124 + tmp124*tmp128 + tmp125*tmp126 + tmp125*tmp34 + tmp129*tmp130 + tmp131*tmp132 + tmp30*tmp44 + tmp32*tmp43;const double tmp134 = cf_dD1*tmp46;const double tmp135 = hDD_dD111*tmp4*tmp60;const double tmp136 = tmp4*tmp51;const double tmp137 = tmp60*(2*hDD12*tmp136 + hDD_dD121*tmp72);const double tmp138 = tmp60*(hDD_dD011*tmp48 - tmp111 - tmp112 - tmp48);const double tmp139 = -tmp135*tmp50 - tmp137*tmp62 - tmp138*tmp24;const double tmp140 = -tmp135*tmp70 - tmp137*tmp50 - tmp138*tmp7;const double tmp141 = -tmp135*tmp7 - tmp137*tmp24 - tmp138*tmp20;const double tmp142 = tmp22*(aDD_dD111*tmp4 + tmp139*tmp73 + 2*tmp140*tmp28 + tmp141*tmp75);const double tmp143 = tmp142*tmp70;const double tmp144 = aDD00*tmp89 + tmp41*tmp86 + tmp44*tmp87;const double tmp145 = tmp28*tmp71 + tmp36*tmp66 + tmp44*tmp68;const double tmp146 = tmp144 + tmp145;const double tmp147 = aDD00*tmp100 + tmp36*tmp71 + tmp41*tmp68 + tmp41*tmp98 + tmp44*tmp99 + tmp67;const double tmp148 = tmp22*tmp62;const double tmp149 = tmp147*tmp148;const double tmp150 = tmp100*tmp44 + tmp28*tmp99 + tmp36*tmp87 + tmp36*tmp98 + tmp41*tmp89 + tmp92;const double tmp151 = tmp148*tmp150;const double tmp152 = aDD_dD020*tmp54 + tmp106*tmp26 + tmp107*tmp36 + tmp108*tmp41 + tmp40 + tmp41*tmp66 + tmp44*tmp71 + tmp76;const double tmp153 = tmp115*tmp26 + tmp116*tmp36 + tmp118*tmp41;const double tmp154 = aDD12*tmp57 + aDD_dD120*tmp35 + tmp145 + tmp153;const double tmp155 = aDD02*tmp52 + aDD_dD021*tmp54 + tmp144 + tmp153;const double tmp156 = aDD12*tmp136 + aDD_dD121*tmp35 + tmp139*tmp26 + tmp140*tmp36 + tmp141*tmp41 + tmp36*tmp86 + tmp44*tmp89 + tmp88;const double tmp157 = aDD01 + aDD_dD010*xx0 + tmp106*tmp36 + tmp107*tmp28 + tmp108*tmp44 + tmp115*tmp41 + tmp116*tmp44 + tmp120;const double tmp158 = aDD00*tmp141 + aDD_dD011*xx0 + tmp115*tmp36 + tmp117 + tmp118*tmp44 + tmp139*tmp41 + tmp140*tmp44;const double tmp159 = tmp22*((tmp50)*(tmp50));const double tmp160 = ((tmp70)*(tmp70));const double tmp161 = tmp127*tmp50;const double tmp162 = 2*tmp50;const double tmp163 = tmp148*tmp24;const double tmp164 = tmp148*tmp7;const double tmp165 = tmp148*tmp70;const double tmp166 = tmp148*tmp20;aux_gfs[IDX4S(MU0GF, i0, i1, i2)] = tmp0*(tmp102*tmp24 + tmp109*tmp31 + tmp119*tmp29 + tmp121*tmp43 + tmp122*tmp150 + tmp123*tmp156 + tmp126*tmp146 + tmp126*tmp155 + tmp128*tmp156 + tmp131*tmp158 - tmp133*tmp134 + tmp143*tmp7 + tmp146*tmp34 + tmp147*tmp25 + tmp149*tmp20 + tmp151*tmp7 + 2*tmp152*tmp39 + 2*tmp154*tmp34 + tmp155*tmp34 + 2*tmp157*tmp43 + tmp158*tmp29 - tmp19*tmp7 - tmp20*tmp21 + tmp25*tmp74 + tmp33*tmp91 + tmp38*tmp78 - tmp47*(tmp25*tmp27 + tmp28*tmp30 + tmp31*tmp32 + tmp34*tmp37 + tmp39*tmp42 + tmp43*tmp45) + tmp94*tmp95);aux_gfs[IDX4S(MU1GF, i0, i1, i2)] = tmp0*xx0*(tmp102*tmp50 + tmp109*tmp43 + tmp119*tmp129 + tmp121*tmp29 + tmp122*tmp147 + tmp122*tmp74 + tmp123*tmp146 + tmp123*tmp154 + 2*tmp123*tmp155 + tmp126*tmp152 + tmp127*tmp156*tmp162 + tmp127*tmp91 + tmp128*tmp146 + tmp128*tmp154 + 2*tmp129*tmp158 + tmp131*tmp157 - tmp133*tmp47 - tmp134*(tmp123*tmp42 + tmp129*tmp45 + tmp130*tmp160*tmp22 + tmp159*tmp27 + tmp161*tmp37 + tmp29*tmp32) + tmp142*tmp160 + tmp149*tmp7 + tmp150*tmp159 + tmp151*tmp70 + tmp152*tmp34 + tmp157*tmp29 + tmp159*tmp93 - tmp19*tmp70 - tmp21*tmp7 + tmp33*tmp78);aux_gfs[IDX4S(MU2GF, i0, i1, i2)] = tmp0*tmp54*(tmp101*((tmp62)*(tmp62)) + tmp109*tmp39 + tmp119*tmp123 + tmp121*tmp34 + 2*tmp122*tmp146 + tmp122*tmp154 + tmp122*tmp155 + tmp123*tmp158 + tmp126*tmp157 + tmp128*tmp158 - tmp134*(tmp122*tmp125 + tmp123*tmp132 + tmp124*tmp159 + tmp124*tmp165 + tmp125*tmp164 + tmp128*tmp132 + tmp130*tmp161 + tmp148*tmp27*tmp50 + tmp32*tmp34) + tmp143*tmp50 + tmp148*tmp94 + 2*tmp149*tmp24 + tmp151*tmp162 + tmp152*tmp166 + tmp152*tmp25 + tmp154*tmp164 + tmp155*tmp164 + tmp156*tmp159 + tmp156*tmp165 + tmp157*tmp34 + tmp159*tmp90 + tmp163*tmp74 - tmp19*tmp50 - tmp21*tmp24 + tmp25*tmp77 - tmp47*(tmp122*tmp124 + tmp123*tmp130 + tmp124*tmp164 + tmp125*tmp166 + tmp125*tmp25 + tmp126*tmp132 + tmp132*tmp34 + tmp163*tmp27 + tmp32*tmp39));}} // END LOOP: for(int i0=NGHOSTS; i0<NGHOSTS+Nxx0; i0++)} // END LOOP: for(int i1=NGHOSTS; i1<NGHOSTS+Nxx1; i1++)} // END LOOP: for(int i2=NGHOSTS; i2<NGHOSTS+Nxx2; i2++)}
const int Nxx0 = params->Nxx0;const int Nxx1 = params->Nxx1;const int Nxx2 = params->Nxx2;const int Nxx_plus_2NGHOSTS0 = params->Nxx_plus_2NGHOSTS0;const int Nxx_plus_2NGHOSTS1 = params->Nxx_plus_2NGHOSTS1;const int Nxx_plus_2NGHOSTS2 = params->Nxx_plus_2NGHOSTS2;const REAL NOSIMDdxx0 = params->dxx0;const REAL_SIMD_ARRAY dxx0 = ConstSIMD(NOSIMDdxx0);const REAL NOSIMDdxx1 = params->dxx1;const REAL_SIMD_ARRAY dxx1 = ConstSIMD(NOSIMDdxx1);const REAL NOSIMDdxx2 = params->dxx2;const REAL_SIMD_ARRAY dxx2 = ConstSIMD(NOSIMDdxx2);const REAL NOSIMDinvdx0 = params->invdx0;const REAL_SIMD_ARRAY invdx0 = ConstSIMD(NOSIMDinvdx0);const REAL NOSIMDinvdx1 = params->invdx1;const REAL_SIMD_ARRAY invdx1 = ConstSIMD(NOSIMDinvdx1);const REAL NOSIMDinvdx2 = params->invdx2;const REAL_SIMD_ARRAY invdx2 = ConstSIMD(NOSIMDinvdx2);const REAL NOSIMDRMAX = params->RMAX;const REAL_SIMD_ARRAY RMAX = ConstSIMD(NOSIMDRMAX);const REAL NOSIMDM = params->M;const REAL_SIMD_ARRAY M = ConstSIMD(NOSIMDM);const REAL NOSIMDa = params->a;const REAL_SIMD_ARRAY a = ConstSIMD(NOSIMDa);const REAL NOSIMDr0 = params->r0;const REAL_SIMD_ARRAY r0 = ConstSIMD(NOSIMDr0);
const int Nxx0 = params.Nxx0;const int Nxx1 = params.Nxx1;const int Nxx2 = params.Nxx2;const int Nxx_plus_2NGHOSTS0 = params.Nxx_plus_2NGHOSTS0;const int Nxx_plus_2NGHOSTS1 = params.Nxx_plus_2NGHOSTS1;const int Nxx_plus_2NGHOSTS2 = params.Nxx_plus_2NGHOSTS2;const REAL dxx0 = params.dxx0;const REAL dxx1 = params.dxx1;const REAL dxx2 = params.dxx2;const REAL invdx0 = params.invdx0;const REAL invdx1 = params.invdx1;const REAL invdx2 = params.invdx2;const REAL RMAX = params.RMAX;const REAL M = params.M;const REAL a = params.a;const REAL r0 = params.r0;
const int Nxx0 = params->Nxx0;const int Nxx1 = params->Nxx1;const int Nxx2 = params->Nxx2;const int Nxx_plus_2NGHOSTS0 = params->Nxx_plus_2NGHOSTS0;const int Nxx_plus_2NGHOSTS1 = params->Nxx_plus_2NGHOSTS1;const int Nxx_plus_2NGHOSTS2 = params->Nxx_plus_2NGHOSTS2;const REAL dxx0 = params->dxx0;const REAL dxx1 = params->dxx1;const REAL dxx2 = params->dxx2;const REAL invdx0 = params->invdx0;const REAL invdx1 = params->invdx1;const REAL invdx2 = params->invdx2;const REAL RMAX = params->RMAX;const REAL M = params->M;const REAL a = params->a;const REAL r0 = params->r0;
params.Nxx0 = 64;params.Nxx1 = 32;params.Nxx2 = 64;params.Nxx_plus_2NGHOSTS0 = 70;params.Nxx_plus_2NGHOSTS1 = 38;params.Nxx_plus_2NGHOSTS2 = 70;params.xx0 = 1e+300;params.xx1 = 1e+300;params.xx2 = 1e+300;params.dxx0 = 0.1;params.dxx1 = 0.1;params.dxx2 = 0.1;params.invdx0 = 1.0;params.invdx1 = 1.0;params.invdx2 = 1.0;params.f0_of_xx0 = 1e+300;params.f1_of_xx1 = 1e+300;params.f2_of_xx0_xx1 = 1e+300;params.f3_of_xx0 = 1e+300;params.f4_of_xx2 = 1e+300;params.f0_of_xx0__D0 = 1e+300;params.f0_of_xx0__DD00 = 1e+300;params.f0_of_xx0__DDD000 = 1e+300;params.f1_of_xx1__D1 = 1e+300;params.f1_of_xx1__DD11 = 1e+300;params.f1_of_xx1__DDD111 = 1e+300;params.f2_of_xx0_xx1__D0 = 1e+300;params.f2_of_xx0_xx1__D1 = 1e+300;params.f2_of_xx0_xx1__DD00 = 1e+300;params.f2_of_xx0_xx1__DD11 = 1e+300;params.f3_of_xx0__D0 = 1e+300;params.f3_of_xx0__DD00 = 1e+300;params.f4_of_xx2__D2 = 1e+300;params.f4_of_xx2__DD22 = 1e+300;params.RMAX = 10.0;params.M = 1.0;params.a = 0.9;params.r0 = 1.0;
void set_Nxx_dxx_invdx_params__and__xx(const int EigenCoord, const int Nxx[3],paramstruct *restrict params, REAL *restrict xx[3]) {// Override parameter defaults with values based on command line arguments and NGHOSTS.params->Nxx0 = Nxx[0];params->Nxx1 = Nxx[1];params->Nxx2 = Nxx[2];params->Nxx_plus_2NGHOSTS0 = Nxx[0] + 2*NGHOSTS;params->Nxx_plus_2NGHOSTS1 = Nxx[1] + 2*NGHOSTS;params->Nxx_plus_2NGHOSTS2 = Nxx[2] + 2*NGHOSTS;// Step 0d: Set up space and time coordinates// Step 0d.i: Declare \Delta x^i=dxx{0,1,2} and invdxx{0,1,2}, as well as xxmin[3] and xxmax[3]:#include "set_Cparameters.h"REAL xxmin[3],xxmax[3];if(EigenCoord == 0) {xxmin[0] = 0;xxmax[0] = RMAX;xxmin[1] = 0;xxmax[1] = M_PI;xxmin[2] = -M_PI;xxmax[2] = M_PI;} else if (EigenCoord == 1) {xxmin[0] = 0;xxmax[0] = RMAX;xxmin[1] = 0;xxmax[1] = M_PI;xxmin[2] = -M_PI;xxmax[2] = M_PI;}params->dxx0 = (xxmax[0] - xxmin[0]) / ((REAL)Nxx[0]);params->dxx1 = (xxmax[1] - xxmin[1]) / ((REAL)Nxx[1]);params->dxx2 = (xxmax[2] - xxmin[2]) / ((REAL)Nxx[2]);params->invdx0 = 1.0/params->dxx0;params->invdx1 = 1.0/params->dxx1;params->invdx2 = 1.0/params->dxx2;// Now that params.dxx{0,1,2} and params.invdxx{0,1,2} have been set,// Step 0d.iii: Set up uniform coordinate gridsxx[0] = (REAL *)malloc(sizeof(REAL)*Nxx_plus_2NGHOSTS0);for(int j=0;j<Nxx_plus_2NGHOSTS0;j++)xx[0][j] = xxmin[0] + ((REAL)(j-NGHOSTS) + (1.0/2.0))*params->dxx0; // Cell-centered grid.xx[1] = (REAL *)malloc(sizeof(REAL)*Nxx_plus_2NGHOSTS1);for(int j=0;j<Nxx_plus_2NGHOSTS1;j++)xx[1][j] = xxmin[1] + ((REAL)(j-NGHOSTS) + (1.0/2.0))*params->dxx1; // Cell-centered grid.xx[2] = (REAL *)malloc(sizeof(REAL)*Nxx_plus_2NGHOSTS2);for(int j=0;j<Nxx_plus_2NGHOSTS2;j++)xx[2][j] = xxmin[2] + ((REAL)(j-NGHOSTS) + (1.0/2.0))*params->dxx2; // Cell-centered grid.//fprintf(stderr,"hey inside setxx: %e %e %e | %e %e\n",xxmin[0],xxmin[1],xxmin[2],xx[0][0],params->dxx0);}
inline void xxCart(const paramstruct *restrict params, REAL *restrict xx[3],const int i0,const int i1,const int i2, REAL xCart[3]) {#include "./set_Cparameters.h"REAL xx0 = xx[0][i0];REAL xx1 = xx[1][i1];REAL xx2 = xx[2][i2];/** Original SymPy expressions:* "[xCart[0] = xx0*sin(xx1)*cos(xx2),* xCart[1] = xx0*sin(xx1)*sin(xx2),* xCart[2] = xx0*cos(xx1)]"*/{const double tmp0 = xx0*sin(xx1);xCart[0] = tmp0*cos(xx2);xCart[1] = tmp0*sin(xx2);xCart[2] = xx0*cos(xx1);}}
{"cells": [{"cell_type": "markdown","metadata": {},"source": ["<script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-59152712-8\"></script>\n","<script>\n"," window.dataLayer = window.dataLayer || [];\n"," function gtag(){dataLayer.push(arguments);}\n"," gtag('js', new Date());\n","\n"," gtag('config', 'UA-59152712-8');\n","</script>\n","\n","# Start-to-Finish Example: Setting up Exact Initial Data for Einstein's Equations, in Curvilinear Coordinates\n","## Authors: Brandon Clark, George Vopal, and Zach Etienne\n","\n","## This module sets up initial data for a specified exact solution written in terms of ADM variables, using the [*Exact* ADM Spherical to BSSN Curvilinear initial data module](../edit/BSSN/ADM_Exact_Spherical_or_Cartesian_to_BSSNCurvilinear.py).\n","\n","**Notebook Status:** <font color='green'><b> Validated </b></font>\n","\n","**Validation Notes:** This module has been validated, confirming that all initial data sets exhibit convergence to zero of the Hamiltonian and momentum constraints at the expected rate or better.\n","\n","### NRPy+ Source Code for this module:\n","* [BSSN/ADM_Exact_Spherical_or_Cartesian_to_BSSNCurvilinear.py](../edit/BSSN/ADM_Exact_Spherical_or_Cartesian_to_BSSNCurvilinear.py); [\\[**tutorial**\\]](Tutorial-ADM_Initial_Data-Converting_Exact_ADM_Spherical_or_Cartesian_to_BSSNCurvilinear.ipynb): *Exact* Spherical ADM$\\to$Curvilinear BSSN converter function\n","* [BSSN/BSSN_constraints.py](../edit/BSSN/BSSN_constraints.py); [\\[**tutorial**\\]](Tutorial-BSSN_constraints.ipynb): Hamiltonian & momentum constraints in BSSN curvilinear basis/coordinates\n","\n","## Introduction:\n","Here we use NRPy+ to generate a C code confirming that specified *exact* initial data satisfy Einstein's equations of general relativity. The following exact initial data types are supported:\n","\n","* Shifted Kerr-Schild spinning black hole initial data\n","* \"Static\" Trumpet black hole initial data\n","* Brill-Lindquist two black hole initial data\n","* UIUC black hole initial data"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='toc'></a>\n","\n","# Table of Contents\n","$$\\label{toc}$$\n","\n","This notebook is organized as follows\n","\n","0. [Preliminaries](#prelim): The Choices for Initial Data\n"," 1. [Choice 1](#sks): Shifted Kerr-Schild spinning black hole initial data\n"," 1. [Choice 2](#st): \"Static\" Trumpet black hole initial data\n"," 1. [Choice 3](#bl): Brill-Lindquist two black hole initial data\n"," 1. [Choice 4](#uiuc): UIUC black hole initial data\n","1. [Step 2](#initializenrpy): Set core NRPy+ parameters for numerical grids and reference metric\n","1. [Step 3](#adm_id): Import Black Hole ADM initial data C function from NRPy+ module\n","1. [Step 4](#validate): Validating that the black hole initial data satisfy the Hamiltonian constraint\n"," 1. [Step 4.a](#ham_const_output): Output C code for evaluating the Hamiltonian and Momentum constraint violation\n"," 1. [Step 4.b](#apply_bcs): Apply singular, curvilinear coordinate boundary conditions\n"," 1. [Step 4.c](#enforce3metric): Enforce conformal 3-metric $\\det{\\bar{\\gamma}_{ij}}=\\det{\\hat{\\gamma}_{ij}}$ constraint\n","1. [Step 5](#mainc): `Initial_Data.c`: The Main C Code\n","1. [Step 6](#plot): Plotting the initial data\n","1. [Step 7](#convergence): Validation: Convergence of numerical errors (Hamiltonian constraint violation) to zero\n","1. [Step 8](#latex_pdf_output): Output this notebook to $\\LaTeX$-formatted PDF file"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='prelim'></a>\n","\n","# Preliminaries: The Choices for Initial Data\n","$$\\label{prelim}$$"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='sks'></a>\n","\n","## Shifted Kerr-Schild spinning black hole initial data \\[Back to [top](#toc)\\]\n","$$\\label{sks}$$\n","\n","Here we use NRPy+ to generate initial data for a spinning black hole.\n","\n","Shifted Kerr-Schild spinning black hole initial data has been <font color='green'><b> validated </b></font> to exhibit convergence to zero of both the Hamiltonian and momentum constraint violations at the expected order to the exact solution.\n","\n","**NRPy+ Source Code:**\n","* [BSSN/ShiftedKerrSchild.py](../edit/BSSN/ShiftedKerrSchild.py); [\\[**tutorial**\\]](Tutorial-ADM_Initial_Data-ShiftedKerrSchild.ipynb)\n","\n","The [BSSN.ShiftedKerrSchild](../edit/BSSN/ShiftedKerrSchild.py) NRPy+ module does the following:\n","\n","1. Set up shifted Kerr-Schild initial data, represented by [ADM](https://en.wikipedia.org/wiki/ADM_formalism) quantities in the **Spherical basis**, as [documented here](Tutorial-ADM_Initial_Data-ShiftedKerrSchild.ipynb). \n","1. Convert the exact ADM **Spherical quantities** to **BSSN quantities in the desired Curvilinear basis** (set by `reference_metric::CoordSystem`), as [documented here](Tutorial-ADM_Initial_Data-Converting_Numerical_ADM_Spherical_or_Cartesian_to_BSSNCurvilinear.ipynb).\n","1. Sets up the standardized C function for setting all BSSN Curvilinear gridfunctions in a pointwise fashion, as [written here](../edit/BSSN/BSSN_ID_function_string.py), and returns the C function as a Python string."]},{"cell_type": "markdown","metadata": {},"source": ["<a id='st'></a>\n","\n","## \"Static\" Trumpet black hole initial data \\[Back to [top](#toc)\\]\n","$$\\label{st}$$\n","\n","Here we use NRPy+ to generate initial data for a single trumpet black hole ([Dennison & Baumgarte, PRD ???](https://arxiv.org/abs/??)).\n","\n","\"Static\" Trumpet black hole initial data has been <font color='green'><b> validated </b></font> to exhibit convergence to zero of the Hamiltonian constraint violation at the expected order to the exact solution. It was carefully ported from the [original NRPy+ code](https://bitbucket.org/zach_etienne/nrpy).\n","\n","**NRPy+ Source Code:**\n","* [BSSN/StaticTrumpet.py](../edit/BSSN/StaticTrumpet.py); [\\[**tutorial**\\]](Tutorial-ADM_Initial_Data-StaticTrumpet.ipynb)\n","\n","The [BSSN.StaticTrumpet](../edit/BSSN/StaticTrumpet.py) NRPy+ module does the following:\n","\n","1. Set up static trumpet black hole initial data, represented by [ADM](https://en.wikipedia.org/wiki/ADM_formalism) quantities in the **Spherical basis**, as [documented here](Tutorial-ADM_Initial_Data-StaticTrumpetBlackHoleipynb). \n","1. Convert the exact ADM **Spherical quantities** to **BSSN quantities in the desired Curvilinear basis** (set by `reference_metric::CoordSystem`), as [documented here](Tutorial-ADM_Initial_Data-Converting_Numerical_ADM_Spherical_or_Cartesian_to_BSSNCurvilinear.ipynb).\n","1. Sets up the standardized C function for setting all BSSN Curvilinear gridfunctions in a pointwise fashion, as [written here](../edit/BSSN/BSSN_ID_function_string.py), and returns the C function as a Python string."]},{"cell_type": "markdown","metadata": {},"source": ["<a id='bl'></a>\n","\n","## Brill-Lindquist initial data \\[Back to [top](#toc)\\]\n","$$\\label{bl}$$\n","\n","Here we use NRPy+ to generate initial data for two black holes (Brill-Lindquist, [Brill & Lindquist, Phys. Rev. 131, 471, 1963](https://journals.aps.org/pr/abstract/10.1103/PhysRev.131.471); see also Eq. 1 of [Brandt & Brügmann, arXiv:gr-qc/9711015v1](https://arxiv.org/pdf/gr-qc/9711015v1.pdf)).\n","\n","[//]: # \" and then we use it to generate the RHS expressions for [Method of Lines](https://reference.wolfram.com/language/tutorial/NDSolveMethodOfLines.html) time integration based on the [explicit Runge-Kutta fourth-order scheme](https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods) (RK4).\"\n","\n","Brill-Lindquist initial data has been <font color='green'><b> validated </b></font> to exhibit convergence to zero of the Hamiltonian constraint violation at the expected order to the exact solution, and all quantities have been validated against the [original SENR code](https://bitbucket.org/zach_etienne/nrpy).\n","\n","**NRPy+ Source Code:**\n","* [BSSN/BrillLindquist.py](../edit/BSSN/BrillLindquist.py); [\\[**tutorial**\\]](Tutorial-ADM_Initial_Data-Brill-Lindquist.ipynb)\n","* [BSSN/BSSN_ID_function_string.py](../edit/BSSN/BSSN_ID_function_string.py)\n","\n","The [BSSN.BrillLindquist](../edit/BSSN/BrillLindquist.py) NRPy+ module does the following:\n","\n","1. Set up Brill-Lindquist initial data [ADM](https://en.wikipedia.org/wiki/ADM_formalism) quantities in the **Cartesian basis**, as [documented here](Tutorial-ADM_Initial_Data-Brill-Lindquist.ipynb). \n","1. Convert the ADM **Cartesian quantities** to **BSSN quantities in the desired Curvilinear basis** (set by `reference_metric::CoordSystem`), as [documented here](Tutorial-ADM_Initial_Data-Converting_ADMCartesian_to_BSSNCurvilinear.ipynb).\n","1. Sets up the standardized C function for setting all BSSN Curvilinear gridfunctions in a pointwise fashion, as [written here](../edit/BSSN/BSSN_ID_function_string.py), and returns the C function as a Python string."]},{"cell_type": "markdown","metadata": {},"source": ["<a id='uiuc'></a>\n","\n","## UIUC black hole initial data \\[Back to [top](#toc)\\]\n","$$\\label{uiuc}$$ \n","\n","UIUC black hole initial data has been <font color='green'><b> validated </b></font> to exhibit convergence to zero of the Hamiltonian constraint violation at the expected order to the exact solution, and all quantities have been validated against the [original SENR code](https://bitbucket.org/zach_etienne/nrpy).\n","\n","**NRPy+ Source Code:**\n","* [BSSN/UIUCBlackHole.py](../edit/BSSN/UIUCBlackHole.py); [\\[**tutorial**\\]](Tutorial-ADM_Initial_Data-UIUCBlackHole.ipynb)\n","\n","The [BSSN.UIUCBlackHole](../edit/BSSN/UIUCBlackHole.py) NRPy+ module does the following:\n","\n","1. Set up UIUC black hole initial data, represented by [ADM](https://en.wikipedia.org/wiki/ADM_formalism) quantities in the **Spherical basis**, as [documented here](Tutorial-ADM_Initial_Data-UIUCBlackHoleipynb). \n","1. Convert the numerical ADM **Spherical quantities** to **BSSN quantities in the desired Curvilinear basis** (set by `reference_metric::CoordSystem`), as [documented here](Tutorial-ADM_Initial_Data-Converting_Numerical_ADM_Spherical_or_Cartesian_to_BSSNCurvilinear.ipynb).\n","1. Sets up the standardized C function for setting all BSSN Curvilinear gridfunctions in a pointwise fashion, as [written here](../edit/BSSN/BSSN_ID_function_string.py), and returns the C function as a Python string."]},{"cell_type": "markdown","metadata": {},"source": ["<a id='-pickid'></a>\n","\n","# Step 1: Specify the Initial Data to Test \\[Back to [top](#toc)\\]\n","$$\\label{pickid}$$\n","\n","Here you have a choice for which initial data you would like to import and test for convergence. The following is a list of the currently compatible `initial_data_string` options for you to choose from.\n","\n","* `\"Shifted KerrSchild\"`\n","* `\"Static Trumpet\"`\n","* `\"Brill-Lindquist\"`\n","* `\"UIUC\"`"]},{"cell_type": "code","execution_count": 1,"metadata": {},"outputs": [],"source": ["import collections\n","\n","#################\n","# For the User: Choose initial data, default is Shifted KerrSchild.\n","# You are also encouraged to adjust any of the \n","# DestGridCoordSystem, freeparams, or EnableMomentum parameters! \n","# NOTE: Only DestGridCoordSystem == Spherical or SinhSpherical\n","# currently work out of the box; additional modifications\n","# will likely be necessary for other CoordSystems.\n","#################\n","initial_data_string = \"Shifted KerrSchild\" # \"UIUC\"\n","\n","\n","dictID = {}\n","IDmod_retfunc = collections.namedtuple('IDmod_retfunc', 'modulename functionname DestGridCoordSystem freeparams EnableMomentum')\n","\n","dictID['Shifted KerrSchild'] = IDmod_retfunc(\n"," modulename = \"BSSN.ShiftedKerrSchild\", functionname = \"ShiftedKerrSchild\", \n"," DestGridCoordSystem = \"Spherical\",\n"," freeparams = [\"const REAL M = 1.0;\", \"const REAL a = 0.9;\", \"const REAL r0 = 1.0;\"], \n"," EnableMomentum = True)\n","\n","dictID['Static Trumpet'] = IDmod_retfunc(\n"," modulename = \"BSSN.StaticTrumpet\", functionname = \"StaticTrumpet\", \n"," DestGridCoordSystem = \"Spherical\",\n"," freeparams = [\"const REAL M = 1.0;\"], \n"," EnableMomentum = False)\n","\n","dictID['Brill-Lindquist'] = IDmod_retfunc(\n"," modulename = \"BSSN.BrillLindquist\", functionname = \"BrillLindquist\", \n"," DestGridCoordSystem = \"Spherical\",\n"," freeparams = [\"const REAL BH1_posn_x =-1.0,BH1_posn_y = 0.0,BH1_posn_z = 0.0;\",\n"," \"const REAL BH2_posn_x = 1.0,BH2_posn_y = 0.0,BH2_posn_z = 0.0;\", \"const REAL BH1_mass = 0.5,BH2_mass = 0.5;\"], \n"," EnableMomentum = False)\n","\n","dictID['UIUC'] = IDmod_retfunc(modulename = \"BSSN.UIUCBlackHole\", functionname = \"UIUCBlackHole\", \n"," DestGridCoordSystem = \"SinhSpherical\",\n"," freeparams = [\"const REAL M = 1.0;\", \"const REAL chi = 0.99;\"], \n"," EnableMomentum = True)"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='initializenrpy'></a>\n","\n","# Step 2: Set up the needed NRPy+ infrastructure and declare core gridfunctions \\[Back to [top](#toc)\\]\n","$$\\label{initializenrpy}$$\n","\n","We will import the core modules of NRPy that we will need and specify the main gridfunctions we will need."]},{"cell_type": "code","execution_count": 2,"metadata": {},"outputs": [],"source": ["# Step P1: Import needed NRPy+ core modules:\n","import sys\n","sys.path.append(\"nrpytutorial\")\n","from outputC import * # NRPy+: Core C code output module\n","import finite_difference as fin # NRPy+: Finite difference C code generation module\n","import NRPy_param_funcs as par # NRPy+: Parameter interface\n","import grid as gri # NRPy+: Functions having to do with numerical grids\n","import indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) support\n","import reference_metric as rfm # NRPy+: Reference metric support\n","import cmdline_helper as cmd # NRPy+: Multi-platform Python command-line interface\n","import shutil, os, time # Standard Python modules for multiplatform OS-level functions, benchmarking\n","import importlib # Standard Python module for interactive module imports\n","\n","# Step P2: Create C code output directory:\n","Ccodesdir = os.path.join(\"BlackHoleID_Ccodes/\")\n","# First remove C code output directory if it exists\n","# Courtesy https://stackoverflow.com/questions/303200/how-do-i-remove-delete-a-folder-that-is-not-empty\n","# !rm -r ScalarWaveCurvilinear_Playground_Ccodes\n","shutil.rmtree(Ccodesdir, ignore_errors=True)\n","# Then create a fresh directory\n","cmd.mkdir(Ccodesdir)\n","\n","# Step P3: Create executable output directory:\n","outdir = os.path.join(Ccodesdir,\"output/\")\n","cmd.mkdir(outdir)\n","\n","# Step 1: Set the spatial dimension parameter \n","# to three this time, and then read\n","# the parameter as DIM.\n","par.set_parval_from_str(\"grid::DIM\",3)\n","DIM = par.parval_from_str(\"grid::DIM\")\n","\n","# Step 2: Set some core parameters, including CoordSystem MoL timestepping algorithm,\n","# FD order, floating point precision, and CFL factor:\n","# Choices are: Spherical, SinhSpherical, SinhSphericalv2, Cylindrical, SinhCylindrical, \n","# SymTP, SinhSymTP\n","CoordSystem = \"Spherical\"\n","\n","# Step 2.a: Set defaults for Coordinate system parameters.\n","# These are perhaps the most commonly adjusted parameters,\n","# so we enable modifications at this high level.\n","\n","# domain_size sets the default value for:\n","# * Spherical's params.RMAX\n","# * SinhSpherical*'s params.AMAX\n","# * Cartesians*'s -params.{x,y,z}min & .{x,y,z}max\n","# * Cylindrical's -params.ZMIN & .{Z,RHO}MAX\n","# * SinhCylindrical's params.AMPL{RHO,Z}\n","# * *SymTP's params.AMAX\n","domain_size = 3.0\n","\n","# sinh_width sets the default value for:\n","# * SinhSpherical's params.SINHW\n","# * SinhCylindrical's params.SINHW{RHO,Z}\n","# * SinhSymTP's params.SINHWAA\n","sinh_width = 0.4 # If Sinh* coordinates chosen\n","\n","# sinhv2_const_dr sets the default value for:\n","# * SinhSphericalv2's params.const_dr\n","# * SinhCylindricalv2's params.const_d{rho,z}\n","sinhv2_const_dr = 0.05# If Sinh*v2 coordinates chosen\n","\n","# SymTP_bScale sets the default value for:\n","# * SinhSymTP's params.bScale\n","SymTP_bScale = 0.5 # If SymTP chosen\n","\n","FD_order = 4 # Finite difference order: even numbers only, starting with 2. 12 is generally unstable\n","REAL = \"double\" # Best to use double here.\n","\n","# Step 3: Set the coordinate system for the numerical grid\n","par.set_parval_from_str(\"reference_metric::CoordSystem\",CoordSystem)\n","rfm.reference_metric() # Create ReU, ReDD needed for rescaling B-L initial data, generating BSSN RHSs, etc.\n","\n","# Step 4: Set the finite differencing order to FD_order (set above).\n","par.set_parval_from_str(\"finite_difference::FD_CENTDERIVS_ORDER\", FD_order)\n","\n","# Step 5: Set the direction=2 (phi) axis to be the symmetry axis; i.e., \n","# axis \"2\", corresponding to the i2 direction. \n","# This sets all spatial derivatives in the phi direction to zero.\n","par.set_parval_from_str(\"indexedexp::symmetry_axes\",\"2\")\n","\n","# Step 6: The MoLtimestepping interface is only used for memory allocation/deallocation\n","import MoLtimestepping.C_Code_Generation as MoL\n","from MoLtimestepping.RK_Butcher_Table_Dictionary import Butcher_dict\n","RK_method = \"Euler\" # DOES NOT MATTER; Again MoL interface is only used for memory alloc/dealloc.\n","RK_order = Butcher_dict[RK_method][1]\n","cmd.mkdir(os.path.join(Ccodesdir,\"MoLtimestepping/\"))\n","MoL.MoL_C_Code_Generation(RK_method, RHS_string = \"\", post_RHS_string = \"\",\n"," outdir = os.path.join(Ccodesdir,\"MoLtimestepping/\"))"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='adm_id'></a>\n","\n","# Step 3: Import Black Hole ADM initial data C function from NRPy+ module \\[Back to [top](#toc)\\]\n","$$\\label{adm_id}$$"]},{"cell_type": "code","execution_count": 3,"metadata": {},"outputs": [],"source": ["# Import Black Hole initial data\n","\n","IDmodule = importlib.import_module(dictID[initial_data_string].modulename)\n","IDfunc = getattr(IDmodule, dictID[initial_data_string].functionname)\n","IDfunc() # Registers ID C function in dictionary, used below to output to file.\n","with open(os.path.join(Ccodesdir,\"initial_data.h\"),\"w\") as file:\n"," file.write(outC_function_dict[\"initial_data\"])"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='cparams_rfm_and_domainsize'></a>\n","\n","## Step 3.a: Output C codes needed for declaring and setting Cparameters; also set `free_parameters.h` \\[Back to [top](#toc)\\]\n","$$\\label{cparams_rfm_and_domainsize}$$\n","\n","Based on declared NRPy+ Cparameters, first we generate `declare_Cparameters_struct.h`, `set_Cparameters_default.h`, and `set_Cparameters[-SIMD].h`.\n","\n","Then we output `free_parameters.h`, which sets initial data parameters, as well as grid domain & reference metric parameters, applying `domain_size` and `sinh_width`/`SymTP_bScale` (if applicable) as set above"]},{"cell_type": "code","execution_count": 4,"metadata": {},"outputs": [],"source": ["# Step 3.a.i: Set free_parameters.h\n","# Output to $Ccodesdir/free_parameters.h reference metric parameters based on generic\n","# domain_size,sinh_width,sinhv2_const_dr,SymTP_bScale,\n","# parameters set above. \n","rfm.out_default_free_parameters_for_rfm(os.path.join(Ccodesdir,\"free_parameters.h\"),\n"," domain_size,sinh_width,sinhv2_const_dr,SymTP_bScale)\n","\n","# Step 3.a.ii: Generate set_Nxx_dxx_invdx_params__and__xx.h:\n","rfm.set_Nxx_dxx_invdx_params__and__xx_h(Ccodesdir)\n","\n","# Step 3.a.iii: Generate xxCart.h, which contains xxCart() for\n","# (the mapping from xx->Cartesian) for the chosen\n","# CoordSystem:\n","rfm.xxCart_h(\"xxCart\",\"./set_Cparameters.h\",os.path.join(Ccodesdir,\"xxCart.h\"))\n","\n","# Step 3.a.iv: Generate declare_Cparameters_struct.h, set_Cparameters_default.h, and set_Cparameters[-SIMD].h\n","par.generate_Cparameters_Ccodes(os.path.join(Ccodesdir))"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='validate'></a>\n","\n","# Step 4: Validating that the black hole initial data satisfy the Hamiltonian constraint \\[Back to [top](#toc)\\]\n","$$\\label{validate}$$\n","\n","We will validate that the black hole initial data satisfy the Hamiltonian constraint, modulo numerical finite differencing error."]},{"cell_type": "markdown","metadata": {},"source": ["<a id='ham_const_output'></a>\n","\n","## Step 4.a: Output C code for evaluating the Hamiltonian and Momentum constraint violation \\[Back to [top](#toc)\\]\n","$$\\label{ham_const_output}$$\n","\n","First output C code for evaluating the Hamiltonian constraint violation. For the initial data where `EnableMomentum = True` we must also output C code for evaluating the Momentum constraint violation."]},{"cell_type": "code","execution_count": 5,"metadata": {},"outputs": [{"name": "stdout","output_type": "stream","text": ["Output C function Hamiltonian_constraint() to file BlackHoleID_Ccodes/Hamiltonian_constraint.h\n","Output C function momentum_constraint() to file BlackHoleID_Ccodes/momentum_constraint.h\n"]}],"source": ["import BSSN.BSSN_constraints as bssncon\n","# Now register the Hamiltonian & momentum constraints as gridfunctions.\n","H = gri.register_gridfunctions(\"AUX\",\"H\")\n","MU = ixp.register_gridfunctions_for_single_rank1(\"AUX\", \"MU\")\n","\n","# Generate symbolic expressions for Hamiltonian & momentum constraints\n","import BSSN.BSSN_constraints as bssncon\n","bssncon.BSSN_constraints(add_T4UUmunu_source_terms=False)\n","\n","# Generate otpimized C code for Hamiltonian constraint\n","desc=\"Evaluate the Hamiltonian constraint\"\n","name=\"Hamiltonian_constraint\"\n","outCfunction(\n"," outfile = os.path.join(Ccodesdir,name+\".h\"), desc=desc, name=name,\n"," params = \"\"\"const paramstruct *restrict params, REAL *restrict xx[3],\n"," REAL *restrict in_gfs, REAL *restrict aux_gfs\"\"\",\n"," body = fin.FD_outputC(\"returnstring\",lhrh(lhs=gri.gfaccess(\"aux_gfs\", \"H\"), rhs=bssncon.H),\n"," params=\"outCverbose=False\").replace(\"IDX4\",\"IDX4S\"),\n"," loopopts = \"InteriorPoints,Read_xxs\")\n","\n","# Generate otpimized C code for momentum constraint\n","desc=\"Evaluate the momentum constraint\"\n","name=\"momentum_constraint\"\n","outCfunction(\n"," outfile = os.path.join(Ccodesdir,name+\".h\"), desc=desc, name=name,\n"," params = \"\"\"const paramstruct *restrict params, REAL *restrict xx[3],\n"," REAL *restrict in_gfs, REAL *restrict aux_gfs\"\"\",\n"," body = fin.FD_outputC(\"returnstring\",\n"," [lhrh(lhs=gri.gfaccess(\"aux_gfs\", \"MU0\"), rhs=bssncon.MU[0]),\n"," lhrh(lhs=gri.gfaccess(\"aux_gfs\", \"MU1\"), rhs=bssncon.MU[1]),\n"," lhrh(lhs=gri.gfaccess(\"aux_gfs\", \"MU2\"), rhs=bssncon.MU[2])],\n"," params=\"outCverbose=False\").replace(\"IDX4\",\"IDX4S\"),\n"," loopopts = \"InteriorPoints,Read_xxs\")"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='enforce3metric'></a>\n","\n","## Step 4.b: Enforce conformal 3-metric $\\det{\\bar{\\gamma}_{ij}}=\\det{\\hat{\\gamma}_{ij}}$ constraint \\[Back to [top](#toc)\\]\n","$$\\label{enforce3metric}$$\n","\n","Then enforce conformal 3-metric $\\det{\\bar{\\gamma}_{ij}}=\\det{\\hat{\\gamma}_{ij}}$ constraint (Eq. 53 of [Ruchlin, Etienne, and Baumgarte (2018)](https://arxiv.org/abs/1712.07658)), as [documented in the corresponding NRPy+ tutorial notebook](Tutorial-BSSN-Enforcing_Determinant_gammabar_equals_gammahat_Constraint.ipynb)\n","\n","Applying curvilinear boundary conditions should affect the initial data at the outer boundary, and will in general cause the $\\det{\\bar{\\gamma}_{ij}}=\\det{\\hat{\\gamma}_{ij}}$ constraint to be violated there. Thus after we apply these boundary conditions, we must always call the routine for enforcing the $\\det{\\bar{\\gamma}_{ij}}=\\det{\\hat{\\gamma}_{ij}}$ constraint:"]},{"cell_type": "code","execution_count": 6,"metadata": {},"outputs": [{"name": "stdout","output_type": "stream","text": ["Output C function enforce_detgammabar_constraint() to file BlackHoleID_Ccodes/enforce_detgammabar_constraint.h\n"]}],"source": ["# Set up the C function for the det(gammahat) = det(gammabar)\n","import BSSN.Enforce_Detgammabar_Constraint as EGC\n","enforce_detg_constraint_symb_expressions = EGC.Enforce_Detgammabar_Constraint_symb_expressions()\n","\n","EGC.output_Enforce_Detgammabar_Constraint_Ccode(Ccodesdir,exprs=enforce_detg_constraint_symb_expressions,\n"," Read_xxs=True)"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='bc_functs'></a>\n","\n","## Step 4.c: Set up boundary condition functions for chosen singular, curvilinear coordinate system \\[Back to [top](#toc)\\]\n","$$\\label{bc_functs}$$\n","\n","Next apply singular, curvilinear coordinate boundary conditions [as documented in the corresponding NRPy+ tutorial notebook](Tutorial-Start_to_Finish-Curvilinear_BCs.ipynb)"]},{"cell_type": "code","execution_count": 7,"metadata": {"scrolled": true},"outputs": [{"name": "stdout","output_type": "stream","text": ["Wrote to file \"BlackHoleID_Ccodes/boundary_conditions/parity_conditions_symbolic_dot_products.h\"\n","Evolved gridfunction \"aDD00\" has parity type 4.\n","Evolved gridfunction \"aDD01\" has parity type 5.\n","Evolved gridfunction \"aDD02\" has parity type 6.\n","Evolved gridfunction \"aDD11\" has parity type 7.\n","Evolved gridfunction \"aDD12\" has parity type 8.\n","Evolved gridfunction \"aDD22\" has parity type 9.\n","Evolved gridfunction \"alpha\" has parity type 0.\n","Evolved gridfunction \"betU0\" has parity type 1.\n","Evolved gridfunction \"betU1\" has parity type 2.\n","Evolved gridfunction \"betU2\" has parity type 3.\n","Evolved gridfunction \"cf\" has parity type 0.\n","Evolved gridfunction \"hDD00\" has parity type 4.\n","Evolved gridfunction \"hDD01\" has parity type 5.\n","Evolved gridfunction \"hDD02\" has parity type 6.\n","Evolved gridfunction \"hDD11\" has parity type 7.\n","Evolved gridfunction \"hDD12\" has parity type 8.\n","Evolved gridfunction \"hDD22\" has parity type 9.\n","Evolved gridfunction \"lambdaU0\" has parity type 1.\n","Evolved gridfunction \"lambdaU1\" has parity type 2.\n","Evolved gridfunction \"lambdaU2\" has parity type 3.\n","Evolved gridfunction \"trK\" has parity type 0.\n","Evolved gridfunction \"vetU0\" has parity type 1.\n","Evolved gridfunction \"vetU1\" has parity type 2.\n","Evolved gridfunction \"vetU2\" has parity type 3.\n","Auxiliary gridfunction \"H\" has parity type 0.\n","Auxiliary gridfunction \"MU0\" has parity type 1.\n","Auxiliary gridfunction \"MU1\" has parity type 2.\n","Auxiliary gridfunction \"MU2\" has parity type 3.\n","Wrote to file \"BlackHoleID_Ccodes/boundary_conditions/EigenCoord_Cart_to_xx.h\"\n"]}],"source": ["import CurviBoundaryConditions.CurviBoundaryConditions as cbcs\n","cbcs.Set_up_CurviBoundaryConditions(os.path.join(Ccodesdir,\"boundary_conditions/\"),Cparamspath=os.path.join(\"../\"))"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='mainc'></a>\n","\n","# Step 5: `Initial_Data_Playground.c`: The Main C Code \\[Back to [top](#toc)\\]\n","$$\\label{mainc}$$"]},{"cell_type": "code","execution_count": 8,"metadata": {},"outputs": [],"source": ["# Part P0: Set the number of ghost cells, from NRPy+'s FD_CENTDERIVS_ORDER\n","# set REAL=double, so that all floating point numbers are stored to at least ~16 significant digits.\n","\n","with open(os.path.join(Ccodesdir,\"Initial_Data_Playground_REAL__NGHOSTS.h\"), \"w\") as file:\n"," file.write(\"\"\"\n","// Part P0.a: Set the number of ghost cells, from NRPy+'s FD_CENTDERIVS_ORDER\n","#define NGHOSTS \"\"\"+str(int(par.parval_from_str(\"finite_difference::FD_CENTDERIVS_ORDER\")/2)+1)+\"\"\"\\n\n","// Part P0.b: Set the numerical precision (REAL) to double, ensuring all floating point\n","// numbers are stored to at least ~16 significant digits\n","#define REAL double\\n\"\"\")"]},{"cell_type": "code","execution_count": 9,"metadata": {},"outputs": [{"name": "stdout","output_type": "stream","text": ["Writing BlackHoleID_Ccodes//Initial_Data_Playground.c\n"]}],"source": ["with open(os.path.join(Ccodesdir,\"Initial_Data_Playground.c\"), \"w\") as file:\n"," file.write(\"\"\"\n","\n","// Step P0: Define REAL and NGHOSTS. This header is generated by NRPy+.\n","#include \"Initial_Data_Playground_REAL__NGHOSTS.h\"\n","\n","#include \"declare_Cparameters_struct.h\"\n","\n","// Step P1: Import needed header files\n","#include \"stdio.h\"\n","#include \"stdlib.h\"\n","#include \"math.h\"\n","#ifndef M_PI\n","#define M_PI 3.141592653589793238462643383279502884L\n","#endif\n","#ifndef M_SQRT1_2\n","#define M_SQRT1_2 0.707106781186547524400844362104849039L\n","#endif\n","\n","// Step P2: Declare the IDX4S(gf,i,j,k) macro, which enables us to store 4-dimensions of\n","// data in a 1D array. In this case, consecutive values of \"i\" \n","// (all other indices held to a fixed value) are consecutive in memory, where \n","// consecutive values of \"j\" (fixing all other indices) are separated by \n","// Nxx_plus_2NGHOSTS0 elements in memory. Similarly, consecutive values of\n","// \"k\" are separated by Nxx_plus_2NGHOSTS0*Nxx_plus_2NGHOSTS1 in memory, etc.\n","#define IDX4S(g,i,j,k) \\\n","( (i) + Nxx_plus_2NGHOSTS0 * ( (j) + Nxx_plus_2NGHOSTS1 * ( (k) + Nxx_plus_2NGHOSTS2 * (g) ) ) )\n","#define IDX4ptS(g,idx) ( (idx) + (Nxx_plus_2NGHOSTS0*Nxx_plus_2NGHOSTS1*Nxx_plus_2NGHOSTS2) * (g) )\n","#define IDX3S(i,j,k) ( (i) + Nxx_plus_2NGHOSTS0 * ( (j) + Nxx_plus_2NGHOSTS1 * ( (k) ) ) )\n","#define LOOP_REGION(i0min,i0max, i1min,i1max, i2min,i2max) \\\n"," for(int i2=i2min;i2<i2max;i2++) for(int i1=i1min;i1<i1max;i1++) for(int i0=i0min;i0<i0max;i0++)\n","#define LOOP_ALL_GFS_GPS(ii) _Pragma(\"omp parallel for\") \\\n"," for(int (ii)=0;(ii)<Nxx_plus_2NGHOSTS_tot*NUM_EVOL_GFS;(ii)++)\n","\n","// Step P3: Set UUGF and VVGF macros, as well as xxCart()\n","#include \"boundary_conditions/gridfunction_defines.h\"\n","\n","// Step P4: Set xxCart(const paramstruct *restrict params, \n","// REAL *restrict xx[3],\n","// const int i0,const int i1,const int i2, \n","// REAL xCart[3]),\n","// which maps xx->Cartesian via\n","// {xx[0][i0],xx[1][i1],xx[2][i2]}->{xCart[0],xCart[1],xCart[2]}\n","#include \"xxCart.h\"\n","\n","// Step P5: Defines set_Nxx_dxx_invdx_params__and__xx(const int EigenCoord, const int Nxx[3], \n","// paramstruct *restrict params, REAL *restrict xx[3]),\n","// which sets params Nxx,Nxx_plus_2NGHOSTS,dxx,invdx, and xx[] for\n","// the chosen Eigen-CoordSystem if EigenCoord==1, or\n","// CoordSystem if EigenCoord==0.\n","#include \"set_Nxx_dxx_invdx_params__and__xx.h\"\n","\n","// Step P6: Include basic functions needed to impose curvilinear\n","// parity and boundary conditions.\n","#include \"boundary_conditions/CurviBC_include_Cfunctions.h\"\n","\n","// Step P8: Include function for enforcing detgammabar constraint.\n","#include \"enforce_detgammabar_constraint.h\"\n","\n","// Step P10: Declare function necessary for setting up the initial data.\n","// Step P10.a: Define BSSN_ID() for BrillLindquist initial data\n","\n","// Step P10.b: Set the generic driver function for setting up BSSN initial data\n","#include \"initial_data.h\"\n","\n","// Step P11: Declare function for evaluating Hamiltonian constraint (diagnostic)\n","#include \"Hamiltonian_constraint.h\" \n","#include \"momentum_constraint.h\" \n","\n","// main() function:\n","// Step 0: Read command-line input, set up grid structure, allocate memory for gridfunctions, set up coordinates\n","// Step 1: Set up initial data to an exact solution\n","// Step 2: Start the timer, for keeping track of how fast the simulation is progressing.\n","// Step 3: Integrate the initial data forward in time using the chosen RK-like Method of \n","// Lines timestepping algorithm, and output periodic simulation diagnostics \n","// Step 3.a: Output 2D data file periodically, for visualization\n","// Step 3.b: Step forward one timestep (t -> t+dt) in time using \n","// chosen RK-like MoL timestepping algorithm\n","// Step 3.c: If t=t_final, output conformal factor & Hamiltonian \n","// constraint violation to 2D data file\n","// Step 3.d: Progress indicator printing to stderr\n","// Step 4: Free all allocated memory\n","int main(int argc, const char *argv[]) {\n"," paramstruct params;\n","#include \"set_Cparameters_default.h\"\n"," \n"," // Step 0a: Read command-line input, error out if nonconformant\n"," if((argc != 4) || atoi(argv[1]) < NGHOSTS || atoi(argv[2]) < NGHOSTS || atoi(argv[3]) < 2 /* FIXME; allow for axisymmetric sims */) {\n"," fprintf(stderr,\"Error: Expected three command-line arguments: ./BrillLindquist_Playground Nx0 Nx1 Nx2,\\n\");\n"," fprintf(stderr,\"where Nx[0,1,2] is the number of grid points in the 0, 1, and 2 directions.\\n\");\n"," fprintf(stderr,\"Nx[] MUST BE larger than NGHOSTS (= %d)\\n\",NGHOSTS);\n"," exit(1);\n"," }\n"," // Step 0b: Set up numerical grid structure, first in space...\n"," const int Nxx[3] = { atoi(argv[1]), atoi(argv[2]), atoi(argv[3]) };\n"," if(Nxx[0]%2 != 0 || Nxx[1]%2 != 0 || Nxx[2]%2 != 0) {\n"," fprintf(stderr,\"Error: Cannot guarantee a proper cell-centered grid if number of grid cells not set to even number.\\n\");\n"," fprintf(stderr,\" For example, in case of angular directions, proper symmetry zones will not exist.\\n\");\n"," exit(1);\n"," }\n","\n"," // Step 0c: Set free parameters, overwriting Cparameters defaults \n"," // by hand or with command-line input, as desired.\n","#include \"free_parameters.h\"\n","\n"," // Step 0d: Uniform coordinate grids are stored to *xx[3]\n"," REAL *xx[3];\n"," // Step 0d.i: Set bcstruct\n"," bc_struct bcstruct;\n"," {\n"," int EigenCoord = 1;\n"," // Step 0d.ii: Call set_Nxx_dxx_invdx_params__and__xx(), which sets\n"," // params Nxx,Nxx_plus_2NGHOSTS,dxx,invdx, and xx[] for the\n"," // chosen Eigen-CoordSystem.\n"," set_Nxx_dxx_invdx_params__and__xx(EigenCoord, Nxx, ¶ms, xx);\n"," // Step 0d.iii: Set Nxx_plus_2NGHOSTS_tot\n","#include \"set_Cparameters-nopointer.h\"\n"," const int Nxx_plus_2NGHOSTS_tot = Nxx_plus_2NGHOSTS0*Nxx_plus_2NGHOSTS1*Nxx_plus_2NGHOSTS2;\n"," // Step 0e: Find ghostzone mappings; set up bcstruct\n","#include \"boundary_conditions/driver_bcstruct.h\"\n"," // Step 0e.i: Free allocated space for xx[][] array\n"," for(int i=0;i<3;i++) free(xx[i]);\n"," }\n"," \n"," // Step 0f: Call set_Nxx_dxx_invdx_params__and__xx(), which sets\n"," // params Nxx,Nxx_plus_2NGHOSTS,dxx,invdx, and xx[] for the\n"," // chosen (non-Eigen) CoordSystem.\n"," int EigenCoord = 0;\n"," set_Nxx_dxx_invdx_params__and__xx(EigenCoord, Nxx, ¶ms, xx);\n","\n"," // Step 0g: Set all C parameters \"blah\" for params.blah, including\n"," // Nxx_plus_2NGHOSTS0 = params.Nxx_plus_2NGHOSTS0, etc.\n","#include \"set_Cparameters-nopointer.h\"\n"," const int Nxx_plus_2NGHOSTS_tot = Nxx_plus_2NGHOSTS0*Nxx_plus_2NGHOSTS1*Nxx_plus_2NGHOSTS2;\n","\n"," // Step 0j: Error out if the number of auxiliary gridfunctions outnumber evolved gridfunctions.\n"," // This is a limitation of the RK method. You are always welcome to declare & allocate \n"," // additional gridfunctions by hand.\n"," if(NUM_AUX_GFS > NUM_EVOL_GFS) {\n"," fprintf(stderr,\"Error: NUM_AUX_GFS > NUM_EVOL_GFS. Either reduce the number of auxiliary gridfunctions,\\n\");\n"," fprintf(stderr,\" or allocate (malloc) by hand storage for *diagnostic_output_gfs. \\n\");\n"," exit(1);\n"," }\n"," \n"," // Step 0k: Allocate memory for gridfunctions\n","#include \"MoLtimestepping/RK_Allocate_Memory.h\"\n"," REAL *restrict auxevol_gfs = (REAL *)malloc(sizeof(REAL) * NUM_AUXEVOL_GFS * Nxx_plus_2NGHOSTS_tot);\n"," \n"," // Step 1: Set up initial data to an exact solution\n"," initial_data(¶ms, xx, y_n_gfs);\n","\n"," // Step 1b: Apply boundary conditions, as initial data \n"," // are sometimes ill-defined in ghost zones.\n"," // E.g., spherical initial data might not be\n"," // properly defined at points where r=-1.\n"," apply_bcs_curvilinear(¶ms, &bcstruct, NUM_EVOL_GFS,evol_gf_parity, y_n_gfs);\n"," enforce_detgammabar_constraint(¶ms, xx, y_n_gfs);\n","\n"," // Evaluate Hamiltonian & momentum constraint violations\n"," Hamiltonian_constraint(¶ms, xx, y_n_gfs, diagnostic_output_gfs);\n"," momentum_constraint( ¶ms, xx, y_n_gfs, diagnostic_output_gfs);\n","\n"," /* Step 2: 2D output: Output conformal factor (CFGF) and constraint violations (HGF, MU0GF, MU1GF, MU2GF). */\n"," const int i0MIN=NGHOSTS; // In spherical, r=Delta r/2.\n"," const int i1mid=Nxx_plus_2NGHOSTS1/2;\n"," const int i2mid=Nxx_plus_2NGHOSTS2/2;\n"," LOOP_REGION(NGHOSTS,Nxx_plus_2NGHOSTS0-NGHOSTS, i1mid,i1mid+1, NGHOSTS,Nxx_plus_2NGHOSTS2-NGHOSTS) {\n"," REAL xCart[3];\n"," xxCart(¶ms, xx, i0,i1,i2, xCart);\n"," int idx = IDX3S(i0,i1,i2);\n"," printf(\"%e %e %e %e %e %e %e\\n\",xCart[0],xCart[1], y_n_gfs[IDX4ptS(CFGF,idx)],\n"," log10(fabs(diagnostic_output_gfs[IDX4ptS(HGF,idx)])),\n"," log10(fabs(diagnostic_output_gfs[IDX4ptS(MU0GF,idx)])+1e-200),\n"," log10(fabs(diagnostic_output_gfs[IDX4ptS(MU1GF,idx)])+1e-200),\n"," log10(fabs(diagnostic_output_gfs[IDX4ptS(MU2GF,idx)])+1e-200));\n"," }\n"," // Step 4: Free all allocated memory\n","#include \"boundary_conditions/bcstruct_freemem.h\"\n","#include \"MoLtimestepping/RK_Free_Memory.h\"\n"," free(auxevol_gfs);\n"," for(int i=0;i<3;i++) free(xx[i]);\n","\n"," return 0;\n","}\\n\"\"\")"]}],"metadata": {"kernelspec": {"display_name": "Python 3","language": "python","name": "python3"},"language_info": {"codemirror_mode": {"name": "ipython","version": 3},"file_extension": ".py","mimetype": "text/x-python","name": "python","nbconvert_exporter": "python","pygments_lexer": "ipython3","version": "3.8.0"}},"nbformat": 4,"nbformat_minor": 2}
{"cells": [{"cell_type": "markdown","metadata": {},"source": ["<script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-59152712-8\"></script>\n","<script>\n"," window.dataLayer = window.dataLayer || [];\n"," function gtag(){dataLayer.push(arguments);}\n"," gtag('js', new Date());\n","\n"," gtag('config', 'UA-59152712-8');\n","</script>\n","\n","# Start-to-Finish Example: Setting up Exact Initial Data for Einstein's Equations, in Curvilinear Coordinates\n","## Authors: Brandon Clark, George Vopal, and Zach Etienne\n","\n","## This module sets up initial data for a specified exact solution written in terms of ADM variables, using the [*Exact* ADM Spherical to BSSN Curvilinear initial data module](../edit/BSSN/ADM_Exact_Spherical_or_Cartesian_to_BSSNCurvilinear.py).\n","\n","**Notebook Status:** <font color='green'><b> Validated </b></font>\n","\n","**Validation Notes:** This module has been validated, confirming that all initial data sets exhibit convergence to zero of the Hamiltonian and momentum constraints at the expected rate or better.\n","\n","### NRPy+ Source Code for this module:\n","* [BSSN/ADM_Exact_Spherical_or_Cartesian_to_BSSNCurvilinear.py](../edit/BSSN/ADM_Exact_Spherical_or_Cartesian_to_BSSNCurvilinear.py); [\\[**tutorial**\\]](Tutorial-ADM_Initial_Data-Converting_Exact_ADM_Spherical_or_Cartesian_to_BSSNCurvilinear.ipynb): *Exact* Spherical ADM$\\to$Curvilinear BSSN converter function\n","* [BSSN/BSSN_constraints.py](../edit/BSSN/BSSN_constraints.py); [\\[**tutorial**\\]](Tutorial-BSSN_constraints.ipynb): Hamiltonian & momentum constraints in BSSN curvilinear basis/coordinates\n","\n","## Introduction:\n","Here we use NRPy+ to generate a C code confirming that specified *exact* initial data satisfy Einstein's equations of general relativity. The following exact initial data types are supported:\n","\n","* Shifted Kerr-Schild spinning black hole initial data\n","* \"Static\" Trumpet black hole initial data\n","* Brill-Lindquist two black hole initial data\n","* UIUC black hole initial data"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='toc'></a>\n","\n","# Table of Contents\n","$$\\label{toc}$$\n","\n","This notebook is organized as follows\n","\n","0. [Preliminaries](#prelim): The Choices for Initial Data\n"," 1. [Choice 1](#sks): Shifted Kerr-Schild spinning black hole initial data\n"," 1. [Choice 2](#st): \"Static\" Trumpet black hole initial data\n"," 1. [Choice 3](#bl): Brill-Lindquist two black hole initial data\n"," 1. [Choice 4](#uiuc): UIUC black hole initial data\n","1. [Step 2](#initializenrpy): Set core NRPy+ parameters for numerical grids and reference metric\n","1. [Step 3](#adm_id): Import Black Hole ADM initial data C function from NRPy+ module\n","1. [Step 4](#validate): Validating that the black hole initial data satisfy the Hamiltonian constraint\n"," 1. [Step 4.a](#ham_const_output): Output C code for evaluating the Hamiltonian and Momentum constraint violation\n"," 1. [Step 4.b](#apply_bcs): Apply singular, curvilinear coordinate boundary conditions\n"," 1. [Step 4.c](#enforce3metric): Enforce conformal 3-metric $\\det{\\bar{\\gamma}_{ij}}=\\det{\\hat{\\gamma}_{ij}}$ constraint\n","1. [Step 5](#mainc): `Initial_Data.c`: The Main C Code\n","1. [Step 6](#plot): Plotting the initial data\n","1. [Step 7](#convergence): Validation: Convergence of numerical errors (Hamiltonian constraint violation) to zero\n","1. [Step 8](#latex_pdf_output): Output this notebook to $\\LaTeX$-formatted PDF file"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='prelim'></a>\n","\n","# Preliminaries: The Choices for Initial Data\n","$$\\label{prelim}$$"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='sks'></a>\n","\n","## Shifted Kerr-Schild spinning black hole initial data \\[Back to [top](#toc)\\]\n","$$\\label{sks}$$\n","\n","Here we use NRPy+ to generate initial data for a spinning black hole.\n","\n","Shifted Kerr-Schild spinning black hole initial data has been <font color='green'><b> validated </b></font> to exhibit convergence to zero of both the Hamiltonian and momentum constraint violations at the expected order to the exact solution.\n","\n","**NRPy+ Source Code:**\n","* [BSSN/ShiftedKerrSchild.py](../edit/BSSN/ShiftedKerrSchild.py); [\\[**tutorial**\\]](Tutorial-ADM_Initial_Data-ShiftedKerrSchild.ipynb)\n","\n","The [BSSN.ShiftedKerrSchild](../edit/BSSN/ShiftedKerrSchild.py) NRPy+ module does the following:\n","\n","1. Set up shifted Kerr-Schild initial data, represented by [ADM](https://en.wikipedia.org/wiki/ADM_formalism) quantities in the **Spherical basis**, as [documented here](Tutorial-ADM_Initial_Data-ShiftedKerrSchild.ipynb). \n","1. Convert the exact ADM **Spherical quantities** to **BSSN quantities in the desired Curvilinear basis** (set by `reference_metric::CoordSystem`), as [documented here](Tutorial-ADM_Initial_Data-Converting_Numerical_ADM_Spherical_or_Cartesian_to_BSSNCurvilinear.ipynb).\n","1. Sets up the standardized C function for setting all BSSN Curvilinear gridfunctions in a pointwise fashion, as [written here](../edit/BSSN/BSSN_ID_function_string.py), and returns the C function as a Python string."]},{"cell_type": "markdown","metadata": {},"source": ["<a id='st'></a>\n","\n","## \"Static\" Trumpet black hole initial data \\[Back to [top](#toc)\\]\n","$$\\label{st}$$\n","\n","Here we use NRPy+ to generate initial data for a single trumpet black hole ([Dennison & Baumgarte, PRD ???](https://arxiv.org/abs/??)).\n","\n","\"Static\" Trumpet black hole initial data has been <font color='green'><b> validated </b></font> to exhibit convergence to zero of the Hamiltonian constraint violation at the expected order to the exact solution. It was carefully ported from the [original NRPy+ code](https://bitbucket.org/zach_etienne/nrpy).\n","\n","**NRPy+ Source Code:**\n","* [BSSN/StaticTrumpet.py](../edit/BSSN/StaticTrumpet.py); [\\[**tutorial**\\]](Tutorial-ADM_Initial_Data-StaticTrumpet.ipynb)\n","\n","The [BSSN.StaticTrumpet](../edit/BSSN/StaticTrumpet.py) NRPy+ module does the following:\n","\n","1. Set up static trumpet black hole initial data, represented by [ADM](https://en.wikipedia.org/wiki/ADM_formalism) quantities in the **Spherical basis**, as [documented here](Tutorial-ADM_Initial_Data-StaticTrumpetBlackHoleipynb). \n","1. Convert the exact ADM **Spherical quantities** to **BSSN quantities in the desired Curvilinear basis** (set by `reference_metric::CoordSystem`), as [documented here](Tutorial-ADM_Initial_Data-Converting_Numerical_ADM_Spherical_or_Cartesian_to_BSSNCurvilinear.ipynb).\n","1. Sets up the standardized C function for setting all BSSN Curvilinear gridfunctions in a pointwise fashion, as [written here](../edit/BSSN/BSSN_ID_function_string.py), and returns the C function as a Python string."]},{"cell_type": "markdown","metadata": {},"source": ["<a id='bl'></a>\n","\n","## Brill-Lindquist initial data \\[Back to [top](#toc)\\]\n","$$\\label{bl}$$\n","\n","Here we use NRPy+ to generate initial data for two black holes (Brill-Lindquist, [Brill & Lindquist, Phys. Rev. 131, 471, 1963](https://journals.aps.org/pr/abstract/10.1103/PhysRev.131.471); see also Eq. 1 of [Brandt & Brügmann, arXiv:gr-qc/9711015v1](https://arxiv.org/pdf/gr-qc/9711015v1.pdf)).\n","\n","[//]: # \" and then we use it to generate the RHS expressions for [Method of Lines](https://reference.wolfram.com/language/tutorial/NDSolveMethodOfLines.html) time integration based on the [explicit Runge-Kutta fourth-order scheme](https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods) (RK4).\"\n","\n","Brill-Lindquist initial data has been <font color='green'><b> validated </b></font> to exhibit convergence to zero of the Hamiltonian constraint violation at the expected order to the exact solution, and all quantities have been validated against the [original SENR code](https://bitbucket.org/zach_etienne/nrpy).\n","\n","**NRPy+ Source Code:**\n","* [BSSN/BrillLindquist.py](../edit/BSSN/BrillLindquist.py); [\\[**tutorial**\\]](Tutorial-ADM_Initial_Data-Brill-Lindquist.ipynb)\n","* [BSSN/BSSN_ID_function_string.py](../edit/BSSN/BSSN_ID_function_string.py)\n","\n","The [BSSN.BrillLindquist](../edit/BSSN/BrillLindquist.py) NRPy+ module does the following:\n","\n","1. Set up Brill-Lindquist initial data [ADM](https://en.wikipedia.org/wiki/ADM_formalism) quantities in the **Cartesian basis**, as [documented here](Tutorial-ADM_Initial_Data-Brill-Lindquist.ipynb). \n","1. Convert the ADM **Cartesian quantities** to **BSSN quantities in the desired Curvilinear basis** (set by `reference_metric::CoordSystem`), as [documented here](Tutorial-ADM_Initial_Data-Converting_ADMCartesian_to_BSSNCurvilinear.ipynb).\n","1. Sets up the standardized C function for setting all BSSN Curvilinear gridfunctions in a pointwise fashion, as [written here](../edit/BSSN/BSSN_ID_function_string.py), and returns the C function as a Python string."]},{"cell_type": "markdown","metadata": {},"source": ["<a id='uiuc'></a>\n","\n","## UIUC black hole initial data \\[Back to [top](#toc)\\]\n","$$\\label{uiuc}$$ \n","\n","UIUC black hole initial data has been <font color='green'><b> validated </b></font> to exhibit convergence to zero of the Hamiltonian constraint violation at the expected order to the exact solution, and all quantities have been validated against the [original SENR code](https://bitbucket.org/zach_etienne/nrpy).\n","\n","**NRPy+ Source Code:**\n","* [BSSN/UIUCBlackHole.py](../edit/BSSN/UIUCBlackHole.py); [\\[**tutorial**\\]](Tutorial-ADM_Initial_Data-UIUCBlackHole.ipynb)\n","\n","The [BSSN.UIUCBlackHole](../edit/BSSN/UIUCBlackHole.py) NRPy+ module does the following:\n","\n","1. Set up UIUC black hole initial data, represented by [ADM](https://en.wikipedia.org/wiki/ADM_formalism) quantities in the **Spherical basis**, as [documented here](Tutorial-ADM_Initial_Data-UIUCBlackHoleipynb). \n","1. Convert the numerical ADM **Spherical quantities** to **BSSN quantities in the desired Curvilinear basis** (set by `reference_metric::CoordSystem`), as [documented here](Tutorial-ADM_Initial_Data-Converting_Numerical_ADM_Spherical_or_Cartesian_to_BSSNCurvilinear.ipynb).\n","1. Sets up the standardized C function for setting all BSSN Curvilinear gridfunctions in a pointwise fashion, as [written here](../edit/BSSN/BSSN_ID_function_string.py), and returns the C function as a Python string."]},{"cell_type": "markdown","metadata": {},"source": ["<a id='-pickid'></a>\n","\n","# Step 1: Specify the Initial Data to Test \\[Back to [top](#toc)\\]\n","$$\\label{pickid}$$\n","\n","Here you have a choice for which initial data you would like to import and test for convergence. The following is a list of the currently compatible `initial_data_string` options for you to choose from.\n","\n","* `\"Shifted KerrSchild\"`\n","* `\"Static Trumpet\"`\n","* `\"Brill-Lindquist\"`\n","* `\"UIUC\"`"]},{"cell_type": "code","execution_count": 1,"metadata": {},"outputs": [],"source": ["import collections\n","\n","#################\n","# For the User: Choose initial data, default is Shifted KerrSchild.\n","# You are also encouraged to adjust any of the \n","# DestGridCoordSystem, freeparams, or EnableMomentum parameters! \n","# NOTE: Only DestGridCoordSystem == Spherical or SinhSpherical\n","# currently work out of the box; additional modifications\n","# will likely be necessary for other CoordSystems.\n","#################\n","initial_data_string = \"Shifted KerrSchild\" # \"UIUC\"\n","\n","\n","dictID = {}\n","IDmod_retfunc = collections.namedtuple('IDmod_retfunc', 'modulename functionname DestGridCoordSystem freeparams EnableMomentum')\n","\n","dictID['Shifted KerrSchild'] = IDmod_retfunc(\n"," modulename = \"BSSN.ShiftedKerrSchild\", functionname = \"ShiftedKerrSchild\", \n"," DestGridCoordSystem = \"Spherical\",\n"," freeparams = [\"const REAL M = 1.0;\", \"const REAL a = 0.9;\", \"const REAL r0 = 1.0;\"], \n"," EnableMomentum = True)\n","\n","dictID['Static Trumpet'] = IDmod_retfunc(\n"," modulename = \"BSSN.StaticTrumpet\", functionname = \"StaticTrumpet\", \n"," DestGridCoordSystem = \"Spherical\",\n"," freeparams = [\"const REAL M = 1.0;\"], \n"," EnableMomentum = False)\n","\n","dictID['Brill-Lindquist'] = IDmod_retfunc(\n"," modulename = \"BSSN.BrillLindquist\", functionname = \"BrillLindquist\", \n"," DestGridCoordSystem = \"Spherical\",\n"," freeparams = [\"const REAL BH1_posn_x =-1.0,BH1_posn_y = 0.0,BH1_posn_z = 0.0;\",\n"," \"const REAL BH2_posn_x = 1.0,BH2_posn_y = 0.0,BH2_posn_z = 0.0;\", \"const REAL BH1_mass = 0.5,BH2_mass = 0.5;\"], \n"," EnableMomentum = False)\n","\n","dictID['UIUC'] = IDmod_retfunc(modulename = \"BSSN.UIUCBlackHole\", functionname = \"UIUCBlackHole\", \n"," DestGridCoordSystem = \"SinhSpherical\",\n"," freeparams = [\"const REAL M = 1.0;\", \"const REAL chi = 0.99;\"], \n"," EnableMomentum = True)"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='initializenrpy'></a>\n","\n","# Step 2: Set up the needed NRPy+ infrastructure and declare core gridfunctions \\[Back to [top](#toc)\\]\n","$$\\label{initializenrpy}$$\n","\n","We will import the core modules of NRPy that we will need and specify the main gridfunctions we will need."]},{"cell_type": "code","execution_count": 2,"metadata": {},"outputs": [],"source": ["# Step P1: Import needed NRPy+ core modules:\n","import sys\n","sys.path.append(\"nrpytutorial\")\n","from outputC import * # NRPy+: Core C code output module\n","import finite_difference as fin # NRPy+: Finite difference C code generation module\n","import NRPy_param_funcs as par # NRPy+: Parameter interface\n","import grid as gri # NRPy+: Functions having to do with numerical grids\n","import indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) support\n","import reference_metric as rfm # NRPy+: Reference metric support\n","import cmdline_helper as cmd # NRPy+: Multi-platform Python command-line interface\n","import shutil, os, time # Standard Python modules for multiplatform OS-level functions, benchmarking\n","import importlib # Standard Python module for interactive module imports\n","\n","# Step P2: Create C code output directory:\n","Ccodesdir = os.path.join(\"BlackHoleID_Ccodes/\")\n","# First remove C code output directory if it exists\n","# Courtesy https://stackoverflow.com/questions/303200/how-do-i-remove-delete-a-folder-that-is-not-empty\n","# !rm -r ScalarWaveCurvilinear_Playground_Ccodes\n","shutil.rmtree(Ccodesdir, ignore_errors=True)\n","# Then create a fresh directory\n","cmd.mkdir(Ccodesdir)\n","\n","# Step P3: Create executable output directory:\n","outdir = os.path.join(Ccodesdir,\"output/\")\n","cmd.mkdir(outdir)\n","\n","# Step 1: Set the spatial dimension parameter \n","# to three this time, and then read\n","# the parameter as DIM.\n","par.set_parval_from_str(\"grid::DIM\",3)\n","DIM = par.parval_from_str(\"grid::DIM\")\n","\n","# Step 2: Set some core parameters, including CoordSystem MoL timestepping algorithm,\n","# FD order, floating point precision, and CFL factor:\n","# Choices are: Spherical, SinhSpherical, SinhSphericalv2, Cylindrical, SinhCylindrical, \n","# SymTP, SinhSymTP\n","CoordSystem = \"Spherical\"\n","\n","# Step 2.a: Set defaults for Coordinate system parameters.\n","# These are perhaps the most commonly adjusted parameters,\n","# so we enable modifications at this high level.\n","\n","# domain_size sets the default value for:\n","# * Spherical's params.RMAX\n","# * SinhSpherical*'s params.AMAX\n","# * Cartesians*'s -params.{x,y,z}min & .{x,y,z}max\n","# * Cylindrical's -params.ZMIN & .{Z,RHO}MAX\n","# * SinhCylindrical's params.AMPL{RHO,Z}\n","# * *SymTP's params.AMAX\n","domain_size = 3.0\n","\n","# sinh_width sets the default value for:\n","# * SinhSpherical's params.SINHW\n","# * SinhCylindrical's params.SINHW{RHO,Z}\n","# * SinhSymTP's params.SINHWAA\n","sinh_width = 0.4 # If Sinh* coordinates chosen\n","\n","# sinhv2_const_dr sets the default value for:\n","# * SinhSphericalv2's params.const_dr\n","# * SinhCylindricalv2's params.const_d{rho,z}\n","sinhv2_const_dr = 0.05# If Sinh*v2 coordinates chosen\n","\n","# SymTP_bScale sets the default value for:\n","# * SinhSymTP's params.bScale\n","SymTP_bScale = 0.5 # If SymTP chosen\n","\n","FD_order = 4 # Finite difference order: even numbers only, starting with 2. 12 is generally unstable\n","REAL = \"double\" # Best to use double here.\n","\n","# Step 3: Set the coordinate system for the numerical grid\n","par.set_parval_from_str(\"reference_metric::CoordSystem\",CoordSystem)\n","rfm.reference_metric() # Create ReU, ReDD needed for rescaling B-L initial data, generating BSSN RHSs, etc.\n","\n","# Step 4: Set the finite differencing order to FD_order (set above).\n","par.set_parval_from_str(\"finite_difference::FD_CENTDERIVS_ORDER\", FD_order)\n","\n","# Step 5: Set the direction=2 (phi) axis to be the symmetry axis; i.e., \n","# axis \"2\", corresponding to the i2 direction. \n","# This sets all spatial derivatives in the phi direction to zero.\n","par.set_parval_from_str(\"indexedexp::symmetry_axes\",\"2\")\n","\n","# Step 6: The MoLtimestepping interface is only used for memory allocation/deallocation\n","import MoLtimestepping.C_Code_Generation as MoL\n","from MoLtimestepping.RK_Butcher_Table_Dictionary import Butcher_dict\n","RK_method = \"Euler\" # DOES NOT MATTER; Again MoL interface is only used for memory alloc/dealloc.\n","RK_order = Butcher_dict[RK_method][1]\n","cmd.mkdir(os.path.join(Ccodesdir,\"MoLtimestepping/\"))\n","MoL.MoL_C_Code_Generation(RK_method, RHS_string = \"\", post_RHS_string = \"\",\n"," outdir = os.path.join(Ccodesdir,\"MoLtimestepping/\"))"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='adm_id'></a>\n","\n","# Step 3: Import Black Hole ADM initial data C function from NRPy+ module \\[Back to [top](#toc)\\]\n","$$\\label{adm_id}$$"]},{"cell_type": "code","execution_count": 3,"metadata": {},"outputs": [],"source": ["# Import Black Hole initial data\n","\n","IDmodule = importlib.import_module(dictID[initial_data_string].modulename)\n","IDfunc = getattr(IDmodule, dictID[initial_data_string].functionname)\n","IDfunc() # Registers ID C function in dictionary, used below to output to file.\n","with open(os.path.join(Ccodesdir,\"initial_data.h\"),\"w\") as file:\n"," file.write(outC_function_dict[\"initial_data\"])"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='cparams_rfm_and_domainsize'></a>\n","\n","## Step 3.a: Output C codes needed for declaring and setting Cparameters; also set `free_parameters.h` \\[Back to [top](#toc)\\]\n","$$\\label{cparams_rfm_and_domainsize}$$\n","\n","Based on declared NRPy+ Cparameters, first we generate `declare_Cparameters_struct.h`, `set_Cparameters_default.h`, and `set_Cparameters[-SIMD].h`.\n","\n","Then we output `free_parameters.h`, which sets initial data parameters, as well as grid domain & reference metric parameters, applying `domain_size` and `sinh_width`/`SymTP_bScale` (if applicable) as set above"]},{"cell_type": "code","execution_count": 4,"metadata": {},"outputs": [],"source": ["# Step 3.a.i: Set free_parameters.h\n","# Output to $Ccodesdir/free_parameters.h reference metric parameters based on generic\n","# domain_size,sinh_width,sinhv2_const_dr,SymTP_bScale,\n","# parameters set above. \n","rfm.out_default_free_parameters_for_rfm(os.path.join(Ccodesdir,\"free_parameters.h\"),\n"," domain_size,sinh_width,sinhv2_const_dr,SymTP_bScale)\n","\n","# Step 3.a.ii: Generate set_Nxx_dxx_invdx_params__and__xx.h:\n","rfm.set_Nxx_dxx_invdx_params__and__xx_h(Ccodesdir)\n","\n","# Step 3.a.iii: Generate xxCart.h, which contains xxCart() for\n","# (the mapping from xx->Cartesian) for the chosen\n","# CoordSystem:\n","rfm.xxCart_h(\"xxCart\",\"./set_Cparameters.h\",os.path.join(Ccodesdir,\"xxCart.h\"))\n","\n","# Step 3.a.iv: Generate declare_Cparameters_struct.h, set_Cparameters_default.h, and set_Cparameters[-SIMD].h\n","par.generate_Cparameters_Ccodes(os.path.join(Ccodesdir))"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='validate'></a>\n","\n","# Step 4: Validating that the black hole initial data satisfy the Hamiltonian constraint \\[Back to [top](#toc)\\]\n","$$\\label{validate}$$\n","\n","We will validate that the black hole initial data satisfy the Hamiltonian constraint, modulo numerical finite differencing error."]},{"cell_type": "markdown","metadata": {},"source": ["<a id='ham_const_output'></a>\n","\n","## Step 4.a: Output C code for evaluating the Hamiltonian and Momentum constraint violation \\[Back to [top](#toc)\\]\n","$$\\label{ham_const_output}$$\n","\n","First output C code for evaluating the Hamiltonian constraint violation. For the initial data where `EnableMomentum = True` we must also output C code for evaluating the Momentum constraint violation."]},{"cell_type": "code","execution_count": 5,"metadata": {},"outputs": [{"name": "stdout","output_type": "stream","text": ["Output C function Hamiltonian_constraint() to file BlackHoleID_Ccodes/Hamiltonian_constraint.h\n","Output C function momentum_constraint() to file BlackHoleID_Ccodes/momentum_constraint.h\n"]}],"source": ["import BSSN.BSSN_constraints as bssncon\n","# Now register the Hamiltonian & momentum constraints as gridfunctions.\n","H = gri.register_gridfunctions(\"AUX\",\"H\")\n","MU = ixp.register_gridfunctions_for_single_rank1(\"AUX\", \"MU\")\n","\n","# Generate symbolic expressions for Hamiltonian & momentum constraints\n","import BSSN.BSSN_constraints as bssncon\n","bssncon.BSSN_constraints(add_T4UUmunu_source_terms=False)\n","\n","# Generate otpimized C code for Hamiltonian constraint\n","desc=\"Evaluate the Hamiltonian constraint\"\n","name=\"Hamiltonian_constraint\"\n","outCfunction(\n"," outfile = os.path.join(Ccodesdir,name+\".h\"), desc=desc, name=name,\n"," params = \"\"\"const paramstruct *restrict params, REAL *restrict xx[3],\n"," REAL *restrict in_gfs, REAL *restrict aux_gfs\"\"\",\n"," body = fin.FD_outputC(\"returnstring\",lhrh(lhs=gri.gfaccess(\"aux_gfs\", \"H\"), rhs=bssncon.H),\n"," params=\"outCverbose=False\").replace(\"IDX4\",\"IDX4S\"),\n"," loopopts = \"InteriorPoints,Read_xxs\")\n","\n","# Generate otpimized C code for momentum constraint\n","desc=\"Evaluate the momentum constraint\"\n","name=\"momentum_constraint\"\n","outCfunction(\n"," outfile = os.path.join(Ccodesdir,name+\".h\"), desc=desc, name=name,\n"," params = \"\"\"const paramstruct *restrict params, REAL *restrict xx[3],\n"," REAL *restrict in_gfs, REAL *restrict aux_gfs\"\"\",\n"," body = fin.FD_outputC(\"returnstring\",\n"," [lhrh(lhs=gri.gfaccess(\"aux_gfs\", \"MU0\"), rhs=bssncon.MU[0]),\n"," lhrh(lhs=gri.gfaccess(\"aux_gfs\", \"MU1\"), rhs=bssncon.MU[1]),\n"," lhrh(lhs=gri.gfaccess(\"aux_gfs\", \"MU2\"), rhs=bssncon.MU[2])],\n"," params=\"outCverbose=False\").replace(\"IDX4\",\"IDX4S\"),\n"," loopopts = \"InteriorPoints,Read_xxs\")"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='enforce3metric'></a>\n","\n","## Step 4.b: Enforce conformal 3-metric $\\det{\\bar{\\gamma}_{ij}}=\\det{\\hat{\\gamma}_{ij}}$ constraint \\[Back to [top](#toc)\\]\n","$$\\label{enforce3metric}$$\n","\n","Then enforce conformal 3-metric $\\det{\\bar{\\gamma}_{ij}}=\\det{\\hat{\\gamma}_{ij}}$ constraint (Eq. 53 of [Ruchlin, Etienne, and Baumgarte (2018)](https://arxiv.org/abs/1712.07658)), as [documented in the corresponding NRPy+ tutorial notebook](Tutorial-BSSN-Enforcing_Determinant_gammabar_equals_gammahat_Constraint.ipynb)\n","\n","Applying curvilinear boundary conditions should affect the initial data at the outer boundary, and will in general cause the $\\det{\\bar{\\gamma}_{ij}}=\\det{\\hat{\\gamma}_{ij}}$ constraint to be violated there. Thus after we apply these boundary conditions, we must always call the routine for enforcing the $\\det{\\bar{\\gamma}_{ij}}=\\det{\\hat{\\gamma}_{ij}}$ constraint:"]},{"cell_type": "code","execution_count": 6,"metadata": {},"outputs": [{"name": "stdout","output_type": "stream","text": ["Output C function enforce_detgammabar_constraint() to file BlackHoleID_Ccodes/enforce_detgammabar_constraint.h\n"]}],"source": ["# Set up the C function for the det(gammahat) = det(gammabar)\n","import BSSN.Enforce_Detgammabar_Constraint as EGC\n","enforce_detg_constraint_symb_expressions = EGC.Enforce_Detgammabar_Constraint_symb_expressions()\n","\n","EGC.output_Enforce_Detgammabar_Constraint_Ccode(Ccodesdir,exprs=enforce_detg_constraint_symb_expressions,\n"," Read_xxs=True)"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='bc_functs'></a>\n","\n","## Step 4.c: Set up boundary condition functions for chosen singular, curvilinear coordinate system \\[Back to [top](#toc)\\]\n","$$\\label{bc_functs}$$\n","\n","Next apply singular, curvilinear coordinate boundary conditions [as documented in the corresponding NRPy+ tutorial notebook](Tutorial-Start_to_Finish-Curvilinear_BCs.ipynb)"]},{"cell_type": "code","execution_count": 7,"metadata": {"scrolled": true},"outputs": [{"name": "stdout","output_type": "stream","text": ["Wrote to file \"BlackHoleID_Ccodes/boundary_conditions/parity_conditions_symbolic_dot_products.h\"\n","Evolved gridfunction \"aDD00\" has parity type 4.\n","Evolved gridfunction \"aDD01\" has parity type 5.\n","Evolved gridfunction \"aDD02\" has parity type 6.\n","Evolved gridfunction \"aDD11\" has parity type 7.\n","Evolved gridfunction \"aDD12\" has parity type 8.\n","Evolved gridfunction \"aDD22\" has parity type 9.\n","Evolved gridfunction \"alpha\" has parity type 0.\n","Evolved gridfunction \"betU0\" has parity type 1.\n","Evolved gridfunction \"betU1\" has parity type 2.\n","Evolved gridfunction \"betU2\" has parity type 3.\n","Evolved gridfunction \"cf\" has parity type 0.\n","Evolved gridfunction \"hDD00\" has parity type 4.\n","Evolved gridfunction \"hDD01\" has parity type 5.\n","Evolved gridfunction \"hDD02\" has parity type 6.\n","Evolved gridfunction \"hDD11\" has parity type 7.\n","Evolved gridfunction \"hDD12\" has parity type 8.\n","Evolved gridfunction \"hDD22\" has parity type 9.\n","Evolved gridfunction \"lambdaU0\" has parity type 1.\n","Evolved gridfunction \"lambdaU1\" has parity type 2.\n","Evolved gridfunction \"lambdaU2\" has parity type 3.\n","Evolved gridfunction \"trK\" has parity type 0.\n","Evolved gridfunction \"vetU0\" has parity type 1.\n","Evolved gridfunction \"vetU1\" has parity type 2.\n","Evolved gridfunction \"vetU2\" has parity type 3.\n","Auxiliary gridfunction \"H\" has parity type 0.\n","Auxiliary gridfunction \"MU0\" has parity type 1.\n","Auxiliary gridfunction \"MU1\" has parity type 2.\n","Auxiliary gridfunction \"MU2\" has parity type 3.\n","Wrote to file \"BlackHoleID_Ccodes/boundary_conditions/EigenCoord_Cart_to_xx.h\"\n"]}],"source": ["import CurviBoundaryConditions.CurviBoundaryConditions as cbcs\n","cbcs.Set_up_CurviBoundaryConditions(os.path.join(Ccodesdir,\"boundary_conditions/\"),Cparamspath=os.path.join(\"../\"))"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='mainc'></a>\n","\n","# Step 5: `Initial_Data_Playground.c`: The Main C Code \\[Back to [top](#toc)\\]\n","$$\\label{mainc}$$"]},{"cell_type": "code","execution_count": 8,"metadata": {},"outputs": [],"source": ["# Part P0: Set the number of ghost cells, from NRPy+'s FD_CENTDERIVS_ORDER\n","# set REAL=double, so that all floating point numbers are stored to at least ~16 significant digits.\n","\n","with open(os.path.join(Ccodesdir,\"Initial_Data_Playground_REAL__NGHOSTS.h\"), \"w\") as file:\n"," file.write(\"\"\"\n","// Part P0.a: Set the number of ghost cells, from NRPy+'s FD_CENTDERIVS_ORDER\n","#define NGHOSTS \"\"\"+str(int(par.parval_from_str(\"finite_difference::FD_CENTDERIVS_ORDER\")/2)+1)+\"\"\"\\n\n","// Part P0.b: Set the numerical precision (REAL) to double, ensuring all floating point\n","// numbers are stored to at least ~16 significant digits\n","#define REAL double\\n\"\"\")"]},{"cell_type": "code","execution_count": 9,"metadata": {},"outputs": [{"name": "stdout","output_type": "stream","text": ["Writing BlackHoleID_Ccodes//Initial_Data_Playground.c\n"]}],"source": ["%%writefile $Ccodesdir/Initial_Data_Playground.c\n","\n","// Step P0: Define REAL and NGHOSTS. This header is generated by NRPy+.\n","#include \"Initial_Data_Playground_REAL__NGHOSTS.h\"\n","\n","#include \"declare_Cparameters_struct.h\"\n","\n","// Step P1: Import needed header files\n","#include \"stdio.h\"\n","#include \"stdlib.h\"\n","#include \"math.h\"\n","#ifndef M_PI\n","#define M_PI 3.141592653589793238462643383279502884L\n","#endif\n","#ifndef M_SQRT1_2\n","#define M_SQRT1_2 0.707106781186547524400844362104849039L\n","#endif\n","\n","// Step P2: Declare the IDX4S(gf,i,j,k) macro, which enables us to store 4-dimensions of\n","// data in a 1D array. In this case, consecutive values of \"i\" \n","// (all other indices held to a fixed value) are consecutive in memory, where \n","// consecutive values of \"j\" (fixing all other indices) are separated by \n","// Nxx_plus_2NGHOSTS0 elements in memory. Similarly, consecutive values of\n","// \"k\" are separated by Nxx_plus_2NGHOSTS0*Nxx_plus_2NGHOSTS1 in memory, etc.\n","#define IDX4S(g,i,j,k) \\\n","( (i) + Nxx_plus_2NGHOSTS0 * ( (j) + Nxx_plus_2NGHOSTS1 * ( (k) + Nxx_plus_2NGHOSTS2 * (g) ) ) )\n","#define IDX4ptS(g,idx) ( (idx) + (Nxx_plus_2NGHOSTS0*Nxx_plus_2NGHOSTS1*Nxx_plus_2NGHOSTS2) * (g) )\n","#define IDX3S(i,j,k) ( (i) + Nxx_plus_2NGHOSTS0 * ( (j) + Nxx_plus_2NGHOSTS1 * ( (k) ) ) )\n","#define LOOP_REGION(i0min,i0max, i1min,i1max, i2min,i2max) \\\n"," for(int i2=i2min;i2<i2max;i2++) for(int i1=i1min;i1<i1max;i1++) for(int i0=i0min;i0<i0max;i0++)\n","#define LOOP_ALL_GFS_GPS(ii) _Pragma(\"omp parallel for\") \\\n"," for(int (ii)=0;(ii)<Nxx_plus_2NGHOSTS_tot*NUM_EVOL_GFS;(ii)++)\n","\n","// Step P3: Set UUGF and VVGF macros, as well as xxCart()\n","#include \"boundary_conditions/gridfunction_defines.h\"\n","\n","// Step P4: Set xxCart(const paramstruct *restrict params, \n","// REAL *restrict xx[3],\n","// const int i0,const int i1,const int i2, \n","// REAL xCart[3]),\n","// which maps xx->Cartesian via\n","// {xx[0][i0],xx[1][i1],xx[2][i2]}->{xCart[0],xCart[1],xCart[2]}\n","#include \"xxCart.h\"\n","\n","// Step P5: Defines set_Nxx_dxx_invdx_params__and__xx(const int EigenCoord, const int Nxx[3], \n","// paramstruct *restrict params, REAL *restrict xx[3]),\n","// which sets params Nxx,Nxx_plus_2NGHOSTS,dxx,invdx, and xx[] for\n","// the chosen Eigen-CoordSystem if EigenCoord==1, or\n","// CoordSystem if EigenCoord==0.\n","#include \"set_Nxx_dxx_invdx_params__and__xx.h\"\n","\n","// Step P6: Include basic functions needed to impose curvilinear\n","// parity and boundary conditions.\n","#include \"boundary_conditions/CurviBC_include_Cfunctions.h\"\n","\n","// Step P8: Include function for enforcing detgammabar constraint.\n","#include \"enforce_detgammabar_constraint.h\"\n","\n","// Step P10: Declare function necessary for setting up the initial data.\n","// Step P10.a: Define BSSN_ID() for BrillLindquist initial data\n","\n","// Step P10.b: Set the generic driver function for setting up BSSN initial data\n","#include \"initial_data.h\"\n","\n","// Step P11: Declare function for evaluating Hamiltonian constraint (diagnostic)\n","#include \"Hamiltonian_constraint.h\" \n","#include \"momentum_constraint.h\" \n","\n","// main() function:\n","// Step 0: Read command-line input, set up grid structure, allocate memory for gridfunctions, set up coordinates\n","// Step 1: Set up initial data to an exact solution\n","// Step 2: Start the timer, for keeping track of how fast the simulation is progressing.\n","// Step 3: Integrate the initial data forward in time using the chosen RK-like Method of \n","// Lines timestepping algorithm, and output periodic simulation diagnostics \n","// Step 3.a: Output 2D data file periodically, for visualization\n","// Step 3.b: Step forward one timestep (t -> t+dt) in time using \n","// chosen RK-like MoL timestepping algorithm\n","// Step 3.c: If t=t_final, output conformal factor & Hamiltonian \n","// constraint violation to 2D data file\n","// Step 3.d: Progress indicator printing to stderr\n","// Step 4: Free all allocated memory\n","int main(int argc, const char *argv[]) {\n"," paramstruct params;\n","#include \"set_Cparameters_default.h\"\n"," \n"," // Step 0a: Read command-line input, error out if nonconformant\n"," if((argc != 4) || atoi(argv[1]) < NGHOSTS || atoi(argv[2]) < NGHOSTS || atoi(argv[3]) < 2 /* FIXME; allow for axisymmetric sims */) {\n"," fprintf(stderr,\"Error: Expected three command-line arguments: ./BrillLindquist_Playground Nx0 Nx1 Nx2,\\n\");\n"," fprintf(stderr,\"where Nx[0,1,2] is the number of grid points in the 0, 1, and 2 directions.\\n\");\n"," fprintf(stderr,\"Nx[] MUST BE larger than NGHOSTS (= %d)\\n\",NGHOSTS);\n"," exit(1);\n"," }\n"," // Step 0b: Set up numerical grid structure, first in space...\n"," const int Nxx[3] = { atoi(argv[1]), atoi(argv[2]), atoi(argv[3]) };\n"," if(Nxx[0]%2 != 0 || Nxx[1]%2 != 0 || Nxx[2]%2 != 0) {\n"," fprintf(stderr,\"Error: Cannot guarantee a proper cell-centered grid if number of grid cells not set to even number.\\n\");\n"," fprintf(stderr,\" For example, in case of angular directions, proper symmetry zones will not exist.\\n\");\n"," exit(1);\n"," }\n","\n"," // Step 0c: Set free parameters, overwriting Cparameters defaults \n"," // by hand or with command-line input, as desired.\n","#include \"free_parameters.h\"\n","\n"," // Step 0d: Uniform coordinate grids are stored to *xx[3]\n"," REAL *xx[3];\n"," // Step 0d.i: Set bcstruct\n"," bc_struct bcstruct;\n"," {\n"," int EigenCoord = 1;\n"," // Step 0d.ii: Call set_Nxx_dxx_invdx_params__and__xx(), which sets\n"," // params Nxx,Nxx_plus_2NGHOSTS,dxx,invdx, and xx[] for the\n"," // chosen Eigen-CoordSystem.\n"," set_Nxx_dxx_invdx_params__and__xx(EigenCoord, Nxx, ¶ms, xx);\n"," // Step 0d.iii: Set Nxx_plus_2NGHOSTS_tot\n","#include \"set_Cparameters-nopointer.h\"\n"," const int Nxx_plus_2NGHOSTS_tot = Nxx_plus_2NGHOSTS0*Nxx_plus_2NGHOSTS1*Nxx_plus_2NGHOSTS2;\n"," // Step 0e: Find ghostzone mappings; set up bcstruct\n","#include \"boundary_conditions/driver_bcstruct.h\"\n"," // Step 0e.i: Free allocated space for xx[][] array\n"," for(int i=0;i<3;i++) free(xx[i]);\n"," }\n"," \n"," // Step 0f: Call set_Nxx_dxx_invdx_params__and__xx(), which sets\n"," // params Nxx,Nxx_plus_2NGHOSTS,dxx,invdx, and xx[] for the\n"," // chosen (non-Eigen) CoordSystem.\n"," int EigenCoord = 0;\n"," set_Nxx_dxx_invdx_params__and__xx(EigenCoord, Nxx, ¶ms, xx);\n","\n"," // Step 0g: Set all C parameters \"blah\" for params.blah, including\n"," // Nxx_plus_2NGHOSTS0 = params.Nxx_plus_2NGHOSTS0, etc.\n","#include \"set_Cparameters-nopointer.h\"\n"," const int Nxx_plus_2NGHOSTS_tot = Nxx_plus_2NGHOSTS0*Nxx_plus_2NGHOSTS1*Nxx_plus_2NGHOSTS2;\n","\n"," // Step 0j: Error out if the number of auxiliary gridfunctions outnumber evolved gridfunctions.\n"," // This is a limitation of the RK method. You are always welcome to declare & allocate \n"," // additional gridfunctions by hand.\n"," if(NUM_AUX_GFS > NUM_EVOL_GFS) {\n"," fprintf(stderr,\"Error: NUM_AUX_GFS > NUM_EVOL_GFS. Either reduce the number of auxiliary gridfunctions,\\n\");\n"," fprintf(stderr,\" or allocate (malloc) by hand storage for *diagnostic_output_gfs. \\n\");\n"," exit(1);\n"," }\n"," \n"," // Step 0k: Allocate memory for gridfunctions\n","#include \"MoLtimestepping/RK_Allocate_Memory.h\"\n"," REAL *restrict auxevol_gfs = (REAL *)malloc(sizeof(REAL) * NUM_AUXEVOL_GFS * Nxx_plus_2NGHOSTS_tot);\n"," \n"," // Step 1: Set up initial data to an exact solution\n"," initial_data(¶ms, xx, y_n_gfs);\n","\n"," // Step 1b: Apply boundary conditions, as initial data \n"," // are sometimes ill-defined in ghost zones.\n"," // E.g., spherical initial data might not be\n"," // properly defined at points where r=-1.\n"," apply_bcs_curvilinear(¶ms, &bcstruct, NUM_EVOL_GFS,evol_gf_parity, y_n_gfs);\n"," enforce_detgammabar_constraint(¶ms, xx, y_n_gfs);\n","\n"," // Evaluate Hamiltonian & momentum constraint violations\n"," Hamiltonian_constraint(¶ms, xx, y_n_gfs, diagnostic_output_gfs);\n"," momentum_constraint( ¶ms, xx, y_n_gfs, diagnostic_output_gfs);\n","\n"," /* Step 2: 2D output: Output conformal factor (CFGF) and constraint violations (HGF, MU0GF, MU1GF, MU2GF). */\n"," const int i0MIN=NGHOSTS; // In spherical, r=Delta r/2.\n"," const int i1mid=Nxx_plus_2NGHOSTS1/2;\n"," const int i2mid=Nxx_plus_2NGHOSTS2/2;\n"," LOOP_REGION(NGHOSTS,Nxx_plus_2NGHOSTS0-NGHOSTS, i1mid,i1mid+1, NGHOSTS,Nxx_plus_2NGHOSTS2-NGHOSTS) {\n"," REAL xCart[3];\n"," xxCart(¶ms, xx, i0,i1,i2, xCart);\n"," int idx = IDX3S(i0,i1,i2);\n"," printf(\"%e %e %e %e %e %e %e\\n\",xCart[0],xCart[1], y_n_gfs[IDX4ptS(CFGF,idx)],\n"," log10(fabs(diagnostic_output_gfs[IDX4ptS(HGF,idx)])),\n"," log10(fabs(diagnostic_output_gfs[IDX4ptS(MU0GF,idx)])+1e-200),\n"," log10(fabs(diagnostic_output_gfs[IDX4ptS(MU1GF,idx)])+1e-200),\n"," log10(fabs(diagnostic_output_gfs[IDX4ptS(MU2GF,idx)])+1e-200));\n"," }\n"," // Step 4: Free all allocated memory\n","#include \"boundary_conditions/bcstruct_freemem.h\"\n","#include \"MoLtimestepping/RK_Free_Memory.h\"\n"," free(auxevol_gfs);\n"," for(int i=0;i<3;i++) free(xx[i]);\n","\n"," return 0;\n","}"]},{"cell_type": "code","execution_count": 10,"metadata": {},"outputs": [{"name": "stdout","output_type": "stream","text": ["Compiling executable...\n","Executing `gcc -Ofast -fopenmp -march=native -funroll-loops BlackHoleID_Ccodes/Initial_Data_Playground.c -o Initial_Data_Playground -lm`...\n","Finished executing in 2.815635919570923 seconds.\n","Finished compilation.\n","Executing `taskset -c 0,1,2,3 ./Initial_Data_Playground 96 96 96`...\n","Finished executing in 0.41163206100463867 seconds.\n","Executing `taskset -c 0,1,2,3 ./Initial_Data_Playground 48 48 48`...\n","Finished executing in 0.2117936611175537 seconds.\n"]}],"source": ["import cmdline_helper as cmd\n","\n","cmd.C_compile(os.path.join(Ccodesdir,\"Initial_Data_Playground.c\"), \"Initial_Data_Playground\")\n","cmd.delete_existing_files(\"out*.txt\")\n","cmd.delete_existing_files(\"out*.png\")\n","args_output_list = [[\"96 96 96\", \"out96.txt\"], [\"48 48 48\", \"out48.txt\"]]\n","for args_output in args_output_list:\n"," cmd.Execute(\"Initial_Data_Playground\", args_output[0], args_output[1])"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='plot'></a>\n","\n","# Step 6: Plotting the initial data \\[Back to [top](#toc)\\]\n","$$\\label{plot}$$\n","\n","Here we plot the evolved conformal factor of these initial data on a 2D grid, such that darker colors imply stronger gravitational fields. Hence, we see the black hole(s) centered at $x/M=\\pm 1$, where $M$ is an arbitrary mass scale (conventionally the [ADM mass](https://en.wikipedia.org/w/index.php?title=ADM_formalism&oldid=846335453) is chosen), and our formulation of Einstein's equations adopt $G=c=1$ [geometrized units](https://en.wikipedia.org/w/index.php?title=Geometrized_unit_system&oldid=861682626)."]},{"cell_type": "code","execution_count": 11,"metadata": {},"outputs": [{"data": {"image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3de5BcdZ3//1d3zy0hF3KRm0xIDKIgRhdIYSJgsq6RgIasJauCXCSwhQK1iOUq4GLiilFBwAuweEusLV1AWSQiUMHlEi9gCN+grCwoIAYNKjGQQCBz6e7fH/Nj5vN5n+nPmTPT3WdmPs9HVarSOafP+XT36ebT/Xnxfheq1WpVAAAAiEYx7wEAAACguZgAAgAARIYJIAAAQGSYAAIAAESGCSAAAEBkmAACAABEhgkgAABAZJgAAgAARIYJIAAAQGSYAAIAAESGCSAAAEBkmAACAABEhgkgAABAZJgAAgAARIYJIAAAQGSYAAIAAESGCSAAAEBkmAACAABEhgkgAABAZJgAAgAARIYJIAAAQGSYAAIAAESGCSAAAEBkmAACAABEhgkgAABAZJgAAgAARIYJIAAAQGSYAAIAAESGCSAAAEBkmAACAABEhgkgAABAZJgAAgAARIYJIAAAQGSYAAIAAESGCSAAAEBkmAACAABEhgkggKZYu3atCoWCNm3aNKz7FwoFrVy5sv/2I488opUrV+qpp55K7Hv66adr9uzZwzrPUO97+umnq1Ao9P/ZY489NHv2bC1btkxr1qxRV1fXsM4vSbfddpv3WAGg3pgAAhgT7rvvPp155pn9tx955BGtWrVq0Angv/3bv+nmm29u+JgmTJig++67T/fdd59uvfVWfeYzn9Eee+yhs846S4cffrj++Mc/Duu4t912m1atWlXn0QLAgJa8BwAAQ/GWt7xlyPvOnTu3gSMZUCwWE+M69dRT9aEPfUjvete79N73vlf3339/U8YCAFnwCyCA3Jx++umaNGmSHn/8cR133HGaNGmSOjs79bGPfSyxhOouAa9du1YnnniiJGnx4sX9y7Br167tP65dxr366qt1zDHHaK+99tIee+yhN77xjfriF7+onp6euj+uJUuW6KyzztIvf/lLbdiwof/fb7jhBi1ZskT77ruvJkyYoIMPPlif/OQntWvXLu85ufrqq/sf8yt/Xvmls5mPA8D4xS+AAHLV09OjZcuWacWKFfrYxz6mDRs26N///d81depUXXLJJYPe5/jjj9fnPvc5XXTRRbr66qt12GGHSQr/8vfEE0/opJNO0pw5c9TW1qZf/epXuvTSS/Xoo4/q29/+dt0f17Jly3TNNddow4YNOuaYYyRJv/vd73Tcccfp/PPP1x577KFHH31UX/jCF7Rx40bdddddkvqWr3ft2qUf/OAHuu+++/qPt+++++byOACMT0wAAeSqu7tbq1at6v9F7+1vf7s2bdqk733vezUngK961av02te+VpJ0yCGHDGl5+Iorruj/e6VS0dFHH60ZM2boQx/6kL70pS9p2rRpdXg0Aw444ABJ0tatW/v/7VOf+lT/36vVqt761rfq4IMP1tve9jb9+te/1rx58zR37lztvffekgZf9m724wAwPrEEDCBXhUJB7373u71/mzdvnv7whz/U9TybN2/WsmXLNGPGDJVKJbW2turUU09VuVzWb3/727qeS+qb4FlPPvmkTjrpJO2zzz79Y3jb294mSfq///u/IR232Y8DwPjEL4AAcjVx4kR1dHR4/9be3q7du3fX7RxbtmzR0Ucfrde97nX68pe/rNmzZ6ujo0MbN27UOeeco5dffrlu53rFKxPY/fbbT5L04osv6uijj1ZHR4c++9nP6qCDDtLEiRP19NNP6z3vec+QxpDH4wAwPjEBBDDu/fCHP9SuXbv03//93/1Ls5L00EMPNeyc69atkyQtWrRIknTXXXdp69atuueee/p/9ZOk559/fsjHzONxABifWAIGMCa1t7dL0pB+9SoUCt59pL4l2m984xsNGdudd96pb37zm1q4cKGOOuqommOQpOuuuy5x/1qPrdmPA8D4xS+AAMakQw89VJL09a9/XZMnT1ZHR4fmzJmjGTNmJPZ9xzveoba2Nn3gAx/Qv/7rv2r37t269tpr9dxzz41oDJVKpb/OX1dXl7Zs2aLbb79dN954ow4++GDdeOON/fsuXLhQ06ZN09lnn61Pf/rTam1t1Xe/+1396le/Shz3jW98oyTpC1/4gpYuXapSqaR58+Y17HEAiA+/AAIYk+bMmaOrrrpKv/rVr7Ro0SLNnz9fP/rRjwbd9/Wvf71uuukmPffcc3rPe96j8847T29+85v1la98ZURjePnll7VgwQItWLBAS5cu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NWwU9/1fMl/QS4Wx/diAV4yv/8qNIbfddpuefPJJHXnkkfr4xz+u/fffX5/4xCf02GOP5T00AAAwzjEBzNG+++6rCy+8UI899phuuOEG/fWvf9X8+fP11re+VS+/HP4lAgAAYLhYAh4l5s+fr6eeekqPPPKINm/erJ6eHk2YMKHh573mmmt02WWX6ZlnntEb3vAGXXXVVTr66KMbft6xZqyXjMmiXBl73wvdMjCJVm+mvZst9eIu+5Z/+0TwPKWD5g4cx2xrMWVhWpxWcWWzHFzxV49HJXsdtBRHX9u1ekmWdgHGP67znN13330666yztM8+++irX/2qTjvtNG3dulVTpkxp+LlvuOEGnX/++br44ou1efNmHX300Vq6dKm2bNnS8HMDAID8MAHMyRe/+EUdfPDBOuGEEzRp0iT97Gc/0wMPPKCPfOQj2nPPPZsyhiuuuEIrVqzQmWeeqYMPPlhXXXWVOjs7de211zbl/AAAIB8sAefkk5/8pGbNmqV/+qd/UqFQ0Jo1awbd74orrmjI+bu7u/Xggw/qk5/8pPfvS5Ys0S9+8YvE/l1dXerq6uq/vXPnzoaMCwAANB4TwJwcc8wxKhQK+s1vflNzn0Khcbmzbdu2qVwua++99/b+fe+999af//znxP6rV6/WqlWrGjYeAADQPEwAc3LPPffkPQRJyUlmtVoddOJ54YUX6oILLui/vXPnTnV2djZ8fAAAoP6YAOZk4cKFWr58uZYtW6bXv/71TT//zJkzVSqVEr/2/fWvf038KihJ7e3tam9vb9bwAABAA/E/geTkn//5n/XLX/5S8+fP10EHHaSPf/zj+ulPf1qzLVy9tbW16fDDD9edd97p/fudd96phQsXNmUMAAAgH/wCmJPTTz9dp59+urq6uvSTn/xE69at0/ve9z719PTo+OOP1wknnKB3vvOdmjhxYsPGcMEFF+iUU07REUccoQULFujrX/+6tmzZorPPPrth5xyrSvIn5uO5GVTJ1nur5N8mLo1bV8+2YOu1LdommxZuzt/dOn+DnmfKQG1Oe5zEeZxxjIW6f1biOhjH7PsbiAG/AOasvb1dxx9/vK677jpt3bpVt956q1796lfrkksu0cyZM/Wud71LP//5zxty7ve973266qqr9JnPfEZvfvObtWHDBt1222064IADGnI+AAAwOjABzNnpp5+u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O3bskCTtfLEy6P4AgNHtlc9vfgeKExPAiH3iE5/Q1772Nb300kt6y1veoltvvbXmvqtXr9aqVasS/37AYU81cIQAgEb729/+pqlTp+Y9DDQZS8DjyMqVKwedpLkeeOABHXHEEZKkbdu2afv27frDH/6gVatWaerUqbr11ltVKCR7sNpfAJ9//nkdcMAB2rJlS1QfHDt37lRnZ6eefvrpaJZMYnzMEo87pscd42OW+lZyZs2apeeee0577rln3sNBkzEBHEe2bdumbdu2BfeZPXu2Ojo6Ev/+xz/+UZ2dnfrFL36hBQsWpJ7rlQxgbNmRGB93jI9Z4nHH9LhjfMxSvI8bfVgCHkdmzpypmTNnDuu+r3wPcH/lAwAA4xMTwAht3LhRGzdu1FFHHaVp06bpySef1CWXXKK5c+cO6dc/AAAwtpVWrly5Mu9BoLm2b9+uK6+8Ul/84hd1xRVX6K677tLChQu1Zs0aTZs2bcjHKZVKWrRokVpa4voeEePjjvExSzzumB53jI9ZivdxgwwgAABAdKjgCwAAEBkmgAAAAJFhAggAABAZJoAAAACRYQKIuli2bJlmzZqljo4O7bvvvjrllFO0devWvIfVME899ZRWrFihOXPmaMKECZo7d64+/elPq7u7O++hNdyll16qhQsXauLEieO2e8A111yjOXPmqKOjQ4cffrh++tOf5j2khtuwYYPe/e53a7/99lOhUNAPf/jDvIfUcKtXr9b8+fM1efJk7bXXXlq+fLkee+yxvIfVUNdee63mzZunKVOmaMqUKVqwYIFuv/32vIeFHDABRF0sXrxYN954ox577DHddNNNeuKJJ/Te974372E1zKOPPqpKpaLrrrtOv/nNb3TllVfqP/7jP3TRRRflPbSG6+7u1oknnqgPf/jDeQ+lIW644Qadf/75uvjii7V582YdffTRWrp0qbZs2ZL30Bpq165detOb3qSvfe1reQ+lae69916dc845uv/++3XnnXeqt7dXS5Ys0a5du/IeWsPsv//++vznP69NmzZp06ZN+vu//3udcMIJ+s1vfpP30NBklIFBQ6xbt07Lly9XV1eXWltb8x5OU1x22WW69tpr9eSTT+Y9lKZYu3atzj//fD3//PN5D6WujjzySB122GG69tpr+//t4IMP1vLly7V69eocR9Y8hUJBN998s5YvX573UJrq2Wef1V577aV7771XxxxzTN7DaZrp06frsssu04oVK/IeCpqIXwBRd9u3b9d3v/tdLVy4MJrJn9TXWH369Ol5DwMj0N3drQcffFBLlizx/n3JkiX6xS9+kdOo0Cw7duyQpGjex+VyWddff7127dpFF6gIMQFE3XziE5/QHnvsoRkzZmjLli265ZZb8h5S0zzxxBP66le/qrPPPjvvoWAEtm3bpnK5rL333tv797333lt//vOfcxoVmqFareqCCy7QUUcdpUMPPTTv4TTUww8/rEmTJqm9vV1nn322br75Zh1yyCF5DwtNxgQQNa1cuVKFQiH4Z9OmTf37f/zjH9fmzZu1fv16lUolnXrqqRprCYOsj1mStm7dqmOPPVYnnniizjzzzJxGPjLDedzjWaFQ8G5Xq9XEv2F8Offcc/XrX/9a//Vf/5X3UBruda97nR566CHdf//9+vCHP6zTTjtNjzzySN7DQpPR/A81nXvuuXr/+98f3Gf27Nn9f585c6Zmzpypgw46SAcffLA6Ozt1//33j6mlhayPeevWrVq8eLEWLFigr3/96w0eXeNkfdzj1cyZM1UqlRK/9v31r39N/CqI8eO8887TunXrtGHDBu2///55D6fh2tradOCBB0qSjjjiCD3wwAP68pe/rOuuuy7nkaGZmACiplcmdMPxyi9/XV1d9RxSw2V5zH/605+0ePFiHX744VqzZo2KxbH7g/pIXuvxpK2tTYcffrjuvPNO/eM//mP/v99555064YQTchwZGqFareq8887TzTffrHvuuUdz5szJe0i5qFarY+6zGiPHBBAjtnHjRm3cuFFHHXWUpk2bpieffFKXXHKJ5s6dO6Z+/cti69atWrRokWbNmqXLL79czz77bP+2ffbZJ8eRNd6WLVu0fft2bdmyReVyWQ899JAk6cADD9SkSZNyHt3IXXDBBTrllFN0xBFH9P+yu2XLlnGf73zxxRf1+OOP99/+/e9/r4ceekjTp0/XrFmzchxZ45xzzjn63ve+p1tuuUWTJ0/u/+V36tSpmjBhQs6ja4yLLrpIS5cuVWdnp1544QVdf/31uueee3THHXfkPTQ0WxUYoV//+tfVxYsXV6dPn15tb2+vzp49u3r22WdX//jHP+Y9tIZZs2ZNVdKgf8a70047bdDHfffdd+c9tLq5+uqrqwcccEC1ra2tethhh1XvvffevIfUcHffffegr+tpp52W99AaptZ7eM2aNXkPrWHOOOOM/mv7Va96VfXtb397df369XkPCzmgDiAAAEBkxm5oCQAAAMPCBBAAACAyTAABAAAiwwQQAAAgMkwAAQAAIsMEEAAAIDJMAAEAACLDBBAAACAyTAABAAAiwwQQAIy1a9fqLW95iyRp0aJFKhQK+vznP5/Y77jjjlOhUNDKlSubPEIAGBkmgABgrFu3TieccEL/7c7OTq1Zs8bbZ+vWrbrrrru07777Nnt4ADBiTAABROPZZ5/VPvvso8997nP9//bLX/5SbW1tWr9+vSRp9+7dWr9+vZYtW9a/z7ve9S797W9/089//vP+f1u7dq2WLFmivfbaq3kPAADqhAkggGi86lWv0re//W2tXLlSmzZt0osvvqgPfvCD+shHPqIlS5ZIkv7nf/5H++yzj97whjf036+trU0nn3yy9yvg2rVrdcYZZzT9MQBAPTABBBCV4447TmeddZZOPvlknX322ero6PDyfbfccou3/PuKFStW6MYbb9SuXbu0YcMG7dixQ8cff3wzhw4AddOS9wAAoNkuv/xyHXroobrxxhu1adMmdXR0SJKq1ap+9KMf6frrr0/cZ968eXrta1+rH/zgB7r77rt1yimnqLW1tdlDB4C6YAIIIDpPPvmktm7dqkqloj/84Q+aN2+eJGnjxo3q7u7WUUcdNej9zjjjDF199dV65JFHtHHjxmYOGQDqiiVgAFHp7u7WySefrPe973367Gc/qxUrVugvf/mLpL7l3+OPP16lUmnQ+5500kl6+OGHdeihh+qQQw5p5rABoK74BRBAVC6++GLt2LFDX/nKVzRp0iTdfvvtWrFihW699VatW7dOq1atqnnfadOm6ZlnnmHpF8CYxwQQQDTuueceXXXVVbr77rs1ZcoUSdJ//ud/at68ebr66qv1+OOP653vfGfwGHvuuWczhgoADVWoVqvVvAcBAHm74oor9JOf/ES33XZb3kMBgIYjAwgAkvbff39deOGFeQ8DAJqCXwABAAAiwy+AAAAAkWECCAAAEBkmgAAAAJFhAggAABAZJoAAAACRYQIIAAAQGSaAAAAAkWECCAAAEBkmgAAAAJH5/wCuhcPDQ6g5wgAAAABJRU5ErkJggg==\n","text/plain": ["<IPython.core.display.Image object>"]},"execution_count": 11,"metadata": {},"output_type": "execute_result"}],"source": ["import numpy as np\n","from scipy.interpolate import griddata\n","from pylab import savefig\n","import matplotlib.pyplot as plt\n","import matplotlib.cm as cm\n","from IPython.display import Image\n","\n","x96,y96,valuesCF96,valuesHam96,valuesmomr96,valuesmomtheta96,valuesmomphi96 = np.loadtxt('out96.txt').T #Transposed for easier unpacking\n","\n","\n","pl_xmin = -3.\n","pl_xmax = +3.\n","pl_ymin = -3.\n","pl_ymax = +3.\n","\n","grid_x, grid_y = np.mgrid[pl_xmin:pl_xmax:100j, pl_ymin:pl_ymax:100j]\n","points96 = np.zeros((len(x96), 2))\n","for i in range(len(x96)):\n"," points96[i][0] = x96[i]\n"," points96[i][1] = y96[i]\n","\n","grid96 = griddata(points96, valuesCF96, (grid_x, grid_y), method='nearest')\n","grid96cub = griddata(points96, valuesCF96, (grid_x, grid_y), method='cubic')\n","\n","plt.clf()\n","plt.title(\"Initial Data\")\n","plt.xlabel(\"x/M\")\n","plt.ylabel(\"y/M\")\n","\n","# fig, ax = plt.subplots()\n","#ax.plot(grid96cub.T, extent=(pl_xmin,pl_xmax, pl_ymin,pl_ymax))\n","plt.imshow(grid96.T, extent=(pl_xmin,pl_xmax, pl_ymin,pl_ymax))\n","savefig(\"ID.png\")\n","plt.close()\n","Image(\"ID.png\")\n","# # interpolation='nearest', cmap=cm.gist_rainbow)"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='convergence'></a>\n","\n","# Step 7: Validation: Convergence of numerical errors (Hamiltonian & momentum constraint violations) to zero \\[Back to [top](#toc)\\]\n","$$\\label{convergence}$$\n","\n","**Special thanks to George Vopal for creating the following plotting script.**\n","\n","The equations behind these initial data solve Einstein's equations exactly, at a single instant in time. One reflection of this solution is that the Hamiltonian constraint violation should be exactly zero in the initial data. \n","\n","However, when evaluated on numerical grids, the Hamiltonian constraint violation will *not* generally evaluate to zero due to the associated numerical derivatives not being exact. However, these numerical derivatives (finite difference derivatives in this case) should *converge* to the exact derivatives as the density of numerical sampling points approaches infinity.\n","\n","In this case, all of our finite difference derivatives agree with the exact solution, with an error term that drops with the uniform gridspacing to the fourth power: $\\left(\\Delta x^i\\right)^4$. \n","\n","Here, as in the [Start-to-Finish Scalar Wave (Cartesian grids) NRPy+ tutorial](Tutorial-Start_to_Finish-ScalarWave.ipynb) and the [Start-to-Finish Scalar Wave (curvilinear grids) NRPy+ tutorial](Tutorial-Start_to_Finish-ScalarWaveCurvilinear.ipynb) we confirm this convergence.\n","\n","First, let's take a look at what the numerical error looks like on the x-y plane at a given numerical resolution, plotting $\\log_{10}|H|$, where $H$ is the Hamiltonian constraint violation:"]},{"cell_type": "code","execution_count": 12,"metadata": {},"outputs": [{"data": {"text/plain": ["<Figure size 432x288 with 0 Axes>"]},"metadata": {},"output_type": "display_data"},{"data": {"image/png": "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ABeZXf8dwItFZALJhf7zo24rzVIKoNvt/x8RjS3GGmpdpLGGHbApFmcjmar+GQB/nK77WQAnm32mAHwPwK8DWKSqd5iyViIiohDGGqKaeDNBsdgDwFIAkwAWisgaAHep6s5p+30OwJcBnDna5tGsxzIlormAsYbaFWGs4c0ExWITgNMAHADg/QBuRDntnPkugL8A8E+jaxrNCRFe4ImoNsYaaleEsYY3EzT2ROQNAHap6j+mNar/A+CNAI6cvq+qKoALRtxEoqETkaMBfALAQgC7APyhql7ebquIZg/GGqJmeDNBY09VPwPgM+nylIi8GMB/q+odZp+Xeo5dOoo20myn4zAr6XkAzlLVb4rIz6dfv7TdJhHNHow11L6xiDW18WaCoqOqOwBsbLsdNIcooNr6aEwKYFm6vBzAvS22hWjWY6yhkRuPWFMbbyaIiOLwVgAXi8gFSIb1flHL7SEiIuLNBBFRJYNJPa8UkSvN15tUdVP2hYhcAmCt47hTAbwCwJ+q6r+IyK8B+CSA4wfRKCIiGhMscyIimqUGM8LGNlX1lk2oqvfmQEQ+A+BP0i//GcDfDqJBREQ0RjiaExHRLKQ6DjNY3wvgJQAuBfByAD9qtTVERDRY4xFrauPNBBFRHH4PwIdEZB6S2XlPark9REREvJkgIqqk5dSzqn4PwE+32ggiIhouljkREc1OGmHqmYiI4hJjrOm03QAiIiIiIooTMxNEREEaZeqZiIhiEmes4c0EEVGIIsqxv4mIKCKRxhqWORERERERUSPMTBARVaHxdYojIqLIRBhreDNBRBSgADTC1DMREcUj1ljDmwkiohDVKJ8WERFRRCKNNewzQUREREREjTAzQURUQYypZyIiikuMsYY3E0REVUSYeiYioshEGGtEI5wcg4holETkIgArB3Cqbap6wgDOQ0REs0yssYY3E0RERERE1Ag7YBMRERERUSO8mSAiIiIiokZ4M0FERERERI3wZoKIiIiIiBrhzQQRERERETXCmwkiIiIiImqENxNERERERNQIbyaIiIiIiKgR3kwQEREREVEjvJkgIiIiIqJGeDNBRERERESN8GaCiIiIiIga4c0EERERERE1wpsJIiIiIiJqhDcTRERERETUCG8miIiIiIioEd5MEBERERFRI7yZICIiIiKiRngzQUREREREjfBmgoiIiIiIGuHNBBERERERNcKbCSIiIiIiaoQ3E0RERERE1AhvJoiIiIiIqBHeTBARERERUSO8mSAiIiIiokZ4M0FERERERI3wZoKIiIiIiBrhzQQRERERETXCmwkiIiIiImqENxNERERERNQIbyaIiIiIiKgR3kwQEREREVEjvJkgIiIiIqJGeDNBRERERESN8GaCiIiIiIga4c0EERERERE1wpsJIiIiIiJqhDcTRERERETUCG8miIiIiIioEd5MEBERERFRI7yZICIiIiKiRngzQUREREREjcxruwFEROPu1S9bog8/MtX3ea66dsfFqnrCAJpERESzTKyxhjcTREQBDz8yhcsvXt/3eSb2+tHKATSHiIhmoVhjDW8miIgCFEAX3babQUREs1issYY3E0REQYopje8CT0REMYkz1rADNhERERERNcLMBBFRQJJ61rabQUREs1issYY3E0REFcRYx0pERHGJMdbwZoKIKEChmNL4nhYREVE8RhlrROQEAB8CMAHgb1X1fU3PxT4TRERERERzhIhMAPgogNcAOAzAb4rIYU3Px8wEEVEFMdaxEhFRXEYUa44FcIuq3gYAIvI5ACcCuKHJyXgzQUQUoACmeDNBRERDNMJYsw+Au8zXdwN4QdOT8WaCiIiIiGj2WCkiV5qvN6nqJvO1OI5pfBfDmwkiogpY5kRERMM2oFizTVU3zrD9bgDrzNf7Ari36YvxZoKIKEABjuZERERDNcJYcwWA54rIAQDuAfAbAH6r6cl4M0FERERENEeo6i4ReTOAi5EMDfspVb2+6fl4M0FEVEF80wgREVFsRhVrVPUbAL4xiHPxZoKIKEChHM2JiIiGKtZYw5sJIqIQBabiu74TEVFMIo01nAGbiIiIiIgaYWaCiChAwT4TREQ0XLHGGt5MEBEFCaacc/wQERENSpyxhmVORERERETUCDMTREQBCqAbYac4IiKKR6yxhjcTREQVxJh6JiKiuMQYa1jmREREREREjTAzQUQUoIjzaREREcUj1ljDmwkiogq6Gt8FnoiI4hJjrGGZExERERERNcLMBBFRQKypZyIiikessYY3E5EQkTUAvgzgWQBTAP63qt7XbqtothCRgwF8CMAqACer6qXttmi8KARTTOTSLMc4Q6MgIpeq6kvbbsc4ijXW8GYiHtsA/JyqdkXkdwD8HwDvbbdJNBuISAfAxwD8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\n","text/plain": ["<Figure size 864x864 with 8 Axes>"]},"metadata": {"needs_background": "light"},"output_type": "display_data"}],"source": ["RefData=[valuesHam96,valuesmomr96,valuesmomtheta96,valuesmomphi96]\n","SubTitles=[\"\\mathcal{H}\",'\\mathcal{M}^r',r\"\\mathcal{M}^{\\theta}\",\"\\mathcal{M}^{\\phi}\"]\n","axN = [] #this will let us automate the subplots in the loop that follows\n","grid96N = [] #we need to calculate the grid96 data for each constraint for use later\n","plt.clf()\n","\n","# We want to create four plots. One for the Hamiltonian, and three for the momentum\n","# constraints (r,th,ph)\n","# Define the size of the overall figure\n","fig = plt.figure(figsize=(12,12)) # 8 in x 8 in\n","\n","num_plots = 4\n","\n","if dictID[initial_data_string].EnableMomentum == False:\n"," num_plots = 1\n","\n","\n","for p in range(num_plots):\n"," grid96 = griddata(points96, RefData[p], (grid_x, grid_y), method='nearest')\n"," grid96N.append(grid96)\n"," grid96cub = griddata(points96, RefData[p], (grid_x, grid_y), method='cubic')\n","\n"," #fig, axes = plt.subplots(nrows=2, ncols=2, sharex=True, sharey=True)\n","\n","\n"," #Generate the subplot for the each constraint\n"," ax = fig.add_subplot(221+p)\n"," axN.append(ax) # Grid of 2x2\n"," \n"," axN[p].set_xlabel('x/M')\n"," axN[p].set_ylabel('y/M')\n"," axN[p].set_title('$96^3$ Numerical Err.: $log_{10}|'+SubTitles[p]+'|$')\n","\n"," fig96cub = plt.imshow(grid96cub.T, extent=(pl_xmin,pl_xmax, pl_ymin,pl_ymax))\n"," cb = plt.colorbar(fig96cub)\n"," \n","# Adjust the spacing between plots\n","plt.tight_layout(pad=4)"]},{"cell_type": "markdown","metadata": {},"source": ["Next, we set up the same initial data but on a lower-resolution, $48^3$ grid. Since the constraint violation (numerical error associated with the fourth-order-accurate, finite-difference derivatives) should converge to zero with the uniform gridspacing to the fourth power: $\\left(\\Delta x^i\\right)^4$, we expect the constraint violation will increase (relative to the $96^3$ grid) by a factor of $\\left(96/48\\right)^4$. Here we demonstrate that indeed this order of convergence is observed as expected. I.e., at all points *except* at the points immediately surrounding the coordinate center of the black hole (due to the spatial slice excising the physical singularity at this point through [the puncture method](http://gr.physics.ncsu.edu/UMD_June09.pdf)) exhibit numerical errors that drop as $\\left(\\Delta x^i\\right)^4$."]},{"cell_type": "code","execution_count": 13,"metadata": {},"outputs": [{"data": {"text/plain": ["<Figure size 432x288 with 0 Axes>"]},"metadata": {},"output_type": "display_data"},{"data": {"image/png": "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MWO82m5hYSFLly4lJyfHq+2KVEXAFx7W2nnW2gL31WXA8U7mkfDwyiuvUL9+fVJTUx3LULduXe6//352796tEwFF/ED9jQSSxYsXA3DWWWd5td327dtjrWX+/PlebVekKgK+8CjlSkC7f8Wnjhw5wty5cykqKiI6OtrRLFdffTXGGN577z1Hc4iEIfU34pjc3FwyMjJo2rQpiYmJXm177NixALzzzjtebVekKgKi8DDGLDDGfF/G5dwSj7kbKADKXNjAGDPBGLPKGLNqz549/oouIej999+nsLCQs88+2+/T6JbWvHlzmjZtyuTJk+eBbh4AACAASURBVDXvuogXqL+RYLB06VKstcXn+nnTmWeeiTGGr776yutti1QmyukAANbaoRXdb4y5DBgBnGnL+e/LWjsFmALQq1cv/YcmNfb8888DMGnSJIeTuDRr1ox169bx7bff0q1bN6fjiAQ19TcSDBYtWkRkZCT33nuv19uuW7cuLVq0YNu2bRw8eNDrIyoiFQmIEY+KGGPOAm4HRlprc53OI6EtJyeH1atXk5iYSO/evZ2OA8A111wDwNNPP+1wEpHQpv5GAsXHH39M586dqVevnk/a9xxupVEP8beALzyA54F6wHxjzDpjjOYWFZ+ZMWMGRUVFjBgxwvHDrDzGjRtHREQEH374oQ63EvEt9TfiuEOHDpGWlsbu3bt9to0HH3yQ2NhYTasrflftwsMYU9cYE+mLMGWx1raz1ra01nZzXyb6a9sSfj766COSkpJ44oknnI5SLCEhge7du3Pw4EEtJihhRf2NhKP//ve/APTv399n26hTpw69evXi008/9dk2RMpSaeFhjIkwxowzxnxijMkE0oGdxpgf3Isttfd9TBHf27dvH5988gljx46lRYsWTsf5ndtvv52IiAimTp3qdBQRn1F/IwLvvvsuABdddJFPt7N161Y2bNjAvn37fLodkZKqMuKxCGiLayGlZu69QcnAAFzznD9mjLnEhxlF/OK5557j6NGjDBgwwOko/+PCCy9k9OjRvPvuu+Tl5TkdR8RX1N9I2Pvyyy8BGDq0wnkQau2MM84A0Hoe4ldVKTyGWmsfstamWWuLPDdaa/dZa/9jrb0A0CIDEtSstbz44osA9OzZ0+E0Zbv66qvZv38///73v52OIuIr6m8krO3evZsdO3bQrFkzGjZs6NNt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lyxcuJAzzzyT3NxcunbtytKlS0lKSnI6llTDn//8Z9566y2KioqYPXs255xzjk8WGgo31lpeeOEFRo4cWVx4eFYFDjNh098MGzaMX375hZ9++snpKFKJlStX8tBDDzF+/HimTp1avMaXlG3ixImcdtpp5ObmcsUVV6i4DgKff/45jRo18uksrlUuPKy151lrs621DwD3Aq8Bo3wVLBB49jTm5ubqECAvKSwsZPz48Rw9epTTTjuNJUuW0LhxY6djSQ1ccsklzJo1i6ioKBYsWMDgwYPJzs52OlZQi4iIYOLEifTt27d4soVwXDQznPobz55FHW4V2PLy8jj//PMxxnDNNdc4HScoGGN4//33ue+++5g3bx6vvvqq05GkAtZaPv/8c1JTU4mMjPTZdmo0R6y19gtr7YfW2pA+vqJk4fHTTz8VDxtKzRQWFnL//fezc+dOhg0bxsKFC4vPn5HgdO655zJv3jxiY2NZvnw599xzj9ORglpeXh5r1qzhwIEDxYVHuAvV/qaoqIj09HTatm1L27ZtVXgEuJtuuolt27bRokULunXr5nScoNGiRQvuv/9+hgwZwg033MDmzZudjiTlSEtLY9euXQwbNoxdu3axb98+n2ynKgsIHjLGHHRfDpW4fsgYE9JzAJYsPKTmrLXcddddnHTSSTzyyCNcffXVfPzxx+F6CEnIGTx4MEuXLqVx48ZMmzaNr776SosM1tCPP/5Iz549WbhwYVgWHuHU3zz99NN07NiRzMxM+vfvz7p165yOJOX47LPPeOWVV4iIiGDWrFnF531K1URERNC/f3/y8vI499xzNSFJgPr2228BOO2003j88cdp2bKlT87frMo6HvWstYnuS70S1+tZaxO9niiAlCw8/v73v3P33Xc7nCj4HD16lDFjxvDoo4+yefNm7rvvPl555RWioqKcjiZe1KNHD1atWkWzZs0YOnQobdu21RShNeA5j8xzcnm4FR7h1N8MGjQIgAULFpCYmEhOTo6zgaRMmZmZXHTRRQDce++99OjRw+FEwenGG2+kUaNGfP/99xoZD1CemVvr16/PvHnz6N+/PzExMV7fTnXW8TDGmEuMMfe6r7c0xvTxeqIAUrLw+Oabb5g7d67DiYJLVlYWp59+Oh988AERERG89tprPPjgg2F5zHo4aN26NV9//TVdu3bll19+ITU1lddee83pWEEl3AsPj3Dob3r06EHjxo35/PPPqVu3rgqPAGSt5YorruDw4cP06tWLe++91+lIQatRo0Z88MEHADz++ON8+eWXDieS0jyfQfv372f9+vXOrVxewovAqcA49/XDwAteTxRAShYe9erV06xW1WCtZcCAAaxatYq6deuycOFCrrzySqdjiY81btyYJUuWcPHFF1NUVMSf//xnJk2aRGFhodPRgoLnM8azcnm4Fh6EQX8TGRlJamoq8+bNIz4+nvz8fPLz852OJSU8//zzfPrppzz77LMsXLjQpyfchoPBgwdzyy23AHD++eezf/9+hxNJSZ7TCtq2bcvy5csZN25cJc+omeoUHn2ttdcCRwCstfsB74/BBJC6desCKjxqYsqUKfz0008cf/zxrF27tviwAgl9sbGxTJ8+nYceegiAZ555hptvvtnhVMHBM9Qd7iMehEl/M93X/QAAIABJREFU4zmJ8+BB1+krOp8wcKxdu5abbrqJwYMHc91115GYGFJH+jnm73//OwMHDmT//v1cddVVmmI3gOTk5BAXF0dMTAx9+vThuOOO88l2qlN45BtjIgELYIxJAvxyBqkx5q/GmI3GmB+MMU/4Y5vw+xEPreNRuaKiIh588EFOPfVUJk6cSGpqKmlpabRv397paOJnxhjuueceZs2aRWxsLG+//TZLlixRJ1OJgQMH8uabb5KcnBzuhUdY9DcjRozgo48+olWrVgA63CpAHDx4kLPPPpvCwkJOOukkHR7sRdHR0XzxxRc88cQTzJo1i8mTJzsdSdxycnKIj49n0qRJrF271mfbqU7h8U9gFpBsjHkEWAL83SepSjDGDAbOBbpaazsBT/l6mx4lC4/jjjuOpk2baraecmRnZzNs2DAeeOABli1bxu23387HH39Mw4YNnY4mDho1ahRr1qyhYcOGDBo0iE6dOjFjxgynYwWsdu3acemll1KnTp1wLzzCor9p0qQJI0aMoEGDBoAKj0BgreWSSy5h165dtGvXTtPo+8hNN91Ehw4duOmmm1i1apXTcQTX509UVBTPPPMMGzdu9Nl2qrOA4NvAbcCjwE5glLXWH/9BXAM8Zq096s6R6YdtAr8vPG655RY2b95MRESNlj4JaWlpaXTq1IkFCxYQExPDe++9x2OPPabjYQWAk08+mRUrVnDmmWeyYcMGxowZw/XXX6/j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iIhIIIuIiMj7ZeDll18u8vdPSUnh+eef56effmLTpk3s378ft9udd7xOnTq0adOG/v37c9dddxXrLyQi/q569eo8+uijPProo6xevZqXX36Zb7/9lr179/L222/z9ttvU79+fRITE6latSotWrSgY8eOXHnlldSrV69Iiv/ff/+dRo0aMXXqVC677DKAYp1crsJDRETER+Tv8bDWkpWVRUhIyDm9x9atW4mNjeWXX35h48aNxMXFARASEkJcXBzWWiC7R6NSpUpcfPHFdO/enX79+lGvXr0ivR4RKViLFi2YOnUqAGlpaSxbtoyVK1fy448/snDhQg4ePMjatWvznhMdHU2XLl2oV68ea9asoUWLFrRt25aWLVtSqVKls55rlTtvLCoqSj0eIiIigSwyMpKUlBQAunTpQnp6OrGxscc9x+12s337dn744QdWrFjBxo0bOXr0KLVq1WL79u1s3bo1r7iA7EnrlSpVon379gwePJhq1apx5ZVX0rBhQw2fEvEB4eHhdOrUiU6dOuU9dvToUX755RcWLVrEb7/9RkJCAt999x0ff/wxALNmzcp7blBQEK1bt6ZLly5ER0dz8OBB2rZtS0xMDOXLlz/uXLnzxkqXLp13r1HhISIiEoAiIyPz1v0vVaoU27dv56GHHmLDhg00aNCAbdu2ERsbe9Kkc5fLRVBQEM2aNSMmJoaaNWvSpk0bYmJiqF69ulaeEilhypcvT7du3ejWrdtxj6emprJ582aWLVvGqlWr2Lx5M7t372bnzp2MHTv2uEYHgODgYMqXL0+fPn245ppr2L59O5BdeBw9ehQo3sLDnBigP4iJibErVqxwOgwREZ9hjFlprY1xOg5/U9T5pn///sydO5cGDRqwbt264+ZfRERE0LBhQ8qUKUNUVBTNmzfniiuuICYmhqpVq6q4EAlw6enpeUXJypUr2bhxI7t37yY+Pv6k1bOio6OpWLEiGzduZM2aNVxyySVFFsfp8o16PERERHxEx44dWblyJdWqVeOyyy4jJCSENm3a0LFjR2rWrKniQkROKSwsjObNm9O8efOTjqWmprJ9+3ZiY2NZuXIlWVlZbN68mWbNmlGnTp1ii1E9HiIiAUA9Ht6hfCMicrzT5RttICgiIiIiIl6nwkNERERERLxOhYeIiIiIiHidCg8REREREfE6nyg8jDE3GWM2GGM8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IiIiIiKeU+MhIiIiIiKeU+MhIiIiIiKeU+MhIiIiIiKeU+MhIiIiIiKeU+MhIiIiIiKeU+MhIiIiIiKeU+MhIiIiIiKeU+MhIiIiIiKeU+MhIiIiIiKeU+MhIiIiIiKeU+MhIiIiIiKei4rGw8xqmdknZrbKzL4zs5v8ziQiIsWP6o2IiHcS/A4QogPALc65r80sCVhiZrOdcyv9DiYiIsWK6o2IiEeiYo2Hc26jc+7r4Pl0YBVQw99UIiJS3KjeiIh4Jyoaj+zMrDbQBPgyx/V9zWyxmS3evHmzH9FERKQYUb0REQmvqGo8zKwcMA0Y5JxLy36bc+5551xz51zzypUr+xNQRESKBdUbEZHwi5rGw8wSCRSB15xzb/udR0REiifVGxERb0RF42FmBowHVjnnnvA7j4iIFE+qNyIi3omKxgM4HbgcaG9my4Knc/wOJSIixY7qjYiIR6JiOl3n3GeA+Z1DRESKN9UbERHvRMsaDxERERERiWJqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHNqPERERERExHMJfgcQERERkYIZN24cq1atAiAuLo4BAwbQoEEDn1OJ5E6Nh4iIiEgU2rt3LzfccANlypShdOnSbN26lRIlSjBy5Ei/o4nkKmo2tTKzs8zsezP70cz+43ceEREpnlRvJFr89ttvQGCtx5YtWzj++ONZv369z6lEDi8qGg8ziwfGAWcDJwI9zOxEf1OJiEhxo3oj0SSryahZs+ahf9V4SCSLisYDOBX40Tn3s3NuP/A6cJ7PmUREpPhRvZGokbXGI3vjkXWdSCSKlsajBvBrtsvrg9eJiIiEk+qNRI2stRs1agQ+olmNx8GDB/2MJXJY0dJ4WC7Xub/cwayvmS02s8WbN28uolgiIlLMqN5I1Fi/fj3JyckkJSUBgQYkIyMDfS4lUkVL47EeqJXtck1gQ/Y7OOeed841d841r1y5cpGGExGRYkP1RqLG+vXrD21mBX9ucqX9PCRSRUvj8RVQz8zqmFkJ4FJghs+ZRESk+FG9kajx22+/5dp4aD8PiVRR0Xg45w4ANwCzgFXAm8657/xNJSIixY3qjUQTrfGQaBM1BxB0zr0HvOd3DhERKd5UbyQaZGRksHHjxkM7lgNUqVKFhIQENR4SsaJijYeIiIiI/GnTpk045/6yxiMuLo7q1aur8ZCIpcZDREREJMrkPIZHFh3LQyKZGg8RERGRKJPzqOVZdPRyiWRqPERERESiTM6DB2apUaMG69evxzmX28NEfKXGQ0RERCTKrF+/nlKlSlGpUqW/XF+zZk12797Njh07fEomcnhqPERERESiTNYxPMzsL9frWB4SydR4iIiIiESZnMfwyKJjeUgkU+MhIiIiEmXWr1//t/074M99PtR4SCRS4yEiIiISRQ4ePHhoU6ucqlWrhpmp8ZCIpMZDREREJIps2bKFjIyMXBuPEiVKULVqVe3jIRFJjYeIiIhIFDncMTyy6FgeEqnUeIiIiIhEkcMdwyNL1rE8RCKNGg8RERGRKPLKK68AWuMh0UeNh4iIiEiU2LhxI9OnTwcgMTEx1/uULVuWHTt2sGvXrqKMJpInNR4iIiIiUaJ8+fI0atQIgIEDB/7t9pUrVzJq1CgAunTpUqTZRPKixkNEREQkSpQpU4bKlStTq1YtpkyZwpQpUw7dtn//fi677DLKlCkDwCeffKLZrSSiqPEQERERiRIvvvgiP/30E6eeeipnnHEGmzZtAgJNxvXXX8+yZct45JFHDt1/3rx5fkUV+Rs1HiIiIiJRYOvWrVx77bVs2LCBWrVq8fHHHzN48GAAHnroIcaPH0/fvn258sorAShZsqQaD4koCX4HEBEREZG8zZ8/H4CMjAxOO+004uPjD9328ssvs2/fPurVq4eZccopp7B27Vo1HhJRtMZDREREJArMmzeP+Ph4EhIS6Ny5819uS0lJoX79+pgZAF27dmXHjh3Ur1+fAwcO+BFX5G/UeIiIiIhEgU8//ZQSJUrQvn17kpOTj3jfrl274pzj/PPPJyFBG7hIZFDjISIiIhLhdu/ezXfffceePXs477zz8rx/06ZNqV69OjNmzCA9Pb0IEorkTY2HiIiISIQrU6YMd999NxDa8TnMjK5du/J///d/nHHGGV7HEwmJGg8RERGRKPD+++/TpEkTatWqFdL9zzvvPDIzM1m+fDk7duzwOJ1I3tR4iIiIiES4q666igULFoS0mVWWdu3aUapUKZxzfP755x6mEwmNGg8RERGRCLZ//34mTpwIBHYaD1XJkiU566yzAPjss888ySaSH2o8RERERCLYypUryczMpFKlSpxyyin5emy3bt2AP48BIuKniG88zGyEma02s2/MbLqZVfA7k4iIFD+qNxKplixZAkCnTp0OHacjVOeccw4ANWrUCHsukfyK+MYDmA2c5JxrDPwPuMPnPCIiUjyp3khE+uijj4D8bWaV5eijj6ZRo0akpqaGO5ZIvkV84+Gc+9A5l3XIzYVATT/ziIhI8aR6I5Fq8+bNAJx22mkFevy//vUvPv/8c9avXx/OWCL5FvGNRw5XA+/7HUJERIo91RuJGFWrVqVatWoce+yxBXr8SSedxM6dOxkzZkyYk4nkT4LfAQDMbA5wTC433eWc+7/gfe4CDgCvHWaMvkBfoMB/mCIiUryp3kg0WrhwIS1atMj3/h1ZOnXqBGhmK/FfRDQezrmOR7rdzK4E/g10cM65w4zxPPA8QPPmzXO9j4iIxDbVG4k2r7/+Oj/99BPdu3cv8BgNGjQgISGB77//PozJRPIv4je1MrOzgNuBrs653X7nERGR4kn1RiLRO++8A0CHDh0KPEZcXBy1atVi27Zt7Nu3L1zRRPIt4hsP4CkgCZhtZsvM7Fm/A4mISLGkeiMRZ/HixQC0bt26UOM0a9YMgK+++qrQmUQKKt+bWplZWWCvcy7Tgzx/45w7viiWIyIikUX1RgTWrVtHhQoVKFOmTKHGufDCC3nrrbfYsWNHmJKJ5F+eazzMLM7MeprZu2b2B7Aa2Ghm3wUPtlTP+5giIlLcqd6I/NWOHTvYs2cPDRo0KPRYnTt3BmD58uWFHkukoELZ1OoT4DgCB1I6xjlXyzlXBWhNYJ7z4WbWy8OMIiISG1RvRLL5+uuvAejY8YhzIoSkQoUKpKSk8NZbbxV6LJGCCmVTq47OuYycVzrntgHTgGlmlhj2ZCIiEmtUb0Sy+eGHHwC46qqrwjJeqVKlWL58OQcPHiQuLhp285XiJs9PnXMuwwJqHek+4Y0lIiKxRvVG5K/mzZvHUUcdRd26dcMyXrNmzXDO6Xge4puQ2t3gXOb/9TiLiIjEONUbkT+9/fbbJCQkFPjAgTmdffbZAEyfPj0s44nkV37Wsy00s396lkRERCRA9UZi3o8//sjevXupVy98cyp06dIFgI8//jhsY4rkR36m020H9DOztcAuwAj8ONXYk2QiIhKrVG8k5o0ePRqAyy67LGxjli9fnsqVK7Ny5UoyMzOJj48P29giochP43G2ZylERET+pHojMW/mzJmYGZdffnlYx33ooYe47rrr+OKLL2jVqlVYxxbJS8ibWjnn1gIVgC7BU4XgdSIiImGjeiOxbufOnaxdu5aUlBTKli0b1rF79OhBYmIiM2fODOu4IqEIufEws5uA14AqwdMkM7vRq2AiIhKbVG8k1s2aNQuAgQMHhn3s5ORkUlJSePHFF8M+tkhe8rOpVR/gX865XQBm9ijwBTDWi2AiIhKzVG8kps2cOZOKFStyww03eDJ+5cqV+fHHH1m5ciUnnniiJ8sQyU1+ZrUyIDPb5czgdSIiIuGkeiMxKzMzk2nTptGyZUsSE705XuaVV14JwLhx4zwZX+Rw8tN4vAx8aWb3m9n9wEJgvCepREQklqneSMz65JNP2LlzZ9iO3ZGbHj16YGbaz0OKXEibWlng0z8VmAu0IvDL01XOuaXeRRMRkVijeiOx7tlnnwWgb9++ni0jaz+PX375hW3btlGpUiXPliWSXb6OXO6c+9o5N8Y5N1pFQEREwk31RmKZc46PPvqI+Ph4zjrrLE+XdemllwIwY8YMT5cjkp2OXC4iIpFG9UZi0pIlS9ixYwcnnXQSJUqU8HRZw4YNo1atWrzxxhueLkcku/w0Hu2AL8zsJzP7xsxWmNk3XgUTiWYjRozg66+/BuC7775jxYoVPicSiSqqNxKTso5Wfv3113u+rLi4q5uZVAAAIABJREFUOK688kpmzZrFb7/95vnyRCB/+3hcB+gATiJ52LRpE0OGDKFatWocc8wxbNy4kVNOOYX333/f72giEU/1RmLVvn37eO+99+jWrduhWae8Vrp0aZxzjBo1ipEjRxbJMiW25Wcfj1HOubU5Tx7nE4k67733HgDlypWjZs2abN68mS+++MLnVCLRQfVGYtXMmTPZtm0bffv2pWTJkkWyzKwG55VXXiHwpyfiLe3jIRJmWWs2xo0bx4wZM6hTpw6pqals27bN52QiUUP1RmLO0KFDSUxMpFGjRkW2zBo1anDSSSexdetWFixYUGTLldiV3308FmqbW5EjW7x4MQDNmjUDoGnTpgD6UhcJneqNxJSNGzeyfPlyypQpQ7Vq1Yp02YMHDwZg+PDhRbpciU35aTzOBuoC7YEuwL+D/4pIUGZmJhs2bKBcuXKH5kXv0KEDAO+++66f0USiieqNxJSxY8cCcPnllxMXl5//mhVejx49SExMZNasWezevbtIly2xJ89Pt5kNAQhuX3tqju1t+3kdUCSaxMfH06BBA1q2bHnoulNPPRWAChUq+BVLJCqo3kgscs7x4osvAnDzzTcX+fJLly7NqFGjyMjI4O233y7y5UtsCaWtvjTb+Tty3Obt0W1Eosz+/ftZvXr1oc2sAE444QTi4+OL/FcskSikeiMxZ/bs2WzevJn69etTp04dXzL079+f+vXrM2bMGO1kLp4K5X9CdpjzuV0WiWk33HADGRkZNG7c+NB1JUuWpEGDBixYsIDNmzf7mE4k4qneSMwZNWoUycnJjBgxwrcMcXFxtG7dmq+++orPP//ctxxS/IXSeLjDnM/tskjMcs7x1ltvAfyl8QA4/vjjmTt3LlOnTvUjmki0UL2RmLJq1So++OADbrnlFrp27eprllNOOQWAu+66y9ccUryF0nicbGZpZpYONA6ez7pcdHO+iUS4devWsX37duLj46lfv/5fbmvRogUAc+fO9SGZSNRQvZGYct999xEfH8/ll1/udxT69OlD6dKlmTdvHmvWrPE7jhRTeTYezrl451yycy7JOZcQPJ91ObEoQgKY2a1m5szs6KJapkh+ZE2Xe9xxx5GY+Nc/jZNPPhmAzz77rMhziUQL1RuJJVu2bDm0M3f58uV9ThPYybxv374APPDAAz6nkeIqKvZ2NbNawJnAOr+ziBzOF198gZkdmsUqu6xNrzZu3MjGjRuLOpqIhEj1RorK448/TmZmJhdeeOGh6df99p///Ie4uDgmT55Mamqq33GkGIqKxgMYBQxB2/hKhHPOHdpONrsaNWqQlJQEBBoUEYlYqjfiuT179vDUU08BkbV24ZhjjuH6668nIyOD559/3u84UgxFfONhZl2B35xzy/O4X18zW2xmizVzkPihW7duwN93LAcwM0455RTq169Pu3btijqaiIRA9UaKypgxY9i5cyctWrSgQYMGfsf5i7Fjx9KpUydGjBjBrl27/I4jxUxENB5mNsfMvs3ldB5wF3BvXmM45553zjV3zjWvXLmy96FFgg4ePMicOXNYvjzwf5XcGg8IzBjy22+/Ub58eQ4ePFiUEUUkSPVG/LZnzx4ef/xxKlSowOOPP+53nFzdfPPNbN68mSeeeMLvKFLMhNx4WEAvM7s3ePlYM/v7xuwF4Jzr6Jw7KecJ+BmoAyw3s1+AmsDXZnZMOJYrEg4vvfQSZ555Jh988AFVqlShatWqud6vcePG7Nq1i3HjxtG0aVP9kiRyGKo3Upw9++yzbN68mRkzZnDaaaf5HSdXRx11FADDhw9n586dPqeR4iQ/azyeBloCPYKX04FxYU+UjXNuhXOuinOutnOuNrAeaOqc2+TlckVCtWXLFm6//XbOOOMMtmzZcti1HfDnmpC0tDSWL1/OsGHDiiqmSLRRvZFiaffu3Tz44IOcfvrptG7d2u84h9W8eXNatWrF7t27I3atjESn/DQe/3LODQD2AjjntgMlPEklEiX+85//kJaWxsiRI/nuu+8OTZubm4YNGxIfH096ejpXXHEFI0eOZPXq1UWYViRqqN5IsfTkk0+yY8cOv2OEZPTo0QA8+uijWushYZOfxiPDzOIJzvRhZpWBIt1QPfhL1JaiXKbI4ezatYtXXnmF6667jp9++om9e/fSpUuXw96/bNmytG/fnqlTp/LYY48RFxfHiy++WISJRaKG6o0UO+np6Tz88MMAUbHvRNOmTTnjjDPYs2cPjzzyiN9xpJjIT+MxBpgOVDWzYcBnwMOepBKJAr/99hvHH388Z511FpMnT6ZGjRp5rjrv2bMnP//8M7/88gtNmzZl0aJFRZRWJKqo3kixc//997Nr1y5OP/30XI/3FIlGjx5N1apVefLJJ9m0SVsdSuGZc6FNVW5mg4HFQGPAgI+cc6s8zFZgzZs3d4sXL/Y7hsSIbdu2ccwxxzBw4EBGjhx5xPumpqZStWpV+vXrR9euXSlRokREb+crxYeZLXHONfc7RyhUb6S4+fXXX6lTpw6ZmZksX778iPsDRpoffviBE088kT59+vDss8/6HUeiwJHqTX7WeCQDzwKXElj9vS0M2USi3rRp08jIyKBnz5553rd8+fKce+65vPHGG7Rp00ZNh0juVG+kWLnrrrtwztGjR4+oajoA6tWrx2WXXcbzzz/Pd99953cciXIhNx7OuQeccw2BAUB14FMzm+NZMpEI16JFC4YPH87kyZNp0KABTZo0CelxPXv25Pfff+ejjz7i3XffZcmSJR4nFYkuqjdSnHz99ddMnDiR2267jUmTJvkdp0AqVqyIc46+ffv6HUWiXEEOIPgHsAnYClQJbxyR6LB582a+/PJLdu3axaeffkqPHj0ws5Aee84555CUlMTrr79Or169eP755z1OKxK1VG8kqmX9Z71ChQrccccdxMVFxHGb8+2BBx6gbNmyLFiwgFmzZvkdR6JYfg4g2N/M5gIfAUcD1zrnomt9oUiYfPXVV0Bg/46s1eehKl26NN27d2f69Ok0a9ZMO5iL5KB6I8XF66+/fmitdpkyZXxOU3DJycmHZra6+uqr2b9/v8+JJFrlp/VOAQY55xo65+5zzq30KpRIpFu0aBFxcXEsWLCA5s2bU79+/Xw9vmfPnqSmplKxYkVWrFjB7t27PUoqEpVUbyTqpaen079/fyBw/I7ExESfExVO//79SUlJYcOGDQwfPtzvOBKl8rOPx3+cc8u8DCMSLRYtWkT9+vVZtmwZF1xwQb4f3759eypUqMCOHTvIzMxk6dKlHqQUiU6qN1IcDBkyhNTUVJo0acIVV1zhd5xCS0hIYNKkSdSuXZvhw4ezbt06vyNJFMqz8TCzz4L/pptZWrZTupmleR9RJPKcdtpph3Ym79ixY74fn5CQQNu2bfn+++8B0HScIqo3UnysWLGC5557DjNj4sSJIe8DGOlatWrF3LlzARg0aJC/YSQq5dl4OOdaBf9Ncs4lZzslOeeSvY8oEnnuvvtuypUrR/ny5UOezSqndu3a8euvvzJnzhxuuOGGMCcUiT6qN1IcHDx4kOuvv55SpUpxyy230LBhQ78jhVVKSgq9e/dm+vTpvPvuu37HkSiTn53LHw3lOpHibvv27ezbt4+PP/6YNm3aEB8fX6Bx2rdvD8C6desKPIZIcaR6I9HshRde4LPPPuOpp55ixIgRfsfxxAknnADAlVdeSXp6us9pJJrkZ+fyM3O57uxwBRGJFkOHDqVy5cr89NNPtGvXrsDjNGzYkMqVK/P2229z3XXXsXXr1jCmFIlqqjcSldavX89NN91E48aNueqqq/yO45nrr7+ehg0bsnXrVm1yJfkSyj4e/c1sBdDAzL7JdloDrPA+okhkWbRoEVWrVgX+XGtREGZGu3btWLhwIc8999yhKXpFYpXqjUQz5xyXXXYZ+/bto1atWsVmv47cxMfH8+abbxIXF8dLL73EZ5995nckiRKhrPGYDHQBZgT/zTo1c85d5mE2kYize/dulixZQmJiIkcddRQnnXRSocZr164dW7ZsIS4ujvnz54cppUjUUr2RqDV58mTmzZtH2bJleemll/yO47kTTzyRu+66C4AePXqwd+9enxNJNAhl5/JU59wvzrkeQBpQlcAc6yeZ2RleBxSJJO+//z579uxhy5YttGvXrtBHoc1aY1KvXj2mTZuGcy4cMUWikuqNRKvff/+dfv36AfDMM89QpUoVnxMVjXvuuYcbb7yR9evXc//99/sdR6JAQqh3NLNrgJuAmsAyoAXwBVDwbU1EoszUqVOpVKkSmzdvLtT+HVnq1atH9erVKVeuHEuWLGHFihU0bqwDNEtsU72RaOKco1evXuzatYs2bdrQq1cvvyMVmcTERMaMGcOePXt47LHH6NKlC6effrrfsSSC5efn2puAfwJrnXPtgCbAZk9SiUSoO++8k0suuQQo3P4dWcyM9u3bs3btWmrXrs1vv/1W6DFFigHVG4kar7zyCnPmzKFnz55Mnjy5WO/bcTjXXXcdcXFxXHDBBezcudPvOBLB8tN47HXO7QUws5LOudVAA29iiUSmxo0bs2PHDo455hgaNAjPxz9rP4+ZM2dy9tmauEcE1RuJEr/88gsDBw6kTZs2TJw4kerVq/sdyReNGzfmuOOO4/fff9dxqeSI8tN4rDezCsB/gdlm9n/ABm9iiUSeZ599lo8++oiPP/6Y9u3bh+1Xraw1Jx999BGZmZn6tUhE9UaiQGZm5qFf+Pv06VPoff6iWWJiItOnTyc+Pp4JEybw/vvv+x1JIlTIfyXOuW7OuR3OufuBe4DxwPleBROJJLt37+aWW25hzJgx/P777/z73/8O29i1a9fmpJNO4vXXX+fYY49l+PDhYRtbJBrFQr159dVXGTJkiN8xpBCGDRvG119/TYUKFTj33HP9juO7E088kUceeQSASy65hD/++MPnRFJQy5Yt49prr+XXX38N+9gFas+dc58652Y45/aHO5BIJHrvvffYvXs3mZmZlC1blq5du4Z1/J49e7Jw4UJq167N1KlTNbuVSFBxrTfffPMNo0ePZteuXX5HkQJYtGjRoVmc3njjDSpVquRvoAhxyy230KJFC3bt2sVVV12lWhal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FBP79u0z/83OmTPnvuOHDh3SderU0Uop7e3trRcsWJCrv2OTyaQvXbqkly9frkePHq1r1aqlXVxcMn1GHB0dde/evfWsWbP0uXPnCqB0D++DDz7QgE5NTdX9+/fX1apVy9fz55RvLH7TLojHoyaCixcvmv9gzp8//0jnEg924MAB/dJLL+mUlBQdGRmpv/zyS/3ll1/qEydOaK21XrNmjXZwcNBNmjTRt27dsnC0tm3JkiXaYDDoJ598UickJOi0tDS9aNEi87/J9evXtdZar1y5Uqemplo4Wts3bNgwrZTKl2VVpeJhnfnmbitWrNCA3r17tz579qyeP3++jomJybfzP4wrV67osWPH6u7du2t3d3dzTrS3t9f169fXo0eP1idPnsyXa02ePNl8/hdeeCHTMZPJpA8cOKABPWvWrHy5nih+TCaTrlKlilZK6VGjRmU6dubMGe3s7Ky9vb31hg0bdFpa2iNfLzExUf/666+6V69eum3btrpChQrmv/ESJUrobt26WTSPLliwQD/77LNaa6179Oih69evn6/nl4pHHmS0wHTr1k0HBwc/8vlE1rZv365LliypK1asmGUlb+3atdrJyUn7+/vryMhIC0RY/MyfP18rpXTHjh11fHz8fcd37NihAd2vXz+dlJRkgQiLh7Vr15qT1U8//fTI55OKh/Xmmwx//vmnBnRISIi59+Po0aP5dv4HOXz4sH7hhRe0l5eX+UtSyZIl9ZAhQ/Ts2bP1li1bCmyfn88++0wD2mg0ZrrXHz58WLu6umpAX7lypUCuLYqHN954QyuldLdu3TI9P3LkSA3oTz75pMCubTKZ9Lp163STJk20g4OD+fNlZ2enu3fvrpctW6bj4uIK7Po5ad++vW7VqlW+njOnfGNdg86sSO/evYH0VWUuXbpk4Whs0/Lly3nyyScpU6YMW7dupVKlSpmOr1mzhu7du1OrVi1CQkIeOClM5I8BAwbw3XffsW7dOnr06HHf8oPNmjXjs88+Y/HixXTr1s28IobIX1euXCEyMhJXV1cZ115M3D3HI+N+V5ATzLXW7N27lw8++IDatWtTr1495syZw/Xr1/Hz8+Ojjz7i1KlT/O9//+OFF16gVatWBTYO/J133qFly5akpaWxZMkS8/NHjx4lLi4Of39/vLy8CuTaonjo1auX+W8+g8lkYsGCBQC0bt26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VF+l1BGllEkpFXjPsfeUUqeUUseVUoW+hendFQ8vL68i1eNx4cIFZs6cSffu3Tl8+DAAVapUoW/fvqxbt46LFy/yxRdfZLlBk9aa1atX06FDB5o1a8bu3buZNGkSp0+f5tVXX8XBwaGwiyNsWJ06dfjtt9/YsWMHTZo04f3336dq1aqMGTMmy8q+0Whk4MCBrF+/3vx37OrqSlJSEgBnzpxh5MiRhISEkJycXNjFyRNPT0+6detG+fLlzfccmeOR/6w53wghhM3TWlv8AfgCtYFNQOBdz/sBBwBHoBpwGjA+6HwBAQE6v/Tr10/XqlVLa631uXPn9JEjR/Lt3AXh2rVreuTIkbpevXoa0ICuWrWqDg4OztX7Y2Ji9KxZs7Sfn58GtI+Pj/700091TExMAUcuxB27d+/WPXr00Eop7eDgoF944QUdFhaW6/f/+uuv2tHRUQPazc1N/+Mf/9BffvmlvnnzZgFGnX9+/vlnDegDBw7k2zmBMG0F93tLP6w53wghhC3IKd9YRY+H1jpca308i0M9gEVa6ySt9VngFNCkMGO7u8ejSpUqWc59sJS4uDjWr1/PBx98wJw5c4D0lYO+//57vL29mTJlCkePHuXMmTN07tw5x3MdOHCAV155hfLlyzNs2DDs7OyYN28e586d49///jdubm6FUSQhAGjcuDG///47x48fZ8iQISxevJjAwEAaN27Md999R0xMTI7v79WrFzdu3GD58uX079+f8PBwXn/9ddLS0gD4448/+O677zh58qRVTlCXoVYFx5rzjRBC2DqrqHjkoAJw4a6f/7793H2UUsOUUmFKqbB7V8d5FBmTy7XWXL58mS+//JLz58/n2/nzYvz48TRr1oySJUsSFBTEpEmTzCtTubm5ERERwbp163j77bfx9fXNdh7GlStXmDZtGv7+/jRo0IDvv/+eHj16sHXrVvbv38/AgQNlSJWwqJo1a/L1119z8eJFvvrqKxISEhg6dCje3t4MGDCAdevWkZqamuV7XV1d6d69O99++y2nTp3iwoUL5i/yCxYsYOjQodSqVQsfHx/69u3LzJkzC7No9+nbty+dOqWP7pGKh0VYPN8IIYStsyusCymlQgDvLA6N1lovy+5tWTyXZfOk1noWMAsgMDAw35owS5UqRVpaGjExMVy6dInXX3+dKlWqULly5fy6RJYSExM5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\n","text/plain": ["<Figure size 864x864 with 4 Axes>"]},"metadata": {"needs_background": "light"},"output_type": "display_data"}],"source": ["x48,y48,valuesCF48,valuesHam48,valuesmomr48,valuesmomtheta48,valuesmomphi48 = np.loadtxt('out48.txt').T #Transposed for easier unpacking\n","points48 = np.zeros((len(x48), 2))\n","for i in range(len(x48)):\n"," points48[i][0] = x48[i]\n"," points48[i][1] = y48[i]\n","\n","RefData=[valuesHam48,valuesmomr48,valuesmomtheta48,valuesmomphi48]\n","SubTitles=[\"\\mathcal{H}\",'\\mathcal{M}^r',r\"\\mathcal{M}^{\\theta}\",\"\\mathcal{M}^{\\phi}\"]\n","axN = []\n","plt.clf()\n","\n","# We want to create four plots. One for the Hamiltonian, and three for the momentum\n","# constrains (r,th,ph)\n","# Define the size of the overall figure\n","fig = plt.figure(figsize=(12,12)) # 8 in x 8 in\n","\n","for p in range(num_plots): #loop to cycle through our constraints and plot the data\n"," grid48 = griddata(points48, RefData[p], (grid_x, grid_y), method='nearest')\n"," griddiff_48_minus_96 = np.zeros((100,100))\n"," griddiff_48_minus_96_1darray = np.zeros(100*100)\n"," gridx_1darray_yeq0 = np.zeros(100)\n"," grid48_1darray_yeq0 = np.zeros(100)\n"," grid96_1darray_yeq0 = np.zeros(100)\n"," count = 0\n"," for i in range(100):\n"," for j in range(100):\n"," griddiff_48_minus_96[i][j] = grid48[i][j] - grid96N[p][i][j]\n"," griddiff_48_minus_96_1darray[count] = griddiff_48_minus_96[i][j]\n"," if j==49:\n"," gridx_1darray_yeq0[i] = grid_x[i][j]\n"," grid48_1darray_yeq0[i] = grid48[i][j] + np.log10((48./96.)**4)\n"," grid96_1darray_yeq0[i] = grid96N[p][i][j]\n"," count = count + 1\n","\n"," #Generate the subplot for the each constraint\n"," ax = fig.add_subplot(221+p)\n"," axN.append(ax) # Grid of 2x2\n"," axN[p].set_title('Plot Demonstrating $4^{th}$-Order Convergence of $'+SubTitles[p]+'$')\n"," axN[p].set_xlabel(\"x/M\")\n"," axN[p].set_ylabel(\"$log_{10}$(Relative Error)\")\n","\n"," ax.plot(gridx_1darray_yeq0, grid96_1darray_yeq0, 'k-', label='Nr=96')\n"," ax.plot(gridx_1darray_yeq0, grid48_1darray_yeq0, 'k--', label='Nr=48, mult by (48/96)^4')\n"," ax.set_ylim([-14,4.])\n","\n"," legend = ax.legend(loc='lower right', shadow=True, fontsize='x-large')\n"," legend.get_frame().set_facecolor('C1')\n","\n","# Adjust the spacing between plots\n","plt.tight_layout(pad=4)"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='latex_pdf_output'></a>\n","\n","# Step 7: Output this notebook to $\\LaTeX$-formatted PDF file \\[Back to [top](#toc)\\]\n","$$\\label{latex_pdf_output}$$\n","\n","The following code cell converts this Jupyter notebook into a proper, clickable $\\LaTeX$-formatted PDF file. After the cell is successfully run, the generated PDF may be found in the root NRPy+ tutorial directory, with filename\n","[Tutorial-Start_to_Finish-BSSNCurvilinear-Setting_up_Exact_Initial_Data.pdf](Tutorial-Start_to_Finish-BSSNCurvilinear-Setting_up_Exact_Initial_Data.pdf) (Note that clicking on this link may not work; you may need to open the PDF file through another means.)"]},{"cell_type": "code","execution_count": 14,"metadata": {},"outputs": [{"name": "stdout","output_type": "stream","text": ["This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/Debian) (preloaded format=pdflatex)\r\n"," restricted \\write18 enabled.\r\n","entering extended mode\r\n","This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/Debian) (preloaded format=pdflatex)\r\n"," restricted \\write18 enabled.\r\n","entering extended mode\r\n","This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/Debian) (preloaded format=pdflatex)\r\n"," restricted \\write18 enabled.\r\n","entering extended mode\r\n"]}],"source": ["!jupyter nbconvert --to latex --template latex_nrpy_style.tplx --log-level='WARN' Tutorial-Start_to_Finish-BSSNCurvilinear-Setting_up_Exact_Initial_Data.ipynb\n","!pdflatex -interaction=batchmode Tutorial-Start_to_Finish-BSSNCurvilinear-Setting_up_Exact_Initial_Data.tex\n","!pdflatex -interaction=batchmode Tutorial-Start_to_Finish-BSSNCurvilinear-Setting_up_Exact_Initial_Data.tex\n","!pdflatex -interaction=batchmode Tutorial-Start_to_Finish-BSSNCurvilinear-Setting_up_Exact_Initial_Data.tex\n","!rm -f Tut*.out Tut*.aux Tut*.log"]}],"metadata": {"kernelspec": {"display_name": "Python 3","language": "python","name": "python3"},"language_info": {"codemirror_mode": {"name": "ipython","version": 3},"file_extension": ".py","mimetype": "text/x-python","name": "python","nbconvert_exporter": "python","pygments_lexer": "ipython3","version": "3.8.0"}},"nbformat": 4,"nbformat_minor": 2}
# As documented in the NRPy+ tutorial module# Tutorial-ADMBSSN_tofrom_4metric.ipynb,# this module will construct expressions for# ADM or BSSN quantities in terms of the# 4-metric g4DD, and g4DD/g4UU in terms of# ADM/BSSN quantities.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* comimport sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport sys # Standard Python modules for multiplatform OS-level functionsdef setup_ADM_quantities(inputvars):if inputvars == "ADM":gammaDD = ixp.declarerank2("gammaDD", "sym01")betaU = ixp.declarerank1("betaU")alpha = sp.symbols("alpha", real=True)elif inputvars == "BSSN":import BSSN.ADM_in_terms_of_BSSN as AitoB# Construct gamma_{ij} in terms of cf & gammabar_{ij}AitoB.ADM_in_terms_of_BSSN()gammaDD = AitoB.gammaDD# Next construct beta^i in terms of vet^i and reference metric quantitiesimport BSSN.BSSN_quantities as BqBq.BSSN_basic_tensors()betaU = Bq.betaUalpha = sp.symbols("alpha", real=True)else:print("inputvars = " + str(inputvars) + " not supported. Please choose ADM or BSSN.")sys.exit(1)return gammaDD,betaU,alpha# g_{mu nu} in terms of BSSN (if inputvars=="BSSN") or ADM (if inputvars=="ADM") variables.def g4DD_ito_BSSN_or_ADM(inputvars,gammaDD=None,betaU=None,alpha=None):# Step 0: Declare g4DD as globals, to make interfacing with other modules/functions easierglobal g4DD# Step 1: Set gammaDD, betaU, and alpha if not already input.if gammaDD==None and betaU==None and alpha==None:gammaDD,betaU,alpha = setup_ADM_quantities(inputvars)# Step 2: Compute g4DD = g_{mu nu}:# To get \gamma_{\mu \nu} = gamma4DD[mu][nu], we'll need to construct the 4-metric, using Eq. 2.122 in B&S:g4DD = ixp.zerorank2(DIM=4)# Step 2.a: Compute beta_i via Eq. 2.121 in B&SbetaD = ixp.zerorank1()for i in range(3):for j in range(3):betaD[i] += gammaDD[i][j] * betaU[j]# Step 2.b: Compute beta_i beta^i, the beta contraction.beta2 = sp.sympify(0)for i in range(3):beta2 += betaU[i] * betaD[i]# Step 2.c: Construct g4DD via Eq. 2.122 in B&Sg4DD[0][0] = -alpha ** 2 + beta2for mu in range(1, 4):g4DD[mu][0] = g4DD[0][mu] = betaD[mu - 1]for mu in range(1, 4):for nu in range(1, 4):g4DD[mu][nu] = gammaDD[mu - 1][nu - 1]# g^{mu nu} in terms of BSSN (if inputvars=="BSSN") or ADM (if inputvars=="ADM") variables.def g4UU_ito_BSSN_or_ADM(inputvars,gammaDD=None,betaU=None,alpha=None, gammaUU=None):# Step 0: Declare g4UU as globals, to make interfacing with other modules/functions easierglobal g4UU# Step 1: Set gammaDD, betaU, and alpha if not already input.if gammaDD==None and betaU==None and alpha==None:gammaDD,betaU,alpha = setup_ADM_quantities(inputvars)# Step 2: Compute g4UU = g_{mu nu}:# To get \gamma^{\mu \nu} = gamma4UU[mu][nu], we'll need to use Eq. 2.119 in B&S.g4UU = ixp.zerorank2(DIM=4)# Step 3: Construct g4UU = g^{mu nu}# Step 3.a: Compute gammaUU based on provided gammaDD:if gammaUU==None:gammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD)# Then evaluate g4UU:g4UU = ixp.zerorank2(DIM=4)g4UU[0][0] = -1 / alpha ** 2for mu in range(1, 4):g4UU[0][mu] = g4UU[mu][0] = betaU[mu - 1] / alpha ** 2for mu in range(1, 4):for nu in range(1, 4):g4UU[mu][nu] = gammaUU[mu - 1][nu - 1] - betaU[mu - 1] * betaU[nu - 1] / alpha ** 2# BSSN (if inputvars=="BSSN") or ADM (if inputvars=="ADM") metric variables in terms of g_{mu nu}def BSSN_or_ADM_ito_g4DD(inputvars,g4DD=None):# Step 0: Declare output variables as globals, to make interfacing with other modules/functions easierif inputvars == "ADM":global gammaDD, betaU, alphaelif inputvars == "BSSN":global hDD, cf, vetU, alphaelse:print("inputvars = " + str(inputvars) + " not supported. Please choose ADM or BSSN.")sys.exit(1)# Step 1: declare g4DD as symmetric rank-4 tensor:g4DD_is_input_into_this_function = Trueif g4DD == None:g4DD = ixp.declarerank2("g4DD", "sym01", DIM=4)g4DD_is_input_into_this_function = False# Step 2: Compute gammaDD & betaDbetaD = ixp.zerorank1()gammaDD = ixp.zerorank2()for i in range(3):betaD[i] = g4DD[0][i]for j in range(3):gammaDD[i][j] = g4DD[i + 1][j + 1]# Step 3: Compute betaU# Step 3.a: Compute gammaUU based on provided gammaDDgammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD)# Step 3.b: Use gammaUU to raise betaUbetaU = ixp.zerorank1()for i in range(3):for j in range(3):betaU[i] += gammaUU[i][j] * betaD[j]# Step 4: Compute alpha = sqrt(beta^2 - g_{00}):# Step 4.a: Compute beta^2 = beta^k beta_k:beta_squared = sp.sympify(0)for k in range(3):beta_squared += betaU[k] * betaD[k]# Step 4.b: alpha = sqrt(beta^2 - g_{00}):if g4DD_is_input_into_this_function == False:alpha = sp.sqrt(sp.simplify(beta_squared) - g4DD[0][0])else:alpha = sp.sqrt(beta_squared - g4DD[0][0])# Step 5: If inputvars == "ADM", we are finished. Return.if inputvars == "ADM":return# Step 6: If inputvars == "BSSN", convert ADM to BSSNimport BSSN.BSSN_in_terms_of_ADM as BitoAdummyBU = ixp.zerorank1()BitoA.gammabarDD_hDD(gammaDD)BitoA.cf_from_gammaDD(gammaDD)BitoA.betU_vetU(betaU, dummyBU)hDD = BitoA.hDDcf = BitoA.cfvetU = BitoA.vetU
# This module performs the conversion between ADM# spacetime variables in Spherical or Cartesian coordinates# given as *exact* SymPy expressions (i.e., direct functions# of r,th,ph or x,y,z), to rescaled BSSN-in-curvilinear# coordinate quantities, as defined in BSSN_RHSs.py# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step P0: Import needed Python/NRPy+ modulesimport sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport reference_metric as rfm # NRPy+: Reference metric supportimport sys # Standard Python module for multiplatform OS-level functionsdef Convert_Spherical_or_Cartesian_ADM_to_BSSN_curvilinear(CoordType_in, Sph_r_th_ph_or_Cart_xyz,gammaDD_inSphorCart, KDD_inSphorCart, alpha_inSphorCart, betaU_inSphorCart, BU_inSphorCart):# This routine converts the ADM variables# $$\left\{\gamma_{ij}, K_{ij}, \alpha, \beta^i\right\}$$# in Spherical or Cartesian basis+coordinates, first to the BSSN variables# in the chosen reference_metric::CoordSystem coordinate system+basis:# $$\left\{\bar{\gamma}_{i j},\bar{A}_{i j},\phi, K, \bar{\Lambda}^{i}, \alpha, \beta^i, B^i\right\},$$# and then to the rescaled variables:# $$\left\{h_{i j},a_{i j},\phi, K, \lambda^{i}, \alpha, \mathcal{V}^i, \mathcal{B}^i\right\}.$$# The ADM & BSSN formalisms only work in 3D; they are 3+1 decompositions of Einstein's equations.# To implement axisymmetry or spherical symmetry, simply set all spatial derivatives in# the relevant angular directions to zero; DO NOT SET DIM TO ANYTHING BUT 3.# Step P1: Set spatial dimension (must be 3 for BSSN)DIM = 3# Step P2: Copy gammaSphDD_in to gammaSphDD, KSphDD_in to KSphDD, etc.# This ensures that the input arrays are not modified below;# modifying them would result in unexpected effects outside# this function.alphaSphorCart = alpha_inSphorCartbetaSphorCartU = ixp.zerorank1()BSphorCartU = ixp.zerorank1()gammaSphorCartDD = ixp.zerorank2()KSphorCartDD = ixp.zerorank2()for i in range(DIM):betaSphorCartU[i] = betaU_inSphorCart[i]BSphorCartU[i] = BU_inSphorCart[i]for j in range(DIM):gammaSphorCartDD[i][j] = gammaDD_inSphorCart[i][j]KSphorCartDD[i][j] = KDD_inSphorCart[i][j]# Make sure that rfm.reference_metric() has been called.# We'll need the variables it defines throughout this module.if rfm.have_already_called_reference_metric_function == False:print("Error. Called Convert_Spherical_ADM_to_BSSN_curvilinear() without")print(" first setting up reference metric, by calling rfm.reference_metric().")sys.exit(1)# Step 1: All input quantitiefs are in terms of r,th,ph or x,y,z. We want them in terms# of xx0,xx1,xx2, so here we call sympify_integers__replace_rthph() to replace# r,th,ph or x,y,z, respectively, with the appropriate functions of xx0,xx1,xx2# as defined for this particular reference metric in reference_metric.py's# xxSph[] or xxCart[], respectively:# Note that substitution only works when the variable is not an integer. Hence the# if isinstance(...,...) stuff:def sympify_integers__replace_rthph_or_Cartxyz(obj, rthph_or_xyz, rthph_or_xyz_of_xx):if isinstance(obj, int):return sp.sympify(obj)else:return obj.subs(rthph_or_xyz[0], rthph_or_xyz_of_xx[0]).\subs(rthph_or_xyz[1], rthph_or_xyz_of_xx[1]).\subs(rthph_or_xyz[2], rthph_or_xyz_of_xx[2])r_th_ph_or_Cart_xyz_of_xx = []if CoordType_in == "Spherical":r_th_ph_or_Cart_xyz_of_xx = rfm.xxSphelif CoordType_in == "Cartesian":r_th_ph_or_Cart_xyz_of_xx = rfm.xxCartelse:print("Error: Can only convert ADM Cartesian or Spherical initial data to BSSN Curvilinear coords.")sys.exit(1)alphaSphorCart = sympify_integers__replace_rthph_or_Cartxyz(alphaSphorCart, Sph_r_th_ph_or_Cart_xyz, r_th_ph_or_Cart_xyz_of_xx)for i in range(DIM):betaSphorCartU[i] = sympify_integers__replace_rthph_or_Cartxyz(betaSphorCartU[i], Sph_r_th_ph_or_Cart_xyz, r_th_ph_or_Cart_xyz_of_xx)BSphorCartU[i] = sympify_integers__replace_rthph_or_Cartxyz(BSphorCartU[i], Sph_r_th_ph_or_Cart_xyz, r_th_ph_or_Cart_xyz_of_xx)for j in range(DIM):gammaSphorCartDD[i][j] = sympify_integers__replace_rthph_or_Cartxyz(gammaSphorCartDD[i][j], Sph_r_th_ph_or_Cart_xyz, r_th_ph_or_Cart_xyz_of_xx)KSphorCartDD[i][j] = sympify_integers__replace_rthph_or_Cartxyz(KSphorCartDD[i][j], Sph_r_th_ph_or_Cart_xyz, r_th_ph_or_Cart_xyz_of_xx)# Step 2: All ADM initial data quantities are now functions of xx0,xx1,xx2, but# they are still in the Spherical or Cartesian basis. We can now directly apply# Jacobian transformations to get them in the correct xx0,xx1,xx2 basis:# alpha is a scalar, so no Jacobian transformation is necessary.alpha = alphaSphorCartJac_dUSphorCart_dDrfmUD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):Jac_dUSphorCart_dDrfmUD[i][j] = sp.diff(r_th_ph_or_Cart_xyz_of_xx[i],rfm.xx[j])Jac_dUrfm_dDSphorCartUD, dummyDET = ixp.generic_matrix_inverter3x3(Jac_dUSphorCart_dDrfmUD)betaU = ixp.zerorank1()BU = ixp.zerorank1()gammaDD = ixp.zerorank2()KDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):betaU[i] += Jac_dUrfm_dDSphorCartUD[i][j] * betaSphorCartU[j]BU[i] += Jac_dUrfm_dDSphorCartUD[i][j] * BSphorCartU[j]for k in range(DIM):for l in range(DIM):gammaDD[i][j] += Jac_dUSphorCart_dDrfmUD[k][i]*Jac_dUSphorCart_dDrfmUD[l][j] * gammaSphorCartDD[k][l]KDD[i][j] += Jac_dUSphorCart_dDrfmUD[k][i]*Jac_dUSphorCart_dDrfmUD[l][j] * KSphorCartDD[k][l]# Step 3: All ADM quantities were input into this function in the Spherical or Cartesian# basis, as functions of r,th,ph or x,y,z, respectively. In Steps 1 and 2 above,# we converted them to the xx0,xx1,xx2 basis, and as functions of xx0,xx1,xx2.# Here we convert ADM quantities in the "rfm" basis to their BSSN Curvilinear# counterparts:import BSSN.BSSN_in_terms_of_ADM as BitoABitoA.gammabarDD_hDD(gammaDD)BitoA.trK_AbarDD_aDD(gammaDD, KDD)BitoA.LambdabarU_lambdaU__exact_gammaDD(gammaDD)BitoA.cf_from_gammaDD(gammaDD)BitoA.betU_vetU(betaU, BU)# Step 4: Return the BSSN Curvilinear variables in the desired xx0,xx1,xx2# basis, and as functions of the consistent xx0,xx1,xx2 coordinates.return BitoA.cf, BitoA.hDD, BitoA.lambdaU, BitoA.aDD, BitoA.trK, alpha, BitoA.vetU, BitoA.betU
# This module performs the conversion between ADM# spacetime variables in Spherical or Cartesian coordinates# given as *numerical* expressions (i.e., ADM quantities# are only given to floating-point precision; e.g., in the# case of an initial data solver), to rescaled BSSN-in-curvilinear# coordinate quantities, as defined in BSSN_RHSs.py# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step P1: Initialize core Python/NRPy+ modulesfrom outputC import * # NRPy+: Core C code output moduleimport sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport finite_difference as fin # NRPy+: Finite difference C code generation moduleimport grid as gri # NRPy+: Functions having to do with numerical gridsimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport reference_metric as rfm # NRPy+: Reference metric supportimport BSSN.BSSN_quantities as Bq # NRPy+: Computes useful BSSN quantities; e.g., gammabarUU & GammabarUDD needed belowimport os, sys # Standard Python modules for multiplatform OS-level functionsdef Convert_Spherical_or_Cartesian_ADM_to_BSSN_curvilinear(CoordType_in, ADM_input_function_name,Ccodesdir = "BSSN", pointer_to_ID_inputs=False,loopopts=",oldloops"):# The ADM & BSSN formalisms only work in 3D; they are 3+1 decompositions of Einstein's equations.# To implement axisymmetry or spherical symmetry, simply set all spatial derivatives in# the relevant angular directions to zero; DO NOT SET DIM TO ANYTHING BUT 3.# Step 0: Set spatial dimension (must be 3 for BSSN)DIM = 3# Step 1: All ADM initial data quantities are now functions of xx0,xx1,xx2, but# they are still in the Spherical or Cartesian basis. We can now directly apply# Jacobian transformations to get them in the correct xx0,xx1,xx2 basis:# All input quantities are in terms of r,th,ph or x,y,z. We want them in terms# of xx0,xx1,xx2, so here we call sympify_integers__replace_rthph() to replace# r,th,ph or x,y,z, respectively, with the appropriate functions of xx0,xx1,xx2# as defined for this particular reference metric in reference_metric.py's# xxSph[] or xxCart[], respectively:# Define the input variables:gammaSphorCartDD = ixp.declarerank2("gammaSphorCartDD", "sym01")KSphorCartDD = ixp.declarerank2("KSphorCartDD", "sym01")alphaSphorCart = sp.symbols("alphaSphorCart")betaSphorCartU = ixp.declarerank1("betaSphorCartU")BSphorCartU = ixp.declarerank1("BSphorCartU")# Make sure that rfm.reference_metric() has been called.# We'll need the variables it defines throughout this module.if rfm.have_already_called_reference_metric_function == False:print("Error. Called Convert_Spherical_ADM_to_BSSN_curvilinear() without")print(" first setting up reference metric, by calling rfm.reference_metric().")sys.exit(1)r_th_ph_or_Cart_xyz_oID_xx = []if CoordType_in == "Spherical":r_th_ph_or_Cart_xyz_oID_xx = rfm.xxSphelif CoordType_in == "Cartesian":r_th_ph_or_Cart_xyz_oID_xx = rfm.xxCartelse:print("Error: Can only convert ADM Cartesian or Spherical initial data to BSSN Curvilinear coords.")sys.exit(1)# Step 2: All ADM initial data quantities are now functions of xx0,xx1,xx2, but# they are still in the Spherical or Cartesian basis. We can now directly apply# Jacobian transformations to get them in the correct xx0,xx1,xx2 basis:# alpha is a scalar, so no Jacobian transformation is necessary.alpha = alphaSphorCartJac_dUSphorCart_dDrfmUD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):Jac_dUSphorCart_dDrfmUD[i][j] = sp.diff(r_th_ph_or_Cart_xyz_oID_xx[i], rfm.xx[j])Jac_dUrfm_dDSphorCartUD, dummyDET = ixp.generic_matrix_inverter3x3(Jac_dUSphorCart_dDrfmUD)betaU = ixp.zerorank1()BU = ixp.zerorank1()gammaDD = ixp.zerorank2()KDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):betaU[i] += Jac_dUrfm_dDSphorCartUD[i][j] * betaSphorCartU[j]BU[i] += Jac_dUrfm_dDSphorCartUD[i][j] * BSphorCartU[j]for k in range(DIM):for l in range(DIM):gammaDD[i][j] += Jac_dUSphorCart_dDrfmUD[k][i] * Jac_dUSphorCart_dDrfmUD[l][j] * \gammaSphorCartDD[k][l]KDD[i][j] += Jac_dUSphorCart_dDrfmUD[k][i] * Jac_dUSphorCart_dDrfmUD[l][j] * KSphorCartDD[k][l]# Step 3: All ADM quantities were input into this function in the Spherical or Cartesian# basis, as functions of r,th,ph or x,y,z, respectively. In Steps 1 and 2 above,# we converted them to the xx0,xx1,xx2 basis, and as functions of xx0,xx1,xx2.# Here we convert ADM quantities in the "rfm" basis to their BSSN Curvilinear# counterparts, for all BSSN quantities *except* lambda^i:import BSSN.BSSN_in_terms_of_ADM as BitoABitoA.gammabarDD_hDD(gammaDD)BitoA.trK_AbarDD_aDD(gammaDD, KDD)BitoA.cf_from_gammaDD(gammaDD)BitoA.betU_vetU(betaU, BU)hDD = BitoA.hDDtrK = BitoA.trKaDD = BitoA.aDDcf = BitoA.cfvetU = BitoA.vetUbetU = BitoA.betU# Step 4: Compute $\bar{\Lambda}^i$ (Eqs. 4 and 5 of# [Baumgarte *et al.*](https://arxiv.org/pdf/1211.6632.pdf)),# from finite-difference derivatives of rescaled metric# quantities $h_{ij}$:# \bar{\Lambda}^i = \bar{\gamma}^{jk}\left(\bar{\Gamma}^i_{jk} - \hat{\Gamma}^i_{jk}\right).# The reference_metric.py module provides us with analytic expressions for# $\hat{\Gamma}^i_{jk}$, so here we need only compute# finite-difference expressions for $\bar{\Gamma}^i_{jk}$, based on# the values for $h_{ij}$ provided in the initial data. Once# $\bar{\Lambda}^i$ has been computed, we apply the usual rescaling# procedure:# \lambda^i = \bar{\Lambda}^i/\text{ReU[i]},# and then output the result to a C file using the NRPy+# finite-difference C output routine.# We will need all BSSN gridfunctions to be defined, as well as# expressions for gammabarDD_dD in terms of exact derivatives of# the rescaling matrix and finite-difference derivatives of# hDD's. This functionality is provided by BSSN.BSSN_unrescaled_and_barred_vars,# which we call here to overwrite above definitions of gammabarDD,gammabarUU, etc.Bq.gammabar__inverse_and_derivs() # Provides gammabarUU and GammabarUDDgammabarUU = Bq.gammabarUUGammabarUDD = Bq.GammabarUDD# Next evaluate \bar{\Lambda}^i, based on GammabarUDD above and GammahatUDD# (from the reference metric):LambdabarU = ixp.zerorank1()for i in range(DIM):for j in range(DIM):for k in range(DIM):LambdabarU[i] += gammabarUU[j][k] * (GammabarUDD[i][j][k] - rfm.GammahatUDD[i][j][k])# Finally apply rescaling:# lambda^i = Lambdabar^i/\text{ReU[i]}lambdaU = ixp.zerorank1()for i in range(DIM):lambdaU[i] = LambdabarU[i] / rfm.ReU[i]if ADM_input_function_name == "DoNotOutputADMInputFunction":return hDD,aDD,trK,vetU,betU,alpha,cf,lambdaU# Step 5.A: Output files containing finite-differenced lambdas.outCparams = "preindent=1,outCfileaccess=a,outCverbose=False,includebraces=False"lambdaU_expressions = [lhrh(lhs=gri.gfaccess("in_gfs", "lambdaU0"), rhs=lambdaU[0]),lhrh(lhs=gri.gfaccess("in_gfs", "lambdaU1"), rhs=lambdaU[1]),lhrh(lhs=gri.gfaccess("in_gfs", "lambdaU2"), rhs=lambdaU[2])]desc = "Output lambdaU[i] for BSSN, built using finite-difference derivatives."name = "ID_BSSN_lambdas"params = "const paramstruct *restrict params,REAL *restrict xx[3],REAL *restrict in_gfs"preloop = ""opts = ""idx4replace = "IDX4S"if "oldloops" in loopopts:params = "const int Nxx[3],const int Nxx_plus_2NGHOSTS[3],REAL *xx[3],const REAL dxx[3],REAL *in_gfs"opts = "DisableCparameters"idx4replace = "IDX4"preloop = """const REAL invdx0 = 1.0/dxx[0];const REAL invdx1 = 1.0/dxx[1];const REAL invdx2 = 1.0/dxx[2];"""outCfunction(outfile=os.path.join(Ccodesdir, name + ".h"), desc=desc, name=name, params=params,preloop=preloop,body=fin.FD_outputC("returnstring", lambdaU_expressions, outCparams).replace("IDX4",idx4replace),loopopts="InteriorPoints,Read_xxs"+loopopts, opts=opts)# Step 5: Output all ADM-to-BSSN expressions to a C function. This function# must first call the ID_ADM_SphorCart() defined above. Using these# Spherical or Cartesian data, it sets up all quantities needed for# BSSNCurvilinear initial data, *except* $\lambda^i$, which must be# computed from numerical data using finite-difference derivatives.ID_inputs_param = "ID_inputs other_inputs,"if pointer_to_ID_inputs == True:ID_inputs_param = "ID_inputs *other_inputs,"desc = "Write BSSN variables in terms of ADM variables at a given point xx0,xx1,xx2"name = "ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs"opts = ""params = "const paramstruct *restrict params, "if "oldloops" in loopopts:opts = "DisableCparameters"params = ""params += "const REAL xx0xx1xx2[3]," + ID_inputs_param + """REAL *hDD00,REAL *hDD01,REAL *hDD02,REAL *hDD11,REAL *hDD12,REAL *hDD22,REAL *aDD00,REAL *aDD01,REAL *aDD02,REAL *aDD11,REAL *aDD12,REAL *aDD22,REAL *trK,REAL *vetU0,REAL *vetU1,REAL *vetU2,REAL *betU0,REAL *betU1,REAL *betU2,REAL *alpha, REAL *cf"""outCparams = "preindent=1,outCverbose=False,includebraces=False"outCfunction(outfile=os.path.join(Ccodesdir, name + ".h"), desc=desc, name=name, params=params,body="""REAL gammaSphorCartDD00,gammaSphorCartDD01,gammaSphorCartDD02,gammaSphorCartDD11,gammaSphorCartDD12,gammaSphorCartDD22;REAL KSphorCartDD00,KSphorCartDD01,KSphorCartDD02,KSphorCartDD11,KSphorCartDD12,KSphorCartDD22;REAL alphaSphorCart,betaSphorCartU0,betaSphorCartU1,betaSphorCartU2;REAL BSphorCartU0,BSphorCartU1,BSphorCartU2;const REAL xx0 = xx0xx1xx2[0];const REAL xx1 = xx0xx1xx2[1];const REAL xx2 = xx0xx1xx2[2];REAL xyz_or_rthph[3];\n""" +outputC(r_th_ph_or_Cart_xyz_oID_xx[0:3], ["xyz_or_rthph[0]", "xyz_or_rthph[1]", "xyz_or_rthph[2]"],"returnstring",outCparams + ",CSE_enable=False") + " " + ADM_input_function_name + """(xyz_or_rthph, other_inputs,&gammaSphorCartDD00,&gammaSphorCartDD01,&gammaSphorCartDD02,&gammaSphorCartDD11,&gammaSphorCartDD12,&gammaSphorCartDD22,&KSphorCartDD00,&KSphorCartDD01,&KSphorCartDD02,&KSphorCartDD11,&KSphorCartDD12,&KSphorCartDD22,&alphaSphorCart,&betaSphorCartU0,&betaSphorCartU1,&betaSphorCartU2,&BSphorCartU0,&BSphorCartU1,&BSphorCartU2);// Next compute all rescaled BSSN curvilinear quantities:\n""" +outputC([hDD[0][0], hDD[0][1], hDD[0][2], hDD[1][1], hDD[1][2], hDD[2][2],aDD[0][0], aDD[0][1], aDD[0][2], aDD[1][1], aDD[1][2], aDD[2][2],trK, vetU[0], vetU[1], vetU[2], betU[0], betU[1], betU[2],alpha, cf],["*hDD00", "*hDD01", "*hDD02", "*hDD11", "*hDD12", "*hDD22","*aDD00", "*aDD01", "*aDD02", "*aDD11", "*aDD12", "*aDD22","*trK", "*vetU0", "*vetU1", "*vetU2", "*betU0", "*betU1", "*betU2","*alpha", "*cf"], "returnstring", params=outCparams),opts = opts)# Step 5.a: Output the driver function for the above# function ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs()# Next write the driver function for ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs():desc = """Driver function for ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs(),which writes BSSN variables in terms of ADM variables at a given point xx0,xx1,xx2"""name = "ID_BSSN__ALL_BUT_LAMBDAs"params = "const paramstruct *restrict params,REAL *restrict xx[3]," + ID_inputs_param + "REAL *in_gfs"opts = ""funccallparams = "params, "idx3replace = "IDX3S"idx4ptreplace = "IDX4ptS"if "oldloops" in loopopts:params = "const int Nxx_plus_2NGHOSTS[3],REAL *xx[3]," + ID_inputs_param + "REAL *in_gfs"opts = "DisableCparameters"funccallparams = ""idx3replace = "IDX3"idx4ptreplace = "IDX4pt"outCfunction(outfile=os.path.join(Ccodesdir, name + ".h"), desc=desc, name=name, params=params,body="""const int idx = IDX3(i0,i1,i2);const REAL xx0xx1xx2[3] = {xx0,xx1,xx2};ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs(""".replace("IDX3",idx3replace)+funccallparams+"""xx0xx1xx2,other_inputs,&in_gfs[IDX4pt(HDD00GF,idx)],&in_gfs[IDX4pt(HDD01GF,idx)],&in_gfs[IDX4pt(HDD02GF,idx)],&in_gfs[IDX4pt(HDD11GF,idx)],&in_gfs[IDX4pt(HDD12GF,idx)],&in_gfs[IDX4pt(HDD22GF,idx)],&in_gfs[IDX4pt(ADD00GF,idx)],&in_gfs[IDX4pt(ADD01GF,idx)],&in_gfs[IDX4pt(ADD02GF,idx)],&in_gfs[IDX4pt(ADD11GF,idx)],&in_gfs[IDX4pt(ADD12GF,idx)],&in_gfs[IDX4pt(ADD22GF,idx)],&in_gfs[IDX4pt(TRKGF,idx)],&in_gfs[IDX4pt(VETU0GF,idx)],&in_gfs[IDX4pt(VETU1GF,idx)],&in_gfs[IDX4pt(VETU2GF,idx)],&in_gfs[IDX4pt(BETU0GF,idx)],&in_gfs[IDX4pt(BETU1GF,idx)],&in_gfs[IDX4pt(BETU2GF,idx)],&in_gfs[IDX4pt(ALPHAGF,idx)],&in_gfs[IDX4pt(CFGF,idx)]);""".replace("IDX4pt",idx4ptreplace),loopopts="AllPoints,Read_xxs"+loopopts, opts=opts)
# As documented in the NRPy+ tutorial module# Tutorial-ADM_in_terms_of_BSSN.ipynb,# this module will construct expressions for ADM# quantities in terms of BSSN quantities.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step 1.a: import all needed modules from NRPy+:from outputC import * # NRPy+: Core C code output moduleimport sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport reference_metric as rfm # NRPy+: Reference metric supportimport sys # Standard Python module for multiplatform OS-level functionsdef ADM_in_terms_of_BSSN():global gammaDD, gammaDDdD, gammaDDdDD, gammaUU, detgamma, GammaUDD, KDD, KDDdD# Step 1.c: Given the chosen coordinate system, set up# corresponding reference metric and needed# reference metric quantities# The following function call sets up the reference metric# and related quantities, including rescaling matrices ReDD,# ReU, and hatted quantities.rfm.reference_metric()# Step 1.d: Set spatial dimension (must be 3 for BSSN, as BSSN is# a 3+1-dimensional decomposition of the general# relativistic field equations)DIM = 3# Step 1.e: Import all basic (unrescaled) BSSN scalars & tensorsimport BSSN.BSSN_quantities as BqBq.BSSN_basic_tensors()gammabarDD = Bq.gammabarDDcf = Bq.cfAbarDD = Bq.AbarDDtrK = Bq.trKBq.gammabar__inverse_and_derivs()gammabarDD_dD = Bq.gammabarDD_dDgammabarDD_dDD = Bq.gammabarDD_dDDBq.AbarUU_AbarUD_trAbar_AbarDD_dD()AbarDD_dD = Bq.AbarDD_dD# Step 2: The ADM three-metric gammaDD and its# derivatives in terms of BSSN quantities.gammaDD = ixp.zerorank2()exp4phi = sp.sympify(0)if par.parval_from_str("EvolvedConformalFactor_cf") == "phi":exp4phi = sp.exp(4 * cf)elif par.parval_from_str("EvolvedConformalFactor_cf") == "chi":exp4phi = (1 / cf)elif par.parval_from_str("EvolvedConformalFactor_cf") == "W":exp4phi = (1 / cf ** 2)else:print("Error EvolvedConformalFactor_cf type = \"" + par.parval_from_str("EvolvedConformalFactor_cf") + "\" unknown.")sys.exit(1)for i in range(DIM):for j in range(DIM):gammaDD[i][j] = exp4phi * gammabarDD[i][j]# Step 2.a: Derivatives of $e^{4\phi}$phidD = ixp.zerorank1()phidDD = ixp.zerorank2()cf_dD = ixp.declarerank1("cf_dD")cf_dDD = ixp.declarerank2("cf_dDD","sym01")if par.parval_from_str("EvolvedConformalFactor_cf") == "phi":for i in range(DIM):phidD[i] = cf_dD[i]for j in range(DIM):phidDD[i][j] = cf_dDD[i][j]elif par.parval_from_str("EvolvedConformalFactor_cf") == "chi":for i in range(DIM):phidD[i] = -sp.Rational(1,4)*exp4phi*cf_dD[i]for j in range(DIM):phidDD[i][j] = sp.Rational(1,4)*( exp4phi**2*cf_dD[i]*cf_dD[j] - exp4phi*cf_dDD[i][j] )elif par.parval_from_str("EvolvedConformalFactor_cf") == "W":exp2phi = (1 / cf)for i in range(DIM):phidD[i] = -sp.Rational(1,2)*exp2phi*cf_dD[i]for j in range(DIM):phidDD[i][j] = sp.Rational(1,2)*( exp4phi*cf_dD[i]*cf_dD[j] - exp2phi*cf_dDD[i][j] )else:print("Error EvolvedConformalFactor_cf type = \""+par.parval_from_str("EvolvedConformalFactor_cf")+"\" unknown.")sys.exit(1)exp4phidD = ixp.zerorank1()exp4phidDD = ixp.zerorank2()for i in range(DIM):exp4phidD[i] = 4*exp4phi*phidD[i]for j in range(DIM):exp4phidDD[i][j] = 16*exp4phi*phidD[i]*phidD[j] + 4*exp4phi*phidDD[i][j]# Step 2.b: Derivatives of gammaDD, the ADM three-metricgammaDDdD = ixp.zerorank3()gammaDDdDD = ixp.zerorank4()for i in range(DIM):for j in range(DIM):for k in range(DIM):gammaDDdD[i][j][k] = exp4phidD[k] * gammabarDD[i][j] + exp4phi * gammabarDD_dD[i][j][k]for l in range(DIM):gammaDDdDD[i][j][k][l] = exp4phidDD[k][l] * gammabarDD[i][j] + \exp4phidD[k] * gammabarDD_dD[i][j][l] + \exp4phidD[l] * gammabarDD_dD[i][j][k] + \exp4phi * gammabarDD_dDD[i][j][k][l]# Step 2.c: 3-Christoffel symbols associated with ADM 3-metric gammaDD# Step 2.c.i: First compute the inverse 3-metric gammaUU:gammaUU, detgamma = ixp.symm_matrix_inverter3x3(gammaDD)GammaUDD = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):GammaUDD[i][j][k] += sp.Rational(1,2)*gammaUU[i][l]* \(gammaDDdD[l][j][k] + gammaDDdD[l][k][j] - gammaDDdD[j][k][l])# Step 3: Define ADM extrinsic curvature KDD and# its first spatial derivatives KDDdD# in terms of BSSN quantitiesKDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):KDD[i][j] = exp4phi * AbarDD[i][j] + sp.Rational(1, 3) * gammaDD[i][j] * trKKDDdD = ixp.zerorank3()trK_dD = ixp.declarerank1("trK_dD")for i in range(DIM):for j in range(DIM):for k in range(DIM):KDDdD[i][j][k] = exp4phidD[k] * AbarDD[i][j] + exp4phi * AbarDD_dD[i][j][k] + \sp.Rational(1, 3) * (gammaDDdD[i][j][k] * trK + gammaDD[i][j] * trK_dD[k])
# This module sets up a standard initial data function used for# setting up SENR initial data at all gridpoints.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* comfrom outputC import *def BSSN_ID_function_string(cf,hDD,lambdaU,aDD,trK,alpha,vetU,betU):rhss = [trK,alpha,cf]lhss = ["in_gfs[IDX4S(TRKGF,i0,i1,i2)]","in_gfs[IDX4S(ALPHAGF,i0,i1,i2)]","in_gfs[IDX4S(CFGF,i0,i1,i2)]"]for i in range(3):rhss.append(lambdaU[i])lhss.append("in_gfs[IDX4S(LAMBDAU"+str(i)+"GF,i0,i1,i2)]")rhss.append(vetU[i])lhss.append("in_gfs[IDX4S(VETU"+str(i)+"GF,i0,i1,i2)]")rhss.append(betU[i])lhss.append("in_gfs[IDX4S(BETU"+str(i)+"GF,i0,i1,i2)]")for j in range(i,3):rhss.append(hDD[i][j])lhss.append("in_gfs[IDX4S(HDD" + str(i) + str(j) + "GF,i0,i1,i2)]")rhss.append(aDD[i][j])lhss.append("in_gfs[IDX4S(ADD" + str(i) + str(j) + "GF,i0,i1,i2)]")# Sort the lhss list alphabetically, and rhss to match:lhss,rhss = [list(x) for x in zip(*sorted(zip(lhss, rhss), key=lambda pair: pair[0]))]body = outputC(rhss, lhss, filename="returnstring",params="preindent=1,CSE_enable=True,outCverbose=False", # outCverbose=False to prevent# enormous output files.prestring="", poststring="")desc = "Set up the initial data at all points on the numerical grid."add_to_Cfunction_dict(desc =desc,name ="initial_data",params ="const paramstruct *restrict params,REAL *restrict xx[3], REAL *restrict in_gfs",body =body,loopopts="AllPoints,Read_xxs")
# As documented in the NRPy+ tutorial module# Tutorial-BSSN_time_evolution-BSSN_RHSs.ipynb,# this module will construct the right-hand sides (RHSs)# expressions of the BSSN time evolution equations.## Time-evolution equations for the BSSN gauge conditions are# specified in the BSSN_gauge_RHSs module and documented in# the Tutorial-BSSN_time_evolution-BSSN_gauge_RHSs.ipynb# NRPy+ tutorial module.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step 1.a: import all needed modules from NRPy+:import sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport reference_metric as rfm # NRPy+: Reference metric supportimport sys # Standard Python modules for multiplatform OS-level functionsimport BSSN.BSSN_quantities as Bq # NRPy+: This module depends on the parameter EvolvedConformalFactor_cf,# which is defined in BSSN.BSSN_quantitieshave_already_called_BSSN_RHSs_function = False# Step 1.b: Set the coordinate system for the numerical grid:# DO NOT SET IN STANDALONE PYTHON MODULE# par.set_parval_from_str("reference_metric::CoordSystem","Spherical")def BSSN_RHSs():# Step 1.c: Given the chosen coordinate system, set up# corresponding reference metric and needed# reference metric quantities# The following function call sets up the reference metric# and related quantities, including rescaling matrices ReDD,# ReU, and hatted quantities.rfm.reference_metric()global have_already_called_BSSN_RHSs_function # setting to global enables other modules to see updated value.have_already_called_BSSN_RHSs_function = True# Step 1.d: Set spatial dimension (must be 3 for BSSN, as BSSN is# a 3+1-dimensional decomposition of the general# relativistic field equations)DIM = 3# Step 1.e: Import all basic (unrescaled) BSSN scalars & tensorsimport BSSN.BSSN_quantities as BqBq.BSSN_basic_tensors()gammabarDD = Bq.gammabarDDAbarDD = Bq.AbarDDLambdabarU = Bq.LambdabarUtrK = Bq.trKalpha = Bq.alphabetaU = Bq.betaU# Step 1.f: Import all neeeded rescaled BSSN tensors:aDD = Bq.aDDcf = Bq.cflambdaU = Bq.lambdaU# Step 2.a.i: Import derivative expressions for betaU defined in the BSSN.BSSN_quantities module:Bq.betaU_derivs()betaU_dD = Bq.betaU_dDbetaU_dDD = Bq.betaU_dDD# Step 2.a.ii: Import derivative expression for gammabarDDBq.gammabar__inverse_and_derivs()gammabarDD_dupD = Bq.gammabarDD_dupD# Step 2.a.iii: First term of \partial_t \bar{\gamma}_{i j} right-hand side:# \beta^k \bar{\gamma}_{ij,k} + \beta^k_{,i} \bar{\gamma}_{kj} + \beta^k_{,j} \bar{\gamma}_{ik}gammabar_rhsDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):for k in range(DIM):gammabar_rhsDD[i][j] += betaU[k] * gammabarDD_dupD[i][j][k] + betaU_dD[k][i] * gammabarDD[k][j] \+ betaU_dD[k][j] * gammabarDD[i][k]# Step 2.b.i: First import \bar{A}_{ij} = AbarDD[i][j], and its contraction trAbar = \bar{A}^k_k# from BSSN.BSSN_quantitiesBq.AbarUU_AbarUD_trAbar_AbarDD_dD()trAbar = Bq.trAbar# Step 2.b.ii: Import detgammabar quantities from BSSN.BSSN_quantities:Bq.detgammabar_and_derivs()detgammabar = Bq.detgammabardetgammabar_dD = Bq.detgammabar_dD# Step 2.b.ii: Compute the contraction \bar{D}_k \beta^k = \beta^k_{,k} + \frac{\beta^k \bar{\gamma}_{,k}}{2 \bar{\gamma}}Dbarbetacontraction = sp.sympify(0)for k in range(DIM):Dbarbetacontraction += betaU_dD[k][k] + betaU[k] * detgammabar_dD[k] / (2 * detgammabar)# Step 2.b.iii: Second term of \partial_t \bar{\gamma}_{i j} right-hand side:# \frac{2}{3} \bar{\gamma}_{i j} \left (\alpha \bar{A}_{k}^{k} - \bar{D}_{k} \beta^{k}\right )for i in range(DIM):for j in range(DIM):gammabar_rhsDD[i][j] += sp.Rational(2, 3) * gammabarDD[i][j] * (alpha * trAbar - Dbarbetacontraction)# Step 2.c: Third term of \partial_t \bar{\gamma}_{i j} right-hand side:# -2 \alpha \bar{A}_{ij}for i in range(DIM):for j in range(DIM):gammabar_rhsDD[i][j] += -2 * alpha * AbarDD[i][j]# Step 3.a: First term of \partial_t \bar{A}_{i j}:# \beta^k \partial_k \bar{A}_{ij} + \partial_i \beta^k \bar{A}_{kj} + \partial_j \beta^k \bar{A}_{ik}# First define AbarDD_dupD:AbarDD_dupD = Bq.AbarDD_dupD # From Bq.AbarUU_AbarUD_trAbar_AbarDD_dD()Abar_rhsDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):for k in range(DIM):Abar_rhsDD[i][j] += betaU[k] * AbarDD_dupD[i][j][k] + betaU_dD[k][i] * AbarDD[k][j] \+ betaU_dD[k][j] * AbarDD[i][k]# Step 3.b: Second term of \partial_t \bar{A}_{i j}:# - (2/3) \bar{A}_{i j} \bar{D}_{k} \beta^{k} - 2 \alpha \bar{A}_{i k} {\bar{A}^{k}}_{j} + \alpha \bar{A}_{i j} KgammabarUU = Bq.gammabarUU # From Bq.gammabar__inverse_and_derivs()AbarUD = Bq.AbarUD # From Bq.AbarUU_AbarUD_trAbar()for i in range(DIM):for j in range(DIM):Abar_rhsDD[i][j] += -sp.Rational(2, 3) * AbarDD[i][j] * Dbarbetacontraction + alpha * AbarDD[i][j] * trKfor k in range(DIM):Abar_rhsDD[i][j] += -2 * alpha * AbarDD[i][k] * AbarUD[k][j]# Step 3.c.i: Define partial derivatives of \phi in terms of evolved quantity "cf":Bq.phi_and_derivs()phi_dD = Bq.phi_dDphi_dupD = Bq.phi_dupDphi_dDD = Bq.phi_dDDexp_m4phi = Bq.exp_m4phiphi_dBarD = Bq.phi_dBarD # phi_dBarD = Dbar_i phi = phi_dD (since phi is a scalar)phi_dBarDD = Bq.phi_dBarDD # phi_dBarDD = Dbar_i Dbar_j phi (covariant derivative)# Step 3.c.ii: Define RbarDDBq.RicciBar__gammabarDD_dHatD__DGammaUDD__DGammaU()RbarDD = Bq.RbarDD# Step 3.c.iii: Define first and second derivatives of \alpha, as well as# \bar{D}_i \bar{D}_j \alpha, which is defined just like phialpha_dD = ixp.declarerank1("alpha_dD")alpha_dDD = ixp.declarerank2("alpha_dDD", "sym01")alpha_dBarD = alpha_dDalpha_dBarDD = ixp.zerorank2()GammabarUDD = Bq.GammabarUDD # Defined in Bq.gammabar__inverse_and_derivs()for i in range(DIM):for j in range(DIM):alpha_dBarDD[i][j] = alpha_dDD[i][j]for k in range(DIM):alpha_dBarDD[i][j] += - GammabarUDD[k][i][j] * alpha_dD[k]# Step 3.c.iv: Define the terms in curly braces:curlybrackettermsDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):curlybrackettermsDD[i][j] = -2 * alpha * phi_dBarDD[i][j] + 4 * alpha * phi_dBarD[i] * phi_dBarD[j] \+ 2 * alpha_dBarD[i] * phi_dBarD[j] \+ 2 * alpha_dBarD[j] * phi_dBarD[i] \- alpha_dBarDD[i][j] + alpha * RbarDD[i][j]# Step 3.c.v: Compute the trace:curlybracketterms_trace = sp.sympify(0)for i in range(DIM):for j in range(DIM):curlybracketterms_trace += gammabarUU[i][j] * curlybrackettermsDD[i][j]# Step 3.c.vi: Third and final term of Abar_rhsDD[i][j]:for i in range(DIM):for j in range(DIM):Abar_rhsDD[i][j] += exp_m4phi * (curlybrackettermsDD[i][j] -sp.Rational(1, 3) * gammabarDD[i][j] * curlybracketterms_trace)# Step 4: Right-hand side of conformal factor variable "cf". Supported# options include: cf=phi, cf=W=e^(-2*phi) (default), and cf=chi=e^(-4*phi)# \partial_t phi = \left[\beta^k \partial_k \phi \right] <- TERM 1# + \frac{1}{6} \left (\bar{D}_{k} \beta^{k} - \alpha K \right ) <- TERM 2global cf_rhscf_rhs = sp.Rational(1, 6) * (Dbarbetacontraction - alpha * trK) # Term 2for k in range(DIM):cf_rhs += betaU[k] * phi_dupD[k] # Term 1# Next multiply to convert phi_rhs to cf_rhs.if par.parval_from_str("BSSN.BSSN_quantities::EvolvedConformalFactor_cf") == "phi":pass # do nothing; cf_rhs = phi_rhselif par.parval_from_str("BSSN.BSSN_quantities::EvolvedConformalFactor_cf") == "W":cf_rhs *= -2 * cf # cf_rhs = -2*cf*phi_rhselif par.parval_from_str("BSSN.BSSN_quantities::EvolvedConformalFactor_cf") == "chi":cf_rhs *= -4 * cf # cf_rhs = -4*cf*phi_rhselse:print("Error: EvolvedConformalFactor_cf == " +par.parval_from_str("BSSN.BSSN_quantities::EvolvedConformalFactor_cf") + " unsupported!")sys.exit(1)# Step 5: right-hand side of trK (trace of extrinsic curvature):# \partial_t K = \beta^k \partial_k K <- TERM 1# + \frac{1}{3} \alpha K^{2} <- TERM 2# + \alpha \bar{A}_{i j} \bar{A}^{i j} <- TERM 3# - - e^{-4 \phi} (\bar{D}_{i} \bar{D}^{i} \alpha + 2 \bar{D}^{i} \alpha \bar{D}_{i} \phi ) <- TERM 4global trK_rhs# TERM 2:trK_rhs = sp.Rational(1, 3) * alpha * trK * trKtrK_dupD = ixp.declarerank1("trK_dupD")for i in range(DIM):# TERM 1:trK_rhs += betaU[i] * trK_dupD[i]for i in range(DIM):for j in range(DIM):# TERM 4:trK_rhs += -exp_m4phi * gammabarUU[i][j] * (alpha_dBarDD[i][j] + 2 * alpha_dBarD[j] * phi_dBarD[i])AbarUU = Bq.AbarUU # From Bq.AbarUU_AbarUD_trAbar()for i in range(DIM):for j in range(DIM):# TERM 3:trK_rhs += alpha * AbarDD[i][j] * AbarUU[i][j]# Step 6: right-hand side of \partial_t \bar{\Lambda}^i:# \partial_t \bar{\Lambda}^i = \beta^k \partial_k \bar{\Lambda}^i - \partial_k \beta^i \bar{\Lambda}^k <- TERM 1# + \bar{\gamma}^{j k} \hat{D}_{j} \hat{D}_{k} \beta^{i} <- TERM 2# + \frac{2}{3} \Delta^{i} \bar{D}_{j} \beta^{j} <- TERM 3# + \frac{1}{3} \bar{D}^{i} \bar{D}_{j} \beta^{j} <- TERM 4# - 2 \bar{A}^{i j} (\partial_{j} \alpha - 6 \partial_{j} \phi) <- TERM 5# + 2 \alpha \bar{A}^{j k} \Delta_{j k}^{i} <- TERM 6# - \frac{4}{3} \alpha \bar{\gamma}^{i j} \partial_{j} K <- TERM 7# Step 6.a: Term 1 of \partial_t \bar{\Lambda}^i: \beta^k \partial_k \bar{\Lambda}^i - \partial_k \beta^i \bar{\Lambda}^k# First we declare \bar{\Lambda}^i and \bar{\Lambda}^i_{,j} in terms of \lambda^i and \lambda^i_{,j}global LambdabarU_dupD # Used on the RHS of the Gamma-driving shift conditionsLambdabarU_dupD = ixp.zerorank2()lambdaU_dupD = ixp.declarerank2("lambdaU_dupD", "nosym")for i in range(DIM):for j in range(DIM):LambdabarU_dupD[i][j] = lambdaU_dupD[i][j] * rfm.ReU[i] + lambdaU[i] * rfm.ReUdD[i][j]global Lambdabar_rhsU # Used on the RHS of the Gamma-driving shift conditionsLambdabar_rhsU = ixp.zerorank1()for i in range(DIM):for k in range(DIM):Lambdabar_rhsU[i] += betaU[k] * LambdabarU_dupD[i][k] - betaU_dD[i][k] * LambdabarU[k] # Term 1# Step 6.b: Term 2 of \partial_t \bar{\Lambda}^i = \bar{\gamma}^{jk} (Term 2a + Term 2b + Term 2c)# Term 2a: \bar{\gamma}^{jk} \beta^i_{,kj}Term2aUDD = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for k in range(DIM):Term2aUDD[i][j][k] += betaU_dDD[i][k][j]# Term 2b: \hat{\Gamma}^i_{mk,j} \beta^m + \hat{\Gamma}^i_{mk} \beta^m_{,j}# + \hat{\Gamma}^i_{dj}\beta^d_{,k} - \hat{\Gamma}^d_{kj} \beta^i_{,d}Term2bUDD = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for k in range(DIM):for m in range(DIM):Term2bUDD[i][j][k] += rfm.GammahatUDDdD[i][m][k][j] * betaU[m] \+ rfm.GammahatUDD[i][m][k] * betaU_dD[m][j] \+ rfm.GammahatUDD[i][m][j] * betaU_dD[m][k] \- rfm.GammahatUDD[m][k][j] * betaU_dD[i][m]# Term 2c: \hat{\Gamma}^i_{dj}\hat{\Gamma}^d_{mk} \beta^m - \hat{\Gamma}^d_{kj} \hat{\Gamma}^i_{md} \beta^mTerm2cUDD = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for k in range(DIM):for m in range(DIM):for d in range(DIM):Term2cUDD[i][j][k] += (rfm.GammahatUDD[i][d][j] * rfm.GammahatUDD[d][m][k] \- rfm.GammahatUDD[d][k][j] * rfm.GammahatUDD[i][m][d]) * betaU[m]Lambdabar_rhsUpieceU = ixp.zerorank1()# Put it all together to get Term 2:for i in range(DIM):for j in range(DIM):for k in range(DIM):Lambdabar_rhsU[i] += gammabarUU[j][k] * (Term2aUDD[i][j][k] + Term2bUDD[i][j][k] + Term2cUDD[i][j][k])Lambdabar_rhsUpieceU[i] += gammabarUU[j][k] * (Term2aUDD[i][j][k] + Term2bUDD[i][j][k] + Term2cUDD[i][j][k])# Step 6.c: Term 3 of \partial_t \bar{\Lambda}^i:# \frac{2}{3} \Delta^{i} \bar{D}_{j} \beta^{j}DGammaU = Bq.DGammaU # From Bq.RicciBar__gammabarDD_dHatD__DGammaUDD__DGammaU()for i in range(DIM):Lambdabar_rhsU[i] += sp.Rational(2, 3) * DGammaU[i] * Dbarbetacontraction # Term 3# Step 6.d: Term 4 of \partial_t \bar{\Lambda}^i:# \frac{1}{3} \bar{D}^{i} \bar{D}_{j} \beta^{j}detgammabar_dDD = Bq.detgammabar_dDD # From Bq.detgammabar_and_derivs()Dbarbetacontraction_dBarD = ixp.zerorank1()for k in range(DIM):for m in range(DIM):Dbarbetacontraction_dBarD[m] += betaU_dDD[k][k][m] + \(betaU_dD[k][m] * detgammabar_dD[k] +betaU[k] * detgammabar_dDD[k][m]) / (2 * detgammabar) \- betaU[k] * detgammabar_dD[k] * detgammabar_dD[m] / (2 * detgammabar * detgammabar)for i in range(DIM):for m in range(DIM):Lambdabar_rhsU[i] += sp.Rational(1, 3) * gammabarUU[i][m] * Dbarbetacontraction_dBarD[m]# Step 6.e: Term 5 of \partial_t \bar{\Lambda}^i:# - 2 \bar{A}^{i j} (\partial_{j} \alpha - 6 \alpha \partial_{j} \phi)for i in range(DIM):for j in range(DIM):Lambdabar_rhsU[i] += -2 * AbarUU[i][j] * (alpha_dD[j] - 6 * alpha * phi_dD[j])# Step 6.f: Term 6 of \partial_t \bar{\Lambda}^i:# 2 \alpha \bar{A}^{j k} \Delta^{i}_{j k}DGammaUDD = Bq.DGammaUDD # From RicciBar__gammabarDD_dHatD__DGammaUDD__DGammaU()for i in range(DIM):for j in range(DIM):for k in range(DIM):Lambdabar_rhsU[i] += 2 * alpha * AbarUU[j][k] * DGammaUDD[i][j][k]# Step 6.g: Term 7 of \partial_t \bar{\Lambda}^i:# -\frac{4}{3} \alpha \bar{\gamma}^{i j} \partial_{j} KtrK_dD = ixp.declarerank1("trK_dD")for i in range(DIM):for j in range(DIM):Lambdabar_rhsU[i] += -sp.Rational(4, 3) * alpha * gammabarUU[i][j] * trK_dD[j]# Step 7: Rescale the RHS quantities so that the evolved# variables are smooth across coord singularitiesglobal h_rhsDD,a_rhsDD,lambda_rhsUh_rhsDD = ixp.zerorank2()a_rhsDD = ixp.zerorank2()lambda_rhsU = ixp.zerorank1()for i in range(DIM):lambda_rhsU[i] = Lambdabar_rhsU[i] / rfm.ReU[i]for j in range(DIM):h_rhsDD[i][j] = gammabar_rhsDD[i][j] / rfm.ReDD[i][j]a_rhsDD[i][j] = Abar_rhsDD[i][j] / rfm.ReDD[i][j]# print(str(Abar_rhsDD[2][2]).replace("**","^").replace("_","").replace("xx","x").replace("sin(x2)","Sin[x2]").replace("sin(2*x2)","Sin[2*x2]").replace("cos(x2)","Cos[x2]").replace("detgbaroverdetghat","detg"))# print(str(Dbarbetacontraction).replace("**","^").replace("_","").replace("xx","x").replace("sin(x2)","Sin[x2]").replace("detgbaroverdetghat","detg"))# print(betaU_dD)# print(str(trK_rhs).replace("xx2","xx3").replace("xx1","xx2").replace("xx0","xx1").replace("**","^").replace("_","").replace("sin(xx2)","Sinx2").replace("xx","x").replace("sin(2*x2)","Sin2x2").replace("cos(x2)","Cosx2").replace("detgbaroverdetghat","detg"))# print(str(bet_rhsU[0]).replace("xx2","xx3").replace("xx1","xx2").replace("xx0","xx1").replace("**","^").replace("_","").replace("sin(xx2)","Sinx2").replace("xx","x").replace("sin(2*x2)","Sin2x2").replace("cos(x2)","Cosx2").replace("detgbaroverdetghat","detg"))
# This module registers rescaled BSSN T^{mu nu} source term variables# as AUX (i.e., not evolved) gridfunctions# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step P1: import all needed modules from NRPy+:import indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport grid as gri # NRPy+: Functions having to do with numerical gridsdef define_BSSN_T4UUmunu_rescaled_source_terms():# Step 0: First check to see if this function has already been called.# If so, do not register the gridfunctions again!for i in range(len(gri.glb_gridfcs_list)):if "sDD00" in gri.glb_gridfcs_list[i].name:return# Step 1: Declare as globals all quantities declared in this function.global rho,S,sD,sDD# Step 2: Register all needed *evolved* gridfunctions.# Step 2a: Register indexed quantities, using ixp.register_... functionssDD = ixp.register_gridfunctions_for_single_rank2("AUX", "sDD", "sym01")sD = ixp.register_gridfunctions_for_single_rank1("AUX", "sD")# Step 2b: Register scalar quantities, using gri.register_gridfunctions()rho, S = gri.register_gridfunctions("AUX",["rho","S"])
# As documented in the NRPy+ tutorial module# Tutorial-BSSN_constraints.ipynb,# this module will construct expressions for the# BSSN Hamiltonian and momentum constraint equations.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step 1: Initialize needed Python/NRPy+ modulesimport sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport reference_metric as rfm # NRPy+: Reference metric supportimport BSSN.BSSN_quantities as Bq # NRPy+: Computes useful BSSN quantitiesimport BSSN.BSSN_T4UUmunu_vars as BTmunuthismodule = __name__def BSSN_constraints(add_T4UUmunu_source_terms=False):# Step 1.a: Set spatial dimension (must be 3 for BSSN, as BSSN is# a 3+1-dimensional decomposition of the general# relativistic field equations)DIM = 3# Step 1.b: Given the chosen coordinate system, set up# corresponding reference metric and needed# reference metric quantities# The following function call sets up the reference metric# and related quantities, including rescaling matrices ReDD,# ReU, and hatted quantities.rfm.reference_metric()# Step 2: Hamiltonian constraint.# First declare all needed variablesBq.declare_BSSN_gridfunctions_if_not_declared_already() # Sets trKBq.BSSN_basic_tensors() # Sets AbarDDBq.gammabar__inverse_and_derivs() # Sets gammabarUUBq.AbarUU_AbarUD_trAbar_AbarDD_dD() # Sets AbarUU and AbarDD_dDBq.RicciBar__gammabarDD_dHatD__DGammaUDD__DGammaU() # Sets RbarDDBq.phi_and_derivs() # Sets phi_dBarD & phi_dBarDD############################################################### HAMILTONIAN CONSTRAINT############################################################### Term 1: 2/3 K^2global HH = sp.Rational(2, 3) * Bq.trK ** 2# Term 2: -A_{ij} A^{ij}for i in range(DIM):for j in range(DIM):H += -Bq.AbarDD[i][j] * Bq.AbarUU[i][j]# Term 3a: trace(Rbar)Rbartrace = sp.sympify(0)for i in range(DIM):for j in range(DIM):Rbartrace += Bq.gammabarUU[i][j] * Bq.RbarDD[i][j]# Term 3b: -8 \bar{\gamma}^{ij} \bar{D}_i \phi \bar{D}_j \phi = -8*phi_dBar_times_phi_dBar# Term 3c: -8 \bar{\gamma}^{ij} \bar{D}_i \bar{D}_j \phi = -8*phi_dBarDD_contractionphi_dBar_times_phi_dBar = sp.sympify(0) # Term 3bphi_dBarDD_contraction = sp.sympify(0) # Term 3cfor i in range(DIM):for j in range(DIM):phi_dBar_times_phi_dBar += Bq.gammabarUU[i][j] * Bq.phi_dBarD[i] * Bq.phi_dBarD[j]phi_dBarDD_contraction += Bq.gammabarUU[i][j] * Bq.phi_dBarDD[i][j]# Add Term 3:H += Bq.exp_m4phi * (Rbartrace - 8 * (phi_dBar_times_phi_dBar + phi_dBarDD_contraction))if add_T4UUmunu_source_terms:M_PI = par.Cparameters("#define", thismodule, "M_PI","") # M_PI is pi as defined in CBTmunu.define_BSSN_T4UUmunu_rescaled_source_terms()rho = BTmunu.rhoH += -16*M_PI*rho# FIXME: ADD T4UUmunu SOURCE TERMS TO MOMENTUM CONSTRAINT!# Step 3: M^i, the momentum constraint############################################################### MOMENTUM CONSTRAINT############################################################### SEE Tutorial-BSSN_constraints.ipynb for full documentation.global MUMU = ixp.zerorank1()# Term 2: 6 A^{ij} \partial_j \phi:for i in range(DIM):for j in range(DIM):MU[i] += 6*Bq.AbarUU[i][j]*Bq.phi_dD[j]# Term 3: -2/3 \bar{\gamma}^{ij} K_{,j}trK_dD = ixp.declarerank1("trK_dD") # Not defined in BSSN_RHSs; only trK_dupD is defined there.for i in range(DIM):for j in range(DIM):MU[i] += -sp.Rational(2,3)*Bq.gammabarUU[i][j]*trK_dD[j]# Next evaluate the conformal covariant derivative \bar{D}_j \bar{A}_{lm}AbarDD_dBarD = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for k in range(DIM):AbarDD_dBarD[i][j][k] = Bq.AbarDD_dD[i][j][k]for l in range(DIM):AbarDD_dBarD[i][j][k] += -Bq.GammabarUDD[l][k][i] * Bq.AbarDD[l][j]AbarDD_dBarD[i][j][k] += -Bq.GammabarUDD[l][k][j] * Bq.AbarDD[i][l]# Term 1: Contract twice with the metric to make \bar{D}_{j} \bar{A}^{ij}for i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):MU[i] += Bq.gammabarUU[i][k] * Bq.gammabarUU[j][l] * AbarDD_dBarD[k][l][j]# Finally, we multiply by e^{-4 phi} and rescale the momentum constraint:for i in range(DIM):MU[i] *= Bq.exp_m4phi / rfm.ReU[i]
# As documented in the NRPy+ tutorial module# Tutorial-BSSN_time_evolution-BSSN_gauge_RHSs.ipynb# this module will construct the right-hand sides (RHSs)# expressions for the time evolution equations of the# BSSN gauge quantities alpha and beta^i (i.e., the# lapse and shift)## Non-gauge BSSN time-evolution equations are documented in the# NRPy+ tutorial module# Tutorial-BSSN_time_evolution-BSSN_RHSs.ipynb,# and separately constructed in the BSSN.BSSN_RHSs# Python module.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step 1: Import all needed modules from NRPy+:import sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport reference_metric as rfm # NRPy+: Reference metric supportimport BSSN.BSSN_quantities as Bq # NRPy+: Computes useful BSSN quantitiesimport BSSN.BSSN_RHSs as Brhs # NRPy+: Constructs BSSN right-hand-side expressionsimport sys # Standard Python modules for multiplatform OS-level functions# Step 1.a: Declare/initialize parameters for this modulethismodule = __name__par.initialize_param(par.glb_param("char", thismodule, "LapseEvolutionOption", "OnePlusLog"))par.initialize_param(par.glb_param("char", thismodule, "ShiftEvolutionOption", "GammaDriving2ndOrder_Covariant"))def BSSN_gauge_RHSs():# Step 1.d: Set spatial dimension (must be 3 for BSSN, as BSSN is# a 3+1-dimensional decomposition of the general# relativistic field equations)DIM = 3# Step 1.e: Given the chosen coordinate system, set up# corresponding reference metric and needed# reference metric quantities# The following function call sets up the reference metric# and related quantities, including rescaling matrices ReDD,# ReU, and hatted quantities.rfm.reference_metric()# Step 1.f: Define needed BSSN quantities:# Declare scalars & tensors (in terms of rescaled BSSN quantities)Bq.BSSN_basic_tensors()Bq.betaU_derivs()# Declare BSSN_RHSs (excluding the time evolution equations for the gauge conditions),# if they haven't already been declared.if Brhs.have_already_called_BSSN_RHSs_function == False:print("BSSN_gauge_RHSs() Error: You must call BSSN_RHSs() before calling BSSN_gauge_RHSs().")sys.exit(1)# Step 2: Lapse conditionsLapseEvolOption = par.parval_from_str(thismodule + "::LapseEvolutionOption")# Step 2.a: The 1+log lapse condition:# \partial_t \alpha = \beta^i \alpha_{,i} - 2*\alpha*K# First import expressions from BSSN_quantitiescf = Bq.cftrK = Bq.trKalpha = Bq.alphabetaU = Bq.betaU# Implement the 1+log lapse conditionglobal alpha_rhsalpha_rhs = sp.sympify(0)if LapseEvolOption == "OnePlusLog":alpha_rhs = -2 * alpha * trKalpha_dupD = ixp.declarerank1("alpha_dupD")for i in range(DIM):alpha_rhs += betaU[i] * alpha_dupD[i]# Step 2.b: Implement the harmonic slicing lapse conditionelif LapseEvolOption == "HarmonicSlicing":if par.parval_from_str("BSSN.BSSN_quantities::EvolvedConformalFactor_cf") == "W":alpha_rhs = -3 * cf ** (-4) * Brhs.cf_rhselif par.parval_from_str("BSSN.BSSN_quantities::EvolvedConformalFactor_cf") == "phi":alpha_rhs = 6 * sp.exp(6 * cf) * Brhs.cf_rhselse:print("Error LapseEvolutionOption==HarmonicSlicing unsupported for EvolvedConformalFactor_cf!=(W or phi)")sys.exit(1)# Step 2.c: Frozen lapse# \partial_t \alpha = 0elif LapseEvolOption == "Frozen":alpha_rhs = sp.sympify(0)else:print("Error: "+thismodule + "::LapseEvolutionOption == "+LapseEvolOption+" not supported!")sys.exit(1)# Step 3.a: Set \partial_t \beta^i# First check that ShiftEvolutionOption parameter choice is supported.ShiftEvolOption = par.parval_from_str(thismodule + "::ShiftEvolutionOption")if ShiftEvolOption != "Frozen" and \ShiftEvolOption != "GammaDriving2ndOrder_NoCovariant" and \ShiftEvolOption != "GammaDriving2ndOrder_Covariant" and \ShiftEvolOption != "GammaDriving2ndOrder_Covariant__Hatted" and \ShiftEvolOption != "GammaDriving1stOrder_Covariant" and \ShiftEvolOption != "GammaDriving1stOrder_Covariant__Hatted":print("Error: ShiftEvolutionOption == " + ShiftEvolOption + " unsupported!")sys.exit(1)# Next import expressions from BSSN_quantitiesBU = Bq.BUbetU = Bq.betUbetaU_dupD = Bq.betaU_dupD# Define needed quantitiesbeta_rhsU = ixp.zerorank1()B_rhsU = ixp.zerorank1()# In the case of Frozen shift condition, we# explicitly set the betaU and BU RHS's to zero# instead of relying on the ixp.zerorank1()'s above,# for safety.if ShiftEvolOption == "Frozen":for i in range(DIM):beta_rhsU[i] = sp.sympify(0)BU[i] = sp.sympify(0)if ShiftEvolOption == "GammaDriving2ndOrder_NoCovariant":# Step 3.a.i: Compute right-hand side of beta^i# * \partial_t \beta^i = \beta^j \beta^i_{,j} + B^ifor i in range(DIM):beta_rhsU[i] += BU[i]for j in range(DIM):beta_rhsU[i] += betaU[j] * betaU_dupD[i][j]# Compute right-hand side of B^i:eta = par.Cparameters("REAL", thismodule, ["eta"],2.0)# Step 3.a.ii: Compute right-hand side of B^i# * \partial_t B^i = \beta^j B^i_{,j} + 3/4 * \partial_0 \Lambda^i - eta B^i# Step 3.a.iii: Define BU_dupD, in terms of derivative of rescaled variable \bet^iBU_dupD = ixp.zerorank2()betU_dupD = ixp.declarerank2("betU_dupD", "nosym")for i in range(DIM):for j in range(DIM):BU_dupD[i][j] = betU_dupD[i][j] * rfm.ReU[i] + betU[i] * rfm.ReUdD[i][j]# Step 3.a.iv: Compute \partial_0 \bar{\Lambda}^i = (\partial_t - \beta^i \partial_i) \bar{\Lambda}^jLambdabar_partial0 = ixp.zerorank1()for i in range(DIM):Lambdabar_partial0[i] = Brhs.Lambdabar_rhsU[i]for i in range(DIM):for j in range(DIM):Lambdabar_partial0[j] += -betaU[i] * Brhs.LambdabarU_dupD[j][i]# Step 3.a.v: Evaluate RHS of B^i:for i in range(DIM):B_rhsU[i] += sp.Rational(3, 4) * Lambdabar_partial0[i] - eta * BU[i]for j in range(DIM):B_rhsU[i] += betaU[j] * BU_dupD[i][j]# Step 3.b: The right-hand side of the \partial_t \beta^i equationif "GammaDriving2ndOrder_Covariant" in ShiftEvolOption:# Step 3.b Option 2: \partial_t \beta^i = \left[\beta^j \bar{D}_j \beta^i\right] + B^{i}# First we need GammabarUDD, defined in Bq.gammabar__inverse_and_derivs()Bq.gammabar__inverse_and_derivs()ConnectionUDD = Bq.GammabarUDD# If instead we wish to use the Hatted covariant derivative, we replace# ConnectionUDD with GammahatUDD:if ShiftEvolOption == "GammaDriving2ndOrder_Covariant__Hatted":ConnectionUDD = rfm.GammahatUDD# Then compute right-hand side:# Term 1: \beta^j \beta^i_{,j}for i in range(DIM):for j in range(DIM):beta_rhsU[i] += betaU[j] * betaU_dupD[i][j]# Term 2: \beta^j \bar{\Gamma}^i_{mj} \beta^mfor i in range(DIM):for j in range(DIM):for m in range(DIM):beta_rhsU[i] += betaU[j] * ConnectionUDD[i][m][j] * betaU[m]# Term 3: B^ifor i in range(DIM):beta_rhsU[i] += BU[i]if "GammaDriving2ndOrder_Covariant" in ShiftEvolOption:ConnectionUDD = Bq.GammabarUDD# If instead we wish to use the Hatted covariant derivative, we replace# ConnectionUDD with GammahatUDD:if ShiftEvolOption == "GammaDriving2ndOrder_Covariant__Hatted":ConnectionUDD = rfm.GammahatUDD# Step 3.c: Covariant option:# \partial_t B^i = \beta^j \bar{D}_j B^i# + \frac{3}{4} ( \partial_t \bar{\Lambda}^{i} - \beta^j \bar{D}_j \bar{\Lambda}^{i} )# - \eta B^{i}# = \beta^j B^i_{,j} + \beta^j \bar{\Gamma}^i_{mj} B^m# + \frac{3}{4}[ \partial_t \bar{\Lambda}^{i}# - \beta^j (\bar{\Lambda}^i_{,j} + \bar{\Gamma}^i_{mj} \bar{\Lambda}^m)]# - \eta B^{i}# Term 1, part a: First compute B^i_{,j} using upwinded derivativeBU_dupD = ixp.zerorank2()betU_dupD = ixp.declarerank2("betU_dupD", "nosym")for i in range(DIM):for j in range(DIM):BU_dupD[i][j] = betU_dupD[i][j] * rfm.ReU[i] + betU[i] * rfm.ReUdD[i][j]# Term 1: \beta^j B^i_{,j}for i in range(DIM):for j in range(DIM):B_rhsU[i] += betaU[j] * BU_dupD[i][j]# Term 2: \beta^j \bar{\Gamma}^i_{mj} B^mfor i in range(DIM):for j in range(DIM):for m in range(DIM):B_rhsU[i] += betaU[j] * ConnectionUDD[i][m][j] * BU[m]# Term 3: \frac{3}{4}\partial_t \bar{\Lambda}^{i}for i in range(DIM):B_rhsU[i] += sp.Rational(3, 4) * Brhs.Lambdabar_rhsU[i]# Term 4: -\frac{3}{4}\beta^j \bar{\Lambda}^i_{,j}for i in range(DIM):for j in range(DIM):B_rhsU[i] += -sp.Rational(3, 4) * betaU[j] * Brhs.LambdabarU_dupD[i][j]# Term 5: -\frac{3}{4}\beta^j \bar{\Gamma}^i_{mj} \bar{\Lambda}^mfor i in range(DIM):for j in range(DIM):for m in range(DIM):B_rhsU[i] += -sp.Rational(3, 4) * betaU[j] * ConnectionUDD[i][m][j] * Bq.LambdabarU[m]# Term 6: - \eta B^i# eta is a free parameter; we declare it here:eta = par.Cparameters("REAL", thismodule, ["eta"],2.0)for i in range(DIM):B_rhsU[i] += -eta * BU[i]if "GammaDriving1stOrder_Covariant" in ShiftEvolOption:# Step 3.c: \partial_t \beta^i = \left[\beta^j \bar{D}_j \beta^i\right] + 3/4 Lambdabar^i - eta*beta^i# First set \partial_t B^i = 0:B_rhsU = ixp.zerorank1() # \partial_t B^i = 0# Second, set \partial_t beta^i RHS:# Compute covariant advection term:# We need GammabarUDD, defined in Bq.gammabar__inverse_and_derivs()Bq.gammabar__inverse_and_derivs()ConnectionUDD = Bq.GammabarUDD# If instead we wish to use the Hatted covariant derivative, we replace# ConnectionUDD with GammahatUDD:if ShiftEvolOption == "GammaDriving1stOrder_Covariant__Hatted":ConnectionUDD = rfm.GammahatUDD# Term 1: \beta^j \beta^i_{,j}for i in range(DIM):for j in range(DIM):beta_rhsU[i] += betaU[j] * betaU_dupD[i][j]# Term 2: \beta^j \bar{\Gamma}^i_{mj} \beta^mfor i in range(DIM):for j in range(DIM):for m in range(DIM):beta_rhsU[i] += betaU[j] * ConnectionUDD[i][m][j] * betaU[m]# Term 3: 3/4 Lambdabar^i - eta*beta^ieta = par.Cparameters("REAL", thismodule, ["eta"], 2.0)for i in range(DIM):beta_rhsU[i] += sp.Rational(3, 4) * Bq.LambdabarU[i] - eta * betaU[i]# Step 4: Rescale the BSSN gauge RHS quantities so that the evolved# variables may remain smooth across coord singularitiesglobal vet_rhsU,bet_rhsUvet_rhsU = ixp.zerorank1()bet_rhsU = ixp.zerorank1()for i in range(DIM):vet_rhsU[i] = beta_rhsU[i] / rfm.ReU[i]bet_rhsU[i] = B_rhsU[i] / rfm.ReU[i]# print(str(Abar_rhsDD[2][2]).replace("**","^").replace("_","").replace("xx","x").replace("sin(x2)","Sin[x2]").replace("sin(2*x2)","Sin[2*x2]").replace("cos(x2)","Cos[x2]").replace("detgbaroverdetghat","detg"))# print(str(Dbarbetacontraction).replace("**","^").replace("_","").replace("xx","x").replace("sin(x2)","Sin[x2]").replace("detgbaroverdetghat","detg"))# print(betaU_dD)# print(str(trK_rhs).replace("xx2","xx3").replace("xx1","xx2").replace("xx0","xx1").replace("**","^").replace("_","").replace("sin(xx2)","Sinx2").replace("xx","x").replace("sin(2*x2)","Sin2x2").replace("cos(x2)","Cosx2").replace("detgbaroverdetghat","detg"))# print(str(bet_rhsU[0]).replace("xx2","xx3").replace("xx1","xx2").replace("xx0","xx1").replace("**","^").replace("_","").replace("sin(xx2)","Sinx2").replace("xx","x").replace("sin(2*x2)","Sin2x2").replace("cos(x2)","Cosx2").replace("detgbaroverdetghat","detg"))
# As documented in the NRPy+ tutorial module# Tutorial-BSSN_in_terms_of_ADM.ipynb,# this module will construct expressions for BSSN# quantities in terms of ADM quantities.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step 1: Import needed core NRPy+ modulesfrom outputC import * # NRPy+: Core C code output moduleimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport reference_metric as rfm # NRPy+: Reference metric supportimport sys # Standard Python modules for multiplatform OS-level functionsimport BSSN.BSSN_quantities as Bq # NRPy+: This module depends on the parameter EvolvedConformalFactor_cf,# which is defined in BSSN.BSSN_quantities# Step 1.a: Set DIM=3, as we're using a 3+1 decomposition of Einstein's equationsDIM=3# Step 2: All ADM quantities were input into this function in the Spherical or Cartesian# basis, as functions of r,th,ph or x,y,z, respectively. In Steps 1 and 2 above,# we converted them to the xx0,xx1,xx2 basis, and as functions of xx0,xx1,xx2.# Here we convert ADM quantities to their BSSN Curvilinear counterparts:# Step 2.a: Convert ADM $\gamma_{ij}$ to BSSN $\bar{gamma}_{ij}$:# We have (Eqs. 2 and 3 of [Ruchlin *et al.*](https://arxiv.org/pdf/1712.07658.pdf)):def gammabarDD_hDD(gammaDD):global gammabarDD,hDDif gammaDD == None:gammaDD = ixp.declarerank2("gammaDD","sym01")if rfm.have_already_called_reference_metric_function == False:print("BSSN.BSSN_in_terms_of_ADM.hDD_given_ADM(): Must call reference_metric() first!")sys.exit(1)# \bar{gamma}_{ij} = (\frac{\bar{gamma}}{gamma})^{1/3}*gamma_{ij}.gammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD)gammabarDD = ixp.zerorank2()hDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):gammabarDD[i][j] = (rfm.detgammahat/gammaDET)**(sp.Rational(1,3))*gammaDD[i][j]hDD[i][j] = (gammabarDD[i][j] - rfm.ghatDD[i][j]) / rfm.ReDD[i][j]# Step 2.b: Convert the extrinsic curvature K_{ij} to the trace-free extrinsic# curvature \bar{A}_{ij}, plus the trace of the extrinsic curvature K,# where (Eq. 3 of [Baumgarte *et al.*](https://arxiv.org/pdf/1211.6632.pdf)):def trK_AbarDD_aDD(gammaDD,KDD):global trK,AbarDD,aDDif gammaDD == None:gammaDD = ixp.declarerank2("gammaDD","sym01")if KDD == None:KDD = ixp.declarerank2("KDD","sym01")if rfm.have_already_called_reference_metric_function == False:print("BSSN.BSSN_in_terms_of_ADM.trK_AbarDD(): Must call reference_metric() first!")sys.exit(1)# \bar{gamma}_{ij} = (\frac{\bar{gamma}}{gamma})^{1/3}*gamma_{ij}.gammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD)# K = gamma^{ij} K_{ij}, and# \bar{A}_{ij} &= (\frac{\bar{gamma}}{gamma})^{1/3}*(K_{ij} - \frac{1}{3}*gamma_{ij}*K)trK = sp.sympify(0)for i in range(DIM):for j in range(DIM):trK += gammaUU[i][j]*KDD[i][j]AbarDD = ixp.zerorank2()aDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):AbarDD[i][j] = (rfm.detgammahat/gammaDET)**(sp.Rational(1,3))*(KDD[i][j] - sp.Rational(1,3)*gammaDD[i][j]*trK)aDD[i][j] = AbarDD[i][j] / rfm.ReDD[i][j]# Step 2.c: Define \bar{Lambda}^i (Eqs. 4 and 5 of [Baumgarte *et al.*](https://arxiv.org/pdf/1211.6632.pdf)):def LambdabarU_lambdaU__exact_gammaDD(gammaDD):global LambdabarU, lambdaUif gammaDD == None:gammaDD = ixp.declarerank2("gammaDD","sym01")# \bar{Lambda}^i = \bar{gamma}^{jk}(\bar{Gamma}^i_{jk} - \hat{Gamma}^i_{jk}).gammabarDD_hDD(gammaDD)gammabarUU, gammabarDET = ixp.symm_matrix_inverter3x3(gammabarDD)# First compute Christoffel symbols \bar{Gamma}^i_{jk}, with respect to barred metric:GammabarUDD = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):GammabarUDD[i][j][k] += sp.Rational(1, 2) * gammabarUU[i][l] * (sp.diff(gammabarDD[l][j], rfm.xx[k]) +sp.diff(gammabarDD[l][k], rfm.xx[j]) -sp.diff(gammabarDD[j][k], rfm.xx[l]))# Next evaluate \bar{Lambda}^i, based on GammabarUDD above and GammahatUDD# (from the reference metric):LambdabarU = ixp.zerorank1()for i in range(DIM):for j in range(DIM):for k in range(DIM):LambdabarU[i] += gammabarUU[j][k] * (GammabarUDD[i][j][k] - rfm.GammahatUDD[i][j][k])lambdaU = ixp.zerorank1()for i in range(DIM):lambdaU[i] = LambdabarU[i] / rfm.ReU[i]# Step 2.d: Set the conformal factor variable cf, which is set# by the "BSSN_quantities::EvolvedConformalFactor_cf" parameter. For example if# "EvolvedConformalFactor_cf" is set to "phi", we can use Eq. 3 of# [Ruchlin *et al.*](https://arxiv.org/pdf/1712.07658.pdf),# which in arbitrary coordinates is written:def cf_from_gammaDD(gammaDD):global cfif gammaDD == None:gammaDD = ixp.declarerank2("gammaDD","sym01")# \bar{Lambda}^i = \bar{gamma}^{jk}(\bar{Gamma}^i_{jk} - \hat{Gamma}^i_{jk}).gammabarDD_hDD(gammaDD)gammabarUU, gammabarDET = ixp.symm_matrix_inverter3x3(gammabarDD)gammaUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaDD)cf = sp.sympify(0)if par.parval_from_str("EvolvedConformalFactor_cf") == "phi":# phi = \frac{1}{12} log(\frac{gamma}{\bar{gamma}}).cf = sp.Rational(1, 12) * sp.log(gammaDET / gammabarDET)elif par.parval_from_str("EvolvedConformalFactor_cf") == "chi":# chi = exp(-4*phi) = exp(-4*\frac{1}{12}*(\frac{gamma}{\bar{gamma}}))# = exp(-\frac{1}{3}*log(\frac{gamma}{\bar{gamma}})) = (\frac{gamma}{\bar{gamma}})^{-1/3}.#cf = (gammaDET / gammabarDET) ** (-sp.Rational(1, 3))elif par.parval_from_str("EvolvedConformalFactor_cf") == "W":# W = exp(-2*phi) = exp(-2*\frac{1}{12}*log(\frac{gamma}{\bar{gamma}}))# = exp(-\frac{1}{6}*log(\frac{gamma}{\bar{gamma}})) = (\frac{gamma}{bar{gamma}})^{-1/6}.cf = (gammaDET / gammabarDET) ** (-sp.Rational(1, 6))else:print("Error EvolvedConformalFactor_cf type = \"" + par.parval_from_str("EvolvedConformalFactor_cf") + "\" unknown.")sys.exit(1)# Step 2.e: Rescale beta^i and B^i according to the prescription described in# the [BSSN in curvilinear coordinates tutorial module](Tutorial-BSSNCurvilinear.ipynb)# (also [Ruchlin *et al.*](https://arxiv.org/pdf/1712.07658.pdf)):## \mathcal{V}^i &= beta^i/(ReU[i])# \mathcal{B}^i &= B^i/(ReU[i])def betU_vetU(betaU,BU):global vetU,betUif betaU == None:betaU = ixp.declarerank1("betaU")if BU == None:BU = ixp.declarerank1("BU")if rfm.have_already_called_reference_metric_function == False:print("BSSN.BSSN_in_terms_of_ADM.bet_vet(): Must call reference_metric() first!")sys.exit(1)vetU = ixp.zerorank1()betU = ixp.zerorank1()for i in range(DIM):vetU[i] = betaU[i] / rfm.ReU[i]betU[i] = BU[i] / rfm.ReU[i]
# This module provides functions that declare and define useful BSSN quantities# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step 1: Import all needed modules from NRPy+:import NRPy_param_funcs as par # NRPy+: Parameter interfaceimport sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport grid as gri # NRPy+: Functions having to do with numerical gridsimport reference_metric as rfm # NRPy+: Reference metric supportimport sys # Standard Python modules for multiplatform OS-level functions# Step 1.a: Set the coordinate system for the numerical grid# DO NOT SET IN STANDALONE PYTHON MODULE# par.set_parval_from_str("reference_metric::CoordSystem","Spherical")# Step 1.b: Given the chosen coordinate system, set up# corresponding reference metric and needed# reference metric quantities# The following function call sets up the reference metric# and related quantities, including rescaling matrices ReDD,# ReU, and hatted quantities.# DO NOT CALL IN STANDALONE PYTHON MODULE# rfm.reference_metric()# Step 1.c: Set spatial dimension (must be 3 for BSSN, as BSSN is# a 3+1-dimensional decomposition of the general# relativistic field equations)# DO NOT CALL IN STANDALONE PYTHON MODULE# DIM = 3# par.set_parval_from_str("grid::DIM",DIM)# Step 1.d: Declare/initialize parameters for this modulethismodule = __name__par.initialize_param(par.glb_param("char", thismodule, "EvolvedConformalFactor_cf", "W"))par.initialize_param(par.glb_param("bool", thismodule, "detgbarOverdetghat_equals_one", "True"))par.initialize_param(par.glb_param("bool", thismodule, "LeaveRicciSymbolic", "False"))def declare_BSSN_gridfunctions_if_not_declared_already():# Step 2: Register all needed BSSN gridfunctions.# Declare as globals all variables that may be# used outside this functionglobal hDD,aDD,lambdaU,vetU,betU,trK,cf,alpha# Check to see if this function has already been called.# If so, do not register the gridfunctions again!for i in range(len(gri.glb_gridfcs_list)):if "hDD00" in gri.glb_gridfcs_list[i].name:hDD = ixp.declarerank2("hDD", "sym01")aDD = ixp.declarerank2("aDD", "sym01")lambdaU = ixp.declarerank1("lambdaU")vetU = ixp.declarerank1("vetU")betU = ixp.declarerank1("betU")trK, cf, alpha = sp.symbols('trK cf alpha', real=True)return hDD, aDD, lambdaU, vetU, betU, trK, cf, alpha# Step 2.a: Register indexed quantities, using ixp.register_... functionshDD = ixp.register_gridfunctions_for_single_rank2("EVOL", "hDD", "sym01")aDD = ixp.register_gridfunctions_for_single_rank2("EVOL", "aDD", "sym01")lambdaU = ixp.register_gridfunctions_for_single_rank1("EVOL", "lambdaU")vetU = ixp.register_gridfunctions_for_single_rank1("EVOL", "vetU")betU = ixp.register_gridfunctions_for_single_rank1("EVOL", "betU")# Step 2.b: Register scalar quantities, using gri.register_gridfunctions()trK, cf, alpha = gri.register_gridfunctions("EVOL", ["trK", "cf", "alpha"])return hDD, aDD, lambdaU, vetU, betU, trK, cf, alpha# Step 3: Define all basic conformal BSSN tensors# gammabarDD,AbarDD,LambdabarU,betaU,BU# in terms of BSSN gridfunctions.def BSSN_basic_tensors():# Step 3.a: Declare as globals all variables that may be used# outside this function, declare BSSN gridfunctions# if not defined already, and set DIM=3.global gammabarDD,AbarDD,LambdabarU,betaU,BUhDD, aDD, lambdaU, vetU, betU, trK, cf, alpha = declare_BSSN_gridfunctions_if_not_declared_already()DIM = 3# Step 3.a.i: gammabarDD and AbarDD:gammabarDD = ixp.zerorank2()AbarDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):# gammabar_{ij} = h_{ij}*ReDD[i][j] + gammahat_{ij}gammabarDD[i][j] = hDD[i][j] * rfm.ReDD[i][j] + rfm.ghatDD[i][j]# Abar_{ij} = a_{ij}*ReDD[i][j]AbarDD[i][j] = aDD[i][j] * rfm.ReDD[i][j]# Step 3.a.ii: LambdabarU, betaU, and BU:LambdabarU = ixp.zerorank1()betaU = ixp.zerorank1()BU = ixp.zerorank1()for i in range(DIM):LambdabarU[i] = lambdaU[i] * rfm.ReU[i]betaU[i] = vetU[i] * rfm.ReU[i]BU[i] = betU[i] * rfm.ReU[i]# Step 4: gammabarUU and spatial derivatives of gammabarDD,# including GammabarUDDdef gammabar__inverse_and_derivs():# Step 4.a: Declare as globals all expressions that may be used# outside this function, declare BSSN gridfunctions# if not defined already, and set DIM=3.global gammabarUU, gammabarDD_dD, gammabarDD_dupD, gammabarDD_dDD, GammabarUDDhDD, aDD, lambdaU, vetU, betU, trK, cf, alpha = declare_BSSN_gridfunctions_if_not_declared_already()DIM = 3# This function needs gammabarDD, defined in BSSN_basic_tensors()BSSN_basic_tensors()# Step 4.a.i: gammabarUU:gammabarUU, dummydet = ixp.symm_matrix_inverter3x3(gammabarDD)# Step 4.b.i: gammabarDDdD[i][j][k]# = \hat{\gamma}_{ij,k} + h_{ij,k} \text{ReDD[i][j]} + h_{ij} \text{ReDDdD[i][j][k]}.gammabarDD_dD = ixp.zerorank3()gammabarDD_dupD = ixp.zerorank3()hDD_dD = ixp.declarerank3("hDD_dD", "sym01")hDD_dupD = ixp.declarerank3("hDD_dupD", "sym01")for i in range(DIM):for j in range(DIM):for k in range(DIM):gammabarDD_dD[i][j][k] = rfm.ghatDDdD[i][j][k] + \hDD_dD[i][j][k] * rfm.ReDD[i][j] + hDD[i][j] * rfm.ReDDdD[i][j][k]# Compute associated upwinded derivative, needed for the \bar{\gamma}_{ij} RHSgammabarDD_dupD[i][j][k] = rfm.ghatDDdD[i][j][k] + \hDD_dupD[i][j][k] * rfm.ReDD[i][j] + hDD[i][j] * rfm.ReDDdD[i][j][k]# Step 4.b.ii: Compute gammabarDD_dDD in terms of the rescaled BSSN quantity hDD# and its derivatives, as well as the reference metric and rescaling# matrix, and its derivatives (expression given below):hDD_dDD = ixp.declarerank4("hDD_dDD", "sym01_sym23")gammabarDD_dDD = ixp.zerorank4()for i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):# gammabar_{ij,kl} = gammahat_{ij,kl}# + h_{ij,kl} ReDD[i][j]# + h_{ij,k} ReDDdD[i][j][l] + h_{ij,l} ReDDdD[i][j][k]# + h_{ij} ReDDdDD[i][j][k][l]gammabarDD_dDD[i][j][k][l] = rfm.ghatDDdDD[i][j][k][l]gammabarDD_dDD[i][j][k][l] += hDD_dDD[i][j][k][l] * rfm.ReDD[i][j]gammabarDD_dDD[i][j][k][l] += hDD_dD[i][j][k] * rfm.ReDDdD[i][j][l] + \hDD_dD[i][j][l] * rfm.ReDDdD[i][j][k]gammabarDD_dDD[i][j][k][l] += hDD[i][j] * rfm.ReDDdDD[i][j][k][l]# Step 4.b.iii: Define barred Christoffel symbol \bar{\Gamma}^{i}_{kl} = GammabarUDD[i][k][l] (see expression below)GammabarUDD = ixp.zerorank3()for i in range(DIM):for k in range(DIM):for l in range(DIM):for m in range(DIM):# Gammabar^i_{kl} = 1/2 * gammabar^{im} ( gammabar_{mk,l} + gammabar_{ml,k} - gammabar_{kl,m}):GammabarUDD[i][k][l] += sp.Rational(1, 2) * gammabarUU[i][m] * \(gammabarDD_dD[m][k][l] + gammabarDD_dD[m][l][k] - gammabarDD_dD[k][l][m])# Step 5: det(gammabarDD) and its derivativesdef detgammabar_and_derivs():# Step 5.a: Declare as globals all expressions that may be used# outside this function, declare BSSN gridfunctions# if not defined already, and set DIM=3.global detgammabar,detgammabar_dD,detgammabar_dDDhDD, aDD, lambdaU, vetU, betU, trK, cf, alpha = declare_BSSN_gridfunctions_if_not_declared_already()DIM = 3detgbarOverdetghat = sp.sympify(1)detgbarOverdetghat_dD = ixp.zerorank1()detgbarOverdetghat_dDD = ixp.zerorank2()if par.parval_from_str(thismodule + "::detgbarOverdetghat_equals_one") == "False":print("Error: detgbarOverdetghat_equals_one=\"False\" is not fully implemented yet.")sys.exit(1)## Approach for implementing detgbarOverdetghat_equals_one=False:# detgbarOverdetghat = gri.register_gridfunctions("AUX", ["detgbarOverdetghat"])# detgbarOverdetghatInitial = gri.register_gridfunctions("AUX", ["detgbarOverdetghatInitial"])# detgbarOverdetghat_dD = ixp.declarerank1("detgbarOverdetghat_dD")# detgbarOverdetghat_dDD = ixp.declarerank2("detgbarOverdetghat_dDD", "sym01")# Step 5.b: Define detgammabar, detgammabar_dD, and detgammabar_dDD (needed for \partial_t \bar{\Lambda}^i below)detgammabar = detgbarOverdetghat * rfm.detgammahatdetgammabar_dD = ixp.zerorank1()for i in range(DIM):detgammabar_dD[i] = detgbarOverdetghat_dD[i] * rfm.detgammahat + detgbarOverdetghat * rfm.detgammahatdD[i]detgammabar_dDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):detgammabar_dDD[i][j] = detgbarOverdetghat_dDD[i][j] * rfm.detgammahat + \detgbarOverdetghat_dD[i] * rfm.detgammahatdD[j] + \detgbarOverdetghat_dD[j] * rfm.detgammahatdD[i] + \detgbarOverdetghat * rfm.detgammahatdDD[i][j]# Step 6: Quantities related to conformal traceless# extrinsic curvature AbarDD:# AbarUU, AbarUD, and trAbardef AbarUU_AbarUD_trAbar_AbarDD_dD():# Step 6.a: Declare as globals all expressions that may be used# outside this function, declare BSSN gridfunctions# if not defined already, and set DIM=3.global AbarUU,AbarUD,trAbar,AbarDD_dD,AbarDD_dupDhDD, aDD, lambdaU, vetU, betU, trK, cf, alpha = declare_BSSN_gridfunctions_if_not_declared_already()DIM = 3# Define AbarDD and gammabarDD in terms of BSSN gridfunctionsBSSN_basic_tensors()# Define gammabarUU in terms of BSSN gridfunctionsgammabar__inverse_and_derivs()# Step 6.a.i: Compute Abar^{ij} in terms of Abar_{ij} and gammabar^{ij}AbarUU = ixp.zerorank2()for i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):# Abar^{ij} = gammabar^{ik} gammabar^{jl} Abar_{kl}AbarUU[i][j] += gammabarUU[i][k] * gammabarUU[j][l] * AbarDD[k][l]# Step 6.a.ii: Compute Abar^i_j in terms of Abar_{ij} and gammabar^{ij}AbarUD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):for k in range(DIM):# Abar^i_j = gammabar^{ik} Abar_{kj}AbarUD[i][j] += gammabarUU[i][k] * AbarDD[k][j]# Step 6.a.iii: Compute Abar^k_k = trace of Abar:trAbar = sp.sympify(0)for k in range(DIM):for j in range(DIM):# Abar^k_k = gammabar^{kj} Abar_{jk}trAbar += gammabarUU[k][j] * AbarDD[j][k]# Step 6.a.iv: Compute Abar_{ij,k}AbarDD_dD = ixp.zerorank3()AbarDD_dupD = ixp.zerorank3()aDD_dD = ixp.declarerank3("aDD_dD" ,"sym01")aDD_dupD = ixp.declarerank3("aDD_dupD","sym01")for i in range(DIM):for j in range(DIM):for k in range(DIM):AbarDD_dupD[i][j][k] = rfm.ReDDdD[i][j][k]*aDD[i][j] + rfm.ReDD[i][j]*aDD_dupD[i][j][k]AbarDD_dD[i][j][k] = rfm.ReDDdD[i][j][k]*aDD[i][j] + rfm.ReDD[i][j]*aDD_dD[ i][j][k]# Step 7: The conformal ("barred") Ricci tensor RbarDD# and associated quantitiesdef RicciBar__gammabarDD_dHatD__DGammaUDD__DGammaU():# Step 7.a: Declare as globals all expressions that may be used# outside this function, declare BSSN gridfunctions# if not defined already, and set DIM=3.global RbarDD,DGammaUDD,gammabarDD_dHatD,DGammaUhDD, aDD, lambdaU, vetU, betU, trK, cf, alpha = declare_BSSN_gridfunctions_if_not_declared_already()DIM = 3# GammabarUDD is used below, defined in# gammabar__inverse_and_derivs()gammabar__inverse_and_derivs()# Step 7.a.i: Define \varepsilon_{ij} = epsDD[i][j]epsDD = ixp.zerorank3()for i in range(DIM):for j in range(DIM):epsDD[i][j] = hDD[i][j] * rfm.ReDD[i][j]# Step 7.a.ii: Define epsDD_dD[i][j][k]hDD_dD = ixp.declarerank3("hDD_dD", "sym01")epsDD_dD = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for k in range(DIM):epsDD_dD[i][j][k] = hDD_dD[i][j][k] * rfm.ReDD[i][j] + hDD[i][j] * rfm.ReDDdD[i][j][k]# Step 7.a.iii: Define epsDD_dDD[i][j][k][l]hDD_dDD = ixp.declarerank4("hDD_dDD", "sym01_sym23")epsDD_dDD = ixp.zerorank4()for i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):epsDD_dDD[i][j][k][l] = hDD_dDD[i][j][k][l] * rfm.ReDD[i][j] + \hDD_dD[i][j][k] * rfm.ReDDdD[i][j][l] + \hDD_dD[i][j][l] * rfm.ReDDdD[i][j][k] + \hDD[i][j] * rfm.ReDDdDD[i][j][k][l]# Step 7.a.iv: DhatgammabarDDdD[i][j][l] = \bar{\gamma}_{ij;\hat{l}}# \bar{\gamma}_{ij;\hat{l}} = \varepsilon_{i j,l}# - \hat{\Gamma}^m_{i l} \varepsilon_{m j}# - \hat{\Gamma}^m_{j l} \varepsilon_{i m}gammabarDD_dHatD = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for l in range(DIM):gammabarDD_dHatD[i][j][l] = epsDD_dD[i][j][l]for m in range(DIM):gammabarDD_dHatD[i][j][l] += - rfm.GammahatUDD[m][i][l] * epsDD[m][j] \- rfm.GammahatUDD[m][j][l] * epsDD[i][m]# Step 7.a.v: \bar{\gamma}_{ij;\hat{l},k} = DhatgammabarDD_dHatD_dD[i][j][l][k]:# \bar{\gamma}_{ij;\hat{l},k} = \varepsilon_{ij,lk}# - \hat{\Gamma}^m_{i l,k} \varepsilon_{m j}# - \hat{\Gamma}^m_{i l} \varepsilon_{m j,k}# - \hat{\Gamma}^m_{j l,k} \varepsilon_{i m}# - \hat{\Gamma}^m_{j l} \varepsilon_{i m,k}gammabarDD_dHatD_dD = ixp.zerorank4()for i in range(DIM):for j in range(DIM):for l in range(DIM):for k in range(DIM):gammabarDD_dHatD_dD[i][j][l][k] = epsDD_dDD[i][j][l][k]for m in range(DIM):gammabarDD_dHatD_dD[i][j][l][k] += -rfm.GammahatUDDdD[m][i][l][k] * epsDD[m][j] \- rfm.GammahatUDD[m][i][l] * epsDD_dD[m][j][k] \- rfm.GammahatUDDdD[m][j][l][k] * epsDD[i][m] \- rfm.GammahatUDD[m][j][l] * epsDD_dD[i][m][k]# Step 7.a.vi: \bar{\gamma}_{ij;\hat{l}\hat{k}} = DhatgammabarDD_dHatDD[i][j][l][k]# \bar{\gamma}_{ij;\hat{l}\hat{k}} = \partial_k \hat{D}_{l} \varepsilon_{i j}# - \hat{\Gamma}^m_{lk} \left(\hat{D}_{m} \varepsilon_{i j}\right)# - \hat{\Gamma}^m_{ik} \left(\hat{D}_{l} \varepsilon_{m j}\right)# - \hat{\Gamma}^m_{jk} \left(\hat{D}_{l} \varepsilon_{i m}\right)gammabarDD_dHatDD = ixp.zerorank4()for i in range(DIM):for j in range(DIM):for l in range(DIM):for k in range(DIM):gammabarDD_dHatDD[i][j][l][k] = gammabarDD_dHatD_dD[i][j][l][k]for m in range(DIM):gammabarDD_dHatDD[i][j][l][k] += - rfm.GammahatUDD[m][l][k] * gammabarDD_dHatD[i][j][m] \- rfm.GammahatUDD[m][i][k] * gammabarDD_dHatD[m][j][l] \- rfm.GammahatUDD[m][j][k] * gammabarDD_dHatD[i][m][l]# Step 7.b: Second term of RhatDD: compute \hat{D}_{j} \bar{\Lambda}^{k} = LambarU_dHatD[k][j]lambdaU_dD = ixp.declarerank2("lambdaU_dD", "nosym")LambarU_dHatD = ixp.zerorank2()for j in range(DIM):for k in range(DIM):LambarU_dHatD[k][j] = lambdaU_dD[k][j] * rfm.ReU[k] + lambdaU[k] * rfm.ReUdD[k][j]for m in range(DIM):LambarU_dHatD[k][j] += rfm.GammahatUDD[k][m][j] * lambdaU[m] * rfm.ReU[m]# Step 7.c: Conformal Ricci tensor, part 3: The \Delta^{k} \Delta_{(i j) k}# + \bar{\gamma}^{k l}*(2 \Delta_{k(i}^{m} \Delta_{j) m l}# + \Delta_{i k}^{m} \Delta_{m j l}) terms# Step 7.c.i: Define \Delta^i_{jk} = \bar{\Gamma}^i_{jk} - \hat{\Gamma}^i_{jk} = DGammaUDD[i][j][k]DGammaUDD = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for k in range(DIM):DGammaUDD[i][j][k] = GammabarUDD[i][j][k] - rfm.GammahatUDD[i][j][k]# Step 7.c.ii: Define \Delta^i = \bar{\gamma}^{jk} \Delta^i_{jk}DGammaU = ixp.zerorank1()for i in range(DIM):for j in range(DIM):for k in range(DIM):DGammaU[i] += gammabarUU[j][k] * DGammaUDD[i][j][k]# Step 7.c.iii: Define \Delta_{ijk} = \bar{\gamma}_{im} \Delta^m_{jk}DGammaDDD = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for k in range(DIM):for m in range(DIM):DGammaDDD[i][j][k] += gammabarDD[i][m] * DGammaUDD[m][j][k]if par.parval_from_str(thismodule+"::LeaveRicciSymbolic") == "True":for i in range(len(gri.glb_gridfcs_list)):if "RbarDD00" in gri.glb_gridfcs_list[i].name:returnRbarDD = ixp.register_gridfunctions_for_single_rank2("AUXEVOL","RbarDD","sym01")return# Step 7.d: Summing the terms and defining \bar{R}_{ij}# Step 7.d.i: Add the first term to RbarDD:# Rbar_{ij} += - \frac{1}{2} \bar{\gamma}^{k l} \hat{D}_{k} \hat{D}_{l} \bar{\gamma}_{i j}RbarDD = ixp.zerorank2()RbarDDpiece = ixp.zerorank2()for i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):RbarDD[i][j] += -sp.Rational(1, 2) * gammabarUU[k][l] * gammabarDD_dHatDD[i][j][l][k]RbarDDpiece[i][j] += -sp.Rational(1, 2) * gammabarUU[k][l] * gammabarDD_dHatDD[i][j][l][k]# Step 7.d.ii: Add the second term to RbarDD:# Rbar_{ij} += (1/2) * (gammabar_{ki} Lambar^k_{;\hat{j}} + gammabar_{kj} Lambar^k_{;\hat{i}})for i in range(DIM):for j in range(DIM):for k in range(DIM):RbarDD[i][j] += sp.Rational(1, 2) * ( gammabarDD[k][i] * LambarU_dHatD[k][j] +gammabarDD[k][j] * LambarU_dHatD[k][i] )# Step 7.d.iii: Add the remaining term to RbarDD:# Rbar_{ij} += \Delta^{k} \Delta_{(i j) k} = 1/2 \Delta^{k} (\Delta_{i j k} + \Delta_{j i k})for i in range(DIM):for j in range(DIM):for k in range(DIM):RbarDD[i][j] += sp.Rational(1, 2) * DGammaU[k] * (DGammaDDD[i][j][k] + DGammaDDD[j][i][k])# Step 7.d.iv: Add the final term to RbarDD:# Rbar_{ij} += \bar{\gamma}^{k l} (\Delta^{m}_{k i} \Delta_{j m l}# + \Delta^{m}_{k j} \Delta_{i m l}# + \Delta^{m}_{i k} \Delta_{m j l})for i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):for m in range(DIM):RbarDD[i][j] += gammabarUU[k][l] * (DGammaUDD[m][k][i] * DGammaDDD[j][m][l] +DGammaUDD[m][k][j] * DGammaDDD[i][m][l] +DGammaUDD[m][i][k] * DGammaDDD[m][j][l])# Step 8: The unrescaled shift vector betaU spatial derivatives:# betaUdD & betaUdDD, written in terms of the# rescaled shift vector vetUdef betaU_derivs():# Step 8.i: Declare as globals all expressions that may be used# outside this function, declare BSSN gridfunctions# if not defined already, and set DIM=3.global betaU_dD,betaU_dupD,betaU_dDDhDD, aDD, lambdaU, vetU, betU, trK, cf, alpha = declare_BSSN_gridfunctions_if_not_declared_already()DIM = 3# Step 8.ii: Compute the unrescaled shift vector beta^i = ReU[i]*vet^ivetU_dD = ixp.declarerank2("vetU_dD", "nosym")vetU_dupD = ixp.declarerank2("vetU_dupD", "nosym") # Needed for upwinded \beta^i_{,j}vetU_dDD = ixp.declarerank3("vetU_dDD", "sym12") # Needed for \beta^i_{,j}betaU_dD = ixp.zerorank2()betaU_dupD = ixp.zerorank2() # Needed for, e.g., \beta^i RHSbetaU_dDD = ixp.zerorank3() # Needed for, e.g., \bar{\Lambda}^i RHSfor i in range(DIM):for j in range(DIM):betaU_dD[i][j] = vetU_dD[i][j] * rfm.ReU[i] + vetU[i] * rfm.ReUdD[i][j]betaU_dupD[i][j] = vetU_dupD[i][j] * rfm.ReU[i] + vetU[i] * rfm.ReUdD[i][j] # Needed for \beta^i RHSfor k in range(DIM):# Needed for, e.g., \bar{\Lambda}^i RHS:betaU_dDD[i][j][k] = vetU_dDD[i][j][k] * rfm.ReU[i] + vetU_dD[i][j] * rfm.ReUdD[i][k] + \vetU_dD[i][k] * rfm.ReUdD[i][j] + vetU[i] * rfm.ReUdDD[i][j][k]# Step 9: Standard BSSN conformal factor phi,# and its partial and covariant derivatives,# all in terms of BSSN gridfunctions like cfdef phi_and_derivs():# Step 9.a: Declare as globals all expressions that may be used# outside this function, declare BSSN gridfunctions# if not defined already, and set DIM=3.global phi_dD,phi_dupD,phi_dDD,exp_m4phi,phi_dBarD,phi_dBarDDhDD, aDD, lambdaU, vetU, betU, trK, cf, alpha = declare_BSSN_gridfunctions_if_not_declared_already()DIM = 3# GammabarUDD is used below, defined in# gammabar__inverse_and_derivs()gammabar__inverse_and_derivs()# Step 9.a.i: Define partial derivatives of \phi in terms of evolved quantity "cf":cf_dD = ixp.declarerank1("cf_dD")cf_dupD = ixp.declarerank1("cf_dupD") # Needed for \partial_t \phi next.cf_dDD = ixp.declarerank2("cf_dDD", "sym01")phi_dD = ixp.zerorank1()phi_dupD = ixp.zerorank1()phi_dDD = ixp.zerorank2()exp_m4phi = sp.sympify(0)# Step 9.a.ii: Assuming cf=phi, define exp_m4phi, phi_dD,# phi_dupD (upwind finite-difference version of phi_dD), and phi_DDif par.parval_from_str("BSSN.BSSN_quantities::EvolvedConformalFactor_cf") == "phi":for i in range(DIM):phi_dD[i] = cf_dD[i]phi_dupD[i] = cf_dupD[i]for j in range(DIM):phi_dDD[i][j] = cf_dDD[i][j]exp_m4phi = sp.exp(-4 * cf)# Step 9.a.iii: Assuming cf=W=e^{-2 phi}, define exp_m4phi, phi_dD,# phi_dupD (upwind finite-difference version of phi_dD), and phi_DDif par.parval_from_str("BSSN.BSSN_quantities::EvolvedConformalFactor_cf") == "W":# \partial_i W = \partial_i (e^{-2 phi}) = -2 e^{-2 phi} \partial_i phi# -> \partial_i phi = -\partial_i cf / (2 cf)for i in range(DIM):phi_dD[i] = - cf_dD[i] / (2 * cf)phi_dupD[i] = - cf_dupD[i] / (2 * cf)for j in range(DIM):# \partial_j \partial_i phi = - \partial_j [\partial_i cf / (2 cf)]# = - cf_{,ij} / (2 cf) + \partial_i cf \partial_j cf / (2 cf^2)phi_dDD[i][j] = (- cf_dDD[i][j] + cf_dD[i] * cf_dD[j] / cf) / (2 * cf)exp_m4phi = cf * cf# Step 9.a.iv: Assuming cf=chi=e^{-4 phi}, define exp_m4phi, phi_dD,# phi_dupD (upwind finite-difference version of phi_dD), and phi_DDif par.parval_from_str("BSSN.BSSN_quantities::EvolvedConformalFactor_cf") == "chi":# \partial_i chi = \partial_i (e^{-4 phi}) = -4 e^{-4 phi} \partial_i phi# -> \partial_i phi = -\partial_i cf / (4 cf)for i in range(DIM):phi_dD[i] = - cf_dD[i] / (4 * cf)phi_dupD[i] = - cf_dupD[i] / (4 * cf)for j in range(DIM):# \partial_j \partial_i phi = - \partial_j [\partial_i cf / (4 cf)]# = - cf_{,ij} / (4 cf) + \partial_i cf \partial_j cf / (4 cf^2)phi_dDD[i][j] = (- cf_dDD[i][j] + cf_dD[i] * cf_dD[j] / cf) / (4 * cf)exp_m4phi = cf# Step 9.a.v: Error out if unsupported EvolvedConformalFactor_cf choice is made:cf_choice = par.parval_from_str("BSSN.BSSN_quantities::EvolvedConformalFactor_cf")if not (cf_choice == "phi" or cf_choice == "W" or cf_choice == "chi"):print("Error: EvolvedConformalFactor_cf == " + par.parval_from_str("BSSN.BSSN_quantities::EvolvedConformalFactor_cf") + " unsupported!")sys.exit(1)# Step 9.b: Define phi_dBarD = phi_dD (since phi is a scalar) and phi_dBarDD (covariant derivative)# \bar{D}_i \bar{D}_j \phi = \phi_{;\bar{i}\bar{j}} = \bar{D}_i \phi_{,j}# = \phi_{,ij} - \bar{\Gamma}^k_{ij} \phi_{,k}phi_dBarD = phi_dDphi_dBarDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):phi_dBarDD[i][j] = phi_dDD[i][j]for k in range(DIM):phi_dBarDD[i][j] += - GammabarUDD[k][i][j] * phi_dD[k]
# As documented in the NRPy+ tutorial module# Tutorial-BSSN_stress_energy_source_terms.ipynb,# this module will construct expressions for# BSSN stress-energy source terms, in terms of# elements of T^{mu nu}.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* comimport sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport reference_metric as rfm # NRPy+: Reference metric supportimport BSSN.ADMBSSN_tofrom_4metric as AB4m # NRPy+: ADM/BSSN <-> 4-metric conversionsimport sys # Standard Python modules for multiplatform OS-level functionsthismodule = __name__# Define BSSN source terms in terms of T^{mu nu} or T_{mu nu}def stress_energy_source_terms_ito_T4UU_and_ADM_or_BSSN_metricvars(inputvars,custom_T4UU=None):# Step 1: Check if rfm.reference_metric() already called. If not, BSSN# quantities are not yet defined, so cannot proceed!if rfm.have_already_called_reference_metric_function == False:print("BSSN_source_terms_ito_T4UU(): Must call reference_metric() first!")sys.exit(1)# Step 2.a: Define gamma4DD[mu][nu] = g_{mu nu} + n_{mu} n_{nu}alpha = sp.symbols("alpha", real=True)zero = sp.sympify(0)n4D = [-alpha, zero, zero, zero]AB4m.g4DD_ito_BSSN_or_ADM(inputvars)gamma4DD = ixp.zerorank2(DIM=4)for mu in range(4):for nu in range(4):gamma4DD[mu][nu] = AB4m.g4DD[mu][nu] + n4D[mu] * n4D[nu]# Step 2.b: If expression for components of T4UU not given, declare T4UU hereif custom_T4UU == None:T4UU = ixp.declarerank2("T4UU","sym01",DIM=4)else:T4UU = custom_T4UU# Step 2.c: Define BSSN source termsglobal SDD,SD,S,rho# Step 2.c.i: S_{ij} = gamma_{i mu} gamma_{j nu} T^{mu nu}SDD = ixp.zerorank2()for i in range(3):for j in range(3):for mu in range(4):for nu in range(4):SDD[i][j] += gamma4DD[i+1][mu] * gamma4DD[j+1][nu] * T4UU[mu][nu]# Step 2.c.ii: S_{i} = -gamma_{i mu} n_{nu} T^{mu nu}SD = ixp.zerorank1()for i in range(3):for mu in range(4):for nu in range(4):SD[i] += - gamma4DD[i+1][mu] * n4D[nu] * T4UU[mu][nu]# Step 2.c.iii: S = gamma^{ij} S_{ij}if inputvars == "ADM":gammaDD = ixp.declarerank2("gammaDD", "sym01")gammaUU, dummydet = ixp.symm_matrix_inverter3x3(gammaDD) # Set gammaUUelif inputvars == "BSSN":import BSSN.ADM_in_terms_of_BSSN as AitoB # NRPy+: ADM quantities in terms of BSSN quantitiesAitoB.ADM_in_terms_of_BSSN()gammaUU = AitoB.gammaUUS = zerofor i in range(3):for j in range(3):S += gammaUU[i][j] * SDD[i][j]# Step 2.c.iv: rho = n_{mu} n_{nu} T^{mu nu}rho = zerofor mu in range(4):for nu in range(4):rho += n4D[mu] * n4D[nu] * T4UU[mu][nu]return SDD,SD,S,rho# Step 3: Add BSSN stress-energy source terms to BSSN RHSsdef BSSN_source_terms_for_BSSN_RHSs(custom_T4UU=None):global sourceterm_trK_rhs, sourceterm_a_rhsDD, sourceterm_lambda_rhsU, sourceterm_Lambdabar_rhsU# Step 3.a: Call BSSN_source_terms_ito_T4UU to get SDD, SD, S, & rhoif custom_T4UU == "unrescaled BSSN source terms already given":SDD = ixp.declarerank2("SDD", "sym01")SD = ixp.declarerank1("SD")S = sp.symbols("S", real=True)rho = sp.symbols("rho", real=True)else:SDD,SD,S,rho = stress_energy_source_terms_ito_T4UU_and_ADM_or_BSSN_metricvars("BSSN", custom_T4UU)PI = par.Cparameters("REAL", thismodule, ["PI"], "3.14159265358979323846264338327950288")alpha = sp.symbols("alpha", real=True)# Step 3.b: trK_rhssourceterm_trK_rhs = 4 * PI * alpha * (rho + S)# Step 3.c: Abar_rhsDD:# Step 3.c.i: Compute trace-free part of S_{ij}:import BSSN.BSSN_quantities as BqBq.BSSN_basic_tensors() # Sets gammabarDDgammabarUU, dummydet = ixp.symm_matrix_inverter3x3(Bq.gammabarDD) # Set gammabarUUtracefree_SDD = ixp.zerorank2()for i in range(3):for j in range(3):tracefree_SDD[i][j] = SDD[i][j]for i in range(3):for j in range(3):for k in range(3):for m in range(3):tracefree_SDD[i][j] += -sp.Rational(1, 3) * Bq.gammabarDD[i][j] * gammabarUU[k][m] * SDD[k][m]# Step 3.c.ii: Define exp_m4phi = e^{-4 phi}Bq.phi_and_derivs()# Step 3.c.iii: Evaluate stress-energy part of AbarDD's RHSsourceterm_a_rhsDD = ixp.zerorank2()for i in range(3):for j in range(3):Abar_rhsDDij = -8 * PI * alpha * Bq.exp_m4phi * tracefree_SDD[i][j]sourceterm_a_rhsDD[i][j] = Abar_rhsDDij / rfm.ReDD[i][j]# Step 3.d: Stress-energy part of Lambdabar_rhsU = stressenergy_Lambdabar_rhsUsourceterm_Lambdabar_rhsU = ixp.zerorank1()for i in range(3):for j in range(3):sourceterm_Lambdabar_rhsU[i] += -16 * PI * alpha * gammabarUU[i][j] * SD[j]sourceterm_lambda_rhsU = ixp.zerorank1()for i in range(3):sourceterm_lambda_rhsU[i] = sourceterm_Lambdabar_rhsU[i] / rfm.ReU[i]# Step 4: Add BSSN stress-energy source terms to BSSN constraintsdef BSSN_source_terms_for_BSSN_constraints(custom_T4UU=None):global sourceterm_H, sourceterm_MU# Step 4.a: Call BSSN_source_terms_ito_T4UU to get SDD, SD, S, & rhoif custom_T4UU == "unrescaled BSSN source terms already given":SDD = ixp.declarerank2("SDD", "sym01")SD = ixp.declarerank1("SD")S = sp.symbols("S", real=True)rho = sp.symbols("rho", real=True)else:SDD,SD,S,rho = stress_energy_source_terms_ito_T4UU_and_ADM_or_BSSN_metricvars("BSSN", custom_T4UU)PI = par.Cparameters("REAL", thismodule, ["PI"], "3.14159265358979323846264338327950288")# Step 4.b: Add source term to the Hamiltonian constraint Hsourceterm_H = -16 * PI * rho# Step 4.c: Add source term to the momentum constraint M^i# Step 4.c.i: Compute gammaUU in terms of BSSN quantitiesimport BSSN.ADM_in_terms_of_BSSN as AitoBAitoB.ADM_in_terms_of_BSSN() # Provides gammaUU# Step 4.c.ii: Raise S_iSU = ixp.zerorank1()for i in range(3):for j in range(3):SU[i] += AitoB.gammaUU[i][j] * SD[j]# Step 4.c.iii: Add source term to momentum constraint & rescale:sourceterm_MU = ixp.zerorank1()for i in range(3):sourceterm_MU[i] = -8 * PI * SU[i] / rfm.ReU[i]
# This module sets up Brill-Lindquist initial data in terms of# the variables used in BSSN_RHSs.py# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# # Setting up Two Black Hole Initial Data, in Curvilinear Coordinates## ## This module sets up initial data for two black holes at rest in spherical coordinates, converts the initial data/basis to the desired CoordSystem, and then rescales all quantities according to the BSSNCurvilinear prescription.## ### Brill-Lindquist initial data ([Brill & Lindquist, Phys. Rev. 131, 471, 1963](https://journals.aps.org/pr/abstract/10.1103/PhysRev.131.471); see also Eq. 1 of [Brandt & Br\"ugmann, arXiv:gr-qc/9711015v1](https://arxiv.org/pdf/gr-qc/9711015v1.pdf)) may be written in terms of the BSSN conformal factor and ADM extrinsic curvature as## $$\psi = e^{\phi} = 1 + \sum_{i=1}^N \frac{m_{(i)}}{2 \left|\vec{r}_{(i)} - \vec{r}\right|};\quad K_{ij}=0.$$## These data consist of $N$ nonspinning black holes initially at rest. This module restricts to the case of two such black holes, positioned along either the $x$ or $z$ axis. Here, we implement $N=2$.## **Inputs for $\psi$**:# * The position and (bare) mass of black hole 1: $\left(x_{(1)},y_{(1)},z_{(1)}\right)$ and $m_{(1)}$, respectively# * The position and (bare) mass of black hole 2: $\left(x_{(2)},y_{(2)},z_{(2)}\right)$ and $m_{(2)}$, respectively## **Additional variables needed for spacetime evolution**:# * Desired coordinate system# * Desired initial lapse $\alpha$ and shift $\beta^i$## **Transformation to curvilinear coordinates**:# * Once the above variables have been set in Cartesian coordinates, we will apply the appropriate coordinate transformations and tensor rescalings ([described in the BSSN NRPy+ tutorial module](Tutorial-BSSNCurvilinear.ipynb))# Step 1: Initialize core Python/NRPy+ modulesimport sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport BSSN.ADM_Exact_Spherical_or_Cartesian_to_BSSNCurvilinear as AtoBthismodule = __name__BH1_posn_x, BH1_posn_y, BH1_posn_z = par.Cparameters("REAL", thismodule,["BH1_posn_x", "BH1_posn_y", "BH1_posn_z"],[0.0, 0.0, +0.5])BH1_mass = par.Cparameters("REAL", thismodule, ["BH1_mass"], 1.0)BH2_posn_x, BH2_posn_y, BH2_posn_z = par.Cparameters("REAL", thismodule,["BH2_posn_x", "BH2_posn_y", "BH2_posn_z"],[0.0, 0.0, -0.5])BH2_mass = par.Cparameters("REAL", thismodule, ["BH2_mass"], 1.0)# ComputeADMGlobalsOnly == True will only set up the ADM global quantities.# == False will perform the full ADM SphorCart->BSSN Curvi conversiondef BrillLindquist(ComputeADMGlobalsOnly = False):global Cartxyz,gammaCartDD, KCartDD, alphaCart, betaCartU, BCartU# Step 2: Setting up Brill-Lindquist initial data# Step 2.a: Set spatial dimension (must be 3 for BSSN)DIM = 3par.set_parval_from_str("grid::DIM",DIM)global Cartxyz, gammaCartDD, KCartDD, alphaCart, betaCartU, BCartUCartxyz = ixp.declarerank1("Cartxyz")# Step 2.b: Set psi, the conformal factor:psi = sp.sympify(1)psi += BH1_mass / ( 2 * sp.sqrt((Cartxyz[0]-BH1_posn_x)**2 + (Cartxyz[1]-BH1_posn_y)**2 + (Cartxyz[2]-BH1_posn_z)**2) )psi += BH2_mass / ( 2 * sp.sqrt((Cartxyz[0]-BH2_posn_x)**2 + (Cartxyz[1]-BH2_posn_y)**2 + (Cartxyz[2]-BH2_posn_z)**2) )# Step 2.c: Set all needed ADM variables in Cartesian coordinatesgammaCartDD = ixp.zerorank2()KCartDD = ixp.zerorank2() # K_{ij} = 0 for these initial datafor i in range(DIM):gammaCartDD[i][i] = psi**4alphaCart = 1/psi**2betaCartU = ixp.zerorank1() # We generally choose \beta^i = 0 for these initial dataBCartU = ixp.zerorank1() # We generally choose B^i = 0 for these initial dataif ComputeADMGlobalsOnly == True:returncf,hDD,lambdaU,aDD,trK,alpha,vetU,betU = \AtoB.Convert_Spherical_or_Cartesian_ADM_to_BSSN_curvilinear("Cartesian",Cartxyz,gammaCartDD,KCartDD,alphaCart,betaCartU,BCartU)import BSSN.BSSN_ID_function_string as bIDfglobal returnfunctionreturnfunction = bIDf.BSSN_ID_function_string(cf, hDD, lambdaU, aDD, trK, alpha, vetU, betU)
# This module implements the gammabar = gammahat constraint.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step P1: import all needed modules from NRPy+:from outputC import * # NRPy+: Core C code output moduleimport finite_difference as fin # NRPy+: Finite difference C code generation moduleimport grid as gri # NRPy+: Functions having to do with numerical gridsimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport reference_metric as rfm # NRPy+: Reference metric supportimport sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport BSSN.BSSN_quantities as Bq # NRPy+: Computes useful BSSN quantitiesimport os # Standard Python modules for multiplatform OS-level functionsdef Enforce_Detgammabar_Constraint_symb_expressions():# Set spatial dimension (must be 3 for BSSN)DIM = 3# Then we set the coordinate system for the numerical gridrfm.reference_metric() # Create ReU, ReDD needed for rescaling B-L initial data, generating BSSN RHSs, etc.# We will need the h_{ij} quantities defined within BSSN_RHSs# below when we enforce the gammahat=gammabar constraint# Step 1: All barred quantities are defined in terms of BSSN rescaled gridfunctions,# which we declare here in case they haven't yet been declared elsewhere.Bq.declare_BSSN_gridfunctions_if_not_declared_already()hDD = Bq.hDDBq.BSSN_basic_tensors()gammabarDD = Bq.gammabarDD# First define the Kronecker delta:KroneckerDeltaDD = ixp.zerorank2()for i in range(DIM):KroneckerDeltaDD[i][i] = sp.sympify(1)# The detgammabar in BSSN_RHSs is set to detgammahat when BSSN_RHSs::detgbarOverdetghat_equals_one=True (default),# so we manually compute it here:dummygammabarUU, detgammabar = ixp.symm_matrix_inverter3x3(gammabarDD)# Next apply the constraint enforcement equation above.hprimeDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):hprimeDD[i][j] = \(nrpyAbs(rfm.detgammahat) / detgammabar) ** (sp.Rational(1, 3)) * (KroneckerDeltaDD[i][j] + hDD[i][j]) \- KroneckerDeltaDD[i][j]enforce_detg_constraint_symb_expressions = [lhrh(lhs=gri.gfaccess("in_gfs", "hDD00"), rhs=hprimeDD[0][0]),lhrh(lhs=gri.gfaccess("in_gfs", "hDD01"), rhs=hprimeDD[0][1]),lhrh(lhs=gri.gfaccess("in_gfs", "hDD02"), rhs=hprimeDD[0][2]),lhrh(lhs=gri.gfaccess("in_gfs", "hDD11"), rhs=hprimeDD[1][1]),lhrh(lhs=gri.gfaccess("in_gfs", "hDD12"), rhs=hprimeDD[1][2]),lhrh(lhs=gri.gfaccess("in_gfs", "hDD22"), rhs=hprimeDD[2][2])]return enforce_detg_constraint_symb_expressionsdef output_Enforce_Detgammabar_Constraint_Ccode(outdir="BSSN/", exprs="", Read_xxs=False):# Step 0: Check if outdir is string; error out if not.check_if_string__error_if_not(outdir,"outdir")desc = "Enforce det(gammabar) = det(gammahat) constraint."name = "enforce_detgammabar_constraint"params = "const rfm_struct *restrict rfmstruct,const paramstruct *restrict params, REAL *restrict in_gfs"loopopts = "AllPoints,Enable_rfm_precompute"if Read_xxs:params = "const paramstruct *restrict params, REAL *restrict xx[3], REAL *restrict in_gfs"loopopts = "AllPoints,Read_xxs"outCfunction(outfile=os.path.join(outdir, name + ".h"), desc=desc, name=name, params=params,body=fin.FD_outputC("returnstring", exprs,params="outCverbose=False,preindent=1,includebraces=False").replace("IDX4", "IDX4S"),loopopts=loopopts)
// This function takes as input either (x,y,z) or (r,th,ph) and outputs// all ADM quantities in the Cartesian or Spherical basis, respectively.void ID_ADM_SphorCart(const REAL xyz_or_rthph[3],REAL *gammaDD00,REAL *gammaDD01,REAL *gammaDD02,REAL *gammaDD11,REAL *gammaDD12,REAL *gammaDD22,REAL *KDD00,REAL *KDD01,REAL *KDD02,REAL *KDD11,REAL *KDD12,REAL *KDD22,REAL *alpha,REAL *betaU0,REAL *betaU1,REAL *betaU2,REAL *BU0,REAL *BU1,REAL *BU2) {const REAL r = xyz_or_rthph[0];const REAL th = xyz_or_rthph[1];const REAL ph = xyz_or_rthph[2];const double tmp0 = (1.0/4.0)*M;const double tmp1 = pow(M, 2);const double tmp2 = pow(chi, 2)*tmp1;const double tmp3 = -tmp2;const double tmp4 = sqrt(tmp1 + tmp3);const double tmp5 = (1.0/4.0)*tmp4;const double tmp6 = cos(th);const double tmp7 = 1.0/r;const double tmp8 = (1.0/4.0)*tmp7*(M + tmp4) + 1;const double tmp9 = pow(r, 2)*pow(tmp8, 4);const double tmp10 = tmp2*pow(tmp6, 2) + tmp9;const double tmp11 = r*pow(tmp8, 2);const double tmp12 = -M + tmp11 + tmp4;const double tmp13 = tmp2 + tmp9;const double tmp14 = 2*tmp11;const double tmp15 = sin(th);const double tmp16 = pow(tmp15, 2);const double tmp17 = tmp16*tmp2;const double tmp18 = pow(tmp13, 2) - tmp17*(-M*tmp14 + tmp13);const double tmp19 = 1.0/tmp10;const double tmp20 = tmp16*tmp19;const double tmp21 = pow(tmp10*tmp18, -1.0/2.0);const double tmp22 = pow(M, 4);*gammaDD00 = tmp10*pow(r + tmp0 + tmp5, 2)/(pow(r, 3)*tmp12);*gammaDD01 = 0;*gammaDD02 = 0;*gammaDD11 = tmp10;*gammaDD12 = 0;*gammaDD22 = tmp18*tmp20;*KDD00 = 0;*KDD01 = 0;*KDD02 = chi*tmp1*tmp20*tmp21*tmp8*(-pow(chi, 4)*tmp22 + 3*pow(r, 4)*pow(tmp8, 8) - tmp17*(tmp3 + tmp9) + 2*tmp2*tmp9)/sqrt(r*tmp12);*KDD11 = 0;*KDD12 = -pow(chi, 3)*tmp14*pow(tmp15, 3)*tmp19*tmp21*tmp22*tmp6*sqrt(tmp12*tmp7)*(r - tmp0 - tmp5);*KDD22 = 0;*alpha = 1;*betaU0 = 0;*betaU1 = 0;*betaU2 = 0;*BU0 = 0;*BU1 = 0;*BU2 = 0;}
# As documented in the NRPy+ tutorial module# Tutorial-Psi4.ipynb,# this module will construct a generic# expression for \psi_4# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step 1.a: import all needed modules from NRPy+:import sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport reference_metric as rfm # NRPy+: Reference metric supportdef Psi4(specify_tetrad=True):global psi4_im_pt, psi4_re_pt# Step 1.b: Given the chosen coordinate system, set up# corresponding reference metric and needed# reference metric quantities# The following function call sets up the reference metric# and related quantities, including rescaling matrices ReDD,# ReU, and hatted quantities.rfm.reference_metric()# Step 1.c: Set spatial dimension (must be 3 for BSSN, as BSSN is# a 3+1-dimensional decomposition of the general# relativistic field equations)DIM = 3# Step 1.d: Import all ADM quantities as written in terms of BSSN quantitiesimport BSSN.ADM_in_terms_of_BSSN as ABAB.ADM_in_terms_of_BSSN()# Step 1.e: Set up tetrad vectorsif specify_tetrad==True:import BSSN.Psi4_tetrads as BP4tBP4t.Psi4_tetrads()mre4U = BP4t.mre4Umim4U = BP4t.mim4Un4U = BP4t.n4Uelse:# For code validation against NRPy+ psi_4 tutorial module (Tutorial-Psi4.ipynb);# ensures a more complete code validation.mre4U = ixp.declarerank1("mre4U", DIM=4)mim4U = ixp.declarerank1("mim4U", DIM=4)n4U = ixp.declarerank1("n4U", DIM=4)# Step 2: Construct the (rank-4) Riemann curvature tensor associated with the ADM 3-metric:RDDDD = ixp.zerorank4()gammaDDdDD = AB.gammaDDdDDfor i in range(DIM):for k in range(DIM):for l in range(DIM):for m in range(DIM):RDDDD[i][k][l][m] = sp.Rational(1, 2) * \(gammaDDdDD[i][m][k][l] + gammaDDdDD[k][l][i][m] - gammaDDdDD[i][l][k][m] -gammaDDdDD[k][m][i][l])# ... then we add the term on the right:gammaDD = AB.gammaDDGammaUDD = AB.GammaUDDfor i in range(DIM):for k in range(DIM):for l in range(DIM):for m in range(DIM):for n in range(DIM):for p in range(DIM):RDDDD[i][k][l][m] += gammaDD[n][p] * \(GammaUDD[n][k][l] * GammaUDD[p][i][m] - GammaUDD[n][k][m] * GammaUDD[p][i][l])# Step 3: Construct the (rank-4) tensor in term 1 of psi_4 (referring to Eq 5.1 in# Baker, Campanelli, Lousto (2001); https://arxiv.org/pdf/gr-qc/0104063.pdfrank4term1DDDD = ixp.zerorank4()KDD = AB.KDDfor i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):rank4term1DDDD[i][j][k][l] = RDDDD[i][j][k][l] + KDD[i][k] * KDD[l][j] - KDD[i][l] * KDD[k][j]# Step 4: Construct the (rank-3) tensor in term 2 of psi_4 (referring to Eq 5.1 in# Baker, Campanelli, Lousto (2001); https://arxiv.org/pdf/gr-qc/0104063.pdfrank3term2DDD = ixp.zerorank3()KDDdD = AB.KDDdDfor j in range(DIM):for k in range(DIM):for l in range(DIM):rank3term2DDD[j][k][l] = sp.Rational(1, 2) * (KDDdD[j][k][l] - KDDdD[j][l][k])# ... then we construct the second term in this sum:# \Gamma^{p}_{j[k} K_{l]p} = \frac{1}{2} (\Gamma^{p}_{jk} K_{lp}-\Gamma^{p}_{jl} K_{kp}):for j in range(DIM):for k in range(DIM):for l in range(DIM):for p in range(DIM):rank3term2DDD[j][k][l] += sp.Rational(1, 2) * (GammaUDD[p][j][k] * KDD[l][p] - GammaUDD[p][j][l] * KDD[k][p])# Finally, we multiply the term by $-8$:for j in range(DIM):for k in range(DIM):for l in range(DIM):rank3term2DDD[j][k][l] *= sp.sympify(-8)# Step 5: Construct the (rank-2) tensor in term 3 of psi_4 (referring to Eq 5.1 in# Baker, Campanelli, Lousto (2001); https://arxiv.org/pdf/gr-qc/0104063.pdf# Step 5.1: Construct 3-Ricci tensor R_{ij} = gamma^{im} R_{ijml}RDD = ixp.zerorank2()gammaUU = AB.gammaUUfor j in range(DIM):for l in range(DIM):for i in range(DIM):for m in range(DIM):RDD[j][l] += gammaUU[i][m]*RDDDD[i][j][m][l]# Step 5.2: Construct K^p_l = gamma^{pi} K_{il}KUD = ixp.zerorank2()for p in range(DIM):for l in range(DIM):for i in range(DIM):KUD[p][l] += gammaUU[p][i]*KDD[i][l]# Step 5.3: Construct trK = gamma^{ij} K_{ij}trK = sp.sympify(0)for i in range(DIM):for j in range(DIM):trK += gammaUU[i][j]*KDD[i][j]# Next we put these terms together to construct the entire term in parentheses:# +4 \left(R_{jl} - K_{jp} K^p_l + K K_{jl} \right),rank2term3DD = ixp.zerorank2()for j in range(DIM):for l in range(DIM):rank2term3DD[j][l] = RDD[j][l] + trK*KDD[j][l]for p in range(DIM):rank2term3DD[j][l] += - KDD[j][p]*KUD[p][l]# Finally we multiply by +4:for j in range(DIM):for l in range(DIM):rank2term3DD[j][l] *= sp.sympify(4)# Step 6: Construct real & imaginary parts of psi_4# by contracting constituent rank 2, 3, and 4# tensors with input tetrads mre4U, mim4U, & n4U.def tetrad_product__Real_psi4(n, Mre, Mim, mu, nu, eta, delta):return +n[mu] * Mre[nu] * n[eta] * Mre[delta] - n[mu] * Mim[nu] * n[eta] * Mim[delta]def tetrad_product__Imag_psi4(n, Mre, Mim, mu, nu, eta, delta):return -n[mu] * Mre[nu] * n[eta] * Mim[delta] - n[mu] * Mim[nu] * n[eta] * Mre[delta]# We split psi_4 into three pieces, to expedite & possibly parallelize C code generation.psi4_re_pt = [sp.sympify(0),sp.sympify(0),sp.sympify(0)]psi4_im_pt = [sp.sympify(0),sp.sympify(0),sp.sympify(0)]# First term:for i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):psi4_re_pt[0] += rank4term1DDDD[i][j][k][l] * tetrad_product__Real_psi4(n4U, mre4U, mim4U,i + 1, j + 1,k + 1, l + 1)psi4_im_pt[0] += rank4term1DDDD[i][j][k][l] * tetrad_product__Imag_psi4(n4U, mre4U, mim4U,i + 1, j + 1, k + 1, l + 1)# Second term:for j in range(DIM):for k in range(DIM):for l in range(DIM):psi4_re_pt[1] += rank3term2DDD[j][k][l] * \sp.Rational(1, 2) * (+tetrad_product__Real_psi4(n4U, mre4U, mim4U, 0, j + 1, k + 1, l + 1)- tetrad_product__Real_psi4(n4U, mre4U, mim4U, j + 1, 0, k + 1, l + 1))psi4_im_pt[1] += rank3term2DDD[j][k][l] * \sp.Rational(1, 2) * (+tetrad_product__Imag_psi4(n4U, mre4U, mim4U, 0, j + 1, k + 1, l + 1)- tetrad_product__Imag_psi4(n4U, mre4U, mim4U, j + 1, 0, k + 1, l + 1))# Third term:for j in range(DIM):for l in range(DIM):psi4_re_pt[2] += rank2term3DD[j][l] * \(sp.Rational(1, 4) * (+tetrad_product__Real_psi4(n4U, mre4U, mim4U, 0, j + 1, 0, l + 1)- tetrad_product__Real_psi4(n4U, mre4U, mim4U, j + 1, 0, 0, l + 1)- tetrad_product__Real_psi4(n4U, mre4U, mim4U, 0, j + 1, l + 1, 0)+ tetrad_product__Real_psi4(n4U, mre4U, mim4U, j + 1, 0, l + 1, 0)))psi4_im_pt[2] += rank2term3DD[j][l] * \(sp.Rational(1, 4) * (+tetrad_product__Imag_psi4(n4U, mre4U, mim4U, 0, j + 1, 0, l + 1)- tetrad_product__Imag_psi4(n4U, mre4U, mim4U, j + 1, 0, 0, l + 1)- tetrad_product__Imag_psi4(n4U, mre4U, mim4U, 0, j + 1, l + 1, 0)+ tetrad_product__Imag_psi4(n4U, mre4U, mim4U, j + 1, 0, l + 1, 0)))
# As documented in the NRPy+ tutorial module# Tutorial-Psi4_tetrads.ipynb,# this module will construct tetrads# needed to compute \psi_4 (as well as other# Weyl scalars and invariants in principle)# Authors: Zachariah B. Etienne# (zachetie **at** gmail **dot* com),# and Patrick Nelson# Step 1.a: import all needed modules from NRPy+:import sympy as spimport NRPy_param_funcs as parimport indexedexp as ixpimport grid as griimport finite_difference as finimport reference_metric as rfm# Step 1.b: Initialize TetradChoice parameterthismodule = __name__# Current option: QuasiKinnersley = choice made in Baker, Campanelli, and Lousto. PRD 65, 044001 (2002)par.initialize_param(par.glb_param("char", thismodule, "TetradChoice", "QuasiKinnersley"))par.initialize_param(par.glb_param("char", thismodule, "UseCorrectUnitNormal", "False"))def Psi4_tetrads():global l4U, n4U, mre4U, mim4U# Step 1.c: Check if tetrad choice is implemented:if par.parval_from_str(thismodule+"::TetradChoice") != "QuasiKinnersley":print("ERROR: "+thismodule+"::TetradChoice = "+par.parval_from_str("TetradChoice")+" currently unsupported!")exit(1)# Step 1.d: Given the chosen coordinate system, set up# corresponding reference metric and needed# reference metric quantities# The following function call sets up the reference metric# and related quantities, including rescaling matrices ReDD,# ReU, and hatted quantities.rfm.reference_metric()# Step 1.e: Set spatial dimension (must be 3 for BSSN, as BSSN is# a 3+1-dimensional decomposition of the general# relativistic field equations)DIM = 3# Step 1.f: Import all ADM quantities as written in terms of BSSN quantities# import BSSN.ADM_in_terms_of_BSSN as AB# AB.ADM_in_terms_of_BSSN()# Step 2.a: Declare the Cartesian x,y,z as input parameters# and v_1^a, v_2^a, and v_3^a tetrads,# as well as detgamma and gammaUU from# BSSN.ADM_in_terms_of_BSSNx,y,z = gri.register_gridfunctions("AUX",["x","y","z"])# x, y, z = par.Cparameters("REAL", thismodule, ["x", "y", "z"])v1UCart = ixp.zerorank1()v2UCart = ixp.zerorank1()gammaDD = ixp.declarerank2("gammaDD","sym01")gammaUU,detgamma = ixp.symm_matrix_inverter3x3(gammaDD)# detgamma = AB.detgamma# gammaUU = AB.gammaUU# Step 2.b: Define v1U and v2Uv1UCart = [-y, x, sp.sympify(0)]v2UCart = [x, y, z]v1U = ixp.zerorank1()v2U = ixp.zerorank1()for i in range(DIM):v1U[i] = v1UCart[i]v2U[i] = v2UCart[i]# # Step 2.c: Construct the Jacobian d x_Cart^i / d xx^j# Jac_dUCart_dDrfmUD = ixp.zerorank2()# for i in range(DIM):# for j in range(DIM):# Jac_dUCart_dDrfmUD[i][j] = sp.diff(rfm.xxCart[i], rfm.xx[j])## # Step 2.d: Invert above Jacobian to get needed d xx^j / d x_Cart^i# Jac_dUrfm_dDCartUD, dummyDET = ixp.generic_matrix_inverter3x3(Jac_dUCart_dDrfmUD)## # Step 2.e: Transform v1U and v2U from the Cartesian to the xx^i basis# v1U = ixp.zerorank1()# v2U = ixp.zerorank1()# for i in range(DIM):# for j in range(DIM):# v1U[i] += Jac_dUrfm_dDCartUD[i][j] * v1UCart[j]# v2U[i] += Jac_dUrfm_dDCartUD[i][j] * v2UCart[j]# Step 2.f: Define the rank-3 version of the Levi-Civita symbol. Amongst# other uses, this is needed for the construction of the approximate# quasi-Kinnersley tetrad.def define_LeviCivitaSymbol_rank3(DIM=-1):if DIM == -1:DIM = par.parval_from_str("DIM")LeviCivitaSymbol = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for k in range(DIM):# From https://codegolf.stackexchange.com/questions/160359/levi-civita-symbol :LeviCivitaSymbol[i][j][k] = (i - j) * (j - k) * (k - i) / 2return LeviCivitaSymbol# Step 2.g: Define v3Uv3U = ixp.zerorank1()LeviCivitaSymbolDDD = define_LeviCivitaSymbol_rank3(DIM=3)for a in range(DIM):for b in range(DIM):for c in range(DIM):for d in range(DIM):v3U[a] += sp.sqrt(detgamma) * gammaUU[a][d] * LeviCivitaSymbolDDD[d][b][c] * v1U[b] * v2U[c]# Step 2.h: Define omega_{ij}omegaDD = ixp.zerorank2()#gammaDD = AB.gammaDDdef v_vectorDU(v1U,v2U,v3U, i,a):if i==0:return v1U[a]elif i==1:return v2U[a]elif i==2:return v3U[a]else:print("ERROR: unknown vector!")exit(1)def update_omega(omegaDD, i,j, v1U,v2U,v3U,gammaDD):omegaDD[i][j] = sp.sympify(0)for a in range(DIM):for b in range(DIM):omegaDD[i][j] += v_vectorDU(v1U,v2U,v3U, i,a)*v_vectorDU(v1U,v2U,v3U, j,b)*gammaDD[a][b]# Step 2.i: Define e^a_i. Note that:# omegaDD[0][0] = \omega_{11} above;# omegaDD[1][1] = \omega_{22} above, etc.# First e_1^a: Orthogonalize & normalize:e1U = ixp.zerorank1()update_omega(omegaDD, 0,0, v1U,v2U,v3U,gammaDD)for a in range(DIM):e1U[a] = v1U[a]/sp.sqrt(omegaDD[0][0])# Next e_2^a: First orthogonalize:e2U = ixp.zerorank1()update_omega(omegaDD, 0,1, e1U,v2U,v3U,gammaDD)for a in range(DIM):e2U[a] = (v2U[a] - omegaDD[0][1]*e1U[a])# Then normalize:update_omega(omegaDD, 1,1, e1U,e2U,v3U,gammaDD)for a in range(DIM):e2U[a] /= sp.sqrt(omegaDD[1][1])# Next e_3^a: First orthogonalize:e3U = ixp.zerorank1()update_omega(omegaDD, 0,2, e1U,e2U,v3U,gammaDD)update_omega(omegaDD, 1,2, e1U,e2U,v3U,gammaDD)for a in range(DIM):e3U[a] = (v3U[a] - omegaDD[0][2]*e1U[a] - omegaDD[1][2]*e2U[a])# Then normalize:update_omega(omegaDD, 2,2, e1U,e2U,e3U,gammaDD)for a in range(DIM):e3U[a] /= sp.sqrt(omegaDD[2][2])# Step 2.j: Construct l^mu, n^mu, and m^mu, based on r^mu, theta^mu, phi^mu, and u^mu:r4U = ixp.zerorank1(DIM=4)u4U = ixp.zerorank1(DIM=4)theta4U = ixp.zerorank1(DIM=4)phi4U = ixp.zerorank1(DIM=4)for a in range(DIM):r4U[ a+1] = e2U[a]theta4U[a+1] = e3U[a]phi4U[ a+1] = e1U[a]# FIXME? assumes alpha=1, beta^i = 0if par.parval_from_str(thismodule+"::UseCorrectUnitNormal") == "False":u4U[0] = 1else:# Eq. 2.116 in Baumgarte & Shapiro:# n^mu = {1/alpha, -beta^i/alpha}. Note that n_mu = {alpha,0}, so n^mu n_mu = -1.import BSSN.BSSN_quantities as BqBq.declare_BSSN_gridfunctions_if_not_declared_already()Bq.BSSN_basic_tensors()u4U[0] = 1/Bq.alphafor i in range(DIM):u4U[i+1] = -Bq.betaU[i]/Bq.alphal4U = ixp.zerorank1(DIM=4)n4U = ixp.zerorank1(DIM=4)mre4U = ixp.zerorank1(DIM=4)mim4U = ixp.zerorank1(DIM=4)isqrt2 = 1/sp.sqrt(2)for mu in range(4):l4U[mu] = isqrt2*(u4U[mu] + r4U[mu])n4U[mu] = isqrt2*(u4U[mu] - r4U[mu])mre4U[mu] = isqrt2*theta4U[mu]mim4U[mu] = isqrt2* phi4U[mu]
{"cells": [{"cell_type": "markdown","metadata": {},"source": ["<script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-59152712-8\"></script>\n","<script>\n"," window.dataLayer = window.dataLayer || [];\n"," function gtag(){dataLayer.push(arguments);}\n"," gtag('js', new Date());\n","\n"," gtag('config', 'UA-59152712-8');\n","</script>\n","\n","# Start-to-Finish validation of $\\psi_4$ in curvilinear coordinates against Cartesian formulation provided by [Patrick Nelson's Weyl scalars & invariants in Cartesian coordinates module](../../Tutorial-WeylScalarsInvariants-Cartesian.ipynb)\n","\n","### Author: Zach Etienne\n","\n","<font color='blue'>**This module exists as a modification of [the NRPy+ $\\psi_4$ in curvilinear coordinates module](../../Tutorial-Psi4.ipynb), writing all spacetime quantities in terms of ADM variables and their derivatives directly.**</font>\n","\n","## A Note on Notation\n","\n","As is standard in NRPy+, \n","\n","* Greek indices range from 0 to 3, inclusive, with the zeroth component denoting the temporal (time) component.\n","* Latin indices range from 0 to 2, inclusive, with the zeroth component denoting the first spatial component.\n","\n","As a corollary, any expressions involving mixed Greek and Latin indices will need to offset one set of indices by one: A Latin index in a four-vector will be incremented and a Greek index in a three-vector will be decremented (however, the latter case does not occur in this tutorial module).\n","\n","<a id='toc'></a>\n","\n","# Introduction, Table of Contents\n","$$\\label{toc}$$\n","\n","This module constructs $\\psi_4$, a quantity that is immensely useful when extracting gravitational wave content from a numerical relativity simulation. $\\psi_4$ is related to the gravitational wave strain via\n","\n","$$\n","\\psi_4 = \\ddot{h}_+ - i \\ddot{h}_\\times.\n","$$\n","\n","We construct $\\psi_4$ from the standard ADM spatial metric $\\gamma_{ij}$ and extrinsic curvature $K_{ij}$, and their derivatives. The full expression is given by Eq. 5.1 in [Baker, Campanelli, Lousto (2001)](https://arxiv.org/pdf/gr-qc/0104063.pdf):\n","\n","\\begin{align}\n","\\psi_4 &= \\left[ {R}_{ijkl}+2K_{i[k}K_{l]j}\\right]\n","{n}^i\\bar{m}^j{n}^k\\bar{m}^l \\\\\n","& -8\\left[ K_{j[k,l]}+{\\Gamma }_{j[k}^pK_{l]p}\\right]\n","{n}^{[0}\\bar{m}^{j]}{n}^k\\bar{m}^l \\\\\n","& +4\\left[ {R}_{jl}-K_{jp}K_l^p+KK_{jl}\\right]\n","{n}^{[0}\\bar{m}^{j]}{n}^{[0}\\bar{m}^{l]},\n","\\end{align}\n","\n","Note that $\\psi_4$ is imaginary, with the imaginary components originating from the tetrad vector $m^\\mu$. This module does not specify a tetrad; instead it only constructs the above expression leaving $m^\\mu$ and $n^\\mu$ unspecified. The [next module on tetrads defines these tetrad quantities](Tutorial-Psi4_tetrads.ipynb) (currently only a quasi-Kinnersley tetrad is supported).\n","\n","**This tutorial module is organized as follows:**\n","\n","1. [Step 1](#initializenrpy): Initialize needed NRPy+ modules\n","1. [Step 2](#riemann): Constructing the 3-Riemann tensor $R_{ik\\ell m}$\n","1. [Step 3](#termone): Constructing the rank-4 tensor in Term 1 of $\\psi_4$: $R_{ijkl} + 2 K_{i[k} K_{l]j}$\n","1. [Step 4](#termtwo): Constructing the rank-3 tensor in Term 2 of $\\psi_4$: $-8 \\left(K_{j[k,l]} + \\Gamma^{p}_{j[k} K_{l]p} \\right)$\n","1. [Step 5](#termthree): Constructing the rank-2 tensor in term 3 of $\\psi_4$: $+4 \\left(R_{jl} - K_{jp} K^p_l + K K_{jl} \\right)$\n","1. [Step 6](#psifour): Constructing $\\psi_4$ through contractions of the above terms with arbitrary tetrad vectors $n^\\mu$ and $m^\\mu$\n","1. [Step 7](#code_validation): Code Validation against BSSN.Psi4 NRPy+ module\n","1. [Step 8](#latex_pdf_output): Output this notebook to $\\LaTeX$-formatted PDF"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='initializenrpy'></a>\n","\n","# Step 1: Initialize core NRPy+ modules \\[Back to [top](#toc)\\]\n","$$\\label{initializenrpy}$$\n","\n","Let's start by importing all the needed modules from NRPy+:"]},{"cell_type": "code","execution_count": 1,"metadata": {},"outputs": [],"source": ["# Step 1.a: import all needed modules from NRPy+:\n","import sympy as sp\n","from outputC import *\n","import NRPy_param_funcs as par\n","import indexedexp as ixp\n","import grid as gri\n","import finite_difference as fin\n","import reference_metric as rfm\n","\n","# Step 1.b: Set the coordinate system for the numerical grid\n","par.set_parval_from_str(\"reference_metric::CoordSystem\",\"Cartesian\")\n","\n","# Step 1.c: Given the chosen coordinate system, set up \n","# corresponding reference metric and needed\n","# reference metric quantities\n","# The following function call sets up the reference metric\n","# and related quantities, including rescaling matrices ReDD,\n","# ReU, and hatted quantities.\n","rfm.reference_metric()\n","\n","# Step 1.d: Set spatial dimension (must be 3 for BSSN, as BSSN is \n","# a 3+1-dimensional decomposition of the general \n","# relativistic field equations)\n","DIM = 3\n","\n","# Step 1.e: Import all ADM quantities as written in terms of BSSN quantities\n","# import BSSN.ADM_in_terms_of_BSSN as AB\n","# AB.ADM_in_terms_of_BSSN()"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='riemann'></a>\n","\n","# Step 2: Constructing the 3-Riemann tensor $R_{ik\\ell m}$ \\[Back to [top](#toc)\\]\n","$$\\label{riemann}$$\n","\n","Analogously to Christoffel symbols, the Riemann tensor is a measure of the curvature of an $N$-dimensional manifold. Thus the 3-Riemann tensor is not simply a projection of the 4-Riemann tensor (see e.g., Eq. 2.7 of [Campanelli *et al* (1998)](https://arxiv.org/pdf/gr-qc/9803058.pdf) for the relation between 4-Riemann and 3-Riemann), as $N$-dimensional Riemann tensors are meant to define a notion of curvature given only the associated $N$-dimensional metric. \n","\n","So, given the ADM 3-metric, the Riemann tensor in arbitrary dimension is given by the 3-dimensional version of Eq. 1.19 in Baumgarte & Shapiro's *Numerical Relativity*. I.e.,\n","\n","$$\n","R^i_{jkl} = \\partial_k \\Gamma^{i}_{jl} - \\partial_l \\Gamma^{i}_{jk} + \\Gamma^i_{mk} \\Gamma^m_{jl} - \\Gamma^{i}_{ml} \\Gamma^{m}_{jk},\n","$$\n","where $\\Gamma^i_{jk}$ is the Christoffel symbol associated with the 3-metric $\\gamma_{ij}$:\n","\n","$$\n","\\Gamma^l_{ij} = \\frac{1}{2} \\gamma^{lk} \\left(\\gamma_{ki,j} + \\gamma_{kj,i} - \\gamma_{ij,k} \\right) \n","$$\n","\n","Notice that this equation for the Riemann tensor is equivalent to the equation given in the Wikipedia article on [Formulas in Riemannian geometry](https://en.wikipedia.org/w/index.php?title=List_of_formulas_in_Riemannian_geometry&oldid=882667524):\n","\n","$$\n","R^\\ell{}_{ijk}=\n","\\partial_j \\Gamma^\\ell{}_{ik}-\\partial_k\\Gamma^\\ell{}_{ij}\n","+\\Gamma^\\ell{}_{js}\\Gamma_{ik}^s-\\Gamma^\\ell{}_{ks}\\Gamma^s{}_{ij},\n","$$\n","with the replacements $i\\to \\ell$, $j\\to i$, $k\\to j$, $l\\to k$, and $s\\to m$. Wikipedia also provides a simpler form in terms of second-derivatives of three-metric itself (using the definition of Christoffel symbol), so that we need not define derivatives of the Christoffel symbol:\n","\n","$$\n","R_{ik\\ell m}=\\frac{1}{2}\\left(\n","\\gamma_{im,k\\ell} \n","+ \\gamma_{k\\ell,im}\n","- \\gamma_{i\\ell,km}\n","- \\gamma_{km,i\\ell} \\right)\n","+\\gamma_{np} \\left(\n","\\Gamma^n{}_{k\\ell} \\Gamma^p{}_{im} - \n","\\Gamma^n{}_{km} \\Gamma^p{}_{i\\ell} \\right).\n","$$\n","\n","First we construct the term on the left:"]},{"cell_type": "code","execution_count": 2,"metadata": {},"outputs": [],"source": ["# Step 2: Construct the (rank-4) Riemann curvature tensor associated with the ADM 3-metric:\n","RDDDD = ixp.zerorank4()\n","gammaDD = ixp.register_gridfunctions_for_single_rank2(\"AUX\",\"gammaDD\", \"sym01\") # The AUX or EVOL designation is *not*\n"," # used in diagnostic modules.\n","kDD = ixp.register_gridfunctions_for_single_rank2(\"AUX\",\"kDD\", \"sym01\")\n","gammaDD_dD = ixp.declarerank3(\"gammaDD_dD\",\"sym01\")\n","gammaDD_dDD = ixp.declarerank4(\"gammaDD_dDD\",\"sym01_sym23\")\n","\n","# gammaDD_dDD = AB.gammaDD_dDD\n","\n","for i in range(DIM):\n"," for k in range(DIM):\n"," for l in range(DIM):\n"," for m in range(DIM):\n"," RDDDD[i][k][l][m] = sp.Rational(1,2) * \\\n"," (gammaDD_dDD[i][m][k][l] + gammaDD_dDD[k][l][i][m] - gammaDD_dDD[i][l][k][m] - gammaDD_dDD[k][m][i][l])"]},{"cell_type": "markdown","metadata": {},"source": ["... then we add the term on the right:"]},{"cell_type": "code","execution_count": 3,"metadata": {},"outputs": [],"source": ["# ... then we add the term on the right:\n","# Define the Christoffel symbols\n","GammaUDD = ixp.zerorank3(DIM)\n","gammaUU,gammadetdummy = ixp.symm_matrix_inverter3x3(gammaDD)\n","for i in range(DIM):\n"," for k in range(DIM):\n"," for l in range(DIM):\n"," for m in range(DIM):\n"," GammaUDD[i][k][l] += (sp.Rational(1,2))*gammaUU[i][m]*\\\n"," (gammaDD_dD[m][k][l] + gammaDD_dD[m][l][k] - gammaDD_dD[k][l][m])\n","\n","for i in range(DIM):\n"," for k in range(DIM):\n"," for l in range(DIM):\n"," for m in range(DIM):\n"," for n in range(DIM):\n"," for p in range(DIM):\n"," RDDDD[i][k][l][m] += gammaDD[n][p] * \\\n"," (GammaUDD[n][k][l]*GammaUDD[p][i][m] - GammaUDD[n][k][m]*GammaUDD[p][i][l])"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='termone'></a>\n","\n","# Step 3: Constructing the rank-4 tensor in Term 1 of $\\psi_4$: $R_{ijkl} + 2 K_{i[k} K_{l]j}$ \\[Back to [top](#toc)\\]\n","$$\\label{termone}$$\n","\n","Following Eq. 5.1 in [Baker, Campanelli, Lousto (2001)](https://arxiv.org/pdf/gr-qc/0104063.pdf), the rank-4 tensor in the first term of $\\psi_4$ is given by\n","\n","$$\n","R_{ijkl} + 2 K_{i[k} K_{l]j} = R_{ijkl} + K_{ik} K_{lj} - K_{il} K_{kj}\n","$$"]},{"cell_type": "code","execution_count": 4,"metadata": {},"outputs": [],"source": ["# Step 3: Construct the (rank-4) tensor in term 1 of psi_4 (referring to Eq 5.1 in \n","# Baker, Campanelli, Lousto (2001); https://arxiv.org/pdf/gr-qc/0104063.pdf\n","rank4term1 = ixp.zerorank4()\n","# kDD = AB.kDD\n","\n","for i in range(DIM):\n"," for j in range(DIM):\n"," for k in range(DIM):\n"," for l in range(DIM):\n"," rank4term1[i][j][k][l] = RDDDD[i][j][k][l] + kDD[i][k]*kDD[l][j] - kDD[i][l]*kDD[k][j]"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='termtwo'></a>\n","\n","# Step 4: Constructing the rank-3 tensor in Term 2 of $\\psi_4$: $-8 \\left(K_{j[k,l]} + \\Gamma^{p}_{j[k} K_{l]p} \\right)$ \\[Back to [top](#toc)\\]\n","$$\\label{termtwo}$$\n","\n","Following Eq. 5.1 in [Baker, Campanelli, Lousto (2001)](https://arxiv.org/pdf/gr-qc/0104063.pdf), the rank-3 tensor in the second term of $\\psi_4$ is given by\n","\n","$$\n","-8 \\left(K_{j[k,l]} + \\Gamma^{p}_{j[k} K_{l]p} \\right)\n","$$\n","First let's construct the first term in this sum: $K_{j[k,l]} = \\frac{1}{2} (K_{jk,l} - K_{jl,k})$:"]},{"cell_type": "code","execution_count": 5,"metadata": {},"outputs": [],"source": ["# Step 4: Construct the (rank-3) tensor in term 2 of psi_4 (referring to Eq 5.1 in \n","# Baker, Campanelli, Lousto (2001); https://arxiv.org/pdf/gr-qc/0104063.pdf\n","rank3term2 = ixp.zerorank3()\n","# kDD_dD = AB.kDD_dD\n","kDD_dD = ixp.declarerank3(\"kDD_dD\",\"sym01\")\n","\n","for j in range(DIM):\n"," for k in range(DIM):\n"," for l in range(DIM):\n"," rank3term2[j][k][l] = sp.Rational(1,2)*(kDD_dD[j][k][l] - kDD_dD[j][l][k])"]},{"cell_type": "markdown","metadata": {},"source": ["... then we construct the second term in this sum: $\\Gamma^{p}_{j[k} K_{l]p} = \\frac{1}{2} (\\Gamma^{p}_{jk} K_{lp}-\\Gamma^{p}_{jl} K_{kp})$:"]},{"cell_type": "code","execution_count": 6,"metadata": {},"outputs": [],"source": ["# ... then we construct the second term in this sum: \n","# \\Gamma^{p}_{j[k} K_{l]p} = \\frac{1}{2} (\\Gamma^{p}_{jk} K_{lp}-\\Gamma^{p}_{jl} K_{kp}):\n","for j in range(DIM):\n"," for k in range(DIM):\n"," for l in range(DIM):\n"," for p in range(DIM):\n"," rank3term2[j][k][l] += sp.Rational(1,2)*(GammaUDD[p][j][k]*kDD[l][p] - GammaUDD[p][j][l]*kDD[k][p])"]},{"cell_type": "markdown","metadata": {},"source": ["Finally, we multiply the term by $-8$:"]},{"cell_type": "code","execution_count": 7,"metadata": {},"outputs": [],"source": ["# Finally, we multiply the term by $-8$:\n","for j in range(DIM):\n"," for k in range(DIM):\n"," for l in range(DIM):\n"," rank3term2[j][k][l] *= sp.sympify(-8)"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='termthree'></a>\n","\n","# Step 5: Constructing the rank-2 tensor in term 3 of $\\psi_4$: $+4 \\left(R_{jl} - K_{jp} K^p_l + K K_{jl} \\right)$ \\[Back to [top](#toc)\\]\n","$$\\label{termthree}$$\n","\n","Following Eq. 5.1 in [Baker, Campanelli, Lousto (2001)](https://arxiv.org/pdf/gr-qc/0104063.pdf), the rank-2 tensor in the third term of $\\psi_4$ is given by\n","\n","$$\n","+4 \\left(R_{jl} - K_{jp} K^p_l + K K_{jl} \\right),\n","$$\n","where\n","\\begin{align}\n","R_{jl} &= R^i_{jil} \\\\\n","&= \\gamma^{im} R_{ijml} \\\\\n","K &= K^i_i \\\\\n","&= \\gamma^{im} K_{im}\n","\\end{align}\n","\n","Let's build the components of this term: $R_{jl}$, $K^p_l$, and $K$, as defined above:"]},{"cell_type": "code","execution_count": 8,"metadata": {},"outputs": [],"source": ["# Step 5: Construct the (rank-2) tensor in term 3 of psi_4 (referring to Eq 5.1 in \n","# Baker, Campanelli, Lousto (2001); https://arxiv.org/pdf/gr-qc/0104063.pdf\n","\n","# Step 5.1: Construct 3-Ricci tensor R_{ij} = gamma^{im} R_{ijml}\n","RDD = ixp.zerorank2()\n","for j in range(DIM):\n"," for l in range(DIM):\n"," for i in range(DIM):\n"," for m in range(DIM):\n"," RDD[j][l] += gammaUU[i][m]*RDDDD[i][j][m][l]\n","\n","# Step 5.2: Construct K^p_l = gamma^{pi} K_{il}\n","KUD = ixp.zerorank2()\n","for p in range(DIM):\n"," for l in range(DIM):\n"," for i in range(DIM):\n"," KUD[p][l] += gammaUU[p][i]*kDD[i][l]\n","\n","# Step 5.3: Construct trK = gamma^{ij} K_{ij}\n","trK = sp.sympify(0)\n","for i in range(DIM):\n"," for j in range(DIM):\n"," trK += gammaUU[i][j]*kDD[i][j]"]},{"cell_type": "markdown","metadata": {},"source": ["Next we put these terms together to construct the entire term:\n","$$\n","+4 \\left(R_{jl} - K_{jp} K^p_l + K K_{jl} \\right),\n","$$"]},{"cell_type": "code","execution_count": 9,"metadata": {},"outputs": [],"source": ["# Next we put these terms together to construct the entire term in parentheses:\n","# +4 \\left(R_{jl} - K_{jp} K^p_l + K K_{jl} \\right),\n","rank2term3 = ixp.zerorank2()\n","for j in range(DIM):\n"," for l in range(DIM):\n"," rank2term3[j][l] = RDD[j][l] + trK*kDD[j][l]\n"," for p in range(DIM):\n"," rank2term3[j][l] += - kDD[j][p]*KUD[p][l]\n","# Finally we multiply by +4:\n","for j in range(DIM):\n"," for l in range(DIM):\n"," rank2term3[j][l] *= sp.sympify(4)"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='psifour'></a>\n","\n","# Step 6: Constructing $\\psi_4$ through contractions of the above terms with an arbitrary tetrad vectors $m^\\mu$ and $n^\\mu$ \\[Back to [top](#toc)\\]\n","$$\\label{psifour}$$\n","\n","Eq. 5.1 in [Baker, Campanelli, Lousto (2001)](https://arxiv.org/pdf/gr-qc/0104063.pdf) writes $\\psi_4$ (which is complex) as the contraction of each of the above terms with products of tetrad vectors:\n","\n","\\begin{align}\n","\\psi_4 &= \\left[ {R}_{ijkl}+2K_{i[k}K_{l]j}\\right]\n","{n}^i\\bar{m}^j{n}^k\\bar{m}^l \\\\\n","& -8\\left[ K_{j[k,l]}+{\\Gamma }_{j[k}^pK_{l]p}\\right]\n","{n}^{[0}\\bar{m}^{j]}{n}^k\\bar{m}^l \\\\\n","& +4\\left[ {R}_{jl}-K_{jp}K_l^p+KK_{jl}\\right]\n","{n}^{[0}\\bar{m}^{j]}{n}^{[0}\\bar{m}^{l]},\n","\\end{align}\n","where $\\bar{m}^\\mu$ is the complex conjugate of $m^\\mu$, and $n^\\mu$ is real. The third term is given by\n","\\begin{align}\n","{n}^{[0}\\bar{m}^{j]}{n}^{[0}\\bar{m}^{l]}\n","&= \\frac{1}{2}({n}^{0}\\bar{m}^{j} - {n}^{j}\\bar{m}^{0} )\\frac{1}{2}({n}^{0}\\bar{m}^{l} - {n}^{l}\\bar{m}^{0} )\\\\\n","&= \\frac{1}{4}({n}^{0}\\bar{m}^{j} - {n}^{j}\\bar{m}^{0} )({n}^{0}\\bar{m}^{l} - {n}^{l}\\bar{m}^{0} )\\\\\n","&= \\frac{1}{4}({n}^{0}\\bar{m}^{j}{n}^{0}\\bar{m}^{l} - {n}^{j}\\bar{m}^{0}{n}^{0}\\bar{m}^{l} - {n}^{0}\\bar{m}^{j}{n}^{l}\\bar{m}^{0} + {n}^{j}\\bar{m}^{0}{n}^{l}\\bar{m}^{0})\n","\\end{align}\n","\n","Only $m^\\mu$ is complex, so we can separate the real and imaginary parts of $\\psi_4$ by hand, defining $M^\\mu$ to now be the real part of $\\bar{m}^\\mu$ and $\\mathcal{M}^\\mu$ to be the imaginary part. All of the above products are of the form ${n}^\\mu\\bar{m}^\\nu{n}^\\eta\\bar{m}^\\delta$, so let's evalute the real and imaginary parts of this product once, for all such terms:\n","\n","\\begin{align}\n","{n}^\\mu\\bar{m}^\\nu{n}^\\eta\\bar{m}^\\delta\n","&= {n}^\\mu(M^\\nu - i \\mathcal{M}^\\nu){n}^\\eta(M^\\delta - i \\mathcal{M}^\\delta) \\\\\n","&= \\left({n}^\\mu M^\\nu {n}^\\eta M^\\delta -\n","{n}^\\mu \\mathcal{M}^\\nu {n}^\\eta \\mathcal{M}^\\delta \\right)+\n","i \\left(\n","-{n}^\\mu M^\\nu {n}^\\eta \\mathcal{M}^\\delta\n","-{n}^\\mu \\mathcal{M}^\\nu {n}^\\eta M^\\delta\n","\\right)\n","\\end{align}\n","\n"]},{"cell_type": "code","execution_count": 10,"metadata": {},"outputs": [{"name": "stdout","output_type": "stream","text": ["initialize_param() minor warning: Did nothing; already initialized parameter reference_metric::M_PI\n","initialize_param() minor warning: Did nothing; already initialized parameter reference_metric::xmin\n","initialize_param() minor warning: Did nothing; already initialized parameter reference_metric::xmax\n","initialize_param() minor warning: Did nothing; already initialized parameter reference_metric::ymin\n","initialize_param() minor warning: Did nothing; already initialized parameter reference_metric::ymax\n","initialize_param() minor warning: Did nothing; already initialized parameter reference_metric::zmin\n","initialize_param() minor warning: Did nothing; already initialized parameter reference_metric::zmax\n"]}],"source": ["# mre4U = ixp.declarerank1(\"mre4U\",DIM=4)\n","# mim4U = ixp.declarerank1(\"mim4U\",DIM=4)\n","# n4U = ixp.declarerank1(\"n4U\" ,DIM=4)\n","\n","import BSSN.Psi4_tetrads as P4t\n","P4t.Psi4_tetrads()\n","mre4U = P4t.mre4U\n","mim4U = P4t.mim4U\n","n4U = P4t.n4U\n","\n","def tetrad_product__Real_psi4(n,Mre,Mim, mu,nu,eta,delta):\n"," return +n[mu]*Mre[nu]*n[eta]*Mre[delta] - n[mu]*Mim[nu]*n[eta]*Mim[delta]\n","\n","def tetrad_product__Imag_psi4(n,Mre,Mim, mu,nu,eta,delta):\n"," return -n[mu]*Mre[nu]*n[eta]*Mim[delta] - n[mu]*Mim[nu]*n[eta]*Mre[delta]\n","\n","\n","psi4_re = sp.sympify(0)\n","psi4_im = sp.sympify(0)\n","# First term:\n","for i in range(DIM):\n"," for j in range(DIM):\n"," for k in range(DIM):\n"," for l in range(DIM):\n"," psi4_re += rank4term1[i][j][k][l]*tetrad_product__Real_psi4(n4U,mre4U,mim4U, i+1,j+1,k+1,l+1)\n"," psi4_im += rank4term1[i][j][k][l]*tetrad_product__Imag_psi4(n4U,mre4U,mim4U, i+1,j+1,k+1,l+1)\n","\n","# Second term:\n","for j in range(DIM):\n"," for k in range(DIM):\n"," for l in range(DIM):\n"," psi4_re += rank3term2[j][k][l] * \\\n"," sp.Rational(1,2)*(+tetrad_product__Real_psi4(n4U,mre4U,mim4U, 0,j+1,k+1,l+1)\n"," -tetrad_product__Real_psi4(n4U,mre4U,mim4U, j+1,0,k+1,l+1) )\n"," psi4_im += rank3term2[j][k][l] * \\\n"," sp.Rational(1,2)*(+tetrad_product__Imag_psi4(n4U,mre4U,mim4U, 0,j+1,k+1,l+1)\n"," -tetrad_product__Imag_psi4(n4U,mre4U,mim4U, j+1,0,k+1,l+1) )\n","# Third term:\n","for j in range(DIM):\n"," for l in range(DIM):\n"," psi4_re += rank2term3[j][l] * \\\n"," (sp.Rational(1,4)*(+tetrad_product__Real_psi4(n4U,mre4U,mim4U, 0,j+1,0,l+1)\n"," -tetrad_product__Real_psi4(n4U,mre4U,mim4U, j+1,0,0,l+1)\n"," -tetrad_product__Real_psi4(n4U,mre4U,mim4U, 0,j+1,l+1,0)\n"," +tetrad_product__Real_psi4(n4U,mre4U,mim4U, j+1,0,l+1,0)))\n"," psi4_im += rank2term3[j][l] * \\\n"," (sp.Rational(1,4)*(+tetrad_product__Imag_psi4(n4U,mre4U,mim4U, 0,j+1,0,l+1)\n"," -tetrad_product__Imag_psi4(n4U,mre4U,mim4U, j+1,0,0,l+1)\n"," -tetrad_product__Imag_psi4(n4U,mre4U,mim4U, 0,j+1,l+1,0)\n"," +tetrad_product__Imag_psi4(n4U,mre4U,mim4U, j+1,0,l+1,0)))"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='code_validation'></a>\n","\n","# Step 6: Code validation against BSSN.Psi4 NRPy+ module \\[Back to [top](#toc)\\]\n","$$\\label{code_validation}$$\n","\n","As a code validation check, we verify agreement in the SymPy expressions for the RHSs of the BSSN equations between\n","1. this tutorial and \n","2. the NRPy+ BSSN.Psi4 module.\n","\n","By default, we compare all quantities in Spherical coordinates, though other coordinate systems may be chosen."]},{"cell_type": "code","execution_count": 11,"metadata": {"scrolled": true},"outputs": [{"name": "stdout","output_type": "stream","text": ["STARTING NEW\n","Wrote to file \"Psi4_new.h\"\n","FINISHED NEW\n","STARTING OLD\n","Wrote to file \"Psi4_old.h\"\n","FINISHED OLD\n"]}],"source": ["outCparams = \"preindent=1,outCfileaccess=w,outCverbose=False,includebraces=False\"\n","print(\"STARTING NEW\")\n","fin.FD_outputC(\"Psi4_new.h\", lhrh(lhs=\"psi4_real\", rhs=psi4_im), outCparams)\n","print(\"FINISHED NEW\")\n","\n","gri.glb_gridfcs_list = []\n","\n","import WeylScal4NRPy.WeylScalars_Cartesian as W4\n","W4.WeylScalars_Cartesian()\n","print(\"STARTING OLD\")\n","fin.FD_outputC(\"Psi4_old.h\", lhrh(lhs=\"psi4_real\", rhs=W4.psi4i), outCparams)\n","print(\"FINISHED OLD\")\n","\n","# print(\"FullSimplify[\"+str(sp.mathematica_code(psi4_re-W4.psi4r))+\"]\")\n","# with open(\"math.txt\",\"w\") as file:\n","# file.write(\"FullSimplify[\"+str(sp.mathematica_code(psi4_re-W4.psi4r))+\"]\")\n"," \n","# # Call the BSSN_RHSs() function from within the\n","# # BSSN/BSSN_RHSs.py module,\n","# # which should do exactly the same as in Steps 1-16 above.\n","# print(\"vvv Ignore the minor warnings below. vvv\")\n","# import BSSN.Psi4 as BP4\n","# BP4.Psi4()\n","# print(\"^^^ Ignore the minor warnings above. ^^^\\n\")\n","\n","# print(\"Consistency check between this tutorial and BSSN.Psi4 NRPy+ module: ALL SHOULD BE ZERO.\")\n","\n","# print(\"psi4_im - BP4.psi4_im = \" + str(psi4_im - BP4.psi4_im))\n","# print(\"psi4_re - BP4.psi4_re = \" + str(psi4_re - BP4.psi4_re))"]},{"cell_type": "code","execution_count": 12,"metadata": {},"outputs": [{"name": "stdout","output_type": "stream","text": ["GOOD: 9.858968807130199e-16 : 1.678026634904849e-08 1.678026634904847e-08\r\n"]}],"source": ["!gcc -O2 psi4_tester.c -o psi4_tester -lm\n","!./psi4_tester 4 4 4"]},{"cell_type": "markdown","metadata": {},"source": ["<a id='latex_pdf_output'></a>\n","\n","# Step 7: Output this notebook to $\\LaTeX$-formatted PDF file \\[Back to [top](#toc)\\]\n","$$\\label{latex_pdf_output}$$"]},{"cell_type": "code","execution_count": 13,"metadata": {},"outputs": [{"name": "stdout","output_type": "stream","text": ["[NbConvertApp] Converting notebook Tutorial-Psi4.ipynb to latex\n","[NbConvertApp] Writing 61056 bytes to Tutorial-Psi4.tex\n","This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/Debian) (preloaded format=pdflatex)\n"," restricted \\write18 enabled.\n","entering extended mode\n","This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/Debian) (preloaded format=pdflatex)\n"," restricted \\write18 enabled.\n","entering extended mode\n","This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/Debian) (preloaded format=pdflatex)\n"," restricted \\write18 enabled.\n","entering extended mode\n"]}],"source": ["!jupyter nbconvert --to latex --template latex_nrpy_style.tplx --log-level='WARN' Tutorial-Psi4.ipynb\n","!pdflatex -interaction=batchmode Tutorial-Psi4.tex\n","!pdflatex -interaction=batchmode Tutorial-Psi4.tex\n","!pdflatex -interaction=batchmode Tutorial-Psi4.tex\n","!rm -f Tut*.out Tut*.aux Tut*.log"]}],"metadata": {"kernelspec": {"display_name": "Python 2","language": "python","name": "python2"},"language_info": {"codemirror_mode": {"name": "ipython","version": 2},"file_extension": ".py","mimetype": "text/x-python","name": "python","nbconvert_exporter": "python","pygments_lexer": "ipython2","version": "2.7.13"}},"nbformat": 4,"nbformat_minor": 2}
# This code calculates the Weyl scalars psi0, psi1, psi2, psi3, and psi4. It does so by following the paper# Baker, Campanelli, and Lousto. PRD 65, 044001 (2002), gr-qc/0104063 and the example set by the Kranc-# generated ETK thorn which can be found at https://bitbucket.org/einsteintoolkit/einsteinanalysis/src# Step 1: import all needed modules from NRPy+:import NRPy_param_funcs as parimport indexedexp as ixpimport grid as griimport finite_difference as finfrom outputC import *import sympy as sp# Step 2: Initialize WeylScalars parametersthismodule = __name__# Current option: Approx_QuasiKinnersley = choice made in Baker, Campanelli, and Lousto. PRD 65, 044001 (2002)par.initialize_param(par.glb_param("char *", thismodule, "TetradChoice", "Approx_QuasiKinnersley"))# This controls what gets output. Acceptable values are "psi4_only", "all_psis", and "all_psis_and_invariants"par.initialize_param(par.glb_param("char *", thismodule, "output_scalars", "all_psis_and_invariants"))# Step 3: Define the rank-3 version of the Levi-Civita symbol. Amongst# other possible uses, this is needed for the construction of the approximate# quasi-Kinnersley tetrad.def define_LeviCivitaSymbol_rank3(DIM=-1):if DIM == -1:DIM = par.parval_from_str("DIM")LeviCivitaSymbol = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for k in range(DIM):# From https://codegolf.stackexchange.com/questions/160359/levi-civita-symbol :LeviCivitaSymbol[i][j][k] = (i - j) * (j - k) * (k - i) / 2return LeviCivitaSymbol# Step 1: Call BSSNs. This module computes many different quantities related to the metric,# many of which will be essential here. We must first change to our desired coordinate# system, however.def WeylScalars_Cartesian():# We do not need the barred or hatted quantities calculated when using Cartesian coordinates.# Instead, we declare the PHYSICAL metric and extrinsic curvature as grid functions.gammaDD = ixp.register_gridfunctions_for_single_rank2("AUX","gammaDD", "sym01")kDD = ixp.register_gridfunctions_for_single_rank2("AUX","kDD", "sym01")gammaUU, detgamma = ixp.symm_matrix_inverter3x3(gammaDD)output_scalars = par.parval_from_str("output_scalars")global psi4r,psi4i,psi3r,psi3i,psi2r,psi2i,psi1r,psi1i,psi0r,psi0i# if output_scalars is "all_psis_and_invariants":# psi4r,psi4i,psi3r,psi3i,psi2r,psi2i,psi1r,psi1i,psi0r,psi0i = sp.symbols("psi4r psi4i\# psi3r psi3i\# psi2r psi2i\# psi1r psi1i\# psi0r psi0i")# elif output_scalars is "all_psis":psi4r,psi4i,psi3r,psi3i,psi2r,psi2i,psi1r,psi1i,psi0r,psi0i = gri.register_gridfunctions("AUX",["psi4r","psi4i",\"psi3r","psi3i",\"psi2r","psi2i",\"psi1r","psi1i",\"psi0r","psi0i"])# Step 2a: Set spatial dimension (must be 3 for BSSN)DIM = 3par.set_parval_from_str("grid::DIM",DIM)# Step 2b: Set the coordinate system to Cartesianx,y,z = gri.register_gridfunctions("AUX",["x","y","z"])# Step 2c: Set which tetrad is used; at the moment, only one supported optionif par.parval_from_str("WeylScal4NRPy.WeylScalars_Cartesian::TetradChoice") == "Approx_QuasiKinnersley":# Step 3a: Choose 3 orthogonal vectors. Here, we choose one in the azimuthal# direction, one in the radial direction, and the cross product of the two.# Eqs 5.6, 5.7 in https://arxiv.org/pdf/gr-qc/0104063.pdf:# v_1^a &= [-y,x,0] \\# v_2^a &= [x,y,z] \\# v_3^a &= {\rm det}(g)^{1/2} g^{ad} \epsilon_{dbc} v_1^b v_2^c,v1U = ixp.zerorank1()v2U = ixp.zerorank1()v3U = ixp.zerorank1()v1U[0] = -yv1U[1] = xv1U[2] = sp.sympify(0)v2U[0] = xv2U[1] = yv2U[2] = zLeviCivitaSymbol_rank3 = define_LeviCivitaSymbol_rank3()for a in range(DIM):for b in range(DIM):for c in range(DIM):for d in range(DIM):v3U[a] += sp.sqrt(detgamma) * gammaUU[a][d] * LeviCivitaSymbol_rank3[d][b][c] * v1U[b] *v2U[c]# Step 3b: Gram-Schmidt orthonormalization of the vectors.# The w_i^a vectors here are used to temporarily hold values on the way to the final vectors e_i^a# e_1^a &= \frac{v_1^a}{\omega_{11}} \\# e_2^a &= \frac{v_2^a - \omega_{12} e_1^a}{\omega_{22}} \\# e_3^a &= \frac{v_3^a - \omega_{13} e_1^a - \omega_{23} e_2^a}{\omega_{33}}, \\# Normalize the first vectorw1U = ixp.zerorank1()for a in range(DIM):w1U[a] = v1U[a]omega11 = sp.sympify(0)for a in range(DIM):for b in range(DIM):omega11 += w1U[a] * w1U[b] * gammaDD[a][b]e1U = ixp.zerorank1()for a in range(DIM):e1U[a] = w1U[a] / sp.sqrt(omega11)# Subtract off the portion of the first vector along the second, then normalizeomega12 = sp.sympify(0)for a in range(DIM):for b in range(DIM):omega12 += e1U[a] * v2U[b] * gammaDD[a][b]w2U = ixp.zerorank1()for a in range(DIM):w2U[a] = v2U[a] - omega12*e1U[a]omega22 = sp.sympify(0)for a in range(DIM):for b in range(DIM):omega22 += w2U[a] * w2U[b] *gammaDD[a][b]e2U = ixp.zerorank1()for a in range(DIM):e2U[a] = w2U[a] / sp.sqrt(omega22)# Subtract off the portion of the first and second vectors along the third, then normalizeomega13 = sp.sympify(0)for a in range(DIM):for b in range(DIM):omega13 += e1U[a] * v3U[b] * gammaDD[a][b]omega23 = sp.sympify(0)for a in range(DIM):for b in range(DIM):omega23 += e2U[a] * v3U[b] * gammaDD[a][b]w3U = ixp.zerorank1()for a in range(DIM):w3U[a] = v3U[a] - omega13*e1U[a] - omega23*e2U[a]omega33 = sp.sympify(0)for a in range(DIM):for b in range(DIM):omega33 += w3U[a] * w3U[b] * gammaDD[a][b]e3U = ixp.zerorank1()for a in range(DIM):e3U[a] = w3U[a] / sp.sqrt(omega33)# Step 3c: Construct the tetrad itself.# Eqs. 5.6:# l^a &= \frac{1}{\sqrt{2}} e_2^a \\# n^a &= -\frac{1}{\sqrt{2}} e_2^a \\# m^a &= \frac{1}{\sqrt{2}} (e_3^a + i e_1^a) \\# \overset{*}{m}{}^a &= \frac{1}{\sqrt{2}} (e_3^a - i e_1^a)isqrt2 = 1/sp.sqrt(2)ltetU = ixp.zerorank1()ntetU = ixp.zerorank1()#mtetU = ixp.zerorank1()#mtetccU = ixp.zerorank1()remtetU = ixp.zerorank1() # SymPy does not like trying to take the real/imaginary parts of such aimmtetU = ixp.zerorank1() # complicated expression as the Weyl scalars, so we will do it ourselves.for i in range(DIM):ltetU[i] = isqrt2 * e2U[i]ntetU[i] = -isqrt2 * e2U[i]remtetU[i] = isqrt2 * e3U[i]immtetU[i] = isqrt2 * e1U[i]nn = isqrt2else:print("Error: TetradChoice == "+par.parval_from_str("TetradChoice")+" unsupported!")exit(1)gammaDD_dD = ixp.declarerank3("gammaDD_dD","sym01")# Define the Christoffel symbolsGammaUDD = ixp.zerorank3(DIM)for i in range(DIM):for k in range(DIM):for l in range(DIM):for m in range(DIM):GammaUDD[i][k][l] += (sp.Rational(1,2))*gammaUU[i][m]*\(gammaDD_dD[m][k][l] + gammaDD_dD[m][l][k] - gammaDD_dD[k][l][m])# Step 4b: Declare and construct the Riemann curvature tensor:# R_{abcd} = \frac{1}{2} (\gamma_{ad,cb}+\gamma_{bc,da}-\gamma_{ac,bd}-\gamma_{bd,ac})# + \gamma_{je} \Gamma^{j}_{bc}\Gamma^{e}_{ad} - \gamma_{je} \Gamma^{j}_{bd} \Gamma^{e}_{ac}gammaDD_dDD = ixp.declarerank4("gammaDD_dDD","sym01_sym23")RiemannDDDD = ixp.zerorank4()for a in range(DIM):for b in range(DIM):for c in range(DIM):for d in range(DIM):RiemannDDDD[a][b][c][d] = (gammaDD_dDD[a][d][c][b] + \gammaDD_dDD[b][c][d][a] - \gammaDD_dDD[a][c][b][d] - \gammaDD_dDD[b][d][a][c]) / 2for e in range(DIM):for j in range(DIM):RiemannDDDD[a][b][c][d] += gammaDD[j][e] * GammaUDD[j][b][c] * GammaUDD[e][a][d] - \gammaDD[j][e] * GammaUDD[j][b][d] * GammaUDD[e][a][c]# Step 4c: We also need the extrinsic curvature tensor $K_{ij}$.# In Cartesian coordinates, we already made the components gridfunctions.# We will, however, need to calculate the trace of K seperately:trK = sp.sympify(0)for i in range(DIM):for j in range(DIM):trK += gammaUU[i][j] * kDD[i][j]# Step 5: Build the formula for \psi_4.# Gauss equation: involving the Riemann tensor and extrinsic curvature.# GaussDDDD[i][j][k][l] =& R_{ijkl} + 2K_{i[k}K_{l]j}GaussDDDD = ixp.zerorank4()for i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):GaussDDDD[i][j][k][l] = RiemannDDDD[i][j][k][l] + kDD[i][k]*kDD[l][j] - kDD[i][l]*kDD[k][j]# Codazzi equation: involving partial derivatives of the extrinsic curvature.# We will first need to declare derivatives of kDD# CodazziDDD[j][k][l] =& -2 (K_{j[k,l]} + \Gamma^p_{j[k} K_{l]p})kDD_dD = ixp.declarerank3("kDD_dD","sym01")CodazziDDD = ixp.zerorank3()for j in range(DIM):for k in range(DIM):for l in range(DIM):CodazziDDD[j][k][l] = kDD_dD[j][l][k] - kDD_dD[j][k][l]for p in range(DIM):CodazziDDD[j][k][l] += GammaUDD[p][j][l]*kDD[k][p] - GammaUDD[p][j][k]*kDD[l][p]# Another piece. While not associated with any particular equation,# this is still useful for organizational purposes.# RojoDD[j][l]} = & R_{jl} - K_{jp} K^p_l + KK_{jl} \\# = & \gamma^{pd} R_{jpld} - K_{jp} K^p_l + KK_{jl}RojoDD = ixp.zerorank2()for j in range(DIM):for l in range(DIM):RojoDD[j][l] = trK*kDD[j][l]for p in range(DIM):for d in range(DIM):RojoDD[j][l] += gammaUU[p][d]*RiemannDDDD[j][p][l][d] - kDD[j][p]*gammaUU[p][d]*kDD[d][l]# Now we can calculate $\psi_4$ itself! We assume l^0 = n^0 = \frac{1}{\sqrt{2}}# and m^0 = \overset{*}{m}{}^0 = 0 to simplify these equations.# We calculate the Weyl scalars as defined in https://arxiv.org/abs/gr-qc/0104063# In terms of the above-defined quantites, the psis are defined as:# \psi_4 =&\ (\text{GaussDDDD[i][j][k][l]}) n^i \overset{*}{m}{}^j n^k \overset{*}{m}{}^l \\# &+2 (\text{CodazziDDD[j][k][l]}) n^{0} \overset{*}{m}{}^{j} n^k \overset{*}{m}{}^l \\# &+ (\text{RojoDD[j][l]}) n^{0} \overset{*}{m}{}^{j} n^{0} \overset{*}{m}{}^{l}.# \psi_3 =&\ (\text{GaussDDDD[i][j][k][l]}) l^i n^j \overset{*}{m}{}^k n^l \\# &+ (\text{CodazziDDD[j][k][l]}) (l^{0} n^{j} \overset{*}{m}{}^k n^l - l^{j} n^{0} \overset{*}{m}{}^k n^l - l^k n^j\overset{*}{m}{}^l n^0) \\# &- (\text{RojoDD[j][l]}) l^{0} n^{j} \overset{*}{m}{}^l n^0 - l^{j} n^{0} \overset{*}{m}{}^l n^0 \\# \psi_2 =&\ (\text{GaussDDDD[i][j][k][l]}) l^i m^j \overset{*}{m}{}^k n^l \\# &+ (\text{CodazziDDD[j][k][l]}) (l^{0} m^{j} \overset{*}{m}{}^k n^l - l^{j} m^{0} \overset{*}{m}{}^k n^l - l^k m^l \overset{*}{m}{}^l n^0) \\# &- (\text{RojoDD[j][l]}) l^0 m^j \overset{*}{m}{}^l n^0 \\# \psi_1 =&\ (\text{GaussDDDD[i][j][k][l]}) n^i l^j m^k l^l \\# &+ (\text{CodazziDDD[j][k][l]}) (n^{0} l^{j} m^k l^l - n^{j} l^{0} m^k l^l - n^k l^l m^j l^0) \\# &- (\text{RojoDD[j][l]}) (n^{0} l^{j} m^l l^0 - n^{j} l^{0} m^l l^0) \\# \psi_0 =&\ (\text{GaussDDDD[i][j][k][l]}) l^i m^j l^k m^l \\# &+2 (\text{CodazziDDD[j][k][l]}) (l^0 m^j l^k m^l + l^k m^l l^0 m^j) \\# &+ (\text{RojoDD[j][l]}) l^0 m^j l^0 m^j. \\psi4r = sp.sympify(0)psi4i = sp.sympify(0)psi3r = sp.sympify(0)psi3i = sp.sympify(0)psi2r = sp.sympify(0)psi2i = sp.sympify(0)psi1r = sp.sympify(0)psi1i = sp.sympify(0)psi0r = sp.sympify(0)psi0i = sp.sympify(0)for l in range(DIM):for j in range(DIM):psi4r += RojoDD[j][l] * nn * nn * (remtetU[j]*remtetU[l]-immtetU[j]*immtetU[l])psi4i += RojoDD[j][l] * nn * nn * (-remtetU[j]*immtetU[l]-immtetU[j]*remtetU[l])psi3r +=-RojoDD[j][l] * nn * nn * (ntetU[j]-ltetU[j]) * remtetU[l]psi3i += RojoDD[j][l] * nn * nn * (ntetU[j]-ltetU[j]) * immtetU[l]psi2r +=-RojoDD[j][l] * nn * nn * (remtetU[l]*remtetU[j]+immtetU[j]*immtetU[l])psi2i +=-RojoDD[j][l] * nn * nn * (immtetU[l]*remtetU[j]-remtetU[j]*immtetU[l])psi1r += RojoDD[j][l] * nn * nn * (ntetU[j]*remtetU[l]-ltetU[j]*remtetU[l])psi1i += RojoDD[j][l] * nn * nn * (ntetU[j]*immtetU[l]-ltetU[j]*immtetU[l])psi0r += RojoDD[j][l] * nn * nn * (remtetU[j]*remtetU[l]-immtetU[j]*immtetU[l])psi0i += RojoDD[j][l] * nn * nn * (remtetU[j]*immtetU[l]+immtetU[j]*remtetU[l])for l in range(DIM):for j in range(DIM):for k in range(DIM):psi4r += 2 * CodazziDDD[j][k][l] * ntetU[k] * nn * (remtetU[j]*remtetU[l]-immtetU[j]*immtetU[l])psi4i += 2 * CodazziDDD[j][k][l] * ntetU[k] * nn * (-remtetU[j]*immtetU[l]-immtetU[j]*remtetU[l])psi3r += 1 * CodazziDDD[j][k][l] * nn * ((ntetU[j]-ltetU[j])*remtetU[k]*ntetU[l]-remtetU[j]*ltetU[k]*ntetU[l])psi3i +=-1 * CodazziDDD[j][k][l] * nn * ((ntetU[j]-ltetU[j])*immtetU[k]*ntetU[l]-immtetU[j]*ltetU[k]*ntetU[l])psi2r += 1 * CodazziDDD[j][k][l] * nn * (ntetU[l]*(remtetU[j]*remtetU[k]+immtetU[j]*immtetU[k])-ltetU[k]*(remtetU[j]*remtetU[l]+immtetU[j]*immtetU[l]))psi2i += 1 * CodazziDDD[j][k][l] * nn * (ntetU[l]*(immtetU[j]*remtetU[k]-remtetU[j]*immtetU[k])-ltetU[k]*(remtetU[j]*immtetU[l]-immtetU[j]*remtetU[l]))psi1r += 1 * CodazziDDD[j][k][l] * nn * (ltetU[j]*remtetU[k]*ltetU[l]-remtetU[j]*ntetU[k]*ltetU[l]-ntetU[j]*remtetU[k]*ltetU[l])psi1i += 1 * CodazziDDD[j][k][l] * nn * (ltetU[j]*immtetU[k]*ltetU[l]-immtetU[j]*ntetU[k]*ltetU[l]-ntetU[j]*immtetU[k]*ltetU[l])psi0r += 2 * CodazziDDD[j][k][l] * nn * ltetU[k]*(remtetU[j]*remtetU[l]-immtetU[j]*immtetU[l])psi0i += 2 * CodazziDDD[j][k][l] * nn * ltetU[k]*(remtetU[j]*immtetU[l]+immtetU[j]*remtetU[l])for l in range(DIM):for j in range(DIM):for k in range(DIM):for i in range(DIM):psi4r += GaussDDDD[i][j][k][l] * ntetU[i] * ntetU[k] * (remtetU[j]*remtetU[l]-immtetU[j]*immtetU[l])psi4i += GaussDDDD[i][j][k][l] * ntetU[i] * ntetU[k] * (-remtetU[j]*immtetU[l]-immtetU[j]*remtetU[l])psi3r += GaussDDDD[i][j][k][l] * ltetU[i] * ntetU[j] * remtetU[k] * ntetU[l]psi3i +=-GaussDDDD[i][j][k][l] * ltetU[i] * ntetU[j] * immtetU[k] * ntetU[l]psi2r += GaussDDDD[i][j][k][l] * ltetU[i] * ntetU[l] * (remtetU[j]*remtetU[k]+immtetU[j]*immtetU[k])psi2i += GaussDDDD[i][j][k][l] * ltetU[i] * ntetU[l] * (immtetU[j]*remtetU[k]-remtetU[j]*immtetU[k])psi1r += GaussDDDD[i][j][k][l] * ntetU[i] * ltetU[j] * remtetU[k] * ltetU[l]psi1i += GaussDDDD[i][j][k][l] * ntetU[i] * ltetU[j] * immtetU[k] * ltetU[l]psi0r += GaussDDDD[i][j][k][l] * ltetU[i] * ltetU[k] * (remtetU[j]*remtetU[l]-immtetU[j]*immtetU[l])psi0i += GaussDDDD[i][j][k][l] * ltetU[i] * ltetU[k] * (remtetU[j]*immtetU[l]+immtetU[j]*remtetU[l])
#include <stdio.h>#include <math.h>#include <stdlib.h>#include <sys/time.h>/* EVOLVED VARIABLES: */#define NUM_AUX_GFS 15#define KDD00GF 0#define KDD01GF 1#define KDD02GF 2#define KDD11GF 3#define KDD12GF 4#define KDD22GF 5#define GAMMADD00GF 6#define GAMMADD01GF 7#define GAMMADD02GF 8#define GAMMADD11GF 9#define GAMMADD12GF 10#define GAMMADD22GF 11#define XGF 12#define YGF 13#define ZGF 14#define REAL double#define NGHOSTS 2// Cartesian coordinates parametersconst REAL xmin = -10.,xmax=10.;const REAL ymin = -10.,ymax=10.;const REAL zmin = -10.,zmax=10.;#define IDX4(g,i,j,k) \( (i) + Nxx_plus_2NGHOSTS[0] * ( (j) + Nxx_plus_2NGHOSTS[1] * ( (k) + Nxx_plus_2NGHOSTS[2] * (g) ) ) )#define IDX3(i,j,k) ( (i) + Nxx_plus_2NGHOSTS[0] * ( (j) + Nxx_plus_2NGHOSTS[1] * (k) ) )// Assuming idx = IDX3(i,j,k). Much faster if idx can be reused over and over:#define IDX4pt(g,idx) ( (idx) + (Nxx_plus_2NGHOSTS[0]*Nxx_plus_2NGHOSTS[1]*Nxx_plus_2NGHOSTS[2]) * (g) )int main(int argc, const char *argv[]) {// Step 0a: Read command-line input, error out if nonconformantif((argc != 4) || atoi(argv[1]) < NGHOSTS || atoi(argv[2]) < NGHOSTS || atoi(argv[3]) < 2 /* FIXME; allow for axisymmetric sims */) {fprintf(stderr,"Error: Expected three command-line arguments: ./BrillLindquist_Playground Nx0 Nx1 Nx2,\n");fprintf(stderr,"where Nx[0,1,2] is the number of grid points in the 0, 1, and 2 directions.\n");fprintf(stderr,"Nx[] MUST BE larger than NGHOSTS (= %d)\n",NGHOSTS);exit(1);}// Step 0b: Set up numerical grid structure, first in space...const int Nxx[3] = { atoi(argv[1]), atoi(argv[2]), atoi(argv[3]) };if(Nxx[0]%2 != 0 || Nxx[1]%2 != 0 || Nxx[2]%2 != 0) {fprintf(stderr,"Error: Cannot guarantee a proper cell-centered grid if number of grid cells not set to even number.\n");fprintf(stderr," For example, in case of angular directions, proper symmetry zones will not exist.\n");exit(1);}const int Nxx_plus_2NGHOSTS[3] = { Nxx[0]+2*NGHOSTS, Nxx[1]+2*NGHOSTS, Nxx[2]+2*NGHOSTS };const int Nxx_plus_2NGHOSTS_tot = Nxx_plus_2NGHOSTS[0]*Nxx_plus_2NGHOSTS[1]*Nxx_plus_2NGHOSTS[2];REAL *aux_gfs_new = (REAL *)malloc(sizeof(REAL) * NUM_AUX_GFS * Nxx_plus_2NGHOSTS_tot);REAL *aux_gfs_old = (REAL *)malloc(sizeof(REAL) * NUM_AUX_GFS * Nxx_plus_2NGHOSTS_tot);// Step 0d: Set up space and time coordinates// Step 0d.i: Set \Delta x^i on uniform grids.REAL xxmin[3],xxmax[3];xxmin[0] = xmin;xxmin[1] = ymin;xxmin[2] = zmin;xxmax[0] = xmax;xxmax[1] = ymax;xxmax[2] = zmax;REAL dxx[3];for(int i=0;i<3;i++) dxx[i] = (xxmax[i] - xxmin[i]) / ((REAL)Nxx[i]);// Step 0d.ii: Set up uniform coordinate gridsREAL *xx[3];for(int i=0;i<3;i++) {xx[i] = (REAL *)malloc(sizeof(REAL)*Nxx_plus_2NGHOSTS[i]);for(int j=0;j<Nxx_plus_2NGHOSTS[i];j++) {xx[i][j] = xxmin[i] + ((REAL)(j-NGHOSTS) + (1.0/2.0))*dxx[i]; // Cell-centered grid.}}struct timeval time;gettimeofday(&time,NULL);// microsecond has 1 000 000// Assuming you did not need quite that accuracy// Also do not assume the system clock has that accuracy.srand48((time.tv_sec * 1000) + (time.tv_usec / 1000));/*time_t t;srand48((unsigned) time(&t));*/#define PERT_SIZE 1e-6#define LOOP_REGION(i0min,i0max, i1min,i1max, i2min,i2max) \for(int i2=i2min;i2<i2max;i2++) for(int i1=i1min;i1<i1max;i1++) for(int i0=i0min;i0<i0max;i0++)LOOP_REGION(0,Nxx_plus_2NGHOSTS[0], 0,Nxx_plus_2NGHOSTS[1], 0,Nxx_plus_2NGHOSTS[2]) {for(int gf=KDD00GF;gf<=KDD22GF;gf++) aux_gfs_new[IDX4(gf,i0,i1,i2)] = aux_gfs_old[IDX4(gf,i0,i1,i2)] = PERT_SIZE*(0.5-drand48());for(int gf=GAMMADD00GF;gf<=GAMMADD22GF;gf++) aux_gfs_new[IDX4(gf,i0,i1,i2)] = aux_gfs_old[IDX4(gf,i0,i1,i2)] = PERT_SIZE*(0.5-drand48());aux_gfs_new[IDX4(GAMMADD00GF,i0,i1,i2)] = aux_gfs_old[IDX4(GAMMADD00GF,i0,i1,i2)] = 1.0 + PERT_SIZE*(0.5-drand48());aux_gfs_new[IDX4(GAMMADD11GF,i0,i1,i2)] = aux_gfs_old[IDX4(GAMMADD11GF,i0,i1,i2)] = 1.0 + PERT_SIZE*(0.5-drand48());aux_gfs_new[IDX4(GAMMADD22GF,i0,i1,i2)] = aux_gfs_old[IDX4(GAMMADD22GF,i0,i1,i2)] = 1.0 + PERT_SIZE*(0.5-drand48());aux_gfs_new[IDX4(XGF,i0,i1,i2)] = aux_gfs_old[IDX4(XGF,i0,i1,i2)] = xx[0][i0];aux_gfs_new[IDX4(YGF,i0,i1,i2)] = aux_gfs_old[IDX4(YGF,i0,i1,i2)] = xx[1][i1];aux_gfs_new[IDX4(ZGF,i0,i1,i2)] = aux_gfs_old[IDX4(ZGF,i0,i1,i2)] = xx[2][i2];}REAL psi4_real_new,psi4_real_old;LOOP_REGION(NGHOSTS,Nxx_plus_2NGHOSTS[0]-NGHOSTS, NGHOSTS,Nxx_plus_2NGHOSTS[1]-NGHOSTS, NGHOSTS,Nxx_plus_2NGHOSTS[2]-NGHOSTS) {REAL *aux_gfs = aux_gfs_new;const REAL xx0 = xx[0][i0], xx1 = xx[1][i1], xx2 = xx[2][i2];const REAL invdx0 = 1.0/dxx[0];const REAL invdx1 = 1.0/dxx[1];const REAL invdx2 = 1.0/dxx[2];REAL psi4_real;#include "Psi4_new.h"if(i0==Nxx_plus_2NGHOSTS[0]/2 && i1==Nxx_plus_2NGHOSTS[1]/2 && i2==Nxx_plus_2NGHOSTS[2]/2) {//printf("%.15e\n",psi4_real);psi4_real_new = psi4_real;}//printf("%d %d %d %.15e\n",i0,i1,i2,psi4_real);}LOOP_REGION(NGHOSTS,Nxx_plus_2NGHOSTS[0]-NGHOSTS, NGHOSTS,Nxx_plus_2NGHOSTS[1]-NGHOSTS, NGHOSTS,Nxx_plus_2NGHOSTS[2]-NGHOSTS) {REAL *aux_gfs = aux_gfs_old;const REAL xx0 = xx[0][i0], xx1 = xx[1][i1], xx2 = xx[2][i2];const REAL invdx0 = 1.0/dxx[0];const REAL invdx1 = 1.0/dxx[1];const REAL invdx2 = 1.0/dxx[2];REAL psi4_real;#include "Psi4_old.h"if(i0==Nxx_plus_2NGHOSTS[0]/2 && i1==Nxx_plus_2NGHOSTS[1]/2 && i2==Nxx_plus_2NGHOSTS[2]/2) {psi4_real_old = psi4_real;//printf("%.15e\n",psi4_real);}}REAL relerror = fabs(psi4_real_new - psi4_real_old) / (0.5* ( fabs(psi4_real_new) + fabs(psi4_real_old) ));if(relerror < 1e-13) {printf("GOOD: %.15e : %.15e %.15e\n",relerror, psi4_real_new,psi4_real_old);} else {printf("BAD: %.15e : %.15e %.15e %ld\n",relerror, psi4_real_new,psi4_real_old, (time.tv_sec * 1000) + (time.tv_usec / 1000));}for(int i=0;i<3;i++) free(xx[i]);free(aux_gfs_new);free(aux_gfs_old);return 0;}
# As documented in the NRPy+ tutorial module# Tutorial-Psi4_tetrads.ipynb,# this module will construct tetrads# needed to compute \psi_4 (as well as other# Weyl scalars and invariants in principle)# Authors: Zachariah B. Etienne# (zachetie **at** gmail **dot* com),# and Patrick Nelson# Step 1.a: import all needed modules from NRPy+:import sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport reference_metric as rfm # NRPy+: Reference metric supportimport sys # Standard Python modules for multiplatform OS-level functions# Step 1.b: Initialize TetradChoice parameterthismodule = __name__# Current option: QuasiKinnersley = choice made in Baker, Campanelli, and Lousto. PRD 65, 044001 (2002)par.initialize_param(par.glb_param("char", thismodule, "TetradChoice", "QuasiKinnersley"))par.initialize_param(par.glb_param("char", thismodule, "UseCorrectUnitNormal", "False")) # False = consistent with WeylScal4 ETK thorn.def Psi4_tetrads():global l4U, n4U, mre4U, mim4U# Step 1.c: Check if tetrad choice is implemented:if par.parval_from_str(thismodule+"::TetradChoice") != "QuasiKinnersley":print("ERROR: "+thismodule+"::TetradChoice = "+par.parval_from_str("TetradChoice")+" currently unsupported!")sys.exit(1)# Step 1.d: Given the chosen coordinate system, set up# corresponding reference metric and needed# reference metric quantities# The following function call sets up the reference metric# and related quantities, including rescaling matrices ReDD,# ReU, and hatted quantities.rfm.reference_metric()# Step 1.e: Set spatial dimension (must be 3 for BSSN, as BSSN is# a 3+1-dimensional decomposition of the general# relativistic field equations)DIM = 3# Step 1.f: Import all ADM quantities as written in terms of BSSN quantitiesimport BSSN.ADM_in_terms_of_BSSN as ABAB.ADM_in_terms_of_BSSN()# Step 2.a: Declare the Cartesian x,y,z in terms of# xx0,xx1,xx2.x = rfm.xxCart[0]y = rfm.xxCart[1]z = rfm.xxCart[2]# Step 2.b: Declare v_1^a, v_2^a, and v_3^a tetrads,# as well as detgamma and gammaUU from# BSSN.ADM_in_terms_of_BSSNv1UCart = ixp.zerorank1()v2UCart = ixp.zerorank1()detgamma = AB.detgammagammaUU = AB.gammaUU# Step 2.c: Define v1U and v2Uv1UCart = [-y, x, sp.sympify(0)]v2UCart = [x, y, z]# Step 2.d: Construct the Jacobian d x_Cart^i / d xx^jJac_dUCart_dDrfmUD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):Jac_dUCart_dDrfmUD[i][j] = sp.simplify(sp.diff(rfm.xxCart[i], rfm.xx[j]))# Step 2.e: Invert above Jacobian to get needed d xx^j / d x_Cart^iJac_dUrfm_dDCartUD, dummyDET = ixp.generic_matrix_inverter3x3(Jac_dUCart_dDrfmUD)# Step 2.e.i: Simplify expressions for d xx^j / d x_Cart^i:for i in range(DIM):for j in range(DIM):Jac_dUrfm_dDCartUD[i][j] = sp.simplify(Jac_dUrfm_dDCartUD[i][j])# Step 2.f: Transform v1U and v2U from the Cartesian to the xx^i basisv1U = ixp.zerorank1()v2U = ixp.zerorank1()for i in range(DIM):for j in range(DIM):v1U[i] += Jac_dUrfm_dDCartUD[i][j] * v1UCart[j]v2U[i] += Jac_dUrfm_dDCartUD[i][j] * v2UCart[j]# Step 2.g: Define the rank-3 version of the Levi-Civita symbol. Amongst# other uses, this is needed for the construction of the approximate# quasi-Kinnersley tetrad.def define_LeviCivitaSymbol_rank3(DIM=-1):if DIM == -1:DIM = par.parval_from_str("DIM")LeviCivitaSymbol = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for k in range(DIM):# From https://codegolf.stackexchange.com/questions/160359/levi-civita-symbol :LeviCivitaSymbol[i][j][k] = (i - j) * (j - k) * (k - i) / 2return LeviCivitaSymbol# Step 2.h: Define v3Uv3U = ixp.zerorank1()LeviCivitaSymbolDDD = define_LeviCivitaSymbol_rank3(DIM=3)for a in range(DIM):for b in range(DIM):for c in range(DIM):for d in range(DIM):v3U[a] += sp.sqrt(detgamma) * gammaUU[a][d] * LeviCivitaSymbolDDD[d][b][c] * v1U[b] * v2U[c]# Step 2.h.i: Simplify expressions for v1U,v2U,v3U. This greatly expedites the C code generation (~10x faster)for a in range(DIM):v1U[a] = sp.simplify(v1U[a])v2U[a] = sp.simplify(v2U[a])v3U[a] = sp.simplify(v3U[a])# Step 2.i: Define omega_{ij}omegaDD = ixp.zerorank2()gammaDD = AB.gammaDDdef v_vectorDU(v1U,v2U,v3U, i,a):if i==0:return v1U[a]elif i==1:return v2U[a]elif i==2:return v3U[a]else:print("ERROR: unknown vector!")sys.exit(1)def update_omega(omegaDD, i,j, v1U,v2U,v3U,gammaDD):omegaDD[i][j] = sp.sympify(0)for a in range(DIM):for b in range(DIM):omegaDD[i][j] += v_vectorDU(v1U,v2U,v3U, i,a)*v_vectorDU(v1U,v2U,v3U, j,b)*gammaDD[a][b]# Step 2.j: Define e^a_i. Note that:# omegaDD[0][0] = \omega_{11} above;# omegaDD[1][1] = \omega_{22} above, etc.# First e_1^a: Orthogonalize & normalize:e1U = ixp.zerorank1()update_omega(omegaDD, 0,0, v1U,v2U,v3U,gammaDD)for a in range(DIM):e1U[a] = v1U[a]/sp.sqrt(omegaDD[0][0])# Next e_2^a: First orthogonalize:e2U = ixp.zerorank1()update_omega(omegaDD, 0,1, e1U,v2U,v3U,gammaDD)for a in range(DIM):e2U[a] = (v2U[a] - omegaDD[0][1]*e1U[a])# Then normalize:update_omega(omegaDD, 1,1, e1U,e2U,v3U,gammaDD)for a in range(DIM):e2U[a] /= sp.sqrt(omegaDD[1][1])# Next e_3^a: First orthogonalize:e3U = ixp.zerorank1()update_omega(omegaDD, 0,2, e1U,e2U,v3U,gammaDD)update_omega(omegaDD, 1,2, e1U,e2U,v3U,gammaDD)for a in range(DIM):e3U[a] = (v3U[a] - omegaDD[0][2]*e1U[a] - omegaDD[1][2]*e2U[a])# Then normalize:update_omega(omegaDD, 2,2, e1U,e2U,e3U,gammaDD)for a in range(DIM):e3U[a] /= sp.sqrt(omegaDD[2][2])# Step 2.k: Construct l^mu, n^mu, and m^mu, based on r^mu, theta^mu, phi^mu, and u^mu:r4U = ixp.zerorank1(DIM=4)u4U = ixp.zerorank1(DIM=4)theta4U = ixp.zerorank1(DIM=4)phi4U = ixp.zerorank1(DIM=4)for a in range(DIM):r4U[ a+1] = e2U[a]theta4U[a+1] = e3U[a]phi4U[ a+1] = e1U[a]# FIXME? assumes alpha=1, beta^i = 0if par.parval_from_str(thismodule+"::UseCorrectUnitNormal") == "False":u4U[0] = 1else:# Eq. 2.116 in Baumgarte & Shapiro:# n^mu = {1/alpha, -beta^i/alpha}. Note that n_mu = {alpha,0}, so n^mu n_mu = -1.import BSSN.BSSN_quantities as BqBq.declare_BSSN_gridfunctions_if_not_declared_already()Bq.BSSN_basic_tensors()u4U[0] = 1/Bq.alphafor i in range(DIM):u4U[i+1] = -Bq.betaU[i]/Bq.alphal4U = ixp.zerorank1(DIM=4)n4U = ixp.zerorank1(DIM=4)mre4U = ixp.zerorank1(DIM=4)mim4U = ixp.zerorank1(DIM=4)# M_SQRT1_2 = 1 / sqrt(2) (defined in math.h on Linux)M_SQRT1_2 = par.Cparameters("#define",thismodule,"M_SQRT1_2","")isqrt2 = M_SQRT1_2 #1/sp.sqrt(2) <- SymPy drops precision to 15 sig. digits in unit testsfor mu in range(4):l4U[mu] = isqrt2*(u4U[mu] + r4U[mu])n4U[mu] = isqrt2*(u4U[mu] - r4U[mu])mre4U[mu] = isqrt2*theta4U[mu]mim4U[mu] = isqrt2* phi4U[mu]
# This module sets up Shifted Kerr-Schild initial data in terms of# the variables used in BSSN_RHSs.py# Authors: George Vopal, gvopal **at** gmail **dot** com# Zachariah B. Etienne, zachetie **at** gmail **dot** com# ### NRPy+ Source Code for this module: [BSSN/ShiftedKerrSchild.py](../edit/BSSN/BrillLindquist.py)## WARNING: This module has not yet undergone code testing.# **Inputs for initial data**:## * The black hole mass, M# * The black hole spin parameter, a# Step 1: Initialize core Python/NRPy+ modulesimport sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport BSSN.ADM_Exact_Spherical_or_Cartesian_to_BSSNCurvilinear as AtoBthismodule = __name__# Input parameters:M, a, r0 = par.Cparameters("REAL", thismodule,["M", "a", "r0"],[1.0, 0.9, 1.0])# ComputeADMGlobalsOnly == True will only set up the ADM global quantities.# == False will perform the full ADM SphorCart->BSSN Curvi conversiondef ShiftedKerrSchild(ComputeADMGlobalsOnly = False):global Sph_r_th_ph,r,th,ph, rho2, gammaSphDD, KSphDD, alphaSph, betaSphU, BSphU# All gridfunctions will be written in terms of spherical coordinates (r, th, ph):r,th,ph = sp.symbols('r th ph', real=True)DIM = 3par.set_parval_from_str("grid::DIM",DIM)# Auxiliary variables:rho2 = sp.symbols('rho2', real=True)# Step 1: Define rho^2, alpha, beta^(r_{KS}), beta^(theta), beta^(phi), gamma_{r_{KS}theta}, gamma_{theta\phi}# r_{KS} = r + r0rKS = r+r0# rho^2 = rKS^2 + a^2*cos^2(theta)rho2 = rKS*rKS + a*a*sp.cos(th)**2# alpha = 1/sqrt{1 + M*rKS/rho^2}alphaSph = 1/(sp.sqrt(1 + 2*M*rKS/rho2))# Initialize the shift vector, \beta^i, to zero.betaSphU = ixp.zerorank1()# beta^r = alpha^2*2Mr/rho^2betaSphU[0] = alphaSph*alphaSph*2*M*rKS/rho2# Time derivative of shift vector beta^i, B^i, is zero.BSphU = ixp.zerorank1()# Step 2: Define and construct nonzero components gamma_{r_{KS}r_{KS}}$, gamma_{r_{KS}phi},# gamma_{thetatheta}, gamma_{phiphi}# Initialize \gamma_{ij} to zero.gammaSphDD = ixp.zerorank2()# gammaDD{rKS rKS} = 1 +2M*rKS/rho^2gammaSphDD[0][0] = 1 + 2*M*rKS/rho2# gammaDD{rKS phi} = -a*gammaDD{r r}*sin^2(theta)gammaSphDD[0][2] = gammaSphDD[2][0] = -a*gammaSphDD[0][0]*sp.sin(th)**2# gammaDD{theta theta} = rho^2gammaSphDD[1][1] = rho2# gammaDD{phi phi} = (rKS^2 + a^2 + 2Mr/rho^2*a^2*sin^2(theta))*sin^2(theta)gammaSphDD[2][2] = (rKS*rKS + a*a + 2*M*rKS*a*a*sp.sin(th)**2/rho2)*sp.sin(th)**2# Step 3: Define useful quantities A, B, C# A = (a^2*cos^2(2theta) + a^2 + 2r^2)A = (a*a*sp.cos(2*th) + a*a + 2*rKS*rKS)# B = A + 4M*rKSB = A + 4*M*rKS# D = \sqrt(2M*rKS/(a^2cos^2(theta) + rKS^2) + 1)D = sp.sqrt(2*M*rKS/(a*a*sp.cos(th)**2 + rKS*rKS) + 1)# Step 4: Define the extrinsic curvature in spherical polar coordinates# Establish the 3x3 zero-matrixKSphDD = ixp.zerorank2()# *** Fill in the nonzero components ***# *** This will create an upper-triangular matrix ***# K_{r r} = D(A+2Mr)/(A^2*B)[4M(a^2*cos(2theta) + a^2 - 2r^2)]KSphDD[0][0] = D*(A+2*M*rKS)/(A*A*B)*(4*M*(a*a*sp.cos(2*th)+a*a-2*rKS*rKS))# K_{r theta} = D/(AB)[8a^2*Mr*sin(theta)cos(theta)]KSphDD[0][1] = KSphDD[1][0] = D/(A*B)*(8*a*a*M*rKS*sp.sin(th)*sp.cos(th))# K_{r phi} = D/A^2[-2aMsin^2(theta)(a^2cos(2theta)+a^2-2r^2)]KSphDD[0][2] = KSphDD[2][0] = D/(A*A)*(-2*a*M*sp.sin(th)**2*(a*a*sp.cos(2*th)+a*a-2*rKS*rKS))# K_{theta theta} = D/B[4Mr^2]KSphDD[1][1] = D/B*(4*M*rKS*rKS)# K_{theta phi} = D/(AB)*(-8*a^3*Mr*sin^3(theta)cos(theta))KSphDD[1][2] = KSphDD[2][1] = D/(A*B)*(-8*a**3*M*rKS*sp.sin(th)**3*sp.cos(th))# K_{phi phi} = D/(A^2*B)[2Mr*sin^2(theta)(a^4(M+3r)# +4a^2r^2(2r-M)+4a^2r*cos(2theta)(a^2+r(M+2r))+8r^5)]KSphDD[2][2] = D/(A*A*B)*(2*M*rKS*sp.sin(th)**2*(a**4*(rKS-M)*sp.cos(4*th)\+ a**4*(M+3*rKS)+4*a*a*rKS*rKS*(2*rKS-M)\+ 4*a*a*rKS*sp.cos(2*th)*(a*a + rKS*(M + 2*rKS)) + 8*rKS**5))if ComputeADMGlobalsOnly == True:return# Validated against original SENR:#print(sp.mathematica_code(gammaSphDD[1][1]))Sph_r_th_ph = [r,th,ph]cf,hDD,lambdaU,aDD,trK,alpha,vetU,betU = \AtoB.Convert_Spherical_or_Cartesian_ADM_to_BSSN_curvilinear("Spherical", Sph_r_th_ph,gammaSphDD,KSphDD,alphaSph,betaSphU,BSphU)import BSSN.BSSN_ID_function_string as bIDfglobal returnfunctionreturnfunction = bIDf.BSSN_ID_function_string(cf, hDD, lambdaU, aDD, trK, alpha, vetU, betU)
# This module sets up Static Trumpet initial data in terms of# the variables used in BSSN_RHSs.py# Authors: Terrence Pierre Jacques, terrencepierrej **at** gmail **dot** com# Zachariah B. Etienne, zachetie **at** gmail **dot** com# Ian Ruchlin# ## This module sets up initial data for a static trumpet geometry in spherical coordinates. We can convert from spherical to any coordinate system defined in [reference_metric.py](../edit/reference_metric.py) (e.g., SinhSpherical, Cylindrical, Cartesian, etc.) using the [Exact ADM Spherical-to-BSSNCurvilinear converter module](Tutorial-ADM_Initial_Data-Converting_Exact_ADM_Spherical_or_Cartesian_to_BSSNCurvilinear.ipynb)## ### NRPy+ Source Code for this module: [BSSN/BrillLindquist.py](../edit/BSSN/BrillLindquist.py)## <font color='green'>**All quantities have been validated against the [original SENR code](https://bitbucket.org/zach_etienne/nrpy).**</font># ### Here we set up Static Trumpet initial data ([Dennison and Baumgarte, 2014](https://arxiv.org/abs/1403.5484)):## Description of Static Trumpet geometry.## **Inputs for initial data**:## * The black hole mass $M$.## **Additional variables needed for spacetime evolution**:## * Desired coordinate system# * Desired initial lapse $\alpha$ and shift $\beta^i$. We will choose our gauge conditions as $\alpha=1$ and $\beta^i=B^i=0$. $\alpha = \psi^{-2}$ will yield much better behavior, but the conformal factor $\psi$ depends on the desired *destination* coordinate system (which may not be spherical coordinates).# Step 1: Initialize core Python/NRPy+ modulesimport sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport BSSN.ADM_Exact_Spherical_or_Cartesian_to_BSSNCurvilinear as AtoBthismodule = __name__# Input parameters:M = par.Cparameters("REAL", thismodule, ["M"], [1.0])# ComputeADMGlobalsOnly == True will only set up the ADM global quantities.# == False will perform the full ADM SphorCart->BSSN Curvi conversiondef StaticTrumpet(ComputeADMGlobalsOnly = False):global Sph_r_th_ph,r,th,ph, gammaSphDD, KSphDD, alphaSph, betaSphU, BSphU# All gridfunctions will be written in terms of spherical coordinates (r, th, ph):r,th,ph = sp.symbols('r th ph', real=True)# Step 0: Set spatial dimension (must be 3 for BSSN)DIM = 3par.set_parval_from_str("grid::DIM",DIM)# Step 1: Set psi, the conformal factor:# Auxiliary variables:psi0 = sp.symbols('psi0', real=True)# *** The StaticTrumpet conformal factor ***# Dennison and Baumgarte (2014) Eq. 13# https://arxiv.org/pdf/1403.5484.pdf# psi = sqrt{1 + M/r }psi0 = sp.sqrt(1 + M/r)# *** The physical spatial metric in spherical basis ***# Set the upper-triangle of the matrix...# Eq. 15# gamma_{ij} = psi^4 * eta_{ij}# eta_00 = 1, eta_11 = r^2, eta_22 = r^2 * sin^2 (theta)gammaSphDD = ixp.zerorank2()gammaSphDD[0][0] = psi0**4gammaSphDD[1][1] = psi0**4 * r**2gammaSphDD[2][2] = psi0**4 * r**2*sp.sin(th)**2# ... then apply symmetries to get the other components# *** The physical trace-free extrinsic curvature in spherical basis ***# Set the upper-triangle of the matrix...# Eq.19 and 20KSphDD = ixp.zerorank2()# K_{rr} = M / r^2KSphDD[0][0] = -M / r**2# K_{theta theta} = K_{phi phi} / sin^2 theta = MKSphDD[1][1] = MKSphDD[2][2] = M * sp.sin(th)**2# ... then apply symmetries to get the other components# Lapse function and shift vector# Eq. 15# alpha = r / (r+M)alphaSph = r / (r + M)betaSphU = ixp.zerorank1()# beta^r = Mr / (r + M)^2betaSphU[0] = M*r / (r + M)**2BSphU = ixp.zerorank1()if ComputeADMGlobalsOnly == True:return# Validated against original SENR:#print(sp.mathematica_code(gammaSphDD[1][1]))Sph_r_th_ph = [r,th,ph]cf,hDD,lambdaU,aDD,trK,alpha,vetU,betU = \AtoB.Convert_Spherical_or_Cartesian_ADM_to_BSSN_curvilinear("Spherical", Sph_r_th_ph,gammaSphDD,KSphDD,alphaSph,betaSphU,BSphU)import BSSN.BSSN_ID_function_string as bIDfglobal returnfunctionreturnfunction = bIDf.BSSN_ID_function_string(cf, hDD, lambdaU, aDD, trK, alpha, vetU, betU)
# This module performs the conversion of T^{mu nu}# in Spherical or Cartesian coordinates# given as *numerical* expressions (i.e., given as# numerical values with fixed floating-point precision;# e.g., in the case of an initial data solver), to# rescaled BSSN stress-energy source terms.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step P1: Import needed modulesfrom outputC import * # NRPy+: Core C code output moduleimport finite_difference as fin # NRPy+: Finite difference C code generation moduleimport grid as gri # NRPy+: Functions having to do with numerical gridsimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport reference_metric as rfm # NRPy+: Reference metric supportimport sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport BSSN.BSSN_quantities as Bq # NRPy+: This module depends on the parameter EvolvedConformalFactor_cf,# which is defined in BSSN.BSSN_quantitiesimport sys # Standard Python modules for multiplatform OS-level functionsimport BSSN.BSSN_RHSs as bssnrhs # NRPy+: BSSN RHS quantitiesimport loop as lp # NRPy+: Helper module for writing C-code loopsdef T4UUmunu_Numerical_Spherical_or_Cartesian_to_BSSNCurvilinear(CoordType_in,Tmunu_input_function_name,pointer_to_ID_inputs=False):# The ADM & BSSN formalisms only work in 3D; they are 3+1 decompositions of Einstein's equations.# To implement axisymmetry or spherical symmetry, simply set all spatial derivatives in# the relevant angular directions to zero; DO NOT SET DIM TO ANYTHING BUT 3.# Step 0: Set spatial dimension (must be 3 for BSSN)DIM = 3# Step 1: Define the input variables: the 4D stress-energy tensor, and the ADM 3-metric, lapse, & shift:T4SphorCartUU = ixp.declarerank2("T4SphorCartUU", "sym01", DIM=4)gammaSphorCartDD = ixp.declarerank2("gammaSphorCartDD", "sym01")alphaSphorCart = sp.symbols("alphaSphorCart")betaSphorCartU = ixp.declarerank1("betaSphorCartU")# Step 2: All Tmunu initial data quantities are functions of xx0,xx1,xx2, but# in the Spherical or Cartesian basis.# We first define the BSSN stress-energy source terms in the Spherical# or Cartesian basis, respectively.# To get \gamma_{\mu \nu} = gammabar4DD[mu][nu], we'll need to construct the 4-metric, using Eq. 2.122 in B&S:# S_{ij} = \gamma_{i \mu} \gamma_{j \nu} T^{\mu \nu}# S_{i} = -\gamma_{i\mu} n_\nu T^{\mu\nu}# S = \gamma^{ij} S_{ij}# rho = n_\mu n_\nu T^{\mu\nu},# where# \gamma_{\mu\nu} = g_{\mu\nu} + n_\mu n_\nu# and# n_mu = {-\alpha,0,0,0},# Step 2.1: Construct the 4-metric based on the input ADM quantities.# This is provided by Eq 4.47 in [Gourgoulhon](https://arxiv.org/pdf/gr-qc/0703035.pdf):# g_{tt} = -\alpha^2 + \beta^k \beta_k# g_{ti} = \beta_i# g_{ij} = \gamma_{ij}# Eq. 2.121 in B&SbetaSphorCartD = ixp.zerorank1()for i in range(DIM):for j in range(DIM):betaSphorCartD[i] += gammaSphorCartDD[i][j] * betaSphorCartU[j]# Now compute the beta contraction.beta2 = sp.sympify(0)for i in range(DIM):beta2 += betaSphorCartU[i] * betaSphorCartD[i]# Eq. 2.122 in B&Sg4SphorCartDD = ixp.zerorank2(DIM=4)g4SphorCartDD[0][0] = -alphaSphorCart ** 2 + beta2for i in range(DIM):g4SphorCartDD[i + 1][0] = g4SphorCartDD[0][i + 1] = betaSphorCartD[i]for i in range(DIM):for j in range(DIM):g4SphorCartDD[i + 1][j + 1] = gammaSphorCartDD[i][j]# Step 2.2: Construct \gamma_{mu nu} = g_{mu nu} + n_mu n_nu:n4SphorCartD = ixp.zerorank1(DIM=4)n4SphorCartD[0] = -alphaSphorCartgamma4SphorCartDD = ixp.zerorank2(DIM=4)for mu in range(4):for nu in range(4):gamma4SphorCartDD[mu][nu] = g4SphorCartDD[mu][nu] + n4SphorCartD[mu] * n4SphorCartD[nu]# Step 2.3: We now have all we need to construct the BSSN source# terms in the current basis (Spherical or Cartesian):# S_{ij} = \gamma_{i \mu} \gamma_{j \nu} T^{\mu \nu}# S_{i} = -\gamma_{i\mu} n_\nu T^{\mu\nu}# S = \gamma^{ij} S_{ij}# rho = n_\mu n_\nu T^{\mu\nu},SSphorCartDD = ixp.zerorank2()SSphorCartD = ixp.zerorank1()SSphorCart = sp.sympify(0)rhoSphorCart = sp.sympify(0)for i in range(DIM):for j in range(DIM):for mu in range(4):for nu in range(4):SSphorCartDD[i][j] += gamma4SphorCartDD[i + 1][mu] * gamma4SphorCartDD[j + 1][nu] * T4SphorCartUU[mu][nu]for i in range(DIM):for mu in range(4):for nu in range(4):SSphorCartD[i] += -gamma4SphorCartDD[i + 1][mu] * n4SphorCartD[nu] * T4SphorCartUU[mu][nu]gammaSphorCartUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaSphorCartDD)for i in range(DIM):for j in range(DIM):SSphorCart += gammaSphorCartUU[i][j] * SSphorCartDD[i][j]for mu in range(4):for nu in range(4):rhoSphorCart += n4SphorCartD[mu] * n4SphorCartD[nu] * T4SphorCartUU[mu][nu]# Step 3: Perform basis conversion to# Make sure that rfm.reference_metric() has been called.# We'll need the variables it defines throughout this module.if rfm.have_already_called_reference_metric_function == False:print("Error. Called Tmunu_Numerical_Spherical_or_Cartesian_to_BSSNCurvilinear() without")print(" first setting up reference metric, by calling rfm.reference_metric().")sys.exit(1)# Step 1: All input quantities are in terms of r,th,ph or x,y,z. We want them in terms# of xx0,xx1,xx2, so here we call sympify_integers__replace_rthph() to replace# r,th,ph or x,y,z, respectively, with the appropriate functions of xx0,xx1,xx2# as defined for this particular reference metric in reference_metric.py's# xxSph[] or xxCart[], respectively:r_th_ph_or_Cart_xyz_oID_xx = []if CoordType_in == "Spherical":r_th_ph_or_Cart_xyz_oID_xx = rfm.xxSphelif CoordType_in == "Cartesian":r_th_ph_or_Cart_xyz_oID_xx = rfm.xxCartelse:print("Error: Can only convert ADM Cartesian or Spherical initial data to BSSN Curvilinear coords.")sys.exit(1)# Next apply Jacobian transformations to convert into the (xx0,xx1,xx2) basis# alpha is a scalar, so no Jacobian transformation is necessary.alpha = alphaSphorCartJac_dUSphorCart_dDrfmUD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):Jac_dUSphorCart_dDrfmUD[i][j] = sp.diff(r_th_ph_or_Cart_xyz_oID_xx[i], rfm.xx[j])Jac_dUrfm_dDSphorCartUD, dummyDET = ixp.generic_matrix_inverter3x3(Jac_dUSphorCart_dDrfmUD)betaU = ixp.zerorank1()BU = ixp.zerorank1()gammaSphorCartDD = ixp.zerorank2()KDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):betaU[i] += Jac_dUrfm_dDSphorCartUD[i][j] * betaSphorCartU[j]BU[i] += Jac_dUrfm_dDSphorCartUD[i][j] * BSphorCartU[j]for k in range(DIM):for l in range(DIM):gammaSphorCartDD[i][j] += Jac_dUSphorCart_dDrfmUD[k][i] * Jac_dUSphorCart_dDrfmUD[l][j] * \gammaSphorCartDD[k][l]KDD[i][j] += Jac_dUSphorCart_dDrfmUD[k][i] * Jac_dUSphorCart_dDrfmUD[l][j] * KSphorCartDD[k][l]# Step 3: All ADM quantities were input into this function in the Spherical or Cartesian# basis, as functions of r,th,ph or x,y,z, respectively. In Steps 1 and 2 above,# we converted them to the xx0,xx1,xx2 basis, and as functions of xx0,xx1,xx2.# Here we convert ADM quantities to their BSSN Curvilinear counterparts:# Step 3.1: Convert ADM $\gamma_{ij}$ to BSSN $\bar{\gamma}_{ij}$:# We have (Eqs. 2 and 3 of [Ruchlin *et al.*](https://arxiv.org/pdf/1712.07658.pdf)):# \bar{\gamma}_{i j} = \left(\frac{\bar{\gamma}}{\gamma}\right)^{1/3} \gamma_{ij}.gammaSphorCartUU, gammaDET = ixp.symm_matrix_inverter3x3(gammaSphorCartDD)gammabarDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):gammabarDD[i][j] = (rfm.detgammahat / gammaDET) ** (sp.Rational(1, 3)) * gammaSphorCartDD[i][j]# Step 3.2: Convert the extrinsic curvature $K_{ij}$ to the trace-free extrinsic# curvature $\bar{A}_{ij}$, plus the trace of the extrinsic curvature $K$,# where (Eq. 3 of [Baumgarte *et al.*](https://arxiv.org/pdf/1211.6632.pdf)):# K = \gamma^{ij} K_{ij}, and# \bar{A}_{ij} &= \left(\frac{\bar{\gamma}}{\gamma}\right)^{1/3} \left(K_{ij} - \frac{1}{3} \gamma_{ij} K \right)trK = sp.sympify(0)for i in range(DIM):for j in range(DIM):trK += gammaSphorCartUU[i][j] * KDD[i][j]AbarDD = ixp.zerorank2()for i in range(DIM):for j in range(DIM):AbarDD[i][j] = (rfm.detgammahat / gammaDET) ** (sp.Rational(1, 3)) * (KDD[i][j] - sp.Rational(1, 3) * gammaSphorCartDD[i][j] * trK)# Step 3.3: Set the conformal factor variable $\texttt{cf}$, which is set# by the "BSSN_RHSs::EvolvedConformalFactor_cf" parameter. For example if# "EvolvedConformalFactor_cf" is set to "phi", we can use Eq. 3 of# [Ruchlin *et al.*](https://arxiv.org/pdf/1712.07658.pdf),# which in arbitrary coordinates is written:# \phi = \frac{1}{12} \log\left(\frac{\gamma}{\bar{\gamma}}\right).# Alternatively if "BSSN_RHSs::EvolvedConformalFactor_cf" is set to "chi", then# \chi = e^{-4 \phi} = \exp\left(-4 \frac{1}{12} \left(\frac{\gamma}{\bar{\gamma}}\right)\right)# = \exp\left(-\frac{1}{3} \log\left(\frac{\gamma}{\bar{\gamma}}\right)\right) = \left(\frac{\gamma}{\bar{\gamma}}\right)^{-1/3}.## Finally if "BSSN_RHSs::EvolvedConformalFactor_cf" is set to "W", then# W = e^{-2 \phi} = \exp\left(-2 \frac{1}{12} \log\left(\frac{\gamma}{\bar{\gamma}}\right)\right) =# \exp\left(-\frac{1}{6} \log\left(\frac{\gamma}{\bar{\gamma}}\right)\right) =# \left(\frac{\gamma}{\bar{\gamma}}\right)^{-1/6}.# First compute gammabarDET:gammabarUU, gammabarDET = ixp.symm_matrix_inverter3x3(gammabarDD)cf = sp.sympify(0)if par.parval_from_str("EvolvedConformalFactor_cf") == "phi":cf = sp.Rational(1, 12) * sp.log(gammaDET / gammabarDET)elif par.parval_from_str("EvolvedConformalFactor_cf") == "chi":cf = (gammaDET / gammabarDET) ** (-sp.Rational(1, 3))elif par.parval_from_str("EvolvedConformalFactor_cf") == "W":cf = (gammaDET / gammabarDET) ** (-sp.Rational(1, 6))else:print("Error EvolvedConformalFactor_cf type = \"" + par.parval_from_str("EvolvedConformalFactor_cf") + "\" unknown.")sys.exit(1)# Step 4: Rescale tensorial quantities according to the prescription described in# the [BSSN in curvilinear coordinates tutorial module](Tutorial-BSSNCurvilinear.ipynb)# (also [Ruchlin *et al.*](https://arxiv.org/pdf/1712.07658.pdf)):## h_{ij} &= (\bar{\gamma}_{ij} - \hat{\gamma}_{ij})/\text{ReDD[i][j]}\\# a_{ij} &= \bar{A}_{ij}/\text{ReDD[i][j]}\\# \lambda^i &= \bar{\Lambda}^i/\text{ReU[i]}\\# \mathcal{V}^i &= \beta^i/\text{ReU[i]}\\# \mathcal{B}^i &= B^i/\text{ReU[i]}\\hDD = ixp.zerorank2()aDD = ixp.zerorank2()vetU = ixp.zerorank1()betU = ixp.zerorank1()for i in range(DIM):vetU[i] = betaU[i] / rfm.ReU[i]betU[i] = BU[i] / rfm.ReU[i]for j in range(DIM):hDD[i][j] = (gammabarDD[i][j] - rfm.ghatDD[i][j]) / rfm.ReDD[i][j]aDD[i][j] = AbarDD[i][j] / rfm.ReDD[i][j]# Step 5: Output all ADM-to-BSSN expressions to a C function. This function# must first call the ID_ADM_SphorCart() defined above. Using these# Spherical or Cartesian data, it sets up all quantities needed for# BSSNCurvilinear initial data, *except* $\lambda^i$, which must be# computed from numerical data using finite-difference derivatives.with open("BSSN/ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs.h", "w") as file:file.write("void ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs(const REAL xx0xx1xx2[3],")if pointer_to_ID_inputs == True:file.write("ID_inputs *other_inputs,")else:file.write("ID_inputs other_inputs,")file.write("""REAL *hDD00,REAL *hDD01,REAL *hDD02,REAL *hDD11,REAL *hDD12,REAL *hDD22,REAL *aDD00,REAL *aDD01,REAL *aDD02,REAL *aDD11,REAL *aDD12,REAL *aDD22,REAL *trK,REAL *vetU0,REAL *vetU1,REAL *vetU2,REAL *betU0,REAL *betU1,REAL *betU2,REAL *alpha, REAL *cf) {REAL gammaSphorCartDD00,gammaSphorCartDD01,gammaSphorCartDD02,gammaSphorCartDD11,gammaSphorCartDD12,gammaSphorCartDD22;REAL KSphorCartDD00,KSphorCartDD01,KSphorCartDD02,KSphorCartDD11,KSphorCartDD12,KSphorCartDD22;REAL alphaSphorCart,betaSphorCartU0,betaSphorCartU1,betaSphorCartU2;REAL BSphorCartU0,BSphorCartU1,BSphorCartU2;const REAL xx0 = xx0xx1xx2[0];const REAL xx1 = xx0xx1xx2[1];const REAL xx2 = xx0xx1xx2[2];REAL xyz_or_rthph[3];\n""")outCparams = "preindent=1,outCfileaccess=a,outCverbose=False,includebraces=False"outputC(r_th_ph_or_Cart_xyz_oID_xx[0:3], ["xyz_or_rthph[0]", "xyz_or_rthph[1]", "xyz_or_rthph[2]"],"BSSN/ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs.h", outCparams + ",CSE_enable=False")with open("BSSN/ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs.h", "a") as file:file.write(" "+ADM_input_function_name+"""(xyz_or_rthph, other_inputs,&gammaSphorCartDD00,&gammaSphorCartDD01,&gammaSphorCartDD02,&gammaSphorCartDD11,&gammaSphorCartDD12,&gammaSphorCartDD22,&KSphorCartDD00,&KSphorCartDD01,&KSphorCartDD02,&KSphorCartDD11,&KSphorCartDD12,&KSphorCartDD22,&alphaSphorCart,&betaSphorCartU0,&betaSphorCartU1,&betaSphorCartU2,&BSphorCartU0,&BSphorCartU1,&BSphorCartU2);// Next compute all rescaled BSSN curvilinear quantities:\n""")outCparams = "preindent=1,outCfileaccess=a,outCverbose=False,includebraces=False"outputC([hDD[0][0], hDD[0][1], hDD[0][2], hDD[1][1], hDD[1][2], hDD[2][2],aDD[0][0], aDD[0][1], aDD[0][2], aDD[1][1], aDD[1][2], aDD[2][2],trK, vetU[0], vetU[1], vetU[2], betU[0], betU[1], betU[2],alpha, cf],["*hDD00", "*hDD01", "*hDD02", "*hDD11", "*hDD12", "*hDD22","*aDD00", "*aDD01", "*aDD02", "*aDD11", "*aDD12", "*aDD22","*trK", "*vetU0", "*vetU1", "*vetU2", "*betU0", "*betU1", "*betU2","*alpha", "*cf"],"BSSN/ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs.h", params=outCparams)with open("BSSN/ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs.h", "a") as file:file.write("}\n")# Step 5.A: Output the driver function for the above# function ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs()# Next write the driver function for ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs():with open("BSSN/ID_BSSN__ALL_BUT_LAMBDAs.h", "w") as file:file.write("void ID_BSSN__ALL_BUT_LAMBDAs(const int Nxx_plus_2NGHOSTS[3],REAL *xx[3],")if pointer_to_ID_inputs == True:file.write("ID_inputs *other_inputs,")else:file.write("ID_inputs other_inputs,")file.write("REAL *in_gfs) {\n")file.write(lp.loop(["i2", "i1", "i0"], ["0", "0", "0"],["Nxx_plus_2NGHOSTS[2]", "Nxx_plus_2NGHOSTS[1]", "Nxx_plus_2NGHOSTS[0]"],["1", "1", "1"], ["#pragma omp parallel for"," const REAL xx2 = xx[2][i2];"," const REAL xx1 = xx[1][i1];"], "","""const REAL xx0 = xx[0][i0];const int idx = IDX3(i0,i1,i2);const REAL xx0xx1xx2[3] = {xx0,xx1,xx2};ID_ADM_xx0xx1xx2_to_BSSN_xx0xx1xx2__ALL_BUT_LAMBDAs(xx0xx1xx2,other_inputs,&in_gfs[IDX4pt(HDD00GF,idx)],&in_gfs[IDX4pt(HDD01GF,idx)],&in_gfs[IDX4pt(HDD02GF,idx)],&in_gfs[IDX4pt(HDD11GF,idx)],&in_gfs[IDX4pt(HDD12GF,idx)],&in_gfs[IDX4pt(HDD22GF,idx)],&in_gfs[IDX4pt(ADD00GF,idx)],&in_gfs[IDX4pt(ADD01GF,idx)],&in_gfs[IDX4pt(ADD02GF,idx)],&in_gfs[IDX4pt(ADD11GF,idx)],&in_gfs[IDX4pt(ADD12GF,idx)],&in_gfs[IDX4pt(ADD22GF,idx)],&in_gfs[IDX4pt(TRKGF,idx)],&in_gfs[IDX4pt(VETU0GF,idx)],&in_gfs[IDX4pt(VETU1GF,idx)],&in_gfs[IDX4pt(VETU2GF,idx)],&in_gfs[IDX4pt(BETU0GF,idx)],&in_gfs[IDX4pt(BETU1GF,idx)],&in_gfs[IDX4pt(BETU2GF,idx)],&in_gfs[IDX4pt(ALPHAGF,idx)],&in_gfs[IDX4pt(CFGF,idx)]);"""))file.write("}\n")# Step 6: Compute $\bar{\Lambda}^i$ (Eqs. 4 and 5 of# [Baumgarte *et al.*](https://arxiv.org/pdf/1211.6632.pdf)),# from finite-difference derivatives of rescaled metric# quantities $h_{ij}$:# \bar{\Lambda}^i = \bar{\gamma}^{jk}\left(\bar{\Gamma}^i_{jk} - \hat{\Gamma}^i_{jk}\right).# The reference_metric.py module provides us with analytic expressions for# $\hat{\Gamma}^i_{jk}$, so here we need only compute# finite-difference expressions for $\bar{\Gamma}^i_{jk}$, based on# the values for $h_{ij}$ provided in the initial data. Once# $\bar{\Lambda}^i$ has been computed, we apply the usual rescaling# procedure:# \lambda^i = \bar{\Lambda}^i/\text{ReU[i]},# and then output the result to a C file using the NRPy+# finite-difference C output routine.# We will need all BSSN gridfunctions to be defined, as well as# expressions for gammabarDD_dD in terms of exact derivatives of# the rescaling matrix and finite-difference derivatives of# hDD's.gammabarDD = bssnrhs.gammabarDDgammabarUU, gammabarDET = ixp.symm_matrix_inverter3x3(gammabarDD)gammabarDD_dD = bssnrhs.gammabarDD_dD# Next compute Christoffel symbols \bar{\Gamma}^i_{jk}:GammabarUDD = ixp.zerorank3()for i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):GammabarUDD[i][j][k] += sp.Rational(1, 2) * gammabarUU[i][l] * (gammabarDD_dD[l][j][k] +gammabarDD_dD[l][k][j] -gammabarDD_dD[j][k][l])# Next evaluate \bar{\Lambda}^i, based on GammabarUDD above and GammahatUDD# (from the reference metric):LambdabarU = ixp.zerorank1()for i in range(DIM):for j in range(DIM):for k in range(DIM):LambdabarU[i] += gammabarUU[j][k] * (GammabarUDD[i][j][k] - rfm.GammahatUDD[i][j][k])# Finally apply rescaling:# lambda^i = Lambdabar^i/\text{ReU[i]}lambdaU = ixp.zerorank1()for i in range(DIM):lambdaU[i] = LambdabarU[i] / rfm.ReU[i]outCparams = "preindent=1,outCfileaccess=a,outCverbose=False,includebraces=False"lambdaU_expressions = [lhrh(lhs=gri.gfaccess("in_gfs", "lambdaU0"), rhs=lambdaU[0]),lhrh(lhs=gri.gfaccess("in_gfs", "lambdaU1"), rhs=lambdaU[1]),lhrh(lhs=gri.gfaccess("in_gfs", "lambdaU2"), rhs=lambdaU[2])]lambdaU_expressions_FDout = fin.FD_outputC("returnstring", lambdaU_expressions, outCparams)with open("BSSN/ID_BSSN_lambdas.h", "w") as file:file.write("""void ID_BSSN_lambdas(const int Nxx[3],const int Nxx_plus_2NGHOSTS[3],REAL *xx[3],const REAL dxx[3],REAL *in_gfs) {\n""")file.write(lp.loop(["i2", "i1", "i0"], ["NGHOSTS", "NGHOSTS", "NGHOSTS"],["NGHOSTS+Nxx[2]", "NGHOSTS+Nxx[1]", "NGHOSTS+Nxx[0]"],["1", "1", "1"], ["const REAL invdx0 = 1.0/dxx[0];\n" +"const REAL invdx1 = 1.0/dxx[1];\n" +"const REAL invdx2 = 1.0/dxx[2];\n" +"#pragma omp parallel for"," const REAL xx2 = xx[2][i2];"," const REAL xx1 = xx[1][i1];"], "","const REAL xx0 = xx[0][i0];\n" + lambdaU_expressions_FDout))file.write("}\n")
# This module sets up UIUC Black Hole initial data in terms of# the variables used in BSSN_RHSs.py# Authors: Zachariah B. Etienne, zachetie **at** gmail **dot** com# Terrence Pierre Jacques, terrencepierrej **at** gmail **dot** com# Ian Ruchlin# ## This module sets up initial data for a merging black hole system in spherical coordinates. We can convert from spherical to any coordinate system defined in [reference_metric.py](../edit/reference_metric.py) (e.g., SinhSpherical, Cylindrical, Cartesian, etc.) using the [Exact ADM Spherical-to-BSSNCurvilinear converter module](Tutorial-ADM_Initial_Data-Converting_Exact_ADM_Spherical_or_Cartesian_to_BSSNCurvilinear.ipynb)## ### Here we set up UIUC Black Hole initial data ([Liu, Etienne, & Shapiro, PRD 80 121503, 2009](https://arxiv.org/abs/1001.4077)):## UIUC black holes have the advantage of finite coordinate radius in the maximal spin limit. It is therefore excellent for studying very highly spinning black holes. This module sets the UIUC black hole at the origin.## **Inputs for initial data**:## * The black hole mass $M$.# * The dimensionless spin parameter $\chi = a/M$## **Additional variables needed for spacetime evolution**:## * Desired coordinate system# * Desired initial lapse $\alpha$ and shift $\beta^i$. We will choose our gauge conditions as $\alpha=1$ and $\beta^i=B^i=0$. $\alpha = \psi^{-2}$ will yield much better behavior, but the conformal factor $\psi$ depends on the desired *destination* coordinate system (which may not be spherical coordinates).# Step P0: Load needed modulesimport sympy as sp # SymPy: The Python computer algebra package upon which NRPy+ dependsimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport BSSN.ADM_Exact_Spherical_or_Cartesian_to_BSSNCurvilinear as AtoBthismodule = __name__# The UIUC initial data represent a Kerr black hole with mass M# and dimensionless spin chi in UIUC quasi-isotropic coordinates,# see https://arxiv.org/abs/1001.4077# Input parameters:M, chi = par.Cparameters("REAL", thismodule, ["M", "chi"], [1.0, 0.99])# ComputeADMGlobalsOnly == True will only set up the ADM global quantities.# == False will perform the full ADM SphorCart->BSSN Curvi conversiondef UIUCBlackHole(ComputeADMGlobalsOnly = False):global Sph_r_th_ph,r,th,ph, gammaSphDD, KSphDD, alphaSph, betaSphU, BSphU# All gridfunctions will be written in terms of spherical coordinates (r, th, ph):r,th,ph = sp.symbols('r th ph', real=True)# Step 0: Set spatial dimension (must be 3 for BSSN)DIM = 3par.set_parval_from_str("grid::DIM",DIM)# Step 1: Set psi, the conformal factor:# Spin per unit massa = M*chi# Defined under equation 1 in Liu, Etienne, & Shapiro (2009) https://arxiv.org/pdf/1001.4077.pdf# Boyer - Lindquist outer horizonrp = M + sp.sqrt(M**2 - a**2)# Boyer - Lindquist inner horizonrm = M - sp.sqrt(M**2 - a**2)# Boyer - Lindquist radius in terms of UIUC radius# Eq. 11# r_{BL} = r * ( 1 + r_+ / 4r )^2rBL = r*(1 + rp / (4*r))**2# Expressions found below Eq. 2# Sigma = r_{BL}^2 + a^2 cos^2 thetaSIG = rBL**2 + a**2*sp.cos(th)**2# Delta = r_{BL}^2 - 2Mr_{BL} + a^2DEL = rBL**2 - 2*M*rBL + a**2# A = (r_{BL}^2 + a^2)^2 - Delta a^2 sin^2 thetaAA = (rBL**2 + a**2)**2 - DEL*a**2*sp.sin(th)**2# *** The ADM 3-metric in spherical basis ***gammaSphDD = ixp.zerorank2()# Declare the nonzero components of the 3-metric# (Eq. 13 of Liu, Etienne, & Shapiro, https://arxiv.org/pdf/1001.4077.pdf):# ds^2 = Sigma (r + r_+/4)^2 / ( r^3 (r_{BL} - r_- ) * dr^2 +# Sigma d theta^2 + (A sin^2 theta) / Sigma * d\phi^2gammaSphDD[0][0] = ((SIG*(r + rp/4)**2)/(r**3*(rBL - rm)))gammaSphDD[1][1] = SIGgammaSphDD[2][2] = AA/SIG*sp.sin(th)**2# *** The physical trace-free extrinsic curvature in spherical basis ***# Nonzero components of the extrinsic curvature K, given by# Eq. 14 of Liu, Etienne, & Shapiro, https://arxiv.org/pdf/1001.4077.pdf:KSphDD = ixp.zerorank2()# K_{r phi} = K_{phi r} = (Ma sin^2 theta) / (Sigma sqrt{A Sigma}) *# [3r^4_{BL} + 2a^2 r^2_{BL} - a^4 - a^2 (r^2_{BL} - a^2) sin^2 theta] *# (1 + r_+ / 4r) (1 / sqrt{r(r_{BL} - r_-)})KSphDD[0][2] = KSphDD[2][0] = (M*a*sp.sin(th)**2)/(SIG*sp.sqrt(AA*SIG))*\(3*rBL**4 + 2*a**2*rBL**2 - a**4- a**2*(rBL**2 - a**2)*\sp.sin(th)**2)*(1 + rp/(4*r))*1/sp.sqrt(r*(rBL - rm))# Components of the extrinsic curvature K, given by# Eq. 15 of Liu, Etienne, & Shapiro, https://arxiv.org/pdf/1001.4077.pdf:# K_{theta phi} = K_{phi theta} = -(2a^3 Mr_{BL} cos theta sin^3 theta) /# (Sigma sqrt{A Sigma}) x (r - r_+ / 4) sqrt{(r_{BL} - r_-) / r }KSphDD[1][2] = KSphDD[2][1] = -((2*a**3*M*rBL*sp.cos(th)*sp.sin(th)**3)/ \(SIG*sp.sqrt(AA*SIG)))*(r - rp/4)*sp.sqrt((rBL - rm)/r)alphaSph = sp.sympify(1) # We generally choose alpha = 1/psi**2 (psi = BSSN conformal factor) for these initial databetaSphU = ixp.zerorank1() # We generally choose \beta^i = 0 for these initial dataBSphU = ixp.zerorank1() # We generally choose B^i = 0 for these initial dataif ComputeADMGlobalsOnly == True:return# Validated against original SENR: KSphDD[0][2], KSphDD[1][2], gammaSphDD[2][2], gammaSphDD[0][0], gammaSphDD[1][1]#print(sp.mathematica_code(gammaSphDD[1][1]))Sph_r_th_ph = [r,th,ph]cf,hDD,lambdaU,aDD,trK,alpha,vetU,betU = \AtoB.Convert_Spherical_or_Cartesian_ADM_to_BSSN_curvilinear("Spherical", Sph_r_th_ph,gammaSphDD,KSphDD,alphaSph,betaSphU,BSphU)import BSSN.BSSN_ID_function_string as bIDfglobal returnfunctionreturnfunction = bIDf.BSSN_ID_function_string(cf, hDD, lambdaU, aDD, trK, alpha, vetU, betU)
from UnitTesting.create_test import create_testdef test_ADMBSSN_tofrom_4metric():module = 'BSSN.ADMBSSN_tofrom_4metric'module_name = 'ADMBSSN_tofrom_4metric'function_and_global_dict = {'g4DD_ito_BSSN_or_ADM(\"ADM\")': ['g4DD'],'g4UU_ito_BSSN_or_ADM(\"ADM\")': ['g4UU'],'BSSN_or_ADM_ito_g4DD(\"ADM\")': ['gammaDD', 'betaU', 'alpha']}create_test(module, module_name, function_and_global_dict)def test_ADMBSSN_tofrom_4metric_BSSN():module = 'BSSN.ADMBSSN_tofrom_4metric'module_name = 'ADMBSSN_tofrom_4metric'function_and_global_dict = {'g4DD_ito_BSSN_or_ADM(\"BSSN\")': ['g4DD'],'g4UU_ito_BSSN_or_ADM(\"BSSN\")': ['g4UU'],'BSSN_or_ADM_ito_g4DD(\"BSSN\")': ['hDD', 'cf', 'vetU', 'alpha']}rfm_init_string = '''import BSSN.BSSN_quantities as Bqimport reference_metric as rfmrfm.reference_metric()rfm.ref_metric__hatted_quantities()'''initialization_string_dict = {'g4DD_ito_BSSN_or_ADM(\"BSSN\")': rfm_init_string,'g4UU_ito_BSSN_or_ADM(\"BSSN\")': rfm_init_string,'BSSN_or_ADM_ito_g4DD(\"BSSN\")': rfm_init_string}create_test(module, module_name, function_and_global_dict, logging_level='INFO', initialization_string_dict=initialization_string_dict)def test_BSSN_stress_energy_source_terms():module = 'BSSN.BSSN_stress_energy_source_terms'module_name = 'BSSN_stress_energy_source_terms'function_and_global_dict = {'stress_energy_source_terms_ito_T4UU_and_ADM_or_BSSN_metricvars(\"ADM\")': ['SDD','SD','S','rho'],'stress_energy_source_terms_ito_T4UU_and_ADM_or_BSSN_metricvars(\"BSSN\")': ['SDD','SD','S','rho'],'BSSN_source_terms_for_BSSN_RHSs()': ['sourceterm_trK_rhs', 'sourceterm_a_rhsDD', 'sourceterm_lambda_rhsU', 'sourceterm_Lambdabar_rhsU']}rfm_init_string = '''import BSSN.BSSN_quantities as Bqimport reference_metric as rfmrfm.reference_metric()rfm.ref_metric__hatted_quantities()'''initialization_string_dict = {'stress_energy_source_terms_ito_T4UU_and_ADM_or_BSSN_metricvars(\"ADM\")': rfm_init_string,'stress_energy_source_terms_ito_T4UU_and_ADM_or_BSSN_metricvars(\"BSSN\")': rfm_init_string,'BSSN_source_terms_for_BSSN_RHSs()': rfm_init_string}create_test(module, module_name, function_and_global_dict, logging_level='INFO', initialization_string_dict=initialization_string_dict)def test_ADM_in_terms_of_BSSN():module = 'BSSN.ADM_in_terms_of_BSSN'module_name = 'ADM_in_terms_of_BSSN'function_and_global_dict = {'ADM_in_terms_of_BSSN()': ['gammaDD', 'gammaDDdD', 'gammaDDdDD', 'gammaUU', 'detgamma','GammaUDD', 'KDD', 'KDDdD']}create_test(module, module_name, function_and_global_dict)def test_BSSN_in_terms_of_ADM():module = 'BSSN.BSSN_in_terms_of_ADM'module_name = 'BSSN_in_terms_of_ADM'function_and_global_dict = {'gammabarDD_hDD(gammaDD=None)': ['gammabarDD','hDD'],'trK_AbarDD_aDD(gammaDD=None,KDD=None)': ['trK','AbarDD','aDD'],'LambdabarU_lambdaU__exact_gammaDD(gammaDD=None)': ['LambdabarU','lambdaU'],'cf_from_gammaDD(gammaDD=None)': ['cf'],'betU_vetU(betaU=None,BU=None)': ['vetU','betU']}rfm_init_string = '''import BSSN.BSSN_quantities as Bqimport reference_metric as rfmrfm.reference_metric()rfm.ref_metric__hatted_quantities()'''initialization_string_dict = {'gammabarDD_hDD(gammaDD=None)': rfm_init_string,'trK_AbarDD_aDD(gammaDD=None,KDD=None)': rfm_init_string,'LambdabarU_lambdaU__exact_gammaDD(gammaDD=None)': rfm_init_string,'cf_from_gammaDD(gammaDD=None)': rfm_init_string,'betU_vetU(betaU=None,BU=None)': rfm_init_string}create_test(module, module_name, function_and_global_dict, logging_level='INFO', initialization_string_dict=initialization_string_dict)def test_BrillLindquist():module = 'BSSN.BrillLindquist'module_name = 'BrillLindquist'function_and_global_dict = {'BrillLindquist(ComputeADMGlobalsOnly=True)': ['alphaCart', 'betaCartU', 'BCartU','gammaCartDD', 'KCartDD']}create_test(module, module_name, function_and_global_dict)def test_constraints():module = 'BSSN.BSSN_constraints'module_name = 'BSSN_constraints'function_and_global_dict = {'BSSN_constraints()': ['H', 'MU']}create_test(module, module_name, function_and_global_dict)def test_Psi4():module = 'BSSN.Psi4'module_name = 'Psi4'function_and_global_dict = {'Psi4(specify_tetrad=False)': ['psi4_re_pt', 'psi4_im_pt']}create_test(module, module_name, function_and_global_dict)def test_Psi4_tetrads():module = 'BSSN.Psi4_tetrads'module_name = 'Psi4_tetrads'function_and_global_dict = {'Psi4_tetrads()': ['l4U', 'n4U', 'mre4U', 'mim4U']}create_test(module, module_name, function_and_global_dict)def test_quantities():module = 'BSSN.BSSN_quantities'module_name = 'BSSN_quantities'function_and_global_dict = {'declare_BSSN_gridfunctions_if_not_declared_already()': ['hDD', 'aDD', 'lambdaU', 'vetU', 'betU', 'trK', 'cf', 'alpha'],'BSSN_basic_tensors()': ['gammabarDD', 'AbarDD', 'LambdabarU', 'betaU', 'BU'],'gammabar__inverse_and_derivs()': ['gammabarUU', 'gammabarDD_dD', 'gammabarDD_dupD', 'gammabarDD_dDD', 'GammabarUDD'],'detgammabar_and_derivs()': ['detgammabar', 'detgammabar_dD', 'detgammabar_dDD'],'AbarUU_AbarUD_trAbar_AbarDD_dD()': ['AbarUU', 'AbarUD', 'trAbar', 'AbarDD_dD', 'AbarDD_dupD'],'RicciBar__gammabarDD_dHatD__DGammaUDD__DGammaU()': ['RbarDD', 'DGammaUDD', 'gammabarDD_dHatD', 'DGammaU'],'betaU_derivs()': ['betaU_dD', 'betaU_dupD', 'betaU_dDD'],'phi_and_derivs()': ['phi_dD', 'phi_dupD', 'phi_dDD', 'exp_m4phi', 'phi_dBarD', 'phi_dBarDD']}rfm_init_string = '''import reference_metric as rfmrfm.reference_metric()rfm.ref_metric__hatted_quantities()'''initialization_string_dict = {'BSSN_basic_tensors()': rfm_init_string,'gammabar__inverse_and_derivs()': rfm_init_string,'detgammabar_and_derivs()': rfm_init_string,'AbarUU_AbarUD_trAbar_AbarDD_dD()': rfm_init_string,'RicciBar__gammabarDD_dHatD__DGammaUDD__DGammaU()': rfm_init_string,'betaU_derivs()': rfm_init_string,'phi_and_derivs()': rfm_init_string}create_test(module, module_name, function_and_global_dict, logging_level='INFO', initialization_string_dict=initialization_string_dict)def test_RHSs():module = 'BSSN.BSSN_RHSs'module_name = 'BSSN_RHSs'function_and_global_dict = {'BSSN_RHSs()': ['cf_rhs', 'trK_rhs', 'lambda_rhsU', 'a_rhsDD', 'h_rhsDD']}create_test(module, module_name, function_and_global_dict)def test_gauge_RHSs():module = 'BSSN.BSSN_gauge_RHSs'module_name = 'gauge_RHSs'function_and_global_dict = {'BSSN_gauge_RHSs()': ['alpha_rhs', 'bet_rhsU', 'vet_rhsU']}bssn_rhs_init_string = '''import BSSN.BSSN_RHSs as rhsrhs.BSSN_RHSs()'''initialization_string_dict = { 'BSSN_gauge_RHSs()': bssn_rhs_init_string }create_test(module, module_name, function_and_global_dict, initialization_string_dict=initialization_string_dict)def test_ShiftedKerrSchild():module = 'BSSN.ShiftedKerrSchild'module_name = 'ShiftedKerrSchild'function_and_global_dict = {'ShiftedKerrSchild(ComputeADMGlobalsOnly=True)': ['alphaSph', 'betaSphU', 'BSphU','gammaSphDD', 'KSphDD']}create_test(module, module_name, function_and_global_dict)def test_StaticTrumpet():module = 'BSSN.StaticTrumpet'module_name = 'StaticTrumpet'function_and_global_dict = {'StaticTrumpet(ComputeADMGlobalsOnly=True)': ['alphaSph', 'betaSphU', 'BSphU','gammaSphDD', 'KSphDD']}create_test(module, module_name, function_and_global_dict)def test_T4UUmunu_vars():module = 'BSSN.BSSN_T4UUmunu_vars'module_name = 'T4UUmunu_vars'function_and_global_dict = {'define_BSSN_T4UUmunu_rescaled_source_terms()': ['rho', 'S', 'sD', 'sDD']}create_test(module, module_name, function_and_global_dict)def test_UIUCBlackHole():module = 'BSSN.UIUCBlackHole'module_name = 'UIUCBlackHole'function_and_global_dict = {'UIUCBlackHole(ComputeADMGlobalsOnly=True)': ['alphaSph', 'betaSphU', 'BSphU','gammaSphDD', 'KSphDD']}create_test(module, module_name, function_and_global_dict)if __name__ == '__main__':import sysif len(sys.argv) <= 3:failed_functions = []for fun in dir():if fun[0:5] == 'test_':print('\nTesting ' + str(fun) + '...\n')try:exec(fun + '()')except SystemExit:failed_functions.append(fun)if failed_functions != []:import sys, oswith open(os.path.join('UnitTesting', 'failed_tests.txt'), 'a') as file:for function in failed_functions:file.write(sys.argv[0] + ': ' + str(function) + '\n')exit(1)else:globals()[sys.argv[4]]()
from mpmath import mpf, mp, mpcfrom UnitTesting.standard_constants import precisionmp.dps = precisiontrusted_values_dict = {}# Generated on: 2019-08-09trusted_values_dict['ADM_in_terms_of_BSSN__ADM_in_terms_of_BSSN__globals'] = {'gammaDD[0][0]': mpf('8.84684305820134422150597858207921'), 'gammaDD[0][1]': mpf('3.350018689599008046165002833204'), 'gammaDD[0][2]': mpf('0.194795767378908960688399288371257'), 'gammaDD[1][0]': mpf('3.350018689599008046165002833204'), 'gammaDD[1][1]': mpf('1.92752387150314689143948714387062'), 'gammaDD[1][2]': mpf('0.617514215490828029162196536408385'), 'gammaDD[2][0]': mpf('0.194795767378908960688399288371257'), 'gammaDD[2][1]': mpf('0.617514215490828029162196536408385'), 'gammaDD[2][2]': mpf('0.440219517017598275317485123438443'), 'gammaDDdD[0][0][0]': mpf('-39.2181788667717063214934687853284'), 'gammaDDdD[0][0][1]': mpf('-43.5347678242827125179031665798782'), 'gammaDDdD[0][0][2]': mpf('-43.5448629253377323761214222661368'), 'gammaDDdD[0][1][0]': mpf('-3.82269337582904325002653701794443'), 'gammaDDdD[0][1][1]': mpf('-15.8371132982064951265352981022794'), 'gammaDDdD[0][1][2]': mpf('-13.0007465813467278947970267824292'), 'gammaDDdD[0][2][0]': mpf('-0.218013883809053119477949934634148'), 'gammaDDdD[0][2][1]': mpf('0.785829885135145904482804685445781'), 'gammaDDdD[0][2][2]': mpf('-0.581351677673311207621301361731265'), 'gammaDDdD[1][0][0]': mpf('-3.82269337582904325002653701794443'), 'gammaDDdD[1][0][1]': mpf('-15.8371132982064951265352981022794'), 'gammaDDdD[1][0][2]': mpf('-13.0007465813467278947970267824292'), 'gammaDDdD[1][1][0]': mpf('1.02077344056659026570129696849467'), 'gammaDDdD[1][1][1]': mpf('-9.20007419968800686893912169288767'), 'gammaDDdD[1][1][2]': mpf('-8.15422339233949609213151393845906'), 'gammaDDdD[1][2][0]': mpf('0.357104131772599372488808535542396'), 'gammaDDdD[1][2][1]': mpf('-1.65079628886562588602648974576529'), 'gammaDDdD[1][2][2]': mpf('-2.86344337379037596725739579107855'), 'gammaDDdD[2][0][0]': mpf('-0.218013883809053119477949934634148'), 'gammaDDdD[2][0][1]': mpf('0.785829885135145904482804685445781'), 'gammaDDdD[2][0][2]': mpf('-0.581351677673311207621301361731265'), 'gammaDDdD[2][1][0]': mpf('0.357104131772599372488808535542396'), 'gammaDDdD[2][1][1]': mpf('-1.65079628886562588602648974576529'), 'gammaDDdD[2][1][2]': mpf('-2.86344337379037596725739579107855'), 'gammaDDdD[2][2][0]': mpf('0.195001221087943638085807308270354'), 'gammaDDdD[2][2][1]': mpf('-0.410311324085430408983791626770926'), 'gammaDDdD[2][2][2]': mpf('-1.92276041454685421458861940256278'), 'gammaDDdDD[0][0][0][0]': mpf('225.398957517527156513326956764229'), 'gammaDDdDD[0][0][0][1]': mpf('288.140070211252996184124719294385'), 'gammaDDdDD[0][0][0][2]': mpf('281.623967129510091655495816474147'), 'gammaDDdDD[0][0][1][0]': mpf('288.140070211252996184124719294385'), 'gammaDDdDD[0][0][1][1]': mpf('337.948619849001134211864646627346'), 'gammaDDdDD[0][0][1][2]': mpf('322.481152355898457651315654723053'), 'gammaDDdDD[0][0][2][0]': mpf('281.623967129510091655495816474147'), 'gammaDDdDD[0][0][2][1]': mpf('322.481152355898457651315654723053'), 'gammaDDdDD[0][0][2][2]': mpf('293.564334950019576720032123379472'), 'gammaDDdDD[0][1][0][0]': mpf('3.64051177720082509234617335007875'), 'gammaDDdDD[0][1][0][1]': mpf('50.4627675517741918630578752181752'), 'gammaDDdDD[0][1][0][2]': mpf('46.1357119642924033983593968867937'), 'gammaDDdDD[0][1][1][0]': mpf('50.4627675517741918630578752181752'), 'gammaDDdDD[0][1][1][1]': mpf('119.02655264345724986788778186216'), 'gammaDDdDD[0][1][1][2]': mpf('100.654984059470512047205484497294'), 'gammaDDdDD[0][1][2][0]': mpf('46.1357119642924033983593968867937'), 'gammaDDdDD[0][1][2][1]': mpf('100.654984059470512047205484497294'), 'gammaDDdDD[0][1][2][2]': mpf('77.760445818040255191531604261198'), 'gammaDDdDD[0][2][0][0]': mpf('0.375532488603708956700281774274923'), 'gammaDDdDD[0][2][0][1]': mpf('0.678340756727625343658227489853017'), 'gammaDDdDD[0][2][0][2]': mpf('2.78948049995862477035881653480892'), 'gammaDDdDD[0][2][1][0]': mpf('0.678340756727625343658227489853017'), 'gammaDDdDD[0][2][1][1]': mpf('-6.12617437316042868416067368255866'), 'gammaDDdDD[0][2][1][2]': mpf('-1.75847734950653146320336447142805'), 'gammaDDdDD[0][2][2][0]': mpf('2.78948049995862477035881653480892'), 'gammaDDdDD[0][2][2][1]': mpf('-1.75847734950653146320336447142805'), 'gammaDDdDD[0][2][2][2]': mpf('2.73521309266304236084886214346027'), 'gammaDDdDD[1][0][0][0]': mpf('3.64051177720082509234617335007875'), 'gammaDDdDD[1][0][0][1]': mpf('50.4627675517741918630578752181752'), 'gammaDDdDD[1][0][0][2]': mpf('46.1357119642924033983593968867937'), 'gammaDDdDD[1][0][1][0]': mpf('50.4627675517741918630578752181752'), 'gammaDDdDD[1][0][1][1]': mpf('119.02655264345724986788778186216'), 'gammaDDdDD[1][0][1][2]': mpf('100.654984059470512047205484497294'), 'gammaDDdDD[1][0][2][0]': mpf('46.1357119642924033983593968867937'), 'gammaDDdDD[1][0][2][1]': mpf('100.654984059470512047205484497294'), 'gammaDDdDD[1][0][2][2]': mpf('77.760445818040255191531604261198'), 'gammaDDdDD[1][1][0][0]': mpf('-9.92106187379982562603610831325235'), 'gammaDDdDD[1][1][0][1]': mpf('15.825454310362637536048355653535'), 'gammaDDdDD[1][1][0][2]': mpf('14.4039518436611112501034205835319'), 'gammaDDdDD[1][1][1][0]': mpf('15.825454310362637536048355653535'), 'gammaDDdDD[1][1][1][1]': mpf('70.6517225129821789456736189152217'), 'gammaDDdDD[1][1][1][2]': mpf('61.9035794546980075683100782914809'), 'gammaDDdDD[1][1][2][0]': mpf('14.4039518436611112501034205835319'), 'gammaDDdDD[1][1][2][1]': mpf('61.9035794546980075683100782914809'), 'gammaDDdDD[1][1][2][2]': mpf('50.8579841651123380242828623654651'), 'gammaDDdDD[1][2][0][0]': mpf('-3.34089527571068728373797749836677'), 'gammaDDdDD[1][2][0][1]': mpf('5.5335349427183318693808176585407'), 'gammaDDdDD[1][2][0][2]': mpf('4.51408779818567722405331676792284'), 'gammaDDdDD[1][2][1][0]': mpf('5.5335349427183318693808176585407'), 'gammaDDdDD[1][2][1][1]': mpf('9.66395575640457553089340537573125'), 'gammaDDdDD[1][2][1][2]': mpf('15.1141997261213981599250387014752'), 'gammaDDdDD[1][2][2][0]': mpf('4.51408779818567722405331676792284'), 'gammaDDdDD[1][2][2][1]': mpf('15.1141997261213981599250387014752'), 'gammaDDdDD[1][2][2][2]': mpf('19.0650383126789942251109383834193'), 'gammaDDdDD[2][0][0][0]': mpf('0.375532488603708956700281774274923'), 'gammaDDdDD[2][0][0][1]': mpf('0.678340756727625343658227489853017'), 'gammaDDdDD[2][0][0][2]': mpf('2.78948049995862477035881653480892'), 'gammaDDdDD[2][0][1][0]': mpf('0.678340756727625343658227489853017'), 'gammaDDdDD[2][0][1][1]': mpf('-6.12617437316042868416067368255866'), 'gammaDDdDD[2][0][1][2]': mpf('-1.75847734950653146320336447142805'), 'gammaDDdDD[2][0][2][0]': mpf('2.78948049995862477035881653480892'), 'gammaDDdDD[2][0][2][1]': mpf('-1.75847734950653146320336447142805'), 'gammaDDdDD[2][0][2][2]': mpf('2.73521309266304236084886214346027'), 'gammaDDdDD[2][1][0][0]': mpf('-3.34089527571068728373797749836677'), 'gammaDDdDD[2][1][0][1]': mpf('5.5335349427183318693808176585407'), 'gammaDDdDD[2][1][0][2]': mpf('4.51408779818567722405331676792284'), 'gammaDDdDD[2][1][1][0]': mpf('5.5335349427183318693808176585407'), 'gammaDDdDD[2][1][1][1]': mpf('9.66395575640457553089340537573125'), 'gammaDDdDD[2][1][1][2]': mpf('15.1141997261213981599250387014752'), 'gammaDDdDD[2][1][2][0]': mpf('4.51408779818567722405331676792284'), 'gammaDDdDD[2][1][2][1]': mpf('15.1141997261213981599250387014752'), 'gammaDDdDD[2][1][2][2]': mpf('19.0650383126789942251109383834193'), 'gammaDDdDD[2][2][0][0]': mpf('-2.52353147414316377574820905559147'), 'gammaDDdDD[2][2][0][1]': mpf('4.53575664377867062493942188091689'), 'gammaDDdDD[2][2][0][2]': mpf('3.56377908834306629097560544110174'), 'gammaDDdDD[2][2][1][0]': mpf('4.5357566437786706249394218809232'), 'gammaDDdDD[2][2][1][1]': mpf('1.84054709164445852274067505481422'), 'gammaDDdDD[2][2][1][2]': mpf('7.16074940759453707759590964424542'), 'gammaDDdDD[2][2][2][0]': mpf('3.56377908834306629097560544110174'), 'gammaDDdDD[2][2][2][1]': mpf('7.16074940759453707759590964424542'), 'gammaDDdDD[2][2][2][2]': mpf('12.0437865836043923259359609593463'), 'gammaUU[0][0]': mpf('-6.28938129956539035233976956863059'), 'gammaUU[0][1]': mpf('18.2330938347990520861338232067731'), 'gammaUU[0][2]': mpf('-22.7932869645533398576110813493934'), 'gammaUU[1][0]': mpf('18.2330938347990520861338232067731'), 'gammaUU[1][1]': mpf('-51.9160225808937703970803496330078'), 'gammaUU[1][2]': mpf('64.7566755861571412059499249935555'), 'gammaUU[2][0]': mpf('-22.7932869645533398576110813493934'), 'gammaUU[2][1]': mpf('64.7566755861571412059499249935555'), 'gammaUU[2][2]': mpf('-78.479328065890663873188546288808'), 'detgamma': mpf('-0.0742854979156755661927481235463981'), 'GammaUDD[0][0][0]': mpf('-40.7797584599095266200402578142104'), 'GammaUDD[0][0][1]': mpf('-14.9811790250568026018422503217171'), 'GammaUDD[0][0][2]': mpf('12.2823492767347497337333129446469'), 'GammaUDD[0][1][0]': mpf('-14.9811790250568026018422503217171'), 'GammaUDD[0][1][1]': mpf('-36.3609505192780257845662292664448'), 'GammaUDD[0][1][2]': mpf('-30.1270719072420555274502961949333'), 'GammaUDD[0][2][0]': mpf('12.2823492767347497337333129446469'), 'GammaUDD[0][2][1]': mpf('-30.1270719072420555274502961949333'), 'GammaUDD[0][2][2]': mpf('-22.2862334550824046529070435685497'), 'GammaUDD[1][0][0]': mpf('106.641099858555951710230668316931'), 'GammaUDD[1][0][1]': mpf('34.5648661443104393199809718733873'), 'GammaUDD[1][0][2]': mpf('-42.0625759749969397716067483012153'), 'GammaUDD[1][1][0]': mpf('34.5648661443104393199809718733873'), 'GammaUDD[1][1][1]': mpf('97.8702478474345566909160962391556'), 'GammaUDD[1][1][2]': mpf('83.7688065067695141694849527164939'), 'GammaUDD[1][2][0]': mpf('-42.0625759749969397716067483012153'), 'GammaUDD[1][2][1]': mpf('83.7688065067695141694849527164939'), 'GammaUDD[1][2][2]': mpf('63.37436120121238471219216463813'), 'GammaUDD[2][0][0]': mpf('-82.5821023178249589056509375957706'), 'GammaUDD[2][0][1]': mpf('-25.7920996188850360970982778501415'), 'GammaUDD[2][0][2]': mpf('53.7895042071558641126267308366467'), 'GammaUDD[2][1][0]': mpf('-25.7920996188850360970982778501415'), 'GammaUDD[2][1][1]': mpf('-115.685453925551790074619499114864'), 'GammaUDD[2][1][2]': mpf('-104.640881703073552107006493456468'), 'GammaUDD[2][2][0]': mpf('53.7895042071558641126267308366467'), 'GammaUDD[2][2][1]': mpf('-104.640881703073552107006493456468'), 'GammaUDD[2][2][2]': mpf('-81.2201272697658198766768439312511'), 'KDD[0][0]': mpf('2.52635313601760623671007177930783'), 'KDD[0][1]': mpf('2.82898873912114767238892405861643'), 'KDD[0][2]': mpf('0.381578303862588400274173947157554'), 'KDD[1][0]': mpf('2.82898873912114767238892405861643'), 'KDD[1][1]': mpf('0.775186746770488740436250426070358'), 'KDD[1][2]': mpf('0.547222495805151738810645787512339'), 'KDD[2][0]': mpf('0.381578303862588400274173947157554'), 'KDD[2][1]': mpf('0.547222495805151738810645787512339'), 'KDD[2][2]': mpf('0.23987159265969208367518412563801'), 'KDDdD[0][0][0]': mpf('-6.98418007348680855492680452748596'), 'KDDdD[0][0][1]': mpf('-4.90357255070945013899614827846758'), 'KDDdD[0][0][2]': mpf('-9.51091715630967778721956190135931'), 'KDDdD[0][1][0]': mpf('-4.23975060495945983382577294248919'), 'KDDdD[0][1][1]': mpf('-13.8610965865853556038884955897668'), 'KDDdD[0][1][2]': mpf('-10.9245220106877969893233753184212'), 'KDDdD[0][2][0]': mpf('0.673882280969017838122158707807608'), 'KDDdD[0][2][1]': mpf('-0.152233642969041739842056712724457'), 'KDDdD[0][2][2]': mpf('-0.869578101320992405108114411360838'), 'KDDdD[1][0][0]': mpf('-4.23975060495945983382577294248919'), 'KDDdD[1][0][1]': mpf('-13.8610965865853556038884955897668'), 'KDDdD[1][0][2]': mpf('-10.9245220106877969893233753184212'), 'KDDdD[1][1][0]': mpf('0.830817678793678957257737618165166'), 'KDDdD[1][1][1]': mpf('-3.44366499994735267064814741173414'), 'KDDdD[1][1][2]': mpf('-3.27432266931077674480141080049683'), 'KDDdD[1][2][0]': mpf('0.708601442458893682779601967212525'), 'KDDdD[1][2][1]': mpf('-1.5539589956391283812811555376677'), 'KDDdD[1][2][2]': mpf('-2.26158238807310704211409034124987'), 'KDDdD[2][0][0]': mpf('0.673882280969017838122158707807608'), 'KDDdD[2][0][1]': mpf('-0.152233642969041739842056712724457'), 'KDDdD[2][0][2]': mpf('-0.869578101320992405108114411360838'), 'KDDdD[2][1][0]': mpf('0.708601442458893682779601967212525'), 'KDDdD[2][1][1]': mpf('-1.5539589956391283812811555376677'), 'KDDdD[2][1][2]': mpf('-2.26158238807310704211409034124987'), 'KDDdD[2][2][0]': mpf('0.424502981369425679158130440942863'), 'KDDdD[2][2][1]': mpf('-0.116489737786019245029640728668932'), 'KDDdD[2][2][2]': mpf('-1.03790663578070485250054725692471')}# Generated on: 2019-08-09trusted_values_dict['BrillLindquist__BrillLindquist__ComputeADMGlobalsOnly=True__globals'] = {'alphaCart': mpf('0.343480750893445797669295337903236'), 'betaCartU[0]': mpf('0.0'), 'betaCartU[1]': mpf('0.0'), 'betaCartU[2]': mpf('0.0'), 'BCartU[0]': mpf('0.0'), 'BCartU[1]': mpf('0.0'), 'BCartU[2]': mpf('0.0'), 'gammaCartDD[0][0]': mpf('8.47608284216415538664572854966934'), 'gammaCartDD[0][1]': mpf('0.0'), 'gammaCartDD[0][2]': mpf('0.0'), 'gammaCartDD[1][0]': mpf('0.0'), 'gammaCartDD[1][1]': mpf('8.47608284216415538664572854966934'), 'gammaCartDD[1][2]': mpf('0.0'), 'gammaCartDD[2][0]': mpf('0.0'), 'gammaCartDD[2][1]': mpf('0.0'), 'gammaCartDD[2][2]': mpf('8.47608284216415538664572854966934'), 'KCartDD[0][0]': mpf('0.0'), 'KCartDD[0][1]': mpf('0.0'), 'KCartDD[0][2]': mpf('0.0'), 'KCartDD[1][0]': mpf('0.0'), 'KCartDD[1][1]': mpf('0.0'), 'KCartDD[1][2]': mpf('0.0'), 'KCartDD[2][0]': mpf('0.0'), 'KCartDD[2][1]': mpf('0.0'), 'KCartDD[2][2]': mpf('0.0')}# Generated on: 2019-08-09trusted_values_dict['Psi4__Psi4__specify_tetrad=False__globals'] = {'psi4_re_pt[0]': mpf('-11.4627408385133346012203475168749'), 'psi4_re_pt[1]': mpf('-35.6806714906029645727316589574499'), 'psi4_re_pt[2]': mpf('-3374.92496104893019517395960329346'), 'psi4_im_pt[0]': mpf('7.17626585537563385139665194926662'), 'psi4_im_pt[1]': mpf('103.321768247585408574682983348206'), 'psi4_im_pt[2]': mpf('-1785.88265198482805325630868693525')}# Generated on: 2019-08-09trusted_values_dict['Psi4_tetrads__Psi4_tetrads__globals'] = {'l4U[0]': mpf('0.707106781186547524400844362104785'), 'l4U[1]': mpf('0.238900425354320344832613106016182'), 'l4U[2]': mpf('0.0'), 'l4U[3]': mpf('-0.105712695337363311625493077156009'), 'n4U[0]': mpf('0.707106781186547524400844362104785'), 'n4U[1]': mpf('-0.238900425354320344832613106016182'), 'n4U[2]': mpf('0.0'), 'n4U[3]': mpf('0.105712695337363311625493077156009'), 'mre4U[0]': mpf('0.0'), 'mre4U[1]': mpc(real='0.0', imag='1.78934738466770903997371533478145'), 'mre4U[2]': mpc(real='0.0', imag='-5.09490051820905343049616931239143'), 'mre4U[3]': mpc(real='0.0', imag='6.3550480872706263113514069118537'), 'mim4U[0]': mpf('0.0'), 'mim4U[1]': mpf('0.0'), 'mim4U[2]': mpf('0.0'), 'mim4U[3]': mpf('1.06573776541005837815518683742699')}# Generated on: 2019-08-09trusted_values_dict['BSSN_RHSs__BSSN_RHSs__globals'] = {'cf_rhs': mpf('3.77382093789289698643326794257121'), 'trK_rhs': mpf('4897.15010872261926255101979442461'), 'lambda_rhsU[0]': mpf('-932925.380251880280514928387377418'), 'lambda_rhsU[1]': mpf('1067214.31502612160105983520112858'), 'lambda_rhsU[2]': mpf('-634521.485102957628967190217797872'), 'a_rhsDD[0][0]': mpf('140611.691921936258075248177043018'), 'a_rhsDD[0][1]': mpf('129610.009549628960496251001913799'), 'a_rhsDD[0][2]': mpf('12478.2048292408067063007598939149'), 'a_rhsDD[1][0]': mpf('129610.009549628960496251001913218'), 'a_rhsDD[1][1]': mpf('190869.710957991947993273525242575'), 'a_rhsDD[1][2]': mpf('127861.933393387548396211650851467'), 'a_rhsDD[2][0]': mpf('12478.2048292408067063007598938196'), 'a_rhsDD[2][1]': mpf('127861.933393387548396211650851428'), 'a_rhsDD[2][2]': mpf('200379.251226055957975675818299921'), 'h_rhsDD[0][0]': mpf('26.0204338410819173136453286914799'), 'h_rhsDD[0][1]': mpf('25.0575733174708969733897611044168'), 'h_rhsDD[0][2]': mpf('11.7768556092635889801475757434684'), 'h_rhsDD[1][0]': mpf('25.0575733174708969733897611044168'), 'h_rhsDD[1][1]': mpf('40.8921058052569946189333312205232'), 'h_rhsDD[1][2]': mpf('39.8230119150907530884376958638246'), 'h_rhsDD[2][0]': mpf('11.7768556092635889801475757434684'), 'h_rhsDD[2][1]': mpf('39.8230119150907530884376958638246'), 'h_rhsDD[2][2]': mpf('72.3354550710637207030251571354033')}# Generated on: 2019-08-09trusted_values_dict['ShiftedKerrSchild__ShiftedKerrSchild__ComputeADMGlobalsOnly=True__globals'] = {'alphaSph': mpf('0.764992222074068488402374263959388'), 'betaSphU[0]': mpf('0.414786900166179080948286822502086'), 'betaSphU[1]': mpf('0.0'), 'betaSphU[2]': mpf('0.0'), 'BSphU[0]': mpf('0.0'), 'BSphU[1]': mpf('0.0'), 'BSphU[2]': mpf('0.0'), 'gammaSphDD[0][0]': mpf('1.70877924688282501671697638255698'), 'gammaSphDD[0][1]': mpf('0.0'), 'gammaSphDD[0][2]': mpf('-0.34407721284779690446451905546302'), 'gammaSphDD[1][0]': mpf('0.0'), 'gammaSphDD[1][1]': mpf('0.83749814889950038479162273698221'), 'gammaSphDD[1][2]': mpf('0.0'), 'gammaSphDD[2][0]': mpf('-0.34407721284779690446451905546302'), 'gammaSphDD[2][1]': mpf('0.0'), 'gammaSphDD[2][2]': mpf('0.428211355345928897234853289336263'), 'KSphDD[0][0]': mpf('-0.608416975836176206520434449342952'), 'KSphDD[0][1]': mpf('0.0707242913409545835190603089766082'), 'KSphDD[0][2]': mpf('0.0772829375209889643435925308431919'), 'KSphDD[1][0]': mpf('0.0707242913409545835190603089766082'), 'KSphDD[1][1]': mpf('0.457311525223526834585984744200641'), 'KSphDD[1][2]': mpf('-0.0142409366743087039035851689662884'), 'KSphDD[2][0]': mpf('0.0772829375209889643435925308431919'), 'KSphDD[2][1]': mpf('-0.0142409366743087039035851689662884'), 'KSphDD[2][2]': mpf('0.189536302720822065090385756720081')}# Generated on: 2019-08-09trusted_values_dict['StaticTrumpet__StaticTrumpet__ComputeADMGlobalsOnly=True__globals'] = {'alphaSph': mpf('0.47901157071628237535174768234896'), 'betaSphU[0]': mpf('0.249559485836202384477547321977731'), 'betaSphU[1]': mpf('0.0'), 'betaSphU[2]': mpf('0.0'), 'BSphU[0]': mpf('0.0'), 'BSphU[1]': mpf('0.0'), 'BSphU[2]': mpf('0.0'), 'gammaSphDD[0][0]': mpf('4.35820838377928180149222863568597'), 'gammaSphDD[0][1]': mpf('0.0'), 'gammaSphDD[0][2]': mpf('0.0'), 'gammaSphDD[1][0]': mpf('0.0'), 'gammaSphDD[1][1]': mpf('0.456231514782622374769913065861258'), 'gammaSphDD[1][2]': mpf('0.0'), 'gammaSphDD[2][0]': mpf('0.0'), 'gammaSphDD[2][1]': mpf('0.0'), 'gammaSphDD[2][2]': mpf('0.19552817796951759898685705719116'), 'KSphDD[0][0]': mpf('-3.36157982955715545881983739302993'), 'KSphDD[0][1]': mpf('0.0'), 'KSphDD[0][2]': mpf('0.0'), 'KSphDD[1][0]': mpf('0.0'), 'KSphDD[1][1]': mpf('0.351901176504010315682080545229837'), 'KSphDD[1][2]': mpf('0.0'), 'KSphDD[2][0]': mpf('0.0'), 'KSphDD[2][1]': mpf('0.0'), 'KSphDD[2][2]': mpf('0.150815087598546495698285048292878')}# Generated on: 2019-08-09trusted_values_dict['T4UUmunu_vars__define_BSSN_T4UUmunu_rescaled_source_terms__globals'] = {'rho': mpf('0.318351756980246647366072920704028'), 'S': mpf('0.41672759971301631676254828562378'), 'sD[0]': mpf('0.139936033700502671095478035567794'), 'sD[1]': mpf('0.724042932336828037875875452300534'), 'sD[2]': mpf('0.634678894759461820207491200562799'), 'sDD[0][0]': mpf('0.975581143777359494073664336610818'), 'sDD[0][1]': mpf('0.319506043115684978950241657003062'), 'sDD[0][2]': mpf('0.843707417334013110021828651952092'), 'sDD[1][0]': mpf('0.319506043115684978950241657003062'), 'sDD[1][1]': mpf('0.535419446395211107159184393822215'), 'sDD[1][2]': mpf('0.697293983830049590721955610206351'), 'sDD[2][0]': mpf('0.843707417334013110021828651952092'), 'sDD[2][1]': mpf('0.697293983830049590721955610206351'), 'sDD[2][2]': mpf('0.0883241044811280406889864025288261')}# Generated on: 2019-08-09trusted_values_dict['UIUCBlackHole__UIUCBlackHole__ComputeADMGlobalsOnly=True__globals'] = {'alphaSph': mpf('1.0'), 'betaSphU[0]': mpf('0.0'), 'betaSphU[1]': mpf('0.0'), 'betaSphU[2]': mpf('0.0'), 'BSphU[0]': mpf('0.0'), 'BSphU[1]': mpf('0.0'), 'BSphU[2]': mpf('0.0'), 'gammaSphDD[0][0]': mpf('5.88800397535091508054696345959799'), 'gammaSphDD[0][1]': mpf('0.0'), 'gammaSphDD[0][2]': mpf('0.0'), 'gammaSphDD[1][0]': mpf('0.0'), 'gammaSphDD[1][1]': mpf('0.49579570354855419371061261468577'), 'gammaSphDD[1][2]': mpf('0.0'), 'gammaSphDD[2][0]': mpf('0.0'), 'gammaSphDD[2][1]': mpf('0.0'), 'gammaSphDD[2][2]': mpf('0.239531368774223457427342816780148'), 'KSphDD[0][0]': mpf('0.0'), 'KSphDD[0][1]': mpf('0.0'), 'KSphDD[0][2]': mpf('0.516384223238703786717270771044344'), 'KSphDD[1][0]': mpf('0.0'), 'KSphDD[1][1]': mpf('0.0'), 'KSphDD[1][2]': mpf('-0.00263738331117854302766878470676251'), 'KSphDD[2][0]': mpf('0.516384223238703786717270771044344'), 'KSphDD[2][1]': mpf('-0.00263738331117854302766878470676251'), 'KSphDD[2][2]': mpf('0.0')}# Generated on: 2019-08-09trusted_values_dict['BSSN_constraints__BSSN_constraints__globals'] = {'H': mpf('-743404.980107555200155796229460404'), 'MU[0]': mpf('180487.187683651511140228998931702'), 'MU[1]': mpf('-212737.320962133501867845763983593'), 'MU[2]': mpf('117663.393460122555345796445578668')}# Generated on: 2019-08-09trusted_values_dict['gauge_RHSs__BSSN_gauge_RHSs__globals'] = {'alpha_rhs': mpf('4.55215595841202287904255791161233'), 'bet_rhsU[0]': mpf('-699763.514938021371061944114376614'), 'bet_rhsU[1]': mpf('800493.882262268190058064264269136'), 'bet_rhsU[2]': mpf('-475937.852585205029810577745084266'), 'vet_rhsU[0]': mpf('-202.50075396040237046126314033238'), 'vet_rhsU[1]': mpf('243.191035932372271446347823729945'), 'vet_rhsU[2]': mpf('-122.639420805832850593976051533138')}# Generated on: 2019-08-09trusted_values_dict['BSSN_quantities__declare_BSSN_gridfunctions_if_not_declared_already__globals'] = {'hDD[0][0]': mpf('0.00450974412619198350427041077637114'), 'hDD[0][1]': mpf('0.923519781999295741314881524886005'), 'hDD[0][2]': mpf('0.120267555611392129577552623231895'), 'hDD[1][0]': mpf('0.923519781999295741314881524886005'), 'hDD[1][1]': mpf('0.290125263019792467567015137319686'), 'hDD[1][2]': mpf('0.925654825647319157155834545847028'), 'hDD[2][0]': mpf('0.120267555611392129577552623231895'), 'hDD[2][1]': mpf('0.925654825647319157155834545847028'), 'hDD[2][2]': mpf('0.477887576370744082687735954095842'), 'aDD[0][0]': mpf('0.142813553146530880511022587597836'), 'aDD[0][1]': mpf('0.647457955584693545247887414006982'), 'aDD[0][2]': mpf('0.21834217753528206706903347367188'), 'aDD[1][0]': mpf('0.647457955584693545247887414006982'), 'aDD[1][1]': mpf('0.333850909184938648976981312443968'), 'aDD[1][2]': mpf('0.687554902414082569350739504443482'), 'aDD[2][0]': mpf('0.21834217753528206706903347367188'), 'aDD[2][1]': mpf('0.687554902414082569350739504443482'), 'aDD[2][2]': mpf('0.593368548750377144962442343967268'), 'lambdaU[0]': mpf('0.562783861711218968970626974623883'), 'lambdaU[1]': mpf('0.664424004972256732060031936271116'), 'lambdaU[2]': mpf('0.26459724357734237809580690736766'), 'vetU[0]': mpf('0.696603667756184763426574590994278'), 'vetU[1]': mpf('0.602357411405810894144963185681263'), 'vetU[2]': mpf('0.850413289206002676046125543507515'), 'betU[0]': mpf('0.0391630274878592699039359104062896'), 'betU[1]': mpf('0.0690677340046900178904820677416865'), 'betU[2]': mpf('0.210433354840527941931327404745389'), 'trK': mpf('0.430179315304250131646313093369827'), 'cf': mpf('0.336963542644043156926159099384677'), 'alpha': mpf('0.574476527200906694758941739564762')}# Generated on: 2019-08-09trusted_values_dict['BSSN_quantities__BSSN_basic_tensors__globals'] = {'gammabarDD[0][0]': mpf('1.00450974412619198350427041077637'), 'gammabarDD[0][1]': mpf('0.380375959488448974007020456949004'), 'gammabarDD[0][2]': mpf('0.0221179741925291571131550303027706'), 'gammabarDD[1][0]': mpf('0.380375959488448974007020456949004'), 'gammabarDD[1][1]': mpf('0.218859597510979935870263689587696'), 'gammabarDD[1][2]': mpf('0.0701152990412707885651168831120483'), 'gammabarDD[2][0]': mpf('0.0221179741925291571131550303027706'), 'gammabarDD[2][1]': mpf('0.0701152990412707885651168831120483'), 'gammabarDD[2][2]': mpf('0.0499844737257731260766363781664902'), 'AbarDD[0][0]': mpf('0.142813553146530880511022587597836'), 'AbarDD[0][1]': mpf('0.266672621295452871655360256826897'), 'AbarDD[0][2]': mpf('0.0401545256600238301157730952990965'), 'AbarDD[1][0]': mpf('0.266672621295452871655360256826897'), 'AbarDD[1][1]': mpf('0.056635179317288849494133380201829'), 'AbarDD[1][2]': mpf('0.0520800154164839604018649639497029'), 'AbarDD[2][0]': mpf('0.0401545256600238301157730952990965'), 'AbarDD[2][1]': mpf('0.0520800154164839604018649639497029'), 'AbarDD[2][2]': mpf('0.0200686541445511291805537698984873'), 'LambdabarU[0]': mpf('0.562783861711218968970626974623883'), 'LambdabarU[1]': mpf('1.61316375791018207963945540610151'), 'LambdabarU[2]': mpf('1.43876032359725990511334321483131'), 'betaU[0]': mpf('0.696603667756184763426574590994278'), 'betaU[1]': mpf('1.46247146117037299492483621025343'), 'betaU[2]': mpf('4.6241634365771266519514488292252'), 'BU[0]': mpf('0.0391630274878592699039359104062896'), 'BU[1]': mpf('0.167690457454195833796083765751675'), 'BU[2]': mpf('1.14424155600667335640923075733714')}# Generated on: 2019-08-09trusted_values_dict['BSSN_quantities__gammabar__inverse_and_derivs__globals'] = {'gammabarUU[0][0]': mpf('-55.3913683921929939892608290454462'), 'gammabarUU[0][1]': mpf('160.581139770070431806627488067463'), 'gammabarUU[0][2]': mpf('-200.743331495864219543840762334583'), 'gammabarUU[1][0]': mpf('160.581139770070431806627488067463'), 'gammabarUU[1][1]': mpf('-457.230909570455507522618494885285'), 'gammabarUU[1][2]': mpf('570.320147944349793491547665601545'), 'gammabarUU[2][0]': mpf('-200.743331495864219543840762334583'), 'gammabarUU[2][1]': mpf('570.320147944349793491547665601545'), 'gammabarUU[2][2]': mpf('-691.177266096096440977423920582226'), 'gammabarDD_dD[0][0][0]': mpf('0.113376527866793974652637189137749'), 'gammabarDD_dD[0][0][1]': mpf('0.597031746016325581827288715430768'), 'gammabarDD_dD[0][0][2]': mpf('0.0326900992587932925914628867758438'), 'gammabarDD_dD[0][1][0]': mpf('1.29509849818179299105146594183329'), 'gammabarDD_dD[0][1][1]': mpf('0.29966757015887334440305520963308'), 'gammabarDD_dD[0][1][2]': mpf('0.408456984468846210692212242298237'), 'gammabarDD_dD[0][2][0]': mpf('0.0757914276030065310563752344719272'), 'gammabarDD_dD[0][2][1]': mpf('0.211213637778013737361842492406609'), 'gammabarDD_dD[0][2][2]': mpf('0.043576970886389692140854474231034'), 'gammabarDD_dD[1][0][0]': mpf('1.29509849818179299105146594183329'), 'gammabarDD_dD[1][0][1]': mpf('0.29966757015887334440305520963308'), 'gammabarDD_dD[1][0][2]': mpf('0.408456984468846210692212242298237'), 'gammabarDD_dD[1][1][0]': mpf('1.11081293166050470517099765479562'), 'gammabarDD_dD[1][1][1]': mpf('0.162456880553023991817285210787008'), 'gammabarDD_dD[1][1][2]': mpf('0.158500072577490769771706912461303'), 'gammabarDD_dD[1][2][0]': mpf('0.359283025128967082047900286877992'), 'gammabarDD_dD[1][2][1]': mpf('0.199267454573993880968860334987007'), 'gammabarDD_dD[1][2][2]': mpf('0.0222668035023729125133168779194776'), 'gammabarDD_dD[2][0][0]': mpf('0.0757914276030065310563752344719272'), 'gammabarDD_dD[2][0][1]': mpf('0.211213637778013737361842492406609'), 'gammabarDD_dD[2][0][2]': mpf('0.043576970886389692140854474231034'), 'gammabarDD_dD[2][1][0]': mpf('0.359283025128967082047900286877992'), 'gammabarDD_dD[2][1][1]': mpf('0.199267454573993880968860334987007'), 'gammabarDD_dD[2][1][2]': mpf('0.0222668035023729125133168779194776'), 'gammabarDD_dD[2][2][0]': mpf('0.249364796420989096924555910811589'), 'gammabarDD_dD[2][2][1]': mpf('0.229090281001197346827970614026702'), 'gammabarDD_dD[2][2][2]': mpf('0.0293354706024628609686096695909266'), 'gammabarDD_dupD[0][0][0]': mpf('0.37728180260573840332227746330318'), 'gammabarDD_dupD[0][0][1]': mpf('0.670267766719132906949596417689463'), 'gammabarDD_dupD[0][0][2]': mpf('0.781414536731840470018539690499892'), 'gammabarDD_dupD[0][1][0]': mpf('1.27559379975272638197786370234481'), 'gammabarDD_dupD[0][1][1]': mpf('0.270519930552051576420169894439394'), 'gammabarDD_dupD[0][1][2]': mpf('0.126974122612752350149982986405959'), 'gammabarDD_dupD[0][2][0]': mpf('0.160014994496667253968983142186692'), 'gammabarDD_dupD[0][2][1]': mpf('0.159417776511127717981289959174267'), 'gammabarDD_dupD[0][2][2]': mpf('0.0914222006910319288079363366980038'), 'gammabarDD_dupD[1][0][0]': mpf('1.27559379975272638197786370234481'), 'gammabarDD_dupD[1][0][1]': mpf('0.270519930552051576420169894439394'), 'gammabarDD_dupD[1][0][2]': mpf('0.126974122612752350149982986405959'), 'gammabarDD_dupD[1][1][0]': mpf('1.11565554836934532567070034274662'), 'gammabarDD_dupD[1][1][1]': mpf('0.0225054491023032484277595044174296'), 'gammabarDD_dupD[1][1][2]': mpf('0.148236212186685765996028318648501'), 'gammabarDD_dupD[1][2][0]': mpf('0.38244111267429014279462120452751'), 'gammabarDD_dupD[1][2][1]': mpf('0.19605291006032265256196166097098'), 'gammabarDD_dupD[1][2][2]': mpf('0.000359393084847625499631216495471881'), 'gammabarDD_dupD[2][0][0]': mpf('0.160014994496667253968983142186692'), 'gammabarDD_dupD[2][0][1]': mpf('0.159417776511127717981289959174267'), 'gammabarDD_dupD[2][0][2]': mpf('0.0914222006910319288079363366980038'), 'gammabarDD_dupD[2][1][0]': mpf('0.38244111267429014279462120452751'), 'gammabarDD_dupD[2][1][1]': mpf('0.19605291006032265256196166097098'), 'gammabarDD_dupD[2][1][2]': mpf('0.000359393084847625499631216495471881'), 'gammabarDD_dupD[2][2][0]': mpf('0.255124908396158921845552323395099'), 'gammabarDD_dupD[2][2][1]': mpf('0.210716113114337146067597109416175'), 'gammabarDD_dupD[2][2][2]': mpf('0.01339819778908501331879521055357'), 'gammabarDD_dDD[0][0][0][0]': mpf('0.185845801018537204463143552857218'), 'gammabarDD_dDD[0][0][0][1]': mpf('0.41265964722127601582712941308273'), 'gammabarDD_dDD[0][0][0][2]': mpf('0.37985477211695328758622736131656'), 'gammabarDD_dDD[0][0][1][0]': mpf('0.41265964722127601582712941308273'), 'gammabarDD_dDD[0][0][1][1]': mpf('0.689211123606880748937442149326671'), 'gammabarDD_dDD[0][0][1][2]': mpf('0.0048337295380591616122956111212261'), 'gammabarDD_dDD[0][0][2][0]': mpf('0.37985477211695328758622736131656'), 'gammabarDD_dDD[0][0][2][1]': mpf('0.0048337295380591616122956111212261'), 'gammabarDD_dDD[0][0][2][2]': mpf('0.538905401817390661278750485507771'), 'gammabarDD_dDD[0][1][0][0]': mpf('2.17695434404486827829573669497839'), 'gammabarDD_dDD[0][1][0][1]': mpf('0.737845818275736881995111390979058'), 'gammabarDD_dDD[0][1][0][2]': mpf('1.27821731904689736052853767370668'), 'gammabarDD_dDD[0][1][1][0]': mpf('0.737845818275736881995111390979058'), 'gammabarDD_dDD[0][1][1][1]': mpf('0.0572033349261599444767919389310414'), 'gammabarDD_dDD[0][1][1][2]': mpf('0.114449372510356573992423216972657'), 'gammabarDD_dDD[0][1][2][0]': mpf('1.27821731904689736052853767370668'), 'gammabarDD_dDD[0][1][2][1]': mpf('0.114449372510356573992423216972657'), 'gammabarDD_dDD[0][1][2][2]': mpf('0.336172859503064373361339781168181'), 'gammabarDD_dDD[0][2][0][0]': mpf('0.149593239036693143279810874442325'), 'gammabarDD_dDD[0][2][0][1]': mpf('0.670365627630913964987374237749722'), 'gammabarDD_dDD[0][2][0][2]': mpf('0.178979216891036880951181191336912'), 'gammabarDD_dDD[0][2][1][0]': mpf('0.670365627630913964987374237749722'), 'gammabarDD_dDD[0][2][1][1]': mpf('0.659480314934221443474116011063672'), 'gammabarDD_dDD[0][2][1][2]': mpf('0.211927554805221158936564646974544'), 'gammabarDD_dDD[0][2][2][0]': mpf('0.178979216891036880951181191336912'), 'gammabarDD_dDD[0][2][2][1]': mpf('0.211927554805221158936564646974544'), 'gammabarDD_dDD[0][2][2][2]': mpf('0.0131768891907001501822079393602128'), 'gammabarDD_dDD[1][0][0][0]': mpf('2.17695434404486827829573669497839'), 'gammabarDD_dDD[1][0][0][1]': mpf('0.737845818275736881995111390979058'), 'gammabarDD_dDD[1][0][0][2]': mpf('1.27821731904689736052853767370668'), 'gammabarDD_dDD[1][0][1][0]': mpf('0.737845818275736881995111390979058'), 'gammabarDD_dDD[1][0][1][1]': mpf('0.0572033349261599444767919389310414'), 'gammabarDD_dDD[1][0][1][2]': mpf('0.114449372510356573992423216972657'), 'gammabarDD_dDD[1][0][2][0]': mpf('1.27821731904689736052853767370668'), 'gammabarDD_dDD[1][0][2][1]': mpf('0.114449372510356573992423216972657'), 'gammabarDD_dDD[1][0][2][2]': mpf('0.336172859503064373361339781168181'), 'gammabarDD_dDD[1][1][0][0]': mpf('3.2125897978005476278879035565663'), 'gammabarDD_dDD[1][1][0][1]': mpf('0.89598315374067949012654219762452'), 'gammabarDD_dDD[1][1][0][2]': mpf('0.820646830703092166810003596680962'), 'gammabarDD_dDD[1][1][1][0]': mpf('0.89598315374067949012654219762452'), 'gammabarDD_dDD[1][1][1][1]': mpf('0.168996792900712596062122767009282'), 'gammabarDD_dDD[1][1][1][2]': mpf('0.0473971971696919594315542625878797'), 'gammabarDD_dDD[1][1][2][0]': mpf('0.820646830703092166810003596680962'), 'gammabarDD_dDD[1][1][2][1]': mpf('0.0473971971696919594315542625878797'), 'gammabarDD_dDD[1][1][2][2]': mpf('0.12968746168617386620955233939796'), 'gammabarDD_dDD[1][2][0][0]': mpf('1.04180796862731772248736459987955'), 'gammabarDD_dDD[1][2][0][1]': mpf('1.02777187626693600280637544109045'), 'gammabarDD_dDD[1][2][0][2]': mpf('0.138815878772543536594426398853965'), 'gammabarDD_dDD[1][2][1][0]': mpf('1.02777187626693600280637544109045'), 'gammabarDD_dDD[1][2][1][1]': mpf('0.205354158028681326149566579067253'), 'gammabarDD_dDD[1][2][1][2]': mpf('0.051702758215965343443390702033079'), 'gammabarDD_dDD[1][2][2][0]': mpf('0.138815878772543536594426398853965'), 'gammabarDD_dDD[1][2][2][1]': mpf('0.051702758215965343443390702033079'), 'gammabarDD_dDD[1][2][2][2]': mpf('0.0737488709653608336887200438662802'), 'gammabarDD_dDD[2][0][0][0]': mpf('0.149593239036693143279810874442325'), 'gammabarDD_dDD[2][0][0][1]': mpf('0.670365627630913964987374237749722'), 'gammabarDD_dDD[2][0][0][2]': mpf('0.178979216891036880951181191336912'), 'gammabarDD_dDD[2][0][1][0]': mpf('0.670365627630913964987374237749722'), 'gammabarDD_dDD[2][0][1][1]': mpf('0.659480314934221443474116011063672'), 'gammabarDD_dDD[2][0][1][2]': mpf('0.211927554805221158936564646974544'), 'gammabarDD_dDD[2][0][2][0]': mpf('0.178979216891036880951181191336912'), 'gammabarDD_dDD[2][0][2][1]': mpf('0.211927554805221158936564646974544'), 'gammabarDD_dDD[2][0][2][2]': mpf('0.0131768891907001501822079393602128'), 'gammabarDD_dDD[2][1][0][0]': mpf('1.04180796862731772248736459987955'), 'gammabarDD_dDD[2][1][0][1]': mpf('1.02777187626693600280637544109045'), 'gammabarDD_dDD[2][1][0][2]': mpf('0.138815878772543536594426398853965'), 'gammabarDD_dDD[2][1][1][0]': mpf('1.02777187626693600280637544109045'), 'gammabarDD_dDD[2][1][1][1]': mpf('0.205354158028681326149566579067253'), 'gammabarDD_dDD[2][1][1][2]': mpf('0.051702758215965343443390702033079'), 'gammabarDD_dDD[2][1][2][0]': mpf('0.138815878772543536594426398853965'), 'gammabarDD_dDD[2][1][2][1]': mpf('0.051702758215965343443390702033079'), 'gammabarDD_dDD[2][1][2][2]': mpf('0.0737488709653608336887200438662802'), 'gammabarDD_dDD[2][2][0][0]': mpf('0.66508879899869765324495129089009'), 'gammabarDD_dDD[2][2][0][1]': mpf('1.15812919014671874295450095368265'), 'gammabarDD_dDD[2][2][0][2]': mpf('0.165896787206516112586624167221097'), 'gammabarDD_dDD[2][2][1][0]': mpf('1.15812919014671874295450095368285'), 'gammabarDD_dDD[2][2][1][1]': mpf('0.533174868302490566724214906488119'), 'gammabarDD_dDD[2][2][1][2]': mpf('0.131976505361826978863691234258533'), 'gammabarDD_dDD[2][2][2][0]': mpf('0.165896787206516112586624167221097'), 'gammabarDD_dDD[2][2][2][1]': mpf('0.131976505361826978863691234258533'), 'gammabarDD_dDD[2][2][2][2]': mpf('0.010262022536939967495395958633956'), 'GammabarUDD[0][0][0]': mpf('144.958869354596952650223295197696'), 'GammabarUDD[0][0][1]': mpf('56.3884081838815055298106227619069'), 'GammabarUDD[0][0][2]': mpf('18.7492848883834673075437947835502'), 'GammabarUDD[0][1][0]': mpf('56.3884081838815055298106227619069'), 'GammabarUDD[0][1][1]': mpf('3.11678651957992149533502697995063'), 'GammabarUDD[0][1][2]': mpf('-17.4797246150434126590734188209953'), 'GammabarUDD[0][2][0]': mpf('18.7492848883834673075437947835502'), 'GammabarUDD[0][2][1]': mpf('-17.4797246150434126590734188209953'), 'GammabarUDD[0][2][2]': mpf('-13.2700699776147156200210831819353'), 'GammabarUDD[1][0][0]': mpf('-412.661847055574875860384479574194'), 'GammabarUDD[1][0][1]': mpf('-159.805737735924117067707092684796'), 'GammabarUDD[1][0][2]': mpf('-53.4969391010037688000184007256669'), 'GammabarUDD[1][1][0]': mpf('-159.805737735924117067707092684796'), 'GammabarUDD[1][1][1]': mpf('-9.75864522872634062530478027925608'), 'GammabarUDD[1][1][2]': mpf('49.998503864403681839928229922025'), 'GammabarUDD[1][2][0]': mpf('-53.4969391010037688000184007256669'), 'GammabarUDD[1][2][1]': mpf('49.998503864403681839928229922025'), 'GammabarUDD[1][2][2]': mpf('37.5338109651112817021709810969423'), 'GammabarUDD[2][0][0]': mpf('515.903374261971431760645349581284'), 'GammabarUDD[2][0][1]': mpf('200.835355938522818161227492367693'), 'GammabarUDD[2][0][2]': mpf('69.2403025140953793071085058377914'), 'GammabarUDD[2][1][0]': mpf('200.835355938522818161227492367693'), 'GammabarUDD[2][1][1]': mpf('14.7107829316252639239815376245426'), 'GammabarUDD[2][1][2]': mpf('-60.1086414978290381532119255024356'), 'GammabarUDD[2][2][0]': mpf('69.2403025140953793071085058377914'), 'GammabarUDD[2][2][1]': mpf('-60.1086414978290381532119255024356'), 'GammabarUDD[2][2][2]': mpf('-46.4848263107765220270562375920812')}# Generated on: 2019-08-09trusted_values_dict['BSSN_quantities__detgammabar_and_derivs__globals'] = {'detgammabar': mpf('0.00573756266880972544377979111558305'), 'detgammabar_dD[0]': mpf('0.0557212146869903791885764536246544'), 'detgammabar_dD[1]': mpf('0.0229955254712656127315158404877634'), 'detgammabar_dD[2]': mpf('0.0'), 'detgammabar_dDD[0][0]': mpf('0.405858804349815958396163363914466'), 'detgammabar_dDD[0][1]': mpf('0.223324551832801915665195788045795'), 'detgammabar_dDD[0][2]': mpf('0.0'), 'detgammabar_dDD[1][0]': mpf('0.223324551832801915665195788045795'), 'detgammabar_dDD[1][1]': mpf('0.0346066538274459059495911839041824'), 'detgammabar_dDD[1][2]': mpf('0.0'), 'detgammabar_dDD[2][0]': mpf('0.0'), 'detgammabar_dDD[2][1]': mpf('0.0'), 'detgammabar_dDD[2][2]': mpf('0.0')}# Generated on: 2019-08-09trusted_values_dict['BSSN_quantities__AbarUU_AbarUD_trAbar_AbarDD_dD__globals'] = {'AbarUU[0][0]': mpf('-4501.35489903001232813737257379218'), 'AbarUU[0][1]': mpf('12891.1260926920183373060745066027'), 'AbarUU[0][2]': mpf('-16048.8656589832488120714141642617'), 'AbarUU[1][0]': mpf('12891.1260926920183373060745066027'), 'AbarUU[1][1]': mpf('-36915.8909445128919893699783581937'), 'AbarUU[1][2]': mpf('45960.7552497439495397460051934269'), 'AbarUU[2][0]': mpf('-16048.8656589832488120714141642617'), 'AbarUU[2][1]': mpf('45960.7552497439495397460051934269'), 'AbarUU[2][2]': mpf('-57214.0298282929626166132996415947'), 'AbarUD[0][0]': mpf('26.8512020837293036423215049007785'), 'AbarUD[0][1]': mpf('-16.1315355594965963827373776014512'), 'AbarUD[0][2]': mpf('2.11020561975821049709560254567513'), 'AbarUD[1][0]': mpf('-76.096867038514101536679331070774'), 'AbarUD[1][1]': mpf('46.6295210174394985755149432015637'), 'AbarUD[1][2]': mpf('-5.91897552114475146319310921096151'), 'AbarUD[2][0]': mpf('95.6660051214531525255013492129713'), 'AbarUD[2][1]': mpf('-57.2290892443011388753856943624776'), 'AbarUD[2][2]': mpf('7.77053133578485609602163485965202'), 'trAbar': mpf('81.251254436953658313858082961098'), 'AbarDD_dD[0][0][0]': mpf('0.33721198437911092948837676885887'), 'AbarDD_dD[0][0][1]': mpf('0.679909473427153132618627751071472'), 'AbarDD_dD[0][0][2]': mpf('0.327242304499680503049319213459967'), 'AbarDD_dD[0][1][0]': mpf('0.733454489269375682720410108340373'), 'AbarDD_dD[0][1][1]': mpf('0.0564054522687123879076101957745309'), 'AbarDD_dD[0][1][2]': mpf('0.288952399746149364416592105125356'), 'AbarDD_dD[0][2][0]': mpf('0.259134566883295043505905621463171'), 'AbarDD_dD[0][2][1]': mpf('0.18566392834089806327031028199579'), 'AbarDD_dD[0][2][2]': mpf('0.10947288045690455436180777612326'), 'AbarDD_dD[1][0][0]': mpf('0.733454489269375682720410108340373'), 'AbarDD_dD[1][0][1]': mpf('0.0564054522687123879076101957745309'), 'AbarDD_dD[1][0][2]': mpf('0.288952399746149364416592105125356'), 'AbarDD_dD[1][1][0]': mpf('0.300852467812027766391019475297803'), 'AbarDD_dD[1][1][1]': mpf('0.0145399155791957464680340380309724'), 'AbarDD_dD[1][1][2]': mpf('0.0395378448600819201304333750185868'), 'AbarDD_dD[1][2][0]': mpf('0.300398363998209101604122555846344'), 'AbarDD_dD[1][2][1]': mpf('0.119537195366846939854213812053404'), 'AbarDD_dD[1][2][2]': mpf('0.04721114477346884448153824722088'), 'AbarDD_dD[2][0][0]': mpf('0.259134566883295043505905621463171'), 'AbarDD_dD[2][0][1]': mpf('0.18566392834089806327031028199579'), 'AbarDD_dD[2][0][2]': mpf('0.10947288045690455436180777612326'), 'AbarDD_dD[2][1][0]': mpf('0.300398363998209101604122555846344'), 'AbarDD_dD[2][1][1]': mpf('0.119537195366846939854213812053404'), 'AbarDD_dD[2][1][2]': mpf('0.04721114477346884448153824722088'), 'AbarDD_dD[2][2][0]': mpf('0.128416701185305713723338911303584'), 'AbarDD_dD[2][2][1]': mpf('0.091211183233673576891878621321523'), 'AbarDD_dD[2][2][2]': mpf('0.0124213262600154053715160803941519'), 'AbarDD_dupD[0][0][0]': mpf('0.769930872140056510311012516467599'), 'AbarDD_dupD[0][0][1]': mpf('0.406856967532203017690051183308242'), 'AbarDD_dupD[0][0][2]': mpf('0.034573833670986209298803260026034'), 'AbarDD_dupD[0][1][0]': mpf('0.799078538941273777740809109133389'), 'AbarDD_dupD[0][1][1]': mpf('0.111116568306179455959424903906438'), 'AbarDD_dupD[0][1][2]': mpf('0.377511909918297386621098531539175'), 'AbarDD_dupD[0][2][0]': mpf('0.214500608396807435491964973223518'), 'AbarDD_dupD[0][2][1]': mpf('0.115344958017771695940477015182743'), 'AbarDD_dupD[0][2][2]': mpf('0.122244734709826544219416183615818'), 'AbarDD_dupD[1][0][0]': mpf('0.799078538941273777740809109133389'), 'AbarDD_dupD[1][0][1]': mpf('0.111116568306179455959424903906438'), 'AbarDD_dupD[1][0][2]': mpf('0.377511909918297386621098531539175'), 'AbarDD_dupD[1][1][0]': mpf('0.435501861817190390787863358691289'), 'AbarDD_dupD[1][1][1]': mpf('0.116623980226106608051172387504808'), 'AbarDD_dupD[1][1][2]': mpf('0.0029262421496022085618519737385143'), 'AbarDD_dupD[1][2][0]': mpf('0.319628992953124375855747562860006'), 'AbarDD_dupD[1][2][1]': mpf('0.154649167361595245816006653565866'), 'AbarDD_dupD[1][2][2]': mpf('0.0691883280846439197601862955001518'), 'AbarDD_dupD[2][0][0]': mpf('0.214500608396807435491964973223518'), 'AbarDD_dupD[2][0][1]': mpf('0.115344958017771695940477015182743'), 'AbarDD_dupD[2][0][2]': mpf('0.122244734709826544219416183615818'), 'AbarDD_dupD[2][1][0]': mpf('0.319628992953124375855747562860006'), 'AbarDD_dupD[2][1][1]': mpf('0.154649167361595245816006653565866'), 'AbarDD_dupD[2][1][2]': mpf('0.0691883280846439197601862955001518'), 'AbarDD_dupD[2][2][0]': mpf('0.102626201407641450303174373971461'), 'AbarDD_dupD[2][2][1]': mpf('0.102313858934520263961250056659667'), 'AbarDD_dupD[2][2][2]': mpf('0.00853496939586718772700035856415055')}# Generated on: 2019-08-09trusted_values_dict['BSSN_quantities__RicciBar__gammabarDD_dHatD__DGammaUDD__DGammaU__globals'] = {'RbarDD[0][0]': mpf('-41245.2193607369706612392062712087'), 'RbarDD[0][1]': mpf('-13279.8476666719541384124392490902'), 'RbarDD[0][2]': mpf('-13136.4852727140129778266912775021'), 'RbarDD[1][0]': mpf('-13279.8476666719541384124392490142'), 'RbarDD[1][1]': mpf('17572.3339460500557245822009043625'), 'RbarDD[1][2]': mpf('-4983.05391806650925004378740779'), 'RbarDD[2][0]': mpf('-13136.485272714012977826691277452'), 'RbarDD[2][1]': mpf('-4983.05391806650925004378740779404'), 'RbarDD[2][2]': mpf('-5521.17554758589382532917232982535'), 'DGammaUDD[0][0][0]': mpf('144.958869354596952650223295197696'), 'DGammaUDD[0][0][1]': mpf('56.3884081838815055298106227619069'), 'DGammaUDD[0][0][2]': mpf('18.7492848883834673075437947835502'), 'DGammaUDD[0][1][0]': mpf('56.3884081838815055298106227619069'), 'DGammaUDD[0][1][1]': mpf('3.52866287231487465035648484008052'), 'DGammaUDD[0][1][2]': mpf('-17.4797246150434126590734188209953'), 'DGammaUDD[0][2][0]': mpf('18.7492848883834673075437947835502'), 'DGammaUDD[0][2][1]': mpf('-17.4797246150434126590734188209953'), 'DGammaUDD[0][2][2]': mpf('-13.1879541513368329697779753752397'), 'DGammaUDD[1][0][0]': mpf('-412.661847055574875860384479574194'), 'DGammaUDD[1][0][1]': mpf('-162.233650854411671297209410338331'), 'DGammaUDD[1][0][2]': mpf('-53.4969391010037688000184007256669'), 'DGammaUDD[1][1][0]': mpf('-162.233650854411671297209410338331'), 'DGammaUDD[1][1][1]': mpf('-9.75864522872634062530478027925608'), 'DGammaUDD[1][1][2]': mpf('49.998503864403681839928229922025'), 'DGammaUDD[1][2][0]': mpf('-53.4969391010037688000184007256669'), 'DGammaUDD[1][2][1]': mpf('49.998503864403681839928229922025'), 'DGammaUDD[1][2][2]': mpf('37.9333377581165059513560056676581'), 'DGammaUDD[2][0][0]': mpf('515.903374261971431760645349581284'), 'DGammaUDD[2][0][1]': mpf('200.835355938522818161227492367693'), 'DGammaUDD[2][0][2]': mpf('66.8123893956078250776061881842562'), 'DGammaUDD[2][1][0]': mpf('200.835355938522818161227492367693'), 'DGammaUDD[2][1][1]': mpf('14.7107829316252639239815376245426'), 'DGammaUDD[2][1][2]': mpf('-62.1125869707275593077009803716383'), 'DGammaUDD[2][2][0]': mpf('66.8123893956078250776061881842562'), 'DGammaUDD[2][2][1]': mpf('-62.1125869707275593077009803716383'), 'DGammaUDD[2][2][2]': mpf('-46.4848263107765220270562375920812'), 'gammabarDD_dHatD[0][0][0]': mpf('0.113376527866793974652637189137749'), 'gammabarDD_dHatD[0][0][1]': mpf('-1.25000781798226590080247433434124'), 'gammabarDD_dHatD[0][0][2]': mpf('-0.0747109401340281274447427294117478'), 'gammabarDD_dHatD[0][1][0]': mpf('0.371578716182497249736584416947285'), 'gammabarDD_dHatD[0][1][1]': mpf('0.182029291952476074147915289630397'), 'gammabarDD_dHatD[0][1][2]': mpf('0.193899915867061900813055159582757'), 'gammabarDD_dHatD[0][2][0]': mpf('0.0220909079065958210382724263781314'), 'gammabarDD_dHatD[0][2][1]': mpf('-0.00334343082377057251731459030886539'), 'gammabarDD_dHatD[0][2][2]': mpf('0.156675546280700493851442555008333'), 'gammabarDD_dHatD[1][0][0]': mpf('0.371578716182497249736584416947285'), 'gammabarDD_dHatD[1][0][1]': mpf('0.182029291952476074147915289630397'), 'gammabarDD_dHatD[1][0][2]': mpf('0.193899915867061900813055159582757'), 'gammabarDD_dHatD[1][1][0]': mpf('0.0480687558528761896352673763644066'), 'gammabarDD_dHatD[1][1][1]': mpf('0.475792606277345313962293654458942'), 'gammabarDD_dHatD[1][1][2]': mpf('-0.122514399611870464853979699604412'), 'gammabarDD_dHatD[1][2][0]': mpf('0.0188153164310087189522141894729995'), 'gammabarDD_dHatD[1][2][1]': mpf('0.0678700890196179934569006598920808'), 'gammabarDD_dHatD[1][2][2]': mpf('0.0407758029860071575845246674537359'), 'gammabarDD_dHatD[2][0][0]': mpf('0.0220909079065958210382724263781314'), 'gammabarDD_dHatD[2][0][1]': mpf('-0.00334343082377057251731459030886539'), 'gammabarDD_dHatD[2][0][2]': mpf('0.156675546280700493851442555008333'), 'gammabarDD_dHatD[2][1][0]': mpf('0.0188153164310087189522141894729995'), 'gammabarDD_dHatD[2][1][1]': mpf('0.0678700890196179934569006598920808'), 'gammabarDD_dHatD[2][1][2]': mpf('0.0407758029860071575845246674537359'), 'gammabarDD_dHatD[2][2][0]': mpf('0.00664887746198699878899292414052604'), 'gammabarDD_dHatD[2][2][1]': mpf('0.0287579613252410813496304259029699'), 'gammabarDD_dHatD[2][2][2]': mpf('0.0889938231884100782604806662221182'), 'DGammaU[0]': mpf('-9883.50614138972832359869160635136'), 'DGammaU[1]': mpf('27506.4846155065370543113398270077'), 'DGammaU[2]': mpf('-36345.2254745846641825231815918191')}# Generated on: 2019-08-09trusted_values_dict['BSSN_quantities__betaU_derivs__globals'] = {'betaU_dD[0][0]': mpf('0.192243539484738046319023396790726'), 'betaU_dD[0][1]': mpf('0.754980728051157679026061941840453'), 'betaU_dD[0][2]': mpf('0.586123078895915305963626451557502'), 'betaU_dD[1][0]': mpf('-3.18830793589382952185971488180311'), 'betaU_dD[1][1]': mpf('0.922655491152517150129828380218527'), 'betaU_dD[1][2]': mpf('2.402141784188005363245692498957'), 'betaU_dD[2][0]': mpf('-8.9043744551685352332500234492703'), 'betaU_dD[2][1]': mpf('-4.62598533129686961830418682100716'), 'betaU_dD[2][2]': mpf('3.76687640853700760943325487483147'), 'betaU_dupD[0][0]': mpf('0.659472189904469763277461424877401'), 'betaU_dupD[0][1]': mpf('0.948628367838908470588421550928615'), 'betaU_dupD[0][2]': mpf('0.669133180747105038577160485147033'), 'betaU_dupD[1][0]': mpf('-1.60394693865713402126230258890783'), 'betaU_dupD[1][1]': mpf('1.41044106421919101151961432862351'), 'betaU_dupD[1][2]': mpf('0.406302118865459317620854482607423'), 'betaU_dupD[2][0]': mpf('-6.34070058470575134851313539411892'), 'betaU_dupD[2][1]': mpf('-8.20689620375936786515281493126901'), 'betaU_dupD[2][2]': mpf('3.95742743877129970876759452390656'), 'betaU_dDD[0][0][0]': mpf('0.693440743164982609236801636143355'), 'betaU_dDD[0][0][1]': mpf('0.474644061200962252833335242030444'), 'betaU_dDD[0][0][2]': mpf('0.248757440072191138291657352965558'), 'betaU_dDD[0][1][0]': mpf('0.474644061200962252833335242030444'), 'betaU_dDD[0][1][1]': mpf('0.0806331535826826373281051019148435'), 'betaU_dDD[0][1][2]': mpf('0.906200949230643648668603873375105'), 'betaU_dDD[0][2][0]': mpf('0.248757440072191138291657352965558'), 'betaU_dDD[0][2][1]': mpf('0.906200949230643648668603873375105'), 'betaU_dDD[0][2][2]': mpf('0.256446105879290064955000616464531'), 'betaU_dDD[1][0][0]': mpf('17.6480807195419839436961496336133'), 'betaU_dDD[1][0][1]': mpf('-0.521955208304153160154395471306198'), 'betaU_dDD[1][0][2]': mpf('-3.59469879181060009166143907294526'), 'betaU_dDD[1][1][0]': mpf('-0.521955208304153160154395471306198'), 'betaU_dDD[1][1][1]': mpf('0.390333580442849126669804861962297'), 'betaU_dDD[1][1][2]': mpf('1.03879140080831086038810101219714'), 'betaU_dDD[1][2][0]': mpf('-3.59469879181060009166143907294526'), 'betaU_dDD[1][2][1]': mpf('1.03879140080831086038810101219714'), 'betaU_dDD[1][2][2]': mpf('0.429021139775372473874225378432791'), 'betaU_dDD[2][0][0]': mpf('47.7279356778735564316328362884232'), 'betaU_dDD[2][0][1]': mpf('11.3305777369963646737013674981541'), 'betaU_dDD[2][0][2]': mpf('-9.09922406127764796777495296898437'), 'betaU_dDD[2][1][0]': mpf('11.3305777369963646737013674981541'), 'betaU_dDD[2][1][1]': mpf('24.3353794441474582057173283509946'), 'betaU_dDD[2][1][2]': mpf('-3.95193536311042053355897439286505'), 'betaU_dDD[2][2][0]': mpf('-9.09922406127764796777495296898437'), 'betaU_dDD[2][2][1]': mpf('-3.95193536311042053355897439286505'), 'betaU_dDD[2][2][2]': mpf('0.749372685256775991946308530989456')}# Generated on: 2019-08-09trusted_values_dict['BSSN_quantities__phi_and_derivs__globals'] = {'phi_dD[0]': mpf('-1.13647037353523967950954390927125'), 'phi_dD[1]': mpf('-1.37882238967032079487109408639122'), 'phi_dD[2]': mpf('-1.23865565471203051564572756374677'), 'phi_dupD[0]': mpf('-1.30437304716054772824033366627827'), 'phi_dupD[1]': mpf('-0.387439729438011521402787682064875'), 'phi_dupD[2]': mpf('-1.286536248178407847990777607347'), 'phi_dDD[0][0]': mpf('1.41350298031869520561660429447829'), 'phi_dDD[0][1]': mpf('2.60287661327406578686593533352924'), 'phi_dDD[0][2]': mpf('2.40978752502737233244962940835342'), 'phi_dDD[1][0]': mpf('2.60287661327406578686593533352924'), 'phi_dDD[1][1]': mpf('3.41285382262798172893551850424285'), 'phi_dDD[1][2]': mpf('3.0612083554957324225454264680395'), 'phi_dDD[2][0]': mpf('2.40978752502737233244962940835342'), 'phi_dDD[2][1]': mpf('3.0612083554957324225454264680395'), 'phi_dDD[2][2]': mpf('2.10516420696710843004822415147254'), 'exp_m4phi': mpf('0.113544429071223891132192393151795'), 'phi_dBarD[0]': mpf('-1.13647037353523967950954390927125'), 'phi_dBarD[1]': mpf('-1.37882238967032079487109408639122'), 'phi_dBarD[2]': mpf('-1.23865565471203051564572756374677'), 'phi_dBarDD[0][0]': mpf('236.194201114655255326559793477184'), 'phi_dBarDD[0][1]': mpf('95.1087520363466622986255911257178'), 'phi_dBarDD[0][2]': mpf('35.7199091574093810655803917372351'), 'phi_dBarDD[1][0]': mpf('95.1087520363466622986255911257178'), 'phi_dBarDD[1][1]': mpf('11.7211452920461024221333792078154'), 'phi_dBarDD[1][2]': mpf('-22.3188329171420787008183405055411'), 'phi_dBarDD[2][0]': mpf('35.7199091574093810655803917372351'), 'phi_dBarDD[2][1]': mpf('-22.3188329171420787008183405055411'), 'phi_dBarDD[2][2]': mpf('-18.8021112171325449817326637076808')}# Generated on: 2019-09-03trusted_values_dict['BrillLindquist__BrillLindquist__ComputeADMGlobalsOnly_True__globals'] = {'alphaCart': mpf('0.343480750893445797669295337903236'), 'betaCartU[0]': mpf('0.0'), 'betaCartU[1]': mpf('0.0'), 'betaCartU[2]': mpf('0.0'), 'BCartU[0]': mpf('0.0'), 'BCartU[1]': mpf('0.0'), 'BCartU[2]': mpf('0.0'), 'gammaCartDD[0][0]': mpf('8.47608284216415538664572854966934'), 'gammaCartDD[0][1]': mpf('0.0'), 'gammaCartDD[0][2]': mpf('0.0'), 'gammaCartDD[1][0]': mpf('0.0'), 'gammaCartDD[1][1]': mpf('8.47608284216415538664572854966934'), 'gammaCartDD[1][2]': mpf('0.0'), 'gammaCartDD[2][0]': mpf('0.0'), 'gammaCartDD[2][1]': mpf('0.0'), 'gammaCartDD[2][2]': mpf('8.47608284216415538664572854966934'), 'KCartDD[0][0]': mpf('0.0'), 'KCartDD[0][1]': mpf('0.0'), 'KCartDD[0][2]': mpf('0.0'), 'KCartDD[1][0]': mpf('0.0'), 'KCartDD[1][1]': mpf('0.0'), 'KCartDD[1][2]': mpf('0.0'), 'KCartDD[2][0]': mpf('0.0'), 'KCartDD[2][1]': mpf('0.0'), 'KCartDD[2][2]': mpf('0.0')}# Generated on: 2019-09-03trusted_values_dict['Psi4__Psi4__specify_tetrad_False__globals'] = {'psi4_re_pt[0]': mpf('-11.4627408385133346012203475168749'), 'psi4_re_pt[1]': mpf('-35.6806714906029645727316589574499'), 'psi4_re_pt[2]': mpf('-3374.92496104893019517395960329346'), 'psi4_im_pt[0]': mpf('7.17626585537563385139665194926662'), 'psi4_im_pt[1]': mpf('103.321768247585408574682983348206'), 'psi4_im_pt[2]': mpf('-1785.88265198482805325630868693525')}# Generated on: 2019-09-03trusted_values_dict['ShiftedKerrSchild__ShiftedKerrSchild__ComputeADMGlobalsOnly_True__globals'] = {'alphaSph': mpf('0.764992222074068488402374263959388'), 'betaSphU[0]': mpf('0.414786900166179080948286822502086'), 'betaSphU[1]': mpf('0.0'), 'betaSphU[2]': mpf('0.0'), 'BSphU[0]': mpf('0.0'), 'BSphU[1]': mpf('0.0'), 'BSphU[2]': mpf('0.0'), 'gammaSphDD[0][0]': mpf('1.70877924688282501671697638255698'), 'gammaSphDD[0][1]': mpf('0.0'), 'gammaSphDD[0][2]': mpf('-0.34407721284779690446451905546302'), 'gammaSphDD[1][0]': mpf('0.0'), 'gammaSphDD[1][1]': mpf('0.83749814889950038479162273698221'), 'gammaSphDD[1][2]': mpf('0.0'), 'gammaSphDD[2][0]': mpf('-0.34407721284779690446451905546302'), 'gammaSphDD[2][1]': mpf('0.0'), 'gammaSphDD[2][2]': mpf('0.428211355345928897234853289336263'), 'KSphDD[0][0]': mpf('-0.608416975836176206520434449342952'), 'KSphDD[0][1]': mpf('0.0707242913409545835190603089766082'), 'KSphDD[0][2]': mpf('0.0772829375209889643435925308431919'), 'KSphDD[1][0]': mpf('0.0707242913409545835190603089766082'), 'KSphDD[1][1]': mpf('0.457311525223526834585984744200641'), 'KSphDD[1][2]': mpf('-0.0142409366743087039035851689662884'), 'KSphDD[2][0]': mpf('0.0772829375209889643435925308431919'), 'KSphDD[2][1]': mpf('-0.0142409366743087039035851689662884'), 'KSphDD[2][2]': mpf('0.189536302720822065090385756720081')}# Generated on: 2019-09-03trusted_values_dict['StaticTrumpet__StaticTrumpet__ComputeADMGlobalsOnly_True__globals'] = {'alphaSph': mpf('0.47901157071628237535174768234896'), 'betaSphU[0]': mpf('0.249559485836202384477547321977731'), 'betaSphU[1]': mpf('0.0'), 'betaSphU[2]': mpf('0.0'), 'BSphU[0]': mpf('0.0'), 'BSphU[1]': mpf('0.0'), 'BSphU[2]': mpf('0.0'), 'gammaSphDD[0][0]': mpf('4.35820838377928180149222863568597'), 'gammaSphDD[0][1]': mpf('0.0'), 'gammaSphDD[0][2]': mpf('0.0'), 'gammaSphDD[1][0]': mpf('0.0'), 'gammaSphDD[1][1]': mpf('0.456231514782622374769913065861258'), 'gammaSphDD[1][2]': mpf('0.0'), 'gammaSphDD[2][0]': mpf('0.0'), 'gammaSphDD[2][1]': mpf('0.0'), 'gammaSphDD[2][2]': mpf('0.19552817796951759898685705719116'), 'KSphDD[0][0]': mpf('-3.36157982955715545881983739302993'), 'KSphDD[0][1]': mpf('0.0'), 'KSphDD[0][2]': mpf('0.0'), 'KSphDD[1][0]': mpf('0.0'), 'KSphDD[1][1]': mpf('0.351901176504010315682080545229837'), 'KSphDD[1][2]': mpf('0.0'), 'KSphDD[2][0]': mpf('0.0'), 'KSphDD[2][1]': mpf('0.0'), 'KSphDD[2][2]': mpf('0.150815087598546495698285048292878')}# Generated on: 2019-09-03trusted_values_dict['UIUCBlackHole__UIUCBlackHole__ComputeADMGlobalsOnly_True__globals'] = {'alphaSph': mpf('1.0'), 'betaSphU[0]': mpf('0.0'), 'betaSphU[1]': mpf('0.0'), 'betaSphU[2]': mpf('0.0'), 'BSphU[0]': mpf('0.0'), 'BSphU[1]': mpf('0.0'), 'BSphU[2]': mpf('0.0'), 'gammaSphDD[0][0]': mpf('5.88800397535091508054696345959799'), 'gammaSphDD[0][1]': mpf('0.0'), 'gammaSphDD[0][2]': mpf('0.0'), 'gammaSphDD[1][0]': mpf('0.0'), 'gammaSphDD[1][1]': mpf('0.49579570354855419371061261468577'), 'gammaSphDD[1][2]': mpf('0.0'), 'gammaSphDD[2][0]': mpf('0.0'), 'gammaSphDD[2][1]': mpf('0.0'), 'gammaSphDD[2][2]': mpf('0.239531368774223457427342816780148'), 'KSphDD[0][0]': mpf('0.0'), 'KSphDD[0][1]': mpf('0.0'), 'KSphDD[0][2]': mpf('0.516384223238703786717270771044344'), 'KSphDD[1][0]': mpf('0.0'), 'KSphDD[1][1]': mpf('0.0'), 'KSphDD[1][2]': mpf('-0.00263738331117854302766878470676251'), 'KSphDD[2][0]': mpf('0.516384223238703786717270771044344'), 'KSphDD[2][1]': mpf('-0.00263738331117854302766878470676251'), 'KSphDD[2][2]': mpf('0.0')}# Generated on: 2019-10-08trusted_values_dict['ADMBSSN_tofrom_4metric__g4DD_ito_BSSN_or_ADM___ADM___globals'] = {'g4DD[0][0]': mpf('1.42770464273047624140299713522594'), 'g4DD[0][1]': mpf('0.813388473397507463814385913308194'), 'g4DD[0][2]': mpf('0.652706348793296836714132090802973'), 'g4DD[0][3]': mpf('1.22429414375154980405074869244046'), 'g4DD[1][0]': mpf('0.813388473397507463814385913308194'), 'g4DD[1][1]': mpf('0.657497767033916602485987823456526'), 'g4DD[1][2]': mpf('0.0577387051674528306577371949970257'), 'g4DD[1][3]': mpf('0.391026617743468030141684721456841'), 'g4DD[2][0]': mpf('0.652706348793296836714132090802973'), 'g4DD[2][1]': mpf('0.0577387051674528306577371949970257'), 'g4DD[2][2]': mpf('0.14235077874207879844448143558111'), 'g4DD[2][3]': mpf('0.723120760610660329170684690325288'), 'g4DD[3][0]': mpf('1.22429414375154980405074869244046'), 'g4DD[3][1]': mpf('0.391026617743468030141684721456841'), 'g4DD[3][2]': mpf('0.723120760610660329170684690325288'), 'g4DD[3][3]': mpf('0.919283767179900235255729512573453')}# Generated on: 2019-10-08trusted_values_dict['ADMBSSN_tofrom_4metric__g4UU_ito_BSSN_or_ADM___ADM___globals'] = {'g4UU[0][0]': mpf('-3.03008926847944211197781568780977'), 'g4UU[0][1]': mpf('2.25487680174746330097911429618154'), 'g4UU[0][2]': mpf('0.88396408821931067329277382962707'), 'g4UU[0][3]': mpf('2.38097417962378184338842987036543'), 'g4UU[1][0]': mpf('2.25487680174746330097911429618154'), 'g4UU[1][1]': mpf('-0.109478866681308257858746913532804'), 'g4UU[1][2]': mpf('-1.57673807708112257475456728613969'), 'g4UU[1][3]': mpf('-1.71617440778374167644096697698262'), 'g4UU[2][0]': mpf('0.88396408821931067329277382962707'), 'g4UU[2][1]': mpf('-1.57673807708112257475456728613969'), 'g4UU[2][2]': mpf('-2.06437348264308527564608946533953'), 'g4UU[2][3]': mpf('1.11728919891515454886216209391363'), 'g4UU[3][0]': mpf('2.38097417962378184338842987036543'), 'g4UU[3][1]': mpf('-1.71617440778374167644096697698262'), 'g4UU[3][2]': mpf('1.11728919891515454886216209391363'), 'g4UU[3][3]': mpf('-2.23203972375107587678882970577398')}# Generated on: 2019-10-08trusted_values_dict['ADMBSSN_tofrom_4metric__BSSN_or_ADM_ito_g4DD___ADM___globals'] = {'gammaDD[0][0]': mpf('0.498904274895148658330867874610703'), 'gammaDD[0][1]': mpf('0.252497897757109623917415319738211'), 'gammaDD[0][2]': mpf('0.501283702587057011790250271587865'), 'gammaDD[1][0]': mpf('0.252497897757109623917415319738211'), 'gammaDD[1][1]': mpf('0.974132307468977720610325832240051'), 'gammaDD[1][2]': mpf('0.788410581529429888014703919907333'), 'gammaDD[2][0]': mpf('0.501283702587057011790250271587865'), 'gammaDD[2][1]': mpf('0.788410581529429888014703919907333'), 'gammaDD[2][2]': mpf('0.909148885640877257863223803724395'), 'betaU[0]': mpf('9.06694959302922007806468735643867'), 'betaU[1]': mpf('6.98967266398671524153764426039564'), 'betaU[2]': mpf('-10.826763784327769115585618700949'), 'alpha': mpf('2.9281812371251576982173791733214')}# Generated on: 2019-10-08trusted_values_dict['ADMBSSN_tofrom_4metric__g4DD_ito_BSSN_or_ADM___BSSN___globals'] = {'g4DD[0][0]': mpf('33.9316040782510563053933745757657'), 'g4DD[0][1]': mpf('11.962817515445852455324947838214'), 'g4DD[0][2]': mpf('8.00807061586371404752271503878887'), 'g4DD[0][3]': mpf('3.0744393577022965271968636933869'), 'g4DD[1][0]': mpf('11.962817515445852455324947838214'), 'g4DD[1][1]': mpf('8.84684305820134422150597858207921'), 'g4DD[1][2]': mpf('3.350018689599008046165002833204'), 'g4DD[1][3]': mpf('0.194795767378908960688399288371257'), 'g4DD[2][0]': mpf('8.00807061586371404752271503878887'), 'g4DD[2][1]': mpf('3.350018689599008046165002833204'), 'g4DD[2][2]': mpf('1.92752387150314689143948714387062'), 'g4DD[2][3]': mpf('0.617514215490828029162196536408385'), 'g4DD[3][0]': mpf('3.0744393577022965271968636933869'), 'g4DD[3][1]': mpf('0.194795767378908960688399288371257'), 'g4DD[3][2]': mpf('0.617514215490828029162196536408385'), 'g4DD[3][3]': mpf('0.440219517017598275317485123438443')}# Generated on: 2019-10-08trusted_values_dict['ADMBSSN_tofrom_4metric__g4UU_ito_BSSN_or_ADM___BSSN___globals'] = {'g4UU[0][0]': mpf('-3.03008926847944211197781568780977'), 'g4UU[0][1]': mpf('2.11077129805143422596450042497429'), 'g4UU[0][2]': mpf('4.4314190799497963375295703643971'), 'g4UU[0][3]': mpf('14.0116280048673688065179881220934'), 'g4UU[1][0]': mpf('2.11077129805143422596450042497429'), 'g4UU[1][1]': mpf('-7.75975232758250248342057473161043'), 'g4UU[1][2]': mpf('15.146151050341286192891709193053'), 'g4UU[1][3]': mpf('-32.5538384239792224249547239894336'), 'g4UU[2][0]': mpf('4.4314190799497963375295703643971'), 'g4UU[2][1]': mpf('15.146151050341286192891709193053'), 'g4UU[2][2]': mpf('-58.3968465178062189938977785341917'), 'g4UU[2][3]': mpf('44.2650695045030422092937754418837'), 'g4UU[3][0]': mpf('14.0116280048673688065179881220934'), 'g4UU[3][1]': mpf('-32.5538384239792224249547239894336'), 'g4UU[3][2]': mpf('44.2650695045030422092937754418837'), 'g4UU[3][3]': mpf('-143.271385972918464696654248758534')}# Generated on: 2019-10-08trusted_values_dict['ADMBSSN_tofrom_4metric__BSSN_or_ADM_ito_g4DD___BSSN___globals'] = {'hDD[0][0]': mpf('-0.707823822038679430924860360088691'), 'hDD[0][1]': mpf('0.359019871168498611582168252151222'), 'hDD[0][2]': mpf('1.59629921830030516363312220121092'), 'hDD[1][0]': mpf('0.359019871168498611582168252151222'), 'hDD[1][1]': mpf('2.36288339604623268350851551662764'), 'hDD[1][2]': mpf('6.09559777405440062117804245902213'), 'hDD[2][0]': mpf('1.59629921830030516363312220121092'), 'hDD[2][1]': mpf('6.09559777405440062117804245902213'), 'hDD[2][2]': mpf('14.7423246171918635049100138961082'), 'cf': mpf('0.765268415331718015781674002095462'), 'vetU[0]': mpf('9.06694959302922007806468735643867'), 'vetU[1]': mpf('2.87888088365405202711159845187769'), 'vetU[2]': mpf('-1.99111124153992461429422443718632'), 'alpha': mpf('2.9281812371251576982173791733214')}# Generated on: 2019-10-08trusted_values_dict['BSSN_stress_energy_source_terms__stress_energy_source_terms_ito_T4UU_and_ADM_or_BSSN_metricvars___ADM___globals'] = {'SDD[0][0]': mpf('1.80029784665212934056799078226269'), 'SDD[0][1]': mpf('1.39659583030126451047804795612856'), 'SDD[0][2]': mpf('3.00811244695977724176245476191804'), 'SDD[1][0]': mpf('1.39659583030126451047804795612856'), 'SDD[1][1]': mpf('1.22494659231382375810150001831715'), 'SDD[1][2]': mpf('2.50094687070838058316104348117154'), 'SDD[2][0]': mpf('3.00811244695977724176245476191804'), 'SDD[2][1]': mpf('2.50094687070838058316104348117154'), 'SDD[2][2]': mpf('5.32511755805920028174659119741427'), 'SD[0]': mpf('0.608341733349877488954095315599777'), 'SD[1]': mpf('0.470565344820866964820125587278172'), 'SD[2]': mpf('1.12342071849067535252360437426405'), 'S': mpf('5.51886985348101528899497640423697'), 'rho': mpf('0.128468170910047767321502802016049')}# Generated on: 2019-10-08trusted_values_dict['BSSN_stress_energy_source_terms__stress_energy_source_terms_ito_T4UU_and_ADM_or_BSSN_metricvars___BSSN___globals'] = {'SDD[0][0]': mpf('340.54483250614325553458020093047'), 'SDD[0][1]': mpf('193.449779818371076633319750276679'), 'SDD[0][2]': mpf('59.7673665437832411953316595668582'), 'SDD[1][0]': mpf('193.449779818371076633319750276679'), 'SDD[1][1]': mpf('109.367007247314914388974035339596'), 'SDD[1][2]': mpf('33.5362683001178984597875112467598'), 'SDD[2][0]': mpf('59.7673665437832411953316595668582'), 'SDD[2][1]': mpf('33.5362683001178984597875112467598'), 'SDD[2][2]': mpf('10.1607088644086656351007264098463'), 'SD[0]': mpf('8.31158076395254821775662660137348'), 'SD[1]': mpf('4.46081177450846137199550370457638'), 'SD[2]': mpf('1.24975530738365002814654512794839'), 'S': mpf('56.0590719290101215802838899642879'), 'rho': mpf('0.128468170910047767321502802016049')}# Generated on: 2019-10-08trusted_values_dict['BSSN_stress_energy_source_terms__BSSN_source_terms_for_BSSN_RHSs__globals'] = {'sourceterm_trK_rhs': mpf('34.481947192059905389281900539522'), 'sourceterm_a_rhsDD[0][0]': mpf('-24.4205232684807096387985845039797'), 'sourceterm_a_rhsDD[0][1]': mpf('-44.274626076606489686511882243972'), 'sourceterm_a_rhsDD[0][2]': mpf('-42.5329213202643698441006620646304'), 'sourceterm_a_rhsDD[1][0]': mpf('-44.274626076606489686511882243972'), 'sourceterm_a_rhsDD[1][1]': mpf('-60.2567558996127088470902295335831'), 'sourceterm_a_rhsDD[1][2]': mpf('-40.4716414381018667155368392378324'), 'sourceterm_a_rhsDD[2][0]': mpf('-42.5329213202643698441006620646304'), 'sourceterm_a_rhsDD[2][1]': mpf('-40.4716414381018667155368392378324'), 'sourceterm_a_rhsDD[2][2]': mpf('-7.97163159314560426073123653904653'), 'sourceterm_lambda_rhsU[0]': mpf('-12.4024163649413169626935281713898'), 'sourceterm_lambda_rhsU[1]': mpf('-7.90926902901598263785587714011605'), 'sourceterm_lambda_rhsU[2]': mpf('-5.32437139197028910868095764281183'), 'sourceterm_Lambdabar_rhsU[0]': mpf('-12.4024163649413169626935281713898'), 'sourceterm_Lambdabar_rhsU[1]': mpf('-19.2030180331952244454789590045448'), 'sourceterm_Lambdabar_rhsU[2]': mpf('-28.9515272468210212098860497720561')}# Generated on: 2019-10-08trusted_values_dict['BSSN_in_terms_of_ADM__gammabarDD_hDD__gammaDD_None__globals'] = {'gammabarDD[0][0]': mpc(real='0.0934311617845273723048649117117748', imag='0.161827519220989063386539896782779'), 'gammabarDD[0][1]': mpc(real='0.00820473402984368653523272740812899', imag='0.0142110162022786069846436163288672'), 'gammabarDD[0][2]': mpc(real='0.0555653159846578106884074088611669', imag='0.0962419504240464018796075151840341'), 'gammabarDD[1][0]': mpc(real='0.00820473402984368653523272740812899', imag='0.0142110162022786069846436163288672'), 'gammabarDD[1][1]': mpc(real='0.0202282035098053057653455510944696', imag='0.035036276224825878278235080642844'), 'gammabarDD[1][2]': mpc(real='0.102756261940095613982570910138747', imag='0.177979066476101677185539529091329'), 'gammabarDD[2][0]': mpc(real='0.0555653159846578106884074088611669', imag='0.0962419504240464018796075151840341'), 'gammabarDD[2][1]': mpc(real='0.102756261940095613982570910138747', imag='0.177979066476101677185539529091329'), 'gammabarDD[2][2]': mpc(real='0.1306312426956797445587454831184', imag='0.226259949404778087922451845770411'), 'hDD[0][0]': mpc(real='-0.906568838215472627695135088288225', imag='0.161827519220989063386539896782779'), 'hDD[0][1]': mpc(real='0.0199203813847587431207220021178728', imag='0.0345031126645514094053446285670361'), 'hDD[0][2]': mpc(real='0.302139096107031490667793605098268', imag='0.523320265410314511278500049229478'), 'hDD[1][0]': mpc(real='0.0199203813847587431207220021178728', imag='0.0345031126645514094053446285670361'), 'hDD[1][1]': mpc(real='-0.880759552378340582201587949384702', imag='0.206530513597969589412173263553996'), 'hDD[1][2]': mpc(real='1.35657739510377672864649412076687', imag='2.34966097271918039623983531782869'), 'hDD[2][0]': mpc(real='0.302139096107031490667793605098268', imag='0.523320265410314511278500049229478'), 'hDD[2][1]': mpc(real='1.35657739510377672864649412076687', imag='2.34966097271918039623983531782869'), 'hDD[2][2]': mpc(real='2.86236517613411134419720838195644', imag='6.68981272244899649592753121396527')}# Generated on: 2019-10-08trusted_values_dict['BSSN_in_terms_of_ADM__trK_AbarDD_aDD__gammaDD_None_KDD_None__globals'] = {'trK': mpf('1.2095765123256476836242095293423'), 'AbarDD[0][0]': mpc(real='0.0386623707004693575872700250783964', imag='0.0669651903942752452225661841112014'), 'AbarDD[0][1]': mpc(real='0.0197082770012822795779872109278585', imag='0.0341357370958621092471574343107932'), 'AbarDD[0][2]': mpc(real='-0.0116599231388074490306516750592891', imag='-0.0201955792887624809017754756723662'), 'AbarDD[1][0]': mpc(real='0.0197082770012822795779872109278585', imag='0.0341357370958621092471574343107932'), 'AbarDD[1][1]': mpc(real='0.0523135333085628650984233445342397', imag='0.0906096976138776738496360962926701'), 'AbarDD[1][2]': mpc(real='0.0274023107443551947048909767090663', imag='0.0474621944540137424839443269775074'), 'AbarDD[2][0]': mpc(real='-0.0116599231388074490306516750592891', imag='-0.0201955792887624809017754756723662'), 'AbarDD[2][1]': mpc(real='0.0274023107443551947048909767090663', imag='0.0474621944540137424839443269775074'), 'AbarDD[2][2]': mpc(real='0.0773121459494762602870920886743988', imag='0.133908564826673265324430417422263'), 'aDD[0][0]': mpc(real='0.0386623707004693575872700250783964', imag='0.0669651903942752452225661841112014'), 'aDD[0][1]': mpc(real='0.0478499842741998068773590091495862', imag='0.0828786039042858496683763291912328'), 'aDD[0][2]': mpc(real='-0.0634013966339984497144754982400627', imag='-0.109814440240911720403360618547595'), 'aDD[1][0]': mpc(real='0.0478499842741998068773590091495862', imag='0.0828786039042858496683763291912328'), 'aDD[1][1]': mpc(real='0.308375834035874929472953454023809', imag='0.534122612376563332681200790830189'), 'aDD[1][2]': mpc(real='0.361762433038608999247287556499941', imag='0.626590914292604606039560621866258'), 'aDD[2][0]': mpc(real='-0.0634013966339984497144754982400627', imag='-0.109814440240911720403360618547595'), 'aDD[2][1]': mpc(real='0.361762433038608999247287556499941', imag='0.626590914292604606039560621866258'), 'aDD[2][2]': mpc(real='2.28588302495977568895568765583448', imag='3.95926553938956793388115329435095')}# Generated on: 2019-10-08trusted_values_dict['BSSN_in_terms_of_ADM__LambdabarU_lambdaU__exact_gammaDD__gammaDD_None__globals'] = {'LambdabarU[0]': mpc(real='-4.74783841908033465983862697612494', imag='8.22349736797463570781019370770082'), 'LambdabarU[1]': mpc(real='12.33620224866062287105705763679', imag='-21.3669290671256320024440356064588'), 'LambdabarU[2]': mpc(real='-15.5391046195871584956194055848755', imag='26.9145187052532079974298540037125'), 'lambdaU[0]': mpc(real='-4.74783841908033465983862697612494', imag='8.22349736797463570781019370770082'), 'lambdaU[1]': mpc(real='5.08098998877906549154204185470007', imag='-8.80053281331416137334144877968356'), 'lambdaU[2]': mpc(real='-2.85774091943449803920884733088315', imag='4.949752467329147975760861299932')}# Generated on: 2019-10-08trusted_values_dict['BSSN_in_terms_of_ADM__cf_from_gammaDD__gammaDD_None__globals'] = {'cf': mpc(real='0.461683509914074474700385053438367', imag='-0.266553098729302162528398412177921')}# Generated on: 2019-10-08trusted_values_dict['BSSN_in_terms_of_ADM__betU_vetU__betaU_None_BU_None__globals'] = {'vetU[0]': mpf('0.744161838795925789646901193918893'), 'vetU[1]': mpf('0.120156164503744952492307520976668'), 'vetU[2]': mpf('0.144509409106853504997322208612039'), 'betU[0]': mpf('0.53440111094236486533048946512281'), 'betU[1]': mpf('0.216739633922006111369610208272842'), 'betU[2]': mpf('0.00830060552287044152590411578016158')}
# This module provides functions for setting up Curvilinear boundary conditions,# as documented in Tutorial-Start_to_Finish-Curvilinear_BCs.ipynb# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* com# First we import needed core NRPy+ modulesfrom outputC import * # NRPy+: Core C code output moduleimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport grid as gri # NRPy+: Functions having to do with numerical gridsimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport reference_metric as rfm # NRPy+: Reference metric supportimport cmdline_helper as cmd # NRPy+: Multi-platform Python command-line interfaceimport shutil, os, sys # Standard Python modules for multiplatform OS-level functionsdef Set_up_CurviBoundaryConditions(Ccodesdir,verbose=True,Cparamspath=os.path.join("../"),enable_copy_of_static_Ccodes=True):# Step P0: Check that Ccodesdir is not the same as CurviBoundaryConditions/boundary_conditions,# to prevent trusted versions of these C codes from becoming contaminated.if os.path.join(Ccodesdir) == os.path.join("CurviBoundaryConditions", "boundary_conditions"):print("Error: Tried to output boundary conditions C code into CurviBoundaryConditions/boundary_conditions,"" which is not allowed, to prevent trusted versions of these C codes from becoming contaminated.")sys.exit(1)# Step P1: Create the C codes output directory & copy static CurviBC files# from CurviBoundaryConditions/boundary_conditions to Ccodesdir/if enable_copy_of_static_Ccodes:cmd.mkdir(os.path.join(Ccodesdir))for file in ["apply_bcs_curvilinear.h", "BCs_data_structs.h", "bcstruct_freemem.h", "CurviBC_include_Cfunctions.h","driver_bcstruct.h", "set_bcstruct.h", "set_up__bc_gz_map_and_parity_condns.h"]:shutil.copy(os.path.join("nrpytutorial", "CurviBoundaryConditions", "boundary_conditions", file),os.path.join(Ccodesdir))# Step P2: Output correct #include for set_Cparameters.h to# Ccodesdir/boundary_conditions/RELATIVE_PATH__set_Cparameters.hwith open(os.path.join(Ccodesdir, "RELATIVE_PATH__set_Cparameters.h"), "w") as file:file.write("#include \"" + Cparamspath + "/set_Cparameters.h\"\n") # #include's may include forward slashes for paths, even in Windows.# Step 0: Set up reference metric in case it hasn't already been set up.# (Doing it twice hurts nothing).rfm.reference_metric()# Step 1: Set unit-vector dot products (=parity) for each of the 10 parity condition typesparity = ixp.zerorank1(DIM=10)UnitVectors_inner = ixp.zerorank2()xx0_inbounds, xx1_inbounds, xx2_inbounds = sp.symbols("xx0_inbounds xx1_inbounds xx2_inbounds", real=True)for i in range(3):for j in range(3):UnitVectors_inner[i][j] = rfm.UnitVectors[i][j].subs(rfm.xx[0], xx0_inbounds).subs(rfm.xx[1],xx1_inbounds).subs(rfm.xx[2], xx2_inbounds)# Type 0: scalarparity[0] = sp.sympify(1)# Type 1: i0-direction vector or one-form# Type 2: i1-direction vector or one-form# Type 3: i2-direction vector or one-formfor i in range(3):for Type in range(1, 4):parity[Type] += rfm.UnitVectors[Type - 1][i] * UnitVectors_inner[Type - 1][i]# Type 4: i0i0-direction rank-2 tensor# parity[4] = parity[1]*parity[1]# Type 5: i0i1-direction rank-2 tensor# Type 6: i0i2-direction rank-2 tensor# Type 7: i1i1-direction rank-2 tensor# Type 8: i1i2-direction rank-2 tensor# Type 9: i2i2-direction rank-2 tensorcount = 4for i in range(3):for j in range(i, 3):parity[count] = parity[i + 1] * parity[j + 1]count = count + 1lhs_strings = []for i in range(10):lhs_strings.append("parity[" + str(i) + "]")outputC(parity, lhs_strings, os.path.join(Ccodesdir, "parity_conditions_symbolic_dot_products.h"))# Step 2.a: Generate Ccodesdir/gridfunction_defines.h file,# containing human-readable gridfunction aliasesevolved_variables_list, auxiliary_variables_list, auxevol_variables_list = gri.output__gridfunction_defines_h__return_gf_lists(Ccodesdir)# Step 2.b: set the parity conditions on all gridfunctions in gf_list,# based on how many digits are at the end of their namesdef set_parity_types(list_of_gf_names):parity_type = []for name in list_of_gf_names:for gf in gri.glb_gridfcs_list:if gf.name == name:parity_type__orig_len = len(parity_type)if gf.DIM < 3 or gf.DIM > 4:print("Error: Cannot currently specify parity conditions on gridfunctions with DIM<3 or >4.")sys.exit(1)if gf.rank == 0:parity_type.append(0)elif gf.rank == 1:if gf.DIM == 3:parity_type.append(int(gf.name[-1]) + 1) # = 1 for e.g., beta^0; = 2 for e.g., beta^1, etc.elif gf.DIM == 4:parity_type.append(int(gf.name[-1])) # = 0 for e.g., b4^0; = 1 for e.g., beta^1, etc.elif gf.rank == 2:if gf.DIM == 3:# element of a list; a[-2] the# second-to-last element, etc.idx0 = gf.name[-2]idx1 = gf.name[-1]if idx0 == "0" and idx1 == "0":parity_type.append(4)elif (idx0 == "0" and idx1 == "1") or (idx0 == "1" and idx1 == "0"):parity_type.append(5)elif (idx0 == "0" and idx1 == "2") or (idx0 == "2" and idx1 == "0"):parity_type.append(6)elif idx0 == "1" and idx1 == "1":parity_type.append(7)elif (idx0 == "1" and idx1 == "2") or (idx0 == "2" and idx1 == "1"):parity_type.append(8)elif idx0 == "2" and idx1 == "2":parity_type.append(9)elif gf.DIM == 4:idx0 = gf.name[-2]idx1 = gf.name[-1]# g4DD00 = g_{tt} : parity type = 0# g4DD01 = g_{tx} : parity type = 1# g4DD02 = g_{ty} : parity type = 2# g4DD0a = g_{ta} : parity type = aif idx0 == "0":parity_type.append(int(idx1))elif idx1 == "0":parity_type.append(int(idx0))if idx0 == "1" and idx1 == "1":parity_type.append(4)elif (idx0 == "1" and idx1 == "2") or (idx0 == "2" and idx1 == "1"):parity_type.append(5)elif (idx0 == "1" and idx1 == "3") or (idx0 == "3" and idx1 == "1"):parity_type.append(6)elif idx0 == "2" and idx1 == "2":parity_type.append(7)elif (idx0 == "2" and idx1 == "3") or (idx0 == "3" and idx1 == "2"):parity_type.append(8)elif idx0 == "3" and idx1 == "3":parity_type.append(9)if len(parity_type) == parity_type__orig_len:print("Error: Could not figure out parity type for "+gf.gftype+" gridfunction: " + gf.name,gf.DIM,gf.name[-2],gf.name[-1],gf.rank)sys.exit(1)if len(parity_type) != len(list_of_gf_names):print("Error: For some reason the length of the parity types list did not match the length of the gf list.")sys.exit(1)return parity_typeevol_parity_type = set_parity_types(evolved_variables_list)aux_parity_type = set_parity_types(auxiliary_variables_list)auxevol_parity_type = set_parity_types(auxevol_variables_list)# Step 2.c: Output all gridfunctions to Ccodesdir+"/gridfunction_defines.h"# ... then append to the file the parity type for each gridfunction.with open(os.path.join(Ccodesdir, "gridfunction_defines.h"), "a") as file:file.write("\n\n/* PARITY TYPES FOR ALL GRIDFUNCTIONS.\n")file.write(" SEE \"Tutorial-Start_to_Finish-Curvilinear_BCs.ipynb\" FOR DEFINITIONS. */\n")if len(evolved_variables_list) > 0:file.write("const int8_t evol_gf_parity[" + str(len(evolved_variables_list)) + "] = { ")for i in range(len(evolved_variables_list) - 1):file.write(str(evol_parity_type[i]) + ", ")file.write(str(evol_parity_type[len(evolved_variables_list) - 1]) + " };\n")if len(auxiliary_variables_list) > 0:file.write("const int8_t aux_gf_parity[" + str(len(auxiliary_variables_list)) + "] = { ")for i in range(len(auxiliary_variables_list) - 1):file.write(str(aux_parity_type[i]) + ", ")file.write(str(aux_parity_type[len(auxiliary_variables_list) - 1]) + " };\n")if len(auxevol_variables_list) > 0:file.write("const int8_t auxevol_gf_parity[" + str(len(auxevol_variables_list)) + "] = { ")for i in range(len(auxevol_variables_list) - 1):file.write(str(auxevol_parity_type[i]) + ", ")file.write(str(auxevol_parity_type[len(auxevol_variables_list) - 1]) + " };\n")if verbose == True:for i in range(len(evolved_variables_list)):print("Evolved gridfunction \"" + evolved_variables_list[i] + "\" has parity type " + str(evol_parity_type[i]) + ".")for i in range(len(auxiliary_variables_list)):print("Auxiliary gridfunction \"" + auxiliary_variables_list[i] + "\" has parity type " + str(aux_parity_type[i]) + ".")for i in range(len(auxevol_variables_list)):print("AuxEvol gridfunction \"" + auxevol_variables_list[i] + "\" has parity type " + str(auxevol_parity_type[i]) + ".")# Step 3: Find the Eigen-Coordinate and set up the Eigen-Coordinate's reference metric:CoordSystem_orig = par.parval_from_str("reference_metric::CoordSystem")par.set_parval_from_str("reference_metric::CoordSystem", rfm.get_EigenCoord())rfm.reference_metric()# Step 4: Output C code for the Eigen-Coordinate mapping from xx->Cartesian:rfm.xxCart_h("EigenCoord_xxCart", os.path.join(Cparamspath,"set_Cparameters.h"), os.path.join(Ccodesdir, "EigenCoord_xxCart.h"))# Step 5: Output the Eigen-Coordinate mapping from Cartesian->xx:# Step 5.a: Sanity check: First make sure that rfm.Cart_to_xx has been set. Error out if not!if rfm.Cart_to_xx[0] == 0 or rfm.Cart_to_xx[1] == 0 or rfm.Cart_to_xx[2] == 0:print("ERROR: rfm.Cart_to_xx[], which maps Cartesian -> xx, has not been set for")print(" reference_metric::CoordSystem = " + par.parval_from_str("reference_metric::CoordSystem"))print(" Boundary conditions in curvilinear coordinates REQUIRE this be set.")sys.exit(1)# Step 5.b: Output C code for the Eigen-Coordinate mapping from Cartesian->xx:outputC([rfm.Cart_to_xx[0], rfm.Cart_to_xx[1], rfm.Cart_to_xx[2]],["Cart_to_xx0_inbounds", "Cart_to_xx1_inbounds", "Cart_to_xx2_inbounds"],os.path.join(Ccodesdir, "EigenCoord_Cart_to_xx.h"))# Step 6: Restore reference_metric::CoordSystem back to the original CoordSystempar.set_parval_from_str("reference_metric::CoordSystem", CoordSystem_orig)rfm.reference_metric()
7c7< #include "Logo.c"---> //#include "Logo.c"16c16< printf("\x1B[32mID: %s, Evol: %s, Coords: %s, FD order: %d\x1B[0m\n", params.ID_scheme,params.Evol_scheme,params.CoordSystem, params.FDCENTERDERIVS_FDORDER);---> // printf("\x1B[32mID: %s, Evol: %s, Coords: %s, FD order: %d\x1B[0m\n", params.ID_scheme,params.Evol_scheme,params.CoordSystem, params.FDCENTERDERIVS_FDORDER);189a190,205> LOOP_GZFILL(ii,jj,kk) {> int which_gf = 0;> gfs_n[IDX4(VET1,ii,jj,kk)] = (REAL)IDX4(which_gf,ii,jj,kk); which_gf++;> gfs_n[IDX4(VET2,ii,jj,kk)] = (REAL)IDX4(which_gf,ii,jj,kk); which_gf++;> gfs_n[IDX4(VET3,ii,jj,kk)] = (REAL)IDX4(which_gf,ii,jj,kk); which_gf++;>> gfs_n[IDX4(A11,ii,jj,kk)] = (REAL)IDX4(which_gf,ii,jj,kk); which_gf++;> gfs_n[IDX4(A12,ii,jj,kk)] = (REAL)IDX4(which_gf,ii,jj,kk); which_gf++;> gfs_n[IDX4(A13,ii,jj,kk)] = (REAL)IDX4(which_gf,ii,jj,kk); which_gf++;> gfs_n[IDX4(A22,ii,jj,kk)] = (REAL)IDX4(which_gf,ii,jj,kk); which_gf++;> gfs_n[IDX4(A23,ii,jj,kk)] = (REAL)IDX4(which_gf,ii,jj,kk); which_gf++;> gfs_n[IDX4(A33,ii,jj,kk)] = (REAL)IDX4(which_gf,ii,jj,kk); which_gf++;>> gfs_n[IDX4(CF,ii,jj,kk)] = (REAL)IDX4(which_gf,ii,jj,kk); which_gf++;> }>195a212,230> LOOP_GZFILL(ii,jj,kk) {> int which_gf = 0;> printf("%d %d %d | ",ii,jj,kk);> printf("%d ",(int)gfs_n[IDX4(VET1,ii,jj,kk)]);> printf("%d ",(int)gfs_n[IDX4(VET2,ii,jj,kk)]);> printf("%d ",(int)gfs_n[IDX4(VET3,ii,jj,kk)]);>> printf("%d ",(int)gfs_n[IDX4(A11,ii,jj,kk)]);> printf("%d ",(int)gfs_n[IDX4(A12,ii,jj,kk)]);> printf("%d ",(int)gfs_n[IDX4(A13,ii,jj,kk)]);> printf("%d ",(int)gfs_n[IDX4(A22,ii,jj,kk)]);> printf("%d ",(int)gfs_n[IDX4(A23,ii,jj,kk)]);> printf("%d ",(int)gfs_n[IDX4(A33,ii,jj,kk)]);>> printf("%d ",(int)gfs_n[IDX4(CF,ii,jj,kk)]);> printf("\n");> }> exit(0);>
0 0 0 | -65 -1065 2065 3065 4065 -5065 6065 -7065 8065 90651 0 0 | -64 -1064 2064 3064 4064 -5064 6064 -7064 8064 90642 0 0 | -63 -1063 2063 3063 4063 -5063 6063 -7063 8063 90633 0 0 | 43 1043 2043 3043 4043 5043 6043 7043 8043 90434 0 0 | 44 1044 2044 3044 4044 5044 6044 7044 8044 90445 0 0 | 45 1045 2045 3045 4045 5045 6045 7045 8045 90456 0 0 | 46 1046 2046 3046 4046 5046 6046 7046 8046 90467 0 0 | 47 1047 2047 3047 4047 5047 6047 7047 8047 90478 0 0 | 48 1048 2048 3048 4048 5048 6048 7048 8048 90489 0 0 | 49 1049 2049 3049 4049 5049 6049 7049 8049 90490 1 0 | -35 -1035 2035 3035 4035 -5035 6035 -7035 8035 90351 1 0 | -34 -1034 2034 3034 4034 -5034 6034 -7034 8034 90342 1 0 | -33 -1033 2033 3033 4033 -5033 6033 -7033 8033 90333 1 0 | 53 1053 2053 3053 4053 5053 6053 7053 8053 90534 1 0 | 54 1054 2054 3054 4054 5054 6054 7054 8054 90545 1 0 | 55 1055 2055 3055 4055 5055 6055 7055 8055 90556 1 0 | 56 1056 2056 3056 4056 5056 6056 7056 8056 90567 1 0 | 57 1057 2057 3057 4057 5057 6057 7057 8057 90578 1 0 | 58 1058 2058 3058 4058 5058 6058 7058 8058 90589 1 0 | 59 1059 2059 3059 4059 5059 6059 7059 8059 90590 2 0 | -45 -1045 2045 3045 4045 -5045 6045 -7045 8045 90451 2 0 | -44 -1044 2044 3044 4044 -5044 6044 -7044 8044 90442 2 0 | -43 -1043 2043 3043 4043 -5043 6043 -7043 8043 90433 2 0 | 63 1063 2063 3063 4063 5063 6063 7063 8063 90634 2 0 | 64 1064 2064 3064 4064 5064 6064 7064 8064 90645 2 0 | 65 1065 2065 3065 4065 5065 6065 7065 8065 90656 2 0 | 66 1066 2066 3066 4066 5066 6066 7066 8066 90667 2 0 | 67 1067 2067 3067 4067 5067 6067 7067 8067 90678 2 0 | 68 1068 2068 3068 4068 5068 6068 7068 8068 90689 2 0 | 69 1069 2069 3069 4069 5069 6069 7069 8069 90690 3 0 | -55 -1055 2055 3055 4055 -5055 6055 -7055 8055 90551 3 0 | -54 -1054 2054 3054 4054 -5054 6054 -7054 8054 90542 3 0 | -53 -1053 2053 3053 4053 -5053 6053 -7053 8053 90533 3 0 | 33 1033 2033 3033 4033 5033 6033 7033 8033 90334 3 0 | 34 1034 2034 3034 4034 5034 6034 7034 8034 90345 3 0 | 35 1035 2035 3035 4035 5035 6035 7035 8035 90356 3 0 | 36 1036 2036 3036 4036 5036 6036 7036 8036 90367 3 0 | 37 1037 2037 3037 4037 5037 6037 7037 8037 90378 3 0 | 38 1038 2038 3038 4038 5038 6038 7038 8038 90389 3 0 | 39 1039 2039 3039 4039 5039 6039 7039 8039 90390 4 0 | -65 -1065 2065 3065 4065 -5065 6065 -7065 8065 90651 4 0 | -64 -1064 2064 3064 4064 -5064 6064 -7064 8064 90642 4 0 | -63 -1063 2063 3063 4063 -5063 6063 -7063 8063 90633 4 0 | 43 1043 2043 3043 4043 5043 6043 7043 8043 90434 4 0 | 44 1044 2044 3044 4044 5044 6044 7044 8044 90445 4 0 | 45 1045 2045 3045 4045 5045 6045 7045 8045 90456 4 0 | 46 1046 2046 3046 4046 5046 6046 7046 8046 90467 4 0 | 47 1047 2047 3047 4047 5047 6047 7047 8047 90478 4 0 | 48 1048 2048 3048 4048 5048 6048 7048 8048 90489 4 0 | 49 1049 2049 3049 4049 5049 6049 7049 8049 90490 5 0 | -35 -1035 2035 3035 4035 -5035 6035 -7035 8035 90351 5 0 | -34 -1034 2034 3034 4034 -5034 6034 -7034 8034 90342 5 0 | -33 -1033 2033 3033 4033 -5033 6033 -7033 8033 90333 5 0 | 53 1053 2053 3053 4053 5053 6053 7053 8053 90534 5 0 | 54 1054 2054 3054 4054 5054 6054 7054 8054 90545 5 0 | 55 1055 2055 3055 4055 5055 6055 7055 8055 90556 5 0 | 56 1056 2056 3056 4056 5056 6056 7056 8056 90567 5 0 | 57 1057 2057 3057 4057 5057 6057 7057 8057 90578 5 0 | 58 1058 2058 3058 4058 5058 6058 7058 8058 90589 5 0 | 59 1059 2059 3059 4059 5059 6059 7059 8059 90590 6 0 | -45 -1045 2045 3045 4045 -5045 6045 -7045 8045 90451 6 0 | -44 -1044 2044 3044 4044 -5044 6044 -7044 8044 90442 6 0 | -43 -1043 2043 3043 4043 -5043 6043 -7043 8043 90433 6 0 | 63 1063 2063 3063 4063 5063 6063 7063 8063 90634 6 0 | 64 1064 2064 3064 4064 5064 6064 7064 8064 90645 6 0 | 65 1065 2065 3065 4065 5065 6065 7065 8065 90656 6 0 | 66 1066 2066 3066 4066 5066 6066 7066 8066 90667 6 0 | 67 1067 2067 3067 4067 5067 6067 7067 8067 90678 6 0 | 68 1068 2068 3068 4068 5068 6068 7068 8068 90689 6 0 | 69 1069 2069 3069 4069 5069 6069 7069 8069 90690 7 0 | -55 -1055 2055 3055 4055 -5055 6055 -7055 8055 90551 7 0 | -54 -1054 2054 3054 4054 -5054 6054 -7054 8054 90542 7 0 | -53 -1053 2053 3053 4053 -5053 6053 -7053 8053 90533 7 0 | 33 1033 2033 3033 4033 5033 6033 7033 8033 90334 7 0 | 34 1034 2034 3034 4034 5034 6034 7034 8034 90345 7 0 | 35 1035 2035 3035 4035 5035 6035 7035 8035 90356 7 0 | 36 1036 2036 3036 4036 5036 6036 7036 8036 90367 7 0 | 37 1037 2037 3037 4037 5037 6037 7037 8037 90378 7 0 | 38 1038 2038 3038 4038 5038 6038 7038 8038 90389 7 0 | 39 1039 2039 3039 4039 5039 6039 7039 8039 90390 8 0 | -65 -1065 2065 3065 4065 -5065 6065 -7065 8065 90651 8 0 | -64 -1064 2064 3064 4064 -5064 6064 -7064 8064 90642 8 0 | -63 -1063 2063 3063 4063 -5063 6063 -7063 8063 90633 8 0 | 43 1043 2043 3043 4043 5043 6043 7043 8043 90434 8 0 | 44 1044 2044 3044 4044 5044 6044 7044 8044 90445 8 0 | 45 1045 2045 3045 4045 5045 6045 7045 8045 90456 8 0 | 46 1046 2046 3046 4046 5046 6046 7046 8046 90467 8 0 | 47 1047 2047 3047 4047 5047 6047 7047 8047 90478 8 0 | 48 1048 2048 3048 4048 5048 6048 7048 8048 90489 8 0 | 49 1049 2049 3049 4049 5049 6049 7049 8049 90490 9 0 | -35 -1035 2035 3035 4035 -5035 6035 -7035 8035 90351 9 0 | -34 -1034 2034 3034 4034 -5034 6034 -7034 8034 90342 9 0 | -33 -1033 2033 3033 4033 -5033 6033 -7033 8033 90333 9 0 | 53 1053 2053 3053 4053 5053 6053 7053 8053 90534 9 0 | 54 1054 2054 3054 4054 5054 6054 7054 8054 90545 9 0 | 55 1055 2055 3055 4055 5055 6055 7055 8055 90556 9 0 | 56 1056 2056 3056 4056 5056 6056 7056 8056 90567 9 0 | 57 1057 2057 3057 4057 5057 6057 7057 8057 90578 9 0 | 58 1058 2058 3058 4058 5058 6058 7058 8058 90589 9 0 | 59 1059 2059 3059 4059 5059 6059 7059 8059 90590 0 1 | -165 -1165 2165 3165 4165 -5165 6165 -7165 8165 91651 0 1 | -164 -1164 2164 3164 4164 -5164 6164 -7164 8164 91642 0 1 | -163 -1163 2163 3163 4163 -5163 6163 -7163 8163 91633 0 1 | 143 1143 2143 3143 4143 5143 6143 7143 8143 91434 0 1 | 144 1144 2144 3144 4144 5144 6144 7144 8144 91445 0 1 | 145 1145 2145 3145 4145 5145 6145 7145 8145 91456 0 1 | 146 1146 2146 3146 4146 5146 6146 7146 8146 91467 0 1 | 147 1147 2147 3147 4147 5147 6147 7147 8147 91478 0 1 | 148 1148 2148 3148 4148 5148 6148 7148 8148 91489 0 1 | 149 1149 2149 3149 4149 5149 6149 7149 8149 91490 1 1 | -135 -1135 2135 3135 4135 -5135 6135 -7135 8135 91351 1 1 | -134 -1134 2134 3134 4134 -5134 6134 -7134 8134 91342 1 1 | -133 -1133 2133 3133 4133 -5133 6133 -7133 8133 91333 1 1 | 153 1153 2153 3153 4153 5153 6153 7153 8153 91534 1 1 | 154 1154 2154 3154 4154 5154 6154 7154 8154 91545 1 1 | 155 1155 2155 3155 4155 5155 6155 7155 8155 91556 1 1 | 156 1156 2156 3156 4156 5156 6156 7156 8156 91567 1 1 | 157 1157 2157 3157 4157 5157 6157 7157 8157 91578 1 1 | 158 1158 2158 3158 4158 5158 6158 7158 8158 91589 1 1 | 159 1159 2159 3159 4159 5159 6159 7159 8159 91590 2 1 | -145 -1145 2145 3145 4145 -5145 6145 -7145 8145 91451 2 1 | -144 -1144 2144 3144 4144 -5144 6144 -7144 8144 91442 2 1 | -143 -1143 2143 3143 4143 -5143 6143 -7143 8143 91433 2 1 | 163 1163 2163 3163 4163 5163 6163 7163 8163 91634 2 1 | 164 1164 2164 3164 4164 5164 6164 7164 8164 91645 2 1 | 165 1165 2165 3165 4165 5165 6165 7165 8165 91656 2 1 | 166 1166 2166 3166 4166 5166 6166 7166 8166 91667 2 1 | 167 1167 2167 3167 4167 5167 6167 7167 8167 91678 2 1 | 168 1168 2168 3168 4168 5168 6168 7168 8168 91689 2 1 | 169 1169 2169 3169 4169 5169 6169 7169 8169 91690 3 1 | -155 -1155 2155 3155 4155 -5155 6155 -7155 8155 91551 3 1 | -154 -1154 2154 3154 4154 -5154 6154 -7154 8154 91542 3 1 | -153 -1153 2153 3153 4153 -5153 6153 -7153 8153 91533 3 1 | 133 1133 2133 3133 4133 5133 6133 7133 8133 91334 3 1 | 134 1134 2134 3134 4134 5134 6134 7134 8134 91345 3 1 | 135 1135 2135 3135 4135 5135 6135 7135 8135 91356 3 1 | 136 1136 2136 3136 4136 5136 6136 7136 8136 91367 3 1 | 137 1137 2137 3137 4137 5137 6137 7137 8137 91378 3 1 | 138 1138 2138 3138 4138 5138 6138 7138 8138 91389 3 1 | 139 1139 2139 3139 4139 5139 6139 7139 8139 91390 4 1 | -165 -1165 2165 3165 4165 -5165 6165 -7165 8165 91651 4 1 | -164 -1164 2164 3164 4164 -5164 6164 -7164 8164 91642 4 1 | -163 -1163 2163 3163 4163 -5163 6163 -7163 8163 91633 4 1 | 143 1143 2143 3143 4143 5143 6143 7143 8143 91434 4 1 | 144 1144 2144 3144 4144 5144 6144 7144 8144 91445 4 1 | 145 1145 2145 3145 4145 5145 6145 7145 8145 91456 4 1 | 146 1146 2146 3146 4146 5146 6146 7146 8146 91467 4 1 | 147 1147 2147 3147 4147 5147 6147 7147 8147 91478 4 1 | 148 1148 2148 3148 4148 5148 6148 7148 8148 91489 4 1 | 149 1149 2149 3149 4149 5149 6149 7149 8149 91490 5 1 | -135 -1135 2135 3135 4135 -5135 6135 -7135 8135 91351 5 1 | -134 -1134 2134 3134 4134 -5134 6134 -7134 8134 91342 5 1 | -133 -1133 2133 3133 4133 -5133 6133 -7133 8133 91333 5 1 | 153 1153 2153 3153 4153 5153 6153 7153 8153 91534 5 1 | 154 1154 2154 3154 4154 5154 6154 7154 8154 91545 5 1 | 155 1155 2155 3155 4155 5155 6155 7155 8155 91556 5 1 | 156 1156 2156 3156 4156 5156 6156 7156 8156 91567 5 1 | 157 1157 2157 3157 4157 5157 6157 7157 8157 91578 5 1 | 158 1158 2158 3158 4158 5158 6158 7158 8158 91589 5 1 | 159 1159 2159 3159 4159 5159 6159 7159 8159 91590 6 1 | -145 -1145 2145 3145 4145 -5145 6145 -7145 8145 91451 6 1 | -144 -1144 2144 3144 4144 -5144 6144 -7144 8144 91442 6 1 | -143 -1143 2143 3143 4143 -5143 6143 -7143 8143 91433 6 1 | 163 1163 2163 3163 4163 5163 6163 7163 8163 91634 6 1 | 164 1164 2164 3164 4164 5164 6164 7164 8164 91645 6 1 | 165 1165 2165 3165 4165 5165 6165 7165 8165 91656 6 1 | 166 1166 2166 3166 4166 5166 6166 7166 8166 91667 6 1 | 167 1167 2167 3167 4167 5167 6167 7167 8167 91678 6 1 | 168 1168 2168 3168 4168 5168 6168 7168 8168 91689 6 1 | 169 1169 2169 3169 4169 5169 6169 7169 8169 91690 7 1 | -155 -1155 2155 3155 4155 -5155 6155 -7155 8155 91551 7 1 | -154 -1154 2154 3154 4154 -5154 6154 -7154 8154 91542 7 1 | -153 -1153 2153 3153 4153 -5153 6153 -7153 8153 91533 7 1 | 133 1133 2133 3133 4133 5133 6133 7133 8133 91334 7 1 | 134 1134 2134 3134 4134 5134 6134 7134 8134 91345 7 1 | 135 1135 2135 3135 4135 5135 6135 7135 8135 91356 7 1 | 136 1136 2136 3136 4136 5136 6136 7136 8136 91367 7 1 | 137 1137 2137 3137 4137 5137 6137 7137 8137 91378 7 1 | 138 1138 2138 3138 4138 5138 6138 7138 8138 91389 7 1 | 139 1139 2139 3139 4139 5139 6139 7139 8139 91390 8 1 | -165 -1165 2165 3165 4165 -5165 6165 -7165 8165 91651 8 1 | -164 -1164 2164 3164 4164 -5164 6164 -7164 8164 91642 8 1 | -163 -1163 2163 3163 4163 -5163 6163 -7163 8163 91633 8 1 | 143 1143 2143 3143 4143 5143 6143 7143 8143 91434 8 1 | 144 1144 2144 3144 4144 5144 6144 7144 8144 91445 8 1 | 145 1145 2145 3145 4145 5145 6145 7145 8145 91456 8 1 | 146 1146 2146 3146 4146 5146 6146 7146 8146 91467 8 1 | 147 1147 2147 3147 4147 5147 6147 7147 8147 91478 8 1 | 148 1148 2148 3148 4148 5148 6148 7148 8148 91489 8 1 | 149 1149 2149 3149 4149 5149 6149 7149 8149 91490 9 1 | -135 -1135 2135 3135 4135 -5135 6135 -7135 8135 91351 9 1 | -134 -1134 2134 3134 4134 -5134 6134 -7134 8134 91342 9 1 | -133 -1133 2133 3133 4133 -5133 6133 -7133 8133 91333 9 1 | 153 1153 2153 3153 4153 5153 6153 7153 8153 91534 9 1 | 154 1154 2154 3154 4154 5154 6154 7154 8154 91545 9 1 | 155 1155 2155 3155 4155 5155 6155 7155 8155 91556 9 1 | 156 1156 2156 3156 4156 5156 6156 7156 8156 91567 9 1 | 157 1157 2157 3157 4157 5157 6157 7157 8157 91578 9 1 | 158 1158 2158 3158 4158 5158 6158 7158 8158 91589 9 1 | 159 1159 2159 3159 4159 5159 6159 7159 8159 91590 0 2 | -265 -1265 2265 3265 4265 -5265 6265 -7265 8265 92651 0 2 | -264 -1264 2264 3264 4264 -5264 6264 -7264 8264 92642 0 2 | -263 -1263 2263 3263 4263 -5263 6263 -7263 8263 92633 0 2 | 243 1243 2243 3243 4243 5243 6243 7243 8243 92434 0 2 | 244 1244 2244 3244 4244 5244 6244 7244 8244 92445 0 2 | 245 1245 2245 3245 4245 5245 6245 7245 8245 92456 0 2 | 246 1246 2246 3246 4246 5246 6246 7246 8246 92467 0 2 | 247 1247 2247 3247 4247 5247 6247 7247 8247 92478 0 2 | 248 1248 2248 3248 4248 5248 6248 7248 8248 92489 0 2 | 249 1249 2249 3249 4249 5249 6249 7249 8249 92490 1 2 | -235 -1235 2235 3235 4235 -5235 6235 -7235 8235 92351 1 2 | -234 -1234 2234 3234 4234 -5234 6234 -7234 8234 92342 1 2 | -233 -1233 2233 3233 4233 -5233 6233 -7233 8233 92333 1 2 | 253 1253 2253 3253 4253 5253 6253 7253 8253 92534 1 2 | 254 1254 2254 3254 4254 5254 6254 7254 8254 92545 1 2 | 255 1255 2255 3255 4255 5255 6255 7255 8255 92556 1 2 | 256 1256 2256 3256 4256 5256 6256 7256 8256 92567 1 2 | 257 1257 2257 3257 4257 5257 6257 7257 8257 92578 1 2 | 258 1258 2258 3258 4258 5258 6258 7258 8258 92589 1 2 | 259 1259 2259 3259 4259 5259 6259 7259 8259 92590 2 2 | -245 -1245 2245 3245 4245 -5245 6245 -7245 8245 92451 2 2 | -244 -1244 2244 3244 4244 -5244 6244 -7244 8244 92442 2 2 | -243 -1243 2243 3243 4243 -5243 6243 -7243 8243 92433 2 2 | 263 1263 2263 3263 4263 5263 6263 7263 8263 92634 2 2 | 264 1264 2264 3264 4264 5264 6264 7264 8264 92645 2 2 | 265 1265 2265 3265 4265 5265 6265 7265 8265 92656 2 2 | 266 1266 2266 3266 4266 5266 6266 7266 8266 92667 2 2 | 267 1267 2267 3267 4267 5267 6267 7267 8267 92678 2 2 | 268 1268 2268 3268 4268 5268 6268 7268 8268 92689 2 2 | 269 1269 2269 3269 4269 5269 6269 7269 8269 92690 3 2 | -255 -1255 2255 3255 4255 -5255 6255 -7255 8255 92551 3 2 | -254 -1254 2254 3254 4254 -5254 6254 -7254 8254 92542 3 2 | -253 -1253 2253 3253 4253 -5253 6253 -7253 8253 92533 3 2 | 233 1233 2233 3233 4233 5233 6233 7233 8233 92334 3 2 | 234 1234 2234 3234 4234 5234 6234 7234 8234 92345 3 2 | 235 1235 2235 3235 4235 5235 6235 7235 8235 92356 3 2 | 236 1236 2236 3236 4236 5236 6236 7236 8236 92367 3 2 | 237 1237 2237 3237 4237 5237 6237 7237 8237 92378 3 2 | 238 1238 2238 3238 4238 5238 6238 7238 8238 92389 3 2 | 239 1239 2239 3239 4239 5239 6239 7239 8239 92390 4 2 | -265 -1265 2265 3265 4265 -5265 6265 -7265 8265 92651 4 2 | -264 -1264 2264 3264 4264 -5264 6264 -7264 8264 92642 4 2 | -263 -1263 2263 3263 4263 -5263 6263 -7263 8263 92633 4 2 | 243 1243 2243 3243 4243 5243 6243 7243 8243 92434 4 2 | 244 1244 2244 3244 4244 5244 6244 7244 8244 92445 4 2 | 245 1245 2245 3245 4245 5245 6245 7245 8245 92456 4 2 | 246 1246 2246 3246 4246 5246 6246 7246 8246 92467 4 2 | 247 1247 2247 3247 4247 5247 6247 7247 8247 92478 4 2 | 248 1248 2248 3248 4248 5248 6248 7248 8248 92489 4 2 | 249 1249 2249 3249 4249 5249 6249 7249 8249 92490 5 2 | -235 -1235 2235 3235 4235 -5235 6235 -7235 8235 92351 5 2 | -234 -1234 2234 3234 4234 -5234 6234 -7234 8234 92342 5 2 | -233 -1233 2233 3233 4233 -5233 6233 -7233 8233 92333 5 2 | 253 1253 2253 3253 4253 5253 6253 7253 8253 92534 5 2 | 254 1254 2254 3254 4254 5254 6254 7254 8254 92545 5 2 | 255 1255 2255 3255 4255 5255 6255 7255 8255 92556 5 2 | 256 1256 2256 3256 4256 5256 6256 7256 8256 92567 5 2 | 257 1257 2257 3257 4257 5257 6257 7257 8257 92578 5 2 | 258 1258 2258 3258 4258 5258 6258 7258 8258 92589 5 2 | 259 1259 2259 3259 4259 5259 6259 7259 8259 92590 6 2 | -245 -1245 2245 3245 4245 -5245 6245 -7245 8245 92451 6 2 | -244 -1244 2244 3244 4244 -5244 6244 -7244 8244 92442 6 2 | -243 -1243 2243 3243 4243 -5243 6243 -7243 8243 92433 6 2 | 263 1263 2263 3263 4263 5263 6263 7263 8263 92634 6 2 | 264 1264 2264 3264 4264 5264 6264 7264 8264 92645 6 2 | 265 1265 2265 3265 4265 5265 6265 7265 8265 92656 6 2 | 266 1266 2266 3266 4266 5266 6266 7266 8266 92667 6 2 | 267 1267 2267 3267 4267 5267 6267 7267 8267 92678 6 2 | 268 1268 2268 3268 4268 5268 6268 7268 8268 92689 6 2 | 269 1269 2269 3269 4269 5269 6269 7269 8269 92690 7 2 | -255 -1255 2255 3255 4255 -5255 6255 -7255 8255 92551 7 2 | -254 -1254 2254 3254 4254 -5254 6254 -7254 8254 92542 7 2 | -253 -1253 2253 3253 4253 -5253 6253 -7253 8253 92533 7 2 | 233 1233 2233 3233 4233 5233 6233 7233 8233 92334 7 2 | 234 1234 2234 3234 4234 5234 6234 7234 8234 92345 7 2 | 235 1235 2235 3235 4235 5235 6235 7235 8235 92356 7 2 | 236 1236 2236 3236 4236 5236 6236 7236 8236 92367 7 2 | 237 1237 2237 3237 4237 5237 6237 7237 8237 92378 7 2 | 238 1238 2238 3238 4238 5238 6238 7238 8238 92389 7 2 | 239 1239 2239 3239 4239 5239 6239 7239 8239 92390 8 2 | -265 -1265 2265 3265 4265 -5265 6265 -7265 8265 92651 8 2 | -264 -1264 2264 3264 4264 -5264 6264 -7264 8264 92642 8 2 | -263 -1263 2263 3263 4263 -5263 6263 -7263 8263 92633 8 2 | 243 1243 2243 3243 4243 5243 6243 7243 8243 92434 8 2 | 244 1244 2244 3244 4244 5244 6244 7244 8244 92445 8 2 | 245 1245 2245 3245 4245 5245 6245 7245 8245 92456 8 2 | 246 1246 2246 3246 4246 5246 6246 7246 8246 92467 8 2 | 247 1247 2247 3247 4247 5247 6247 7247 8247 92478 8 2 | 248 1248 2248 3248 4248 5248 6248 7248 8248 92489 8 2 | 249 1249 2249 3249 4249 5249 6249 7249 8249 92490 9 2 | -235 -1235 2235 3235 4235 -5235 6235 -7235 8235 92351 9 2 | -234 -1234 2234 3234 4234 -5234 6234 -7234 8234 92342 9 2 | -233 -1233 2233 3233 4233 -5233 6233 -7233 8233 92333 9 2 | 253 1253 2253 3253 4253 5253 6253 7253 8253 92534 9 2 | 254 1254 2254 3254 4254 5254 6254 7254 8254 92545 9 2 | 255 1255 2255 3255 4255 5255 6255 7255 8255 92556 9 2 | 256 1256 2256 3256 4256 5256 6256 7256 8256 92567 9 2 | 257 1257 2257 3257 4257 5257 6257 7257 8257 92578 9 2 | 258 1258 2258 3258 4258 5258 6258 7258 8258 92589 9 2 | 259 1259 2259 3259 4259 5259 6259 7259 8259 92590 0 3 | -365 -1365 2365 3365 4365 -5365 6365 -7365 8365 93651 0 3 | -364 -1364 2364 3364 4364 -5364 6364 -7364 8364 93642 0 3 | -363 -1363 2363 3363 4363 -5363 6363 -7363 8363 93633 0 3 | 343 1343 2343 3343 4343 5343 6343 7343 8343 93434 0 3 | 344 1344 2344 3344 4344 5344 6344 7344 8344 93445 0 3 | 345 1345 2345 3345 4345 5345 6345 7345 8345 93456 0 3 | 346 1346 2346 3346 4346 5346 6346 7346 8346 93467 0 3 | 347 1347 2347 3347 4347 5347 6347 7347 8347 93478 0 3 | 348 1348 2348 3348 4348 5348 6348 7348 8348 93489 0 3 | 349 1349 2349 3349 4349 5349 6349 7349 8349 93490 1 3 | -335 -1335 2335 3335 4335 -5335 6335 -7335 8335 93351 1 3 | -334 -1334 2334 3334 4334 -5334 6334 -7334 8334 93342 1 3 | -333 -1333 2333 3333 4333 -5333 6333 -7333 8333 93333 1 3 | 353 1353 2353 3353 4353 5353 6353 7353 8353 93534 1 3 | 354 1354 2354 3354 4354 5354 6354 7354 8354 93545 1 3 | 355 1355 2355 3355 4355 5355 6355 7355 8355 93556 1 3 | 356 1356 2356 3356 4356 5356 6356 7356 8356 93567 1 3 | 357 1357 2357 3357 4357 5357 6357 7357 8357 93578 1 3 | 358 1358 2358 3358 4358 5358 6358 7358 8358 93589 1 3 | 359 1359 2359 3359 4359 5359 6359 7359 8359 93590 2 3 | -345 -1345 2345 3345 4345 -5345 6345 -7345 8345 93451 2 3 | -344 -1344 2344 3344 4344 -5344 6344 -7344 8344 93442 2 3 | -343 -1343 2343 3343 4343 -5343 6343 -7343 8343 93433 2 3 | 363 1363 2363 3363 4363 5363 6363 7363 8363 93634 2 3 | 364 1364 2364 3364 4364 5364 6364 7364 8364 93645 2 3 | 365 1365 2365 3365 4365 5365 6365 7365 8365 93656 2 3 | 366 1366 2366 3366 4366 5366 6366 7366 8366 93667 2 3 | 367 1367 2367 3367 4367 5367 6367 7367 8367 93678 2 3 | 368 1368 2368 3368 4368 5368 6368 7368 8368 93689 2 3 | 369 1369 2369 3369 4369 5369 6369 7369 8369 93690 3 3 | -355 -1355 2355 3355 4355 -5355 6355 -7355 8355 93551 3 3 | -354 -1354 2354 3354 4354 -5354 6354 -7354 8354 93542 3 3 | -353 -1353 2353 3353 4353 -5353 6353 -7353 8353 93533 3 3 | 333 1333 2333 3333 4333 5333 6333 7333 8333 93334 3 3 | 334 1334 2334 3334 4334 5334 6334 7334 8334 93345 3 3 | 335 1335 2335 3335 4335 5335 6335 7335 8335 93356 3 3 | 336 1336 2336 3336 4336 5336 6336 7336 8336 93367 3 3 | 337 1337 2337 3337 4337 5337 6337 7337 8337 93378 3 3 | 338 1338 2338 3338 4338 5338 6338 7338 8338 93389 3 3 | 339 1339 2339 3339 4339 5339 6339 7339 8339 93390 4 3 | -365 -1365 2365 3365 4365 -5365 6365 -7365 8365 93651 4 3 | -364 -1364 2364 3364 4364 -5364 6364 -7364 8364 93642 4 3 | -363 -1363 2363 3363 4363 -5363 6363 -7363 8363 93633 4 3 | 343 1343 2343 3343 4343 5343 6343 7343 8343 93434 4 3 | 344 1344 2344 3344 4344 5344 6344 7344 8344 93445 4 3 | 345 1345 2345 3345 4345 5345 6345 7345 8345 93456 4 3 | 346 1346 2346 3346 4346 5346 6346 7346 8346 93467 4 3 | 347 1347 2347 3347 4347 5347 6347 7347 8347 93478 4 3 | 348 1348 2348 3348 4348 5348 6348 7348 8348 93489 4 3 | 349 1349 2349 3349 4349 5349 6349 7349 8349 93490 5 3 | -335 -1335 2335 3335 4335 -5335 6335 -7335 8335 93351 5 3 | -334 -1334 2334 3334 4334 -5334 6334 -7334 8334 93342 5 3 | -333 -1333 2333 3333 4333 -5333 6333 -7333 8333 93333 5 3 | 353 1353 2353 3353 4353 5353 6353 7353 8353 93534 5 3 | 354 1354 2354 3354 4354 5354 6354 7354 8354 93545 5 3 | 355 1355 2355 3355 4355 5355 6355 7355 8355 93556 5 3 | 356 1356 2356 3356 4356 5356 6356 7356 8356 93567 5 3 | 357 1357 2357 3357 4357 5357 6357 7357 8357 93578 5 3 | 358 1358 2358 3358 4358 5358 6358 7358 8358 93589 5 3 | 359 1359 2359 3359 4359 5359 6359 7359 8359 93590 6 3 | -345 -1345 2345 3345 4345 -5345 6345 -7345 8345 93451 6 3 | -344 -1344 2344 3344 4344 -5344 6344 -7344 8344 93442 6 3 | -343 -1343 2343 3343 4343 -5343 6343 -7343 8343 93433 6 3 | 363 1363 2363 3363 4363 5363 6363 7363 8363 93634 6 3 | 364 1364 2364 3364 4364 5364 6364 7364 8364 93645 6 3 | 365 1365 2365 3365 4365 5365 6365 7365 8365 93656 6 3 | 366 1366 2366 3366 4366 5366 6366 7366 8366 93667 6 3 | 367 1367 2367 3367 4367 5367 6367 7367 8367 93678 6 3 | 368 1368 2368 3368 4368 5368 6368 7368 8368 93689 6 3 | 369 1369 2369 3369 4369 5369 6369 7369 8369 93690 7 3 | -355 -1355 2355 3355 4355 -5355 6355 -7355 8355 93551 7 3 | -354 -1354 2354 3354 4354 -5354 6354 -7354 8354 93542 7 3 | -353 -1353 2353 3353 4353 -5353 6353 -7353 8353 93533 7 3 | 333 1333 2333 3333 4333 5333 6333 7333 8333 93334 7 3 | 334 1334 2334 3334 4334 5334 6334 7334 8334 93345 7 3 | 335 1335 2335 3335 4335 5335 6335 7335 8335 93356 7 3 | 336 1336 2336 3336 4336 5336 6336 7336 8336 93367 7 3 | 337 1337 2337 3337 4337 5337 6337 7337 8337 93378 7 3 | 338 1338 2338 3338 4338 5338 6338 7338 8338 93389 7 3 | 339 1339 2339 3339 4339 5339 6339 7339 8339 93390 8 3 | -365 -1365 2365 3365 4365 -5365 6365 -7365 8365 93651 8 3 | -364 -1364 2364 3364 4364 -5364 6364 -7364 8364 93642 8 3 | -363 -1363 2363 3363 4363 -5363 6363 -7363 8363 93633 8 3 | 343 1343 2343 3343 4343 5343 6343 7343 8343 93434 8 3 | 344 1344 2344 3344 4344 5344 6344 7344 8344 93445 8 3 | 345 1345 2345 3345 4345 5345 6345 7345 8345 93456 8 3 | 346 1346 2346 3346 4346 5346 6346 7346 8346 93467 8 3 | 347 1347 2347 3347 4347 5347 6347 7347 8347 93478 8 3 | 348 1348 2348 3348 4348 5348 6348 7348 8348 93489 8 3 | 349 1349 2349 3349 4349 5349 6349 7349 8349 93490 9 3 | -335 -1335 2335 3335 4335 -5335 6335 -7335 8335 93351 9 3 | -334 -1334 2334 3334 4334 -5334 6334 -7334 8334 93342 9 3 | -333 -1333 2333 3333 4333 -5333 6333 -7333 8333 93333 9 3 | 353 1353 2353 3353 4353 5353 6353 7353 8353 93534 9 3 | 354 1354 2354 3354 4354 5354 6354 7354 8354 93545 9 3 | 355 1355 2355 3355 4355 5355 6355 7355 8355 93556 9 3 | 356 1356 2356 3356 4356 5356 6356 7356 8356 93567 9 3 | 357 1357 2357 3357 4357 5357 6357 7357 8357 93578 9 3 | 358 1358 2358 3358 4358 5358 6358 7358 8358 93589 9 3 | 359 1359 2359 3359 4359 5359 6359 7359 8359 93590 0 4 | -465 -1465 2465 3465 4465 -5465 6465 -7465 8465 94651 0 4 | -464 -1464 2464 3464 4464 -5464 6464 -7464 8464 94642 0 4 | -463 -1463 2463 3463 4463 -5463 6463 -7463 8463 94633 0 4 | 443 1443 2443 3443 4443 5443 6443 7443 8443 94434 0 4 | 444 1444 2444 3444 4444 5444 6444 7444 8444 94445 0 4 | 445 1445 2445 3445 4445 5445 6445 7445 8445 94456 0 4 | 446 1446 2446 3446 4446 5446 6446 7446 8446 94467 0 4 | 447 1447 2447 3447 4447 5447 6447 7447 8447 94478 0 4 | 448 1448 2448 3448 4448 5448 6448 7448 8448 94489 0 4 | 449 1449 2449 3449 4449 5449 6449 7449 8449 94490 1 4 | -435 -1435 2435 3435 4435 -5435 6435 -7435 8435 94351 1 4 | -434 -1434 2434 3434 4434 -5434 6434 -7434 8434 94342 1 4 | -433 -1433 2433 3433 4433 -5433 6433 -7433 8433 94333 1 4 | 453 1453 2453 3453 4453 5453 6453 7453 8453 94534 1 4 | 454 1454 2454 3454 4454 5454 6454 7454 8454 94545 1 4 | 455 1455 2455 3455 4455 5455 6455 7455 8455 94556 1 4 | 456 1456 2456 3456 4456 5456 6456 7456 8456 94567 1 4 | 457 1457 2457 3457 4457 5457 6457 7457 8457 94578 1 4 | 458 1458 2458 3458 4458 5458 6458 7458 8458 94589 1 4 | 459 1459 2459 3459 4459 5459 6459 7459 8459 94590 2 4 | -445 -1445 2445 3445 4445 -5445 6445 -7445 8445 94451 2 4 | -444 -1444 2444 3444 4444 -5444 6444 -7444 8444 94442 2 4 | -443 -1443 2443 3443 4443 -5443 6443 -7443 8443 94433 2 4 | 463 1463 2463 3463 4463 5463 6463 7463 8463 94634 2 4 | 464 1464 2464 3464 4464 5464 6464 7464 8464 94645 2 4 | 465 1465 2465 3465 4465 5465 6465 7465 8465 94656 2 4 | 466 1466 2466 3466 4466 5466 6466 7466 8466 94667 2 4 | 467 1467 2467 3467 4467 5467 6467 7467 8467 94678 2 4 | 468 1468 2468 3468 4468 5468 6468 7468 8468 94689 2 4 | 469 1469 2469 3469 4469 5469 6469 7469 8469 94690 3 4 | -455 -1455 2455 3455 4455 -5455 6455 -7455 8455 94551 3 4 | -454 -1454 2454 3454 4454 -5454 6454 -7454 8454 94542 3 4 | -453 -1453 2453 3453 4453 -5453 6453 -7453 8453 94533 3 4 | 433 1433 2433 3433 4433 5433 6433 7433 8433 94334 3 4 | 434 1434 2434 3434 4434 5434 6434 7434 8434 94345 3 4 | 435 1435 2435 3435 4435 5435 6435 7435 8435 94356 3 4 | 436 1436 2436 3436 4436 5436 6436 7436 8436 94367 3 4 | 437 1437 2437 3437 4437 5437 6437 7437 8437 94378 3 4 | 438 1438 2438 3438 4438 5438 6438 7438 8438 94389 3 4 | 439 1439 2439 3439 4439 5439 6439 7439 8439 94390 4 4 | -465 -1465 2465 3465 4465 -5465 6465 -7465 8465 94651 4 4 | -464 -1464 2464 3464 4464 -5464 6464 -7464 8464 94642 4 4 | -463 -1463 2463 3463 4463 -5463 6463 -7463 8463 94633 4 4 | 443 1443 2443 3443 4443 5443 6443 7443 8443 94434 4 4 | 444 1444 2444 3444 4444 5444 6444 7444 8444 94445 4 4 | 445 1445 2445 3445 4445 5445 6445 7445 8445 94456 4 4 | 446 1446 2446 3446 4446 5446 6446 7446 8446 94467 4 4 | 447 1447 2447 3447 4447 5447 6447 7447 8447 94478 4 4 | 448 1448 2448 3448 4448 5448 6448 7448 8448 94489 4 4 | 449 1449 2449 3449 4449 5449 6449 7449 8449 94490 5 4 | -435 -1435 2435 3435 4435 -5435 6435 -7435 8435 94351 5 4 | -434 -1434 2434 3434 4434 -5434 6434 -7434 8434 94342 5 4 | -433 -1433 2433 3433 4433 -5433 6433 -7433 8433 94333 5 4 | 453 1453 2453 3453 4453 5453 6453 7453 8453 94534 5 4 | 454 1454 2454 3454 4454 5454 6454 7454 8454 94545 5 4 | 455 1455 2455 3455 4455 5455 6455 7455 8455 94556 5 4 | 456 1456 2456 3456 4456 5456 6456 7456 8456 94567 5 4 | 457 1457 2457 3457 4457 5457 6457 7457 8457 94578 5 4 | 458 1458 2458 3458 4458 5458 6458 7458 8458 94589 5 4 | 459 1459 2459 3459 4459 5459 6459 7459 8459 94590 6 4 | -445 -1445 2445 3445 4445 -5445 6445 -7445 8445 94451 6 4 | -444 -1444 2444 3444 4444 -5444 6444 -7444 8444 94442 6 4 | -443 -1443 2443 3443 4443 -5443 6443 -7443 8443 94433 6 4 | 463 1463 2463 3463 4463 5463 6463 7463 8463 94634 6 4 | 464 1464 2464 3464 4464 5464 6464 7464 8464 94645 6 4 | 465 1465 2465 3465 4465 5465 6465 7465 8465 94656 6 4 | 466 1466 2466 3466 4466 5466 6466 7466 8466 94667 6 4 | 467 1467 2467 3467 4467 5467 6467 7467 8467 94678 6 4 | 468 1468 2468 3468 4468 5468 6468 7468 8468 94689 6 4 | 469 1469 2469 3469 4469 5469 6469 7469 8469 94690 7 4 | -455 -1455 2455 3455 4455 -5455 6455 -7455 8455 94551 7 4 | -454 -1454 2454 3454 4454 -5454 6454 -7454 8454 94542 7 4 | -453 -1453 2453 3453 4453 -5453 6453 -7453 8453 94533 7 4 | 433 1433 2433 3433 4433 5433 6433 7433 8433 94334 7 4 | 434 1434 2434 3434 4434 5434 6434 7434 8434 94345 7 4 | 435 1435 2435 3435 4435 5435 6435 7435 8435 94356 7 4 | 436 1436 2436 3436 4436 5436 6436 7436 8436 94367 7 4 | 437 1437 2437 3437 4437 5437 6437 7437 8437 94378 7 4 | 438 1438 2438 3438 4438 5438 6438 7438 8438 94389 7 4 | 439 1439 2439 3439 4439 5439 6439 7439 8439 94390 8 4 | -465 -1465 2465 3465 4465 -5465 6465 -7465 8465 94651 8 4 | -464 -1464 2464 3464 4464 -5464 6464 -7464 8464 94642 8 4 | -463 -1463 2463 3463 4463 -5463 6463 -7463 8463 94633 8 4 | 443 1443 2443 3443 4443 5443 6443 7443 8443 94434 8 4 | 444 1444 2444 3444 4444 5444 6444 7444 8444 94445 8 4 | 445 1445 2445 3445 4445 5445 6445 7445 8445 94456 8 4 | 446 1446 2446 3446 4446 5446 6446 7446 8446 94467 8 4 | 447 1447 2447 3447 4447 5447 6447 7447 8447 94478 8 4 | 448 1448 2448 3448 4448 5448 6448 7448 8448 94489 8 4 | 449 1449 2449 3449 4449 5449 6449 7449 8449 94490 9 4 | -435 -1435 2435 3435 4435 -5435 6435 -7435 8435 94351 9 4 | -434 -1434 2434 3434 4434 -5434 6434 -7434 8434 94342 9 4 | -433 -1433 2433 3433 4433 -5433 6433 -7433 8433 94333 9 4 | 453 1453 2453 3453 4453 5453 6453 7453 8453 94534 9 4 | 454 1454 2454 3454 4454 5454 6454 7454 8454 94545 9 4 | 455 1455 2455 3455 4455 5455 6455 7455 8455 94556 9 4 | 456 1456 2456 3456 4456 5456 6456 7456 8456 94567 9 4 | 457 1457 2457 3457 4457 5457 6457 7457 8457 94578 9 4 | 458 1458 2458 3458 4458 5458 6458 7458 8458 94589 9 4 | 459 1459 2459 3459 4459 5459 6459 7459 8459 94590 0 5 | -565 -1565 2565 3565 4565 -5565 6565 -7565 8565 95651 0 5 | -564 -1564 2564 3564 4564 -5564 6564 -7564 8564 95642 0 5 | -563 -1563 2563 3563 4563 -5563 6563 -7563 8563 95633 0 5 | 543 1543 2543 3543 4543 5543 6543 7543 8543 95434 0 5 | 544 1544 2544 3544 4544 5544 6544 7544 8544 95445 0 5 | 545 1545 2545 3545 4545 5545 6545 7545 8545 95456 0 5 | 546 1546 2546 3546 4546 5546 6546 7546 8546 95467 0 5 | 547 1547 2547 3547 4547 5547 6547 7547 8547 95478 0 5 | 548 1548 2548 3548 4548 5548 6548 7548 8548 95489 0 5 | 549 1549 2549 3549 4549 5549 6549 7549 8549 95490 1 5 | -535 -1535 2535 3535 4535 -5535 6535 -7535 8535 95351 1 5 | -534 -1534 2534 3534 4534 -5534 6534 -7534 8534 95342 1 5 | -533 -1533 2533 3533 4533 -5533 6533 -7533 8533 95333 1 5 | 553 1553 2553 3553 4553 5553 6553 7553 8553 95534 1 5 | 554 1554 2554 3554 4554 5554 6554 7554 8554 95545 1 5 | 555 1555 2555 3555 4555 5555 6555 7555 8555 95556 1 5 | 556 1556 2556 3556 4556 5556 6556 7556 8556 95567 1 5 | 557 1557 2557 3557 4557 5557 6557 7557 8557 95578 1 5 | 558 1558 2558 3558 4558 5558 6558 7558 8558 95589 1 5 | 559 1559 2559 3559 4559 5559 6559 7559 8559 95590 2 5 | -545 -1545 2545 3545 4545 -5545 6545 -7545 8545 95451 2 5 | -544 -1544 2544 3544 4544 -5544 6544 -7544 8544 95442 2 5 | -543 -1543 2543 3543 4543 -5543 6543 -7543 8543 95433 2 5 | 563 1563 2563 3563 4563 5563 6563 7563 8563 95634 2 5 | 564 1564 2564 3564 4564 5564 6564 7564 8564 95645 2 5 | 565 1565 2565 3565 4565 5565 6565 7565 8565 95656 2 5 | 566 1566 2566 3566 4566 5566 6566 7566 8566 95667 2 5 | 567 1567 2567 3567 4567 5567 6567 7567 8567 95678 2 5 | 568 1568 2568 3568 4568 5568 6568 7568 8568 95689 2 5 | 569 1569 2569 3569 4569 5569 6569 7569 8569 95690 3 5 | -555 -1555 2555 3555 4555 -5555 6555 -7555 8555 95551 3 5 | -554 -1554 2554 3554 4554 -5554 6554 -7554 8554 95542 3 5 | -553 -1553 2553 3553 4553 -5553 6553 -7553 8553 95533 3 5 | 533 1533 2533 3533 4533 5533 6533 7533 8533 95334 3 5 | 534 1534 2534 3534 4534 5534 6534 7534 8534 95345 3 5 | 535 1535 2535 3535 4535 5535 6535 7535 8535 95356 3 5 | 536 1536 2536 3536 4536 5536 6536 7536 8536 95367 3 5 | 537 1537 2537 3537 4537 5537 6537 7537 8537 95378 3 5 | 538 1538 2538 3538 4538 5538 6538 7538 8538 95389 3 5 | 539 1539 2539 3539 4539 5539 6539 7539 8539 95390 4 5 | -565 -1565 2565 3565 4565 -5565 6565 -7565 8565 95651 4 5 | -564 -1564 2564 3564 4564 -5564 6564 -7564 8564 95642 4 5 | -563 -1563 2563 3563 4563 -5563 6563 -7563 8563 95633 4 5 | 543 1543 2543 3543 4543 5543 6543 7543 8543 95434 4 5 | 544 1544 2544 3544 4544 5544 6544 7544 8544 95445 4 5 | 545 1545 2545 3545 4545 5545 6545 7545 8545 95456 4 5 | 546 1546 2546 3546 4546 5546 6546 7546 8546 95467 4 5 | 547 1547 2547 3547 4547 5547 6547 7547 8547 95478 4 5 | 548 1548 2548 3548 4548 5548 6548 7548 8548 95489 4 5 | 549 1549 2549 3549 4549 5549 6549 7549 8549 95490 5 5 | -535 -1535 2535 3535 4535 -5535 6535 -7535 8535 95351 5 5 | -534 -1534 2534 3534 4534 -5534 6534 -7534 8534 95342 5 5 | -533 -1533 2533 3533 4533 -5533 6533 -7533 8533 95333 5 5 | 553 1553 2553 3553 4553 5553 6553 7553 8553 95534 5 5 | 554 1554 2554 3554 4554 5554 6554 7554 8554 95545 5 5 | 555 1555 2555 3555 4555 5555 6555 7555 8555 95556 5 5 | 556 1556 2556 3556 4556 5556 6556 7556 8556 95567 5 5 | 557 1557 2557 3557 4557 5557 6557 7557 8557 95578 5 5 | 558 1558 2558 3558 4558 5558 6558 7558 8558 95589 5 5 | 559 1559 2559 3559 4559 5559 6559 7559 8559 95590 6 5 | -545 -1545 2545 3545 4545 -5545 6545 -7545 8545 95451 6 5 | -544 -1544 2544 3544 4544 -5544 6544 -7544 8544 95442 6 5 | -543 -1543 2543 3543 4543 -5543 6543 -7543 8543 95433 6 5 | 563 1563 2563 3563 4563 5563 6563 7563 8563 95634 6 5 | 564 1564 2564 3564 4564 5564 6564 7564 8564 95645 6 5 | 565 1565 2565 3565 4565 5565 6565 7565 8565 95656 6 5 | 566 1566 2566 3566 4566 5566 6566 7566 8566 95667 6 5 | 567 1567 2567 3567 4567 5567 6567 7567 8567 95678 6 5 | 568 1568 2568 3568 4568 5568 6568 7568 8568 95689 6 5 | 569 1569 2569 3569 4569 5569 6569 7569 8569 95690 7 5 | -555 -1555 2555 3555 4555 -5555 6555 -7555 8555 95551 7 5 | -554 -1554 2554 3554 4554 -5554 6554 -7554 8554 95542 7 5 | -553 -1553 2553 3553 4553 -5553 6553 -7553 8553 95533 7 5 | 533 1533 2533 3533 4533 5533 6533 7533 8533 95334 7 5 | 534 1534 2534 3534 4534 5534 6534 7534 8534 95345 7 5 | 535 1535 2535 3535 4535 5535 6535 7535 8535 95356 7 5 | 536 1536 2536 3536 4536 5536 6536 7536 8536 95367 7 5 | 537 1537 2537 3537 4537 5537 6537 7537 8537 95378 7 5 | 538 1538 2538 3538 4538 5538 6538 7538 8538 95389 7 5 | 539 1539 2539 3539 4539 5539 6539 7539 8539 95390 8 5 | -565 -1565 2565 3565 4565 -5565 6565 -7565 8565 95651 8 5 | -564 -1564 2564 3564 4564 -5564 6564 -7564 8564 95642 8 5 | -563 -1563 2563 3563 4563 -5563 6563 -7563 8563 95633 8 5 | 543 1543 2543 3543 4543 5543 6543 7543 8543 95434 8 5 | 544 1544 2544 3544 4544 5544 6544 7544 8544 95445 8 5 | 545 1545 2545 3545 4545 5545 6545 7545 8545 95456 8 5 | 546 1546 2546 3546 4546 5546 6546 7546 8546 95467 8 5 | 547 1547 2547 3547 4547 5547 6547 7547 8547 95478 8 5 | 548 1548 2548 3548 4548 5548 6548 7548 8548 95489 8 5 | 549 1549 2549 3549 4549 5549 6549 7549 8549 95490 9 5 | -535 -1535 2535 3535 4535 -5535 6535 -7535 8535 95351 9 5 | -534 -1534 2534 3534 4534 -5534 6534 -7534 8534 95342 9 5 | -533 -1533 2533 3533 4533 -5533 6533 -7533 8533 95333 9 5 | 553 1553 2553 3553 4553 5553 6553 7553 8553 95534 9 5 | 554 1554 2554 3554 4554 5554 6554 7554 8554 95545 9 5 | 555 1555 2555 3555 4555 5555 6555 7555 8555 95556 9 5 | 556 1556 2556 3556 4556 5556 6556 7556 8556 95567 9 5 | 557 1557 2557 3557 4557 5557 6557 7557 8557 95578 9 5 | 558 1558 2558 3558 4558 5558 6558 7558 8558 95589 9 5 | 559 1559 2559 3559 4559 5559 6559 7559 8559 95590 0 6 | -665 -1665 2665 3665 4665 -5665 6665 -7665 8665 96651 0 6 | -664 -1664 2664 3664 4664 -5664 6664 -7664 8664 96642 0 6 | -663 -1663 2663 3663 4663 -5663 6663 -7663 8663 96633 0 6 | 643 1643 2643 3643 4643 5643 6643 7643 8643 96434 0 6 | 644 1644 2644 3644 4644 5644 6644 7644 8644 96445 0 6 | 645 1645 2645 3645 4645 5645 6645 7645 8645 96456 0 6 | 646 1646 2646 3646 4646 5646 6646 7646 8646 96467 0 6 | 647 1647 2647 3647 4647 5647 6647 7647 8647 96478 0 6 | 648 1648 2648 3648 4648 5648 6648 7648 8648 96489 0 6 | 649 1649 2649 3649 4649 5649 6649 7649 8649 96490 1 6 | -635 -1635 2635 3635 4635 -5635 6635 -7635 8635 96351 1 6 | -634 -1634 2634 3634 4634 -5634 6634 -7634 8634 96342 1 6 | -633 -1633 2633 3633 4633 -5633 6633 -7633 8633 96333 1 6 | 653 1653 2653 3653 4653 5653 6653 7653 8653 96534 1 6 | 654 1654 2654 3654 4654 5654 6654 7654 8654 96545 1 6 | 655 1655 2655 3655 4655 5655 6655 7655 8655 96556 1 6 | 656 1656 2656 3656 4656 5656 6656 7656 8656 96567 1 6 | 657 1657 2657 3657 4657 5657 6657 7657 8657 96578 1 6 | 658 1658 2658 3658 4658 5658 6658 7658 8658 96589 1 6 | 659 1659 2659 3659 4659 5659 6659 7659 8659 96590 2 6 | -645 -1645 2645 3645 4645 -5645 6645 -7645 8645 96451 2 6 | -644 -1644 2644 3644 4644 -5644 6644 -7644 8644 96442 2 6 | -643 -1643 2643 3643 4643 -5643 6643 -7643 8643 96433 2 6 | 663 1663 2663 3663 4663 5663 6663 7663 8663 96634 2 6 | 664 1664 2664 3664 4664 5664 6664 7664 8664 96645 2 6 | 665 1665 2665 3665 4665 5665 6665 7665 8665 96656 2 6 | 666 1666 2666 3666 4666 5666 6666 7666 8666 96667 2 6 | 667 1667 2667 3667 4667 5667 6667 7667 8667 96678 2 6 | 668 1668 2668 3668 4668 5668 6668 7668 8668 96689 2 6 | 669 1669 2669 3669 4669 5669 6669 7669 8669 96690 3 6 | -655 -1655 2655 3655 4655 -5655 6655 -7655 8655 96551 3 6 | -654 -1654 2654 3654 4654 -5654 6654 -7654 8654 96542 3 6 | -653 -1653 2653 3653 4653 -5653 6653 -7653 8653 96533 3 6 | 633 1633 2633 3633 4633 5633 6633 7633 8633 96334 3 6 | 634 1634 2634 3634 4634 5634 6634 7634 8634 96345 3 6 | 635 1635 2635 3635 4635 5635 6635 7635 8635 96356 3 6 | 636 1636 2636 3636 4636 5636 6636 7636 8636 96367 3 6 | 637 1637 2637 3637 4637 5637 6637 7637 8637 96378 3 6 | 638 1638 2638 3638 4638 5638 6638 7638 8638 96389 3 6 | 639 1639 2639 3639 4639 5639 6639 7639 8639 96390 4 6 | -665 -1665 2665 3665 4665 -5665 6665 -7665 8665 96651 4 6 | -664 -1664 2664 3664 4664 -5664 6664 -7664 8664 96642 4 6 | -663 -1663 2663 3663 4663 -5663 6663 -7663 8663 96633 4 6 | 643 1643 2643 3643 4643 5643 6643 7643 8643 96434 4 6 | 644 1644 2644 3644 4644 5644 6644 7644 8644 96445 4 6 | 645 1645 2645 3645 4645 5645 6645 7645 8645 96456 4 6 | 646 1646 2646 3646 4646 5646 6646 7646 8646 96467 4 6 | 647 1647 2647 3647 4647 5647 6647 7647 8647 96478 4 6 | 648 1648 2648 3648 4648 5648 6648 7648 8648 96489 4 6 | 649 1649 2649 3649 4649 5649 6649 7649 8649 96490 5 6 | -635 -1635 2635 3635 4635 -5635 6635 -7635 8635 96351 5 6 | -634 -1634 2634 3634 4634 -5634 6634 -7634 8634 96342 5 6 | -633 -1633 2633 3633 4633 -5633 6633 -7633 8633 96333 5 6 | 653 1653 2653 3653 4653 5653 6653 7653 8653 96534 5 6 | 654 1654 2654 3654 4654 5654 6654 7654 8654 96545 5 6 | 655 1655 2655 3655 4655 5655 6655 7655 8655 96556 5 6 | 656 1656 2656 3656 4656 5656 6656 7656 8656 96567 5 6 | 657 1657 2657 3657 4657 5657 6657 7657 8657 96578 5 6 | 658 1658 2658 3658 4658 5658 6658 7658 8658 96589 5 6 | 659 1659 2659 3659 4659 5659 6659 7659 8659 96590 6 6 | -645 -1645 2645 3645 4645 -5645 6645 -7645 8645 96451 6 6 | -644 -1644 2644 3644 4644 -5644 6644 -7644 8644 96442 6 6 | -643 -1643 2643 3643 4643 -5643 6643 -7643 8643 96433 6 6 | 663 1663 2663 3663 4663 5663 6663 7663 8663 96634 6 6 | 664 1664 2664 3664 4664 5664 6664 7664 8664 96645 6 6 | 665 1665 2665 3665 4665 5665 6665 7665 8665 96656 6 6 | 666 1666 2666 3666 4666 5666 6666 7666 8666 96667 6 6 | 667 1667 2667 3667 4667 5667 6667 7667 8667 96678 6 6 | 668 1668 2668 3668 4668 5668 6668 7668 8668 96689 6 6 | 669 1669 2669 3669 4669 5669 6669 7669 8669 96690 7 6 | -655 -1655 2655 3655 4655 -5655 6655 -7655 8655 96551 7 6 | -654 -1654 2654 3654 4654 -5654 6654 -7654 8654 96542 7 6 | -653 -1653 2653 3653 4653 -5653 6653 -7653 8653 96533 7 6 | 633 1633 2633 3633 4633 5633 6633 7633 8633 96334 7 6 | 634 1634 2634 3634 4634 5634 6634 7634 8634 96345 7 6 | 635 1635 2635 3635 4635 5635 6635 7635 8635 96356 7 6 | 636 1636 2636 3636 4636 5636 6636 7636 8636 96367 7 6 | 637 1637 2637 3637 4637 5637 6637 7637 8637 96378 7 6 | 638 1638 2638 3638 4638 5638 6638 7638 8638 96389 7 6 | 639 1639 2639 3639 4639 5639 6639 7639 8639 96390 8 6 | -665 -1665 2665 3665 4665 -5665 6665 -7665 8665 96651 8 6 | -664 -1664 2664 3664 4664 -5664 6664 -7664 8664 96642 8 6 | -663 -1663 2663 3663 4663 -5663 6663 -7663 8663 96633 8 6 | 643 1643 2643 3643 4643 5643 6643 7643 8643 96434 8 6 | 644 1644 2644 3644 4644 5644 6644 7644 8644 96445 8 6 | 645 1645 2645 3645 4645 5645 6645 7645 8645 96456 8 6 | 646 1646 2646 3646 4646 5646 6646 7646 8646 96467 8 6 | 647 1647 2647 3647 4647 5647 6647 7647 8647 96478 8 6 | 648 1648 2648 3648 4648 5648 6648 7648 8648 96489 8 6 | 649 1649 2649 3649 4649 5649 6649 7649 8649 96490 9 6 | -635 -1635 2635 3635 4635 -5635 6635 -7635 8635 96351 9 6 | -634 -1634 2634 3634 4634 -5634 6634 -7634 8634 96342 9 6 | -633 -1633 2633 3633 4633 -5633 6633 -7633 8633 96333 9 6 | 653 1653 2653 3653 4653 5653 6653 7653 8653 96534 9 6 | 654 1654 2654 3654 4654 5654 6654 7654 8654 96545 9 6 | 655 1655 2655 3655 4655 5655 6655 7655 8655 96556 9 6 | 656 1656 2656 3656 4656 5656 6656 7656 8656 96567 9 6 | 657 1657 2657 3657 4657 5657 6657 7657 8657 96578 9 6 | 658 1658 2658 3658 4658 5658 6658 7658 8658 96589 9 6 | 659 1659 2659 3659 4659 5659 6659 7659 8659 96590 0 7 | -765 -1765 2765 3765 4765 -5765 6765 -7765 8765 97651 0 7 | -764 -1764 2764 3764 4764 -5764 6764 -7764 8764 97642 0 7 | -763 -1763 2763 3763 4763 -5763 6763 -7763 8763 97633 0 7 | 743 1743 2743 3743 4743 5743 6743 7743 8743 97434 0 7 | 744 1744 2744 3744 4744 5744 6744 7744 8744 97445 0 7 | 745 1745 2745 3745 4745 5745 6745 7745 8745 97456 0 7 | 746 1746 2746 3746 4746 5746 6746 7746 8746 97467 0 7 | 747 1747 2747 3747 4747 5747 6747 7747 8747 97478 0 7 | 748 1748 2748 3748 4748 5748 6748 7748 8748 97489 0 7 | 749 1749 2749 3749 4749 5749 6749 7749 8749 97490 1 7 | -735 -1735 2735 3735 4735 -5735 6735 -7735 8735 97351 1 7 | -734 -1734 2734 3734 4734 -5734 6734 -7734 8734 97342 1 7 | -733 -1733 2733 3733 4733 -5733 6733 -7733 8733 97333 1 7 | 753 1753 2753 3753 4753 5753 6753 7753 8753 97534 1 7 | 754 1754 2754 3754 4754 5754 6754 7754 8754 97545 1 7 | 755 1755 2755 3755 4755 5755 6755 7755 8755 97556 1 7 | 756 1756 2756 3756 4756 5756 6756 7756 8756 97567 1 7 | 757 1757 2757 3757 4757 5757 6757 7757 8757 97578 1 7 | 758 1758 2758 3758 4758 5758 6758 7758 8758 97589 1 7 | 759 1759 2759 3759 4759 5759 6759 7759 8759 97590 2 7 | -745 -1745 2745 3745 4745 -5745 6745 -7745 8745 97451 2 7 | -744 -1744 2744 3744 4744 -5744 6744 -7744 8744 97442 2 7 | -743 -1743 2743 3743 4743 -5743 6743 -7743 8743 97433 2 7 | 763 1763 2763 3763 4763 5763 6763 7763 8763 97634 2 7 | 764 1764 2764 3764 4764 5764 6764 7764 8764 97645 2 7 | 765 1765 2765 3765 4765 5765 6765 7765 8765 97656 2 7 | 766 1766 2766 3766 4766 5766 6766 7766 8766 97667 2 7 | 767 1767 2767 3767 4767 5767 6767 7767 8767 97678 2 7 | 768 1768 2768 3768 4768 5768 6768 7768 8768 97689 2 7 | 769 1769 2769 3769 4769 5769 6769 7769 8769 97690 3 7 | -755 -1755 2755 3755 4755 -5755 6755 -7755 8755 97551 3 7 | -754 -1754 2754 3754 4754 -5754 6754 -7754 8754 97542 3 7 | -753 -1753 2753 3753 4753 -5753 6753 -7753 8753 97533 3 7 | 733 1733 2733 3733 4733 5733 6733 7733 8733 97334 3 7 | 734 1734 2734 3734 4734 5734 6734 7734 8734 97345 3 7 | 735 1735 2735 3735 4735 5735 6735 7735 8735 97356 3 7 | 736 1736 2736 3736 4736 5736 6736 7736 8736 97367 3 7 | 737 1737 2737 3737 4737 5737 6737 7737 8737 97378 3 7 | 738 1738 2738 3738 4738 5738 6738 7738 8738 97389 3 7 | 739 1739 2739 3739 4739 5739 6739 7739 8739 97390 4 7 | -765 -1765 2765 3765 4765 -5765 6765 -7765 8765 97651 4 7 | -764 -1764 2764 3764 4764 -5764 6764 -7764 8764 97642 4 7 | -763 -1763 2763 3763 4763 -5763 6763 -7763 8763 97633 4 7 | 743 1743 2743 3743 4743 5743 6743 7743 8743 97434 4 7 | 744 1744 2744 3744 4744 5744 6744 7744 8744 97445 4 7 | 745 1745 2745 3745 4745 5745 6745 7745 8745 97456 4 7 | 746 1746 2746 3746 4746 5746 6746 7746 8746 97467 4 7 | 747 1747 2747 3747 4747 5747 6747 7747 8747 97478 4 7 | 748 1748 2748 3748 4748 5748 6748 7748 8748 97489 4 7 | 749 1749 2749 3749 4749 5749 6749 7749 8749 97490 5 7 | -735 -1735 2735 3735 4735 -5735 6735 -7735 8735 97351 5 7 | -734 -1734 2734 3734 4734 -5734 6734 -7734 8734 97342 5 7 | -733 -1733 2733 3733 4733 -5733 6733 -7733 8733 97333 5 7 | 753 1753 2753 3753 4753 5753 6753 7753 8753 97534 5 7 | 754 1754 2754 3754 4754 5754 6754 7754 8754 97545 5 7 | 755 1755 2755 3755 4755 5755 6755 7755 8755 97556 5 7 | 756 1756 2756 3756 4756 5756 6756 7756 8756 97567 5 7 | 757 1757 2757 3757 4757 5757 6757 7757 8757 97578 5 7 | 758 1758 2758 3758 4758 5758 6758 7758 8758 97589 5 7 | 759 1759 2759 3759 4759 5759 6759 7759 8759 97590 6 7 | -745 -1745 2745 3745 4745 -5745 6745 -7745 8745 97451 6 7 | -744 -1744 2744 3744 4744 -5744 6744 -7744 8744 97442 6 7 | -743 -1743 2743 3743 4743 -5743 6743 -7743 8743 97433 6 7 | 763 1763 2763 3763 4763 5763 6763 7763 8763 97634 6 7 | 764 1764 2764 3764 4764 5764 6764 7764 8764 97645 6 7 | 765 1765 2765 3765 4765 5765 6765 7765 8765 97656 6 7 | 766 1766 2766 3766 4766 5766 6766 7766 8766 97667 6 7 | 767 1767 2767 3767 4767 5767 6767 7767 8767 97678 6 7 | 768 1768 2768 3768 4768 5768 6768 7768 8768 97689 6 7 | 769 1769 2769 3769 4769 5769 6769 7769 8769 97690 7 7 | -755 -1755 2755 3755 4755 -5755 6755 -7755 8755 97551 7 7 | -754 -1754 2754 3754 4754 -5754 6754 -7754 8754 97542 7 7 | -753 -1753 2753 3753 4753 -5753 6753 -7753 8753 97533 7 7 | 733 1733 2733 3733 4733 5733 6733 7733 8733 97334 7 7 | 734 1734 2734 3734 4734 5734 6734 7734 8734 97345 7 7 | 735 1735 2735 3735 4735 5735 6735 7735 8735 97356 7 7 | 736 1736 2736 3736 4736 5736 6736 7736 8736 97367 7 7 | 737 1737 2737 3737 4737 5737 6737 7737 8737 97378 7 7 | 738 1738 2738 3738 4738 5738 6738 7738 8738 97389 7 7 | 739 1739 2739 3739 4739 5739 6739 7739 8739 97390 8 7 | -765 -1765 2765 3765 4765 -5765 6765 -7765 8765 97651 8 7 | -764 -1764 2764 3764 4764 -5764 6764 -7764 8764 97642 8 7 | -763 -1763 2763 3763 4763 -5763 6763 -7763 8763 97633 8 7 | 743 1743 2743 3743 4743 5743 6743 7743 8743 97434 8 7 | 744 1744 2744 3744 4744 5744 6744 7744 8744 97445 8 7 | 745 1745 2745 3745 4745 5745 6745 7745 8745 97456 8 7 | 746 1746 2746 3746 4746 5746 6746 7746 8746 97467 8 7 | 747 1747 2747 3747 4747 5747 6747 7747 8747 97478 8 7 | 748 1748 2748 3748 4748 5748 6748 7748 8748 97489 8 7 | 749 1749 2749 3749 4749 5749 6749 7749 8749 97490 9 7 | -735 -1735 2735 3735 4735 -5735 6735 -7735 8735 97351 9 7 | -734 -1734 2734 3734 4734 -5734 6734 -7734 8734 97342 9 7 | -733 -1733 2733 3733 4733 -5733 6733 -7733 8733 97333 9 7 | 753 1753 2753 3753 4753 5753 6753 7753 8753 97534 9 7 | 754 1754 2754 3754 4754 5754 6754 7754 8754 97545 9 7 | 755 1755 2755 3755 4755 5755 6755 7755 8755 97556 9 7 | 756 1756 2756 3756 4756 5756 6756 7756 8756 97567 9 7 | 757 1757 2757 3757 4757 5757 6757 7757 8757 97578 9 7 | 758 1758 2758 3758 4758 5758 6758 7758 8758 97589 9 7 | 759 1759 2759 3759 4759 5759 6759 7759 8759 97590 0 8 | -865 -1865 2865 3865 4865 -5865 6865 -7865 8865 98651 0 8 | -864 -1864 2864 3864 4864 -5864 6864 -7864 8864 98642 0 8 | -863 -1863 2863 3863 4863 -5863 6863 -7863 8863 98633 0 8 | 843 1843 2843 3843 4843 5843 6843 7843 8843 98434 0 8 | 844 1844 2844 3844 4844 5844 6844 7844 8844 98445 0 8 | 845 1845 2845 3845 4845 5845 6845 7845 8845 98456 0 8 | 846 1846 2846 3846 4846 5846 6846 7846 8846 98467 0 8 | 847 1847 2847 3847 4847 5847 6847 7847 8847 98478 0 8 | 848 1848 2848 3848 4848 5848 6848 7848 8848 98489 0 8 | 849 1849 2849 3849 4849 5849 6849 7849 8849 98490 1 8 | -835 -1835 2835 3835 4835 -5835 6835 -7835 8835 98351 1 8 | -834 -1834 2834 3834 4834 -5834 6834 -7834 8834 98342 1 8 | -833 -1833 2833 3833 4833 -5833 6833 -7833 8833 98333 1 8 | 853 1853 2853 3853 4853 5853 6853 7853 8853 98534 1 8 | 854 1854 2854 3854 4854 5854 6854 7854 8854 98545 1 8 | 855 1855 2855 3855 4855 5855 6855 7855 8855 98556 1 8 | 856 1856 2856 3856 4856 5856 6856 7856 8856 98567 1 8 | 857 1857 2857 3857 4857 5857 6857 7857 8857 98578 1 8 | 858 1858 2858 3858 4858 5858 6858 7858 8858 98589 1 8 | 859 1859 2859 3859 4859 5859 6859 7859 8859 98590 2 8 | -845 -1845 2845 3845 4845 -5845 6845 -7845 8845 98451 2 8 | -844 -1844 2844 3844 4844 -5844 6844 -7844 8844 98442 2 8 | -843 -1843 2843 3843 4843 -5843 6843 -7843 8843 98433 2 8 | 863 1863 2863 3863 4863 5863 6863 7863 8863 98634 2 8 | 864 1864 2864 3864 4864 5864 6864 7864 8864 98645 2 8 | 865 1865 2865 3865 4865 5865 6865 7865 8865 98656 2 8 | 866 1866 2866 3866 4866 5866 6866 7866 8866 98667 2 8 | 867 1867 2867 3867 4867 5867 6867 7867 8867 98678 2 8 | 868 1868 2868 3868 4868 5868 6868 7868 8868 98689 2 8 | 869 1869 2869 3869 4869 5869 6869 7869 8869 98690 3 8 | -855 -1855 2855 3855 4855 -5855 6855 -7855 8855 98551 3 8 | -854 -1854 2854 3854 4854 -5854 6854 -7854 8854 98542 3 8 | -853 -1853 2853 3853 4853 -5853 6853 -7853 8853 98533 3 8 | 833 1833 2833 3833 4833 5833 6833 7833 8833 98334 3 8 | 834 1834 2834 3834 4834 5834 6834 7834 8834 98345 3 8 | 835 1835 2835 3835 4835 5835 6835 7835 8835 98356 3 8 | 836 1836 2836 3836 4836 5836 6836 7836 8836 98367 3 8 | 837 1837 2837 3837 4837 5837 6837 7837 8837 98378 3 8 | 838 1838 2838 3838 4838 5838 6838 7838 8838 98389 3 8 | 839 1839 2839 3839 4839 5839 6839 7839 8839 98390 4 8 | -865 -1865 2865 3865 4865 -5865 6865 -7865 8865 98651 4 8 | -864 -1864 2864 3864 4864 -5864 6864 -7864 8864 98642 4 8 | -863 -1863 2863 3863 4863 -5863 6863 -7863 8863 98633 4 8 | 843 1843 2843 3843 4843 5843 6843 7843 8843 98434 4 8 | 844 1844 2844 3844 4844 5844 6844 7844 8844 98445 4 8 | 845 1845 2845 3845 4845 5845 6845 7845 8845 98456 4 8 | 846 1846 2846 3846 4846 5846 6846 7846 8846 98467 4 8 | 847 1847 2847 3847 4847 5847 6847 7847 8847 98478 4 8 | 848 1848 2848 3848 4848 5848 6848 7848 8848 98489 4 8 | 849 1849 2849 3849 4849 5849 6849 7849 8849 98490 5 8 | -835 -1835 2835 3835 4835 -5835 6835 -7835 8835 98351 5 8 | -834 -1834 2834 3834 4834 -5834 6834 -7834 8834 98342 5 8 | -833 -1833 2833 3833 4833 -5833 6833 -7833 8833 98333 5 8 | 853 1853 2853 3853 4853 5853 6853 7853 8853 98534 5 8 | 854 1854 2854 3854 4854 5854 6854 7854 8854 98545 5 8 | 855 1855 2855 3855 4855 5855 6855 7855 8855 98556 5 8 | 856 1856 2856 3856 4856 5856 6856 7856 8856 98567 5 8 | 857 1857 2857 3857 4857 5857 6857 7857 8857 98578 5 8 | 858 1858 2858 3858 4858 5858 6858 7858 8858 98589 5 8 | 859 1859 2859 3859 4859 5859 6859 7859 8859 98590 6 8 | -845 -1845 2845 3845 4845 -5845 6845 -7845 8845 98451 6 8 | -844 -1844 2844 3844 4844 -5844 6844 -7844 8844 98442 6 8 | -843 -1843 2843 3843 4843 -5843 6843 -7843 8843 98433 6 8 | 863 1863 2863 3863 4863 5863 6863 7863 8863 98634 6 8 | 864 1864 2864 3864 4864 5864 6864 7864 8864 98645 6 8 | 865 1865 2865 3865 4865 5865 6865 7865 8865 98656 6 8 | 866 1866 2866 3866 4866 5866 6866 7866 8866 98667 6 8 | 867 1867 2867 3867 4867 5867 6867 7867 8867 98678 6 8 | 868 1868 2868 3868 4868 5868 6868 7868 8868 98689 6 8 | 869 1869 2869 3869 4869 5869 6869 7869 8869 98690 7 8 | -855 -1855 2855 3855 4855 -5855 6855 -7855 8855 98551 7 8 | -854 -1854 2854 3854 4854 -5854 6854 -7854 8854 98542 7 8 | -853 -1853 2853 3853 4853 -5853 6853 -7853 8853 98533 7 8 | 833 1833 2833 3833 4833 5833 6833 7833 8833 98334 7 8 | 834 1834 2834 3834 4834 5834 6834 7834 8834 98345 7 8 | 835 1835 2835 3835 4835 5835 6835 7835 8835 98356 7 8 | 836 1836 2836 3836 4836 5836 6836 7836 8836 98367 7 8 | 837 1837 2837 3837 4837 5837 6837 7837 8837 98378 7 8 | 838 1838 2838 3838 4838 5838 6838 7838 8838 98389 7 8 | 839 1839 2839 3839 4839 5839 6839 7839 8839 98390 8 8 | -865 -1865 2865 3865 4865 -5865 6865 -7865 8865 98651 8 8 | -864 -1864 2864 3864 4864 -5864 6864 -7864 8864 98642 8 8 | -863 -1863 2863 3863 4863 -5863 6863 -7863 8863 98633 8 8 | 843 1843 2843 3843 4843 5843 6843 7843 8843 98434 8 8 | 844 1844 2844 3844 4844 5844 6844 7844 8844 98445 8 8 | 845 1845 2845 3845 4845 5845 6845 7845 8845 98456 8 8 | 846 1846 2846 3846 4846 5846 6846 7846 8846 98467 8 8 | 847 1847 2847 3847 4847 5847 6847 7847 8847 98478 8 8 | 848 1848 2848 3848 4848 5848 6848 7848 8848 98489 8 8 | 849 1849 2849 3849 4849 5849 6849 7849 8849 98490 9 8 | -835 -1835 2835 3835 4835 -5835 6835 -7835 8835 98351 9 8 | -834 -1834 2834 3834 4834 -5834 6834 -7834 8834 98342 9 8 | -833 -1833 2833 3833 4833 -5833 6833 -7833 8833 98333 9 8 | 853 1853 2853 3853 4853 5853 6853 7853 8853 98534 9 8 | 854 1854 2854 3854 4854 5854 6854 7854 8854 98545 9 8 | 855 1855 2855 3855 4855 5855 6855 7855 8855 98556 9 8 | 856 1856 2856 3856 4856 5856 6856 7856 8856 98567 9 8 | 857 1857 2857 3857 4857 5857 6857 7857 8857 98578 9 8 | 858 1858 2858 3858 4858 5858 6858 7858 8858 98589 9 8 | 859 1859 2859 3859 4859 5859 6859 7859 8859 98590 0 9 | -965 -1965 2965 3965 4965 -5965 6965 -7965 8965 99651 0 9 | -964 -1964 2964 3964 4964 -5964 6964 -7964 8964 99642 0 9 | -963 -1963 2963 3963 4963 -5963 6963 -7963 8963 99633 0 9 | 943 1943 2943 3943 4943 5943 6943 7943 8943 99434 0 9 | 944 1944 2944 3944 4944 5944 6944 7944 8944 99445 0 9 | 945 1945 2945 3945 4945 5945 6945 7945 8945 99456 0 9 | 946 1946 2946 3946 4946 5946 6946 7946 8946 99467 0 9 | 947 1947 2947 3947 4947 5947 6947 7947 8947 99478 0 9 | 948 1948 2948 3948 4948 5948 6948 7948 8948 99489 0 9 | 949 1949 2949 3949 4949 5949 6949 7949 8949 99490 1 9 | -935 -1935 2935 3935 4935 -5935 6935 -7935 8935 99351 1 9 | -934 -1934 2934 3934 4934 -5934 6934 -7934 8934 99342 1 9 | -933 -1933 2933 3933 4933 -5933 6933 -7933 8933 99333 1 9 | 953 1953 2953 3953 4953 5953 6953 7953 8953 99534 1 9 | 954 1954 2954 3954 4954 5954 6954 7954 8954 99545 1 9 | 955 1955 2955 3955 4955 5955 6955 7955 8955 99556 1 9 | 956 1956 2956 3956 4956 5956 6956 7956 8956 99567 1 9 | 957 1957 2957 3957 4957 5957 6957 7957 8957 99578 1 9 | 958 1958 2958 3958 4958 5958 6958 7958 8958 99589 1 9 | 959 1959 2959 3959 4959 5959 6959 7959 8959 99590 2 9 | -945 -1945 2945 3945 4945 -5945 6945 -7945 8945 99451 2 9 | -944 -1944 2944 3944 4944 -5944 6944 -7944 8944 99442 2 9 | -943 -1943 2943 3943 4943 -5943 6943 -7943 8943 99433 2 9 | 963 1963 2963 3963 4963 5963 6963 7963 8963 99634 2 9 | 964 1964 2964 3964 4964 5964 6964 7964 8964 99645 2 9 | 965 1965 2965 3965 4965 5965 6965 7965 8965 99656 2 9 | 966 1966 2966 3966 4966 5966 6966 7966 8966 99667 2 9 | 967 1967 2967 3967 4967 5967 6967 7967 8967 99678 2 9 | 968 1968 2968 3968 4968 5968 6968 7968 8968 99689 2 9 | 969 1969 2969 3969 4969 5969 6969 7969 8969 99690 3 9 | -955 -1955 2955 3955 4955 -5955 6955 -7955 8955 99551 3 9 | -954 -1954 2954 3954 4954 -5954 6954 -7954 8954 99542 3 9 | -953 -1953 2953 3953 4953 -5953 6953 -7953 8953 99533 3 9 | 933 1933 2933 3933 4933 5933 6933 7933 8933 99334 3 9 | 934 1934 2934 3934 4934 5934 6934 7934 8934 99345 3 9 | 935 1935 2935 3935 4935 5935 6935 7935 8935 99356 3 9 | 936 1936 2936 3936 4936 5936 6936 7936 8936 99367 3 9 | 937 1937 2937 3937 4937 5937 6937 7937 8937 99378 3 9 | 938 1938 2938 3938 4938 5938 6938 7938 8938 99389 3 9 | 939 1939 2939 3939 4939 5939 6939 7939 8939 99390 4 9 | -965 -1965 2965 3965 4965 -5965 6965 -7965 8965 99651 4 9 | -964 -1964 2964 3964 4964 -5964 6964 -7964 8964 99642 4 9 | -963 -1963 2963 3963 4963 -5963 6963 -7963 8963 99633 4 9 | 943 1943 2943 3943 4943 5943 6943 7943 8943 99434 4 9 | 944 1944 2944 3944 4944 5944 6944 7944 8944 99445 4 9 | 945 1945 2945 3945 4945 5945 6945 7945 8945 99456 4 9 | 946 1946 2946 3946 4946 5946 6946 7946 8946 99467 4 9 | 947 1947 2947 3947 4947 5947 6947 7947 8947 99478 4 9 | 948 1948 2948 3948 4948 5948 6948 7948 8948 99489 4 9 | 949 1949 2949 3949 4949 5949 6949 7949 8949 99490 5 9 | -935 -1935 2935 3935 4935 -5935 6935 -7935 8935 99351 5 9 | -934 -1934 2934 3934 4934 -5934 6934 -7934 8934 99342 5 9 | -933 -1933 2933 3933 4933 -5933 6933 -7933 8933 99333 5 9 | 953 1953 2953 3953 4953 5953 6953 7953 8953 99534 5 9 | 954 1954 2954 3954 4954 5954 6954 7954 8954 99545 5 9 | 955 1955 2955 3955 4955 5955 6955 7955 8955 99556 5 9 | 956 1956 2956 3956 4956 5956 6956 7956 8956 99567 5 9 | 957 1957 2957 3957 4957 5957 6957 7957 8957 99578 5 9 | 958 1958 2958 3958 4958 5958 6958 7958 8958 99589 5 9 | 959 1959 2959 3959 4959 5959 6959 7959 8959 99590 6 9 | -945 -1945 2945 3945 4945 -5945 6945 -7945 8945 99451 6 9 | -944 -1944 2944 3944 4944 -5944 6944 -7944 8944 99442 6 9 | -943 -1943 2943 3943 4943 -5943 6943 -7943 8943 99433 6 9 | 963 1963 2963 3963 4963 5963 6963 7963 8963 99634 6 9 | 964 1964 2964 3964 4964 5964 6964 7964 8964 99645 6 9 | 965 1965 2965 3965 4965 5965 6965 7965 8965 99656 6 9 | 966 1966 2966 3966 4966 5966 6966 7966 8966 99667 6 9 | 967 1967 2967 3967 4967 5967 6967 7967 8967 99678 6 9 | 968 1968 2968 3968 4968 5968 6968 7968 8968 99689 6 9 | 969 1969 2969 3969 4969 5969 6969 7969 8969 99690 7 9 | -955 -1955 2955 3955 4955 -5955 6955 -7955 8955 99551 7 9 | -954 -1954 2954 3954 4954 -5954 6954 -7954 8954 99542 7 9 | -953 -1953 2953 3953 4953 -5953 6953 -7953 8953 99533 7 9 | 933 1933 2933 3933 4933 5933 6933 7933 8933 99334 7 9 | 934 1934 2934 3934 4934 5934 6934 7934 8934 99345 7 9 | 935 1935 2935 3935 4935 5935 6935 7935 8935 99356 7 9 | 936 1936 2936 3936 4936 5936 6936 7936 8936 99367 7 9 | 937 1937 2937 3937 4937 5937 6937 7937 8937 99378 7 9 | 938 1938 2938 3938 4938 5938 6938 7938 8938 99389 7 9 | 939 1939 2939 3939 4939 5939 6939 7939 8939 99390 8 9 | -965 -1965 2965 3965 4965 -5965 6965 -7965 8965 99651 8 9 | -964 -1964 2964 3964 4964 -5964 6964 -7964 8964 99642 8 9 | -963 -1963 2963 3963 4963 -5963 6963 -7963 8963 99633 8 9 | 943 1943 2943 3943 4943 5943 6943 7943 8943 99434 8 9 | 944 1944 2944 3944 4944 5944 6944 7944 8944 99445 8 9 | 945 1945 2945 3945 4945 5945 6945 7945 8945 99456 8 9 | 946 1946 2946 3946 4946 5946 6946 7946 8946 99467 8 9 | 947 1947 2947 3947 4947 5947 6947 7947 8947 99478 8 9 | 948 1948 2948 3948 4948 5948 6948 7948 8948 99489 8 9 | 949 1949 2949 3949 4949 5949 6949 7949 8949 99490 9 9 | -935 -1935 2935 3935 4935 -5935 6935 -7935 8935 99351 9 9 | -934 -1934 2934 3934 4934 -5934 6934 -7934 8934 99342 9 9 | -933 -1933 2933 3933 4933 -5933 6933 -7933 8933 99333 9 9 | 953 1953 2953 3953 4953 5953 6953 7953 8953 99534 9 9 | 954 1954 2954 3954 4954 5954 6954 7954 8954 99545 9 9 | 955 1955 2955 3955 4955 5955 6955 7955 8955 99556 9 9 | 956 1956 2956 3956 4956 5956 6956 7956 8956 99567 9 9 | 957 1957 2957 3957 4957 5957 6957 7957 8957 99578 9 9 | 958 1958 2958 3958 4958 5958 6958 7958 8958 99589 9 9 | 959 1959 2959 3959 4959 5959 6959 7959 8959 9959
0 0 0 | -445 -1445 2445 3445 4445 -5445 6445 -7445 8445 94451 0 0 | -444 -1444 2444 3444 4444 -5444 6444 -7444 8444 94442 0 0 | -443 -1443 2443 3443 4443 -5443 6443 -7443 8443 94433 0 0 | 653 -1653 -2653 3653 -4653 -5653 6653 7653 8653 96534 0 0 | 654 -1654 -2654 3654 -4654 -5654 6654 7654 8654 96545 0 0 | 655 -1655 -2655 3655 -4655 -5655 6655 7655 8655 96556 0 0 | 656 -1656 -2656 3656 -4656 -5656 6656 7656 8656 96567 0 0 | 657 -1657 -2657 3657 -4657 -5657 6657 7657 8657 96578 0 0 | 658 -1658 -2658 3658 -4658 -5658 6658 7658 8658 96589 0 0 | 659 -1659 -2659 3659 -4659 -5659 6659 7659 8659 96590 1 0 | -455 -1455 2455 3455 4455 -5455 6455 -7455 8455 94551 1 0 | -454 -1454 2454 3454 4454 -5454 6454 -7454 8454 94542 1 0 | -453 -1453 2453 3453 4453 -5453 6453 -7453 8453 94533 1 0 | 643 -1643 -2643 3643 -4643 -5643 6643 7643 8643 96434 1 0 | 644 -1644 -2644 3644 -4644 -5644 6644 7644 8644 96445 1 0 | 645 -1645 -2645 3645 -4645 -5645 6645 7645 8645 96456 1 0 | 646 -1646 -2646 3646 -4646 -5646 6646 7646 8646 96467 1 0 | 647 -1647 -2647 3647 -4647 -5647 6647 7647 8647 96478 1 0 | 648 -1648 -2648 3648 -4648 -5648 6648 7648 8648 96489 1 0 | 649 -1649 -2649 3649 -4649 -5649 6649 7649 8649 96490 2 0 | -465 -1465 2465 3465 4465 -5465 6465 -7465 8465 94651 2 0 | -464 -1464 2464 3464 4464 -5464 6464 -7464 8464 94642 2 0 | -463 -1463 2463 3463 4463 -5463 6463 -7463 8463 94633 2 0 | 633 -1633 -2633 3633 -4633 -5633 6633 7633 8633 96334 2 0 | 634 -1634 -2634 3634 -4634 -5634 6634 7634 8634 96345 2 0 | 635 -1635 -2635 3635 -4635 -5635 6635 7635 8635 96356 2 0 | 636 -1636 -2636 3636 -4636 -5636 6636 7636 8636 96367 2 0 | 637 -1637 -2637 3637 -4637 -5637 6637 7637 8637 96378 2 0 | 638 -1638 -2638 3638 -4638 -5638 6638 7638 8638 96389 2 0 | 639 -1639 -2639 3639 -4639 -5639 6639 7639 8639 96390 3 0 | -665 1665 -2665 3665 -4665 5665 6665 -7665 8665 96651 3 0 | -664 1664 -2664 3664 -4664 5664 6664 -7664 8664 96642 3 0 | -663 1663 -2663 3663 -4663 5663 6663 -7663 8663 96633 3 0 | 433 1433 2433 3433 4433 5433 6433 7433 8433 94334 3 0 | 434 1434 2434 3434 4434 5434 6434 7434 8434 94345 3 0 | 435 1435 2435 3435 4435 5435 6435 7435 8435 94356 3 0 | 436 1436 2436 3436 4436 5436 6436 7436 8436 94367 3 0 | 437 1437 2437 3437 4437 5437 6437 7437 8437 94378 3 0 | 438 1438 2438 3438 4438 5438 6438 7438 8438 94389 3 0 | 439 1439 2439 3439 4439 5439 6439 7439 8439 94390 4 0 | -655 1655 -2655 3655 -4655 5655 6655 -7655 8655 96551 4 0 | -654 1654 -2654 3654 -4654 5654 6654 -7654 8654 96542 4 0 | -653 1653 -2653 3653 -4653 5653 6653 -7653 8653 96533 4 0 | 443 1443 2443 3443 4443 5443 6443 7443 8443 94434 4 0 | 444 1444 2444 3444 4444 5444 6444 7444 8444 94445 4 0 | 445 1445 2445 3445 4445 5445 6445 7445 8445 94456 4 0 | 446 1446 2446 3446 4446 5446 6446 7446 8446 94467 4 0 | 447 1447 2447 3447 4447 5447 6447 7447 8447 94478 4 0 | 448 1448 2448 3448 4448 5448 6448 7448 8448 94489 4 0 | 449 1449 2449 3449 4449 5449 6449 7449 8449 94490 5 0 | -645 1645 -2645 3645 -4645 5645 6645 -7645 8645 96451 5 0 | -644 1644 -2644 3644 -4644 5644 6644 -7644 8644 96442 5 0 | -643 1643 -2643 3643 -4643 5643 6643 -7643 8643 96433 5 0 | 453 1453 2453 3453 4453 5453 6453 7453 8453 94534 5 0 | 454 1454 2454 3454 4454 5454 6454 7454 8454 94545 5 0 | 455 1455 2455 3455 4455 5455 6455 7455 8455 94556 5 0 | 456 1456 2456 3456 4456 5456 6456 7456 8456 94567 5 0 | 457 1457 2457 3457 4457 5457 6457 7457 8457 94578 5 0 | 458 1458 2458 3458 4458 5458 6458 7458 8458 94589 5 0 | 459 1459 2459 3459 4459 5459 6459 7459 8459 94590 6 0 | -635 1635 -2635 3635 -4635 5635 6635 -7635 8635 96351 6 0 | -634 1634 -2634 3634 -4634 5634 6634 -7634 8634 96342 6 0 | -633 1633 -2633 3633 -4633 5633 6633 -7633 8633 96333 6 0 | 463 1463 2463 3463 4463 5463 6463 7463 8463 94634 6 0 | 464 1464 2464 3464 4464 5464 6464 7464 8464 94645 6 0 | 465 1465 2465 3465 4465 5465 6465 7465 8465 94656 6 0 | 466 1466 2466 3466 4466 5466 6466 7466 8466 94667 6 0 | 467 1467 2467 3467 4467 5467 6467 7467 8467 94678 6 0 | 468 1468 2468 3468 4468 5468 6468 7468 8468 94689 6 0 | 469 1469 2469 3469 4469 5469 6469 7469 8469 94690 7 0 | -435 -1435 2435 3435 4435 -5435 6435 -7435 8435 94351 7 0 | -434 -1434 2434 3434 4434 -5434 6434 -7434 8434 94342 7 0 | -433 -1433 2433 3433 4433 -5433 6433 -7433 8433 94333 7 0 | 663 -1663 -2663 3663 -4663 -5663 6663 7663 8663 96634 7 0 | 664 -1664 -2664 3664 -4664 -5664 6664 7664 8664 96645 7 0 | 665 -1665 -2665 3665 -4665 -5665 6665 7665 8665 96656 7 0 | 666 -1666 -2666 3666 -4666 -5666 6666 7666 8666 96667 7 0 | 667 -1667 -2667 3667 -4667 -5667 6667 7667 8667 96678 7 0 | 668 -1668 -2668 3668 -4668 -5668 6668 7668 8668 96689 7 0 | 669 -1669 -2669 3669 -4669 -5669 6669 7669 8669 96690 8 0 | -445 -1445 2445 3445 4445 -5445 6445 -7445 8445 94451 8 0 | -444 -1444 2444 3444 4444 -5444 6444 -7444 8444 94442 8 0 | -443 -1443 2443 3443 4443 -5443 6443 -7443 8443 94433 8 0 | 653 -1653 -2653 3653 -4653 -5653 6653 7653 8653 96534 8 0 | 654 -1654 -2654 3654 -4654 -5654 6654 7654 8654 96545 8 0 | 655 -1655 -2655 3655 -4655 -5655 6655 7655 8655 96556 8 0 | 656 -1656 -2656 3656 -4656 -5656 6656 7656 8656 96567 8 0 | 657 -1657 -2657 3657 -4657 -5657 6657 7657 8657 96578 8 0 | 658 -1658 -2658 3658 -4658 -5658 6658 7658 8658 96589 8 0 | 659 -1659 -2659 3659 -4659 -5659 6659 7659 8659 96590 9 0 | -455 -1455 2455 3455 4455 -5455 6455 -7455 8455 94551 9 0 | -454 -1454 2454 3454 4454 -5454 6454 -7454 8454 94542 9 0 | -453 -1453 2453 3453 4453 -5453 6453 -7453 8453 94533 9 0 | 643 -1643 -2643 3643 -4643 -5643 6643 7643 8643 96434 9 0 | 644 -1644 -2644 3644 -4644 -5644 6644 7644 8644 96445 9 0 | 645 -1645 -2645 3645 -4645 -5645 6645 7645 8645 96456 9 0 | 646 -1646 -2646 3646 -4646 -5646 6646 7646 8646 96467 9 0 | 647 -1647 -2647 3647 -4647 -5647 6647 7647 8647 96478 9 0 | 648 -1648 -2648 3648 -4648 -5648 6648 7648 8648 96489 9 0 | 649 -1649 -2649 3649 -4649 -5649 6649 7649 8649 96490 0 1 | -545 -1545 2545 3545 4545 -5545 6545 -7545 8545 95451 0 1 | -544 -1544 2544 3544 4544 -5544 6544 -7544 8544 95442 0 1 | -543 -1543 2543 3543 4543 -5543 6543 -7543 8543 95433 0 1 | 353 -1353 -2353 3353 -4353 -5353 6353 7353 8353 93534 0 1 | 354 -1354 -2354 3354 -4354 -5354 6354 7354 8354 93545 0 1 | 355 -1355 -2355 3355 -4355 -5355 6355 7355 8355 93556 0 1 | 356 -1356 -2356 3356 -4356 -5356 6356 7356 8356 93567 0 1 | 357 -1357 -2357 3357 -4357 -5357 6357 7357 8357 93578 0 1 | 358 -1358 -2358 3358 -4358 -5358 6358 7358 8358 93589 0 1 | 359 -1359 -2359 3359 -4359 -5359 6359 7359 8359 93590 1 1 | -555 -1555 2555 3555 4555 -5555 6555 -7555 8555 95551 1 1 | -554 -1554 2554 3554 4554 -5554 6554 -7554 8554 95542 1 1 | -553 -1553 2553 3553 4553 -5553 6553 -7553 8553 95533 1 1 | 343 -1343 -2343 3343 -4343 -5343 6343 7343 8343 93434 1 1 | 344 -1344 -2344 3344 -4344 -5344 6344 7344 8344 93445 1 1 | 345 -1345 -2345 3345 -4345 -5345 6345 7345 8345 93456 1 1 | 346 -1346 -2346 3346 -4346 -5346 6346 7346 8346 93467 1 1 | 347 -1347 -2347 3347 -4347 -5347 6347 7347 8347 93478 1 1 | 348 -1348 -2348 3348 -4348 -5348 6348 7348 8348 93489 1 1 | 349 -1349 -2349 3349 -4349 -5349 6349 7349 8349 93490 2 1 | -565 -1565 2565 3565 4565 -5565 6565 -7565 8565 95651 2 1 | -564 -1564 2564 3564 4564 -5564 6564 -7564 8564 95642 2 1 | -563 -1563 2563 3563 4563 -5563 6563 -7563 8563 95633 2 1 | 333 -1333 -2333 3333 -4333 -5333 6333 7333 8333 93334 2 1 | 334 -1334 -2334 3334 -4334 -5334 6334 7334 8334 93345 2 1 | 335 -1335 -2335 3335 -4335 -5335 6335 7335 8335 93356 2 1 | 336 -1336 -2336 3336 -4336 -5336 6336 7336 8336 93367 2 1 | 337 -1337 -2337 3337 -4337 -5337 6337 7337 8337 93378 2 1 | 338 -1338 -2338 3338 -4338 -5338 6338 7338 8338 93389 2 1 | 339 -1339 -2339 3339 -4339 -5339 6339 7339 8339 93390 3 1 | -365 1365 -2365 3365 -4365 5365 6365 -7365 8365 93651 3 1 | -364 1364 -2364 3364 -4364 5364 6364 -7364 8364 93642 3 1 | -363 1363 -2363 3363 -4363 5363 6363 -7363 8363 93633 3 1 | 533 1533 2533 3533 4533 5533 6533 7533 8533 95334 3 1 | 534 1534 2534 3534 4534 5534 6534 7534 8534 95345 3 1 | 535 1535 2535 3535 4535 5535 6535 7535 8535 95356 3 1 | 536 1536 2536 3536 4536 5536 6536 7536 8536 95367 3 1 | 537 1537 2537 3537 4537 5537 6537 7537 8537 95378 3 1 | 538 1538 2538 3538 4538 5538 6538 7538 8538 95389 3 1 | 539 1539 2539 3539 4539 5539 6539 7539 8539 95390 4 1 | -355 1355 -2355 3355 -4355 5355 6355 -7355 8355 93551 4 1 | -354 1354 -2354 3354 -4354 5354 6354 -7354 8354 93542 4 1 | -353 1353 -2353 3353 -4353 5353 6353 -7353 8353 93533 4 1 | 543 1543 2543 3543 4543 5543 6543 7543 8543 95434 4 1 | 544 1544 2544 3544 4544 5544 6544 7544 8544 95445 4 1 | 545 1545 2545 3545 4545 5545 6545 7545 8545 95456 4 1 | 546 1546 2546 3546 4546 5546 6546 7546 8546 95467 4 1 | 547 1547 2547 3547 4547 5547 6547 7547 8547 95478 4 1 | 548 1548 2548 3548 4548 5548 6548 7548 8548 95489 4 1 | 549 1549 2549 3549 4549 5549 6549 7549 8549 95490 5 1 | -345 1345 -2345 3345 -4345 5345 6345 -7345 8345 93451 5 1 | -344 1344 -2344 3344 -4344 5344 6344 -7344 8344 93442 5 1 | -343 1343 -2343 3343 -4343 5343 6343 -7343 8343 93433 5 1 | 553 1553 2553 3553 4553 5553 6553 7553 8553 95534 5 1 | 554 1554 2554 3554 4554 5554 6554 7554 8554 95545 5 1 | 555 1555 2555 3555 4555 5555 6555 7555 8555 95556 5 1 | 556 1556 2556 3556 4556 5556 6556 7556 8556 95567 5 1 | 557 1557 2557 3557 4557 5557 6557 7557 8557 95578 5 1 | 558 1558 2558 3558 4558 5558 6558 7558 8558 95589 5 1 | 559 1559 2559 3559 4559 5559 6559 7559 8559 95590 6 1 | -335 1335 -2335 3335 -4335 5335 6335 -7335 8335 93351 6 1 | -334 1334 -2334 3334 -4334 5334 6334 -7334 8334 93342 6 1 | -333 1333 -2333 3333 -4333 5333 6333 -7333 8333 93333 6 1 | 563 1563 2563 3563 4563 5563 6563 7563 8563 95634 6 1 | 564 1564 2564 3564 4564 5564 6564 7564 8564 95645 6 1 | 565 1565 2565 3565 4565 5565 6565 7565 8565 95656 6 1 | 566 1566 2566 3566 4566 5566 6566 7566 8566 95667 6 1 | 567 1567 2567 3567 4567 5567 6567 7567 8567 95678 6 1 | 568 1568 2568 3568 4568 5568 6568 7568 8568 95689 6 1 | 569 1569 2569 3569 4569 5569 6569 7569 8569 95690 7 1 | -535 -1535 2535 3535 4535 -5535 6535 -7535 8535 95351 7 1 | -534 -1534 2534 3534 4534 -5534 6534 -7534 8534 95342 7 1 | -533 -1533 2533 3533 4533 -5533 6533 -7533 8533 95333 7 1 | 363 -1363 -2363 3363 -4363 -5363 6363 7363 8363 93634 7 1 | 364 -1364 -2364 3364 -4364 -5364 6364 7364 8364 93645 7 1 | 365 -1365 -2365 3365 -4365 -5365 6365 7365 8365 93656 7 1 | 366 -1366 -2366 3366 -4366 -5366 6366 7366 8366 93667 7 1 | 367 -1367 -2367 3367 -4367 -5367 6367 7367 8367 93678 7 1 | 368 -1368 -2368 3368 -4368 -5368 6368 7368 8368 93689 7 1 | 369 -1369 -2369 3369 -4369 -5369 6369 7369 8369 93690 8 1 | -545 -1545 2545 3545 4545 -5545 6545 -7545 8545 95451 8 1 | -544 -1544 2544 3544 4544 -5544 6544 -7544 8544 95442 8 1 | -543 -1543 2543 3543 4543 -5543 6543 -7543 8543 95433 8 1 | 353 -1353 -2353 3353 -4353 -5353 6353 7353 8353 93534 8 1 | 354 -1354 -2354 3354 -4354 -5354 6354 7354 8354 93545 8 1 | 355 -1355 -2355 3355 -4355 -5355 6355 7355 8355 93556 8 1 | 356 -1356 -2356 3356 -4356 -5356 6356 7356 8356 93567 8 1 | 357 -1357 -2357 3357 -4357 -5357 6357 7357 8357 93578 8 1 | 358 -1358 -2358 3358 -4358 -5358 6358 7358 8358 93589 8 1 | 359 -1359 -2359 3359 -4359 -5359 6359 7359 8359 93590 9 1 | -555 -1555 2555 3555 4555 -5555 6555 -7555 8555 95551 9 1 | -554 -1554 2554 3554 4554 -5554 6554 -7554 8554 95542 9 1 | -553 -1553 2553 3553 4553 -5553 6553 -7553 8553 95533 9 1 | 343 -1343 -2343 3343 -4343 -5343 6343 7343 8343 93434 9 1 | 344 -1344 -2344 3344 -4344 -5344 6344 7344 8344 93445 9 1 | 345 -1345 -2345 3345 -4345 -5345 6345 7345 8345 93456 9 1 | 346 -1346 -2346 3346 -4346 -5346 6346 7346 8346 93467 9 1 | 347 -1347 -2347 3347 -4347 -5347 6347 7347 8347 93478 9 1 | 348 -1348 -2348 3348 -4348 -5348 6348 7348 8348 93489 9 1 | 349 -1349 -2349 3349 -4349 -5349 6349 7349 8349 93490 0 2 | -645 -1645 2645 3645 4645 -5645 6645 -7645 8645 96451 0 2 | -644 -1644 2644 3644 4644 -5644 6644 -7644 8644 96442 0 2 | -643 -1643 2643 3643 4643 -5643 6643 -7643 8643 96433 0 2 | 453 -1453 -2453 3453 -4453 -5453 6453 7453 8453 94534 0 2 | 454 -1454 -2454 3454 -4454 -5454 6454 7454 8454 94545 0 2 | 455 -1455 -2455 3455 -4455 -5455 6455 7455 8455 94556 0 2 | 456 -1456 -2456 3456 -4456 -5456 6456 7456 8456 94567 0 2 | 457 -1457 -2457 3457 -4457 -5457 6457 7457 8457 94578 0 2 | 458 -1458 -2458 3458 -4458 -5458 6458 7458 8458 94589 0 2 | 459 -1459 -2459 3459 -4459 -5459 6459 7459 8459 94590 1 2 | -655 -1655 2655 3655 4655 -5655 6655 -7655 8655 96551 1 2 | -654 -1654 2654 3654 4654 -5654 6654 -7654 8654 96542 1 2 | -653 -1653 2653 3653 4653 -5653 6653 -7653 8653 96533 1 2 | 443 -1443 -2443 3443 -4443 -5443 6443 7443 8443 94434 1 2 | 444 -1444 -2444 3444 -4444 -5444 6444 7444 8444 94445 1 2 | 445 -1445 -2445 3445 -4445 -5445 6445 7445 8445 94456 1 2 | 446 -1446 -2446 3446 -4446 -5446 6446 7446 8446 94467 1 2 | 447 -1447 -2447 3447 -4447 -5447 6447 7447 8447 94478 1 2 | 448 -1448 -2448 3448 -4448 -5448 6448 7448 8448 94489 1 2 | 449 -1449 -2449 3449 -4449 -5449 6449 7449 8449 94490 2 2 | -665 -1665 2665 3665 4665 -5665 6665 -7665 8665 96651 2 2 | -664 -1664 2664 3664 4664 -5664 6664 -7664 8664 96642 2 2 | -663 -1663 2663 3663 4663 -5663 6663 -7663 8663 96633 2 2 | 433 -1433 -2433 3433 -4433 -5433 6433 7433 8433 94334 2 2 | 434 -1434 -2434 3434 -4434 -5434 6434 7434 8434 94345 2 2 | 435 -1435 -2435 3435 -4435 -5435 6435 7435 8435 94356 2 2 | 436 -1436 -2436 3436 -4436 -5436 6436 7436 8436 94367 2 2 | 437 -1437 -2437 3437 -4437 -5437 6437 7437 8437 94378 2 2 | 438 -1438 -2438 3438 -4438 -5438 6438 7438 8438 94389 2 2 | 439 -1439 -2439 3439 -4439 -5439 6439 7439 8439 94390 3 2 | -465 1465 -2465 3465 -4465 5465 6465 -7465 8465 94651 3 2 | -464 1464 -2464 3464 -4464 5464 6464 -7464 8464 94642 3 2 | -463 1463 -2463 3463 -4463 5463 6463 -7463 8463 94633 3 2 | 633 1633 2633 3633 4633 5633 6633 7633 8633 96334 3 2 | 634 1634 2634 3634 4634 5634 6634 7634 8634 96345 3 2 | 635 1635 2635 3635 4635 5635 6635 7635 8635 96356 3 2 | 636 1636 2636 3636 4636 5636 6636 7636 8636 96367 3 2 | 637 1637 2637 3637 4637 5637 6637 7637 8637 96378 3 2 | 638 1638 2638 3638 4638 5638 6638 7638 8638 96389 3 2 | 639 1639 2639 3639 4639 5639 6639 7639 8639 96390 4 2 | -455 1455 -2455 3455 -4455 5455 6455 -7455 8455 94551 4 2 | -454 1454 -2454 3454 -4454 5454 6454 -7454 8454 94542 4 2 | -453 1453 -2453 3453 -4453 5453 6453 -7453 8453 94533 4 2 | 643 1643 2643 3643 4643 5643 6643 7643 8643 96434 4 2 | 644 1644 2644 3644 4644 5644 6644 7644 8644 96445 4 2 | 645 1645 2645 3645 4645 5645 6645 7645 8645 96456 4 2 | 646 1646 2646 3646 4646 5646 6646 7646 8646 96467 4 2 | 647 1647 2647 3647 4647 5647 6647 7647 8647 96478 4 2 | 648 1648 2648 3648 4648 5648 6648 7648 8648 96489 4 2 | 649 1649 2649 3649 4649 5649 6649 7649 8649 96490 5 2 | -445 1445 -2445 3445 -4445 5445 6445 -7445 8445 94451 5 2 | -444 1444 -2444 3444 -4444 5444 6444 -7444 8444 94442 5 2 | -443 1443 -2443 3443 -4443 5443 6443 -7443 8443 94433 5 2 | 653 1653 2653 3653 4653 5653 6653 7653 8653 96534 5 2 | 654 1654 2654 3654 4654 5654 6654 7654 8654 96545 5 2 | 655 1655 2655 3655 4655 5655 6655 7655 8655 96556 5 2 | 656 1656 2656 3656 4656 5656 6656 7656 8656 96567 5 2 | 657 1657 2657 3657 4657 5657 6657 7657 8657 96578 5 2 | 658 1658 2658 3658 4658 5658 6658 7658 8658 96589 5 2 | 659 1659 2659 3659 4659 5659 6659 7659 8659 96590 6 2 | -435 1435 -2435 3435 -4435 5435 6435 -7435 8435 94351 6 2 | -434 1434 -2434 3434 -4434 5434 6434 -7434 8434 94342 6 2 | -433 1433 -2433 3433 -4433 5433 6433 -7433 8433 94333 6 2 | 663 1663 2663 3663 4663 5663 6663 7663 8663 96634 6 2 | 664 1664 2664 3664 4664 5664 6664 7664 8664 96645 6 2 | 665 1665 2665 3665 4665 5665 6665 7665 8665 96656 6 2 | 666 1666 2666 3666 4666 5666 6666 7666 8666 96667 6 2 | 667 1667 2667 3667 4667 5667 6667 7667 8667 96678 6 2 | 668 1668 2668 3668 4668 5668 6668 7668 8668 96689 6 2 | 669 1669 2669 3669 4669 5669 6669 7669 8669 96690 7 2 | -635 -1635 2635 3635 4635 -5635 6635 -7635 8635 96351 7 2 | -634 -1634 2634 3634 4634 -5634 6634 -7634 8634 96342 7 2 | -633 -1633 2633 3633 4633 -5633 6633 -7633 8633 96333 7 2 | 463 -1463 -2463 3463 -4463 -5463 6463 7463 8463 94634 7 2 | 464 -1464 -2464 3464 -4464 -5464 6464 7464 8464 94645 7 2 | 465 -1465 -2465 3465 -4465 -5465 6465 7465 8465 94656 7 2 | 466 -1466 -2466 3466 -4466 -5466 6466 7466 8466 94667 7 2 | 467 -1467 -2467 3467 -4467 -5467 6467 7467 8467 94678 7 2 | 468 -1468 -2468 3468 -4468 -5468 6468 7468 8468 94689 7 2 | 469 -1469 -2469 3469 -4469 -5469 6469 7469 8469 94690 8 2 | -645 -1645 2645 3645 4645 -5645 6645 -7645 8645 96451 8 2 | -644 -1644 2644 3644 4644 -5644 6644 -7644 8644 96442 8 2 | -643 -1643 2643 3643 4643 -5643 6643 -7643 8643 96433 8 2 | 453 -1453 -2453 3453 -4453 -5453 6453 7453 8453 94534 8 2 | 454 -1454 -2454 3454 -4454 -5454 6454 7454 8454 94545 8 2 | 455 -1455 -2455 3455 -4455 -5455 6455 7455 8455 94556 8 2 | 456 -1456 -2456 3456 -4456 -5456 6456 7456 8456 94567 8 2 | 457 -1457 -2457 3457 -4457 -5457 6457 7457 8457 94578 8 2 | 458 -1458 -2458 3458 -4458 -5458 6458 7458 8458 94589 8 2 | 459 -1459 -2459 3459 -4459 -5459 6459 7459 8459 94590 9 2 | -655 -1655 2655 3655 4655 -5655 6655 -7655 8655 96551 9 2 | -654 -1654 2654 3654 4654 -5654 6654 -7654 8654 96542 9 2 | -653 -1653 2653 3653 4653 -5653 6653 -7653 8653 96533 9 2 | 443 -1443 -2443 3443 -4443 -5443 6443 7443 8443 94434 9 2 | 444 -1444 -2444 3444 -4444 -5444 6444 7444 8444 94445 9 2 | 445 -1445 -2445 3445 -4445 -5445 6445 7445 8445 94456 9 2 | 446 -1446 -2446 3446 -4446 -5446 6446 7446 8446 94467 9 2 | 447 -1447 -2447 3447 -4447 -5447 6447 7447 8447 94478 9 2 | 448 -1448 -2448 3448 -4448 -5448 6448 7448 8448 94489 9 2 | 449 -1449 -2449 3449 -4449 -5449 6449 7449 8449 94490 0 3 | -345 -1345 2345 3345 4345 -5345 6345 -7345 8345 93451 0 3 | -344 -1344 2344 3344 4344 -5344 6344 -7344 8344 93442 0 3 | -343 -1343 2343 3343 4343 -5343 6343 -7343 8343 93433 0 3 | 553 -1553 -2553 3553 -4553 -5553 6553 7553 8553 95534 0 3 | 554 -1554 -2554 3554 -4554 -5554 6554 7554 8554 95545 0 3 | 555 -1555 -2555 3555 -4555 -5555 6555 7555 8555 95556 0 3 | 556 -1556 -2556 3556 -4556 -5556 6556 7556 8556 95567 0 3 | 557 -1557 -2557 3557 -4557 -5557 6557 7557 8557 95578 0 3 | 558 -1558 -2558 3558 -4558 -5558 6558 7558 8558 95589 0 3 | 559 -1559 -2559 3559 -4559 -5559 6559 7559 8559 95590 1 3 | -355 -1355 2355 3355 4355 -5355 6355 -7355 8355 93551 1 3 | -354 -1354 2354 3354 4354 -5354 6354 -7354 8354 93542 1 3 | -353 -1353 2353 3353 4353 -5353 6353 -7353 8353 93533 1 3 | 543 -1543 -2543 3543 -4543 -5543 6543 7543 8543 95434 1 3 | 544 -1544 -2544 3544 -4544 -5544 6544 7544 8544 95445 1 3 | 545 -1545 -2545 3545 -4545 -5545 6545 7545 8545 95456 1 3 | 546 -1546 -2546 3546 -4546 -5546 6546 7546 8546 95467 1 3 | 547 -1547 -2547 3547 -4547 -5547 6547 7547 8547 95478 1 3 | 548 -1548 -2548 3548 -4548 -5548 6548 7548 8548 95489 1 3 | 549 -1549 -2549 3549 -4549 -5549 6549 7549 8549 95490 2 3 | -365 -1365 2365 3365 4365 -5365 6365 -7365 8365 93651 2 3 | -364 -1364 2364 3364 4364 -5364 6364 -7364 8364 93642 2 3 | -363 -1363 2363 3363 4363 -5363 6363 -7363 8363 93633 2 3 | 533 -1533 -2533 3533 -4533 -5533 6533 7533 8533 95334 2 3 | 534 -1534 -2534 3534 -4534 -5534 6534 7534 8534 95345 2 3 | 535 -1535 -2535 3535 -4535 -5535 6535 7535 8535 95356 2 3 | 536 -1536 -2536 3536 -4536 -5536 6536 7536 8536 95367 2 3 | 537 -1537 -2537 3537 -4537 -5537 6537 7537 8537 95378 2 3 | 538 -1538 -2538 3538 -4538 -5538 6538 7538 8538 95389 2 3 | 539 -1539 -2539 3539 -4539 -5539 6539 7539 8539 95390 3 3 | -565 1565 -2565 3565 -4565 5565 6565 -7565 8565 95651 3 3 | -564 1564 -2564 3564 -4564 5564 6564 -7564 8564 95642 3 3 | -563 1563 -2563 3563 -4563 5563 6563 -7563 8563 95633 3 3 | 333 1333 2333 3333 4333 5333 6333 7333 8333 93334 3 3 | 334 1334 2334 3334 4334 5334 6334 7334 8334 93345 3 3 | 335 1335 2335 3335 4335 5335 6335 7335 8335 93356 3 3 | 336 1336 2336 3336 4336 5336 6336 7336 8336 93367 3 3 | 337 1337 2337 3337 4337 5337 6337 7337 8337 93378 3 3 | 338 1338 2338 3338 4338 5338 6338 7338 8338 93389 3 3 | 339 1339 2339 3339 4339 5339 6339 7339 8339 93390 4 3 | -555 1555 -2555 3555 -4555 5555 6555 -7555 8555 95551 4 3 | -554 1554 -2554 3554 -4554 5554 6554 -7554 8554 95542 4 3 | -553 1553 -2553 3553 -4553 5553 6553 -7553 8553 95533 4 3 | 343 1343 2343 3343 4343 5343 6343 7343 8343 93434 4 3 | 344 1344 2344 3344 4344 5344 6344 7344 8344 93445 4 3 | 345 1345 2345 3345 4345 5345 6345 7345 8345 93456 4 3 | 346 1346 2346 3346 4346 5346 6346 7346 8346 93467 4 3 | 347 1347 2347 3347 4347 5347 6347 7347 8347 93478 4 3 | 348 1348 2348 3348 4348 5348 6348 7348 8348 93489 4 3 | 349 1349 2349 3349 4349 5349 6349 7349 8349 93490 5 3 | -545 1545 -2545 3545 -4545 5545 6545 -7545 8545 95451 5 3 | -544 1544 -2544 3544 -4544 5544 6544 -7544 8544 95442 5 3 | -543 1543 -2543 3543 -4543 5543 6543 -7543 8543 95433 5 3 | 353 1353 2353 3353 4353 5353 6353 7353 8353 93534 5 3 | 354 1354 2354 3354 4354 5354 6354 7354 8354 93545 5 3 | 355 1355 2355 3355 4355 5355 6355 7355 8355 93556 5 3 | 356 1356 2356 3356 4356 5356 6356 7356 8356 93567 5 3 | 357 1357 2357 3357 4357 5357 6357 7357 8357 93578 5 3 | 358 1358 2358 3358 4358 5358 6358 7358 8358 93589 5 3 | 359 1359 2359 3359 4359 5359 6359 7359 8359 93590 6 3 | -535 1535 -2535 3535 -4535 5535 6535 -7535 8535 95351 6 3 | -534 1534 -2534 3534 -4534 5534 6534 -7534 8534 95342 6 3 | -533 1533 -2533 3533 -4533 5533 6533 -7533 8533 95333 6 3 | 363 1363 2363 3363 4363 5363 6363 7363 8363 93634 6 3 | 364 1364 2364 3364 4364 5364 6364 7364 8364 93645 6 3 | 365 1365 2365 3365 4365 5365 6365 7365 8365 93656 6 3 | 366 1366 2366 3366 4366 5366 6366 7366 8366 93667 6 3 | 367 1367 2367 3367 4367 5367 6367 7367 8367 93678 6 3 | 368 1368 2368 3368 4368 5368 6368 7368 8368 93689 6 3 | 369 1369 2369 3369 4369 5369 6369 7369 8369 93690 7 3 | -335 -1335 2335 3335 4335 -5335 6335 -7335 8335 93351 7 3 | -334 -1334 2334 3334 4334 -5334 6334 -7334 8334 93342 7 3 | -333 -1333 2333 3333 4333 -5333 6333 -7333 8333 93333 7 3 | 563 -1563 -2563 3563 -4563 -5563 6563 7563 8563 95634 7 3 | 564 -1564 -2564 3564 -4564 -5564 6564 7564 8564 95645 7 3 | 565 -1565 -2565 3565 -4565 -5565 6565 7565 8565 95656 7 3 | 566 -1566 -2566 3566 -4566 -5566 6566 7566 8566 95667 7 3 | 567 -1567 -2567 3567 -4567 -5567 6567 7567 8567 95678 7 3 | 568 -1568 -2568 3568 -4568 -5568 6568 7568 8568 95689 7 3 | 569 -1569 -2569 3569 -4569 -5569 6569 7569 8569 95690 8 3 | -345 -1345 2345 3345 4345 -5345 6345 -7345 8345 93451 8 3 | -344 -1344 2344 3344 4344 -5344 6344 -7344 8344 93442 8 3 | -343 -1343 2343 3343 4343 -5343 6343 -7343 8343 93433 8 3 | 553 -1553 -2553 3553 -4553 -5553 6553 7553 8553 95534 8 3 | 554 -1554 -2554 3554 -4554 -5554 6554 7554 8554 95545 8 3 | 555 -1555 -2555 3555 -4555 -5555 6555 7555 8555 95556 8 3 | 556 -1556 -2556 3556 -4556 -5556 6556 7556 8556 95567 8 3 | 557 -1557 -2557 3557 -4557 -5557 6557 7557 8557 95578 8 3 | 558 -1558 -2558 3558 -4558 -5558 6558 7558 8558 95589 8 3 | 559 -1559 -2559 3559 -4559 -5559 6559 7559 8559 95590 9 3 | -355 -1355 2355 3355 4355 -5355 6355 -7355 8355 93551 9 3 | -354 -1354 2354 3354 4354 -5354 6354 -7354 8354 93542 9 3 | -353 -1353 2353 3353 4353 -5353 6353 -7353 8353 93533 9 3 | 543 -1543 -2543 3543 -4543 -5543 6543 7543 8543 95434 9 3 | 544 -1544 -2544 3544 -4544 -5544 6544 7544 8544 95445 9 3 | 545 -1545 -2545 3545 -4545 -5545 6545 7545 8545 95456 9 3 | 546 -1546 -2546 3546 -4546 -5546 6546 7546 8546 95467 9 3 | 547 -1547 -2547 3547 -4547 -5547 6547 7547 8547 95478 9 3 | 548 -1548 -2548 3548 -4548 -5548 6548 7548 8548 95489 9 3 | 549 -1549 -2549 3549 -4549 -5549 6549 7549 8549 95490 0 4 | -445 -1445 2445 3445 4445 -5445 6445 -7445 8445 94451 0 4 | -444 -1444 2444 3444 4444 -5444 6444 -7444 8444 94442 0 4 | -443 -1443 2443 3443 4443 -5443 6443 -7443 8443 94433 0 4 | 653 -1653 -2653 3653 -4653 -5653 6653 7653 8653 96534 0 4 | 654 -1654 -2654 3654 -4654 -5654 6654 7654 8654 96545 0 4 | 655 -1655 -2655 3655 -4655 -5655 6655 7655 8655 96556 0 4 | 656 -1656 -2656 3656 -4656 -5656 6656 7656 8656 96567 0 4 | 657 -1657 -2657 3657 -4657 -5657 6657 7657 8657 96578 0 4 | 658 -1658 -2658 3658 -4658 -5658 6658 7658 8658 96589 0 4 | 659 -1659 -2659 3659 -4659 -5659 6659 7659 8659 96590 1 4 | -455 -1455 2455 3455 4455 -5455 6455 -7455 8455 94551 1 4 | -454 -1454 2454 3454 4454 -5454 6454 -7454 8454 94542 1 4 | -453 -1453 2453 3453 4453 -5453 6453 -7453 8453 94533 1 4 | 643 -1643 -2643 3643 -4643 -5643 6643 7643 8643 96434 1 4 | 644 -1644 -2644 3644 -4644 -5644 6644 7644 8644 96445 1 4 | 645 -1645 -2645 3645 -4645 -5645 6645 7645 8645 96456 1 4 | 646 -1646 -2646 3646 -4646 -5646 6646 7646 8646 96467 1 4 | 647 -1647 -2647 3647 -4647 -5647 6647 7647 8647 96478 1 4 | 648 -1648 -2648 3648 -4648 -5648 6648 7648 8648 96489 1 4 | 649 -1649 -2649 3649 -4649 -5649 6649 7649 8649 96490 2 4 | -465 -1465 2465 3465 4465 -5465 6465 -7465 8465 94651 2 4 | -464 -1464 2464 3464 4464 -5464 6464 -7464 8464 94642 2 4 | -463 -1463 2463 3463 4463 -5463 6463 -7463 8463 94633 2 4 | 633 -1633 -2633 3633 -4633 -5633 6633 7633 8633 96334 2 4 | 634 -1634 -2634 3634 -4634 -5634 6634 7634 8634 96345 2 4 | 635 -1635 -2635 3635 -4635 -5635 6635 7635 8635 96356 2 4 | 636 -1636 -2636 3636 -4636 -5636 6636 7636 8636 96367 2 4 | 637 -1637 -2637 3637 -4637 -5637 6637 7637 8637 96378 2 4 | 638 -1638 -2638 3638 -4638 -5638 6638 7638 8638 96389 2 4 | 639 -1639 -2639 3639 -4639 -5639 6639 7639 8639 96390 3 4 | -665 1665 -2665 3665 -4665 5665 6665 -7665 8665 96651 3 4 | -664 1664 -2664 3664 -4664 5664 6664 -7664 8664 96642 3 4 | -663 1663 -2663 3663 -4663 5663 6663 -7663 8663 96633 3 4 | 433 1433 2433 3433 4433 5433 6433 7433 8433 94334 3 4 | 434 1434 2434 3434 4434 5434 6434 7434 8434 94345 3 4 | 435 1435 2435 3435 4435 5435 6435 7435 8435 94356 3 4 | 436 1436 2436 3436 4436 5436 6436 7436 8436 94367 3 4 | 437 1437 2437 3437 4437 5437 6437 7437 8437 94378 3 4 | 438 1438 2438 3438 4438 5438 6438 7438 8438 94389 3 4 | 439 1439 2439 3439 4439 5439 6439 7439 8439 94390 4 4 | -655 1655 -2655 3655 -4655 5655 6655 -7655 8655 96551 4 4 | -654 1654 -2654 3654 -4654 5654 6654 -7654 8654 96542 4 4 | -653 1653 -2653 3653 -4653 5653 6653 -7653 8653 96533 4 4 | 443 1443 2443 3443 4443 5443 6443 7443 8443 94434 4 4 | 444 1444 2444 3444 4444 5444 6444 7444 8444 94445 4 4 | 445 1445 2445 3445 4445 5445 6445 7445 8445 94456 4 4 | 446 1446 2446 3446 4446 5446 6446 7446 8446 94467 4 4 | 447 1447 2447 3447 4447 5447 6447 7447 8447 94478 4 4 | 448 1448 2448 3448 4448 5448 6448 7448 8448 94489 4 4 | 449 1449 2449 3449 4449 5449 6449 7449 8449 94490 5 4 | -645 1645 -2645 3645 -4645 5645 6645 -7645 8645 96451 5 4 | -644 1644 -2644 3644 -4644 5644 6644 -7644 8644 96442 5 4 | -643 1643 -2643 3643 -4643 5643 6643 -7643 8643 96433 5 4 | 453 1453 2453 3453 4453 5453 6453 7453 8453 94534 5 4 | 454 1454 2454 3454 4454 5454 6454 7454 8454 94545 5 4 | 455 1455 2455 3455 4455 5455 6455 7455 8455 94556 5 4 | 456 1456 2456 3456 4456 5456 6456 7456 8456 94567 5 4 | 457 1457 2457 3457 4457 5457 6457 7457 8457 94578 5 4 | 458 1458 2458 3458 4458 5458 6458 7458 8458 94589 5 4 | 459 1459 2459 3459 4459 5459 6459 7459 8459 94590 6 4 | -635 1635 -2635 3635 -4635 5635 6635 -7635 8635 96351 6 4 | -634 1634 -2634 3634 -4634 5634 6634 -7634 8634 96342 6 4 | -633 1633 -2633 3633 -4633 5633 6633 -7633 8633 96333 6 4 | 463 1463 2463 3463 4463 5463 6463 7463 8463 94634 6 4 | 464 1464 2464 3464 4464 5464 6464 7464 8464 94645 6 4 | 465 1465 2465 3465 4465 5465 6465 7465 8465 94656 6 4 | 466 1466 2466 3466 4466 5466 6466 7466 8466 94667 6 4 | 467 1467 2467 3467 4467 5467 6467 7467 8467 94678 6 4 | 468 1468 2468 3468 4468 5468 6468 7468 8468 94689 6 4 | 469 1469 2469 3469 4469 5469 6469 7469 8469 94690 7 4 | -435 -1435 2435 3435 4435 -5435 6435 -7435 8435 94351 7 4 | -434 -1434 2434 3434 4434 -5434 6434 -7434 8434 94342 7 4 | -433 -1433 2433 3433 4433 -5433 6433 -7433 8433 94333 7 4 | 663 -1663 -2663 3663 -4663 -5663 6663 7663 8663 96634 7 4 | 664 -1664 -2664 3664 -4664 -5664 6664 7664 8664 96645 7 4 | 665 -1665 -2665 3665 -4665 -5665 6665 7665 8665 96656 7 4 | 666 -1666 -2666 3666 -4666 -5666 6666 7666 8666 96667 7 4 | 667 -1667 -2667 3667 -4667 -5667 6667 7667 8667 96678 7 4 | 668 -1668 -2668 3668 -4668 -5668 6668 7668 8668 96689 7 4 | 669 -1669 -2669 3669 -4669 -5669 6669 7669 8669 96690 8 4 | -445 -1445 2445 3445 4445 -5445 6445 -7445 8445 94451 8 4 | -444 -1444 2444 3444 4444 -5444 6444 -7444 8444 94442 8 4 | -443 -1443 2443 3443 4443 -5443 6443 -7443 8443 94433 8 4 | 653 -1653 -2653 3653 -4653 -5653 6653 7653 8653 96534 8 4 | 654 -1654 -2654 3654 -4654 -5654 6654 7654 8654 96545 8 4 | 655 -1655 -2655 3655 -4655 -5655 6655 7655 8655 96556 8 4 | 656 -1656 -2656 3656 -4656 -5656 6656 7656 8656 96567 8 4 | 657 -1657 -2657 3657 -4657 -5657 6657 7657 8657 96578 8 4 | 658 -1658 -2658 3658 -4658 -5658 6658 7658 8658 96589 8 4 | 659 -1659 -2659 3659 -4659 -5659 6659 7659 8659 96590 9 4 | -455 -1455 2455 3455 4455 -5455 6455 -7455 8455 94551 9 4 | -454 -1454 2454 3454 4454 -5454 6454 -7454 8454 94542 9 4 | -453 -1453 2453 3453 4453 -5453 6453 -7453 8453 94533 9 4 | 643 -1643 -2643 3643 -4643 -5643 6643 7643 8643 96434 9 4 | 644 -1644 -2644 3644 -4644 -5644 6644 7644 8644 96445 9 4 | 645 -1645 -2645 3645 -4645 -5645 6645 7645 8645 96456 9 4 | 646 -1646 -2646 3646 -4646 -5646 6646 7646 8646 96467 9 4 | 647 -1647 -2647 3647 -4647 -5647 6647 7647 8647 96478 9 4 | 648 -1648 -2648 3648 -4648 -5648 6648 7648 8648 96489 9 4 | 649 -1649 -2649 3649 -4649 -5649 6649 7649 8649 96490 0 5 | -545 -1545 2545 3545 4545 -5545 6545 -7545 8545 95451 0 5 | -544 -1544 2544 3544 4544 -5544 6544 -7544 8544 95442 0 5 | -543 -1543 2543 3543 4543 -5543 6543 -7543 8543 95433 0 5 | 353 -1353 -2353 3353 -4353 -5353 6353 7353 8353 93534 0 5 | 354 -1354 -2354 3354 -4354 -5354 6354 7354 8354 93545 0 5 | 355 -1355 -2355 3355 -4355 -5355 6355 7355 8355 93556 0 5 | 356 -1356 -2356 3356 -4356 -5356 6356 7356 8356 93567 0 5 | 357 -1357 -2357 3357 -4357 -5357 6357 7357 8357 93578 0 5 | 358 -1358 -2358 3358 -4358 -5358 6358 7358 8358 93589 0 5 | 359 -1359 -2359 3359 -4359 -5359 6359 7359 8359 93590 1 5 | -555 -1555 2555 3555 4555 -5555 6555 -7555 8555 95551 1 5 | -554 -1554 2554 3554 4554 -5554 6554 -7554 8554 95542 1 5 | -553 -1553 2553 3553 4553 -5553 6553 -7553 8553 95533 1 5 | 343 -1343 -2343 3343 -4343 -5343 6343 7343 8343 93434 1 5 | 344 -1344 -2344 3344 -4344 -5344 6344 7344 8344 93445 1 5 | 345 -1345 -2345 3345 -4345 -5345 6345 7345 8345 93456 1 5 | 346 -1346 -2346 3346 -4346 -5346 6346 7346 8346 93467 1 5 | 347 -1347 -2347 3347 -4347 -5347 6347 7347 8347 93478 1 5 | 348 -1348 -2348 3348 -4348 -5348 6348 7348 8348 93489 1 5 | 349 -1349 -2349 3349 -4349 -5349 6349 7349 8349 93490 2 5 | -565 -1565 2565 3565 4565 -5565 6565 -7565 8565 95651 2 5 | -564 -1564 2564 3564 4564 -5564 6564 -7564 8564 95642 2 5 | -563 -1563 2563 3563 4563 -5563 6563 -7563 8563 95633 2 5 | 333 -1333 -2333 3333 -4333 -5333 6333 7333 8333 93334 2 5 | 334 -1334 -2334 3334 -4334 -5334 6334 7334 8334 93345 2 5 | 335 -1335 -2335 3335 -4335 -5335 6335 7335 8335 93356 2 5 | 336 -1336 -2336 3336 -4336 -5336 6336 7336 8336 93367 2 5 | 337 -1337 -2337 3337 -4337 -5337 6337 7337 8337 93378 2 5 | 338 -1338 -2338 3338 -4338 -5338 6338 7338 8338 93389 2 5 | 339 -1339 -2339 3339 -4339 -5339 6339 7339 8339 93390 3 5 | -365 1365 -2365 3365 -4365 5365 6365 -7365 8365 93651 3 5 | -364 1364 -2364 3364 -4364 5364 6364 -7364 8364 93642 3 5 | -363 1363 -2363 3363 -4363 5363 6363 -7363 8363 93633 3 5 | 533 1533 2533 3533 4533 5533 6533 7533 8533 95334 3 5 | 534 1534 2534 3534 4534 5534 6534 7534 8534 95345 3 5 | 535 1535 2535 3535 4535 5535 6535 7535 8535 95356 3 5 | 536 1536 2536 3536 4536 5536 6536 7536 8536 95367 3 5 | 537 1537 2537 3537 4537 5537 6537 7537 8537 95378 3 5 | 538 1538 2538 3538 4538 5538 6538 7538 8538 95389 3 5 | 539 1539 2539 3539 4539 5539 6539 7539 8539 95390 4 5 | -355 1355 -2355 3355 -4355 5355 6355 -7355 8355 93551 4 5 | -354 1354 -2354 3354 -4354 5354 6354 -7354 8354 93542 4 5 | -353 1353 -2353 3353 -4353 5353 6353 -7353 8353 93533 4 5 | 543 1543 2543 3543 4543 5543 6543 7543 8543 95434 4 5 | 544 1544 2544 3544 4544 5544 6544 7544 8544 95445 4 5 | 545 1545 2545 3545 4545 5545 6545 7545 8545 95456 4 5 | 546 1546 2546 3546 4546 5546 6546 7546 8546 95467 4 5 | 547 1547 2547 3547 4547 5547 6547 7547 8547 95478 4 5 | 548 1548 2548 3548 4548 5548 6548 7548 8548 95489 4 5 | 549 1549 2549 3549 4549 5549 6549 7549 8549 95490 5 5 | -345 1345 -2345 3345 -4345 5345 6345 -7345 8345 93451 5 5 | -344 1344 -2344 3344 -4344 5344 6344 -7344 8344 93442 5 5 | -343 1343 -2343 3343 -4343 5343 6343 -7343 8343 93433 5 5 | 553 1553 2553 3553 4553 5553 6553 7553 8553 95534 5 5 | 554 1554 2554 3554 4554 5554 6554 7554 8554 95545 5 5 | 555 1555 2555 3555 4555 5555 6555 7555 8555 95556 5 5 | 556 1556 2556 3556 4556 5556 6556 7556 8556 95567 5 5 | 557 1557 2557 3557 4557 5557 6557 7557 8557 95578 5 5 | 558 1558 2558 3558 4558 5558 6558 7558 8558 95589 5 5 | 559 1559 2559 3559 4559 5559 6559 7559 8559 95590 6 5 | -335 1335 -2335 3335 -4335 5335 6335 -7335 8335 93351 6 5 | -334 1334 -2334 3334 -4334 5334 6334 -7334 8334 93342 6 5 | -333 1333 -2333 3333 -4333 5333 6333 -7333 8333 93333 6 5 | 563 1563 2563 3563 4563 5563 6563 7563 8563 95634 6 5 | 564 1564 2564 3564 4564 5564 6564 7564 8564 95645 6 5 | 565 1565 2565 3565 4565 5565 6565 7565 8565 95656 6 5 | 566 1566 2566 3566 4566 5566 6566 7566 8566 95667 6 5 | 567 1567 2567 3567 4567 5567 6567 7567 8567 95678 6 5 | 568 1568 2568 3568 4568 5568 6568 7568 8568 95689 6 5 | 569 1569 2569 3569 4569 5569 6569 7569 8569 95690 7 5 | -535 -1535 2535 3535 4535 -5535 6535 -7535 8535 95351 7 5 | -534 -1534 2534 3534 4534 -5534 6534 -7534 8534 95342 7 5 | -533 -1533 2533 3533 4533 -5533 6533 -7533 8533 95333 7 5 | 363 -1363 -2363 3363 -4363 -5363 6363 7363 8363 93634 7 5 | 364 -1364 -2364 3364 -4364 -5364 6364 7364 8364 93645 7 5 | 365 -1365 -2365 3365 -4365 -5365 6365 7365 8365 93656 7 5 | 366 -1366 -2366 3366 -4366 -5366 6366 7366 8366 93667 7 5 | 367 -1367 -2367 3367 -4367 -5367 6367 7367 8367 93678 7 5 | 368 -1368 -2368 3368 -4368 -5368 6368 7368 8368 93689 7 5 | 369 -1369 -2369 3369 -4369 -5369 6369 7369 8369 93690 8 5 | -545 -1545 2545 3545 4545 -5545 6545 -7545 8545 95451 8 5 | -544 -1544 2544 3544 4544 -5544 6544 -7544 8544 95442 8 5 | -543 -1543 2543 3543 4543 -5543 6543 -7543 8543 95433 8 5 | 353 -1353 -2353 3353 -4353 -5353 6353 7353 8353 93534 8 5 | 354 -1354 -2354 3354 -4354 -5354 6354 7354 8354 93545 8 5 | 355 -1355 -2355 3355 -4355 -5355 6355 7355 8355 93556 8 5 | 356 -1356 -2356 3356 -4356 -5356 6356 7356 8356 93567 8 5 | 357 -1357 -2357 3357 -4357 -5357 6357 7357 8357 93578 8 5 | 358 -1358 -2358 3358 -4358 -5358 6358 7358 8358 93589 8 5 | 359 -1359 -2359 3359 -4359 -5359 6359 7359 8359 93590 9 5 | -555 -1555 2555 3555 4555 -5555 6555 -7555 8555 95551 9 5 | -554 -1554 2554 3554 4554 -5554 6554 -7554 8554 95542 9 5 | -553 -1553 2553 3553 4553 -5553 6553 -7553 8553 95533 9 5 | 343 -1343 -2343 3343 -4343 -5343 6343 7343 8343 93434 9 5 | 344 -1344 -2344 3344 -4344 -5344 6344 7344 8344 93445 9 5 | 345 -1345 -2345 3345 -4345 -5345 6345 7345 8345 93456 9 5 | 346 -1346 -2346 3346 -4346 -5346 6346 7346 8346 93467 9 5 | 347 -1347 -2347 3347 -4347 -5347 6347 7347 8347 93478 9 5 | 348 -1348 -2348 3348 -4348 -5348 6348 7348 8348 93489 9 5 | 349 -1349 -2349 3349 -4349 -5349 6349 7349 8349 93490 0 6 | -645 -1645 2645 3645 4645 -5645 6645 -7645 8645 96451 0 6 | -644 -1644 2644 3644 4644 -5644 6644 -7644 8644 96442 0 6 | -643 -1643 2643 3643 4643 -5643 6643 -7643 8643 96433 0 6 | 453 -1453 -2453 3453 -4453 -5453 6453 7453 8453 94534 0 6 | 454 -1454 -2454 3454 -4454 -5454 6454 7454 8454 94545 0 6 | 455 -1455 -2455 3455 -4455 -5455 6455 7455 8455 94556 0 6 | 456 -1456 -2456 3456 -4456 -5456 6456 7456 8456 94567 0 6 | 457 -1457 -2457 3457 -4457 -5457 6457 7457 8457 94578 0 6 | 458 -1458 -2458 3458 -4458 -5458 6458 7458 8458 94589 0 6 | 459 -1459 -2459 3459 -4459 -5459 6459 7459 8459 94590 1 6 | -655 -1655 2655 3655 4655 -5655 6655 -7655 8655 96551 1 6 | -654 -1654 2654 3654 4654 -5654 6654 -7654 8654 96542 1 6 | -653 -1653 2653 3653 4653 -5653 6653 -7653 8653 96533 1 6 | 443 -1443 -2443 3443 -4443 -5443 6443 7443 8443 94434 1 6 | 444 -1444 -2444 3444 -4444 -5444 6444 7444 8444 94445 1 6 | 445 -1445 -2445 3445 -4445 -5445 6445 7445 8445 94456 1 6 | 446 -1446 -2446 3446 -4446 -5446 6446 7446 8446 94467 1 6 | 447 -1447 -2447 3447 -4447 -5447 6447 7447 8447 94478 1 6 | 448 -1448 -2448 3448 -4448 -5448 6448 7448 8448 94489 1 6 | 449 -1449 -2449 3449 -4449 -5449 6449 7449 8449 94490 2 6 | -665 -1665 2665 3665 4665 -5665 6665 -7665 8665 96651 2 6 | -664 -1664 2664 3664 4664 -5664 6664 -7664 8664 96642 2 6 | -663 -1663 2663 3663 4663 -5663 6663 -7663 8663 96633 2 6 | 433 -1433 -2433 3433 -4433 -5433 6433 7433 8433 94334 2 6 | 434 -1434 -2434 3434 -4434 -5434 6434 7434 8434 94345 2 6 | 435 -1435 -2435 3435 -4435 -5435 6435 7435 8435 94356 2 6 | 436 -1436 -2436 3436 -4436 -5436 6436 7436 8436 94367 2 6 | 437 -1437 -2437 3437 -4437 -5437 6437 7437 8437 94378 2 6 | 438 -1438 -2438 3438 -4438 -5438 6438 7438 8438 94389 2 6 | 439 -1439 -2439 3439 -4439 -5439 6439 7439 8439 94390 3 6 | -465 1465 -2465 3465 -4465 5465 6465 -7465 8465 94651 3 6 | -464 1464 -2464 3464 -4464 5464 6464 -7464 8464 94642 3 6 | -463 1463 -2463 3463 -4463 5463 6463 -7463 8463 94633 3 6 | 633 1633 2633 3633 4633 5633 6633 7633 8633 96334 3 6 | 634 1634 2634 3634 4634 5634 6634 7634 8634 96345 3 6 | 635 1635 2635 3635 4635 5635 6635 7635 8635 96356 3 6 | 636 1636 2636 3636 4636 5636 6636 7636 8636 96367 3 6 | 637 1637 2637 3637 4637 5637 6637 7637 8637 96378 3 6 | 638 1638 2638 3638 4638 5638 6638 7638 8638 96389 3 6 | 639 1639 2639 3639 4639 5639 6639 7639 8639 96390 4 6 | -455 1455 -2455 3455 -4455 5455 6455 -7455 8455 94551 4 6 | -454 1454 -2454 3454 -4454 5454 6454 -7454 8454 94542 4 6 | -453 1453 -2453 3453 -4453 5453 6453 -7453 8453 94533 4 6 | 643 1643 2643 3643 4643 5643 6643 7643 8643 96434 4 6 | 644 1644 2644 3644 4644 5644 6644 7644 8644 96445 4 6 | 645 1645 2645 3645 4645 5645 6645 7645 8645 96456 4 6 | 646 1646 2646 3646 4646 5646 6646 7646 8646 96467 4 6 | 647 1647 2647 3647 4647 5647 6647 7647 8647 96478 4 6 | 648 1648 2648 3648 4648 5648 6648 7648 8648 96489 4 6 | 649 1649 2649 3649 4649 5649 6649 7649 8649 96490 5 6 | -445 1445 -2445 3445 -4445 5445 6445 -7445 8445 94451 5 6 | -444 1444 -2444 3444 -4444 5444 6444 -7444 8444 94442 5 6 | -443 1443 -2443 3443 -4443 5443 6443 -7443 8443 94433 5 6 | 653 1653 2653 3653 4653 5653 6653 7653 8653 96534 5 6 | 654 1654 2654 3654 4654 5654 6654 7654 8654 96545 5 6 | 655 1655 2655 3655 4655 5655 6655 7655 8655 96556 5 6 | 656 1656 2656 3656 4656 5656 6656 7656 8656 96567 5 6 | 657 1657 2657 3657 4657 5657 6657 7657 8657 96578 5 6 | 658 1658 2658 3658 4658 5658 6658 7658 8658 96589 5 6 | 659 1659 2659 3659 4659 5659 6659 7659 8659 96590 6 6 | -435 1435 -2435 3435 -4435 5435 6435 -7435 8435 94351 6 6 | -434 1434 -2434 3434 -4434 5434 6434 -7434 8434 94342 6 6 | -433 1433 -2433 3433 -4433 5433 6433 -7433 8433 94333 6 6 | 663 1663 2663 3663 4663 5663 6663 7663 8663 96634 6 6 | 664 1664 2664 3664 4664 5664 6664 7664 8664 96645 6 6 | 665 1665 2665 3665 4665 5665 6665 7665 8665 96656 6 6 | 666 1666 2666 3666 4666 5666 6666 7666 8666 96667 6 6 | 667 1667 2667 3667 4667 5667 6667 7667 8667 96678 6 6 | 668 1668 2668 3668 4668 5668 6668 7668 8668 96689 6 6 | 669 1669 2669 3669 4669 5669 6669 7669 8669 96690 7 6 | -635 -1635 2635 3635 4635 -5635 6635 -7635 8635 96351 7 6 | -634 -1634 2634 3634 4634 -5634 6634 -7634 8634 96342 7 6 | -633 -1633 2633 3633 4633 -5633 6633 -7633 8633 96333 7 6 | 463 -1463 -2463 3463 -4463 -5463 6463 7463 8463 94634 7 6 | 464 -1464 -2464 3464 -4464 -5464 6464 7464 8464 94645 7 6 | 465 -1465 -2465 3465 -4465 -5465 6465 7465 8465 94656 7 6 | 466 -1466 -2466 3466 -4466 -5466 6466 7466 8466 94667 7 6 | 467 -1467 -2467 3467 -4467 -5467 6467 7467 8467 94678 7 6 | 468 -1468 -2468 3468 -4468 -5468 6468 7468 8468 94689 7 6 | 469 -1469 -2469 3469 -4469 -5469 6469 7469 8469 94690 8 6 | -645 -1645 2645 3645 4645 -5645 6645 -7645 8645 96451 8 6 | -644 -1644 2644 3644 4644 -5644 6644 -7644 8644 96442 8 6 | -643 -1643 2643 3643 4643 -5643 6643 -7643 8643 96433 8 6 | 453 -1453 -2453 3453 -4453 -5453 6453 7453 8453 94534 8 6 | 454 -1454 -2454 3454 -4454 -5454 6454 7454 8454 94545 8 6 | 455 -1455 -2455 3455 -4455 -5455 6455 7455 8455 94556 8 6 | 456 -1456 -2456 3456 -4456 -5456 6456 7456 8456 94567 8 6 | 457 -1457 -2457 3457 -4457 -5457 6457 7457 8457 94578 8 6 | 458 -1458 -2458 3458 -4458 -5458 6458 7458 8458 94589 8 6 | 459 -1459 -2459 3459 -4459 -5459 6459 7459 8459 94590 9 6 | -655 -1655 2655 3655 4655 -5655 6655 -7655 8655 96551 9 6 | -654 -1654 2654 3654 4654 -5654 6654 -7654 8654 96542 9 6 | -653 -1653 2653 3653 4653 -5653 6653 -7653 8653 96533 9 6 | 443 -1443 -2443 3443 -4443 -5443 6443 7443 8443 94434 9 6 | 444 -1444 -2444 3444 -4444 -5444 6444 7444 8444 94445 9 6 | 445 -1445 -2445 3445 -4445 -5445 6445 7445 8445 94456 9 6 | 446 -1446 -2446 3446 -4446 -5446 6446 7446 8446 94467 9 6 | 447 -1447 -2447 3447 -4447 -5447 6447 7447 8447 94478 9 6 | 448 -1448 -2448 3448 -4448 -5448 6448 7448 8448 94489 9 6 | 449 -1449 -2449 3449 -4449 -5449 6449 7449 8449 94490 0 7 | -345 -1345 2345 3345 4345 -5345 6345 -7345 8345 93451 0 7 | -344 -1344 2344 3344 4344 -5344 6344 -7344 8344 93442 0 7 | -343 -1343 2343 3343 4343 -5343 6343 -7343 8343 93433 0 7 | 553 -1553 -2553 3553 -4553 -5553 6553 7553 8553 95534 0 7 | 554 -1554 -2554 3554 -4554 -5554 6554 7554 8554 95545 0 7 | 555 -1555 -2555 3555 -4555 -5555 6555 7555 8555 95556 0 7 | 556 -1556 -2556 3556 -4556 -5556 6556 7556 8556 95567 0 7 | 557 -1557 -2557 3557 -4557 -5557 6557 7557 8557 95578 0 7 | 558 -1558 -2558 3558 -4558 -5558 6558 7558 8558 95589 0 7 | 559 -1559 -2559 3559 -4559 -5559 6559 7559 8559 95590 1 7 | -355 -1355 2355 3355 4355 -5355 6355 -7355 8355 93551 1 7 | -354 -1354 2354 3354 4354 -5354 6354 -7354 8354 93542 1 7 | -353 -1353 2353 3353 4353 -5353 6353 -7353 8353 93533 1 7 | 543 -1543 -2543 3543 -4543 -5543 6543 7543 8543 95434 1 7 | 544 -1544 -2544 3544 -4544 -5544 6544 7544 8544 95445 1 7 | 545 -1545 -2545 3545 -4545 -5545 6545 7545 8545 95456 1 7 | 546 -1546 -2546 3546 -4546 -5546 6546 7546 8546 95467 1 7 | 547 -1547 -2547 3547 -4547 -5547 6547 7547 8547 95478 1 7 | 548 -1548 -2548 3548 -4548 -5548 6548 7548 8548 95489 1 7 | 549 -1549 -2549 3549 -4549 -5549 6549 7549 8549 95490 2 7 | -365 -1365 2365 3365 4365 -5365 6365 -7365 8365 93651 2 7 | -364 -1364 2364 3364 4364 -5364 6364 -7364 8364 93642 2 7 | -363 -1363 2363 3363 4363 -5363 6363 -7363 8363 93633 2 7 | 533 -1533 -2533 3533 -4533 -5533 6533 7533 8533 95334 2 7 | 534 -1534 -2534 3534 -4534 -5534 6534 7534 8534 95345 2 7 | 535 -1535 -2535 3535 -4535 -5535 6535 7535 8535 95356 2 7 | 536 -1536 -2536 3536 -4536 -5536 6536 7536 8536 95367 2 7 | 537 -1537 -2537 3537 -4537 -5537 6537 7537 8537 95378 2 7 | 538 -1538 -2538 3538 -4538 -5538 6538 7538 8538 95389 2 7 | 539 -1539 -2539 3539 -4539 -5539 6539 7539 8539 95390 3 7 | -565 1565 -2565 3565 -4565 5565 6565 -7565 8565 95651 3 7 | -564 1564 -2564 3564 -4564 5564 6564 -7564 8564 95642 3 7 | -563 1563 -2563 3563 -4563 5563 6563 -7563 8563 95633 3 7 | 333 1333 2333 3333 4333 5333 6333 7333 8333 93334 3 7 | 334 1334 2334 3334 4334 5334 6334 7334 8334 93345 3 7 | 335 1335 2335 3335 4335 5335 6335 7335 8335 93356 3 7 | 336 1336 2336 3336 4336 5336 6336 7336 8336 93367 3 7 | 337 1337 2337 3337 4337 5337 6337 7337 8337 93378 3 7 | 338 1338 2338 3338 4338 5338 6338 7338 8338 93389 3 7 | 339 1339 2339 3339 4339 5339 6339 7339 8339 93390 4 7 | -555 1555 -2555 3555 -4555 5555 6555 -7555 8555 95551 4 7 | -554 1554 -2554 3554 -4554 5554 6554 -7554 8554 95542 4 7 | -553 1553 -2553 3553 -4553 5553 6553 -7553 8553 95533 4 7 | 343 1343 2343 3343 4343 5343 6343 7343 8343 93434 4 7 | 344 1344 2344 3344 4344 5344 6344 7344 8344 93445 4 7 | 345 1345 2345 3345 4345 5345 6345 7345 8345 93456 4 7 | 346 1346 2346 3346 4346 5346 6346 7346 8346 93467 4 7 | 347 1347 2347 3347 4347 5347 6347 7347 8347 93478 4 7 | 348 1348 2348 3348 4348 5348 6348 7348 8348 93489 4 7 | 349 1349 2349 3349 4349 5349 6349 7349 8349 93490 5 7 | -545 1545 -2545 3545 -4545 5545 6545 -7545 8545 95451 5 7 | -544 1544 -2544 3544 -4544 5544 6544 -7544 8544 95442 5 7 | -543 1543 -2543 3543 -4543 5543 6543 -7543 8543 95433 5 7 | 353 1353 2353 3353 4353 5353 6353 7353 8353 93534 5 7 | 354 1354 2354 3354 4354 5354 6354 7354 8354 93545 5 7 | 355 1355 2355 3355 4355 5355 6355 7355 8355 93556 5 7 | 356 1356 2356 3356 4356 5356 6356 7356 8356 93567 5 7 | 357 1357 2357 3357 4357 5357 6357 7357 8357 93578 5 7 | 358 1358 2358 3358 4358 5358 6358 7358 8358 93589 5 7 | 359 1359 2359 3359 4359 5359 6359 7359 8359 93590 6 7 | -535 1535 -2535 3535 -4535 5535 6535 -7535 8535 95351 6 7 | -534 1534 -2534 3534 -4534 5534 6534 -7534 8534 95342 6 7 | -533 1533 -2533 3533 -4533 5533 6533 -7533 8533 95333 6 7 | 363 1363 2363 3363 4363 5363 6363 7363 8363 93634 6 7 | 364 1364 2364 3364 4364 5364 6364 7364 8364 93645 6 7 | 365 1365 2365 3365 4365 5365 6365 7365 8365 93656 6 7 | 366 1366 2366 3366 4366 5366 6366 7366 8366 93667 6 7 | 367 1367 2367 3367 4367 5367 6367 7367 8367 93678 6 7 | 368 1368 2368 3368 4368 5368 6368 7368 8368 93689 6 7 | 369 1369 2369 3369 4369 5369 6369 7369 8369 93690 7 7 | -335 -1335 2335 3335 4335 -5335 6335 -7335 8335 93351 7 7 | -334 -1334 2334 3334 4334 -5334 6334 -7334 8334 93342 7 7 | -333 -1333 2333 3333 4333 -5333 6333 -7333 8333 93333 7 7 | 563 -1563 -2563 3563 -4563 -5563 6563 7563 8563 95634 7 7 | 564 -1564 -2564 3564 -4564 -5564 6564 7564 8564 95645 7 7 | 565 -1565 -2565 3565 -4565 -5565 6565 7565 8565 95656 7 7 | 566 -1566 -2566 3566 -4566 -5566 6566 7566 8566 95667 7 7 | 567 -1567 -2567 3567 -4567 -5567 6567 7567 8567 95678 7 7 | 568 -1568 -2568 3568 -4568 -5568 6568 7568 8568 95689 7 7 | 569 -1569 -2569 3569 -4569 -5569 6569 7569 8569 95690 8 7 | -345 -1345 2345 3345 4345 -5345 6345 -7345 8345 93451 8 7 | -344 -1344 2344 3344 4344 -5344 6344 -7344 8344 93442 8 7 | -343 -1343 2343 3343 4343 -5343 6343 -7343 8343 93433 8 7 | 553 -1553 -2553 3553 -4553 -5553 6553 7553 8553 95534 8 7 | 554 -1554 -2554 3554 -4554 -5554 6554 7554 8554 95545 8 7 | 555 -1555 -2555 3555 -4555 -5555 6555 7555 8555 95556 8 7 | 556 -1556 -2556 3556 -4556 -5556 6556 7556 8556 95567 8 7 | 557 -1557 -2557 3557 -4557 -5557 6557 7557 8557 95578 8 7 | 558 -1558 -2558 3558 -4558 -5558 6558 7558 8558 95589 8 7 | 559 -1559 -2559 3559 -4559 -5559 6559 7559 8559 95590 9 7 | -355 -1355 2355 3355 4355 -5355 6355 -7355 8355 93551 9 7 | -354 -1354 2354 3354 4354 -5354 6354 -7354 8354 93542 9 7 | -353 -1353 2353 3353 4353 -5353 6353 -7353 8353 93533 9 7 | 543 -1543 -2543 3543 -4543 -5543 6543 7543 8543 95434 9 7 | 544 -1544 -2544 3544 -4544 -5544 6544 7544 8544 95445 9 7 | 545 -1545 -2545 3545 -4545 -5545 6545 7545 8545 95456 9 7 | 546 -1546 -2546 3546 -4546 -5546 6546 7546 8546 95467 9 7 | 547 -1547 -2547 3547 -4547 -5547 6547 7547 8547 95478 9 7 | 548 -1548 -2548 3548 -4548 -5548 6548 7548 8548 95489 9 7 | 549 -1549 -2549 3549 -4549 -5549 6549 7549 8549 95490 0 8 | -445 -1445 2445 3445 4445 -5445 6445 -7445 8445 94451 0 8 | -444 -1444 2444 3444 4444 -5444 6444 -7444 8444 94442 0 8 | -443 -1443 2443 3443 4443 -5443 6443 -7443 8443 94433 0 8 | 653 -1653 -2653 3653 -4653 -5653 6653 7653 8653 96534 0 8 | 654 -1654 -2654 3654 -4654 -5654 6654 7654 8654 96545 0 8 | 655 -1655 -2655 3655 -4655 -5655 6655 7655 8655 96556 0 8 | 656 -1656 -2656 3656 -4656 -5656 6656 7656 8656 96567 0 8 | 657 -1657 -2657 3657 -4657 -5657 6657 7657 8657 96578 0 8 | 658 -1658 -2658 3658 -4658 -5658 6658 7658 8658 96589 0 8 | 659 -1659 -2659 3659 -4659 -5659 6659 7659 8659 96590 1 8 | -455 -1455 2455 3455 4455 -5455 6455 -7455 8455 94551 1 8 | -454 -1454 2454 3454 4454 -5454 6454 -7454 8454 94542 1 8 | -453 -1453 2453 3453 4453 -5453 6453 -7453 8453 94533 1 8 | 643 -1643 -2643 3643 -4643 -5643 6643 7643 8643 96434 1 8 | 644 -1644 -2644 3644 -4644 -5644 6644 7644 8644 96445 1 8 | 645 -1645 -2645 3645 -4645 -5645 6645 7645 8645 96456 1 8 | 646 -1646 -2646 3646 -4646 -5646 6646 7646 8646 96467 1 8 | 647 -1647 -2647 3647 -4647 -5647 6647 7647 8647 96478 1 8 | 648 -1648 -2648 3648 -4648 -5648 6648 7648 8648 96489 1 8 | 649 -1649 -2649 3649 -4649 -5649 6649 7649 8649 96490 2 8 | -465 -1465 2465 3465 4465 -5465 6465 -7465 8465 94651 2 8 | -464 -1464 2464 3464 4464 -5464 6464 -7464 8464 94642 2 8 | -463 -1463 2463 3463 4463 -5463 6463 -7463 8463 94633 2 8 | 633 -1633 -2633 3633 -4633 -5633 6633 7633 8633 96334 2 8 | 634 -1634 -2634 3634 -4634 -5634 6634 7634 8634 96345 2 8 | 635 -1635 -2635 3635 -4635 -5635 6635 7635 8635 96356 2 8 | 636 -1636 -2636 3636 -4636 -5636 6636 7636 8636 96367 2 8 | 637 -1637 -2637 3637 -4637 -5637 6637 7637 8637 96378 2 8 | 638 -1638 -2638 3638 -4638 -5638 6638 7638 8638 96389 2 8 | 639 -1639 -2639 3639 -4639 -5639 6639 7639 8639 96390 3 8 | -665 1665 -2665 3665 -4665 5665 6665 -7665 8665 96651 3 8 | -664 1664 -2664 3664 -4664 5664 6664 -7664 8664 96642 3 8 | -663 1663 -2663 3663 -4663 5663 6663 -7663 8663 96633 3 8 | 433 1433 2433 3433 4433 5433 6433 7433 8433 94334 3 8 | 434 1434 2434 3434 4434 5434 6434 7434 8434 94345 3 8 | 435 1435 2435 3435 4435 5435 6435 7435 8435 94356 3 8 | 436 1436 2436 3436 4436 5436 6436 7436 8436 94367 3 8 | 437 1437 2437 3437 4437 5437 6437 7437 8437 94378 3 8 | 438 1438 2438 3438 4438 5438 6438 7438 8438 94389 3 8 | 439 1439 2439 3439 4439 5439 6439 7439 8439 94390 4 8 | -655 1655 -2655 3655 -4655 5655 6655 -7655 8655 96551 4 8 | -654 1654 -2654 3654 -4654 5654 6654 -7654 8654 96542 4 8 | -653 1653 -2653 3653 -4653 5653 6653 -7653 8653 96533 4 8 | 443 1443 2443 3443 4443 5443 6443 7443 8443 94434 4 8 | 444 1444 2444 3444 4444 5444 6444 7444 8444 94445 4 8 | 445 1445 2445 3445 4445 5445 6445 7445 8445 94456 4 8 | 446 1446 2446 3446 4446 5446 6446 7446 8446 94467 4 8 | 447 1447 2447 3447 4447 5447 6447 7447 8447 94478 4 8 | 448 1448 2448 3448 4448 5448 6448 7448 8448 94489 4 8 | 449 1449 2449 3449 4449 5449 6449 7449 8449 94490 5 8 | -645 1645 -2645 3645 -4645 5645 6645 -7645 8645 96451 5 8 | -644 1644 -2644 3644 -4644 5644 6644 -7644 8644 96442 5 8 | -643 1643 -2643 3643 -4643 5643 6643 -7643 8643 96433 5 8 | 453 1453 2453 3453 4453 5453 6453 7453 8453 94534 5 8 | 454 1454 2454 3454 4454 5454 6454 7454 8454 94545 5 8 | 455 1455 2455 3455 4455 5455 6455 7455 8455 94556 5 8 | 456 1456 2456 3456 4456 5456 6456 7456 8456 94567 5 8 | 457 1457 2457 3457 4457 5457 6457 7457 8457 94578 5 8 | 458 1458 2458 3458 4458 5458 6458 7458 8458 94589 5 8 | 459 1459 2459 3459 4459 5459 6459 7459 8459 94590 6 8 | -635 1635 -2635 3635 -4635 5635 6635 -7635 8635 96351 6 8 | -634 1634 -2634 3634 -4634 5634 6634 -7634 8634 96342 6 8 | -633 1633 -2633 3633 -4633 5633 6633 -7633 8633 96333 6 8 | 463 1463 2463 3463 4463 5463 6463 7463 8463 94634 6 8 | 464 1464 2464 3464 4464 5464 6464 7464 8464 94645 6 8 | 465 1465 2465 3465 4465 5465 6465 7465 8465 94656 6 8 | 466 1466 2466 3466 4466 5466 6466 7466 8466 94667 6 8 | 467 1467 2467 3467 4467 5467 6467 7467 8467 94678 6 8 | 468 1468 2468 3468 4468 5468 6468 7468 8468 94689 6 8 | 469 1469 2469 3469 4469 5469 6469 7469 8469 94690 7 8 | -435 -1435 2435 3435 4435 -5435 6435 -7435 8435 94351 7 8 | -434 -1434 2434 3434 4434 -5434 6434 -7434 8434 94342 7 8 | -433 -1433 2433 3433 4433 -5433 6433 -7433 8433 94333 7 8 | 663 -1663 -2663 3663 -4663 -5663 6663 7663 8663 96634 7 8 | 664 -1664 -2664 3664 -4664 -5664 6664 7664 8664 96645 7 8 | 665 -1665 -2665 3665 -4665 -5665 6665 7665 8665 96656 7 8 | 666 -1666 -2666 3666 -4666 -5666 6666 7666 8666 96667 7 8 | 667 -1667 -2667 3667 -4667 -5667 6667 7667 8667 96678 7 8 | 668 -1668 -2668 3668 -4668 -5668 6668 7668 8668 96689 7 8 | 669 -1669 -2669 3669 -4669 -5669 6669 7669 8669 96690 8 8 | -445 -1445 2445 3445 4445 -5445 6445 -7445 8445 94451 8 8 | -444 -1444 2444 3444 4444 -5444 6444 -7444 8444 94442 8 8 | -443 -1443 2443 3443 4443 -5443 6443 -7443 8443 94433 8 8 | 653 -1653 -2653 3653 -4653 -5653 6653 7653 8653 96534 8 8 | 654 -1654 -2654 3654 -4654 -5654 6654 7654 8654 96545 8 8 | 655 -1655 -2655 3655 -4655 -5655 6655 7655 8655 96556 8 8 | 656 -1656 -2656 3656 -4656 -5656 6656 7656 8656 96567 8 8 | 657 -1657 -2657 3657 -4657 -5657 6657 7657 8657 96578 8 8 | 658 -1658 -2658 3658 -4658 -5658 6658 7658 8658 96589 8 8 | 659 -1659 -2659 3659 -4659 -5659 6659 7659 8659 96590 9 8 | -455 -1455 2455 3455 4455 -5455 6455 -7455 8455 94551 9 8 | -454 -1454 2454 3454 4454 -5454 6454 -7454 8454 94542 9 8 | -453 -1453 2453 3453 4453 -5453 6453 -7453 8453 94533 9 8 | 643 -1643 -2643 3643 -4643 -5643 6643 7643 8643 96434 9 8 | 644 -1644 -2644 3644 -4644 -5644 6644 7644 8644 96445 9 8 | 645 -1645 -2645 3645 -4645 -5645 6645 7645 8645 96456 9 8 | 646 -1646 -2646 3646 -4646 -5646 6646 7646 8646 96467 9 8 | 647 -1647 -2647 3647 -4647 -5647 6647 7647 8647 96478 9 8 | 648 -1648 -2648 3648 -4648 -5648 6648 7648 8648 96489 9 8 | 649 -1649 -2649 3649 -4649 -5649 6649 7649 8649 96490 0 9 | -545 -1545 2545 3545 4545 -5545 6545 -7545 8545 95451 0 9 | -544 -1544 2544 3544 4544 -5544 6544 -7544 8544 95442 0 9 | -543 -1543 2543 3543 4543 -5543 6543 -7543 8543 95433 0 9 | 353 -1353 -2353 3353 -4353 -5353 6353 7353 8353 93534 0 9 | 354 -1354 -2354 3354 -4354 -5354 6354 7354 8354 93545 0 9 | 355 -1355 -2355 3355 -4355 -5355 6355 7355 8355 93556 0 9 | 356 -1356 -2356 3356 -4356 -5356 6356 7356 8356 93567 0 9 | 357 -1357 -2357 3357 -4357 -5357 6357 7357 8357 93578 0 9 | 358 -1358 -2358 3358 -4358 -5358 6358 7358 8358 93589 0 9 | 359 -1359 -2359 3359 -4359 -5359 6359 7359 8359 93590 1 9 | -555 -1555 2555 3555 4555 -5555 6555 -7555 8555 95551 1 9 | -554 -1554 2554 3554 4554 -5554 6554 -7554 8554 95542 1 9 | -553 -1553 2553 3553 4553 -5553 6553 -7553 8553 95533 1 9 | 343 -1343 -2343 3343 -4343 -5343 6343 7343 8343 93434 1 9 | 344 -1344 -2344 3344 -4344 -5344 6344 7344 8344 93445 1 9 | 345 -1345 -2345 3345 -4345 -5345 6345 7345 8345 93456 1 9 | 346 -1346 -2346 3346 -4346 -5346 6346 7346 8346 93467 1 9 | 347 -1347 -2347 3347 -4347 -5347 6347 7347 8347 93478 1 9 | 348 -1348 -2348 3348 -4348 -5348 6348 7348 8348 93489 1 9 | 349 -1349 -2349 3349 -4349 -5349 6349 7349 8349 93490 2 9 | -565 -1565 2565 3565 4565 -5565 6565 -7565 8565 95651 2 9 | -564 -1564 2564 3564 4564 -5564 6564 -7564 8564 95642 2 9 | -563 -1563 2563 3563 4563 -5563 6563 -7563 8563 95633 2 9 | 333 -1333 -2333 3333 -4333 -5333 6333 7333 8333 93334 2 9 | 334 -1334 -2334 3334 -4334 -5334 6334 7334 8334 93345 2 9 | 335 -1335 -2335 3335 -4335 -5335 6335 7335 8335 93356 2 9 | 336 -1336 -2336 3336 -4336 -5336 6336 7336 8336 93367 2 9 | 337 -1337 -2337 3337 -4337 -5337 6337 7337 8337 93378 2 9 | 338 -1338 -2338 3338 -4338 -5338 6338 7338 8338 93389 2 9 | 339 -1339 -2339 3339 -4339 -5339 6339 7339 8339 93390 3 9 | -365 1365 -2365 3365 -4365 5365 6365 -7365 8365 93651 3 9 | -364 1364 -2364 3364 -4364 5364 6364 -7364 8364 93642 3 9 | -363 1363 -2363 3363 -4363 5363 6363 -7363 8363 93633 3 9 | 533 1533 2533 3533 4533 5533 6533 7533 8533 95334 3 9 | 534 1534 2534 3534 4534 5534 6534 7534 8534 95345 3 9 | 535 1535 2535 3535 4535 5535 6535 7535 8535 95356 3 9 | 536 1536 2536 3536 4536 5536 6536 7536 8536 95367 3 9 | 537 1537 2537 3537 4537 5537 6537 7537 8537 95378 3 9 | 538 1538 2538 3538 4538 5538 6538 7538 8538 95389 3 9 | 539 1539 2539 3539 4539 5539 6539 7539 8539 95390 4 9 | -355 1355 -2355 3355 -4355 5355 6355 -7355 8355 93551 4 9 | -354 1354 -2354 3354 -4354 5354 6354 -7354 8354 93542 4 9 | -353 1353 -2353 3353 -4353 5353 6353 -7353 8353 93533 4 9 | 543 1543 2543 3543 4543 5543 6543 7543 8543 95434 4 9 | 544 1544 2544 3544 4544 5544 6544 7544 8544 95445 4 9 | 545 1545 2545 3545 4545 5545 6545 7545 8545 95456 4 9 | 546 1546 2546 3546 4546 5546 6546 7546 8546 95467 4 9 | 547 1547 2547 3547 4547 5547 6547 7547 8547 95478 4 9 | 548 1548 2548 3548 4548 5548 6548 7548 8548 95489 4 9 | 549 1549 2549 3549 4549 5549 6549 7549 8549 95490 5 9 | -345 1345 -2345 3345 -4345 5345 6345 -7345 8345 93451 5 9 | -344 1344 -2344 3344 -4344 5344 6344 -7344 8344 93442 5 9 | -343 1343 -2343 3343 -4343 5343 6343 -7343 8343 93433 5 9 | 553 1553 2553 3553 4553 5553 6553 7553 8553 95534 5 9 | 554 1554 2554 3554 4554 5554 6554 7554 8554 95545 5 9 | 555 1555 2555 3555 4555 5555 6555 7555 8555 95556 5 9 | 556 1556 2556 3556 4556 5556 6556 7556 8556 95567 5 9 | 557 1557 2557 3557 4557 5557 6557 7557 8557 95578 5 9 | 558 1558 2558 3558 4558 5558 6558 7558 8558 95589 5 9 | 559 1559 2559 3559 4559 5559 6559 7559 8559 95590 6 9 | -335 1335 -2335 3335 -4335 5335 6335 -7335 8335 93351 6 9 | -334 1334 -2334 3334 -4334 5334 6334 -7334 8334 93342 6 9 | -333 1333 -2333 3333 -4333 5333 6333 -7333 8333 93333 6 9 | 563 1563 2563 3563 4563 5563 6563 7563 8563 95634 6 9 | 564 1564 2564 3564 4564 5564 6564 7564 8564 95645 6 9 | 565 1565 2565 3565 4565 5565 6565 7565 8565 95656 6 9 | 566 1566 2566 3566 4566 5566 6566 7566 8566 95667 6 9 | 567 1567 2567 3567 4567 5567 6567 7567 8567 95678 6 9 | 568 1568 2568 3568 4568 5568 6568 7568 8568 95689 6 9 | 569 1569 2569 3569 4569 5569 6569 7569 8569 95690 7 9 | -535 -1535 2535 3535 4535 -5535 6535 -7535 8535 95351 7 9 | -534 -1534 2534 3534 4534 -5534 6534 -7534 8534 95342 7 9 | -533 -1533 2533 3533 4533 -5533 6533 -7533 8533 95333 7 9 | 363 -1363 -2363 3363 -4363 -5363 6363 7363 8363 93634 7 9 | 364 -1364 -2364 3364 -4364 -5364 6364 7364 8364 93645 7 9 | 365 -1365 -2365 3365 -4365 -5365 6365 7365 8365 93656 7 9 | 366 -1366 -2366 3366 -4366 -5366 6366 7366 8366 93667 7 9 | 367 -1367 -2367 3367 -4367 -5367 6367 7367 8367 93678 7 9 | 368 -1368 -2368 3368 -4368 -5368 6368 7368 8368 93689 7 9 | 369 -1369 -2369 3369 -4369 -5369 6369 7369 8369 93690 8 9 | -545 -1545 2545 3545 4545 -5545 6545 -7545 8545 95451 8 9 | -544 -1544 2544 3544 4544 -5544 6544 -7544 8544 95442 8 9 | -543 -1543 2543 3543 4543 -5543 6543 -7543 8543 95433 8 9 | 353 -1353 -2353 3353 -4353 -5353 6353 7353 8353 93534 8 9 | 354 -1354 -2354 3354 -4354 -5354 6354 7354 8354 93545 8 9 | 355 -1355 -2355 3355 -4355 -5355 6355 7355 8355 93556 8 9 | 356 -1356 -2356 3356 -4356 -5356 6356 7356 8356 93567 8 9 | 357 -1357 -2357 3357 -4357 -5357 6357 7357 8357 93578 8 9 | 358 -1358 -2358 3358 -4358 -5358 6358 7358 8358 93589 8 9 | 359 -1359 -2359 3359 -4359 -5359 6359 7359 8359 93590 9 9 | -555 -1555 2555 3555 4555 -5555 6555 -7555 8555 95551 9 9 | -554 -1554 2554 3554 4554 -5554 6554 -7554 8554 95542 9 9 | -553 -1553 2553 3553 4553 -5553 6553 -7553 8553 95533 9 9 | 343 -1343 -2343 3343 -4343 -5343 6343 7343 8343 93434 9 9 | 344 -1344 -2344 3344 -4344 -5344 6344 7344 8344 93445 9 9 | 345 -1345 -2345 3345 -4345 -5345 6345 7345 8345 93456 9 9 | 346 -1346 -2346 3346 -4346 -5346 6346 7346 8346 93467 9 9 | 347 -1347 -2347 3347 -4347 -5347 6347 7347 8347 93478 9 9 | 348 -1348 -2348 3348 -4348 -5348 6348 7348 8348 93489 9 9 | 349 -1349 -2349 3349 -4349 -5349 6349 7349 8349 9349
typedef struct __ghostzone_map__ {short i0,i1,i2; // i0,i1,i2 stores values from -1 (used to indicate outer boundary)// to Nxx_plus_2NGHOSTS*. We assume that grid extents beyond the// limits of short (i.e., beyond about 32,000) are unlikely. This// can be easily extended if needed, though.} gz_map;const int8_t MAXFACE = -1;const int8_t NUL = +0;const int8_t MINFACE = +1;typedef struct __parity__ {int8_t parity[10]; // We store the 10 parity conditions in 10 int8_t integers,// one for each condition. Note that these conditions can// only take one of two values: +1 or -1, hence the use of// int8_t, the smallest C data type.} parity_condition;typedef struct __inner_bc__ {gz_map inner_bc_dest_pt;gz_map inner_bc_src_pt;int8_t parity[10]; // We store the 10 parity conditions in 10 int8_t integers,// one for each condition. Note that these conditions can// only take one of two values: +1 or -1, hence the use of// int8_t, the smallest C data type.} inner_bc;typedef struct __outer_bc__ {gz_map outer_bc_dest_pt;int8_t FACEi0,FACEi1,FACEi2; // FACEi* takes values of -1, 0, and +1 only,// corresponding to MAXFACE, NUL, and MINFACE// respectively.// Thus int8_t (one byte each, the smallest C// type) is sufficient.} outer_bc;typedef struct __bcstruct__ {outer_bc **outer; // Array of 1D arrays, of length// [NGHOSTS][num_ob_gz_pts[which_outer_ghostzone_point]]inner_bc **inner; // Array of 1D arrays, of length// [NGHOSTS][num_ib_gz_pts[which_inner_ghostzone_point]]// Arrays storing number of outer/inner boundary ghostzone points at each ghostzone,// of length NGHOSTS:int *num_ob_gz_pts;int *num_ib_gz_pts;} bc_struct;
#include "BCs_data_structs.h"#include "EigenCoord_xxCart.h"#include "set_up__bc_gz_map_and_parity_condns.h"#include "set_bcstruct.h"#include "apply_bcs_curvilinear.h"
// Declare boundary condition BC_UPDATE_OUTER macro,// which updates a single outer boundary face// of the 3D grid cube using quadratic polynomial// extrapolation.#define BC_UPDATE_OUTER(which_gf, i0,i1,i2, FACEX0,FACEX1,FACEX2) { \const int idx3 = IDX3S(i0,i1,i2); \gfs[IDX4S(which_gf,i0,i1,i2)] = \+3.0*gfs[IDX4S(which_gf,i0+1*FACEX0,i1+1*FACEX1,i2+1*FACEX2)] \-3.0*gfs[IDX4S(which_gf,i0+2*FACEX0,i1+2*FACEX1,i2+2*FACEX2)] \+1.0*gfs[IDX4S(which_gf,i0+3*FACEX0,i1+3*FACEX1,i2+3*FACEX2)]; \}// Curvilinear boundary condition driver routine: Apply BCs to all six// boundary faces of the 3D numerical domain, filling in the// innermost ghost zone layer first, and moving outward.void apply_bcs_curvilinear(const paramstruct *restrict params, const bc_struct *restrict bcstruct,const int NUM_GFS, const int8_t *restrict gfs_parity, REAL *restrict gfs) {#pragma omp parallel forfor(int which_gf=0;which_gf<NUM_GFS;which_gf++) {#include "RELATIVE_PATH__set_Cparameters.h" /* Header file containing correct #include for set_Cparameters.h;* accounting for the relative path */for(int which_gz = 0; which_gz < NGHOSTS; which_gz++) {// First apply OUTER boundary conditions,// in case an INNER (parity) boundary point// needs data at the outer boundary:// After updating each face, adjust imin[] and imax[]// to reflect the newly-updated face extents.for(int pt=0;pt<bcstruct->num_ob_gz_pts[which_gz];pt++) {BC_UPDATE_OUTER(which_gf,bcstruct->outer[which_gz][pt].outer_bc_dest_pt.i0,bcstruct->outer[which_gz][pt].outer_bc_dest_pt.i1,bcstruct->outer[which_gz][pt].outer_bc_dest_pt.i2,bcstruct->outer[which_gz][pt].FACEi0,bcstruct->outer[which_gz][pt].FACEi1,bcstruct->outer[which_gz][pt].FACEi2);}// Then apply INNER (parity) boundary conditions:for(int pt=0;pt<bcstruct->num_ib_gz_pts[which_gz];pt++) {const int i0dest = bcstruct->inner[which_gz][pt].inner_bc_dest_pt.i0;const int i1dest = bcstruct->inner[which_gz][pt].inner_bc_dest_pt.i1;const int i2dest = bcstruct->inner[which_gz][pt].inner_bc_dest_pt.i2;const int i0src = bcstruct->inner[which_gz][pt].inner_bc_src_pt.i0;const int i1src = bcstruct->inner[which_gz][pt].inner_bc_src_pt.i1;const int i2src = bcstruct->inner[which_gz][pt].inner_bc_src_pt.i2;const int8_t *prty= bcstruct->inner[which_gz][pt].parity;// printf("%d\n",bcstruct->inner_bc_parity[which_gz][pt].parity[gfs_parity[which_gf]]);gfs[IDX4S(which_gf,i0dest,i1dest,i2dest)] =bcstruct->inner[which_gz][pt].parity[gfs_parity[which_gf]] * gfs[IDX4S(which_gf, i0src,i1src,i2src)];} // END for(int pt=0;pt<num_ib_gz_pts[which_gz];pt++)} // END for(int which_gz = 0; which_gz < NGHOSTS; which_gz++)} // END for(int which_gf=0;which_gf<NUM_GFS;which_gf++)} // END function
for(int i=0;i<NGHOSTS;i++) { free(bcstruct.outer[i]); free(bcstruct.inner[i]); }free(bcstruct.num_ob_gz_pts); free(bcstruct.num_ib_gz_pts);
// Step 1: Allocate memory storage for bc_gz_map, which// in the case a boundary point is a *parity*// boundary, is set to the interior, non-// boundary point corresponding to the same// Cartesian gridpoint. Otherwise bc_gz_map// is set to (i0,i1,i2) = (-1,-1,-1).gz_map *bc_gz_map = (gz_map *)malloc(sizeof(gz_map)*Nxx_plus_2NGHOSTS_tot);// Step 2: Allocate memory storage for bc_parity_conditions,// which store parity conditions for all 10// gridfunction types at all grid points.parity_condition *bc_parity_conditions = (parity_condition *)malloc(sizeof(parity_condition)*Nxx_plus_2NGHOSTS_tot);// Step 3: Set bc_gz_map and bc_parity_conditions at *all*// points; on the boundary and otherwise.set_up__bc_gz_map_and_parity_condns(¶ms, xx, bc_gz_map,bc_parity_conditions);// Step 4: Declare and allocate memory for bcstruct,// which will store all information needed for// applying the boundary conditions.bcstruct.outer = (outer_bc **)malloc(sizeof(outer_bc *)*NGHOSTS);bcstruct.inner = (inner_bc **)malloc(sizeof(inner_bc *)*NGHOSTS);bcstruct.num_ob_gz_pts = ( int *)malloc(sizeof(int)*NGHOSTS);bcstruct.num_ib_gz_pts = ( int *)malloc(sizeof(int)*NGHOSTS);// Step 4: Store all information needed to quickly and// efficiently apply boundary conditions. This// function transfers all information from// bc_gz_map (defined at *all gridpoints*) into// bcstruct (defined only at boundary points).// Thus when this function has finished,// bc_gz_map is no longer needed.set_bcstruct(¶ms,bc_gz_map,bc_parity_conditions,&bcstruct);// Step 5: As described in Step 4, bc_gz_map is no// longer needed at this point, so we free its// memory. Farewell, friend!free(bc_gz_map);free(bc_parity_conditions);
// set_bcstruct() loops from the innermost boundary// ghostzones on the cube ("which_gz==0",// corresponding to the single layer of ghostzones// closest to the interior data), and at each// ghostzone layer, we apply the following 5-step// algorithm:// Step 1: Count the number of outer and inner// boundary points, store to// num_ob_pts and num_ib_pts, respectively.// Step 2: Now that we know the number of outer// boundary points on this ghostzone layer,// allocate memory needed for storing the// outer and inner boundary condition data.// Step 2.a: At all outer boundary ghost zones, allocate// memory for a single member of the outer_bc// data type.// Step 2.b: At all inner boundary ghost zones, allocate// memory for a single member of the inner_bc// data type.// Step 3: Store the number of outer and inner boundary// points on each ghostzone layer, where e.g.,// which_gz==0 corresponds to the innermost// ghostzones on the numerical domain.// Step 4: Store information needed for outer boundary// conditions, to outer_bc_dest_pt and// outer_bc_face arrays.// Step 5: Store information needed for inner boundary// conditions, including interior point to which// inner ghost zone maps, and parity conditions// for all 10 gridfunction types.void set_bcstruct(const paramstruct *restrict params,gz_map *restrict bc_gz_map,parity_condition *bc_parity_conditions,bc_struct *restrict bcstruct) {#include "RELATIVE_PATH__set_Cparameters.h" /* Header file containing correct #include for set_Cparameters.h;* accounting for the relative path */int imin[3] = { NGHOSTS, NGHOSTS, NGHOSTS };int imax[3] = { Nxx_plus_2NGHOSTS0-NGHOSTS, Nxx_plus_2NGHOSTS1-NGHOSTS, Nxx_plus_2NGHOSTS2-NGHOSTS };// Loop from the innermost ghostzone on the cube (which_gz==0) and work outward.// This ordering is necessary, as ghostzones at which_gz==1 will generally// depend on ghostzones at which_gz==0 being already set.for(int which_gz = 0; which_gz < NGHOSTS; which_gz++) {// Step 1: Count the number of outer and inner// boundary points, store to// num_ob_pts and num_ib_pts, respectively.#define COUNT_INNER_OR_OUTER if(bc_gz_map[IDX3S(i0,i1,i2)].i0==-1) { num_ob_pts++;} else { num_ib_pts++; }int num_ob_pts = 0;int num_ib_pts = 0;LOOP_REGION(imin[0]-1,imin[0], imin[1],imax[1], imin[2],imax[2]) { COUNT_INNER_OR_OUTER } imin[0]--;LOOP_REGION(imax[0],imax[0]+1, imin[1],imax[1], imin[2],imax[2]) { COUNT_INNER_OR_OUTER } imax[0]++;LOOP_REGION(imin[0],imax[0], imin[1]-1,imin[1], imin[2],imax[2]) { COUNT_INNER_OR_OUTER } imin[1]--;LOOP_REGION(imin[0],imax[0], imax[1],imax[1]+1, imin[2],imax[2]) { COUNT_INNER_OR_OUTER } imax[1]++;LOOP_REGION(imin[0],imax[0], imin[1],imax[1], imin[2]-1,imin[2]) { COUNT_INNER_OR_OUTER } imin[2]--;LOOP_REGION(imin[0],imax[0], imin[1],imax[1], imax[2],imax[2]+1) { COUNT_INNER_OR_OUTER } imax[2]++;// Step 2: Now that we know the number of outer boundary points on this ghostzone// layer, we allocate memory needed for storing the outer and inner boundary// condition data.// Step 2.a: At all outer boundary ghost zones, allocate memory for a single member of the outer_bc// data type.bcstruct->outer[which_gz] = (outer_bc *)malloc(sizeof(outer_bc)*num_ob_pts);// Step 2.b: At all inner boundary ghost zones, allocate memory for a single member of the inner_bc// data type.bcstruct->inner[which_gz] = (inner_bc *)malloc(sizeof(inner_bc)*num_ib_pts);// Step 3: Store the number of outer and inner boundary points on each ghostzone layer, where e.g.,// which_gz==0 corresponds to the innermost ghostzones on the numerical domain.bcstruct->num_ob_gz_pts[which_gz] = num_ob_pts;bcstruct->num_ib_gz_pts[which_gz] = num_ib_pts;// Reset imin[] and imax[], to prepare for the next step.for(int ii=0;ii<3;ii++) {imin[ii]++; imax[ii]--;}// Step 4: Store information needed for outer boundary conditions, to outer_bc_dest_pt[which_gz][]// and outer_bc_face[which_gz][] arrays:#define OB_SET(facei0,facei1,facei2) if(bc_gz_map[IDX3S(i0,i1,i2)].i0==-1) { \bcstruct->outer[which_gz][pt].outer_bc_dest_pt.i0 = i0; \bcstruct->outer[which_gz][pt].outer_bc_dest_pt.i1 = i1; \bcstruct->outer[which_gz][pt].outer_bc_dest_pt.i2 = i2; \bcstruct->outer[which_gz][pt].FACEi0= facei0; \bcstruct->outer[which_gz][pt].FACEi1= facei1; \bcstruct->outer[which_gz][pt].FACEi2= facei2; \pt++; }int pt = 0;LOOP_REGION(imin[0]-1,imin[0], imin[1],imax[1], imin[2],imax[2]) {OB_SET(MINFACE,NUL,NUL)} imin[0]--;LOOP_REGION(imax[0],imax[0]+1, imin[1],imax[1], imin[2],imax[2]) {OB_SET(MAXFACE,NUL,NUL)} imax[0]++;LOOP_REGION(imin[0],imax[0], imin[1]-1,imin[1], imin[2],imax[2]) {OB_SET(NUL,MINFACE,NUL)} imin[1]--;LOOP_REGION(imin[0],imax[0], imax[1],imax[1]+1, imin[2],imax[2]) {OB_SET(NUL,MAXFACE,NUL)} imax[1]++;LOOP_REGION(imin[0],imax[0], imin[1],imax[1], imin[2]-1,imin[2]) {OB_SET(NUL,NUL,MINFACE)} imin[2]--;LOOP_REGION(imin[0],imax[0], imin[1],imax[1], imax[2],imax[2]+1) {OB_SET(NUL,NUL,MAXFACE)} imax[2]++;// fprintf(stderr,"num OB points with which_gz = %d: %d | should be: %d\n",which_gz,pt,num_ob_gz_pts[which_gz]);// Reset imin[] and imax[], to prepare for the next step.for(int ii=0;ii<3;ii++) {imin[ii]++; imax[ii]--;}// Step 5: Store information needed for inner boundary conditions, including interior point to which// inner ghost zone maps, and parity conditions for all 10 gridfunction types.#define IB_SET if(bc_gz_map[IDX3S(i0,i1,i2)].i0!=-1) { \bcstruct->inner[which_gz][pt].inner_bc_dest_pt.i0=i0; \bcstruct->inner[which_gz][pt].inner_bc_dest_pt.i1=i1; \bcstruct->inner[which_gz][pt].inner_bc_dest_pt.i2=i2; \bcstruct->inner[which_gz][pt].inner_bc_src_pt.i0 =bc_gz_map[IDX3S(i0,i1,i2)].i0; \bcstruct->inner[which_gz][pt].inner_bc_src_pt.i1 =bc_gz_map[IDX3S(i0,i1,i2)].i1; \bcstruct->inner[which_gz][pt].inner_bc_src_pt.i2 =bc_gz_map[IDX3S(i0,i1,i2)].i2; \for(int ii=0;ii<10;ii++) { \bcstruct->inner[which_gz][pt].parity[ii] = \(int8_t)bc_parity_conditions[IDX3S(i0,i1,i2)].parity[ii]; } \pt++; }pt = 0;LOOP_REGION(imin[0]-1,imin[0], imin[1],imax[1], imin[2],imax[2]) {IB_SET} imin[0]--;LOOP_REGION(imax[0],imax[0]+1, imin[1],imax[1], imin[2],imax[2]) {IB_SET} imax[0]++;LOOP_REGION(imin[0],imax[0], imin[1]-1,imin[1], imin[2],imax[2]) {IB_SET} imin[1]--;LOOP_REGION(imin[0],imax[0], imax[1],imax[1]+1, imin[2],imax[2]) {IB_SET} imax[1]++;LOOP_REGION(imin[0],imax[0], imin[1],imax[1], imin[2]-1,imin[2]) {IB_SET} imin[2]--;LOOP_REGION(imin[0],imax[0], imin[1],imax[1], imax[2],imax[2]+1) {IB_SET} imax[2]++;} // END for(int which_gz = 0; which_gz < NGHOSTS; which_gz++)} // END function
// set_parity_conditions_from_symbolic_dot_products():// Evaluate dot products needed for setting parity// conditions at a given point (xx0,xx1,xx2),// using C code generated by NRPy+ function// parity_conditions_symbolic_dot_products().void eval_symbolic_dot_products_to_set_parity_conditions(const paramstruct *restrict params, REAL parity[10],const REAL xx0,const REAL xx1,const REAL xx2,const REAL xx0_inbounds,const REAL xx1_inbounds,const REAL xx2_inbounds) {#include "RELATIVE_PATH__set_Cparameters.h" /* Header file containing correct #include for set_Cparameters.h;* accounting for the relative path */#include "parity_conditions_symbolic_dot_products.h"}void set_up__bc_gz_map_and_parity_condns(const paramstruct *restrict params,REAL *xx[3], gz_map *bc_gz_map,parity_condition *bc_parity_conditions) {#include "RELATIVE_PATH__set_Cparameters.h" /* Header file containing correct #include for set_Cparameters.h;* accounting for the relative path */// xx[0][j] = xxmin[0] + ((REAL)(j-NGHOSTS) + (1.0/2.0))*dxx0;// -> xxmin[0] = xx[0][0] - ((REAL)(0-NGHOSTS) + (1.0/2.0))*dxx0const REAL xxmin[3] = { xx[0][0] - ((REAL)(0-NGHOSTS) + (1.0/2.0))*dxx0,xx[1][0] - ((REAL)(0-NGHOSTS) + (1.0/2.0))*dxx1,xx[2][0] - ((REAL)(0-NGHOSTS) + (1.0/2.0))*dxx2 };//fprintf(stderr,"hey inside setbc: %e %e %e | %e %e\n",xxmin[0],xxmin[1],xxmin[2],xx[0][0],dxx0);LOOP_REGION(0,Nxx_plus_2NGHOSTS0,0,Nxx_plus_2NGHOSTS1,0,Nxx_plus_2NGHOSTS2) {// Step 1: Convert the (curvilinear) coordinate (x0,x1,x2) to Cartesian coordinatesREAL xCart[3];EigenCoord_xxCart(params, xx, i0,i1,i2, xCart);REAL Cartx = xCart[0];REAL Carty = xCart[1];REAL Cartz = xCart[2];// Step 2: Find the (i0_inbounds,i1_inbounds,i2_inbounds) corresponding to the above Cartesian coordinate.// If (i0_inbounds,i1_inbounds,i2_inbounds) is in a ghost zone, then it must equal (i0,i1,i2), and// the point is an outer boundary point.// Otherwise (i0_inbounds,i1_inbounds,i2_inbounds) is in the grid interior, and data at (i0,i1,i2)// must be replaced with data at (i0_inbounds,i1_inbounds,i2_inbounds), but multiplied by the// appropriate parity condition (+/- 1).REAL Cart_to_xx0_inbounds,Cart_to_xx1_inbounds,Cart_to_xx2_inbounds;#include "EigenCoord_Cart_to_xx.h"int i0_inbounds = (int)( (Cart_to_xx0_inbounds - xxmin[0] - (1.0/2.0)*dxx0 + ((REAL)NGHOSTS)*dxx0)/dxx0 + 0.5 );int i1_inbounds = (int)( (Cart_to_xx1_inbounds - xxmin[1] - (1.0/2.0)*dxx1 + ((REAL)NGHOSTS)*dxx1)/dxx1 + 0.5 );int i2_inbounds = (int)( (Cart_to_xx2_inbounds - xxmin[2] - (1.0/2.0)*dxx2 + ((REAL)NGHOSTS)*dxx2)/dxx2 + 0.5 );// Step 2.a: (Sanity/validation check) Convert the interior point// x0(i0_inbounds),x1(i1_inbounds),x2(i2_inbounds) to Cartesian coordinates,// make sure that the Cartesian coordinate matches the Cartesian coordinate of// x0(i0),x1(i1),x2(i2). If not, error out!REAL xCart_orig[3]; for(int ii=0;ii<3;ii++) xCart_orig[ii] = xCart[ii];EigenCoord_xxCart(params, xx, i0_inbounds,i1_inbounds,i2_inbounds, xCart);//fprintf(stderr,"Cartesian agreement: ( %.15e %.15e %.15e ) ?= ( %.15e %.15e %.15e )\n",// (double)xCart_orig[0],(double)xCart_orig[1],(double)xCart_orig[2],// (double)xCart[0],(double)xCart[1],(double)xCart[2]);#define EPS_ABS 1e-8if(fabs( (double)(xCart_orig[0] - xCart[0]) ) > EPS_ABS ||fabs( (double)(xCart_orig[1] - xCart[1]) ) > EPS_ABS ||fabs( (double)(xCart_orig[2] - xCart[2]) ) > EPS_ABS) {fprintf(stderr,"Error. Cartesian disagreement: ( %.15e %.15e %.15e ) != ( %.15e %.15e %.15e )\n",(double)xCart_orig[0],(double)xCart_orig[1],(double)xCart_orig[2],(double)xCart[0],(double)xCart[1],(double)xCart[2]);exit(1);}// Step 3: Set bc_gz_map and bc_parity_conditions.if(i0_inbounds-i0 == 0 && i1_inbounds-i1 == 0 && i2_inbounds-i2 == 0) {// Step 3.a: Iff we are on an outer boundary point or in the grid// interior, i0_inbounds==i0, i1_inbounds==i1, and// i2_inbounds==i2, and inner boundary conditions do not// apply: set bc_gz_map to -1, and parity=1.bc_gz_map[IDX3S(i0,i1,i2)].i0=-1;bc_gz_map[IDX3S(i0,i1,i2)].i1=-1;bc_gz_map[IDX3S(i0,i1,i2)].i2=-1;for(int which_parity=0; which_parity<10; which_parity++) {bc_parity_conditions[IDX3S(i0,i1,i2)].parity[which_parity] = 1;}} else {// Step 3.b: If we are on an *inner* boundary point:// 1. Set bc_gz_map at (i0,i1,i2) to the point// in the interior to which this boundary// point maps, and// 2. Perform the unit vector dot products// necessary to set all 10 possible parity// conditions, calling function// set_parity_from_unit_vector_dot_product()bc_gz_map[IDX3S(i0,i1,i2)].i0=i0_inbounds;bc_gz_map[IDX3S(i0,i1,i2)].i1=i1_inbounds;bc_gz_map[IDX3S(i0,i1,i2)].i2=i2_inbounds;const REAL xx0 = xx[0][i0];const REAL xx1 = xx[1][i1];const REAL xx2 = xx[2][i2];const REAL xx0_inbounds = xx[0][i0_inbounds];const REAL xx1_inbounds = xx[1][i1_inbounds];const REAL xx2_inbounds = xx[2][i2_inbounds];REAL REAL_parity_array[10];eval_symbolic_dot_products_to_set_parity_conditions(params, REAL_parity_array, xx0,xx1,xx2,xx0_inbounds,xx1_inbounds,xx2_inbounds);for(int whichparity=0;whichparity<10;whichparity++) {//printf("Good? Parity %d evaluated to %e\n",whichparity,(double)REAL_parity_array[whichparity]);// Perform sanity check on parity array output: should be +1 or -1 to within 8 significant digits:if( (REAL_parity_array[whichparity] > 0 && fabs(REAL_parity_array[whichparity] - (+1)) > 1e-8) ||(REAL_parity_array[whichparity] <= 0 && fabs(REAL_parity_array[whichparity] - (-1)) > 1e-8) ) {fprintf(stderr,"Error. Parity evaluated to %e , which is not within 8 significant digits of +1 or -1.",REAL_parity_array[whichparity]);exit(1);}if(REAL_parity_array[whichparity] < 0.0) bc_parity_conditions[IDX3S(i0,i1,i2)].parity[whichparity] = -1;if(REAL_parity_array[whichparity] > 0.0) bc_parity_conditions[IDX3S(i0,i1,i2)].parity[whichparity] = +1;}}}}
# As documented in the NRPy+ tutorial module# Tutorial-RK_Butcher_Table_Generating_C_Code.ipynb,# this module will produce the required C codes for# allocating required memory Method of Lines (MoL) timestepping,# implementing MoL timestepping, and deallocating memory# Authors: Brandon Clark# Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step 1: Initialize needed Python/NRPy+ modulesimport sympy as sp # Import SymPy, a computer algebra system written entirely in Pythonimport os # Standard Python module for multiplatform OS-level functionsfrom MoLtimestepping.RK_Butcher_Table_Dictionary import Butcher_dict# Step 2: Checking if Butcher Table is Diagonaldef diagonal(key):diagonal = True # Start with the Butcher table is diagonalButcher = Butcher_dict[key][0]L = len(Butcher)-1 # Establish the number of rows to check for diagonal trait, all bust last rowrow_idx = 0 # Initialize the Butcher table row indexfor i in range(L): # Check all the desired rowsfor j in range(1,row_idx): # Check each element before the diagonal element in a rowif Butcher[i][j] != sp.sympify(0): # If any non-diagonal coeffcient is non-zero,# then the table is not diagonaldiagonal = Falsereturn diagonalrow_idx += 1 # Update to check the next rowreturn diagonal# Step 3: When allocating memory, we populate a list malloced_gridfunctions,# which is used here to determine which gridfunctions need memory freed,# via the free() command. Free the mallocs!def free_allocated_memory(outdir,RK_method,malloced_gridfunctions):# This step is made extremely easy, as we had towith open(os.path.join(outdir, "RK_Free_Memory.h"), "w") as file:file.write("// Code snippet freeing gridfunction memory for \"" + RK_method + "\" method:\n")for gridfunction in malloced_gridfunctions:file.write("free(" + gridfunction + ");\n")# # State whether each Butcher table is diagonal or not# for key, value in Butcher_dict.items():# if diagonal(key) == True:# print("The RK method "+str(key)+" is diagonal! \n")# else:# print("The RK method "+str(key)+" is NOT diagonal! \n")# ################################################################## Step 4: Main driver function for outputting all the MoL C Codedef MoL_C_Code_Generation(RK_method = "RK4", RHS_string = "", post_RHS_string = "",outdir="MoLtimestepping/",MemAllocOnly=False):####### Step 3.a: Allocating Memorymalloc_str = "// Code snippet allocating gridfunction memory for \"" + RK_method + "\" method:\n"# Loop over gridsmalloced_gridfunctions = []# Set gridfunction typetype_str = "REAL *restrict "# Define a couple useful functions for outputting the needed C code for allocating memorydef malloc_gfs_str(varname):malloced_gridfunctions.append(varname)memory_alloc_str = " = (REAL *)malloc(sizeof(REAL) * NUM_EVOL_GFS * Nxx_plus_2NGHOSTS_tot"+")"return type_str + varname + memory_alloc_str + ";\n"def diagnostic_output_gfs_equal_to(gfs):return type_str + "diagnostic_output_gfs"+" = "+gfs + ";\n"# No matter the method we define gridfunctions "y_n_gfs" to store the initial datamalloc_str += malloc_gfs_str("y_n_gfs")if diagonal(RK_method) == True and "RK3" in RK_method:malloc_str += malloc_gfs_str("k1_or_y_nplus_a21_k1_or_y_nplus1_running_total_gfs")malloc_str += malloc_gfs_str("k2_or_y_nplus_a32_k2_gfs")malloc_str += diagnostic_output_gfs_equal_to("k1_or_y_nplus_a21_k1_or_y_nplus1_running_total_gfs")else:if diagonal(RK_method) == False: # Allocate memory for non-diagonal Butcher tables# Determine the number of k_i steps based on length of Butcher Tablenum_k = len(Butcher_dict[RK_method][0])-1# For non-diagonal tables an intermediate gridfunction "next_y_input" is used for rhs evaluationsmalloc_str += malloc_gfs_str("next_y_input_gfs")for i in range(num_k): # Need to allocate all k_i steps for a given methodmalloc_str += malloc_gfs_str("k"+str(i+1)+"_gfs")malloc_str += diagnostic_output_gfs_equal_to("k1_gfs")else: # Allocate memory for diagonal Butcher tables, which use a "y_nplus1_running_total gridfunction"malloc_str += malloc_gfs_str("y_nplus1_running_total_gfs")if RK_method != 'Euler': # Allocate memory for diagonal Butcher tables that aren't Euler# Need k_odd for k_1,3,5... and k_even for k_2,4,6...malloc_str += malloc_gfs_str("k_odd_gfs")malloc_str += malloc_gfs_str("k_even_gfs")malloc_str += diagnostic_output_gfs_equal_to("y_nplus1_running_total_gfs")with open(os.path.join(outdir,"RK_Allocate_Memory.h"), "w") as file:file.write(malloc_str)if MemAllocOnly:free_allocated_memory(outdir,RK_method,malloced_gridfunctions)return######################################################################################################################### EXAMPLE# ODE: y' = f(t,y), y(t_0) = y_0# Starting at time t_n with solution having value y_n and trying to update to y_nplus1 with timestep dt# Example of scheme for RK4 with k_1, k_2, k_3, k_4 (Using non-diagonal algortihm) Notice this requires storage of# y_n, y_nplus1, k_1 through k_4# k_1 = dt*f(t_n, y_n)# k_2 = dt*f(t_n + 1/2*dt, y_n + 1/2*k_1)# k_3 = dt*f(t_n + 1/2*dt, y_n + 1/2*k_2)# k_4 = dt*f(t_n + dt, y_n + k_3)# y_nplus1 = y_n + 1/3k_1 + 1/6k_2 + 1/6k_3 + 1/3k_4# Example of scheme RK4 using only k_odd and k_even (Diagonal algroithm) Notice that this only requires storage# k_odd = dt*f(t_n, y_n)# y_nplus1 = 1/3*k_odd# k_even = dt*f(t_n + 1/2*dt, y_n + 1/2*k_odd)# y_nplus1 += 1/6*k_even# k_odd = dt*f(t_n + 1/2*dt, y_n + 1/2*k_even)# y_nplus1 += 1/6*k_odd# k_even = dt*f(t_n + dt, y_n + k_odd)# y_nplus1 += 1/3*k_even############################################################################################################################### Step 3b: Implementing the Runge Kutta Scheme for Method of Lines TimesteppingButcher = Butcher_dict[RK_method][0] # Get the desired Butcher table from the dictionarynum_steps = len(Butcher)-1 # Specify the number of required steps to update solutionindent = " "RK_str = "// Code snippet implementing "+RK_method+" algorithm for Method of Lines timestepping\n"# Diagonal RK3 only!!!def single_RK_substep(commentblock, RHS_str, RHS_input_str, RHS_output_str, RK_lhss_list, RK_rhss_list,post_RHS_list, post_RHS_output_list, indent = " "):return_str = commentblock + "\n"if not isinstance(RK_lhss_list,list):RK_lhss_list = [RK_lhss_list]if not isinstance(RK_rhss_list,list):RK_rhss_list = [RK_rhss_list]if not isinstance(post_RHS_list,list):post_RHS_list = [post_RHS_list]if not isinstance(post_RHS_output_list,list):post_RHS_output_list = [post_RHS_output_list]# Part 1: RHS evaluation:return_str += RHS_str.replace("RK_INPUT_GFS", RHS_input_str).\replace("RK_OUTPUT_GFS",RHS_output_str)+"\n"# Part 2: RK updatereturn_str += "LOOP_ALL_GFS_GPS"+"(i) {\n"for lhs,rhs in zip(RK_lhss_list,RK_rhss_list):return_str += indent + lhs + "[i] = " + rhs.replace("_gfs","_gfs") + ";\n"return_str += "}\n"# Part 3: Call post-RHS functionsfor post_RHS,post_RHS_output in zip(post_RHS_list,post_RHS_output_list):return_str += post_RHS.replace("RK_OUTPUT_GFS",post_RHS_output)+"\n"return return_str+"\n"RK_str = "// C code implementation of " + RK_method + " Method of Lines timestepping.\n"if diagonal(RK_method) == True and "RK3" in RK_method:# In a diagonal RK3 method, only 3 gridfunctions need be defined. Below implements this approach.# k_1RK_str += """// In a diagonal RK3 method like this one, only 3 gridfunctions need be defined. Below implements this approach.// Using y_n_gfs as input, k1 and apply boundary conditions\n"""RK_str += single_RK_substep(commentblock = """// ***k1 substep:***// 1. We will store k1_or_y_nplus_a21_k1_or_y_nplus1_running_total_gfs now as// ... the update for the next rhs evaluation y_n + a21*k1*dt// Post-RHS evaluation:// 1. Apply post-RHS to y_n + a21*k1*dt""",RHS_str = RHS_string,RHS_input_str = "y_n_gfs", RHS_output_str = "k1_or_y_nplus_a21_k1_or_y_nplus1_running_total_gfs",RK_lhss_list = ["k1_or_y_nplus_a21_k1_or_y_nplus1_running_total_gfs"],RK_rhss_list = ["("+sp.ccode(Butcher[1][1]).replace("L","")+")*k1_or_y_nplus_a21_k1_or_y_nplus1_running_total_gfs[i]*dt + y_n_gfs[i]"],post_RHS_list = [post_RHS_string], post_RHS_output_list = ["k1_or_y_nplus_a21_k1_or_y_nplus1_running_total_gfs"])# k_2RK_str += single_RK_substep(commentblock="""// ***k2 substep:***// 1. Reassign k1_or_y_nplus_a21_k1_or_y_nplus1_running_total_gfs to be the running total y_{n+1}; a32*k2*dt to the running total// 2. Store k2_or_y_nplus_a32_k2_gfs now as y_n + a32*k2*dt// Post-RHS evaluation:// 1. Apply post-RHS to both y_n + a32*k2 (stored in k2_or_y_nplus_a32_k2_gfs)// ... and the y_{n+1} running total, as they have not been applied yet to k2-related gridfunctions""",RHS_str=RHS_string,RHS_input_str="k1_or_y_nplus_a21_k1_or_y_nplus1_running_total_gfs", RHS_output_str="k2_or_y_nplus_a32_k2_gfs",RK_lhss_list=["k1_or_y_nplus_a21_k1_or_y_nplus1_running_total_gfs","k2_or_y_nplus_a32_k2_gfs"],RK_rhss_list=["("+sp.ccode(Butcher[3][1]).replace("L","")+")*(k1_or_y_nplus_a21_k1_or_y_nplus1_running_total_gfs[i] - y_n_gfs[i])/("+sp.ccode(Butcher[1][1]).replace("L","")+") + y_n_gfs[i] + ("+sp.ccode(Butcher[3][2]).replace("L","")+")*k2_or_y_nplus_a32_k2_gfs[i]*dt","("+sp.ccode(Butcher[2][2]).replace("L","")+")*k2_or_y_nplus_a32_k2_gfs[i]*dt + y_n_gfs[i]"],post_RHS_list=[post_RHS_string,post_RHS_string],post_RHS_output_list=["k2_or_y_nplus_a32_k2_gfs","k1_or_y_nplus_a21_k1_or_y_nplus1_running_total_gfs"])# k_3RK_str += single_RK_substep(commentblock="""// ***k3 substep:***// 1. Add k3 to the running total and save to y_n// Post-RHS evaluation:// 1. Apply post-RHS to y_n""",RHS_str=RHS_string,RHS_input_str="k2_or_y_nplus_a32_k2_gfs", RHS_output_str="y_n_gfs",RK_lhss_list=["y_n_gfs","k2_or_y_nplus_a32_k2_gfs"],RK_rhss_list=["k1_or_y_nplus_a21_k1_or_y_nplus1_running_total_gfs[i] + ("+sp.ccode(Butcher[3][3]).replace("L","")+")*y_n_gfs[i]*dt"],post_RHS_list=[post_RHS_string],post_RHS_output_list=["y_n_gfs"])else:y_n = "y_n_gfs"if diagonal(RK_method) == False:for s in range(num_steps):next_y_input = "next_y_input_gfs"# If we're on the first step (s=0), we use y_n gridfunction as input.# Otherwise next_y_input is input. Output is just the reverse.if s==0: # If on first step:RHS_input = y_nelse: # If on second step or later:RHS_input = next_y_inputRHS_output = "k" + str(s + 1) + "_gfs"if s == num_steps-1: # If on final step:RK_lhs = y_nRK_rhs = y_n + "[i] + dt*("else: # If on anything but the final step:RK_lhs = next_y_inputRK_rhs = y_n + "[i] + dt*("for m in range(s+1):if Butcher[s+1][m+1] != 0:if Butcher[s+1][m+1] != 1:RK_rhs += " + k"+str(m+1)+"_gfs[i]*("+sp.ccode(Butcher[s+1][m+1]).replace("L","")+")"else:RK_rhs += " + k"+str(m+1)+"_gfs[i]"RK_rhs += " )"post_RHS = post_RHS_stringif s == num_steps-1: # If on final step:post_RHS_output = y_nelse: # If on anything but the final step:post_RHS_output = next_y_inputRK_str += single_RK_substep(commentblock="// ***k" + str(s + 1) + " substep:***",RHS_str=RHS_string,RHS_input_str=RHS_input, RHS_output_str=RHS_output,RK_lhss_list=[RK_lhs], RK_rhss_list=[RK_rhs],post_RHS_list=[post_RHS],post_RHS_output_list=[post_RHS_output])else:y_nplus1_running_total = "y_nplus1_running_total_gfs"if RK_method == 'Euler': # Euler's method doesn't require any k_i, and gets its own unique algorithmRK_str += single_RK_substep(commentblock="// ***Euler timestepping only requires one RHS evaluation***",RHS_str=RHS_string,RHS_input_str=y_n, RHS_output_str=y_nplus1_running_total,RK_lhss_list=[y_n], RK_rhss_list=[y_n+"[i] + "+y_nplus1_running_total+"[i]*dt"],post_RHS_list=[post_RHS_string],post_RHS_output_list=[y_n])else:for s in range(num_steps):# If we're on the first step (s=0), we use y_n gridfunction as input.# and k_odd as output.if s == 0:RHS_input = "y_n_gfs"RHS_output = "k_odd_gfs"# For the remaining steps the inputs and ouputs alternate between k_odd and k_evenelif s%2 == 0:RHS_input = "k_even_gfs"RHS_output = "k_odd_gfs"else:RHS_input = "k_odd_gfs"RHS_output = "k_even_gfs"RK_lhs_list = []RK_rhs_list = []if s != num_steps-1: # For anything besides the final stepif s == 0: # The first RK stepRK_lhs_list.append(y_nplus1_running_total)RK_rhs_list.append(RHS_output+"[i]*dt*("+sp.ccode(Butcher[num_steps][s+1]).replace("L","")+")")RK_lhs_list.append(RHS_output)RK_rhs_list.append(y_n+"[i] + "+RHS_output+"[i]*dt*("+sp.ccode(Butcher[s+1][s+1]).replace("L","")+")")else:if Butcher[num_steps][s+1] !=0:RK_lhs_list.append(y_nplus1_running_total)if Butcher[num_steps][s+1] !=1:RK_rhs_list.append(y_nplus1_running_total+"[i] + "+RHS_output+"[i]*dt*("+sp.ccode(Butcher[num_steps][s+1]).replace("L","")+")")else:RK_rhs_list.append(y_nplus1_running_total+"[i] + "+RHS_output+"[i]*dt")if Butcher[s+1][s+1] !=0:RK_lhs_list.append(RHS_output)if Butcher[s+1][s+1] !=1:RK_rhs_list.append(y_n+"[i] + "+RHS_output+"[i]*dt*("+sp.ccode(Butcher[s+1][s+1]).replace("L","")+")")else:RK_rhs_list.append(y_n+"[i] + "+RHS_output+"[i]*dt")post_RHS_output = RHS_outputif s == num_steps-1: # If on the final stepif Butcher[num_steps][s+1] != 0:RK_lhs_list.append(y_n)if Butcher[num_steps][s+1] != 1:RK_rhs_list.append(y_n+"[i] + "+y_nplus1_running_total+"[i] + "+RHS_output+"[i]*dt*("+sp.ccode(Butcher[num_steps][s+1]).replace("L","")+")")else:RK_rhs_list.append(y_n+"[i] + "+y_nplus1_running_total+"[i] + "+RHS_output+"[i]*dt)")post_RHS_output = y_nRK_str += single_RK_substep(commentblock="// ***k" + str(s + 1) + " substep:***",RHS_str=RHS_string,RHS_input_str=RHS_input, RHS_output_str=RHS_output,RK_lhss_list=RK_lhs_list, RK_rhss_list=RK_rhs_list,post_RHS_list=[post_RHS_string],post_RHS_output_list=[post_RHS_output])with open(os.path.join(outdir,"RK_MoL.h"), "w") as file:file.write(RK_str)####### Step 3c: Freeing Allocated Memoryfree_allocated_memory(outdir,RK_method,malloced_gridfunctions)
# As documented in the NRPy+ tutorial module# Tutorial-RK_Butcher_Table_Dictionary.ipynb ,# this module will construct a Python dictionary# of Butcher tables for a large number of explicit# RK methods.# Authors: Brandon Clark# Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step 1: Initialize needed Python/NRPy+ modulesimport sympy as spimport NRPy_param_funcs as par# Step 2a: Generating a Dictionary of Butcher Tables for Explicit Runge Kutta Techniques# Initialize the dictionary Butcher_dictButcher_dict = {}# Step 2.a.i: Euler's MethodButcher_dict['Euler'] = ([[sp.sympify(0)],["", sp.sympify(1)]], 1)# Step 2.a.ii: RK2 Heun's MethodButcher_dict['RK2 Heun'] = ([[sp.sympify(0)],[sp.sympify(1), sp.sympify(1)],["", sp.Rational(1,2), sp.Rational(1,2)]], 2)# Step 2.a.iii: RK2 Midpoint (MP) MethodButcher_dict['RK2 MP'] = ([[sp.sympify(0)],[sp.Rational(1,2), sp.Rational(1,2)],["", sp.sympify(0), sp.sympify(1)]], 2)# Step 2.a.iv: RK2 Ralston's MethodButcher_dict['RK2 Ralston'] = ([[sp.sympify(0)],[sp.Rational(2,3), sp.Rational(2,3)],["", sp.Rational(1,4), sp.Rational(3,4)]], 2)# Step 2.a.v: Kutta's Third-order MethodButcher_dict['RK3'] = ([[sp.sympify(0)],[sp.Rational(1,2), sp.Rational(1,2)],[sp.sympify(1), sp.sympify(-1), sp.sympify(2)],["", sp.Rational(1,6), sp.Rational(2,3), sp.Rational(1,6)]], 3)# Step 2.a.vi: RK3 Heun's MethodButcher_dict['RK3 Heun'] = ([[sp.sympify(0)],[sp.Rational(1,3), sp.Rational(1,3)],[sp.Rational(2,3), sp.sympify(0), sp.Rational(2,3)],["", sp.Rational(1,4), sp.sympify(0), sp.Rational(3,4)]], 3)# Step 2.a.vii: RK3 Ralton's MethodButcher_dict['RK3 Ralston'] = ([[0],[sp.Rational(1,2), sp.Rational(1,2)],[sp.Rational(3,4), sp.sympify(0), sp.Rational(3,4)],["", sp.Rational(2,9), sp.Rational(1,3), sp.Rational(4,9)]], 3)# Step 2.a.viii: Strong Stability Preserving Runge-Kutta (SSPRK3) MethodButcher_dict['SSPRK3'] = ([[0],[sp.sympify(1), sp.sympify(1)],[sp.Rational(1,2), sp.Rational(1,4), sp.Rational(1,4)],["", sp.Rational(1,6), sp.Rational(1,6), sp.Rational(2,3)]], 3)# Step 2.a.ix: Classic RK4 MethodButcher_dict['RK4'] = ([[sp.sympify(0)],[sp.Rational(1,2), sp.Rational(1,2)],[sp.Rational(1,2), sp.sympify(0), sp.Rational(1,2)],[sp.sympify(1), sp.sympify(0), sp.sympify(0), sp.sympify(1)],["", sp.Rational(1,6), sp.Rational(1,3), sp.Rational(1,3), sp.Rational(1,6)]], 4)# Step 2.a.x: RK5 Dormand-Prince MethodButcher_dict['DP5'] = ([[0],[sp.Rational(1,5), sp.Rational(1,5)],[sp.Rational(3,10),sp.Rational(3,40), sp.Rational(9,40)],[sp.Rational(4,5), sp.Rational(44,45), sp.Rational(-56,15), sp.Rational(32,9)],[sp.Rational(8,9), sp.Rational(19372,6561), sp.Rational(-25360,2187), sp.Rational(64448,6561), sp.Rational(-212,729)],[sp.sympify(1), sp.Rational(9017,3168), sp.Rational(-355,33), sp.Rational(46732,5247), sp.Rational(49,176), sp.Rational(-5103,18656)],[sp.sympify(1), sp.Rational(35,384), sp.sympify(0), sp.Rational(500,1113), sp.Rational(125,192), sp.Rational(-2187,6784), sp.Rational(11,84)],["", sp.Rational(35,384), sp.sympify(0), sp.Rational(500,1113), sp.Rational(125,192), sp.Rational(-2187,6784), sp.Rational(11,84), sp.sympify(0)]], 5)# Step 2.a.xi: RK5 Dormand-Prince Method AlternativeButcher_dict['DP5alt'] = ([[0],[sp.Rational(1,10), sp.Rational(1,10)],[sp.Rational(2,9), sp.Rational(-2, 81), sp.Rational(20, 81)],[sp.Rational(3,7), sp.Rational(615, 1372), sp.Rational(-270, 343), sp.Rational(1053, 1372)],[sp.Rational(3,5), sp.Rational(3243, 5500), sp.Rational(-54, 55), sp.Rational(50949, 71500), sp.Rational(4998, 17875)],[sp.Rational(4, 5), sp.Rational(-26492, 37125), sp.Rational(72, 55), sp.Rational(2808, 23375), sp.Rational(-24206, 37125), sp.Rational(338, 459)],[sp.sympify(1), sp.Rational(5561, 2376), sp.Rational(-35, 11), sp.Rational(-24117, 31603), sp.Rational(899983, 200772), sp.Rational(-5225, 1836), sp.Rational(3925, 4056)],["", sp.Rational(821, 10800), sp.sympify(0), sp.Rational(19683, 71825), sp.Rational(175273, 912600), sp.Rational(395, 3672), sp.Rational(785, 2704), sp.Rational(3, 50)]], 5)# Step 2.a.xii: RK5 Dormand-Prince Method AlternativeButcher_dict['DP5alt'] = ([[0],[sp.Rational(1,10), sp.Rational(1,10)],[sp.Rational(2,9), sp.Rational(-2, 81), sp.Rational(20, 81)],[sp.Rational(3,7), sp.Rational(615, 1372), sp.Rational(-270, 343), sp.Rational(1053, 1372)],[sp.Rational(3,5), sp.Rational(3243, 5500), sp.Rational(-54, 55), sp.Rational(50949, 71500), sp.Rational(4998, 17875)],[sp.Rational(4, 5), sp.Rational(-26492, 37125), sp.Rational(72, 55), sp.Rational(2808, 23375), sp.Rational(-24206, 37125), sp.Rational(338, 459)],[sp.sympify(1), sp.Rational(5561, 2376), sp.Rational(-35, 11), sp.Rational(-24117, 31603), sp.Rational(899983, 200772), sp.Rational(-5225, 1836), sp.Rational(3925, 4056)],["", sp.Rational(821, 10800), sp.sympify(0), sp.Rational(19683, 71825), sp.Rational(175273, 912600), sp.Rational(395, 3672), sp.Rational(785, 2704), sp.Rational(3, 50)]], 5)# Step 2.a.xiii: RK5 Cash-Karp MethodButcher_dict['CK5'] = ([[0],[sp.Rational(1,5), sp.Rational(1,5)],[sp.Rational(3,10),sp.Rational(3,40), sp.Rational(9,40)],[sp.Rational(3,5), sp.Rational(3,10), sp.Rational(-9,10), sp.Rational(6,5)],[sp.sympify(1), sp.Rational(-11,54), sp.Rational(5,2), sp.Rational(-70,27), sp.Rational(35,27)],[sp.Rational(7,8), sp.Rational(1631,55296), sp.Rational(175,512), sp.Rational(575,13824), sp.Rational(44275,110592), sp.Rational(253,4096)],["",sp.Rational(37,378), sp.sympify(0), sp.Rational(250,621), sp.Rational(125,594), sp.sympify(0), sp.Rational(512,1771)]], 5)# Step 2.a.xiv: RK6 Dormand-Prince MethodButcher_dict['DP6'] = ([[0],[sp.Rational(1,10), sp.Rational(1,10)],[sp.Rational(2,9), sp.Rational(-2, 81), sp.Rational(20, 81)],[sp.Rational(3,7), sp.Rational(615, 1372), sp.Rational(-270, 343), sp.Rational(1053, 1372)],[sp.Rational(3,5), sp.Rational(3243, 5500), sp.Rational(-54, 55), sp.Rational(50949, 71500), sp.Rational(4998, 17875)],[sp.Rational(4, 5), sp.Rational(-26492, 37125), sp.Rational(72, 55), sp.Rational(2808, 23375), sp.Rational(-24206, 37125), sp.Rational(338, 459)],[sp.sympify(1), sp.Rational(5561, 2376), sp.Rational(-35, 11), sp.Rational(-24117, 31603), sp.Rational(899983, 200772), sp.Rational(-5225, 1836), sp.Rational(3925, 4056)],[sp.sympify(1), sp.Rational(465467, 266112), sp.Rational(-2945, 1232), sp.Rational(-5610201, 14158144), sp.Rational(10513573, 3212352), sp.Rational(-424325, 205632), sp.Rational(376225, 454272), sp.sympify(0)],["", sp.Rational(61, 864), sp.sympify(0), sp.Rational(98415, 321776), sp.Rational(16807, 146016), sp.Rational(1375, 7344), sp.Rational(1375, 5408), sp.Rational(-37, 1120), sp.Rational(1,10)]], 6)# Step 2.a.xv: RK6 Luther's Methodq = sp.sqrt(21)Butcher_dict['L6'] = ([[0],[sp.sympify(1), sp.sympify(1)],[sp.Rational(1,2), sp.Rational(3,8), sp.Rational(1,8)],[sp.Rational(2,3), sp.Rational(8,27), sp.Rational(2,27), sp.Rational(8,27)],[(7 - q)/14, (-21 + 9*q)/392, (-56 + 8*q)/392, (336 -48*q)/392, (-63 + 3*q)/392],[(7 + q)/14, (-1155 - 255*q)/1960, (-280 - 40*q)/1960, (-320*q)/1960, (63 + 363*q)/1960, (2352 + 392*q)/1960],[sp.sympify(1), ( 330 + 105*q)/180, sp.Rational(2,3), (-200 + 280*q)/180, (126 - 189*q)/180, (-686 - 126*q)/180, (490 - 70*q)/180],["", sp.Rational(1, 20), sp.sympify(0), sp.Rational(16, 45), sp.sympify(0), sp.Rational(49, 180), sp.Rational(49, 180), sp.Rational(1, 20)]], 6)# Step 2.a.xvi: RK8 Dormand-Prince MethodButcher_dict['DP8']=([[0],[sp.Rational(1, 18), sp.Rational(1, 18)],[sp.Rational(1, 12), sp.Rational(1, 48), sp.Rational(1, 16)],[sp.Rational(1, 8), sp.Rational(1, 32), sp.sympify(0), sp.Rational(3, 32)],[sp.Rational(5, 16), sp.Rational(5, 16), sp.sympify(0), sp.Rational(-75, 64), sp.Rational(75, 64)],[sp.Rational(3, 8), sp.Rational(3, 80), sp.sympify(0), sp.sympify(0), sp.Rational(3, 16), sp.Rational(3, 20)],[sp.Rational(59, 400), sp.Rational(29443841, 614563906), sp.sympify(0), sp.sympify(0), sp.Rational(77736538, 692538347), sp.Rational(-28693883, 1125000000), sp.Rational(23124283, 1800000000)],[sp.Rational(93, 200), sp.Rational(16016141, 946692911), sp.sympify(0), sp.sympify(0), sp.Rational(61564180, 158732637), sp.Rational(22789713, 633445777), sp.Rational(545815736, 2771057229), sp.Rational(-180193667, 1043307555)],[sp.Rational(5490023248, 9719169821), sp.Rational(39632708, 573591083), sp.sympify(0), sp.sympify(0), sp.Rational(-433636366, 683701615), sp.Rational(-421739975, 2616292301), sp.Rational(100302831, 723423059), sp.Rational(790204164, 839813087), sp.Rational(800635310, 3783071287)],[sp.Rational(13, 20), sp.Rational(246121993, 1340847787), sp.sympify(0), sp.sympify(0), sp.Rational(-37695042795, 15268766246), sp.Rational(-309121744, 1061227803), sp.Rational(-12992083, 490766935), sp.Rational(6005943493, 2108947869), sp.Rational(393006217, 1396673457), sp.Rational(123872331, 1001029789)],[sp.Rational(1201146811, 1299019798), sp.Rational(-1028468189, 846180014), sp.sympify(0), sp.sympify(0), sp.Rational(8478235783, 508512852), sp.Rational(1311729495, 1432422823), sp.Rational(-10304129995, 1701304382), sp.Rational(-48777925059, 3047939560), sp.Rational(15336726248, 1032824649), sp.Rational(-45442868181, 3398467696), sp.Rational(3065993473, 597172653)],[sp.sympify(1), sp.Rational(185892177, 718116043), sp.sympify(0), sp.sympify(0), sp.Rational(-3185094517, 667107341), sp.Rational(-477755414, 1098053517), sp.Rational(-703635378, 230739211), sp.Rational(5731566787, 1027545527), sp.Rational(5232866602, 850066563), sp.Rational(-4093664535, 808688257), sp.Rational(3962137247, 1805957418), sp.Rational(65686358, 487910083)],[sp.sympify(1), sp.Rational(403863854, 491063109), sp.sympify(0), sp.sympify(0), sp.Rational(-5068492393, 434740067), sp.Rational(-411421997, 543043805), sp.Rational(652783627, 914296604), sp.Rational(11173962825, 925320556), sp.Rational(-13158990841, 6184727034), sp.Rational(3936647629, 1978049680), sp.Rational(-160528059, 685178525), sp.Rational(248638103, 1413531060), sp.sympify(0)],["", sp.Rational(14005451, 335480064), sp.sympify(0), sp.sympify(0), sp.sympify(0), sp.sympify(0), sp.Rational(-59238493, 1068277825), sp.Rational(181606767, 758867731), sp.Rational(561292985, 797845732), sp.Rational(-1041891430, 1371343529), sp.Rational(760417239, 1151165299), sp.Rational(118820643, 751138087), sp.Rational(-528747749, 2220607170), sp.Rational(1, 4)]], 8)
# As documented in the NRPy+ tutorial module# Tutorial-RK_Butcher_Table_Validation.ipynb ,# this module will validate the Python dictionary# of Butcher tables.# Authors: Brandon Clark# Zachariah B. Etienne# zachetie **at** gmail **dot* com# Step 1: Initialize needed Python/NRPy+ modulesimport sympy as spimport NRPy_param_funcs as parimport numpy as npfrom MoLtimestepping.RK_Butcher_Table_Dictionary import Butcher_dictimport osimport sysfrom IPython.display import Image, display# Step 2a: Defining the right-hand side of the ODErhs_dict = {}def fypt(y,t):return y+trhs_dict['ypt'] = fyptdef fy(y,t):return yrhs_dict['y'] = fydef feypt(y,t):return sp.exp(1.0*(y+t))rhs_dict['eypt'] = feyptdef ftpoly6(y,t):return 2*t**6-389*t**5+15*t**4-22*t**3+81*t**2-t+42rhs_dict['tpoly6'] = ftpoly6def ftpoly5(y,t):return t**5 + t**4 + t**3 + t**2 + t + 1rhs_dict["tpoly5"] = ftpoly5def fty2pt(y,t):return t*y**2+trhs_dict["ty2pt"] = fty2ptdef fymcost(y,t):return y-sp.cos(t)rhs_dict["ymcost"] = fymcostdef fypsint(y,t):return y+sp.sin(t)rhs_dict['ypsint'] = fypsint# Step 2b: Defining a Validation Functiondef Validate(Butcher_dict, Butcher_key, yn, tn, rhs_key):# Set needed symbolic expressionst, dt = sp.symbols('t dt')# 1. First we solve the ODE exactlyy = sp.Function('y')sol = sp.dsolve(sp.Eq(y(t).diff(t), rhs_dict[rhs_key](y(t), t)), y(t)).rhsconstants = sp.solve([sol.subs(t,tn)-yn])exact = sol.subs(constants)# 2. Now we solve the ODE numerically using specified Butcher table# Access the requested Butcher tableButcher = Butcher_dict[Butcher_key][0]# Determine number of predictor-corrector stepsL = len(Butcher)-1# Set a temporary array for update valuesk = np.zeros(L, dtype=object)# Initialize intermediate variableyhat = 0# Initialize the updated solutionynp1 = 0for i in range(L):#Initialize and approximate update for solutionyhat = ynfor j in range(i):# Update yhat for solution using a_ij Butcher table coefficientsyhat += Butcher[i][j+1]*k[j]if Butcher_key == "DP8" or Butcher_key == "L6":yhat = 1.0*sp.N(yhat,20) # Otherwise the adding of fractions kills performance.# Determine the next corrector variable k_i using c_i Butcher table coefficientsk[i] = dt*rhs_dict[rhs_key](yhat, tn + Butcher[i][0]*dt)# Update the solution at the next iteration ynp1 using Butcher table coefficientsynp1 += Butcher[L][i+1]*k[i]# Finish determining the solution for the next iterationynp1 += yn# Determine the order of the RK methodorder = Butcher_dict[Butcher_key][1]+2# Produces Taylor series of exact solution at t=tn about t = 0 with the specified orderexact_series = sp.series(exact.subs(t, dt),dt, 0, order)num_series = sp.series(ynp1, dt, 0, order)diff = exact_series-num_seriesreturn diff# # Step 2d: Validating Convergence with ScalarWave PDE in Cartesian Coordinates# def fd_order(RK_order):# if (RK_order+1)%2==0: # If RK_order is odd, then set FD_order (must be even) to RK_order+1# return RK_order+1# else:# return RK_order+2 # If RK_order is even, then set FD_order (must be even) to RK_order+2# # CFL_FACTOR = 0.5# for key,value in Butcher_dict.items():# for CFL_FACTOR in [0.5]:# with open("ScalarWave/params.txt", "w") as file:# # DON'T ADD SPACES TO THE FOLLOWING!# file.write(# """RK_method="""+str(key)+"""# FD_order="""+str(fd_order(value[1]))+"""# REAL=double# CFL_FACTOR="""+str(CFL_FACTOR))# outfilename = "Out"+str(key)+"_CFL_"+str(CFL_FACTOR)+".png"# os.system("rm -f "+outfilename)# os.system("jupyter nbconvert --to notebook --inplace --execute --ExecutePreprocessor.timeout=-1 Tutorial-Start_to_Finish-ScalarWave.ipynb")# if os.path.isfile(outfilename):# print("Successfully generated figure "+outfilename)# #display(Image(filename=outfilename,width=600))# else:# print("ERROR: Failed to generate figure "+outfilename)# sys.exit(1)
# As documented in the NRPy+ tutorial module# Tutorial-Coutput__Parameter_Interface.ipynb# this core NRPy+ module is used for# initializing, storing, and recalling# parameters.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* comimport sympy as sp # Import SymPyimport os, sys # Standard Python: OS-independent system functionsfrom collections import namedtuple # Standard Python: Enable namedtuple data typeglb_params_list = [] # = where we store NRPy+ parameters and default values of parameters. A list of named tuplesglb_paramsvals_list = [] # = where we store NRPy+ parameter values.glb_param = namedtuple('glb_param', 'type module parname defaultval')glb_Cparams_list = [] # = where we store C runtime parameters and default values of parameters. A list of named tuplesglb_Cparam = namedtuple('glb_Cparam','type module parname defaultval')veryverbose = Falsedef initialize_param(input):if get_params_idx(input) == -1:glb_params_list.append(input)glb_paramsvals_list.append(input.defaultval)else:if veryverbose == True:print("initialize_param() minor warning: Did nothing; already initialized parameter "+input.module+"::"+input.parname)def initialize_Cparam(input):if get_params_idx(input,Cparam=True) == -1:glb_Cparams_list.append(input)else:if veryverbose == True:print("initialize_Cparam() minor warning: Did nothing; already initialized parameter "+input.module+"::"+input.parname)# Given the named tuple `input` and list of named tuples `params`,# defined according to namedtuple('param', 'type module name defaultval'),# where in the case of `input`, defaultval need not be set,# return the list index of `params` that matches `input`.# On error returns -1def get_params_idx(input,Cparam=False):# inspired by: https://stackoverflow.com/questions/2917372/how-to-search-a-list-of-tuples-in-python:if Cparam==False:list = [i for i, v in enumerate(glb_params_list)if (input.type=="ignoretype" or input.type==v[0]) and input.module == v[1] and input.parname == v[2]]else:list = [i for i, v in enumerate(glb_Cparams_list) if input.parname == v[2]]if list == []:return -1 # No match found => error out!else:if len(list) > 1:print("Error: Found multiple parameters matching "+str(input))sys.exit(1)return list.pop() # pop() returns the indexdef get_params_value(input):idx = get_params_idx(input)if idx < 0:print("Error: could not find a parameter matching:",input)print("Full list of modules:\n",glb_params_list)sys.exit(1)else:return glb_paramsvals_list[idx]#def idx_from_str(varname,modname=""):if "::" in varname:splitstring = re.split('::', varname)modname=splitstring[0]varname=splitstring[1]# inspired by: https://stackoverflow.com/questions/2917372/how-to-search-a-list-of-tuples-in-python:if modname == "":list = [i for i, v in enumerate(glb_params_list) if v[2] == varname]else:list = [i for i, v in enumerate(glb_params_list) if (v[1] == modname and v[2] == varname)]if list == []:print("Error: Could not find a parameter matching \""+varname+"\" in ",glb_params_list)sys.exit(1)if len(list) > 1:print("Error: Found more than one parameter named \""+varname+"\". Use get_params_value() instead.")sys.exit(1)return list.pop()def parval_from_str(string):return glb_paramsvals_list[idx_from_str(string)]def set_parval_from_str(string,value):glb_paramsvals_list[idx_from_str(string)] = value# parse_param_string__set__params_and_paramsvars:# Summary: This function parses a string like this# module::variablename=value# into its component parts: module,variablename,value# then hunts for module,variablename in the# params list. When it finds the matching index in the# list "idx", it sets paramsvals[idx] = value.# Usage comment: This function parses both parameter file# inputs as well as parameter inputs from the command# line. You should set filename = "" if reading from the# command line. This ensures the error messages are# appropriate for the context.import redef set_paramsvals_value(line,filename="", FindMainModuleMode=False):MainModuleFound = Trueif FindMainModuleMode == True:MainModuleFound = False# First remove carriage return and leading whitespace:stripped_line_of_text = line.strip()# Only process lines that do NOT start with a hashif not stripped_line_of_text.startswith("#"):# Valid lines take the form:# module::variable = value # Comment here# Thus, using the delimiters "::", "=", and "#",# with the regex split command, the first three# items in single_param_def will be [module, variablename, value]single_param_def = re.split('::|=|#', stripped_line_of_text)# First verify that single_param_def has at least 3 parts:if len(single_param_def) < 3:if filename != "":print("Error: the line " + line + " in parameter file " + filename + " is not in the form")print("\"module::variable = value\"")else:print("Error: the command-line argument " + stripped_line_of_text + " is not in the form")print("\"module::variable=value\" <-- NOTICE NO SPACES ALLOWED!")sys.exit(1)# Next remove all leading/trailing whitespace from single_param_deffor i in range(len(single_param_def)):single_param_def[i] = single_param_def[i].strip()if FindMainModuleMode == False:# Next find the parameter in the params list and set# the corresponding element in paramsvals to the value.idx = get_params_idx(glb_param("ignoretype", single_param_def[0], single_param_def[1], "ignoredefval"))# If parameter is not found, print useful error message, then exit:if idx == -1:if filename != "":print("Error: when reading line \"" + line + "\" in parameter file \"" + filename + "\":")else:print("Error: when parsing command-line argument \"" + stripped_line_of_text + "\":")print("\t\tcould not find parameter \""+ single_param_def[1] + "\" in \""+single_param_def[0]+"\" module.")sys.exit(1)# If parameter is found at index idx, set paramsval[idx] to the value specified in the file.partype = glb_params_list[idx].typeif partype == "bool":if single_param_def[2] == "True":glb_paramsvals_list[idx] = Trueelif single_param_def[2] == "False":glb_paramsvals_list[idx] = Falseelse:print("Error: \"bool\" type can only take values of \"True\" or \"False\"")sys.exit(1)elif partype == "int":glb_paramsvals_list[idx] = int(single_param_def[2])elif partype == "REAL" or \partype == "char" or \partype == "char *":glb_paramsvals_list[idx] = single_param_def[2]else:print("Error: type \""+partype+"\" on variable \""+ glb_params_list[idx].parname +"\" is unsupported.")print("Supported types include: bool, int, REAL, REALARRAY, char, and char *")sys.exit(1)elif FindMainModuleMode == True and MainModuleFound == False:if single_param_def[0] == "NRPy" and single_param_def[1] == "MainModule":idx = get_params_idx(glb_param("ignoretype", single_param_def[0], single_param_def[1], "ignoredefval"))if idx == -1:print("Critical error: NRPy::MainModule is uninitialized!")sys.exit(1)glb_paramsvals_list[idx] = single_param_def[2]def Cparameters(type,module,names,defaultvals,assumption="Real"):output = []# if names is not a list, make it a list, to# simplify the remainder of this routine.if not isinstance(names,list):names = [names]defaultval_list = []if not isinstance(defaultvals,list):for i in range(len(names)):defaultval_list.append(defaultvals)else:# If defaultvals *is* a list, then make sure it has the same number of elements as "names".if len(defaultvals) != len(names):print("Error in Cparameters(): Was provided a list of variables:\n"+str(names)+"\n")print("and a list of their default values:\n"+str(defaultvals)+"\n")print("but the lists have different lengths ("+str(len(names))+" != "+str(len(defaultvals))+")\n")sys.exit(1)defaultval_list = defaultvalsfor i in range(len(names)):initialize_Cparam(glb_Cparam(type, module, names[i], defaultval_list[i]))if assumption == "Real":tmp = sp.Symbol(names[i], real=True) # Assumes all Cparameters are real.elif assumption == "RealPositive":tmp = sp.Symbol(names[i], real=True, positive=True) # Assumes all Cparameters are real and positive.else:print("Error: assumption "+str(assumption)+" not supported.")sys.exit(1)output.append(tmp)if len(names) == 1:return output[0]return outputdef generate_Cparameters_Ccodes(directory="./"):# Step 1: Check that Cparams types are supported.for i in range(len(glb_Cparams_list)):partype = glb_Cparams_list[i].typeif partype != "bool" and \partype != "#define" and \partype != "char" and \partype != "int" and \partype != "REAL":print("Error: parameter "+glb_Cparams_list[i].module+"::"+glb_Cparams_list[i].parname+" has unsupported type: \""+ glb_Cparams_list[i].type + "\"")sys.exit(1)# Step 2: Generate C code to declare C paramstruct;# output to "declare_Cparameters_struct.h"with open(os.path.join(directory,"declare_Cparameters_struct.h"), "w") as file:file.write("typedef struct __paramstruct__ {\n")for i in range(len(glb_Cparams_list)):if glb_Cparams_list[i].type != "#define":if glb_Cparams_list[i].type == "char":Ctype = "char *"else:Ctype = glb_Cparams_list[i].typefile.write(Ctype + " " + glb_Cparams_list[i].parname + ";\n")file.write("} paramstruct;\n")# Step 3: Generate C code to set all elements in# C paramstruct to default values; output to# "set_Cparameters_default.h"with open(os.path.join(directory,"set_Cparameters_default.h"), "w") as file:for i in range(len(glb_Cparams_list)):if glb_Cparams_list[i].type != "#define":Coutput = "params." + glb_Cparams_list[i].parnameif isinstance(glb_Cparams_list[i].defaultval, (bool,int,float)):Coutput += " = " + str(glb_Cparams_list[i].defaultval).lower() + ";\n"elif glb_Cparams_list[i].type == "char" and isinstance(glb_Cparams_list[i].defaultval, (str)):Coutput += " = \"" + str(glb_Cparams_list[i].defaultval).lower() + "\";\n"else:Coutput += " = " + str(glb_Cparams_list[i].defaultval) + ";\n"file.write(Coutput)# Step 4: Generate C code to set C parameter constants# (i.e., all ints != -12345678 and REALs != 1e300);# output to filename "set_Cparameters.h" if SIMD_enable==False# or "set_Cparameters-SIMD.h" if SIMD_enable==True# Step 4.a: Output non-SIMD version, set_Cparameters.hdef gen_set_Cparameters(pointerEnable=True):returnstring = ""for i in range(len(glb_Cparams_list)):if glb_Cparams_list[i].type == "char":Ctype = "char *"else:Ctype = glb_Cparams_list[i].typepointer = "->"if pointerEnable==False:pointer = "."if not ((Ctype == "REAL" and glb_Cparams_list[i].defaultval == 1e300) or Ctype == "#define"):Coutput = "const "+Ctype+" "+glb_Cparams_list[i].parname+" = "+"params"+pointer+glb_Cparams_list[i].parname + ";\n"returnstring += Coutputreturn returnstringwith open(os.path.join(directory,"set_Cparameters.h"), "w") as file:file.write(gen_set_Cparameters(pointerEnable=True))with open(os.path.join(directory,"set_Cparameters-nopointer.h"), "w") as file:file.write(gen_set_Cparameters(pointerEnable=False))# Step 4.b: Output SIMD version, set_Cparameters-SIMD.hwith open(os.path.join(directory,"set_Cparameters-SIMD.h"), "w") as file:for i in range(len(glb_Cparams_list)):if glb_Cparams_list[i].type == "char":Ctype = "char *"else:Ctype = glb_Cparams_list[i].typeparname = glb_Cparams_list[i].parnameif Ctype == "REAL" and glb_Cparams_list[i].defaultval != 1e300:Coutput = "const REAL NOSIMD" + parname + " = " + "params->" + glb_Cparams_list[i].parname + ";\n"Coutput += "const REAL_SIMD_ARRAY " + parname + " = ConstSIMD(NOSIMD" + parname + ");\n"file.write(Coutput)elif glb_Cparams_list[i].defaultval != 1e300 and Ctype !="#define":Coutput = "const "+Ctype+" "+parname + " = " + "params->" + glb_Cparams_list[i].parname + ";\n"file.write(Coutput)
from sympy import Integer,Symbol,symbols,simplify,Rational,sign,Function,srepr,sin,cos,exp,log,Abs,Add,Mul,Pow,preorder_traversal,N,Float,S,var,sympifyimport re, sys# For debugging purposes, Part 1:# Basic arithmetic operationsdef ConstSIMD_check(a):return Float(a,34)def AbsSIMD_check(a):return Abs(a)def nrpyAbsSIMD_check(a):return Abs(a)def AddSIMD_check(a,b):return a+bdef SubSIMD_check(a,b):return a-bdef MulSIMD_check(a,b):return a*bdef FusedMulAddSIMD_check(a,b,c):return a*b + cdef FusedMulSubSIMD_check(a,b,c):return a*b - cdef DivSIMD_check(a,b):return a/bdef signSIMD_check(a):return sign(a)# For debugging purposes, Part 2:# Transcendental operationsdef PowSIMD_check(a, b):return a**bdef SqrtSIMD_check(a):return a**(Rational(1,2))def CbrtSIMD_check(a):return a**(Rational(1,3))def ExpSIMD_check(a):return exp(a)def LogSIMD_check(a):return log(a)def SinSIMD_check(a):return sin(a)def CosSIMD_check(a):return cos(a)# Input: SymPy expression.# Return value: SymPy expression containing all needed SIMD compiler intrinsics# Complication: SIMD functions require numerical constants to be stored in SIMD arrays# Resolution: This function extends lists "SIMD_const_varnms" and "SIMD_const_values",# which store the name of each constant SIMD array (e.g., _Integer_1) and# the value of each variable (e.g., 1.0).def expr_convert_to_SIMD_intrins(expr, SIMD_const_varnms,SIMD_const_values,SIMD_const_suffix="",debug="False"):# Declare all variables, so we can eval them in the next (AddSIMD & MulSIMD) stepfor item in preorder_traversal(expr):for i in range(len(item.args)):if isinstance(item.args[i],Symbol):var(str(item.args[i]))expr_orig = exprAbsSIMD = Function("AbsSIMD")AddSIMD = Function("AddSIMD")SubSIMD = Function("SubSIMD")MulSIMD = Function("MulSIMD")FusedMulAddSIMD = Function("FusedMulAddSIMD")FusedMulSubSIMD = Function("FusedMulSubSIMD")DivSIMD = Function("DivSIMD")SignSIMD = Function("SignSIMD")PowSIMD = Function("PowSIMD")SqrtSIMD = Function("SqrtSIMD")CbrtSIMD = Function("CbrtSIMD")ExpSIMD = Function("ExpSIMD")LogSIMD = Function("LogSIMD")SinSIMD = Function("SinSIMD")CosSIMD = Function("CosSIMD")# Step 1: Replace transcendental, power, and division functions with SIMD equivalents# Note that due to how SymPy expresses rational numbers, the following does not# affect fractional expressions of integersfor item in preorder_traversal(expr):if item.func == Abs:expr = expr.xreplace({item: AbsSIMD(item.args[0])})elif item.func == exp:expr = expr.xreplace({item: ExpSIMD(item.args[0])})elif item.func == log:expr = expr.xreplace({item: LogSIMD(item.args[0])})elif item.func == sin:expr = expr.xreplace({item: SinSIMD(item.args[0])})elif item.func == cos:expr = expr.xreplace({item: CosSIMD(item.args[0])})elif item.func == sign:expr = expr.xreplace({item: SignSIMD(item.args[0])})# Fun little recursive function for constructing integer powers:def IntegerPowSIMD(a, n):if n == 2:return MulSIMD(a, a)elif n > 2:return MulSIMD(IntegerPowSIMD(a, n - 1), a)elif n <= -2:return DivSIMD(1, IntegerPowSIMD(a, -n))elif n == -1:return DivSIMD(1, a)for item in preorder_traversal(expr):if item.func == Pow:if item.args[1] == 0.5:expr = expr.xreplace({item: SqrtSIMD(item.args[0])})elif item.args[1] == -0.5:expr = expr.xreplace({item: DivSIMD(1,SqrtSIMD(item.args[0]))})elif item.args[1] == Rational(1,3):expr = expr.xreplace({item: CbrtSIMD(item.args[0])})elif item.args[1] == int(item.args[1]):expr = expr.xreplace({item: IntegerPowSIMD(item.args[0], item.args[1])})else:expr = expr.xreplace({item: PowSIMD(item.args[0], item.args[1])})# Step 2: Replace all rational numbers (expressed as Rational(a,b))# and integers with the new functions RationalTMP and# IntegerTMP, where Rational(a,b) -> RationalTMP(a,b)# and Integer(a) -> IntegerTMP(a)RationalTMP = Function("RationalTMP")IntegerTMP = Function("IntegerTMP")string = str(srepr(expr))string2 = re.sub(r'Integer\(([+\-0-9]+)\)',"(Function('IntegerTMP')('\\1'))", string)expr = eval(string2)string = str(srepr(expr))string2 = re.sub(r'Rational\(([-0-9]+), ([0-9]+)\)',"(Function('RationalTMP')(('\\1'),('\\2')))", string)expr = eval(string2)# Step 3: The pattern Mul(-1,Rational(a,b)) is often seen. Replace with Rational(-a,b).for item in preorder_traversal(expr):if item.func == Mul:idx_has_Negative1 = -10for i in range(len(item.args)):if item.args[i].func == IntegerTMP and item.args[i].args[0] == -1:idx_has_Negative1 = iif idx_has_Negative1 >= 0:for i in range(len(item.args)):if item.args[i].func==RationalTMP:tempitem_orig = Mul(IntegerTMP(-1),RationalTMP(item.args[i].args[0], item.args[i].args[1]))tempitem_new = RationalTMP(-item.args[i].args[0], item.args[i].args[1])expr = expr.subs(tempitem_orig, tempitem_new )break# Step 4: SIMD multiplication and addition compiler intrinsics read in# only two arguments at once, where SymPy's Mul() and Add()# operators can read an arbitrary number of arguments.# Here, we split e.g., Mul(a,b,c,d) into# MulSIMD(a,MulSIMD(b,MulSIMD(c,d))),# To accomplish this easily, we construct a string# 'MulSIMD(A,MulSIMD(B,...', where MulSIMD(a,b) is some user-# defined function that takes in only two arguments, and then# evaluate the string using the eval() function.# Implementation detail: If we did not perform Step 2 above, the eval# function would automatically evaluate all Rational expressions# as though they were input as integers: e.g., 1/2 evaluates to 0.# This is undesirable, so we instead define new, temporary# functions IntegerTMP and RationalTMP that are undisturbed by# the eval()for item in preorder_traversal(expr):if item.func == Mul:blahtmp = symbols('blahtmp')tempitem = blahtmpfor i in range(len(item.args)-1):tempitem = MulSIMD(item.args[i],tempitem)tempitem = tempitem.xreplace({blahtmp: item.args[len(item.args)-1]})expr = expr.xreplace({item: tempitem})for item in preorder_traversal(expr):if item.func == Add:blahtmp = symbols('blahtmp')tempitem = blahtmpfor i in range(len(item.args)-1):tempitem = AddSIMD(item.args[i],tempitem)tempitem = tempitem.xreplace({blahtmp: item.args[len(item.args)-1]})expr = expr.xreplace({item: tempitem})# Step 5: Simplification patterns:# Step 5a: Replace the pattern Mul(Div(1,b),a) or Mul(a,Div(1,b)) with Div(a,b):for item in preorder_traversal(expr):if item.func == MulSIMD:if item.func == MulSIMD and (item.args[0].func == DivSIMD and item.args[0].args[0].func == IntegerTMP and item.args[0].args[0].args[0] == 1):expr = expr.xreplace({item: DivSIMD(item.args[1],item.args[0].args[1])})if item.func == MulSIMD and (item.args[1].func == DivSIMD and item.args[1].args[0].func == IntegerTMP and item.args[1].args[0].args[0] == 1):expr = expr.xreplace({item: DivSIMD(item.args[0],item.args[1].args[1])})# Step 5: Subtraction intrinsics. SymPy replaces all a-b with a + (-b) = Add(a,Mul(-1,b))# Here, we replace# a) AddSIMD(a,MulSIMD(-1,b)),# b) AddSIMD(a,MulSIMD(b,-1)),# c) AddSIMD(MulSIMD(-1,b),a), and# d) AddSIMD(MulSIMD(b,-1),a)# with SubSIMD(a,b)for item in preorder_traversal(expr):tempitem = item# First match patterns a) and b): AddSIMD(a,MULSIMD(.,.)):if item.func == AddSIMD and item.args[1].func == MulSIMD:# Pattern a) AddSIMD(a,MulSIMD(-1,b)) --> SubSIMD(a,b):if item.args[1].args[0].func == IntegerTMP and item.args[1].args[0].args[0] == -1:tempitem = SubSIMD(item.args[0],item.args[1].args[1])# Pattern b) AddSIMD(a,MulSIMD(b,-1)) --> SubSIMD(a,b):elif item.args[1].args[1].func == IntegerTMP and item.args[1].args[1].args[0] == -1:tempitem = SubSIMD(item.args[0],item.args[1].args[0])# Next match patterns c) and d): AddSIMD(MulSIMD(.,.),a):elif item.func == AddSIMD and item.args[0].func == MulSIMD:# Pattern c) AddSIMD(MulSIMD(-1,b),a) --> SubSIMD(a,b):if item.args[0].args[0].func == IntegerTMP and item.args[0].args[0].args[0] == -1:tempitem = SubSIMD(item.args[1],item.args[0].args[1])# Pattern d) AddSIMD(MulSIMD(b,-1,a)) --> SubSIMD(a,b):elif item.args[0].args[1].func == IntegerTMP and item.args[0].args[1].args[0] == -1:tempitem = SubSIMD(item.args[1],item.args[0].args[0])expr = expr.subs(item,tempitem)# Step 6: Now that all multiplication and addition functions only take two# arguments, we can now easily define fused-multiply-add functions,# where AddSIMD(a,MulSIMD(b,c)) = b*c + a = FusedMulAddSIMD(b,c,a),# or AddSIMD(MulSIMD(b,c),a) = b*c + a = FusedMulAddSIMD(b,c,a).# Fused multiply add (FMA3) is standard on Intel CPUs with the AVX2# instruction set, starting with Haswell processors in 2013:# https://en.wikipedia.org/wiki/Haswell_(microarchitecture)for item in preorder_traversal(expr):tempitem = item# If the pattern is a*b + c, replace with FMA(a,b,c)if item.func == AddSIMD and item.args[0].func == MulSIMD:tempitem = FusedMulAddSIMD(item.args[0].args[0],item.args[0].args[1],item.args[1])# If the pattern is c + a*b, replace with FMA(a,b,c)if item.func == AddSIMD and item.args[1].func == MulSIMD:tempitem = FusedMulAddSIMD(item.args[1].args[0],item.args[1].args[1],item.args[0])# If the pattern is a*b - c, replace with FMS(a,b,c)if item.func == SubSIMD and item.args[0].func == MulSIMD:tempitem = FusedMulSubSIMD(item.args[0].args[0],item.args[0].args[1],item.args[1])if item != tempitem: expr = expr.subs(item, tempitem)# Step 7: SIMD intrinsics cannot take integers or rational numbers as arguments.# Therefore we must declare all integers & rational numbers as# const vector doubles (e.g., const _m256d ...). To make the code# more human readable, we adopt the convention# RationalTMP(1,3) = 1/3 = "Rational_1_3# RationalTMP(-1,3) = -1/3 = "Rational_m1_3# TODO: Keep track of all integers and rationals, so repeats are not computed?# Step 7a: Set all variable names and corresponding values.for item in preorder_traversal(expr):if item.func == RationalTMP:# Set variable nameif item.args[0]*item.args[1] < 0:SIMD_const_varnms.extend(["_Rational_m"+str(abs(item.args[0]))+"_"+str(abs(item.args[1]))+SIMD_const_suffix])elif item.args[0] > 0 and item.args[1] > 0:SIMD_const_varnms.extend(["_Rational_"+str(item.args[0])+"_"+str(item.args[1])+SIMD_const_suffix])else:# E.g., doesn't make sense to have -1/-3. SymPy should have simplified this.print("Found a weird Rational(a,b) expression, where a<0 and b<0. Report to SymPy devels")print("Specifically, found that a="+str(item.args[0])+" and b="+str(item.args[1]))sys.exit(1)# Set variable value, to 34 digits of precisionSIMD_const_values.extend([str(N(Float(item.args[0],34)/Float(item.args[1],34),34))])elif item.func == IntegerTMP:# Set variable nameif item.args[0] < 0:SIMD_const_varnms.extend(["_Integer_m"+str(-item.args[0])+SIMD_const_suffix])else:SIMD_const_varnms.extend(["_Integer_" + str(item.args[0])+SIMD_const_suffix])# Set variable value, to 34 digits of precisionSIMD_const_values.extend([str((Float(item.args[0],34)))])# Step 7b: Replace all integers and rationals with the appropriate variable names:for item in preorder_traversal(expr):tempitem = itemif item.func == RationalTMP:if item.args[0]*item.args[1] < 0:tempitem = var("_Rational_m" + str(abs(item.args[0])) + "_" + str(abs(item.args[1]))+SIMD_const_suffix)elif item.args[0] > 0 and item.args[1] > 0:tempitem = var("_Rational_" + str(item.args[0]) + "_" + str(item.args[1])+SIMD_const_suffix)else:# E.g., doesn't make sense to have -1/-3. SymPy should have simplified this.print("Found a weird Rational(a,b) expression, where a<0 and b<0. Report to SymPy devels")print("Specifically, found that a=" + str(item.args[0]) + " and b=" + str(item.args[1]))sys.exit(1)elif item.func == IntegerTMP:if item.args[0] < 0:tempitem = var("_Integer_m" + str(-item.args[0])+SIMD_const_suffix)else:tempitem = var("_Integer_" + str(item.args[0])+SIMD_const_suffix)if item != tempitem: expr = expr.subs(item, tempitem)def lookup_name_output_idx(name, list_of_names):for i in range(len(list_of_names)):if list_of_names[i] == name:return iprint("I SHOULDN'T BE HERE!",name,list_of_names)sys.exit(1)if debug=="True":expr_check = exprif "SIMD" in str(expr):expr_check = eval(str(expr).replace("SIMD","SIMD_check"))for item in preorder_traversal(expr_check):tempitem = itemif item.is_Symbol and str(item)[0]=="_":if str(item)[:9]=="_Integer_" or str(item)[:10]=="_Rational_":tempitem = SIMD_const_values[lookup_name_output_idx(str(item), SIMD_const_varnms)]if item != tempitem: expr_check = expr_check.subs(item, tempitem)expr_diff = expr_check - expr_orig# Some variables do not want to cancel in SymPy ~0.7.4. The eval(str(srepr())) below normalizes the expression.expr_diff = eval(str(srepr(expr_diff)))for item in preorder_traversal(expr_diff):if item.func == Float:if abs(item - Integer(item)) < 1.0e-14:expr_diff = expr_diff.xreplace({item:Integer(item)})# Only simplify if expr_diff != 0:if expr_diff != 0:simp_expr_diff = simplify(expr_diff)if simp_expr_diff != 0:print("Warning: found possible diff",(simp_expr_diff))return(expr)
# As documented in the NRPy+ tutorial notebook# Tutorial-cmdline_helper.ipynb, this Python script# provides a multi-platform means to run executables,# remove files, and compile code.# Basic functions:# check_executable_exists(): Check to see whether an executable exists.# Error out or return False if not exists;# return True if executable exists in PATH.# C_compile(): Compile C code using gcc.# Execute(): Execute generated executable file, using taskset# if available. Calls Execute_input_string() to# redirect output from stdout & stderr to desired# destinations.# Execute_input_string(): Executes an input string and redirects# output from stdout & stderr to desired destinations.# delete_existing_files(file_or_wildcard):# Runs del file_or_wildcard in Windows, or# rm file_or_wildcard in Linux/MacOS# Authors: Brandon Clark# Zach Etienne# zachetie **at** gmail **dot* com# Kevin Lituchyimport io, os, shlex, subprocess, sys, time, multiprocessing, getpass, platform# check_executable_exists(): Check to see whether an executable exists.# Error out or return False if not exists;# return True if executable exists in PATH.def check_executable_exists(exec_name,error_if_not_found=True):cmd = "where" if os.name == "nt" else "which"try:subprocess.check_output([cmd, exec_name])except subprocess.CalledProcessError:if error_if_not_found:print("Sorry, cannot execute the command: " + exec_name)sys.exit(1)else:return Falsereturn True# C_compile(): Write a function to compile the Main C code into an executable filedef C_compile(main_C_output_path, main_C_output_file, compile_mode="optimized", custom_compile_string=""):print("Compiling executable...")# Step 1: Check for gcc compilercheck_executable_exists("gcc")# Step 2: Delete existing version of executabledelete_string = ""if os.name == "nt":main_C_output_file += ".exe"delete_existing_files(main_C_output_file)# Step 3: Compile the executableif compile_mode=="safe":compile_string = "gcc -O2 -g -fopenmp "+str(main_C_output_path)+" -o "+str(main_C_output_file)+" -lm"Execute_input_string(compile_string, os.devnull)# Check if executable exists (i.e., compile was successful), if not, try with more conservative compile flags.if not os.path.isfile(main_C_output_file):print("Sorry, compilation failed")sys.exit(1)elif compile_mode=="icc":check_executable_exists("icc")compile_string = "icc -O2 -xHost -qopenmp -unroll "+str(main_C_output_path)+" -o "+str(main_C_output_file)+" -lm"Execute_input_string(compile_string, os.devnull)# Check if executable exists (i.e., compile was successful), if not, try with more conservative compile flags.if not os.path.isfile(main_C_output_file):print("Sorry, compilation failed")sys.exit(1)elif compile_mode=="custom":Execute_input_string(custom_compile_string, os.devnull)# Check if executable exists (i.e., compile was successful), if not, try with more conservative compile flags.if not os.path.isfile(main_C_output_file):print("Sorry, compilation failed")sys.exit(1)elif compile_mode=="optimized":compile_string = "gcc -Ofast -fopenmp -march=native -funroll-loops "+str(main_C_output_path)+" -o "+str(main_C_output_file)+" -lm"Execute_input_string(compile_string, os.devnull)# Check if executable exists (i.e., compile was successful), if not, try with more conservative compile flags.if not os.path.isfile(main_C_output_file):# Step 3.A: Revert to more compatible gcc compile optionprint("Most optimized compilation failed. Removing -march=native:")compile_string = "gcc -Ofast -fopenmp -funroll-loops "+str(main_C_output_path)+" -o "+str(main_C_output_file)+" -lm"Execute_input_string(compile_string, os.devnull)if not os.path.isfile(main_C_output_file):# Step 3.B: Revert to maximally compatible gcc compile optionprint("Next-to-most optimized compilation failed. Moving to maximally-compatible gcc compile option:")compile_string = "gcc -O2 "+str(main_C_output_path)+" -o "+str(main_C_output_file)+" -lm"Execute_input_string(compile_string, os.devnull)# Step 3.C: If there are still missing components within the compiler, say compilation failedif not os.path.isfile(main_C_output_file):print("Sorry, compilation failed")sys.exit(1)else:print("Sorry, compile_mode = \""+compile_mode+"\" unsupported.")sys.exit(1)print("Finished compilation.")# Execute(): Execute generated executable file, using taskset# if available. Calls Execute_input_string() to# redirect output from stdout & stderr to desired# destinations.def Execute(executable, executable_output_arguments="", file_to_redirect_stdout=os.devnull,verbose=True):# Step 1: Delete old version of executable fileif file_to_redirect_stdout != os.devnull:delete_existing_files(file_to_redirect_stdout)# Step 2: Build the script for executing the desired executableexecute_string = ""# When in Windows...# https://stackoverflow.com/questions/1325581/how-do-i-check-if-im-running-on-windows-in-pythonif os.name == "nt":# ... do as the Windows do# https://stackoverflow.com/questions/49018413/filenotfounderror-subprocess-popendir-windows-7execute_prefix = "cmd /c " # Run with cmd /c executable [options] on Windowselse:execute_prefix = "./" # Run with ./executable [options] on Linux & Mactaskset_exists = check_executable_exists("taskset", error_if_not_found=False)if taskset_exists:execute_string += "taskset -c 0"if getpass.getuser() != "jovyan": # on mybinder, username is jovyan, and taskset -c 0 is the fastest option.# If not on mybinder and taskset exists:has_HT_cores = False # Does CPU have hyperthreading cores?if platform.processor() != '': # If processor string returns null, then assume CPU does not support hyperthreading.# This will yield correct behavior on ARM (e.g., cell phone) CPUs.has_HT_cores=Trueif has_HT_cores == True:# NOTE: You will observe a speed-up by using only *PHYSICAL* (as opposed to logical/hyperthreading) cores:N_cores_to_use = int(multiprocessing.cpu_count()/2) # To account for hyperthreading coreselse:N_cores_to_use = int(multiprocessing.cpu_count()) # Use all cores if none are hyperthreading cores.# This will happen on ARM (e.g., cellphone) CPUsfor i in range(N_cores_to_use-1):execute_string += ","+str(i+1)execute_string += " "execute_string += execute_prefix+executable+" "+executable_output_arguments# Step 3: Execute the desired executableExecute_input_string(execute_string, file_to_redirect_stdout,verbose)# Execute_input_string(): Executes an input string and redirects# output from stdout & stderr to desired destinations.def Execute_input_string(input_string, file_to_redirect_stdout=os.devnull, verbose=True):if verbose:print("Executing `"+input_string+"`...")start = time.time()# https://docs.python.org/3/library/subprocess.htmlif os.name != 'nt':args = shlex.split(input_string)else:args = input_string# https://stackoverflow.com/questions/18421757/live-output-from-subprocess-commandfilename = "tmp.txt"with io.open(filename, 'w') as writer, io.open(filename, 'rb', buffering=-1) as reader, io.open(file_to_redirect_stdout, 'wb') as rdirect:process = subprocess.Popen(args, stdout=rdirect, stderr=writer)while process.poll() is None:# https://stackoverflow.com/questions/21689365/python-3-typeerror-must-be-str-not-bytes-with-sys-stdout-write/21689447sys.stdout.write(reader.read().decode('utf-8'))time.sleep(0.2)# Read the remainingsys.stdout.write(reader.read().decode('utf-8'))delete_existing_files(filename)end = time.time()if verbose:print("Finished executing in "+str(end-start)+" seconds.")# delete_existing_files(file_or_wildcard):# Runs del file_or_wildcard in Windows, or# rm file_or_wildcard in Linux/MacOSdef delete_existing_files(file_or_wildcard):delete_string = ""if os.name == "nt":delete_string += "del " + file_or_wildcardelse:delete_string += "rm -f " + file_or_wildcardos.system(delete_string)# https://stackoverflow.com/questions/1274405/how-to-create-new-folderdef mkdir(newpath):if not os.path.exists(os.path.join(newpath)):os.makedirs(os.path.join(newpath))
# finite_difference.py:# As documented in the NRPy+ tutorial notebook:# Tutorial-Finite_Difference_Derivatives.ipynb ,# This module generates C kernels for numerically# solving PDEs with finite differences.## Depends on: outputC.py and grid.py.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* comfrom outputC import * # NRPy+: Core C code output moduleimport grid as gri # NRPy+: Functions having to do with numerical gridsimport sys # Standard Python module for multiplatform OS-level functionsfrom operator import itemgetter# Step 1: Initialize free parameters for this module:import NRPy_param_funcs as parmodulename = __name__# Centered finite difference accuracy orderpar.initialize_param(par.glb_param("int", modulename, "FD_CENTDERIVS_ORDER", 4))par.initialize_param(par.glb_param("int", modulename, "FD_KO_ORDER__CENTDERIVS_PLUS", 2))def FD_outputC(filename,sympyexpr_list, params="", upwindcontrolvec=""):outCparams = parse_outCparams_string(params)# Step 0.a:# In case sympyexpr_list is a single sympy expression,# convert it to a list with just one element:if type(sympyexpr_list) is not list:sympyexpr_list = [sympyexpr_list]# Step 0.b:# finite_difference.py takes control over outCparams.includebraces here,# which is necessary because outputC() is called twice:# first for the reads from main memory and finite difference# stencil expressions, and second for the SymPy expressions and# writes to main memory.# If outCparams.includebraces==True, then it will close off the braces# after the finite difference stencil expressions and start new ones# for the SymPy expressions and writes to main memory, resulting# in a non-functioning C code.# To get around this issue, we create braces around the entire# string of C output from this function, only if# outCparams.includebraces==True.# See Step 6 for corresponding end brace.if outCparams.includebraces == "True":Coutput = outCparams.preindent+"{\n"indent = " "else:Coutput = ""indent = ""# Step 1a:# Create a list of free symbols in the sympy expr list# that are registered neither as gridfunctions nor# as C parameters. These *must* be derivatives,# so we call the list "list_of_deriv_vars"list_of_deriv_vars_with_duplicates = []for expr in sympyexpr_list:for var in expr.rhs.free_symbols:vartype = gri.variable_type(var)if vartype == "other":# vartype=="other" should ONLY refer to derivatives, so# if "_dD" or variants do not appear in a variable classified# neither as a gridfunction nor a Cparameter, then error out.if ("_dD" in str(var)) or \("_dKOD" in str(var)) or \("_dupD" in str(var)) or \("_ddnD" in str(var)):passelse:print("Error: Unregistered variable \""+str(var)+"\" in SymPy expression for "+expr.lhs)print("All variables in SymPy expressions passed to FD_outputC() must be registered")print("in NRPy+ as either a gridfunction or Cparameter, by calling")print(str(var)+" = register_gridfunctions...() (in ixp/grid) if \""+str(var)+"\" is a gridfunction, or")print(str(var)+" = Cparameters() (in par) otherwise (e.g., if it is a free parameter set at C runtime).")sys.exit(1)list_of_deriv_vars_with_duplicates.append(var)# elif vartype == "gridfunction":# list_of_deriv_vars_with_duplicates.append(var)list_of_deriv_vars = superfast_uniq(list_of_deriv_vars_with_duplicates)# Upwinding with respect to a control vector: algorithm description.# To enable, set the FD_outputC()'s fourth function argument to the# desired control vector. In BSSN, the betaU vector controls the upwinding.# See https://arxiv.org/pdf/gr-qc/0206072.pdf for motivation and# https://arxiv.org/pdf/gr-qc/0109032.pdf for implementation details,# at second order. Note that the BSSN shift vector behaves like a *negative*# velocity. See http://www.damtp.cam.ac.uk/user/naweb/ii/advection/advection.php# for a very basic example motivating this choice.# Step 1b: For each variable with suffix _dupD, append to# the list_of_deriv_vars the corresponding _ddnD.# Both are required for control-vector upwinding. See# the above print() block for further documentation# on upwinding--both motivation and implementation# details.if upwindcontrolvec != "":for var in list_of_deriv_vars:if "_dupD" in str(var):list_of_deriv_vars.append(sp.sympify(str(var).replace("_dupD","_ddnD")))# Finally, sort the list_of_deriv_vars. This ensures# consistency in the C code output, and might even be# tuned to reduce cache misses.# Thanks to Aaron Meurer for this nice one-liner!list_of_deriv_vars = sorted(list_of_deriv_vars,key=sp.default_sort_key)# Step 2:# Process list_of_deriv_vars into a list of base gridfunctions# and a list of derivative operators.# Step 2a:# First determine the base gridfunction name from# "list_of_deriv_vars"deriv__base_gridfunction_name = []deriv__operator = []for var in list_of_deriv_vars:# Step 2a.1: Check that the number of juxtaposed integers# at the end of a variable name matches the# number of U's + D's in the variable name:varstr = str(var)num_UDs = 0for i in range(len(varstr)):if varstr[i] == 'D' or varstr[i] == 'U':num_UDs += 1num_digits = 0i = len(varstr) - 1while varstr[i].isdigit():num_digits += 1i-=1if num_UDs != num_digits:print("Error: "+varstr+" has "+str(num_UDs)+" U's and D's, but ")print(str(num_digits)+" integers at the end. These must be equal.")print("Please rename your gridfunction.")sys.exit(1)# Step 2a.2: Based on the variable name, find the rank of# the underlying gridfunction of which we're# trying to take the derivative.rank = 0 # rank = "number of juxtaposed U's and D's before the underscore in a derivative expression"underscore_position = -1for i in range(len(varstr)-1,-1,-1):if underscore_position > 0 and (varstr[i] == "U" or varstr[i] == "D"):rank += 1if varstr[i] == "_":underscore_position = i# Step 2a.3: Based on the variable name, find the order# of the derivative we're trying to take.deriv_order = 0 # deriv_order = "number of D's after the underscore in a derivative expression"for i in range(underscore_position+1,len(varstr)):if (varstr[i] == "D"):deriv_order += 1# Step 2a.4: Based on derivative order and rank,# store the base gridfunction name in# deriv__base_gridfunction_name[]deriv__base_gridfunction_name.append(varstr[0:underscore_position]+varstr[len(varstr)-deriv_order-rank:len(varstr)-deriv_order])deriv__operator.append(varstr[underscore_position+1:len(varstr)-deriv_order-rank]+varstr[len(varstr)-deriv_order:len(varstr)])# Step 2b:# Then check each base gridfunction to determine whether# it is indeed registered as a gridfunction.# If not, exit with error.for basegf in deriv__base_gridfunction_name:is_gf = Falsefor gf in gri.glb_gridfcs_list:if basegf == str(gf.name):is_gf = Truepassif not is_gf:print("Error: Attempting to take the derivative of "+basegf+", which is not a registered gridfunction.")print(" Make sure your gridfunction name does not have any underscores in it!")sys.exit(1)# Step 2c:# Check each derivative operator to make sure it is# supported. If not, error out.for i in range(len(deriv__operator)):found_derivID = Falsefor derivID in ["dD","dupD","ddnD","dKOD"]:if derivID in deriv__operator[i]:found_derivID = Trueif not found_derivID:print("Error: Valid derivative operator in "+deriv__operator[i]+" not found.")sys.exit(1)# Step 2d (Upwinded derivatives algorithm, part 1):# If an upwinding control vector is specified, determine# which of the elements of the vector will be required.# This ensures that those elements are read from memory.# For example, if a symmetry axis is specified,# upwind derivatives with respect to only# two of the three dimensions are used. Here# we find all directions used for upwinding.if upwindcontrolvec != "":upwind_directions_unsorted_withdups = []for deriv_op in deriv__operator:if "dupD" in deriv_op:if deriv_op[len(deriv_op)-1].isdigit():dirn = int(deriv_op[len(deriv_op)-1])upwind_directions_unsorted_withdups.append(dirn)else:print("Error: Derivative operator "+deriv_op+" does not contain a direction")sys.exit(1)upwind_directions = []if len(upwind_directions_unsorted_withdups)>0:upwind_directions = superfast_uniq(upwind_directions_unsorted_withdups)upwind_directions = sorted(upwind_directions,key=sp.default_sort_key)# Step 3:# Evaluate the finite difference stencil for each# derivative operator,# TODO: being careful not to needlessly recompute.# Note: Each finite difference stencil consists# of two parts:# 1) The coefficient, and# 2) The index corresponding to the coefficient.# The former is stored as a rational number, and# the latter as a simple string, such that e.g.,# in 3D, the empty string corresponds to (i,j,k),# the string "ip1" corresponds to (i+1,j,k),# the string "ip1kp1" corresponds to (i+1,j,k+1),# etc.fdcoeffs = [[] for i in range(len(deriv__operator))]fdstencl = [[[] for i in range(4)] for j in range(len(deriv__operator))]for i in range(len(deriv__operator)):fdcoeffs[i], fdstencl[i] = compute_fdcoeffs_fdstencl(deriv__operator[i])# Step 4:# Create C code to read gridfunctions from memory# Step 4a: Compile list of points to read from memory# for each gridfunction i, based on list# provided in fdstencil[i][].list_of_points_read_from_memory_with_duplicates = [[] for i in range(len(gri.glb_gridfcs_list))]for j in range(len(deriv__base_gridfunction_name)):derivgfname = deriv__base_gridfunction_name[j]# Next find the corresponding gridfunction index:for i in range(len(gri.glb_gridfcs_list)):gfname = gri.glb_gridfcs_list[i].name# If the gridfunction for the derivative matches, then# add to the list of points read from memory:if derivgfname == gfname:for k in range(len(fdstencl[j])):list_of_points_read_from_memory_with_duplicates[i].append(str(fdstencl[j][k][0]) + "," + \str(fdstencl[j][k][1]) + "," + \str(fdstencl[j][k][2]) + "," + \str(fdstencl[j][k][3]))# Step 4b: "Zeroth derivative" case:# If gridfunction appears in expression not# as derivative (i.e., by itself), it must# be read from memory as well.for expr in range(len(sympyexpr_list)):for var in sympyexpr_list[expr].rhs.free_symbols:vartype = gri.variable_type(var)if vartype == "gridfunction":for i in range(len(gri.glb_gridfcs_list)):gfname = gri.glb_gridfcs_list[i].nameif gfname == str(var):list_of_points_read_from_memory_with_duplicates[i].append("0,0,0,0")# Step 4c: Remove duplicates when reading from memory;# do not needlessly read the same variable# from memory twice.list_of_points_read_from_memory = [[] for i in range(len(gri.glb_gridfcs_list))]for i in range(len(gri.glb_gridfcs_list)):list_of_points_read_from_memory[i] = superfast_uniq(list_of_points_read_from_memory_with_duplicates[i])# Step 4d: Minimize cache misses:# Sort the list of points read from# main memory by how they are stored# in memory.# Step 4d.i: Define a function that maps a gridpoint# index (i,j,k,l) to a unique memory "address",# which will correspond to the correct ordering# of actual memory addresses.## Input: a list of 4 indices, e.g., (i,j,k,l)# corresponding to a gridpoint's *spatial*# index in memory (thus we support up to# 4D in space). If spatial dimension is# less than 4D, then just set latter# index/indices to zero. E.g., for 2D# spatial indexing, set (i,j,0,0).# Output: a single number, which when sorted# will yield a unique "address" in memory# such that consecutive addresses are# consecutive in memory.def unique_idx(idx4):# os and sz are set *just for the purposes of ensuring indices are ordered in memory*# Do not modify the values of os and sz.os = 50 # offsetsz = 100 # assumed size in each directionif par.parval_from_str("MemAllocStyle") == "210":return str(int(idx4[0])+os + sz*( (int(idx4[1])+os) + sz*( (int(idx4[2])+os) + sz*( int(idx4[3])+os ) ) ))elif par.parval_from_str("MemAllocStyle") == "012":return str(int(idx4[3])+os + sz*( (int(idx4[2])+os) + sz*( (int(idx4[1])+os) + sz*( int(idx4[0])+os ) ) ))else:print("Error: MemAllocStyle = "+par.parval_from_str("MemAllocStyle")+" unsupported.")sys.exit(1)# Step 4d.ii: For each gridfunction and# point read from memory, call unique_idx,# then sort according to memory "address"# Input: list_of_points_read_from_memory[gridfunction][point],# gri.glb_gridfcs_list[gridfunction]# Output: 1) A list of points to be read from# memory, sorted according to memory# "address":# sorted_list_of_points_read_from_memory[gridfunction][point]# 2) A list containing the gridfunction# read at each point, with the number# of elements corresponding exactly# to the total number of points read# from memory for all gridfunctions:# read_from_memory_gf[]read_from_memory_gf = []sorted_list_of_points_read_from_memory = [[] for i in range(len(gri.glb_gridfcs_list))]for gfidx in range(len(gri.glb_gridfcs_list)):# Continue only if reading at least one point of gfidx from memory.# The sorting algorithm at the end of this code block is not# well-defined (will throw an error) if no points of gfidx are# read from memory.if len(list_of_points_read_from_memory[gfidx]) > 0:read_from_memory_index = []for idx in list_of_points_read_from_memory[gfidx]:read_from_memory_gf.append(gri.glb_gridfcs_list[gfidx])idxsplit = idx.split(',')idx4 = [int(idxsplit[0]),int(idxsplit[1]),int(idxsplit[2]),int(idxsplit[3])]read_from_memory_index.append(unique_idx(idx4))# https://stackoverflow.com/questions/13668393/python-sorting-two-listsUNUSEDlist, sorted_list_of_points_read_from_memory[gfidx] = \[list(x) for x in zip(*sorted(zip(read_from_memory_index, list_of_points_read_from_memory[gfidx]),key=itemgetter(0)))]# Step 4e: Create the full C code string# for reading from memory:# if DIM==4:# input: [i,j,k,l]# output: "i0+i,i1+j,i2+k,i3+l"# if DIM==3:# input: [i,j,k,l]# output: "i0+i,i1+j,i2+k"# etc.def ijkl_string(idx4):DIM = par.parval_from_str("DIM")retstring = ""for i in range(DIM):if i>0:# Add a commaretstring += ","retstring += "i"+str(i)+"+"+str(idx4[i])return retstring.replace("+-", "-").replace("+0", "")def out__type_var(in_var,AddPrefix_for_UpDownWindVars=True):varname = str(in_var)# Disable prefixing upwinded and downwinded variables# if the upwind control vector algorithm is disabled.if upwindcontrolvec == "":AddPrefix_for_UpDownWindVars = Falseif AddPrefix_for_UpDownWindVars:if "_dupD" in varname: # Variables suffixed with "_dupD" are set# to be the "pure" upwinded derivative,# before the upwinding algorithm has been# applied. However, when they are used# in the RHS expressions, it is assumed# that the up. algorithm has been applied.# To ensure consistency we rename all# _dupD suffixed variables as# _dupDPUREUPWIND, and use them as input# into the upwinding algorithm. The output# will be the original _dupD variable.varname = "UpwindAlgInput"+varnameif "_ddnD" in varname: # For consistency with _dupDvarname = "UpwindAlgInput"+varnameif outCparams.SIMD_enable == "True":return "const REAL_SIMD_ARRAY " + varnameelse:TYPE = par.parval_from_str("PRECISION")return "const "+ TYPE + " " + varnamedef varsuffix(idx4):if idx4 == [0,0,0,0]:return ""return "_"+ijkl_string(idx4).replace(",","_").replace("+","p").replace("-","m")def read_from_memory_Ccode_onept(gfname,idx):idxsplit = idx.split(',')idx4 = [int(idxsplit[0]),int(idxsplit[1]),int(idxsplit[2]),int(idxsplit[3])]gf_array_name = "in_gfs" # Default array name.gfaccess_str = gri.gfaccess(gf_array_name,gfname,ijkl_string(idx4))if outCparams.SIMD_enable == "True":retstring = out__type_var(gfname) + varsuffix(idx4) +" = ReadSIMD(&" + gfaccess_str + ");"else:retstring = out__type_var(gfname) + varsuffix(idx4) +" = " + gfaccess_str + ";"return retstring+"\n"read_from_memory_Ccode = ""count = 0for gfidx in range(len(gri.glb_gridfcs_list)):for pt in range(len(sorted_list_of_points_read_from_memory[gfidx])):read_from_memory_Ccode += read_from_memory_Ccode_onept(read_from_memory_gf[count].name,sorted_list_of_points_read_from_memory[gfidx][pt])count += 1# Step 5: Output C code. C code consists of three parts# a) Read gridfunctions from memory at needed pts.# b) Perform arithmetic needed for input expressions# provided in sympyexpr_list[].rhs and associated# finite differences.# c) Write output to gridfunctions specified in# sympyexpr_list[].lhs.def indent_Ccode(Ccode):Ccodesplit = Ccode.splitlines()outstring = ""for i in range(len(Ccodesplit)):outstring += outCparams.preindent+indent+Ccodesplit[i]+'\n'return outstring# Step 5a: Read gridfunctions from memory at needed pts.# *** No need to do anything here; already set in# string "read_from_memory_Ccode". ***# FIXME: Update these code comments:# Step 5b: Perform arithmetic needed for finite differences# associated with input expressions provided in# sympyexpr_list[].rhs.# Note that exprs and lhsvarnames contain# i) finite difference expressions (constructed# in steps above) and associated variable names,# and# ii) Input expressions sympyexpr_list[], which# in general depend on finite difference# variables.exprs = []lhsvarnames = []# Step 5b.i: Output finite difference expressions to# Coutput stringfor i in range(len(list_of_deriv_vars)):exprs.append(sp.sympify(0)) # Append a new element to the list of derivative expressions.lhsvarnames.append(out__type_var(list_of_deriv_vars[i]))var = deriv__base_gridfunction_name[i]for j in range(len(fdcoeffs[i])):varname = str(var)+varsuffix(fdstencl[i][j])exprs[i] += fdcoeffs[i][j]*sp.sympify(varname)# Multiply each expression by the appropriate power# of 1/dx[i]invdx = []for d in range(par.parval_from_str("DIM")):invdx.append(sp.sympify("invdx"+str(d)))# First-order or Kreiss-Oliger derivatives:if (len(deriv__operator[i]) == 5 and "dKOD" in deriv__operator[i]) or \(len(deriv__operator[i]) == 3 and "dD" in deriv__operator[i]) or \(len(deriv__operator[i]) == 5 and ("dupD" in deriv__operator[i] or "ddnD" in deriv__operator[i])):dirn = int(deriv__operator[i][len(deriv__operator[i])-1])exprs[i] *= invdx[dirn]# Second-order derivs:elif len(deriv__operator[i]) == 5 and "dDD" in deriv__operator[i]:dirn1 = int(deriv__operator[i][len(deriv__operator[i]) - 2])dirn2 = int(deriv__operator[i][len(deriv__operator[i]) - 1])exprs[i] *= invdx[dirn1]*invdx[dirn2]else:print("Error: was unable to parse derivative operator: ",deriv__operator[i])sys.exit(1)# Step 5b.ii: If upwind control vector is specified,# add upwind control vectors to the# derivative expression list, so its# needed elements are read from memory.if upwindcontrolvec != "":for i in range(len(upwind_directions)):exprs.append(upwindcontrolvec[upwind_directions[i]])lhsvarnames.append(out__type_var("UpwindControlVectorU"+str(upwind_directions[i])))# Step 5b.iii: Output useful code comment regarding# which step we are on. *At most* this# is a 3-step process:# 1. Read from memory & compute FD stencils,# 2. Perform upwinding, and# 3. Evaluate remaining expressions+write# results to main memory.NRPy_FD_StepNumber = 1NRPy_FD__Number_of_Steps = 1if len(list_of_deriv_vars) > 0:NRPy_FD__Number_of_Steps += 1if upwindcontrolvec != "" and len(upwind_directions) > 0:NRPy_FD__Number_of_Steps += 1if len(read_from_memory_Ccode) > 0:Coutput += indent_Ccode("/* \n * NRPy+ Finite Difference Code Generation, Step "+ str(NRPy_FD_StepNumber) + " of " + str(NRPy_FD__Number_of_Steps)+": Read from main memory and compute finite difference stencils:\n */\n")NRPy_FD_StepNumber = NRPy_FD_StepNumber + 1default_CSE_varprefix = outCparams.CSE_varprefix# Prefix chosen CSE variables with "FD", for the finite difference coefficients:Coutput += indent_Ccode(outputC(exprs,lhsvarnames,"returnstring",params=params + ",CSE_varprefix="+default_CSE_varprefix+"FD,includebraces=False,SIMD_const_suffix=_FDcoeff",prestring=read_from_memory_Ccode))# Step 5b.iv: Implement control-vector upwinding algorithm.if upwindcontrolvec != "":if len(upwind_directions) > 0:Coutput += indent_Ccode("/* \n * NRPy+ Finite Difference Code Generation, Step "+ str(NRPy_FD_StepNumber) + " of " + str(NRPy_FD__Number_of_Steps) +": Implement upwinding algorithm:\n */\n")NRPy_FD_StepNumber = NRPy_FD_StepNumber + 1if outCparams.SIMD_enable == "True":Coutput += """const double tmp_upwind_Integer_1 = 1.000000000000000000000000000000000;const REAL_SIMD_ARRAY upwind_Integer_1 = ConstSIMD(tmp_upwind_Integer_1);const double tmp_upwind_Integer_0 = 0.000000000000000000000000000000000;const REAL_SIMD_ARRAY upwind_Integer_0 = ConstSIMD(tmp_upwind_Integer_0);"""for dirn in upwind_directions:Coutput += indent_Ccode(out__type_var("UpWind" + str(dirn)) + " = UPWIND_ALG(UpwindControlVectorU" + str(dirn) + ");\n")upwindU = [sp.sympify(0) for i in range(par.parval_from_str("DIM"))]for dirn in upwind_directions:upwindU[dirn] = sp.sympify("UpWind"+str(dirn))for i in range(len(list_of_deriv_vars)):if len(deriv__operator[i]) == 5 and ("dupD" in deriv__operator[i]):var_dupD = sp.sympify("UpwindAlgInput"+str(list_of_deriv_vars[i]))var_ddnD = sp.sympify("UpwindAlgInput"+str(list_of_deriv_vars[i]).replace("_dupD","_ddnD"))upwind_dirn = int(deriv__operator[i][len(deriv__operator[i])-1])upwind_expr = upwindU[upwind_dirn]*(var_dupD - var_ddnD) + var_ddnD# For convenience, we require out__type_var() above to# prefix up/downwinded variables with "UpwindAlgInput".# Here we do not wish to have this prefix.Coutput += indent_Ccode(outputC(upwind_expr,out__type_var(str(list_of_deriv_vars[i]),AddPrefix_for_UpDownWindVars=False),"returnstring",params=params + ",includebraces=False"))# Step 5b.v: Add input RHS & LHS expressions from# sympyexpr_list[]Coutput += indent_Ccode("/* \n * NRPy+ Finite Difference Code Generation, Step "+ str(NRPy_FD_StepNumber) + " of " + str(NRPy_FD__Number_of_Steps) +": Evaluate SymPy expressions and write to main memory:\n */\n")exprs = []lhsvarnames = []for i in range(len(sympyexpr_list)):exprs.append(sympyexpr_list[i].rhs)if outCparams.SIMD_enable == "True":lhsvarnames.append("const REAL_SIMD_ARRAY __RHS_exp_"+str(i))else:lhsvarnames.append(sympyexpr_list[i].lhs)# Step 5c: Write output to gridfunctions specified in# sympyexpr_list[].lhs.write_to_mem_string = ""if outCparams.SIMD_enable == "True":for i in range(len(sympyexpr_list)):write_to_mem_string += "WriteSIMD(&"+sympyexpr_list[i].lhs+", __RHS_exp_"+str(i)+");\n"Coutput += indent_Ccode(outputC(exprs,lhsvarnames,"returnstring", params = params+",includebraces=False,preindent=0", prestring="",poststring=write_to_mem_string))# Step 6: Add consistent indentation to the output end brace.# See Step 0.b for corresponding start brace.if outCparams.includebraces == "True":Coutput += outCparams.preindent+"}\n"# Step 7: Output the C code in desired format: stdout, string, or file.if filename == "stdout":print(Coutput)elif filename == "returnstring":return Coutput+'\n'else:# Output to the file specified by outCfilenamewith open(filename, outCparams.outCfileaccess) as file:file.write(Coutput)successstr = ""if outCparams.outCfileaccess == "a":successstr = "Appended "elif outCparams.outCfileaccess == "w":successstr = "Wrote "print(successstr + "to file \"" + filename + "\"")# print(gri.glb_gridfcs_list[1].name,list_of_points_read_from_memory[1])# Define the to-be-inverted matrix, A.# We define A row-by-row, according to the prescription# derived in notes/notes.pdf, via the following pattern# that applies for arbitrary order.## As an example, consider a 5-point finite difference# stencil (4th-order accurate), where we wish to compute# some derivative at the center point.## Then A is given by:## -2^0 -1^0 1 1^0 2^0# -2^1 -1^1 0 1^1 2^1# -2^2 -1^2 0 1^2 2^2# -2^3 -1^3 0 1^3 2^3# -2^4 -1^4 0 1^4 2^4## Then right-multiplying A^{-1}# by (1 0 0 0 0)^T will yield 0th deriv. stencil# by (0 1 0 0 0)^T will yield 1st deriv. stencil# by (0 0 1 0 0)^T will yield 2nd deriv. stencil# etc.## Next suppose we want an upwinded, 4th-order accurate# stencil. For this case, A is given by:## -1^0 1 1^0 2^0 3^0# -1^1 0 1^1 2^1 3^1# -1^2 0 1^2 2^2 3^2# -1^3 0 1^3 2^3 3^3# -1^4 0 1^4 2^4 3^4## ... and similarly for the downwinded derivative.## Finally, let's consider a 3rd-order accurate# stencil. This would correspond to an in-place# upwind stencil with stencil radius of 2 gridpoints,# where other, centered derivatives are 4th-order# accurate. For this case, A is given by:## -1^0 1 1^0 2^0# -1^1 0 1^1 2^1# -1^2 0 1^2 2^2# -1^3 0 1^3 2^3# -1^4 0 1^4 2^4## ... and similarly for the downwinded derivative.## The general pattern is as follows:## 1) The top row is all 1's,# 2) If the second row has N elements (N must be odd),# .... then the radius of the stencil is rs = (N-1)/2# .... and the j'th row e_j = j-rs-1. For example,# .... for 4th order, we have rs = 2# .... j | element# .... 1 | -2# .... 2 | -1# .... 3 | 0# .... 4 | 1# .... 5 | 2# 3) The L'th row, L>2 will be the same as the second# .... row, but with each element e_j -> e_j^(L-1)# A1 is used later to validate the inverted# matrix.def compute_fdcoeffs_fdstencl(derivstring,FDORDER=-1):# Step 0: Set finite differencing order, stencil size, and up/downwindingif FDORDER == -1:FDORDER = par.parval_from_str("FD_CENTDERIVS_ORDER")if "dKOD" in derivstring:FDORDER += par.parval_from_str("FD_KO_ORDER__CENTDERIVS_PLUS")STENCILSIZE = FDORDER+1UPDOWNWIND = 0if "dupD" in derivstring:UPDOWNWIND = 1elif "ddnD" in derivstring:UPDOWNWIND = -1# Step 1: Set up matrix based on the stencil size (FDORDER+1).# See documentation above for details on how this# matrix is set up.M = sp.zeros(STENCILSIZE,STENCILSIZE)for i in range(STENCILSIZE):for j in range(STENCILSIZE):if i == 0:M[(i,j)] = 1 # Setting n^0 = 1 for all n, including n=0, because this matches the patternelse:dist_from_xeq0_col = j - sp.Rational((STENCILSIZE - 1),2) + UPDOWNWINDif dist_from_xeq0_col==0:M[(i,j)] = 0else:M[(i, j)] = dist_from_xeq0_col**(i)Minv = sp.zeros(STENCILSIZE,STENCILSIZE)Minv = M**(-1)# Step 2:# Based on the input derivative string,# pick out the relevant row of the matrix# inverse, as outlined in the detailed code# comments prior to this function definition.derivtype = "FirstDeriv"matrixrow = 1if "DDD" in derivstring:print("Error: Only derivatives up to second order currently supported.")print(" Feel free to contribute to NRPy+ to extend its functionality!")sys.exit(1)elif "DD" in derivstring:if derivstring[len(derivstring)-1] == derivstring[len(derivstring)-2]:# Assuming i==j, we call \partial_i \partial_j gf an "unmixed" second derivative,# or more simply, just "SecondDeriv":derivtype = "SecondDeriv"matrixrow = 2else:# Assuming i!=j, we call \partial_i \partial_j gf a MIXED second derivative,# which is computed using a composite of first derivative operations.derivtype = "MixedSecondDeriv"elif "dKOD" in derivstring:derivtype = "KreissOligerDeriv"matrixrow = STENCILSIZE - 1else:# Up/downwinded and first derivs are all of "FirstDeriv" typepass# Step 3:# Set finite difference coefficients# and stencil points corresponding to# each finite difference coefficient.fdcoeffs = []fdstencl = []if derivtype != "MixedSecondDeriv":for i in range(STENCILSIZE):idx4 = [0, 0, 0, 0]# First compute finite difference coefficient.fdcoeff = sp.factorial(matrixrow)*Minv[(i,matrixrow)]# Do not store fdcoeff or fdstencil if# finite difference coefficient is zero.if fdcoeff != 0:fdcoeffs.append(fdcoeff)if derivtype == "KreissOligerDeriv":fdcoeffs[i] *= (-1)**(sp.Rational((STENCILSIZE+1),2))/2**matrixrow# Next store finite difference stencil point# corresponding to coefficient.gridpt_posn = i - int((STENCILSIZE-1)/2) + UPDOWNWINDif gridpt_posn != 0:dirn = int(derivstring[len(derivstring)-1])idx4[dirn] = gridpt_posnfdstencl.append(idx4)else:# Mixed second derivative finite difference coeffs# consist of products of first deriv coeffs,# defined in first Minv matrix row.for i in range(STENCILSIZE):for j in range(STENCILSIZE):idx4 = [0, 0, 0, 0]# First compute finite difference coefficient.fdcoeff = (sp.factorial(matrixrow)*Minv[(i,matrixrow)]) * \(sp.factorial(matrixrow)*Minv[(j,matrixrow)])# Do not store fdcoeff or fdstencil if# finite difference coefficient is zero.if fdcoeff != 0:fdcoeffs.append(fdcoeff)# Next store finite difference stencil point# corresponding to coefficient.gridpt_posn1 = i - int((STENCILSIZE - 1) / 2)gridpt_posn2 = j - int((STENCILSIZE - 1) / 2)dirn1 = int(derivstring[len(derivstring) - 1])dirn2 = int(derivstring[len(derivstring) - 2])idx4[dirn1] = gridpt_posn1idx4[dirn2] = gridpt_posn2fdstencl.append(idx4)return fdcoeffs,fdstencl
# grid.py: functions & parameters related to numerical grids# functions: Automatic loop output, output C code needed for gridfunction memory I/O, gridfunction registration# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* comimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport sympy as sp # Import SymPy, a computer algebra system written entirely in Pythonfrom collections import namedtuple # Standard Python `collections` module: defines named tuples data structure# Initialize globals related to the gridglb_gridfcs_list = []glb_gridfc = namedtuple('gridfunction', 'gftype name rank DIM')thismodule = __name__par.initialize_param(par.glb_param("char", thismodule, "GridFuncMemAccess", "SENRlike"))par.initialize_param(par.glb_param("char", thismodule, "MemAllocStyle","210"))par.initialize_param(par.glb_param("int", thismodule, "DIM", 3))Nxx = par.Cparameters("int", thismodule,["Nxx0","Nxx1","Nxx2"],[64,32,64]) # Default to 64x32x64 gridNxx_plus_2NGHOSTS = par.Cparameters("int", thismodule,["Nxx_plus_2NGHOSTS0","Nxx_plus_2NGHOSTS1","Nxx_plus_2NGHOSTS2"],[ 70, 38, 70]) # Default to 64x32x64 grid w/ NGHOSTS=3xx = par.Cparameters("REAL",thismodule,[ "xx0", "xx1", "xx2"],1e300) # These are C variables, not parameters, and# will be overwritten; best to initialize to crazy# number to ensure they are overwritten!dxx = par.Cparameters("REAL",thismodule,[ "dxx0", "dxx1", "dxx2"],0.1)invdx = par.Cparameters("REAL",thismodule,[ "invdx0", "invdx1", "invdx2"],1.0)def variable_type(var):var_is_gf = Falsefor gf in range(len(glb_gridfcs_list)):if str(var) == glb_gridfcs_list[gf].name:var_is_gf = Truevar_is_parameter = False# for paramname in range(len(par.glb_params_list)):# if str(var) == par.glb_params_list[paramname].parname:# var_is_parameter = Truefor paramname in range(len(par.glb_Cparams_list)):if str(var) == par.glb_Cparams_list[paramname].parname:var_is_parameter = Trueif var_is_parameter and var_is_gf:print("Error: variable "+str(var)+" is registered both as a gridfunction and as a Cparameter.")sys.exit(1)if not (var_is_parameter or var_is_gf):return "other"if var_is_parameter:return "Cparameter"if var_is_gf:return "gridfunction"def find_gftype(varname):for gf in glb_gridfcs_list:if gf.name == varname:return gf.gftypedef gfaccess(gfarrayname = "", varname = "", ijklstring = ""):found_registered_gf = Falsefor gf in glb_gridfcs_list:if gf.name == varname:if found_registered_gf:print("Error: found duplicate gridfunction name: "+gf.name)sys.exit(1)found_registered_gf = Trueif not found_registered_gf:print("Error: gridfunction \""+varname+"\" is not registered!")sys.exit(1)gftype = find_gftype(varname)DIM = par.parval_from_str("DIM")retstring = ""if par.parval_from_str("GridFuncMemAccess") == "SENRlike":if gfarrayname == "":print("Error: GridFuncMemAccess = SENRlike requires gfarrayname be passed to gfaccess()")sys.exit(1)# FIXME: if gftype == "AUX" then override gfarrayname to aux_gfs[].# This enables expressions containing a mixture of AUX and EVOL# gridfunctions, though in a slightly hacky way.if gftype == "AUX":gfarrayname = "aux_gfs"elif gftype == "AUXEVOL":gfarrayname = "auxevol_gfs"# Return gfarrayname[IDX3(varname,i0)] for DIM=1, gfarrayname[IDX3(varname,i0,i1)] for DIM=2, etc.retstring += gfarrayname + "[IDX" + str(DIM+1) + "(" + varname.upper()+"GF" + ", "elif par.parval_from_str("GridFuncMemAccess") == "ETK":# Return varname[CCTK_GFINDEX3D(i0,i1,i2)] for DIM=3. Error otherwiseif DIM != 3:print("Error: GridFuncMemAccess = ETK currently requires that gridfunctions be 3D. Can be easily extended.")sys.exit(1)if gfarrayname == "rhs_gfs":retstring += varname + "_rhsGF" + "[CCTK_GFINDEX"+str(DIM)+"D(cctkGH, "else:retstring += varname + "GF" + "[CCTK_GFINDEX"+str(DIM)+"D(cctkGH, "else:print("grid::GridFuncMemAccess = "+par.parval_from_str("GridFuncMemAccess")+" not supported")sys.exit(1)if ijklstring == "":for i in range(DIM):retstring += "i"+str(i)if i != DIM-1:retstring += ', 'else:retstring += ijklstringreturn retstring + ")]"# Gridfunction basenames cannot end in integers.# For example, rank-1 gridfunction vecU1 has# basename "vecU". Thus this gridfunction has# a valid basename. If we instead defined a# scalar gridfunction "u2", this would have a# basename of "u2" -- not a valid basename.# Being so strict enables us to determine# quickly what a gridfunction is by its name# alone, which is useful, e.g., when setting# up parity boundary conditions.def verify_gridfunction_basename_is_valid(gf_basename):# First check for zero-length basenames:if len(gf_basename) == 0:print("Error: tried to register gridfunction without a name!")sys.exit(1)# https://stackoverflow.com/questions/1303243/how-to-find-out-if-a-python-object-is-a-stringif sys.version_info[0] < 3:if not isinstance(gf_basename,basestring):print("ERROR: gf_names must be strings")sys.exit(1)else:if not isinstance(gf_basename, str):print("ERROR: gf_names must be strings")sys.exit(1)if len(gf_basename) > 0 and gf_basename[-1].isdigit():print("Error: tried to register gridfunction with base name: "+gf_basename)print(" Gridfunctions with base names ending in an integer is forbidden; pick a new name.")sys.exit(1)import sysdef register_gridfunctions(gf_type,gf_names,rank=0,is_indexed=False,DIM=3):# Step 0: Sanity checkif (rank > 0 and is_indexed == False) or (rank == 0 and is_indexed == True):print("Error: Attempted to register *indexed* gridfunction(s) with rank 0, or *scalar* gridfunctions with rank>0.")print(" Gridfunctions = ",gf_names)sys.exit(1)# Step 1: convert gf_names to a list if it's not already a listif type(gf_names) is not list:gf_namestmp = [gf_names]gf_names = gf_namestmp# Step 2: if the gridfunction is not indexed, then# gf_names == base names. Check that the# gridfunction basenames are valid:if is_indexed==False:for i in range(len(gf_names)):verify_gridfunction_basename_is_valid(gf_names[i])# Step 3: Verify that gridfunction type is valid.if not (gf_type == "EVOL" or gf_type == "AUX" or gf_type == "AUXEVOL"):print("Error in registering gridfunction(s) with unsupported type "+gf_type+".")print("Supported types include \"EVOL\" for gridfunctions related to evolved quantities or \"AUX\" for all others.")sys.exit(1)# Step 4: Check for duplicate grid function registrations. If:# a) A duplicate is found, error out. Otherwise# b) Append to list of gridfunctions, stored in glb_gridfcs_list[].for i in range(len(gf_names)):for j in range(len(glb_gridfcs_list)):if gf_names[i] == glb_gridfcs_list[j].name:print("Error: Tried to register the gridfunction \""+gf_names[i]+"\" twice (ignored type)\n\n")sys.exit(1)# If no duplicate found, append to "gridfunctions" list:glb_gridfcs_list.append(glb_gridfc(gf_type,gf_names[i],rank,DIM))# Step 5: Return SymPy object corresponding to symbol or# list of symbols representing gridfunction in# SymPy expressionOBJ_TMPS = []for i in range(len(gf_names)):OBJ_TMPS.append(sp.symbols(gf_names[i], real=True))# OBJ_TMPS.append(sp.sympify(gf_names[i]))if len(gf_names)==1:return OBJ_TMPS[0]return OBJ_TMPS# Given output directory "outdir" as input, the# following function outputs a file called# "outdir/gridfunction_defines.h", which# #define's all the gridfunction aliases, and# returns two lists, corresponding to the# names (strings) of the evolved and auxiliary# gridfunction names respectively.## For example, if we define only two gridfunctions uu and vv,# which are evolved quantities (i.e., represent# the solution of the PDEs we are solving and are# registered with gftype == "EVOL"), then# this function will create a file with the following# content:## | /* This file is automatically generated by NRPy+. Do not edit. */# | /* EVOLVED VARIABLES: */# | #define NUM_EVOL_GFS 2# | #define UUGF 0# | #define VVGF 1# |# | /* AUXILIARY VARIABLES: */# | #define NUM_AUX_GFS 0## The function will return two lists: the lists of# EVOL and AUX gridfunction names, respectively.# For this example, the first list (all gridfunctions# registered as EVOL) will be ["uu","vv"], and the# second (all gridfunctions registered as AUX) will# be the empty list: []def gridfunction_lists():evolved_variables_list = []auxiliary_variables_list = []auxevol_variables_list = []for i in range(len(glb_gridfcs_list)):if glb_gridfcs_list[i].gftype == "EVOL":evolved_variables_list.append(glb_gridfcs_list[i].name)if glb_gridfcs_list[i].gftype == "AUX":auxiliary_variables_list.append(glb_gridfcs_list[i].name)if glb_gridfcs_list[i].gftype == "AUXEVOL":auxevol_variables_list.append(glb_gridfcs_list[i].name)# Next we alphabetize the listsevolved_variables_list.sort()auxiliary_variables_list.sort()auxevol_variables_list.sort()return evolved_variables_list,auxiliary_variables_list,auxevol_variables_listdef output__gridfunction_defines_h__return_gf_lists(outdir):evolved_variables_list, auxiliary_variables_list, auxevol_variables_list = gridfunction_lists()# Finally we set up the #define statements:with open(outdir+"/gridfunction_defines.h", "w") as file:file.write("/* This file is automatically generated by NRPy+. Do not edit. */\n\n")file.write("/* EVOLVED VARIABLES: */\n")file.write("#define NUM_EVOL_GFS "+str(len(evolved_variables_list))+"\n")for i in range(len(evolved_variables_list)):file.write("#define "+evolved_variables_list[i].upper()+"GF\t"+str(i)+"\n")file.write("\n\n /* AUXILIARY VARIABLES: */\n")file.write("#define NUM_AUX_GFS " + str(len(auxiliary_variables_list)) + "\n")for i in range(len(auxiliary_variables_list)):file.write("#define " + auxiliary_variables_list[i].upper() + "GF\t" + str(i) + "\n")file.write("\n\n /* AUXEVOL VARIABLES: */\n")file.write("#define NUM_AUXEVOL_GFS "+str(len(auxevol_variables_list))+"\n")for i in range(len(auxevol_variables_list)):file.write("#define "+auxevol_variables_list[i].upper()+"GF\t"+str(i)+"\n")return evolved_variables_list,auxiliary_variables_list,auxevol_variables_list
# indexedexp.py: functions related to indexed expressions,# including e.g., tensors and pseudotensors:# Step 1: Load needed modulesimport NRPy_param_funcs as parimport grid as griimport sympy as spimport systhismodule = __name__par.initialize_param(par.glb_param("char", thismodule, "symmetry_axes", ""))def zerorank1(DIM=-1):if DIM == -1:DIM = par.parval_from_str("DIM")return [sp.sympify(0) for i in range(DIM)]def zerorank2(DIM=-1):if DIM == -1:DIM = par.parval_from_str("DIM")return [[sp.sympify(0) for i in range(DIM)] for j in range(DIM)]def zerorank3(DIM=-1):if DIM == -1:DIM = par.parval_from_str("DIM")return [[[sp.sympify(0) for i in range(DIM)] for j in range(DIM)] for k in range(DIM)]def zerorank4(DIM=-1):if DIM == -1:DIM = par.parval_from_str("DIM")return [[[[sp.sympify(0) for i in range(DIM)] for j in range(DIM)] for k in range(DIM)] for l in range(DIM)]def apply_symmetry_condition_to_derivatives(IDX_OBJ):symmetry_axes = par.parval_from_str("indexedexp::symmetry_axes")if symmetry_axes == "":return IDX_OBJrank = 1if isinstance(IDX_OBJ[0], list):if not isinstance(IDX_OBJ[0][0], list):rank = 2elif not isinstance(IDX_OBJ[0][0][0], list):rank = 3elif not isinstance(IDX_OBJ[0][0][0][0], list):rank = 4else:print("Error: could not figure out rank for ",IDX_OBJ)sys.exit(1)def does_IDXOBJ_perform_derivative_across_symmetry_axis(idxobj_str):returnval = Falseif "_d" in idxobj_str:# First we find the order of the derivative:deriv_order = 0underscore_position = -1000for i in range(len(idxobj_str)-1):if idxobj_str[i] == "_" and idxobj_str[i+1]=="d":# The order of the derivative is given by the number of D's in a row after the _d:for k in range(i+2,len(idxobj_str)):if idxobj_str[k] == "D":deriv_order = deriv_order + 1if deriv_order > 2:print("Error. Derivative order > 2 not supported. Found derivative order = "+str(deriv_order))sys.exit(1)end_idx_of_idxobj_str = len(idxobj_str)-1for j in range(end_idx_of_idxobj_str,end_idx_of_idxobj_str-deriv_order,-1):if idxobj_str[j] in symmetry_axes:return Truereturn Falseif rank == 1:DIM = len(IDX_OBJ)for i0 in range(DIM):if does_IDXOBJ_perform_derivative_across_symmetry_axis(str(IDX_OBJ[i0])) == True:IDX_OBJ[i0] = sp.sympify(0)if rank == 2:DIM = len(IDX_OBJ[0])for i0 in range(DIM):for i1 in range(DIM):if does_IDXOBJ_perform_derivative_across_symmetry_axis(str(IDX_OBJ[i0][i1])) == True:IDX_OBJ[i0][i1] = sp.sympify(0)if rank == 3:DIM = len(IDX_OBJ[0][0])for i0 in range(DIM):for i1 in range(DIM):for i2 in range(DIM):if does_IDXOBJ_perform_derivative_across_symmetry_axis(str(IDX_OBJ[i0][i1][i2])) == True:IDX_OBJ[i0][i1][i2] = sp.sympify(0)if rank == 4:DIM = len(IDX_OBJ[0][0][0])for i0 in range(DIM):for i1 in range(DIM):for i2 in range(DIM):for i3 in range(DIM):if does_IDXOBJ_perform_derivative_across_symmetry_axis(str(IDX_OBJ[i0][i1][i2][i3])) == True:IDX_OBJ[i0][i1][i2][i3] = sp.sympify(0)return IDX_OBJdef declarerank1(objname, DIM=-1):if DIM==-1:DIM = par.parval_from_str("DIM")IDX_OBJ_TMP = [sp.sympify(objname + str(i)) for i in range(DIM)]return apply_symmetry_condition_to_derivatives(IDX_OBJ_TMP)def register_gridfunctions_for_single_rank1(gf_type,gf_basename, DIM=-1):# Step 0: Verify the gridfunction basename is valid:gri.verify_gridfunction_basename_is_valid(gf_basename)# Step 1: Declare a list of SymPy variables,# where IDX_OBJ_TMP[i] = gf_basename+str(i)IDX_OBJ_TMP = declarerank1(gf_basename, DIM)# Step 2: Register each gridfunctionif DIM==-1:DIM = par.parval_from_str("DIM")gf_list = []for i in range(DIM):gf_list.append(str(IDX_OBJ_TMP[i]))gri.register_gridfunctions(gf_type, gf_list, rank=1, is_indexed=True, DIM=DIM)# Step 3: Return array of SymPy variablesreturn IDX_OBJ_TMPdef declarerank2(objname, symmetry_option, DIM=-1):if DIM==-1:DIM = par.parval_from_str("DIM")IDX_OBJ_TMP = [[sp.sympify(objname + str(i) + str(j)) for j in range(DIM)] for i in range(DIM)]for i in range(DIM):for j in range(DIM):if symmetry_option == "sym01":if (j < i):# j<i in g_{ij} would indicate, e.g., g_{21}.# By this convention, we must set# g_{21} = g_{12}:IDX_OBJ_TMP[i][j] = IDX_OBJ_TMP[j][i]elif symmetry_option == "nosym":passelse:print("Error: symmetry option " + symmetry_option + " unsupported.")sys.exit(1)return apply_symmetry_condition_to_derivatives(IDX_OBJ_TMP)def register_gridfunctions_for_single_rank2(gf_type,gf_basename, symmetry_option, DIM=-1):# Step 0: Verify the gridfunction basename is valid:gri.verify_gridfunction_basename_is_valid(gf_basename)# Step 1: Declare a list of lists of SymPy variables,# where IDX_OBJ_TMP[i][j] = gf_basename+str(i)+str(j)IDX_OBJ_TMP = declarerank2(gf_basename,symmetry_option, DIM)# Step 2: register each gridfunction, being careful not# not to store duplicates due to rank-2 symmetries.if DIM==-1:DIM = par.parval_from_str("DIM")# Register only unique gridfunctions. Otherwise# rank-2 symmetries might result in duplicatesgf_list = []for i in range(DIM):for j in range(DIM):save = Truefor l in range(len(gf_list)):if gf_list[l] == str(IDX_OBJ_TMP[i][j]):save = Falseif save == True:gf_list.append(str(IDX_OBJ_TMP[i][j]))gri.register_gridfunctions(gf_type,gf_list,rank=2, is_indexed=True, DIM=DIM)# Step 3: Return array of SymPy variablesreturn IDX_OBJ_TMPdef declarerank3(objname, symmetry_option, DIM=-1):if DIM==-1:DIM = par.parval_from_str("DIM")IDX_OBJ_TMP = [[[sp.sympify(objname + str(i) + str(j) + str(k)) for k in range(DIM)] for j in range(DIM)] for i in range(DIM)]for i in range(DIM):for j in range(DIM):for k in range(DIM):if symmetry_option == "sym01":if j < i:IDX_OBJ_TMP[i][j][k] = IDX_OBJ_TMP[j][i][k]if symmetry_option == "sym12":if k < j:IDX_OBJ_TMP[i][j][k] = IDX_OBJ_TMP[i][k][j]if not (symmetry_option == "sym01" or symmetry_option == "sym12" or symmetry_option == "nosym"):print("Error: symmetry option " + symmetry_option + " unsupported.")sys.exit(1)return apply_symmetry_condition_to_derivatives(IDX_OBJ_TMP)def declarerank4(objname, symmetry_option, DIM=-1):if DIM==-1:DIM = par.parval_from_str("DIM")IDX_OBJ_TMP = [[[[sp.sympify(objname + str(i) + str(j) + str(k) + str(l)) for l in range(DIM)] for k in range(DIM)] for j in range(DIM)] for i in range(DIM)]for i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):IDX_OBJ_TMP[i][j][k][l] = sp.sympify(objname + str(i) + str(j) + str(k) + str(l))if symmetry_option == "sym01" or symmetry_option == "sym01_sym23":if(j < i):IDX_OBJ_TMP[i][j][k][l] = IDX_OBJ_TMP[j][i][k][l]if symmetry_option == "sym12":if(k < j):IDX_OBJ_TMP[i][j][k][l] = IDX_OBJ_TMP[i][k][j][l]if symmetry_option == "sym23" or symmetry_option == "sym01_sym23":if(l < k):IDX_OBJ_TMP[i][j][k][l] = IDX_OBJ_TMP[i][j][l][k]if not (symmetry_option=="sym01" or symmetry_option=="sym23" or symmetry_option=="sym01_sym23" or symmetry_option=="none"):print("Error: symmetry option "+symmetry_option+" unsupported.")sys.exit(1)return apply_symmetry_condition_to_derivatives(IDX_OBJ_TMP)# We use the following functions to evaluate 3-metric inversesdef symm_matrix_inverter3x3(a):# It is far more efficient to write out the matrix determinant and inverse by hand# instead of using symmetry_optionPy's built-in functions, since the matrix is symmetric.outDET = -a[0][2]**2*a[1][1] + 2*a[0][1]*a[0][2]*a[1][2] - \a[0][0]*a[1][2]**2 - a[0][1]**2*a[2][2] + \a[0][0]*a[1][1]*a[2][2]outINV = [[sp.sympify(0) for i in range(3)] for j in range(3)]# First fill in the upper-triangle of the gPhysINV matrix...outINV[0][0] = (-a[1][2]**2 + a[1][1]*a[2][2])/outDEToutINV[0][1] = (+a[0][2]*a[1][2] - a[0][1]*a[2][2])/outDEToutINV[0][2] = (-a[0][2]*a[1][1] + a[0][1]*a[1][2])/outDEToutINV[1][1] = (-a[0][2]**2 + a[0][0]*a[2][2])/outDEToutINV[1][2] = (+a[0][1]*a[0][2] - a[0][0]*a[1][2])/outDEToutINV[2][2] = (-a[0][1]**2 + a[0][0]*a[1][1])/outDEToutINV[1][0] = outINV[0][1]outINV[2][0] = outINV[0][2]outINV[2][1] = outINV[1][2]return outINV, outDETdef symm_matrix_inverter4x4(a):# It is far more efficient to write out the matrix determinant and inverse by hand# instead of using symmetry_optionPy's built-in functions, since the matrix is symmetric.outDET = + a[0][2]*a[0][2]*a[1][3]*a[1][3] + a[0][3]*a[0][3]*a[1][2]*a[1][2] + a[0][1]*a[0][1]*a[2][3]*a[2][3] \- a[0][0]*a[1][3]*a[1][3]*a[2][2] - a[0][3]*a[0][3]*a[1][1]*a[2][2] - a[0][0]*a[1][1]*a[2][3]*a[2][3] \- 2*(+ a[0][1]*a[0][2]*a[1][3]*a[2][3] - a[0][0]*a[1][2]*a[1][3]*a[2][3] \- a[0][3]*(- a[0][2]*a[1][2]*a[1][3] + a[0][1]*a[1][3]*a[2][2] \+ a[0][2]*a[1][1]*a[2][3] - a[0][1]*a[1][2]*a[2][3])) \- a[3][3] * (+ a[0][2]*a[0][2]*a[1][1] - a[0][1]*a[0][2]*a[1][2] - a[0][1]*a[0][2]*a[1][2] \+ a[0][0]*a[1][2]*a[1][2] + a[0][1]*a[0][1]*a[2][2] - a[0][0]*a[1][1]*a[2][2])outINV = [[sp.sympify(0) for i in range(4)] for j in range(4)]# First fill in the upper-triangle of the gPhysINV matrix...outINV[0][0] = (-a[1][3]*a[1][3]*a[2][2] + 2*a[1][2]*a[1][3]*a[2][3] - a[1][1]*a[2][3]*a[2][3] - a[1][2]*a[1][2]*a[3][3] + a[1][1]*a[2][2]*a[3][3])/outDEToutINV[1][1] = (-a[0][3]*a[0][3]*a[2][2] + 2*a[0][2]*a[0][3]*a[2][3] - a[0][0]*a[2][3]*a[2][3] - a[0][2]*a[0][2]*a[3][3] + a[0][0]*a[2][2]*a[3][3])/outDEToutINV[2][2] = (-a[0][3]*a[0][3]*a[1][1] + 2*a[0][1]*a[0][3]*a[1][3] - a[0][0]*a[1][3]*a[1][3] - a[0][1]*a[0][1]*a[3][3] + a[0][0]*a[1][1]*a[3][3])/outDEToutINV[3][3] = (-a[0][2]*a[0][2]*a[1][1] + 2*a[0][1]*a[0][2]*a[1][2] - a[0][0]*a[1][2]*a[1][2] - a[0][1]*a[0][1]*a[2][2] + a[0][0]*a[1][1]*a[2][2])/outDEToutINV[0][1] = (+a[0][3]*a[1][3]*a[2][2] - a[0][3]*a[1][2]*a[2][3] - a[0][2]*a[1][3]*a[2][3] + a[0][1]*a[2][3]*a[2][3] + a[0][2]*a[1][2]*a[3][3] - a[0][1]*a[2][2]*a[3][3])/outDEToutINV[0][2] = (-a[0][3]*a[1][2]*a[1][3] + a[0][2]*a[1][3]*a[1][3] + a[0][3]*a[1][1]*a[2][3] - a[0][1]*a[1][3]*a[2][3] - a[0][2]*a[1][1]*a[3][3] + a[0][1]*a[1][2]*a[3][3])/outDEToutINV[0][3] = (-a[0][2]*a[1][2]*a[1][3] + a[0][1]*a[1][3]*a[2][2] + a[0][3]*a[1][2]*a[1][2] - a[0][3]*a[1][1]*a[2][2] + a[0][2]*a[1][1]*a[2][3] - a[0][1]*a[1][2]*a[2][3])/outDEToutINV[1][2] = (+a[0][3]*a[0][3]*a[1][2] + a[0][0]*a[1][3]*a[2][3] - a[0][3]*a[0][2]*a[1][3] - a[0][3]*a[0][1]*a[2][3] + a[0][1]*a[0][2]*a[3][3] - a[0][0]*a[1][2]*a[3][3])/outDEToutINV[1][3] = (+a[0][2]*a[0][2]*a[1][3] + a[0][1]*a[0][3]*a[2][2] - a[0][0]*a[1][3]*a[2][2] + a[0][0]*a[1][2]*a[2][3] - a[0][2]*a[0][3]*a[1][2] - a[0][2]*a[0][1]*a[2][3])/outDEToutINV[2][3] = (+a[0][2]*a[0][3]*a[1][1] - a[0][1]*a[0][3]*a[1][2] - a[0][1]*a[0][2]*a[1][3] + a[0][0]*a[1][2]*a[1][3] + a[0][1]*a[0][1]*a[2][3] - a[0][0]*a[1][1]*a[2][3])/outDET# Then we fill the lower triangle of the symmetric matrixoutINV[1][0] = outINV[0][1]outINV[2][0] = outINV[0][2]outINV[2][1] = outINV[1][2]outINV[3][0] = outINV[0][3]outINV[3][1] = outINV[1][3]outINV[3][2] = outINV[2][3]return outINV, outDET# symmetry_optionPy's generic matrix inverter is highly inefficient for 3x3 matrices, so here we have an optimized version.def generic_matrix_inverter3x3(a):outDET = -a[0][2]*a[1][1]*a[2][0] + a[0][1]*a[1][2]*a[2][0] + \a[0][2]*a[1][0]*a[2][1] - a[0][0]*a[1][2]*a[2][1] - \a[0][1]*a[1][0]*a[2][2] + a[0][0]*a[1][1]*a[2][2]outINV = [[sp.sympify(0) for i in range(3)] for j in range(3)]outINV[0][0] = -a[1][2]*a[2][1] + a[1][1]*a[2][2]outINV[0][1] = a[0][2]*a[2][1] - a[0][1]*a[2][2]outINV[0][2] = -a[0][2]*a[1][1] + a[0][1]*a[1][2]outINV[1][0] = a[1][2]*a[2][0] - a[1][0]*a[2][2]outINV[1][1] = -a[0][2]*a[2][0] + a[0][0]*a[2][2]outINV[1][2] = a[0][2]*a[1][0] - a[0][0]*a[1][2]outINV[2][0] = -a[1][1]*a[2][0] + a[1][0]*a[2][1]outINV[2][1] = a[0][1]*a[2][0] - a[0][0]*a[2][1]outINV[2][2] = -a[0][1]*a[1][0] + a[0][0]*a[1][1]for i in range(3):for j in range(3):outINV[i][j] /= outDETreturn outINV, outDETdef generic_matrix_inverter4x4(a):# A = {{a00, a01, a02, a03},# {a10, a11, a12, a13},# {a20, a21, a22, a23},# {a30, a31, a32, a33}}# A // MatrixForm# CForm[FullSimplify[Det[A]]] >>> t2.txt# cat t2.txt | sed "s/ //g" |sed "s/ //g;s/\([0-3]\)/[\1]/g"outDET = a[0][1]*a[1][3]*a[2][2]*a[3][0]-a[0][1]*a[1][2]*a[2][3]*a[3][0]-a[0][0]*a[1][3]*a[2][2]*a[3][1]+ \a[0][0]*a[1][2]*a[2][3]*a[3][1]-a[0][1]*a[1][3]*a[2][0]*a[3][2]+a[0][0]*a[1][3]*a[2][1]*a[3][2]+ \a[0][1]*a[1][0]*a[2][3]*a[3][2]-a[0][0]*a[1][1]*a[2][3]*a[3][2]+ \a[0][3]*(a[1][2]*a[2][1]*a[3][0]-a[1][1]*a[2][2]*a[3][0]-a[1][2]*a[2][0]*a[3][1]+a[1][0]*a[2][2]*a[3][1]+a[1][1]*a[2][0]*a[3][2]-a[1][0]*a[2][1]*a[3][2])+ \(a[0][1]*a[1][2]*a[2][0]-a[0][0]*a[1][2]*a[2][1]-a[0][1]*a[1][0]*a[2][2]+a[0][0]*a[1][1]*a[2][2])*a[3][3]+\a[0][2]*(-(a[1][3]*a[2][1]*a[3][0])+a[1][1]*a[2][3]*a[3][0]+a[1][3]*a[2][0]*a[3][1]-a[1][0]*a[2][3]*a[3][1]-a[1][1]*a[2][0]*a[3][3]+a[1][0]*a[2][1]*a[3][3])outINV = [[sp.sympify(0) for i in range(4)] for j in range(4)]# CForm[FullSimplify[Inverse[A]*Det[A]]] >>> t.txt# cat t.txt | sed "s/,/\n/g;s/List(//g;s/))/)/g;s/)//g;s/(//g"|grep -v ^$|sed "s/ //g;s/\([0-3]\)/[\1]/g"| awk '{line[NR]=$0}END{count=1;for(i=0;i<4;i++) { for(j=0;j<4;j++) { printf "outINV[%d][%d] = %s\n", i,j,line[count];count++; }}}'outINV[0][0] = -a[1][3]*a[2][2]*a[3][1]+a[1][2]*a[2][3]*a[3][1]+a[1][3]*a[2][1]*a[3][2]-a[1][1]*a[2][3]*a[3][2]-a[1][2]*a[2][1]*a[3][3]+a[1][1]*a[2][2]*a[3][3]outINV[0][1] = a[0][3]*a[2][2]*a[3][1]-a[0][2]*a[2][3]*a[3][1]-a[0][3]*a[2][1]*a[3][2]+a[0][1]*a[2][3]*a[3][2]+a[0][2]*a[2][1]*a[3][3]-a[0][1]*a[2][2]*a[3][3]outINV[0][2] = -a[0][3]*a[1][2]*a[3][1]+a[0][2]*a[1][3]*a[3][1]+a[0][3]*a[1][1]*a[3][2]-a[0][1]*a[1][3]*a[3][2]-a[0][2]*a[1][1]*a[3][3]+a[0][1]*a[1][2]*a[3][3]outINV[0][3] = a[0][3]*a[1][2]*a[2][1]-a[0][2]*a[1][3]*a[2][1]-a[0][3]*a[1][1]*a[2][2]+a[0][1]*a[1][3]*a[2][2]+a[0][2]*a[1][1]*a[2][3]-a[0][1]*a[1][2]*a[2][3]outINV[1][0] = a[1][3]*a[2][2]*a[3][0]-a[1][2]*a[2][3]*a[3][0]-a[1][3]*a[2][0]*a[3][2]+a[1][0]*a[2][3]*a[3][2]+a[1][2]*a[2][0]*a[3][3]-a[1][0]*a[2][2]*a[3][3]outINV[1][1] = -a[0][3]*a[2][2]*a[3][0]+a[0][2]*a[2][3]*a[3][0]+a[0][3]*a[2][0]*a[3][2]-a[0][0]*a[2][3]*a[3][2]-a[0][2]*a[2][0]*a[3][3]+a[0][0]*a[2][2]*a[3][3]outINV[1][2] = a[0][3]*a[1][2]*a[3][0]-a[0][2]*a[1][3]*a[3][0]-a[0][3]*a[1][0]*a[3][2]+a[0][0]*a[1][3]*a[3][2]+a[0][2]*a[1][0]*a[3][3]-a[0][0]*a[1][2]*a[3][3]outINV[1][3] = -a[0][3]*a[1][2]*a[2][0]+a[0][2]*a[1][3]*a[2][0]+a[0][3]*a[1][0]*a[2][2]-a[0][0]*a[1][3]*a[2][2]-a[0][2]*a[1][0]*a[2][3]+a[0][0]*a[1][2]*a[2][3]outINV[2][0] = -a[1][3]*a[2][1]*a[3][0]+a[1][1]*a[2][3]*a[3][0]+a[1][3]*a[2][0]*a[3][1]-a[1][0]*a[2][3]*a[3][1]-a[1][1]*a[2][0]*a[3][3]+a[1][0]*a[2][1]*a[3][3]outINV[2][1] = a[0][3]*a[2][1]*a[3][0]-a[0][1]*a[2][3]*a[3][0]-a[0][3]*a[2][0]*a[3][1]+a[0][0]*a[2][3]*a[3][1]+a[0][1]*a[2][0]*a[3][3]-a[0][0]*a[2][1]*a[3][3]outINV[2][2] = -a[0][3]*a[1][1]*a[3][0]+a[0][1]*a[1][3]*a[3][0]+a[0][3]*a[1][0]*a[3][1]-a[0][0]*a[1][3]*a[3][1]-a[0][1]*a[1][0]*a[3][3]+a[0][0]*a[1][1]*a[3][3]outINV[2][3] = a[0][3]*a[1][1]*a[2][0]-a[0][1]*a[1][3]*a[2][0]-a[0][3]*a[1][0]*a[2][1]+a[0][0]*a[1][3]*a[2][1]+a[0][1]*a[1][0]*a[2][3]-a[0][0]*a[1][1]*a[2][3]outINV[3][0] = a[1][2]*a[2][1]*a[3][0]-a[1][1]*a[2][2]*a[3][0]-a[1][2]*a[2][0]*a[3][1]+a[1][0]*a[2][2]*a[3][1]+a[1][1]*a[2][0]*a[3][2]-a[1][0]*a[2][1]*a[3][2]outINV[3][1] = -a[0][2]*a[2][1]*a[3][0]+a[0][1]*a[2][2]*a[3][0]+a[0][2]*a[2][0]*a[3][1]-a[0][0]*a[2][2]*a[3][1]-a[0][1]*a[2][0]*a[3][2]+a[0][0]*a[2][1]*a[3][2]outINV[3][2] = a[0][2]*a[1][1]*a[3][0]-a[0][1]*a[1][2]*a[3][0]-a[0][2]*a[1][0]*a[3][1]+a[0][0]*a[1][2]*a[3][1]+a[0][1]*a[1][0]*a[3][2]-a[0][0]*a[1][1]*a[3][2]outINV[3][3] = -a[0][2]*a[1][1]*a[2][0]+a[0][1]*a[1][2]*a[2][0]+a[0][2]*a[1][0]*a[2][1]-a[0][0]*a[1][2]*a[2][1]-a[0][1]*a[1][0]*a[2][2]+a[0][0]*a[1][1]*a[2][2]for mu in range(4):for nu in range(4):outINV[mu][nu] /= outDETreturn outINV, outDET
# This module contains infrastructure for generating# C-code loops of arbitrary dimension# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* comimport sys # Standard Python modules for multiplatform OS-level functions# loop1D() is just a special case of loop(), and in fact is called by loop().# For documentation on the inputs, see loop()'s documentation below.def loop1D(idxvar="i0",lower="0",upper="Nx0",incr="1",OpenMPpragma="#pragma omp parallel for",tabprefix=""):if not (isinstance(idxvar, str) and isinstance(lower, str) andisinstance(upper, str) and isinstance(incr, str) and isinstance(OpenMPpragma, str)):print("Error: all inputs to loop1D() must be STRINGS, and to loop() must be LISTS OF STRINGS")sys.exit(1)OMPheader = ""if OpenMPpragma != "":OMPheader = OpenMPpragma + "\n"incrstr = "++"if incr != "1":incrstr = "+="+incrloopbody = tabprefix+"for(int "+idxvar+"="+lower+"; "+idxvar+"<"+upper+"; "+idxvar+incrstr+")"return OMPheader+loopbody+" {\n", tabprefix+"} // END LOOP: "+loopbody.replace(tabprefix,"")+"\n"# loop() creates a C code loop, taking as input:# idxvar (string or list of strings): the index variable name or list of names.# In the case that idxvar is a list of N strings, we adopt the formulation:# idxvar[0]=outermost loop variable# idxvar[N-1]=innermost loop variable# lower (string or list of strings): lower loop index of idxvar or idxvar[i].# See definition of "idxvar" if lower is a list of strings.# idxvar[] must have the same length as idxvar.# upper (string or list of strings): Defined similarly to "lower", except# this refers to the *upper* loop index of idxvar or idxvar[i].# incr (string or list of strings): Defined similarly to "lower", except# this refers to the loop increment of idxvar or idxvar[i]# (incr[i] = 1 -> idxvar++)# OpenMPpragma (string or list of strings): Defined similarly to "lower", except# this refers to the OpenMP pragma corresponding to idxvar or idxvar[i].# tabprefix (optional; string): Sets the tab stop for the C code.# loopguts (optional; string): The loop interior.## Example: loop(["i0","i1"],["0","5"],["N","N-5"],["1","5"],["#pragma omp parallel for",""],# "double a=-2;\n gf[IDX3(GF,i0,i1)]=-2*a;\n"])# Output:# #pragma omp parallel for# for(int i0=0;i0<N;i0++) {# for(int i1=5;i1<N-5;i1+=5) {# a=-2;# gf[IDX3(GF,i0,i1)]=-2*a;# } // END LOOP: for(int i1=5;i1<N-5;i1+=5)# } // END LOOP: for(int i0=0;i0<N;i0++)def loop(idxvar,lower,upper,incr,OpenMPpragma,tabprefix="",loopguts=""):# Step 1: Check and/or clean input.# Step 1a: If only strings are passed, then create lists out of them:if (isinstance(idxvar,str) and isinstance(lower,str) andisinstance(upper, str) and isinstance(incr, str) and isinstance(OpenMPpragma, str)):idxvar = [idxvar]lower = [lower]upper = [upper]incr = [incr]OpenMPpragma = [OpenMPpragma]# Step 1b: At this point all inputs should be lists. If they are not, then exit.if not (isinstance(idxvar,list) and isinstance(lower,list) andisinstance(upper, list) and isinstance(incr, list) and isinstance(OpenMPpragma, list)):print("Error: loop(idxvar,lower,upper,incr,OpenMPpragma) requires all inputs be lists")sys.exit(1)# Step 1c: At this point all inputs should be lists. If they are not the same length, then exit.if len(idxvar) != len(lower) or len(lower) != len(upper) or len(upper) != len(incr) or len(incr) != len(OpenMPpragma):print("Error: loop(idxvar,lower,upper,incr,OpenMPpragma) requires all inputs be lists OF THE SAME LENGTH")sys.exit(1)# Step 2: tabprefix will be set according to the loop nesting, so the loop has proper tabination;# one tab for each nesting of the loop.# Step 3: header will be the top of the loopheader = ""# Step 4: footerarrayfooterarray = []for i in range(len(idxvar)):headerstr,footerstr = loop1D(idxvar[i],lower[i],upper[i],incr[i],OpenMPpragma[i],tabprefix)header += headerstrfooterarray.append(footerstr)tabprefix += " "loopgutsout = ""if loopguts != "":loopgutsarray = loopguts.split("\n")for line in loopgutsarray:loopgutsout += tabprefix+line+"\n"footer = ""for i in range(len(idxvar)-1,-1,-1):footer += footerarray[i]if loopguts == "":return header,footerreturn header+loopgutsout+footer# Automatic generation of C-code loops around an arbitrarily# defined loop body.def simple_loop(loopopts, body):if loopopts == "":return bodyif "AllPoints" in loopopts:i2i1i0_mins = ["0", "0", "0"]i2i1i0_maxs = ["Nxx_plus_2NGHOSTS2", "Nxx_plus_2NGHOSTS1", "Nxx_plus_2NGHOSTS0"]if "oldloops" in loopopts:i2i1i0_maxs = ["Nxx_plus_2NGHOSTS[2]", "Nxx_plus_2NGHOSTS[1]", "Nxx_plus_2NGHOSTS[0]"]elif "InteriorPoints" in loopopts:i2i1i0_mins = ["NGHOSTS","NGHOSTS","NGHOSTS"]i2i1i0_maxs = ["NGHOSTS+Nxx2","NGHOSTS+Nxx1","NGHOSTS+Nxx0"]if "oldloops" in loopopts:i2i1i0_maxs = ["NGHOSTS+Nxx[2]", "NGHOSTS+Nxx[1]", "NGHOSTS+Nxx[0]"]else:print("Error: loopopts given, but no points over which to loop were specified.")sys.exit(1)Read_1Darrays = ["", "", ""]if "Read_xxs" in loopopts:if not "EnableSIMD" in loopopts:Read_1Darrays = ["const REAL xx0 = xx[0][i0];"," const REAL xx1 = xx[1][i1];"," const REAL xx2 = xx[2][i2];", ]else:print("Error: No SIMD support on Read_xxs yet.")sys.exit(1)if "Enable_rfm_precompute" in loopopts:if "Read_xxs" in loopopts:print("Error: Enable_rfm_precompute and Read_xxs cannot both be enabled.")sys.exit(1)if "EnableSIMD" in loopopts:Read_1Darrays = ["#include \"rfm_files/rfm_struct__SIMD_inner_read0.h\"","#include \"rfm_files/rfm_struct__SIMD_outer_read1.h\"","#include \"rfm_files/rfm_struct__SIMD_outer_read2.h\""]else:Read_1Darrays = ["#include \"rfm_files/rfm_struct__read0.h\"","#include \"rfm_files/rfm_struct__read1.h\"","#include \"rfm_files/rfm_struct__read2.h\""]OpenMPpragma = "#pragma omp parallel for"if "DisableOpenMP" in loopopts:OpenMPpragma = ""loopincrements = ["1","1","1"]if "EnableSIMD" in loopopts:loopincrements = ["1", "1", "SIMD_width"]return loop(["i2","i1","i0"],i2i1i0_mins,i2i1i0_maxs,loopincrements,[OpenMPpragma,Read_1Darrays[2],Read_1Darrays[1]],tabprefix=" ",loopguts = Read_1Darrays[0]+"\n"+body)#loopheader,loopfooter = loop(idxvar=["i0","i1"],lower=["0","0"],upper=["Nx0","Nx1"],incr=["1","1"],# OpenMPpragma=["", "#pragma omp parallel for"])#loopheader,loopfooter = loop(idxvar=["i0","i1"],lower=["0","0"],upper=["Nx0","Nx1"],incr=["1","1"],# OpenMPpragma=["", "#pragma omp parallel for"])#print(loopheader+loopfooter)
# As documented in the NRPy+ tutorial module# Tutorial-Coutput__Parameter_Interface.ipynb# this core NRPy+ module is used for# generating C code and functions.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* comimport loop as lp # NRPy+: C code loop interfaceimport NRPy_param_funcs as par # NRPy+: parameter interfacefrom SIMD import expr_convert_to_SIMD_intrins # NRPy+: SymPy expression => SIMD intrinsics interfaceimport sympy as sp # Import SymPyimport re, sys # Standard Python: regular expressions & OS-independent system functionsfrom collections import namedtuple # Standard Python: Enable namedtuple data typelhrh = namedtuple('lhrh', 'lhs rhs')outCparams = namedtuple('outCparams', 'preindent includebraces declareoutputvars outCfileaccess outCverbose CSE_enable CSE_varprefix SIMD_enable SIMD_const_suffix SIMD_debug enable_TYPE')# Sometimes SymPy has problems evaluating complicated expressions involving absolute# values, resulting in hangs. So instead of using sp.Abs(), if we instead use# nrpyAbs, we can sidestep the internal SymPy evaluation and force the C# codegen to output our desired fabs().nrpyAbs = sp.Function('nrpyAbs')custom_functions_for_SymPy_ccode = {"nrpyAbs": "fabs",'Pow': [(lambda b, e: e == 0.5, lambda b, e: 'sqrt(%s)' % (b)),(lambda b, e: e ==-0.5, lambda b, e: '(1.0/sqrt(%s))' % (b)),(lambda b, e: e == sp.S.One/3, lambda b, e: 'cbrt(%s)' % (b)),(lambda b, e: e ==-sp.S.One/3, lambda b, e: '(1.0/cbrt(%s))' % (b)),(lambda b, e: e == 2, lambda b, e: '((%s)*(%s))' % (b,b)),(lambda b, e: e == 3, lambda b, e: '((%s)*(%s)*(%s))' % (b,b,b)),(lambda b, e: e == 4, lambda b, e: '((%s)*(%s)*(%s)*(%s))' % (b,b,b,b)),(lambda b, e: e == 5, lambda b, e: '((%s)*(%s)*(%s)*(%s)*(%s))' % (b,b,b,b,b)),(lambda b, e: e ==-1, lambda b, e: '(1.0/(%s))' % (b)),(lambda b, e: e ==-2, lambda b, e: '(1.0/((%s)*(%s)))' % (b,b)),(lambda b, e: e ==-3, lambda b, e: '(1.0/((%s)*(%s)*(%s)))' % (b,b,b)),(lambda b, e: e ==-4, lambda b, e: '(1.0/((%s)*(%s)*(%s)*(%s)))' % (b,b,b,b)),(lambda b, e: e ==-5, lambda b, e: '(1.0/((%s)*(%s)*(%s)*(%s)*(%s)))' % (b,b,b,b,b)),(lambda b, e: e !=-5, 'pow')]## (lambda b, e: e != 2, 'pow')]}# Parameter initialization is called once, within nrpy.py.par.initialize_param(par.glb_param("char", __name__, "PRECISION", "double")) # __name__ = "outputC", this module's name.# par.initialize_param(par.glb_param("bool", thismodule, "SIMD_enable", False))# super fast 'uniq' function:# f8() function from https://www.peterbe.com/plog/uniqifiers-benchmarkdef superfast_uniq(seq): # Author: Dave Kirby# Order preservingseen = set()return [x for x in seq if x not in seen and not seen.add(x)]def check_if_string__error_if_not(allegedstring,stringdesc):import sysif sys.version_info[0] == 3:string_types = strelse:string_types = basestringif not isinstance(allegedstring, string_types):print("ERROR: "+str(stringdesc)+" =="+str(allegedstring)+" not a string!")sys.exit(1)def ccode_postproc(string):PRECISION = par.parval_from_str("PRECISION")# In the C math library, e.g., pow(x,y) assumes x and y are doubles, and returns a double.# If x and y are floats, then for consistency should use powf(x,y) instead.# Similarly, in the case of x and y being long doubles, should use powl(x,y) for consistency.# First we find the appropriate suffix depending on the desired precision:cmathsuffix = ""if PRECISION == "double":passelif PRECISION == "long double":cmathsuffix = "l"elif PRECISION == "float":cmathsuffix = "f"else:print("Error: "+__name__+"::PRECISION = \""+ PRECISION +"\" not supported")sys.exit(1)# ... then we append the above suffix to standard C math library functions:for func in ['pow', 'sqrt', 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'exp', 'log', 'fabs']:string2 = re.sub(func+r'\(', func + cmathsuffix+"(", string); string = string2# Finally, SymPy prefers to output Rationals as long-double fractions.# E.g., Rational(1,3) is output as 1.0L/3.0L.# The Intel compiler vectorizer complains miserably about this,# and strictly speaking it is useless when we're in double precision.# So here we get rid of the "L" suffix on floating point numbers:if PRECISION!="long double":string2 = re.sub(r'([0-9.]+)L/([0-9.]+)L', '(\\1 / \\2)', string); string = string2return stringdef parse_outCparams_string(params):# Default values:preindent = ""includebraces = "True"declareoutputvars = "False"outCfileaccess = "w"outCverbose = "True"CSE_enable = "True"CSE_varprefix = "tmp"SIMD_enable = "False"SIMD_const_suffix = ""SIMD_debug = "False"enable_TYPE = "True"if params != "":params2 = re.sub("^,","",params)params = params2.strip()splitstring = re.split("=|,", params)if len(splitstring) % 2 != 0:print("outputC: Invalid params string: "+params)sys.exit(1)parnm = []value = []for i in range(int(len(splitstring)/2)):parnm.append(splitstring[2*i])value.append(splitstring[2*i+1])for i in range(len(parnm)):# Clean the stringif value[i] == "true":value[i] = "True"if value[i] == "false":value[i] = "False"if parnm[i] == "preindent":if not value[i].isdigit():print("Error: preindent must be set to an integer (corresponding to the number of tab stops). ")print(value[i]+" is not an integer.")sys.exit(1)preindent = ""for i in range(int(value[i])):preindent += " "elif parnm[i] == "includebraces":includebraces = value[i]elif parnm[i] == "declareoutputvars":declareoutputvars = value[i]elif parnm[i] == "outCfileaccess":outCfileaccess = value[i]elif parnm[i] == "outCverbose":outCverbose = value[i]elif parnm[i] == "CSE_enable":CSE_enable = value[i]elif parnm[i] == "CSE_varprefix":CSE_varprefix = value[i]elif parnm[i] == "SIMD_enable":SIMD_enable = value[i]elif parnm[i] == "SIMD_const_suffix":SIMD_const_suffix = value[i]elif parnm[i] == "SIMD_debug":SIMD_debug = value[i]elif parnm[i] == "enable_TYPE":enable_TYPE = value[i]else:print("Error: outputC parameter name \""+parnm[i]+"\" unrecognized.")sys.exit(1)return outCparams(preindent,includebraces,declareoutputvars,outCfileaccess,outCverbose,CSE_enable,CSE_varprefix,SIMD_enable,SIMD_const_suffix,SIMD_debug,enable_TYPE)import sympy as sp# Input: sympyexpr = a single SymPy expression *or* a list of SymPy expressions# output_varname_str = a single output variable name *or* a list of output# variable names, one per sympyexpr.# Output: C code, as a string.def outputC(sympyexpr, output_varname_str, filename = "stdout", params = "", prestring = "", poststring = ""):outCparams = parse_outCparams_string(params)preindent = outCparams.preindentTYPE = par.parval_from_str("PRECISION")if outCparams.enable_TYPE == "False":TYPE = ""# Step 0: Initialize# commentblock: comment block containing the input SymPy string,# set only if outCverbose==True# outstring: the output C code stringcommentblock = ""outstring = ""# Step 1: If SIMD_enable==True, then check if TYPE=="double". If not, error out.# Otherwise set TYPE="REAL_SIMD_ARRAY", which should be #define'd# within the C code. For example for AVX-256, the C code should have# #define REAL_SIMD_ARRAY __m256dif outCparams.SIMD_enable == "True":if not (TYPE == "double" or TYPE == ""):print("SIMD output currently only supports double precision or typeless. Sorry!")sys.exit(1)if TYPE == "double":TYPE = "REAL_SIMD_ARRAY"else:TYPE = ""# Step 2a: Apply sanity checks when either sympyexpr or# output_varname_str is a list.if type(output_varname_str) is list and type(sympyexpr) is not list:print("Error: Provided a list of output variable names, but only one SymPy expression.")sys.exit(1)if type(sympyexpr) is list:if type(output_varname_str) is not list:print("Error: Provided a list of SymPy expressions, but no corresponding list of output variable names")sys.exit(1)elif len(output_varname_str) != len(sympyexpr):print("Error: Length of SymPy expressions list ("+str(len(sympyexpr))+") != Length of corresponding output variable name list ("+str(len(output_varname_str))+")")sys.exit(1)# Step 2b: If sympyexpr and output_varname_str are not lists,# convert them to lists of one element each, to# simplify proceeding code.if type(output_varname_str) is not list and type(sympyexpr) is not list:output_varname_strtmp = [output_varname_str]output_varname_str = output_varname_strtmpsympyexprtmp = [sympyexpr]sympyexpr = sympyexprtmp# Step 3: If outCparams.verbose = True, then output the original SymPy# expression(s) in code comments prior to actual C codeif outCparams.outCverbose == "True":commentblock += preindent+"/*\n"+preindent+" * Original SymPy expression"if len(output_varname_str)>1:commentblock += "s"commentblock += ":\n"for i in range(len(output_varname_str)):if i==0:if len(output_varname_str)!=1:commentblock += preindent+" * \"["else:commentblock += preindent+" * \""else:commentblock += preindent+" * "commentblock += output_varname_str[i] + " = " + str(sympyexpr[i])if i==len(output_varname_str)-1:if len(output_varname_str)!=1:commentblock += "]\"\n"else:commentblock += "\"\n"else:commentblock += ",\n"commentblock += preindent+" */\n"# Step 4: Add proper indentation of C code:if outCparams.includebraces == "True":indent = outCparams.preindent+" "else:indent = outCparams.preindent+""# Step 5: Should the output variable, e.g., outvar, be declared?# If so, start output line with e.g., "double outvar "outtypestring = ""if outCparams.declareoutputvars == "True":outtypestring = outCparams.preindent+indent+TYPE + " "else:outtypestring = outCparams.preindent+indent# Step 6a: If common subexpression elimination (CSE) disabled, then# just output the SymPy string in the most boring way,# nearly consistent with SymPy's ccode() function,# though with support for float & long double types# as well.SIMD_decls = ""if outCparams.CSE_enable == "False":# If CSE is disabled:for i in range(len(sympyexpr)):outstring += outtypestring + ccode_postproc(sp.ccode(sympyexpr[i], output_varname_str[i],user_functions=custom_functions_for_SymPy_ccode))+"\n"# Step 6b: If CSE enabled, then perform CSE using SymPy and then# resulting C code.else:# If CSE is enabled:SIMD_const_varnms = []SIMD_const_values = []CSE_results = sp.cse(sympyexpr, sp.numbered_symbols(outCparams.CSE_varprefix), order='canonical')for commonsubexpression in CSE_results[0]:FULLTYPESTRING = "const " + TYPE + " "if outCparams.enable_TYPE == "False":FULLTYPESTRING = ""if outCparams.SIMD_enable == "True":outstring += outCparams.preindent + indent + FULLTYPESTRING + str(commonsubexpression[0]) + " = " + \str(expr_convert_to_SIMD_intrins(commonsubexpression[1],SIMD_const_varnms,SIMD_const_values,outCparams.SIMD_const_suffix,outCparams.SIMD_debug)) + ";\n"else:outstring += outCparams.preindent+indent+FULLTYPESTRING+ccode_postproc(sp.ccode(commonsubexpression[1],commonsubexpression[0],user_functions=custom_functions_for_SymPy_ccode))+"\n"for i,result in enumerate(CSE_results[1]):if outCparams.SIMD_enable == "True":outstring += outtypestring + output_varname_str[i] + " = " + \str(expr_convert_to_SIMD_intrins(result,SIMD_const_varnms,SIMD_const_values,outCparams.SIMD_const_suffix,outCparams.SIMD_debug)) + ";\n"else:outstring += outtypestring+ccode_postproc(sp.ccode(result,output_varname_str[i],user_functions=custom_functions_for_SymPy_ccode))+"\n"# Step 6b.i: If SIMD_enable == True , and# there is at least one SIMD const variable,# then declare the SIMD_const_varnms and SIMD_const_values arraysif outCparams.SIMD_enable == "True" and len(SIMD_const_varnms) != 0:# Step 6a) Sort the list of definitions. Idea from:# https://stackoverflow.com/questions/9764298/is-it-possible-to-sort-two-listswhich-reference-each-other-in-the-exact-same-wSIMD_const_varnms, SIMD_const_values = \(list(t) for t in zip(*sorted(zip(SIMD_const_varnms, SIMD_const_values))))# Step 6b) Remove duplicatesuniq_varnms = superfast_uniq(SIMD_const_varnms)uniq_values = superfast_uniq(SIMD_const_values)SIMD_const_varnms = uniq_varnmsSIMD_const_values = uniq_valuesif len(SIMD_const_varnms) != len(SIMD_const_values):print("Error: SIMD constant declaration arrays SIMD_const_varnms[] and SIMD_const_values[] have inconsistent sizes!")sys.exit(1)for i in range(len(SIMD_const_varnms)):if outCparams.enable_TYPE == "False":SIMD_decls += outCparams.preindent + indent + SIMD_const_varnms[i] + " = " + SIMD_const_values[i]+";"else:SIMD_decls += outCparams.preindent + indent + "const double " + outCparams.CSE_varprefix + SIMD_const_varnms[i] + " = " + SIMD_const_values[i] + ";\n"SIMD_decls += outCparams.preindent+indent+ "const REAL_SIMD_ARRAY " + SIMD_const_varnms[i] + " = ConstSIMD("+ outCparams.CSE_varprefix + SIMD_const_varnms[i] + ");\n"SIMD_decls += "\n"# Step 7: Construct final output stringfinal_Ccode_output_str = commentblock# Step 7a: Output C code in indented curly brackets if# outCparams.includebraces = Trueif outCparams.includebraces == "True": final_Ccode_output_str += outCparams.preindent+"{\n"final_Ccode_output_str += prestring + SIMD_decls + outstring + poststringif outCparams.includebraces == "True": final_Ccode_output_str += outCparams.preindent+"}\n"# Step 8: If filename == "stdout", then output# C code to standard out (useful for copy-paste or interactive# mode). Otherwise output to file specified in variable name.if filename == "stdout":# Output to standard out (stdout; "the screen")print(final_Ccode_output_str)elif filename == "returnstring":return final_Ccode_output_strelse:# Output to the file specified by the function input parameter string 'filename':with open(filename, outCparams.outCfileaccess) as file:file.write(final_Ccode_output_str)successstr = ""if outCparams.outCfileaccess == "a":successstr = "Appended "elif outCparams.outCfileaccess == "w":successstr = "Wrote "print(successstr + "to file \"" + filename + "\"")outC_function_prototype_dict = {}outC_function_dict = {}def Cfunction(desc="",type="void",name=None,params=None,preloop="",body=None,loopopts="",postloop="",opts=""):if name == None or params == None or body == None:print("Cfunction() error: strings must be provided for function name, parameters, and body")sys.exit(1)func_prototype = type+" "+name+"("+params+")"include_Cparams_str = ""if not "DisableCparameters" in opts:if "EnableSIMD" in loopopts:include_Cparams_str = "#include \"set_Cparameters-SIMD.h\"\n"else:include_Cparams_str = "#include \"set_Cparameters.h\"\n"complete_func = ""if desc != "":complete_func = "/*\n" + desc + "\n */\n"complete_func += func_prototype + " {\n"+include_Cparams_str+preloop+"\n"+lp.simple_loop(loopopts,body)+postloop+"}\n"return func_prototype+";",complete_funcdef add_to_Cfunction_dict(desc="",type="void",name=None,params=None,preloop="",body=None,loopopts="",postloop="",opts=""):outC_function_prototype_dict[name],outC_function_dict[name] = Cfunction(desc,type,name,params,preloop,body,loopopts,postloop,opts)def outCfunction(outfile="",desc="",type="void",name=None,params=None,preloop="",body=None,loopopts="",postloop="",opts=""):ignoreprototype,Cfunc = Cfunction(desc,type,name,params,preloop,body,loopopts,postloop,opts)if outfile == "returnstring":return Cfuncwith open(outfile,"w") as file:file.write(Cfunc)print("Output C function "+name+"() to file "+outfile)
# reference_metric.py: Define all needed quantities# for a reference metric.# Given uniform (reference metric) coordinate# (xx[0],xx[1],xx[2]), you must define:# 1) xxmin[3],xxmax[3]: Valid ranges for each# uniform coordinate xx0,xx1,xx2# 2) xxSph[3]: Spherical coordinate (r,theta,phi),# in terms of uniform coordinate xx0,xx1,xx2# 3) xxCart[3]: Cartesian coordinate (x,y,z),# in terms of uniform coordinate xx0,xx1,xx2# 4) scalefactor_orthog:# orthogonal coordinate scale factor# (positive root of diagonal reference metric# components)# 5) Cart_to_xx[3]: Inverse of xxCart:# xx0,xx1,xx2 as functions of (x,y,z).# In the case that there exists no closed-form# expression, then a root finder might be needed# 6) UnitVectors[3][3]: Unit vectors of reference# metric.# Author: Zachariah B. Etienne# zachetie **at** gmail **dot* comimport sympy as sp # Import SymPyfrom outputC import outputC,superfast_uniq,outC_function_dict,add_to_Cfunction_dict # NRPy+: Core C code output moduleimport NRPy_param_funcs as par # NRPy+: Parameter interfaceimport grid as gri # NRPy+: Functions having to do with numerical gridsimport indexedexp as ixp # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) supportimport sys # Standard Python modules for multiplatform OS-level functions# Step 0a: Initialize parametersthismodule = __name__par.initialize_param(par.glb_param("char", thismodule, "CoordSystem", "Spherical"))par.initialize_param(par.glb_param("char", thismodule, "enable_rfm_precompute", "False"))par.initialize_param(par.glb_param("char", thismodule, "rfm_precompute_Ccode_outdir", "Ccode"))# Step 0b: Declare global variablesxx = gri.xxxxCart = ixp.zerorank1(DIM=4) # Must be set in terms of xx[]sCart_to_xx = ixp.zerorank1(DIM=4) # Must be set in terms of xx[]sCartx,Carty,Cartz = sp.symbols("Cartx Carty Cartz", real=True)Cart = [Cartx,Carty,Cartz]xxSph = ixp.zerorank1(DIM=4) # Must be set in terms of xx[]sscalefactor_orthog = ixp.zerorank1(DIM=4) # Must be set in terms of xx[]sscalefactor_orthog_funcform = ixp.zerorank1(DIM=4) # Must be set in terms of generic functions of xx[]shave_already_called_reference_metric_function = Falsedef reference_metric(SymPySimplifyExpressions=True):global f0_of_xx0_funcform, f1_of_xx1_funcform, f2_of_xx0_xx1_funcform, f3_of_xx0_funcform, f4_of_xx2_funcformglobal f0_of_xx0, f1_of_xx1, f2_of_xx0_xx1, f3_of_xx0, f4_of_xx2f0_of_xx0_funcform = sp.Function('f0_of_xx0_funcform')(xx[0])f1_of_xx1_funcform = sp.Function('f1_of_xx1_funcform')(xx[1])f2_of_xx0_xx1_funcform = sp.Function('f2_of_xx0_xx1_funcform')(xx[0], xx[1])f3_of_xx0_funcform = sp.Function('f3_of_xx0_funcform')(xx[0])f4_of_xx2_funcform = sp.Function('f4_of_xx2_funcform')(xx[2])f0_of_xx0, f1_of_xx1, f2_of_xx0_xx1, f3_of_xx0, f4_of_xx2 = par.Cparameters("REAL", thismodule,["f0_of_xx0", "f1_of_xx1", "f2_of_xx0_xx1", "f3_of_xx0", "f4_of_xx2"], 1e300)# FIXME: Hackf0_of_xx0__D0, f0_of_xx0__DD00, f0_of_xx0__DDD000 = par.Cparameters("REAL", thismodule,["f0_of_xx0__D0", "f0_of_xx0__DD00","f0_of_xx0__DDD000"], 1e300)f1_of_xx1__D1, f1_of_xx1__DD11, f1_of_xx1__DDD111 = par.Cparameters("REAL", thismodule,["f1_of_xx1__D1", "f1_of_xx1__DD11","f1_of_xx1__DDD111"], 1e300)f2_of_xx0_xx1__D0,f2_of_xx0_xx1__D1,f2_of_xx0_xx1__DD00,f2_of_xx0_xx1__DD11 = \par.Cparameters("REAL", thismodule,["f2_of_xx0_xx1__D0","f2_of_xx0_xx1__D1","f2_of_xx0_xx1__DD00","f2_of_xx0_xx1__DD11"],1e300)f3_of_xx0__D0,f3_of_xx0__DD00 = par.Cparameters("REAL", thismodule,["f3_of_xx0__D0","f3_of_xx0__DD00"], 1e300)f4_of_xx2__D2,f4_of_xx2__DD22 = par.Cparameters("REAL", thismodule,["f4_of_xx2__D2","f4_of_xx2__DD22"], 1e300)global have_already_called_reference_metric_function # setting to global enables other modules to see updated value.have_already_called_reference_metric_function = TrueCoordSystem = par.parval_from_str("reference_metric::CoordSystem")M_PI,M_SQRT1_2 = par.Cparameters("#define",thismodule,["M_PI","M_SQRT1_2"],"")global xxminglobal xxmaxglobal UnitVectorsUnitVectors = ixp.zerorank2(DIM=3)# Set up hatted metric tensor, rescaling matrix, and rescaling vector###################################################################### SPHERICAL-LIKE COORDINATE SYSTEMS WITH & WITHOUT RADIAL RESCALING ######################################################################if CoordSystem == "Spherical" or CoordSystem == "SinhSpherical" or CoordSystem == "SinhSphericalv2":# Adding assumption real=True can help simplify expressions involving xx[0] & xx[1] below.xx[0] = sp.symbols("xx0", real=True)xx[1] = sp.symbols("xx1", real=True)if CoordSystem == "Spherical":RMAX = par.Cparameters("REAL", thismodule, ["RMAX"],10.0)xxmin = [sp.sympify(0), sp.sympify(0), -M_PI]xxmax = [ RMAX, M_PI, M_PI]r = xx[0]th = xx[1]ph = xx[2]Cart_to_xx[0] = sp.sqrt(Cartx ** 2 + Carty ** 2 + Cartz ** 2)Cart_to_xx[1] = sp.acos(Cartz / Cart_to_xx[0])Cart_to_xx[2] = sp.atan2(Carty, Cartx)elif CoordSystem == "SinhSpherical":xxmin = [sp.sympify(0), sp.sympify(0), -M_PI]xxmax = [sp.sympify(1), M_PI, M_PI]AMPL, SINHW = par.Cparameters("REAL",thismodule,["AMPL","SINHW"],[10.0,0.2])# Set SinhSpherical radial coordinate by default; overwrite later if CoordSystem == "SinhSphericalv2".r = AMPL * (sp.exp(xx[0] / SINHW) - sp.exp(-xx[0] / SINHW)) / \(sp.exp(1 / SINHW) - sp.exp(-1 / SINHW))th = xx[1]ph = xx[2]Cart_to_xx[0] = SINHW*sp.asinh(sp.sqrt(Cartx ** 2 + Carty ** 2 + Cartz ** 2)*sp.sinh(1/SINHW)/AMPL)Cart_to_xx[1] = sp.acos(Cartz / sp.sqrt(Cartx ** 2 + Carty ** 2 + Cartz ** 2))Cart_to_xx[2] = sp.atan2(Carty, Cartx)# SinhSphericalv2 adds the parameter "const_dr", which allows for a region near xx[0]=0 to have# constant radial resolution of const_dr, provided the sinh() term does not dominate near xx[0]=0.elif CoordSystem == "SinhSphericalv2":xxmin = [sp.sympify(0), sp.sympify(0), -M_PI]xxmax = [sp.sympify(1), M_PI, M_PI]AMPL, SINHW = par.Cparameters("REAL",thismodule,["AMPL","SINHW"],[10.0,0.2])const_dr = par.Cparameters("REAL",thismodule,["const_dr"],0.0625)r = AMPL*( const_dr*xx[0] + (sp.exp(xx[0] / SINHW) - sp.exp(-xx[0] / SINHW)) /(sp.exp(1 / SINHW) - sp.exp(-1 / SINHW)) )th = xx[1]ph = xx[2]# NO CLOSED-FORM EXPRESSION FOR RADIAL INVERSION.# Cart_to_xx[0] = "NewtonRaphson"# Cart_to_xx[1] = sp.acos(Cartz / sp.sqrt(Cartx ** 2 + Carty ** 2 + Cartz ** 2))# Cart_to_xx[2] = sp.atan2(Carty, Cartx)xxSph[0] = rxxSph[1] = thxxSph[2] = ph# Now define xCart, yCart, and zCart in terms of x0,xx[1],xx[2].# Note that the relation between r and x0 is not necessarily trivial in SinhSpherical coordinates. See above.xxCart[0] = xxSph[0]*sp.sin(xxSph[1])*sp.cos(xxSph[2])xxCart[1] = xxSph[0]*sp.sin(xxSph[1])*sp.sin(xxSph[2])xxCart[2] = xxSph[0]*sp.cos(xxSph[1])scalefactor_orthog[0] = sp.diff(xxSph[0],xx[0])scalefactor_orthog[1] = xxSph[0]scalefactor_orthog[2] = xxSph[0]*sp.sin(xxSph[1])f0_of_xx0 = xxSph[0]f1_of_xx1 = sp.sin(xxSph[1])scalefactor_orthog_funcform[0] = sp.diff(f0_of_xx0_funcform,xx[0])scalefactor_orthog_funcform[1] = f0_of_xx0_funcformscalefactor_orthog_funcform[2] = f0_of_xx0_funcform*f1_of_xx1_funcform# Set the unit vectorsUnitVectors = [[ sp.sin(xxSph[1])*sp.cos(xxSph[2]), sp.sin(xxSph[1])*sp.sin(xxSph[2]), sp.cos(xxSph[1])],[ sp.cos(xxSph[1])*sp.cos(xxSph[2]), sp.cos(xxSph[1])*sp.sin(xxSph[2]), -sp.sin(xxSph[1])],[ -sp.sin(xxSph[2]), sp.cos(xxSph[2]), sp.sympify(0) ]]####################################################################### SPHERICAL-LIKE COORDINATE SYSTEMS WITH RADIAL AND THETA RESCALINGS #######################################################################elif CoordSystem == "NobleSphericalThetaOptionOne" or CoordSystem == "NobleSphericalThetaOptionTwo":# WARNING: CANNOT BE USED FOR SENR RUNS;# THESE DO NOT DEFINE xxmin, xxmax, Cart_to_xx# ALSO THE RADIAL RESCALINGS ARE NOT ODD FUNCTIONS OF xx0,# MEANING THAT CURVI. BOUNDARY CONDITIONS WILL NOT WORK.Rin,R0 = par.Cparameters("REAL", thismodule, ["Rin","R0"],[1.08986052555408,0.0])x0beg = sp.log(Rin-R0)xx[0] = sp.symbols("xx0", real=True)r = R0 + sp.exp(x0beg + xx[0])# 0.053407075111026485 == 0.017*pith_c,xi,x1beg = par.Cparameters("REAL", thismodule, ["th_c","xi","x1beg"],[0.053407075111026485,0.25,0.0])xx[1] = sp.symbols("xx1", real=True)x1j = x1beg + xx[1]if CoordSystem == "NobleSphericalThetaOptionOne":th = th_c + (M_PI - 2*th_c)*x1j + xi*sp.sin(2*M_PI*x1j)elif CoordSystem == "NobleSphericalThetaOptionTwo":x1_n_exponent = par.Cparameters("REAL", thismodule, ["x1_n_exponent"],9.0)th = M_PI/2 * ( 1 + (1 - xi)*(2*x1j - 1) + (xi - 2*th_c/M_PI)*(2*x1j - 1)**x1_n_exponent )xx[2] = sp.symbols("xx2", real=True)ph = xx[2]xxSph[0] = rxxSph[1] = thxxSph[2] = ph# Now define xCart, yCart, and zCart in terms of x0,xx[1],xx[2].# Note that the relation between r and x0 is not necessarily trivial in SinhSpherical coordinates. See above.xxCart[0] = xxSph[0]*sp.sin(xxSph[1])*sp.cos(xxSph[2])xxCart[1] = xxSph[0]*sp.sin(xxSph[1])*sp.sin(xxSph[2])xxCart[2] = xxSph[0]*sp.cos(xxSph[1])scalefactor_orthog[0] = sp.diff(xxSph[0],xx[0])scalefactor_orthog[1] = xxSph[0]scalefactor_orthog[2] = xxSph[0]*sp.sin(xxSph[1])# Set the unit vectorsUnitVectors = [[ sp.sin(xxSph[1])*sp.cos(xxSph[2]), sp.sin(xxSph[1])*sp.sin(xxSph[2]), sp.cos(xxSph[1])],[ sp.cos(xxSph[1])*sp.cos(xxSph[2]), sp.cos(xxSph[1])*sp.sin(xxSph[2]), -sp.sin(xxSph[1])],[ -sp.sin(xxSph[2]), sp.cos(xxSph[2]), sp.sympify(0) ]]########################################################################### CYLINDRICAL-LIKE COORDINATE SYSTEMS WITH & WITHOUT RADIAL/Z RESCALINGS ###########################################################################elif CoordSystem == "Cylindrical" or CoordSystem == "SinhCylindrical" or CoordSystem == "SinhCylindricalv2":# Assuming the cylindrical radial coordinate# is positive makes nice simplifications of# unit vectors possible.xx[0] = sp.symbols("xx0", real=True)if CoordSystem == "Cylindrical":RHOMAX,ZMIN,ZMAX = par.Cparameters("REAL",thismodule,["RHOMAX","ZMIN","ZMAX"],[10.0,-10.0,10.0])xxmin = [sp.sympify(0), -M_PI, ZMIN]xxmax = [ RHOMAX, M_PI, ZMAX]RHOCYL = xx[0]PHICYL = xx[1]ZCYL = xx[2]Cart_to_xx[0] = sp.sqrt(Cartx ** 2 + Carty ** 2)Cart_to_xx[1] = sp.atan2(Carty, Cartx)Cart_to_xx[2] = Cartzelif CoordSystem == "SinhCylindrical":xxmin = [sp.sympify(0), -M_PI, sp.sympify(-1)]xxmax = [sp.sympify(1), M_PI, sp.sympify(+1)]AMPLRHO, SINHWRHO, AMPLZ, SINHWZ = par.Cparameters("REAL",thismodule,["AMPLRHO","SINHWRHO","AMPLZ","SINHWZ"],[ 10.0, 0.2, 10.0, 0.2])# Set SinhCylindrical radial & z coordinates by default; overwrite later if CoordSystem == "SinhCylindricalv2".RHOCYL = AMPLRHO * (sp.exp(xx[0] / SINHWRHO) - sp.exp(-xx[0] / SINHWRHO)) / (sp.exp(1 / SINHWRHO) - sp.exp(-1 / SINHWRHO))# phi coordinate remains unchanged.PHICYL = xx[1]ZCYL = AMPLZ * (sp.exp(xx[2] / SINHWZ) - sp.exp(-xx[2] / SINHWZ)) / (sp.exp(1 / SINHWZ) - sp.exp(-1 / SINHWZ))Cart_to_xx[0] = SINHWRHO*sp.asinh(sp.sqrt(Cartx ** 2 + Carty ** 2)*sp.sinh(1/SINHWRHO)/AMPLRHO)Cart_to_xx[1] = sp.atan2(Carty, Cartx)Cart_to_xx[2] = SINHWZ*sp.asinh(Cartz*sp.sinh(1/SINHWZ)/AMPLZ)# SinhCylindricalv2 adds the parameters "const_drho", "const_dz", which allows for regions near xx[0]=0# and xx[2]=0 to have constant rho and z resolution of const_drho and const_dz, provided the sinh() terms# do not dominate near xx[0]=0 and xx[2]=0.elif CoordSystem == "SinhCylindricalv2":xxmin = [sp.sympify(0), -M_PI, sp.sympify(-1)]xxmax = [sp.sympify(1), M_PI, sp.sympify(+1)]AMPLRHO, SINHWRHO, AMPLZ, SINHWZ = par.Cparameters("REAL",thismodule,["AMPLRHO","SINHWRHO","AMPLZ","SINHWZ"],[ 10.0, 0.2, 10.0, 0.2])const_drho, const_dz = par.Cparameters("REAL",thismodule,["const_drho","const_dz"],[0.0625,0.0625])RHOCYL = AMPLRHO * ( const_drho*xx[0] + (sp.exp(xx[0] / SINHWRHO) - sp.exp(-xx[0] / SINHWRHO)) / (sp.exp(1 / SINHWRHO) - sp.exp(-1 / SINHWRHO)) )PHICYL = xx[1]ZCYL = AMPLZ * ( const_dz *xx[2] + (sp.exp(xx[2] / SINHWZ ) - sp.exp(-xx[2] / SINHWZ )) / (sp.exp(1 / SINHWZ ) - sp.exp(-1 / SINHWZ )) )# NO CLOSED-FORM EXPRESSION FOR RADIAL OR Z INVERSION.# Cart_to_xx[0] = "NewtonRaphson"# Cart_to_xx[1] = sp.atan2(Carty, Cartx)# Cart_to_xx[2] = "NewtonRaphson"xxCart[0] = RHOCYL*sp.cos(PHICYL)xxCart[1] = RHOCYL*sp.sin(PHICYL)xxCart[2] = ZCYLxxSph[0] = sp.sqrt(RHOCYL**2 + ZCYL**2)xxSph[1] = sp.acos(ZCYL / xxSph[0])xxSph[2] = PHICYLscalefactor_orthog[0] = sp.diff(RHOCYL,xx[0])scalefactor_orthog[1] = RHOCYLscalefactor_orthog[2] = sp.diff(ZCYL,xx[2])f0_of_xx0 = RHOCYLf4_of_xx2 = sp.diff(ZCYL,xx[2])scalefactor_orthog_funcform[0] = sp.diff(f0_of_xx0_funcform,xx[0])scalefactor_orthog_funcform[1] = f0_of_xx0_funcformscalefactor_orthog_funcform[2] = f4_of_xx2_funcform# Set the unit vectorsUnitVectors = [[ sp.cos(PHICYL), sp.sin(PHICYL), sp.sympify(0)],[-sp.sin(PHICYL), sp.cos(PHICYL), sp.sympify(0)],[ sp.sympify(0), sp.sympify(0), sp.sympify(1)]]elif CoordSystem == "SymTP" or CoordSystem == "SinhSymTP":# var1, var2= sp.symbols('var1 var2',real=True)bScale, SINHWAA, AMAX = par.Cparameters("REAL",thismodule,["bScale","SINHWAA","AMAX"],[0.5, 0.2, 10.0 ])# Assuming xx0, xx1, and bScale# are positive makes nice simplifications of# unit vectors possible.xx[0],xx[1] = sp.symbols("xx0 xx1", real=True)xxmin = [sp.sympify(0), sp.sympify(0),-M_PI]xxmax = [ AMAX, M_PI, M_PI]AA = xx[0]if CoordSystem == "SinhSymTP":# With xxmax[0] == AMAX, sinh(xx0/AMAX) will evaluate to a number between 0 and 1.# Similarly, sinh(xx0/(AMAX*SINHWAA)) / sinh(1/SINHWAA) will also evaluate to a number between 0 and 1.# Then AA = AMAX*sinh(xx0/(AMAX*SINHWAA)) / sinh(1/SINHWAA) will evaluate to a number between 0 and AMAX.AA = AMAX * (sp.exp(xx[0] / (AMAX*SINHWAA)) - sp.exp(-xx[0] / (AMAX*SINHWAA))) / (sp.exp(1 / SINHWAA) - sp.exp(-1 / AMAX))var1 = sp.sqrt(AA**2 + (bScale * sp.sin(xx[1]))**2)var2 = sp.sqrt(AA**2 + bScale**2)RHOSYMTP = AA*sp.sin(xx[1])PHSYMTP = xx[2]ZSYMTP = var2*sp.cos(xx[1])xxCart[0] = AA *sp.sin(xx[1])*sp.cos(xx[2])xxCart[1] = AA *sp.sin(xx[1])*sp.sin(xx[2])xxCart[2] = ZSYMTPxxSph[0] = sp.sqrt(RHOSYMTP**2 + ZSYMTP**2)xxSph[1] = sp.acos(ZSYMTP / xxSph[0])xxSph[2] = PHSYMTPif CoordSystem == "SymTP":rSph = sp.sqrt(Cartx ** 2 + Carty ** 2 + Cartz ** 2)thSph = sp.acos(Cartz / rSph)phSph = sp.atan2(Carty, Cartx)# Mathematica script to compute Cart_to_xx[]# AA = x1;# var2 = Sqrt[AA^2 + bScale^2];# RHOSYMTP = AA*Sin[x2];# ZSYMTP = var2*Cos[x2];# Solve[{rSph == Sqrt[RHOSYMTP^2 + ZSYMTP^2],# thSph == ArcCos[ZSYMTP/Sqrt[RHOSYMTP^2 + ZSYMTP^2]],# phSph == x3},# {x1, x2, x3}]Cart_to_xx[0] = sp.sqrt(-bScale**2 + rSph**2 +sp.sqrt(bScale**4 + 2*bScale**2*rSph**2 + rSph**4 -4*bScale**2*rSph**2*sp.cos(thSph)**2))*M_SQRT1_2 # M_SQRT1_2 = 1/sqrt(2); define this way for UnitTesting# The sign() function in the following expression ensures the correct root is taken.Cart_to_xx[1] = sp.acos(sp.sign(Cartz)*(sp.sqrt(1 + rSph**2/bScale**2 -sp.sqrt(bScale**4 + 2*bScale**2*rSph**2 + rSph**4 -4*bScale**2*rSph**2*sp.cos(thSph)**2)/bScale**2)*M_SQRT1_2)) # M_SQRT1_2 = 1/sqrt(2); define this way for UnitTestingCart_to_xx[2] = phSphelif CoordSystem == "SinhSymTP":pass# Closed form expression for Cart_to_xx in SinhSymTP may exist, but has not yet been foundscalefactor_orthog[0] = sp.diff(AA,xx[0]) * var1 / var2scalefactor_orthog[1] = var1scalefactor_orthog[2] = AA * sp.sin(xx[1])f0_of_xx0 = AAf1_of_xx1 = sp.sin(xx[1])f2_of_xx0_xx1 = var1f3_of_xx0 = var2scalefactor_orthog_funcform[0] = sp.diff(f0_of_xx0_funcform,xx[0]) * f2_of_xx0_xx1_funcform/f3_of_xx0_funcformscalefactor_orthog_funcform[1] = f2_of_xx0_xx1_funcformscalefactor_orthog_funcform[2] = f0_of_xx0_funcform*f1_of_xx1_funcform# Set the transpose of the matrix of unit vectorsUnitVectors = [[sp.sin(xx[1]) * sp.cos(xx[2]) * var2 / var1,sp.sin(xx[1]) * sp.sin(xx[2]) * var2 / var1,AA * sp.cos(xx[1]) / var1],[AA * sp.cos(xx[1]) * sp.cos(xx[2]) / var1,AA * sp.cos(xx[1]) * sp.sin(xx[2]) / var1,-sp.sin(xx[1]) * var2 / var1],[-sp.sin(xx[2]), sp.cos(xx[2]), sp.sympify(0)]]elif CoordSystem == "Cartesian":xmin, xmax, ymin, ymax, zmin, zmax = par.Cparameters("REAL",thismodule,["xmin","xmax","ymin","ymax","zmin","zmax"],[ -10.0, 10.0, -10.0, 10.0, -10.0, 10.0])xxmin = ["xmin", "ymin", "zmin"]xxmax = ["xmax", "ymax", "zmax"]xxCart[0] = xx[0]xxCart[1] = xx[1]xxCart[2] = xx[2]xxSph[0] = sp.sqrt(xx[0] ** 2 + xx[1] ** 2 + xx[2] ** 2)xxSph[1] = sp.acos(xx[2] / xxSph[0])xxSph[2] = sp.atan2(xx[1], xx[0])Cart_to_xx[0] = CartxCart_to_xx[1] = CartyCart_to_xx[2] = Cartzscalefactor_orthog[0] = sp.sympify(1)scalefactor_orthog[1] = sp.sympify(1)scalefactor_orthog[2] = sp.sympify(1)scalefactor_orthog_funcform[0] = sp.sympify(1)scalefactor_orthog_funcform[1] = sp.sympify(1)scalefactor_orthog_funcform[2] = sp.sympify(1)# Set the transpose of the matrix of unit vectorsUnitVectors = [[sp.sympify(1), sp.sympify(0), sp.sympify(0)],[sp.sympify(0), sp.sympify(1), sp.sympify(0)],[sp.sympify(0), sp.sympify(0), sp.sympify(1)]]else:print("CoordSystem == " + CoordSystem + " is not supported.")sys.exit(1)# Finally, call ref_metric__hatted_quantities()# to construct hatted metric, derivs of hatted# metric, and Christoffel symbolsref_metric__hatted_quantities(SymPySimplifyExpressions)# ref_metric__hatted_quantities(scalefactor_orthog_funcform,SymPySimplifyExpressions)# ref_metric__hatted_quantities(scalefactor_orthog,SymPySimplifyExpressions)def ref_metric__hatted_quantities(SymPySimplifyExpressions=True):enable_rfm_precompute = Falseif par.parval_from_str(thismodule+"::enable_rfm_precompute") == "True":enable_rfm_precompute = True# Step 0: Set dimension DIMDIM = par.parval_from_str("grid::DIM")global ReU,ReDD,ghatDD,ghatUU,detgammahatReU = ixp.zerorank1()ReDD = ixp.zerorank2()ghatDD = ixp.zerorank2()# Step 1: Compute ghatDD (reference metric), ghatUU# (inverse reference metric), as well as# rescaling vector ReU & rescaling matrix ReDDif enable_rfm_precompute == False:for i in range(DIM):scalefactor_orthog[i] = sp.sympify(scalefactor_orthog[i])ghatDD[i][i] = scalefactor_orthog[i]**2ReU[i] = 1/scalefactor_orthog[i]for j in range(DIM):ReDD[i][j] = scalefactor_orthog[i]*scalefactor_orthog[j]else:for i in range(DIM):scalefactor_orthog_funcform[i] = sp.sympify(scalefactor_orthog_funcform[i])ghatDD[i][i] = scalefactor_orthog_funcform[i]**2ReU[i] = 1/scalefactor_orthog_funcform[i]for j in range(DIM):ReDD[i][j] = scalefactor_orthog_funcform[i]*scalefactor_orthog_funcform[j]# Step 1b: Compute ghatUUghatUU, detgammahat = ixp.symm_matrix_inverter3x3(ghatDD)# Step 1c: Sanity check: verify that ReDD, ghatDD,# and ghatUU are all symmetric rank-2:for i in range(DIM):for j in range(DIM):if ReDD[i][j] != ReDD[j][i]:print("Error: ReDD["+ str(i) + "][" + str(j) + "] != ReDD["+ str(j) + "][" + str(i) + ": " + str(ReDD[i][j]) + "!=" + str(ReDD[j][i]))sys.exit(1)if ghatDD[i][j] != ghatDD[j][i]:print("Error: ghatDD["+ str(i) + "][" + str(j) + "] != ghatDD["+ str(j) + "][" + str(i) + ": " + str(ghatDD[i][j]) + "!=" + str(ghatDD[j][i]))sys.exit(1)if ghatUU[i][j] != ghatUU[j][i]:print("Error: ghatUU["+ str(i) + "][" + str(j) + "] != ghatUU["+ str(j) + "][" + str(i) + ": " + str(ghatUU[i][j]) + "!=" + str(ghatUU[j][i]))sys.exit(1)# Step 2: Compute det(ghat) and its 1st & 2nd derivativesglobal detgammahatdD,detgammahatdDDdetgammahatdD = ixp.zerorank1(DIM)detgammahatdDD = ixp.zerorank2(DIM)for i in range(DIM):detgammahatdD[i] = (sp.diff(detgammahat, xx[i]))for j in range(DIM):detgammahatdDD[i][j] = sp.diff(detgammahatdD[i], xx[j])# Step 3a: Compute 1st & 2nd derivatives of rescaling vector.# (E.g., needed in BSSN for betaUdDD computation)global ReUdD,ReUdDDReUdD = ixp.zerorank2(DIM)ReUdDD = ixp.zerorank3(DIM)for i in range(DIM):for j in range(DIM):ReUdD[i][j] = sp.diff(ReU[i], xx[j])for k in range(DIM):ReUdDD[i][j][k] = sp.diff(ReUdD[i][j], xx[k])# Step 3b: Compute 1st & 2nd derivatives of rescaling matrix.global ReDDdD,ReDDdDDReDDdD = ixp.zerorank3(DIM)ReDDdDD = ixp.zerorank4(DIM)for i in range(DIM):for j in range(DIM):for k in range(DIM):ReDDdD[i][j][k] = (sp.diff(ReDD[i][j],xx[k]))for l in range(DIM):# Simplifying this doesn't appear to help overall NRPy run time.ReDDdDD[i][j][k][l] = sp.diff(ReDDdD[i][j][k],xx[l])# Step 3c: Compute 1st & 2nd derivatives of reference metric.global ghatDDdD,ghatDDdDDghatDDdD = ixp.zerorank3(DIM)ghatDDdDD = ixp.zerorank4(DIM)for i in range(DIM):for j in range(DIM):for k in range(DIM):if SymPySimplifyExpressions==True:# ghatDDdD[i][j][k] = sp.trigsimp(sp.diff(ghatDD[i][j],xx[k])) # FIXME: BAD: MUST BE SIMPLIFIED OR ANSWER IS INCORRECT! Must be some bug in sympy...ghatDDdD[i][j][k] = sp.simplify(sp.diff(ghatDD[i][j],xx[k])) # FIXME: BAD: MUST BE SIMPLIFIED OR ANSWER IS INCORRECT! Must be some bug in sympy...else:ghatDDdD[i][j][k] = (sp.diff(ghatDD[i][j],xx[k])) # FIXME: BAD: MUST BE SIMPLIFIED OR ANSWER IS INCORRECT! Must be some bug in sympy...for l in range(DIM):ghatDDdDD[i][j][k][l] = (sp.diff(ghatDDdD[i][j][k],xx[l]))# Step 4a: Compute Christoffel symbols of reference metric.global GammahatUDDGammahatUDD = ixp.zerorank3(DIM)for i in range(DIM):for k in range(DIM):for l in range(DIM):for m in range(DIM):# GammahatUDD[i][k][l] += sp.trigsimp((sp.Rational(1,2))*ghatUU[i][m]*\GammahatUDD[i][k][l] += (sp.Rational(1,2))*ghatUU[i][m]*\(ghatDDdD[m][k][l] + ghatDDdD[m][l][k] - ghatDDdD[k][l][m])# Step 4b: Compute derivs of Christoffel symbols of reference metric.global GammahatUDDdDGammahatUDDdD = ixp.zerorank4(DIM)for i in range(DIM):for j in range(DIM):for k in range(DIM):for l in range(DIM):GammahatUDDdD[i][j][k][l] = (sp.diff(GammahatUDD[i][j][k],xx[l]))# Step 4c: If rfm_precompute is disabled, then we are finished with this function.# Otherwise continue to Step 5.if enable_rfm_precompute == False:returnelse:CoordSystem = par.parval_from_str("reference_metric::CoordSystem")# if not (("Spherical" in CoordSystem) or ("SymTP" in CoordSystem)):# if not (( "Spherical" in CoordSystem)):# print("Error: CoordSystem == "+CoordSystem+" does not yet support rfm precompute infrastructure.")# sys.exit(1)# enable_rfm_precompute: precompute and store in memory complicated# expressions related to the reference metric (a.k.a., "hatted# quantities")# The precomputed "hatted quantity" expressions will be stored in# a C struct called rfmstruct. As these expressions generally# involve computationally expensive transcendental functions# of xx0,xx1,or xx2, and xx0,xx1, and xx2 remain fixed across# most (if not all) of a given simulation, setting up the# rfmstruct can greatly improve performance.# The core challenge in setting up the rfmstruct is collecting# all the information needed to automatically generate it.# Step 5 and onwards implements this algorithm, using the# *generic functional form* of the hatted quantities (as# opposed to the exact closed-form expressions of the# hatted quantities) computed above.# Step 5: Now that all hatted quantities are written in terms of generic SymPy functions,# we will now replace SymPy functions with simple variables using rigid NRPy+ syntax,# and store these variables to globals defined above.def make_replacements(expr):sympy_version = sp.__version__.replace("rc","...").replace("b","...") # Ignore the rc's and b's for release candidates & betas.sympy_major_version = int(sympy_version.split(".")[0])sympy_minor_version = int(sympy_version.split(".")[1])if sympy_major_version < 1 or (sympy_major_version >= 1 and sympy_minor_version < 2):print("Detected SymPy version "+sympy_version)print("Sorry, reference metric precomputation unsupported in SymPy < 1.2!")sys.exit(1)for item in sp.preorder_traversal(expr):if item.func == sp.Derivative:stringfunc = str(item.args[0]).split("_funcform(", 1)[0] # store everything before _funcform(...stringderv = str(item.args[1]).replace(" ", "") # Ignore whitespacederiv_wrt = stringderv.split(",")[0].replace("(xx", "")derivorder = int(stringderv.split(",")[1].replace(")", ""))derivop = "__D"for i in range(derivorder - 1):derivop += "D"derivop += deriv_wrtfor i in range(derivorder - 1):derivop += deriv_wrtexpr = expr.xreplace({item: sp.sympify(stringfunc + derivop)})for item in sp.preorder_traversal(expr):if "_funcform" in str(item.func):stringfunc = str(item.func).split("_funcform", 1)[0] # store everything before _funcform(...expr = expr.xreplace({item: sp.sympify(stringfunc)})return exprdetgammahat = make_replacements(detgammahat)for i in range(DIM):ReU[i] = make_replacements(ReU[i])detgammahatdD[i] = make_replacements(detgammahatdD[i])for j in range(DIM):ReDD[i][j] = make_replacements(ReDD[i][j])ReUdD[i][j] = make_replacements(ReUdD[i][j])ghatDD[i][j] = make_replacements(ghatDD[i][j])ghatUU[i][j] = make_replacements(ghatUU[i][j])detgammahatdDD[i][j] = make_replacements(detgammahatdDD[i][j])for k in range(DIM):ReDDdD[i][j][k] = make_replacements(ReDDdD[i][j][k])ReUdDD[i][j][k] = make_replacements(ReUdDD[i][j][k])ghatDDdD[i][j][k] = make_replacements(ghatDDdD[i][j][k])GammahatUDD[i][j][k] = make_replacements(GammahatUDD[i][j][k])for l in range(DIM):ReDDdDD[i][j][k][l] = make_replacements(ReDDdDD[i][j][k][l])ghatDDdDD[i][j][k][l] = make_replacements(ghatDDdDD[i][j][k][l])GammahatUDDdD[i][j][k][l] = make_replacements(GammahatUDDdD[i][j][k][l])# Step 6: At this point, each expression is written in terms of the generic functions# of xx0, xx1, and/or xx2 and their derivatives. Depending on the functions, some# of these derivatives may be zero. In Step 5 we'll evaluate the function# derivatives exactly and set the expressions to zero. Otherwise in the C code# we'd be storing performing arithmetic with zeros -- wasteful!# Step 6.a: Construct the full list of *unique* NRPy+ variables representing the# SymPy functions and derivatives, so that all zero derivatives can be# computed.freevars = []freevars.extend(detgammahat.free_symbols)for i in range(DIM):freevars.extend(ReU[i].free_symbols)freevars.extend(detgammahatdD[i].free_symbols)for j in range(DIM):freevars.extend(ReDD[i][j].free_symbols)freevars.extend(ReUdD[i][j].free_symbols)freevars.extend(ghatDD[i][j].free_symbols)freevars.extend(ghatUU[i][j].free_symbols)freevars.extend(detgammahatdDD[i][j].free_symbols)for k in range(DIM):freevars.extend(ReDDdD[i][j][k].free_symbols)freevars.extend(ReUdDD[i][j][k].free_symbols)freevars.extend(ghatDDdD[i][j][k].free_symbols)freevars.extend(GammahatUDD[i][j][k].free_symbols)for l in range(DIM):freevars.extend(ReDDdDD[i][j][k][l].free_symbols)freevars.extend(ghatDDdDD[i][j][k][l].free_symbols)freevars.extend(GammahatUDDdD[i][j][k][l].free_symbols)freevars_uniq = superfast_uniq(freevars)freevars_uniq_xx_indep = []for i in range(len(freevars_uniq)):freevars_uniq_xx_indep.append(freevars_uniq[i])# Step 6.b: Using the expressions f?_of_xx? set in reference_metric(),# evaluate each needed derivative and, in the case it is zero,# set the corresponding "freevar" variable to zero.freevars_uniq_vals = []for i in range(len(freevars_uniq)):var = freevars_uniq[i]basename = str(var).split("__")[0].replace("_funcform", "")derivatv = ""if "__" in str(var):derivatv = str(var).split("__")[1].replace("_funcform", "")if basename == "f0_of_xx0":basefunc = f0_of_xx0elif basename == "f1_of_xx1":basefunc = f1_of_xx1elif basename == "f2_of_xx0_xx1":basefunc = f2_of_xx0_xx1elif basename == "f3_of_xx0":basefunc = f3_of_xx0elif basename == "f4_of_xx2":basefunc = f4_of_xx2else:print("Error: function inside " + str(var) + " undefined.")sys.exit(1)diff_result = basefuncif derivatv == "":passelse:derivorder = derivatv.replace("d", "").replace("D", "").replace("0", "0 ").replace("1", "1 ").replace("2", "2 ").split(" ")for derivdirn in derivorder:if derivdirn != "":derivwrt = xx[int(derivdirn)]diff_result = sp.diff(diff_result, derivwrt)freevars_uniq_vals.append(diff_result)frees_uniq = superfast_uniq(diff_result.free_symbols)xx_dep = Falsefor dirn in range(3):if gri.xx[dirn] in frees_uniq:xx_dep = Trueif xx_dep == False:freevars_uniq_xx_indep[i] = diff_result# Step 6.c: Finally, substitute integers for all functions & derivatives that evaluate to integersfor varidx in range(len(freevars_uniq)):detgammahat = detgammahat.subs(freevars_uniq[varidx], freevars_uniq_xx_indep[varidx])for i in range(DIM):ReU[i] = ReU[i].subs(freevars_uniq[varidx], freevars_uniq_xx_indep[varidx])detgammahatdD[i] = detgammahatdD[i].subs(freevars_uniq[varidx], freevars_uniq_xx_indep[varidx])for j in range(DIM):ReDD[i][j] = ReDD[i][j].subs(freevars_uniq[varidx], freevars_uniq_xx_indep[varidx])ReUdD[i][j] = ReUdD[i][j].subs(freevars_uniq[varidx], freevars_uniq_xx_indep[varidx])ghatDD[i][j] = ghatDD[i][j].subs(freevars_uniq[varidx], freevars_uniq_xx_indep[varidx])ghatUU[i][j] = ghatUU[i][j].subs(freevars_uniq[varidx], freevars_uniq_xx_indep[varidx])detgammahatdDD[i][j] = detgammahatdDD[i][j].subs(freevars_uniq[varidx],freevars_uniq_xx_indep[varidx])for k in range(DIM):ReDDdD[i][j][k] = ReDDdD[i][j][k].subs(freevars_uniq[varidx], freevars_uniq_xx_indep[varidx])ReUdDD[i][j][k] = ReUdDD[i][j][k].subs(freevars_uniq[varidx], freevars_uniq_xx_indep[varidx])ghatDDdD[i][j][k] = ghatDDdD[i][j][k].subs(freevars_uniq[varidx], freevars_uniq_xx_indep[varidx])GammahatUDD[i][j][k] = GammahatUDD[i][j][k].subs(freevars_uniq[varidx],freevars_uniq_xx_indep[varidx])for l in range(DIM):ReDDdDD[i][j][k][l] = ReDDdDD[i][j][k][l].subs(freevars_uniq[varidx],freevars_uniq_xx_indep[varidx])ghatDDdDD[i][j][k][l] = ghatDDdDD[i][j][k][l].subs(freevars_uniq[varidx],freevars_uniq_xx_indep[varidx])GammahatUDDdD[i][j][k][l] = GammahatUDDdD[i][j][k][l].subs(freevars_uniq[varidx],freevars_uniq_xx_indep[varidx])# Step 7: Construct needed C code for declaring rfmstruct, allocating storage for# rfmstruct arrays, defining each element in each array, reading the# rfmstruct data from memory (both with and without SIMD enabled), and# freeing allocated memory for the rfmstrcut arrays.# struct_str: String that declares the rfmstruct struct.struct_str = "typedef struct __rfmstruct__ {\n"define_str = ""# rfmstruct stores pointers to (so far) 1D arrays. The malloc_str string allocates space for the arrays.malloc_str = "rfm_struct rfmstruct;\n"freemm_str = ""# readvr_str reads the arrays from memory as neededreadvr_str = ["", "", ""]readvr_SIMD_outer_str = ["", "", ""]readvr_SIMD_inner_str = ["", "", ""]# Sort freevars_uniq_vals and freevars_uniq_xx_indep, according to alphabetized freevars_uniq_xx_indep.# Without this step, the ordering of elements in rfmstruct would be random, and would change each time# this function was called.if len(freevars_uniq_xx_indep) > 0:freevars_uniq_xx_indep, freevars_uniq_vals = (list(x) for x in zip(*sorted(zip(freevars_uniq_xx_indep, freevars_uniq_vals),key=str)))# Tease out how many variables each function in freevars_uniq_valswhich_freevar = 0for expr in freevars_uniq_vals:if "_of_xx" in str(freevars_uniq_xx_indep[which_freevar]):frees = expr.free_symbolsfrees_uniq = superfast_uniq(frees)xx_list = []malloc_size = 1for i in range(3):if gri.xx[i] in frees_uniq:xx_list.append(gri.xx[i])malloc_size *= gri.Nxx_plus_2NGHOSTS[i]struct_str += "\tREAL *restrict " + str(freevars_uniq_xx_indep[which_freevar]) + ";\n"malloc_str += "rfmstruct." + str(freevars_uniq_xx_indep[which_freevar]) + " = (REAL *)malloc(sizeof(REAL)*" + str(malloc_size) + ");\n"freemm_str += "free(rfmstruct." + str(freevars_uniq_xx_indep[which_freevar]) + ");\n"output_define_and_readvr = Falsefor dirn in range(3):if (gri.xx[dirn] in frees_uniq) and not (gri.xx[(dirn+1)%3] in frees_uniq) and not (gri.xx[(dirn+2)%3] in frees_uniq):define_str += "for(int i"+str(dirn)+"=0;i"+str(dirn)+"<Nxx_plus_2NGHOSTS"+str(dirn)+";i"+str(dirn)+"++) {\n"define_str += " const REAL xx"+str(dirn)+" = xx["+str(dirn)+"][i"+str(dirn)+"];\n"define_str += " rfmstruct." + str(freevars_uniq_xx_indep[which_freevar]) + "[i"+str(dirn)+"] = " + str(sp.ccode(freevars_uniq_vals[which_freevar])) + ";\n"define_str += "}\n\n"readvr_str[dirn] += "const REAL " + str(freevars_uniq_xx_indep[which_freevar]) + " = rfmstruct->" + \str(freevars_uniq_xx_indep[which_freevar]) + "[i"+str(dirn)+"];\n"readvr_SIMD_outer_str[dirn] += "const double NOSIMD" + str(freevars_uniq_xx_indep[which_freevar]) + " = rfmstruct->" + str(freevars_uniq_xx_indep[which_freevar]) + "[i"+str(dirn)+"]; "readvr_SIMD_outer_str[dirn] += "const REAL_SIMD_ARRAY " + str(freevars_uniq_xx_indep[which_freevar]) + \" = ConstSIMD(NOSIMD" + str(freevars_uniq_xx_indep[which_freevar]) + ");\n"readvr_SIMD_inner_str[dirn] += "const REAL_SIMD_ARRAY " + str(freevars_uniq_xx_indep[which_freevar]) + \" = ReadSIMD(&rfmstruct->" + str(freevars_uniq_xx_indep[which_freevar]) + "[i"+str(dirn)+"]);\n"output_define_and_readvr = Trueif (output_define_and_readvr == False) and (gri.xx[0] in frees_uniq) and (gri.xx[1] in frees_uniq):define_str += """for(int i1=0;i1<Nxx_plus_2NGHOSTS1;i1++) for(int i0=0;i0<Nxx_plus_2NGHOSTS0;i0++) {const REAL xx0 = xx[0][i0];const REAL xx1 = xx[1][i1];rfmstruct.""" + str(freevars_uniq_xx_indep[which_freevar]) + """[i0 + Nxx_plus_2NGHOSTS0*i1] = """ + str(sp.ccode(freevars_uniq_vals[which_freevar])) + """;}\n\n"""readvr_str[0] += "const REAL " + str(freevars_uniq_xx_indep[which_freevar]) + " = rfmstruct->" + \str(freevars_uniq_xx_indep[which_freevar]) + "[i0 + Nxx_plus_2NGHOSTS0*i1];\n"readvr_SIMD_outer_str[0] += "const double NOSIMD" + str(freevars_uniq_xx_indep[which_freevar]) + \" = rfmstruct->" + str(freevars_uniq_xx_indep[which_freevar]) + "[i0 + Nxx_plus_2NGHOSTS0*i1]; "readvr_SIMD_outer_str[0] += "const REAL_SIMD_ARRAY " + str(freevars_uniq_xx_indep[which_freevar]) + \" = ConstSIMD(NOSIMD" + str(freevars_uniq_xx_indep[which_freevar]) + ");\n"readvr_SIMD_inner_str[0] += "const REAL_SIMD_ARRAY " + str(freevars_uniq_xx_indep[which_freevar]) + \" = ReadSIMD(&rfmstruct->" + str(freevars_uniq_xx_indep[which_freevar]) + "[i0 + Nxx_plus_2NGHOSTS0*i1]);\n"output_define_and_readvr = Trueif output_define_and_readvr == False:print("ERROR: Could not figure out the (xx0,xx1,xx2) dependency within the expression for "+str(freevars_uniq_xx_indep[which_freevar])+":")print(str(freevars_uniq_vals[which_freevar]))sys.exit(1)which_freevar += 1struct_str += "} rfm_struct;\n\n"# Step 8: Output needed C code to filesoutdir = par.parval_from_str(thismodule+"::rfm_precompute_Ccode_outdir")with open(outdir + "/rfm_struct__declare.h", "w") as file:file.write(struct_str)with open(outdir + "/rfm_struct__malloc.h", "w") as file:file.write(malloc_str)with open(outdir + "/rfm_struct__define.h", "w") as file:file.write(define_str)for i in range(3):with open(outdir + "/rfm_struct__read" + str(i) + ".h", "w") as file:file.write(readvr_str[i])with open(outdir + "/rfm_struct__SIMD_outer_read" + str(i) + ".h", "w") as file:file.write(readvr_SIMD_outer_str[i])with open(outdir + "/rfm_struct__SIMD_inner_read" + str(i) + ".h", "w") as file:file.write(readvr_SIMD_inner_str[i])with open(outdir + "/rfm_struct__freemem.h", "w") as file:file.write(freemm_str)def get_EigenCoord():CoordSystem_orig = par.parval_from_str("reference_metric::CoordSystem")for EigenCoordstr in ["Spherical","Cylindrical","SymTP","Cartesian"]:if EigenCoordstr in CoordSystem_orig:return EigenCoordstrprint("Error: Could not find EigenCoord for reference_metric::CoordSystem == "+CoordSystem_orig)sys.exit(1)def set_Nxx_dxx_invdx_params__and__xx_h(outdir="."):import oswith open(os.path.join(outdir,"set_Nxx_dxx_invdx_params__and__xx.h"),"w") as file:file.write("""void set_Nxx_dxx_invdx_params__and__xx(const int EigenCoord, const int Nxx[3],paramstruct *restrict params, REAL *restrict xx[3]) {// Override parameter defaults with values based on command line arguments and NGHOSTS.params->Nxx0 = Nxx[0];params->Nxx1 = Nxx[1];params->Nxx2 = Nxx[2];params->Nxx_plus_2NGHOSTS0 = Nxx[0] + 2*NGHOSTS;params->Nxx_plus_2NGHOSTS1 = Nxx[1] + 2*NGHOSTS;params->Nxx_plus_2NGHOSTS2 = Nxx[2] + 2*NGHOSTS;// Step 0d: Set up space and time coordinates// Step 0d.i: Declare \Delta x^i=dxx{0,1,2} and invdxx{0,1,2}, as well as xxmin[3] and xxmax[3]:#include "set_Cparameters.h"REAL xxmin[3],xxmax[3];if(EigenCoord == 0) {""")for i in range(3):file.write(" xxmin["+str(i)+"] = "+str(xxmin[i])+";\n")file.write(" xxmax["+str(i)+"] = "+str(xxmax[i])+";\n")file.write("""} else if (EigenCoord == 1) {""")CoordSystem_orig = par.parval_from_str("reference_metric::CoordSystem")par.set_parval_from_str("reference_metric::CoordSystem",get_EigenCoord())reference_metric()for i in range(3):file.write(" xxmin["+str(i)+"] = "+str(xxmin[i])+";\n")file.write(" xxmax["+str(i)+"] = "+str(xxmax[i])+";\n")par.set_parval_from_str("reference_metric::CoordSystem",CoordSystem_orig)reference_metric()file.write("""}params->dxx0 = (xxmax[0] - xxmin[0]) / ((REAL)Nxx[0]);params->dxx1 = (xxmax[1] - xxmin[1]) / ((REAL)Nxx[1]);params->dxx2 = (xxmax[2] - xxmin[2]) / ((REAL)Nxx[2]);params->invdx0 = 1.0/params->dxx0;params->invdx1 = 1.0/params->dxx1;params->invdx2 = 1.0/params->dxx2;// Now that params.dxx{0,1,2} and params.invdxx{0,1,2} have been set,// Step 0d.iii: Set up uniform coordinate gridsxx[0] = (REAL *)malloc(sizeof(REAL)*Nxx_plus_2NGHOSTS0);for(int j=0;j<Nxx_plus_2NGHOSTS0;j++)xx[0][j] = xxmin[0] + ((REAL)(j-NGHOSTS) + (1.0/2.0))*params->dxx0; // Cell-centered grid.xx[1] = (REAL *)malloc(sizeof(REAL)*Nxx_plus_2NGHOSTS1);for(int j=0;j<Nxx_plus_2NGHOSTS1;j++)xx[1][j] = xxmin[1] + ((REAL)(j-NGHOSTS) + (1.0/2.0))*params->dxx1; // Cell-centered grid.xx[2] = (REAL *)malloc(sizeof(REAL)*Nxx_plus_2NGHOSTS2);for(int j=0;j<Nxx_plus_2NGHOSTS2;j++)xx[2][j] = xxmin[2] + ((REAL)(j-NGHOSTS) + (1.0/2.0))*params->dxx2; // Cell-centered grid.//fprintf(stderr,"hey inside setxx: %e %e %e | %e %e\\n",xxmin[0],xxmin[1],xxmin[2],xx[0][0],params->dxx0);}""")def xxCart_h(funcname,cparamsloc,outfile):import outputC# Arbitrary-coordinate NRPy+ file output, Part 1: output the conversion from (x0,x1,x2) to Cartesian (x,y,z)Cout = outputC.outputC([xxCart[0],xxCart[1],xxCart[2]],["xCart[0]","xCart[1]","xCart[2]"],"returnstring",params="preindent=1")with open(outfile, "w") as file:file.write("""inline void """+funcname+"""(const paramstruct *restrict params, REAL *restrict xx[3],const int i0,const int i1,const int i2, REAL xCart[3]) {#include """+"\""+cparamsloc+"\""+"""REAL xx0 = xx[0][i0];REAL xx1 = xx[1][i1];REAL xx2 = xx[2][i2];\n"""+Cout+"}\n")# Compute proper distance in all 3 directions. Used to find the appropriate timestep for the CFL condition.def ds_dirn(delxx):ds_dirn = ixp.zerorank1(3)for i in range(3):ds_dirn[i] = delxx[i]*scalefactor_orthog[i]return ds_dirn# Find the appropriate timestep for the CFL condition.def add_find_timestep_func_to_dict():# Compute proper distance in all 3 directions.delxx = ixp.declarerank1("dxx", DIM=3)ds_drn = ds_dirn(delxx)ds_dirn_h = outputC([ds_drn[0], ds_drn[1], ds_drn[2]], ["ds_dirn0", "ds_dirn1", "ds_dirn2"],"returnstring")desc="Find the CFL-constrained timestep"add_to_Cfunction_dict(desc =desc,type ="REAL",name ="find_timestep",params ="const paramstruct *restrict params, REAL *restrict xx[3]",preloop ="REAL dsmin = 1e38; // Start with a crazy high value... close to the largest number in single precision.",body ="REAL ds_dirn0, ds_dirn1, ds_dirn2;\n"+ds_dirn_h+"""#ifndef MIN#define MIN(A, B) ( ((A) < (B)) ? (A) : (B) )#endif// Set dsmin = MIN(dsmin, ds_dirn0, ds_dirn1, ds_dirn2);dsmin = MIN(dsmin,MIN(ds_dirn0,MIN(ds_dirn1,ds_dirn2)));""",loopopts ="InteriorPoints,Read_xxs,DisableOpenMP",postloop ="return dsmin*CFL_FACTOR/wavespeed;\n")def out_timestep_func_to_file(outfile):add_find_timestep_func_to_dict()with open(outfile, "w") as file:file.write(outC_function_dict["find_timestep"])def out_default_free_parameters_for_rfm(free_parameters_file,domain_size=1.0,sinh_width=0.4,sinhv2_const_dr=0.05,SymTP_bScale=0.5):CoordSystem = par.parval_from_str("reference_metric::CoordSystem")with open(free_parameters_file, "a") as file:file.write("""// Set free-parameter values.const REAL domain_size = """ + str(domain_size) + """;const REAL sinh_width = """ + str(sinh_width) + """;const REAL sinhv2_const_dr= """ + str(sinhv2_const_dr) + """;const REAL SymTP_bScale = """ + str(SymTP_bScale) + ";\n")coordparams = ""if CoordSystem == "Spherical":coordparams += """params.RMAX = domain_size;\n"""elif "SinhSpherical" in CoordSystem:coordparams += """params.AMPL = domain_size;params.SINHW= sinh_width;\n"""if CoordSystem == "SinhSphericalv2":coordparams += " params.const_dr = sinhv2_const_dr;\n"elif "SymTP" in CoordSystem:coordparams += """params.bScale = SymTP_bScale;params.AMAX = domain_size;\n"""if CoordSystem == "SinhSymTP":coordparams += " params.SINHWAA = sinh_width;\n"elif CoordSystem == "Cartesian":coordparams += """params.xmin = -domain_size, params.xmax = domain_size;params.ymin = -domain_size, params.ymax = domain_size;params.zmin = -domain_size, params.zmax = domain_size;\n"""elif CoordSystem == "Cylindrical":coordparams += """params.ZMIN = -domain_size;params.ZMAX = domain_size;params.RHOMAX = domain_size;\n"""elif "SinhCylindrical" in CoordSystem:coordparams += """params.AMPLRHO = domain_size;params.SINHWRHO= sinh_width;params.AMPLZ = domain_size;params.SINHWZ = sinh_width;\n"""if CoordSystem == "SinhCylindricalv2":coordparams += """params.const_drho = sinhv2_const_dr;params.const_dz = sinhv2_const_dr;\n"""file.write(coordparams + "\n")
IMPLEMENTS: StaticTrumpetINHERITS: ADMBaseUSES INCLUDE HEADER: loop.hxx
ActiveThorns = "ADMBaseBaikalXCarpetXErrorEstimatorIOUtilODESolversStaticTrumpet"$nlevels = 1 # 2 #TODO 8$ncells = 128 #TODO 32Cactus::cctk_show_schedule = yesCactus::terminate = "time"Cactus::cctk_final_time = 1.0CarpetX::verbose = yesCarpetX::xmin = -6.4 #TODO -16.0CarpetX::ymin = -6.4 #TODO -16.0CarpetX::zmin = -6.4 #TODO -16.0CarpetX::xmax = +6.4 #TODO +16.0CarpetX::ymax = +6.4 #TODO +16.0CarpetX::zmax = +6.4 #TODO +16.0CarpetX::ncells_x = $ncellsCarpetX::ncells_y = $ncellsCarpetX::ncells_z = $ncellsCarpetX::ghost_size = 2CarpetX::max_num_levels = $nlevelsCarpetX::regrid_every = 16CarpetX::regrid_error_threshold = 1.0 #TODO 1.0 / 16.0ErrorEstimator::region_shape = "cube"ErrorEstimator::scale_by_resolution = no #TODO yesCarpetX::prolongation_type = "ddf"CarpetX::prolongation_order = 3CarpetX::dtfac = 0.25ADMBase::initial_data = "Static Trumpet"ADMBase::initial_lapse = "Static Trumpet"ADMBase::initial_shift = "Static Trumpet"ADMBase::initial_dtshift = "Static Trumpet"IO::out_dir = $parfileIO::out_every = 1 #TODO $ncells * 2 ** ($nlevels - 1) / 32CarpetX::out_tsv = no
SHARES: ADMBaseEXTENDS KEYWORD initial_data "Initial metric and extrinsic curvature datasets"{"Static Trumpet" :: "Static Trumpet black hole"}EXTENDS KEYWORD initial_lapse "Initial lapse value"{"Static Trumpet" :: "Static Trumpet black hole"}EXTENDS KEYWORD initial_shift "Initial lapse value"{"Static Trumpet" :: "Static Trumpet black hole"}EXTENDS KEYWORD initial_dtshift "Initial lapse value"{"Static Trumpet" :: "Static Trumpet black hole"}
if (CCTK_EQUALS(initial_data, "Static Trumpet") ||CCTK_EQUALS(initial_lapse, "Static Trumpet") ||CCTK_EQUALS(initial_shift, "Static Trumpet") ||CCTK_EQUALS(initial_dtshift, "Static Trumpet")) {SCHEDULE StaticTrumpet_Initial IN ADMBase_InitialData{LANG: CWRITES: ADMBase::metric(everywhere)WRITES: ADMBase::curv(everywhere)WRITES: ADMBase::lapse(everywhere)WRITES: ADMBase::shift(everywhere)WRITES: ADMBase::dtshift(everywhere)SYNC: ADMBase::metricSYNC: ADMBase::curvSYNC: ADMBase::lapseSYNC: ADMBase::shiftSYNC: ADMBase::dtshift} "Set up static trumpet initial conditions"}
#include <loop.hxx>#include <cctk.h>#include <cctk_Arguments.h>#include <cctk_Parameters.h>#include <cmath>namespace StaticTrumpet {using namespace Loop;using namespace std;template <typename T> T pow2(const T x) { return x * x; }template <typename T> T pow4(const T x) {const auto x2 = pow2(x);return x2 * x2;}extern "C" void StaticTrumpet_Initial(CCTK_ARGUMENTS) {DECLARE_CCTK_ARGUMENTS;DECLARE_CCTK_PARAMETERS;const bool set_metric = CCTK_EQUALS(initial_data, "Static Trumpet");const bool set_lapse = CCTK_EQUALS(initial_lapse, "Static Trumpet");const bool set_shift = CCTK_EQUALS(initial_shift, "Static Trumpet");const bool set_dtshift = CCTK_EQUALS(initial_dtshift, "Static Trumpet");const GF3D<CCTK_REAL, 0, 0, 0> gxx_(cctkGH, gxx);const GF3D<CCTK_REAL, 0, 0, 0> gxy_(cctkGH, gxy);const GF3D<CCTK_REAL, 0, 0, 0> gxz_(cctkGH, gxz);const GF3D<CCTK_REAL, 0, 0, 0> gyy_(cctkGH, gyy);const GF3D<CCTK_REAL, 0, 0, 0> gyz_(cctkGH, gyz);const GF3D<CCTK_REAL, 0, 0, 0> gzz_(cctkGH, gzz);const GF3D<CCTK_REAL, 0, 0, 0> kxx_(cctkGH, kxx);const GF3D<CCTK_REAL, 0, 0, 0> kxy_(cctkGH, kxy);const GF3D<CCTK_REAL, 0, 0, 0> kxz_(cctkGH, kxz);const GF3D<CCTK_REAL, 0, 0, 0> kyy_(cctkGH, kyy);const GF3D<CCTK_REAL, 0, 0, 0> kyz_(cctkGH, kyz);const GF3D<CCTK_REAL, 0, 0, 0> kzz_(cctkGH, kzz);const GF3D<CCTK_REAL, 0, 0, 0> alp_(cctkGH, alp);// const GF3D<CCTK_REAL, 0, 0, 0> dtalp_(cctkGH, dtalp);const GF3D<CCTK_REAL, 0, 0, 0> betax_(cctkGH, betax);const GF3D<CCTK_REAL, 0, 0, 0> betay_(cctkGH, betay);const GF3D<CCTK_REAL, 0, 0, 0> betaz_(cctkGH, betaz);const GF3D<CCTK_REAL, 0, 0, 0> dtbetax_(cctkGH, dtbetax);const GF3D<CCTK_REAL, 0, 0, 0> dtbetay_(cctkGH, dtbetay);const GF3D<CCTK_REAL, 0, 0, 0> dtbetaz_(cctkGH, dtbetaz);constexpr CCTK_REAL rmin = 1.0e-2;constexpr CCTK_REAL M = 1;loop_all<0, 0, 0>(cctkGH, [&](const PointDesc &p) {const auto r = sqrt(pow2(p.x) + pow2(p.y) + pow2(p.z));const auto r1 = 1 / fmax(rmin, r);const auto rho = sqrt(pow2(p.x) * pow2(p.y));const auto rho1 = 1 / fmax(rmin, rho);// x = r sin theta cos phi// y = r sin theta sin phi// z = r cos theta// rho = r sin theta = sqrt (x^2 + y^2)// dx/dr = x / r// dy/dr = y / r// dz/dr = z / r// dx/dtheta = r cos theta cos phi = x * z / rho// dy/dtheta = r cos theta sin phi = y * z / rho// dz/dtheta = - r sin theta = - rho// dx/dphi = - r sin theta sin phi = - y// dy/dphi = r sin theta cos phi = x// dz/dphi = 0const auto ex_r = p.x * r1;const auto ey_r = p.y * r1;const auto ez_r = p.z * r1;const auto ex_theta = +p.x * p.z * rho1;const auto ey_theta = +p.y * p.z * rho1;const auto ez_theta = -rho;const auto ex_phi = -p.y;const auto ey_phi = +p.x;const auto ez_phi = -rho;// first index i (cartesian), second index a (spherical)const array<array<CCTK_REAL, 3>, 3> dX_dR{{{{ex_r, ex_theta, ex_phi}},{{ey_r, ey_theta, ey_phi}},{{ez_r, ez_theta, ez_phi}},}};const auto phi = sqrt(1 + M * r1);const auto phi4 = pow4(phi);// array<array<CCTK_REAL, 3>, 3>// gij{{{{0, 0, 0}}, {{0, 0, 0}}, {{0, 0, 0}}}};// gij[0][0] = phi4;// gij[1][1] = phi4;// gij[2][2] = phi4;// array<array<CCTK_REAL, 3>, 3>// guij{{{{0, 0, 0}}, {{0, 0, 0}}, {{0, 0, 0}}}};// guij[0][0] = 1 / phi4;// guij[1][1] = 1 / phi4;// guij[2][2] = 1 / phi4;// array<array<CCTK_REAL, 3>, 3>// gab{{{{0, 0, 0}}, {{0, 0, 0}}, {{0, 0, 0}}}};// gab[0][0] = phi4;// gab[1][1] = pow2(r);// gab[2][2] = pow2(rho);// array<array<CCTK_REAL, 3>, 3>// guab{{{{0, 0, 0}}, {{0, 0, 0}}, {{0, 0, 0}}}};// guab[0][0] = 1 / phi4;// guab[1][1] = pow2(r1);// guab[2][2] = pow2(rho1);if (set_metric) {gxx_(p.I) = phi4;gxy_(p.I) = 0;gxz_(p.I) = 0;gyy_(p.I) = phi4;gyz_(p.I) = 0;gzz_(p.I) = phi4;}// Set K_ab in spherical coordinates// array<array<CCTK_REAL, 3>, 3>// kab{{{{0, 0, 0}}, {{0, 0, 0}}, {{0, 0, 0}}}};// kab[0][0] = -M * pow2(r1);// kab[1][1] = M;// kab[2][2] = M * pow2(rho * r1);// Raise indicesarray<array<CCTK_REAL, 3>, 3> kuab{{{{0, 0, 0}}, {{0, 0, 0}}, {{0, 0, 0}}}};kuab[0][0] = -M * pow2(r1) / pow2(phi4);kuab[1][1] = M * pow2(r1);kuab[2][2] = M * pow2(r1); // M * pow2(rho * r1) * pow2(rho1)// Convert to cartesian coordinatesarray<array<CCTK_REAL, 3>, 3> kuij;for (int i = 0; i < 3; ++i)for (int j = 0; j < 3; ++j) {CCTK_REAL t = 0;for (int a = 0; a < 3; ++a)for (int b = 0; b < 3; ++b)t += dX_dR[i][a] * dX_dR[j][b] * kuab[a][b];kuij[i][j] = t;}// Symmetrizefor (int i = 0; i < 3; ++i)for (int j = 0; j < i; ++j) {const auto t = (kuij[i][j] + kuij[j][i]) / 2;kuij[i][j] = kuij[j][i] = t;}// Lower indicesarray<array<CCTK_REAL, 3>, 3> kij;for (int i = 0; i < 3; ++i)for (int j = 0; j < 3; ++j)kij[i][j] = pow2(phi4) * kuij[i][j];if (set_metric) {kxx_(p.I) = kij[0][0];kxy_(p.I) = kij[0][1];kxz_(p.I) = kij[0][2];kyy_(p.I) = kij[1][1];kyz_(p.I) = kij[1][2];kzz_(p.I) = kij[2][2];}if (set_lapse)alp_(p.I) = r / (M + r1);// dtalp_(p.I) = 0;if (set_shift) {const auto betar = M * r / pow2(M + r1);betax_(p.I) = betar * ex_r;betay_(p.I) = betar * ey_r;betaz_(p.I) = betar * ez_r;}if (set_dtshift) {dtbetax_(p.I) = 0;dtbetay_(p.I) = 0;dtbetaz_(p.I) = 0;}});}} // namespace StaticTrumpet
# Main make.code.defn file for thorn StaticTrumpet# Source files in this directorySRCS = StaticTrumpet.cxx