ansys-pyensight-core 0.10.4__tar.gz → 0.10.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ansys-pyensight-core might be problematic. Click here for more details.

Files changed (37) hide show
  1. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/PKG-INFO +2 -1
  2. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/pyproject.toml +3 -2
  3. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/dockerlauncher.py +3 -5
  4. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/locallauncher.py +11 -4
  5. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/omniverse.py +55 -11
  6. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/omniverse_dsg_server.py +16 -5
  7. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/LICENSE +0 -0
  8. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/README.rst +0 -0
  9. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/__init__.py +0 -0
  10. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/common.py +0 -0
  11. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/deep_pixel_view.html +0 -0
  12. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/dvs.py +0 -0
  13. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/enscontext.py +0 -0
  14. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/enshell_grpc.py +0 -0
  15. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/ensight_grpc.py +0 -0
  16. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/ensobj.py +0 -0
  17. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/launch_ensight.py +0 -0
  18. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/launcher.py +0 -0
  19. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/libuserd.py +0 -0
  20. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/listobj.py +0 -0
  21. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/py.typed +0 -0
  22. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/renderable.py +0 -0
  23. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/session.py +0 -0
  24. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/sgeo_poll.html +0 -0
  25. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/__init__.py +0 -0
  26. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/adr.py +0 -0
  27. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/dsg_server.py +0 -0
  28. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/export.py +0 -0
  29. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/omniverse_cli.py +0 -0
  30. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/omniverse_glb_server.py +0 -0
  31. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/parts.py +0 -0
  32. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/query.py +0 -0
  33. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/readers.py +0 -0
  34. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/resources/Materials/000_sky.exr +0 -0
  35. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/support.py +0 -0
  36. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/variables.py +0 -0
  37. {ansys_pyensight_core-0.10.4 → ansys_pyensight_core-0.10.6}/src/ansys/pyensight/core/utils/views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ansys-pyensight-core
3
- Version: 0.10.4
3
+ Version: 0.10.6
4
4
  Summary: A python wrapper for Ansys EnSight
5
5
  Author-email: "ANSYS, Inc." <pyansys.core@ansys.com>
6
6
  Maintainer-email: "ANSYS, Inc." <pyansys.core@ansys.com>
@@ -27,6 +27,7 @@ Requires-Dist: pypng>=0.0.20
27
27
  Requires-Dist: psutil>=5.9.2
28
28
  Requires-Dist: usd-core==24.8; python_version < '3.13' and platform_machine != 'aarch64'
29
29
  Requires-Dist: pygltflib>=1.16.2
30
+ Requires-Dist: grpcio<1.68.0
30
31
  Requires-Dist: build>=0.10.0 ; extra == "dev"
31
32
  Requires-Dist: bump2version>=1.0.1 ; extra == "dev"
32
33
  Requires-Dist: ipdb>=0.9.4 ; extra == "dev"
@@ -6,7 +6,7 @@ build-backend = "flit_core.buildapi"
6
6
 
7
7
  [project]
8
8
  name = "ansys-pyensight-core"
9
- version = "0.10.4"
9
+ version = "0.10.6"
10
10
  description = "A python wrapper for Ansys EnSight"
11
11
  readme = "README.rst"
12
12
  requires-python = ">=3.10,<3.14"
@@ -36,7 +36,8 @@ dependencies = [
36
36
  "pypng>=0.0.20",
37
37
  "psutil>=5.9.2",
38
38
  "usd-core==24.8; python_version < '3.13' and platform_machine != 'aarch64'",
39
- "pygltflib>=1.16.2"
39
+ "pygltflib>=1.16.2",
40
+ "grpcio<1.68.0",
40
41
  ]
41
42
 
42
43
  [project.optional-dependencies]
@@ -384,7 +384,8 @@ class DockerLauncher(Launcher):
384
384
 
385
385
  def launch_webui(self, container_env_str):
386
386
  # Run websocketserver
