luminarycloud 0.18.1__py3-none-any.whl → 0.19.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 (45) hide show
  1. luminarycloud/_client/client.py +21 -5
  2. luminarycloud/_client/http_client.py +168 -0
  3. luminarycloud/_client/rpc_error.py +1 -0
  4. luminarycloud/_client/tracing.py +72 -22
  5. luminarycloud/_helpers/_wait_for_mesh.py +5 -7
  6. luminarycloud/_proto/api/v0/luminarycloud/inference/inference_pb2.py +8 -8
  7. luminarycloud/_proto/api/v0/luminarycloud/inference/inference_pb2.pyi +9 -8
  8. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2.py +83 -25
  9. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2.pyi +214 -0
  10. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2_grpc.py +34 -0
  11. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2_grpc.pyi +12 -0
  12. luminarycloud/_proto/api/v0/luminarycloud/simulation/simulation_pb2.py +60 -60
  13. luminarycloud/_proto/api/v0/luminarycloud/simulation/simulation_pb2.pyi +5 -1
  14. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.py +70 -40
  15. luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.pyi +64 -3
  16. luminarycloud/_proto/client/simulation_pb2.py +347 -332
  17. luminarycloud/_proto/client/simulation_pb2.pyi +55 -9
  18. luminarycloud/_proto/inferenceservice/inferenceservice_pb2.py +10 -10
  19. luminarycloud/_proto/inferenceservice/inferenceservice_pb2.pyi +9 -8
  20. luminarycloud/_proto/physicsaitrainingservice/physicsaitrainingservice_pb2.py +29 -0
  21. luminarycloud/_proto/physicsaitrainingservice/physicsaitrainingservice_pb2.pyi +7 -0
  22. luminarycloud/_proto/physicsaitrainingservice/physicsaitrainingservice_pb2_grpc.py +70 -0
  23. luminarycloud/_proto/physicsaitrainingservice/physicsaitrainingservice_pb2_grpc.pyi +30 -0
  24. luminarycloud/enum/quantity_type.py +13 -0
  25. luminarycloud/exceptions.py +6 -0
  26. luminarycloud/params/enum/_enum_wrappers.py +28 -2
  27. luminarycloud/params/simulation/material/material_solid_.py +15 -1
  28. luminarycloud/params/simulation/sliding_interfaces_.py +8 -0
  29. luminarycloud/physics_ai/architectures.py +58 -0
  30. luminarycloud/physics_ai/inference.py +30 -25
  31. luminarycloud/physics_ai/training_jobs.py +37 -0
  32. luminarycloud/pipelines/api.py +50 -102
  33. luminarycloud/project.py +15 -43
  34. luminarycloud/simulation.py +2 -0
  35. luminarycloud/simulation_template.py +2 -1
  36. luminarycloud/tables.py +14 -15
  37. luminarycloud/vis/visualization.py +2 -2
  38. {luminarycloud-0.18.1.dist-info → luminarycloud-0.19.1.dist-info}/METADATA +1 -1
  39. {luminarycloud-0.18.1.dist-info → luminarycloud-0.19.1.dist-info}/RECORD +40 -39
  40. luminarycloud/_proto/api/v0/luminarycloud/pipelines/pipelines_pb2.py +0 -246
  41. luminarycloud/_proto/api/v0/luminarycloud/pipelines/pipelines_pb2.pyi +0 -420
  42. luminarycloud/_proto/api/v0/luminarycloud/pipelines/pipelines_pb2_grpc.py +0 -240
  43. luminarycloud/_proto/api/v0/luminarycloud/pipelines/pipelines_pb2_grpc.pyi +0 -90
  44. luminarycloud/enum/pipeline_job_status.py +0 -23
  45. {luminarycloud-0.18.1.dist-info → luminarycloud-0.19.1.dist-info}/WHEEL +0 -0
