gmshairfoil2d 0.2.2__py3-none-any.whl → 0.2.31__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gmshairfoil2d/__init__.py +3 -0
- gmshairfoil2d/__main__.py +6 -0
- gmshairfoil2d/airfoil_func.py +126 -71
- gmshairfoil2d/config_handler.py +198 -0
- gmshairfoil2d/geometry_def.py +331 -277
- gmshairfoil2d/gmshairfoil2d.py +265 -29
- {gmshairfoil2d-0.2.2.dist-info → gmshairfoil2d-0.2.31.dist-info}/METADATA +108 -19
- gmshairfoil2d-0.2.31.dist-info/RECORD +16 -0
- {gmshairfoil2d-0.2.2.dist-info → gmshairfoil2d-0.2.31.dist-info}/WHEEL +1 -1
- tests/test_airfoil_func.py +52 -1
- tests/test_config_handler.py +260 -0
- tests/test_geometry_def.py +11 -7
- gmshairfoil2d-0.2.2.dist-info/RECORD +0 -13
- {gmshairfoil2d-0.2.2.dist-info → gmshairfoil2d-0.2.31.dist-info}/entry_points.txt +0 -0
- {gmshairfoil2d-0.2.2.dist-info → gmshairfoil2d-0.2.31.dist-info}/licenses/LICENSE +0 -0
- {gmshairfoil2d-0.2.2.dist-info → gmshairfoil2d-0.2.31.dist-info}/top_level.txt +0 -0
gmshairfoil2d/geometry_def.py
CHANGED
|
@@ -1,152 +1,118 @@
|
|
|
1
1
|
"""
|
|
2
|
-
This
|
|
2
|
+
This module contains the definition of geometrical objects needed to build the geometry.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import math
|
|
6
|
+
import sys
|
|
5
7
|
from operator import attrgetter
|
|
8
|
+
|
|
6
9
|
import gmsh
|
|
7
10
|
import numpy as np
|
|
8
|
-
import math
|
|
9
|
-
import sys
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class Point:
|
|
13
|
-
"""
|
|
14
|
-
A class to represent the point geometrical object of gmsh
|
|
15
|
-
|
|
16
|
-
...
|
|
14
|
+
"""A class to represent a point geometrical object in gmsh.
|
|
17
15
|
|
|
18
16
|
Attributes
|
|
19
17
|
----------
|
|
20
18
|
x : float
|
|
21
|
-
|
|
19
|
+
Position in x
|
|
22
20
|
y : float
|
|
23
|
-
|
|
21
|
+
Position in y
|
|
24
22
|
z : float
|
|
25
|
-
|
|
23
|
+
Position in z
|
|
26
24
|
mesh_size : float
|
|
27
|
-
|
|
28
|
-
at that point
|
|
25
|
+
Meshing constraint size at this point (if > 0)
|
|
29
26
|
"""
|
|
30
27
|
|
|
31
28
|
def __init__(self, x, y, z, mesh_size):
|
|
32
|
-
|
|
33
29
|
self.x = x
|
|
34
30
|
self.y = y
|
|
35
31
|
self.z = z
|
|
36
32
|
self.mesh_size = mesh_size
|
|
37
33
|
self.dim = 0
|
|
38
|
-
|
|
39
34
|
# create the gmsh object and store the tag of the geometric object
|
|
40
|
-
self.tag = gmsh.model.geo.addPoint(
|
|
41
|
-
self.x, self.y, self.z, self.mesh_size)
|
|
35
|
+
self.tag = gmsh.model.geo.addPoint(self.x, self.y, self.z, self.mesh_size)
|
|
42
36
|
|
|
43
37
|
def rotation(self, angle, origin, axis):
|
|
44
|
-
"""
|
|
45
|
-
|
|
46
|
-
...
|
|
38
|
+
"""Rotate the point around an axis.
|
|
39
|
+
|
|
47
40
|
Parameters
|
|
48
41
|
----------
|
|
49
42
|
angle : float
|
|
50
|
-
|
|
43
|
+
Angle of rotation in radians
|
|
51
44
|
origin : tuple
|
|
52
|
-
|
|
45
|
+
Tuple of (x, y, z) defining the rotation origin
|
|
53
46
|
axis : tuple
|
|
54
|
-
|
|
47
|
+
Tuple of (x, y, z) defining the rotation axis
|
|
55
48
|
"""
|
|
56
|
-
gmsh.model.geo.rotate(
|
|
57
|
-
[(self.dim, self.tag)],
|
|
58
|
-
*origin,
|
|
59
|
-
*axis,
|
|
60
|
-
angle,
|
|
61
|
-
)
|
|
49
|
+
gmsh.model.geo.rotate([(self.dim, self.tag)], *origin, *axis, angle)
|
|
62
50
|
|
|
63
51
|
def translation(self, vector):
|
|
64
|
-
"""
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
...
|
|
68
|
-
|
|
52
|
+
"""Translate the point.
|
|
53
|
+
|
|
69
54
|
Parameters
|
|
70
55
|
----------
|
|
71
|
-
|
|
72
|
-
|
|
56
|
+
vector : tuple
|
|
57
|
+
Tuple of (x, y, z) defining the translation vector
|
|
73
58
|
"""
|
|
74
59
|
gmsh.model.geo.translate([(self.dim, self.tag)], *vector)
|
|
75
60
|
|
|
76
61
|
|
|
77
62
|
class Line:
|
|
78
|
-
"""
|
|
79
|
-
A class to represent the Line geometrical object of gmsh
|
|
80
|
-
|
|
81
|
-
...
|
|
63
|
+
"""A class to represent a line geometrical object in gmsh.
|
|
82
64
|
|
|
83
65
|
Attributes
|
|
84
66
|
----------
|
|
85
67
|
start_point : Point
|
|
86
|
-
|
|
68
|
+
First point of the line
|
|
87
69
|
end_point : Point
|
|
88
|
-
|
|
70
|
+
Second point of the line
|
|
89
71
|
"""
|
|
90
72
|
|
|
91
73
|
def __init__(self, start_point, end_point):
|
|
92
74
|
self.start_point = start_point
|
|
93
75
|
self.end_point = end_point
|
|
94
|
-
|
|
95
76
|
self.dim = 1
|
|
96
|
-
|
|
97
77
|
# create the gmsh object and store the tag of the geometric object
|
|
98
|
-
self.tag = gmsh.model.geo.addLine(
|
|
99
|
-
self.start_point.tag, self.end_point.tag)
|
|
78
|
+
self.tag = gmsh.model.geo.addLine(self.start_point.tag, self.end_point.tag)
|
|
100
79
|
|
|
101
80
|
def rotation(self, angle, origin, axis):
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
...
|
|
105
|
-
|
|
81
|
+
"""Rotate the line around an axis.
|
|
82
|
+
|
|
106
83
|
Parameters
|
|
107
84
|
----------
|
|
108
85
|
angle : float
|
|
109
|
-
|
|
86
|
+
Angle of rotation in radians
|
|
110
87
|
origin : tuple
|
|
111
|
-
|
|
88
|
+
Tuple of (x, y, z) defining the rotation origin
|
|
112
89
|
axis : tuple
|
|
113
|
-
|
|
90
|
+
Tuple of (x, y, z) defining the rotation axis
|
|
114
91
|
"""
|
|
115
|
-
gmsh.model.geo.rotate(
|
|
116
|
-
[(self.dim, self.tag)],
|
|
117
|
-
*origin,
|
|
118
|
-
*axis,
|
|
119
|
-
angle,
|
|
120
|
-
)
|
|
92
|
+
gmsh.model.geo.rotate([(self.dim, self.tag)], *origin, *axis, angle)
|
|
121
93
|
|
|
122
94
|
def translation(self, vector):
|
|
123
|
-
"""
|
|
124
|
-
|
|
125
|
-
...
|
|
126
|
-
|
|
95
|
+
"""Translate the line.
|
|
96
|
+
|
|
127
97
|
Parameters
|
|
128
98
|
----------
|
|
129
|
-
|
|
130
|
-
|
|
99
|
+
vector : tuple
|
|
100
|
+
Tuple of (x, y, z) defining the translation vector
|
|
131
101
|
"""
|
|
132
102
|
gmsh.model.geo.translate([(self.dim, self.tag)], *vector)
|
|
133
103
|
|
|
134
104
|
|
|
135
105
|
class Spline:
|
|
136
|
-
"""
|
|
137
|
-
A class to represent the Spine geometrical object of gmsh
|
|
138
|
-
|
|
139
|
-
...
|
|
106
|
+
"""A class to represent a Spline geometrical object in gmsh.
|
|
140
107
|
|
|
141
108
|
Attributes
|
|
142
109
|
----------
|
|
143
|
-
|
|
144
|
-
|
|
110
|
+
point_list : list of Point
|
|
111
|
+
List of Point objects forming the Spline
|
|
145
112
|
"""
|
|
146
113
|
|
|
147
114
|
def __init__(self, point_list):
|
|
148
115
|
self.point_list = point_list
|
|
149
|
-
|
|
150
116
|
# generate the Lines tag list to follow
|
|
151
117
|
self.tag_list = [point.tag for point in self.point_list]
|
|
152
118
|
self.dim = 1
|
|
@@ -154,48 +120,36 @@ class Spline:
|
|
|
154
120
|
self.tag = gmsh.model.geo.addSpline(self.tag_list)
|
|
155
121
|
|
|
156
122
|
def rotation(self, angle, origin, axis):
|
|
157
|
-
"""
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
...
|
|
162
|
-
|
|
123
|
+
"""Rotate the spline around an axis.
|
|
124
|
+
|
|
125
|
+
Rotates the spline curve and all intermediate points.
|
|
126
|
+
|
|
163
127
|
Parameters
|
|
164
128
|
----------
|
|
165
129
|
angle : float
|
|
166
|
-
|
|
130
|
+
Angle of rotation in radians
|
|
167
131
|
origin : tuple
|
|
168
|
-
|
|
132
|
+
Tuple of (x, y, z) defining the rotation origin
|
|
169
133
|
axis : tuple
|
|
170
|
-
|
|
134
|
+
Tuple of (x, y, z) defining the rotation axis
|
|
171
135
|
"""
|
|
172
|
-
gmsh.model.geo.rotate(
|
|
173
|
-
|
|
174
|
-
*origin,
|
|
175
|
-
*axis,
|
|
176
|
-
angle,
|
|
177
|
-
)
|
|
178
|
-
|
|
179
|
-
[
|
|
136
|
+
gmsh.model.geo.rotate([(self.dim, self.tag)], *origin, *axis, angle)
|
|
137
|
+
for interm_point in self.point_list[1:-1]:
|
|
180
138
|
interm_point.rotation(angle, origin, axis)
|
|
181
|
-
for interm_point in self.point_list[1:-1]
|
|
182
|
-
]
|
|
183
139
|
|
|
184
140
|
def translation(self, vector):
|
|
185
|
-
"""
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
...
|
|
190
|
-
|
|
141
|
+
"""Translate the spline.
|
|
142
|
+
|
|
143
|
+
Translates the spline curve and all intermediate points.
|
|
144
|
+
|
|
191
145
|
Parameters
|
|
192
146
|
----------
|
|
193
|
-
|
|
194
|
-
|
|
147
|
+
vector : tuple
|
|
148
|
+
Tuple of (x, y, z) defining the translation vector
|
|
195
149
|
"""
|
|
196
150
|
gmsh.model.geo.translate([(self.dim, self.tag)], *vector)
|
|
197
|
-
|
|
198
|
-
|
|
151
|
+
for interm_point in self.point_list[1:-1]:
|
|
152
|
+
interm_point.translation(vector)
|
|
199
153
|
|
|
200
154
|
|
|
201
155
|
class CurveLoop:
|
|
@@ -606,11 +560,12 @@ class AirfoilSpline:
|
|
|
606
560
|
boundary condition
|
|
607
561
|
"""
|
|
608
562
|
|
|
609
|
-
def __init__(self, point_cloud, mesh_size, name=
|
|
563
|
+
def __init__(self, point_cloud, mesh_size, name, is_flap=False):
|
|
610
564
|
|
|
611
565
|
self.name = name
|
|
612
566
|
self.dim = 1
|
|
613
567
|
self.mesh_size = mesh_size
|
|
568
|
+
self.is_flap = is_flap
|
|
614
569
|
|
|
615
570
|
# Generate Points object from the point_cloud
|
|
616
571
|
self.points = [
|
|
@@ -630,11 +585,17 @@ class AirfoilSpline:
|
|
|
630
585
|
vertical = False
|
|
631
586
|
# If two (in the end) are so close in coordinate x, they are vertical and not just neighbouring point (examples below)
|
|
632
587
|
# Just need to check if the one before or after and then label them correctly
|
|
633
|
-
|
|
588
|
+
# Tollerance is the distance between the two points, might be necessary to change it
|
|
589
|
+
if is_flap:
|
|
590
|
+
tollerance = 0.001
|
|
591
|
+
else:
|
|
592
|
+
tollerance = 0.0001
|
|
593
|
+
|
|
594
|
+
if self.points[self.te_indx-1].x > self.te.x-tollerance:
|
|
634
595
|
te_up_indx = self.te_indx-1
|
|
635
596
|
te_down_indx = self.te_indx
|
|
636
597
|
vertical = True
|
|
637
|
-
elif self.points[self.te_indx+1].x > self.te.x-
|
|
598
|
+
elif self.points[self.te_indx+1].x > self.te.x-tollerance:
|
|
638
599
|
te_up_indx = self.te_indx
|
|
639
600
|
te_down_indx = self.te_indx+1
|
|
640
601
|
vertical = True
|
|
@@ -694,37 +655,66 @@ class AirfoilSpline:
|
|
|
694
655
|
|
|
695
656
|
def gen_skin(self):
|
|
696
657
|
"""
|
|
697
|
-
Method to generate the three splines forming the foil
|
|
698
|
-
of the airfoil are in their final position
|
|
658
|
+
Method to generate the three splines forming the foil.
|
|
659
|
+
Only call this function when the points of the airfoil are in their final position.
|
|
660
|
+
|
|
661
|
+
For airfoils: discretizes into upper, lower, and front splines based on x=0.05 threshold.
|
|
662
|
+
For flaps: discretizes into upper, lower, and front splines based on proximity to leading edge.
|
|
699
663
|
-------
|
|
700
664
|
"""
|
|
701
|
-
# Find the first point after 0.049 in the upper band lower spline
|
|
702
|
-
debut = True
|
|
703
|
-
for p in self.points:
|
|
704
|
-
if p.x > 0.049 and debut:
|
|
705
|
-
k1 = self.points.index(p)
|
|
706
|
-
debut = False
|
|
707
|
-
if p.x <= 0.049 and not debut:
|
|
708
|
-
k2 = self.points.index(p)-1
|
|
709
|
-
break
|
|
710
665
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
self.points
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
666
|
+
if getattr(self, "is_flap", False):
|
|
667
|
+
# For flap: find the leading edge and trailing edge
|
|
668
|
+
le_index = min(enumerate(self.points), key=lambda x: x[1].x)[0]
|
|
669
|
+
te_index = max(enumerate(self.points), key=lambda x: x[1].x)[0]
|
|
670
|
+
|
|
671
|
+
n = len(self.points)
|
|
672
|
+
# Define front region width (approximately 10% of total points, at least 3)
|
|
673
|
+
front_width = max(3, n // 10)
|
|
674
|
+
k1 = (le_index - front_width // 2) % n
|
|
675
|
+
k2 = (le_index + front_width // 2) % n
|
|
676
|
+
|
|
677
|
+
# For a flap, points typically go: TE -> lower surface -> LE -> upper surface -> TE
|
|
678
|
+
# Create continuous splines that form a closed loop:
|
|
679
|
+
# lower: TE to LE, front: LE region, upper: LE to TE
|
|
680
|
+
|
|
681
|
+
if te_index < le_index:
|
|
682
|
+
# Normal case: TE is before LE
|
|
683
|
+
# Lower: from TE to k1 (before LE front region)
|
|
684
|
+
# Front: from k1 to k2 around LE
|
|
685
|
+
# Upper: from k2 (after LE front region) to TE
|
|
686
|
+
self.lower_spline = Spline(self.points[te_index:k1+1])
|
|
687
|
+
self.front_spline = Spline(self.points[k1:k2+1])
|
|
688
|
+
self.upper_spline = Spline(self.points[k2:] + self.points[:te_index+1])
|
|
689
|
+
else:
|
|
690
|
+
# TE is after LE (wraps around)
|
|
691
|
+
# Lower: from TE to k1 (wrapping)
|
|
692
|
+
# Front: from k1 to k2 around LE
|
|
693
|
+
# Upper: from k2 to TE
|
|
694
|
+
self.lower_spline = Spline(self.points[te_index:] + self.points[:k1+1])
|
|
695
|
+
self.front_spline = Spline(self.points[k1:k2+1])
|
|
696
|
+
self.upper_spline = Spline(self.points[k2:te_index+1])
|
|
719
697
|
|
|
720
|
-
|
|
721
|
-
|
|
698
|
+
else:
|
|
699
|
+
# For regular airfoils: find points at x > 0.05
|
|
700
|
+
debut = True
|
|
701
|
+
for p in self.points:
|
|
702
|
+
if p.x > 0.049 and debut:
|
|
703
|
+
k1 = self.points.index(p)
|
|
704
|
+
debut = False
|
|
705
|
+
if p.x <= 0.049 and not debut:
|
|
706
|
+
k2 = self.points.index(p)-1
|
|
707
|
+
break
|
|
708
|
+
|
|
709
|
+
self.upper_spline = Spline(self.points[k1: self.te_indx + 1])
|
|
710
|
+
self.lower_spline = Spline(self.points[self.te_indx:k2+1])
|
|
711
|
+
self.front_spline = Spline(self.points[k2:] + self.points[:k1 + 1])
|
|
722
712
|
|
|
723
713
|
return k1, k2
|
|
724
714
|
|
|
725
715
|
def gen_skin_struct(self, k1, k2):
|
|
726
716
|
"""
|
|
727
|
-
Method to generate the two splines forming the foil for
|
|
717
|
+
Method to generate the two splines forming the foil for structured mesh, Only call this function when the points
|
|
728
718
|
of the airfoil are in their final position
|
|
729
719
|
-------
|
|
730
720
|
"""
|
|
@@ -871,10 +861,36 @@ def outofbounds(airfoil, box, radius, blthick):
|
|
|
871
861
|
|
|
872
862
|
class CType:
|
|
873
863
|
"""
|
|
874
|
-
A class to represent a C-type structured
|
|
864
|
+
A class to represent a C-type mesh domain with optional structured meshing.
|
|
865
|
+
Can be used for both fully structured meshes and as a structured farfield
|
|
866
|
+
for hybrid (unstructured) meshes.
|
|
875
867
|
"""
|
|
876
868
|
|
|
877
|
-
def __init__(self, airfoil_spline, dx_trail, dy, mesh_size, height,
|
|
869
|
+
def __init__(self, airfoil_spline, dx_trail, dy, mesh_size, height=None,
|
|
870
|
+
ratio=None, aoa=0, structured=True):
|
|
871
|
+
"""
|
|
872
|
+
Initialize a C-type mesh domain.
|
|
873
|
+
|
|
874
|
+
Parameters
|
|
875
|
+
----------
|
|
876
|
+
airfoil_spline : AirfoilSpline
|
|
877
|
+
The airfoil spline object
|
|
878
|
+
dx_trail : float
|
|
879
|
+
Length of trailing domain extension [m]
|
|
880
|
+
dy : float
|
|
881
|
+
Total height of the domain [m]
|
|
882
|
+
mesh_size : float
|
|
883
|
+
Mesh size for the domain
|
|
884
|
+
height : float, optional
|
|
885
|
+
Height of first boundary layer (for structured mesh only)
|
|
886
|
+
ratio : float, optional
|
|
887
|
+
Growth ratio of boundary layer (for structured mesh only)
|
|
888
|
+
aoa : float, optional
|
|
889
|
+
Angle of attack in radians (default 0)
|
|
890
|
+
structured : bool, optional
|
|
891
|
+
If True, create transfinite curves and surfaces for structured mesh
|
|
892
|
+
(default True)
|
|
893
|
+
"""
|
|
878
894
|
z = 0
|
|
879
895
|
self.airfoil_spline = airfoil_spline
|
|
880
896
|
|
|
@@ -890,6 +906,7 @@ class CType:
|
|
|
890
906
|
self.firstheight = height
|
|
891
907
|
self.ratio = ratio
|
|
892
908
|
self.aoa = aoa
|
|
909
|
+
self.structured = structured
|
|
893
910
|
|
|
894
911
|
# First compute k1 & k2 the first coordinate after 0.041 (up & down)
|
|
895
912
|
debut = True
|
|
@@ -901,10 +918,19 @@ class CType:
|
|
|
901
918
|
k2 = airfoil_spline.points.index(p)-1
|
|
902
919
|
break
|
|
903
920
|
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
self.
|
|
907
|
-
|
|
921
|
+
# Only call gen_skin_struct if creating structured mesh
|
|
922
|
+
# For unstructured, the airfoil already has proper splines from gen_skin()
|
|
923
|
+
if self.structured:
|
|
924
|
+
upper_spline_back, lower_spline_back = self.airfoil_spline.gen_skin_struct(
|
|
925
|
+
k1, k2)
|
|
926
|
+
self.le_upper_point = airfoil_spline.points[k1]
|
|
927
|
+
self.le_lower_point = airfoil_spline.points[k2]
|
|
928
|
+
else:
|
|
929
|
+
# For unstructured mesh, use the regular splines already generated
|
|
930
|
+
self.le_upper_point = airfoil_spline.points[k1]
|
|
931
|
+
self.le_lower_point = airfoil_spline.points[k2]
|
|
932
|
+
upper_spline_back = airfoil_spline.upper_spline
|
|
933
|
+
lower_spline_back = airfoil_spline.lower_spline
|
|
908
934
|
|
|
909
935
|
# Create the new front spline (from the two front parts)
|
|
910
936
|
upper_points_front = airfoil_spline.points[:k1+1]
|
|
@@ -1010,161 +1036,189 @@ class CType:
|
|
|
1010
1036
|
# --------------------------------------
|
|
1011
1037
|
# L6 L5
|
|
1012
1038
|
|
|
1013
|
-
#
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1039
|
+
# Store flag and parameters for later use
|
|
1040
|
+
self.structured = structured
|
|
1041
|
+
self.k1 = k1
|
|
1042
|
+
self.k2 = k2
|
|
1043
|
+
|
|
1044
|
+
if self.structured:
|
|
1045
|
+
# Only create structured mesh if requested
|
|
1046
|
+
# Now we compute all of the parameters to have smooth mesh around mesh size
|
|
1047
|
+
|
|
1048
|
+
# HEIGHT
|
|
1049
|
+
# Compute number of nodes needed to have the desired first layer height (=nb of layer (N) +1)
|
|
1050
|
+
# Computation : we have that dy/2 is total height, and let a=first layer height
|
|
1051
|
+
# dy/2= a + a*ratio + a*ratio^2 + ... + a*ratio^(N-1) and rearrange to get the following equation
|
|
1052
|
+
nb_points_y = 3+int(math.log(1+dy/2/height*(ratio-1))/math.log(ratio))
|
|
1053
|
+
progression_y = ratio
|
|
1054
|
+
progression_y_inv = 1/ratio
|
|
1055
|
+
|
|
1056
|
+
# WAKE
|
|
1057
|
+
# Set a progression to adapt slightly the wake (don't need as much precision further away from airfoil)
|
|
1058
|
+
progression_wake = 1/1.025
|
|
1059
|
+
progression_wake_inv = 1.025
|
|
1060
|
+
# Set number of points in x direction at wake to get desired meshsize on the one next to airfoil
|
|
1061
|
+
# (solve dx_trail = meshsize + meshsize*1.02 + meshsize*1.02^2 + ... + meshsize*1.02^(N-1) with N=nb of intervals)
|
|
1062
|
+
nb_points_wake = int(
|
|
1063
|
+
math.log(1+dx_trail*0.025/mesh_size_end)/math.log(1.025))+1
|
|
1064
|
+
|
|
1065
|
+
# AIRFOIL CENTER
|
|
1066
|
+
# Set number of points on upper and lower part of airfoil. Want mesh size at the end (b) to be meshsizeend, and at the front (a) meshsizeend/coef to be more coherent with airfoilfront
|
|
1067
|
+
if mesh_size_end > 0.05:
|
|
1068
|
+
coeffdiv = 4
|
|
1069
|
+
elif mesh_size_end >= 0.03:
|
|
1070
|
+
coeffdiv = 3
|
|
1071
|
+
else:
|
|
1072
|
+
coeffdiv = 2
|
|
1073
|
+
a, b, l = mesh_size_end/coeffdiv, mesh_size_end, airfoil_spline.te.x
|
|
1074
|
+
# So compute ratio and nb of points accordingly: (solve l=a+a*r+a*r^2+a*r^(N-1) and a*r^(N-1)=b, and N=nb of intervals=nb of points-1)
|
|
1075
|
+
ratio_airfoil = (l-a)/(l-b)
|
|
1076
|
+
if l-b < 0:
|
|
1077
|
+
nb_airfoil = 3
|
|
1078
|
+
else:
|
|
1079
|
+
nb_airfoil = max(3, int(math.log(b/a)/math.log(ratio_airfoil))+2)
|
|
1080
|
+
|
|
1081
|
+
# AIRFOIL FRONT
|
|
1082
|
+
# Now we can try to put the good number of point on the front to have a good mesh
|
|
1083
|
+
# First we estimate the length of the spline
|
|
1084
|
+
x, y, v, w = airfoil_spline.points[k1].x, airfoil_spline.points[
|
|
1085
|
+
k2].y, airfoil_spline.points[k1].x, airfoil_spline.points[k2].y
|
|
1086
|
+
c1, c2 = airfoil_spline.le.x, airfoil_spline.le.y
|
|
1087
|
+
estim_length = (math.sqrt((x-c1)*(x-c1)+(y-c2)*(y-c2)) +
|
|
1088
|
+
math.sqrt((v-c1)*(v-c1)+(w-c2)*(w-c2)))+0.01
|
|
1089
|
+
# Compute nb of points if they were all same size, multiply par a factor (3) to have an okay number (and good when apply bump)
|
|
1090
|
+
nb_airfoil_front = max(
|
|
1091
|
+
4, int(estim_length/mesh_size_end*coeffdiv*3))+4
|
|
1092
|
+
|
|
1093
|
+
# Now we set all the corresponding transfinite curve we need (with our coefficient computed before)
|
|
1094
|
+
|
|
1095
|
+
# transfinite curve A
|
|
1066
1096
|
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1067
|
-
|
|
1068
|
-
|
|
1097
|
+
self.lines[7].tag, nb_points_y, "Progression", progression_y_inv) # same for plane E
|
|
1098
|
+
if mesh_size_end < 0.04:
|
|
1099
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1100
|
+
spline_front, nb_airfoil_front, "Bump", 12)
|
|
1101
|
+
else:
|
|
1102
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1103
|
+
spline_front, nb_airfoil_front, "Bump", 7)
|
|
1104
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1105
|
+
self.lines[0].tag, nb_points_y, "Progression", progression_y) # same for plane B
|
|
1106
|
+
# Because of different length of L1 and L6, need a bigger coefficient when point 1 and 7 are really far (coef is 1 when far and 9 when close)
|
|
1107
|
+
coef = 8/3*(pt1x+pt7x)/2+31/3
|
|
1108
|
+
if dy < 6:
|
|
1109
|
+
coef = (coef+2)/3
|
|
1110
|
+
if dy <= 3:
|
|
1111
|
+
coef = (coef + 2)/3
|
|
1069
1112
|
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1070
|
-
|
|
1071
|
-
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1072
|
-
self.lines[0].tag, nb_points_y, "Progression", progression_y) # same for plane B
|
|
1073
|
-
# Because of different length of L1 and L6, need a bigger coefficient when point 1 and 7 are really far (coef is 1 when far and 9 when close)
|
|
1074
|
-
coef = 8/3*(pt1x+pt7x)/2+31/3
|
|
1075
|
-
if dy < 6:
|
|
1076
|
-
coef = (coef+2)/3
|
|
1077
|
-
if dy <= 3:
|
|
1078
|
-
coef = (coef + 2)/3
|
|
1079
|
-
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1080
|
-
self.circle_arc, nb_airfoil_front, "Bump", 1/coef)
|
|
1113
|
+
self.circle_arc, nb_airfoil_front, "Bump", 1/coef)
|
|
1081
1114
|
|
|
1082
1115
|
# transfinite curve B
|
|
1083
|
-
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1084
|
-
self.lines[8].tag, nb_points_y, "Progression", progression_y) # same for plane C
|
|
1085
|
-
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1086
|
-
upper_spline_back.tag, nb_airfoil, "Progression", ratio_airfoil)
|
|
1087
|
-
# For L1, we adapt depeding if the curve is much longer than 1 or not (if goes "far in the front")
|
|
1088
|
-
if pt1x < airfoil_spline.le.x-1.5:
|
|
1089
1116
|
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1090
|
-
self.lines[
|
|
1091
|
-
elif pt1x < airfoil_spline.le.x-0.7:
|
|
1117
|
+
self.lines[8].tag, nb_points_y, "Progression", progression_y) # same for plane C
|
|
1092
1118
|
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1093
|
-
|
|
1094
|
-
|
|
1119
|
+
upper_spline_back.tag, nb_airfoil, "Progression", ratio_airfoil)
|
|
1120
|
+
# For L1, we adapt depeding if the curve is much longer than 1 or not (if goes "far in the front")
|
|
1121
|
+
if pt1x < airfoil_spline.le.x-1.5:
|
|
1122
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1123
|
+
self.lines[1].tag, nb_airfoil, "Progression", 1/ratio_airfoil)
|
|
1124
|
+
elif pt1x < airfoil_spline.le.x-0.7:
|
|
1125
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1126
|
+
self.lines[1].tag, nb_airfoil, "Progression", 1/math.sqrt(ratio_airfoil))
|
|
1127
|
+
else:
|
|
1128
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1129
|
+
self.lines[1].tag, nb_airfoil)
|
|
1130
|
+
|
|
1131
|
+
# transfinite curve C
|
|
1095
1132
|
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1096
|
-
self.lines[
|
|
1097
|
-
|
|
1098
|
-
# transfinite curve C
|
|
1099
|
-
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1100
|
-
self.lines[2].tag, nb_points_wake, "Progression", progression_wake_inv)
|
|
1101
|
-
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1102
|
-
self.lines[3].tag, nb_points_y, "Progression", progression_y_inv)
|
|
1103
|
-
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1104
|
-
self.lines[10].tag, nb_points_wake, "Progression", progression_wake) # same for plane D
|
|
1105
|
-
|
|
1106
|
-
# transfinite curve D
|
|
1107
|
-
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1108
|
-
self.lines[9].tag, nb_points_y, "Progression", progression_y) # same for plane E
|
|
1109
|
-
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1110
|
-
self.lines[4].tag, nb_points_y, "Progression", progression_y)
|
|
1111
|
-
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1112
|
-
self.lines[5].tag, nb_points_wake, "Progression", progression_wake)
|
|
1113
|
-
|
|
1114
|
-
# transfinite curve E
|
|
1115
|
-
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1116
|
-
lower_spline_back.tag, nb_airfoil, "Progression", 1/ratio_airfoil)
|
|
1117
|
-
# For L6, we adapt depeding if the line is much longer than 1 or not (if goes "far in the front")
|
|
1118
|
-
if pt7x < airfoil_spline.le.x-1.5:
|
|
1133
|
+
self.lines[2].tag, nb_points_wake, "Progression", progression_wake_inv)
|
|
1119
1134
|
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1120
|
-
self.lines[
|
|
1121
|
-
elif pt7x < airfoil_spline.le.x-0.4:
|
|
1135
|
+
self.lines[3].tag, nb_points_y, "Progression", progression_y_inv)
|
|
1122
1136
|
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1123
|
-
self.lines[
|
|
1124
|
-
|
|
1137
|
+
self.lines[10].tag, nb_points_wake, "Progression", progression_wake) # same for plane D
|
|
1138
|
+
|
|
1139
|
+
# transfinite curve D
|
|
1125
1140
|
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1126
|
-
self.lines[
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1141
|
+
self.lines[9].tag, nb_points_y, "Progression", progression_y) # same for plane E
|
|
1142
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1143
|
+
self.lines[4].tag, nb_points_y, "Progression", progression_y)
|
|
1144
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1145
|
+
self.lines[5].tag, nb_points_wake, "Progression", progression_wake)
|
|
1146
|
+
|
|
1147
|
+
# transfinite curve E
|
|
1148
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1149
|
+
lower_spline_back.tag, nb_airfoil, "Progression", 1/ratio_airfoil)
|
|
1150
|
+
# For L6, we adapt depeding if the line is much longer than 1 or not (if goes "far in the front")
|
|
1151
|
+
if pt7x < airfoil_spline.le.x-1.5:
|
|
1152
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1153
|
+
self.lines[6].tag, nb_airfoil, "Progression", ratio_airfoil)
|
|
1154
|
+
elif pt7x < airfoil_spline.le.x-0.4:
|
|
1155
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1156
|
+
self.lines[6].tag, nb_airfoil, "Progression", math.sqrt(ratio_airfoil))
|
|
1157
|
+
else:
|
|
1158
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1159
|
+
self.lines[6].tag, nb_airfoil)
|
|
1160
|
+
|
|
1161
|
+
# Now we add the surfaces
|
|
1162
|
+
|
|
1163
|
+
# transfinite surface A (forces structured mesh)
|
|
1164
|
+
c1 = gmsh.model.geo.addCurveLoop(
|
|
1165
|
+
[self.lines[7].tag, spline_front, self.lines[0].tag, - self.circle_arc])
|
|
1166
|
+
surf1 = gmsh.model.geo.addPlaneSurface([c1])
|
|
1167
|
+
gmsh.model.geo.mesh.setTransfiniteSurface(surf1)
|
|
1168
|
+
|
|
1169
|
+
# transfinite surface B
|
|
1170
|
+
c2 = gmsh.model.geo.addCurveLoop(
|
|
1171
|
+
[self.lines[0].tag, self.lines[1].tag, - self.lines[8].tag, - upper_spline_back.tag])
|
|
1172
|
+
surf2 = gmsh.model.geo.addPlaneSurface([c2])
|
|
1173
|
+
gmsh.model.geo.mesh.setTransfiniteSurface(surf2)
|
|
1174
|
+
|
|
1175
|
+
# transfinite surface C
|
|
1176
|
+
c3 = gmsh.model.geo.addCurveLoop(
|
|
1177
|
+
[self.lines[8].tag, self.lines[2].tag, self.lines[3].tag, self.lines[10].tag])
|
|
1178
|
+
surf3 = gmsh.model.geo.addPlaneSurface([c3])
|
|
1179
|
+
gmsh.model.geo.mesh.setTransfiniteSurface(surf3)
|
|
1180
|
+
|
|
1181
|
+
# transfinite surface D
|
|
1182
|
+
c4 = gmsh.model.geo.addCurveLoop(
|
|
1183
|
+
[- self.lines[9].tag, - self.lines[10].tag, self.lines[4].tag, self.lines[5].tag])
|
|
1184
|
+
surf4 = gmsh.model.geo.addPlaneSurface([c4])
|
|
1185
|
+
gmsh.model.geo.mesh.setTransfiniteSurface(surf4)
|
|
1186
|
+
|
|
1187
|
+
# transfinite surface E
|
|
1188
|
+
c5 = gmsh.model.geo.addCurveLoop(
|
|
1189
|
+
[self.lines[7].tag, - lower_spline_back.tag, self.lines[9].tag, self.lines[6].tag])
|
|
1190
|
+
surf5 = gmsh.model.geo.addPlaneSurface([c5])
|
|
1191
|
+
gmsh.model.geo.mesh.setTransfiniteSurface(surf5)
|
|
1192
|
+
self.curveloops = [c1, c2, c3, c4, c5]
|
|
1193
|
+
self.surfaces = [surf1, surf2, surf3, surf4, surf5]
|
|
1194
|
+
|
|
1195
|
+
# Lastly, recombine surface to create quadrilateral elements
|
|
1196
|
+
gmsh.model.geo.mesh.setRecombine(2, surf1, 90)
|
|
1197
|
+
gmsh.model.geo.mesh.setRecombine(2, surf2, 90)
|
|
1198
|
+
gmsh.model.geo.mesh.setRecombine(2, surf3, 90)
|
|
1199
|
+
gmsh.model.geo.mesh.setRecombine(2, surf4, 90)
|
|
1200
|
+
gmsh.model.geo.mesh.setRecombine(2, surf5, 90)
|
|
1201
|
+
else:
|
|
1202
|
+
# For non-structured (hybrid) mesh, create C-type farfield boundary
|
|
1203
|
+
# Only create the outer curve loop - PlaneSurface will use it as a hole
|
|
1204
|
+
# Outer loop: circle_arc (p7→p1) + lines[1:7] (p1→p2→p3→p4→p5→p6→p7)
|
|
1205
|
+
curve_loop = gmsh.model.geo.addCurveLoop(
|
|
1206
|
+
[self.circle_arc] +
|
|
1207
|
+
[self.lines[i].tag for i in range(1, 7)]
|
|
1208
|
+
)
|
|
1209
|
+
self.surfaces = []
|
|
1210
|
+
self.curveloops = [curve_loop]
|
|
1211
|
+
|
|
1212
|
+
def close_loop(self):
|
|
1213
|
+
"""
|
|
1214
|
+
Return the outer boundary curve loop for the farfield domain.
|
|
1215
|
+
|
|
1216
|
+
Returns
|
|
1217
|
+
-------
|
|
1218
|
+
tag : int
|
|
1219
|
+
Tag of the first (outer) curve loop
|
|
1220
|
+
"""
|
|
1221
|
+
return self.curveloops[0]
|
|
1168
1222
|
|
|
1169
1223
|
def define_bc(self):
|
|
1170
1224
|
"""
|
|
@@ -1186,4 +1240,4 @@ class CType:
|
|
|
1186
1240
|
|
|
1187
1241
|
# Surface
|
|
1188
1242
|
self.bc = gmsh.model.addPhysicalGroup(2, self.surfaces)
|
|
1189
|
-
gmsh.model.setPhysicalName(2, self.bc, "fluid")
|
|
1243
|
+
gmsh.model.setPhysicalName(2, self.bc, "fluid")
|