better np hash, Fiber always array, resonance
This commit is contained in:
@@ -153,6 +153,9 @@ capillary_spacing : float, optional if d is specified
|
|||||||
capillary_resonance_strengths : list, optional
|
capillary_resonance_strengths : list, optional
|
||||||
list of resonance strengths. Default is []
|
list of resonance strengths. Default is []
|
||||||
|
|
||||||
|
capillary_resonance_max_order : int, optional
|
||||||
|
max order of resonance strengths to be deduced
|
||||||
|
|
||||||
capillary_nested : int, optional
|
capillary_nested : int, optional
|
||||||
how many nested capillaries. Default is 0
|
how many nested capillaries. Default is 0
|
||||||
|
|
||||||
|
|||||||
@@ -7,28 +7,23 @@ scgenerator module but some function may be used in any python program
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
import multiprocessing
|
|
||||||
import os
|
import os
|
||||||
import random
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
import threading
|
|
||||||
from collections import abc
|
from collections import abc
|
||||||
from io import StringIO
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from string import printable as str_printable
|
from string import printable as str_printable
|
||||||
from functools import cache
|
from functools import cache
|
||||||
from typing import Any, Callable, Generator, Iterable, MutableMapping, Sequence, TypeVar, Union
|
from typing import Any, MutableMapping, Sequence, TypeVar
|
||||||
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from numpy.lib.arraysetops import isin
|
||||||
import pkg_resources as pkg
|
import pkg_resources as pkg
|
||||||
import toml
|
import toml
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
import itertools
|
||||||
|
|
||||||
from .pbar import PBars
|
|
||||||
from ..const import PARAM_FN, PARAM_SEPARATOR, SPEC1_FN, SPECN_FN1, Z_FN, __version__
|
from ..const import SPEC1_FN, __version__
|
||||||
from ..env import pbar_policy
|
|
||||||
from ..logger import get_logger
|
from ..logger import get_logger
|
||||||
|
|
||||||
T_ = TypeVar("T_")
|
T_ = TypeVar("T_")
|
||||||
@@ -95,11 +90,11 @@ def load_spectrum(file: os.PathLike) -> np.ndarray:
|
|||||||
return np.load(file)
|
return np.load(file)
|
||||||
|
|
||||||
|
|
||||||
def conform_toml_path(path: os.PathLike) -> str:
|
def conform_toml_path(path: os.PathLike) -> Path:
|
||||||
path: str = str(path)
|
path: str = str(path)
|
||||||
if not path.lower().endswith(".toml"):
|
if not path.lower().endswith(".toml"):
|
||||||
path = path + ".toml"
|
path = path + ".toml"
|
||||||
return path
|
return Path(path)
|
||||||
|
|
||||||
|
|
||||||
def open_single_config(path: os.PathLike) -> dict[str, Any]:
|
def open_single_config(path: os.PathLike) -> dict[str, Any]:
|
||||||
@@ -116,13 +111,20 @@ def _open_config(path: os.PathLike):
|
|||||||
path = conform_toml_path(path)
|
path = conform_toml_path(path)
|
||||||
dico = resolve_loadfile_arg(load_toml(path))
|
dico = resolve_loadfile_arg(load_toml(path))
|
||||||
|
|
||||||
dico.setdefault("variable", {})
|
dico = standardize_variable_dicts(dico)
|
||||||
for key in {"simulation", "fiber", "gas", "pulse"} & dico.keys():
|
if "Fiber" not in dico:
|
||||||
section = dico.pop(key)
|
dico = dict(name=path.name, Fiber=[dico])
|
||||||
dico["variable"].update(section.pop("variable", {}))
|
return dico
|
||||||
dico.update(section)
|
|
||||||
if len(dico["variable"]) == 0:
|
|
||||||
dico.pop("variable")
|
def standardize_variable_dicts(dico: dict[str, Any]):
|
||||||
|
if "Fiber" in dico:
|
||||||
|
dico["Fiber"] = [standardize_variable_dicts(fiber) for fiber in dico["Fiber"]]
|
||||||
|
if (var := dico.get("variable")) is not None:
|
||||||
|
if isinstance(var, MutableMapping):
|
||||||
|
dico["variable"] = [var]
|
||||||
|
else:
|
||||||
|
dico["variable"] = [{}]
|
||||||
return dico
|
return dico
|
||||||
|
|
||||||
|
|
||||||
@@ -194,14 +196,18 @@ def load_config_sequence(path: os.PathLike) -> tuple[Path, list[dict[str, Any]]]
|
|||||||
final_path = loaded_config.get("name")
|
final_path = loaded_config.get("name")
|
||||||
configs = []
|
configs = []
|
||||||
for i, params in enumerate(fiber_list):
|
for i, params in enumerate(fiber_list):
|
||||||
params.setdefault("variable", {})
|
|
||||||
configs.append(loaded_config | params)
|
configs.append(loaded_config | params)
|
||||||
configs[0]["variable"] = loaded_config.get("variable", {}) | configs[0]["variable"]
|
for root_vary, first_vary in itertools.product(
|
||||||
configs[0]["variable"]["num"] = list(range(configs[0].get("repeat", 1)))
|
loaded_config["variable"], configs[0]["variable"]
|
||||||
|
):
|
||||||
|
if len(common := root_vary.keys() & first_vary.keys()) != 0:
|
||||||
|
raise ValueError(f"These variable keys are specified twice : {common!r}")
|
||||||
|
configs[0] |= {k: v for k, v in loaded_config.items() if k != "variable"}
|
||||||
|
configs[0]["variable"].append(dict(num=list(range(configs[0].get("repeat", 1)))))
|
||||||
return Path(final_path), configs
|
return Path(final_path), configs
|
||||||
|
|
||||||
|
|
||||||
|
@cache
|
||||||
def load_material_dico(name: str) -> dict[str, Any]:
|
def load_material_dico(name: str) -> dict[str, Any]:
|
||||||
"""loads a material dictionary
|
"""loads a material dictionary
|
||||||
Parameters
|
Parameters
|
||||||
|
|||||||
@@ -6,6 +6,14 @@ import numpy as np
|
|||||||
CacheInfo = namedtuple("CacheInfo", "hits misses size")
|
CacheInfo = namedtuple("CacheInfo", "hits misses size")
|
||||||
|
|
||||||
|
|
||||||
|
def make_arg_hashable(arg):
|
||||||
|
if isinstance(arg, np.ndarray):
|
||||||
|
return arg.tobytes()
|
||||||
|
elif isinstance(arg, list):
|
||||||
|
return tuple(make_arg_hashable(a) for a in arg)
|
||||||
|
return arg
|
||||||
|
|
||||||
|
|
||||||
def np_cache(func):
|
def np_cache(func):
|
||||||
def new_cached_func():
|
def new_cached_func():
|
||||||
cache = {}
|
cache = {}
|
||||||
@@ -14,15 +22,8 @@ def np_cache(func):
|
|||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapped(*args, **kwargs):
|
def wrapped(*args, **kwargs):
|
||||||
nonlocal cache, hits, misses
|
nonlocal cache, hits, misses
|
||||||
hashable_args = tuple(
|
hashable_args = tuple(make_arg_hashable(a) for a in args)
|
||||||
tuple(arg) if isinstance(arg, (np.ndarray, list)) else arg for arg in args
|
hashable_kwargs = tuple({k: make_arg_hashable(a) for k, a in kwargs.items()}.items())
|
||||||
)
|
|
||||||
hashable_kwargs = tuple(
|
|
||||||
{
|
|
||||||
k: tuple(kwarg) if isinstance(kwarg, (np.ndarray, list)) else kwarg
|
|
||||||
for k, kwarg in kwargs.items()
|
|
||||||
}.items()
|
|
||||||
)
|
|
||||||
key = hash((hashable_args, hashable_kwargs))
|
key = hash((hashable_args, hashable_kwargs))
|
||||||
if key not in cache:
|
if key not in cache:
|
||||||
misses += 1
|
misses += 1
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ VALID_VARIABLE = {
|
|||||||
"capillary_thickness",
|
"capillary_thickness",
|
||||||
"capillary_spacing",
|
"capillary_spacing",
|
||||||
"capillary_resonance_strengths",
|
"capillary_resonance_strengths",
|
||||||
|
"capillary_resonance_max_order",
|
||||||
"capillary_nested",
|
"capillary_nested",
|
||||||
"he_mode",
|
"he_mode",
|
||||||
"fit_parameters",
|
"fit_parameters",
|
||||||
@@ -377,7 +378,10 @@ class Parameters(_AbstractParameters):
|
|||||||
capillary_radius: float = Parameter(in_range_excl(0, 1e-3))
|
capillary_radius: float = Parameter(in_range_excl(0, 1e-3))
|
||||||
capillary_thickness: float = Parameter(in_range_excl(0, 1e-3))
|
capillary_thickness: float = Parameter(in_range_excl(0, 1e-3))
|
||||||
capillary_spacing: float = Parameter(in_range_excl(0, 1e-3))
|
capillary_spacing: float = Parameter(in_range_excl(0, 1e-3))
|
||||||
capillary_resonance_strengths: Iterable[float] = Parameter(num_list, default=[])
|
capillary_resonance_strengths: Iterable[float] = Parameter(
|
||||||
|
validator_list(type_checker(int, float, np.ndarray))
|
||||||
|
)
|
||||||
|
capillary_resonance_max_order: int = Parameter(non_negative(int), default=0)
|
||||||
capillary_nested: int = Parameter(non_negative(int), default=0)
|
capillary_nested: int = Parameter(non_negative(int), default=0)
|
||||||
|
|
||||||
# gas
|
# gas
|
||||||
@@ -468,12 +472,12 @@ class Parameters(_AbstractParameters):
|
|||||||
param_dict = {k: v for k, v in asdict(self).items() if v is not None}
|
param_dict = {k: v for k, v in asdict(self).items() if v is not None}
|
||||||
evaluator = Evaluator.default()
|
evaluator = Evaluator.default()
|
||||||
evaluator.set(**param_dict)
|
evaluator.set(**param_dict)
|
||||||
for p_name in to_compute:
|
results = [evaluator.compute(p_name) for p_name in to_compute]
|
||||||
evaluator.compute(p_name)
|
|
||||||
valid_fields = self.all_parameters()
|
valid_fields = self.all_parameters()
|
||||||
for k, v in evaluator.params.items():
|
for k, v in evaluator.params.items():
|
||||||
if k in valid_fields:
|
if k in valid_fields:
|
||||||
setattr(self, k, v)
|
setattr(self, k, v)
|
||||||
|
return results
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def all_parameters(cls) -> list[str]:
|
def all_parameters(cls) -> list[str]:
|
||||||
@@ -481,7 +485,7 @@ class Parameters(_AbstractParameters):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, path: os.PathLike) -> "Parameters":
|
def load(cls, path: os.PathLike) -> "Parameters":
|
||||||
return cls(**utils._open_config(path))
|
return cls(**utils.load_toml(path))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_and_compute(cls, path: os.PathLike) -> "Parameters":
|
def load_and_compute(cls, path: os.PathLike) -> "Parameters":
|
||||||
@@ -870,8 +874,8 @@ class Configuration:
|
|||||||
config.setdefault("name", Parameters.name.default)
|
config.setdefault("name", Parameters.name.default)
|
||||||
self.z_num += config["z_num"]
|
self.z_num += config["z_num"]
|
||||||
fiber_names.add(config["name"])
|
fiber_names.add(config["name"])
|
||||||
vary_dict = config.pop("variable")
|
vary_dict_list: list[dict[str, list]] = config.pop("variable")
|
||||||
self.variationer.append(vary_dict)
|
self.variationer.append(vary_dict_list)
|
||||||
self.fiber_paths.append(
|
self.fiber_paths.append(
|
||||||
utils.ensure_folder(
|
utils.ensure_folder(
|
||||||
self.final_path / fiber_folder(i, self.name, config["name"]),
|
self.final_path / fiber_folder(i, self.name, config["name"]),
|
||||||
@@ -879,10 +883,13 @@ class Configuration:
|
|||||||
prevent_overwrite=not self.overwrite,
|
prevent_overwrite=not self.overwrite,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.__validate_variable(vary_dict)
|
self.__validate_variable(vary_dict_list)
|
||||||
self.num_fibers += 1
|
self.num_fibers += 1
|
||||||
Evaluator.evaluate_default(
|
Evaluator.evaluate_default(
|
||||||
self.__build_base_config() | config | {k: v[0] for k, v in vary_dict.items()}, True
|
self.__build_base_config()
|
||||||
|
| config
|
||||||
|
| {k: v[0] for vary_dict in vary_dict_list for k, v in vary_dict.items()},
|
||||||
|
True,
|
||||||
)
|
)
|
||||||
self.num_sim = self.variationer.var_num()
|
self.num_sim = self.variationer.var_num()
|
||||||
self.total_num_steps = sum(
|
self.total_num_steps = sum(
|
||||||
@@ -893,17 +900,18 @@ class Configuration:
|
|||||||
|
|
||||||
def __build_base_config(self):
|
def __build_base_config(self):
|
||||||
cfg = self.master_config.copy()
|
cfg = self.master_config.copy()
|
||||||
vary = cfg.pop("variable", {})
|
vary: list[dict[str, list]] = cfg.pop("variable")
|
||||||
return cfg | {k: v[0] for k, v in vary.items()}
|
return cfg | {k: v[0] for vary_dict in vary for k, v in vary_dict.items()}
|
||||||
|
|
||||||
def __validate_variable(self, vary_dict: dict[str, list]):
|
def __validate_variable(self, vary_dict_list: list[dict[str, list]]):
|
||||||
for k, v in vary_dict.items():
|
for vary_dict in vary_dict_list:
|
||||||
p = getattr(Parameters, k)
|
for k, v in vary_dict.items():
|
||||||
validator_list(p.validator)("variable " + k, v)
|
p = getattr(Parameters, k)
|
||||||
if k not in VALID_VARIABLE:
|
validator_list(p.validator)("variable " + k, v)
|
||||||
raise TypeError(f"{k!r} is not a valid variable parameter")
|
if k not in VALID_VARIABLE:
|
||||||
if len(v) == 0:
|
raise TypeError(f"{k!r} is not a valid variable parameter")
|
||||||
raise ValueError(f"variable parameter {k!r} must not be empty")
|
if len(v) == 0:
|
||||||
|
raise ValueError(f"variable parameter {k!r} must not be empty")
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[tuple[VariationDescriptor, Parameters]]:
|
def __iter__(self) -> Iterator[tuple[VariationDescriptor, Parameters]]:
|
||||||
for i in range(self.num_fibers):
|
for i in range(self.num_fibers):
|
||||||
@@ -1116,6 +1124,8 @@ default_rules: list[Rule] = [
|
|||||||
conditions=dict(model="pcf"),
|
conditions=dict(model="pcf"),
|
||||||
),
|
),
|
||||||
Rule("capillary_spacing", fiber.capillary_spacing_hasan),
|
Rule("capillary_spacing", fiber.capillary_spacing_hasan),
|
||||||
|
Rule("capillary_resonance_strengths", fiber.capillary_resonance_strengths),
|
||||||
|
Rule("capillary_resonance_strengths", lambda: [], priorities=-1),
|
||||||
# Fiber nonlinearity
|
# Fiber nonlinearity
|
||||||
Rule("A_eff", fiber.A_eff_from_V),
|
Rule("A_eff", fiber.A_eff_from_V),
|
||||||
Rule("A_eff", fiber.A_eff_from_diam),
|
Rule("A_eff", fiber.A_eff_from_diam),
|
||||||
|
|||||||
@@ -76,12 +76,13 @@ class Variationer:
|
|||||||
num_vars = []
|
num_vars = []
|
||||||
for d in var_list:
|
for d in var_list:
|
||||||
values = list(d.values())
|
values = list(d.values())
|
||||||
len_to_test = len(values[0])
|
if len(values) > 0:
|
||||||
if not all(len(v) == len_to_test for v in values[1:]):
|
len_to_test = len(values[0])
|
||||||
raise VariationSpecsError(
|
if not all(len(v) == len_to_test for v in values[1:]):
|
||||||
f"variable items should all have the same number of parameters"
|
raise VariationSpecsError(
|
||||||
)
|
f"variable items should all have the same number of parameters"
|
||||||
num_vars.append(len_to_test)
|
)
|
||||||
|
num_vars.append(len_to_test)
|
||||||
if len(num_vars) == 0:
|
if len(num_vars) == 0:
|
||||||
num_vars = [1]
|
num_vars = [1]
|
||||||
self.all_indices.append(num_vars)
|
self.all_indices.append(num_vars)
|
||||||
|
|||||||
@@ -196,6 +196,60 @@ def capillary_spacing_hasan(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def resonance_thickness(
|
||||||
|
wl_for_disp: np.ndarray, order: int, n_gas_2: np.ndarray, core_radius: float
|
||||||
|
) -> float:
|
||||||
|
"""computes at which wall thickness the specified wl is resonant
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
wl_for_disp : np.ndarray
|
||||||
|
in m
|
||||||
|
order : int
|
||||||
|
0, 1, ...
|
||||||
|
n_gas_2 : np.ndarray
|
||||||
|
as returned by materials.n_gas_2
|
||||||
|
core_radius : float
|
||||||
|
in m
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
float
|
||||||
|
thickness in m
|
||||||
|
"""
|
||||||
|
n_si_2 = mat.n_gas_2(wl_for_disp, "silica", None, None, True)
|
||||||
|
return (
|
||||||
|
wl_for_disp
|
||||||
|
/ (4 * np.sqrt(n_si_2))
|
||||||
|
* (2 * order + 1)
|
||||||
|
* (1 - n_gas_2 / n_si_2 + wl_for_disp ** 2 / (4 * n_si_2 * core_radius ** 2)) ** -0.5
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def resonance_strength(
|
||||||
|
wl_for_disp: np.ndarray, core_radius: float, capillary_thickness: float, order: int
|
||||||
|
) -> float:
|
||||||
|
a = 1.83 + (2.3 * capillary_thickness / core_radius)
|
||||||
|
n_si = np.sqrt(mat.n_gas_2(wl_for_disp, "silica", None, None, True))
|
||||||
|
return (
|
||||||
|
capillary_thickness
|
||||||
|
/ (n_si * core_radius) ** (2.303 * a / n_si)
|
||||||
|
* ((order + 2) / (3 * order)) ** (3.57 * a)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def capillary_resonance_strengths(
|
||||||
|
wl_for_disp: np.ndarray,
|
||||||
|
core_radius: float,
|
||||||
|
capillary_thickness: float,
|
||||||
|
capillary_resonance_max_order: int,
|
||||||
|
) -> list[float]:
|
||||||
|
return [
|
||||||
|
resonance_strength(wl_for_disp, core_radius, capillary_thickness, o)
|
||||||
|
for o in range(1, capillary_resonance_max_order + 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@np_cache
|
@np_cache
|
||||||
def n_eff_hasan(
|
def n_eff_hasan(
|
||||||
wl_for_disp: np.ndarray,
|
wl_for_disp: np.ndarray,
|
||||||
@@ -238,6 +292,7 @@ def n_eff_hasan(
|
|||||||
Hasan, Md Imran, Nail Akhmediev, and Wonkeun Chang. "Empirical formulae for dispersion and effective mode area in hollow-core antiresonant fibers." Journal of Lightwave Technology 36.18 (2018): 4060-4065.
|
Hasan, Md Imran, Nail Akhmediev, and Wonkeun Chang. "Empirical formulae for dispersion and effective mode area in hollow-core antiresonant fibers." Journal of Lightwave Technology 36.18 (2018): 4060-4065.
|
||||||
"""
|
"""
|
||||||
u = u_nm(1, 1)
|
u = u_nm(1, 1)
|
||||||
|
alpha = 5e-12
|
||||||
|
|
||||||
Rg = core_radius / capillary_spacing
|
Rg = core_radius / capillary_spacing
|
||||||
|
|
||||||
@@ -257,7 +312,7 @@ def n_eff_hasan(
|
|||||||
n_eff_2 += (
|
n_eff_2 += (
|
||||||
strength
|
strength
|
||||||
* wl_for_disp ** 2
|
* wl_for_disp ** 2
|
||||||
/ (wl_for_disp ** 2 - chi_sil * (2 * capillary_thickness / (m + 1)) ** 2)
|
/ (alpha + wl_for_disp ** 2 - chi_sil * (2 * capillary_thickness / (m + 1)) ** 2)
|
||||||
)
|
)
|
||||||
|
|
||||||
return np.sqrt(n_eff_2)
|
return np.sqrt(n_eff_2)
|
||||||
|
|||||||
@@ -7,11 +7,14 @@ from ..logger import get_logger
|
|||||||
from . import units
|
from . import units
|
||||||
from .. import _utils
|
from .. import _utils
|
||||||
from .units import NA, c, kB, me, e, hbar
|
from .units import NA, c, kB, me, e, hbar
|
||||||
|
from .._utils.cache import np_cache
|
||||||
|
|
||||||
|
|
||||||
|
@np_cache
|
||||||
def n_gas_2(
|
def n_gas_2(
|
||||||
wl_for_disp: np.ndarray, gas_name: str, pressure: float, temperature: float, ideal_gas: bool
|
wl_for_disp: np.ndarray, gas_name: str, pressure: float, temperature: float, ideal_gas: bool
|
||||||
):
|
):
|
||||||
|
"""Returns the sqare of the index of refraction of the specified gas"""
|
||||||
material_dico = _utils.load_material_dico(gas_name)
|
material_dico = _utils.load_material_dico(gas_name)
|
||||||
|
|
||||||
if ideal_gas:
|
if ideal_gas:
|
||||||
|
|||||||
@@ -489,12 +489,12 @@ class Simulations:
|
|||||||
self.sim_jobs_per_node = 1
|
self.sim_jobs_per_node = 1
|
||||||
|
|
||||||
def finished_and_complete(self):
|
def finished_and_complete(self):
|
||||||
for sim in self.configuration.all_configs.values():
|
# for sim in self.configuration.all_configs.values():
|
||||||
if (
|
# if (
|
||||||
self.configuration.sim_status(sim.output_path)[0]
|
# self.configuration.sim_status(sim.output_path)[0]
|
||||||
!= self.configuration.State.COMPLETE
|
# != self.configuration.State.COMPLETE
|
||||||
):
|
# ):
|
||||||
return False
|
# return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|||||||
22
testing/test_resonance.py
Normal file
22
testing/test_resonance.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import numpy as np
|
||||||
|
import scgenerator as sc
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
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, True)
|
||||||
|
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()
|
||||||
Reference in New Issue
Block a user