From d6c573af79611b058f1e9063aadc2b92c3637f61 Mon Sep 17 00:00:00 2001 From: Yannick Augenstein Date: Fri, 31 May 2024 13:03:12 +0200 Subject: [PATCH] Oops, restore accidentally deleted tests --- tests/test_components/test_simulation.py | 207 +++++++++++++++++++++++ 1 file changed, 207 insertions(+) diff --git a/tests/test_components/test_simulation.py b/tests/test_components/test_simulation.py index c33030eced..5d1ab0934a 100644 --- a/tests/test_components/test_simulation.py +++ b/tests/test_components/test_simulation.py @@ -1786,6 +1786,213 @@ def test_warn_large_epsilon(log_capture, size, num_struct, log_level): @pytest.mark.parametrize("dl, log_level", [(0.1, None), (0.005, "WARNING")]) def test_warn_large_mode_monitor(log_capture, dl, log_level): + """Make sure we get a warning if the mode monitor grid is too large.""" + + sim = td.Simulation( + size=(2.0, 2.0, 2.0), + grid_spec=td.GridSpec.uniform(dl=dl), + run_time=1e-12, + sources=[ + td.ModeSource( + size=(0.4, 0.4, 0), + direction="+", + source_time=td.GaussianPulse(freq0=1e12, fwidth=0.1e12), + ) + ], + monitors=[ + td.ModeMonitor( + size=(td.inf, 0, td.inf), freqs=[1e12], name="test", mode_spec=td.ModeSpec() + ) + ], + ) + sim.validate_pre_upload() + assert_log_level(log_capture, log_level) + + +@pytest.mark.parametrize("dl, log_level", [(0.1, None), (0.005, "WARNING")]) +def test_warn_large_mode_source(log_capture, dl, log_level): + """Make sure we get a warning if the mode source grid is too large.""" + + sim = td.Simulation( + size=(2.0, 2.0, 2.0), + grid_spec=td.GridSpec.uniform(dl=dl), + run_time=1e-12, + sources=[ + td.ModeSource( + size=(td.inf, td.inf, 0), + direction="+", + source_time=td.GaussianPulse(freq0=1e12, fwidth=0.1e12), + ) + ], + ) + sim.validate_pre_upload() + assert_log_level(log_capture, log_level) + + +mnt_size = (td.inf, 0, td.inf) +mnt_test = [ + td.ModeMonitor(size=mnt_size, freqs=[1e12], name="test", mode_spec=td.ModeSpec()), + td.FluxMonitor(size=mnt_size, freqs=[1e12], name="test"), + td.FluxTimeMonitor(size=mnt_size, name="test"), + td.DiffractionMonitor(size=mnt_size, freqs=[1e12], name="test"), + td.FieldProjectionAngleMonitor(size=mnt_size, freqs=[1e12], name="test", theta=[0], phi=[0]), + td.FieldMonitor(size=mnt_size, freqs=[1e12], name="test", fields=["Ex", "Hx"]), + td.FieldTimeMonitor(size=mnt_size, stop=1e-17, name="test", fields=["Ex", "Hx"]), +] + + +@pytest.mark.parametrize("monitor", mnt_test) +def test_error_large_monitors(monitor): + """Test if various large monitors cause pre-upload validation to error.""" + + sim_large = td.Simulation( + size=(40.0, 0, 40.0), + grid_spec=td.GridSpec.uniform(dl=0.001), + run_time=1e-12, + boundary_spec=td.BoundarySpec.all_sides(boundary=td.Periodic()), + sources=[ + td.ModeSource( + size=(0.1, 0.1, 0), + direction="+", + source_time=td.GaussianPulse(freq0=1e12, fwidth=0.1e12), + ) + ], + monitors=[monitor], + ) + + # small sim should not error + sim_small = sim_large.updated_copy(size=(4.0, 0, 4.0)) + sim_small.validate_pre_upload() + + # large sim should error + with pytest.raises(SetupError): + sim_large.validate_pre_upload() + + +def test_error_max_time_monitor_steps(): + """Test if a time monitor with too many time steps causes pre upload error.""" + + sim = td.Simulation( + size=(5, 5, 5), + run_time=1e-12, + grid_spec=td.GridSpec.uniform(dl=0.01), + sources=[ + td.ModeSource( + size=(0.1, 0.1, 0), + direction="+", + source_time=td.GaussianPulse(freq0=2e14, fwidth=0.1e14), + ) + ], + ) + + # simulation with a 0D time monitor should not error + monitor = td.FieldTimeMonitor(center=(0, 0, 0), size=(0, 0, 0), name="time") + sim = sim.updated_copy(monitors=[monitor]) + sim.validate_pre_upload() + + # 1D monitor should error + with pytest.raises(SetupError): + monitor = monitor.updated_copy(size=(1, 0, 0)) + sim = sim.updated_copy(monitors=[monitor]) + sim.validate_pre_upload() + + # setting a large enough interval should again not error + monitor = monitor.updated_copy(interval=20) + sim = sim.updated_copy(monitors=[monitor]) + sim.validate_pre_upload() + + +def test_monitor_num_cells(): + """Test the computation of number of cells in monitor.""" + sim = td.Simulation( + size=(2.0, 2.0, 2.0), + grid_spec=td.GridSpec.uniform(dl=0.01), + run_time=1e-12, + ) + monitor_3d = td.FluxMonitor(size=[1, 1, 1], freqs=[1e12], name="test") + monitor_2d = td.FluxMonitor(size=[1, 0, 1], freqs=[1e12], name="test") + downsample = 3 + monitor_downsample = td.FieldMonitor( + size=[1, 0, 1], freqs=[1e12], name="test", interval_space=[downsample] * 3 + ) + num_cells_3d = sim._monitor_num_cells(monitor_3d) + num_cells_2d = sim._monitor_num_cells(monitor_2d) + num_cells_downsample = sim._monitor_num_cells(monitor_downsample) + assert num_cells_2d * 6 == num_cells_3d + # downsampling is not exact + assert np.isclose(num_cells_downsample, num_cells_2d / downsample**2, rtol=0.1) + + +@pytest.mark.parametrize("start, log_level", [(1e-12, None), (1, "WARNING")]) +def test_warn_time_monitor_outside_run_time(log_capture, start, log_level): + """Make sure we get a warning if the mode monitor grid is too large.""" + + sim = td.Simulation( + size=(2.0, 2.0, 2.0), + grid_spec=td.GridSpec.uniform(dl=0.1), + run_time=1e-12, + sources=[ + td.ModeSource( + size=(0.4, 0.4, 0), + direction="+", + source_time=td.GaussianPulse(freq0=1e12, fwidth=0.1e12), + ) + ], + monitors=[td.FieldTimeMonitor(size=(td.inf, 0, td.inf), start=start, name="test")], + ) + with AssertLogLevel(log_capture, log_level_expected=log_level, contains_str="start time"): + sim.validate_pre_upload() + + +def test_dt(): + """make sure dt is reduced when there is a medium with eps_inf < 1.""" + sim = td.Simulation( + size=(2.0, 2.0, 2.0), + run_time=1e-12, + grid_spec=td.GridSpec.uniform(dl=0.1), + ) + dt = sim.dt + + # simulation with eps_inf < 1 + structure = td.Structure( + geometry=td.Box(size=(1, 1, 1), center=(-1, 0, 0)), + medium=td.PoleResidue(eps_inf=0.16, poles=[(-1 + 1j, 2 + 2j)]), + ) + sim_new = sim.copy(update=dict(structures=[structure])) + assert sim_new.dt == 0.4 * dt + + +def test_conformal_dt(): + """make sure dt is reduced when PEC structures are present and PECConformal is used.""" + box = td.Structure( + geometry=td.Box(size=(1, 1, 1)), + medium=td.PECMedium(), + ) + sim = td.Simulation( + size=(2.0, 2.0, 2.0), + run_time=1e-12, + structures=[box], + grid_spec=td.GridSpec.uniform(dl=0.1), + subpixel=td.SubpixelSpec(pec=td.Staircasing()), + ) + dt = sim.dt + + # Conformal + sim_conformal = sim.updated_copy(subpixel=td.SubpixelSpec(pec=td.PECConformal())) + assert sim_conformal.dt < dt + + # Conformal: same courant + sim_conformal2 = sim.updated_copy( + subpixel=td.SubpixelSpec(pec=td.PECConformal(timestep_reduction=0)) + ) + assert sim_conformal2.dt == dt + + # heuristic + sim_heuristic = sim.updated_copy(subpixel=td.SubpixelSpec(pec=td.HeuristicPECStaircasing())) + assert sim_heuristic.dt == dt + + +def test_sim_volumetric_structures(log_capture, tmp_path): """Test volumetric equivalent of 2D materials.""" sigma = 0.45 thickness = 0.01