fix: reordered init to suppress warnings and unit-conversion fix

main
Sofus Albert Høgsbro Rose 2024-05-15 14:08:00 +02:00
parent c9936b8942
commit af358a4d32
Signed by: so-rose
GPG Key ID: AD901CB0F3701434
8 changed files with 59 additions and 37 deletions

View File

@ -56,6 +56,7 @@ class ParamsFlow:
msg = f"Symbols in {symbol_values} don't perfectly match the ParamsFlow symbols {self.symbols}"
raise ValueError(msg)
## TODO: MutableDenseMatrix causes error with 'in' check bc it isn't hashable.
return [
spux.scale_to_unit_system(arg, unit_system, use_jax_array=True)
if arg not in symbol_values

View File

@ -30,6 +30,7 @@ from ... import base, events
log = logger.get(__name__)
FUNCS = {
# Number | Number
'ADD': lambda exprs: exprs[0] + exprs[1],
'SUB': lambda exprs: exprs[0] - exprs[1],
'MUL': lambda exprs: exprs[0] * exprs[1],

View File

@ -974,16 +974,19 @@ class MaxwellSimNode(bpy.types.Node, bl_instance.BLInstance):
Notes:
Run by Blender when a new instance of a node is added to a tree.
"""
# Initialize Sockets
## -> Ensures the availability of static sockets before items/methods.
## -> Ensures the availability of static sockets before items/methods.
self._sync_sockets()
# Initialize Instance ID
## -> This is used by various caches from 'bl_cache'.
## -> Also generates (first-time) the various enums.
self.reset_instance_id()
# Initialize Sockets
## -> Ensures the availability of static sockets before dynamic fields.
self._sync_sockets()
# Initialize Dynamic Field Persistance
## -> Ensures the availability of enum items for subsequent setters.
self.regenerate_dynamic_field_persistance()
# Initialize Name
## -> Ensures the availability of sim_node_name immediately.
self.sim_node_name = self.name

View File

@ -51,6 +51,7 @@ class SocketDef(pyd.BaseModel, abc.ABC):
bl_socket: The Blender node socket to alter using data from this SocketDef.
"""
bl_socket.reset_instance_id()
bl_socket.regenerate_dynamic_field_persistance()
def postinit(self, bl_socket: bpy.types.NodeSocket) -> None:
"""Pre-initialize a real Blender node socket from this socket definition.
@ -205,11 +206,12 @@ class MaxwellSimSocket(bpy.types.NodeSocket, bl_instance.BLInstance):
"""
## TODO: Evaluate this properly
if self.is_initializing:
log.debug(
'%s: Rejected on_prop_changed("%s") while initializing',
self.bl_label,
prop_name,
)
pass
# log.debug(
# '%s: Rejected on_prop_changed("%s") while initializing',
# self.bl_label,
# prop_name,
# )
elif hasattr(self, prop_name):
# Property Callbacks: Active Kind
if prop_name == 'active_kind':

View File

@ -214,9 +214,7 @@ class ExprBLSocket(base.MaxwellSimSocket):
return None
@bl_cache.cached_bl_property()
def prev_unit(self) -> spux.Unit | None:
return self.unit
prev_unit: str | None = bl_cache.BLField(None)
####################
# - Prop-Change Callback
@ -231,19 +229,21 @@ class ExprBLSocket(base.MaxwellSimSocket):
## -> 1. "Laggy" unit must be different than new unit.
## -> 2. Unit-conversion of value only within same physical_type
## -> 3. Never unit-convert expressions w/symbolic variables
## No matter what, prev_unit is always re-armed.
## No matter what, prev_unit is always regenerated.
prev_unit = (
spux.unit_str_to_unit(self.prev_unit)
if self.prev_unit is not None
else None
)
if (
self.prev_unit != self.unit
and self.prev_unit in self.physical_type.valid_units
prev_unit != self.unit
and prev_unit in self.physical_type.valid_units
and not self.symbols
):
log.critical(self.value, self.prev_unit, self.unit)
self.value = spu.convert_to(self.value, self.prev_unit)
log.critical(self.value, self.prev_unit, self.unit)
self.lazy_array_range = self.lazy_array_range.rescale_to_unit(
self.prev_unit
)
self.prev_unit = bl_cache.Signal.InvalidateCache
self.value = self.value.subs({self.unit: prev_unit})
self.lazy_array_range = self.lazy_array_range.correct_unit(prev_unit)
self.prev_unit = self.active_unit
####################
# - Value Utilities
@ -378,18 +378,22 @@ class ExprBLSocket(base.MaxwellSimSocket):
),
},
NS.Vec2: {
MT_Z: lambda: sp.Matrix([Z(i) for i in self.raw_value_int2]),
MT_Q: lambda: sp.Matrix([Q(q[0], q[1]) for q in self.raw_value_rat2]),
MT_R: lambda: sp.Matrix([R(r) for r in self.raw_value_float2]),
MT_C: lambda: sp.Matrix(
MT_Z: lambda: sp.ImmutableMatrix([Z(i) for i in self.raw_value_int2]),
MT_Q: lambda: sp.ImmutableMatrix(
[Q(q[0], q[1]) for q in self.raw_value_rat2]
),
MT_R: lambda: sp.ImmutableMatrix([R(r) for r in self.raw_value_float2]),
MT_C: lambda: sp.ImmutableMatrix(
[c[0] + sp.I * c[1] for c in self.raw_value_complex2]
),
},
NS.Vec3: {
MT_Z: lambda: sp.Matrix([Z(i) for i in self.raw_value_int3]),
MT_Q: lambda: sp.Matrix([Q(q[0], q[1]) for q in self.raw_value_rat3]),
MT_R: lambda: sp.Matrix([R(r) for r in self.raw_value_float3]),
MT_C: lambda: sp.Matrix(
MT_Z: lambda: sp.ImmutableMatrix([Z(i) for i in self.raw_value_int3]),
MT_Q: lambda: sp.ImmutableMatrix(
[Q(q[0], q[1]) for q in self.raw_value_rat3]
),
MT_R: lambda: sp.ImmutableMatrix([R(r) for r in self.raw_value_float3]),
MT_C: lambda: sp.ImmutableMatrix(
[c[0] + sp.I * c[1] for c in self.raw_value_complex3]
),
},
@ -1185,11 +1189,13 @@ class ExprSocketDef(base.SocketDef):
# FlowKind.Value
## -> We must take units into account when setting bl_socket.value
if self.physical_type is not spux.PhysicalType.NonPhysical:
self.active_unit = sp.sstr(self.default_unit)
bl_socket.active_unit = sp.sstr(self.default_unit)
bl_socket.value = self.default_value * self.default_unit
else:
bl_socket.value = self.default_value
bl_socket.prev_unit = bl_socket.active_unit
# FlowKind.LazyArrayRange
## -> We can directly pass None to unit.
bl_socket.lazy_array_range = ct.LazyArrayRangeFlow(

View File

@ -75,6 +75,9 @@ class CachedBLProperty:
self.decode_type: type = inspect.signature(getter_method).return_annotation
# Write Suppressing
self.suppress_write: dict[str, bool] = {}
# Check Non-Empty Type Annotation
## For now, just presume that all types can be encoded/decoded.
if self.decode_type is inspect.Signature.empty:
@ -122,6 +125,10 @@ class CachedBLProperty:
return Signal.CacheNotReady
return cached_value
def suppress_next_write(self, bl_instance) -> None:
self.suppress_write[bl_instance.instance_id] = True
## TODO: Make it a context manager to prevent the worst of surprises
def __set__(
self, bl_instance: bl_instance.BLInstance | None, value: typ.Any
) -> None:
@ -144,7 +151,10 @@ class CachedBLProperty:
# Fill Caches
## -> persist: Fill Persist and Non-Persist Cache
## -> else: Fill Non-Persist Cache
if self.persist:
if self.persist and not self.suppress_write.get(
bl_instance.instance_id
):
self.suppress_next_write(bl_instance)
self.bl_prop.write(bl_instance, self.getter_method(bl_instance))
else:
@ -162,7 +172,7 @@ class CachedBLProperty:
self.setter_method(bl_instance, value)
# Fill Non-Persistant (and maybe Persistent) Cache
if self.persist:
if self.persist and not self.suppress_write.get(bl_instance.instance_id):
self.bl_prop.write(bl_instance, self.getter_method(bl_instance))
else:

View File

@ -20,7 +20,6 @@
import typing as typ
from blender_maxwell import contracts as ct
from blender_maxwell.utils import bl_instance, logger
from .signal import Signal
@ -94,8 +93,9 @@ def read(
# Check if Instance ID is Available
if not bl_instance.instance_id:
log.debug(
"Can't Get CachedBLProperty: Instance ID not (yet) defined on bl_instance.BLInstance %s",
'%s (Non-Persist): Tried read() (key=%s), but Instance ID not (yet) defined',
str(bl_instance),
str(key),
)
return Signal.CacheNotReady

View File

@ -74,7 +74,6 @@ class BLInstance:
The Instance ID is a `UUID4`, which is globally unique, negating the need for extraneous overlap-checks.
"""
self.instance_id = str(uuid.uuid4())
self.regenerate_dynamic_field_persistance()
@classmethod
def assert_attrs_valid(cls, mandatory_props: set[str]) -> None: