SpECTRE  v2024.09.29
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
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 ReduceCceWorldtube executable and YAML file for converting between worldtube data formats in the ReduceCceWorldtube/ diretory
  • 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 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 formats

The worldtube data must be constructed as spheres of constant coordinate radius, and (for the time being) written to a filename of the format ...CceRXXXX.h5, where the XXXX is to be replaced by the integer for which the extraction radius is equal to XXXXM. For instance, a 100M extraction should have filename ...CceR0100.h5. This scheme of labeling files with the extraction radius is constructed for compatibility with SpEC worldtube data.

Currently CCE is able to read in worldtube data in two different formats.

Cartesian metric and derivatives

This metric data format must be provided as the following datasets:

  • 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

Spherical harmonic modes

In this format, the worldtube data are stored as spherical harmonic coefficients. 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. That is,

"time", "Lapse_Re(0,0)", "Lapse_Im(0,0)",
"Lapse_Re(1,1)", "Lapse_Im(1,1)", "Lapse_Re(1,0)", "Lapse_Im(1,0)",
"Lapse_Re(1,-1)", "Lapse_Im(1,-1)",
"Lapse_Re(2,2)", "Lapse_Im(2,2)", "Lapse_Re(2,1)", "Lapse_Im(2,1)",
"Lapse_Re(2,0)", "Lapse_Im(2,0)", "Lapse_Re(2,-1)", "Lapse_Im(2,-1)",
"Lapse_Re(2,-2)", "Lapse_Im(2,-2)"

Spherical harmonic nodes

Warning
This format is not yet fully supported but is under development. If you need it please file an issue so we can escalate the priority.

In this format the value of the functions at specially chosen collocation points (grid points) is read in. This allows SpECTRE to perform integrals, derivatives, and interpolation exactly on the input data. These grid points are Gauss-Legendre in cos(θ) and equally spaced in ϕ. Below is a routine for computing the spherical harmonic θ and ϕ values. These can be used to compute the Cartesian locations for a given radius using the standard transformation. The routine supports [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;
}

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

"time",
"Theta_0_Phi_0", "Theta_1_Phi_0", "Theta_2_Phi_0", "Theta_3_Phi_0",
"Theta_4_Phi_0",
"Theta_0_Phi_1", "Theta_1_Phi_1", "Theta_2_Phi_1", "Theta_3_Phi_1",
"Theta_4_Phi_1",

Formatting of data types

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 DrLapse.dat/Legend CceR0150.h5

Bondi-Sachs

The second format is Bondi-Sachs metric component data. This format is far more space-efficient (by around a factor of 4) than the cartesian_metric format.

The format is similar to the cartesian_metric format, except in spin-weighted spherical harmonic modes, and the real (spin-weight-0) quantities omit the redundant negative-m modes and imaginary parts of m=0 modes. The quantities that must be provided by the Bondi-Sachs metric data format are:

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

An example of the columns of these dat files is

"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)", ...

See [141] for a description of these quantities.

Note
The columns of the legend of the cartesian_metric format are different from the Bondi-Sachs format. In the cartesian_metric, the name of the quantity is in the legend, while for Bondi-Sachs it isn't.

Converting data formats

Since the Bondi-Sachs format is far more space-efficient, SpECTRE provides a separate executable for converting from the cartesian_metric format to the Bondi-Sachs worldtube format called ReduceCceWorldtube. The ReduceCceWorldtube executable should be run on a cartesian_metric worldtube file, and will produce a corresponding 'reduced' Bondi-Sachs worldtube file. This executable works similarly to our other executables by accepting a YAML input file:

ReduceCceWorldtube --input-file ReduceCceWorldtube.yaml

with a YAML file

InputH5File: InputFilenameR0292.h5
OutputH5File: ReducedWorldtubeR0292.h5
FixSpecNormalization: False
BufferDepth: Auto
LMaxFactor: 3

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.

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 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.
  • If the worldtube data is in the Bondi-Sachs form, set Cce.H5IsBondiData to True. If the worldtube data is the cartesian_metric form, set Cce.H5IsBondiData to False.

Initial data on the null hypersurface

Choosing initial data on the initial null hypersurface is a non-trivial task and is an active area of research. We want initial data that will reduce the amount of CCE junk radiation as much as possible, while also having the initial data work for as many cases as possible.

SpECTRE currently has four different methods to choose the initial data on the null hypersurface. In order from most recommended to least recommended, these are:

  • ConformalFactor: Try to make initial time coordinate as inertial as possible at I+ with a smart choice of the conformal factor. This will work for many cases, but not all. But will produce the best initial data when it does work.
  • InverseCubic: Ansatz where J=A/r+B/r3. 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 Ψ0=0; this does not actually lead to no incoming radiation, since Ψ0 and Ψ4 both include incoming and outgoing radiation.

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

You may notice at the beginning you get some warnings that look like

Warning: iterative angular solve did not reach target tolerance 1.000000e-13.
Exited after 300 iterations, achieving final maximum over collocation points
for deviation from target of 2.073455e-08
Proceeding with evolution using the partial result from partial angular solve.

This is normal and expected. All it means is that initially an angular solve didn't hit a tolerance. We've found that it never really reaches the tolerance of 1e-13, but we still keep this tolerance so it gets as low as possible.

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 =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 [137] 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.