Simple workflow#

This example shows how to use PyConcentEV to perform basic operations. - Required imports - Define example data - Get a token from Ansys ID - Use API client for the Ansys ConceptEV service

Perform Required imports#

import datetime
from pathlib import Path

import matplotlib.pyplot as plt

from ansys.conceptev.core import app, auth
Encryption unavailable. Opting in to plain text.
Traceback (most recent call last):
  File "/home/runner/work/pyconceptev/pyconceptev/.venv/lib/python3.13/site-packages/msal_extensions/libsecret.py", line 18, in <module>
    import gi  # https://github.com/AzureAD/microsoft-authentication-extensions-for-python/wiki/Encryption-on-Linux  # pylint: disable=line-too-long
    ^^^^^^^^^
ModuleNotFoundError: No module named 'gi'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/runner/work/pyconceptev/pyconceptev/src/ansys/conceptev/core/auth.py", line 51, in build_persistence
    return build_encrypted_persistence(location)
  File "/home/runner/work/pyconceptev/pyconceptev/.venv/lib/python3.13/site-packages/msal_extensions/persistence.py", line 98, in build_encrypted_persistence
    return LibsecretPersistence(location)
  File "/home/runner/work/pyconceptev/pyconceptev/.venv/lib/python3.13/site-packages/msal_extensions/persistence.py", line 314, in __init__
    from .libsecret import (  # This uncertain import is deferred till runtime
        LibSecretAgent, trial_run)
  File "/home/runner/work/pyconceptev/pyconceptev/.venv/lib/python3.13/site-packages/msal_extensions/libsecret.py", line 20, in <module>
        raise ImportError("""Unable to import module 'gi'
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<5 lines>...
    """)  # Message via exception rather than log
    ^^^^
ImportError: Unable to import module 'gi'
Runtime dependency of PyGObject is missing.
Depends on your Linux distro, you could install it system-wide by something like:
    sudo apt install python3-gi python3-gi-cairo gir1.2-secret-1
If necessary, please refer to PyGObject's doc:
https://pygobject.readthedocs.io/en/latest/getting_started.html

Define example data#

You can obtain example data from the schema sections of the API documentation.

MOTOR_LAB_FILE = Path("resources") / "e9.lab"
MOTOR_LOSS_MAP_FILE = Path("resources") / "e9.xlsx"
AERO_1 = {
    "name": "New Aero Config",
    "drag_coefficient": 0.3,
    "cross_sectional_area": 2,
    "config_type": "aero",
}

AERO_2 = {
    "name": "Second Aero Configuration",
    "drag_coefficient": 0.6,
    "cross_sectional_area": 3,
    "config_type": "aero",
}

MASS = {
    "name": "New Mass Config",
    "mass": 3000,
    "config_type": "mass",
}

WHEEL = {
    "name": "New Wheel Config",
    "rolling_radius": 0.3,
    "config_type": "wheel",
}

TRANSMISSION = {
    "gear_ratios": [5],
    "headline_efficiencies": [0.95],
    "max_torque": 500,
    "max_speed": 2000,
    "static_drags": [0.5],
    "friction_ratios": [60],
    "windage_ratios": [40],
    "component_type": "TransmissionLossCoefficients",
}

BATTERY = {
    "capacity": 86400000,
    "charge_acceptance_limit": 0,
    "component_type": "BatteryFixedVoltages",
    "internal_resistance": 0.1,
    "name": "New Battery",
    "voltage_max": 400,
    "voltage_mid": 350,
    "voltage_min": 300,
}

motor_data = {"name": "e9", "component_type": "MotorLabID", "inverter_losses_included": False}

Get a token from Ansys ID#

Get a token from Ansys ID to authenticate with the Ansys ConceptEV service.

msal_app = auth.create_msal_app()
token = auth.get_ansyId_token(msal_app)
Encryption unavailable. Opting in to plain text.
Traceback (most recent call last):
  File "/home/runner/work/pyconceptev/pyconceptev/.venv/lib/python3.13/site-packages/msal_extensions/libsecret.py", line 18, in <module>
    import gi  # https://github.com/AzureAD/microsoft-authentication-extensions-for-python/wiki/Encryption-on-Linux  # pylint: disable=line-too-long
    ^^^^^^^^^
ModuleNotFoundError: No module named 'gi'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/runner/work/pyconceptev/pyconceptev/src/ansys/conceptev/core/auth.py", line 51, in build_persistence
    return build_encrypted_persistence(location)
  File "/home/runner/work/pyconceptev/pyconceptev/.venv/lib/python3.13/site-packages/msal_extensions/persistence.py", line 98, in build_encrypted_persistence
    return LibsecretPersistence(location)
  File "/home/runner/work/pyconceptev/pyconceptev/.venv/lib/python3.13/site-packages/msal_extensions/persistence.py", line 314, in __init__
    from .libsecret import (  # This uncertain import is deferred till runtime
        LibSecretAgent, trial_run)
  File "/home/runner/work/pyconceptev/pyconceptev/.venv/lib/python3.13/site-packages/msal_extensions/libsecret.py", line 20, in <module>
        raise ImportError("""Unable to import module 'gi'
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<5 lines>...
    """)  # Message via exception rather than log
    ^^^^
ImportError: Unable to import module 'gi'
Runtime dependency of PyGObject is missing.
Depends on your Linux distro, you could install it system-wide by something like:
    sudo apt install python3-gi python3-gi-cairo gir1.2-secret-1
If necessary, please refer to PyGObject's doc:
https://pygobject.readthedocs.io/en/latest/getting_started.html

Use API client for the Ansys ConceptEV service#

Use the API client to perform basic operations on the Ansys ConceptEV service. Such as: - Check api connection is healthy. - Get the account ID and HPC ID. - Create a new project. - Create a new concept within that project.

with app.get_http_client(token) as client:
    health = app.get(client, "/health")
    print(f"API is healthy: {health}\n")

    account_id = app.get_account_id(token)

    hpc_id = app.get_default_hpc(token, account_id)
    product_id = app.get_product_id(token)
    # Uncomment to print HPC ID
    # print(f"HPC ID: {hpc_id}\n")
    # Create a project
    project = app.create_new_project(
        client, account_id, hpc_id, f"New Project +{datetime.datetime.now()}"
    )
    print(f"ID of the created project: {project['projectId']}")

    # Create a concept with that project

    concept = app.create_new_concept(
        client, project["projectId"], product_id, f"New Concept +{datetime.datetime.now()}"
    )
    print(f"ID of the created concept: {concept['id']}")
API is healthy: {'name': 'ConceptEV', 'version': '0.2.35'}

ID of the created project: 8608ad42-9d40-4f28-bb3b-e6ab8450e238
ID of the created concept: 67e13b8faf05df2bce8ecb1a

Perform basic operations#

Perform basic operations on the design instance associated with the new project. Such as: - Create configurations. - Create components. - Create architectures. - Create requirements. - Create and submit a job. - Read the results and show the result in your browser.

design_instance_id = concept["design_instance_id"]

with app.get_http_client(token, design_instance_id) as client:

    # Create configurations
    created_aero = app.post(client, "/configurations", data=AERO_1)
    created_aero2 = app.post(client, "/configurations", data=AERO_2)
    created_mass = app.post(client, "/configurations", data=MASS)
    created_wheel = app.post(client, "/configurations", data=WHEEL)

    # Read all aero configurations
    configurations = app.get(
        client, f"/concepts/{design_instance_id}/configurations", params={"config_type": "aero"}
    )
    # Uncomment to print configurations
    # print(f"List of configurations: {configurations}\n")

    # Get a specific aero configuration
    aero = app.get(client, "/configurations", id=created_aero["id"])
    print(f"First created areo configuration: {aero}\n")

    # Create component
    created_transmission = app.post(client, "/components", data=TRANSMISSION)

    # Create component from file
    motor_lab = app.post_component_file(client, MOTOR_LAB_FILE, "motor_lab_file")
    motor_data["data_id"] = motor_lab[0]
    motor_data["max_speed"] = motor_lab[1]

    created_motor_lab = app.post(client, "/components", data=motor_data)
    print(f"Created motor: {created_motor_lab}\n")

    # Create loss map motor component from file
    client.timeout = 2000
    motor_loss_map = app.post_component_file(client, MOTOR_LOSS_MAP_FILE, "motor_torque_grid_file")
    loss_map_motor_data = {
        "name": "e9_loss_map",
        "component_type": "MotorLossMapID",
        "poles": 8,
        "data_id": motor_loss_map[0],
    }

    created_motor = app.post(client, "/components", data=loss_map_motor_data)
    print(f"Created motor: {created_motor}\n")

    # Extend client timeout to get loss map from the motor
    client.timeout = 2000
    motor_loss_map = app.post(
        client,
        "/components:get_display_data",
        data={},
        params={"component_id": created_motor_lab["id"]},
    )

    # Show a figure of the loss map from the motor in you browser
    x = motor_loss_map["currents"]
    y = motor_loss_map["phase_advances"]
    z = motor_loss_map["losses_total"]

    fig, ax = plt.subplots()
    im = ax.pcolormesh(x, y, z)
    ax.set_xlabel("Currents (A)")
    ax.set_ylabel("Phase Advances (deg)")
    fig.colorbar(im, ax=ax, label="Total Losses (W)")
    plt.show()

    created_battery = app.post(client, "/components", data=BATTERY)

    # Create an architecture
    architecture = {
        "number_of_front_wheels": 2,
        "number_of_front_motors": 1,
        "front_transmission_id": created_transmission["id"],
        "front_motor_id": created_motor["id"],
        "number_of_rear_wheels": 2,
        "number_of_rear_motors": 0,
        "battery_id": created_battery["id"],
    }
    created_arch = app.post(client, "/architectures", data=architecture)
    print(f"Created architecture: {created_arch}\n")

    # Create a requirement
    requirement = {
        "speed": 10,
        "acceleration": 1,
        "aero_id": created_aero["id"],
        "mass_id": created_mass["id"],
        "wheel_id": created_wheel["id"],
        "state_of_charge": 0.9,
        "requirement_type": "static_acceleration",
        "name": "Static Requirement 1",
    }
    created_requirement = app.post(client, "requirements", data=requirement)
    print(f"Created requirement: {created_requirement}")

    # Create and submit a job
    concept = app.get(client, "/concepts", id=design_instance_id, params={"populated": True})
    job_info = app.create_submit_job(client, concept, account_id, hpc_id)

    # Read and plot the results
    results = app.read_results(client, job_info, calculate_units=False, filtered=True)
    x = results[0]["capability_curve"]["speeds"]
    y = results[0]["capability_curve"]["torques"]

    fig, ax = plt.subplots()
    fig = ax.scatter(x, y, label="Capability Curve")
    ax.set_xlabel("Speed (rad/s)")
    ax.set_ylabel("Torque (Nm)")
    plt.show()
  • 01 simple workflow
  • 01 simple workflow
First created areo configuration: {'item_type': 'config', 'name': 'New Aero Config', 'drag_coefficient_front': 0.3, 'drag_coefficient_rear': None, 'cross_sectional_area': 2.0, 'config_type': 'aero', 'id': '67e13b8faf05df2bce8ecb1b'}

Created motor: {'item_type': 'component', 'name': 'e9', 'mass': 0.0, 'moment_of_inertia': 0.0, 'cost': 0.0, 'id': '67e13b90af05df2bce8ecb22', 'data_id': '67e13b8faf05df2bce8ecb20', 'submitted_job': None, 'inverter_losses_included': False, 'max_speed': 10000.0, 'stator_winding_temp': None, 'rotor_temp': None, 'stator_current_limit': None, 'component_type': 'MotorLabID'}

Created motor: {'item_type': 'component', 'name': 'e9_loss_map', 'mass': 0.0, 'moment_of_inertia': 0.0, 'cost': 0.0, 'id': '67e13b96af05df2bce8ecb25', 'data_id': '67e13b95af05df2bce8ecb23', 'submitted_job': None, 'poles': 8, 'voltages': [400.0, 300.0], 'inverter_losses_included': False, 'component_type': 'MotorLossMapID'}

