From 967bfb1edc33eb60489f5bb2011cb42c20b07764 Mon Sep 17 00:00:00 2001 From: Paul <paul.dechamps@student.uliege.be> Date: Sun, 10 Jul 2022 17:26:17 +0200 Subject: [PATCH] Using 2 meshes for 3D --- sdpm/src/pPanels.cpp | 23 +- sdpm/src/pPanels.h | 21 +- sdpm/src/pSDSolver.cpp | 74 ++- sdpm/src/pSDSolver.h | 3 +- sdpm/tests/panels3d.py | 6 +- vii/models/n0012_3_visc.geo | 397 +++++++++++++ vii/pyVII/vInterpolator.py | 1053 +++++++++++++++++++++++------------ vii/pyVII/vUtils.py | 24 + vii/src/wBLRegion.cpp | 42 +- vii/src/wClosures.cpp | 119 +++- vii/src/wClosures.h | 5 +- vii/src/wTimeSolver.cpp | 6 +- vii/src/wViscFluxes.cpp | 6 +- vii/src/wViscSolver.cpp | 11 +- vii/tests/bli2.py | 2 +- vii/tests/bli3.py | 237 ++++---- 16 files changed, 1436 insertions(+), 593 deletions(-) create mode 100644 vii/models/n0012_3_visc.geo diff --git a/sdpm/src/pPanels.cpp b/sdpm/src/pPanels.cpp index f930572..c565b9c 100644 --- a/sdpm/src/pPanels.cpp +++ b/sdpm/src/pPanels.cpp @@ -9,12 +9,15 @@ using namespace sdpm; Panels::Panels(size_t _nPanChord) { nPanChord = _nPanChord; - nPanSpan = 2; + nPanSpan = 20; beta = 1; } void Panels::CreateWing() { + + b = AR*(c0+c0*_lambda)/2; + Eigen::RowVectorXd xp(2*nPanChord+1); // Non-linear chordwise distribution Eigen::RowVectorXd xc(2*nPanChord+1); // Control point chordwise distribution @@ -46,7 +49,7 @@ void Panels::CreateWing() /* Spanwise chord variation */ Eigen::RowVectorXd cvar; - cvar = (lambda-1)*c0*yp.cwiseAbs(); + cvar = (_lambda-1)*c0*yp.cwiseAbs(); cvar += c0 * Eigen::MatrixXd::Ones(1, cvar.size()); Eigen::RowVectorXd epsilonvar; epsilonvar=epsilon*yp.cwiseAbs(); @@ -63,26 +66,24 @@ void Panels::CreateWing() Eigen::MatrixXd zp = Eigen::MatrixXd::Zero(1,2*nPanChord+1); - double t = .12; // Airfoil maximum thickness - /* Upper side */ for (auto i=0; i<zp.size()/2; ++i) { - zp(i) = -(t/0.2)*(0.2969*std::sqrt(xp(i)) - .126 * xp(i) - .3516* xp(i)*xp(i) + .2843*xp(i)*xp(i)*xp(i) - .1036*xp(i)*xp(i)*xp(i)*xp(i)); + zp(i) = -(thick/0.2)*(0.2969*std::sqrt(xp(i)) - .126 * xp(i) - .3516* xp(i)*xp(i) + .2843*xp(i)*xp(i)*xp(i) - .1036*xp(i)*xp(i)*xp(i)*xp(i)); } /* Lower side */ for (auto i=zp.size()/2; i<zp.size(); ++i) { - zp(i) = (t/0.2)*(0.2969*std::sqrt(xp(i)) - .126 * xp(i) - .3516* xp(i)*xp(i) + .2843*xp(i)*xp(i)*xp(i) - .1036*xp(i)*xp(i)*xp(i)*xp(i)); + zp(i) = (thick/0.2)*(0.2969*std::sqrt(xp(i)) - .126 * xp(i) - .3516* xp(i)*xp(i) + .2843*xp(i)*xp(i)*xp(i) - .1036*xp(i)*xp(i)*xp(i)*xp(i)); } - // iko=find(xp <= maxpos); - // zp(iko)=zp(iko)+maxcamb/maxpos^2*(2*maxpos*xp(iko)-xp(iko).^2); - // iko=find(xp > maxpos); - // zp(iko)=zp(iko)+maxcamb/(1-maxpos)^2*((1-2*maxpos)+2*maxpos*xp(iko)-xp(iko).^2); + /* iko = xp <= maxpos; + zp(iko)=zp(iko)+maxcamb/(maxpos*maxpos)*(2*maxpos*xp(iko)-xp(iko).array()*xp(iko).array()); + iko=xp > maxpos; + zp(iko)=zp(iko)+maxcamb/((1-maxpos)*(1-maxpos))*((1-2*maxpos)+2*maxpos*xp(iko)-xp(iko).array()*xp(iko).array()); */ /* Assemble bound panel corner point matrices */ /* Eigen::Array * Eigen::Array is a mult element wise while Eigen::Matrix * Eigen::Matrix is a matrix product -> cwiseProduct */ @@ -90,7 +91,7 @@ void Panels::CreateWing() Yp = yp.replicate(2*nPanChord+1,1) * b/2; Zp = zp.transpose().replicate(1,nPanSpan+1).cwiseProduct(cvar.replicate(2*nPanChord+1,1)); - Surface = (c0+c0*lambda)/2 * b; + Surface = (c0+c0*_lambda)/2 * b; diff --git a/sdpm/src/pPanels.h b/sdpm/src/pPanels.h index 736330c..d613b65 100644 --- a/sdpm/src/pPanels.h +++ b/sdpm/src/pPanels.h @@ -3,6 +3,7 @@ #include "sdpm.h" #include <vector> +#include <cmath> #include <Eigen/Dense> namespace sdpm @@ -14,13 +15,19 @@ class DART_API Panels private: public: - double c0 = 1; /* Root chord (m) */ - double lambda = 1; /* Taper ratio (-) */ - double epsilon = 0; /* Twist angle (rad) */ - double LambdaC4 = 0; /* Sweep angle at 1/4 chord (rad) */ - double b = 1; /* Span (m) */ - double dihedral = 0; /* Dihedral angle (rad) */ - double ax = 0; /* Axis around which twist and taper are defined */ + double c0 = 2; /* Root chord (m) */ + double _lambda = 0.3; /* Taper ratio (-) */ + double epsilon = 3*M_PI/180; /* Twist angle (rad) */ + double LambdaC4 = 35*M_PI/180; /* Sweep angle at 1/4 chord (rad) */ + double AR = 7; + double b; /* Span (m) */ + double dihedral = 3*M_PI/180; /* Dihedral angle (rad) */ + double ax = 1/2; /* Axis around which twist and taper are defined */ + + double maxcamb = 0.02; + double maxpos = 0.4; + double thick = .12; // Airfoil maximum thickness + double beta; double Surface; diff --git a/sdpm/src/pSDSolver.cpp b/sdpm/src/pSDSolver.cpp index 721fc44..581108a 100644 --- a/sdpm/src/pSDSolver.cpp +++ b/sdpm/src/pSDSolver.cpp @@ -4,20 +4,28 @@ #include <vector> #include <cmath> +#include <iomanip> +#include <deque> + using namespace sdpm; -SDSolver::SDSolver(Panels *_pan, double _alpha, double _airspeed, unsigned long _maxIt) +SDSolver::SDSolver(Panels *_pan, double _alpha, double _airspeed, double _tol, unsigned long _maxIt) { pan = _pan; fs_alpha = _alpha; fs_airspeed = _airspeed; + tol = _tol; maxIt = _maxIt; } void SDSolver::Run() { - int R = 1; /* Wake type */ + std::cout << std::fixed << std::setprecision(2) + << "\nSolving flow for alpha " << fs_alpha * 180 / 3.14159 << "deg AoA, " + << std::endl; + + int R = 0; /* Wake type */ Eigen::Vector3d fs_velocity; @@ -51,6 +59,10 @@ void SDSolver::Run() pan->Yp0 = pan->Yp; pan->Zp0 = pan->Zp; + Eigen::MatrixXd uc; + Eigen::MatrixXd vc; + Eigen::MatrixXd wc; + /* std::cout << " xp yp zp " << std::endl; std::cout << pan->Xp << std::endl; std::cout << pan->Yp << std::endl; @@ -229,9 +241,17 @@ void SDSolver::Run() unsigned long it = 1; - while(it < maxIt){ + std::cout << std::setw(8) << "Iters" + << std::setw(12) << "Cl" + << std::setw(12) << "Cd" + << std::setw(15) << "Error\n"; + std::cout << std::fixed << std::setprecision(5); + std::cout << std::setw(8) << 0 + << std::setw(12) << 0 + << std::setw(12) << 1 + << std::setw(15) << "-" << "\n"; - std::cout << it << std::endl; + while(it < maxIt){ /* Propagate wake */ Eigen::MatrixXd uwp = Eigen::MatrixXd::Zero(it-1, pan->nPanSpan + 1); @@ -408,9 +428,9 @@ void SDSolver::Run() /* Calculate velocities on control points in the x,y,z directions On each control point we project the velocities in the chordwise, spanwise and normal directions to the x,y,z axes */ - Eigen::MatrixXd uc(2*pan->nPanChord, pan->nPanSpan); - Eigen::MatrixXd vc(2*pan->nPanChord, pan->nPanSpan); - Eigen::MatrixXd wc(2*pan->nPanChord, pan->nPanSpan); + uc.setZero(2*pan->nPanChord, pan->nPanSpan); + vc.setZero(2*pan->nPanChord, pan->nPanSpan); + wc.setZero(2*pan->nPanChord, pan->nPanSpan); Eigen::Matrix3d Rmat_sys; Eigen::Vector3d RHS_sys; @@ -443,45 +463,40 @@ void SDSolver::Run() } } - uc = Eigen::MatrixXd::Constant(uc.rows(), uc.cols(), fs_velocity(0)) + uc; - vc = Eigen::MatrixXd::Constant(vc.rows(), vc.cols(), fs_velocity(1)) + vc; - wc = Eigen::MatrixXd::Constant(wc.rows(), wc.cols(), fs_velocity(2)) + wc; + uc += Eigen::MatrixXd::Constant(uc.rows(), uc.cols(), fs_velocity(0)); + vc += Eigen::MatrixXd::Constant(vc.rows(), vc.cols(), fs_velocity(1)); + wc += Eigen::MatrixXd::Constant(wc.rows(), wc.cols(), fs_velocity(2)); /* Calculate presssure coefficient */ Eigen::MatrixXd dPhidt; if (it==1){ - Eigen::Map<Eigen::VectorXd> Phi1Flatten(Phi[1].data(),Phi[1].size()); - Eigen::Map<Eigen::VectorXd> Phi0Flatten(Phi0.data(),Phi0.size()); - dPhidt = (Phi1Flatten-Phi0Flatten)/dt; + dPhidt = (Phi[1]-Phi0)/dt; } else{ - Eigen::Map<Eigen::VectorXd> Phi1Flatten(Phi[it].data(),Phi[it].size()); - Eigen::Map<Eigen::VectorXd> Phi0Flatten(Phi[it-1].data(),Phi[it-1].size()); - dPhidt = (Phi1Flatten - Phi0Flatten)/dt; + dPhidt = (Phi[it] - Phi[it-1])/dt; } Eigen::MatrixXd cp_dum = (uc.array()*uc.array() + vc.array()*vc.array() + wc.array()*wc.array())*1/fs_airspeed/fs_airspeed - 2*dPhidt.array()*1/fs_airspeed/fs_airspeed; cp = Eigen::MatrixXd::Constant(uc.rows(), uc.cols(), 1) - cp_dum; - /* Forces on panels */ - std::cout << "cp" << std::endl; + /*std::cout << "cp" << std::endl; std::cout << cp << std::endl; std::cout << "pan->s" << std::endl; std::cout << pan->s << std::endl; std::cout << "pan->nx" << std::endl; std::cout << pan->nx << std::endl; std::cout << "pan->Surface" << std::endl; - std::cout << pan->Surface << std::endl; + std::cout << pan->Surface << std::endl; */ Eigen::MatrixXd fx = -cp.array()*pan->s.array()*pan->nx.array()/pan->Surface; - Eigen::MatrixXd fy = -cp.array()*pan->s.array()*pan->nx.array()/pan->Surface; - Eigen::MatrixXd fz = -cp.array()*pan->s.array()*pan->nx.array()/pan->Surface; + Eigen::MatrixXd fy = -cp.array()*pan->s.array()*pan->ny.array()/pan->Surface; + Eigen::MatrixXd fz = -cp.array()*pan->s.array()*pan->nz.array()/pan->Surface; - std::cout << fx << std::endl; + /* std::cout << fx << std::endl; std::cout << fy << std::endl; - std::cout << fz << std::endl; + std::cout << fz << std::endl; */ double Fx = fx.sum(); //double Fy = fy.sum(); @@ -495,7 +510,18 @@ void SDSolver::Run() CL(it) = Fz-Fx*fs_alpha; CD(it) = Fz*fs_alpha+Fx; } - std::cout << " CL = " << CL(it) << std::endl; + + double error = (CL(it)-CL(it-1))/CL(it-1); + + std::cout << std::fixed << std::setprecision(5); + std::cout << std::setw(8) << it + << std::setw(12) << CL(it) + << std::setw(12) << CD(it) + << std::setw(15) << std::log10(error) << "\n"; + + if (error < tol){ + break; + } it++; } diff --git a/sdpm/src/pSDSolver.h b/sdpm/src/pSDSolver.h index 9180461..8c6cef8 100644 --- a/sdpm/src/pSDSolver.h +++ b/sdpm/src/pSDSolver.h @@ -21,12 +21,13 @@ public: Panels *pan; double fs_alpha, fs_Mach, fs_airspeed; unsigned long maxIt; +double tol; Eigen::VectorXd CL; Eigen::VectorXd CD; Eigen::VectorXd CY; Eigen::MatrixXd cp; -SDSolver(Panels *_pan, double _alpha, double _airspeed, unsigned long _maxIt); +SDSolver(Panels *_pan, double _alpha, double _airspeed, double tol=1e-3, unsigned long _maxIt=100); void Run(); diff --git a/sdpm/tests/panels3d.py b/sdpm/tests/panels3d.py index 04bb3b1..b7c5056 100644 --- a/sdpm/tests/panels3d.py +++ b/sdpm/tests/panels3d.py @@ -8,19 +8,15 @@ def main(): nPanels = 2 airspeed = 50 - maxIt = 10 wing = sdpm.Panels(nPanels) wing.CreateWing() - solver = sdpm.SDSolver(wing, alpha, airspeed, maxIt) + solver = sdpm.SDSolver(wing, alpha, airspeed) print('Computation started (pyCheck)') solver.Run() - plt.plot(solver.CL) - plt.show() - print('Computation ended (pyCheck)') if __name__ == "__main__": diff --git a/vii/models/n0012_3_visc.geo b/vii/models/n0012_3_visc.geo new file mode 100644 index 0000000..b449ddc --- /dev/null +++ b/vii/models/n0012_3_visc.geo @@ -0,0 +1,397 @@ +/* Rectangular NACA0012 wing */ +// Initially generated by unsRgridWingGen.m +// For gmsh 4, use line 334 instead of line 335 (Bezier <- BSpline) + +// Parameters +// domain and mesh +DefineConstant[ spn = { 2.0, Name "Wing span" } ]; +DefineConstant[ lgt = { 3.0, Name "Channel length" } ]; +DefineConstant[ wdt = { 3.0, Name "Channel width" } ]; +DefineConstant[ hgt = { 3.0, Name "Channel height" } ]; +DefineConstant[ msLe = { 0.05, Name "Leading edge mesh size" } ]; +DefineConstant[ msTe = { 0.05, Name "Trailing edge mesh size" } ]; +DefineConstant[ msF = { 1.0, Name "Farfield mesh size" } ]; + +//// GEOMETRY + + +/// Points + +// Airfoil 1: naca0012, 101 points +Point(1) = {1.000000,0.000000,0.000000,msTe}; +Point(2) = {0.999013,0.000000,0.000143}; +Point(3) = {0.996057,0.000000,0.000572}; +Point(4) = {0.991144,0.000000,0.001280}; +Point(5) = {0.984292,0.000000,0.002260}; +Point(6) = {0.975528,0.000000,0.003501}; +Point(7) = {0.964888,0.000000,0.004990}; +Point(8) = {0.952414,0.000000,0.006710}; +Point(9) = {0.938153,0.000000,0.008643}; +Point(10) = {0.922164,0.000000,0.010770}; +Point(11) = {0.904508,0.000000,0.013071,msTe}; +Point(12) = {0.885257,0.000000,0.015523}; +Point(13) = {0.864484,0.000000,0.018106}; +Point(14) = {0.842274,0.000000,0.020795}; +Point(15) = {0.818712,0.000000,0.023569}; +Point(16) = {0.793893,0.000000,0.026405}; +Point(17) = {0.767913,0.000000,0.029279}; +Point(18) = {0.740877,0.000000,0.032168}; +Point(19) = {0.712890,0.000000,0.035048}; +Point(20) = {0.684062,0.000000,0.037896}; +Point(21) = {0.654508,0.000000,0.040686}; +Point(22) = {0.624345,0.000000,0.043394}; +Point(23) = {0.593691,0.000000,0.045992}; +Point(24) = {0.562667,0.000000,0.048455}; +Point(25) = {0.531395,0.000000,0.050754}; +Point(26) = {0.500000,0.000000,0.052862}; +Point(27) = {0.468605,0.000000,0.054749}; +Point(28) = {0.437333,0.000000,0.056390}; +Point(29) = {0.406309,0.000000,0.057755}; +Point(30) = {0.375655,0.000000,0.058819}; +Point(31) = {0.345492,0.000000,0.059557}; +Point(32) = {0.315938,0.000000,0.059947}; +Point(33) = {0.287110,0.000000,0.059971,msTe}; +Point(34) = {0.259123,0.000000,0.059614}; +Point(35) = {0.232087,0.000000,0.058863}; +Point(36) = {0.206107,0.000000,0.057712}; +Point(37) = {0.181288,0.000000,0.056159}; +Point(38) = {0.157726,0.000000,0.054206}; +Point(39) = {0.135516,0.000000,0.051862}; +Point(40) = {0.114743,0.000000,0.049138}; +Point(41) = {0.095492,0.000000,0.046049}; +Point(42) = {0.077836,0.000000,0.042615}; +Point(43) = {0.061847,0.000000,0.038859}; +Point(44) = {0.047586,0.000000,0.034803}; +Point(45) = {0.035112,0.000000,0.030473}; +Point(46) = {0.024472,0.000000,0.025893}; +Point(47) = {0.015708,0.000000,0.021088}; +Point(48) = {0.008856,0.000000,0.016078}; +Point(49) = {0.003943,0.000000,0.010884}; +Point(50) = {0.000987,0.000000,0.005521}; +Point(51) = {0.000000,0.000000,0.000000,msLe}; +Point(52) = {0.000987,0.000000,-0.005521}; +Point(53) = {0.003943,0.000000,-0.010884}; +Point(54) = {0.008856,0.000000,-0.016078}; +Point(55) = {0.015708,0.000000,-0.021088}; +Point(56) = {0.024472,0.000000,-0.025893}; +Point(57) = {0.035112,0.000000,-0.030473}; +Point(58) = {0.047586,0.000000,-0.034803}; +Point(59) = {0.061847,0.000000,-0.038859}; +Point(60) = {0.077836,0.000000,-0.042615}; +Point(61) = {0.095492,0.000000,-0.046049}; +Point(62) = {0.114743,0.000000,-0.049138}; +Point(63) = {0.135516,0.000000,-0.051862}; +Point(64) = {0.157726,0.000000,-0.054206}; +Point(65) = {0.181288,0.000000,-0.056159}; +Point(66) = {0.206107,0.000000,-0.057712}; +Point(67) = {0.232087,0.000000,-0.058863}; +Point(68) = {0.259123,0.000000,-0.059614}; +Point(69) = {0.287110,0.000000,-0.059971,msTe}; +Point(70) = {0.315938,0.000000,-0.059947}; +Point(71) = {0.345492,0.000000,-0.059557}; +Point(72) = {0.375655,0.000000,-0.058819}; +Point(73) = {0.406309,0.000000,-0.057755}; +Point(74) = {0.437333,0.000000,-0.056390}; +Point(75) = {0.468605,0.000000,-0.054749}; +Point(76) = {0.500000,0.000000,-0.052862}; +Point(77) = {0.531395,0.000000,-0.050754}; +Point(78) = {0.562667,0.000000,-0.048455}; +Point(79) = {0.593691,0.000000,-0.045992}; +Point(80) = {0.624345,0.000000,-0.043394}; +Point(81) = {0.654508,0.000000,-0.040686}; +Point(82) = {0.684062,0.000000,-0.037896}; +Point(83) = {0.712890,0.000000,-0.035048}; +Point(84) = {0.740877,0.000000,-0.032168}; +Point(85) = {0.767913,0.000000,-0.029279}; +Point(86) = {0.793893,0.000000,-0.026405}; +Point(87) = {0.818712,0.000000,-0.023569}; +Point(88) = {0.842274,0.000000,-0.020795}; +Point(89) = {0.864484,0.000000,-0.018106}; +Point(90) = {0.885257,0.000000,-0.015523}; +Point(91) = {0.904508,0.000000,-0.013071,msTe}; +Point(92) = {0.922164,0.000000,-0.010770}; +Point(93) = {0.938153,0.000000,-0.008643}; +Point(94) = {0.952414,0.000000,-0.006710}; +Point(95) = {0.964888,0.000000,-0.004990}; +Point(96) = {0.975528,0.000000,-0.003501}; +Point(97) = {0.984292,0.000000,-0.002260}; +Point(98) = {0.991144,0.000000,-0.001280}; +Point(99) = {0.996057,0.000000,-0.000572}; +Point(100) = {0.999013,0.000000,-0.000143,msTe}; + +// Airfoil 2: naca0012, 101 points +Point(102) = {1.000000,spn,0.000000,msTe}; +Point(103) = {0.999013,spn,0.000143}; +Point(104) = {0.996057,spn,0.000572}; +Point(105) = {0.991144,spn,0.001280}; +Point(106) = {0.984292,spn,0.002260}; +Point(107) = {0.975528,spn,0.003501}; +Point(108) = {0.964888,spn,0.004990}; +Point(109) = {0.952414,spn,0.006710}; +Point(110) = {0.938153,spn,0.008643}; +Point(111) = {0.922164,spn,0.010770}; +Point(112) = {0.904508,spn,0.013071,msTe}; +Point(113) = {0.885257,spn,0.015523}; +Point(114) = {0.864484,spn,0.018106}; +Point(115) = {0.842274,spn,0.020795}; +Point(116) = {0.818712,spn,0.023569}; +Point(117) = {0.793893,spn,0.026405}; +Point(118) = {0.767913,spn,0.029279}; +Point(119) = {0.740877,spn,0.032168}; +Point(120) = {0.712890,spn,0.035048}; +Point(121) = {0.684062,spn,0.037896}; +Point(122) = {0.654508,spn,0.040686}; +Point(123) = {0.624345,spn,0.043394}; +Point(124) = {0.593691,spn,0.045992}; +Point(125) = {0.562667,spn,0.048455}; +Point(126) = {0.531395,spn,0.050754}; +Point(127) = {0.500000,spn,0.052862}; +Point(128) = {0.468605,spn,0.054749}; +Point(129) = {0.437333,spn,0.056390}; +Point(130) = {0.406309,spn,0.057755}; +Point(131) = {0.375655,spn,0.058819}; +Point(132) = {0.345492,spn,0.059557}; +Point(133) = {0.315938,spn,0.059947}; +Point(134) = {0.287110,spn,0.059971,msTe}; +Point(135) = {0.259123,spn,0.059614}; +Point(136) = {0.232087,spn,0.058863}; +Point(137) = {0.206107,spn,0.057712}; +Point(138) = {0.181288,spn,0.056159}; +Point(139) = {0.157726,spn,0.054206}; +Point(140) = {0.135516,spn,0.051862}; +Point(141) = {0.114743,spn,0.049138}; +Point(142) = {0.095492,spn,0.046049}; +Point(143) = {0.077836,spn,0.042615}; +Point(144) = {0.061847,spn,0.038859}; +Point(145) = {0.047586,spn,0.034803}; +Point(146) = {0.035112,spn,0.030473}; +Point(147) = {0.024472,spn,0.025893}; +Point(148) = {0.015708,spn,0.021088}; +Point(149) = {0.008856,spn,0.016078}; +Point(150) = {0.003943,spn,0.010884}; +Point(151) = {0.000987,spn,0.005521}; +Point(152) = {0.000000,spn,0.000000,msLe}; +Point(153) = {0.000987,spn,-0.005521}; +Point(154) = {0.003943,spn,-0.010884}; +Point(155) = {0.008856,spn,-0.016078}; +Point(156) = {0.015708,spn,-0.021088}; +Point(157) = {0.024472,spn,-0.025893}; +Point(158) = {0.035112,spn,-0.030473}; +Point(159) = {0.047586,spn,-0.034803}; +Point(160) = {0.061847,spn,-0.038859}; +Point(161) = {0.077836,spn,-0.042615}; +Point(162) = {0.095492,spn,-0.046049}; +Point(163) = {0.114743,spn,-0.049138}; +Point(164) = {0.135516,spn,-0.051862}; +Point(165) = {0.157726,spn,-0.054206}; +Point(166) = {0.181288,spn,-0.056159}; +Point(167) = {0.206107,spn,-0.057712}; +Point(168) = {0.232087,spn,-0.058863}; +Point(169) = {0.259123,spn,-0.059614}; +Point(170) = {0.287110,spn,-0.059971,msTe}; +Point(171) = {0.315938,spn,-0.059947}; +Point(172) = {0.345492,spn,-0.059557}; +Point(173) = {0.375655,spn,-0.058819}; +Point(174) = {0.406309,spn,-0.057755}; +Point(175) = {0.437333,spn,-0.056390}; +Point(176) = {0.468605,spn,-0.054749}; +Point(177) = {0.500000,spn,-0.052862}; +Point(178) = {0.531395,spn,-0.050754}; +Point(179) = {0.562667,spn,-0.048455}; +Point(180) = {0.593691,spn,-0.045992}; +Point(181) = {0.624345,spn,-0.043394}; +Point(182) = {0.654508,spn,-0.040686}; +Point(183) = {0.684062,spn,-0.037896}; +Point(184) = {0.712890,spn,-0.035048}; +Point(185) = {0.740877,spn,-0.032168}; +Point(186) = {0.767913,spn,-0.029279}; +Point(187) = {0.793893,spn,-0.026405}; +Point(188) = {0.818712,spn,-0.023569}; +Point(189) = {0.842274,spn,-0.020795}; +Point(190) = {0.864484,spn,-0.018106}; +Point(191) = {0.885257,spn,-0.015523}; +Point(192) = {0.904508,spn,-0.013071,msTe}; +Point(193) = {0.922164,spn,-0.010770}; +Point(194) = {0.938153,spn,-0.008643}; +Point(195) = {0.952414,spn,-0.006710}; +Point(196) = {0.964888,spn,-0.004990}; +Point(197) = {0.975528,spn,-0.003501}; +Point(198) = {0.984292,spn,-0.002260}; +Point(199) = {0.991144,spn,-0.001280}; +Point(200) = {0.996057,spn,-0.000572}; +Point(201) = {0.999013,spn,-0.000143,msTe}; + +// Tip: +Point(5101) = {0.999013,spn,0.000000}; +Point(5102) = {0.996057,spn+0.000125,0.000000}; +Point(5103) = {0.991144,spn+0.000331,0.000000}; +Point(5104) = {0.984292,spn+0.000620,0.000000}; +Point(5105) = {0.975528,spn+0.000989,0.000000}; +Point(5106) = {0.964888,spn+0.001437,0.000000}; +Point(5107) = {0.952414,spn+0.001963,0.000000}; +Point(5108) = {0.938153,spn+0.002563,0.000000}; +Point(5109) = {0.922164,spn+0.003237,0.000000}; +Point(5110) = {0.904508,spn+0.003981,0.000000,msTe}; +Point(5111) = {0.885257,spn+0.004791,0.000000}; +Point(5112) = {0.864484,spn+0.005666,0.000000}; +Point(5113) = {0.842274,spn+0.006602,0.000000}; +Point(5114) = {0.818712,spn+0.007594,0.000000}; +Point(5115) = {0.793893,spn+0.008640,0.000000}; +Point(5116) = {0.767913,spn+0.009734,0.000000}; +Point(5117) = {0.740877,spn+0.010873,0.000000}; +Point(5118) = {0.712890,spn+0.012052,0.000000}; +Point(5119) = {0.684062,spn+0.013266,0.000000}; +Point(5120) = {0.654508,spn+0.014511,0.000000}; +Point(5121) = {0.624345,spn+0.015781,0.000000}; +Point(5122) = {0.593691,spn+0.017072,0.000000}; +Point(5123) = {0.562667,spn+0.018379,0.000000}; +Point(5124) = {0.531395,spn+0.019696,0.000000}; +Point(5125) = {0.500000,spn+0.021019,0.000000}; +Point(5126) = {0.468605,spn+0.022341,0.000000}; +Point(5127) = {0.437333,spn+0.023658,0.000000}; +Point(5128) = {0.406309,spn+0.024965,0.000000}; +Point(5129) = {0.375655,spn+0.026256,0.000000}; +Point(5130) = {0.345492,spn+0.027526,0.000000}; +Point(5131) = {0.315938,spn+0.028771,0.000000}; +Point(5132) = {0.287110,spn+0.029985,0.000000,msTe}; +Point(5133) = {0.019492,spn+0.041801,0.000000}; + +// Dummy tip center: +Point(5349) = {0.904508,spn,0.000000}; +Point(5350) = {0.287110,spn,0.000000}; + +// Box +Point(10001) = {1+lgt, 0, 0, msF}; + +// Wake +Point(10021) = {1+lgt, spn, 0, msF}; + +/// Lines + +// Airfoil 1: +Spline(1) = {1,2,3,4,5,6,7,8,9,10,11}; +Spline(2) = {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33}; +Spline(3) = {33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; +Spline(4) = {51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69}; +Spline(5) = {69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91}; +Spline(6) = {91,92,93,94,95,96,97,98,99,100,1}; + +// Airfoil 2: +Spline(7) = {102,103,104,105,106,107,108,109,110,111,112}; +Spline(8) = {112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134}; +Spline(9) = {134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152}; +Spline(10) = {152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170}; +Spline(11) = {170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192}; +Spline(12) = {192,193,194,195,196,197,198,199,200,201,102}; + +// Airfoil 1 to airfoil 2: +Line(61) = {1,102}; +Line(62) = {11,112}; +Line(63) = {33,134}; +Line(64) = {51,152}; +Line(65) = {69,170}; +Line(66) = {91,192}; + +// Tip: +Spline(121) = {102,5101,5102,5103,5104,5105,5106,5107,5108,5109,5110}; +Spline(122) = {5110,5111,5112,5113,5114,5115,5116,5117,5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132}; +If(GMSH_MAJOR_VERSION >= 4) + Bezier(123) = {5132,5133,152}; +Else + BSpline(123) = {5132,5133,152}; +EndIf +Ellipse(124) = {112,5349,112,5110}; +Ellipse(125) = {134,5350,134,5132}; +Ellipse(126) = {170,5350,170,5132}; +Ellipse(127) = {192,5349,192,5110}; + +// Box +Line(221) = {1, 10001}; +Line(222) = {102, 10021}; + +// Wake +Line(241) = {10001, 10021}; + +/// Line loops & Surfaces + +// Wing 1: +Line Loop(1) = {1,62,-7,-61}; +Line Loop(2) = {2,63,-8,-62}; +Line Loop(3) = {3,64,-9,-63}; +Line Loop(4) = {4,65,-10,-64}; +Line Loop(5) = {5,66,-11,-65}; +Line Loop(6) = {6,61,-12,-66}; +Surface(1) = {-1}; +Surface(2) = {-2}; +Surface(3) = {-3}; +Surface(4) = {-4}; +Surface(5) = {-5}; +Surface(6) = {-6}; + +// Wingtip: +Line Loop(11) = {7,124,-121}; +Line Loop(12) = {8,125,-122,-124}; +Line Loop(13) = {9,-123,-125}; +Line Loop(14) = {10,126,123}; +Line Loop(15) = {11,127,122,-126}; +Line Loop(16) = {12,121,-127}; +Surface(11) = {-11}; +Surface(12) = {-12}; +Surface(13) = {-13}; +Surface(14) = {-14}; +Surface(15) = {-15}; +Surface(16) = {-16}; + +// Wake +Line Loop(51) = {221, 241, -222, -61}; +Surface(51) = {51}; + +//// MESHING ALGORITHM +//+ +nElmSpan = 50; +Transfinite Curve {65, 63, 62, 66, 61, 64, 241} = nElmSpan Using Progression 1; +nElmChrodwise_wake = 20; +//+ +Transfinite Curve {222, 221} = nElmChrodwise_wake Using Progression 1.01; +Transfinite Surface {51}; + +nChordwise_midWing = 40; +//+ +Transfinite Curve {8, 11, 5, 2, 122} = nChordwise_midWing Using Progression 1.01; +//+ +nChordwise_Le = 40; +Transfinite Curve {9, 9, 10, 3, 4} = nChordwise_Le Using Progression 0.95; + +//+ +nChordwise_Te = 20; +Transfinite Curve {7, 121, 12, 1, 6} = nChordwise_Te Using Progression 1.01; + +Transfinite Surface {3}; +Transfinite Surface {4}; +Transfinite Surface {2}; +Transfinite Surface {5}; +Transfinite Surface {1}; +Transfinite Surface {6}; + +Recombine Surface {3}; +Recombine Surface {4}; +Recombine Surface {2}; +Recombine Surface {5}; +Recombine Surface {1}; +Recombine Surface {6}; +Recombine Surface {51}; + + +//// PHYSICAL GROUPS + +// Trailing edge and wake tip +Physical Line("wakeTip") = {222}; +Physical Line("te") = {61}; +Physical Line("teTip") = {61, 222}; + +// Wing: +Physical Surface("wing") = {1,2,3,11,12,13}; +Physical Surface("wing_") = {4,5,6,14,15,16}; + +// Wake: +Physical Surface("wake") = {51}; diff --git a/vii/pyVII/vInterpolator.py b/vii/pyVII/vInterpolator.py index 66dee72..573cc10 100644 --- a/vii/pyVII/vInterpolator.py +++ b/vii/pyVII/vInterpolator.py @@ -1,367 +1,686 @@ -import numpy as np -from matplotlib import pyplot as plt -from fwk.coloring import ccolors - -import dart.pyVII.vUtils as blxU -import sys -#import dart.pyVII.vStructures as vStruct - -# 3D spline with Bézier curves -from scipy.interpolate import bisplrep -from scipy.interpolate import bisplev -from scipy.interpolate import splrep -from scipy.interpolate import splev - -from scipy.interpolate import interp1d - -from scipy.interpolate import RBFInterpolator - -import fwk - - -class Interpolator: - def __init__(self, _dartAPI, _blw, _cfg): - - self.iSolver = _dartAPI - self.blw = _blw - - # Create data structures for interpolation - self.tms = fwk.Timers() - self.tms['GetWing'].start() - self.__GetWing(_blw, _cfg) - self.tms['GetWing'].stop() - - self.cfg = _cfg - print(self.tms) - - self.stgPt=np.zeros(self.cfg['nSections'], dtype=int) - - self.xxPrev = [[np.zeros(0) for iReg in range(3)] for iSec in range(self.cfg['nSections'])] - #self.uePrev = [[np.zeros(len(self.viscStruct[iSec][iReg][:,0])) for iReg in range(3)] for iSec in range(len(self.viscStruct))] - self.DeltaStarPrev = [[np.zeros(0) for iReg in range(3)] for iSec in range(self.cfg['nSections'])] - - - def GetInvBC(self, vSolver, couplIter): - self.tms['InvToVisc'].start() - - # Extract parameters from the inviscid solver - # Particular care must be taken with space directions; In the inviscid, the airfoil is in the x,z plane. - # While setting up the viscous solver, y and z must be inverted. - - # Wing - - U = [np.zeros((len(self.invStruct[i][:,0]), 3)) for i in range(len(self.invStruct))] - M = [np.zeros(len(self.invStruct[i][:,0])) for i in range(len(self.invStruct))] - Rho = [np.zeros(len(self.invStruct[i][:,0])) for i in range(len(self.invStruct))] - - # Extract variables. - - for iReg in range(len(self.invStruct)): - for iNode, row in enumerate(self.invStruct[iReg][:,3]): - row = int(row) - U[iReg][iNode,:] = [self.iSolver.U[row][0], self.iSolver.U[row][1], self.iSolver.U[row][2]] - M[iReg][iNode] = self.iSolver.M[row] - Rho[iReg][iNode] = self.iSolver.rho[row] - - if self.cfg['nDim'] == 3: - U[iReg][:,[1,2]] = U[iReg][:,[2,1]] - - # Find stagnation point - nD = self.cfg['nDim'] - for iSec in range(len(self.viscStruct_tr)): - Ux = [self.__RbfToSections(self.invStruct_tr[0][:,:nD], U[0][:,0], self.viscStruct_tr[iSec][0][:,:nD]), self.__RbfToSections(self.invStruct_tr[1][:, [0,2] if nD==3 else 0], U[1][:,0], self.viscStruct[iSec][1][:,[0,2] if nD==3 else 0])] - Uy = [self.__RbfToSections(self.invStruct_tr[0][:,:nD], U[0][:,1], self.viscStruct_tr[iSec][0][:,:nD]), self.__RbfToSections(self.invStruct_tr[1][:, [0,2] if nD==3 else 0], U[1][:,1], self.viscStruct[iSec][1][:,[0,2] if nD==3 else 0])] - Uz = [self.__RbfToSections(self.invStruct_tr[0][:,:nD], U[0][:,2], self.viscStruct_tr[iSec][0][:,:nD]), self.__RbfToSections(self.invStruct_tr[1][:, [0,2] if nD==3 else 0], U[1][:,2], self.viscStruct[iSec][1][:,[0,2] if nD==3 else 0])] - Me = [self.__RbfToSections(self.invStruct_tr[0][:,:nD], M[0], self.viscStruct_tr[iSec][0][:,:nD]), self.__RbfToSections(self.invStruct_tr[1][:, [0,2] if nD==3 else 0], M[1], self.viscStruct[iSec][1][:,[0,2] if nD==3 else 0])] - Rhoe = [self.__RbfToSections(self.invStruct_tr[0][:,:nD], Rho[0], self.viscStruct_tr[iSec][0][:,:nD]), self.__RbfToSections(self.invStruct_tr[1][:, [0,2] if nD==3 else 0], Rho[1], self.viscStruct[iSec][1][:,[0,2] if nD==3 else 0])] - - if couplIter == 0: - self.stgPt[iSec] = np.argmin(Ux[0]**2+Uy[0]**2) - - xUp, xLw = self.__Remesh(self.viscStruct[iSec][0][:,0], self.stgPt[iSec]) - yUp, yLw = self.__Remesh(self.viscStruct[iSec][0][:,1], self.stgPt[iSec]) - zUp, zLw = self.__Remesh(self.viscStruct[iSec][0][:,2], self.stgPt[iSec]) - - vSolver.SetGlobMesh(iSec, 0, xUp, yUp, zUp) - vSolver.SetGlobMesh(iSec, 1, xLw, yLw, zLw) - vSolver.SetGlobMesh(iSec, 2, self.viscStruct[iSec][1][:,0], - self.viscStruct[iSec][1][:,1], - self.viscStruct[iSec][1][:,2]) - - self.DeltaStarPrev[iSec][0] = np.zeros(len(xUp)) - self.DeltaStarPrev[iSec][1] = np.zeros(len(xLw)) - self.DeltaStarPrev[iSec][2] = np.zeros(len(self.viscStruct[iSec][1][:,0])) - - self.xxPrev[iSec][0] = np.zeros(len(xUp)) - self.xxPrev[iSec][1] = np.zeros(len(xLw)) - self.xxPrev[iSec][2] = np.zeros(len(self.viscStruct[iSec][1][:,0])) - - UxUp, UxLw = self.__Remesh(Ux[0], self.stgPt[iSec]) - UyUp, UyLw = self.__Remesh(Uy[0], self.stgPt[iSec]) - UzUp, UzLw = self.__Remesh(Uz[0], self.stgPt[iSec]) - - plt.plot(xUp, UxUp) - plt.plot(xLw, UxLw) - plt.show() - - vSolver.SetVelocities(iSec, 0, UxUp, UyUp, UzUp) - vSolver.SetVelocities(iSec, 1, UxLw, UyLw, UzLw) - vSolver.SetVelocities(iSec, 2, Ux[1], Uy[1], Uz[1]) - - MeUp, MeLw = self.__Remesh(Me[0], self.stgPt[iSec]) - - vSolver.SetMe(iSec, 0, MeUp) - vSolver.SetMe(iSec, 1, MeLw) - vSolver.SetMe(iSec, 2, Me[1]) - - RhoUp, RhoLw = self.__Remesh(Rhoe[0], self.stgPt[iSec]) - - vSolver.SetRhoe(iSec, 0, RhoUp) - vSolver.SetRhoe(iSec, 1, RhoLw) - vSolver.SetRhoe(iSec, 2, Rhoe[1]) - - for iReg in range(3): - vSolver.SetDeltaStarExt(iSec, iReg, self.DeltaStarPrev[iSec][iReg]) - vSolver.SetxxExt(iSec, iReg, self.xxPrev[iSec][iReg]) - - - - def SetBlowingVel(self, vSolver, couplIter): - - for iSec in range(len(self.viscStruct)): - for iReg in range(3): - self.DeltaStarPrev[iSec][iReg] = vSolver.ExtractDeltaStar(iSec, iReg) - self.xxPrev[iSec][iReg] = vSolver.Extractxx(iSec, iReg) - - x = [np.zeros((0,3)) for _ in range(2)] - blw = [np.zeros(0) for _ in range(2)] - - for iSec in range(len(self.viscStruct)): - for iReg in range(2): - if iReg == 0: - x[iReg] = np.vstack((x[iReg], self.viscCg_tr[iSec][iReg][:,:3])) - blwUp = vSolver.ExtractBlowingVel(iSec, 0) - blwLw = vSolver.ExtractBlowingVel(iSec, 1) - blw[iReg] = np.concatenate((blw[iReg], blwUp[::-1] , blwLw)) - elif iReg == 1: - x[iReg] = np.vstack((x[iReg], self.viscCg_tr[iSec][iReg][:,:3])) - blw[iReg] = np.concatenate((blw[iReg], vSolver.ExtractBlowingVel(iSec, 2))) - - self.tms['Interpolation'].start() - nD = self.cfg['nDim'] - mappedBlw = [self.__RbfToSections(x[0], blw[0], self.invCg_tr[0][:,:3]), self.__RbfToSections(x[1][:, [0,2] if nD==3 else 0], blw[1], self.invCg_tr[1][:, [0,2] if nD==3 else 0])] - - self.tms['Interpolation'].stop() - for iElm in range(len(self.invCg_tr[0][:,0])): - self.blw[0].setU(iElm, mappedBlw[0][iElm]) - for iElm in range(len(self.invCg_tr[1][:,0])): - self.blw[1].setU(iElm, mappedBlw[1][iElm]) - - def RunSolver(self): - self.iSolver.run() - - def ResetSolver(self): - self.iSolver.reset() - - def GetCp(self,bnd): - import dart.utils as floU - Cp = floU.extract(bnd, self.iSolver.Cp) - return Cp - - def GetAlpha(self): - return self.iSolver.pbl.alpha - - def GetMinf(self): - return self.iSolver.pbl.M_inf - - def GetCl(self): - return self.iSolver.Cl - - def GetCm(self): - return self.iSolver.Cm - - def __Remesh(self, vec, stgPt): - xUp = vec[:stgPt+1] - xUp = xUp[::-1] - - xLw = vec[stgPt:] - return xUp, xLw - - def __RbfToSections(self, x, var, xs): - if np.all(var == var[0]): - varOut = RBFInterpolator(x, var, neighbors=1, kernel='linear', smoothing=0.0, degree=0)(xs) - else: - varOut = RBFInterpolator(x, var, neighbors=self.cfg['neighbors'], kernel=self.cfg['rbftype'], smoothing=self.cfg['smoothing'], degree=self.cfg['degree'])(xs) - return varOut - - - def __GetWing(self, blw, config): - - viscStruct = [[np.zeros((config['nPoints'][1] if i==1 else 2*config['nPoints'][0]-1, 3)) for i in range(2)] for _ in range(config['nSections'])] - viscStruct_tr = [[np.zeros((config['nPoints'][1] if i==1 else 2*config['nPoints'][0]-1, 3)) for i in range(2)] for _ in range(config['nSections'])] - - - invStruct = [np.zeros((len(blw[i].nodes), 4)) for i in range(len(blw))] - invStruct_tr = [np.zeros((len(blw[i].nodes), 4)) for i in range(len(blw))] - - # Wing - upperNodes = np.zeros((0,4)) - lowerNodes = np.zeros((0,4)) - - self.tms['ElmLoop'].start() - # Compute reference normal - nVec = [np.zeros(0) for _ in range(blw[1].tag.elems[0].nodes.size())] - for iNode, n in enumerate(blw[1].tag.elems[0].nodes): - nVec[iNode] = np.array([n.pos[0], n.pos[1], n.pos[2]]) - normalRef = np.cross(nVec[1] - nVec[0], nVec[2] - nVec[0]) - normalRef/=np.linalg.norm(normalRef) - - for e in blw[0].tag.elems: - nVec = [np.zeros(0) for _ in range(e.nodes.size())] - for iNode, n in enumerate(e.nodes): - nVec[iNode] = np.array([n.pos[0], n.pos[1], n.pos[2]]) - normal = np.cross(nVec[1] - nVec[0], nVec[2] - nVec[0]) - normal/=np.linalg.norm(normalRef) - if np.dot(normal, normalRef) >= 0: - for n in e.nodes: - if n.row not in upperNodes[:,3] and n.row not in lowerNodes[:,3]: - upperNodes = np.vstack((upperNodes, [n.pos[0], n.pos[1], n.pos[2], n.row])) - if np.dot(normal, normalRef) < 0: - for n in e.nodes: - if n.row not in lowerNodes[:,3] and n.row not in upperNodes[:,3]: - lowerNodes = np.vstack((lowerNodes, [n.pos[0], n.pos[1], n.pos[2], n.row])) - - self.tms['ElmLoop'].stop() - - dummyLower = lowerNodes.copy() - dummyLower[:,0] *= -1 - - invStruct_tr[0] = np.vstack((upperNodes, dummyLower)) - invStruct[0] = np.vstack((upperNodes, lowerNodes)) - - # Remove duplicates - #invStruct_tr[0] = np.unique(invStruct_tr[0], axis=0) - - # Wake part - for iNode, n in enumerate(blw[1].nodes): - invStruct_tr[1][iNode, :] = [n.pos[0], n.pos[1], n.pos[2], n.row] - invStruct[1] = invStruct_tr[1].copy() - - # Create spanwise distribution - if config['nDim'] == 2: - spanDistri = np.zeros(1) - spanDistri[0] = invStruct[0][0,2] # Span direction is the z direction - - wingSpan = 0. - fInterp = interp1d(invStruct_tr[0][:,0], invStruct_tr[0][:,1]) - - elif config['nDim'] == 3: - invStruct[0][:, [1,2]] = invStruct[0][:, [2, 1]] - invStruct[1][:, [1,2]] = invStruct[1][:, [2, 1]] - invStruct_tr[0][:, [1,2]] = invStruct_tr[0][:, [2, 1]] - invStruct_tr[1][:, [1,2]] = invStruct_tr[1][:, [2, 1]] - spanDistri = np.linspace(min(invStruct[0][:,2]), max(invStruct[0][:,2]), config['nSections']) - spanDistri[0] +=0.1 - spanDistri[-1] -=0.1 - - # Spline wing - # Point in the wing tip region are not accounted for during Bezier curve spline - - m = len(invStruct_tr[0][:,0]) - _s = (m-np.sqrt(2*m) + m+np.sqrt(2*m))/2 - tck_wing = bisplrep(invStruct_tr[0][invStruct_tr[0][:,2]<config['span'],0], invStruct_tr[0][invStruct_tr[0][:,2]<config['span'],2], invStruct_tr[0][invStruct_tr[0][:,2]<config['span'],1], kx=5, ky=5, s=1e-6, quiet=1) - - # Create sections - self.tms['iSecLoop'].start() - - for iSec, z in enumerate(spanDistri): - portion = invStruct[0][abs(invStruct[0][:,2] - z) <= 0.01 * config['span'],:] - - chordLength = max(portion[:, 0]) - min(portion[:, 0]) - xDistri = min(portion[:,0]) + 1/2*(1 + np.cos(np.linspace(0, np.pi, config['nPoints'][0])))*chordLength - - viscStruct[iSec][0][:,0] = np.concatenate((xDistri[:-1], xDistri[::-1]), axis=None) - viscStruct[iSec][0][:,2] = z*np.ones(len(viscStruct[iSec][0][:,0])) - - viscStruct_tr[iSec][0][:,0] = np.concatenate((xDistri[:-1], -xDistri[::-1]), axis=None).copy() - viscStruct_tr[iSec][0][:,2] = z*np.ones(len(viscStruct[iSec][0][:,0])) - - # Interpolation in the transformed space. - if config['nDim'] == 3: - - for iPoint in range(len(viscStruct_tr[iSec][0][:,0])): - viscStruct_tr[iSec][0][iPoint, 1] = bisplev(viscStruct_tr[iSec][0][iPoint,0], viscStruct_tr[iSec][0][iPoint,2], tck_wing) - - - elif config['nDim'] == 2: - viscStruct_tr[iSec][0][:,1] = fInterp(viscStruct_tr[iSec][0][:,0]) - - #viscStruct_tr[iSec][0][0,1] = 0. - #viscStruct_tr[iSec][0][-1,1] = 0. - viscStruct[iSec][0][:,1] = viscStruct_tr[iSec][0][:,1].copy() - - # Wake - wakeLength = np.max(invStruct[1][:,0]) - np.max(viscStruct[iSec][0][:,0]) - viscStruct_tr[iSec][1][:,0] = np.max(viscStruct[iSec][0][:,0]) + (np.max(viscStruct[iSec][0][:,0]) + np.cos(np.linspace(np.pi, np.pi/2, config['nPoints'][1]))) * wakeLength - viscStruct_tr[iSec][1][:,2] = z*np.ones(len(viscStruct[iSec][1][:,0])) - viscStruct_tr[iSec][1][:,1] = interp1d(invStruct_tr[1][:,0], invStruct_tr[1][:,1])(viscStruct_tr[iSec][1][:,0]) - - viscStruct[iSec][1] = viscStruct_tr[iSec][1].copy() - - # Cg positions - self.tms['iSecLoop'].stop() - - """fig = plt.figure() - ax = fig.add_subplot(projection='3d') - ax.scatter(invStruct_tr[0][:,0], invStruct_tr[0][:,2], invStruct_tr[0][:,1], s=0.3) - ax.scatter(invStruct_tr[1][:,0], invStruct_tr[1][:,2], invStruct_tr[1][:,1], s=0.3) - for sec in viscStruct_tr: - ax.scatter(sec[0][:,0], sec[0][:,2], sec[0][:,1], color = 'red') - ax.scatter(sec[1][:,0], sec[1][:,2], sec[1][:,1], color = 'red') - ax.set_zlim([-0.5, 0.5]) - ax.set_xlabel('x') - ax.set_ylabel('y') - ax.set_zlabel('z') - plt.show()""" - - viscCg_tr = [[np.zeros((len(viscStruct[iSec][iReg][:,0]) - 1, 3)) for iReg in range(2)] for iSec in range(len(viscStruct))] - invCg_tr = [np.zeros((len(blw[iReg].tag.elems), 3)) for iReg in range(2)] - self.tms['CgLoop'].start() - - # Viscous - for iSec in range(len(viscStruct)): - for iReg in range(len(viscStruct[iSec])): - for iElm in range(len(viscStruct[iSec][iReg][:,0]) - 1): - for iDir in range(3): - viscCg_tr[iSec][iReg][iElm, iDir] = viscStruct_tr[iSec][iReg][iElm, iDir] + viscStruct_tr[iSec][iReg][iElm + 1, iDir] - viscCg_tr[iSec][iReg] /= 2 - - # Inviscid - for iReg in range(len(blw)): - for iElm, e in enumerate(blw[iReg].tag.elems): - for n in e.nodes: - if n.row in upperNodes[:,3] or iReg == 1: - invCg_tr[iReg][iElm, 0] +=n.pos[0] - elif n.row in lowerNodes[:,3]: - invCg_tr[iReg][iElm, 0] += -n.pos[0] - - invCg_tr[iReg][iElm, 1] +=n.pos[1] - invCg_tr[iReg][iElm, 2] +=n.pos[2] - invCg_tr[iReg][iElm, :] /= e.nodes.size() - - if config['nDim'] == 3: - invCg_tr[iReg][:,[1,2]] = invCg_tr[iReg][:,[2,1]] - self.tms['CgLoop'].stop() - - self.invStruct = invStruct - self.invStruct_tr = invStruct_tr - self.viscStruct = viscStruct - self.viscStruct_tr = viscStruct_tr - - self.invCg_tr = invCg_tr - self.viscCg_tr = viscCg_tr - np.set_printoptions(threshold=sys.maxsize) - for sec in self.viscStruct: - print('next') - sec[0][:,[1,2]] = sec[0][:,[2,1]] - print(sec[0]) +import numpy as np +from matplotlib import pyplot as plt +from fwk.coloring import ccolors + +# 3D spline with Bézier curves +from scipy.interpolate import bisplrep +from scipy.interpolate import bisplev +from scipy.interpolate import splrep +from scipy.interpolate import splev + +from scipy.interpolate import interp1d + +from scipy.interpolate import RBFInterpolator + +import fwk + + +class Interpolator: + def __init__(self, _dartAPI, _blw, _imsh, _vmsh, _cfg): + + self.cfg = _cfg + + self.tms = fwk.Timers() + + self.tms['Mesh sort'].start() + self.idata, self.icg = self.GetMesh(_imsh) + self.vdata, self.vcg = self.GetMesh(_vmsh) + self.sortedRows, self.sortedElems = self.SortMesh(self.vdata, self.vcg) + + self.tms['Mesh sort'].stop() + print(self.tms) + + fig = plt.figure() + ax = fig.add_subplot(projection='3d') + ax.scatter(self.vdata[0][:,0], self.vdata[0][:,1], self.vdata[0][:,2], s=0.3) + ax.scatter(self.vcg[0][:,0], self.vcg[0][:,1], self.vcg[0][:,2], s=0.3) + ax.scatter(self.vdata[1][:,0], self.vdata[1][:,1], self.vdata[1][:,2], s=0.3) + ax.scatter(self.vcg[1][:,0], self.vcg[1][:,1], self.vcg[1][:,2], s=0.3) + ax.set_xlabel('x') + ax.set_ylabel('y') + ax.set_zlabel('z') + #plt.gca().invert_yaxis() + plt.axis('off') + plt.show() + + fig = plt.figure() + ax = fig.add_subplot(projection='3d') + ax.scatter(self.idata[0][:,0], self.idata[0][:,1], self.idata[0][:,2], s=0.3) + ax.scatter(self.icg[0][:,0], self.icg[0][:,1], self.icg[0][:,2], s=0.3) + ax.scatter(self.idata[1][:,0], self.idata[1][:,1], self.idata[1][:,2], s=0.3) + ax.scatter(self.icg[1][:,0], self.icg[1][:,1], self.icg[1][:,2], s=0.3) + ax.set_xlabel('x') + ax.set_ylabel('y') + ax.set_zlabel('z') + #plt.gca().invert_yaxis() + plt.axis('off') + plt.show() + + self.iSolver = _dartAPI + self.blw = _blw + + # Create data structures for interpolation + self.tms = fwk.Timers() + self.tms['GetWing'].start() + """if _cfg['nDim'] == 2: + self.__GetAirfoil(_blw, _cfg) + elif _cfg['nDim'] == 3: + self.__GetWing(_blw, _cfg)""" + self.tms['GetWing'].stop() + + # self.cfg = _cfg + print(self.tms) + + self.stgPt=np.zeros(self.cfg['nSections'], dtype=int) + + self.xxPrev = [[np.zeros(0) for iReg in range(3)] for iSec in range(self.cfg['nSections'])] + #self.uePrev = [[np.zeros(len(self.viscStruct[iSec][iReg][:,0])) for iReg in range(3)] for iSec in range(len(self.viscStruct))] + self.DeltaStarPrev = [[np.zeros(0) for iReg in range(3)] for iSec in range(self.cfg['nSections'])] + + + def GetInvBC(self, vSolver, couplIter): + self.tms['InvToVisc'].start() + + # Extract parameters from the inviscid solver + # Particular care must be taken with space directions; In the inviscid, the airfoil is in the x,z plane. + # While setting up the viscous solver, y and z must be inverted. + + # Wing + + U = [np.zeros((len(self.idata[i][:,0]), 3)) for i in range(len(self.idata))] + M = [np.zeros(len(self.idata[i][:,0])) for i in range(len(self.idata))] + Rho = [np.zeros(len(self.idata[i][:,0])) for i in range(len(self.idata))] + + # Extract variables. + + for iReg in range(len(self.idata)): + for iNode, row in enumerate(self.idata[iReg][:,3]): + row = int(row) + U[iReg][iNode,:] = [self.iSolver.U[row][0], self.iSolver.U[row][1], self.iSolver.U[row][2]] + M[iReg][iNode] = self.iSolver.M[row] + Rho[iReg][iNode] = self.iSolver.rho[row] + + """if self.cfg['nDim'] == 3: + U[iReg][:,[1,2]] = U[iReg][:,[2,1]]""" + + # Find stagnation point + nD = self.cfg['nDim'] + Ux = [self.__RbfToSections(self.idata[0][:,:nD], U[0][:,0], self.vdata[0][:,:nD]), self.__RbfToSections(self.idata[1][:, [0,2] if nD==3 else 0], U[1][:,0], self.vdata[1][:,[0,2] if nD==3 else 0])] + Uy = [self.__RbfToSections(self.idata[0][:,:nD], U[0][:,1], self.vdata[0][:,:nD]), self.__RbfToSections(self.idata[1][:, [0,2] if nD==3 else 0], U[1][:,1], self.vdata[1][:,[0,2] if nD==3 else 0])] + Uz = [self.__RbfToSections(self.idata[0][:,:nD], U[0][:,2], self.vdata[0][:,:nD]), self.__RbfToSections(self.idata[1][:, [0,2] if nD==3 else 0], U[1][:,2], self.vdata[1][:,[0,2] if nD==3 else 0])] + Me = [self.__RbfToSections(self.idata[0][:,:nD], M[0], self.vdata[0][:,:nD]), self.__RbfToSections(self.idata[1][:, [0,2] if nD==3 else 0], M[1], self.vdata[1][:,[0,2] if nD==3 else 0])] + Rhoe = [self.__RbfToSections(self.idata[0][:,:nD], Rho[0], self.vdata[0][:,:nD]), self.__RbfToSections(self.idata[1][:, [0,2] if nD==3 else 0], Rho[1], self.vdata[1][:,[0,2] if nD==3 else 0])] + + print('yeeeeah') + quit() + if couplIter == 0: + self.stgPt[iSec] = np.argmin(Ux[0]**2+Uy[0]**2) + + xUp, xLw = self.__Remesh(self.viscStruct[iSec][0][:,0], self.stgPt[iSec]) + yUp, yLw = self.__Remesh(self.viscStruct[iSec][0][:,1], self.stgPt[iSec]) + zUp, zLw = self.__Remesh(self.viscStruct[iSec][0][:,2], self.stgPt[iSec]) + + vSolver.SetGlobMesh(iSec, 0, xUp, yUp, zUp) + vSolver.SetGlobMesh(iSec, 1, xLw, yLw, zLw) + vSolver.SetGlobMesh(iSec, 2, self.viscStruct[iSec][1][:,0], + self.viscStruct[iSec][1][:,1], + self.viscStruct[iSec][1][:,2]) + + self.DeltaStarPrev[iSec][0] = np.zeros(len(xUp)) + self.DeltaStarPrev[iSec][1] = np.zeros(len(xLw)) + self.DeltaStarPrev[iSec][2] = np.zeros(len(self.viscStruct[iSec][1][:,0])) + + self.xxPrev[iSec][0] = np.zeros(len(xUp)) + self.xxPrev[iSec][1] = np.zeros(len(xLw)) + self.xxPrev[iSec][2] = np.zeros(len(self.viscStruct[iSec][1][:,0])) + + UxUp, UxLw = self.__Remesh(Ux[0], self.stgPt[iSec]) + UyUp, UyLw = self.__Remesh(Uy[0], self.stgPt[iSec]) + UzUp, UzLw = self.__Remesh(Uz[0], self.stgPt[iSec]) + + plt.plot(xUp, UxUp) + plt.plot(xLw, UxLw) + plt.xlabel('$x/c$') + plt.ylabel('$U_x$') + plt.show() + + vSolver.SetVelocities(iSec, 0, UxUp, UyUp, UzUp) + vSolver.SetVelocities(iSec, 1, UxLw, UyLw, UzLw) + vSolver.SetVelocities(iSec, 2, Ux[1], Uy[1], Uz[1]) + + MeUp, MeLw = self.__Remesh(Me[0], self.stgPt[iSec]) + + vSolver.SetMe(iSec, 0, MeUp) + vSolver.SetMe(iSec, 1, MeLw) + vSolver.SetMe(iSec, 2, Me[1]) + + RhoUp, RhoLw = self.__Remesh(Rhoe[0], self.stgPt[iSec]) + + vSolver.SetRhoe(iSec, 0, RhoUp) + vSolver.SetRhoe(iSec, 1, RhoLw) + vSolver.SetRhoe(iSec, 2, Rhoe[1]) + + for iReg in range(3): + vSolver.SetDeltaStarExt(iSec, iReg, self.DeltaStarPrev[iSec][iReg]) + vSolver.SetxxExt(iSec, iReg, self.xxPrev[iSec][iReg]) + + + + def SetBlowingVel(self, vSolver, couplIter): + + for iSec in range(len(self.viscStruct)): + for iReg in range(3): + self.DeltaStarPrev[iSec][iReg] = vSolver.ExtractDeltaStar(iSec, iReg) + self.xxPrev[iSec][iReg] = vSolver.Extractxx(iSec, iReg) + + x = [np.zeros((0,3)) for _ in range(2)] + blw = [np.zeros(0) for _ in range(2)] + + for iSec in range(len(self.viscStruct)): + for iReg in range(2): + if iReg == 0: + x[iReg] = np.vstack((x[iReg], self.viscCg_tr[iSec][iReg][:,:3])) + blwUp = vSolver.ExtractBlowingVel(iSec, 0) + blwLw = vSolver.ExtractBlowingVel(iSec, 1) + blw[iReg] = np.concatenate((blw[iReg], blwUp[::-1] , blwLw)) + elif iReg == 1: + x[iReg] = np.vstack((x[iReg], self.viscCg_tr[iSec][iReg][:,:3])) + blw[iReg] = np.concatenate((blw[iReg], vSolver.ExtractBlowingVel(iSec, 2))) + + fig = plt.figure() + ax = fig.add_subplot(projection='3d') + ax.scatter(x[0][:,0], x[0][:,2], blw[0], color = 'red') + """for sec in viscStruct_tr: + ax.scatter(sec[0][:,0], sec[0][:,2], sec[0][:,1], color = 'red') + #ax.scatter(sec[1][:,0], sec[1][:,2], sec[1][:,1], color = 'red')""" + #ax.set_zlim([-0.5, 0.5]) + ax.set_xlabel('x') + ax.set_ylabel('y') + ax.set_zlabel('Blowing velocity') + #plt.axis('off') + plt.show() + self.tms['Interpolation'].start() + nD = self.cfg['nDim'] + #wignggg = self.__RbfToSections(x[0], blw[0], self.invCg_tr[0][:,:3]) + wakke = self.__RbfToSections(x[1][:, [0,2] if nD==3 else 0], blw[1], self.invCg_tr[1][:, [0,2] if nD==3 else 0]) + mappedBlw = [self.__RbfToSections(x[0], blw[0], self.invCg_tr[0][:,:3]), self.__RbfToSections(x[1][:, [0,2] if nD==3 else 0], blw[1], self.invCg_tr[1][:, [0,2] if nD==3 else 0])] + + self.tms['Interpolation'].stop() + for iElm in range(len(self.invCg_tr[0][:,0])): + self.blw[0].setU(iElm, mappedBlw[0][iElm]) + for iElm in range(len(self.invCg_tr[1][:,0])): + self.blw[1].setU(iElm, mappedBlw[1][iElm]) + + def RunSolver(self): + self.iSolver.run() + + def ResetSolver(self): + self.iSolver.reset() + + def GetCp(self,bnd): + import dart.utils as floU + Cp = floU.extract(bnd, self.iSolver.Cp) + return Cp + + def GetAlpha(self): + return self.iSolver.pbl.alpha + + def GetMinf(self): + return self.iSolver.pbl.M_inf + + def GetCl(self): + return self.iSolver.Cl + + def GetCm(self): + return self.iSolver.Cm + + def __Remesh(self, vec, stgPt): + xUp = vec[:stgPt+1] + xUp = xUp[::-1] + + xLw = vec[stgPt:] + return xUp, xLw + + def __RbfToSections(self, x, var, xs): + if np.all(var == var[0]): + varOut = RBFInterpolator(x, var, neighbors=1, kernel='linear', smoothing=0.0, degree=0)(xs) + else: + varOut = RBFInterpolator(x, var, neighbors=self.cfg['neighbors'], kernel=self.cfg['rbftype'], smoothing=self.cfg['smoothing'], degree=self.cfg['degree'])(xs) + return varOut + + + def __GetWing(self, blw, config): + + viscStruct = [[np.zeros((config['nPoints'][1] if i==1 else 2*config['nPoints'][0]-1, 3)) for i in range(2)] for _ in range(config['nSections'])] + viscStruct_tr = [[np.zeros((config['nPoints'][1] if i==1 else 2*config['nPoints'][0]-1, 3)) for i in range(2)] for _ in range(config['nSections'])] + + + invStruct = [np.zeros((len(blw[i].nodes), 4)) for i in range(len(blw))] + invStruct_tr = [np.zeros((len(blw[i].nodes), 4)) for i in range(len(blw))] + + # Wing + upperNodes = np.zeros((0,4)) + lowerNodes = np.zeros((0,4)) + + self.tms['ElmLoop'].start() + # Compute reference normal + nVec = [np.zeros(0) for _ in range(blw[1].tag.elems[0].nodes.size())] + for iNode, n in enumerate(blw[1].tag.elems[0].nodes): + nVec[iNode] = np.array([n.pos[0], n.pos[1], n.pos[2]]) + normalRef = np.cross(nVec[1] - nVec[0], nVec[2] - nVec[0]) + normalRef/=np.linalg.norm(normalRef) + + for e in blw[0].tag.elems: + nVec = [np.zeros(0) for _ in range(e.nodes.size())] + for iNode, n in enumerate(e.nodes): + nVec[iNode] = np.array([n.pos[0], n.pos[1], n.pos[2]]) + normal = np.cross(nVec[1] - nVec[0], nVec[2] - nVec[0]) + normal/=np.linalg.norm(normalRef) + if np.dot(normal, normalRef) >= 0: + for n in e.nodes: + if n.row not in upperNodes[:,3] and n.row not in lowerNodes[:,3]: + upperNodes = np.vstack((upperNodes, [n.pos[0], n.pos[1], n.pos[2], n.row])) + if np.dot(normal, normalRef) < 0: + for n in e.nodes: + if n.row not in lowerNodes[:,3] and n.row not in upperNodes[:,3]: + lowerNodes = np.vstack((lowerNodes, [n.pos[0], n.pos[1], n.pos[2], n.row])) + + self.tms['ElmLoop'].stop() + + dummyLower = lowerNodes.copy() + dummyLower[:,0] *= -1 + + invStruct_tr[0] = np.vstack((upperNodes, dummyLower)) + invStruct[0] = np.vstack((upperNodes, lowerNodes)) + + # Remove duplicates + #invStruct_tr[0] = np.unique(invStruct_tr[0], axis=0) + + # Wake part + for iNode, n in enumerate(blw[1].nodes): + invStruct_tr[1][iNode, :] = [n.pos[0], n.pos[1], n.pos[2], n.row] + invStruct[1] = invStruct_tr[1].copy() + + # Create spanwise distribution + if config['nDim'] == 2: + spanDistri = np.zeros(1) + spanDistri[0] = invStruct[0][0,2] # Span direction is the z direction + + wingSpan = 0. + fInterp = interp1d(invStruct_tr[0][:,0], invStruct_tr[0][:,1]) + + elif config['nDim'] == 3: + invStruct[0][:, [1,2]] = invStruct[0][:, [2, 1]] + invStruct[1][:, [1,2]] = invStruct[1][:, [2, 1]] + invStruct_tr[0][:, [1,2]] = invStruct_tr[0][:, [2, 1]] + invStruct_tr[1][:, [1,2]] = invStruct_tr[1][:, [2, 1]] + spanDistri = np.linspace(min(invStruct[0][:,2]), max(invStruct[0][:,2]), config['nSections']) + spanDistri[0] +=0.1 + spanDistri[-1] -=0.1 + + # Spline wing + # Point in the wing tip region are not accounted for during Bezier curve spline + + m = len(invStruct_tr[0][:,0]) + _s = (m-np.sqrt(2*m) + m+np.sqrt(2*m))/2 + tck_wing = bisplrep(invStruct_tr[0][invStruct_tr[0][:,2]<config['span'],0], invStruct_tr[0][invStruct_tr[0][:,2]<config['span'],2], invStruct_tr[0][invStruct_tr[0][:,2]<config['span'],1], kx=5, ky=5, s=1e-6, quiet=1) + + # Create sections + self.tms['iSecLoop'].start() + + for iSec, z in enumerate(spanDistri): + portion = invStruct[0][abs(invStruct[0][:,2] - z) <= 0.01 * config['span'],:] + + chordLength = max(portion[:, 0]) - min(portion[:, 0]) + xDistri = min(portion[:,0]) + 1/2*(1 + np.cos(np.linspace(0, np.pi, config['nPoints'][0])))*chordLength + + viscStruct[iSec][0][:,0] = np.concatenate((xDistri[:-1], xDistri[::-1]), axis=None) + viscStruct[iSec][0][:,2] = z*np.ones(len(viscStruct[iSec][0][:,0])) + + viscStruct_tr[iSec][0][:,0] = np.concatenate((xDistri[:-1], -xDistri[::-1]), axis=None).copy() + viscStruct_tr[iSec][0][:,2] = z*np.ones(len(viscStruct[iSec][0][:,0])) + + # Interpolation in the transformed space. + if config['nDim'] == 3: + + for iPoint in range(len(viscStruct_tr[iSec][0][:,0])): + viscStruct_tr[iSec][0][iPoint, 1] = bisplev(viscStruct_tr[iSec][0][iPoint,0], viscStruct_tr[iSec][0][iPoint,2], tck_wing) + + + elif config['nDim'] == 2: + viscStruct_tr[iSec][0][:,1] = fInterp(viscStruct_tr[iSec][0][:,0]) + + #viscStruct_tr[iSec][0][0,1] = 0. + #viscStruct_tr[iSec][0][-1,1] = 0. + viscStruct[iSec][0][:,1] = viscStruct_tr[iSec][0][:,1].copy() + + # Wake + wakeLength = np.max(invStruct[1][:,0]) - np.max(viscStruct[iSec][0][:,0]) + viscStruct_tr[iSec][1][:,0] = np.max(viscStruct[iSec][0][:,0]) + (np.max(viscStruct[iSec][0][:,0]) + np.cos(np.linspace(np.pi, np.pi/2, config['nPoints'][1]))) * wakeLength + viscStruct_tr[iSec][1][:,2] = z*np.ones(len(viscStruct[iSec][1][:,0])) + viscStruct_tr[iSec][1][:,1] = interp1d(invStruct_tr[1][:,0], invStruct_tr[1][:,1])(viscStruct_tr[iSec][1][:,0]) + + viscStruct[iSec][1] = viscStruct_tr[iSec][1].copy() + + # Cg positions + self.tms['iSecLoop'].stop() + + viscCg_tr = [[np.zeros((len(viscStruct[iSec][iReg][:,0]) - 1, 3)) for iReg in range(2)] for iSec in range(len(viscStruct))] + invCg_tr = [np.zeros((len(blw[iReg].tag.elems), 3)) for iReg in range(2)] + self.tms['CgLoop'].start() + + # Viscous + for iSec in range(len(viscStruct)): + for iReg in range(len(viscStruct[iSec])): + for iElm in range(len(viscStruct[iSec][iReg][:,0]) - 1): + for iDir in range(3): + viscCg_tr[iSec][iReg][iElm, iDir] = viscStruct_tr[iSec][iReg][iElm, iDir] + viscStruct_tr[iSec][iReg][iElm + 1, iDir] + viscCg_tr[iSec][iReg] /= 2 + + # Inviscid + for iReg in range(len(blw)): + for iElm, e in enumerate(blw[iReg].tag.elems): + for n in e.nodes: + if n.row in upperNodes[:,3] or iReg == 1: + invCg_tr[iReg][iElm, 0] +=n.pos[0] + elif n.row in lowerNodes[:,3]: + invCg_tr[iReg][iElm, 0] += -n.pos[0] + + invCg_tr[iReg][iElm, 1] +=n.pos[1] + invCg_tr[iReg][iElm, 2] +=n.pos[2] + invCg_tr[iReg][iElm, :] /= e.nodes.size() + + if config['nDim'] == 3: + invCg_tr[iReg][:,[1,2]] = invCg_tr[iReg][:,[2,1]] + self.tms['CgLoop'].stop() + + self.invStruct = invStruct + self.invStruct_tr = invStruct_tr + self.viscStruct = viscStruct + self.viscStruct_tr = viscStruct_tr + + self.invCg_tr = invCg_tr + self.viscCg_tr = viscCg_tr + """np.set_printoptions(threshold=sys.maxsize) + for sec in self.viscStruct: + print('next') + sec[0][:,[1,2]] = sec[0][:,[2,1]] + print(sec[0])""" + + fig = plt.figure() + ax = fig.add_subplot(projection='3d') + ax.scatter(invStruct_tr[0][:,0], invStruct_tr[0][:,2], invStruct_tr[0][:,1], s=0.3) + ax.scatter(invStruct_tr[0][:,0], -invStruct_tr[0][:,2], invStruct_tr[0][:,1], s=0.3, color='grey') + #ax.scatter(invStruct[1][:,0], invStruct[1][:,2], invStruct[1][:,1], s=0.3) + for sec in viscStruct_tr: + ax.scatter(sec[0][:,0], sec[0][:,2], sec[0][:,1], color = 'red') + ax.scatter(sec[1][:,0], sec[1][:,2], sec[1][:,1], color = 'red') + ax.set_zlim([-0.5, 0.5]) + ax.set_xlabel('x') + ax.set_ylabel('y') + ax.set_zlabel('z') + #plt.gca().invert_yaxis() + plt.axis('off') + plt.show() + + + def __GetAirfoil(self, blw, config): + + if config['nSections'] != 1: + raise RuntimeError('Cannot create more than 1 section on 2D geometry. Specified:', config['nSections']) + + viscStruct = [[np.zeros((config['nPoints'][1] if i==1 else 2*config['nPoints'][0]-1, 3)) for i in range(2)] for _ in range(config['nSections'])] + viscStruct_tr = [[np.zeros((config['nPoints'][1] if i==1 else 2*config['nPoints'][0]-1, 3)) for i in range(1)] for _ in range(config['nSections'])] + + # Create node list + nodesCoord = np.zeros((0, 4)) + for n in blw[0].nodes: + nodesCoord = np.vstack((nodesCoord, [n.pos[0], n.pos[1], n.pos[2], n.row])) + + spanDistri = np.zeros(1) + spanDistri[0] = nodesCoord[0,2] # Span direction is the z direction + + wingSpan = max(nodesCoord[:,2]) - min(nodesCoord[:,2]) + + #upperNodes = nodesCoord[nodesCoord[:,2]>0] + + """nVec = [np.zeros(0) for _ in range(blw[1].tag.elems[0].nodes.size())] + nVec = blw[1].tag.elems[0] + normalRef = np.cross(nVec[1] - nVec[0], nVec[2] - nVec[0]) + normalRef/=np.linalg.norm(normalRef) + + upperNodes = np.zeros((0,4)) + lowerNodes = np.zeros((0,4)) + for e in blw[0].tag.elems: + # Compute normal + cVec = [e.nodes[1].pos[0] - e.nodes[0].pos[0], -(e.nodes[1].pos[1] - e.nodes[0].pos[1]), 0] + print(cVec) + if np.dot(cVec, normalRef) >=0: + for n in e.nodes: + if n.row not in upperNodes[:,3] and n.row not in lowerNodes[:,3]: + upperNodes = np.vstack((upperNodes, [n.pos[0], n.pos[1], n.pos[2], n.row])) + + else: + for n in e.nodes: + if n.row not in upperNodes[:,3] and n.row not in lowerNodes[:,3]: + upperNodes = np.vstack((upperNodes, [n.pos[0], n.pos[1], n.pos[2], n.row])) + + plt.plot(upperNodes[:,0], upperNodes[:,1]) + plt.plot(lowerNodes[:,0], lowerNodes[:,1]) + plt.show()""" + for iSec, z in enumerate(spanDistri): + + portion = nodesCoord[abs(nodesCoord[:,2] - z) <= 0.01 * wingSpan,:] + + le_coord = portion[portion[:,0] == np.min((portion[:,0])), :][0] + te_coord = portion[portion[:,0] == np.max((portion[:,0])), :][0] + + # Find te elements + te_elems = [] + for e in blw[0].tag.elems: + for n in e.nodes: + if n.pos[0] == te_coord[0]: + te_elems.append(e) + break + + # Cg of te elements + cg_teElems = np.zeros((len(te_elems), 3)) + for iElm, eTe in enumerate(te_elems): + for n in eTe.nodes: + cg_teElems[iElm, 0] += n.pos[0] + cg_teElems[iElm, 1] += n.pos[1] + cg_teElems[iElm, 2] += n.pos[2] + + # Sort upper side in 0 and lower side in 1 + if cg_teElems[0, 1] < cg_teElems[1, 1]: + save = te_elems[0].copy() + te_elems[0] = te_elems[1] + te_elems[1] = save + + # Find te_nodes (sorted [upper, lower]) + te_nodes = [None, None] + for i in range(len(te_elems)): + for n in te_elems[i].nodes: + if n.pos[0] == te_coord[0]: + te_nodes[i] = n + break + + # Find le_node + for n in blw[0].nodes: + if n.pos[0] == le_coord[0]: + le_node = n + break + + + meany = (le_coord[1] + te_coord[1]) / 2 + + transformedCoord = np.zeros((0, 4)) + nodesList = [] + + for iNode, n in enumerate(blw[0].nodes): + if n.pos[0] != le_coord[0] and n.pos[0] != te_coord[0]: + if n.pos[1] > meany: + transformedCoord = np.vstack((transformedCoord, [n.pos[0], n.pos[1], n.pos[2], n.row])) + nodesList.append(n) + + elif n.pos[1] < meany: + transformedCoord = np.vstack((transformedCoord, [-n.pos[0], n.pos[1], n.pos[2], n.row])) + nodesList.append(n) + + transformedCoord = np.vstack((transformedCoord, le_coord)) + nodesList.append(le_node) + transformedCoord = np.vstack((transformedCoord, [te_nodes[0].pos[0], te_nodes[0].pos[1], te_nodes[0].pos[2], te_nodes[0].row])) + nodesList.append(te_nodes[0]) + transformedCoord = np.vstack((transformedCoord, [-te_nodes[1].pos[0], te_nodes[1].pos[1], te_nodes[1].pos[2], te_nodes[1].row])) + nodesList.append(te_nodes[1]) + + wakeCoord = np.zeros((len(blw[1].nodes), 4)) + for iNode, n in enumerate(blw[1].nodes): + wakeCoord[iNode, 0] = n.pos[0] + wakeCoord[iNode, 1] = n.pos[1] + wakeCoord[iNode, 2] = n.pos[2] + wakeCoord[iNode, 3] = n.row + + chordLength = max(portion[:, 0]) - min(portion[:, 0]) + xDistri = le_coord[0] + 1/2*(1 + np.cos(np.linspace(0, np.pi, config['nPoints'][0])))*chordLength + + viscStruct[iSec][0][:,0] = np.concatenate((xDistri[:-1], xDistri[::-1]), axis=None) + viscStruct[iSec][0][:,2] = z*np.ones(len(viscStruct[iSec][0][:,0])) + + viscStruct_tr[iSec][0][:,0] = np.concatenate((xDistri[:-1], -xDistri[::-1]), axis=None).copy() + viscStruct_tr[iSec][0][:,2] = z*np.ones(len(viscStruct[iSec][0][:,0])) + + # Interpolation in the transformed space. + splineTr = transformedCoord.copy() + splineTr = splineTr[splineTr[:, 0].argsort()] + spl = splrep(splineTr[:,0], splineTr[:,1], k=5) + viscStruct_tr[iSec][0][:,1] = splev(viscStruct_tr[iSec][0][:,0], spl) + #viscStruct_tr[iSec][0][:,1] = interp1d(transformedCoord[:,0], transformedCoord[:,1])(viscStruct_tr[iSec][0][:,0]) + viscStruct[iSec][0][:,1] = viscStruct_tr[iSec][0][:,1].copy() + + # Wake + wakeLength = np.max(wakeCoord[:,0]) - np.max(viscStruct[iSec][0][:,0]) + viscStruct[iSec][1][:,0] = np.max(viscStruct[iSec][0][:,0]) + (np.max(viscStruct[iSec][0][:,0]) + np.cos(np.linspace(np.pi, np.pi/2, config['nPoints'][1]))) * wakeLength + viscStruct[iSec][1][:,2] = z*np.ones(len(viscStruct[iSec][1][:,0])) + viscStruct[iSec][1][:,1] = interp1d(wakeCoord[:,0], wakeCoord[:,1])(viscStruct[iSec][1][:,0]) + + self.invStruct = [np.zeros((0, 4)) for _ in range(2)] + self.invStruct_tr = [np.zeros((0, 4)) for _ in range(2)] + self.invStruct[0] = abs(transformedCoord.copy()) + self.invStruct_tr[0] = transformedCoord.copy() + self.invStruct[1] = abs(wakeCoord.copy()) + self.invStruct_tr[1] = wakeCoord.copy() + + print(np.shape(self.invStruct[0])) + + + self.viscStruct = viscStruct + self.viscStruct_tr = viscStruct_tr + #plt.plot(nodesCoord[:,0], nodesCoord[:,1], 'o', markersize=8, color='green') + plt.plot(viscStruct[0][0][:,0], viscStruct[0][0][:,1], 'x', color='blue') + plt.axis('off') + plt.show() + return nodesList, transformedCoord, wakeCoord, viscStruct, viscStruct_tr + + def GetMesh(self, msh): + + data = [np.zeros((0,4)) for _ in range(2)] + cg = [np.zeros((0,4)) for _ in range(2)] + + alreadysaid = [''] + for e in msh.elems: + if e.ptag.name not in alreadysaid: + print(e.ptag.name) + alreadysaid.append(e.ptag.name) + print('') + + for e in msh.elems: + # Compute cg position + cg_pt = np.zeros(3) + for n in e.nodes: + cg_pt += [n.pos[0], n.pos[1], n.pos[2]] + cg_pt/=e.nodes.size() + cg_pt = np.hstack((cg_pt, e.no)) + + if e.ptag.name == "wake": + for nw in e.nodes: + if nw.row not in data[1][:,3]: + data[1] = np.vstack((data[1], [nw.pos[0], nw.pos[1], nw.pos[2], nw.row])) + cg[1] = np.vstack((cg[1], cg_pt)) + elif e.ptag.name == 'wing': + for nw in e.nodes: + if nw.row not in data[0][:,3]: + data[0] = np.vstack((data[0], [nw.pos[0], nw.pos[1], nw.pos[2], nw.row])) + cg[0] = np.vstack((cg[0], cg_pt)) + elif e.ptag.name == 'wing_': + for nw in e.nodes: + if nw.row not in data[0][:,3]: + data[0] = np.vstack((data[0], [-nw.pos[0], nw.pos[1], nw.pos[2], nw.row])) + cg_pt[0] = -cg_pt[0] + cg[0] = np.vstack((cg[0], cg_pt)) + + return data, cg + + def SortMesh(self, data, cg): + + data = data.copy() + + data[0] = data[0][data[0][:,1]<=1, :] + + cg = data.copy() + + cg[0] = cg[0][cg[0][:,1]<=1, :] + + sections = data[0][:,1] + for i in range(len(sections)): + sections[i] = round(sections[i], 3) + sections = np.unique(sections) + + nChord = [len(data[i][abs(data[i][:,1]-sections[0])<1e-3, 0]) for i in range(len(data))] + + sortedRows = [np.zeros((nChord[i], 0)) for i in range(len(data))] + + for iReg, reg in enumerate(data): + + for iy, y in enumerate(sections): + + # Find nearest value in the mesh + + idx = (np.abs(reg[:,1]-y).argmin()) + sections[iy] = reg[idx,1] + + sort = reg[abs(reg[:,1]-sections[iy])<1e-3, :] + + sortedRows[iReg] = np.column_stack((sortedRows[iReg], sort[:,3])) + + sections_cg = cg[0][:,1] + for i in range(len(sections_cg)): + sections_cg[i] = round(sections_cg[i], 3) + sections_cg = np.unique(sections) + + nChord_cg = [len(cg[i][abs(cg[i][:,1]-sections[0])<1e-3, 0]) for i in range(len(cg))] + + sortedElems = [np.zeros((nChord_cg[i], 0)) for i in range(len(cg))] + + for iReg, reg in enumerate(cg): + + for iy, y in enumerate(sections_cg): + + # Find nearest value in the mesh + + idx = (np.abs(reg[:,1]-y).argmin()) + sections_cg[iy] = reg[idx,1] + + sort = reg[abs(reg[:,1]-sections_cg[iy])<1e-3, :] + + sortedElems[iReg] = np.column_stack((sortedElems[iReg], sort[:,3])) + + return sortedRows, sortedElems + + + + + + + + \ No newline at end of file diff --git a/vii/pyVII/vUtils.py b/vii/pyVII/vUtils.py index 16b8868..0a49e49 100644 --- a/vii/pyVII/vUtils.py +++ b/vii/pyVII/vUtils.py @@ -23,6 +23,30 @@ def initBL(Re, Minf, CFL0, nSections, verbose=1): return solver +def mesh(file, pars): + """Initialize mesh and mesh writer + + Parameters + ---------- + dim : int (2 or 3) + number of dimensions + file : str + file contaning mesh (w/o extention) + pars : dict + parameters for mesh + bnds : array of str + names of crack (wake) boundaries physical tag + wk : str (optional) + name of crack (wake) physical tag + wktp : str (optional) + name of crack (wake) tip physical tag + """ + import tbox.gmsh as tmsh + # load the mesh + msh = tmsh.MeshLoader(file,__file__).execute(**pars) + return msh + + def GetSolution(iSec, vSolver): if iSec<0: raise RuntimeError("dart::viscU Invalid section number", iSec) diff --git a/vii/src/wBLRegion.cpp b/vii/src/wBLRegion.cpp index deb501f..9f18080 100644 --- a/vii/src/wBLRegion.cpp +++ b/vii/src/wBLRegion.cpp @@ -94,16 +94,17 @@ void BLRegion::SetStagBC(double Re) DeltaStar[0] = U[0] * U[1]; - std::vector<double> ClosParam = closSolver->LaminarClosures(U[0], U[1], Ret[0], invBnd->GetMe(0), name); - - Hstar[0] = ClosParam[0]; - Hstar2[0] = ClosParam[1]; - Hk[0] = ClosParam[2]; - Cf[0] = ClosParam[3]; - Cd[0] = ClosParam[4]; - Delta[0] = ClosParam[5]; - Cteq[0] = ClosParam[6]; - Us[0] = ClosParam[7]; + std::vector<double> lamParam(8, 0.); + closSolver->LaminarClosures(lamParam, U[0], U[1], Ret[0], invBnd->GetMe(0), name); + + Hstar[0] = lamParam[0]; + Hstar2[0] = lamParam[1]; + Hk[0] = lamParam[2]; + Cf[0] = lamParam[3]; + Cd[0] = lamParam[4]; + Delta[0] = lamParam[5]; + Cteq[0] = lamParam[6]; + Us[0] = lamParam[7]; } // End SetStagBC @@ -133,16 +134,17 @@ void BLRegion::SetWakeBC(double Re, std::vector<double> UpperCond, std::vector<d /* Laminar closures. */ - std::vector<double> ClosParam = closSolver->LaminarClosures(U[0], U[1], Ret[0], invBnd->GetMe(0), name); - - Hstar[0] = ClosParam[0]; - Hstar2[0] = ClosParam[1]; - Hk[0] = ClosParam[2]; - Cf[0] = ClosParam[3]; - Cd[0] = ClosParam[4]; - Delta[0] = ClosParam[5]; - Cteq[0] = ClosParam[6]; - Us[0] = ClosParam[7]; + std::vector<double> lamParam(8, 0.); + closSolver->LaminarClosures(lamParam, U[0], U[1], Ret[0], invBnd->GetMe(0), name); + + Hstar[0] = lamParam[0]; + Hstar2[0] = lamParam[1]; + Hk[0] = lamParam[2]; + Cf[0] = lamParam[3]; + Cd[0] = lamParam[4]; + Delta[0] = lamParam[5]; + Cteq[0] = lamParam[6]; + Us[0] = lamParam[7]; for (size_t k = 0; k < mesh->GetnMarkers(); ++k) { diff --git a/vii/src/wClosures.cpp b/vii/src/wClosures.cpp index 49c1aa8..0c0434a 100644 --- a/vii/src/wClosures.cpp +++ b/vii/src/wClosures.cpp @@ -12,7 +12,7 @@ Closures::~Closures(){} /** * @brief Laminar closure relations */ -std::vector<double> Closures::LaminarClosures(double theta, double H, double Ret, double Me, std::string name) const +void Closures::LaminarClosures(std::vector<double> &closureVars, double theta, double H, double Ret, const double Me, const std::string name) const { H = std::max(H, 1.00005); @@ -90,29 +90,15 @@ std::vector<double> Closures::LaminarClosures(double theta, double H, double Ret double Us = 0.; double Cteq = 0.; - std::vector<double> ClosureVars(8, 0.); - - ClosureVars[0] = Hstar; - ClosureVars[1] = Hstar2; - ClosureVars[2] = Hk; - ClosureVars[3] = Cf; - ClosureVars[4] = Cd; - ClosureVars[5] = delta; - ClosureVars[6] = Cteq; - ClosureVars[7] = Us; - - return ClosureVars; + closureVars = {Hstar, Hstar2, Hk, Cf, Cd, delta, Cteq, Us}; } /** * @brief Turbulent closure relations */ -std::vector<double> Closures::TurbulentClosures(double theta, double H, double Ct, double Ret, double Me, std::string name) const +void Closures::TurbulentClosures(std::vector<double> &closureVars, double theta, double H, double Ct, double Ret, const double Me, const std::string name) const { - /*if (std::isnan(Ret)) - { - std::cout << "Ret is nan. H:" << H << std::endl; - }*/ + H = std::max(H, 1.00005); Ct = std::min(Ct, 0.3); //Ct = std::max(std::min(Ct, 0.30), 0.0000001); @@ -154,6 +140,7 @@ std::vector<double> Closures::TurbulentClosures(double theta, double H, double C { Hstar = (Hk-H0)*(Hk-H0)*(0.007*std::log(Ret)/((Hk-H0+4/std::log(Ret))*(Hk-H0+4/std::log(Ret))) + 0.015/Hk) + 1.5 + 4/Ret; } + /* Whitfield's minor additional compressibility correction */ Hstar = (Hstar + 0.028*Me*Me)/(1+0.014*Me*Me); @@ -223,20 +210,92 @@ std::vector<double> Closures::TurbulentClosures(double theta, double H, double C std::cout << "Negative sqrt encountered " << std::endl; //throw; } - //double Cteq = std::sqrt(n*Hstar*Ctcon*((Hk-1)*Hkc*Hkc)/((1-Us)*(Hk*Hk)*H)); + + /* Dissipation coefficient */ Cd = n*(Cdw+ Cdd + Cdl); - // Ueq = 1.25/Hk*(Cf/2-((Hk-1)/(6.432*Hk))**2) - std::vector<double> ClosureVars(8, 0.); + closureVars = {Hstar, Hstar2, Hk, Cf, Cd, delta, Cteq, Us}; + +} + +void Closures::TurbulentClosures(double &closureVars, double theta, double H, double Ct, double Ret, const double Me, const std::string name) const +{ - ClosureVars[0] = Hstar; - ClosureVars[1] = Hstar2; - ClosureVars[2] = Hk; - ClosureVars[3] = Cf; - ClosureVars[4] = Cd; - ClosureVars[5] = delta; - ClosureVars[6] = Cteq; - ClosureVars[7] = Us; + H = std::max(H, 1.00005); + Ct = std::min(Ct, 0.3); - return ClosureVars; + double Hk = (H - 0.29*Me*Me)/(1+0.113*Me*Me); + if (name == "wake") + { + Hk = std::max(Hk, 1.00005); + } + else + { + Hk = std::max(Hk, 1.05000); + } + + double Hstar2 = ((0.064/(Hk-0.8))+0.251)*Me*Me; + double gamma = 1.4 - 1.; + double Fc = std::sqrt(1+0.5*gamma*Me*Me); /* .2 can be used as well replacing .5*gamma */ + + double H0 = 0.; + if (Ret <= 400) + { + H0 = 4.0; + } + else + { + H0 = 3 + (400/Ret); + } + if (Ret <= 200) + { + Ret = 200; + } + + double Hstar = 0.; + if (Hk <= H0) + { + Hstar = ((0.5-4/Ret)*((H0-Hk)/(H0-1))*((H0-Hk)/(H0-1)))*(1.5/(Hk+0.5))+1.5+4/Ret; + } + else + { + Hstar = (Hk-H0)*(Hk-H0)*(0.007*std::log(Ret)/((Hk-H0+4/std::log(Ret))*(Hk-H0+4/std::log(Ret))) + 0.015/Hk) + 1.5 + 4/Ret; + } + + /* Whitfield's minor additional compressibility correction */ + Hstar = (Hstar + 0.028*Me*Me)/(1+0.014*Me*Me); + + /* Equivalent normalized wall slip velocity */ + double Us = (Hstar/2)*(1-4*(Hk-1)/(3*H)); + + double Ctcon = 0.5/(6.7*6.7*0.75); + + double Hkc = 0.; + double Cteq = 0.; + + if (name == "wake") + { + if (Us > 0.99995) + { + Us = 0.99995; + } + Hkc = Hk - 1; + Cteq = std::sqrt(4*Hstar*Ctcon*((Hk-1)*Hkc*Hkc)/((1-Us)*(Hk*Hk)*H)); // Here it is Cteq^0.5 + } + else + { + if (Us > 0.95) + { + Us = 0.98; + } + Hkc = std::max(Hk-1-18/Ret, 0.01); + Cteq = std::sqrt(Hstar*Ctcon*((Hk-1)*Hkc*Hkc)/((1-Us)*(Hk*Hk)*H)); // Here it is Cteq^0.5 + } + if (Hstar*Ctcon*((Hk-1)*Hkc*Hkc)/((1-Us)*(Hk*Hk)*H)<0) + { + std::cout << "Negative sqrt encountered " << std::endl; + } + + closureVars = Cteq; + } \ No newline at end of file diff --git a/vii/src/wClosures.h b/vii/src/wClosures.h index 23f92d9..a786a79 100644 --- a/vii/src/wClosures.h +++ b/vii/src/wClosures.h @@ -13,8 +13,9 @@ class DART_API Closures public: Closures(); ~Closures(); - std::vector<double> LaminarClosures(double theta, double H, double Ret, double Me, std::string name) const; - std::vector<double> TurbulentClosures(double theta, double H, double Ct, double Ret, double Me, std::string name) const; + void LaminarClosures(std::vector<double> &closureVars, double theta, double H, double Ret, const double Me, const std::string name) const; + void TurbulentClosures(std::vector<double> &closureVars, double theta, double H, double Ct, double Ret, double Me, const std::string name) const; + void TurbulentClosures(double &closureVars, double theta, double H, double Ct, double Ret, const double Me, const std::string name) const; }; } // namespace vii #endif //WClosures_H \ No newline at end of file diff --git a/vii/src/wTimeSolver.cpp b/vii/src/wTimeSolver.cpp index be6e0e7..8c8ea39 100644 --- a/vii/src/wTimeSolver.cpp +++ b/vii/src/wTimeSolver.cpp @@ -194,7 +194,8 @@ void TimeSolver::ResetSolution(size_t iPoint, BLRegion *bl, std::vector<double> if (bl->Regime[iPoint] == 0) { - std::vector<double> lamParam = bl->closSolver->LaminarClosures(bl->U[iPoint * nVar + 0], bl->U[iPoint * nVar + 1], bl->Ret[iPoint], bl->invBnd->GetMe(iPoint), bl->name); + std::vector<double> lamParam(8, 0.); + bl->closSolver->LaminarClosures(lamParam, bl->U[iPoint * nVar + 0], bl->U[iPoint * nVar + 1], bl->Ret[iPoint], bl->invBnd->GetMe(iPoint), bl->name); bl->Hstar[iPoint] = lamParam[0]; bl->Hstar2[iPoint] = lamParam[1]; bl->Hk[iPoint] = lamParam[2]; @@ -206,7 +207,8 @@ void TimeSolver::ResetSolution(size_t iPoint, BLRegion *bl, std::vector<double> } // End if else if (bl->Regime[iPoint] == 1) { - std::vector<double> turbParam = bl->closSolver->TurbulentClosures(bl->U[iPoint * nVar + 0], bl->U[iPoint * nVar + 1], bl->U[iPoint * nVar + 4], bl->Ret[iPoint], bl->invBnd->GetMe(iPoint), bl->name); + std::vector<double> turbParam(8, 0.); + bl->closSolver->TurbulentClosures(turbParam, bl->U[iPoint * nVar + 0], bl->U[iPoint * nVar + 1], bl->U[iPoint * nVar + 4], bl->Ret[iPoint], bl->invBnd->GetMe(iPoint), bl->name); bl->Hstar[iPoint] = turbParam[0]; bl->Hstar2[iPoint] = turbParam[1]; bl->Hk[iPoint] = turbParam[2]; diff --git a/vii/src/wViscFluxes.cpp b/vii/src/wViscFluxes.cpp index 1b667ba..672aa99 100644 --- a/vii/src/wViscFluxes.cpp +++ b/vii/src/wViscFluxes.cpp @@ -83,7 +83,8 @@ VectorXd ViscFluxes::BLlaws(size_t iPoint, BLRegion *bl, std::vector<double> u) if (bl->Regime[iPoint] == 0) { /* Laminar closure relations */ - std::vector<double> lamParam = bl->closSolver->LaminarClosures(u[0], u[1], bl->Ret[iPoint], bl->invBnd->GetMe(iPoint), bl->name); + std::vector<double> lamParam(8, 0.); + bl->closSolver->LaminarClosures(lamParam, u[0], u[1], bl->Ret[iPoint], bl->invBnd->GetMe(iPoint), bl->name); bl->Hstar[iPoint] = lamParam[0]; bl->Hstar2[iPoint] = lamParam[1]; bl->Hk[iPoint] = lamParam[2]; @@ -97,7 +98,8 @@ VectorXd ViscFluxes::BLlaws(size_t iPoint, BLRegion *bl, std::vector<double> u) else if (bl->Regime[iPoint] == 1) { /* Turbulent closure relations */ - std::vector<double> turbParam = bl->closSolver->TurbulentClosures(u[0], u[1], u[4], bl->Ret[iPoint], bl->invBnd->GetMe(iPoint), bl->name); + std::vector<double> turbParam(8, 0.); + bl->closSolver->TurbulentClosures(turbParam, u[0], u[1], u[4], bl->Ret[iPoint], bl->invBnd->GetMe(iPoint), bl->name); bl->Hstar[iPoint] = turbParam[0]; bl->Hstar2[iPoint] = turbParam[1]; bl->Hk[iPoint] = turbParam[2]; diff --git a/vii/src/wViscSolver.cpp b/vii/src/wViscSolver.cpp index c7dcb05..3e364fc 100644 --- a/vii/src/wViscSolver.cpp +++ b/vii/src/wViscSolver.cpp @@ -327,8 +327,9 @@ void ViscSolver::AverageTransition(size_t iPoint, BLRegion *bl, int forced) double avLam = 1. - avTurb; /* Impose boundary condition */ - std::vector<double> turbParam1 = bl->closSolver->TurbulentClosures(bl->U[(iPoint - 1) * nVar + 0], bl->U[(iPoint - 1) * nVar + 1], 0.03, bl->Ret[iPoint - 1], bl->invBnd->GetMe(iPoint - 1), bl->name); - bl->Cteq[iPoint - 1] = turbParam1[6]; + double Cteq_trans; + bl->closSolver->TurbulentClosures(Cteq_trans, bl->U[(iPoint - 1) * nVar + 0], bl->U[(iPoint - 1) * nVar + 1], 0.03, bl->Ret[iPoint - 1], bl->invBnd->GetMe(iPoint - 1), bl->name); + bl->Cteq[iPoint - 1] = Cteq_trans; bl->U[(iPoint - 1) * nVar + 4] = 0.7 * bl->Cteq[iPoint - 1]; /* Avoid starting with ill conditioned IC for turbulent computation. (Regime was switched above) */ @@ -353,7 +354,8 @@ void ViscSolver::AverageTransition(size_t iPoint, BLRegion *bl, int forced) bl->U[iPoint * nVar + 4] = avTurb * bl->U[(iPoint)*nVar + 4]; /* Ct */ /* Recompute closures. (The turbulent BC @ iPoint - 1 does not influence laminar closure relations). */ - std::vector<double> lamParam = bl->closSolver->LaminarClosures(bl->U[(iPoint - 1) * nVar + 0], bl->U[(iPoint - 1) * nVar + 1], bl->Ret[iPoint - 1], bl->invBnd->GetMe(iPoint - 1), bl->name); + std::vector<double> lamParam(8, 0.); + bl->closSolver->LaminarClosures(lamParam, bl->U[(iPoint - 1) * nVar + 0], bl->U[(iPoint - 1) * nVar + 1], bl->Ret[iPoint - 1], bl->invBnd->GetMe(iPoint - 1), bl->name); bl->Hstar[iPoint - 1] = lamParam[0]; bl->Hstar2[iPoint - 1] = lamParam[1]; bl->Hk[iPoint - 1] = lamParam[2]; @@ -363,7 +365,8 @@ void ViscSolver::AverageTransition(size_t iPoint, BLRegion *bl, int forced) bl->Cteq[iPoint - 1] = lamParam[6]; bl->Us[iPoint - 1] = lamParam[7]; - std::vector<double> turbParam = bl->closSolver->TurbulentClosures(bl->U[(iPoint)*nVar + 0], bl->U[(iPoint)*nVar + 1], bl->U[(iPoint)*nVar + 4], bl->Ret[iPoint], bl->invBnd->GetMe(iPoint), bl->name); + std::vector<double> turbParam(8, 0.); + bl->closSolver->TurbulentClosures(turbParam, bl->U[(iPoint)*nVar + 0], bl->U[(iPoint)*nVar + 1], bl->U[(iPoint)*nVar + 4], bl->Ret[iPoint], bl->invBnd->GetMe(iPoint), bl->name); bl->Hstar[iPoint] = turbParam[0]; bl->Hstar2[iPoint] = turbParam[1]; bl->Hk[iPoint] = turbParam[2]; diff --git a/vii/tests/bli2.py b/vii/tests/bli2.py index cf3b476..c46a10a 100644 --- a/vii/tests/bli2.py +++ b/vii/tests/bli2.py @@ -57,7 +57,7 @@ def main(): # define flow variables Re = 1e7 - alpha = 2.*math.pi/180 + alpha = 5.*math.pi/180 M_inf = 0. CFL0 = 1 diff --git a/vii/tests/bli3.py b/vii/tests/bli3.py index 718ba48..29c99f8 100644 --- a/vii/tests/bli3.py +++ b/vii/tests/bli3.py @@ -1,117 +1,120 @@ -#!/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 lifting (linear or nonlinear) potential flow around a NACA 0012 rectangular wing -# Adrien Crovato -# -# Test the nonlinear shock-capturing capability and the Kutta condition -# -# CAUTION -# This test is provided to ensure that the solver works properly. -# Mesh refinement may have to be performed to obtain physical results. - -import math -import dart.utils as floU -import dart.default as floD - -import dart.pyVII.vUtils as viscU -import dart.pyVII.vCoupler2 as viscC -import dart.pyVII.vInterpolator as vInterpol - -import fwk -from fwk.testing import * -from fwk.coloring import ccolors - -def main(): - # timer - tms = fwk.Timers() - tms['total'].start() - - # define flow variables - """Re = 11.72e6 - alpha = 3.06*math.pi/180 - M_inf = 0.8395""" - Re = 1e7 - alpha = 0.*math.pi/180 - M_inf = 0. - dim = 3 - CFL0 = 1 - - nSections = 5 - - # define dimension and mesh size - spn = 1.0 # wing span - lgt = 3.0 # channel half length - hgt = 3.0 # channel half height - wdt = 3.0 # channel width - S_ref = 1.*spn # reference area - c_ref = 1 # reference chord - fms = 1.0 # farfield mesh size - nms = 0.02 # nearfield mesh size - - # mesh the geometry - print(ccolors.ANSI_BLUE + 'PyMeshing...' + ccolors.ANSI_RESET) - tms['msh'].start() - pars = {'spn' : spn, 'lgt' : lgt, 'wdt' : wdt, 'hgt' : hgt, 'msLe' : nms, 'msTe' : nms, 'msF' : fms} - msh, gmshWriter = floD.mesh(dim, 'models/n0012_3.geo', pars, ['field', 'wing', 'symmetry', 'downstream'], wktp = 'wakeTip') - tms['msh'].stop() - - # set the problem and add fluid, initial/boundary conditions - tms['pre'].start() - pbl, _, wk, bnd, blw = floD.problem(msh, dim, alpha, 0., M_inf, S_ref, c_ref, 0., 0., 0., 'wing', tp = 'teTip', vsc=True) - tms['pre'].stop() - - # solve problem - config = {'nDim': dim, 'nSections':nSections, 'span':spn, 'nPoints':[100, 25], 'eps':0.02, 'rbftype': 'cubic', 'smoothing': 1e-8, 'degree': 1, 'neighbors': 50} - iSolverAPI = vInterpol.Interpolator(floD.newton(pbl), blw, config) - vSolver = viscU.initBL(Re, M_inf, CFL0, nSections, 2) - #iSolverAPI = viscAPI.dartAPI(floD.newton(pbl), bnd, wk, nSections, vInterp) - coupler = viscC.Coupler(iSolverAPI, vSolver) - - coupler.Run() - - # display timers - tms['total'].stop() - print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET) - print('CPU statistics') - print(tms) - print(coupler.tms) - - # visualize solution - iSolverAPI.GetCp() - iSolverAPI.iSolver.save(gmshWriter) - floD.initViewer(pbl) - - # check results - print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET) - tests = CTests() - if alpha == 3*math.pi/180 and M_inf == 0.3 and spn == 1.0: - tests.add(CTest('iteration count', solver.nIt, 3, 1, forceabs=True)) - tests.add(CTest('CL', solver.Cl, 0.135, 5e-2)) - tests.add(CTest('CD', solver.Cd, 0.0062, 1e-2)) # Tranair (NF=0.0062, FF=0.0030), Panair 0.0035 - tests.add(CTest('CS', solver.Cs, 0.0121, 5e-2)) - tests.add(CTest('CM', solver.Cm, -0.0278, 1e-2)) - else: - raise Exception('Test not defined for this flow') - tests.run() - - # eof - print('') - -if __name__ == "__main__": - main() +#!/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 lifting (linear or nonlinear) potential flow around a NACA 0012 rectangular wing +# Adrien Crovato +# +# Test the nonlinear shock-capturing capability and the Kutta condition +# +# CAUTION +# This test is provided to ensure that the solver works properly. +# Mesh refinement may have to be performed to obtain physical results. + +import math +import dart.utils as floU +import dart.default as floD + +import vii.pyVII.vUtils as viscU +import vii.pyVII.vCoupler2 as viscC +import vii.pyVII.vInterpolator as vInterpol + +import fwk +from fwk.testing import * +from fwk.coloring import ccolors + +def main(): + # timer + tms = fwk.Timers() + tms['total'].start() + + # define flow variables + """Re = 11.72e6 + alpha = 3.06*math.pi/180 + M_inf = 0.8395""" + Re = 1e7 + alpha = 0.*math.pi/180 + M_inf = 0. + dim = 3 + CFL0 = 1 + + nSections = 50 + + # define dimension and mesh size + spn = 1.0 # wing span + lgt = 3.0 # channel half length + hgt = 3.0 # channel half height + wdt = 3.0 # channel width + S_ref = 1.*spn # reference area + c_ref = 1 # reference chord + fms = 1.0 # farfield mesh size + nms = 0.02 # nearfield mesh size + + # mesh the geometry + print(ccolors.ANSI_BLUE + 'PyMeshing...' + ccolors.ANSI_RESET) + tms['msh'].start() + pars = {'spn' : spn, 'lgt' : lgt, 'wdt' : wdt, 'hgt' : hgt, 'msLe' : nms, 'msTe' : nms, 'msF' : fms} + imsh = viscU.mesh('/home/paul/lab/dartflo/dart/models/n0012_3.geo', pars) + vmsh = viscU.mesh('/home/paul/lab/dartflo/vii/models/n0012_3_visc.geo', pars) + msh, gmshWriter = floD.mesh(dim, 'models/n0012_3.geo', pars, ['field', 'wing', 'symmetry', 'downstream'], wktp = 'wakeTip') + tms['msh'].stop() + + # set the problem and add fluid, initial/boundary conditions + tms['pre'].start() + # Replce tp = 'teTip' by tp = 'wakeTip' for oneraM6.geo + pbl, _, wk, bnd, blw = floD.problem(msh, dim, alpha, 0., M_inf, S_ref, c_ref, 0., 0., 0., 'wing', tp = 'teTip', vsc=True) + tms['pre'].stop() + + # solve problem + config = {'nDim': dim, 'nSections':nSections, 'span':spn, 'nPoints':[100, 25], 'eps':0.02, 'rbftype': 'linear', 'smoothing': 1e-6, 'degree': 0, 'neighbors': 50} + iSolverAPI = vInterpol.Interpolator(floD.newton(pbl), blw, imsh, vmsh, config) + vSolver = viscU.initBL(Re, M_inf, CFL0, nSections, 2) + #iSolverAPI = viscAPI.dartAPI(floD.newton(pbl), bnd, wk, nSections, vInterp) + coupler = viscC.Coupler(iSolverAPI, vSolver) + + coupler.Run() + + # display timers + tms['total'].stop() + print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET) + print('CPU statistics') + print(tms) + print(coupler.tms) + + # visualize solution + iSolverAPI.GetCp() + iSolverAPI.iSolver.save(gmshWriter) + floD.initViewer(pbl) + + # check results + print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET) + tests = CTests() + if alpha == 3*math.pi/180 and M_inf == 0.3 and spn == 1.0: + tests.add(CTest('iteration count', solver.nIt, 3, 1, forceabs=True)) + tests.add(CTest('CL', solver.Cl, 0.135, 5e-2)) + tests.add(CTest('CD', solver.Cd, 0.0062, 1e-2)) # Tranair (NF=0.0062, FF=0.0030), Panair 0.0035 + tests.add(CTest('CS', solver.Cs, 0.0121, 5e-2)) + tests.add(CTest('CM', solver.Cm, -0.0278, 1e-2)) + else: + raise Exception('Test not defined for this flow') + tests.run() + + # eof + print('') + +if __name__ == "__main__": + main() -- GitLab