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: ISAR plot #5639

Merged
merged 30 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3a7d8be
Add examples
Samuelopez-ansys Nov 26, 2024
32f6569
Isar 2D Pyvista plot
Samuelopez-ansys Nov 26, 2024
5311a46
Add test
Samuelopez-ansys Nov 26, 2024
e0560fe
Merge branch 'main' into feat/isar_plot
Samuelopez-ansys Nov 26, 2024
99ef8fb
Fix plot contour
Samuelopez-ansys Nov 26, 2024
bd8eb9e
Add external figure plot_waterfall
Samuelopez-ansys Nov 26, 2024
416a55d
Merge branch 'main' into feat/isar_plot
Samuelopez-ansys Nov 26, 2024
da16bb0
ISAR 2D
Samuelopez-ansys Nov 27, 2024
b04c166
Merge branch 'main' into feat/isar_plot
Samuelopez-ansys Nov 29, 2024
fbfc297
Add relief
Samuelopez-ansys Nov 29, 2024
8b7fe7a
normalize relief z axis
tadanegishi Dec 5, 2024
e485544
Merge branch 'main' into feat/isar_plot
Samuelopez-ansys Dec 7, 2024
38f8d07
Add projection
Samuelopez-ansys Dec 7, 2024
db4eeeb
Merge branch 'main' into feat/isar_plot
Samuelopez-ansys Dec 12, 2024
bf54b7d
Merge branch 'main' into feat/isar_plot
Samuelopez-ansys Dec 12, 2024
e57bc8c
Merge branch 'main' into feat/isar_plot
Samuelopez-ansys Dec 19, 2024
adace1b
Test isar 2D relief
Samuelopez-ansys Dec 19, 2024
2cebfc0
Merge branch 'main' into feat/isar_plot
Samuelopez-ansys Jan 8, 2025
0e58424
Remove comment
Samuelopez-ansys Jan 8, 2025
0a248b2
Add possibility to just load the geometry without data
Samuelopez-ansys Jan 8, 2025
2c65708
Remove comments
Samuelopez-ansys Jan 9, 2025
1baf7af
Update src/ansys/aedt/core/visualization/advanced/rcs_visualization.py
Samuelopez-ansys Jan 9, 2025
8df556b
Update src/ansys/aedt/core/visualization/advanced/rcs_visualization.py
Samuelopez-ansys Jan 9, 2025
681ad93
Merge remote-tracking branch 'origin/feat/isar_plot' into feat/isar_plot
Samuelopez-ansys Jan 9, 2025
21ed619
Update src/ansys/aedt/core/visualization/advanced/rcs_visualization.py
Samuelopez-ansys Jan 9, 2025
5a93cf7
Update src/ansys/aedt/core/visualization/advanced/rcs_visualization.py
Samuelopez-ansys Jan 9, 2025
5bbac0c
Update src/ansys/aedt/core/visualization/advanced/rcs_visualization.py
Samuelopez-ansys Jan 9, 2025
76a6925
Merge branch 'main' into feat/isar_plot
Samuelopez-ansys Jan 9, 2025
3684fca
Remove json files and create them on the fly
Samuelopez-ansys Jan 9, 2025
98d0e33
Merge branch 'main' into feat/isar_plot
Samuelopez-ansys Jan 9, 2025
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
139 changes: 114 additions & 25 deletions src/ansys/aedt/core/visualization/advanced/rcs_visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@

self.__frequency_units = self.__metadata["frequency_units"]

self.__monostatic_file = self.output_dir / self.__metadata["monostatic_file"]
self.__monostatic_file = None
if self.__metadata["monostatic_file"]:
self.__monostatic_file = self.output_dir / self.__metadata["monostatic_file"]

self.__data_conversion_function = "dB20"
self.__window = "Flat"
Expand All @@ -141,19 +143,23 @@
self.__upsample_range = 512
self.__upsample_azimuth = 64

if not self.__monostatic_file.is_file():
if self.__monostatic_file and not self.__monostatic_file.is_file():
raise Exception("Monostatic file invalid.")

self.rcs_column_names = ["data"]

# Load farfield data
is_rcs_loaded = self.__init_rcs()
if self.__monostatic_file:
is_rcs_loaded = self.__init_rcs()
else:
is_rcs_loaded = True

if not is_rcs_loaded: # pragma: no cover
raise RuntimeError("RCS information can not be loaded.")

# Update active frequency if passed in the initialization
self.frequency = self.frequencies[0]
if self.__monostatic_file:
# Update active frequency if passed in the initialization
self.frequency = self.frequencies[0]

@property
def raw_data(self):
Expand Down Expand Up @@ -611,9 +617,6 @@

def __init__(self, rcs_data):

# Public
self.modeler_window = None
Samuelopez-ansys marked this conversation as resolved.
Show resolved Hide resolved

