luminarycloud 0.19.0__py3-none-any.whl → 0.20.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.
Files changed (38) hide show
  1. luminarycloud/_client/client.py +2 -0
  2. luminarycloud/_helpers/_wait_for_mesh.py +6 -5
  3. luminarycloud/_helpers/_wait_for_simulation.py +3 -3
  4. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2.py +83 -25
  5. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2.pyi +214 -0
  6. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2_grpc.py +34 -0
  7. luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2_grpc.pyi +12 -0
  8. luminarycloud/_proto/api/v0/luminarycloud/simulation/simulation_pb2.py +60 -60
  9. luminarycloud/_proto/api/v0/luminarycloud/simulation/simulation_pb2.pyi +5 -1
  10. luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2.py +77 -27
  11. luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2.pyi +85 -0
  12. luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2_grpc.py +66 -0
  13. luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2_grpc.pyi +20 -0
  14. luminarycloud/_proto/client/simulation_pb2.py +342 -331
  15. luminarycloud/_proto/client/simulation_pb2.pyi +37 -3
  16. luminarycloud/_proto/physicsaitrainingservice/physicsaitrainingservice_pb2.py +29 -0
  17. luminarycloud/_proto/physicsaitrainingservice/physicsaitrainingservice_pb2.pyi +7 -0
  18. luminarycloud/_proto/physicsaitrainingservice/physicsaitrainingservice_pb2_grpc.py +70 -0
  19. luminarycloud/_proto/physicsaitrainingservice/physicsaitrainingservice_pb2_grpc.pyi +30 -0
  20. luminarycloud/exceptions.py +7 -1
  21. luminarycloud/geometry.py +3 -1
  22. luminarycloud/mesh.py +1 -2
  23. luminarycloud/params/enum/_enum_wrappers.py +25 -0
  24. luminarycloud/params/simulation/material/material_solid_.py +15 -1
  25. luminarycloud/physics_ai/architectures.py +58 -0
  26. luminarycloud/physics_ai/training_jobs.py +37 -0
  27. luminarycloud/pipelines/api.py +8 -12
  28. luminarycloud/simulation.py +3 -2
  29. luminarycloud/simulation_template.py +2 -1
  30. luminarycloud/vis/__init__.py +15 -0
  31. luminarycloud/vis/data_extraction.py +20 -4
  32. luminarycloud/vis/interactive_report.py +124 -0
  33. luminarycloud/vis/interactive_scene.py +29 -2
  34. luminarycloud/vis/report.py +98 -0
  35. luminarycloud/vis/visualization.py +67 -5
  36. {luminarycloud-0.19.0.dist-info → luminarycloud-0.20.0.dist-info}/METADATA +1 -1
  37. {luminarycloud-0.19.0.dist-info → luminarycloud-0.20.0.dist-info}/RECORD +38 -31
  38. {luminarycloud-0.19.0.dist-info → luminarycloud-0.20.0.dist-info}/WHEEL +0 -0
@@ -599,6 +599,31 @@ TEMPERATURE_DEPENDENT_LAMINAR_VISCOSITY: LaminarViscosityModelNewtonian.ValueTyp
599
599
  """Tabulated dynamic viscosity values vs temperature."""
600
600
  global___LaminarViscosityModelNewtonian = LaminarViscosityModelNewtonian
601
601
 
602
+ class _ThermalConductivityModelSolid:
603
+ ValueType = typing.NewType("ValueType", builtins.int)
604
+ V: typing_extensions.TypeAlias = ValueType
605
+
606
+ class _ThermalConductivityModelSolidEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_ThermalConductivityModelSolid.ValueType], builtins.type): # noqa: F821
607
+ DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
608
+ INVALID_THERMAL_CONDUCTIVITY_MODEL_SOLID: _ThermalConductivityModelSolid.ValueType # 0
609
+ ISOTROPIC_CONDUCTIVITY: _ThermalConductivityModelSolid.ValueType # 52316
610
+ """Equal thermal conductivity in all directions."""
611
+ ORTHOTROPIC_CONDUCTIVITY: _ThermalConductivityModelSolid.ValueType # 60601
612
+ """Different thermal conductivity along each axis of the frames to which
613
+ the volumes of this material are assigned.
614
+ """
615
+
616
+ class ThermalConductivityModelSolid(_ThermalConductivityModelSolid, metaclass=_ThermalConductivityModelSolidEnumTypeWrapper): ...
617
+
618
+ INVALID_THERMAL_CONDUCTIVITY_MODEL_SOLID: ThermalConductivityModelSolid.ValueType # 0
619
+ ISOTROPIC_CONDUCTIVITY: ThermalConductivityModelSolid.ValueType # 52316
620
+ """Equal thermal conductivity in all directions."""
621
+ ORTHOTROPIC_CONDUCTIVITY: ThermalConductivityModelSolid.ValueType # 60601
622
+ """Different thermal conductivity along each axis of the frames to which
623
+ the volumes of this material are assigned.
624
+ """
625
+ global___ThermalConductivityModelSolid = ThermalConductivityModelSolid
626
+
602
627
  class _MaterialSolidPreset:
