luminarycloud 0.16.0__py3-none-any.whl → 0.16.2__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/_client/client.py +6 -1
- luminarycloud/_helpers/_code_representation.py +5 -3
- luminarycloud/_helpers/warnings/__init__.py +0 -1
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.py +88 -34
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.pyi +100 -10
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.py +68 -0
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.pyi +24 -0
- luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2.py +128 -107
- luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2.pyi +48 -3
- luminarycloud/_proto/cad/shape_pb2.py +78 -19
- luminarycloud/_proto/cad/transformation_pb2.py +34 -15
- luminarycloud/_proto/client/simulation_pb2.py +348 -350
- luminarycloud/_proto/client/simulation_pb2.pyi +95 -95
- luminarycloud/_proto/geometry/geometry_pb2.py +68 -68
- luminarycloud/_proto/geometry/geometry_pb2.pyi +10 -6
- luminarycloud/_proto/hexmesh/hexmesh_pb2.py +40 -15
- luminarycloud/_proto/hexmesh/hexmesh_pb2.pyi +58 -1
- luminarycloud/_proto/lcstatus/codes_pb2.py +3 -2
- luminarycloud/_proto/lcstatus/codes_pb2.pyi +4 -0
- luminarycloud/_proto/upload/upload_pb2.py +25 -15
- luminarycloud/_proto/upload/upload_pb2.pyi +31 -2
- luminarycloud/enum/quantity_type.py +4 -0
- luminarycloud/enum/tables.py +1 -0
- luminarycloud/enum/vis_enums.py +20 -0
- luminarycloud/feature_modification.py +6 -7
- luminarycloud/geometry.py +26 -2
- luminarycloud/geometry_version.py +23 -0
- luminarycloud/named_variable_set.py +3 -4
- luminarycloud/outputs/stopping_conditions.py +0 -3
- luminarycloud/params/simulation/adjoint_.py +4 -4
- luminarycloud/params/simulation/material/material_fluid_.py +1 -1
- luminarycloud/params/simulation/material/material_solid_.py +1 -1
- luminarycloud/params/simulation/output_.py +1 -1
- luminarycloud/params/simulation/physics/fluid/initialization/fluid_existing_solution_.py +28 -0
- luminarycloud/params/simulation/simulation_param_.py +6 -0
- luminarycloud/physics_ai/architectures.py +0 -4
- luminarycloud/physics_ai/inference.py +0 -4
- luminarycloud/physics_ai/models.py +0 -4
- luminarycloud/physics_ai/solution.py +2 -2
- luminarycloud/pipelines/__init__.py +6 -0
- luminarycloud/pipelines/arguments.py +105 -0
- luminarycloud/pipelines/core.py +204 -20
- luminarycloud/pipelines/operators.py +11 -9
- luminarycloud/pipelines/parameters.py +25 -4
- luminarycloud/project.py +13 -12
- luminarycloud/simulation_param.py +29 -17
- luminarycloud/simulation_template.py +15 -13
- luminarycloud/solution.py +1 -3
- luminarycloud/tables.py +5 -4
- luminarycloud/thirdparty/__init__.py +12 -0
- luminarycloud/thirdparty/onshape.py +170 -0
- luminarycloud/vis/__init__.py +2 -0
- luminarycloud/vis/data_extraction.py +40 -1
- luminarycloud/vis/filters.py +128 -2
- luminarycloud/vis/visualization.py +1 -1
- luminarycloud/volume_selection.py +2 -2
- {luminarycloud-0.16.0.dist-info → luminarycloud-0.16.2.dist-info}/METADATA +6 -6
- {luminarycloud-0.16.0.dist-info → luminarycloud-0.16.2.dist-info}/RECORD +59 -57
- luminarycloud/_helpers/warnings/experimental.py +0 -48
- {luminarycloud-0.16.0.dist-info → luminarycloud-0.16.2.dist-info}/WHEEL +0 -0
|
@@ -8,7 +8,7 @@ from difflib import Differ
|
|
|
8
8
|
from .enum import (
|
|
9
9
|
TableType,
|
|
10
10
|
)
|
|
11
|
-
from ._helpers.warnings import
|
|
11
|
+
from ._helpers.warnings import deprecated
|
|
12
12
|
from ._client import get_default_client
|
|
13
13
|
from ._helpers._simulation_params_from_json import simulation_params_from_json_path
|
|
14
14
|
from ._helpers._timestamp_to_datetime import timestamp_to_datetime
|
|
@@ -119,14 +119,6 @@ class SimulationTemplate(ProtoWrapperBase):
|
|
|
119
119
|
param_proto.CopyFrom(parameters)
|
|
120
120
|
else:
|
|
121
121
|
param_proto = simulation_params_from_json_path(parameters)
|
|
122
|
-
|
|
123
|
-
if isinstance(parameters, (SimulationParam, clientpb.SimulationParam)):
|
|
124
|
-
# Table references are manipulated via the simulation template, hence we need to persist
|
|
125
|
-
# them when we update the parameters.
|
|
126
|
-
param_proto.table_references.clear()
|
|
127
|
-
for k, v in self._proto.parameters.table_references.items():
|
|
128
|
-
param_proto.table_references[k].CopyFrom(v)
|
|
129
|
-
|
|
130
122
|
req.parameters.CopyFrom(param_proto)
|
|
131
123
|
|
|
132
124
|
if copy_from is not None:
|
|
@@ -438,7 +430,6 @@ class SimulationTemplate(ProtoWrapperBase):
|
|
|
438
430
|
"""
|
|
439
431
|
return delete_stopping_condition(self.id, id)
|
|
440
432
|
|
|
441
|
-
@experimental
|
|
442
433
|
def get_general_stopping_conditions(self) -> GeneralStoppingConditions:
|
|
443
434
|
"""
|
|
444
435
|
Get the general stopping conditions for this simulation template.
|
|
@@ -447,7 +438,6 @@ class SimulationTemplate(ProtoWrapperBase):
|
|
|
447
438
|
"""
|
|
448
439
|
return get_general_stopping_conditions(self.id)
|
|
449
440
|
|
|
450
|
-
@experimental
|
|
451
441
|
def update_general_stopping_conditions(
|
|
452
442
|
self,
|
|
453
443
|
max_iterations: int | None = None,
|
|
@@ -482,7 +472,8 @@ class SimulationTemplate(ProtoWrapperBase):
|
|
|
482
472
|
By default parameters with default values are omitted, this change be changed with
|
|
483
473
|
hide_defaults=False.
|
|
484
474
|
"""
|
|
485
|
-
|
|
475
|
+
parameters = self.get_parameters()
|
|
476
|
+
param_code = parameters.to_code(hide_defaults)
|
|
486
477
|
code, param_code = param_code.split("\n\n\n")
|
|
487
478
|
|
|
488
479
|
# Modify the header note included by SimulationParam.to_code.
|
|
@@ -490,10 +481,21 @@ class SimulationTemplate(ProtoWrapperBase):
|
|
|
490
481
|
code += "\n\n\n"
|
|
491
482
|
code += '# Create a new simulation template or modify the one that is synced with the UI "Setup" tab.\n'
|
|
492
483
|
code += "# TODO(USER): Replace ... with project ID, or create a project.\n"
|
|
493
|
-
code += 'project = get_project("...")\n'
|
|
484
|
+
code += 'project = luminarycloud.get_project("...")\n'
|
|
494
485
|
code += f"# template = project.create_simulation_template(name={self.name})\n"
|
|
495
486
|
code += "template = project.list_simulation_templates()[0] # Setup template\n\n"
|
|
496
487
|
|
|
488
|
+
if parameters._table_references:
|
|
489
|
+
code += "# Upload tabular data.\n"
|
|
490
|
+
code += (
|
|
491
|
+
"# TODO(USER): Provide the local file paths (they are not stored by Luminary).\n"
|
|
492
|
+
)
|
|
493
|
+
for name, table in sorted(parameters._table_references.items()):
|
|
494
|
+
table_type = TableType(table.table_type).__repr__().split(": ")[0][1:]
|
|
495
|
+
code += f'project.create_table({table_type}, "path/to/{table.uploaded_filename}", template)\n'
|
|
496
|
+
code += "# This shows the available tables:\n"
|
|
497
|
+
code += "# print(template.list_tables())\n\n"
|
|
498
|
+
|
|
497
499
|
code += "# Define the simulation parameters.\n"
|
|
498
500
|
code += param_code
|
|
499
501
|
code += "\n# Update the simulation template with the parameters.\n"
|
luminarycloud/solution.py
CHANGED
|
@@ -6,7 +6,6 @@ from os import PathLike
|
|
|
6
6
|
import luminarycloud as lc
|
|
7
7
|
|
|
8
8
|
from ._client import get_default_client
|
|
9
|
-
from ._helpers.warnings import experimental
|
|
10
9
|
from ._helpers.download import (
|
|
11
10
|
download_surface_solution,
|
|
12
11
|
download_volume_solution,
|
|
@@ -146,14 +145,13 @@ class Solution(ProtoWrapperBase):
|
|
|
146
145
|
stream = download_surface_sensitivity_data(get_default_client(), self.id)
|
|
147
146
|
_handle_surface_data_stream(stream, dst)
|
|
148
147
|
|
|
149
|
-
@experimental
|
|
150
148
|
def download_parameter_sensitivity_data(self, dst: Optional[PathLike] = None) -> None:
|
|
151
149
|
"""
|
|
152
150
|
Download the parameter sensitivity data associated with an adjoint solution into the
|
|
153
151
|
destination file or into a default-named file. The data consists of parameter names and
|
|
154
152
|
sensitivity values (d "adjoint output" / d "SimulationParam parameter").
|
|
155
153
|
|
|
156
|
-
|
|
154
|
+
.. warning:: This is a very experimental feature, likely to change in the future in favor of
|
|
157
155
|
including the sensitivities in a SimulationParam object directly.
|
|
158
156
|
"""
|
|
159
157
|
stream = download_parameter_sensitivity_data(get_default_client(), self.id)
|
luminarycloud/tables.py
CHANGED
|
@@ -8,6 +8,7 @@ import csv
|
|
|
8
8
|
from typing import Union
|
|
9
9
|
|
|
10
10
|
from .enum import TableType, QuantityType
|
|
11
|
+
from ._helpers import CodeRepr
|
|
11
12
|
from ._proto.table import table_pb2 as tablepb
|
|
12
13
|
from ._proto.quantity import quantity_pb2 as quantitypb
|
|
13
14
|
|
|
@@ -155,12 +156,12 @@ def create_rectilinear_table(
|
|
|
155
156
|
|
|
156
157
|
|
|
157
158
|
@dataclass(kw_only=True)
|
|
158
|
-
class RectilinearTable:
|
|
159
|
+
class RectilinearTable(CodeRepr):
|
|
159
160
|
"""Represents an uploaded table."""
|
|
160
161
|
|
|
161
|
-
id: str
|
|
162
|
-
name: str
|
|
163
|
-
table_type: TableType
|
|
162
|
+
id: str = ""
|
|
163
|
+
name: str = ""
|
|
164
|
+
table_type: TableType = TableType.INVALID
|
|
164
165
|
|
|
165
166
|
|
|
166
167
|
def _param_name_to_table_type(name: str) -> TableType:
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Copyright 2025 Luminary Cloud, Inc. All Rights Reserved.
|
|
2
|
+
"""
|
|
3
|
+
Third-party integration functionality for the Luminary SDK.
|
|
4
|
+
|
|
5
|
+
This package provides modules for interacting with various third-party services.
|
|
6
|
+
Each service has its own submodule with specific functionality.
|
|
7
|
+
|
|
8
|
+
Available integrations:
|
|
9
|
+
- onshape: Onshape CAD platform integration
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from . import onshape as onshape
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Copyright 2025 Luminary Cloud, Inc. All Rights Reserved.
|
|
2
|
+
"""
|
|
3
|
+
Onshape integration functionality for the Luminary SDK.
|
|
4
|
+
|
|
5
|
+
This module provides functions for interacting with Onshape CAD platform,
|
|
6
|
+
allowing users to check authentication status and fetch variables using
|
|
7
|
+
native Python types. This is in addition to our more integrated uses of
|
|
8
|
+
Onshape within the SDK, such as allowing Onshape URLs in create_geometry.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from typing import NamedTuple
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
import re
|
|
14
|
+
|
|
15
|
+
from .._client import get_default_client
|
|
16
|
+
from .._proto.api.v0.luminarycloud.thirdpartyintegration.onshape import onshape_pb2 as onshapepb
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class OnshapeVariable:
|
|
21
|
+
"""
|
|
22
|
+
Represents a variable from Onshape according to its variable studio definition.
|
|
23
|
+
|
|
24
|
+
Attributes
|
|
25
|
+
----------
|
|
26
|
+
type : str
|
|
27
|
+
The type of the variable (e.g., "LENGTH", "ANGLE", "NUMBER", "ANY")
|
|
28
|
+
name : str
|
|
29
|
+
The name of the variable
|
|
30
|
+
description : str
|
|
31
|
+
A description of the variable
|
|
32
|
+
value : str
|
|
33
|
+
The current value of the variable as a string
|
|
34
|
+
expression : str
|
|
35
|
+
The expression defining the variable
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
type: str
|
|
39
|
+
name: str
|
|
40
|
+
description: str
|
|
41
|
+
value: str
|
|
42
|
+
expression: str
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class AuthenticationStatus(NamedTuple):
|
|
46
|
+
"""
|
|
47
|
+
Authentication status for Onshape.
|
|
48
|
+
|
|
49
|
+
Attributes
|
|
50
|
+
----------
|
|
51
|
+
is_authenticated : bool
|
|
52
|
+
Whether the use has active authentication with Onshape.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
is_authenticated: bool
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _parse_onshape_url(url: str) -> onshapepb.OnshapePath:
|
|
59
|
+
"""
|
|
60
|
+
Parse an Onshape URL to extract the necessary components and return an OnshapePath.
|
|
61
|
+
|
|
62
|
+
Parameters
|
|
63
|
+
----------
|
|
64
|
+
url : str
|
|
65
|
+
The Onshape URL to parse
|
|
66
|
+
|
|
67
|
+
Returns
|
|
68
|
+
-------
|
|
69
|
+
OnshapePath
|
|
70
|
+
A protobuf OnshapePath object with all fields populated
|
|
71
|
+
|
|
72
|
+
Raises
|
|
73
|
+
------
|
|
74
|
+
ValueError
|
|
75
|
+
If the URL format is invalid or cannot be parsed
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
# Expected format: https://{company_prefix}.onshape.com/documents/{document_id}/{w_or_v}/{wv_id}/e/{element_id}
|
|
79
|
+
url_pattern = (
|
|
80
|
+
r"https://([^.\s]+)\.onshape\.com/documents/([^/\s]+)/([wv])/([^/\s]+)/e/([^/\s?#]+)$"
|
|
81
|
+
)
|
|
82
|
+
match = re.match(url_pattern, url)
|
|
83
|
+
|
|
84
|
+
if not match:
|
|
85
|
+
raise ValueError(f"Invalid Onshape URL format: {url}")
|
|
86
|
+
|
|
87
|
+
company_prefix, document_id, w_or_v, wv_id, element_id = match.groups()
|
|
88
|
+
|
|
89
|
+
return onshapepb.OnshapePath(
|
|
90
|
+
company_prefix=company_prefix,
|
|
91
|
+
document_id=document_id,
|
|
92
|
+
w_or_v=w_or_v,
|
|
93
|
+
wv_id=wv_id,
|
|
94
|
+
element_id=element_id,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def get_authentication_status() -> AuthenticationStatus:
|
|
99
|
+
"""
|
|
100
|
+
Check whether the current user has valid authentication with Onshape.
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
AuthenticationStatus
|
|
105
|
+
The authentication status containing whether the user is authenticated
|
|
106
|
+
|
|
107
|
+
Examples
|
|
108
|
+
--------
|
|
109
|
+
>>> import luminarycloud.thirdparty.onshape as onshape
|
|
110
|
+
>>> status = onshape.get_authentication_status()
|
|
111
|
+
>>> if status.is_authenticated:
|
|
112
|
+
... print("User is authenticated with Onshape")
|
|
113
|
+
... else:
|
|
114
|
+
... print("User needs to authenticate with Onshape")
|
|
115
|
+
"""
|
|
116
|
+
req = onshapepb.GetAuthenticationStatusRequest()
|
|
117
|
+
res = get_default_client().GetAuthenticationStatus(req)
|
|
118
|
+
return AuthenticationStatus(is_authenticated=res.auth_active)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def fetch_variables(onshape_url: str) -> list[OnshapeVariable]:
|
|
122
|
+
"""
|
|
123
|
+
Fetch variables from an Onshape document using an Onshape URL.
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
onshape_url : str
|
|
128
|
+
The Onshape URL pointing to the document element.
|
|
129
|
+
Expected format: https://{company}.onshape.com/documents/{doc_id}/{w_or_v}/{workspace_or_version_id}/e/{element_id}
|
|
130
|
+
|
|
131
|
+
Returns
|
|
132
|
+
-------
|
|
133
|
+
list[OnshapeVariable]
|
|
134
|
+
A list of variables available in the specified Onshape element
|
|
135
|
+
|
|
136
|
+
Raises
|
|
137
|
+
------
|
|
138
|
+
ValueError
|
|
139
|
+
If the URL format is invalid or cannot be parsed
|
|
140
|
+
|
|
141
|
+
Examples
|
|
142
|
+
--------
|
|
143
|
+
>>> import luminarycloud.thirdparty.onshape as onshape
|
|
144
|
+
>>> # Fetch variables from a workspace URL
|
|
145
|
+
>>> fake_url = "https://cad.onshape.com/documents/abc123/w/def456/e/ghi789"
|
|
146
|
+
>>> variables = onshape.fetch_variables(fake_url)
|
|
147
|
+
>>> for var in variables:
|
|
148
|
+
... print(f"{var.name}: {var.value} ({var.type})")
|
|
149
|
+
|
|
150
|
+
>>> # Fetch variables from a version URL
|
|
151
|
+
>>> fake_url = "https://cad.onshape.com/documents/abc123/v/xyz999/e/ghi789"
|
|
152
|
+
>>> variables = onshape.fetch_variables(fake_url)
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
path = _parse_onshape_url(onshape_url)
|
|
156
|
+
req = onshapepb.FetchVariablesRequest(path=path)
|
|
157
|
+
res = get_default_client().FetchVariables(req)
|
|
158
|
+
variables = []
|
|
159
|
+
for proto_var in res.variables:
|
|
160
|
+
variables.append(
|
|
161
|
+
OnshapeVariable(
|
|
162
|
+
type=proto_var.type,
|
|
163
|
+
name=proto_var.name,
|
|
164
|
+
value=proto_var.value,
|
|
165
|
+
expression=proto_var.expression,
|
|
166
|
+
description=proto_var.description,
|
|
167
|
+
)
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
return variables
|
luminarycloud/vis/__init__.py
CHANGED
|
@@ -20,6 +20,7 @@ from .filters import (
|
|
|
20
20
|
FixedSizeVectorGlyphs as FixedSizeVectorGlyphs,
|
|
21
21
|
ScaledVectorGlyphs as ScaledVectorGlyphs,
|
|
22
22
|
RakeStreamlines as RakeStreamlines,
|
|
23
|
+
GridStreamlines as GridStreamlines,
|
|
23
24
|
SurfaceStreamlines as SurfaceStreamlines,
|
|
24
25
|
SurfaceLIC as SurfaceLIC,
|
|
25
26
|
Threshold as Threshold,
|
|
@@ -30,6 +31,7 @@ from .data_extraction import (
|
|
|
30
31
|
IntersectionCurve as IntersectionCurve,
|
|
31
32
|
DataExtractor as DataExtractor,
|
|
32
33
|
ExtractOutput as ExtractOutput,
|
|
34
|
+
LineSample as LineSample,
|
|
33
35
|
list_data_extracts as list_data_extracts,
|
|
34
36
|
)
|
|
35
37
|
|
|
@@ -8,7 +8,7 @@ from typing import List, Tuple, cast, Union
|
|
|
8
8
|
from abc import ABC, abstractmethod
|
|
9
9
|
from .._proto.api.v0.luminarycloud.vis import vis_pb2
|
|
10
10
|
from .primitives import Plane
|
|
11
|
-
from ..types.vector3 import _to_vector3
|
|
11
|
+
from ..types.vector3 import _to_vector3, Vector3Like, Vector3
|
|
12
12
|
from .._client import get_default_client
|
|
13
13
|
import logging
|
|
14
14
|
from ..solution import Solution
|
|
@@ -122,6 +122,45 @@ class IntersectionCurve(DataExtract):
|
|
|
122
122
|
return vis_filter
|
|
123
123
|
|
|
124
124
|
|
|
125
|
+
class LineSample(DataExtract):
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
Generate line data by computing intersections between volumetric data and a line.
|
|
129
|
+
|
|
130
|
+
Extracts a 1D curve where the line intersects cell faces with solution field
|
|
131
|
+
values at intersection points.
|
|
132
|
+
|
|
133
|
+
.. warning:: This feature is experimental and may change or be removed in the future.
|
|
134
|
+
|
|
135
|
+
Attributes:
|
|
136
|
+
-----------
|
|
137
|
+
start: Vector3Like
|
|
138
|
+
The start of the line segment. Defaults to (0, 0, 0).
|
|
139
|
+
end: Vector3Like
|
|
140
|
+
The end of the line segment. Defaults to (1, 0, 0).
|
|
141
|
+
label: str
|
|
142
|
+
A user provided label for the line sample.
|
|
143
|
+
name : str
|
|
144
|
+
A user provided name for the filter.
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
def __init__(self, name: str) -> None:
|
|
148
|
+
super().__init__(generate_id("line-sample"))
|
|
149
|
+
self.name = name
|
|
150
|
+
self.start: Vector3Like = Vector3(x=0, y=0, z=0)
|
|
151
|
+
self.end: Vector3Like = Vector3(x=1, y=0, z=0)
|
|
152
|
+
self.label: str = ""
|
|
153
|
+
|
|
154
|
+
def _to_proto(self) -> vis_pb2.Filter:
|
|
155
|
+
vis_filter = vis_pb2.Filter()
|
|
156
|
+
vis_filter.id = self.id
|
|
157
|
+
vis_filter.name = self.name
|
|
158
|
+
vis_filter.line_sample.label = self.label
|
|
159
|
+
vis_filter.line_sample.start.CopyFrom(_to_vector3(self.start)._to_proto())
|
|
160
|
+
vis_filter.line_sample.end.CopyFrom(_to_vector3(self.end)._to_proto())
|
|
161
|
+
return vis_filter
|
|
162
|
+
|
|
163
|
+
|
|
125
164
|
class ExtractOutput:
|
|
126
165
|
"""
|
|
127
166
|
The extract output represents the request to extract data from a solution,
|
luminarycloud/vis/filters.py
CHANGED
|
@@ -631,7 +631,7 @@ class RakeStreamlines(Streamlines):
|
|
|
631
631
|
max_length: float
|
|
632
632
|
The maximum path length of the particle in meters. Default: 10
|
|
633
633
|
quantity: VisQuantity
|
|
634
|
-
The vector field to
|
|
634
|
+
The vector field to use for the particle advection. Default: Velocity
|
|
635
635
|
start: Vector3Like
|
|
636
636
|
The start point of the rake. Default: [0,0,0].
|
|
637
637
|
end: Vector3Like
|
|
@@ -687,6 +687,130 @@ class RakeStreamlines(Streamlines):
|
|
|
687
687
|
self.quantity = VisQuantity(filter.streamlines.field.quantity_typ)
|
|
688
688
|
|
|
689
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)
|
|
812
|
+
|
|
813
|
+
|
|
690
814
|
class SurfaceStreamlines(Streamlines):
|
|
691
815
|
"""
|
|
692
816
|
Streamlines is a vector field visualization technique that integrates
|
|
@@ -732,7 +856,7 @@ class SurfaceStreamlines(Streamlines):
|
|
|
732
856
|
max_length: float
|
|
733
857
|
The maximum path length of the particle in meters. Default: 10
|
|
734
858
|
quantity: VisQuantity
|
|
735
|
-
The vector field to
|
|
859
|
+
The vector field to use for the particle advection. Default: Velocity
|
|
736
860
|
name : str
|
|
737
861
|
A user provided name for the filter.
|
|
738
862
|
display_attrs : DisplayAttributes
|
|
@@ -963,6 +1087,8 @@ def _filter_to_obj_name(filter: Filter) -> str:
|
|
|
963
1087
|
return "threshold"
|
|
964
1088
|
elif isinstance(filter, RakeStreamlines):
|
|
965
1089
|
return "rake_streamlines"
|
|
1090
|
+
elif isinstance(filter, GridStreamlines):
|
|
1091
|
+
return "grid_streamlines"
|
|
966
1092
|
elif isinstance(filter, SurfaceStreamlines):
|
|
967
1093
|
return "surface_streamlines"
|
|
968
1094
|
elif isinstance(filter, SurfaceLIC):
|
|
@@ -507,7 +507,7 @@ class Scene(CodeRepr):
|
|
|
507
507
|
display attributes using tags, then surface ids.
|
|
508
508
|
"""
|
|
509
509
|
if not surface_id in self._surface_ids:
|
|
510
|
-
raise ValueError(f"Id {
|
|
510
|
+
raise ValueError(f"Id {surface_id} not a boundary id")
|
|
511
511
|
self._surface_visibilities[surface_id] = visible
|
|
512
512
|
|
|
513
513
|
if self._interactive_scene:
|
|
@@ -157,8 +157,8 @@ class VolumeSelection:
|
|
|
157
157
|
cad_url = finish_res.url
|
|
158
158
|
|
|
159
159
|
feature = gpb.Feature(feature_name=feature_name)
|
|
160
|
-
|
|
161
|
-
gpb.
|
|
160
|
+
feature.import_geometry.CopyFrom(
|
|
161
|
+
gpb.ImportGeometry(
|
|
162
162
|
geometry_url=cad_url,
|
|
163
163
|
scaling=scaling,
|
|
164
164
|
force_discrete=force_discrete,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: luminarycloud
|
|
3
|
-
Version: 0.16.
|
|
3
|
+
Version: 0.16.2
|
|
4
4
|
Summary: Luminary Cloud SDK
|
|
5
5
|
Project-URL: Homepage, https://www.luminarycloud.com/
|
|
6
6
|
Project-URL: Documentation, https://app.luminarycloud.com/docs/api/
|
|
@@ -13,13 +13,13 @@ Requires-Dist: grpcio-status~=1.51
|
|
|
13
13
|
Requires-Dist: grpcio-tools~=1.51
|
|
14
14
|
Requires-Dist: grpcio~=1.51
|
|
15
15
|
Requires-Dist: importlib-metadata~=6.0.0
|
|
16
|
-
Requires-Dist: opentelemetry-api~=1.25
|
|
17
|
-
Requires-Dist: opentelemetry-exporter-otlp-proto-common~=1.25
|
|
18
|
-
Requires-Dist: opentelemetry-exporter-otlp-proto-http~=1.25
|
|
16
|
+
Requires-Dist: opentelemetry-api~=1.25
|
|
17
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-common~=1.25
|
|
18
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http~=1.25
|
|
19
19
|
Requires-Dist: opentelemetry-instrumentation-grpc~=0.46b0
|
|
20
20
|
Requires-Dist: opentelemetry-instrumentation~=0.46b0
|
|
21
|
-
Requires-Dist: opentelemetry-proto~=1.25
|
|
22
|
-
Requires-Dist: opentelemetry-sdk~=1.25
|
|
21
|
+
Requires-Dist: opentelemetry-proto~=1.25
|
|
22
|
+
Requires-Dist: opentelemetry-sdk~=1.25
|
|
23
23
|
Requires-Dist: opentelemetry-semantic-conventions~=0.46b0
|
|
24
24
|
Requires-Dist: protobuf~=4.21
|
|
25
25
|
Requires-Dist: pyjwt~=2.6
|