Skip to content

Commit 6510d21

Browse files
Implemented new method to get all available report quantities categories and all report quantities. (#1323)
* Implemented new method to get all available report quantities categories and all report quantities. Furthermore now the report_by_templates classes supports None expression as argument as they will take all quantities of default category. Added method to identify if a setup or a sweep is solved or not by checking the solution data. * Fixed Documentation * Fixed Documentation * Update pyaedt/modules/SolveSetup.py * Update pyaedt/modules/PostProcessor.py * Update pyaedt/modules/PostProcessor.py * Fixed Documentation Co-authored-by: maxcapodi78 <Shark78> Co-authored-by: Maxime Rey <[email protected]>
1 parent ca8a3c1 commit 6510d21

File tree

7 files changed

+306
-80
lines changed

7 files changed

+306
-80
lines changed

_unittest/test_12_PostProcessing.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,12 @@ def teardown_class(self):
5757
BasisTest.my_teardown(self)
5858

5959
def test_01B_Field_Plot(self):
60+
assert len(self.aedtapp.post.available_display_types()) > 0
61+
assert len(self.aedtapp.post.available_report_types) > 0
62+
assert len(self.aedtapp.post.available_report_quantities()) > 0
6063
cutlist = ["Global:XY", "Global:XZ", "Global:YZ"]
6164
setup_name = self.aedtapp.existing_analysis_sweeps[0]
65+
assert self.aedtapp.setups[0].is_solved
6266
quantity_name = "ComplexMag_E"
6367
intrinsic = {"Freq": "5GHz", "Phase": "180deg"}
6468
min_value = self.aedtapp.post.get_scalar_field_value(quantity_name, "Minimum", setup_name, intrinsics="5GHz")
@@ -254,6 +258,7 @@ def test_09_manipulate_report(self):
254258
assert data.primary_sweep == "Freq"
255259
assert data.expressions[0] == "S(1,1)"
256260
assert len(self.aedtapp.post.all_report_names) > 0
261+
257262
variations = self.field_test.available_variations.nominal_w_values_dict
258263
variations["Theta"] = ["All"]
259264
variations["Phi"] = ["All"]
@@ -511,7 +516,7 @@ def test_09h_add_line_from_point(self): # pragma: no cover
511516
config["desktopVersion"] < "2022.2", reason="Not working in non-graphical mode in version earlier than 2022.2."
512517
)
513518
def test_09l_add_note(self): # pragma: no cover
514-
new_report = self.aedtapp.post.reports_by_category.modal_solution("dB(S(1,1))")
519+
new_report = self.aedtapp.post.reports_by_category.modal_solution()
515520
new_report.create()
516521

517522
new_report.add_note("Test", 8000, 1500)
@@ -608,8 +613,11 @@ def test_16_create_field_plot(self):
608613
assert plot
609614

