Geometry Report#
This script showcases the generation of a simulation report using the Flow360 Python API’s reporting plugin. It involves defining a simulation setup for an airplane geometry, performing a parameter sweep over the angle of attack, and then utilizing various report items like tables, 2D charts, and 3D visualizations to compile the results into a PDF report.
1import flow360 as fl
2from flow360 import u
3from flow360.examples import Airplane
4from flow360.plugins.report.report import ReportTemplate
5from flow360.plugins.report.report_items import (
6 Camera,
7 Chart2D,
8 Chart3D,
9 Inputs,
10 Settings,
11 Summary,
12 Table,
13)
14from flow360.plugins.report.utils import Average, DataItem, Delta
15from flow360.version import __solver_version__
16
17project_id = None # if running for the first time
18
19# then replace it with your project ID to avoid re-creation of projects. You can find project ID on web GUI:
20# project_id = "prj-...."
21
22if project_id is not None:
23 project = fl.Project.from_cloud(project_id)
24else:
25 project = fl.Project.from_geometry(
26 Airplane.geometry, name="Python Project (Geometry, from file) - for Report"
27 )
28
29geo = project.geometry
30geo.group_faces_by_tag("groupName")
31
32
33def simulation_params(angle_of_attack):
34 with fl.SI_unit_system:
35 far_field_zone = fl.AutomatedFarfield()
36 params = fl.SimulationParams(
37 meshing=fl.MeshingParams(
38 defaults=fl.MeshingDefaults(
39 boundary_layer_first_layer_thickness=0.001,
40 surface_max_edge_length=1,
41 ),
42 volume_zones=[far_field_zone],
43 ),
44 reference_geometry=fl.ReferenceGeometry(area=1, moment_length=1),
45 operating_condition=fl.AerospaceCondition(
46 velocity_magnitude=100,
47 alpha=angle_of_attack * fl.u.deg,
48 ),
49 time_stepping=fl.Steady(max_steps=1000),
50 models=[
51 fl.Wall(
52 surfaces=[geo["*"]],
53 ),
54 fl.Freestream(
55 surfaces=[far_field_zone.farfield],
56 ),
57 ],
58 outputs=[
59 fl.SurfaceOutput(
60 surfaces=geo["*"],
61 output_fields=[
62 "Cp",
63 "Cf",
64 "yPlus",
65 "CfVec",
66 "primitiveVars",
67 ],
68 ),
69 ],
70 )
71 return params
72
73
74cases: list[fl.Case] = []
75for alpha in [0, 2, 4]:
76 case = project.run_case(params=simulation_params(alpha), name=f"Case for report, alpha={alpha}")
77 cases.append(case)
78
79[print(case.short_description()) for case in cases]
80
81# waiting explicitly for all the cases to finish (report pipeline will not wait for cases)
82[case.wait() for case in cases]
83
84
85top_camera = Camera(
86 position=(0, 0, 1),
87 look_at=(0, 0, 0),
88 pan_target=(5, 0, 0),
89 up=(0, 1, 0),
90 dimension=15,
91 dimension_dir="width",
92)
93side_camera = Camera(
94 position=(0, -1, 0),
95 look_at=(0, 0, 0),
96 pan_target=(5, 0, 0),
97 up=(0, 0, 1),
98 dimension=12,
99 dimension_dir="width",
100)
101front_left_bottom_camera = Camera(
102 position=(-1, -1, -1),
103 look_at=(0, 0, 0),
104 pan_target=(4, 0, 0),
105 up=(0, 0, 1),
106 dimension=15,
107 dimension_dir="width",
108)
109rear_right_bottom_camera = Camera(
110 position=(1, 1, -1),
111 look_at=(0, 0, 0),
112 pan_target=(4, 0, 0),
113 up=(0, 0, 1),
114 dimension=15,
115 dimension_dir="width",
116)
117
118cameras_geo = [
119 top_camera,
120 side_camera,
121 front_left_bottom_camera,
122 rear_right_bottom_camera,
123]
124
125avg = Average(fraction=0.1)
126
127CD = DataItem(data="surface_forces/totalCD", title="CD", operations=avg)
128
129CL = DataItem(data="surface_forces/totalCL", title="CL", operations=avg)
130
131statistical_data = [
132 "params/reference_geometry/area",
133 CD,
134 CL,
135 Delta(data=CL),
136 "volume_mesh/stats/n_nodes",
137 "params/time_stepping/max_steps",
138]
139statistical_table = Table(
140 data=statistical_data,
141 section_title="Statistical data",
142 formatter=[
143 (
144 None
145 if d
146 in [
147 "params/reference_geometry/area",
148 "volume_mesh/stats/n_nodes",
149 "params/time_stepping/max_steps",
150 ]
151 else ".4f"
152 )
153 for d in statistical_data
154 ],
155)
156
157
158geometry_screenshots = [
159 Chart3D(
160 section_title="Geometry",
161 items_in_row=2,
162 force_new_page=True,
163 show="boundaries",
164 camera=camera,
165 fig_name=f"geo_{i}",
166 )
167 for i, camera in enumerate(cameras_geo)
168]
169
170report = ReportTemplate(
171 title="Geometry to report",
172 items=[
173 Summary(),
174 Inputs(),
175 statistical_table,
176 Chart2D(
177 x="surface_forces/pseudo_step",
178 y="surface_forces/totalCL",
179 section_title="Lift Coefficient",
180 fig_name="cl_fig",
181 focus_x=(1 / 3, 1),
182 ),
183 *geometry_screenshots,
184 ],
185 settings=Settings(dpi=150),
186)
187
188
189report = report.create_in_cloud(
190 f"Geometry to report - Report, dpi=150",
191 cases,
192 solver_version=__solver_version__,
193)
194
195report.wait()
196report.download("report.pdf")
Notes#
Multiple simulation cases are executed sequentially, and their completion is explicitly awaited using
case.wait()
before initiating the report generation process.The
ReportTemplate
class orchestrates the report structure, incorporating elements likeTable
,Chart2D
, andChart3D
.Data post-processing, such as averaging force coefficients (
DataItem
withAverage
), can be defined directly within the report configuration.