603
628
  ValueType = typing.NewType("ValueType", builtins.int)
604
629
  V: typing_extensions.TypeAlias = ValueType
@@ -3086,7 +3111,9 @@ class MaterialSolid(google.protobuf.message.Message):
3086
3111
 
3087
3112
  CONSTANT_DENSITY_VALUE_SOLID_FIELD_NUMBER: builtins.int
3088
3113
  SPECIFIC_HEAT_CP_SOLID_FIELD_NUMBER: builtins.int
3114
+ THERMAL_CONDUCTIVITY_MODEL_SOLID_FIELD_NUMBER: builtins.int
3089
3115
  THERMAL_CONDUCTIVITY_CONSTANT_SOLID_FIELD_NUMBER: builtins.int
3116
+ THERMAL_CONDUCTIVITY_ORTHOTROPIC_SOLID_FIELD_NUMBER: builtins.int
3090
3117
  THERMAL_CONDUCTIVITY_TABLE_DATA_FIELD_NUMBER: builtins.int
3091
3118
  MATERIAL_SOLID_PRESET_FIELD_NUMBER: builtins.int
3092
3119
  @property
@@ -3094,10 +3121,15 @@ class MaterialSolid(google.protobuf.message.Message):
3094
3121
  """Constant density value."""
3095
3122
  @property
3096
3123
  def specific_heat_cp_solid(self) -> luminarycloud._proto.base.base_pb2.AdFloatType:
3097
- """Specific heat at constant pressure."""
3124
+ """Specific heat."""
3125
+ thermal_conductivity_model_solid: global___ThermalConductivityModelSolid.ValueType
3126
+ """Uniform or direction-dependent conductivity models."""
3098
3127
  @property
3099
3128
  def thermal_conductivity_constant_solid(self) -> luminarycloud._proto.base.base_pb2.AdFloatType:
3100
3129
  """The thermal conductivity of the material."""
3130
+ @property
3131
+ def thermal_conductivity_orthotropic_solid(self) -> luminarycloud._proto.base.base_pb2.AdVector3:
3132
+ """The thermal conductivities of the material along each axis."""
3101
3133
  thermal_conductivity_table_data: builtins.str
3102
3134
  """Correlation between thermal conductivity and temperature."""
3103
3135
  material_solid_preset: global___MaterialSolidPreset.ValueType
@@ -3107,12 +3139,14 @@ class MaterialSolid(google.protobuf.message.Message):
3107
3139
  *,
3108
3140
  constant_density_value_solid: luminarycloud._proto.base.base_pb2.AdFloatType | None = ...,
3109
3141
  specific_heat_cp_solid: luminarycloud._proto.base.base_pb2.AdFloatType | None = ...,
3142
+ thermal_conductivity_model_solid: global___ThermalConductivityModelSolid.ValueType = ...,
3110
3143
  thermal_conductivity_constant_solid: luminarycloud._proto.base.base_pb2.AdFloatType | None = ...,
3144
+ thermal_conductivity_orthotropic_solid: luminarycloud._proto.base.base_pb2.AdVector3 | None = ...,
3111
3145
  thermal_conductivity_table_data: builtins.str = ...,
3112
3146
  material_solid_preset: global___MaterialSolidPreset.ValueType = ...,
3113
3147
  ) -> None: ...
