From fedb74ebac1fe55256f0dcf4a9a9dd175ed3138a Mon Sep 17 00:00:00 2001 From: Ismir Tufek Date: Wed, 21 May 2025 14:14:31 -0400 Subject: [PATCH 1/7] Add files via upload Initial upload --- .../stk/extensions/data_provider_extension.py | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 extensions/src/ansys/stk/extensions/data_provider_extension.py diff --git a/extensions/src/ansys/stk/extensions/data_provider_extension.py b/extensions/src/ansys/stk/extensions/data_provider_extension.py new file mode 100644 index 0000000000..39cead19cc --- /dev/null +++ b/extensions/src/ansys/stk/extensions/data_provider_extension.py @@ -0,0 +1,104 @@ +from asyncio.windows_events import NULL +import ansys.stk.core.stkobjects +import ansys.stk.core.vgt +from ansys.stk.core.stkobjects import IStkObject, DATA_PROVIDER_TYPE, Access +import pandas as pd + + +class data_provider_extension(object): + def __init__(self, base_object:IStkObject) -> None: + self.BaseObject = base_object + pass + + def _get_fixed_data(self, provider_name, elements = None, pre_data = None): + fixed_data_provider = self.BaseObject.data_providers.item(provider_name) + if pre_data != None: + fixed_data_provider.pre_data = pre_data + if elements == None: + fixed_result = fixed_data_provider.execute() + else: + fixed_result = fixed_data_provider.execute_elements(elements) + fixed_result_data = fixed_result.data_sets.to_pandas_dataframe() + return fixed_result_data + + def _get_interval_data(self,provider_name,start_time,stop_time, elements = None, pre_data = None): + interval_data_provider = self.BaseObject.data_providers.item(provider_name) + if pre_data != None: + interval_data_provider.pre_data = pre_data + if elements == None: + interval_result = interval_data_provider.execute(start_time, stop_time) + else: + interval_result = interval_data_provider.execute_elements(start_time, stop_time, elements) + interval_result_data = interval_result.data_sets.to_pandas_dataframe() + return interval_result_data + + def _get_time_data(self,provider_name,start_time,stop_time,time_step, elements = None, pre_data = None): + time_data_provider = self.BaseObject.data_providers.get_data_provider_time_varying_from_path(provider_name) + if pre_data != None: + time_data_provider.pre_data = pre_data + if elements == None: + time_result = time_data_provider.execute(start_time, stop_time, time_step) + else: + time_result = time_data_provider.execute_elements(start_time, stop_time, time_step, elements) + if (time_result.sections.count > 0): + #Process sections + for x in range(0, time_result.sections.count): + for y in range(0, time_result.sections[x].intervals.count): + row_data = time_result.sections[x].intervals[y].data_sets.to_pandas_dataframe(); + row_data.insert(0,'Section','') + row_data['Section'] = time_result.sections[x].title + #print(row_data) + if x==0 and y==0: + panda = row_data + else: + panda = pd.concat([panda,row_data], ignore_index=True) + time_result_data = panda + else: + if (time_result.intervals.count > 0): + for i in range(0,time_result.intervals.count): + row = time_result.intervals[i].data_sets.to_pandas_dataframe() + if i > 0: + panda = pd.concat([panda,row], ignore_index=True) + else: + panda = row + time_result_data = panda + else: + time_result_data = time_result.data_sets.to_pandas_dataframe() + return time_result_data + + def get_pandas(self,provider_path,start_time = None,stop_time = None,time_step = None, elements = None, pre_data = None): + if isinstance(self.BaseObject,Access): + root = self.BaseObject.target.root + else: + root = self.BaseObject.root + scenario = root.current_scenario +# To do: check if exists + provider_info = self.BaseObject.data_providers.get_data_provider_information_from_path(provider_path) + panda = None + match provider_info.type: + case DATA_PROVIDER_TYPE.FIXED: + panda = self._get_fixed_data(self, provider_path, elements, pre_data) + pass + case DATA_PROVIDER_TYPE.INTERVAL: + if start_time == None: + start_time = scenario.start_time + if stop_time == None: + stop_time = scenario.stop_time + panda = self._get_interval_data(self, provider_path, start_time, stop_time, elements, pre_data) + pass + case DATA_PROVIDER_TYPE.TIME_VARYING: + if start_time == None: + start_time = scenario.start_time + if stop_time == None: + stop_time = scenario.stop_time + if time_step == None: + time_step = 60.0 + #panda = self._get_time_data(self, provider_path, start_time, stop_time, time_step, elements, pre_data) + panda = self._get_time_data(provider_path, start_time, stop_time, time_step, elements, pre_data) + pass + + return panda + + def get_value_at_time(time): + pass + From 6712016710c6df73dd617c18ad692675acf8529d Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Wed, 21 May 2025 19:17:12 +0000 Subject: [PATCH 2/7] chore: adding changelog file 715.added.md [dependabot-skip] --- doc/source/changelog/715.added.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/source/changelog/715.added.md diff --git a/doc/source/changelog/715.added.md b/doc/source/changelog/715.added.md new file mode 100644 index 0000000000..1d5f4f2bfc --- /dev/null +++ b/doc/source/changelog/715.added.md @@ -0,0 +1 @@ +new data provider extension \ No newline at end of file From d19846453b688ff1642a370ddb7c49a7c978224e Mon Sep 17 00:00:00 2001 From: Justin Winkler <70604068+jwinkle8@users.noreply.github.com> Date: Wed, 21 May 2025 15:40:26 -0400 Subject: [PATCH 3/7] fix: run and apply code-style formatting --- .../stk/extensions/data_provider_extension.py | 131 +++++++++++------- 1 file changed, 80 insertions(+), 51 deletions(-) diff --git a/extensions/src/ansys/stk/extensions/data_provider_extension.py b/extensions/src/ansys/stk/extensions/data_provider_extension.py index 39cead19cc..dbba784ac7 100644 --- a/extensions/src/ansys/stk/extensions/data_provider_extension.py +++ b/extensions/src/ansys/stk/extensions/data_provider_extension.py @@ -1,104 +1,133 @@ -from asyncio.windows_events import NULL -import ansys.stk.core.stkobjects -import ansys.stk.core.vgt -from ansys.stk.core.stkobjects import IStkObject, DATA_PROVIDER_TYPE, Access +# Copyright (C) 2022 - 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. + +""" +PySTK Data Provider Extensions. + +A set of convenience utilities to facilitate the access and manipulation of STK data providers. +""" + import pandas as pd +from ansys.stk.core.stkobjects import DATA_PROVIDER_TYPE, Access, IStkObject -class data_provider_extension(object): - def __init__(self, base_object:IStkObject) -> None: - self.BaseObject = base_object + +class DataProviderExtension(object): + """Encapsulate the data and implementation necessary to simplify the process of accessing and manipulating data provider information.""" + + def __init__(self, base_object: IStkObject) -> None: + self.base_object = base_object pass - - def _get_fixed_data(self, provider_name, elements = None, pre_data = None): - fixed_data_provider = self.BaseObject.data_providers.item(provider_name) - if pre_data != None: + + def _get_fixed_data(self, provider_name, elements=None, pre_data=None): + fixed_data_provider = self.base_object.data_providers.item(provider_name) + if pre_data is not None: fixed_data_provider.pre_data = pre_data - if elements == None: + if elements is None: fixed_result = fixed_data_provider.execute() else: fixed_result = fixed_data_provider.execute_elements(elements) fixed_result_data = fixed_result.data_sets.to_pandas_dataframe() return fixed_result_data - - def _get_interval_data(self,provider_name,start_time,stop_time, elements = None, pre_data = None): - interval_data_provider = self.BaseObject.data_providers.item(provider_name) - if pre_data != None: + + def _get_interval_data(self, provider_name, start_time, stop_time, elements=None, pre_data=None): + interval_data_provider = self.base_object.data_providers.item(provider_name) + if pre_data is not None: interval_data_provider.pre_data = pre_data - if elements == None: + if elements is None: interval_result = interval_data_provider.execute(start_time, stop_time) else: interval_result = interval_data_provider.execute_elements(start_time, stop_time, elements) interval_result_data = interval_result.data_sets.to_pandas_dataframe() return interval_result_data - - def _get_time_data(self,provider_name,start_time,stop_time,time_step, elements = None, pre_data = None): - time_data_provider = self.BaseObject.data_providers.get_data_provider_time_varying_from_path(provider_name) - if pre_data != None: + + def _get_time_data(self, provider_name, start_time, stop_time, time_step, elements=None, pre_data=None): + time_data_provider = self.base_object.data_providers.get_data_provider_time_varying_from_path(provider_name) + if pre_data is not None: time_data_provider.pre_data = pre_data - if elements == None: + if elements is None: time_result = time_data_provider.execute(start_time, stop_time, time_step) else: time_result = time_data_provider.execute_elements(start_time, stop_time, time_step, elements) - if (time_result.sections.count > 0): - #Process sections + if time_result.sections.count > 0: + # Process sections for x in range(0, time_result.sections.count): for y in range(0, time_result.sections[x].intervals.count): - row_data = time_result.sections[x].intervals[y].data_sets.to_pandas_dataframe(); - row_data.insert(0,'Section','') - row_data['Section'] = time_result.sections[x].title - #print(row_data) - if x==0 and y==0: + row_data = time_result.sections[x].intervals[y].data_sets.to_pandas_dataframe() + row_data.insert(0, "Section", "") + row_data["Section"] = time_result.sections[x].title + # print(row_data) + if x == 0 and y == 0: panda = row_data else: - panda = pd.concat([panda,row_data], ignore_index=True) + panda = pd.concat([panda, row_data], ignore_index=True) time_result_data = panda else: - if (time_result.intervals.count > 0): - for i in range(0,time_result.intervals.count): + if time_result.intervals.count > 0: + for i in range(0, time_result.intervals.count): row = time_result.intervals[i].data_sets.to_pandas_dataframe() if i > 0: - panda = pd.concat([panda,row], ignore_index=True) + panda = pd.concat([panda, row], ignore_index=True) else: panda = row time_result_data = panda else: time_result_data = time_result.data_sets.to_pandas_dataframe() return time_result_data - - def get_pandas(self,provider_path,start_time = None,stop_time = None,time_step = None, elements = None, pre_data = None): - if isinstance(self.BaseObject,Access): - root = self.BaseObject.target.root + + def get_pandas(self, provider_path, start_time=None, stop_time=None, time_step=None, elements=None, pre_data=None): + """Return an object's data provider in the form of a Pandas DataFrame.""" + if isinstance(self.base_object, Access): + root = self.base_object.target.root else: - root = self.BaseObject.root + root = self.base_object.root scenario = root.current_scenario -# To do: check if exists - provider_info = self.BaseObject.data_providers.get_data_provider_information_from_path(provider_path) + # To do: check if exists + provider_info = self.base_object.data_providers.get_data_provider_information_from_path(provider_path) panda = None match provider_info.type: case DATA_PROVIDER_TYPE.FIXED: panda = self._get_fixed_data(self, provider_path, elements, pre_data) pass case DATA_PROVIDER_TYPE.INTERVAL: - if start_time == None: + if start_time is None: start_time = scenario.start_time - if stop_time == None: + if stop_time is None: stop_time = scenario.stop_time panda = self._get_interval_data(self, provider_path, start_time, stop_time, elements, pre_data) pass case DATA_PROVIDER_TYPE.TIME_VARYING: - if start_time == None: + if start_time is None: start_time = scenario.start_time - if stop_time == None: + if stop_time is None: stop_time = scenario.stop_time - if time_step == None: + if time_step is None: time_step = 60.0 - #panda = self._get_time_data(self, provider_path, start_time, stop_time, time_step, elements, pre_data) + # panda = self._get_time_data(self, provider_path, start_time, stop_time, time_step, elements, pre_data) panda = self._get_time_data(provider_path, start_time, stop_time, time_step, elements, pre_data) - pass - + pass + return panda - - def get_value_at_time(time): + + def get_value_at_time(self, time): + """Return the value retrieved by indexing an object's data provider with a given time.""" pass - From 0fca5f3a36f435aecdc9b4395bf4dd4a332428fd Mon Sep 17 00:00:00 2001 From: Justin Winkler <70604068+jwinkle8@users.noreply.github.com> Date: Wed, 4 Jun 2025 17:07:59 -0400 Subject: [PATCH 4/7] fix: fix casing of enumeration --- .../src/ansys/stk/extensions/data_provider_extension.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/src/ansys/stk/extensions/data_provider_extension.py b/extensions/src/ansys/stk/extensions/data_provider_extension.py index dbba784ac7..4394268bd5 100644 --- a/extensions/src/ansys/stk/extensions/data_provider_extension.py +++ b/extensions/src/ansys/stk/extensions/data_provider_extension.py @@ -28,7 +28,7 @@ import pandas as pd -from ansys.stk.core.stkobjects import DATA_PROVIDER_TYPE, Access, IStkObject +from ansys.stk.core.stkobjects import Access, DataProviderType, IStkObject class DataProviderExtension(object): @@ -105,17 +105,17 @@ def get_pandas(self, provider_path, start_time=None, stop_time=None, time_step=N provider_info = self.base_object.data_providers.get_data_provider_information_from_path(provider_path) panda = None match provider_info.type: - case DATA_PROVIDER_TYPE.FIXED: + case DataProviderType.FIXED: panda = self._get_fixed_data(self, provider_path, elements, pre_data) pass - case DATA_PROVIDER_TYPE.INTERVAL: + case DataProviderType.INTERVAL: if start_time is None: start_time = scenario.start_time if stop_time is None: stop_time = scenario.stop_time panda = self._get_interval_data(self, provider_path, start_time, stop_time, elements, pre_data) pass - case DATA_PROVIDER_TYPE.TIME_VARYING: + case DataProviderType.TIME_VARYING: if start_time is None: start_time = scenario.start_time if stop_time is None: From 395751203bebb698c81a70c6e35587936439367a Mon Sep 17 00:00:00 2001 From: Justin Winkler <70604068+jwinkle8@users.noreply.github.com> Date: Thu, 5 Jun 2025 10:38:52 -0400 Subject: [PATCH 5/7] fix: more casing fixes --- .../src/ansys/stk/extensions/data_provider_extension.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/src/ansys/stk/extensions/data_provider_extension.py b/extensions/src/ansys/stk/extensions/data_provider_extension.py index 4394268bd5..abd70534ea 100644 --- a/extensions/src/ansys/stk/extensions/data_provider_extension.py +++ b/extensions/src/ansys/stk/extensions/data_provider_extension.py @@ -28,13 +28,13 @@ import pandas as pd -from ansys.stk.core.stkobjects import Access, DataProviderType, IStkObject +from ansys.stk.core.stkobjects import Access, DataProviderType, ISTKObject class DataProviderExtension(object): """Encapsulate the data and implementation necessary to simplify the process of accessing and manipulating data provider information.""" - def __init__(self, base_object: IStkObject) -> None: + def __init__(self, base_object: ISTKObject) -> None: self.base_object = base_object pass From 5cfcbd145355b8458de3a0a9a0f15c520f661d55 Mon Sep 17 00:00:00 2001 From: Justin Winkler <70604068+jwinkle8@users.noreply.github.com> Date: Thu, 5 Jun 2025 10:40:05 -0400 Subject: [PATCH 6/7] test: add pytest snippet for data provider extension --- .../test_data_provider_extension.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/extensions/test_data_provider_extension.py diff --git a/tests/extensions/test_data_provider_extension.py b/tests/extensions/test_data_provider_extension.py new file mode 100644 index 0000000000..dbbc42d9ef --- /dev/null +++ b/tests/extensions/test_data_provider_extension.py @@ -0,0 +1,36 @@ +# Copyright (C) 2022 - 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. + +"""Test the data provider access and manipulation extension.""" + +import pytest + +from ansys.stk.extensions.data_provider_extension import DataProviderExtension +from ansys.stk.core.stkobjects import Access, STKObjectType, DataProviderFixed, DataProviderGroup +from ansys.stk.core.stkutil import CoordinateSystem + +from stk_environment import stk_root + + +def test_fixed_data_provider(stk_root): + # STKObjectRoot stk_root: STK Object Model root + pass \ No newline at end of file From 5acdf3e401ccac40f7c8d64968ee35c57bde9c3b Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Thu, 5 Jun 2025 14:42:15 +0000 Subject: [PATCH 7/7] chore: adding changelog file 715.added.md [dependabot-skip] --- doc/source/changelog/715.added.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/changelog/715.added.md b/doc/source/changelog/715.added.md index 1d5f4f2bfc..097ff1e898 100644 --- a/doc/source/changelog/715.added.md +++ b/doc/source/changelog/715.added.md @@ -1 +1 @@ -new data provider extension \ No newline at end of file +New data provider extension \ No newline at end of file