feat: Finished Library Medium node.
It now supports selecting the variant, and exporting a generated LazyArrayRange of valid freqs/wls. The UI was also revamped, with greatly more readable range values, dynamic labels, link button pointing to the original data, etc. . While more LOC, the code structure is also far more explicit and predictable to maintain.main
parent
339ee0226d
commit
14b98d219e
40
TODO.md
40
TODO.md
|
@ -7,14 +7,21 @@
|
||||||
- [ ] TFSF Source
|
- [ ] TFSF Source
|
||||||
- [ ] Gaussian Beam Source
|
- [ ] Gaussian Beam Source
|
||||||
- [ ] Astig. Gauss Beam
|
- [ ] Astig. Gauss Beam
|
||||||
- Material Data Fitting
|
|
||||||
- [ ] Data File Import
|
|
||||||
- [ ] DataFit Medium
|
|
||||||
- Monitors
|
- Monitors
|
||||||
- [x] EH Field
|
- [x] EH Field
|
||||||
- [x] Power Flux
|
- [x] Power Flux
|
||||||
- [ ] Permittivity
|
- [ ] Permittivity
|
||||||
- [ ] Diffraction
|
- [ ] Diffraction
|
||||||
|
- Tidy3D / Integration
|
||||||
|
- [ ] Exporter
|
||||||
|
- [ ] Combine
|
||||||
|
- [ ] Importer
|
||||||
|
- Sim Grid
|
||||||
|
- [ ] Sim Grid
|
||||||
|
- [ ] Auto
|
||||||
|
- [ ] Manual
|
||||||
|
- [ ] Uniform
|
||||||
|
- [ ] Data
|
||||||
- Structures
|
- Structures
|
||||||
- [ ] Cylinder
|
- [ ] Cylinder
|
||||||
- [ ] Cylinder Array
|
- [ ] Cylinder Array
|
||||||
|
@ -23,22 +30,22 @@
|
||||||
- [ ] FCC Lattice
|
- [ ] FCC Lattice
|
||||||
- [ ] BCC Lattice
|
- [ ] BCC Lattice
|
||||||
- [ ] Monkey
|
- [ ] Monkey
|
||||||
- Sim Grid
|
- Expr Socket
|
||||||
- [ ] Sim Grid
|
- [ ] Array Mode
|
||||||
- [ ] Auto
|
- Math Nodes
|
||||||
- [ ] Manual
|
- [ ] Reduce Math
|
||||||
- [ ] Uniform
|
- [ ] Transform Math - reindex freq->wl
|
||||||
- [ ] Data
|
- Material Data Fitting
|
||||||
|
- [ ] Data File Import
|
||||||
|
- [ ] DataFit Medium
|
||||||
- Mediums
|
- Mediums
|
||||||
|
- [ ] Non-Linearities
|
||||||
- [ ] PEC Medium
|
- [ ] PEC Medium
|
||||||
- [ ] Isotropic Medium
|
- [ ] Isotropic Medium
|
||||||
- [ ] Sellmeier Medium
|
- [ ] Sellmeier Medium
|
||||||
- [ ] Drude Medium
|
- [ ] Drude Medium
|
||||||
- [ ] Debye Medium
|
- [ ] Debye Medium
|
||||||
- [ ] Anisotropic Medium
|
- [ ] Anisotropic Medium
|
||||||
- Tidy3D
|
|
||||||
- [ ] Exporter
|
|
||||||
- [ ] Importer
|
|
||||||
- Integration
|
- Integration
|
||||||
- [ ] Simulation and Analysis of Maxim's Cavity
|
- [ ] Simulation and Analysis of Maxim's Cavity
|
||||||
- Constants
|
- Constants
|
||||||
|
@ -62,15 +69,15 @@
|
||||||
- [ ] Pol SocketType: 2D elliptical visualization of Jones vectors.
|
- [ ] Pol SocketType: 2D elliptical visualization of Jones vectors.
|
||||||
- [ ] Pol SocketType: 3D Poincare sphere visualization of Stokes vectors.
|
- [ ] Pol SocketType: 3D Poincare sphere visualization of Stokes vectors.
|
||||||
|
|
||||||
|
- [x] Math / Operate Math
|
||||||
|
- [ ] Remove two-layered dropdown; directly filter operations and use categories to seperate them.
|
||||||
|
- [ ] Implement Expr socket advancements to make a better experience operating between random expression-like sockets.
|
||||||
- [x] Math / Map Math
|
- [x] Math / Map Math
|
||||||
- [x] Remove "By x" socket set let socket sets only be "Function"/"Expr"; then add a dynamic enum underneath to select "By x" based on data support.
|
- [x] Remove "By x" socket set let socket sets only be "Function"/"Expr"; then add a dynamic enum underneath to select "By x" based on data support.
|
||||||
- [ ] Filter the operations based on data support, ex. use positive-definiteness to guide cholesky.
|
- [ ] Filter the operations based on data support, ex. use positive-definiteness to guide cholesky.
|
||||||
- [ ] Implement support for additional symbols via `Expr`.
|
- [ ] Implement support for additional symbols via `Expr`.
|
||||||
- [x] Math / Filter Math
|
- [x] Math / Filter Math
|
||||||
- [ ] Math / Reduce Math
|
- [ ] Math / Reduce Math
|
||||||
- [x] Math / Operate Math
|
|
||||||
- [ ] Remove two-layered dropdown; directly filter operations and use categories to seperate them.
|
|
||||||
- [ ] Implement Expr socket advancements to make a better experience operating between random expression-like sockets.
|
|
||||||
|
|
||||||
## Inputs
|
## Inputs
|
||||||
- [x] Wave Constant
|
- [x] Wave Constant
|
||||||
|
@ -156,8 +163,7 @@
|
||||||
|
|
||||||
## Mediums
|
## Mediums
|
||||||
- [x] Library Medium
|
- [x] Library Medium
|
||||||
- [ ] Implement frequency range output (listy), perhaps in the `InfoFlow` lane?
|
- [ ] Implement wavelength-based plot, as opposed to merely the frequency plot.
|
||||||
- [ ] Implement dynamic label.
|
|
||||||
- [ ] DataFit Medium
|
- [ ] DataFit Medium
|
||||||
- [ ] Implement by migrating the material data fitting logic from the `Tidy3D File Importer`, except now only accept a `Data` input socket, and rely on the `Data File Importer` to do the parsing into an acceptable `Data` socket format.
|
- [ ] Implement by migrating the material data fitting logic from the `Tidy3D File Importer`, except now only accept a `Data` input socket, and rely on the `Data File Importer` to do the parsing into an acceptable `Data` socket format.
|
||||||
- [ ] Save the result in the node, specifically in a property (serialized!) and lock the input graph while saved.
|
- [ ] Save the result in the node, specifically in a property (serialized!) and lock the input graph while saved.
|
||||||
|
|
|
@ -2,7 +2,7 @@ from . import (
|
||||||
analysis,
|
analysis,
|
||||||
bounds,
|
bounds,
|
||||||
inputs,
|
inputs,
|
||||||
# mediums,
|
mediums,
|
||||||
monitors,
|
monitors,
|
||||||
outputs,
|
outputs,
|
||||||
# simulations,
|
# simulations,
|
||||||
|
@ -16,7 +16,7 @@ BL_REGISTER = [
|
||||||
*inputs.BL_REGISTER,
|
*inputs.BL_REGISTER,
|
||||||
*outputs.BL_REGISTER,
|
*outputs.BL_REGISTER,
|
||||||
# *sources.BL_REGISTER,
|
# *sources.BL_REGISTER,
|
||||||
# *mediums.BL_REGISTER,
|
*mediums.BL_REGISTER,
|
||||||
# *structures.BL_REGISTER,
|
# *structures.BL_REGISTER,
|
||||||
*bounds.BL_REGISTER,
|
*bounds.BL_REGISTER,
|
||||||
*monitors.BL_REGISTER,
|
*monitors.BL_REGISTER,
|
||||||
|
@ -28,7 +28,7 @@ BL_NODES = {
|
||||||
**inputs.BL_NODES,
|
**inputs.BL_NODES,
|
||||||
**outputs.BL_NODES,
|
**outputs.BL_NODES,
|
||||||
# **sources.BL_NODES,
|
# **sources.BL_NODES,
|
||||||
# **mediums.BL_NODES,
|
**mediums.BL_NODES,
|
||||||
# **structures.BL_NODES,
|
# **structures.BL_NODES,
|
||||||
**bounds.BL_NODES,
|
**bounds.BL_NODES,
|
||||||
**monitors.BL_NODES,
|
**monitors.BL_NODES,
|
||||||
|
|
|
@ -1,17 +1,89 @@
|
||||||
|
import enum
|
||||||
|
import typing as typ
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import scipy as sc
|
|
||||||
import sympy as sp
|
import sympy as sp
|
||||||
import sympy.physics.units as spu
|
import sympy.physics.units as spu
|
||||||
import tidy3d as td
|
import tidy3d as td
|
||||||
|
from tidy3d.material_library.material_library import MaterialItem as Tidy3DMediumItem
|
||||||
|
from tidy3d.material_library.material_library import VariantItem as Tidy3DMediumVariant
|
||||||
|
|
||||||
from blender_maxwell.utils import extra_sympy_units as spuex
|
from blender_maxwell.utils import bl_cache, sci_constants
|
||||||
|
from blender_maxwell.utils import extra_sympy_units as spux
|
||||||
|
|
||||||
from ... import contracts as ct
|
from ... import contracts as ct
|
||||||
from ... import managed_objs, sockets
|
from ... import managed_objs, sockets
|
||||||
from .. import base, events
|
from .. import base, events
|
||||||
|
|
||||||
VAC_SPEED_OF_LIGHT = sc.constants.speed_of_light * spu.meter / spu.second
|
_mat_lib_iter = iter(td.material_library)
|
||||||
|
_mat_key = ''
|
||||||
|
|
||||||
|
|
||||||
|
class VendoredMedium(enum.StrEnum):
|
||||||
|
# Declare StrEnum of All Tidy3D Mediums
|
||||||
|
## -> This is a 'for ... in ...', which uses globals as loop variables.
|
||||||
|
## -> It's a bit of a hack, but very effective.
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
globals()['_mat_key'] = next(_mat_lib_iter)
|
||||||
|
except StopIteration:
|
||||||
|
break
|
||||||
|
|
||||||
|
## -> Exclude graphene. Graphene is special.
|
||||||
|
if _mat_key != 'graphene':
|
||||||
|
locals()[_mat_key] = _mat_key
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def to_name(v: typ.Self) -> str:
|
||||||
|
return td.material_library[v].name
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def to_icon(_: typ.Self) -> str:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
####################
|
||||||
|
# - Medium Properties
|
||||||
|
####################
|
||||||
|
@property
|
||||||
|
def tidy3d_medium_item(self) -> Tidy3DMediumItem:
|
||||||
|
"""Extracts the Tidy3D "Medium Item", which encapsulates all the provided experimental variants."""
|
||||||
|
return td.material_library[self]
|
||||||
|
|
||||||
|
####################
|
||||||
|
# - Medium Variant Properties
|
||||||
|
####################
|
||||||
|
@property
|
||||||
|
def medium_variants(self) -> set[Tidy3DMediumVariant]:
|
||||||
|
"""Extracts the list of medium variants, each corresponding to a particular experiment in the literature."""
|
||||||
|
return self.tidy3d_medium_item.variants
|
||||||
|
|
||||||
|
@property
|
||||||
|
def default_medium_variant(self) -> Tidy3DMediumVariant:
|
||||||
|
"""Extracts the "default" medium variant, as selected by Tidy3D."""
|
||||||
|
return self.medium_variants[self.tidy3d_medium_item.default]
|
||||||
|
|
||||||
|
####################
|
||||||
|
# - Enum Helper
|
||||||
|
####################
|
||||||
|
@property
|
||||||
|
def variants_as_bl_enum_elements(self) -> list[ct.BLEnumElement]:
|
||||||
|
"""Computes a list of variants in a format suitable for use in a dynamic `EnumProperty`.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
This `EnumProperty` will only return a string `variant_name`.
|
||||||
|
|
||||||
|
To reconstruct the actual `Tidy3DMediumVariant` object, one must therefore access it via the `vendored_medium.medium_variants[variant_name]`.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
(
|
||||||
|
variant_name,
|
||||||
|
variant_name,
|
||||||
|
' | '.join([ref.journal for ref in variant.reference]),
|
||||||
|
'',
|
||||||
|
i,
|
||||||
|
)
|
||||||
|
for i, (variant_name, variant) in enumerate(self.medium_variants.items())
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class LibraryMediumNode(base.MaxwellSimNode):
|
class LibraryMediumNode(base.MaxwellSimNode):
|
||||||
|
@ -21,124 +93,226 @@ class LibraryMediumNode(base.MaxwellSimNode):
|
||||||
####################
|
####################
|
||||||
# - Sockets
|
# - Sockets
|
||||||
####################
|
####################
|
||||||
input_sockets = {}
|
input_sockets: typ.ClassVar = {
|
||||||
output_sockets = {
|
'Generated Steps': sockets.ExprSocketDef(
|
||||||
|
mathtype=spux.MathType.Integer, default_value=2, abs_min=2
|
||||||
|
)
|
||||||
|
}
|
||||||
|
output_sockets: typ.ClassVar = {
|
||||||
'Medium': sockets.MaxwellMediumSocketDef(),
|
'Medium': sockets.MaxwellMediumSocketDef(),
|
||||||
|
'Valid Freqs': sockets.ExprSocketDef(
|
||||||
|
active_kind=ct.FlowKind.LazyArrayRange,
|
||||||
|
physical_type=spux.PhysicalType.Freq,
|
||||||
|
),
|
||||||
|
'Valid WLs': sockets.ExprSocketDef(
|
||||||
|
active_kind=ct.FlowKind.LazyArrayRange,
|
||||||
|
physical_type=spux.PhysicalType.Length,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
managed_obj_types = {
|
managed_obj_types: typ.ClassVar = {
|
||||||
'nk_plot': managed_objs.ManagedBLImage,
|
'plot': managed_objs.ManagedBLImage,
|
||||||
}
|
}
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - Properties
|
# - Properties
|
||||||
####################
|
####################
|
||||||
material: bpy.props.EnumProperty(
|
vendored_medium: VendoredMedium = bl_cache.BLField(VendoredMedium.Au, prop_ui=True)
|
||||||
name='',
|
variant_name: enum.Enum = bl_cache.BLField(
|
||||||
description='',
|
prop_ui=True, enum_cb=lambda self, _: self.search_variants()
|
||||||
# icon="NODE_MATERIAL",
|
|
||||||
items=[
|
|
||||||
(
|
|
||||||
mat_key,
|
|
||||||
td.material_library[mat_key].name,
|
|
||||||
', '.join(
|
|
||||||
[
|
|
||||||
ref.journal
|
|
||||||
for ref in td.material_library[mat_key]
|
|
||||||
.variants[td.material_library[mat_key].default]
|
|
||||||
.reference
|
|
||||||
]
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
for mat_key in td.material_library
|
|
||||||
if mat_key != 'graphene' ## For some reason, it's unique...
|
def search_variants(self) -> list[ct.BLEnumElement]:
|
||||||
],
|
"""Search for all valid variant of the current `self.vendored_medium`."""
|
||||||
default='Au',
|
return self.vendored_medium.variants_as_bl_enum_elements
|
||||||
update=(lambda self, context: self.on_prop_changed('material', context)),
|
|
||||||
|
####################
|
||||||
|
# - Computed
|
||||||
|
####################
|
||||||
|
@property
|
||||||
|
def variant(self) -> Tidy3DMediumVariant:
|
||||||
|
"""Deduce the actual medium variant from `self.vendored_medium` and `self.variant_name`."""
|
||||||
|
return self.vendored_medium.medium_variants[self.variant_name]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def medium(self) -> td.PoleResidue:
|
||||||
|
"""Deduce the actual currently selected `PoleResidue` medium from `self.variant`."""
|
||||||
|
return self.variant.medium
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data_url(self) -> str | None:
|
||||||
|
"""Deduce the URL associated with the currently selected medium from `self.variant`."""
|
||||||
|
return self.variant.data_url
|
||||||
|
|
||||||
|
@property
|
||||||
|
def references(self) -> td.PoleResidue:
|
||||||
|
"""Deduce the references associated with the currently selected `PoleResidue` medium from `self.variant`."""
|
||||||
|
return self.variant.reference
|
||||||
|
|
||||||
|
@property
|
||||||
|
def freq_range(self) -> spux.SympyExpr:
|
||||||
|
"""Deduce the frequency range as a unit-aware (THz, for convenience) column vector.
|
||||||
|
|
||||||
|
A rational approximation to each frequency bound is computed with `sp.nsimplify`, in order to **guarantee** lack of precision-loss as computations are performed on the frequency.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return spu.convert_to(
|
||||||
|
sp.Matrix([sp.nsimplify(el) for el in self.medium.frequency_range])
|
||||||
|
* spu.hertz,
|
||||||
|
spux.terahertz,
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def freq_range_str(self) -> tuple[sp.Expr, sp.Expr]:
|
def wl_range(self) -> spux.SympyExpr:
|
||||||
## TODO: Cache (node instances don't seem able to keep data outside of properties, not even cached_property)
|
"""Deduce the vacuum wavelength range as a unit-aware (nanometer, for convenience) column vector."""
|
||||||
mat = td.material_library[self.material]
|
return sp.Matrix(
|
||||||
freq_range = [
|
self.freq_range.applyfunc(
|
||||||
spu.convert_to(
|
lambda el: spu.convert_to(
|
||||||
val * spu.hertz,
|
sci_constants.vac_speed_of_light / el, spu.nanometer
|
||||||
spuex.terahertz,
|
)
|
||||||
|
)[::-1]
|
||||||
)
|
)
|
||||||
/ spuex.terahertz
|
|
||||||
for val in mat.medium.frequency_range
|
|
||||||
]
|
|
||||||
return sp.pretty([freq_range[0].n(4), freq_range[1].n(4)], use_unicode=True)
|
|
||||||
|
|
||||||
@property
|
####################
|
||||||
def nm_range_str(self) -> str:
|
# - Cached UI Properties
|
||||||
## TODO: Cache (node instances don't seem able to keep data outside of properties, not even cached_property)
|
####################
|
||||||
mat = td.material_library[self.material]
|
@staticmethod
|
||||||
nm_range = [
|
def _ui_range_format(sp_number: spux.SympyExpr, e_not_limit: int = 6):
|
||||||
spu.convert_to(
|
if sp_number.is_infinite:
|
||||||
VAC_SPEED_OF_LIGHT / (val * spu.hertz),
|
return sp.pretty(sp_number, use_unicode=True)
|
||||||
spu.nanometer,
|
|
||||||
)
|
number = float(sp_number.subs({spux.THz: 1, spu.nm: 1}))
|
||||||
/ spu.nanometer
|
formatted_str = f'{number:.2f}'
|
||||||
for val in reversed(mat.medium.frequency_range)
|
if len(formatted_str) > e_not_limit:
|
||||||
]
|
formatted_str = f'{number:.2e}'
|
||||||
return sp.pretty([nm_range[0].n(4), nm_range[1].n(4)], use_unicode=True)
|
return formatted_str
|
||||||
|
|
||||||
|
@bl_cache.cached_bl_property()
|
||||||
|
def ui_freq_range(self) -> tuple[str, str]:
|
||||||
|
"""Cached mirror of `self.wl_range` which contains UI-ready strings."""
|
||||||
|
return tuple([self._ui_range_format(el) for el in self.freq_range])
|
||||||
|
|
||||||
|
@bl_cache.cached_bl_property()
|
||||||
|
def ui_wl_range(self) -> tuple[str, str]:
|
||||||
|
"""Cached mirror of `self.wl_range` which contains UI-ready strings."""
|
||||||
|
return tuple([self._ui_range_format(el) for el in self.wl_range])
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - UI
|
# - UI
|
||||||
####################
|
####################
|
||||||
def draw_props(self, context, layout):
|
def draw_label(self) -> str:
|
||||||
layout.prop(self, 'material', text='')
|
return f'Medium: {self.vendored_medium}'
|
||||||
|
|
||||||
def draw_info(self, context, col):
|
def draw_props(self, _: bpy.types.Context, layout: bpy.types.UILayout) -> None:
|
||||||
# UI Drawing
|
layout.prop(self, self.blfields['vendored_medium'], text='')
|
||||||
split = col.split(factor=0.23, align=True)
|
layout.prop(self, self.blfields['variant_name'], text='')
|
||||||
|
|
||||||
_col = split.column(align=True)
|
def draw_info(self, _: bpy.types.Context, col: bpy.types.UILayout) -> None:
|
||||||
_col.alignment = 'LEFT'
|
box = col.box()
|
||||||
_col.label(text='nm')
|
|
||||||
_col.label(text='THz')
|
|
||||||
|
|
||||||
_col = split.column(align=True)
|
row = box.row(align=True)
|
||||||
_col.alignment = 'RIGHT'
|
row.alignment = 'CENTER'
|
||||||
_col.label(text=self.nm_range_str)
|
row.label(text='min|max')
|
||||||
_col.label(text=self.freq_range_str)
|
|
||||||
|
grid = box.grid_flow(row_major=True, columns=2, align=True)
|
||||||
|
grid.label(text='λ Range')
|
||||||
|
grid.label(text='𝑓 Range')
|
||||||
|
|
||||||
|
grid.label(text=self.ui_wl_range[0])
|
||||||
|
grid.label(text=self.ui_freq_range[0])
|
||||||
|
grid.label(text=self.ui_wl_range[1])
|
||||||
|
grid.label(text=self.ui_freq_range[1])
|
||||||
|
|
||||||
|
# URL Link
|
||||||
|
if self.data_url is not None:
|
||||||
|
box.operator('wm.url_open', text='Link to Data').url = self.data_url
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - Output Sockets
|
# - Events
|
||||||
####################
|
####################
|
||||||
@events.computes_output_socket('Medium')
|
@events.on_value_changed(
|
||||||
def compute_vac_wl(self) -> sp.Expr:
|
prop_name={'vendored_medium', 'variant_name'},
|
||||||
return td.material_library[self.material].medium
|
run_on_init=True,
|
||||||
|
props={'vendored_medium'},
|
||||||
|
)
|
||||||
|
def on_medium_changed(self, props):
|
||||||
|
if self.variant_name not in props['vendored_medium'].medium_variants:
|
||||||
|
self.variant_name = bl_cache.Signal.ResetEnumItems
|
||||||
|
|
||||||
|
self.ui_freq_range = bl_cache.Signal.InvalidateCache
|
||||||
|
self.ui_wl_range = bl_cache.Signal.InvalidateCache
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - Event Callbacks
|
# - Output
|
||||||
|
####################
|
||||||
|
@events.computes_output_socket(
|
||||||
|
'Medium',
|
||||||
|
props={'medium'},
|
||||||
|
)
|
||||||
|
def compute_medium(self, props) -> sp.Expr:
|
||||||
|
return props['medium']
|
||||||
|
|
||||||
|
@events.computes_output_socket(
|
||||||
|
'Valid Freqs',
|
||||||
|
props={'freq_range'},
|
||||||
|
)
|
||||||
|
def compute_valid_freqs(self, props) -> sp.Expr:
|
||||||
|
return props['freq_range']
|
||||||
|
|
||||||
|
@events.computes_output_socket(
|
||||||
|
'Valid Freqs',
|
||||||
|
kind=ct.FlowKind.LazyArrayRange,
|
||||||
|
props={'freq_range'},
|
||||||
|
input_sockets={'Generated Steps'},
|
||||||
|
)
|
||||||
|
def compute_valid_freqs_lazy(self, props, input_sockets) -> sp.Expr:
|
||||||
|
return ct.LazyArrayRangeFlow(
|
||||||
|
start=props['freq_range'][0] / spux.THz,
|
||||||
|
stop=props['freq_range'][1] / spux.THz,
|
||||||
|
steps=input_sockets['Generated Steps'],
|
||||||
|
scaling='lin',
|
||||||
|
unit=spux.THz,
|
||||||
|
)
|
||||||
|
|
||||||
|
@events.computes_output_socket(
|
||||||
|
'Valid WLs',
|
||||||
|
props={'wl_range'},
|
||||||
|
)
|
||||||
|
def compute_valid_wls(self, props) -> sp.Expr:
|
||||||
|
return props['wl_range']
|
||||||
|
|
||||||
|
@events.computes_output_socket(
|
||||||
|
'Valid WLs',
|
||||||
|
kind=ct.FlowKind.LazyArrayRange,
|
||||||
|
props={'wl_range'},
|
||||||
|
input_sockets={'Generated Steps'},
|
||||||
|
)
|
||||||
|
def compute_valid_wls_lazy(self, props, input_sockets) -> sp.Expr:
|
||||||
|
return ct.LazyArrayRangeFlow(
|
||||||
|
start=props['wl_range'][0] / spu.nm,
|
||||||
|
stop=props['wl_range'][0] / spu.nm,
|
||||||
|
steps=input_sockets['Generated Steps'],
|
||||||
|
scaling='lin',
|
||||||
|
unit=spu.nm,
|
||||||
|
)
|
||||||
|
|
||||||
|
####################
|
||||||
|
# - Preview
|
||||||
####################
|
####################
|
||||||
@events.on_show_plot(
|
@events.on_show_plot(
|
||||||
managed_objs={'nk_plot'},
|
managed_objs={'plot'},
|
||||||
props={'material'},
|
props={'material'},
|
||||||
stop_propagation=True, ## Plot only the first plottable node
|
stop_propagation=True,
|
||||||
)
|
)
|
||||||
def on_show_plot(
|
def on_show_plot(
|
||||||
self,
|
self,
|
||||||
managed_objs: dict,
|
managed_objs: dict,
|
||||||
props: dict,
|
|
||||||
):
|
):
|
||||||
medium = td.material_library[props['material']].medium
|
managed_objs['plot'].mpl_plot_to_image(
|
||||||
freq_range = [
|
lambda ax: self.medium.plot(self.medium.frequency_range, ax=ax),
|
||||||
spu.convert_to(
|
|
||||||
val * spu.hertz,
|
|
||||||
spuex.terahertz,
|
|
||||||
)
|
|
||||||
/ spu.hertz
|
|
||||||
for val in medium.frequency_range
|
|
||||||
]
|
|
||||||
|
|
||||||
managed_objs['nk_plot'].mpl_plot_to_image(
|
|
||||||
lambda ax: medium.plot(medium.frequency_range, ax=ax),
|
|
||||||
bl_select=True,
|
bl_select=True,
|
||||||
)
|
)
|
||||||
|
## TODO: Plot based on Wl, not freq.
|
||||||
|
|
||||||
|
|
||||||
####################
|
####################
|
||||||
|
|
Loading…
Reference in New Issue