From 23d4022a2cc92b06768911f8b5654ae5d41c4a2b Mon Sep 17 00:00:00 2001
From: acrovato <a.crovato@uliege.be>
Date: Mon, 12 Sep 2022 13:49:14 +0200
Subject: [PATCH] Add CRM files. Add max number of GMRES iterations in API. Add
 CREDITS.

---
 CREDITS.md             |  11 ++++
 README.md              |  10 +--
 dart/api/core.py       |   2 +-
 dart/models/crm.geo    | 123 +++++++++++++++++++++++++++++++++++++
 dart/models/crm.stp    |   3 +
 dart/validation/crm.py | 135 +++++++++++++++++++++++++++++++++++++++++
 6 files changed, 279 insertions(+), 5 deletions(-)
 create mode 100644 CREDITS.md
 create mode 100644 dart/models/crm.geo
 create mode 100644 dart/models/crm.stp
 create mode 100644 dart/validation/crm.py

diff --git a/CREDITS.md b/CREDITS.md
new file mode 100644
index 0000000..5288936
--- /dev/null
+++ b/CREDITS.md
@@ -0,0 +1,11 @@
+DARTFlo (DART) is Copyright (C) of University of Liège.
+
+The main author of DART is Adrien Crovato.
+
+Direct and indirect contributions have been made to DART by the following people:
+- Romain Boman
+- Luc Papeleux
+- Amaury Bilocq, [Implementation of a viscous-inviscid interaction scheme in a finite element full potential solver](http://hdl.handle.net/2268/252195).
+- Paul Dechamps, [Improvement of the viscous-inviscid interaction method implemented in DARTFlo](http://hdl.handle.net/2268.2/13886).
+- Guillaume Brian, [Investigation of various transonic stabilisation techniques for full potential flow calculations in DARTFlo](http://hdl.handle.net/2268.2/14510).
+- Guillem Battle I Capa, Aerodynamic and aeroelastic computations of full aircraft configurations.
diff --git a/README.md b/README.md
index fe67eec..33f2de7 100644
--- a/README.md
+++ b/README.md
@@ -11,10 +11,10 @@ DART is currently capable of rapidly solving steady transonic flows on arbitrary
   - steady transonic flows
   - viscous-inviscid interaction (2D only)
 * Numerical methods
-  - linear algrebra using [Eigen](http://eigen.tuxfamily.org/) and [Intel MKL](https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/onemkl.html#gs.a3o4w5) or [openBLAS](https://www.openblas.net/)
+  - linear algrebra using [Eigen](http://eigen.tuxfamily.org/)
   - direct (forward) and adjoint (backward) modes
   - nonlinear Newton solver with Bank&Rose line search
-  - linear Intel PARDISO, Eigen GMRES or [MUMPS](http://mumps.enseeiht.fr/) solvers
+  - linear [Intel MKL](https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/onemkl.html) PARDISO, Eigen GMRES or [MUMPS](http://mumps.enseeiht.fr/) solvers
 * Interfaced with
   - [VTK](https://vtk.org/)
   - [CUPyDO](https://github.com/ulgltas/CUPyDO)
@@ -28,6 +28,8 @@ Crovato Adrien, [Steady Transonic Aerodynamic and Aeroelastic Modeling for Preli
 
 Crovato Adrien, [DARTFlo - Discrete Adjoint for Rapid Transonic Flows](http://hdl.handle.net/2268/264284), Technical note, University of Liège, 2021.
 
-Crovato A., Boman R., et al., [A Full Potential Static Aeroelastic Solver for Preliminary Aircraft Design](http://hdl.handle.net/2268/237955), 18th International Forum on Aeroelasticity and Structural Dynamics, IFASD 2019.
+Crovato A., et al. [A discrete adjoint full potential formulation for fast aerostructural optimization in preliminary aircraft design](), Submitted to Aerospace Science and Technology, 2022.
 
-Bilocq Amaury, [Implementation of a viscous-inviscid interaction scheme in a finite element full potential solver](http://hdl.handle.net/2268/252195), Master thesis, University of Liège, 2020.
+Crovato A., et al., [A Full Potential Static Aeroelastic Solver for Preliminary Aircraft Design](http://hdl.handle.net/2268/237955), 18th International Forum on Aeroelasticity and Structural Dynamics, IFASD 2019.
+
+Crovato A., et al., [Fast Full Potential Based Aerostructural Optimization Calculations for Preliminary Aircraft Design](http://hdl.handle.net/2268/292456), 19th International Forum on Aeroelasticity and Structural Dynamics, IFASD 2022.
diff --git a/dart/api/core.py b/dart/api/core.py
index 6518f84..3dd8799 100644
--- a/dart/api/core.py
+++ b/dart/api/core.py
@@ -238,7 +238,7 @@ def initDart(cfg, scenario='aerodynamic', task='analysis', viscous=False):
         gfil = cfg['G_fill'] if 'G_fill' in cfg else 2
         grst = cfg['G_restart'] if 'G_restart' in cfg else 50
         gtol = cfg['G_tol'] if 'G_tol' in cfg else 1e-5
-        linsol = tbox.Gmres(gfil, 1e-6, grst, gtol)
+        linsol = tbox.Gmres(gfil, 1e-6, grst, gtol, 200)
     else:
         raise RuntimeError('Available linear solvers: PARDISO, MUMPS or GMRES, but ' + cfg['LSolver'] + ' was given!\n')
     # initialize the nonlinear (outer) solver
diff --git a/dart/models/crm.geo b/dart/models/crm.geo
new file mode 100644
index 0000000..a7d4926
--- /dev/null
+++ b/dart/models/crm.geo
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2020 University of Liège
+ *
+ * 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.
+ */
+
+/* NASA CRM - NASA Common Research Model
+ * CAD created by Guillem Battle I Capa
+ * Valid mesh obtained with gmsh 4.8.4
+ */
+
+/* Model information
+ * Length of fuselage: 62.79 m
+ * Chord length at wing root: 12.09 m
+ * Chord length at Yehudi break: 7.30 m
+ * Chord length at wing tip: 2.76 m
+ * Chord length at tail root: 5.45 m
+ * Chord length at tail tip: 2.33 m
+ * Reference wing area: 1/2 * 383.69 m^2
+ * Reference chord length: 7.01 m
+ */
+
+/// Constants
+scl = 2; // scaling factor for lifting surfaces mesh size (testing purpose)
+DefineConstant[ msFar = {36.8, Name "Mesh size on farfield" },
+                msFus = {0.628, Name "Mesh size on fuselage" },
+                msWingR = {0.121 * scl, Name "Mesh size on wing root" },
+				msWingY = {0.073 * scl, Name "Mesh size on wing Yehudi break" },
+				msWingT = {0.028 * scl, Name "Mesh size on wing tip" },
+				msTailR = {0.055 * scl, Name "Mesh size on tail root" },
+                msTailT = {0.023 * scl, Name "Mesh size on tail tip" } ];
+
+/// Geometry definition
+// Import
+Geometry.OCCAutoFix = 1;
+Geometry.OCCFixDegenerated = 1;
+Geometry.OCCFixSmallEdges = 1;
+Geometry.OCCFixSmallFaces = 1;
+Geometry.OCCSewFaces = 1;
+Geometry.Tolerance = 1e-5; // 0.01 mm
+Geometry.OCCTargetUnit = "M";
+Merge "crm.stp";
+Coherence;
+
+// Re-orient
+ReverseMesh Surface{1:48}; //To reverse the direction of the mesh normal vectors
+
+// Volume
+Surface Loop(1) = {4:48};
+Volume(1) = {1};
+
+// Embedded
+Line{3} In Surface{16};
+Line{7} In Surface{16};
+Line{15} In Surface{16};
+Surface{1} In Volume{1};
+Surface{2} In Volume{1};
+Surface{3} In Volume{1};
+
+// Physical groups
+Physical Line("wakeExW") = {10,11,12,13};
+Physical Line("teW") = {9,14};
+Physical Line("wakeTipW") = {10};
+Physical Line("wakeExT") = {1,2,5};
+Physical Line("teT") = {6};
+Physical Line("wakeTipT") = {1,2};
+Physical Surface("symmetry") = {19,20,21,22};
+Physical Surface("downstream") = {16};
+Physical Surface("upstream") = {18};
+Physical Surface("farfield") = {14,15,17};
+Physical Surface("fuselage") = {13,23:45};
+Physical Surface("wing") = {4,5,6,11,12};
+Physical Surface("wing_") = {7,8,9,10};
+Physical Surface("tail") = {47,48};
+Physical Surface("tail_") = {46};
+Physical Surface("wakeW") = {2,3};
+Physical Surface("wakeT") = {1};
+Physical Volume("field") = {1};
+
+/// Mesh definition
+// Farfield
+Characteristic Length {34,35,36,37,38,39,40,43,44,45} = msFar; // farfield boundaries
+Characteristic Length {3,4,7,8,15,41,42} = msFar; // wake
+
+// Fuselage
+Characteristic Length {11,12,13,51,61,50,73,74,62,63,64,65,47,29,70,46} = msFus; // body
+Characteristic Length {51,52,53,54,55,56,59,60,89,85,86,90,91,92} = 0.5 * msFus; // nose and windshield
+Characteristic Length {57,58,87,88} = 0.2 * msFus; // surface between windshield
+Characteristic Length {49,72,28,33,32,24,31,30,75,71,48,76,69,47} = 0.75 * msFus; // wingbox
+Characteristic Length {5,66,67,68} = 0.25 * msFus; // APU
+Characteristic Length {46,11} = msFus; // Fuselage-wake intersection
+
+// Wing
+Characteristic Length {24, 25,26,27,14} = msWingR; // wing root
+Characteristic Length {22, 20,21,23,9} = msWingY; // wing kink
+Characteristic Length {18,10,16,19} = 2 * msWingT; // wing tip TE
+Characteristic Length {17} = msWingT; // wing tip LE
+
+// Tail
+Characteristic Length {79:84,93:99, 100:102,77,78,103,6} = msTailR; // Tail root
+Characteristic Length {1,2,105} = 2 * msTailT; // tail tip TE
+Characteristic Length {104} = msTailT; // tail tip LE
+
+// Mesh algos
+Mesh.Algorithm = 1;
+Mesh.Algorithm3D = 2;
+Mesh.Optimize = 1;
+Mesh.Smoothing = 10;
+Mesh.SmoothNormals = 1;
+
+Mesh 1;
+Geometry.Tolerance = 1e-6;
+Coherence Mesh;
diff --git a/dart/models/crm.stp b/dart/models/crm.stp
new file mode 100644
index 0000000..ceeacb1
--- /dev/null
+++ b/dart/models/crm.stp
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:61b0676bf086cadd4ff336a922aa3cf5c74d49590261691ed0edd7bac23f5fb8
+size 16234345
diff --git a/dart/validation/crm.py b/dart/validation/crm.py
new file mode 100644
index 0000000..c70fd7a
--- /dev/null
+++ b/dart/validation/crm.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# Copyright 2020 University of Liège
+#
+# 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.
+
+
+## Compute the flow around the NASA CRM (Common Research Model) at CL = 0.5 and Mach 0.85
+# CAD created by Guillem Battle I Capa
+# Valid mesh obtained with gmsh 4.8.4
+
+try:
+   import tboxVtk
+   import vtk
+   hasVTK = True
+except:
+   hasVTK = False
+
+def cfg():
+    from fwk.wutils import parseargs
+    import os.path
+    # Mesh size
+    wrms = 0.121 # wing root trailing edge mesh size
+    wyms = 0.073 # wing root trailing edge mesh size
+    wtms = 0.028 # wing root trailing edge mesh size
+    trms = 0.055 # wing root trailing edge mesh size
+    ttms = 0.023 # wing root trailing edge mesh size
+    fums = 0.628 # fuselage mesh size
+    fams = 36.8 # farfield mesh size
+    # Parse
+    args = parseargs()
+    # Parameters
+    return {
+    # Options
+    'Threads' : args.k, # number of threads
+    'Verb' : args.verb + 2, # verbosity
+    # Model (geometry or mesh)
+    'File' : os.path.join(os.path.abspath(os.path.dirname(__file__)), '../models/crm.geo'), # Input file containing the model
+    'Pars' : {'msWingR' : wrms, 'msWingY' : wyms, 'msWingT' : wtms,
+              'msTailR' : trms, 'msTailT' : ttms,
+              'msFus' : fums, 'msFar' : fams}, # parameters for input file model
+    'Dim' : 3, # problem dimension (2 or 3)
+    'Format' : 'vtk', # save format (vtk or gmsh)
+    # Markers...
+    'Fluid' : 'field', # name of physical group containing the fluid
+    'Farfield' : ['upstream', 'farfield', 'downstream'], # LIST of names of physical groups containing the farfield boundaries (upstream/downstream should be first/last element)
+    'Wings' : ['wing', 'tail'], # LIST of names of physical groups containing the lifting surface boundary (first element will be the body of interest for aerostructural and optimization)
+    'Wakes' : ['wakeW', 'wakeT'], # LIST of names of physical group containing the wake
+    'WakeTips' : ['wakeTipW', 'wakeTipT'], # LIST of names of physical group containing the edge of the wake
+    'WakeExs' : ['wakeExW', 'wakeExT'], # LIST of names of physical group containing the edge of the wake and the intersection of lifting surface with fuselage (to be excluded from Wake B.C.)
+    'Tes' : ['teW', 'teT'], # LIST of names of physical group containing the trailing edge
+    'Fuselage' : 'fuselage', # name of physical group containing the fuselage boundaries
+    'Symmetry' : 'symmetry', # name of physical group containing the symmetry boundaries
+    # Freestream
+    'M_inf' : 0.85, # freestream Mach number
+    'AoA' : 1.2, # freestream angle of attack [deg] (optional, default=0)
+    'AoS' : 0.0, # freestream angle of sideslip [deg] (optional, default=0)
+    'Q_inf' : 0.0, # freesteam dynamic pressure (only required for aerostructural computations)
+    # Geometry
+    'S_ref' : 383.69/2, # reference surface length
+    'c_ref' : 7.005, # reference chord length
+    'x_ref' : 33.667, # x-coordinate of reference point for moment computation
+    'y_ref' : 11.906, # y-coordinate of reference point for moment computation
+    'z_ref' : 4.520, # z-coordinate of reference point for moment computation
+    # Numerical
+    'LSolver' : 'GMRES', # inner solver (PARDISO, MUMPS or GMRES)
+    'G_fill' : 2, # fill-in factor for GMRES preconditioner (optional, default=2)
+    'G_tol' : 1e-5, # tolerance for GMRES (optional, default=1e-5)
+    'G_restart' : 50, # restart for GMRES (optional, default=50)
+    'Rel_tol' : 1e-6, # relative tolerance on solver residual
+    'Abs_tol' : 1e-8, # absolute tolerance on solver residual
+    'Max_it' : 25 # maximum number of iterations for nonlinear solver
+    }
+
+def main():
+    from dart.api.core import initDart
+    from dart import utils
+    from fwk import Timers
+    from fwk.testing import CTest, CTests
+    import numpy as np
+    import matplotlib.pyplot as plt
+    # pre
+    tms = Timers()
+    tms['pre'].start()
+    _dart = initDart(cfg(), scenario='aerodynamic', task='analysis')
+    msh = _dart['msh']
+    sol = _dart['sol']
+    wrt = _dart['wrt']
+    tms['pre'].stop()
+    # solve
+    tms['sol'].start()
+    sol.run()
+    sol.save(wrt)
+    tms['sol'].stop()
+    # post
+    tms['pos'].start()
+    if hasVTK:
+        utils.writeSlices(msh.name, [3.81973, 5.8765, 8.2271, 11.753, 14.6913, 17.6295, 19.0986, 21.4492, 24.9751, 27.91338], 12)
+        for i in range(10):
+            data = np.loadtxt(f'{msh.name}_slice_{i}.dat', delimiter=',', skiprows=1) # read
+            plt.plot(data[:,3], data[:,4], lw=2) # plot results
+        font = {'family': 'serif', 'color': 'darkred', 'weight': 'normal', 'size': 16}
+        plt.xlabel('$x/c$', fontdict=font)
+        plt.ylabel('$C_p$', fontdict=font)
+        plt.gca().invert_yaxis()
+        plt.show()
+    tms['pos'].stop()
+
+    # display timers
+    print('CPU statistics')
+    print(tms)
+
+    # check results
+    tests = CTests()
+    tests.add(CTest('CL', sol.Cl, 0.5105, 1e-1))
+    tests.add(CTest('CD', sol.Cd, 0.0143, 1e-1))
+    tests.add(CTest('CM', sol.Cm, -0.1214, 1e-1))
+    tests.run()
+
+    # eof
+    print('')
+
+if __name__ == '__main__':
+    main()
-- 
GitLab