From 772c7b6935722676200733f6191ab7010ac0a3ad Mon Sep 17 00:00:00 2001 From: Niko Savola Date: Fri, 20 Oct 2023 09:41:31 -0700 Subject: [PATCH 1/2] Export raw NumPy array capacitance matrix for ElectrostaticResults --- gplugins/common/base_models/simulation.py | 33 +++++++++++---------- gplugins/elmer/tests/test_elmer.py | 36 +++++++++++++++-------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/gplugins/common/base_models/simulation.py b/gplugins/common/base_models/simulation.py index 123dbd03..42a86fc3 100644 --- a/gplugins/common/base_models/simulation.py +++ b/gplugins/common/base_models/simulation.py @@ -1,10 +1,13 @@ from __future__ import annotations from collections.abc import Sequence +from functools import cached_property from pathlib import Path from typing import Any -from pydantic import BaseModel, ConfigDict +import numpy as np +from numpy.typing import NDArray +from pydantic import BaseModel, ConfigDict, computed_field from ..types import CapacitanceDict @@ -18,23 +21,23 @@ class ElectrostaticResults(BaseModel): mesh_location: Path | None = None field_file_location: Path | None = None - # @computed_field - # @cached_property - # def raw_capacitance_matrix(self) -> NDArray: - # n = int(np.sqrt(len(self.capacitance_matrix))) - # matrix = np.zeros((n, n)) + @computed_field + @cached_property + def raw_capacitance_matrix(self) -> NDArray: + n = int(np.sqrt(len(self.capacitance_matrix))) + matrix = np.zeros((n, n)) - # port_to_index_map = {} - # for iname, jname in self.capacitance_matrix.keys(): - # if iname not in port_to_index_map: - # port_to_index_map[iname] = len(port_to_index_map) + 1 - # if jname not in port_to_index_map: - # port_to_index_map[jname] = len(port_to_index_map) + 1 + port_to_index_map = {} + for iname, jname in self.capacitance_matrix.keys(): + if iname not in port_to_index_map: + port_to_index_map[iname] = len(port_to_index_map) + 1 + if jname not in port_to_index_map: + port_to_index_map[jname] = len(port_to_index_map) + 1 - # for (iname, jname), c in self.capacitance_matrix.items(): - # matrix[port_to_index_map[iname], port_to_index_map[jname]] = c + for (iname, jname), c in self.capacitance_matrix.items(): + matrix[port_to_index_map[iname], port_to_index_map[jname]] = c - # return matrix + return matrix class DrivenFullWaveResults(BaseModel): diff --git a/gplugins/elmer/tests/test_elmer.py b/gplugins/elmer/tests/test_elmer.py index 94bc70ee..c5cfd5e8 100644 --- a/gplugins/elmer/tests/test_elmer.py +++ b/gplugins/elmer/tests/test_elmer.py @@ -8,6 +8,7 @@ from gdsfactory.technology import LayerStack from gdsfactory.technology.layer_stack import LayerLevel +from gplugins.common.base_models.simulation import ElectrostaticResults from gplugins.elmer import run_capacitive_simulation_elmer layer_stack = LayerStack( @@ -35,7 +36,7 @@ } -@pytest.fixture +@pytest.fixture(scope="session") @gf.cell def geometry(): simulation_box = [[-200, -200], [200, 200]] @@ -67,7 +68,7 @@ def get_reasonable_mesh_parameters(c: Component): "resolution": 40, }, **{ - f"bw{port}": { + f"bw__{port}": { "resolution": 20, "DistMax": 30, "DistMin": 10, @@ -80,9 +81,11 @@ def get_reasonable_mesh_parameters(c: Component): ) -def test_elmer_capacitance_simulation_runs(geometry) -> None: +@pytest.fixture(scope="session") +def elmer_capacitance_simulation_basic_results(geometry) -> ElectrostaticResults: + """Run a Elmer capacitance simulation and cache the results""" c = geometry - run_capacitive_simulation_elmer( + return run_capacitive_simulation_elmer( c, layer_stack=layer_stack, material_spec=material_spec, @@ -90,6 +93,12 @@ def test_elmer_capacitance_simulation_runs(geometry) -> None: ) +def test_elmer_capacitance_simulation_runs( + elmer_capacitance_simulation_basic_results, +) -> None: + assert elmer_capacitance_simulation_basic_results is not None + + @pytest.mark.parametrize("n_processes", [(1), (2)]) def test_elmer_capacitance_simulation_n_processes(geometry, n_processes): c = geometry @@ -114,21 +123,22 @@ def test_elmer_capacitance_simulation_element_order(geometry, element_order) -> ) -@pytest.mark.skip(reason="TODO") -def test_elmer_capacitance_simulation_mesh_size_field(geometry) -> None: - pass - - @pytest.mark.skip(reason="TODO") def test_elmer_capacitance_simulation_flip_chip(geometry) -> None: pass @pytest.mark.skip(reason="TODO") -def test_elmer_capacitance_simulation_pyvist_plot(geometry) -> None: +def test_elmer_capacitance_simulation_pyvista_plot(geometry) -> None: pass -@pytest.mark.skip(reason="TODO") -def test_elmer_capacitance_simulation_cdict_form(geometry) -> None: - pass +def test_elmer_capacitance_simulation_raw_cap_matrix( + elmer_capacitance_simulation_basic_results, +) -> None: + matrix = elmer_capacitance_simulation_basic_results.raw_capacitance_matrix + assert matrix is not None + assert ( + len(elmer_capacitance_simulation_basic_results.capacitance_matrix) + == matrix.size + ) From fe621f8fe6ecc8d4d3ae514cb3b224de7ee858c0 Mon Sep 17 00:00:00 2001 From: Niko Savola Date: Fri, 20 Oct 2023 10:04:32 -0700 Subject: [PATCH 2/2] Generalize getting raw matrix from dict, comment out for scattering --- gplugins/common/base_models/simulation.py | 51 ++++++++++++++++------- gplugins/common/types.py | 1 + 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/gplugins/common/base_models/simulation.py b/gplugins/common/base_models/simulation.py index 42a86fc3..ee865a12 100644 --- a/gplugins/common/base_models/simulation.py +++ b/gplugins/common/base_models/simulation.py @@ -9,7 +9,32 @@ from numpy.typing import NDArray from pydantic import BaseModel, ConfigDict, computed_field -from ..types import CapacitanceDict +from ..types import CapacitanceDict, ScatteringDict + + +def _raw_matrix_from_dict(dict_matrix: CapacitanceDict | ScatteringDict) -> NDArray: + """Converts dictionary formatted matrix results to a NumPy array. + + Args: + dict_matrix: Dictionary with matrix results in ``(port_i, port_j): result`` configuration. + + Returns: + ndarray: A matrix representation of the connections. + """ + n = int(np.sqrt(len(dict_matrix))) + matrix = np.zeros((n, n)) + + port_to_index_map = {} + for iname, jname in dict_matrix.keys(): + if iname not in port_to_index_map: + port_to_index_map[iname] = len(port_to_index_map) + if jname not in port_to_index_map: + port_to_index_map[jname] = len(port_to_index_map) + + for (iname, jname), c in dict_matrix.items(): + matrix[port_to_index_map[iname], port_to_index_map[jname]] = c + + return matrix class ElectrostaticResults(BaseModel): @@ -24,25 +49,19 @@ class ElectrostaticResults(BaseModel): @computed_field @cached_property def raw_capacitance_matrix(self) -> NDArray: - n = int(np.sqrt(len(self.capacitance_matrix))) - matrix = np.zeros((n, n)) - - port_to_index_map = {} - for iname, jname in self.capacitance_matrix.keys(): - if iname not in port_to_index_map: - port_to_index_map[iname] = len(port_to_index_map) + 1 - if jname not in port_to_index_map: - port_to_index_map[jname] = len(port_to_index_map) + 1 - - for (iname, jname), c in self.capacitance_matrix.items(): - matrix[port_to_index_map[iname], port_to_index_map[jname]] = c - - return matrix + """Capacitance matrix as a NumPy array.""" + return _raw_matrix_from_dict(self.capacitance_matrix) class DrivenFullWaveResults(BaseModel): """Results class for driven full-wave simulations.""" - scattering_matrix: Any # TODO convert to SDict or similar + scattering_matrix: Any # TODO convert dataframe to ScatteringDict mesh_location: Path | None = None field_file_locations: Sequence[Path] | None = None + + # @computed_field + # @cached_property + # def raw_scattering_matrix(self) -> NDArray: + # """Scattering matrix as a NumPy array.""" + # return _raw_matrix_from_dict(self.scattering_matrix) diff --git a/gplugins/common/types.py b/gplugins/common/types.py index d1050280..deb9afc4 100644 --- a/gplugins/common/types.py +++ b/gplugins/common/types.py @@ -6,6 +6,7 @@ RFMaterialSpec = dict[str, dict[str, float | int]] CapacitanceDict = dict[tuple[str, str], float] +ScatteringDict = dict[tuple[str, str], float] AnyShapelyPolygon = Annotated[ GeometryCollection | MultiPolygon | Polygon, PlainSerializer(lambda x: x.wkb_hex, when_used="json"),