luminarycloud 0.22.0__py3-none-any.whl → 0.22.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.
Files changed (86) hide show
  1. luminarycloud/_client/authentication_plugin.py +49 -0
  2. luminarycloud/_client/client.py +38 -11
  3. luminarycloud/_client/http_client.py +1 -1
  4. luminarycloud/_client/retry_interceptor.py +64 -2
  5. luminarycloud/_helpers/__init__.py +9 -0
  6. luminarycloud/_helpers/_inference_jobs.py +227 -0
  7. luminarycloud/_helpers/_parse_iso_datetime.py +54 -0
  8. luminarycloud/_helpers/download.py +11 -0
  9. luminarycloud/_helpers/proto_decorator.py +38 -7
  10. luminarycloud/_proto/api/v0/luminarycloud/geometry/geometry_pb2.py +152 -132
  11. luminarycloud/_proto/api/v0/luminarycloud/geometry/geometry_pb2.pyi +66 -8
  12. luminarycloud/_proto/api/v0/luminarycloud/geometry/geometry_pb2_grpc.py +34 -0
  13. luminarycloud/_proto/api/v0/luminarycloud/geometry/geometry_pb2_grpc.pyi +12 -0
  14. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2.py +142 -39
  15. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2.pyi +300 -3
  16. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2_grpc.py +34 -0
  17. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2_grpc.pyi +12 -0
  18. luminarycloud/_proto/api/v0/luminarycloud/physicsaiinference/physicsaiinference_pb2.py +255 -0
  19. luminarycloud/_proto/api/v0/luminarycloud/physicsaiinference/physicsaiinference_pb2.pyi +466 -0
  20. luminarycloud/_proto/api/v0/luminarycloud/physicsaiinference/physicsaiinference_pb2_grpc.py +242 -0
  21. luminarycloud/_proto/api/v0/luminarycloud/physicsaiinference/physicsaiinference_pb2_grpc.pyi +95 -0
  22. luminarycloud/_proto/api/v0/luminarycloud/simulation/simulation_pb2.py +29 -7
  23. luminarycloud/_proto/api/v0/luminarycloud/simulation/simulation_pb2.pyi +39 -0
  24. luminarycloud/_proto/api/v0/luminarycloud/simulation/simulation_pb2_grpc.py +36 -0
  25. luminarycloud/_proto/api/v0/luminarycloud/simulation/simulation_pb2_grpc.pyi +18 -0
  26. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.py +88 -65
  27. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.pyi +42 -0
  28. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.py +34 -0
  29. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.pyi +12 -0
  30. luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2.py +163 -153
  31. luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2.pyi +37 -3
  32. luminarycloud/_proto/base/base_pb2.py +7 -6
  33. luminarycloud/_proto/base/base_pb2.pyi +4 -0
  34. luminarycloud/_proto/client/simulation_pb2.py +358 -339
  35. luminarycloud/_proto/client/simulation_pb2.pyi +89 -3
  36. luminarycloud/_proto/physicsaiinferenceservice/physicsaiinferenceservice_pb2.py +35 -0
  37. luminarycloud/_proto/physicsaiinferenceservice/physicsaiinferenceservice_pb2.pyi +7 -0
  38. luminarycloud/_proto/physicsaitrainingservice/physicsaitrainingservice_pb2.py +6 -3
  39. luminarycloud/_proto/physicsaitrainingservice/physicsaitrainingservice_pb2_grpc.py +68 -0
  40. luminarycloud/_proto/physicsaitrainingservice/physicsaitrainingservice_pb2_grpc.pyi +24 -0
  41. luminarycloud/_wrapper.py +53 -7
  42. luminarycloud/enum/vis_enums.py +6 -0
  43. luminarycloud/feature_modification.py +25 -32
  44. luminarycloud/geometry.py +10 -6
  45. luminarycloud/geometry_version.py +4 -0
  46. luminarycloud/mesh.py +4 -0
  47. luminarycloud/meshing/mesh_generation_params.py +5 -6
  48. luminarycloud/meshing/sizing_strategy/sizing_strategies.py +1 -2
  49. luminarycloud/outputs/__init__.py +2 -0
  50. luminarycloud/outputs/output_definitions.py +3 -3
  51. luminarycloud/outputs/stopping_conditions.py +94 -0
  52. luminarycloud/params/enum/_enum_wrappers.py +16 -0
  53. luminarycloud/params/geometry/shapes.py +33 -33
  54. luminarycloud/params/simulation/adaptive_mesh_refinement/__init__.py +1 -0
  55. luminarycloud/params/simulation/adaptive_mesh_refinement/active_region_.py +83 -0
  56. luminarycloud/params/simulation/adaptive_mesh_refinement/boundary_layer_profile_.py +1 -1
  57. luminarycloud/params/simulation/adaptive_mesh_refinement_.py +8 -1
  58. luminarycloud/physics_ai/__init__.py +7 -0
  59. luminarycloud/physics_ai/inference.py +166 -199
  60. luminarycloud/physics_ai/models.py +22 -0
  61. luminarycloud/physics_ai/solution.py +4 -0
  62. luminarycloud/pipelines/api.py +143 -16
  63. luminarycloud/pipelines/core.py +1 -1
  64. luminarycloud/pipelines/stages.py +22 -9
  65. luminarycloud/project.py +61 -8
  66. luminarycloud/simulation.py +25 -0
  67. luminarycloud/types/__init__.py +2 -0
  68. luminarycloud/types/ids.py +2 -0
  69. luminarycloud/types/vector3.py +1 -2
  70. luminarycloud/vis/__init__.py +1 -0
  71. luminarycloud/vis/data_extraction.py +7 -7
  72. luminarycloud/vis/filters.py +97 -0
  73. luminarycloud/vis/interactive_report.py +163 -7
  74. luminarycloud/vis/report.py +113 -1
  75. luminarycloud/vis/visualization.py +3 -0
  76. luminarycloud/volume_selection.py +16 -8
  77. luminarycloud/workflow_utils.py +149 -0
  78. {luminarycloud-0.22.0.dist-info → luminarycloud-0.22.2.dist-info}/METADATA +1 -1
  79. {luminarycloud-0.22.0.dist-info → luminarycloud-0.22.2.dist-info}/RECORD +80 -76
  80. {luminarycloud-0.22.0.dist-info → luminarycloud-0.22.2.dist-info}/WHEEL +1 -1
  81. luminarycloud/_proto/api/v0/luminarycloud/inference/inference_pb2.py +0 -61
  82. luminarycloud/_proto/api/v0/luminarycloud/inference/inference_pb2.pyi +0 -85
  83. luminarycloud/_proto/api/v0/luminarycloud/inference/inference_pb2_grpc.py +0 -67
  84. luminarycloud/_proto/api/v0/luminarycloud/inference/inference_pb2_grpc.pyi +0 -26
  85. luminarycloud/_proto/inferenceservice/inferenceservice_pb2.py +0 -69
  86. luminarycloud/pipeline_util/dictable.py +0 -27
@@ -1,217 +1,184 @@
1
1
  # File: python/sdk/luminarycloud/inference/inference.py
2
2
  # Copyright 2025 Luminary Cloud, Inc. All Rights Reserved.
3
- from datetime import datetime
4
- from typing import Any, Callable, Dict, Optional
5
- from json import loads as json_loads, dumps as json_dumps
6
- from dataclasses import dataclass
7
- import base64
8
- import os
9
- import urllib.request
10
-
11
- from .._client import get_default_client
12
- from .._helpers._timestamp_to_datetime import timestamp_to_datetime
13
- from .._proto.api.v0.luminarycloud.inference import inference_pb2 as inferencepb
14
- from .._proto.inferenceservice import inferenceservice_pb2 as inferenceservicepb
3
+ from typing import Any
4
+ from enum import IntEnum
5
+ from google.protobuf.json_format import MessageToDict
15
6
  from .._wrapper import ProtoWrapper, ProtoWrapperBase
16
- from ..project import Project
17
- from ..project import Project
18
- from .._helpers import upload_file
19
- from .._proto.upload import upload_pb2 as uploadpb
20
- from ..types.ids import PhysicsAiModelVersionID
7
+ from .._proto.api.v0.luminarycloud.physicsaiinference import (
8
+ physicsaiinference_pb2 as physicsaiinferencepb,
9
+ )
10
+ from .._proto.base import base_pb2 as basepb
21
11
 
