Compare commits
5 Commits
e1f11f6d68
...
568fc449e8
Author | SHA1 | Date |
---|---|---|
Sofus Albert Høgsbro Rose | 568fc449e8 | |
Sofus Albert Høgsbro Rose | 269af4ba32 | |
Sofus Albert Høgsbro Rose | b5a4b6b0a1 | |
Sofus Albert Høgsbro Rose | 4f6bd8e990 | |
Sofus Albert Høgsbro Rose | 3def85e24f |
14
TODO.md
14
TODO.md
|
@ -504,13 +504,13 @@ Unreported:
|
|||
- We found the translation callback! https://projects.blender.org/blender/blender/commit/8564e03cdf59fb2a71d545e81871411b82f561d9
|
||||
- This can update the node center!!
|
||||
|
||||
- [ ] Optimize the `DataChanged` invalidator.
|
||||
- [x] Optimize the `DataChanged` invalidator.
|
||||
- [ ] Optimize unit stripping.
|
||||
|
||||
|
||||
|
||||
## Keyed Cache
|
||||
- [ ] Implement `bl_cache.KeyedCache` for, especially, abstracting the caches underlying the input and output sockets.
|
||||
- [x] Implement `bl_cache.KeyedCache` for, especially, abstracting the caches underlying the input and output sockets.
|
||||
|
||||
|
||||
|
||||
|
@ -546,12 +546,12 @@ We need support for arbitrary objects, but still backed by the persistance seman
|
|||
- [ ] Similarly, a field method that gets the 'blfield__' prop data as a dictionary.
|
||||
|
||||
### Parallel Features
|
||||
- [ ] Move serialization work to a `utils`.
|
||||
- [ ] Also make ENCODER a function that can shortcut the easy cases.
|
||||
- [ ] For serializeability, let the encoder/decoder be able to make use of an optional `.msgspec_encodable()` and similar decoder respectively, and add support for these in the ENCODER/DECODER functions.
|
||||
- [ ] Define a superclass for `SocketDef` and make everyone inherit from it
|
||||
- [x] Move serialization work to a `utils`.
|
||||
- [x] Also make ENCODER a function that can shortcut the easy cases.
|
||||
- [x] For serializeability, let the encoder/decoder be able to make use of an optional `.msgspec_encodable()` and similar decoder respectively, and add support for these in the ENCODER/DECODER functions.
|
||||
- [x] Define a superclass for `SocketDef` and make everyone inherit from it
|
||||
- [ ] Collect with a `BL_SOCKET_DEFS` object, instead of manually from `__init__.py`s
|
||||
- [ ] Add support for `.msgspec_*()` methods, so that we remove the dependency on sockets from the serialization module.
|
||||
- [x] Add support for `.msgspec_*()` methods, so that we remove the dependency on sockets from the serialization module.
|
||||
|
||||
### Sweeping Features
|
||||
- [ ] Replace all raw Blender properties with `BLField`.
|
||||
|
|
|
@ -5,14 +5,8 @@ import inspect
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import msgspec
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from ...utils import extra_sympy_units as spux
|
||||
from ...utils import logger
|
||||
from . import contracts as ct
|
||||
from . import managed_objs, sockets
|
||||
from ...utils import logger, serialize
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
|
@ -39,149 +33,12 @@ class BLInstance(typ.Protocol):
|
|||
) -> None: ...
|
||||
|
||||
|
||||
EncodableValue: typ.TypeAlias = typ.Any ## msgspec-compatible
|
||||
PropGetMethod: typ.TypeAlias = typ.Callable[[BLInstance], EncodableValue]
|
||||
PropSetMethod: typ.TypeAlias = typ.Callable[[BLInstance, EncodableValue], None]
|
||||
|
||||
####################
|
||||
# - (De)Serialization
|
||||
####################
|
||||
EncodedComplex: typ.TypeAlias = tuple[float, float] | list[float, float]
|
||||
EncodedSympy: typ.TypeAlias = str
|
||||
EncodedManagedObj: typ.TypeAlias = tuple[str, str] | list[str, str]
|
||||
EncodedPydanticModel: typ.TypeAlias = tuple[str, str] | list[str, str]
|
||||
|
||||
|
||||
def _enc_hook(obj: typ.Any) -> EncodableValue:
|
||||
"""Translates types not natively supported by `msgspec`, to an encodable form supported by `msgspec`.
|
||||
|
||||
Parameters:
|
||||
obj: The object of arbitrary type to transform into an encodable value.
|
||||
|
||||
Returns:
|
||||
A value encodable by `msgspec`.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: When the type transformation hasn't been implemented.
|
||||
"""
|
||||
if isinstance(obj, complex):
|
||||
return (obj.real, obj.imag)
|
||||
if isinstance(obj, sp.Basic | sp.MatrixBase | sp.Expr | spu.Quantity):
|
||||
return sp.srepr(obj)
|
||||
if isinstance(obj, managed_objs.ManagedObj):
|
||||
return (obj.name, obj.__class__.__name__)
|
||||
if isinstance(obj, ct.schemas.SocketDef):
|
||||
return (obj.model_dump(), obj.__class__.__name__)
|
||||
|
||||
msg = f'Can\'t encode "{obj}" of type {type(obj)}'
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
|
||||
def _dec_hook(_type: type, obj: EncodableValue) -> typ.Any:
|
||||
"""Translates the `msgspec`-encoded form of an object back to its true form.
|
||||
|
||||
Parameters:
|
||||
_type: The type to transform the `msgspec`-encoded object back into.
|
||||
obj: The encoded object of to transform back into an encodable value.
|
||||
|
||||
Returns:
|
||||
A value encodable by `msgspec`.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: When the type transformation hasn't been implemented.
|
||||
"""
|
||||
if _type is complex and isinstance(obj, EncodedComplex):
|
||||
return complex(obj[0], obj[1])
|
||||
if (
|
||||
_type is sp.Basic
|
||||
and isinstance(obj, EncodedSympy)
|
||||
or _type is sp.Expr
|
||||
and isinstance(obj, EncodedSympy)
|
||||
or _type is sp.MatrixBase
|
||||
and isinstance(obj, EncodedSympy)
|
||||
or _type is spu.Quantity
|
||||
and isinstance(obj, EncodedSympy)
|
||||
):
|
||||
return sp.sympify(obj).subs(spux.ALL_UNIT_SYMBOLS)
|
||||
if (
|
||||
_type is managed_objs.ManagedBLMesh
|
||||
and isinstance(obj, EncodedManagedObj)
|
||||
or _type is managed_objs.ManagedBLImage
|
||||
and isinstance(obj, EncodedManagedObj)
|
||||
or _type is managed_objs.ManagedBLModifier
|
||||
and isinstance(obj, EncodedManagedObj)
|
||||
):
|
||||
return {
|
||||
'ManagedBLMesh': managed_objs.ManagedBLMesh,
|
||||
'ManagedBLImage': managed_objs.ManagedBLImage,
|
||||
'ManagedBLModifier': managed_objs.ManagedBLModifier,
|
||||
}[obj[1]](obj[0])
|
||||
if _type is ct.schemas.SocketDef:
|
||||
return getattr(sockets, obj[1])(**obj[0])
|
||||
|
||||
msg = f'Can\'t decode "{obj}" to type {type(obj)}'
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
|
||||
ENCODER = msgspec.json.Encoder(enc_hook=_enc_hook, order='deterministic')
|
||||
|
||||
_DECODERS: dict[type, msgspec.json.Decoder] = {
|
||||
complex: msgspec.json.Decoder(type=complex, dec_hook=_dec_hook),
|
||||
sp.Basic: msgspec.json.Decoder(type=sp.Basic, dec_hook=_dec_hook),
|
||||
sp.Expr: msgspec.json.Decoder(type=sp.Expr, dec_hook=_dec_hook),
|
||||
sp.MatrixBase: msgspec.json.Decoder(type=sp.MatrixBase, dec_hook=_dec_hook),
|
||||
spu.Quantity: msgspec.json.Decoder(type=spu.Quantity, dec_hook=_dec_hook),
|
||||
managed_objs.ManagedBLMesh: msgspec.json.Decoder(
|
||||
type=managed_objs.ManagedBLMesh,
|
||||
dec_hook=_dec_hook,
|
||||
),
|
||||
managed_objs.ManagedBLImage: msgspec.json.Decoder(
|
||||
type=managed_objs.ManagedBLImage,
|
||||
dec_hook=_dec_hook,
|
||||
),
|
||||
managed_objs.ManagedBLModifier: msgspec.json.Decoder(
|
||||
type=managed_objs.ManagedBLModifier,
|
||||
dec_hook=_dec_hook,
|
||||
),
|
||||
# managed_objs.ManagedObj: msgspec.json.Decoder(
|
||||
# type=managed_objs.ManagedObj, dec_hook=_dec_hook
|
||||
# ), ## Doesn't work b/c unions are not explicit
|
||||
ct.schemas.SocketDef: msgspec.json.Decoder(
|
||||
type=ct.schemas.SocketDef,
|
||||
dec_hook=_dec_hook,
|
||||
),
|
||||
}
|
||||
_DECODER_FALLBACK: msgspec.json.Decoder = msgspec.json.Decoder(dec_hook=_dec_hook)
|
||||
|
||||
|
||||
@functools.cache
|
||||
def DECODER(_type: type) -> msgspec.json.Decoder: # noqa: N802
|
||||
"""Retrieve a suitable `msgspec.json.Decoder` by-type.
|
||||
|
||||
Parameters:
|
||||
_type: The type to retrieve a decoder for.
|
||||
|
||||
Returns:
|
||||
A suitable decoder.
|
||||
"""
|
||||
if (decoder := _DECODERS.get(_type)) is not None:
|
||||
return decoder
|
||||
|
||||
return _DECODER_FALLBACK
|
||||
|
||||
|
||||
def decode_any(_type: type, obj: str) -> typ.Any:
|
||||
naive_decode = DECODER(_type).decode(obj)
|
||||
if _type == dict[str, ct.schemas.SocketDef]:
|
||||
return {
|
||||
socket_name: getattr(sockets, socket_def_list[1])(**socket_def_list[0])
|
||||
for socket_name, socket_def_list in naive_decode.items()
|
||||
}
|
||||
|
||||
log.critical(
|
||||
'Naive Decode of "%s" to "%s" (%s)', str(obj), str(naive_decode), str(_type)
|
||||
)
|
||||
return naive_decode
|
||||
PropGetMethod: typ.TypeAlias = typ.Callable[
|
||||
[BLInstance], serialize.NaivelyEncodableType
|
||||
]
|
||||
PropSetMethod: typ.TypeAlias = typ.Callable[
|
||||
[BLInstance, serialize.NaivelyEncodableType], None
|
||||
]
|
||||
|
||||
|
||||
####################
|
||||
|
@ -210,7 +67,7 @@ class KeyedCache:
|
|||
self,
|
||||
func: typ.Callable,
|
||||
exclude: set[str],
|
||||
serialize: set[str],
|
||||
encode: set[str],
|
||||
):
|
||||
# Function Information
|
||||
self.func: typ.Callable = func
|
||||
|
@ -219,7 +76,7 @@ class KeyedCache:
|
|||
# Arg -> Key Information
|
||||
self.exclude: set[str] = exclude
|
||||
self.include: set[str] = set(self.func_sig.parameters.keys()) - exclude
|
||||
self.serialize: set[str] = serialize
|
||||
self.encode: set[str] = encode
|
||||
|
||||
# Cache Information
|
||||
self.key_schema: tuple[str, ...] = tuple(
|
||||
|
@ -247,8 +104,8 @@ class KeyedCache:
|
|||
[
|
||||
(
|
||||
arg_value
|
||||
if arg_name not in self.serialize
|
||||
else ENCODER.encode(arg_value)
|
||||
if arg_name not in self.encode
|
||||
else serialize.encode(arg_value)
|
||||
)
|
||||
for arg_name, arg_value in arguments.items()
|
||||
if arg_name in self.include
|
||||
|
@ -298,8 +155,8 @@ class KeyedCache:
|
|||
|
||||
# Compute Keys to Invalidate
|
||||
arguments_hashable = {
|
||||
arg_name: ENCODER.encode(arg_value)
|
||||
if arg_name in self.serialize and arg_name not in wildcard_arguments
|
||||
arg_name: serialize.encode(arg_value)
|
||||
if arg_name in self.encode and arg_name not in wildcard_arguments
|
||||
else arg_value
|
||||
for arg_name, arg_value in arguments.items()
|
||||
}
|
||||
|
@ -313,12 +170,12 @@ class KeyedCache:
|
|||
cache.pop(key)
|
||||
|
||||
|
||||
def keyed_cache(exclude: set[str], serialize: set[str] = frozenset()) -> typ.Callable:
|
||||
def keyed_cache(exclude: set[str], encode: set[str] = frozenset()) -> typ.Callable:
|
||||
def decorator(func: typ.Callable) -> typ.Callable:
|
||||
return KeyedCache(
|
||||
func,
|
||||
exclude=exclude,
|
||||
serialize=serialize,
|
||||
encode=encode,
|
||||
)
|
||||
|
||||
return decorator
|
||||
|
@ -364,9 +221,6 @@ class CachedBLProperty:
|
|||
inspect.signature(getter_method).return_annotation if persist else None
|
||||
)
|
||||
|
||||
# Check Non-Empty Type Annotation
|
||||
## For now, just presume that all types can be encoded/decoded.
|
||||
|
||||
# Check Non-Empty Type Annotation
|
||||
## For now, just presume that all types can be encoded/decoded.
|
||||
if self._type is not None and self._type is inspect.Signature.empty:
|
||||
|
@ -428,7 +282,7 @@ class CachedBLProperty:
|
|||
self._persist
|
||||
and (encoded_value := getattr(bl_instance, self._bl_prop_name)) != ''
|
||||
):
|
||||
value = decode_any(self._type, encoded_value)
|
||||
value = serialize.decode(self._type, encoded_value)
|
||||
cache_nopersist[self._bl_prop_name] = value
|
||||
return value
|
||||
|
||||
|
@ -439,7 +293,7 @@ class CachedBLProperty:
|
|||
cache_nopersist[self._bl_prop_name] = value
|
||||
if self._persist:
|
||||
setattr(
|
||||
bl_instance, self._bl_prop_name, ENCODER.encode(value).decode('utf-8')
|
||||
bl_instance, self._bl_prop_name, serialize.encode(value).decode('utf-8')
|
||||
)
|
||||
return value
|
||||
|
||||
|
@ -611,7 +465,7 @@ class BLField:
|
|||
raise TypeError(msg)
|
||||
|
||||
# Define Blender Property (w/Update Sync)
|
||||
encoded_default_value = ENCODER.encode(self._default_value).decode('utf-8')
|
||||
encoded_default_value = serialize.encode(self._default_value).decode('utf-8')
|
||||
log.debug(
|
||||
'%s set to StringProperty w/default "%s" and no_update="%s"',
|
||||
bl_attr_name,
|
||||
|
@ -632,14 +486,14 @@ class BLField:
|
|||
## 2. Retrieve bpy.props.StringProperty string.
|
||||
## 3. Decode using annotated type.
|
||||
def getter(_self: BLInstance) -> AttrType:
|
||||
return decode_any(AttrType, getattr(_self, bl_attr_name))
|
||||
return serialize.decode(AttrType, getattr(_self, bl_attr_name))
|
||||
|
||||
## Setter:
|
||||
## 1. Initialize bpy.props.StringProperty to Default (if undefined).
|
||||
## 3. Encode value (implicitly using the annotated type).
|
||||
## 2. Set bpy.props.StringProperty string.
|
||||
def setter(_self: BLInstance, value: AttrType) -> None:
|
||||
encoded_value = ENCODER.encode(value).decode('utf-8')
|
||||
encoded_value = serialize.encode(value).decode('utf-8')
|
||||
log.debug(
|
||||
'Writing BLField attr "%s" w/encoded value: %s',
|
||||
bl_attr_name,
|
||||
|
|
|
@ -132,7 +132,7 @@ def _socket_def_from_bl_socket(
|
|||
|
||||
def socket_def_from_bl_socket(
|
||||
bl_interface_socket: bpy.types.NodeTreeInterfaceSocket,
|
||||
) -> ct.schemas.SocketDef:
|
||||
) -> sockets.base.SocketDef:
|
||||
"""Computes an appropriate (no-arg) SocketDef from the given `bl_interface_socket`, by parsing it."""
|
||||
return _socket_def_from_bl_socket(
|
||||
bl_interface_socket.description, bl_interface_socket.bl_socket_idname
|
||||
|
|
|
@ -65,11 +65,6 @@ from .data_flows import (
|
|||
)
|
||||
from .data_flow_actions import DataFlowAction
|
||||
|
||||
####################
|
||||
# - Schemas
|
||||
####################
|
||||
from . import schemas
|
||||
|
||||
####################
|
||||
# - Export
|
||||
####################
|
||||
|
@ -103,5 +98,4 @@ __all__ = [
|
|||
'LazyDataValueRange',
|
||||
'LazyDataValueSpectrum',
|
||||
'DataFlowAction',
|
||||
'schemas',
|
||||
]
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import enum
|
||||
import pydantic as pyd
|
||||
import typing_extensions as pytypes_ext
|
||||
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
from .managed_obj import ManagedObj
|
||||
from .managed_obj_def import ManagedObjDef
|
||||
from .preset_def import PresetDef
|
||||
from .socket_def import SocketDef
|
||||
|
||||
__all__ = [
|
||||
'SocketDef',
|
||||
'ManagedObj',
|
||||
'ManagedObjDef',
|
||||
'PresetDef',
|
||||
]
|
|
@ -1,22 +0,0 @@
|
|||
import typing as typ
|
||||
|
||||
from ..bl import ManagedObjName
|
||||
from ..managed_obj_type import ManagedObjType
|
||||
|
||||
|
||||
class ManagedObj(typ.Protocol):
|
||||
managed_obj_type: ManagedObjType
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: ManagedObjName,
|
||||
): ...
|
||||
|
||||
@property
|
||||
def name(self) -> str: ...
|
||||
@name.setter
|
||||
def name(self, value: str): ...
|
||||
|
||||
def free(self): ...
|
||||
|
||||
def bl_select(self): ...
|
|
@ -1,10 +0,0 @@
|
|||
import typing as typ
|
||||
|
||||
import pydantic as pyd
|
||||
|
||||
from .managed_obj import ManagedObj
|
||||
|
||||
|
||||
class ManagedObjDef(pyd.BaseModel):
|
||||
mk: typ.Callable[[str], ManagedObj]
|
||||
name_prefix: str = ''
|
|
@ -1,12 +0,0 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
|
||||
from ..socket_types import SocketType
|
||||
|
||||
|
||||
@typ.runtime_checkable
|
||||
class SocketDef(typ.Protocol):
|
||||
socket_type: SocketType
|
||||
|
||||
def init(self, bl_socket: bpy.types.NodeSocket) -> None: ...
|
|
@ -1,4 +1,5 @@
|
|||
import typing as typ
|
||||
|
||||
from .base import ManagedObj
|
||||
|
||||
# from .managed_bl_empty import ManagedBLEmpty
|
||||
from .managed_bl_image import ManagedBLImage
|
||||
|
@ -10,9 +11,8 @@ from .managed_bl_mesh import ManagedBLMesh
|
|||
# from .managed_bl_volume import ManagedBLVolume
|
||||
from .managed_bl_modifier import ManagedBLModifier
|
||||
|
||||
ManagedObj: typ.TypeAlias = ManagedBLImage | ManagedBLMesh | ManagedBLModifier
|
||||
|
||||
__all__ = [
|
||||
'ManagedObj',
|
||||
#'ManagedBLEmpty',
|
||||
'ManagedBLImage',
|
||||
#'ManagedBLCollection',
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
import abc
|
||||
import typing as typ
|
||||
|
||||
from blender_maxwell.utils import logger, serialize
|
||||
|
||||
from .. import contracts as ct
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
|
||||
class ManagedObj(abc.ABC):
|
||||
managed_obj_type: ct.ManagedObjType
|
||||
|
||||
@abc.abstractmethod
|
||||
def __init__(
|
||||
self,
|
||||
name: ct.ManagedObjName,
|
||||
):
|
||||
"""Initializes the managed object with a unique name."""
|
||||
|
||||
####################
|
||||
# - Properties
|
||||
####################
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def name(self) -> str:
|
||||
"""Retrieve the name of the managed object."""
|
||||
|
||||
@name.setter
|
||||
@abc.abstractmethod
|
||||
def name(self, value: str) -> None:
|
||||
"""Retrieve the name of the managed object."""
|
||||
|
||||
####################
|
||||
# - Methods
|
||||
####################
|
||||
@abc.abstractmethod
|
||||
def free(self) -> None:
|
||||
"""Cleanup the resources managed by the managed object."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def bl_select(self) -> None:
|
||||
"""Select the managed object in Blender, if such an operation makes sense."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def hide_preview(self) -> None:
|
||||
"""Select the managed object in Blender, if such an operation makes sense."""
|
||||
|
||||
####################
|
||||
# - Serialization
|
||||
####################
|
||||
def dump_as_msgspec(self) -> serialize.NaiveRepresentation:
|
||||
return [
|
||||
serialize.TypeID.ManagedObj,
|
||||
self.__class__.__name__,
|
||||
self.name,
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def parse_as_msgspec(obj: serialize.NaiveRepresentation) -> typ.Self:
|
||||
return next(
|
||||
subclass(obj[2])
|
||||
for subclass in ManagedObj.__subclasses__()
|
||||
if subclass.__name__ == obj[1]
|
||||
)
|
|
@ -1,4 +1,3 @@
|
|||
import functools
|
||||
|
||||
import bpy
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import io
|
||||
import time
|
||||
import typing as typ
|
||||
|
||||
import bpy
|
||||
|
@ -12,6 +11,7 @@ import typing_extensions as typx
|
|||
|
||||
from ....utils import logger
|
||||
from .. import contracts as ct
|
||||
from . import base
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
|
@ -76,7 +76,7 @@ def rgba_image_from_xyzf(xyz_freq, colormap: str | None = None):
|
|||
return rgba_image_from_xyzf__grayscale(xyz_freq)
|
||||
|
||||
|
||||
class ManagedBLImage(ct.schemas.ManagedObj):
|
||||
class ManagedBLImage(base.ManagedObj):
|
||||
managed_obj_type = ct.ManagedObjType.ManagedBLImage
|
||||
_bl_image_name: str
|
||||
|
||||
|
@ -181,6 +181,9 @@ class ManagedBLImage(ct.schemas.ManagedObj):
|
|||
if bl_image := bpy.data.images.get(self.name):
|
||||
self.preview_space.image = bl_image
|
||||
|
||||
def hide_preview(self) -> None:
|
||||
self.preview_space.image = None
|
||||
|
||||
####################
|
||||
# - Image Geometry
|
||||
####################
|
||||
|
@ -269,12 +272,12 @@ class ManagedBLImage(ct.schemas.ManagedObj):
|
|||
)
|
||||
# log.debug('Computed MPL Geometry (%f)', time.perf_counter() - time_start)
|
||||
|
||||
#log.debug(
|
||||
# 'Creating MPL Axes (aspect=%f, width=%f, height=%f)',
|
||||
# aspect_ratio,
|
||||
# _width_inches,
|
||||
# _height_inches,
|
||||
#)
|
||||
# log.debug(
|
||||
# 'Creating MPL Axes (aspect=%f, width=%f, height=%f)',
|
||||
# aspect_ratio,
|
||||
# _width_inches,
|
||||
# _height_inches,
|
||||
# )
|
||||
# Create MPL Figure, Axes, and Compute Figure Geometry
|
||||
fig, ax = plt.subplots(
|
||||
figsize=[_width_inches, _height_inches],
|
||||
|
|
|
@ -6,6 +6,7 @@ import numpy as np
|
|||
|
||||
from ....utils import logger
|
||||
from .. import contracts as ct
|
||||
from . import base
|
||||
from .managed_bl_collection import managed_collection, preview_collection
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
@ -14,7 +15,7 @@ log = logger.get(__name__)
|
|||
####################
|
||||
# - BLMesh
|
||||
####################
|
||||
class ManagedBLMesh(ct.schemas.ManagedObj):
|
||||
class ManagedBLMesh(base.ManagedObj):
|
||||
managed_obj_type = ct.ManagedObjType.ManagedBLMesh
|
||||
_bl_object_name: str | None = None
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import typing_extensions as typx
|
|||
from ....utils import analyze_geonodes, logger
|
||||
from .. import bl_socket_map
|
||||
from .. import contracts as ct
|
||||
from . import base
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
|
@ -160,7 +161,7 @@ def write_modifier(
|
|||
####################
|
||||
# - ManagedObj
|
||||
####################
|
||||
class ManagedBLModifier(ct.schemas.ManagedObj):
|
||||
class ManagedBLModifier(base.ManagedObj):
|
||||
managed_obj_type = ct.ManagedObjType.ManagedBLModifier
|
||||
_modifier_name: str | None = None
|
||||
|
||||
|
@ -185,6 +186,9 @@ class ManagedBLModifier(ct.schemas.ManagedObj):
|
|||
def __init__(self, name: str):
|
||||
self.name = name
|
||||
|
||||
def bl_select(self) -> None: pass
|
||||
def hide_preview(self) -> None: pass
|
||||
|
||||
####################
|
||||
# - Deallocation
|
||||
####################
|
||||
|
|
|
@ -5,7 +5,6 @@ import bpy
|
|||
|
||||
from ...utils import logger
|
||||
from . import contracts as ct
|
||||
from .managed_objs.managed_bl_collection import preview_collection
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import bpy
|
|||
|
||||
from .....utils import logger
|
||||
from ... import contracts as ct
|
||||
from ... import managed_objs, sockets
|
||||
from ... import sockets
|
||||
from .. import base, events
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
@ -245,9 +245,9 @@ class ExtractDataNode(base.MaxwellSimNode):
|
|||
field_data = self._compute_input('Field Data')
|
||||
return getattr(field_data, props['field_data__component'])
|
||||
|
||||
elif self.active_socket_set == 'Flux Data': # noqa: RET505
|
||||
elif self.active_socket_set == 'Flux Data':
|
||||
flux_data = self._compute_input('Flux Data')
|
||||
return getattr(flux_data, 'flux')
|
||||
return flux_data.flux
|
||||
|
||||
msg = f'Tried to get data from unknown output socket in "{self.bl_label}"'
|
||||
raise RuntimeError(msg)
|
||||
|
|
|
@ -24,23 +24,12 @@ class VizNode(base.MaxwellSimNode):
|
|||
'Data': sockets.AnySocketDef(),
|
||||
'Freq': sockets.PhysicalFreqSocketDef(),
|
||||
}
|
||||
# input_sockets_sets: typ.ClassVar = {
|
||||
# '2D Freq': {
|
||||
# 'Data': sockets.AnySocketDef(),
|
||||
# 'Freq': sockets.PhysicalFreqSocketDef(),
|
||||
# },
|
||||
# }
|
||||
output_sockets: typ.ClassVar = {
|
||||
'Preview': sockets.AnySocketDef(),
|
||||
}
|
||||
|
||||
managed_obj_defs: typ.ClassVar = {
|
||||
'plot': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLImage(name),
|
||||
),
|
||||
#'empty': ct.schemas.ManagedObjDef(
|
||||
# mk=lambda name: managed_objs.ManagedBLEmpty(name),
|
||||
# ),
|
||||
managed_obj_types: typ.ClassVar = {
|
||||
'plot': managed_objs.ManagedBLImage,
|
||||
}
|
||||
|
||||
#####################
|
||||
|
@ -78,7 +67,7 @@ class VizNode(base.MaxwellSimNode):
|
|||
)
|
||||
def on_show_plot(
|
||||
self,
|
||||
managed_objs: dict[str, ct.schemas.ManagedObj],
|
||||
managed_objs: dict,
|
||||
input_sockets: dict,
|
||||
props: dict,
|
||||
unit_systems: dict,
|
||||
|
|
|
@ -12,11 +12,13 @@ import bpy
|
|||
import sympy as sp
|
||||
import typing_extensions as typx
|
||||
|
||||
from ....utils import logger
|
||||
from .. import bl_cache
|
||||
from blender_maxwell.utils import logger
|
||||
|
||||
from .. import bl_cache, sockets
|
||||
from .. import contracts as ct
|
||||
from .. import managed_objs as _managed_objs
|
||||
from . import events
|
||||
from . import presets as _presets
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
|
@ -42,21 +44,27 @@ class MaxwellSimNode(bpy.types.Node):
|
|||
## TODO: bl_description from first line of __doc__?
|
||||
|
||||
# Sockets
|
||||
input_sockets: typ.ClassVar[dict[str, ct.schemas.SocketDef]] = MappingProxyType({})
|
||||
output_sockets: typ.ClassVar[dict[str, ct.schemas.SocketDef]] = MappingProxyType({})
|
||||
input_socket_sets: typ.ClassVar[dict[str, dict[str, ct.schemas.SocketDef]]] = (
|
||||
input_sockets: typ.ClassVar[dict[str, sockets.base.SocketDef]] = MappingProxyType(
|
||||
{}
|
||||
)
|
||||
output_sockets: typ.ClassVar[dict[str, sockets.base.SocketDef]] = MappingProxyType(
|
||||
{}
|
||||
)
|
||||
input_socket_sets: typ.ClassVar[dict[str, dict[str, sockets.base.SocketDef]]] = (
|
||||
MappingProxyType({})
|
||||
)
|
||||
output_socket_sets: typ.ClassVar[dict[str, dict[str, ct.schemas.SocketDef]]] = (
|
||||
output_socket_sets: typ.ClassVar[dict[str, dict[str, sockets.base.SocketDef]]] = (
|
||||
MappingProxyType({})
|
||||
)
|
||||
|
||||
# Presets
|
||||
presets: typ.ClassVar = MappingProxyType({})
|
||||
presets: typ.ClassVar[dict[str, dict[str, _presets.PresetDef]]] = MappingProxyType(
|
||||
{}
|
||||
)
|
||||
|
||||
# Managed Objects
|
||||
managed_obj_defs: typ.ClassVar[
|
||||
dict[ct.ManagedObjName, ct.schemas.ManagedObjDef]
|
||||
managed_obj_types: typ.ClassVar[
|
||||
dict[ct.ManagedObjName, type[_managed_objs.ManagedObj]]
|
||||
] = MappingProxyType({})
|
||||
|
||||
####################
|
||||
|
@ -222,7 +230,7 @@ class MaxwellSimNode(bpy.types.Node):
|
|||
####################
|
||||
@events.on_value_changed(
|
||||
prop_name='sim_node_name',
|
||||
props={'sim_node_name', 'managed_objs', 'managed_obj_defs'},
|
||||
props={'sim_node_name', 'managed_objs', 'managed_obj_types'},
|
||||
)
|
||||
def _on_sim_node_name_changed(self, props: dict):
|
||||
log.info(
|
||||
|
@ -233,9 +241,8 @@ class MaxwellSimNode(bpy.types.Node):
|
|||
)
|
||||
|
||||
# Set Name of Managed Objects
|
||||
for mobj_id, mobj in props['managed_objs'].items():
|
||||
mobj_def = props['managed_obj_defs'][mobj_id]
|
||||
mobj.name = mobj_def.name_prefix + props['sim_node_name']
|
||||
for mobj in props['managed_objs'].values():
|
||||
mobj.name = props['sim_node_name']
|
||||
|
||||
@events.on_value_changed(prop_name='active_socket_set')
|
||||
def _on_socket_set_changed(self):
|
||||
|
@ -282,9 +289,7 @@ class MaxwellSimNode(bpy.types.Node):
|
|||
def _on_preview_changed(self, props):
|
||||
if not props['preview_active']:
|
||||
for mobj in self.managed_objs.values():
|
||||
if isinstance(mobj, _managed_objs.ManagedBLMesh):
|
||||
## TODO: This is a Workaround
|
||||
mobj.hide_preview()
|
||||
mobj.hide_preview()
|
||||
|
||||
@events.on_enable_lock()
|
||||
def _on_enabled_lock(self):
|
||||
|
@ -303,8 +308,8 @@ class MaxwellSimNode(bpy.types.Node):
|
|||
####################
|
||||
# - Loose Sockets w/Events
|
||||
####################
|
||||
loose_input_sockets: dict[str, ct.schemas.SocketDef] = bl_cache.BLField({})
|
||||
loose_output_sockets: dict[str, ct.schemas.SocketDef] = bl_cache.BLField({})
|
||||
loose_input_sockets: dict[str, sockets.base.SocketDef] = bl_cache.BLField({})
|
||||
loose_output_sockets: dict[str, sockets.base.SocketDef] = bl_cache.BLField({})
|
||||
|
||||
@events.on_value_changed(prop_name={'loose_input_sockets', 'loose_output_sockets'})
|
||||
def _on_loose_sockets_changed(self):
|
||||
|
@ -334,7 +339,7 @@ class MaxwellSimNode(bpy.types.Node):
|
|||
def _active_socket_set_socket_defs(
|
||||
self,
|
||||
direc: typx.Literal['input', 'output'],
|
||||
) -> dict[ct.SocketName, ct.schemas.SocketDef]:
|
||||
) -> dict[ct.SocketName, sockets.base.SocketDef]:
|
||||
"""Retrieve all socket definitions for sockets that should be defined, according to the `self.active_socket_set`.
|
||||
|
||||
Notes:
|
||||
|
@ -344,7 +349,7 @@ class MaxwellSimNode(bpy.types.Node):
|
|||
direc: The direction to load Blender sockets from.
|
||||
|
||||
Returns:
|
||||
Mapping from socket names to corresponding `ct.schemas.SocketDef`s.
|
||||
Mapping from socket names to corresponding `sockets.base.SocketDef`s.
|
||||
|
||||
If `self.active_socket_set` is None, the empty dict is returned.
|
||||
"""
|
||||
|
@ -360,14 +365,14 @@ class MaxwellSimNode(bpy.types.Node):
|
|||
|
||||
def active_socket_defs(
|
||||
self, direc: typx.Literal['input', 'output']
|
||||
) -> dict[ct.SocketName, ct.schemas.SocketDef]:
|
||||
) -> dict[ct.SocketName, sockets.base.SocketDef]:
|
||||
"""Retrieve all socket definitions for sockets that should be defined.
|
||||
|
||||
Parameters:
|
||||
direc: The direction to load Blender sockets from.
|
||||
|
||||
Returns:
|
||||
Mapping from socket names to corresponding `ct.schemas.SocketDef`s.
|
||||
Mapping from socket names to corresponding `sockets.base.SocketDef`s.
|
||||
"""
|
||||
static_sockets = self.input_sockets if direc == 'input' else self.output_sockets
|
||||
loose_sockets = (
|
||||
|
@ -460,33 +465,17 @@ class MaxwellSimNode(bpy.types.Node):
|
|||
####################
|
||||
# - Managed Objects
|
||||
####################
|
||||
managed_bl_meshes: dict[str, _managed_objs.ManagedBLMesh] = bl_cache.BLField({})
|
||||
managed_bl_images: dict[str, _managed_objs.ManagedBLImage] = bl_cache.BLField({})
|
||||
managed_bl_modifiers: dict[str, _managed_objs.ManagedBLModifier] = bl_cache.BLField(
|
||||
{}
|
||||
)
|
||||
|
||||
@bl_cache.cached_bl_property(
|
||||
persist=False
|
||||
) ## Disable broken ManagedObj union DECODER
|
||||
@bl_cache.cached_bl_property(persist=True)
|
||||
def managed_objs(self) -> dict[str, _managed_objs.ManagedObj]:
|
||||
"""Access the managed objects defined on this node.
|
||||
|
||||
Persistent cache ensures that the managed objects are only created on first access, even across file reloads.
|
||||
"""
|
||||
if self.managed_obj_defs:
|
||||
if not (
|
||||
managed_objs := (
|
||||
self.managed_bl_meshes
|
||||
| self.managed_bl_images
|
||||
| self.managed_bl_modifiers
|
||||
)
|
||||
):
|
||||
return {
|
||||
mobj_name: mobj_def.mk(mobj_def.name_prefix + self.sim_node_name)
|
||||
for mobj_name, mobj_def in self.managed_obj_defs.items()
|
||||
}
|
||||
return managed_objs
|
||||
if self.managed_obj_types:
|
||||
return {
|
||||
mobj_name: mobj_type(self.sim_node_name)
|
||||
for mobj_name, mobj_type in self.managed_obj_types.items()
|
||||
}
|
||||
|
||||
return {}
|
||||
|
||||
|
@ -564,7 +553,7 @@ class MaxwellSimNode(bpy.types.Node):
|
|||
####################
|
||||
@bl_cache.keyed_cache(
|
||||
exclude={'self', 'optional'},
|
||||
serialize={'unit_system'},
|
||||
encode={'unit_system'},
|
||||
)
|
||||
def _compute_input(
|
||||
self,
|
||||
|
@ -719,13 +708,6 @@ class MaxwellSimNode(bpy.types.Node):
|
|||
stop_propagation |= event_method.stop_propagation
|
||||
event_method(self)
|
||||
|
||||
# Stop Propagation (maybe)
|
||||
if (
|
||||
ct.DataFlowAction.stop_if_no_event_methods(action)
|
||||
and len(triggered_event_methods) == 0
|
||||
):
|
||||
return
|
||||
|
||||
# Propagate Action to All Sockets in "Trigger Direction"
|
||||
## The trigger chain goes node/socket/node/socket/...
|
||||
if not stop_propagation:
|
||||
|
|
|
@ -47,11 +47,8 @@ class Tidy3DFileImporterNode(base.MaxwellSimNode):
|
|||
input_sockets: typ.ClassVar = {
|
||||
'File Path': sockets.FilePathSocketDef(),
|
||||
}
|
||||
managed_obj_defs: typ.ClassVar = {
|
||||
'plot': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLImage(name),
|
||||
name_prefix='',
|
||||
),
|
||||
managed_obj_types: typ.ClassVar = {
|
||||
'plot': managed_objs.ManagedBLImage,
|
||||
}
|
||||
|
||||
####################
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import typing as typ
|
||||
from pathlib import Path
|
||||
|
||||
import tidy3d as td
|
||||
|
||||
from ...... import info
|
||||
from ......services import tdcloud
|
||||
from ......utils import logger
|
||||
|
|
|
@ -26,11 +26,8 @@ class LibraryMediumNode(base.MaxwellSimNode):
|
|||
'Medium': sockets.MaxwellMediumSocketDef(),
|
||||
}
|
||||
|
||||
managed_obj_defs = {
|
||||
'nk_plot': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLImage(name),
|
||||
name_prefix='',
|
||||
)
|
||||
managed_obj_types = {
|
||||
'nk_plot': managed_objs.ManagedBLImage,
|
||||
}
|
||||
|
||||
####################
|
||||
|
@ -125,8 +122,8 @@ class LibraryMediumNode(base.MaxwellSimNode):
|
|||
)
|
||||
def on_show_plot(
|
||||
self,
|
||||
managed_objs: dict[str, ct.schemas.ManagedObj],
|
||||
props: dict[str, typ.Any],
|
||||
managed_objs: dict,
|
||||
props: dict,
|
||||
):
|
||||
medium = td.material_library[props['material']].medium
|
||||
freq_range = [
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import typing as typ
|
||||
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
|
||||
from .....assets.import_geonodes import GeoNodes, import_geonodes
|
||||
|
@ -50,13 +49,9 @@ class EHFieldMonitorNode(base.MaxwellSimNode):
|
|||
'Time Domain': {'Time Monitor': sockets.MaxwellMonitorSocketDef()},
|
||||
}
|
||||
|
||||
managed_obj_defs: typ.ClassVar = {
|
||||
'mesh': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLMesh(name),
|
||||
),
|
||||
'modifier': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLModifier(name),
|
||||
),
|
||||
managed_obj_types: typ.ClassVar = {
|
||||
'mesh': managed_objs.ManagedBLMesh,
|
||||
'modifier': managed_objs.ManagedBLModifier,
|
||||
}
|
||||
|
||||
####################
|
||||
|
@ -118,7 +113,7 @@ class EHFieldMonitorNode(base.MaxwellSimNode):
|
|||
def on_inputs_changed(
|
||||
self,
|
||||
props: dict,
|
||||
managed_objs: dict[str, ct.schemas.ManagedObj],
|
||||
managed_objs: dict,
|
||||
input_sockets: dict,
|
||||
unit_systems: dict,
|
||||
):
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
|
||||
from .....assets.import_geonodes import GeoNodes, import_geonodes
|
||||
|
@ -50,13 +48,9 @@ class PowerFluxMonitorNode(base.MaxwellSimNode):
|
|||
'Time Domain': {'Time Monitor': sockets.MaxwellMonitorSocketDef()},
|
||||
}
|
||||
|
||||
managed_obj_defs: typ.ClassVar = {
|
||||
'mesh': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLMesh(name),
|
||||
),
|
||||
'modifier': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLModifier(name),
|
||||
),
|
||||
managed_obj_types: typ.ClassVar = {
|
||||
'mesh': managed_objs.ManagedBLMesh,
|
||||
'modifier': managed_objs.ManagedBLModifier,
|
||||
}
|
||||
|
||||
####################
|
||||
|
@ -98,7 +92,7 @@ class PowerFluxMonitorNode(base.MaxwellSimNode):
|
|||
center=input_sockets['Center'],
|
||||
size=input_sockets['Size'],
|
||||
name=props['sim_node_name'],
|
||||
interval_space=(1,1,1),
|
||||
interval_space=(1, 1, 1),
|
||||
freqs=input_sockets['Freqs'].realize().values,
|
||||
normal_dir='+' if input_sockets['Direction'] else '-',
|
||||
)
|
||||
|
@ -120,7 +114,7 @@ class PowerFluxMonitorNode(base.MaxwellSimNode):
|
|||
def on_inputs_changed(
|
||||
self,
|
||||
props: dict,
|
||||
managed_objs: dict[str, ct.schemas.ManagedObj],
|
||||
managed_objs: dict,
|
||||
input_sockets: dict,
|
||||
unit_systems: dict,
|
||||
):
|
||||
|
|
|
@ -6,7 +6,6 @@ import sympy as sp
|
|||
from .....utils import logger
|
||||
from ... import contracts as ct
|
||||
from ... import sockets
|
||||
from ...managed_objs.managed_bl_collection import preview_collection
|
||||
from .. import base, events
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
|
|
@ -2,10 +2,10 @@ import typing as typ
|
|||
|
||||
import pydantic as pyd
|
||||
|
||||
from ..bl import PresetName, SocketName
|
||||
from .. import contracts as ct
|
||||
|
||||
|
||||
class PresetDef(pyd.BaseModel):
|
||||
label: PresetName
|
||||
label: ct.PresetName
|
||||
description: str
|
||||
values: dict[SocketName, typ.Any]
|
||||
values: dict[ct.SocketName, typ.Any]
|
|
@ -28,14 +28,9 @@ class SimDomainNode(base.MaxwellSimNode):
|
|||
'Domain': sockets.MaxwellSimDomainSocketDef(),
|
||||
}
|
||||
|
||||
managed_obj_defs: typ.ClassVar = {
|
||||
'mesh': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLMesh(name),
|
||||
name_prefix='',
|
||||
),
|
||||
'modifier': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLModifier(name),
|
||||
),
|
||||
managed_obj_types: typ.ClassVar = {
|
||||
'mesh': managed_objs.ManagedBLMesh,
|
||||
'modifier': managed_objs.ManagedBLModifier,
|
||||
}
|
||||
|
||||
####################
|
||||
|
@ -75,7 +70,7 @@ class SimDomainNode(base.MaxwellSimNode):
|
|||
def on_input_changed(
|
||||
self,
|
||||
props: dict,
|
||||
managed_objs: dict[str, ct.schemas.ManagedObj],
|
||||
managed_objs: dict,
|
||||
input_sockets: dict,
|
||||
unit_systems: dict,
|
||||
):
|
||||
|
|
|
@ -56,11 +56,8 @@ class PlaneWaveSourceNode(base.MaxwellSimNode):
|
|||
'Source': sockets.MaxwellSourceSocketDef(),
|
||||
}
|
||||
|
||||
managed_obj_defs: typ.ClassVar = {
|
||||
'plane_wave_source': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLObject(name),
|
||||
name_prefix='',
|
||||
)
|
||||
managed_obj_types: typ.ClassVar = {
|
||||
'plane_wave_source': managed_objs.ManagedBLMesh,
|
||||
}
|
||||
|
||||
####################
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
|
||||
from ... import contracts as ct
|
||||
|
@ -27,11 +26,8 @@ class PointDipoleSourceNode(base.MaxwellSimNode):
|
|||
'Source': sockets.MaxwellSourceSocketDef(),
|
||||
}
|
||||
|
||||
managed_obj_defs = {
|
||||
'sphere_empty': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLObject(name),
|
||||
name_prefix='',
|
||||
)
|
||||
managed_obj_types = {
|
||||
'mesh': managed_objs.ManagedBLMesh,
|
||||
}
|
||||
|
||||
####################
|
||||
|
|
|
@ -41,11 +41,8 @@ class GaussianPulseTemporalShapeNode(base.MaxwellSimNode):
|
|||
'Temporal Shape': sockets.MaxwellTemporalShapeSocketDef(),
|
||||
}
|
||||
|
||||
managed_obj_defs = {
|
||||
'amp_time': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLImage(name),
|
||||
name_prefix='amp_time_',
|
||||
)
|
||||
managed_obj_types = {
|
||||
'amp_time': managed_objs.ManagedBLImage,
|
||||
}
|
||||
|
||||
####################
|
||||
|
@ -123,9 +120,9 @@ class GaussianPulseTemporalShapeNode(base.MaxwellSimNode):
|
|||
)
|
||||
def on_show_plot(
|
||||
self,
|
||||
managed_objs: dict[str, ct.schemas.ManagedObj],
|
||||
output_sockets: dict[str, typ.Any],
|
||||
props: dict[str, typ.Any],
|
||||
managed_objs: dict,
|
||||
output_sockets: dict,
|
||||
props: dict,
|
||||
):
|
||||
temporal_shape = output_sockets['Temporal Shape']
|
||||
plot_time_start = props['plot_time_start'] * 1e-15
|
||||
|
|
|
@ -27,13 +27,9 @@ class GeoNodesStructureNode(base.MaxwellSimNode):
|
|||
'Structure': sockets.MaxwellStructureSocketDef(),
|
||||
}
|
||||
|
||||
managed_obj_defs: typ.ClassVar = {
|
||||
'mesh': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLMesh(name),
|
||||
),
|
||||
'modifier': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLModifier(name),
|
||||
),
|
||||
managed_obj_types: typ.ClassVar = {
|
||||
'mesh': managed_objs.ManagedBLMesh,
|
||||
'modifier': managed_objs.ManagedBLModifier,
|
||||
}
|
||||
|
||||
####################
|
||||
|
@ -46,8 +42,8 @@ class GeoNodesStructureNode(base.MaxwellSimNode):
|
|||
)
|
||||
def compute_structure(
|
||||
self,
|
||||
input_sockets: dict[str, typ.Any],
|
||||
managed_objs: dict[str, ct.schemas.ManagedObj],
|
||||
input_sockets: dict,
|
||||
managed_objs: dict,
|
||||
) -> td.Structure:
|
||||
# Simulate Input Value Change
|
||||
## This ensures that the mesh has been re-computed.
|
||||
|
@ -68,7 +64,7 @@ class GeoNodesStructureNode(base.MaxwellSimNode):
|
|||
# - Event Methods
|
||||
####################
|
||||
@events.on_value_changed(
|
||||
socket_name='GeoNodes',
|
||||
socket_name={'GeoNodes', 'Center'},
|
||||
prop_name='preview_active',
|
||||
any_loose_input_socket=True,
|
||||
run_on_init=True,
|
||||
|
@ -83,7 +79,7 @@ class GeoNodesStructureNode(base.MaxwellSimNode):
|
|||
def on_input_changed(
|
||||
self,
|
||||
props: dict,
|
||||
managed_objs: dict[str, ct.schemas.ManagedObj],
|
||||
managed_objs: dict,
|
||||
input_sockets: dict,
|
||||
loose_input_sockets: dict,
|
||||
unit_systems: dict,
|
||||
|
|
|
@ -29,13 +29,9 @@ class BoxStructureNode(base.MaxwellSimNode):
|
|||
'Structure': sockets.MaxwellStructureSocketDef(),
|
||||
}
|
||||
|
||||
managed_obj_defs: typ.ClassVar = {
|
||||
'mesh': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLMesh(name),
|
||||
),
|
||||
'modifier': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLModifier(name),
|
||||
),
|
||||
managed_obj_types: typ.ClassVar = {
|
||||
'mesh': managed_objs.ManagedBLMesh,
|
||||
'modifier': managed_objs.ManagedBLModifier,
|
||||
}
|
||||
|
||||
####################
|
||||
|
@ -74,7 +70,7 @@ class BoxStructureNode(base.MaxwellSimNode):
|
|||
def on_inputs_changed(
|
||||
self,
|
||||
props: dict,
|
||||
managed_objs: dict[str, ct.schemas.ManagedObj],
|
||||
managed_objs: dict,
|
||||
input_sockets: dict,
|
||||
unit_systems: dict,
|
||||
):
|
||||
|
|
|
@ -28,13 +28,9 @@ class SphereStructureNode(base.MaxwellSimNode):
|
|||
'Structure': sockets.MaxwellStructureSocketDef(),
|
||||
}
|
||||
|
||||
managed_obj_defs: typ.ClassVar = {
|
||||
'mesh': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLMesh(name),
|
||||
),
|
||||
'modifier': ct.schemas.ManagedObjDef(
|
||||
mk=lambda name: managed_objs.ManagedBLModifier(name),
|
||||
),
|
||||
managed_obj_types: typ.ClassVar = {
|
||||
'mesh': managed_objs.ManagedBLMesh,
|
||||
'modifier': managed_objs.ManagedBLModifier,
|
||||
}
|
||||
|
||||
####################
|
||||
|
@ -77,7 +73,7 @@ class SphereStructureNode(base.MaxwellSimNode):
|
|||
def on_inputs_changed(
|
||||
self,
|
||||
props: dict,
|
||||
managed_objs: dict[str, ct.schemas.ManagedObj],
|
||||
managed_objs: dict,
|
||||
input_sockets: dict,
|
||||
unit_systems: dict,
|
||||
):
|
||||
|
|
|
@ -1,17 +1,46 @@
|
|||
import abc
|
||||
import functools
|
||||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import typing_extensions as typx
|
||||
|
||||
from ....utils import logger
|
||||
from ....utils import logger, serialize
|
||||
from .. import contracts as ct
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
|
||||
####################
|
||||
# - SocketDef
|
||||
####################
|
||||
class SocketDef(pyd.BaseModel, abc.ABC):
|
||||
socket_type: ct.SocketType
|
||||
|
||||
@abc.abstractmethod
|
||||
def init(self, bl_socket: bpy.types.NodeSocket) -> None:
|
||||
"""Initializes a real Blender node socket from this socket definition."""
|
||||
|
||||
####################
|
||||
# - Serialization
|
||||
####################
|
||||
def dump_as_msgspec(self) -> serialize.NaiveRepresentation:
|
||||
return [serialize.TypeID.SocketDef, self.__class__.__name__, self.model_dump()]
|
||||
|
||||
@staticmethod
|
||||
def parse_as_msgspec(obj: serialize.NaiveRepresentation) -> typ.Self:
|
||||
return next(
|
||||
subclass(**obj[2])
|
||||
for subclass in SocketDef.__subclasses__()
|
||||
if subclass.__name__ == obj[1]
|
||||
)
|
||||
|
||||
|
||||
####################
|
||||
# - SocketDef
|
||||
####################
|
||||
class MaxwellSimSocket(bpy.types.NodeSocket):
|
||||
# Fundamentals
|
||||
socket_type: ct.SocketType
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -23,7 +22,7 @@ class AnyBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class AnySocketDef(pyd.BaseModel):
|
||||
class AnySocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.Any
|
||||
|
||||
def init(self, bl_socket: AnyBLSocket) -> None:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -44,7 +43,7 @@ class BoolBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class BoolSocketDef(pyd.BaseModel):
|
||||
class BoolSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.Bool
|
||||
|
||||
default_value: bool = False
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from pathlib import Path
|
||||
|
||||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -46,7 +45,7 @@ class FilePathBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class FilePathSocketDef(pyd.BaseModel):
|
||||
class FilePathSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.FilePath
|
||||
|
||||
default_path: Path = Path()
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -43,7 +42,7 @@ class StringBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class StringSocketDef(pyd.BaseModel):
|
||||
class StringSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.String
|
||||
|
||||
default_text: str = ''
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -43,7 +42,7 @@ class BlenderCollectionBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class BlenderCollectionSocketDef(pyd.BaseModel):
|
||||
class BlenderCollectionSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.BlenderCollection
|
||||
|
||||
def init(self, bl_socket: BlenderCollectionBLSocket) -> None:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -82,7 +81,7 @@ class BlenderGeoNodesBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class BlenderGeoNodesSocketDef(pyd.BaseModel):
|
||||
class BlenderGeoNodesSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.BlenderGeoNodes
|
||||
|
||||
def init(self, bl_socket: BlenderGeoNodesBLSocket) -> None:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -43,7 +42,7 @@ class BlenderImageBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class BlenderImageSocketDef(pyd.BaseModel):
|
||||
class BlenderImageSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.BlenderImage
|
||||
|
||||
def init(self, bl_socket: BlenderImageBLSocket) -> None:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -40,7 +39,7 @@ class BlenderMaterialBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class BlenderMaterialSocketDef(pyd.BaseModel):
|
||||
class BlenderMaterialSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.BlenderMaterial
|
||||
|
||||
def init(self, bl_socket: BlenderMaterialBLSocket) -> None:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -88,7 +87,7 @@ class BlenderObjectBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class BlenderObjectSocketDef(pyd.BaseModel):
|
||||
class BlenderObjectSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.BlenderObject
|
||||
|
||||
def init(self, bl_socket: BlenderObjectBLSocket) -> None:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -43,7 +42,7 @@ class BlenderTextBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class BlenderTextSocketDef(pyd.BaseModel):
|
||||
class BlenderTextSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.BlenderText
|
||||
|
||||
def init(self, bl_socket: BlenderTextBLSocket) -> None:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import tidy3d as td
|
||||
import typing_extensions as typx
|
||||
|
||||
|
@ -53,7 +52,7 @@ class MaxwellBoundCondBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class MaxwellBoundCondSocketDef(pyd.BaseModel):
|
||||
class MaxwellBoundCondSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.MaxwellBoundCond
|
||||
|
||||
default_choice: typx.Literal['PML', 'PEC', 'PMC', 'PERIODIC'] = 'PML'
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import tidy3d as td
|
||||
|
||||
from ... import contracts as ct
|
||||
|
@ -124,7 +123,7 @@ class MaxwellBoundCondsBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class MaxwellBoundCondsSocketDef(pyd.BaseModel):
|
||||
class MaxwellBoundCondsSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.MaxwellBoundConds
|
||||
|
||||
def init(self, bl_socket: MaxwellBoundCondsBLSocket) -> None:
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -16,7 +15,7 @@ class MaxwellFDTDSimBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class MaxwellFDTDSimSocketDef(pyd.BaseModel):
|
||||
class MaxwellFDTDSimSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.MaxwellFDTDSim
|
||||
|
||||
def init(self, bl_socket: MaxwellFDTDSimBLSocket) -> None:
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -16,7 +15,7 @@ class MaxwellFDTDSimDataBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class MaxwellFDTDSimDataSocketDef(pyd.BaseModel):
|
||||
class MaxwellFDTDSimDataSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.MaxwellFDTDSimData
|
||||
|
||||
def init(self, bl_socket: MaxwellFDTDSimDataBLSocket) -> None:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import scipy as sc
|
||||
import sympy.physics.units as spu
|
||||
import tidy3d as td
|
||||
|
@ -98,7 +97,7 @@ class MaxwellMediumBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class MaxwellMediumSocketDef(pyd.BaseModel):
|
||||
class MaxwellMediumSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.MaxwellMedium
|
||||
|
||||
default_permittivity_real: float = 1.0
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -12,7 +11,7 @@ class MaxwellMediumNonLinearityBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class MaxwellMediumNonLinearitySocketDef(pyd.BaseModel):
|
||||
class MaxwellMediumNonLinearitySocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.MaxwellMediumNonLinearity
|
||||
|
||||
def init(self, bl_socket: MaxwellMediumNonLinearityBLSocket) -> None:
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -12,7 +11,7 @@ class MaxwellMonitorBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class MaxwellMonitorSocketDef(pyd.BaseModel):
|
||||
class MaxwellMonitorSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.MaxwellMonitor
|
||||
|
||||
is_list: bool = False
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -12,7 +11,7 @@ class MaxwellSimDomainBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class MaxwellSimDomainSocketDef(pyd.BaseModel):
|
||||
class MaxwellSimDomainSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.MaxwellSimDomain
|
||||
|
||||
def init(self, bl_socket: MaxwellSimDomainBLSocket) -> None:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import tidy3d as td
|
||||
|
||||
from ... import contracts as ct
|
||||
|
@ -48,7 +47,7 @@ class MaxwellSimGridBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class MaxwellSimGridSocketDef(pyd.BaseModel):
|
||||
class MaxwellSimGridSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.MaxwellSimGrid
|
||||
|
||||
min_steps_per_wl: float = 10.0
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -12,7 +11,7 @@ class MaxwellSimGridAxisBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class MaxwellSimGridAxisSocketDef(pyd.BaseModel):
|
||||
class MaxwellSimGridAxisSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.MaxwellSimGridAxis
|
||||
|
||||
def init(self, bl_socket: MaxwellSimGridAxisBLSocket) -> None:
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -12,7 +11,7 @@ class MaxwellSourceBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class MaxwellSourceSocketDef(pyd.BaseModel):
|
||||
class MaxwellSourceSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.MaxwellSource
|
||||
|
||||
is_list: bool = False
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -12,7 +11,7 @@ class MaxwellStructureBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class MaxwellStructureSocketDef(pyd.BaseModel):
|
||||
class MaxwellStructureSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.MaxwellStructure
|
||||
|
||||
is_list: bool = False
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -12,7 +11,7 @@ class MaxwellTemporalShapeBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class MaxwellTemporalShapeSocketDef(pyd.BaseModel):
|
||||
class MaxwellTemporalShapeSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.MaxwellTemporalShape
|
||||
|
||||
def init(self, bl_socket: MaxwellTemporalShapeBLSocket) -> None:
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy as sp
|
||||
|
||||
from .....utils.pydantic_sympy import SympyExpr
|
||||
|
@ -119,7 +118,7 @@ class ComplexNumberBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class ComplexNumberSocketDef(pyd.BaseModel):
|
||||
class ComplexNumberSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.ComplexNumber
|
||||
|
||||
default_value: SympyExpr = sp.S(0 + 0j)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -44,7 +43,7 @@ class IntegerNumberBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class IntegerNumberSocketDef(pyd.BaseModel):
|
||||
class IntegerNumberSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.IntegerNumber
|
||||
|
||||
default_value: int = 0
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy as sp
|
||||
|
||||
from .....utils.pydantic_sympy import SympyExpr
|
||||
|
@ -55,7 +54,7 @@ class RationalNumberBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class RationalNumberSocketDef(pyd.BaseModel):
|
||||
class RationalNumberSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.RationalNumber
|
||||
|
||||
default_value: SympyExpr = sp.Rational(0, 1)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from .....utils.pydantic_sympy import SympyExpr
|
||||
from ... import contracts as ct
|
||||
|
@ -49,7 +48,7 @@ class RealNumberBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class RealNumberSocketDef(pyd.BaseModel):
|
||||
class RealNumberSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.RealNumber
|
||||
|
||||
default_value: float = 0.0
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from .....utils.pydantic_sympy import SympyExpr
|
||||
|
@ -47,7 +46,7 @@ class PhysicalAccelScalarBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalAccelScalarSocketDef(pyd.BaseModel):
|
||||
class PhysicalAccelScalarSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.PhysicalAccelScalar
|
||||
|
||||
default_unit: SympyExpr | None = None
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from .....utils.pydantic_sympy import SympyExpr
|
||||
|
@ -47,7 +46,7 @@ class PhysicalAngleBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalAngleSocketDef(pyd.BaseModel):
|
||||
class PhysicalAngleSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.PhysicalAngle
|
||||
|
||||
default_unit: SympyExpr | None = None
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy as sp
|
||||
|
||||
from ... import contracts as ct
|
||||
|
@ -55,7 +54,7 @@ class PhysicalAreaBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalAreaSocketDef(pyd.BaseModel):
|
||||
class PhysicalAreaSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.PhysicalArea
|
||||
|
||||
default_unit: typ.Any | None = None
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from .....utils.pydantic_sympy import SympyExpr
|
||||
|
@ -47,7 +46,7 @@ class PhysicalForceScalarBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalForceScalarSocketDef(pyd.BaseModel):
|
||||
class PhysicalForceScalarSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.PhysicalForceScalar
|
||||
|
||||
default_unit: SympyExpr | None = None
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from .....utils import extra_sympy_units as spux
|
||||
from .....utils import logger
|
||||
|
@ -97,7 +95,7 @@ class PhysicalFreqBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalFreqSocketDef(pyd.BaseModel):
|
||||
class PhysicalFreqSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.PhysicalFreq
|
||||
is_array: bool = False
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
|
||||
|
@ -96,7 +95,7 @@ class PhysicalLengthBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalLengthSocketDef(pyd.BaseModel):
|
||||
class PhysicalLengthSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.PhysicalLength
|
||||
is_array: bool = False
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from .....utils.pydantic_sympy import SympyExpr
|
||||
|
@ -47,7 +46,7 @@ class PhysicalMassBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalMassSocketDef(pyd.BaseModel):
|
||||
class PhysicalMassSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.PhysicalMass
|
||||
|
||||
default_unit: SympyExpr | None = None
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
|
||||
|
@ -48,7 +47,7 @@ class PhysicalPoint3DBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalPoint3DSocketDef(pyd.BaseModel):
|
||||
class PhysicalPoint3DSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.PhysicalPoint3D
|
||||
|
||||
default_unit: typ.Any | None = None
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy as sp
|
||||
import sympy.physics.optics.polarization as spo_pol
|
||||
import sympy.physics.units as spu
|
||||
|
@ -237,7 +236,7 @@ class PhysicalPolBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalPolSocketDef(pyd.BaseModel):
|
||||
class PhysicalPolSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.PhysicalPol
|
||||
|
||||
def init(self, bl_socket: PhysicalPolBLSocket) -> None:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
|
||||
|
@ -46,7 +45,7 @@ class PhysicalSize3DBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalSize3DSocketDef(pyd.BaseModel):
|
||||
class PhysicalSize3DSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.PhysicalSize3D
|
||||
|
||||
default_value: SympyExpr = sp.Matrix([1, 1, 1]) * spu.um
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from .....utils.pydantic_sympy import SympyExpr
|
||||
|
@ -47,7 +46,7 @@ class PhysicalSpeedBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalSpeedSocketDef(pyd.BaseModel):
|
||||
class PhysicalSpeedSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.PhysicalSpeed
|
||||
|
||||
default_unit: SympyExpr | None = None
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from .....utils.pydantic_sympy import SympyExpr
|
||||
|
@ -49,7 +48,7 @@ class PhysicalTimeBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalTimeSocketDef(pyd.BaseModel):
|
||||
class PhysicalTimeSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.PhysicalTime
|
||||
|
||||
default_value: SympyExpr | None = None
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from .....utils.pydantic_sympy import SympyExpr
|
||||
from ... import contracts as ct
|
||||
|
@ -273,7 +272,7 @@ class PhysicalUnitSystemBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalUnitSystemSocketDef(pyd.BaseModel):
|
||||
class PhysicalUnitSystemSocketDef(base.SocketDef):
|
||||
socket_type: ST = ST.PhysicalUnitSystem
|
||||
|
||||
show_by_default: bool = False
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from .....utils.pydantic_sympy import SympyExpr
|
||||
|
@ -44,7 +43,7 @@ class PhysicalVolumeBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalVolumeSocketDef(pyd.BaseModel):
|
||||
class PhysicalVolumeSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.PhysicalVolume
|
||||
|
||||
default_unit: SympyExpr | None = None
|
||||
|
|
|
@ -3,9 +3,10 @@ import types
|
|||
from .. import contracts as ct
|
||||
|
||||
|
||||
## TODO: Replace with BL_SOCKET_DEFS export from each module, a little like BL_NODES.
|
||||
def scan_for_socket_defs(
|
||||
sockets_module: types.ModuleType,
|
||||
) -> dict[ct.SocketType, type[ct.schemas.SocketDef]]:
|
||||
) -> dict:
|
||||
return {
|
||||
socket_type: getattr(
|
||||
sockets_module,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from .....services import tdcloud
|
||||
from ... import contracts as ct
|
||||
|
@ -319,7 +318,7 @@ class Tidy3DCloudTaskBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class Tidy3DCloudTaskSocketDef(pyd.BaseModel):
|
||||
class Tidy3DCloudTaskSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.Tidy3DCloudTask
|
||||
|
||||
should_exist: bool
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -15,7 +14,7 @@ class Complex2DVectorBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class Complex2DVectorSocketDef(pyd.BaseModel):
|
||||
class Complex2DVectorSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.Complex2DVector
|
||||
|
||||
def init(self, bl_socket: Complex2DVectorBLSocket) -> None:
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import pydantic as pyd
|
||||
|
||||
from ... import contracts as ct
|
||||
from .. import base
|
||||
|
@ -15,7 +14,7 @@ class Complex3DVectorBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class Complex3DVectorSocketDef(pyd.BaseModel):
|
||||
class Complex3DVectorSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.Complex3DVector
|
||||
|
||||
def init(self, bl_socket: Complex3DVectorBLSocket) -> None:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy as sp
|
||||
|
||||
from .....utils.pydantic_sympy import ConstrSympyExpr
|
||||
|
@ -54,7 +53,7 @@ class Integer3DVectorBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class Integer3DVectorSocketDef(pyd.BaseModel):
|
||||
class Integer3DVectorSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.Integer3DVector
|
||||
|
||||
default_value: Integer3DVector = sp.Matrix([0, 0, 0])
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy as sp
|
||||
|
||||
from .....utils.pydantic_sympy import ConstrSympyExpr
|
||||
|
@ -55,7 +54,7 @@ class Real2DVectorBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class Real2DVectorSocketDef(pyd.BaseModel):
|
||||
class Real2DVectorSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.Real2DVector
|
||||
|
||||
default_value: Real2DVector = sp.Matrix([0.0, 0.0])
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import bpy
|
||||
import pydantic as pyd
|
||||
import sympy as sp
|
||||
|
||||
from .....utils.pydantic_sympy import ConstrSympyExpr
|
||||
|
@ -55,7 +54,7 @@ class Real3DVectorBLSocket(base.MaxwellSimSocket):
|
|||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class Real3DVectorSocketDef(pyd.BaseModel):
|
||||
class Real3DVectorSocketDef(base.SocketDef):
|
||||
socket_type: ct.SocketType = ct.SocketType.Real3DVector
|
||||
|
||||
default_value: Real3DVector = sp.Matrix([0.0, 0.0, 0.0])
|
||||
|
|
|
@ -5,6 +5,8 @@ import typing as typ
|
|||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
|
||||
SympyType = sp.Basic | sp.Expr | sp.MatrixBase | spu.Quantity
|
||||
|
||||
|
||||
####################
|
||||
# - Useful Methods
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
"""Robust serialization tool for use in the addon.
|
||||
|
||||
Attributes:
|
||||
NaiveEncodableType: See <https://jcristharif.com/msgspec/supported-types.html> for details.
|
||||
"""
|
||||
|
||||
import dataclasses
|
||||
import datetime as dt
|
||||
import decimal
|
||||
import enum
|
||||
import functools
|
||||
import typing as typ
|
||||
import uuid
|
||||
|
||||
import msgspec
|
||||
import sympy as sp
|
||||
|
||||
from . import extra_sympy_units as spux
|
||||
from . import logger
|
||||
|
||||
log = logger.get(__name__)
|
||||
|
||||
####################
|
||||
# - Serialization Types
|
||||
####################
|
||||
NaivelyEncodableType: typ.TypeAlias = (
|
||||
None
|
||||
| bool
|
||||
| int
|
||||
| float
|
||||
| str
|
||||
| bytes
|
||||
| bytearray
|
||||
## NO SUPPORT:
|
||||
# | memoryview
|
||||
| tuple
|
||||
| list
|
||||
| dict
|
||||
| set
|
||||
| frozenset
|
||||
## NO SUPPORT:
|
||||
# | typ.Literal
|
||||
| typ.Collection
|
||||
## NO SUPPORT:
|
||||
# | typ.Sequence ## -> list
|
||||
# | typ.MutableSequence ## -> list
|
||||
# | typ.AbstractSet ## -> set
|
||||
# | typ.MutableSet ## -> set
|
||||
# | typ.Mapping ## -> dict
|
||||
# | typ.MutableMapping ## -> dict
|
||||
| typ.TypedDict
|
||||
| typ.NamedTuple
|
||||
| dt.datetime
|
||||
| dt.date
|
||||
| dt.time
|
||||
| dt.timedelta
|
||||
| uuid.UUID
|
||||
| decimal.Decimal
|
||||
## NO SUPPORT:
|
||||
# | enum.Enum
|
||||
| enum.IntEnum
|
||||
| enum.Flag
|
||||
| enum.IntFlag
|
||||
| dataclasses.dataclass
|
||||
| typ.Optional[typ.Any] # noqa: UP007
|
||||
| typ.Union[typ.Any, ...] # noqa: UP007
|
||||
| typ.NewType
|
||||
| typ.TypeAlias
|
||||
## SUPPORT:
|
||||
# | typ.Generic[typ.Any]
|
||||
# | typ.TypeVar
|
||||
# | typ.Final
|
||||
| msgspec.Raw
|
||||
## NO SUPPORT:
|
||||
# | msgspec.UNSET
|
||||
)
|
||||
_NaivelyEncodableTypeSet = frozenset(typ.get_args(NaivelyEncodableType))
|
||||
## TODO: Use for runtime type check? Beartype?
|
||||
|
||||
|
||||
class TypeID(enum.StrEnum):
|
||||
Complex: str = '!type=complex'
|
||||
SympyType: str = '!type=sympytype'
|
||||
SocketDef: str = '!type=socketdef'
|
||||
ManagedObj: str = '!type=managedobj'
|
||||
|
||||
|
||||
NaiveRepresentation: typ.TypeAlias = list[TypeID, str | None, typ.Any]
|
||||
|
||||
|
||||
def is_representation(obj: NaivelyEncodableType) -> bool:
|
||||
return isinstance(obj, list) and len(obj) == 3 and obj[0] in set(TypeID) # noqa: PLR2004
|
||||
|
||||
|
||||
####################
|
||||
# - Serialization Hooks
|
||||
####################
|
||||
def _enc_hook(obj: typ.Any) -> NaivelyEncodableType:
|
||||
"""Translates types not natively supported by `msgspec`, to an encodable form supported by `msgspec`.
|
||||
|
||||
Parameters:
|
||||
obj: The object of arbitrary type to transform into an encodable value.
|
||||
|
||||
Returns:
|
||||
A value encodable by `msgspec`.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: When the type transformation hasn't been implemented.
|
||||
"""
|
||||
if isinstance(obj, complex):
|
||||
return ['!type=complex', None, (obj.real, obj.imag)]
|
||||
|
||||
if isinstance(obj, spux.SympyType):
|
||||
return ['!type=sympytype', None, sp.srepr(obj)]
|
||||
|
||||
if hasattr(obj, 'dump_as_msgspec'):
|
||||
return obj.dump_as_msgspec()
|
||||
|
||||
msg = f'Can\'t encode "{obj}" of type {type(obj)}'
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
|
||||
def _dec_hook(_type: type, obj: NaivelyEncodableType) -> typ.Any:
|
||||
"""Translates the `msgspec`-encoded form of an object back to its true form.
|
||||
|
||||
Parameters:
|
||||
_type: The type to transform the `msgspec`-encoded object back into.
|
||||
obj: The naively decoded object to transform back into its actual type.
|
||||
|
||||
Returns:
|
||||
A value encodable by `msgspec`.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: When the type transformation hasn't been implemented.
|
||||
"""
|
||||
if _type is complex or (is_representation(obj) and obj[0] == TypeID.Complex):
|
||||
obj_value = obj[2]
|
||||
return complex(obj_value[0], obj_value[1])
|
||||
|
||||
if _type in typ.get_args(spux.SympyType) or (
|
||||
is_representation(obj) and obj[0] == TypeID.SympyType
|
||||
):
|
||||
obj_value = obj[2]
|
||||
return sp.sympify(obj_value).subs(spux.ALL_UNIT_SYMBOLS)
|
||||
|
||||
if hasattr(_type, 'parse_as_msgspec') and (
|
||||
is_representation(obj) and obj[0] in [TypeID.SocketDef, TypeID.ManagedObj]
|
||||
):
|
||||
return _type.parse_as_msgspec(obj)
|
||||
|
||||
msg = f'Can\'t decode "{obj}" to type {type(obj)}'
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
|
||||
####################
|
||||
# - Global Encoders / Decoders
|
||||
####################
|
||||
_ENCODER = msgspec.json.Encoder(enc_hook=_enc_hook, order='deterministic')
|
||||
|
||||
|
||||
@functools.cache
|
||||
def _DECODER(_type: type) -> msgspec.json.Decoder: # noqa: N802
|
||||
"""Retrieve a suitable `msgspec.json.Decoder` by-type.
|
||||
|
||||
Parameters:
|
||||
_type: The type to retrieve a decoder for.
|
||||
|
||||
Returns:
|
||||
A suitable decoder.
|
||||
"""
|
||||
return msgspec.json.Decoder(type=_type, dec_hook=_dec_hook)
|
||||
|
||||
|
||||
####################
|
||||
# - Encoder / Decoder Functions
|
||||
####################
|
||||
def encode(obj: typ.Any) -> bytes:
|
||||
return _ENCODER.encode(obj)
|
||||
|
||||
|
||||
def decode(_type: type, obj: str | bytes) -> typ.Any:
|
||||
return _DECODER(_type).decode(obj)
|
|
@ -9,7 +9,6 @@ import bpy
|
|||
PATH_SCRIPT = str(Path(__file__).resolve().parent)
|
||||
sys.path.insert(0, str(PATH_SCRIPT))
|
||||
import info # noqa: E402
|
||||
import pack # noqa: E402
|
||||
|
||||
sys.path.remove(str(PATH_SCRIPT))
|
||||
|
||||
|
|
Loading…
Reference in New Issue