387
- cmd = "cpython -m ansys.simba.plugin.post.simba_post"
387
+ cmd = f"/ansys_inc/v{self._ansys_version}/FluidsOne/server/linx64/fluidsone"
388
+ cmd += " --main-run-mode post"
388
389
  # websocket port - this needs to come first since we now have
389
390
  # --add_header as a optional arg that can take an arbitrary
390
391
  # number of optional headers.
@@ -393,10 +394,7 @@ class DockerLauncher(Launcher):
393
394
  http_port = self._service_host_port["http"][1]
394
395
  ws_port = self._service_host_port["ws"][1]
395
396
  cmd += f" --server-listen-port {webui_port}"
396
- cmd += (
397
- f" --server-web-roots /ansys_inc/v{self._ansys_version}/CEI/nexus{self._ansys_version}/"
398
- )
399
- cmd += f"ansys{self._ansys_version}/ensight/WebUI/web/ui/"
397
+ cmd += f" --server-web-roots /ansys_inc/v{self._ansys_version}/FluidsOne/web/ui"
400
398
  cmd += f" --ensight-grpc-port {grpc_port}"
401
399
  cmd += f" --ensight-html-port {http_port}"
402
400
  cmd += f" --ensight-ws-port {ws_port}"
@@ -102,8 +102,16 @@ class LocalLauncher(Launcher):
102
102
  """Type of app to launch. Options are ``ensight`` and ``envision``."""
103
103
  return self._application
104
104
 
105
- def launch_webui(self, cpython, version, popen_common):
106
- cmd = [cpython, "-m", "ansys.simba.plugin.post.simba_post"]
105
+ def launch_webui(self, version, popen_common):
106
+ if os.environ.get("PYENSIGHT_FLUIDSONE_PATH"):
107
+ fluids_one_path = os.environ["PYENSIGHT_FLUIDSONE_PATH"]
108
+ else:
109
+ awp_path = os.path.dirname(self._install_path)
110
+ platf = "winx64" if self._is_windows() else "linx64"
111
+ fluids_one_path = os.path.join(awp_path, "FluidsOne", "server", platf, "fluids_one")
112
+ if self._is_windows():
113
+ fluids_one_path += ".exe"
114
+ cmd = [fluids_one_path, "--main-run-mode", "post"]
107
115
  path_to_webui = self._install_path
108
116
  # Dev environment
