luminarycloud 0.15.3__py3-none-any.whl → 0.15.5__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/__init__.py +1 -0
- luminarycloud/_helpers/_create_geometry.py +36 -17
- luminarycloud/_helpers/_create_simulation.py +2 -0
- luminarycloud/_helpers/_entity_identifier.py +6 -0
- luminarycloud/_helpers/named_variables.py +6 -15
- luminarycloud/_helpers/warnings/experimental.py +6 -2
- luminarycloud/_proto/api/v0/luminarycloud/geometry/geometry_pb2.py +77 -55
- luminarycloud/_proto/api/v0/luminarycloud/geometry/geometry_pb2.pyi +34 -2
- luminarycloud/_proto/api/v0/luminarycloud/geometry/geometry_pb2_grpc.py +33 -0
- luminarycloud/_proto/api/v0/luminarycloud/geometry/geometry_pb2_grpc.pyi +10 -0
- luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2.py +45 -15
- luminarycloud/_proto/api/v0/luminarycloud/physics_ai/physics_ai_pb2.pyi +104 -22
- luminarycloud/_proto/api/v0/luminarycloud/simulation_template/simulation_template_pb2.py +12 -12
- luminarycloud/_proto/api/v0/luminarycloud/simulation_template/simulation_template_pb2.pyi +10 -2
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.py +27 -105
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2.pyi +24 -173
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.py +17 -113
- luminarycloud/_proto/api/v0/luminarycloud/thirdpartyintegration/onshape/onshape_pb2_grpc.pyi +16 -44
- luminarycloud/_proto/api/v0/luminarycloud/upload/upload_pb2.py +4 -2
- luminarycloud/_proto/api/v0/luminarycloud/upload/upload_pb2_grpc.py +37 -0
- luminarycloud/_proto/api/v0/luminarycloud/upload/upload_pb2_grpc.pyi +20 -0
- luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2.py +221 -143
- luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2.pyi +154 -7
- luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2_grpc.py +33 -0
- luminarycloud/_proto/api/v0/luminarycloud/vis/vis_pb2_grpc.pyi +10 -0
- luminarycloud/_proto/assistant/assistant_pb2.py +62 -61
- luminarycloud/_proto/client/simulation_pb2.py +349 -309
- luminarycloud/_proto/client/simulation_pb2.pyi +97 -2
- luminarycloud/_proto/fvm/solver_results_pb2.py +25 -11
- luminarycloud/_proto/fvm/solver_results_pb2.pyi +24 -1
- luminarycloud/_proto/geometry/geometry_pb2.py +63 -64
- luminarycloud/_proto/namedvariableset/namedvariableset_pb2.py +49 -0
- luminarycloud/_proto/namedvariableset/namedvariableset_pb2.pyi +53 -0
- luminarycloud/_proto/upload/upload_pb2.py +27 -7
- luminarycloud/_proto/upload/upload_pb2.pyi +31 -0
- luminarycloud/_wrapper.py +26 -7
- luminarycloud/enum/__init__.py +2 -0
- luminarycloud/enum/physics_ai_lifecycle_state.py +30 -0
- luminarycloud/enum/quantity_type.py +43 -0
- luminarycloud/enum/vis_enums.py +6 -2
- luminarycloud/geometry.py +46 -2
- luminarycloud/named_variable_set.py +10 -5
- luminarycloud/params/enum/_enum_wrappers.py +68 -0
- luminarycloud/params/simulation/_lib.py +1 -1
- luminarycloud/params/simulation/adaptive_mesh_refinement/boundary_layer_profile_.py +5 -6
- luminarycloud/params/simulation/adaptive_mesh_refinement_.py +6 -7
- luminarycloud/params/simulation/adjoint_.py +3 -4
- luminarycloud/params/simulation/basic/gravity/gravity_off_.py +3 -4
- luminarycloud/params/simulation/basic/gravity/gravity_on_.py +3 -4
- luminarycloud/params/simulation/basic/gravity_.py +3 -4
- luminarycloud/params/simulation/body_frame_.py +3 -4
- luminarycloud/params/simulation/entity_relationships/volume_material_relationship_.py +9 -6
- luminarycloud/params/simulation/entity_relationships/volume_physics_relationship_.py +9 -6
- luminarycloud/params/simulation/entity_relationships_.py +3 -4
- luminarycloud/params/simulation/general_.py +3 -4
- luminarycloud/params/simulation/material/fluid/boussinesq_approximation/boussinesq_off_.py +3 -4
- luminarycloud/params/simulation/material/fluid/boussinesq_approximation/boussinesq_on_.py +5 -6
- luminarycloud/params/simulation/material/fluid/boussinesq_approximation_.py +3 -4
- luminarycloud/params/simulation/material/fluid/material_model/ideal_gas_.py +5 -6
- luminarycloud/params/simulation/material/fluid/material_model/incompressible_fluid_.py +4 -5
- luminarycloud/params/simulation/material/fluid/material_model/incompressible_fluid_with_energy_.py +5 -6
- luminarycloud/params/simulation/material/fluid/material_model_.py +3 -4
- luminarycloud/params/simulation/material/fluid/thermal_conductivity_model/prescribed_conductivity_.py +4 -5
- luminarycloud/params/simulation/material/fluid/thermal_conductivity_model/prescribed_prandtl_number_.py +4 -5
- luminarycloud/params/simulation/material/fluid/thermal_conductivity_model/temperature_dependent_conductivity_.py +3 -4
- luminarycloud/params/simulation/material/fluid/thermal_conductivity_model_.py +3 -4
- luminarycloud/params/simulation/material/fluid/viscosity_model/prescribed_viscosity_.py +4 -5
- luminarycloud/params/simulation/material/fluid/viscosity_model/sutherland_.py +6 -7
- luminarycloud/params/simulation/material/fluid/viscosity_model/temperature_dependent_viscosity_.py +3 -4
- luminarycloud/params/simulation/material/fluid/viscosity_model_.py +3 -4
- luminarycloud/params/simulation/material/material_fluid_.py +4 -5
- luminarycloud/params/simulation/material/material_solid_.py +6 -7
- luminarycloud/params/simulation/material_entity_.py +6 -5
- luminarycloud/params/simulation/monitor_plane_.py +4 -5
- luminarycloud/params/simulation/motion_data/frame_transforms/no_transform_.py +3 -4
- luminarycloud/params/simulation/motion_data/frame_transforms/rotational_transform_.py +3 -4
- luminarycloud/params/simulation/motion_data/frame_transforms/translational_transform_.py +3 -4
- luminarycloud/params/simulation/motion_data/frame_transforms_.py +3 -4
- luminarycloud/params/simulation/motion_data/motion_type/constant_angular_motion_.py +3 -4
- luminarycloud/params/simulation/motion_data/motion_type/constant_translation_motion_.py +3 -4
- luminarycloud/params/simulation/motion_data/motion_type_.py +3 -4
- luminarycloud/params/simulation/motion_data_.py +3 -4
- luminarycloud/params/simulation/multi_physics_coupling_options_.py +3 -4
- luminarycloud/params/simulation/output_.py +3 -4
- luminarycloud/params/simulation/particle_group/particle_group_type/actuator_disk/actuator_disk_orientation_selection/actuator_disk_specify_normal_vector_.py +3 -4
- luminarycloud/params/simulation/particle_group/particle_group_type/actuator_disk/actuator_disk_orientation_selection/actuator_disk_specify_rotation_angles_.py +3 -4
- luminarycloud/params/simulation/particle_group/particle_group_type/actuator_disk/actuator_disk_orientation_selection_.py +3 -4
- luminarycloud/params/simulation/particle_group/particle_group_type/actuator_disk_.py +5 -6
- luminarycloud/params/simulation/particle_group/particle_group_type/actuator_line_.py +3 -4
- luminarycloud/params/simulation/particle_group/particle_group_type/probe_points_.py +3 -4
- luminarycloud/params/simulation/particle_group/particle_group_type/source_points_.py +3 -4
- luminarycloud/params/simulation/particle_group/particle_group_type_.py +3 -4
- luminarycloud/params/simulation/particle_group_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/adjoint_controls_fluid_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/basic_fluid_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/farfield_.py +9 -10
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/inlet/fan_curve_inlet_.py +5 -6
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/inlet/mach_inlet_.py +5 -6
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/inlet/mass_flow_inlet_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/inlet/total_pressure_inlet_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/inlet/velocity_components_inlet_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/inlet/velocity_magnitude_inlet_.py +5 -6
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/inlet_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/outlet/outlet_strategy/fan_curve_outlet_.py +5 -6
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/outlet/outlet_strategy/outlet_pressure_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/outlet/outlet_strategy/outlet_target_corrected_mass_flow_rate_.py +7 -8
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/outlet/outlet_strategy/outlet_target_mass_flow_rate_.py +5 -6
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/outlet/outlet_strategy_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/outlet_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/symmetry_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/turbulence_boundary_conditions_.py +9 -10
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/wall/energy/prescribed_heat_flux_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/wall/energy/prescribed_temperature_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/wall/momentum/no_slip_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/wall/momentum/slip_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/wall/momentum/wall_model_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/wall/wall_energy_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/wall/wall_momentum_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/boundary_conditions/wall_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/boundary_conditions_fluid_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/initialization/fluid_existing_solution_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/initialization/fluid_farfield_values_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/initialization/fluid_prescribed_values_.py +5 -6
- luminarycloud/params/simulation/physics/fluid/initialization/turbulence_initialization_.py +9 -10
- luminarycloud/params/simulation/physics/fluid/initialization_fluid_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/physical_behavior/blade_element_airfoil_data_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/physical_behavior/physical_behavior_model/actuator_disk_model/actuator_disk_blade_element_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/physical_behavior/physical_behavior_model/actuator_disk_model/actuator_disk_radial_distribution_.py +6 -7
- luminarycloud/params/simulation/physics/fluid/physical_behavior/physical_behavior_model/actuator_disk_model/actuator_disk_uniform_thrust_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/physical_behavior/physical_behavior_model/actuator_disk_model/fan_curve_internal_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/physical_behavior/physical_behavior_model/actuator_disk_model_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/physical_behavior/physical_behavior_model/actuator_line_model/actuator_line_blade_element_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/physical_behavior/physical_behavior_model/actuator_line_model_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/physical_behavior/physical_behavior_model/blade_element_params_.py +5 -6
- luminarycloud/params/simulation/physics/fluid/physical_behavior/physical_behavior_model/particle_source_model/general_acceleration_source_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/physical_behavior/physical_behavior_model/particle_source_model/general_mass_source_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/physical_behavior/physical_behavior_model/particle_source_model_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/physical_behavior/physical_behavior_model_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/physical_behavior_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/porous_behavior_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method/fluid_explicit_relaxation_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method/fluid_implicit_relaxation/robust_startup/robust_startup_off_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method/fluid_implicit_relaxation/robust_startup/robust_startup_on_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method/fluid_implicit_relaxation/robust_startup_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method/fluid_implicit_relaxation_.py +9 -10
- luminarycloud/params/simulation/physics/fluid/solution_controls/fluid_relaxation_method_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/solution_controls/pseudo_time_step_method/cfl_based_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/solution_controls/pseudo_time_step_method/fixed_pseudo_time_step_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/solution_controls/pseudo_time_step_method_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/solution_controls_fluid_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/spatial_discretization/convective_scheme/ec2_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/spatial_discretization/convective_scheme/fds_.py +5 -6
- luminarycloud/params/simulation/physics/fluid/spatial_discretization/convective_scheme/ld2_.py +5 -6
- luminarycloud/params/simulation/physics/fluid/spatial_discretization/convective_scheme/rhie_chow_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/spatial_discretization/convective_scheme_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/spatial_discretization/convective_scheme_order/first_order_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/spatial_discretization/convective_scheme_order/second_order_.py +8 -9
- luminarycloud/params/simulation/physics/fluid/spatial_discretization/convective_scheme_order_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/spatial_discretization_fluid_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/turbulence/des_formulation/ddes_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/turbulence/des_formulation/ddes_vtm_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/turbulence/des_formulation/iddes_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/turbulence/des_formulation_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/turbulence/komega_sst/constants/custom_komega_sst_constants_.py +16 -17
- luminarycloud/params/simulation/physics/fluid/turbulence/komega_sst/constants/default_komega_sst_constants_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/turbulence/komega_sst/komega_sst_constants_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/turbulence/komega_sst_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/turbulence/spalart_allmaras/constants/custom_spalart_allmaras_constants_.py +15 -16
- luminarycloud/params/simulation/physics/fluid/turbulence/spalart_allmaras/constants/default_spalart_allmaras_constants_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/turbulence/spalart_allmaras/spalart_allmaras_constants_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/turbulence/spalart_allmaras_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/turbulence/sub_grid_scale_model/amd_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/turbulence/sub_grid_scale_model/sigma_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/turbulence/sub_grid_scale_model/smagorinsky_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/turbulence/sub_grid_scale_model/vreman_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/turbulence/sub_grid_scale_model/wale_.py +4 -5
- luminarycloud/params/simulation/physics/fluid/turbulence/sub_grid_scale_model_.py +3 -4
- luminarycloud/params/simulation/physics/fluid/turbulence_.py +6 -7
- luminarycloud/params/simulation/physics/fluid_.py +8 -7
- luminarycloud/params/simulation/physics/heat/adjoint_controls_heat_.py +3 -4
- luminarycloud/params/simulation/physics/heat/boundary_conditions/heat_bc_convection_.py +5 -6
- luminarycloud/params/simulation/physics/heat/boundary_conditions/heat_bc_heat_flux_.py +4 -5
- luminarycloud/params/simulation/physics/heat/boundary_conditions/heat_bc_integrated_heat_flux_.py +4 -5
- luminarycloud/params/simulation/physics/heat/boundary_conditions/heat_bc_symmetry_.py +3 -4
- luminarycloud/params/simulation/physics/heat/boundary_conditions/heat_bc_temperature_.py +4 -5
- luminarycloud/params/simulation/physics/heat/boundary_conditions_heat_.py +3 -4
- luminarycloud/params/simulation/physics/heat/heat_source/heat_source_type/heat_source_type_power_.py +4 -5
- luminarycloud/params/simulation/physics/heat/heat_source/heat_source_type/heat_source_type_power_per_unit_of_volume_.py +4 -5
- luminarycloud/params/simulation/physics/heat/heat_source/heat_source_type_.py +3 -4
- luminarycloud/params/simulation/physics/heat/heat_source_.py +3 -4
- luminarycloud/params/simulation/physics/heat/initialization/heat_existing_solution_.py +3 -4
- luminarycloud/params/simulation/physics/heat/initialization/heat_prescribed_values_.py +4 -5
- luminarycloud/params/simulation/physics/heat/initialization_heat_.py +3 -4
- luminarycloud/params/simulation/physics/heat/solution_controls/heat_relaxation_method/heat_implicit_relaxation_.py +4 -5
- luminarycloud/params/simulation/physics/heat/solution_controls/heat_relaxation_method_.py +3 -4
- luminarycloud/params/simulation/physics/heat/solution_controls_heat_.py +4 -5
- luminarycloud/params/simulation/physics/heat/spatial_discretization_heat_.py +5 -6
- luminarycloud/params/simulation/physics/heat_.py +5 -5
- luminarycloud/params/simulation/physics/periodic_pair/periodicity_type/rotational_periodicity_.py +3 -4
- luminarycloud/params/simulation/physics/periodic_pair/periodicity_type/translational_periodicity_.py +3 -4
- luminarycloud/params/simulation/physics/periodic_pair/periodicity_type_.py +3 -4
- luminarycloud/params/simulation/physics/periodic_pair_.py +3 -4
- luminarycloud/params/simulation/physics/solution_controls/linear_solver_type/gauss_seidel_.py +3 -4
- luminarycloud/params/simulation/physics/solution_controls/linear_solver_type/krylov_amg_.py +4 -5
- luminarycloud/params/simulation/physics/solution_controls/linear_solver_type_.py +4 -5
- luminarycloud/params/simulation/physics_.py +6 -5
- luminarycloud/params/simulation/simulation_param_.py +3 -4
- luminarycloud/params/simulation/sliding_interfaces_.py +3 -4
- luminarycloud/params/simulation/surface_name_.py +3 -4
- luminarycloud/params/simulation/time/compute_statistics/compute_statistics_off_.py +3 -4
- luminarycloud/params/simulation/time/compute_statistics/compute_statistics_on_.py +3 -4
- luminarycloud/params/simulation/time/compute_statistics_.py +3 -4
- luminarycloud/params/simulation/time/time_marching/time_explicit_.py +3 -4
- luminarycloud/params/simulation/time/time_marching/time_implicit_.py +3 -4
- luminarycloud/params/simulation/time/time_marching_.py +3 -4
- luminarycloud/params/simulation/time/time_step_ramp/time_step_ramp_off_.py +3 -4
- luminarycloud/params/simulation/time/time_step_ramp/time_step_ramp_on_.py +4 -5
- luminarycloud/params/simulation/time/time_step_ramp_.py +3 -4
- luminarycloud/params/simulation/time_.py +4 -5
- luminarycloud/params/simulation/volume_entity_.py +6 -5
- luminarycloud/physics_ai/__init__.py +2 -0
- luminarycloud/physics_ai/architectures.py +42 -8
- luminarycloud/physics_ai/inference.py +0 -2
- luminarycloud/physics_ai/models.py +44 -15
- luminarycloud/project.py +54 -3
- luminarycloud/simulation_template.py +21 -6
- luminarycloud/solution.py +1 -1
- luminarycloud/types/__init__.py +2 -0
- luminarycloud/types/adfloat.py +50 -8
- luminarycloud/types/ids.py +2 -0
- luminarycloud/vis/__init__.py +12 -2
- luminarycloud/vis/data_extraction.py +546 -0
- luminarycloud/vis/display.py +61 -6
- luminarycloud/vis/filters.py +199 -43
- luminarycloud/vis/interactive_scene.py +1 -0
- luminarycloud/vis/primitives.py +38 -0
- luminarycloud/vis/vis_util.py +56 -0
- luminarycloud/vis/visualization.py +224 -70
- {luminarycloud-0.15.3.dist-info → luminarycloud-0.15.5.dist-info}/METADATA +2 -1
- {luminarycloud-0.15.3.dist-info → luminarycloud-0.15.5.dist-info}/RECORD +241 -235
- luminarycloud/_proto/luminarycloud/luminarycloud_api.pb +0 -0
- {luminarycloud-0.15.3.dist-info → luminarycloud-0.15.5.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
# Copyright 2023-2024 Luminary Cloud, Inc. All Rights Reserved.
|
|
2
|
+
import zstandard as zstd
|
|
3
|
+
import csv
|
|
4
|
+
import json
|
|
5
|
+
from .vis_util import _download_file, _InternalToken, generate_id, _get_status
|
|
6
|
+
from ..enum import ExtractStatusType, EntityType
|
|
7
|
+
from typing import List, Tuple, cast, Union
|
|
8
|
+
from abc import ABC, abstractmethod
|
|
9
|
+
from .._proto.api.v0.luminarycloud.vis import vis_pb2
|
|
10
|
+
from .primitives import Plane
|
|
11
|
+
from ..types.vector3 import _to_vector3
|
|
12
|
+
from .._client import get_default_client
|
|
13
|
+
import logging
|
|
14
|
+
from ..solution import Solution
|
|
15
|
+
from ..geometry import Geometry, get_geometry
|
|
16
|
+
from ..mesh import Mesh, get_mesh, get_mesh_metadata
|
|
17
|
+
from ..simulation import get_simulation
|
|
18
|
+
from .._helpers._get_project_id import _get_project_id
|
|
19
|
+
from .display import DisplayAttributes
|
|
20
|
+
from time import sleep, time
|
|
21
|
+
from luminarycloud.params.simulation.physics.fluid.boundary_conditions import Farfield
|
|
22
|
+
from ..exceptions import NotFoundError
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DataExtract(ABC):
|
|
28
|
+
"""
|
|
29
|
+
This is the base class for all data extracts. Each derived extract class
|
|
30
|
+
is responsible for providing a _to_proto method to convert to a filter
|
|
31
|
+
protobuf.
|
|
32
|
+
|
|
33
|
+
Attributes
|
|
34
|
+
----------
|
|
35
|
+
id: str
|
|
36
|
+
A automatically generated uniqiue filter id.
|
|
37
|
+
|
|
38
|
+
.. warning:: This feature is experimental and may change or be removed in the future.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def __init__(self, id: str) -> None:
|
|
42
|
+
self.id = id
|
|
43
|
+
self._parent_id: str = ""
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def _to_proto(self) -> vis_pb2.Filter:
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class IntersectionCurve(DataExtract):
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
Generate line data by computing intersections between solution surfaces and a slice plane.
|
|
54
|
+
|
|
55
|
+
Extracts 1D curves where surfaces intersect the specified cutting plane, preserving
|
|
56
|
+
solution field values at intersection points.
|
|
57
|
+
|
|
58
|
+
.. warning:: This feature is experimental and may change or be removed in the future.
|
|
59
|
+
|
|
60
|
+
Attributes:
|
|
61
|
+
-----------
|
|
62
|
+
plane : Plane
|
|
63
|
+
The slice plane.
|
|
64
|
+
name : str
|
|
65
|
+
A user provided name for the filter.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
def __init__(self, name: str) -> None:
|
|
69
|
+
super().__init__(generate_id("intersection-curve"))
|
|
70
|
+
self.name = name
|
|
71
|
+
self._surface_names: List[str] = []
|
|
72
|
+
self._plane = Plane()
|
|
73
|
+
self.label: str = ""
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def plane(self) -> Plane:
|
|
77
|
+
return self._plane
|
|
78
|
+
|
|
79
|
+
@plane.setter
|
|
80
|
+
def plane(self, new_plane: Plane) -> None:
|
|
81
|
+
if not isinstance(new_plane, Plane):
|
|
82
|
+
raise TypeError(f"Expected 'Plane', got {type(new_plane).__name__}")
|
|
83
|
+
self._plane = new_plane
|
|
84
|
+
|
|
85
|
+
def add_surface(self, id: str) -> None:
|
|
86
|
+
"""
|
|
87
|
+
Add a surface to compute the intersection curve on. Adding no
|
|
88
|
+
surfaces indicates that all surfaces will be used. The id can
|
|
89
|
+
either be a tag or explicit surface id. These values will be
|
|
90
|
+
validated by the DataExtractor before sending the request.
|
|
91
|
+
|
|
92
|
+
Parameters
|
|
93
|
+
----------
|
|
94
|
+
id: str
|
|
95
|
+
A surface id or a tag id.
|
|
96
|
+
"""
|
|
97
|
+
if not isinstance(id, str):
|
|
98
|
+
raise TypeError(f"Expected 'str', got {type(id).__name__}")
|
|
99
|
+
self._surface_names.append(id)
|
|
100
|
+
|
|
101
|
+
def _surfaces(self) -> List[str]:
|
|
102
|
+
"""
|
|
103
|
+
Returns the current list of surfaces.
|
|
104
|
+
"""
|
|
105
|
+
return self._surface_names
|
|
106
|
+
|
|
107
|
+
def _to_proto(self) -> vis_pb2.Filter:
|
|
108
|
+
vis_filter = vis_pb2.Filter()
|
|
109
|
+
vis_filter.id = self.id
|
|
110
|
+
vis_filter.name = self.name
|
|
111
|
+
vis_filter.intersection_curve.label = self.label
|
|
112
|
+
|
|
113
|
+
for id in self._surface_names:
|
|
114
|
+
vis_filter.intersection_curve.surfaces.append(id)
|
|
115
|
+
|
|
116
|
+
vis_filter.intersection_curve.plane.origin.CopyFrom(
|
|
117
|
+
_to_vector3(self.plane.origin)._to_proto()
|
|
118
|
+
)
|
|
119
|
+
vis_filter.intersection_curve.plane.normal.CopyFrom(
|
|
120
|
+
_to_vector3(self.plane.normal)._to_proto()
|
|
121
|
+
)
|
|
122
|
+
return vis_filter
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class ExtractOutput:
|
|
126
|
+
"""
|
|
127
|
+
The extract output represents the request to extract data from a solution,
|
|
128
|
+
and is contructed by the DataExtractor class. The operation exectutes
|
|
129
|
+
asyncronously, so the caller must check the status of the data extract. If
|
|
130
|
+
the status is completed, then the resuling data is available for download.
|
|
131
|
+
|
|
132
|
+
.. warning:: This class should not be directly instantiated by users.
|
|
133
|
+
|
|
134
|
+
.. warning:: This feature is experimental and may change or be removed in the future.
|
|
135
|
+
|
|
136
|
+
Attributes:
|
|
137
|
+
-----------
|
|
138
|
+
name: str
|
|
139
|
+
The user provided name of the extract.
|
|
140
|
+
description: str
|
|
141
|
+
The user provided description of the extract.
|
|
142
|
+
status: ExtractStatusType
|
|
143
|
+
The status of the extract (i.e., has it completed or not).
|
|
144
|
+
_extract_id: str
|
|
145
|
+
The unique indentifier of the extract.
|
|
146
|
+
_project_id: str
|
|
147
|
+
The project id associated with the extract.
|
|
148
|
+
_deleted: bool
|
|
149
|
+
Internal flag to track if the extract has been deleted.
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
def __init__(self, factory_token: _InternalToken):
|
|
153
|
+
if not isinstance(factory_token, _InternalToken):
|
|
154
|
+
raise ValueError("This class can only be constructed through the Scene class")
|
|
155
|
+
|
|
156
|
+
self._extract_id: str = ""
|
|
157
|
+
self._project_id: str = ""
|
|
158
|
+
self.status: ExtractStatusType = ExtractStatusType.INVALID
|
|
159
|
+
self.name: str = ""
|
|
160
|
+
self.description: str = ""
|
|
161
|
+
self._deleted = False
|
|
162
|
+
|
|
163
|
+
def _set_data(
|
|
164
|
+
self,
|
|
165
|
+
extract_id: str,
|
|
166
|
+
project_id: str,
|
|
167
|
+
name: str,
|
|
168
|
+
desciption: str,
|
|
169
|
+
status: ExtractStatusType,
|
|
170
|
+
) -> None:
|
|
171
|
+
self._extract_id = extract_id
|
|
172
|
+
self._project_id = project_id
|
|
173
|
+
self.status = status
|
|
174
|
+
self.name = name
|
|
175
|
+
self.description = desciption
|
|
176
|
+
|
|
177
|
+
def __repr__(self) -> str:
|
|
178
|
+
return f"ExtractOutput (Id: {self._extract_id} status: {self.status})"
|
|
179
|
+
|
|
180
|
+
def refresh(self) -> "ExtractOutput":
|
|
181
|
+
"""
|
|
182
|
+
Refesh the status of the ExtractOutput.
|
|
183
|
+
|
|
184
|
+
Returns
|
|
185
|
+
-------
|
|
186
|
+
self
|
|
187
|
+
"""
|
|
188
|
+
self._fail_if_deleted()
|
|
189
|
+
self.status = _get_status(self._project_id, self._extract_id)
|
|
190
|
+
return self
|
|
191
|
+
|
|
192
|
+
def wait(
|
|
193
|
+
self, interval_seconds: float = 4, timeout_seconds: float = float("inf")
|
|
194
|
+
) -> ExtractStatusType:
|
|
195
|
+
"""
|
|
196
|
+
Wait until the ExtractOutput is completed or failed.
|
|
197
|
+
|
|
198
|
+
Parameters
|
|
199
|
+
----------
|
|
200
|
+
interval : float, optional
|
|
201
|
+
Number of seconds between polls.
|
|
202
|
+
timeout : float, optional
|
|
203
|
+
Number of seconds before timeout.
|
|
204
|
+
|
|
205
|
+
Returns
|
|
206
|
+
-------
|
|
207
|
+
ExtractStatusType: Current status of the image extract.
|
|
208
|
+
"""
|
|
209
|
+
self._fail_if_deleted()
|
|
210
|
+
deadline = time() + timeout_seconds
|
|
211
|
+
while True:
|
|
212
|
+
self.refresh()
|
|
213
|
+
|
|
214
|
+
if self.status in [
|
|
215
|
+
ExtractStatusType.COMPLETED,
|
|
216
|
+
ExtractStatusType.FAILED,
|
|
217
|
+
ExtractStatusType.INVALID,
|
|
218
|
+
]:
|
|
219
|
+
return self.status
|
|
220
|
+
if time() >= deadline:
|
|
221
|
+
logger.error("`ExtractOutput: wait ` timed out.")
|
|
222
|
+
raise TimeoutError
|
|
223
|
+
sleep(max(-1, min(interval_seconds, deadline - time())))
|
|
224
|
+
|
|
225
|
+
def download_data(self) -> List[Tuple[List[List[Union[str, int, float]]], str]]:
|
|
226
|
+
"""
|
|
227
|
+
Downloads the resulting data into memory. This is useful
|
|
228
|
+
for plotting data in notebooks. If that status is not complete, an
|
|
229
|
+
error will be raised.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
A list of results for each extract added to the request. Each result is a tuple
|
|
233
|
+
where the first entry is a in-memory csv file (List[List[Union[str, int, float]]]).
|
|
234
|
+
The first row is the header followed by the data rows. The second entry of the tuple
|
|
235
|
+
is the label provided by the user for the DataExtract.
|
|
236
|
+
|
|
237
|
+
.. warning:: This feature is experimental and may change or be removed in the future.
|
|
238
|
+
|
|
239
|
+
"""
|
|
240
|
+
self._fail_if_deleted()
|
|
241
|
+
self.refresh()
|
|
242
|
+
if self.status != ExtractStatusType.COMPLETED:
|
|
243
|
+
raise Exception("download_data: status not complete.")
|
|
244
|
+
req = vis_pb2.DownloadExtractRequest()
|
|
245
|
+
req.extract_id = self._extract_id
|
|
246
|
+
req.project_id = self._project_id
|
|
247
|
+
res: vis_pb2.DownloadExtractResponse = get_default_client().DownloadExtract(req)
|
|
248
|
+
|
|
249
|
+
csv_files: List[Tuple[List[List[Union[str, int, float]]], str]] = []
|
|
250
|
+
if res.HasField("line_data"):
|
|
251
|
+
compressed_buffer = _download_file(res.line_data)
|
|
252
|
+
dctx = zstd.ZstdDecompressor()
|
|
253
|
+
decompressed_size = zstd.frame_content_size(compressed_buffer.getvalue())
|
|
254
|
+
serializedTable = dctx.decompress(
|
|
255
|
+
compressed_buffer.getvalue(), max_output_size=decompressed_size
|
|
256
|
+
)
|
|
257
|
+
line_data = vis_pb2.LineDataExtract()
|
|
258
|
+
# If uncompressed: this is
|
|
259
|
+
# line_data.ParseFromString(line_data_buffer.read())
|
|
260
|
+
line_data.ParseFromString(serializedTable)
|
|
261
|
+
ids = line_data.lines.keys()
|
|
262
|
+
# Each filter(id) produces a set of tables, one per line segment.
|
|
263
|
+
for id in ids:
|
|
264
|
+
header: List[Union[str, float, int]] = []
|
|
265
|
+
tables = line_data.lines[id]
|
|
266
|
+
# One table per line segment. First, figure out the
|
|
267
|
+
# shape of the data and validate what we expect.
|
|
268
|
+
total_rows = 0
|
|
269
|
+
n_cols = 0
|
|
270
|
+
for _, table in enumerate(tables.lines_table):
|
|
271
|
+
assert len(table.axis) == 1
|
|
272
|
+
assert len(table.record) == 1
|
|
273
|
+
n_rows = len(table.axis[0].coordinate)
|
|
274
|
+
total_rows += n_rows
|
|
275
|
+
n_cols = len(table.header.record_label)
|
|
276
|
+
if len(header) == 0:
|
|
277
|
+
for _, label in enumerate(table.header.record_label):
|
|
278
|
+
header.append(label.name)
|
|
279
|
+
# We also have a curve id we need to add.
|
|
280
|
+
header.append("curve id")
|
|
281
|
+
# verify what we expect to see
|
|
282
|
+
assert n_rows * n_cols == len(table.record[0].entry)
|
|
283
|
+
assert len(header) != 0
|
|
284
|
+
assert n_cols != 0
|
|
285
|
+
rows: List[List[Union[str, float, int]]] = []
|
|
286
|
+
rows.append(header)
|
|
287
|
+
for curve_id, table in enumerate(tables.lines_table):
|
|
288
|
+
n_rows = len(table.axis[0].coordinate)
|
|
289
|
+
new_rows: List[List[Union[str, float, int]]] = []
|
|
290
|
+
idx = 0
|
|
291
|
+
# The the shape of the values are in row-major ordering.
|
|
292
|
+
for r in range(n_rows):
|
|
293
|
+
row: List[Union[str, float, int]] = []
|
|
294
|
+
for c in range(n_cols):
|
|
295
|
+
row.append(table.record[0].entry[idx].adfloat.value)
|
|
296
|
+
idx += 1
|
|
297
|
+
new_rows.append(row)
|
|
298
|
+
# Now add the curve id to all the rows.
|
|
299
|
+
for row in new_rows:
|
|
300
|
+
row.append(curve_id)
|
|
301
|
+
rows = rows + new_rows
|
|
302
|
+
csv_files.append((rows, line_data.labels[id]))
|
|
303
|
+
return csv_files
|
|
304
|
+
|
|
305
|
+
def save_files(self, file_prefix: str, write_labels: bool = False) -> None:
|
|
306
|
+
"""
|
|
307
|
+
A helper for downloading and save resulting csv files to the file system. If that status is not
|
|
308
|
+
complete, an error will be raised. csv_files will be of the form {file_prefix}_{index}.csv.
|
|
309
|
+
Optionally, a file will be written containing a list of file names and image labels. Labels
|
|
310
|
+
are an optional field in the DataExtracts.
|
|
311
|
+
|
|
312
|
+
.. warning:: This feature is experimental and may change or be removed in the future.
|
|
313
|
+
|
|
314
|
+
Parameters
|
|
315
|
+
----------
|
|
316
|
+
file_prefix: str, required
|
|
317
|
+
The file prefix to save the extract. A file index and '.csv' will be
|
|
318
|
+
appended to the file names.
|
|
319
|
+
write_labels: bool, optional
|
|
320
|
+
Write a json file containing a list of csv file names and labels,
|
|
321
|
+
if True. The resulting json file is named '{file_prefix}.json' Default: False
|
|
322
|
+
"""
|
|
323
|
+
if not file_prefix:
|
|
324
|
+
raise ValueError("file_prefix must be non-empty")
|
|
325
|
+
|
|
326
|
+
csv_files = self.download_data()
|
|
327
|
+
names_labels: List[Tuple[str, str]] = []
|
|
328
|
+
counter = 0
|
|
329
|
+
for csv_file in csv_files:
|
|
330
|
+
output_file = f"{file_prefix}_{counter}.csv"
|
|
331
|
+
with open(output_file, "w", newline="") as file:
|
|
332
|
+
writer = csv.writer(file)
|
|
333
|
+
writer.writerows(csv_file[0])
|
|
334
|
+
counter = counter + 1
|
|
335
|
+
names_labels.append((output_file, csv_file[1]))
|
|
336
|
+
if write_labels:
|
|
337
|
+
with open(f"{file_prefix}.json", "w") as json_file:
|
|
338
|
+
json.dump(names_labels, json_file, indent=1)
|
|
339
|
+
|
|
340
|
+
def _fail_if_deleted(self) -> None:
|
|
341
|
+
if self._deleted:
|
|
342
|
+
raise ValueError("RenderOutput has been deleted.")
|
|
343
|
+
|
|
344
|
+
def delete(self) -> None:
|
|
345
|
+
"""Delete the the extracts."""
|
|
346
|
+
self._fail_if_deleted()
|
|
347
|
+
req = vis_pb2.DeleteExtractRequest()
|
|
348
|
+
req.extract_id = self._extract_id
|
|
349
|
+
req.project_id = self._project_id
|
|
350
|
+
get_default_client().DeleteExtract(req)
|
|
351
|
+
self._deleted = True
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class DataExtractor:
|
|
355
|
+
"""
|
|
356
|
+
I extract data from solutions.
|
|
357
|
+
|
|
358
|
+
.. warning:: This feature is experimental and may change or be removed in the future.
|
|
359
|
+
|
|
360
|
+
"""
|
|
361
|
+
|
|
362
|
+
def __init__(self, solution: Solution):
|
|
363
|
+
if not isinstance(solution, Solution):
|
|
364
|
+
raise TypeError(f"Expected Solution got {type(solution).__name__}")
|
|
365
|
+
self._solution: Solution = solution
|
|
366
|
+
self._entity_type: EntityType = EntityType.SIMULATION
|
|
367
|
+
self._extracts: List[DataExtract] = []
|
|
368
|
+
|
|
369
|
+
# Meshes that are directly uploaded will not have tags.
|
|
370
|
+
self._has_tags: bool = True
|
|
371
|
+
|
|
372
|
+
project_id = _get_project_id(solution)
|
|
373
|
+
if not project_id:
|
|
374
|
+
raise ValueError("Unable to get project id from solution")
|
|
375
|
+
|
|
376
|
+
self._project_id = project_id
|
|
377
|
+
|
|
378
|
+
# Trace each entity all the way back to the geometry so we
|
|
379
|
+
# can accesss the tags, if they are present.
|
|
380
|
+
geom: Geometry | None = None
|
|
381
|
+
simulation = get_simulation(self._solution.simulation_id)
|
|
382
|
+
mesh_meta = get_mesh_metadata(simulation.mesh_id)
|
|
383
|
+
mesh = get_mesh(simulation.mesh_id)
|
|
384
|
+
try:
|
|
385
|
+
geom = mesh.geometry_version().geometry()
|
|
386
|
+
except NotFoundError:
|
|
387
|
+
self._has_tags = False
|
|
388
|
+
except Exception as e:
|
|
389
|
+
raise ValueError("An unknow error occurred retrieving tags")
|
|
390
|
+
|
|
391
|
+
self._surface_ids: List[str] = []
|
|
392
|
+
for zone in mesh_meta.zones:
|
|
393
|
+
for bound in zone.boundaries:
|
|
394
|
+
self._surface_ids.append(bound.name)
|
|
395
|
+
|
|
396
|
+
self._tag_ids: List[str] = []
|
|
397
|
+
if geom and self._has_tags:
|
|
398
|
+
tags = geom.list_tags()
|
|
399
|
+
for tag in tags:
|
|
400
|
+
self._tag_ids.append(tag.id)
|
|
401
|
+
|
|
402
|
+
self.far_field_boundary_ids: List[str] = []
|
|
403
|
+
|
|
404
|
+
# Find all the far field surfaces if we can get the params.
|
|
405
|
+
params = simulation.get_parameters()
|
|
406
|
+
for physics in params.physics:
|
|
407
|
+
if physics.fluid:
|
|
408
|
+
for bc in physics.fluid.boundary_conditions:
|
|
409
|
+
if isinstance(bc, Farfield):
|
|
410
|
+
for bc_surface in bc.surfaces:
|
|
411
|
+
self.far_field_boundary_ids.append(bc_surface)
|
|
412
|
+
|
|
413
|
+
def _validate_surfaces_and_tags(self, ids: List[str]) -> List[str]:
|
|
414
|
+
"""
|
|
415
|
+
Validate a list of ids as either tags or ids. Returns a list of invalid ids. If the
|
|
416
|
+
length of the list is zero, the input list is valid.
|
|
417
|
+
"""
|
|
418
|
+
bad_ids: List[str] = []
|
|
419
|
+
for id in ids:
|
|
420
|
+
if id in self._tag_ids:
|
|
421
|
+
continue
|
|
422
|
+
if id not in self._surface_ids:
|
|
423
|
+
bad_ids.append(id)
|
|
424
|
+
return bad_ids
|
|
425
|
+
|
|
426
|
+
def surface_ids(self) -> List[str]:
|
|
427
|
+
"""Get a list of all the surface ids associated with the solution."""
|
|
428
|
+
return self._surface_ids
|
|
429
|
+
|
|
430
|
+
def tag_ids(self) -> List[str]:
|
|
431
|
+
"""Get a list of all the tag ids associated with the solution."""
|
|
432
|
+
return self._tag_ids
|
|
433
|
+
|
|
434
|
+
def add_data_extract(self, extract: DataExtract) -> None:
|
|
435
|
+
"""
|
|
436
|
+
Add a data extract.
|
|
437
|
+
"""
|
|
438
|
+
if not isinstance(extract, DataExtract):
|
|
439
|
+
raise TypeError(f"Expected 'Filter', got {type(extract).__name__}")
|
|
440
|
+
self._extracts.append(extract)
|
|
441
|
+
|
|
442
|
+
def _create_request(self, name: str, description: str) -> vis_pb2.CreateExtractRequest:
|
|
443
|
+
req = vis_pb2.CreateExtractRequest()
|
|
444
|
+
|
|
445
|
+
# We have to add a bunch of dummy params to get the request to go through the same
|
|
446
|
+
# path as filters.
|
|
447
|
+
req.spec.global_display_attributes.CopyFrom(DisplayAttributes()._to_proto())
|
|
448
|
+
req.spec.animation_properties
|
|
449
|
+
req.spec.data_only = True
|
|
450
|
+
for extract in self._extracts:
|
|
451
|
+
if isinstance(extract, IntersectionCurve):
|
|
452
|
+
# Validate surfaces names
|
|
453
|
+
icurve = cast(IntersectionCurve, extract)
|
|
454
|
+
bad_ids = self._validate_surfaces_and_tags(icurve._surface_names)
|
|
455
|
+
if len(bad_ids) != 0:
|
|
456
|
+
raise ValueError(f"IntersectionCurve has invalid surfaces: {bad_ids}")
|
|
457
|
+
|
|
458
|
+
if isinstance(extract, DataExtract):
|
|
459
|
+
vis_filter: vis_pb2.Filter = extract._to_proto()
|
|
460
|
+
req.spec.filters.append(vis_filter)
|
|
461
|
+
# Add dummy display attrs
|
|
462
|
+
req.spec.display_attributes[extract.id].CopyFrom(DisplayAttributes()._to_proto())
|
|
463
|
+
else:
|
|
464
|
+
raise TypeError(f"Expected 'filter', got {type(filter).__name__}")
|
|
465
|
+
|
|
466
|
+
req.project_id = self._project_id
|
|
467
|
+
req.spec.entity_type.simulation.id = self._solution.simulation_id
|
|
468
|
+
req.spec.entity_type.simulation.solution_id = self._solution.id
|
|
469
|
+
req.spec.name = name
|
|
470
|
+
req.spec.description = description
|
|
471
|
+
return req
|
|
472
|
+
|
|
473
|
+
def create_extracts(self, name: str, description: str) -> ExtractOutput:
|
|
474
|
+
"""
|
|
475
|
+
Create a request to extract data from a solution.
|
|
476
|
+
|
|
477
|
+
Parameters
|
|
478
|
+
----------
|
|
479
|
+
name : str
|
|
480
|
+
A short name for the the extracts.
|
|
481
|
+
description : str
|
|
482
|
+
A longer description of the extracts.
|
|
483
|
+
"""
|
|
484
|
+
req: vis_pb2.CreateExtractRequest = self._create_request(name=name, description=description)
|
|
485
|
+
res: vis_pb2.CreateExtractResponse = get_default_client().CreateExtract(req)
|
|
486
|
+
extract_output = ExtractOutput(_InternalToken())
|
|
487
|
+
extract_output._set_data(
|
|
488
|
+
extract_id=res.extract.extract_id,
|
|
489
|
+
project_id=self._project_id,
|
|
490
|
+
name=name,
|
|
491
|
+
desciption=description,
|
|
492
|
+
status=ExtractStatusType(res.extract.status),
|
|
493
|
+
)
|
|
494
|
+
return extract_output
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
def list_data_extracts(solution: Solution) -> List[ExtractOutput]:
|
|
498
|
+
"""
|
|
499
|
+
Lists all previously created data extract associated with a project and a solution.
|
|
500
|
+
|
|
501
|
+
.. warning:: This feature is experimental and may change or be removed in the future.
|
|
502
|
+
|
|
503
|
+
Parameters
|
|
504
|
+
----------
|
|
505
|
+
project_id : str
|
|
506
|
+
The project id to query.
|
|
507
|
+
entity : Geometry | Mesh | Solution
|
|
508
|
+
Specifies what types of rendering extracts to list(e.g., geometry, mesh or solution).
|
|
509
|
+
|
|
510
|
+
"""
|
|
511
|
+
|
|
512
|
+
# Find out what we are working on.
|
|
513
|
+
if not isinstance(solution, Solution):
|
|
514
|
+
raise TypeError(f"Expected Solution got {type(solution).__name__}")
|
|
515
|
+
|
|
516
|
+
entity_type = EntityType.SIMULATION
|
|
517
|
+
project_id = _get_project_id(solution)
|
|
518
|
+
if not project_id:
|
|
519
|
+
raise ValueError("Unable to get project id from solution")
|
|
520
|
+
|
|
521
|
+
req = vis_pb2.ListExtractsRequest()
|
|
522
|
+
req.project_id = project_id
|
|
523
|
+
|
|
524
|
+
sim_entity = cast(Solution, solution)
|
|
525
|
+
req.entity.simulation.id = sim_entity.simulation_id
|
|
526
|
+
req.entity.simulation.solution_id = sim_entity.id
|
|
527
|
+
|
|
528
|
+
# We are requesting data not images
|
|
529
|
+
req.data_only = True
|
|
530
|
+
res: vis_pb2.ListExtractsResponse = get_default_client().ListExtracts(req)
|
|
531
|
+
|
|
532
|
+
results: List[ExtractOutput] = []
|
|
533
|
+
for extract in res.extracts:
|
|
534
|
+
result = ExtractOutput(_InternalToken())
|
|
535
|
+
result._set_data(
|
|
536
|
+
extract_id=extract.extract_id,
|
|
537
|
+
project_id=extract.project_id,
|
|
538
|
+
name=extract.name,
|
|
539
|
+
desciption=extract.description,
|
|
540
|
+
status=ExtractStatusType(extract.status),
|
|
541
|
+
)
|
|
542
|
+
# This need to be fixed on the backend, but manually refreshing works for now.
|
|
543
|
+
result.refresh()
|
|
544
|
+
results.append(result)
|
|
545
|
+
|
|
546
|
+
return results
|
luminarycloud/vis/display.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
# Copyright 2023-2024 Luminary Cloud, Inc. All Rights Reserved.
|
|
1
2
|
import dataclasses as dc
|
|
2
3
|
from luminarycloud.enum import Representation, ColorMapPreset, FieldComponent, VisQuantity
|
|
3
4
|
from .._proto.api.v0.luminarycloud.vis import vis_pb2
|
|
4
5
|
from typing import Optional
|
|
6
|
+
import luminarycloud.enum.quantity_type as quantity_type
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
@dc.dataclass
|
|
@@ -16,15 +18,33 @@ class Field:
|
|
|
16
18
|
|
|
17
19
|
quantity: VisQuantity = VisQuantity.ABSOLUTE_PRESSURE
|
|
18
20
|
"""The quantity to color by."""
|
|
19
|
-
component: FieldComponent = FieldComponent.
|
|
21
|
+
component: FieldComponent = FieldComponent.MAGNITUDE
|
|
20
22
|
"""
|
|
21
23
|
The component of the field to use, applicable to vector fields. If the field is a
|
|
22
|
-
scalar,
|
|
24
|
+
scalar, the component field is ignored. Default: MAGNITUDE.
|
|
23
25
|
"""
|
|
24
26
|
|
|
25
27
|
def __hash__(self) -> int:
|
|
26
28
|
return hash((self.quantity, self.component))
|
|
27
29
|
|
|
30
|
+
def _to_proto(self) -> vis_pb2.Field:
|
|
31
|
+
field = vis_pb2.Field()
|
|
32
|
+
field.quantity_typ = self.quantity.value
|
|
33
|
+
if quantity_type._is_vector(self.quantity):
|
|
34
|
+
field.component = self.component.value
|
|
35
|
+
else:
|
|
36
|
+
field.component = vis_pb2.Field.COMPONENT_UNSPECIFIED
|
|
37
|
+
return field
|
|
38
|
+
|
|
39
|
+
def _from_proto(self, field: vis_pb2.Field) -> None:
|
|
40
|
+
self.quantity = VisQuantity(field.quantity_typ)
|
|
41
|
+
if quantity_type._is_vector(self.quantity):
|
|
42
|
+
if field.component == vis_pb2.Field.COMPONENT_UNSPECIFIED:
|
|
43
|
+
raise ValueError("vector field must specify a component.")
|
|
44
|
+
else:
|
|
45
|
+
self.component = FieldComponent(field.component)
|
|
46
|
+
# If its a scalar, just ignore the component.
|
|
47
|
+
|
|
28
48
|
|
|
29
49
|
@dc.dataclass
|
|
30
50
|
class DisplayAttributes:
|
|
@@ -56,10 +76,14 @@ class DisplayAttributes:
|
|
|
56
76
|
attrs = vis_pb2.DisplayAttributes()
|
|
57
77
|
attrs.visible = self.visible
|
|
58
78
|
attrs.representation = self.representation.value
|
|
59
|
-
attrs.field.
|
|
60
|
-
attrs.field.quantity_typ = self.field.quantity.value
|
|
79
|
+
attrs.field.CopyFrom(self.field._to_proto())
|
|
61
80
|
return attrs
|
|
62
81
|
|
|
82
|
+
def _from_proto(self, attrs: vis_pb2.DisplayAttributes) -> None:
|
|
83
|
+
self.visible = attrs.visible
|
|
84
|
+
self.representation = Representation(attrs.representation)
|
|
85
|
+
self.field._from_proto(attrs.field)
|
|
86
|
+
|
|
63
87
|
|
|
64
88
|
@dc.dataclass
|
|
65
89
|
class DataRange:
|
|
@@ -167,8 +191,7 @@ class ColorMap:
|
|
|
167
191
|
|
|
168
192
|
def _to_proto(self) -> vis_pb2.ColorMap:
|
|
169
193
|
res: vis_pb2.ColorMap = vis_pb2.ColorMap()
|
|
170
|
-
res.field.
|
|
171
|
-
res.field.quantity_typ = self.field.quantity.value
|
|
194
|
+
res.field.CopyFrom(self.field._to_proto())
|
|
172
195
|
res.name = self.preset.value
|
|
173
196
|
res.discretize = self.discretize
|
|
174
197
|
res.n_colors = self.n_colors
|
|
@@ -188,3 +211,35 @@ class ColorMap:
|
|
|
188
211
|
res.lower_left_anchor_location.y = self.appearance.lower_left_y
|
|
189
212
|
res.text_size = self.appearance.text_size
|
|
190
213
|
return res
|
|
214
|
+
|
|
215
|
+
def _from_proto(self, color_map: vis_pb2.ColorMap) -> None:
|
|
216
|
+
self.field = Field(
|
|
217
|
+
component=FieldComponent(color_map.field.component),
|
|
218
|
+
quantity=VisQuantity(color_map.field.quantity_typ),
|
|
219
|
+
)
|
|
220
|
+
if color_map.HasField("range"):
|
|
221
|
+
self.data_range = DataRange(
|
|
222
|
+
min_value=color_map.range.min,
|
|
223
|
+
max_value=color_map.range.max,
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
self.preset = ColorMapPreset(color_map.name)
|
|
227
|
+
|
|
228
|
+
if color_map.HasField("discretize"):
|
|
229
|
+
self.discretize = color_map.discretize
|
|
230
|
+
if color_map.HasField("n_colors"):
|
|
231
|
+
self.n_colors = color_map.n_colors
|
|
232
|
+
|
|
233
|
+
self.appearance = ColorMapAppearance()
|
|
234
|
+
if color_map.HasField("visible"):
|
|
235
|
+
self.appearance.visible = color_map.visible
|
|
236
|
+
l_typ = color_map.WhichOneof("location")
|
|
237
|
+
if l_typ == "lower_left_anchor_location":
|
|
238
|
+
self.appearance.lower_left_x = color_map.lower_left_anchor_location.x
|
|
239
|
+
self.appearance.lower_left_y = color_map.lower_left_anchor_location.y
|
|
240
|
+
if color_map.HasField("text_size"):
|
|
241
|
+
self.appearance.text_size = int(color_map.text_size)
|
|
242
|
+
if color_map.HasField("width"):
|
|
243
|
+
self.appearance.width = color_map.width
|
|
244
|
+
if color_map.HasField("height"):
|
|
245
|
+
self.appearance.height = color_map.height
|