fix: fixed bugs preventing end-to-end sim
Several bugs/gotchas/papercuts have been fixed, which together made it really hard Closes #47, #48, #49, #50, #51, #52.
parent
999d601c49
commit
20c9e6f902
Binary file not shown.
BIN
src/blender_maxwell/assets/internal/monitor/_monitor_eh_field.blend (Stored with Git LFS)
BIN
src/blender_maxwell/assets/internal/monitor/_monitor_eh_field.blend (Stored with Git LFS)
Binary file not shown.
BIN
src/blender_maxwell/assets/internal/monitor/_monitor_power_flux.blend (Stored with Git LFS)
BIN
src/blender_maxwell/assets/internal/monitor/_monitor_power_flux.blend (Stored with Git LFS)
Binary file not shown.
BIN
src/blender_maxwell/assets/internal/simulation/_simulation_sim_domain.blend (Stored with Git LFS)
BIN
src/blender_maxwell/assets/internal/simulation/_simulation_sim_domain.blend (Stored with Git LFS)
Binary file not shown.
BIN
src/blender_maxwell/assets/internal/structure/_structure_primitive_box.blend (Stored with Git LFS)
BIN
src/blender_maxwell/assets/internal/structure/_structure_primitive_box.blend (Stored with Git LFS)
Binary file not shown.
BIN
src/blender_maxwell/assets/internal/structure/_structure_primitive_ring.blend (Stored with Git LFS)
BIN
src/blender_maxwell/assets/internal/structure/_structure_primitive_ring.blend (Stored with Git LFS)
Binary file not shown.
BIN
src/blender_maxwell/assets/internal/structure/_structure_primitive_sphere.blend (Stored with Git LFS)
BIN
src/blender_maxwell/assets/internal/structure/_structure_primitive_sphere.blend (Stored with Git LFS)
Binary file not shown.
|
@ -48,10 +48,10 @@ ORIGINAL_SYS_PATH = sys.path.copy()
|
||||||
####################
|
####################
|
||||||
# - Local Addon Cache
|
# - Local Addon Cache
|
||||||
####################
|
####################
|
||||||
ADDON_CACHE = PATH_ADDON_ROOT / '.addon_cache'
|
DEFAULT_ADDON_CACHE = PATH_ADDON_ROOT / '.addon_cache'
|
||||||
ADDON_CACHE.mkdir(exist_ok=True)
|
DEFAULT_ADDON_CACHE.mkdir(exist_ok=True)
|
||||||
|
|
||||||
PIP_INSTALL_LOG = ADDON_CACHE / 'pip_install.log'
|
PIP_INSTALL_LOG = DEFAULT_ADDON_CACHE / 'pip_install.log'
|
||||||
|
|
||||||
|
|
||||||
####################
|
####################
|
||||||
|
|
|
@ -133,7 +133,7 @@ class BLSocketType(enum.StrEnum):
|
||||||
return {
|
return {
|
||||||
# Blender
|
# Blender
|
||||||
# Basic
|
# Basic
|
||||||
BLST.Bool: ST.String,
|
BLST.Bool: ST.Bool,
|
||||||
# Float
|
# Float
|
||||||
# Array-Like
|
# Array-Like
|
||||||
BLST.Color: ST.Color,
|
BLST.Color: ST.Color,
|
||||||
|
|
|
@ -69,7 +69,8 @@ class FlowKind(enum.StrEnum):
|
||||||
flow_obj,
|
flow_obj,
|
||||||
unit_system: spux.UnitSystem,
|
unit_system: spux.UnitSystem,
|
||||||
):
|
):
|
||||||
log.debug('%s: Scaling "%s" to Unit System', kind, str(flow_obj))
|
# log.debug('%s: Scaling "%s" to Unit System', kind, str(flow_obj))
|
||||||
|
## TODO: Use a hot-path logger.
|
||||||
if kind == FlowKind.Value:
|
if kind == FlowKind.Value:
|
||||||
return spux.scale_to_unit_system(
|
return spux.scale_to_unit_system(
|
||||||
flow_obj,
|
flow_obj,
|
||||||
|
|
|
@ -352,6 +352,22 @@ class LazyArrayRangeFlow:
|
||||||
####################
|
####################
|
||||||
# - Realization
|
# - Realization
|
||||||
####################
|
####################
|
||||||
|
def realize_start(
|
||||||
|
self,
|
||||||
|
symbol_values: dict[spux.Symbol, typ.Any] = MappingProxyType({}),
|
||||||
|
) -> ArrayFlow | LazyValueFuncFlow:
|
||||||
|
return spux.sympy_to_python(
|
||||||
|
self.start.subs({sym: symbol_values[sym.name] for sym in self.symbols})
|
||||||
|
)
|
||||||
|
|
||||||
|
def realize_stop(
|
||||||
|
self,
|
||||||
|
symbol_values: dict[spux.Symbol, typ.Any] = MappingProxyType({}),
|
||||||
|
) -> ArrayFlow | LazyValueFuncFlow:
|
||||||
|
return spux.sympy_to_python(
|
||||||
|
self.stop.subs({sym: symbol_values[sym.name] for sym in self.symbols})
|
||||||
|
)
|
||||||
|
|
||||||
def realize(
|
def realize(
|
||||||
self,
|
self,
|
||||||
symbol_values: dict[spux.Symbol, typ.Any] = MappingProxyType({}),
|
symbol_values: dict[spux.Symbol, typ.Any] = MappingProxyType({}),
|
||||||
|
@ -377,12 +393,8 @@ class LazyArrayRangeFlow:
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
# Realize Symbols
|
# Realize Symbols
|
||||||
realized_start = spux.sympy_to_python(
|
realized_start = self.realize_start(symbol_values)
|
||||||
self.start.subs({sym: symbol_values[sym.name] for sym in self.symbols})
|
realized_stop = self.realize_stop(symbol_values)
|
||||||
)
|
|
||||||
realized_stop = spux.sympy_to_python(
|
|
||||||
self.stop.subs({sym: symbol_values[sym.name] for sym in self.symbols})
|
|
||||||
)
|
|
||||||
|
|
||||||
# Return Linspace / Logspace
|
# Return Linspace / Logspace
|
||||||
def gen_array() -> jtyp.Inexact[jtyp.Array, ' steps']:
|
def gen_array() -> jtyp.Inexact[jtyp.Array, ' steps']:
|
||||||
|
|
|
@ -110,9 +110,15 @@ def write_modifier_geonodes(
|
||||||
|
|
||||||
for socket_name in modifier_attrs['inputs']:
|
for socket_name in modifier_attrs['inputs']:
|
||||||
iface_id = socket_infos[socket_name].bl_isocket_identifier
|
iface_id = socket_infos[socket_name].bl_isocket_identifier
|
||||||
|
input_value = modifier_attrs['inputs'][socket_name]
|
||||||
|
|
||||||
|
if isinstance(input_value, spux.SympyType):
|
||||||
bl_modifier[iface_id] = spux.scale_to_unit_system(
|
bl_modifier[iface_id] = spux.scale_to_unit_system(
|
||||||
modifier_attrs['inputs'][socket_name], modifier_attrs['unit_system']
|
input_value, modifier_attrs['unit_system']
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
bl_modifier[iface_id] = input_value
|
||||||
|
|
||||||
modifier_altered = True
|
modifier_altered = True
|
||||||
## TODO: More fine-grained alterations
|
## TODO: More fine-grained alterations
|
||||||
|
|
||||||
|
|
|
@ -164,7 +164,6 @@ class VizTarget(enum.StrEnum):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def valid_targets_for(viz_mode: VizMode) -> list[typ.Self] | None:
|
def valid_targets_for(viz_mode: VizMode) -> list[typ.Self] | None:
|
||||||
return {
|
return {
|
||||||
None: [],
|
|
||||||
VizMode.Hist1D: [VizTarget.Plot2D],
|
VizMode.Hist1D: [VizTarget.Plot2D],
|
||||||
VizMode.BoxPlot1D: [VizTarget.Plot2D],
|
VizMode.BoxPlot1D: [VizTarget.Plot2D],
|
||||||
VizMode.Curve2D: [VizTarget.Plot2D],
|
VizMode.Curve2D: [VizTarget.Plot2D],
|
||||||
|
@ -227,7 +226,7 @@ class VizNode(base.MaxwellSimNode):
|
||||||
## - Properties
|
## - Properties
|
||||||
#####################
|
#####################
|
||||||
viz_mode: enum.Enum = bl_cache.BLField(
|
viz_mode: enum.Enum = bl_cache.BLField(
|
||||||
prop_ui=True, enum_cb=lambda self, _: self.search_modes()
|
prop_ui=True, enum_cb=lambda self, _: self.search_viz_modes()
|
||||||
)
|
)
|
||||||
viz_target: enum.Enum = bl_cache.BLField(
|
viz_target: enum.Enum = bl_cache.BLField(
|
||||||
prop_ui=True, enum_cb=lambda self, _: self.search_targets()
|
prop_ui=True, enum_cb=lambda self, _: self.search_targets()
|
||||||
|
@ -249,8 +248,8 @@ class VizNode(base.MaxwellSimNode):
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def search_modes(self) -> list[ct.BLEnumElement]:
|
def search_viz_modes(self) -> list[ct.BLEnumElement]:
|
||||||
if not ct.FlowSignal.check(self.data_info):
|
if self.data_info is not None:
|
||||||
return [
|
return [
|
||||||
(
|
(
|
||||||
viz_mode,
|
viz_mode,
|
||||||
|
|
|
@ -261,17 +261,24 @@ class MaxwellSimNode(bpy.types.Node):
|
||||||
####################
|
####################
|
||||||
@events.on_value_changed(
|
@events.on_value_changed(
|
||||||
prop_name='sim_node_name',
|
prop_name='sim_node_name',
|
||||||
|
props={'sim_node_name'},
|
||||||
stop_propagation=True,
|
stop_propagation=True,
|
||||||
)
|
)
|
||||||
def _on_sim_node_name_changed(self):
|
def _on_sim_node_name_changed(self, props):
|
||||||
log.info(
|
log.info(
|
||||||
'Changed Sim Node Name of a "%s" to "%s" (self=%s)',
|
'Changed Sim Node Name of a "%s" to "%s" (self=%s)',
|
||||||
self.bl_idname,
|
self.bl_idname,
|
||||||
self.sim_node_name,
|
props['sim_node_name'],
|
||||||
str(self),
|
str(self),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set Name of Managed Objects
|
# Set Name of Managed Objects
|
||||||
|
for mobj in self.managed_objs.values():
|
||||||
|
mobj.name = props['sim_node_name']
|
||||||
|
|
||||||
|
## Invalidate Cache
|
||||||
|
## -> Persistance doesn't happen if we simply mutate.
|
||||||
|
## -> This ensures that the name change is picked up.
|
||||||
self.managed_objs = bl_cache.Signal.InvalidateCache
|
self.managed_objs = bl_cache.Signal.InvalidateCache
|
||||||
|
|
||||||
@events.on_value_changed(prop_name='active_socket_set')
|
@events.on_value_changed(prop_name='active_socket_set')
|
||||||
|
|
|
@ -80,7 +80,6 @@ class ReloadTrackedTask(bpy.types.Operator):
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
node = context.node
|
node = context.node
|
||||||
tdcloud.TidyCloudTasks.update_task(node.cloud_task)
|
tdcloud.TidyCloudTasks.update_task(node.cloud_task)
|
||||||
node.sim_data = bl_cache.Signal.InvalidateCache
|
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
@ -137,7 +136,7 @@ class Tidy3DWebRunnerNode(base.MaxwellSimNode):
|
||||||
|
|
||||||
return task_info
|
return task_info
|
||||||
|
|
||||||
@bl_cache.cached_bl_property(persist=False)
|
@property
|
||||||
def sim_data(self) -> td.Simulation | None:
|
def sim_data(self) -> td.Simulation | None:
|
||||||
"""Retrieve the simulation data of the current cloud task from the input socket.
|
"""Retrieve the simulation data of the current cloud task from the input socket.
|
||||||
|
|
||||||
|
@ -155,7 +154,7 @@ class Tidy3DWebRunnerNode(base.MaxwellSimNode):
|
||||||
self.cloud_task,
|
self.cloud_task,
|
||||||
tdcloud.TidyCloudTasks.task_info(
|
tdcloud.TidyCloudTasks.task_info(
|
||||||
self.cloud_task.task_id
|
self.cloud_task.task_id
|
||||||
).disk_cache_path(ct.addon.ADDON_CACHE),
|
).disk_cache_path(ct.addon.prefs().addon_cache_path),
|
||||||
)
|
)
|
||||||
if sim_data is None:
|
if sim_data is None:
|
||||||
return None
|
return None
|
||||||
|
@ -250,12 +249,6 @@ class Tidy3DWebRunnerNode(base.MaxwellSimNode):
|
||||||
####################
|
####################
|
||||||
# - Output Methods
|
# - Output Methods
|
||||||
####################
|
####################
|
||||||
@events.on_value_changed(
|
|
||||||
socket_name='Cloud Task',
|
|
||||||
)
|
|
||||||
def compute_cloud_task(self) -> None:
|
|
||||||
self.sim_data = bl_cache.Signal.InvalidateCache
|
|
||||||
|
|
||||||
@events.computes_output_socket(
|
@events.computes_output_socket(
|
||||||
'Sim Data',
|
'Sim Data',
|
||||||
props={'sim_data'},
|
props={'sim_data'},
|
||||||
|
|
|
@ -135,6 +135,48 @@ class EHFieldMonitorNode(base.MaxwellSimNode):
|
||||||
freqs=input_sockets['Freqs'].realize().values,
|
freqs=input_sockets['Freqs'].realize().values,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@events.computes_output_socket(
|
||||||
|
'Time Monitor',
|
||||||
|
props={'sim_node_name'},
|
||||||
|
input_sockets={
|
||||||
|
'Center',
|
||||||
|
'Size',
|
||||||
|
'Spatial Subdivs',
|
||||||
|
'Time Range',
|
||||||
|
'Temporal Subdivs',
|
||||||
|
},
|
||||||
|
input_socket_kinds={
|
||||||
|
'Time Range': ct.FlowKind.LazyArrayRange,
|
||||||
|
},
|
||||||
|
unit_systems={'Tidy3DUnits': ct.UNITS_TIDY3D},
|
||||||
|
scale_input_sockets={
|
||||||
|
'Center': 'Tidy3DUnits',
|
||||||
|
'Size': 'Tidy3DUnits',
|
||||||
|
'Time Range': 'Tidy3DUnits',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
def compute_time_monitor(
|
||||||
|
self,
|
||||||
|
input_sockets: dict,
|
||||||
|
props: dict,
|
||||||
|
unit_systems: dict,
|
||||||
|
) -> td.FieldMonitor:
|
||||||
|
log.info(
|
||||||
|
'Computing FieldMonitor (name="%s") with center="%s", size="%s"',
|
||||||
|
props['sim_node_name'],
|
||||||
|
input_sockets['Center'],
|
||||||
|
input_sockets['Size'],
|
||||||
|
)
|
||||||
|
return td.FieldTimeMonitor(
|
||||||
|
center=input_sockets['Center'],
|
||||||
|
size=input_sockets['Size'],
|
||||||
|
name=props['sim_node_name'],
|
||||||
|
interval_space=tuple(input_sockets['Spatial Subdivs']),
|
||||||
|
start=input_sockets['Time Range'].realize_start(),
|
||||||
|
stop=input_sockets['Time Range'].realize_stop(),
|
||||||
|
interval=input_sockets['Temporal Subdivs'],
|
||||||
|
)
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - Preview
|
# - Preview
|
||||||
####################
|
####################
|
||||||
|
|
|
@ -132,7 +132,7 @@ class PowerFluxMonitorNode(base.MaxwellSimNode):
|
||||||
size=input_sockets['Size'],
|
size=input_sockets['Size'],
|
||||||
name=props['sim_node_name'],
|
name=props['sim_node_name'],
|
||||||
interval_space=(1, 1, 1),
|
interval_space=(1, 1, 1),
|
||||||
freqs=input_sockets['Freqs'].realize_array,
|
freqs=input_sockets['Freqs'].realize_array.values,
|
||||||
normal_dir='+' if input_sockets['Direction'] else '-',
|
normal_dir='+' if input_sockets['Direction'] else '-',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -190,7 +190,9 @@ class Tidy3DWebExporterNode(base.MaxwellSimNode):
|
||||||
has_uploaded_task = self.uploaded_task_id != ''
|
has_uploaded_task = self.uploaded_task_id != ''
|
||||||
|
|
||||||
if has_uploaded_task:
|
if has_uploaded_task:
|
||||||
return tdcloud.TidyCloudTasks.task(self.uploaded_task_id)
|
return tdcloud.TidyCloudTasks.tasks(self.new_cloud_task.cloud_folder).get(
|
||||||
|
self.uploaded_task_id
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -199,9 +201,8 @@ class Tidy3DWebExporterNode(base.MaxwellSimNode):
|
||||||
|
|
||||||
If one can't be loaded, return None.
|
If one can't be loaded, return None.
|
||||||
"""
|
"""
|
||||||
has_uploaded_task = self.uploaded_task_id != ''
|
uploaded_task = self.uploaded_task
|
||||||
|
if uploaded_task is not None:
|
||||||
if has_uploaded_task:
|
|
||||||
return tdcloud.TidyCloudTasks.task_info(self.uploaded_task_id)
|
return tdcloud.TidyCloudTasks.task_info(self.uploaded_task_id)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -979,6 +979,16 @@ class MaxwellSimSocket(bpy.types.NodeSocket):
|
||||||
col: Target for defining UI elements.
|
col: Target for defining UI elements.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def draw_lazy_value_func(self, col: bpy.types.UILayout) -> None:
|
||||||
|
"""Draws the socket lazy value function UI on its own line.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
Should be overriden by individual socket classes, if they have an editable `FlowKind.LazyValueFunc`.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
col: Target for defining UI elements.
|
||||||
|
"""
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - UI Methods: Auxilliary
|
# - UI Methods: Auxilliary
|
||||||
####################
|
####################
|
||||||
|
|
|
@ -225,7 +225,7 @@ class ExprBLSocket(base.MaxwellSimSocket):
|
||||||
|
|
||||||
# Workaround: Manually Jiggle FlowKind Invalidation
|
# Workaround: Manually Jiggle FlowKind Invalidation
|
||||||
self.value = self.value
|
self.value = self.value
|
||||||
self.lazy_value_range = self.lazy_value_range
|
self.lazy_array_range = self.lazy_array_range
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - Property Callback
|
# - Property Callback
|
||||||
|
|
|
@ -46,6 +46,23 @@ class BLMaxwellAddonPrefs(bpy.types.AddonPreferences):
|
||||||
####################
|
####################
|
||||||
# - Properties
|
# - Properties
|
||||||
####################
|
####################
|
||||||
|
# Addon Cache Path
|
||||||
|
bl__addon_cache_path: bpy.props.StringProperty(
|
||||||
|
name='Addon Cache Path',
|
||||||
|
description='Path to Addon Cache',
|
||||||
|
subtype='FILE_PATH',
|
||||||
|
default=str(ct.addon.DEFAULT_ADDON_CACHE),
|
||||||
|
update=lambda self, _: self.on_addon_pydeps_changed(),
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def addon_cache_path(self) -> Path:
|
||||||
|
return Path(bpy.path.abspath(self.bl__addon_cache_path))
|
||||||
|
|
||||||
|
@addon_cache_path.setter
|
||||||
|
def addon_cache_path(self, path: Path) -> None:
|
||||||
|
self.bl__addon_cache_path = str(path.resolve())
|
||||||
|
|
||||||
# PyDeps Default Path
|
# PyDeps Default Path
|
||||||
use_default_pydeps_path: bpy.props.BoolProperty(
|
use_default_pydeps_path: bpy.props.BoolProperty(
|
||||||
name='Use Default PyDeps Path',
|
name='Use Default PyDeps Path',
|
||||||
|
|
|
@ -68,12 +68,18 @@ def install_and_enable_addon(addon_name: str, addon_zip: Path) -> None:
|
||||||
bpy.ops.wm.save_userpref()
|
bpy.ops.wm.save_userpref()
|
||||||
|
|
||||||
|
|
||||||
def setup_for_development(addon_name: str, path_addon_dev_deps: Path) -> None:
|
def setup_for_development(
|
||||||
|
addon_name: str,
|
||||||
|
path_addon_dev_deps: Path,
|
||||||
|
path_addon_cache_path: Path | None = None,
|
||||||
|
) -> None:
|
||||||
addon_prefs = bpy.context.preferences.addons[addon_name].preferences
|
addon_prefs = bpy.context.preferences.addons[addon_name].preferences
|
||||||
|
|
||||||
# PyDeps Path
|
# PyDeps Path
|
||||||
addon_prefs.use_default_pydeps_path = False
|
addon_prefs.use_default_pydeps_path = False
|
||||||
addon_prefs.pydeps_path = path_addon_dev_deps
|
addon_prefs.pydeps_path = path_addon_dev_deps
|
||||||
|
if path_addon_cache_path is not None:
|
||||||
|
addon_prefs.addon_cache_path = path_addon_cache_path
|
||||||
|
|
||||||
# Save User Preferences
|
# Save User Preferences
|
||||||
bpy.ops.wm.save_userpref()
|
bpy.ops.wm.save_userpref()
|
||||||
|
@ -92,7 +98,9 @@ if __name__ == '__main__':
|
||||||
) as path_zipped:
|
) as path_zipped:
|
||||||
install_and_enable_addon(info.ADDON_NAME, path_zipped)
|
install_and_enable_addon(info.ADDON_NAME, path_zipped)
|
||||||
|
|
||||||
setup_for_development(info.ADDON_NAME, info.PATH_ADDON_DEV_DEPS)
|
setup_for_development(
|
||||||
|
info.ADDON_NAME, info.PATH_ADDON_DEV_DEPS, info.PATH_ADDON_DEV_CACHE
|
||||||
|
)
|
||||||
|
|
||||||
bpy.ops.wm.quit_blender()
|
bpy.ops.wm.quit_blender()
|
||||||
sys.exit(info.STATUS_INSTALLED_ADDON)
|
sys.exit(info.STATUS_INSTALLED_ADDON)
|
||||||
|
|
|
@ -77,4 +77,5 @@ BOOTSTRAP_LOG_LEVEL_FILENAME = '.bootstrap_log_level'
|
||||||
PATH_ADDON_DEV_BLEND = PATH_DEV / 'demo.blend'
|
PATH_ADDON_DEV_BLEND = PATH_DEV / 'demo.blend'
|
||||||
|
|
||||||
PATH_ADDON_DEV_DEPS = PATH_DEV / '.cached-dev-dependencies'
|
PATH_ADDON_DEV_DEPS = PATH_DEV / '.cached-dev-dependencies'
|
||||||
|
PATH_ADDON_DEV_CACHE = PATH_DEV / '.dev-addon-cache'
|
||||||
PATH_ADDON_DEV_DEPS.mkdir(exist_ok=True)
|
PATH_ADDON_DEV_DEPS.mkdir(exist_ok=True)
|
||||||
|
|
Loading…
Reference in New Issue