Skip to content

Commit cdd4552

Browse files
authored
New API: update_modeling_region() (#363)
1 parent 74587d9 commit cdd4552

File tree

3 files changed

+491
-17
lines changed

3 files changed

+491
-17
lines changed

src/ansys/sherlock/core/errors.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,3 +1200,20 @@ def str_itr(self):
12001200

12011201
assert self.error_array is None
12021202
return [f"Add modeling region error: {self.message}"]
1203+
1204+
1205+
class SherlockUpdateModelingRegionError(Exception):
1206+
"""Contains the errors raised when modeling regions for a project cannot be updated."""
1207+
1208+
def __init__(self, message=None, error_array=None):
1209+
"""Initialize error message."""
1210+
self.message = message
1211+
self.error_array = error_array
1212+
1213+
def str_itr(self):
1214+
"""Format error message."""
1215+
if self.message is None:
1216+
return [f"Update modeling region error: {error}" for error in self.error_array]
1217+
1218+
assert self.error_array is None
1219+
return [f"Update modeling region error: {self.message}"]

src/ansys/sherlock/core/layer.py

Lines changed: 278 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
SherlockExportAllMountPoints,
3131
SherlockExportAllTestFixtures,
3232
SherlockExportAllTestPoints,
33+
SherlockUpdateModelingRegionError,
3334
SherlockUpdateMountPointsByFileError,
3435
SherlockUpdateTestFixturesByFileError,
3536
SherlockUpdateTestPointsByFileError,
@@ -997,7 +998,7 @@ def add_modeling_region(
997998
}
998999
}
9991000
]
1000-
>>> result = sherlock.project.add_modeling_region("Tutorial Project", modeling_regions)
1001+
>>> result = sherlock.layer.add_modeling_region("Tutorial Project", modeling_regions)
10011002
"""
10021003
try:
10031004
if not project:
@@ -1087,24 +1088,25 @@ def add_modeling_region(
10871088
polygonal_shape.rotation = shape.rotation
10881089
elif isinstance(shape, RectangularShape):
10891090
rectangular_shape = modeling_region.rectangularShape
1090-
for point in shape.points:
1091-
rectangular_point = rectangular_shape.points.add()
1092-
rectangular_point.x = point[0]
1093-
rectangular_point.y = point[1]
1091+
rectangular_shape.length = shape.length
1092+
rectangular_shape.width = shape.width
1093+
rectangular_shape.centerX = shape.centerX
1094+
rectangular_shape.centerY = shape.centerY
10941095
rectangular_shape.rotation = shape.rotation
10951096
elif isinstance(shape, SlotShape):
10961097
slot_shape = modeling_region.slotShape
1097-
for point in shape.points:
1098-
slot_point = slot_shape.points.add()
1099-
slot_point.x = point[0]
1100-
slot_point.y = point[1]
1098+
slot_shape.length = shape.length
1099+
slot_shape.width = shape.width
1100+
slot_shape.nodeCount = shape.nodeCount
1101+
slot_shape.centerX = shape.centerX
1102+
slot_shape.centerY = shape.centerY
11011103
slot_shape.rotation = shape.rotation
11021104
elif isinstance(shape, CircularShape):
11031105
circular_shape = modeling_region.circularShape
1104-
for point in shape.points:
1105-
circular_point = circular_shape.points.add()
1106-
circular_point.x = point[0]
1107-
circular_point.y = point[1]
1106+
circular_shape.diameter = shape.diameter
1107+
circular_shape.nodeCount = shape.nodeCount
1108+
circular_shape.centerX = shape.centerX
1109+
circular_shape.centerY = shape.centerY
11081110
circular_shape.rotation = shape.rotation
11091111
else:
11101112
raise SherlockAddModelingRegionError(
@@ -1158,3 +1160,266 @@ def add_modeling_region(
11581160
except SherlockAddModelingRegionError as e:
11591161
LOG.error(str(e))
11601162
raise e
1163+
1164+
def update_modeling_region(
1165+
self,
1166+
project: str,
1167+
modeling_regions: List[Dict[str, Union[str, float, bool, dict]]],
1168+
):
1169+
"""
1170+
Update one or more modeling regions in a specific project.
1171+
1172+
Parameters
1173+
----------
1174+
project : str
1175+
Name of the Sherlock project.
1176+
modeling_regions : list of dict
1177+
List of modeling regions to update. Each dictionary should contain:
1178+
1179+
- cca_name : str
1180+
Name of the CCA.
1181+
- region_id : str
1182+
Unique region ID of the modeling region.
1183+
- region_units : str
1184+
Units of the modeling region.
1185+
- model_mode : str
1186+
Mode that specifies how the region is used. Valid values are ``Enabled``,
1187+
``Disabled`` and ``Excluded``.
1188+
- shape: PolygonalShape|RectangularShape|SlotShape|CircularShape|PCBShape
1189+
The shape of the modeling region.
1190+
- pcb_model_props : list
1191+
List of the PCB model parameters consisting of these properties:
1192+
1193+
- export_model_type : str
1194+
The type of model to be generated for a given modeling region.
1195+
Valid values are ``Default``, ``Sherlock``, ``Sweep`` and ``None``.
1196+
- elem_order: str
1197+
The type of 3D elements to be created for the PCB in the modeling region.
1198+
Valid values are ``First_Order``, ``Second_Order`` and ``Solid_Shell``.
1199+
- max_mesh_size : float
1200+
The maximum size of the mesh to be used in the region.
1201+
- max_mesh_size_units : str
1202+
Units for the maximum mesh size.
1203+
- quads_preferred : bool
1204+
Whether to generate quad-shaped elements when creating the mesh if true.
1205+
- trace_model_props : list
1206+
List of the trace model parameters consisting of these properties:
1207+
1208+
- trace_model_type : str
1209+
The specification of whether trace modeling should be performed
1210+
within the region. Valid values are ``Default``, ``Enabled`` and
1211+
``Disabled``.
1212+
- elem_order: str, optional
1213+
The type of 3D elements to be created for the PCB in the modeling region.
1214+
Valid values are ``First_Order``, ``Second_Order`` and ``Solid_Shell``.
1215+
- trace_mesh_size : float, optional
1216+
The maximum mesh size to be used in the region when trace modeling
1217+
is enabled.
1218+
- trace_mesh_size_units: str, optional
1219+
Units for the maximum mesh size when trace modeling is enabled.
1220+
- region_id_replacement : str, optional
1221+
Represents a unique region id that will replace the existing regionId value during
1222+
a modeling region update if a value exists.
1223+
1224+
Returns
1225+
-------
1226+
int
1227+
Status code of the response. 0 for success.
1228+
1229+
Example
1230+
-------
1231+
>>> from ansys.sherlock.core.launcher import launch_sherlock
1232+
>>> sherlock = launch_sherlock()
1233+
>>> sherlock.project.import_odb_archive(
1234+
"ODB++ Tutorial.tgz",
1235+
True,
1236+
True,
1237+
True,
1238+
True,
1239+
project="Tutorial Project",
1240+
cca_name="Card",
1241+
)
1242+
>>> modeling_regions = [
1243+
>>> {
1244+
>>> "cca_name": "Card",
1245+
>>> "region_id": "Region001",
1246+
>>> "region_units": "mm",
1247+
>>> "model_mode": "Enabled",
1248+
>>> "shape": PolygonalShape(points=[(0, 0), (1, 1)], rotation=0),
1249+
>>> "pcb_model_props": {
1250+
>>> "export_model_type": "Sherlock",
1251+
>>> "elem_order": "Second_Order",
1252+
>>> "max_mesh_size": 0.5,
1253+
>>> "max_mesh_size_units": "mm",
1254+
>>> "quads_preferred": True,
1255+
>>> },
1256+
>>> "trace_model_props": {
1257+
>>> "trace_model_type": "Enabled",
1258+
>>> "elem_order": "Second_Order",
1259+
>>> "trace_mesh_size": 0.1,
1260+
>>> "trace_mesh_size_units": "mm",
1261+
>>> },
1262+
>>> "region_id_replacement": "NewRegion001",
1263+
>>> }
1264+
>>> ]
1265+
>>> result = sherlock.layer.update_modeling_region("Tutorial Project", modeling_regions)
1266+
"""
1267+
try:
1268+
if not project:
1269+
raise SherlockUpdateModelingRegionError(message="Project name is invalid.")
1270+
1271+
if not modeling_regions:
1272+
raise SherlockUpdateModelingRegionError(message="Modeling regions list is empty.")
1273+
1274+
for region in modeling_regions:
1275+
if "cca_name" not in region:
1276+
raise SherlockUpdateModelingRegionError(message="CCA name is invalid.")
1277+
if "region_id" not in region:
1278+
raise SherlockUpdateModelingRegionError(message="Region ID is invalid.")
1279+
if "region_units" not in region:
1280+
raise SherlockUpdateModelingRegionError(message="Region units are invalid.")
1281+
if "shape" not in region:
1282+
raise SherlockUpdateModelingRegionError(message="Shape is missing.")
1283+
elif not isinstance(
1284+
region["shape"],
1285+
(
1286+
PolygonalShape,
1287+
RectangularShape,
1288+
SlotShape,
1289+
CircularShape,
1290+
PCBShape,
1291+
),
1292+
):
1293+
raise SherlockUpdateModelingRegionError(message="Shape is not of a valid type.")
1294+
1295+
pcb_model_props = region.get("pcb_model_props", {})
1296+
if pcb_model_props:
1297+
if (
1298+
"export_model_type" not in pcb_model_props
1299+
or pcb_model_props["export_model_type"] == ""
1300+
):
1301+
raise SherlockUpdateModelingRegionError(
1302+
message="PCB model export type is invalid."
1303+
)
1304+
if "elem_order" not in pcb_model_props or pcb_model_props["elem_order"] == "":
1305+
raise SherlockUpdateModelingRegionError(
1306+
message="PCB element order is invalid."
1307+
)
1308+
if "max_mesh_size" not in pcb_model_props or not isinstance(
1309+
pcb_model_props["max_mesh_size"], float
1310+
):
1311+
raise SherlockUpdateModelingRegionError(
1312+
message="PCB max mesh size is invalid."
1313+
)
1314+
if "quads_preferred" not in pcb_model_props or not isinstance(
1315+
pcb_model_props["quads_preferred"], bool
1316+
):
1317+
raise SherlockUpdateModelingRegionError(
1318+
message="PCB quads preferred is invalid."
1319+
)
1320+
1321+
trace_model_props = region.get("trace_model_props", {})
1322+
if trace_model_props:
1323+
if (
1324+
"trace_model_type" not in trace_model_props
1325+
or trace_model_props["trace_model_type"] == ""
1326+
):
1327+
raise SherlockUpdateModelingRegionError(
1328+
message="Trace model type is invalid."
1329+
)
1330+
1331+
if not self._is_connection_up():
1332+
LOG.error("There is no connection to a gRPC service.")
1333+
return
1334+
1335+
update_modeling_region_request = SherlockLayerService_pb2.UpdateModelingRegionRequest()
1336+
update_modeling_region_request.project = project
1337+
1338+
for region_request in modeling_regions:
1339+
modeling_region = update_modeling_region_request.modelingRegions.add()
1340+
modeling_region.ccaName = region_request["cca_name"]
1341+
modeling_region.regionId = region_request["region_id"]
1342+
modeling_region.regionUnits = region_request["region_units"]
1343+
modeling_region.modelMode = ModelingRegion.ModelingMode.Value(
1344+
region_request["model_mode"]
1345+
)
1346+
1347+
shape = region_request["shape"]
1348+
if isinstance(shape, PolygonalShape):
1349+
polygonal_shape = modeling_region.polygonalShape
1350+
for point in shape.points:
1351+
polygonal_point = polygonal_shape.points.add()
1352+
polygonal_point.x = point[0]
1353+
polygonal_point.y = point[1]
1354+
polygonal_shape.rotation = shape.rotation
1355+
elif isinstance(shape, RectangularShape):
1356+
rectangular_shape = modeling_region.rectangularShape
1357+
rectangular_shape.length = shape.length
1358+
rectangular_shape.width = shape.width
1359+
rectangular_shape.centerX = shape.center_x
1360+
rectangular_shape.centerY = shape.center_y
1361+
rectangular_shape.rotation = shape.rotation
1362+
elif isinstance(shape, SlotShape):
1363+
slot_shape = modeling_region.slotShape
1364+
slot_shape.length = shape.length
1365+
slot_shape.width = shape.width
1366+
slot_shape.nodeCount = shape.node_count
1367+
slot_shape.centerX = shape.center_x
1368+
slot_shape.centerY = shape.center_y
1369+
slot_shape.rotation = shape.rotation
1370+
elif isinstance(shape, CircularShape):
1371+
circular_shape = modeling_region.circularShape
1372+
circular_shape.diameter = shape.diameter
1373+
circular_shape.nodeCount = shape.node_count
1374+
circular_shape.centerX = shape.center_x
1375+
circular_shape.centerY = shape.center_y
1376+
circular_shape.rotation = shape.rotation
1377+
1378+
ExportModelType = ModelingRegion.PCBModelingProperties.ExportModelType
1379+
pcb_model_props = region_request.get("pcb_model_props", {})
1380+
modeling_region.pcbModelProps.exportModelType = getattr(
1381+
ExportModelType,
1382+
pcb_model_props["export_model_type"],
1383+
)
1384+
modeling_region.pcbModelProps.elemOrder = getattr(
1385+
ModelingRegion.ElementOrder,
1386+
pcb_model_props["elem_order"],
1387+
)
1388+
modeling_region.pcbModelProps.maxMeshSize = pcb_model_props["max_mesh_size"]
1389+
modeling_region.pcbModelProps.maxMeshSizeUnits = pcb_model_props[
1390+
"max_mesh_size_units"
1391+
]
1392+
modeling_region.pcbModelProps.quadsPreferred = pcb_model_props["quads_preferred"]
1393+
1394+
TraceModelingType = ModelingRegion.TraceModelingProperties.TraceModelingType
1395+
trace_model_props = region_request.get("trace_model_props", {})
1396+
modeling_region.traceModelProps.traceModelType = getattr(
1397+
TraceModelingType,
1398+
trace_model_props["trace_model_type"],
1399+
)
1400+
if "elem_order" in trace_model_props:
1401+
modeling_region.traceModelProps.elemOrder = getattr(
1402+
ModelingRegion.ElementOrder,
1403+
trace_model_props["elem_order"],
1404+
)
1405+
if "trace_mesh_size" in trace_model_props:
1406+
modeling_region.traceModelProps.traceMeshSize = trace_model_props[
1407+
"trace_mesh_size"
1408+
]
1409+
if "trace_mesh_size_units" in trace_model_props:
1410+
modeling_region.traceModelProps.traceMeshSizeUnits = trace_model_props[
1411+
"trace_mesh_size_units"
1412+
]
1413+
1414+
if "region_id_replacement" in region_request:
1415+
modeling_region.regionIdReplacement = region_request["region_id_replacement"]
1416+
1417+
return_code = self.stub.updateModelingRegion(update_modeling_region_request)
1418+
if return_code.value != 0:
1419+
raise SherlockUpdateModelingRegionError(message=return_code.message)
1420+
1421+
return return_code.value
1422+
1423+
except SherlockUpdateModelingRegionError as e:
1424+
LOG.error(str(e))
1425+
raise e

0 commit comments

Comments
 (0)