22
12
 
23
- @dataclass
24
- class ExtAeroInferenceResult:
25
- """Result of an external aerodynamic inference job.
13
+ class VisualizationOutput(IntEnum):
14
+ """
15
+ Represents the type of visualization output.
26
16
 
27
17
  Attributes
28
18
  ----------
29
- drag_force: float
30
- The drag force returned from the inference.
31
- lift_force: float
32
- The lift force returned from the inference.
33
- wall_shear_stress:
34
- A dict containing wall shear stress data, or None if not available.
35
- pressure_surface:
36
- A dict containing pressure surface stress data, or None if not available.
19
+ INVALID
20
+ Invalid visualization output type.
21
+ LUMINARY
22
+ Luminary visualization format.
23
+ VTK
24
+ VTK visualization format.
37
25
  """
38
26
 
39
- drag_force: float
40
- lift_force: float
41
- wall_shear_stress: dict[str, Any] | None
42
- pressure_surface: dict[str, Any] | None
43
-
44
- def __init__(self, inference_result: dict[str, Any]) -> None:
45
- self.drag_force = inference_result["drag_force"]
46
- self.lift_force = inference_result["lift_force"]
47
- self.wall_shear_stress = inference_result.get("wall-shear-stress", None)
48
- self.pressure_surface = inference_result.get("pressure_surface", None)
49
-
50
-
51
- def external_aero_inference(
52
- project: Project,
53
- stl_file: str,
54
- model_version_id: PhysicsAiModelVersionID,
55
- conditions: Optional[Dict[str, Any]] = None,
56
- settings: Optional[Dict[str, Any]] = None,
57
- write_visualization_data=False,
58
- ) -> ExtAeroInferenceResult:
59
- """Performs an inference job returning external aerodynamic results.
60
- Parameters
61
- ----------
62
- project : Project
63
- The project to which the inference files will be added.
64
- stl_file : str
65
- Fullpath the STL file to be used for inference.
66
- model_version_id : PhysicsAiModelVersionID
67
- The ID of the trained model version to use for inference.
68
- conditions : Dict[str, Any], optional
69
- Dictionary of conditions to be passed to the inference service (e.g., alpha, beta, etc.).
70
- settings : Dict[str, Any], optional
71
- Dictionary of settings to be passed to inference service (e.g., stencil_size)
72
- write_visualization_data : bool, optional
73
- Whether to write LC visualization data for visualization by Luminary.
74
-
75
-
76
- Returns
77
- ExtAeroInferenceResult
78
- Result of the external aerodynamic inference job.
79
-
80
- warning:: This feature is experimental and may change or be removed without notice.
27
+ INVALID = physicsaiinferencepb.INVALID
28
+ LUMINARY = physicsaiinferencepb.LUMINARY
29
+ VTK = physicsaiinferencepb.VTK
30
+
31
+
32
+ class InferenceFieldType(IntEnum):
81
33
  """
34
+ Represents the type of an inference field.
82
35
 
83
- result = perform_inference(
84
- project, stl_file, model_version_id, conditions, settings, write_visualization_data
85
- )
86
- return ExtAeroInferenceResult(result)
87
-
88
-
89
- def perform_inference(
90
- project: Project,
91
- stl_file: str,
92
- model_version_id: PhysicsAiModelVersionID,
93
- conditions: Optional[Dict[str, Any]] = None,
94
- settings: Optional[Dict[str, Any]] = None,
95
- write_visualization_data=False,
96
- ) -> dict[str, Any]:
97
- """Creates an inference service job.
98
- Parameters
36
+ Attributes
99
37
  ----------
