SpECTRE  v2026.09.05
Loading...
Searching...
No Matches
Running CCE

Acquiring the CCE module

There are a couple different ways to acquire the CCE module/executable.

From a release

Starting from late May 2024, in every Release of SpECTRE we offer a tarball that contains everything needed to run CCE on a large number of different systems. This will be under the Assets section towards the bottom of the release (there may be a lot of text detailing what's been updated in this release). Inside this tarball is

  • the CCE executable CharacteristicExtract
  • an example YAML input file
  • an example set of Bondi-Sachs worldtube data in the Tests/ directory (see Input worldtube data formats section)
  • example output from CCE in the Tests/ directory
  • a PreprocessCceWorldtube executable and YAML files for converting between worldtube data formats in the PreprocessCceWorldtube/ directory
  • a WriteCceWorldtubeCoordsToFile executable that writes grid points on a sphere to a text file in the PreprocessCceWorldtube/ directory
  • a python script CheckCceOutput.py (meant to be run from the root of the tarball and after you run the example YAML input file also in the root of the tarball) that will check if the example output is correct
Note
The tarball is .xz so use tar -xf TarName.tar.xz to extract. The -z flag to use gzip will cause an error.

See Running the CCE executable for how to run CCE.

We have tested that this executable works natively on the following machines:

  • Expanse
  • Anvil
  • Stampede3
  • Delta (if you add LD_LIBRARY_PATH=/sw/spack/deltas11-2023-03/apps/linux-rhel8-x86_64/gcc-8.5.0/gcc-11.4.0-yycklku/lib64/:$LD_LIBRARY_PATH before running CCE)
  • Perlmutter
  • Ubuntu 18.04 LTS or later (LTS version only)

We have also tested that this executable works inside our dev Docker container on the following machines (in addition to the ones above):

  • Frontera
  • Delta

From Docker

You can download a docker image sxscollaboration/spectre:deploy which has a few pre-built executables within, including the ones listed above in the release section. See the containerized releases section of our Installation instructions for how start the container.

The input files can be found within the container at /sxscollaboration/spectre/tests/InputFiles/.

From source

You can clone the spectre repo and follow the instructions on the Installation page to obtain an environment to configure and build SpECTRE. Once you have a configured build directory, build the CCE executable with

make CharacteristicExtract
Note
You may want to add the -j4 flag to speed up compilation. However, be warned that this executable will need several GB of memory to build.

Input worldtube data format

In order to run the CCE executable, the worldtube data must be represented as Bondi-Sachs variables decomposed as a subset of spin-weighted spherical harmonic modes on a sphere of constant coordinate radius. We have chosen this format because it is far more space-efficient to store on disk than other formats. This section will detail the required data format, provide options for converting worldtube data from other NR codes into our format, and give insights into what the worldtube data should look like.

Required H5 worldtube data format

Within the H5 file that holds the worldtube data, there must be the following datasets with these exact names (including the .dat suffix):

  • Beta.dat
  • DrJ.dat
  • DuR.dat
  • H.dat
  • J.dat
  • Q.dat
  • R.dat
  • U.dat
  • W.dat

Each dataset in the file must also have an attribute named Legend which is an ASCII-encoded null-terminated variable-length string. That is, the HDF5 type is:

DATATYPE H5T_STRING {
STRSIZE H5T_VARIABLE;
STRPAD H5T_STR_NULLTERM;
CSET H5T_CSET_ASCII;
CTYPE H5T_C_S1;
}

This can be checked for a dataset by running

h5dump -a Beta.dat/Legend WorldtubeFile.h5

For the ordering of the data, we use spherical harmonic conventions documented by the ylm::Spherepack class. Each row must start with the time stamp, and the remaining values are the complex modes in m-varies-fastest format. For spin-weight zero Bondi variables (Beta, R, DuR, W), we omit the redundant negative-m modes and imaginary parts of the m=0 modes to save space on disk. Here is an example of a legend for the spin-weight zero variables:

"time", "Re(0,0)", "Re(1,0)", "Re(1,1)", "Im(1,1)", "Re(2,0)",
"Re(2,1)", "Im(2,1)", "Re(2,2)", "Im(2,2)", "Re(3,0)", "Re(3,1)",
"Im(3,1)", "Re(3,2)", "Im(3,2)", "Re(3,3)", "Im(3,3)", ...

For non-zero spin-weight Bondi variables (J, DrJ, H, Q, U) we must store all complex m-modes. Here is an example of a legend for variables where all complex m-modes must be specified:

"time", "Re(0,0)", "Im(0,0)", "Re(1,-1)", "Im(1,-1)", "Re(1,0)", "Im(1,0)",
"Re(1,1)", "Im(1,1)", "Re(2,-2)", "Im(2,-2)", "Re(2,-1)", "Im(2,-1)", "Re(2,0)",
"Im(2,0)", "Re(2,1)", "Im(2,1)", "Re(2,2)", "Im(2,2)", ...

We don't have strict requirement on the name of the H5 file that holds the worldtube data. However, it is recommended to name the H5 file ...CceRXXXX.h5, where the XXXX is to be replaced by the zero-padded integer for which the extraction radius is equal to XXXXM. For instance, a 100M extraction should have filename ...CceR0100.h5. If you do not adhere to this naming convention, you will need to specify the extraction radius in your YAML input file.

Note
This scheme of labeling files with the extraction radius is constructed for compatibility with worldtube data from the SXS Collaboration's SpEC code.

Converting to the required H5 format

Unless you are using worldtube data that was generated from SpECTRE (or SpEC), it's possible that your worldtube data is not in the correct format. We allow conversion into our data format from a few other data formats using the `PreprocessCceWorldtube` executable provided. These are

  • Nodal cartesian metric data (which we refer to as "metric nodal")
  • Modal cartesian metric data (which we refer to as "metric modal")
  • Nodal Bondi-Sachs data (which we refer to as "bondi nodal")

Requirements for these data formats are listed below.

Spherical harmonic modes

When we refer to a "modal" data format, we mean that the worldtube data are stored as spherical harmonic coefficients (a.k.a. modes). We use spherical harmonic conventions documented by the ylm::Spherepack class. For each dataset, each row must start with the time stamp, and the remaining values are the complex modes in m-varies-fastest format. That is,

"time", "Re(0,0)", "Im(0,0)", "Re(1,-1)", "Im(1,-1)", "Re(1,0)", "Im(1,0)",
"Re(1,1)", "Im(1,1)", "Re(2,-2)", "Im(2,-2)", "Re(2,-1)", "Im(2,-1)", "Re(2,0)",
"Im(2,0)", "Re(2,1)", "Im(2,1)", "Re(2,2)", "Im(2,2)", ...

Each dataset in the H5 file must also have an attribute named Legend which is an ASCII-encoded null-terminated variable-length string.

Spherical harmonic nodes

When we refer to a "nodal" data format, we mean that the worldtube data are stored as values at specially chosen collocation points (a.k.a. grid points or nodes). This allows SpECTRE to perform integrals, derivatives, and interpolation exactly on the input data. These grid points are Gauss-Legendre in \(cos(\theta)\) and equally spaced in \(\phi\).

Below is a routine for computing the spherical harmonic \(\theta\) and \(\phi\) values. These can be used to compute the Cartesian locations for a given radius using the standard transformation. The routine supports \(\ell\in[4, 32]\).

C Code for computing SpECTRE CCE gridpoint locations
struct SpectreCceGridPointLocations {
int number_of_theta_points;
int number_of_phi_points;
// We use C-style arrays to avoid dealing with malloc/free and new/delete
// interoperability between different libraries.
double theta_points[33];
double phi_points[2 * 33 + 1];
};
SpectreCceGridPointLocations spectre_ylm_theta_phi_points(const int l_max) {
SpectreCceGridPointLocations result{};
if (l_max < 4 or l_max > 32) {
result.number_of_theta_points = 0;
result.number_of_phi_points = 0;
return result;
}
result.number_of_theta_points = l_max + 1;
result.number_of_phi_points = 2 * l_max + 1;
for (int i = 0; i < result.number_of_theta_points; ++i) {
switch (result.number_of_theta_points) {
case 5: {
const double temp[5] = {
4.366349492255221509e-01, 1.002176803643121561e+00,
1.570796326794896558e+00, 2.139415849946671777e+00,
2.704957704364271187e+00};
result.theta_points[i] = temp[i];
break;
}
case 6: {
const double temp[6] = {
3.696066519448289456e-01, 8.483666264874876184e-01,
1.329852612388110256e+00, 1.811740041201682860e+00,
2.293226027102305498e+00, 2.771986001644964226e+00};
result.theta_points[i] = temp[i];
break;
}
case 7: {
const double temp[7] = {
3.204050902900620335e-01, 7.354466143229519970e-01,
1.152892953722227221e+00, 1.570796326794896558e+00,
1.988699699867565895e+00, 2.406146039266841008e+00,
2.821187563299730972e+00};
result.theta_points[i] = temp[i];
break;
}
case 8: {
const double temp[8] = {
2.827570635937968202e-01, 6.490365804607796107e-01,
1.017455539490153438e+00, 1.386317078892131294e+00,
1.755275574697661822e+00, 2.124137114099639678e+00,
2.492556073129013505e+00, 2.858835589995996074e+00};
result.theta_points[i] = temp[i];
break;
}
case 9: {
const double temp[9] = {
2.530224166119307005e-01, 5.807869795060065510e-01,
9.104740292261472856e-01, 1.240573923404363343e+00,
1.570796326794896558e+00, 1.901018730185429773e+00,
2.231118624363645608e+00, 2.560805674083786343e+00,
2.888570236977862304e+00};
result.theta_points[i] = temp[i];
break;
}
case 10: {
const double temp[10] = {
2.289442988470259954e-01, 5.255196555285001070e-01,
8.238386589997556131e-01, 1.122539327631709494e+00,
1.421366498439524895e+00, 1.720226155150268221e+00,
2.019053325958083622e+00, 2.317753994590037614e+00,
2.616072998061293120e+00, 2.912648354742767065e+00};
result.theta_points[i] = temp[i];
break;
}
case 11: {
const double temp[11] = {
2.090492874137409585e-01, 4.798534223256742948e-01,
7.522519395990820978e-01, 1.025003226369574749e+00,
1.297877729331450292e+00, 1.570796326794896558e+00,
1.843714924258342824e+00, 2.116589427220218589e+00,
2.389340713990710796e+00, 2.661739231264118821e+00,
2.932543366176052047e+00};
result.theta_points[i] = temp[i];
break;
}
case 12: {
const double temp[12] = {
1.923346793046672165e-01, 4.414870814893317452e-01,
6.921076988818409825e-01, 9.430552870605736215e-01,
1.194120375947706592e+00, 1.445233238471440140e+00,
1.696359415118352976e+00, 1.947472277642086524e+00,
2.198537366529219383e+00, 2.449484954707952244e+00,
2.700105572100461426e+00, 2.949257974285125705e+00};
result.theta_points[i] = temp[i];
break;
}
case 13: {
const double temp[13] = {
1.780944581262765558e-01, 4.088002373420211999e-01,
6.408663264733868159e-01, 8.732366099401630555e-01,
1.105718066248490006e+00, 1.338247676100454475e+00,
1.570796326794896558e+00, 1.803344977489338641e+00,
2.035874587341303332e+00, 2.268356043649629949e+00,
2.500726327116406189e+00, 2.732792416247772138e+00,
2.963498195463516449e+00};
result.theta_points[i] = temp[i];
break;
}
case 14: {
const double temp[14] = {
1.658171411523663707e-01, 3.806189306666775130e-01,
5.966877608172733716e-01, 8.130407055389454740e-01,
1.029498592525136758e+00, 1.246003586776677663e+00,
1.462529992921481892e+00, 1.679062660668311224e+00,
1.895589066813115453e+00, 2.112094061064656358e+00,
2.328551948050847642e+00, 2.544904892772519744e+00,
2.760973722923115492e+00, 2.975775512437426773e+00};
result.theta_points[i] = temp[i];
break;
}
case 15: {
const double temp[15] = {
1.551231069747375235e-01, 3.560718303314724942e-01,
5.582062109125313087e-01, 7.606069572889918584e-01,
9.631067821301482201e-01, 1.165652065603030252e+00,
1.368219536992351770e+00, 1.570796326794896558e+00,
1.773373116597441346e+00, 1.975940587986762864e+00,
2.178485871459645118e+00, 2.380985696300801369e+00,
2.583386442677261918e+00, 2.785520823258320622e+00,
2.986469546615055481e+00};
result.theta_points[i] = temp[i];
break;
}
case 16: {
const double temp[16] = {
1.457246820036738055e-01, 3.344986386876292461e-01,
5.243866409035942144e-01, 7.145252532340252705e-01,
9.047575323895165056e-01, 1.095033401803444439e+00,
1.285331444322965311e+00, 1.475640280808194316e+00,
1.665952372781598800e+00, 1.856261209266827805e+00,
2.046559251786348455e+00, 2.236835121200276610e+00,
2.427067400355767735e+00, 2.617206012686199124e+00,
2.807094014902163703e+00, 2.995867971586119172e+00};
result.theta_points[i] = temp[i];
break;
}
case 17: {
const double temp[17] = {
1.373998952992547817e-01, 3.153898594929282484e-01,
4.944303818194982769e-01, 6.737074594242522529e-01,
8.530732514258505539e-01, 1.032480728417239479e+00,
1.211909966211469625e+00, 1.391350647015287434e+00,
1.570796326794896558e+00, 1.750242006574505682e+00,
1.929682687378323491e+00, 2.109111925172553637e+00,
2.288519402163942562e+00, 2.467885194165540863e+00,
2.647162271770294950e+00, 2.826202794096865034e+00,
3.004192758290538556e+00};
result.theta_points[i] = temp[i];
break;
}
case 18: {
const double temp[18] = {
1.299747364196768562e-01, 2.983460782092324792e-01,
4.677113145328286592e-01, 6.373005058706191495e-01,
8.069738930788195042e-01, 9.766871104439832640e-01,
1.146421481056642211e+00, 1.316167494718022635e+00,
1.485919440392653001e+00, 1.655673213197140115e+00,
1.825425158871770481e+00, 1.995171172533150905e+00,
2.164905543145809741e+00, 2.334618760510973612e+00,
2.504292147719174189e+00, 2.673881339056964457e+00,
2.843246575380560692e+00, 3.011617917170116066e+00};
result.theta_points[i] = temp[i];
break;
}
case 19: {
const double temp[19] = {
1.233108673082312784e-01, 2.830497588453067537e-01,
4.437316659960951482e-01, 6.046261769405451014e-01,
7.656007620508340494e-01, 9.266134127998189030e-01,
1.087646521650454945e+00, 1.248691224331339278e+00,
1.409742336767428883e+00, 1.570796326794896558e+00,
1.731850316822364233e+00, 1.892901429258453838e+00,
2.053946131939338393e+00, 2.214979240789974213e+00,
2.375991891538959067e+00, 2.536966476649248126e+00,
2.697860987593697857e+00, 2.858542894744486418e+00,
3.018281786281561629e+00};
result.theta_points[i] = temp[i];
break;
}
case 20: {
const double temp[20] = {
1.172969277059561499e-01, 2.692452880289302186e-01,
4.220907301111165855e-01, 5.751385026314284055e-01,
7.282625848696072657e-01, 8.814230742890135639e-01,
1.034603297590104276e+00, 1.187794926634099024e+00,
1.340993178589955148e+00, 1.494194914310399636e+00,
1.647397739279393480e+00, 1.800599474999837968e+00,
1.953797726955694092e+00, 2.106989355999688840e+00,
2.260169579300779663e+00, 2.413330068720185739e+00,
2.566454150958364711e+00, 2.719501923478676364e+00,
2.872347365560862897e+00, 3.024295725883836994e+00};
result.theta_points[i] = temp[i];
break;
}
case 21: {
const double temp[21] = {
1.118422651428890996e-01, 2.567245837448891010e-01,
4.024623099018152517e-01, 5.483930281810389662e-01,
6.943966110110700862e-01, 8.404350520135058789e-01,
9.864925055883793092e-01, 1.132561101012537597e+00,
1.278636375242898637e+00, 1.424715475176742796e+00,
1.570796326794896558e+00, 1.716877178413050320e+00,
1.862956278346894479e+00, 2.009031552577255297e+00,
2.155100148001413807e+00, 2.301157601576287348e+00,
2.447196042578723141e+00, 2.593199625408754372e+00,
2.739130343687977920e+00, 2.884868069844904070e+00,
3.029750388446903919e+00};
result.theta_points[i] = temp[i];
break;
}
case 22: {
const double temp[22] = {
1.068723357985259942e-01, 2.453165389983613109e-01,
3.845781703583910915e-01, 5.240242709487281658e-01,
6.635400754448063099e-01, 8.030892957063359150e-01,
9.426568273796608333e-01, 1.082235198111836771e+00,
1.221820208990359813e+00, 1.361409225664372169e+00,
1.501000399130816065e+00, 1.640592254458977051e+00,
1.780183427925420947e+00, 1.919772444599433303e+00,
2.059357455477956123e+00, 2.198935826210132394e+00,
2.338503357883457312e+00, 2.478052578144986917e+00,
2.617568382641064950e+00, 2.757014483231401858e+00,
2.896276114591431750e+00, 3.034720317791267163e+00};
result.theta_points[i] = temp[i];
break;
}
case 23: {
const double temp[23] = {
1.023252788872632685e-01, 2.348791589702580174e-01,
3.682157131008290119e-01, 5.017289283414202439e-01,
6.353089402976822564e-01, 7.689210263823624825e-01,
9.025507517347876041e-01, 1.036190996404462217e+00,
1.169837785762829929e+00, 1.303488659735581257e+00,
1.437141935303526186e+00, 1.570796326794896558e+00,
1.704450718286266930e+00, 1.838103993854211859e+00,
1.971754867826963187e+00, 2.105401657185330677e+00,
2.239041901855005623e+00, 2.372671627207430411e+00,
2.506283713292110971e+00, 2.639863725248372983e+00,
2.773376940488963882e+00, 2.906713494619534988e+00,
3.039267374702530056e+00};
result.theta_points[i] = temp[i];
break;
}
case 24: {
const double temp[24] = {
9.814932949793685191e-02, 2.252936226353075833e-01,
3.531886675690780741e-01, 4.812531951313686607e-01,
6.093818382449566196e-01, 7.375413075437535770e-01,
8.657177770401081052e-01, 9.939044422989454786e-01,
1.122097523267250763e+00, 1.250294703417273112e+00,
1.378494427506219200e+00, 1.506695545558101035e+00,
1.634897108031692081e+00, 1.763098226083573916e+00,
1.891297950172520004e+00, 2.019495130322542131e+00,
2.147688211290847526e+00, 2.275874876549685233e+00,
2.404051346046039761e+00, 2.532210815344836607e+00,
2.660339458458424566e+00, 2.788403986020715042e+00,
2.916299030954485616e+00, 3.043443324091856361e+00};
result.theta_points[i] = temp[i];
break;
}
case 25: {
const double temp[25] = {
9.430083986305520805e-02, 2.164597408964339387e-01,
3.393399712563371362e-01, 4.623830630132757524e-01,
5.854877911108011812e-01, 7.086221837538611013e-01,
8.317729718814276252e-01, 9.549336362382321308e-01,
1.078100568411879845e+00, 1.201271573324181219e+00,
1.324445197736386692e+00, 1.447620393135667038e+00,
1.570796326794896558e+00, 1.693972260454126078e+00,
1.817147455853406424e+00, 1.940321080265611897e+00,
2.063492085177913271e+00, 2.186659017351560763e+00,
2.309819681708365380e+00, 2.432970469835932015e+00,
2.556104862478991713e+00, 2.679209590576517197e+00,
2.802252682333456146e+00, 2.925132912693359177e+00,
3.047291813726737963e+00};
result.theta_points[i] = temp[i];
break;
}
case 26: {
const double temp[26] = {
9.074274842993197698e-02, 2.082924425598466356e-01,
3.265362611165358309e-01, 4.449368152119130282e-01,
5.633967073169293682e-01, 6.818851814129298639e-01,
8.003894803353296394e-01, 9.189033445598993044e-01,
1.037423319077439121e+00, 1.155947313793812103e+00,
1.274473959424494041e+00, 1.393002286179807925e+00,
1.511531546703289264e+00, 1.630061106886503852e+00,
1.748590367409985191e+00, 1.867118694165299075e+00,
1.985645339795981013e+00, 2.104169334512353995e+00,
2.222689309029894034e+00, 2.341203173254463366e+00,
2.459707472176863252e+00, 2.578195946272863637e+00,
2.696655838377880254e+00, 2.815056392473257230e+00,
2.933300211029946425e+00, 3.050849905159861208e+00};
result.theta_points[i] = temp[i];
break;
}
case 27: {
const double temp[27] = {
8.744338280630299665e-02, 2.007190266590380412e-01,
3.146635662674374112e-01, 4.287591577660783693e-01,
5.429119513798658092e-01, 6.570923167092416195e-01,
7.712879690777516561e-01, 8.854928869950799974e-01,
9.997037539874953360e-01, 1.113918572282611930e+00,
1.228136043468909699e+00, 1.342355260834552144e+00,
1.456575541704195897e+00, 1.570796326794896558e+00,
1.685017111885597219e+00, 1.799237392755240972e+00,
1.913456610120883417e+00, 2.027674081307181186e+00,
2.141888899602297780e+00, 2.256099766594712897e+00,
2.370304684512041682e+00, 2.484500336880551608e+00,
2.598680702209927418e+00, 2.712833495823714802e+00,
2.826929087322355816e+00, 2.940873626930755158e+00,
3.054149270783490078e+00};
result.theta_points[i] = temp[i];
break;
}
case 28: {
const double temp[28] = {
8.437551461511597073e-02, 1.936769929947376179e-01,
3.036239070914333316e-01, 4.137165857369637378e-01,
5.238644768825679865e-01, 6.340389954584301213e-01,
7.442282945111358128e-01, 8.544265718392254350e-01,
9.646306371285441328e-01, 1.074838574917869272e+00,
1.185049147889021492e+00, 1.295261501292316098e+00,
1.405475003062348627e+00, 1.515689149557281068e+00,
1.625903504032512048e+00, 1.736117650527444489e+00,
1.846331152297477018e+00, 1.956543505700771624e+00,
2.066754078671923622e+00, 2.176962016461248872e+00,
2.287166081750567681e+00, 2.397364359078657081e+00,
2.507553658131362884e+00, 2.617728176707225352e+00,
2.727876067852829323e+00, 2.837968746498359618e+00,
2.947915660595055609e+00, 3.057217138974677173e+00};
result.theta_points[i] = temp[i];
break;
}
case 29: {
const double temp[29] = {
8.151560650977880684e-02, 1.871123137498062194e-01,
2.933325857619472621e-01, 3.996936914666951446e-01,
5.061081521563000063e-01, 6.125483562383020608e-01,
7.190028636037067988e-01, 8.254660749671546283e-01,
9.319349156915986976e-01, 1.038407544520296710e+00,
1.144882777708662536e+00, 1.251359804334884807e+00,
1.357838033080061679e+00, 1.464317002991565309e+00,
1.570796326794896558e+00, 1.677275650598227807e+00,
1.783754620509731437e+00, 1.890232849254908309e+00,
1.996709875881130580e+00, 2.103185109069496406e+00,
2.209657737898194529e+00, 2.316126578622638377e+00,
2.422589789986086206e+00, 2.529044297351490833e+00,
2.635484501433492888e+00, 2.741898962123098027e+00,
2.848260067827845798e+00, 2.954480339839987035e+00,
3.060077047080014268e+00};
result.theta_points[i] = temp[i];
break;
}
case 30: {
const double temp[30] = {
7.884320726554944203e-02, 1.809780449917272049e-01,
2.837160095793466730e-01, 3.865901987860504985e-01,
4.895160050896970039e-01, 5.924667257887386018e-01,
6.954313000299366943e-01, 7.984043170121235544e-01,
9.013828087667156153e-01, 1.004365001539081037e+00,
1.107349759228459130e+00, 1.210336308624476498e+00,
1.313324092045794700e+00, 1.416312682230741693e+00,
1.519301729274526558e+00, 1.622290924315266558e+00,
1.725279971359051423e+00, 1.828268561543998416e+00,
1.931256344965316618e+00, 2.034242894361334208e+00,
2.137227652050712301e+00, 2.240209844823077390e+00,
2.343188336577669340e+00, 2.446161353559856533e+00,
2.549125927801054736e+00, 2.652076648500095946e+00,
2.755002454803742395e+00, 2.857876644010446388e+00,
2.960614608598065800e+00, 3.062749446324243507e+00};
result.theta_points[i] = temp[i];
break;
}
case 31: {
const double temp[31] = {
7.634046205384431572e-02, 1.752332025619508515e-01,
2.747099287638327669e-01, 3.743185619229329464e-01,
4.739771829190733698e-01, 5.736599396529727946e-01,
6.733561257504194764e-01, 7.730605060747958168e-01,
8.727702114891848773e-01, 9.724835301003497134e-01,
1.072199368669106478e+00, 1.171916986981363706e+00,
1.271635855736122256e+00, 1.371355574944659095e+00,
1.471075823713997366e+00, 1.570796326794896558e+00,
1.670516829875795750e+00, 1.770237078645134021e+00,
1.869956797853670860e+00, 1.969675666608429410e+00,
2.069393284920686860e+00, 2.169109123489443292e+00,
2.268822442100608239e+00, 2.368532147514997188e+00,
2.468236527839373640e+00, 2.567932713936820210e+00,
2.667615470670719802e+00, 2.767274091666860336e+00,
2.866882724825960516e+00, 2.966359451027842375e+00,
3.065252191535948967e+00};
result.theta_points[i] = temp[i];
break;
}
case 32: {
const double temp[32] = {
7.399171309970958843e-02, 1.698418454282150103e-01,
2.662579994723859311e-01, 3.628020075350028018e-01,
4.593944730762095641e-01, 5.560103418005302167e-01,
6.526392394594561219e-01, 7.492760951181414164e-01,
8.459181315837993598e-01, 9.425636940046776546e-01,
1.039211728068951679e+00, 1.135861522840293736e+00,
1.232512573416362889e+00, 1.329164502391080749e+00,
1.425817011963825376e+00, 1.522469852641529231e+00,
1.619122800948263885e+00, 1.715775641625967740e+00,
1.812428151198712367e+00, 1.909080080173430227e+00,
2.005731130749499158e+00, 2.102380925520841437e+00,
2.199028959585115572e+00, 2.295674522005993978e+00,
2.392316558471651700e+00, 2.488953414130337105e+00,
2.585582311789262899e+00, 2.682198180513583718e+00,
2.778790646054790425e+00, 2.875334654117406963e+00,
2.971750808161578217e+00, 3.067600940490083694e+00};
result.theta_points[i] = temp[i];
break;
}
case 33: {
const double temp[33] = {
7.178317184275122276e-02, 1.647723231643112574e-01,
2.583106041071417946e-01, 3.519729273095236199e-01,
4.456822679082866334e-01, 5.394143214244183637e-01,
6.331590254855161692e-01, 7.269114630504562857e-01,
8.206689427646121082e-01, 9.144298626454031576e-01,
1.008193204014774080e+00, 1.101958282220461438e+00,
1.195724613675799519e+00, 1.289491840051302685e+00,
1.383259682348271680e+00, 1.477027911291552309e+00,
1.570796326794896558e+00, 1.664564742298240807e+00,
1.758332971241521436e+00, 1.852100813538490431e+00,
1.945868039913993597e+00, 2.039634371369331678e+00,
2.133399449575018814e+00, 2.227162790944389847e+00,
2.320923710825181008e+00, 2.414681190539337052e+00,
2.508433628104277169e+00, 2.602178332165374641e+00,
2.695910385681506316e+00, 2.789619726280269330e+00,
2.883282049482651210e+00, 2.976820330425481664e+00,
3.069809481747042046e+00};
result.theta_points[i] = temp[i];
break;
}
default: {
result.number_of_theta_points = 0;
result.number_of_phi_points = 0;
break;
}
}
}
const double d_phi = (2.0 * M_PI) / result.number_of_phi_points;
for (int i = 0; i < result.number_of_phi_points; ++i) {
result.phi_points[i] = i * d_phi;
}
return result;
}

Alternatively, if your code can read in grid points from a text file, you can run the WriteCceWorldtubeCoordsToFile executable like so to get a text file with three columns for the x,y,z coordinates of each point.

./WriteCceWorldtubeCoordsToFile -r 200 -L 16 -o GridPointsR200.txt

Each dataset holds 1 + (l_max + 1) * (2 * l_max + 1) columns, with the first one being the time. The columns must be in \(\theta\)-varies-fastest ordering. That is,

"time",
"Phi_0_Theta_0", "Phi_0_Theta_1", "Phi_0_Theta_2", "Phi_0_Theta_3", "Phi_0_Theta_4",
"Phi_1_Theta_0", "Phi_1_Theta_1", "Phi_1_Theta_2", "Phi_1_Theta_3", "Phi_1_Theta_4",

Each dataset in the H5 file must also have an attribute named Legend which is an ASCII-encoded null-terminated variable-length string.

Note
Nodal data is likely the easiest to write out since no conversion to spherical harmonic coefficients is necessary.

ADM Cartesian metric and derivatives

For worldtube data stored in an H5 file in the "ADM metric nodal" format, there must be the following datasets with these exact names (including the .dat suffix):

  • gxx.dat, gxy.dat, gxz.dat, gyy.dat, gyz.dat, gzz.dat
  • Dxgxx.dat, Dxgxy.dat, Dxgxz.dat, Dxgyy.dat, Dxgyz.dat, Dxgzz.dat
  • Dygxx.dat, Dygxy.dat, Dygxz.dat, Dygyy.dat, Dygyz.dat, Dygzz.dat
  • Dzgxx.dat, Dzgxy.dat, Dzgxz.dat, Dzgyy.dat, Dzgyz.dat, Dzgzz.dat
  • Shiftx.dat, Shifty.dat, Shiftz.dat
  • DxShiftx.dat, DxShifty.dat, DxShiftz.dat
  • DyShiftx.dat, DyShifty.dat, DyShiftz.dat
  • DzShiftx.dat, DzShifty.dat, DzShiftz.dat
  • Lapse.dat, DxLapse.dat, DyLapse.dat, DzLapse.dat
  • Kxx.dat, Kxy.dat, Kxz.dat, Kyy.dat, Kyz.dat, Kzz.dat
  • Either: AuxiliaryShiftx.dat, AuxiliaryShifty.dat, AuxiliaryShiftz.dat
  • Or: ConformalChristoffelx.dat, ConformalChristoffely.dat, ConformalChristoffelz.dat

Here g represents the spacetime metric, but we only require the spatial components (e.g. gxx.dat, gxy.dat, etc...) so in practice, those are the tensor components of the spatial metric. The temporal components of the spacetime metric are stored separately in the lapse and shift. Each of the spatial metric, lapse, and shift must also have their cartesian derivatives. K is the extrinsic curvature, AuxiliaryShift is the auxiliary shift vector used in the first-order form of the Gamma-driver condition, and ConformalChristoffel is the trace of the conformal second_order symbols.

We will compute the time derivative of the spatial metric using Eq. (2.134) of [14],

\begin{equation}\partial_t \gamma_{ij} = -2\alpha K_{ij} + D_i\beta_j + D_j\beta_i. \end{equation}

The time derivative of the lapse is computed using the 1+log slicing condition from Eq. (4.87) of [14]

\begin{equation}\partial_t \alpha = -2\alpha K + \beta^j\partial_j\alpha, \end{equation}

and the time derivative of the shift is computed using either the first order reduction form of the Gamma-driver condition from Eq. (4.89) of [14]

\begin{equation}\partial_t \beta^i = \eta B^i + \beta^j\partial_j\beta^i, \end{equation}

where you can choose \(\eta\) (typically \(\eta=0.75\)) or using the integrated Gamma-driver condition from Eq. (12) of [105]

\begin{equation}\partial_t \beta^i = \tilde{\Gamma}^i - \eta\beta^i + \beta^j\partial_j\beta^i, \end{equation}

again, where you can choose \(\eta\) (typically \(\eta=2/M_{\textrm{ADM}}\)).

Warning
If your worldtube data is in the ADM metric nodal format but you have not used 1+log slicing and the Gamma-driver conditions specified above, your time derivatives will be wrong. If you'd like us to support other commonly used gauge conditions (or variants of 1+log or Gamma-driver), please open an issue on our GitHub.

The layout of each of these datasets must be spherical harmonic nodes.

Cartesian metric and derivatives

For worldtube data stored in an H5 file in either the "metric nodal" or "metric modal" formats, there must be the following datasets with these exact names (including the .dat suffix):

  • gxx.dat, gxy.dat, gxz.dat, gyy.dat, gyz.dat, gzz.dat
  • Drgxx.dat, Drgxy.dat, Drgxz.dat, Drgyy.dat, Drgyz.dat, Drgzz.dat
  • Dtgxx.dat, Dtgxy.dat, Dtgxz.dat, Dtgyy.dat, Dtgyz.dat, Dtgzz.dat
  • Shiftx.dat, Shifty.dat, Shiftz.dat
  • DrShiftx.dat, DrShifty.dat, DrShiftz.dat
  • DtShiftx.dat, DtShifty.dat, DtShiftz.dat
  • Lapse.dat
  • DrLapse.dat
  • DtLapse.dat

Here g represents the spacetime metric, but we only require the spatial components (e.g. gxx.dat, gxy.dat, etc...) so in practice, those are the tensor components of the spatial metric. The temporal components of the spacetime metric are stored separately in the lapse and shift. The layout of each of these datasets must be in either spherical harmonic modes or spherical harmonic nodes.

Bondi-Sachs

In the "bondi nodal" format, you must have the same Bondi variables as the required format, but each variable layout must be the spherical harmonic nodal layout with complex values interleaved as Re, Im, Re, Im, ...

If you already have data in the required "bondi modal" format, then nothing needs to be done.

Running the PreprocessCceWorldtube executable

The PreprocessCceWorldtube executable should be run on any of the allowed input formats, and will produce a corresponding Bondi-Sachs worldtube file that can be read in by CCE. This executable works similarly to our other executables by accepting a YAML input file:

PreprocessCceWorldtube --input-file PreprocessCceWorldtube.yaml

with a YAML file

InputH5File: InputFilename.h5
OutputH5File: ReducedWorldtubeR0292.h5
InputDataFormat: MetricModal
ExtractionRadius: 292
FixSpecNormalization: False
DescendingM: False
BufferDepth: Auto
LMaxFactor: 3

In addition to converting worldtube data formats, PreprocessCceWorldtube also accepts multiple input worldtube H5 files that have sequential times (e.g. from different checkpoints) and will combine the times from all H5 files alongside converting the worldtube data format. If there are duplicate or overlapping times, the last/latest of the times are chosen. If you pass multiple input worldtube H5 files, it is assumed that they are ordered increasing in time.

Here are some notes about the different options in the YAML input file:

  • If the extraction radius is in the InputH5File names, then the ExtractionRadius option can be Auto. Otherwise, it must be specified.
  • The option LMaxFactor determines the factor by which the resolution of the boundary computation that is run will exceed the resolution of the input and output files. Empirically, we have found that LMaxFactor of 3 is sufficient to achieve roundoff precision in all boundary data we have attempted, and an LMaxFactor of 2 is usually sufficient to vastly exceed the precision of the simulation that provided the boundary dataset.
  • FixSpecNormalization should always be False unless you are using a particualy old version of SpEC
  • DescendingM should always be False. This option is to support metric modal data from SpEC. Our data format is always in ascending m.
  • BufferDepth is an advanced option that lets you load more data into RAM at once so there are fewer filesystem accesses.
  • If using the ADM metric nodal input data format with a first-order form gamma driver, specify the InputDataFormat: like so:
    InputDataFormat:
    AdmMetricNodal:
    Lapse:
    Advective: True
    Shift:
    Advective: True
    FirstOrderDriverFactor: 0.75 # Eq. 4.89 B&S
  • If using the ADM metric nodal input data format with an integrated gamma driver, specify the InputDataFormat: like so:
    InputDataFormat:
    AdmMetricNodal:
    Lapse:
    Advective: True
    Shift:
    Advective: True
    ConformalChristoffelFactor: 1.0 # Eq. 12 Hilditch 2013
    SecondOrderDriverEta: 2.0 # Eq. 12 Hilditch 2013

What Worldtube data "should" look like

While no two simulations will look exactly the same, there are some general trends in the worldtube data to look for. Here is a plot of some modes of the Bondi variable J from the Bondi-Sachs worldtube format.

Bondi variable J on the Worldtube

The 2,2 modes are oscillatory and capture the orbits of the two objects. The real part of the 2,0 mode contains the gravitational memory of the system. Then for this system, all the other modes are subdominant.

If you are using the cartesian metric or adm cartesian metric worldtube format, here is a plot of the imaginary part of the 2,2 mode of the lapse and its radial and time derivative during inspiral.

2,2 component of lapse and its radial and time derivative

One thing to keep in mind with this plot is that it was produced using the Generalized Harmonic formulation of Einstein's equations using the damped harmonic gauge. Therefore, if you are using a different formulation and gauge (like BSSN + moving punctures), the lapse may look different than this. One way to sanity check your data (regardless of what type it is or where you got it from) is to look and how the mode amplitude for a given quantity decays as you increase (l,m). Here is a plot of the amplitude of the modes for the lapse in the above plot.

Amplitude of modes of Lapse

You'll notice that most modes are around machine precision and only the first few have any real impact. This is expected.

Input file for CCE

Input files for CCE are commonly named CharacteristicExtract.yaml. An example input file with comments explaining some of the options can be found in $SPECTRE_HOME/tests/InputFiles/Cce/CharacteristicExtract.yaml. Here we expand a bit on why we chose some of those parameters.

General options

  • For resolution, the example input file has lmax (Cce.LMax) of 20, and filter lmax (Filtering.FilterLMax) of 18; that may run a bit slow for basic tests, but this value yields the best precision-to-run-time ratio for a typical BBH system. Note that precision doesn't improve above lmax 24, filter 22 (be sure to update the filter as you update lmax – the filter should generally be around 2 lower than the maximum l to reduce possible aliasing).
  • If you want to just run over all times in the worldtube H5 file, you can set both the StartTime and EndTime to Auto and it will automatically figure it out based on the data in the worldtube file.
  • The ScriOutputDensity adds extra interpolation points to the output, which is useful for finite-difference derivatives on the output data, but otherwise it'll just unnecessarily inflate the output files, so if you don't need the extra points, best just set it to 1.
  • For production level runs, it's recommended to have the Cce.Evolution.StepChoosers.Constant option set to 0.1 for an accurate time evolution. However, if you're just testing, this can be increased to 0.5 to speed things up.
  • We generally do not recommend extracting at less than 100M due to the CCE junk radiation being much worse at these smaller worldtube radii. That being said, we also recommend running CCE over several worldtube radii and checking which is the best based on the Bianchi identity violations. There isn't necessarily a "best radius" to extract waveforms at.
  • Most users will not need it, but if you want to dump data from the volume (instead of only on future null infinity), this is possible with the ObserveFields option to Events within EventsAndTriggersAtSlabs in the input file. See the input file referenced above for a (commented-out) example, and the documentation of the class Cce::Events::ObserveFields for details.

Initial data on the null hypersurface

CauchySecondOrder, described below, is the best method to choose the initial data on the null hypersurface, and the example input file uses it. If it fails for your worldtube data, the following methods are available as fallbacks, in order of preference:

  • ConformalFactor: Try to make initial time coordinate as inertial as possible at \(\mathscr{I}^+\) with a smart choice of the conformal factor. This works for many cases, but not all.
  • InverseCubic: Ansatz where \(J = A/r + B/r^3\). This is very robust and almost never fails, but contains a lot of CCE junk radiation compared to ConformalFactor.
  • ZeroNonSmooth: Make J vanish. Like the name says, it's not smooth.
  • NoIncomingRadiation: Make \(\Psi_0 = 0\); this does not actually lead to no incoming radiation, since \(\Psi_0\) and \(\Psi_4\) both include incoming and outgoing radiation.

CauchySecondOrder

CCE works in the compactified radial coordinate \(\tilde y = 1 - 2R/r\), where \(R\) is the worldtube radius, so that the worldtube \(\Gamma\) is at \(\tilde y = -1\) and \(\mathscr{I}^+\) is at \(\tilde y = 1\). Here \(\tilde J\) denotes \(J\) in the Cauchy coordinates, built on the worldtube from the Cauchy angular coordinates, and \(\breve J\) its counterpart in the partially flat coordinates used for the evolution. \(\tilde J^{(n)}\) and \(\breve J^{(n)}\) are their coefficients of \((1 - \tilde y)^n\). The initial data must satisfy the partially flat conditions \(\breve J^{(0)} = 0\) and \(\breve J^{(2)} = 0\). Both coefficients then remain zero throughout the evolution, which in the partially flat gauge prevents logarithmic terms from arising.

CauchySecondOrder matches the initial \(\tilde J\) on the initial null hypersurface \(\Sigma_0\) to the worldtube value \(\tilde J|_\Gamma\) and its first two radial derivatives in the Cauchy gauge, using the ansatz

\begin{align*} \tilde J(\tilde y; x) = \tilde J^{(0)}(x) + \tilde J^{(1)}(x)\,(1 - \tilde y) + x\,(1 - \tilde y)^2 + \tilde J^{(3)}(x)\,(1 - \tilde y)^3 . \end{align*}

The three matching conditions determine \(\tilde J^{(0)}\), \(\tilde J^{(1)}\) and \(\tilde J^{(3)}\) as functions of \(x = \tilde J^{(2)}\), which is left to be determined by the remaining partially flat condition \(\breve J^{(2)} = 0\). Expressed in Cauchy-gauge quantities, this condition is a nonlinear equation \(x = \Phi(x)\). It is solved by iterating \(x_{k+1} = \Phi(x_k)\) from \(x_0 = 0\) until the largest change in \(x\) over the angular collocation points falls below J2Tolerance.

Of the required radial derivatives, the Cauchy simulation supplies only \(\partial_r J|_\Gamma\), or equivalently \(\partial_{\tilde y}\tilde J|_\Gamma = (R/2)\,\partial_r J|_\Gamma\). The second derivative \(\partial_{\tilde y}^2\tilde J|_\Gamma\) is obtained by inverting the characteristic \(H\)-hypersurface equation at the worldtube, which uses only quantities already stored in the worldtube data, together with the time derivative \(\partial_{\tilde u}\partial_r J|_\Gamma\). This time derivative is computed by interpolating the stored time series of \(\partial_r J|_\Gamma\) and differentiating the interpolant.

With these, the construction consists of three steps:

  1. Match the initial \(\tilde J\) on \(\Sigma_0\) to the worldtube value and its first two radial derivatives in the Cauchy gauge, and solve the fixed-point problem for \(x\).
  2. Use the resulting \(\tilde J^{(0)}\) to solve the Beltrami problem \(\breve J^{(0)} = 0\) for the initial angular map \(\hat\phi^{\hat A}(u_0, \phi^A)\) from the Cauchy to the partially flat angular coordinates.
  3. Transform the whole profile into the partially flat gauge with this map.

The transformed profile preserves the worldtube matching and satisfies both partially flat conditions: \(\breve J^{(0)} = 0\) through the angular map and \(\breve J^{(2)} = 0\) through the root \(x\).

In step 2, the condition \(\breve J^{(0)} = 0\) is solved in closed form at each angular point, which specifies the target angular Jacobian of the map at every point of the sphere. The map is then recovered iteratively. A potential-based solve generates each displacement of the map from a single spin-weight-1 potential, determined by the difference between the current and the target Jacobian, and reaches its minimum residual within a few iterations. If that does not bring \(\max|\breve J^{(0)}|\) below MaxPartiallyFlatJ0, linearized iterations continue from its map until \(\max|\breve J^{(0)}|\) stops improving.

The options of CauchySecondOrder are:

  • MaxPartiallyFlatJ0: the largest \(\max|\breve J^{(0)}|\) accepted after step 3.
  • J0MaxIterations: the largest number of iterations of the angular solve of step 2, potential-based and linearized together.
  • MaxCauchyJ0: the largest \(\max|\tilde J^{(0)}|\) accepted, which also bounds \(\max|\breve J^{(0)}|\) during the iterations of step 2.
  • J2Tolerance: the tolerance on the largest change in \(x\) at which the fixed-point iteration of step 1 stops.
  • J2MaxIterations: initialization aborts if the fixed-point iteration does not reach J2Tolerance within this many iterations.
  • MaxPartiallyFlatJ2: the largest \(\max|\breve J^{(2)}|\) accepted after step 3.
  • DuDrJInterpolator: the interpolator of the stored time series of \(\partial_r J|_\Gamma\) whose derivative gives \(\partial_{\tilde u}\partial_r J|_\Gamma\). The high-order barycentric interpolant used for the worldtube data (H5Interpolator) can introduce numerical artifacts when the evolution starts at \(t_0 = 0\) with large worldtube data at very small extraction radii. These artifacts can distort the spin-weighted spherical harmonic mode content of \(\partial_{\tilde u}\partial_r J|_\Gamma\) enough to prevent the angular solve from finding a solution. Second-order interpolation resolves these problems while giving numerically indistinguishable results for well-behaved simulations. DuDrJInterpolator must not use a wider stencil than H5Interpolator.

After building the initial data, CauchySecondOrder prints a summary of steps 1 and 2 and of \(\max|\breve J^{(0)}|\) and \(\max|\breve J^{(2)}|\) over the angular grid. In it, the Cauchy-gauge \(J^{(2)}\) is \(x\), and the partially flat \(J^{(0)}\) and \(J^{(2)}\) are \(\breve J^{(0)}\) and \(\breve J^{(2)}\). For a binary black hole worldtube at \(R = 100M\) with LMax: 20 it reads, for example (long lines wrapped):

CauchySecondOrder initial data:
Cauchy-gauge J^(2) fixed point: 2 iterations, last change of J^(2)
6.828636e-17 (J2Tolerance 1.000000e-14)
partially flat J^(0) angular solve: 1394 iterations = 4 potential
iterations (reaching max|J^(0)| 3.387280e-11) + 1390 linearized sweeps
partially flat constraints: max|J^(0)| = 1.6469519047383257e-12
(MaxPartiallyFlatJ0 5.000000e-12), max|J^(2)| = 2.0354096531992744e-15
(MaxPartiallyFlatJ2 1.000000e-12)

Initialization stops if \(\max|\breve J^{(0)}|\) exceeds MaxPartiallyFlatJ0 or \(\max|\breve J^{(2)}|\) exceeds MaxPartiallyFlatJ2. The angular solve can bring \(\breve J^{(0)}\) only down to a floor, which rises with the size of \(\tilde J^{(0)}\), so it is mostly a concern for worldtubes at small extraction radii. When \(\max|\breve J^{(0)}|\) cannot reach MaxPartiallyFlatJ0, the worldtube data are usually the cause: the spherical-harmonic modes of \(J\) do not decay with \(\ell\). Raising the CCE LMax lowers the floor only if the modes still decay beyond the current LMax. If the error reports that \(\max|\breve J^{(0)}|\) had stopped improving, raising J0MaxIterations does not help either. Instead, use a worldtube at a larger extraction radius, or raise MaxPartiallyFlatJ0 to sit just above the reported \(\max|\breve J^{(0)}|\).

Rechunking worldtube data

Note
This section is less important than the others and really only matters if you will be doing a large number of CCE runs like for a catalog. For only a couple runs or just for testing, this part is unnecessary and can be skipped.

CCE will run faster if the input worldtube hdf5 file is chunked in small numbers of complete rows. This is relevant because by default, SpEC and SpECTRE write their worldtube files chunked along full time-series columns, which is efficient for writing and compression, but not for reading in to CCE. In that case, you can rechunk the input file before running CCE for maximum performance. This can be done, for instance, using h5py (you will need to fill in filenames appropriate to your case in place of "BondiCceR0050.h5" and "RechunkBondiCceR0050.h5"):

import h5py
input_file = "BondiCceR0050.h5"
output_file = "RechunkBondiCceR0050.h5"
with h5py.File(input_file,'r') as input_h5,\
h5py.File(output_file, 'w') as output_h5:
for dset in input_h5:
if("Version" in dset):
output_h5[dset] = input_h5[dset][()]
continue
number_of_columns = input_h5[dset][()].shape[1]
output_h5.create_dataset(dset, data=input_h5[dset],
maxshape=(None, number_of_columns),
chunks=(4, number_of_columns), dtype='d')
for attribute in input_h5[dset].attrs.keys():
output_h5[dset].attrs[attribute] = input_h5[dset].attrs[attribute]

The rechunked data will still be in the same format as before, but will just have a different underlying structure in the H5 file that makes it faster to read in.

Running the CCE executable

Once you have acquired an executable, running CCE in a supported environment is a simple command:

./CharacteristicExtract --input-file CharacteristicExtract.yaml

The initial data are built first. CauchySecondOrder prints a summary of them and stops if they do not meet its tolerances.

After this, you'll likely see some output like

Simulation time: 10.000000
Wall time: 00:00:44
Simulation time: 20.000000
Wall time: 00:01:14

which tells you that the simulation is proceeding as expected. When the run finished, you'll see something like

Done!
Wall time: 06:01:41
Date and time at completion: Thu May 23 22:31:27 2024
[Partition 0][Node 0] End of program

In terms of runtime, we've found that for a ~5000M long cauchy simulation, CCE takes about 6 hours to run. This will vary based on a number of factors like how long the cauchy evolution actually is, the desired error tolerance of your characteristic timestepper, and also how much data you output at future null infinity. Therefore, take these numbers with a grain of salt and only use them as a rough estimate for how long a job will take.

Note
CCE can technically run on two (2) cores by adding the option ++ppn 2 to the above command, however, we have found in practice that this makes little-to-no difference in the runtime of the executable.

Output from CCE

Once you have the reduction data output file from a successful CCE run, you can confirm the integrity of the h5 file and its contents by running

h5ls -r CharacteristicExtractReduction.h5

For the reduction file produced by a successful run, the output of the h5ls should resemble

/SpectreR0100.cce Group
/SpectreR0100.cce/EthInertialRetardedTime Dataset {26451/Inf, 163}
/SpectreR0100.cce/News Dataset {26451/Inf, 163}
/SpectreR0100.cce/Psi0 Dataset {26451/Inf, 163}
/SpectreR0100.cce/Psi1 Dataset {26451/Inf, 163}
/SpectreR0100.cce/Psi2 Dataset {26451/Inf, 163}
/SpectreR0100.cce/Psi3 Dataset {26451/Inf, 163}
/SpectreR0100.cce/Psi4 Dataset {26451/Inf, 163}
/SpectreR0100.cce/Strain Dataset {26451/Inf, 163}
/src.tar.gz Dataset {7757329}

Notice that the worldtube radius will be encoded into the subfile name.

Note
Prior to this Pull Request, merged May 15, 2024, the output of h5ls looked like this
/ Group
/Cce Group
/Cce/EthInertialRetardedTime.dat Dataset {3995/Inf, 163}
/Cce/News.dat Dataset {3995/Inf, 163}
/Cce/Psi0.dat Dataset {3995/Inf, 163}
/Cce/Psi1.dat Dataset {3995/Inf, 163}
/Cce/Psi2.dat Dataset {3995/Inf, 163}
/Cce/Psi3.dat Dataset {3995/Inf, 163}
/Cce/Psi4.dat Dataset {3995/Inf, 163}
/Cce/Strain.dat Dataset {3995/Inf, 163}
/src.tar.gz Dataset {3750199}

No matter the spin weight of the quantity, the \(\ell = 0,1\) modes will always be output by CCE. Also, the /SpectreR0100.cce group will have a legend attribute that specifies the columns.

Raw CCE output

The Strain represents the asymptotic transverse-traceless contribution to the metric scaled by the Bondi radius (to give the asymptotically leading part), the News represents the first time derivative of the strain, and each of the Psi... datasets represent the Weyl scalars, each scaled by the appropriate factor of the Bondi-Sachs radius to retrieve the asymptotically leading contribution.

The EthInertialRetardedTime is a diagnostic dataset that represents the angular derivative of the inertial retarded time, which determines the coordinate transformation that is performed at future null infinity.

If you'd like to visualize the output of a CCE run, we offer a CLI that will produce a plot of all of quantities except EthInertialRetardedTime. To see how to use this CLI, run

spectre plot cce -h

If you'd like to do something more complicated than just make a quick plot, you'll have to load in the output data yourself using h5py or our spectre.IO.H5 bindings.

Note
The CLI can also plot the "old" version of CCE output, described above. Pass --cce-group Cce to the CLI. This option is only for backwards compatibility with the old CCE output and is not supported for the current version of output. This options is deprecated and will be removed in the future.

Frame fixing

You may notice some odd features in some of the output quantities if you try and plot them. This is not a bug in CCE (not that we know of at least). This occurs because the data at future null infinity is in the wrong Bondi-Metzner-Sachs (BMS) frame. In order to put this data into the correct BMS frame, the SXS Collaboration offers a python/numba code called scri to do these transformations. See their documentation for how to install/run/plot a waveform at future null infinity in the correct BMS frame.

Below is a plot of the imaginary part of the 2,2 component for the strain when plotted using the raw output from SpECTRE CCE and BMS frame-fixing with scri. You'll notice that there is a non-zero offset, and this component of the strain doesn't decay back down to zero during the ringdown. This is because of the improper BMS frame that the SpECTRE CCE waveform is in. A supertranslation must be applied to transform the waveform into the correct BMS frame. See [152] for a review of BMS transformations and gravitational memory. To perform the frame fixing, see this tutorial in scri.

Imaginary part of 2,2 component of the strain

The discrepancy is even more apparent if you plot the amplitude of the two waveforms. It's pretty clear which waveform is the more "physical" one.

Amplitude of imaginary part of 2,2 component of the strain

Notice that there are still some oscillations in the strain output by scri towards the beginning of the waveform (up to ~1500M). This is caused by CCE junk radiation from imperfect initial data on the null hypersurface. In order to use this waveform in analysis, the CCE junk must be cut off from the beginning.

You are also able to see gravitational memory effects with SpECTRE CCE! This shows up in the real part of the 2,0 mode of the strain. Though you can see the memory effects in the SpECTRE CCE waveform, in order to do any analysis, you must also transform the waveform to a more physically motivated BMS frame.

Real part of 2,0 component of the strain

Citing CCE

If you use the SpECTRE CCE module to extract your waveforms at future null infinity, please cite the following:

If you used scri to perform any frame-fixing, please also consult the scri GitHub for how you should cite it.

You can also consult our Publication policies page for further questions or contact spectre-devel@black-holes.org.