luminarycloud 0.15.5__py3-none-any.whl → 0.16.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. luminarycloud/_client/client.py +5 -0
  2. luminarycloud/_helpers/__init__.py +1 -0
  3. luminarycloud/_helpers/_code_representation.py +21 -4
  4. luminarycloud/_helpers/download.py +67 -1
  5. luminarycloud/_proto/api/v0/luminarycloud/inference/inference_pb2.py +9 -9
  6. luminarycloud/_proto/api/v0/luminarycloud/inference/inference_pb2.pyi +7 -4
  7. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2.py +45 -21
  8. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2.pyi +65 -0
  9. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2_grpc.py +34 -0
  10. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2_grpc.pyi +12 -0
  11. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.py +194 -7
  12. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.pyi +407 -5
  13. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.py +171 -0
  14. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.pyi +64 -0
  15. luminarycloud/_proto/api/v0/luminarycloud/upload/upload_pb2.py +4 -2
  16. luminarycloud/_proto/api/v0/luminarycloud/upload/upload_pb2_grpc.py +34 -0
  17. luminarycloud/_proto/api/v0/luminarycloud/upload/upload_pb2_grpc.pyi +12 -0
  18. luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2.py +128 -107
  19. luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2.pyi +48 -3
  20. luminarycloud/_proto/assistant/assistant_pb2.py +82 -61
  21. luminarycloud/_proto/assistant/assistant_pb2.pyi +40 -0
  22. luminarycloud/_proto/assistant/assistant_pb2_grpc.py +34 -0
  23. luminarycloud/_proto/assistant/assistant_pb2_grpc.pyi +12 -0
  24. luminarycloud/_proto/base/base_pb2.py +7 -6
  25. luminarycloud/_proto/base/base_pb2.pyi +4 -0
  26. luminarycloud/_proto/client/simulation_pb2.py +351 -351
  27. luminarycloud/_proto/client/simulation_pb2.pyi +105 -97
  28. luminarycloud/_proto/geometry/geometry_pb2.py +68 -68
  29. luminarycloud/_proto/geometry/geometry_pb2.pyi +15 -7
  30. luminarycloud/_proto/hexmesh/hexmesh_pb2.py +40 -15
  31. luminarycloud/_proto/hexmesh/hexmesh_pb2.pyi +58 -1
  32. luminarycloud/_proto/inferenceservice/inferenceservice_pb2.py +11 -11
  33. luminarycloud/_proto/inferenceservice/inferenceservice_pb2.pyi +12 -4
  34. luminarycloud/_proto/lcstatus/codes_pb2.py +3 -2
  35. luminarycloud/_proto/lcstatus/codes_pb2.pyi +4 -0
  36. luminarycloud/_proto/quantity/quantity_pb2.py +11 -2
  37. luminarycloud/_proto/quantity/quantity_pb2.pyi +6 -0
  38. luminarycloud/_proto/table/table_pb2.pyi +4 -2
  39. luminarycloud/_proto/upload/upload_pb2.py +27 -7
  40. luminarycloud/_proto/upload/upload_pb2.pyi +31 -0
  41. luminarycloud/enum/quantity_type.py +19 -0
  42. luminarycloud/enum/tables.py +1 -0
  43. luminarycloud/enum/vis_enums.py +20 -0
  44. luminarycloud/feature_modification.py +6 -7
  45. luminarycloud/geometry.py +24 -0
  46. luminarycloud/geometry_version.py +23 -0
  47. luminarycloud/mesh.py +8 -1
  48. luminarycloud/params/simulation/adjoint_.py +4 -4
  49. luminarycloud/params/simulation/material/material_fluid_.py +1 -1
  50. luminarycloud/params/simulation/material/material_solid_.py +1 -1
  51. luminarycloud/params/simulation/output_.py +1 -1
  52. luminarycloud/params/simulation/physics/fluid/initialization/fluid_existing_solution_.py +28 -0
  53. luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method/fluid_implicit_relaxation/robust_startup/__init__.py +1 -0
  54. luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method/fluid_implicit_relaxation/robust_startup/robust_startup_auto_.py +30 -0
  55. luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method/fluid_implicit_relaxation/robust_startup/robust_startup_on_.py +1 -1
  56. luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method/fluid_implicit_relaxation_.py +6 -2
  57. luminarycloud/params/simulation/physics/fluid/solution_controls_fluid_.py +4 -0
  58. luminarycloud/params/simulation/simulation_param_.py +6 -0
  59. luminarycloud/physics_ai/__init__.py +4 -0
  60. luminarycloud/physics_ai/inference.py +140 -4
  61. luminarycloud/physics_ai/solution.py +60 -0
  62. luminarycloud/project.py +9 -7
  63. luminarycloud/simulation_param.py +29 -15
  64. luminarycloud/simulation_template.py +14 -10
  65. luminarycloud/tables.py +11 -12
  66. luminarycloud/thirdparty/__init__.py +12 -0
  67. luminarycloud/thirdparty/onshape.py +170 -0
  68. luminarycloud/vis/__init__.py +2 -0
  69. luminarycloud/vis/data_extraction.py +44 -6
  70. luminarycloud/vis/display.py +26 -11
  71. luminarycloud/vis/filters.py +226 -67
  72. luminarycloud/vis/primitives.py +3 -2
  73. luminarycloud/vis/visualization.py +198 -41
  74. luminarycloud/volume_selection.py +2 -2
  75. {luminarycloud-0.15.5.dist-info → luminarycloud-0.16.1.dist-info}/METADATA +6 -6
  76. {luminarycloud-0.15.5.dist-info → luminarycloud-0.16.1.dist-info}/RECORD +77 -73
  77. {luminarycloud-0.15.5.dist-info → luminarycloud-0.16.1.dist-info}/WHEEL +0 -0
@@ -15,9 +15,10 @@ from .display import Field, DisplayAttributes
15
15
  from typing import List, Any, cast
16
16
  from .primitives import Box, Plane
17
17
  from .vis_util import generate_id
18
+ from .._helpers._code_representation import CodeRepr
18
19
 
19
20
 
20
- class Filter(ABC):
21
+ class Filter(ABC, CodeRepr):
21
22
  """
22
23
  This is the base class for all filters. Each derived filter class
23
24
  is responsible for providing a _to_proto method to convert to a filter
@@ -95,7 +96,7 @@ class Slice(Filter):
95
96
  Specifies this filter's appearance.
96
97
  """
97
98
 
98
- def __init__(self, name: str) -> None:
99
+ def __init__(self, name: str = "") -> None:
99
100
  super().__init__(generate_id("slice-"))
100
101
  self._plane = Plane()
101
102
  self._project_vectors: bool = False
@@ -166,7 +167,7 @@ class Isosurface(Filter):
166
167
  Specifies this filter's appearance.
167
168
  """
168
169
 
169
- def __init__(self, name: str) -> None:
170
+ def __init__(self, name: str = "") -> None:
170
171
  super().__init__(generate_id("contour-"))
171
172
  self.isovalues: List[float] = []
172
173
  self.field: Field = Field()
@@ -233,11 +234,9 @@ class PlaneClip(Filter):
233
234
  are removed. Default: False
234
235
  """
235
236
 
236
- def __init__(self, name: str) -> None:
237
+ def __init__(self, name: str = "") -> None:
237
238
  super().__init__(generate_id("planeClip-"))
238
239
  self._plane: Plane = Plane()
239
- # TODO(matt): We could make this a prop to that is unsettable. Or we could
240
- # not use ids and force that the filter names are unique.
241
240
  self.name = name
242
241
  self.inverted: bool = False
243
242
 
@@ -296,7 +295,7 @@ class BoxClip(Filter):
296
295
  Default : False
297
296
  """
298
297
 
299
- def __init__(self, name: str) -> None:
298
+ def __init__(self, name: str = "") -> None:
300
299
  super().__init__(generate_id("boxClip-"))
301
300
  self._box: Box = Box()
302
301
  self.name = name
@@ -358,17 +357,11 @@ class VectorGlyphs(Filter):
358
357
 
359
358
  """
360
359
 
361
- def __init__(self, name: str) -> None:
360
+ def __init__(self, name: str = "") -> None:
362
361
  super().__init__(generate_id("vector-"))
363
362
  self.name: str = name
364
- # TODO(matt): we should be able to help set some reasonable defaults bases
365
- # on the mesh size (i.e., number of points) and bounds (the default glyph size).
366
- # The scene has accesss to this theoretically. Perhaps the scene class can be used
367
- # as a factory.
368
363
  self._sampling_rate: int = 500
369
- self.field: Field = Field()
370
- # TODO(matt): we should only allow vectors somehow
371
- self.field.quantity = VisQuantity.VELOCITY
364
+ self.quantity: VisQuantity = VisQuantity.VELOCITY
372
365
 
373
366
  @property
