How to create a part#
This tutorial demonstrates how to create a part.
What is a part?#
A part is either a volume or a face type bodies that are defined by a number of mesh triangles.
Then a material optical property can be then applied to a part (like bodies, faces).
Prerequisites#
Perform imports#
[1]:
from pathlib import Path
from ansys.speos.core import Body, Face, Part, Project, Speos
from ansys.speos.core.launcher import launch_local_speos_rpc_server
Define constants#
The constants help ensure consistency and avoid repetition throughout the example.
[2]:
HOSTNAME = "localhost"
GRPC_PORT = 50098 # Be sure the Speos GRPC Server has been started on this port.
USE_DOCKER = True # Set to False if you're running this example locally as a Notebook.
Model Setup#
Load assets#
The assets used to run this example are available in the PySpeos repository on GitHub.
Note: Make sure you have downloaded the simulation assets and set
assets_data_path
to point to the assets folder.
[3]:
if USE_DOCKER: # Running on the remote server.
assets_data_path = Path("/app") / "assets"
else:
assets_data_path = Path("/path/to/your/download/assets/directory")
Start/Connect to Speos RPC Server#
This Python client connects to a server where the Speos engine is running as a service. In this example, the server and client are the same machine. The launch_local_speos_rpc_method can be used to start a local instance of the service.
[4]:
if USE_DOCKER:
speos = Speos(host=HOSTNAME, port=GRPC_PORT)
else:
speos = launch_local_speos_rpc_server(port=GRPC_PORT)
New Project#
The only way to create parts, bodies and faces is from a project.
[5]:
p = Project(speos=speos)
print(p)
{
"name": "",
"description": "",
"metadata": {},
"part_guid": "",
"sources": [],
"sensors": [],
"simulations": [],
"materials": [],
"scenes": []
}
Create#
Before creating a body, a Root part needs to be created and committed.
[6]:
root_part = p.create_root_part().commit()
print(root_part)
{
"name": "RootPart",
"description": "",
"metadata": {},
"body_guids": [],
"parts": []
}
Create bodies in root part.#
A body can either a volume or face type. Both use the method named “create_body”.
[7]:
body_b1 = root_part.create_body(name="TheBodyB1").commit()
body_b2 = root_part.create_body(name="TheBodyB2").commit()
print(root_part)
{
"name": "RootPart",
"body_guids": [
"7a58cbc5-1f7b-4a28-8fce-d20af036fc3d",
"9944c0c2-d949-4f1c-88f7-4fa095fd3ccb"
],
"description": "",
"metadata": {},
"parts": [],
"bodys": [
{
"name": "TheBodyB1",
"description": "",
"metadata": {},
"face_guids": []
},
{
"name": "TheBodyB2",
"description": "",
"metadata": {},
"face_guids": []
}
]
}
Create faces inside a body.#
A body can have one (example, surface/open-volume type of body) or multiple faces (close-volume type of body).
Each face is then defined by a number of triangles/facets.
Each triangle/facet is defined by vertices and vertice normals.
[8]:
face_b1_f1 = (
body_b1.create_face(name="TheFaceF1")
.set_vertices([0, 0, 0, 1, 0, 0, 0, 1, 0])
.set_facets([0, 1, 2])
.set_normals([0, 0, 1, 0, 0, 1, 0, 0, 1])
.commit()
)
print(root_part)
{
"name": "RootPart",
"body_guids": [
"7a58cbc5-1f7b-4a28-8fce-d20af036fc3d",
"9944c0c2-d949-4f1c-88f7-4fa095fd3ccb"
],
"description": "",
"metadata": {},
"parts": [],
"bodys": [
{
"name": "TheBodyB1",
"face_guids": [
"bf309bf0-9595-4a59-9cd9-032bfa36db4f"
],
"description": "",
"metadata": {},
"faces": [
{
"name": "TheFaceF1",
"vertices": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
]
},
{
"name": "TheBodyB2",
"description": "",
"metadata": {},
"face_guids": []
}
]
}
Create bodies in sub part.#
Part can also be created under a sub-part.
The location sub-part can be defined using set_axis_system method.
[9]:
sub_part1 = (
root_part.create_sub_part(name="TheSubPartSP1")
.set_axis_system(axis_system=[5, 5, 5, 1, 0, 0, 0, 1, 0, 0, 0, 1])
.commit()
)
print(root_part)
{
"name": "RootPart",
"body_guids": [
"7a58cbc5-1f7b-4a28-8fce-d20af036fc3d",
"9944c0c2-d949-4f1c-88f7-4fa095fd3ccb"
],
"parts": [
{
"name": "TheSubPartSP1",
"description": "UniqueId_65d95bef-8c98-4399-b98e-f31c0dc7a7f6",
"part_guid": "2878d70c-cf00-4403-aeba-a462cdcef5f0",
"axis_system": [
5.0,
5.0,
5.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
],
"part": {
"name": "TheSubPartSP1",
"description": "",
"metadata": {},
"body_guids": [],
"parts": []
}
}
],
"description": "",
"metadata": {},
"bodys": [
{
"name": "TheBodyB1",
"face_guids": [
"bf309bf0-9595-4a59-9cd9-032bfa36db4f"
],
"description": "",
"metadata": {},
"faces": [
{
"name": "TheFaceF1",
"vertices": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
]
},
{
"name": "TheBodyB2",
"description": "",
"metadata": {},
"face_guids": []
}
]
}
Create body and faces in sub part body#
[10]:
body_sp1_b1 = sub_part1.create_body(name="TheBodySP1_B1").commit()
print(root_part)
face_sp1_b1_f1 = (
body_sp1_b1.create_face(name="TheFaceSP1_B1_F1")
.set_vertices([0, 1, 0, 0, 2, 0, 1, 2, 0])
.set_facets([0, 1, 2])
.set_normals([0, 0, 1, 0, 0, 1, 0, 0, 1])
.commit()
)
print(root_part)
{
"name": "RootPart",
"body_guids": [
"7a58cbc5-1f7b-4a28-8fce-d20af036fc3d",
"9944c0c2-d949-4f1c-88f7-4fa095fd3ccb"
],
"parts": [
{
"name": "TheSubPartSP1",
"description": "UniqueId_65d95bef-8c98-4399-b98e-f31c0dc7a7f6",
"part_guid": "2878d70c-cf00-4403-aeba-a462cdcef5f0",
"axis_system": [
5.0,
5.0,
5.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
],
"part": {
"name": "TheSubPartSP1",
"body_guids": [
"772487de-e3e6-444d-85b5-24593c8a9324"
],
"description": "",
"metadata": {},
"parts": [],
"bodys": [
{
"name": "TheBodySP1_B1",
"description": "",
"metadata": {},
"face_guids": []
}
]
}
}
],
"description": "",
"metadata": {},
"bodys": [
{
"name": "TheBodyB1",
"face_guids": [
"bf309bf0-9595-4a59-9cd9-032bfa36db4f"
],
"description": "",
"metadata": {},
"faces": [
{
"name": "TheFaceF1",
"vertices": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
]
},
{
"name": "TheBodyB2",
"description": "",
"metadata": {},
"face_guids": []
}
]
}
{
"name": "RootPart",
"body_guids": [
"7a58cbc5-1f7b-4a28-8fce-d20af036fc3d",
"9944c0c2-d949-4f1c-88f7-4fa095fd3ccb"
],
"parts": [
{
"name": "TheSubPartSP1",
"description": "UniqueId_65d95bef-8c98-4399-b98e-f31c0dc7a7f6",
"part_guid": "2878d70c-cf00-4403-aeba-a462cdcef5f0",
"axis_system": [
5.0,
5.0,
5.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
],
"part": {
"name": "TheSubPartSP1",
"body_guids": [
"772487de-e3e6-444d-85b5-24593c8a9324"
],
"description": "",
"metadata": {},
"parts": [],
"bodys": [
{
"name": "TheBodySP1_B1",
"face_guids": [
"8cc14ad6-2e9b-470d-8101-ece788644963"
],
"description": "",
"metadata": {},
"faces": [
{
"name": "TheFaceSP1_B1_F1",
"vertices": [
0.0,
1.0,
0.0,
0.0,
2.0,
0.0,
1.0,
2.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
]
}
]
}
}
],
"description": "",
"metadata": {},
"bodys": [
{
"name": "TheBodyB1",
"face_guids": [
"bf309bf0-9595-4a59-9cd9-032bfa36db4f"
],
"description": "",
"metadata": {},
"faces": [
{
"name": "TheFaceF1",
"vertices": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
]
},
{
"name": "TheBodyB2",
"description": "",
"metadata": {},
"face_guids": []
}
]
}
Create sub parts in sub part#
[11]:
sub_part11 = (
sub_part1.create_sub_part(name="TheSubPartSP11")
.set_axis_system([1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1])
.commit()
)
print(root_part)
{
"name": "RootPart",
"body_guids": [
"7a58cbc5-1f7b-4a28-8fce-d20af036fc3d",
"9944c0c2-d949-4f1c-88f7-4fa095fd3ccb"
],
"parts": [
{
"name": "TheSubPartSP1",
"description": "UniqueId_65d95bef-8c98-4399-b98e-f31c0dc7a7f6",
"part_guid": "2878d70c-cf00-4403-aeba-a462cdcef5f0",
"axis_system": [
5.0,
5.0,
5.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
],
"part": {
"name": "TheSubPartSP1",
"body_guids": [
"772487de-e3e6-444d-85b5-24593c8a9324"
],
"parts": [
{
"name": "TheSubPartSP11",
"description": "UniqueId_4b73ebbc-1589-40ab-a0eb-cc2d53acf441",
"part_guid": "1f3382e3-ad42-4f0f-bc96-ff767dda2234",
"axis_system": [
1.0,
1.0,
1.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
],
"part": {
"name": "TheSubPartSP11",
"description": "",
"metadata": {},
"body_guids": [],
"parts": []
}
}
],
"description": "",
"metadata": {},
"bodys": [
{
"name": "TheBodySP1_B1",
"face_guids": [
"8cc14ad6-2e9b-470d-8101-ece788644963"
],
"description": "",
"metadata": {},
"faces": [
{
"name": "TheFaceSP1_B1_F1",
"vertices": [
0.0,
1.0,
0.0,
0.0,
2.0,
0.0,
1.0,
2.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
]
}
]
}
}
],
"description": "",
"metadata": {},
"bodys": [
{
"name": "TheBodyB1",
"face_guids": [
"bf309bf0-9595-4a59-9cd9-032bfa36db4f"
],
"description": "",
"metadata": {},
"faces": [
{
"name": "TheFaceF1",
"vertices": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
]
},
{
"name": "TheBodyB2",
"description": "",
"metadata": {},
"face_guids": []
}
]
}
Read#
Find with exact name#
Find the root part
[12]:
features = p.find(name="", feature_type=Part)
print(features[0])
{
"name": "RootPart",
"body_guids": [
"7a58cbc5-1f7b-4a28-8fce-d20af036fc3d",
"9944c0c2-d949-4f1c-88f7-4fa095fd3ccb"
],
"parts": [
{
"name": "TheSubPartSP1",
"description": "UniqueId_65d95bef-8c98-4399-b98e-f31c0dc7a7f6",
"part_guid": "2878d70c-cf00-4403-aeba-a462cdcef5f0",
"axis_system": [
5.0,
5.0,
5.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
],
"part": {
"name": "TheSubPartSP1",
"body_guids": [
"772487de-e3e6-444d-85b5-24593c8a9324"
],
"parts": [
{
"name": "TheSubPartSP11",
"description": "UniqueId_4b73ebbc-1589-40ab-a0eb-cc2d53acf441",
"part_guid": "1f3382e3-ad42-4f0f-bc96-ff767dda2234",
"axis_system": [
1.0,
1.0,
1.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
],
"part": {
"name": "TheSubPartSP11",
"description": "",
"metadata": {},
"body_guids": [],
"parts": []
}
}
],
"description": "",
"metadata": {},
"bodys": [
{
"name": "TheBodySP1_B1",
"face_guids": [
"8cc14ad6-2e9b-470d-8101-ece788644963"
],
"description": "",
"metadata": {},
"faces": [
{
"name": "TheFaceSP1_B1_F1",
"vertices": [
0.0,
1.0,
0.0,
0.0,
2.0,
0.0,
1.0,
2.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
]
}
]
}
}
],
"description": "",
"metadata": {},
"bodys": [
{
"name": "TheBodyB1",
"face_guids": [
"bf309bf0-9595-4a59-9cd9-032bfa36db4f"
],
"description": "",
"metadata": {},
"faces": [
{
"name": "TheFaceF1",
"vertices": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
]
},
{
"name": "TheBodyB2",
"description": "",
"metadata": {},
"face_guids": []
}
]
}
Find a specific body in root part
[13]:
features = p.find(name="TheBodyB1", feature_type=Body)
print(features[0])
{
"name": "TheBodyB1",
"face_guids": [
"bf309bf0-9595-4a59-9cd9-032bfa36db4f"
],
"description": "",
"metadata": {},
"faces": [
{
"name": "TheFaceF1",
"vertices": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
]
}
Find a specific face of a body in root part
[14]:
features = p.find(name="TheBodyB1/TheFaceF1", feature_type=Face)
print(features[0])
{
"name": "TheFaceF1",
"vertices": [
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
Find a sub part
[15]:
features = p.find(name="TheSubPartSP1", feature_type=Part.SubPart)
print(features[0])
{
"name": "TheSubPartSP1",
"description": "UniqueId_65d95bef-8c98-4399-b98e-f31c0dc7a7f6",
"part_guid": "2878d70c-cf00-4403-aeba-a462cdcef5f0",
"axis_system": [
5.0,
5.0,
5.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
],
"part": {
"name": "TheSubPartSP1",
"body_guids": [
"772487de-e3e6-444d-85b5-24593c8a9324"
],
"parts": [
{
"name": "TheSubPartSP11",
"description": "UniqueId_4b73ebbc-1589-40ab-a0eb-cc2d53acf441",
"part_guid": "1f3382e3-ad42-4f0f-bc96-ff767dda2234",
"axis_system": [
1.0,
1.0,
1.0,
1.0,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
1.0
],
"part": {
"name": "TheSubPartSP11",
"description": "",
"metadata": {},
"body_guids": [],
"parts": []
}
}
],
"description": "",
"metadata": {},
"bodys": [
{
"name": "TheBodySP1_B1",
"face_guids": [
"8cc14ad6-2e9b-470d-8101-ece788644963"
],
"description": "",
"metadata": {},
"faces": [
{
"name": "TheFaceSP1_B1_F1",
"vertices": [
0.0,
1.0,
0.0,
0.0,
2.0,
0.0,
1.0,
2.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
]
}
]
}
}
Find a specific body in sub part
[16]:
features = p.find(name="TheSubPartSP1/TheBodySP1_B1", feature_type=Body)
print(features[0])
{
"name": "TheBodySP1_B1",
"face_guids": [
"8cc14ad6-2e9b-470d-8101-ece788644963"
],
"description": "",
"metadata": {},
"faces": [
{
"name": "TheFaceSP1_B1_F1",
"vertices": [
0.0,
1.0,
0.0,
0.0,
2.0,
0.0,
1.0,
2.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
]
}
Find a specific face of a body in sub part
[17]:
features = p.find(name="TheSubPartSP1/TheBodySP1_B1/TheFaceSP1_B1_F1", feature_type=Face)
print(features[0])
{
"name": "TheFaceSP1_B1_F1",
"vertices": [
0.0,
1.0,
0.0,
0.0,
2.0,
0.0,
1.0,
2.0,
0.0
],
"facets": [
0,
1,
2
],
"normals": [
0.0,
0.0,
1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
1.0
],
"description": "",
"metadata": {},
"texture_coordinates_channels": []
}
Find with approximation name#
Find all bodies in root part
[18]:
features = p.find(name=".*", name_regex=True, feature_type=Body)
for feat in features:
print(feat._name)
TheBodyB1
TheBodyB2
Find all faces inside body called “TheBodyB1”
[19]:
features = p.find(name="TheBodyB1/.*", name_regex=True, feature_type=Face)
for feat in features:
print(feat._name)
TheFaceF1
If you want to retrieve several kind of geometry features at a certain level, give feature_type=Part
All the geometry features at root part level:
[20]:
features = p.find(name=".*", name_regex=True, feature_type=Part)
for feat in features:
print(str(type(feat)) + " : name=" + feat._name)
<class 'ansys.speos.core.body.Body'> : name=TheBodyB1
<class 'ansys.speos.core.body.Body'> : name=TheBodyB2
<class 'ansys.speos.core.part.Part.SubPart'> : name=TheSubPartSP1
All the geometry features at second level: e.g.:
TheBodyB1’s all faces
TheSubPartSP1’s all bodies
TheSubPartSP1’s all sub part
[21]:
features = p.find(name=".*/.*", name_regex=True, feature_type=Part)
for feat in features:
print(str(type(feat)) + " : name=" + feat._name)
<class 'ansys.speos.core.face.Face'> : name=TheFaceF1
<class 'ansys.speos.core.body.Body'> : name=TheBodySP1_B1
<class 'ansys.speos.core.part.Part.SubPart'> : name=TheSubPartSP11
All the geometry features at the third level: e.g. TheSubPartSP1’s all bodies’ faces
[22]:
features = p.find(name=".*/.*/.*", name_regex=True, feature_type=Part)
for feat in features:
print(str(type(feat)) + " : name=" + feat._name)
<class 'ansys.speos.core.face.Face'> : name=TheFaceSP1_B1_F1
Delete#
[23]:
root_part.delete()
print(root_part)
local: {
"name": "RootPart",
"description": "",
"metadata": {},
"body_guids": [],
"parts": []
}
[24]:
speos.close()
[24]:
True