100
- project : Project
101
- The project to which the inference files will be added.
102
- stl_file : str
103
- Fullpath the STL file to be used for inference.
104
- model_version_id : PhysicsAiModelVersionID
105
- The ID of the trained model version to use for inference.
106
- conditions : Dict[str, Any], optional
107
- Dictionary of conditions to be passed to the inference service (e.g., alpha, beta, etc.).
108
- settings : Dict[str, Any], optional
109
- Dictionary of settings to be passed to inference service (e.g., stencil_size)
110
- write_visualization_data : bool, optional
111
- Whether to write LC visualization data for visualization by Luminary.
112
-
113
-
114
- Returns
115
- dict[str, Any]
116
- Response from the server as key-value pairs.
117
-
118
- warning:: This feature is experimental and may change or be removed without notice.
38
+ UNKNOWN_TYPE
39
+ Unknown field type.
40
+ SCALAR
41
+ Scalar field type (single value).
42
+ VECTOR
43
+ Vector field type (multiple values).
119
44
  """
120
45
 
121
- client = get_default_client()
122
-
123
- def upload_if_file(fname: str) -> str:
124
- if os.path.exists(fname) and os.path.isfile(fname):
125
- params = uploadpb.ResourceParams()
126
- result = upload_file(client, project.id, params, fname)
127
- return result[1].url
128
- if fname.startswith("gs://"):
129
- return fname
130
- raise RuntimeError("Unsupported file for inference")
131
-
132
- def future_file(url: str) -> Callable[[], dict[str, Any]]:
133
- def download_file() -> dict[str, Any]:
134
- with urllib.request.urlopen(url) as f:
135
- serialized = f.read()
136
- jsondata = json_loads(serialized)
137
- data = base64.b64decode(jsondata["data"])
138
- jsondata["data"] = data
139
- return jsondata
140
-
141
- return download_file
142
-
143
- stl_url = upload_if_file(stl_file)
144
-
145
- raw = start_inference_job(
146
- project, stl_url, model_version_id, conditions, settings, write_visualization_data
147
- )
148
- currated: dict[str, Any] = {}
149
- for k, v in raw.items():
150
- if isinstance(v, str) and v.startswith("https://"):
151
- tmp = future_file(v)
152
- if k.endswith("_url"):
153
- currated[k[:-4]] = tmp
154
- currated[k] = v
155
- else:
156
- currated[k] = tmp
157
- currated[k + "_url"] = v
158
- else:
159
- currated[k] = v
160
- return currated
161
-
162
-
163
- def start_inference_job(
164
- project: Project,
165
- stl_url: str,
166
- model_version_id: PhysicsAiModelVersionID,
167
- conditions: Optional[Dict[str, Any]] = None,
168
- settings: Optional[Dict[str, Any]] = None,
169
- write_visualization_data=False,
170
- ) -> dict[str, Any]:
171
- """Creates an inference service job.
172
- Parameters
46
+ UNKNOWN_TYPE = physicsaiinferencepb.UNKNOWN_TYPE
47
+ SCALAR = physicsaiinferencepb.SCALAR
48
+ VECTOR = physicsaiinferencepb.VECTOR
49
+
50
+
51
+ class InferenceFieldCategory(IntEnum):
52
+ """
53
+ Represents the category of an inference field.
54
+
55
+ Attributes
173
56
  ----------
174
- project : Project
175
- Reference to a project.
176
- stl_url : str
177
- URL of the STL file to be used for inference.
178
- model_version_id : PhysicsAiModelVersionID
179
- The ID of the trained model version to use for inference.
180
- conditions : Dict[str, Any], optional
181
- Dictionary of conditions to be passed to the inference service (e.g., alpha, beta, etc.).
182
- settings : Dict[str, Any], optional
183
- Dictionary of settings to be passed to inference service (e.g., stencil_size)
184
- write_visualization_data : bool, optional
185
- Whether to write LC visualization data for visualization by Luminary.
186
-
187
-
188
- Returns
189
- dict[str, Any]
190
- Response from the server as key-value pairs.
191
-
192
- warning:: This feature is experimental and may change or be removed without notice.
57
+ UNKNOWN_CATEGORY
58
+ Unknown field category.
59
+ NUMERIC
60
+ Numeric field category (e.g., forces, moments).
61
+ SURFACE
62
+ Surface field category (e.g., surface pressure).
63
+ VOLUME
64
+ Volume field category (e.g., velocity, pressure).
193
65
  """
194
66
 