# Private
self.__rcs_data = rcs_data
self.__logger = logger
Expand Down Expand Up @@ -716,7 +719,7 @@
"""
curves = []
all_secondary_sweep_value = secondary_sweep_value
if primary_sweep.lower() == "freq" or primary_sweep.lower() == "frequency":
if primary_sweep.casefold() == "freq" or primary_sweep.casefold() == "frequency":
x_key = "Freq"
x = self.rcs_data.frequencies
if secondary_sweep == "IWaveTheta":
Expand All @@ -732,7 +735,7 @@
y_key = "IWavePhi"
else:
data = self.rcs_data.rcs_active_frequency
if primary_sweep.lower() == "iwavephi":
if primary_sweep.casefold() == "iwavephi":
x_key = "IWavePhi"
y_key = "IWaveTheta"
x = self.rcs_data.available_incident_wave_phi
Expand Down Expand Up @@ -902,7 +905,9 @@
return new

@pyaedt_function_handler()
def plot_waterfall(self, title="Waterfall", output_file=None, show=True, is_polar=False, size=(1920, 1440)):
def plot_waterfall(
self, title="Waterfall", output_file=None, show=True, is_polar=False, size=(1920, 1440), figure=None
):
"""Create a 2D contour plot of the waterfall.

Parameters
Expand All @@ -918,6 +923,10 @@
Whether to display in polar coordinates. The default is ``True``.
size : tuple, optional
Image size in pixel (width, height).
figure : :class:`matplotlib.pyplot.Figure`, optional
An existing Matplotlib `Figure` to which the plot is added.
If not provided, a new `Figure` and `Axes` objects are created.
Default is ``None``.

Returns
-------
Expand Down Expand Up @@ -961,16 +970,11 @@
}

new.add_trace(plot_data, 2, props)
_ = new.plot_contour(
trace=0,
polar=is_polar,
snapshot_path=output_file,
show=show,
)
_ = new.plot_contour(trace=0, polar=is_polar, snapshot_path=output_file, show=show, figure=figure)
return new

@pyaedt_function_handler()
def plot_isar_2d(self, title="ISAR", output_file=None, show=True, size=(1920, 1440)):
def plot_isar_2d(self, title="ISAR", output_file=None, show=True, size=(1920, 1440), figure=None):
"""Create a 2D contour plot of the ISAR.

Parameters
Expand All @@ -984,6 +988,10 @@
If ``False``, the Matplotlib instance of the plot is shown.
size : tuple, optional
Image size in pixel (width, height).
figure : :class:`matplotlib.pyplot.Figure`, optional
An existing Matplotlib `Figure` to which the plot is added.
If not provided, a new `Figure` and `Axes` objects are created.
Default is ``None``.

Returns
-------
Expand Down Expand Up @@ -1019,12 +1027,7 @@
}

new.add_trace(plot_data, 2, props)
_ = new.plot_contour(
trace=0,
polar=False,
snapshot_path=output_file,
show=show,
)
_ = new.plot_contour(trace=0, polar=False, snapshot_path=output_file, show=show, figure=figure)
return new

@pyaedt_function_handler()
Expand Down Expand Up @@ -1617,6 +1620,92 @@

self.all_scene_actors["results"]["waterfall"][waterfall_name] = rcs_mesh

@pyaedt_function_handler()
def add_isar_2d(
self,
plot_type="plane",
color_bar="jet",
):
"""Add the ISAR 2D.

