gmshairfoil2d 0.1.4__py3-none-any.whl → 0.2__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/geometry_def.py +588 -86
- gmshairfoil2d/gmshairfoil2d.py +158 -24
- gmshairfoil2d-0.2.dist-info/METADATA +136 -0
- gmshairfoil2d-0.2.dist-info/RECORD +10 -0
- {gmshairfoil2d-0.1.4.dist-info → gmshairfoil2d-0.2.dist-info}/WHEEL +1 -1
- gmshairfoil2d-0.1.4.dist-info/METADATA +0 -106
- gmshairfoil2d-0.1.4.dist-info/RECORD +0 -10
- {gmshairfoil2d-0.1.4.dist-info → gmshairfoil2d-0.2.dist-info}/entry_points.txt +0 -0
- {gmshairfoil2d-0.1.4.dist-info → gmshairfoil2d-0.2.dist-info/licenses}/LICENSE +0 -0
- {gmshairfoil2d-0.1.4.dist-info → gmshairfoil2d-0.2.dist-info}/top_level.txt +0 -0
gmshairfoil2d/geometry_def.py
CHANGED
|
@@ -6,6 +6,7 @@ from operator import attrgetter
|
|
|
6
6
|
import gmsh
|
|
7
7
|
import numpy as np
|
|
8
8
|
import math
|
|
9
|
+
import sys
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class Point:
|
|
@@ -32,18 +33,17 @@ class Point:
|
|
|
32
33
|
self.x = x
|
|
33
34
|
self.y = y
|
|
34
35
|
self.z = z
|
|
35
|
-
|
|
36
36
|
self.mesh_size = mesh_size
|
|
37
37
|
self.dim = 0
|
|
38
38
|
|
|
39
39
|
# create the gmsh object and store the tag of the geometric object
|
|
40
|
-
self.tag = gmsh.model.
|
|
40
|
+
self.tag = gmsh.model.geo.addPoint(
|
|
41
|
+
self.x, self.y, self.z, self.mesh_size)
|
|
41
42
|
|
|
42
43
|
def rotation(self, angle, origin, axis):
|
|
43
44
|
"""
|
|
44
|
-
|
|
45
|
+
Method to rotate the object Point
|
|
45
46
|
...
|
|
46
|
-
|
|
47
47
|
Parameters
|
|
48
48
|
----------
|
|
49
49
|
angle : float
|
|
@@ -53,7 +53,7 @@ class Point:
|
|
|
53
53
|
axis : tuple
|
|
54
54
|
tuple of point (x,y,z) which represent the axis of rotation
|
|
55
55
|
"""
|
|
56
|
-
gmsh.model.
|
|
56
|
+
gmsh.model.geo.rotate(
|
|
57
57
|
[(self.dim, self.tag)],
|
|
58
58
|
*origin,
|
|
59
59
|
*axis,
|
|
@@ -62,7 +62,8 @@ class Point:
|
|
|
62
62
|
|
|
63
63
|
def translation(self, vector):
|
|
64
64
|
"""
|
|
65
|
-
|
|
65
|
+
Method to translate the object Point
|
|
66
|
+
|
|
66
67
|
...
|
|
67
68
|
|
|
68
69
|
Parameters
|
|
@@ -70,7 +71,7 @@ class Point:
|
|
|
70
71
|
direction : tuple
|
|
71
72
|
tuple of point (x,y,z) which represent the direction of the translation
|
|
72
73
|
"""
|
|
73
|
-
gmsh.model.
|
|
74
|
+
gmsh.model.geo.translate([(self.dim, self.tag)], *vector)
|
|
74
75
|
|
|
75
76
|
|
|
76
77
|
class Line:
|
|
@@ -94,11 +95,12 @@ class Line:
|
|
|
94
95
|
self.dim = 1
|
|
95
96
|
|
|
96
97
|
# create the gmsh object and store the tag of the geometric object
|
|
97
|
-
self.tag = gmsh.model.
|
|
98
|
+
self.tag = gmsh.model.geo.addLine(
|
|
99
|
+
self.start_point.tag, self.end_point.tag)
|
|
98
100
|
|
|
99
101
|
def rotation(self, angle, origin, axis):
|
|
100
102
|
"""
|
|
101
|
-
|
|
103
|
+
Method to rotate the object Line
|
|
102
104
|
...
|
|
103
105
|
|
|
104
106
|
Parameters
|
|
@@ -110,7 +112,7 @@ class Line:
|
|
|
110
112
|
axis : tuple
|
|
111
113
|
tuple of point (x,y,z) which represent the axis of rotation
|
|
112
114
|
"""
|
|
113
|
-
gmsh.model.
|
|
115
|
+
gmsh.model.geo.rotate(
|
|
114
116
|
[(self.dim, self.tag)],
|
|
115
117
|
*origin,
|
|
116
118
|
*axis,
|
|
@@ -119,7 +121,7 @@ class Line:
|
|
|
119
121
|
|
|
120
122
|
def translation(self, vector):
|
|
121
123
|
"""
|
|
122
|
-
|
|
124
|
+
Method to translate the object Line
|
|
123
125
|
...
|
|
124
126
|
|
|
125
127
|
Parameters
|
|
@@ -127,7 +129,7 @@ class Line:
|
|
|
127
129
|
direction : tuple
|
|
128
130
|
tuple of point (x,y,z) which represent the direction of the translation
|
|
129
131
|
"""
|
|
130
|
-
gmsh.model.
|
|
132
|
+
gmsh.model.geo.translate([(self.dim, self.tag)], *vector)
|
|
131
133
|
|
|
132
134
|
|
|
133
135
|
class Spline:
|
|
@@ -145,17 +147,17 @@ class Spline:
|
|
|
145
147
|
def __init__(self, point_list):
|
|
146
148
|
self.point_list = point_list
|
|
147
149
|
|
|
148
|
-
# generate the Lines tag list to
|
|
150
|
+
# generate the Lines tag list to follow
|
|
149
151
|
self.tag_list = [point.tag for point in self.point_list]
|
|
150
152
|
self.dim = 1
|
|
151
153
|
# create the gmsh object and store the tag of the geometric object
|
|
152
|
-
self.tag = gmsh.model.
|
|
154
|
+
self.tag = gmsh.model.geo.addSpline(self.tag_list)
|
|
153
155
|
|
|
154
156
|
def rotation(self, angle, origin, axis):
|
|
155
157
|
"""
|
|
156
|
-
|
|
158
|
+
Method to rotate the object Spline
|
|
157
159
|
|
|
158
|
-
Rotate the spline itself (curve,
|
|
160
|
+
Rotate the spline itself (curve, startpoint, endpoint), then rotate the intermediate points
|
|
159
161
|
...
|
|
160
162
|
|
|
161
163
|
Parameters
|
|
@@ -167,7 +169,7 @@ class Spline:
|
|
|
167
169
|
axis : tuple
|
|
168
170
|
tuple of point (x,y,z) which represent the axis of rotation
|
|
169
171
|
"""
|
|
170
|
-
gmsh.model.
|
|
172
|
+
gmsh.model.geo.rotate(
|
|
171
173
|
[(self.dim, self.tag)],
|
|
172
174
|
*origin,
|
|
173
175
|
*axis,
|
|
@@ -181,9 +183,9 @@ class Spline:
|
|
|
181
183
|
|
|
182
184
|
def translation(self, vector):
|
|
183
185
|
"""
|
|
184
|
-
|
|
186
|
+
Method to translate the object Line
|
|
185
187
|
|
|
186
|
-
Translate the spline itself (curve,
|
|
188
|
+
Translate the spline itself (curve, startpoint,endpoint), then translate the indermediate points
|
|
187
189
|
...
|
|
188
190
|
|
|
189
191
|
Parameters
|
|
@@ -191,8 +193,9 @@ class Spline:
|
|
|
191
193
|
direction : tuple
|
|
192
194
|
tuple of point (x,y,z) which represent the direction of the translation
|
|
193
195
|
"""
|
|
194
|
-
gmsh.model.
|
|
195
|
-
[interm_point.translation(vector)
|
|
196
|
+
gmsh.model.geo.translate([(self.dim, self.tag)], *vector)
|
|
197
|
+
[interm_point.translation(vector)
|
|
198
|
+
for interm_point in self.point_list[1:-1]]
|
|
196
199
|
|
|
197
200
|
|
|
198
201
|
class CurveLoop:
|
|
@@ -207,17 +210,40 @@ class CurveLoop:
|
|
|
207
210
|
----------
|
|
208
211
|
line_list : list(Line)
|
|
209
212
|
List of Line object, in the order of the wanted CurveLoop and closed
|
|
213
|
+
Possibility to give either the tags directly, or the object Line
|
|
210
214
|
"""
|
|
211
215
|
|
|
212
216
|
def __init__(self, line_list):
|
|
213
217
|
|
|
214
218
|
self.line_list = line_list
|
|
215
219
|
self.dim = 1
|
|
216
|
-
|
|
217
|
-
# generate the Lines tag list to folow
|
|
220
|
+
# generate the Lines tag list to follow
|
|
218
221
|
self.tag_list = [line.tag for line in self.line_list]
|
|
219
222
|
# create the gmsh object and store the tag of the geometric object
|
|
220
|
-
self.tag = gmsh.model.
|
|
223
|
+
self.tag = gmsh.model.geo.addCurveLoop(self.tag_list)
|
|
224
|
+
|
|
225
|
+
def close_loop(self):
|
|
226
|
+
"""
|
|
227
|
+
Method to form a close loop with the current geometrical object. In our case,
|
|
228
|
+
we already have it so just return the tag
|
|
229
|
+
|
|
230
|
+
Returns
|
|
231
|
+
-------
|
|
232
|
+
_ : int
|
|
233
|
+
return the tag of the CurveLoop object
|
|
234
|
+
"""
|
|
235
|
+
return self.tag
|
|
236
|
+
|
|
237
|
+
def define_bc(self):
|
|
238
|
+
"""
|
|
239
|
+
Method that define the marker of the CurveLoop (when used as boundary layer boundary)
|
|
240
|
+
for the boundary condition
|
|
241
|
+
-------
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
self.bc = gmsh.model.addPhysicalGroup(self.dim, [self.tag])
|
|
245
|
+
self.physical_name = gmsh.model.setPhysicalName(
|
|
246
|
+
self.dim, self.bc, "top of boundary layer")
|
|
221
247
|
|
|
222
248
|
|
|
223
249
|
class Circle:
|
|
@@ -232,7 +258,7 @@ class Circle:
|
|
|
232
258
|
position of the center in x
|
|
233
259
|
yc : float
|
|
234
260
|
position of the center in y
|
|
235
|
-
|
|
261
|
+
zc : float
|
|
236
262
|
position in z
|
|
237
263
|
radius : float
|
|
238
264
|
radius of the circle
|
|
@@ -251,22 +277,39 @@ class Circle:
|
|
|
251
277
|
self.mesh_size = mesh_size
|
|
252
278
|
self.dim = 1
|
|
253
279
|
|
|
254
|
-
# create
|
|
255
|
-
|
|
280
|
+
# create multiples ArcCircle to merge in one circle
|
|
281
|
+
|
|
282
|
+
# first compute how many points on the circle (for the meshing to be alined with the points)
|
|
283
|
+
self.distribution = math.floor(
|
|
284
|
+
(np.pi * 2 * self.radius) / self.mesh_size)
|
|
285
|
+
realmeshsize = (np.pi * 2 * self.radius)/self.distribution
|
|
286
|
+
|
|
287
|
+
# Create the center of the circle
|
|
288
|
+
center = Point(self.xc, self.yc, self.zc, realmeshsize)
|
|
289
|
+
|
|
290
|
+
# Create all the points for the circle
|
|
291
|
+
points = []
|
|
292
|
+
for i in range(0, self.distribution):
|
|
293
|
+
angle = 2 * np.pi / self.distribution * i
|
|
294
|
+
p = Point(self.xc+self.radius*math.cos(angle), self.yc+self.radius *
|
|
295
|
+
math.sin(angle), self.zc, realmeshsize)
|
|
296
|
+
points.append(p)
|
|
297
|
+
# Add the first point last for continuity when creating the arcs
|
|
298
|
+
points.append(points[0])
|
|
299
|
+
|
|
300
|
+
# Create arcs between two neighbouring points to create a circle
|
|
256
301
|
self.arcCircle_list = [
|
|
257
|
-
gmsh.model.
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
self.radius,
|
|
262
|
-
angle1=2 * np.pi / self.distribution * i,
|
|
263
|
-
angle2=2 * np.pi / self.distribution * (1 + i),
|
|
302
|
+
gmsh.model.geo.addCircleArc(
|
|
303
|
+
points[i].tag,
|
|
304
|
+
center.tag,
|
|
305
|
+
points[i+1].tag,
|
|
264
306
|
)
|
|
265
307
|
for i in range(0, self.distribution)
|
|
266
308
|
]
|
|
309
|
+
|
|
267
310
|
# Remove the duplicated points generated by the arcCircle
|
|
268
|
-
gmsh.model.
|
|
269
|
-
gmsh.model.
|
|
311
|
+
gmsh.model.geo.synchronize()
|
|
312
|
+
gmsh.model.geo.removeAllDuplicates()
|
|
270
313
|
|
|
271
314
|
def close_loop(self):
|
|
272
315
|
"""
|
|
@@ -277,7 +320,7 @@ class Circle:
|
|
|
277
320
|
_ : int
|
|
278
321
|
return the tag of the CurveLoop object
|
|
279
322
|
"""
|
|
280
|
-
return gmsh.model.
|
|
323
|
+
return gmsh.model.geo.addCurveLoop(self.arcCircle_list)
|
|
281
324
|
|
|
282
325
|
def define_bc(self):
|
|
283
326
|
"""
|
|
@@ -287,11 +330,12 @@ class Circle:
|
|
|
287
330
|
"""
|
|
288
331
|
|
|
289
332
|
self.bc = gmsh.model.addPhysicalGroup(self.dim, self.arcCircle_list)
|
|
290
|
-
self.physical_name = gmsh.model.setPhysicalName(
|
|
333
|
+
self.physical_name = gmsh.model.setPhysicalName(
|
|
334
|
+
self.dim, self.bc, "farfield")
|
|
291
335
|
|
|
292
336
|
def rotation(self, angle, origin, axis):
|
|
293
337
|
"""
|
|
294
|
-
|
|
338
|
+
Method to rotate the object Circle
|
|
295
339
|
...
|
|
296
340
|
|
|
297
341
|
Parameters
|
|
@@ -304,7 +348,7 @@ class Circle:
|
|
|
304
348
|
tuple of point (x,y,z) which represent the axis of rotation
|
|
305
349
|
"""
|
|
306
350
|
[
|
|
307
|
-
gmsh.model.
|
|
351
|
+
gmsh.model.geo.rotate(
|
|
308
352
|
[(self.dim, arccircle)],
|
|
309
353
|
*origin,
|
|
310
354
|
*axis,
|
|
@@ -315,7 +359,7 @@ class Circle:
|
|
|
315
359
|
|
|
316
360
|
def translation(self, vector):
|
|
317
361
|
"""
|
|
318
|
-
|
|
362
|
+
Method to translate the object Circle
|
|
319
363
|
...
|
|
320
364
|
|
|
321
365
|
Parameters
|
|
@@ -324,7 +368,7 @@ class Circle:
|
|
|
324
368
|
tuple of point (x,y,z) which represent the direction of the translation
|
|
325
369
|
"""
|
|
326
370
|
[
|
|
327
|
-
gmsh.model.
|
|
371
|
+
gmsh.model.geo.translate([(self.dim, arccircle)], *vector)
|
|
328
372
|
for arccircle in self.arcCircle_list
|
|
329
373
|
]
|
|
330
374
|
|
|
@@ -362,14 +406,18 @@ class Rectangle:
|
|
|
362
406
|
|
|
363
407
|
self.mesh_size = mesh_size
|
|
364
408
|
self.dim = 1
|
|
365
|
-
|
|
366
409
|
# Generate the 4 corners of the rectangle
|
|
367
410
|
self.points = [
|
|
368
|
-
Point(self.xc - self.dx / 2, self.yc -
|
|
369
|
-
|
|
370
|
-
Point(self.xc + self.dx / 2, self.yc
|
|
371
|
-
|
|
411
|
+
Point(self.xc - self.dx / 2, self.yc -
|
|
412
|
+
self.dy / 2, z, self.mesh_size),
|
|
413
|
+
Point(self.xc + self.dx / 2, self.yc -
|
|
414
|
+
self.dy / 2, z, self.mesh_size),
|
|
415
|
+
Point(self.xc + self.dx / 2, self.yc +
|
|
416
|
+
self.dy / 2, z, self.mesh_size),
|
|
417
|
+
Point(self.xc - self.dx / 2, self.yc +
|
|
418
|
+
self.dy / 2, z, self.mesh_size),
|
|
372
419
|
]
|
|
420
|
+
gmsh.model.geo.synchronize()
|
|
373
421
|
|
|
374
422
|
# Generate the 4 lines of the rectangle
|
|
375
423
|
self.lines = [
|
|
@@ -379,6 +427,8 @@ class Rectangle:
|
|
|
379
427
|
Line(self.points[3], self.points[0]),
|
|
380
428
|
]
|
|
381
429
|
|
|
430
|
+
gmsh.model.geo.synchronize()
|
|
431
|
+
|
|
382
432
|
def close_loop(self):
|
|
383
433
|
"""
|
|
384
434
|
Method to form a close loop with the current geometrical object
|
|
@@ -400,10 +450,12 @@ class Rectangle:
|
|
|
400
450
|
-------
|
|
401
451
|
"""
|
|
402
452
|
|
|
403
|
-
self.bc_in = gmsh.model.addPhysicalGroup(
|
|
453
|
+
self.bc_in = gmsh.model.addPhysicalGroup(
|
|
454
|
+
self.dim, [self.lines[3].tag], tag=-1)
|
|
404
455
|
gmsh.model.setPhysicalName(self.dim, self.bc_in, "inlet")
|
|
405
456
|
|
|
406
|
-
self.bc_out = gmsh.model.addPhysicalGroup(
|
|
457
|
+
self.bc_out = gmsh.model.addPhysicalGroup(
|
|
458
|
+
self.dim, [self.lines[1].tag])
|
|
407
459
|
gmsh.model.setPhysicalName(self.dim, self.bc_out, "outlet")
|
|
408
460
|
|
|
409
461
|
self.bc_wall = gmsh.model.addPhysicalGroup(
|
|
@@ -415,7 +467,7 @@ class Rectangle:
|
|
|
415
467
|
|
|
416
468
|
def rotation(self, angle, origin, axis):
|
|
417
469
|
"""
|
|
418
|
-
|
|
470
|
+
Method to rotate the object Rectangle
|
|
419
471
|
...
|
|
420
472
|
|
|
421
473
|
Parameters
|
|
@@ -431,7 +483,7 @@ class Rectangle:
|
|
|
431
483
|
|
|
432
484
|
def translation(self, vector):
|
|
433
485
|
"""
|
|
434
|
-
|
|
486
|
+
Method to translate the object Rectangle
|
|
435
487
|
...
|
|
436
488
|
|
|
437
489
|
Parameters
|
|
@@ -453,9 +505,9 @@ class Airfoil:
|
|
|
453
505
|
point_cloud : list(list(float))
|
|
454
506
|
List of points forming the airfoil in the order,
|
|
455
507
|
each point is a list containing in the order
|
|
456
|
-
its
|
|
508
|
+
its position x,y,z
|
|
457
509
|
mesh_size : float
|
|
458
|
-
attribute given for the class Point,Note that a mesh size larger
|
|
510
|
+
attribute given for the class Point, Note that a mesh size larger
|
|
459
511
|
than the resolution given by the cloud of points
|
|
460
512
|
will not be taken into account
|
|
461
513
|
name : str
|
|
@@ -507,7 +559,7 @@ class Airfoil:
|
|
|
507
559
|
|
|
508
560
|
def rotation(self, angle, origin, axis):
|
|
509
561
|
"""
|
|
510
|
-
|
|
562
|
+
Method to rotate the object CurveLoop
|
|
511
563
|
...
|
|
512
564
|
|
|
513
565
|
Parameters
|
|
@@ -523,7 +575,7 @@ class Airfoil:
|
|
|
523
575
|
|
|
524
576
|
def translation(self, vector):
|
|
525
577
|
"""
|
|
526
|
-
|
|
578
|
+
Method to translate the object CurveLoop
|
|
527
579
|
...
|
|
528
580
|
|
|
529
581
|
Parameters
|
|
@@ -544,60 +596,147 @@ class AirfoilSpline:
|
|
|
544
596
|
point_cloud : list(list(float))
|
|
545
597
|
List of points forming the airfoil in the order,
|
|
546
598
|
each point is a list containing in the order
|
|
547
|
-
its
|
|
599
|
+
its position x,y,z
|
|
548
600
|
mesh_size : float
|
|
549
|
-
attribute given for the class Point,Note that a mesh size larger
|
|
601
|
+
attribute given for the class Point, (Note that a mesh size larger
|
|
550
602
|
than the resolution given by the cloud of points
|
|
551
|
-
will not be taken into account
|
|
603
|
+
will not be taken into account --> Not implemented)
|
|
552
604
|
name : str
|
|
553
605
|
name of the marker that will be associated to the airfoil
|
|
554
606
|
boundary condition
|
|
555
607
|
"""
|
|
556
608
|
|
|
557
|
-
def __init__(self, point_cloud, mesh_size,
|
|
609
|
+
def __init__(self, point_cloud, mesh_size, name="airfoil"):
|
|
558
610
|
|
|
559
611
|
self.name = name
|
|
560
612
|
self.dim = 1
|
|
613
|
+
self.mesh_size = mesh_size
|
|
561
614
|
|
|
562
615
|
# Generate Points object from the point_cloud
|
|
563
616
|
self.points = [
|
|
564
617
|
Point(point_cord[0], point_cord[1], point_cord[2], mesh_size)
|
|
565
618
|
for point_cord in point_cloud
|
|
566
619
|
]
|
|
620
|
+
|
|
567
621
|
# Find leading and trailing edge location
|
|
568
622
|
# in space
|
|
569
623
|
self.le = min(self.points, key=attrgetter("x"))
|
|
570
624
|
self.te = max(self.points, key=attrgetter("x"))
|
|
571
|
-
|
|
572
625
|
# in the list of point
|
|
573
|
-
self.le_indx = self.points.index(self.le)
|
|
574
626
|
self.te_indx = self.points.index(self.te)
|
|
627
|
+
self.le_indx = self.points.index(self.le)
|
|
628
|
+
|
|
629
|
+
# Check if the airfoil end in a single point, or with two different points (vertical of each other)
|
|
630
|
+
vertical = False
|
|
631
|
+
# If two (in the end) are so close in coordinate x, they are vertical and not just neighbouring point (examples below)
|
|
632
|
+
# Just need to check if the one before or after and then label them correctly
|
|
633
|
+
if self.points[self.te_indx-1].x > self.te.x-0.0001:
|
|
634
|
+
te_up_indx = self.te_indx-1
|
|
635
|
+
te_down_indx = self.te_indx
|
|
636
|
+
vertical = True
|
|
637
|
+
elif self.points[self.te_indx+1].x > self.te.x-0.0001:
|
|
638
|
+
te_up_indx = self.te_indx
|
|
639
|
+
te_down_indx = self.te_indx+1
|
|
640
|
+
vertical = True
|
|
641
|
+
|
|
642
|
+
# If end with two points, add one point in the prolongation of the curves to get pointy edge
|
|
643
|
+
if vertical:
|
|
644
|
+
# Compute the prolongation of the last segment and their meetpoint : it will be the new point
|
|
645
|
+
x, y, z, w = self.points[te_up_indx].x, self.points[
|
|
646
|
+
te_up_indx].y, self.points[te_down_indx].x, self.points[te_down_indx].y
|
|
647
|
+
a, b, c, d = x - self.points[te_up_indx-1].x, y-self.points[te_up_indx -
|
|
648
|
+
1].y, z-self.points[te_down_indx+1].x, w-self.points[te_down_indx+1].y
|
|
649
|
+
#
|
|
650
|
+
# We have that (x,y) are the coordinates of te_up and (z,w) the coordinates of te_down
|
|
651
|
+
# p1 is the point before te_up and p2 the point after te_down
|
|
652
|
+
# \
|
|
653
|
+
# . p1
|
|
654
|
+
# \ vector from p1 to (x,y) is (a,b)
|
|
655
|
+
# \
|
|
656
|
+
# . (x,y)
|
|
657
|
+
# p2
|
|
658
|
+
# .----->. . <- want to compute this point (which will be our new te)
|
|
659
|
+
# (z,w)
|
|
660
|
+
# vector from p2 to (z,w) is (c,d)
|
|
661
|
+
#
|
|
662
|
+
|
|
663
|
+
nothing = False
|
|
664
|
+
# We compute mu: solution from the system (x,y)+lambda(a,b)=(z,w)+mu(c,d) that gives us the intersection point
|
|
665
|
+
if b*c-a*d != 0:
|
|
666
|
+
mu = (b*(x-z)+a*(w-y))/(b*c-a*d)
|
|
667
|
+
else:
|
|
668
|
+
# only happens with vr7b and vr8b (parallel edges so no solutions)
|
|
669
|
+
mu = 10000000
|
|
670
|
+
# will be treated in the else
|
|
671
|
+
|
|
672
|
+
# Now to be coherent, we want the pointy edge to have a x coordinate between te.x and 0.1 further
|
|
673
|
+
if z+mu*c <= self.te.x + 0.1 and z+mu*c > self.te.x:
|
|
674
|
+
new = Point(z+mu*c, w+mu*d, 0, self.mesh_size)
|
|
675
|
+
|
|
676
|
+
# If not, it can be in the wrong direction (like with oaf095) or absurdly far (like with hh02), and so we constrain it
|
|
677
|
+
# (happens with roughly 40 airfoils, most because not well discretized)
|
|
678
|
+
|
|
679
|
+
# First we take off the ones in this case (new would be so close) are the one not well coded with two really close horizontally points (like s2091). So we just don't do anything
|
|
680
|
+
elif z+mu*c > self.te.x-0.001 and z+mu*c <= self.te.x:
|
|
681
|
+
nothing = True
|
|
682
|
+
else:
|
|
683
|
+
# if too far or behind, we take the point p in the middle of (x,y) and (z,w), and add the vector mean of (a,b) and (c,d) until we reach 1.05 (or te +0.05 to be precise)
|
|
684
|
+
px, py = (x+z)/2, (y+w)/2
|
|
685
|
+
e, f = (a+c)/2, (b+d)/2
|
|
686
|
+
lambd = (self.te.x + 0.05-px)/e
|
|
687
|
+
new = Point(self.te.x + 0.05, py+lambd*f, 0, self.mesh_size)
|
|
688
|
+
|
|
689
|
+
if not nothing:
|
|
690
|
+
# Now insert the point in th list of points and change the index for te to be the new point
|
|
691
|
+
self.points.insert(te_down_indx, new)
|
|
692
|
+
self.te = new
|
|
693
|
+
self.te_indx = te_down_indx
|
|
575
694
|
|
|
576
695
|
def gen_skin(self):
|
|
577
696
|
"""
|
|
578
|
-
Method to generate the
|
|
697
|
+
Method to generate the three splines forming the foil, Only call this function when the points
|
|
579
698
|
of the airfoil are in their final position
|
|
580
699
|
-------
|
|
581
700
|
"""
|
|
582
|
-
#
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
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
|
+
|
|
711
|
+
# create a spline from the up middle point to the trailing edge (up part)
|
|
712
|
+
self.upper_spline = Spline(
|
|
713
|
+
self.points[k1: self.te_indx + 1])
|
|
714
|
+
|
|
715
|
+
# create a spline from the trailing edge to the up down point (down part)
|
|
716
|
+
self.lower_spline = Spline(
|
|
717
|
+
self.points[self.te_indx:k2+1]
|
|
718
|
+
)
|
|
590
719
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
)
|
|
596
|
-
# create a spline from the trailing edge to the leading edge
|
|
597
|
-
self.lower_spline = Spline(self.points[self.te_indx : self.le_indx + 1])
|
|
720
|
+
# Create a spline for the front part of the airfoil
|
|
721
|
+
self.front_spline = Spline(self.points[k2:]+self.points[:k1+1])
|
|
722
|
+
|
|
723
|
+
return k1, k2
|
|
598
724
|
|
|
725
|
+
def gen_skin_struct(self, k1, k2):
|
|
726
|
+
"""
|
|
727
|
+
Method to generate the two splines forming the foil for structural mesh, Only call this function when the points
|
|
728
|
+
of the airfoil are in their final position
|
|
729
|
+
-------
|
|
730
|
+
"""
|
|
731
|
+
# create a spline from the up middle point to the trailing edge (up part)
|
|
732
|
+
self.upper_spline = Spline(
|
|
733
|
+
self.points[k1: self.te_indx + 1])
|
|
734
|
+
|
|
735
|
+
# create a spline from the trailing edge to the up down point (down part)
|
|
736
|
+
self.lower_spline = Spline(
|
|
737
|
+
self.points[self.te_indx:k2+1]
|
|
738
|
+
)
|
|
599
739
|
return self.upper_spline, self.lower_spline
|
|
600
|
-
# form the curvedloop
|
|
601
740
|
|
|
602
741
|
def close_loop(self):
|
|
603
742
|
"""
|
|
@@ -608,7 +747,7 @@ class AirfoilSpline:
|
|
|
608
747
|
_ : int
|
|
609
748
|
return the tag of the CurveLoop object
|
|
610
749
|
"""
|
|
611
|
-
return CurveLoop([self.upper_spline, self.lower_spline]).tag
|
|
750
|
+
return CurveLoop([self.upper_spline, self.lower_spline, self.front_spline]).tag
|
|
612
751
|
|
|
613
752
|
def define_bc(self):
|
|
614
753
|
"""
|
|
@@ -617,13 +756,14 @@ class AirfoilSpline:
|
|
|
617
756
|
"""
|
|
618
757
|
|
|
619
758
|
self.bc = gmsh.model.addPhysicalGroup(
|
|
620
|
-
self.dim, [self.upper_spline.tag,
|
|
759
|
+
self.dim, [self.upper_spline.tag,
|
|
760
|
+
self.lower_spline.tag, self.front_spline.tag]
|
|
621
761
|
)
|
|
622
762
|
gmsh.model.setPhysicalName(self.dim, self.bc, self.name)
|
|
623
763
|
|
|
624
764
|
def rotation(self, angle, origin, axis):
|
|
625
765
|
"""
|
|
626
|
-
|
|
766
|
+
Method to rotate the object AirfoilSpline
|
|
627
767
|
...
|
|
628
768
|
|
|
629
769
|
Parameters
|
|
@@ -636,10 +776,11 @@ class AirfoilSpline:
|
|
|
636
776
|
tuple of point (x,y,z) which represent the axis of rotation
|
|
637
777
|
"""
|
|
638
778
|
[point.rotation(angle, origin, axis) for point in self.points]
|
|
779
|
+
gmsh.model.geo.synchronize()
|
|
639
780
|
|
|
640
781
|
def translation(self, vector):
|
|
641
782
|
"""
|
|
642
|
-
|
|
783
|
+
Method to translate the object AirfoilSpline
|
|
643
784
|
...
|
|
644
785
|
|
|
645
786
|
Parameters
|
|
@@ -654,7 +795,6 @@ class PlaneSurface:
|
|
|
654
795
|
"""
|
|
655
796
|
A class to represent the PlaneSurface geometrical object of gmsh
|
|
656
797
|
|
|
657
|
-
|
|
658
798
|
...
|
|
659
799
|
|
|
660
800
|
Attributes
|
|
@@ -671,12 +811,12 @@ class PlaneSurface:
|
|
|
671
811
|
|
|
672
812
|
self.geom_objects = geom_objects
|
|
673
813
|
# close_loop() will form a close loop object and return its tag
|
|
674
|
-
self.tag_list = [geom_object.close_loop()
|
|
675
|
-
|
|
814
|
+
self.tag_list = [geom_object.close_loop()
|
|
815
|
+
for geom_object in self.geom_objects]
|
|
676
816
|
self.dim = 2
|
|
677
817
|
|
|
678
818
|
# create the gmsh object and store the tag of the geometric object
|
|
679
|
-
self.tag = gmsh.model.
|
|
819
|
+
self.tag = gmsh.model.geo.addPlaneSurface(self.tag_list)
|
|
680
820
|
|
|
681
821
|
def define_bc(self):
|
|
682
822
|
"""
|
|
@@ -685,3 +825,365 @@ class PlaneSurface:
|
|
|
685
825
|
"""
|
|
686
826
|
self.ps = gmsh.model.addPhysicalGroup(self.dim, [self.tag])
|
|
687
827
|
gmsh.model.setPhysicalName(self.dim, self.ps, "fluid")
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
def outofbounds(airfoil, box, radius, blthick):
|
|
831
|
+
"""Method that checks if the boundary layer or airfoil goes out of the box/farfield
|
|
832
|
+
(which is a problem for meshing later)
|
|
833
|
+
|
|
834
|
+
Args:
|
|
835
|
+
cloud_points (AirfoilSpline):
|
|
836
|
+
The AirfoilSpline containing the points
|
|
837
|
+
box (string):
|
|
838
|
+
the box arguments received by the parser (float x float)
|
|
839
|
+
radius (float):
|
|
840
|
+
radius of the farfield
|
|
841
|
+
blthick (float):
|
|
842
|
+
total thickness of the boundary layer (0 for mesh without bl)
|
|
843
|
+
"""
|
|
844
|
+
if box:
|
|
845
|
+
length, width = [float(value) for value in box.split("x")]
|
|
846
|
+
# Compute the min and max values in the x and y directions
|
|
847
|
+
minx = min(p.x for p in airfoil.points)
|
|
848
|
+
maxx = max(p.x for p in airfoil.points)
|
|
849
|
+
miny = min(p.y for p in airfoil.points)
|
|
850
|
+
maxy = max(p.y for p in airfoil.points)
|
|
851
|
+
# Check :
|
|
852
|
+
# If the max-0.5 (which is just recentering the airfoil in 0)+bl thickness value is bigger than length/2 --> too far right.
|
|
853
|
+
# Same with min and left. (minx & maxx should be 0 & 1 but we recompute to be sure)
|
|
854
|
+
# Same in y.
|
|
855
|
+
if abs(maxx-0.5)+abs(blthick) > length/2 or abs(minx-0.5)+abs(blthick) > length/2 or abs(maxy)+abs(blthick) > width/2 or abs(miny)+abs(blthick) > width/2:
|
|
856
|
+
print("\nThe boundary layer or airfoil is bigger than the box, exiting")
|
|
857
|
+
print(
|
|
858
|
+
"You must change the boundary layer parameters or choose a bigger box\n")
|
|
859
|
+
sys.exit()
|
|
860
|
+
else:
|
|
861
|
+
# Compute the further from (0.5,0,0) a point is (norm of (x-0.5,y))
|
|
862
|
+
maxr = math.sqrt(max((p.x-0.5)*(p.x-0.5)+p.y*p.y
|
|
863
|
+
for p in airfoil.points))
|
|
864
|
+
# Check if furthest + bl is bigger than radius
|
|
865
|
+
if maxr+abs(blthick) > radius:
|
|
866
|
+
print("\nThe boundary layer or airfoil is bigger than the circle, exiting")
|
|
867
|
+
print(
|
|
868
|
+
"You must change the boundary layer parameters or choose a bigger radius\n")
|
|
869
|
+
sys.exit()
|
|
870
|
+
|
|
871
|
+
|
|
872
|
+
class CType:
|
|
873
|
+
"""
|
|
874
|
+
A class to represent a C-type structured mesh.
|
|
875
|
+
"""
|
|
876
|
+
|
|
877
|
+
def __init__(self, airfoil_spline, dx_trail, dy, mesh_size, height, ratio, aoa):
|
|
878
|
+
z = 0
|
|
879
|
+
self.airfoil_spline = airfoil_spline
|
|
880
|
+
|
|
881
|
+
self.dx_trail = dx_trail
|
|
882
|
+
self.dy = dy
|
|
883
|
+
|
|
884
|
+
self.mesh_size = mesh_size
|
|
885
|
+
# Because all the computations are based on the mesh size at the trailing edge which is the biggest accross the whole airfoil, we take it bigger
|
|
886
|
+
# so that the mesh size is right mostly on the middle of the airfoil
|
|
887
|
+
mesh_size_end = mesh_size*2
|
|
888
|
+
self.mesh_size_end = mesh_size_end
|
|
889
|
+
|
|
890
|
+
self.firstheight = height
|
|
891
|
+
self.ratio = ratio
|
|
892
|
+
self.aoa = aoa
|
|
893
|
+
|
|
894
|
+
# First compute k1 & k2 the first coordinate after 0.041 (up & down)
|
|
895
|
+
debut = True
|
|
896
|
+
for p in airfoil_spline.points:
|
|
897
|
+
if p.x > 0.041 and debut:
|
|
898
|
+
k1 = airfoil_spline.points.index(p)
|
|
899
|
+
debut = False
|
|
900
|
+
if p.x <= 0.041 and not debut:
|
|
901
|
+
k2 = airfoil_spline.points.index(p)-1
|
|
902
|
+
break
|
|
903
|
+
|
|
904
|
+
upper_spline_back, lower_spline_back = self.airfoil_spline.gen_skin_struct(
|
|
905
|
+
k1, k2)
|
|
906
|
+
self.le_upper_point = airfoil_spline.points[k1]
|
|
907
|
+
self.le_lower_point = airfoil_spline.points[k2]
|
|
908
|
+
|
|
909
|
+
# Create the new front spline (from the two front parts)
|
|
910
|
+
upper_points_front = airfoil_spline.points[:k1+1]
|
|
911
|
+
lower_points_front = airfoil_spline.points[k2:]
|
|
912
|
+
points_front = lower_points_front + upper_points_front
|
|
913
|
+
points_front_tag = [point.tag for point in points_front]
|
|
914
|
+
spline_front = gmsh.model.geo.addSpline(points_front_tag)
|
|
915
|
+
self.spline_front, self.upper_spline_back, self.lower_spline_back = spline_front, upper_spline_back, lower_spline_back
|
|
916
|
+
|
|
917
|
+
# Create points on the outside domain (& center point)
|
|
918
|
+
# p1 p2 p3
|
|
919
|
+
# -------------------------------------------
|
|
920
|
+
# / \ | |
|
|
921
|
+
# / \ | |
|
|
922
|
+
# / \ | | *1 : dx_wake
|
|
923
|
+
# / /00000000000000\ | | *2 : dy (total height)
|
|
924
|
+
# ( (0000000(p0)0000000)|-----------------| p4
|
|
925
|
+
# \ \00000000000000/ | *1 |*2
|
|
926
|
+
# \ / | |
|
|
927
|
+
# \ / | |
|
|
928
|
+
# \ / | |
|
|
929
|
+
# ------------------------------------------- p5
|
|
930
|
+
# p7 p6
|
|
931
|
+
|
|
932
|
+
# We want the line to p1 to be perpendicular to airfoil for better boundary layer, and same for p2
|
|
933
|
+
# We compute the normal to the line linking the points before and after our point of separation (point[k1]&point[k2])
|
|
934
|
+
xup, yup, xdown, ydown = airfoil_spline.points[k1].x, airfoil_spline.points[
|
|
935
|
+
k1].y, airfoil_spline.points[k2].x, airfoil_spline.points[k2].y
|
|
936
|
+
xupbefore, yupbefore, xupafter, yupafter = airfoil_spline.points[
|
|
937
|
+
k1-1].x, airfoil_spline.points[k1-1].y, airfoil_spline.points[k1+1].x, airfoil_spline.points[k1+1].y
|
|
938
|
+
xdownbefore, ydownbefore, xdownafter, ydownafter = airfoil_spline.points[
|
|
939
|
+
k2-1].x, airfoil_spline.points[k2-1].y, airfoil_spline.points[k2+1].x, airfoil_spline.points[k2+1].y
|
|
940
|
+
directionupx, directionupy, directiondownx, directiondowny = yupbefore - \
|
|
941
|
+
yupafter, xupafter-xupbefore, ydownafter-ydownbefore, xdownbefore-xdownafter
|
|
942
|
+
# As the points coordinates we get are not rotated, we need to change it by hand
|
|
943
|
+
cos, sin = math.cos(aoa), math.sin(aoa)
|
|
944
|
+
directionupx, directionupy, directiondownx, directiondowny = cos*directionupx-sin * directionupy, sin * \
|
|
945
|
+
directionupx+cos * directionupy, cos*directiondownx-sin * \
|
|
946
|
+
directiondowny, sin*directiondownx+cos * directiondowny
|
|
947
|
+
xup, yup, xdown, ydown = cos*xup-sin*yup, sin*xup + \
|
|
948
|
+
cos*yup, cos*xdown-sin*ydown, sin*xdown+cos*ydown
|
|
949
|
+
|
|
950
|
+
# Then compute where the line in this direction going from point[k1] intersect the line y=dy/2 (i.e. the horizontal line where we want L1)
|
|
951
|
+
pt1x, pt1y, pt7x, pt7y = xup+(dy/2-yup)/directionupy*directionupx, dy/2, xdown + \
|
|
952
|
+
(0-dy/2-ydown)/directiondowny*directiondownx, -dy/2
|
|
953
|
+
# Check that the line doesn't go "back" or "too far", and constrain it to go between le-0.05*dy and le-3.5
|
|
954
|
+
pt1x = max(min(pt1x, airfoil_spline.le.x-0.05*dy),
|
|
955
|
+
airfoil_spline.le.x-3.5)
|
|
956
|
+
pt7x = max(min(pt7x, airfoil_spline.le.x-0.05*dy),
|
|
957
|
+
airfoil_spline.le.x-3.5)
|
|
958
|
+
# Compute the center of the circle : we want a x coordinate of 0.5, and compute cy so that p1 and p7 are at same distance from the (0.5,cy)
|
|
959
|
+
centery = (pt1y+pt7y)/2 + (0.5-(pt1x+pt7x)/2)/(pt1y-pt7y)*(pt7x-pt1x)
|
|
960
|
+
|
|
961
|
+
# Create the 8 points we wanted
|
|
962
|
+
self.points = [
|
|
963
|
+
Point(0.5, centery, z, self.mesh_size_end), # 0
|
|
964
|
+
Point(pt1x, pt1y, z, self.mesh_size_end), # 1
|
|
965
|
+
Point(self.airfoil_spline.te.x, self.dy /
|
|
966
|
+
2, z, self.mesh_size_end), # 2
|
|
967
|
+
Point(self.airfoil_spline.te.x + self.dx_trail,
|
|
968
|
+
self.dy / 2, z, self.mesh_size_end), # 3
|
|
969
|
+
Point(self.airfoil_spline.te.x + self.dx_trail,
|
|
970
|
+
self.airfoil_spline.te.y, z, self.mesh_size_end), # 4
|
|
971
|
+
Point(self.airfoil_spline.te.x + self.dx_trail, -
|
|
972
|
+
self.dy / 2, z, self.mesh_size_end), # 5
|
|
973
|
+
Point(self.airfoil_spline.te.x, -
|
|
974
|
+
self.dy / 2, z, self.mesh_size_end), # 6
|
|
975
|
+
Point(pt7x, pt7y, z, self.mesh_size_end), # 7
|
|
976
|
+
]
|
|
977
|
+
|
|
978
|
+
# Create all the lines : outside and surface separation
|
|
979
|
+
self.lines = [
|
|
980
|
+
Line(self.le_upper_point, self.points[1]), # 0
|
|
981
|
+
Line(self.points[1], self.points[2]), # 1
|
|
982
|
+
Line(self.points[2], self.points[3]), # 2
|
|
983
|
+
Line(self.points[3], self.points[4]), # 3
|
|
984
|
+
Line(self.points[4], self.points[5]), # 4
|
|
985
|
+
Line(self.points[5], self.points[6]), # 5
|
|
986
|
+
Line(self.points[6], self.points[7]), # 6
|
|
987
|
+
Line(self.points[7], self.le_lower_point), # 7
|
|
988
|
+
Line(self.airfoil_spline.te, self.points[2]), # 8
|
|
989
|
+
Line(self.airfoil_spline.te, self.points[6]), # 9
|
|
990
|
+
Line(self.points[4], self.airfoil_spline.te), # 10
|
|
991
|
+
]
|
|
992
|
+
|
|
993
|
+
# Circle arc for C shape at the front
|
|
994
|
+
self.circle_arc = gmsh.model.geo.addCircleArc(
|
|
995
|
+
self.points[7].tag, self.points[0].tag, self.points[1].tag)
|
|
996
|
+
|
|
997
|
+
# planar surfaces for structured grid are named from A-E
|
|
998
|
+
# straight lines are numbered from L0 to L10
|
|
999
|
+
#
|
|
1000
|
+
# --------------------------------------
|
|
1001
|
+
# / \ L1 | L2 |
|
|
1002
|
+
# circ / \L0 B | C |
|
|
1003
|
+
# / A \ L8| |L3 *1 : dx_wake
|
|
1004
|
+
# / /00000000000000\ | *1 | *2 : dy
|
|
1005
|
+
# ( (000000000000000000)|-------------|
|
|
1006
|
+
# \ \00000000000000/ | L10 |*2
|
|
1007
|
+
# \ / | |
|
|
1008
|
+
# \ /L7 E L9| D |L4
|
|
1009
|
+
# \ / | |
|
|
1010
|
+
# --------------------------------------
|
|
1011
|
+
# L6 L5
|
|
1012
|
+
|
|
1013
|
+
# Now we compute all of the parameters to have smooth mesh around mesh size
|
|
1014
|
+
|
|
1015
|
+
# HEIGHT
|
|
1016
|
+
# Compute number of nodes needed to have the desired first layer height (=nb of layer (N) +1)
|
|
1017
|
+
# Computation : we have that dy/2 is total height, and let a=first layer height
|
|
1018
|
+
# dy/2= a + a*ratio + a*ratio^2 + ... + a*ratio^(N-1) and rearrange to get the following equation
|
|
1019
|
+
nb_points_y = 3+int(math.log(1+dy/2/height*(ratio-1))/math.log(ratio))
|
|
1020
|
+
progression_y = ratio
|
|
1021
|
+
progression_y_inv = 1/ratio
|
|
1022
|
+
|
|
1023
|
+
# WAKE
|
|
1024
|
+
# Set a progression to adapt slightly the wake (don't need as much precision further away from airfoil)
|
|
1025
|
+
progression_wake = 1/1.025
|
|
1026
|
+
progression_wake_inv = 1.025
|
|
1027
|
+
# Set number of points in x direction at wake to get desired meshsize on the one next to airfoil
|
|
1028
|
+
# (solve dx_trail = meshsize + meshsize*1.02 + meshsize*1.02^2 + ... + meshsize*1.02^(N-1) with N=nb of intervals)
|
|
1029
|
+
nb_points_wake = int(
|
|
1030
|
+
math.log(1+dx_trail*0.025/mesh_size_end)/math.log(1.025))+1
|
|
1031
|
+
|
|
1032
|
+
# AIRFOIL CENTER
|
|
1033
|
+
# 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
|
|
1034
|
+
if mesh_size_end > 0.05:
|
|
1035
|
+
coeffdiv = 4
|
|
1036
|
+
elif mesh_size_end >= 0.03:
|
|
1037
|
+
coeffdiv = 3
|
|
1038
|
+
else:
|
|
1039
|
+
coeffdiv = 2
|
|
1040
|
+
a, b, l = mesh_size_end/coeffdiv, mesh_size_end, airfoil_spline.te.x
|
|
1041
|
+
# 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)
|
|
1042
|
+
ratio_airfoil = (l-a)/(l-b)
|
|
1043
|
+
if l-b < 0:
|
|
1044
|
+
nb_airfoil = 3
|
|
1045
|
+
else:
|
|
1046
|
+
nb_airfoil = max(3, int(math.log(b/a)/math.log(ratio_airfoil))+2)
|
|
1047
|
+
|
|
1048
|
+
# AIRFOIL FRONT
|
|
1049
|
+
# Now we can try to put the good number of point on the front to have a good mesh
|
|
1050
|
+
# First we estimate the length of the spline
|
|
1051
|
+
x, y, v, w = airfoil_spline.points[k1].x, airfoil_spline.points[
|
|
1052
|
+
k2].y, airfoil_spline.points[k1].x, airfoil_spline.points[k2].y
|
|
1053
|
+
c1, c2 = airfoil_spline.le.x, airfoil_spline.le.y
|
|
1054
|
+
estim_length = (math.sqrt((x-c1)*(x-c1)+(y-c2)*(y-c2)) +
|
|
1055
|
+
math.sqrt((v-c1)*(v-c1)+(w-c2)*(w-c2)))+0.01
|
|
1056
|
+
# 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)
|
|
1057
|
+
nb_airfoil_front = max(
|
|
1058
|
+
4, int(estim_length/mesh_size_end*coeffdiv*3))+4
|
|
1059
|
+
|
|
1060
|
+
# Now we set all the corresponding transfinite curve we need (with our coefficient computed before)
|
|
1061
|
+
|
|
1062
|
+
# transfinite curve A
|
|
1063
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1064
|
+
self.lines[7].tag, nb_points_y, "Progression", progression_y_inv) # same for plane E
|
|
1065
|
+
if mesh_size_end < 0.04:
|
|
1066
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1067
|
+
spline_front, nb_airfoil_front, "Bump", 12)
|
|
1068
|
+
else:
|
|
1069
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1070
|
+
spline_front, nb_airfoil_front, "Bump", 7)
|
|
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)
|
|
1081
|
+
|
|
1082
|
+
# 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
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1090
|
+
self.lines[1].tag, nb_airfoil, "Progression", 1/ratio_airfoil)
|
|
1091
|
+
elif pt1x < airfoil_spline.le.x-0.7:
|
|
1092
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1093
|
+
self.lines[1].tag, nb_airfoil, "Progression", 1/math.sqrt(ratio_airfoil))
|
|
1094
|
+
else:
|
|
1095
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1096
|
+
self.lines[1].tag, nb_airfoil)
|
|
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:
|
|
1119
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1120
|
+
self.lines[6].tag, nb_airfoil, "Progression", ratio_airfoil)
|
|
1121
|
+
elif pt7x < airfoil_spline.le.x-0.4:
|
|
1122
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1123
|
+
self.lines[6].tag, nb_airfoil, "Progression", math.sqrt(ratio_airfoil))
|
|
1124
|
+
else:
|
|
1125
|
+
gmsh.model.geo.mesh.setTransfiniteCurve(
|
|
1126
|
+
self.lines[6].tag, nb_airfoil)
|
|
1127
|
+
|
|
1128
|
+
# Now we add the surfaces
|
|
1129
|
+
|
|
1130
|
+
# transfinite surface A (forces structured mesh)
|
|
1131
|
+
c1 = gmsh.model.geo.addCurveLoop(
|
|
1132
|
+
[self.lines[7].tag, spline_front, self.lines[0].tag, - self.circle_arc])
|
|
1133
|
+
surf1 = gmsh.model.geo.addPlaneSurface([c1])
|
|
1134
|
+
gmsh.model.geo.mesh.setTransfiniteSurface(surf1)
|
|
1135
|
+
|
|
1136
|
+
# transfinite surface B
|
|
1137
|
+
c2 = gmsh.model.geo.addCurveLoop(
|
|
1138
|
+
[self.lines[0].tag, self.lines[1].tag, - self.lines[8].tag, - upper_spline_back.tag])
|
|
1139
|
+
surf2 = gmsh.model.geo.addPlaneSurface([c2])
|
|
1140
|
+
gmsh.model.geo.mesh.setTransfiniteSurface(surf2)
|
|
1141
|
+
|
|
1142
|
+
# transfinite surface C
|
|
1143
|
+
c3 = gmsh.model.geo.addCurveLoop(
|
|
1144
|
+
[self.lines[8].tag, self.lines[2].tag, self.lines[3].tag, self.lines[10].tag])
|
|
1145
|
+
surf3 = gmsh.model.geo.addPlaneSurface([c3])
|
|
1146
|
+
gmsh.model.geo.mesh.setTransfiniteSurface(surf3)
|
|
1147
|
+
|
|
1148
|
+
# transfinite surface D
|
|
1149
|
+
c4 = gmsh.model.geo.addCurveLoop(
|
|
1150
|
+
[- self.lines[9].tag, - self.lines[10].tag, self.lines[4].tag, self.lines[5].tag])
|
|
1151
|
+
surf4 = gmsh.model.geo.addPlaneSurface([c4])
|
|
1152
|
+
gmsh.model.geo.mesh.setTransfiniteSurface(surf4)
|
|
1153
|
+
|
|
1154
|
+
# transfinite surface E
|
|
1155
|
+
c5 = gmsh.model.geo.addCurveLoop(
|
|
1156
|
+
[self.lines[7].tag, - lower_spline_back.tag, self.lines[9].tag, self.lines[6].tag])
|
|
1157
|
+
surf5 = gmsh.model.geo.addPlaneSurface([c5])
|
|
1158
|
+
gmsh.model.geo.mesh.setTransfiniteSurface(surf5)
|
|
1159
|
+
self.curveloops = [c1, c2, c3, c4, c5]
|
|
1160
|
+
self.surfaces = [surf1, surf2, surf3, surf4, surf5]
|
|
1161
|
+
|
|
1162
|
+
# Lastly, recombine surface to create quadrilateral elements
|
|
1163
|
+
gmsh.model.geo.mesh.setRecombine(2, surf1, 90)
|
|
1164
|
+
gmsh.model.geo.mesh.setRecombine(2, surf2, 90)
|
|
1165
|
+
gmsh.model.geo.mesh.setRecombine(2, surf3, 90)
|
|
1166
|
+
gmsh.model.geo.mesh.setRecombine(2, surf4, 90)
|
|
1167
|
+
gmsh.model.geo.mesh.setRecombine(2, surf5, 90)
|
|
1168
|
+
|
|
1169
|
+
def define_bc(self):
|
|
1170
|
+
"""
|
|
1171
|
+
Method that define the domain marker of the surface, the airfoil and the farfield
|
|
1172
|
+
-------
|
|
1173
|
+
"""
|
|
1174
|
+
|
|
1175
|
+
# Airfoil
|
|
1176
|
+
self.bc = gmsh.model.addPhysicalGroup(
|
|
1177
|
+
1, [self.upper_spline_back.tag,
|
|
1178
|
+
self.lower_spline_back.tag, self.spline_front]
|
|
1179
|
+
)
|
|
1180
|
+
gmsh.model.setPhysicalName(1, self.bc, "airfoil")
|
|
1181
|
+
|
|
1182
|
+
# Farfield
|
|
1183
|
+
self.bc = gmsh.model.addPhysicalGroup(1, [self.lines[1].tag, self.lines[2].tag,
|
|
1184
|
+
self.lines[3].tag, self.lines[4].tag, self.lines[5].tag, self.lines[6].tag, self.circle_arc])
|
|
1185
|
+
gmsh.model.setPhysicalName(1, self.bc, "farfield")
|
|
1186
|
+
|
|
1187
|
+
# Surface
|
|
1188
|
+
self.bc = gmsh.model.addPhysicalGroup(2, self.surfaces)
|
|
1189
|
+
gmsh.model.setPhysicalName(2, self.bc, "fluid")
|