You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

ansys-additive-core

Package Overview
Dependencies
Maintainers
1
Versions
70
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ansys-additive-core - pypi Package Compare versions

Comparing version
0.20.1
to
0.19.2
+37
src/ansys/additive/core/simulation_input_base.py
# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""Provides a base class for simulation inputs."""
from ansys.additive.core import misc
class SimulationInputBase:
"""Provides a base class for simulation inputs."""
def __init__(self) -> None:
"""Initialize the simulation input base class."""
self._id: str = misc.short_uuid()
@property
def id(self) -> str:
"""Return a unique identifier for this simulation."""
return self._id
+13
-13
MIT License
Copyright (c) 2023 - 2025 ANSYS, Inc. and/or its affiliates.
Copyright (c) 2023 ANSYS, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the “Software”), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
+37
-35
Metadata-Version: 2.4
Name: ansys-additive-core
Version: 0.20.1
Version: 0.19.2
Summary: A Python client for the Ansys Additive service

@@ -17,5 +17,4 @@ Author-email: "ANSYS, Inc." <pyansys.core@ansys.com>

Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
License-File: LICENSE
Requires-Dist: ansys-api-additive==5.0.3
Requires-Dist: ansys-api-additive==2.2.1
Requires-Dist: ansys-platform-instancemanagement>=1.1.1

@@ -26,4 +25,4 @@ Requires-Dist: ansys-tools-common>=0.4.0

Requires-Dist: googleapis-common-protos>=1.52.0
Requires-Dist: grpcio>=1.35.0
Requires-Dist: grpcio-health-checking>=1.45.0
Requires-Dist: grpcio>=1.63.0
Requires-Dist: grpcio-health-checking>=1.60.0
Requires-Dist: importlib-metadata>=4.0

@@ -39,41 +38,40 @@ Requires-Dist: numpy>=1.20.3

Requires-Dist: ansys-sphinx-theme[autoapi]==1.5.0 ; extra == "doc"
Requires-Dist: enum-tools==0.13.0 ; extra == "doc"
Requires-Dist: joblib==1.5.1 ; extra == "doc"
Requires-Dist: enum-tools==0.12.0 ; extra == "doc"
Requires-Dist: jupyter_sphinx==0.5.3 ; extra == "doc"
Requires-Dist: matplotlib==3.10.3 ; extra == "doc"
Requires-Dist: matplotlib==3.9.2 ; extra == "doc"
Requires-Dist: numpydoc==1.8.0 ; extra == "doc"
Requires-Dist: phantomjs==1.4.1 ; extra == "doc"
Requires-Dist: pypandoc==1.15 ; extra == "doc"
Requires-Dist: pyvista==0.45.2 ; extra == "doc"
Requires-Dist: ipywidgets==8.1.7 ; extra == "doc"
Requires-Dist: trame==3.10.1 ; extra == "doc"
Requires-Dist: trame-vtk==2.8.15 ; extra == "doc"
Requires-Dist: trame-plotly==3.1.0 ; extra == "doc"
Requires-Dist: trame-vuetify==3.0.1 ; extra == "doc"
Requires-Dist: imageio==2.37.0 ; extra == "doc"
Requires-Dist: sphinx==8.2.3 ; extra == "doc"
Requires-Dist: sphinx-autodoc-typehints==3.1.0 ; extra == "doc"
Requires-Dist: pypandoc==1.14 ; extra == "doc"
Requires-Dist: pyvista==0.46.4 ; extra == "doc"
Requires-Dist: ipywidgets==8.1.5 ; extra == "doc"
Requires-Dist: trame==3.7.0 ; extra == "doc"
Requires-Dist: trame-vtk==2.8.11 ; extra == "doc"
Requires-Dist: trame-plotly==3.0.2 ; extra == "doc"
Requires-Dist: trame-vuetify==2.7.1 ; extra == "doc"
Requires-Dist: imageio==2.36.0 ; extra == "doc"
Requires-Dist: sphinx==8.1.3 ; extra == "doc"
Requires-Dist: sphinx-autodoc-typehints==2.5.0 ; extra == "doc"
Requires-Dist: sphinx-copybutton==0.5.2 ; extra == "doc"
Requires-Dist: sphinx-design==0.6.1 ; extra == "doc"
Requires-Dist: sphinx-gallery==0.19.0 ; extra == "doc"
Requires-Dist: sphinx-gallery==0.18.0 ; extra == "doc"
Requires-Dist: sphinx-jinja==2.0.2 ; extra == "doc"
Requires-Dist: sphinx-notfound-page==1.1.0 ; extra == "doc"
Requires-Dist: sphinx-toolbox==4.0.0 ; extra == "doc"
Requires-Dist: sphinx-notfound-page==1.0.4 ; extra == "doc"
Requires-Dist: sphinx-toolbox==3.8.1 ; extra == "doc"
Requires-Dist: sphinxemoji==0.3.1 ; extra == "doc"
Requires-Dist: ipython>=7.0.0 ; extra == "doc"
Requires-Dist: ansys-platform-instancemanagement==1.1.2 ; extra == "tests"
Requires-Dist: dill==0.4.0 ; extra == "tests"
Requires-Dist: google-api-python-client==2.164.0 ; extra == "tests"
Requires-Dist: googleapis-common-protos==1.69.1 ; extra == "tests"
Requires-Dist: grpcio==1.70.0 ; extra == "tests"
Requires-Dist: grpcio-health-checking==1.70.0 ; extra == "tests"
Requires-Dist: numpy==2.2.6 ; extra == "tests"
Requires-Dist: dill==0.3.9 ; extra == "tests"
Requires-Dist: google-api-python-client==2.149.0 ; extra == "tests"
Requires-Dist: googleapis-common-protos==1.65.0 ; extra == "tests"
Requires-Dist: grpcio==1.63.0 ; extra == "tests"
Requires-Dist: grpcio-health-checking==1.60.0 ; extra == "tests"
Requires-Dist: numpy==2.1.2 ; extra == "tests"
Requires-Dist: pandas==2.2.3 ; extra == "tests"
Requires-Dist: platformdirs==4.3.8 ; extra == "tests"
Requires-Dist: protobuf==5.29.3 ; extra == "tests"
Requires-Dist: six==1.17.0 ; extra == "tests"
Requires-Dist: tqdm==4.67.1 ; extra == "tests"
Requires-Dist: pydantic==2.11.5 ; extra == "tests"
Requires-Dist: pytest==8.3.5 ; extra == "tests"
Requires-Dist: pytest-cov==6.1.1 ; extra == "tests"
Requires-Dist: platformdirs==4.3.6 ; extra == "tests"
Requires-Dist: protobuf==5.28.3 ; extra == "tests"
Requires-Dist: six==1.16.0 ; extra == "tests"
Requires-Dist: tqdm==4.66.5 ; extra == "tests"
Requires-Dist: pydantic==2.9.2 ; extra == "tests"
Requires-Dist: pytest==8.3.3 ; extra == "tests"
Requires-Dist: pytest-cov==5.0.0 ; extra == "tests"
Project-URL: Discussions, https://github.com/ansys/pyadditive/discussions

