luminarycloud 0.15.4__py3-none-any.whl → 0.16.0__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.
- luminarycloud/_helpers/__init__.py +1 -0
- luminarycloud/_helpers/_code_representation.py +18 -3
- luminarycloud/_helpers/_create_geometry.py +36 -17
- luminarycloud/_helpers/download.py +67 -1
- luminarycloud/_proto/api/v0/luminarycloud/geometry/geometry_pb2.pyi +1 -2
- luminarycloud/_proto/api/v0/luminarycloud/inference/inference_pb2.py +9 -9
- luminarycloud/_proto/api/v0/luminarycloud/inference/inference_pb2.pyi +7 -4
- luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2.py +45 -21
- luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2.pyi +65 -0
- luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2_grpc.py +34 -0
- luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2_grpc.pyi +12 -0
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.py +191 -82
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.pyi +327 -74
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.py +140 -65
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.pyi +74 -38
- luminarycloud/_proto/api/v0/luminarycloud/upload/upload_pb2.py +6 -2
- luminarycloud/_proto/api/v0/luminarycloud/upload/upload_pb2_grpc.py +71 -0
- luminarycloud/_proto/api/v0/luminarycloud/upload/upload_pb2_grpc.pyi +32 -0
- luminarycloud/_proto/assistant/assistant_pb2.py +76 -75
- luminarycloud/_proto/assistant/assistant_pb2.pyi +21 -18
- luminarycloud/_proto/assistant/assistant_pb2_grpc.py +14 -14
- luminarycloud/_proto/assistant/assistant_pb2_grpc.pyi +8 -8
- luminarycloud/_proto/base/base_pb2.py +7 -6
- luminarycloud/_proto/base/base_pb2.pyi +4 -0
- luminarycloud/_proto/client/simulation_pb2.py +188 -186
- luminarycloud/_proto/client/simulation_pb2.pyi +10 -2
- luminarycloud/_proto/geometry/geometry_pb2.py +63 -64
- luminarycloud/_proto/geometry/geometry_pb2.pyi +5 -1
- luminarycloud/_proto/inferenceservice/inferenceservice_pb2.py +11 -11
- luminarycloud/_proto/inferenceservice/inferenceservice_pb2.pyi +12 -4
- luminarycloud/_proto/quantity/quantity_pb2.py +11 -2
- luminarycloud/_proto/quantity/quantity_pb2.pyi +6 -0
- luminarycloud/_proto/table/table_pb2.pyi +4 -2
- luminarycloud/_proto/upload/upload_pb2.py +47 -7
- luminarycloud/_proto/upload/upload_pb2.pyi +62 -0
- luminarycloud/enum/quantity_type.py +15 -0
- luminarycloud/mesh.py +8 -1
- luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method/fluid_implicit_relaxation/robust_startup/__init__.py +1 -0
- luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method/fluid_implicit_relaxation/robust_startup/robust_startup_auto_.py +30 -0
- luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method/fluid_implicit_relaxation/robust_startup/robust_startup_on_.py +1 -1
- luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method/fluid_implicit_relaxation_.py +7 -3
- luminarycloud/params/simulation/physics/fluid/solution_controls_fluid_.py +4 -0
- luminarycloud/params/simulation/physics/fluid/turbulence_.py +1 -1
- luminarycloud/params/simulation/physics/fluid_.py +1 -1
- luminarycloud/params/simulation/physics/heat/solution_controls/heat_relaxation_method/heat_implicit_relaxation_.py +1 -1
- luminarycloud/params/simulation/physics/heat/solution_controls_heat_.py +1 -1
- luminarycloud/physics_ai/__init__.py +4 -0
- luminarycloud/physics_ai/inference.py +140 -4
- luminarycloud/physics_ai/solution.py +60 -0
- luminarycloud/tables.py +6 -8
- luminarycloud/vis/data_extraction.py +4 -5
- luminarycloud/vis/display.py +26 -11
- luminarycloud/vis/filters.py +116 -68
- luminarycloud/vis/primitives.py +3 -2
- luminarycloud/vis/visualization.py +197 -40
- {luminarycloud-0.15.4.dist-info → luminarycloud-0.16.0.dist-info}/METADATA +1 -1
- {luminarycloud-0.15.4.dist-info → luminarycloud-0.16.0.dist-info}/RECORD +58 -56
- {luminarycloud-0.15.4.dist-info → luminarycloud-0.16.0.dist-info}/WHEEL +0 -0
luminarycloud/vis/filters.py
CHANGED
|
@@ -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()
|
|
@@ -188,7 +189,10 @@ class Isosurface(Filter):
|
|
|
188
189
|
vis_filter.id = self.id
|
|
189
190
|
vis_filter.name = self.name
|
|
190
191
|
vis_filter.contour.field.quantity_typ = self.field.quantity.value
|
|
191
|
-
|
|
192
|
+
if not quantity_type._is_vector(self.field.quantity):
|
|
193
|
+
vis_filter.contour.field.component = vis_pb2.Field.COMPONENT_UNSPECIFIED
|
|
194
|
+
else:
|
|
195
|
+
vis_filter.contour.field.component = self.field.component.value
|
|
192
196
|
for val in self.isovalues:
|
|
193
197
|
vis_filter.contour.iso_values.append(val)
|
|
194
198
|
return vis_filter
|
|
@@ -200,7 +204,11 @@ class Isosurface(Filter):
|
|
|
200
204
|
self.id = filter.id
|
|
201
205
|
self.name = filter.name
|
|
202
206
|
self.field.quantity = VisQuantity(filter.contour.field.quantity_typ)
|
|
203
|
-
|
|
207
|
+
if not quantity_type._is_vector(self.field.quantity):
|
|
208
|
+
# This is a scalar so just set the component to magnitude which is the default.
|
|
209
|
+
self.field.component = FieldComponent.MAGNITUDE
|
|
210
|
+
else:
|
|
211
|
+
self.field.component = FieldComponent(filter.contour.field.component)
|
|
204
212
|
self.isovalues.clear()
|
|
205
213
|
for val in filter.contour.iso_values:
|
|
206
214
|
self.isovalues.append(val)
|
|
@@ -226,11 +234,9 @@ class PlaneClip(Filter):
|
|
|
226
234
|
are removed. Default: False
|
|
227
235
|
"""
|
|
228
236
|
|
|
229
|
-
def __init__(self, name: str) -> None:
|
|
237
|
+
def __init__(self, name: str = "") -> None:
|
|
230
238
|
super().__init__(generate_id("planeClip-"))
|
|
231
239
|
self._plane: Plane = Plane()
|
|
232
|
-
# TODO(matt): We could make this a prop to that is unsettable. Or we could
|
|
233
|
-
# not use ids and force that the filter names are unique.
|
|
234
240
|
self.name = name
|
|
235
241
|
self.inverted: bool = False
|
|
236
242
|
|
|
@@ -289,7 +295,7 @@ class BoxClip(Filter):
|
|
|
289
295
|
Default : False
|
|
290
296
|
"""
|
|
291
297
|
|
|
292
|
-
def __init__(self, name: str) -> None:
|
|
298
|
+
def __init__(self, name: str = "") -> None:
|
|
293
299
|
super().__init__(generate_id("boxClip-"))
|
|
294
300
|
self._box: Box = Box()
|
|
295
301
|
self.name = name
|
|
@@ -351,17 +357,11 @@ class VectorGlyphs(Filter):
|
|
|
351
357
|
|
|
352
358
|
"""
|
|
353
359
|
|
|
354
|
-
def __init__(self, name: str) -> None:
|
|
360
|
+
def __init__(self, name: str = "") -> None:
|
|
355
361
|
super().__init__(generate_id("vector-"))
|
|
356
362
|
self.name: str = name
|
|
357
|
-
# TODO(matt): we should be able to help set some reasonable defaults bases
|
|
358
|
-
# on the mesh size (i.e., number of points) and bounds (the default glyph size).
|
|
359
|
-
# The scene has accesss to this theoretically. Perhaps the scene class can be used
|
|
360
|
-
# as a factory.
|
|
361
363
|
self._sampling_rate: int = 500
|
|
362
|
-
self.
|
|
363
|
-
# TODO(matt): we should only allow vectors somehow
|
|
364
|
-
self.field.quantity = VisQuantity.VELOCITY
|
|
364
|
+
self.quantity: VisQuantity = VisQuantity.VELOCITY
|
|
365
365
|
|
|
366
366
|
@property
|
|
367
367
|
def sampling_rate(self) -> int:
|
|
@@ -396,11 +396,11 @@ class FixedSizeVectorGlyphs(VectorGlyphs):
|
|
|
396
396
|
The size in world units (meters) of the glyphs.
|
|
397
397
|
display_attrs (DisplayAttributes)
|
|
398
398
|
Specifies this filters appearance.
|
|
399
|
-
|
|
399
|
+
quantity: VisQuantity
|
|
400
400
|
The vector field to use for glyph generation. Default: Velocity
|
|
401
401
|
"""
|
|
402
402
|
|
|
403
|
-
def __init__(self, name: str) -> None:
|
|
403
|
+
def __init__(self, name: str = "") -> None:
|
|
404
404
|
super().__init__(name)
|
|
405
405
|
self.size: float = 1.0
|
|
406
406
|
|
|
@@ -411,10 +411,10 @@ class FixedSizeVectorGlyphs(VectorGlyphs):
|
|
|
411
411
|
vis_filter.glyph.fixed_size_glyphs = self.size
|
|
412
412
|
vis_filter.glyph.n_glyphs = self.sampling_rate
|
|
413
413
|
vis_filter.glyph.sampling_mode = vis_pb2.GLYPH_SAMPLING_MODE_EVERY_NTH
|
|
414
|
-
if not quantity_type._is_vector(self.
|
|
414
|
+
if not quantity_type._is_vector(self.quantity):
|
|
415
415
|
raise ValueError("FixedSizeVectorGlyphs: field must be a vector type")
|
|
416
|
-
vis_filter.glyph.field.quantity_typ = self.
|
|
417
|
-
vis_filter.glyph.field.component =
|
|
416
|
+
vis_filter.glyph.field.quantity_typ = self.quantity.value
|
|
417
|
+
vis_filter.glyph.field.component = vis_pb2.Field.COMPONENT_UNSPECIFIED
|
|
418
418
|
return vis_filter
|
|
419
419
|
|
|
420
420
|
def _from_proto(self, filter: vis_pb2.Filter) -> None:
|
|
@@ -429,8 +429,7 @@ class FixedSizeVectorGlyphs(VectorGlyphs):
|
|
|
429
429
|
self.n_glyphs = filter.glyph.n_glyphs
|
|
430
430
|
self.size = filter.glyph.fixed_size_glyphs
|
|
431
431
|
self.sampling_rate = filter.glyph.n_glyphs
|
|
432
|
-
self.
|
|
433
|
-
self.field.component = FieldComponent(filter.glyph.field.component)
|
|
432
|
+
self.quantity = VisQuantity(filter.glyph.field.quantity_typ)
|
|
434
433
|
|
|
435
434
|
|
|
436
435
|
class ScaledVectorGlyphs(VectorGlyphs):
|
|
@@ -457,11 +456,11 @@ class ScaledVectorGlyphs(VectorGlyphs):
|
|
|
457
456
|
0.5 and the scale is 2 then the resulting world space size is 1 meter. Default: 1.
|
|
458
457
|
display_attrs (DisplayAttributes)
|
|
459
458
|
Specifies this filters appearance.
|
|
460
|
-
|
|
459
|
+
quantity: VisQuantity
|
|
461
460
|
The vector field to use for glyph generation. Default: Velocity
|
|
462
461
|
"""
|
|
463
462
|
|
|
464
|
-
def __init__(self, name: str) -> None:
|
|
463
|
+
def __init__(self, name: str = "") -> None:
|
|
465
464
|
super().__init__(name)
|
|
466
465
|
self.scale: float = 1.0
|
|
467
466
|
|
|
@@ -472,10 +471,10 @@ class ScaledVectorGlyphs(VectorGlyphs):
|
|
|
472
471
|
vis_filter.glyph.glyph_scale_size = self.scale
|
|
473
472
|
vis_filter.glyph.n_glyphs = self.sampling_rate
|
|
474
473
|
vis_filter.glyph.sampling_mode = vis_pb2.GLYPH_SAMPLING_MODE_EVERY_NTH
|
|
475
|
-
if not quantity_type._is_vector(self.
|
|
474
|
+
if not quantity_type._is_vector(self.quantity):
|
|
476
475
|
raise ValueError("ScaledVectorGyph: field must be a vector type")
|
|
477
|
-
vis_filter.glyph.field.quantity_typ = self.
|
|
478
|
-
vis_filter.glyph.field.component =
|
|
476
|
+
vis_filter.glyph.field.quantity_typ = self.quantity.value
|
|
477
|
+
vis_filter.glyph.field.component = vis_pb2.Field.COMPONENT_UNSPECIFIED
|
|
479
478
|
return vis_filter
|
|
480
479
|
|
|
481
480
|
def _from_proto(self, filter: vis_pb2.Filter) -> None:
|
|
@@ -490,8 +489,7 @@ class ScaledVectorGlyphs(VectorGlyphs):
|
|
|
490
489
|
self.n_glyphs = filter.glyph.n_glyphs
|
|
491
490
|
self.scale = filter.glyph.glyph_scale_size
|
|
492
491
|
self.sampling_rate = filter.glyph.n_glyphs
|
|
493
|
-
self.
|
|
494
|
-
self.field.component = FieldComponent(filter.glyph.field.component)
|
|
492
|
+
self.quantity = VisQuantity(filter.glyph.field.quantity_typ)
|
|
495
493
|
|
|
496
494
|
|
|
497
495
|
class Threshold(Filter):
|
|
@@ -526,7 +524,7 @@ class Threshold(Filter):
|
|
|
526
524
|
Specifies this filter's appearance.
|
|
527
525
|
"""
|
|
528
526
|
|
|
529
|
-
def __init__(self, name: str) -> None:
|
|
527
|
+
def __init__(self, name: str = "") -> None:
|
|
530
528
|
super().__init__(generate_id("threshold-"))
|
|
531
529
|
self.field: Field = Field()
|
|
532
530
|
self.min_value: float = 0.0
|
|
@@ -559,6 +557,10 @@ class Threshold(Filter):
|
|
|
559
557
|
vis_filter.threshold.range.min = self.min_value
|
|
560
558
|
vis_filter.threshold.range.max = self.max_value
|
|
561
559
|
vis_filter.threshold.field.quantity_typ = self.field.quantity.value
|
|
560
|
+
if not quantity_type._is_vector(self.field.quantity):
|
|
561
|
+
vis_filter.threshold.field.component = vis_pb2.Field.COMPONENT_UNSPECIFIED
|
|
562
|
+
else:
|
|
563
|
+
vis_filter.threshold.field.component = self.field.component.value
|
|
562
564
|
vis_filter.threshold.field.component = self.field.component.value
|
|
563
565
|
vis_filter.threshold.smooth = self.smooth
|
|
564
566
|
vis_filter.threshold.invert = self.invert
|
|
@@ -577,7 +579,11 @@ class Threshold(Filter):
|
|
|
577
579
|
self.invert = filter.threshold.invert
|
|
578
580
|
self.strict = filter.threshold.strict
|
|
579
581
|
self.field.quantity = VisQuantity(filter.threshold.field.quantity_typ)
|
|
580
|
-
|
|
582
|
+
if not quantity_type._is_vector(self.field.quantity):
|
|
583
|
+
# This is a scalar so just set the component to magnitude which is the default.
|
|
584
|
+
self.field.component = FieldComponent.MAGNITUDE
|
|
585
|
+
else:
|
|
586
|
+
self.field.component = FieldComponent(filter.threshold.field.component)
|
|
581
587
|
|
|
582
588
|
|
|
583
589
|
class Streamlines(Filter):
|
|
@@ -595,14 +601,13 @@ class Streamlines(Filter):
|
|
|
595
601
|
Specifies this filter's appearance.
|
|
596
602
|
"""
|
|
597
603
|
|
|
598
|
-
def __init__(self, name: str) -> None:
|
|
604
|
+
def __init__(self, name: str = "") -> None:
|
|
599
605
|
super().__init__(generate_id("streamlines-"))
|
|
600
606
|
self.name: str = name
|
|
601
607
|
self.n_streamlines: int = 100
|
|
602
608
|
self.max_length: float = 10
|
|
603
609
|
self.direction: StreamlineDirection = StreamlineDirection.FORWARD
|
|
604
|
-
self.
|
|
605
|
-
self.field.quantity = VisQuantity.VELOCITY
|
|
610
|
+
self.quantity: VisQuantity = VisQuantity.VELOCITY
|
|
606
611
|
|
|
607
612
|
|
|
608
613
|
class RakeStreamlines(Streamlines):
|
|
@@ -625,7 +630,7 @@ class RakeStreamlines(Streamlines):
|
|
|
625
630
|
The number of seed particles to place on the rake. Default: 100
|
|
626
631
|
max_length: float
|
|
627
632
|
The maximum path length of the particle in meters. Default: 10
|
|
628
|
-
|
|
633
|
+
quantity: VisQuantity
|
|
629
634
|
The vector field to used for the particle advection. Default: Velocity
|
|
630
635
|
start: Vector3Like
|
|
631
636
|
The start point of the rake. Default: [0,0,0].
|
|
@@ -637,10 +642,10 @@ class RakeStreamlines(Streamlines):
|
|
|
637
642
|
Specifies this filter's appearance.
|
|
638
643
|
"""
|
|
639
644
|
|
|
640
|
-
def __init__(self, name: str) -> None:
|
|
645
|
+
def __init__(self, name: str = "") -> None:
|
|
641
646
|
super().__init__(name)
|
|
642
|
-
self.start: Vector3Like =
|
|
643
|
-
self.end: Vector3Like =
|
|
647
|
+
self.start: Vector3Like = Vector3(x=0, y=0, z=0)
|
|
648
|
+
self.end: Vector3Like = Vector3(x=1, y=0, z=0)
|
|
644
649
|
|
|
645
650
|
def _to_proto(self) -> vis_pb2.Filter:
|
|
646
651
|
# Type checking
|
|
@@ -648,8 +653,8 @@ class RakeStreamlines(Streamlines):
|
|
|
648
653
|
raise TypeError(f"Expected 'int', got {type(self.n_streamlines).__name__}")
|
|
649
654
|
if not isinstance(self.max_length, (float, int)):
|
|
650
655
|
raise TypeError(f"Expected 'float or int', got {type(self.max_length).__name__}")
|
|
651
|
-
if not isinstance(self.
|
|
652
|
-
raise TypeError(f"Expected '
|
|
656
|
+
if not isinstance(self.quantity, VisQuantity):
|
|
657
|
+
raise TypeError(f"Expected 'VisQuantity', got {type(self.quantity).__name__}")
|
|
653
658
|
|
|
654
659
|
vis_filter = vis_pb2.Filter()
|
|
655
660
|
vis_filter.id = self.id
|
|
@@ -658,9 +663,9 @@ class RakeStreamlines(Streamlines):
|
|
|
658
663
|
vis_filter.streamlines.max_length = self.max_length
|
|
659
664
|
vis_filter.streamlines.rake.start.CopyFrom(_to_vector3(self.start)._to_proto())
|
|
660
665
|
vis_filter.streamlines.rake.end.CopyFrom(_to_vector3(self.end)._to_proto())
|
|
661
|
-
if not quantity_type._is_vector(self.
|
|
666
|
+
if not quantity_type._is_vector(self.quantity):
|
|
662
667
|
raise ValueError("RakeStreamlines: field must be a vector type")
|
|
663
|
-
vis_filter.streamlines.field.quantity_typ = self.
|
|
668
|
+
vis_filter.streamlines.field.quantity_typ = self.quantity.value
|
|
664
669
|
return vis_filter
|
|
665
670
|
|
|
666
671
|
def _from_proto(self, filter: vis_pb2.Filter) -> None:
|
|
@@ -679,7 +684,7 @@ class RakeStreamlines(Streamlines):
|
|
|
679
684
|
self.start._from_proto(filter.streamlines.rake.start)
|
|
680
685
|
self.end = Vector3()
|
|
681
686
|
self.end._from_proto(filter.streamlines.rake.end)
|
|
682
|
-
self.
|
|
687
|
+
self.quantity = VisQuantity(filter.streamlines.field.quantity_typ)
|
|
683
688
|
|
|
684
689
|
|
|
685
690
|
class SurfaceStreamlines(Streamlines):
|
|
@@ -726,7 +731,7 @@ class SurfaceStreamlines(Streamlines):
|
|
|
726
731
|
particles further into the volume based on the surface normal. Default: 0.0
|
|
727
732
|
max_length: float
|
|
728
733
|
The maximum path length of the particle in meters. Default: 10
|
|
729
|
-
|
|
734
|
+
quantity: VisQuantity
|
|
730
735
|
The vector field to used for the particle advection. Default: Velocity
|
|
731
736
|
name : str
|
|
732
737
|
A user provided name for the filter.
|
|
@@ -734,7 +739,7 @@ class SurfaceStreamlines(Streamlines):
|
|
|
734
739
|
Specifies this filter's appearance.
|
|
735
740
|
"""
|
|
736
741
|
|
|
737
|
-
def __init__(self, name: str) -> None:
|
|
742
|
+
def __init__(self, name: str = "") -> None:
|
|
738
743
|
super().__init__(name)
|
|
739
744
|
self.offset: float = 0.0
|
|
740
745
|
self._surface_names: List[str] = []
|
|
@@ -768,8 +773,8 @@ class SurfaceStreamlines(Streamlines):
|
|
|
768
773
|
raise TypeError(f"Expected 'float or int', got {type(self.max_length).__name__}")
|
|
769
774
|
if not isinstance(self.offset, (float, int)):
|
|
770
775
|
raise TypeError(f"Expected 'float or int', got {type(self.offset).__name__}")
|
|
771
|
-
if not isinstance(self.
|
|
772
|
-
raise TypeError(f"Expected '
|
|
776
|
+
if not isinstance(self.quantity, VisQuantity):
|
|
777
|
+
raise TypeError(f"Expected 'VisQuantity', got {type(self.quantity).__name__}")
|
|
773
778
|
if not isinstance(self.mode, SurfaceStreamlineMode):
|
|
774
779
|
raise TypeError(f"Expected 'SurfaceStreamlinesMode', got {type(self.mode).__name__}")
|
|
775
780
|
|
|
@@ -781,12 +786,12 @@ class SurfaceStreamlines(Streamlines):
|
|
|
781
786
|
project = False
|
|
782
787
|
# Prevent common mistakes that cause confusion.
|
|
783
788
|
if self.mode == SurfaceStreamlineMode.ADVECT_ON_SURFACE:
|
|
784
|
-
if self.
|
|
789
|
+
if self.quantity == VisQuantity.VELOCITY:
|
|
785
790
|
raise ValueError(
|
|
786
791
|
"SurfacesStreamines: velocity is 0 on surfaces and will produce no data"
|
|
787
792
|
)
|
|
788
793
|
project = True
|
|
789
|
-
elif self.
|
|
794
|
+
elif self.quantity == VisQuantity.WALL_SHEAR_STRESS:
|
|
790
795
|
raise ValueError(
|
|
791
796
|
"SurfacesStreamines: wall shear stress is 0 in the volume and will produce no data "
|
|
792
797
|
)
|
|
@@ -796,10 +801,9 @@ class SurfaceStreamlines(Streamlines):
|
|
|
796
801
|
raise ValueError("SurfaceStreamlines: need at least one surfaces specified.")
|
|
797
802
|
for id in self._surface_names:
|
|
798
803
|
vis_filter.streamlines.surface.surface_names.append(id)
|
|
799
|
-
if not quantity_type._is_vector(self.
|
|
800
|
-
raise ValueError("SurfaceStreamlines:
|
|
801
|
-
vis_filter.streamlines.field.
|
|
802
|
-
vis_filter.streamlines.field.quantity_typ = self.field.quantity.value
|
|
804
|
+
if not quantity_type._is_vector(self.quantity):
|
|
805
|
+
raise ValueError("SurfaceStreamlines: quantity must be a vector type")
|
|
806
|
+
vis_filter.streamlines.field.quantity_typ = self.quantity.value
|
|
803
807
|
return vis_filter
|
|
804
808
|
|
|
805
809
|
def _from_proto(self, filter: vis_pb2.Filter) -> None:
|
|
@@ -816,7 +820,15 @@ class SurfaceStreamlines(Streamlines):
|
|
|
816
820
|
self._surface_names.clear()
|
|
817
821
|
for s in filter.streamlines.surface.surface_names:
|
|
818
822
|
self._surface_names.append(s)
|
|
819
|
-
self.
|
|
823
|
+
self.quantity = VisQuantity(filter.streamlines.field.quantity_typ)
|
|
824
|
+
|
|
825
|
+
def _to_code(self, hide_defaults: bool = True, use_tmp_objs: bool = True) -> str:
|
|
826
|
+
code = super()._to_code(hide_defaults=hide_defaults)
|
|
827
|
+
# We need to explicity write the code for the surfaces since its
|
|
828
|
+
# technically a private variable.
|
|
829
|
+
for s in self._surface_names:
|
|
830
|
+
code += f".add_surface('{s}')\n"
|
|
831
|
+
return code
|
|
820
832
|
|
|
821
833
|
|
|
822
834
|
class SurfaceLIC(Filter):
|
|
@@ -840,7 +852,7 @@ class SurfaceLIC(Filter):
|
|
|
840
852
|
|
|
841
853
|
Attributes:
|
|
842
854
|
-----------
|
|
843
|
-
|
|
855
|
+
quantity: VisQuantity
|
|
844
856
|
Specifies the field used to advect particles for the surface LIC.
|
|
845
857
|
Default: WALL_SHEER_STRESS
|
|
846
858
|
contrast: float
|
|
@@ -849,13 +861,12 @@ class SurfaceLIC(Filter):
|
|
|
849
861
|
higher values mean more contrast. Default: 1
|
|
850
862
|
"""
|
|
851
863
|
|
|
852
|
-
def __init__(self, name: str) -> None:
|
|
864
|
+
def __init__(self, name: str = "") -> None:
|
|
853
865
|
super().__init__(generate_id("surface-lic-"))
|
|
854
866
|
self.name = name
|
|
855
867
|
self.contrast: float = 1.0
|
|
856
868
|
self._surface_names: List[str] = []
|
|
857
|
-
self.
|
|
858
|
-
self.field.quantity = VisQuantity.WALL_SHEAR_STRESS
|
|
869
|
+
self.quantity: VisQuantity = VisQuantity.WALL_SHEAR_STRESS
|
|
859
870
|
|
|
860
871
|
def add_surface(self, id: str) -> None:
|
|
861
872
|
"""
|
|
@@ -883,9 +894,9 @@ class SurfaceLIC(Filter):
|
|
|
883
894
|
vis_filter.name = self.name
|
|
884
895
|
# Prevent common mistakes that cause confusion. The only current option
|
|
885
896
|
# is to be on a surface, so no velocity.
|
|
886
|
-
if not isinstance(self.
|
|
887
|
-
raise TypeError(f"Expected '
|
|
888
|
-
if self.
|
|
897
|
+
if not isinstance(self.quantity, VisQuantity):
|
|
898
|
+
raise TypeError(f"Expected 'VisQuantity', got {type(self.quantity).__name__}")
|
|
899
|
+
if self.quantity == VisQuantity.VELOCITY:
|
|
889
900
|
raise ValueError("SurfaceLIC: velocity is 0 on surfaces and will produce no data")
|
|
890
901
|
if not isinstance(self.contrast, (int, float)):
|
|
891
902
|
raise TypeError(f"Expected 'int or float', got {type(self.contrast).__name__}")
|
|
@@ -899,7 +910,7 @@ class SurfaceLIC(Filter):
|
|
|
899
910
|
geometry = vis_pb2.SurfaceLICGeomtery()
|
|
900
911
|
vis_filter.surface_lic.geometry.CopyFrom(geometry)
|
|
901
912
|
|
|
902
|
-
vis_filter.surface_lic.field.quantity_typ = self.
|
|
913
|
+
vis_filter.surface_lic.field.quantity_typ = self.quantity.value
|
|
903
914
|
vis_filter.surface_lic.contrast = self.contrast
|
|
904
915
|
return vis_filter
|
|
905
916
|
|
|
@@ -917,7 +928,44 @@ class SurfaceLIC(Filter):
|
|
|
917
928
|
self._surface_names = []
|
|
918
929
|
for s in filter.surface_lic.geometry.surface_names:
|
|
919
930
|
self._surface_names.append(s)
|
|
920
|
-
if not quantity_type._is_vector(self.
|
|
921
|
-
raise ValueError("SurfaceLIC:
|
|
922
|
-
self.
|
|
923
|
-
|
|
931
|
+
if not quantity_type._is_vector(self.quantity):
|
|
932
|
+
raise ValueError("SurfaceLIC: quantity must be a vector type")
|
|
933
|
+
self.quantity = VisQuantity(filter.surface_lic.field.quantity_typ)
|
|
934
|
+
|
|
935
|
+
def _to_code(self, hide_defaults: bool = True, use_tmp_objs: bool = True) -> str:
|
|
936
|
+
code = super()._to_code(hide_defaults=hide_defaults)
|
|
937
|
+
# We need to explicity write the code for the surfaces since its
|
|
938
|
+
# technically a private variable.
|
|
939
|
+
for s in self._surface_names:
|
|
940
|
+
code += f".add_surface('{s}')\n"
|
|
941
|
+
return code
|
|
942
|
+
|
|
943
|
+
|
|
944
|
+
def _filter_to_obj_name(filter: Filter) -> str:
|
|
945
|
+
"""
|
|
946
|
+
Helper function to convert a filter to a code object name used in code gen.
|
|
947
|
+
"""
|
|
948
|
+
if not isinstance(filter, Filter):
|
|
949
|
+
raise TypeError(f"Expected 'Filter', got {type(filter).__name__}")
|
|
950
|
+
if isinstance(filter, Slice):
|
|
951
|
+
return "slice"
|
|
952
|
+
elif isinstance(filter, Isosurface):
|
|
953
|
+
return "isosurface"
|
|
954
|
+
elif isinstance(filter, PlaneClip):
|
|
955
|
+
return "plane_clip"
|
|
956
|
+
elif isinstance(filter, BoxClip):
|
|
957
|
+
return "box_clip"
|
|
958
|
+
elif isinstance(filter, FixedSizeVectorGlyphs):
|
|
959
|
+
return "fixed_size_vector_glyphs"
|
|
960
|
+
elif isinstance(filter, ScaledVectorGlyphs):
|
|
961
|
+
return "scaled_vector_glyphs"
|
|
962
|
+
elif isinstance(filter, Threshold):
|
|
963
|
+
return "threshold"
|
|
964
|
+
elif isinstance(filter, RakeStreamlines):
|
|
965
|
+
return "rake_streamlines"
|
|
966
|
+
elif isinstance(filter, SurfaceStreamlines):
|
|
967
|
+
return "surface_streamlines"
|
|
968
|
+
elif isinstance(filter, SurfaceLIC):
|
|
969
|
+
return "surface_lic"
|
|
970
|
+
else:
|
|
971
|
+
raise TypeError(f"Unknown filter type: {type(filter).__name__}")
|
luminarycloud/vis/primitives.py
CHANGED
|
@@ -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
|
|