luminarycloud 0.15.5__py3-none-any.whl → 0.16.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.
- luminarycloud/_client/client.py +5 -0
- luminarycloud/_helpers/__init__.py +1 -0
- luminarycloud/_helpers/_code_representation.py +21 -4
- luminarycloud/_helpers/download.py +67 -1
- 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 +194 -7
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.pyi +407 -5
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.py +171 -0
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.pyi +64 -0
- luminarycloud/_proto/api/v0/luminarycloud/upload/upload_pb2.py +4 -2
- luminarycloud/_proto/api/v0/luminarycloud/upload/upload_pb2_grpc.py +34 -0
- luminarycloud/_proto/api/v0/luminarycloud/upload/upload_pb2_grpc.pyi +12 -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/assistant/assistant_pb2.py +82 -61
- luminarycloud/_proto/assistant/assistant_pb2.pyi +40 -0
- luminarycloud/_proto/assistant/assistant_pb2_grpc.py +34 -0
- luminarycloud/_proto/assistant/assistant_pb2_grpc.pyi +12 -0
- luminarycloud/_proto/base/base_pb2.py +7 -6
- luminarycloud/_proto/base/base_pb2.pyi +4 -0
- luminarycloud/_proto/client/simulation_pb2.py +351 -351
- luminarycloud/_proto/client/simulation_pb2.pyi +105 -97
- luminarycloud/_proto/geometry/geometry_pb2.py +68 -68
- luminarycloud/_proto/geometry/geometry_pb2.pyi +15 -7
- luminarycloud/_proto/hexmesh/hexmesh_pb2.py +40 -15
- luminarycloud/_proto/hexmesh/hexmesh_pb2.pyi +58 -1
- luminarycloud/_proto/inferenceservice/inferenceservice_pb2.py +11 -11
- luminarycloud/_proto/inferenceservice/inferenceservice_pb2.pyi +12 -4
- luminarycloud/_proto/lcstatus/codes_pb2.py +3 -2
- luminarycloud/_proto/lcstatus/codes_pb2.pyi +4 -0
- 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 +27 -7
- luminarycloud/_proto/upload/upload_pb2.pyi +31 -0
- luminarycloud/enum/quantity_type.py +19 -0
- luminarycloud/enum/tables.py +1 -0
- luminarycloud/enum/vis_enums.py +20 -0
- luminarycloud/feature_modification.py +6 -7
- luminarycloud/geometry.py +24 -0
- luminarycloud/geometry_version.py +23 -0
- luminarycloud/mesh.py +8 -1
- 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/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 +6 -2
- luminarycloud/params/simulation/physics/fluid/solution_controls_fluid_.py +4 -0
- luminarycloud/params/simulation/simulation_param_.py +6 -0
- luminarycloud/physics_ai/__init__.py +4 -0
- luminarycloud/physics_ai/inference.py +140 -4
- luminarycloud/physics_ai/solution.py +60 -0
- luminarycloud/project.py +9 -7
- luminarycloud/simulation_param.py +29 -15
- luminarycloud/simulation_template.py +14 -10
- luminarycloud/tables.py +11 -12
- luminarycloud/thirdparty/__init__.py +12 -0
- luminarycloud/thirdparty/onshape.py +170 -0
- luminarycloud/vis/__init__.py +2 -0
- luminarycloud/vis/data_extraction.py +44 -6
- luminarycloud/vis/display.py +26 -11
- luminarycloud/vis/filters.py +226 -67
- luminarycloud/vis/primitives.py +3 -2
- luminarycloud/vis/visualization.py +198 -41
- luminarycloud/volume_selection.py +2 -2
- {luminarycloud-0.15.5.dist-info → luminarycloud-0.16.1.dist-info}/METADATA +6 -6
- {luminarycloud-0.15.5.dist-info → luminarycloud-0.16.1.dist-info}/RECORD +77 -73
- {luminarycloud-0.15.5.dist-info → luminarycloud-0.16.1.dist-info}/WHEEL +0 -0
|
@@ -12,7 +12,7 @@ from google.protobuf.internal.containers import RepeatedScalarFieldContainer
|
|
|
12
12
|
class FeatureOperationType(Enum):
|
|
13
13
|
"""Enum representing the type of operation in a Feature."""
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
IMPORT_GEOMETRY = auto()
|
|
16
16
|
CREATE = auto()
|
|
17
17
|
DELETE = auto()
|
|
18
18
|
UNION = auto()
|
|
@@ -73,7 +73,7 @@ def get_operation_type(feature: gpb.Feature) -> FeatureOperationType:
|
|
|
73
73
|
|
|
74
74
|
# Base operation map for simple one-to-one mappings
|
|
75
75
|
base_operation_map = {
|
|
76
|
-
"
|
|
76
|
+
"import_geometry": FeatureOperationType.IMPORT_GEOMETRY,
|
|
77
77
|
"create": FeatureOperationType.CREATE,
|
|
78
78
|
"delete": FeatureOperationType.DELETE,
|
|
79
79
|
"imprint": FeatureOperationType.IMPRINT,
|
|
@@ -165,21 +165,20 @@ def modify_import(
|
|
|
165
165
|
Returns:
|
|
166
166
|
A gpb.Modification object
|
|
167
167
|
"""
|
|
168
|
-
if get_operation_type(feature) != FeatureOperationType.
|
|
168
|
+
if get_operation_type(feature) != FeatureOperationType.IMPORT_GEOMETRY:
|
|
169
169
|
raise ValueError("Feature is not an import operation")
|
|
170
170
|
|
|
171
171
|
feature_copy = deepcopy(feature)
|
|
172
|
-
import_op = getattr(feature_copy, "import")
|
|
173
172
|
|
|
174
173
|
if geometry_url is not None:
|
|
175
174
|
# TODO(chiodi): Handle upload of file here.
|
|
176
|
-
|
|
175
|
+
feature_copy.import_geometry.geometry_url = geometry_url
|
|
177
176
|
|
|
178
177
|
if scaling is not None:
|
|
179
|
-
|
|
178
|
+
feature_copy.import_geometry.scaling = scaling
|
|
180
179
|
|
|
181
180
|
if force_discrete is not None:
|
|
182
|
-
|
|
181
|
+
feature_copy.import_geometry.force_discrete = force_discrete
|
|
183
182
|
|
|
184
183
|
return gpb.Modification(
|
|
185
184
|
mod_type=gpb.Modification.ModificationType.MODIFICATION_TYPE_UPDATE_FEATURE,
|
luminarycloud/geometry.py
CHANGED
|
@@ -554,6 +554,30 @@ class Geometry(ProtoWrapperBase):
|
|
|
554
554
|
res: geometrypb.GetGeometryResponse = get_default_client().GetGeometry(req)
|
|
555
555
|
self._proto = res.geometry
|
|
556
556
|
|
|
557
|
+
def to_code(self) -> str:
|
|
558
|
+
"""
|
|
559
|
+
Returns the python code that creates (from scratch) an identical geometry.
|
|
560
|
+
If the geometry has been modified, the code will be generated for the latest version of the
|
|
561
|
+
geometry.
|
|
562
|
+
|
|
563
|
+
Returns
|
|
564
|
+
-------
|
|
565
|
+
str
|
|
566
|
+
The SDK code that can be used to recreate this geometry.
|
|
567
|
+
|
|
568
|
+
Examples
|
|
569
|
+
--------
|
|
570
|
+
>>> geometry = lc.get_geometry("geometry-id")
|
|
571
|
+
>>> python_code = geometry.to_code()
|
|
572
|
+
>>> print(python_code)
|
|
573
|
+
"""
|
|
574
|
+
req = geometrypb.GetSdkCodeRequest(
|
|
575
|
+
geometry_id=self.id,
|
|
576
|
+
geometry_version_id="", # Use the latest version of the geometry by default
|
|
577
|
+
)
|
|
578
|
+
res: geometrypb.GetSdkCodeResponse = get_default_client().GetSdkCode(req)
|
|
579
|
+
return res.sdk_code
|
|
580
|
+
|
|
557
581
|
|
|
558
582
|
def get_geometry(id: str) -> Geometry:
|
|
559
583
|
"""
|
|
@@ -126,6 +126,29 @@ class GeometryVersion(ProtoWrapperBase):
|
|
|
126
126
|
)
|
|
127
127
|
return list(res.features_issues)
|
|
128
128
|
|
|
129
|
+
def to_code(self) -> str:
|
|
130
|
+
"""
|
|
131
|
+
Returns the Python code that creates (from scratch) an identical geometry of
|
|
132
|
+
this particular version.
|
|
133
|
+
|
|
134
|
+
Returns
|
|
135
|
+
-------
|
|
136
|
+
str
|
|
137
|
+
The SDK code that can be used to recreate this specific geometry version.
|
|
138
|
+
|
|
139
|
+
Examples
|
|
140
|
+
--------
|
|
141
|
+
>>> geometry_version = lc.get_geometry_version("version-id")
|
|
142
|
+
>>> python_code = geometry_version.to_code()
|
|
143
|
+
>>> print(python_code)
|
|
144
|
+
"""
|
|
145
|
+
req = geometrypb.GetSdkCodeRequest(
|
|
146
|
+
geometry_id=self.geometry_id,
|
|
147
|
+
geometry_version_id=self.id,
|
|
148
|
+
)
|
|
149
|
+
res: geometrypb.GetSdkCodeResponse = get_default_client().GetSdkCode(req)
|
|
150
|
+
return res.sdk_code
|
|
151
|
+
|
|
129
152
|
|
|
130
153
|
def get_geometry_version(id: str) -> GeometryVersion:
|
|
131
154
|
"""
|
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(
|
|
@@ -22,7 +22,7 @@ from luminarycloud.params.simulation._lib import ParamGroupWrapper, create_uniqu
|
|
|
22
22
|
class Adjoint(CodeRepr, ParamGroupWrapper[clientpb.Adjoint]):
|
|
23
23
|
"""Settings for adjoint sensitivity analysis."""
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
_output: Any | None = None
|
|
26
26
|
"Function to differentiate."
|
|
27
27
|
surfaces: list[str] = field(default_factory=list)
|
|
28
28
|
""
|
|
@@ -33,8 +33,8 @@ class Adjoint(CodeRepr, ParamGroupWrapper[clientpb.Adjoint]):
|
|
|
33
33
|
|
|
34
34
|
def _to_proto(self) -> clientpb.Adjoint:
|
|
35
35
|
_proto = clientpb.Adjoint()
|
|
36
|
-
if self.
|
|
37
|
-
_proto.adjoint_output.CopyFrom(self.
|
|
36
|
+
if self._output is not None:
|
|
37
|
+
_proto.adjoint_output.CopyFrom(self._output)
|
|
38
38
|
if self.surfaces is not None:
|
|
39
39
|
_proto.surfaces.extend(self.surfaces)
|
|
40
40
|
if self.deformed_coords_id is not None:
|
|
@@ -44,7 +44,7 @@ class Adjoint(CodeRepr, ParamGroupWrapper[clientpb.Adjoint]):
|
|
|
44
44
|
return _proto
|
|
45
45
|
|
|
46
46
|
def _from_proto(self, proto: clientpb.Adjoint) -> None:
|
|
47
|
-
self.
|
|
47
|
+
self._output = proto.adjoint_output
|
|
48
48
|
self.surfaces.extend(proto.surfaces)
|
|
49
49
|
self.deformed_coords_id = proto.deformed_coords_id
|
|
50
50
|
self.primal_simulation_id = proto.primal_simulation_id
|
|
@@ -85,7 +85,7 @@ class MaterialFluid(CodeRepr, ParamGroupWrapper[clientpb.MaterialFluid]):
|
|
|
85
85
|
"Model for the laminar thermal conductivity of a fluid. Possible types: ``PrescribedPrandtlNumber``, ``PrescribedConductivity``, ``TemperatureDependentConductivity`` from the ``thermal_conductivity_model`` module."
|
|
86
86
|
boussinesq_approximation: BoussinesqApproximation = field(default_factory=BoussinesqOn)
|
|
87
87
|
"Introduce a body force due to thermal expansion without modifying the material density. Possible types: ``BoussinesqOff``, ``BoussinesqOn`` from the ``boussinesq_approximation`` module."
|
|
88
|
-
preset: enum.MaterialFluidPreset = enum.MaterialFluidPreset.
|
|
88
|
+
preset: enum.MaterialFluidPreset = enum.MaterialFluidPreset.STANDARD_AIR
|
|
89
89
|
"Select a predefined set of material properties or allow a custom set of properties."
|
|
90
90
|
viscosity_model: ViscosityModel = field(default_factory=Sutherland)
|
|
91
91
|
"Models available for the dynamic viscosity of the fluid. Possible types: ``Sutherland``, ``PrescribedViscosity``, ``TemperatureDependentViscosity`` from the ``viscosity_model`` module."
|
|
@@ -30,7 +30,7 @@ class MaterialSolid(CodeRepr, ParamGroupWrapper[clientpb.MaterialSolid]):
|
|
|
30
30
|
"The thermal conductivity of the material."
|
|
31
31
|
thermal_conductivity_table: RectilinearTable | None = None
|
|
32
32
|
"Correlation between thermal conductivity and temperature."
|
|
33
|
-
preset: enum.MaterialSolidPreset = enum.MaterialSolidPreset.
|
|
33
|
+
preset: enum.MaterialSolidPreset = enum.MaterialSolidPreset.ALUMINUM
|
|
34
34
|
"Select a predefined set of material properties or allow a custom set of properties."
|
|
35
35
|
|
|
36
36
|
def _to_proto(self) -> clientpb.MaterialSolid:
|
|
@@ -22,7 +22,7 @@ from luminarycloud.params.simulation._lib import ParamGroupWrapper, create_uniqu
|
|
|
22
22
|
class Output(CodeRepr, ParamGroupWrapper[clientpb.Output]):
|
|
23
23
|
"""Solution output settings."""
|
|
24
24
|
|
|
25
|
-
iters_per_output: int =
|
|
25
|
+
iters_per_output: int = 0
|
|
26
26
|
"Number of (pseudo) timesteps between successive full solution output. If ≤0, only the final solution is written."
|
|
27
27
|
include_residuals: bool = False
|
|
28
28
|
"Include the residuals for each equation in the volume solution."
|
|
@@ -19,6 +19,10 @@ from luminarycloud.params.simulation._lib import ParamGroupWrapper, create_uniqu
|
|
|
19
19
|
|
|
20
20
|
from luminarycloud.params.simulation.physics.fluid.initialization_fluid_ import InitializationFluid
|
|
21
21
|
from luminarycloud.params.simulation.physics.fluid.initialization_fluid_ import *
|
|
22
|
+
from luminarycloud.params.simulation.physics.fluid.initialization.turbulence_initialization_ import (
|
|
23
|
+
TurbulenceInitialization,
|
|
24
|
+
)
|
|
25
|
+
from luminarycloud.params.simulation.physics.fluid.initialization.turbulence_initialization_ import *
|
|
22
26
|
|
|
23
27
|
|
|
24
28
|
@dataclass(kw_only=True)
|
|
@@ -27,16 +31,40 @@ class FluidExistingSolution(InitializationFluid):
|
|
|
27
31
|
|
|
28
32
|
solution_id: str = ""
|
|
29
33
|
"ID for the existing solution to use for initialization."
|
|
34
|
+
turbulence: TurbulenceInitialization = field(default_factory=TurbulenceInitialization)
|
|
35
|
+
""
|
|
30
36
|
|
|
31
37
|
def _to_proto(self) -> clientpb.InitializationFluid:
|
|
32
38
|
_proto = super()._to_proto()
|
|
33
39
|
_proto.initialization_type = clientpb.InitializationType.EXISTING_SOLUTION
|
|
34
40
|
if self.solution_id is not None:
|
|
35
41
|
_proto.existing_solution_id = self.solution_id
|
|
42
|
+
_proto.turbulent_variable_initialization_type_sa = self.turbulence.spalart_allmaras.value
|
|
43
|
+
_proto.turbulent_variable_initialization_type_komega = self.turbulence.komega.value
|
|
44
|
+
_proto.init_turbulent_viscosity_ratio.CopyFrom(
|
|
45
|
+
_to_ad_proto(self.turbulence.viscosity_ratio)
|
|
46
|
+
)
|
|
47
|
+
_proto.init_turbulent_viscosity.CopyFrom(_to_ad_proto(self.turbulence.viscosity))
|
|
48
|
+
_proto.init_turbulence_intensity.CopyFrom(_to_ad_proto(self.turbulence.intensity))
|
|
49
|
+
_proto.uniform_nu_tilde.CopyFrom(_to_ad_proto(self.turbulence.sa_variable))
|
|
50
|
+
_proto.uniform_tke.CopyFrom(_to_ad_proto(self.turbulence.tke))
|
|
51
|
+
_proto.uniform_omega.CopyFrom(_to_ad_proto(self.turbulence.omega))
|
|
36
52
|
return _proto
|
|
37
53
|
|
|
38
54
|
def _from_proto(self, proto: clientpb.InitializationFluid) -> None:
|
|
39
55
|
super()._from_proto(proto)
|
|
40
56
|
assert proto.initialization_type == clientpb.InitializationType.EXISTING_SOLUTION
|
|
41
57
|
self.solution_id = proto.existing_solution_id
|
|
58
|
+
self.turbulence.spalart_allmaras = enum.TurbulentVariableInitializationTypeSa(
|
|
59
|
+
proto.turbulent_variable_initialization_type_sa
|
|
60
|
+
)
|
|
61
|
+
self.turbulence.komega = enum.TurbulentVariableInitializationTypeKomega(
|
|
62
|
+
proto.turbulent_variable_initialization_type_komega
|
|
63
|
+
)
|
|
64
|
+
self.turbulence.viscosity_ratio = _from_ad_proto(proto.init_turbulent_viscosity_ratio)
|
|
65
|
+
self.turbulence.viscosity = _from_ad_proto(proto.init_turbulent_viscosity)
|
|
66
|
+
self.turbulence.intensity = _from_ad_proto(proto.init_turbulence_intensity)
|
|
67
|
+
self.turbulence.sa_variable = _from_ad_proto(proto.uniform_nu_tilde)
|
|
68
|
+
self.turbulence.tke = _from_ad_proto(proto.uniform_tke)
|
|
69
|
+
self.turbulence.omega = _from_ad_proto(proto.uniform_omega)
|
|
42
70
|
return None
|
|
@@ -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
|
)
|
|
@@ -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)
|
|
@@ -77,6 +77,8 @@ class SimulationParam(CodeRepr, ParamGroupWrapper[clientpb.SimulationParam]):
|
|
|
77
77
|
"Body frame."
|
|
78
78
|
surface_name: dict[str, SurfaceName] = field(default_factory=dict)
|
|
79
79
|
"Surface name map."
|
|
80
|
+
_table_references: dict[str, Any] = field(default_factory=dict)
|
|
81
|
+
"Solution inputs - metadata for general n-dimensional rectilinear grid data (Monitor points, radial distribution, blade geometry, airfoil performance)."
|
|
80
82
|
output: Output = field(default_factory=Output)
|
|
81
83
|
"Solution output settings."
|
|
82
84
|
entity_relationships: EntityRelationships = field(default_factory=EntityRelationships)
|
|
@@ -115,6 +117,9 @@ class SimulationParam(CodeRepr, ParamGroupWrapper[clientpb.SimulationParam]):
|
|
|
115
117
|
if self.surface_name is not None:
|
|
116
118
|
for k, v in self.surface_name.items():
|
|
117
119
|
_proto.surface_name[k].CopyFrom(v._to_proto())
|
|
120
|
+
if self._table_references is not None:
|
|
121
|
+
for k, v in self._table_references.items():
|
|
122
|
+
_proto.table_references[k].CopyFrom(v)
|
|
118
123
|
if self.output is not None:
|
|
119
124
|
_proto.output.CopyFrom(self.output._to_proto())
|
|
120
125
|
if self.entity_relationships is not None:
|
|
@@ -140,6 +145,7 @@ class SimulationParam(CodeRepr, ParamGroupWrapper[clientpb.SimulationParam]):
|
|
|
140
145
|
self.monitor_plane = [MonitorPlane.from_proto(v) for v in proto.monitor_plane]
|
|
141
146
|
self.body_frame = BodyFrame.from_proto(proto.body_frame)
|
|
142
147
|
self.surface_name = {k: SurfaceName.from_proto(v) for k, v in proto.surface_name.items()}
|
|
148
|
+
self._table_references.update(proto.table_references)
|
|
143
149
|
self.output = Output.from_proto(proto.output)
|
|
144
150
|
self.entity_relationships = EntityRelationships.from_proto(proto.entity_relationships)
|
|
145
151
|
self.adaptive_mesh_refinement = AdaptiveMeshRefinement.from_proto(
|
|
@@ -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/project.py
CHANGED
|
@@ -39,6 +39,7 @@ from ._proto.api.v0.luminarycloud.simulation_template import (
|
|
|
39
39
|
simulation_template_pb2 as simtemplatepb,
|
|
40
40
|
)
|
|
41
41
|
from ._proto.client import simulation_pb2 as clientpb
|
|
42
|
+
from ._proto.table import table_pb2 as tablepb
|
|
42
43
|
from ._proto.hexmesh import hexmesh_pb2 as hexmeshpb
|
|
43
44
|
from ._proto.upload import upload_pb2 as uploadpb
|
|
44
45
|
from ._wrapper import ProtoWrapper, ProtoWrapperBase
|
|
@@ -440,13 +441,14 @@ class Project(ProtoWrapperBase):
|
|
|
440
441
|
raise RuntimeError("The table upload failed.")
|
|
441
442
|
|
|
442
443
|
# Update the simulation template with the new table reference.
|
|
443
|
-
params:
|
|
444
|
-
params.
|
|
445
|
-
params.
|
|
446
|
-
params.
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
444
|
+
params: SimulationParam = simulation_template.get_parameters()
|
|
445
|
+
params._table_references[name] = tablepb.Metadata()
|
|
446
|
+
params._table_references[name].url = url
|
|
447
|
+
params._table_references[name].table_type = table_type.value
|
|
448
|
+
params._table_references[name].uploaded_filename = uploaded_filename
|
|
449
|
+
simulation_template.update(parameters=params)
|
|
450
|
+
# The name is lost in to/from proto conversions so make it equal to the id for consistency.
|
|
451
|
+
return RectilinearTable(id=name, name=name, table_type=table_type)
|
|
450
452
|
|
|
451
453
|
@experimental
|
|
452
454
|
def set_surface_deformation(
|