From 878dd3bc591ff8942d4c1bcadf7e939458d93269 Mon Sep 17 00:00:00 2001 From: acrovato <39187559+acrovato@users.noreply.github.com> Date: Sat, 30 Mar 2019 11:47:10 +0100 Subject: [PATCH 1/6] Add sphere domain for SU2 support. Add print --- config/onera.py | 11 +--- config/rae.py | 1 + box.py => domain.py | 154 ++++++++++++++++++++++++++++++++++++++++++-- geoGen.py | 53 +++++++++++---- shippable.yml | 3 +- tip.py | 18 +++++- wake.py | 44 ++++++++++++- wing.py | 21 +++++- 8 files changed, 275 insertions(+), 30 deletions(-) rename box.py => domain.py (62%) diff --git a/config/onera.py b/config/onera.py index ae2dee0..ee4868d 100644 --- a/config/onera.py +++ b/config/onera.py @@ -17,13 +17,8 @@ def getParams(): p['twist'] = [0, 0] # twist angle of each airfoil (size: nP+1) p['rootChord'] = 0.8059 # root chord p['coWingtip'] = True # cut-off wingtip (not supported yet) - # Box - p['xoBox'] = -3.5*p['rootChord'] - p['xfBox'] = 4.5*p['rootChord'] - p['yfBox'] = 2*sum(p['span']) - p['zoBox'] = -3.5*p['rootChord'] - p['zfBox'] = 3.5*p['rootChord'] - # Wake - p['nSlope'] = 10 # number of airfoil TE points to compute wake slope + # Sphere + p['domType'] = 'sphere' # domain type ('sphere' or 'box') + p['rSphere'] = 50*p['rootChord'] return p diff --git a/config/rae.py b/config/rae.py index 5cfdfcf..9aefbc5 100644 --- a/config/rae.py +++ b/config/rae.py @@ -18,6 +18,7 @@ def getParams(): p['rootChord'] = 1.0 # root chord p['coWingtip'] = True # cut-off wingtip (not supported yet) # Box + p['domType'] = 'box' # domain type ('sphere' or 'box') p['xoBox'] = -3.5*p['rootChord'] p['xfBox'] = 4.5*p['rootChord'] p['yfBox'] = 2*sum(p['span']) diff --git a/box.py b/domain.py similarity index 62% rename from box.py rename to domain.py index 84579fe..fff8d94 100644 --- a/box.py +++ b/domain.py @@ -1,6 +1,22 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# + +''' +Copyright 2019 University of Liege + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +''' + ## @package GeoGen (CFD basic grid creator) # # Create an unstructured tetrahedral grid around a wing @@ -9,13 +25,134 @@ import numpy as np -## Handle box data +## Generic domain class # # Adrien Crovato -class Box: - def __init__(self, xO, xF, yF, zO, zF, _wing, _tip, _wake): +class Domain: + def __init__(self, _wing, _tip): self.wing = _wing self.tip = _tip + +## Handle sphere data +# +# Adrien Crovato +class Sphere(Domain): + def __init__(self, R, _wing, _tip): + Domain.__init__(self, _wing, _tip) + self.initData(R) + + def initData(self, R): + """Initialize data, define numbering + """ + self.pts = [np.array([[R+self.wing.chord[0], 0., 0.], + [0., 0., R], + [-R+self.wing.chord[0], 0., 0.], + [0., 0., -R]]), + np.array([[self.wing.chord[0], R, 0.]])] + self.ptsN = [np.arange(5000, 5004), np.array([5004])] + + # lines (2*4 lines: 191-194 and 195-198) + self.linN = [np.arange(191, 195), np.arange(195, 199)] + + # surface (5 surfaces: 111-115) + self.surN = [np.arange(111, 116)] + + def writeInfo(self, fname): + """Write sphere geometrical parameters + """ + file = open(fname, 'a') + file.write('// --- Domain geometry ---\n') + file.write('// Sphere radius: {0:f}\n'.format(self.pts[0][0,0]-self.wing.pts[0][0,0])) + file.write('\n') + file.close() + + def writeOpts(self, fname): + """Write sphere gmsh options + """ + file = open(fname, 'a') + file.write('// --- Domain options ---\n') + file.write('DefineConstant[ msF = {{ {0:f}, Name "Farfield mesh size" }} ];\n'.format(10*self.wing.chord[0])) + file.write('\n') + file.close() + + def writePoints(self, fname): + """Write sphere points + """ + file = open(fname, 'a') + file.write('// --- Sphere points ---\n') + for j in range(0,4): + file.write('Point({0:d}) = {{{1:f},{2:f},{3:f},msF}};\n'.format(self.ptsN[0][j], self.pts[0][j,0], self.pts[0][j,1], self.pts[0][j,2])) + file.write('Point({0:d}) = {{{1:f},{2:f},{3:f},msF}};\n'.format(self.ptsN[1][0], self.pts[1][0,0], self.pts[1][0,1], self.pts[1][0,2])) + file.write('\n') + file.close() + + def writeLines(self, fname): + """Write sphere lines + """ + file = open(fname, 'a') + file.write('// --- Sphere lines ---\n') + for j in range(0, 4): + file.write('Circle({0:d}) = {{{1:d},{2:d},{3:d}}};\n'.format(self.linN[0][j], self.ptsN[0][j], self.wing.ptsN[0][0], self.ptsN[0][np.mod(j+1,4)])) + for j in range(0, 4): + file.write('Circle({0:d}) = {{{1:d},{2:d},{3:d}}};\n'.format(self.linN[1][j], self.ptsN[0][j], self.wing.ptsN[0][0], self.ptsN[1][0])) + file.write('\n') + file.close() + + def writeSurfaces(self, fname): + """Write sphere surfaces + """ + file = open(fname, 'a') + file.write('// --- Sphere surfaces ---\n') + # line loops + for j in range(0, 4): + file.write('Line Loop({0:d}) = {{{1:d},{2:d},{3:d}}};\n'.format(self.surN[0][j], self.linN[0][j], self.linN[1][np.mod(j+1,4)], -self.linN[1][j])) + file.write('Line Loop({0:d}) = {{{1:d},{2:d},{3:d},{4:d}}};\n'.format(self.surN[0][-1], self.linN[0][0], self.linN[0][1], self.linN[0][2], self.linN[0][3])) + file.write('Line Loop({0:d}) = {{{1:d},{2:d},{3:d},{4:d},{5:d},{6:d}}};\n'.format(self.surN[0][-1]+1, self.wing.linaN[0][0], self.wing.linaN[0][1], self.wing.linaN[0][2], self.wing.linaN[0][3], self.wing.linaN[0][4], self.wing.linaN[0][5])) + # surfaces + for j in range(0, 4): + file.write('Surface({0:d}) = {{{0:d}}};\n'.format(self.surN[0][j])) + file.write('Plane Surface({0:d}) = {{{0:d},{1:d}}};\n'.format(self.surN[0][-1], self.surN[0][-1]+1)) + file.write('\n') + file.close() + + def writeVolumes(self, fname): + """Write computational volume + """ + file = open(fname, 'a') + file.write('// --- Computational volumes ---\n') + # surface loops + file.write('Surface Loop({0:d}) = {{'.format(1)) + for i in range(0, self.wing.n-1): + for j in range(0, 6): + file.write('{0:d},'.format(self.wing.surN[i][j])) + for j in range(0, 6): + file.write('{0:d},'.format(self.tip.surN[0][j])) + for j in range(0, 4): + file.write('{0:d},'.format(self.surN[0][j])) + file.write('{0:d}}};\n'.format(self.surN[0][-1])) + + # volumes + file.write('Volume({0:d}) = {{{0:d}}};\n'.format(1)) + file.write('\n') + file.close() + + def writePhysical(self, fname): + """Write sphere physical groups + """ + file = open(fname, 'a') + file.write('// --- Box physical groups ---\n') + file.write('Physical Surface("symmetry") = {{{0:d}}};\n'.format(self.surN[0][-1])) + file.write('Physical Surface("farfield") = {{{0:d},{1:d},{2:d},{3:d}}};\n'.format(self.surN[0][0],self.surN[0][1],self.surN[0][2],self.surN[0][3])) + file.write('Physical Volume("field") = {{{0:d}}};\n'.format(1)) + file.write('\n') + file.close() + +## Handle box data +# +# Adrien Crovato +class Box(Domain): + def __init__(self, xO, xF, yF, zO, zF, _wing, _tip, _wake): + Domain.__init__(self, _wing, _tip) self.wake = _wake self.initData(xO, xF, yF, zO, zF) @@ -51,6 +188,15 @@ def writeInfo(self, fname): file.write('\n') file.close() + def writeOpts(self, fname): + """Write box gmsh options + """ + file = open(fname, 'a') + file.write('// --- Domain options ---\n') + file.write('DefineConstant[ msF = {{ {0:f}, Name "Farfield mesh size" }} ];\n'.format(0.5*self.wing.chord[0])) + file.write('\n') + file.close() + def writePoints(self, fname): """Write box points """ diff --git a/geoGen.py b/geoGen.py index c00a6dd..3eeac7c 100755 --- a/geoGen.py +++ b/geoGen.py @@ -1,6 +1,22 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# + +''' +Copyright 2019 University of Liege + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +''' + ## @package GeoGen (CFD basic grid creator) # # Create an unstructured tetrahedral grid around a wing @@ -10,20 +26,26 @@ import wing as w import tip as t import wake as wk -import box as b +import domain as d def main(_module, _output): # Get config p = getConfig(_module) - # Create wing, wingtip, wake and bounding box + # Create wing, wingtip, wake and bounding domain wing = w.Wing(p['airfName'], p['span'], p['taper'], p['sweep'], p['dihedral'], p['twist'], p['rootChord']) if p['coWingtip']: tip = t.CTip(wing) else: tip = t.RTip(wing) - wake = wk.Wake(p['xoBox'], p['xfBox'], p['yfBox'], p['nSlope'], wing, tip) - box = b.Box(p['xoBox'], p['xfBox'], p['yfBox'], p['zoBox'], p['zfBox'], wing, tip, wake) + if p['domType'] == 'box': + wake = wk.Wake(p['xoBox'], p['xfBox'], p['yfBox'], p['nSlope'], wing, tip) + dom = d.Box(p['xoBox'], p['xfBox'], p['yfBox'], p['zoBox'], p['zfBox'], wing, tip, wake) + elif p['domType'] == 'sphere': + wake = wk.GWake() + dom = d.Sphere(p['rSphere'], wing, tip) + else: + raise Exception('"domType" parameter can be either "box" or "sphere", but', p['domType'], 'was given!\n') # Switch to workspace and write createWdir() @@ -32,30 +54,31 @@ def main(_module, _output): writeHeader(outFile, _module) wing.writeInfo(outFile) tip.writeInfo(outFile) - box.writeInfo(outFile) + dom.writeInfo(outFile) wing.writeOpts(outFile) + dom.writeOpts(outFile) # points wing.writePoints(outFile) tip.writePoints(outFile) wake.writePoints(outFile) - box.writePoints(outFile) + dom.writePoints(outFile) # lines wing.writeLines(outFile) tip.writeLines(outFile) wake.writeLines(outFile) - box.writeLines(outFile) + dom.writeLines(outFile) # surfaces wing.writeSurfaces(outFile) tip.writeSurfaces(outFile) wake.writeSurfaces(outFile) - box.writeSurfaces(outFile) + dom.writeSurfaces(outFile) # volumes - box.writeVolumes(outFile) + dom.writeVolumes(outFile) # physical wing.writePhysical(outFile) tip.writePhysical(outFile) wake.writePhysical(outFile) - box.writePhysical(outFile) + dom.writePhysical(outFile) # mesh options writeOpts(outFile, p['coWingtip']) @@ -115,7 +138,15 @@ def printInfo(fname): """Print info """ import os + print '*' * 79 + print '* geoGen' + print '* Adrien Crovato' + print '* ULiege, 2018-2019' + print '* Distributed under Apache license 2.0' + print '*' * 79 print os.path.abspath(os.path.join(os.getcwd(), fname)), 'has been successfully written!' + print 'Visual file check in gmsh recommended before further use!' + print '*' * 79 if __name__ == "__main__": # Arguments parser diff --git a/shippable.yml b/shippable.yml index f0b333b..7f438e8 100644 --- a/shippable.yml +++ b/shippable.yml @@ -19,8 +19,9 @@ before_install: - sudo ln -s $PWD/gmsh-4.2.2-Linux64/bin/gmsh /usr/bin/gmsh script: + - python geoGen.py -m config/onera -o onera + - gmsh -3 workspace/onera.geo -o workspace/onera.msh - python geoGen.py -m config/rae -o rae - - ls workspace - gmsh -3 workspace/rae.geo -o workspace/rae.msh integrations: diff --git a/tip.py b/tip.py index b77d8fc..5c51ef8 100644 --- a/tip.py +++ b/tip.py @@ -1,6 +1,22 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# + +''' +Copyright 2019 University of Liege + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +''' + ## @package GeoGen (CFD basic grid creator) # # Create an unstructured tetrahedral grid around a wing diff --git a/wake.py b/wake.py index de665ab..f294046 100644 --- a/wake.py +++ b/wake.py @@ -1,6 +1,22 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# + +''' +Copyright 2019 University of Liege + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +''' + ## @package GeoGen (CFD basic grid creator) # # Create an unstructured tetrahedral grid around a wing @@ -9,10 +25,34 @@ import numpy as np +## Generic wake class (does nothing) +# +# Adrien Crovato +class GWake: + def __init__(self): + """Desc. + """ + + def writePoints(self, fname): + """Desc. + """ + + def writeLines(self, fname): + """Desc. + """ + + def writeSurfaces(self, fname): + """Desc. + """ + + def writePhysical(self, fname): + """Desc. + """ + ## Manage wake data # # Adrien Crovato -class Wake: +class Wake(GWake): def __init__(self, xO, xF, yF, nSlope, _wing, _tip): self.wing = _wing self.tip = _tip diff --git a/wing.py b/wing.py index 3eff11b..d48997c 100644 --- a/wing.py +++ b/wing.py @@ -1,6 +1,22 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# + +''' +Copyright 2019 University of Liege + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +''' + ## @package GeoGen (CFD basic grid creator) # # Create an unstructured tetrahedral grid around a wing @@ -57,7 +73,7 @@ def initData(self, filenames, span, twist, sweep, dihedral): size = aPts.shape[0] aPts = np.hstack((aPts, self.spanPos[i]*np.ones([size,1]))) aPts[:,[1,2]] = np.fliplr(aPts[:,[1,2]]) - aIdx = np.transpose(np.arange(i*500+1, i*500+1+size)) + aIdx = np.arange(i*500+1, i*500+1+size) self.pts.append(aPts) self.ptsN.append(aIdx) # transform coordinates @@ -148,7 +164,6 @@ def writeOpts(self, fname): file.write('DefineConstant[ msLe{0:1d} = {{ {1:f}, Name "leading edge mesh size on {2:1d}th spanwise station" }} ];\n'.format(i, self.chord[i]/100, i)) file.write('DefineConstant[ msTe{0:1d} = {{ {1:f}, Name "trailing edge mesh size on {2:1d}th spanwise station" }} ];\n'.format(i, self.chord[i]/100, i)) file.write('DefineConstant[ gr{0:1d} = {{ {1:f}, Name "growth ratio for {2:1d}th spanwise station" }} ];\n'.format(i, 1.5, i)) - file.write('DefineConstant[ msF = {{ {0:f}, Name "Farfield mesh size" }} ];\n'.format(0.5*self.chord[0])) file.write('\n') file.close() From 22e86e19409c6d97b207ce89ffeb182f056a067e Mon Sep 17 00:00:00 2001 From: acrovato <39187559+acrovato@users.noreply.github.com> Date: Sat, 30 Mar 2019 12:40:23 +0100 Subject: [PATCH 2/6] Updt readme --- README.md | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 364267e..f55b7f7 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,54 @@ ULiege, 2018-2019 ## Features and limitations ### What is GeoGen? -This is it! +GeoGen is a python code that generates an aerodynamic geometry which can then be meshed in gmsh and used in CFD solvers. + +### What can GeoGen do? +GeoGen currently supports the following configurations: + - [x] Arbitrary isolated wing + - [x] Sharp trailing edge + - [x] Cutoff wingtip + - [ ] Rounded wingtip + - [ ] Generic fuselage + - [ ] Horizontal tail + - [ ] Multibody (e.g. several isolated wings) +GeoGen was primarly designed to be used with [SU2](https://github.com/su2code/SU2) and [waves](https://github.com/ulgltas/waves), but any solver interfaced with [gmsh](http://gmsh.info/) can be used! ### Cite us! If you use this work, please acknowledge the authors: ```text -"GeoGen - a python/gmsh automated geometry generator for Flow and SU2 CFD solvers" by Adrien Crovato, University of Liege +"GeoGen - a python/gmsh automated geometry generator for CFD solvers" by Adrien Crovato, University of Liege ``` ## Usage +The script is run through the command line: +```sh +python geoGen.py -m path/to/config/file <-o path/to/output/file> +``` +Note that the extensions (.py and .geo) are automatically handled by the code and should to be provided in the path. +If no output file is provided, a workspace directory will be created and the geometry will be stored inside as grid.geo. + +The geometry is generated from a python file containing a dictionary of parameters. Examples are given in [config](config/) and the main options are summurized hereunder. +**Parameters** +Wing definition: + - airfPath: relative path to the airfoils directory + - airfName: array (size: nP+1) of names of file containing airfoil (Selig formatted) coordinates + - span: array (size: nP) of span for each planform of the wing + - taper: array (size: nP)) of taper of each planform of the wing + - sweep: array (size: nP) of leading edge sweep of each planform of the wing + - dihedral: array (size: nP) of dihedral angle of each planform of the wing + - twist: array (size: nP+1) of twist angle of each airfoil of the wing + - rootChord: root chord (scalar) of the wing + - coWingtip: boolean, True for cutoof wingtip, Fasle for rounded wingtip (not supported yet) +Domain definition: + - domType: string, box for box-shaped domain or shpere for shperical-shaped domain +if domain type is shpere, typical for Euler equations: + - rSphere: radius of the sphere (scalar) +if domain type is a box (a wake will then be defined), typically for potential equations: + - xoBox: x-coordinate (scalar) of the origin of the box + - xfBox: x-coordinate (scalar) of the end of the box + - yfBox: y-coordinate (scalar) of the end of the box + - zoBox: z-coordinate (scalar) of the origin of the box + - zfBox: z-coordinate (scalar) of the end of the box + - nSlope: number (scalar) of airfoil geometrical points counted from TE used to compute wake slope -### Input From b919aacf4fccc03c5c04127c3796dcb0459b01e9 Mon Sep 17 00:00:00 2001 From: acrovato <39187559+acrovato@users.noreply.github.com> Date: Tue, 2 Apr 2019 11:37:45 +0200 Subject: [PATCH 3/6] Add offset support --- README.md | 1 + config/onera.py | 1 + config/rae.py | 1 + domain.py | 20 ++++++++++++-------- geoGen.py | 2 +- wing.py | 10 +++++++--- 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index f55b7f7..ce9539b 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ Wing definition: - dihedral: array (size: nP) of dihedral angle of each planform of the wing - twist: array (size: nP+1) of twist angle of each airfoil of the wing - rootChord: root chord (scalar) of the wing + - offset: array of x and z offset (size: 2) applied to the leading edge of the root section - coWingtip: boolean, True for cutoof wingtip, Fasle for rounded wingtip (not supported yet) Domain definition: - domType: string, box for box-shaped domain or shpere for shperical-shaped domain diff --git a/config/onera.py b/config/onera.py index ee4868d..866a40f 100644 --- a/config/onera.py +++ b/config/onera.py @@ -16,6 +16,7 @@ def getParams(): p['dihedral'] = [0] # dihedral angle of each planform (size: nP) p['twist'] = [0, 0] # twist angle of each airfoil (size: nP+1) p['rootChord'] = 0.8059 # root chord + p['offset'] = [0., 0.] # x and z offset at the leading edge root p['coWingtip'] = True # cut-off wingtip (not supported yet) # Sphere p['domType'] = 'sphere' # domain type ('sphere' or 'box') diff --git a/config/rae.py b/config/rae.py index 9aefbc5..9e6e9eb 100644 --- a/config/rae.py +++ b/config/rae.py @@ -16,6 +16,7 @@ def getParams(): p['dihedral'] = [2., 1.] # dihedral angle of each planform (size: nP) p['twist'] = [1., 0, -1.] # twist angle of each airfoil (size: nP+1) p['rootChord'] = 1.0 # root chord + p['offset'] = [0., -0.1] # x and z offset at the leading edge root p['coWingtip'] = True # cut-off wingtip (not supported yet) # Box p['domType'] = 'box' # domain type ('sphere' or 'box') diff --git a/domain.py b/domain.py index fff8d94..ae96c0c 100644 --- a/domain.py +++ b/domain.py @@ -44,12 +44,13 @@ def __init__(self, R, _wing, _tip): def initData(self, R): """Initialize data, define numbering """ - self.pts = [np.array([[R+self.wing.chord[0], 0., 0.], + self.pts = [np.array([[self.wing.chord[0], 0., 0.]]), + np.array([[R+self.wing.chord[0], 0., 0.], [0., 0., R], [-R+self.wing.chord[0], 0., 0.], [0., 0., -R]]), np.array([[self.wing.chord[0], R, 0.]])] - self.ptsN = [np.arange(5000, 5004), np.array([5004])] + self.ptsN = [np.array([5001]), np.arange(5002, 5006), np.array([5007])] # lines (2*4 lines: 191-194 and 195-198) self.linN = [np.arange(191, 195), np.arange(195, 199)] @@ -62,7 +63,7 @@ def writeInfo(self, fname): """ file = open(fname, 'a') file.write('// --- Domain geometry ---\n') - file.write('// Sphere radius: {0:f}\n'.format(self.pts[0][0,0]-self.wing.pts[0][0,0])) + file.write('// Sphere radius: {0:f}\n'.format(self.pts[0][0,0]-self.wing.pts[1][0,0])) file.write('\n') file.close() @@ -80,9 +81,12 @@ def writePoints(self, fname): """ file = open(fname, 'a') file.write('// --- Sphere points ---\n') + file.write('// --- Center\n') + file.write('Point({0:d}) = {{{1:f},{2:f},{3:f},msF}};\n'.format(self.ptsN[0][0], self.pts[0][0,0], self.pts[0][0,1], self.pts[0][0,2])) + file.write('// --- Farfield\n') for j in range(0,4): - file.write('Point({0:d}) = {{{1:f},{2:f},{3:f},msF}};\n'.format(self.ptsN[0][j], self.pts[0][j,0], self.pts[0][j,1], self.pts[0][j,2])) - file.write('Point({0:d}) = {{{1:f},{2:f},{3:f},msF}};\n'.format(self.ptsN[1][0], self.pts[1][0,0], self.pts[1][0,1], self.pts[1][0,2])) + file.write('Point({0:d}) = {{{1:f},{2:f},{3:f},msF}};\n'.format(self.ptsN[1][j], self.pts[1][j,0], self.pts[1][j,1], self.pts[1][j,2])) + file.write('Point({0:d}) = {{{1:f},{2:f},{3:f},msF}};\n'.format(self.ptsN[2][0], self.pts[2][0,0], self.pts[2][0,1], self.pts[2][0,2])) file.write('\n') file.close() @@ -92,9 +96,9 @@ def writeLines(self, fname): file = open(fname, 'a') file.write('// --- Sphere lines ---\n') for j in range(0, 4): - file.write('Circle({0:d}) = {{{1:d},{2:d},{3:d}}};\n'.format(self.linN[0][j], self.ptsN[0][j], self.wing.ptsN[0][0], self.ptsN[0][np.mod(j+1,4)])) + file.write('Circle({0:d}) = {{{1:d},{2:d},{3:d}}};\n'.format(self.linN[0][j], self.ptsN[1][j], self.ptsN[0][0], self.ptsN[1][np.mod(j+1,4)])) for j in range(0, 4): - file.write('Circle({0:d}) = {{{1:d},{2:d},{3:d}}};\n'.format(self.linN[1][j], self.ptsN[0][j], self.wing.ptsN[0][0], self.ptsN[1][0])) + file.write('Circle({0:d}) = {{{1:d},{2:d},{3:d}}};\n'.format(self.linN[1][j], self.ptsN[1][j], self.ptsN[0][0], self.ptsN[2][0])) file.write('\n') file.close() @@ -168,7 +172,7 @@ def initData(self, xO, xF, yF, zO, zF): [xO, yF, zF], [xO, yF, zO], [xF, yF, zO]])] - self.ptsN = [np.arange(5000, 5004), np.arange(5004, 5008)] + self.ptsN = [np.arange(5001, 5005), np.arange(5005, 5009)] # line numbering (2*6 x lines: 191-203) AND (4 y lines: 205-209) self.linxN = [np.arange(191, 197), np.arange(197, 204)] diff --git a/geoGen.py b/geoGen.py index 3eeac7c..2217da9 100755 --- a/geoGen.py +++ b/geoGen.py @@ -33,7 +33,7 @@ def main(_module, _output): p = getConfig(_module) # Create wing, wingtip, wake and bounding domain - wing = w.Wing(p['airfName'], p['span'], p['taper'], p['sweep'], p['dihedral'], p['twist'], p['rootChord']) + wing = w.Wing(p['airfName'], p['span'], p['taper'], p['sweep'], p['dihedral'], p['twist'], p['rootChord'], p['offset']) if p['coWingtip']: tip = t.CTip(wing) else: diff --git a/wing.py b/wing.py index d48997c..f53f7ca 100644 --- a/wing.py +++ b/wing.py @@ -29,7 +29,7 @@ # # Adrien Crovato class Wing: - def __init__(self, filenames, span, taper, sweep, dihedral, twist, rootChord): + def __init__(self, filenames, span, taper, sweep, dihedral, twist, rootChord, offset): # Number of airfoils self.n = len(filenames) if self.n > 10: @@ -44,7 +44,7 @@ def __init__(self, filenames, span, taper, sweep, dihedral, twist, rootChord): self.compShape(span, taper, rootChord) # Create airfoil points and indices - self.initData(filenames, span, twist, sweep, dihedral) + self.initData(filenames, span, twist, sweep, dihedral, offset) def compShape(self, span, taper, rootChord): """Compute basic shape parameters of the wing @@ -62,7 +62,7 @@ def compShape(self, span, taper, rootChord): self.b = sum(span) self.AR = 2 * self.b*self.b/self.S - def initData(self, filenames, span, twist, sweep, dihedral): + def initData(self, filenames, span, twist, sweep, dihedral, offset): """Read, transform and store airfoil points, and define numbering """ self.pts = [] @@ -87,6 +87,10 @@ def initData(self, filenames, span, twist, sweep, dihedral): self.pts[i][:, 0] = self.pts[i][:, 0] + np.min(self.pts[i-1][:, 0]) + np.tan(sweep[i-1])*span[i-1] # apply dihedral (translatation) self.pts[i][:, 2] = self.pts[i][:, 2] + sum(np.tan(dihedral[0:i-1])*span[0:i-1]) + for i in range(0, self.n): + # apply offset + self.pts[i][:, 0] += offset[0] # x + self.pts[i][:, 2] += offset[1] # z # get separation points numbering self.sptsNl = [] self.sptsNg = [] # todo: remove since global index can be recovered from local index: ptsN[local] From 7272a103d742f51392819bddf410693c0efa841e Mon Sep 17 00:00:00 2001 From: acrovato <39187559+acrovato@users.noreply.github.com> Date: Wed, 3 Apr 2019 11:23:39 +0200 Subject: [PATCH 4/6] Corr 2 bugs. --- geoGen.py | 7 +++---- wake.py | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/geoGen.py b/geoGen.py index 2217da9..760d7e8 100755 --- a/geoGen.py +++ b/geoGen.py @@ -80,7 +80,7 @@ def main(_module, _output): wake.writePhysical(outFile) dom.writePhysical(outFile) # mesh options - writeOpts(outFile, p['coWingtip']) + writeOpts(outFile, tip.surN) # Printout printInfo(outFile) @@ -118,15 +118,14 @@ def writeHeader(fname, _module): file.write('/******************************************/\n\n') file.close() -def writeOpts(fname, cowtp): +def writeOpts(fname, tipSur): """Write misc options """ import os file = open(fname, 'a') file.write('// --- Misc Meshing options ---\n') file.write('Mesh.Algorithm = 5; // Delaunay\n') - if not cowtp: - file.write('MeshAlgorithm Surface {{73,74}} = 1; // Mesh-adapt\n') # hard-coded, not good + file.write('MeshAlgorithm Surface {{{0:d},{1:d}}} = 1; // Mesh-adapt\n').format(tipSur[0][2], tipSur[0][3]) file.write('Mesh.Algorithm3D = 2; // New Delaunay\n') file.write('Mesh.OptimizeNetgen = 1;\n') file.write('Mesh.Smoothing = 10;\n') diff --git a/wake.py b/wake.py index f294046..43c1e6e 100644 --- a/wake.py +++ b/wake.py @@ -146,7 +146,7 @@ def writePhysical(self, fname): file = open(fname, 'a') file.write('// --- Wake physical groups ---\n') file.write('Physical Line("wakeTip") = {{{0:d}}};\n'.format(self.linN[1][self.wing.n-1])) - file.write('Physical Line("teTip") = {{{0:d}'.format(self.linN[1][self.wing.n-1])) + file.write('Physical Line("teTip") = {{{0:d},'.format(self.linN[1][self.wing.n-1])) for i in range(0, self.wing.n-1): file.write('{0:d},'.format(self.wing.linpN[i][0])) file.seek(-1, os.SEEK_END) From 5c8ee77fe1c75e0d67d4ebafe66f46022af2ed9c Mon Sep 17 00:00:00 2001 From: acrovato <39187559+acrovato@users.noreply.github.com> Date: Wed, 3 Apr 2019 11:30:34 +0200 Subject: [PATCH 5/6] Corr 1 typo. gg... --- geoGen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geoGen.py b/geoGen.py index 760d7e8..83fe363 100755 --- a/geoGen.py +++ b/geoGen.py @@ -125,7 +125,7 @@ def writeOpts(fname, tipSur): file = open(fname, 'a') file.write('// --- Misc Meshing options ---\n') file.write('Mesh.Algorithm = 5; // Delaunay\n') - file.write('MeshAlgorithm Surface {{{0:d},{1:d}}} = 1; // Mesh-adapt\n').format(tipSur[0][2], tipSur[0][3]) + file.write('MeshAlgorithm Surface {{{0:d},{1:d}}} = 1; // Mesh-adapt\n'.format(tipSur[0][2], tipSur[0][3])) file.write('Mesh.Algorithm3D = 2; // New Delaunay\n') file.write('Mesh.OptimizeNetgen = 1;\n') file.write('Mesh.Smoothing = 10;\n') From 97d5148b9bb05fbafa0cecc8fac3b9a769d0d8de Mon Sep 17 00:00:00 2001 From: acrovato <39187559+acrovato@users.noreply.github.com> Date: Wed, 3 Apr 2019 13:43:38 +0200 Subject: [PATCH 6/6] new branch for testing for release --- shippable.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shippable.yml b/shippable.yml index 7f438e8..b778ea9 100644 --- a/shippable.yml +++ b/shippable.yml @@ -6,7 +6,7 @@ python: branches: only: - - master + - ci_shippable before_install: # python