374
367
  def sampling_rate(self) -> int:
@@ -403,11 +396,11 @@ class FixedSizeVectorGlyphs(VectorGlyphs):
403
396
  The size in world units (meters) of the glyphs.
404
397
  display_attrs (DisplayAttributes)
405
398
  Specifies this filters appearance.
406
- field: Field
399
+ quantity: VisQuantity
407
400
  The vector field to use for glyph generation. Default: Velocity
408
401
  """
409
402
 
410
- def __init__(self, name: str) -> None:
403
+ def __init__(self, name: str = "") -> None:
411
404
  super().__init__(name)
412
405
  self.size: float = 1.0
413
406
 
@@ -418,10 +411,10 @@ class FixedSizeVectorGlyphs(VectorGlyphs):
418
411
  vis_filter.glyph.fixed_size_glyphs = self.size
419
412
  vis_filter.glyph.n_glyphs = self.sampling_rate
420
413
  vis_filter.glyph.sampling_mode = vis_pb2.GLYPH_SAMPLING_MODE_EVERY_NTH
421
- if not quantity_type._is_vector(self.field.quantity):
414
+ if not quantity_type._is_vector(self.quantity):
422
415
  raise ValueError("FixedSizeVectorGlyphs: field must be a vector type")
423
- vis_filter.glyph.field.quantity_typ = self.field.quantity.value
424
- vis_filter.glyph.field.component = self.field.component.value
416
+ vis_filter.glyph.field.quantity_typ = self.quantity.value
417
+ vis_filter.glyph.field.component = vis_pb2.Field.COMPONENT_UNSPECIFIED
425
418
  return vis_filter
426
419
 
427
420
  def _from_proto(self, filter: vis_pb2.Filter) -> None:
@@ -436,8 +429,7 @@ class FixedSizeVectorGlyphs(VectorGlyphs):
436
429
  self.n_glyphs = filter.glyph.n_glyphs
437
430
  self.size = filter.glyph.fixed_size_glyphs
438
431
  self.sampling_rate = filter.glyph.n_glyphs
439
- self.field.quantity = VisQuantity(filter.glyph.field.quantity_typ)
440
- self.field.component = FieldComponent(filter.glyph.field.component)
432
+ self.quantity = VisQuantity(filter.glyph.field.quantity_typ)
441
433
 
442
434
 
443
435
  class ScaledVectorGlyphs(VectorGlyphs):
@@ -464,11 +456,11 @@ class ScaledVectorGlyphs(VectorGlyphs):
464
456
  0.5 and the scale is 2 then the resulting world space size is 1 meter. Default: 1.
465
457
  display_attrs (DisplayAttributes)
466
458
  Specifies this filters appearance.
467
- field: Field
459
+ quantity: VisQuantity
468
460
  The vector field to use for glyph generation. Default: Velocity
469
461
  """
470
462
 
471
- def __init__(self, name: str) -> None:
463
+ def __init__(self, name: str = "") -> None:
472
464
  super().__init__(name)
473
465
  self.scale: float = 1.0
474
466
 
@@ -479,10 +471,10 @@ class ScaledVectorGlyphs(VectorGlyphs):
479
471
  vis_filter.glyph.glyph_scale_size = self.scale
480
472
  vis_filter.glyph.n_glyphs = self.sampling_rate
481
473
  vis_filter.glyph.sampling_mode = vis_pb2.GLYPH_SAMPLING_MODE_EVERY_NTH
482
- if not quantity_type._is_vector(self.field.quantity):
474
+ if not quantity_type._is_vector(self.quantity):
483
475
  raise ValueError("ScaledVectorGyph: field must be a vector type")
484
- vis_filter.glyph.field.quantity_typ = self.field.quantity.value
485
- vis_filter.glyph.field.component = self.field.component.value
476
+ vis_filter.glyph.field.quantity_typ = self.quantity.value
477
+ vis_filter.glyph.field.component = vis_pb2.Field.COMPONENT_UNSPECIFIED
486
478
  return vis_filter
487
479
 
488
480
  def _from_proto(self, filter: vis_pb2.Filter) -> None:
@@ -497,8 +489,7 @@ class ScaledVectorGlyphs(VectorGlyphs):
497
489
  self.n_glyphs = filter.glyph.n_glyphs
498
490
  self.scale = filter.glyph.glyph_scale_size
499
491
  self.sampling_rate = filter.glyph.n_glyphs
