Skip to content

Commit 8b3d741

Browse files
feat(tidy3d): FXC-3294-add-opt-in-local-cache-for-simulation-results
1 parent c52a9a5 commit 8b3d741

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1745
-847
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2626
- Validation for `run_only` field in component modelers to catch duplicate or invalid matrix indices early with clear error messages.
2727
- Introduced a profile-based configuration manager with TOML persistence and runtime overrides exposed via `tidy3d.config`.
2828
- Added support of `os.PathLike` objects as paths like `pathlib.Path` alongside `str` paths in all path-related functions.
29+
- Added configurable local simulation result caching with checksum validation, eviction limits. Can configured with `config.local_cache`.
2930

3031
### Changed
3132
- Improved performance of antenna metrics calculation by utilizing cached wave amplitude calculations instead of recomputing wave amplitudes for each port excitation in the `TerminalComponentModelerData`.

docs/index.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,13 @@ This will produce the following plot, which visualizes the electromagnetic field
168168

169169
You can now postprocess simulation data using the same python session, or view the results of this simulation on our web-based `graphical user interface (GUI) <https://tidy3d.simulation.cloud>`_.
170170

171+
.. tip::
172+
173+
Repeated runs of the same simulation can reuse solver results by enabling the optional
174+
local cache: ``td.config.simulation_cache.enabled = True``. The cache location and limits are
175+
configurable (see ``~/.tidy3d/config``), entries are checksum-validated, and you can clear
176+
all stored artifacts with ``tidy3d.web.cache.clear()``.
177+
171178
.. `TODO: open example in colab <https://github.com/flexcompute/tidy3d>`_
172179
173180
@@ -262,4 +269,3 @@ Contents
262269

263270

264271

265-

tests/config/test_legacy.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import importlib
44

5-
import pytest
6-
75
from tidy3d.config.__init__ import get_manager, reload_config
86

97

@@ -16,11 +14,9 @@ def test_legacy_logging_level(config_manager):
1614

1715
def test_env_switch(config_manager):
1816
config_module = importlib.import_module("tidy3d.config.__init__")
19-
with pytest.warns(DeprecationWarning, match="tidy3d.config.Env"):
20-
config_module.Env.dev.active()
17+
config_module.Env.dev.active()
2118
assert get_manager().profile == "dev"
22-
with pytest.warns(DeprecationWarning, match="tidy3d.config.Env"):
23-
config_module.Env.set_current(config_module.Env.prod)
19+
config_module.Env.set_current(config_module.Env.prod)
2420
assert get_manager().profile == "prod"
2521

2622

tests/config/test_loader.py

Lines changed: 8 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@
66
from pydantic import Field
77

88
from tidy3d.config import get_manager, reload_config
9-
from tidy3d.config import loader as config_loader
109
from tidy3d.config import registry as config_registry
11-
from tidy3d.config.legacy import finalize_legacy_migration
12-
from tidy3d.config.loader import migrate_legacy_config
1310
from tidy3d.config.sections import ConfigSection
1411
from tidy3d.web.cli.app import tidy3d_cli
1512

@@ -35,7 +32,7 @@ def test_save_includes_descriptions(config_manager, mock_config_dir):
3532
manager.save(include_defaults=True)
3633

3734
content = _config_path(mock_config_dir).read_text(encoding="utf-8")
38-
assert "Lowest logging level that will be emitted." in content
35+
assert "# Web/HTTP configuration." in content
3936

4037

4138
def test_preserves_user_comments(config_manager, mock_config_dir):
@@ -44,7 +41,10 @@ def test_preserves_user_comments(config_manager, mock_config_dir):
4441

4542
config_path = _config_path(mock_config_dir)
4643
text = config_path.read_text(encoding="utf-8")
47-
text = text.replace("Lowest logging level that will be emitted.", "user-modified comment")
44+
text = text.replace(
45+
"Web/HTTP configuration.",
46+
"user-modified comment",
47+
)
4848
config_path.write_text(text, encoding="utf-8")
4949

5050
reload_config(profile="default")
@@ -53,7 +53,7 @@ def test_preserves_user_comments(config_manager, mock_config_dir):
5353

5454
updated = config_path.read_text(encoding="utf-8")
5555
assert "user-modified comment" in updated
56-
assert "Lowest logging level that will be emitted." not in updated
56+
assert "Web/HTTP configuration." not in updated
5757

5858

5959
def test_profile_preserves_comments(config_manager, mock_config_dir):
@@ -118,7 +118,7 @@ class CLIPlugin(ConfigSection):
118118
assert result.exit_code == 0, result.output
119119

