Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: Build and Publish ansys-workbench-core

# run only on main branch. This avoids duplicated actions on PRs
on:
pull_request:
push:
tags:
- "*"
branches:
- main

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
MAIN_PYTHON_VERSION: "3.10"
PACKAGE_NAME: "ansys.workbench.core"

jobs:

package:
name: Package
runs-on: ubuntu-latest
steps:
- name: Build library source and wheel artifacts
uses: ansys/actions/build-library@v4
with:
library-name: ${{ env.PACKAGE_NAME }}
python-version: ${{ env.MAIN_PYTHON_VERSION }}
- name: Upload package
uses: actions/upload-artifact@v3
with:
name: ansys-workbench-core-packages
path: dist/
retention-days: 7

release:
name: Release
if: github.event_name == 'push' && contains(github.ref, 'refs/tags')
needs: [package]
runs-on: ubuntu-latest
steps:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ env.MAIN_PYTHON_VERSION }}

- name: Download package
uses: actions/download-artifact@v3
with:
name: ansys-workbench-core-packages

- name: Display structure of downloaded files
run: ls -R

- name: Upload to Ansys private PyPI
run: |
pip install twine
twine upload --skip-existing ./*.whl
twine upload --skip-existing ./*.tar.gz
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYANSYS_PYPI_PRIVATE_PAT }}
TWINE_REPOSITORY_URL: https://pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/upload

- name: Github release
uses: softprops/action-gh-release@v1
with:
generate_release_notes: true
files: |
./*.whl
./*.tar.gz
105 changes: 103 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,103 @@
# pyworkbench
PyWorkbench
### ansys-workbench-core PyWorkbench Package

This Python package contains the public API to PyWorkbench.


#### Installation

NOTE: Users must first apply the `PYANSYS_PRIVATE_PYPI_PAT` token as an environment variable. This allows authentication with Private PyPI.
The value can be found at the following [link](https://dev-docs.solutions.ansys.com/solution_journey/journey_prepare/connect_to_private_pypi.html).

Provided that these wheels have been published to PyPI, they can be
installed with:

Linux (bash)
```bash
# Create and activate a virtualenv
python -m venv .venv
source .venv/bin/activate # can be deactivated with the 'deactivate' command
# Install pre-requisites to connect to artifact feed
pip install --upgrade pip
pip install keyring artifacts-keyring
#Install wMI (Not Available in Private PyPI At This Time)
pip install wMI==1.5.1
# Install the latest package
pip install --index-url https://$PYANSYS_PRIVATE_PYPI_PAT@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple ansys-workbench-core
# OR - Install a package version of your choice
pip install --index-url https://$PYANSYS_PRIVATE_PYPI_PAT@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple ansys-workbench-core==0.1.2
```

Windows (PowerShell)
```powershell
# Create and activate a virtualenv
python.exe -m venv .venv
.\venv\Scripts\Activate.ps1 # can be deactivated with the 'deactivate' command
# Install pre-requisites to connect to artifact feed
pip.exe install --upgrade pip
pip.exe install keyring artifacts-keyring
#Install wMI (Not Available in Private PyPI At This Time)
pip.exe install wMI==1.5.1
# Install the latest package
pip.exe install --index-url https://$env:PYANSYS_PRIVATE_PYPI_PAT@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple ansys-workbench-core
# OR - Install a package version of your choice
pip.exe install --index-url https://$env:PYANSYS_PRIVATE_PYPI_PAT@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple ansys-workbench-core==0.1.2
```

Windows (Command Prompt)
```
# Create and activate a virtualenv
python -m venv .venv
.\venv\Scripts\activate.bat # can be deactivated with the 'deactivate' command
# Install pre-requisites to connect to artifact feed
pip install --upgrade pip
pip install keyring artifacts-keyring
#Install wMI (Not Available in Private PyPI At This Time)
pip install wMI==1.5.1
# Install the latest package
pip install --index-url https://%PYANSYS_PRIVATE_PYPI_PAT%@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple ansys-workbench-core
# OR - Install a package version of your choice
pip install --index-url https://%PYANSYS_PRIVATE_PYPI_PAT%@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple ansys-workbench-core==0.1.2
```


#### Build

To build the gRPC packages, run:

```
pip install build
python -m build
```

This will create both the source distribution containing just the protofiles
along with the wheel containing the protofiles and build Python interface
files.

Note that the interface files are identical regardless of the version of Python
used to generate them, but the last pre-built wheel for ``grpcio~=1.17`` was
Python 3.7, so to improve your build time, use Python 3.7 when building the
wheel.


#### Automatic Deployment

This repository contains GitHub CI/CD that enables the automatic building of
source and wheel packages for these gRPC Python interface files. By default,
these are built on PRs, the main branch, and on tags when pushing. Artifacts
are uploaded to GitHub for each PR and push to the main branch. Artifacts
are published to Ansys Private PyPI when tags are pushed.

To release wheels to PyPI, ensure your branch is up-to-date and then
push tags. For example, for the version ``v0.1.5``. This version MUST MATCH
the version in `pyproject.toml`.

For example, if you intend to release version `0.1.5` to Private PyPI, the
pyproject.toml file should contain '0.1.5'. You will then run:

```bash
git tag v0.1.5
git push --tags
```

Note that there is a 'v' prepended to the GitHub tag, keeping with best practices.
The 'v' is not required in the `pyproject.toml` file.
188 changes: 188 additions & 0 deletions example/demo.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "558376fd-674a-424c-8885-65a872acfd95",
"metadata": {},
"source": [
"# PyFluent and PyMechanical out of PyWorkbench session"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "014c5732-9f2b-423d-81ed-8e70928b2e47",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"import os\n",
"import json\n",
"from ansys.workbench.core.launch_workbench import launch_workbench\n",
"import ansys.fluent.core as pyfluent\n",
"from ansys.mechanical.core import launch_mechanical"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "705a3b24-b51d-4724-8a17-f7307873197c",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"# launch Workbench on the local machine\n",
"wb = launch_workbench(client_workdir='C:/Users/fli/demo')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d02aea0f-e99b-434b-b3d1-c60a87b092ea",
"metadata": {},
"outputs": [],
"source": [
"# upload-download-file round trip\n",
"wb.upload_file('sample.png')\n",
"wb.run_script_string(\"\"\"import os\n",
"wdir = GetServerWorkingDirectory()\n",
"if os.path.exists(os.path.join(wdir, 'renamed.png')):\n",
" os.remove(os.path.join(wdir, 'renamed.png'))\n",
"os.rename(os.path.join(wdir, 'sample.png'), os.path.join(wdir, 'renamed.png'))\n",
"\"\"\")\n",
"wb.download_file('renamed.png')\n",
"are_same = open('sample.png', 'rb').read() == open('renamed.png', 'rb').read()\n",
"print('are two files the same? ' + str(are_same))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b6af4888-7482-4c40-96da-c959b4147b3a",
"metadata": {},
"outputs": [],
"source": [
"# create a Fluent system and return its name\n",
"fluent_sys_name = wb.run_script_string('import json\\nwb_script_result=json.dumps(GetTemplate(TemplateName=\\\"FLUENT\\\").CreateSystem().Name)')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e88ab850-d840-4919-954c-eacd29a699fd",
"metadata": {},
"outputs": [],
"source": [
"# start PyFluent server on the system, then create a PyFluent client session\n",
"server_info_file=wb.start_pyfluent(system_name=fluent_sys_name)\n",
"fluent=pyfluent.connect_to_fluent(server_info_filepath=server_info_file)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "221ad401-82d1-480d-8910-da0dd34b5a2c",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"# basic status queries on the PyFluent session\n",
"print('server is serving? ' + str(fluent.health_check_service.is_serving))\n",
"print('server version: ' + fluent.get_fluent_version())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6a3fd1a1-d261-45e0-9c9f-3f043d00aea6",
"metadata": {},
"outputs": [],
"source": [
"# upload an example Fluent case file, load it into the Fluent session\n",
"wb.upload_file_from_example_repo(\"elbow.cas.h5\", \"elbow_case_file\")\n",
"setup_state=wb.run_script_string(f\"\"\"import os\n",
"sys=GetSystem(Name='{fluent_sys_name}')\n",
"dir=GetServerWorkingDirectory()\n",
"sys.GetContainer(ComponentName=\"Setup\").Import(FilePath=os.path.join(dir, 'elbow.cas.h5'), FileType='CffCase')\n",
"setup=sys.GetComponent(Name=\"Setup\")\n",
"setup.Refresh()\n",
"wb_script_result = json.dumps(GetComponentState(Component=setup).State.ToString())\n",
"\"\"\")\n",
"print('Fluent Setup component is ' + setup_state)\n",
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a94f8a4e-4995-4d48-8966-8734c6c9d4bc",
"metadata": {},
"outputs": [],
"source": [
"# create a Mechanical system on Workbench, then load geometry\n",
"wb.upload_file_from_example_repo(\"2pipes.agdb\", \"2pipes\")\n",
"ss_system_name = wb.run_script_file('load_geometry.wbjn')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "110c8edc-e890-422b-8323-3dddb2af346c",
"metadata": {},
"outputs": [],
"source": [
"# start PyMechanical server on the system, then create a PyMechanical client session\n",
"#server_port=wb.start_pymechanical(system_name=ss_system_name)\n",
"mechanical = launch_mechanical(start_instance=False, ip='localhost', port=server_port)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "48320724-37fb-41d4-959e-d9b0437a7bff",
"metadata": {},
"outputs": [],
"source": [
"# perform some queries on the PyMechanical session\n",
"print(mechanical.version)\n",
"mechanical.list_files()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6dfe8b49-c81b-4718-851e-e1f6f0f30a12",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"# shutdown the Workbench service\n",
"wb.exit()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.4"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
13 changes: 13 additions & 0 deletions example/load_geometry.wbjn
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import os
import json

work_dir = GetServerWorkingDirectory()
geometry_file = os.path.join(work_dir, "2pipes.agdb")

# create a Static Structural system with the given geometry
template = GetTemplate(TemplateName="Static Structural", Solver="ANSYS")
system = CreateSystemFromTemplate(Template=template, Name="Static Structural (ANSYS)")
system.GetContainer(ComponentName="Geometry").SetFile(FilePath=geometry_file)

# output the name of the system
wb_script_result = json.dumps(system.Name)
Binary file added example/sample.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading