Skip to content

Commit 477e319

Browse files
StefanThoenepyansys-ci-botpluAtAnsys
authored
feat: geopath property (#551)
## Description **provide easy access to geometry path information from part body face instances** ## Issue linked #550 ## Checklist - [x] I have tested my changes locally. - [x] I have added necessary documentation or updated existing documentation. - [x] I have followed the coding style guidelines of this project. - [x] I have added appropriate tests (unit, integration, system). - [x] I have reviewed my changes before submitting this pull request. - [x] I have linked the issue or issues that are solved by the PR if any. - [x] I have assigned this PR to myself. - [x] I have made sure that the title of my PR follows [Conventional commits style](https://www.conventionalcommits.org/en/v1.0.0/#summary) (e.g. ``feat: add optical property``) - [x] I have agreed with the Contributor License Agreement ([CLA](https://developer.ansys.com/form/cla-acceptance)). --------- Co-authored-by: pyansys-ci-bot <[email protected]> Co-authored-by: Pengyuan LU <[email protected]>
1 parent c57731c commit 477e319

File tree

11 files changed

+128
-47
lines changed

11 files changed

+128
-47
lines changed

doc/changelog.d/551.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
geopath property

examples/core/opt-prop.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# +
1717
from pathlib import Path
1818

19-
from ansys.speos.core import GeoRef, Project, Speos
19+
from ansys.speos.core import Project, Speos
2020

2121
# -
2222

@@ -34,21 +34,24 @@ def create_helper_geometries(project: Project):
3434
"""Create bodies and faces."""
3535

3636
def create_face(body):
37-
(
37+
face = (
3838
body.create_face(name="TheFaceF")
3939
.set_vertices([0, 0, 0, 1, 0, 0, 0, 1, 0])
4040
.set_facets([0, 1, 2])
4141
.set_normals([0, 0, 1, 0, 0, 1, 0, 0, 1])
4242
.commit()
4343
)
44+
return face
4445

46+
data = {"bodies": [], "faces": []}
4547
root_part = project.create_root_part().commit()
46-
body_b1 = root_part.create_body(name="TheBodyB").commit()
47-
body_b2 = root_part.create_body(name="TheBodyC").commit()
48-
body_b3 = root_part.create_body(name="TheBodyD").commit()
49-
body_b4 = root_part.create_body(name="TheBodyE").commit()
50-
for b in [body_b1, body_b2, body_b3, body_b4]:
51-
create_face(b)
48+
data["bodies"].append(root_part.create_body(name="TheBodyB").commit())
49+
data["bodies"].append(root_part.create_body(name="TheBodyC").commit())
50+
data["bodies"].append(root_part.create_body(name="TheBodyD").commit())
51+
data["bodies"].append(root_part.create_body(name="TheBodyE").commit())
52+
for b in data["bodies"]:
53+
data["faces"].append(create_face(b))
54+
return data
5255

5356

5457
# ## Model Setup
@@ -80,7 +83,9 @@ def create_face(body):
8083

8184
p = Project(speos=speos)
8285
print(p)
83-
create_helper_geometries(p)
86+
data = create_helper_geometries(p)
87+
bodies = data["bodies"]
88+
faces = data["faces"]
8489

8590
# ## Create VOP (volume optical property)
8691
#
@@ -93,8 +98,8 @@ def create_face(body):
9398
# This optical property will be applied to two bodies named : "TheBodyB" and "TheBodyC".
9499
op1.set_geometries(
95100
geometries=[
96-
GeoRef.from_native_link(geopath="TheBodyB"),
97-
GeoRef.from_native_link(geopath="TheBodyC"),
101+
bodies[0],
102+
bodies[1],
98103
]
99104
)
100105
print(op1)
@@ -120,8 +125,8 @@ def create_face(body):
120125
# This optical property will be applied to two bodies named : "TheBodyD" and "TheBodyE".
121126
op2.set_geometries(
122127
geometries=[
123-
GeoRef.from_native_link(geopath="TheBodyD"),
124-
GeoRef.from_native_link(geopath="TheBodyE"),
128+
bodies[2],
129+
bodies[3],
125130
]
126131
)
127132
op2.commit()
@@ -138,7 +143,7 @@ def create_face(body):
138143
op3 = p.create_optical_property(name="Material.FOP")
139144
op3.set_surface_mirror(reflectance=90) # SOP : mirror
140145
# This optical property will be applied a face from TheBodyD named : "TheFaceF".
141-
op3.set_geometries(geometries=[GeoRef.from_native_link(geopath="TheBodyD/TheFaceF")])
146+
op3.set_geometries(geometries=[faces[2]])
142147
op3.commit()
143148
print(op3)
144149

examples/core/simulation.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# +
1414
from pathlib import Path
1515

16-
from ansys.speos.core import GeoRef, Project, Speos
16+
from ansys.speos.core import Project, Speos
1717
from ansys.speos.core.simulation import SimulationInteractive, SimulationInverse
1818

1919
# -
@@ -48,7 +48,7 @@
4848
# is running as a service. In this example, the server and
4949
# client are the same machine.
5050

51-
speos = Speos(host="localhost", port=50098)
51+
speos = Speos(host=HOSTNAME, port=GRPC_PORT)
5252

5353
# ### Create a new project
5454
#
@@ -66,9 +66,13 @@
6666
# ### Prepare the root part
6767

6868
root_part = p.create_root_part()
69-
root_part.create_body(name="Body.1").create_face(name="Face.1").set_vertices(
70-
[0, 1, 2, 0, 2, 2, 1, 2, 2]
71-
).set_facets([0, 1, 2]).set_normals([0, 0, 1, 0, 0, 1, 0, 0, 1])
69+
body_1 = root_part.create_body(name="Body.1")
70+
face_1 = (
71+
body_1.create_face(name="Face.1")
72+
.set_vertices([0, 1, 2, 0, 2, 2, 1, 2, 2])
73+
.set_facets([0, 1, 2])
74+
.set_normals([0, 0, 1, 0, 0, 1, 0, 0, 1])
75+
)
7276
root_part.commit()
7377

7478
# ### Prepare an optical property
@@ -79,7 +83,7 @@
7983

8084
# Choose the geometry for this optical property : Body.1
8185

82-
opt_prop.set_geometries(geometries=[GeoRef.from_native_link(geopath="Body.1")])
86+
opt_prop.set_geometries(geometries=[body_1])
8387
opt_prop.commit()
8488

8589

@@ -95,7 +99,7 @@
9599
# ### Prepare a surface source
96100

97101
source1 = p.create_source(name=SOURCE_NAME)
98-
source1.set_exitance_constant(geometries=[(GeoRef.from_native_link(geopath="Body.1/Face.1"), True)])
102+
source1.set_exitance_constant(geometries=[(face_1, True)])
99103
# define a spectrum which is not monochromatic so it can be used in both direct and inverse
100104
# simulation
101105
source1.set_spectrum().set_blackbody()

src/ansys/speos/core/body.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
from ansys.speos.core import proto_message_utils
3131
import ansys.speos.core.face as face
32+
from ansys.speos.core.geo_ref import GeoRef
3233
from ansys.speos.core.kernel.body import ProtoBody
3334
from ansys.speos.core.kernel.client import SpeosClient
3435
import ansys.speos.core.part as part
@@ -81,6 +82,14 @@ def __init__(
8182

8283
self._geom_features = []
8384

85+
@property
86+
def geo_path(self) -> GeoRef:
87+
"""Geometry path to be used within other speos objects."""
88+
geo_paths = [self._name]
89+
if isinstance(self._parent_part, part.Part.SubPart):
90+
geo_paths.insert(0, self._parent_part.geo_path.metadata["GeoPath"])
91+
return GeoRef.from_native_link("/".join(geo_paths))
92+
8493
def create_face(
8594
self,
8695
name: str,

src/ansys/speos/core/face.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
from ansys.speos.core import proto_message_utils
3030
import ansys.speos.core.body as body
31+
from ansys.speos.core.geo_ref import GeoRef
3132
from ansys.speos.core.kernel.client import SpeosClient
3233
from ansys.speos.core.kernel.face import ProtoFace
3334

@@ -76,6 +77,15 @@ def __init__(
7677
# Create local Face
7778
self._face = ProtoFace(name=name, description=description, metadata=metadata)
7879

80+
@property
81+
def geo_path(self) -> GeoRef:
82+
"""Geometry path to be used within other speos objects."""
83+
geo_paths = [self._name]
84+
parent = self._parent_body
85+
if isinstance(parent, body.Body):
86+
geo_paths.insert(0, parent.geo_path.metadata["GeoPath"])
87+
return GeoRef.from_native_link("/".join(geo_paths))
88+
7989
def set_vertices(self, values: List[float]) -> Face:
8090
"""Set the face vertices.
8191

src/ansys/speos/core/opt_prop.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@
2424
from __future__ import annotations
2525

2626
from difflib import SequenceMatcher
27-
from typing import List, Mapping, Optional
27+
from typing import List, Mapping, Optional, Union
2828
import uuid
2929

30+
import ansys.speos.core.body as body
31+
import ansys.speos.core.face as face
3032
from ansys.speos.core.geo_ref import GeoRef
3133
from ansys.speos.core.kernel.scene import ProtoScene
3234
from ansys.speos.core.kernel.sop_template import ProtoSOPTemplate
3335
from ansys.speos.core.kernel.vop_template import ProtoVOPTemplate
36+
import ansys.speos.core.part as part
3437
import ansys.speos.core.project as project
3538
import ansys.speos.core.proto_message_utils as proto_message_utils
3639

@@ -264,7 +267,10 @@ def set_volume_library(self, path: str) -> OptProp:
264267
self._vop_template.library.material_file_uri = path
265268
return self
266269

267-
def set_geometries(self, geometries: Optional[List[GeoRef]] = None) -> OptProp:
270+
def set_geometries(
271+
self,
272+
geometries: Optional[List[Union[GeoRef, body.Body, face.Face, part.Part.SubPart]]] = None,
273+
) -> OptProp:
268274
"""Select geometries on which the optical properties will be applied.
269275
270276
Parameters
@@ -281,8 +287,17 @@ def set_geometries(self, geometries: Optional[List[GeoRef]] = None) -> OptProp:
281287
if geometries is None:
282288
self._material_instance.ClearField("geometries")
283289
else:
290+
geo_paths = []
291+
for gr in geometries:
292+
if isinstance(gr, GeoRef):
293+
geo_paths.append(gr)
294+
elif isinstance(gr, (face.Face, body.Body, part.Part.SubPart)):
295+
geo_paths.append(gr.geo_path)
296+
else:
297+
msg = f"Type {type(gr)} is not supported as Optical property geometry input."
298+
raise TypeError(msg)
284299
self._material_instance.geometries.geo_paths[:] = [
285-
gr.to_native_link() for gr in geometries
300+
gp.to_native_link() for gp in geo_paths
286301
]
287302
return self
288303

src/ansys/speos/core/part.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from ansys.speos.core import proto_message_utils
3232
import ansys.speos.core.body as body
3333
import ansys.speos.core.face as face
34+
from ansys.speos.core.geo_ref import GeoRef
3435
from ansys.speos.core.kernel.client import SpeosClient
3536
from ansys.speos.core.kernel.part import ProtoPart
3637
import ansys.speos.core.project as project
@@ -100,6 +101,14 @@ def __init__(
100101

101102
self._geom_features = []
102103

104+
@property
105+
def geo_path(self) -> GeoRef:
106+
"""Geometry path to be used within other speos objects."""
107+
geo_paths = [self._name]
108+
if isinstance(self._parent_part, Part.SubPart):
109+
geo_paths.insert(0, self._parent_part.geo_path.metadata["GeoPath"])
110+
return GeoRef.from_native_link("/".join(geo_paths))
111+
103112
def create_body(
104113
self,
105114
name: str,

src/ansys/speos/core/source.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
project as project,
3333
proto_message_utils as proto_message_utils,
3434
)
35+
import ansys.speos.core.body as body
36+
import ansys.speos.core.face as face
3537
from ansys.speos.core.geo_ref import GeoRef
3638
from ansys.speos.core.intensity import Intensity
3739
from ansys.speos.core.kernel.client import SpeosClient
@@ -959,7 +961,9 @@ def set_intensity(self) -> Intensity:
959961

960962
return self._intensity
961963

962-
def set_exitance_constant(self, geometries: List[tuple[GeoRef, bool]]) -> SourceSurface:
964+
def set_exitance_constant(
965+
self, geometries: List[tuple[Union[GeoRef, face.Face, body.Body], bool]]
966+
) -> SourceSurface:
963967
"""Set existence constant.
964968
965969
Parameters
@@ -979,12 +983,25 @@ def set_exitance_constant(self, geometries: List[tuple[GeoRef, bool]]) -> Source
979983
"geo_paths"
980984
)
981985
if geometries != []:
982-
my_list = [
983-
ProtoScene.GeoPath(geo_path=gr.to_native_link(), reverse_normal=reverse_normal)
984-
for (gr, reverse_normal) in geometries
985-
]
986+
geo_paths = []
987+
for gr, reverse_normal in geometries:
988+
if isinstance(gr, GeoRef):
989+
geo_paths.append(
990+
ProtoScene.GeoPath(
991+
geo_path=gr.to_native_link(), reverse_normal=reverse_normal
992+
)
993+
)
994+
elif isinstance(gr, (face.Face, body.Body)):
995+
geo_paths.append(
996+
ProtoScene.GeoPath(
997+
geo_path=gr.geo_path.to_native_link(), reverse_normal=reverse_normal
998+
)
999+
)
1000+
else:
1001+
msg = f"Type {type(gr)} is not supported as Surface Source geometry input."
1002+
raise TypeError(msg)
9861003
self._source_instance.surface_properties.exitance_constant_properties.geo_paths.extend(
987-
my_list
1004+
geo_paths
9881005
)
9891006
return self
9901007

tests/core/test_opt_prop.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -148,16 +148,19 @@ def test_reset_optical_property(speos: Speos):
148148

149149
root_part = p.create_root_part()
150150
body_b = root_part.create_body(name="TheBodyB")
151-
body_b.create_face(name="TheFaceF").set_vertices([0, 0, 0, 1, 0, 0, 0, 1, 0]).set_facets(
152-
[0, 1, 2]
153-
).set_normals([0, 0, 1, 0, 0, 1, 0, 0, 1])
151+
(
152+
body_b.create_face(name="TheFaceF")
153+
.set_vertices([0, 0, 0, 1, 0, 0, 0, 1, 0])
154+
.set_facets([0, 1, 2])
155+
.set_normals([0, 0, 1, 0, 0, 1, 0, 0, 1])
156+
)
154157
root_part.commit()
155158

156159
# Create + commit
157160
op1 = (
158161
p.create_optical_property(name="Material.1")
159162
.set_volume_opaque()
160-
.set_geometries(geometries=[GeoRef.from_native_link("TheBodyB")])
163+
.set_geometries(geometries=[body_b.geo_path])
161164
.commit()
162165
)
163166
assert op1.vop_template_link is not None
@@ -233,9 +236,12 @@ def test_get_optical_property(speos: Speos, capsys):
233236

234237
root_part = p.create_root_part()
235238
body_a = root_part.create_body(name="TheBodyA")
236-
body_a.create_face(name="TheFaceF").set_vertices([0, 0, 0, 1, 0, 0, 0, 1, 0]).set_facets(
237-
[0, 1, 2]
238-
).set_normals([0, 0, 1, 0, 0, 1, 0, 0, 1])
239+
face = (
240+
body_a.create_face(name="TheFaceF")
241+
.set_vertices([0, 0, 0, 1, 0, 0, 0, 1, 0])
242+
.set_facets([0, 1, 2])
243+
.set_normals([0, 0, 1, 0, 0, 1, 0, 0, 1])
244+
)
239245
body_b = root_part.create_body(name="TheBodyB")
240246
body_b.create_face(name="TheFaceF").set_vertices([0, 0, 0, 1, 0, 0, 0, 1, 0]).set_facets(
241247
[0, 1, 2]
@@ -245,7 +251,7 @@ def test_get_optical_property(speos: Speos, capsys):
245251
op1 = (
246252
p.create_optical_property(name="Material.1")
247253
.set_volume_opaque()
248-
.set_geometries(geometries=[GeoRef.from_native_link("TheBodyA")])
254+
.set_geometries(geometries=[body_a])
249255
.commit()
250256
)
251257

@@ -269,7 +275,7 @@ def test_get_optical_property(speos: Speos, capsys):
269275
p.create_optical_property(name="OpticalProperty2")
270276
.set_volume_optic(index=1.7, absorption=0.01, constringence=55)
271277
.set_surface_opticalpolished()
272-
.set_geometries(geometries=[GeoRef.from_native_link("TheBodyB")])
278+
.set_geometries(geometries=[body_b])
273279
.commit()
274280
)
275281

@@ -292,6 +298,7 @@ def test_get_optical_property(speos: Speos, capsys):
292298
p.create_optical_property(name="OpticalProperty3")
293299
.set_volume_none()
294300
.set_surface_library(path=str(Path(test_path) / "R_test.anisotropicbsdf"))
301+
.set_geometries(geometries=[face])
295302
.commit()
296303
)
297304

0 commit comments

Comments
 (0)