feat: cylinder primitive & fixed GN previews

Re-added the cylinder primitive (it's quite important), including an
appropriate asset `.blend`.

Also finished (I think?) a quick cleanup round from the enhanced
`ManagedBLModifier`, which now owns the mesh and doesn't need a seperate
`ManagedBLMesh`.
This seems faster for some reason, but more importantly, it simplifies a
bunch of the previewing code.

Finally, fixed a small issue with the extract data node where its
`ExprSocket` still had the `FlowKind.Array`, causing it to not be able
to be connected to the whole math system. So, yeah.
main
Sofus Albert Høgsbro Rose 2024-05-16 19:15:11 +02:00
parent 2d26ea6ce8
commit 7ac6b615de
Signed by: so-rose
GPG Key ID: AD901CB0F3701434
11 changed files with 171 additions and 139 deletions

View File

@ -61,7 +61,9 @@ class ExtractDataNode(base.MaxwellSimNode):
}
output_socket_sets: typ.ClassVar = {
'Sim Data': {'Monitor Data': sockets.MaxwellMonitorDataSocketDef()},
'Monitor Data': {'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.Array)},
'Monitor Data': {
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.LazyArrayRange)
},
}
####################

View File

@ -222,9 +222,9 @@ class EHFieldMonitorNode(base.MaxwellSimNode):
)
def on_inputs_changed(
self,
managed_objs: dict,
input_sockets: dict,
unit_systems: dict,
managed_objs,
input_sockets,
unit_systems,
):
# Push Input Values to GeoNodes Modifier
managed_objs['modifier'].bl_modifier(

View File

@ -65,7 +65,6 @@ class SimDomainNode(base.MaxwellSimNode):
}
managed_obj_types: typ.ClassVar = {
'mesh': managed_objs.ManagedBLMesh,
'modifier': managed_objs.ManagedBLModifier,
}
@ -95,19 +94,17 @@ class SimDomainNode(base.MaxwellSimNode):
# - Preview
####################
@events.on_value_changed(
# Trigger
prop_name='preview_active',
run_on_init=True,
# Loaded
managed_objs={'modifier'},
props={'preview_active'},
managed_objs={'mesh'},
)
def on_preview_changed(self, props, managed_objs) -> None:
mesh = managed_objs['mesh']
# Push Preview State to Managed Mesh
def on_preview_changed(self, managed_objs, props):
if props['preview_active']:
mesh.show_preview()
managed_objs['modifier'].show_preview()
else:
mesh.hide_preview()
managed_objs['modifier'].hide_preview()
@events.on_value_changed(
## Trigger
@ -115,7 +112,7 @@ class SimDomainNode(base.MaxwellSimNode):
run_on_init=True,
# Loaded
input_sockets={'Center', 'Size'},
managed_objs={'mesh', 'modifier'},
managed_objs={'modifier'},
unit_systems={'BlenderUnits': ct.UNITS_BLENDER},
scale_input_sockets={
'Center': 'BlenderUnits',
@ -127,21 +124,17 @@ class SimDomainNode(base.MaxwellSimNode):
input_sockets,
unit_systems,
):
mesh = managed_objs['mesh']
modifier = managed_objs['modifier']
center = input_sockets['Center']
size = input_sockets['Size']
unit_system = unit_systems['BlenderUnits']
# Push Loose Input Values to GeoNodes Modifier
modifier.bl_modifier(
mesh.bl_object(location=center),
managed_objs['modifier'].bl_modifier(
'NODES',
{
'node_group': import_geonodes(GeoNodes.SimulationSimDomain),
'inputs': {'Size': size},
'unit_system': unit_system,
'unit_system': unit_systems['BlenderUnits'],
'inputs': {
'Size': input_sockets['Size'],
},
},
location=input_sockets['Center'],
)

View File

@ -92,7 +92,6 @@ class GaussianBeamSourceNode(base.MaxwellSimNode):
}
managed_obj_types: typ.ClassVar = {
'mesh': managed_objs.ManagedBLMesh,
'modifier': managed_objs.ManagedBLModifier,
}
@ -170,18 +169,14 @@ class GaussianBeamSourceNode(base.MaxwellSimNode):
# Trigger
prop_name='preview_active',
# Loaded
managed_objs={'mesh'},
managed_objs={'modifier'},
props={'preview_active'},
)
def on_preview_changed(self, managed_objs, props):
"""Enables/disables previewing of the GeoNodes-driven mesh, regardless of whether a particular GeoNodes tree is chosen."""
mesh = managed_objs['mesh']
# Push Preview State to Managed Mesh
if props['preview_active']:
mesh.show_preview()
managed_objs['modifier'].show_preview()
else:
mesh.hide_preview()
managed_objs['modifier'].hide_preview()
@events.on_value_changed(
# Trigger
@ -196,7 +191,7 @@ class GaussianBeamSourceNode(base.MaxwellSimNode):
prop_name={'injection_axis', 'injection_direction'},
run_on_init=True,
# Loaded
managed_objs={'mesh', 'modifier'},
managed_objs={'modifier'},
props={'injection_axis', 'injection_direction'},
input_sockets={
'Temporal Shape',
@ -222,7 +217,6 @@ class GaussianBeamSourceNode(base.MaxwellSimNode):
# Push Input Values to GeoNodes Modifier
managed_objs['modifier'].bl_modifier(
managed_objs['mesh'].bl_object(location=input_sockets['Center']),
'NODES',
{
'node_group': import_geonodes(GeoNodes.SourceGaussianBeam),
@ -240,6 +234,7 @@ class GaussianBeamSourceNode(base.MaxwellSimNode):
'Waist Radius': input_sockets['Waist Radius'],
},
},
location=input_sockets['Center'],
)

View File

@ -56,7 +56,6 @@ class PointDipoleSourceNode(base.MaxwellSimNode):
}
managed_obj_types: typ.ClassVar = {
'mesh': managed_objs.ManagedBLMesh,
'modifier': managed_objs.ManagedBLModifier,
}
@ -106,27 +105,24 @@ class PointDipoleSourceNode(base.MaxwellSimNode):
# - Preview
####################
@events.on_value_changed(
# Trigger
prop_name='preview_active',
run_on_init=True,
# Loaded
managed_objs={'modifier'},
props={'preview_active'},
managed_objs={'mesh'},
)
def on_preview_changed(self, props, managed_objs) -> None:
"""Enables/disables previewing of the GeoNodes-driven mesh, regardless of whether a particular GeoNodes tree is chosen."""
mesh = managed_objs['mesh']
# Push Preview State to Managed Mesh
def on_preview_changed(self, managed_objs, props):
if props['preview_active']:
mesh.show_preview()
managed_objs['modifier'].show_preview()
else:
mesh.hide_preview()
managed_objs['modifier'].hide_preview()
@events.on_value_changed(
socket_name={'Center'},
prop_name='pol_axis',
run_on_init=True,
# Pass Data
managed_objs={'mesh', 'modifier'},
managed_objs={'modifier'},
props={'pol_axis'},
input_sockets={'Center'},
unit_systems={'BlenderUnits': ct.UNITS_BLENDER},
@ -135,9 +131,7 @@ class PointDipoleSourceNode(base.MaxwellSimNode):
def on_inputs_changed(
self, managed_objs, props, input_sockets, unit_systems
) -> None:
mesh = managed_objs['mesh']
modifier = managed_objs['modifier']
center = input_sockets['Center']
unit_system = unit_systems['BlenderUnits']
axis = {
ct.SimSpaceAxis.X: 0,
@ -147,13 +141,13 @@ class PointDipoleSourceNode(base.MaxwellSimNode):
# Push Loose Input Values to GeoNodes Modifier
modifier.bl_modifier(
mesh.bl_object(location=center),
'NODES',
{
'node_group': import_geonodes(GeoNodes.SourcePointDipole),
'inputs': {'Axis': axis},
'unit_system': unit_system,
},
location=input_sockets['Center'],
)

View File

@ -14,16 +14,15 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# from . import cylinder_structure
from . import box_structure, sphere_structure
from . import box_structure, cylinder_structure, sphere_structure
BL_REGISTER = [
*box_structure.BL_REGISTER,
# *cylinder_structure.BL_REGISTER,
*cylinder_structure.BL_REGISTER,
*sphere_structure.BL_REGISTER,
]
BL_NODES = {
**box_structure.BL_NODES,
# **cylinder_structure.BL_NODES,
**cylinder_structure.BL_NODES,
**sphere_structure.BL_NODES,
}

View File

@ -43,15 +43,11 @@ class BoxStructureNode(base.MaxwellSimNode):
'Medium': sockets.MaxwellMediumSocketDef(),
'Center': sockets.ExprSocketDef(
size=spux.NumberSize1D.Vec3,
mathtype=spux.MathType.Real,
physical_type=spux.PhysicalType.Length,
default_unit=spu.micrometer,
default_value=sp.Matrix([0, 0, 0]),
),
'Size': sockets.ExprSocketDef(
size=spux.NumberSize1D.Vec3,
mathtype=spux.MathType.Real,
physical_type=spux.PhysicalType.Length,
default_unit=spu.nanometer,
default_value=sp.Matrix([500, 500, 500]),
abs_min=0.001,
@ -62,7 +58,6 @@ class BoxStructureNode(base.MaxwellSimNode):
}
managed_obj_types: typ.ClassVar = {
'mesh': managed_objs.ManagedBLMesh,
'modifier': managed_objs.ManagedBLModifier,
}
@ -91,25 +86,25 @@ class BoxStructureNode(base.MaxwellSimNode):
# - Preview
####################
@events.on_value_changed(
# Trigger
prop_name='preview_active',
run_on_init=True,
# Loaded
managed_objs={'modifier'},
props={'preview_active'},
managed_objs={'mesh'},
)
def on_preview_changed(self, props, managed_objs) -> None:
mesh = managed_objs['mesh']
# Push Preview State to Managed Mesh
def on_preview_changed(self, managed_objs, props):
if props['preview_active']:
mesh.show_preview()
managed_objs['modifier'].show_preview()
else:
mesh.hide_preview()
managed_objs['modifier'].hide_preview()
@events.on_value_changed(
# Trigger
socket_name={'Center', 'Size'},
run_on_init=True,
# Loaded
input_sockets={'Center', 'Size'},
managed_objs={'mesh', 'modifier'},
managed_objs={'modifier'},
unit_systems={'BlenderUnits': ct.UNITS_BLENDER},
scale_input_sockets={
'Center': 'BlenderUnits',
@ -121,21 +116,17 @@ class BoxStructureNode(base.MaxwellSimNode):
input_sockets,
unit_systems,
):
mesh = managed_objs['mesh']
modifier = managed_objs['modifier']
center = input_sockets['Center']
size = input_sockets['Size']
unit_system = unit_systems['BlenderUnits']
# Push Loose Input Values to GeoNodes Modifier
modifier.bl_modifier(
mesh.bl_object(location=center),
managed_objs['modifier'].bl_modifier(
'NODES',
{
'node_group': import_geonodes(GeoNodes.StructurePrimitiveBox),
'inputs': {'Size': size},
'unit_system': unit_system,
'unit_system': unit_systems['BlenderUnits'],
'inputs': {
'Size': input_sockets['Size'],
},
},
location=input_sockets['Center'],
)

View File

@ -14,62 +14,127 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import typing as typ
import sympy as sp
import sympy.physics.units as spu
import tidy3d as td
from .... import contracts, sockets
from blender_maxwell.assets.geonodes import GeoNodes, import_geonodes
from blender_maxwell.utils import extra_sympy_units as spux
from blender_maxwell.utils import logger
from .... import contracts as ct
from .... import managed_objs, sockets
from ... import base, events
log = logger.get(__name__)
class CylinderStructureNode(base.MaxwellSimTreeNode):
node_type = contracts.NodeType.CylinderStructure
class CylinderStructureNode(base.MaxwellSimNode):
node_type = ct.NodeType.CylinderStructure
bl_label = 'Cylinder Structure'
# bl_icon = ...
use_sim_node_name = True
####################
# - Sockets
####################
input_sockets = {
'medium': sockets.MaxwellMediumSocketDef(
label='Medium',
input_sockets: typ.ClassVar = {
'Medium': sockets.MaxwellMediumSocketDef(),
'Center': sockets.ExprSocketDef(
size=spux.NumberSize1D.Vec3,
default_unit=spu.micrometer,
default_value=sp.Matrix([0, 0, 0]),
),
'center': sockets.PhysicalPoint3DSocketDef(
label='Center',
'Radius': sockets.ExprSocketDef(
default_unit=spu.nanometer,
default_value=150,
),
'radius': sockets.PhysicalLengthSocketDef(
label='Radius',
),
'height': sockets.PhysicalLengthSocketDef(
label='Height',
'Height': sockets.ExprSocketDef(
default_unit=spu.nanometer,
default_value=500,
),
}
output_sockets = {
'structure': sockets.MaxwellStructureSocketDef(
label='Structure',
),
output_sockets: typ.ClassVar = {
'Structure': sockets.MaxwellStructureSocketDef(),
}
managed_obj_types: typ.ClassVar = {
'modifier': managed_objs.ManagedBLModifier,
}
####################
# - Output Socket Computation
####################
@events.computes_output_socket('structure')
def compute_simulation(self: contracts.NodeTypeProtocol) -> td.Box:
medium = self.compute_input('medium')
_center = self.compute_input('center')
_radius = self.compute_input('radius')
_height = self.compute_input('height')
center = tuple(spu.convert_to(_center, spu.um) / spu.um)
radius = spu.convert_to(_radius, spu.um) / spu.um
height = spu.convert_to(_height, spu.um) / spu.um
@events.computes_output_socket(
'Structure',
input_sockets={'Center', 'Radius', 'Medium', 'Height'},
unit_systems={'Tidy3DUnits': ct.UNITS_TIDY3D},
scale_input_sockets={
'Center': 'Tidy3DUnits',
'Radius': 'Tidy3DUnits',
'Height': 'Tidy3DUnits',
},
)
def compute_structure(self, input_sockets, unit_systems) -> td.Box:
return td.Structure(
geometry=td.Cylinder(
radius=radius,
center=center,
length=height,
radius=input_sockets['Radius'],
center=input_sockets['Center'],
length=input_sockets['Height'],
),
medium=medium,
medium=input_sockets['Medium'],
)
####################
# - Preview
####################
@events.on_value_changed(
# Trigger
prop_name='preview_active',
# Loaded
managed_objs={'modifier'},
props={'preview_active'},
)
def on_preview_changed(self, managed_objs, props):
if props['preview_active']:
managed_objs['modifier'].show_preview()
else:
managed_objs['modifier'].hide_preview()
@events.on_value_changed(
# Trigger
socket_name={'Center', 'Radius', 'Medium', 'Height'},
run_on_init=True,
# Loaded
input_sockets={'Center', 'Radius', 'Medium', 'Height'},
managed_objs={'modifier'},
unit_systems={'BlenderUnits': ct.UNITS_BLENDER},
scale_input_sockets={
'Center': 'BlenderUnits',
},
)
def on_inputs_changed(
self,
managed_objs,
input_sockets,
unit_systems,
):
modifier = managed_objs['modifier']
unit_system = unit_systems['BlenderUnits']
# Push Loose Input Values to GeoNodes Modifier
modifier.bl_modifier(
'NODES',
{
'node_group': import_geonodes(GeoNodes.StructurePrimitiveCylinder),
'inputs': {
'Radius': input_sockets['Radius'],
'Height': input_sockets['Height'],
},
'unit_system': unit_system,
},
location=input_sockets['Center'],
)
@ -80,7 +145,5 @@ BL_REGISTER = [
CylinderStructureNode,
]
BL_NODES = {
contracts.NodeType.CylinderStructure: (
contracts.NodeCategory.MAXWELLSIM_STRUCTURES_PRIMITIVES
)
ct.NodeType.CylinderStructure: (ct.NodeCategory.MAXWELLSIM_STRUCTURES_PRIMITIVES)
}

View File

@ -56,7 +56,6 @@ class SphereStructureNode(base.MaxwellSimNode):
}
managed_obj_types: typ.ClassVar = {
'mesh': managed_objs.ManagedBLMesh,
'modifier': managed_objs.ManagedBLModifier,
}
@ -85,25 +84,25 @@ class SphereStructureNode(base.MaxwellSimNode):
# - Preview
####################
@events.on_value_changed(
# Trigger
prop_name='preview_active',
run_on_init=True,
# Loaded
managed_objs={'modifier'},
props={'preview_active'},
managed_objs={'mesh'},
)
def on_preview_changed(self, props, managed_objs) -> None:
mesh = managed_objs['mesh']
# Push Preview State to Managed Mesh
def on_preview_changed(self, managed_objs, props):
if props['preview_active']:
mesh.show_preview()
managed_objs['modifier'].show_preview()
else:
mesh.hide_preview()
managed_objs['modifier'].hide_preview()
@events.on_value_changed(
# Trigger
socket_name={'Center', 'Radius'},
run_on_init=True,
# Loaded
input_sockets={'Center', 'Radius'},
managed_objs={'mesh', 'modifier'},
managed_objs={'modifier'},
unit_systems={'BlenderUnits': ct.UNITS_BLENDER},
scale_input_sockets={
'Center': 'BlenderUnits',
@ -115,21 +114,20 @@ class SphereStructureNode(base.MaxwellSimNode):
input_sockets,
unit_systems,
):
mesh = managed_objs['mesh']
modifier = managed_objs['modifier']
center = input_sockets['Center']
radius = input_sockets['Radius']
unit_system = unit_systems['BlenderUnits']
# Push Loose Input Values to GeoNodes Modifier
modifier.bl_modifier(
mesh.bl_object(location=center),
'NODES',
{
'node_group': import_geonodes(GeoNodes.StructurePrimitiveSphere),
'inputs': {'Radius': radius},
'inputs': {
'Radius': input_sockets['Radius'],
},
'unit_system': unit_system,
},
location=input_sockets['Center'],
)

View File

@ -17,9 +17,13 @@
import bpy
import tidy3d as td
from blender_maxwell.utils import bl_cache, logger
from ... import contracts as ct
from .. import base
log = logger.get(__name__)
class MaxwellSimGridBLSocket(base.MaxwellSimSocket):
socket_type = ct.SocketType.MaxwellSimGrid
@ -28,17 +32,7 @@ class MaxwellSimGridBLSocket(base.MaxwellSimSocket):
####################
# - Properties
####################
min_steps_per_wl: bpy.props.FloatProperty(
name='Minimum Steps per Wavelength',
description='How many grid steps to ensure per wavelength',
default=10.0,
min=0.01,
# step=10,
precision=2,
update=(
lambda self, context: self.on_prop_changed('min_steps_per_wl', context)
),
)
min_steps_per_wl: float = bl_cache.BLField(10.0, abs_min=0.01, float_prec=2)
####################
# - Socket UI
@ -50,7 +44,7 @@ class MaxwellSimGridBLSocket(base.MaxwellSimSocket):
col.label(text='min. stp/λ')
col = split.column(align=True)
col.prop(self, 'min_steps_per_wl', text='')
col.prop(self, self.blfields['min_steps_per_wl'], text='')
####################
# - Computation of Default Value