Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEAT: Fields markers #4981

Merged
merged 25 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4ccd672
Add mesh reuse function
lorenzovecchietti Jun 20, 2024
f67c1c7
Add mesh file
lorenzovecchietti Jun 24, 2024
16b2e93
rename default name
lorenzovecchietti Jun 24, 2024
fc05180
add mesh test
lorenzovecchietti Jun 24, 2024
8da91f4
Merge branch 'main' into mesh_reuse
lorenzovecchietti Jun 24, 2024
169c7d8
improve coverage
lorenzovecchietti Jun 24, 2024
5b430a2
Add get point data from field method
lorenzovecchietti Jul 31, 2024
c4dbba9
Merge branch 'refs/heads/main' into fieldplot_markers
lorenzovecchietti Jul 31, 2024
97ccfb2
Merge branch 'main' into fieldplot_markers
lorenzovecchietti Jul 31, 2024
f22c974
Fix ut and add note for non graphical mode
lorenzovecchietti Aug 1, 2024
694eca0
Merge branch 'main' into fieldplot_markers
lorenzovecchietti Aug 1, 2024
d9ab560
Fix for ironpython
lorenzovecchietti Aug 2, 2024
50f4ad6
Merge remote-tracking branch 'origin/fieldplot_markers' into fieldplo…
lorenzovecchietti Aug 2, 2024
d2a8b22
Merge branch 'main' into fieldplot_markers
lorenzovecchietti Aug 2, 2024
2fc8318
Fix for ironpython
lorenzovecchietti Aug 2, 2024
b36087e
Merge remote-tracking branch 'origin/fieldplot_markers' into fieldplo…
lorenzovecchietti Aug 2, 2024
0108628
Merge branch 'main' into fieldplot_markers
lorenzovecchietti Aug 8, 2024
230c44f
add option to leave the markers visible
lorenzovecchietti Aug 9, 2024
e810c08
Merge remote-tracking branch 'origin/fieldplot_markers' into fieldplo…
lorenzovecchietti Aug 9, 2024
82c1ab4
Update pyaedt/modules/solutions.py
Samuelopez-ansys Aug 12, 2024
2054cb8
Merge branch 'main' into fieldplot_markers
Samuelopez-ansys Aug 12, 2024
2338dc0
Update pyaedt/modules/solutions.py
lorenzovecchietti Aug 12, 2024
be06e29
Remove useless context manager usage
lorenzovecchietti Aug 12, 2024
56642b0
Merge remote-tracking branch 'origin/fieldplot_markers' into fieldplo…
lorenzovecchietti Aug 12, 2024
9768e07
Fix docstring
lorenzovecchietti Aug 12, 2024
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
Binary file added _unittest/example_models/T12/ipk_markers.aedtz
Binary file not shown.
47 changes: 46 additions & 1 deletion _unittest/test_12_PostProcessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@

import os
import sys
import tempfile

from _unittest.conftest import config
import pandas as pd
import pytest

from pyaedt import Circuit
Expand All @@ -45,6 +47,7 @@
sbr_file = "poc_scat_small_231"
q3d_file = "via_gsg_231"
m2d_file = "m2d_field_lines_test_231"
ipk_markers_proj = "ipk_markers"

else:
test_field_name = "Potter_Horn"
Expand Down Expand Up @@ -756,7 +759,7 @@ def test_z99_delete_variations_B(self, field_test):
assert field_test.cleanup_solution(vars, entire_solution=False)
assert field_test.cleanup_solution(vars, entire_solution=True)

def test_76_ipk_get_scalar_field_value(self, icepak_post):
def test_100_ipk_get_scalar_field_value(self, icepak_post):
assert icepak_post.post.get_scalar_field_value(
"Heat_Flow_Rate",
scalar_function="Integrate",
Expand Down Expand Up @@ -829,3 +832,45 @@ def test_76_ipk_get_scalar_field_value(self, icepak_post):
object_type="point",
adjacent_side=False,
)