@@ -51,8 +51,8 @@ def external_aero_inference(
51
51
  project: Project,
52
52
  stl_file: str,
53
53
  artifact_url: str,
54
- parameters: Optional[Dict[str, Any]] = None,
55
- stencil_size: int = 1,
54
+ conditions: Optional[Dict[str, Any]] = None,
55
+ settings: Optional[Dict[str, Any]] = None,
56
56
  write_visualization_data=False,
57
57
  ) -> ExtAeroInferenceResult:
58
58
  """Performs an inference job returning external aerodynamic results.
@@ -64,10 +64,10 @@ def external_aero_inference(
64
64
  Fullpath the STL file to be used for inference.
65
65
  artifact_url : str
66
66
  Fullpath of the model artifact directory to be used for inference.
67
- parameters : Dict[str, Any], optional
68
- Dictionary of parameters to be passed to the inference service (e.g., alpha, beta, etc.).
69
- stencil_size : int, optional
70
- Size of the stencil to be used for inference. Defaults to 1.
67
+ conditions : Dict[str, Any], optional
68
+ Dictionary of conditions to be passed to the inference service (e.g., alpha, beta, etc.).
69
+ settings : Dict[str, Any], optional
70
+ Dictionary of settings to be passed to inference service (e.g., stencil_size)
71
71
  write_visualization_data : bool, optional
72
72
  Whether to write LC visualization data for visualization by Luminary.
73
73
 
@@ -80,7 +80,7 @@ def external_aero_inference(
80
80
  """
81
81
 
82
82
  result = perform_inference(
83
- project, stl_file, artifact_url, parameters, stencil_size, write_visualization_data
83
+ project, stl_file, artifact_url, conditions, settings, write_visualization_data
84
84
  )
85
85
  return ExtAeroInferenceResult(result)
86
86
 
@@ -89,8 +89,8 @@ def perform_inference(
89
89
  project: Project,
90
90
  stl_file: str,
91
91
  artifact_url: str,
92
- parameters: Optional[Dict[str, Any]] = None,
93
- stencil_size: int = 1,
92
+ conditions: Optional[Dict[str, Any]] = None,
93
+ settings: Optional[Dict[str, Any]] = None,
94
94
  write_visualization_data=False,
95
95
  ) -> dict[str, Any]:
96
96
  """Creates an inference service job.
@@ -102,10 +102,10 @@ def perform_inference(
102
102
  Fullpath the STL file to be used for inference.
103
103
  artifact_url : str
104
104
  Fullpath of the model artifact directory to be used for inference.
105
- parameters : Dict[str, Any], optional
106
- Dictionary of parameters to be passed to the inference service (e.g., alpha, beta, etc.).
107
- stencil_size : int, optional
108
- Size of the stencil to be used for inference. Defaults to 1.
105
+ conditions : Dict[str, Any], optional
106
+ Dictionary of conditions to be passed to the inference service (e.g., alpha, beta, etc.).
107
+ settings : Dict[str, Any], optional
108
+ Dictionary of settings to be passed to inference service (e.g., stencil_size)
109
109
  write_visualization_data : bool, optional
110
110
  Whether to write LC visualization data for visualization by Luminary.
111
111
 
@@ -142,7 +142,7 @@ def perform_inference(
142
142
  stl_url = upload_if_file(stl_file)
143
143
 
144
144
  raw = start_inference_job(
145
- project, stl_url, artifact_url, parameters, stencil_size, write_visualization_data
145
+ project, stl_url, artifact_url, conditions, settings, write_visualization_data
146
146
  )
147
147
  currated: dict[str, Any] = {}
148
148
  for k, v in raw.items():
@@ -163,8 +163,8 @@ def start_inference_job(
163
163
  project: Project,
164
164
  stl_url: str,
165
165
  artifact_url: str,
166
- parameters: Optional[Dict[str, Any]] = None,
167
- stencil_size: int = 1,
166
+ conditions: Optional[Dict[str, Any]] = None,
167
+ settings: Optional[Dict[str, Any]] = None,
168
168
  write_visualization_data=False,
169
169
  ) -> dict[str, Any]:
170
170
  """Creates an inference service job.
