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/mesh.py
CHANGED
|
@@ -44,10 +44,17 @@ class Mesh(ProtoWrapperBase):
|
|
|
44
44
|
"""
|
|
45
45
|
return lc.get_project(ProjectID(self._proto.project_id))
|
|
46
46
|
|
|
47
|
-
def geometry_version(self) -> GeometryVersion:
|
|
47
|
+
def geometry_version(self) -> GeometryVersion | None:
|
|
48
48
|
"""
|
|
49
49
|
Get the geometry version associated with this mesh.
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
GeometryVersion | None
|
|
54
|
+
The geometry version associated with this mesh, or None if the mesh has no geometry version.
|
|
50
55
|
"""
|
|
56
|
+
if self._proto.geometry_version_id == "":
|
|
57
|
+
return None
|
|
51
58
|
return get_geometry_version(self._proto.geometry_version_id)
|
|
52
59
|
|
|
53
60
|
def update(
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Generated by generate_sdk_wrappers.py. DO NOT EDIT
|
|
2
|
+
|
|
3
|
+
from abc import ABC, ABCMeta
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import Any
|
|
6
|
+
from uuid import uuid4
|
|
7
|
+
|
|
8
|
+
from google.protobuf.message import Message as _Message
|
|
9
|
+
from luminarycloud.tables import RectilinearTable, _param_name_to_table_type
|
|
10
|
+
from luminarycloud.types import Vector3, LcFloat
|
|
11
|
+
from luminarycloud.types.adfloat import _to_ad_proto, _from_ad_proto
|
|
12
|
+
from luminarycloud._helpers._entity_identifier import _create_entity_identifier
|
|
13
|
+
from luminarycloud._proto.client import simulation_pb2 as clientpb
|
|
14
|
+
from luminarycloud._proto.client.entity_pb2 import EntityIdentifier
|
|
15
|
+
from luminarycloud._helpers import CodeRepr
|
|
16
|
+
import luminarycloud.params.enum._enum_wrappers as enum
|
|
17
|
+
|
|
18
|
+
from luminarycloud.params.simulation._lib import ParamGroupWrapper, create_unique_id
|
|
19
|
+
|
|
20
|
+
from luminarycloud.params.simulation.physics.fluid.solution_controls.fluid_relaxation_method.fluid_implicit_relaxation.robust_startup_ import (
|
|
21
|
+
RobustStartup,
|
|
22
|
+
)
|
|
23
|
+
from luminarycloud.params.simulation.physics.fluid.solution_controls.fluid_relaxation_method.fluid_implicit_relaxation.robust_startup_ import *
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass(kw_only=True)
|
|
27
|
+
class RobustStartupAuto(RobustStartup):
|
|
28
|
+
"""Enable robust startup mode and automatically determine the settings."""
|
|
29
|
+
|
|
30
|
+
pass
|
|
@@ -25,7 +25,7 @@ from luminarycloud.params.simulation.physics.fluid.solution_controls.fluid_relax
|
|
|
25
25
|
|
|
26
26
|
@dataclass(kw_only=True)
|
|
27
27
|
class RobustStartupOn(RobustStartup):
|
|
28
|
-
"""Enable robust startup mode."""
|
|
28
|
+
"""Enable robust startup mode and manually specify the settings."""
|
|
29
29
|
|
|
30
30
|
robust_startup_initial_cfl: LcFloat = 1.0
|
|
31
31
|
"Initial CFL number for robust startup mode. The CFL is ramped toward the target value during startup."
|
|
@@ -37,6 +37,10 @@ from luminarycloud.params.simulation.physics.fluid.solution_controls.fluid_relax
|
|
|
37
37
|
RobustStartup,
|
|
38
38
|
)
|
|
39
39
|
from luminarycloud.params.simulation.physics.fluid.solution_controls.fluid_relaxation_method.fluid_implicit_relaxation.robust_startup_ import *
|
|
40
|
+
from luminarycloud.params.simulation.physics.fluid.solution_controls.fluid_relaxation_method.fluid_implicit_relaxation.robust_startup.robust_startup_auto_ import (
|
|
41
|
+
RobustStartupAuto,
|
|
42
|
+
)
|
|
43
|
+
from luminarycloud.params.simulation.physics.fluid.solution_controls.fluid_relaxation_method.fluid_implicit_relaxation.robust_startup.robust_startup_auto_ import *
|
|
40
44
|
from luminarycloud.params.simulation.physics.fluid.solution_controls.fluid_relaxation_method.fluid_implicit_relaxation.robust_startup.robust_startup_off_ import (
|
|
41
45
|
RobustStartupOff,
|
|
42
46
|
)
|
|
@@ -54,7 +58,7 @@ class FluidImplicitRelaxation(FluidRelaxationMethod):
|
|
|
54
58
|
implicit_method: enum.ImplicitMethod = enum.ImplicitMethod.BACKWARD_EULER
|
|
55
59
|
"Scheme for implicit relaxation of the governing equations."
|
|
56
60
|
linear_solver_type: LinearSolverType = field(default_factory=GaussSeidel)
|
|
57
|
-
"Type of linear solver used for implicit relaxation. Possible types: ``GaussSeidel``, ``
|
|
61
|
+
"Type of linear solver used for implicit relaxation. Possible types: ``GaussSeidel``, ``KrylovAmg`` from the ``linear_solver_type`` module."
|
|
58
62
|
jacobian_update_method: enum.JacobianUpdateMethod = (
|
|
59
63
|
enum.JacobianUpdateMethod.EXPLICIT_INTERVAL_AND_WARMUP
|
|
60
64
|
)
|
|
@@ -63,8 +67,8 @@ class FluidImplicitRelaxation(FluidRelaxationMethod):
|
|
|
63
67
|
"How many iterations in between updating the Jacobian values for implicit solving."
|
|
64
68
|
jacobian_warmup_threshold: int = 300
|
|
65
69
|
"How many iterations to update Jacobians every iteration before switching to the specified 'Jacobian Update Interval'."
|
|
66
|
-
robust_startup: RobustStartup = field(default_factory=
|
|
67
|
-
"Applies a robust startup process during the initial transients of a simulation. Applicable to steady problems only. Possible types: ``RobustStartupOn``, ``RobustStartupOff`` from the ``robust_startup`` module."
|
|
70
|
+
robust_startup: RobustStartup = field(default_factory=RobustStartupAuto)
|
|
71
|
+
"Applies a robust startup process during the initial transients of a simulation. Applicable to steady problems only. Possible types: ``RobustStartupOn``, ``RobustStartupAuto``, ``RobustStartupOff`` from the ``robust_startup`` module."
|
|
68
72
|
relaxation_flow: LcFloat = 1.0
|
|
69
73
|
"Under-relaxation factor in [0,1] applied to the mean flow solution update with each implicit nonlinear iteration. Default of 1.0."
|
|
70
74
|
relaxation_turb: LcFloat = 0.5
|
|
@@ -122,6 +122,8 @@ class SolutionControlsFluid(CodeRepr, ParamGroupWrapper[clientpb.SolutionControl
|
|
|
122
122
|
_proto.robust_startup_iterations.value = (
|
|
123
123
|
self.fluid_relaxation_method.robust_startup.robust_startup_iterations
|
|
124
124
|
)
|
|
125
|
+
if isinstance(self.fluid_relaxation_method.robust_startup, RobustStartupAuto):
|
|
126
|
+
_proto.robust_startup = clientpb.ROBUST_STARTUP_AUTO
|
|
125
127
|
if isinstance(self.fluid_relaxation_method.robust_startup, RobustStartupOff):
|
|
126
128
|
_proto.robust_startup = clientpb.ROBUST_STARTUP_OFF
|
|
127
129
|
_proto.relax_flow.CopyFrom(_to_ad_proto(self.fluid_relaxation_method.relaxation_flow))
|
|
@@ -211,6 +213,8 @@ class SolutionControlsFluid(CodeRepr, ParamGroupWrapper[clientpb.SolutionControl
|
|
|
211
213
|
self.fluid_relaxation_method.robust_startup.robust_startup_iterations = (
|
|
212
214
|
proto.robust_startup_iterations.value
|
|
213
215
|
)
|
|
216
|
+
elif proto.robust_startup == clientpb.ROBUST_STARTUP_AUTO:
|
|
217
|
+
self.fluid_relaxation_method.robust_startup = RobustStartupAuto()
|
|
214
218
|
elif proto.robust_startup == clientpb.ROBUST_STARTUP_OFF:
|
|
215
219
|
self.fluid_relaxation_method.robust_startup = RobustStartupOff()
|
|
216
220
|
self.fluid_relaxation_method.relaxation_flow = _from_ad_proto(proto.relax_flow)
|
|
@@ -54,7 +54,7 @@ class Turbulence(CodeRepr, ParamGroupWrapper[clientpb.Turbulence]):
|
|
|
54
54
|
"""Turbulence settings for a fluid flow physics solver."""
|
|
55
55
|
|
|
56
56
|
des_formulation: DesFormulation = field(default_factory=DdesVtm)
|
|
57
|
-
"Select a Detached Eddy Simulation (DES) formulation. Possible types: ``DdesVtm``, ``
|
|
57
|
+
"Select a Detached Eddy Simulation (DES) formulation. Possible types: ``DdesVtm``, ``Iddes``, ``Ddes`` from the ``des_formulation`` module."
|
|
58
58
|
sub_grid_scale_model: SubGridScaleModel | None = field(default_factory=Vreman)
|
|
59
59
|
"Sub-grid scale models available for Large Eddy Simulation (LES). Possible types: ``Smagorinsky``, ``Vreman``, ``Wale``, ``Sigma``, ``Amd`` from the ``sub_grid_scale_model`` module."
|
|
60
60
|
turbulent_prandtl_number: LcFloat = 0.85
|
|
@@ -124,7 +124,7 @@ class Fluid(CodeRepr, ParamGroupWrapper[clientpb.Fluid]):
|
|
|
124
124
|
periodic_pair: list[PeriodicPair] = field(default_factory=list)
|
|
125
125
|
"Defines the input options needed for periodic boundaries. We assume each periodic BC can have translational OR rotational periodicity. To transform a point on boundary A to its periodically matching point on boundary B, we first subtract the center of rotation from the point coordinates to get the distance vector from the center to the point of interest, then we apply rotation around the periodicity axis and add back the center of rotation to get the coordinates of the transformed point."
|
|
126
126
|
initialization: InitializationFluid = field(default_factory=FluidPrescribedValues)
|
|
127
|
-
"Type of initial condition for the field variables. Possible types: ``FluidPrescribedValues``, ``FluidFarfieldValues``, ``
|
|
127
|
+
"Type of initial condition for the field variables. Possible types: ``FluidPrescribedValues``, ``FluidFarfieldValues``, ``FluidExistingSolution`` from the ``initialization`` module."
|
|
128
128
|
physical_behavior: list[PhysicalBehavior] = field(default_factory=list)
|
|
129
129
|
"Physical behavior settings for a fluid flow physics solver."
|
|
130
130
|
porous_behavior: list[PorousBehavior] = field(default_factory=list)
|
|
@@ -42,4 +42,4 @@ class HeatImplicitRelaxation(HeatRelaxationMethod):
|
|
|
42
42
|
implicit_method: enum.ImplicitMethod = enum.ImplicitMethod.BACKWARD_EULER
|
|
43
43
|
"Scheme for implicit relaxation of the governing equations."
|
|
44
44
|
linear_solver_type: LinearSolverType = field(default_factory=GaussSeidel)
|
|
45
|
-
"Type of linear solver used for implicit relaxation. Possible types: ``GaussSeidel``, ``
|
|
45
|
+
"Type of linear solver used for implicit relaxation. Possible types: ``GaussSeidel``, ``KrylovAmg`` from the ``linear_solver_type`` module."
|
|
@@ -32,7 +32,7 @@ class SolutionControlsHeat(CodeRepr, ParamGroupWrapper[clientpb.SolutionControls
|
|
|
32
32
|
"""Solution controls for a heat transfer physics solver."""
|
|
33
33
|
|
|
34
34
|
heat_relaxation_method: HeatRelaxationMethod = field(default_factory=HeatImplicitRelaxation)
|
|
35
|
-
"Relaxation scheme for steady-state simulations or time implicit transient simulations. Possible types: ``HeatImplicitRelaxation
|
|
35
|
+
"Relaxation scheme for steady-state simulations or time implicit transient simulations. Possible types: ``HeatImplicitRelaxation`` from the ``heat_relaxation_method`` module."
|
|
36
36
|
preset: enum.SolutionControlsHeatPreset = (
|
|
37
37
|
enum.SolutionControlsHeatPreset.DEFAULT_SOLUTION_CONTROLS_HEAT
|
|
38
38
|
)
|
|
@@ -1,30 +1,165 @@
|
|
|
1
1
|
# File: python/sdk/luminarycloud/inference/inference.py
|
|
2
2
|
# Copyright 2025 Luminary Cloud, Inc. All Rights Reserved.
|
|
3
3
|
from datetime import datetime
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any, Callable
|
|
5
5
|
from json import loads as json_loads
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
import base64
|
|
8
|
+
import os
|
|
9
|
+
import urllib.request
|
|
6
10
|
|
|
7
11
|
from .._client import get_default_client
|
|
8
12
|
from .._helpers._timestamp_to_datetime import timestamp_to_datetime
|
|
9
13
|
from .._proto.api.v0.luminarycloud.inference import inference_pb2 as inferencepb
|
|
10
14
|
from .._proto.inferenceservice import inferenceservice_pb2 as inferenceservicepb
|
|
11
15
|
from .._wrapper import ProtoWrapper, ProtoWrapperBase
|
|
16
|
+
from ..project import Project
|
|
12
17
|
from .._helpers.warnings import experimental
|
|
18
|
+
from ..project import Project
|
|
19
|
+
from .._helpers import upload_file
|
|
20
|
+
from .._proto.upload import upload_pb2 as uploadpb
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class ExtAeroInferenceResult:
|
|
25
|
+
"""Result of an external aerodynamic inference job.
|
|
26
|
+
|
|
27
|
+
Attributes
|
|
28
|
+
----------
|
|
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.
|
|
37
|
+
"""
|
|
38
|
+
|
|
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
|
+
@experimental
|
|
52
|
+
def external_aero_inference(
|
|
53
|
+
project: Project, stl_file: str, checkpoint_file: str, config_name: str, stencil_size: int
|
|
54
|
+
) -> ExtAeroInferenceResult:
|
|
55
|
+
"""Performs an inference job returning external aerodynamic results.
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
project : Project
|
|
59
|
+
The project to which the inference files will be added.
|
|
60
|
+
stl_file : str
|
|
61
|
+
Fullpath the STL file to be used for inference.
|
|
62
|
+
checkpoint_file : str
|
|
63
|
+
Fullpath of the model to be used for inference.
|
|
64
|
+
config_name :str
|
|
65
|
+
Name of the configuration to be used for inference.
|
|
66
|
+
stencil_size :int
|
|
67
|
+
Size of the stencil to be used for inference.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
ExtAeroInferenceResult
|
|
71
|
+
Result of the external aerodynamic inference job.
|
|
72
|
+
|
|
73
|
+
warning:: This feature is experimental and may change or be removed without notice.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
result = perform_inference(project, stl_file, checkpoint_file, config_name, stencil_size)
|
|
77
|
+
return ExtAeroInferenceResult(result)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@experimental
|
|
81
|
+
def perform_inference(
|
|
82
|
+
project: Project, stl_file: str, checkpoint_file: str, config_name: str, stencil_size: int
|
|
83
|
+
) -> dict[str, Any]:
|
|
84
|
+
"""Creates an inference service job.
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
project : Project
|
|
88
|
+
The project to which the inference files will be added.
|
|
89
|
+
stl_file : str
|
|
90
|
+
Fullpath the STL file to be used for inference.
|
|
91
|
+
checkpoint_file : str
|
|
92
|
+
Fullpath of the model to be used for inference.
|
|
93
|
+
config_name :str
|
|
94
|
+
Name of the configuration to be used for inference.
|
|
95
|
+
stencil_size :int
|
|
96
|
+
Size of the stencil to be used for inference.
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
dict[str, Any]
|
|
101
|
+
Response from the server as key-value pairs.
|
|
102
|
+
|
|
103
|
+
warning:: This feature is experimental and may change or be removed without notice.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
client = get_default_client()
|
|
107
|
+
|
|
108
|
+
def upload_if_file(fname: str) -> str:
|
|
109
|
+
if os.path.exists(fname) and os.path.isfile(fname):
|
|
110
|
+
params = uploadpb.ResourceParams()
|
|
111
|
+
result = upload_file(client, project.id, params, fname)
|
|
112
|
+
return result[1].url
|
|
113
|
+
if fname.startswith("gs://"):
|
|
114
|
+
return fname
|
|
115
|
+
raise RuntimeError("Unsupported file for inference")
|
|
116
|
+
|
|
117
|
+
def future_file(url: str) -> Callable[[], dict[str, Any]]:
|
|
118
|
+
def download_file() -> dict[str, Any]:
|
|
119
|
+
with urllib.request.urlopen(url) as f:
|
|
120
|
+
serialized = f.read()
|
|
121
|
+
jsondata = json_loads(serialized)
|
|
122
|
+
data = base64.b64decode(jsondata["data"])
|
|
123
|
+
jsondata["data"] = data
|
|
124
|
+
return jsondata
|
|
125
|
+
|
|
126
|
+
return download_file
|
|
127
|
+
|
|
128
|
+
stl_url = upload_if_file(stl_file)
|
|
129
|
+
check_url = upload_if_file(checkpoint_file)
|
|
130
|
+
|
|
131
|
+
raw = start_inference_job(project, stl_url, check_url, config_name, stencil_size)
|
|
132
|
+
currated: dict[str, Any] = {}
|
|
133
|
+
for k, v in raw.items():
|
|
134
|
+
if isinstance(v, str) and v.startswith("https://"):
|
|
135
|
+
tmp = future_file(v)
|
|
136
|
+
if k.endswith("_url"):
|
|
137
|
+
currated[k[:-4]] = tmp
|
|
138
|
+
currated[k] = v
|
|
139
|
+
else:
|
|
140
|
+
currated[k] = tmp
|
|
141
|
+
currated[k + "_url"] = v
|
|
142
|
+
else:
|
|
143
|
+
currated[k] = v
|
|
144
|
+
return currated
|
|
13
145
|
|
|
14
146
|
|
|
15
147
|
@experimental
|
|
16
148
|
def start_inference_job(
|
|
149
|
+
project: Project,
|
|
17
150
|
stl_url: str,
|
|
18
|
-
|
|
151
|
+
checkpoint_url: str,
|
|
19
152
|
config_name: str,
|
|
20
153
|
stencil_size: int,
|
|
21
154
|
) -> dict[str, Any]:
|
|
22
155
|
"""Creates an inference service job.
|
|
23
156
|
Parameters
|
|
24
157
|
----------
|
|
158
|
+
project : Project
|
|
159
|
+
Reference to a project.
|
|
25
160
|
stl_url : str
|
|
26
161
|
URL of the STL file to be used for inference.
|
|
27
|
-
|
|
162
|
+
checkpoint_url : str
|
|
28
163
|
URL of the model to be used for inference.
|
|
29
164
|
config_name :str
|
|
30
165
|
Name of the configuration to be used for inference.
|
|
@@ -41,9 +176,10 @@ def start_inference_job(
|
|
|
41
176
|
|
|
42
177
|
req = inferencepb.CreateInferenceServiceJobRequest(
|
|
43
178
|
stl_url=stl_url,
|
|
44
|
-
|
|
179
|
+
checkpoint_url=checkpoint_url,
|
|
45
180
|
config_name=config_name,
|
|
46
181
|
stencil_size=stencil_size,
|
|
182
|
+
project_id=project.id,
|
|
47
183
|
)
|
|
48
184
|
|
|
49
185
|
res: inferencepb.CreateInferenceServiceJobResponse = (
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import tarfile
|
|
4
|
+
from typing import List, Optional, BinaryIO, cast
|
|
5
|
+
|
|
6
|
+
from .._client import get_default_client
|
|
7
|
+
from .._helpers.warnings import experimental
|
|
8
|
+
from .._helpers.download import download_solution_physics_ai as _download_solution_physics_ai
|
|
9
|
+
from ..enum.quantity_type import QuantityType
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@experimental
|
|
13
|
+
def _download_processed_solution_physics_ai( # noqa: F841
|
|
14
|
+
solution_id: str,
|
|
15
|
+
exclude_surfaces: Optional[List[str]] = None,
|
|
16
|
+
fill_holes: float = -1.0,
|
|
17
|
+
surface_fields_to_keep: Optional[List[QuantityType]] = None,
|
|
18
|
+
volume_fields_to_keep: Optional[List[QuantityType]] = None,
|
|
19
|
+
process_volume: bool = False,
|
|
20
|
+
single_precision: bool = True,
|
|
21
|
+
) -> tarfile.TarFile:
|
|
22
|
+
"""
|
|
23
|
+
Download solution data with physics AI processing applied.
|
|
24
|
+
|
|
25
|
+
Returns a compressed archive containing processed solution files including
|
|
26
|
+
merged surfaces (VTP/STL) and optionally volume data (VTU).
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
solution_id: ID of the solution to download
|
|
30
|
+
exclude_surfaces: List of surface names to exclude from processing
|
|
31
|
+
fill_holes: Sets the maximum size of the hole to be filled for the STL file, measured as the radius of the bounding circumsphere.
|
|
32
|
+
If fill_holes is negative or zero, no holes will be filled.
|
|
33
|
+
surface_fields_to_keep: List of QuantityType enum values for surface fields to keep in output.
|
|
34
|
+
If None, all available surface fields are included.
|
|
35
|
+
volume_fields_to_keep: List of QuantityType enum values for volume fields to keep in output.
|
|
36
|
+
If None, all available volume fields are included.
|
|
37
|
+
process_volume: Whether to process volume data
|
|
38
|
+
single_precision: Whether to use single precision for floating point fields
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
ValueError: If invalid field names are provided
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
stream = _download_solution_physics_ai(
|
|
45
|
+
get_default_client(),
|
|
46
|
+
solution_id,
|
|
47
|
+
exclude_surfaces=exclude_surfaces,
|
|
48
|
+
fill_holes=fill_holes,
|
|
49
|
+
surface_fields_to_keep=surface_fields_to_keep,
|
|
50
|
+
volume_fields_to_keep=volume_fields_to_keep,
|
|
51
|
+
process_volume=process_volume,
|
|
52
|
+
single_precision=single_precision,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
assert stream is not None, "Failed to download solution data"
|
|
56
|
+
return tarfile.open(
|
|
57
|
+
name=stream.filename,
|
|
58
|
+
fileobj=cast(BinaryIO, stream),
|
|
59
|
+
mode="r|gz",
|
|
60
|
+
)
|
luminarycloud/tables.py
CHANGED
|
@@ -121,11 +121,11 @@ def create_rectilinear_table(
|
|
|
121
121
|
table.header.record_label[-1].name = label
|
|
122
122
|
else:
|
|
123
123
|
table.header.record_label[-1].quantity = QuantityType(label).value
|
|
124
|
-
table.record.append(tablepb.Record())
|
|
125
124
|
|
|
126
125
|
types = data_types(table_type, len(header))
|
|
127
126
|
|
|
128
127
|
for row in rows:
|
|
128
|
+
record = tablepb.Record()
|
|
129
129
|
for i, val in enumerate(row):
|
|
130
130
|
# Axis coordinates are always adfloats and cannot be missing.
|
|
131
131
|
if i == 0 and has_axis(table_type):
|
|
@@ -133,25 +133,23 @@ def create_rectilinear_table(
|
|
|
133
133
|
table.axis[0].coordinate[-1].adfloat.value = float(val)
|
|
134
134
|
continue
|
|
135
135
|
|
|
136
|
-
j = i - has_axis(table_type)
|
|
137
136
|
if val == "":
|
|
138
137
|
if allow_missing_entries(table_type):
|
|
139
|
-
|
|
140
|
-
tablepb.Record.Entry(empty=tablepb.Record.Entry.Empty())
|
|
141
|
-
)
|
|
138
|
+
record.entry.append(tablepb.Record.Entry(empty=tablepb.Record.Entry.Empty()))
|
|
142
139
|
pass
|
|
143
140
|
else:
|
|
144
141
|
raise ValueError(f"Entry {i} in row {row} is missing.")
|
|
145
142
|
continue
|
|
146
143
|
|
|
147
|
-
|
|
144
|
+
record.entry.append(tablepb.Record.Entry())
|
|
148
145
|
try:
|
|
149
146
|
if types[i] == float:
|
|
150
|
-
|
|
147
|
+
record.entry[-1].adfloat.value = float(val)
|
|
151
148
|
else:
|
|
152
|
-
|
|
149
|
+
record.entry[-1].string = val
|
|
153
150
|
except ValueError:
|
|
154
151
|
raise ValueError(f"Expected type {types[i]} for entry {i} in row {row}.")
|
|
152
|
+
table.record.append(record)
|
|
155
153
|
|
|
156
154
|
return table
|
|
157
155
|
|
|
@@ -381,12 +381,11 @@ class DataExtractor:
|
|
|
381
381
|
simulation = get_simulation(self._solution.simulation_id)
|
|
382
382
|
mesh_meta = get_mesh_metadata(simulation.mesh_id)
|
|
383
383
|
mesh = get_mesh(simulation.mesh_id)
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
except NotFoundError:
|
|
384
|
+
geo_ver = mesh.geometry_version()
|
|
385
|
+
if geo_ver is None:
|
|
387
386
|
self._has_tags = False
|
|
388
|
-
|
|
389
|
-
|
|
387
|
+
else:
|
|
388
|
+
geom = geo_ver.geometry()
|
|
390
389
|
|
|
391
390
|
self._surface_ids: List[str] = []
|
|
392
391
|
for zone in mesh_meta.zones:
|
luminarycloud/vis/display.py
CHANGED
|
@@ -4,10 +4,11 @@ from luminarycloud.enum import Representation, ColorMapPreset, FieldComponent, V
|
|
|
4
4
|
from .._proto.api.v0.luminarycloud.vis import vis_pb2
|
|
5
5
|
from typing import Optional
|
|
6
6
|
import luminarycloud.enum.quantity_type as quantity_type
|
|
7
|
+
from .._helpers._code_representation import CodeRepr
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
@dc.dataclass
|
|
10
|
-
class Field:
|
|
11
|
+
class Field(CodeRepr):
|
|
11
12
|
"""
|
|
12
13
|
The field controls the field displayed on the object. If the field doesn't
|
|
13
14
|
exist, we show a solid color.
|
|
@@ -16,8 +17,8 @@ class Field:
|
|
|
16
17
|
|
|
17
18
|
"""
|
|
18
19
|
|
|
19
|
-
quantity: VisQuantity = VisQuantity.
|
|
20
|
-
"""The quantity to color by."""
|
|
20
|
+
quantity: VisQuantity = VisQuantity.NONE
|
|
21
|
+
"""The quantity to color by. Default: NONE."""
|
|
21
22
|
component: FieldComponent = FieldComponent.MAGNITUDE
|
|
22
23
|
"""
|
|
23
24
|
The component of the field to use, applicable to vector fields. If the field is a
|
|
@@ -45,9 +46,25 @@ class Field:
|
|
|
45
46
|
self.component = FieldComponent(field.component)
|
|
46
47
|
# If its a scalar, just ignore the component.
|
|
47
48
|
|
|
49
|
+
def _to_code(self, hide_defaults: bool = True, use_tmp_objs: bool = True) -> str:
|
|
50
|
+
# We have to handle this case specially because we need to omit the field
|
|
51
|
+
# component if the quantity is a scalar. Otherwise, it could confuse the user.
|
|
52
|
+
# Also we omit the instantiation line because all classes that use a Field already
|
|
53
|
+
# instantiate a default one in their own constructor. (Hopefully that invariant continues to
|
|
54
|
+
# hold)
|
|
55
|
+
def enum_to_string(val: VisQuantity | FieldComponent) -> str:
|
|
56
|
+
str_val = val.__repr__()
|
|
57
|
+
return str_val.split(": ")[0][1:]
|
|
58
|
+
|
|
59
|
+
code = ""
|
|
60
|
+
code += f".quantity = {enum_to_string(self.quantity)}\n"
|
|
61
|
+
if quantity_type._is_vector(self.quantity):
|
|
62
|
+
code += f".component = {enum_to_string(self.component)}\n"
|
|
63
|
+
return code
|
|
64
|
+
|
|
48
65
|
|
|
49
66
|
@dc.dataclass
|
|
50
|
-
class DisplayAttributes:
|
|
67
|
+
class DisplayAttributes(CodeRepr):
|
|
51
68
|
"""
|
|
52
69
|
Display attributes specify how objects such as meshes, geometries, and
|
|
53
70
|
filters appear in the scene.
|
|
@@ -86,7 +103,7 @@ class DisplayAttributes:
|
|
|
86
103
|
|
|
87
104
|
|
|
88
105
|
@dc.dataclass
|
|
89
|
-
class DataRange:
|
|
106
|
+
class DataRange(CodeRepr):
|
|
90
107
|
"""
|
|
91
108
|
The data range represents a range of values. Ranges are only valid if the
|
|
92
109
|
max value is greater than the or equal to the min_value. The default is
|
|
@@ -106,7 +123,7 @@ class DataRange:
|
|
|
106
123
|
|
|
107
124
|
|
|
108
125
|
@dc.dataclass
|
|
109
|
-
class ColorMapAppearance:
|
|
126
|
+
class ColorMapAppearance(CodeRepr):
|
|
110
127
|
"""
|
|
111
128
|
ColorMapAppearance controls how the color maps appear in the image, including
|
|
112
129
|
visibility, position and size.
|
|
@@ -141,7 +158,7 @@ class ColorMapAppearance:
|
|
|
141
158
|
|
|
142
159
|
|
|
143
160
|
@dc.dataclass
|
|
144
|
-
class ColorMap:
|
|
161
|
+
class ColorMap(CodeRepr):
|
|
145
162
|
"""
|
|
146
163
|
The color map allows user control over how field values are mapped to
|
|
147
164
|
colors. Color maps are assigned to fields (e.g., the quantity and component)
|
|
@@ -213,10 +230,8 @@ class ColorMap:
|
|
|
213
230
|
return res
|
|
214
231
|
|
|
215
232
|
def _from_proto(self, color_map: vis_pb2.ColorMap) -> None:
|
|
216
|
-
self.field
|
|
217
|
-
|
|
218
|
-
quantity=VisQuantity(color_map.field.quantity_typ),
|
|
219
|
-
)
|
|
233
|
+
self.field._from_proto(color_map.field)
|
|
234
|
+
|
|
220
235
|
if color_map.HasField("range"):
|
|
221
236
|
self.data_range = DataRange(
|
|
222
237
|
min_value=color_map.range.min,
|