From e8b5f8baf22894f71666fa2488838b189ff34e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sofus=20Albert=20H=C3=B8gsbro=20Rose?= Date: Mon, 19 Feb 2024 18:36:16 +0100 Subject: [PATCH] feat: More sockets, nodes, fixes. We're starting to have a very advanced socket-based language for defining nodes. It's very practical already. The priorities are 1. All the nodes! 2. Sockets, including default values, as needed. 3. Library constants, mediums. 4. Output socket previews w/geonodes, geonodes structures. 5. Utilities including arrays (and selected array multi-input) The code is still very spaghetti. This is very much still the "first, make it run" part of the system design. --- .../node_trees/maxwell_sim_nodes/contracts.py | 116 +++++++++++++++++- .../maxwell_sim_nodes/nodes/base.py | 49 ++++++-- .../nodes/inputs/constants/number_constant.py | 23 ++-- .../inputs/constants/physical_constant.py | 74 ++++++++++- .../maxwell_sim_nodes/nodes/kitchen_sink.py | 24 ++-- .../nodes/simulations/fdtd_sim.py | 26 ++-- .../nodes/sources/point_dipole_source.py | 33 +++-- .../gaussian_pulse_temporal_shape.py | 82 ++++++++++++- .../structures/primitives/box_structure.py | 41 ++----- .../maxwell_sim_nodes/sockets/__init__.py | 7 +- .../maxwell_sim_nodes/sockets/base.py | 20 ++- .../sockets/basic/__init__.py | 4 + .../sockets/basic/bool_socket.py | 73 +++++++++++ .../sockets/basic/text_socket.py | 3 + .../sockets/maxwell/__init__.py | 1 + .../sockets/maxwell/medium_socket.py | 4 +- .../sockets/number/real_number_socket.py | 8 -- .../sockets/physical/__init__.py | 22 +++- ...accel_socket.py => accel_scalar_socket.py} | 28 ++--- .../sockets/physical/angle_socket.py | 21 +++- .../sockets/physical/area_socket.py | 3 - .../sockets/physical/force_scalar_socket.py | 56 +++++++++ .../sockets/physical/force_socket.py | 41 ------- .../sockets/physical/freq_socket.py | 16 ++- .../sockets/physical/length_socket.py | 21 +++- .../sockets/physical/point_3d_socket.py | 67 ++++++++++ .../sockets/physical/size_3d_socket.py | 67 ++++++++++ .../sockets/physical/time_socket.py | 21 +++- .../sockets/physical/volume_socket.py | 3 - blender_maxwell/requirements.txt | 1 + 30 files changed, 751 insertions(+), 204 deletions(-) create mode 100644 blender_maxwell/node_trees/maxwell_sim_nodes/sockets/basic/bool_socket.py rename blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/{accel_socket.py => accel_scalar_socket.py} (61%) create mode 100644 blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/force_scalar_socket.py delete mode 100644 blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/force_socket.py create mode 100644 blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/point_3d_socket.py create mode 100644 blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/size_3d_socket.py diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/contracts.py b/blender_maxwell/node_trees/maxwell_sim_nodes/contracts.py index 6a55df7..a417a04 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/contracts.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/contracts.py @@ -79,6 +79,7 @@ class TreeType(BlenderTypeEnum): class SocketType(BlenderTypeEnum): # Base Any = enum.auto() + Bool = enum.auto() Text = enum.auto() FilePath = enum.auto() @@ -104,11 +105,19 @@ class SocketType(BlenderTypeEnum): PhysicalArea = enum.auto() PhysicalVolume = enum.auto() + PhysicalPoint2D = enum.auto() + PhysicalPoint3D = enum.auto() + + PhysicalSize2D = enum.auto() + PhysicalSize3D = enum.auto() + PhysicalMass = enum.auto() PhysicalSpeed = enum.auto() - PhysicalAccel = enum.auto() - PhysicalForce = enum.auto() + PhysicalAccelScalar = enum.auto() + PhysicalForceScalar = enum.auto() + PhysicalAccel3DVector = enum.auto() + PhysicalForce3DVector = enum.auto() PhysicalPol = enum.auto() @@ -220,6 +229,72 @@ SocketType_to_units = { }, }, + SocketType.PhysicalPoint2D: { + "default": "UM", + "values": { + "PM": spu.picometer, + "A": spu.angstrom, + "NM": spu.nanometer, + "UM": spu.micrometer, + "MM": spu.millimeter, + "CM": spu.centimeter, + "M": spu.meter, + "INCH": spu.inch, + "FOOT": spu.foot, + "YARD": spu.yard, + "MILE": spu.mile, + }, + }, + SocketType.PhysicalPoint3D: { + "default": "UM", + "values": { + "PM": spu.picometer, + "A": spu.angstrom, + "NM": spu.nanometer, + "UM": spu.micrometer, + "MM": spu.millimeter, + "CM": spu.centimeter, + "M": spu.meter, + "INCH": spu.inch, + "FOOT": spu.foot, + "YARD": spu.yard, + "MILE": spu.mile, + }, + }, + + SocketType.PhysicalSize2D: { + "default": "UM", + "values": { + "PM": spu.picometer, + "A": spu.angstrom, + "NM": spu.nanometer, + "UM": spu.micrometer, + "MM": spu.millimeter, + "CM": spu.centimeter, + "M": spu.meter, + "INCH": spu.inch, + "FOOT": spu.foot, + "YARD": spu.yard, + "MILE": spu.mile, + }, + }, + SocketType.PhysicalSize3D: { + "default": "UM", + "values": { + "PM": spu.picometer, + "A": spu.angstrom, + "NM": spu.nanometer, + "UM": spu.micrometer, + "MM": spu.millimeter, + "CM": spu.centimeter, + "M": spu.meter, + "INCH": spu.inch, + "FOOT": spu.foot, + "YARD": spu.yard, + "MILE": spu.mile, + }, + }, + SocketType.PhysicalMass: { "default": "UG", "values": { @@ -247,7 +322,7 @@ SocketType_to_units = { "MI_H": spu.mile / spu.hour, }, }, - SocketType.PhysicalAccel: { + SocketType.PhysicalAccelScalar: { "default": "UM_S_SQ", "values": { "PM_S_SQ": spu.picometer / spu.second**2, @@ -259,7 +334,29 @@ SocketType_to_units = { "FT_S_SQ": spu.feet / spu.second**2, }, }, - SocketType.PhysicalForce: { + SocketType.PhysicalForceScalar: { + "default": "UNEWT", + "values": { + "KG_M_S_SQ": spu.kg * spu.m/spu.second**2, + "NNEWT": spuex.nanonewton, + "UNEWT": spuex.micronewton, + "MNEWT": spuex.millinewton, + "NEWT": spu.newton, + }, + }, + SocketType.PhysicalAccel3DVector: { + "default": "UM_S_SQ", + "values": { + "PM_S_SQ": spu.picometer / spu.second**2, + "NM_S_SQ": spu.nanometer / spu.second**2, + "UM_S_SQ": spu.micrometer / spu.second**2, + "MM_S_SQ": spu.millimeter / spu.second**2, + "M_S_SQ": spu.meter / spu.second**2, + "KM_S_SQ": spu.kilometer / spu.second**2, + "FT_S_SQ": spu.feet / spu.second**2, + }, + }, + SocketType.PhysicalForce3DVector: { "default": "UNEWT", "values": { "KG_M_S_SQ": spu.kg * spu.m/spu.second**2, @@ -294,6 +391,7 @@ SocketType_to_units = { SocketType_to_color = { # Basic SocketType.Any: (0.8, 0.8, 0.8, 1.0), # Light Grey + SocketType.Bool: (0.7, 0.7, 0.7, 1.0), # Medium Light Grey SocketType.Text: (0.7, 0.7, 0.7, 1.0), # Medium Light Grey SocketType.FilePath: (0.6, 0.6, 0.6, 1.0), # Medium Grey @@ -315,10 +413,16 @@ SocketType_to_color = { SocketType.PhysicalLength: (0.8, 0.4, 0.4, 1.0), # Medium Red SocketType.PhysicalArea: (0.7, 0.35, 0.35, 1.0), # Medium Dark Red SocketType.PhysicalVolume: (0.6, 0.3, 0.3, 1.0), # Dark Red + SocketType.PhysicalPoint2D: (0.7, 0.35, 0.35, 1.0), # Medium Dark Red + SocketType.PhysicalPoint3D: (0.6, 0.3, 0.3, 1.0), # Dark Red + SocketType.PhysicalSize2D: (0.7, 0.35, 0.35, 1.0), # Medium Dark Red + SocketType.PhysicalSize3D: (0.6, 0.3, 0.3, 1.0), # Dark Red SocketType.PhysicalMass: (0.9, 0.6, 0.4, 1.0), # Light Orange SocketType.PhysicalSpeed: (0.8, 0.55, 0.35, 1.0), # Medium Light Orange - SocketType.PhysicalAccel: (0.7, 0.5, 0.3, 1.0), # Medium Orange - SocketType.PhysicalForce: (0.6, 0.45, 0.25, 1.0), # Medium Dark Orange + SocketType.PhysicalAccelScalar: (0.7, 0.5, 0.3, 1.0), # Medium Orange + SocketType.PhysicalForceScalar: (0.6, 0.45, 0.25, 1.0), # Medium Dark Orange + SocketType.PhysicalAccel3DVector: (0.7, 0.5, 0.3, 1.0), # Medium Orange + SocketType.PhysicalForce3DVector: (0.6, 0.45, 0.25, 1.0), # Medium Dark Orange SocketType.PhysicalPol: (0.5, 0.4, 0.2, 1.0), # Dark Orange SocketType.PhysicalFreq: (1.0, 0.7, 0.5, 1.0), # Light Peach SocketType.PhysicalSpecPowerDist: (0.9, 0.65, 0.45, 1.0), # Medium Light Peach diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/base.py b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/base.py index ea1565a..6f131f2 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/base.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/base.py @@ -371,12 +371,23 @@ class MaxwellSimTreeNode(bpy.types.Node): Blender's own node socket object. """ - # (Guard) Socket Exists - if input_socket_name not in self.input_sockets: - msg = f"Input socket with name {input_socket_name} does not exist" - raise ValueError(msg) + if input_socket_name in self.input_sockets: + # Check Nicely that it Exists + if input_socket_name not in self.input_sockets: + msg = f"Input socket with name {input_socket_name} does not exist" + raise ValueError(msg) + + return self.inputs[self.input_sockets[input_socket_name].label] - return self.inputs[self.input_sockets[input_socket_name].label] + elif hasattr(self, "input_socket_sets"): + # You're on your own, chump + + return self.inputs[next( + socket_def.label + for socket_set, socket_dict in self.input_socket_sets.items() + for socket_name, socket_def in socket_dict.items() + if socket_name == input_socket_name + )] def g_output_bl_socket( self, @@ -392,17 +403,35 @@ class MaxwellSimTreeNode(bpy.types.Node): Blender's own node socket object. """ - # (Guard) Socket Exists - if output_socket_name not in self.output_sockets: - msg = f"Input socket with name {output_socket_name} does not exist" - raise ValueError(msg) - return self.outputs[self.output_sockets[output_socket_name].label] + if output_socket_name in self.output_sockets: + # (Guard) Socket Exists + if output_socket_name not in self.output_sockets: + msg = f"Input socket with name {output_socket_name} does not exist" + raise ValueError(msg) + + return self.outputs[self.output_sockets[output_socket_name].label] + + elif hasattr(self, "input_socket_sets"): + return self.outputs[next( + socket_def.label + for socket_set, socket_dict in self.input_socket_sets.items() + for socket_name, socket_def in socket_dict.items() + if socket_name == output_socket_name + )] def g_output_socket_name( self, output_bl_socket_name: contracts.BLSocketName, ) -> contracts.SocketName: + if hasattr(self, "output_socket_sets"): + return next( + socket_name + for socket_set, socket_dict in self.output_socket_sets.items() + for socket_name, socket_def in socket_dict.items() + if socket_def.label == output_bl_socket_name + ) + else: return next( output_socket_name for output_socket_name in self.output_sockets.keys() diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/inputs/constants/number_constant.py b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/inputs/constants/number_constant.py index 216ff2f..16d0e36 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/inputs/constants/number_constant.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/inputs/constants/number_constant.py @@ -11,16 +11,21 @@ class NumberConstantNode(base.MaxwellSimTreeNode): bl_label = "Numerical Constant" #bl_icon = constants.ICON_SIM_INPUT - input_sockets = { - "value": sockets.ComplexNumberSocketDef( - label="Complex", - ), ## TODO: Dynamic number socket! - } - output_sockets = { - "value": sockets.ComplexNumberSocketDef( - label="Complex", - ), ## TODO: Dynamic number socket! + input_sockets = {} + input_socket_sets = { + "real": { + "value": sockets.RealNumberSocketDef( + label="Real", + ), + }, + "complex": { + "value": sockets.ComplexNumberSocketDef( + label="Complex", + ), + }, } + output_sockets = {} + output_socket_sets = input_socket_sets #################### # - Callbacks diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/inputs/constants/physical_constant.py b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/inputs/constants/physical_constant.py index 41fac16..1503b45 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/inputs/constants/physical_constant.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/inputs/constants/physical_constant.py @@ -1,5 +1,75 @@ +import bpy +import sympy as sp + +from .... import contracts +from .... import sockets +from ... import base + +class PhysicalConstantNode(base.MaxwellSimTreeNode): + node_type = contracts.NodeType.PhysicalConstant + + bl_label = "Physical Constant" + #bl_icon = constants.ICON_SIM_INPUT + + input_sockets = {} + input_socket_sets = { + "time": { + "value": sockets.PhysicalTimeSocketDef( + label="Time", + ), + }, + "angle": { + "value": sockets.PhysicalAngleSocketDef( + label="Angle", + ), + }, + "length": { + "value": sockets.PhysicalLengthSocketDef( + label="Length", + ), + }, + "area": { + "value": sockets.PhysicalAreaSocketDef( + label="Area", + ), + }, + "volume": { + "value": sockets.PhysicalVolumeSocketDef( + label="Volume", + ), + }, + "point_3d": { + "value": sockets.PhysicalPoint3DSocketDef( + label="3D Point", + ), + }, + "size_3d": { + "value": sockets.PhysicalSize3DSocketDef( + label="3D Size", + ), + }, + ## I got bored so maybe the rest later + } + output_sockets = {} + output_socket_sets = input_socket_sets + + #################### + # - Callbacks + #################### + @base.computes_output_socket("value") + def compute_value(self: contracts.NodeTypeProtocol) -> sp.Expr: + return self.compute_input("value") + + + #################### # - Blender Registration #################### -BL_REGISTER = [] -BL_NODES = {} +BL_REGISTER = [ + PhysicalConstantNode, +] +BL_NODES = { + contracts.NodeType.PhysicalConstant: ( + contracts.NodeCategory.MAXWELLSIM_INPUTS_CONSTANTS + ) +} diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/kitchen_sink.py b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/kitchen_sink.py index ea41c38..fac1788 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/kitchen_sink.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/kitchen_sink.py @@ -19,6 +19,7 @@ class KitchenSinkNode(base.MaxwellSimTreeNode): input_socket_sets = { "basic": { "basic_any": sockets.AnySocketDef(label="Any"), + "basic_bool": sockets.BoolSocketDef(label="Bool"), "basic_filepath": sockets.FilePathSocketDef(label="FilePath"), "basic_text": sockets.TextSocketDef(label="Text"), }, @@ -36,14 +37,20 @@ class KitchenSinkNode(base.MaxwellSimTreeNode): }, "physical": { "physical_time": sockets.PhysicalTimeSocketDef(label="PhysicalTime"), + #"physical_point_2d": sockets.PhysicalPoint2DSocketDef(label="PhysicalPoint2D"), "physical_angle": sockets.PhysicalAngleSocketDef(label="PhysicalAngle"), "physical_length": sockets.PhysicalLengthSocketDef(label="PhysicalLength"), "physical_area": sockets.PhysicalAreaSocketDef(label="PhysicalArea"), "physical_volume": sockets.PhysicalVolumeSocketDef(label="PhysicalVolume"), + "physical_point_3d": sockets.PhysicalPoint3DSocketDef(label="PhysicalPoint3D"), + #"physical_size_2d": sockets.PhysicalSize2DSocketDef(label="PhysicalSize2D"), + "physical_size_3d": sockets.PhysicalSize3DSocketDef(label="PhysicalSize3D"), "physical_mass": sockets.PhysicalMassSocketDef(label="PhysicalMass"), "physical_speed": sockets.PhysicalSpeedSocketDef(label="PhysicalSpeed"), - "physical_accel": sockets.PhysicalAccelSocketDef(label="PhysicalAccel"), - "physical_force": sockets.PhysicalForceSocketDef(label="PhysicalForce"), + "physical_accel_scalar": sockets.PhysicalAccelScalarSocketDef(label="PhysicalAccelScalar"), + "physical_force_scalar": sockets.PhysicalForceScalarSocketDef(label="PhysicalForceScalar"), + #"physical_accel_3dvector": sockets.PhysicalAccel3DVectorSocketDef(label="PhysicalAccel3DVector"), + #"physical_force_3dvector": sockets.PhysicalForce3DVectorSocketDef(label="PhysicalForce3DVector"), "physical_pol": sockets.PhysicalPolSocketDef(label="PhysicalPol"), "physical_freq": sockets.PhysicalFreqSocketDef(label="PhysicalFreq"), "physical_spec_power_dist": sockets.PhysicalSpecPowerDistSocketDef(label="PhysicalSpecPowerDist"), @@ -62,18 +69,21 @@ class KitchenSinkNode(base.MaxwellSimTreeNode): "maxwell_temporal_shape": sockets.MaxwellTemporalShapeSocketDef(label="MaxwellTemporalShape"), "maxwell_medium": sockets.MaxwellMediumSocketDef(label="MaxwellMedium"), #"maxwell_medium_nonlinearity": sockets.MaxwellMediumNonLinearitySocketDef(label="MaxwellMediumNonLinearity"), - "maxwell_structure": sockets.MaxwellMediumSocketDef(label="MaxwellMedium"), + "maxwell_structure": sockets.MaxwellStructureSocketDef(label="MaxwellMedium"), "maxwell_bound_box": sockets.MaxwellBoundBoxSocketDef(label="MaxwellBoundBox"), "maxwell_bound_face": sockets.MaxwellBoundFaceSocketDef(label="MaxwellBoundFace"), "maxwell_monitor": sockets.MaxwellMonitorSocketDef(label="MaxwellMonitor"), - "maxwell_monitor": sockets.MaxwellFDTDSimSocketDef(label="MaxwellFDTDSim"), - "maxwell_monitor": sockets.MaxwellSimGridSocketDef(label="MaxwellSimGrid"), - "maxwell_monitor": sockets.MaxwellSimGridAxisSocketDef(label="MaxwellSimGridAxis"), + "maxwell_fdtd_sim": sockets.MaxwellFDTDSimSocketDef(label="MaxwellFDTDSim"), + "maxwell_sim_grid": sockets.MaxwellSimGridSocketDef(label="MaxwellSimGrid"), + "maxwell_sim_grid_axis": sockets.MaxwellSimGridAxisSocketDef(label="MaxwellSimGridAxis"), }, } output_sockets = {} - output_socket_sets = input_socket_sets + output_socket_sets = { + k + " Output": v + for k, v in input_socket_sets.items() + } diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/simulations/fdtd_sim.py b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/simulations/fdtd_sim.py index e681efb..f08cbfc 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/simulations/fdtd_sim.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/simulations/fdtd_sim.py @@ -16,21 +16,11 @@ class FDTDSimNode(base.MaxwellSimTreeNode): # - Sockets #################### input_sockets = { - "run_time": sockets.RealNumberSocketDef( + "run_time": sockets.PhysicalTimeSocketDef( label="Run Time", - default_value=1.0, ), - "size_x": sockets.RealNumberSocketDef( - label="Size X", - default_value=1.0, - ), - "size_y": sockets.RealNumberSocketDef( - label="Size Y", - default_value=1.0, - ), - "size_z": sockets.RealNumberSocketDef( - label="Size Z", - default_value=1.0, + "size": sockets.PhysicalSize3DSocketDef( + label="Size", ), "ambient_medium": sockets.MaxwellMediumSocketDef( label="Ambient Medium", @@ -56,17 +46,15 @@ class FDTDSimNode(base.MaxwellSimTreeNode): #################### @base.computes_output_socket("fdtd_sim") def compute_simulation(self: contracts.NodeTypeProtocol) -> td.Simulation: - run_time = self.compute_input("run_time") + _run_time = self.compute_input("run_time") + _size = self.compute_input("size") ambient_medium = self.compute_input("ambient_medium") structures = [self.compute_input("structure")] sources = [self.compute_input("source")] bound = self.compute_input("bound") - size = ( - self.compute_input("size_x"), - self.compute_input("size_y"), - self.compute_input("size_z"), - ) + run_time = spu.convert_to(_run_time, spu.second) / spu.second + size = tuple(spu.convert_to(_size, spu.um) / spu.um) return td.Simulation( size=size, diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/sources/point_dipole_source.py b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/sources/point_dipole_source.py index 655d286..608dcb3 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/sources/point_dipole_source.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/sources/point_dipole_source.py @@ -16,17 +16,14 @@ class PointDipoleSourceNode(base.MaxwellSimTreeNode): # - Sockets #################### input_sockets = { - "center_x": sockets.RealNumberSocketDef( - label="Center X", - default_value=0.0, + #"polarization": sockets.PhysicalPolSocketDef( + # label="Polarization", + #), ## TODO: Exactly how to go about this... + "temporal_shape": sockets.MaxwellTemporalShapeSocketDef( + label="Temporal Shape", ), - "center_y": sockets.RealNumberSocketDef( - label="Center Y", - default_value=0.0, - ), - "center_z": sockets.RealNumberSocketDef( - label="Center Z", - default_value=0.0, + "center": sockets.PhysicalPoint3DSocketDef( + label="Center", ), } output_sockets = { @@ -40,19 +37,19 @@ class PointDipoleSourceNode(base.MaxwellSimTreeNode): #################### @base.computes_output_socket("source") def compute_source(self: contracts.NodeTypeProtocol) -> td.PointDipole: - center = ( - self.compute_input("center_x"), - self.compute_input("center_y"), - self.compute_input("center_z"), - ) + temporal_shape = self.compute_input("temporal_shape") - cheating_pulse = td.GaussianPulse(freq0=200e12, fwidth=20e12) + _center = self.compute_input("center") + center = tuple(spu.convert_to(_center, spu.um) / spu.um) + + cheating_pol = "Ex" + ## TODO: Fix return td.PointDipole( center=center, - source_time=cheating_pulse, + source_time=temporal_shape, interpolate=True, - polarization="Ex", + polarization=cheating_pol, ) diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/sources/temporal_shapes/gaussian_pulse_temporal_shape.py b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/sources/temporal_shapes/gaussian_pulse_temporal_shape.py index 8f4a665..5d29bda 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/sources/temporal_shapes/gaussian_pulse_temporal_shape.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/sources/temporal_shapes/gaussian_pulse_temporal_shape.py @@ -1,6 +1,82 @@ +import tidy3d as td +import sympy as sp +import sympy.physics.units as spu + +from .... import contracts +from .... import sockets +from ... import base + +class GaussianPulseTemporalShapeNode(base.MaxwellSimTreeNode): + node_type = contracts.NodeType.GaussianPulseTemporalShape + + bl_label = "Gaussian Pulse Temporal Shape" + #bl_icon = ... + + #################### + # - Sockets + #################### + input_sockets = { + #"amplitude": sockets.RealNumberSocketDef( + # label="Temporal Shape", + #), ## Should have a unit of some kind... + "phase": sockets.PhysicalAngleSocketDef( + label="Phase", + ), + "freq_center": sockets.PhysicalFreqSocketDef( + label="Freq Center", + ), + "freq_std": sockets.PhysicalFreqSocketDef( + label="Freq STD", + ), + "time_delay_rel_ang_freq": sockets.RealNumberSocketDef( + label="Time Delay rel. Ang. Freq", + ), + "remove_dc_component": sockets.BoolSocketDef( + label="Remove DC", + default_value=True, + ), + } + output_sockets = { + "temporal_shape": sockets.MaxwellTemporalShapeSocketDef( + label="Temporal Shape", + ), + } + + #################### + # - Output Socket Computation + #################### + @base.computes_output_socket("temporal_shape") + def compute_source(self: contracts.NodeTypeProtocol) -> td.PointDipole: + _phase = self.compute_input("phase") + _freq_center = self.compute_input("freq_center") + _freq_std = self.compute_input("freq_std") + time_delay_rel_ang_freq = self.compute_input("time_delay_rel_ang_freq") + remove_dc_component = self.compute_input("remove_dc_component") + + cheating_amplitude = 1.0 + phase = spu.convert_to(_phase, spu.radian) / spu.radian + freq_center = spu.convert_to(_freq_center, spu.hertz) / spu.hertz + freq_std = spu.convert_to(_freq_std, spu.hertz) / spu.hertz + + return td.GaussianPulse( + amplitude=cheating_amplitude, + phase=phase, + freq0=freq_center, + fwidth=freq_std, + offset=time_delay_rel_ang_freq, + remove_dc_component=remove_dc_component, + ) + + + #################### # - Blender Registration #################### -BL_REGISTER = [] -BL_NODES = {} - +BL_REGISTER = [ + GaussianPulseTemporalShapeNode, +] +BL_NODES = { + contracts.NodeType.GaussianPulseTemporalShape: ( + contracts.NodeCategory.MAXWELLSIM_SOURCES_TEMPORALSHAPES + ) +} diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/structures/primitives/box_structure.py b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/structures/primitives/box_structure.py index d550c69..56c0961 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/structures/primitives/box_structure.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/nodes/structures/primitives/box_structure.py @@ -18,29 +18,11 @@ class BoxStructureNode(base.MaxwellSimTreeNode): "medium": sockets.MaxwellMediumSocketDef( label="Medium", ), - "center_x": sockets.RealNumberSocketDef( - label="Center X", - default_value=0.0, + "center": sockets.PhysicalPoint3DSocketDef( + label="Center", ), - "center_y": sockets.RealNumberSocketDef( - label="Center Y", - default_value=0.0, - ), - "center_z": sockets.RealNumberSocketDef( - label="Center Z", - default_value=0.0, - ), - "size_x": sockets.RealNumberSocketDef( - label="Size X", - default_value=1.0, - ), - "size_y": sockets.RealNumberSocketDef( - label="Size Y", - default_value=1.0, - ), - "size_z": sockets.RealNumberSocketDef( - label="Size Z", - default_value=1.0, + "size": sockets.PhysicalSize3DSocketDef( + label="Size", ), } output_sockets = { @@ -55,16 +37,11 @@ class BoxStructureNode(base.MaxwellSimTreeNode): @base.computes_output_socket("structure") def compute_simulation(self: contracts.NodeTypeProtocol) -> td.Box: medium = self.compute_input("medium") - center = ( - self.compute_input("center_x"), - self.compute_input("center_y"), - self.compute_input("center_z"), - ) - size = ( - self.compute_input("size_x"), - self.compute_input("size_y"), - self.compute_input("size_z"), - ) + _center = self.compute_input("center") + _size = self.compute_input("size") + + center = tuple(spu.convert_to(_center, spu.um) / spu.um) + size = tuple(spu.convert_to(_size, spu.um) / spu.um) return td.Structure( geometry=td.Box( diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/__init__.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/__init__.py index d61eb79..c0a2853 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/__init__.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/__init__.py @@ -1,5 +1,6 @@ from . import basic AnySocketDef = basic.AnySocketDef +BoolSocketDef = basic.BoolSocketDef TextSocketDef = basic.TextSocketDef FilePathSocketDef = basic.FilePathSocketDef @@ -21,10 +22,12 @@ PhysicalAngleSocketDef = physical.PhysicalAngleSocketDef PhysicalLengthSocketDef = physical.PhysicalLengthSocketDef PhysicalAreaSocketDef = physical.PhysicalAreaSocketDef PhysicalVolumeSocketDef = physical.PhysicalVolumeSocketDef +PhysicalPoint3DSocketDef = physical.PhysicalPoint3DSocketDef +PhysicalSize3DSocketDef = physical.PhysicalSize3DSocketDef PhysicalMassSocketDef = physical.PhysicalMassSocketDef PhysicalSpeedSocketDef = physical.PhysicalSpeedSocketDef -PhysicalAccelSocketDef = physical.PhysicalAccelSocketDef -PhysicalForceSocketDef = physical.PhysicalForceSocketDef +PhysicalAccelScalarSocketDef = physical.PhysicalAccelScalarSocketDef +PhysicalForceScalarSocketDef = physical.PhysicalForceScalarSocketDef PhysicalPolSocketDef = physical.PhysicalPolSocketDef PhysicalFreqSocketDef = physical.PhysicalFreqSocketDef PhysicalSpecRelPermDistSocketDef = physical.PhysicalSpecRelPermDistSocketDef diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/base.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/base.py index 9655cf1..bfd451a 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/base.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/base.py @@ -127,10 +127,16 @@ class BLSocket(bpy.types.NodeSocket): the value with the new unit. """ if hasattr(self, "raw_value") and hasattr(self, "unit"): - self.raw_value = spu.convert_to( - self.raw_value * self._unit_previous, - self.unit, - ) / self.unit + if hasattr(self.raw_value, "__getitem__"): + self.raw_value = tuple(spu.convert_to( + sp.Matrix(tuple(self.raw_value)) * self._unit_previous, + self.unit, + ) / self.unit) + else: + self.raw_value = spu.convert_to( + self.raw_value * self._unit_previous, + self.unit, + ) / self.unit self._unit_previous = self.unit @@ -187,6 +193,9 @@ class BLSocket(bpy.types.NodeSocket): label_col_row = col.row(align=True) if hasattr(self, "draw_label_row"): self.draw_label_row(label_col_row, text) + elif hasattr(self, "raw_unit"): + label_col_row.label(text=text) + label_col_row.prop(self, "raw_unit", text="") else: label_col_row.label(text=text) @@ -208,6 +217,9 @@ class BLSocket(bpy.types.NodeSocket): # Row(s): Value if hasattr(self, "draw_value"): self.draw_value(col) + elif hasattr(self, "raw_value"): + #col_row = col.row(align=True) + col.prop(self, "raw_value", text="") def draw_output( self, diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/basic/__init__.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/basic/__init__.py index 0f5cc2a..db03d73 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/basic/__init__.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/basic/__init__.py @@ -1,6 +1,9 @@ from . import any_socket AnySocketDef = any_socket.AnySocketDef +from . import bool_socket +BoolSocketDef = bool_socket.BoolSocketDef + from . import text_socket TextSocketDef = text_socket.TextSocketDef @@ -10,6 +13,7 @@ FilePathSocketDef = file_path_socket.FilePathSocketDef BL_REGISTER = [ *any_socket.BL_REGISTER, + *bool_socket.BL_REGISTER, *text_socket.BL_REGISTER, *file_path_socket.BL_REGISTER, ] diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/basic/bool_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/basic/bool_socket.py new file mode 100644 index 0000000..a417304 --- /dev/null +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/basic/bool_socket.py @@ -0,0 +1,73 @@ +import typing as typ + +import bpy +import sympy as sp +import pydantic as pyd + +from .. import base +from ... import contracts + +#################### +# - Blender Socket +#################### +class BoolBLSocket(base.BLSocket): + socket_type = contracts.SocketType.Bool + bl_label = "Bool" + + compatible_types = { + bool: {}, + } + + #################### + # - Properties + #################### + raw_value: bpy.props.BoolProperty( + name="Boolean", + description="Represents a boolean", + default=False, + ) + + #################### + # - Socket UI + #################### + def draw_label_row(self, label_col_row: bpy.types.UILayout, text: str) -> None: + label_col_row.label(text=text) + label_col_row.prop(self, "raw_value", text="") + + def draw_value(self, label_col_row: bpy.types.UILayout) -> None: + pass + + #################### + # - Computation of Default Value + #################### + @property + def default_value(self) -> str: + return self.raw_value + + @default_value.setter + def default_value(self, value: typ.Any) -> None: + # (Guard) Value Compatibility + if not self.is_compatible(value): + msg = f"Tried setting socket ({self}) to incompatible value ({value}) of type {type(value)}" + raise ValueError(msg) + + self.raw_value = bool(value) + +#################### +# - Socket Configuration +#################### +class BoolSocketDef(pyd.BaseModel): + socket_type: contracts.SocketType = contracts.SocketType.Bool + label: str + + default_value: bool = False + + def init(self, bl_socket: BoolBLSocket) -> None: + bl_socket.raw_value = self.default_value + +#################### +# - Blender Registration +#################### +BL_REGISTER = [ + BoolBLSocket, +] diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/basic/text_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/basic/text_socket.py index dfdbff7..c6b2fd0 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/basic/text_socket.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/basic/text_socket.py @@ -37,6 +37,9 @@ class TextBLSocket(base.BLSocket): """ label_col_row.prop(self, "raw_value", text=text) + def draw_value(self, label_col_row: bpy.types.UILayout) -> None: + pass + #################### # - Computation of Default Value #################### diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/maxwell/__init__.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/maxwell/__init__.py index c09a292..6088df8 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/maxwell/__init__.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/maxwell/__init__.py @@ -32,6 +32,7 @@ BL_REGISTER = [ *source_socket.BL_REGISTER, *temporal_shape_socket.BL_REGISTER, *structure_socket.BL_REGISTER, + *monitor_socket.BL_REGISTER, *fdtd_sim_socket.BL_REGISTER, *sim_grid_socket.BL_REGISTER, *sim_grid_axis_socket.BL_REGISTER, diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/maxwell/medium_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/maxwell/medium_socket.py index 4929229..cd9312f 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/maxwell/medium_socket.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/maxwell/medium_socket.py @@ -22,7 +22,7 @@ class MaxwellMediumBLSocket(base.BLSocket): name="Permittivity", description="Represents a simple, real permittivity.", default=0.0, - precision=6, + precision=4, ) #################### @@ -33,7 +33,7 @@ class MaxwellMediumBLSocket(base.BLSocket): specifying the active unit. """ col_row = col.row(align=True) - col_row.prop(self, "rel_permittivity", text="Re(eps_r)") + col_row.prop(self, "rel_permittivity", text="ϵr") #################### # - Computation of Default Value diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/number/real_number_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/number/real_number_socket.py index d7427fe..7a3da98 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/number/real_number_socket.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/number/real_number_socket.py @@ -32,14 +32,6 @@ class RealNumberBLSocket(base.BLSocket): precision=6, ) - #################### - # - Socket UI - #################### - def draw_label_row(self, label_col_row: bpy.types.UILayout, text: str) -> None: - """Draw the value of the real number. - """ - label_col_row.prop(self, "raw_value", text=text) - #################### # - Computation of Default Value #################### diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/__init__.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/__init__.py index 943e06e..182e2fc 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/__init__.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/__init__.py @@ -11,15 +11,21 @@ PhysicalLengthSocketDef = length_socket.PhysicalLengthSocketDef PhysicalAreaSocketDef = area_socket.PhysicalAreaSocketDef PhysicalVolumeSocketDef = volume_socket.PhysicalVolumeSocketDef +from . import point_3d_socket +PhysicalPoint3DSocketDef = point_3d_socket.PhysicalPoint3DSocketDef + +from . import size_3d_socket +PhysicalSize3DSocketDef = size_3d_socket.PhysicalSize3DSocketDef + from . import mass_socket PhysicalMassSocketDef = mass_socket.PhysicalMassSocketDef from . import speed_socket -from . import accel_socket -from . import force_socket +from . import accel_scalar_socket +from . import force_scalar_socket PhysicalSpeedSocketDef = speed_socket.PhysicalSpeedSocketDef -PhysicalAccelSocketDef = accel_socket.PhysicalAccelSocketDef -PhysicalForceSocketDef = force_socket.PhysicalForceSocketDef +PhysicalAccelScalarSocketDef = accel_scalar_socket.PhysicalAccelScalarSocketDef +PhysicalForceScalarSocketDef = force_scalar_socket.PhysicalForceScalarSocketDef from . import pol_socket PhysicalPolSocketDef = pol_socket.PhysicalPolSocketDef @@ -42,11 +48,15 @@ BL_REGISTER = [ *area_socket.BL_REGISTER, *volume_socket.BL_REGISTER, + *point_3d_socket.BL_REGISTER, + + *size_3d_socket.BL_REGISTER, + *mass_socket.BL_REGISTER, *speed_socket.BL_REGISTER, - *accel_socket.BL_REGISTER, - *force_socket.BL_REGISTER, + *accel_scalar_socket.BL_REGISTER, + *force_scalar_socket.BL_REGISTER, *pol_socket.BL_REGISTER, diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/accel_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/accel_scalar_socket.py similarity index 61% rename from blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/accel_socket.py rename to blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/accel_scalar_socket.py index deba94e..02d9b5a 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/accel_socket.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/accel_scalar_socket.py @@ -9,8 +9,8 @@ from ... import contracts #################### # - Blender Socket #################### -class PhysicalAccelBLSocket(base.BLSocket): - socket_type = contracts.SocketType.PhysicalAccel +class PhysicalAccelScalarBLSocket(base.BLSocket): + socket_type = contracts.SocketType.PhysicalAccelScalar bl_label = "PhysicalAccel" use_units = True @@ -24,17 +24,6 @@ class PhysicalAccelBLSocket(base.BLSocket): precision=6, ) - #################### - # - Socket UI - #################### - def draw_label_row(self, label_col_row: bpy.types.UILayout, text: str) -> None: - label_col_row.label(text=text) - label_col_row.prop(self, "raw_unit", text="") - - def draw_value(self, col: bpy.types.UILayout) -> None: - col_row = col.row(align=True) - col_row.prop(self, "raw_value", text="") - #################### # - Default Value #################### @@ -49,16 +38,19 @@ class PhysicalAccelBLSocket(base.BLSocket): #################### # - Socket Configuration #################### -class PhysicalAccelSocketDef(pyd.BaseModel): - socket_type: contracts.SocketType = contracts.SocketType.PhysicalAccel +class PhysicalAccelScalarSocketDef(pyd.BaseModel): + socket_type: contracts.SocketType = contracts.SocketType.PhysicalAccelScalar label: str - def init(self, bl_socket: PhysicalAccelBLSocket) -> None: - pass + default_unit: typ.Any | None = None + + def init(self, bl_socket: PhysicalAccelScalarBLSocket) -> None: + if self.default_unit: + bl_socket.unit = self.default_unit #################### # - Blender Registration #################### BL_REGISTER = [ - PhysicalAccelBLSocket, + PhysicalAccelScalarBLSocket, ] diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/angle_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/angle_socket.py index 3a2b62d..ac4bfc5 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/angle_socket.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/angle_socket.py @@ -1,5 +1,6 @@ import typing as typ +import bpy import pydantic as pyd from .. import base @@ -11,17 +12,28 @@ from ... import contracts class PhysicalAngleBLSocket(base.BLSocket): socket_type = contracts.SocketType.PhysicalAngle bl_label = "PhysicalAngle" + use_units = True + + #################### + # - Properties + #################### + raw_value: bpy.props.FloatProperty( + name="Unitless Acceleration", + description="Represents the unitless part of the acceleration", + default=0.0, + precision=4, + ) #################### # - Default Value #################### @property def default_value(self) -> None: - pass + return self.raw_value * self.unit @default_value.setter def default_value(self, value: typ.Any) -> None: - pass + self.raw_value = self.value_as_unit(value) #################### # - Socket Configuration @@ -30,8 +42,11 @@ class PhysicalAngleSocketDef(pyd.BaseModel): socket_type: contracts.SocketType = contracts.SocketType.PhysicalAngle label: str + default_unit: typ.Any | None = None + def init(self, bl_socket: PhysicalAngleBLSocket) -> None: - pass + if self.default_unit: + bl_socket.unit = self.default_unit #################### # - Blender Registration diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/area_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/area_socket.py index 5adf794..5ad6dea 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/area_socket.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/area_socket.py @@ -38,9 +38,6 @@ class PhysicalAreaBLSocket(base.BLSocket): # - Socket UI #################### def draw_label_row(self, label_col_row: bpy.types.UILayout, text: str) -> None: - """Draw the value of the area, including a toggle for - specifying the active unit. - """ label_col_row.label(text=text) label_col_row.prop(self, "raw_unit", text="") diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/force_scalar_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/force_scalar_socket.py new file mode 100644 index 0000000..1e84256 --- /dev/null +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/force_scalar_socket.py @@ -0,0 +1,56 @@ +import typing as typ + +import bpy +import pydantic as pyd + +from .. import base +from ... import contracts + +#################### +# - Blender Socket +#################### +class PhysicalForceScalarBLSocket(base.BLSocket): + socket_type = contracts.SocketType.PhysicalForceScalar + bl_label = "PhysicalForceScalar" + use_units = True + + #################### + # - Properties + #################### + raw_value: bpy.props.FloatProperty( + name="Unitless Force", + description="Represents the unitless part of the force", + default=0.0, + precision=6, + ) + + #################### + # - Default Value + #################### + @property + def default_value(self) -> None: + return self.raw_value * self.unit + + @default_value.setter + def default_value(self, value: typ.Any) -> None: + self.raw_value = self.value_as_unit(value) + +#################### +# - Socket Configuration +#################### +class PhysicalForceScalarSocketDef(pyd.BaseModel): + socket_type: contracts.SocketType = contracts.SocketType.PhysicalForceScalar + label: str + + default_unit: typ.Any | None = None + + def init(self, bl_socket: PhysicalForceScalarBLSocket) -> None: + if self.default_unit: + bl_socket.unit = self.default_unit + +#################### +# - Blender Registration +#################### +BL_REGISTER = [ + PhysicalForceScalarBLSocket, +] diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/force_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/force_socket.py deleted file mode 100644 index e558597..0000000 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/force_socket.py +++ /dev/null @@ -1,41 +0,0 @@ -import typing as typ - -import pydantic as pyd - -from .. import base -from ... import contracts - -#################### -# - Blender Socket -#################### -class PhysicalForceBLSocket(base.BLSocket): - socket_type = contracts.SocketType.PhysicalForce - bl_label = "PhysicalForce" - - #################### - # - Default Value - #################### - @property - def default_value(self) -> None: - pass - - @default_value.setter - def default_value(self, value: typ.Any) -> None: - pass - -#################### -# - Socket Configuration -#################### -class PhysicalForceSocketDef(pyd.BaseModel): - socket_type: contracts.SocketType = contracts.SocketType.PhysicalForce - label: str - - def init(self, bl_socket: PhysicalForceBLSocket) -> None: - pass - -#################### -# - Blender Registration -#################### -BL_REGISTER = [ - PhysicalForceBLSocket, -] diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/freq_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/freq_socket.py index 66a1cb3..0ef7376 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/freq_socket.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/freq_socket.py @@ -1,5 +1,6 @@ import typing as typ +import bpy import pydantic as pyd from .. import base @@ -11,17 +12,28 @@ from ... import contracts class PhysicalFreqBLSocket(base.BLSocket): socket_type = contracts.SocketType.PhysicalFreq bl_label = "PhysicalFreq" + use_units = True + + #################### + # - Properties + #################### + raw_value: bpy.props.FloatProperty( + name="Unitless Frequency", + description="Represents the unitless part of the frequency", + default=0.0, + precision=6, + ) #################### # - Default Value #################### @property def default_value(self) -> None: - pass + return self.raw_value * self.unit @default_value.setter def default_value(self, value: typ.Any) -> None: - pass + self.raw_value = self.value_as_unit(value) #################### # - Socket Configuration diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/length_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/length_socket.py index d153d89..109f29b 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/length_socket.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/length_socket.py @@ -1,5 +1,6 @@ import typing as typ +import bpy import pydantic as pyd from .. import base @@ -11,17 +12,28 @@ from ... import contracts class PhysicalLengthBLSocket(base.BLSocket): socket_type = contracts.SocketType.PhysicalLength bl_label = "PhysicalLength" + use_units = True + + #################### + # - Properties + #################### + raw_value: bpy.props.FloatProperty( + name="Unitless Force", + description="Represents the unitless part of the force", + default=0.0, + precision=6, + ) #################### # - Default Value #################### @property def default_value(self) -> None: - pass + return self.raw_value * self.unit @default_value.setter def default_value(self, value: typ.Any) -> None: - pass + self.raw_value = self.value_as_unit(value) #################### # - Socket Configuration @@ -30,8 +42,11 @@ class PhysicalLengthSocketDef(pyd.BaseModel): socket_type: contracts.SocketType = contracts.SocketType.PhysicalLength label: str + default_unit: typ.Any | None = None + def init(self, bl_socket: PhysicalLengthBLSocket) -> None: - pass + if self.default_unit: + bl_socket.unit = self.default_unit #################### # - Blender Registration diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/point_3d_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/point_3d_socket.py new file mode 100644 index 0000000..812f84b --- /dev/null +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/point_3d_socket.py @@ -0,0 +1,67 @@ +import typing as typ + +import bpy +import sympy as sp +import sympy.physics.units as spu +import pydantic as pyd + +from .. import base +from ... import contracts + +class PhysicalPoint3DBLSocket(base.BLSocket): + socket_type = contracts.SocketType.PhysicalPoint3D + bl_label = "Physical Volume" + use_units = True + + compatible_types = { + sp.Expr: { + lambda self, v: v.is_real, + lambda self, v: len(v.free_symbols) == 0, + lambda self, v: any( + contracts.is_exactly_expressed_as_unit(v, unit) + for unit in self.units.values() + ) + }, + } + + #################### + # - Properties + #################### + raw_value: bpy.props.FloatVectorProperty( + name="Unitless 3D Point (global coordinate system)", + description="Represents the unitless part of the 3D point", + size=3, + default=(0.0, 0.0, 0.0), + precision=4, + ) + + #################### + # - Computation of Default Value + #################### + @property + def default_value(self) -> sp.Expr: + return sp.Matrix(tuple(self.raw_value)) * self.unit + + @default_value.setter + def default_value(self, value: typ.Any) -> None: + self.raw_value = self.value_as_unit(value) + +#################### +# - Socket Configuration +#################### +class PhysicalPoint3DSocketDef(pyd.BaseModel): + socket_type: contracts.SocketType = contracts.SocketType.PhysicalPoint3D + label: str + + default_unit: typ.Any | None = None + + def init(self, bl_socket: PhysicalPoint3DBLSocket) -> None: + if self.default_unit: + bl_socket.unit = self.default_unit + +#################### +# - Blender Registration +#################### +BL_REGISTER = [ + PhysicalPoint3DBLSocket, +] diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/size_3d_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/size_3d_socket.py new file mode 100644 index 0000000..aabd749 --- /dev/null +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/size_3d_socket.py @@ -0,0 +1,67 @@ +import typing as typ + +import bpy +import sympy as sp +import sympy.physics.units as spu +import pydantic as pyd + +from .. import base +from ... import contracts + +class PhysicalSize3DBLSocket(base.BLSocket): + socket_type = contracts.SocketType.PhysicalSize3D + bl_label = "Physical Volume" + use_units = True + + compatible_types = { + sp.Expr: { + lambda self, v: v.is_real, + lambda self, v: len(v.free_symbols) == 0, + lambda self, v: any( + contracts.is_exactly_expressed_as_unit(v, unit) + for unit in self.units.values() + ) + }, + } + + #################### + # - Properties + #################### + raw_value: bpy.props.FloatVectorProperty( + name="Unitless 3D Size", + description="Represents the unitless part of the 3D size", + size=3, + default=(1.0, 1.0, 1.0), + precision=4, + ) + + #################### + # - Computation of Default Value + #################### + @property + def default_value(self) -> sp.Expr: + return sp.Matrix(tuple(self.raw_value)) * self.unit + + @default_value.setter + def default_value(self, value: typ.Any) -> None: + self.raw_value = self.value_as_unit(value) + +#################### +# - Socket Configuration +#################### +class PhysicalSize3DSocketDef(pyd.BaseModel): + socket_type: contracts.SocketType = contracts.SocketType.PhysicalSize3D + label: str + + default_unit: typ.Any | None = None + + def init(self, bl_socket: PhysicalSize3DBLSocket) -> None: + if self.default_unit: + bl_socket.unit = self.default_unit + +#################### +# - Blender Registration +#################### +BL_REGISTER = [ + PhysicalSize3DBLSocket, +] diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/time_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/time_socket.py index 093ddbe..a35759b 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/time_socket.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/time_socket.py @@ -1,5 +1,6 @@ import typing as typ +import bpy import pydantic as pyd from .. import base @@ -11,17 +12,28 @@ from ... import contracts class PhysicalTimeBLSocket(base.BLSocket): socket_type = contracts.SocketType.PhysicalTime bl_label = "PhysicalTime" + use_units = True + + #################### + # - Properties + #################### + raw_value: bpy.props.FloatProperty( + name="Unitless Force", + description="Represents the unitless part of the force", + default=0.0, + precision=6, + ) #################### # - Default Value #################### @property def default_value(self) -> None: - pass + return self.raw_value * self.unit @default_value.setter def default_value(self, value: typ.Any) -> None: - pass + self.raw_value = self.value_as_unit(value) #################### # - Socket Configuration @@ -30,8 +42,11 @@ class PhysicalTimeSocketDef(pyd.BaseModel): socket_type: contracts.SocketType = contracts.SocketType.PhysicalTime label: str + default_unit: typ.Any | None = None + def init(self, bl_socket: PhysicalTimeBLSocket) -> None: - pass + if self.default_unit: + bl_socket.unit = self.default_unit #################### # - Blender Registration diff --git a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/volume_socket.py b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/volume_socket.py index 4fa88fc..cd465c6 100644 --- a/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/volume_socket.py +++ b/blender_maxwell/node_trees/maxwell_sim_nodes/sockets/physical/volume_socket.py @@ -5,9 +5,6 @@ import sympy as sp import sympy.physics.units as spu import pydantic as pyd -sp.printing.str.StrPrinter._default_settings['abbrev'] = True -## When we str() a unit expression, use abbrevied units. - from .. import base from ... import contracts diff --git a/blender_maxwell/requirements.txt b/blender_maxwell/requirements.txt index 2d1034c..4bcb244 100644 --- a/blender_maxwell/requirements.txt +++ b/blender_maxwell/requirements.txt @@ -1,3 +1,4 @@ tidy3d==2.5.2 pydantic==2.6.0 sympy==1.12 +scipy==1.12.0