Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ classifiers = [
]

dependencies = [
"ansys-api-sherlock==0.1.29",
"ansys-api-sherlock==0.1.30",
"grpcio>=1.17",
"importlib-metadata>=4.0,<5; python_version<='3.8'",
"protobuf~=3.20",
Expand Down
17 changes: 17 additions & 0 deletions src/ansys/sherlock/core/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -1183,3 +1183,20 @@ def __init__(self, message):
def __str__(self):
"""Format error message."""
return f"Export FEA model error: {self.message}"


class SherlockAddModelingRegionError(Exception):
"""Contains the errors raised when modeling regions for a project cannot be added."""

def __init__(self, message=None, error_array=None):
"""Initialize error message."""
self.message = message
self.error_array = error_array

def str_itr(self):
"""Format error message."""
if self.message is None:
return [f"Add modeling region error: {error}" for error in self.error_array]

assert self.error_array is None
return [f"Add modeling region error: {self.message}"]
269 changes: 269 additions & 0 deletions src/ansys/sherlock/core/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@

try:
import SherlockLayerService_pb2
from SherlockLayerService_pb2 import ModelingRegion
import SherlockLayerService_pb2_grpc
except ModuleNotFoundError:
from ansys.api.sherlock.v0 import SherlockLayerService_pb2
from ansys.api.sherlock.v0 import SherlockLayerService_pb2_grpc
from ansys.api.sherlock.v0.SherlockLayerService_pb2 import ModelingRegion

from typing import Dict, List, Union

from ansys.sherlock.core import LOG
from ansys.sherlock.core.errors import (
SherlockAddModelingRegionError,
SherlockAddPottingRegionError,
SherlockDeleteAllICTFixturesError,
SherlockDeleteAllMountPointsError,
Expand Down Expand Up @@ -889,3 +894,267 @@ def export_all_mount_points(
raise e

return response.value

def add_modeling_region(
self,
project: str,
modeling_regions: List[Dict[str, Union[str, float, bool, dict]]],
):
"""
Add one or more modeling regions to a specific project.

Parameters
----------
project : str
Name of the Sherlock project.
modeling_regions : list of dict
List of modeling regions to add. Each dictionary should contain:

- cca_name : str
Name of the CCA.
- region_id : str
Unique region ID of the modeling region.
- region_units : str
Units of the modeling region.
- model_mode : str
Mode that specifies how the region is used. Valid values are ``Enabled``,
``Disabled`` and ``Excluded``.
- shape: PolygonalShape|RectangularShape|SlotShape|CircularShape|PCBShape
The shape of the modeling region.
- pcb_model_props : list
List of the PCB model parameters consisting of these properties:

- export_model_type : str
The type of model to be generated for a given modeling region.
Valid values are ``Default``, ``Sherlock``, ``Sweep`` and ``None``.
- elem_order: str
The type of 3D elements to be created for the PCB in the modeling region.
Valid values are ``First_Order``, ``Second_Order`` and ``Solid_Shell``.
- max_mesh_size : float
The maximum size of the mesh to be used in the region.
- max_mesh_size_units : str
Units for the maximum mesh size.
- quads_preferred : bool
Whether to generate quad-shaped elements when creating the mesh if true.
- trace_model_props : list
List of the trace model parameters consisting of these properties:

- trace_model_type : str
The specification of whether trace modeling should be performed
within the region. Valid values are ``Default``, ``Enabled`` and
``Disabled``.
- elem_order: str, optional
The type of 3D elements to be created for the PCB in the modeling region.
Valid values are ``First_Order``, ``Second_Order`` and ``Solid_Shell``.
- trace_mesh_size : float, optional
The maximum mesh size to be used in the region when trace modeling
is enabled.
- trace_mesh_size_units: str, optional
Units for the maximum mesh size when trace modeling is enabled.


Returns
-------
int
Status code of the response. 0 for success.

Examples
--------
>>> from ansys.sherlock.core.launcher import launch_sherlock
>>> sherlock = launch_sherlock()
>>> sherlock.project.import_odb_archive(
"ODB++ Tutorial.tgz",
True,
True,
True,
True,
project="Tutorial Project",
cca_name="Card",
)
>>> modeling_regions = [
{
"cca_name": "Card",
"region_id": "Region001",
"region_units": "mm",
"model_mode": "Enabled",
"shape": PolygonalShape(points=[
(0, 0),
(0, 6.35),
(9.77, 0)
], rotation=87.8),
"pcb_model_props": {
"export_model_type": "Sherlock",
"elem_order": "First_Order",
"max_mesh_size": 0.5,
"max_mesh_size_units": "mm",
"quads_preferred": True
},
"trace_model_props": {
"trace_model_type": "Enabled",
"elem_order": "Second_Order",
"trace_mesh_size": 0.3,
"trace_mesh_size_units": "mm"
}
}
]
>>> result = sherlock.project.add_modeling_region("Tutorial Project", modeling_regions)
"""
try:
if not project:
raise SherlockAddModelingRegionError(message="Project name is invalid.")

if not modeling_regions:
raise SherlockAddModelingRegionError(message="Modeling regions list is empty.")

for region in modeling_regions:
if "cca_name" not in region or not region["cca_name"]:
raise SherlockAddModelingRegionError(message="CCA name is invalid.")
if "region_id" not in region or not region["region_id"]:
raise SherlockAddModelingRegionError(message="Region ID is invalid.")
if "region_units" not in region or not region["region_units"]:
raise SherlockAddModelingRegionError(message="Region units are invalid.")
if "shape" not in region:
raise SherlockAddModelingRegionError(message="Shape is missing.")
elif not isinstance(
region["shape"],
(
PolygonalShape,
RectangularShape,
SlotShape,
CircularShape,
PCBShape,
),
):
raise SherlockAddModelingRegionError(message="Shape is not of a valid type.")

pcb_model_props = region.get("pcb_model_props", {})
if pcb_model_props:
if (
"export_model_type" not in pcb_model_props
or pcb_model_props["export_model_type"] == ""
):
raise SherlockAddModelingRegionError(
message="PCB model export type is invalid."
)
if "elem_order" not in pcb_model_props or pcb_model_props["elem_order"] == "":
raise SherlockAddModelingRegionError(
message="PCB element order is invalid."
)
if "max_mesh_size" not in pcb_model_props or not isinstance(
pcb_model_props["max_mesh_size"], float
):
raise SherlockAddModelingRegionError(
message="PCB max mesh size is invalid."
)
if "quads_preferred" not in pcb_model_props or not isinstance(
pcb_model_props["quads_preferred"], bool
):
raise SherlockAddModelingRegionError(
message="PCB quads preferred is invalid."
)

trace_model_props = region.get("trace_model_props", {})
if trace_model_props:
if (
"trace_model_type" not in trace_model_props
or trace_model_props["trace_model_type"] == ""
):
raise SherlockAddModelingRegionError(message="Trace model type is invalid.")

if not self._is_connection_up():
LOG.error("There is no connection to a gRPC service.")
return

add_modeling_region_request = SherlockLayerService_pb2.AddModelingRegionRequest()
add_modeling_region_request.project = project

for region_request in modeling_regions:
modeling_region = add_modeling_region_request.modelingRegions.add()
modeling_region.ccaName = region_request["cca_name"]
modeling_region.regionId = region_request["region_id"]
modeling_region.regionUnits = region_request["region_units"]
modeling_region.modelMode = ModelingRegion.ModelingMode.Value(
region_request["model_mode"]
)

shape = region_request["shape"]
if isinstance(shape, PolygonalShape):
polygonal_shape = modeling_region.polygonalShape
for point in shape.points:
polygonal_point = polygonal_shape.points.add()
polygonal_point.x = point[0]
polygonal_point.y = point[1]
polygonal_shape.rotation = shape.rotation
elif isinstance(shape, RectangularShape):
rectangular_shape = modeling_region.rectangularShape
for point in shape.points:
rectangular_point = rectangular_shape.points.add()
rectangular_point.x = point[0]
rectangular_point.y = point[1]
rectangular_shape.rotation = shape.rotation
elif isinstance(shape, SlotShape):
slot_shape = modeling_region.slotShape
for point in shape.points:
slot_point = slot_shape.points.add()
slot_point.x = point[0]
slot_point.y = point[1]
slot_shape.rotation = shape.rotation
elif isinstance(shape, CircularShape):
circular_shape = modeling_region.circularShape
for point in shape.points:
circular_point = circular_shape.points.add()
circular_point.x = point[0]
circular_point.y = point[1]
circular_shape.rotation = shape.rotation
else:
raise SherlockAddModelingRegionError(
message="Shape is not of a valid type."
)

ExportModelType = ModelingRegion.PCBModelingProperties.ExportModelType
pcb_model_props = region_request.get("pcb_model_props", {})
modeling_region.pcbModelProps.exportModelType = getattr(
ExportModelType,
pcb_model_props["export_model_type"],
)
modeling_region.pcbModelProps.elemOrder = getattr(
ModelingRegion.ElementOrder,
pcb_model_props["elem_order"],
)
modeling_region.pcbModelProps.maxMeshSize = pcb_model_props["max_mesh_size"]
modeling_region.pcbModelProps.maxMeshSizeUnits = pcb_model_props[
"max_mesh_size_units"
]
modeling_region.pcbModelProps.quadsPreferred = pcb_model_props[
"quads_preferred"
]

TraceModelingType = ModelingRegion.TraceModelingProperties.TraceModelingType
trace_model_props = region_request.get("trace_model_props", {})
modeling_region.traceModelProps.traceModelType = getattr(
TraceModelingType,
trace_model_props["trace_model_type"],
)
if "elem_order" in trace_model_props:
modeling_region.traceModelProps.elemOrder = getattr(
ModelingRegion.ElementOrder,
trace_model_props["elem_order"],
)
if "trace_mesh_size" in trace_model_props:
modeling_region.traceModelProps.traceMeshSize = trace_model_props[
"trace_mesh_size"
]
if "trace_mesh_size_units" in trace_model_props:
modeling_region.traceModelProps.traceMeshSizeUnits = trace_model_props[
"trace_mesh_size_units"
]

return_code = self.stub.addModelingRegion(add_modeling_region_request)
if return_code.value != 0:
raise SherlockAddModelingRegionError(message=return_code.message)

return return_code.value

except SherlockAddModelingRegionError as e:
LOG.error(str(e))
raise e
Loading