610615
def test_17_circuit(self):
616+
assert not self.circuit_test.setups[0].is_solved
617+
611618
self.circuit_test.analyze_setup("LNA")
612619
self.circuit_test.analyze_setup("Transient")
620+
assert self.circuit_test.setups[0].is_solved
613621
assert self.circuit_test.post.create_report(["dB(S(Port1, Port1))", "dB(S(Port1, Port2))"], "LNA")
614622
new_report = self.circuit_test.post.reports_by_category.standard(
615623
["dB(S(Port1, Port1))", "dB(S(Port1, Port2))"], "LNA"
@@ -648,10 +656,21 @@ def test_17_circuit(self):
648656
assert self.circuit_test.post.create_report(
649657
["dB(V(net_11))", "dB(V(Port1))"], domain="Spectrum", setup_sweep_name="Transient"
650658
)
659+
new_report = self.circuit_test.post.reports_by_category.spectral(None, "Transient")
660+
new_report.window = "Hanning"
661+
new_report.max_freq = "1GHz"
662+
new_report.time_start = "1ns"
663+
new_report.time_stop = "190ns"
664+
new_report.plot_continous_spectrum = True
665+
assert new_report.create()
651666
pass
652667

653668
def test_18_diff_plot(self):
669+
assert len(self.diff_test.post.available_display_types()) > 0
670+
assert len(self.diff_test.post.available_report_types) > 0
671+
assert len(self.diff_test.post.available_report_quantities()) > 0
654672
self.diff_test.analyze_setup("LinearFrequency")
673+
assert self.diff_test.setups[0].is_solved
655674
variations = self.diff_test.available_variations.nominal_w_values_dict
656675
variations["Freq"] = ["All"]
657676
variations["l1"] = ["All"]
@@ -725,6 +744,7 @@ def test_54_reload(self):
725744
@pytest.mark.skipif(is_ironpython, reason="plot_scene method is not supported in ironpython")
726745
def test_55_time_plot(self):
727746
self.sbr_test.analyze_nominal(use_auto_settings=False)
747+
assert self.sbr_test.setups[0].is_solved
728748
solution_data = self.sbr_test.post.get_solution_data(
729749
expressions=["NearEX", "NearEY", "NearEZ"],
730750
variations={"_u": ["All"], "_v": ["All"], "Freq": ["All"]},
@@ -778,6 +798,8 @@ def test_57_test_export_q2d_results(self):
778798
new_report = self.q2dtest.post.reports_by_category.rl_fields("Mag_H", polyline="Poly1")
779799
assert new_report.create()
780800
assert len(self.q2dtest.post.plots) == 3
801+
new_report = self.q2dtest.post.reports_by_category.standard()
802+
assert new_report.get_solution_data()
781803

782804
def test_58_test_no_report(self):
783805
assert not self.aedtapp.post.reports_by_category.eye_diagram()

_unittest/test_20_HFSS.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ def test_06a_create_linear_count_sweep(self):
127127
setup.props["MaximumPasses"] = 1
128128
assert setup.update()
129129
assert self.aedtapp.create_linear_count_sweep("MySetup", "GHz", 0.8, 1.2, 401)
130+
assert not self.aedtapp.setups[0].sweeps[0].is_solved
130131
assert self.aedtapp.create_linear_count_sweep("MySetup", "GHz", 0.8, 1.2, 401)
131132
assert self.aedtapp.create_linear_count_sweep(
132133
setupname="MySetup",

pyaedt/application/design_solutions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,14 +336,14 @@
336336
"options": "TemperatureAndFlow",
337337
"report_type": "Monitor",
338338
"default_setup": 11,
339-
"default_adaptive": None,
339+
"default_adaptive": "SteadyState",
340340
},
341341
"Transient": {
342342
"name": "Transient",
343343
"options": "TemperatureAndFlow",
344344
"report_type": "Monitor",
345345
"default_setup": 36,
346-
"default_adaptive": None,
346+
"default_adaptive": "Transient",
347347
},
348348
},
349349
"RMxprtSolution": {

pyaedt/modules/PostProcessor.py

Lines changed: 126 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"HFSS": [
2525
"Modal Solution Data",
2626
"Terminal Solution Data",
27-
"EigenMode Parameters",
27+
"Eigenmode Parameters",
2828
"Fields",
2929
"Far Fields",
3030
"Emissions",
@@ -55,6 +55,7 @@
5555
"Icepak": ["Monitor", "Fields"],
5656
"Circuit Design": ["Standard", "Eye Diagram", "Spectrum"],
5757
"HFSS 3D Layout": ["Standard", "Fields", "Spectrum"],
58+
"HFSS 3D Layout Design": ["Standard", "Fields", "Spectrum"],
5859
"Mechanical": ["Standard", "Fields"],
5960
"Q3D Extractor": ["Matrix", "CG Fields", "DC R/L Fields", "AC R/L Fields"],
6061
"2D Extractor": ["Matrix", "CG Fields", "RL Fields"],
@@ -73,7 +74,7 @@
7374
"Far Fields": rt.FarField,
7475
"Near Fields": rt.NearField,
7576
"Eye Diagram": rt.EyeDiagram,
76-
"EigenMode Parameters": rt.Standard,
77+
"Eigenmode Parameters": rt.Standard,
7778
"Spectrum": rt.Spectral,
7879
}
7980

@@ -481,8 +482,8 @@ def eigenmode(self, expressions=None, setup_name=None):
481482
"""
482483
if not setup_name:
483484
setup_name = self._post_app._app.nominal_sweep
484-
if "EigenMode Parameters" in self._templates:
485-
rep = rt.Standard(self._post_app, "EigenMode Parameters", setup_name)
485+
if "Eigenmode Parameters" in self._templates:
486+
rep = rt.Standard(self._post_app, "Eigenmode Parameters", setup_name)
486487
rep.expressions = expressions
487488
return rep
488489
return
@@ -609,6 +610,113 @@ def __init__(self, app):
609610
self.plots = self._get_plot_inputs()
610611
self.reports_by_category = Reports(self, self._app.design_type)
611612

613+
@property
614+
def available_report_types(self):
615+
"""Report types.
616+
617+
References
618+
----------
619+
620+
>>> oModule.GetAvailableReportTypes
621+
"""
622+
return list(self.oreportsetup.GetAvailableReportTypes())
623+
624+
@pyaedt_function_handler()
625+
def available_display_types(self, report_category=None):
626+
"""Retrieve display types for a report categories.
627+
628+
Parameters
629+
----------
630+
report_category : str, optional
631+
Type of the report. The default value is ``None``.
632+
633+
Returns
634+
-------
635+
list
636+
List of available report categories.
637+
638+
References
639+
----------
640+
>>> oModule.GetAvailableDisplayTypes
641+
"""
642+
if not report_category:
643+
report_category = self.available_report_types[0]
644+
if report_category:
645+
return list(self.oreportsetup.GetAvailableDisplayTypes(report_category))
646+
return []
647+
648+
@pyaedt_function_handler()
649+
def available_quantities_categories(self, report_category=None, display_type=None, solution=None, context=""):
650+
"""Compute the list of all available report categories.
651+
652+
Parameters
653+
----------
654+
report_category : str, optional
655+
Report Category. Default is `None` which will take first default category.
656+
display_type : str, optional
657+
Report Display Type.
658+
Default is `None` which will take first default type which is in most of the case "Rectangular Plot".
659+
solution : str, optional
660+
Report Setup. Default is `None` which will take first nominal_adpative solution.
661+
context : str, optional
662+
Report Category. Default is `""` which will take first default context.
663+
664+
Returns
665+
-------
666+
list
667+
"""
668+
if not report_category:
669+
report_category = self.available_report_types[0]
670+
if not display_type:
671+
display_type = self.available_display_types(report_category)[0]
672+
if not solution:
673+
solution = self._app.nominal_adaptive
674+
if solution and report_category and display_type:
675+
return list(self.oreportsetup.GetAllCategories(report_category, display_type, solution, context))
676+
return []
677+
678+
@pyaedt_function_handler()
679+
def available_report_quantities(
680+
self, report_category=None, display_type=None, solution=None, quantities_category=None, context=""
681+
):
682+
"""Compute the list of all available report quantities of a given report quantity category.
683+
684+
Parameters
685+
----------
686+
report_category : str, optional
687+
Report Category. Default is `None` which will take first default category.
688+
display_type : str, optional
689+
Report Display Type.
690+
Default is `None` which will take first default type which is in most of the case "Rectangular Plot".
691+
solution : str, optional
692+
Report Setup. Default is `None` which will take first nominal_adpative solution.
693+
quantities_category : str, optional
694+
The category to which quantities belong. It has to be one of `available_quantities_categories` method.
695+
Default is `None` which will take first default quantity.".
696+
context : str, optional
697+
Report Category. Default is `""` which will take first default context.
698+
699+
Returns
700+
-------
701+
list
702+
"""
703+
if not report_category:
704+
report_category = self.available_report_types[0]
705+
if not display_type:
706+
display_type = self.available_display_types(report_category)[0]
707+
if not solution:
708+
solution = self._app.nominal_adaptive
709+
if not quantities_category:
710+
categories = self.available_quantities_categories(report_category, display_type, solution, context)
711+
quantities_category = categories[0] if categories else None
712+
if quantities_category and display_type and report_category and solution:
713+
return list(
714+
self.oreportsetup.GetAllQuantities(
715+
report_category, display_type, solution, context, quantities_category
716+
)
717+
)
718+
return None
719+
612720
@pyaedt_function_handler()
613721
def _get_plot_inputs(self):
614722
names = self._app.get_oo_name(self.oreportsetup)
@@ -1013,12 +1121,15 @@ def get_solution_data_per_variation(
10131121
if not setup_sweep_name:
10141122
setup_sweep_name = self._app.nominal_adaptive
10151123
sweep_list = _convert_dict_to_report_sel(sweeps)
1016-
1017-
data = list(
1018-
self.oreportsetup.GetSolutionDataPerVariation(soltype, setup_sweep_name, ctxt, sweep_list, expression)
1019-
)
1020-
self.logger.info("Solution Data Correctly Loaded.")
1021-
return SolutionData(data)
1124+
try:
1125+
data = list(
1126+
self.oreportsetup.GetSolutionDataPerVariation(soltype, setup_sweep_name, ctxt, sweep_list, expression)
1127+
)
1128+
self.logger.info("Solution Data Correctly Loaded.")
1129+
return SolutionData(data)
1130+
except:
1131+
self.logger.warning("Solution Data failed to load. Check solution, context or expression.")
1132+
return None
10221133

10231134
@pyaedt_function_handler()
10241135
def steal_focus_oneditor(self):
@@ -1762,37 +1873,6 @@ def ofieldsreporter(self):
17621873
"""
17631874
return self._app.ofieldsreporter
17641875

1765-
@property
1766-
def report_types(self):
1767-
"""Report types.
1768-
1769-
References
1770-
----------
1771-
1772-
>>> oModule.GetAvailableReportTypes
1773-
"""
1774-
return list(self.oreportsetup.GetAvailableReportTypes())
1775-
1776-
@pyaedt_function_handler()
1777-
def display_types(self, report_type):
1778-
"""Retrieve display types for a report type.
1779-
1780-
Parameters
1781-
----------
1782-
report_type : str
1783-
Type of the report.
1784-
1785-
Returns
1786-
-------
1787-
:attr:`pyaedt.modules.PostProcessor.PostProcessor.report_types`
1788-
1789-
References
1790-
----------
1791-
1792-
>>> oModule.GetAvailableDisplayTypes
1793-
"""
1794-
return self.oreportsetup.GetAvailableDisplayTypes(report_type)
1795-
17961876
@pyaedt_function_handler()
17971877
def _get_base_name(self, setup):
17981878
setups_data = self._app.design_properties["FieldsReporter"]["FieldsPlotManagerID"]
@@ -1805,7 +1885,11 @@ def _get_base_name(self, setup):
18051885
if isinstance(sim_data["SimSetup"], list):
18061886
for solution in sim_data["SimSetup"]:
18071887
base_name = solution["Name"]
1808-
for sol in solution["Solution"]:
1888+
if isinstance(solution["Solution"], (dict, OrderedDict)):
1889+
sols = [solution["Solution"]]
1890+
else:
1891+
sols = solution["Solution"]
1892+
for sol in sols:
18091893
if sol["ID"] == setups_data[setup]["SolutionId"]:
18101894
base_name += " : " + sol["Name"]
18111895
return base_name

0 commit comments

Comments
 (0)