Skip to content

Commit f5172c8

Browse files
Merge pull request #154 from KratosMultiphysics/potentail_fllow/add_incompresible_example
[POTENTIAL] Add example for incompressible potential flow
2 parents 81f1a26 + 92e6690 commit f5172c8

File tree

9 files changed

+25172
-0
lines changed

9 files changed

+25172
-0
lines changed

potential_flow/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
- [Naca 0012 compressible - sensitivity analysis](https://github.com/KratosMultiphysics/Examples/tree/master/potential_flow/use_cases/sensitivity_analysis_compressible/README.md)
55

66
**Validation**
7+
- [Naca 0012 incompressible potential flow](https://github.com/KratosMultiphysics/Examples/tree/master/potential_flow/validation/naca0012_potential_incompressible_flow/README.md)
78
- [Naca 0012 transonic scheme](https://github.com/KratosMultiphysics/Examples/tree/master/potential_flow/validation/naca0012_transonic_scheme/README.md)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Incompressible Potential Flow
2+
# Naca 0012 airfoil - Mach number = 0.0588, Angle of attack = 5º
3+
4+
**Author:** [Juan Ignacio Camarotti](https://github.com/juancamarotti)
5+
6+
**Kratos version:** 10.4
7+
8+
**Source files:** [Naca 0012 incompressible potential flow](https://github.com/KratosMultiphysics/Examples/tree/master/potential_flow/validation/naca0012_potential_incompressible_flow/source)
9+
10+
## Case Specification
11+
This example presents a two-dimensional simulation of inviscid incompressible flow around a NACA 0012 airfoil using the potential flow solver available in the Kratos CompressiblePotentialFlowApplication.
12+
13+
The flow around the airfoil is computed at AOA=5° and Mach 0.0588. Although the formulation is incompressible, the Mach number is provided to define the free-stream velocity.
14+
15+
The problem geometry consists in a 100[m]x100[m] domain and an airfoil with a chord length of 1[m] at zero degrees angle of attack. The computational domain was meshed with 7920 linear triangular elements (Figure 1).
16+
17+
<p align="center">
18+
<img src="data/Airfoil_geometry.png" style="width: 600px;"/>
19+
<figcaption align="center"> Figure 1: NACA0012 airfoil geometry and domain. </figcaption align="center">
20+
</p>
21+
22+
### Boundary Conditions
23+
The boundary conditions imposed in the far field are:
24+
25+
* Free stream density = 1.225 _kg/m<sup>3</sup>_
26+
* Angle of attack = 5º
27+
* Mach infinity = 0.0588
28+
* Wake condition is computed automatically by the app
29+
* Slip boundary condition on the airfoil surface, enforcing zero normal velocity
30+
31+
## Results
32+
33+
Two snapshots of the pressure coefficient ($C_p$) are shown below: one depicting the distribution along the airfoil surface and another showing the pressure field over the entire computational domain.
34+
35+
Figure 2 presents the pressure coefficient ($C_p$) distribution along the chord of the airfoil.
36+
37+
<p align="center">
38+
<img src="data/Cp_distribution_x.png" alt="Pressure coefficient distribution along the airfoil chord." style="width: 600px;"/>
39+
<figcaption align="center"> Figure 2: Pressure coefficient (Cp) distribution along the chord of the NACA 0012 airfoil. </figcaption>
40+
</p>
41+
42+
Figure 3 shows the spatial distribution of the pressure coefficient over the entire computational domain.
43+
44+
<p align="center">
45+
<img src="data/Cp_distribution_airfoil.png" alt="Pressure coefficient distribution around the NACA 0012 airfoil." style="width: 600px;"/>
46+
<figcaption align="center"> Figure 3: Pressure coefficient (Cp) distribution in the computational domain around the NACA 0012 airfoil. </figcaption>
47+
</p>
48+
49+
The aerodynamic coefficients obtained from the simulation can be compared with reference data using the lift curve shown in Figure 4.
50+
51+
<p align="center">
52+
<img src="data/naca0012_lift_curve.png" alt="NACA 0012 Lift vs AOA Curve" style="width: 600px;"/>
53+
<figcaption align="center"> Figure 4: Reference lift coefficient (Cl) as a function of the angle of attack for the NACA 0012 airfoil. </figcaption>
54+
</p>
55+
56+
For an angle of attack of $\alpha = 5^\circ$, the computed lift coefficient is $C_l = 0.569$. This result shows very good agreement with the reference data presented in Figure 4, which is used here for validation purposes.
57+
58+
## References
59+
(1) https://aerospaceweb.org/question/airfoils/q0259c.shtml
60+
1.05 MB
Loading
67.4 KB
Loading
181 KB
Loading
13.8 KB
Loading
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import sys
2+
import time
3+
import importlib
4+
import numpy as np
5+
import matplotlib.pyplot as plt
6+
7+
import KratosMultiphysics
8+
9+
10+
def CreateAnalysisStageWithFlushInstance(cls, global_model, parameters):
11+
class AnalysisStageWithFlush(cls):
12+
13+
def __init__(self, model, project_parameters, flush_frequency=10.0):
14+
super().__init__(model, project_parameters)
15+
self.flush_frequency = flush_frequency
16+
self.last_flush = time.time()
17+
sys.stdout.flush()
18+
19+
def Initialize(self):
20+
super().Initialize()
21+
sys.stdout.flush()
22+
23+
def FinalizeSolutionStep(self):
24+
super().FinalizeSolutionStep()
25+
26+
if self.parallel_type == "OpenMP":
27+
now = time.time()
28+
if now - self.last_flush > self.flush_frequency:
29+
sys.stdout.flush()
30+
self.last_flush = now
31+
32+
return AnalysisStageWithFlush(global_model, parameters)
33+
34+
35+
if __name__ == "__main__":
36+
37+
with open("ProjectParameters.json", 'r') as parameter_file:
38+
parameters = KratosMultiphysics.Parameters(parameter_file.read())
39+
40+
analysis_stage_module_name = parameters["analysis_stage"].GetString()
41+
analysis_stage_class_name = analysis_stage_module_name.split('.')[-1]
42+
analysis_stage_class_name = ''.join(x.title() for x in analysis_stage_class_name.split('_'))
43+
44+
analysis_stage_module = importlib.import_module(analysis_stage_module_name)
45+
analysis_stage_class = getattr(analysis_stage_module, analysis_stage_class_name)
46+
47+
# Create model and run simulation
48+
global_model = KratosMultiphysics.Model()
49+
simulation = CreateAnalysisStageWithFlushInstance(analysis_stage_class, global_model, parameters)
50+
simulation.Run()
51+
52+
# Extract Cp
53+
modelpart = global_model["FluidModelPart.Body2D_Body"]
54+
55+
upper_x = []
56+
upper_cp = []
57+
lower_x = []
58+
lower_cp = []
59+
60+
for node in modelpart.Nodes:
61+
x = node.X0
62+
y = node.Y0
63+
cp = node.GetValue(KratosMultiphysics.PRESSURE_COEFFICIENT)
64+
65+
if y >= 0.0:
66+
upper_x.append(x)
67+
upper_cp.append(cp)
68+
else:
69+
lower_x.append(x)
70+
lower_cp.append(cp)
71+
72+
# convert to numpy
73+
upper_x = np.array(upper_x)
74+
upper_cp = np.array(upper_cp)
75+
lower_x = np.array(lower_x)
76+
lower_cp = np.array(lower_cp)
77+
78+
# sort along chord
79+
upper_order = np.argsort(upper_x)
80+
lower_order = np.argsort(lower_x)
81+
82+
upper_x = upper_x[upper_order]
83+
upper_cp = upper_cp[upper_order]
84+
85+
lower_x = lower_x[lower_order]
86+
lower_cp = lower_cp[lower_order]
87+
88+
# Plot
89+
fig, ax = plt.subplots()
90+
fig.set_figwidth(8)
91+
fig.set_figheight(6)
92+
93+
ax.plot(upper_x, -upper_cp, "o", label="Upper surface")
94+
ax.plot(lower_x, -lower_cp, "o", label="Lower surface")
95+
96+
ax.set_xlabel("x/c")
97+
ax.set_ylabel("-Cp")
98+
ax.set_title("NACA0012 Potential Flow")
99+
ax.grid()
100+
101+
# aerodynamic convention
102+
ax.invert_yaxis()
103+
104+
ax.legend()
105+
plt.tight_layout()
106+
plt.savefig("Cp_distribution.png", dpi=400)
107+
plt.show()
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
{
2+
"analysis_stage" : "KratosMultiphysics.CompressiblePotentialFlowApplication.potential_flow_analysis",
3+
"problem_data" : {
4+
"problem_name" : "naca0012_2D",
5+
"parallel_type" : "OpenMP",
6+
"echo_level" : 0,
7+
"start_time" : 0.0,
8+
"end_time" : 1.0
9+
},
10+
"output_processes" : {
11+
"gid_output" : [{
12+
"python_module" : "gid_output_process",
13+
"kratos_module" : "KratosMultiphysics",
14+
"process_name" : "GiDOutputProcess",
15+
"Parameters" : {
16+
"model_part_name" : "FluidModelPart",
17+
"postprocess_parameters" : {
18+
"result_file_configuration" : {
19+
"gidpost_flags" : {
20+
"GiDPostMode" : "GiD_PostBinary",
21+
"WriteDeformedMeshFlag" : "WriteDeformed",
22+
"WriteConditionsFlag" : "WriteConditions",
23+
"MultiFileFlag" : "SingleFile"
24+
},
25+
"file_label" : "step",
26+
"output_control_type" : "step",
27+
"output_interval" : 1,
28+
"body_output" : true,
29+
"node_output" : false,
30+
"skin_output" : false,
31+
"plane_output" : [],
32+
"nodal_results" : ["VELOCITY_POTENTIAL","AUXILIARY_VELOCITY_POTENTIAL"],
33+
"nodal_nonhistorical_results" : ["PRESSURE_COEFFICIENT","VELOCITY","DENSITY"],
34+
"gauss_point_results" : ["MACH","DENSITY","TEMPERATURE"]
35+
},
36+
"point_data_configuration" : []
37+
},
38+
"output_name" : "gid_output/naca0012_2D"
39+
}
40+
}]
41+
,
42+
"vtk_output" : [{
43+
"python_module" : "vtk_output_process",
44+
"kratos_module" : "KratosMultiphysics",
45+
"process_name" : "VtkOutputProcess",
46+
"help" : "This process writes postprocessing files for Paraview",
47+
"Parameters" : {
48+
"model_part_name" : "FluidModelPart",
49+
"output_control_type" : "step",
50+
"output_interval" : 1,
51+
"file_format" : "binary",
52+
"output_precision" : 7,
53+
"output_sub_model_parts" : true,
54+
"output_path" : "vtk_output",
55+
"save_output_files_in_folder" : true,
56+
"nodal_solution_step_data_variables" : ["VELOCITY_POTENTIAL","AUXILIARY_VELOCITY_POTENTIAL"],
57+
"nodal_data_value_variables" : ["PRESSURE_COEFFICIENT","VELOCITY","DENSITY",
58+
"MACH","POTENTIAL_JUMP","TRAILING_EDGE","WAKE_DISTANCE","WING_TIP"],
59+
"element_data_value_variables" : ["WAKE","KUTTA"],
60+
"gauss_point_variables_in_elements" : ["PRESSURE_COEFFICIENT","VELOCITY","MACH"],
61+
"condition_data_value_variables" : []
62+
}
63+
}]
64+
},
65+
"solver_settings" : {
66+
"model_part_name" : "FluidModelPart",
67+
"domain_size" : 2,
68+
"solver_type" : "potential_flow",
69+
"model_import_settings" : {
70+
"input_type" : "mdpa",
71+
"input_filename" : "naca0012"
72+
},
73+
"formulation": {
74+
"element_type": "incompressible"
75+
},
76+
"scheme_settings" : {
77+
"is_transonic" : false
78+
,
79+
"initial_critical_mach" : 0.0,
80+
"initial_upwind_factor_constant": 0.0,
81+
"target_critical_mach" : 0.0,
82+
"target_upwind_factor_constant" : 0.0,
83+
"update_relative_residual_norm" : 0.0,
84+
"mach_number_squared_limit" : 0.0
85+
},
86+
"maximum_iterations" : 30,
87+
"compute_reactions": true,
88+
"echo_level" : 2,
89+
"relative_tolerance" : 1e-8,
90+
"absolute_tolerance" : 1e-8,
91+
"solving_strategy_settings" : {
92+
"type" : "line_search",
93+
"advanced_settings": {
94+
"first_alpha_value" : 0.5,
95+
"second_alpha_value" : 1.0,
96+
"min_alpha" : 0.5,
97+
"max_alpha" : 1.0,
98+
"line_search_tolerance" : 0.5,
99+
"max_line_search_iterations": 5
100+
}
101+
},
102+
"linear_solver_settings" : {
103+
"solver_type" : "LinearSolversApplication.pardiso_lu"
104+
},
105+
"volume_model_part_name" : "Parts_Parts_Auto1",
106+
"skin_parts" : ["PotentialWallCondition2D_Far_field_Auto1","Body2D_Body"],
107+
"no_skin_parts" : [],
108+
"reform_dofs_at_each_step" : false,
109+
"auxiliary_variables_list" : []
110+
},
111+
"processes" : {
112+
"boundary_conditions_process_list" : [{
113+
"python_module" : "apply_far_field_and_wake_process",
114+
"kratos_module" : "KratosMultiphysics.CompressiblePotentialFlowApplication",
115+
"process_name" : "ApplyFarFieldAndWakeProcess",
116+
"Parameters" : {
117+
"model_part_name" : "FluidModelPart.PotentialWallCondition2D_Far_field_Auto1",
118+
"angle_of_attack_units": "degrees",
119+
"free_stream_density" : 1.225,
120+
"mach_infinity": 0.0588235,
121+
"angle_of_attack" : 5.0,
122+
"perturbation_field" : false,
123+
"define_wake": true,
124+
"wake_type": "Operations.KratosMultiphysics.CompressiblePotentialFlowApplication.Define2DWakeOperation",
125+
"wake_parameters" : {
126+
"body_model_part_name" : "FluidModelPart.Body2D_Body"
127+
}
128+
}
129+
},{
130+
"python_module" : "compute_nodal_value_process",
131+
"kratos_module" : "KratosMultiphysics.CompressiblePotentialFlowApplication",
132+
"process_name" : "ComputeNodalValueProcess",
133+
"Parameters" : {
134+
"model_part_name" : "FluidModelPart",
135+
"elemental_variables_list_to_project": ["VELOCITY", "PRESSURE_COEFFICIENT"]
136+
}
137+
}
138+
,
139+
{
140+
"python_module" : "compute_lift_process",
141+
"kratos_module" : "KratosMultiphysics.CompressiblePotentialFlowApplication",
142+
"process_name" : "ComputeLiftProcess",
143+
"Parameters" : {
144+
"model_part_name": "FluidModelPart.Body2D_Body",
145+
"moment_reference_point" : [0.0,0.0,0.0],
146+
"mean_aerodynamic_chord" : 1.0,
147+
"far_field_model_part_name": "FluidModelPart.PotentialWallCondition2D_Far_field_Auto1",
148+
"trailing_edge_model_part_name": "FluidModelPart.Body2D_Body",
149+
"is_infinite_wing": false
150+
}
151+
}
152+
],
153+
"auxiliar_process_list" : []
154+
}
155+
}

0 commit comments

Comments
 (0)