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

View File

@ -30,6 +30,7 @@ from ... import base, events
log = logger.get(__name__) log = logger.get(__name__)
FUNCS = { FUNCS = {
# Number | Number
'ADD': lambda exprs: exprs[0] + exprs[1], 'ADD': lambda exprs: exprs[0] + exprs[1],
'SUB': lambda exprs: exprs[0] - exprs[1], 'SUB': lambda exprs: exprs[0] - exprs[1],
'MUL': 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: Notes:
Run by Blender when a new instance of a node is added to a tree. 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 # Initialize Instance ID
## -> This is used by various caches from 'bl_cache'. ## -> This is used by various caches from 'bl_cache'.
## -> Also generates (first-time) the various enums. ## -> Also generates (first-time) the various enums.
self.reset_instance_id() 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 # Initialize Name
## -> Ensures the availability of sim_node_name immediately. ## -> Ensures the availability of sim_node_name immediately.
self.sim_node_name = self.name 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: The Blender node socket to alter using data from this SocketDef.
""" """
bl_socket.reset_instance_id() bl_socket.reset_instance_id()
bl_socket.regenerate_dynamic_field_persistance()
def postinit(self, bl_socket: bpy.types.NodeSocket) -> None: def postinit(self, bl_socket: bpy.types.NodeSocket) -> None:
"""Pre-initialize a real Blender node socket from this socket definition. """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 ## TODO: Evaluate this properly
if self.is_initializing: if self.is_initializing:
log.debug( pass
'%s: Rejected on_prop_changed("%s") while initializing', # log.debug(
self.bl_label, # '%s: Rejected on_prop_changed("%s") while initializing',
prop_name, # self.bl_label,
) # prop_name,
# )
elif hasattr(self, prop_name): elif hasattr(self, prop_name):
# Property Callbacks: Active Kind # Property Callbacks: Active Kind
if prop_name == 'active_kind': if prop_name == 'active_kind':

View File

@ -214,9 +214,7 @@ class ExprBLSocket(base.MaxwellSimSocket):
return None return None
@bl_cache.cached_bl_property() prev_unit: str | None = bl_cache.BLField(None)
def prev_unit(self) -> spux.Unit | None:
return self.unit
#################### ####################
# - Prop-Change Callback # - Prop-Change Callback
@ -231,19 +229,21 @@ class ExprBLSocket(base.MaxwellSimSocket):
## -> 1. "Laggy" unit must be different than new unit. ## -> 1. "Laggy" unit must be different than new unit.
## -> 2. Unit-conversion of value only within same physical_type ## -> 2. Unit-conversion of value only within same physical_type
## -> 3. Never unit-convert expressions w/symbolic variables ## -> 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 ( if (
self.prev_unit != self.unit prev_unit != self.unit
and self.prev_unit in self.physical_type.valid_units and prev_unit in self.physical_type.valid_units
and not self.symbols and not self.symbols
): ):
log.critical(self.value, self.prev_unit, self.unit) self.value = self.value.subs({self.unit: prev_unit})
self.value = spu.convert_to(self.value, self.prev_unit) self.lazy_array_range = self.lazy_array_range.correct_unit(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.active_unit
self.prev_unit
)
self.prev_unit = bl_cache.Signal.InvalidateCache
#################### ####################
# - Value Utilities # - Value Utilities
@ -378,18 +378,22 @@ class ExprBLSocket(base.MaxwellSimSocket):
), ),
}, },
NS.Vec2: { NS.Vec2: {
MT_Z: lambda: sp.Matrix([Z(i) for i in self.raw_value_int2]), MT_Z: lambda: sp.ImmutableMatrix([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_Q: lambda: sp.ImmutableMatrix(
MT_R: lambda: sp.Matrix([R(r) for r in self.raw_value_float2]), [Q(q[0], q[1]) for q in self.raw_value_rat2]
MT_C: lambda: sp.Matrix( ),
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] [c[0] + sp.I * c[1] for c in self.raw_value_complex2]
), ),
}, },
NS.Vec3: { NS.Vec3: {
MT_Z: lambda: sp.Matrix([Z(i) for i in self.raw_value_int3]), MT_Z: lambda: sp.ImmutableMatrix([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_Q: lambda: sp.ImmutableMatrix(
MT_R: lambda: sp.Matrix([R(r) for r in self.raw_value_float3]), [Q(q[0], q[1]) for q in self.raw_value_rat3]
MT_C: lambda: sp.Matrix( ),
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] [c[0] + sp.I * c[1] for c in self.raw_value_complex3]
), ),
}, },
@ -1185,11 +1189,13 @@ class ExprSocketDef(base.SocketDef):
# FlowKind.Value # FlowKind.Value
## -> We must take units into account when setting bl_socket.value ## -> We must take units into account when setting bl_socket.value
if self.physical_type is not spux.PhysicalType.NonPhysical: 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 bl_socket.value = self.default_value * self.default_unit
else: else:
bl_socket.value = self.default_value bl_socket.value = self.default_value
bl_socket.prev_unit = bl_socket.active_unit
# FlowKind.LazyArrayRange # FlowKind.LazyArrayRange
## -> We can directly pass None to unit. ## -> We can directly pass None to unit.
bl_socket.lazy_array_range = ct.LazyArrayRangeFlow( 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 self.decode_type: type = inspect.signature(getter_method).return_annotation
# Write Suppressing
self.suppress_write: dict[str, bool] = {}
# Check Non-Empty Type Annotation # Check Non-Empty Type Annotation
## For now, just presume that all types can be encoded/decoded. ## For now, just presume that all types can be encoded/decoded.
if self.decode_type is inspect.Signature.empty: if self.decode_type is inspect.Signature.empty:
@ -122,6 +125,10 @@ class CachedBLProperty:
return Signal.CacheNotReady return Signal.CacheNotReady
return cached_value 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__( def __set__(
self, bl_instance: bl_instance.BLInstance | None, value: typ.Any self, bl_instance: bl_instance.BLInstance | None, value: typ.Any
) -> None: ) -> None:
@ -144,7 +151,10 @@ class CachedBLProperty:
# Fill Caches # Fill Caches
## -> persist: Fill Persist and Non-Persist Cache ## -> persist: Fill Persist and Non-Persist Cache
## -> else: Fill 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)) self.bl_prop.write(bl_instance, self.getter_method(bl_instance))
else: else:
@ -162,7 +172,7 @@ class CachedBLProperty:
self.setter_method(bl_instance, value) self.setter_method(bl_instance, value)
# Fill Non-Persistant (and maybe Persistent) Cache # 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)) self.bl_prop.write(bl_instance, self.getter_method(bl_instance))
else: else:

View File

@ -20,7 +20,6 @@
import typing as typ import typing as typ
from blender_maxwell import contracts as ct
from blender_maxwell.utils import bl_instance, logger from blender_maxwell.utils import bl_instance, logger
from .signal import Signal from .signal import Signal
@ -94,8 +93,9 @@ def read(
# Check if Instance ID is Available # Check if Instance ID is Available
if not bl_instance.instance_id: if not bl_instance.instance_id:
log.debug( 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(bl_instance),
str(key),
) )
return Signal.CacheNotReady 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. The Instance ID is a `UUID4`, which is globally unique, negating the need for extraneous overlap-checks.
""" """
self.instance_id = str(uuid.uuid4()) self.instance_id = str(uuid.uuid4())
self.regenerate_dynamic_field_persistance()
@classmethod @classmethod
def assert_attrs_valid(cls, mandatory_props: set[str]) -> None: def assert_attrs_valid(cls, mandatory_props: set[str]) -> None: