From 1c01352b2f1c8eafbff808f592baec0a6abc168b Mon Sep 17 00:00:00 2001 From: Angran Li Date: Wed, 14 May 2025 18:44:24 +0000 Subject: [PATCH 01/15] Add dump_table_csv to report settings --- flow360/plugins/report/report_items.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/flow360/plugins/report/report_items.py b/flow360/plugins/report/report_items.py index 06017f66c..34e3531d9 100644 --- a/flow360/plugins/report/report_items.py +++ b/flow360/plugins/report/report_items.py @@ -109,6 +109,7 @@ class Settings(Flow360BaseModel): """ dpi: Optional[pd.PositiveInt] = 300 + dump_table_csv: Optional[pd.StrictBool] = False class ReportItem(Flow360BaseModel): @@ -408,6 +409,10 @@ def get_doc_item(self, context: ReportContext, settings: Settings = None) -> Non table.add_row(formatted) table.add_hline() + if settings is not None and settings.dump_table_csv: + df = self.to_dataframe(context=context) + df.to_csv(f"{self.section_title}.csv", index=False) + class PatternCaption(Flow360BaseModel): """ From 851c0a37e79ef4c403cd3b77365c37b7565bfdd2 Mon Sep 17 00:00:00 2001 From: Angran Li Date: Mon, 19 May 2025 11:24:01 +0000 Subject: [PATCH 02/15] Create default report config service --- flow360/component/project.py | 6 +++ flow360/component/simulation/services.py | 60 ++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/flow360/component/project.py b/flow360/component/project.py index a89562f01..56af7cd35 100644 --- a/flow360/component/project.py +++ b/flow360/component/project.py @@ -14,6 +14,7 @@ from PrettyPrint import PrettyPrintTree from pydantic import PositiveInt +from flow360.plugins.report.report import ReportTemplate from flow360.cloud.flow360_requests import LengthUnitType from flow360.cloud.rest_api import RestApi from flow360.component.case import Case @@ -31,6 +32,7 @@ validate_params_with_context, ) from flow360.component.resource_base import Flow360Resource +from flow360.component.simulation.services import get_default_report_config from flow360.component.simulation.simulation_params import SimulationParams from flow360.component.simulation.unit_system import LengthType from flow360.component.simulation.web.asset_base import AssetBase @@ -1356,6 +1358,10 @@ def _run( log.info(f"Successfully submitted: {destination_obj.short_description()}") + if target == "Case": + report_config = get_default_report_config() + ReportTemplate(**report_config).create_in_cloud(name = "ResultSummary", cases=[destination_obj]) + if not run_async: destination_obj.wait() diff --git a/flow360/component/simulation/services.py b/flow360/component/simulation/services.py index ce6a3931c..3a5f31a78 100644 --- a/flow360/component/simulation/services.py +++ b/flow360/component/simulation/services.py @@ -57,6 +57,10 @@ from flow360.exceptions import Flow360RuntimeError, Flow360TranslationError from flow360.version import __version__ +from flow360.plugins.report.report import ReportTemplate +from flow360.plugins.report.report_items import Settings, Table +from flow360.plugins.report.utils import Average, DataItem + unit_system_map = { "SI": SI_unit_system, "CGS": CGS_unit_system, @@ -764,3 +768,59 @@ def update_simulation_json(*, params_as_dict: dict, target_python_api_version: s # Expected exceptions errors.append(str(e)) return updated_params_as_dict, errors + + +def get_default_report_config() -> dict: + avg = Average(fraction=0.1) + CL = DataItem( + data="surface_forces/totalCL", title="CL", operations=avg + ) + CD = DataItem( + data="surface_forces/totalCD", title="CD", operations=avg + ) + CFy = DataItem( + data="surface_forces/totalCFy", title="CFy", operations=avg + ) + CMx = DataItem( + data="surface_forces/totalCMx", title="CMx", operations=avg + ) + CMy = DataItem( + data="surface_forces/totalCMy", title="CMy", operations=avg + ) + CMz = DataItem( + data="surface_forces/totalCMz", title="CMz", operations=avg + ) + + data = [ + "volume_mesh/bounding_box/length", + "volume_mesh/bounding_box/height", + "volume_mesh/bounding_box/width", + "params/reference_geometry/moment_length", + "params/reference_geometry/area", + CL, + CD, + CFy, + CMx, + CMy, + CMz, + ] + + headers = [ + "OAL", + "OAH", + "OAW", + "Reference Length", + "Reference Area", + "CL", + "CD", + "CFy", + "CMx", + "CMy", + "CMz", + ] + formatter = [".4f" for _ in data] + table = Table( + data=data, section_title="result_summary", headers=headers, formatter=formatter + ) + report_dict = ReportTemplate(items=[table], settings=Settings(dump_table_csv=True)).model_dump(exclude_none=True) + return report_dict \ No newline at end of file From b77468f2f245094e5e0fb83cb851bda7fdf4a79a Mon Sep 17 00:00:00 2001 From: Angran Li Date: Mon, 19 May 2025 11:29:41 +0000 Subject: [PATCH 03/15] Fix format --- flow360/component/project.py | 7 ++-- flow360/component/simulation/services.py | 44 ++++++++---------------- 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/flow360/component/project.py b/flow360/component/project.py index 56af7cd35..7760397a5 100644 --- a/flow360/component/project.py +++ b/flow360/component/project.py @@ -14,7 +14,6 @@ from PrettyPrint import PrettyPrintTree from pydantic import PositiveInt -from flow360.plugins.report.report import ReportTemplate from flow360.cloud.flow360_requests import LengthUnitType from flow360.cloud.rest_api import RestApi from flow360.component.case import Case @@ -50,6 +49,7 @@ from flow360.component.volume_mesh import VolumeMeshV2 from flow360.exceptions import Flow360FileError, Flow360ValueError, Flow360WebError from flow360.log import log +from flow360.plugins.report.report import ReportTemplate from flow360.version import __solver_version__ AssetOrResource = Union[type[AssetBase], type[Flow360Resource]] @@ -1277,6 +1277,7 @@ def _run( root asset (Geometry or VolumeMesh) is not initialized. """ + # pylint: disable=too-many-branches if use_beta_mesher is None: if use_geometry_AI is True: log.info("Beta mesher is enabled to use Geometry AI.") @@ -1360,7 +1361,9 @@ def _run( if target == "Case": report_config = get_default_report_config() - ReportTemplate(**report_config).create_in_cloud(name = "ResultSummary", cases=[destination_obj]) + ReportTemplate(**report_config).create_in_cloud( + name="ResultSummary", cases=[destination_obj] + ) if not run_async: destination_obj.wait() diff --git a/flow360/component/simulation/services.py b/flow360/component/simulation/services.py index 3a5f31a78..672b6f4e0 100644 --- a/flow360/component/simulation/services.py +++ b/flow360/component/simulation/services.py @@ -55,11 +55,10 @@ ValidationContext, ) from flow360.exceptions import Flow360RuntimeError, Flow360TranslationError -from flow360.version import __version__ - from flow360.plugins.report.report import ReportTemplate from flow360.plugins.report.report_items import Settings, Table from flow360.plugins.report.utils import Average, DataItem +from flow360.version import __version__ unit_system_map = { "SI": SI_unit_system, @@ -771,25 +770,10 @@ def update_simulation_json(*, params_as_dict: dict, target_python_api_version: s def get_default_report_config() -> dict: + """ + Returns default report config for result summary. + """ avg = Average(fraction=0.1) - CL = DataItem( - data="surface_forces/totalCL", title="CL", operations=avg - ) - CD = DataItem( - data="surface_forces/totalCD", title="CD", operations=avg - ) - CFy = DataItem( - data="surface_forces/totalCFy", title="CFy", operations=avg - ) - CMx = DataItem( - data="surface_forces/totalCMx", title="CMx", operations=avg - ) - CMy = DataItem( - data="surface_forces/totalCMy", title="CMy", operations=avg - ) - CMz = DataItem( - data="surface_forces/totalCMz", title="CMz", operations=avg - ) data = [ "volume_mesh/bounding_box/length", @@ -797,12 +781,12 @@ def get_default_report_config() -> dict: "volume_mesh/bounding_box/width", "params/reference_geometry/moment_length", "params/reference_geometry/area", - CL, - CD, - CFy, - CMx, - CMy, - CMz, + DataItem(data="surface_forces/totalCL", title="CL", operations=avg), + DataItem(data="surface_forces/totalCD", title="CD", operations=avg), + DataItem(data="surface_forces/totalCFy", title="CFy", operations=avg), + DataItem(data="surface_forces/totalCMx", title="CMx", operations=avg), + DataItem(data="surface_forces/totalCMy", title="CMy", operations=avg), + DataItem(data="surface_forces/totalCMz", title="CMz", operations=avg), ] headers = [ @@ -819,8 +803,8 @@ def get_default_report_config() -> dict: "CMz", ] formatter = [".4f" for _ in data] - table = Table( - data=data, section_title="result_summary", headers=headers, formatter=formatter + table = Table(data=data, section_title="result_summary", headers=headers, formatter=formatter) + report_dict = ReportTemplate(items=[table], settings=Settings(dump_table_csv=True)).model_dump( + exclude_none=True ) - report_dict = ReportTemplate(items=[table], settings=Settings(dump_table_csv=True)).model_dump(exclude_none=True) - return report_dict \ No newline at end of file + return report_dict From 19f208dafd792f2db543eade9fba86c11688e10d Mon Sep 17 00:00:00 2001 From: Angran Li Date: Mon, 19 May 2025 14:40:10 +0000 Subject: [PATCH 04/15] Address circular import --- flow360/plugins/report/report.py | 2 +- flow360/plugins/report/report_context.py | 2 +- flow360/plugins/report/report_items.py | 3 ++- flow360/plugins/report/utils.py | 2 +- flow360/plugins/report/uvf_shutter.py | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/flow360/plugins/report/report.py b/flow360/plugins/report/report.py index 7c74f8516..ea0452e6c 100644 --- a/flow360/plugins/report/report.py +++ b/flow360/plugins/report/report.py @@ -11,9 +11,9 @@ # pylint: disable=import-error from pylatex import Section, Subsection -from flow360 import Case from flow360.cloud.flow360_requests import NewReportRequest from flow360.cloud.rest_api import RestApi +from flow360.component.case import Case from flow360.component.interfaces import ReportInterface from flow360.component.resource_base import AssetMetaBaseModel, Flow360Resource from flow360.component.simulation.framework.base_model import Flow360BaseModel diff --git a/flow360/plugins/report/report_context.py b/flow360/plugins/report/report_context.py index e54c78574..11e157b61 100644 --- a/flow360/plugins/report/report_context.py +++ b/flow360/plugins/report/report_context.py @@ -9,7 +9,7 @@ # pylint: disable=import-error from pylatex import Document, Section, Subsection -from flow360 import Case +from flow360.component.case import Case class ReportContext(pd.BaseModel): diff --git a/flow360/plugins/report/report_items.py b/flow360/plugins/report/report_items.py index 34e3531d9..c6a2c9b30 100644 --- a/flow360/plugins/report/report_items.py +++ b/flow360/plugins/report/report_items.py @@ -33,13 +33,14 @@ # pylint: disable=import-error from pylatex.utils import bold, escape_latex -from flow360 import Case, SimulationParams +from flow360.component.case import Case from flow360.component.simulation.framework.base_model import Flow360BaseModel from flow360.component.simulation.outputs.output_fields import ( IsoSurfaceFieldNames, SurfaceFieldNames, get_unit_for_field, ) +from flow360.component.simulation.simulation_params import SimulationParams from flow360.component.simulation.time_stepping.time_stepping import Unsteady from flow360.component.simulation.unit_system import ( DimensionedTypes, diff --git a/flow360/plugins/report/utils.py b/flow360/plugins/report/utils.py index 8ee766a5b..3cb94e293 100644 --- a/flow360/plugins/report/utils.py +++ b/flow360/plugins/report/utils.py @@ -26,7 +26,7 @@ # pylint: disable=import-error from pylatex import NoEscape, Package, Tabular -from flow360 import Case +from flow360.component.case import Case from flow360.component.results import base_results, case_results from flow360.component.simulation.framework.base_model import ( Conflicts, diff --git a/flow360/plugins/report/uvf_shutter.py b/flow360/plugins/report/uvf_shutter.py index 4e7a8a6e5..d754e818f 100644 --- a/flow360/plugins/report/uvf_shutter.py +++ b/flow360/plugins/report/uvf_shutter.py @@ -15,8 +15,8 @@ import pydantic as pd -from flow360 import Env from flow360.component.simulation.framework.base_model import Flow360BaseModel +from flow360.environment import Env from flow360.exceptions import ( Flow360RuntimeError, Flow360WebError, From a2ea4f9466bc030b26718f6de8769eb1462fc5b0 Mon Sep 17 00:00:00 2001 From: Angran Li Date: Mon, 19 May 2025 15:44:33 +0000 Subject: [PATCH 05/15] Add function to get default report config and initiate a report job after each case --- flow360/component/project.py | 9 +++---- flow360/plugins/report/report.py | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/flow360/component/project.py b/flow360/component/project.py index 7760397a5..0dcdb6df0 100644 --- a/flow360/component/project.py +++ b/flow360/component/project.py @@ -31,7 +31,6 @@ validate_params_with_context, ) from flow360.component.resource_base import Flow360Resource -from flow360.component.simulation.services import get_default_report_config from flow360.component.simulation.simulation_params import SimulationParams from flow360.component.simulation.unit_system import LengthType from flow360.component.simulation.web.asset_base import AssetBase @@ -49,7 +48,7 @@ from flow360.component.volume_mesh import VolumeMeshV2 from flow360.exceptions import Flow360FileError, Flow360ValueError, Flow360WebError from flow360.log import log -from flow360.plugins.report.report import ReportTemplate +from flow360.plugins.report.report import get_default_report_template from flow360.version import __solver_version__ AssetOrResource = Union[type[AssetBase], type[Flow360Resource]] @@ -1360,10 +1359,8 @@ def _run( log.info(f"Successfully submitted: {destination_obj.short_description()}") if target == "Case": - report_config = get_default_report_config() - ReportTemplate(**report_config).create_in_cloud( - name="ResultSummary", cases=[destination_obj] - ) + report_template = get_default_report_template() + report_template.create_in_cloud(name="ResultSummary", cases=[destination_obj]) if not run_async: destination_obj.wait() diff --git a/flow360/plugins/report/report.py b/flow360/plugins/report/report.py index ea0452e6c..33a2dda43 100644 --- a/flow360/plugins/report/report.py +++ b/flow360/plugins/report/report.py @@ -32,6 +32,8 @@ Table, ) from flow360.plugins.report.utils import ( + Average, + DataItem, RequirementItem, get_requirements_from_data_path, ) @@ -319,3 +321,41 @@ def create_pdf( item.get_doc_item(case_context, self.settings) report_doc.generate_pdf(os.path.join(data_storage, filename)) + + +def get_default_report_template() -> ReportTemplate: + """ + Returns default report template for result summary. + """ + avg = Average(fraction=0.1) + + data = [ + "volume_mesh/bounding_box/length", + "volume_mesh/bounding_box/height", + "volume_mesh/bounding_box/width", + "params/reference_geometry/moment_length", + "params/reference_geometry/area", + DataItem(data="surface_forces/totalCL", title="CL", operations=avg), + DataItem(data="surface_forces/totalCD", title="CD", operations=avg), + DataItem(data="surface_forces/totalCFy", title="CFy", operations=avg), + DataItem(data="surface_forces/totalCMx", title="CMx", operations=avg), + DataItem(data="surface_forces/totalCMy", title="CMy", operations=avg), + DataItem(data="surface_forces/totalCMz", title="CMz", operations=avg), + ] + + headers = [ + "OAL", + "OAH", + "OAW", + "Reference Length", + "Reference Area", + "CL", + "CD", + "CFy", + "CMx", + "CMy", + "CMz", + ] + formatter = [".4f" for _ in data] + table = Table(data=data, section_title="result_summary", headers=headers, formatter=formatter) + return ReportTemplate(items=[table], settings=Settings(dump_table_csv=True)) From 78a3dfe10973526feae8f417d054bec5a431999c Mon Sep 17 00:00:00 2001 From: Angran Li Date: Mon, 19 May 2025 16:42:30 +0000 Subject: [PATCH 06/15] Add service function --- flow360/component/simulation/services.py | 46 +++++------------------- 1 file changed, 8 insertions(+), 38 deletions(-) diff --git a/flow360/component/simulation/services.py b/flow360/component/simulation/services.py index 672b6f4e0..243285d0c 100644 --- a/flow360/component/simulation/services.py +++ b/flow360/component/simulation/services.py @@ -55,9 +55,7 @@ ValidationContext, ) from flow360.exceptions import Flow360RuntimeError, Flow360TranslationError -from flow360.plugins.report.report import ReportTemplate -from flow360.plugins.report.report_items import Settings, Table -from flow360.plugins.report.utils import Average, DataItem +from flow360.plugins.report.report import get_default_report_template from flow360.version import __version__ unit_system_map = { @@ -771,40 +769,12 @@ def update_simulation_json(*, params_as_dict: dict, target_python_api_version: s def get_default_report_config() -> dict: """ - Returns default report config for result summary. + Get the default report config + Returns + ------- + dict + default report config """ - avg = Average(fraction=0.1) - - data = [ - "volume_mesh/bounding_box/length", - "volume_mesh/bounding_box/height", - "volume_mesh/bounding_box/width", - "params/reference_geometry/moment_length", - "params/reference_geometry/area", - DataItem(data="surface_forces/totalCL", title="CL", operations=avg), - DataItem(data="surface_forces/totalCD", title="CD", operations=avg), - DataItem(data="surface_forces/totalCFy", title="CFy", operations=avg), - DataItem(data="surface_forces/totalCMx", title="CMx", operations=avg), - DataItem(data="surface_forces/totalCMy", title="CMy", operations=avg), - DataItem(data="surface_forces/totalCMz", title="CMz", operations=avg), - ] - - headers = [ - "OAL", - "OAH", - "OAW", - "Reference Length", - "Reference Area", - "CL", - "CD", - "CFy", - "CMx", - "CMy", - "CMz", - ] - formatter = [".4f" for _ in data] - table = Table(data=data, section_title="result_summary", headers=headers, formatter=formatter) - report_dict = ReportTemplate(items=[table], settings=Settings(dump_table_csv=True)).model_dump( - exclude_none=True + return get_default_report_template().model_dump( + exclude_none=True, ) - return report_dict From fd5ab4a965a7fb8b44130213357a6c05c14f1a78 Mon Sep 17 00:00:00 2001 From: Angran Li Date: Mon, 19 May 2025 17:07:26 +0000 Subject: [PATCH 07/15] Add unit test --- .../simulation/framework/updater_utils.py | 2 +- .../service/ref/default_report_config.json | 112 ++++++++++++++++++ tests/simulation/service/test_services_v2.py | 9 ++ 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 tests/simulation/service/ref/default_report_config.json diff --git a/flow360/component/simulation/framework/updater_utils.py b/flow360/component/simulation/framework/updater_utils.py index c566cf2df..dc78ff539 100644 --- a/flow360/component/simulation/framework/updater_utils.py +++ b/flow360/component/simulation/framework/updater_utils.py @@ -48,7 +48,7 @@ def compare_lists(list1, list2, atol=1e-15, rtol=1e-10, ignore_keys=None): if len(list1) != len(list2): return False - if list1 and not isinstance(list1[0], dict): + if list1 and not any(isinstance(item, dict) for item in list1): list1, list2 = sorted(list1), sorted(list2) for item1, item2 in zip(list1, list2): diff --git a/tests/simulation/service/ref/default_report_config.json b/tests/simulation/service/ref/default_report_config.json new file mode 100644 index 000000000..97ce07c47 --- /dev/null +++ b/tests/simulation/service/ref/default_report_config.json @@ -0,0 +1,112 @@ +{ + "items": [ + { + "data": [ + "volume_mesh/bounding_box/length", + "volume_mesh/bounding_box/height", + "volume_mesh/bounding_box/width", + "params/reference_geometry/moment_length", + "params/reference_geometry/area", + { + "data": "surface_forces/totalCL", + "title": "CL", + "operations": [ + { + "fraction": 0.1, + "type_name": "Average" + } + ], + "type_name": "DataItem" + }, + { + "data": "surface_forces/totalCD", + "title": "CD", + "operations": [ + { + "fraction": 0.1, + "type_name": "Average" + } + ], + "type_name": "DataItem" + }, + { + "data": "surface_forces/totalCFy", + "title": "CFy", + "operations": [ + { + "fraction": 0.1, + "type_name": "Average" + } + ], + "type_name": "DataItem" + }, + { + "data": "surface_forces/totalCMx", + "title": "CMx", + "operations": [ + { + "fraction": 0.1, + "type_name": "Average" + } + ], + "type_name": "DataItem" + }, + { + "data": "surface_forces/totalCMy", + "title": "CMy", + "operations": [ + { + "fraction": 0.1, + "type_name": "Average" + } + ], + "type_name": "DataItem" + }, + { + "data": "surface_forces/totalCMz", + "title": "CMz", + "operations": [ + { + "fraction": 0.1, + "type_name": "Average" + } + ], + "type_name": "DataItem" + } + ], + "section_title": "result_summary", + "headers": [ + "OAL", + "OAH", + "OAW", + "Reference Length", + "Reference Area", + "CL", + "CD", + "CFy", + "CMx", + "CMy", + "CMz" + ], + "type_name": "Table", + "formatter": [ + ".4f", + ".4f", + ".4f", + ".4f", + ".4f", + ".4f", + ".4f", + ".4f", + ".4f", + ".4f", + ".4f" + ] + } + ], + "include_case_by_case": false, + "settings": { + "dpi": 300, + "dump_table_csv": true + } +} \ No newline at end of file diff --git a/tests/simulation/service/test_services_v2.py b/tests/simulation/service/test_services_v2.py index e11bdc38f..30f10b4f7 100644 --- a/tests/simulation/service/test_services_v2.py +++ b/tests/simulation/service/test_services_v2.py @@ -1258,3 +1258,12 @@ def _get_all_units(value): f"Unit {unit_system_dimension_string} (A.K.A {field_name}) is not supported by the front-end.", "Please ensure front end team is aware of this new unit and add its support.", ) + + +def test_get_default_report_config_json(): + report_config_dict = services.get_default_report_config() + with open("ref/default_report_config.json", "r") as fp: + ref_dict = json.load(fp) + print(report_config_dict) + print(ref_dict) + assert compare_values(report_config_dict, ref_dict) From 0cc5c61394c0f811d0dcf82c8c525c348c822d84 Mon Sep 17 00:00:00 2001 From: Angran Li Date: Mon, 19 May 2025 18:14:57 +0000 Subject: [PATCH 08/15] Fix report submission --- flow360/component/project.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/flow360/component/project.py b/flow360/component/project.py index 0dcdb6df0..325cc1041 100644 --- a/flow360/component/project.py +++ b/flow360/component/project.py @@ -1358,9 +1358,11 @@ def _run( log.info(f"Successfully submitted: {destination_obj.short_description()}") - if target == "Case": + if isinstance(destination_obj, Case): report_template = get_default_report_template() - report_template.create_in_cloud(name="ResultSummary", cases=[destination_obj]) + report_template.create_in_cloud( + name="ResultSummary", cases=[destination_obj], solver_version=solver_version + ) if not run_async: destination_obj.wait() From cf1a2db8603f690340aa654a61d661b3b62be380 Mon Sep 17 00:00:00 2001 From: Angran Li Date: Mon, 19 May 2025 18:17:35 +0000 Subject: [PATCH 09/15] fix solver version --- flow360/component/project.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flow360/component/project.py b/flow360/component/project.py index 325cc1041..1bdf82392 100644 --- a/flow360/component/project.py +++ b/flow360/component/project.py @@ -1361,7 +1361,9 @@ def _run( if isinstance(destination_obj, Case): report_template = get_default_report_template() report_template.create_in_cloud( - name="ResultSummary", cases=[destination_obj], solver_version=solver_version + name="ResultSummary", + cases=[destination_obj], + solver_version=solver_version if solver_version else self.solver_version, ) if not run_async: From 8ba9b26a82deb0e16f8c4f67925c6237e3a664a3 Mon Sep 17 00:00:00 2001 From: Angran Li Date: Mon, 19 May 2025 19:01:52 +0000 Subject: [PATCH 10/15] Add mock response --- flow360/plugins/report/report.py | 3 +++ tests/data/mock_webapi/report_meta_resp.json | 15 +++++++++++++++ tests/mock_server.py | 11 +++++++++++ 3 files changed, 29 insertions(+) create mode 100644 tests/data/mock_webapi/report_meta_resp.json diff --git a/flow360/plugins/report/report.py b/flow360/plugins/report/report.py index 33a2dda43..941f28730 100644 --- a/flow360/plugins/report/report.py +++ b/flow360/plugins/report/report.py @@ -131,6 +131,9 @@ def submit( solver_version=solver_version, ) resp = cls._webapi.post(json=request.dict()) + print("AAAAAAAAAAAAAAAAAA",resp) + from flow360.log import log + log.info(f"Report draft response: {resp}") return Report(resp["id"]) diff --git a/tests/data/mock_webapi/report_meta_resp.json b/tests/data/mock_webapi/report_meta_resp.json new file mode 100644 index 000000000..114b74818 --- /dev/null +++ b/tests/data/mock_webapi/report_meta_resp.json @@ -0,0 +1,15 @@ +{ + "userId": "AIDAU77I6BZ2QYZLLVSRW", + "id": "rep-00508a80-2566-45bf-9572-56228a3161fd", + "status": "submitted", + "name": "ResultSummary", + "resources": [ + { + "type": "Case", + "id": "case-f813742a-61d3-497c-8447-3ac8b0c997f1", + "rawData": null + } + ], + "createdAt": "2025-05-19T18:30:51.476347Z", + "updatedAt": "2025-05-19T18:30:51.476347Z" +} \ No newline at end of file diff --git a/tests/mock_server.py b/tests/mock_server.py index b7393e757..9b39113e2 100644 --- a/tests/mock_server.py +++ b/tests/mock_server.py @@ -526,6 +526,16 @@ def json(self): return res +class MockResponseReportSubmit(MockResponse): + """response for report_template.create_in_cloud's meta json""" + + @staticmethod + def json(): + with open(os.path.join(here, "data/mock_webapi/report_meta_resp.json")) as fh: + res = json.load(fh) + print(res) + return res + GET_RESPONSE_MAP = { "/volumemeshes/00112233-4455-6677-8899-aabbccddeeff": MockResponseVolumeMesh, "/volumemeshes/00000000-0000-0000-0000-000000000000": MockResponseVolumeMesh, @@ -574,6 +584,7 @@ def json(self): "/v2/drafts/vm-7c3681cd-8c6c-4db7-a62c-1742d825e9d3/run": MockResponseProjectVolumeMesh, "/v2/drafts/case-84d4604e-f3cd-4c6b-8517-92a80a3346d3/simulation/file": MockResponseProjectCaseForkSimConfig, "/v2/drafts/case-84d4604e-f3cd-4c6b-8517-92a80a3346d3/run": MockResponseProjectCaseFork, + "/v2/report":MockResponseReportSubmit } From 90d28b0876bfae8724f866ac935df303ef19dfac Mon Sep 17 00:00:00 2001 From: Angran Li Date: Mon, 19 May 2025 19:10:18 +0000 Subject: [PATCH 11/15] Fix unit test --- flow360/plugins/report/report.py | 3 --- tests/data/mock_webapi/report_meta_resp.json | 28 +++++++++++--------- tests/mock_server.py | 4 +-- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/flow360/plugins/report/report.py b/flow360/plugins/report/report.py index 941f28730..33a2dda43 100644 --- a/flow360/plugins/report/report.py +++ b/flow360/plugins/report/report.py @@ -131,9 +131,6 @@ def submit( solver_version=solver_version, ) resp = cls._webapi.post(json=request.dict()) - print("AAAAAAAAAAAAAAAAAA",resp) - from flow360.log import log - log.info(f"Report draft response: {resp}") return Report(resp["id"]) diff --git a/tests/data/mock_webapi/report_meta_resp.json b/tests/data/mock_webapi/report_meta_resp.json index 114b74818..9b97ddd21 100644 --- a/tests/data/mock_webapi/report_meta_resp.json +++ b/tests/data/mock_webapi/report_meta_resp.json @@ -1,15 +1,17 @@ { - "userId": "AIDAU77I6BZ2QYZLLVSRW", - "id": "rep-00508a80-2566-45bf-9572-56228a3161fd", - "status": "submitted", - "name": "ResultSummary", - "resources": [ - { - "type": "Case", - "id": "case-f813742a-61d3-497c-8447-3ac8b0c997f1", - "rawData": null - } - ], - "createdAt": "2025-05-19T18:30:51.476347Z", - "updatedAt": "2025-05-19T18:30:51.476347Z" + "data": { + "userId": "AIDAU77I6BZ2QYZLLVSRW", + "id": "rep-00508a80-2566-45bf-9572-56228a3161fd", + "status": "submitted", + "name": "ResultSummary", + "resources": [ + { + "type": "Case", + "id": "case-f813742a-61d3-497c-8447-3ac8b0c997f1", + "rawData": null + } + ], + "createdAt": "2025-05-19T18:30:51.476347Z", + "updatedAt": "2025-05-19T18:30:51.476347Z" + } } \ No newline at end of file diff --git a/tests/mock_server.py b/tests/mock_server.py index 9b39113e2..8d5792947 100644 --- a/tests/mock_server.py +++ b/tests/mock_server.py @@ -533,9 +533,9 @@ class MockResponseReportSubmit(MockResponse): def json(): with open(os.path.join(here, "data/mock_webapi/report_meta_resp.json")) as fh: res = json.load(fh) - print(res) return res + GET_RESPONSE_MAP = { "/volumemeshes/00112233-4455-6677-8899-aabbccddeeff": MockResponseVolumeMesh, "/volumemeshes/00000000-0000-0000-0000-000000000000": MockResponseVolumeMesh, @@ -584,7 +584,7 @@ def json(): "/v2/drafts/vm-7c3681cd-8c6c-4db7-a62c-1742d825e9d3/run": MockResponseProjectVolumeMesh, "/v2/drafts/case-84d4604e-f3cd-4c6b-8517-92a80a3346d3/simulation/file": MockResponseProjectCaseForkSimConfig, "/v2/drafts/case-84d4604e-f3cd-4c6b-8517-92a80a3346d3/run": MockResponseProjectCaseFork, - "/v2/report":MockResponseReportSubmit + "/v2/report": MockResponseReportSubmit, } From 87385914b1f5127b2fd5fc4536317b4e4647a208 Mon Sep 17 00:00:00 2001 From: Angran Li Date: Tue, 20 May 2025 01:35:17 +0000 Subject: [PATCH 12/15] Address comment --- flow360/component/project.py | 16 ++++++-------- flow360/component/simulation/services.py | 4 ++-- flow360/plugins/report/report.py | 4 ++-- flow360/plugins/report/report_items.py | 1 + .../service/ref/default_report_config.json | 22 +++++++++---------- tests/simulation/service/test_services_v2.py | 2 -- 6 files changed, 23 insertions(+), 26 deletions(-) diff --git a/flow360/component/project.py b/flow360/component/project.py index 1bdf82392..e40641e66 100644 --- a/flow360/component/project.py +++ b/flow360/component/project.py @@ -48,7 +48,7 @@ from flow360.component.volume_mesh import VolumeMeshV2 from flow360.exceptions import Flow360FileError, Flow360ValueError, Flow360WebError from flow360.log import log -from flow360.plugins.report.report import get_default_report_template +from flow360.plugins.report.report import get_default_report_summary_template from flow360.version import __solver_version__ AssetOrResource = Union[type[AssetBase], type[Flow360Resource]] @@ -1358,14 +1358,6 @@ def _run( log.info(f"Successfully submitted: {destination_obj.short_description()}") - if isinstance(destination_obj, Case): - report_template = get_default_report_template() - report_template.create_in_cloud( - name="ResultSummary", - cases=[destination_obj], - solver_version=solver_version if solver_version else self.solver_version, - ) - if not run_async: destination_obj.wait() @@ -1560,4 +1552,10 @@ def run_case( tags=tags, **kwargs, ) + report_template = get_default_report_summary_template() + report_template.create_in_cloud( + name="ResultSummary", + cases=[case], + solver_version=solver_version if solver_version else self.solver_version, + ) return case diff --git a/flow360/component/simulation/services.py b/flow360/component/simulation/services.py index 243285d0c..4a461170e 100644 --- a/flow360/component/simulation/services.py +++ b/flow360/component/simulation/services.py @@ -55,7 +55,7 @@ ValidationContext, ) from flow360.exceptions import Flow360RuntimeError, Flow360TranslationError -from flow360.plugins.report.report import get_default_report_template +from flow360.plugins.report.report import get_default_report_summary_template from flow360.version import __version__ unit_system_map = { @@ -775,6 +775,6 @@ def get_default_report_config() -> dict: dict default report config """ - return get_default_report_template().model_dump( + return get_default_report_summary_template().model_dump( exclude_none=True, ) diff --git a/flow360/plugins/report/report.py b/flow360/plugins/report/report.py index 33a2dda43..9107dc706 100644 --- a/flow360/plugins/report/report.py +++ b/flow360/plugins/report/report.py @@ -323,7 +323,7 @@ def create_pdf( report_doc.generate_pdf(os.path.join(data_storage, filename)) -def get_default_report_template() -> ReportTemplate: +def get_default_report_summary_template() -> ReportTemplate: """ Returns default report template for result summary. """ @@ -356,6 +356,6 @@ def get_default_report_template() -> ReportTemplate: "CMy", "CMz", ] - formatter = [".4f" for _ in data] + formatter = [".e" for _ in data] table = Table(data=data, section_title="result_summary", headers=headers, formatter=formatter) return ReportTemplate(items=[table], settings=Settings(dump_table_csv=True)) diff --git a/flow360/plugins/report/report_items.py b/flow360/plugins/report/report_items.py index c6a2c9b30..7688a9d78 100644 --- a/flow360/plugins/report/report_items.py +++ b/flow360/plugins/report/report_items.py @@ -109,6 +109,7 @@ class Settings(Flow360BaseModel): If not specified, defaults to 300. """ + # TODO: Create a setting class for each type of report items. dpi: Optional[pd.PositiveInt] = 300 dump_table_csv: Optional[pd.StrictBool] = False diff --git a/tests/simulation/service/ref/default_report_config.json b/tests/simulation/service/ref/default_report_config.json index 97ce07c47..5250fd37f 100644 --- a/tests/simulation/service/ref/default_report_config.json +++ b/tests/simulation/service/ref/default_report_config.json @@ -90,17 +90,17 @@ ], "type_name": "Table", "formatter": [ - ".4f", - ".4f", - ".4f", - ".4f", - ".4f", - ".4f", - ".4f", - ".4f", - ".4f", - ".4f", - ".4f" + ".e", + ".e", + ".e", + ".e", + ".e", + ".e", + ".e", + ".e", + ".e", + ".e", + ".e" ] } ], diff --git a/tests/simulation/service/test_services_v2.py b/tests/simulation/service/test_services_v2.py index 30f10b4f7..1e0beebac 100644 --- a/tests/simulation/service/test_services_v2.py +++ b/tests/simulation/service/test_services_v2.py @@ -1264,6 +1264,4 @@ def test_get_default_report_config_json(): report_config_dict = services.get_default_report_config() with open("ref/default_report_config.json", "r") as fp: ref_dict = json.load(fp) - print(report_config_dict) - print(ref_dict) assert compare_values(report_config_dict, ref_dict) From 97fc5e5ad77327980e24eae03d0cd7b12f78ba04 Mon Sep 17 00:00:00 2001 From: Angran Li Date: Tue, 20 May 2025 01:38:09 +0000 Subject: [PATCH 13/15] Fix format --- flow360/plugins/report/report_items.py | 1 + 1 file changed, 1 insertion(+) diff --git a/flow360/plugins/report/report_items.py b/flow360/plugins/report/report_items.py index 7688a9d78..269930500 100644 --- a/flow360/plugins/report/report_items.py +++ b/flow360/plugins/report/report_items.py @@ -109,6 +109,7 @@ class Settings(Flow360BaseModel): If not specified, defaults to 300. """ + #pylint: disable=fixme # TODO: Create a setting class for each type of report items. dpi: Optional[pd.PositiveInt] = 300 dump_table_csv: Optional[pd.StrictBool] = False From ef10f47a3a5f4a67c2920a45da3a5415d899c98b Mon Sep 17 00:00:00 2001 From: Angran Li Date: Tue, 20 May 2025 01:39:39 +0000 Subject: [PATCH 14/15] Fix format --- flow360/plugins/report/report_items.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flow360/plugins/report/report_items.py b/flow360/plugins/report/report_items.py index 269930500..646d654f0 100644 --- a/flow360/plugins/report/report_items.py +++ b/flow360/plugins/report/report_items.py @@ -109,7 +109,7 @@ class Settings(Flow360BaseModel): If not specified, defaults to 300. """ - #pylint: disable=fixme + # pylint: disable=fixme # TODO: Create a setting class for each type of report items. dpi: Optional[pd.PositiveInt] = 300 dump_table_csv: Optional[pd.StrictBool] = False From a197e2b63ba8d0de4e411e7fa81d050843c8641b Mon Sep 17 00:00:00 2001 From: Angran Li Date: Tue, 20 May 2025 14:12:30 +0000 Subject: [PATCH 15/15] More comments to address --- flow360/plugins/report/report.py | 4 +--- .../service/ref/default_report_config.json | 22 +++++++++---------- tests/simulation/service/test_services_v2.py | 2 +- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/flow360/plugins/report/report.py b/flow360/plugins/report/report.py index 9107dc706..c3f632ad4 100644 --- a/flow360/plugins/report/report.py +++ b/flow360/plugins/report/report.py @@ -342,7 +342,6 @@ def get_default_report_summary_template() -> ReportTemplate: DataItem(data="surface_forces/totalCMy", title="CMy", operations=avg), DataItem(data="surface_forces/totalCMz", title="CMz", operations=avg), ] - headers = [ "OAL", "OAH", @@ -356,6 +355,5 @@ def get_default_report_summary_template() -> ReportTemplate: "CMy", "CMz", ] - formatter = [".e" for _ in data] - table = Table(data=data, section_title="result_summary", headers=headers, formatter=formatter) + table = Table(data=data, section_title="result_summary", headers=headers) return ReportTemplate(items=[table], settings=Settings(dump_table_csv=True)) diff --git a/tests/simulation/service/ref/default_report_config.json b/tests/simulation/service/ref/default_report_config.json index 5250fd37f..f4e61d6ba 100644 --- a/tests/simulation/service/ref/default_report_config.json +++ b/tests/simulation/service/ref/default_report_config.json @@ -90,17 +90,17 @@ ], "type_name": "Table", "formatter": [ - ".e", - ".e", - ".e", - ".e", - ".e", - ".e", - ".e", - ".e", - ".e", - ".e", - ".e" + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null ] } ], diff --git a/tests/simulation/service/test_services_v2.py b/tests/simulation/service/test_services_v2.py index 1e0beebac..d35616662 100644 --- a/tests/simulation/service/test_services_v2.py +++ b/tests/simulation/service/test_services_v2.py @@ -1264,4 +1264,4 @@ def test_get_default_report_config_json(): report_config_dict = services.get_default_report_config() with open("ref/default_report_config.json", "r") as fp: ref_dict = json.load(fp) - assert compare_values(report_config_dict, ref_dict) + assert compare_values(report_config_dict, ref_dict, ignore_keys=["formatter"])