@pytest.mark.skipif(config["NonGraphical"], reason="Method does not work in non-graphical mode.")
def test_101_markers(self, add_app):
ipk = add_app(project_name=ipk_markers_proj, application=Icepak, subfolder=test_subfolder)

f1 = ipk.modeler["Region"].top_face_z
p1 = ipk.post.create_fieldplot_surface(f1.id, "Uz")
f1_c = f1.center
f1_p1 = [f1_c[0] + 0.01, f1_c[1] + 0.01, f1_c[2]]
f1_p2 = [f1_c[0] - 0.01, f1_c[1] - 0.01, f1_c[2]]
d1 = p1.get_points_value([f1_c, f1_p1, f1_p2])
assert isinstance(d1, pd.DataFrame)
assert d1.index.name == "Name"
assert all(d1.index.values == ["m1", "m2", "m3"])
assert len(d1["X [mm]"].values) == 3
assert len(d1.columns) == 4

f2 = ipk.modeler["Box1"].top_face_z
p2 = ipk.post.create_fieldplot_surface(f2.id, "Pressure")
d2 = p2.get_points_value({"Center Point": f2.center})
assert isinstance(d2, pd.DataFrame)
assert d2.index.name == "Name"
assert all(d2.index.values == ["Center Point"])
assert len(d2.columns) == 4
assert len(d2["X [mm]"].values) == 1

f3 = ipk.modeler["Box1"].bottom_face_y
p3 = ipk.post.create_fieldplot_surface(f3.id, "Temperature")
d3 = p3.get_points_value(f3.center)
assert isinstance(d3, pd.DataFrame)
assert d3.index.name == "Name"
assert all(d3.index.values == ["m1"])
assert len(d3.columns) == 4
assert len(d3["X [mm]"].values) == 1