@@ -91,3 +89,3 @@ Project-URL: Documentation, https://additive.docs.pyansys.com

|pyansys| |python| |pypi| |GH-CI| |codecov| |MIT|
|pyansys| |python| |pypi| |GH-CI| |codecov| |MIT| |black|

@@ -118,2 +116,6 @@ .. |pyansys| image:: https://img.shields.io/badge/Py-Ansys-ffc107.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABDklEQVQ4jWNgoDfg5mD8vE7q/3bpVyskbW0sMRUwofHD7Dh5OBkZGBgW7/3W2tZpa2tLQEOyOzeEsfumlK2tbVpaGj4N6jIs1lpsDAwMJ278sveMY2BgCA0NFRISwqkhyQ1q/Nyd3zg4OBgYGNjZ2ePi4rB5loGBhZnhxTLJ/9ulv26Q4uVk1NXV/f///////69du4Zdg78lx//t0v+3S88rFISInD59GqIH2esIJ8G9O2/XVwhjzpw5EAam1xkkBJn/bJX+v1365hxxuCAfH9+3b9/+////48cPuNehNsS7cDEzMTAwMMzb+Q2u4dOnT2vWrMHu9ZtzxP9vl/69RVpCkBlZ3N7enoDXBwEAAA+YYitOilMVAAAAAElFTkSuQmCC

.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg?style=flat
:target: https://github.com/psf/black
:alt: Black
Overview

@@ -120,0 +122,0 @@ ========

@@ -17,3 +17,2 @@ [build-system]

"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]

@@ -26,6 +25,6 @@ description = "A Python client for the Ansys Additive service"

requires-python = ">=3.10,<4"
version = "0.20.1"
version = "0.19.2"
dependencies = [
"ansys-api-additive==5.0.3",
"ansys-api-additive==2.2.1",
"ansys-platform-instancemanagement>=1.1.1",

@@ -36,4 +35,4 @@ "ansys-tools-common>=0.4.0",

"googleapis-common-protos>=1.52.0",
"grpcio>=1.35.0",
"grpcio-health-checking>=1.45.0",
"grpcio>=1.63.0",
"grpcio-health-checking>=1.60.0",
"importlib-metadata>=4.0",

@@ -53,16 +52,16 @@ "numpy>=1.20.3",

"ansys-platform-instancemanagement==1.1.2",
"dill==0.4.0",
"google-api-python-client==2.164.0",
"googleapis-common-protos==1.69.1",
"grpcio==1.70.0",
"grpcio-health-checking==1.70.0",
"numpy==2.2.6",
"dill==0.3.9",
"google-api-python-client==2.149.0",
"googleapis-common-protos==1.65.0",
"grpcio==1.63.0",
"grpcio-health-checking==1.60.0",
"numpy==2.1.2",
"pandas==2.2.3",
"platformdirs==4.3.8",
"protobuf==5.29.3",
"six==1.17.0",
"tqdm==4.67.1",
"pydantic==2.11.5",
"pytest==8.3.5",
"pytest-cov==6.1.1",
"platformdirs==4.3.6",
"protobuf==5.28.3",
"six==1.16.0",
"tqdm==4.66.5",
"pydantic==2.9.2",
"pytest==8.3.3",
"pytest-cov==5.0.0",
]