109
117
  path_to_webui_internal = os.path.join(
@@ -265,7 +273,6 @@ class LocalLauncher(Launcher):
265
273
  cmd = [os.path.join(self._install_path, "bin", "cpython"), websocket_script]
266
274
  if is_windows:
267
275
  cmd[0] += ".bat"
268
- ensight_python = cmd[0]
269
276
  cmd.extend(["--http_directory", self.session_directory])
270
277
  # http port
271
278
  cmd.extend(["--http_port", str(self._ports[2])])
@@ -312,7 +319,7 @@ class LocalLauncher(Launcher):
312
319
  self._sessions.append(session)
313
320
 
314
321
  if self._launch_webui:
315
- self.launch_webui(ensight_python, version, popen_common)
322
+ self.launch_webui(version, popen_common)
316
323
  return session
317
324
 
318
325
  def stop(self) -> None:
@@ -5,6 +5,7 @@ import platform
5
5
  import subprocess
6
6
  import sys
7
7
  import tempfile
8
+ import threading
8
9
  from types import ModuleType
9
10
  from typing import TYPE_CHECKING, List, Optional, Union
10
11
  import uuid
@@ -35,8 +36,15 @@ class OmniverseKitInstance:
35
36
  The process id of the launched instance
36
37
  """
37
38
 
38
- def __init__(self, pid: int) -> None:
39
- self._pid: Optional[int] = pid
39
+ def __init__(self, proc: subprocess.Popen) -> None:
40
+ self._proc: subprocess.Popen = proc
41
+ self._returncode: Optional[int] = None
42
+ self._rendering = False
43
+ self._lines_read = 0
44
+ self._scanner_thread = threading.Thread(
45
+ target=OmniverseKitInstance._scan_stdout, args=(self,)
46
+ )
47
+ self._scanner_thread.start()
40
48
 
41
49
  def __del__(self) -> None:
42
50
  """Close down the instance on delete"""
@@ -50,7 +58,7 @@ class OmniverseKitInstance:
50
58
  """
51
59
  if not self.is_running():
52
60
  return
53
- proc = psutil.Process(self._pid)
61
+ proc = psutil.Process(self._proc.pid)
54
62
  for child in proc.children(recursive=True):
55
63
  if psutil.pid_exists(child.pid):
56
64
  # This can be a race condition, so it is ok if the child is dead already
@@ -63,7 +71,29 @@ class OmniverseKitInstance:
63
71
  proc.terminate()
64
72
  except psutil.NoSuchProcess:
65
73
  pass
66
- self._pid = None
74
+ self._scanner_thread.join()
75
+
76
+ # On a forced close, set a return code of 0
77
+ self._returncode = 0
78
+
79
+ @staticmethod
80
+ def _scan_stdout(oki: "OmniverseKitInstance"):
81
+ while oki._proc and oki._proc.poll() is None:
82
+ if oki._proc.stdout is not None:
83
+ output_line = oki._proc.stdout.readline().decode("utf-8")
84
+ oki._lines_read = oki._lines_read + 1
85
+ if "RTX ready" in output_line:
86
+ oki._rendering = True
87
+
88
+ def is_rendering(self) -> bool:
89
+ """Check if the instance has finished launching and is ready to render
90
+
91
+ Returns
92
+ -------
93
+ bool
94
+ True if the instance is ready to render.
95
+ """
96
+ return self.is_running() and self._rendering
67
97
 
68
98
  def is_running(self) -> bool:
69
99
  """Check if the instance is still running
@@ -73,13 +103,27 @@ class OmniverseKitInstance:
73
103
  bool
74
104
  True if the instance is still running.
75
105
  """
76
- if not self._pid:
106
+ if self._proc is None:
77
107
  return False
78
- if psutil.pid_exists(self._pid):
108
+ if self._proc.poll() is None:
79
109
  return True
80
- self._pid = None
81
110
  return False
82
111
 
112
+ def returncode(self) -> Optional[int]:
113
+ """Get the return code if the process has stopped, or None if still running
114
+
115
+ Returns
116
+ -------
117
+ int or None
118
+ Get the return code if the process has stopped, or None if still running
119
+ """
120
+ if self._returncode is not None:
121
+ return self._returncode
122
+ if self.is_running():
123
+ return None
124
+ self._returncode = self._proc.returncode
125
+ return self._returncode
126
+
83
127
 
84
128
  # Deprecated
85
129
  def find_kit_filename(fallback_directory: Optional[str] = None) -> Optional[str]:
@@ -216,8 +260,8 @@ def launch_kit_instance(
216
260
  cmd.append("--/log/enabled=true")
217
261
  # Launch the process
218
262
  env_vars = os.environ.copy()
219
- p = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, env=env_vars)
220
- return OmniverseKitInstance(p.pid)
263
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env_vars)
264
+ return OmniverseKitInstance(p)
221
265
 
222
266
 
223
267
  def find_app(ansys_installation: Optional[str] = None) -> Optional[str]:
@@ -322,8 +366,8 @@ def launch_app(
322
366
 
323
367
  # Launch the process
324
368
  env_vars = os.environ.copy()
325
- p = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, env=env_vars)
326
- return OmniverseKitInstance(p.pid)
369
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env_vars)
370
+ return OmniverseKitInstance(p)
327
371
 
328
372
 
329
373
  class Omniverse:
@@ -70,7 +70,7 @@ class OmniverseWrapper(object):
70
70
  self._time_codes_per_second: float = 120.0
71
71
  # Omniverse content currently only scales correctly for scenes in cm. DJB, Feb 2025