f4 = ipk.modeler["Box1"].top_face_x
p4 = ipk.post.create_fieldplot_surface(f4.id, "HeatFlowRate")
temp_file = tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".csv")
temp_file.close()
d4 = p4.get_points_value(f4.center, filename=temp_file.name)
assert isinstance(d4, pd.DataFrame)
os.path.exists(temp_file.name)
8 changes: 4 additions & 4 deletions pyaedt/modules/AdvancedPostProcessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,7 @@ def evaluate_faces_quantity(
Dictionary of parameters defined for the specific setup with values. The default is ``{}``.
ref_temperature: str, optional
Reference temperature to use for heat transfer coefficient computation. The default is ``""``.
time : str
time : str, optional
Timestep to get the data from. Default is ``"0s"``.

Returns
Expand Down Expand Up @@ -1168,7 +1168,7 @@ def evaluate_boundary_quantity(
Dictionary of parameters defined for the specific setup with values. The default is ``{}``.
ref_temperature: str, optional
Reference temperature to use for heat transfer coefficient computation. The default is ``""``.
time : str
time : str, optional
Timestep to get the data from. Default is ``"0s"``.

Returns
Expand Down Expand Up @@ -1220,7 +1220,7 @@ def evaluate_monitor_quantity(
Dictionary of parameters defined for the specific setup with values. The default is ``{}``.
ref_temperature: str, optional
Reference temperature to use for heat transfer coefficient computation. The default is ``""``.
time : str
time : str, optional
Timestep to get the data from. Default is ``"0s"``.

Returns
Expand Down Expand Up @@ -1286,7 +1286,7 @@ def evaluate_object_quantity(
Dictionary of parameters defined for the specific setup with values. The default is ``{}``.
ref_temperature: str, optional
Reference temperature to use for heat transfer coefficient computation. The default is ``""``.
time : str
time : str, optional
Timestep to get the data from. Default is ``"0s"``.

Returns
Expand Down
2 changes: 1 addition & 1 deletion pyaedt/modules/PostProcessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5711,7 +5711,7 @@ def add_calculation(
ref_temperature : str, optional
Reference temperature to use in the calculation of the heat transfer
coefficient. The default is ``"AmbientTemp"``.
time : str
time : str, optional
Timestep to get the data from. Default is ``"0s"``.

Returns
Expand Down
111 changes: 110 additions & 1 deletion pyaedt/modules/solutions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,22 @@
# 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.

from collections import OrderedDict
from collections import defaultdict
import csv
import itertools
import logging
import math
import os
import shutil
import sys
import tempfile

from pyaedt.generic.constants import AEDT_UNITS
from pyaedt.generic.constants import CSS4_COLORS
from pyaedt.generic.constants import db10
from pyaedt.generic.constants import db20
from pyaedt.generic.general_methods import GrpcApiError
from pyaedt.generic.general_methods import check_and_download_file
from pyaedt.generic.general_methods import is_ironpython
from pyaedt.generic.general_methods import open_file
Expand Down Expand Up @@ -1797,6 +1801,111 @@ def plotsettings(self):
]
return arg

@pyaedt_function_handler()
def get_points_value(self, points, filename=None, visibility=False): # pragma: no cover
"""
Get points data from field plot.

.. note::
This method is working only if the associated field plot is currently visible.

.. note::
This method does not work in non-graphical mode.

Parameters
----------
points : list, list of lists or dict
List with [x,y,z] coordinates of a point or list of lists of points or
dictionary with keys containing point names and for each key the point
coordinates [x,y,z].
filename : str, optional
Full path or relative path with filename.
Default is ``None`` in which case no file is exported.
visibility : bool, optional
Whether to keep the markers visible in the UI. Default is ``False``.

Returns
-------
dict or pd.DataFrame
Dict containing 5 keys: point names, x,y,z coordinates and the quantity probed.
Each key is associated with a list with the same length of the argument points.
If pandas is installed, the output is a pandas DataFrame with point names as
index and coordinates and quantity as columns.
"""
self.oField.ClearAllMarkers()

# Clean inputs
if isinstance(points, dict):
points_name, points_value = list(points.keys()), list(points.values())
elif isinstance(points, list):
points_name = None
if not isinstance(points[0], list):
points_value = [points]
else:
points_value = points
else:
raise AttributeError("``points`` argument is invalid.")
if filename is not None:
if not os.path.isdir(os.path.dirname(filename)):
raise AttributeError("Specified path ({}) does not exist".format(filename))

# Create markers
u = self._postprocessor._app.modeler.model_units
added_points_name = []
for pt_name_idx, pt in enumerate(points_value):
try:
pt = [c if isinstance(c, str) else "{}{}".format(c, u) for c in pt]
self.oField.AddMarkerToPlot(pt, self.name)
if points_name is not None:
added_points_name.append(points_name[pt_name_idx])
except (GrpcApiError, SystemExit) as e: # pragma: no cover
self._postprocessor.logger.error(
"Point {} not added. Check if it lies inside the plot.".format(str(pt))
)
raise e

# Export data
temp_file = tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".csv")
temp_file.close()
self.oField.ExportMarkerTable(temp_file.name)
with open_file(temp_file.name, "r") as f:
reader = csv.DictReader(f)
out_dict = defaultdict(list)
for row in reader:
for key in row.keys():
if key == "Name":
val = row[key]
else:
val = float(row[key].lstrip())
out_dict[key.lstrip()].append(val)

# Modify data if needed
if points_name is not None:
out_dict["Name"] = added_points_name
# Export data
if filename is not None:
with open(filename, mode="w") as outfile:
writer = csv.DictWriter(outfile, fieldnames=out_dict.keys())
writer.writeheader()
for i in range(len(out_dict["Name"])):
row = {field: out_dict[field][i] for field in out_dict}
writer.writerow(row)
elif filename is not None:
# Export data
shutil.copy2(temp_file.name, filename)
os.remove(temp_file.name)

if not visibility:
self.oField.ClearAllMarkers()

# Convert to pandas
if pd is not None:
df = pd.DataFrame(out_dict, columns=out_dict.keys())
df = df.set_index("Name")
return df
else:
return out_dict

@property
def surfacePlotInstruction(self):
"""Surface plot settings.
Expand Down
Loading