@@ -72,24 +71,23 @@

"ansys-sphinx-theme[autoapi]==1.5.0",
"enum-tools==0.13.0",
"joblib==1.5.1",
"enum-tools==0.12.0",
"jupyter_sphinx==0.5.3",
"matplotlib==3.10.3",
"matplotlib==3.9.2",
"numpydoc==1.8.0",
"phantomjs==1.4.1",
"pypandoc==1.15",
"pyvista==0.45.2",
"ipywidgets==8.1.7",
"trame==3.10.1",
"trame-vtk==2.8.15",
"trame-plotly==3.1.0",
"trame-vuetify==3.0.1",
"imageio==2.37.0",
"sphinx==8.2.3",
"sphinx-autodoc-typehints==3.1.0",
"pypandoc==1.14",
"pyvista==0.46.4",
"ipywidgets==8.1.5",
"trame==3.7.0",
"trame-vtk==2.8.11",
"trame-plotly==3.0.2",
"trame-vuetify==2.7.1",
"imageio==2.36.0",
"sphinx==8.1.3",
"sphinx-autodoc-typehints==2.5.0",
"sphinx-copybutton==0.5.2",
"sphinx-design==0.6.1",
"sphinx-gallery==0.19.0",
"sphinx-gallery==0.18.0",
"sphinx-jinja==2.0.2",
"sphinx-notfound-page==1.1.0",
"sphinx-toolbox==4.0.0",
"sphinx-notfound-page==1.0.4",
"sphinx-toolbox==3.8.1",
"sphinxemoji==0.3.1",

@@ -109,2 +107,12 @@ "ipython>=7.0.0",

[tool.black]
line-length = 100
[tool.isort]
default_section = "THIRDPARTY"
force_sort_within_sections = true
line_length = 100
profile = "black"
src_paths = ["doc", "src", "tests"]
[tool.coverage.run]

@@ -111,0 +119,0 @@ source = ["ansys.additive.core"]

@@ -5,3 +5,3 @@ ##########

|pyansys| |python| |pypi| |GH-CI| |codecov| |MIT|
|pyansys| |python| |pypi| |GH-CI| |codecov| |MIT| |black|

@@ -32,2 +32,6 @@ .. |pyansys| image:: https://img.shields.io/badge/Py-Ansys-ffc107.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABDklEQVQ4jWNgoDfg5mD8vE7q/3bpVyskbW0sMRUwofHD7Dh5OBkZGBgW7/3W2tZpa2tLQEOyOzeEsfumlK2tbVpaGj4N6jIs1lpsDAwMJ278sveMY2BgCA0NFRISwqkhyQ1q/Nyd3zg4OBgYGNjZ2ePi4rB5loGBhZnhxTLJ/9ulv26Q4uVk1NXV/f///////69du4Zdg78lx//t0v+3S88rFISInD59GqIH2esIJ8G9O2/XVwhjzpw5EAam1xkkBJn/bJX+v1365hxxuCAfH9+3b9/+////48cPuNehNsS7cDEzMTAwMMzb+Q2u4dOnT2vWrMHu9ZtzxP9vl/69RVpCkBlZ3N7enoDXBwEAAA+YYitOilMVAAAAAElFTkSuQmCC

.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg?style=flat
:target: https://github.com/psf/black
:alt: Black
Overview

@@ -34,0 +38,0 @@ ========

@@ -50,15 +50,6 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

from ansys.additive.core.additive import Additive # noqa: F401, E402
from ansys.additive.core.exceptions import ( # noqa: F401, E402
BetaFeatureNotEnabledError,
)
from ansys.additive.core.geometry_file import ( # noqa: F401, E402
BuildFile,
MachineType,
StlFile,
)
from ansys.additive.core.exceptions import BetaFeatureNotEnabledError # noqa: F401, E402
from ansys.additive.core.geometry_file import BuildFile, MachineType, StlFile # noqa: F401, E402
from ansys.additive.core.logger import LOG # noqa: F401, E402
from ansys.additive.core.machine import ( # noqa: F401, E402
AdditiveMachine,
MachineConstants,
)
from ansys.additive.core.machine import AdditiveMachine, MachineConstants # noqa: F401, E402
from ansys.additive.core.material import ( # noqa: F401, E402

@@ -82,15 +73,10 @@ AdditiveMaterial,

)
from ansys.additive.core.porosity import ( # noqa: F401, E402
PorosityInput,
PorositySummary,
)
from ansys.additive.core.porosity import PorosityInput, PorositySummary # noqa: F401, E402
from ansys.additive.core.simulation import ( # noqa: F401, E402
SimulationError,
SimulationStatus,
SimulationType,
)
from ansys.additive.core.simulation_error import SimulationError # noqa: F401, E402
from ansys.additive.core.simulation_task import SimulationTask # noqa: F401, E402
from ansys.additive.core.simulation_task_manager import ( # noqa: F401, E402
SimulationTaskManager,
)
from ansys.additive.core.simulation_task_manager import SimulationTaskManager # noqa: F401, E402
from ansys.additive.core.single_bead import ( # noqa: F401, E402

@@ -97,0 +83,0 @@ MeltPool,

@@ -35,3 +35,2 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

from ansys.additive.core import USER_DATA_PATH, __version__
from ansys.additive.core.download import download_logs
from ansys.additive.core.exceptions import BetaFeatureNotEnabledError

@@ -67,6 +66,6 @@ from ansys.additive.core.logger import LOG

from ansys.additive.core.simulation import (
SimulationError,
SimulationStatus,
SimulationType,
)
from ansys.additive.core.simulation_error import SimulationError
from ansys.additive.core.simulation_requests import create_request

@@ -336,4 +335,2 @@ from ansys.additive.core.simulation_task import SimulationTask

"""Return True if the client is connected to a server."""
if self._server is None:
return False
return self._server.status().connected

@@ -776,4 +773,5 @@

request = input._to_request()
operation = self._server.simulation_stub.Simulate(request)
LOG.debug(f"Material tuning operation created for {input.id}")
operation = self._server.materials_stub.TuneMaterial(request)
return SimulationTask(self._server, operation, input, out_dir)

@@ -813,3 +811,3 @@

progress_handler = ParametricStudyProgressHandler(study)
summaries = []
num_summaries = 0

@@ -824,7 +822,6 @@ try:

task_mgr.status(progress_handler)
current_summaries = task_mgr.summaries()
new_summaries = [s for s in current_summaries if s not in summaries]
if new_summaries:
study.update(new_summaries)
summaries = current_summaries
if len(task_mgr.summaries()) > num_summaries:
# TODO: Only update the study with new summaries
study.update(task_mgr.summaries())
num_summaries = len(task_mgr.summaries())
time.sleep(SLEEP_INTERVAL)

@@ -848,7 +845,2 @@

Notes
-----
The caller of this method is responsible for updating the study with the results of the simulations.
See :meth:`SimulationTaskManager.summaries` and :meth:`ParametricStudy.update`.
Parameters

@@ -912,19 +904,1 @@ ----------

ids.append(i.id)
def download_server_logs(self, log_dir: str | os.PathLike) -> str:
"""Download server logs to a specified directory.
Parameters
----------
log_dir : str
Directory to save the logs to.
Returns
-------
str
Path to the downloaded logs.
"""
if log_dir and not os.path.exists(log_dir):
os.makedirs(log_dir)
return download_logs(self._server.simulation_stub, log_dir)

@@ -24,3 +24,2 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

import datetime
import hashlib

@@ -34,3 +33,2 @@ import os

)
from ansys.api.additive.v0.additive_server_info_pb2_grpc import ServerInfoServiceStub
from ansys.api.additive.v0.additive_simulation_pb2 import DownloadFileRequest

@@ -72,61 +70,4 @@ from ansys.api.additive.v0.additive_simulation_pb2_grpc import SimulationServiceStub

handle_download_file_response(dest, stub.DownloadFile(request), progress_handler)
return dest
def download_logs(
stub: ServerInfoServiceStub,
local_folder: str,
progress_handler: IProgressHandler = None,
) -> str:
"""Download logs from the server to the localhost.
Parameters
----------
stub: ServerInfoServiceStub
gRPC stub for the server information service.
local_folder: str
Folder on your localhost to write the server logs to.
progress_handler: ProgressLogger, None, default: None
Progress update handler. If ``None``, no progress will be provided.
Returns
-------
str
Local path of downloaded file.
"""
if not os.path.isdir(local_folder):
os.makedirs(local_folder)
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
dest = os.path.join(local_folder, f"additive-server-logs-{timestamp}.zip")
response = stub.ServerLogs()
handle_download_file_response(dest, response, progress_handler)
return dest
def handle_download_file_response(
destination: str,
download_file_response: any,
progress_handler: IProgressHandler = None,
) -> None:
"""
Handle server response.
Parameters
----------
destination: str
Destination of the file.
download_file_response: any
Download file response.
progress_handler: IProgressHandler, default: None
Progress handler.
"""
with open(destination, "wb") as f:
for response in download_file_response:
with open(dest, "wb") as f:
for response in stub.DownloadFile(request):
if progress_handler:

@@ -149,1 +90,2 @@ progress_handler.update(

f.write(response.content)
return dest

@@ -26,3 +26,3 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

from ansys.additive.core.simulation import SimulationInputBase
from ansys.additive.core.simulation_input_base import SimulationInputBase
from ansys.api.additive.v0.additive_domain_pb2 import (

@@ -34,3 +34,3 @@ MaterialTuningInput as MaterialTuningInputMessage,

)
from ansys.api.additive.v0.additive_simulation_pb2 import SimulationRequest
from ansys.api.additive.v0.additive_materials_pb2 import TuneMaterialRequest

@@ -99,3 +99,3 @@

def _to_request(self) -> SimulationRequest:
def _to_request(self) -> TuneMaterialRequest:
"""Convert this object into a material tuning request message."""

@@ -116,3 +116,3 @@ input = MaterialTuningInputMessage(

input.characteristic_width_lookup = f.read()
return SimulationRequest(id=self.id, material_tuning_input=input)
return TuneMaterialRequest(id=self.id, input=input)

@@ -119,0 +119,0 @@ def __repr__(self):

@@ -313,4 +313,2 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

anisotropic_strain_coefficient_z: float = 0,
cooling_rate_sim_coeff_a: float = 0,
cooling_rate_sim_coeff_b: float = 0,
description: str = "",

@@ -356,4 +354,2 @@ elastic_modulus: float = 0,

self._anisotropic_strain_coefficient_z = anisotropic_strain_coefficient_z
self._cooling_rate_sim_coeff_a = cooling_rate_sim_coeff_a
self._cooling_rate_sim_coeff_b = cooling_rate_sim_coeff_b
self._description = description

@@ -503,22 +499,2 @@ self._elastic_modulus = elastic_modulus

@property
def cooling_rate_sim_coeff_a(self) -> float:
"""First coefficient for the cooling rate SIM model."""
return self._cooling_rate_sim_coeff_a
@cooling_rate_sim_coeff_a.setter
def cooling_rate_sim_coeff_a(self, value: float):
"""Set cooling rate SIM model coefficient A."""
self._cooling_rate_sim_coeff_a = value
@property
def cooling_rate_sim_coeff_b(self) -> float:
"""Second coefficient for the cooling rate SIM model."""
return self._cooling_rate_sim_coeff_b
@cooling_rate_sim_coeff_b.setter
def cooling_rate_sim_coeff_b(self, value: float):
"""Set cooling rate SIM model coefficient B."""
self._cooling_rate_sim_coeff_b = value
@property
def description(self) -> str:

@@ -525,0 +501,0 @@ """Description of the material."""

@@ -31,7 +31,2 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

from ansys.additive.core.microstructure import Microstructure2DResult
from ansys.additive.core.simulation import (
SimulationInputBase,
SimulationStatus,
SimulationSummaryBase,
)
from ansys.api.additive.v0.additive_domain_pb2 import (

@@ -44,3 +39,3 @@ Microstructure3DInput as Microstructure3DInputMessage,

class Microstructure3DInput(SimulationInputBase):
class Microstructure3DInput:
"""Provides input parameters for 3D microstructure simulation.

@@ -97,2 +92,3 @@

self,
id: str = "",
*,

@@ -114,3 +110,3 @@ sample_min_x: float = DEFAULT_POSITION_COORDINATE,

super().__init__()
self.id = id
self.sample_min_x = sample_min_x

@@ -172,2 +168,11 @@ self.sample_min_y = sample_min_y

@property
def id(self) -> str:
"""User-provided ID for the simulation."""
return self._id
@id.setter
def id(self, value: str):
self._id = value
@property
def machine(self):

@@ -365,3 +370,3 @@ """Machine-related parameters."""

class Microstructure3DSummary(SimulationSummaryBase):
class Microstructure3DSummary:
"""Provides the summary of a 3D microstructure simulation."""

@@ -375,5 +380,3 @@

result: Microstructure3DResult,
logs: str,
user_data_path: str,
status: SimulationStatus = SimulationStatus.COMPLETED,
) -> None:

@@ -387,5 +390,2 @@ """Initialize a ``Microstructure3DSummary`` object."""

raise ValueError("Invalid user data path, " + self.__class__.__name__)
if not isinstance(logs, str):
raise ValueError("Invalid logs type passed to init, " + self.__class__.__name__)
super().__init__(logs, status)
self._input = input

@@ -399,3 +399,2 @@ id = input.id if input.id else misc.short_uuid()

self._2d_result = Microstructure2DResult(result.two_d_result, outpath)
self._logs = logs

@@ -402,0 +401,0 @@ def __repr__(self):

@@ -34,7 +34,3 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

from ansys.additive.core.material import AdditiveMaterial
from ansys.additive.core.simulation import (
SimulationInputBase,
SimulationStatus,
SimulationSummaryBase,
)
from ansys.additive.core.simulation_input_base import SimulationInputBase
from ansys.api.additive.v0.additive_domain_pb2 import (

@@ -520,3 +516,3 @@ MicrostructureInput as MicrostructureInputMessage,

class MicrostructureSummary(SimulationSummaryBase):
class MicrostructureSummary:
"""Provides the summary of a microstructure simulation."""

@@ -528,5 +524,3 @@

result: MicrostructureResultMessage,
logs: str,
user_data_path: str,
status: SimulationStatus = SimulationStatus.COMPLETED,
) -> None:

@@ -540,5 +534,2 @@ """Initialize a ``MicrostructureSummary`` object."""

raise ValueError("Invalid user data path, " + self.__class__.__name__)
if not isinstance(logs, str):
raise ValueError("Invalid logs type passed to init, " + self.__class__.__name__)
super().__init__(logs, status)
self._input = input

@@ -548,3 +539,2 @@ id = input.id if input.id else misc.short_uuid()

self._result = Microstructure2DResult(result, outpath)
self._logs = logs

@@ -551,0 +541,0 @@ def __repr__(self):

@@ -35,4 +35,4 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

Number of characters in the UUID. Only applies if ``nchars`` is greater
than 6. Using the default, the probability of a collision is 1.23e-17
for 1 billion rounds.
than 6. Using the default, the probability
of a collision is 1.23e-17 for 1 billion rounds.

@@ -39,0 +39,0 @@ """

@@ -28,7 +28,3 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

from ansys.additive.core.material import AdditiveMaterial
from ansys.additive.core.simulation import (
SimulationInputBase,
SimulationStatus,
SimulationSummaryBase,
)
from ansys.additive.core.simulation_input_base import SimulationInputBase
from ansys.api.additive.v0.additive_domain_pb2 import (

@@ -167,3 +163,3 @@ PorosityInput as PorosityInputMessage,

class PorositySummary(SimulationSummaryBase):
class PorositySummary:
"""Provides a summary of a porosity simulation."""

@@ -175,4 +171,2 @@

result: PorosityResult,
logs: str,
status: SimulationStatus = SimulationStatus.COMPLETED,
):

@@ -184,8 +178,4 @@ """Initialize a ``PorositySummary`` object."""

raise ValueError("Invalid result type passed to init, " + self.__class__.__name__)
if not isinstance(logs, str):
raise ValueError("Invalid logs type passed to init, " + self.__class__.__name__)
super().__init__(logs, status)
self._input = input
self._relative_density = result.solid_ratio
self._logs = logs

@@ -192,0 +182,0 @@ @property

@@ -31,3 +31,3 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

"""Product name for the Additive server in a PyPIM environment."""
DEFAULT_PRODUCT_VERSION = "252"
DEFAULT_PRODUCT_VERSION = "251"
"""Default Ansys product version to use for the Additive server."""

@@ -34,0 +34,0 @@ ADDITIVE_SERVER_EXE_NAME = "additiveserver"

@@ -28,3 +28,2 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

import time
import weakref
from dataclasses import dataclass

@@ -46,4 +45,4 @@ from pathlib import Path

from ansys.additive.core.server_connection.network_utils import create_channel
from ansys.api.additive.v0.about_pb2_grpc import AboutServiceStub
from ansys.api.additive.v0.additive_materials_pb2_grpc import MaterialsServiceStub
from ansys.api.additive.v0.additive_server_info_pb2_grpc import ServerInfoServiceStub
from ansys.api.additive.v0.additive_settings_pb2_grpc import SettingsServiceStub

@@ -143,4 +142,2 @@ from ansys.api.additive.v0.additive_simulation_pb2_grpc import SimulationServiceStub

weakref.finalize(self, self.disconnect)
if channel and addr:

@@ -183,3 +180,3 @@ raise ValueError("Both 'channel' and 'addr' cannot both be specified.")

self._simulation_stub = SimulationServiceStub(self._channel)
self._server_info_stub = ServerInfoServiceStub(self._channel)
self._about_stub = AboutServiceStub(self._channel)
self._operations_stub = OperationsStub(self._channel)

@@ -226,3 +223,2 @@ self._settings_stub = SettingsServiceStub(self._channel)

"""GRPC channel target.
The form is generally ``"ip:port"``. For example, ``"127.0.0.1:50052"``.

@@ -270,3 +266,3 @@ In the case of UDS channels, the form is the path to the UDS socket file.

try:
response = self._server_info_stub.About(Empty())
response = self._about_stub.About(Empty())
except grpc.RpcError:

@@ -298,3 +294,3 @@ return ServerConnectionStatus(False, self.channel_str)

try:
self._server_info_stub.About(Empty())
self._about_stub.About(Empty())
ready = True

@@ -301,0 +297,0 @@ break

@@ -24,4 +24,2 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

import base64
import io
import os

@@ -39,3 +37,2 @@ import zipfile

from google.rpc.code_pb2 import Code
from google.rpc.error_details_pb2 import ErrorInfo

@@ -63,4 +60,3 @@ from ansys.additive.core.download import download_file

from ansys.additive.core.server_connection import ServerConnection
from ansys.additive.core.simulation import SimulationStatus
from ansys.additive.core.simulation_error import SimulationError
from ansys.additive.core.simulation import SimulationError
from ansys.additive.core.single_bead import SingleBeadInput, SingleBeadSummary

@@ -71,2 +67,3 @@ from ansys.additive.core.thermal_history import (

)
from ansys.api.additive.v0.additive_materials_pb2 import TuneMaterialResponse
from ansys.api.additive.v0.additive_operations_pb2 import OperationMetadata

@@ -249,6 +246,14 @@ from ansys.api.additive.v0.additive_simulation_pb2 import SimulationResponse

if progress.state == ProgressState.ERROR:
self._summary = SimulationError(self._simulation_input, progress.message)
return progress
if operation.HasField("response"):
response = SimulationResponse()
response = (
SimulationResponse()
if not isinstance(self._simulation_input, MaterialTuningInput)
else TuneMaterialResponse()
)
operation.response.Unpack(response)
self._summary = self._create_summary(response, progress)
self._summary = self._create_summary_from_response(response)
elif operation.HasField("error") and operation.error.code not in [

@@ -258,16 +263,4 @@ Code.CANCELLED,

]:
logs = ""
if operation.error.details:
info = ErrorInfo()
operation.error.details[0].Unpack(info)
if info.metadata["mimetype"] != "application/zip":
logs = base64.b64decode(info.metadata["logs"]).decode("utf-8")
else:
logs = self._extract_logs(base64.b64decode(info.metadata["logs"]))
self._summary = SimulationError(self._simulation_input, operation.error.message)
self._summary = SimulationError(self._simulation_input, operation.error.message, logs)
# ensure returned progress has an error state
progress.state = ProgressState.ERROR
return progress

@@ -306,4 +299,4 @@

def _create_summary(
self, response: SimulationResponse, progress: Progress
def _create_summary_from_response(
self, response: SimulationResponse | TuneMaterialResponse
) -> (

@@ -317,17 +310,6 @@ SingleBeadSummary

):
progress_state_to_simulation_status = {
ProgressState.ERROR: SimulationStatus.ERROR,
ProgressState.WARNING: SimulationStatus.WARNING,
ProgressState.COMPLETED: SimulationStatus.COMPLETED,
}
simulation_status = progress_state_to_simulation_status[progress.state]
if response.HasField("material_tuning_result"):
if isinstance(response, TuneMaterialResponse):
return MaterialTuningSummary(
self._simulation_input,
response.material_tuning_result,
self._user_data_path,
self._simulation_input, response.result, self._user_data_path
)
logs = ""
if response.logs:
logs = self._extract_logs(response.logs)
if response.HasField("melt_pool"):

@@ -345,15 +327,6 @@ thermal_history_output = None

return SingleBeadSummary(
self._simulation_input,
response.melt_pool,
logs,
thermal_history_output,
simulation_status,
self._simulation_input, response.melt_pool, thermal_history_output
)
if response.HasField("porosity_result"):
return PorositySummary(
self._simulation_input,
response.porosity_result,
logs,
simulation_status,
)
return PorositySummary(self._simulation_input, response.porosity_result)
if response.HasField("microstructure_result"):

@@ -363,5 +336,3 @@ return MicrostructureSummary(

response.microstructure_result,
logs,
self._user_data_path,
simulation_status,
)

@@ -372,5 +343,3 @@ if response.HasField("microstructure_3d_result"):

response.microstructure_3d_result,
logs,
self._user_data_path,
simulation_status,
)

@@ -387,3 +356,3 @@ if response.HasField("thermal_history_result"):

os.remove(local_zip)
return ThermalHistorySummary(self._simulation_input, path, logs, simulation_status)
return ThermalHistorySummary(self._simulation_input, path)

@@ -393,41 +362,1 @@ def _check_if_thermal_history_is_present(self, response) -> bool:

return response.melt_pool.thermal_history_vtk_zip != str()
def _extract_logs(self, log_bytes: bytes) -> str:
"""
Extract log files from an array of bytes.
Parameters
----------
log_bytes : bytes
An array of bytes containing the one or more log files.
The bytes are assumed to be zip encoded.
Returns
-------
str
A string containing the concatenated log file contents.
The name of each log file will precede its contents.
"""
if not log_bytes:
return ""
# Create a BytesIO object from log_bytes
byte_stream_io = io.BytesIO(log_bytes)
# Open the ZIP file from the byte stream
with zipfile.ZipFile(byte_stream_io, "r") as zip_ref:
# Initialize an empty string to store the concatenated content
concatenated_content = ""
# Iterate through the files in the ZIP archive
for file_name in zip_ref.namelist():
# Read the content of the file
with zip_ref.open(file_name) as file:
file_content = file.read().decode("utf-8")
# Concatenate the file name and its content
concatenated_content += f"File: {file_name}\n{file_content}\n"
return concatenated_content

@@ -25,4 +25,8 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

from enum import Enum
from typing import Union
from ansys.additive.core.misc import short_uuid
from ansys.additive.core.microstructure import MicrostructureInput
from ansys.additive.core.porosity import PorosityInput
from ansys.additive.core.single_bead import SingleBeadInput
from ansys.additive.core.thermal_history import ThermalHistoryInput

@@ -66,31 +70,24 @@

class SimulationInputBase:
"""Provides a base class for simulation inputs."""
class SimulationError:
"""Provides simulation errors."""
def __init__(self) -> None:
"""Initialize the simulation input base class."""
self._id: str = short_uuid()
def __init__(
self,
input: Union[SingleBeadInput, PorosityInput, MicrostructureInput, ThermalHistoryInput],
message: str,
):
"""Initialize a ``SimulationError`` object."""
self._input = input
self._message = message
@property
def id(self) -> str:
"""Return a unique identifier for this simulation."""
return self._id
def input(
self,
) -> Union[SingleBeadInput, PorosityInput, MicrostructureInput, ThermalHistoryInput]:
"""Simulation input."""
return self._input
class SimulationSummaryBase:
"""Provides a base class for simulation summaries."""
def __init__(self, logs: str, status: SimulationStatus = SimulationStatus.COMPLETED):
"""Initialize a ``SimulationSummaryBase`` object."""
self._logs = logs
self._status = status
@property
def logs(self) -> str:
"""Simulation logs."""
return self._logs
@property
def status(self) -> SimulationStatus:
"""Simulation status."""
return self._status
def message(self) -> str:
"""Provides simulation error message."""
return self._message

@@ -34,7 +34,3 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

from ansys.additive.core.material import AdditiveMaterial
from ansys.additive.core.simulation import (
SimulationInputBase,
SimulationStatus,
SimulationSummaryBase,
)
from ansys.additive.core.simulation_input_base import SimulationInputBase
from ansys.api.additive.v0.additive_domain_pb2 import MeltPool as MeltPoolMessage

@@ -286,3 +282,5 @@ from ansys.api.additive.v0.additive_domain_pb2 import (

repr += self._df.to_string()
repr += "\ngrid_full_thermal_sensor_file_output_path: " + str(self.thermal_history_output)
repr += (
"\n" + "grid_full_thermal_sensor_file_output_path: " + str(self.thermal_history_output)
)
return repr

@@ -296,3 +294,3 @@

class SingleBeadSummary(SimulationSummaryBase):
class SingleBeadSummary:
"""Provides a summary of a single bead simulation."""

@@ -306,5 +304,3 @@

msg: MeltPoolMessage,
logs: str,
thermal_history_output: str | None = None,
status: SimulationStatus = SimulationStatus.COMPLETED,
):

@@ -316,5 +312,2 @@ """Initialize a ``SingleBeadSummary`` object."""

raise ValueError("Invalid message type passed to init, " + self.__class__.__name__)
if not isinstance(logs, str):
raise ValueError("Invalid logs type passed to init, " + self.__class__.__name__)
super().__init__(logs, status)
self._input = input

@@ -321,0 +314,0 @@ self._melt_pool = MeltPool(msg, thermal_history_output)

@@ -27,7 +27,3 @@ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.

from ansys.additive.core.material import AdditiveMaterial
from ansys.additive.core.simulation import (
SimulationInputBase,
SimulationStatus,
SimulationSummaryBase,
)
from ansys.additive.core.simulation_input_base import SimulationInputBase
from ansys.api.additive.v0.additive_domain_pb2 import BuildFile as BuildFileMessage

@@ -248,18 +244,9 @@ from ansys.api.additive.v0.additive_domain_pb2 import (

class ThermalHistorySummary(SimulationSummaryBase):
class ThermalHistorySummary:
"""Summary of a thermal history simulation."""
def __init__(
self,
input: ThermalHistoryInput,
coax_ave_output_folder: str,
logs: str,
status: SimulationStatus = SimulationStatus.COMPLETED,
):
def __init__(self, input: ThermalHistoryInput, coax_ave_output_folder: str):
"""Initialize a ``ThermalHistorySummary`` object."""
if not isinstance(input, ThermalHistoryInput):
raise ValueError("Invalid input type passed to init, " + self.__class__.__name__)
if not isinstance(logs, str):
raise ValueError("Invalid logs type passed to init, " + self.__class__.__name__)
super().__init__(logs, status)
self._input = input

@@ -266,0 +253,0 @@ self._coax_ave_output_folder = coax_ave_output_folder

# Copyright (C) 2023 - 2025 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""Provides simulation error information."""
from ansys.additive.core.material_tuning import MaterialTuningInput
from ansys.additive.core.microstructure import MicrostructureInput
from ansys.additive.core.microstructure_3d import Microstructure3DInput
from ansys.additive.core.porosity import PorosityInput
from ansys.additive.core.single_bead import SingleBeadInput
from ansys.additive.core.thermal_history import ThermalHistoryInput
class SimulationError:
"""Provides simulation error information."""
def __init__(
self,
input: (
SingleBeadInput
| PorosityInput
| MicrostructureInput
| Microstructure3DInput
| ThermalHistoryInput
| MaterialTuningInput
),
message: str,
logs: str,
):
"""Initialize a ``SimulationError`` object."""
self._input = input
self._message = message
self._logs = logs
@property
def input(
self,
) -> (
SingleBeadInput
| PorosityInput
| MicrostructureInput
| Microstructure3DInput
| ThermalHistoryInput
| MaterialTuningInput
):
"""Simulation input."""
return self._input
@property
def message(self) -> str:
"""Provides simulation error message."""
return self._message
@property
def logs(self) -> str:
"""Provides simulation logs."""
return self._logs

Sorry, the diff of this file is too big to display