500
- self.field.quantity = VisQuantity(filter.glyph.field.quantity_typ)
501
- self.field.component = FieldComponent(filter.glyph.field.component)
492
+ self.quantity = VisQuantity(filter.glyph.field.quantity_typ)
502
493
 
503
494
 
504
495
  class Threshold(Filter):
@@ -533,7 +524,7 @@ class Threshold(Filter):
533
524
  Specifies this filter's appearance.
534
525
  """
535
526
 
536
- def __init__(self, name: str) -> None:
527
+ def __init__(self, name: str = "") -> None:
537
528
  super().__init__(generate_id("threshold-"))
538
529
  self.field: Field = Field()
539
530
  self.min_value: float = 0.0
@@ -610,14 +601,13 @@ class Streamlines(Filter):
610
601
  Specifies this filter's appearance.
611
602
  """
612
603
 
613
- def __init__(self, name: str) -> None:
604
+ def __init__(self, name: str = "") -> None:
614
605
  super().__init__(generate_id("streamlines-"))
615
606
  self.name: str = name
616
607
  self.n_streamlines: int = 100
617
608
  self.max_length: float = 10
618
609
  self.direction: StreamlineDirection = StreamlineDirection.FORWARD
619
- self.field: Field = Field()
620
- self.field.quantity = VisQuantity.VELOCITY
610
+ self.quantity: VisQuantity = VisQuantity.VELOCITY
621
611
 
622
612
 
623
613
  class RakeStreamlines(Streamlines):
@@ -640,8 +630,8 @@ class RakeStreamlines(Streamlines):
640
630
  The number of seed particles to place on the rake. Default: 100
641
631
  max_length: float
642
632
  The maximum path length of the particle in meters. Default: 10
643
- field: Field
644
- The vector field to used for the particle advection. Default: Velocity
633
+ quantity: VisQuantity
634
+ The vector field to use for the particle advection. Default: Velocity
645
635
  start: Vector3Like
646
636
  The start point of the rake. Default: [0,0,0].
647
637
  end: Vector3Like
@@ -652,10 +642,10 @@ class RakeStreamlines(Streamlines):
652
642
  Specifies this filter's appearance.
653
643
  """
654
644
 
655
- def __init__(self, name: str) -> None:
645
+ def __init__(self, name: str = "") -> None:
656
646
  super().__init__(name)
657
- self.start: Vector3Like = dc.field(default_factory=lambda: Vector3(x=0, y=0, z=0))
658
- self.end: Vector3Like = dc.field(default_factory=lambda: Vector3(x=1, y=0, z=0))
647
+ self.start: Vector3Like = Vector3(x=0, y=0, z=0)
648
+ self.end: Vector3Like = Vector3(x=1, y=0, z=0)
659
649
 
660
650
  def _to_proto(self) -> vis_pb2.Filter:
661
651
  # Type checking
@@ -663,8 +653,8 @@ class RakeStreamlines(Streamlines):
663
653
  raise TypeError(f"Expected 'int', got {type(self.n_streamlines).__name__}")
664
654
  if not isinstance(self.max_length, (float, int)):
665
655
  raise TypeError(f"Expected 'float or int', got {type(self.max_length).__name__}")
666
- if not isinstance(self.field, Field):
667
- raise TypeError(f"Expected 'Field', got {type(self.field).__name__}")
656
+ if not isinstance(self.quantity, VisQuantity):
657
+ raise TypeError(f"Expected 'VisQuantity', got {type(self.quantity).__name__}")
668
658
 
669
659
  vis_filter = vis_pb2.Filter()
670
660
  vis_filter.id = self.id
@@ -673,9 +663,9 @@ class RakeStreamlines(Streamlines):
673
663
  vis_filter.streamlines.max_length = self.max_length
674
664
  vis_filter.streamlines.rake.start.CopyFrom(_to_vector3(self.start)._to_proto())
675
665
  vis_filter.streamlines.rake.end.CopyFrom(_to_vector3(self.end)._to_proto())
676
- if not quantity_type._is_vector(self.field.quantity):
666
+ if not quantity_type._is_vector(self.quantity):
677
667
  raise ValueError("RakeStreamlines: field must be a vector type")
678
- vis_filter.streamlines.field.quantity_typ = self.field.quantity.value
668
+ vis_filter.streamlines.field.quantity_typ = self.quantity.value
679
669
  return vis_filter
680
670
 
681
671
  def _from_proto(self, filter: vis_pb2.Filter) -> None:
@@ -694,7 +684,131 @@ class RakeStreamlines(Streamlines):
694
684
  self.start._from_proto(filter.streamlines.rake.start)
695
685
  self.end = Vector3()
696
686
  self.end._from_proto(filter.streamlines.rake.end)
697
- self.field.quantity = VisQuantity(filter.streamlines.field.quantity_typ)
687
+ self.quantity = VisQuantity(filter.streamlines.field.quantity_typ)
688
+
689
+
690
+ class GridStreamlines(Streamlines):
691
+ """
692
+ Streamlines is a vector field visualization technique that integrates
693
+ massless particles through a vector field forming curves. Streamlines are
694
+ used to visualize and analyze fluid flow patterns (e.g., the velocity
695
+ field), helping to understand how the fluid moves. Streamlines
696
+ can be use used to visualize any vector field contained in the solution.
697
+
698
+ GridStreamlines generates seed particles arranged in a 2D grid pattern
699
+ inside the volume. GridStreamlines only work with volume data.
700
+
701
+ The grid is defined by a center point and two vectors that define the u
702
+ (rake_direction) and v (seed_direction) directions of the grid. It's
703
+ recommended that the rake_direction and seed_direction vectors are
704
+ orthogonal to each other, but it's not required. Rakes (sets of seed
705
+ particles) are generated in the rake_direction. Seed particles are
706
+ distributed along the seed_direction. The rake spacing controls the distance
707
+ between the rakes, and the seed spacing controls the distance between the
708
+ seed particles along the rake.
709
+
710
+ For example, if the rake vector is [1,0,0] and the seed vector is [0,1,0],
711
+ then the rakes will be generated in the x direction and the seed particles
712
+ will be generated in the y direction. Lets say we want to create a grid of
713
+ of 4x4 particles that is 8 meters wide and 2 meters tall. The rake spacing
714
+ would be 2 meters / 4 = 0.5 meters, and the seed spacing would be 8 meters /
715
+ 4 = 2 meters.
716
+
717
+ .. warning:: This feature is experimental and may change or be removed in the future.
718
+
719
+ Attributes:
720
+ -----------
721
+ max_length: float
722
+ The maximum path length of the particle in meters. Default: 10
723
+ quantity: VisQuantity
724
+ The vector field to use for the particle advection. Default: Velocity
725
+ rake_direction: Vector3Like
726
+ The vector defining the u direction of the grid along which the rakes are placed.
727
+ Default: [1,0,0].
728
+ seed_direction: Vector3Like
729
+ The vector defining the v direction of the grid along which the seed particles are placed.
730
+ Default: [0,1,0].
731
+ center: Vector3Like
732
+ The center point of the grid. Default: [0,0,0].
733
+ rake_res: int
734
+ The number of rake lines to generate in the u direction. Default: 2.
735
+ seed_res: int
736
+ The number of seed particles to generate in the v direction. Default: 10.
737
+ rake_spacing: float
738
+ The spacing between the rake lines in meters. Default: 0.5.
739
+ seed_spacing: float
740
+ The spacing between the seed particles in meters. Default: 0.1.
741
+ name : str
742
+ A user provided name for the filter.
743
+ display_attrs : DisplayAttributes
744
+ Specifies this filter's appearance.
745
+ """
746
+
747
+ def __init__(self, name: str = "") -> None:
748
+ super().__init__(name)
749
+ self.rake_direction: Vector3Like = Vector3(x=1, y=0, z=0)
750
+ self.seed_direction: Vector3Like = Vector3(x=0, y=1, z=0)
751
+ self.center: Vector3Like = Vector3(x=0, y=0, z=0)
752
+ self.rake_res: int = 2
753
+ self.seed_res: int = 10
754
+ self.rake_spacing: float = 0.5
755
+ self.seed_spacing: float = 0.1
756
+
757
+ def _to_proto(self) -> vis_pb2.Filter:
758
+ # Type checking
759
+ if not isinstance(self.max_length, (float, int)):
760
+ raise TypeError(f"Expected 'float or int', got {type(self.max_length).__name__}")
761
+ if not isinstance(self.quantity, VisQuantity):
762
+ raise TypeError(f"Expected 'VisQuantity', got {type(self.quantity).__name__}")
763
+ if not isinstance(self.rake_res, int):
764
+ raise TypeError(f"Expected 'int', got {type(self.rake_res).__name__}")
765
+ if not isinstance(self.seed_res, int):
766
+ raise TypeError(f"Expected 'int', got {type(self.seed_res).__name__}")
767
+ if not isinstance(self.rake_spacing, (float, int)):
768
+ raise TypeError(f"Expected 'float or int', got {type(self.rake_spacing).__name__}")
769
+ if not isinstance(self.seed_spacing, (float, int)):
770
+ raise TypeError(f"Expected 'float or int', got {type(self.seed_spacing).__name__}")
771
+
772
+ vis_filter = vis_pb2.Filter()
773
+ vis_filter.id = self.id
774
+ vis_filter.name = self.name
775
+ vis_filter.streamlines.max_length = self.max_length
776
+ vis_filter.streamlines.grid.center.CopyFrom(_to_vector3(self.center)._to_proto())
777
+ vis_filter.streamlines.grid.u_vec.CopyFrom(_to_vector3(self.rake_direction)._to_proto())
778
+ vis_filter.streamlines.grid.v_vec.CopyFrom(_to_vector3(self.seed_direction)._to_proto())
779
+ vis_filter.streamlines.grid.rake_res = self.rake_res
780
+ vis_filter.streamlines.grid.seed_res = self.seed_res
781
+ vis_filter.streamlines.grid.rake_spacing = self.rake_spacing
782
+ vis_filter.streamlines.grid.seed_spacing = self.seed_spacing
783
+
784
+ if not quantity_type._is_vector(self.quantity):
785
+ raise ValueError("GridStreamlines: field must be a vector type")
786
+ vis_filter.streamlines.field.quantity_typ = self.quantity.value
787
+ return vis_filter
788
+
789
+ def _from_proto(self, filter: vis_pb2.Filter) -> None:
790
+ typ = filter.WhichOneof("value")
791
+ if typ != "streamlines":
792
+ raise TypeError(f"Expected 'streamlines', got {typ}")
793
+ s_typ = filter.streamlines.WhichOneof("seed_type")
794
+ if s_typ != "grid":
795
+ raise TypeError(f"Expected 'grid streamlines', got {s_typ}")
796
+ self.id = filter.id
797
+ self.name = filter.name
798
+ self.n_streamlines = filter.streamlines.n_streamlines
799
+ self.max_length = filter.streamlines.max_length
800
+
801
+ self.center = Vector3()
802
+ self.center._from_proto(filter.streamlines.grid.center)
803
+ self.rake_direction = Vector3()
804
+ self.rake_direction._from_proto(filter.streamlines.grid.u_vec)
805
+ self.seed_direction = Vector3()
806
+ self.seed_direction._from_proto(filter.streamlines.grid.v_vec)
807
+ self.rake_res = filter.streamlines.grid.rake_res
808
+ self.seed_res = filter.streamlines.grid.seed_res
809
+ self.rake_spacing = filter.streamlines.grid.rake_spacing
810
+ self.seed_spacing = filter.streamlines.grid.seed_spacing
811
+ self.quantity = VisQuantity(filter.streamlines.field.quantity_typ)
698
812
 
699
813
 
700
814
  class SurfaceStreamlines(Streamlines):
@@ -741,15 +855,15 @@ class SurfaceStreamlines(Streamlines):
741
855
  particles further into the volume based on the surface normal. Default: 0.0
742
856
  max_length: float
743
857
  The maximum path length of the particle in meters. Default: 10
744
- field: Field
745
- The vector field to used for the particle advection. Default: Velocity
858
+ quantity: VisQuantity
859
+ The vector field to use for the particle advection. Default: Velocity
746
860
  name : str
747
861
  A user provided name for the filter.
748
862
  display_attrs : DisplayAttributes
749
863
  Specifies this filter's appearance.
750
864
  """
751
865
 
752
- def __init__(self, name: str) -> None:
866
+ def __init__(self, name: str = "") -> None:
753
867
  super().__init__(name)
754
868
  self.offset: float = 0.0
755
869
  self._surface_names: List[str] = []
@@ -783,8 +897,8 @@ class SurfaceStreamlines(Streamlines):
783
897
  raise TypeError(f"Expected 'float or int', got {type(self.max_length).__name__}")
784
898
  if not isinstance(self.offset, (float, int)):
785
899
  raise TypeError(f"Expected 'float or int', got {type(self.offset).__name__}")
786
- if not isinstance(self.field, Field):
787
- raise TypeError(f"Expected 'Field', got {type(self.field).__name__}")
900
+ if not isinstance(self.quantity, VisQuantity):
901
+ raise TypeError(f"Expected 'VisQuantity', got {type(self.quantity).__name__}")
788
902
  if not isinstance(self.mode, SurfaceStreamlineMode):
789
903
  raise TypeError(f"Expected 'SurfaceStreamlinesMode', got {type(self.mode).__name__}")
790
904
 
@@ -796,12 +910,12 @@ class SurfaceStreamlines(Streamlines):
796
910
  project = False
797
911
  # Prevent common mistakes that cause confusion.
798
912
  if self.mode == SurfaceStreamlineMode.ADVECT_ON_SURFACE:
799
- if self.field.quantity == VisQuantity.VELOCITY:
913
+ if self.quantity == VisQuantity.VELOCITY:
800
914
  raise ValueError(
801
915
  "SurfacesStreamines: velocity is 0 on surfaces and will produce no data"
802
916
  )
803
917
  project = True
804
- elif self.field.quantity == VisQuantity.WALL_SHEAR_STRESS:
918
+ elif self.quantity == VisQuantity.WALL_SHEAR_STRESS:
805
919
  raise ValueError(
806
920
  "SurfacesStreamines: wall shear stress is 0 in the volume and will produce no data "
807
921
  )
@@ -811,10 +925,9 @@ class SurfaceStreamlines(Streamlines):
811
925
  raise ValueError("SurfaceStreamlines: need at least one surfaces specified.")
812
926
  for id in self._surface_names:
813
927
  vis_filter.streamlines.surface.surface_names.append(id)
814
- if not quantity_type._is_vector(self.field.quantity):
815
- raise ValueError("SurfaceStreamlines: field must be a vector type")
816
- vis_filter.streamlines.field.component = self.field.component.value
817
- vis_filter.streamlines.field.quantity_typ = self.field.quantity.value
928
+ if not quantity_type._is_vector(self.quantity):
929
+ raise ValueError("SurfaceStreamlines: quantity must be a vector type")
930
+ vis_filter.streamlines.field.quantity_typ = self.quantity.value
818
931
  return vis_filter
819
932
 
820
933
  def _from_proto(self, filter: vis_pb2.Filter) -> None:
@@ -831,7 +944,15 @@ class SurfaceStreamlines(Streamlines):
831
944
  self._surface_names.clear()
832
945
  for s in filter.streamlines.surface.surface_names:
833
946
  self._surface_names.append(s)
834
- self.field.quantity = VisQuantity(filter.streamlines.field.quantity_typ)
947
+ self.quantity = VisQuantity(filter.streamlines.field.quantity_typ)
948
+
949
+ def _to_code(self, hide_defaults: bool = True, use_tmp_objs: bool = True) -> str:
950
+ code = super()._to_code(hide_defaults=hide_defaults)
951
+ # We need to explicity write the code for the surfaces since its
952
+ # technically a private variable.
953
+ for s in self._surface_names:
954
+ code += f".add_surface('{s}')\n"
955
+ return code
835
956
 
836
957
 
837
958
  class SurfaceLIC(Filter):
@@ -855,7 +976,7 @@ class SurfaceLIC(Filter):
855
976
 
856
977
  Attributes:
857
978
  -----------
858
- field: Field
979
+ quantity: VisQuantity
859
980
  Specifies the field used to advect particles for the surface LIC.
860
981
  Default: WALL_SHEER_STRESS
861
982
  contrast: float
@@ -864,13 +985,12 @@ class SurfaceLIC(Filter):
864
985
  higher values mean more contrast. Default: 1
865
986
  """
866
987
 
867
- def __init__(self, name: str) -> None:
988
+ def __init__(self, name: str = "") -> None:
868
989
  super().__init__(generate_id("surface-lic-"))
869
990
  self.name = name
870
991
  self.contrast: float = 1.0
871
992
  self._surface_names: List[str] = []
872
- self.field: Field = Field()
873
- self.field.quantity = VisQuantity.WALL_SHEAR_STRESS
993
+ self.quantity: VisQuantity = VisQuantity.WALL_SHEAR_STRESS
874
994
 
875
995
  def add_surface(self, id: str) -> None:
876
996
  """
@@ -898,9 +1018,9 @@ class SurfaceLIC(Filter):
898
1018
  vis_filter.name = self.name
899
1019
  # Prevent common mistakes that cause confusion. The only current option
900
1020
  # is to be on a surface, so no velocity.