3114
- def HasField(self, field_name: typing_extensions.Literal["constant_density_value_solid", b"constant_density_value_solid", "specific_heat_cp_solid", b"specific_heat_cp_solid", "thermal_conductivity_constant_solid", b"thermal_conductivity_constant_solid"]) -> builtins.bool: ...
3115
- def ClearField(self, field_name: typing_extensions.Literal["constant_density_value_solid", b"constant_density_value_solid", "material_solid_preset", b"material_solid_preset", "specific_heat_cp_solid", b"specific_heat_cp_solid", "thermal_conductivity_constant_solid", b"thermal_conductivity_constant_solid", "thermal_conductivity_table_data", b"thermal_conductivity_table_data"]) -> None: ...
3148
+ def HasField(self, field_name: typing_extensions.Literal["constant_density_value_solid", b"constant_density_value_solid", "specific_heat_cp_solid", b"specific_heat_cp_solid", "thermal_conductivity_constant_solid", b"thermal_conductivity_constant_solid", "thermal_conductivity_orthotropic_solid", b"thermal_conductivity_orthotropic_solid"]) -> builtins.bool: ...
3149
+ def ClearField(self, field_name: typing_extensions.Literal["constant_density_value_solid", b"constant_density_value_solid", "material_solid_preset", b"material_solid_preset", "specific_heat_cp_solid", b"specific_heat_cp_solid", "thermal_conductivity_constant_solid", b"thermal_conductivity_constant_solid", "thermal_conductivity_model_solid", b"thermal_conductivity_model_solid", "thermal_conductivity_orthotropic_solid", b"thermal_conductivity_orthotropic_solid", "thermal_conductivity_table_data", b"thermal_conductivity_table_data"]) -> None: ...
3116
3150
 
3117
3151
  global___MaterialSolid = MaterialSolid
3118
3152
 