Parameters
----------
plot_type : str, optional
The type of plot to create for the range profile. It can be ``"plane"``, ``"relief"``, and `"projection"``.
The default is ``"plane"``.
color_bar : str, optional
Color mapping to be applied to the RCS data. It can be a color (``"blue"``,
``"green"``, ...) or a colormap (``"jet"``, ``"viridis"``, ...). The default is ``"jet"``.
"""
data_isar_2d = self.rcs_data.isar_2d

down_range = data_isar_2d["Down-range"].unique()
cross_range = data_isar_2d["Cross-range"].unique()

values_2d = data_isar_2d.pivot(index="Cross-range", columns="Down-range", values="Data").to_numpy()

x, y = np.meshgrid(down_range, cross_range)
z = np.zeros_like(x)

if plot_type.casefold() == "relief":
m = 2.0
b = -1.0
Samuelopez-ansys marked this conversation as resolved.
Show resolved Hide resolved
z = (values_2d - values_2d.min()) / (values_2d.max() - values_2d.min()) * m + b

if plot_type.casefold() in ["relief", "plane"]:
actor = pv.StructuredGrid()
actor.points = np.c_[x.ravel(), y.ravel(), z.ravel()]

actor.dimensions = (len(down_range), len(cross_range), 1)

actor["values"] = values_2d.ravel()

else:
scene_actors = self.all_scene_actors["model"]
if scene_actors is None:
return None
actor = pv.PolyData()
for model_actor in scene_actors.values():
mesh = model_actor.custom_object.get_mesh()
xypoints = mesh.points
cpos = values_2d.flatten()
xpos_ypos = np.column_stack((x.flatten(), y.flatten(), cpos))
all_indices = self.__find_nearest_neighbors(xpos_ypos, xypoints)

Check warning on line 1673 in src/ansys/aedt/core/visualization/advanced/rcs_visualization.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/aedt/core/visualization/advanced/rcs_visualization.py#L1664-L1673

Added lines #L1664 - L1673 were not covered by tests

mag_for_color = np.ndarray.flatten(cpos[all_indices])
if mesh.__class__.__name__ != "PolyData":
mesh_triangulated = mesh.triangulate()
model_actor.custom_object.mesh = pv.PolyData(mesh_triangulated.points, mesh_triangulated.cells)

Check warning on line 1678 in src/ansys/aedt/core/visualization/advanced/rcs_visualization.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/aedt/core/visualization/advanced/rcs_visualization.py#L1675-L1678

Added lines #L1675 - L1678 were not covered by tests
else:
model_actor.custom_object.mesh.clear_data()
model_actor.custom_object.mesh[self.rcs_data.data_conversion_function] = mag_for_color
actor += model_actor.custom_object.mesh

Check warning on line 1682 in src/ansys/aedt/core/visualization/advanced/rcs_visualization.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/aedt/core/visualization/advanced/rcs_visualization.py#L1680-L1682

Added lines #L1680 - L1682 were not covered by tests

all_results_actors = list(self.all_scene_actors["results"].keys())

if "isar_2d" not in all_results_actors:
self.all_scene_actors["results"]["isar_2d"] = {}

index = 0
while f"isar_2d_{index}" in self.all_scene_actors["results"]["isar_2d"]:
index += 1

Check warning on line 1691 in src/ansys/aedt/core/visualization/advanced/rcs_visualization.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/aedt/core/visualization/advanced/rcs_visualization.py#L1691

Added line #L1691 was not covered by tests

isar_name = f"isar_2d_{index}"

isar_object = SceneMeshObject()
isar_object.name = isar_name

scalar_dict = dict(color="#000000", title="ISAR 2D")
isar_object.scalar_dict = scalar_dict

isar_object.cmap = color_bar

isar_object.mesh = actor

rcs_mesh = MeshObjectPlot(isar_object, isar_object.get_mesh())

self.all_scene_actors["results"]["isar_2d"][isar_name] = rcs_mesh

@pyaedt_function_handler()
def clear_scene(self, first_level=None, second_level=None, name=None):
if not first_level:
Expand Down Expand Up @@ -1651,7 +1740,7 @@
if extents is None:
extents = [0, 10, 0, 10, 0, 10]

plot_type_lower = plot_type.lower()
plot_type_lower = plot_type.casefold()
actor = None

if (
Expand Down
26 changes: 14 additions & 12 deletions src/ansys/aedt/core/visualization/plot/matplotlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1311,14 +1311,7 @@

@pyaedt_function_handler()
def plot_contour(
self,
trace=0,
polar=False,
levels=64,
max_theta=180,
color_bar=None,
snapshot_path=None,
show=True,
self, trace=0, polar=False, levels=64, max_theta=180, color_bar=None, snapshot_path=None, show=True, figure=None
):
"""Create a Matplotlib figure contour based on a list of data.

Expand All @@ -1343,6 +1336,9 @@
The default value is ``None``.
show : bool, optional
Whether to show the plot or return the matplotlib object. Default is ``True``.
figure : :class:`matplotlib.pyplot.Figure`, optional
An existing Matplotlib `Figure` to which the plot is added.
If not provided, a new `Figure` and `Axes` object are created.

Returns
-------
Expand All @@ -1355,7 +1351,14 @@
else:
tr = tr[0]
projection = "polar" if polar else "rectilinear"
self.fig, self.ax = plt.subplots(subplot_kw={"projection": projection})

if not figure:
self.fig, self.ax = plt.subplots(subplot_kw={"projection": projection})
self.ax = plt.gca()
else:
self.fig = figure
self.ax = figure.add_subplot(111, polar=polar)

Check warning on line 1360 in src/ansys/aedt/core/visualization/plot/matplotlib.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/aedt/core/visualization/plot/matplotlib.py#L1359-L1360

Added lines #L1359 - L1360 were not covered by tests

self.ax.set_xlabel(tr.x_label)
if polar:
self.ax.set_rticks(np.linspace(0, max_theta, 3))
Expand All @@ -1366,18 +1369,17 @@
ph = tr._spherical_data[2]
th = tr._spherical_data[1]
data_to_plot = tr._spherical_data[0]
plt.contourf(
contour = self.ax.contourf(
ph,
th,
data_to_plot,
levels=levels,
cmap="jet",
)
if color_bar:
cbar = plt.colorbar()
cbar = self.fig.colorbar(contour, ax=self.ax)
cbar.set_label(color_bar, rotation=270, labelpad=20)

self.ax = plt.gca()
self.ax.yaxis.set_label_coords(-0.1, 0.5)
self._plot(snapshot_path, show)
return self.fig
Expand Down
38 changes: 0 additions & 38 deletions tests/system/general/example_models/T49/rcs_metadata.json

This file was deleted.

38 changes: 0 additions & 38 deletions tests/system/general/example_models/T49/rcs_metadata_fake.json

This file was deleted.

Loading
Loading