@@ -176,10 +176,10 @@ def start_inference_job(
176
176
  URL of the STL file to be used for inference.
177
177
  artifact_url : str
178
178
  URL of the model artifact directory to be used for inference.
179
- parameters : Dict[str, Any], optional
180
- Dictionary of parameters to be passed to the inference service (e.g., alpha, beta, etc.).
181
- stencil_size : int, optional
182
- Size of the stencil to be used for inference. Defaults to 1.
179
+ conditions : Dict[str, Any], optional
180
+ Dictionary of conditions to be passed to the inference service (e.g., alpha, beta, etc.).
181
+ settings : Dict[str, Any], optional
182
+ Dictionary of settings to be passed to inference service (e.g., stencil_size)
183
183
  write_visualization_data : bool, optional
184
184
  Whether to write LC visualization data for visualization by Luminary.
185
185
 
@@ -191,16 +191,21 @@ def start_inference_job(
191
191
  warning:: This feature is experimental and may change or be removed without notice.
192
192
  """
193
193
 
194
+ # Embed settings and store as bytes
195
+ settings_bytes = b""
196
+ if settings is not None:
197
+ settings_bytes = json_dumps(settings).encode("utf-8")
198
+
194
199
  # Convert parameters dict to bytes if provided
195
- parameters_bytes = b""
196
- if parameters is not None:
197
- parameters_bytes = json_dumps(parameters).encode("utf-8")
200
+ conditions_bytes = b""
201
+ if conditions is not None:
202
+ conditions_bytes = json_dumps(conditions).encode("utf-8")
198
203
 
199
204
  req = inferencepb.CreateInferenceServiceJobRequest(
200
205
  stl_url=stl_url,
201
206
  artifact_url=artifact_url,
202
- parameters=parameters_bytes,
203
- stencil_size=stencil_size,
207
+ conditions=conditions_bytes,
208
+ settings=settings_bytes,
204
209
  project_id=project.id,
205
210
  write_visualization_data=write_visualization_data,
206
211
  )
@@ -0,0 +1,37 @@
1
+ # Copyright 2025 Luminary Cloud, Inc. All Rights Reserved.
2
+ from typing import List, Optional
3
+ from datetime import datetime
4
+
5
+ from .._client import get_default_client
6
+ from .._proto.api.v0.luminarycloud.physics_ai import physics_ai_pb2 as physaipb
7
+ from .._proto.base import base_pb2 as basepb
8
+ from .._wrapper import ProtoWrapper, ProtoWrapperBase
9
+ from ..types.ids import PhysicsAiArchitectureVersionID
10
+
11
+
12
+ @ProtoWrapper(physaipb.PhysicsAiTrainingJob)
13
+ class PhysicsAiTrainingJob(ProtoWrapperBase):
14
+ """
15
+ Represents a Physics AI training job.
16
+
17
+ .. warning:: This feature is experimental and may change or be removed without notice.
18
+ """
19
+
20
+ id: str
21
+ architecture_version_id: PhysicsAiArchitectureVersionID
22
+ user_id: str
23
+ training_config: str
24
+ training_data_source_type: physaipb.TrainingDataSourceType
25
+ training_description: str
26
+ external_dataset_uri: str
27
+ initialization_type: physaipb.ModelInitializationType
28
+ base_model_version_id: str
29
+ status: basepb.JobStatus
30
+ error_message: str
31
+ output_model_version_id: str
32
+ creation_time: datetime
33
+ update_time: datetime
34
+ _proto: physaipb.PhysicsAiTrainingJob
35
+
36
+ def get_status(self) -> str:
37
+ return basepb.JobStatusType.Name(self.status.typ)
@@ -1,14 +1,11 @@
1
1
  # Copyright 2023-2024 Luminary Cloud, Inc. All Rights Reserved.
2
+ from typing import Literal
2
3
  from dataclasses import dataclass
3
4
 
4
5
  from datetime import datetime
5
6
 
6
- from luminarycloud._helpers import timestamp_to_datetime
7
-
8
- from ..enum.pipeline_job_status import PipelineJobStatus
9
7
  from ..pipelines import Pipeline, PipelineArgs
10
8
  from .._client import get_default_client
11
- from .._proto.api.v0.luminarycloud.pipelines import pipelines_pb2 as pipelinespb
12
9
 
13
10
 
14
11
  @dataclass
@@ -17,21 +14,21 @@ class PipelineRecord:
17
14
  name: str
18
15
  description: str | None
19
16
  definition_yaml: str
20
- create_time: datetime
21
- update_time: datetime
17
+ created_at: datetime
18
+ updated_at: datetime
22
19
 
23
20
  def pipeline(self) -> Pipeline:
24
21
  return Pipeline._from_yaml(self.definition_yaml)
25
22
 
26
23
  @classmethod
27
- def from_proto(cls, proto: pipelinespb.Pipeline) -> "PipelineRecord":
24
+ def from_json(cls, json: dict) -> "PipelineRecord":
28
25
  return cls(
29
- id=proto.id,
30
- name=proto.name,
31
- description=proto.description,
32
- definition_yaml=proto.definition_yaml,
33
- create_time=timestamp_to_datetime(proto.created_at),
34
- update_time=timestamp_to_datetime(proto.updated_at),
26
+ id=json["id"],
27
+ name=json["name"],
28
+ description=json["description"],
29
+ definition_yaml=json["definition_yaml"],
30
+ created_at=datetime.fromisoformat(json["created_at"]),
31
+ updated_at=datetime.fromisoformat(json["updated_at"]),
35
32
  )
36
33
 
37
34
 
@@ -42,30 +39,26 @@ class PipelineJobRecord:
42
39
  project_id: str
43
40
  name: str
44
41
  description: str | None
45
- status: PipelineJobStatus
46
- create_time: datetime
47
- update_time: datetime
42
+ status: Literal["pending", "running", "completed", "failed", "cancelled"]
43
+ created_at: datetime
44
+ updated_at: datetime
48
45
  started_at: datetime | None
49
46
  completed_at: datetime | None
50
47
 
51
48
  @classmethod
52
- def from_proto(cls, proto: pipelinespb.PipelineJob) -> "PipelineJobRecord":
49
+ def from_json(cls, json: dict) -> "PipelineJobRecord":
53
50
  return cls(
54
- id=proto.id,
55
- pipeline_id=proto.pipeline_id,
56
- project_id=proto.project_id,
57
- name=proto.name,
58
- description=proto.description,
59
- status=PipelineJobStatus(proto.status),
60
- create_time=timestamp_to_datetime(proto.created_at),
61
- update_time=timestamp_to_datetime(proto.updated_at),
62
- started_at=(
63
- timestamp_to_datetime(proto.started_at) if proto.HasField("started_at") else None
64
- ),
51
+ id=json["id"],
52
+ pipeline_id=json["pipeline_id"],
53
+ project_id=json["project_id"],
54
+ name=json["name"],
55
+ description=json["description"],
56
+ status=json["status"],
57
+ created_at=datetime.fromisoformat(json["created_at"]),
58
+ updated_at=datetime.fromisoformat(json["updated_at"]),
59
+ started_at=datetime.fromisoformat(json["started_at"]) if json["started_at"] else None,
65
60
  completed_at=(
66
- timestamp_to_datetime(proto.completed_at)
67
- if proto.HasField("completed_at")
68
- else None
61
+ datetime.fromisoformat(json["completed_at"]) if json["completed_at"] else None
69
62
  ),
70
63
  )
71
64
 
@@ -89,20 +82,21 @@ def create_pipeline(
89
82
  definition_yaml = pipeline.to_yaml()
90
83
  else:
91
84
  definition_yaml = pipeline
92
- req = pipelinespb.CreatePipelineRequest(
93
- name=name, definition_yaml=definition_yaml, description=description
94
- )
95
- res: pipelinespb.CreatePipelineResponse = get_default_client().CreatePipeline(req)
96
- return PipelineRecord.from_proto(res.pipeline)
85
+ body = {
86
+ "name": name,
87
+ "definition_yaml": definition_yaml,
88
+ "description": description,
89
+ }
90
+ res = get_default_client().http.post("/rest/v0/pipelines", body)
91
+ return PipelineRecord.from_json(res["data"])
97
92
 
98
93
 
99
94
  def list_pipelines() -> list[PipelineRecord]:
100
95
  """
101
96
  List all pipelines.
102
97
  """
103
- req = pipelinespb.ListPipelinesRequest()
104
- res: pipelinespb.ListPipelinesResponse = get_default_client().ListPipelines(req)
105
- return [PipelineRecord.from_proto(p) for p in res.pipelines]
98
+ res = get_default_client().http.get("/rest/v0/pipelines")
99
+ return [PipelineRecord.from_json(p) for p in res["data"]]
106
100
 
107
101
 
108
102
  def get_pipeline(id: str) -> PipelineRecord:
@@ -114,9 +108,8 @@ def get_pipeline(id: str) -> PipelineRecord:
114
108
  id : str
115
109
  ID of the pipeline to fetch.
116
110
  """
117
- req = pipelinespb.GetPipelineRequest(id=id)
118
- res: pipelinespb.GetPipelineResponse = get_default_client().GetPipeline(req)
119
- return PipelineRecord.from_proto(res.pipeline)
111
+ res = get_default_client().http.get(f"/rest/v0/pipelines/{id}")
112
+ return PipelineRecord.from_json(res["data"])
120
113
 
121
114
 
122
115
  def create_pipeline_job(
@@ -139,75 +132,30 @@ def create_pipeline_job(
139
132
  Description of the pipeline job.
140
133
  """
141
134
 
142
- col_values = [[] for _ in args.params]
143
- for row in args.rows:
144
- for i, v in enumerate(row.row_values):
145
- col_values[i].append(v)
146
-
147
- cols = []
148
-
149
- for i, param in enumerate(args.params):
150
- if param._represented_type() == str:
151
- cols.append(
152
- pipelinespb.PipelineJobArgsColumn(
153
- string_column=pipelinespb.PipelineJobArgsColumn.StringColumn(
154
- name=param.name,
155
- values=col_values[i],
156
- )
157
- )
158
- )
159
- elif param._represented_type() == int:
160
- cols.append(
161
- pipelinespb.PipelineJobArgsColumn(
162
- int_column=pipelinespb.PipelineJobArgsColumn.IntColumn(
163
- name=param.name,
164
- values=col_values[i],
165
- )
166
- )
167
- )
168
- elif param._represented_type() == float:
169
- cols.append(
170
- pipelinespb.PipelineJobArgsColumn(
171
- double_column=pipelinespb.PipelineJobArgsColumn.DoubleColumn(
172
- name=param.name,
173
- values=col_values[i],
174
- )
175
- )
176
- )
177
- elif param._represented_type() == bool:
178
- cols.append(
179
- pipelinespb.PipelineJobArgsColumn(
180
- bool_column=pipelinespb.PipelineJobArgsColumn.BoolColumn(
181
- name=param.name,
182
- values=col_values[i],
183
- )
184
- )
185
- )
186
-
187
- req = pipelinespb.CreatePipelineJobRequest(
188
- pipeline_id=pipeline_id,
189
- args_columns=cols,
190
- name=name,
191
- description=description,
192
- project_id=project_id,
193
- )
194
- res: pipelinespb.CreatePipelineJobResponse = get_default_client().CreatePipelineJob(req)
195
- return PipelineJobRecord.from_proto(res.pipeline_job)
135
+ arg_rows = [row.row_values for row in args.rows]
136
+ body = {
137
+ "name": name,
138
+ "description": description,
139
+ "project_id": project_id,
140
+ "argument_names": [p.name for p in args.params],
141
+ "argument_rows": arg_rows,
142
+ }
143
+
144
+ res = get_default_client().http.post(f"/rest/v0/pipelines/{pipeline_id}/pipeline_jobs", body)
145
+ return PipelineJobRecord.from_json(res["data"])
196
146
 
197
147
 
198
148
  def get_pipeline_job(id: str) -> PipelineJobRecord:
199
149
  """
200
150
  Get a pipeline job by ID.
201
151
  """
202
- req = pipelinespb.GetPipelineJobRequest(id=id)
203
- res: pipelinespb.GetPipelineJobResponse = get_default_client().GetPipelineJob(req)
204
- return PipelineJobRecord.from_proto(res.pipeline_job)
152
+ res = get_default_client().http.get(f"/rest/v0/pipeline_jobs/{id}")
153
+ return PipelineJobRecord.from_json(res["data"])
205
154
 
206
155
 
207
156
  def list_pipeline_jobs() -> list[PipelineJobRecord]:
208
157
  """
209
158
  List all pipeline jobs.
210
159
  """
211
- req = pipelinespb.ListPipelineJobsRequest()
212
- res: pipelinespb.ListPipelineJobsResponse = get_default_client().ListPipelineJobs(req)
213
- return [PipelineJobRecord.from_proto(p) for p in res.pipeline_jobs]
160
+ res = get_default_client().http.get("/rest/v0/pipeline_jobs")
161
+ return [PipelineJobRecord.from_json(p) for p in res["data"]]
luminarycloud/project.py CHANGED
@@ -10,8 +10,6 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, Literal
10
10
 
11
11
  import concurrent
12
12
 
13
- import grpc
14
-
15
13
  import luminarycloud as lc
16
14
  from luminarycloud._helpers.named_variables import _named_variables_to_proto
17
15
  from luminarycloud.params.simulation.adjoint_ import Adjoint
@@ -258,19 +256,16 @@ class Project(ProtoWrapperBase):
258
256
  )
259
257
  return lc.Mesh(_mesh)
260
258
 
261
- @deprecated("Use create_or_get_mesh() instead", "0.10.0")
262
- def create_mesh(
259
+ def create_or_get_mesh(
263
260
  self,
264
261
  params: MeshAdaptationParams | MeshGenerationParams,
265
262
  *,
266
263
  name: str,
264
+ request_id: Optional[str] = None,
267
265
  ) -> "Mesh":
268
266
  """
269
- Create a new mesh in the project.
270
-
271
- .. deprecated:: 0.10.0
272
- `create_mesh()` will be removed in v0.11.0, it is replaced by
273
- `create_or_get_mesh()`.
267
+ Create a new mesh in the project, or return an existing mesh with the same request_id
268
+ if it already exists.
274
269
 
275
270
  Parameters
276
271
  ----------
@@ -279,14 +274,24 @@ class Project(ProtoWrapperBase):
279
274
  existing geometry, use MeshGenerationParams. If adapting a mesh from an existing,
280
275
  solution use MeshAdaptationParams.
281
276
  name : str
282
- (Optional) Mesh name. Max 256 characters.
277
+ Mesh name. Max 256 characters.
278
+ request_id : str, optional
279
+ Can be useful as an idempotency key. If there's an existing Mesh with the given
280
+ request_id, that Mesh will be returned. If there's no existing Mesh with the given
281
+ request_id, then a Mesh will be created and associated with that request_id. If not
282
+ provided, a random request_id will be generated for the Mesh, effectively preventing it
283
+ from being retrieved by a future `create_or_get_mesh` request. Max 256 characters.
283
284
  """
284
285
 
286
+ if request_id is None:
287
+ request_id = str(uuid.uuid4())
288
+
285
289
  client = get_default_client()
286
290
 
287
291
  req = meshpb.CreateMeshRequest(
288
292
  project_id=self.id,
289
293
  name=name,
294
+ request_id=request_id,
290
295
  )
291
296
 
292
297
  if isinstance(params, meshpb.MeshGenerationParams):
@@ -314,39 +319,6 @@ class Project(ProtoWrapperBase):
314
319
  res: meshpb.CreateMeshResponse = client.CreateMesh(req)
315
320
  return lc.Mesh(res.mesh)
316
321
 
317
- def create_or_get_mesh(
318
- self,
319
- params: MeshAdaptationParams | MeshGenerationParams,
320
- *,
321
- name: str,
322
- ) -> "Mesh":
323
- """
324
- Create a new mesh in the project, or return an existing mesh with the same parameters
325
- if it already exists.
326
-
327
- Parameters
328
- ----------
329
- params : MeshGenerationParams | MeshAdaptationParams
330
- The parameters to use to create the mesh. If generating a new mesh from an
331
- existing geometry, use MeshGenerationParams. If adapting a mesh from an existing,
332
- solution use MeshAdaptationParams.
333
- name : str
334
- Mesh name. Max 256 characters.
335
- """
336
-
337
- try:
338
- return self.create_mesh(params, name=name)
339
- except grpc.RpcError as e:
340
- if e.code() == grpc.StatusCode.ALREADY_EXISTS:
341
- message = e.details()
342
- match = re.search(r"mesh-[a-f0-9-]+$", message)
343
- if match:
344
- existing_mesh_id = match.group(0)
345
- req = meshpb.GetMeshRequest(id=existing_mesh_id)
346
- res = get_default_client().GetMesh(req)
347
- return lc.Mesh(res.mesh)
348
- raise
349
-
350
322
  def _create_hex_mesh(
351
323
  self,
352
324
  names_to_file_paths: Dict[str, Union[PathLike[Any], str]],
@@ -57,6 +57,8 @@ class Simulation(ProtoWrapperBase):
57
57
  "ID of the simulation mesh."
58
58
  project_id: ProjectID
59
59
  "ID of the project containing this simulation."
60
+ doe_name: str
61
+ "Name of the design of experiments that created this simulation."
60
62
 
61
63
  _proto: simulationpb.Simulation
62
64
 
@@ -490,7 +490,8 @@ class SimulationTemplate(ProtoWrapperBase):
490
490
  code += "\n\n\n"
491
491
  code += '# Create a new simulation template or modify the one that is synced with the UI "Setup" tab.\n'
492
492
  code += f'project = luminarycloud.get_project("{self.project_id}")\n'
493
- code += f"template = project.create_simulation_template(name={self.name})\n"
493
+ escaped_name = self.name.replace('\\','\\\\').replace('"','\\"')
494
+ code += f'template = project.create_simulation_template(name="{escaped_name}")\n'
494
495
  code += '# TODO(USER): To modify the "Setup" template, uncomment the line below and comment out the line above.\n'
495
496
  code += "# template = project.list_simulation_templates()[0] # Setup template\n\n"
496
497
 
luminarycloud/tables.py CHANGED
@@ -10,7 +10,6 @@ from typing import Union
10
10
  from .enum import TableType, QuantityType
11
11
  from ._helpers import CodeRepr
12
12
  from ._proto.table import table_pb2 as tablepb
13
- from ._proto.quantity import quantity_pb2 as quantitypb
14
13
 
15
14
 
16
15
  def create_rectilinear_table(
@@ -37,30 +36,30 @@ def create_rectilinear_table(
37
36
  def lc_defined_header(table_type: TableType) -> list[Union[int, str]]:
38
37
  """Returns the required header (if any) for a type of table."""
39
38
  if table_type == TableType.MONITOR_POINTS:
40
- return [quantitypb.LENGTH, quantitypb.LENGTH, quantitypb.LENGTH, "name", "id"]
39
+ return [QuantityType.LENGTH, QuantityType.LENGTH, QuantityType.LENGTH, "name", "id"]
41
40
  elif table_type == TableType.RADIAL_DISTRIBUTION:
42
41
  return [
43
- quantitypb.RELATIVE_RADIUS,
44
- quantitypb.THRUST_PROFILE,
45
- quantitypb.TORQUE_PROFILE,
46
- quantitypb.RADIAL_FORCE_PROFILE,
42
+ QuantityType.RELATIVE_RADIUS,
43
+ QuantityType.THRUST_PROFILE,
44
+ QuantityType.TORQUE_PROFILE,
45
+ QuantityType.RADIAL_FORCE_PROFILE,
47
46
  ]
48
47
  elif table_type == TableType.BLADE_GEOMETRY:
49
48
  return [
50
- quantitypb.RELATIVE_RADIUS,
51
- quantitypb.TWIST_ANGLE,
52
- quantitypb.SWEEP_ANGLE,
53
- quantitypb.ANHEDRAL_ANGLE,
54
- quantitypb.RELATIVE_CHORD,
49
+ QuantityType.RELATIVE_RADIUS,
50
+ QuantityType.TWIST_ANGLE,
51
+ QuantityType.SWEEP_ANGLE,
52
+ QuantityType.ANHEDRAL_ANGLE,
53
+ QuantityType.RELATIVE_CHORD,
55
54
  ]
56
55
  elif table_type == TableType.PROFILE_BC:
57
56
  return []
58
57
  elif table_type == TableType.FAN_CURVE:
59
- return [quantitypb.VOLUME_FLOW_RATE, quantitypb.PRESSURE_RISE]
58
+ return [QuantityType.VOLUME_FLOW_RATE, QuantityType.PRESSURE_RISE]
60
59
  elif table_type == TableType.CUSTOM_SAMPLE_DOE:
61
60
  return []
62
61
  elif table_type == TableType.TEMP_VARYING:
63
- return [quantitypb.TEMPERATURE, "quantity"]
62
+ return [QuantityType.TEMPERATURE, "quantity"]
64
63
  else:
65
64
  raise RuntimeError("Unknown type of table.")
66
65
 
@@ -113,7 +112,7 @@ def create_rectilinear_table(
113
112
  if isinstance(first_header, str):
114
113
  table.header.axis_label[-1].name = first_header
115
114
  else:
116
- table.header.axis_label[-1].quantity = QuantityType(first_header).value
115
+ table.header.axis_label[-1].quantity = first_header.value
117
116
  table.axis.append(tablepb.Axis())
118
117
 
119
118
  for label in header[has_axis(table_type) :]:
@@ -121,7 +120,7 @@ def create_rectilinear_table(
121
120
  if isinstance(label, str):
122
121
  table.header.record_label[-1].name = label
123
122
  else:
124
- table.header.record_label[-1].quantity = QuantityType(label).value
123
+ table.header.record_label[-1].quantity = label.value
125
124
 
126
125
  types = data_types(table_type, len(header))
127
126
 
@@ -14,7 +14,6 @@ from luminarycloud.types import Vector3, Vector3Like
14
14
  from .._client import get_default_client
15
15
  from .._helpers._get_project_id import _get_project_id
16
16
  from .._helpers._code_representation import CodeRepr
17
- from .._proto.quantity import quantity_pb2 as quantitypb
18
17
  from .._proto.api.v0.luminarycloud.vis import vis_pb2
19
18
  from ..types import SimulationID, MeshID
20
19
  from luminarycloud.enum import (
@@ -24,6 +23,7 @@ from luminarycloud.enum import (
24
23
  EntityType,
25
24
  SceneMode,
26
25
  VisQuantity,
26
+ QuantityType,
27
27
  )
28
28
  from ..exceptions import NotFoundError
29
29
  from ..geometry import Geometry, get_geometry
@@ -657,7 +657,7 @@ class Scene(CodeRepr):
657
657
  attrs = vis_pb2.DisplayAttributes()
658
658
  attrs.visible = visible
659
659
  attrs.field.component = vis_pb2.Field.COMPONENT_X
660
- attrs.field.quantity_typ = quantitypb.INVALID_QUANTITY_TYPE
660
+ attrs.field.quantity_typ = QuantityType.UNSPECIFIED.value
661
661
  req.spec.display_attributes[id].CopyFrom(attrs)
662
662
 
663
663
  self._validate_filter_connections()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: luminarycloud
3
- Version: 0.18.1
3
+ Version: 0.19.1
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/