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.
Sofus Albert Høgsbro Rose 2024-05-05 14:26:09 +02:00
parent 999d601c49
commit 20c9e6f902
Signed by: so-rose
GPG Key ID: AD901CB0F3701434
23 changed files with 148 additions and 48 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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'
####################

View File

@ -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,

View File

@ -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,

View File

@ -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']:

View File

@ -110,9 +110,15 @@ def write_modifier_geonodes(
for socket_name in modifier_attrs['inputs']:
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(
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
## TODO: More fine-grained alterations

View File

@ -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,

View File

@ -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')

View File

@ -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'},

View File

@ -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
####################

View File

@ -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 '-',
)

View File

@ -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

View File

@ -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
####################

View File

@ -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

View File

@ -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',

View File

@ -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)

View File

@ -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)