@@ -0,0 +1,29 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: proto/physicsaitrainingservice/physicsaitrainingservice.proto
4
+ """Generated protocol buffer code."""
5
+ from google.protobuf import descriptor as _descriptor
6
+ from google.protobuf import descriptor_pool as _descriptor_pool
7
+ from google.protobuf import message as _message
8
+ from google.protobuf import reflection as _reflection
9
+ from google.protobuf import symbol_database as _symbol_database
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+ from luminarycloud._proto.api.v0.luminarycloud.physics_ai import physics_ai_pb2 as proto_dot_api_dot_v0_dot_luminarycloud_dot_physics__ai_dot_physics__ai__pb2
16
+
17
+
18
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n=proto/physicsaitrainingservice/physicsaitrainingservice.proto\x12\'luminary.proto.physicsaitrainingservice\x1a\x36proto/api/v0/luminarycloud/physics_ai/physics_ai.proto2\xc7\x01\n\x18PhysicsAiTrainingService\x12\xaa\x01\n\x11SubmitTrainingJob\x12H.luminary.proto.api.v0.luminarycloud.physics_ai.SubmitTrainingJobRequest\x1aI.luminary.proto.api.v0.luminarycloud.physics_ai.SubmitTrainingJobResponse\"\x00\x42\x37Z5luminarycloud.com/core/proto/physicsaitrainingserviceb\x06proto3')
19
+
20
+
21
+
22
+ _PHYSICSAITRAININGSERVICE = DESCRIPTOR.services_by_name['PhysicsAiTrainingService']
23
+ if _descriptor._USE_C_DESCRIPTORS == False:
24
+
25
+ DESCRIPTOR._options = None
26
+ DESCRIPTOR._serialized_options = b'Z5luminarycloud.com/core/proto/physicsaitrainingservice'
27
+ _PHYSICSAITRAININGSERVICE._serialized_start=163
28
+ _PHYSICSAITRAININGSERVICE._serialized_end=362
29
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,7 @@
1
+ """
2
+ @generated by mypy-protobuf. Do not edit manually!
3
+ isort:skip_file
4
+ Copyright 2025 Luminary Cloud, Inc. All Rights Reserved."""
5
+ import google.protobuf.descriptor
6
+
7
+ DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
@@ -0,0 +1,70 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+
5
+ from luminarycloud._proto.api.v0.luminarycloud.physics_ai import physics_ai_pb2 as proto_dot_api_dot_v0_dot_luminarycloud_dot_physics__ai_dot_physics__ai__pb2
6
+
7
+
8
+ class PhysicsAiTrainingServiceStub(object):
9
+ """PhysicsAiTrainingService provides training functionality for Physics AI
10
+ """
11
+
12
+ def __init__(self, channel):
13
+ """Constructor.
14
+
15
+ Args:
16
+ channel: A grpc.Channel.
17
+ """
18
+ self.SubmitTrainingJob = channel.unary_unary(
19
+ '/luminary.proto.physicsaitrainingservice.PhysicsAiTrainingService/SubmitTrainingJob',
20
+ request_serializer=proto_dot_api_dot_v0_dot_luminarycloud_dot_physics__ai_dot_physics__ai__pb2.SubmitTrainingJobRequest.SerializeToString,
21
+ response_deserializer=proto_dot_api_dot_v0_dot_luminarycloud_dot_physics__ai_dot_physics__ai__pb2.SubmitTrainingJobResponse.FromString,
22
+ )
23
+
24
+
25
+ class PhysicsAiTrainingServiceServicer(object):
26
+ """PhysicsAiTrainingService provides training functionality for Physics AI
27
+ """
28
+
29
+ def SubmitTrainingJob(self, request, context):
30
+ """Submit a physics AI training job
31
+ """
32
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
33
+ context.set_details('Method not implemented!')
34
+ raise NotImplementedError('Method not implemented!')
35
+
36
+
37
+ def add_PhysicsAiTrainingServiceServicer_to_server(servicer, server):
38
+ rpc_method_handlers = {
39
+ 'SubmitTrainingJob': grpc.unary_unary_rpc_method_handler(
40
+ servicer.SubmitTrainingJob,
41
+ request_deserializer=proto_dot_api_dot_v0_dot_luminarycloud_dot_physics__ai_dot_physics__ai__pb2.SubmitTrainingJobRequest.FromString,
42
+ response_serializer=proto_dot_api_dot_v0_dot_luminarycloud_dot_physics__ai_dot_physics__ai__pb2.SubmitTrainingJobResponse.SerializeToString,
43
+ ),
44
+ }
45
+ generic_handler = grpc.method_handlers_generic_handler(
46
+ 'luminary.proto.physicsaitrainingservice.PhysicsAiTrainingService', rpc_method_handlers)
47
+ server.add_generic_rpc_handlers((generic_handler,))
48
+
49
+
50
+ # This class is part of an EXPERIMENTAL API.
51
+ class PhysicsAiTrainingService(object):
52
+ """PhysicsAiTrainingService provides training functionality for Physics AI
53
+ """
54
+
55
+ @staticmethod
56
+ def SubmitTrainingJob(request,
57
+ target,
58
+ options=(),
59
+ channel_credentials=None,
60
+ call_credentials=None,
61
+ insecure=False,
62
+ compression=None,
63
+ wait_for_ready=None,
64
+ timeout=None,
65
+ metadata=None):
66
+ return grpc.experimental.unary_unary(request, target, '/luminary.proto.physicsaitrainingservice.PhysicsAiTrainingService/SubmitTrainingJob',
67
+ proto_dot_api_dot_v0_dot_luminarycloud_dot_physics__ai_dot_physics__ai__pb2.SubmitTrainingJobRequest.SerializeToString,
68
+ proto_dot_api_dot_v0_dot_luminarycloud_dot_physics__ai_dot_physics__ai__pb2.SubmitTrainingJobResponse.FromString,
69
+ options, channel_credentials,
70
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@@ -0,0 +1,30 @@
1
+ """
2
+ @generated by mypy-protobuf. Do not edit manually!
3
+ isort:skip_file
4
+ Copyright 2025 Luminary Cloud, Inc. All Rights Reserved."""
5
+ import abc
6
+ import grpc
7
+ import luminarycloud._proto.api.v0.luminarycloud.physics_ai.physics_ai_pb2
8
+
9
+ class PhysicsAiTrainingServiceStub:
10
+ """PhysicsAiTrainingService provides training functionality for Physics AI"""
11
+
12
+ def __init__(self, channel: grpc.Channel) -> None: ...
13
+ SubmitTrainingJob: grpc.UnaryUnaryMultiCallable[
14
+ luminarycloud._proto.api.v0.luminarycloud.physics_ai.physics_ai_pb2.SubmitTrainingJobRequest,
15
+ luminarycloud._proto.api.v0.luminarycloud.physics_ai.physics_ai_pb2.SubmitTrainingJobResponse,
16
+ ]
17
+ """Submit a physics AI training job"""
18
+
19
+ class PhysicsAiTrainingServiceServicer(metaclass=abc.ABCMeta):
20
+ """PhysicsAiTrainingService provides training functionality for Physics AI"""
21
+
22
+ @abc.abstractmethod
23
+ def SubmitTrainingJob(
24
+ self,
25
+ request: luminarycloud._proto.api.v0.luminarycloud.physics_ai.physics_ai_pb2.SubmitTrainingJobRequest,
26
+ context: grpc.ServicerContext,
27
+ ) -> luminarycloud._proto.api.v0.luminarycloud.physics_ai.physics_ai_pb2.SubmitTrainingJobResponse:
28
+ """Submit a physics AI training job"""
29
+
30
+ def add_PhysicsAiTrainingServiceServicer_to_server(servicer: PhysicsAiTrainingServiceServicer, server: grpc.Server) -> None: ...
@@ -22,6 +22,12 @@ class SDKException(Exception):
22
22
  return [self.message]
23
23
 
24
24
 
25
+ class Timeout(SDKException):
26
+ """Raised when some long-running operation doesn't finish before its deadline."""
27
+
28
+ pass
29
+
30
+
25
31
  class RpcError(SDKException):
26
32
  """Raised when an RPC error occurs."""
27
33
 
@@ -70,6 +76,6 @@ class FailedPreconditionError(RpcError):
70
76
 
71
77
 
72
78
  class DeadlineExceededError(RpcError):
73
- """Raised when the deadline expired before the operation could complete. I.e. it timed out."""
79
+ """Raised when the gRPC deadline expired before the operation could complete. I.e. it timed out."""
74
80
 
75
81
  pass
luminarycloud/geometry.py CHANGED
@@ -42,6 +42,8 @@ class Geometry(ProtoWrapperBase):
42
42
  "Geometry name."
43
43
  status: GeometryStatus
44
44
  "The status of the geometry."
45
+ project_id: ProjectID
46
+ "The ID of the project this geometry belongs to."
45
47
 
46
48
  _proto: geometrypb.Geometry
47
49
 
@@ -63,7 +65,7 @@ class Geometry(ProtoWrapperBase):
63
65
  """
64
66
  Get the project this geometry belongs to.
65
67
  """
66
- return lc.get_project(ProjectID(self._proto.project_id))
68
+ return lc.get_project(self.project_id)
67
69
 
68
70
  def update(self, *, name: str | None = None) -> None:
69
71
  """
luminarycloud/mesh.py CHANGED
@@ -106,8 +106,7 @@ class Mesh(ProtoWrapperBase):
106
106
  interval_seconds=interval_seconds,
107
107
  timeout_seconds=timeout_seconds,
108
108
  )
109
- self._proto = get_mesh(self.id)._proto
110
- return self.status
109
+ return self.refresh().status
111
110
 
112
111
  def refresh(self) -> "Mesh":
113
112
  """
@@ -541,6 +541,31 @@ class MaterialFluidPreset(_IntEnum):
541
541
  CUSTOM_MATERIAL_FLUID = _clientpb.CUSTOM_MATERIAL_FLUID
542
542
 
543
543
 
544
+ class ThermalConductivityModelSolid(_IntEnum):
545
+ """
546
+ Uniform or direction-dependent conductivity models.
547
+
548
+ Attributes
549
+ ----------
550
+ ISOTROPIC_CONDUCTIVITY
551
+ Equal thermal conductivity in all directions.
552
+ ORTHOTROPIC_CONDUCTIVITY
553
+ Different thermal conductivity along each axis of the frames to which
554
+ the volumes of this material are assigned.
555
+
556
+
557
+ Examples
558
+ --------
559
+ >>> from luminarycloud.params.enum import ThermalConductivityModelSolid
560
+ >>> ThermalConductivityModelSolid.ISOTROPIC_CONDUCTIVITY
561
+ >>> ThermalConductivityModelSolid.ORTHOTROPIC_CONDUCTIVITY
562
+ """
563
+
564
+ INVALID = _clientpb.INVALID_THERMAL_CONDUCTIVITY_MODEL_SOLID
565
+ ISOTROPIC_CONDUCTIVITY = _clientpb.ISOTROPIC_CONDUCTIVITY
566
+ ORTHOTROPIC_CONDUCTIVITY = _clientpb.ORTHOTROPIC_CONDUCTIVITY
567
+
568
+
544
569
  class MaterialSolidPreset(_IntEnum):
545
570
  """
546
571
  Select a predefined set of material properties or allow a custom set of properties.
@@ -25,9 +25,15 @@ class MaterialSolid(CodeRepr, ParamGroupWrapper[clientpb.MaterialSolid]):
25
25
  density: LcFloat = 2700
26
26
  "Constant density value."
27
27
  specific_heat_cp: LcFloat = 896
28
- "Specific heat at constant pressure."
28
+ "Specific heat."
29
+ conductivity_model: enum.ThermalConductivityModelSolid = (
30
+ enum.ThermalConductivityModelSolid.ISOTROPIC_CONDUCTIVITY
31
+ )
32
+ "Uniform or direction-dependent conductivity models."
29
33
  thermal_conductivity: LcFloat = 167
30
34
  "The thermal conductivity of the material."
35
+ orthotropic_conductivity: Vector3 = field(default_factory=lambda: Vector3(167, 167, 167))
36
+ "The thermal conductivities of the material along each axis."
31
37
  thermal_conductivity_table: RectilinearTable | None = None
32
38
  "Correlation between thermal conductivity and temperature."
33
39
  preset: enum.MaterialSolidPreset = enum.MaterialSolidPreset.ALUMINUM
@@ -37,7 +43,11 @@ class MaterialSolid(CodeRepr, ParamGroupWrapper[clientpb.MaterialSolid]):
37
43
  _proto = clientpb.MaterialSolid()
38
44
  _proto.constant_density_value_solid.CopyFrom(_to_ad_proto(self.density))
39
45
  _proto.specific_heat_cp_solid.CopyFrom(_to_ad_proto(self.specific_heat_cp))
46
+ _proto.thermal_conductivity_model_solid = self.conductivity_model.value
40
47
  _proto.thermal_conductivity_constant_solid.CopyFrom(_to_ad_proto(self.thermal_conductivity))
48
+ _proto.thermal_conductivity_orthotropic_solid.CopyFrom(
49
+ self.orthotropic_conductivity._to_ad_proto()
50
+ )
41
51
  if self.thermal_conductivity_table is not None:
42
52
  if self.thermal_conductivity_table.table_type != _param_name_to_table_type(
43
53
  "thermal_conductivity_table_data"
@@ -50,7 +60,11 @@ class MaterialSolid(CodeRepr, ParamGroupWrapper[clientpb.MaterialSolid]):
50
60
  def _from_proto(self, proto: clientpb.MaterialSolid) -> None:
51
61
  self.density = _from_ad_proto(proto.constant_density_value_solid)
52
62
  self.specific_heat_cp = _from_ad_proto(proto.specific_heat_cp_solid)
63
+ self.conductivity_model = enum.ThermalConductivityModelSolid(
64
+ proto.thermal_conductivity_model_solid
65
+ )
53
66
  self.thermal_conductivity = _from_ad_proto(proto.thermal_conductivity_constant_solid)
67
+ self.orthotropic_conductivity._from_ad_proto(proto.thermal_conductivity_orthotropic_solid)
54
68
  if proto.thermal_conductivity_table_data != "":
55
69
  self.thermal_conductivity_table = RectilinearTable(
56
70
  id=proto.thermal_conductivity_table_data,
@@ -1,5 +1,6 @@
1
1
  # Copyright 2025 Luminary Cloud, Inc. All Rights Reserved.
2
2
  from typing import List, Optional
3
+ import json
3
4
 
4
5
  from .._client import get_default_client
5
6
  from .._proto.api.v0.luminarycloud.physics_ai import physics_ai_pb2 as physaipb
@@ -7,6 +8,8 @@ from .._wrapper import ProtoWrapper, ProtoWrapperBase
7
8
  from ..types.ids import PhysicsAiArchitectureID, PhysicsAiArchitectureVersionID
8
9
  from ..enum.physics_ai_lifecycle_state import PhysicsAiLifecycleState
9
10
 
11
+ from .training_jobs import PhysicsAiTrainingJob
12
+
10
13
 
11
14
  @ProtoWrapper(physaipb.PhysicsAiArchitectureVersion)
12
15
  class PhysicsAiArchitectureVersion(ProtoWrapperBase):
@@ -18,10 +21,65 @@ class PhysicsAiArchitectureVersion(ProtoWrapperBase):
18
21
 
19
22
  id: PhysicsAiArchitectureVersionID
20
23
  name: str
24
+ architecture_name: str
21
25
  changelog: str
22
26
  lifecycle_state: PhysicsAiLifecycleState
23
27
  _proto: physaipb.PhysicsAiArchitectureVersion
24
28
 
29
+ def get_training_description(self, config: dict) -> str:
30
+ if config.get("description"):
31
+ return config["description"]
32
+
33
+ desc = f"Training job for architecture {self.name}"
34
+ if config.get("custom_args"):
35
+ desc += f" with custom args: {config['custom_args']}"
36
+ return desc
37
+
38
+ def train(self, config: dict) -> PhysicsAiTrainingJob:
39
+ """
40
+ Submit a training job for this architecture version.
41
+
42
+ Parameters
43
+ ----------
44
+ config : dict, optional
45
+ Training configuration dictionary
46
+
47
+ Returns
48
+ -------
49
+ PhysicsAiTrainingJob
50
+ The submitted training job object
51
+ """
52
+
53
+ if "custom_args" not in config:
54
+ config["custom_args"] = ""
55
+ if "priority_class" not in config:
56
+ config["priority_class"] = "prod-batch-priority"
57
+ if "resources" not in config:
58
+ config["resources"] = {}
59
+ if "process_gpus" not in config["resources"]:
60
+ config["resources"]["process_gpus"] = 8
61
+ if "train_gpus" not in config["resources"]:
62
+ config["resources"]["train_gpus"] = 8
63
+ if "test_gpus" not in config["resources"]:
64
+ config["resources"]["test_gpus"] = 8
65
+ if "mode" not in config:
66
+ config["mode"] = "full-gpu"
67
+
68
+ training_config_json = json.dumps(config, indent=2)
69
+ external_dataset_uri = f"gs://training-data/architecture-{self.id}"
70
+ req = physaipb.SubmitTrainingJobRequest(
71
+ architecture_version_id=self.id,
72
+ training_description=self.get_training_description(config),
73
+ external_dataset_uri=external_dataset_uri,
74
+ training_config=training_config_json,
75
+ initialization_type=physaipb.MODEL_INITIALIZATION_TYPE_RANDOM,
76
+ base_model_version_id="",
77
+ )
78
+
79
+ response = get_default_client().SubmitTrainingJob(req)
80
+
81
+ return PhysicsAiTrainingJob(response.training_job)
82
+
25
83
 
26
84
  @ProtoWrapper(physaipb.PhysicsAiArchitecture)
27
85
  class PhysicsAiArchitecture(ProtoWrapperBase):
@@ -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)
@@ -36,7 +36,6 @@ class PipelineRecord:
36
36
  class PipelineJobRecord:
37
37
  id: str
38
38
  pipeline_id: str
39
- project_id: str
40
39
  name: str
41
40
  description: str | None
42
41
  status: Literal["pending", "running", "completed", "failed", "cancelled"]
@@ -50,7 +49,6 @@ class PipelineJobRecord:
50
49
  return cls(
51
50
  id=json["id"],
52
51
  pipeline_id=json["pipeline_id"],
53
- project_id=json["project_id"],
54
52
  name=json["name"],
55
53
  description=json["description"],
56
54
  status=json["status"],
@@ -88,7 +86,7 @@ def create_pipeline(
88
86
  "description": description,
89
87
  }
90
88
  res = get_default_client().http.post("/rest/v0/pipelines", body)
91
- return PipelineRecord.from_json(res)
89
+ return PipelineRecord.from_json(res["data"])
92
90
 
93
91
 
94
92
  def list_pipelines() -> list[PipelineRecord]:
@@ -96,7 +94,7 @@ def list_pipelines() -> list[PipelineRecord]:
96
94
  List all pipelines.
97
95
  """
98
96
  res = get_default_client().http.get("/rest/v0/pipelines")
99
- return [PipelineRecord.from_json(p) for p in res]
97
+ return [PipelineRecord.from_json(p) for p in res["data"]]
100
98
 
101
99
 
102
100
  def get_pipeline(id: str) -> PipelineRecord:
@@ -109,11 +107,11 @@ def get_pipeline(id: str) -> PipelineRecord:
109
107
  ID of the pipeline to fetch.
110
108
  """
111
109
  res = get_default_client().http.get(f"/rest/v0/pipelines/{id}")
112
- return PipelineRecord.from_json(res)
110
+ return PipelineRecord.from_json(res["data"])
113
111
 
114
112
 
115
113
  def create_pipeline_job(
116
- pipeline_id: str, args: PipelineArgs, project_id: str, name: str, description: str | None = None
114
+ pipeline_id: str, args: PipelineArgs, name: str, description: str | None = None
117
115
  ) -> PipelineJobRecord:
118
116
  """
119
117
  Create a new pipeline job.
@@ -124,8 +122,6 @@ def create_pipeline_job(
124
122
  ID of the pipeline to invoke.
125
123
  args : PipelineArgs
126
124
  Arguments to pass to the pipeline.
127
- project_id : str
128
- ID of the project to run the pipeline job in.
129
125
  name : str
130
126
  Name of the pipeline job.
131
127
  description : str, optional
@@ -135,13 +131,13 @@ def create_pipeline_job(
135
131
  arg_rows = [row.row_values for row in args.rows]
136
132
  body = {
137
133
  "name": name,
138
- "project_id": project_id,
134
+ "description": description,
139
135
  "argument_names": [p.name for p in args.params],
140
136
  "argument_rows": arg_rows,
141
137
  }
142
138
 
143
139
  res = get_default_client().http.post(f"/rest/v0/pipelines/{pipeline_id}/pipeline_jobs", body)
144
- return PipelineJobRecord.from_json(res)
140
+ return PipelineJobRecord.from_json(res["data"])
145
141
 
146
142
 
147
143
  def get_pipeline_job(id: str) -> PipelineJobRecord:
@@ -149,7 +145,7 @@ def get_pipeline_job(id: str) -> PipelineJobRecord:
149
145
  Get a pipeline job by ID.
150
146
  """
151
147
  res = get_default_client().http.get(f"/rest/v0/pipeline_jobs/{id}")
152
- return PipelineJobRecord.from_json(res)
148
+ return PipelineJobRecord.from_json(res["data"])
153
149
 
154
150
 
155
151
  def list_pipeline_jobs() -> list[PipelineJobRecord]:
@@ -157,4 +153,4 @@ def list_pipeline_jobs() -> list[PipelineJobRecord]:
157
153
  List all pipeline jobs.
158
154
  """
159
155
  res = get_default_client().http.get("/rest/v0/pipeline_jobs")
160
- return [PipelineJobRecord.from_json(p) for p in res]
156
+ return [PipelineJobRecord.from_json(p) for p in res["data"]]
@@ -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
 
@@ -122,8 +124,7 @@ class Simulation(ProtoWrapperBase):
122
124
  interval_seconds=interval_seconds,
123
125
  timeout_seconds=timeout_seconds,
124
126
  )
125
- self._proto = get_simulation(self.id)._proto
126
- return self.status
127
+ return self.refresh().status
127
128
 
128
129
  def refresh(self) -> "Simulation":
129
130
  """
@@ -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
 
@@ -4,8 +4,12 @@ from .visualization import (
4
4
  EntityType as EntityType,
5
5
  list_renders as list_renders,
6
6
  list_quantities as list_quantities,
7
+ list_quantities as list_quantities,
8
+ list_cameras as list_cameras,
9
+ get_camera as get_camera,
7
10
  DirectionalCamera as DirectionalCamera,
8
11
  LookAtCamera as LookAtCamera,
12
+ CameraEntry as CameraEntry,
9
13
  )
10
14
 
11
15
  from .primitives import (
@@ -52,3 +56,14 @@ from .interactive_scene import (
52
56
  from .interactive_inference import (
53
57
  InteractiveInference as InteractiveInference,
54
58
  )
59
+
60
+ # Unreleased/internal for testing now
61
+
62
+ # from .report import (
63
+ # Report as Report,
64
+ # )
65
+
66
+ # from .interactive_report import (
67
+ # InteractiveReport as InteractiveReport,
68
+ # ReportEntry as ReportEntry,
69
+ # )