133 lines
3.3 KiB
Python
133 lines
3.3 KiB
Python
import bpy
|
|
import sympy as sp
|
|
import sympy.physics.units as spu
|
|
import scipy as sc
|
|
|
|
from .....utils import analyze_geonodes
|
|
from ... import contracts as ct
|
|
from ... import sockets
|
|
from .. import base
|
|
from ... import managed_objs
|
|
|
|
GEONODES_DOMAIN_BOX = "simdomain_box"
|
|
|
|
class SimDomainNode(base.MaxwellSimNode):
|
|
node_type = ct.NodeType.SimDomain
|
|
bl_label = "Sim Domain"
|
|
|
|
input_sockets = {
|
|
"Duration": sockets.PhysicalTimeSocketDef(
|
|
default_value = 5 * spu.ps,
|
|
default_unit = spu.ps,
|
|
),
|
|
"Center": sockets.PhysicalSize3DSocketDef(),
|
|
"Size": sockets.PhysicalSize3DSocketDef(),
|
|
"Grid": sockets.MaxwellSimGridSocketDef(),
|
|
"Ambient Medium": sockets.MaxwellMediumSocketDef(),
|
|
}
|
|
output_sockets = {
|
|
"Domain": sockets.MaxwellSimDomainSocketDef(),
|
|
}
|
|
|
|
managed_obj_defs = {
|
|
"domain_box": ct.schemas.ManagedObjDef(
|
|
mk=lambda name: managed_objs.ManagedBLObject(name),
|
|
name_prefix="domain_box_",
|
|
)
|
|
}
|
|
|
|
####################
|
|
# - Callbacks
|
|
####################
|
|
@base.computes_output_socket(
|
|
"Domain",
|
|
input_sockets={"Duration", "Center", "Size", "Grid", "Ambient Medium"},
|
|
)
|
|
def compute_sim_domain(self, input_sockets: dict) -> sp.Expr:
|
|
if all([
|
|
(_duration := input_sockets["Duration"]),
|
|
(_center := input_sockets["Center"]),
|
|
(_size := input_sockets["Size"]),
|
|
(grid := input_sockets["Grid"]),
|
|
(medium := input_sockets["Ambient Medium"]),
|
|
]):
|
|
duration = spu.convert_to(_duration, spu.second) / spu.second
|
|
center = tuple(spu.convert_to(_center, spu.um) / spu.um)
|
|
size = tuple(spu.convert_to(_size, spu.um) / spu.um)
|
|
return dict(
|
|
run_time=duration,
|
|
center=center,
|
|
size=size,
|
|
grid_spec=grid,
|
|
medium=medium,
|
|
)
|
|
|
|
####################
|
|
# - Preview
|
|
####################
|
|
@base.on_value_changed(
|
|
socket_name={"Center", "Size"},
|
|
input_sockets={"Center", "Size"},
|
|
managed_objs={"domain_box"},
|
|
)
|
|
def on_value_changed__center_size(
|
|
self,
|
|
input_sockets: dict,
|
|
managed_objs: dict[str, ct.schemas.ManagedObj],
|
|
):
|
|
_center = input_sockets["Center"]
|
|
center = tuple([
|
|
float(el)
|
|
for el in spu.convert_to(_center, spu.um) / spu.um
|
|
])
|
|
|
|
_size = input_sockets["Size"]
|
|
size = tuple([
|
|
float(el)
|
|
for el in spu.convert_to(_size, spu.um) / spu.um
|
|
])
|
|
## TODO: Preview unit system?? Presume um for now
|
|
|
|
# Retrieve Hard-Coded GeoNodes and Analyze Input
|
|
geo_nodes = bpy.data.node_groups[GEONODES_DOMAIN_BOX]
|
|
geonodes_interface = analyze_geonodes.interface(
|
|
geo_nodes, direc="INPUT"
|
|
)
|
|
|
|
# Sync Modifier Inputs
|
|
managed_objs["domain_box"].sync_geonodes_modifier(
|
|
geonodes_node_group=geo_nodes,
|
|
geonodes_identifier_to_value={
|
|
geonodes_interface["Size"].identifier: size,
|
|
## TODO: Use 'bl_socket_map.value_to_bl`!
|
|
## - This accounts for auto-conversion, unit systems, etc. .
|
|
## - We could keep it in the node base class...
|
|
## - ...But it needs aligning with Blender, too. Hmm.
|
|
}
|
|
)
|
|
|
|
# Sync Object Position
|
|
managed_objs["domain_box"].bl_object("MESH").location = center
|
|
|
|
@base.on_show_preview(
|
|
managed_objs={"domain_box"},
|
|
)
|
|
def on_show_preview(
|
|
self,
|
|
managed_objs: dict[str, ct.schemas.ManagedObj],
|
|
):
|
|
managed_objs["domain_box"].show_preview("MESH")
|
|
self.on_value_changed__center_size()
|
|
|
|
####################
|
|
# - Blender Registration
|
|
####################
|
|
BL_REGISTER = [
|
|
SimDomainNode,
|
|
]
|
|
BL_NODES = {
|
|
ct.NodeType.SimDomain: (
|
|
ct.NodeCategory.MAXWELLSIM_SIMS
|
|
)
|
|
}
|