diff --git a/doc/changelog.d/2444.maintenance.md b/doc/changelog.d/2444.maintenance.md new file mode 100644 index 0000000000..a42f1cf393 --- /dev/null +++ b/doc/changelog.d/2444.maintenance.md @@ -0,0 +1 @@ +Chore: v1 implementation of beam stub diff --git a/src/ansys/geometry/core/_grpc/_services/v1/beams.py b/src/ansys/geometry/core/_grpc/_services/v1/beams.py index c45305b103..f20aa44265 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/beams.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/beams.py @@ -24,8 +24,22 @@ import grpc from ansys.geometry.core.errors import protect_grpc +from ansys.geometry.core.misc.measurements import DEFAULT_UNITS from ..base.beams import GRPCBeamsService +from ..base.conversions import to_distance +from .conversions import ( + build_grpc_id, + from_grpc_angle_to_angle, + from_grpc_curve_to_curve, + from_grpc_frame_to_frame, + from_grpc_material_to_material, + from_grpc_point_to_point3d, + from_grpc_quantity_to_distance, + from_grpc_quantity_to_float, + from_plane_to_grpc_plane, + from_point3d_to_grpc_point, +) class GRPCBeamsServiceV1(GRPCBeamsService): @@ -43,26 +57,203 @@ class GRPCBeamsServiceV1(GRPCBeamsService): @protect_grpc def __init__(self, channel: grpc.Channel): # noqa: D102 - from ansys.api.discovery.v1.assignments.beams import BeamsStub + from ansys.api.discovery.v1.design.extensions.beam_pb2_grpc import ( + BeamStub, + ) + from ansys.api.discovery.v1.engineeringdata.beamprofiledata_pb2_grpc import ( + BeamProfileDataStub, + ) - self.stub = BeamsStub(channel) + self.beam_profile_commands_stub = BeamProfileDataStub(channel) + self.beam_commands_stub = BeamStub(channel) @protect_grpc def create_beam_segments(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.commonmessages_pb2 import Line + from ansys.api.discovery.v1.engineeringdata.beamprofiledata_pb2 import ( + CreateBeamProfileSegmentsRequest, + CreateBeamProfileSegmentsRequestData, + ) + + # Create the gRPC Line objects + lines = [] + for segment in kwargs["segments"]: + lines.append( + Line( + start=from_point3d_to_grpc_point(segment[0]), + end=from_point3d_to_grpc_point(segment[1]), + ) + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = CreateBeamProfileSegmentsRequest( + request_data=[ + CreateBeamProfileSegmentsRequestData( + profile_id=build_grpc_id(kwargs["profile_id"]), + parent_id=build_grpc_id(kwargs["parent_id"]), + lines=lines, + ) + ] + ) + + # Call the gRPC service + response = self.beam_profile_commands_stub.CreateSegments(request) + + # Return the response - formatted as a dictionary + return { + "beam_ids": [ + [beam.id for beam in response_data.beams_ids] + for response_data in response.response_data + ] + } @protect_grpc def create_descriptive_beam_segments(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.commonmessages_pb2 import Line + from ansys.api.discovery.v1.engineeringdata.beamprofiledata_pb2 import ( + CreateBeamProfileSegmentsRequest, + CreateBeamProfileSegmentsRequestData, + ) + + from ansys.geometry.core.shapes.parameterization import Interval, ParamUV + + # Create the gRPC Line objects + lines = [] + for segment in kwargs["segments"]: + lines.append( + Line( + start=from_point3d_to_grpc_point(segment[0]), + end=from_point3d_to_grpc_point(segment[1]), + ) + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = CreateBeamProfileSegmentsRequest( + request_data=[ + CreateBeamProfileSegmentsRequestData( + profile_id=build_grpc_id(kwargs["profile_id"]), + parent_id=build_grpc_id(kwargs["parent_id"]), + lines=lines, + ) + ] + ) + + # Call the gRPC service + response = self.beam_profile_commands_stub.CreateDescriptiveSegments(request) + + # Return the response - formatted as a dictionary + return { + "created_beams": [ + { + "cross_section": { + "section_anchor": beam.cross_section.section_anchor, + "section_angle": ( + from_grpc_angle_to_angle(beam.cross_section.section_angle) + ).m_as(DEFAULT_UNITS.SERVER_ANGLE), + "section_frame": from_grpc_frame_to_frame(beam.cross_section.section_frame), + "section_profile": [ + [ + { + "geometry": from_grpc_curve_to_curve(curve.curve), + "start": from_grpc_point_to_point3d(curve.start), + "end": from_grpc_point_to_point3d(curve.end), + "interval": Interval(curve.interval_start, curve.interval_end), + "length": to_distance(curve.length).value, + } + for curve in curve_list.curves + ] + for curve_list in beam.cross_section.section_profile + ], + }, + "properties": { + "area": from_grpc_quantity_to_float(beam.properties.area), + "centroid": ParamUV(beam.properties.centroid_x, beam.properties.centroid_y), + "warping_constant": from_grpc_quantity_to_float( + beam.properties.warping_constant + ), + "ixx": from_grpc_quantity_to_float(beam.properties.ixx), + "ixy": from_grpc_quantity_to_float(beam.properties.ixy), + "iyy": from_grpc_quantity_to_float(beam.properties.iyy), + "shear_center": ParamUV( + beam.properties.shear_center_x, beam.properties.shear_center_y + ), + "torsional_constant": from_grpc_quantity_to_float( + beam.properties.torsional_constant + ), + }, + "id": beam.id.id, + "start": from_grpc_point_to_point3d(beam.shape.start), + "end": from_grpc_point_to_point3d(beam.shape.end), + "name": beam.name, + "is_deleted": beam.is_deleted, + "is_reversed": beam.is_reversed, + "is_rigid": beam.is_rigid, + "material": from_grpc_material_to_material(beam.material), + "shape": { + "geometry": from_grpc_curve_to_curve(beam.shape.curve), + "start": from_grpc_point_to_point3d(beam.shape.start), + "end": from_grpc_point_to_point3d(beam.shape.end), + "interval": Interval(beam.shape.interval_start, beam.shape.interval_end), + "length": from_grpc_quantity_to_distance(beam.shape.length), + }, + "beam_type": beam.type, + } + for response_data in response.response_data + for beam in response_data.beams + ], + } @protect_grpc def delete_beam(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.commonmessages_pb2 import MultipleEntitiesRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["beam_id"])]) + + # Call the gRPC service + _ = self.beam_commands_stub.Delete(request) + + # Return the response - formatted as a dictionary + return {} @protect_grpc def delete_beam_profile(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.commonmessages_pb2 import MultipleEntitiesRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + _ = self.beam_profile_commands_stub.Delete(request) + + # Return the response - formatted as a dictionary + return {} @protect_grpc def create_beam_circular_profile(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.engineeringdata.beamprofiledata_pb2 import ( + CreateBeamProfileCircularRequest, + CreateBeamProfileCircularRequestData, + ) + + from .conversions import from_length_to_grpc_quantity + + # Create the request - assumes all inputs are valid and of the proper type + request = CreateBeamProfileCircularRequest( + request_data=[ + CreateBeamProfileCircularRequestData( + origin=from_point3d_to_grpc_point(kwargs["center"]), + radius=from_length_to_grpc_quantity(kwargs["radius"]), + plane=from_plane_to_grpc_plane(kwargs["plane"]), + name=kwargs["name"], + ) + ] + ) + + # Call the gRPC service + response = self.beam_profile_commands_stub.CreateCircular(request) + + # Return the response - formatted as a dictionary + # Note: response.ids is a repeated field, we return the first one + created_beam_entity = response.ids[0] + return {"id": created_beam_entity.id} diff --git a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py index 3dcf779609..9eb2f770a2 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py @@ -1428,6 +1428,22 @@ def from_length_to_grpc_quantity(input: "Distance") -> GRPCQuantity: return GRPCQuantity(value_in_geometry_units=input.value.m_as(DEFAULT_UNITS.SERVER_LENGTH)) +def from_grpc_quantity_to_distance(input: "GRPCQuantity") -> Distance: + """Convert a gRPC quantity to ``Distance`` containing a length. + + Parameters + ---------- + input : GRPCQuantity + Source measurement data. + + Returns + ------- + Distance + Converted Distance quantity. + """ + return Distance(input.value_in_geometry_units, DEFAULT_UNITS.SERVER_LENGTH) + + def from_angle_to_grpc_quantity(input: "Measurement") -> GRPCQuantity: """Convert a ``Measurement`` containing an angle to a gRPC quantity. @@ -1444,6 +1460,22 @@ def from_angle_to_grpc_quantity(input: "Measurement") -> GRPCQuantity: return GRPCQuantity(value_in_geometry_units=input.value.m_as(DEFAULT_UNITS.SERVER_ANGLE)) +def from_grpc_angle_to_angle(grpc_quantity: GRPCQuantity) -> "pint.Quantity": + """Convert a gRPC quantity representing an angle to a pint Quantity. + + Parameters + ---------- + grpc_quantity : GRPCQuantity + Source gRPC quantity data. + + Returns + ------- + Measurement + Converted angle quantity with server angle units. + """ + return pint.Quantity(grpc_quantity.value_in_geometry_units, DEFAULT_UNITS.SERVER_ANGLE) + + def from_area_to_grpc_quantity(input: "Measurement") -> GRPCQuantity: """Convert a ``Measurement`` containing an area to a gRPC quantity. @@ -1492,6 +1524,22 @@ def from_grpc_volume_to_volume(grpc_quantity: GRPCQuantity) -> "pint.Quantity": return pint.Quantity(grpc_quantity.value_in_geometry_units, DEFAULT_UNITS.SERVER_VOLUME) +def from_grpc_quantity_to_float(grpc_quantity: GRPCQuantity) -> float: + """Convert a gRPC quantity to a float. + + Parameters + ---------- + grpc_quantity : GRPCQuantity + Source gRPC quantity data. + + Returns + ------- + float + The float value contained in the quantity. + """ + return grpc_quantity.value_in_geometry_units + + def from_parameter_to_grpc_quantity(value: float) -> GRPCQuantity: """Convert a dimensionless parameter to a gRPC quantity.