in the middle of fixing custom field import
This commit is contained in:
126
log
Normal file
126
log
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
attempt 1 to compute w_c, this time using Rule(targets={'z_targets': 1, 't': 1, 'time_window': 1, 't_num': 1, 'dt': 1, 'w_c': 1, 'w0': 1, 'w': 1, 'w_power_fact': 1, 'l': 1}, func=<function build_sim_grid_0 at 0x7f9e92cb1280>, args=['length', 'z_num', 'wavelength', 'interpolation_degree', 'time_window', 't_num'])
|
||||||
|
attempt 1 to compute time_window, this time using Rule(targets={'z_targets': 1, 't': 1, 'time_window': 1, 't_num': 1, 'dt': 1, 'w_c': 1, 'w0': 1, 'w': 1, 'w_power_fact': 1, 'l': 1}, func=<function build_sim_grid_0 at 0x7f9e92cb1280>, args=['length', 'z_num', 'wavelength', 'interpolation_degree', 'time_window', 't_num'])
|
||||||
|
error using build_sim_grid_0 : cyclic dependency detected : 'time_window' seems to depend on itself, please provide a value for at least one variable in {'w_c', 'time_window'}
|
||||||
|
attempt 2 to compute time_window, this time using Rule(targets={'z_targets': 1, 't': 1, 'time_window': 1, 't_num': 1, 'dt': 1, 'w_c': 1, 'w0': 1, 'w': 1, 'w_power_fact': 1, 'l': 1}, func=<function build_sim_grid_0 at 0x7f9e92cb11f0>, args=['length', 'z_num', 'wavelength', 'interpolation_degree', 'time_window', 'dt'])
|
||||||
|
error using build_sim_grid_0 : cyclic dependency detected : 'time_window' seems to depend on itself, please provide a value for at least one variable in {'w_c', 'time_window'}
|
||||||
|
attempt 3 to compute time_window, this time using Rule(targets={'z_targets': 1, 't': 1, 'time_window': 1, 't_num': 1, 'dt': 1, 'w_c': 1, 'w0': 1, 'w': 1, 'w_power_fact': 1, 'l': 1}, func=<function build_sim_grid_0 at 0x7f9e92cb1310>, args=['length', 'z_num', 'wavelength', 'interpolation_degree', 't_num', 'dt'])
|
||||||
|
computed z_targets=[0. 0.00043307 0.00086614 0.00129921 0.00173228 0.00216535
|
||||||
|
0.00259843 0.0030315 0.00346457 0.00389764 0.00433071 0.00476378
|
||||||
|
0.00519685 0.00562992 0.00606299 0.00649606 0.00692913 0.0073622
|
||||||
|
0.00779528 0.00822835 0.00866142 0.00909449 0.00952756 0.00996063
|
||||||
|
0.0103937 0.01082677 0.01125984 0.01169291 0.01212598 0.01255906
|
||||||
|
0.01299213 0.0134252 0.01385827 0.01429134 0.01472441 0.01515748
|
||||||
|
0.01559055 0.01602362 0.01645669 0.01688976 0.01732283 0.01775591
|
||||||
|
0.01818898 0.01862205 0.01905512 0.01948819 0.01992126 0.02035433
|
||||||
|
0.0207874 0.02122047 0.02165354 0.02208661 0.02251969 0.02295276
|
||||||
|
0.02338583 0.0238189 0.02425197 0.02468504 0.02511811 0.02555118
|
||||||
|
0.02598425 0.02641732 0.02685039 0.02728346 0.02771654 0.02814961
|
||||||
|
0.02858268 0.02901575 0.02944882 0.02988189 0.03031496 0.03074803
|
||||||
|
0.0311811 0.03161417 0.03204724 0.03248031 0.03291339 0.03334646
|
||||||
|
0.03377953 0.0342126 0.03464567 0.03507874 0.03551181 0.03594488
|
||||||
|
0.03637795 0.03681102 0.03724409 0.03767717 0.03811024 0.03854331
|
||||||
|
0.03897638 0.03940945 0.03984252 0.04027559 0.04070866 0.04114173
|
||||||
|
0.0415748 0.04200787 0.04244094 0.04287402 0.04330709 0.04374016
|
||||||
|
0.04417323 0.0446063 0.04503937 0.04547244 0.04590551 0.04633858
|
||||||
|
0.04677165 0.04720472 0.0476378 0.04807087 0.04850394 0.04893701
|
||||||
|
0.04937008 0.04980315 0.05023622 0.05066929 0.05110236 0.05153543
|
||||||
|
0.0519685 0.05240157 0.05283465 0.05326772 0.05370079 0.05413386
|
||||||
|
0.05456693 0.055 ] using build_sim_grid_0 from evaluator
|
||||||
|
computed t=[-8.1915e-12 -8.1905e-12 -8.1895e-12 ... 8.1895e-12 8.1905e-12
|
||||||
|
8.1915e-12] using build_sim_grid_0 from evaluator
|
||||||
|
computed time_window=1.6383000000000002e-11 using build_sim_grid_0 from evaluator
|
||||||
|
computed w_c=[ 0.00000000e+00 3.83495197e+11 7.66990394e+11 ... -1.15048559e+12
|
||||||
|
-7.66990391e+11 -3.83495194e+11] using build_sim_grid_0 from evaluator
|
||||||
|
computed w0=1226655097231605.2 using build_sim_grid_0 from evaluator
|
||||||
|
computed w=[1.22665510e+15 1.22703859e+15 1.22742209e+15 ... 1.22550461e+15
|
||||||
|
1.22588811e+15 1.22627160e+15] using build_sim_grid_0 from evaluator
|
||||||
|
computed w_power_fact=[[ 0.00000000e+000 7.35342831e+022 2.94137132e+023 ... 6.61808544e+023
|
||||||
|
2.94137130e+023 7.35342818e+022]
|
||||||
|
[ 0.00000000e+000 9.40001479e+033 7.52001183e+034 ... -2.53800397e+035
|
||||||
|
-7.52001174e+034 -9.40001456e+033]
|
||||||
|
[ 0.00000000e+000 9.01215131e+044 1.44194421e+046 ... 7.29984248e+046
|
||||||
|
1.44194419e+046 9.01215101e+044]
|
||||||
|
...
|
||||||
|
[ 0.00000000e+000 1.16026959e+088 2.97029015e+090 ... 7.61252860e+091
|
||||||
|
2.97029005e+090 1.16026951e+088]
|
||||||
|
[ 0.00000000e+000 4.94397571e+098 2.53131557e+101 ... -9.73122716e+102
|
||||||
|
-2.53131547e+101 -4.94397535e+098]
|
||||||
|
[ 0.00000000e+000 1.89599094e+109 1.94149472e+112 ... 1.11956366e+114
|
||||||
|
1.94149464e+112 1.89599078e+109]] using build_sim_grid_0 from evaluator
|
||||||
|
computed l=[1.53560000e-06 1.53512007e-06 1.53464044e-06 ... 1.53704160e-06
|
||||||
|
1.53656077e-06 1.53608023e-06] using build_sim_grid_0 from evaluator
|
||||||
|
computed w_c=[ 0.00000000e+00 3.83495197e+11 7.66990394e+11 ... -1.15048559e+12
|
||||||
|
-7.66990391e+11 -3.83495194e+11] using build_sim_grid_0 from evaluator
|
||||||
|
attempt 1 to compute spec_0, this time using Rule(targets={'spec_0': 3}, func=<function load_previous_spectrum at 0x7f9e8fca7ca0>, args=['prev_data_dir'])
|
||||||
|
error using load_previous_spectrum : no rule for prev_data_dir
|
||||||
|
attempt 2 to compute spec_0, this time using Rule(targets={'spec_0': 1}, func=<function fft at 0x7f9e8dd27040>, args=['field_0'])
|
||||||
|
attempt 1 to compute field_0, this time using Rule(targets={'field_0': 1}, func=<function ifft at 0x7f9e8dd27160>, args=['spec_0'])
|
||||||
|
error using ifft : cyclic dependency detected : 'spec_0' seems to depend on itself, please provide a value for at least one variable in {'field_0', 'spec_0', 'prev_data_dir'}
|
||||||
|
attempt 2 to compute field_0, this time using Rule(targets={'field_0': 1}, func=<function add_shot_noise at 0x7f9e92c9e280>, args=['pre_field_0', 'quantum_noise', 'w_c', 'w0', 'time_window', 'dt'])
|
||||||
|
attempt 1 to compute pre_field_0, this time using Rule(targets={'pre_field_0': 2, 'peak_power': 1, 'energy': 1, 'width': 1}, func=<function load_and_adjust_field_file at 0x7f9e92c9baf0>, args=['field_file', 't', 'peak_power', 'energy', 'intensity_noise', 'noise_correlation'])
|
||||||
|
attempt 1 to compute peak_power, this time using Rule(targets={'pre_field_0': 2, 'peak_power': 1, 'energy': 1, 'width': 1}, func=<function load_and_adjust_field_file at 0x7f9e92c9baf0>, args=['field_file', 't', 'peak_power', 'energy', 'intensity_noise', 'noise_correlation'])
|
||||||
|
error using load_and_adjust_field_file : cyclic dependency detected : 'peak_power' seems to depend on itself, please provide a value for at least one variable in {'peak_power', 'field_0', 'spec_0', 'prev_data_dir', 'pre_field_0'}
|
||||||
|
attempt 2 to compute peak_power, this time using Rule(targets={'peak_power': 1}, func=<function E0_to_P0 at 0x7f9e92c9bca0>, args=['energy', 't0', 'shape'])
|
||||||
|
attempt 1 to compute energy, this time using Rule(targets={'pre_field_0': 2, 'peak_power': 1, 'energy': 1, 'width': 1}, func=<function load_and_adjust_field_file at 0x7f9e92c9baf0>, args=['field_file', 't', 'peak_power', 'energy', 'intensity_noise', 'noise_correlation'])
|
||||||
|
error using load_and_adjust_field_file : cyclic dependency detected : 'peak_power' seems to depend on itself, please provide a value for at least one variable in {'peak_power', 'field_0', 'energy', 'spec_0', 'prev_data_dir', 'pre_field_0'}
|
||||||
|
attempt 2 to compute energy, this time using Rule(targets={'width': 1, 'peak_power': 1, 'energy': 1}, func=<function measure_custom_field at 0x7f9e92c9ec10>, args=['field_file', 't'])
|
||||||
|
computed width=8.827707794861245e-14 using measure_custom_field from scgenerator.physics.pulse
|
||||||
|
computed peak_power=0.0008031855671188997 using measure_custom_field from scgenerator.physics.pulse
|
||||||
|
computed energy=8.994671799886145e-17 using measure_custom_field from scgenerator.physics.pulse
|
||||||
|
attempt 1 to compute t0, this time using Rule(targets={'t0': 1}, func=<function width_to_t0 at 0x7f9e92c9b670>, args=['width', 'shape'])
|
||||||
|
computed t0=7.497564676748131e-14 using width_to_t0 from scgenerator.physics.pulse
|
||||||
|
computed peak_power=0.0009572054484404637 using E0_to_P0 from scgenerator.physics.pulse
|
||||||
|
computed pre_field_0=[0.+0.j 0.+0.j 0.+0.j ... 0.+0.j 0.+0.j 0.+0.j] using load_and_adjust_field_file from scgenerator.physics.pulse
|
||||||
|
computed field_0=[ 0.00160864+0.02127688j -0.01957086-0.0069138j -0.01820735+0.02002421j
|
||||||
|
... 0.00622707-0.01068023j 0.01055843-0.00319426j
|
||||||
|
0.00117607-0.03033724j] using add_shot_noise from scgenerator.physics.pulse
|
||||||
|
computed spec_0=[ 1.50681561-3.69877757j -5.66353753-2.05828961j -0.54462979-1.50501029j
|
||||||
|
... -1.45621111-3.03434314j 2.6362116 -3.91420005j
|
||||||
|
-2.2820021 -3.24150382j] using fft from numpy.fft
|
||||||
|
attempt 1 to compute beta2_coefficients, this time using Rule(targets={'beta2_coefficients': 1}, func=<function dispersion_coefficients at 0x7f9e9158f3a0>, args=['wl_for_disp', 'beta2_arr', 'w0', 'interpolation_range', 'interpolation_degree'])
|
||||||
|
attempt 1 to compute wl_for_disp, this time using Rule(targets={'wl_for_disp': 2, 'beta2_arr': 2, 'interpolation_range': 2}, func=<function load_custom_dispersion at 0x7f9e9158f0d0>, args=['dispersion_file'])
|
||||||
|
computed wl_for_disp=[7.0000e-07 7.0125e-07 7.0250e-07 ... 2.3960e-06 2.3970e-06 2.3980e-06] using load_custom_dispersion from scgenerator.physics.fiber
|
||||||
|
computed beta2_arr=[ 3.37108270e-26 3.37294702e-26 3.37477437e-26 ... -2.08838856e-25
|
||||||
|
-2.09213746e-25 -2.09589149e-25] using load_custom_dispersion from scgenerator.physics.fiber
|
||||||
|
computed interpolation_range=(7e-07, 2.398e-06) using load_custom_dispersion from scgenerator.physics.fiber
|
||||||
|
interpolating dispersion between 700.0nm and 2398.0nm
|
||||||
|
computed beta2_coefficients=[-2.11874551e-026 1.48178177e-040 -4.15401033e-055 2.03223853e-069
|
||||||
|
-1.65547343e-083 1.26886165e-097 -6.93559198e-112 2.31284341e-126
|
||||||
|
-3.54046694e-141] using dispersion_coefficients from scgenerator.physics.fiber
|
||||||
|
attempt 1 to compute gamma_arr, this time using Rule(targets={'gamma_arr': 1}, func=<function gamma_parameter at 0x7f9e9158caf0>, args=['n2', 'w0', 'A_eff_arr'])
|
||||||
|
attempt 1 to compute A_eff_arr, this time using Rule(targets={'A_eff_arr': 1}, func=<function A_eff_from_V at 0x7f9e9158c790>, args=['core_radius', 'V_eff_arr'])
|
||||||
|
error using A_eff_from_V : no rule for core_radius
|
||||||
|
attempt 2 to compute A_eff_arr, this time using Rule(targets={'A_eff_arr': 1}, func=<function load_custom_A_eff at 0x7f9e9158f040>, args=['A_eff_file', 'l'])
|
||||||
|
error using load_custom_A_eff : no rule for A_eff_file
|
||||||
|
attempt 3 to compute A_eff_arr, this time using Rule(targets={'A_eff_arr': -1}, func=<function constant_A_eff_arr at 0x7f9e9158cb80>, args=['l', 'A_eff'])
|
||||||
|
attempt 1 to compute A_eff, this time using Rule(targets={'A_eff': 1}, func=<function A_eff_from_V at 0x7f9e9158c790>, args=['core_radius', 'V_eff'])
|
||||||
|
error using A_eff_from_V : cyclic dependency detected : 'core_radius' seems to depend on itself, please provide a value for at least one variable in {'core_radius', 'A_eff', 'gamma_arr', 'prev_data_dir', 'A_eff_arr', 'A_eff_file'}
|
||||||
|
attempt 2 to compute A_eff, this time using Rule(targets={'A_eff': 1}, func=<function A_eff_from_diam at 0x7f9e9158cca0>, args=['effective_mode_diameter'])
|
||||||
|
computed A_eff=8.01184666481737e-11 using A_eff_from_diam from scgenerator.physics.fiber
|
||||||
|
computed A_eff_arr=[8.01184666e-11 8.01184666e-11 8.01184666e-11 ... 8.01184666e-11
|
||||||
|
8.01184666e-11 8.01184666e-11] using constant_A_eff_arr from scgenerator.physics.fiber
|
||||||
|
computed gamma_arr=[0.00112355 0.00112355 0.00112355 ... 0.00112355 0.00112355 0.00112355] using gamma_parameter from scgenerator.physics.fiber
|
||||||
|
attempt 1 to compute hr_w, this time using Rule(targets={'hr_w': 1}, func=<function delayed_raman_w at 0x7f9e9158f5e0>, args=['t', 'dt', 'raman_type'])
|
||||||
|
computed hr_w=[1.00168656+0.j 1.00197747-0.00248147j 1.00283647-0.00508742j ...
|
||||||
|
1.00422327+0.00793569j 1.00283647+0.00508742j 1.00197747+0.00248147j] using delayed_raman_w from scgenerator.physics.fiber
|
||||||
|
attempt 1 to compute adapt_step_size, this time using Rule(targets={'adapt_step_size': 1}, func=<function <lambda> at 0x7f9e92cb13a0>, args=['step_size'])
|
||||||
|
computed adapt_step_size=True using <lambda> from scgenerator.utils.parameter
|
||||||
|
attempt 1 to compute dynamic_dispersion, this time using Rule(targets={'dynamic_dispersion': 1}, func=<function <lambda> at 0x7f9e92cb1430>, args=['pressure'])
|
||||||
|
computed dynamic_dispersion=False using <lambda> from scgenerator.utils.parameter
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "/Users/benoitsierro/Nextcloud/PhD/Supercontinuum/Module/play.py", line 20, in <module>
|
||||||
|
main()
|
||||||
|
File "/Users/benoitsierro/Nextcloud/PhD/Supercontinuum/Module/play.py", line 10, in main
|
||||||
|
pa = Parameters.load(
|
||||||
|
File "/Users/benoitsierro/Nextcloud/PhD/Supercontinuum/Module/src/scgenerator/utils/parameter.py", line 507, in load
|
||||||
|
return cls(**utils.load_toml(path))
|
||||||
|
File "<string>", line 87, in __init__
|
||||||
|
File "/Users/benoitsierro/Nextcloud/PhD/Supercontinuum/Module/src/scgenerator/utils/parameter.py", line 503, in __post_init__
|
||||||
|
setattr(self, k, v)
|
||||||
|
File "/Users/benoitsierro/Nextcloud/PhD/Supercontinuum/Module/src/scgenerator/utils/parameter.py", line 245, in __set__
|
||||||
|
self.validator(self.name, value)
|
||||||
|
File "/Users/benoitsierro/Nextcloud/PhD/Supercontinuum/Module/src/scgenerator/utils/parameter.py", line 41, in _type_checker_wrapped
|
||||||
|
validator(name, n)
|
||||||
|
File "/Users/benoitsierro/Nextcloud/PhD/Supercontinuum/Module/src/scgenerator/utils/parameter.py", line 105, in int_pair
|
||||||
|
raise ValueError(f"{name!r} must be a list or a tuple of 2 int")
|
||||||
|
ValueError: 'fit_parameters' must be a list or a tuple of 2 int
|
||||||
10
play.py
10
play.py
@@ -1,5 +1,7 @@
|
|||||||
from scgenerator import Parameters
|
from scgenerator import Parameters
|
||||||
|
from scgenerator.physics.simulate import RK4IP
|
||||||
import os
|
import os
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -7,9 +9,13 @@ def main():
|
|||||||
try:
|
try:
|
||||||
os.chdir("/Users/benoitsierro/Nextcloud/PhD/Supercontinuum/PCF Simulations")
|
os.chdir("/Users/benoitsierro/Nextcloud/PhD/Supercontinuum/PCF Simulations")
|
||||||
|
|
||||||
pa = Parameters.load("PM1550+PM2000D/PM1550_PM2000D raman_test/initial_config_0.toml")
|
pa = Parameters.load(
|
||||||
|
"/Users/benoitsierro/Nextcloud/PhD/Supercontinuum/PCF Simulations/PM1550+PM2000D/PM1550_RIN.toml"
|
||||||
|
)
|
||||||
|
|
||||||
print(pa)
|
plt.plot(pa.t, pa.field_0.imag)
|
||||||
|
plt.plot(pa.t, pa.field_0.real)
|
||||||
|
plt.show()
|
||||||
finally:
|
finally:
|
||||||
os.chdir(cwd)
|
os.chdir(cwd)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from . import initialize, io, math, utils
|
from . import initialize, math, utils
|
||||||
from .initialize import (
|
from .initialize import (
|
||||||
Config,
|
Config,
|
||||||
ContinuationParamSequence,
|
ContinuationParamSequence,
|
||||||
@@ -6,11 +6,10 @@ from .initialize import (
|
|||||||
ParamSequence,
|
ParamSequence,
|
||||||
RecoveryParamSequence,
|
RecoveryParamSequence,
|
||||||
)
|
)
|
||||||
from .io import Paths, load_toml
|
|
||||||
from .math import abs2, argclosest, span
|
from .math import abs2, argclosest, span
|
||||||
from .physics import fiber, materials, pulse, simulate, units
|
from .physics import fiber, materials, pulse, simulate, units
|
||||||
from .physics.simulate import RK4IP, new_simulation, resume_simulations
|
from .physics.simulate import RK4IP, new_simulation, resume_simulations
|
||||||
from .physics.units import PlotRange
|
|
||||||
from .plotting import mean_values_plot, plot_spectrogram, propagation_plot, single_position_plot
|
from .plotting import mean_values_plot, plot_spectrogram, propagation_plot, single_position_plot
|
||||||
from .spectra import Pulse, Spectrum
|
from .spectra import Pulse, Spectrum
|
||||||
from .utils.parameter import BareConfig, Parameters
|
from .utils import Paths, load_toml
|
||||||
|
from .utils.parameter import BareConfig, Parameters, PlotRange
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import re
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from .. import env, io, scripts
|
from .. import env, utils, scripts
|
||||||
from ..logger import get_logger
|
from ..logger import get_logger
|
||||||
from ..physics.fiber import dispersion_coefficients
|
from ..physics.fiber import dispersion_coefficients
|
||||||
from ..physics.simulate import SequencialSimulations, resume_simulations, run_simulation_sequence
|
from ..physics.simulate import SequencialSimulations, resume_simulations, run_simulation_sequence
|
||||||
@@ -150,13 +150,13 @@ def run_sim(args):
|
|||||||
|
|
||||||
|
|
||||||
def merge(args):
|
def merge(args):
|
||||||
path_trees = io.build_path_trees(Path(args.path))
|
path_trees = utils.build_path_trees(Path(args.path))
|
||||||
|
|
||||||
output = env.output_path()
|
output = env.output_path()
|
||||||
if output is None:
|
if output is None:
|
||||||
output = path_trees[0][-1][0].parent.name + " merged"
|
output = path_trees[0][-1][0].parent.name + " merged"
|
||||||
|
|
||||||
io.merge(output, path_trees)
|
utils.merge(output, path_trees)
|
||||||
|
|
||||||
|
|
||||||
def prep_ray():
|
def prep_ray():
|
||||||
|
|||||||
@@ -1,34 +1,6 @@
|
|||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
default_parameters = dict(
|
|
||||||
input_transmission=1.0,
|
|
||||||
name="no name",
|
|
||||||
he_mode=(1, 1),
|
|
||||||
fit_parameters=(0.08, 200e-9),
|
|
||||||
model="custom",
|
|
||||||
length=1,
|
|
||||||
n2=2.2e-20,
|
|
||||||
capillary_resonance_strengths=[],
|
|
||||||
capillary_nested=0,
|
|
||||||
gas_name="vacuum",
|
|
||||||
plasma_density=0,
|
|
||||||
pressure=1e5,
|
|
||||||
temperature=300,
|
|
||||||
quantum_noise=False,
|
|
||||||
intensity_noise=0,
|
|
||||||
shape="gaussian",
|
|
||||||
frep=40e6,
|
|
||||||
behaviors=["spm", "ss"],
|
|
||||||
raman_type="agrawal",
|
|
||||||
parallel=True,
|
|
||||||
repeat=1,
|
|
||||||
tolerated_error=1e-11,
|
|
||||||
interpolation_degree=8,
|
|
||||||
interpolation_range=(200e-9, 3000e-9),
|
|
||||||
ideal_gas=False,
|
|
||||||
recovery_last_stored=0,
|
|
||||||
)
|
|
||||||
|
|
||||||
default_plotting = dict(
|
default_plotting = dict(
|
||||||
figsize=(10, 7),
|
figsize=(10, 7),
|
||||||
|
|||||||
@@ -34,3 +34,11 @@ class DuplicateParameterError(Exception):
|
|||||||
|
|
||||||
class IncompleteDataFolderError(FileNotFoundError):
|
class IncompleteDataFolderError(FileNotFoundError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EvaluatorError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NoDefaultError(Exception):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -1,24 +1,23 @@
|
|||||||
import os
|
import os
|
||||||
|
from collections import defaultdict
|
||||||
from collections.abc import Mapping
|
from collections.abc import Mapping
|
||||||
from dataclasses import asdict, dataclass
|
from dataclasses import asdict, dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, Iterator, List, Tuple, Union
|
from typing import Any, Iterator, Union
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from . import io, utils
|
from . import utils
|
||||||
from .defaults import default_parameters
|
|
||||||
from .errors import *
|
from .errors import *
|
||||||
from .logger import get_logger
|
from .logger import get_logger
|
||||||
from .utils import override_config, required_simulations
|
|
||||||
from .utils.evaluator import Evaluator
|
|
||||||
from .utils.parameter import (
|
from .utils.parameter import (
|
||||||
BareConfig,
|
BareConfig,
|
||||||
Parameters,
|
Parameters,
|
||||||
hc_model_specific_parameters,
|
hc_model_specific_parameters,
|
||||||
mandatory_parameters,
|
override_config,
|
||||||
|
required_simulations,
|
||||||
)
|
)
|
||||||
|
from scgenerator.utils import parameter
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -188,12 +187,12 @@ class Config(BareConfig):
|
|||||||
|
|
||||||
|
|
||||||
class ParamSequence:
|
class ParamSequence:
|
||||||
def __init__(self, config_dict: Union[Dict[str, Any], os.PathLike, BareConfig]):
|
def __init__(self, config_dict: Union[dict[str, Any], os.PathLike, BareConfig]):
|
||||||
"""creates a param sequence from a base config
|
"""creates a param sequence from a base config
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
config_dict : Union[Dict[str, Any], os.PathLike, BareConfig]
|
config_dict : Union[dict[str, Any], os.PathLike, BareConfig]
|
||||||
Can be either a dictionary, a path to a config toml file or BareConfig obj
|
Can be either a dictionary, a path to a config toml file or BareConfig obj
|
||||||
"""
|
"""
|
||||||
if isinstance(config_dict, Config):
|
if isinstance(config_dict, Config):
|
||||||
@@ -202,14 +201,14 @@ class ParamSequence:
|
|||||||
self.config = Config.from_bare(config_dict)
|
self.config = Config.from_bare(config_dict)
|
||||||
else:
|
else:
|
||||||
if not isinstance(config_dict, Mapping):
|
if not isinstance(config_dict, Mapping):
|
||||||
config_dict = io.load_toml(config_dict)
|
config_dict = utils.load_toml(config_dict)
|
||||||
self.config = Config(**config_dict)
|
self.config = Config(**config_dict)
|
||||||
self.name = self.config.name
|
self.name = self.config.name
|
||||||
self.logger = get_logger(__name__)
|
self.logger = get_logger(__name__)
|
||||||
|
|
||||||
self.update_num_sim()
|
self.update_num_sim()
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[Tuple[List[Tuple[str, Any]], Parameters]]:
|
def __iter__(self) -> Iterator[tuple[list[tuple[str, Any]], Parameters]]:
|
||||||
"""iterates through all possible parameters, yielding a config as well as a flattened
|
"""iterates through all possible parameters, yielding a config as well as a flattened
|
||||||
computed parameters set each time"""
|
computed parameters set each time"""
|
||||||
for variable_list, params in required_simulations(self.config):
|
for variable_list, params in required_simulations(self.config):
|
||||||
@@ -242,17 +241,17 @@ class ContinuationParamSequence(ParamSequence):
|
|||||||
----------
|
----------
|
||||||
prev_sim_dir : PathLike
|
prev_sim_dir : PathLike
|
||||||
path to the folder of the previous simulation containing 'initial_config.toml'
|
path to the folder of the previous simulation containing 'initial_config.toml'
|
||||||
new_config : Dict[str, Any]
|
new_config : dict[str, Any]
|
||||||
new config
|
new config
|
||||||
"""
|
"""
|
||||||
self.prev_sim_dir = Path(prev_sim_dir)
|
self.prev_sim_dir = Path(prev_sim_dir)
|
||||||
self.bare_configs = BareConfig.load_sequence(new_config.previous_config_file)
|
self.bare_configs = BareConfig.load_sequence(new_config.previous_config_file)
|
||||||
self.bare_configs.append(new_config)
|
self.bare_configs.append(new_config)
|
||||||
self.bare_configs[0] = Config.from_bare(self.bare_configs[0])
|
self.bare_configs[0] = Config.from_bare(self.bare_configs[0])
|
||||||
final_config = utils.final_config_from_sequence(*self.bare_configs)
|
final_config = parameter.final_config_from_sequence(*self.bare_configs)
|
||||||
super().__init__(final_config)
|
super().__init__(final_config)
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[Tuple[List[Tuple[str, Any]], Parameters]]:
|
def __iter__(self) -> Iterator[tuple[list[tuple[str, Any]], Parameters]]:
|
||||||
"""iterates through all possible parameters, yielding a config as well as a flattened
|
"""iterates through all possible parameters, yielding a config as well as a flattened
|
||||||
computed parameters set each time"""
|
computed parameters set each time"""
|
||||||
for variable_list, params in required_simulations(*self.bare_configs):
|
for variable_list, params in required_simulations(*self.bare_configs):
|
||||||
@@ -260,12 +259,12 @@ class ContinuationParamSequence(ParamSequence):
|
|||||||
params.prev_data_dir = str(prev_data_dir.resolve())
|
params.prev_data_dir = str(prev_data_dir.resolve())
|
||||||
yield variable_list, params
|
yield variable_list, params
|
||||||
|
|
||||||
def find_prev_data_dirs(self, new_variable_list: List[Tuple[str, Any]]) -> List[Path]:
|
def find_prev_data_dirs(self, new_variable_list: list[tuple[str, Any]]) -> list[Path]:
|
||||||
"""finds the previous simulation data that this new config should start from
|
"""finds the previous simulation data that this new config should start from
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
new_variable_list : List[Tuple[str, Any]]
|
new_variable_list : list[tuple[str, Any]]
|
||||||
as yielded by required_simulations
|
as yielded by required_simulations
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
@@ -278,7 +277,7 @@ class ContinuationParamSequence(ParamSequence):
|
|||||||
ValueError
|
ValueError
|
||||||
no data folder found
|
no data folder found
|
||||||
"""
|
"""
|
||||||
new_target = set(utils.format_variable_list(new_variable_list).split()[2:])
|
new_target = set(parameter.format_variable_list(new_variable_list).split()[2:])
|
||||||
path_dic = defaultdict(list)
|
path_dic = defaultdict(list)
|
||||||
max_in_common = 0
|
max_in_common = 0
|
||||||
for data_dir in self.prev_sim_dir.glob("id*"):
|
for data_dir in self.prev_sim_dir.glob("id*"):
|
||||||
@@ -315,7 +314,7 @@ class RecoveryParamSequence(ParamSequence):
|
|||||||
self.prev_variable_lists = [
|
self.prev_variable_lists = [
|
||||||
(
|
(
|
||||||
set(variable_list[1:]),
|
set(variable_list[1:]),
|
||||||
self.prev_sim_dir / utils.format_variable_list(variable_list),
|
self.prev_sim_dir / parameter.format_variable_list(variable_list),
|
||||||
)
|
)
|
||||||
for variable_list, _ in required_simulations(init_config)
|
for variable_list, _ in required_simulations(init_config)
|
||||||
]
|
]
|
||||||
@@ -330,12 +329,12 @@ class RecoveryParamSequence(ParamSequence):
|
|||||||
)
|
)
|
||||||
self.update_num_sim(self.num_sim * additional_sims_factor)
|
self.update_num_sim(self.num_sim * additional_sims_factor)
|
||||||
not_started = self.num_sim
|
not_started = self.num_sim
|
||||||
sub_folders = io.get_data_dirs(io.get_sim_dir(self.id))
|
sub_folders = utils.get_data_dirs(utils.get_sim_dir(self.id))
|
||||||
|
|
||||||
for sub_folder in utils.PBars(
|
for sub_folder in utils.PBars(
|
||||||
sub_folders, "Initial recovery", head_kwargs=dict(unit="sim")
|
sub_folders, "Initial recovery", head_kwargs=dict(unit="sim")
|
||||||
):
|
):
|
||||||
num_left = io.num_left_to_propagate(sub_folder, self.config.z_num)
|
num_left = utils.num_left_to_propagate(sub_folder, self.config.z_num)
|
||||||
if num_left == 0:
|
if num_left == 0:
|
||||||
self.num_sim -= 1
|
self.num_sim -= 1
|
||||||
self.num_steps += num_left
|
self.num_steps += num_left
|
||||||
@@ -344,26 +343,26 @@ class RecoveryParamSequence(ParamSequence):
|
|||||||
self.num_steps += not_started * self.config.z_num
|
self.num_steps += not_started * self.config.z_num
|
||||||
self.single_sim = self.num_sim == 1
|
self.single_sim = self.num_sim == 1
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[Tuple[List[Tuple[str, Any]], Parameters]]:
|
def __iter__(self) -> Iterator[tuple[list[tuple[str, Any]], Parameters]]:
|
||||||
for variable_list, params in required_simulations(self.config):
|
for variable_list, params in required_simulations(self.config):
|
||||||
|
|
||||||
data_dir = io.get_sim_dir(self.id) / utils.format_variable_list(variable_list)
|
data_dir = utils.get_sim_dir(self.id) / parameter.format_variable_list(variable_list)
|
||||||
|
|
||||||
if not data_dir.is_dir() or io.find_last_spectrum_num(data_dir) == 0:
|
if not data_dir.is_dir() or utils.find_last_spectrum_num(data_dir) == 0:
|
||||||
if (prev_data_dir := self.find_prev_data_dir(variable_list)) is not None:
|
if (prev_data_dir := self.find_prev_data_dirs(variable_list)) is not None:
|
||||||
params.prev_data_dir = str(prev_data_dir)
|
params.prev_data_dir = str(prev_data_dir)
|
||||||
yield variable_list, params
|
yield variable_list, params
|
||||||
elif io.num_left_to_propagate(data_dir, self.config.z_num) != 0:
|
elif utils.num_left_to_propagate(data_dir, self.config.z_num) != 0:
|
||||||
yield variable_list, params + "Needs to rethink recovery procedure"
|
yield variable_list, params + "Needs to rethink recovery procedure"
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
def find_prev_data_dirs(self, new_variable_list: List[Tuple[str, Any]]) -> List[Path]:
|
def find_prev_data_dirs(self, new_variable_list: list[tuple[str, Any]]) -> list[Path]:
|
||||||
"""finds the previous simulation data that this new config should start from
|
"""finds the previous simulation data that this new config should start from
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
new_variable_list : List[Tuple[str, Any]]
|
new_variable_list : list[tuple[str, Any]]
|
||||||
as yielded by required_simulations
|
as yielded by required_simulations
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
@@ -411,194 +410,3 @@ def validate_config_sequence(*configs: os.PathLike) -> tuple[str, int]:
|
|||||||
new_conf = config
|
new_conf = config
|
||||||
previous = Config.from_bare(override_config(new_conf, previous))
|
previous = Config.from_bare(override_config(new_conf, previous))
|
||||||
return previous.name, count_variations(*configs)
|
return previous.name, count_variations(*configs)
|
||||||
|
|
||||||
|
|
||||||
# def wspace(t, t_num=0):
|
|
||||||
# """frequency array such that x(t) <-> np.fft(x)(w)
|
|
||||||
# Parameters
|
|
||||||
# ----------
|
|
||||||
# t : float or array
|
|
||||||
# float : total width of the time window
|
|
||||||
# array : time array
|
|
||||||
# t_num : int-
|
|
||||||
# if t is a float, specifies the number of points
|
|
||||||
# Returns
|
|
||||||
# ----------
|
|
||||||
# w : array
|
|
||||||
# linspace of frencies corresponding to t
|
|
||||||
# """
|
|
||||||
# if isinstance(t, (np.ndarray, list, tuple)):
|
|
||||||
# dt = t[1] - t[0]
|
|
||||||
# t_num = len(t)
|
|
||||||
# t = t[-1] - t[0] + dt
|
|
||||||
# else:
|
|
||||||
# dt = t / t_num
|
|
||||||
# w = 2 * pi * np.arange(t_num) / t
|
|
||||||
# w = np.where(w >= pi / dt, w - 2 * pi / dt, w)
|
|
||||||
# return w
|
|
||||||
|
|
||||||
|
|
||||||
# def tspace(time_window=None, t_num=None, dt=None):
|
|
||||||
# """returns a time array centered on 0
|
|
||||||
# Parameters
|
|
||||||
# ----------
|
|
||||||
# time_window : float
|
|
||||||
# total time spanned
|
|
||||||
# t_num : int
|
|
||||||
# number of points
|
|
||||||
# dt : float
|
|
||||||
# time resolution
|
|
||||||
|
|
||||||
# at least 2 arguments must be given. They are prioritize as such
|
|
||||||
# t_num > time_window > dt
|
|
||||||
|
|
||||||
# Returns
|
|
||||||
# -------
|
|
||||||
# t : array
|
|
||||||
# a linearily spaced time array
|
|
||||||
# Raises
|
|
||||||
# ------
|
|
||||||
# TypeError
|
|
||||||
# missing at least 1 argument
|
|
||||||
# """
|
|
||||||
# if t_num is not None:
|
|
||||||
# if isinstance(time_window, (float, int)):
|
|
||||||
# return np.linspace(-time_window / 2, time_window / 2, int(t_num))
|
|
||||||
# elif isinstance(dt, (float, int)):
|
|
||||||
# time_window = (t_num - 1) * dt
|
|
||||||
# return np.linspace(-time_window / 2, time_window / 2, t_num)
|
|
||||||
# elif isinstance(time_window, (float, int)) and isinstance(dt, (float, int)):
|
|
||||||
# t_num = int(time_window / dt) + 1
|
|
||||||
# return np.linspace(-time_window / 2, time_window / 2, t_num)
|
|
||||||
# else:
|
|
||||||
# raise TypeError("not enough parameter to determine time vector")
|
|
||||||
|
|
||||||
|
|
||||||
# def recover_params(params: Parameters, data_folder: Path) -> Parameters:
|
|
||||||
# try:
|
|
||||||
# prev = Parameters.load(data_folder / "params.toml")
|
|
||||||
# except FileNotFoundError:
|
|
||||||
# prev = Parameters()
|
|
||||||
# for k, v in filter(lambda el: el[1] is not None, vars(prev).items()):
|
|
||||||
# if getattr(params, k) is None:
|
|
||||||
# setattr(params, k, v)
|
|
||||||
# num, last_spectrum = io.load_last_spectrum(data_folder)
|
|
||||||
# params.spec_0 = last_spectrum
|
|
||||||
# params.field_0 = np.fft.ifft(last_spectrum)
|
|
||||||
# params.recovery_last_stored = num
|
|
||||||
# params.cons_qty = np.load(data_folder / "cons_qty.npy")
|
|
||||||
# return params
|
|
||||||
|
|
||||||
|
|
||||||
# def build_sim_grid(
|
|
||||||
# length: float,
|
|
||||||
# z_num: int,
|
|
||||||
# wavelength: float,
|
|
||||||
# deg: int,
|
|
||||||
# time_window: float = None,
|
|
||||||
# t_num: int = None,
|
|
||||||
# dt: float = None,
|
|
||||||
# ) -> tuple[
|
|
||||||
# np.ndarray, np.ndarray, float, int, float, np.ndarray, float, np.ndarray, np.ndarray, np.ndarray
|
|
||||||
# ]:
|
|
||||||
# """computes a bunch of values that relate to the simulation grid
|
|
||||||
|
|
||||||
# Parameters
|
|
||||||
# ----------
|
|
||||||
# length : float
|
|
||||||
# length of the fiber in m
|
|
||||||
# z_num : int
|
|
||||||
# number of spatial points
|
|
||||||
# wavelength : float
|
|
||||||
# pump wavelength in m
|
|
||||||
# deg : int
|
|
||||||
# dispersion interpolation degree
|
|
||||||
# time_window : float, optional
|
|
||||||
# total width of the temporal grid in s, by default None
|
|
||||||
# t_num : int, optional
|
|
||||||
# number of temporal grid points, by default None
|
|
||||||
# dt : float, optional
|
|
||||||
# spacing of the temporal grid in s, by default None
|
|
||||||
|
|
||||||
# Returns
|
|
||||||
# -------
|
|
||||||
# z_targets : np.ndarray, shape (z_num, )
|
|
||||||
# spatial points in m
|
|
||||||
# t : np.ndarray, shape (t_num, )
|
|
||||||
# temporal points in s
|
|
||||||
# time_window : float
|
|
||||||
# total width of the temporal grid in s, by default None
|
|
||||||
# t_num : int
|
|
||||||
# number of temporal grid points, by default None
|
|
||||||
# dt : float
|
|
||||||
# spacing of the temporal grid in s, by default None
|
|
||||||
# w_c : np.ndarray, shape (t_num, )
|
|
||||||
# centered angular frequencies in rad/s where 0 is the pump frequency
|
|
||||||
# w0 : float
|
|
||||||
# pump angular frequency
|
|
||||||
# w : np.ndarray, shape (t_num, )
|
|
||||||
# actual angualr frequency grid in rad/s
|
|
||||||
# w_power_fact : np.ndarray, shape (deg, t_num)
|
|
||||||
# set of all the necessaray powers of w_c
|
|
||||||
# l : np.ndarray, shape (t_num)
|
|
||||||
# wavelengths in m
|
|
||||||
# """
|
|
||||||
# t = tspace(time_window, t_num, dt)
|
|
||||||
|
|
||||||
# time_window = t.max() - t.min()
|
|
||||||
# dt = t[1] - t[0]
|
|
||||||
# t_num = len(t)
|
|
||||||
# z_targets = np.linspace(0, length, z_num)
|
|
||||||
# w_c, w0, w, w_power_fact = update_frequency_domain(t, wavelength, deg)
|
|
||||||
# l = units.To.m(w)
|
|
||||||
# return z_targets, t, time_window, t_num, dt, w_c, w0, w, w_power_fact, l
|
|
||||||
|
|
||||||
|
|
||||||
# def build_sim_grid_in_place(params: BareParams):
|
|
||||||
# """similar to calling build_sim_grid, but sets the attributes in place"""
|
|
||||||
# (
|
|
||||||
# params.z_targets,
|
|
||||||
# params.t,
|
|
||||||
# params.time_window,
|
|
||||||
# params.t_num,
|
|
||||||
# params.dt,
|
|
||||||
# params.w_c,
|
|
||||||
# params.w0,
|
|
||||||
# params.w,
|
|
||||||
# params.w_power_fact,
|
|
||||||
# params.l,
|
|
||||||
# ) = build_sim_grid(
|
|
||||||
# params.length,
|
|
||||||
# params.z_num,
|
|
||||||
# params.wavelength,
|
|
||||||
# params.interpolation_degree,
|
|
||||||
# params.time_window,
|
|
||||||
# params.t_num,
|
|
||||||
# params.dt,
|
|
||||||
# )
|
|
||||||
|
|
||||||
|
|
||||||
# def update_frequency_domain(
|
|
||||||
# t: np.ndarray, wavelength: float, deg: int
|
|
||||||
# ) -> Tuple[np.ndarray, float, np.ndarray, np.ndarray]:
|
|
||||||
# """updates the frequency grid
|
|
||||||
|
|
||||||
# Parameters
|
|
||||||
# ----------
|
|
||||||
# t : np.ndarray
|
|
||||||
# time array
|
|
||||||
# wavelength : float
|
|
||||||
# wavelength
|
|
||||||
# deg : int
|
|
||||||
# interpolation degree of the dispersion
|
|
||||||
|
|
||||||
# Returns
|
|
||||||
# -------
|
|
||||||
# Tuple[np.ndarray, float, np.ndarray, np.ndarray]
|
|
||||||
# w_c, w0, w, w_power_fact
|
|
||||||
# """
|
|
||||||
# w_c = wspace(t)
|
|
||||||
# w0 = units.m(wavelength)
|
|
||||||
# w = w_c + w0
|
|
||||||
# w_power_fact = np.array([power_fact(w_c, k) for k in range(2, deg + 3)])
|
|
||||||
# return w_c, w0, w, w_power_fact
|
|
||||||
|
|||||||
@@ -1,409 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import itertools
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import TYPE_CHECKING, Any, Callable, Dict, Generator, List, Sequence, Tuple
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
import pkg_resources as pkg
|
|
||||||
import toml
|
|
||||||
from tqdm.std import Bar
|
|
||||||
|
|
||||||
from scgenerator.utils.parameter import BareConfig
|
|
||||||
|
|
||||||
from . import env
|
|
||||||
from .const import PARAM_FN, PARAM_SEPARATOR, SPEC1_FN, SPECN_FN, Z_FN, __version__
|
|
||||||
from .env import TMP_FOLDER_KEY_BASE
|
|
||||||
from .logger import get_logger
|
|
||||||
|
|
||||||
PathTree = List[Tuple[Path, ...]]
|
|
||||||
|
|
||||||
|
|
||||||
class Paths:
|
|
||||||
_data_files = [
|
|
||||||
"silica.toml",
|
|
||||||
"gas.toml",
|
|
||||||
"hr_t.npz",
|
|
||||||
"submit_job_template.txt",
|
|
||||||
"start_worker.sh",
|
|
||||||
"start_head.sh",
|
|
||||||
]
|
|
||||||
|
|
||||||
paths = {
|
|
||||||
f.split(".")[0]: os.path.abspath(
|
|
||||||
pkg.resource_filename("scgenerator", os.path.join("data", f))
|
|
||||||
)
|
|
||||||
for f in _data_files
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get(cls, key):
|
|
||||||
if key not in cls.paths:
|
|
||||||
if os.path.exists("paths.toml"):
|
|
||||||
with open("paths.toml") as file:
|
|
||||||
paths_dico = toml.load(file)
|
|
||||||
for k, v in paths_dico.items():
|
|
||||||
cls.paths[k] = v
|
|
||||||
if key not in cls.paths:
|
|
||||||
get_logger(__name__).info(
|
|
||||||
f"{key} was not found in path index, returning current working directory."
|
|
||||||
)
|
|
||||||
cls.paths[key] = os.getcwd()
|
|
||||||
|
|
||||||
return cls.paths[key]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def gets(cls, key):
|
|
||||||
"""returned the specified file as a string"""
|
|
||||||
with open(cls.get(key)) as file:
|
|
||||||
return file.read()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def plot(cls, name):
|
|
||||||
"""returns the paths to the specified plot. Used to save new plot
|
|
||||||
example
|
|
||||||
---------
|
|
||||||
fig.savefig(Paths.plot("figure5.pdf"))
|
|
||||||
"""
|
|
||||||
return os.path.join(cls.get("plots"), name)
|
|
||||||
|
|
||||||
|
|
||||||
def conform_toml_path(path: os.PathLike) -> Path:
|
|
||||||
path = Path(path)
|
|
||||||
if not path.name.lower().endswith(".toml"):
|
|
||||||
path = path.parent / (path.name + ".toml")
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def load_toml(path: os.PathLike):
|
|
||||||
"""returns a dictionary parsed from the specified toml file"""
|
|
||||||
path = conform_toml_path(path)
|
|
||||||
with open(path, mode="r") as file:
|
|
||||||
dico = toml.load(file)
|
|
||||||
dico.setdefault("variable", {})
|
|
||||||
for key in {"simulation", "fiber", "gas", "pulse"} & dico.keys():
|
|
||||||
section = dico.pop(key, {})
|
|
||||||
dico["variable"].update(section.pop("variable", {}))
|
|
||||||
dico.update(section)
|
|
||||||
if len(dico["variable"]) == 0:
|
|
||||||
dico.pop("variable")
|
|
||||||
return dico
|
|
||||||
|
|
||||||
|
|
||||||
def save_toml(path: os.PathLike, dico):
|
|
||||||
"""saves a dictionary into a toml file"""
|
|
||||||
path = conform_toml_path(path)
|
|
||||||
with open(path, mode="w") as file:
|
|
||||||
toml.dump(dico, file)
|
|
||||||
return dico
|
|
||||||
|
|
||||||
|
|
||||||
def save_parameters(
|
|
||||||
params: dict[str, Any], destination_dir: Path, file_name: str = "params.toml"
|
|
||||||
) -> Path:
|
|
||||||
"""saves a parameter dictionary. Note that is does remove some entries, particularly
|
|
||||||
those that take a lot of space ("t", "w", ...)
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
params : Dict[str, Any]
|
|
||||||
dictionary to save
|
|
||||||
destination_dir : Path
|
|
||||||
destination directory
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
Path
|
|
||||||
path to newly created the paramter file
|
|
||||||
"""
|
|
||||||
file_path = destination_dir / file_name
|
|
||||||
|
|
||||||
file_path.parent.mkdir(exist_ok=True)
|
|
||||||
|
|
||||||
# save toml of the simulation
|
|
||||||
with open(file_path, "w") as file:
|
|
||||||
toml.dump(params, file, encoder=toml.TomlNumpyEncoder())
|
|
||||||
|
|
||||||
return file_path
|
|
||||||
|
|
||||||
|
|
||||||
def load_material_dico(name: str) -> dict[str, Any]:
|
|
||||||
"""loads a material dictionary
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
name : str
|
|
||||||
name of the material
|
|
||||||
Returns
|
|
||||||
----------
|
|
||||||
material_dico : dict
|
|
||||||
"""
|
|
||||||
if name == "silica":
|
|
||||||
return toml.loads(Paths.gets("silica"))
|
|
||||||
else:
|
|
||||||
return toml.loads(Paths.gets("gas"))[name]
|
|
||||||
|
|
||||||
|
|
||||||
def get_data_dirs(sim_dir: Path) -> List[Path]:
|
|
||||||
"""returns a list of absolute paths corresponding to a particular run
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
sim_dir : Path
|
|
||||||
path to directory containing the initial config file and the spectra sub folders
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
List[Path]
|
|
||||||
paths to sub folders
|
|
||||||
"""
|
|
||||||
|
|
||||||
return [p.resolve() for p in sim_dir.glob("*") if p.is_dir()]
|
|
||||||
|
|
||||||
|
|
||||||
def update_appended_params(source: Path, destination: Path, z: Sequence):
|
|
||||||
z_num = len(z)
|
|
||||||
params = load_toml(source)
|
|
||||||
if "simulation" in params:
|
|
||||||
params["simulation"]["z_num"] = z_num
|
|
||||||
params["fiber"]["length"] = float(z[-1] - z[0])
|
|
||||||
else:
|
|
||||||
params["z_num"] = z_num
|
|
||||||
params["length"] = float(z[-1] - z[0])
|
|
||||||
save_toml(destination, params)
|
|
||||||
|
|
||||||
|
|
||||||
def build_path_trees(sim_dir: Path) -> List[PathTree]:
|
|
||||||
sim_dir = sim_dir.resolve()
|
|
||||||
path_branches: List[Tuple[Path, ...]] = []
|
|
||||||
to_check = list(sim_dir.glob("id*num*"))
|
|
||||||
with utils.PBars(len(to_check), desc="Building path trees") as pbar:
|
|
||||||
for branch in map(build_path_branch, to_check):
|
|
||||||
if branch is not None:
|
|
||||||
path_branches.append(branch)
|
|
||||||
pbar.update()
|
|
||||||
path_trees = group_path_branches(path_branches)
|
|
||||||
return path_trees
|
|
||||||
|
|
||||||
|
|
||||||
def build_path_branch(data_dir: Path) -> Tuple[Path, ...]:
|
|
||||||
if not data_dir.is_dir():
|
|
||||||
return None
|
|
||||||
path_branch = [data_dir]
|
|
||||||
while (prev_sim_path := load_toml(path_branch[-1] / PARAM_FN).get("prev_data_dir")) is not None:
|
|
||||||
p = Path(prev_sim_path).resolve()
|
|
||||||
if not p.exists():
|
|
||||||
p = Path(*p.parts[-2:]).resolve()
|
|
||||||
path_branch.append(p)
|
|
||||||
return tuple(reversed(path_branch))
|
|
||||||
|
|
||||||
|
|
||||||
def group_path_branches(path_branches: List[Tuple[Path, ...]]) -> List[PathTree]:
|
|
||||||
"""groups path lists
|
|
||||||
|
|
||||||
[
|
|
||||||
("a/id 0 wavelength 100 num 0"," b/id 0 wavelength 100 num 0"),
|
|
||||||
("a/id 2 wavelength 100 num 1"," b/id 2 wavelength 100 num 1"),
|
|
||||||
("a/id 1 wavelength 200 num 0"," b/id 1 wavelength 200 num 0"),
|
|
||||||
("a/id 3 wavelength 200 num 1"," b/id 3 wavelength 200 num 1")
|
|
||||||
]
|
|
||||||
->
|
|
||||||
[
|
|
||||||
(
|
|
||||||
("a/id 0 wavelength 100 num 0", "a/id 2 wavelength 100 num 1"),
|
|
||||||
("b/id 0 wavelength 100 num 0", "b/id 2 wavelength 100 num 1"),
|
|
||||||
)
|
|
||||||
(
|
|
||||||
("a/id 1 wavelength 200 num 0", "a/id 3 wavelength 200 num 1"),
|
|
||||||
("b/id 1 wavelength 200 num 0", "b/id 3 wavelength 200 num 1"),
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
path_branches : List[Tuple[Path, ...]]
|
|
||||||
each element of the list is a path to a folder containing data of one simulation
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
List[PathTree]
|
|
||||||
List of PathTrees to be used in merge
|
|
||||||
"""
|
|
||||||
sort_key = lambda el: el[0]
|
|
||||||
|
|
||||||
size = len(path_branches[0])
|
|
||||||
out_trees_map: Dict[str, Dict[int, Dict[int, Path]]] = {}
|
|
||||||
for branch in path_branches:
|
|
||||||
b_id = utils.branch_id(branch)
|
|
||||||
out_trees_map.setdefault(b_id, {i: {} for i in range(size)})
|
|
||||||
for sim_part, data_dir in enumerate(branch):
|
|
||||||
*_, num = data_dir.name.split()
|
|
||||||
out_trees_map[b_id][sim_part][int(num)] = data_dir
|
|
||||||
|
|
||||||
return [
|
|
||||||
tuple(
|
|
||||||
tuple(w for _, w in sorted(v.items(), key=sort_key))
|
|
||||||
for __, v in sorted(d.items(), key=sort_key)
|
|
||||||
)
|
|
||||||
for d in out_trees_map.values()
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def merge_path_tree(
|
|
||||||
path_tree: PathTree, destination: Path, z_callback: Callable[[int], None] = None
|
|
||||||
):
|
|
||||||
"""given a path tree, copies the file into the right location
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
path_tree : PathTree
|
|
||||||
elements of the list returned by group_path_branches
|
|
||||||
destination : Path
|
|
||||||
dir where to save the data
|
|
||||||
"""
|
|
||||||
z_arr: List[float] = []
|
|
||||||
|
|
||||||
destination.mkdir(exist_ok=True)
|
|
||||||
|
|
||||||
for i, (z, merged_spectra) in enumerate(merge_spectra(path_tree)):
|
|
||||||
z_arr.append(z)
|
|
||||||
spec_out_name = SPECN_FN.format(i)
|
|
||||||
np.save(destination / spec_out_name, merged_spectra)
|
|
||||||
if z_callback is not None:
|
|
||||||
z_callback(i)
|
|
||||||
d = np.diff(z_arr)
|
|
||||||
d[d < 0] = 0
|
|
||||||
z_arr = np.concatenate(([z_arr[0]], np.cumsum(d)))
|
|
||||||
np.save(destination / Z_FN, z_arr)
|
|
||||||
update_appended_params(path_tree[-1][0] / PARAM_FN, destination / PARAM_FN, z_arr)
|
|
||||||
|
|
||||||
|
|
||||||
def merge_spectra(
|
|
||||||
path_tree: PathTree,
|
|
||||||
) -> Generator[Tuple[float, np.ndarray], None, None]:
|
|
||||||
for same_sim_paths in path_tree:
|
|
||||||
z_arr = np.load(same_sim_paths[0] / Z_FN)
|
|
||||||
for i, z in enumerate(z_arr):
|
|
||||||
spectra: List[np.ndarray] = []
|
|
||||||
for data_dir in same_sim_paths:
|
|
||||||
spec = np.load(data_dir / SPEC1_FN.format(i))
|
|
||||||
spectra.append(spec)
|
|
||||||
yield z, np.atleast_2d(spectra)
|
|
||||||
|
|
||||||
|
|
||||||
def merge(destination: os.PathLike, path_trees: List[PathTree] = None):
|
|
||||||
|
|
||||||
destination = ensure_folder(Path(destination))
|
|
||||||
|
|
||||||
z_num = 0
|
|
||||||
prev_z_num = 0
|
|
||||||
|
|
||||||
for i, sim_dir in enumerate(sim_dirs(path_trees)):
|
|
||||||
conf = sim_dir / "initial_config.toml"
|
|
||||||
shutil.copy(
|
|
||||||
conf,
|
|
||||||
destination / f"initial_config_{i}.toml",
|
|
||||||
)
|
|
||||||
prev_z_num = load_toml(conf).get("z_num", prev_z_num)
|
|
||||||
z_num += prev_z_num
|
|
||||||
|
|
||||||
pbars = utils.PBars(
|
|
||||||
len(path_trees) * z_num, "Merging", 1, worker_kwargs=dict(total=z_num, desc="current pos")
|
|
||||||
)
|
|
||||||
for path_tree in path_trees:
|
|
||||||
pbars.reset(1)
|
|
||||||
iden = PARAM_SEPARATOR.join(path_tree[-1][0].name.split()[2:-2])
|
|
||||||
merge_path_tree(path_tree, destination / iden, z_callback=lambda i: pbars.update(1))
|
|
||||||
|
|
||||||
|
|
||||||
def sim_dirs(path_trees: List[PathTree]) -> Generator[Path, None, None]:
|
|
||||||
for p in path_trees[0]:
|
|
||||||
yield p[0].parent
|
|
||||||
|
|
||||||
|
|
||||||
def get_sim_dir(task_id: int, path_if_new: Path = None) -> Path:
|
|
||||||
if path_if_new is None:
|
|
||||||
path_if_new = Path("scgenerator data")
|
|
||||||
tmp = env.data_folder(task_id)
|
|
||||||
if tmp is None:
|
|
||||||
tmp = ensure_folder(path_if_new)
|
|
||||||
os.environ[TMP_FOLDER_KEY_BASE + str(task_id)] = str(tmp)
|
|
||||||
tmp = Path(tmp).resolve()
|
|
||||||
if not tmp.exists():
|
|
||||||
tmp.mkdir()
|
|
||||||
return tmp
|
|
||||||
|
|
||||||
|
|
||||||
def set_data_folder(task_id: int, path: os.PathLike):
|
|
||||||
"""stores the path to an existing data folder in the environment
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
task_id : int
|
|
||||||
id uniquely identifying the session
|
|
||||||
path : str
|
|
||||||
path to the root of the data folder
|
|
||||||
"""
|
|
||||||
idstr = str(int(task_id))
|
|
||||||
os.environ[TMP_FOLDER_KEY_BASE + idstr] = str(path)
|
|
||||||
|
|
||||||
|
|
||||||
def save_data(data: np.ndarray, data_dir: Path, file_name: str):
|
|
||||||
"""saves numpy array to disk
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
data : np.ndarray
|
|
||||||
data to save
|
|
||||||
file_name : str
|
|
||||||
file name
|
|
||||||
task_id : int
|
|
||||||
id that uniquely identifies the process
|
|
||||||
identifier : str, optional
|
|
||||||
identifier in the main data folder of the task, by default ""
|
|
||||||
"""
|
|
||||||
path = data_dir / file_name
|
|
||||||
np.save(path, data)
|
|
||||||
get_logger(__name__).debug(f"saved data in {path}")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def ensure_folder(path: Path, prevent_overwrite: bool = True) -> Path:
|
|
||||||
"""ensure a folder exists and doesn't overwrite anything if required
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
path : Path
|
|
||||||
desired path
|
|
||||||
prevent_overwrite : bool, optional
|
|
||||||
whether to create a new directory when one already exists, by default True
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
Path
|
|
||||||
final path
|
|
||||||
"""
|
|
||||||
|
|
||||||
path = path.resolve()
|
|
||||||
|
|
||||||
# is path root ?
|
|
||||||
if len(path.parts) < 2:
|
|
||||||
return path
|
|
||||||
|
|
||||||
# is a part of path an existing *file* ?
|
|
||||||
parts = path.parts
|
|
||||||
path = Path(path.root)
|
|
||||||
for part in parts:
|
|
||||||
if path.is_file():
|
|
||||||
path = ensure_folder(path, prevent_overwrite=False)
|
|
||||||
path /= part
|
|
||||||
|
|
||||||
folder_name = path.name
|
|
||||||
|
|
||||||
for i in itertools.count():
|
|
||||||
if not path.is_file() and (not prevent_overwrite or not path.is_dir()):
|
|
||||||
path.mkdir(exist_ok=True)
|
|
||||||
return path
|
|
||||||
path = path.parent / (folder_name + f"_{i}")
|
|
||||||
@@ -8,8 +8,9 @@ from typing import TypeVar
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from scipy.optimize import minimize_scalar
|
from scipy.optimize import minimize_scalar
|
||||||
|
|
||||||
from .. import math, io
|
from .. import math
|
||||||
from . import fiber, materials, units, pulse
|
from . import fiber, materials, units, pulse
|
||||||
|
from .. import utils
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ def material_dispersion(
|
|||||||
|
|
||||||
order = np.argsort(w)
|
order = np.argsort(w)
|
||||||
|
|
||||||
material_dico = io.load_material_dico(material)
|
material_dico = utils.load_material_dico(material)
|
||||||
if ideal:
|
if ideal:
|
||||||
n_gas_2 = materials.sellmeier(wavelengths, material_dico, pressure, temperature) + 1
|
n_gas_2 = materials.sellmeier(wavelengths, material_dico, pressure, temperature) + 1
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from scipy.interpolate import interp1d
|
|||||||
|
|
||||||
from ..logger import get_logger
|
from ..logger import get_logger
|
||||||
|
|
||||||
from .. import io
|
from .. import utils
|
||||||
from ..math import abs2, argclosest, power_fact, u_nm
|
from ..math import abs2, argclosest, power_fact, u_nm
|
||||||
from ..utils.cache import np_cache
|
from ..utils.cache import np_cache
|
||||||
from . import materials as mat
|
from . import materials as mat
|
||||||
@@ -247,7 +247,7 @@ def n_eff_hasan(
|
|||||||
|
|
||||||
n_eff_2 = n_gas_2 - (u * wl_for_disp / (pipi * R_eff)) ** 2
|
n_eff_2 = n_gas_2 - (u * wl_for_disp / (pipi * R_eff)) ** 2
|
||||||
|
|
||||||
chi_sil = mat.sellmeier(wl_for_disp, io.load_material_dico("silica"))
|
chi_sil = mat.sellmeier(wl_for_disp, utils.load_material_dico("silica"))
|
||||||
|
|
||||||
with np.errstate(divide="ignore", invalid="ignore"):
|
with np.errstate(divide="ignore", invalid="ignore"):
|
||||||
for m, strength in enumerate(capillary_resonance_strengths):
|
for m, strength in enumerate(capillary_resonance_strengths):
|
||||||
@@ -670,7 +670,7 @@ def n_eff_pcf(wl_for_disp: np.ndarray, pitch: float, pitch_ratio: float) -> np.n
|
|||||||
n_eff2 = (wl_for_disp * W / (pi2a)) ** 2 + n_FSM2
|
n_eff2 = (wl_for_disp * W / (pi2a)) ** 2 + n_FSM2
|
||||||
n_eff = np.sqrt(n_eff2)
|
n_eff = np.sqrt(n_eff2)
|
||||||
|
|
||||||
material_dico = io.load_material_dico("silica")
|
material_dico = utils.load_material_dico("silica")
|
||||||
chi_mat = mat.sellmeier(wl_for_disp, material_dico)
|
chi_mat = mat.sellmeier(wl_for_disp, material_dico)
|
||||||
return n_eff + np.sqrt(chi_mat + 1)
|
return n_eff + np.sqrt(chi_mat + 1)
|
||||||
|
|
||||||
@@ -882,7 +882,7 @@ def delayed_raman_t(t: np.ndarray, raman_type: str) -> np.ndarray:
|
|||||||
|
|
||||||
elif raman_type == "measured":
|
elif raman_type == "measured":
|
||||||
try:
|
try:
|
||||||
path = io.Paths.get("hr_t")
|
path = utils.Paths.get("hr_t")
|
||||||
loaded = np.load(path)
|
loaded = np.load(path)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print(
|
print(
|
||||||
@@ -1090,7 +1090,7 @@ def capillary_loss(
|
|||||||
"""
|
"""
|
||||||
alpha = np.zeros_like(wl_for_disp)
|
alpha = np.zeros_like(wl_for_disp)
|
||||||
mask = wl_for_disp > 0
|
mask = wl_for_disp > 0
|
||||||
chi_silica = mat.sellmeier(wl_for_disp[mask], io.load_material_dico("silica"))
|
chi_silica = mat.sellmeier(wl_for_disp[mask], utils.load_material_dico("silica"))
|
||||||
nu_n = 0.5 * (chi_silica + 2) / np.sqrt(chi_silica)
|
nu_n = 0.5 * (chi_silica + 2) / np.sqrt(chi_silica)
|
||||||
alpha[mask] = nu_n * (u_nm(*he_mode) * wl_for_disp[mask] / pipi) ** 2 * core_radius ** -3
|
alpha[mask] = nu_n * (u_nm(*he_mode) * wl_for_disp[mask] / pipi) ** 2 * core_radius ** -3
|
||||||
return alpha
|
return alpha
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ from scipy.integrate import cumulative_trapezoid
|
|||||||
|
|
||||||
from ..logger import get_logger
|
from ..logger import get_logger
|
||||||
from . import units
|
from . import units
|
||||||
from .. import io
|
from .. import utils
|
||||||
from .units import NA, c, kB, me, e, hbar
|
from .units import NA, c, kB, me, e, hbar
|
||||||
|
|
||||||
|
|
||||||
def n_gas_2(
|
def n_gas_2(
|
||||||
wl_for_disp: np.ndarray, gas: str, pressure: float, temperature: float, ideal_gas: bool
|
wl_for_disp: np.ndarray, gas: str, pressure: float, temperature: float, ideal_gas: bool
|
||||||
):
|
):
|
||||||
material_dico = io.load_material_dico(gas)
|
material_dico = utils.load_material_dico(gas)
|
||||||
|
|
||||||
if ideal_gas:
|
if ideal_gas:
|
||||||
n_gas_2 = sellmeier(wl_for_disp, material_dico, pressure, temperature) + 1
|
n_gas_2 = sellmeier(wl_for_disp, material_dico, pressure, temperature) + 1
|
||||||
@@ -103,7 +103,7 @@ def sellmeier(lambda_, material_dico, pressure=None, temperature=None):
|
|||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
lambda_ : wl vector over which to compute the refractive index
|
lambda_ : wl vector over which to compute the refractive index
|
||||||
material_dico : material dictionary as explained in scgenerator.io.load_material_dico
|
material_dico : material dictionary as explained in scgenerator.utils.load_material_dico
|
||||||
pressure : pressure in mbar if material is a gas. Can be a constant or a tupple if a presure gradient is considered
|
pressure : pressure in mbar if material is a gas. Can be a constant or a tupple if a presure gradient is considered
|
||||||
temperature : temperature of the gas in Kelvin
|
temperature : temperature of the gas in Kelvin
|
||||||
Returns
|
Returns
|
||||||
@@ -150,7 +150,7 @@ def delta_gas(w, material_dico):
|
|||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
w : angular frequency array
|
w : angular frequency array
|
||||||
material_dico : material dictionary as explained in scgenerator.io.load_material_dico
|
material_dico : material dictionary as explained in scgenerator.utils.load_material_dico
|
||||||
Returns
|
Returns
|
||||||
----------
|
----------
|
||||||
delta_t
|
delta_t
|
||||||
|
|||||||
@@ -11,25 +11,23 @@ n is the number of spectra at the same z position and nt is the size of the time
|
|||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
import os
|
import os
|
||||||
|
from dataclasses import astuple, dataclass, fields
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Literal, Tuple, TypeVar
|
from typing import Literal, Tuple, TypeVar
|
||||||
from collections import namedtuple
|
|
||||||
from dataclasses import dataclass, astuple
|
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from numpy import pi
|
from numpy import pi
|
||||||
from numpy.fft import fft, fftshift, ifft
|
from numpy.fft import fft, fftshift, ifft
|
||||||
from scipy import optimize
|
|
||||||
from scipy.interpolate import UnivariateSpline
|
from scipy.interpolate import UnivariateSpline
|
||||||
from scipy.optimize import minimize_scalar
|
from scipy.optimize import minimize_scalar
|
||||||
from scipy.optimize.optimize import OptimizeResult
|
from scipy.optimize.optimize import OptimizeResult
|
||||||
|
|
||||||
from .. import io
|
from scgenerator import utils
|
||||||
|
|
||||||
from ..defaults import default_plotting
|
from ..defaults import default_plotting
|
||||||
from ..logger import get_logger
|
from ..logger import get_logger
|
||||||
from ..math import *
|
from ..math import *
|
||||||
from ..plotting import plot_setup
|
|
||||||
from . import units
|
from . import units
|
||||||
|
|
||||||
c = 299792458.0
|
c = 299792458.0
|
||||||
@@ -317,24 +315,18 @@ def L_sol(L_D):
|
|||||||
return pi / 2 * L_D
|
return pi / 2 * L_D
|
||||||
|
|
||||||
|
|
||||||
def load_previous_spectrum(prev_data_dir: str) -> np.ndarray:
|
def load_and_adjust_field_file(
|
||||||
num = utils.find_last_spectrum_num(data_dir)
|
|
||||||
return np.load(data_dir / SPEC1_FN.format(num))
|
|
||||||
|
|
||||||
|
|
||||||
def load_field_file(
|
|
||||||
field_file: str,
|
field_file: str,
|
||||||
t: np.ndarray,
|
t: np.ndarray,
|
||||||
peak_power: float,
|
|
||||||
energy: float,
|
|
||||||
intensity_noise: float,
|
intensity_noise: float,
|
||||||
noise_correlation: float,
|
noise_correlation: float,
|
||||||
|
energy: float = None,
|
||||||
|
peak_power: float = None,
|
||||||
) -> np.ndarray:
|
) -> np.ndarray:
|
||||||
field_data = np.load(field_file)
|
field_0 = load_field_file(field_file, t)
|
||||||
field_interp = interp1d(
|
if energy is not None:
|
||||||
field_data["time"], field_data["field"], bounds_error=False, fill_value=(0, 0)
|
curr_energy = np.trapz(abs2(field_0), t)
|
||||||
)
|
field_0 *=
|
||||||
field_0 = field_interp(t)
|
|
||||||
|
|
||||||
field_0 = field_0 * modify_field_ratio(
|
field_0 = field_0 * modify_field_ratio(
|
||||||
t, field_0, peak_power, energy, intensity_noise, noise_correlation
|
t, field_0, peak_power, energy, intensity_noise, noise_correlation
|
||||||
@@ -343,6 +335,15 @@ def load_field_file(
|
|||||||
return field_0, peak_power, energy, width
|
return field_0, peak_power, energy, width
|
||||||
|
|
||||||
|
|
||||||
|
def load_field_file(field_file: str, t: np.ndarray) -> np.ndarray:
|
||||||
|
field_data = np.load(field_file)
|
||||||
|
field_interp = interp1d(
|
||||||
|
field_data["time"], field_data["field"], bounds_error=False, fill_value=(0, 0)
|
||||||
|
)
|
||||||
|
field_0 = field_interp(t)
|
||||||
|
return field_0
|
||||||
|
|
||||||
|
|
||||||
def correct_wavelength(init_wavelength: float, w_c: np.ndarray, field_0: np.ndarray) -> float:
|
def correct_wavelength(init_wavelength: float, w_c: np.ndarray, field_0: np.ndarray) -> float:
|
||||||
"""
|
"""
|
||||||
finds a new wavelength parameter such that the maximum of the spectrum corresponding
|
finds a new wavelength parameter such that the maximum of the spectrum corresponding
|
||||||
@@ -908,7 +909,7 @@ def _detailed_find_lobe_limits(
|
|||||||
# if the final measurement is good or not
|
# if the final measurement is good or not
|
||||||
|
|
||||||
out_path, fig, ax = (
|
out_path, fig, ax = (
|
||||||
plot_setup(out_path=f"measurement_errors_plots/it_{iterations}_{debug}")
|
(Path(f"measurement_errors_plots/it_{iterations}_{debug}"), *plt.subplots())
|
||||||
if debug != ""
|
if debug != ""
|
||||||
else (None, None, None)
|
else (None, None, None)
|
||||||
)
|
)
|
||||||
@@ -1055,6 +1056,10 @@ def measure_field(t: np.ndarray, field: np.ndarray) -> Tuple[float, float, float
|
|||||||
return fwhm, peak_power, energy
|
return fwhm, peak_power, energy
|
||||||
|
|
||||||
|
|
||||||
|
def measure_custom_field(field_file: str, t: np.ndarray) -> float:
|
||||||
|
return measure_field(t, load_field_file(field_file, t))[0]
|
||||||
|
|
||||||
|
|
||||||
def remove_2nd_order_dispersion(
|
def remove_2nd_order_dispersion(
|
||||||
spectrum: T, w_c: np.ndarray, beta2: float, max_z: float = -100.0
|
spectrum: T, w_c: np.ndarray, beta2: float, max_z: float = -100.0
|
||||||
) -> tuple[T, OptimizeResult]:
|
) -> tuple[T, OptimizeResult]:
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import os
|
|||||||
import random
|
import random
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Tuple, Type, Union
|
from typing import Type
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from .. import env, initialize, io, utils
|
from .. import env, initialize, utils
|
||||||
from ..utils import Parameters, BareConfig
|
from ..utils.parameter import Parameters, BareConfig
|
||||||
from ..const import PARAM_SEPARATOR
|
from ..const import PARAM_SEPARATOR
|
||||||
from ..errors import IncompleteDataFolderError
|
from ..errors import IncompleteDataFolderError
|
||||||
from ..logger import get_logger
|
from ..logger import get_logger
|
||||||
@@ -55,7 +55,7 @@ class RK4IP:
|
|||||||
self.job_identifier = job_identifier
|
self.job_identifier = job_identifier
|
||||||
self.id = task_id
|
self.id = task_id
|
||||||
|
|
||||||
self.sim_dir = io.get_sim_dir(self.id)
|
self.sim_dir = utils.get_sim_dir(self.id)
|
||||||
self.sim_dir.mkdir(exist_ok=True)
|
self.sim_dir.mkdir(exist_ok=True)
|
||||||
self.data_dir = self.sim_dir / self.job_identifier
|
self.data_dir = self.sim_dir / self.job_identifier
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ class RK4IP:
|
|||||||
self.dw = self.w[1] - self.w[0]
|
self.dw = self.w[1] - self.w[0]
|
||||||
self.w0 = params.w0
|
self.w0 = params.w0
|
||||||
self.w_power_fact = params.w_power_fact
|
self.w_power_fact = params.w_power_fact
|
||||||
self.alpha = params.alpha
|
self.alpha = params.alpha_arr
|
||||||
self.spec_0 = np.sqrt(params.input_transmission) * params.spec_0
|
self.spec_0 = np.sqrt(params.input_transmission) * params.spec_0
|
||||||
self.z_targets = params.z_targets
|
self.z_targets = params.z_targets
|
||||||
self.z_final = params.length
|
self.z_final = params.length
|
||||||
@@ -81,7 +81,7 @@ class RK4IP:
|
|||||||
self.raman_type = params.raman_type
|
self.raman_type = params.raman_type
|
||||||
self.hr_w = params.hr_w
|
self.hr_w = params.hr_w
|
||||||
self.adapt_step_size = params.adapt_step_size
|
self.adapt_step_size = params.adapt_step_size
|
||||||
self.error_ok = params.tolerated_error
|
self.error_ok = params.tolerated_error if self.adapt_step_size else params.step_size
|
||||||
self.dynamic_dispersion = params.dynamic_dispersion
|
self.dynamic_dispersion = params.dynamic_dispersion
|
||||||
self.starting_num = params.recovery_last_stored
|
self.starting_num = params.recovery_last_stored
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ class RK4IP:
|
|||||||
name : str
|
name : str
|
||||||
file name
|
file name
|
||||||
"""
|
"""
|
||||||
io.save_data(data, self.data_dir, name)
|
utils.save_data(data, self.data_dir, name)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
@@ -241,7 +241,7 @@ class RK4IP:
|
|||||||
|
|
||||||
def take_step(
|
def take_step(
|
||||||
self, step: int, h_next_step: float, current_spectrum: np.ndarray
|
self, step: int, h_next_step: float, current_spectrum: np.ndarray
|
||||||
) -> Tuple[float, float, np.ndarray]:
|
) -> tuple[float, float, np.ndarray]:
|
||||||
"""computes a new spectrum, whilst adjusting step size if required, until the error estimation
|
"""computes a new spectrum, whilst adjusting step size if required, until the error estimation
|
||||||
validates the new spectrum
|
validates the new spectrum
|
||||||
|
|
||||||
@@ -385,8 +385,8 @@ class Simulations:
|
|||||||
New Simulations child classes can be written and must implement the following
|
New Simulations child classes can be written and must implement the following
|
||||||
"""
|
"""
|
||||||
|
|
||||||
simulation_methods: List[Tuple[Type["Simulations"], int]] = []
|
simulation_methods: list[tuple[Type["Simulations"], int]] = []
|
||||||
simulation_methods_dict: Dict[str, Type["Simulations"]] = dict()
|
simulation_methods_dict: dict[str, Type["Simulations"]] = dict()
|
||||||
|
|
||||||
def __init_subclass__(cls, priority=0, **kwargs):
|
def __init_subclass__(cls, priority=0, **kwargs):
|
||||||
Simulations.simulation_methods.append((cls, priority))
|
Simulations.simulation_methods.append((cls, priority))
|
||||||
@@ -437,16 +437,16 @@ class Simulations:
|
|||||||
"""
|
"""
|
||||||
if not self.is_available():
|
if not self.is_available():
|
||||||
raise RuntimeError(f"{self.__class__} is currently not available")
|
raise RuntimeError(f"{self.__class__} is currently not available")
|
||||||
self.logger = io.get_logger(__name__)
|
self.logger = get_logger(__name__)
|
||||||
self.id = int(task_id)
|
self.id = int(task_id)
|
||||||
|
|
||||||
self.update(param_seq)
|
self.update(param_seq)
|
||||||
|
|
||||||
self.name = self.param_seq.name
|
self.name = self.param_seq.name
|
||||||
self.sim_dir = io.get_sim_dir(
|
self.sim_dir = utils.get_sim_dir(
|
||||||
self.id, path_if_new=Path(self.name + PARAM_SEPARATOR + "tmp")
|
self.id, path_if_new=Path(self.name + PARAM_SEPARATOR + "tmp")
|
||||||
)
|
)
|
||||||
io.save_parameters(
|
utils.save_parameters(
|
||||||
self.param_seq.config.prepare_for_dump(), self.sim_dir, file_name="initial_config.toml"
|
self.param_seq.config.prepare_for_dump(), self.sim_dir, file_name="initial_config.toml"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -455,7 +455,9 @@ class Simulations:
|
|||||||
@property
|
@property
|
||||||
def finished_and_complete(self):
|
def finished_and_complete(self):
|
||||||
try:
|
try:
|
||||||
io.check_data_integrity(io.get_data_dirs(self.sim_dir), self.param_seq.config.z_num)
|
utils.check_data_integrity(
|
||||||
|
utils.get_data_dirs(self.sim_dir), self.param_seq.config.z_num
|
||||||
|
)
|
||||||
return True
|
return True
|
||||||
except IncompleteDataFolderError:
|
except IncompleteDataFolderError:
|
||||||
return False
|
return False
|
||||||
@@ -470,7 +472,7 @@ class Simulations:
|
|||||||
def _run_available(self):
|
def _run_available(self):
|
||||||
for variable, params in self.param_seq:
|
for variable, params in self.param_seq:
|
||||||
v_list_str = utils.format_variable_list(variable)
|
v_list_str = utils.format_variable_list(variable)
|
||||||
io.save_parameters(params.prepare_for_dump(), self.sim_dir / v_list_str)
|
utils.save_parameters(params.prepare_for_dump(), self.sim_dir / v_list_str)
|
||||||
|
|
||||||
self.new_sim(v_list_str, params)
|
self.new_sim(v_list_str, params)
|
||||||
self.finish()
|
self.finish()
|
||||||
@@ -582,7 +584,7 @@ class MultiProcSimulations(Simulations, priority=1):
|
|||||||
p_queue: multiprocessing.Queue,
|
p_queue: multiprocessing.Queue,
|
||||||
):
|
):
|
||||||
while True:
|
while True:
|
||||||
raw_data: Tuple[List[tuple], Parameters] = queue.get()
|
raw_data: tuple[list[tuple], Parameters] = queue.get()
|
||||||
if raw_data == 0:
|
if raw_data == 0:
|
||||||
queue.task_done()
|
queue.task_done()
|
||||||
return
|
return
|
||||||
@@ -695,17 +697,17 @@ def run_simulation_sequence(
|
|||||||
sim = new_simulation(config, prev, method)
|
sim = new_simulation(config, prev, method)
|
||||||
sim.run()
|
sim.run()
|
||||||
prev = sim.sim_dir
|
prev = sim.sim_dir
|
||||||
path_trees = io.build_path_trees(sim.sim_dir)
|
path_trees = utils.build_path_trees(sim.sim_dir)
|
||||||
|
|
||||||
final_name = env.get(env.OUTPUT_PATH)
|
final_name = env.get(env.OUTPUT_PATH)
|
||||||
if final_name is None:
|
if final_name is None:
|
||||||
final_name = config.name
|
final_name = config.name
|
||||||
|
|
||||||
io.merge(final_name, path_trees)
|
utils.merge(final_name, path_trees)
|
||||||
|
|
||||||
|
|
||||||
def new_simulation(
|
def new_simulation(
|
||||||
config: utils.BareConfig,
|
config: BareConfig,
|
||||||
prev_sim_dir=None,
|
prev_sim_dir=None,
|
||||||
method: Type[Simulations] = None,
|
method: Type[Simulations] = None,
|
||||||
) -> Simulations:
|
) -> Simulations:
|
||||||
@@ -729,8 +731,8 @@ def new_simulation(
|
|||||||
def resume_simulations(sim_dir: Path, method: Type[Simulations] = None) -> Simulations:
|
def resume_simulations(sim_dir: Path, method: Type[Simulations] = None) -> Simulations:
|
||||||
|
|
||||||
task_id = random.randint(1e9, 1e12)
|
task_id = random.randint(1e9, 1e12)
|
||||||
config = io.load_toml(sim_dir / "initial_config.toml")
|
config = utils.load_toml(sim_dir / "initial_config.toml")
|
||||||
io.set_data_folder(task_id, sim_dir)
|
utils.set_data_folder(task_id, sim_dir)
|
||||||
param_seq = initialize.RecoveryParamSequence(config, task_id)
|
param_seq = initialize.RecoveryParamSequence(config, task_id)
|
||||||
|
|
||||||
return Simulations.new(param_seq, task_id, method)
|
return Simulations.new(param_seq, task_id, method)
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
# For example, nm(X) means "I give the number X in nm, figure out the ang. freq."
|
# For example, nm(X) means "I give the number X in nm, figure out the ang. freq."
|
||||||
# to be used especially when giving plotting ranges : (400, 1400, nm), (-4, 8, ps), ...
|
# to be used especially when giving plotting ranges : (400, 1400, nm), (-4, 8, ps), ...
|
||||||
|
|
||||||
from typing import Callable, TypeVar, Union
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from typing import Callable, TypeVar, Union
|
||||||
|
|
||||||
from ..utils import parameter
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from numpy import pi
|
from numpy import pi
|
||||||
|
|
||||||
@@ -181,17 +180,6 @@ def is_unit(name, value):
|
|||||||
raise TypeError("invalid unit specified")
|
raise TypeError("invalid unit specified")
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class PlotRange:
|
|
||||||
left: float = parameter.Parameter(parameter.type_checker(int, float))
|
|
||||||
right: float = parameter.Parameter(parameter.type_checker(int, float))
|
|
||||||
unit: Callable[[float], float] = parameter.Parameter(is_unit, converter=get_unit)
|
|
||||||
conserved_quantity: bool = parameter.Parameter(parameter.boolean, default=True)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.left:.1f}-{self.right:.1f} {self.unit.__name__}"
|
|
||||||
|
|
||||||
|
|
||||||
def beta2_coef(beta2_coefficients):
|
def beta2_coef(beta2_coefficients):
|
||||||
fac = 1e27
|
fac = 1e27
|
||||||
out = np.zeros_like(beta2_coefficients)
|
out = np.zeros_like(beta2_coefficients)
|
||||||
@@ -231,54 +219,6 @@ def standardize_dictionary(dico):
|
|||||||
return dico
|
return dico
|
||||||
|
|
||||||
|
|
||||||
def sort_axis(axis, plt_range: PlotRange) -> tuple[np.ndarray, np.ndarray, tuple[float, float]]:
|
|
||||||
"""
|
|
||||||
given an axis, returns this axis cropped according to the given range, converted and sorted
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
axis : 1D array containing the original axis (usual the w or t array)
|
|
||||||
plt_range : tupple (min, max, conversion_function) used to crop the axis
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
cropped : the axis cropped, converted and sorted
|
|
||||||
indices : indices to use to slice and sort other array in the same fashion
|
|
||||||
extent : tupple with min and max of cropped
|
|
||||||
|
|
||||||
Example
|
|
||||||
-------
|
|
||||||
w = np.append(np.linspace(0, -10, 20), np.linspace(0, 10, 20))
|
|
||||||
t = np.linspace(-10, 10, 400)
|
|
||||||
W, T = np.meshgrid(w, t)
|
|
||||||
y = np.exp(-W**2 - T**2)
|
|
||||||
|
|
||||||
# Define ranges
|
|
||||||
rw = (-4, 4, s)
|
|
||||||
rt = (-2, 6, s)
|
|
||||||
|
|
||||||
w, cw = sort_axis(w, rw)
|
|
||||||
t, ct = sort_axis(t, rt)
|
|
||||||
|
|
||||||
# slice y according to the given ranges
|
|
||||||
y = y[ct][:, cw]
|
|
||||||
"""
|
|
||||||
if isinstance(plt_range, tuple):
|
|
||||||
plt_range = PlotRange(*plt_range)
|
|
||||||
r = np.array((plt_range.left, plt_range.right), dtype="float")
|
|
||||||
|
|
||||||
indices = np.arange(len(axis))[
|
|
||||||
(axis <= np.max(plt_range.unit(r))) & (axis >= np.min(plt_range.unit(r)))
|
|
||||||
]
|
|
||||||
cropped = axis[indices]
|
|
||||||
order = np.argsort(plt_range.unit.inv(cropped))
|
|
||||||
indices = indices[order]
|
|
||||||
cropped = cropped[order]
|
|
||||||
out_ax = plt_range.unit.inv(cropped)
|
|
||||||
|
|
||||||
return out_ax, indices, (out_ax[0], out_ax[-1])
|
|
||||||
|
|
||||||
|
|
||||||
def to_WL(spectrum: np.ndarray, lambda_: np.ndarray) -> np.ndarray:
|
def to_WL(spectrum: np.ndarray, lambda_: np.ndarray) -> np.ndarray:
|
||||||
"""rescales the spectrum because of uneven binning when going from freq to wl
|
"""rescales the spectrum because of uneven binning when going from freq to wl
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,22 @@
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import re
|
from typing import Any, Callable, Literal, Optional, Union
|
||||||
from typing import Any, Callable, Dict, Literal, Optional, Tuple, Union
|
|
||||||
from PIL.Image import new
|
|
||||||
|
|
||||||
import matplotlib.gridspec as gs
|
import matplotlib.gridspec as gs
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from matplotlib.colors import ListedColormap
|
from matplotlib.colors import ListedColormap
|
||||||
from numpy.core.fromnumeric import mean
|
|
||||||
from scipy.interpolate import UnivariateSpline
|
from scipy.interpolate import UnivariateSpline
|
||||||
from scipy.interpolate.interpolate import interp1d
|
from scipy.interpolate.interpolate import interp1d
|
||||||
from tqdm import utils
|
|
||||||
|
|
||||||
from scgenerator.const import PARAM_SEPARATOR
|
from . import math
|
||||||
|
from .const import PARAM_SEPARATOR
|
||||||
from .logger import get_logger
|
|
||||||
|
|
||||||
from . import io, math
|
|
||||||
from .defaults import default_plotting as defaults
|
from .defaults import default_plotting as defaults
|
||||||
from .math import abs2, make_uniform_1D, span
|
from .math import abs2, span
|
||||||
from .physics import pulse, units
|
from .physics import pulse, units
|
||||||
from .utils.parameter import BareConfig, Parameters
|
from .utils.parameter import Parameters, PlotRange, sort_axis
|
||||||
|
|
||||||
RangeType = Tuple[float, float, Union[str, Callable]]
|
RangeType = tuple[float, float, Union[str, Callable]]
|
||||||
NO_LIM = object()
|
NO_LIM = object()
|
||||||
|
|
||||||
|
|
||||||
@@ -52,9 +45,9 @@ def get_extent(x, y, facx=1, facy=1):
|
|||||||
def plot_setup(
|
def plot_setup(
|
||||||
out_path: Path,
|
out_path: Path,
|
||||||
file_type: str = "png",
|
file_type: str = "png",
|
||||||
figsize: Tuple[float, float] = defaults["figsize"],
|
figsize: tuple[float, float] = defaults["figsize"],
|
||||||
mode: Literal["default", "coherence", "coherence_T"] = "default",
|
mode: Literal["default", "coherence", "coherence_T"] = "default",
|
||||||
) -> Tuple[Path, plt.Figure, Union[plt.Axes, Tuple[plt.Axes]]]:
|
) -> tuple[Path, plt.Figure, Union[plt.Axes, tuple[plt.Axes]]]:
|
||||||
out_path = defaults["name"] if out_path is None else out_path
|
out_path = defaults["name"] if out_path is None else out_path
|
||||||
out_path = Path(out_path)
|
out_path = Path(out_path)
|
||||||
plot_name = out_path.name.replace(f".{file_type}", "")
|
plot_name = out_path.name.replace(f".{file_type}", "")
|
||||||
@@ -181,7 +174,7 @@ def create_zoom_axis(
|
|||||||
ymin, ymax = 0, 0
|
ymin, ymax = 0, 0
|
||||||
for line in lines:
|
for line in lines:
|
||||||
xdata = line.get_xdata()
|
xdata = line.get_xdata()
|
||||||
xdata, ind, _ = units.sort_axis(xdata, (*xlim, units.s))
|
xdata, ind, _ = sort_axis(xdata, (*xlim, units.s))
|
||||||
ydata = line.get_ydata()[ind]
|
ydata = line.get_ydata()[ind]
|
||||||
inset.plot(
|
inset.plot(
|
||||||
xdata, ydata, c=line.get_color(), ls=line.get_linestyle(), lw=line.get_linewidth()
|
xdata, ydata, c=line.get_color(), ls=line.get_linestyle(), lw=line.get_linewidth()
|
||||||
@@ -262,7 +255,7 @@ def corner_annotation(text, ax, position="tl", rel_x_offset=0.05, rel_y_offset=0
|
|||||||
|
|
||||||
def propagation_plot(
|
def propagation_plot(
|
||||||
values: np.ndarray,
|
values: np.ndarray,
|
||||||
plt_range: Union[units.PlotRange, RangeType],
|
plt_range: Union[PlotRange, RangeType],
|
||||||
params: Parameters,
|
params: Parameters,
|
||||||
ax: plt.Axes,
|
ax: plt.Axes,
|
||||||
log: Union[int, float, bool, str] = "1D",
|
log: Union[int, float, bool, str] = "1D",
|
||||||
@@ -279,7 +272,7 @@ def propagation_plot(
|
|||||||
----------
|
----------
|
||||||
values : np.ndarray
|
values : np.ndarray
|
||||||
raw values, either complex fields or complex spectra
|
raw values, either complex fields or complex spectra
|
||||||
plt_range : Union[units.PlotRange, RangeType]
|
plt_range : Union[PlotRange, RangeType]
|
||||||
time, wavelength or frequency range
|
time, wavelength or frequency range
|
||||||
params : Parameters
|
params : Parameters
|
||||||
parameters of the simulation
|
parameters of the simulation
|
||||||
@@ -417,7 +410,7 @@ def plot_2D(
|
|||||||
|
|
||||||
def transform_2D_propagation(
|
def transform_2D_propagation(
|
||||||
values: np.ndarray,
|
values: np.ndarray,
|
||||||
plt_range: Union[units.PlotRange, RangeType],
|
plt_range: Union[PlotRange, RangeType],
|
||||||
params: Parameters,
|
params: Parameters,
|
||||||
log: Union[int, float, bool, str] = "1D",
|
log: Union[int, float, bool, str] = "1D",
|
||||||
skip: int = 1,
|
skip: int = 1,
|
||||||
@@ -428,7 +421,7 @@ def transform_2D_propagation(
|
|||||||
----------
|
----------
|
||||||
values : np.ndarray, shape (n, nt)
|
values : np.ndarray, shape (n, nt)
|
||||||
values to transform
|
values to transform
|
||||||
plt_range : Union[units.PlotRange, RangeType]
|
plt_range : Union[PlotRange, RangeType]
|
||||||
range
|
range
|
||||||
params : Parameters
|
params : Parameters
|
||||||
parameters of the simulation
|
parameters of the simulation
|
||||||
@@ -468,7 +461,7 @@ def transform_2D_propagation(
|
|||||||
|
|
||||||
def mean_values_plot(
|
def mean_values_plot(
|
||||||
values: np.ndarray,
|
values: np.ndarray,
|
||||||
plt_range: Union[units.PlotRange, RangeType],
|
plt_range: Union[PlotRange, RangeType],
|
||||||
params: Parameters,
|
params: Parameters,
|
||||||
ax: plt.Axes,
|
ax: plt.Axes,
|
||||||
log: Union[float, int, str, bool] = False,
|
log: Union[float, int, str, bool] = False,
|
||||||
@@ -478,7 +471,7 @@ def mean_values_plot(
|
|||||||
spacing: Union[float, int] = 1,
|
spacing: Union[float, int] = 1,
|
||||||
renormalize: bool = True,
|
renormalize: bool = True,
|
||||||
y_label: str = None,
|
y_label: str = None,
|
||||||
line_labels: Tuple[str, str] = None,
|
line_labels: tuple[str, str] = None,
|
||||||
mean_style: dict[str, Any] = None,
|
mean_style: dict[str, Any] = None,
|
||||||
individual_style: dict[str, Any] = None,
|
individual_style: dict[str, Any] = None,
|
||||||
) -> tuple[plt.Line2D, list[plt.Line2D]]:
|
) -> tuple[plt.Line2D, list[plt.Line2D]]:
|
||||||
@@ -510,7 +503,7 @@ def mean_values_plot(
|
|||||||
|
|
||||||
def transform_mean_values(
|
def transform_mean_values(
|
||||||
values: np.ndarray,
|
values: np.ndarray,
|
||||||
plt_range: Union[units.PlotRange, RangeType],
|
plt_range: Union[PlotRange, RangeType],
|
||||||
params: Parameters,
|
params: Parameters,
|
||||||
log: Union[bool, int, float] = False,
|
log: Union[bool, int, float] = False,
|
||||||
spacing: Union[int, float] = 1,
|
spacing: Union[int, float] = 1,
|
||||||
@@ -521,7 +514,7 @@ def transform_mean_values(
|
|||||||
----------
|
----------
|
||||||
values : np.ndarray, shape (m, n)
|
values : np.ndarray, shape (m, n)
|
||||||
values to transform
|
values to transform
|
||||||
plt_range : Union[units.PlotRange, RangeType]
|
plt_range : Union[PlotRange, RangeType]
|
||||||
x axis specifications
|
x axis specifications
|
||||||
params : Parameters
|
params : Parameters
|
||||||
parameters of the simulation
|
parameters of the simulation
|
||||||
@@ -545,7 +538,7 @@ def transform_mean_values(
|
|||||||
is_complex, x_axis, plt_range = prep_plot_axis(values, plt_range, params)
|
is_complex, x_axis, plt_range = prep_plot_axis(values, plt_range, params)
|
||||||
if is_complex:
|
if is_complex:
|
||||||
values = abs2(values)
|
values = abs2(values)
|
||||||
new_axis, ind, ext = units.sort_axis(x_axis, plt_range)
|
new_axis, ind, ext = sort_axis(x_axis, plt_range)
|
||||||
values = values[:, ind]
|
values = values[:, ind]
|
||||||
if plt_range.unit.type == "WL":
|
if plt_range.unit.type == "WL":
|
||||||
values = np.apply_along_axis(units.to_WL, -1, values, new_axis)
|
values = np.apply_along_axis(units.to_WL, -1, values, new_axis)
|
||||||
@@ -636,7 +629,7 @@ def plot_mean(
|
|||||||
|
|
||||||
def single_position_plot(
|
def single_position_plot(
|
||||||
values: np.ndarray,
|
values: np.ndarray,
|
||||||
plt_range: Union[units.PlotRange, RangeType],
|
plt_range: Union[PlotRange, RangeType],
|
||||||
params: Parameters,
|
params: Parameters,
|
||||||
ax: plt.Axes,
|
ax: plt.Axes,
|
||||||
log: Union[str, int, float, bool] = False,
|
log: Union[str, int, float, bool] = False,
|
||||||
@@ -711,7 +704,7 @@ def plot_1D(
|
|||||||
|
|
||||||
def transform_1D_values(
|
def transform_1D_values(
|
||||||
values: np.ndarray,
|
values: np.ndarray,
|
||||||
plt_range: Union[units.PlotRange, RangeType],
|
plt_range: Union[PlotRange, RangeType],
|
||||||
params: Parameters,
|
params: Parameters,
|
||||||
log: Union[int, float, bool] = False,
|
log: Union[int, float, bool] = False,
|
||||||
spacing: Union[int, float] = 1,
|
spacing: Union[int, float] = 1,
|
||||||
@@ -722,7 +715,7 @@ def transform_1D_values(
|
|||||||
----------
|
----------
|
||||||
values : np.ndarray, shape (n,)
|
values : np.ndarray, shape (n,)
|
||||||
values to plot, may be complex
|
values to plot, may be complex
|
||||||
plt_range : Union[units.PlotRange, RangeType]
|
plt_range : Union[PlotRange, RangeType]
|
||||||
plot range specification, either (min, max, unit) or a PlotRange obj
|
plot range specification, either (min, max, unit) or a PlotRange obj
|
||||||
params : Parameters
|
params : Parameters
|
||||||
parameters of the simulations
|
parameters of the simulations
|
||||||
@@ -744,7 +737,7 @@ def transform_1D_values(
|
|||||||
is_complex, x_axis, plt_range = prep_plot_axis(values, plt_range, params)
|
is_complex, x_axis, plt_range = prep_plot_axis(values, plt_range, params)
|
||||||
if is_complex:
|
if is_complex:
|
||||||
values = abs2(values)
|
values = abs2(values)
|
||||||
new_axis, ind, ext = units.sort_axis(x_axis, plt_range)
|
new_axis, ind, ext = sort_axis(x_axis, plt_range)
|
||||||
values = values[ind]
|
values = values[ind]
|
||||||
if plt_range.unit.type == "WL":
|
if plt_range.unit.type == "WL":
|
||||||
values = units.to_WL(values, new_axis)
|
values = units.to_WL(values, new_axis)
|
||||||
@@ -814,8 +807,8 @@ def plot_spectrogram(
|
|||||||
if values.ndim != 1:
|
if values.ndim != 1:
|
||||||
print("plot_spectrogram can only plot 1D arrays")
|
print("plot_spectrogram can only plot 1D arrays")
|
||||||
return
|
return
|
||||||
x_range: units.PlotRange
|
x_range: PlotRange
|
||||||
y_range: units.PlotRange
|
y_range: PlotRange
|
||||||
_, x_axis, x_range = prep_plot_axis(values, x_range, params)
|
_, x_axis, x_range = prep_plot_axis(values, x_range, params)
|
||||||
_, y_axis, y_range = prep_plot_axis(values, y_range, params)
|
_, y_axis, y_range = prep_plot_axis(values, y_range, params)
|
||||||
|
|
||||||
@@ -862,7 +855,7 @@ def plot_spectrogram(
|
|||||||
|
|
||||||
|
|
||||||
def uniform_axis(
|
def uniform_axis(
|
||||||
axis: np.ndarray, values: np.ndarray, new_axis_spec: Union[units.PlotRange, RangeType, str]
|
axis: np.ndarray, values: np.ndarray, new_axis_spec: Union[PlotRange, RangeType, str]
|
||||||
) -> tuple[np.ndarray, np.ndarray]:
|
) -> tuple[np.ndarray, np.ndarray]:
|
||||||
"""given some values(axis), creates a new uniformly spaced axis and interpolates
|
"""given some values(axis), creates a new uniformly spaced axis and interpolates
|
||||||
the values over it.
|
the values over it.
|
||||||
@@ -891,14 +884,14 @@ def uniform_axis(
|
|||||||
new_axis_spec = "unity"
|
new_axis_spec = "unity"
|
||||||
if isinstance(new_axis_spec, str) or callable(new_axis_spec):
|
if isinstance(new_axis_spec, str) or callable(new_axis_spec):
|
||||||
unit = units.get_unit(new_axis_spec)
|
unit = units.get_unit(new_axis_spec)
|
||||||
plt_range = units.PlotRange(unit.inv(axis.min()), unit.inv(axis.max()), new_axis_spec)
|
plt_range = PlotRange(unit.inv(axis.min()), unit.inv(axis.max()), new_axis_spec)
|
||||||
elif isinstance(new_axis_spec, tuple):
|
elif isinstance(new_axis_spec, tuple):
|
||||||
plt_range = units.PlotRange(*new_axis_spec)
|
plt_range = PlotRange(*new_axis_spec)
|
||||||
elif isinstance(new_axis_spec, units.PlotRange):
|
elif isinstance(new_axis_spec, PlotRange):
|
||||||
plt_range = new_axis_spec
|
plt_range = new_axis_spec
|
||||||
else:
|
else:
|
||||||
raise TypeError(f"Don't know how to interpret {new_axis_spec}")
|
raise TypeError(f"Don't know how to interpret {new_axis_spec}")
|
||||||
tmp_axis, ind, ext = units.sort_axis(axis, plt_range)
|
tmp_axis, ind, ext = sort_axis(axis, plt_range)
|
||||||
values = np.atleast_2d(values)
|
values = np.atleast_2d(values)
|
||||||
if np.allclose((diff := np.diff(tmp_axis))[0], diff):
|
if np.allclose((diff := np.diff(tmp_axis))[0], diff):
|
||||||
new_axis = tmp_axis
|
new_axis = tmp_axis
|
||||||
@@ -954,11 +947,11 @@ def apply_log(values: np.ndarray, log: Union[str, bool, float, int]) -> np.ndarr
|
|||||||
|
|
||||||
|
|
||||||
def prep_plot_axis(
|
def prep_plot_axis(
|
||||||
values: np.ndarray, plt_range: Union[units.PlotRange, RangeType], params: Parameters
|
values: np.ndarray, plt_range: Union[PlotRange, RangeType], params: Parameters
|
||||||
) -> tuple[bool, np.ndarray, units.PlotRange]:
|
) -> tuple[bool, np.ndarray, PlotRange]:
|
||||||
is_spectrum = values.dtype == "complex"
|
is_spectrum = values.dtype == "complex"
|
||||||
if not isinstance(plt_range, units.PlotRange):
|
if not isinstance(plt_range, PlotRange):
|
||||||
plt_range = units.PlotRange(*plt_range)
|
plt_range = PlotRange(*plt_range)
|
||||||
if plt_range.unit.type in ["WL", "FREQ", "AFREQ"]:
|
if plt_range.unit.type in ["WL", "FREQ", "AFREQ"]:
|
||||||
x_axis = params.w.copy()
|
x_axis = params.w.copy()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
from itertools import cycle
|
|
||||||
import itertools
|
import itertools
|
||||||
|
from itertools import cycle
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Iterable, Optional
|
from typing import Any, Iterable, Optional
|
||||||
from cycler import cycler
|
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from cycler import cycler
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
from ..utils.parameter import Parameters
|
|
||||||
from ..const import PARAM_SEPARATOR
|
|
||||||
|
|
||||||
from ..initialize import ParamSequence
|
|
||||||
from ..physics import units, fiber
|
|
||||||
from ..spectra import Pulse
|
|
||||||
from ..utils import pretty_format_value, pretty_format_from_sim_name, auto_crop
|
|
||||||
from ..plotting import plot_setup
|
|
||||||
from .. import env, math
|
from .. import env, math
|
||||||
|
from ..const import PARAM_SEPARATOR
|
||||||
|
from ..initialize import ParamSequence
|
||||||
|
from ..physics import fiber, units
|
||||||
|
from ..plotting import plot_setup
|
||||||
|
from ..spectra import Pulse
|
||||||
|
from ..utils import auto_crop
|
||||||
|
from ..utils.parameter import Parameters, pretty_format_from_sim_name, pretty_format_value
|
||||||
|
|
||||||
|
|
||||||
def fingerprint(params: Parameters):
|
def fingerprint(params: Parameters):
|
||||||
@@ -91,7 +90,7 @@ def plot_dispersion(config_path: Path, lim: tuple[float, float] = None):
|
|||||||
loss_ax = None
|
loss_ax = None
|
||||||
plt.sca(left)
|
plt.sca(left)
|
||||||
for style, lbl, params in plot_helper(config_path):
|
for style, lbl, params in plot_helper(config_path):
|
||||||
if params.alpha is not None and loss_ax is None:
|
if params.alpha_arr is not None and loss_ax is None:
|
||||||
loss_ax = right.twinx()
|
loss_ax = right.twinx()
|
||||||
if (bbb := tuple(params.beta2_coefficients)) not in already_plotted:
|
if (bbb := tuple(params.beta2_coefficients)) not in already_plotted:
|
||||||
already_plotted.add(bbb)
|
already_plotted.add(bbb)
|
||||||
@@ -116,7 +115,7 @@ def plot_init(
|
|||||||
all_labels = []
|
all_labels = []
|
||||||
already_plotted = set()
|
already_plotted = set()
|
||||||
for style, lbl, params in plot_helper(config_path):
|
for style, lbl, params in plot_helper(config_path):
|
||||||
if params.alpha is not None and loss_ax is None:
|
if params.alpha_arr is not None and loss_ax is None:
|
||||||
loss_ax = tr.twinx()
|
loss_ax = tr.twinx()
|
||||||
if (fp := fingerprint(params)) not in already_plotted:
|
if (fp := fingerprint(params)) not in already_plotted:
|
||||||
already_plotted.add(fp)
|
already_plotted.add(fp)
|
||||||
@@ -214,8 +213,8 @@ def plot_1_dispersion(
|
|||||||
left.set_xlabel(units.nm.label)
|
left.set_xlabel(units.nm.label)
|
||||||
right.set_xlabel("wavelength (nm)")
|
right.set_xlabel("wavelength (nm)")
|
||||||
|
|
||||||
if params.alpha is not None and loss is not None:
|
if params.alpha_arr is not None and loss is not None:
|
||||||
loss.plot(1e9 * wl[m], params.alpha[m], c="r", ls="--")
|
loss.plot(1e9 * wl[m], params.alpha_arr[m], c="r", ls="--")
|
||||||
loss.set_ylabel("loss (1/m)", color="r")
|
loss.set_ylabel("loss (1/m)", color="r")
|
||||||
loss.set_yscale("log")
|
loss.set_yscale("log")
|
||||||
loss.tick_params(axis="y", labelcolor="r")
|
loss.tick_params(axis="y", labelcolor="r")
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from typing import Tuple
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from ..initialize import validate_config_sequence
|
from ..initialize import validate_config_sequence
|
||||||
from ..io import Paths
|
from ..utils import Paths
|
||||||
from ..utils.parameter import BareConfig
|
from ..utils.parameter import BareConfig
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ from typing import Callable, Dict, Iterable, Union
|
|||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from . import initialize, io, math
|
from . import initialize, math
|
||||||
from .const import SPECN_FN
|
from .const import SPECN_FN
|
||||||
from .logger import get_logger
|
from .logger import get_logger
|
||||||
from .physics import pulse, units
|
from .physics import pulse, units
|
||||||
from .plotting import mean_values_plot, propagation_plot, single_position_plot
|
from .plotting import mean_values_plot, propagation_plot, single_position_plot
|
||||||
from .utils.parameter import Parameters
|
from .utils.parameter import Parameters, PlotRange
|
||||||
|
|
||||||
|
|
||||||
class Spectrum(np.ndarray):
|
class Spectrum(np.ndarray):
|
||||||
@@ -347,7 +347,7 @@ class Pulse(Sequence):
|
|||||||
return mean_values_plot(vals, plt_range, self.params, ax, **kwargs)
|
return mean_values_plot(vals, plt_range, self.params, ax, **kwargs)
|
||||||
|
|
||||||
def retrieve_plot_values(self, left, right, unit, z_pos, sim_ind):
|
def retrieve_plot_values(self, left, right, unit, z_pos, sim_ind):
|
||||||
plt_range = units.PlotRange(left, right, unit)
|
plt_range = PlotRange(left, right, unit)
|
||||||
if plt_range.unit.type == "TIME":
|
if plt_range.unit.type == "TIME":
|
||||||
vals = self.all_fields(ind=z_pos)
|
vals = self.all_fields(ind=z_pos)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -4,32 +4,428 @@ scgenerator module but some function may be used in any python program
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
|
import shutil
|
||||||
import threading
|
import threading
|
||||||
from collections import abc
|
from collections import abc
|
||||||
from copy import deepcopy
|
|
||||||
from dataclasses import asdict, replace
|
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Iterable, Iterator, TypeVar, Union
|
from typing import Any, Callable, Generator, Iterable, Sequence, TypeVar, Union
|
||||||
from ..errors import IncompleteDataFolderError
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from numpy.lib.arraysetops import isin
|
import pkg_resources as pkg
|
||||||
|
import toml
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
from .. import env
|
from ..const import PARAM_FN, PARAM_SEPARATOR, SPEC1_FN, SPECN_FN, Z_FN, __version__
|
||||||
from ..const import PARAM_SEPARATOR, SPEC1_FN
|
from ..env import TMP_FOLDER_KEY_BASE, data_folder, pbar_policy
|
||||||
from ..math import *
|
from ..errors import IncompleteDataFolderError
|
||||||
from .. import io
|
from ..logger import get_logger
|
||||||
from .parameter import BareConfig, Parameters
|
|
||||||
|
|
||||||
T_ = TypeVar("T_")
|
T_ = TypeVar("T_")
|
||||||
|
|
||||||
|
PathTree = list[tuple[Path, ...]]
|
||||||
|
|
||||||
|
|
||||||
|
class Paths:
|
||||||
|
_data_files = [
|
||||||
|
"silica.toml",
|
||||||
|
"gas.toml",
|
||||||
|
"hr_t.npz",
|
||||||
|
"submit_job_template.txt",
|
||||||
|
"start_worker.sh",
|
||||||
|
"start_head.sh",
|
||||||
|
]
|
||||||
|
|
||||||
|
paths = {
|
||||||
|
f.split(".")[0]: os.path.abspath(
|
||||||
|
pkg.resource_filename("scgenerator", os.path.join("data", f))
|
||||||
|
)
|
||||||
|
for f in _data_files
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get(cls, key):
|
||||||
|
if key not in cls.paths:
|
||||||
|
if os.path.exists("paths.toml"):
|
||||||
|
with open("paths.toml") as file:
|
||||||
|
paths_dico = toml.load(file)
|
||||||
|
for k, v in paths_dico.items():
|
||||||
|
cls.paths[k] = v
|
||||||
|
if key not in cls.paths:
|
||||||
|
get_logger(__name__).info(
|
||||||
|
f"{key} was not found in path index, returning current working directory."
|
||||||
|
)
|
||||||
|
cls.paths[key] = os.getcwd()
|
||||||
|
|
||||||
|
return cls.paths[key]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def gets(cls, key):
|
||||||
|
"""returned the specified file as a string"""
|
||||||
|
with open(cls.get(key)) as file:
|
||||||
|
return file.read()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def plot(cls, name):
|
||||||
|
"""returns the paths to the specified plot. Used to save new plot
|
||||||
|
example
|
||||||
|
---------
|
||||||
|
fig.savefig(Paths.plot("figure5.pdf"))
|
||||||
|
"""
|
||||||
|
return os.path.join(cls.get("plots"), name)
|
||||||
|
|
||||||
|
|
||||||
|
def load_previous_spectrum(prev_data_dir: str) -> np.ndarray:
|
||||||
|
num = find_last_spectrum_num(prev_data_dir)
|
||||||
|
return np.load(prev_data_dir / SPEC1_FN.format(num))
|
||||||
|
|
||||||
|
|
||||||
|
def conform_toml_path(path: os.PathLike) -> Path:
|
||||||
|
path = Path(path)
|
||||||
|
if not path.name.lower().endswith(".toml"):
|
||||||
|
path = path.parent / (path.name + ".toml")
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def load_toml(path: os.PathLike):
|
||||||
|
"""returns a dictionary parsed from the specified toml file"""
|
||||||
|
path = conform_toml_path(path)
|
||||||
|
with open(path, mode="r") as file:
|
||||||
|
dico = toml.load(file)
|
||||||
|
dico.setdefault("variable", {})
|
||||||
|
for key in {"simulation", "fiber", "gas", "pulse"} & dico.keys():
|
||||||
|
section = dico.pop(key, {})
|
||||||
|
dico["variable"].update(section.pop("variable", {}))
|
||||||
|
dico.update(section)
|
||||||
|
if len(dico["variable"]) == 0:
|
||||||
|
dico.pop("variable")
|
||||||
|
return dico
|
||||||
|
|
||||||
|
|
||||||
|
def save_toml(path: os.PathLike, dico):
|
||||||
|
"""saves a dictionary into a toml file"""
|
||||||
|
path = conform_toml_path(path)
|
||||||
|
with open(path, mode="w") as file:
|
||||||
|
toml.dump(dico, file)
|
||||||
|
return dico
|
||||||
|
|
||||||
|
|
||||||
|
def save_parameters(
|
||||||
|
params: dict[str, Any], destination_dir: Path, file_name: str = "params.toml"
|
||||||
|
) -> Path:
|
||||||
|
"""saves a parameter dictionary. Note that is does remove some entries, particularly
|
||||||
|
those that take a lot of space ("t", "w", ...)
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
params : dict[str, Any]
|
||||||
|
dictionary to save
|
||||||
|
destination_dir : Path
|
||||||
|
destination directory
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Path
|
||||||
|
path to newly created the paramter file
|
||||||
|
"""
|
||||||
|
file_path = destination_dir / file_name
|
||||||
|
|
||||||
|
file_path.parent.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
# save toml of the simulation
|
||||||
|
with open(file_path, "w") as file:
|
||||||
|
toml.dump(params, file, encoder=toml.TomlNumpyEncoder())
|
||||||
|
|
||||||
|
return file_path
|
||||||
|
|
||||||
|
|
||||||
|
def load_material_dico(name: str) -> dict[str, Any]:
|
||||||
|
"""loads a material dictionary
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
name : str
|
||||||
|
name of the material
|
||||||
|
Returns
|
||||||
|
----------
|
||||||
|
material_dico : dict
|
||||||
|
"""
|
||||||
|
if name == "silica":
|
||||||
|
return toml.loads(Paths.gets("silica"))
|
||||||
|
else:
|
||||||
|
return toml.loads(Paths.gets("gas"))[name]
|
||||||
|
|
||||||
|
|
||||||
|
def get_data_dirs(sim_dir: Path) -> list[Path]:
|
||||||
|
"""returns a list of absolute paths corresponding to a particular run
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
sim_dir : Path
|
||||||
|
path to directory containing the initial config file and the spectra sub folders
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list[Path]
|
||||||
|
paths to sub folders
|
||||||
|
"""
|
||||||
|
|
||||||
|
return [p.resolve() for p in sim_dir.glob("*") if p.is_dir()]
|
||||||
|
|
||||||
|
|
||||||
|
def update_appended_params(source: Path, destination: Path, z: Sequence):
|
||||||
|
z_num = len(z)
|
||||||
|
params = load_toml(source)
|
||||||
|
if "simulation" in params:
|
||||||
|
params["simulation"]["z_num"] = z_num
|
||||||
|
params["fiber"]["length"] = float(z[-1] - z[0])
|
||||||
|
else:
|
||||||
|
params["z_num"] = z_num
|
||||||
|
params["length"] = float(z[-1] - z[0])
|
||||||
|
save_toml(destination, params)
|
||||||
|
|
||||||
|
|
||||||
|
def build_path_trees(sim_dir: Path) -> list[PathTree]:
|
||||||
|
sim_dir = sim_dir.resolve()
|
||||||
|
path_branches: list[tuple[Path, ...]] = []
|
||||||
|
to_check = list(sim_dir.glob("id*num*"))
|
||||||
|
with PBars(len(to_check), desc="Building path trees") as pbar:
|
||||||
|
for branch in map(build_path_branch, to_check):
|
||||||
|
if branch is not None:
|
||||||
|
path_branches.append(branch)
|
||||||
|
pbar.update()
|
||||||
|
path_trees = group_path_branches(path_branches)
|
||||||
|
return path_trees
|
||||||
|
|
||||||
|
|
||||||
|
def build_path_branch(data_dir: Path) -> tuple[Path, ...]:
|
||||||
|
if not data_dir.is_dir():
|
||||||
|
return None
|
||||||
|
path_branch = [data_dir]
|
||||||
|
while (prev_sim_path := load_toml(path_branch[-1] / PARAM_FN).get("prev_data_dir")) is not None:
|
||||||
|
p = Path(prev_sim_path).resolve()
|
||||||
|
if not p.exists():
|
||||||
|
p = Path(*p.parts[-2:]).resolve()
|
||||||
|
path_branch.append(p)
|
||||||
|
return tuple(reversed(path_branch))
|
||||||
|
|
||||||
|
|
||||||
|
def group_path_branches(path_branches: list[tuple[Path, ...]]) -> list[PathTree]:
|
||||||
|
"""groups path lists
|
||||||
|
|
||||||
|
[
|
||||||
|
("a/id 0 wavelength 100 num 0"," b/id 0 wavelength 100 num 0"),
|
||||||
|
("a/id 2 wavelength 100 num 1"," b/id 2 wavelength 100 num 1"),
|
||||||
|
("a/id 1 wavelength 200 num 0"," b/id 1 wavelength 200 num 0"),
|
||||||
|
("a/id 3 wavelength 200 num 1"," b/id 3 wavelength 200 num 1")
|
||||||
|
]
|
||||||
|
->
|
||||||
|
[
|
||||||
|
(
|
||||||
|
("a/id 0 wavelength 100 num 0", "a/id 2 wavelength 100 num 1"),
|
||||||
|
("b/id 0 wavelength 100 num 0", "b/id 2 wavelength 100 num 1"),
|
||||||
|
)
|
||||||
|
(
|
||||||
|
("a/id 1 wavelength 200 num 0", "a/id 3 wavelength 200 num 1"),
|
||||||
|
("b/id 1 wavelength 200 num 0", "b/id 3 wavelength 200 num 1"),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
path_branches : list[tuple[Path, ...]]
|
||||||
|
each element of the list is a path to a folder containing data of one simulation
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list[PathTree]
|
||||||
|
list of PathTrees to be used in merge
|
||||||
|
"""
|
||||||
|
sort_key = lambda el: el[0]
|
||||||
|
|
||||||
|
size = len(path_branches[0])
|
||||||
|
out_trees_map: dict[str, dict[int, dict[int, Path]]] = {}
|
||||||
|
for branch in path_branches:
|
||||||
|
b_id = branch_id(branch)
|
||||||
|
out_trees_map.setdefault(b_id, {i: {} for i in range(size)})
|
||||||
|
for sim_part, data_dir in enumerate(branch):
|
||||||
|
*_, num = data_dir.name.split()
|
||||||
|
out_trees_map[b_id][sim_part][int(num)] = data_dir
|
||||||
|
|
||||||
|
return [
|
||||||
|
tuple(
|
||||||
|
tuple(w for _, w in sorted(v.items(), key=sort_key))
|
||||||
|
for __, v in sorted(d.items(), key=sort_key)
|
||||||
|
)
|
||||||
|
for d in out_trees_map.values()
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def merge_path_tree(
|
||||||
|
path_tree: PathTree, destination: Path, z_callback: Callable[[int], None] = None
|
||||||
|
):
|
||||||
|
"""given a path tree, copies the file into the right location
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
path_tree : PathTree
|
||||||
|
elements of the list returned by group_path_branches
|
||||||
|
destination : Path
|
||||||
|
dir where to save the data
|
||||||
|
"""
|
||||||
|
z_arr: list[float] = []
|
||||||
|
|
||||||
|
destination.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
for i, (z, merged_spectra) in enumerate(merge_spectra(path_tree)):
|
||||||
|
z_arr.append(z)
|
||||||
|
spec_out_name = SPECN_FN.format(i)
|
||||||
|
np.save(destination / spec_out_name, merged_spectra)
|
||||||
|
if z_callback is not None:
|
||||||
|
z_callback(i)
|
||||||
|
d = np.diff(z_arr)
|
||||||
|
d[d < 0] = 0
|
||||||
|
z_arr = np.concatenate(([z_arr[0]], np.cumsum(d)))
|
||||||
|
np.save(destination / Z_FN, z_arr)
|
||||||
|
update_appended_params(path_tree[-1][0] / PARAM_FN, destination / PARAM_FN, z_arr)
|
||||||
|
|
||||||
|
|
||||||
|
def merge_spectra(
|
||||||
|
path_tree: PathTree,
|
||||||
|
) -> Generator[tuple[float, np.ndarray], None, None]:
|
||||||
|
for same_sim_paths in path_tree:
|
||||||
|
z_arr = np.load(same_sim_paths[0] / Z_FN)
|
||||||
|
for i, z in enumerate(z_arr):
|
||||||
|
spectra: list[np.ndarray] = []
|
||||||
|
for data_dir in same_sim_paths:
|
||||||
|
spec = np.load(data_dir / SPEC1_FN.format(i))
|
||||||
|
spectra.append(spec)
|
||||||
|
yield z, np.atleast_2d(spectra)
|
||||||
|
|
||||||
|
|
||||||
|
def merge(destination: os.PathLike, path_trees: list[PathTree] = None):
|
||||||
|
|
||||||
|
destination = ensure_folder(Path(destination))
|
||||||
|
|
||||||
|
z_num = 0
|
||||||
|
prev_z_num = 0
|
||||||
|
|
||||||
|
for i, sim_dir in enumerate(sim_dirs(path_trees)):
|
||||||
|
conf = sim_dir / "initial_config.toml"
|
||||||
|
shutil.copy(
|
||||||
|
conf,
|
||||||
|
destination / f"initial_config_{i}.toml",
|
||||||
|
)
|
||||||
|
prev_z_num = load_toml(conf).get("z_num", prev_z_num)
|
||||||
|
z_num += prev_z_num
|
||||||
|
|
||||||
|
pbars = PBars(
|
||||||
|
len(path_trees) * z_num, "Merging", 1, worker_kwargs=dict(total=z_num, desc="current pos")
|
||||||
|
)
|
||||||
|
for path_tree in path_trees:
|
||||||
|
pbars.reset(1)
|
||||||
|
iden = PARAM_SEPARATOR.join(path_tree[-1][0].name.split()[2:-2])
|
||||||
|
merge_path_tree(path_tree, destination / iden, z_callback=lambda i: pbars.update(1))
|
||||||
|
|
||||||
|
|
||||||
|
def sim_dirs(path_trees: list[PathTree]) -> Generator[Path, None, None]:
|
||||||
|
for p in path_trees[0]:
|
||||||
|
yield p[0].parent
|
||||||
|
|
||||||
|
|
||||||
|
def get_sim_dir(task_id: int, path_if_new: Path = None) -> Path:
|
||||||
|
if path_if_new is None:
|
||||||
|
path_if_new = Path("scgenerator data")
|
||||||
|
tmp = data_folder(task_id)
|
||||||
|
if tmp is None:
|
||||||
|
tmp = ensure_folder(path_if_new)
|
||||||
|
os.environ[TMP_FOLDER_KEY_BASE + str(task_id)] = str(tmp)
|
||||||
|
tmp = Path(tmp).resolve()
|
||||||
|
if not tmp.exists():
|
||||||
|
tmp.mkdir()
|
||||||
|
return tmp
|
||||||
|
|
||||||
|
|
||||||
|
def set_data_folder(task_id: int, path: os.PathLike):
|
||||||
|
"""stores the path to an existing data folder in the environment
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
task_id : int
|
||||||
|
id uniquely identifying the session
|
||||||
|
path : str
|
||||||
|
path to the root of the data folder
|
||||||
|
"""
|
||||||
|
idstr = str(int(task_id))
|
||||||
|
os.environ[TMP_FOLDER_KEY_BASE + idstr] = str(path)
|
||||||
|
|
||||||
|
|
||||||
|
def save_data(data: np.ndarray, data_dir: Path, file_name: str):
|
||||||
|
"""saves numpy array to disk
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
data : np.ndarray
|
||||||
|
data to save
|
||||||
|
file_name : str
|
||||||
|
file name
|
||||||
|
task_id : int
|
||||||
|
id that uniquely identifies the process
|
||||||
|
identifier : str, optional
|
||||||
|
identifier in the main data folder of the task, by default ""
|
||||||
|
"""
|
||||||
|
path = data_dir / file_name
|
||||||
|
np.save(path, data)
|
||||||
|
get_logger(__name__).debug(f"saved data in {path}")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_folder(path: Path, prevent_overwrite: bool = True) -> Path:
|
||||||
|
"""ensure a folder exists and doesn't overwrite anything if required
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
path : Path
|
||||||
|
desired path
|
||||||
|
prevent_overwrite : bool, optional
|
||||||
|
whether to create a new directory when one already exists, by default True
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Path
|
||||||
|
final path
|
||||||
|
"""
|
||||||
|
|
||||||
|
path = path.resolve()
|
||||||
|
|
||||||
|
# is path root ?
|
||||||
|
if len(path.parts) < 2:
|
||||||
|
return path
|
||||||
|
|
||||||
|
# is a part of path an existing *file* ?
|
||||||
|
parts = path.parts
|
||||||
|
path = Path(path.root)
|
||||||
|
for part in parts:
|
||||||
|
if path.is_file():
|
||||||
|
path = ensure_folder(path, prevent_overwrite=False)
|
||||||
|
path /= part
|
||||||
|
|
||||||
|
folder_name = path.name
|
||||||
|
|
||||||
|
for i in itertools.count():
|
||||||
|
if not path.is_file() and (not prevent_overwrite or not path.is_dir()):
|
||||||
|
path.mkdir(exist_ok=True)
|
||||||
|
return path
|
||||||
|
path = path.parent / (folder_name + f"_{i}")
|
||||||
|
|
||||||
|
|
||||||
class PBars:
|
class PBars:
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -53,7 +449,7 @@ class PBars:
|
|||||||
self.num_tot: int = task
|
self.num_tot: int = task
|
||||||
self.iterator = None
|
self.iterator = None
|
||||||
|
|
||||||
self.policy = env.pbar_policy()
|
self.policy = pbar_policy()
|
||||||
if head_kwargs is None:
|
if head_kwargs is None:
|
||||||
head_kwargs = dict()
|
head_kwargs = dict()
|
||||||
if worker_kwargs is None:
|
if worker_kwargs is None:
|
||||||
@@ -62,7 +458,7 @@ class PBars:
|
|||||||
desc="Worker {worker_id}",
|
desc="Worker {worker_id}",
|
||||||
bar_format="{l_bar}{bar}" "|[{elapsed}<{remaining}, " "{rate_fmt}{postfix}]",
|
bar_format="{l_bar}{bar}" "|[{elapsed}<{remaining}, " "{rate_fmt}{postfix}]",
|
||||||
)
|
)
|
||||||
if "print" not in env.pbar_policy():
|
if "print" not in pbar_policy():
|
||||||
head_kwargs["file"] = worker_kwargs["file"] = StringIO()
|
head_kwargs["file"] = worker_kwargs["file"] = StringIO()
|
||||||
self.width = 80
|
self.width = 80
|
||||||
head_kwargs["desc"] = desc
|
head_kwargs["desc"] = desc
|
||||||
@@ -190,72 +586,10 @@ def progress_worker(
|
|||||||
pbars[0].update()
|
pbars[0].update()
|
||||||
|
|
||||||
|
|
||||||
def format_variable_list(l: list[tuple[str, Any]]):
|
|
||||||
joints = 2 * PARAM_SEPARATOR
|
|
||||||
str_list = []
|
|
||||||
for p_name, p_value in l:
|
|
||||||
ps = p_name.replace("/", "").replace(joints[0], "").replace(joints[1], "")
|
|
||||||
vs = (
|
|
||||||
format_value(p_name, p_value)
|
|
||||||
.replace("/", "")
|
|
||||||
.replace(joints[0], "")
|
|
||||||
.replace(joints[1], "")
|
|
||||||
)
|
|
||||||
str_list.append(ps + joints[1] + vs)
|
|
||||||
return joints[0].join(str_list)
|
|
||||||
|
|
||||||
|
|
||||||
def branch_id(branch: tuple[Path, ...]) -> str:
|
def branch_id(branch: tuple[Path, ...]) -> str:
|
||||||
return "".join("".join(re.sub(r"id\d+\S*num\d+", "", b.name).split()[2:-2]) for b in branch)
|
return "".join("".join(re.sub(r"id\d+\S*num\d+", "", b.name).split()[2:-2]) for b in branch)
|
||||||
|
|
||||||
|
|
||||||
def format_value(name: str, value) -> str:
|
|
||||||
if value is True or value is False:
|
|
||||||
return str(value)
|
|
||||||
elif isinstance(value, (float, int)):
|
|
||||||
try:
|
|
||||||
return getattr(Parameters, name).display(value)
|
|
||||||
except AttributeError:
|
|
||||||
return format(value, ".9g")
|
|
||||||
elif isinstance(value, (list, tuple, np.ndarray)):
|
|
||||||
return "-".join([str(v) for v in value])
|
|
||||||
elif isinstance(value, str):
|
|
||||||
p = Path(value)
|
|
||||||
if p.exists():
|
|
||||||
return p.stem
|
|
||||||
return str(value)
|
|
||||||
|
|
||||||
|
|
||||||
def pretty_format_value(name: str, value) -> str:
|
|
||||||
try:
|
|
||||||
return getattr(Parameters, name).display(value)
|
|
||||||
except AttributeError:
|
|
||||||
return name + PARAM_SEPARATOR + str(value)
|
|
||||||
|
|
||||||
|
|
||||||
def pretty_format_from_sim_name(name: str) -> str:
|
|
||||||
"""formats a pretty version of a simulation directory
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
name : str
|
|
||||||
name of the simulation (directory name)
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
str
|
|
||||||
prettier name
|
|
||||||
"""
|
|
||||||
s = name.split(PARAM_SEPARATOR)
|
|
||||||
out = []
|
|
||||||
for key, value in zip(s[::2], s[1::2]):
|
|
||||||
try:
|
|
||||||
out += [key.replace("_", " "), getattr(Parameters, key).display(float(value))]
|
|
||||||
except (AttributeError, ValueError):
|
|
||||||
out.append(key + PARAM_SEPARATOR + value)
|
|
||||||
return PARAM_SEPARATOR.join(out)
|
|
||||||
|
|
||||||
|
|
||||||
def check_data_integrity(sub_folders: list[Path], init_z_num: int):
|
def check_data_integrity(sub_folders: list[Path], init_z_num: int):
|
||||||
"""checks the integrity and completeness of a simulation data folder
|
"""checks the integrity and completeness of a simulation data folder
|
||||||
|
|
||||||
@@ -299,7 +633,7 @@ def num_left_to_propagate(sub_folder: Path, init_z_num: int) -> int:
|
|||||||
IncompleteDataFolderError
|
IncompleteDataFolderError
|
||||||
raised if init_z_num doesn't match that specified in the individual parameter file
|
raised if init_z_num doesn't match that specified in the individual parameter file
|
||||||
"""
|
"""
|
||||||
z_num = io.load_toml(sub_folder / "params.toml")["z_num"]
|
z_num = load_toml(sub_folder / "params.toml")["z_num"]
|
||||||
num_spectra = find_last_spectrum_num(sub_folder) + 1 # because of zero-indexing
|
num_spectra = find_last_spectrum_num(sub_folder) + 1 # because of zero-indexing
|
||||||
|
|
||||||
if z_num != init_z_num:
|
if z_num != init_z_num:
|
||||||
@@ -318,105 +652,6 @@ def find_last_spectrum_num(data_dir: Path):
|
|||||||
return num - 1
|
return num - 1
|
||||||
|
|
||||||
|
|
||||||
def variable_iterator(config: BareConfig) -> Iterator[tuple[list[tuple[str, Any]], dict[str, Any]]]:
|
|
||||||
"""given a config with "variable" parameters, iterates through every possible combination,
|
|
||||||
yielding a a list of (parameter_name, value) tuples and a full config dictionary.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
config : BareConfig
|
|
||||||
initial config obj
|
|
||||||
|
|
||||||
Yields
|
|
||||||
-------
|
|
||||||
Iterator[tuple[list[tuple[str, Any]], dict[str, Any]]]
|
|
||||||
variable_list : a list of (name, value) tuple of parameter name and value that are variable.
|
|
||||||
|
|
||||||
params : a dict[str, Any] to be fed to Parameters
|
|
||||||
"""
|
|
||||||
possible_keys = []
|
|
||||||
possible_ranges = []
|
|
||||||
|
|
||||||
for key, values in config.variable.items():
|
|
||||||
possible_keys.append(key)
|
|
||||||
possible_ranges.append(range(len(values)))
|
|
||||||
|
|
||||||
combinations = itertools.product(*possible_ranges)
|
|
||||||
|
|
||||||
for combination in combinations:
|
|
||||||
indiv_config = {}
|
|
||||||
variable_list = []
|
|
||||||
for i, key in enumerate(possible_keys):
|
|
||||||
parameter_value = config.variable[key][combination[i]]
|
|
||||||
indiv_config[key] = parameter_value
|
|
||||||
variable_list.append((key, parameter_value))
|
|
||||||
param_dict = asdict(config)
|
|
||||||
param_dict.pop("variable")
|
|
||||||
param_dict.update(indiv_config)
|
|
||||||
yield variable_list, param_dict
|
|
||||||
|
|
||||||
|
|
||||||
def required_simulations(
|
|
||||||
*configs: BareConfig,
|
|
||||||
) -> Iterator[tuple[list[tuple[str, Any]], Parameters]]:
|
|
||||||
"""takes the output of `scgenerator.utils.variable_iterator` which is a new dict per different
|
|
||||||
parameter set and iterates through every single necessary simulation
|
|
||||||
|
|
||||||
Yields
|
|
||||||
-------
|
|
||||||
Iterator[tuple[list[tuple[str, Any]], dict]]
|
|
||||||
variable_ind : a list of (name, value) tuple of parameter name and value that are variable. The parameter
|
|
||||||
"num" (how many times this specific parameter set has been yielded already) and "id" (how many parameter sets
|
|
||||||
have been exhausted already) are added to the list to make sure every yielded list is unique.
|
|
||||||
|
|
||||||
dict : a config dictionary for one simulation
|
|
||||||
"""
|
|
||||||
i = 0 # unique sim id
|
|
||||||
for data in itertools.product(*[variable_iterator(config) for config in configs]):
|
|
||||||
all_variable_only, all_params_dict = list(zip(*data))
|
|
||||||
params_dict = all_params_dict[0]
|
|
||||||
for p in all_params_dict[1:]:
|
|
||||||
params_dict.update({k: v for k, v in p.items() if v is not None})
|
|
||||||
variable_only = reduce_all_variable(all_variable_only)
|
|
||||||
for j in range(configs[0].repeat or 1):
|
|
||||||
variable_ind = [("id", i)] + variable_only + [("num", j)]
|
|
||||||
i += 1
|
|
||||||
yield variable_ind, Parameters(**params_dict)
|
|
||||||
|
|
||||||
|
|
||||||
def reduce_all_variable(all_variable: list[list[tuple[str, Any]]]) -> list[tuple[str, Any]]:
|
|
||||||
out = []
|
|
||||||
for n, variable_list in enumerate(all_variable):
|
|
||||||
out += [("fiber", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n % 26] * (n // 26 + 1)), *variable_list]
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
def override_config(new: BareConfig, old: BareConfig = None) -> BareConfig:
|
|
||||||
"""makes sure all the parameters set in new are there, leaves untouched parameters in old"""
|
|
||||||
new_dict = asdict(new)
|
|
||||||
if old is None:
|
|
||||||
return BareConfig(**new_dict)
|
|
||||||
variable = deepcopy(old.variable)
|
|
||||||
new_dict = {k: v for k, v in new_dict.items() if v is not None}
|
|
||||||
|
|
||||||
for k, v in new_dict.pop("variable", {}).items():
|
|
||||||
variable[k] = v
|
|
||||||
for k in variable:
|
|
||||||
new_dict[k] = None
|
|
||||||
return replace(old, variable=variable, **new_dict)
|
|
||||||
|
|
||||||
|
|
||||||
def final_config_from_sequence(*configs: BareConfig) -> BareConfig:
|
|
||||||
if len(configs) == 0:
|
|
||||||
raise ValueError("Must provide at least one config")
|
|
||||||
if len(configs) == 1:
|
|
||||||
return configs[0]
|
|
||||||
elif len(configs) == 2:
|
|
||||||
return override_config(*configs[::-1])
|
|
||||||
else:
|
|
||||||
return override_config(configs[-1], final_config_from_sequence(*configs[:-1]))
|
|
||||||
|
|
||||||
|
|
||||||
def auto_crop(x: np.ndarray, y: np.ndarray, rel_thr: float = 0.01) -> np.ndarray:
|
def auto_crop(x: np.ndarray, y: np.ndarray, rel_thr: float = 0.01) -> np.ndarray:
|
||||||
threshold = y.min() + rel_thr * (y.max() - y.min())
|
threshold = y.min() + rel_thr * (y.max() - y.min())
|
||||||
above_threshold = y > threshold
|
above_threshold = y > threshold
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
import datetime as datetime_module
|
import datetime as datetime_module
|
||||||
import inspect
|
import inspect
|
||||||
import itertools
|
import itertools
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from dataclasses import asdict, dataclass
|
from dataclasses import asdict, dataclass, fields, replace
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, TypeVar, Union
|
from pathlib import Path
|
||||||
import os
|
from typing import Any, Callable, Iterable, Optional, TypeVar, Union, Iterator
|
||||||
import numpy as np
|
from copy import deepcopy
|
||||||
from tqdm.std import Bar
|
|
||||||
|
|
||||||
from .. import math
|
import numpy as np
|
||||||
from ..const import __version__
|
|
||||||
|
from .. import math, utils
|
||||||
|
from ..const import PARAM_SEPARATOR, __version__
|
||||||
from ..logger import get_logger
|
from ..logger import get_logger
|
||||||
from .. import io
|
|
||||||
from ..physics import fiber, materials, pulse, units
|
from ..physics import fiber, materials, pulse, units
|
||||||
|
from ..errors import EvaluatorError, NoDefaultError
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
@@ -99,7 +101,7 @@ def int_pair(name, t):
|
|||||||
invalid = len(t) != 2
|
invalid = len(t) != 2
|
||||||
for m in t:
|
for m in t:
|
||||||
if invalid or not isinstance(m, int):
|
if invalid or not isinstance(m, int):
|
||||||
raise ValueError(f"{name!r} must be a list or a tuple of 2 int")
|
raise ValueError(f"{name!r} must be a list or a tuple of 2 int. got {t!r} instead")
|
||||||
|
|
||||||
|
|
||||||
@type_checker(tuple, list)
|
@type_checker(tuple, list)
|
||||||
@@ -107,7 +109,7 @@ def float_pair(name, t):
|
|||||||
invalid = len(t) != 2
|
invalid = len(t) != 2
|
||||||
for m in t:
|
for m in t:
|
||||||
if invalid or not isinstance(m, (int, float)):
|
if invalid or not isinstance(m, (int, float)):
|
||||||
raise ValueError(f"{name!r} must be a list or a tuple of 2 numbers")
|
raise ValueError(f"{name!r} must be a list or a tuple of 2 numbers. got {t!r} instead")
|
||||||
|
|
||||||
|
|
||||||
def literal(*l):
|
def literal(*l):
|
||||||
@@ -235,8 +237,9 @@ class Parameter:
|
|||||||
|
|
||||||
def __set__(self, instance, value):
|
def __set__(self, instance, value):
|
||||||
if isinstance(value, Parameter):
|
if isinstance(value, Parameter):
|
||||||
defaut = None if self.default is None else copy(self.default)
|
# defaut = None if self.default is None else copy(self.default)
|
||||||
instance.__dict__[self.name] = defaut
|
# instance.__dict__[self.name] = defaut
|
||||||
|
instance.__dict__[self.name] = None
|
||||||
else:
|
else:
|
||||||
if value is not None:
|
if value is not None:
|
||||||
self.validator(self.name, value)
|
self.validator(self.name, value)
|
||||||
@@ -356,6 +359,7 @@ mandatory_parameters = [
|
|||||||
"w_power_fact",
|
"w_power_fact",
|
||||||
"alpha",
|
"alpha",
|
||||||
"spec_0",
|
"spec_0",
|
||||||
|
"field_0",
|
||||||
"z_targets",
|
"z_targets",
|
||||||
"length",
|
"length",
|
||||||
"beta2_coefficients",
|
"beta2_coefficients",
|
||||||
@@ -364,7 +368,7 @@ mandatory_parameters = [
|
|||||||
"raman_type",
|
"raman_type",
|
||||||
"hr_w",
|
"hr_w",
|
||||||
"adapt_step_size",
|
"adapt_step_size",
|
||||||
"tollerated_error",
|
"tolerated_error",
|
||||||
"dynamic_dispersion",
|
"dynamic_dispersion",
|
||||||
"recovery_last_stored",
|
"recovery_last_stored",
|
||||||
]
|
]
|
||||||
@@ -394,8 +398,8 @@ class Parameters:
|
|||||||
pitch: float = Parameter(in_range_excl(0, 1e-3))
|
pitch: float = Parameter(in_range_excl(0, 1e-3))
|
||||||
pitch_ratio: float = Parameter(in_range_excl(0, 1))
|
pitch_ratio: float = Parameter(in_range_excl(0, 1))
|
||||||
core_radius: float = Parameter(in_range_excl(0, 1e-3))
|
core_radius: float = Parameter(in_range_excl(0, 1e-3))
|
||||||
he_mode: Tuple[int, int] = Parameter(int_pair, default=(1, 1))
|
he_mode: tuple[int, int] = Parameter(int_pair, default=(1, 1))
|
||||||
fit_parameters: Tuple[int, int] = Parameter(int_pair, default=(0.08, 200e-9))
|
fit_parameters: tuple[int, int] = Parameter(int_pair, default=(0.08, 200e-9))
|
||||||
beta2_coefficients: Iterable[float] = Parameter(num_list)
|
beta2_coefficients: Iterable[float] = Parameter(num_list)
|
||||||
dispersion_file: str = Parameter(string)
|
dispersion_file: str = Parameter(string)
|
||||||
model: str = Parameter(
|
model: str = Parameter(
|
||||||
@@ -430,6 +434,7 @@ class Parameters:
|
|||||||
shape: str = Parameter(literal("gaussian", "sech"), default="gaussian")
|
shape: str = Parameter(literal("gaussian", "sech"), default="gaussian")
|
||||||
wavelength: float = Parameter(in_range_incl(100e-9, 3000e-9), display_info=(1e9, "nm"))
|
wavelength: float = Parameter(in_range_incl(100e-9, 3000e-9), display_info=(1e9, "nm"))
|
||||||
intensity_noise: float = Parameter(in_range_incl(0, 1), display_info=(1e2, "%"), default=0)
|
intensity_noise: float = Parameter(in_range_incl(0, 1), display_info=(1e2, "%"), default=0)
|
||||||
|
noise_correlation: float = Parameter(in_range_incl(-10, 10), default=0)
|
||||||
width: float = Parameter(in_range_excl(0, 1e-9), display_info=(1e15, "fs"))
|
width: float = Parameter(in_range_excl(0, 1e-9), display_info=(1e15, "fs"))
|
||||||
t0: float = Parameter(in_range_excl(0, 1e-9), display_info=(1e15, "fs"))
|
t0: float = Parameter(in_range_excl(0, 1e-9), display_info=(1e15, "fs"))
|
||||||
|
|
||||||
@@ -446,8 +451,8 @@ class Parameters:
|
|||||||
time_window: float = Parameter(positive(float, int))
|
time_window: float = Parameter(positive(float, int))
|
||||||
dt: float = Parameter(in_range_excl(0, 5e-15))
|
dt: float = Parameter(in_range_excl(0, 5e-15))
|
||||||
tolerated_error: float = Parameter(in_range_excl(1e-15, 1e-3), default=1e-11)
|
tolerated_error: float = Parameter(in_range_excl(1e-15, 1e-3), default=1e-11)
|
||||||
step_size: float = Parameter(positive(float, int))
|
step_size: float = Parameter(positive(float, int), default=0)
|
||||||
interpolation_range: Tuple[float, float] = Parameter(float_pair)
|
interpolation_range: tuple[float, float] = Parameter(float_pair)
|
||||||
interpolation_degree: int = Parameter(positive(int), default=8)
|
interpolation_degree: int = Parameter(positive(int), default=8)
|
||||||
prev_sim_dir: str = Parameter(string)
|
prev_sim_dir: str = Parameter(string)
|
||||||
recovery_last_stored: int = Parameter(non_negative(int), default=0)
|
recovery_last_stored: int = Parameter(non_negative(int), default=0)
|
||||||
@@ -457,7 +462,8 @@ class Parameters:
|
|||||||
field_0: np.ndarray = Parameter(type_checker(np.ndarray))
|
field_0: np.ndarray = Parameter(type_checker(np.ndarray))
|
||||||
spec_0: np.ndarray = Parameter(type_checker(np.ndarray))
|
spec_0: np.ndarray = Parameter(type_checker(np.ndarray))
|
||||||
beta2: float = Parameter(type_checker(int, float))
|
beta2: float = Parameter(type_checker(int, float))
|
||||||
alpha: np.ndarray = Parameter(type_checker(np.ndarray))
|
alpha_arr: np.ndarray = Parameter(type_checker(np.ndarray))
|
||||||
|
alpha: float = Parameter(positive(float, int), default=0)
|
||||||
gamma_arr: np.ndarray = Parameter(type_checker(np.ndarray))
|
gamma_arr: np.ndarray = Parameter(type_checker(np.ndarray))
|
||||||
A_eff_arr: np.ndarray = Parameter(type_checker(np.ndarray))
|
A_eff_arr: np.ndarray = Parameter(type_checker(np.ndarray))
|
||||||
w: np.ndarray = Parameter(type_checker(np.ndarray))
|
w: np.ndarray = Parameter(type_checker(np.ndarray))
|
||||||
@@ -475,12 +481,12 @@ class Parameters:
|
|||||||
hr_w: np.ndarray = Parameter(type_checker(np.ndarray))
|
hr_w: np.ndarray = Parameter(type_checker(np.ndarray))
|
||||||
z_targets: np.ndarray = Parameter(type_checker(np.ndarray))
|
z_targets: np.ndarray = Parameter(type_checker(np.ndarray))
|
||||||
const_qty: np.ndarray = Parameter(type_checker(np.ndarray))
|
const_qty: np.ndarray = Parameter(type_checker(np.ndarray))
|
||||||
beta_func: Callable[[float], List[float]] = Parameter(func_validator)
|
beta_func: Callable[[float], list[float]] = Parameter(func_validator)
|
||||||
gamma_func: Callable[[float], float] = Parameter(func_validator)
|
gamma_func: Callable[[float], float] = Parameter(func_validator)
|
||||||
datetime: datetime_module.datetime = Parameter(type_checker(datetime_module.datetime))
|
datetime: datetime_module.datetime = Parameter(type_checker(datetime_module.datetime))
|
||||||
version: str = Parameter(string)
|
version: str = Parameter(string)
|
||||||
|
|
||||||
def prepare_for_dump(self) -> Dict[str, Any]:
|
def prepare_for_dump(self) -> dict[str, Any]:
|
||||||
param = asdict(self)
|
param = asdict(self)
|
||||||
param = Parameters.strip_params_dict(param)
|
param = Parameters.strip_params_dict(param)
|
||||||
param["datetime"] = datetime_module.datetime.now()
|
param["datetime"] = datetime_module.datetime.now()
|
||||||
@@ -493,16 +499,21 @@ class Parameters:
|
|||||||
evaluator.set(**param_dict)
|
evaluator.set(**param_dict)
|
||||||
for p_name in mandatory_parameters:
|
for p_name in mandatory_parameters:
|
||||||
evaluator.compute(p_name)
|
evaluator.compute(p_name)
|
||||||
|
valid_fields = self.all_parameters()
|
||||||
for k, v in evaluator.params.items():
|
for k, v in evaluator.params.items():
|
||||||
if k in param_dict:
|
if k in valid_fields:
|
||||||
setattr(self, k, v)
|
setattr(self, k, v)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def all_parameters(cls) -> list[str]:
|
||||||
|
return [f.name for f in fields(cls)]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, path: os.PathLike) -> "Parameters":
|
def load(cls, path: os.PathLike) -> "Parameters":
|
||||||
return cls(**io.load_toml(path))
|
return cls(**utils.load_toml(path))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def strip_params_dict(dico: Dict[str, Any]) -> Dict[str, Any]:
|
def strip_params_dict(dico: dict[str, Any]) -> dict[str, Any]:
|
||||||
"""prepares a dictionary for serialization. Some keys may not be preserved
|
"""prepares a dictionary for serialization. Some keys may not be preserved
|
||||||
(dropped because they take a lot of space and can be exactly reconstructed)
|
(dropped because they take a lot of space and can be exactly reconstructed)
|
||||||
|
|
||||||
@@ -545,10 +556,6 @@ class Parameters:
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
class EvaluatorError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Rule:
|
class Rule:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -657,6 +664,12 @@ class Evaluator:
|
|||||||
self.params = {}
|
self.params = {}
|
||||||
self.eval_stats = defaultdict(EvalStat)
|
self.eval_stats = defaultdict(EvalStat)
|
||||||
|
|
||||||
|
def get_default(self, key: str) -> Any:
|
||||||
|
try:
|
||||||
|
return getattr(Parameters, key).default
|
||||||
|
except AttributeError:
|
||||||
|
return None
|
||||||
|
|
||||||
def compute(self, target: str) -> Any:
|
def compute(self, target: str) -> Any:
|
||||||
"""computes a target
|
"""computes a target
|
||||||
|
|
||||||
@@ -679,6 +692,8 @@ class Evaluator:
|
|||||||
"""
|
"""
|
||||||
value = self.params.get(target)
|
value = self.params.get(target)
|
||||||
if value is None:
|
if value is None:
|
||||||
|
prefix = "\t" * len(self.__curent_lookup)
|
||||||
|
# Avoid cycles
|
||||||
if target in self.__curent_lookup:
|
if target in self.__curent_lookup:
|
||||||
raise EvaluatorError(
|
raise EvaluatorError(
|
||||||
"cyclic dependency detected : "
|
"cyclic dependency detected : "
|
||||||
@@ -689,13 +704,17 @@ class Evaluator:
|
|||||||
self.__curent_lookup.add(target)
|
self.__curent_lookup.add(target)
|
||||||
|
|
||||||
if len(self.rules[target]) == 0:
|
if len(self.rules[target]) == 0:
|
||||||
raise EvaluatorError(f"no rule for {target}")
|
error = EvaluatorError(f"no rule for {target}")
|
||||||
|
else:
|
||||||
error = None
|
error = None
|
||||||
|
|
||||||
|
# try every rule until one succeeds
|
||||||
for ii, rule in enumerate(
|
for ii, rule in enumerate(
|
||||||
filter(lambda r: self.validate_condition(r), reversed(self.rules[target]))
|
filter(lambda r: self.validate_condition(r), self.rules[target])
|
||||||
):
|
):
|
||||||
self.logger.debug(f"attempt {ii+1} to compute {target}, this time using {rule!r}")
|
self.logger.debug(
|
||||||
|
prefix + f"attempt {ii+1} to compute {target}, this time using {rule!r}"
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
args = [self.compute(k) for k in rule.args]
|
args = [self.compute(k) for k in rule.args]
|
||||||
returned_values = rule.func(*args)
|
returned_values = rule.func(*args)
|
||||||
@@ -710,16 +729,26 @@ class Evaluator:
|
|||||||
or self.eval_stats[param_name].priority < param_priority
|
or self.eval_stats[param_name].priority < param_priority
|
||||||
):
|
):
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
f"computed {param_name}={returned_value} using {rule.func.__name__} from {rule.func.__module__}"
|
prefix
|
||||||
|
+ f"computed {param_name}={returned_value} using {rule.func.__name__} from {rule.func.__module__}"
|
||||||
)
|
)
|
||||||
self.params[param_name] = returned_value
|
self.params[param_name] = returned_value
|
||||||
self.eval_stats[param_name] = param_priority
|
self.eval_stats[param_name].priority = param_priority
|
||||||
if param_name == target:
|
if param_name == target:
|
||||||
value = returned_value
|
value = returned_value
|
||||||
break
|
break
|
||||||
except (EvaluatorError, KeyError) as e:
|
except (EvaluatorError, KeyError, NoDefaultError) as e:
|
||||||
error = e
|
error = e
|
||||||
|
self.logger.debug(
|
||||||
|
prefix + f"error using {rule.func.__name__} : {str(error).strip()}"
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
|
else:
|
||||||
|
default = self.get_default(target)
|
||||||
|
if default is None:
|
||||||
|
error = NoDefaultError(prefix + f"No default provided for {target}")
|
||||||
|
else:
|
||||||
|
value = default
|
||||||
|
|
||||||
if value is None and error is not None:
|
if value is None and error is not None:
|
||||||
raise error
|
raise error
|
||||||
@@ -749,6 +778,107 @@ class Evaluator:
|
|||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BareConfig(Parameters):
|
||||||
|
variable: dict = VariableParameter(Parameters)
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls, path: os.PathLike) -> "BareConfig":
|
||||||
|
return cls(**utils.load_toml(path))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_sequence(cls, *config_paths: os.PathLike) -> list["BareConfig"]:
|
||||||
|
"""Loads a sequence of
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
config_paths : os.PathLike
|
||||||
|
either one path (the last config containing previous_config_file parameter)
|
||||||
|
or a list of config path in the order they have to be simulated
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list[BareConfig]
|
||||||
|
all loaded configs
|
||||||
|
"""
|
||||||
|
if config_paths[0] is None:
|
||||||
|
return []
|
||||||
|
all_configs = [cls.load(config_paths[0])]
|
||||||
|
if len(config_paths) == 1:
|
||||||
|
while True:
|
||||||
|
if all_configs[0].previous_config_file is not None:
|
||||||
|
all_configs.insert(0, cls.load(all_configs[0].previous_config_file))
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
for i, path in enumerate(config_paths[1:]):
|
||||||
|
all_configs.append(cls.load(path))
|
||||||
|
all_configs[i + 1].previous_config_file = config_paths[i]
|
||||||
|
return all_configs
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PlotRange:
|
||||||
|
left: float = Parameter(type_checker(int, float))
|
||||||
|
right: float = Parameter(type_checker(int, float))
|
||||||
|
unit: Callable[[float], float] = Parameter(units.is_unit, converter=units.get_unit)
|
||||||
|
conserved_quantity: bool = Parameter(boolean, default=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.left:.1f}-{self.right:.1f} {self.unit.__name__}"
|
||||||
|
|
||||||
|
|
||||||
|
def sort_axis(axis, plt_range: PlotRange) -> tuple[np.ndarray, np.ndarray, tuple[float, float]]:
|
||||||
|
"""
|
||||||
|
given an axis, returns this axis cropped according to the given range, converted and sorted
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
axis : 1D array containing the original axis (usual the w or t array)
|
||||||
|
plt_range : tupple (min, max, conversion_function) used to crop the axis
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
cropped : the axis cropped, converted and sorted
|
||||||
|
indices : indices to use to slice and sort other array in the same fashion
|
||||||
|
extent : tupple with min and max of cropped
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
w = np.append(np.linspace(0, -10, 20), np.linspace(0, 10, 20))
|
||||||
|
t = np.linspace(-10, 10, 400)
|
||||||
|
W, T = np.meshgrid(w, t)
|
||||||
|
y = np.exp(-W**2 - T**2)
|
||||||
|
|
||||||
|
# Define ranges
|
||||||
|
rw = (-4, 4, s)
|
||||||
|
rt = (-2, 6, s)
|
||||||
|
|
||||||
|
w, cw = sort_axis(w, rw)
|
||||||
|
t, ct = sort_axis(t, rt)
|
||||||
|
|
||||||
|
# slice y according to the given ranges
|
||||||
|
y = y[ct][:, cw]
|
||||||
|
"""
|
||||||
|
if isinstance(plt_range, tuple):
|
||||||
|
plt_range = PlotRange(*plt_range)
|
||||||
|
r = np.array((plt_range.left, plt_range.right), dtype="float")
|
||||||
|
|
||||||
|
indices = np.arange(len(axis))[
|
||||||
|
(axis <= np.max(plt_range.unit(r))) & (axis >= np.min(plt_range.unit(r)))
|
||||||
|
]
|
||||||
|
cropped = axis[indices]
|
||||||
|
order = np.argsort(plt_range.unit.inv(cropped))
|
||||||
|
indices = indices[order]
|
||||||
|
cropped = cropped[order]
|
||||||
|
out_ax = plt_range.unit.inv(cropped)
|
||||||
|
|
||||||
|
return out_ax, indices, (out_ax[0], out_ax[-1])
|
||||||
|
|
||||||
|
|
||||||
def get_arg_names(func: Callable) -> list[str]:
|
def get_arg_names(func: Callable) -> list[str]:
|
||||||
spec = inspect.getfullargspec(func)
|
spec = inspect.getfullargspec(func)
|
||||||
args = spec.args
|
args = spec.args
|
||||||
@@ -780,6 +910,167 @@ def func_rewrite(func: Callable, kwarg_names: list[str], arg_names: list[str] =
|
|||||||
return out_func
|
return out_func
|
||||||
|
|
||||||
|
|
||||||
|
def format_variable_list(l: list[tuple[str, Any]]):
|
||||||
|
joints = 2 * PARAM_SEPARATOR
|
||||||
|
str_list = []
|
||||||
|
for p_name, p_value in l:
|
||||||
|
ps = p_name.replace("/", "").replace(joints[0], "").replace(joints[1], "")
|
||||||
|
vs = (
|
||||||
|
format_value(p_name, p_value)
|
||||||
|
.replace("/", "")
|
||||||
|
.replace(joints[0], "")
|
||||||
|
.replace(joints[1], "")
|
||||||
|
)
|
||||||
|
str_list.append(ps + joints[1] + vs)
|
||||||
|
return joints[0].join(str_list)
|
||||||
|
|
||||||
|
|
||||||
|
def format_value(name: str, value) -> str:
|
||||||
|
if value is True or value is False:
|
||||||
|
return str(value)
|
||||||
|
elif isinstance(value, (float, int)):
|
||||||
|
try:
|
||||||
|
return getattr(Parameters, name).display(value)
|
||||||
|
except AttributeError:
|
||||||
|
return format(value, ".9g")
|
||||||
|
elif isinstance(value, (list, tuple, np.ndarray)):
|
||||||
|
return "-".join([str(v) for v in value])
|
||||||
|
elif isinstance(value, str):
|
||||||
|
p = Path(value)
|
||||||
|
if p.exists():
|
||||||
|
return p.stem
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
|
def pretty_format_value(name: str, value) -> str:
|
||||||
|
try:
|
||||||
|
return getattr(Parameters, name).display(value)
|
||||||
|
except AttributeError:
|
||||||
|
return name + PARAM_SEPARATOR + str(value)
|
||||||
|
|
||||||
|
|
||||||
|
def pretty_format_from_sim_name(name: str) -> str:
|
||||||
|
"""formats a pretty version of a simulation directory
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
name : str
|
||||||
|
name of the simulation (directory name)
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
prettier name
|
||||||
|
"""
|
||||||
|
s = name.split(PARAM_SEPARATOR)
|
||||||
|
out = []
|
||||||
|
for key, value in zip(s[::2], s[1::2]):
|
||||||
|
try:
|
||||||
|
out += [key.replace("_", " "), getattr(Parameters, key).display(float(value))]
|
||||||
|
except (AttributeError, ValueError):
|
||||||
|
out.append(key + PARAM_SEPARATOR + value)
|
||||||
|
return PARAM_SEPARATOR.join(out)
|
||||||
|
|
||||||
|
|
||||||
|
def variable_iterator(config: BareConfig) -> Iterator[tuple[list[tuple[str, Any]], dict[str, Any]]]:
|
||||||
|
"""given a config with "variable" parameters, iterates through every possible combination,
|
||||||
|
yielding a a list of (parameter_name, value) tuples and a full config dictionary.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
config : BareConfig
|
||||||
|
initial config obj
|
||||||
|
|
||||||
|
Yields
|
||||||
|
-------
|
||||||
|
Iterator[tuple[list[tuple[str, Any]], dict[str, Any]]]
|
||||||
|
variable_list : a list of (name, value) tuple of parameter name and value that are variable.
|
||||||
|
|
||||||
|
params : a dict[str, Any] to be fed to Parameters
|
||||||
|
"""
|
||||||
|
possible_keys = []
|
||||||
|
possible_ranges = []
|
||||||
|
|
||||||
|
for key, values in config.variable.items():
|
||||||
|
possible_keys.append(key)
|
||||||
|
possible_ranges.append(range(len(values)))
|
||||||
|
|
||||||
|
combinations = itertools.product(*possible_ranges)
|
||||||
|
|
||||||
|
for combination in combinations:
|
||||||
|
indiv_config = {}
|
||||||
|
variable_list = []
|
||||||
|
for i, key in enumerate(possible_keys):
|
||||||
|
parameter_value = config.variable[key][combination[i]]
|
||||||
|
indiv_config[key] = parameter_value
|
||||||
|
variable_list.append((key, parameter_value))
|
||||||
|
param_dict = asdict(config)
|
||||||
|
param_dict.pop("variable")
|
||||||
|
param_dict.update(indiv_config)
|
||||||
|
yield variable_list, param_dict
|
||||||
|
|
||||||
|
|
||||||
|
def required_simulations(
|
||||||
|
*configs: BareConfig,
|
||||||
|
) -> Iterator[tuple[list[tuple[str, Any]], Parameters]]:
|
||||||
|
"""takes the output of `scgenerator.utils.variable_iterator` which is a new dict per different
|
||||||
|
parameter set and iterates through every single necessary simulation
|
||||||
|
|
||||||
|
Yields
|
||||||
|
-------
|
||||||
|
Iterator[tuple[list[tuple[str, Any]], dict]]
|
||||||
|
variable_ind : a list of (name, value) tuple of parameter name and value that are variable. The parameter
|
||||||
|
"num" (how many times this specific parameter set has been yielded already) and "id" (how many parameter sets
|
||||||
|
have been exhausted already) are added to the list to make sure every yielded list is unique.
|
||||||
|
|
||||||
|
dict : a config dictionary for one simulation
|
||||||
|
"""
|
||||||
|
i = 0 # unique sim id
|
||||||
|
for data in itertools.product(*[variable_iterator(config) for config in configs]):
|
||||||
|
all_variable_only, all_params_dict = list(zip(*data))
|
||||||
|
params_dict = all_params_dict[0]
|
||||||
|
for p in all_params_dict[1:]:
|
||||||
|
params_dict.update({k: v for k, v in p.items() if v is not None})
|
||||||
|
variable_only = reduce_all_variable(all_variable_only)
|
||||||
|
for j in range(configs[0].repeat or 1):
|
||||||
|
variable_ind = [("id", i)] + variable_only + [("num", j)]
|
||||||
|
i += 1
|
||||||
|
yield variable_ind, Parameters(**params_dict)
|
||||||
|
|
||||||
|
|
||||||
|
def reduce_all_variable(all_variable: list[list[tuple[str, Any]]]) -> list[tuple[str, Any]]:
|
||||||
|
out = []
|
||||||
|
for n, variable_list in enumerate(all_variable):
|
||||||
|
out += [("fiber", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n % 26] * (n // 26 + 1)), *variable_list]
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def override_config(new: BareConfig, old: BareConfig = None) -> BareConfig:
|
||||||
|
"""makes sure all the parameters set in new are there, leaves untouched parameters in old"""
|
||||||
|
new_dict = asdict(new)
|
||||||
|
if old is None:
|
||||||
|
return BareConfig(**new_dict)
|
||||||
|
variable = deepcopy(old.variable)
|
||||||
|
new_dict = {k: v for k, v in new_dict.items() if v is not None}
|
||||||
|
|
||||||
|
for k, v in new_dict.pop("variable", {}).items():
|
||||||
|
variable[k] = v
|
||||||
|
for k in variable:
|
||||||
|
new_dict[k] = None
|
||||||
|
return replace(old, variable=variable, **new_dict)
|
||||||
|
|
||||||
|
|
||||||
|
def final_config_from_sequence(*configs: BareConfig) -> BareConfig:
|
||||||
|
if len(configs) == 0:
|
||||||
|
raise ValueError("Must provide at least one config")
|
||||||
|
if len(configs) == 1:
|
||||||
|
return configs[0]
|
||||||
|
elif len(configs) == 2:
|
||||||
|
return override_config(*configs[::-1])
|
||||||
|
else:
|
||||||
|
return override_config(configs[-1], final_config_from_sequence(*configs[:-1]))
|
||||||
|
|
||||||
|
|
||||||
default_rules: list[Rule] = [
|
default_rules: list[Rule] = [
|
||||||
# Grid
|
# Grid
|
||||||
*Rule.deduce(
|
*Rule.deduce(
|
||||||
@@ -788,26 +1079,16 @@ default_rules: list[Rule] = [
|
|||||||
["time_window", "t_num", "dt"],
|
["time_window", "t_num", "dt"],
|
||||||
2,
|
2,
|
||||||
),
|
),
|
||||||
|
Rule("adapt_step_size", lambda step_size: step_size == 0),
|
||||||
|
Rule("dynamic_dispersion", lambda pressure: isinstance(pressure, (list, tuple, np.ndarray))),
|
||||||
# Pulse
|
# Pulse
|
||||||
Rule("spec_0", np.fft.fft, ["field_0"]),
|
Rule("spec_0", np.fft.fft, ["field_0"]),
|
||||||
Rule("field_0", np.fft.ifft, ["spec_0"]),
|
Rule("field_0", np.fft.ifft, ["spec_0"]),
|
||||||
Rule("spec_0", pulse.load_previous_spectrum, priorities=3),
|
Rule("spec_0", utils.load_previous_spectrum, priorities=3),
|
||||||
Rule(
|
Rule(
|
||||||
["pre_field_0", "peak_power", "energy", "width"],
|
["pre_field_0", "peak_power", "energy", "width"],
|
||||||
pulse.load_field_file,
|
pulse.load_and_adjust_field_file,
|
||||||
[
|
["field_file", "t", "peak_power", "energy", "intensity_noise", "noise_correlation"],
|
||||||
"field_file",
|
|
||||||
"t",
|
|
||||||
"peak_power",
|
|
||||||
"energy",
|
|
||||||
"intensity_noise",
|
|
||||||
"noise_correlation",
|
|
||||||
"quantum_noise",
|
|
||||||
"w_c",
|
|
||||||
"w0",
|
|
||||||
"time_window",
|
|
||||||
"dt",
|
|
||||||
],
|
|
||||||
priorities=[2, 1, 1, 1],
|
priorities=[2, 1, 1, 1],
|
||||||
),
|
),
|
||||||
Rule("pre_field_0", pulse.initial_field, priorities=1),
|
Rule("pre_field_0", pulse.initial_field, priorities=1),
|
||||||
@@ -818,6 +1099,7 @@ default_rules: list[Rule] = [
|
|||||||
),
|
),
|
||||||
Rule("peak_power", pulse.E0_to_P0, ["energy", "t0", "shape"]),
|
Rule("peak_power", pulse.E0_to_P0, ["energy", "t0", "shape"]),
|
||||||
Rule("peak_power", pulse.soliton_num_to_peak_power),
|
Rule("peak_power", pulse.soliton_num_to_peak_power),
|
||||||
|
Rule(["width", "peak_power", "energy"], pulse.measure_custom_field),
|
||||||
Rule("energy", pulse.P0_to_E0, ["peak_power", "t0", "shape"]),
|
Rule("energy", pulse.P0_to_E0, ["peak_power", "t0", "shape"]),
|
||||||
Rule("energy", pulse.mean_power_to_energy),
|
Rule("energy", pulse.mean_power_to_energy),
|
||||||
Rule("t0", pulse.width_to_t0),
|
Rule("t0", pulse.width_to_t0),
|
||||||
@@ -874,55 +1156,14 @@ default_rules: list[Rule] = [
|
|||||||
Rule("gamma", lambda gamma_arr: gamma_arr[0]),
|
Rule("gamma", lambda gamma_arr: gamma_arr[0]),
|
||||||
Rule("gamma_arr", fiber.gamma_parameter, ["n2", "w0", "A_eff_arr"]),
|
Rule("gamma_arr", fiber.gamma_parameter, ["n2", "w0", "A_eff_arr"]),
|
||||||
# Fiber loss
|
# Fiber loss
|
||||||
Rule("alpha", fiber.compute_capillary_loss),
|
Rule("alpha_arr", fiber.compute_capillary_loss),
|
||||||
Rule("alpha", fiber.load_custom_loss),
|
Rule("alpha_arr", fiber.load_custom_loss),
|
||||||
|
Rule("alpha_arr", lambda alpha, t: np.ones_like(t) * alpha),
|
||||||
# gas
|
# gas
|
||||||
Rule("n_gas_2", materials.n_gas_2),
|
Rule("n_gas_2", materials.n_gas_2),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class BareConfig(Parameters):
|
|
||||||
variable: dict = VariableParameter(Parameters)
|
|
||||||
|
|
||||||
def __post_init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def load(cls, path: os.PathLike) -> "BareConfig":
|
|
||||||
return cls(**io.load_toml(path))
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def load_sequence(cls, *config_paths: os.PathLike) -> list["BareConfig"]:
|
|
||||||
"""Loads a sequence of
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
config_paths : os.PathLike
|
|
||||||
either one path (the last config containing previous_config_file parameter)
|
|
||||||
or a list of config path in the order they have to be simulated
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
list[BareConfig]
|
|
||||||
all loaded configs
|
|
||||||
"""
|
|
||||||
if config_paths[0] is None:
|
|
||||||
return []
|
|
||||||
all_configs = [cls.load(config_paths[0])]
|
|
||||||
if len(config_paths) == 1:
|
|
||||||
while True:
|
|
||||||
if all_configs[0].previous_config_file is not None:
|
|
||||||
all_configs.insert(0, cls.load(all_configs[0].previous_config_file))
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
for i, path in enumerate(config_paths[1:]):
|
|
||||||
all_configs.append(cls.load(path))
|
|
||||||
all_configs[i + 1].previous_config_file = config_paths[i]
|
|
||||||
return all_configs
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
numero = type_checker(int)
|
numero = type_checker(int)
|
||||||
|
|||||||
Reference in New Issue
Block a user