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
15
16project_id = None # if running for the first time
17
18# then replace it with your project ID to avoid re-creation of projects. You can find project ID on web GUI:
19# project_id = "prj-...."
20
21if project_id is not None:
22 project = fl.Project.from_cloud(project_id)
23else:
24 project = fl.Project.from_geometry(
25 Airplane.geometry, name="Python Project (Geometry, from file) - for Report"
26 )
27
28geo = project.geometry
29geo.group_faces_by_tag("groupName")
30
31
32def simulation_params(angle_of_attack):
33 with fl.SI_unit_system:
34 far_field_zone = fl.AutomatedFarfield()
35 params = fl.SimulationParams(
36 meshing=fl.MeshingParams(
37 defaults=fl.MeshingDefaults(
38 boundary_layer_first_layer_thickness=0.001,
39 surface_max_edge_length=1,
40 ),
41 volume_zones=[far_field_zone],
42 ),
43 reference_geometry=fl.ReferenceGeometry(area=1, moment_length=1),
44 operating_condition=fl.AerospaceCondition(
45 velocity_magnitude=100,
46 alpha=angle_of_attack * fl.u.deg,
47 ),
48 time_stepping=fl.Steady(max_steps=1000),
49 models=[
50 fl.Wall(
51 surfaces=[geo["*"]],
52 ),
53 fl.Freestream(
54 surfaces=[far_field_zone.farfield],
55 ),
56 ],
57 outputs=[
58 fl.SurfaceOutput(
59 surfaces=geo["*"],
60 output_fields=[
61 "Cp",
62 "Cf",
63 "yPlus",
64 "CfVec",
65 "primitiveVars",
66 ],
67 ),
68 ],
69 )
70 return params
71
72
73cases: list[fl.Case] = []
74for alpha in [0, 2, 4]:
75 case = project.run_case(params=simulation_params(alpha), name=f"Case for report, alpha={alpha}")
76 cases.append(case)
77
78[print(case.short_description()) for case in cases]
79
80# waiting explicitly for all the cases to finish (report pipeline will not wait for cases)
81[case.wait() for case in cases]
82
83
84top_camera = Camera(
85 position=(0, 0, 1),
86 look_at=(0, 0, 0),
87 pan_target=(5, 0, 0),
88 up=(0, 1, 0),
89 dimension=15,
90 dimension_dir="width",
91)
92side_camera = Camera(
93 position=(0, -1, 0),
94 look_at=(0, 0, 0),
95 pan_target=(5, 0, 0),
96 up=(0, 0, 1),
97 dimension=12,
98 dimension_dir="width",
99)
100front_left_bottom_camera = Camera(
101 position=(-1, -1, -1),
102 look_at=(0, 0, 0),
103 pan_target=(4, 0, 0),
104 up=(0, 0, 1),
105 dimension=15,
106 dimension_dir="width",
107)
108rear_right_bottom_camera = Camera(
109 position=(1, 1, -1),
110 look_at=(0, 0, 0),
111 pan_target=(4, 0, 0),
112 up=(0, 0, 1),
113 dimension=15,
114 dimension_dir="width",
115)
116
117cameras_geo = [
118 top_camera,
119 side_camera,
120 front_left_bottom_camera,
121 rear_right_bottom_camera,
122]
123
124avg = Average(fraction=0.1)
125
126CL = DataItem(data="surface_forces/totalCL", title="CL", operations=avg)
127
128CD = DataItem(data="surface_forces/totalCD", title="CD", operations=avg)
129
130statistical_data = [
131 "params/operating_condition/alpha",
132 "params/reference_geometry/area",
133 CL,
134 Delta(data=CL),
135 CD,
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
157geometry_screenshots = [
158 Chart3D(
159 section_title="Geometry",
160 items_in_row=2,
161 force_new_page=True,
162 show="boundaries",
163 camera=camera,
164 fig_name=f"geo_{i}",
165 )
166 for i, camera in enumerate(cameras_geo)
167]
168
169report = ReportTemplate(
170 title="Geometry to report",
171 items=[
172 Summary(),
173 Inputs(),
174 statistical_table,
175 Chart2D(
176 x="total_forces/pseudo_step",
177 y="total_forces/CL",
178 section_title="Lift Coefficient",
179 fig_name="cl_fig",
180 focus_x=(1 / 3, 1),
181 ),
182 *geometry_screenshots,
183 ],
184 settings=Settings(dpi=150),
185)
186
187
188report = report.create_in_cloud(
189 f"Geometry to report - Report, dpi=150",
190 cases,
191)
192
193report.wait()
194report.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
ReportTemplateclass orchestrates the report structure, incorporating elements likeTable,Chart2D, andChart3D.Data post-processing, such as averaging force coefficients (
DataItemwithAverage), can be defined directly within the report configuration.