Compare commits

...

8 commits

32 changed files with 213 additions and 34 deletions

Binary file not shown.

View file

@ -0,0 +1,35 @@
Metadata-Version: 2.4
Name: sbmy_control
Version: 0.1.0
Summary: Simbelmyne control package
Home-page: https://git.aquila-consortium.org/maubin/sbmy_control
Author: Mayeul Aubin
Author-email: mayeul.aubin@iap.fr
License: GPL-3.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: pysbmy
Requires-Dist: numpy
Requires-Dist: matplotlib
Requires-Dist: h5py
Requires-Dist: tqdm
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary
This package provides control functionalities for Simbelmyne. It allows to create automatically all the required files and scripts to run a N-body simulation with Simbelmyne, using monofonIC for initial conditions. The subpackage `analysis` provides tools to analyze the results of the simulation (slices and power spectra), while the subpackage `scripts` includes tools to handle snapshots, tiles and density fields.

View file

@ -0,0 +1,30 @@
setup.py
sbmy_control/ICs.py
sbmy_control/__init__.py
sbmy_control/args_main.py
sbmy_control/cosmo_params.py
sbmy_control/low_level.py
sbmy_control/main.py
sbmy_control/monofonic.py
sbmy_control/parameters_card.py
sbmy_control/parameters_monofonic.py
sbmy_control/progress_bar.py
sbmy_control/scola.py
sbmy_control/simbelmyne.py
sbmy_control/slurm_submission.py
sbmy_control/timestepping.py
sbmy_control.egg-info/PKG-INFO
sbmy_control.egg-info/SOURCES.txt
sbmy_control.egg-info/dependency_links.txt
sbmy_control.egg-info/entry_points.txt
sbmy_control.egg-info/requires.txt
sbmy_control.egg-info/top_level.txt
sbmy_control/analysis/__init__.py
sbmy_control/analysis/colormaps.py
sbmy_control/analysis/power_spectrum.py
sbmy_control/analysis/slices.py
sbmy_control/scripts/__init__.py
sbmy_control/scripts/convert_snapshot_to_density.py
sbmy_control/scripts/field_to_field.py
sbmy_control/scripts/gather_tiles.py
sbmy_control/scripts/scola_submit.py

View file

@ -0,0 +1 @@

View file

@ -0,0 +1,8 @@
[console_scripts]
convert_snapshot_to_density = sbmy_control.scripts.convert_snapshot_to_density:console_main
field_to_field = sbmy_control.scripts.field_to_field:console_main
gather_tiles = sbmy_control.scripts.gather_tiles:console_main
power_spectrum = sbmy_control.analysis.power_spectrum:console_main
sbmy_control = sbmy_control.main:console_main
scola_submit = sbmy_control.scripts.scola_submit:console_main
slices = sbmy_control.analysis.slices:console_main

View file

@ -0,0 +1,5 @@
pysbmy
numpy
matplotlib
h5py
tqdm

View file

@ -0,0 +1 @@
sbmy_control

View file

@ -1,4 +1,5 @@
import numpy as np
import os
kmin = 1e-1
kmax = 2e0
@ -262,7 +263,9 @@ def get_ylims_and_yticks(ylims):
return ylims, yticks
if __name__ == "__main__":
def console_main():
from argparse import ArgumentParser
parser = ArgumentParser(description='Plot power spectra of fields')
@ -286,6 +289,10 @@ if __name__ == "__main__":
if not args.power_spectrum and not args.cross_correlation:
print('You must choose between power_spectrum and cross_correlation.')
exit()
for _k,f in enumerate(args.filenames):
if not os.path.exists(args.directory+f):
raise FileNotFoundError(f"File {args.directory+f} does not exist.")
if args.reference is not None:
from pysbmy.field import read_field
@ -398,5 +405,8 @@ if __name__ == "__main__":
fig.savefig(args.output)
else:
fig.savefig(args.directory+'power_spectrum.png')
if __name__ == "__main__":
console_main()

View file

@ -1,6 +1,7 @@
import numpy as np
import sys
import os
sys.path.append('/home/aubin/Simbelmyne/sbmy_control/')
fs = 18
@ -10,11 +11,11 @@ def add_ax_ticks(ax, ticks, tick_labels):
from matplotlib import ticker
ax.set_xticks(ticks)
ax.set_yticks(ticks)
ax.set_xticklabels(tick_labels)
ax.set_yticklabels(tick_labels)
ax.set_xticklabels([int(t) for t in tick_labels])
ax.set_yticklabels([int(t) for t in tick_labels])
ax.set_xlabel('Mpc/h')
ax.xaxis.set_major_formatter(ticker.FormatStrFormatter('%d'))
ax.yaxis.set_major_formatter(ticker.FormatStrFormatter('%d'))
# ax.xaxis.set_major_formatter(ticker.FormatStrFormatter('%d')) # Does not work
# ax.yaxis.set_major_formatter(ticker.FormatStrFormatter('%d'))
@ -53,7 +54,7 @@ def plot_imshow_with_reference( data_list,
sep = 10 if L[0] < 50 else 20 if L[0] < 100 else 50 if L[0]<250 else 100 if L[0] < 500 else 200 if L[0] < 1000 else 500 if L[0] < 2500 else 1000
ticks = [np.arange(0, l+1, sep)*len(dat)/l for l, dat in zip(L,data_list)]
tick_labels = [np.arange(0, l+1, sep) for l in L]
def score(data, reference):
return np.linalg.norm(data-reference)/np.linalg.norm(reference)
@ -148,8 +149,7 @@ def plot_imshow_diff(data_list,
return fig, axes
if __name__ == "__main__":
def console_main():
from argparse import ArgumentParser
parser = ArgumentParser(description='Comparisons of fields slices.')
@ -177,6 +177,8 @@ if __name__ == "__main__":
ref_field = read_field(args.directory+args.reference) if args.reference is not None else None
fields = []
for k,f in enumerate(args.filenames):
if not os.path.exists(args.directory+f):
raise FileNotFoundError(f"File {args.directory+f} does not exist.")
if args.reference is not None and f == args.reference:
fields.append(ref_field) # Simply copy the reference field instead of reading it again
if args.labels is not None:
@ -220,3 +222,8 @@ if __name__ == "__main__":
fig.savefig(args.output,bbox_inches='tight')
else:
fig.savefig(args.directory+'slices.jpg',bbox_inches='tight')
if __name__ == "__main__":
console_main()

View file

@ -220,7 +220,7 @@ def check_consistency(card_dict, mode):
raise ValueError(f"ModulePMCOLA is not 1: ModulePMCOLA={card_dict["ModulePMCOLA"]}")
if __name__ == "__main__":
def console_main():
from argparse import ArgumentParser
from args_main import register_arguments_main
from timestepping import register_arguments_timestepping, main_timestepping
@ -238,4 +238,9 @@ if __name__ == "__main__":
register_arguments_card(parser)
register_arguments_cosmo(parser)
parsed_args = parser.parse_args()
main(parsed_args)
main(parsed_args)
if __name__ == "__main__":
console_main()

View file

View file

@ -36,8 +36,7 @@ def convert_snapshot_to_density(snapshot_path, output_path, N=None, corner=(0.0,
print("Done.")
if __name__ == "__main__":
def console_main():
parser = argparse.ArgumentParser(description="Convert snapshot to density.")
parser.add_argument(
"-S",
@ -76,4 +75,8 @@ if __name__ == "__main__":
output_path=args.output,
N=args.N,
corner=args.corner,
)
)
if __name__ == "__main__":
console_main()

View file

@ -1,5 +1,5 @@
from pysbmy.density import mesh_to_mesh
from pysbmy.Field import Field, read_field
from pysbmy.field import Field, read_field
import numpy as np
import os
@ -8,23 +8,43 @@ def field_to_field(
input_file:str,
output_file:str,
output_size:int|tuple[int,int,int]|list[int],
output_L:float|tuple[float,float,float]|list[float],
output_dpm:float|tuple[float,float,float]|list[float],
output_corner:tuple[float,float,float]|list[float],
boundary_conditions:int,
):
### Make sure all inputs are valid
if output_L is not None and output_dpm is not None:
raise ValueError("Either output_L or output_dpm can be specified, not both.")
if isinstance(output_size, int):
output_size = (output_size, output_size, output_size) # N0, N1, N2
elif len(output_size) == 1:
output_size = (output_size[0], output_size[0], output_size[0])
if output_L is not None:
if isinstance(output_L, float):
output_L = (output_L, output_L, output_L)
elif len(output_L) == 1:
output_L = (output_L[0], output_L[0], output_L[0])
if isinstance(output_dpm, float):
if output_dpm is None:
if output_L is None:
output_dpm = (-1, -1, -1)
else:
output_dpm = (output_L[0] / output_size[0], output_L[1] / output_size[1], output_L[2] / output_size[2])
elif isinstance(output_dpm, float):
output_dpm = (output_dpm, output_dpm, output_dpm) # d0, d1, d2
elif output_dpm is None:
output_dpm = (-1, -1, -1)
elif len(output_dpm) == 1:
output_dpm = (output_dpm[0], output_dpm[0], output_dpm[0])
if not os.path.exists(input_file):
raise FileNotFoundError(f"Input file {input_file} does not exist.")
# Read the input field
print(f"Reading input field from {input_file}")
input_field = read_field(input_file)
@ -59,9 +79,9 @@ def field_to_field(
print(f"Output field size: {output_size[0]} x {output_size[1]} x {output_size[2]}")
print(f"Input field dpm: {d0_in:.3f} x {d1_in:.3f} x {d2_in:.3f}")
print(f"Output field dpm: {d0_out:.3f} x {d1_out:.3f} x {d2_out:.3f}")
print(f"Input field corner: {corner0:.1f} x {corner1:.1f} x {corner2:.1f}")
print(f"Output field corner: {output_corner[0]:.1f} x {output_corner[1]:.1f} x {output_corner[2]:.1f}")
print(f"Boundary conditions: {boundary_conditions}")
print(f"Input field corner: ({corner0:.1f}, {corner1:.1f}, {corner2:.1f})")
print(f"Output field corner: ({output_corner[0]:.1f}, {output_corner[1]:.1f}, {output_corner[2]:.1f})")
print(f"Boundary conditions: {'periodic' if boundary_conditions == 1 else 'non-periodic'}")
print("-----------------------------------------")
input_grid = input_field.data
@ -95,16 +115,20 @@ def field_to_field(
print("Done.")
if __name__ == "__main__":
def console_main():
import argparse
parser = argparse.ArgumentParser(description="Convert a field from one size to another.")
parser.add_argument("-i","--input_file", type=str, help="Input field file")
parser.add_argument("-o","--output_file", type=str, help="Output field file")
parser.add_argument("-N","--output_size", type=int, nargs=3, help="Output field size (N0, N1, N2)")
parser.add_argument("-dpm","--output_dpm", type=float, nargs=3, default=None, help="Output field dpm (d0, d1, d2)")
parser.add_argument("-N","--output_size", type=int, nargs="+", help="Output field size (N0, N1, N2)")
parser.add_argument("-L","--output_L", type=float, nargs="+", default=None, help="Output field size (L0, L1, L2)")
parser.add_argument("-dpm","--output_dpm", type=float, nargs="+", default=None, help="Output field dpm (d0, d1, d2)")
parser.add_argument("-corner","--output_corner", type=float, nargs=3, default=(0.,0.,0.), help="Output field corner (corner0, corner1, corner2)")
parser.add_argument("-BC","--boundary_conditions", type=int, default=1, help="Boundary conditions (0: periodic, 1: non-periodic)")
parser.add_argument("-BC","--boundary_conditions", type=int, default=1, help="Boundary conditions (1: periodic, 3: non-periodic)")
args = parser.parse_args()
field_to_field(args.input_file, args.output_file, args.output_size, args.output_dpm, args.output_corner, args.boundary_conditions)
field_to_field(args.input_file, args.output_file, args.output_size, args.output_L, args.output_dpm, args.output_corner, args.boundary_conditions)
if __name__ == "__main__":
console_main()

View file

@ -99,8 +99,7 @@ def gather_tiles(folder, tile_base, L, Np, N_TILES, buffer):
if __name__ == "__main__":
def console_main():
parser = argparse.ArgumentParser(description="Gather density from tiles.")
parser.add_argument("-d","--folder", type=str, default="./", help="Folder containing the tiles")
parser.add_argument("--tile_base", type=str, default="sCOLA_tile", help="Base name of the tiles")
@ -121,4 +120,9 @@ if __name__ == "__main__":
Np_tile = Np//N_TILES
dpm = L/Np_tile
gather_tiles(folder, tile_base, L, Np, N_TILES, buffer)
gather_tiles(folder, tile_base, L, Np, N_TILES, buffer)
if __name__ == "__main__":
console_main()

View file

@ -255,7 +255,7 @@ def check_previous_jobs(workdir,slurmdir,slurmfile,tilefile,sleeptime,job_ids_ar
if os.path.exists(workdir+f"{tilefile}{prev_box}.h5"):
job_status_categories['CP'].append(prev_box) # Classify as completed
else:
resubmit_job(slurmdir,slurmfile,job_ids_array,prev_box,resubmit_count,error_count,MAX_RESUBMIT,MAX_ERRORS)
resubmit_count, error_count = resubmit_job(slurmdir,slurmfile,job_ids_array,prev_box,resubmit_count,error_count,MAX_RESUBMIT,MAX_ERRORS)
job_status_categories[status].append(prev_box) # Classify as failed
# Sleep for a while before resubmitting the next job
time.sleep(sleeptime)
@ -445,6 +445,7 @@ def scola_submit(directory,
job_status_categories, resubmit_count, error_count = check_previous_jobs(workdir,slurmdir,slurmfile,tilefile,sleep,job_ids_array,N_tiles**3+1,resubmit_count,error_count,MAX_RESUBMIT,MAX_ERRORS)
print_summary_job_status(job_status_categories, box, resubmit_count, error_count)
# Now wait for all jobs to finish
while len(job_status_categories['CP'])<N_tiles**3:
time.sleep(10*sleep)
@ -461,9 +462,7 @@ def scola_submit(directory,
if __name__ == "__main__":
def console_main():
parser = argparse.ArgumentParser(description="Submit slurm jobs for sCOLA tiles.")
parser.add_argument("-d", "--directory", type=str, default="./", help="Main directory where the output will be saved (if other dir and filenames are not specified).")
@ -495,4 +494,9 @@ if __name__ == "__main__":
if __name__ == "__main__":
console_main()

42
setup.py Normal file
View file

@ -0,0 +1,42 @@
from setuptools import setup, find_packages
setup(
name='sbmy_control',
version='0.1.0',
author='Mayeul Aubin',
author_email='mayeul.aubin@iap.fr',
description='Simbelmyne control package',
long_description='This package provides control functionalities for Simbelmyne. It allows to create automatically all the required files and scripts to run a N-body simulation with Simbelmyne, using monofonIC for initial conditions. The subpackage `analysis` provides tools to analyze the results of the simulation (slices and power spectra), while the subpackage `scripts` includes tools to handle snapshots, tiles and density fields.',
long_description_content_type='text/markdown',
url='https://git.aquila-consortium.org/maubin/sbmy_control',
packages=find_packages(),
install_requires=[
'pysbmy',
'numpy',
'matplotlib',
'h5py',
'tqdm',
],
license='GPL-3.0',
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
],
python_requires='>=3.8',
entry_points={
'console_scripts': [
'sbmy_control=sbmy_control.main:console_main',
'slices=sbmy_control.analysis.slices:console_main',
'power_spectrum=sbmy_control.analysis.power_spectrum:console_main',
'field_to_field=sbmy_control.scripts.field_to_field:console_main',
'gather_tiles=sbmy_control.scripts.gather_tiles:console_main',
'convert_snapshot_to_density=sbmy_control.scripts.convert_snapshot_to_density:console_main',
'scola_submit=sbmy_control.scripts.scola_submit:console_main',
],
},
)