Created architecture: {'id': '67e13b98af05df2bce8ecb28', 'wheelbase': None, 'components_cost': 0.0, 'components_mass': 0.0, 'max_wheel_speed': 2000.0, 'number_of_front_wheels': 2, 'number_of_front_motors': 1, 'front_clutch_id': None, 'front_transmission_id': '67e13b8faf05df2bce8ecb1f', 'front_motor_id': '67e13b96af05df2bce8ecb25', 'front_inverter_id': None, 'number_of_rear_wheels': 2, 'number_of_rear_motors': 0, 'rear_clutch_id': None, 'rear_transmission_id': None, 'rear_motor_id': None, 'rear_inverter_id': None, 'battery_id': '67e13b96af05df2bce8ecb26'}

Created requirement: {'requirement_type': 'static_acceleration', 'id': '67e13b98af05df2bce8ecb2a', 'name': 'Static Requirement 1', 'speed': 9.999999999999998, 'acceleration': 1.0, 'aero_id': '67e13b8faf05df2bce8ecb1b', 'mass_id': '67e13b8faf05df2bce8ecb1d', 'wheel_id': '67e13b8faf05df2bce8ecb1e', 'deceleration_limit_id': None, 'state_of_charge': 0.9000000000000001, 'altitude': 0.0, 'headwind': 0.0, 'gradient': 0.0, 'front_axle_split': None}
Connected to OCM Websockets.
Status:RUNNING
Status:PHASE_PROGRESS
Status:PHASE_PROGRESS
Status:PHASE_DONE
Status:PHASE_PROGRESS
Progress:1
Status:uploading
Status:PHASE_DONE
Status:PHASE_PROGRESS
Status:PHASE_PROGRESS
Status:PHASE_DONE
Status:FINISHED
Encryption unavailable. Opting in to plain text.
Traceback (most recent call last):
  File "/home/runner/work/pyconceptev/pyconceptev/.venv/lib/python3.13/site-packages/msal_extensions/libsecret.py", line 18, in <module>
    import gi  # https://github.com/AzureAD/microsoft-authentication-extensions-for-python/wiki/Encryption-on-Linux  # pylint: disable=line-too-long
    ^^^^^^^^^
ModuleNotFoundError: No module named 'gi'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/runner/work/pyconceptev/pyconceptev/src/ansys/conceptev/core/auth.py", line 51, in build_persistence
    return build_encrypted_persistence(location)
  File "/home/runner/work/pyconceptev/pyconceptev/.venv/lib/python3.13/site-packages/msal_extensions/persistence.py", line 98, in build_encrypted_persistence
    return LibsecretPersistence(location)
  File "/home/runner/work/pyconceptev/pyconceptev/.venv/lib/python3.13/site-packages/msal_extensions/persistence.py", line 314, in __init__
    from .libsecret import (  # This uncertain import is deferred till runtime
        LibSecretAgent, trial_run)
  File "/home/runner/work/pyconceptev/pyconceptev/.venv/lib/python3.13/site-packages/msal_extensions/libsecret.py", line 20, in <module>
        raise ImportError("""Unable to import module 'gi'
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<5 lines>...
    """)  # Message via exception rather than log
    ^^^^
ImportError: Unable to import module 'gi'
Runtime dependency of PyGObject is missing.
Depends on your Linux distro, you could install it system-wide by something like:
    sudo apt install python3-gi python3-gi-cairo gir1.2-secret-1
If necessary, please refer to PyGObject's doc:
https://pygobject.readthedocs.io/en/latest/getting_started.html

Delete the extra project on the server.#

Delete the project on the server.

Warning

This will delete the project and all its contents. Only needed for keep test environment clean.

with app.get_http_client(token) as client:

    client.params = client.params.set("design_instance_id", concept["design_instance_id"])
    app.delete(client, "concepts", id=concept["id"])
    app.delete_project(concept["project_id"], token)
    print(f"Deleted project {concept['project_id']}")
Deleted project 8608ad42-9d40-4f28-bb3b-e6ab8450e238

Total running time of the script: (1 minutes 5.018 seconds)

Gallery generated by Sphinx-Gallery