sbmy_control/scola.py

277 lines
No EOL
13 KiB
Python

def main_scola(parsed_args):
from args_main import parse_arguments_main
from low_level import print_starting_module, print_message, print_ending_module, progress_bar_from_logfile, wait_until_file_exists
from os.path import isfile
import subprocess
print_starting_module("scola", verbose=parsed_args.verbose)
main_dict = parse_arguments_main(parsed_args)
paramfile=parsed_args.paramfile
if paramfile is None:
paramfile = main_dict["paramdir"]+"parameters_"+main_dict["simname"]+".sbmy"
log_file = main_dict["logdir"]+main_dict["simname"]+".log"
nboxes_tot = int(parsed_args.N_tiles**3)
if have_all_tiles(parsed_args) and not parsed_args.force:
print_message("All tiles already exist. Use -F to overwrite.", 1, "scola", verbose=parsed_args.verbose)
print_ending_module("scola", verbose=parsed_args.verbose)
return
if parsed_args.execution == "local":
from parameters_card import parse_arguments_card
from tqdm import tqdm
card_dict = parse_arguments_card(parsed_args)
print_message("Running sCOLA in local mode.", 1, "scola", verbose=parsed_args.verbose)
tile_bar = tqdm(total=nboxes_tot, desc="sCOLA", unit="box", disable=(parsed_args.verbose!=1)) # The progress bar cannot work if there are print statements in the loop
for b in range(1,nboxes_tot+1):
if not isfile(card_dict["OutputTilesBase"]+str(b)+".h5") or parsed_args.force:
if isfile(log_file+f"_{b}"): # Remove the preexisting log file to allow for the progress_bar to be run normally
from os import remove
remove(log_file+f"_{b}")
if parsed_args.verbose > 1:
print_message(f"Running box {b}/{nboxes_tot}.", 2, "scola", verbose=parsed_args.verbose)
command_args = ["scola", paramfile, log_file, "-b", str(b)]
if parsed_args.verbose < 2:
subprocess.Popen(command_args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # Use Popen instead of run to be able to display the progress bar
progress_bar_from_logfile(log_file+f"_{b}", desc=f" Box {b}/{nboxes_tot}", verbose=parsed_args.verbose, leave=False)
else:
subprocess.run(command_args)
if parsed_args.verbose > 1:
print_message(f"Box {b}/{nboxes_tot} finished.", 3, "scola", verbose=parsed_args.verbose)
else:
if parsed_args.verbose > 1:
print_message(f"Box {b}/{nboxes_tot} already exists. Use -F to overwrite.", 2, "scola", verbose=parsed_args.verbose)
tile_bar.update(1)
tile_bar.close()
print_message("sCOLA finished.", 1, "scola", verbose=parsed_args.verbose)
elif parsed_args.execution == "slurm":
from slurm_submission import create_slurm_script, parse_arguments_slurm
from args_main import parse_arguments_main
import os
print_message("Running scola in slurm mode.", 1, "scola", verbose=parsed_args.verbose)
slurm_dict=parse_arguments_slurm(parsed_args)
main_dict=parse_arguments_main(parsed_args)
if have_no_tiles(parsed_args) or parsed_args.force:
## Submit all boxes
print_message("Submitting all boxes.", 2, "scola", verbose=parsed_args.verbose)
slurm_script = slurm_dict["scripts"]+"scola_"+main_dict["simname"]+".sh"
if not isfile(slurm_script) or parsed_args.force:
print_message(f"SLURM script {slurm_script} does not exist (or forced). Creating it.", 2, "scola", verbose=parsed_args.verbose)
create_slurm_script(
slurm_template=slurm_dict["scola_template"],
slurm_script=slurm_script,
job="scola",
job_config_file=paramfile,
job_log=log_file,
array=(1, nboxes_tot),
job_name=main_dict["simname"],
)
print_message(f"SLURM script written to {slurm_script}.", 3, "scola", verbose=parsed_args.verbose)
else:
print_message(f"SLURM script {slurm_script} exists.", 2, "scola", verbose=parsed_args.verbose)
print_message(f"Submitting scola job to SLURM.", 1, "scola", verbose=parsed_args.verbose)
command_args = ["sbatch", slurm_script]
for b in range(1,nboxes_tot+1):
if isfile(log_file+f"_{b}"): # Remove the preexisting log file to allow for the progress_bar to be run normally
os.remove(log_file+f"_{b}")
if parsed_args.verbose < 2:
subprocess.run(command_args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
else:
subprocess.run(command_args)
print_message("sCOLA job submitted.", 2, "scola", verbose=parsed_args.verbose)
else:
## Submit missing boxes
missing_tiles_arrays = get_missing_tiles_arrays(parsed_args)
print_message(f"Submitting missing boxes: {missing_tiles_arrays}.", 2, "scola", verbose=parsed_args.verbose)
for missing_tiles in missing_tiles_arrays:
slurm_script = slurm_dict["scripts"]+"scola_"+main_dict["simname"]+"_"+str(missing_tiles[0])+"_"+str(missing_tiles[-1])+".sh"
if not isfile(slurm_script):
print_message(f"SLURM script {slurm_script} does not exist. Creating it.", 2, "scola", verbose=parsed_args.verbose)
create_slurm_script(
slurm_template=slurm_dict["scola_template"],
slurm_script=slurm_script,
job="scola",
job_config_file=paramfile,
job_log=log_file,
array=missing_tiles,
job_name=main_dict["simname"],
)
print_message(f"SLURM script written to {slurm_script}.", 3, "scola", verbose=parsed_args.verbose)
else:
print_message(f"SLURM script {slurm_script} exists.", 2, "scola", verbose=parsed_args.verbose)
print_message(f"Submitting scola job to SLURM.", 1, "scola", verbose=parsed_args.verbose)
command_args = ["sbatch", slurm_script]
for b in range(missing_tiles[0],missing_tiles[1]+1):
if isfile(log_file+f"_{b}"): # Remove the preexisting log file to allow for the progress_bar to be run normally
os.remove(log_file+f"_{b}")
if parsed_args.verbose < 2:
subprocess.run(command_args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
else:
subprocess.run(command_args)
print_message("sCOLA job submitted.", 2, "scola", verbose=parsed_args.verbose)
os.remove(slurm_script) # Remove the script after submission (because it is specific to the missing tiles)
else:
raise ValueError(f"Execution mode {parsed_args.execution} not recognized.")
print_ending_module("scola", verbose=parsed_args.verbose)
def main_pre_scola(parsed_args):
"""
Pre-scola function. It calls simbelmyne to generate the LPT phi1 and phi2 potential fields.
If they already exist, it does nothing. If all tiles exist, raises error.
"""
from os.path import isfile
from low_level import print_starting_module, print_message, print_ending_module
from parameters_card import parse_arguments_card
print_starting_module("pre-scola", verbose=parsed_args.verbose)
card_dict = parse_arguments_card(parsed_args)
if not isfile(card_dict["OutputLPTPotential1"]) or not isfile(card_dict["OutputLPTPotential2"]) or parsed_args.force:
if not have_all_tiles(parsed_args):
print_message("Running pre-scola.", 1, "pre-scola", verbose=parsed_args.verbose)
from simbelmyne import main_simbelmyne
main_simbelmyne(parsed_args)
else:
raise NotImplementedError("All tiles exists, so calling simbelmyne would generate the final output instead of the LPT potentials.")
else:
print_message("LPT potentials already exist. Use -F to overwrite.", 1, "pre-scola", verbose=parsed_args.verbose)
print_ending_module("pre-scola", verbose=parsed_args.verbose)
def main_post_scola(parsed_args):
"""
Post-scola function. It calls simbelmyne to generate the final output from all tiles.
If the output already exists, it does nothing. If tiles are missing, print the missing tiles.
"""
from os.path import isfile
from low_level import print_starting_module, print_message, print_ending_module
from parameters_card import parse_arguments_card
print_starting_module("post-scola", verbose=parsed_args.verbose)
card_dict = parse_arguments_card(parsed_args)
output_is_required = (card_dict["WriteFinalDensity"] or card_dict["WriteFinalSnapshot"])
if not output_is_required:
print_message("Output is not required. Skipping post-scola.", 1, "post-scola", verbose=parsed_args.verbose)
print_ending_module("post-scola", verbose=parsed_args.verbose)
return
if (card_dict["WriteFinalDensity"] and not isfile(card_dict["OutputFinalDensity"])) or (card_dict["WriteFinalSnapshot"] and not isfile(card_dict["OutputFinalSnapshot"])) or parsed_args.force:
if have_all_tiles(parsed_args):
print_message("Running post-scola.", 1, "post-scola", verbose=parsed_args.verbose)
from simbelmyne import main_simbelmyne
main_simbelmyne(parsed_args)
else:
missing_tiles_arrays = get_missing_tiles_arrays(parsed_args)
count_missing_tiles = sum([m[1]-m[0]+1 for m in missing_tiles_arrays])
nboxes_tot = int(parsed_args.N_tiles**3)
print_message(f"All tiles are not available. Missing {count_missing_tiles} out of {nboxes_tot} ({100*count_missing_tiles/nboxes_tot:.1f}%)", 1, "post-scola", verbose=parsed_args.verbose)
print_message(f"Missing tiles: {missing_tiles_arrays}", 2, "post-scola", verbose=parsed_args.verbose)
else:
print_message("Output already exists. Use -F to overwrite.", 1, "post-scola", verbose=parsed_args.verbose)
print_ending_module("post-scola", verbose=parsed_args.verbose)
def have_all_tiles(parsed_args):
from os.path import isfile
from parameters_card import parse_arguments_card
card_dict = parse_arguments_card(parsed_args)
nboxes_tot = int(parsed_args.N_tiles**3)
all_tiles = True
for b in range(1,nboxes_tot+1):
if not isfile(card_dict["OutputTilesBase"]+str(b)+".h5"):
all_tiles = False
return all_tiles
def have_no_tiles(parsed_args):
from os.path import isfile
from parameters_card import parse_arguments_card
card_dict = parse_arguments_card(parsed_args)
nboxes_tot = int(parsed_args.N_tiles**3)
no_tiles = True
for b in range(1,nboxes_tot+1):
if isfile(card_dict["OutputTilesBase"]+str(b)+".h5"):
no_tiles = False
return no_tiles
def get_missing_tiles_arrays(parsed_args):
from os.path import isfile
from parameters_card import parse_arguments_card
card_dict = parse_arguments_card(parsed_args)
nboxes_tot = int(parsed_args.N_tiles**3)
missing_tiles_arrays = []
in_sequence_of_missing = False
for b in range(1,nboxes_tot+1):
if not isfile(card_dict["OutputTilesBase"]+str(b)+".h5"):
if not in_sequence_of_missing:
missing_tiles_arrays.append([b])
in_sequence_of_missing = True
elif in_sequence_of_missing:
missing_tiles_arrays[-1].append(b-1)
in_sequence_of_missing = False
if in_sequence_of_missing:
missing_tiles_arrays[-1].append(nboxes_tot)
for m in missing_tiles_arrays:
assert len(m) == 2
assert m[0] <= m[1]
return missing_tiles_arrays
if __name__ == "__main__":
from argparse import ArgumentParser
from args_main import register_arguments_main
from timestepping import register_arguments_timestepping, main_timestepping
from parameters_card import register_arguments_card, main_parameter_card
from cosmo_params import register_arguments_cosmo
from parameters_monofonic import register_arguments_monofonic
from slurm_submission import register_arguments_slurm
from low_level import wait_until_file_exists
parser = ArgumentParser(description="Run sCOLA.")
register_arguments_main(parser)
register_arguments_timestepping(parser)
register_arguments_monofonic(parser)
register_arguments_slurm(parser)
register_arguments_card(parser)
register_arguments_cosmo(parser)
parsed_args = parser.parse_args()
card_dict = main_parameter_card(parsed_args)
nboxes_tot = int(parsed_args.N_tiles**3)
main_timestepping(parsed_args)
main_pre_scola(parsed_args)
if parsed_args.execution == "slurm":
wait_until_file_exists(card_dict["OutputLPTPotential2"], verbose=parsed_args.verbose, limit=5*60)
main_scola(parsed_args)
if parsed_args.execution == "slurm":
for b in range(1,nboxes_tot+1):
wait_until_file_exists(f"{card_dict['OutputTilesBase']}{b}.h5", verbose=parsed_args.verbose, limit=5*60)
main_post_scola(parsed_args)