From e8f08645e71efdaefd410d4e9b91e97fcb0fb6fc Mon Sep 17 00:00:00 2001 From: Elodie Chamblas Date: Fri, 4 Jul 2025 16:43:35 +0200 Subject: [PATCH 1/2] FaceActions - check if batch is available - and activate it if available in project _fill_bodies --- src/ansys/speos/core/kernel/face.py | 50 ++++++++++++++++++++++++++--- src/ansys/speos/core/project.py | 25 +++++++++++---- tests/core/test_project.py | 1 + tests/kernel/test_geometry.py | 6 ++-- 4 files changed, 68 insertions(+), 14 deletions(-) diff --git a/src/ansys/speos/core/kernel/face.py b/src/ansys/speos/core/kernel/face.py index 8159b9cd9..34d5c6245 100644 --- a/src/ansys/speos/core/kernel/face.py +++ b/src/ansys/speos/core/kernel/face.py @@ -24,10 +24,13 @@ from typing import Iterator, List +from grpc import RpcError + from ansys.api.speos.part.v1 import ( face_pb2 as messages, face_pb2_grpc as service, ) +from ansys.speos.core.generic.general_methods import min_speos_version from ansys.speos.core.kernel.crud import CrudItem, CrudStub from ansys.speos.core.kernel.proto_message_utils import protobuf_message_to_str @@ -102,7 +105,19 @@ class FaceStub(CrudStub): def __init__(self, channel): super().__init__(stub=service.FacesManagerStub(channel=channel)) self._actions_stub = service.FaceActionsStub(channel=channel) - + self._is_batch_available = self._check_if_batch_available() + + def _check_if_batch_available(self) -> bool: + try: + for reserve_faces_res in self._actions_stub.ReserveFaces( + FaceStub._reserve_face_iterator([ProtoFace(name="tmp")]) + ): + FaceLink(self, reserve_faces_res.guids[0]).delete() + return True + except RpcError: + return False + + @min_speos_version(25, 2, 0) def create_batch(self, message_list: List[ProtoFace]) -> List[FaceLink]: """Create new entries. @@ -116,6 +131,9 @@ def create_batch(self, message_list: List[ProtoFace]) -> List[FaceLink]: List[ansys.speos.core.kernel.face.FaceLink] List pf link objects created. """ + if not self._is_batch_available: + raise NotImplementedError("Please use a Speos Version of 2025 R2 SP0 or higher.") + reserve_faces_res = self._actions_stub.ReserveFaces( FaceStub._reserve_face_iterator(message_list) ) @@ -145,8 +163,15 @@ def create(self, message: ProtoFace) -> FaceLink: ansys.speos.core.kernel.face.FaceLink Link object created. """ - return self.create_batch(message_list=[message])[0] + resp = CrudStub.create(self, messages.Create_Request(face=ProtoFace(name="tmp"))) + chunk_iterator = FaceStub._faces_to_chunks( + guids=[resp.guid], message_list=[message], nb_items=128 * 1024 + ) + self._actions_stub.Upload(chunk_iterator) + return FaceLink(self, resp.guid) + + @min_speos_version(25, 2, 0) def read_batch(self, refs: List[FaceLink]) -> List[ProtoFace]: """Get existing entries. @@ -160,6 +185,9 @@ def read_batch(self, refs: List[FaceLink]) -> List[ProtoFace]: List[face.Face] Datamodels of the entries. """ + if not self._is_batch_available: + raise NotImplementedError("Please use a Speos Version of 2025 R2 SP0 or higher.") + for ref in refs: if not ref.stub == self: raise ValueError("FaceLink is not on current database. Key=" + ref.key) @@ -181,8 +209,13 @@ def read(self, ref: FaceLink) -> ProtoFace: face.Face Datamodel of the entry. """ - return self.read_batch(refs=[ref])[0] + if not ref.stub == self: + raise ValueError("FaceLink is not on current database. Key=" + ref.key) + chunks = self._actions_stub.Download(request=messages.Download_Request(guid=ref.key)) + return FaceStub._chunks_to_faces(chunks)[0] + + @min_speos_version(25, 2, 0) def update_batch(self, refs: List[FaceLink], data: List[ProtoFace]) -> None: """Change existing entries. @@ -194,6 +227,9 @@ def update_batch(self, refs: List[FaceLink], data: List[ProtoFace]) -> None: data : List[face.Face] New datamodels for the entries. """ + if not self._is_batch_available: + raise NotImplementedError("Please use a Speos Version of 2025 R2 SP0 or higher.") + for ref in refs: if not ref.stub == self: raise ValueError("FaceLink is not on current database") @@ -214,7 +250,13 @@ def update(self, ref: FaceLink, data: ProtoFace) -> None: data : face.Face New datamodel for the entry. """ - self.update_batch(refs=[ref], data=[data]) + if not ref.stub == self: + raise ValueError("FaceLink is not on current database") + + chunk_iterator = FaceStub._faces_to_chunks( + guids=[ref.key], message_list=[data], nb_items=128 * 1024 + ) + self._actions_stub.Upload(chunk_iterator) def delete(self, ref: FaceLink) -> None: """Remove an existing entry. diff --git a/src/ansys/speos/core/project.py b/src/ansys/speos/core/project.py index 567d25ec7..cc62ce5bd 100644 --- a/src/ansys/speos/core/project.py +++ b/src/ansys/speos/core/project.py @@ -691,14 +691,25 @@ def _fill_bodies( b_feat = feat_host.create_body(name=b_data.name) b_feat.body_link = b_link b_feat._body = b_data # instead of b_feat.reset() - this avoid a useless read in server + f_links = self.client.get_items(keys=b_data.face_guids, item_type=FaceLink) - for f_link in f_links: - f_data = f_link.get() - f_feat = b_feat.create_face(name=f_data.name) - f_feat.face_link = f_link - f_feat._face = ( - f_data # instead of f_feat.reset() - this avoid a useless read in server - ) + face_db = self.client.faces() + if face_db._is_batch_available: + f_data_list = face_db.read_batch(refs=f_links) + for f_data, f_link in zip(f_data_list, f_links): + f_feat = b_feat.create_face(name=f_data.name) + f_feat.face_link = f_link + f_feat._face = ( + f_data # instead of f_feat.reset() - this avoid a useless read in server + ) + else: + for f_link in f_links: + f_data = f_link.get() + f_feat = b_feat.create_face(name=f_data.name) + f_feat.face_link = f_link + f_feat._face = ( + f_data # instead of f_feat.reset() - this avoid a useless read in server + ) def _add_unique_ids(self): scene_data = self.scene_link.get() diff --git a/tests/core/test_project.py b/tests/core/test_project.py index b741013b2..555950a0d 100644 --- a/tests/core/test_project.py +++ b/tests/core/test_project.py @@ -478,6 +478,7 @@ def test_preview_visual_data(speos: Speos): p2.preview() # preview when there is no cad p3 = Project(speos=speos) + p3.create_root_part().commit() # Needed for 251 server. sr = p3.create_source(name="Luminaire_source.2", feature_type=SourceLuminaire) sr.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) sr.commit() diff --git a/tests/kernel/test_geometry.py b/tests/kernel/test_geometry.py index b2e44c234..fc1a8e0d2 100644 --- a/tests/kernel/test_geometry.py +++ b/tests/kernel/test_geometry.py @@ -65,7 +65,7 @@ def test_create_big_face(speos: Speos): def test_create_big_faces(speos: Speos): - """Test create big faces using batch.""" + """Test create big faces using batch. Only available from SpeosRPC_Server 25.2.""" assert speos.client.healthy is True # Get DB face_db = speos.client.faces() # Create face stub from client channel @@ -124,7 +124,7 @@ def test_create_big_faces(speos: Speos): def test_update_big_face(speos: Speos): - """Test update big face.""" + """Test update big face. Bug on SpeosRPC_Server 25.1. Fixed from SpeosRPC_Server 25.2.""" assert speos.client.healthy is True # Get DB face_db = speos.client.faces() # Create face stub from client channel @@ -175,7 +175,7 @@ def test_update_big_face(speos: Speos): def test_update_big_faces(speos: Speos): - """Test update big faces using batch.""" + """Test update big faces using batch. Only available from SpeosRPC_Server 25.2.""" assert speos.client.healthy is True # Get DB face_db = speos.client.faces() # Create face stub from client channel From d445089869fde395a256a3a678931fc40deb22ca Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Fri, 4 Jul 2025 14:49:58 +0000 Subject: [PATCH 2/2] chore: adding changelog file 656.fixed.md [dependabot-skip] --- doc/changelog.d/656.fixed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/656.fixed.md diff --git a/doc/changelog.d/656.fixed.md b/doc/changelog.d/656.fixed.md new file mode 100644 index 000000000..b6f45bfc4 --- /dev/null +++ b/doc/changelog.d/656.fixed.md @@ -0,0 +1 @@ +Kernel - faceactions - check if batch is available on server - if available use batch project _fill_bodies \ No newline at end of file