72
72
  self._units_per_meter: float = 100.0
73
-
73
+ self._up_axis: str = UsdGeom.Tokens.y
74
74
  if destination:
75
75
  self.destination = destination
76
76
 
@@ -163,7 +163,7 @@ class OmniverseWrapper(object):
163
163
  self._stage = Usd.Stage.CreateNew(self.stage_url())
164
164
  # record the stage in the "_old_stages" list.
165
165
  self._old_stages.append(self.stage_url())
166
- UsdGeom.SetStageUpAxis(self._stage, UsdGeom.Tokens.y)
166
+ UsdGeom.SetStageUpAxis(self._stage, self._up_axis)
167
167
  UsdGeom.SetStageMetersPerUnit(self._stage, 1.0 / self._units_per_meter)
168
168
  logging.info(f"Created stage: {self.stage_url()}")
169
169
 
@@ -302,7 +302,7 @@ class OmniverseWrapper(object):
302
302
 
303
303
  if not os.path.exists(part_stage_url):
304
304
  part_stage = Usd.Stage.CreateNew(part_stage_url)
305
- UsdGeom.SetStageUpAxis(part_stage, UsdGeom.Tokens.y)
305
+ UsdGeom.SetStageUpAxis(part_stage, self._up_axis)
306
306
  UsdGeom.SetStageMetersPerUnit(part_stage, 1.0 / self._units_per_meter)
307
307
  self._old_stages.append(part_stage_url)
308
308
  xform = UsdGeom.Xform.Define(part_stage, "/" + partname)
@@ -400,7 +400,7 @@ class OmniverseWrapper(object):
400
400
 
401
401
  if not os.path.exists(part_stage_url):
402
402
  part_stage = Usd.Stage.CreateNew(part_stage_url)
403
- UsdGeom.SetStageUpAxis(part_stage, UsdGeom.Tokens.y)
403
+ UsdGeom.SetStageUpAxis(part_stage, self._up_axis)
404
404
  UsdGeom.SetStageMetersPerUnit(part_stage, 1.0 / self._units_per_meter)
405
405
  self._old_stages.append(part_stage_url)
406
406
  xform = UsdGeom.Xform.Define(part_stage, "/" + partname)
@@ -485,7 +485,7 @@ class OmniverseWrapper(object):
485
485
 
486
486
  if not os.path.exists(part_stage_url):
487
487
  part_stage = Usd.Stage.CreateNew(part_stage_url)
488
- UsdGeom.SetStageUpAxis(part_stage, UsdGeom.Tokens.y)
488
+ UsdGeom.SetStageUpAxis(part_stage, self._up_axis)
489
489
  UsdGeom.SetStageMetersPerUnit(part_stage, 1.0 / self._units_per_meter)
490
490
  self._old_stages.append(part_stage_url)
491
491
  xform = UsdGeom.Xform.Define(part_stage, "/" + partname)
@@ -766,6 +766,17 @@ class OmniverseUpdateHandler(UpdateHandler):
766
766
  # move the model transform to the camera transform
767
767
  sc = Gf.Matrix4d(self._omni._units_per_meter)
768
768
  cam.transform = c * m.GetInverse() * sc
769
+
770
+ # Determine if the camera is principally more Y, or Z up. X up not supported.
771
+ # Omniverse' built in navigator tries to keep this direction up
772
+ # If the view is principally -Y, there is no good choice. +Y is least bad.
773
+ cam_upvec = Gf.Vec4d(0, 1, 0, 0) * cam.transform
774
+ if abs(cam_upvec[1]) >= abs(cam_upvec[2]):
775
+ self._up_axis = UsdGeom.Tokens.y
776
+ else:
777
+ self._up_axis = UsdGeom.Tokens.z
778
+ UsdGeom.SetStageUpAxis(self._omni._stage, self._up_axis)
779
+
769
780
  # set the updated camera
770
781
  geom_cam.SetFromCamera(cam)
771
782
  # apply the inverse cam transform to move the center of interest