From be0a9b8c2099bb74a58bb8ff37129fc8a11ec261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Sierro?= Date: Mon, 24 Jul 2023 14:28:41 +0200 Subject: [PATCH] Some more cleanups, especially tests --- .../Optica_PM2000D/Optica_PM2000D.toml | 0 .../PM2000D_2 extrapolated 4 0.npz | Bin .../Optica_PM2000D/PM2000D_A_eff_marcuse.npz | Bin .../Optica_PM2000D/Pos30000New.npz | Bin .../Optica_PM2000D/test_Optica_PM2000D.py | 0 {tests => examples}/Travers/Travers.toml | 0 {tests => examples}/Travers/Travers2019.py | 0 examples/{test_rate.py => ion_rate_plot.py} | 0 examples/test_integrator.py | 151 ------------------ src/scgenerator/solver.py | 42 ++++- testing/configs/Chang2011Fig2.toml | 18 --- .../configs/compute_init_parameters/good.toml | 26 --- .../count_variations/120sim_3vary.toml | 24 --- .../configs/count_variations/1sim_0vary.toml | 21 --- .../configs/count_variations/1sim_1vary.toml | 22 --- .../configs/count_variations/2sim_0vary.toml | 21 --- .../configs/count_variations/2sim_1vary.toml | 24 --- testing/configs/custom_field/init_field.npz | Bin 49656 -> 0 bytes testing/configs/custom_field/mean_power.toml | 8 - testing/configs/custom_field/no_change.toml | 6 - testing/configs/custom_field/peak_power.toml | 7 - testing/configs/custom_field/recover1.toml | 7 - testing/configs/custom_field/recover2.toml | 7 - .../custom_field/wavelength_shift1.toml | 20 --- .../custom_field/wavelength_shift2.toml | 24 --- testing/configs/ensure_consistency/bad1.toml | 30 ---- testing/configs/ensure_consistency/bad2.toml | 30 ---- testing/configs/ensure_consistency/bad3.toml | 30 ---- testing/configs/ensure_consistency/bad4.toml | 32 ---- testing/configs/ensure_consistency/bad5.toml | 33 ---- testing/configs/ensure_consistency/bad6.toml | 32 ---- testing/configs/ensure_consistency/good1.toml | 31 ---- testing/configs/ensure_consistency/good2.toml | 30 ---- testing/configs/ensure_consistency/good3.toml | 29 ---- testing/configs/ensure_consistency/good4.toml | 38 ----- testing/configs/ensure_consistency/good5.toml | 30 ---- testing/configs/ensure_consistency/good6.toml | 32 ---- testing/configs/override/fiber2.toml | 23 --- testing/configs/override/initial_config.toml | 42 ----- .../configs/param_sequence/almost_equal.toml | 30 ---- testing/configs/param_sequence/equal.toml | 30 ---- .../configs/param_sequence/no_variations.toml | 27 ---- .../run_simulations/full_anomalous.toml | 33 ---- testing/configs/validate_types/bad1.toml | 31 ---- testing/configs/validate_types/bad2.toml | 31 ---- testing/configs/validate_types/bad3.toml | 31 ---- testing/configs/validate_types/bad4.toml | 32 ---- testing/configs/validate_types/bad5.toml | 31 ---- testing/configs/validate_types/bad6.toml | 31 ---- testing/configs/validate_types/bad7.toml | 29 ---- testing/configs/validate_types/good.toml | 29 ---- testing/test_all_zeros.py | 16 -- testing/test_cache.py | 0 testing/test_env.py | 0 testing/test_evaluator.py | 0 testing/test_full_field.py | 55 ------- testing/test_legacy.py | 0 testing/test_logger.py | 0 testing/test_math.py | 134 ---------------- testing/test_operators.py | 0 testing/test_parameter.py | 0 testing/test_pbar.py | 0 testing/test_plotting.py | 0 testing/test_resonance.py | 21 --- testing/test_spectra.py | 0 testing/test_utils.py | 0 testing/test_variationer.py | 54 ------- testing/test_vincetti.py | 21 --- tests/test_current_state.py | 31 ---- tests/test_integrator.py | 87 ++++++++++ tests/test_simulation_result.py | 17 ++ 71 files changed, 142 insertions(+), 1529 deletions(-) rename {tests => examples}/Optica_PM2000D/Optica_PM2000D.toml (100%) rename {tests => examples}/Optica_PM2000D/PM2000D_2 extrapolated 4 0.npz (100%) rename {tests => examples}/Optica_PM2000D/PM2000D_A_eff_marcuse.npz (100%) rename {tests => examples}/Optica_PM2000D/Pos30000New.npz (100%) rename {tests => examples}/Optica_PM2000D/test_Optica_PM2000D.py (100%) rename {tests => examples}/Travers/Travers.toml (100%) rename {tests => examples}/Travers/Travers2019.py (100%) rename examples/{test_rate.py => ion_rate_plot.py} (100%) delete mode 100644 examples/test_integrator.py delete mode 100644 testing/configs/Chang2011Fig2.toml delete mode 100644 testing/configs/compute_init_parameters/good.toml delete mode 100644 testing/configs/count_variations/120sim_3vary.toml delete mode 100644 testing/configs/count_variations/1sim_0vary.toml delete mode 100644 testing/configs/count_variations/1sim_1vary.toml delete mode 100644 testing/configs/count_variations/2sim_0vary.toml delete mode 100644 testing/configs/count_variations/2sim_1vary.toml delete mode 100644 testing/configs/custom_field/init_field.npz delete mode 100644 testing/configs/custom_field/mean_power.toml delete mode 100644 testing/configs/custom_field/no_change.toml delete mode 100644 testing/configs/custom_field/peak_power.toml delete mode 100644 testing/configs/custom_field/recover1.toml delete mode 100644 testing/configs/custom_field/recover2.toml delete mode 100644 testing/configs/custom_field/wavelength_shift1.toml delete mode 100644 testing/configs/custom_field/wavelength_shift2.toml delete mode 100644 testing/configs/ensure_consistency/bad1.toml delete mode 100644 testing/configs/ensure_consistency/bad2.toml delete mode 100644 testing/configs/ensure_consistency/bad3.toml delete mode 100644 testing/configs/ensure_consistency/bad4.toml delete mode 100644 testing/configs/ensure_consistency/bad5.toml delete mode 100644 testing/configs/ensure_consistency/bad6.toml delete mode 100644 testing/configs/ensure_consistency/good1.toml delete mode 100644 testing/configs/ensure_consistency/good2.toml delete mode 100644 testing/configs/ensure_consistency/good3.toml delete mode 100644 testing/configs/ensure_consistency/good4.toml delete mode 100644 testing/configs/ensure_consistency/good5.toml delete mode 100644 testing/configs/ensure_consistency/good6.toml delete mode 100644 testing/configs/override/fiber2.toml delete mode 100644 testing/configs/override/initial_config.toml delete mode 100644 testing/configs/param_sequence/almost_equal.toml delete mode 100644 testing/configs/param_sequence/equal.toml delete mode 100644 testing/configs/param_sequence/no_variations.toml delete mode 100644 testing/configs/run_simulations/full_anomalous.toml delete mode 100644 testing/configs/validate_types/bad1.toml delete mode 100644 testing/configs/validate_types/bad2.toml delete mode 100644 testing/configs/validate_types/bad3.toml delete mode 100644 testing/configs/validate_types/bad4.toml delete mode 100644 testing/configs/validate_types/bad5.toml delete mode 100644 testing/configs/validate_types/bad6.toml delete mode 100644 testing/configs/validate_types/bad7.toml delete mode 100644 testing/configs/validate_types/good.toml delete mode 100644 testing/test_all_zeros.py delete mode 100644 testing/test_cache.py delete mode 100644 testing/test_env.py delete mode 100644 testing/test_evaluator.py delete mode 100644 testing/test_full_field.py delete mode 100644 testing/test_legacy.py delete mode 100644 testing/test_logger.py delete mode 100644 testing/test_math.py delete mode 100644 testing/test_operators.py delete mode 100644 testing/test_parameter.py delete mode 100644 testing/test_pbar.py delete mode 100644 testing/test_plotting.py delete mode 100644 testing/test_resonance.py delete mode 100644 testing/test_spectra.py delete mode 100644 testing/test_utils.py delete mode 100644 testing/test_variationer.py delete mode 100644 testing/test_vincetti.py delete mode 100644 tests/test_current_state.py create mode 100644 tests/test_integrator.py create mode 100644 tests/test_simulation_result.py diff --git a/tests/Optica_PM2000D/Optica_PM2000D.toml b/examples/Optica_PM2000D/Optica_PM2000D.toml similarity index 100% rename from tests/Optica_PM2000D/Optica_PM2000D.toml rename to examples/Optica_PM2000D/Optica_PM2000D.toml diff --git a/tests/Optica_PM2000D/PM2000D_2 extrapolated 4 0.npz b/examples/Optica_PM2000D/PM2000D_2 extrapolated 4 0.npz similarity index 100% rename from tests/Optica_PM2000D/PM2000D_2 extrapolated 4 0.npz rename to examples/Optica_PM2000D/PM2000D_2 extrapolated 4 0.npz diff --git a/tests/Optica_PM2000D/PM2000D_A_eff_marcuse.npz b/examples/Optica_PM2000D/PM2000D_A_eff_marcuse.npz similarity index 100% rename from tests/Optica_PM2000D/PM2000D_A_eff_marcuse.npz rename to examples/Optica_PM2000D/PM2000D_A_eff_marcuse.npz diff --git a/tests/Optica_PM2000D/Pos30000New.npz b/examples/Optica_PM2000D/Pos30000New.npz similarity index 100% rename from tests/Optica_PM2000D/Pos30000New.npz rename to examples/Optica_PM2000D/Pos30000New.npz diff --git a/tests/Optica_PM2000D/test_Optica_PM2000D.py b/examples/Optica_PM2000D/test_Optica_PM2000D.py similarity index 100% rename from tests/Optica_PM2000D/test_Optica_PM2000D.py rename to examples/Optica_PM2000D/test_Optica_PM2000D.py diff --git a/tests/Travers/Travers.toml b/examples/Travers/Travers.toml similarity index 100% rename from tests/Travers/Travers.toml rename to examples/Travers/Travers.toml diff --git a/tests/Travers/Travers2019.py b/examples/Travers/Travers2019.py similarity index 100% rename from tests/Travers/Travers2019.py rename to examples/Travers/Travers2019.py diff --git a/examples/test_rate.py b/examples/ion_rate_plot.py similarity index 100% rename from examples/test_rate.py rename to examples/ion_rate_plot.py diff --git a/examples/test_integrator.py b/examples/test_integrator.py deleted file mode 100644 index 575eb62..0000000 --- a/examples/test_integrator.py +++ /dev/null @@ -1,151 +0,0 @@ -from collections import defaultdict - -import matplotlib.pyplot as plt -import numpy as np -import pytest -from scipy.interpolate import interp1d - -import scgenerator as sc -import scgenerator.operators as op -import scgenerator.solver as so - - -def test_rk43_absorbtion_only(): - n = 129 - end = 1.0 - h = 2**-3 - w_c = np.linspace(-5, 5, n) - ind = np.argsort(w_c) - spec0 = np.exp(-(w_c**2)) - init_state = op.SimulationState(spec0, end, h) - - lin = op.envelope_linear_operator( - op.no_op_freq(n), - op.constant_array_operator(np.ones(n) * np.log(2)), - ) - non_lin = op.no_op_freq(n) - - judge = so.adaptive_judge(1e-6, 4) - stepper = so.ERK43(lin, non_lin) - - for state in so.integrate(stepper, init_state, h, judge, max_step_size=0.125): - if state.z >= end: - break - assert np.max(state.spectrum2) == pytest.approx(0.5) - - -def test_rk43_soliton(plot=False): - n = 1024 - b2 = sc.fiber.D_to_beta2(sc.units.D_ps_nm_km(24), 835e-9) - gamma = 0.08 - t0_fwhm = 50e-15 - p0 = 1.26e3 - t0 = sc.pulse.width_to_t0(t0_fwhm, "sech") - print(np.sqrt(t0**2 / np.abs(b2) * gamma * p0)) - - disp_len = t0**2 / np.abs(b2) - end = disp_len * 0.5 * np.pi - targets = np.linspace(0, end, 32) - print(end) - - h = 2**-6 - t = np.linspace(-200e-15, 200e-15, n) - w_c = np.pi * 2 * np.fft.fftfreq(n, t[1] - t[0]) - ind = np.argsort(w_c) - field0 = sc.pulse.sech_pulse(t, t0, p0) - init_state = op.SimulationState(np.fft.fft(field0), end, h) - no_op = op.no_op_freq(n) - - lin = op.envelope_linear_operator( - op.constant_polynomial_dispersion([b2], w_c), - no_op, - # op.constant_array_operator(np.ones(n) * np.log(2)), - ) - non_lin = op.envelope_nonlinear_operator( - op.constant_array_operator(np.ones(n) * gamma), - no_op, - op.envelope_spm(0), - no_op, - ) - - # new_state = init_state.copy() - # plt.plot(t, init_state.field2) - # new_state.set_spectrum(non_lin(init_state)) - # plt.plot(t, new_state.field2) - # new_state.set_spectrum(lin(init_state)) - # plt.plot(t, new_state.field2) - # print(new_state.spectrum2.max()) - # plt.show() - # return - - judge = so.adaptive_judge(1e-6, 4) - stepper = so.ERKIP43Stepper(lin, non_lin) - - # stepper.set_state(init_state) - # state, error = stepper.take_step(init_state, 1e-3, True) - # print(error) - # plt.plot(t, stepper.fine.field2) - # plt.plot(t, stepper.coarse.field2) - # plt.show() - # return - - target = 0 - stats = defaultdict(list) - saved = [] - zs = [] - for state in so.integrate(stepper, init_state, h, judge, max_step_size=0.125): - # print(f"z = {state.z*100:.2f}") - saved.append(state.spectrum2[ind]) - zs.append(state.z) - for k, v in state.stats.items(): - stats[k].append(v) - if state.z > end: - break - print(len(saved)) - if plot: - interp = interp1d(zs, saved, axis=0) - plt.imshow(sc.units.to_log(interp(targets)), origin="lower", aspect="auto", vmin=-40) - plt.show() - - plt.plot(stats["z"][1:], np.diff(stats["z"])) - plt.show() - - -def test_simple_euler(): - n = 129 - end = 1.0 - h = 2**-3 - w_c = np.linspace(-5, 5, n) - ind = np.argsort(w_c) - spec0 = np.exp(-(w_c**2)) - init_state = op.SimulationState(spec0, end, h) - - lin = op.envelope_linear_operator( - op.no_op_freq(n), - op.constant_array_operator(np.ones(n) * np.log(2)), - ) - euler = so.ConstantEuler(lin) - - target = 0 - end = 1.0 - h = 2**-6 - for state in so.integrate(euler, init_state, h): - if state.z >= target: - target += 0.125 - plt.plot(w_c[ind], state.spectrum2[ind], label=f"z={state.z:.3f}") - if target > end: - print(np.max(state.spectrum2)) - break - plt.title(f"{h = }") - plt.legend() - plt.show() - - -def benchmark(): - for _ in range(50): - test_rk43_soliton() - - -if __name__ == "__main__": - test_rk43_soliton() - benchmark() diff --git a/src/scgenerator/solver.py b/src/scgenerator/solver.py index 987a920..f10c951 100644 --- a/src/scgenerator/solver.py +++ b/src/scgenerator/solver.py @@ -1,14 +1,18 @@ from __future__ import annotations +import json +import os import warnings +import zipfile from collections import defaultdict +from pathlib import Path from typing import Any, Iterator, Sequence import numba import numpy as np from scgenerator.math import abs2 -from scgenerator.operators import SpecOperator +from scgenerator.operators import SpecOperator, VariableQuantity from scgenerator.utils import TimedMessage @@ -18,8 +22,15 @@ class SimulationResult: stats: dict[str, list[Any]] z: np.ndarray - def __init__(self, spectra: Sequence[np.ndarray], stats: dict[str, list[Any]]): - if "z" in stats: + def __init__( + self, + spectra: Sequence[np.ndarray], + stats: dict[str, list[Any]], + z: np.ndarray | None = None, + ): + if z is not None: + self.z = z + elif "z" in stats: self.z = np.array(stats["z"]) else: self.z = np.arange(len(spectra), dtype=float) @@ -30,6 +41,29 @@ class SimulationResult: def stat(self, stat_name: str) -> np.ndarray: return np.array(self.stats[stat_name]) + def save(self, path: os.PathLike): + path = Path(path) + if not path.name.endswith(".zip"): + path = path.parent / (path.name + ".zip") + with zipfile.ZipFile(path, "w") as zf: + with zf.open("spectra.npy", "w") as file: + np.save(file, self.spectra) + with zf.open("z.npy", "w") as file: + np.save(file, self.z) + with zf.open("stats.json", "w") as file: + file.write(json.dumps(self.stats).encode()) + + @classmethod + def load(cls, path: os.PathLike): + with zipfile.ZipFile(path, "r") as zf: + with zf.open("spectra.npy", "r") as file: + spectra = np.load(file) + with zf.open("z.npy", "r") as file: + z = np.load(file) + with zf.open("stats.json", "r") as file: + stats = json.loads(file.read().decode()) + return cls(spectra, stats, z) + @numba.jit(nopython=True) def compute_diff(coarse_spec: np.ndarray, fine_spec: np.ndarray) -> float: @@ -82,7 +116,7 @@ def pi_step_factor(error: float, last_error: float, order: int, eps: float = 0.8 def solve43( spec: np.ndarray, - linear: SpecOperator, + linear: VariableQuantity, nonlinear: SpecOperator, z_max: float, atol: float, diff --git a/testing/configs/Chang2011Fig2.toml b/testing/configs/Chang2011Fig2.toml deleted file mode 100644 index 8d4fa7e..0000000 --- a/testing/configs/Chang2011Fig2.toml +++ /dev/null @@ -1,18 +0,0 @@ -name = "/Users/benoitsierro/tests/test_sc/Chang2011Fig2" - -wavelength = 800e-9 -shape = "gaussian" -energy = 2.5e-7 -width = 30e-15 - -core_radius = 10e-6 -model = "marcatili" -gas_name = "argon" -pressure = 3.2e5 - -length = 0.1 -full_field = true -photoionization = false -dt = 0.04e-15 -t_num = 32768 -z_num = 128 diff --git a/testing/configs/compute_init_parameters/good.toml b/testing/configs/compute_init_parameters/good.toml deleted file mode 100644 index 87ffddf..0000000 --- a/testing/configs/compute_init_parameters/good.toml +++ /dev/null @@ -1,26 +0,0 @@ -name = "test config" - -# fiber -# gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -intensity_noise = 0.05e-2 -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 -width = 50e-15 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = false -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 diff --git a/testing/configs/count_variations/120sim_3vary.toml b/testing/configs/count_variations/120sim_3vary.toml deleted file mode 100644 index 0d34ff5..0000000 --- a/testing/configs/count_variations/120sim_3vary.toml +++ /dev/null @@ -1,24 +0,0 @@ -# fiber -core_radius = 50e-6 -length = 50e-2 -model = "marcatili" - -# pulse -peak_power = 100e3 -wavelength = 800e-9 - -# simulation -parallel = true -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# gas.variable -gas_name = ["air", "helium"] -# pulse.variable -width = [250e-15, 240e-15, 230e-15, 220e-15, 210e-15] -# simulation.variable -behaviors = [["spm", "raman", "ss"], ["spm", "raman"], ["spm"]] diff --git a/testing/configs/count_variations/1sim_0vary.toml b/testing/configs/count_variations/1sim_0vary.toml deleted file mode 100644 index c5252bf..0000000 --- a/testing/configs/count_variations/1sim_0vary.toml +++ /dev/null @@ -1,21 +0,0 @@ -# fiber -core_radius = 50e-6 -length = 50e-2 -model = "marcatili" - -# gas -gas_name = "air" - -# pulse -peak_power = 100e3 -wavelength = 800e-9 -width = 250e-15 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -repeat = 1 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 diff --git a/testing/configs/count_variations/1sim_1vary.toml b/testing/configs/count_variations/1sim_1vary.toml deleted file mode 100644 index 8d76982..0000000 --- a/testing/configs/count_variations/1sim_1vary.toml +++ /dev/null @@ -1,22 +0,0 @@ -# fiber -core_radius = 50e-6 -length = 50e-2 -model = "marcatili" - -# gas -gas_name = "air" - -# pulse -peak_power = 100e3 -wavelength = 800e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -repeat = 1 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 -[variable] -width = [250e-15] diff --git a/testing/configs/count_variations/2sim_0vary.toml b/testing/configs/count_variations/2sim_0vary.toml deleted file mode 100644 index 5c8b83c..0000000 --- a/testing/configs/count_variations/2sim_0vary.toml +++ /dev/null @@ -1,21 +0,0 @@ -# fiber -core_radius = 50e-6 -length = 50e-2 -model = "marcatili" - -# gas -gas_name = "air" - -# pulse -peak_power = 100e3 -wavelength = 800e-9 -width = 250e-15 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -repeat = 2 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 diff --git a/testing/configs/count_variations/2sim_1vary.toml b/testing/configs/count_variations/2sim_1vary.toml deleted file mode 100644 index fed14b1..0000000 --- a/testing/configs/count_variations/2sim_1vary.toml +++ /dev/null @@ -1,24 +0,0 @@ -# fiber -core_radius = 50e-6 -length = 50e-2 -model = "marcatili" - -# gas -gas_name = "air" - -# pulse -soliton_num = 5 -wavelength = 800e-9 -width = 250e-15 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -repeat = 1 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -shape = ["gaussian", "sech"] diff --git a/testing/configs/custom_field/init_field.npz b/testing/configs/custom_field/init_field.npz deleted file mode 100644 index e5687ede4877b824bb07085f80f612862c76698a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49656 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 P9q|Yv_K{EiefR$W+Bd-G diff --git a/testing/configs/custom_field/mean_power.toml b/testing/configs/custom_field/mean_power.toml deleted file mode 100644 index 953ec5c..0000000 --- a/testing/configs/custom_field/mean_power.toml +++ /dev/null @@ -1,8 +0,0 @@ -dt = 1e-15 -field_file = "testing/configs/custom_field/init_field.npz" -length = 1 -mean_power = 220e-3 -repetition_rate = 40e6 -t_num = 2048 -wavelength = 1000e-9 -z_num = 32 diff --git a/testing/configs/custom_field/no_change.toml b/testing/configs/custom_field/no_change.toml deleted file mode 100644 index 288b1fb..0000000 --- a/testing/configs/custom_field/no_change.toml +++ /dev/null @@ -1,6 +0,0 @@ -dt = 1e-15 -field_file = "testing/configs/custom_field/init_field.npz" -length = 1 -t_num = 2048 -wavelength = 1000e-9 -z_num = 32 diff --git a/testing/configs/custom_field/peak_power.toml b/testing/configs/custom_field/peak_power.toml deleted file mode 100644 index 5ce44f8..0000000 --- a/testing/configs/custom_field/peak_power.toml +++ /dev/null @@ -1,7 +0,0 @@ -dt = 1e-15 -field_file = "testing/configs/custom_field/init_field.npz" -length = 1 -peak_power = 20000 -t_num = 2048 -wavelength = 1593e-9 -z_num = 32 diff --git a/testing/configs/custom_field/recover1.toml b/testing/configs/custom_field/recover1.toml deleted file mode 100644 index 52400f3..0000000 --- a/testing/configs/custom_field/recover1.toml +++ /dev/null @@ -1,7 +0,0 @@ -dt = 1e-15 -input_transmission = 1 -length = 1 -prev_data_dir = "testing/configs/custom_field/recover_data" -t_num = 2048 -wavelength = 1000e-9 -z_num = 32 diff --git a/testing/configs/custom_field/recover2.toml b/testing/configs/custom_field/recover2.toml deleted file mode 100644 index 853b8ea..0000000 --- a/testing/configs/custom_field/recover2.toml +++ /dev/null @@ -1,7 +0,0 @@ -dt = 1e-15 -input_transmission = 0.9 -length = 1 -prev_data_dir = "testing/configs/custom_field/recover_data" -t_num = 2048 -wavelength = 1000e-9 -z_num = 32 diff --git a/testing/configs/custom_field/wavelength_shift1.toml b/testing/configs/custom_field/wavelength_shift1.toml deleted file mode 100644 index 0c58661..0000000 --- a/testing/configs/custom_field/wavelength_shift1.toml +++ /dev/null @@ -1,20 +0,0 @@ -name = "test config" - -# fiber -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -field_file = "testing/configs/custom_field/init_field.npz" -quantum_noise = false -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -raman_type = "agrawal" -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 diff --git a/testing/configs/custom_field/wavelength_shift2.toml b/testing/configs/custom_field/wavelength_shift2.toml deleted file mode 100644 index d425ebc..0000000 --- a/testing/configs/custom_field/wavelength_shift2.toml +++ /dev/null @@ -1,24 +0,0 @@ -name = "test config" - -# fiber -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -field_file = "testing/configs/custom_field/init_field.npz" -quantum_noise = false - -# simulation -behaviors = ["spm", "raman", "ss"] -interpolation_range = [300e-9, 1900e-9] -raman_type = "agrawal" -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -wavelength = [1050e-9, 1321e-9, 1593e-9] diff --git a/testing/configs/ensure_consistency/bad1.toml b/testing/configs/ensure_consistency/bad1.toml deleted file mode 100644 index 00018c7..0000000 --- a/testing/configs/ensure_consistency/bad1.toml +++ /dev/null @@ -1,30 +0,0 @@ -#t0 or width missing - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] diff --git a/testing/configs/ensure_consistency/bad2.toml b/testing/configs/ensure_consistency/bad2.toml deleted file mode 100644 index 629d4a1..0000000 --- a/testing/configs/ensure_consistency/bad2.toml +++ /dev/null @@ -1,30 +0,0 @@ -#t0, width, peak_power or energy missing - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -soliton_num = [1, 2, 3, 4] diff --git a/testing/configs/ensure_consistency/bad3.toml b/testing/configs/ensure_consistency/bad3.toml deleted file mode 100644 index d18888e..0000000 --- a/testing/configs/ensure_consistency/bad3.toml +++ /dev/null @@ -1,30 +0,0 @@ -# window size or dt missing - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/ensure_consistency/bad4.toml b/testing/configs/ensure_consistency/bad4.toml deleted file mode 100644 index c75ac97..0000000 --- a/testing/configs/ensure_consistency/bad4.toml +++ /dev/null @@ -1,32 +0,0 @@ -#multiple width parameters - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 -width = 120e-15 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/ensure_consistency/bad5.toml b/testing/configs/ensure_consistency/bad5.toml deleted file mode 100644 index dc3e33d..0000000 --- a/testing/configs/ensure_consistency/bad5.toml +++ /dev/null @@ -1,33 +0,0 @@ -# missing capillary_thickness - -name = "test config" - -# fiber -capillary_num = 6 -capillary_outer_d = 2e-6 -capillary_spacing = 4e-6 -core_radius = 50e-6 -gamma = 0.018 -length = 1 -model = "hasan" - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/ensure_consistency/bad6.toml b/testing/configs/ensure_consistency/bad6.toml deleted file mode 100644 index e38caf3..0000000 --- a/testing/configs/ensure_consistency/bad6.toml +++ /dev/null @@ -1,32 +0,0 @@ -# missing capillary_outer_d and capillary_spacing - -name = "test config" - -# fiber -capillary_num = 6 -capillary_thickness = 4e-6 -core_radius = 50e-6 -gamma = 0.018 -length = 1 -model = "hasan" - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/ensure_consistency/good1.toml b/testing/configs/ensure_consistency/good1.toml deleted file mode 100644 index 03c0082..0000000 --- a/testing/configs/ensure_consistency/good1.toml +++ /dev/null @@ -1,31 +0,0 @@ -# model 'pcf' should be added and no gas dico - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/ensure_consistency/good2.toml b/testing/configs/ensure_consistency/good2.toml deleted file mode 100644 index ad38cda..0000000 --- a/testing/configs/ensure_consistency/good2.toml +++ /dev/null @@ -1,30 +0,0 @@ -# raman_type should be added - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/ensure_consistency/good3.toml b/testing/configs/ensure_consistency/good3.toml deleted file mode 100644 index 1e5c77c..0000000 --- a/testing/configs/ensure_consistency/good3.toml +++ /dev/null @@ -1,29 +0,0 @@ -# name should be added - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/ensure_consistency/good4.toml b/testing/configs/ensure_consistency/good4.toml deleted file mode 100644 index 4c842f0..0000000 --- a/testing/configs/ensure_consistency/good4.toml +++ /dev/null @@ -1,38 +0,0 @@ -# should add capillary_nested and capillary_resonance_strengths - -name = "test config" - -# fiber -capillary_num = 6 -capillary_outer_d = 2e-6 -capillary_spacing = 4e-6 -capillary_thickness = 1e-7 -core_radius = 50e-6 -length = 1 -model = "hasan" - -# gas -gas_name = "helium" - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# gas.variable -temperature = [300, 350, 400] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/ensure_consistency/good5.toml b/testing/configs/ensure_consistency/good5.toml deleted file mode 100644 index 29cf7dc..0000000 --- a/testing/configs/ensure_consistency/good5.toml +++ /dev/null @@ -1,30 +0,0 @@ -# should add he_mode and gas - -name = "test config" - -# fiber -core_radius = 50e-6 -gamma = 0.018 -length = 1 -model = "marcatili" - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/ensure_consistency/good6.toml b/testing/configs/ensure_consistency/good6.toml deleted file mode 100644 index b297d15..0000000 --- a/testing/configs/ensure_consistency/good6.toml +++ /dev/null @@ -1,32 +0,0 @@ -# should not touch simulation parameters -# should add wavelength ranges - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/override/fiber2.toml b/testing/configs/override/fiber2.toml deleted file mode 100644 index 64d062b..0000000 --- a/testing/configs/override/fiber2.toml +++ /dev/null @@ -1,23 +0,0 @@ -name = "fiber 2" - -# fiber -beta2_coefficients = [ - -1.183e-26, - 8.1038e-41, - -9.5205e-56, - 2.0737e-70, - -5.3943e-85, - 1.3486e-99, - -2.5495e-114, - 3.0524e-129, - -1.714e-144, -] -gamma = 0.13 -length = 0.05 -model = "custom" - -# simulation -z_num = 16 -[variable] -# fiber.variable -input_transmission = [0.9, 0.95] diff --git a/testing/configs/override/initial_config.toml b/testing/configs/override/initial_config.toml deleted file mode 100644 index 0281a76..0000000 --- a/testing/configs/override/initial_config.toml +++ /dev/null @@ -1,42 +0,0 @@ -name = "full anomalous" - -# fiber -beta2_coefficients = [ - -1.183e-26, - 8.1038e-41, - -9.5205e-56, - 2.0737e-70, - -5.3943e-85, - 1.3486e-99, - -2.5495e-114, - 3.0524e-129, - -1.714e-144, -] -gamma = 0.11 -input_transmission = 1.0 -length = 0.02 -model = "custom" - -# pulse -intensity_noise = 0 -peak_power = 10000 -quantum_noise = false -shape = "gaussian" -t0 = 2.84e-14 - -# simulation -behaviors = ["spm", "ss"] -dt = 1e-15 -frep = 80000000.0 -ideal_gas = false -interpolation_range = [3e-7, 1.9e-6] -parallel = true -raman_type = "measured" -repeat = 3 -t_num = 16384 -tolerated_error = 1e-9 -z_num = 64 - -[variable] -# pulse.variable -wavelength = [8.35e-7, 8.3375e-7] diff --git a/testing/configs/param_sequence/almost_equal.toml b/testing/configs/param_sequence/almost_equal.toml deleted file mode 100644 index ee11027..0000000 --- a/testing/configs/param_sequence/almost_equal.toml +++ /dev/null @@ -1,30 +0,0 @@ -# raman_type should be added - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 -width = 50e-15 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.10000000005e-2, 0.1e-2] diff --git a/testing/configs/param_sequence/equal.toml b/testing/configs/param_sequence/equal.toml deleted file mode 100644 index f054c62..0000000 --- a/testing/configs/param_sequence/equal.toml +++ /dev/null @@ -1,30 +0,0 @@ -# raman_type should be added - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 -width = 50e-15 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.1e-2, 0.001] diff --git a/testing/configs/param_sequence/no_variations.toml b/testing/configs/param_sequence/no_variations.toml deleted file mode 100644 index 5abb35d..0000000 --- a/testing/configs/param_sequence/no_variations.toml +++ /dev/null @@ -1,27 +0,0 @@ -# raman_type should be added - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -intensity_noise = 0.1e-2 -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 -width = 50e-15 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 diff --git a/testing/configs/run_simulations/full_anomalous.toml b/testing/configs/run_simulations/full_anomalous.toml deleted file mode 100644 index ca2d6cd..0000000 --- a/testing/configs/run_simulations/full_anomalous.toml +++ /dev/null @@ -1,33 +0,0 @@ -nam)e = "full anomalous" - -# fiber -beta2_coefficients = [ - -1.183e-26, - 8.1038e-41, - -9.5205e-56, - 2.0737e-70, - -5.3943e-85, - 1.3486e-99, - -2.5495e-114, - 3.0524e-129, - -1.714e-144, -] -gamma = 0.11 -length = 0.02 - -# pulse -peak_power = 10000 -t0 = 2.84e-14 - -# simulation -dt = 1e-15 -parallel = true -raman_type = "measured" -repeat = 4 -t_num = 16384 -tolerated_error = 1e-10 -z_num = 64 - -[variable] -# pulse.variable -wavelength = [835e-9, 830e-9] diff --git a/testing/configs/validate_types/bad1.toml b/testing/configs/validate_types/bad1.toml deleted file mode 100644 index 334f706..0000000 --- a/testing/configs/validate_types/bad1.toml +++ /dev/null @@ -1,31 +0,0 @@ -# pitch in wrong section - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -pitch = 1.5e-6 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/validate_types/bad2.toml b/testing/configs/validate_types/bad2.toml deleted file mode 100644 index bf7f2ab..0000000 --- a/testing/configs/validate_types/bad2.toml +++ /dev/null @@ -1,31 +0,0 @@ -# wrong value in behaviors - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss", "q_noise"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/validate_types/bad3.toml b/testing/configs/validate_types/bad3.toml deleted file mode 100644 index c37ebcf..0000000 --- a/testing/configs/validate_types/bad3.toml +++ /dev/null @@ -1,31 +0,0 @@ -# wrong type in width - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = ["gaussian", "sech"] diff --git a/testing/configs/validate_types/bad4.toml b/testing/configs/validate_types/bad4.toml deleted file mode 100644 index c244854..0000000 --- a/testing/configs/validate_types/bad4.toml +++ /dev/null @@ -1,32 +0,0 @@ -# parallel should not be variable - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 1 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] -# simulation.variable -parallel = [true, false] diff --git a/testing/configs/validate_types/bad5.toml b/testing/configs/validate_types/bad5.toml deleted file mode 100644 index b5bd4c2..0000000 --- a/testing/configs/validate_types/bad5.toml +++ /dev/null @@ -1,31 +0,0 @@ -#variable parameters should be lists - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = 0.05e-2 -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/validate_types/bad6.toml b/testing/configs/validate_types/bad6.toml deleted file mode 100644 index 073b014..0000000 --- a/testing/configs/validate_types/bad6.toml +++ /dev/null @@ -1,31 +0,0 @@ -#repeat should not be 0 - -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -intensity_noise = 0.05e-2 -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 0 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/validate_types/bad7.toml b/testing/configs/validate_types/bad7.toml deleted file mode 100644 index 09754ac..0000000 --- a/testing/configs/validate_types/bad7.toml +++ /dev/null @@ -1,29 +0,0 @@ -# gamma missing - -name = "test config" - -# fiber -beta2_coefficients = [1, 2, 3] -gamma = 0.018 -length = 1 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/configs/validate_types/good.toml b/testing/configs/validate_types/good.toml deleted file mode 100644 index 0452231..0000000 --- a/testing/configs/validate_types/good.toml +++ /dev/null @@ -1,29 +0,0 @@ -name = "test config" - -# fiber -gamma = 0.018 -length = 1 -model = "pcf" -pitch = 1.5e-6 -pitch_ratio = 0.37 - -# pulse -peak_power = 100e3 -quantum_noise = true -shape = "gaussian" -wavelength = 1050e-9 - -# simulation -behaviors = ["spm", "raman", "ss"] -parallel = true -raman_type = "agrawal" -repeat = 4 -t_num = 16384 -time_window = 37e-12 -tolerated_error = 1e-11 -z_num = 128 - -[variable] -# pulse.variable -intensity_noise = [0.05e-2, 0.1e-2] -width = [50e-15, 100e-15, 200e-15] diff --git a/testing/test_all_zeros.py b/testing/test_all_zeros.py deleted file mode 100644 index b39b86e..0000000 --- a/testing/test_all_zeros.py +++ /dev/null @@ -1,16 +0,0 @@ -from scgenerator.math import all_zeros -import matplotlib.pyplot as plt -import numpy as np - - -def main(): - x = np.linspace(-10, 10, 30) - y = np.sin(x) - z = all_zeros(x, y) - plt.plot(x, y) - plt.plot(z, z * 0, ls="", marker="o") - plt.show() - - -if __name__ == "__main__": - main() diff --git a/testing/test_cache.py b/testing/test_cache.py deleted file mode 100644 index e69de29..0000000 diff --git a/testing/test_env.py b/testing/test_env.py deleted file mode 100644 index e69de29..0000000 diff --git a/testing/test_evaluator.py b/testing/test_evaluator.py deleted file mode 100644 index e69de29..0000000 diff --git a/testing/test_full_field.py b/testing/test_full_field.py deleted file mode 100644 index f48cf36..0000000 --- a/testing/test_full_field.py +++ /dev/null @@ -1,55 +0,0 @@ -import scgenerator as sc -from customfunc.app import PlotApp -from tqdm import tqdm - -# warnings.filterwarnings("error") - - -def get_specs(params: dict): - p = sc.Parameters(**params) - sim = sc.RK4IP(p) - return [s.actual_spectrum for _, s in tqdm(sim.irun(), total=p.z_num)], p.dump_dict() - - -def main(): - - params = sc.Parameters.load("testing/configs/Chang2011Fig2.toml") - specs, params = get_specs(params.dump_dict(add_metadata=False)) - params = sc.Parameters(**params) - rs = sc.PlotRange(100, 1500, "nm") - rt = sc.PlotRange(-500, 500, "fs") - x, o, ext = rs.sort_axis(params.w) - vmin = -50 - with PlotApp(i=range(params.z_num)) as app: - spec_ax = app[0] - spec_ax.set_xlabel(rs.unit.label) - field_ax = app[1] - field_ax.set_xlabel(rt.unit.label) - - @app.update - def draw(i): - spec, *fields = compute(i) - spec_ax.set_line_data("spec", *spec, label=f"z = {params.z_targets[i]*1e2:.0f}cm") - for label, x, y in fields: - field_ax.set_line_data(label, x, y) - - print(params) - - @app.cache - def compute(i): - xt, field = sc.transform_1D_values(params.ifft(specs[i]), rt, params=params) - x, spec = sc.transform_1D_values(sc.abs2(specs[i]), rs, params=params, log=True) - # spec = np.where(spec > vmin, spec, vmin) - field2 = sc.abs2(field) - bot, top = sc.math.envelope_ind(field2) - return (x, spec), ("field^2", xt, field2), ("envelope", xt[top], field2[top]) - - # bot, top = sc.math.envelope_ind(field) - # bot = interp1d(xt[bot], field[bot], "cubic", bounds_error=False, fill_value=0)(xt) - # top = interp1d(xt[top], field[top], "cubic", bounds_error=False, fill_value=0)(xt) - - # return ((x, spec), ("upper", xt, top), ("field", xt, field), ("lower", xt, bot)) - - -if __name__ == "__main__": - main() diff --git a/testing/test_legacy.py b/testing/test_legacy.py deleted file mode 100644 index e69de29..0000000 diff --git a/testing/test_logger.py b/testing/test_logger.py deleted file mode 100644 index e69de29..0000000 diff --git a/testing/test_math.py b/testing/test_math.py deleted file mode 100644 index bd3fbd2..0000000 --- a/testing/test_math.py +++ /dev/null @@ -1,134 +0,0 @@ -from math import factorial - -import numpy as np -import pytest - -import scgenerator.math as m - - -def test__power_fact_array(): - x = np.random.rand(5) - for i in range(5): - assert m._power_fact_array(x, i) == pytest.approx(x**i / factorial(i)) - - -def test__power_fact_single(): - pass - - -def test_abs2(): - x = np.random.rand(5) - assert m.abs2(5) == 25 - assert m.abs2(2 - 2j) == 8 - assert all(m.abs2(x) == abs(x) ** 2) - - -def test_all_zeros(): - x = np.geomspace(0.1, 1, 100) - y = np.sin(1 / x) - target = [1 / (3 * np.pi), 1 / (2 * np.pi), 1 / np.pi] - assert m.all_zeros(x, y) == pytest.approx(target, abs=1e-4) - - x = np.array([0, 1]) - y = np.array([-1, 1]) - assert all(m.all_zeros(x, y) == np.array([0.5])) - - x = np.array([0, 1]) - y = np.array([1, 1]) - assert len(m.all_zeros(x, y)) == 0 - - -def test_argclosest(): - pass - - -def test_build_sim_grid(): - pass - - -def test_indft(): - pass - - -def test_indft_matrix(): - pass - - -def test_jn_zeros(): - pass - - -def test_length(): - pass - - -def test_ndft(): - pass - - -def test_ndft_matrix(): - pass - - -def test_np_cache(): - pass - - -def test_power_fact(): - pass - - -def test_sigmoid(): - pass - - -def test_span(): - pass - - -def test_tspace(): - pass - - -def test_u_nm(): - pass - - -def test_update_frequency_domain(): - pass - - -def test_wspace(): - pass - - -def test_differentiate(): - x = np.linspace(-10, 10, 256) - y = np.exp(-((x / 3) ** 2)) * (1 + 0.2 * np.sin(x * 5)) - - y[100] = 1e4 - # true = np.exp(-(x/3)**2) * (x*(-0.4/9 * np.sin(5*x) - 2/9) + np.cos(5*x)) - true = np.exp(-((x / 3) ** 2)) * ( - x**2 * (0.00987654321 * np.sin(5 * x) + 0.0493827) - - 5.044444 * np.sin(5 * x) - - 0.44444 * x * np.cos(5 * x) - - 0.2222222 - ) - - import matplotlib.pyplot as plt - - h = x[1] - x[0] - - grad = np.gradient(np.gradient(y)) / h**2 - fine = m.differentiate_arr(y, 2, 6) / h**2 - - plt.plot(x, y) - plt.plot(x, grad, label="gradient") - plt.plot(x, fine, label="fine") - plt.plot(x, true, label="ture", ls=":") - plt.legend() - plt.show() - - -if __name__ == "__main__": - test_differentiate() diff --git a/testing/test_operators.py b/testing/test_operators.py deleted file mode 100644 index e69de29..0000000 diff --git a/testing/test_parameter.py b/testing/test_parameter.py deleted file mode 100644 index e69de29..0000000 diff --git a/testing/test_pbar.py b/testing/test_pbar.py deleted file mode 100644 index e69de29..0000000 diff --git a/testing/test_plotting.py b/testing/test_plotting.py deleted file mode 100644 index e69de29..0000000 diff --git a/testing/test_resonance.py b/testing/test_resonance.py deleted file mode 100644 index decc552..0000000 --- a/testing/test_resonance.py +++ /dev/null @@ -1,21 +0,0 @@ -import numpy as np -import scgenerator as sc -import matplotlib.pyplot as plt - - -def main(): - capillary_thickness = 1.4e-6 - wl = np.linspace(200e-9, 2000e-9, 500) - n_gas_2 = sc.materials.n_gas_2(wl, "air", 3e5, 300) - resonances = [] - for i in range(5): - t = sc.fiber.resonance_thickness(wl, i, n_gas_2, 40e-6) - resonances += list(1e9 * sc.math.all_zeros(wl, t - capillary_thickness)) - plt.plot(1e9 * wl, 1e6 * t) - plt.xlabel("nm") - plt.ylabel("μm") - plt.show() - - -if __name__ == "__main__": - main() diff --git a/testing/test_spectra.py b/testing/test_spectra.py deleted file mode 100644 index e69de29..0000000 diff --git a/testing/test_utils.py b/testing/test_utils.py deleted file mode 100644 index e69de29..0000000 diff --git a/testing/test_variationer.py b/testing/test_variationer.py deleted file mode 100644 index 67033e2..0000000 --- a/testing/test_variationer.py +++ /dev/null @@ -1,54 +0,0 @@ -from pydantic import main -import scgenerator as sc - - -def test_descriptor(): - # Same branch - var1 = sc.VariationDescriptor( - raw_descr=[[("num", 1), ("a", False)], [("b", 0)]], index=[[1, 0], [0]] - ) - var2 = sc.VariationDescriptor( - raw_descr=[[("num", 2), ("a", False)], [("b", 0)]], index=[[1, 0], [0]] - ) - assert var1.branch.identifier == "b_0" - assert var1.identifier != var1.branch.identifier - assert var1.identifier != var2.identifier - assert var1.branch.identifier == var2.branch.identifier - - # different branch - var3 = sc.VariationDescriptor( - raw_descr=[[("num", 2), ("a", True)], [("b", 0)]], index=[[1, 0], [0]] - ) - assert var1.branch.identifier != var3.branch.identifier - assert var1.formatted_descriptor() != var2.formatted_descriptor() - assert var1.formatted_descriptor() != var3.formatted_descriptor() - - -def test_variationer(): - var = sc.Variationer( - [ - dict(a=[1, 2], num=[0, 1, 2]), - [dict(b=["000", "111"], c=["a", "-1"])], - dict(), - dict(), - [dict(aaa=[True, False], bb=[1, 3])], - ] - ) - assert var.var_num(0) == 6 - assert var.var_num(1) == 12 - assert var.var_num() == 24 - - cfg = dict(bb=None) - branches = set() - for descr in var.iterate(): - assert descr.update_config(cfg).items() >= set(descr.raw_descr[-1]) - branches.add(descr.branch.identifier) - assert len(branches) == 8 - - -def main(): - test_descriptor() - - -if __name__ == "__main__": - main() diff --git a/testing/test_vincetti.py b/testing/test_vincetti.py deleted file mode 100644 index 1a1bfa5..0000000 --- a/testing/test_vincetti.py +++ /dev/null @@ -1,21 +0,0 @@ -import matplotlib.pyplot as plt -import numpy as np - -import scgenerator as sc - -wl = np.linspace(200e-9, 2e-6, 2048) -w = sc.units.m(wl) -wl0 = 800e-9 -gas = sc.materials.Gas("argon") -ng2 = gas.sellmeier.n_gas_2(wl, pressure=1e5) - -n = sc.fiber.n_eff_vincetti(wl, wl0, ng2, 1e-6, 20e-6, 5e-6, 7) -b2 = sc.fiber.beta2(w, n) - -bcap = sc.capillary_dispersion( - wl, sc.fiber.core_radius_from_capillaries(20e-6, 5e-6, 7), "argon", pressure=1e5 -) - -plt.plot(wl, b2) -plt.plot(wl, bcap) -plt.show() diff --git a/tests/test_current_state.py b/tests/test_current_state.py deleted file mode 100644 index 300d2b2..0000000 --- a/tests/test_current_state.py +++ /dev/null @@ -1,31 +0,0 @@ -import numpy as np -import pytest - -from scgenerator.operators import SimulationState - - -def test_creation(): - x = np.linspace(0, 1, 128, dtype=complex) - cs = SimulationState(1.0, 0, 0.1, x, 1.0) - - assert cs.converter is np.fft.ifft - assert cs.stats == {} - assert np.allclose(cs.field2, np.abs(np.fft.ifft(x)) ** 2) - - with pytest.raises(ValueError): - cs = SimulationState(1.0, 0, 0.0, x, 1.0, spectrum2=np.abs(x) ** 3) - - cs = SimulationState(1.0, 0, 0.1, x, 1.0, spectrum2=x.copy(), field=x.copy(), field2=x.copy()) - - assert np.allclose(cs.spectrum2, cs.spectrum) - assert np.allclose(cs.spectrum, cs.field) - assert np.allclose(cs.field, cs.field2) - - -def test_copy(): - x = np.linspace(0, 1, 128, dtype=complex) - start = SimulationState(1.0, 0, 0.1, x, 1.0) - end = start.copy() - - assert start.spectrum is not end.spectrum - assert np.all(start.field2 == end.field2) diff --git a/tests/test_integrator.py b/tests/test_integrator.py new file mode 100644 index 0000000..1eef14d --- /dev/null +++ b/tests/test_integrator.py @@ -0,0 +1,87 @@ +import matplotlib.pyplot as plt +import numpy as np +import pytest + +import scgenerator as sc +import scgenerator.operators as op + + +def test_rk43_absorbtion_only(): + n = 129 + w_c = np.linspace(-5, 5, n) + spec0 = np.exp(-(w_c**2)) + + lin = op.envelope_linear_operator( + op.constant_quantity(np.zeros(n)), + op.constant_quantity(np.ones(n) * np.log(2)), + ) + non_lin = op.no_op_freq(n) + + res = sc.integrate(spec0, 1.0, lin, non_lin, targets=[1.0]) + assert np.max(sc.abs2(res.spectra[-1])) == pytest.approx(0.5) + + +def test_rk43_soliton(plot=False): + """ + create a N=3 soliton and test that the spectrum at after one oscillation goes back to the same + maximum value + """ + n = 1024 + l0 = 835e-9 + w0 = sc.units.m(l0) + b2 = sc.fiber.D_to_beta2(sc.units.D_ps_nm_km(24), l0) + gamma = 0.08 + t0_fwhm = 50e-15 + p0 = 1.26e3 + t0 = sc.pulse.width_to_t0(t0_fwhm, "sech") + soliton_num = 3 + p0 = soliton_num**2 * np.abs(b2) / (gamma * t0**2) + + disp_len = t0**2 / np.abs(b2) + end = disp_len * 0.5 * np.pi + targets = np.linspace(0, end, 64) + + t = np.linspace(-200e-15, 200e-15, n) + w_c = np.pi * 2 * np.fft.fftfreq(n, t[1] - t[0]) + field0 = sc.pulse.sech_pulse(t, t0, p0) + spec0 = np.fft.fft(field0) + no_op = op.no_op_freq(n) + + lin = op.envelope_linear_operator( + op.constant_polynomial_dispersion([b2], w_c), + op.constant_quantity(np.zeros(n)), + ) + non_lin = op.envelope_nonlinear_operator( + op.constant_quantity(np.ones(n) * gamma), + op.constant_quantity(np.zeros(n)), + op.envelope_spm(0), + no_op, + ) + + res = sc.integrate(spec0, end, lin, non_lin, targets=targets, atol=1e-10, rtol=1e-9) + if plot: + x, y, z = sc.plotting.transform_2D_propagation( + res.spectra, + sc.PlotRange(500, 1300, "nm"), + w_c + w0, + targets, + ) + plt.imshow(z, extent=sc.plotting.get_extent(x, y), origin="lower", aspect="auto", vmin=-40) + plt.show() + + plt.plot(sc.abs2(spec0)) + plt.plot(sc.abs2(res.spectra[-1])) + plt.yscale("log") + plt.show() + + assert sc.abs2(spec0).max() == pytest.approx(sc.abs2(res.spectra[-1]).max(), rel=0.01) + + +def benchmark(): + for _ in range(50): + test_rk43_soliton() + + +if __name__ == "__main__": + test_rk43_soliton() + benchmark() diff --git a/tests/test_simulation_result.py b/tests/test_simulation_result.py new file mode 100644 index 0000000..4cc628f --- /dev/null +++ b/tests/test_simulation_result.py @@ -0,0 +1,17 @@ +from pathlib import Path + +import numpy as np + +from scgenerator.solver import SimulationResult + + +def test_load_save(tmp_path: Path): + sim = SimulationResult( + np.random.randint(0, 20, (5, 5)), dict(a=[], b=[1, 2, 3], z=list(range(32))) + ) + sim.save(tmp_path / "mysim") + sim2 = SimulationResult.load(tmp_path / "mysim.zip") + assert np.all(sim2.spectra == sim.spectra) + assert np.all(sim2.z == sim.z) + for k, v in sim.stats.items(): + assert sim2.stats[k] == v