Note
Go to the end to download the full example code.
Create a plug-in package that has third-party dependencies#
This example shows how to create a Python plug-in package with third-party dependencies. You should be familiar with these examples before proceeding with this more advanced one:
This plug-in contains an operator whose implementation depends on a third-party Python module named gltf. This operator takes a path, a mesh, and a 3D vector field as inputs and then exports the mesh and the norm of the 3D vector field to a GLTF file at the given path.
Note
This example requires DPF 4.0 (Ansys 2022R2) or above. For more information, see Compatibility.
Create the plug-in package#
Each operator implementation derives from the
ansys.dpf.core.custom_operator.CustomOperatorBase
class
and a call to the ansys.dpf.core.custom_operator.record_operator()
method, which records the operators of the plug-in package.
Download the gltf_plugin
plug-in package that has already been
created for you.
import os
from pathlib import Path
from ansys.dpf.core import examples
plugin_path = Path(examples.download_gltf_plugin())
folder_root = Path(str(Path.cwd()).rsplit("pydpf-core", 1)[0]) / "pydpf-core"
To add third-party modules as dependencies to a plug-in package, you must
create and reference a folder or ZIP file with the sites of the dependencies
in an XML file located next to the folder for the plug-in package. The XML
file must have the same name as the plug-in package plus an .xml
extension.
When the ansys.dpf.core.core.load_library()
method is called,
DPF-Core uses the site
Python module to add custom to the path
for the Python interpreter.
To create these custom sites, requirements of the plug-in package should be installed in a Python virtual environment, the site-packages (with unnecessary folders removed) should be compressed to a ZIP file and placed with the plugin. The path to this ZIP file should be referenced in the XML as shown in the preceding code.
To simplify this step, you can add a requirements file in the plug-in package:
print("\033[1m gltf_plugin/requirements.txt: \n \033[0m")
requirements_path = plugin_path / "requirements.txt"
with requirements_path.open("r") as file:
for line in file.readlines():
print("\t\t\t" + line)
gltf_plugin/requirements.txt:
wheel
pygltflib
Download the script for your operating system.
For Windows, download this
PowerShell script
.For Linux, download this
Shell script
.
Run the downloaded script with the mandatory arguments:
-pluginpath
: Path to the folder with the plug-in package.-zippath
: Path and name for the ZIP file.
Optional arguments are:
-pythonexe
: Path to a Python executable of your choice.-tempfolder
: Path to a temporary folder to work in. The default is the environment variableTEMP
on Windows and/tmp/
on Linux.
Run the command for your operating system.
From Windows PowerShell, run:
create_sites_for_python_operators.ps1 -pluginpath /path/to/plugin -zippath /path/to/plugin/assets/winx64.zip # noqa: E501
From Linux Shell, run:
create_sites_for_python_operators.sh -pluginpath /path/to/plugin -zippath /path/to/plugin/assets/linx64.zip # noqa: E501
site_path = plugin_path / "assets" / "gltf_sites_winx64.zip"
if os.name == "nt" and not site_path.exists():
cmd_file = (
folder_root / "doc" / "source" / "user_guide" / "create_sites_for_python_operators.ps1"
)
args = [
"powershell",
str(cmd_file),
"-pluginpath",
str(plugin_path),
"-zippath",
str(plugin_path / "assets" / "gltf_sites_winx64.zip"),
]
print(args)
import subprocess
process = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if process.stderr:
raise RuntimeError(
"Installing pygltf in a virtual environment failed with error:\n"
+ f"return code = {process.returncode}\n"
+ process.stderr.decode()
+ "\n\n and log:\n"
+ process.stdout.decode()
)
else:
print("Installing pygltf in a virtual environment succeeded")
elif os.name == "posix" and not site_path.exists():
cmd_file = (
folder_root / "doc" / "source" / "user_guide" / "create_sites_for_python_operators.sh"
)
run_cmd = f"{cmd_file}"
args = (
f' -pluginpath "{plugin_path}" '
f'-zippath "{plugin_path / "assets" / "gltf_sites_winx64.zip"}"'
)
print(run_cmd + args)
os.system(f"chmod u=rwx,o=x {cmd_file}")
os.system(run_cmd + args)
print("\nInstalling pygltf in a virtual environment succeeded")
['powershell', 'D:\\a\\pydpf-core\\pydpf-core\\doc\\source\\user_guide\\create_sites_for_python_operators.ps1', '-pluginpath', 'D:\\a\\pydpf-core\\pydpf-core\\.venv\\lib\\site-packages\\ansys\\dpf\\core\\examples\\python_plugins\\gltf_plugin', '-zippath', 'D:\\a\\pydpf-core\\pydpf-core\\.venv\\lib\\site-packages\\ansys\\dpf\\core\\examples\\python_plugins\\gltf_plugin\\assets\\gltf_sites_winx64.zip']
Installing pygltf in a virtual environment succeeded
Load the plug-in package#
You use the function ansys.dpf.core.core.load_library()
to load the
plug-in package.
The first argument is the path to the directory where the plug-in package is located.
The second argument is
py_<package>
, where<package>
is the name identifying the plug-in package.The third argument is the name of the function exposed in the
__init__
file for the plug-in package that is used to record operators.
from ansys.dpf import core as dpf
from ansys.dpf.core import examples
# Python plugins are not supported in process.
dpf.start_local_server(config=dpf.AvailableServerConfigs.GrpcServer)
tmp = Path(dpf.make_tmp_dir_server())
dpf.upload_files_in_folder(dpf.path_utilities.join(str(tmp), "plugins", "gltf_plugin"), plugin_path)
dpf.upload_file(
str(plugin_path) + ".xml", dpf.path_utilities.join(str(tmp), "plugins", "gltf_plugin.xml")
)
dpf.load_library(
dpf.path_utilities.join(str(tmp), "plugins", "gltf_plugin"),
"py_dpf_gltf",
"load_operators",
)
'py_dpf_gltf successfully loaded'
Instantiate the operator.
new_operator = dpf.Operator("gltf_export")
This new gltf_export
operator requires the following as inputs: a triangle
surface mesh, a displacement field on this surface mesh, and a path to export
the GLTF file to.
To demonstrate this new operator, a ansys.dpf.core.model.Model
class
is created on a simple file and the
ansys.dpf.core.operators.mesh.tri_mesh_skin
operator is used
to extract the surface of the mesh in triangle elements.
Use the custom operator#
model = dpf.Model(dpf.upload_file_in_tmp_folder(examples.find_static_rst()))
mesh = model.metadata.meshed_region
skin_mesh = dpf.operators.mesh.tri_mesh_skin(mesh=mesh)
displacement = model.results.displacement()
displacement.inputs.mesh_scoping(skin_mesh)
displacement.inputs.mesh(skin_mesh)
new_operator.inputs.path(str(tmp / "out"))
new_operator.inputs.mesh(skin_mesh)
new_operator.inputs.field(displacement.outputs.fields_container()[0])
new_operator.run()
print("operator ran successfully")
dpf.download_file(tmp / "out.glb", Path.cwd() / "out.glb")
operator ran successfully
You can download output
from the gltf
operator.
Total running time of the script: (0 minutes 49.908 seconds)