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.main
parent
999d601c49
commit
084ae632f1
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
|
||||
####################
|
||||
ADDON_CACHE = PATH_ADDON_ROOT / '.addon_cache'
|
||||
ADDON_CACHE.mkdir(exist_ok=True)
|
||||
DEFAULT_ADDON_CACHE = PATH_ADDON_ROOT / '.addon_cache'
|
||||
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 {
|
||||
# Blender
|
||||
# Basic
|
||||
BLST.Bool: ST.String,
|
||||
BLST.Bool: ST.Bool,
|
||||
# Float
|
||||
# Array-Like
|
||||
BLST.Color: ST.Color,
|
||||
|
|
|
@ -69,7 +69,8 @@ class FlowKind(enum.StrEnum):
|
|||
flow_obj,
|
||||
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:
|
||||
return spux.scale_to_unit_system(
|
||||
flow_obj,
|
||||
|
|
|
@ -352,6 +352,22 @@ class LazyArrayRangeFlow:
|
|||
####################
|
||||
# - 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(
|
||||
self,
|
||||
symbol_values: dict[spux.Symbol, typ.Any] = MappingProxyType({}),
|
||||
|
@ -377,12 +393,8 @@ class LazyArrayRangeFlow:
|
|||
raise ValueError(msg)
|
||||
|
||||
# Realize Symbols
|
||||
realized_start = spux.sympy_to_python(
|
||||
self.start.subs({sym: symbol_values[sym.name] for sym in self.symbols})
|
||||
)
|
||||
realized_stop = spux.sympy_to_python(
|
||||
self.stop.subs({sym: symbol_values[sym.name] for sym in self.symbols})
|
||||
)
|
||||
realized_start = self.realize_start(symbol_values)
|
||||
realized_stop = self.realize_stop(symbol_values)
|
||||
|
||||
# Return Linspace / Logspace
|
||||
def gen_array() -> jtyp.Inexact[jtyp.Array, ' steps']:
|
||||
|
|
|
@ -110,9 +110,15 @@ def write_modifier_geonodes(
|
|||
|
||||
for socket_name in modifier_attrs['inputs']:
|
||||
iface_id = socket_infos[socket_name].bl_isocket_identifier
|
||||
bl_modifier[iface_id] = spux.scale_to_unit_system(
|
||||
modifier_attrs['inputs'][socket_name], modifier_attrs['unit_system']
|
||||
)
|
||||
input_value = modifier_attrs['inputs'][socket_name]
|
||||
|
||||
if isinstance(input_value, spux.SympyType):
|
||||
bl_modifier[iface_id] = spux.scale_to_unit_system(
|
||||
input_value, modifier_attrs['unit_system']
|
||||
)
|
||||
else:
|
||||
bl_modifier[iface_id] = input_value
|
||||
|
||||
modifier_altered = True
|
||||
## TODO: More fine-grained alterations
|
||||
|
||||
|
|
|
@ -164,7 +164,6 @@ class VizTarget(enum.StrEnum):
|
|||
@staticmethod
|
||||
def valid_targets_for(viz_mode: VizMode) -> list[typ.Self] | None:
|
||||
return {
|
||||
None: [],
|
||||
VizMode.Hist1D: [VizTarget.Plot2D],
|
||||
VizMode.BoxPlot1D: [VizTarget.Plot2D],
|
||||
VizMode.Curve2D: [VizTarget.Plot2D],
|
||||
|
@ -227,7 +226,7 @@ class VizNode(base.MaxwellSimNode):
|
|||
## - Properties
|
||||
#####################
|
||||
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(
|
||||
prop_ui=True, enum_cb=lambda self, _: self.search_targets()
|
||||
|
@ -249,8 +248,8 @@ class VizNode(base.MaxwellSimNode):
|
|||
|
||||
return None
|
||||
|
||||
def search_modes(self) -> list[ct.BLEnumElement]:
|
||||
if not ct.FlowSignal.check(self.data_info):
|
||||
def search_viz_modes(self) -> list[ct.BLEnumElement]:
|
||||
if self.data_info is not None:
|
||||
return [
|
||||
(
|
||||
viz_mode,
|
||||
|
|
|
@ -261,17 +261,24 @@ class MaxwellSimNode(bpy.types.Node):
|
|||
####################
|
||||
@events.on_value_changed(
|
||||
prop_name='sim_node_name',
|
||||
props={'sim_node_name'},
|
||||
stop_propagation=True,
|
||||
)
|
||||
def _on_sim_node_name_changed(self):
|
||||
def _on_sim_node_name_changed(self, props):
|
||||
log.info(
|
||||
'Changed Sim Node Name of a "%s" to "%s" (self=%s)',
|
||||
self.bl_idname,
|
||||
self.sim_node_name,
|
||||
props['sim_node_name'],
|
||||
str(self),
|
||||
)
|
||||
|
||||
# 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
|
||||
|
||||
@events.on_value_changed(prop_name='active_socket_set')
|
||||
|
|
|
@ -80,7 +80,6 @@ class ReloadTrackedTask(bpy.types.Operator):
|
|||
def execute(self, context):
|
||||
node = context.node
|
||||
tdcloud.TidyCloudTasks.update_task(node.cloud_task)
|
||||
node.sim_data = bl_cache.Signal.InvalidateCache
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
@ -137,7 +136,7 @@ class Tidy3DWebRunnerNode(base.MaxwellSimNode):
|
|||
|
||||
return task_info
|
||||
|
||||
@bl_cache.cached_bl_property(persist=False)
|
||||
@property
|
||||
def sim_data(self) -> td.Simulation | None:
|
||||
"""Retrieve the simulation data of the current cloud task from the input socket.
|
||||
|
||||
|
@ -155,7 +154,7 @@ class Tidy3DWebRunnerNode(base.MaxwellSimNode):
|
|||
self.cloud_task,
|
||||
tdcloud.TidyCloudTasks.task_info(
|
||||
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:
|
||||
return None
|
||||
|
@ -250,12 +249,6 @@ class Tidy3DWebRunnerNode(base.MaxwellSimNode):
|
|||
####################
|
||||
# - 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(
|
||||
'Sim Data',
|
||||
props={'sim_data'},
|
||||
|
|
|
@ -135,6 +135,48 @@ class EHFieldMonitorNode(base.MaxwellSimNode):
|
|||
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
|
||||
####################
|
||||
|
|
|
@ -132,7 +132,7 @@ class PowerFluxMonitorNode(base.MaxwellSimNode):
|
|||
size=input_sockets['Size'],
|
||||
name=props['sim_node_name'],
|
||||
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 '-',
|
||||
)
|
||||
|
||||
|
|
|
@ -190,7 +190,9 @@ class Tidy3DWebExporterNode(base.MaxwellSimNode):
|
|||
has_uploaded_task = self.uploaded_task_id != ''
|
||||
|
||||
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
|
||||
|
||||
@property
|
||||
|
@ -199,9 +201,8 @@ class Tidy3DWebExporterNode(base.MaxwellSimNode):
|
|||
|
||||
If one can't be loaded, return None.
|
||||
"""
|
||||
has_uploaded_task = self.uploaded_task_id != ''
|
||||
|
||||
if has_uploaded_task:
|
||||
uploaded_task = self.uploaded_task
|
||||
if uploaded_task is not None:
|
||||
return tdcloud.TidyCloudTasks.task_info(self.uploaded_task_id)
|
||||
return None
|
||||
|
||||
|
|
|
@ -979,6 +979,16 @@ class MaxwellSimSocket(bpy.types.NodeSocket):
|
|||
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
|
||||
####################
|
||||
|
|
|
@ -225,7 +225,7 @@ class ExprBLSocket(base.MaxwellSimSocket):
|
|||
|
||||
# Workaround: Manually Jiggle FlowKind Invalidation
|
||||
self.value = self.value
|
||||
self.lazy_value_range = self.lazy_value_range
|
||||
self.lazy_array_range = self.lazy_array_range
|
||||
|
||||
####################
|
||||
# - Property Callback
|
||||
|
|
|
@ -46,6 +46,23 @@ class BLMaxwellAddonPrefs(bpy.types.AddonPreferences):
|
|||
####################
|
||||
# - 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
|
||||
use_default_pydeps_path: bpy.props.BoolProperty(
|
||||
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()
|
||||
|
||||
|
||||
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
|
||||
|
||||
# PyDeps Path
|
||||
addon_prefs.use_default_pydeps_path = False
|
||||
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
|
||||
bpy.ops.wm.save_userpref()
|
||||
|
@ -92,7 +98,9 @@ if __name__ == '__main__':
|
|||
) as 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()
|
||||
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_DEPS = PATH_DEV / '.cached-dev-dependencies'
|
||||
PATH_ADDON_DEV_CACHE = PATH_DEV / '.dev-addon-cache'
|
||||
PATH_ADDON_DEV_DEPS.mkdir(exist_ok=True)
|
||||
|
|
Loading…
Reference in New Issue