195
- # Embed settings and store as bytes
196
- settings_bytes = b""
197
- if settings is not None:
198
- settings_bytes = json_dumps(settings).encode("utf-8")
199
-
200
- # Convert parameters dict to bytes if provided
201
- conditions_bytes = b""
202
- if conditions is not None:
203
- conditions_bytes = json_dumps(conditions).encode("utf-8")
204
-
205
- req = inferencepb.CreateInferenceServiceJobRequest(
206
- stl_url=stl_url,
207
- model_version_id=str(model_version_id),
208
- conditions=conditions_bytes,
209
- settings=settings_bytes,
210
- project_id=project.id,
211
- write_visualization_data=write_visualization_data,
212
- )
213
- res: inferencepb.CreateInferenceServiceJobResponse = (
214
- get_default_client().CreateInferenceServiceJob(req)
215
- )
216
-
217
- return json_loads(str(res.response, encoding="utf-8"))
67
+ UNKNOWN_CATEGORY = physicsaiinferencepb.UNKNOWN_CATEGORY
68
+ NUMERIC = physicsaiinferencepb.NUMERIC
69
+ SURFACE = physicsaiinferencepb.SURFACE
70
+ VOLUME = physicsaiinferencepb.VOLUME
71
+
72
+
73
+ @ProtoWrapper(physicsaiinferencepb.VisualizationExport)
74
+ class VisualizationExport(ProtoWrapperBase):
75
+ """Represents a visualization export."""
76
+
77
+ type: VisualizationOutput
78
+ url: str
79
+ _proto: physicsaiinferencepb.VisualizationExport
80
+
81
+ def get_url(self) -> str:
82
+ return self.url
83
+
84
+
85
+ @ProtoWrapper(physicsaiinferencepb.NumericResult)
86
+ class NumericResult(ProtoWrapperBase):
87
+ """Represents a numeric result."""
88
+
89
+ scalar: float
90
+ vector: list[float]
91
+ _proto: physicsaiinferencepb.NumericResult
92
+
93
+ def get_value(self) -> Any:
94
+ if self._proto.HasField("scalar"):
95
+ return self.scalar
96
+ if self._proto.HasField("vector"):
97
+ return list(self._proto.vector.values)
98
+ return None
99
+
100
+
101
+ @ProtoWrapper(physicsaiinferencepb.SurfaceForInference)
102
+ class SurfaceForInference(ProtoWrapperBase):
103
+ """Represents a surface for inference."""
104
+
105
+ name: str
106
+ url: str
107
+ _proto: physicsaiinferencepb.SurfaceForInference
108
+
109
+ def get_name(self) -> str:
110
+ return self.name
111
+
112
+ def get_url(self) -> str:
113
+ return self.url
114
+
115
+
116
+ @ProtoWrapper(physicsaiinferencepb.InferenceResult)
117
+ class InferenceResult(ProtoWrapperBase):
118
+ """Represents an inference result."""
119
+
120
+ name: str
121
+ surface_results: dict[str, str]
122
+ volume_results: dict[str, str]
123
+ visualizations: list[VisualizationExport]
124
+
125
+ @property
126
+ def number_outputs(self) -> dict[str, NumericResult]:
127
+ """Returns number_outputs with wrapped NumericResult values."""
128
+ return {k: NumericResult(v) for k, v in self._proto.number_outputs.items()}
129
+
130
+ def get_number_outputs(self) -> dict[str, Any]:
131
+ return MessageToDict(self._proto.number_outputs, preserving_proto_field_name=True)
132
+
133
+ def get_surface_results(self) -> dict[str, Any]:
134
+ return MessageToDict(self.surface_results, preserving_proto_field_name=True)
135
+
136
+ def get_volume_results(self) -> dict[str, Any]:
137
+ return MessageToDict(self.volume_results, preserving_proto_field_name=True)
138
+
139
+ def get_visualizations(self) -> list[dict[str, Any]]:
140
+ return [
141
+ MessageToDict(viz._proto, preserving_proto_field_name=True)
142
+ for viz in self.visualizations
143
+ ]
144
+
145
+
146
+ @ProtoWrapper(physicsaiinferencepb.InferenceServiceJob)
147
+ class InferenceJob(ProtoWrapperBase):
148
+ """Represents an inference service job."""
149
+
150
+ job_id: str
151
+ status: basepb.JobStatus
152
+ results: list[InferenceResult]
153
+ merged_visualizations: list[VisualizationExport]
154
+ _proto: physicsaiinferencepb.InferenceServiceJob
155
+
156
+ @property
157
+ def id(self) -> str:
158
+ """Alias for job_id for convenience."""
159
+ return self.job_id
160
+
161
+ def get_status(self) -> str:
162
+ return basepb.JobStatusType.Name(self.status.typ)
163
+
164
+ def get_results(self) -> list[dict[str, Any]]:
165
+ return [
166
+ MessageToDict(result._proto, preserving_proto_field_name=True)
167
+ for result in self.results
168
+ ]
169
+
170
+ def get_merged_visualizations(self) -> list[dict[str, Any]]:
171
+ return [
172
+ MessageToDict(viz._proto, preserving_proto_field_name=True)
173
+ for viz in self.merged_visualizations
174
+ ]
175
+
176
+
177
+ @ProtoWrapper(physicsaiinferencepb.InferenceField)
178
+ class InferenceField(ProtoWrapperBase):
179
+ """Represents an inference field."""
180
+
181
+ name: str
182
+ type: InferenceFieldType
183
+ category: InferenceFieldCategory
184
+ _proto: physicsaiinferencepb.InferenceField
@@ -3,6 +3,9 @@ from typing import List, Optional
3
3
 
