#!/usr/bin/env python # Copyright Barry Wardell, Ian Hinder, Eloisa Bentivegna # We ask that if you make use of the parameter file or the example # data, then please cite # Simulation of GW150914 binary black hole merger using the # Einstein Toolkit - https://doi.org/10.5281/zenodo.155394 # as well as the Einstein Toolkit, the Llama multi-block # infrastructure, the Carpet mesh-refinement driver, the apparent # horizon finder AHFinderDirect, the TwoPunctures initial data code, # QuasiLocalMeasures, Cactus, and the McLachlan spacetime evolution # code, the Kranc code generation package, and the Simulation Factory. # An appropriate bibtex file, etgw150914.bib, is provided with this # parameter file. from math import * import sys import re from string import Template ################################################################################ # Binary black hole configuration ################################################################################ # BHs labeled as '+' and '-' ('p' and 'm') for their initial position # on the x axis. The more massive BH is '+'. D = 10.0 # Separation q = 36.0/29.0 # Mass ratio: q = mp/mm >= 1 M = 1.0 # Total mass chip = [0, 0, 0.31] # Dimensionsless spin of + BH (x0 > 0, more massive) chim = [0, 0, -0.46] # Dimensionsless spin of - BH (x0 < 0, less massive) Pr = -0.00084541526517121; # Radial linear momentum Pphi = 0.09530152296974252; # Azimuthal linear momentum ################################################################################ # Initial data ################################################################################ mp = M * q/(1+q) # Heavier, larger BH, AH1, SS 0 mm = M * 1/(1+q) # Lighter, smaller BH, AH2, SS 1 xp = D * mm xm = -D * mp half_D = D/2.0 center_offset = xp - half_D Spx = chip[0] * mp**2; Spy = chip[1] * mp**2; Spz = chip[2] * mp**2; Smx = chim[0] * mm**2; Smy = chim[1] * mm**2; Smz = chim[2] * mm**2; Ppx = Pr Ppy = Pphi Ppz = 0 Pmx = -Ppx Pmy = -Ppy Pmz = -Ppz ################################################################################ # Grid structure ################################################################################ sphere_inner_radius = 45 expected_merger = 1000.0 # Number of cells across finest grid radius n = int("@N@") if "@N@"[0] != "@" else 28 i = n/4 n_angular = 2*i*2 # Estimated eventual AH radii ahrp = mp * 1.0 ahrm = mm * 1.0 # Coordinate size of finest boxes around each BH rp = ahrp * 1.2 rm = ahrm * 1.2 # Minimum acceptable radial grid spacing hr_min = 2*0.96*M maxrls = 9 # Essentially determines iteration counting # Smaller '-' BH # Decisions are made independent of n, to avoid roundoff problems. # This is achieved by using nmin for the calculations and scaling by # n/nmin at the end. n_min = 24 # Cells across AHm radius hfm_min = rm/n_min # Fine grid spacing for '-' BH rlsm = 1 + int(log(hr_min/hfm_min,2)) # Number of refinements to attain hr_min h0_min = hfm_min * 2**(rlsm-1) # RL0 Cartesian spacing # Radii of each level for the centre around the '-' BH levelsm = "[0," + ",".join(["%f" %(rm*2**(rlsm-l-1)) for l in range(1,rlsm)])+"]" # '+' BH # Number of levels for '+' BH estimated to keep error in angular # velocity the same as for the '-' BH, assuming vErr \propto v * # (h0/2**(rls-1)/rAH)**8 rlsp = rlsm + log(ahrm/ahrp * (xp/-xm)**(1./8))/log(2) rlsp = int(round(rlsp)) levelsp = "[0," + ",".join(["%f" %(rp*2**(rlsp-l-1)) for l in range(1,rlsp)])+"]" hr = h0_min * float(n_min)/float(n) # This could be changed (h0_min -> # hr_min) to get the minimum # radial resolution for efficiency h0 = h0_min * float(n_min)/float(n) time_after_merger = 200.0 waveform_length = expected_merger + time_after_merger outermost_detector = 500.0 final_time = waveform_length + outermost_detector sphere_outer_radius = int((outermost_detector + final_time)/(i*hr))*i*hr sphere_outer_radius = int(sphere_outer_radius / hr) * hr + hr # round up to a multiple of hr sphere_inner_radius = int(ceil(sphere_inner_radius/(i*h0))) * h0 * i ################################################################################ # Frequencies ################################################################################ dtdx = 0.45 # Courant factor dtdx0 = dtdx * 0.5 # RL0 is evolved with the same frequency as RL1 dt0 = dtdx0 * h0 # Time step on RL0 rl0_every = 2**(maxrls-2) rl1_every = rl0_every rl_max = maxrls-1 dt_it = dt0/2.0**(rl_max-1) # Time step of one iteration find_cah = max(int((expected_merger - 200)/dt_it), 0) wave_extract_every = rl0_every * 2 # Every other coarse grid step # (TODO: should this be every # coarse grid step?) horizon_every = rl0_every * 2 out_every = rl0_every # out3d_every = rl0_every * 2 out3d_every = 0 out2d_every = rl0_every * 8 ################################################################################ # Record all script variables in generated parameter file ################################################################################ local_vars = locals() col_width = 0 for key,val in sorted(local_vars.items()): if isinstance(val, (int, long, float, complex, str)): col_width = max(len(str(key)), col_width) var_settings = [] for key,val in sorted(local_vars.items()): if isinstance(val, (int, long, float, complex, str)): var_settings = var_settings + ["# {0}{1} = {2}".format(key," "*(col_width-len(key)),val)] var_settings_str = "\n".join(var_settings) lines = """ ################################################################################ # Script variables ################################################################################ $var_settings_str ################################################################################ # Active thorns ################################################################################ ActiveThorns = " ADMBase ML_ADMConstraints ADMCoupling ADMMacros AEILocalInterp AHFinderDirect Boundary Carpet CarpetIOASCII CarpetIOBasic CarpetIOHDF5 CarpetIOScalar CarpetInterp CarpetInterp2 CarpetLib CarpetReduce CarpetRegrid2 CarpetTracker CartGrid3D CoordBase CoordGauge Coordinates CoordinatesSymmetry Formaline GlobalDerivative hwloc IOUtil InitBase Interpolate2 QuasiLocalMeasures LocalInterp LoopControl MoL NaNChecker PunctureTracker Slab SpaceMask SphericalSurface StaticConformal SummationByParts SymBase SystemStatistics SystemTopology TerminationTrigger TensorTypes Time TmunuBase TwoPunctures Vectors ML_BSSN ML_BSSN_Helper NewRad GenericFD WeylScal4 Multipole # WaveExtractCPM ADMDerivatives " ################################################################################ # Grid structure ################################################################################ Carpet::domain_from_multipatch = yes CartGrid3D::type = "multipatch" CartGrid3D::set_coordinate_ranges_on = "all maps" Coordinates::coordinate_system = "Thornburg04" Coordinates::h_cartesian = $h0 Coordinates::h_radial = $hr Coordinates::sphere_inner_radius = $sphere_inner_radius Coordinates::sphere_outer_radius = $sphere_outer_radius Coordinates::n_angular = $n_angular Driver::ghost_size = 5 Coordinates::patch_boundary_size = 5 Coordinates::additional_overlap_size = 3 Coordinates::outer_boundary_size = 5 CoordinatesSymmetry::reflection_z = yes CoordinatesSymmetry::stagger = no Coordinates::symmetry = "+z bitant" Coordinates::additional_symmetry_size = 1 Coordinates::verbose = no Time::timestep_method = "given" Time::timestep = $dt0 Carpet::time_refinement_factors = "[1,1,2,4,8,16,32,64,128,256]" ################################################################################ # Mesh refinement ################################################################################ Carpet::max_refinement_levels = $maxrls CarpetRegrid2::num_centres = 2 CarpetRegrid2::num_levels_1 = $rlsp CarpetRegrid2::position_x_1 = $xp CarpetRegrid2::radius_1 = $levelsp CarpetRegrid2::num_levels_2 = $rlsm CarpetRegrid2::position_x_2 = $xm CarpetRegrid2::radius_2 = $levelsm Carpet::use_buffer_zones = yes Carpet::prolongation_order_space = 5 Carpet::prolongation_order_time = 2 CarpetRegrid2::regrid_every = $rl1_every CarpetRegrid2::verbose = no Carpet::grid_coordinates_filename = "carpet-grid.asc" ################################################################################ # Initial data ################################################################################ ADMBase::initial_data = "twopunctures" ADMBase::initial_lapse = "twopunctures-averaged" ADMBase::initial_shift = "zero" ADMBase::initial_dtlapse = "zero" ADMBase::initial_dtshift = "zero" TwoPunctures::target_M_plus = $mp TwoPunctures::target_M_minus = $mm # Initial guesses for iterative solve TwoPunctures::par_m_plus = $mp TwoPunctures::par_m_minus = $mm TwoPunctures::par_b = $half_D TwoPunctures::center_offset[0] = $center_offset TwoPunctures::par_P_plus[0] = $Ppx TwoPunctures::par_P_plus[1] = $Ppy TwoPunctures::par_P_plus[2] = $Ppz TwoPunctures::par_P_minus[0] = $Pmx TwoPunctures::par_P_minus[1] = $Pmy TwoPunctures::par_P_minus[2] = $Pmz TwoPunctures::par_S_plus[0] = $Spx TwoPunctures::par_S_plus[1] = $Spy TwoPunctures::par_S_plus[2] = $Spz TwoPunctures::par_S_minus[0] = $Smx TwoPunctures::par_S_minus[1] = $Smy TwoPunctures::par_S_minus[2] = $Smz TwoPunctures::grid_setup_method = "evaluation" TwoPunctures::give_bare_mass = no TwoPunctures::TP_epsilon = 1e-6 Carpet::init_fill_timelevels = yes InitBase::initial_data_setup_method = "init_single_level" ################################################################################ # Evolution and boundary ################################################################################ GenericFD::jacobian_group = "Coordinates::jacobian" GenericFD::jacobian_derivative_group = "Coordinates::jacobian2" GenericFD::jacobian_identity_map = 0 ADMBase::evolution_method = "ML_BSSN" ADMBase::lapse_evolution_method = "ML_BSSN" ADMBase::shift_evolution_method = "ML_BSSN" ADMBase::dtlapse_evolution_method = "ML_BSSN" ADMBase::dtshift_evolution_method = "ML_BSSN" ML_BSSN::fdOrder = 8 # 1+log slicing requires harmonicN = 1 and harmonicF = 2.0 ML_BSSN::harmonicN = 1 ML_BSSN::harmonicF = 2.0 ML_BSSN::ShiftGammaCoeff = 0.75 ML_BSSN::BetaDriver = 1.0 ML_BSSN::advectLapse = 1 ML_BSSN::advectShift = 1 ML_BSSN::MinimumLapse = 1.0e-8 # conformalaMethod = 1 for W, 0 for phi ML_BSSN::conformalMethod = 1 # We apply dissipation using GlobalDerivaitive so disable it here ML_BSSN::epsDiss = 0.0 ML_BSSN::dt_lapse_shift_method = "noLapseShiftAdvection" ML_BSSN::initial_boundary_condition = "extrapolate-gammas" ML_BSSN::rhs_boundary_condition = "scalar" Boundary::radpower = 2 ################################################################################ # BH tracking ################################################################################ CarpetTracker::surface [0] = 0 CarpetTracker::surface [1] = 1 PunctureTracker::track [0] = yes PunctureTracker::initial_x [0] = $xp PunctureTracker::which_surface_to_store_info[0] = 0 PunctureTracker::track [1] = yes PunctureTracker::initial_x [1] = $xm PunctureTracker::which_surface_to_store_info[1] = 1 ################################################################################ # Spatial finite differencing ################################################################################ SummationByParts::order = 8 # Drop order instead of using upwinded stencils, only for advection derivatives SummationByParts::sbp_upwind_deriv = no SummationByParts::sbp_1st_deriv = yes SummationByParts::sbp_2nd_deriv = no SummationByParts::onesided_interpatch_boundaries = no SummationByParts::onesided_outer_boundaries = yes SummationByParts::use_dissipation = no GlobalDerivative::use_dissipation = yes SummationByParts::scale_with_h = yes SummationByParts::dissipation_type = "Kreiss-Oliger" SummationByParts::epsdis = 0.15 # Because dt/dx is half that of the other levels we also need half the dissipation GlobalDerivative::epsdis_for_level [0] = 0.075 # Variables for dissipation SummationByParts::vars = " ML_BSSN::ML_log_confac ML_BSSN::ML_metric ML_BSSN::ML_trace_curv ML_BSSN::ML_curv ML_BSSN::ML_Gamma ML_BSSN::ML_lapse ML_BSSN::ML_shift ML_BSSN::ML_dtlapse ML_BSSN::ML_dtshift " ################################################################################ # Time integration ################################################################################ MoL::ODE_Method = "rk4" MoL::MoL_Intermediate_Steps = 4 MoL::MoL_Num_Scratch_Levels = 1 ################################################################################ # Interpolation ################################################################################ CarpetInterp::check_tree_search = no CarpetInterp::tree_search = yes # Use 5-th order interpatch interpolation on the Llama grid Interpolate::interpolator_order = 5 ################################################################################ # Psi4 computation ################################################################################ WeylScal4::fdOrder = 8 WeylScal4::calc_scalars = "psis" WeylScal4::calc_invariants = "always" ################################################################################ # Psi4 mode decomposition ################################################################################ # Radii are chosen to be evenly spaced in 1/r as that is the variable # extrapolation is performed in Multipole::nradii = 7 Multipole::radius[0] = 100 Multipole::radius[1] = 115 Multipole::radius[2] = 136 Multipole::radius[3] = 167 Multipole::radius[4] = 214 Multipole::radius[5] = 300 Multipole::radius[6] = 500 Multipole::ntheta = 120 Multipole::nphi = 240 Multipole::variables = "WeylScal4::Psi4r{sw=-2 cmplx='WeylScal4::Psi4i' name='psi4'}" Multipole::out_every = $wave_extract_every Multipole::l_max = 8 Multipole::output_hdf5 = yes # Disable ASCII output to avoid creating a large number of files Multipole::output_ascii = no ################################################################################ # Gauge invariant perturbations of Schwarzschild (ZM-CPM variables) ################################################################################ # WaveExtractCPM::out_every = $wave_extract_every # WaveExtractCPM::use_carpetinterp2 = no # WaveExtractCPM::calc_when_necessary = no # WaveExtractCPM::verbose = 0 # WaveExtractCPM::maximum_detector_number = 7 # WaveExtractCPM::switch_output_format = 100 # WaveExtractCPM::rsch2_computation = "average Schwarzschild metric" # WaveExtractCPM::l_mode = 8 # WaveExtractCPM::m_mode = 8 # WaveExtractCPM::detector_radius [0] = 100 # WaveExtractCPM::detector_radius [1] = 115 # WaveExtractCPM::detector_radius [2] = 136 # WaveExtractCPM::detector_radius [3] = 167 # WaveExtractCPM::detector_radius [4] = 214 # WaveExtractCPM::detector_radius [5] = 300 # WaveExtractCPM::detector_radius [6] = 500 # WaveExtractCPM::maxntheta = 120 # WaveExtractCPM::maxnphi = 240 # WaveExtractCPM::output_hdf5 = yes # WaveExtractCPM::output_ascii = no # WaveExtractCPM::output_h = yes # WaveExtractCPM::output_Psi = yes ################################################################################ # Apparent Horizons ################################################################################ AHFinderDirect::N_horizons = 3 AHFinderDirect::find_every = $horizon_every AHFinderDirect::output_h_every = 0 AHFinderDirect::max_Newton_iterations__initial = 50 AHFinderDirect::max_Newton_iterations__subsequent = 50 AHFinderDirect::max_allowable_Theta_growth_iterations = 10 AHFinderDirect::max_allowable_Theta_nonshrink_iterations = 10 AHFinderDirect::geometry_interpolator_name = "Lagrange polynomial interpolation" AHFinderDirect::geometry_interpolator_pars = "order=4" AHFinderDirect::surface_interpolator_name = "Lagrange polynomial interpolation" AHFinderDirect::surface_interpolator_pars = "order=4" AHFinderDirect::verbose_level = "physics details" AHFinderDirect::move_origins = yes AHFinderDirect::origin_x [1] = $xp AHFinderDirect::initial_guess__coord_sphere__x_center[1] = $xp AHFinderDirect::initial_guess__coord_sphere__radius [1] = $rp AHFinderDirect::which_surface_to_store_info [1] = 2 AHFinderDirect::set_mask_for_individual_horizon [1] = no AHFinderDirect::reset_horizon_after_not_finding [1] = no AHFinderDirect::track_origin_from_grid_scalar [1] = yes AHFinderDirect::track_origin_source_x [1] = "PunctureTracker::pt_loc_x[0]" AHFinderDirect::track_origin_source_y [1] = "PunctureTracker::pt_loc_y[0]" AHFinderDirect::track_origin_source_z [1] = "PunctureTracker::pt_loc_z[0]" AHFinderDirect::max_allowable_horizon_radius [1] = 3 AHFinderDirect::origin_x [2] = $xm AHFinderDirect::initial_guess__coord_sphere__x_center[2] = $xm AHFinderDirect::initial_guess__coord_sphere__radius [2] = $rm AHFinderDirect::which_surface_to_store_info [2] = 3 AHFinderDirect::set_mask_for_individual_horizon [2] = no AHFinderDirect::reset_horizon_after_not_finding [2] = no AHFinderDirect::track_origin_from_grid_scalar [2] = yes AHFinderDirect::track_origin_source_x [2] = "PunctureTracker::pt_loc_x[1]" AHFinderDirect::track_origin_source_y [2] = "PunctureTracker::pt_loc_y[1]" AHFinderDirect::track_origin_source_z [2] = "PunctureTracker::pt_loc_z[1]" AHFinderDirect::max_allowable_horizon_radius [2] = 3 AHFinderDirect::origin_x [3] = 0 AHFinderDirect::find_after_individual [3] = $find_cah AHFinderDirect::initial_guess__coord_sphere__x_center[3] = 0 AHFinderDirect::initial_guess__coord_sphere__radius [3] = 1.0 AHFinderDirect::which_surface_to_store_info [3] = 4 AHFinderDirect::set_mask_for_individual_horizon [3] = no AHFinderDirect::max_allowable_horizon_radius [3] = 6 ################################################################################ # Spherical surfaces ################################################################################ SphericalSurface::nsurfaces = 5 SphericalSurface::maxntheta = 66 SphericalSurface::maxnphi = 124 SphericalSurface::verbose = no # Surfaces 0 and 1 are used by PunctureTracker # Horizon 1 SphericalSurface::ntheta [2] = 41 SphericalSurface::nphi [2] = 80 SphericalSurface::nghoststheta [2] = 2 SphericalSurface::nghostsphi [2] = 2 # Horizon 2 SphericalSurface::ntheta [3] = 41 SphericalSurface::nphi [3] = 80 SphericalSurface::nghoststheta [3] = 2 SphericalSurface::nghostsphi [3] = 2 # Common horizon SphericalSurface::ntheta [4] = 41 SphericalSurface::nphi [4] = 80 SphericalSurface::nghoststheta [4] = 2 SphericalSurface::nghostsphi [4] = 2 ################################################################################ # Isolated Horizons ################################################################################ QuasiLocalMeasures::verbose = no QuasiLocalMeasures::veryverbose = no QuasiLocalMeasures::interpolator = "Lagrange polynomial interpolation" QuasiLocalMeasures::interpolator_options = "order=4" QuasiLocalMeasures::spatial_order = 4 QuasiLocalMeasures::num_surfaces = 3 QuasiLocalMeasures::surface_index [0] = 2 QuasiLocalMeasures::surface_index [1] = 3 QuasiLocalMeasures::surface_index [2] = 4 QuasiLocalMeasures::output_vtk_every = $out3d_every ################################################################################ # Correctness checking ################################################################################ Carpet::poison_new_timelevels = no Carpet::check_for_poison = no NaNChecker::check_every = 256 NanChecker::check_after = 0 NaNChecker::report_max = 10 NaNChecker::verbose = "all" NaNChecker::action_if_found = terminate NaNChecker::out_NaNmask = yes NaNChecker::check_vars = " ML_BSSN::ML_log_confac " ################################################################################ # Timers ################################################################################ Carpet::output_timer_tree_every = 1024 Carpet::output_initialise_timer_tree = yes ################################################################################ # Output ################################################################################ IO::out_dir = "@SIMULATION_NAME@" IOScalar::one_file_per_group = yes IOASCII::one_file_per_group = yes IOBasic::outInfo_every = 1 IOBasic::outInfo_reductions = "minimum maximum" IOBasic::outInfo_vars = " ML_BSSN::ML_log_confac Carpet::physical_time_per_hour SystemStatistics::maxrss_mb SystemStatistics::swap_used_mb " IOScalar::outScalar_every = 256 IOScalar::outScalar_reductions = "minimum maximum average" IOScalar::outScalar_vars = "SystemStatistics::process_memory_mb" IOASCII::out0D_every = 256 IOASCII::out0D_vars = " Carpet::timing PunctureTracker::pt_loc QuasiLocalMeasures::qlm_scalars{out_every = $horizon_every} " IOASCII::out1D_every = 0 IOASCII::out1D_d = no IOASCII::out1D_x = yes IOASCII::out1D_y = no IOASCII::out1D_z = yes IOASCII::out1D_vars = " ML_BSSN::ML_log_confac ML_BSSN::ML_trace_curv WeylScal4::Psi4r " IOASCII::out2D_every = 0 IOASCII::out2D_vars = " " IOHDF5::out_every = $out3d_every IOHDF5::out_vars = " Grid::Coordinates{out_every=1000000000 refinement_levels={0}} ML_BSSN::ML_log_confac WeylScal4::Psi4r WeylScal4::Psi4i WeylScal4::curvIr{refinement_levels={3 5}} WeylScal4::curvIi{refinement_levels={3 5}} WeylScal4::curvJr{refinement_levels={3 5}} WeylScal4::curvJi{refinement_levels={3 5}} " IOHDF5::out2D_every = $out2d_every IOHDF5::out2D_vars = " Grid::Coordinates{out_every=1000000000 refinement_levels={0}} ML_BSSN::alpha ML_BSSN::phi ML_BSSN::trK WeylScal4::Psi4r WeylScal4::Psi4i " ################################################################################ # Checkpointing and recovery ################################################################################ CarpetIOHDF5::checkpoint = yes IO::checkpoint_ID = no IO::recover = "autoprobe" IO::out_proc_every = 2 IO::checkpoint_on_terminate = yes IO::checkpoint_dir = "../checkpoints" IO::recover_dir = "../checkpoints" IO::abort_on_io_errors = yes CarpetIOHDF5::open_one_input_file_at_a_time = yes CarpetIOHDF5::compression_level = 0 ################################################################################ # Run termination ################################################################################ TerminationTrigger::max_walltime = @WALLTIME_HOURS@ # Trigger termination 30 minutes before the walltime is reached TerminationTrigger::on_remaining_walltime = 30 TerminationTrigger::output_remtime_every_minutes = 30 TerminationTrigger::termination_from_file = yes TerminationTrigger::termination_file = "terminate.txt" TerminationTrigger::create_termination_file = yes Cactus::terminate = time Cactus::cctk_final_time = $final_time """ open(re.sub(r'(.*)\.rpar$', r'\1.par', sys.argv[0]), 'w').write(re.sub(r'\n *',r'\n',Template(Template(lines).substitute(locals())).substitute(locals())))