################################################################## ## ## AMSS-NCKU ABE Test Program (Skip TwoPuncture if data exists) ## Modified from AMSS_NCKU_Program.py ## Author: Xiaoqu ## Modified: 2026/02/01 ## ################################################################## ################################################################## ## Print program introduction import print_information print_information.print_program_introduction() ################################################################## import AMSS_NCKU_Input as input_data ################################################################## ## Create directories to store program run data import os import shutil import sys import time ## Set the output directory according to the input file File_directory = os.path.join(input_data.File_directory) ## Check if output directory exists and if TwoPuncture data is available #skip_twopuncture = False skip_twopuncture = True output_directory = os.path.join(File_directory, "AMSS_NCKU_output") binary_results_directory = os.path.join(output_directory, input_data.Output_directory) if os.path.exists(File_directory): print( " Output directory already exists." ) print() ''' # Check if TwoPuncture initial data files exist if (input_data.Initial_Data_Method == "Ansorg-TwoPuncture"): twopuncture_output = os.path.join(output_directory, "TwoPunctureABE") input_par = os.path.join(output_directory, "input.par") if os.path.exists(twopuncture_output) and os.path.exists(input_par): print( " Found existing TwoPuncture initial data." ) print( " Do you want to skip TwoPuncture phase and reuse existing data?" ) print( " Input 'skip' to skip TwoPuncture and start ABE directly" ) print( " Input 'regenerate' to regenerate everything from scratch" ) print() while True: try: inputvalue = input() if ( inputvalue == "skip" ): print( " Skipping TwoPuncture phase, will reuse existing initial data." ) print() skip_twopuncture = True break elif ( inputvalue == "regenerate" ): print( " Regenerating everything from scratch." ) print() skip_twopuncture = False break else: print( " Please input 'skip' or 'regenerate'." ) except ValueError: print( " Please input 'skip' or 'regenerate'." ) else: print( " TwoPuncture initial data not found, will regenerate everything." ) print() ''' # If not skipping, remove and recreate directory if not skip_twopuncture: shutil.rmtree(File_directory, ignore_errors=True) os.mkdir(File_directory) os.mkdir(output_directory) os.mkdir(binary_results_directory) figure_directory = os.path.join(File_directory, "figure") os.mkdir(figure_directory) shutil.copy("AMSS_NCKU_Input.py", File_directory) print( " Output directory has been regenerated." ) print() else: # Create fresh directory structure os.mkdir(File_directory) shutil.copy("AMSS_NCKU_Input.py", File_directory) os.mkdir(output_directory) os.mkdir(binary_results_directory) figure_directory = os.path.join(File_directory, "figure") os.mkdir(figure_directory) print( " Output directory has been generated." ) print() # Ensure figure directory exists figure_directory = os.path.join(File_directory, "figure") if not os.path.exists(figure_directory): os.mkdir(figure_directory) ################################################################## ## Output related parameter information import setup ## Print and save input parameter information setup.print_input_data( File_directory ) if not skip_twopuncture: setup.generate_AMSSNCKU_input() setup.print_puncture_information() ################################################################## ## Generate AMSS-NCKU program input files based on the configured parameters if not skip_twopuncture: print() print( " Generating the AMSS-NCKU input parfile for the ABE executable." ) print() ## Generate cgh-related input files from the grid information import numerical_grid numerical_grid.append_AMSSNCKU_cgh_input() print() print( " The input parfile for AMSS-NCKU C++ executable file ABE has been generated." ) print( " However, the input relevant to TwoPuncture need to be appended later." ) print() ################################################################## ## Plot the initial grid configuration if not skip_twopuncture: print() print( " Schematically plot the numerical grid structure." ) print() import numerical_grid numerical_grid.plot_initial_grid() ################################################################## ## Generate AMSS-NCKU macro files according to the numerical scheme and parameters if not skip_twopuncture: print() print( " Automatically generating the macro file for AMSS-NCKU C++ executable file ABE " ) print( " (Based on the finite-difference numerical scheme) " ) print() import generate_macrodef generate_macrodef.generate_macrodef_h() print( " AMSS-NCKU macro file macrodef.h has been generated. " ) generate_macrodef.generate_macrodef_fh() print( " AMSS-NCKU macro file macrodef.fh has been generated. " ) ################################################################## # Compile the AMSS-NCKU program according to user requirements # NOTE: ABE compilation is always performed, even when skipping TwoPuncture print() print( " Preparing to compile and run the AMSS-NCKU code as requested " ) print( " Compiling the AMSS-NCKU code based on the generated macro files " ) print() AMSS_NCKU_source_path = "AMSS_NCKU_source" AMSS_NCKU_source_copy = os.path.join(File_directory, "AMSS_NCKU_source_copy") ## If AMSS_NCKU source folder is missing, create it and prompt the user if not os.path.exists(AMSS_NCKU_source_path): os.makedirs(AMSS_NCKU_source_path) print( " The AMSS-NCKU source files are incomplete; copy all source files into ./AMSS_NCKU_source. " ) print( " Press Enter to continue. " ) inputvalue = input() # Copy AMSS-NCKU source files to prepare for compilation # If skipping TwoPuncture and source_copy already exists, remove it first if skip_twopuncture and os.path.exists(AMSS_NCKU_source_copy): shutil.rmtree(AMSS_NCKU_source_copy) shutil.copytree(AMSS_NCKU_source_path, AMSS_NCKU_source_copy) # Copy the generated macro files into the AMSS_NCKU source folder if not skip_twopuncture: macrodef_h_path = os.path.join(File_directory, "macrodef.h") macrodef_fh_path = os.path.join(File_directory, "macrodef.fh") else: # When skipping TwoPuncture, use existing macro files from previous run macrodef_h_path = os.path.join(File_directory, "macrodef.h") macrodef_fh_path = os.path.join(File_directory, "macrodef.fh") shutil.copy2(macrodef_h_path, AMSS_NCKU_source_copy) shutil.copy2(macrodef_fh_path, AMSS_NCKU_source_copy) # Compile related programs import makefile_and_run ## Change working directory to the target source copy os.chdir(AMSS_NCKU_source_copy) ## Build the main AMSS-NCKU executable (ABE or ABEGPU) makefile_and_run.makefile_ABE() ## If the initial-data method is Ansorg-TwoPuncture, build the TwoPunctureABE executable ## Only build TwoPunctureABE if not skipping TwoPuncture phase if (input_data.Initial_Data_Method == "Ansorg-TwoPuncture" ) and not skip_twopuncture: makefile_and_run.makefile_TwoPunctureABE() ## Change current working directory back up two levels os.chdir('..') os.chdir('..') print() ################################################################## ## Copy the AMSS-NCKU executable (ABE/ABEGPU) to the run directory if (input_data.GPU_Calculation == "no"): ABE_file = os.path.join(AMSS_NCKU_source_copy, "ABE") elif (input_data.GPU_Calculation == "yes"): ABE_file = os.path.join(AMSS_NCKU_source_copy, "ABEGPU") if not os.path.exists( ABE_file ): print() print( " Lack of AMSS-NCKU executable file ABE/ABEGPU; recompile AMSS_NCKU_source manually. " ) print( " When recompilation is finished, press Enter to continue. " ) inputvalue = input() ## Copy the executable ABE (or ABEGPU) into the run directory shutil.copy2(ABE_file, output_directory) ## If the initial-data method is TwoPuncture, copy the TwoPunctureABE executable to the run directory ## Only copy TwoPunctureABE if not skipping TwoPuncture phase if (input_data.Initial_Data_Method == "Ansorg-TwoPuncture" ) and not skip_twopuncture: TwoPuncture_file = os.path.join(AMSS_NCKU_source_copy, "TwoPunctureABE") if not os.path.exists( TwoPuncture_file ): print() print( " Lack of AMSS-NCKU executable file TwoPunctureABE; recompile TwoPunctureABE in AMSS_NCKU_source. " ) print( " When recompilation is finished, press Enter to continue. " ) inputvalue = input() ## Copy the TwoPunctureABE executable into the run directory shutil.copy2(TwoPuncture_file, output_directory) ################################################################## ## If the initial-data method is TwoPuncture, generate the TwoPuncture input files if (input_data.Initial_Data_Method == "Ansorg-TwoPuncture" ) and not skip_twopuncture: print() print( " Initial data is chosen as Ansorg-TwoPuncture" ) print() print() print( " Automatically generating the input parfile for the TwoPunctureABE executable " ) print() import generate_TwoPuncture_input generate_TwoPuncture_input.generate_AMSSNCKU_TwoPuncture_input() print() print( " The input parfile for the TwoPunctureABE executable has been generated. " ) print() ## Generated AMSS-NCKU TwoPuncture input filename AMSS_NCKU_TwoPuncture_inputfile = 'AMSS-NCKU-TwoPuncture.input' AMSS_NCKU_TwoPuncture_inputfile_path = os.path.join( File_directory, AMSS_NCKU_TwoPuncture_inputfile ) ## Copy and rename the file shutil.copy2( AMSS_NCKU_TwoPuncture_inputfile_path, os.path.join(output_directory, 'TwoPunctureinput.par') ) ## Run TwoPuncture to generate initial-data files start_time = time.time() # Record start time print() print() ## Change to the output (run) directory os.chdir(output_directory) ## Run the TwoPuncture executable import makefile_and_run makefile_and_run.run_TwoPunctureABE() ## Change current working directory back up two levels os.chdir('..') os.chdir('..') elif (input_data.Initial_Data_Method == "Ansorg-TwoPuncture" ) and skip_twopuncture: print() print( " Skipping TwoPuncture execution, using existing initial data." ) print() start_time = time.time() # Record start time for ABE only else: start_time = time.time() # Record start time ################################################################## ## Update puncture data based on TwoPuncture run results if not skip_twopuncture: import renew_puncture_parameter renew_puncture_parameter.append_AMSSNCKU_BSSN_input(File_directory, output_directory) ## Generated AMSS-NCKU input filename AMSS_NCKU_inputfile = 'AMSS-NCKU.input' AMSS_NCKU_inputfile_path = os.path.join(File_directory, AMSS_NCKU_inputfile) ## Copy and rename the file shutil.copy2( AMSS_NCKU_inputfile_path, os.path.join(output_directory, 'input.par') ) print() print( " Successfully copy all AMSS-NCKU input parfile to target dictionary. " ) print() else: print() print( " Using existing input.par file from previous run." ) print() ################################################################## ## Launch the AMSS-NCKU program print() print() ## Change to the run directory os.chdir( output_directory ) import makefile_and_run makefile_and_run.run_ABE() ## Change current working directory back up two levels os.chdir('..') os.chdir('..') end_time = time.time() elapsed_time = end_time - start_time ################################################################## ## Copy some basic input and log files out to facilitate debugging ## Path to the file that stores calculation settings AMSS_NCKU_error_file_path = os.path.join(binary_results_directory, "setting.par") ## Copy and rename the file for easier inspection shutil.copy( AMSS_NCKU_error_file_path, os.path.join(output_directory, "AMSSNCKU_setting_parameter") ) ## Path to the error log file AMSS_NCKU_error_file_path = os.path.join(binary_results_directory, "Error.log") ## Copy and rename the error log shutil.copy( AMSS_NCKU_error_file_path, os.path.join(output_directory, "Error.log") ) ## Primary program outputs AMSS_NCKU_BH_data = os.path.join(binary_results_directory, "bssn_BH.dat" ) AMSS_NCKU_ADM_data = os.path.join(binary_results_directory, "bssn_ADMQs.dat" ) AMSS_NCKU_psi4_data = os.path.join(binary_results_directory, "bssn_psi4.dat" ) AMSS_NCKU_constraint_data = os.path.join(binary_results_directory, "bssn_constraint.dat") ## copy and rename the file shutil.copy( AMSS_NCKU_BH_data, os.path.join(output_directory, "bssn_BH.dat" ) ) shutil.copy( AMSS_NCKU_ADM_data, os.path.join(output_directory, "bssn_ADMQs.dat" ) ) shutil.copy( AMSS_NCKU_psi4_data, os.path.join(output_directory, "bssn_psi4.dat" ) ) shutil.copy( AMSS_NCKU_constraint_data, os.path.join(output_directory, "bssn_constraint.dat") ) ## Additional program outputs if (input_data.Equation_Class == "BSSN-EM"): AMSS_NCKU_phi1_data = os.path.join(binary_results_directory, "bssn_phi1.dat" ) AMSS_NCKU_phi2_data = os.path.join(binary_results_directory, "bssn_phi2.dat" ) shutil.copy( AMSS_NCKU_phi1_data, os.path.join(output_directory, "bssn_phi1.dat" ) ) shutil.copy( AMSS_NCKU_phi2_data, os.path.join(output_directory, "bssn_phi2.dat" ) ) elif (input_data.Equation_Class == "BSSN-EScalar"): AMSS_NCKU_maxs_data = os.path.join(binary_results_directory, "bssn_maxs.dat" ) shutil.copy( AMSS_NCKU_maxs_data, os.path.join(output_directory, "bssn_maxs.dat" ) ) ################################################################## ## Plot the AMSS-NCKU program results print() print( " Plotting the txt and binary results data from the AMSS-NCKU simulation " ) print() import plot_xiaoqu import plot_GW_strain_amplitude_xiaoqu ## Plot black hole trajectory plot_xiaoqu.generate_puncture_orbit_plot( binary_results_directory, figure_directory ) plot_xiaoqu.generate_puncture_orbit_plot3D( binary_results_directory, figure_directory ) ## Plot black hole separation vs. time plot_xiaoqu.generate_puncture_distence_plot( binary_results_directory, figure_directory ) ## Plot gravitational waveforms (psi4 and strain amplitude) for i in range(input_data.Detector_Number): plot_xiaoqu.generate_gravitational_wave_psi4_plot( binary_results_directory, figure_directory, i ) plot_GW_strain_amplitude_xiaoqu.generate_gravitational_wave_amplitude_plot( binary_results_directory, figure_directory, i ) ## Plot ADM mass evolution for i in range(input_data.Detector_Number): plot_xiaoqu.generate_ADMmass_plot( binary_results_directory, figure_directory, i ) ## Plot Hamiltonian constraint violation over time for i in range(input_data.grid_level): plot_xiaoqu.generate_constraint_check_plot( binary_results_directory, figure_directory, i ) ## Plot stored binary data plot_xiaoqu.generate_binary_data_plot( binary_results_directory, figure_directory ) print() print( f" This Program Cost = {elapsed_time} Seconds " ) print() ################################################################## print() print( " The AMSS-NCKU-Python simulation is successfully finished, thanks for using !!! " ) print() ##################################################################