120120
config_text = _config_path(mock_config_dir).read_text(encoding="utf-8")
121-
assert "Lowest logging level that will be emitted." in config_text
121+
assert "Web/HTTP configuration." in config_text
122122
assert "[web]" in config_text
123123
assert "secret" not in config_text
124124
assert not profiles_dir.exists()
@@ -143,58 +143,8 @@ class CommentPlugin(ConfigSection):
143143
manager = get_manager()
144144
manager.save(include_defaults=True)
145145
content = _config_path(mock_config_dir).read_text(encoding="utf-8")
146+
assert "Comment plugin configuration." in content
146147
assert "Plugin knob description." in content
147148
finally:
148149
config_registry._SECTIONS.pop("plugins.comment_test", None)
149150
reload_config(profile="default")
150-
151-
152-
def test_finalize_legacy_migration_promotes_flat_file(tmp_path):
153-
canonical_dir = tmp_path / "canonical"
154-
canonical_dir.mkdir()
155-
legacy_file = canonical_dir / "config"
156-
legacy_file.write_text('apikey = "legacy-key"\n', encoding="utf-8")
157-
extra_file = canonical_dir / "extra.txt"
158-
extra_file.write_text("keep", encoding="utf-8")
159-
160-
finalize_legacy_migration(canonical_dir)
161-
162-
config_toml = canonical_dir / "config.toml"
163-
assert config_toml.exists()
164-
content = config_toml.read_text(encoding="utf-8")
165-
assert "[web]" in content
166-
assert "[logging]" in content
167-
assert "Lowest logging level that will be emitted." in content
168-
assert "legacy-key" in content
169-
assert not legacy_file.exists()
170-
assert extra_file.exists()
171-
assert extra_file.read_text(encoding="utf-8") == "keep"
172-
173-
174-
def test_migrate_legacy_config_promotes_structured_config(tmp_path, monkeypatch):
175-
legacy_dir = tmp_path / "legacy"
176-
legacy_dir.mkdir()
177-
legacy_file = legacy_dir / "config"
178-
legacy_file.write_text('apikey = "legacy-key"\n', encoding="utf-8")
179-
(legacy_dir / "extra.txt").write_text("keep", encoding="utf-8")
180-
181-
canonical_dir = tmp_path / "canonical"
182-
183-
monkeypatch.setattr(config_loader, "legacy_config_directory", lambda: legacy_dir)
184-
monkeypatch.setattr(config_loader, "canonical_config_directory", lambda: canonical_dir)
185-
186-
destination = migrate_legacy_config()
187-
188-
assert destination == canonical_dir
189-
config_toml = canonical_dir / "config.toml"
190-
assert config_toml.exists()
191-
content = config_toml.read_text(encoding="utf-8")
192-
assert "[web]" in content
193-
assert "[logging]" in content
194-
assert "Lowest logging level that will be emitted." in content
195-
assert "legacy-key" in content
196-
assert not (canonical_dir / "config").exists()
197-
extra_file = canonical_dir / "extra.txt"
198-
assert extra_file.exists()
199-
assert extra_file.read_text(encoding="utf-8") == "keep"
200-
assert legacy_dir.exists()

tests/config/test_manager.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,12 @@ def test_runtime_isolated_per_profile(config_manager):
2828
assert config_manager.get_section("web").timeout == 45
2929

3030

31-
def test_runtime_overrides_env(monkeypatch, config_manager):
31+
def test_environment_variable_precedence(monkeypatch, config_manager):
3232
monkeypatch.setenv("TIDY3D_LOGGING__LEVEL", "WARNING")
3333
config_manager.switch_profile(config_manager.profile)
3434
config_manager.update_section("logging", level="DEBUG")
3535
logging_section = config_manager.get_section("logging")
36-
# runtime change should override the environment variable
37-
assert logging_section.level == "DEBUG"
38-
39-
40-
def test_env_applies_without_runtime_override(monkeypatch, config_manager):
41-
monkeypatch.setenv("TIDY3D_LOGGING__LEVEL", "WARNING")
42-
config_manager.switch_profile(config_manager.profile)
43-
logging_section = config_manager.get_section("logging")
36+
# env var should still take precedence
4437
assert logging_section.level == "WARNING"
4538

4639

tests/test_components/autograd/test_autograd.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ def plot_sim(sim: td.Simulation, plot_eps: bool = True) -> None:
661661
# args = [("polyslab", "mode")]
662662

663663

664-
def get_functions(structure_key: str, monitor_key: str) -> typing.Callable:
664+
def get_functions(structure_key: str, monitor_key: str) -> dict[str, typing.Callable]:
665665
if structure_key == ALL_KEY:
666666
structure_keys = structure_keys_
667667
else:

0 commit comments

Comments
 (0)