4
4
  from .._client import get_default_client
5
5
  from .._proto.api.v0.luminarycloud.physics_ai import physics_ai_pb2 as physaipb
6
+ from .._proto.api.v0.luminarycloud.physicsaiinference import (
7
+ physicsaiinference_pb2 as physicsaiinferencepb,
8
+ )
6
9
  from .._wrapper import ProtoWrapper, ProtoWrapperBase
7
10
  from ..types.ids import PhysicsAiModelID, PhysicsAiModelVersionID
8
11
  from ..enum.physics_ai_lifecycle_state import PhysicsAiLifecycleState
@@ -21,6 +24,25 @@ class PhysicsAiModelVersion(ProtoWrapperBase):
21
24
  lifecycle_state: PhysicsAiLifecycleState
22
25
  _proto: physaipb.PhysicsAiModelVersion
23
26
 
27
+ def get_inference_fields(self) -> list[str]:
28
+ """Gets the inference fields available for a trained model version.
29
+
30
+ This retrieves the list of output fields that can be requested from a specific
31
+ model version during inference.
32
+
33
+ Returns
34
+ -------
35
+ list[str]
36
+ List of available inference field names that can be requested from the model.
37
+
38
+ warning:: This feature is experimental and may change or be removed without notice.
39
+ """
40
+ req = physicsaiinferencepb.GetInferenceFieldsRequest(model_version_id=str(self.id))
41
+ res: physicsaiinferencepb.GetInferenceFieldsResponse = (
42
+ get_default_client().GetInferenceFields(req)
43
+ )
44
+ return list(res.inference_fields)
45
+
24
46
 
25
47
  @ProtoWrapper(physaipb.PhysicsAiModel)
26
48
  class PhysicsAiModel(ProtoWrapperBase):
@@ -17,6 +17,7 @@ def _download_processed_solution_physics_ai( # noqa: F841
17
17
  process_volume: bool = False,
18
18
  single_precision: bool = True,
19
19
  internal_options: Optional[Dict[str, str]] = None,
20
+ export_surface_groups: Optional[Dict[str, List[str]]] = None,
20
21
  ) -> tarfile.TarFile:
21
22
  """
22
23
  Download solution data with physics AI processing applied.
@@ -37,6 +38,8 @@ def _download_processed_solution_physics_ai( # noqa: F841
37
38
  If None, all available volume fields are included.
38
39
  process_volume: Whether to process volume data
39
40
  single_precision: Whether to use single precision for floating point fields
41
+ export_surface_groups: Dictionary mapping group names to lists of surface names.
42
+ Each group will be exported as an individual STL file.
40
43
 
41
44
  Raises:
42
45
  ValueError: If invalid field names are provided
@@ -46,6 +49,7 @@ def _download_processed_solution_physics_ai( # noqa: F841
46
49
  get_default_client(),
47
50
  solution_id,
48
51
  exclude_surfaces=exclude_surfaces,
52
+ export_surface_groups=export_surface_groups,
49
53
  fill_holes=fill_holes,
50
54
  surface_fields_to_keep=surface_fields_to_keep,
51
55
  volume_fields_to_keep=volume_fields_to_keep,