901
- if not isinstance(self.field, Field):
902
- raise TypeError(f"Expected 'Field', got {type(self.field).__name__}")
903
- if self.field.quantity == VisQuantity.VELOCITY:
1021
+ if not isinstance(self.quantity, VisQuantity):
1022
+ raise TypeError(f"Expected 'VisQuantity', got {type(self.quantity).__name__}")
1023
+ if self.quantity == VisQuantity.VELOCITY:
904
1024
  raise ValueError("SurfaceLIC: velocity is 0 on surfaces and will produce no data")
905
1025
  if not isinstance(self.contrast, (int, float)):
906
1026
  raise TypeError(f"Expected 'int or float', got {type(self.contrast).__name__}")
@@ -914,7 +1034,7 @@ class SurfaceLIC(Filter):
914
1034
  geometry = vis_pb2.SurfaceLICGeomtery()
915
1035
  vis_filter.surface_lic.geometry.CopyFrom(geometry)
916
1036
 
917
- vis_filter.surface_lic.field.quantity_typ = self.field.quantity.value
1037
+ vis_filter.surface_lic.field.quantity_typ = self.quantity.value
918
1038
  vis_filter.surface_lic.contrast = self.contrast
919
1039
  return vis_filter
920
1040
 
@@ -932,7 +1052,46 @@ class SurfaceLIC(Filter):
932
1052
  self._surface_names = []
933
1053
  for s in filter.surface_lic.geometry.surface_names:
934
1054
  self._surface_names.append(s)
935
- if not quantity_type._is_vector(self.field.quantity):
936
- raise ValueError("SurfaceLIC: field must be a vector type")
937
- self.field.quantity = VisQuantity(filter.surface_lic.field.quantity_typ)
938
- self.field.component = FieldComponent(filter.surface_lic.field.component)
1055
+ if not quantity_type._is_vector(self.quantity):
1056
+ raise ValueError("SurfaceLIC: quantity must be a vector type")
1057
+ self.quantity = VisQuantity(filter.surface_lic.field.quantity_typ)
1058
+
1059
+ def _to_code(self, hide_defaults: bool = True, use_tmp_objs: bool = True) -> str:
1060
+ code = super()._to_code(hide_defaults=hide_defaults)
1061
+ # We need to explicity write the code for the surfaces since its
1062
+ # technically a private variable.
1063
+ for s in self._surface_names:
1064
+ code += f".add_surface('{s}')\n"
1065
+ return code
1066
+
1067
+
1068
+ def _filter_to_obj_name(filter: Filter) -> str:
1069
+ """
1070
+ Helper function to convert a filter to a code object name used in code gen.
1071
+ """
1072
+ if not isinstance(filter, Filter):
1073
+ raise TypeError(f"Expected 'Filter', got {type(filter).__name__}")
1074
+ if isinstance(filter, Slice):
1075
+ return "slice"
1076
+ elif isinstance(filter, Isosurface):
1077
+ return "isosurface"
1078
+ elif isinstance(filter, PlaneClip):
1079
+ return "plane_clip"
1080
+ elif isinstance(filter, BoxClip):
1081
+ return "box_clip"
1082
+ elif isinstance(filter, FixedSizeVectorGlyphs):
1083
+ return "fixed_size_vector_glyphs"
1084
+ elif isinstance(filter, ScaledVectorGlyphs):
1085
+ return "scaled_vector_glyphs"
1086
+ elif isinstance(filter, Threshold):
1087
+ return "threshold"
1088
+ elif isinstance(filter, RakeStreamlines):
1089
+ return "rake_streamlines"
1090
+ elif isinstance(filter, GridStreamlines):
1091
+ return "grid_streamlines"
1092
+ elif isinstance(filter, SurfaceStreamlines):
1093
+ return "surface_streamlines"
1094
+ elif isinstance(filter, SurfaceLIC):
1095
+ return "surface_lic"
1096
+ else:
1097
+ raise TypeError(f"Unknown filter type: {type(filter).__name__}")
@@ -1,10 +1,11 @@
1
1
  # Copyright 2023-2024 Luminary Cloud, Inc. All Rights Reserved.
2
2
  import dataclasses as dc
3
3
  from luminarycloud.types import Vector3, Vector3Like
4
+ from .._helpers._code_representation import CodeRepr
4
5
 
5
6
 
6
7
  @dc.dataclass
7
- class Plane:
8
+ class Plane(CodeRepr):
8
9
  """
9
10
  This class defines a plane.
10
11
 
@@ -19,7 +20,7 @@ class Plane:
19
20
 
20
21
 
21
22
  @dc.dataclass
22
- class Box:
23
+ class Box(CodeRepr):
23
24
  """
24
25
  This class defines a box used for filter such as box clip.
25
26