446 lines
16 KiB
Python
446 lines
16 KiB
Python
|
|
##################################################################
|
|
##
|
|
## 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
|
|
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()
|
|
|
|
##################################################################
|
|
|
|
|