From f50785a5eee5a9445679a882f27099f68e703e09 Mon Sep 17 00:00:00 2001 From: pcarruscag Date: Wed, 11 Mar 2020 15:20:29 +0000 Subject: [PATCH 01/79] general cleanup --- SU2_CFD/include/solvers/CFEASolver.hpp | 6 +++--- SU2_CFD/src/solvers/CFEASolver.cpp | 16 ++++------------ 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/SU2_CFD/include/solvers/CFEASolver.hpp b/SU2_CFD/include/solvers/CFEASolver.hpp index b4a20c377d97..948ef934ffef 100644 --- a/SU2_CFD/include/solvers/CFEASolver.hpp +++ b/SU2_CFD/include/solvers/CFEASolver.hpp @@ -46,7 +46,7 @@ class CFEASolver : public CSolver { su2double Total_CFEA; /*!< \brief Total FEA coefficient for all the boundaries. */ - unsigned short *iElem_iDe; /*!< \brief For DE cases, ID of the region considered for each iElem. */ + unsigned short *iElem_iDe = nullptr; /*!< \brief For DE cases, ID of the region considered for each iElem. */ su2double a_dt[9]; /*!< \brief Integration constants. */ @@ -179,8 +179,8 @@ class CFEASolver : public CSolver { CSysMatrix MassMatrix; /*!< \brief Sparse structure for storing the mass matrix. */ - CElement*** element_container; /*!< \brief Vector which the define the finite element structure for each problem. */ - CProperty** element_properties; /*!< \brief Vector which stores the properties of each element */ + CElement*** element_container = nullptr; /*!< \brief Vector which the define the finite element structure for each problem. */ + CProperty** element_properties = nullptr; /*!< \brief Vector which stores the properties of each element */ /*! * \brief Constructor of the class. diff --git a/SU2_CFD/src/solvers/CFEASolver.cpp b/SU2_CFD/src/solvers/CFEASolver.cpp index f1a7104a235f..3819e0b713a1 100644 --- a/SU2_CFD/src/solvers/CFEASolver.cpp +++ b/SU2_CFD/src/solvers/CFEASolver.cpp @@ -96,12 +96,6 @@ CFEASolver::CFEASolver(bool mesh_deform_mode) : CSolver(mesh_deform_mode) { for (unsigned short iTerm = 0; iTerm < MAX_TERMS; iTerm++) element_container[iTerm] = new CElement* [MAX_FE_KINDS*omp_get_max_threads()](); - nodes = nullptr; - - element_properties = nullptr; - - iElem_iDe = nullptr; - topol_filter_applied = false; element_based = false; @@ -243,8 +237,6 @@ CFEASolver::CFEASolver(CGeometry *geometry, CConfig *config) : CSolver() { /*--- Initialize structures for hybrid-parallel mode. ---*/ HybridParallelInitialization(geometry); - iElem_iDe = nullptr; - /*--- Initialize the value of the total objective function ---*/ Total_OFRefGeom = 0.0; Total_OFRefNode = 0.0; @@ -312,15 +304,15 @@ CFEASolver::~CFEASolver(void) { delete [] element_container; } - if (element_properties != nullptr){ + if (element_properties != nullptr) { for (unsigned long iElem = 0; iElem < nElement; iElem++) - if (element_properties[iElem] != nullptr) delete element_properties[iElem]; + delete element_properties[iElem]; delete [] element_properties; } - if (iElem_iDe != nullptr) delete [] iElem_iDe; + delete [] iElem_iDe; - if (nodes != nullptr) delete nodes; + delete nodes; if (LockStrategy) { for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) From 49f7d625845a2d85fbaf169ec6d0b6a399ce42f1 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 17 Mar 2020 11:54:04 +0000 Subject: [PATCH 02/79] cleanup RBF interpolation --- Common/include/interpolation_structure.hpp | 141 +- Common/src/interpolation_structure.cpp | 1423 +++++++------------- 2 files changed, 523 insertions(+), 1041 deletions(-) diff --git a/Common/include/interpolation_structure.hpp b/Common/include/interpolation_structure.hpp index 28bdf3af8677..a1349ecd4df7 100644 --- a/Common/include/interpolation_structure.hpp +++ b/Common/include/interpolation_structure.hpp @@ -145,10 +145,16 @@ class CInterpolator { /*! * \brief compute distance between 2 points + * \param[in] nDim - number of dimensions * \param[in] point_i * \param[in] point_i */ - su2double PointsDistance(su2double *point_i, su2double *point_j); + inline su2double PointsDistance(unsigned short nDim, const su2double *point_i, const su2double *point_j) const { + su2double m = 0; + for(unsigned short iDim = 0; iDim < nDim; iDim++) + m += pow(point_j[iDim] - point_i[iDim], 2); + return sqrt(m); + } /*! * \brief Set up transfer matrix defining relation between two meshes @@ -382,9 +388,8 @@ class CSlidingMesh : public CInterpolator { /*! * \brief Radial basis function interpolation */ -class CRadialBasisFunction : public CInterpolator { +class CRadialBasisFunction final : public CInterpolator { public: - /*! * \brief Constructor of the class. */ @@ -399,16 +404,11 @@ class CRadialBasisFunction : public CInterpolator { */ CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - /*! - * \brief Destructor of the class. - */ - ~CRadialBasisFunction(void); - /*! * \brief Set up transfer matrix defining relation between two meshes * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(CConfig **config); + void Set_TransferCoeff(CConfig **config) override; /*! * \brief Compute the value of a radial basis function, this is static so it can be re-used. @@ -416,76 +416,77 @@ class CRadialBasisFunction : public CInterpolator { * \param[in] radius - the characteristic dimension * \param[in] dist - distance */ - static su2double Get_RadialBasisValue(const short unsigned int type, const su2double &radius, const su2double &dist); - + static su2double Get_RadialBasisValue(const unsigned short type, const su2double radius, const su2double dist); + private: /*! - * \brief If the polynomial term is included in the interpolation, and the points lie on a plane, the matrix becomes rank deficient - * and cannot be inverted. This method detects that condition and corrects it by removing a row from P (the polynomial part of the matrix). - * \param[in] m - number of rows of P - * \param[in] n - number of columns of P - * \param[in] skip_row - marks the row of P which is all ones (by construction) - * \param[in] max_diff_tol_in - tolerance to detect points are on a plane - * \param[out] keep_row - marks the rows of P kept - * \param[out] n_polynomial - size of the polynomial part on exit (i.e. new number of rows) - * \param[in,out] P - polynomial part of the matrix, may be changed or not! + * \brief If the polynomial term is included in the interpolation, and the points lie on a plane, the matrix + * becomes rank deficient and cannot be inverted. This method detects that condition and corrects it by + * removing a row from P (the polynomial part of the interpolation matrix). + * \param[in] max_diff_tol - Tolerance to detect whether points are on a plane. + * \param[out] keep_row - Marks the dimensions of P kept. + * \param[in,out] P - Polynomial part of the interpolation matrix, one row may be eliminated. + * \return n_polynomial - Size of the polynomial part on exit (in practice nDim or nDim-1). */ - void Check_PolynomialTerms(int m, unsigned long n, const int *skip_row, su2double max_diff_tol_in, int *keep_row, int &n_polynomial, su2double *P); + int CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, su2passivematrix &P) const; }; /*! - * \brief Helper class used by CRadialBasisFunction to calculate the interpolation weights. - * This does not inherit from CSysMatrix because: it is a dense format rather than block sparse; - * as the interpolation is done on a single core there are no methods for communication. - * The code can be compiled with LAPACK to use optimized matrix inversion and multiplication routines. - * CPPFLAGS="-DHAVE_LAPACK" LDFLAGS=-L/path/to/lapack_lib LIBS="-llapack -lrefblas -lgfortran" + * \brief Helper class used by CRadialBasisFunction to compute the interpolation weights. + * The matrix is symmetric but full storage is used as that gives much better performance + * for some BLAS libraries (notably OpenBLAS). The code should be compiled with LAPACK + * to use optimized matrix inversion and multiplication routines. */ class CSymmetricMatrix{ +private: + enum DecompositionType { NONE, CHOLESKY, LU }; + + vector val_vec, decomp_vec; + vector perm_vec; + int sz = 0; + bool initialized = false; + DecompositionType decomposed = NONE; + + inline void CheckBounds(int i, int j) const { + assert(initialized && "Matrix not initialized."); + assert(i>=0 && i=0 && jGetnDim(); - su2double m; - - m = 0 ; - for(iDim = 0; iDim < nDim; iDim++) - m += (point_j[iDim] - point_i[iDim])*(point_j[iDim] - point_i[iDim]); - - return sqrt(m); -} - /* Nearest Neighbor Interpolator */ CNearestNeighbor::CNearestNeighbor(void): CInterpolator() { } @@ -685,7 +646,7 @@ void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { Coord_j = &Buffer_Receive_Coord[ Global_Point_Donor*nDim]; - dist = PointsDistance(Coord_i, Coord_j); + dist = PointsDistance(nDim, Coord_i, Coord_j); if (dist < mindist) { mindist = dist; pProcessor = iProcessor; @@ -1674,7 +1635,7 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config){ Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; - dist = PointsDistance(Coord_i, Coord_j); + dist = PointsDistance(nDim, Coord_i, Coord_j); if (dist < mindist) { mindist = dist; @@ -1719,7 +1680,7 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config){ for(iDim = 0; iDim < nDim; iDim++) Direction[iDim] /= dTMP; - length = PointsDistance(target_iMidEdge_point, target_jMidEdge_point); + length = PointsDistance(nDim, target_iMidEdge_point, target_jMidEdge_point); check = false; @@ -1951,7 +1912,7 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config){ Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; - dist = PointsDistance(Coord_i, Coord_j); + dist = PointsDistance(nDim, Coord_i, Coord_j); if (dist < mindist) { mindist = dist; @@ -2723,620 +2684,344 @@ bool CSlidingMesh::CheckPointInsideTriangle(su2double* Point, su2double* T1, su2 } /*--- Radial Basis Function Interpolator ---*/ -CRadialBasisFunction::CRadialBasisFunction(void): CInterpolator() { } +CRadialBasisFunction::CRadialBasisFunction(void): CInterpolator() { } -CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { +CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, + unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { /*--- Initialize transfer coefficients between the zones ---*/ Set_TransferCoeff(config); - } -CRadialBasisFunction::~CRadialBasisFunction() {} - void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { - int iProcessor, nProcessor = size; - int nPolynomial = 0; - int mark_donor, mark_target, target_check, donor_check; - int *skip_row = NULL, *calc_polynomial_check; - - unsigned short iDim, nDim, iMarkerInt, nMarkerInt; - - unsigned long iVertexDonor, jVertexDonor, iVertexTarget, iCount, jCount; - unsigned long nVertexDonor, nVertexTarget, nVertexDonorInDomain; - unsigned long nGlobalVertexDonor, iGlobalVertexDonor_end, nLocalM; - unsigned long point_donor, point_target; - unsigned long *nLocalM_arr; - - su2double val_i, val_j; - su2double interface_coord_tol=1e6*numeric_limits::epsilon(); - su2double *Coord_i, *Coord_j; - su2double *local_M; - su2double *P = NULL; - su2double *C_inv_trunc = NULL, *C_tmp = NULL; - su2double *target_vec, *coeff_vec; - - CSymmetricMatrix *global_M = NULL, *Mp = NULL; - -#ifdef HAVE_MPI - unsigned long iLocalM; - su2double *global_M_val_arr = NULL, *Buffer_recv_local_M; - int *Buffer_Recv_mark = new int[nProcessor], iRank; -#endif + /*--- RBF options. ---*/ + const unsigned short kindRBF = config[donorZone]->GetKindRadialBasisFunction(); + const su2double paramRBF = config[donorZone]->GetRadialBasisFunctionParameter(); + const bool usePolynomial = config[donorZone]->GetRadialBasisFunctionPolynomialOption(); + const passivedouble eps = numeric_limits::epsilon(); + const su2double interfaceCoordTol = 1e6 * eps; - /*--- Initialize variables --- */ - - nMarkerInt = (int) ( config[donorZone]->GetMarker_n_ZoneInterface() / 2 ); - - nDim = donor_geometry->GetnDim(); + const int nDim = donor_geometry->GetnDim(); - + const int nProcessor = size; + Buffer_Send_nVertex_Donor = new unsigned long [1]; Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; + /*--- Cycle over nMarkersInt interface to determine communication pattern. ---*/ - /*--- Cycle over nMarkersInt interface to determine communication pattern ---*/ + const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; - for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { + for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - mark_donor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - - /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - mark_target = Find_InterfaceMarker(config[targetZone], iMarkerInt); + /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ + int mark_donor = Find_InterfaceMarker(config[donorZone], iMarkerInt); -#ifdef HAVE_MPI + /*--- On the target side: find the tag of the boundary sharing the interface. ---*/ + int mark_target = Find_InterfaceMarker(config[targetZone], iMarkerInt); - donor_check = -1; - target_check = -1; - - /*--- We gather a vector in MASTER_NODE to determines whether the boundary is not on the processor because of the partition or because the zone does not include it ---*/ - - SU2_MPI::Gather(&mark_donor , 1, MPI_INT, Buffer_Recv_mark, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) - for (iRank = 0; iRank < nProcessor; iRank++) - if( Buffer_Recv_mark[iRank] != -1 ) { - donor_check = Buffer_Recv_mark[iRank]; - break; - } - - SU2_MPI::Bcast(&donor_check , 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - - SU2_MPI::Gather(&mark_target, 1, MPI_INT, Buffer_Recv_mark, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) - for (iRank = 0; iRank < nProcessor; iRank++) - if( Buffer_Recv_mark[iRank] != -1 ) { - target_check = Buffer_Recv_mark[iRank]; - break; - } + /*--- We gather a vector in MASTER_NODE to determines whether the boundary is not on + the processor because of the partition or because the zone does not include it. ---*/ + int donor_check, target_check; + SU2_MPI::Allreduce(&mark_donor, &donor_check, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&mark_target, &target_check, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Bcast(&target_check, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - -#else - donor_check = mark_donor; - target_check = mark_target; -#endif - - /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ - if(target_check == -1 || donor_check == -1) - continue; + /*--- If the zone does not contain the interface continue to the next pair of markers. ---*/ + if(target_check == -1 || donor_check == -1) continue; - if(mark_donor != -1) - nVertexDonor = donor_geometry->GetnVertex( mark_donor ); - else - nVertexDonor = 0; - - if(mark_target != -1) - nVertexTarget = target_geometry->GetnVertex( mark_target ); - else - nVertexTarget = 0; - - Buffer_Send_nVertex_Donor = new unsigned long [ 1 ]; + unsigned long nVertexDonor = 0, nVertexTarget = 0; + if(mark_donor != -1) nVertexDonor = donor_geometry->GetnVertex( mark_donor ); + if(mark_target != -1) nVertexTarget = target_geometry->GetnVertex( mark_target ); - /*--- Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor ---*/ + /*--- Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor. ---*/ Determine_ArraySize(false, mark_donor, mark_target, nVertexDonor, nDim); - - /*--- Collect information about number of donor vertices in domain. - Calculate total number of donor vertices across all ranks and - number of vertices on boundary prior to current rank. ---*/ - nVertexDonorInDomain = Buffer_Send_nVertex_Donor[0]; - iGlobalVertexDonor_end = nGlobalVertexDonor = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) - { - nGlobalVertexDonor += Buffer_Receive_nVertex_Donor[iProcessor]; - if (iProcessor<=rank) iGlobalVertexDonor_end += Buffer_Receive_nVertex_Donor[iProcessor]; - } - /*-- Collect coordinates, global points, and normal vectors ---*/ - Buffer_Send_Coord = new su2double [ MaxLocalVertex_Donor * nDim ]; - Buffer_Send_GlobalPoint = new long [ MaxLocalVertex_Donor ]; - Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; - Buffer_Receive_GlobalPoint = new long [ nProcessor * MaxLocalVertex_Donor ]; + /*--- Compute total number of donor vertices. ---*/ + auto nGlobalVertexDonor = accumulate(Buffer_Receive_nVertex_Donor, + Buffer_Receive_nVertex_Donor+nProcessor, 0ul); - Collect_VertexInfo( false, mark_donor, mark_target, nVertexDonor, nDim); + /*--- Gather coordinates and global point indices. ---*/ + Buffer_Send_Coord = new su2double [ MaxLocalVertex_Donor * nDim ]; + Buffer_Send_GlobalPoint = new long [ MaxLocalVertex_Donor ]; + Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; + Buffer_Receive_GlobalPoint = new long [ nProcessor * MaxLocalVertex_Donor ]; - /*--- Send information about size of local_M array ---*/ - nLocalM = nVertexDonorInDomain*(nVertexDonorInDomain+1)/2 \ - + nVertexDonorInDomain*(nGlobalVertexDonor-iGlobalVertexDonor_end); - - nLocalM_arr = new unsigned long [nProcessor]; -#ifdef HAVE_MPI - SU2_MPI::Allgather(&nLocalM, 1, MPI_UNSIGNED_LONG, nLocalM_arr, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#else - nLocalM_arr[MASTER_NODE] = nLocalM; -#endif - - /*--- Initialize local M array and calculate values ---*/ - local_M = new su2double [nLocalM]; - Coord_i = new su2double [nDim]; - Coord_j = new su2double [nDim]; - iCount=0; - for (iVertexDonor=0; iVertexDonorGetKindRadialBasisFunction(), - config[donorZone]->GetRadialBasisFunctionParameter(), - PointsDistance(Coord_i, Coord_j)); + auto iCount = 0ul; + for (int iProcessor = 0; iProcessor < nProcessor; ++iProcessor) { + auto offset = iProcessor * MaxLocalVertex_Donor * nDim; + for (auto iVertex = 0ul; iVertex < Buffer_Receive_nVertex_Donor[iProcessor]; ++iVertex) { + for (int iDim = 0; iDim < nDim; ++iDim) + DonorCoord(iCount,iDim) = Buffer_Receive_Coord[offset + iVertex*nDim + iDim]; + ++iCount; } + } + assert((iCount == nGlobalVertexDonor) && "Global donor point count mismatch."); - for (iProcessor=rank+1; iProcessor keepPolynomialRow(nDim,1); - local_M[iCount++] = Get_RadialBasisValue(config[donorZone]->GetKindRadialBasisFunction(), - config[donorZone]->GetRadialBasisFunctionParameter(), - PointsDistance(Coord_i, Coord_j)); - } - } - } - -#ifdef HAVE_MPI - if (rank != MASTER_NODE) { - SU2_MPI::Send(local_M, nLocalM, MPI_DOUBLE, MASTER_NODE, 0, MPI_COMM_WORLD); - } - - /*--- Assemble global_M ---*/ - if (rank == MASTER_NODE) { - global_M_val_arr = new su2double [nGlobalVertexDonor*(nGlobalVertexDonor+1)/2]; - - /*--- Copy master node local_M to global_M ---*/ - iCount = 0; - for (iLocalM=0; iLocalM SINGLE_NODE) { - for (iProcessor=1; iProcessorInitialize(nGlobalVertexDonor, global_M_val_arr); - } - -#else - global_M = new CSymmetricMatrix; - global_M->Initialize((int)nVertexDonorInDomain, local_M); -#endif - - /*--- Invert M matrix ---*/ - if (rank == MASTER_NODE) { - switch (config[donorZone]->GetKindRadialBasisFunction()) - { - /*--- Basis functions that make M positive definite ---*/ + su2passivematrix C_inv_trunc; + + if (rank==MASTER_NODE) { + + /*--- Populate interpolation kernel. ---*/ + CSymmetricMatrix global_M(nGlobalVertexDonor); + + for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; ++iVertex) + for (auto jVertex = iVertex; jVertex < nGlobalVertexDonor; ++jVertex) + global_M(iVertex, jVertex) = SU2_TYPE::GetValue(Get_RadialBasisValue(kindRBF, paramRBF, + PointsDistance(nDim, DonorCoord[iVertex], DonorCoord[jVertex]))); + + /*--- Invert M matrix (operation is in-place). ---*/ + switch (kindRBF) { + /*--- Basis functions that make M positive definite. ---*/ case WENDLAND_C2: case INV_MULTI_QUADRIC: case GAUSSIAN: - global_M->Invert(true); - break; + global_M.Invert(true); break; + /*--- Basis functions that make M semi-positive definite. ---*/ case THIN_PLATE_SPLINE: case MULTI_QUADRIC: - global_M->Invert(false); - break; + global_M.Invert(false); break; } - } - - calc_polynomial_check = new int [nDim]; - - /*--- Calculate C_inv_trunc ---*/ - if (rank == MASTER_NODE) { - - if ( config[donorZone]->GetRadialBasisFunctionPolynomialOption() ) { - - /*--- Fill P matrix and get minimum and maximum values ---*/ - P = new su2double [nGlobalVertexDonor*(nDim+1)]; - iCount = 0; - for (iProcessor=MASTER_NODE; iProcessorInitialize(nPolynomial+1); - for (int m=0; mRead((int)iVertexDonor, (int)jVertexDonor)*P[jVertexDonor*(nPolynomial+1)+n]; - } - val_i += val_j*P[iVertexDonor*(nPolynomial+1)+m]; - } - Mp->Write(m, n, val_i); + /*--- Check if points lie on a plane and remove one coordinate from P if so. ---*/ + nPolynomial = CheckPolynomialTerms(interfaceCoordTol, keepPolynomialRow, P); + + /*--- Calculate Mp = (P * M^-1 * P^T)^-1 ---*/ + CSymmetricMatrix Mp(nPolynomial+1); + + su2passivematrix tmp; + global_M.MatMatMult('R', P, tmp); // tmp = P * M^-1 + + for (int i = 0; i <= nPolynomial; ++i) // Mp = tmp * P + for (int j = i; j <= nPolynomial; ++j) { + Mp(i,j) = 0.0; + for (auto k = 0ul; k < nGlobalVertexDonor; ++k) Mp(i,j) += tmp(i,k) * P(j,k); } - } - Mp->Invert(false); - - /*--- Calculate M_p*P*M_inv ---*/ - C_inv_trunc = new su2double [(nGlobalVertexDonor+nPolynomial+1)*nGlobalVertexDonor]; - for (int m=0; mRead((int)jVertexDonor, (int)iVertexDonor); - } - val_i += val_j*Mp->Read(m, n); - } - /*--- Save in row major order ---*/ - C_inv_trunc[m*nGlobalVertexDonor+iVertexDonor] = val_i; - } - } - - /*--- Calculate (I - P'*M_p*P*M_inv) ---*/ - C_tmp = new su2double [nGlobalVertexDonor*nGlobalVertexDonor]; - for (iVertexDonor=0; iVertexDonorMatMatMult(true, C_tmp, (int)nGlobalVertexDonor); + /*--- Calculate M^-1 * (I - P^T * M_p * P * M^-1), finalize bottom of C_inv_trunc. ---*/ + global_M.MatMatMult('L', tmp, C_inv_trunc); - /*--- Write to C_inv_trunc matrix ---*/ - for (iVertexDonor=0; iVertexDonorRead((int)iVertexDonor, (int)jVertexDonor); - - } // endif GetRadialBasisFunctionPolynomialOption - } // endif (rank == MASTER_NODE) - -#ifdef HAVE_MPI SU2_MPI::Bcast(&nPolynomial, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Bcast(calc_polynomial_check, nDim, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - if (rank != MASTER_NODE) { - C_inv_trunc = new su2double [(nGlobalVertexDonor+nPolynomial+1)*nGlobalVertexDonor]; - } + SU2_MPI::Bcast(keepPolynomialRow.data(), nDim, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Bcast(C_inv_trunc, (nGlobalVertexDonor+nPolynomial+1)*nGlobalVertexDonor, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + if (rank != MASTER_NODE) + C_inv_trunc.resize(nGlobalVertexDonor+nPolynomial+1, nGlobalVertexDonor); + +#ifdef HAVE_MPI + /*--- MPI wrapper not used due to passive double. ---*/ + MPI_Bcast(C_inv_trunc.data(), C_inv_trunc.size(), MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); #endif - - /*--- Calculate H matrix ---*/ - if (config[donorZone]->GetRadialBasisFunctionPolynomialOption()) - target_vec = new su2double [nGlobalVertexDonor+nPolynomial+1]; - else - target_vec = new su2double [nGlobalVertexDonor]; - - coeff_vec = new su2double [nGlobalVertexDonor]; - - for (iVertexTarget = 0; iVertexTarget < nVertexTarget; iVertexTarget++) { - point_target = target_geometry->vertex[mark_target][iVertexTarget]->GetNode(); - - if ( target_geometry->node[point_target]->GetDomain() ) { - iCount = 0; - if (config[donorZone]->GetRadialBasisFunctionPolynomialOption()) { - target_vec[iCount] = 1; - iCount++; - } - - for (iDim=0; iDimnode[point_target]->GetCoord(iDim); - if (config[donorZone]->GetRadialBasisFunctionPolynomialOption()) { - if (calc_polynomial_check[iDim] == 1) { - target_vec[iCount] = Coord_i[iDim]; - iCount++; - } - } - } - - for (iProcessor=0; iProcessorGetKindRadialBasisFunction(), - config[donorZone]->GetRadialBasisFunctionParameter(), - PointsDistance(Coord_i, Coord_j)); - } - } - - for (iVertexDonor=0; iVertexDonorvertex[mark_target][iVertexTarget]->SetnDonorPoints(iCount); - target_geometry->vertex[mark_target][iVertexTarget]->Allocate_DonorInfo(); - - iCount = 0; - jCount = 0; - for (iProcessor=0; iProcessorvertex[mark_target][iVertexTarget]->SetInterpDonorPoint(jCount, point_donor); - target_geometry->vertex[mark_target][iVertexTarget]->SetInterpDonorProcessor(jCount, iProcessor); - target_geometry->vertex[mark_target][iVertexTarget]->SetDonorCoeff(jCount, coeff_vec[iCount]); - jCount++; - } - iCount++; + for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; iVertexTarget++) { + + auto target_vertex = target_geometry->vertex[mark_target][iVertexTarget]; + const auto point_target = target_vertex->GetNode(); + + /*--- If not domain point move to next. ---*/ + if (!target_geometry->node[point_target]->GetDomain()) continue; + + su2passivevector target_vec(nGlobalVertexDonor+nPolynomial+1); + su2passivevector coeff_vec(nGlobalVertexDonor); + + const su2double* coord_i = target_geometry->node[point_target]->GetCoord(); + + /*--- Prepare target vector (one row of the target matrix). ---*/ + /*--- polynominal part ---*/ + int idx = 0; + if (usePolynomial) { + target_vec(idx++) = 1.0; // constant term + for (int iDim = 0; iDim < nDim; ++iDim) // linear terms + if (keepPolynomialRow[iDim]) // of which one may have been excluded + target_vec(idx++) = SU2_TYPE::GetValue(coord_i[iDim]); + } + /*--- RBF part ---*/ + for (auto iVertexDonor = 0ul; iVertexDonor < nGlobalVertexDonor; ++iVertexDonor) + target_vec(iVertexDonor+idx) = SU2_TYPE::GetValue(Get_RadialBasisValue(kindRBF, paramRBF, + PointsDistance(nDim, coord_i, DonorCoord[iVertexDonor]))); + + /*--- Multiply target vector by C_inv_trunc to obtain the interpolation coefficients. ---*/ + for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; ++iVertex) { + coeff_vec(iVertex) = 0.0; + for (auto jVertex = 0ul; jVertex < target_vec.size(); ++jVertex) + coeff_vec(iVertex) += target_vec(jVertex) * C_inv_trunc(jVertex, iVertex); + } + + /*--- Count the number of donor points (non zero coefficients) for this target point. ---*/ + idx = 0; + for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; ++iVertex) + idx += (fabs(coeff_vec(iVertex)) > eps); + + target_vertex->SetnDonorPoints(idx); + target_vertex->Allocate_DonorInfo(); + + int iSet = 0; + for (int iProcessor = 0, iTest = -1; iProcessor < nProcessor; ++iProcessor) { + const auto offset = iProcessor * MaxLocalVertex_Donor; + for (auto iVertex = 0ul; iVertex < Buffer_Receive_nVertex_Donor[iProcessor]; ++iVertex) + if (fabs(coeff_vec(++iTest)) > eps) { + auto point_donor = Buffer_Receive_GlobalPoint[offset + iVertex]; + target_vertex->SetInterpDonorProcessor(iSet, iProcessor); + target_vertex->SetInterpDonorPoint(iSet, point_donor); + target_vertex->SetDonorCoeff(iSet, coeff_vec(iTest)); + ++iSet; } - } - } // endif - } // endfor - - /*--- Memory management ---*/ - delete [] nLocalM_arr; - delete [] local_M; - delete [] Coord_i; - delete [] Coord_j; - delete [] calc_polynomial_check; - delete [] C_inv_trunc; - delete [] target_vec; - delete [] coeff_vec; - - if ( rank == MASTER_NODE ) { - delete global_M; - - if ( config[donorZone]->GetRadialBasisFunctionPolynomialOption() ) { - delete [] skip_row; - delete [] P; - delete Mp; - delete [] C_tmp; } - } - + assert(idx==iSet && "Error while setting donor point coefficients."); + + } // end target vertex loop + delete[] Buffer_Send_Coord; delete[] Buffer_Send_GlobalPoint; - delete[] Buffer_Receive_Coord; delete[] Buffer_Receive_GlobalPoint; - delete[] Buffer_Send_nVertex_Donor; - -#ifdef HAVE_MPI - if (rank == MASTER_NODE) - delete [] global_M_val_arr; -#endif - } // end loop over markers + } // end loop over interface markers + delete[] Buffer_Send_nVertex_Donor; delete[] Buffer_Receive_nVertex_Donor; -#ifdef HAVE_MPI - if (rank == MASTER_NODE) - delete [] Buffer_Recv_mark; -#endif } -void CRadialBasisFunction::Check_PolynomialTerms(int m, unsigned long n, const int *skip_row, su2double max_diff_tol_in, int *keep_row, int &n_polynomial, su2double *P) -{ - /*--- This routine keeps the AD information in P but the calculations are done in passivedouble as their purpose - is to decide which (if any) row of P to remove, and that process is not differentiable anyway. ---*/ - - int *write_row = NULL; - unsigned long iCount, jCount, n_rows; - passivedouble sum, max_diff, max_coeff, *coeff = NULL, max_diff_tol = SU2_TYPE::GetValue(max_diff_tol_in); - CSymmetricMatrix *PPT; - su2double *P_tmp = NULL; - - n_rows = 0; - for (int i=0; iInitialize((int)n_rows); +int CRadialBasisFunction::CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, + su2passivematrix &P) const { + const int m = P.rows(); + const int n = P.cols(); - iCount = 0; - for (int i = 0; i < m; i ++) { - if (skip_row[i] == 0) { - - jCount = 0; - for (int j = 0; j < m; j ++){ - if (skip_row[j] == 0) { - - sum = 0.0; - for (unsigned long k = 0; k < n; k ++) - { - sum += SU2_TYPE::GetValue(P[k*m+i]*P[k*m+j]); - } - PPT->Write((int)iCount, (int)jCount, sum); - - jCount++; - } - } - - iCount++; - } - } - - PPT->Invert(true); - - /*--- RHS for the least squares fit (vector of ones times P) ---*/ - coeff = new passivedouble [n_rows]; - iCount = 0; - for (int i = 0; i < m; i ++) { - if (skip_row[i] == 0) { - coeff[iCount] = 0; - for (unsigned long j = 0; j < n; j += 1) - { - coeff[iCount] += SU2_TYPE::GetValue(P[j*m+i]); - } - iCount++; + /*--- The first row of P is all ones and we do not care about it for this analysis. ---*/ + const int n_rows = m-1; + keep_row.resize(n_rows); + + /*--- By default assume points are not on a plane (all rows kept). ---*/ + int n_polynomial = n_rows; + for (int i = 0; i < n_rows; ++i) keep_row[i] = 1; + + /*--- Fit a plane through the points in P. ---*/ + + /*--- Compute P times its transpose and invert. ---*/ + CSymmetricMatrix PPT(n_rows); + + for (int i = 0; i < n_rows; ++i) + for (int j = i; j < n_rows; ++j) { + PPT(i,j) = 0.0; + for (int k = 0; k < n; ++k) PPT(i,j) += P(i+1,k) * P(j+1,k); } - } - - /*--- Multiply the RHS by the inverse thus obtaining the coefficients ---*/ - PPT->MatVecMult(coeff); - - /*--- Determine the maximum deviation of the points from the fitted plane ---*/ - max_diff = 0; - for (unsigned long i = 0; i < n; i ++) + PPT.Invert(true); + + /*--- RHS for the least squares fit (vector of ones times P). ---*/ + vector coeff(n_rows,0.0); + + for (int i = 0; i < n_rows; ++i) + for (int j = 0; j < n; ++j) + coeff[i] += P(i+1,j); + + /*--- Multiply the RHS by the inverse thus obtaining the coefficients. ---*/ + PPT.MatVecMult(coeff.data()); + + /*--- Determine the maximum deviation of the points from the fitted plane. ---*/ + passivedouble max_diff = 0.0; + + for (int j = 0; j < n; ++j) { - sum = 0; - iCount = 0; - for (int j = 0; j < m; j ++) - { - if (skip_row[j] == 0) { - sum += coeff[iCount]*SU2_TYPE::GetValue(P[i*m+j]); - iCount++; - } - } - /*--- 1.0 is the arbitrary constant we are assuming when fitting the plane ---*/ + passivedouble sum = 0.0; + for (int i = 0; i < n_rows; ++i) sum += coeff[i] * P(i+1,j); + + /*--- 1.0 is the arbitrary constant we are assuming when fitting + the plane, i.e. the vector of ones used to generate the RHS. ---*/ max_diff = max(abs(1.0-sum), max_diff); } - - for (unsigned long i=0; i max_coeff) iCount = i; - } + /*--- Find the max coeff and mark the corresponding row for removal. ---*/ + int remove_row = 0; + for (int i = 1; i < n_rows; ++i) + if (abs(coeff[i]) > abs(coeff[remove_row])) + remove_row = i; - for (unsigned long i=0; i 0.0 && "LLT failed, matrix is not SPD."); + Set(j, j, sqrt(sum)); - /*--- Decompose matrix ---*/ - for (j=0; j abs(pivot) ) { - pivot = decompose_vec[CalcIdxFull(i, j)]; + /*--- Decompose LU matrix. ---*/ + for (int j = 0; j < sz-1; ++j) { + /*--- Search for maximum pivot and interchange rows. ---*/ + passivedouble pivot = decomp(j,j); + int pivot_idx = j; + for (int i = j+1; i < sz; ++i) + if (abs(decomp(i,j)) > abs(pivot)) { + pivot = decomp(i,j); pivot_idx = i; - interchange_row = true; - } - } - - if ( interchange_row ) { - for ( k=0; k inv(sz*sz, 0.0); + + /*--- Compute L inverse. ---*/ + /*--- Solve smaller and smaller systems. ---*/ + for (int j = 0; j < sz; ++j) { + /*--- Forward substitution. ---*/ + inv[IdxSym(j,j)] = 1.0 / Get(j,j); + + for (int i = j+1; i < sz; ++i) { + passivedouble sum = 0.0; + for (int k = j; k < i; ++k) sum -= Get(i,k) * inv[IdxSym(k,j)]; + inv[IdxSym(i,j)] = sum / Get(i,i); + } + } // L inverse in inv + + /*--- Multiply inversed matrices overwrite val_vec. ---*/ + for (int j = 0; j < sz; ++j) + for (int i = j; i < sz; ++i) { + passivedouble sum = 0.0; + for (int k = i; k < sz; ++k) sum += inv[IdxSym(k,i)] * inv[IdxSym(k,j)]; + Set(i, j, sum); + } - inv_val_vec[CalcIdx(j, j)] = 1.0; + break; + } - /*--- Forward substitution ---*/ - for (i=j; i& inv = val_vec; - if (i==j) { - inv_val_vec[CalcIdx(i, i)] = 1/ReadL(i, i); - } - else { - sum = 0.0; - for (k=j; k().swap(decomp_vec); break; - - default: - throw invalid_argument("Default (LU) decomposition failed."); + } + default: assert(false && "Default (LU) decomposition failed."); } - decompose_vec = NULL; - decomposed = none; - inversed = true; + decomposed = NONE; #endif } -void CSymmetricMatrix::CalcInv_sptri() +void CSymmetricMatrix::CalcInv_sytri() { #ifdef HAVE_LAPACK char uplo = 'L'; - int info, *ipiv = new int [sz]; - passivedouble *work = new passivedouble [sz]; + int info; + perm_vec.resize(sz); // ipiv array + + /*--- Query the optimum work size. ---*/ + int query = -1; passivedouble tmp; + dsytrf_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), &tmp, &query, &info); + query = static_cast(tmp); + decomp_vec.resize(query); // work array + + /*--- Factorize and invert. ---*/ + dsytrf_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), decomp_vec.data(), &query, &info); + if (info!=0) SU2_MPI::Error("LDLT factorization failed.", CURRENT_FUNCTION); + dsytri_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), decomp_vec.data(), &info); + if (info!=0) SU2_MPI::Error("Inversion with LDLT factorization failed.", CURRENT_FUNCTION); + + decomposed = NONE; +#endif +} - dsptrf_(&uplo, &sz, val_vec, ipiv, &info); - dsptri_(&uplo, &sz, val_vec, ipiv, work, &info); +void CSymmetricMatrix::CalcInv_potri() +{ +#ifdef HAVE_LAPACK + char uplo = 'L'; + int info; - delete [] ipiv; - delete [] work; + dpotrf_(&uplo, &sz, val_vec.data(), &sz, &info); + if (info!=0) SU2_MPI::Error("LLT factorization failed.", CURRENT_FUNCTION); + dpotri_(&uplo, &sz, val_vec.data(), &sz, &info); + if (info!=0) SU2_MPI::Error("Inversion with LLT factorization failed.", CURRENT_FUNCTION); - if(decompose_vec) delete[] decompose_vec; - decompose_vec = NULL; - decomposed = none; - inversed = true; + decomposed = NONE; #endif } void CSymmetricMatrix::Invert(const bool is_spd) { #ifdef HAVE_LAPACK - CalcInv_sptri(); + if(is_spd) CalcInv_potri(); + else CalcInv_sytri(); #else if(!is_spd) LUDecompose(); - else CholeskyDecompose(true); - CalcInv(true); + else CholeskyDecompose(); + CalcInv(); #endif } -void CSymmetricMatrix::MatVecMult(passivedouble *v) +void CSymmetricMatrix::MatVecMult(passivedouble *v) const { passivedouble *tmp_res = new passivedouble [sz]; for (int i=0; i=sz || j<0 || j>=sz) { - throw out_of_range("Index to access matrix out of bounds."); } -} -void CSymmetricMatrix::Write(int i, int j, const su2double& val) -{ - CheckBounds(i,j); - val_vec[CalcIdx(i, j)] = SU2_TYPE::GetValue(val); -} - -passivedouble CSymmetricMatrix::Read(int i, int j) -{ - CheckBounds(i,j); - return val_vec[CalcIdx(i, j)]; -} - -passivedouble CSymmetricMatrix::ReadL(int i, int j) -{ - passivedouble *p = NULL; - - CheckBounds(i,j); - - if (decompose_vec) { p = decompose_vec; } - else { p = val_vec; } - - switch (decomposed) { - case cholesky: - if (i>=j) return p[CalcIdx(i, j)]; - else return 0.0; - - case lu: - if (i>j) return p[CalcIdxFull(i, j)]; - else return passivedouble(i==j); - - default: - throw invalid_argument("Matrix not decomposed yet or results have been deleted."); - } -} - -passivedouble CSymmetricMatrix::ReadU(int i, int j) -{ - passivedouble *p = NULL; - - CheckBounds(i,j); - - if (decompose_vec){ p = decompose_vec; } - else {p = val_vec;} - - switch (decomposed) { - case cholesky: - return 0.0; - - case lu: - if (j>=i) return p[CalcIdxFull(j, i)]; - else return 0.0; - - default: - throw invalid_argument("Matrix not decomposed yet or results have been deleted."); - } -} - -double CSymmetricMatrix::ReadInv(int i, int j) -{ - passivedouble *p = NULL; - - CheckBounds(i,j); - - if (inversed) { - if (inv_val_vec) { p = inv_val_vec; } - else { p = val_vec; } - - return p[CalcIdx(i, j)]; - } - else { - throw invalid_argument("Matrix inverse not calculated yet."); - } } From ff8c57f96f8313e9815d108003711b0396b75576 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 17 Mar 2020 14:35:56 +0000 Subject: [PATCH 03/79] prune tolerance for sparse RBF interpolation matrix --- Common/include/CConfig.hpp | 8 ++++- Common/src/CConfig.cpp | 7 ++-- Common/src/interpolation_structure.cpp | 37 ++++++++++++++------ TestCases/fea_fsi/Airfoil_RBF/config.cfg | 2 +- TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg | 3 +- TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg | 14 +++++--- 6 files changed, 50 insertions(+), 21 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index e316b4cb8d01..877f073cc08e 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -990,7 +990,8 @@ class CConfig { bool ConservativeInterpolation; /*!< \brief Conservative approach for non matching mesh interpolation. */ unsigned short Kind_RadialBasisFunction; /*!< \brief type of radial basis function to use for radial basis FSI. */ bool RadialBasisFunction_PolynomialOption; /*!< \brief Option of whether to include polynomial terms in Radial Basis Function Interpolation or not. */ - su2double RadialBasisFunction_Parameter; /*!< \brief Radial basis function parameter. */ + su2double RadialBasisFunction_Parameter; /*!< \brief Radial basis function parameter (radius). */ + su2double RadialBasisFunction_PruneTol; /*!< \brief Tolerance to prune the RBF interpolation matrix. */ bool Prestretch; /*!< \brief Read a reference geometry for optimization purposes. */ string Prestretch_FEMFileName; /*!< \brief File name for reference geometry. */ string FEA_FileName; /*!< \brief File name for element-based properties. */ @@ -8787,6 +8788,11 @@ class CConfig { */ su2double GetRadialBasisFunctionParameter(void) const { return RadialBasisFunction_Parameter; } + /*! + * \brief Get the tolerance used to prune the interpolation matrix (making it sparser). + */ + su2double GetRadialBasisFunctionPruneTol(void) const { return RadialBasisFunction_PruneTol; } + /*! * \brief Get the kind of inlet face interpolation function to use. */ diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 84dd8cef7eae..2899aab3328f 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2478,8 +2478,11 @@ void CConfig::SetConfig_Options() { * Options: NO, YES \ingroup Config */ addBoolOption("RADIAL_BASIS_FUNCTION_POLYNOMIAL_TERM", RadialBasisFunction_PolynomialOption, true); - /* DESCRIPTION: Radius for radial basis function */ - addDoubleOption("RADIAL_BASIS_FUNCTION_PARAMETER", RadialBasisFunction_Parameter, 1); + /* DESCRIPTION: Radius for radial basis function. */ + addDoubleOption("RADIAL_BASIS_FUNCTION_PARAMETER", RadialBasisFunction_Parameter, 1.0); + + /* DESCRIPTION: Tolerance to prune small coefficients from the RBF interpolation matrix. */ + addDoubleOption("RADIAL_BASIS_FUNCTION_PRUNE_TOLERANCE", RadialBasisFunction_PruneTol, 1e-6); /*!\par INLETINTERPOLATION \n * DESCRIPTION: Type of spanwise interpolation to use for the inlet face. \n OPTIONS: see \link Inlet_SpanwiseInterpolation_Map \endlink diff --git a/Common/src/interpolation_structure.cpp b/Common/src/interpolation_structure.cpp index 000a55cf9e06..421d3d94e0e0 100644 --- a/Common/src/interpolation_structure.cpp +++ b/Common/src/interpolation_structure.cpp @@ -2697,8 +2697,9 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { /*--- RBF options. ---*/ const unsigned short kindRBF = config[donorZone]->GetKindRadialBasisFunction(); - const su2double paramRBF = config[donorZone]->GetRadialBasisFunctionParameter(); const bool usePolynomial = config[donorZone]->GetRadialBasisFunctionPolynomialOption(); + const su2double paramRBF = config[donorZone]->GetRadialBasisFunctionParameter(); + const su2double pruneTol = config[donorZone]->GetRadialBasisFunctionPruneTol(); const passivedouble eps = numeric_limits::epsilon(); const su2double interfaceCoordTol = 1e6 * eps; @@ -2792,7 +2793,7 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { global_M.Invert(false); break; } - /*--- Calculate C_inv_trunc. ---*/ + /*--- Compute C_inv_trunc. ---*/ if (usePolynomial) { /*--- Fill P matrix (P for points, with an extra top row of ones). ---*/ @@ -2807,7 +2808,7 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { /*--- Check if points lie on a plane and remove one coordinate from P if so. ---*/ nPolynomial = CheckPolynomialTerms(interfaceCoordTol, keepPolynomialRow, P); - /*--- Calculate Mp = (P * M^-1 * P^T)^-1 ---*/ + /*--- Compute Mp = (P * M^-1 * P^T)^-1 ---*/ CSymmetricMatrix Mp(nPolynomial+1); su2passivematrix tmp; @@ -2820,12 +2821,12 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { } Mp.Invert(false); // Mp = Mp^-1 - /*--- Calculate M_p * P * M^-1, the top part of C_inv_trunc. ---*/ + /*--- Compute M_p * P * M^-1, the top part of C_inv_trunc. ---*/ Mp.MatMatMult('L', P, tmp); su2passivematrix C_inv_top; global_M.MatMatMult('R', tmp, C_inv_top); - /*--- Calculate tmp = (I - P^T * M_p * P * M^-1), part of the bottom part of + /*--- Compute tmp = (I - P^T * M_p * P * M^-1), part of the bottom part of C_inv_trunc. Note that most of the product is known from the top part. ---*/ tmp.resize(nGlobalVertexDonor, nGlobalVertexDonor); @@ -2837,7 +2838,7 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { tmp(i,i) += 1.0; // identity part } - /*--- Calculate M^-1 * (I - P^T * M_p * P * M^-1), finalize bottom of C_inv_trunc. ---*/ + /*--- Compute M^-1 * (I - P^T * M_p * P * M^-1), finalize bottom of C_inv_trunc. ---*/ global_M.MatMatMult('L', tmp, C_inv_trunc); /*--- Merge top and bottom of C_inv_trunc. ---*/ @@ -2901,18 +2902,32 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { target_vec(iVertexDonor+idx) = SU2_TYPE::GetValue(Get_RadialBasisValue(kindRBF, paramRBF, PointsDistance(nDim, coord_i, DonorCoord[iVertexDonor]))); - /*--- Multiply target vector by C_inv_trunc to obtain the interpolation coefficients. ---*/ + /*--- Multiply target vector by C_inv_trunc to obtain the interpolation coefficients. + Simultaneously determine a reference for dropping small coefficients. ---*/ + passivedouble coeffRef = 0.0; for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; ++iVertex) { coeff_vec(iVertex) = 0.0; for (auto jVertex = 0ul; jVertex < target_vec.size(); ++jVertex) coeff_vec(iVertex) += target_vec(jVertex) * C_inv_trunc(jVertex, iVertex); + coeffRef = max(coeffRef, fabs(coeff_vec(iVertex))); } + coeffRef *= SU2_TYPE::GetValue(pruneTol); - /*--- Count the number of donor points (non zero coefficients) for this target point. ---*/ + /*--- Prune and count the number of donor points for this target point. ---*/ idx = 0; - for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; ++iVertex) - idx += (fabs(coeff_vec(iVertex)) > eps); + passivedouble coeffSum = 0.0; + for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; ++iVertex) { + if (fabs(coeff_vec(iVertex)) > coeffRef) { + coeffSum += coeff_vec(iVertex); + ++idx; + } + else coeff_vec(iVertex) = 0.0; + } + /*--- Correct remaining coefficients, sum must be 1 for conservation. ---*/ + passivedouble correction = 1.0 / coeffSum; + for (auto i = 0ul; i < nGlobalVertexDonor; ++i) coeff_vec(i) *= correction; + /*--- Allocate and set donor information for this target point. ---*/ target_vertex->SetnDonorPoints(idx); target_vertex->Allocate_DonorInfo(); @@ -2920,7 +2935,7 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { for (int iProcessor = 0, iTest = -1; iProcessor < nProcessor; ++iProcessor) { const auto offset = iProcessor * MaxLocalVertex_Donor; for (auto iVertex = 0ul; iVertex < Buffer_Receive_nVertex_Donor[iProcessor]; ++iVertex) - if (fabs(coeff_vec(++iTest)) > eps) { + if (fabs(coeff_vec(++iTest)) > 0.0) { auto point_donor = Buffer_Receive_GlobalPoint[offset + iVertex]; target_vertex->SetInterpDonorProcessor(iSet, iProcessor); target_vertex->SetInterpDonorPoint(iSet, point_donor); diff --git a/TestCases/fea_fsi/Airfoil_RBF/config.cfg b/TestCases/fea_fsi/Airfoil_RBF/config.cfg index 437ca3394f55..ddcf42c9b8e4 100755 --- a/TestCases/fea_fsi/Airfoil_RBF/config.cfg +++ b/TestCases/fea_fsi/Airfoil_RBF/config.cfg @@ -3,7 +3,7 @@ % Case description: 2D airfoil FSI with radial basis function interp. % % Institution: Imperial College London % % Date: 2015.08.12 % -% File Version 6.2 "Falcon" % +% File Version 7.0.2 "Blackbird" % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SOLVER = MULTIPHYSICS diff --git a/TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg b/TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg index 921a81ac1da0..99e3530ccdd3 100644 --- a/TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg +++ b/TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg @@ -2,7 +2,7 @@ % SU2 configuration file % % Case description: 2D airfoil FSI with radial basis function interp. % % Institution: Imperial College London % -% File Version 7.0.2 "Blackbird" % +% File Version 7.0.2 "Blackbird" % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Interface options ---------------------------------------------------- % @@ -12,6 +12,7 @@ CONSERVATIVE_INTERPOLATION = YES KIND_RADIAL_BASIS_FUNCTION = WENDLAND_C2 RADIAL_BASIS_FUNCTION_PARAMETER = 0.015 RADIAL_BASIS_FUNCTION_POLYNOMIAL_TERM = YES +RADIAL_BASIS_FUNCTION_PRUNE_TOLERANCE = 1e-6 % % Physics -------------------------------------------------------------- % SOLVER= ELASTICITY diff --git a/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg b/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg index 183cb402f3fc..6d293bd5506e 100644 --- a/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg +++ b/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg @@ -2,7 +2,7 @@ % SU2 configuration file % % Case description: 2D airfoil FSI with radial basis function interp. % % Institution: Imperial College London % -% File Version 7.0.2 "Blackbird" % +% File Version 7.0.2 "Blackbird" % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Interface options ---------------------------------------------------- % @@ -20,16 +20,20 @@ KIND_INTERPOLATION = RADIAL_BASIS_FUNCTION % orders) and you have issues, break up the interface or use "NO" for % consistent interpolation. CONSERVATIVE_INTERPOLATION = YES -% Wendland provides good results and produces a nice diagonally dominant -% interpolation kernel, other options: +% Wendland is usually the best option due to sparser and better +% conditioned interpolation kernel, other options: % INV_MULTI_QUADRIC; GAUSSIAN; THIN_PLATE_SPLINE; MULTI_QUADRIC KIND_RADIAL_BASIS_FUNCTION = WENDLAND_C2 % The radius in meters, 2 times the largest cell size on the interface is % a good compromise between accuracy and condition number of the kernel. RADIAL_BASIS_FUNCTION_PARAMETER = 0.015 -% Recommended as it recovers rigid body motion, only requires a few more -% matrix products... feel free to explore though! +% Polynomial terms to recover rigid body motion, this requires slightly +% more computation and reduces the sparsity of the interpolation matrix. RADIAL_BASIS_FUNCTION_POLYNOMIAL_TERM = YES +% The number of donor points per target point is reduced by prunning away +% small interpolation coefficients (making the interp. matrix sparse). +% This tolerance is relative to the maximum absolute coefficient. +RADIAL_BASIS_FUNCTION_PRUNE_TOLERANCE = 1e-6 % % Physics -------------------------------------------------------------- % SOLVER= EULER From 88961123db636096e963162e2c43a0391dfa03a9 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 17 Mar 2020 19:06:33 +0000 Subject: [PATCH 04/79] RBF interpolation in parallel --- Common/src/interpolation_structure.cpp | 301 +++++++++++++++---------- 1 file changed, 187 insertions(+), 114 deletions(-) diff --git a/Common/src/interpolation_structure.cpp b/Common/src/interpolation_structure.cpp index 421d3d94e0e0..414729f9ff55 100644 --- a/Common/src/interpolation_structure.cpp +++ b/Common/src/interpolation_structure.cpp @@ -198,7 +198,7 @@ void CInterpolator::Collect_VertexInfo(bool faces, int markDonor, int markTarget unsigned short iDim; /* Only needed if face data is also collected */ - su2double *Normal; + const su2double *Normal = nullptr; for (iVertex = 0; iVertex < MaxLocalVertex_Donor; iVertex++) { Buffer_Send_GlobalPoint[iVertex] = -1; @@ -220,7 +220,7 @@ void CInterpolator::Collect_VertexInfo(bool faces, int markDonor, int markTarget Buffer_Send_Coord[nLocalVertex_Donor*nDim+iDim] = donor_geometry->node[iPointDonor]->GetCoord(iDim); if (faces) { - Normal = donor_geometry->vertex[markDonor][iVertexDonor]->GetNormal(); + Normal = donor_geometry->vertex[markDonor][iVertexDonor]->GetNormal(); for (iDim = 0; iDim < nDim; iDim++) Buffer_Send_Normal[nLocalVertex_Donor*nDim+iDim] = Normal[iDim]; } @@ -2703,17 +2703,24 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { const passivedouble eps = numeric_limits::epsilon(); const su2double interfaceCoordTol = 1e6 * eps; + const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; const int nDim = donor_geometry->GetnDim(); const int nProcessor = size; Buffer_Send_nVertex_Donor = new unsigned long [1]; Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; - /*--- Cycle over nMarkersInt interface to determine communication pattern. ---*/ - - const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; + /*--- Process interface patches in parallel, fetch all donor point coordinates, + * then distribute interpolation matrix computation over ranks and threads. + * To avoid repeating calls to Collect_VertexInfo we also save the global + * indices of the donor points and the mpi rank index that owns them. ---*/ + vector DonorCoordinates(nMarkerInt); + vector > DonorGlobalPoint(nMarkerInt); + vector > DonorProcessor(nMarkerInt); + vector AssignedProcessor(nMarkerInt,-1); + vector TotalWork(nProcessor,0); - for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { + for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; ++iMarkerInt) { /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ int mark_donor = Find_InterfaceMarker(config[donorZone], iMarkerInt); @@ -2730,9 +2737,8 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { /*--- If the zone does not contain the interface continue to the next pair of markers. ---*/ if(target_check == -1 || donor_check == -1) continue; - unsigned long nVertexDonor = 0, nVertexTarget = 0; - if(mark_donor != -1) nVertexDonor = donor_geometry->GetnVertex( mark_donor ); - if(mark_target != -1) nVertexTarget = target_geometry->GetnVertex( mark_target ); + unsigned long nVertexDonor = 0; + if(mark_donor != -1) nVertexDonor = donor_geometry->GetnVertex(mark_donor); /*--- Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor. ---*/ Determine_ArraySize(false, mark_donor, mark_target, nVertexDonor, nDim); @@ -2749,132 +2755,205 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { Collect_VertexInfo(false, mark_donor, mark_target, nVertexDonor, nDim); - /*--- Compress the gathered donor point coordinates to simplify calculations. ---*/ - su2activematrix DonorCoord(nGlobalVertexDonor, nDim); + /*--- Compresses the gathered donor point information to simplify computation. ---*/ + auto& DonorCoord = DonorCoordinates[iMarkerInt-1]; + auto& DonorPoint = DonorGlobalPoint[iMarkerInt-1]; + auto& DonorProc = DonorProcessor[iMarkerInt-1]; + DonorCoord.resize(nGlobalVertexDonor, nDim); + DonorPoint.resize(nGlobalVertexDonor); + DonorProc.resize(nGlobalVertexDonor); auto iCount = 0ul; for (int iProcessor = 0; iProcessor < nProcessor; ++iProcessor) { - auto offset = iProcessor * MaxLocalVertex_Donor * nDim; + auto offset = iProcessor * MaxLocalVertex_Donor; for (auto iVertex = 0ul; iVertex < Buffer_Receive_nVertex_Donor[iProcessor]; ++iVertex) { for (int iDim = 0; iDim < nDim; ++iDim) - DonorCoord(iCount,iDim) = Buffer_Receive_Coord[offset + iVertex*nDim + iDim]; + DonorCoord(iCount,iDim) = Buffer_Receive_Coord[(offset+iVertex)*nDim + iDim]; + DonorPoint[iCount] = Buffer_Receive_GlobalPoint[offset+iVertex]; + DonorProc[iCount] = iProcessor; ++iCount; } } assert((iCount == nGlobalVertexDonor) && "Global donor point count mismatch."); - /*--- The master node prepares the global interpolation kernel. ---*/ - int nPolynomial = -1; - vector keepPolynomialRow(nDim,1); + delete[] Buffer_Send_Coord; + delete[] Buffer_Send_GlobalPoint; + delete[] Buffer_Receive_Coord; + delete[] Buffer_Receive_GlobalPoint; - su2passivematrix C_inv_trunc; + /*--- Static work scheduling over ranks based on which one has less work currently. ---*/ + int iProcessor = 0; + for (int i = 1; i < nProcessor; ++i) + if (TotalWork[i] < TotalWork[iProcessor]) iProcessor = i; - if (rank==MASTER_NODE) { + TotalWork[iProcessor] += pow(nGlobalVertexDonor,3); // based on matrix inversion. - /*--- Populate interpolation kernel. ---*/ - CSymmetricMatrix global_M(nGlobalVertexDonor); + AssignedProcessor[iMarkerInt-1] = iProcessor; - for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; ++iVertex) - for (auto jVertex = iVertex; jVertex < nGlobalVertexDonor; ++jVertex) - global_M(iVertex, jVertex) = SU2_TYPE::GetValue(Get_RadialBasisValue(kindRBF, paramRBF, - PointsDistance(nDim, DonorCoord[iVertex], DonorCoord[jVertex]))); + } - /*--- Invert M matrix (operation is in-place). ---*/ - switch (kindRBF) { - /*--- Basis functions that make M positive definite. ---*/ - case WENDLAND_C2: - case INV_MULTI_QUADRIC: - case GAUSSIAN: - global_M.Invert(true); break; + /*--- Compute the interpolation matrices for each patch of coordinates + * assigned to the rank. Subdivide work further by threads. ---*/ + vector nPolynomialVec(nMarkerInt,-1); + vector > keepPolynomialRowVec(nMarkerInt, vector(nDim,1)); + vector CinvTrucVec(nMarkerInt); - /*--- Basis functions that make M semi-positive definite. ---*/ - case THIN_PLATE_SPLINE: - case MULTI_QUADRIC: - global_M.Invert(false); break; - } + SU2_OMP_PARALLEL_(for schedule(dynamic,1)) + for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; ++iMarkerInt) { - /*--- Compute C_inv_trunc. ---*/ - if (usePolynomial) { + if (rank != AssignedProcessor[iMarkerInt]) continue; // #notmyjob - /*--- Fill P matrix (P for points, with an extra top row of ones). ---*/ - su2passivematrix P(1+nDim, nGlobalVertexDonor); + const auto& DonorCoord = DonorCoordinates[iMarkerInt]; + const auto nGlobalVertexDonor = DonorCoord.rows(); - for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; iVertex++) { - P(0, iVertex) = 1.0; - for (int iDim = 0; iDim < nDim; ++iDim) - P(1+iDim, iVertex) = SU2_TYPE::GetValue(DonorCoord(iVertex, iDim)); - } + auto& C_inv_trunc = CinvTrucVec[iMarkerInt]; + auto& nPolynomial = nPolynomialVec[iMarkerInt]; + auto& keepPolynomialRow = keepPolynomialRowVec[iMarkerInt]; - /*--- Check if points lie on a plane and remove one coordinate from P if so. ---*/ - nPolynomial = CheckPolynomialTerms(interfaceCoordTol, keepPolynomialRow, P); + /*--- Populate interpolation kernel. ---*/ + CSymmetricMatrix global_M(nGlobalVertexDonor); - /*--- Compute Mp = (P * M^-1 * P^T)^-1 ---*/ - CSymmetricMatrix Mp(nPolynomial+1); + for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; ++iVertex) + for (auto jVertex = iVertex; jVertex < nGlobalVertexDonor; ++jVertex) + global_M(iVertex, jVertex) = SU2_TYPE::GetValue(Get_RadialBasisValue(kindRBF, paramRBF, + PointsDistance(nDim, DonorCoord[iVertex], DonorCoord[jVertex]))); - su2passivematrix tmp; - global_M.MatMatMult('R', P, tmp); // tmp = P * M^-1 + /*--- Invert M matrix (operation is in-place). ---*/ + switch (kindRBF) { + /*--- Basis functions that make M positive definite. ---*/ + case WENDLAND_C2: + case INV_MULTI_QUADRIC: + case GAUSSIAN: + global_M.Invert(true); break; - for (int i = 0; i <= nPolynomial; ++i) // Mp = tmp * P - for (int j = i; j <= nPolynomial; ++j) { - Mp(i,j) = 0.0; - for (auto k = 0ul; k < nGlobalVertexDonor; ++k) Mp(i,j) += tmp(i,k) * P(j,k); - } - Mp.Invert(false); // Mp = Mp^-1 + /*--- Basis functions that make M semi-positive definite. ---*/ + case THIN_PLATE_SPLINE: + case MULTI_QUADRIC: + global_M.Invert(false); break; + } - /*--- Compute M_p * P * M^-1, the top part of C_inv_trunc. ---*/ - Mp.MatMatMult('L', P, tmp); - su2passivematrix C_inv_top; - global_M.MatMatMult('R', tmp, C_inv_top); + /*--- Compute C_inv_trunc. ---*/ + if (usePolynomial) { - /*--- Compute tmp = (I - P^T * M_p * P * M^-1), part of the bottom part of - C_inv_trunc. Note that most of the product is known from the top part. ---*/ - tmp.resize(nGlobalVertexDonor, nGlobalVertexDonor); + /*--- Fill P matrix (P for points, with an extra top row of ones). ---*/ + su2passivematrix P(1+nDim, nGlobalVertexDonor); - for (auto i = 0ul; i < nGlobalVertexDonor; ++i) { - for (auto j = 0ul; j < nGlobalVertexDonor; ++j) { - tmp(i,j) = 0.0; - for (int k = 0; k <= nPolynomial; ++k) tmp(i,j) -= P(k,i) * C_inv_top(k,j); - } - tmp(i,i) += 1.0; // identity part + for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; iVertex++) { + P(0, iVertex) = 1.0; + for (int iDim = 0; iDim < nDim; ++iDim) + P(1+iDim, iVertex) = SU2_TYPE::GetValue(DonorCoord(iVertex, iDim)); + } + + /*--- Check if points lie on a plane and remove one coordinate from P if so. ---*/ + nPolynomial = CheckPolynomialTerms(interfaceCoordTol, keepPolynomialRow, P); + + /*--- Compute Mp = (P * M^-1 * P^T)^-1 ---*/ + CSymmetricMatrix Mp(nPolynomial+1); + + su2passivematrix tmp; + global_M.MatMatMult('R', P, tmp); // tmp = P * M^-1 + + for (int i = 0; i <= nPolynomial; ++i) // Mp = tmp * P + for (int j = i; j <= nPolynomial; ++j) { + Mp(i,j) = 0.0; + for (auto k = 0ul; k < nGlobalVertexDonor; ++k) Mp(i,j) += tmp(i,k) * P(j,k); } + Mp.Invert(false); // Mp = Mp^-1 - /*--- Compute M^-1 * (I - P^T * M_p * P * M^-1), finalize bottom of C_inv_trunc. ---*/ - global_M.MatMatMult('L', tmp, C_inv_trunc); + /*--- Compute M_p * P * M^-1, the top part of C_inv_trunc. ---*/ + Mp.MatMatMult('L', P, tmp); + su2passivematrix C_inv_top; + global_M.MatMatMult('R', tmp, C_inv_top); - /*--- Merge top and bottom of C_inv_trunc. ---*/ - tmp = move(C_inv_trunc); - C_inv_trunc.resize(1+nPolynomial+nGlobalVertexDonor, nGlobalVertexDonor); - memcpy(C_inv_trunc[0], C_inv_top.data(), C_inv_top.size()*sizeof(passivedouble)); - memcpy(C_inv_trunc[1+nPolynomial], tmp.data(), tmp.size()*sizeof(passivedouble)); + /*--- Compute tmp = (I - P^T * M_p * P * M^-1), part of the bottom part of + C_inv_trunc. Note that most of the product is known from the top part. ---*/ + tmp.resize(nGlobalVertexDonor, nGlobalVertexDonor); + + for (auto i = 0ul; i < nGlobalVertexDonor; ++i) { + for (auto j = 0ul; j < nGlobalVertexDonor; ++j) { + tmp(i,j) = 0.0; + for (int k = 0; k <= nPolynomial; ++k) tmp(i,j) -= P(k,i) * C_inv_top(k,j); + } + tmp(i,i) += 1.0; // identity part } - else { - /*--- No polynomial term used in the interpolation, C_inv_trunc = M^-1. ---*/ - C_inv_trunc.resize(nGlobalVertexDonor, nGlobalVertexDonor); - for (auto i = 0ul; i < nGlobalVertexDonor; ++i) - for (auto j = 0ul; j < nGlobalVertexDonor; ++j) - C_inv_trunc(i,j) = global_M(i,j); + /*--- Compute M^-1 * (I - P^T * M_p * P * M^-1), finalize bottom of C_inv_trunc. ---*/ + global_M.MatMatMult('L', tmp, C_inv_trunc); - } // end usePolynomial + /*--- Merge top and bottom of C_inv_trunc. ---*/ + tmp = move(C_inv_trunc); + C_inv_trunc.resize(1+nPolynomial+nGlobalVertexDonor, nGlobalVertexDonor); + memcpy(C_inv_trunc[0], C_inv_top.data(), C_inv_top.size()*sizeof(passivedouble)); + memcpy(C_inv_trunc[1+nPolynomial], tmp.data(), tmp.size()*sizeof(passivedouble)); + } + else { + /*--- No polynomial term used in the interpolation, C_inv_trunc = M^-1. ---*/ + + C_inv_trunc.resize(nGlobalVertexDonor, nGlobalVertexDonor); + for (auto i = 0ul; i < nGlobalVertexDonor; ++i) + for (auto j = 0ul; j < nGlobalVertexDonor; ++j) + C_inv_trunc(i,j) = global_M(i,j); + + } // end usePolynomial + + } - } // end (rank == MASTER_NODE) + /*--- Final loop over interface markers to compute the interpolation coefficients. ---*/ - /*--- Broadcast C_inv_trunc to all nodes, each node then - computes its part of the interpolation matrix. ---*/ + for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; iMarkerInt++) { - SU2_MPI::Bcast(&nPolynomial, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Bcast(keepPolynomialRow.data(), nDim, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); + /*--- Identify the rank that computed the interpolation matrix for this marker. ---*/ + const int iProcessor = AssignedProcessor[iMarkerInt]; + /*--- If no processor was assigned to work, the zone does not contain the interface. ---*/ + if (iProcessor < 0) continue; - if (rank != MASTER_NODE) - C_inv_trunc.resize(nGlobalVertexDonor+nPolynomial+1, nGlobalVertexDonor); + /*--- Setup target information. ---*/ + const int mark_target = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); + unsigned long nVertexTarget = 0; + if(mark_target != -1) nVertexTarget = target_geometry->GetnVertex(mark_target); + + /*--- Set references to donor information. ---*/ + auto& DonorCoord = DonorCoordinates[iMarkerInt]; + auto& DonorPoint = DonorGlobalPoint[iMarkerInt]; + auto& DonorProc = DonorProcessor[iMarkerInt]; + + auto& C_inv_trunc = CinvTrucVec[iMarkerInt]; + auto& nPolynomial = nPolynomialVec[iMarkerInt]; + auto& keepPolynomialRow = keepPolynomialRowVec[iMarkerInt]; + + const auto nGlobalVertexDonor = DonorCoord.rows(); #ifdef HAVE_MPI - /*--- MPI wrapper not used due to passive double. ---*/ - MPI_Bcast(C_inv_trunc.data(), C_inv_trunc.size(), MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); + /*--- For simplicity, broadcast small information about the interpolation matrix. ---*/ + SU2_MPI::Bcast(&nPolynomial, 1, MPI_INT, iProcessor, MPI_COMM_WORLD); + SU2_MPI::Bcast(keepPolynomialRow.data(), nDim, MPI_INT, iProcessor, MPI_COMM_WORLD); + + /*--- Send C_inv_trunc only to the ranks that need it (those with target points), + * partial broadcast. MPI wrapper not used due to passive double. ---*/ + vector allNumVertex(nProcessor); + SU2_MPI::Allgather(&nVertexTarget, 1, MPI_UNSIGNED_LONG, + allNumVertex.data(), 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + if (rank == iProcessor) { + for (int jProcessor = 0; jProcessor < nProcessor; ++jProcessor) + if ((jProcessor != iProcessor) && (allNumVertex[jProcessor] != 0)) + MPI_Send(C_inv_trunc.data(), C_inv_trunc.size(), + MPI_DOUBLE, jProcessor, 0, MPI_COMM_WORLD); + } + else if (nVertexTarget != 0) { + C_inv_trunc.resize(1+nPolynomial+nGlobalVertexDonor, nGlobalVertexDonor); + MPI_Recv(C_inv_trunc.data(), C_inv_trunc.size(), MPI_DOUBLE, + iProcessor, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + } #endif - /*--- Compute H matrix. ---*/ + /*--- Compute H matrix, distributing target points over the threads in the rank. ---*/ + SU2_OMP_PARALLEL + { + su2passivevector target_vec(nGlobalVertexDonor+nPolynomial+1); + su2passivevector coeff_vec(nGlobalVertexDonor); + SU2_OMP_FOR_DYN(roundUpDiv(nVertexTarget, 2*omp_get_max_threads())) for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; iVertexTarget++) { auto target_vertex = target_geometry->vertex[mark_target][iVertexTarget]; @@ -2883,9 +2962,6 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { /*--- If not domain point move to next. ---*/ if (!target_geometry->node[point_target]->GetDomain()) continue; - su2passivevector target_vec(nGlobalVertexDonor+nPolynomial+1); - su2passivevector coeff_vec(nGlobalVertexDonor); - const su2double* coord_i = target_geometry->node[point_target]->GetCoord(); /*--- Prepare target vector (one row of the target matrix). ---*/ @@ -2930,27 +3006,24 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { /*--- Allocate and set donor information for this target point. ---*/ target_vertex->SetnDonorPoints(idx); target_vertex->Allocate_DonorInfo(); - - int iSet = 0; - for (int iProcessor = 0, iTest = -1; iProcessor < nProcessor; ++iProcessor) { - const auto offset = iProcessor * MaxLocalVertex_Donor; - for (auto iVertex = 0ul; iVertex < Buffer_Receive_nVertex_Donor[iProcessor]; ++iVertex) - if (fabs(coeff_vec(++iTest)) > 0.0) { - auto point_donor = Buffer_Receive_GlobalPoint[offset + iVertex]; - target_vertex->SetInterpDonorProcessor(iSet, iProcessor); - target_vertex->SetInterpDonorPoint(iSet, point_donor); - target_vertex->SetDonorCoeff(iSet, coeff_vec(iTest)); - ++iSet; - } + idx = 0; + for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; ++iVertex) { + if (fabs(coeff_vec(iVertex)) > 0.0) { + target_vertex->SetInterpDonorProcessor(idx, DonorProc[iVertex]); + target_vertex->SetInterpDonorPoint(idx, DonorPoint[iVertex]); + target_vertex->SetDonorCoeff(idx, coeff_vec(iVertex)); + ++idx; + } } - assert(idx==iSet && "Error while setting donor point coefficients."); } // end target vertex loop + } // end SU2_OMP_PARALLEL - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_GlobalPoint; - delete[] Buffer_Receive_Coord; - delete[] Buffer_Receive_GlobalPoint; + /*--- Delete global data that will no longer be used. ---*/ + DonorCoord.resize(0,0); + vector().swap(DonorPoint); + vector().swap(DonorProc); + C_inv_trunc.resize(0,0); } // end loop over interface markers From 47ad5d13ebc810a295b77cb02646c166f25f8ba7 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 17 Mar 2020 19:07:52 +0000 Subject: [PATCH 05/79] adjust some settings in regression case to make it closer to reference --- TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg | 2 +- TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg b/TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg index 99e3530ccdd3..eff2d6ed2b36 100644 --- a/TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg +++ b/TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg @@ -12,7 +12,7 @@ CONSERVATIVE_INTERPOLATION = YES KIND_RADIAL_BASIS_FUNCTION = WENDLAND_C2 RADIAL_BASIS_FUNCTION_PARAMETER = 0.015 RADIAL_BASIS_FUNCTION_POLYNOMIAL_TERM = YES -RADIAL_BASIS_FUNCTION_PRUNE_TOLERANCE = 1e-6 +RADIAL_BASIS_FUNCTION_PRUNE_TOLERANCE = 0 % % Physics -------------------------------------------------------------- % SOLVER= ELASTICITY diff --git a/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg b/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg index 6d293bd5506e..9efc636b33d4 100644 --- a/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg +++ b/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg @@ -33,7 +33,7 @@ RADIAL_BASIS_FUNCTION_POLYNOMIAL_TERM = YES % The number of donor points per target point is reduced by prunning away % small interpolation coefficients (making the interp. matrix sparse). % This tolerance is relative to the maximum absolute coefficient. -RADIAL_BASIS_FUNCTION_PRUNE_TOLERANCE = 1e-6 +RADIAL_BASIS_FUNCTION_PRUNE_TOLERANCE = 0 % % Physics -------------------------------------------------------------- % SOLVER= EULER From 04fff4b39e06d48971902a83089749ed4748c1e7 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 17 Mar 2020 21:10:49 +0000 Subject: [PATCH 06/79] move pruning to separate function --- Common/include/interpolation_structure.hpp | 9 ++ Common/src/interpolation_structure.cpp | 121 ++++++++++++--------- 2 files changed, 81 insertions(+), 49 deletions(-) diff --git a/Common/include/interpolation_structure.hpp b/Common/include/interpolation_structure.hpp index a1349ecd4df7..448178a7a4e7 100644 --- a/Common/include/interpolation_structure.hpp +++ b/Common/include/interpolation_structure.hpp @@ -430,6 +430,15 @@ class CRadialBasisFunction final : public CInterpolator { */ int CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, su2passivematrix &P) const; + /*! + * \brief Prunes (by setting to zero) small interpolation coefficients, i.e. + * <= tolerance*max(abs(coeffs)). The vector is re-scaled such that sum(coeffs)==1. + * \param[in] tolerance - Relative pruning tolerance. + * \param[in,out] coeffs - The vector of interpolation coefficients. + * \return Number of non-zero coefficients after pruning. + */ + int PruneSmallCoefficients(passivedouble tolerance, su2passivevector& coeffs) const; + }; /*! diff --git a/Common/src/interpolation_structure.cpp b/Common/src/interpolation_structure.cpp index 414729f9ff55..95d1a9b9aa5f 100644 --- a/Common/src/interpolation_structure.cpp +++ b/Common/src/interpolation_structure.cpp @@ -2720,13 +2720,13 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { vector AssignedProcessor(nMarkerInt,-1); vector TotalWork(nProcessor,0); - for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; ++iMarkerInt) { + for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; ++iMarkerInt) { /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ - int mark_donor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + int mark_donor = Find_InterfaceMarker(config[donorZone], iMarkerInt+1); /*--- On the target side: find the tag of the boundary sharing the interface. ---*/ - int mark_target = Find_InterfaceMarker(config[targetZone], iMarkerInt); + int mark_target = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); /*--- We gather a vector in MASTER_NODE to determines whether the boundary is not on the processor because of the partition or because the zone does not include it. ---*/ @@ -2756,9 +2756,9 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { Collect_VertexInfo(false, mark_donor, mark_target, nVertexDonor, nDim); /*--- Compresses the gathered donor point information to simplify computation. ---*/ - auto& DonorCoord = DonorCoordinates[iMarkerInt-1]; - auto& DonorPoint = DonorGlobalPoint[iMarkerInt-1]; - auto& DonorProc = DonorProcessor[iMarkerInt-1]; + auto& DonorCoord = DonorCoordinates[iMarkerInt]; + auto& DonorPoint = DonorGlobalPoint[iMarkerInt]; + auto& DonorProc = DonorProcessor[iMarkerInt]; DonorCoord.resize(nGlobalVertexDonor, nDim); DonorPoint.resize(nGlobalVertexDonor); DonorProc.resize(nGlobalVertexDonor); @@ -2788,7 +2788,7 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { TotalWork[iProcessor] += pow(nGlobalVertexDonor,3); // based on matrix inversion. - AssignedProcessor[iMarkerInt-1] = iProcessor; + AssignedProcessor[iMarkerInt] = iProcessor; } @@ -2950,7 +2950,6 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { /*--- Compute H matrix, distributing target points over the threads in the rank. ---*/ SU2_OMP_PARALLEL { - su2passivevector target_vec(nGlobalVertexDonor+nPolynomial+1); su2passivevector coeff_vec(nGlobalVertexDonor); SU2_OMP_FOR_DYN(roundUpDiv(nVertexTarget, 2*omp_get_max_threads())) @@ -2964,55 +2963,52 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { const su2double* coord_i = target_geometry->node[point_target]->GetCoord(); - /*--- Prepare target vector (one row of the target matrix). ---*/ - /*--- polynominal part ---*/ - int idx = 0; + /*--- Multiply target vector by C_inv_trunc to obtain the interpolation coefficients. + * The target vector is not stored, we consume its entries immediately to avoid + * strided access to C_inv_trunc (as it is row-major). ---*/ + + /*--- Polynominal part: ---*/ if (usePolynomial) { - target_vec(idx++) = 1.0; // constant term - for (int iDim = 0; iDim < nDim; ++iDim) // linear terms - if (keepPolynomialRow[iDim]) // of which one may have been excluded - target_vec(idx++) = SU2_TYPE::GetValue(coord_i[iDim]); + /*--- Constant term. ---*/ + for (auto j = 0ul; j < nGlobalVertexDonor; ++j) + coeff_vec(j) = C_inv_trunc(0,j); + + /*--- Linear terms. ---*/ + for (int iDim = 0, idx = 1; iDim < nDim; ++iDim) { + /*--- Of which one may have been excluded. ---*/ + if (!keepPolynomialRow[iDim]) continue; + for (auto j = 0ul; j < nGlobalVertexDonor; ++j) + coeff_vec(j) += SU2_TYPE::GetValue(coord_i[iDim]) * C_inv_trunc(idx,j); + idx += 1; + } } - /*--- RBF part ---*/ - for (auto iVertexDonor = 0ul; iVertexDonor < nGlobalVertexDonor; ++iVertexDonor) - target_vec(iVertexDonor+idx) = SU2_TYPE::GetValue(Get_RadialBasisValue(kindRBF, paramRBF, - PointsDistance(nDim, coord_i, DonorCoord[iVertexDonor]))); - - /*--- Multiply target vector by C_inv_trunc to obtain the interpolation coefficients. - Simultaneously determine a reference for dropping small coefficients. ---*/ - passivedouble coeffRef = 0.0; - for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; ++iVertex) { - coeff_vec(iVertex) = 0.0; - for (auto jVertex = 0ul; jVertex < target_vec.size(); ++jVertex) - coeff_vec(iVertex) += target_vec(jVertex) * C_inv_trunc(jVertex, iVertex); - coeffRef = max(coeffRef, fabs(coeff_vec(iVertex))); + else { + /*--- Initialize vector to zero. ---*/ + for (auto j = 0ul; j < nGlobalVertexDonor; ++j) coeff_vec(j) = 0.0; } - coeffRef *= SU2_TYPE::GetValue(pruneTol); - - /*--- Prune and count the number of donor points for this target point. ---*/ - idx = 0; - passivedouble coeffSum = 0.0; - for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; ++iVertex) { - if (fabs(coeff_vec(iVertex)) > coeffRef) { - coeffSum += coeff_vec(iVertex); - ++idx; - } - else coeff_vec(iVertex) = 0.0; + + /*--- RBF terms: ---*/ + for (auto iVertexDonor = 0ul; iVertexDonor < nGlobalVertexDonor; ++iVertexDonor) { + auto w_ij = SU2_TYPE::GetValue(Get_RadialBasisValue(kindRBF, paramRBF, + PointsDistance(nDim, coord_i, DonorCoord[iVertexDonor]))); + + for (auto j = 0ul; j < nGlobalVertexDonor; ++j) + coeff_vec(j) += w_ij * C_inv_trunc(1+nPolynomial+iVertexDonor, j); } - /*--- Correct remaining coefficients, sum must be 1 for conservation. ---*/ - passivedouble correction = 1.0 / coeffSum; - for (auto i = 0ul; i < nGlobalVertexDonor; ++i) coeff_vec(i) *= correction; + + /*--- Prune small coefficients. ---*/ + auto nnz = PruneSmallCoefficients(SU2_TYPE::GetValue(pruneTol), coeff_vec); /*--- Allocate and set donor information for this target point. ---*/ - target_vertex->SetnDonorPoints(idx); + target_vertex->SetnDonorPoints(nnz); target_vertex->Allocate_DonorInfo(); - idx = 0; - for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; ++iVertex) { + + for (unsigned long iVertex = 0, iSet = 0; iVertex < nGlobalVertexDonor; ++iVertex) { if (fabs(coeff_vec(iVertex)) > 0.0) { - target_vertex->SetInterpDonorProcessor(idx, DonorProc[iVertex]); - target_vertex->SetInterpDonorPoint(idx, DonorPoint[iVertex]); - target_vertex->SetDonorCoeff(idx, coeff_vec(iVertex)); - ++idx; + target_vertex->SetInterpDonorProcessor(iSet, DonorProc[iVertex]); + target_vertex->SetInterpDonorPoint(iSet, DonorPoint[iVertex]); + target_vertex->SetDonorCoeff(iSet, coeff_vec(iVertex)); + ++iSet; } } @@ -3032,6 +3028,33 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { } +int CRadialBasisFunction::PruneSmallCoefficients(passivedouble tolerance, + su2passivevector& coeffs) const { + + /*--- Determine the pruning threshold. ---*/ + passivedouble thresh = 0.0; + for (auto i = 0ul; i < coeffs.size(); ++i) + thresh = max(thresh, fabs(coeffs(i))); + thresh *= tolerance; + + /*--- Prune and count non-zeros. ---*/ + int numNonZeros = 0; + passivedouble coeffSum = 0.0; + for (auto i = 0ul; i < coeffs.size(); ++i) { + if (fabs(coeffs(i)) > thresh) { + coeffSum += coeffs(i); + ++numNonZeros; + } + else coeffs(i) = 0.0; + } + + /*--- Correct remaining coefficients, sum must be 1 for conservation. ---*/ + passivedouble correction = 1.0 / coeffSum; + for (auto i = 0ul; i < coeffs.size(); ++i) coeffs(i) *= correction; + + return numNonZeros; +} + int CRadialBasisFunction::CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, su2passivematrix &P) const { const int m = P.rows(); From d077e55a16813db87485182d070a41721ed66a67 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 17 Mar 2020 23:22:06 +0000 Subject: [PATCH 07/79] move one more chunk of code to separate function --- Common/include/interpolation_structure.hpp | 20 +- Common/src/interpolation_structure.cpp | 279 ++++++++++----------- 2 files changed, 155 insertions(+), 144 deletions(-) diff --git a/Common/include/interpolation_structure.hpp b/Common/include/interpolation_structure.hpp index 448178a7a4e7..bffcc34bf78d 100644 --- a/Common/include/interpolation_structure.hpp +++ b/Common/include/interpolation_structure.hpp @@ -415,10 +415,28 @@ class CRadialBasisFunction final : public CInterpolator { * \param[in] type - of radial basis function * \param[in] radius - the characteristic dimension * \param[in] dist - distance + * \return value of the RBF. */ - static su2double Get_RadialBasisValue(const unsigned short type, const su2double radius, const su2double dist); + static su2double Get_RadialBasisValue(ENUM_RADIALBASIS type, const su2double radius, const su2double dist); private: + /*! + * \brief Compute the RBF "generator" matrix with or without polynomial terms. + * \note Multiplying C_inv_trunc by a column vector gives specific coefficients for given "known values", + * conversely, multiplying (on the left) by a row vector of polynomial and RBF values gives generic + * interpolation coefficients for a given target evaluation point. + * \param[in] type - Type of radial basis function. + * \param[in] usePolynomial - Whether to use polynomial terms. + * \param[in] radius - Normalizes point-to-point distance when computing RBF values. + * \param[in] coords - Coordinates of the donor points. + * \param[out] nPolynomial - Num of poly terms, -1 if !usePolynomial, nDim-1 if coords lie on plane, else nDim. + * \param[out] keepPolynomialRow - Size nDim, signals which (if any) iDim was removed from polynomial term. + * \param[out] C_inv_trunc - The generator matrix as described above. + */ + void ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool usePolynomial, su2double radius, + const su2activematrix& coords, int& nPolynomial, + vector& keepPolynomialRow, su2passivematrix& C_inv_trunc) const; + /*! * \brief If the polynomial term is included in the interpolation, and the points lie on a plane, the matrix * becomes rank deficient and cannot be inverted. This method detects that condition and corrects it by diff --git a/Common/src/interpolation_structure.cpp b/Common/src/interpolation_structure.cpp index 95d1a9b9aa5f..f8dab7563711 100644 --- a/Common/src/interpolation_structure.cpp +++ b/Common/src/interpolation_structure.cpp @@ -2683,7 +2683,6 @@ bool CSlidingMesh::CheckPointInsideTriangle(su2double* Point, su2double* T1, su2 return (check == 3); } -/*--- Radial Basis Function Interpolator ---*/ CRadialBasisFunction::CRadialBasisFunction(void): CInterpolator() { } CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, @@ -2693,15 +2692,43 @@ CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, CCo Set_TransferCoeff(config); } +su2double CRadialBasisFunction::Get_RadialBasisValue(ENUM_RADIALBASIS type, const su2double radius, const su2double dist) +{ + su2double rbf = dist/radius; + + switch (type) { + + case WENDLAND_C2: + if(rbf < 1) rbf = pow(pow((1-rbf),2),2)*(4*rbf+1); // double use of pow(x,2) for optimization + else rbf = 0.0; + break; + + case GAUSSIAN: + rbf = exp(-rbf*rbf); + break; + + case THIN_PLATE_SPLINE: + if(rbf < numeric_limits::min()) rbf = 0.0; + else rbf *= rbf*log(rbf); + break; + + case MULTI_QUADRIC: + case INV_MULTI_QUADRIC: + rbf = sqrt(1.0+rbf*rbf); + if(type == INV_MULTI_QUADRIC) rbf = 1.0/rbf; + break; + } + + return rbf; +} + void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { /*--- RBF options. ---*/ - const unsigned short kindRBF = config[donorZone]->GetKindRadialBasisFunction(); + const auto kindRBF = static_cast(config[donorZone]->GetKindRadialBasisFunction()); const bool usePolynomial = config[donorZone]->GetRadialBasisFunctionPolynomialOption(); const su2double paramRBF = config[donorZone]->GetRadialBasisFunctionParameter(); const su2double pruneTol = config[donorZone]->GetRadialBasisFunctionPruneTol(); - const passivedouble eps = numeric_limits::epsilon(); - const su2double interfaceCoordTol = 1e6 * eps; const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; const int nDim = donor_geometry->GetnDim(); @@ -2755,7 +2782,7 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { Collect_VertexInfo(false, mark_donor, mark_target, nVertexDonor, nDim); - /*--- Compresses the gathered donor point information to simplify computation. ---*/ + /*--- Compresses the gathered donor point information to simplify computations. ---*/ auto& DonorCoord = DonorCoordinates[iMarkerInt]; auto& DonorPoint = DonorGlobalPoint[iMarkerInt]; auto& DonorProc = DonorProcessor[iMarkerInt]; @@ -2800,102 +2827,11 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { SU2_OMP_PARALLEL_(for schedule(dynamic,1)) for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; ++iMarkerInt) { - - if (rank != AssignedProcessor[iMarkerInt]) continue; // #notmyjob - - const auto& DonorCoord = DonorCoordinates[iMarkerInt]; - const auto nGlobalVertexDonor = DonorCoord.rows(); - - auto& C_inv_trunc = CinvTrucVec[iMarkerInt]; - auto& nPolynomial = nPolynomialVec[iMarkerInt]; - auto& keepPolynomialRow = keepPolynomialRowVec[iMarkerInt]; - - /*--- Populate interpolation kernel. ---*/ - CSymmetricMatrix global_M(nGlobalVertexDonor); - - for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; ++iVertex) - for (auto jVertex = iVertex; jVertex < nGlobalVertexDonor; ++jVertex) - global_M(iVertex, jVertex) = SU2_TYPE::GetValue(Get_RadialBasisValue(kindRBF, paramRBF, - PointsDistance(nDim, DonorCoord[iVertex], DonorCoord[jVertex]))); - - /*--- Invert M matrix (operation is in-place). ---*/ - switch (kindRBF) { - /*--- Basis functions that make M positive definite. ---*/ - case WENDLAND_C2: - case INV_MULTI_QUADRIC: - case GAUSSIAN: - global_M.Invert(true); break; - - /*--- Basis functions that make M semi-positive definite. ---*/ - case THIN_PLATE_SPLINE: - case MULTI_QUADRIC: - global_M.Invert(false); break; - } - - /*--- Compute C_inv_trunc. ---*/ - if (usePolynomial) { - - /*--- Fill P matrix (P for points, with an extra top row of ones). ---*/ - su2passivematrix P(1+nDim, nGlobalVertexDonor); - - for (auto iVertex = 0ul; iVertex < nGlobalVertexDonor; iVertex++) { - P(0, iVertex) = 1.0; - for (int iDim = 0; iDim < nDim; ++iDim) - P(1+iDim, iVertex) = SU2_TYPE::GetValue(DonorCoord(iVertex, iDim)); - } - - /*--- Check if points lie on a plane and remove one coordinate from P if so. ---*/ - nPolynomial = CheckPolynomialTerms(interfaceCoordTol, keepPolynomialRow, P); - - /*--- Compute Mp = (P * M^-1 * P^T)^-1 ---*/ - CSymmetricMatrix Mp(nPolynomial+1); - - su2passivematrix tmp; - global_M.MatMatMult('R', P, tmp); // tmp = P * M^-1 - - for (int i = 0; i <= nPolynomial; ++i) // Mp = tmp * P - for (int j = i; j <= nPolynomial; ++j) { - Mp(i,j) = 0.0; - for (auto k = 0ul; k < nGlobalVertexDonor; ++k) Mp(i,j) += tmp(i,k) * P(j,k); - } - Mp.Invert(false); // Mp = Mp^-1 - - /*--- Compute M_p * P * M^-1, the top part of C_inv_trunc. ---*/ - Mp.MatMatMult('L', P, tmp); - su2passivematrix C_inv_top; - global_M.MatMatMult('R', tmp, C_inv_top); - - /*--- Compute tmp = (I - P^T * M_p * P * M^-1), part of the bottom part of - C_inv_trunc. Note that most of the product is known from the top part. ---*/ - tmp.resize(nGlobalVertexDonor, nGlobalVertexDonor); - - for (auto i = 0ul; i < nGlobalVertexDonor; ++i) { - for (auto j = 0ul; j < nGlobalVertexDonor; ++j) { - tmp(i,j) = 0.0; - for (int k = 0; k <= nPolynomial; ++k) tmp(i,j) -= P(k,i) * C_inv_top(k,j); - } - tmp(i,i) += 1.0; // identity part - } - - /*--- Compute M^-1 * (I - P^T * M_p * P * M^-1), finalize bottom of C_inv_trunc. ---*/ - global_M.MatMatMult('L', tmp, C_inv_trunc); - - /*--- Merge top and bottom of C_inv_trunc. ---*/ - tmp = move(C_inv_trunc); - C_inv_trunc.resize(1+nPolynomial+nGlobalVertexDonor, nGlobalVertexDonor); - memcpy(C_inv_trunc[0], C_inv_top.data(), C_inv_top.size()*sizeof(passivedouble)); - memcpy(C_inv_trunc[1+nPolynomial], tmp.data(), tmp.size()*sizeof(passivedouble)); + if (rank == AssignedProcessor[iMarkerInt]) { + ComputeGeneratorMatrix(kindRBF, usePolynomial, paramRBF, + DonorCoordinates[iMarkerInt], nPolynomialVec[iMarkerInt], + keepPolynomialRowVec[iMarkerInt], CinvTrucVec[iMarkerInt]); } - else { - /*--- No polynomial term used in the interpolation, C_inv_trunc = M^-1. ---*/ - - C_inv_trunc.resize(nGlobalVertexDonor, nGlobalVertexDonor); - for (auto i = 0ul; i < nGlobalVertexDonor; ++i) - for (auto j = 0ul; j < nGlobalVertexDonor; ++j) - C_inv_trunc(i,j) = global_M(i,j); - - } // end usePolynomial - } /*--- Final loop over interface markers to compute the interpolation coefficients. ---*/ @@ -3028,31 +2964,91 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { } -int CRadialBasisFunction::PruneSmallCoefficients(passivedouble tolerance, - su2passivevector& coeffs) const { +void CRadialBasisFunction::ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool usePolynomial, + su2double radius, const su2activematrix& coords, int& nPolynomial, + vector& keepPolynomialRow, su2passivematrix& C_inv_trunc) const { - /*--- Determine the pruning threshold. ---*/ - passivedouble thresh = 0.0; - for (auto i = 0ul; i < coeffs.size(); ++i) - thresh = max(thresh, fabs(coeffs(i))); - thresh *= tolerance; + const su2double interfaceCoordTol = 1e6 * numeric_limits::epsilon(); - /*--- Prune and count non-zeros. ---*/ - int numNonZeros = 0; - passivedouble coeffSum = 0.0; - for (auto i = 0ul; i < coeffs.size(); ++i) { - if (fabs(coeffs(i)) > thresh) { - coeffSum += coeffs(i); - ++numNonZeros; + const auto nVertexDonor = coords.rows(); + const int nDim = coords.cols(); + + /*--- Populate interpolation kernel. ---*/ + CSymmetricMatrix global_M(nVertexDonor); + + for (auto iVertex = 0ul; iVertex < nVertexDonor; ++iVertex) + for (auto jVertex = iVertex; jVertex < nVertexDonor; ++jVertex) + global_M(iVertex, jVertex) = SU2_TYPE::GetValue(Get_RadialBasisValue(type, radius, + PointsDistance(nDim, coords[iVertex], coords[jVertex]))); + + /*--- Invert M matrix (operation is in-place). ---*/ + const bool kernelIsSPD = (type==WENDLAND_C2) || (type==GAUSSIAN) || (type==INV_MULTI_QUADRIC); + global_M.Invert(kernelIsSPD); + + /*--- Compute C_inv_trunc. ---*/ + if (usePolynomial) { + + /*--- Fill P matrix (P for points, with an extra top row of ones). ---*/ + su2passivematrix P(1+nDim, nVertexDonor); + + for (auto iVertex = 0ul; iVertex < nVertexDonor; iVertex++) { + P(0, iVertex) = 1.0; + for (int iDim = 0; iDim < nDim; ++iDim) + P(1+iDim, iVertex) = SU2_TYPE::GetValue(coords(iVertex, iDim)); } - else coeffs(i) = 0.0; + + /*--- Check if points lie on a plane and remove one coordinate from P if so. ---*/ + nPolynomial = CheckPolynomialTerms(interfaceCoordTol, keepPolynomialRow, P); + + /*--- Compute Mp = (P * M^-1 * P^T)^-1 ---*/ + CSymmetricMatrix Mp(nPolynomial+1); + + su2passivematrix tmp; + global_M.MatMatMult('R', P, tmp); // tmp = P * M^-1 + + for (int i = 0; i <= nPolynomial; ++i) // Mp = tmp * P + for (int j = i; j <= nPolynomial; ++j) { + Mp(i,j) = 0.0; + for (auto k = 0ul; k < nVertexDonor; ++k) Mp(i,j) += tmp(i,k) * P(j,k); + } + Mp.Invert(false); // Mp = Mp^-1 + + /*--- Compute M_p * P * M^-1, the top part of C_inv_trunc. ---*/ + Mp.MatMatMult('L', P, tmp); + su2passivematrix C_inv_top; + global_M.MatMatMult('R', tmp, C_inv_top); + + /*--- Compute tmp = (I - P^T * M_p * P * M^-1), part of the bottom part of + C_inv_trunc. Note that most of the product is known from the top part. ---*/ + tmp.resize(nVertexDonor, nVertexDonor); + + for (auto i = 0ul; i < nVertexDonor; ++i) { + for (auto j = 0ul; j < nVertexDonor; ++j) { + tmp(i,j) = 0.0; + for (int k = 0; k <= nPolynomial; ++k) tmp(i,j) -= P(k,i) * C_inv_top(k,j); + } + tmp(i,i) += 1.0; // identity part + } + + /*--- Compute M^-1 * (I - P^T * M_p * P * M^-1), finalize bottom of C_inv_trunc. ---*/ + global_M.MatMatMult('L', tmp, C_inv_trunc); + + /*--- Merge top and bottom of C_inv_trunc. ---*/ + tmp = move(C_inv_trunc); + C_inv_trunc.resize(1+nPolynomial+nVertexDonor, nVertexDonor); + memcpy(C_inv_trunc[0], C_inv_top.data(), C_inv_top.size()*sizeof(passivedouble)); + memcpy(C_inv_trunc[1+nPolynomial], tmp.data(), tmp.size()*sizeof(passivedouble)); } + else { + /*--- No polynomial term used in the interpolation, C_inv_trunc = M^-1. ---*/ - /*--- Correct remaining coefficients, sum must be 1 for conservation. ---*/ - passivedouble correction = 1.0 / coeffSum; - for (auto i = 0ul; i < coeffs.size(); ++i) coeffs(i) *= correction; + C_inv_trunc.resize(nVertexDonor, nVertexDonor); + for (auto i = 0ul; i < nVertexDonor; ++i) + for (auto j = 0ul; j < nVertexDonor; ++j) + C_inv_trunc(i,j) = global_M(i,j); + + } // end usePolynomial - return numNonZeros; } int CRadialBasisFunction::CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, @@ -3125,34 +3121,31 @@ int CRadialBasisFunction::CheckPolynomialTerms(su2double max_diff_tol, vector::min()) rbf = 0.0; - else rbf *= rbf*log(rbf); - break; + /*--- Determine the pruning threshold. ---*/ + passivedouble thresh = 0.0; + for (auto i = 0ul; i < coeffs.size(); ++i) + thresh = max(thresh, fabs(coeffs(i))); + thresh *= tolerance; - case MULTI_QUADRIC: - case INV_MULTI_QUADRIC: - rbf = sqrt(1.0+rbf*rbf); - if(type == INV_MULTI_QUADRIC) rbf = 1.0/rbf; - break; + /*--- Prune and count non-zeros. ---*/ + int numNonZeros = 0; + passivedouble coeffSum = 0.0; + for (auto i = 0ul; i < coeffs.size(); ++i) { + if (fabs(coeffs(i)) > thresh) { + coeffSum += coeffs(i); + ++numNonZeros; + } + else coeffs(i) = 0.0; } - return rbf; + /*--- Correct remaining coefficients, sum must be 1 for conservation. ---*/ + passivedouble correction = 1.0 / coeffSum; + for (auto i = 0ul; i < coeffs.size(); ++i) coeffs(i) *= correction; + + return numNonZeros; } void CSymmetricMatrix::Initialize(int N) From 9185ca91546b277162dbe5e8bdf9f43d41d76ec4 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Wed, 18 Mar 2020 10:32:18 +0000 Subject: [PATCH 08/79] hybrid parallel nearest neighbor search --- Common/include/interpolation_structure.hpp | 34 +++-- Common/src/interpolation_structure.cpp | 154 +++++++++------------ 2 files changed, 84 insertions(+), 104 deletions(-) diff --git a/Common/include/interpolation_structure.hpp b/Common/include/interpolation_structure.hpp index bffcc34bf78d..7728dcc8180c 100644 --- a/Common/include/interpolation_structure.hpp +++ b/Common/include/interpolation_structure.hpp @@ -142,18 +142,28 @@ class CInterpolator { * \param[in] val_marker - index of the marker */ void ReconstructBoundary(unsigned long val_zone, int val_marker); - + + /*! + * \brief compute squared distance between 2 points + * \param[in] nDim - number of dimensions + * \param[in] point_i - coordinates of point i + * \param[in] point_j - coordinates of point j + */ + inline su2double PointsSquareDistance(unsigned short nDim, const su2double *point_i, const su2double *point_j) const { + su2double d = 0.0; + for(unsigned short iDim = 0; iDim < nDim; iDim++) + d += pow(point_j[iDim] - point_i[iDim], 2); + return d; + } + /*! * \brief compute distance between 2 points * \param[in] nDim - number of dimensions - * \param[in] point_i - * \param[in] point_i + * \param[in] point_i - coordinates of point i + * \param[in] point_j - coordinates of point j */ inline su2double PointsDistance(unsigned short nDim, const su2double *point_i, const su2double *point_j) const { - su2double m = 0; - for(unsigned short iDim = 0; iDim < nDim; iDim++) - m += pow(point_j[iDim] - point_i[iDim], 2); - return sqrt(m); + return sqrt(PointsSquareDistance(nDim, point_i, point_j)); } /*! @@ -188,9 +198,8 @@ class CInterpolator { /*! * \brief Nearest Neighbor interpolation */ -class CNearestNeighbor : public CInterpolator { +class CNearestNeighbor final : public CInterpolator { public: - /*! * \brief Constructor of the class. */ @@ -205,16 +214,11 @@ class CNearestNeighbor : public CInterpolator { */ CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - /*! - * \brief Destructor of the class. - */ - ~CNearestNeighbor(void); - /*! * \brief Set up transfer matrix defining relation between two meshes * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(CConfig **config); + void Set_TransferCoeff(CConfig **config) override; }; diff --git a/Common/src/interpolation_structure.cpp b/Common/src/interpolation_structure.cpp index f8dab7563711..762bcb38644c 100644 --- a/Common/src/interpolation_structure.cpp +++ b/Common/src/interpolation_structure.cpp @@ -544,139 +544,114 @@ bool CInterpolator::CheckInterfaceBoundary(int markDonor, int markTarget){ return true; } -/* Nearest Neighbor Interpolator */ -CNearestNeighbor::CNearestNeighbor(void): CInterpolator() { } +CNearestNeighbor::CNearestNeighbor(void): CInterpolator() { } -CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { +CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, + unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { - /*--- Initialize transfer coefficients between the zones ---*/ + /*--- Initialize transfer coefficients between the zones. ---*/ Set_TransferCoeff(config); } -CNearestNeighbor::~CNearestNeighbor() {} - void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { - int iProcessor, pProcessor, nProcessor = size; - int markDonor, markTarget; - - unsigned short nDim, iMarkerInt, nMarkerInt, iDonor; + /*--- By definition, one donor point per target point. ---*/ + constexpr auto numDonor = 1; + constexpr auto idxDonor = 0; - unsigned long nVertexDonor, nVertexTarget, Point_Target, jVertex, iVertexTarget; - unsigned long Global_Point_Donor; - long pGlobalPoint = 0; + const su2double eps = numeric_limits::epsilon(); - su2double *Coord_i, *Coord_j, dist, mindist, maxdist; - - /*--- Initialize variables --- */ - - nMarkerInt = (int) ( config[donorZone]->GetMarker_n_ZoneInterface() / 2 ); - - nDim = donor_geometry->GetnDim(); + const int nProcessor = size; + const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; + const auto nDim = donor_geometry->GetnDim(); - iDonor = 0; - + Buffer_Send_nVertex_Donor = new unsigned long [1]; Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; + /*--- Cycle over nMarkersInt interface to determine communication pattern. ---*/ - /*--- Cycle over nMarkersInt interface to determine communication pattern ---*/ + for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - - - /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ + const auto markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); + /*--- On the target side: find the tag of the boundary sharing the interface. ---*/ + const auto markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); - /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ - if( !CheckInterfaceBoundary(markDonor, markTarget) ) - continue; + /*--- Checks if the zone contains the interface, if not continue to the next step. ---*/ + if (!CheckInterfaceBoundary(markDonor, markTarget)) continue; - if(markDonor != -1) - nVertexDonor = donor_geometry->GetnVertex( markDonor ); - else - nVertexDonor = 0; - - if(markTarget != -1) - nVertexTarget = target_geometry->GetnVertex( markTarget ); - else - nVertexTarget = 0; - - Buffer_Send_nVertex_Donor = new unsigned long [ 1 ]; + unsigned long nVertexDonor = 0, nVertexTarget = 0; + if(markDonor != -1) nVertexDonor = donor_geometry->GetnVertex( markDonor ); + if(markTarget != -1) nVertexTarget = target_geometry->GetnVertex( markTarget ); - /* Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor */ + /* Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor. */ Determine_ArraySize(false, markDonor, markTarget, nVertexDonor, nDim); - Buffer_Send_Coord = new su2double [ MaxLocalVertex_Donor * nDim ]; - Buffer_Send_GlobalPoint = new long [ MaxLocalVertex_Donor ]; - Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; + Buffer_Send_Coord = new su2double [ MaxLocalVertex_Donor * nDim ]; + Buffer_Send_GlobalPoint = new long [ MaxLocalVertex_Donor ]; + Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; Buffer_Receive_GlobalPoint = new long [ nProcessor * MaxLocalVertex_Donor ]; - /*-- Collect coordinates, global points, and normal vectors ---*/ + /*-- Collect coordinates and global point indices. ---*/ Collect_VertexInfo( false, markDonor, markTarget, nVertexDonor, nDim ); - /*--- Compute the closest point to a Near-Field boundary point ---*/ - maxdist = 0.0; + /*--- Compute the closest donor point to each target. ---*/ + SU2_OMP_PARALLEL_(for schedule(dynamic,roundUpDiv(nVertexTarget,2*omp_get_max_threads()))) + for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; iVertexTarget++) { - for (iVertexTarget = 0; iVertexTarget < nVertexTarget; iVertexTarget++) { + auto target_vertex = target_geometry->vertex[markTarget][iVertexTarget]; + const auto Point_Target = target_vertex->GetNode(); - Point_Target = target_geometry->vertex[markTarget][iVertexTarget]->GetNode(); + if (!target_geometry->node[Point_Target]->GetDomain()) continue; - if ( target_geometry->node[Point_Target]->GetDomain() ) { + /*--- Coordinates of the target point. ---*/ + const su2double* Coord_i = target_geometry->node[Point_Target]->GetCoord(); - target_geometry->vertex[markTarget][iVertexTarget]->SetnDonorPoints(1); - target_geometry->vertex[markTarget][iVertexTarget]->Allocate_DonorInfo(); // Possible meme leak? + su2double mindist = 1e20; + long pGlobalPoint = 0; + int pProcessor = 0; - /*--- Coordinates of the boundary point ---*/ - Coord_i = target_geometry->node[Point_Target]->GetCoord(); + for (int iProcessor = 0; iProcessor < nProcessor; ++iProcessor) { + for (auto jVertex = 0ul; jVertex < Buffer_Receive_nVertex_Donor[iProcessor]; ++jVertex) { - mindist = 1E6; - pProcessor = 0; + const auto idx = iProcessor*MaxLocalVertex_Donor + jVertex; - /*--- Loop over all the boundaries to find the pair ---*/ + const su2double* Coord_j = &Buffer_Receive_Coord[idx*nDim]; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (jVertex = 0; jVertex < MaxLocalVertex_Donor; jVertex++) { - - Global_Point_Donor = iProcessor*MaxLocalVertex_Donor+jVertex; - - if (Buffer_Receive_GlobalPoint[Global_Point_Donor] != -1){ - - Coord_j = &Buffer_Receive_Coord[ Global_Point_Donor*nDim]; - - dist = PointsDistance(nDim, Coord_i, Coord_j); - - if (dist < mindist) { - mindist = dist; pProcessor = iProcessor; - pGlobalPoint = Buffer_Receive_GlobalPoint[Global_Point_Donor]; - } - - if (dist == 0.0) break; - } + const auto dist = PointsSquareDistance(nDim, Coord_i, Coord_j); + + if (dist < mindist) { + mindist = dist; + pProcessor = iProcessor; + pGlobalPoint = Buffer_Receive_GlobalPoint[idx]; } - } - /*--- Store the value of the pair ---*/ - maxdist = max(maxdist, mindist); - target_geometry->vertex[markTarget][iVertexTarget]->SetInterpDonorPoint(iDonor, pGlobalPoint); - target_geometry->vertex[markTarget][iVertexTarget]->SetInterpDonorProcessor(iDonor, pProcessor); - target_geometry->vertex[markTarget][iVertexTarget]->SetDonorCoeff(iDonor, 1.0); + /*--- Test for "exact" match. ---*/ + if (dist < eps) break; + } } + + /*--- Store matching pair. ---*/ + target_vertex->SetnDonorPoints(numDonor); + target_vertex->Allocate_DonorInfo(); + target_vertex->SetInterpDonorPoint(idxDonor, pGlobalPoint); + target_vertex->SetInterpDonorProcessor(idxDonor, pProcessor); + target_vertex->SetDonorCoeff(idxDonor, 1.0); + } delete[] Buffer_Send_Coord; delete[] Buffer_Send_GlobalPoint; - + delete[] Buffer_Receive_Coord; delete[] Buffer_Receive_GlobalPoint; - delete[] Buffer_Send_nVertex_Donor; - } + delete[] Buffer_Send_nVertex_Donor; delete[] Buffer_Receive_nVertex_Donor; + } @@ -2883,7 +2858,8 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { } #endif - /*--- Compute H matrix, distributing target points over the threads in the rank. ---*/ + /*--- Compute H (interpolation) matrix, distributing + * target points over the threads in the rank. ---*/ SU2_OMP_PARALLEL { su2passivevector coeff_vec(nGlobalVertexDonor); From b7223b2c9efe964059c6bd6606f5a493494ff8da Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Wed, 18 Mar 2020 11:49:35 +0000 Subject: [PATCH 09/79] general cleanup of all interpolation classes --- Common/include/interpolation_structure.hpp | 113 +-- Common/src/interpolation_structure.cpp | 985 +++++++++------------ 2 files changed, 449 insertions(+), 649 deletions(-) diff --git a/Common/include/interpolation_structure.hpp b/Common/include/interpolation_structure.hpp index 7728dcc8180c..3f8a01cba646 100644 --- a/Common/include/interpolation_structure.hpp +++ b/Common/include/interpolation_structure.hpp @@ -50,11 +50,10 @@ using namespace std; */ class CInterpolator { protected: - int rank, /*!< \brief MPI Rank. */ - size; /*!< \brief MPI Size. */ - unsigned int nZone; /*!< \brief Number of zones*/ - unsigned int donorZone, - targetZone; /*!< \brief Type of MPI zone */ + const int rank; /*!< \brief MPI Rank. */ + const int size; /*!< \brief MPI Size. */ + const unsigned donorZone; /*!< \brief Index of donor zone. */ + const unsigned targetZone; /*!< \brief Index of target zone. */ unsigned long MaxLocalVertex_Donor, /*!< \brief Maximum vertices per processor*/ @@ -77,7 +76,7 @@ class CInterpolator { *Buffer_Send_FaceProc, /*!< \brief Buffer to send processor which stores the node indicated in Buffer_Receive_FaceNodes*/ *Buffer_Receive_FaceProc; /*!< \brief Buffer to receive processor which stores the node indicated in Buffer_Receive_FaceNodes*/ - long *Buffer_Send_GlobalPoint, /*!< \brief Buffer to send global point indices*/ + long *Buffer_Send_GlobalPoint, /*!< \brief Buffer to send global point indices*/ *Buffer_Receive_GlobalPoint; /*!< \brief Buffer to receive global point indices*/ su2double *Buffer_Send_Coord, /*!< \brief Buffer to send coordinate values*/ @@ -98,18 +97,12 @@ class CInterpolator { nGlobalVertex, /*!< \brief Dummy variable to temporarily store the global number of vertex of a boundary*/ nLocalLinkedNodes; /*!< \brief Dummy variable to temporarily store the number of vertex of a boundary*/ -public: - CGeometry**** Geometry; /*! \brief Vector which stores n zones of geometry. */ - CGeometry* donor_geometry; /*! \brief Vector which stores the donor geometry. */ - CGeometry* target_geometry; /*! \brief Vector which stores the target geometry. */ + CGeometry**** const Geometry; /*! \brief Vector which stores n zones of geometry. */ + CGeometry* const donor_geometry; /*! \brief Vector which stores the donor geometry. */ + CGeometry* const target_geometry; /*! \brief Vector which stores the target geometry. */ /*! - * \brief Constructor of the class. - */ - CInterpolator(void); - - /*! - * \brief Constructor of the class. + * \brief Constructor of the class, protected as it does not make sense to instantiate base class. * \param[in] geometry - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. * \param[in] iZone - index of the donor zone @@ -117,25 +110,39 @@ class CInterpolator { */ CInterpolator(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); +public: + /*! + * \brief No default construction allowed. + */ + CInterpolator(void) = delete; + /*! - * \brief Destructor of the class. + * \brief Destructor of the class, nothing is deleted, derived classes need to manage the MPI buffers. + */ + virtual ~CInterpolator(void) = default; + + /*! + * \brief Set up transfer matrix defining relation between two meshes + * \note Main method that derived classes should implement. + * \param[in] config - Definition of the particular problem. */ - virtual ~CInterpolator(void); + inline virtual void Set_TransferCoeff(CConfig **config) {} +protected: /*! * \brief Find the index of the interface marker shared by that zone * \param[in] config - Definition of the particular problem. * \param[in] val_marker_interface - Interface tag. */ - int Find_InterfaceMarker(CConfig *config, unsigned short val_marker_interface); + int Find_InterfaceMarker(const CConfig *config, unsigned short val_marker_interface) const; /*! - * \brief Check whether the interface should be processed or not + * \brief Check whether an interface should be processed or not, i.e. if it is part of the zones. * \param[in] val_markDonor - Marker tag from donor zone. * \param[in] val_markTarget - Marker tag from target zone. */ - bool CheckInterfaceBoundary(int val_markDonor, int val_markTarget); - + bool CheckInterfaceBoundary(int val_markDonor, int val_markTarget) const; + /*! * \brief Recontstruct the boundary connectivity from parallel partitioning and broadcasts it to all threads * \param[in] val_zone - index of the zone @@ -166,12 +173,6 @@ class CInterpolator { return sqrt(PointsSquareDistance(nDim, point_i, point_j)); } - /*! - * \brief Set up transfer matrix defining relation between two meshes - * \param[in] config - Definition of the particular problem. - */ - virtual void Set_TransferCoeff(CConfig **config); - /*! * \brief Determine array sizes used to collect and send coordinate and global point * information. @@ -200,11 +201,6 @@ class CInterpolator { */ class CNearestNeighbor final : public CInterpolator { public: - /*! - * \brief Constructor of the class. - */ - CNearestNeighbor(void); - /*! * \brief Constructor of the class. * \param[in] geometry - Geometrical definition of the problem. @@ -225,9 +221,8 @@ class CNearestNeighbor final : public CInterpolator { /*! * \brief Isoparametric interpolation */ -class CIsoparametric : public CInterpolator { +class CIsoparametric final : public CInterpolator { public: - /*! * \brief Constructor of the class. * \param[in] geometry - Geometrical definition of the problem. @@ -237,17 +232,13 @@ class CIsoparametric : public CInterpolator { */ CIsoparametric(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - /*! - * \brief Destructor of the class. - */ - ~CIsoparametric(void); - /*! * \brief Set up transfer matrix defining relation between two meshes * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(CConfig **config); + void Set_TransferCoeff(CConfig **config) override; +private: /*! * \brief Calculate the isoparametric representation of point iVertex in marker iZone_0 by nodes of element donor_elem in marker jMarker of zone iZone_1. * \param[in] iVertex - vertex index of the point being interpolated. @@ -258,7 +249,7 @@ class CIsoparametric : public CInterpolator { * \param[in] xj - point projected onto the plane of the donor element. * \param[out] isoparams - isoparametric coefficients. Must be allocated to size nNodes ahead of time. (size> nDonors) * - * If the problem is 2D, the 'face' projected onto is actually an edge; the local index + * \note If the problem is 2D, the 'face' projected onto is actually an edge; the local index * of the edge is then stored in iFace, and the global index of the node (from which the edge * is referenced) */ @@ -270,40 +261,31 @@ class CIsoparametric : public CInterpolator { * \brief Mirror interpolation: copy point linking and coefficient values from the opposing mesh * Assumes that the oppoosing mesh has already run interpolation. (otherwise this will result in empty/trivial interpolation) */ -class CMirror : public CInterpolator { +class CMirror final : public CInterpolator { public: - /*! * \brief Constructor of the class. + * \note Data is set in geometry[targetZone]. * \param[in] geometry_container * \param[in] config - config container * \param[in] iZone - First zone * \param[in] jZone - Second zone - * - * Data is set in geometry[targetZone] - * */ CMirror(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - /*! - * \brief Destructor of the class. - */ - ~CMirror(void); - /*! * \brief Set up transfer matrix defining relation between two meshes * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(CConfig **config); - + void Set_TransferCoeff(CConfig **config) override; + }; /*! * \brief Sliding mesh approach */ -class CSlidingMesh : public CInterpolator { +class CSlidingMesh final : public CInterpolator { public: - /*! * \brief Constructor of the class. * \param[in] geometry - Geometrical definition of the problem. @@ -313,17 +295,13 @@ class CSlidingMesh : public CInterpolator { */ CSlidingMesh(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - /*! - * \brief Destructor of the class. - */ - ~CSlidingMesh(void); - /*! * \brief Set up transfer matrix defining relation between two meshes * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(CConfig **config); - + void Set_TransferCoeff(CConfig **config) override; + +private: /*! * \brief For 3-Dimensional grids, build the dual surface element * \param[in] map - array containing the index of the boundary points connected to the node @@ -333,7 +311,8 @@ class CSlidingMesh : public CInterpolator { * \param[in] centralNode - label of the vertex around which the dual surface element is built * \param[in] element - double array where element node coordinates will be stored */ - int Build_3D_surface_element(unsigned long *map, unsigned long *startIndex, unsigned long* nNeighbor, su2double *coord, unsigned long centralNode, su2double** element); + int Build_3D_surface_element(unsigned long *map, unsigned long *startIndex, unsigned long* nNeighbor, + su2double *coord, unsigned long centralNode, su2double** element); /*! * \brief For 2-Dimensional grids, compute intersection length of two segments projected along a given direction @@ -387,6 +366,7 @@ class CSlidingMesh : public CInterpolator { * \param[in] T3 - third point of triangle T */ bool CheckPointInsideTriangle(su2double* Point, su2double* T1, su2double* T2, su2double* T3); + }; /*! @@ -394,11 +374,6 @@ class CSlidingMesh : public CInterpolator { */ class CRadialBasisFunction final : public CInterpolator { public: - /*! - * \brief Constructor of the class. - */ - CRadialBasisFunction(void); - /*! * \brief Constructor of the class. * \param[in] geometry - Geometrical definition of the problem. diff --git a/Common/src/interpolation_structure.cpp b/Common/src/interpolation_structure.cpp index 762bcb38644c..04f210167e2f 100644 --- a/Common/src/interpolation_structure.cpp +++ b/Common/src/interpolation_structure.cpp @@ -41,81 +41,23 @@ extern "C" void dsymm_(char*, char*, int*, int*, passivedouble*, passivedouble*, passivedouble*, int*, passivedouble*, passivedouble*, int*); #endif -CInterpolator::CInterpolator(void) { - - size = SU2_MPI::GetSize(); - rank = SU2_MPI::GetRank(); - - nZone = 0; - Geometry = NULL; - - donor_geometry = NULL; - target_geometry = NULL; - - donorZone = 0; - targetZone = 0; - - Buffer_Receive_nVertex_Donor = NULL; - Buffer_Receive_nFace_Donor = NULL; - Buffer_Receive_nFaceNodes_Donor = NULL; - Buffer_Send_nVertex_Donor = NULL; - Buffer_Send_nFace_Donor = NULL; - Buffer_Send_nFaceNodes_Donor = NULL; - Buffer_Receive_GlobalPoint = NULL; - Buffer_Send_GlobalPoint = NULL; - Buffer_Send_FaceIndex = NULL; - Buffer_Receive_FaceIndex = NULL; - Buffer_Send_FaceNodes = NULL; - Buffer_Receive_FaceNodes = NULL; - Buffer_Send_FaceProc = NULL; - Buffer_Receive_FaceProc = NULL; - - Buffer_Send_Coord = NULL; - Buffer_Send_Normal = NULL; - Buffer_Receive_Coord = NULL; - Buffer_Receive_Normal = NULL; - - Receive_GlobalPoint = NULL; - Buffer_Receive_nLinkedNodes = NULL; - Buffer_Receive_LinkedNodes = NULL; - Buffer_Receive_StartLinkedNodes = NULL; - Buffer_Receive_Proc = NULL; - -} - -CInterpolator::~CInterpolator(void) { - - //if (Buffer_Receive_nVertex_Donor!= NULL) delete[] Buffer_Receive_nVertex_Donor; -} - +CInterpolator::CInterpolator(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : + rank(SU2_MPI::GetRank()), + size(SU2_MPI::GetSize()), + donorZone(iZone), + targetZone(jZone), + Geometry(geometry_container), + donor_geometry(geometry_container[iZone][INST_0][MESH_0]), + target_geometry(geometry_container[jZone][INST_0][MESH_0]) { -CInterpolator::CInterpolator(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) { - - size = SU2_MPI::GetSize(); - rank = SU2_MPI::GetRank(); - - /* Store pointers*/ - Geometry = geometry_container; - - donorZone = iZone; - targetZone = jZone; - - donor_geometry = geometry_container[donorZone][INST_0][MESH_0]; - target_geometry = geometry_container[targetZone][INST_0][MESH_0]; - - /*--- Initialize transfer coefficients between the zones ---*/ - /* Since this is a virtual function, call it in the child class constructor */ - //Set_TransferCoeff(targetZone,donorZone,config); - /*--- Initialize transfer coefficients between the zones ---*/ - //Set_TransferCoeff(Zones,config); - - //Buffer_Receive_nVertex_Donor = NULL; + /*--- Initialize transfer coefficients between the zones. ---*/ + Set_TransferCoeff(config); } -inline void CInterpolator::Set_TransferCoeff(CConfig **config) { } +void CInterpolator::Determine_ArraySize(bool faces, int markDonor, int markTarget, + unsigned long nVertexDonor, unsigned short nDim) { -void CInterpolator::Determine_ArraySize(bool faces, int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim) { unsigned long nLocalVertex_Donor = 0, nLocalFaceNodes_Donor=0, nLocalFace_Donor=0; unsigned long iVertex, iPointDonor = 0; /* Only needed if face data is also collected */ @@ -127,49 +69,51 @@ void CInterpolator::Determine_ArraySize(bool faces, int markDonor, int markTarge for (iVertex = 0; iVertex < nVertexDonor; iVertex++) { iPointDonor = donor_geometry->vertex[markDonor][iVertex]->GetNode(); - if (donor_geometry->node[iPointDonor]->GetDomain()) { - nLocalVertex_Donor++; - if (faces) { - /*--- On Donor geometry also communicate face info ---*/ - if (nDim==3) { - for (jElem=0; jElemnode[iPointDonor]->GetnElem(); jElem++) { - donor_elem = donor_geometry->node[iPointDonor]->GetElem(jElem); - nFaces = donor_geometry->elem[donor_elem]->GetnFaces(); - for (iFace=0; iFaceelem[donor_elem]->GetnNodesFace(iFace); - for (iDonor=0; iDonorelem[donor_elem]->GetFaces(iFace, iDonor); - jPoint = donor_geometry->elem[donor_elem]->GetNode(inode); - face_on_marker = (face_on_marker && (donor_geometry->node[jPoint]->GetVertex(markDonor) !=-1)); - } - if (face_on_marker ) { - nLocalFace_Donor++; - nLocalFaceNodes_Donor+=nNodes; - } - } + + if (!donor_geometry->node[iPointDonor]->GetDomain()) continue; + + nLocalVertex_Donor++; + + if (!faces) continue; + + /*--- On Donor geometry also communicate face info ---*/ + if (nDim==3) { + for (jElem=0; jElemnode[iPointDonor]->GetnElem(); jElem++) { + donor_elem = donor_geometry->node[iPointDonor]->GetElem(jElem); + nFaces = donor_geometry->elem[donor_elem]->GetnFaces(); + for (iFace=0; iFaceelem[donor_elem]->GetnNodesFace(iFace); + for (iDonor=0; iDonorelem[donor_elem]->GetFaces(iFace, iDonor); + jPoint = donor_geometry->elem[donor_elem]->GetNode(inode); + face_on_marker = (face_on_marker && (donor_geometry->node[jPoint]->GetVertex(markDonor) !=-1)); } - } - else { - /*--- in 2D we use the edges ---*/ - nNodes=2; - nFaces = donor_geometry->node[iPointDonor]->GetnPoint(); - for (iFace=0; iFacenode[iPointDonor]->GetEdge(iFace); - jPoint = donor_geometry->edge[inode]->GetNode(iDonor); - face_on_marker = (face_on_marker && (donor_geometry->node[jPoint]->GetVertex(markDonor) !=-1)); - } - if (face_on_marker ) { - nLocalFace_Donor++; - nLocalFaceNodes_Donor+=nNodes; - } + if (face_on_marker ) { + nLocalFace_Donor++; + nLocalFaceNodes_Donor+=nNodes; } } } } + else { + /*--- in 2D we use the edges ---*/ + nNodes=2; + nFaces = donor_geometry->node[iPointDonor]->GetnPoint(); + for (iFace=0; iFacenode[iPointDonor]->GetEdge(iFace); + jPoint = donor_geometry->edge[inode]->GetNode(iDonor); + face_on_marker = (face_on_marker && (donor_geometry->node[jPoint]->GetVertex(markDonor) !=-1)); + } + if (face_on_marker ) { + nLocalFace_Donor++; + nLocalFaceNodes_Donor+=nNodes; + } + } + } } Buffer_Send_nVertex_Donor[0] = nLocalVertex_Donor; @@ -180,34 +124,33 @@ void CInterpolator::Determine_ArraySize(bool faces, int markDonor, int markTarge /*--- Send Interface vertex information --*/ SU2_MPI::Allreduce(&nLocalVertex_Donor, &MaxLocalVertex_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nVertex_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nVertex_Donor, 1, MPI_UNSIGNED_LONG, + Buffer_Receive_nVertex_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); if (faces) { SU2_MPI::Allreduce(&nLocalFace_Donor, &nGlobalFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); SU2_MPI::Allreduce(&nLocalFace_Donor, &MaxFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &nGlobalFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &MaxFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFace_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nFace_Donor, 1, MPI_UNSIGNED_LONG, + Buffer_Receive_nFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, + Buffer_Receive_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); MaxFace_Donor++; } } -void CInterpolator::Collect_VertexInfo(bool faces, int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim) -{ +void CInterpolator::Collect_VertexInfo(bool faces, int markDonor, int markTarget, + unsigned long nVertexDonor, unsigned short nDim) { + unsigned long iVertex, iPointDonor = 0, iVertexDonor, nBuffer_Coord, nBuffer_Point, nLocalVertex_Donor; unsigned short iDim; - /* Only needed if face data is also collected */ - const su2double *Normal = nullptr; - - for (iVertex = 0; iVertex < MaxLocalVertex_Donor; iVertex++) { - Buffer_Send_GlobalPoint[iVertex] = -1; - for (iDim = 0; iDim < nDim; iDim++) { - Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; - if (faces) - Buffer_Send_Normal[iVertex*nDim+iDim] = 0.0; - } - } + for (iVertex = 0; iVertex < MaxLocalVertex_Donor; iVertex++) Buffer_Send_GlobalPoint[iVertex] = -1; + + for (iVertex = 0; iVertex < MaxLocalVertex_Donor*nDim; iVertex++) Buffer_Send_Coord[iVertex] = 0.0; + + if(faces) + for (iVertex = 0; iVertex < MaxLocalVertex_Donor*nDim; iVertex++) Buffer_Send_Normal[iVertex] = 0.0; /*--- Copy coordinates and point to the auxiliar vector --*/ nLocalVertex_Donor = 0; @@ -220,7 +163,7 @@ void CInterpolator::Collect_VertexInfo(bool faces, int markDonor, int markTarget Buffer_Send_Coord[nLocalVertex_Donor*nDim+iDim] = donor_geometry->node[iPointDonor]->GetCoord(iDim); if (faces) { - Normal = donor_geometry->vertex[markDonor][iVertexDonor]->GetNormal(); + const su2double* Normal = donor_geometry->vertex[markDonor][iVertexDonor]->GetNormal(); for (iDim = 0; iDim < nDim; iDim++) Buffer_Send_Normal[nLocalVertex_Donor*nDim+iDim] = Normal[iDim]; } @@ -230,32 +173,25 @@ void CInterpolator::Collect_VertexInfo(bool faces, int markDonor, int markTarget nBuffer_Coord = MaxLocalVertex_Donor*nDim; nBuffer_Point = MaxLocalVertex_Donor; - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_GlobalPoint, nBuffer_Point, MPI_LONG, Buffer_Receive_GlobalPoint, nBuffer_Point, MPI_LONG, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, + Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_GlobalPoint, nBuffer_Point, MPI_LONG, + Buffer_Receive_GlobalPoint, nBuffer_Point, MPI_LONG, MPI_COMM_WORLD); if (faces) { - SU2_MPI::Allgather(Buffer_Send_Normal, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Normal, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_Normal, nBuffer_Coord, MPI_DOUBLE, + Buffer_Receive_Normal, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); } } -int CInterpolator::Find_InterfaceMarker(CConfig *config, unsigned short val_marker_interface) { - - unsigned short nMarker = config->GetnMarker_All(); - unsigned short iMarker; - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - /*--- If the tag GetMarker_All_ZoneInterface(iMarker) equals the index we are looping at ---*/ - if (config->GetMarker_All_ZoneInterface(iMarker) == val_marker_interface ) { +int CInterpolator::Find_InterfaceMarker(const CConfig *config, unsigned short val_marker_interface) const { - /*--- We have identified the identifier for the interface marker ---*/ - return iMarker; - } + for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + /*--- If the tag GetMarker_All_ZoneInterface(iMarker) equals the interface we are looking for. ---*/ + if (config->GetMarker_All_ZoneInterface(iMarker) == val_marker_interface) return iMarker; } - return -1; } - void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ CGeometry *geom = Geometry[val_zone][INST_0][MESH_0]; @@ -364,13 +300,8 @@ void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ /*--- Reconstruct boundary by gathering data from all ranks ---*/ -#ifdef HAVE_MPI SU2_MPI::Allreduce( &nLocalVertex, &nGlobalVertex, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); SU2_MPI::Allreduce(&nLocalLinkedNodes, &nGlobalLinkedNodes, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#else - nGlobalVertex = nLocalVertex; - nGlobalLinkedNodes = nLocalLinkedNodes; -#endif Buffer_Receive_Coord = new su2double [ nGlobalVertex * nDim ]; Buffer_Receive_GlobalPoint = new long[ nGlobalVertex ]; @@ -472,86 +403,34 @@ void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ } } -#ifdef HAVE_MPI - SU2_MPI::Bcast( Buffer_Receive_Coord, nGlobalVertex * nDim, MPI_DOUBLE, 0, MPI_COMM_WORLD); - SU2_MPI::Bcast(Buffer_Receive_GlobalPoint, nGlobalVertex, MPI_LONG, 0, MPI_COMM_WORLD); - SU2_MPI::Bcast( Buffer_Receive_Proc, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD ); - - SU2_MPI::Bcast( Buffer_Receive_nLinkedNodes, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); - SU2_MPI::Bcast(Buffer_Receive_StartLinkedNodes, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); - SU2_MPI::Bcast( Buffer_Receive_LinkedNodes, nGlobalLinkedNodes, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); -#endif - - if( Buffer_Send_Coord != NULL) {delete [] Buffer_Send_Coord; Buffer_Send_Coord = NULL;} - if( Buffer_Send_GlobalPoint != NULL) {delete [] Buffer_Send_GlobalPoint; Buffer_Send_GlobalPoint = NULL;} - if( Buffer_Send_LinkedNodes != NULL) {delete [] Buffer_Send_LinkedNodes; Buffer_Send_LinkedNodes = NULL;} - if( Buffer_Send_nLinkedNodes != NULL) {delete [] Buffer_Send_nLinkedNodes; Buffer_Send_nLinkedNodes = NULL;} - if( Buffer_Send_StartLinkedNodes != NULL) {delete [] Buffer_Send_StartLinkedNodes; Buffer_Send_StartLinkedNodes = NULL;} -} - -bool CInterpolator::CheckInterfaceBoundary(int markDonor, int markTarget){ - - int Donor_check, Target_check; - - #ifdef HAVE_MPI - - int *Buffer_Recv_mark = NULL; - int iRank, nProcessor = size; - - if (rank == MASTER_NODE) - Buffer_Recv_mark = new int[nProcessor]; - - Donor_check = -1; - Target_check = -1; - - /*--- We gather a vector in MASTER_NODE to determine whether the boundary is not on the processor because of the partition or because the zone does not include it ---*/ - - SU2_MPI::Gather(&markDonor , 1, MPI_INT, Buffer_Recv_mark, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) - for (iRank = 0; iRank < nProcessor; iRank++) - if( Buffer_Recv_mark[iRank] != -1 ){ - Donor_check = Buffer_Recv_mark[iRank]; - break; - } - - SU2_MPI::Bcast(&Donor_check , 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Bcast(Buffer_Receive_GlobalPoint, nGlobalVertex, MPI_LONG, 0, MPI_COMM_WORLD); + SU2_MPI::Bcast(Buffer_Receive_Coord, nGlobalVertex*nDim, MPI_DOUBLE, 0, MPI_COMM_WORLD); + SU2_MPI::Bcast(Buffer_Receive_Proc, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); + SU2_MPI::Bcast(Buffer_Receive_nLinkedNodes, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); + SU2_MPI::Bcast(Buffer_Receive_StartLinkedNodes, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); + SU2_MPI::Bcast(Buffer_Receive_LinkedNodes, nGlobalLinkedNodes, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); - SU2_MPI::Gather(&markTarget, 1, MPI_INT, Buffer_Recv_mark, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); + delete [] Buffer_Send_Coord; Buffer_Send_Coord = NULL; + delete [] Buffer_Send_GlobalPoint; Buffer_Send_GlobalPoint = NULL; + delete [] Buffer_Send_LinkedNodes; Buffer_Send_LinkedNodes = NULL; + delete [] Buffer_Send_nLinkedNodes; Buffer_Send_nLinkedNodes = NULL; + delete [] Buffer_Send_StartLinkedNodes; Buffer_Send_StartLinkedNodes = NULL; - if (rank == MASTER_NODE) - for (iRank = 0; iRank < nProcessor; iRank++) - if( Buffer_Recv_mark[iRank] != -1 ){ - Target_check = Buffer_Recv_mark[iRank]; - break; - } - - - SU2_MPI::Bcast(&Target_check, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) - delete [] Buffer_Recv_mark; +} -#else - Donor_check = markDonor; - Target_check = markTarget; -#endif +bool CInterpolator::CheckInterfaceBoundary(int markDonor, int markTarget) const { - if(Target_check == -1 || Donor_check == -1) - return false; - else - return true; + /*--- Determine whether the boundary is not on the rank because of + * the partition or because it is not part of the zone. ---*/ + int donorCheck = -1, targetCheck = -1; + SU2_MPI::Allreduce(&markDonor, &donorCheck, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&markTarget, &targetCheck, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); + return (donorCheck != -1) && (targetCheck != -1); } -CNearestNeighbor::CNearestNeighbor(void): CInterpolator() { } - CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, - unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { - - /*--- Initialize transfer coefficients between the zones. ---*/ - Set_TransferCoeff(config); -} + unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { } void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { @@ -656,18 +535,11 @@ void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { -CIsoparametric::CIsoparametric(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { - - /*--- Initialize transfer coefficients between the zones ---*/ - Set_TransferCoeff(config); - - /*--- For fluid-structure interaction data interpolated with have nDim dimensions ---*/ - // InitializeData(Zones,nDim); -} - -CIsoparametric::~CIsoparametric() {} +CIsoparametric::CIsoparametric(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, + unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { } void CIsoparametric::Set_TransferCoeff(CConfig **config) { + unsigned long iVertex, jVertex; unsigned long dPoint, inode, jElem, nElem; unsigned short iDim, iDonor=0, iFace; @@ -719,14 +591,13 @@ void CIsoparametric::Set_TransferCoeff(CConfig **config) { */ /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); /*--- On the target side: find the tag of the boundary sharing the interface ---*/ markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ - if( !CheckInterfaceBoundary(markDonor, markTarget) ) - continue; + if(!CheckInterfaceBoundary(markDonor, markTarget)) continue; if(markDonor != -1) nVertexDonor = donor_geometry->GetnVertex( markDonor ); @@ -863,118 +734,112 @@ void CIsoparametric::Set_TransferCoeff(CConfig **config) { } //Buffer_Send_FaceIndex[nLocalFace_Donor+1] = MaxFaceNodes_Donor*rank+nLocalFaceNodes_Donor; -#ifdef HAVE_MPI - SU2_MPI::Allgather(Buffer_Send_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, Buffer_Receive_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_FaceProc, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, Buffer_Receive_FaceProc, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, Buffer_Receive_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#else - for (iFace=0; iFacevertex[markTarget][iVertex]->GetNode(); - if (target_geometry->node[Point_Target]->GetDomain()) { + if (!target_geometry->node[Point_Target]->GetDomain()) continue; - Coord_i = target_geometry->node[Point_Target]->GetCoord(); - /*---Loop over the faces previously communicated/stored ---*/ - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + Coord_i = target_geometry->node[Point_Target]->GetCoord(); + /*---Loop over the faces previously communicated/stored ---*/ + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - nFaces = (unsigned int)Buffer_Receive_nFace_Donor[iProcessor]; + nFaces = (unsigned int)Buffer_Receive_nFace_Donor[iProcessor]; - for (iFace = 0; iFace< nFaces; iFace++) { - /*--- ---*/ + for (iFace = 0; iFace< nFaces; iFace++) { + /*--- ---*/ - nNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1] - - (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; + nNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1] - + (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; - su2double *X = new su2double[nNodes*(nDim+1)]; - faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face - for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetDonorElem(donor_elem); // in 2D is nearest neighbor - target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nNodes); - for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetDonorElem(donor_elem); // in 2D is nearest neighbor + target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nNodes); + for (iDonor=0; iDonorvertex[markTarget][iVertex]->GetnDonorPoints(); - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); - - for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,storeGlobal[iDonor]); - //cout <vertex[markTarget][iVertex]->SetDonorCoeff(iDonor,storeCoeff[iDonor]); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); - } + /*--- Set the appropriate amount of memory and fill ---*/ + nNodes =target_geometry->vertex[markTarget][iVertex]->GetnDonorPoints(); + target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); + + for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,storeGlobal[iDonor]); + //cout <vertex[markTarget][iVertex]->SetDonorCoeff(iDonor,storeCoeff[iDonor]); + target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); } + } delete[] Buffer_Send_nVertex_Donor; @@ -1008,7 +873,7 @@ void CIsoparametric::Set_TransferCoeff(CConfig **config) { } void CIsoparametric::Isoparameters(unsigned short nDim, unsigned short nDonor, - su2double *X, su2double *xj, su2double *isoparams) { + su2double *X, su2double *xj, su2double *isoparams) { short iDonor,iDim,k; // indices su2double tmp, tmp2; @@ -1191,7 +1056,7 @@ void CIsoparametric::Isoparameters(unsigned short nDim, unsigned short nDonor, delete [] Q; delete [] R; delete [] A; - if (A2 != NULL) delete [] A2; + delete [] A2; delete [] x2; delete [] test; @@ -1199,16 +1064,8 @@ void CIsoparametric::Isoparameters(unsigned short nDim, unsigned short nDonor, } - -/* Mirror Interpolator */ -CMirror::CMirror(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { - - /*--- Initialize transfer coefficients between the zones ---*/ - Set_TransferCoeff(config); - -} - -CMirror::~CMirror() {} +CMirror::CMirror(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, + unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { } void CMirror::Set_TransferCoeff(CConfig **config) { unsigned long iVertex, jVertex; @@ -1241,9 +1098,9 @@ void CMirror::Set_TransferCoeff(CConfig **config) { /*--- For the number of markers on the interface... ---*/ for (iMarkerInt=1; iMarkerInt <= nMarkerInt; iMarkerInt++) { /*--- Procedure: - * -Loop through vertices of the aero grid - * -Find nearest element and allocate enough space in the aero grid donor point info - * -set the transfer coefficient values + * - Loop through vertices of the aero grid + * - Find nearest element and allocate enough space in the aero grid donor point info + * - Set the transfer coefficient values */ /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ @@ -1253,8 +1110,7 @@ void CMirror::Set_TransferCoeff(CConfig **config) { markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ - if( !CheckInterfaceBoundary(markDonor, markTarget) ) - continue; + if(!CheckInterfaceBoundary(markDonor, markTarget)) continue; if(markDonor != -1) nVertexDonor = donor_geometry->GetnVertex( markDonor ); @@ -1348,21 +1204,15 @@ void CMirror::Set_TransferCoeff(CConfig **config) { } } -#ifdef HAVE_MPI - SU2_MPI::Allgather(Buffer_Send_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, Buffer_Receive_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_GlobalPoint, MaxFaceNodes_Donor, MPI_LONG,Buffer_Receive_GlobalPoint, MaxFaceNodes_Donor, MPI_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_Coeff, MaxFaceNodes_Donor, MPI_DOUBLE,Buffer_Receive_Coeff, MaxFaceNodes_Donor, MPI_DOUBLE, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, Buffer_Receive_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#else - for (iFace=0; iFaceGetnVertex( markTarget ); @@ -1816,8 +1657,8 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config){ target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ - target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff( iDonor, Coeff_Vect[iDonor]); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorPoint( iDonor, Donor_GlobalPoint[ Donor_Vect[iDonor] ]); + target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor, Coeff_Vect[iDonor]); + target_geometry->vertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor, Donor_GlobalPoint[Donor_Vect[iDonor]]); target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); } } @@ -1842,266 +1683,264 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config){ target_iPoint = target_geometry->vertex[markTarget][iVertex]->GetNode(); - if (target_geometry->node[target_iPoint]->GetDomain()){ + if (!target_geometry->node[target_iPoint]->GetDomain()) continue; - Coord_i = target_geometry->node[target_iPoint]->GetCoord(); + Coord_i = target_geometry->node[target_iPoint]->GetCoord(); - target_geometry->vertex[markTarget][iVertex]->GetNormal(Normal); - - /*--- The value of Area computed here includes also portion of boundary belonging to different marker ---*/ - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - - for (iDim = 0; iDim < nDim; iDim++) - Normal[iDim] /= Area; + target_geometry->vertex[markTarget][iVertex]->GetNormal(Normal); - for (iDim = 0; iDim < nDim; iDim++) - Coord_i[iDim] = target_geometry->node[target_iPoint]->GetCoord(iDim); - - long dPoint = target_geometry->node[target_iPoint]->GetGlobalIndex(); - for (target_iPoint = 0; target_iPoint < nGlobalVertex_Target; target_iPoint++){ - if( dPoint == Target_GlobalPoint[target_iPoint] ) - break; - } - - /*--- Build local surface dual mesh for target element ---*/ + /*--- The value of Area computed here includes also portion of boundary belonging to different marker ---*/ + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + + for (iDim = 0; iDim < nDim; iDim++) + Normal[iDim] /= Area; + + for (iDim = 0; iDim < nDim; iDim++) + Coord_i[iDim] = target_geometry->node[target_iPoint]->GetCoord(iDim); - nEdges_target = Target_nLinkedNodes[target_iPoint]; + long dPoint = target_geometry->node[target_iPoint]->GetGlobalIndex(); + for (target_iPoint = 0; target_iPoint < nGlobalVertex_Target; target_iPoint++){ + if( dPoint == Target_GlobalPoint[target_iPoint] ) + break; + } + + /*--- Build local surface dual mesh for target element ---*/ + + nEdges_target = Target_nLinkedNodes[target_iPoint]; - nNode_target = 2*(nEdges_target + 1); + nNode_target = 2*(nEdges_target + 1); + + target_element = new su2double*[nNode_target]; + for (ii = 0; ii < nNode_target; ii++) + target_element[ii] = new su2double[nDim]; - target_element = new su2double*[nNode_target]; - for (ii = 0; ii < nNode_target; ii++) - target_element[ii] = new su2double[nDim]; - - nNode_target = Build_3D_surface_element(Target_LinkedNodes, Target_StartLinkedNodes, Target_nLinkedNodes, TargetPoint_Coord, target_iPoint, target_element); + nNode_target = Build_3D_surface_element(Target_LinkedNodes, Target_StartLinkedNodes, Target_nLinkedNodes, TargetPoint_Coord, target_iPoint, target_element); - /*--- Brute force to find the closest donor_node ---*/ + /*--- Brute force to find the closest donor_node ---*/ - mindist = 1E6; - donor_StartIndex = 0; - - for (donor_iPoint = 0; donor_iPoint < nGlobalVertex_Donor; donor_iPoint++) { - - Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; + mindist = 1E6; + donor_StartIndex = 0; - dist = PointsDistance(nDim, Coord_i, Coord_j); + for (donor_iPoint = 0; donor_iPoint < nGlobalVertex_Donor; donor_iPoint++) { + + Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; - if (dist < mindist) { - mindist = dist; - donor_StartIndex = donor_iPoint; - } + dist = PointsDistance(nDim, Coord_i, Coord_j); - if (dist == 0.0){ - donor_StartIndex = donor_iPoint; - break; - } + if (dist < mindist) { + mindist = dist; + donor_StartIndex = donor_iPoint; } - - donor_iPoint = donor_StartIndex; - nEdges_donor = Donor_nLinkedNodes[donor_iPoint]; + if (dist == 0.0){ + donor_StartIndex = donor_iPoint; + break; + } + } + + donor_iPoint = donor_StartIndex; - donor_element = new su2double*[ 2*nEdges_donor + 2 ]; - for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - donor_element[ii] = new su2double[nDim]; + nEdges_donor = Donor_nLinkedNodes[donor_iPoint]; - nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); + donor_element = new su2double*[ 2*nEdges_donor + 2 ]; + for (ii = 0; ii < 2*nEdges_donor + 2; ii++) + donor_element[ii] = new su2double[nDim]; - Area = 0; - for (ii = 1; ii < nNode_target-1; ii++){ - for (jj = 1; jj < nNode_donor-1; jj++){ - Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal); - //cout << Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal) << endl; - } + nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); + + Area = 0; + for (ii = 1; ii < nNode_target-1; ii++){ + for (jj = 1; jj < nNode_donor-1; jj++){ + Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal); + //cout << Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal) << endl; } + } - for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - delete [] donor_element[ii]; - delete [] donor_element; + for (ii = 0; ii < 2*nEdges_donor + 2; ii++) + delete [] donor_element[ii]; + delete [] donor_element; - nDonorPoints = 1; + nDonorPoints = 1; - /*--- In case the element intersect the target cell update the auxiliary communication data structure ---*/ + /*--- In case the element intersect the target cell update the auxiliary communication data structure ---*/ - Coeff_Vect = new su2double[ nDonorPoints ]; - Donor_Vect = new unsigned long[ nDonorPoints ]; - storeProc = new unsigned long[ nDonorPoints ]; + Coeff_Vect = new su2double[ nDonorPoints ]; + Donor_Vect = new unsigned long[ nDonorPoints ]; + storeProc = new unsigned long[ nDonorPoints ]; - Coeff_Vect[0] = Area; - Donor_Vect[0] = donor_iPoint; - storeProc[0] = Donor_Proc[donor_iPoint]; + Coeff_Vect[0] = Area; + Donor_Vect[0] = donor_iPoint; + storeProc[0] = Donor_Proc[donor_iPoint]; - alreadyVisitedDonor = new unsigned long[1]; + alreadyVisitedDonor = new unsigned long[1]; - alreadyVisitedDonor[0] = donor_iPoint; - nAlreadyVisited = 1; - StartVisited = 0; + alreadyVisitedDonor[0] = donor_iPoint; + nAlreadyVisited = 1; + StartVisited = 0; - Area_old = -1; - - while( Area > Area_old ){ + Area_old = -1; + + while( Area > Area_old ){ - /* - * - Starting from the closest donor_point, it expands the supermesh by a countour search pattern. - * - The closest donor element becomes the core, at each iteration a new layer of elements around the core is taken into account - */ + /* + * - Starting from the closest donor_point, it expands the supermesh by a countour search pattern. + * - The closest donor element becomes the core, at each iteration a new layer of elements around the core is taken into account + */ - Area_old = Area; + Area_old = Area; - ToVisit = NULL; - nToVisit = 0; + ToVisit = NULL; + nToVisit = 0; - for( iNodeVisited = StartVisited; iNodeVisited < nAlreadyVisited; iNodeVisited++ ){ + for( iNodeVisited = StartVisited; iNodeVisited < nAlreadyVisited; iNodeVisited++ ){ - vPoint = alreadyVisitedDonor[ iNodeVisited ]; - - nEdgeVisited = Donor_nLinkedNodes[vPoint]; - - for (iEdgeVisited = 0; iEdgeVisited < nEdgeVisited; iEdgeVisited++){ + vPoint = alreadyVisitedDonor[ iNodeVisited ]; + + nEdgeVisited = Donor_nLinkedNodes[vPoint]; - donor_iPoint = Donor_LinkedNodes[ Donor_StartLinkedNodes[vPoint] + iEdgeVisited]; + for (iEdgeVisited = 0; iEdgeVisited < nEdgeVisited; iEdgeVisited++){ - /*--- Check if the node to visit is already listed in the data structure to avoid double visits ---*/ + donor_iPoint = Donor_LinkedNodes[ Donor_StartLinkedNodes[vPoint] + iEdgeVisited]; - check = 0; + /*--- Check if the node to visit is already listed in the data structure to avoid double visits ---*/ - for( jj = 0; jj < nAlreadyVisited; jj++ ){ - if( donor_iPoint == alreadyVisitedDonor[jj] ){ - check = 1; - break; - } - } + check = 0; - if( check == 0 && ToVisit != NULL){ - for( jj = 0; jj < nToVisit; jj++ ) - if( donor_iPoint == ToVisit[jj] ){ - check = 1; - break; - } + for( jj = 0; jj < nAlreadyVisited; jj++ ){ + if( donor_iPoint == alreadyVisitedDonor[jj] ){ + check = 1; + break; } + } - if( check == 0 ){ - /*--- If the node was not already visited, visit it and list it into data structure ---*/ - - tmpVect = new unsigned long[ nToVisit + 1 ]; + if( check == 0 && ToVisit != NULL){ + for( jj = 0; jj < nToVisit; jj++ ) + if( donor_iPoint == ToVisit[jj] ){ + check = 1; + break; + } + } - for( jj = 0; jj < nToVisit; jj++ ) - tmpVect[jj] = ToVisit[jj]; - tmpVect[nToVisit] = donor_iPoint; + if( check == 0 ){ + /*--- If the node was not already visited, visit it and list it into data structure ---*/ - if( ToVisit != NULL ) - delete [] ToVisit; - - ToVisit = tmpVect; - tmpVect = NULL; + tmpVect = new unsigned long[ nToVisit + 1 ]; - nToVisit++; + for( jj = 0; jj < nToVisit; jj++ ) + tmpVect[jj] = ToVisit[jj]; + tmpVect[nToVisit] = donor_iPoint; - /*--- Find the value of the intersection area between the current donor element and the target element --- */ + if( ToVisit != NULL ) + delete [] ToVisit; + + ToVisit = tmpVect; + tmpVect = NULL; - nEdges_donor = Donor_nLinkedNodes[donor_iPoint]; + nToVisit++; - donor_element = new su2double*[ 2*nEdges_donor + 2 ]; - for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - donor_element[ii] = new su2double[nDim]; + /*--- Find the value of the intersection area between the current donor element and the target element --- */ - nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); + nEdges_donor = Donor_nLinkedNodes[donor_iPoint]; - tmp_Area = 0; - for (ii = 1; ii < nNode_target-1; ii++) - for (jj = 1; jj < nNode_donor-1; jj++) - tmp_Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal); + donor_element = new su2double*[ 2*nEdges_donor + 2 ]; + for (ii = 0; ii < 2*nEdges_donor + 2; ii++) + donor_element[ii] = new su2double[nDim]; - for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - delete [] donor_element[ii]; - delete [] donor_element; - - /*--- In case the element intersect the target cell update the auxiliary communication data structure ---*/ + nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); - tmp_Coeff_Vect = new su2double[ nDonorPoints + 1 ]; - tmp_Donor_Vect = new unsigned long[ nDonorPoints + 1 ]; - tmp_storeProc = new unsigned long[ nDonorPoints + 1 ]; - - for( iDonor = 0; iDonor < nDonorPoints; iDonor++){ - tmp_Donor_Vect[iDonor] = Donor_Vect[iDonor]; - tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; - tmp_storeProc[iDonor] = storeProc[iDonor]; - } - - tmp_Coeff_Vect[ nDonorPoints ] = tmp_Area; - tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; - tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; + tmp_Area = 0; + for (ii = 1; ii < nNode_target-1; ii++) + for (jj = 1; jj < nNode_donor-1; jj++) + tmp_Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal); - if (Donor_Vect != NULL) {delete [] Donor_Vect; } - if (Coeff_Vect != NULL) {delete [] Coeff_Vect; } - if (storeProc != NULL) {delete [] storeProc; } + for (ii = 0; ii < 2*nEdges_donor + 2; ii++) + delete [] donor_element[ii]; + delete [] donor_element; - Donor_Vect = tmp_Donor_Vect; - Coeff_Vect = tmp_Coeff_Vect; - storeProc = tmp_storeProc; + /*--- In case the element intersect the target cell update the auxiliary communication data structure ---*/ - tmp_Coeff_Vect = NULL; - tmp_Donor_Vect = NULL; - tmp_storeProc = NULL; + tmp_Coeff_Vect = new su2double[ nDonorPoints + 1 ]; + tmp_Donor_Vect = new unsigned long[ nDonorPoints + 1 ]; + tmp_storeProc = new unsigned long[ nDonorPoints + 1 ]; - nDonorPoints++; - - Area += tmp_Area; + for( iDonor = 0; iDonor < nDonorPoints; iDonor++){ + tmp_Donor_Vect[iDonor] = Donor_Vect[iDonor]; + tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; + tmp_storeProc[iDonor] = storeProc[iDonor]; } - } - } + + tmp_Coeff_Vect[ nDonorPoints ] = tmp_Area; + tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; + tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; + + if (Donor_Vect != NULL) {delete [] Donor_Vect; } + if (Coeff_Vect != NULL) {delete [] Coeff_Vect; } + if (storeProc != NULL) {delete [] storeProc; } + + Donor_Vect = tmp_Donor_Vect; + Coeff_Vect = tmp_Coeff_Vect; + storeProc = tmp_storeProc; + + tmp_Coeff_Vect = NULL; + tmp_Donor_Vect = NULL; + tmp_storeProc = NULL; - /*--- Update auxiliary data structure ---*/ + nDonorPoints++; - StartVisited = nAlreadyVisited; + Area += tmp_Area; + } + } + } - tmpVect = new unsigned long[ nAlreadyVisited + nToVisit ]; + /*--- Update auxiliary data structure ---*/ - for( jj = 0; jj < nAlreadyVisited; jj++ ) - tmpVect[jj] = alreadyVisitedDonor[jj]; - - for( jj = 0; jj < nToVisit; jj++ ) - tmpVect[ nAlreadyVisited + jj ] = ToVisit[jj]; + StartVisited = nAlreadyVisited; - if( alreadyVisitedDonor != NULL ) - delete [] alreadyVisitedDonor; + tmpVect = new unsigned long[ nAlreadyVisited + nToVisit ]; - alreadyVisitedDonor = tmpVect; + for( jj = 0; jj < nAlreadyVisited; jj++ ) + tmpVect[jj] = alreadyVisitedDonor[jj]; + + for( jj = 0; jj < nToVisit; jj++ ) + tmpVect[ nAlreadyVisited + jj ] = ToVisit[jj]; - nAlreadyVisited += nToVisit; + if( alreadyVisitedDonor != NULL ) + delete [] alreadyVisitedDonor; - delete [] ToVisit; - } + alreadyVisitedDonor = tmpVect; - delete [] alreadyVisitedDonor; - - /*--- Set the communication data structure and copy data from the auxiliary vectors ---*/ + nAlreadyVisited += nToVisit; - target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nDonorPoints); - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); + delete [] ToVisit; + } - for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ - target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor, Coeff_Vect[iDonor]/Area); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorPoint( iDonor, Donor_GlobalPoint[ Donor_Vect[iDonor] ] ); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); - //cout <vertex[markTarget][iVertex]->SetnDonorPoints(nDonorPoints); + target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); + + for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ + target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor, Coeff_Vect[iDonor]/Area); + target_geometry->vertex[markTarget][iVertex]->SetInterpDonorPoint( iDonor, Donor_GlobalPoint[ Donor_Vect[iDonor] ] ); + target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); + //cout <GetnVertex(mark_donor); From b6da6e930b8bc4cd8c5dd29df89c58379322371e Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Wed, 18 Mar 2020 11:50:30 +0000 Subject: [PATCH 10/79] strip trailing spaces --- Common/include/interpolation_structure.hpp | 24 +- Common/src/interpolation_structure.cpp | 376 ++++++++++----------- 2 files changed, 200 insertions(+), 200 deletions(-) diff --git a/Common/include/interpolation_structure.hpp b/Common/include/interpolation_structure.hpp index 3f8a01cba646..115e477ef46b 100644 --- a/Common/include/interpolation_structure.hpp +++ b/Common/include/interpolation_structure.hpp @@ -7,7 +7,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -83,13 +83,13 @@ class CInterpolator { *Buffer_Send_Normal, /*!< \brief Buffer to send normal vector values */ *Buffer_Receive_Coord, /*!< \brief Buffer to receive coordinate values*/ *Buffer_Receive_Normal; /*!< \brief Buffer to receive normal vector values*/ - + unsigned long *Receive_GlobalPoint, /*!< \brief Buffer to receive Global point indexes*/ *Buffer_Receive_nLinkedNodes, /*!< \brief Buffer to receive the number of edges connected to each node*/ *Buffer_Receive_LinkedNodes, /*!< \brief Buffer to receive the list of notes connected to the nodes through an edge*/ *Buffer_Receive_StartLinkedNodes, /*!< \brief Buffer to receive the index of the Receive_LinkedNodes buffer where corresponding list of linked nodes begins */ *Buffer_Receive_Proc; /*!< \brief Buffer to receive the thread that owns the node*/ - + unsigned long nGlobalVertex_Target, /*!< \brief Global number of vertex of the target boundary*/ nLocalVertex_Target, /*!< \brief Number of vertex of the target boundary owned by the thread*/ nGlobalVertex_Donor, /*!< \brief Global number of vertex of the donor boundary*/ @@ -140,7 +140,7 @@ class CInterpolator { * \brief Check whether an interface should be processed or not, i.e. if it is part of the zones. * \param[in] val_markDonor - Marker tag from donor zone. * \param[in] val_markTarget - Marker tag from target zone. - */ + */ bool CheckInterfaceBoundary(int val_markDonor, int val_markTarget) const; /*! @@ -305,15 +305,15 @@ class CSlidingMesh final : public CInterpolator { /*! * \brief For 3-Dimensional grids, build the dual surface element * \param[in] map - array containing the index of the boundary points connected to the node - * \param[in] startIndex - for each vertex specifies the corresponding index in the global array containing the indexes of all its neighbouring vertexes + * \param[in] startIndex - for each vertex specifies the corresponding index in the global array containing the indexes of all its neighbouring vertexes * \param[in] nNeighbour - for each vertex specifies the number of its neighbouring vertexes (on the boundary) * \param[in] coord - array containing the coordinates of all the boundary vertexes * \param[in] centralNode - label of the vertex around which the dual surface element is built * \param[in] element - double array where element node coordinates will be stored - */ + */ int Build_3D_surface_element(unsigned long *map, unsigned long *startIndex, unsigned long* nNeighbor, su2double *coord, unsigned long centralNode, su2double** element); - + /*! * \brief For 2-Dimensional grids, compute intersection length of two segments projected along a given direction * \param[in] A1 - first point of segment A @@ -323,7 +323,7 @@ class CSlidingMesh final : public CInterpolator { * \param[in] Direction - along which segments are projected */ su2double ComputeLineIntersectionLength(su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* Direction); - + /*! * \brief For 3-Dimensional grids, compute intersection area between two triangle projected on a given plane * \param[in] A1 - first point of triangle A @@ -335,7 +335,7 @@ class CSlidingMesh final : public CInterpolator { * \param[in] Direction - vector normal to projection plane */ su2double Compute_Triangle_Intersection(su2double* A1, su2double* A2, su2double* A3, su2double* B1, su2double* B2, su2double* B3, su2double* Direction); - + /*! * \brief For 3-Dimensional grids, compute intersection area between two triangle projected on a given plane * P1 from triangle P MUST be inside triangle Q, points order doesn't matter @@ -347,7 +347,7 @@ class CSlidingMesh final : public CInterpolator { * \param[in] Q3 - third point of triangle B */ su2double ComputeIntersectionArea( su2double* P1, su2double* P2, su2double* P3, su2double* Q1, su2double* Q2, su2double* Q3 ); - + /*! * \brief For 2-Dimensional grids, check whether, and compute, two lines are intersecting * \param[in] A1 - first defining first line @@ -357,7 +357,7 @@ class CSlidingMesh final : public CInterpolator { * \param[in] IntersectionPoint - Container for intersection coordinates */ void ComputeLineIntersectionPoint( su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* IntersectionPoint ); - + /*! * \brief For N-Dimensional grids, check whether a point is inside a triangle specified by 3 T points * \param[in] Point - query point @@ -482,7 +482,7 @@ class CSymmetricMatrix{ inline int GetSize() const { return sz; } inline passivedouble Get(int i, int j) const { return val_vec[IdxSym(i,j)]; } - + inline void Set(int i, int j, passivedouble val) { val_vec[IdxSym(i,j)] = val; } inline passivedouble& operator() (int i, int j) { return val_vec[IdxSym(i,j)]; } diff --git a/Common/src/interpolation_structure.cpp b/Common/src/interpolation_structure.cpp index 04f210167e2f..e88bcef4e1f4 100644 --- a/Common/src/interpolation_structure.cpp +++ b/Common/src/interpolation_structure.cpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -193,26 +193,26 @@ int CInterpolator::Find_InterfaceMarker(const CConfig *config, unsigned short va } void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ - + CGeometry *geom = Geometry[val_zone][INST_0][MESH_0]; - + unsigned long iVertex, jVertex, kVertex; - + unsigned long count, iTmp, *uptr, dPoint, EdgeIndex, jEdge, nEdges, nNodes, nVertex, iDim, nDim, iPoint; - + unsigned long nGlobalLinkedNodes, nLocalVertex, nLocalLinkedNodes; - + nDim = geom->GetnDim(); - + if( val_marker != -1 ) nVertex = geom->GetnVertex( val_marker ); else nVertex = 0; - - + + su2double *Buffer_Send_Coord = new su2double [ nVertex * nDim ]; unsigned long *Buffer_Send_GlobalPoint = new unsigned long [ nVertex ]; - + unsigned long *Buffer_Send_nLinkedNodes = new unsigned long [ nVertex ]; unsigned long *Buffer_Send_StartLinkedNodes = new unsigned long [ nVertex ]; unsigned long **Aux_Send_Map = new unsigned long*[ nVertex ]; @@ -221,29 +221,29 @@ void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ int nProcessor = size, iRank; unsigned long iTmp2, tmp_index, tmp_index_2; #endif - + /*--- Copy coordinates and point to the auxiliar vector ---*/ - + nGlobalVertex = 0; nLocalVertex = 0; nLocalLinkedNodes = 0; - + for (iVertex = 0; iVertex < nVertex; iVertex++) { - + Buffer_Send_nLinkedNodes[iVertex] = 0; Aux_Send_Map[iVertex] = NULL; - + iPoint = geom->vertex[val_marker][iVertex]->GetNode(); - + if (geom->node[iPoint]->GetDomain()) { Buffer_Send_GlobalPoint[nLocalVertex] = geom->node[iPoint]->GetGlobalIndex(); - + for (iDim = 0; iDim < nDim; iDim++) Buffer_Send_Coord[nLocalVertex*nDim+iDim] = geom->node[iPoint]->GetCoord(iDim); - + nNodes = 0; nEdges = geom->node[iPoint]->GetnPoint(); - + for (jEdge = 0; jEdge < nEdges; jEdge++){ EdgeIndex = geom->node[iPoint]->GetEdge(jEdge); @@ -264,23 +264,23 @@ void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ Aux_Send_Map[nLocalVertex] = new unsigned long[ nNodes ]; nNodes = 0; - for (jEdge = 0; jEdge < nEdges; jEdge++){ + for (jEdge = 0; jEdge < nEdges; jEdge++){ EdgeIndex = geom->node[iPoint]->GetEdge(jEdge); if( iPoint == geom->edge[EdgeIndex]->GetNode(0) ) dPoint = geom->edge[EdgeIndex]->GetNode(1); else - dPoint = geom->edge[EdgeIndex]->GetNode(0); + dPoint = geom->edge[EdgeIndex]->GetNode(0); - if ( geom->node[dPoint]->GetVertex(val_marker) != -1 ){ + if ( geom->node[dPoint]->GetVertex(val_marker) != -1 ){ Aux_Send_Map[nLocalVertex][nNodes] = geom->node[dPoint]->GetGlobalIndex(); nNodes++; } - } + } nLocalVertex++; } } - + unsigned long *Buffer_Send_LinkedNodes = new unsigned long [ nLocalLinkedNodes ]; nLocalLinkedNodes = 0; @@ -291,7 +291,7 @@ void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ nLocalLinkedNodes++; } } - + for (iVertex = 0; iVertex < nVertex; iVertex++){ if( Aux_Send_Map[iVertex] != NULL ) delete [] Aux_Send_Map[iVertex]; @@ -306,7 +306,7 @@ void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ Buffer_Receive_Coord = new su2double [ nGlobalVertex * nDim ]; Buffer_Receive_GlobalPoint = new long[ nGlobalVertex ]; Buffer_Receive_Proc = new unsigned long[ nGlobalVertex ]; - + Buffer_Receive_nLinkedNodes = new unsigned long[ nGlobalVertex ]; Buffer_Receive_LinkedNodes = new unsigned long[ nGlobalLinkedNodes ]; Buffer_Receive_StartLinkedNodes = new unsigned long[ nGlobalVertex ]; @@ -323,21 +323,21 @@ void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ Buffer_Receive_nLinkedNodes[iVertex] = Buffer_Send_nLinkedNodes[iVertex]; Buffer_Receive_StartLinkedNodes[iVertex] = Buffer_Send_StartLinkedNodes[iVertex]; } - + for (iVertex = 0; iVertex < nLocalLinkedNodes; iVertex++) Buffer_Receive_LinkedNodes[iVertex] = Buffer_Send_LinkedNodes[iVertex]; - + tmp_index = nLocalVertex; tmp_index_2 = nLocalLinkedNodes; for(iRank = 1; iRank < nProcessor; iRank++){ - + SU2_MPI::Recv( &iTmp2, 1, MPI_UNSIGNED_LONG, iRank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); SU2_MPI::Recv(&Buffer_Receive_LinkedNodes[tmp_index_2], iTmp2, MPI_UNSIGNED_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); SU2_MPI::Recv( &iTmp, 1, MPI_UNSIGNED_LONG, iRank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); SU2_MPI::Recv(&Buffer_Receive_Coord[tmp_index*nDim], nDim*iTmp, MPI_DOUBLE, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - + SU2_MPI::Recv( &Buffer_Receive_GlobalPoint[tmp_index], iTmp, MPI_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); SU2_MPI::Recv( &Buffer_Receive_nLinkedNodes[tmp_index], iTmp, MPI_UNSIGNED_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); SU2_MPI::Recv(&Buffer_Receive_StartLinkedNodes[tmp_index], iTmp, MPI_UNSIGNED_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); @@ -346,7 +346,7 @@ void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ Buffer_Receive_Proc[ tmp_index + iVertex ] = iRank; Buffer_Receive_StartLinkedNodes[ tmp_index + iVertex ] += tmp_index_2; } - + tmp_index += iTmp; tmp_index_2 += iTmp2; } @@ -354,34 +354,34 @@ void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ else{ SU2_MPI::Send( &nLocalLinkedNodes, 1, MPI_UNSIGNED_LONG, 0, 0, MPI_COMM_WORLD); SU2_MPI::Send(Buffer_Send_LinkedNodes, nLocalLinkedNodes, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); - + SU2_MPI::Send( &nLocalVertex, 1, MPI_UNSIGNED_LONG, 0, 0, MPI_COMM_WORLD); SU2_MPI::Send(Buffer_Send_Coord, nDim * nLocalVertex, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD); - + SU2_MPI::Send( Buffer_Send_GlobalPoint, nLocalVertex, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); SU2_MPI::Send( Buffer_Send_nLinkedNodes, nLocalVertex, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); SU2_MPI::Send(Buffer_Send_StartLinkedNodes, nLocalVertex, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); - } + } #else for (iVertex = 0; iVertex < nDim * nGlobalVertex; iVertex++) Buffer_Receive_Coord[iVertex] = Buffer_Send_Coord[iVertex]; - + for (iVertex = 0; iVertex < nGlobalVertex; iVertex++){ Buffer_Receive_GlobalPoint[iVertex] = Buffer_Send_GlobalPoint[iVertex]; Buffer_Receive_Proc[iVertex] = MASTER_NODE; Buffer_Receive_nLinkedNodes[iVertex] = Buffer_Send_nLinkedNodes[iVertex]; Buffer_Receive_StartLinkedNodes[iVertex] = Buffer_Send_StartLinkedNodes[iVertex]; } - + for (iVertex = 0; iVertex < nGlobalLinkedNodes; iVertex++) Buffer_Receive_LinkedNodes[iVertex] = Buffer_Send_LinkedNodes[iVertex]; -#endif +#endif if (rank == MASTER_NODE){ for (iVertex = 0; iVertex < nGlobalVertex; iVertex++){ count = 0; uptr = &Buffer_Receive_LinkedNodes[ Buffer_Receive_StartLinkedNodes[iVertex] ]; - + for (jVertex = 0; jVertex < Buffer_Receive_nLinkedNodes[iVertex]; jVertex++){ iTmp = uptr[ jVertex ]; for (kVertex = 0; kVertex < nGlobalVertex; kVertex++){ @@ -391,13 +391,13 @@ void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ break; } } - + if( count != (jVertex+1) ){ for (kVertex = jVertex; kVertex < Buffer_Receive_nLinkedNodes[iVertex]-1; kVertex++){ uptr[ kVertex ] = uptr[ kVertex + 1]; } Buffer_Receive_nLinkedNodes[iVertex]--; - jVertex--; + jVertex--; } } } @@ -453,7 +453,7 @@ void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ const auto markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - + /*--- On the target side: find the tag of the boundary sharing the interface. ---*/ const auto markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); @@ -487,7 +487,7 @@ void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { /*--- Coordinates of the target point. ---*/ const su2double* Coord_i = target_geometry->node[Point_Target]->GetCoord(); - su2double mindist = 1e20; + su2double mindist = 1e20; long pGlobalPoint = 0; int pProcessor = 0; @@ -502,8 +502,8 @@ void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { if (dist < mindist) { mindist = dist; - pProcessor = iProcessor; - pGlobalPoint = Buffer_Receive_GlobalPoint[idx]; + pProcessor = iProcessor; + pGlobalPoint = Buffer_Receive_GlobalPoint[idx]; } /*--- Test for "exact" match. ---*/ @@ -592,7 +592,7 @@ void CIsoparametric::Set_TransferCoeff(CConfig **config) { /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - + /*--- On the target side: find the tag of the boundary sharing the interface ---*/ markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); @@ -608,7 +608,7 @@ void CIsoparametric::Set_TransferCoeff(CConfig **config) { nVertexTarget = target_geometry->GetnVertex( markTarget ); else nVertexTarget = 0; - + Buffer_Send_nVertex_Donor = new unsigned long [1]; Buffer_Send_nFace_Donor = new unsigned long [1]; Buffer_Send_nFaceNodes_Donor = new unsigned long [1]; @@ -825,7 +825,7 @@ void CIsoparametric::Set_TransferCoeff(CConfig **config) { storeProc[iDonor] = (int)Buffer_Receive_FaceProc[faceindex+iDonor]; } } - + delete [] X; } } @@ -868,7 +868,7 @@ void CIsoparametric::Set_TransferCoeff(CConfig **config) { } delete [] Coord; delete [] Normal; - + delete [] projected_point; } @@ -876,7 +876,7 @@ void CIsoparametric::Isoparameters(unsigned short nDim, unsigned short nDonor, su2double *X, su2double *xj, su2double *isoparams) { short iDonor,iDim,k; // indices su2double tmp, tmp2; - + su2double *x = new su2double[nDim+1]; su2double *x_tmp = new su2double[nDim+1]; su2double *Q = new su2double[nDonor*nDonor]; @@ -884,12 +884,12 @@ void CIsoparametric::Isoparameters(unsigned short nDim, unsigned short nDonor, su2double *A = new su2double[(nDim+2)*nDonor]; su2double *A2 = NULL; su2double *x2 = new su2double[nDim+1]; - + bool *test = new bool[nDim+1]; bool *testi = new bool[nDim+1]; - + su2double eps = 1E-10; - + short n = nDim+1; if (nDonor>2) { @@ -1050,7 +1050,7 @@ void CIsoparametric::Isoparameters(unsigned short nDim, unsigned short nDonor, isoparams[k] = 1.0; } } - + delete [] x; delete [] x_tmp; delete [] Q; @@ -1058,7 +1058,7 @@ void CIsoparametric::Isoparameters(unsigned short nDim, unsigned short nDonor, delete [] A; delete [] A2; delete [] x2; - + delete [] test; delete [] testi; @@ -1279,9 +1279,9 @@ CSlidingMesh::CSlidingMesh(CGeometry ****geometry_container, CConfig **config, u void CSlidingMesh::Set_TransferCoeff(CConfig **config) { /* --- This routine sets the transfer coefficient for sliding mesh approach --- */ - + /* - * The algorithm is based on Rinaldi et al. "Flux-conserving treatment of non-conformal interfaces + * The algorithm is based on Rinaldi et al. "Flux-conserving treatment of non-conformal interfaces * for finite-volume discritization of conservaation laws" 2015, Comp. Fluids, 120, pp 126-139 */ @@ -1290,19 +1290,19 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { /* --- General variables --- */ bool check; - + unsigned short iDim, nDim; - + unsigned long ii, jj, *uptr; unsigned long vPoint; unsigned long iEdgeVisited, nEdgeVisited, iNodeVisited; unsigned long nAlreadyVisited, nToVisit, StartVisited; - + unsigned long *alreadyVisitedDonor, *ToVisit, *tmpVect; unsigned long *storeProc, *tmp_storeProc; su2double dTMP; - su2double *Coeff_Vect, *tmp_Coeff_Vect; + su2double *Coeff_Vect, *tmp_Coeff_Vect; /* --- Geometrical variables --- */ @@ -1313,7 +1313,7 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { /* --- Markers Variables --- */ - unsigned short iMarkerInt, nMarkerInt; + unsigned short iMarkerInt, nMarkerInt; unsigned long iVertex, nVertexTarget; @@ -1325,24 +1325,24 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { unsigned long nEdges_target, nNode_target; unsigned long *Target_nLinkedNodes, *Target_LinkedNodes, *Target_StartLinkedNodes, *target_segment; - unsigned long *Target_Proc; + unsigned long *Target_Proc; long *Target_GlobalPoint, *Donor_GlobalPoint; - + su2double *TargetPoint_Coord, *target_iMidEdge_point, *target_jMidEdge_point, **target_element; /* --- Donor variables --- */ - unsigned long donor_StartIndex, donor_forward_point, donor_backward_point, donor_iPoint, donor_OldiPoint; - unsigned long nEdges_donor, nNode_donor, nGlobalVertex_Donor; + unsigned long donor_StartIndex, donor_forward_point, donor_backward_point, donor_iPoint, donor_OldiPoint; + unsigned long nEdges_donor, nNode_donor, nGlobalVertex_Donor; unsigned long nDonorPoints, iDonor; unsigned long *Donor_Vect, *tmp_Donor_Vect; unsigned long *Donor_nLinkedNodes, *Donor_LinkedNodes, *Donor_StartLinkedNodes; unsigned long *Donor_Proc; - + su2double *donor_iMidEdge_point, *donor_jMidEdge_point; su2double **donor_element, *DonorPoint_Coord; - + /* 1 - Variable pre-processing - */ nDim = donor_geometry->GetnDim(); @@ -1356,11 +1356,11 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { tmp_Donor_Vect = NULL; tmp_Coeff_Vect = NULL; tmp_storeProc = NULL; - + Normal = new su2double[nDim]; Direction = new su2double[nDim]; - - + + /* 2 - Find boundary tag between touching grids */ /*--- Number of markers on the FSI interface ---*/ @@ -1389,7 +1389,7 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { /*--- Target boundary ---*/ ReconstructBoundary(targetZone, markTarget); - + nGlobalVertex_Target = nGlobalVertex; TargetPoint_Coord = Buffer_Receive_Coord; @@ -1398,10 +1398,10 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { Target_StartLinkedNodes = Buffer_Receive_StartLinkedNodes; Target_LinkedNodes = Buffer_Receive_LinkedNodes; Target_Proc = Buffer_Receive_Proc; - + /*--- Donor boundary ---*/ ReconstructBoundary(donorZone, markDonor); - + nGlobalVertex_Donor = nGlobalVertex; DonorPoint_Coord = Buffer_Receive_Coord; @@ -1414,22 +1414,22 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { /*--- Starts building the supermesh layer (2D or 3D) ---*/ /* - For each target node, it first finds the closest donor point * - Then it creates the supermesh in the close proximity of the target point: - * - Starting from the closest donor node, it expands the supermesh by including + * - Starting from the closest donor node, it expands the supermesh by including * donor elements neighboring the initial one, until the overall target area is fully covered. */ if(nDim == 2){ - + target_iMidEdge_point = new su2double[nDim]; target_jMidEdge_point = new su2double[nDim]; donor_iMidEdge_point = new su2double[nDim]; donor_jMidEdge_point = new su2double[nDim]; - + /*--- Starts with supermesh reconstruction ---*/ target_segment = new unsigned long[2]; - + for (iVertex = 0; iVertex < nVertexTarget; iVertex++) { nDonorPoints = 0; @@ -1446,34 +1446,34 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { mindist = 1E6; donor_StartIndex = 0; - + for (donor_iPoint = 0; donor_iPoint < nGlobalVertex_Donor; donor_iPoint++) { - + Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; dist = PointsDistance(nDim, Coord_i, Coord_j); if (dist < mindist) { - mindist = dist; + mindist = dist; donor_StartIndex = donor_iPoint; } if (dist == 0.0){ donor_StartIndex = donor_iPoint; break; - } + } } donor_iPoint = donor_StartIndex; donor_OldiPoint = donor_iPoint; - + /*--- Contruct information regarding the target cell ---*/ - + long dPoint = target_geometry->node[target_iPoint]->GetGlobalIndex(); for (jVertexTarget = 0; jVertexTarget < nGlobalVertex_Target; jVertexTarget++) if( dPoint == Target_GlobalPoint[jVertexTarget] ) break; - + if ( Target_nLinkedNodes[jVertexTarget] == 1 ){ target_segment[0] = Target_LinkedNodes[ Target_StartLinkedNodes[jVertexTarget] ]; target_segment[1] = jVertexTarget; @@ -1482,7 +1482,7 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { target_segment[0] = Target_LinkedNodes[ Target_StartLinkedNodes[jVertexTarget] ]; target_segment[1] = Target_LinkedNodes[ Target_StartLinkedNodes[jVertexTarget] + 1]; } - + dTMP = 0; for(iDim = 0; iDim < nDim; iDim++){ target_iMidEdge_point[iDim] = ( TargetPoint_Coord[ nDim * target_segment[0] + iDim ] + target_geometry->node[ target_iPoint ]->GetCoord(iDim) ) / 2; @@ -1503,7 +1503,7 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { /*--- Proceeds along the forward direction (depending on which connected boundary node is found first) ---*/ while( !check ){ - + /*--- Proceeds until the value of the intersection area is null ---*/ if ( Donor_nLinkedNodes[donor_iPoint] == 1 ){ @@ -1512,7 +1512,7 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { } else{ uptr = &Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_iPoint] ]; - + if( donor_OldiPoint != uptr[0] ){ donor_forward_point = uptr[0]; donor_backward_point = uptr[1]; @@ -1522,12 +1522,12 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { donor_backward_point = uptr[0]; } } - + if(donor_iPoint >= nGlobalVertex_Donor){ check = true; continue; } - + for(iDim = 0; iDim < nDim; iDim++){ donor_iMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_forward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; donor_jMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_backward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; @@ -1539,13 +1539,13 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { check = true; continue; } - + /*--- In case the element intersects the target cell, update the auxiliary communication data structure ---*/ tmp_Coeff_Vect = new su2double[ nDonorPoints + 1 ]; tmp_Donor_Vect = new unsigned long[ nDonorPoints + 1 ]; tmp_storeProc = new unsigned long[ nDonorPoints + 1 ]; - + for( iDonor = 0; iDonor < nDonorPoints; iDonor++){ tmp_Donor_Vect[iDonor] = Donor_Vect[iDonor]; tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; @@ -1555,9 +1555,9 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; tmp_Coeff_Vect[ nDonorPoints ] = LineIntersectionLength / length; tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; - - if (Donor_Vect != NULL) delete [] Donor_Vect; - if (Coeff_Vect != NULL) delete [] Coeff_Vect; + + if (Donor_Vect != NULL) delete [] Donor_Vect; + if (Coeff_Vect != NULL) delete [] Coeff_Vect; if (storeProc != NULL) delete [] storeProc; Donor_Vect = tmp_Donor_Vect; @@ -1569,10 +1569,10 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { nDonorPoints++; } - + if ( Donor_nLinkedNodes[donor_StartIndex] == 2 ){ check = false; - + uptr = &Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_StartIndex] ]; donor_iPoint = uptr[1]; @@ -1592,7 +1592,7 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { } else{ uptr = &Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_iPoint] ]; - + if( donor_OldiPoint != uptr[0] ){ donor_forward_point = uptr[0]; donor_backward_point = uptr[1]; @@ -1607,11 +1607,11 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { check = true; continue; } - + for(iDim = 0; iDim < nDim; iDim++){ donor_iMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_forward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; donor_jMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_backward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; - } + } LineIntersectionLength = ComputeLineIntersectionLength(target_iMidEdge_point, target_jMidEdge_point, donor_iMidEdge_point, donor_jMidEdge_point, Direction); @@ -1625,14 +1625,14 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { tmp_Coeff_Vect = new su2double[ nDonorPoints + 1 ]; tmp_Donor_Vect = new unsigned long[ nDonorPoints + 1 ]; tmp_storeProc = new unsigned long[ nDonorPoints + 1 ]; - + for( iDonor = 0; iDonor < nDonorPoints; iDonor++){ tmp_Donor_Vect[iDonor] = Donor_Vect[iDonor]; tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; tmp_storeProc[iDonor] = storeProc[iDonor]; } - - tmp_Coeff_Vect[ nDonorPoints ] = LineIntersectionLength / length; + + tmp_Coeff_Vect[ nDonorPoints ] = LineIntersectionLength / length; tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; @@ -1646,52 +1646,52 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { donor_OldiPoint = donor_iPoint; donor_iPoint = donor_forward_point; - + nDonorPoints++; } - + /*--- Set the communication data structure and copy data from the auxiliary vectors ---*/ target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nDonorPoints); target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); - - for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ + + for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor, Coeff_Vect[iDonor]); target_geometry->vertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor, Donor_GlobalPoint[Donor_Vect[iDonor]]); target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); } } - } - + } + delete [] target_segment; - + delete [] target_iMidEdge_point; delete [] target_jMidEdge_point; delete [] donor_iMidEdge_point; delete [] donor_jMidEdge_point; } - else{ + else{ /* --- 3D geometry, creates a superficial super-mesh --- */ - + for (iVertex = 0; iVertex < nVertexTarget; iVertex++) { - + nDonorPoints = 0; /*--- Stores coordinates of the target node ---*/ target_iPoint = target_geometry->vertex[markTarget][iVertex]->GetNode(); - + if (!target_geometry->node[target_iPoint]->GetDomain()) continue; - + Coord_i = target_geometry->node[target_iPoint]->GetCoord(); target_geometry->vertex[markTarget][iVertex]->GetNormal(Normal); /*--- The value of Area computed here includes also portion of boundary belonging to different marker ---*/ Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) + for (iDim = 0; iDim < nDim; iDim++) Area += Normal[iDim]*Normal[iDim]; Area = sqrt(Area); @@ -1700,23 +1700,23 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { for (iDim = 0; iDim < nDim; iDim++) Coord_i[iDim] = target_geometry->node[target_iPoint]->GetCoord(iDim); - + long dPoint = target_geometry->node[target_iPoint]->GetGlobalIndex(); for (target_iPoint = 0; target_iPoint < nGlobalVertex_Target; target_iPoint++){ if( dPoint == Target_GlobalPoint[target_iPoint] ) break; - } - + } + /*--- Build local surface dual mesh for target element ---*/ - + nEdges_target = Target_nLinkedNodes[target_iPoint]; nNode_target = 2*(nEdges_target + 1); - + target_element = new su2double*[nNode_target]; for (ii = 0; ii < nNode_target; ii++) target_element[ii] = new su2double[nDim]; - + nNode_target = Build_3D_surface_element(Target_LinkedNodes, Target_StartLinkedNodes, Target_nLinkedNodes, TargetPoint_Coord, target_iPoint, target_element); /*--- Brute force to find the closest donor_node ---*/ @@ -1725,29 +1725,29 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { donor_StartIndex = 0; for (donor_iPoint = 0; donor_iPoint < nGlobalVertex_Donor; donor_iPoint++) { - + Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; dist = PointsDistance(nDim, Coord_i, Coord_j); if (dist < mindist) { - mindist = dist; + mindist = dist; donor_StartIndex = donor_iPoint; } if (dist == 0.0){ donor_StartIndex = donor_iPoint; break; - } + } } - + donor_iPoint = donor_StartIndex; nEdges_donor = Donor_nLinkedNodes[donor_iPoint]; donor_element = new su2double*[ 2*nEdges_donor + 2 ]; for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - donor_element[ii] = new su2double[nDim]; + donor_element[ii] = new su2double[nDim]; nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); @@ -1782,10 +1782,10 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { StartVisited = 0; Area_old = -1; - - while( Area > Area_old ){ - /* + while( Area > Area_old ){ + + /* * - Starting from the closest donor_point, it expands the supermesh by a countour search pattern. * - The closest donor element becomes the core, at each iteration a new layer of elements around the core is taken into account */ @@ -1798,7 +1798,7 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { for( iNodeVisited = StartVisited; iNodeVisited < nAlreadyVisited; iNodeVisited++ ){ vPoint = alreadyVisitedDonor[ iNodeVisited ]; - + nEdgeVisited = Donor_nLinkedNodes[vPoint]; for (iEdgeVisited = 0; iEdgeVisited < nEdgeVisited; iEdgeVisited++){ @@ -1811,7 +1811,7 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { for( jj = 0; jj < nAlreadyVisited; jj++ ){ if( donor_iPoint == alreadyVisitedDonor[jj] ){ - check = 1; + check = 1; break; } } @@ -1819,12 +1819,12 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { if( check == 0 && ToVisit != NULL){ for( jj = 0; jj < nToVisit; jj++ ) if( donor_iPoint == ToVisit[jj] ){ - check = 1; + check = 1; break; - } + } } - if( check == 0 ){ + if( check == 0 ){ /*--- If the node was not already visited, visit it and list it into data structure ---*/ tmpVect = new unsigned long[ nToVisit + 1 ]; @@ -1835,19 +1835,19 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { if( ToVisit != NULL ) delete [] ToVisit; - + ToVisit = tmpVect; tmpVect = NULL; - nToVisit++; + nToVisit++; /*--- Find the value of the intersection area between the current donor element and the target element --- */ nEdges_donor = Donor_nLinkedNodes[donor_iPoint]; - donor_element = new su2double*[ 2*nEdges_donor + 2 ]; + donor_element = new su2double*[ 2*nEdges_donor + 2 ]; for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - donor_element[ii] = new su2double[nDim]; + donor_element[ii] = new su2double[nDim]; nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); @@ -1871,8 +1871,8 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; tmp_storeProc[iDonor] = storeProc[iDonor]; } - - tmp_Coeff_Vect[ nDonorPoints ] = tmp_Area; + + tmp_Coeff_Vect[ nDonorPoints ] = tmp_Area; tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; @@ -1884,15 +1884,15 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { Coeff_Vect = tmp_Coeff_Vect; storeProc = tmp_storeProc; - tmp_Coeff_Vect = NULL; + tmp_Coeff_Vect = NULL; tmp_Donor_Vect = NULL; tmp_storeProc = NULL; nDonorPoints++; - + Area += tmp_Area; } - } + } } /*--- Update auxiliary data structure ---*/ @@ -1903,18 +1903,18 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { for( jj = 0; jj < nAlreadyVisited; jj++ ) tmpVect[jj] = alreadyVisitedDonor[jj]; - + for( jj = 0; jj < nToVisit; jj++ ) tmpVect[ nAlreadyVisited + jj ] = ToVisit[jj]; if( alreadyVisitedDonor != NULL ) delete [] alreadyVisitedDonor; - alreadyVisitedDonor = tmpVect; + alreadyVisitedDonor = tmpVect; - nAlreadyVisited += nToVisit; + nAlreadyVisited += nToVisit; - delete [] ToVisit; + delete [] ToVisit; } delete [] alreadyVisitedDonor; @@ -1924,17 +1924,17 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nDonorPoints); target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); - for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ + for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor, Coeff_Vect[iDonor]/Area); target_geometry->vertex[markTarget][iVertex]->SetInterpDonorPoint( iDonor, Donor_GlobalPoint[ Donor_Vect[iDonor] ] ); target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); - //cout <= 0) check++; - return (check == 3); + return (check == 3); } CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, @@ -2914,7 +2914,7 @@ int CRadialBasisFunction::CheckPolynomialTerms(su2double max_diff_tol, vector Date: Wed, 18 Mar 2020 14:55:31 +0000 Subject: [PATCH 11/79] split interpolation_structure --- .../interface_interpolation/CInterpolator.hpp | 186 + .../CIsoparametric.hpp | 70 + .../interface_interpolation/CMirror.hpp | 53 + .../CNearestNeighbor.hpp | 51 + .../CRadialBasisFunction.hpp | 159 + .../interface_interpolation/CSlidingMesh.hpp | 117 + Common/include/interpolation_structure.hpp | 498 --- Common/lib/Makefile.am | 7 +- .../interface_interpolation/CInterpolator.cpp | 415 +++ .../CIsoparametric.cpp | 563 +++ .../src/interface_interpolation/CMirror.cpp | 243 ++ .../CNearestNeighbor.cpp | 137 + .../CRadialBasisFunction.cpp | 772 ++++ .../interface_interpolation/CSlidingMesh.cpp | 1255 +++++++ .../src/interface_interpolation/meson.build | 6 + Common/src/interpolation_structure.cpp | 3235 ----------------- Common/src/meson.build | 2 +- SU2_CFD/include/SU2_CFD.hpp | 1 - SU2_CFD/include/drivers/CDriver.hpp | 2 +- SU2_CFD/src/drivers/CDriver.cpp | 8 +- SU2_CFD/src/drivers/CMultizoneDriver.cpp | 4 +- 21 files changed, 4044 insertions(+), 3740 deletions(-) create mode 100644 Common/include/interface_interpolation/CInterpolator.hpp create mode 100644 Common/include/interface_interpolation/CIsoparametric.hpp create mode 100644 Common/include/interface_interpolation/CMirror.hpp create mode 100644 Common/include/interface_interpolation/CNearestNeighbor.hpp create mode 100644 Common/include/interface_interpolation/CRadialBasisFunction.hpp create mode 100644 Common/include/interface_interpolation/CSlidingMesh.hpp delete mode 100644 Common/include/interpolation_structure.hpp create mode 100644 Common/src/interface_interpolation/CInterpolator.cpp create mode 100644 Common/src/interface_interpolation/CIsoparametric.cpp create mode 100644 Common/src/interface_interpolation/CMirror.cpp create mode 100644 Common/src/interface_interpolation/CNearestNeighbor.cpp create mode 100644 Common/src/interface_interpolation/CRadialBasisFunction.cpp create mode 100644 Common/src/interface_interpolation/CSlidingMesh.cpp create mode 100644 Common/src/interface_interpolation/meson.build delete mode 100644 Common/src/interpolation_structure.cpp diff --git a/Common/include/interface_interpolation/CInterpolator.hpp b/Common/include/interface_interpolation/CInterpolator.hpp new file mode 100644 index 000000000000..5144e37ce2bc --- /dev/null +++ b/Common/include/interface_interpolation/CInterpolator.hpp @@ -0,0 +1,186 @@ +/*! + * \file CInterpolator.hpp + * \brief Base class for multiphysics interpolation. + * \author H. Kline + * \version 7.0.2 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#pragma once + +#include "../../include/datatype_structure.hpp" + +class CConfig; +class CGeometry; + +/*! + * \class CInterpolator + * \brief Main class for defining the interpolator, it requires + * a child class for each particular interpolation method + * \author H. Kline + */ +class CInterpolator { +protected: + const int rank; /*!< \brief MPI Rank. */ + const int size; /*!< \brief MPI Size. */ + const unsigned donorZone; /*!< \brief Index of donor zone. */ + const unsigned targetZone; /*!< \brief Index of target zone. */ + + unsigned long + MaxLocalVertex_Donor, /*!< \brief Maximum vertices per processor*/ + nGlobalFace_Donor, /*!< \brief Number of global donor faces*/ + nGlobalFaceNodes_Donor, /*!< \brief Number of global donor face nodes*/ + MaxFace_Donor, /*!< \brief Maximum faces per processor*/ + MaxFaceNodes_Donor; /*!< \brief Maximum nodes associated with faces per processor*/ + + unsigned long + *Buffer_Receive_nVertex_Donor, /*!< \brief Buffer to store the number of vertices per processor on the Donor domain */ + *Buffer_Receive_nFace_Donor, /*!< \brief Buffer to store the number of faces per processor*/ + *Buffer_Receive_nFaceNodes_Donor, /*!< \brief Buffer to store the number of nodes associated with faces per processor*/ + *Buffer_Send_nVertex_Donor, /*!< \brief Buffer to send number of vertices on the local processor*/ + *Buffer_Send_nFace_Donor, /*!< \brief Buffer to send number of faces on the local processor*/ + *Buffer_Send_nFaceNodes_Donor, /*!< \brief Buffer to send the number of nodes assocated with faces per processor*/ + *Buffer_Send_FaceIndex, /*!< \brief Buffer to send indices pointing to the node indices that define the faces*/ + *Buffer_Receive_FaceIndex, /*!< \brief Buffer to receive indices pointing to the node indices that define the faces*/ + *Buffer_Send_FaceNodes, /*!< \brief Buffer to send indices pointing to the location of node information in other buffers, defining faces*/ + *Buffer_Receive_FaceNodes, /*!< \brief Buffer to receive indices pointing to the location of node information in other buffers, defining faces*/ + *Buffer_Send_FaceProc, /*!< \brief Buffer to send processor which stores the node indicated in Buffer_Receive_FaceNodes*/ + *Buffer_Receive_FaceProc; /*!< \brief Buffer to receive processor which stores the node indicated in Buffer_Receive_FaceNodes*/ + + long *Buffer_Send_GlobalPoint, /*!< \brief Buffer to send global point indices*/ + *Buffer_Receive_GlobalPoint; /*!< \brief Buffer to receive global point indices*/ + + su2double *Buffer_Send_Coord, /*!< \brief Buffer to send coordinate values*/ + *Buffer_Send_Normal, /*!< \brief Buffer to send normal vector values */ + *Buffer_Receive_Coord, /*!< \brief Buffer to receive coordinate values*/ + *Buffer_Receive_Normal; /*!< \brief Buffer to receive normal vector values*/ + + unsigned long *Receive_GlobalPoint, /*!< \brief Buffer to receive Global point indexes*/ + *Buffer_Receive_nLinkedNodes, /*!< \brief Buffer to receive the number of edges connected to each node*/ + *Buffer_Receive_LinkedNodes, /*!< \brief Buffer to receive the list of notes connected to the nodes through an edge*/ + *Buffer_Receive_StartLinkedNodes, /*!< \brief Buffer to receive the index of the Receive_LinkedNodes buffer where corresponding list of linked nodes begins */ + *Buffer_Receive_Proc; /*!< \brief Buffer to receive the thread that owns the node*/ + + unsigned long nGlobalVertex_Target, /*!< \brief Global number of vertex of the target boundary*/ + nLocalVertex_Target, /*!< \brief Number of vertex of the target boundary owned by the thread*/ + nGlobalVertex_Donor, /*!< \brief Global number of vertex of the donor boundary*/ + nLocalVertex_Donor, /*!< \brief Number of vertex of the donor boundary owned by the thread*/ + nGlobalVertex, /*!< \brief Dummy variable to temporarily store the global number of vertex of a boundary*/ + nLocalLinkedNodes; /*!< \brief Dummy variable to temporarily store the number of vertex of a boundary*/ + + CGeometry**** const Geometry; /*! \brief Vector which stores n zones of geometry. */ + CGeometry* const donor_geometry; /*! \brief Donor geometry. */ + CGeometry* const target_geometry; /*! \brief Target geometry. */ + +public: + /*! + * \brief Constructor of the class. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - index of the donor zone + * \param[in] jZone - index of the target zone + */ + CInterpolator(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); + + /*! + * \brief No default construction allowed. + */ + CInterpolator(void) = delete; + + /*! + * \brief Destructor of the class, nothing is deleted, derived classes need to manage the MPI buffers. + */ + virtual ~CInterpolator(void) = default; + + /*! + * \brief Set up transfer matrix defining relation between two meshes + * \note Main method that derived classes must implement. + * \param[in] config - Definition of the particular problem. + */ + virtual void Set_TransferCoeff(CConfig **config) = 0; + +protected: + /*! + * \brief Find the index of the interface marker shared by that zone + * \param[in] config - Definition of the particular problem. + * \param[in] val_marker_interface - Interface tag. + */ + int Find_InterfaceMarker(const CConfig *config, unsigned short val_marker_interface) const; + + /*! + * \brief Check whether an interface should be processed or not, i.e. if it is part of the zones. + * \param[in] val_markDonor - Marker tag from donor zone. + * \param[in] val_markTarget - Marker tag from target zone. + */ + bool CheckInterfaceBoundary(int val_markDonor, int val_markTarget) const; + + /*! + * \brief Recontstruct the boundary connectivity from parallel partitioning and broadcasts it to all threads + * \param[in] val_zone - index of the zone + * \param[in] val_marker - index of the marker + */ + void ReconstructBoundary(unsigned long val_zone, int val_marker); + + /*! + * \brief compute squared distance between 2 points + * \param[in] nDim - number of dimensions + * \param[in] point_i - coordinates of point i + * \param[in] point_j - coordinates of point j + */ + inline su2double PointsSquareDistance(unsigned short nDim, const su2double *point_i, const su2double *point_j) const { + su2double d = 0.0; + for(unsigned short iDim = 0; iDim < nDim; iDim++) + d += pow(point_j[iDim] - point_i[iDim], 2); + return d; + } + + /*! + * \brief compute distance between 2 points + * \param[in] nDim - number of dimensions + * \param[in] point_i - coordinates of point i + * \param[in] point_j - coordinates of point j + */ + inline su2double PointsDistance(unsigned short nDim, const su2double *point_i, const su2double *point_j) const { + return sqrt(PointsSquareDistance(nDim, point_i, point_j)); + } + + /*! + * \brief Determine array sizes used to collect and send coordinate and global point + * information. + * \param[in] faces - boolean that determines whether or not to set face information as well + * \param[in] markDonor - Index of the boundary on the donor domain. + * \param[in] markTarget - Index of the boundary on the target domain. + * \param[in] nVertexDonor - Number of vertices on the donor boundary. + * \param[in] nDim - number of physical dimensions. + */ + void Determine_ArraySize(bool faces, int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim); + + /*! + * \brief Collect and communicate vertex info: coord, global point, and if faces=true the normal vector + * \param[in] faces - boolean that determines whether or not to set face information as well + * \param[in] markDonor - Index of the boundary on the donor domain. + * \param[in] markTarget - Index of the boundary on the target domain. + * \param[in] nVertexDonor - Number of vertices on the donor boundary. + * \param[in] nDim - number of physical dimensions. + */ + void Collect_VertexInfo(bool faces, int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim); + +}; diff --git a/Common/include/interface_interpolation/CIsoparametric.hpp b/Common/include/interface_interpolation/CIsoparametric.hpp new file mode 100644 index 000000000000..250a7814f15d --- /dev/null +++ b/Common/include/interface_interpolation/CIsoparametric.hpp @@ -0,0 +1,70 @@ +/*! + * \file CIsoparametric.hpp + * \brief Isoparametric interpolation using FE shape functions. + * \author H. Kline + * \version 7.0.2 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#pragma once + +#include "CInterpolator.hpp" + +/*! + * \brief Isoparametric interpolation. + */ +class CIsoparametric final : public CInterpolator { +public: + /*! + * \brief Constructor of the class. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - index of the donor zone + * \param[in] jZone - index of the target zone + */ + CIsoparametric(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); + + /*! + * \brief Set up transfer matrix defining relation between two meshes + * \param[in] config - Definition of the particular problem. + */ + void Set_TransferCoeff(CConfig **config) override; + +private: + /*! + * \brief Calculate the isoparametric representation of point iVertex in marker iZone_0 by + * nodes of element donor_elem in marker jMarker of zone iZone_1. + * \param[in] iVertex - vertex index of the point being interpolated. + * \param[in] nDim - the dimension of the coordinates. + * \param[in] iZone_1 - zone index of the element to use for interpolation (the DONOR zone) + * \param[in] donor_elem - element index of the element to use for interpolation (or global index of a point in 2D) + * \param[in] nDonorPoints - number of donor points in the element. + * \param[in] xj - point projected onto the plane of the donor element. + * \param[out] isoparams - isoparametric coefficients. Must be allocated to size nNodes ahead of time. (size> nDonors) + * + * \note If the problem is 2D, the 'face' projected onto is actually an edge; the local index + * of the edge is then stored in iFace, and the global index of the node (from which the edge + * is referenced) + */ + void Isoparameters(unsigned short nDim, unsigned short nDonor, const su2double *X, + const su2double *xj, su2double* isoparams) const; + +}; diff --git a/Common/include/interface_interpolation/CMirror.hpp b/Common/include/interface_interpolation/CMirror.hpp new file mode 100644 index 000000000000..c53ebc4bd889 --- /dev/null +++ b/Common/include/interface_interpolation/CMirror.hpp @@ -0,0 +1,53 @@ +/*! + * \file CMirror.hpp + * \brief Mirror interpolation for the conservative (work-wise) approach in FSI problems. + * \author H. Kline + * \version 7.0.2 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#pragma once + +#include "CInterpolator.hpp" + +/*! + * \brief Mirror interpolation: copy point linking and coefficient values from the opposing mesh. + * \note Assumes that the oppoosing mesh has already run interpolation, otherwise will result in empty/trivial interpolation. + */ +class CMirror final : public CInterpolator { +public: + /*! + * \brief Constructor of the class. + * \note Data is set in geometry[targetZone]. + * \param[in] geometry_container + * \param[in] config - config container + * \param[in] iZone - First zone + * \param[in] jZone - Second zone + */ + CMirror(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); + + /*! + * \brief Set up transfer matrix defining relation between two meshes + * \param[in] config - Definition of the particular problem. + */ + void Set_TransferCoeff(CConfig **config) override; + +}; diff --git a/Common/include/interface_interpolation/CNearestNeighbor.hpp b/Common/include/interface_interpolation/CNearestNeighbor.hpp new file mode 100644 index 000000000000..95dcdfdd3e2f --- /dev/null +++ b/Common/include/interface_interpolation/CNearestNeighbor.hpp @@ -0,0 +1,51 @@ +/*! + * \file CNearestNeighbor.hpp + * \brief Nearest Neighbor interpolation class. + * \author H. Kline + * \version 7.0.2 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#pragma once + +#include "CInterpolator.hpp" + +/*! + * \brief Nearest Neighbor interpolation. + */ +class CNearestNeighbor final : public CInterpolator { +public: + /*! + * \brief Constructor of the class. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - index of the donor zone + * \param[in] jZone - index of the target zone + */ + CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); + + /*! + * \brief Set up transfer matrix defining relation between two meshes + * \param[in] config - Definition of the particular problem. + */ + void Set_TransferCoeff(CConfig **config) override; + +}; diff --git a/Common/include/interface_interpolation/CRadialBasisFunction.hpp b/Common/include/interface_interpolation/CRadialBasisFunction.hpp new file mode 100644 index 000000000000..18b1b2083644 --- /dev/null +++ b/Common/include/interface_interpolation/CRadialBasisFunction.hpp @@ -0,0 +1,159 @@ +/*! + * \file CRadialBasisFunction.hpp + * \brief Radial basis function interpolation. + * \author Joel Ho, P. Gomes + * \version 7.0.2 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#pragma once + +#include "CInterpolator.hpp" +#include "../option_structure.hpp" +#include "../toolboxes/C2DContainer.hpp" + +/*! + * \brief Radial basis function interpolation. + */ +class CRadialBasisFunction final : public CInterpolator { +public: + /*! + * \brief Constructor of the class. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - index of the donor zone + * \param[in] jZone - index of the target zone + */ + CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); + + /*! + * \brief Set up transfer matrix defining relation between two meshes + * \param[in] config - Definition of the particular problem. + */ + void Set_TransferCoeff(CConfig **config) override; + + /*! + * \brief Compute the value of a radial basis function, this is static so it can be re-used. + * \param[in] type - of radial basis function + * \param[in] radius - the characteristic dimension + * \param[in] dist - distance + * \return value of the RBF. + */ + static su2double Get_RadialBasisValue(ENUM_RADIALBASIS type, const su2double radius, const su2double dist); + +private: + /*! + * \brief Compute the RBF "generator" matrix with or without polynomial terms. + * \note Multiplying C_inv_trunc by a column vector gives specific coefficients for given "known values", + * conversely, multiplying (on the left) by a row vector of polynomial and RBF values gives generic + * interpolation coefficients for a given target evaluation point. + * \param[in] type - Type of radial basis function. + * \param[in] usePolynomial - Whether to use polynomial terms. + * \param[in] radius - Normalizes point-to-point distance when computing RBF values. + * \param[in] coords - Coordinates of the donor points. + * \param[out] nPolynomial - Num of poly terms, -1 if !usePolynomial, nDim-1 if coords lie on plane, else nDim. + * \param[out] keepPolynomialRow - Size nDim, signals which (if any) iDim was removed from polynomial term. + * \param[out] C_inv_trunc - The generator matrix as described above. + */ + void ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool usePolynomial, su2double radius, + const su2activematrix& coords, int& nPolynomial, + vector& keepPolynomialRow, su2passivematrix& C_inv_trunc) const; + + /*! + * \brief If the polynomial term is included in the interpolation, and the points lie on a plane, the matrix + * becomes rank deficient and cannot be inverted. This method detects that condition and corrects it by + * removing a row from P (the polynomial part of the interpolation matrix). + * \param[in] max_diff_tol - Tolerance to detect whether points are on a plane. + * \param[out] keep_row - Marks the dimensions of P kept. + * \param[in,out] P - Polynomial part of the interpolation matrix, one row may be eliminated. + * \return n_polynomial - Size of the polynomial part on exit (in practice nDim or nDim-1). + */ + int CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, su2passivematrix &P) const; + + /*! + * \brief Prunes (by setting to zero) small interpolation coefficients, i.e. + * <= tolerance*max(abs(coeffs)). The vector is re-scaled such that sum(coeffs)==1. + * \param[in] tolerance - Relative pruning tolerance. + * \param[in,out] coeffs - The vector of interpolation coefficients. + * \return Number of non-zero coefficients after pruning. + */ + int PruneSmallCoefficients(passivedouble tolerance, su2passivevector& coeffs) const; + +}; + +/*! + * \brief Helper class used by CRadialBasisFunction to compute the interpolation weights. + * The matrix is symmetric but full storage is used as that gives much better performance + * for some BLAS libraries (notably OpenBLAS). The code should be compiled with LAPACK + * to use optimized matrix inversion and multiplication routines. + */ +class CSymmetricMatrix { +private: + enum DecompositionType { NONE, CHOLESKY, LU }; + + vector val_vec, decomp_vec; + vector perm_vec; + int sz = 0; + bool initialized = false; + DecompositionType decomposed = NONE; + + inline void CheckBounds(int i, int j) const { + assert(initialized && "Matrix not initialized."); + assert(i>=0 && i=0 && j. + */ +#pragma once + +#include "CInterpolator.hpp" + +/*! + * \brief Sliding mesh approach. + */ +class CSlidingMesh final : public CInterpolator { +public: + /*! + * \brief Constructor of the class. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - index of the donor zone + * \param[in] jZone - index of the target zone + */ + CSlidingMesh(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); + + /*! + * \brief Set up transfer matrix defining relation between two meshes + * \param[in] config - Definition of the particular problem. + */ + void Set_TransferCoeff(CConfig **config) override; + +private: + /*! + * \brief For 3-Dimensional grids, build the dual surface element + * \param[in] map - array containing the index of the boundary points connected to the node + * \param[in] startIndex - for each vertex specifies the corresponding index in the global array containing the indexes of all its neighbouring vertexes + * \param[in] nNeighbour - for each vertex specifies the number of its neighbouring vertexes (on the boundary) + * \param[in] coord - array containing the coordinates of all the boundary vertexes + * \param[in] centralNode - label of the vertex around which the dual surface element is built + * \param[in] element - double array where element node coordinates will be stored + */ + int Build_3D_surface_element(unsigned long *map, unsigned long *startIndex, unsigned long* nNeighbor, + su2double *coord, unsigned long centralNode, su2double** element); + + /*! + * \brief For 2-Dimensional grids, compute intersection length of two segments projected along a given direction + * \param[in] A1 - first point of segment A + * \param[in] A2 - second point of segment A + * \param[in] B1 - first point of segment B + * \param[in] B2 - second point of segment B + * \param[in] Direction - along which segments are projected + */ + su2double ComputeLineIntersectionLength(su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* Direction); + + /*! + * \brief For 3-Dimensional grids, compute intersection area between two triangle projected on a given plane + * \param[in] A1 - first point of triangle A + * \param[in] A2 - second point of triangle A + * \param[in] A3 - third point of triangle A + * \param[in] B1 - first point of triangle B + * \param[in] B2 - second point of triangle B + * \param[in] B3 - third point of triangle B + * \param[in] Direction - vector normal to projection plane + */ + su2double Compute_Triangle_Intersection(su2double* A1, su2double* A2, su2double* A3, su2double* B1, su2double* B2, su2double* B3, su2double* Direction); + + /*! + * \brief For 3-Dimensional grids, compute intersection area between two triangle projected on a given plane + * P1 from triangle P MUST be inside triangle Q, points order doesn't matter + * \param[in] P1 - first point of triangle A + * \param[in] P2 - second point of triangle A + * \param[in] P3 - third point of triangle A + * \param[in] Q1 - first point of triangle B + * \param[in] Q2 - second point of triangle B + * \param[in] Q3 - third point of triangle B + */ + su2double ComputeIntersectionArea( su2double* P1, su2double* P2, su2double* P3, su2double* Q1, su2double* Q2, su2double* Q3 ); + + /*! + * \brief For 2-Dimensional grids, check whether, and compute, two lines are intersecting + * \param[in] A1 - first defining first line + * \param[in] A2 - second defining first line + * \param[in] B1 - first defining second line + * \param[in] B2 - second defining second line + * \param[in] IntersectionPoint - Container for intersection coordinates + */ + void ComputeLineIntersectionPoint( su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* IntersectionPoint ); + + /*! + * \brief For N-Dimensional grids, check whether a point is inside a triangle specified by 3 T points + * \param[in] Point - query point + * \param[in] T1 - first point of triangle T + * \param[in] T2 - second point of triangle T + * \param[in] T3 - third point of triangle T + */ + bool CheckPointInsideTriangle(su2double* Point, su2double* T1, su2double* T2, su2double* T3); + +}; diff --git a/Common/include/interpolation_structure.hpp b/Common/include/interpolation_structure.hpp deleted file mode 100644 index 115e477ef46b..000000000000 --- a/Common/include/interpolation_structure.hpp +++ /dev/null @@ -1,498 +0,0 @@ -/*! - * \file interpolation_structure.hpp - * \brief Headers of classes used for multiphysics interpolation. - * The implementation is in the interpolation_structure.cpp file. - * \author H. Kline - * \version 7.0.2 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "../../Common/include/mpi_structure.hpp" - -#include -#include -#include -#include -#include - -#include "CConfig.hpp" -#include "geometry/CGeometry.hpp" - -using namespace std; - - -/*! - * \class CInterpolator - * \brief Main class for defining the interpolator, it requires - * a child class for each particular interpolation method - * \author H. Kline - */ -class CInterpolator { -protected: - const int rank; /*!< \brief MPI Rank. */ - const int size; /*!< \brief MPI Size. */ - const unsigned donorZone; /*!< \brief Index of donor zone. */ - const unsigned targetZone; /*!< \brief Index of target zone. */ - - unsigned long - MaxLocalVertex_Donor, /*!< \brief Maximum vertices per processor*/ - nGlobalFace_Donor, /*!< \brief Number of global donor faces*/ - nGlobalFaceNodes_Donor, /*!< \brief Number of global donor face nodes*/ - MaxFace_Donor, /*!< \brief Maximum faces per processor*/ - MaxFaceNodes_Donor; /*!< \brief Maximum nodes associated with faces per processor*/ - - unsigned long - *Buffer_Receive_nVertex_Donor, /*!< \brief Buffer to store the number of vertices per processor on the Donor domain */ - *Buffer_Receive_nFace_Donor, /*!< \brief Buffer to store the number of faces per processor*/ - *Buffer_Receive_nFaceNodes_Donor, /*!< \brief Buffer to store the number of nodes associated with faces per processor*/ - *Buffer_Send_nVertex_Donor, /*!< \brief Buffer to send number of vertices on the local processor*/ - *Buffer_Send_nFace_Donor, /*!< \brief Buffer to send number of faces on the local processor*/ - *Buffer_Send_nFaceNodes_Donor, /*!< \brief Buffer to send the number of nodes assocated with faces per processor*/ - *Buffer_Send_FaceIndex, /*!< \brief Buffer to send indices pointing to the node indices that define the faces*/ - *Buffer_Receive_FaceIndex, /*!< \brief Buffer to receive indices pointing to the node indices that define the faces*/ - *Buffer_Send_FaceNodes, /*!< \brief Buffer to send indices pointing to the location of node information in other buffers, defining faces*/ - *Buffer_Receive_FaceNodes, /*!< \brief Buffer to receive indices pointing to the location of node information in other buffers, defining faces*/ - *Buffer_Send_FaceProc, /*!< \brief Buffer to send processor which stores the node indicated in Buffer_Receive_FaceNodes*/ - *Buffer_Receive_FaceProc; /*!< \brief Buffer to receive processor which stores the node indicated in Buffer_Receive_FaceNodes*/ - - long *Buffer_Send_GlobalPoint, /*!< \brief Buffer to send global point indices*/ - *Buffer_Receive_GlobalPoint; /*!< \brief Buffer to receive global point indices*/ - - su2double *Buffer_Send_Coord, /*!< \brief Buffer to send coordinate values*/ - *Buffer_Send_Normal, /*!< \brief Buffer to send normal vector values */ - *Buffer_Receive_Coord, /*!< \brief Buffer to receive coordinate values*/ - *Buffer_Receive_Normal; /*!< \brief Buffer to receive normal vector values*/ - - unsigned long *Receive_GlobalPoint, /*!< \brief Buffer to receive Global point indexes*/ - *Buffer_Receive_nLinkedNodes, /*!< \brief Buffer to receive the number of edges connected to each node*/ - *Buffer_Receive_LinkedNodes, /*!< \brief Buffer to receive the list of notes connected to the nodes through an edge*/ - *Buffer_Receive_StartLinkedNodes, /*!< \brief Buffer to receive the index of the Receive_LinkedNodes buffer where corresponding list of linked nodes begins */ - *Buffer_Receive_Proc; /*!< \brief Buffer to receive the thread that owns the node*/ - - unsigned long nGlobalVertex_Target, /*!< \brief Global number of vertex of the target boundary*/ - nLocalVertex_Target, /*!< \brief Number of vertex of the target boundary owned by the thread*/ - nGlobalVertex_Donor, /*!< \brief Global number of vertex of the donor boundary*/ - nLocalVertex_Donor, /*!< \brief Number of vertex of the donor boundary owned by the thread*/ - nGlobalVertex, /*!< \brief Dummy variable to temporarily store the global number of vertex of a boundary*/ - nLocalLinkedNodes; /*!< \brief Dummy variable to temporarily store the number of vertex of a boundary*/ - - CGeometry**** const Geometry; /*! \brief Vector which stores n zones of geometry. */ - CGeometry* const donor_geometry; /*! \brief Vector which stores the donor geometry. */ - CGeometry* const target_geometry; /*! \brief Vector which stores the target geometry. */ - - /*! - * \brief Constructor of the class, protected as it does not make sense to instantiate base class. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - index of the donor zone - * \param[in] jZone - index of the target zone - */ - CInterpolator(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - -public: - /*! - * \brief No default construction allowed. - */ - CInterpolator(void) = delete; - - /*! - * \brief Destructor of the class, nothing is deleted, derived classes need to manage the MPI buffers. - */ - virtual ~CInterpolator(void) = default; - - /*! - * \brief Set up transfer matrix defining relation between two meshes - * \note Main method that derived classes should implement. - * \param[in] config - Definition of the particular problem. - */ - inline virtual void Set_TransferCoeff(CConfig **config) {} - -protected: - /*! - * \brief Find the index of the interface marker shared by that zone - * \param[in] config - Definition of the particular problem. - * \param[in] val_marker_interface - Interface tag. - */ - int Find_InterfaceMarker(const CConfig *config, unsigned short val_marker_interface) const; - - /*! - * \brief Check whether an interface should be processed or not, i.e. if it is part of the zones. - * \param[in] val_markDonor - Marker tag from donor zone. - * \param[in] val_markTarget - Marker tag from target zone. - */ - bool CheckInterfaceBoundary(int val_markDonor, int val_markTarget) const; - - /*! - * \brief Recontstruct the boundary connectivity from parallel partitioning and broadcasts it to all threads - * \param[in] val_zone - index of the zone - * \param[in] val_marker - index of the marker - */ - void ReconstructBoundary(unsigned long val_zone, int val_marker); - - /*! - * \brief compute squared distance between 2 points - * \param[in] nDim - number of dimensions - * \param[in] point_i - coordinates of point i - * \param[in] point_j - coordinates of point j - */ - inline su2double PointsSquareDistance(unsigned short nDim, const su2double *point_i, const su2double *point_j) const { - su2double d = 0.0; - for(unsigned short iDim = 0; iDim < nDim; iDim++) - d += pow(point_j[iDim] - point_i[iDim], 2); - return d; - } - - /*! - * \brief compute distance between 2 points - * \param[in] nDim - number of dimensions - * \param[in] point_i - coordinates of point i - * \param[in] point_j - coordinates of point j - */ - inline su2double PointsDistance(unsigned short nDim, const su2double *point_i, const su2double *point_j) const { - return sqrt(PointsSquareDistance(nDim, point_i, point_j)); - } - - /*! - * \brief Determine array sizes used to collect and send coordinate and global point - * information. - * \param[in] faces - boolean that determines whether or not to set face information as well - * \param[in] markDonor - Index of the boundary on the donor domain. - * \param[in] markTarget - Index of the boundary on the target domain. - * \param[in] nVertexDonor - Number of vertices on the donor boundary. - * \param[in] nDim - number of physical dimensions. - */ - void Determine_ArraySize(bool faces, int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim); - - /*! - * \brief Collect and communicate vertex info: coord, global point, and if faces=true the normal vector - * \param[in] faces - boolean that determines whether or not to set face information as well - * \param[in] markDonor - Index of the boundary on the donor domain. - * \param[in] markTarget - Index of the boundary on the target domain. - * \param[in] nVertexDonor - Number of vertices on the donor boundary. - * \param[in] nDim - number of physical dimensions. - */ - void Collect_VertexInfo(bool faces, int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim); - -}; - -/*! - * \brief Nearest Neighbor interpolation - */ -class CNearestNeighbor final : public CInterpolator { -public: - /*! - * \brief Constructor of the class. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - index of the donor zone - * \param[in] jZone - index of the target zone - */ - CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - - /*! - * \brief Set up transfer matrix defining relation between two meshes - * \param[in] config - Definition of the particular problem. - */ - void Set_TransferCoeff(CConfig **config) override; - -}; - -/*! - * \brief Isoparametric interpolation - */ -class CIsoparametric final : public CInterpolator { -public: - /*! - * \brief Constructor of the class. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - index of the donor zone - * \param[in] jZone - index of the target zone - */ - CIsoparametric(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - - /*! - * \brief Set up transfer matrix defining relation between two meshes - * \param[in] config - Definition of the particular problem. - */ - void Set_TransferCoeff(CConfig **config) override; - -private: - /*! - * \brief Calculate the isoparametric representation of point iVertex in marker iZone_0 by nodes of element donor_elem in marker jMarker of zone iZone_1. - * \param[in] iVertex - vertex index of the point being interpolated. - * \param[in] nDim - the dimension of the coordinates. - * \param[in] iZone_1 - zone index of the element to use for interpolation (the DONOR zone) - * \param[in] donor_elem - element index of the element to use for interpolation (or global index of a point in 2D) - * \param[in] nDonorPoints - number of donor points in the element. - * \param[in] xj - point projected onto the plane of the donor element. - * \param[out] isoparams - isoparametric coefficients. Must be allocated to size nNodes ahead of time. (size> nDonors) - * - * \note If the problem is 2D, the 'face' projected onto is actually an edge; the local index - * of the edge is then stored in iFace, and the global index of the node (from which the edge - * is referenced) - */ - void Isoparameters(unsigned short nDim, unsigned short nDonor, su2double *X, su2double *xj,su2double* isoparams); - -}; - -/*! - * \brief Mirror interpolation: copy point linking and coefficient values from the opposing mesh - * Assumes that the oppoosing mesh has already run interpolation. (otherwise this will result in empty/trivial interpolation) - */ -class CMirror final : public CInterpolator { -public: - /*! - * \brief Constructor of the class. - * \note Data is set in geometry[targetZone]. - * \param[in] geometry_container - * \param[in] config - config container - * \param[in] iZone - First zone - * \param[in] jZone - Second zone - */ - CMirror(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - - /*! - * \brief Set up transfer matrix defining relation between two meshes - * \param[in] config - Definition of the particular problem. - */ - void Set_TransferCoeff(CConfig **config) override; - -}; - -/*! - * \brief Sliding mesh approach - */ -class CSlidingMesh final : public CInterpolator { -public: - /*! - * \brief Constructor of the class. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - index of the donor zone - * \param[in] jZone - index of the target zone - */ - CSlidingMesh(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - - /*! - * \brief Set up transfer matrix defining relation between two meshes - * \param[in] config - Definition of the particular problem. - */ - void Set_TransferCoeff(CConfig **config) override; - -private: - /*! - * \brief For 3-Dimensional grids, build the dual surface element - * \param[in] map - array containing the index of the boundary points connected to the node - * \param[in] startIndex - for each vertex specifies the corresponding index in the global array containing the indexes of all its neighbouring vertexes - * \param[in] nNeighbour - for each vertex specifies the number of its neighbouring vertexes (on the boundary) - * \param[in] coord - array containing the coordinates of all the boundary vertexes - * \param[in] centralNode - label of the vertex around which the dual surface element is built - * \param[in] element - double array where element node coordinates will be stored - */ - int Build_3D_surface_element(unsigned long *map, unsigned long *startIndex, unsigned long* nNeighbor, - su2double *coord, unsigned long centralNode, su2double** element); - - /*! - * \brief For 2-Dimensional grids, compute intersection length of two segments projected along a given direction - * \param[in] A1 - first point of segment A - * \param[in] A2 - second point of segment A - * \param[in] B1 - first point of segment B - * \param[in] B2 - second point of segment B - * \param[in] Direction - along which segments are projected - */ - su2double ComputeLineIntersectionLength(su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* Direction); - - /*! - * \brief For 3-Dimensional grids, compute intersection area between two triangle projected on a given plane - * \param[in] A1 - first point of triangle A - * \param[in] A2 - second point of triangle A - * \param[in] A3 - third point of triangle A - * \param[in] B1 - first point of triangle B - * \param[in] B2 - second point of triangle B - * \param[in] B3 - third point of triangle B - * \param[in] Direction - vector normal to projection plane - */ - su2double Compute_Triangle_Intersection(su2double* A1, su2double* A2, su2double* A3, su2double* B1, su2double* B2, su2double* B3, su2double* Direction); - - /*! - * \brief For 3-Dimensional grids, compute intersection area between two triangle projected on a given plane - * P1 from triangle P MUST be inside triangle Q, points order doesn't matter - * \param[in] P1 - first point of triangle A - * \param[in] P2 - second point of triangle A - * \param[in] P3 - third point of triangle A - * \param[in] Q1 - first point of triangle B - * \param[in] Q2 - second point of triangle B - * \param[in] Q3 - third point of triangle B - */ - su2double ComputeIntersectionArea( su2double* P1, su2double* P2, su2double* P3, su2double* Q1, su2double* Q2, su2double* Q3 ); - - /*! - * \brief For 2-Dimensional grids, check whether, and compute, two lines are intersecting - * \param[in] A1 - first defining first line - * \param[in] A2 - second defining first line - * \param[in] B1 - first defining second line - * \param[in] B2 - second defining second line - * \param[in] IntersectionPoint - Container for intersection coordinates - */ - void ComputeLineIntersectionPoint( su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* IntersectionPoint ); - - /*! - * \brief For N-Dimensional grids, check whether a point is inside a triangle specified by 3 T points - * \param[in] Point - query point - * \param[in] T1 - first point of triangle T - * \param[in] T2 - second point of triangle T - * \param[in] T3 - third point of triangle T - */ - bool CheckPointInsideTriangle(su2double* Point, su2double* T1, su2double* T2, su2double* T3); - -}; - -/*! - * \brief Radial basis function interpolation - */ -class CRadialBasisFunction final : public CInterpolator { -public: - /*! - * \brief Constructor of the class. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - index of the donor zone - * \param[in] jZone - index of the target zone - */ - CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - - /*! - * \brief Set up transfer matrix defining relation between two meshes - * \param[in] config - Definition of the particular problem. - */ - void Set_TransferCoeff(CConfig **config) override; - - /*! - * \brief Compute the value of a radial basis function, this is static so it can be re-used. - * \param[in] type - of radial basis function - * \param[in] radius - the characteristic dimension - * \param[in] dist - distance - * \return value of the RBF. - */ - static su2double Get_RadialBasisValue(ENUM_RADIALBASIS type, const su2double radius, const su2double dist); - -private: - /*! - * \brief Compute the RBF "generator" matrix with or without polynomial terms. - * \note Multiplying C_inv_trunc by a column vector gives specific coefficients for given "known values", - * conversely, multiplying (on the left) by a row vector of polynomial and RBF values gives generic - * interpolation coefficients for a given target evaluation point. - * \param[in] type - Type of radial basis function. - * \param[in] usePolynomial - Whether to use polynomial terms. - * \param[in] radius - Normalizes point-to-point distance when computing RBF values. - * \param[in] coords - Coordinates of the donor points. - * \param[out] nPolynomial - Num of poly terms, -1 if !usePolynomial, nDim-1 if coords lie on plane, else nDim. - * \param[out] keepPolynomialRow - Size nDim, signals which (if any) iDim was removed from polynomial term. - * \param[out] C_inv_trunc - The generator matrix as described above. - */ - void ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool usePolynomial, su2double radius, - const su2activematrix& coords, int& nPolynomial, - vector& keepPolynomialRow, su2passivematrix& C_inv_trunc) const; - - /*! - * \brief If the polynomial term is included in the interpolation, and the points lie on a plane, the matrix - * becomes rank deficient and cannot be inverted. This method detects that condition and corrects it by - * removing a row from P (the polynomial part of the interpolation matrix). - * \param[in] max_diff_tol - Tolerance to detect whether points are on a plane. - * \param[out] keep_row - Marks the dimensions of P kept. - * \param[in,out] P - Polynomial part of the interpolation matrix, one row may be eliminated. - * \return n_polynomial - Size of the polynomial part on exit (in practice nDim or nDim-1). - */ - int CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, su2passivematrix &P) const; - - /*! - * \brief Prunes (by setting to zero) small interpolation coefficients, i.e. - * <= tolerance*max(abs(coeffs)). The vector is re-scaled such that sum(coeffs)==1. - * \param[in] tolerance - Relative pruning tolerance. - * \param[in,out] coeffs - The vector of interpolation coefficients. - * \return Number of non-zero coefficients after pruning. - */ - int PruneSmallCoefficients(passivedouble tolerance, su2passivevector& coeffs) const; - -}; - -/*! - * \brief Helper class used by CRadialBasisFunction to compute the interpolation weights. - * The matrix is symmetric but full storage is used as that gives much better performance - * for some BLAS libraries (notably OpenBLAS). The code should be compiled with LAPACK - * to use optimized matrix inversion and multiplication routines. - */ -class CSymmetricMatrix{ -private: - enum DecompositionType { NONE, CHOLESKY, LU }; - - vector val_vec, decomp_vec; - vector perm_vec; - int sz = 0; - bool initialized = false; - DecompositionType decomposed = NONE; - - inline void CheckBounds(int i, int j) const { - assert(initialized && "Matrix not initialized."); - assert(i>=0 && i=0 && j. + */ + +#include "../../include/interface_interpolation/CInterpolator.hpp" +#include "../../include/CConfig.hpp" +#include "../../include/geometry/CGeometry.hpp" + + +CInterpolator::CInterpolator(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : + rank(SU2_MPI::GetRank()), + size(SU2_MPI::GetSize()), + donorZone(iZone), + targetZone(jZone), + Geometry(geometry_container), + donor_geometry(geometry_container[iZone][INST_0][MESH_0]), + target_geometry(geometry_container[jZone][INST_0][MESH_0]) { +} + +int CInterpolator::Find_InterfaceMarker(const CConfig *config, unsigned short val_marker_interface) const { + + for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + /*--- If the tag GetMarker_All_ZoneInterface(iMarker) equals the interface we are looking for. ---*/ + if (config->GetMarker_All_ZoneInterface(iMarker) == val_marker_interface) return iMarker; + } + return -1; +} + +bool CInterpolator::CheckInterfaceBoundary(int markDonor, int markTarget) const { + + /*--- Determine whether the boundary is not on the rank because of + * the partition or because it is not part of the zone. ---*/ + int donorCheck = -1, targetCheck = -1; + SU2_MPI::Allreduce(&markDonor, &donorCheck, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&markTarget, &targetCheck, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); + return (donorCheck != -1) && (targetCheck != -1); +} + +void CInterpolator::Determine_ArraySize(bool faces, int markDonor, int markTarget, + unsigned long nVertexDonor, unsigned short nDim) { + + unsigned long nLocalVertex_Donor = 0, nLocalFaceNodes_Donor=0, nLocalFace_Donor=0; + unsigned long iVertex, iPointDonor = 0; + /* Only needed if face data is also collected */ + unsigned long inode; + unsigned long donor_elem, jElem, jPoint; + unsigned short iDonor; + unsigned int nFaces=0, iFace, nNodes=0; + bool face_on_marker = true; + + for (iVertex = 0; iVertex < nVertexDonor; iVertex++) { + iPointDonor = donor_geometry->vertex[markDonor][iVertex]->GetNode(); + + if (!donor_geometry->node[iPointDonor]->GetDomain()) continue; + + nLocalVertex_Donor++; + + if (!faces) continue; + + /*--- On Donor geometry also communicate face info ---*/ + if (nDim==3) { + for (jElem=0; jElemnode[iPointDonor]->GetnElem(); jElem++) { + donor_elem = donor_geometry->node[iPointDonor]->GetElem(jElem); + nFaces = donor_geometry->elem[donor_elem]->GetnFaces(); + for (iFace=0; iFaceelem[donor_elem]->GetnNodesFace(iFace); + for (iDonor=0; iDonorelem[donor_elem]->GetFaces(iFace, iDonor); + jPoint = donor_geometry->elem[donor_elem]->GetNode(inode); + face_on_marker = (face_on_marker && (donor_geometry->node[jPoint]->GetVertex(markDonor) !=-1)); + } + if (face_on_marker ) { + nLocalFace_Donor++; + nLocalFaceNodes_Donor+=nNodes; + } + } + } + } + else { + /*--- in 2D we use the edges ---*/ + nNodes=2; + nFaces = donor_geometry->node[iPointDonor]->GetnPoint(); + for (iFace=0; iFacenode[iPointDonor]->GetEdge(iFace); + jPoint = donor_geometry->edge[inode]->GetNode(iDonor); + face_on_marker = (face_on_marker && (donor_geometry->node[jPoint]->GetVertex(markDonor) !=-1)); + } + if (face_on_marker ) { + nLocalFace_Donor++; + nLocalFaceNodes_Donor+=nNodes; + } + } + } + } + + Buffer_Send_nVertex_Donor[0] = nLocalVertex_Donor; + if (faces) { + Buffer_Send_nFace_Donor[0] = nLocalFace_Donor; + Buffer_Send_nFaceNodes_Donor[0] = nLocalFaceNodes_Donor; + } + + /*--- Send Interface vertex information --*/ + SU2_MPI::Allreduce(&nLocalVertex_Donor, &MaxLocalVertex_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nVertex_Donor, 1, MPI_UNSIGNED_LONG, + Buffer_Receive_nVertex_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + if (faces) { + SU2_MPI::Allreduce(&nLocalFace_Donor, &nGlobalFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalFace_Donor, &MaxFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &nGlobalFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &MaxFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nFace_Donor, 1, MPI_UNSIGNED_LONG, + Buffer_Receive_nFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, + Buffer_Receive_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + MaxFace_Donor++; + } +} + +void CInterpolator::Collect_VertexInfo(bool faces, int markDonor, int markTarget, + unsigned long nVertexDonor, unsigned short nDim) { + + unsigned long iVertex, iPointDonor = 0, iVertexDonor, nBuffer_Coord, nBuffer_Point, nLocalVertex_Donor; + unsigned short iDim; + + for (iVertex = 0; iVertex < MaxLocalVertex_Donor; iVertex++) Buffer_Send_GlobalPoint[iVertex] = -1; + + for (iVertex = 0; iVertex < MaxLocalVertex_Donor*nDim; iVertex++) Buffer_Send_Coord[iVertex] = 0.0; + + if(faces) + for (iVertex = 0; iVertex < MaxLocalVertex_Donor*nDim; iVertex++) Buffer_Send_Normal[iVertex] = 0.0; + + /*--- Copy coordinates and point to the auxiliar vector --*/ + nLocalVertex_Donor = 0; + + for (iVertexDonor = 0; iVertexDonor < nVertexDonor; iVertexDonor++) { + iPointDonor = donor_geometry->vertex[markDonor][iVertexDonor]->GetNode(); + if (donor_geometry->node[iPointDonor]->GetDomain()) { + Buffer_Send_GlobalPoint[nLocalVertex_Donor] = donor_geometry->node[iPointDonor]->GetGlobalIndex(); + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[nLocalVertex_Donor*nDim+iDim] = donor_geometry->node[iPointDonor]->GetCoord(iDim); + + if (faces) { + const su2double* Normal = donor_geometry->vertex[markDonor][iVertexDonor]->GetNormal(); + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Normal[nLocalVertex_Donor*nDim+iDim] = Normal[iDim]; + } + nLocalVertex_Donor++; + } + } + nBuffer_Coord = MaxLocalVertex_Donor*nDim; + nBuffer_Point = MaxLocalVertex_Donor; + + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, + Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_GlobalPoint, nBuffer_Point, MPI_LONG, + Buffer_Receive_GlobalPoint, nBuffer_Point, MPI_LONG, MPI_COMM_WORLD); + if (faces) { + SU2_MPI::Allgather(Buffer_Send_Normal, nBuffer_Coord, MPI_DOUBLE, + Buffer_Receive_Normal, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); + } +} + +void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ + + CGeometry *geom = Geometry[val_zone][INST_0][MESH_0]; + + unsigned long iVertex, jVertex, kVertex; + + unsigned long count, iTmp, *uptr, dPoint, EdgeIndex, jEdge, nEdges, nNodes, nVertex, iDim, nDim, iPoint; + + unsigned long nGlobalLinkedNodes, nLocalVertex, nLocalLinkedNodes; + + nDim = geom->GetnDim(); + + if( val_marker != -1 ) + nVertex = geom->GetnVertex( val_marker ); + else + nVertex = 0; + + + su2double *Buffer_Send_Coord = new su2double [ nVertex * nDim ]; + unsigned long *Buffer_Send_GlobalPoint = new unsigned long [ nVertex ]; + + unsigned long *Buffer_Send_nLinkedNodes = new unsigned long [ nVertex ]; + unsigned long *Buffer_Send_StartLinkedNodes = new unsigned long [ nVertex ]; + unsigned long **Aux_Send_Map = new unsigned long*[ nVertex ]; + +#ifdef HAVE_MPI + int nProcessor = size, iRank; + unsigned long iTmp2, tmp_index, tmp_index_2; +#endif + + /*--- Copy coordinates and point to the auxiliar vector ---*/ + + nGlobalVertex = 0; + nLocalVertex = 0; + nLocalLinkedNodes = 0; + + for (iVertex = 0; iVertex < nVertex; iVertex++) { + + Buffer_Send_nLinkedNodes[iVertex] = 0; + Aux_Send_Map[iVertex] = NULL; + + iPoint = geom->vertex[val_marker][iVertex]->GetNode(); + + if (geom->node[iPoint]->GetDomain()) { + Buffer_Send_GlobalPoint[nLocalVertex] = geom->node[iPoint]->GetGlobalIndex(); + + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[nLocalVertex*nDim+iDim] = geom->node[iPoint]->GetCoord(iDim); + + nNodes = 0; + nEdges = geom->node[iPoint]->GetnPoint(); + + for (jEdge = 0; jEdge < nEdges; jEdge++){ + EdgeIndex = geom->node[iPoint]->GetEdge(jEdge); + + if( iPoint == geom->edge[EdgeIndex]->GetNode(0) ) + dPoint = geom->edge[EdgeIndex]->GetNode(1); + else + dPoint = geom->edge[EdgeIndex]->GetNode(0); + + if ( geom->node[dPoint]->GetVertex(val_marker) != -1 ) + nNodes++; + } + + Buffer_Send_StartLinkedNodes[nLocalVertex] = nLocalLinkedNodes; + Buffer_Send_nLinkedNodes[nLocalVertex] = nNodes; + + nLocalLinkedNodes += nNodes; + + Aux_Send_Map[nLocalVertex] = new unsigned long[ nNodes ]; + nNodes = 0; + + for (jEdge = 0; jEdge < nEdges; jEdge++){ + EdgeIndex = geom->node[iPoint]->GetEdge(jEdge); + + if( iPoint == geom->edge[EdgeIndex]->GetNode(0) ) + dPoint = geom->edge[EdgeIndex]->GetNode(1); + else + dPoint = geom->edge[EdgeIndex]->GetNode(0); + + if ( geom->node[dPoint]->GetVertex(val_marker) != -1 ){ + Aux_Send_Map[nLocalVertex][nNodes] = geom->node[dPoint]->GetGlobalIndex(); + nNodes++; + } + } + nLocalVertex++; + } + } + + unsigned long *Buffer_Send_LinkedNodes = new unsigned long [ nLocalLinkedNodes ]; + + nLocalLinkedNodes = 0; + + for (iVertex = 0; iVertex < nLocalVertex; iVertex++){ + for (jEdge = 0; jEdge < Buffer_Send_nLinkedNodes[iVertex]; jEdge++){ + Buffer_Send_LinkedNodes[nLocalLinkedNodes] = Aux_Send_Map[iVertex][jEdge]; + nLocalLinkedNodes++; + } + } + + for (iVertex = 0; iVertex < nVertex; iVertex++){ + if( Aux_Send_Map[iVertex] != NULL ) + delete [] Aux_Send_Map[iVertex]; + } + delete [] Aux_Send_Map; Aux_Send_Map = NULL; + + /*--- Reconstruct boundary by gathering data from all ranks ---*/ + + SU2_MPI::Allreduce( &nLocalVertex, &nGlobalVertex, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalLinkedNodes, &nGlobalLinkedNodes, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + + Buffer_Receive_Coord = new su2double [ nGlobalVertex * nDim ]; + Buffer_Receive_GlobalPoint = new long[ nGlobalVertex ]; + Buffer_Receive_Proc = new unsigned long[ nGlobalVertex ]; + + Buffer_Receive_nLinkedNodes = new unsigned long[ nGlobalVertex ]; + Buffer_Receive_LinkedNodes = new unsigned long[ nGlobalLinkedNodes ]; + Buffer_Receive_StartLinkedNodes = new unsigned long[ nGlobalVertex ]; + +#ifdef HAVE_MPI + if (rank == MASTER_NODE){ + + for (iVertex = 0; iVertex < nDim*nLocalVertex; iVertex++) + Buffer_Receive_Coord[iVertex] = Buffer_Send_Coord[iVertex]; + + for (iVertex = 0; iVertex < nLocalVertex; iVertex++){ + Buffer_Receive_GlobalPoint[iVertex] = Buffer_Send_GlobalPoint[iVertex]; + Buffer_Receive_Proc[iVertex] = MASTER_NODE; + Buffer_Receive_nLinkedNodes[iVertex] = Buffer_Send_nLinkedNodes[iVertex]; + Buffer_Receive_StartLinkedNodes[iVertex] = Buffer_Send_StartLinkedNodes[iVertex]; + } + + for (iVertex = 0; iVertex < nLocalLinkedNodes; iVertex++) + Buffer_Receive_LinkedNodes[iVertex] = Buffer_Send_LinkedNodes[iVertex]; + + tmp_index = nLocalVertex; + tmp_index_2 = nLocalLinkedNodes; + + for(iRank = 1; iRank < nProcessor; iRank++){ + + SU2_MPI::Recv( &iTmp2, 1, MPI_UNSIGNED_LONG, iRank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + SU2_MPI::Recv(&Buffer_Receive_LinkedNodes[tmp_index_2], iTmp2, MPI_UNSIGNED_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + SU2_MPI::Recv( &iTmp, 1, MPI_UNSIGNED_LONG, iRank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + SU2_MPI::Recv(&Buffer_Receive_Coord[tmp_index*nDim], nDim*iTmp, MPI_DOUBLE, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + SU2_MPI::Recv( &Buffer_Receive_GlobalPoint[tmp_index], iTmp, MPI_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + SU2_MPI::Recv( &Buffer_Receive_nLinkedNodes[tmp_index], iTmp, MPI_UNSIGNED_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + SU2_MPI::Recv(&Buffer_Receive_StartLinkedNodes[tmp_index], iTmp, MPI_UNSIGNED_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + for (iVertex = 0; iVertex < iTmp; iVertex++){ + Buffer_Receive_Proc[ tmp_index + iVertex ] = iRank; + Buffer_Receive_StartLinkedNodes[ tmp_index + iVertex ] += tmp_index_2; + } + + tmp_index += iTmp; + tmp_index_2 += iTmp2; + } + } + else{ + SU2_MPI::Send( &nLocalLinkedNodes, 1, MPI_UNSIGNED_LONG, 0, 0, MPI_COMM_WORLD); + SU2_MPI::Send(Buffer_Send_LinkedNodes, nLocalLinkedNodes, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); + + SU2_MPI::Send( &nLocalVertex, 1, MPI_UNSIGNED_LONG, 0, 0, MPI_COMM_WORLD); + SU2_MPI::Send(Buffer_Send_Coord, nDim * nLocalVertex, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD); + + SU2_MPI::Send( Buffer_Send_GlobalPoint, nLocalVertex, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); + SU2_MPI::Send( Buffer_Send_nLinkedNodes, nLocalVertex, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); + SU2_MPI::Send(Buffer_Send_StartLinkedNodes, nLocalVertex, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); + } +#else + for (iVertex = 0; iVertex < nDim * nGlobalVertex; iVertex++) + Buffer_Receive_Coord[iVertex] = Buffer_Send_Coord[iVertex]; + + for (iVertex = 0; iVertex < nGlobalVertex; iVertex++){ + Buffer_Receive_GlobalPoint[iVertex] = Buffer_Send_GlobalPoint[iVertex]; + Buffer_Receive_Proc[iVertex] = MASTER_NODE; + Buffer_Receive_nLinkedNodes[iVertex] = Buffer_Send_nLinkedNodes[iVertex]; + Buffer_Receive_StartLinkedNodes[iVertex] = Buffer_Send_StartLinkedNodes[iVertex]; + } + + for (iVertex = 0; iVertex < nGlobalLinkedNodes; iVertex++) + Buffer_Receive_LinkedNodes[iVertex] = Buffer_Send_LinkedNodes[iVertex]; +#endif + + if (rank == MASTER_NODE){ + for (iVertex = 0; iVertex < nGlobalVertex; iVertex++){ + count = 0; + uptr = &Buffer_Receive_LinkedNodes[ Buffer_Receive_StartLinkedNodes[iVertex] ]; + + for (jVertex = 0; jVertex < Buffer_Receive_nLinkedNodes[iVertex]; jVertex++){ + iTmp = uptr[ jVertex ]; + for (kVertex = 0; kVertex < nGlobalVertex; kVertex++){ + if( Buffer_Receive_GlobalPoint[kVertex] == long(iTmp) ){ + uptr[ jVertex ] = kVertex; + count++; + break; + } + } + + if( count != (jVertex+1) ){ + for (kVertex = jVertex; kVertex < Buffer_Receive_nLinkedNodes[iVertex]-1; kVertex++){ + uptr[ kVertex ] = uptr[ kVertex + 1]; + } + Buffer_Receive_nLinkedNodes[iVertex]--; + jVertex--; + } + } + } + } + + SU2_MPI::Bcast(Buffer_Receive_GlobalPoint, nGlobalVertex, MPI_LONG, 0, MPI_COMM_WORLD); + SU2_MPI::Bcast(Buffer_Receive_Coord, nGlobalVertex*nDim, MPI_DOUBLE, 0, MPI_COMM_WORLD); + SU2_MPI::Bcast(Buffer_Receive_Proc, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); + + SU2_MPI::Bcast(Buffer_Receive_nLinkedNodes, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); + SU2_MPI::Bcast(Buffer_Receive_StartLinkedNodes, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); + SU2_MPI::Bcast(Buffer_Receive_LinkedNodes, nGlobalLinkedNodes, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); + + delete [] Buffer_Send_Coord; Buffer_Send_Coord = NULL; + delete [] Buffer_Send_GlobalPoint; Buffer_Send_GlobalPoint = NULL; + delete [] Buffer_Send_LinkedNodes; Buffer_Send_LinkedNodes = NULL; + delete [] Buffer_Send_nLinkedNodes; Buffer_Send_nLinkedNodes = NULL; + delete [] Buffer_Send_StartLinkedNodes; Buffer_Send_StartLinkedNodes = NULL; + +} diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp new file mode 100644 index 000000000000..0d42834b6a29 --- /dev/null +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -0,0 +1,563 @@ +/*! + * \file CIsoparametric.cpp + * \brief Implementation isoparametric interpolation (using FE shape functions). + * \author H. Kline + * \version 7.0.2 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "../../include/interface_interpolation/CIsoparametric.hpp" +#include "../../include/CConfig.hpp" +#include "../../include/geometry/CGeometry.hpp" + + +CIsoparametric::CIsoparametric(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, + unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { + Set_TransferCoeff(config); +} + +void CIsoparametric::Set_TransferCoeff(CConfig **config) { + + unsigned long iVertex, jVertex; + unsigned long dPoint, inode, jElem, nElem; + unsigned short iDim, iDonor=0, iFace; + + unsigned short nDim = donor_geometry->GetnDim(); + + unsigned short nMarkerInt; + unsigned short iMarkerInt; + + int markDonor=0, markTarget=0; + + long donor_elem=0, temp_donor=0; + unsigned int nNodes=0; + /*--- Restricted to 2-zone for now ---*/ + unsigned int nFaces=1; //For 2D cases, we want to look at edges, not faces, as the 'interface' + bool face_on_marker=true; + + unsigned long nVertexDonor = 0, nVertexTarget= 0; + unsigned long Point_Target = 0; + + unsigned long iVertexDonor, iPointDonor = 0; + int iProcessor; + + unsigned long nLocalFace_Donor = 0, nLocalFaceNodes_Donor=0; + + unsigned long faceindex; + + su2double dist = 0.0, mindist=1E6, *Coord, *Coord_i; + su2double myCoeff[10]; // Maximum # of donor points + su2double *Normal; + su2double *projected_point = new su2double[nDim]; + su2double tmp, tmp2; + su2double storeCoeff[10]; + unsigned long storeGlobal[10]; + int storeProc[10]; + + int nProcessor = size; + Coord = new su2double[nDim]; + Normal = new su2double[nDim]; + + nMarkerInt = (config[donorZone]->GetMarker_n_ZoneInterface())/2; + + /*--- For the number of markers on the interface... ---*/ + for (iMarkerInt=1; iMarkerInt <= nMarkerInt; iMarkerInt++) { + /*--- Procedure: + * -Loop through vertices of the aero grid + * -Find nearest element and allocate enough space in the aero grid donor point info + * -set the transfer coefficient values + */ + + /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ + markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + + /*--- On the target side: find the tag of the boundary sharing the interface ---*/ + markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); + + /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ + if(!CheckInterfaceBoundary(markDonor, markTarget)) continue; + + if(markDonor != -1) + nVertexDonor = donor_geometry->GetnVertex( markDonor ); + else + nVertexDonor = 0; + + if(markTarget != -1) + nVertexTarget = target_geometry->GetnVertex( markTarget ); + else + nVertexTarget = 0; + + Buffer_Send_nVertex_Donor = new unsigned long [1]; + Buffer_Send_nFace_Donor = new unsigned long [1]; + Buffer_Send_nFaceNodes_Donor = new unsigned long [1]; + + Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; + Buffer_Receive_nFace_Donor = new unsigned long [nProcessor]; + Buffer_Receive_nFaceNodes_Donor = new unsigned long [nProcessor]; + + /* Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor */ + Determine_ArraySize(true, markDonor, markTarget, nVertexDonor, nDim); + + Buffer_Send_Coord = new su2double [MaxLocalVertex_Donor*nDim]; + Buffer_Send_Normal = new su2double [MaxLocalVertex_Donor*nDim]; + Buffer_Send_GlobalPoint = new long [MaxLocalVertex_Donor]; + + Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_Donor*nDim]; + Buffer_Receive_Normal = new su2double [nProcessor*MaxLocalVertex_Donor*nDim]; + Buffer_Receive_GlobalPoint = new long [nProcessor*MaxLocalVertex_Donor]; + + /*-- Collect coordinates, global points, and normal vectors ---*/ + Collect_VertexInfo(true, markDonor,markTarget,nVertexDonor,nDim); + + Buffer_Send_FaceIndex = new unsigned long[MaxFace_Donor]; + Buffer_Send_FaceNodes = new unsigned long[MaxFaceNodes_Donor]; + Buffer_Send_FaceProc = new unsigned long[MaxFaceNodes_Donor]; + + Buffer_Receive_FaceIndex = new unsigned long[MaxFace_Donor*nProcessor]; + Buffer_Receive_FaceNodes = new unsigned long[MaxFaceNodes_Donor*nProcessor]; + Buffer_Receive_FaceProc = new unsigned long[MaxFaceNodes_Donor*nProcessor]; + + nLocalFace_Donor=0; + nLocalFaceNodes_Donor=0; + + /*--- Collect Face info ---*/ + + for (iVertex = 0; iVertex < MaxFace_Donor; iVertex++) { + Buffer_Send_FaceIndex[iVertex] = 0; + } + for (iVertex=0; iVertexvertex[markDonor][iVertexDonor]->GetNode(); + + if (donor_geometry->node[iPointDonor]->GetDomain()) { + + if (nDim==3) nElem = donor_geometry->node[iPointDonor]->GetnElem(); + else nElem =donor_geometry->node[iPointDonor]->GetnPoint(); + + for (jElem=0; jElem < nElem; jElem++) { + if (nDim==3) { + temp_donor = donor_geometry->node[iPointDonor]->GetElem(jElem); + nFaces = donor_geometry->elem[temp_donor]->GetnFaces(); + for (iFace=0; iFaceelem[temp_donor]->GetnNodesFace(iFace); + for (iDonor=0; iDonorelem[temp_donor]->GetFaces(iFace, iDonor); + dPoint = donor_geometry->elem[temp_donor]->GetNode(inode); + face_on_marker = (face_on_marker && (donor_geometry->node[dPoint]->GetVertex(markDonor) !=-1)); + } + + if (face_on_marker ) { + for (iDonor=0; iDonorelem[temp_donor]->GetFaces(iFace, iDonor); + dPoint = donor_geometry->elem[temp_donor]->GetNode(inode); + // Match node on the face to the correct global index + long jGlobalPoint = donor_geometry->node[dPoint]->GetGlobalIndex(); + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (jVertex = 0; jVertex < Buffer_Receive_nVertex_Donor[iProcessor]; jVertex++) { + if (jGlobalPoint == Buffer_Receive_GlobalPoint[MaxLocalVertex_Donor*iProcessor+jVertex]) { + Buffer_Send_FaceNodes[nLocalFaceNodes_Donor]=MaxLocalVertex_Donor*iProcessor+jVertex; + Buffer_Send_FaceProc[nLocalFaceNodes_Donor]=iProcessor; + } + } + } + nLocalFaceNodes_Donor++; // Increment total number of face-nodes / processor + } + /* Store the indices */ + Buffer_Send_FaceIndex[nLocalFace_Donor+1] = Buffer_Send_FaceIndex[nLocalFace_Donor]+nNodes; + nLocalFace_Donor++; // Increment number of faces / processor + } + } + } + else { + /*-- Determine whether this face/edge is on the marker --*/ + face_on_marker=true; + for (iDonor=0; iDonornode[iPointDonor]->GetEdge(jElem); + dPoint = donor_geometry->edge[inode]->GetNode(iDonor); + face_on_marker = (face_on_marker && (donor_geometry->node[dPoint]->GetVertex(markDonor) !=-1)); + } + if (face_on_marker ) { + for (iDonor=0; iDonornode[iPointDonor]->GetEdge(jElem); + dPoint = donor_geometry->edge[inode]->GetNode(iDonor); + // Match node on the face to the correct global index + long jGlobalPoint = donor_geometry->node[dPoint]->GetGlobalIndex(); + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (jVertex = 0; jVertex < Buffer_Receive_nVertex_Donor[iProcessor]; jVertex++) { + if (jGlobalPoint == Buffer_Receive_GlobalPoint[MaxLocalVertex_Donor*iProcessor+jVertex]) { + Buffer_Send_FaceNodes[nLocalFaceNodes_Donor]=MaxLocalVertex_Donor*iProcessor+jVertex; + Buffer_Send_FaceProc[nLocalFaceNodes_Donor]=iProcessor; + } + } + } + nLocalFaceNodes_Donor++; // Increment total number of face-nodes / processor + } + /* Store the indices */ + Buffer_Send_FaceIndex[nLocalFace_Donor+1] = Buffer_Send_FaceIndex[nLocalFace_Donor]+nNodes; + nLocalFace_Donor++; // Increment number of faces / processor + } + } + } + } + } + + //Buffer_Send_FaceIndex[nLocalFace_Donor+1] = MaxFaceNodes_Donor*rank+nLocalFaceNodes_Donor; + + SU2_MPI::Allgather(Buffer_Send_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, + Buffer_Receive_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_FaceProc, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, + Buffer_Receive_FaceProc, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, + Buffer_Receive_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + /*--- Loop over the vertices on the target Marker ---*/ + for (iVertex = 0; iVertexvertex[markTarget][iVertex]->GetNode(); + + if (!target_geometry->node[Point_Target]->GetDomain()) continue; + + Coord_i = target_geometry->node[Point_Target]->GetCoord(); + /*---Loop over the faces previously communicated/stored ---*/ + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + + nFaces = (unsigned int)Buffer_Receive_nFace_Donor[iProcessor]; + + for (iFace = 0; iFace< nFaces; iFace++) { + /*--- ---*/ + + nNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1] - + (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; + + su2double *X = new su2double[nNodes*(nDim+1)]; + faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face + for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetDonorElem(donor_elem); // in 2D is nearest neighbor + target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nNodes); + for (iDonor=0; iDonorvertex[markTarget][iVertex]->GetnDonorPoints(); + target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); + + for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,storeGlobal[iDonor]); + //cout <vertex[markTarget][iVertex]->SetDonorCoeff(iDonor,storeCoeff[iDonor]); + target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); + } + + } + + delete[] Buffer_Send_nVertex_Donor; + delete[] Buffer_Send_nFace_Donor; + delete[] Buffer_Send_nFaceNodes_Donor; + + delete[] Buffer_Receive_nVertex_Donor; + delete[] Buffer_Receive_nFace_Donor; + delete[] Buffer_Receive_nFaceNodes_Donor; + + delete[] Buffer_Send_Coord; + delete[] Buffer_Send_Normal; + delete[] Buffer_Send_GlobalPoint; + + delete[] Buffer_Receive_Coord; + delete[] Buffer_Receive_Normal; + delete[] Buffer_Receive_GlobalPoint; + + delete[] Buffer_Send_FaceIndex; + delete[] Buffer_Send_FaceNodes; + delete[] Buffer_Send_FaceProc; + + delete[] Buffer_Receive_FaceIndex; + delete[] Buffer_Receive_FaceNodes; + delete[] Buffer_Receive_FaceProc; + } + delete [] Coord; + delete [] Normal; + + delete [] projected_point; +} + +void CIsoparametric::Isoparameters(unsigned short nDim, unsigned short nDonor, + const su2double *X, const su2double *xj, su2double *isoparams) const { + + short iDonor,iDim,k; // indices + su2double tmp, tmp2; + + su2double *x = new su2double[nDim+1]; + su2double *x_tmp = new su2double[nDim+1]; + su2double *Q = new su2double[nDonor*nDonor]; + su2double *R = new su2double[nDonor*nDonor]; + su2double *A = new su2double[(nDim+2)*nDonor]; + su2double *A2 = NULL; + su2double *x2 = new su2double[nDim+1]; + + bool *test = new bool[nDim+1]; + bool *testi = new bool[nDim+1]; + + su2double eps = 1E-10; + + short n = nDim+1; + + if (nDonor>2) { + /*--- Create Matrix A: 1st row all 1's, 2nd row x coordinates, 3rd row y coordinates, etc ---*/ + /*--- Right hand side is [1, \vec{x}']'---*/ + for (iDonor=0; iDonoreps && iDonor=0; iDonor--) { + if (R[iDonor*nDonor+iDonor]>eps) + isoparams[iDonor]=x_tmp[iDonor]/R[iDonor*nDonor+iDonor]; + else + isoparams[iDonor]=0; + for (k=0; k1.0) xi=1.0; + if (xi<-1.0) xi=-1.0; + if (eta>1.0) eta=1.0; + if (eta<-1.0) eta=-1.0; + isoparams[0]=0.25*(1-xi)*(1-eta); + isoparams[1]=0.25*(1+xi)*(1-eta); + isoparams[2]=0.25*(1+xi)*(1+eta); + isoparams[3]=0.25*(1-xi)*(1+eta); + + } + if (nDonor<4) { + tmp = 0.0; // value for normalization + tmp2=0; // check for maximum value, to be used to id nearest neighbor if necessary + k=0; // index for maximum value + for (iDonor=0; iDonor< nDonor; iDonor++) { + if (isoparams[iDonor]>tmp2) { + k=iDonor; + tmp2=isoparams[iDonor]; + } + // [0,1] + if (isoparams[iDonor]<0) isoparams[iDonor]=0; + if (isoparams[iDonor]>1) isoparams[iDonor] = 1; + tmp +=isoparams[iDonor]; + } + if (tmp>0) + for (iDonor=0; iDonor< nDonor; iDonor++) + isoparams[iDonor]=isoparams[iDonor]/tmp; + else { + isoparams[k] = 1.0; + } + } + + delete [] x; + delete [] x_tmp; + delete [] Q; + delete [] R; + delete [] A; + delete [] A2; + delete [] x2; + + delete [] test; + delete [] testi; + +} diff --git a/Common/src/interface_interpolation/CMirror.cpp b/Common/src/interface_interpolation/CMirror.cpp new file mode 100644 index 000000000000..67ed3246c628 --- /dev/null +++ b/Common/src/interface_interpolation/CMirror.cpp @@ -0,0 +1,243 @@ +/*! + * \file CMirror.cpp + * \brief Implementation of mirror interpolation (conservative approach in FSI problems). + * \author H. Kline + * \version 7.0.2 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "../../include/interface_interpolation/CMirror.hpp" +#include "../../include/CConfig.hpp" +#include "../../include/geometry/CGeometry.hpp" + + +CMirror::CMirror(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, + unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { + Set_TransferCoeff(config); +} + +void CMirror::Set_TransferCoeff(CConfig **config) { + + unsigned long iVertex, jVertex; + unsigned long iPoint; + unsigned short iDonor=0, iFace=0, iTarget=0; + + unsigned short nMarkerInt; + unsigned short iMarkerInt; + + int markDonor=0, markTarget=0; + + unsigned int nNodes=0, iNodes=0; + unsigned long nVertexDonor = 0, nVertexTarget= 0; + unsigned long Point_Donor = 0; + unsigned long pGlobalPoint = 0; + int iProcessor; + + unsigned long nLocalFace_Donor = 0, nLocalFaceNodes_Donor=0; + + unsigned long faceindex; + + int nProcessor = size; + + su2double *Buffer_Send_Coeff, *Buffer_Receive_Coeff; + su2double coeff; + + /*--- Number of markers on the interface ---*/ + nMarkerInt = (config[targetZone]->GetMarker_n_ZoneInterface())/2; + + /*--- For the number of markers on the interface... ---*/ + for (iMarkerInt=1; iMarkerInt <= nMarkerInt; iMarkerInt++) { + /*--- Procedure: + * - Loop through vertices of the aero grid + * - Find nearest element and allocate enough space in the aero grid donor point info + * - Set the transfer coefficient values + */ + + /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ + markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + + /*--- On the target side: find the tag of the boundary sharing the interface ---*/ + markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); + + /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ + if(!CheckInterfaceBoundary(markDonor, markTarget)) continue; + + if(markDonor != -1) + nVertexDonor = donor_geometry->GetnVertex( markDonor ); + else + nVertexDonor = 0; + + if(markTarget != -1) + nVertexTarget = target_geometry->GetnVertex( markTarget ); + else + nVertexTarget = 0; + + /*-- Collect the number of donor nodes: re-use 'Face' containers --*/ + nLocalFace_Donor=0; + nLocalFaceNodes_Donor=0; + for (jVertex = 0; jVertexvertex[markDonor][jVertex]->GetNode(); // Local index of jVertex + + if (donor_geometry->node[Point_Donor]->GetDomain()) { + nNodes = donor_geometry->vertex[markDonor][jVertex]->GetnDonorPoints(); + nLocalFaceNodes_Donor+=nNodes; + nLocalFace_Donor++; + } + } + Buffer_Send_nFace_Donor= new unsigned long [1]; + Buffer_Send_nFaceNodes_Donor= new unsigned long [1]; + + Buffer_Receive_nFace_Donor = new unsigned long [nProcessor]; + Buffer_Receive_nFaceNodes_Donor = new unsigned long [nProcessor]; + + Buffer_Send_nFace_Donor[0] = nLocalFace_Donor; + Buffer_Send_nFaceNodes_Donor[0] = nLocalFaceNodes_Donor; + + /*--- Send Interface vertex information --*/ +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &MaxFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&nLocalFace_Donor, &MaxFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nFace_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + MaxFace_Donor++; +#else + nGlobalFace_Donor = nLocalFace_Donor; + nGlobalFaceNodes_Donor = nLocalFaceNodes_Donor; + MaxFaceNodes_Donor = nLocalFaceNodes_Donor; + MaxFace_Donor = nLocalFace_Donor+1; + Buffer_Receive_nFace_Donor[0] = Buffer_Send_nFace_Donor[0]; + Buffer_Receive_nFaceNodes_Donor[0] = Buffer_Send_nFaceNodes_Donor[0]; +#endif + + /*-- Send donor info --*/ + Buffer_Send_FaceIndex = new unsigned long[MaxFace_Donor]; + Buffer_Send_FaceNodes = new unsigned long[MaxFaceNodes_Donor]; + Buffer_Send_GlobalPoint = new long[MaxFaceNodes_Donor]; + Buffer_Send_Coeff = new su2double[MaxFaceNodes_Donor]; + + Buffer_Receive_FaceIndex= new unsigned long[MaxFace_Donor*nProcessor]; + Buffer_Receive_FaceNodes= new unsigned long[MaxFaceNodes_Donor*nProcessor]; + Buffer_Receive_GlobalPoint = new long[MaxFaceNodes_Donor*nProcessor]; + Buffer_Receive_Coeff = new su2double[MaxFaceNodes_Donor*nProcessor]; + + for (iVertex=0; iVertexvertex[markDonor][jVertex]->GetNode(); // Local index of jVertex + if (donor_geometry->node[Point_Donor]->GetDomain()) { + nNodes = donor_geometry->vertex[markDonor][jVertex]->GetnDonorPoints(); + for (iDonor=0; iDonornode[Point_Donor]->GetGlobalIndex(); + Buffer_Send_GlobalPoint[nLocalFaceNodes_Donor] = + donor_geometry->vertex[markDonor][jVertex]->GetInterpDonorPoint(iDonor); + Buffer_Send_Coeff[nLocalFaceNodes_Donor] = + donor_geometry->vertex[markDonor][jVertex]->GetDonorCoeff(iDonor); + nLocalFaceNodes_Donor++; + } + Buffer_Send_FaceIndex[nLocalFace_Donor+1] =Buffer_Send_FaceIndex[nLocalFace_Donor]+nNodes; + nLocalFace_Donor++; + } + } + + SU2_MPI::Allgather(Buffer_Send_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, + Buffer_Receive_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_GlobalPoint, MaxFaceNodes_Donor, MPI_LONG, + Buffer_Receive_GlobalPoint, MaxFaceNodes_Donor, MPI_LONG, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_Coeff, MaxFaceNodes_Donor, MPI_DOUBLE, + Buffer_Receive_Coeff, MaxFaceNodes_Donor, MPI_DOUBLE, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, + Buffer_Receive_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + /*--- Loop over the vertices on the target Marker ---*/ + for (iVertex = 0; iVertexvertex[markTarget][iVertex]->GetNode(); + if (target_geometry->node[iPoint]->GetDomain()) { + long Global_Point = target_geometry->node[iPoint]->GetGlobalIndex(); + nNodes = 0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (iFace = 0; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { + faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face + iNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1]- (unsigned int)faceindex; + for (iTarget=0; iTargetvertex[markTarget][iVertex]->SetnDonorPoints(nNodes); + target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); + + iDonor = 0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (iFace = 0; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { + + faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face + iNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1]- (unsigned int)faceindex; + for (iTarget=0; iTargetvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,pGlobalPoint); + target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor,coeff); + target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, iProcessor); + iDonor++; + } + } + } + } + } + } + delete[] Buffer_Send_nFace_Donor; + delete[] Buffer_Send_nFaceNodes_Donor; + + delete[] Buffer_Receive_nFace_Donor; + delete[] Buffer_Receive_nFaceNodes_Donor; + + delete[] Buffer_Send_FaceIndex; + delete[] Buffer_Send_FaceNodes; + delete[] Buffer_Send_GlobalPoint; + delete[] Buffer_Send_Coeff; + + delete[] Buffer_Receive_FaceIndex; + delete[] Buffer_Receive_FaceNodes; + delete[] Buffer_Receive_GlobalPoint; + delete[] Buffer_Receive_Coeff; + + } +} diff --git a/Common/src/interface_interpolation/CNearestNeighbor.cpp b/Common/src/interface_interpolation/CNearestNeighbor.cpp new file mode 100644 index 000000000000..04843729aa97 --- /dev/null +++ b/Common/src/interface_interpolation/CNearestNeighbor.cpp @@ -0,0 +1,137 @@ +/*! + * \file CNearestNeighbor.cpp + * \brief Implementation of nearest neighbor interpolation. + * \author H. Kline + * \version 7.0.2 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "../../include/interface_interpolation/CNearestNeighbor.hpp" +#include "../../include/CConfig.hpp" +#include "../../include/geometry/CGeometry.hpp" + + +CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, + unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { + Set_TransferCoeff(config); +} + +void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { + + /*--- By definition, one donor point per target point. ---*/ + constexpr auto numDonor = 1; + constexpr auto idxDonor = 0; + + const su2double eps = numeric_limits::epsilon(); + + const int nProcessor = size; + const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; + const auto nDim = donor_geometry->GetnDim(); + + Buffer_Send_nVertex_Donor = new unsigned long [1]; + Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; + + /*--- Cycle over nMarkersInt interface to determine communication pattern. ---*/ + + for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { + + /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ + const auto markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + + /*--- On the target side: find the tag of the boundary sharing the interface. ---*/ + const auto markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); + + /*--- Checks if the zone contains the interface, if not continue to the next step. ---*/ + if (!CheckInterfaceBoundary(markDonor, markTarget)) continue; + + unsigned long nVertexDonor = 0, nVertexTarget = 0; + if(markDonor != -1) nVertexDonor = donor_geometry->GetnVertex( markDonor ); + if(markTarget != -1) nVertexTarget = target_geometry->GetnVertex( markTarget ); + + /* Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor. */ + Determine_ArraySize(false, markDonor, markTarget, nVertexDonor, nDim); + + Buffer_Send_Coord = new su2double [ MaxLocalVertex_Donor * nDim ]; + Buffer_Send_GlobalPoint = new long [ MaxLocalVertex_Donor ]; + Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; + Buffer_Receive_GlobalPoint = new long [ nProcessor * MaxLocalVertex_Donor ]; + + /*-- Collect coordinates and global point indices. ---*/ + Collect_VertexInfo( false, markDonor, markTarget, nVertexDonor, nDim ); + + /*--- Compute the closest donor point to each target. ---*/ + SU2_OMP_PARALLEL_(for schedule(dynamic,roundUpDiv(nVertexTarget,2*omp_get_max_threads()))) + for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; iVertexTarget++) { + + auto target_vertex = target_geometry->vertex[markTarget][iVertexTarget]; + const auto Point_Target = target_vertex->GetNode(); + + if (!target_geometry->node[Point_Target]->GetDomain()) continue; + + /*--- Coordinates of the target point. ---*/ + const su2double* Coord_i = target_geometry->node[Point_Target]->GetCoord(); + + su2double mindist = 1e20; + long pGlobalPoint = 0; + int pProcessor = 0; + + for (int iProcessor = 0; iProcessor < nProcessor; ++iProcessor) { + for (auto jVertex = 0ul; jVertex < Buffer_Receive_nVertex_Donor[iProcessor]; ++jVertex) { + + const auto idx = iProcessor*MaxLocalVertex_Donor + jVertex; + + const su2double* Coord_j = &Buffer_Receive_Coord[idx*nDim]; + + const auto dist = PointsSquareDistance(nDim, Coord_i, Coord_j); + + if (dist < mindist) { + mindist = dist; + pProcessor = iProcessor; + pGlobalPoint = Buffer_Receive_GlobalPoint[idx]; + } + + /*--- Test for "exact" match. ---*/ + if (dist < eps) break; + } + } + + /*--- Store matching pair. ---*/ + target_vertex->SetnDonorPoints(numDonor); + target_vertex->Allocate_DonorInfo(); + target_vertex->SetInterpDonorPoint(idxDonor, pGlobalPoint); + target_vertex->SetInterpDonorProcessor(idxDonor, pProcessor); + target_vertex->SetDonorCoeff(idxDonor, 1.0); + + } + + delete[] Buffer_Send_Coord; + delete[] Buffer_Send_GlobalPoint; + + delete[] Buffer_Receive_Coord; + delete[] Buffer_Receive_GlobalPoint; + + } + + delete[] Buffer_Send_nVertex_Donor; + delete[] Buffer_Receive_nVertex_Donor; + +} diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp new file mode 100644 index 000000000000..c9ba5b5e9294 --- /dev/null +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -0,0 +1,772 @@ +/*! + * \file CRadialBasisFunction.cpp + * \brief Implementation of RBF interpolation. + * \author Joel Ho, P. Gomes + * \version 7.0.2 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "../../include/interface_interpolation/CRadialBasisFunction.hpp" +#include "../../include/CConfig.hpp" +#include "../../include/geometry/CGeometry.hpp" + + +CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, + unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { + Set_TransferCoeff(config); +} + +su2double CRadialBasisFunction::Get_RadialBasisValue(ENUM_RADIALBASIS type, const su2double radius, const su2double dist) +{ + su2double rbf = dist/radius; + + switch (type) { + + case WENDLAND_C2: + if(rbf < 1) rbf = pow(pow((1-rbf),2),2)*(4*rbf+1); // double use of pow(x,2) for optimization + else rbf = 0.0; + break; + + case GAUSSIAN: + rbf = exp(-rbf*rbf); + break; + + case THIN_PLATE_SPLINE: + if(rbf < numeric_limits::min()) rbf = 0.0; + else rbf *= rbf*log(rbf); + break; + + case MULTI_QUADRIC: + case INV_MULTI_QUADRIC: + rbf = sqrt(1.0+rbf*rbf); + if(type == INV_MULTI_QUADRIC) rbf = 1.0/rbf; + break; + } + + return rbf; +} + +void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { + + /*--- RBF options. ---*/ + const auto kindRBF = static_cast(config[donorZone]->GetKindRadialBasisFunction()); + const bool usePolynomial = config[donorZone]->GetRadialBasisFunctionPolynomialOption(); + const su2double paramRBF = config[donorZone]->GetRadialBasisFunctionParameter(); + const su2double pruneTol = config[donorZone]->GetRadialBasisFunctionPruneTol(); + + const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; + const int nDim = donor_geometry->GetnDim(); + + const int nProcessor = size; + Buffer_Send_nVertex_Donor = new unsigned long [1]; + Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; + + /*--- Process interface patches in parallel, fetch all donor point coordinates, + * then distribute interpolation matrix computation over ranks and threads. + * To avoid repeating calls to Collect_VertexInfo we also save the global + * indices of the donor points and the mpi rank index that owns them. ---*/ + vector DonorCoordinates(nMarkerInt); + vector > DonorGlobalPoint(nMarkerInt); + vector > DonorProcessor(nMarkerInt); + vector AssignedProcessor(nMarkerInt,-1); + vector TotalWork(nProcessor,0); + + for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; ++iMarkerInt) { + + /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ + const auto mark_donor = Find_InterfaceMarker(config[donorZone], iMarkerInt+1); + + /*--- On the target side: find the tag of the boundary sharing the interface. ---*/ + const auto mark_target = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); + + /*--- If the zone does not contain the interface continue to the next pair of markers. ---*/ + if(!CheckInterfaceBoundary(mark_donor,mark_target)) continue; + + unsigned long nVertexDonor = 0; + if(mark_donor != -1) nVertexDonor = donor_geometry->GetnVertex(mark_donor); + + /*--- Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor. ---*/ + Determine_ArraySize(false, mark_donor, mark_target, nVertexDonor, nDim); + + /*--- Compute total number of donor vertices. ---*/ + auto nGlobalVertexDonor = accumulate(Buffer_Receive_nVertex_Donor, + Buffer_Receive_nVertex_Donor+nProcessor, 0ul); + + /*--- Gather coordinates and global point indices. ---*/ + Buffer_Send_Coord = new su2double [ MaxLocalVertex_Donor * nDim ]; + Buffer_Send_GlobalPoint = new long [ MaxLocalVertex_Donor ]; + Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; + Buffer_Receive_GlobalPoint = new long [ nProcessor * MaxLocalVertex_Donor ]; + + Collect_VertexInfo(false, mark_donor, mark_target, nVertexDonor, nDim); + + /*--- Compresses the gathered donor point information to simplify computations. ---*/ + auto& DonorCoord = DonorCoordinates[iMarkerInt]; + auto& DonorPoint = DonorGlobalPoint[iMarkerInt]; + auto& DonorProc = DonorProcessor[iMarkerInt]; + DonorCoord.resize(nGlobalVertexDonor, nDim); + DonorPoint.resize(nGlobalVertexDonor); + DonorProc.resize(nGlobalVertexDonor); + + auto iCount = 0ul; + for (int iProcessor = 0; iProcessor < nProcessor; ++iProcessor) { + auto offset = iProcessor * MaxLocalVertex_Donor; + for (auto iVertex = 0ul; iVertex < Buffer_Receive_nVertex_Donor[iProcessor]; ++iVertex) { + for (int iDim = 0; iDim < nDim; ++iDim) + DonorCoord(iCount,iDim) = Buffer_Receive_Coord[(offset+iVertex)*nDim + iDim]; + DonorPoint[iCount] = Buffer_Receive_GlobalPoint[offset+iVertex]; + DonorProc[iCount] = iProcessor; + ++iCount; + } + } + assert((iCount == nGlobalVertexDonor) && "Global donor point count mismatch."); + + delete[] Buffer_Send_Coord; + delete[] Buffer_Send_GlobalPoint; + delete[] Buffer_Receive_Coord; + delete[] Buffer_Receive_GlobalPoint; + + /*--- Static work scheduling over ranks based on which one has less work currently. ---*/ + int iProcessor = 0; + for (int i = 1; i < nProcessor; ++i) + if (TotalWork[i] < TotalWork[iProcessor]) iProcessor = i; + + TotalWork[iProcessor] += pow(nGlobalVertexDonor,3); // based on matrix inversion. + + AssignedProcessor[iMarkerInt] = iProcessor; + + } + + /*--- Compute the interpolation matrices for each patch of coordinates + * assigned to the rank. Subdivide work further by threads. ---*/ + vector nPolynomialVec(nMarkerInt,-1); + vector > keepPolynomialRowVec(nMarkerInt, vector(nDim,1)); + vector CinvTrucVec(nMarkerInt); + + SU2_OMP_PARALLEL_(for schedule(dynamic,1)) + for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; ++iMarkerInt) { + if (rank == AssignedProcessor[iMarkerInt]) { + ComputeGeneratorMatrix(kindRBF, usePolynomial, paramRBF, + DonorCoordinates[iMarkerInt], nPolynomialVec[iMarkerInt], + keepPolynomialRowVec[iMarkerInt], CinvTrucVec[iMarkerInt]); + } + } + + /*--- Final loop over interface markers to compute the interpolation coefficients. ---*/ + + for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; iMarkerInt++) { + + /*--- Identify the rank that computed the interpolation matrix for this marker. ---*/ + const int iProcessor = AssignedProcessor[iMarkerInt]; + /*--- If no processor was assigned to work, the zone does not contain the interface. ---*/ + if (iProcessor < 0) continue; + + /*--- Setup target information. ---*/ + const int mark_target = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); + unsigned long nVertexTarget = 0; + if(mark_target != -1) nVertexTarget = target_geometry->GetnVertex(mark_target); + + /*--- Set references to donor information. ---*/ + auto& DonorCoord = DonorCoordinates[iMarkerInt]; + auto& DonorPoint = DonorGlobalPoint[iMarkerInt]; + auto& DonorProc = DonorProcessor[iMarkerInt]; + + auto& C_inv_trunc = CinvTrucVec[iMarkerInt]; + auto& nPolynomial = nPolynomialVec[iMarkerInt]; + auto& keepPolynomialRow = keepPolynomialRowVec[iMarkerInt]; + + const auto nGlobalVertexDonor = DonorCoord.rows(); + +#ifdef HAVE_MPI + /*--- For simplicity, broadcast small information about the interpolation matrix. ---*/ + SU2_MPI::Bcast(&nPolynomial, 1, MPI_INT, iProcessor, MPI_COMM_WORLD); + SU2_MPI::Bcast(keepPolynomialRow.data(), nDim, MPI_INT, iProcessor, MPI_COMM_WORLD); + + /*--- Send C_inv_trunc only to the ranks that need it (those with target points), + * partial broadcast. MPI wrapper not used due to passive double. ---*/ + vector allNumVertex(nProcessor); + SU2_MPI::Allgather(&nVertexTarget, 1, MPI_UNSIGNED_LONG, + allNumVertex.data(), 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + if (rank == iProcessor) { + for (int jProcessor = 0; jProcessor < nProcessor; ++jProcessor) + if ((jProcessor != iProcessor) && (allNumVertex[jProcessor] != 0)) + MPI_Send(C_inv_trunc.data(), C_inv_trunc.size(), + MPI_DOUBLE, jProcessor, 0, MPI_COMM_WORLD); + } + else if (nVertexTarget != 0) { + C_inv_trunc.resize(1+nPolynomial+nGlobalVertexDonor, nGlobalVertexDonor); + MPI_Recv(C_inv_trunc.data(), C_inv_trunc.size(), MPI_DOUBLE, + iProcessor, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + } +#endif + + /*--- Compute H (interpolation) matrix, distributing + * target points over the threads in the rank. ---*/ + SU2_OMP_PARALLEL + { + su2passivevector coeff_vec(nGlobalVertexDonor); + + SU2_OMP_FOR_DYN(roundUpDiv(nVertexTarget, 2*omp_get_max_threads())) + for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; iVertexTarget++) { + + auto target_vertex = target_geometry->vertex[mark_target][iVertexTarget]; + const auto point_target = target_vertex->GetNode(); + + /*--- If not domain point move to next. ---*/ + if (!target_geometry->node[point_target]->GetDomain()) continue; + + const su2double* coord_i = target_geometry->node[point_target]->GetCoord(); + + /*--- Multiply target vector by C_inv_trunc to obtain the interpolation coefficients. + * The target vector is not stored, we consume its entries immediately to avoid + * strided access to C_inv_trunc (as it is row-major). ---*/ + + /*--- Polynominal part: ---*/ + if (usePolynomial) { + /*--- Constant term. ---*/ + for (auto j = 0ul; j < nGlobalVertexDonor; ++j) + coeff_vec(j) = C_inv_trunc(0,j); + + /*--- Linear terms. ---*/ + for (int iDim = 0, idx = 1; iDim < nDim; ++iDim) { + /*--- Of which one may have been excluded. ---*/ + if (!keepPolynomialRow[iDim]) continue; + for (auto j = 0ul; j < nGlobalVertexDonor; ++j) + coeff_vec(j) += SU2_TYPE::GetValue(coord_i[iDim]) * C_inv_trunc(idx,j); + idx += 1; + } + } + else { + /*--- Initialize vector to zero. ---*/ + for (auto j = 0ul; j < nGlobalVertexDonor; ++j) coeff_vec(j) = 0.0; + } + + /*--- RBF terms: ---*/ + for (auto iVertexDonor = 0ul; iVertexDonor < nGlobalVertexDonor; ++iVertexDonor) { + auto w_ij = SU2_TYPE::GetValue(Get_RadialBasisValue(kindRBF, paramRBF, + PointsDistance(nDim, coord_i, DonorCoord[iVertexDonor]))); + + for (auto j = 0ul; j < nGlobalVertexDonor; ++j) + coeff_vec(j) += w_ij * C_inv_trunc(1+nPolynomial+iVertexDonor, j); + } + + /*--- Prune small coefficients. ---*/ + auto nnz = PruneSmallCoefficients(SU2_TYPE::GetValue(pruneTol), coeff_vec); + + /*--- Allocate and set donor information for this target point. ---*/ + target_vertex->SetnDonorPoints(nnz); + target_vertex->Allocate_DonorInfo(); + + for (unsigned long iVertex = 0, iSet = 0; iVertex < nGlobalVertexDonor; ++iVertex) { + if (fabs(coeff_vec(iVertex)) > 0.0) { + target_vertex->SetInterpDonorProcessor(iSet, DonorProc[iVertex]); + target_vertex->SetInterpDonorPoint(iSet, DonorPoint[iVertex]); + target_vertex->SetDonorCoeff(iSet, coeff_vec(iVertex)); + ++iSet; + } + } + + } // end target vertex loop + } // end SU2_OMP_PARALLEL + + /*--- Delete global data that will no longer be used. ---*/ + DonorCoord.resize(0,0); + vector().swap(DonorPoint); + vector().swap(DonorProc); + C_inv_trunc.resize(0,0); + + } // end loop over interface markers + + delete[] Buffer_Send_nVertex_Donor; + delete[] Buffer_Receive_nVertex_Donor; + +} + +void CRadialBasisFunction::ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool usePolynomial, + su2double radius, const su2activematrix& coords, int& nPolynomial, + vector& keepPolynomialRow, su2passivematrix& C_inv_trunc) const { + + const su2double interfaceCoordTol = 1e6 * numeric_limits::epsilon(); + + const auto nVertexDonor = coords.rows(); + const int nDim = coords.cols(); + + /*--- Populate interpolation kernel. ---*/ + CSymmetricMatrix global_M(nVertexDonor); + + for (auto iVertex = 0ul; iVertex < nVertexDonor; ++iVertex) + for (auto jVertex = iVertex; jVertex < nVertexDonor; ++jVertex) + global_M(iVertex, jVertex) = SU2_TYPE::GetValue(Get_RadialBasisValue(type, radius, + PointsDistance(nDim, coords[iVertex], coords[jVertex]))); + + /*--- Invert M matrix (operation is in-place). ---*/ + const bool kernelIsSPD = (type==WENDLAND_C2) || (type==GAUSSIAN) || (type==INV_MULTI_QUADRIC); + global_M.Invert(kernelIsSPD); + + /*--- Compute C_inv_trunc. ---*/ + if (usePolynomial) { + + /*--- Fill P matrix (P for points, with an extra top row of ones). ---*/ + su2passivematrix P(1+nDim, nVertexDonor); + + for (auto iVertex = 0ul; iVertex < nVertexDonor; iVertex++) { + P(0, iVertex) = 1.0; + for (int iDim = 0; iDim < nDim; ++iDim) + P(1+iDim, iVertex) = SU2_TYPE::GetValue(coords(iVertex, iDim)); + } + + /*--- Check if points lie on a plane and remove one coordinate from P if so. ---*/ + nPolynomial = CheckPolynomialTerms(interfaceCoordTol, keepPolynomialRow, P); + + /*--- Compute Mp = (P * M^-1 * P^T)^-1 ---*/ + CSymmetricMatrix Mp(nPolynomial+1); + + su2passivematrix tmp; + global_M.MatMatMult('R', P, tmp); // tmp = P * M^-1 + + for (int i = 0; i <= nPolynomial; ++i) // Mp = tmp * P + for (int j = i; j <= nPolynomial; ++j) { + Mp(i,j) = 0.0; + for (auto k = 0ul; k < nVertexDonor; ++k) Mp(i,j) += tmp(i,k) * P(j,k); + } + Mp.Invert(false); // Mp = Mp^-1 + + /*--- Compute M_p * P * M^-1, the top part of C_inv_trunc. ---*/ + Mp.MatMatMult('L', P, tmp); + su2passivematrix C_inv_top; + global_M.MatMatMult('R', tmp, C_inv_top); + + /*--- Compute tmp = (I - P^T * M_p * P * M^-1), part of the bottom part of + C_inv_trunc. Note that most of the product is known from the top part. ---*/ + tmp.resize(nVertexDonor, nVertexDonor); + + for (auto i = 0ul; i < nVertexDonor; ++i) { + for (auto j = 0ul; j < nVertexDonor; ++j) { + tmp(i,j) = 0.0; + for (int k = 0; k <= nPolynomial; ++k) tmp(i,j) -= P(k,i) * C_inv_top(k,j); + } + tmp(i,i) += 1.0; // identity part + } + + /*--- Compute M^-1 * (I - P^T * M_p * P * M^-1), finalize bottom of C_inv_trunc. ---*/ + global_M.MatMatMult('L', tmp, C_inv_trunc); + + /*--- Merge top and bottom of C_inv_trunc. ---*/ + tmp = move(C_inv_trunc); + C_inv_trunc.resize(1+nPolynomial+nVertexDonor, nVertexDonor); + memcpy(C_inv_trunc[0], C_inv_top.data(), C_inv_top.size()*sizeof(passivedouble)); + memcpy(C_inv_trunc[1+nPolynomial], tmp.data(), tmp.size()*sizeof(passivedouble)); + } + else { + /*--- No polynomial term used in the interpolation, C_inv_trunc = M^-1. ---*/ + + C_inv_trunc.resize(nVertexDonor, nVertexDonor); + for (auto i = 0ul; i < nVertexDonor; ++i) + for (auto j = 0ul; j < nVertexDonor; ++j) + C_inv_trunc(i,j) = global_M(i,j); + + } // end usePolynomial + +} + +int CRadialBasisFunction::CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, + su2passivematrix &P) const { + const int m = P.rows(); + const int n = P.cols(); + + /*--- The first row of P is all ones and we do not care about it for this analysis. ---*/ + const int n_rows = m-1; + keep_row.resize(n_rows); + + /*--- By default assume points are not on a plane (all rows kept). ---*/ + int n_polynomial = n_rows; + for (int i = 0; i < n_rows; ++i) keep_row[i] = 1; + + /*--- Fit a plane through the points in P. ---*/ + + /*--- Compute P times its transpose and invert. ---*/ + CSymmetricMatrix PPT(n_rows); + + for (int i = 0; i < n_rows; ++i) + for (int j = i; j < n_rows; ++j) { + PPT(i,j) = 0.0; + for (int k = 0; k < n; ++k) PPT(i,j) += P(i+1,k) * P(j+1,k); + } + PPT.Invert(true); + + /*--- RHS for the least squares fit (vector of ones times P). ---*/ + vector coeff(n_rows,0.0); + + for (int i = 0; i < n_rows; ++i) + for (int j = 0; j < n; ++j) + coeff[i] += P(i+1,j); + + /*--- Multiply the RHS by the inverse thus obtaining the coefficients. ---*/ + PPT.MatVecMult(coeff.data()); + + /*--- Determine the maximum deviation of the points from the fitted plane. ---*/ + passivedouble max_diff = 0.0; + + for (int j = 0; j < n; ++j) + { + passivedouble sum = 0.0; + for (int i = 0; i < n_rows; ++i) sum += coeff[i] * P(i+1,j); + + /*--- 1.0 is the arbitrary constant we are assuming when fitting + the plane, i.e. the vector of ones used to generate the RHS. ---*/ + max_diff = max(abs(1.0-sum), max_diff); + } + + /*--- If points lie on plane remove row associated with the maximum coefficient. ---*/ + if (max_diff < max_diff_tol) + { + /*--- Find the max coeff and mark the corresponding row for removal. ---*/ + int remove_row = 0; + for (int i = 1; i < n_rows; ++i) + if (abs(coeff[i]) > abs(coeff[remove_row])) + remove_row = i; + + /*--- Mark row as removed and adjust number of polynomial terms. ---*/ + n_polynomial = n_rows-1; + keep_row[remove_row] = 0; + + /*--- Truncated P by shifting rows "up". ---*/ + for (auto i = remove_row+1; i < m-1; ++i) + for (int j = 0; j < n; ++j) + P(i,j) = P(i+1,j); + } + + return n_polynomial; +} + +int CRadialBasisFunction::PruneSmallCoefficients(passivedouble tolerance, + su2passivevector& coeffs) const { + + /*--- Determine the pruning threshold. ---*/ + passivedouble thresh = 0.0; + for (auto i = 0ul; i < coeffs.size(); ++i) + thresh = max(thresh, fabs(coeffs(i))); + thresh *= tolerance; + + /*--- Prune and count non-zeros. ---*/ + int numNonZeros = 0; + passivedouble coeffSum = 0.0; + for (auto i = 0ul; i < coeffs.size(); ++i) { + if (fabs(coeffs(i)) > thresh) { + coeffSum += coeffs(i); + ++numNonZeros; + } + else coeffs(i) = 0.0; + } + + /*--- Correct remaining coefficients, sum must be 1 for conservation. ---*/ + passivedouble correction = 1.0 / coeffSum; + for (auto i = 0ul; i < coeffs.size(); ++i) coeffs(i) *= correction; + + return numNonZeros; +} + +void CSymmetricMatrix::Initialize(int N) +{ + sz = N; + val_vec.resize(sz*sz); + initialized = true; +} + +void CSymmetricMatrix::CholeskyDecompose() +{ +#ifndef HAVE_LAPACK + assert(initialized && "Matrix not initialized."); + + for (int j = 0; j < sz; ++j) { + passivedouble sum = 0.0; + for (int k = 0; k < j; ++k) sum -= pow(Get(j,k), 2); + sum += Get(j,j); + assert(sum > 0.0 && "LLT failed, matrix is not SPD."); + Set(j, j, sqrt(sum)); + + for (int i = j+1; i < sz; ++i) { + passivedouble sum = 0.0; + for (int k = 0; k < j; ++k) sum -= Get(i,k) * Get(j,k); + sum += Get(i,j); + Set(i, j, sum / Get(j,j)); + } + } + decomposed = CHOLESKY; +#endif +} + +void CSymmetricMatrix::LUDecompose() +{ +#ifndef HAVE_LAPACK + assert(initialized && "Matrix not initialized."); + + /*--- Copy matrix values to LU matrix, init permutation vec. ---*/ + decomp_vec.resize(sz*sz); + perm_vec.resize(sz); + for (int i = 0; i < sz; ++i) { + perm_vec[i] = i; + for (int j = i; j < sz; ++j) decomp(j,i) = decomp(i,j) = Get(i,j); + } + + /*--- Decompose LU matrix. ---*/ + for (int j = 0; j < sz-1; ++j) { + /*--- Search for maximum pivot and interchange rows. ---*/ + passivedouble pivot = decomp(j,j); + int pivot_idx = j; + for (int i = j+1; i < sz; ++i) + if (abs(decomp(i,j)) > abs(pivot)) { + pivot = decomp(i,j); + pivot_idx = i; + } + + if (pivot_idx != j) { + swap(perm_vec[j], perm_vec[pivot_idx]); + for (int k = 0; k < sz; ++k) + swap(decomp(j,k), decomp(pivot_idx,k)); + } + + /*--- Perform elimination. ---*/ + for (int k = j+1; k < sz; ++k) decomp(k,j) /= pivot; + + for (int k = j+1; k < sz; ++k) + for (int i = j+1; i < sz; ++i) + decomp(i,k) -= decomp(j,k)*decomp(i,j); + } + + decomposed = LU; +#endif +} + +void CSymmetricMatrix::CalcInv() +{ +#ifndef HAVE_LAPACK + assert(initialized && "Matrix not initialized."); + + /*--- Decompose matrix if not done yet. ---*/ + if (decomposed == NONE) { LUDecompose(); } + + /*--- Compute inverse from decomposed matrices. ---*/ + switch (decomposed) { + + case CHOLESKY: + { + /*--- Initialize inverse matrix. ---*/ + vector inv(sz*sz, 0.0); + + /*--- Compute L inverse. ---*/ + /*--- Solve smaller and smaller systems. ---*/ + for (int j = 0; j < sz; ++j) { + /*--- Forward substitution. ---*/ + inv[IdxSym(j,j)] = 1.0 / Get(j,j); + + for (int i = j+1; i < sz; ++i) { + passivedouble sum = 0.0; + for (int k = j; k < i; ++k) sum -= Get(i,k) * inv[IdxSym(k,j)]; + inv[IdxSym(i,j)] = sum / Get(i,i); + } + } // L inverse in inv + + /*--- Multiply inversed matrices overwrite val_vec. ---*/ + for (int j = 0; j < sz; ++j) + for (int i = j; i < sz; ++i) { + passivedouble sum = 0.0; + for (int k = i; k < sz; ++k) sum += inv[IdxSym(k,i)] * inv[IdxSym(k,j)]; + Set(i, j, sum); + } + + break; + } + + case LU: + { + /*--- Alias val_vec. ---*/ + vector& inv = val_vec; + + /*--- Invert L and U matrices in place. ---*/ + for (int j = 0; j < sz; ++j) { + inv[IdxFull(j,j)] = 1.0 / decomp(j,j); + + for (int i = j+1; i < sz; ++i) { + inv[IdxFull(i,j)] = -decomp(i,j); + inv[IdxFull(j,i)] = -decomp(j,i) * inv[IdxFull(j,j)]; + + for (int k = j+1; k < i; ++k) { + inv[IdxFull(i,j)] -= decomp(i,k) * inv[IdxFull(k,j)]; + inv[IdxFull(j,i)] -= decomp(k,i) * inv[IdxFull(j,k)]; + } + if (j+1 <= i) inv[IdxFull(j,i)] /= decomp(i,i); + } + } + // inverses in val_vec + + /*--- Multiply U_inv by L_inv, overwrite decomp_vec. ---*/ + for (int i = 0; i < sz; ++i) + for (int j = 0; j < sz; ++j) { + decomp(i,j) = 0.0; + for (int k = max(i,j); k < sz; ++k) + decomp(i,j) += inv[IdxFull(i,k)] * ((k==j)? 1.0 : inv[IdxFull(k,j)]); + } + + /*--- Permute multiplied matrix to recover A_inv, overwrite val_vec. ---*/ + for (int j = 0; j < sz; ++j) { + int k = perm_vec[j]; + for (int i = k; i < sz; ++i) Set(i, k, decomp(i,j)); + } + + /*--- Decomposition no longer needed. ---*/ + vector().swap(decomp_vec); + + break; + } + default: assert(false && "Default (LU) decomposition failed."); + } + + decomposed = NONE; +#endif +} + +void CSymmetricMatrix::CalcInv_sytri() +{ +#ifdef HAVE_LAPACK + char uplo = 'L'; + int info; + perm_vec.resize(sz); // ipiv array + + /*--- Query the optimum work size. ---*/ + int query = -1; passivedouble tmp; + dsytrf_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), &tmp, &query, &info); + query = static_cast(tmp); + decomp_vec.resize(query); // work array + + /*--- Factorize and invert. ---*/ + dsytrf_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), decomp_vec.data(), &query, &info); + if (info!=0) SU2_MPI::Error("LDLT factorization failed.", CURRENT_FUNCTION); + dsytri_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), decomp_vec.data(), &info); + if (info!=0) SU2_MPI::Error("Inversion with LDLT factorization failed.", CURRENT_FUNCTION); + + decomposed = NONE; +#endif +} + +void CSymmetricMatrix::CalcInv_potri() +{ +#ifdef HAVE_LAPACK + char uplo = 'L'; + int info; + + dpotrf_(&uplo, &sz, val_vec.data(), &sz, &info); + if (info!=0) SU2_MPI::Error("LLT factorization failed.", CURRENT_FUNCTION); + dpotri_(&uplo, &sz, val_vec.data(), &sz, &info); + if (info!=0) SU2_MPI::Error("Inversion with LLT factorization failed.", CURRENT_FUNCTION); + + decomposed = NONE; +#endif +} + +void CSymmetricMatrix::Invert(const bool is_spd) +{ +#ifdef HAVE_LAPACK + if(is_spd) CalcInv_potri(); + else CalcInv_sytri(); +#else + if(!is_spd) LUDecompose(); + else CholeskyDecompose(); + CalcInv(); +#endif +} + +void CSymmetricMatrix::MatVecMult(passivedouble *v) const +{ + passivedouble *tmp_res = new passivedouble [sz]; + + for (int i=0; i. + */ + +#include "../../include/interface_interpolation/CSlidingMesh.hpp" +#include "../../include/CConfig.hpp" +#include "../../include/geometry/CGeometry.hpp" + + +CSlidingMesh::CSlidingMesh(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, + unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { + Set_TransferCoeff(config); +} + +void CSlidingMesh::Set_TransferCoeff(CConfig **config) { + + /* --- This routine sets the transfer coefficient for sliding mesh approach --- */ + + /* + * The algorithm is based on Rinaldi et al. "Flux-conserving treatment of non-conformal interfaces + * for finite-volume discritization of conservation laws" 2015, Comp. Fluids, 120, pp 126-139 + */ + + /* 0 - Variable declaration - */ + + /* --- General variables --- */ + + bool check; + + unsigned short iDim, nDim; + + unsigned long ii, jj, *uptr; + unsigned long vPoint; + unsigned long iEdgeVisited, nEdgeVisited, iNodeVisited; + unsigned long nAlreadyVisited, nToVisit, StartVisited; + + unsigned long *alreadyVisitedDonor, *ToVisit, *tmpVect; + unsigned long *storeProc, *tmp_storeProc; + + su2double dTMP; + su2double *Coeff_Vect, *tmp_Coeff_Vect; + + /* --- Geometrical variables --- */ + + su2double *Coord_i, *Coord_j, dist, mindist, *Normal; + su2double Area, Area_old, tmp_Area; + su2double LineIntersectionLength, *Direction, length; + + + /* --- Markers Variables --- */ + + unsigned short iMarkerInt, nMarkerInt; + + unsigned long iVertex, nVertexTarget; + + int markDonor, markTarget; + + /* --- Target variables --- */ + + unsigned long target_iPoint, jVertexTarget; + unsigned long nEdges_target, nNode_target; + + unsigned long *Target_nLinkedNodes, *Target_LinkedNodes, *Target_StartLinkedNodes, *target_segment; + unsigned long *Target_Proc; + long *Target_GlobalPoint, *Donor_GlobalPoint; + + su2double *TargetPoint_Coord, *target_iMidEdge_point, *target_jMidEdge_point, **target_element; + + /* --- Donor variables --- */ + + unsigned long donor_StartIndex, donor_forward_point, donor_backward_point, donor_iPoint, donor_OldiPoint; + unsigned long nEdges_donor, nNode_donor, nGlobalVertex_Donor; + + unsigned long nDonorPoints, iDonor; + unsigned long *Donor_Vect, *tmp_Donor_Vect; + unsigned long *Donor_nLinkedNodes, *Donor_LinkedNodes, *Donor_StartLinkedNodes; + unsigned long *Donor_Proc; + + su2double *donor_iMidEdge_point, *donor_jMidEdge_point; + su2double **donor_element, *DonorPoint_Coord; + + /* 1 - Variable pre-processing - */ + + nDim = donor_geometry->GetnDim(); + + /*--- Setting up auxiliary vectors ---*/ + + Donor_Vect = NULL; + Coeff_Vect = NULL; + storeProc = NULL; + + tmp_Donor_Vect = NULL; + tmp_Coeff_Vect = NULL; + tmp_storeProc = NULL; + + Normal = new su2double[nDim]; + Direction = new su2double[nDim]; + + + /* 2 - Find boundary tag between touching grids */ + + /*--- Number of markers on the FSI interface ---*/ + nMarkerInt = (int)( config[ donorZone ]->GetMarker_n_ZoneInterface() ) / 2; + + /*--- For the number of markers on the interface... ---*/ + for ( iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++ ){ + + /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ + markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + + /*--- On the target side: find the tag of the boundary sharing the interface ---*/ + markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); + + /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ + if(!CheckInterfaceBoundary(markDonor, markTarget)) continue; + + if(markTarget != -1) + nVertexTarget = target_geometry->GetnVertex( markTarget ); + else + nVertexTarget = 0; + + /* + 3 -Reconstruct the boundaries from parallel partitioning + */ + + /*--- Target boundary ---*/ + ReconstructBoundary(targetZone, markTarget); + + nGlobalVertex_Target = nGlobalVertex; + + TargetPoint_Coord = Buffer_Receive_Coord; + Target_GlobalPoint = Buffer_Receive_GlobalPoint; + Target_nLinkedNodes = Buffer_Receive_nLinkedNodes; + Target_StartLinkedNodes = Buffer_Receive_StartLinkedNodes; + Target_LinkedNodes = Buffer_Receive_LinkedNodes; + Target_Proc = Buffer_Receive_Proc; + + /*--- Donor boundary ---*/ + ReconstructBoundary(donorZone, markDonor); + + nGlobalVertex_Donor = nGlobalVertex; + + DonorPoint_Coord = Buffer_Receive_Coord; + Donor_GlobalPoint = Buffer_Receive_GlobalPoint; + Donor_nLinkedNodes = Buffer_Receive_nLinkedNodes; + Donor_StartLinkedNodes = Buffer_Receive_StartLinkedNodes; + Donor_LinkedNodes = Buffer_Receive_LinkedNodes; + Donor_Proc = Buffer_Receive_Proc; + + /*--- Starts building the supermesh layer (2D or 3D) ---*/ + /* - For each target node, it first finds the closest donor point + * - Then it creates the supermesh in the close proximity of the target point: + * - Starting from the closest donor node, it expands the supermesh by including + * donor elements neighboring the initial one, until the overall target area is fully covered. + */ + + if(nDim == 2){ + + target_iMidEdge_point = new su2double[nDim]; + target_jMidEdge_point = new su2double[nDim]; + + donor_iMidEdge_point = new su2double[nDim]; + donor_jMidEdge_point = new su2double[nDim]; + + /*--- Starts with supermesh reconstruction ---*/ + + target_segment = new unsigned long[2]; + + for (iVertex = 0; iVertex < nVertexTarget; iVertex++) { + + nDonorPoints = 0; + + /*--- Stores coordinates of the target node ---*/ + + target_iPoint = target_geometry->vertex[markTarget][iVertex]->GetNode(); + + if (target_geometry->node[target_iPoint]->GetDomain()){ + + Coord_i = target_geometry->node[target_iPoint]->GetCoord(); + + /*--- Brute force to find the closest donor_node ---*/ + + mindist = 1E6; + donor_StartIndex = 0; + + for (donor_iPoint = 0; donor_iPoint < nGlobalVertex_Donor; donor_iPoint++) { + + Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; + + dist = PointsDistance(nDim, Coord_i, Coord_j); + + if (dist < mindist) { + mindist = dist; + donor_StartIndex = donor_iPoint; + } + + if (dist == 0.0){ + donor_StartIndex = donor_iPoint; + break; + } + } + + donor_iPoint = donor_StartIndex; + donor_OldiPoint = donor_iPoint; + + /*--- Contruct information regarding the target cell ---*/ + + long dPoint = target_geometry->node[target_iPoint]->GetGlobalIndex(); + for (jVertexTarget = 0; jVertexTarget < nGlobalVertex_Target; jVertexTarget++) + if( dPoint == Target_GlobalPoint[jVertexTarget] ) + break; + + if ( Target_nLinkedNodes[jVertexTarget] == 1 ){ + target_segment[0] = Target_LinkedNodes[ Target_StartLinkedNodes[jVertexTarget] ]; + target_segment[1] = jVertexTarget; + } + else{ + target_segment[0] = Target_LinkedNodes[ Target_StartLinkedNodes[jVertexTarget] ]; + target_segment[1] = Target_LinkedNodes[ Target_StartLinkedNodes[jVertexTarget] + 1]; + } + + dTMP = 0; + for(iDim = 0; iDim < nDim; iDim++){ + target_iMidEdge_point[iDim] = ( TargetPoint_Coord[ nDim * target_segment[0] + iDim ] + target_geometry->node[ target_iPoint ]->GetCoord(iDim) ) / 2; + target_jMidEdge_point[iDim] = ( TargetPoint_Coord[ nDim * target_segment[1] + iDim ] + target_geometry->node[ target_iPoint ]->GetCoord(iDim) ) / 2; + + Direction[iDim] = target_jMidEdge_point[iDim] - target_iMidEdge_point[iDim]; + dTMP += Direction[iDim] * Direction[iDim]; + } + + dTMP = sqrt(dTMP); + for(iDim = 0; iDim < nDim; iDim++) + Direction[iDim] /= dTMP; + + length = PointsDistance(nDim, target_iMidEdge_point, target_jMidEdge_point); + + check = false; + + /*--- Proceeds along the forward direction (depending on which connected boundary node is found first) ---*/ + + while( !check ){ + + /*--- Proceeds until the value of the intersection area is null ---*/ + + if ( Donor_nLinkedNodes[donor_iPoint] == 1 ){ + donor_forward_point = Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_iPoint] ]; + donor_backward_point = donor_iPoint; + } + else{ + uptr = &Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_iPoint] ]; + + if( donor_OldiPoint != uptr[0] ){ + donor_forward_point = uptr[0]; + donor_backward_point = uptr[1]; + } + else{ + donor_forward_point = uptr[1]; + donor_backward_point = uptr[0]; + } + } + + if(donor_iPoint >= nGlobalVertex_Donor){ + check = true; + continue; + } + + for(iDim = 0; iDim < nDim; iDim++){ + donor_iMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_forward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; + donor_jMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_backward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; + } + + LineIntersectionLength = ComputeLineIntersectionLength(target_iMidEdge_point, target_jMidEdge_point, donor_iMidEdge_point, donor_jMidEdge_point, Direction); + + if ( LineIntersectionLength == 0.0 ){ + check = true; + continue; + } + + /*--- In case the element intersects the target cell, update the auxiliary communication data structure ---*/ + + tmp_Coeff_Vect = new su2double[ nDonorPoints + 1 ]; + tmp_Donor_Vect = new unsigned long[ nDonorPoints + 1 ]; + tmp_storeProc = new unsigned long[ nDonorPoints + 1 ]; + + for( iDonor = 0; iDonor < nDonorPoints; iDonor++){ + tmp_Donor_Vect[iDonor] = Donor_Vect[iDonor]; + tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; + tmp_storeProc[iDonor] = storeProc[iDonor]; + } + + tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; + tmp_Coeff_Vect[ nDonorPoints ] = LineIntersectionLength / length; + tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; + + if (Donor_Vect != NULL) delete [] Donor_Vect; + if (Coeff_Vect != NULL) delete [] Coeff_Vect; + if (storeProc != NULL) delete [] storeProc; + + Donor_Vect = tmp_Donor_Vect; + Coeff_Vect = tmp_Coeff_Vect; + storeProc = tmp_storeProc; + + donor_OldiPoint = donor_iPoint; + donor_iPoint = donor_forward_point; + + nDonorPoints++; + } + + if ( Donor_nLinkedNodes[donor_StartIndex] == 2 ){ + check = false; + + uptr = &Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_StartIndex] ]; + + donor_iPoint = uptr[1]; + donor_OldiPoint = donor_StartIndex; + } + else + check = true; + + /*--- Proceeds along the backward direction (depending on which connected boundary node is found first) ---*/ + + while( !check ){ + + /*--- Proceeds until the value of the intersection length is null ---*/ + if ( Donor_nLinkedNodes[donor_iPoint] == 1 ){ + donor_forward_point = donor_OldiPoint; + donor_backward_point = donor_iPoint; + } + else{ + uptr = &Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_iPoint] ]; + + if( donor_OldiPoint != uptr[0] ){ + donor_forward_point = uptr[0]; + donor_backward_point = uptr[1]; + } + else{ + donor_forward_point = uptr[1]; + donor_backward_point = uptr[0]; + } + } + + if(donor_iPoint >= nGlobalVertex_Donor){ + check = true; + continue; + } + + for(iDim = 0; iDim < nDim; iDim++){ + donor_iMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_forward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; + donor_jMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_backward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; + } + + LineIntersectionLength = ComputeLineIntersectionLength(target_iMidEdge_point, target_jMidEdge_point, donor_iMidEdge_point, donor_jMidEdge_point, Direction); + + if ( LineIntersectionLength == 0.0 ){ + check = true; + continue; + } + + /*--- In case the element intersects the target cell, update the auxiliary communication data structure ---*/ + + tmp_Coeff_Vect = new su2double[ nDonorPoints + 1 ]; + tmp_Donor_Vect = new unsigned long[ nDonorPoints + 1 ]; + tmp_storeProc = new unsigned long[ nDonorPoints + 1 ]; + + for( iDonor = 0; iDonor < nDonorPoints; iDonor++){ + tmp_Donor_Vect[iDonor] = Donor_Vect[iDonor]; + tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; + tmp_storeProc[iDonor] = storeProc[iDonor]; + } + + tmp_Coeff_Vect[ nDonorPoints ] = LineIntersectionLength / length; + tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; + tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; + + if (Donor_Vect != NULL) delete [] Donor_Vect; + if (Coeff_Vect != NULL) delete [] Coeff_Vect; + if (storeProc != NULL) delete [] storeProc; + + Donor_Vect = tmp_Donor_Vect; + Coeff_Vect = tmp_Coeff_Vect; + storeProc = tmp_storeProc; + + donor_OldiPoint = donor_iPoint; + donor_iPoint = donor_forward_point; + + nDonorPoints++; + } + + /*--- Set the communication data structure and copy data from the auxiliary vectors ---*/ + + target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nDonorPoints); + + target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); + + for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ + target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor, Coeff_Vect[iDonor]); + target_geometry->vertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor, Donor_GlobalPoint[Donor_Vect[iDonor]]); + target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); + } + } + } + + delete [] target_segment; + + delete [] target_iMidEdge_point; + delete [] target_jMidEdge_point; + + delete [] donor_iMidEdge_point; + delete [] donor_jMidEdge_point; + } + else{ + /* --- 3D geometry, creates a superficial super-mesh --- */ + + for (iVertex = 0; iVertex < nVertexTarget; iVertex++) { + + nDonorPoints = 0; + + /*--- Stores coordinates of the target node ---*/ + + target_iPoint = target_geometry->vertex[markTarget][iVertex]->GetNode(); + + if (!target_geometry->node[target_iPoint]->GetDomain()) continue; + + Coord_i = target_geometry->node[target_iPoint]->GetCoord(); + + target_geometry->vertex[markTarget][iVertex]->GetNormal(Normal); + + /*--- The value of Area computed here includes also portion of boundary belonging to different marker ---*/ + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + + for (iDim = 0; iDim < nDim; iDim++) + Normal[iDim] /= Area; + + for (iDim = 0; iDim < nDim; iDim++) + Coord_i[iDim] = target_geometry->node[target_iPoint]->GetCoord(iDim); + + long dPoint = target_geometry->node[target_iPoint]->GetGlobalIndex(); + for (target_iPoint = 0; target_iPoint < nGlobalVertex_Target; target_iPoint++){ + if( dPoint == Target_GlobalPoint[target_iPoint] ) + break; + } + + /*--- Build local surface dual mesh for target element ---*/ + + nEdges_target = Target_nLinkedNodes[target_iPoint]; + + nNode_target = 2*(nEdges_target + 1); + + target_element = new su2double*[nNode_target]; + for (ii = 0; ii < nNode_target; ii++) + target_element[ii] = new su2double[nDim]; + + nNode_target = Build_3D_surface_element(Target_LinkedNodes, Target_StartLinkedNodes, Target_nLinkedNodes, TargetPoint_Coord, target_iPoint, target_element); + + /*--- Brute force to find the closest donor_node ---*/ + + mindist = 1E6; + donor_StartIndex = 0; + + for (donor_iPoint = 0; donor_iPoint < nGlobalVertex_Donor; donor_iPoint++) { + + Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; + + dist = PointsDistance(nDim, Coord_i, Coord_j); + + if (dist < mindist) { + mindist = dist; + donor_StartIndex = donor_iPoint; + } + + if (dist == 0.0){ + donor_StartIndex = donor_iPoint; + break; + } + } + + donor_iPoint = donor_StartIndex; + + nEdges_donor = Donor_nLinkedNodes[donor_iPoint]; + + donor_element = new su2double*[ 2*nEdges_donor + 2 ]; + for (ii = 0; ii < 2*nEdges_donor + 2; ii++) + donor_element[ii] = new su2double[nDim]; + + nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); + + Area = 0; + for (ii = 1; ii < nNode_target-1; ii++){ + for (jj = 1; jj < nNode_donor-1; jj++){ + Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal); + //cout << Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal) << endl; + } + } + + for (ii = 0; ii < 2*nEdges_donor + 2; ii++) + delete [] donor_element[ii]; + delete [] donor_element; + + nDonorPoints = 1; + + /*--- In case the element intersect the target cell update the auxiliary communication data structure ---*/ + + Coeff_Vect = new su2double[ nDonorPoints ]; + Donor_Vect = new unsigned long[ nDonorPoints ]; + storeProc = new unsigned long[ nDonorPoints ]; + + Coeff_Vect[0] = Area; + Donor_Vect[0] = donor_iPoint; + storeProc[0] = Donor_Proc[donor_iPoint]; + + alreadyVisitedDonor = new unsigned long[1]; + + alreadyVisitedDonor[0] = donor_iPoint; + nAlreadyVisited = 1; + StartVisited = 0; + + Area_old = -1; + + while( Area > Area_old ){ + + /* + * - Starting from the closest donor_point, it expands the supermesh by a countour search pattern. + * - The closest donor element becomes the core, at each iteration a new layer of elements around the core is taken into account + */ + + Area_old = Area; + + ToVisit = NULL; + nToVisit = 0; + + for( iNodeVisited = StartVisited; iNodeVisited < nAlreadyVisited; iNodeVisited++ ){ + + vPoint = alreadyVisitedDonor[ iNodeVisited ]; + + nEdgeVisited = Donor_nLinkedNodes[vPoint]; + + for (iEdgeVisited = 0; iEdgeVisited < nEdgeVisited; iEdgeVisited++){ + + donor_iPoint = Donor_LinkedNodes[ Donor_StartLinkedNodes[vPoint] + iEdgeVisited]; + + /*--- Check if the node to visit is already listed in the data structure to avoid double visits ---*/ + + check = 0; + + for( jj = 0; jj < nAlreadyVisited; jj++ ){ + if( donor_iPoint == alreadyVisitedDonor[jj] ){ + check = 1; + break; + } + } + + if( check == 0 && ToVisit != NULL){ + for( jj = 0; jj < nToVisit; jj++ ) + if( donor_iPoint == ToVisit[jj] ){ + check = 1; + break; + } + } + + if( check == 0 ){ + /*--- If the node was not already visited, visit it and list it into data structure ---*/ + + tmpVect = new unsigned long[ nToVisit + 1 ]; + + for( jj = 0; jj < nToVisit; jj++ ) + tmpVect[jj] = ToVisit[jj]; + tmpVect[nToVisit] = donor_iPoint; + + if( ToVisit != NULL ) + delete [] ToVisit; + + ToVisit = tmpVect; + tmpVect = NULL; + + nToVisit++; + + /*--- Find the value of the intersection area between the current donor element and the target element --- */ + + nEdges_donor = Donor_nLinkedNodes[donor_iPoint]; + + donor_element = new su2double*[ 2*nEdges_donor + 2 ]; + for (ii = 0; ii < 2*nEdges_donor + 2; ii++) + donor_element[ii] = new su2double[nDim]; + + nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); + + tmp_Area = 0; + for (ii = 1; ii < nNode_target-1; ii++) + for (jj = 1; jj < nNode_donor-1; jj++) + tmp_Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal); + + for (ii = 0; ii < 2*nEdges_donor + 2; ii++) + delete [] donor_element[ii]; + delete [] donor_element; + + /*--- In case the element intersect the target cell update the auxiliary communication data structure ---*/ + + tmp_Coeff_Vect = new su2double[ nDonorPoints + 1 ]; + tmp_Donor_Vect = new unsigned long[ nDonorPoints + 1 ]; + tmp_storeProc = new unsigned long[ nDonorPoints + 1 ]; + + for( iDonor = 0; iDonor < nDonorPoints; iDonor++){ + tmp_Donor_Vect[iDonor] = Donor_Vect[iDonor]; + tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; + tmp_storeProc[iDonor] = storeProc[iDonor]; + } + + tmp_Coeff_Vect[ nDonorPoints ] = tmp_Area; + tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; + tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; + + if (Donor_Vect != NULL) {delete [] Donor_Vect; } + if (Coeff_Vect != NULL) {delete [] Coeff_Vect; } + if (storeProc != NULL) {delete [] storeProc; } + + Donor_Vect = tmp_Donor_Vect; + Coeff_Vect = tmp_Coeff_Vect; + storeProc = tmp_storeProc; + + tmp_Coeff_Vect = NULL; + tmp_Donor_Vect = NULL; + tmp_storeProc = NULL; + + nDonorPoints++; + + Area += tmp_Area; + } + } + } + + /*--- Update auxiliary data structure ---*/ + + StartVisited = nAlreadyVisited; + + tmpVect = new unsigned long[ nAlreadyVisited + nToVisit ]; + + for( jj = 0; jj < nAlreadyVisited; jj++ ) + tmpVect[jj] = alreadyVisitedDonor[jj]; + + for( jj = 0; jj < nToVisit; jj++ ) + tmpVect[ nAlreadyVisited + jj ] = ToVisit[jj]; + + if( alreadyVisitedDonor != NULL ) + delete [] alreadyVisitedDonor; + + alreadyVisitedDonor = tmpVect; + + nAlreadyVisited += nToVisit; + + delete [] ToVisit; + } + + delete [] alreadyVisitedDonor; + + /*--- Set the communication data structure and copy data from the auxiliary vectors ---*/ + + target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nDonorPoints); + target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); + + for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ + target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor, Coeff_Vect[iDonor]/Area); + target_geometry->vertex[markTarget][iVertex]->SetInterpDonorPoint( iDonor, Donor_GlobalPoint[ Donor_Vect[iDonor] ] ); + target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); + //cout <GetnDim(); + + su2double dotA2, dotB1, dotB2; + + dotA2 = 0; + for(iDim = 0; iDim < nDim; iDim++) + dotA2 += ( A2[iDim] - A1[iDim] ) * Direction[iDim]; + + if( dotA2 >= 0 ){ + dotB1 = 0; + dotB2 = 0; + for(iDim = 0; iDim < nDim; iDim++){ + dotB1 += ( B1[iDim] - A1[iDim] ) * Direction[iDim]; + dotB2 += ( B2[iDim] - A1[iDim] ) * Direction[iDim]; + } + } + else{ + dotA2 *= -1; + + dotB1 = 0; + dotB2 = 0; + for(iDim = 0; iDim < nDim; iDim++){ + dotB1 -= ( B1[iDim] - A1[iDim] ) * Direction[iDim]; + dotB2 -= ( B2[iDim] - A1[iDim] ) * Direction[iDim]; + } + } + + if( dotB1 >= 0 && dotB1 <= dotA2 ){ + if ( dotB2 < 0 ) + return fabs( dotB1 ); + if ( dotB2 > dotA2 ) + return fabs( dotA2 - dotB1 ); + + return fabs( dotB1 - dotB2 ); + } + + if( dotB2 >= 0 && dotB2 <= dotA2 ){ + if ( dotB1 < 0 ) + return fabs(dotB2); + if ( dotB1 > dotA2 ) + return fabs( dotA2 - dotB2 ); + } + + if( ( dotB1 <= 0 && dotA2 <= dotB2 ) || ( dotB2 <= 0 && dotA2 <= dotB1 ) ) + return fabs( dotA2 ); + + return 0.0; +} + +su2double CSlidingMesh::Compute_Triangle_Intersection(su2double* A1, su2double* A2, su2double* A3, su2double* B1, su2double* B2, su2double* B3, su2double* Direction){ + + /* --- This routine is ONLY for 3D grids --- */ + /* --- Projects triangle points onto a plane, specified by its normal "Direction", and calls the ComputeIntersectionArea routine --- */ + + unsigned short iDim; + unsigned short nDim = 3; + + su2double I[3], J[3], K[3]; + su2double a1[3], a2[3], a3[3]; + su2double b1[3], b2[3], b3[3]; + su2double m1, m2; + + /* --- Reference frame is determined by: x = A1A2 y = x ^ ( -Direction ) --- */ + + for(iDim = 0; iDim < 3; iDim++){ + a1[iDim] = 0; + a2[iDim] = 0; + a3[iDim] = 0; + + b1[iDim] = 0; + b2[iDim] = 0; + b3[iDim] = 0; + } + + m1 = 0; + for(iDim = 0; iDim < nDim; iDim++){ + K[iDim] = Direction[iDim]; + + m1 += K[iDim] * K[iDim]; + } + + for(iDim = 0; iDim < nDim; iDim++) + K[iDim] /= sqrt(m1); + + m2 = 0; + for(iDim = 0; iDim < nDim; iDim++) + m2 += (A2[iDim] - A1[iDim]) * K[iDim]; + + m1 = 0; + for(iDim = 0; iDim < nDim; iDim++){ + I[iDim] = (A2[iDim] - A1[iDim]) - m2 * K[iDim]; + m1 += I[iDim] * I[iDim]; + } + + for(iDim = 0; iDim < nDim; iDim++) + I[iDim] /= sqrt(m1); + + // Cross product to find Y + J[0] = K[1]*I[2] - K[2]*I[1]; + J[1] = -(K[0]*I[2] - K[2]*I[0]); + J[2] = K[0]*I[1] - K[1]*I[0]; + + /* --- Project all points on the plane specified by Direction and change their reference frame taking A1 as origin --- */ + + for(iDim = 0; iDim < nDim; iDim++){ + a2[0] += (A2[iDim] - A1[iDim]) * I[iDim]; + a2[1] += (A2[iDim] - A1[iDim]) * J[iDim]; + a2[2] += (A2[iDim] - A1[iDim]) * K[iDim]; + + a3[0] += (A3[iDim] - A1[iDim]) * I[iDim]; + a3[1] += (A3[iDim] - A1[iDim]) * J[iDim]; + a3[2] += (A3[iDim] - A1[iDim]) * K[iDim]; + + b1[0] += (B1[iDim] - A1[iDim]) * I[iDim]; + b1[1] += (B1[iDim] - A1[iDim]) * J[iDim]; + b1[2] += (B1[iDim] - A1[iDim]) * K[iDim]; + + b2[0] += (B2[iDim] - A1[iDim]) * I[iDim]; + b2[1] += (B2[iDim] - A1[iDim]) * J[iDim]; + b2[2] += (B2[iDim] - A1[iDim]) * K[iDim]; + + b3[0] += (B3[iDim] - A1[iDim]) * I[iDim]; + b3[1] += (B3[iDim] - A1[iDim]) * J[iDim]; + b3[2] += (B3[iDim] - A1[iDim]) * K[iDim]; + } + + /*--- Compute intersection area ---*/ + + return ComputeIntersectionArea( a1, a2, a3, b1, b2, b3 ); +} + +su2double CSlidingMesh::ComputeIntersectionArea( su2double* P1, su2double* P2, su2double* P3, su2double* Q1, su2double* Q2, su2double* Q3 ){ + + /* --- This routines computes the area of the polygonal element generated by the superimposition of 2 planar triangle --- */ + /* --- The 2 triangle must lie on the same plane --- */ + + unsigned short iDim, nPoints, i, j, k; + unsigned short nDim, min_theta_index; + + su2double points[16][2], IntersectionPoint[2], theta[6]; + su2double TriangleP[4][2], TriangleQ[4][2]; + su2double Area, det, dot1, dot2, dtmp, min_theta; + + nDim = 2; + nPoints = 0; + + for(iDim = 0; iDim < nDim; iDim++){ + TriangleP[0][iDim] = 0; + TriangleP[1][iDim] = P2[iDim] - P1[iDim]; + TriangleP[2][iDim] = P3[iDim] - P1[iDim]; + TriangleP[3][iDim] = 0; + + TriangleQ[0][iDim] = Q1[iDim] - P1[iDim]; + TriangleQ[1][iDim] = Q2[iDim] - P1[iDim]; + TriangleQ[2][iDim] = Q3[iDim] - P1[iDim]; + TriangleQ[3][iDim] = Q1[iDim] - P1[iDim]; + } + + + for( j = 0; j < 3; j++){ + if( CheckPointInsideTriangle(TriangleP[j], TriangleQ[0], TriangleQ[1], TriangleQ[2]) ){ + + // Then P1 is also inside triangle Q, so store it + for(iDim = 0; iDim < nDim; iDim++) + points[nPoints][iDim] = TriangleP[j][iDim]; + + nPoints++; + } + } + + for( j = 0; j < 3; j++){ + if( CheckPointInsideTriangle(TriangleQ[j], TriangleP[0], TriangleP[1], TriangleP[2]) ){ + + // Then Q1 is also inside triangle P, so store it + for(iDim = 0; iDim < nDim; iDim++) + points[nPoints][iDim] = TriangleQ[j][iDim]; + + nPoints++; + } + } + + + // Compute all edge intersections + + for( j = 0; j < 3; j++){ + for( i = 0; i < 3; i++){ + + det = (TriangleP[j][0] - TriangleP[j+1][0]) * ( TriangleQ[i][1] - TriangleQ[i+1][1] ) - (TriangleP[j][1] - TriangleP[j+1][1]) * (TriangleQ[i][0] - TriangleQ[i+1][0]); + + if ( det != 0.0 ){ + ComputeLineIntersectionPoint( TriangleP[j], TriangleP[j+1], TriangleQ[i], TriangleQ[i+1], IntersectionPoint ); + + dot1 = 0; + dot2 = 0; + for(iDim = 0; iDim < nDim; iDim++){ + dot1 += ( TriangleP[j][iDim] - IntersectionPoint[iDim] ) * ( TriangleP[j+1][iDim] - IntersectionPoint[iDim] ); + dot2 += ( TriangleQ[i][iDim] - IntersectionPoint[iDim] ) * ( TriangleQ[i+1][iDim] - IntersectionPoint[iDim] ); + } + + if( dot1 <= 0 && dot2 <= 0 ){ // It found one intersection + + // Store temporarily the intersection point + + for(iDim = 0; iDim < nDim; iDim++) + points[nPoints][iDim] = IntersectionPoint[iDim]; + + nPoints++; + } + } + } + } + + // Remove double points, if any + + for( i = 0; i < nPoints; i++){ + for( j = i+1; j < nPoints; j++){ + if(points[j][0] == points[i][0] && points[j][1] == points[i][1]){ + for( k = j; k < nPoints-1; k++){ + points[k][0] = points[k+1][0]; + points[k][1] = points[k+1][1]; + } + nPoints--; + j--; + } + } + } + + // Re-order nodes + + for( i = 1; i < nPoints; i++){ // Change again reference frame + for(iDim = 0; iDim < nDim; iDim++) + points[i][iDim] -= points[0][iDim]; + + // Compute polar azimuth for each node but the first + theta[i] = atan2(points[i][1], points[i][0]); + } + + for(iDim = 0; iDim < nDim; iDim++) + points[0][iDim] = 0; + + for( i = 1; i < nPoints; i++){ + + min_theta = theta[i]; + min_theta_index = 0; + + for( j = i + 1; j < nPoints; j++){ + + if( theta[j] < min_theta ){ + min_theta = theta[j]; + min_theta_index = j; + } + } + + if( min_theta_index != 0 ){ + dtmp = theta[i]; + theta[i] = theta[min_theta_index]; + theta[min_theta_index] = dtmp; + + dtmp = points[i][0]; + points[i][0] = points[min_theta_index][0]; + points[min_theta_index][0] = dtmp; + + dtmp = points[i][1]; + points[i][1] = points[min_theta_index][1]; + points[min_theta_index][1] = dtmp; + } + } + + // compute area using cross product rule, points position are referred to the 2-dimensional, local, reference frame centered in points[0] + + Area = 0; + + if (nPoints > 2){ + for( i = 1; i < nPoints-1; i++ ){ + + // Ax*By + Area += ( points[i][0] - points[0][0] ) * ( points[i+1][1] - points[0][1] ); + + // Ay*Bx + Area -= ( points[i][1] - points[0][1] ) * ( points[i+1][0] - points[0][0] ); + } + } + + return fabs(Area)/2; +} + +void CSlidingMesh::ComputeLineIntersectionPoint( su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* IntersectionPoint ){ + + /* --- Uses determinant rule to compute the intersection point between 2 straight segments --- */ + /* This works only for lines on a 2D plane, A1, A2 and B1, B2 are respectively the head and the tail points of each segment, + * since they're on a 2D plane they are defined by a 2-elements array containing their coordinates */ + + su2double det; + + det = (A1[0] - A2[0]) * (B1[1] - B2[1]) - (A1[1] - A2[1]) * (B1[0] - B2[0]); + + if ( det != 0.0 ){ // else there is no intersection point + IntersectionPoint[0] = ( ( A1[0]*A2[1] - A1[1]*A2[0] ) * ( B1[0] - B2[0] ) - ( B1[0]*B2[1] - B1[1]*B2[0] ) * ( A1[0] - A2[0] ) ) / det; + IntersectionPoint[1] = ( ( A1[0]*A2[1] - A1[1]*A2[0] ) * ( B1[1] - B2[1] ) - ( B1[0]*B2[1] - B1[1]*B2[0] ) * ( A1[1] - A2[1] ) ) / det; + } +} + +bool CSlidingMesh::CheckPointInsideTriangle(su2double* Point, su2double* T1, su2double* T2, su2double* T3){ + + /* --- Check whether a point "Point" lies inside or outside a triangle defined by 3 points "T1", "T2", "T3" --- */ + /* For each edge it checks on which side the point lies: + * - Computes the unit vector pointing at the internal side of the edge + * - Comutes the vector that connects the point to a point along the edge + * - If the dot product is positive it means that the point is on the internal side of the edge + * - If the check is positive for all the 3 edges, then the point lies within the triangle + */ + + unsigned short iDim, nDim, check; + + su2double vect1[2], vect2[2], r[2]; + su2double dot; + + check = 0; + nDim = 2; + + /* --- Check first edge --- */ + + dot = 0; + for(iDim = 0; iDim < nDim; iDim++){ + vect1[iDim] = T3[iDim] - T1[iDim]; // vec 1 is aligned to the edge + vect2[iDim] = T2[iDim] - T1[iDim]; // vect 2 is the vector connecting one edge point to the third triangle vertex + + r[iDim] = Point[iDim] - T1[iDim]; // Connects point to vertex T1 + + dot += vect2[iDim] * vect2[iDim]; + } + dot = sqrt(dot); + + for(iDim = 0; iDim < nDim; iDim++) + vect2[iDim] /= dot; + + dot = 0; + for(iDim = 0; iDim < nDim; iDim++) + dot += vect1[iDim] * vect2[iDim]; + + for(iDim = 0; iDim < nDim; iDim++) + vect1[iDim] = T3[iDim] - (T1[iDim] + dot * vect2[iDim]); // Computes the inward unit vector + + dot = 0; + for(iDim = 0; iDim < nDim; iDim++) // Checs that the point lies on the internal plane + dot += vect1[iDim] * r[iDim]; + + if (dot >= 0) + check++; + + /* --- Check second edge --- */ + + dot = 0; + for(iDim = 0; iDim < nDim; iDim++){ + vect1[iDim] = T1[iDim] - T2[iDim]; + vect2[iDim] = T3[iDim] - T2[iDim]; + + r[iDim] = Point[iDim] - T2[iDim]; + + dot += vect2[iDim] * vect2[iDim]; + } + dot = sqrt(dot); + + for(iDim = 0; iDim < nDim; iDim++) + vect2[iDim] /= dot; + + dot = 0; + for(iDim = 0; iDim < nDim; iDim++) + dot += vect1[iDim] * vect2[iDim]; + + for(iDim = 0; iDim < nDim; iDim++) + vect1[iDim] = T1[iDim] - (T2[iDim] + dot * vect2[iDim]); + + dot = 0; + for(iDim = 0; iDim < nDim; iDim++) + dot += vect1[iDim] * r[iDim]; + + if (dot >= 0) + check++; + + /* --- Check third edge --- */ + + dot = 0; + for(iDim = 0; iDim < nDim; iDim++){ + vect1[iDim] = T2[iDim] - T3[iDim]; + vect2[iDim] = T1[iDim] - T3[iDim]; + + r[iDim] = Point[iDim] - T3[iDim]; + + dot += vect2[iDim] * vect2[iDim]; + } + dot = sqrt(dot); + + for(iDim = 0; iDim < nDim; iDim++) + vect2[iDim] /= dot; + + dot = 0; + for(iDim = 0; iDim < nDim; iDim++) + dot += vect1[iDim] * vect2[iDim]; + + for(iDim = 0; iDim < nDim; iDim++) + vect1[iDim] = T2[iDim] - (T3[iDim] + dot * vect2[iDim]); + + dot = 0; + for(iDim = 0; iDim < nDim; iDim++) + dot += vect1[iDim] * r[iDim]; + + if (dot >= 0) + check++; + + return (check == 3); +} diff --git a/Common/src/interface_interpolation/meson.build b/Common/src/interface_interpolation/meson.build new file mode 100644 index 000000000000..3e1d1a49b2e4 --- /dev/null +++ b/Common/src/interface_interpolation/meson.build @@ -0,0 +1,6 @@ +common_src += files(['CInterpolator.cpp', + 'CMirror.cpp', + 'CSlidingMesh.cpp', + 'CIsoparametric.cpp', + 'CNearestNeighbor.cpp', + 'CRadialBasisFunction.cpp']) diff --git a/Common/src/interpolation_structure.cpp b/Common/src/interpolation_structure.cpp deleted file mode 100644 index e88bcef4e1f4..000000000000 --- a/Common/src/interpolation_structure.cpp +++ /dev/null @@ -1,3235 +0,0 @@ -/*! - * \file interpolation_structure.cpp - * \brief Main subroutines used by SU2_FSI - * \author H. Kline - * \version 7.0.2 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ -#include "../include/interpolation_structure.hpp" - -#if defined(HAVE_MKL) -#include "mkl.h" -#ifndef HAVE_LAPACK -#define HAVE_LAPACK -#endif -#elif defined(HAVE_LAPACK) -/*--- Lapack / Blas routines used in RBF interpolation. ---*/ -extern "C" void dsytrf_(char*, int*, passivedouble*, int*, int*, passivedouble*, int*, int*); -extern "C" void dsytri_(char*, int*, passivedouble*, int*, int*, passivedouble*, int*); -extern "C" void dpotrf_(char*, int*, passivedouble*, int*, int*); -extern "C" void dpotri_(char*, int*, passivedouble*, int*, int*); -extern "C" void dsymm_(char*, char*, int*, int*, passivedouble*, passivedouble*, int*, - passivedouble*, int*, passivedouble*, passivedouble*, int*); -#endif - -CInterpolator::CInterpolator(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : - rank(SU2_MPI::GetRank()), - size(SU2_MPI::GetSize()), - donorZone(iZone), - targetZone(jZone), - Geometry(geometry_container), - donor_geometry(geometry_container[iZone][INST_0][MESH_0]), - target_geometry(geometry_container[jZone][INST_0][MESH_0]) { - - /*--- Initialize transfer coefficients between the zones. ---*/ - Set_TransferCoeff(config); - -} - -void CInterpolator::Determine_ArraySize(bool faces, int markDonor, int markTarget, - unsigned long nVertexDonor, unsigned short nDim) { - - unsigned long nLocalVertex_Donor = 0, nLocalFaceNodes_Donor=0, nLocalFace_Donor=0; - unsigned long iVertex, iPointDonor = 0; - /* Only needed if face data is also collected */ - unsigned long inode; - unsigned long donor_elem, jElem, jPoint; - unsigned short iDonor; - unsigned int nFaces=0, iFace, nNodes=0; - bool face_on_marker = true; - - for (iVertex = 0; iVertex < nVertexDonor; iVertex++) { - iPointDonor = donor_geometry->vertex[markDonor][iVertex]->GetNode(); - - if (!donor_geometry->node[iPointDonor]->GetDomain()) continue; - - nLocalVertex_Donor++; - - if (!faces) continue; - - /*--- On Donor geometry also communicate face info ---*/ - if (nDim==3) { - for (jElem=0; jElemnode[iPointDonor]->GetnElem(); jElem++) { - donor_elem = donor_geometry->node[iPointDonor]->GetElem(jElem); - nFaces = donor_geometry->elem[donor_elem]->GetnFaces(); - for (iFace=0; iFaceelem[donor_elem]->GetnNodesFace(iFace); - for (iDonor=0; iDonorelem[donor_elem]->GetFaces(iFace, iDonor); - jPoint = donor_geometry->elem[donor_elem]->GetNode(inode); - face_on_marker = (face_on_marker && (donor_geometry->node[jPoint]->GetVertex(markDonor) !=-1)); - } - if (face_on_marker ) { - nLocalFace_Donor++; - nLocalFaceNodes_Donor+=nNodes; - } - } - } - } - else { - /*--- in 2D we use the edges ---*/ - nNodes=2; - nFaces = donor_geometry->node[iPointDonor]->GetnPoint(); - for (iFace=0; iFacenode[iPointDonor]->GetEdge(iFace); - jPoint = donor_geometry->edge[inode]->GetNode(iDonor); - face_on_marker = (face_on_marker && (donor_geometry->node[jPoint]->GetVertex(markDonor) !=-1)); - } - if (face_on_marker ) { - nLocalFace_Donor++; - nLocalFaceNodes_Donor+=nNodes; - } - } - } - } - - Buffer_Send_nVertex_Donor[0] = nLocalVertex_Donor; - if (faces) { - Buffer_Send_nFace_Donor[0] = nLocalFace_Donor; - Buffer_Send_nFaceNodes_Donor[0] = nLocalFaceNodes_Donor; - } - - /*--- Send Interface vertex information --*/ - SU2_MPI::Allreduce(&nLocalVertex_Donor, &MaxLocalVertex_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nVertex_Donor, 1, MPI_UNSIGNED_LONG, - Buffer_Receive_nVertex_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - if (faces) { - SU2_MPI::Allreduce(&nLocalFace_Donor, &nGlobalFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalFace_Donor, &MaxFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &nGlobalFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &MaxFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFace_Donor, 1, MPI_UNSIGNED_LONG, - Buffer_Receive_nFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, - Buffer_Receive_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - MaxFace_Donor++; - } -} - -void CInterpolator::Collect_VertexInfo(bool faces, int markDonor, int markTarget, - unsigned long nVertexDonor, unsigned short nDim) { - - unsigned long iVertex, iPointDonor = 0, iVertexDonor, nBuffer_Coord, nBuffer_Point, nLocalVertex_Donor; - unsigned short iDim; - - for (iVertex = 0; iVertex < MaxLocalVertex_Donor; iVertex++) Buffer_Send_GlobalPoint[iVertex] = -1; - - for (iVertex = 0; iVertex < MaxLocalVertex_Donor*nDim; iVertex++) Buffer_Send_Coord[iVertex] = 0.0; - - if(faces) - for (iVertex = 0; iVertex < MaxLocalVertex_Donor*nDim; iVertex++) Buffer_Send_Normal[iVertex] = 0.0; - - /*--- Copy coordinates and point to the auxiliar vector --*/ - nLocalVertex_Donor = 0; - - for (iVertexDonor = 0; iVertexDonor < nVertexDonor; iVertexDonor++) { - iPointDonor = donor_geometry->vertex[markDonor][iVertexDonor]->GetNode(); - if (donor_geometry->node[iPointDonor]->GetDomain()) { - Buffer_Send_GlobalPoint[nLocalVertex_Donor] = donor_geometry->node[iPointDonor]->GetGlobalIndex(); - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[nLocalVertex_Donor*nDim+iDim] = donor_geometry->node[iPointDonor]->GetCoord(iDim); - - if (faces) { - const su2double* Normal = donor_geometry->vertex[markDonor][iVertexDonor]->GetNormal(); - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Normal[nLocalVertex_Donor*nDim+iDim] = Normal[iDim]; - } - nLocalVertex_Donor++; - } - } - nBuffer_Coord = MaxLocalVertex_Donor*nDim; - nBuffer_Point = MaxLocalVertex_Donor; - - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, - Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_GlobalPoint, nBuffer_Point, MPI_LONG, - Buffer_Receive_GlobalPoint, nBuffer_Point, MPI_LONG, MPI_COMM_WORLD); - if (faces) { - SU2_MPI::Allgather(Buffer_Send_Normal, nBuffer_Coord, MPI_DOUBLE, - Buffer_Receive_Normal, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); - } -} - -int CInterpolator::Find_InterfaceMarker(const CConfig *config, unsigned short val_marker_interface) const { - - for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - /*--- If the tag GetMarker_All_ZoneInterface(iMarker) equals the interface we are looking for. ---*/ - if (config->GetMarker_All_ZoneInterface(iMarker) == val_marker_interface) return iMarker; - } - return -1; -} - -void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ - - CGeometry *geom = Geometry[val_zone][INST_0][MESH_0]; - - unsigned long iVertex, jVertex, kVertex; - - unsigned long count, iTmp, *uptr, dPoint, EdgeIndex, jEdge, nEdges, nNodes, nVertex, iDim, nDim, iPoint; - - unsigned long nGlobalLinkedNodes, nLocalVertex, nLocalLinkedNodes; - - nDim = geom->GetnDim(); - - if( val_marker != -1 ) - nVertex = geom->GetnVertex( val_marker ); - else - nVertex = 0; - - - su2double *Buffer_Send_Coord = new su2double [ nVertex * nDim ]; - unsigned long *Buffer_Send_GlobalPoint = new unsigned long [ nVertex ]; - - unsigned long *Buffer_Send_nLinkedNodes = new unsigned long [ nVertex ]; - unsigned long *Buffer_Send_StartLinkedNodes = new unsigned long [ nVertex ]; - unsigned long **Aux_Send_Map = new unsigned long*[ nVertex ]; - -#ifdef HAVE_MPI - int nProcessor = size, iRank; - unsigned long iTmp2, tmp_index, tmp_index_2; -#endif - - /*--- Copy coordinates and point to the auxiliar vector ---*/ - - nGlobalVertex = 0; - nLocalVertex = 0; - nLocalLinkedNodes = 0; - - for (iVertex = 0; iVertex < nVertex; iVertex++) { - - Buffer_Send_nLinkedNodes[iVertex] = 0; - Aux_Send_Map[iVertex] = NULL; - - iPoint = geom->vertex[val_marker][iVertex]->GetNode(); - - if (geom->node[iPoint]->GetDomain()) { - Buffer_Send_GlobalPoint[nLocalVertex] = geom->node[iPoint]->GetGlobalIndex(); - - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[nLocalVertex*nDim+iDim] = geom->node[iPoint]->GetCoord(iDim); - - nNodes = 0; - nEdges = geom->node[iPoint]->GetnPoint(); - - for (jEdge = 0; jEdge < nEdges; jEdge++){ - EdgeIndex = geom->node[iPoint]->GetEdge(jEdge); - - if( iPoint == geom->edge[EdgeIndex]->GetNode(0) ) - dPoint = geom->edge[EdgeIndex]->GetNode(1); - else - dPoint = geom->edge[EdgeIndex]->GetNode(0); - - if ( geom->node[dPoint]->GetVertex(val_marker) != -1 ) - nNodes++; - } - - Buffer_Send_StartLinkedNodes[nLocalVertex] = nLocalLinkedNodes; - Buffer_Send_nLinkedNodes[nLocalVertex] = nNodes; - - nLocalLinkedNodes += nNodes; - - Aux_Send_Map[nLocalVertex] = new unsigned long[ nNodes ]; - nNodes = 0; - - for (jEdge = 0; jEdge < nEdges; jEdge++){ - EdgeIndex = geom->node[iPoint]->GetEdge(jEdge); - - if( iPoint == geom->edge[EdgeIndex]->GetNode(0) ) - dPoint = geom->edge[EdgeIndex]->GetNode(1); - else - dPoint = geom->edge[EdgeIndex]->GetNode(0); - - if ( geom->node[dPoint]->GetVertex(val_marker) != -1 ){ - Aux_Send_Map[nLocalVertex][nNodes] = geom->node[dPoint]->GetGlobalIndex(); - nNodes++; - } - } - nLocalVertex++; - } - } - - unsigned long *Buffer_Send_LinkedNodes = new unsigned long [ nLocalLinkedNodes ]; - - nLocalLinkedNodes = 0; - - for (iVertex = 0; iVertex < nLocalVertex; iVertex++){ - for (jEdge = 0; jEdge < Buffer_Send_nLinkedNodes[iVertex]; jEdge++){ - Buffer_Send_LinkedNodes[nLocalLinkedNodes] = Aux_Send_Map[iVertex][jEdge]; - nLocalLinkedNodes++; - } - } - - for (iVertex = 0; iVertex < nVertex; iVertex++){ - if( Aux_Send_Map[iVertex] != NULL ) - delete [] Aux_Send_Map[iVertex]; - } - delete [] Aux_Send_Map; Aux_Send_Map = NULL; - - /*--- Reconstruct boundary by gathering data from all ranks ---*/ - - SU2_MPI::Allreduce( &nLocalVertex, &nGlobalVertex, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalLinkedNodes, &nGlobalLinkedNodes, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - - Buffer_Receive_Coord = new su2double [ nGlobalVertex * nDim ]; - Buffer_Receive_GlobalPoint = new long[ nGlobalVertex ]; - Buffer_Receive_Proc = new unsigned long[ nGlobalVertex ]; - - Buffer_Receive_nLinkedNodes = new unsigned long[ nGlobalVertex ]; - Buffer_Receive_LinkedNodes = new unsigned long[ nGlobalLinkedNodes ]; - Buffer_Receive_StartLinkedNodes = new unsigned long[ nGlobalVertex ]; - -#ifdef HAVE_MPI - if (rank == MASTER_NODE){ - - for (iVertex = 0; iVertex < nDim*nLocalVertex; iVertex++) - Buffer_Receive_Coord[iVertex] = Buffer_Send_Coord[iVertex]; - - for (iVertex = 0; iVertex < nLocalVertex; iVertex++){ - Buffer_Receive_GlobalPoint[iVertex] = Buffer_Send_GlobalPoint[iVertex]; - Buffer_Receive_Proc[iVertex] = MASTER_NODE; - Buffer_Receive_nLinkedNodes[iVertex] = Buffer_Send_nLinkedNodes[iVertex]; - Buffer_Receive_StartLinkedNodes[iVertex] = Buffer_Send_StartLinkedNodes[iVertex]; - } - - for (iVertex = 0; iVertex < nLocalLinkedNodes; iVertex++) - Buffer_Receive_LinkedNodes[iVertex] = Buffer_Send_LinkedNodes[iVertex]; - - tmp_index = nLocalVertex; - tmp_index_2 = nLocalLinkedNodes; - - for(iRank = 1; iRank < nProcessor; iRank++){ - - SU2_MPI::Recv( &iTmp2, 1, MPI_UNSIGNED_LONG, iRank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - SU2_MPI::Recv(&Buffer_Receive_LinkedNodes[tmp_index_2], iTmp2, MPI_UNSIGNED_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - - SU2_MPI::Recv( &iTmp, 1, MPI_UNSIGNED_LONG, iRank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - SU2_MPI::Recv(&Buffer_Receive_Coord[tmp_index*nDim], nDim*iTmp, MPI_DOUBLE, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - - SU2_MPI::Recv( &Buffer_Receive_GlobalPoint[tmp_index], iTmp, MPI_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - SU2_MPI::Recv( &Buffer_Receive_nLinkedNodes[tmp_index], iTmp, MPI_UNSIGNED_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - SU2_MPI::Recv(&Buffer_Receive_StartLinkedNodes[tmp_index], iTmp, MPI_UNSIGNED_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - - for (iVertex = 0; iVertex < iTmp; iVertex++){ - Buffer_Receive_Proc[ tmp_index + iVertex ] = iRank; - Buffer_Receive_StartLinkedNodes[ tmp_index + iVertex ] += tmp_index_2; - } - - tmp_index += iTmp; - tmp_index_2 += iTmp2; - } - } - else{ - SU2_MPI::Send( &nLocalLinkedNodes, 1, MPI_UNSIGNED_LONG, 0, 0, MPI_COMM_WORLD); - SU2_MPI::Send(Buffer_Send_LinkedNodes, nLocalLinkedNodes, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); - - SU2_MPI::Send( &nLocalVertex, 1, MPI_UNSIGNED_LONG, 0, 0, MPI_COMM_WORLD); - SU2_MPI::Send(Buffer_Send_Coord, nDim * nLocalVertex, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD); - - SU2_MPI::Send( Buffer_Send_GlobalPoint, nLocalVertex, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); - SU2_MPI::Send( Buffer_Send_nLinkedNodes, nLocalVertex, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); - SU2_MPI::Send(Buffer_Send_StartLinkedNodes, nLocalVertex, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); - } -#else - for (iVertex = 0; iVertex < nDim * nGlobalVertex; iVertex++) - Buffer_Receive_Coord[iVertex] = Buffer_Send_Coord[iVertex]; - - for (iVertex = 0; iVertex < nGlobalVertex; iVertex++){ - Buffer_Receive_GlobalPoint[iVertex] = Buffer_Send_GlobalPoint[iVertex]; - Buffer_Receive_Proc[iVertex] = MASTER_NODE; - Buffer_Receive_nLinkedNodes[iVertex] = Buffer_Send_nLinkedNodes[iVertex]; - Buffer_Receive_StartLinkedNodes[iVertex] = Buffer_Send_StartLinkedNodes[iVertex]; - } - - for (iVertex = 0; iVertex < nGlobalLinkedNodes; iVertex++) - Buffer_Receive_LinkedNodes[iVertex] = Buffer_Send_LinkedNodes[iVertex]; -#endif - - if (rank == MASTER_NODE){ - for (iVertex = 0; iVertex < nGlobalVertex; iVertex++){ - count = 0; - uptr = &Buffer_Receive_LinkedNodes[ Buffer_Receive_StartLinkedNodes[iVertex] ]; - - for (jVertex = 0; jVertex < Buffer_Receive_nLinkedNodes[iVertex]; jVertex++){ - iTmp = uptr[ jVertex ]; - for (kVertex = 0; kVertex < nGlobalVertex; kVertex++){ - if( Buffer_Receive_GlobalPoint[kVertex] == long(iTmp) ){ - uptr[ jVertex ] = kVertex; - count++; - break; - } - } - - if( count != (jVertex+1) ){ - for (kVertex = jVertex; kVertex < Buffer_Receive_nLinkedNodes[iVertex]-1; kVertex++){ - uptr[ kVertex ] = uptr[ kVertex + 1]; - } - Buffer_Receive_nLinkedNodes[iVertex]--; - jVertex--; - } - } - } - } - - SU2_MPI::Bcast(Buffer_Receive_GlobalPoint, nGlobalVertex, MPI_LONG, 0, MPI_COMM_WORLD); - SU2_MPI::Bcast(Buffer_Receive_Coord, nGlobalVertex*nDim, MPI_DOUBLE, 0, MPI_COMM_WORLD); - SU2_MPI::Bcast(Buffer_Receive_Proc, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); - - SU2_MPI::Bcast(Buffer_Receive_nLinkedNodes, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); - SU2_MPI::Bcast(Buffer_Receive_StartLinkedNodes, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); - SU2_MPI::Bcast(Buffer_Receive_LinkedNodes, nGlobalLinkedNodes, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); - - delete [] Buffer_Send_Coord; Buffer_Send_Coord = NULL; - delete [] Buffer_Send_GlobalPoint; Buffer_Send_GlobalPoint = NULL; - delete [] Buffer_Send_LinkedNodes; Buffer_Send_LinkedNodes = NULL; - delete [] Buffer_Send_nLinkedNodes; Buffer_Send_nLinkedNodes = NULL; - delete [] Buffer_Send_StartLinkedNodes; Buffer_Send_StartLinkedNodes = NULL; - -} - -bool CInterpolator::CheckInterfaceBoundary(int markDonor, int markTarget) const { - - /*--- Determine whether the boundary is not on the rank because of - * the partition or because it is not part of the zone. ---*/ - int donorCheck = -1, targetCheck = -1; - SU2_MPI::Allreduce(&markDonor, &donorCheck, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&markTarget, &targetCheck, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); - return (donorCheck != -1) && (targetCheck != -1); -} - -CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, - unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { } - -void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { - - /*--- By definition, one donor point per target point. ---*/ - constexpr auto numDonor = 1; - constexpr auto idxDonor = 0; - - const su2double eps = numeric_limits::epsilon(); - - const int nProcessor = size; - const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; - const auto nDim = donor_geometry->GetnDim(); - - Buffer_Send_nVertex_Donor = new unsigned long [1]; - Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; - - /*--- Cycle over nMarkersInt interface to determine communication pattern. ---*/ - - for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - - /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ - const auto markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - - /*--- On the target side: find the tag of the boundary sharing the interface. ---*/ - const auto markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); - - /*--- Checks if the zone contains the interface, if not continue to the next step. ---*/ - if (!CheckInterfaceBoundary(markDonor, markTarget)) continue; - - unsigned long nVertexDonor = 0, nVertexTarget = 0; - if(markDonor != -1) nVertexDonor = donor_geometry->GetnVertex( markDonor ); - if(markTarget != -1) nVertexTarget = target_geometry->GetnVertex( markTarget ); - - /* Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor. */ - Determine_ArraySize(false, markDonor, markTarget, nVertexDonor, nDim); - - Buffer_Send_Coord = new su2double [ MaxLocalVertex_Donor * nDim ]; - Buffer_Send_GlobalPoint = new long [ MaxLocalVertex_Donor ]; - Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; - Buffer_Receive_GlobalPoint = new long [ nProcessor * MaxLocalVertex_Donor ]; - - /*-- Collect coordinates and global point indices. ---*/ - Collect_VertexInfo( false, markDonor, markTarget, nVertexDonor, nDim ); - - /*--- Compute the closest donor point to each target. ---*/ - SU2_OMP_PARALLEL_(for schedule(dynamic,roundUpDiv(nVertexTarget,2*omp_get_max_threads()))) - for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; iVertexTarget++) { - - auto target_vertex = target_geometry->vertex[markTarget][iVertexTarget]; - const auto Point_Target = target_vertex->GetNode(); - - if (!target_geometry->node[Point_Target]->GetDomain()) continue; - - /*--- Coordinates of the target point. ---*/ - const su2double* Coord_i = target_geometry->node[Point_Target]->GetCoord(); - - su2double mindist = 1e20; - long pGlobalPoint = 0; - int pProcessor = 0; - - for (int iProcessor = 0; iProcessor < nProcessor; ++iProcessor) { - for (auto jVertex = 0ul; jVertex < Buffer_Receive_nVertex_Donor[iProcessor]; ++jVertex) { - - const auto idx = iProcessor*MaxLocalVertex_Donor + jVertex; - - const su2double* Coord_j = &Buffer_Receive_Coord[idx*nDim]; - - const auto dist = PointsSquareDistance(nDim, Coord_i, Coord_j); - - if (dist < mindist) { - mindist = dist; - pProcessor = iProcessor; - pGlobalPoint = Buffer_Receive_GlobalPoint[idx]; - } - - /*--- Test for "exact" match. ---*/ - if (dist < eps) break; - } - } - - /*--- Store matching pair. ---*/ - target_vertex->SetnDonorPoints(numDonor); - target_vertex->Allocate_DonorInfo(); - target_vertex->SetInterpDonorPoint(idxDonor, pGlobalPoint); - target_vertex->SetInterpDonorProcessor(idxDonor, pProcessor); - target_vertex->SetDonorCoeff(idxDonor, 1.0); - - } - - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_GlobalPoint; - - delete[] Buffer_Receive_Coord; - delete[] Buffer_Receive_GlobalPoint; - - } - - delete[] Buffer_Send_nVertex_Donor; - delete[] Buffer_Receive_nVertex_Donor; - -} - - - -CIsoparametric::CIsoparametric(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, - unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { } - -void CIsoparametric::Set_TransferCoeff(CConfig **config) { - - unsigned long iVertex, jVertex; - unsigned long dPoint, inode, jElem, nElem; - unsigned short iDim, iDonor=0, iFace; - - unsigned short nDim = donor_geometry->GetnDim(); - - unsigned short nMarkerInt; - unsigned short iMarkerInt; - - int markDonor=0, markTarget=0; - - long donor_elem=0, temp_donor=0; - unsigned int nNodes=0; - /*--- Restricted to 2-zone for now ---*/ - unsigned int nFaces=1; //For 2D cases, we want to look at edges, not faces, as the 'interface' - bool face_on_marker=true; - - unsigned long nVertexDonor = 0, nVertexTarget= 0; - unsigned long Point_Target = 0; - - unsigned long iVertexDonor, iPointDonor = 0; - int iProcessor; - - unsigned long nLocalFace_Donor = 0, nLocalFaceNodes_Donor=0; - - unsigned long faceindex; - - su2double dist = 0.0, mindist=1E6, *Coord, *Coord_i; - su2double myCoeff[10]; // Maximum # of donor points - su2double *Normal; - su2double *projected_point = new su2double[nDim]; - su2double tmp, tmp2; - su2double storeCoeff[10]; - unsigned long storeGlobal[10]; - int storeProc[10]; - - int nProcessor = size; - Coord = new su2double[nDim]; - Normal = new su2double[nDim]; - - nMarkerInt = (config[donorZone]->GetMarker_n_ZoneInterface())/2; - - /*--- For the number of markers on the interface... ---*/ - for (iMarkerInt=1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - /*--- Procedure: - * -Loop through vertices of the aero grid - * -Find nearest element and allocate enough space in the aero grid donor point info - * -set the transfer coefficient values - */ - - /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - - /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); - - /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ - if(!CheckInterfaceBoundary(markDonor, markTarget)) continue; - - if(markDonor != -1) - nVertexDonor = donor_geometry->GetnVertex( markDonor ); - else - nVertexDonor = 0; - - if(markTarget != -1) - nVertexTarget = target_geometry->GetnVertex( markTarget ); - else - nVertexTarget = 0; - - Buffer_Send_nVertex_Donor = new unsigned long [1]; - Buffer_Send_nFace_Donor = new unsigned long [1]; - Buffer_Send_nFaceNodes_Donor = new unsigned long [1]; - - Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; - Buffer_Receive_nFace_Donor = new unsigned long [nProcessor]; - Buffer_Receive_nFaceNodes_Donor = new unsigned long [nProcessor]; - - /* Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor */ - Determine_ArraySize(true, markDonor, markTarget, nVertexDonor, nDim); - - Buffer_Send_Coord = new su2double [MaxLocalVertex_Donor*nDim]; - Buffer_Send_Normal = new su2double [MaxLocalVertex_Donor*nDim]; - Buffer_Send_GlobalPoint = new long [MaxLocalVertex_Donor]; - - Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_Donor*nDim]; - Buffer_Receive_Normal = new su2double [nProcessor*MaxLocalVertex_Donor*nDim]; - Buffer_Receive_GlobalPoint = new long [nProcessor*MaxLocalVertex_Donor]; - - /*-- Collect coordinates, global points, and normal vectors ---*/ - Collect_VertexInfo(true, markDonor,markTarget,nVertexDonor,nDim); - - Buffer_Send_FaceIndex = new unsigned long[MaxFace_Donor]; - Buffer_Send_FaceNodes = new unsigned long[MaxFaceNodes_Donor]; - Buffer_Send_FaceProc = new unsigned long[MaxFaceNodes_Donor]; - - Buffer_Receive_FaceIndex = new unsigned long[MaxFace_Donor*nProcessor]; - Buffer_Receive_FaceNodes = new unsigned long[MaxFaceNodes_Donor*nProcessor]; - Buffer_Receive_FaceProc = new unsigned long[MaxFaceNodes_Donor*nProcessor]; - - nLocalFace_Donor=0; - nLocalFaceNodes_Donor=0; - - /*--- Collect Face info ---*/ - - for (iVertex = 0; iVertex < MaxFace_Donor; iVertex++) { - Buffer_Send_FaceIndex[iVertex] = 0; - } - for (iVertex=0; iVertexvertex[markDonor][iVertexDonor]->GetNode(); - - if (donor_geometry->node[iPointDonor]->GetDomain()) { - - if (nDim==3) nElem = donor_geometry->node[iPointDonor]->GetnElem(); - else nElem =donor_geometry->node[iPointDonor]->GetnPoint(); - - for (jElem=0; jElem < nElem; jElem++) { - if (nDim==3) { - temp_donor = donor_geometry->node[iPointDonor]->GetElem(jElem); - nFaces = donor_geometry->elem[temp_donor]->GetnFaces(); - for (iFace=0; iFaceelem[temp_donor]->GetnNodesFace(iFace); - for (iDonor=0; iDonorelem[temp_donor]->GetFaces(iFace, iDonor); - dPoint = donor_geometry->elem[temp_donor]->GetNode(inode); - face_on_marker = (face_on_marker && (donor_geometry->node[dPoint]->GetVertex(markDonor) !=-1)); - } - - if (face_on_marker ) { - for (iDonor=0; iDonorelem[temp_donor]->GetFaces(iFace, iDonor); - dPoint = donor_geometry->elem[temp_donor]->GetNode(inode); - // Match node on the face to the correct global index - long jGlobalPoint = donor_geometry->node[dPoint]->GetGlobalIndex(); - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (jVertex = 0; jVertex < Buffer_Receive_nVertex_Donor[iProcessor]; jVertex++) { - if (jGlobalPoint == Buffer_Receive_GlobalPoint[MaxLocalVertex_Donor*iProcessor+jVertex]) { - Buffer_Send_FaceNodes[nLocalFaceNodes_Donor]=MaxLocalVertex_Donor*iProcessor+jVertex; - Buffer_Send_FaceProc[nLocalFaceNodes_Donor]=iProcessor; - } - } - } - nLocalFaceNodes_Donor++; // Increment total number of face-nodes / processor - } - /* Store the indices */ - Buffer_Send_FaceIndex[nLocalFace_Donor+1] = Buffer_Send_FaceIndex[nLocalFace_Donor]+nNodes; - nLocalFace_Donor++; // Increment number of faces / processor - } - } - } - else { - /*-- Determine whether this face/edge is on the marker --*/ - face_on_marker=true; - for (iDonor=0; iDonornode[iPointDonor]->GetEdge(jElem); - dPoint = donor_geometry->edge[inode]->GetNode(iDonor); - face_on_marker = (face_on_marker && (donor_geometry->node[dPoint]->GetVertex(markDonor) !=-1)); - } - if (face_on_marker ) { - for (iDonor=0; iDonornode[iPointDonor]->GetEdge(jElem); - dPoint = donor_geometry->edge[inode]->GetNode(iDonor); - // Match node on the face to the correct global index - long jGlobalPoint = donor_geometry->node[dPoint]->GetGlobalIndex(); - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (jVertex = 0; jVertex < Buffer_Receive_nVertex_Donor[iProcessor]; jVertex++) { - if (jGlobalPoint == Buffer_Receive_GlobalPoint[MaxLocalVertex_Donor*iProcessor+jVertex]) { - Buffer_Send_FaceNodes[nLocalFaceNodes_Donor]=MaxLocalVertex_Donor*iProcessor+jVertex; - Buffer_Send_FaceProc[nLocalFaceNodes_Donor]=iProcessor; - } - } - } - nLocalFaceNodes_Donor++; // Increment total number of face-nodes / processor - } - /* Store the indices */ - Buffer_Send_FaceIndex[nLocalFace_Donor+1] = Buffer_Send_FaceIndex[nLocalFace_Donor]+nNodes; - nLocalFace_Donor++; // Increment number of faces / processor - } - } - } - } - } - - //Buffer_Send_FaceIndex[nLocalFace_Donor+1] = MaxFaceNodes_Donor*rank+nLocalFaceNodes_Donor; - - SU2_MPI::Allgather(Buffer_Send_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, - Buffer_Receive_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_FaceProc, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, - Buffer_Receive_FaceProc, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, - Buffer_Receive_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - /*--- Loop over the vertices on the target Marker ---*/ - for (iVertex = 0; iVertexvertex[markTarget][iVertex]->GetNode(); - - if (!target_geometry->node[Point_Target]->GetDomain()) continue; - - Coord_i = target_geometry->node[Point_Target]->GetCoord(); - /*---Loop over the faces previously communicated/stored ---*/ - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - - nFaces = (unsigned int)Buffer_Receive_nFace_Donor[iProcessor]; - - for (iFace = 0; iFace< nFaces; iFace++) { - /*--- ---*/ - - nNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1] - - (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; - - su2double *X = new su2double[nNodes*(nDim+1)]; - faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face - for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetDonorElem(donor_elem); // in 2D is nearest neighbor - target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nNodes); - for (iDonor=0; iDonorvertex[markTarget][iVertex]->GetnDonorPoints(); - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); - - for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,storeGlobal[iDonor]); - //cout <vertex[markTarget][iVertex]->SetDonorCoeff(iDonor,storeCoeff[iDonor]); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); - } - - } - - delete[] Buffer_Send_nVertex_Donor; - delete[] Buffer_Send_nFace_Donor; - delete[] Buffer_Send_nFaceNodes_Donor; - - delete[] Buffer_Receive_nVertex_Donor; - delete[] Buffer_Receive_nFace_Donor; - delete[] Buffer_Receive_nFaceNodes_Donor; - - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_Normal; - delete[] Buffer_Send_GlobalPoint; - - delete[] Buffer_Receive_Coord; - delete[] Buffer_Receive_Normal; - delete[] Buffer_Receive_GlobalPoint; - - delete[] Buffer_Send_FaceIndex; - delete[] Buffer_Send_FaceNodes; - delete[] Buffer_Send_FaceProc; - - delete[] Buffer_Receive_FaceIndex; - delete[] Buffer_Receive_FaceNodes; - delete[] Buffer_Receive_FaceProc; - } - delete [] Coord; - delete [] Normal; - - delete [] projected_point; -} - -void CIsoparametric::Isoparameters(unsigned short nDim, unsigned short nDonor, - su2double *X, su2double *xj, su2double *isoparams) { - short iDonor,iDim,k; // indices - su2double tmp, tmp2; - - su2double *x = new su2double[nDim+1]; - su2double *x_tmp = new su2double[nDim+1]; - su2double *Q = new su2double[nDonor*nDonor]; - su2double *R = new su2double[nDonor*nDonor]; - su2double *A = new su2double[(nDim+2)*nDonor]; - su2double *A2 = NULL; - su2double *x2 = new su2double[nDim+1]; - - bool *test = new bool[nDim+1]; - bool *testi = new bool[nDim+1]; - - su2double eps = 1E-10; - - short n = nDim+1; - - if (nDonor>2) { - /*--- Create Matrix A: 1st row all 1's, 2nd row x coordinates, 3rd row y coordinates, etc ---*/ - /*--- Right hand side is [1, \vec{x}']'---*/ - for (iDonor=0; iDonoreps && iDonor=0; iDonor--) { - if (R[iDonor*nDonor+iDonor]>eps) - isoparams[iDonor]=x_tmp[iDonor]/R[iDonor*nDonor+iDonor]; - else - isoparams[iDonor]=0; - for (k=0; k1.0) xi=1.0; - if (xi<-1.0) xi=-1.0; - if (eta>1.0) eta=1.0; - if (eta<-1.0) eta=-1.0; - isoparams[0]=0.25*(1-xi)*(1-eta); - isoparams[1]=0.25*(1+xi)*(1-eta); - isoparams[2]=0.25*(1+xi)*(1+eta); - isoparams[3]=0.25*(1-xi)*(1+eta); - - } - if (nDonor<4) { - tmp = 0.0; // value for normalization - tmp2=0; // check for maximum value, to be used to id nearest neighbor if necessary - k=0; // index for maximum value - for (iDonor=0; iDonor< nDonor; iDonor++) { - if (isoparams[iDonor]>tmp2) { - k=iDonor; - tmp2=isoparams[iDonor]; - } - // [0,1] - if (isoparams[iDonor]<0) isoparams[iDonor]=0; - if (isoparams[iDonor]>1) isoparams[iDonor] = 1; - tmp +=isoparams[iDonor]; - } - if (tmp>0) - for (iDonor=0; iDonor< nDonor; iDonor++) - isoparams[iDonor]=isoparams[iDonor]/tmp; - else { - isoparams[k] = 1.0; - } - } - - delete [] x; - delete [] x_tmp; - delete [] Q; - delete [] R; - delete [] A; - delete [] A2; - delete [] x2; - - delete [] test; - delete [] testi; - -} - -CMirror::CMirror(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, - unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { } - -void CMirror::Set_TransferCoeff(CConfig **config) { - unsigned long iVertex, jVertex; - unsigned long iPoint; - unsigned short iDonor=0, iFace=0, iTarget=0; - - unsigned short nMarkerInt; - unsigned short iMarkerInt; - - int markDonor=0, markTarget=0; - - unsigned int nNodes=0, iNodes=0; - unsigned long nVertexDonor = 0, nVertexTarget= 0; - unsigned long Point_Donor = 0; - unsigned long pGlobalPoint = 0; - int iProcessor; - - unsigned long nLocalFace_Donor = 0, nLocalFaceNodes_Donor=0; - - unsigned long faceindex; - - int nProcessor = size; - - su2double *Buffer_Send_Coeff, *Buffer_Receive_Coeff; - su2double coeff; - - /*--- Number of markers on the interface ---*/ - nMarkerInt = (config[targetZone]->GetMarker_n_ZoneInterface())/2; - - /*--- For the number of markers on the interface... ---*/ - for (iMarkerInt=1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - /*--- Procedure: - * - Loop through vertices of the aero grid - * - Find nearest element and allocate enough space in the aero grid donor point info - * - Set the transfer coefficient values - */ - - /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - - /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); - - /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ - if(!CheckInterfaceBoundary(markDonor, markTarget)) continue; - - if(markDonor != -1) - nVertexDonor = donor_geometry->GetnVertex( markDonor ); - else - nVertexDonor = 0; - - if(markTarget != -1) - nVertexTarget = target_geometry->GetnVertex( markTarget ); - else - nVertexTarget = 0; - - /*-- Collect the number of donor nodes: re-use 'Face' containers --*/ - nLocalFace_Donor=0; - nLocalFaceNodes_Donor=0; - for (jVertex = 0; jVertexvertex[markDonor][jVertex]->GetNode(); // Local index of jVertex - - if (donor_geometry->node[Point_Donor]->GetDomain()) { - nNodes = donor_geometry->vertex[markDonor][jVertex]->GetnDonorPoints(); - nLocalFaceNodes_Donor+=nNodes; - nLocalFace_Donor++; - } - } - Buffer_Send_nFace_Donor= new unsigned long [1]; - Buffer_Send_nFaceNodes_Donor= new unsigned long [1]; - - Buffer_Receive_nFace_Donor = new unsigned long [nProcessor]; - Buffer_Receive_nFaceNodes_Donor = new unsigned long [nProcessor]; - - Buffer_Send_nFace_Donor[0] = nLocalFace_Donor; - Buffer_Send_nFaceNodes_Donor[0] = nLocalFaceNodes_Donor; - - /*--- Send Interface vertex information --*/ -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &MaxFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalFace_Donor, &MaxFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFace_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - MaxFace_Donor++; -#else - nGlobalFace_Donor = nLocalFace_Donor; - nGlobalFaceNodes_Donor = nLocalFaceNodes_Donor; - MaxFaceNodes_Donor = nLocalFaceNodes_Donor; - MaxFace_Donor = nLocalFace_Donor+1; - Buffer_Receive_nFace_Donor[0] = Buffer_Send_nFace_Donor[0]; - Buffer_Receive_nFaceNodes_Donor[0] = Buffer_Send_nFaceNodes_Donor[0]; -#endif - - /*-- Send donor info --*/ - Buffer_Send_FaceIndex = new unsigned long[MaxFace_Donor]; - Buffer_Send_FaceNodes = new unsigned long[MaxFaceNodes_Donor]; - Buffer_Send_GlobalPoint = new long[MaxFaceNodes_Donor]; - Buffer_Send_Coeff = new su2double[MaxFaceNodes_Donor]; - - Buffer_Receive_FaceIndex= new unsigned long[MaxFace_Donor*nProcessor]; - Buffer_Receive_FaceNodes= new unsigned long[MaxFaceNodes_Donor*nProcessor]; - Buffer_Receive_GlobalPoint = new long[MaxFaceNodes_Donor*nProcessor]; - Buffer_Receive_Coeff = new su2double[MaxFaceNodes_Donor*nProcessor]; - - for (iVertex=0; iVertexvertex[markDonor][jVertex]->GetNode(); // Local index of jVertex - if (donor_geometry->node[Point_Donor]->GetDomain()) { - nNodes = donor_geometry->vertex[markDonor][jVertex]->GetnDonorPoints(); - for (iDonor=0; iDonornode[Point_Donor]->GetGlobalIndex(); - Buffer_Send_GlobalPoint[nLocalFaceNodes_Donor] = - donor_geometry->vertex[markDonor][jVertex]->GetInterpDonorPoint(iDonor); - Buffer_Send_Coeff[nLocalFaceNodes_Donor] = - donor_geometry->vertex[markDonor][jVertex]->GetDonorCoeff(iDonor); - nLocalFaceNodes_Donor++; - } - Buffer_Send_FaceIndex[nLocalFace_Donor+1] =Buffer_Send_FaceIndex[nLocalFace_Donor]+nNodes; - nLocalFace_Donor++; - } - } - - SU2_MPI::Allgather(Buffer_Send_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, - Buffer_Receive_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_GlobalPoint, MaxFaceNodes_Donor, MPI_LONG, - Buffer_Receive_GlobalPoint, MaxFaceNodes_Donor, MPI_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_Coeff, MaxFaceNodes_Donor, MPI_DOUBLE, - Buffer_Receive_Coeff, MaxFaceNodes_Donor, MPI_DOUBLE, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, - Buffer_Receive_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - /*--- Loop over the vertices on the target Marker ---*/ - for (iVertex = 0; iVertexvertex[markTarget][iVertex]->GetNode(); - if (target_geometry->node[iPoint]->GetDomain()) { - long Global_Point = target_geometry->node[iPoint]->GetGlobalIndex(); - nNodes = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iFace = 0; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { - faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face - iNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1]- (unsigned int)faceindex; - for (iTarget=0; iTargetvertex[markTarget][iVertex]->SetnDonorPoints(nNodes); - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); - - iDonor = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iFace = 0; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { - - faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face - iNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1]- (unsigned int)faceindex; - for (iTarget=0; iTargetvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,pGlobalPoint); - target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor,coeff); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, iProcessor); - iDonor++; - } - } - } - } - } - } - delete[] Buffer_Send_nFace_Donor; - delete[] Buffer_Send_nFaceNodes_Donor; - - delete[] Buffer_Receive_nFace_Donor; - delete[] Buffer_Receive_nFaceNodes_Donor; - - delete[] Buffer_Send_FaceIndex; - delete[] Buffer_Send_FaceNodes; - delete[] Buffer_Send_GlobalPoint; - delete[] Buffer_Send_Coeff; - - delete[] Buffer_Receive_FaceIndex; - delete[] Buffer_Receive_FaceNodes; - delete[] Buffer_Receive_GlobalPoint; - delete[] Buffer_Receive_Coeff; - - } -} - -CSlidingMesh::CSlidingMesh(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, - unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { } - -void CSlidingMesh::Set_TransferCoeff(CConfig **config) { - - /* --- This routine sets the transfer coefficient for sliding mesh approach --- */ - - /* - * The algorithm is based on Rinaldi et al. "Flux-conserving treatment of non-conformal interfaces - * for finite-volume discritization of conservaation laws" 2015, Comp. Fluids, 120, pp 126-139 - */ - - /* 0 - Variable declaration - */ - - /* --- General variables --- */ - - bool check; - - unsigned short iDim, nDim; - - unsigned long ii, jj, *uptr; - unsigned long vPoint; - unsigned long iEdgeVisited, nEdgeVisited, iNodeVisited; - unsigned long nAlreadyVisited, nToVisit, StartVisited; - - unsigned long *alreadyVisitedDonor, *ToVisit, *tmpVect; - unsigned long *storeProc, *tmp_storeProc; - - su2double dTMP; - su2double *Coeff_Vect, *tmp_Coeff_Vect; - - /* --- Geometrical variables --- */ - - su2double *Coord_i, *Coord_j, dist, mindist, *Normal; - su2double Area, Area_old, tmp_Area; - su2double LineIntersectionLength, *Direction, length; - - - /* --- Markers Variables --- */ - - unsigned short iMarkerInt, nMarkerInt; - - unsigned long iVertex, nVertexTarget; - - int markDonor, markTarget; - - /* --- Target variables --- */ - - unsigned long target_iPoint, jVertexTarget; - unsigned long nEdges_target, nNode_target; - - unsigned long *Target_nLinkedNodes, *Target_LinkedNodes, *Target_StartLinkedNodes, *target_segment; - unsigned long *Target_Proc; - long *Target_GlobalPoint, *Donor_GlobalPoint; - - su2double *TargetPoint_Coord, *target_iMidEdge_point, *target_jMidEdge_point, **target_element; - - /* --- Donor variables --- */ - - unsigned long donor_StartIndex, donor_forward_point, donor_backward_point, donor_iPoint, donor_OldiPoint; - unsigned long nEdges_donor, nNode_donor, nGlobalVertex_Donor; - - unsigned long nDonorPoints, iDonor; - unsigned long *Donor_Vect, *tmp_Donor_Vect; - unsigned long *Donor_nLinkedNodes, *Donor_LinkedNodes, *Donor_StartLinkedNodes; - unsigned long *Donor_Proc; - - su2double *donor_iMidEdge_point, *donor_jMidEdge_point; - su2double **donor_element, *DonorPoint_Coord; - - /* 1 - Variable pre-processing - */ - - nDim = donor_geometry->GetnDim(); - - /*--- Setting up auxiliary vectors ---*/ - - Donor_Vect = NULL; - Coeff_Vect = NULL; - storeProc = NULL; - - tmp_Donor_Vect = NULL; - tmp_Coeff_Vect = NULL; - tmp_storeProc = NULL; - - Normal = new su2double[nDim]; - Direction = new su2double[nDim]; - - - /* 2 - Find boundary tag between touching grids */ - - /*--- Number of markers on the FSI interface ---*/ - nMarkerInt = (int)( config[ donorZone ]->GetMarker_n_ZoneInterface() ) / 2; - - /*--- For the number of markers on the interface... ---*/ - for ( iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++ ){ - - /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - - /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); - - /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ - if(!CheckInterfaceBoundary(markDonor, markTarget)) continue; - - if(markTarget != -1) - nVertexTarget = target_geometry->GetnVertex( markTarget ); - else - nVertexTarget = 0; - - /* - 3 -Reconstruct the boundaries from parallel partitioning - */ - - /*--- Target boundary ---*/ - ReconstructBoundary(targetZone, markTarget); - - nGlobalVertex_Target = nGlobalVertex; - - TargetPoint_Coord = Buffer_Receive_Coord; - Target_GlobalPoint = Buffer_Receive_GlobalPoint; - Target_nLinkedNodes = Buffer_Receive_nLinkedNodes; - Target_StartLinkedNodes = Buffer_Receive_StartLinkedNodes; - Target_LinkedNodes = Buffer_Receive_LinkedNodes; - Target_Proc = Buffer_Receive_Proc; - - /*--- Donor boundary ---*/ - ReconstructBoundary(donorZone, markDonor); - - nGlobalVertex_Donor = nGlobalVertex; - - DonorPoint_Coord = Buffer_Receive_Coord; - Donor_GlobalPoint = Buffer_Receive_GlobalPoint; - Donor_nLinkedNodes = Buffer_Receive_nLinkedNodes; - Donor_StartLinkedNodes = Buffer_Receive_StartLinkedNodes; - Donor_LinkedNodes = Buffer_Receive_LinkedNodes; - Donor_Proc = Buffer_Receive_Proc; - - /*--- Starts building the supermesh layer (2D or 3D) ---*/ - /* - For each target node, it first finds the closest donor point - * - Then it creates the supermesh in the close proximity of the target point: - * - Starting from the closest donor node, it expands the supermesh by including - * donor elements neighboring the initial one, until the overall target area is fully covered. - */ - - if(nDim == 2){ - - target_iMidEdge_point = new su2double[nDim]; - target_jMidEdge_point = new su2double[nDim]; - - donor_iMidEdge_point = new su2double[nDim]; - donor_jMidEdge_point = new su2double[nDim]; - - /*--- Starts with supermesh reconstruction ---*/ - - target_segment = new unsigned long[2]; - - for (iVertex = 0; iVertex < nVertexTarget; iVertex++) { - - nDonorPoints = 0; - - /*--- Stores coordinates of the target node ---*/ - - target_iPoint = target_geometry->vertex[markTarget][iVertex]->GetNode(); - - if (target_geometry->node[target_iPoint]->GetDomain()){ - - Coord_i = target_geometry->node[target_iPoint]->GetCoord(); - - /*--- Brute force to find the closest donor_node ---*/ - - mindist = 1E6; - donor_StartIndex = 0; - - for (donor_iPoint = 0; donor_iPoint < nGlobalVertex_Donor; donor_iPoint++) { - - Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; - - dist = PointsDistance(nDim, Coord_i, Coord_j); - - if (dist < mindist) { - mindist = dist; - donor_StartIndex = donor_iPoint; - } - - if (dist == 0.0){ - donor_StartIndex = donor_iPoint; - break; - } - } - - donor_iPoint = donor_StartIndex; - donor_OldiPoint = donor_iPoint; - - /*--- Contruct information regarding the target cell ---*/ - - long dPoint = target_geometry->node[target_iPoint]->GetGlobalIndex(); - for (jVertexTarget = 0; jVertexTarget < nGlobalVertex_Target; jVertexTarget++) - if( dPoint == Target_GlobalPoint[jVertexTarget] ) - break; - - if ( Target_nLinkedNodes[jVertexTarget] == 1 ){ - target_segment[0] = Target_LinkedNodes[ Target_StartLinkedNodes[jVertexTarget] ]; - target_segment[1] = jVertexTarget; - } - else{ - target_segment[0] = Target_LinkedNodes[ Target_StartLinkedNodes[jVertexTarget] ]; - target_segment[1] = Target_LinkedNodes[ Target_StartLinkedNodes[jVertexTarget] + 1]; - } - - dTMP = 0; - for(iDim = 0; iDim < nDim; iDim++){ - target_iMidEdge_point[iDim] = ( TargetPoint_Coord[ nDim * target_segment[0] + iDim ] + target_geometry->node[ target_iPoint ]->GetCoord(iDim) ) / 2; - target_jMidEdge_point[iDim] = ( TargetPoint_Coord[ nDim * target_segment[1] + iDim ] + target_geometry->node[ target_iPoint ]->GetCoord(iDim) ) / 2; - - Direction[iDim] = target_jMidEdge_point[iDim] - target_iMidEdge_point[iDim]; - dTMP += Direction[iDim] * Direction[iDim]; - } - - dTMP = sqrt(dTMP); - for(iDim = 0; iDim < nDim; iDim++) - Direction[iDim] /= dTMP; - - length = PointsDistance(nDim, target_iMidEdge_point, target_jMidEdge_point); - - check = false; - - /*--- Proceeds along the forward direction (depending on which connected boundary node is found first) ---*/ - - while( !check ){ - - /*--- Proceeds until the value of the intersection area is null ---*/ - - if ( Donor_nLinkedNodes[donor_iPoint] == 1 ){ - donor_forward_point = Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_iPoint] ]; - donor_backward_point = donor_iPoint; - } - else{ - uptr = &Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_iPoint] ]; - - if( donor_OldiPoint != uptr[0] ){ - donor_forward_point = uptr[0]; - donor_backward_point = uptr[1]; - } - else{ - donor_forward_point = uptr[1]; - donor_backward_point = uptr[0]; - } - } - - if(donor_iPoint >= nGlobalVertex_Donor){ - check = true; - continue; - } - - for(iDim = 0; iDim < nDim; iDim++){ - donor_iMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_forward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; - donor_jMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_backward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; - } - - LineIntersectionLength = ComputeLineIntersectionLength(target_iMidEdge_point, target_jMidEdge_point, donor_iMidEdge_point, donor_jMidEdge_point, Direction); - - if ( LineIntersectionLength == 0.0 ){ - check = true; - continue; - } - - /*--- In case the element intersects the target cell, update the auxiliary communication data structure ---*/ - - tmp_Coeff_Vect = new su2double[ nDonorPoints + 1 ]; - tmp_Donor_Vect = new unsigned long[ nDonorPoints + 1 ]; - tmp_storeProc = new unsigned long[ nDonorPoints + 1 ]; - - for( iDonor = 0; iDonor < nDonorPoints; iDonor++){ - tmp_Donor_Vect[iDonor] = Donor_Vect[iDonor]; - tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; - tmp_storeProc[iDonor] = storeProc[iDonor]; - } - - tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; - tmp_Coeff_Vect[ nDonorPoints ] = LineIntersectionLength / length; - tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; - - if (Donor_Vect != NULL) delete [] Donor_Vect; - if (Coeff_Vect != NULL) delete [] Coeff_Vect; - if (storeProc != NULL) delete [] storeProc; - - Donor_Vect = tmp_Donor_Vect; - Coeff_Vect = tmp_Coeff_Vect; - storeProc = tmp_storeProc; - - donor_OldiPoint = donor_iPoint; - donor_iPoint = donor_forward_point; - - nDonorPoints++; - } - - if ( Donor_nLinkedNodes[donor_StartIndex] == 2 ){ - check = false; - - uptr = &Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_StartIndex] ]; - - donor_iPoint = uptr[1]; - donor_OldiPoint = donor_StartIndex; - } - else - check = true; - - /*--- Proceeds along the backward direction (depending on which connected boundary node is found first) ---*/ - - while( !check ){ - - /*--- Proceeds until the value of the intersection length is null ---*/ - if ( Donor_nLinkedNodes[donor_iPoint] == 1 ){ - donor_forward_point = donor_OldiPoint; - donor_backward_point = donor_iPoint; - } - else{ - uptr = &Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_iPoint] ]; - - if( donor_OldiPoint != uptr[0] ){ - donor_forward_point = uptr[0]; - donor_backward_point = uptr[1]; - } - else{ - donor_forward_point = uptr[1]; - donor_backward_point = uptr[0]; - } - } - - if(donor_iPoint >= nGlobalVertex_Donor){ - check = true; - continue; - } - - for(iDim = 0; iDim < nDim; iDim++){ - donor_iMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_forward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; - donor_jMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_backward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; - } - - LineIntersectionLength = ComputeLineIntersectionLength(target_iMidEdge_point, target_jMidEdge_point, donor_iMidEdge_point, donor_jMidEdge_point, Direction); - - if ( LineIntersectionLength == 0.0 ){ - check = true; - continue; - } - - /*--- In case the element intersects the target cell, update the auxiliary communication data structure ---*/ - - tmp_Coeff_Vect = new su2double[ nDonorPoints + 1 ]; - tmp_Donor_Vect = new unsigned long[ nDonorPoints + 1 ]; - tmp_storeProc = new unsigned long[ nDonorPoints + 1 ]; - - for( iDonor = 0; iDonor < nDonorPoints; iDonor++){ - tmp_Donor_Vect[iDonor] = Donor_Vect[iDonor]; - tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; - tmp_storeProc[iDonor] = storeProc[iDonor]; - } - - tmp_Coeff_Vect[ nDonorPoints ] = LineIntersectionLength / length; - tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; - tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; - - if (Donor_Vect != NULL) delete [] Donor_Vect; - if (Coeff_Vect != NULL) delete [] Coeff_Vect; - if (storeProc != NULL) delete [] storeProc; - - Donor_Vect = tmp_Donor_Vect; - Coeff_Vect = tmp_Coeff_Vect; - storeProc = tmp_storeProc; - - donor_OldiPoint = donor_iPoint; - donor_iPoint = donor_forward_point; - - nDonorPoints++; - } - - /*--- Set the communication data structure and copy data from the auxiliary vectors ---*/ - - target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nDonorPoints); - - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); - - for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ - target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor, Coeff_Vect[iDonor]); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor, Donor_GlobalPoint[Donor_Vect[iDonor]]); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); - } - } - } - - delete [] target_segment; - - delete [] target_iMidEdge_point; - delete [] target_jMidEdge_point; - - delete [] donor_iMidEdge_point; - delete [] donor_jMidEdge_point; - } - else{ - /* --- 3D geometry, creates a superficial super-mesh --- */ - - for (iVertex = 0; iVertex < nVertexTarget; iVertex++) { - - nDonorPoints = 0; - - /*--- Stores coordinates of the target node ---*/ - - target_iPoint = target_geometry->vertex[markTarget][iVertex]->GetNode(); - - if (!target_geometry->node[target_iPoint]->GetDomain()) continue; - - Coord_i = target_geometry->node[target_iPoint]->GetCoord(); - - target_geometry->vertex[markTarget][iVertex]->GetNormal(Normal); - - /*--- The value of Area computed here includes also portion of boundary belonging to different marker ---*/ - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - - for (iDim = 0; iDim < nDim; iDim++) - Normal[iDim] /= Area; - - for (iDim = 0; iDim < nDim; iDim++) - Coord_i[iDim] = target_geometry->node[target_iPoint]->GetCoord(iDim); - - long dPoint = target_geometry->node[target_iPoint]->GetGlobalIndex(); - for (target_iPoint = 0; target_iPoint < nGlobalVertex_Target; target_iPoint++){ - if( dPoint == Target_GlobalPoint[target_iPoint] ) - break; - } - - /*--- Build local surface dual mesh for target element ---*/ - - nEdges_target = Target_nLinkedNodes[target_iPoint]; - - nNode_target = 2*(nEdges_target + 1); - - target_element = new su2double*[nNode_target]; - for (ii = 0; ii < nNode_target; ii++) - target_element[ii] = new su2double[nDim]; - - nNode_target = Build_3D_surface_element(Target_LinkedNodes, Target_StartLinkedNodes, Target_nLinkedNodes, TargetPoint_Coord, target_iPoint, target_element); - - /*--- Brute force to find the closest donor_node ---*/ - - mindist = 1E6; - donor_StartIndex = 0; - - for (donor_iPoint = 0; donor_iPoint < nGlobalVertex_Donor; donor_iPoint++) { - - Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; - - dist = PointsDistance(nDim, Coord_i, Coord_j); - - if (dist < mindist) { - mindist = dist; - donor_StartIndex = donor_iPoint; - } - - if (dist == 0.0){ - donor_StartIndex = donor_iPoint; - break; - } - } - - donor_iPoint = donor_StartIndex; - - nEdges_donor = Donor_nLinkedNodes[donor_iPoint]; - - donor_element = new su2double*[ 2*nEdges_donor + 2 ]; - for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - donor_element[ii] = new su2double[nDim]; - - nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); - - Area = 0; - for (ii = 1; ii < nNode_target-1; ii++){ - for (jj = 1; jj < nNode_donor-1; jj++){ - Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal); - //cout << Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal) << endl; - } - } - - for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - delete [] donor_element[ii]; - delete [] donor_element; - - nDonorPoints = 1; - - /*--- In case the element intersect the target cell update the auxiliary communication data structure ---*/ - - Coeff_Vect = new su2double[ nDonorPoints ]; - Donor_Vect = new unsigned long[ nDonorPoints ]; - storeProc = new unsigned long[ nDonorPoints ]; - - Coeff_Vect[0] = Area; - Donor_Vect[0] = donor_iPoint; - storeProc[0] = Donor_Proc[donor_iPoint]; - - alreadyVisitedDonor = new unsigned long[1]; - - alreadyVisitedDonor[0] = donor_iPoint; - nAlreadyVisited = 1; - StartVisited = 0; - - Area_old = -1; - - while( Area > Area_old ){ - - /* - * - Starting from the closest donor_point, it expands the supermesh by a countour search pattern. - * - The closest donor element becomes the core, at each iteration a new layer of elements around the core is taken into account - */ - - Area_old = Area; - - ToVisit = NULL; - nToVisit = 0; - - for( iNodeVisited = StartVisited; iNodeVisited < nAlreadyVisited; iNodeVisited++ ){ - - vPoint = alreadyVisitedDonor[ iNodeVisited ]; - - nEdgeVisited = Donor_nLinkedNodes[vPoint]; - - for (iEdgeVisited = 0; iEdgeVisited < nEdgeVisited; iEdgeVisited++){ - - donor_iPoint = Donor_LinkedNodes[ Donor_StartLinkedNodes[vPoint] + iEdgeVisited]; - - /*--- Check if the node to visit is already listed in the data structure to avoid double visits ---*/ - - check = 0; - - for( jj = 0; jj < nAlreadyVisited; jj++ ){ - if( donor_iPoint == alreadyVisitedDonor[jj] ){ - check = 1; - break; - } - } - - if( check == 0 && ToVisit != NULL){ - for( jj = 0; jj < nToVisit; jj++ ) - if( donor_iPoint == ToVisit[jj] ){ - check = 1; - break; - } - } - - if( check == 0 ){ - /*--- If the node was not already visited, visit it and list it into data structure ---*/ - - tmpVect = new unsigned long[ nToVisit + 1 ]; - - for( jj = 0; jj < nToVisit; jj++ ) - tmpVect[jj] = ToVisit[jj]; - tmpVect[nToVisit] = donor_iPoint; - - if( ToVisit != NULL ) - delete [] ToVisit; - - ToVisit = tmpVect; - tmpVect = NULL; - - nToVisit++; - - /*--- Find the value of the intersection area between the current donor element and the target element --- */ - - nEdges_donor = Donor_nLinkedNodes[donor_iPoint]; - - donor_element = new su2double*[ 2*nEdges_donor + 2 ]; - for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - donor_element[ii] = new su2double[nDim]; - - nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); - - tmp_Area = 0; - for (ii = 1; ii < nNode_target-1; ii++) - for (jj = 1; jj < nNode_donor-1; jj++) - tmp_Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal); - - for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - delete [] donor_element[ii]; - delete [] donor_element; - - /*--- In case the element intersect the target cell update the auxiliary communication data structure ---*/ - - tmp_Coeff_Vect = new su2double[ nDonorPoints + 1 ]; - tmp_Donor_Vect = new unsigned long[ nDonorPoints + 1 ]; - tmp_storeProc = new unsigned long[ nDonorPoints + 1 ]; - - for( iDonor = 0; iDonor < nDonorPoints; iDonor++){ - tmp_Donor_Vect[iDonor] = Donor_Vect[iDonor]; - tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; - tmp_storeProc[iDonor] = storeProc[iDonor]; - } - - tmp_Coeff_Vect[ nDonorPoints ] = tmp_Area; - tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; - tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; - - if (Donor_Vect != NULL) {delete [] Donor_Vect; } - if (Coeff_Vect != NULL) {delete [] Coeff_Vect; } - if (storeProc != NULL) {delete [] storeProc; } - - Donor_Vect = tmp_Donor_Vect; - Coeff_Vect = tmp_Coeff_Vect; - storeProc = tmp_storeProc; - - tmp_Coeff_Vect = NULL; - tmp_Donor_Vect = NULL; - tmp_storeProc = NULL; - - nDonorPoints++; - - Area += tmp_Area; - } - } - } - - /*--- Update auxiliary data structure ---*/ - - StartVisited = nAlreadyVisited; - - tmpVect = new unsigned long[ nAlreadyVisited + nToVisit ]; - - for( jj = 0; jj < nAlreadyVisited; jj++ ) - tmpVect[jj] = alreadyVisitedDonor[jj]; - - for( jj = 0; jj < nToVisit; jj++ ) - tmpVect[ nAlreadyVisited + jj ] = ToVisit[jj]; - - if( alreadyVisitedDonor != NULL ) - delete [] alreadyVisitedDonor; - - alreadyVisitedDonor = tmpVect; - - nAlreadyVisited += nToVisit; - - delete [] ToVisit; - } - - delete [] alreadyVisitedDonor; - - /*--- Set the communication data structure and copy data from the auxiliary vectors ---*/ - - target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nDonorPoints); - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); - - for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ - target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor, Coeff_Vect[iDonor]/Area); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorPoint( iDonor, Donor_GlobalPoint[ Donor_Vect[iDonor] ] ); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); - //cout <GetnDim(); - - su2double dotA2, dotB1, dotB2; - - dotA2 = 0; - for(iDim = 0; iDim < nDim; iDim++) - dotA2 += ( A2[iDim] - A1[iDim] ) * Direction[iDim]; - - if( dotA2 >= 0 ){ - dotB1 = 0; - dotB2 = 0; - for(iDim = 0; iDim < nDim; iDim++){ - dotB1 += ( B1[iDim] - A1[iDim] ) * Direction[iDim]; - dotB2 += ( B2[iDim] - A1[iDim] ) * Direction[iDim]; - } - } - else{ - dotA2 *= -1; - - dotB1 = 0; - dotB2 = 0; - for(iDim = 0; iDim < nDim; iDim++){ - dotB1 -= ( B1[iDim] - A1[iDim] ) * Direction[iDim]; - dotB2 -= ( B2[iDim] - A1[iDim] ) * Direction[iDim]; - } - } - - if( dotB1 >= 0 && dotB1 <= dotA2 ){ - if ( dotB2 < 0 ) - return fabs( dotB1 ); - if ( dotB2 > dotA2 ) - return fabs( dotA2 - dotB1 ); - - return fabs( dotB1 - dotB2 ); - } - - if( dotB2 >= 0 && dotB2 <= dotA2 ){ - if ( dotB1 < 0 ) - return fabs(dotB2); - if ( dotB1 > dotA2 ) - return fabs( dotA2 - dotB2 ); - } - - if( ( dotB1 <= 0 && dotA2 <= dotB2 ) || ( dotB2 <= 0 && dotA2 <= dotB1 ) ) - return fabs( dotA2 ); - - return 0.0; -} - -su2double CSlidingMesh::Compute_Triangle_Intersection(su2double* A1, su2double* A2, su2double* A3, su2double* B1, su2double* B2, su2double* B3, su2double* Direction){ - - /* --- This routine is ONLY for 3D grids --- */ - /* --- Projects triangle points onto a plane, specified by its normal "Direction", and calls the ComputeIntersectionArea routine --- */ - - unsigned short iDim; - unsigned short nDim = 3; - - su2double I[3], J[3], K[3]; - su2double a1[3], a2[3], a3[3]; - su2double b1[3], b2[3], b3[3]; - su2double m1, m2; - - /* --- Reference frame is determined by: x = A1A2 y = x ^ ( -Direction ) --- */ - - for(iDim = 0; iDim < 3; iDim++){ - a1[iDim] = 0; - a2[iDim] = 0; - a3[iDim] = 0; - - b1[iDim] = 0; - b2[iDim] = 0; - b3[iDim] = 0; - } - - m1 = 0; - for(iDim = 0; iDim < nDim; iDim++){ - K[iDim] = Direction[iDim]; - - m1 += K[iDim] * K[iDim]; - } - - for(iDim = 0; iDim < nDim; iDim++) - K[iDim] /= sqrt(m1); - - m2 = 0; - for(iDim = 0; iDim < nDim; iDim++) - m2 += (A2[iDim] - A1[iDim]) * K[iDim]; - - m1 = 0; - for(iDim = 0; iDim < nDim; iDim++){ - I[iDim] = (A2[iDim] - A1[iDim]) - m2 * K[iDim]; - m1 += I[iDim] * I[iDim]; - } - - for(iDim = 0; iDim < nDim; iDim++) - I[iDim] /= sqrt(m1); - - // Cross product to find Y - J[0] = K[1]*I[2] - K[2]*I[1]; - J[1] = -(K[0]*I[2] - K[2]*I[0]); - J[2] = K[0]*I[1] - K[1]*I[0]; - - /* --- Project all points on the plane specified by Direction and change their reference frame taking A1 as origin --- */ - - for(iDim = 0; iDim < nDim; iDim++){ - a2[0] += (A2[iDim] - A1[iDim]) * I[iDim]; - a2[1] += (A2[iDim] - A1[iDim]) * J[iDim]; - a2[2] += (A2[iDim] - A1[iDim]) * K[iDim]; - - a3[0] += (A3[iDim] - A1[iDim]) * I[iDim]; - a3[1] += (A3[iDim] - A1[iDim]) * J[iDim]; - a3[2] += (A3[iDim] - A1[iDim]) * K[iDim]; - - b1[0] += (B1[iDim] - A1[iDim]) * I[iDim]; - b1[1] += (B1[iDim] - A1[iDim]) * J[iDim]; - b1[2] += (B1[iDim] - A1[iDim]) * K[iDim]; - - b2[0] += (B2[iDim] - A1[iDim]) * I[iDim]; - b2[1] += (B2[iDim] - A1[iDim]) * J[iDim]; - b2[2] += (B2[iDim] - A1[iDim]) * K[iDim]; - - b3[0] += (B3[iDim] - A1[iDim]) * I[iDim]; - b3[1] += (B3[iDim] - A1[iDim]) * J[iDim]; - b3[2] += (B3[iDim] - A1[iDim]) * K[iDim]; - } - - /*--- Compute intersection area ---*/ - - return ComputeIntersectionArea( a1, a2, a3, b1, b2, b3 ); -} - -su2double CSlidingMesh::ComputeIntersectionArea( su2double* P1, su2double* P2, su2double* P3, su2double* Q1, su2double* Q2, su2double* Q3 ){ - - /* --- This routines computes the area of the polygonal element generated by the superimposition of 2 planar triangle --- */ - /* --- The 2 triangle must lie on the same plane --- */ - - unsigned short iDim, nPoints, i, j, k; - unsigned short nDim, min_theta_index; - - su2double points[16][2], IntersectionPoint[2], theta[6]; - su2double TriangleP[4][2], TriangleQ[4][2]; - su2double Area, det, dot1, dot2, dtmp, min_theta; - - nDim = 2; - nPoints = 0; - - for(iDim = 0; iDim < nDim; iDim++){ - TriangleP[0][iDim] = 0; - TriangleP[1][iDim] = P2[iDim] - P1[iDim]; - TriangleP[2][iDim] = P3[iDim] - P1[iDim]; - TriangleP[3][iDim] = 0; - - TriangleQ[0][iDim] = Q1[iDim] - P1[iDim]; - TriangleQ[1][iDim] = Q2[iDim] - P1[iDim]; - TriangleQ[2][iDim] = Q3[iDim] - P1[iDim]; - TriangleQ[3][iDim] = Q1[iDim] - P1[iDim]; - } - - - for( j = 0; j < 3; j++){ - if( CheckPointInsideTriangle(TriangleP[j], TriangleQ[0], TriangleQ[1], TriangleQ[2]) ){ - - // Then P1 is also inside triangle Q, so store it - for(iDim = 0; iDim < nDim; iDim++) - points[nPoints][iDim] = TriangleP[j][iDim]; - - nPoints++; - } - } - - for( j = 0; j < 3; j++){ - if( CheckPointInsideTriangle(TriangleQ[j], TriangleP[0], TriangleP[1], TriangleP[2]) ){ - - // Then Q1 is also inside triangle P, so store it - for(iDim = 0; iDim < nDim; iDim++) - points[nPoints][iDim] = TriangleQ[j][iDim]; - - nPoints++; - } - } - - - // Compute all edge intersections - - for( j = 0; j < 3; j++){ - for( i = 0; i < 3; i++){ - - det = (TriangleP[j][0] - TriangleP[j+1][0]) * ( TriangleQ[i][1] - TriangleQ[i+1][1] ) - (TriangleP[j][1] - TriangleP[j+1][1]) * (TriangleQ[i][0] - TriangleQ[i+1][0]); - - if ( det != 0.0 ){ - ComputeLineIntersectionPoint( TriangleP[j], TriangleP[j+1], TriangleQ[i], TriangleQ[i+1], IntersectionPoint ); - - dot1 = 0; - dot2 = 0; - for(iDim = 0; iDim < nDim; iDim++){ - dot1 += ( TriangleP[j][iDim] - IntersectionPoint[iDim] ) * ( TriangleP[j+1][iDim] - IntersectionPoint[iDim] ); - dot2 += ( TriangleQ[i][iDim] - IntersectionPoint[iDim] ) * ( TriangleQ[i+1][iDim] - IntersectionPoint[iDim] ); - } - - if( dot1 <= 0 && dot2 <= 0 ){ // It found one intersection - - // Store temporarily the intersection point - - for(iDim = 0; iDim < nDim; iDim++) - points[nPoints][iDim] = IntersectionPoint[iDim]; - - nPoints++; - } - } - } - } - - // Remove double points, if any - - for( i = 0; i < nPoints; i++){ - for( j = i+1; j < nPoints; j++){ - if(points[j][0] == points[i][0] && points[j][1] == points[i][1]){ - for( k = j; k < nPoints-1; k++){ - points[k][0] = points[k+1][0]; - points[k][1] = points[k+1][1]; - } - nPoints--; - j--; - } - } - } - - // Re-order nodes - - for( i = 1; i < nPoints; i++){ // Change again reference frame - for(iDim = 0; iDim < nDim; iDim++) - points[i][iDim] -= points[0][iDim]; - - // Compute polar azimuth for each node but the first - theta[i] = atan2(points[i][1], points[i][0]); - } - - for(iDim = 0; iDim < nDim; iDim++) - points[0][iDim] = 0; - - for( i = 1; i < nPoints; i++){ - - min_theta = theta[i]; - min_theta_index = 0; - - for( j = i + 1; j < nPoints; j++){ - - if( theta[j] < min_theta ){ - min_theta = theta[j]; - min_theta_index = j; - } - } - - if( min_theta_index != 0 ){ - dtmp = theta[i]; - theta[i] = theta[min_theta_index]; - theta[min_theta_index] = dtmp; - - dtmp = points[i][0]; - points[i][0] = points[min_theta_index][0]; - points[min_theta_index][0] = dtmp; - - dtmp = points[i][1]; - points[i][1] = points[min_theta_index][1]; - points[min_theta_index][1] = dtmp; - } - } - - // compute area using cross product rule, points position are referred to the 2-dimensional, local, reference frame centered in points[0] - - Area = 0; - - if (nPoints > 2){ - for( i = 1; i < nPoints-1; i++ ){ - - // Ax*By - Area += ( points[i][0] - points[0][0] ) * ( points[i+1][1] - points[0][1] ); - - // Ay*Bx - Area -= ( points[i][1] - points[0][1] ) * ( points[i+1][0] - points[0][0] ); - } - } - - return fabs(Area)/2; -} - -void CSlidingMesh::ComputeLineIntersectionPoint( su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* IntersectionPoint ){ - - /* --- Uses determinant rule to compute the intersection point between 2 straight segments --- */ - /* This works only for lines on a 2D plane, A1, A2 and B1, B2 are respectively the head and the tail points of each segment, - * since they're on a 2D plane they are defined by a 2-elements array containing their coordinates */ - - su2double det; - - det = (A1[0] - A2[0]) * (B1[1] - B2[1]) - (A1[1] - A2[1]) * (B1[0] - B2[0]); - - if ( det != 0.0 ){ // else there is no intersection point - IntersectionPoint[0] = ( ( A1[0]*A2[1] - A1[1]*A2[0] ) * ( B1[0] - B2[0] ) - ( B1[0]*B2[1] - B1[1]*B2[0] ) * ( A1[0] - A2[0] ) ) / det; - IntersectionPoint[1] = ( ( A1[0]*A2[1] - A1[1]*A2[0] ) * ( B1[1] - B2[1] ) - ( B1[0]*B2[1] - B1[1]*B2[0] ) * ( A1[1] - A2[1] ) ) / det; - } -} - -bool CSlidingMesh::CheckPointInsideTriangle(su2double* Point, su2double* T1, su2double* T2, su2double* T3){ - - /* --- Check whether a point "Point" lies inside or outside a triangle defined by 3 points "T1", "T2", "T3" --- */ - /* For each edge it checks on which side the point lies: - * - Computes the unit vector pointing at the internal side of the edge - * - Comutes the vector that connects the point to a point along the edge - * - If the dot product is positive it means that the point is on the internal side of the edge - * - If the check is positive for all the 3 edges, then the point lies within the triangle - */ - - unsigned short iDim, nDim, check; - - su2double vect1[2], vect2[2], r[2]; - su2double dot; - - check = 0; - nDim = 2; - - /* --- Check first edge --- */ - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++){ - vect1[iDim] = T3[iDim] - T1[iDim]; // vec 1 is aligned to the edge - vect2[iDim] = T2[iDim] - T1[iDim]; // vect 2 is the vector connecting one edge point to the third triangle vertex - - r[iDim] = Point[iDim] - T1[iDim]; // Connects point to vertex T1 - - dot += vect2[iDim] * vect2[iDim]; - } - dot = sqrt(dot); - - for(iDim = 0; iDim < nDim; iDim++) - vect2[iDim] /= dot; - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++) - dot += vect1[iDim] * vect2[iDim]; - - for(iDim = 0; iDim < nDim; iDim++) - vect1[iDim] = T3[iDim] - (T1[iDim] + dot * vect2[iDim]); // Computes the inward unit vector - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++) // Checs that the point lies on the internal plane - dot += vect1[iDim] * r[iDim]; - - if (dot >= 0) - check++; - - /* --- Check second edge --- */ - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++){ - vect1[iDim] = T1[iDim] - T2[iDim]; - vect2[iDim] = T3[iDim] - T2[iDim]; - - r[iDim] = Point[iDim] - T2[iDim]; - - dot += vect2[iDim] * vect2[iDim]; - } - dot = sqrt(dot); - - for(iDim = 0; iDim < nDim; iDim++) - vect2[iDim] /= dot; - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++) - dot += vect1[iDim] * vect2[iDim]; - - for(iDim = 0; iDim < nDim; iDim++) - vect1[iDim] = T1[iDim] - (T2[iDim] + dot * vect2[iDim]); - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++) - dot += vect1[iDim] * r[iDim]; - - if (dot >= 0) - check++; - - /* --- Check third edge --- */ - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++){ - vect1[iDim] = T2[iDim] - T3[iDim]; - vect2[iDim] = T1[iDim] - T3[iDim]; - - r[iDim] = Point[iDim] - T3[iDim]; - - dot += vect2[iDim] * vect2[iDim]; - } - dot = sqrt(dot); - - for(iDim = 0; iDim < nDim; iDim++) - vect2[iDim] /= dot; - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++) - dot += vect1[iDim] * vect2[iDim]; - - for(iDim = 0; iDim < nDim; iDim++) - vect1[iDim] = T2[iDim] - (T3[iDim] + dot * vect2[iDim]); - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++) - dot += vect1[iDim] * r[iDim]; - - if (dot >= 0) - check++; - - return (check == 3); -} - -CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, - unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { } - -su2double CRadialBasisFunction::Get_RadialBasisValue(ENUM_RADIALBASIS type, const su2double radius, const su2double dist) -{ - su2double rbf = dist/radius; - - switch (type) { - - case WENDLAND_C2: - if(rbf < 1) rbf = pow(pow((1-rbf),2),2)*(4*rbf+1); // double use of pow(x,2) for optimization - else rbf = 0.0; - break; - - case GAUSSIAN: - rbf = exp(-rbf*rbf); - break; - - case THIN_PLATE_SPLINE: - if(rbf < numeric_limits::min()) rbf = 0.0; - else rbf *= rbf*log(rbf); - break; - - case MULTI_QUADRIC: - case INV_MULTI_QUADRIC: - rbf = sqrt(1.0+rbf*rbf); - if(type == INV_MULTI_QUADRIC) rbf = 1.0/rbf; - break; - } - - return rbf; -} - -void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { - - /*--- RBF options. ---*/ - const auto kindRBF = static_cast(config[donorZone]->GetKindRadialBasisFunction()); - const bool usePolynomial = config[donorZone]->GetRadialBasisFunctionPolynomialOption(); - const su2double paramRBF = config[donorZone]->GetRadialBasisFunctionParameter(); - const su2double pruneTol = config[donorZone]->GetRadialBasisFunctionPruneTol(); - - const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; - const int nDim = donor_geometry->GetnDim(); - - const int nProcessor = size; - Buffer_Send_nVertex_Donor = new unsigned long [1]; - Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; - - /*--- Process interface patches in parallel, fetch all donor point coordinates, - * then distribute interpolation matrix computation over ranks and threads. - * To avoid repeating calls to Collect_VertexInfo we also save the global - * indices of the donor points and the mpi rank index that owns them. ---*/ - vector DonorCoordinates(nMarkerInt); - vector > DonorGlobalPoint(nMarkerInt); - vector > DonorProcessor(nMarkerInt); - vector AssignedProcessor(nMarkerInt,-1); - vector TotalWork(nProcessor,0); - - for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; ++iMarkerInt) { - - /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ - const auto mark_donor = Find_InterfaceMarker(config[donorZone], iMarkerInt+1); - - /*--- On the target side: find the tag of the boundary sharing the interface. ---*/ - const auto mark_target = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); - - /*--- If the zone does not contain the interface continue to the next pair of markers. ---*/ - if(!CheckInterfaceBoundary(mark_donor,mark_target)) continue; - - unsigned long nVertexDonor = 0; - if(mark_donor != -1) nVertexDonor = donor_geometry->GetnVertex(mark_donor); - - /*--- Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor. ---*/ - Determine_ArraySize(false, mark_donor, mark_target, nVertexDonor, nDim); - - /*--- Compute total number of donor vertices. ---*/ - auto nGlobalVertexDonor = accumulate(Buffer_Receive_nVertex_Donor, - Buffer_Receive_nVertex_Donor+nProcessor, 0ul); - - /*--- Gather coordinates and global point indices. ---*/ - Buffer_Send_Coord = new su2double [ MaxLocalVertex_Donor * nDim ]; - Buffer_Send_GlobalPoint = new long [ MaxLocalVertex_Donor ]; - Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; - Buffer_Receive_GlobalPoint = new long [ nProcessor * MaxLocalVertex_Donor ]; - - Collect_VertexInfo(false, mark_donor, mark_target, nVertexDonor, nDim); - - /*--- Compresses the gathered donor point information to simplify computations. ---*/ - auto& DonorCoord = DonorCoordinates[iMarkerInt]; - auto& DonorPoint = DonorGlobalPoint[iMarkerInt]; - auto& DonorProc = DonorProcessor[iMarkerInt]; - DonorCoord.resize(nGlobalVertexDonor, nDim); - DonorPoint.resize(nGlobalVertexDonor); - DonorProc.resize(nGlobalVertexDonor); - - auto iCount = 0ul; - for (int iProcessor = 0; iProcessor < nProcessor; ++iProcessor) { - auto offset = iProcessor * MaxLocalVertex_Donor; - for (auto iVertex = 0ul; iVertex < Buffer_Receive_nVertex_Donor[iProcessor]; ++iVertex) { - for (int iDim = 0; iDim < nDim; ++iDim) - DonorCoord(iCount,iDim) = Buffer_Receive_Coord[(offset+iVertex)*nDim + iDim]; - DonorPoint[iCount] = Buffer_Receive_GlobalPoint[offset+iVertex]; - DonorProc[iCount] = iProcessor; - ++iCount; - } - } - assert((iCount == nGlobalVertexDonor) && "Global donor point count mismatch."); - - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_GlobalPoint; - delete[] Buffer_Receive_Coord; - delete[] Buffer_Receive_GlobalPoint; - - /*--- Static work scheduling over ranks based on which one has less work currently. ---*/ - int iProcessor = 0; - for (int i = 1; i < nProcessor; ++i) - if (TotalWork[i] < TotalWork[iProcessor]) iProcessor = i; - - TotalWork[iProcessor] += pow(nGlobalVertexDonor,3); // based on matrix inversion. - - AssignedProcessor[iMarkerInt] = iProcessor; - - } - - /*--- Compute the interpolation matrices for each patch of coordinates - * assigned to the rank. Subdivide work further by threads. ---*/ - vector nPolynomialVec(nMarkerInt,-1); - vector > keepPolynomialRowVec(nMarkerInt, vector(nDim,1)); - vector CinvTrucVec(nMarkerInt); - - SU2_OMP_PARALLEL_(for schedule(dynamic,1)) - for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; ++iMarkerInt) { - if (rank == AssignedProcessor[iMarkerInt]) { - ComputeGeneratorMatrix(kindRBF, usePolynomial, paramRBF, - DonorCoordinates[iMarkerInt], nPolynomialVec[iMarkerInt], - keepPolynomialRowVec[iMarkerInt], CinvTrucVec[iMarkerInt]); - } - } - - /*--- Final loop over interface markers to compute the interpolation coefficients. ---*/ - - for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; iMarkerInt++) { - - /*--- Identify the rank that computed the interpolation matrix for this marker. ---*/ - const int iProcessor = AssignedProcessor[iMarkerInt]; - /*--- If no processor was assigned to work, the zone does not contain the interface. ---*/ - if (iProcessor < 0) continue; - - /*--- Setup target information. ---*/ - const int mark_target = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); - unsigned long nVertexTarget = 0; - if(mark_target != -1) nVertexTarget = target_geometry->GetnVertex(mark_target); - - /*--- Set references to donor information. ---*/ - auto& DonorCoord = DonorCoordinates[iMarkerInt]; - auto& DonorPoint = DonorGlobalPoint[iMarkerInt]; - auto& DonorProc = DonorProcessor[iMarkerInt]; - - auto& C_inv_trunc = CinvTrucVec[iMarkerInt]; - auto& nPolynomial = nPolynomialVec[iMarkerInt]; - auto& keepPolynomialRow = keepPolynomialRowVec[iMarkerInt]; - - const auto nGlobalVertexDonor = DonorCoord.rows(); - -#ifdef HAVE_MPI - /*--- For simplicity, broadcast small information about the interpolation matrix. ---*/ - SU2_MPI::Bcast(&nPolynomial, 1, MPI_INT, iProcessor, MPI_COMM_WORLD); - SU2_MPI::Bcast(keepPolynomialRow.data(), nDim, MPI_INT, iProcessor, MPI_COMM_WORLD); - - /*--- Send C_inv_trunc only to the ranks that need it (those with target points), - * partial broadcast. MPI wrapper not used due to passive double. ---*/ - vector allNumVertex(nProcessor); - SU2_MPI::Allgather(&nVertexTarget, 1, MPI_UNSIGNED_LONG, - allNumVertex.data(), 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - if (rank == iProcessor) { - for (int jProcessor = 0; jProcessor < nProcessor; ++jProcessor) - if ((jProcessor != iProcessor) && (allNumVertex[jProcessor] != 0)) - MPI_Send(C_inv_trunc.data(), C_inv_trunc.size(), - MPI_DOUBLE, jProcessor, 0, MPI_COMM_WORLD); - } - else if (nVertexTarget != 0) { - C_inv_trunc.resize(1+nPolynomial+nGlobalVertexDonor, nGlobalVertexDonor); - MPI_Recv(C_inv_trunc.data(), C_inv_trunc.size(), MPI_DOUBLE, - iProcessor, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - } -#endif - - /*--- Compute H (interpolation) matrix, distributing - * target points over the threads in the rank. ---*/ - SU2_OMP_PARALLEL - { - su2passivevector coeff_vec(nGlobalVertexDonor); - - SU2_OMP_FOR_DYN(roundUpDiv(nVertexTarget, 2*omp_get_max_threads())) - for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; iVertexTarget++) { - - auto target_vertex = target_geometry->vertex[mark_target][iVertexTarget]; - const auto point_target = target_vertex->GetNode(); - - /*--- If not domain point move to next. ---*/ - if (!target_geometry->node[point_target]->GetDomain()) continue; - - const su2double* coord_i = target_geometry->node[point_target]->GetCoord(); - - /*--- Multiply target vector by C_inv_trunc to obtain the interpolation coefficients. - * The target vector is not stored, we consume its entries immediately to avoid - * strided access to C_inv_trunc (as it is row-major). ---*/ - - /*--- Polynominal part: ---*/ - if (usePolynomial) { - /*--- Constant term. ---*/ - for (auto j = 0ul; j < nGlobalVertexDonor; ++j) - coeff_vec(j) = C_inv_trunc(0,j); - - /*--- Linear terms. ---*/ - for (int iDim = 0, idx = 1; iDim < nDim; ++iDim) { - /*--- Of which one may have been excluded. ---*/ - if (!keepPolynomialRow[iDim]) continue; - for (auto j = 0ul; j < nGlobalVertexDonor; ++j) - coeff_vec(j) += SU2_TYPE::GetValue(coord_i[iDim]) * C_inv_trunc(idx,j); - idx += 1; - } - } - else { - /*--- Initialize vector to zero. ---*/ - for (auto j = 0ul; j < nGlobalVertexDonor; ++j) coeff_vec(j) = 0.0; - } - - /*--- RBF terms: ---*/ - for (auto iVertexDonor = 0ul; iVertexDonor < nGlobalVertexDonor; ++iVertexDonor) { - auto w_ij = SU2_TYPE::GetValue(Get_RadialBasisValue(kindRBF, paramRBF, - PointsDistance(nDim, coord_i, DonorCoord[iVertexDonor]))); - - for (auto j = 0ul; j < nGlobalVertexDonor; ++j) - coeff_vec(j) += w_ij * C_inv_trunc(1+nPolynomial+iVertexDonor, j); - } - - /*--- Prune small coefficients. ---*/ - auto nnz = PruneSmallCoefficients(SU2_TYPE::GetValue(pruneTol), coeff_vec); - - /*--- Allocate and set donor information for this target point. ---*/ - target_vertex->SetnDonorPoints(nnz); - target_vertex->Allocate_DonorInfo(); - - for (unsigned long iVertex = 0, iSet = 0; iVertex < nGlobalVertexDonor; ++iVertex) { - if (fabs(coeff_vec(iVertex)) > 0.0) { - target_vertex->SetInterpDonorProcessor(iSet, DonorProc[iVertex]); - target_vertex->SetInterpDonorPoint(iSet, DonorPoint[iVertex]); - target_vertex->SetDonorCoeff(iSet, coeff_vec(iVertex)); - ++iSet; - } - } - - } // end target vertex loop - } // end SU2_OMP_PARALLEL - - /*--- Delete global data that will no longer be used. ---*/ - DonorCoord.resize(0,0); - vector().swap(DonorPoint); - vector().swap(DonorProc); - C_inv_trunc.resize(0,0); - - } // end loop over interface markers - - delete[] Buffer_Send_nVertex_Donor; - delete[] Buffer_Receive_nVertex_Donor; - -} - -void CRadialBasisFunction::ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool usePolynomial, - su2double radius, const su2activematrix& coords, int& nPolynomial, - vector& keepPolynomialRow, su2passivematrix& C_inv_trunc) const { - - const su2double interfaceCoordTol = 1e6 * numeric_limits::epsilon(); - - const auto nVertexDonor = coords.rows(); - const int nDim = coords.cols(); - - /*--- Populate interpolation kernel. ---*/ - CSymmetricMatrix global_M(nVertexDonor); - - for (auto iVertex = 0ul; iVertex < nVertexDonor; ++iVertex) - for (auto jVertex = iVertex; jVertex < nVertexDonor; ++jVertex) - global_M(iVertex, jVertex) = SU2_TYPE::GetValue(Get_RadialBasisValue(type, radius, - PointsDistance(nDim, coords[iVertex], coords[jVertex]))); - - /*--- Invert M matrix (operation is in-place). ---*/ - const bool kernelIsSPD = (type==WENDLAND_C2) || (type==GAUSSIAN) || (type==INV_MULTI_QUADRIC); - global_M.Invert(kernelIsSPD); - - /*--- Compute C_inv_trunc. ---*/ - if (usePolynomial) { - - /*--- Fill P matrix (P for points, with an extra top row of ones). ---*/ - su2passivematrix P(1+nDim, nVertexDonor); - - for (auto iVertex = 0ul; iVertex < nVertexDonor; iVertex++) { - P(0, iVertex) = 1.0; - for (int iDim = 0; iDim < nDim; ++iDim) - P(1+iDim, iVertex) = SU2_TYPE::GetValue(coords(iVertex, iDim)); - } - - /*--- Check if points lie on a plane and remove one coordinate from P if so. ---*/ - nPolynomial = CheckPolynomialTerms(interfaceCoordTol, keepPolynomialRow, P); - - /*--- Compute Mp = (P * M^-1 * P^T)^-1 ---*/ - CSymmetricMatrix Mp(nPolynomial+1); - - su2passivematrix tmp; - global_M.MatMatMult('R', P, tmp); // tmp = P * M^-1 - - for (int i = 0; i <= nPolynomial; ++i) // Mp = tmp * P - for (int j = i; j <= nPolynomial; ++j) { - Mp(i,j) = 0.0; - for (auto k = 0ul; k < nVertexDonor; ++k) Mp(i,j) += tmp(i,k) * P(j,k); - } - Mp.Invert(false); // Mp = Mp^-1 - - /*--- Compute M_p * P * M^-1, the top part of C_inv_trunc. ---*/ - Mp.MatMatMult('L', P, tmp); - su2passivematrix C_inv_top; - global_M.MatMatMult('R', tmp, C_inv_top); - - /*--- Compute tmp = (I - P^T * M_p * P * M^-1), part of the bottom part of - C_inv_trunc. Note that most of the product is known from the top part. ---*/ - tmp.resize(nVertexDonor, nVertexDonor); - - for (auto i = 0ul; i < nVertexDonor; ++i) { - for (auto j = 0ul; j < nVertexDonor; ++j) { - tmp(i,j) = 0.0; - for (int k = 0; k <= nPolynomial; ++k) tmp(i,j) -= P(k,i) * C_inv_top(k,j); - } - tmp(i,i) += 1.0; // identity part - } - - /*--- Compute M^-1 * (I - P^T * M_p * P * M^-1), finalize bottom of C_inv_trunc. ---*/ - global_M.MatMatMult('L', tmp, C_inv_trunc); - - /*--- Merge top and bottom of C_inv_trunc. ---*/ - tmp = move(C_inv_trunc); - C_inv_trunc.resize(1+nPolynomial+nVertexDonor, nVertexDonor); - memcpy(C_inv_trunc[0], C_inv_top.data(), C_inv_top.size()*sizeof(passivedouble)); - memcpy(C_inv_trunc[1+nPolynomial], tmp.data(), tmp.size()*sizeof(passivedouble)); - } - else { - /*--- No polynomial term used in the interpolation, C_inv_trunc = M^-1. ---*/ - - C_inv_trunc.resize(nVertexDonor, nVertexDonor); - for (auto i = 0ul; i < nVertexDonor; ++i) - for (auto j = 0ul; j < nVertexDonor; ++j) - C_inv_trunc(i,j) = global_M(i,j); - - } // end usePolynomial - -} - -int CRadialBasisFunction::CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, - su2passivematrix &P) const { - const int m = P.rows(); - const int n = P.cols(); - - /*--- The first row of P is all ones and we do not care about it for this analysis. ---*/ - const int n_rows = m-1; - keep_row.resize(n_rows); - - /*--- By default assume points are not on a plane (all rows kept). ---*/ - int n_polynomial = n_rows; - for (int i = 0; i < n_rows; ++i) keep_row[i] = 1; - - /*--- Fit a plane through the points in P. ---*/ - - /*--- Compute P times its transpose and invert. ---*/ - CSymmetricMatrix PPT(n_rows); - - for (int i = 0; i < n_rows; ++i) - for (int j = i; j < n_rows; ++j) { - PPT(i,j) = 0.0; - for (int k = 0; k < n; ++k) PPT(i,j) += P(i+1,k) * P(j+1,k); - } - PPT.Invert(true); - - /*--- RHS for the least squares fit (vector of ones times P). ---*/ - vector coeff(n_rows,0.0); - - for (int i = 0; i < n_rows; ++i) - for (int j = 0; j < n; ++j) - coeff[i] += P(i+1,j); - - /*--- Multiply the RHS by the inverse thus obtaining the coefficients. ---*/ - PPT.MatVecMult(coeff.data()); - - /*--- Determine the maximum deviation of the points from the fitted plane. ---*/ - passivedouble max_diff = 0.0; - - for (int j = 0; j < n; ++j) - { - passivedouble sum = 0.0; - for (int i = 0; i < n_rows; ++i) sum += coeff[i] * P(i+1,j); - - /*--- 1.0 is the arbitrary constant we are assuming when fitting - the plane, i.e. the vector of ones used to generate the RHS. ---*/ - max_diff = max(abs(1.0-sum), max_diff); - } - - /*--- If points lie on plane remove row associated with the maximum coefficient. ---*/ - if (max_diff < max_diff_tol) - { - /*--- Find the max coeff and mark the corresponding row for removal. ---*/ - int remove_row = 0; - for (int i = 1; i < n_rows; ++i) - if (abs(coeff[i]) > abs(coeff[remove_row])) - remove_row = i; - - /*--- Mark row as removed and adjust number of polynomial terms. ---*/ - n_polynomial = n_rows-1; - keep_row[remove_row] = 0; - - /*--- Truncated P by shifting rows "up". ---*/ - for (auto i = remove_row+1; i < m-1; ++i) - for (int j = 0; j < n; ++j) - P(i,j) = P(i+1,j); - } - - return n_polynomial; -} - -int CRadialBasisFunction::PruneSmallCoefficients(passivedouble tolerance, - su2passivevector& coeffs) const { - - /*--- Determine the pruning threshold. ---*/ - passivedouble thresh = 0.0; - for (auto i = 0ul; i < coeffs.size(); ++i) - thresh = max(thresh, fabs(coeffs(i))); - thresh *= tolerance; - - /*--- Prune and count non-zeros. ---*/ - int numNonZeros = 0; - passivedouble coeffSum = 0.0; - for (auto i = 0ul; i < coeffs.size(); ++i) { - if (fabs(coeffs(i)) > thresh) { - coeffSum += coeffs(i); - ++numNonZeros; - } - else coeffs(i) = 0.0; - } - - /*--- Correct remaining coefficients, sum must be 1 for conservation. ---*/ - passivedouble correction = 1.0 / coeffSum; - for (auto i = 0ul; i < coeffs.size(); ++i) coeffs(i) *= correction; - - return numNonZeros; -} - -void CSymmetricMatrix::Initialize(int N) -{ - sz = N; - val_vec.resize(sz*sz); - initialized = true; -} - -void CSymmetricMatrix::CholeskyDecompose() -{ -#ifndef HAVE_LAPACK - assert(initialized && "Matrix not initialized."); - - for (int j = 0; j < sz; ++j) { - passivedouble sum = 0.0; - for (int k = 0; k < j; ++k) sum -= pow(Get(j,k), 2); - sum += Get(j,j); - assert(sum > 0.0 && "LLT failed, matrix is not SPD."); - Set(j, j, sqrt(sum)); - - for (int i = j+1; i < sz; ++i) { - passivedouble sum = 0.0; - for (int k = 0; k < j; ++k) sum -= Get(i,k) * Get(j,k); - sum += Get(i,j); - Set(i, j, sum / Get(j,j)); - } - } - decomposed = CHOLESKY; -#endif -} - -void CSymmetricMatrix::LUDecompose() -{ -#ifndef HAVE_LAPACK - assert(initialized && "Matrix not initialized."); - - /*--- Copy matrix values to LU matrix, init permutation vec. ---*/ - decomp_vec.resize(sz*sz); - perm_vec.resize(sz); - for (int i = 0; i < sz; ++i) { - perm_vec[i] = i; - for (int j = i; j < sz; ++j) decomp(j,i) = decomp(i,j) = Get(i,j); - } - - /*--- Decompose LU matrix. ---*/ - for (int j = 0; j < sz-1; ++j) { - /*--- Search for maximum pivot and interchange rows. ---*/ - passivedouble pivot = decomp(j,j); - int pivot_idx = j; - for (int i = j+1; i < sz; ++i) - if (abs(decomp(i,j)) > abs(pivot)) { - pivot = decomp(i,j); - pivot_idx = i; - } - - if (pivot_idx != j) { - swap(perm_vec[j], perm_vec[pivot_idx]); - for (int k = 0; k < sz; ++k) - swap(decomp(j,k), decomp(pivot_idx,k)); - } - - /*--- Perform elimination. ---*/ - for (int k = j+1; k < sz; ++k) decomp(k,j) /= pivot; - - for (int k = j+1; k < sz; ++k) - for (int i = j+1; i < sz; ++i) - decomp(i,k) -= decomp(j,k)*decomp(i,j); - } - - decomposed = LU; -#endif -} - -void CSymmetricMatrix::CalcInv() -{ -#ifndef HAVE_LAPACK - assert(initialized && "Matrix not initialized."); - - /*--- Decompose matrix if not done yet. ---*/ - if (decomposed == NONE) { LUDecompose(); } - - /*--- Compute inverse from decomposed matrices. ---*/ - switch (decomposed) { - - case CHOLESKY: - { - /*--- Initialize inverse matrix. ---*/ - vector inv(sz*sz, 0.0); - - /*--- Compute L inverse. ---*/ - /*--- Solve smaller and smaller systems. ---*/ - for (int j = 0; j < sz; ++j) { - /*--- Forward substitution. ---*/ - inv[IdxSym(j,j)] = 1.0 / Get(j,j); - - for (int i = j+1; i < sz; ++i) { - passivedouble sum = 0.0; - for (int k = j; k < i; ++k) sum -= Get(i,k) * inv[IdxSym(k,j)]; - inv[IdxSym(i,j)] = sum / Get(i,i); - } - } // L inverse in inv - - /*--- Multiply inversed matrices overwrite val_vec. ---*/ - for (int j = 0; j < sz; ++j) - for (int i = j; i < sz; ++i) { - passivedouble sum = 0.0; - for (int k = i; k < sz; ++k) sum += inv[IdxSym(k,i)] * inv[IdxSym(k,j)]; - Set(i, j, sum); - } - - break; - } - - case LU: - { - /*--- Alias val_vec. ---*/ - vector& inv = val_vec; - - /*--- Invert L and U matrices in place. ---*/ - for (int j = 0; j < sz; ++j) { - inv[IdxFull(j,j)] = 1.0 / decomp(j,j); - - for (int i = j+1; i < sz; ++i) { - inv[IdxFull(i,j)] = -decomp(i,j); - inv[IdxFull(j,i)] = -decomp(j,i) * inv[IdxFull(j,j)]; - - for (int k = j+1; k < i; ++k) { - inv[IdxFull(i,j)] -= decomp(i,k) * inv[IdxFull(k,j)]; - inv[IdxFull(j,i)] -= decomp(k,i) * inv[IdxFull(j,k)]; - } - if (j+1 <= i) inv[IdxFull(j,i)] /= decomp(i,i); - } - } - // inverses in val_vec - - /*--- Multiply U_inv by L_inv, overwrite decomp_vec. ---*/ - for (int i = 0; i < sz; ++i) - for (int j = 0; j < sz; ++j) { - decomp(i,j) = 0.0; - for (int k = max(i,j); k < sz; ++k) - decomp(i,j) += inv[IdxFull(i,k)] * ((k==j)? 1.0 : inv[IdxFull(k,j)]); - } - - /*--- Permute multiplied matrix to recover A_inv, overwrite val_vec. ---*/ - for (int j = 0; j < sz; ++j) { - int k = perm_vec[j]; - for (int i = k; i < sz; ++i) Set(i, k, decomp(i,j)); - } - - /*--- Decomposition no longer needed. ---*/ - vector().swap(decomp_vec); - - break; - } - default: assert(false && "Default (LU) decomposition failed."); - } - - decomposed = NONE; -#endif -} - -void CSymmetricMatrix::CalcInv_sytri() -{ -#ifdef HAVE_LAPACK - char uplo = 'L'; - int info; - perm_vec.resize(sz); // ipiv array - - /*--- Query the optimum work size. ---*/ - int query = -1; passivedouble tmp; - dsytrf_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), &tmp, &query, &info); - query = static_cast(tmp); - decomp_vec.resize(query); // work array - - /*--- Factorize and invert. ---*/ - dsytrf_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), decomp_vec.data(), &query, &info); - if (info!=0) SU2_MPI::Error("LDLT factorization failed.", CURRENT_FUNCTION); - dsytri_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), decomp_vec.data(), &info); - if (info!=0) SU2_MPI::Error("Inversion with LDLT factorization failed.", CURRENT_FUNCTION); - - decomposed = NONE; -#endif -} - -void CSymmetricMatrix::CalcInv_potri() -{ -#ifdef HAVE_LAPACK - char uplo = 'L'; - int info; - - dpotrf_(&uplo, &sz, val_vec.data(), &sz, &info); - if (info!=0) SU2_MPI::Error("LLT factorization failed.", CURRENT_FUNCTION); - dpotri_(&uplo, &sz, val_vec.data(), &sz, &info); - if (info!=0) SU2_MPI::Error("Inversion with LLT factorization failed.", CURRENT_FUNCTION); - - decomposed = NONE; -#endif -} - -void CSymmetricMatrix::Invert(const bool is_spd) -{ -#ifdef HAVE_LAPACK - if(is_spd) CalcInv_potri(); - else CalcInv_sytri(); -#else - if(!is_spd) LUDecompose(); - else CholeskyDecompose(); - CalcInv(); -#endif -} - -void CSymmetricMatrix::MatVecMult(passivedouble *v) const -{ - passivedouble *tmp_res = new passivedouble [sz]; - - for (int i=0; i Date: Wed, 18 Mar 2020 15:34:26 +0000 Subject: [PATCH 12/79] cleanup interface preprocessing --- .../interface_interpolation/CInterpolator.hpp | 48 +- .../interface_interpolation/CInterpolator.cpp | 4 +- .../CIsoparametric.cpp | 34 +- .../CRadialBasisFunction.cpp | 16 + .../interface_interpolation/CSlidingMesh.cpp | 72 +-- SU2_CFD/src/drivers/CDriver.cpp | 411 +++++++----------- SU2_CFD/src/drivers/CMultizoneDriver.cpp | 8 +- 7 files changed, 271 insertions(+), 322 deletions(-) diff --git a/Common/include/interface_interpolation/CInterpolator.hpp b/Common/include/interface_interpolation/CInterpolator.hpp index 5144e37ce2bc..74e4840d5d02 100644 --- a/Common/include/interface_interpolation/CInterpolator.hpp +++ b/Common/include/interface_interpolation/CInterpolator.hpp @@ -45,11 +45,11 @@ class CInterpolator { const unsigned targetZone; /*!< \brief Index of target zone. */ unsigned long - MaxLocalVertex_Donor, /*!< \brief Maximum vertices per processor*/ - nGlobalFace_Donor, /*!< \brief Number of global donor faces*/ - nGlobalFaceNodes_Donor, /*!< \brief Number of global donor face nodes*/ - MaxFace_Donor, /*!< \brief Maximum faces per processor*/ - MaxFaceNodes_Donor; /*!< \brief Maximum nodes associated with faces per processor*/ + MaxLocalVertex_Donor, /*!< \brief Maximum vertices per processor*/ + nGlobalFace_Donor, /*!< \brief Number of global donor faces*/ + nGlobalFaceNodes_Donor, /*!< \brief Number of global donor face nodes*/ + MaxFace_Donor, /*!< \brief Maximum faces per processor*/ + MaxFaceNodes_Donor; /*!< \brief Maximum nodes associated with faces per processor*/ unsigned long *Buffer_Receive_nVertex_Donor, /*!< \brief Buffer to store the number of vertices per processor on the Donor domain */ @@ -68,23 +68,25 @@ class CInterpolator { long *Buffer_Send_GlobalPoint, /*!< \brief Buffer to send global point indices*/ *Buffer_Receive_GlobalPoint; /*!< \brief Buffer to receive global point indices*/ - su2double *Buffer_Send_Coord, /*!< \brief Buffer to send coordinate values*/ - *Buffer_Send_Normal, /*!< \brief Buffer to send normal vector values */ - *Buffer_Receive_Coord, /*!< \brief Buffer to receive coordinate values*/ - *Buffer_Receive_Normal; /*!< \brief Buffer to receive normal vector values*/ + su2double *Buffer_Send_Coord, /*!< \brief Buffer to send coordinate values*/ + *Buffer_Send_Normal, /*!< \brief Buffer to send normal vector values */ + *Buffer_Receive_Coord, /*!< \brief Buffer to receive coordinate values*/ + *Buffer_Receive_Normal; /*!< \brief Buffer to receive normal vector values*/ - unsigned long *Receive_GlobalPoint, /*!< \brief Buffer to receive Global point indexes*/ - *Buffer_Receive_nLinkedNodes, /*!< \brief Buffer to receive the number of edges connected to each node*/ - *Buffer_Receive_LinkedNodes, /*!< \brief Buffer to receive the list of notes connected to the nodes through an edge*/ - *Buffer_Receive_StartLinkedNodes, /*!< \brief Buffer to receive the index of the Receive_LinkedNodes buffer where corresponding list of linked nodes begins */ - *Buffer_Receive_Proc; /*!< \brief Buffer to receive the thread that owns the node*/ + unsigned long + *Receive_GlobalPoint, /*!< \brief Buffer to receive Global point indexes*/ + *Buffer_Receive_nLinkedNodes, /*!< \brief Buffer to receive the number of edges connected to each node*/ + *Buffer_Receive_LinkedNodes, /*!< \brief Buffer to receive the list of notes connected to the nodes through an edge*/ + *Buffer_Receive_StartLinkedNodes, /*!< \brief Buffer to receive the index of the Receive_LinkedNodes buffer where corresponding list of linked nodes begins */ + *Buffer_Receive_Proc; /*!< \brief Buffer to receive the thread that owns the node*/ - unsigned long nGlobalVertex_Target, /*!< \brief Global number of vertex of the target boundary*/ - nLocalVertex_Target, /*!< \brief Number of vertex of the target boundary owned by the thread*/ - nGlobalVertex_Donor, /*!< \brief Global number of vertex of the donor boundary*/ - nLocalVertex_Donor, /*!< \brief Number of vertex of the donor boundary owned by the thread*/ - nGlobalVertex, /*!< \brief Dummy variable to temporarily store the global number of vertex of a boundary*/ - nLocalLinkedNodes; /*!< \brief Dummy variable to temporarily store the number of vertex of a boundary*/ + unsigned long + nGlobalVertex_Target, /*!< \brief Global number of vertex of the target boundary*/ + nLocalVertex_Target, /*!< \brief Number of vertex of the target boundary owned by the thread*/ + nGlobalVertex_Donor, /*!< \brief Global number of vertex of the donor boundary*/ + nLocalVertex_Donor, /*!< \brief Number of vertex of the donor boundary owned by the thread*/ + nGlobalVertex, /*!< \brief Dummy variable to temporarily store the global number of vertex of a boundary*/ + nLocalLinkedNodes; /*!< \brief Dummy variable to temporarily store the number of vertex of a boundary*/ CGeometry**** const Geometry; /*! \brief Vector which stores n zones of geometry. */ CGeometry* const donor_geometry; /*! \brief Donor geometry. */ @@ -117,21 +119,21 @@ class CInterpolator { */ virtual void Set_TransferCoeff(CConfig **config) = 0; -protected: /*! * \brief Find the index of the interface marker shared by that zone * \param[in] config - Definition of the particular problem. * \param[in] val_marker_interface - Interface tag. */ - int Find_InterfaceMarker(const CConfig *config, unsigned short val_marker_interface) const; + static int Find_InterfaceMarker(const CConfig *config, unsigned short val_marker_interface); /*! * \brief Check whether an interface should be processed or not, i.e. if it is part of the zones. * \param[in] val_markDonor - Marker tag from donor zone. * \param[in] val_markTarget - Marker tag from target zone. */ - bool CheckInterfaceBoundary(int val_markDonor, int val_markTarget) const; + static bool CheckInterfaceBoundary(int val_markDonor, int val_markTarget); +protected: /*! * \brief Recontstruct the boundary connectivity from parallel partitioning and broadcasts it to all threads * \param[in] val_zone - index of the zone diff --git a/Common/src/interface_interpolation/CInterpolator.cpp b/Common/src/interface_interpolation/CInterpolator.cpp index 354336c35ade..05d54a74fbdf 100644 --- a/Common/src/interface_interpolation/CInterpolator.cpp +++ b/Common/src/interface_interpolation/CInterpolator.cpp @@ -40,7 +40,7 @@ CInterpolator::CInterpolator(CGeometry ****geometry_container, CConfig **config, target_geometry(geometry_container[jZone][INST_0][MESH_0]) { } -int CInterpolator::Find_InterfaceMarker(const CConfig *config, unsigned short val_marker_interface) const { +int CInterpolator::Find_InterfaceMarker(const CConfig *config, unsigned short val_marker_interface) { for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { /*--- If the tag GetMarker_All_ZoneInterface(iMarker) equals the interface we are looking for. ---*/ @@ -49,7 +49,7 @@ int CInterpolator::Find_InterfaceMarker(const CConfig *config, unsigned short va return -1; } -bool CInterpolator::CheckInterfaceBoundary(int markDonor, int markTarget) const { +bool CInterpolator::CheckInterfaceBoundary(int markDonor, int markTarget) { /*--- Determine whether the boundary is not on the rank because of * the partition or because it is not part of the zone. ---*/ diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp index 0d42834b6a29..ef3468b86fb3 100644 --- a/Common/src/interface_interpolation/CIsoparametric.cpp +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -77,6 +77,14 @@ void CIsoparametric::Set_TransferCoeff(CConfig **config) { Coord = new su2double[nDim]; Normal = new su2double[nDim]; + Buffer_Send_nVertex_Donor = new unsigned long [1]; + Buffer_Send_nFace_Donor = new unsigned long [1]; + Buffer_Send_nFaceNodes_Donor = new unsigned long [1]; + + Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; + Buffer_Receive_nFace_Donor = new unsigned long [nProcessor]; + Buffer_Receive_nFaceNodes_Donor = new unsigned long [nProcessor]; + nMarkerInt = (config[donorZone]->GetMarker_n_ZoneInterface())/2; /*--- For the number of markers on the interface... ---*/ @@ -106,14 +114,6 @@ void CIsoparametric::Set_TransferCoeff(CConfig **config) { else nVertexTarget = 0; - Buffer_Send_nVertex_Donor = new unsigned long [1]; - Buffer_Send_nFace_Donor = new unsigned long [1]; - Buffer_Send_nFaceNodes_Donor = new unsigned long [1]; - - Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; - Buffer_Receive_nFace_Donor = new unsigned long [nProcessor]; - Buffer_Receive_nFaceNodes_Donor = new unsigned long [nProcessor]; - /* Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor */ Determine_ArraySize(true, markDonor, markTarget, nVertexDonor, nDim); @@ -332,21 +332,12 @@ void CIsoparametric::Set_TransferCoeff(CConfig **config) { for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,storeGlobal[iDonor]); - //cout <vertex[markTarget][iVertex]->SetDonorCoeff(iDonor,storeCoeff[iDonor]); target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); } } - delete[] Buffer_Send_nVertex_Donor; - delete[] Buffer_Send_nFace_Donor; - delete[] Buffer_Send_nFaceNodes_Donor; - - delete[] Buffer_Receive_nVertex_Donor; - delete[] Buffer_Receive_nFace_Donor; - delete[] Buffer_Receive_nFaceNodes_Donor; - delete[] Buffer_Send_Coord; delete[] Buffer_Send_Normal; delete[] Buffer_Send_GlobalPoint; @@ -363,6 +354,15 @@ void CIsoparametric::Set_TransferCoeff(CConfig **config) { delete[] Buffer_Receive_FaceNodes; delete[] Buffer_Receive_FaceProc; } + + delete[] Buffer_Send_nVertex_Donor; + delete[] Buffer_Send_nFace_Donor; + delete[] Buffer_Send_nFaceNodes_Donor; + + delete[] Buffer_Receive_nVertex_Donor; + delete[] Buffer_Receive_nFace_Donor; + delete[] Buffer_Receive_nFaceNodes_Donor; + delete [] Coord; delete [] Normal; diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp index c9ba5b5e9294..fd5504ed8c8b 100644 --- a/Common/src/interface_interpolation/CRadialBasisFunction.cpp +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -29,6 +29,22 @@ #include "../../include/CConfig.hpp" #include "../../include/geometry/CGeometry.hpp" +#if defined(HAVE_MKL) +#include "mkl.h" +#ifndef HAVE_LAPACK +#define HAVE_LAPACK +#endif +#elif defined(HAVE_LAPACK) +/*--- Lapack / Blas routines used in RBF interpolation. ---*/ +extern "C" void dsptrf_(char*, int*, passivedouble*, int*, int*); +extern "C" void dsptri_(char*, int*, passivedouble*, int*, passivedouble*, int*); +extern "C" void dsytrf_(char*, int*, passivedouble*, int*, int*, passivedouble*, int*, int*); +extern "C" void dsytri_(char*, int*, passivedouble*, int*, int*, passivedouble*, int*); +extern "C" void dpotrf_(char*, int*, passivedouble*, int*, int*); +extern "C" void dpotri_(char*, int*, passivedouble*, int*, int*); +extern "C" void dsymm_(char*, char*, int*, int*, passivedouble*, passivedouble*, int*, + passivedouble*, int*, passivedouble*, passivedouble*, int*); +#endif CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { diff --git a/Common/src/interface_interpolation/CSlidingMesh.cpp b/Common/src/interface_interpolation/CSlidingMesh.cpp index 41018ddda0be..62084eb55afd 100644 --- a/Common/src/interface_interpolation/CSlidingMesh.cpp +++ b/Common/src/interface_interpolation/CSlidingMesh.cpp @@ -244,8 +244,10 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { dTMP = 0; for(iDim = 0; iDim < nDim; iDim++){ - target_iMidEdge_point[iDim] = ( TargetPoint_Coord[ nDim * target_segment[0] + iDim ] + target_geometry->node[ target_iPoint ]->GetCoord(iDim) ) / 2; - target_jMidEdge_point[iDim] = ( TargetPoint_Coord[ nDim * target_segment[1] + iDim ] + target_geometry->node[ target_iPoint ]->GetCoord(iDim) ) / 2; + target_iMidEdge_point[iDim] = ( TargetPoint_Coord[ nDim * target_segment[0] + iDim ] + + target_geometry->node[ target_iPoint ]->GetCoord(iDim) ) / 2; + target_jMidEdge_point[iDim] = ( TargetPoint_Coord[ nDim * target_segment[1] + iDim ] + + target_geometry->node[ target_iPoint ]->GetCoord(iDim) ) / 2; Direction[iDim] = target_jMidEdge_point[iDim] - target_iMidEdge_point[iDim]; dTMP += Direction[iDim] * Direction[iDim]; @@ -288,11 +290,14 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { } for(iDim = 0; iDim < nDim; iDim++){ - donor_iMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_forward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; - donor_jMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_backward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; + donor_iMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_forward_point * nDim + iDim] + + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; + donor_jMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_backward_point * nDim + iDim] + + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; } - LineIntersectionLength = ComputeLineIntersectionLength(target_iMidEdge_point, target_jMidEdge_point, donor_iMidEdge_point, donor_jMidEdge_point, Direction); + LineIntersectionLength = ComputeLineIntersectionLength(target_iMidEdge_point, target_jMidEdge_point, + donor_iMidEdge_point, donor_jMidEdge_point, Direction); if ( LineIntersectionLength == 0.0 ){ check = true; @@ -368,11 +373,14 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { } for(iDim = 0; iDim < nDim; iDim++){ - donor_iMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_forward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; - donor_jMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_backward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; + donor_iMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_forward_point * nDim + iDim] + + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; + donor_jMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_backward_point * nDim + iDim] + + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; } - LineIntersectionLength = ComputeLineIntersectionLength(target_iMidEdge_point, target_jMidEdge_point, donor_iMidEdge_point, donor_jMidEdge_point, Direction); + LineIntersectionLength = ComputeLineIntersectionLength(target_iMidEdge_point, target_jMidEdge_point, + donor_iMidEdge_point, donor_jMidEdge_point, Direction); if ( LineIntersectionLength == 0.0 ){ check = true; @@ -476,7 +484,8 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { for (ii = 0; ii < nNode_target; ii++) target_element[ii] = new su2double[nDim]; - nNode_target = Build_3D_surface_element(Target_LinkedNodes, Target_StartLinkedNodes, Target_nLinkedNodes, TargetPoint_Coord, target_iPoint, target_element); + nNode_target = Build_3D_surface_element(Target_LinkedNodes, Target_StartLinkedNodes, Target_nLinkedNodes, + TargetPoint_Coord, target_iPoint, target_element); /*--- Brute force to find the closest donor_node ---*/ @@ -508,13 +517,14 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { for (ii = 0; ii < 2*nEdges_donor + 2; ii++) donor_element[ii] = new su2double[nDim]; - nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); + nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, + DonorPoint_Coord, donor_iPoint, donor_element); Area = 0; for (ii = 1; ii < nNode_target-1; ii++){ for (jj = 1; jj < nNode_donor-1; jj++){ - Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal); - //cout << Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal) << endl; + Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], + donor_element[0], donor_element[jj], donor_element[jj+1], Normal); } } @@ -608,12 +618,14 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { for (ii = 0; ii < 2*nEdges_donor + 2; ii++) donor_element[ii] = new su2double[nDim]; - nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); + nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, + DonorPoint_Coord, donor_iPoint, donor_element); tmp_Area = 0; for (ii = 1; ii < nNode_target-1; ii++) for (jj = 1; jj < nNode_donor-1; jj++) - tmp_Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal); + tmp_Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], + donor_element[0], donor_element[jj], donor_element[jj+1], Normal); for (ii = 0; ii < 2*nEdges_donor + 2; ii++) delete [] donor_element[ii]; @@ -687,7 +699,6 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor, Coeff_Vect[iDonor]/Area); target_geometry->vertex[markTarget][iVertex]->SetInterpDonorPoint( iDonor, Donor_GlobalPoint[ Donor_Vect[iDonor] ] ); target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); - //cout < -CDriver::CDriver(char* confFile, - unsigned short val_nZone, - SU2_Comm MPICommunicator, bool dummy_geo):config_file_name(confFile), StartTime(0.0), StopTime(0.0), UsedTime(0.0), - TimeIter(0), nZone(val_nZone), StopCalc(false), fsi(false), fem_solver(false), dry_run(dummy_geo) { +CDriver::CDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunicator, bool dummy_geo) : + config_file_name(confFile), StartTime(0.0), StopTime(0.0), UsedTime(0.0), + TimeIter(0), nZone(val_nZone), StopCalc(false), fsi(false), fem_solver(false), dry_run(dummy_geo) { /*--- Initialize Medipack (must also be here so it is initialized from python) ---*/ #ifdef HAVE_MPI @@ -2532,22 +2531,11 @@ void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGe unsigned short donorZone, targetZone; unsigned short nVar, nVarTransfer; - unsigned short nMarkerTarget, iMarkerTarget, nMarkerDonor, iMarkerDonor; - /*--- Initialize some useful booleans ---*/ bool fluid_donor, structural_donor, heat_donor; bool fluid_target, structural_target, heat_target; - bool discrete_adjoint = config[ZONE_0]->GetDiscrete_Adjoint(); - - int markDonor, markTarget, Donor_check, Target_check, iMarkerInt, nMarkerInt; - -#ifdef HAVE_MPI - int *Buffer_Recv_mark = NULL, iRank, nProcessor = size; - - if (rank == MASTER_NODE) - Buffer_Recv_mark = new int[nProcessor]; -#endif + const bool discrete_adjoint = config[ZONE_0]->GetDiscrete_Adjoint(); /*--- Coupling between zones ---*/ // There's a limit here, the interface boundary must connect only 2 zones @@ -2566,278 +2554,209 @@ void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGe continue; } - nMarkerInt = (int) ( config[donorZone]->GetMarker_n_ZoneInterface() / 2 ); + const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface() / 2; /*--- Loops on Interface markers to find if the 2 zones are sharing the boundary and to *--- determine donor and target marker tag ---*/ - for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { + for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - markDonor = -1; - markTarget = -1; - - /*--- On the donor side ---*/ - nMarkerDonor = config[donorZone]->GetnMarker_All(); - - for (iMarkerDonor = 0; iMarkerDonor < nMarkerDonor; iMarkerDonor++) { - - /*--- If the tag GetMarker_All_ZoneInterface(iMarker) equals the index we are looping at ---*/ - if ( config[donorZone]->GetMarker_All_ZoneInterface(iMarkerDonor) == iMarkerInt ) { - /*--- We have identified the identifier for the interface marker ---*/ - markDonor = iMarkerDonor; - - break; - } + /* --- Check if zones are actually sharing the interface boundary, if not skip. ---*/ + if(!CInterpolator::CheckInterfaceBoundary(CInterpolator::Find_InterfaceMarker(config[donorZone],iMarkerInt), + CInterpolator::Find_InterfaceMarker(config[targetZone],iMarkerInt))) { + interface_types[donorZone][targetZone] = NO_COMMON_INTERFACE; + continue; } - /*--- On the target side ---*/ - nMarkerTarget = config[targetZone]->GetnMarker_All(); - - for (iMarkerTarget = 0; iMarkerTarget < nMarkerTarget; iMarkerTarget++) { - - /*--- If the tag GetMarker_All_ZoneInterface(iMarker) equals the index we are looping at ---*/ - if ( config[targetZone]->GetMarker_All_ZoneInterface(iMarkerTarget) == iMarkerInt ) { - /*--- We have identified the identifier for the interface marker ---*/ - markTarget = iMarkerTarget; - - break; - } - } - -#ifdef HAVE_MPI + /*--- Set some boolean to properly allocate data structure later ---*/ + fluid_target = false; + structural_target = false; - Donor_check = -1; - Target_check = -1; + fluid_donor = false; + structural_donor = false; - /*--- We gather a vector in MASTER_NODE that determines if the boundary is not on the processor because - * of the partition or because the zone does not include it ---*/ + heat_donor = false; + heat_target = false; - SU2_MPI::Gather(&markDonor , 1, MPI_INT, Buffer_Recv_mark, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); + switch ( config[targetZone]->GetKind_Solver() ) { - if (rank == MASTER_NODE) { - for (iRank = 0; iRank < nProcessor; iRank++) { - if( Buffer_Recv_mark[iRank] != -1 ) { - Donor_check = Buffer_Recv_mark[iRank]; + case EULER : case NAVIER_STOKES: case RANS: + case INC_EULER : case INC_NAVIER_STOKES: case INC_RANS: + case DISC_ADJ_INC_EULER: case DISC_ADJ_INC_NAVIER_STOKES: case DISC_ADJ_INC_RANS: + case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: + fluid_target = true; break; - } - } - } - SU2_MPI::Bcast(&Donor_check , 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - SU2_MPI::Gather(&markTarget, 1, MPI_INT, Buffer_Recv_mark, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); + case FEM_ELASTICITY: case DISC_ADJ_FEM: + structural_target = true; + break; - if (rank == MASTER_NODE){ - for (iRank = 0; iRank < nProcessor; iRank++){ - if( Buffer_Recv_mark[iRank] != -1 ){ - Target_check = Buffer_Recv_mark[iRank]; + case HEAT_EQUATION: case DISC_ADJ_HEAT: + heat_target = true; break; - } } - } - - SU2_MPI::Bcast(&Target_check, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); -#else - Donor_check = markDonor; - Target_check = markTarget; -#endif - - /* --- Check if zones are actually sharing the interface boundary, if not skip. ---*/ - if(Target_check == -1 || Donor_check == -1) { - interface_types[donorZone][targetZone] = NO_COMMON_INTERFACE; - continue; - } - - /*--- Set some boolean to properly allocate data structure later ---*/ - fluid_target = false; - structural_target = false; - - fluid_donor = false; - structural_donor = false; + switch ( config[donorZone]->GetKind_Solver() ) { - heat_donor = false; - heat_target = false; + case EULER : case NAVIER_STOKES: case RANS: + case INC_EULER : case INC_NAVIER_STOKES: case INC_RANS: + case DISC_ADJ_INC_EULER: case DISC_ADJ_INC_NAVIER_STOKES: case DISC_ADJ_INC_RANS: + case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: + fluid_donor = true; + break; - switch ( config[targetZone]->GetKind_Solver() ) { + case FEM_ELASTICITY: case DISC_ADJ_FEM: + structural_donor = true; + break; - case EULER : case NAVIER_STOKES: case RANS: - case INC_EULER : case INC_NAVIER_STOKES: case INC_RANS: - case DISC_ADJ_INC_EULER: case DISC_ADJ_INC_NAVIER_STOKES: case DISC_ADJ_INC_RANS: - case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: - fluid_target = true; - break; + case HEAT_EQUATION : case DISC_ADJ_HEAT: + heat_donor = true; + break; + } - case FEM_ELASTICITY: case DISC_ADJ_FEM: - structural_target = true; - break; + /*--- Begin the creation of the communication pattern among zones ---*/ - case HEAT_EQUATION: case DISC_ADJ_HEAT: - heat_target = true; - break; - } + /*--- Retrieve the number of conservative variables (for problems not involving structural analysis ---*/ + if (fluid_donor && fluid_target) + nVar = solver[donorZone][INST_0][MESH_0][FLOW_SOL]->GetnVar(); + else + /*--- If at least one of the components is structural ---*/ + nVar = nDim; - switch ( config[donorZone]->GetKind_Solver() ) { + if (rank == MASTER_NODE) cout << "From zone " << donorZone << " to zone " << targetZone << ": "; - case EULER : case NAVIER_STOKES: case RANS: - case INC_EULER : case INC_NAVIER_STOKES: case INC_RANS: - case DISC_ADJ_INC_EULER: case DISC_ADJ_INC_NAVIER_STOKES: case DISC_ADJ_INC_RANS: - case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: - fluid_donor = true; - break; + /*--- Match Zones ---*/ + if (rank == MASTER_NODE) cout << "Setting coupling "; - case FEM_ELASTICITY: case DISC_ADJ_FEM: - structural_donor = true; - break; + bool conservative_interp = config[donorZone]->GetConservativeInterpolation(); - case HEAT_EQUATION : case DISC_ADJ_HEAT: - heat_donor = true; - break; - } + /*--- Conditions for conservative interpolation are not met, we cannot fallback on the consistent approach + because CFlowTractionInterface relies on the information in config to be correct. ---*/ + if ( conservative_interp && targetZone == 0 && structural_target ) + SU2_MPI::Error("Conservative interpolation assumes the structural model mesh is evaluated second, " + "somehow this has not happened.",CURRENT_FUNCTION); - /*--- Begin the creation of the communication pattern among zones ---*/ + switch (config[donorZone]->GetKindInterpolation()) { - /*--- Retrieve the number of conservative variables (for problems not involving structural analysis ---*/ - if (fluid_donor && fluid_target) - nVar = solver[donorZone][INST_0][MESH_0][FLOW_SOL]->GetnVar(); - else - /*--- If at least one of the components is structural ---*/ - nVar = nDim; - - if (rank == MASTER_NODE) cout << "From zone " << donorZone << " to zone " << targetZone << ": "; + case NEAREST_NEIGHBOR: + if ( conservative_interp && targetZone > 0 && structural_target ) { + interpolation[donorZone][targetZone] = new CMirror(geometry, config, donorZone, targetZone); + if (rank == MASTER_NODE) cout << "using a mirror approach: matching coefficients " + "from opposite mesh." << endl; + } + else { + interpolation[donorZone][targetZone] = new CNearestNeighbor(geometry, config, donorZone, targetZone); + if (rank == MASTER_NODE) cout << "using a nearest-neighbor approach." << endl; + } + break; - /*--- Match Zones ---*/ - if (rank == MASTER_NODE) cout << "Setting coupling "; + case ISOPARAMETRIC: + if ( conservative_interp && targetZone > 0 && structural_target ) { + interpolation[donorZone][targetZone] = new CMirror(geometry, config, donorZone, targetZone); + if (rank == MASTER_NODE) cout << "using a mirror approach: matching coefficients " + "from opposite mesh." << endl; + } + else { + interpolation[donorZone][targetZone] = new CIsoparametric(geometry, config, donorZone, targetZone); + if (rank == MASTER_NODE) cout << "using an isoparametric approach." << endl; + } + break; - bool conservative_interp = config[donorZone]->GetConservativeInterpolation(); + case WEIGHTED_AVERAGE: + interpolation[donorZone][targetZone] = new CSlidingMesh(geometry, config, donorZone, targetZone); + if (rank == MASTER_NODE) cout << "using an sliding mesh approach." << endl; - /*--- Conditions for conservative interpolation are not met, we cannot fallback on the consistent approach - because CFlowTractionInterface relies on the information in config to be correct. ---*/ - if ( conservative_interp && targetZone == 0 && structural_target ) - SU2_MPI::Error("Conservative interpolation assumes the structural model mesh is evaluated second, " - "somehow this has not happened.",CURRENT_FUNCTION); + break; - switch (config[donorZone]->GetKindInterpolation()) { + case RADIAL_BASIS_FUNCTION: + if ( conservative_interp && targetZone > 0 && structural_target ) { + interpolation[donorZone][targetZone] = new CMirror(geometry, config, donorZone, targetZone); + if (rank == MASTER_NODE) cout << "using a mirror approach: matching coefficients " + "from opposite mesh." << endl; + } + else { + interpolation[donorZone][targetZone] = new CRadialBasisFunction(geometry, config, + donorZone, targetZone); + if (rank == MASTER_NODE) cout << "using a radial basis function approach." << endl; + } + break; + } - case NEAREST_NEIGHBOR: - if ( conservative_interp && targetZone > 0 && structural_target ) { - interpolation[donorZone][targetZone] = new CMirror(geometry, config, donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using a mirror approach: matching coefficients " - "from opposite mesh." << endl; - } - else { - interpolation[donorZone][targetZone] = new CNearestNeighbor(geometry, config, donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using a nearest-neighbor approach." << endl; - } - break; + /*--- Initialize the appropriate transfer strategy ---*/ + if (rank == MASTER_NODE) cout << "Transferring "; - case ISOPARAMETRIC: - if ( conservative_interp && targetZone > 0 && structural_target ) { - interpolation[donorZone][targetZone] = new CMirror(geometry, config, donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using a mirror approach: matching coefficients " - "from opposite mesh." << endl; - } - else { - interpolation[donorZone][targetZone] = new CIsoparametric(geometry, config, donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using an isoparametric approach." << endl; + if (fluid_donor && structural_target) { + interface_types[donorZone][targetZone] = FLOW_TRACTION; + nVarTransfer = 2; + if(!discrete_adjoint) { + interface[donorZone][targetZone] = new CFlowTractionInterface(nVar, nVarTransfer, config[donorZone]); + } else { + interface[donorZone][targetZone] = new CDiscAdjFlowTractionInterface(nVar, nVarTransfer, config[donorZone]); } - break; - - case WEIGHTED_AVERAGE: - interpolation[donorZone][targetZone] = new CSlidingMesh(geometry, config, donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using an sliding mesh approach." << endl; - - break; - - case RADIAL_BASIS_FUNCTION: - if ( conservative_interp && targetZone > 0 && structural_target ) { - interpolation[donorZone][targetZone] = new CMirror(geometry, config, donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using a mirror approach: matching coefficients " - "from opposite mesh." << endl; + if (rank == MASTER_NODE) cout << "flow tractions. " << endl; + } + else if (structural_donor && fluid_target) { + /*--- If we are using the new mesh solver, we transfer the total boundary displacements (not incremental) --*/ + if (solver_container[targetZone][INST_0][MESH_0][MESH_SOL] != NULL) { + interface_types[donorZone][targetZone] = BOUNDARY_DISPLACEMENTS; + nVarTransfer = 0; + interface[donorZone][targetZone] = new CDisplacementsInterface(nVar, nVarTransfer, config[donorZone]); + if (rank == MASTER_NODE) cout << "boundary displacements from the structural solver. " << endl; } + /*--- We keep the legacy method temporarily until FSI-adjoint has been adapted ---*/ + /// TODO: LEGACY CLEANUP remove the "else" part and every class and enum referenced there, + /// add a check above to make sure MESH_SOL has been instantiated. else { - interpolation[donorZone][targetZone] = new CRadialBasisFunction(geometry, config, - donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using a radial basis function approach." << endl; + nVarTransfer = 0; + if(!discrete_adjoint) { + interface_types[donorZone][targetZone] = STRUCTURAL_DISPLACEMENTS_LEGACY; + interface[donorZone][targetZone] = new CDisplacementsInterfaceLegacy(nVar, nVarTransfer, config[donorZone]); + } else { + interface_types[donorZone][targetZone] = STRUCTURAL_DISPLACEMENTS_DISC_ADJ; + interface[donorZone][targetZone] = new CDiscAdjDisplacementsInterfaceLegacy(nVar, nVarTransfer, config[donorZone]); + } + if (rank == MASTER_NODE) cout << "structural displacements (legacy). " << endl; } - break; - } - - /*--- Initialize the appropriate transfer strategy ---*/ - if (rank == MASTER_NODE) cout << "Transferring "; - - if (fluid_donor && structural_target) { - interface_types[donorZone][targetZone] = FLOW_TRACTION; - nVarTransfer = 2; - if(!discrete_adjoint) { - interface[donorZone][targetZone] = new CFlowTractionInterface(nVar, nVarTransfer, config[donorZone]); - } else { - interface[donorZone][targetZone] = new CDiscAdjFlowTractionInterface(nVar, nVarTransfer, config[donorZone]); } - if (rank == MASTER_NODE) cout << "flow tractions. " << endl; - } - else if (structural_donor && fluid_target) { - /*--- If we are using the new mesh solver, we transfer the total boundary displacements (not incremental) --*/ - if (solver_container[targetZone][INST_0][MESH_0][MESH_SOL] != NULL) { - interface_types[donorZone][targetZone] = BOUNDARY_DISPLACEMENTS; + else if (fluid_donor && fluid_target) { + interface_types[donorZone][targetZone] = SLIDING_INTERFACE; + nVarTransfer = 0; + nVar = solver[donorZone][INST_0][MESH_0][FLOW_SOL]->GetnPrimVar(); + interface[donorZone][targetZone] = new CSlidingInterface(nVar, nVarTransfer, config[donorZone]); + if (rank == MASTER_NODE) cout << "sliding interface. " << endl; + } + else if (fluid_donor && heat_target) { nVarTransfer = 0; - interface[donorZone][targetZone] = new CDisplacementsInterface(nVar, nVarTransfer, config[donorZone]); - if (rank == MASTER_NODE) cout << "boundary displacements from the structural solver. " << endl; + nVar = 4; + if(config[donorZone]->GetEnergy_Equation() || (config[donorZone]->GetKind_Regime() == COMPRESSIBLE)) + interface_types[donorZone][targetZone] = CONJUGATE_HEAT_FS; + else if (config[donorZone]->GetWeakly_Coupled_Heat()) + interface_types[donorZone][targetZone] = CONJUGATE_HEAT_WEAKLY_FS; + else { } + interface[donorZone][targetZone] = new CConjugateHeatInterface(nVar, nVarTransfer, config[donorZone]); + if (rank == MASTER_NODE) cout << "conjugate heat variables. " << endl; + } + else if (heat_donor && fluid_target) { + nVarTransfer = 0; + nVar = 4; + if(config[targetZone]->GetEnergy_Equation() || (config[targetZone]->GetKind_Regime() == COMPRESSIBLE)) + interface_types[donorZone][targetZone] = CONJUGATE_HEAT_SF; + else if (config[targetZone]->GetWeakly_Coupled_Heat()) + interface_types[donorZone][targetZone] = CONJUGATE_HEAT_WEAKLY_SF; + else { } + interface[donorZone][targetZone] = new CConjugateHeatInterface(nVar, nVarTransfer, config[donorZone]); + if (rank == MASTER_NODE) cout << "conjugate heat variables. " << endl; + } + else if (heat_donor && heat_target) { + SU2_MPI::Error("Conjugate heat transfer between solids not implemented yet.", CURRENT_FUNCTION); } - /*--- We keep the legacy method temporarily until FSI-adjoint has been adapted ---*/ - /// TODO: LEGACY CLEANUP remove the "else" part and every class and enum referenced there, - /// add a check above to make sure MESH_SOL has been instantiated. else { + interface_types[donorZone][targetZone] = CONSERVATIVE_VARIABLES; nVarTransfer = 0; - if(!discrete_adjoint) { - interface_types[donorZone][targetZone] = STRUCTURAL_DISPLACEMENTS_LEGACY; - interface[donorZone][targetZone] = new CDisplacementsInterfaceLegacy(nVar, nVarTransfer, config[donorZone]); - } else { - interface_types[donorZone][targetZone] = STRUCTURAL_DISPLACEMENTS_DISC_ADJ; - interface[donorZone][targetZone] = new CDiscAdjDisplacementsInterfaceLegacy(nVar, nVarTransfer, config[donorZone]); - } - if (rank == MASTER_NODE) cout << "structural displacements (legacy). " << endl; + interface[donorZone][targetZone] = new CConservativeVarsInterface(nVar, nVarTransfer, config[donorZone]); + if (rank == MASTER_NODE) cout << "generic conservative variables. " << endl; } - } - else if (fluid_donor && fluid_target) { - interface_types[donorZone][targetZone] = SLIDING_INTERFACE; - nVarTransfer = 0; - nVar = solver[donorZone][INST_0][MESH_0][FLOW_SOL]->GetnPrimVar(); - interface[donorZone][targetZone] = new CSlidingInterface(nVar, nVarTransfer, config[donorZone]); - if (rank == MASTER_NODE) cout << "sliding interface. " << endl; - } - else if (fluid_donor && heat_target) { - nVarTransfer = 0; - nVar = 4; - if(config[donorZone]->GetEnergy_Equation() || (config[donorZone]->GetKind_Regime() == COMPRESSIBLE)) - interface_types[donorZone][targetZone] = CONJUGATE_HEAT_FS; - else if (config[donorZone]->GetWeakly_Coupled_Heat()) - interface_types[donorZone][targetZone] = CONJUGATE_HEAT_WEAKLY_FS; - else { } - interface[donorZone][targetZone] = new CConjugateHeatInterface(nVar, nVarTransfer, config[donorZone]); - if (rank == MASTER_NODE) cout << "conjugate heat variables. " << endl; - } - else if (heat_donor && fluid_target) { - nVarTransfer = 0; - nVar = 4; - if(config[targetZone]->GetEnergy_Equation() || (config[targetZone]->GetKind_Regime() == COMPRESSIBLE)) - interface_types[donorZone][targetZone] = CONJUGATE_HEAT_SF; - else if (config[targetZone]->GetWeakly_Coupled_Heat()) - interface_types[donorZone][targetZone] = CONJUGATE_HEAT_WEAKLY_SF; - else { } - interface[donorZone][targetZone] = new CConjugateHeatInterface(nVar, nVarTransfer, config[donorZone]); - if (rank == MASTER_NODE) cout << "conjugate heat variables. " << endl; - } - else if (heat_donor && heat_target) { - SU2_MPI::Error("Conjugate heat transfer between solids not implemented yet.", CURRENT_FUNCTION); - } - else { - interface_types[donorZone][targetZone] = CONSERVATIVE_VARIABLES; - nVarTransfer = 0; - interface[donorZone][targetZone] = new CConservativeVarsInterface(nVar, nVarTransfer, config[donorZone]); - if (rank == MASTER_NODE) cout << "generic conservative variables. " << endl; - } - break; + break; } @@ -2855,10 +2774,6 @@ void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGe } -#ifdef HAVE_MPI - if (rank == MASTER_NODE) - delete [] Buffer_Recv_mark; -#endif } void CDriver::StaticMesh_Preprocessing(CConfig *config, CGeometry** geometry, CSurfaceMovement* surface_movement){ diff --git a/SU2_CFD/src/drivers/CMultizoneDriver.cpp b/SU2_CFD/src/drivers/CMultizoneDriver.cpp index 2179cb084a11..66db6a2544cc 100644 --- a/SU2_CFD/src/drivers/CMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CMultizoneDriver.cpp @@ -29,12 +29,8 @@ #include "../../include/definition_structure.hpp" #include "../../../Common/include/interface_interpolation/CInterpolator.hpp" -CMultizoneDriver::CMultizoneDriver(char* confFile, - unsigned short val_nZone, - SU2_Comm MPICommunicator) : CDriver(confFile, - val_nZone, - MPICommunicator, - false) { +CMultizoneDriver::CMultizoneDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunicator) : + CDriver(confFile, val_nZone, MPICommunicator, false) { /*--- Initialize the counter for TimeIter ---*/ TimeIter = 0; From e1fa6dfbac3298a9f9b3c630de738090e980d139 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Wed, 18 Mar 2020 15:56:59 +0000 Subject: [PATCH 13/79] move CSymmetricMatrix to toolboxes --- .../interface_interpolation/CInterpolator.hpp | 4 +- .../CRadialBasisFunction.hpp | 70 +--- Common/include/toolboxes/CSymmetricMatrix.hpp | 90 +++++ Common/lib/Makefile.am | 1 + .../src/interface_interpolation/CMirror.cpp | 102 +++--- .../CRadialBasisFunction.cpp | 308 +--------------- Common/src/toolboxes/CSymmetricMatrix.cpp | 332 ++++++++++++++++++ Common/src/toolboxes/meson.build | 3 +- 8 files changed, 489 insertions(+), 421 deletions(-) create mode 100644 Common/include/toolboxes/CSymmetricMatrix.hpp create mode 100644 Common/src/toolboxes/CSymmetricMatrix.cpp diff --git a/Common/include/interface_interpolation/CInterpolator.hpp b/Common/include/interface_interpolation/CInterpolator.hpp index 74e4840d5d02..487e5131f345 100644 --- a/Common/include/interface_interpolation/CInterpolator.hpp +++ b/Common/include/interface_interpolation/CInterpolator.hpp @@ -147,7 +147,7 @@ class CInterpolator { * \param[in] point_i - coordinates of point i * \param[in] point_j - coordinates of point j */ - inline su2double PointsSquareDistance(unsigned short nDim, const su2double *point_i, const su2double *point_j) const { + static inline su2double PointsSquareDistance(unsigned short nDim, const su2double *point_i, const su2double *point_j) { su2double d = 0.0; for(unsigned short iDim = 0; iDim < nDim; iDim++) d += pow(point_j[iDim] - point_i[iDim], 2); @@ -160,7 +160,7 @@ class CInterpolator { * \param[in] point_i - coordinates of point i * \param[in] point_j - coordinates of point j */ - inline su2double PointsDistance(unsigned short nDim, const su2double *point_i, const su2double *point_j) const { + static inline su2double PointsDistance(unsigned short nDim, const su2double *point_i, const su2double *point_j) { return sqrt(PointsSquareDistance(nDim, point_i, point_j)); } diff --git a/Common/include/interface_interpolation/CRadialBasisFunction.hpp b/Common/include/interface_interpolation/CRadialBasisFunction.hpp index 18b1b2083644..37b75d784940 100644 --- a/Common/include/interface_interpolation/CRadialBasisFunction.hpp +++ b/Common/include/interface_interpolation/CRadialBasisFunction.hpp @@ -59,7 +59,6 @@ class CRadialBasisFunction final : public CInterpolator { */ static su2double Get_RadialBasisValue(ENUM_RADIALBASIS type, const su2double radius, const su2double dist); -private: /*! * \brief Compute the RBF "generator" matrix with or without polynomial terms. * \note Multiplying C_inv_trunc by a column vector gives specific coefficients for given "known values", @@ -73,9 +72,9 @@ class CRadialBasisFunction final : public CInterpolator { * \param[out] keepPolynomialRow - Size nDim, signals which (if any) iDim was removed from polynomial term. * \param[out] C_inv_trunc - The generator matrix as described above. */ - void ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool usePolynomial, su2double radius, - const su2activematrix& coords, int& nPolynomial, - vector& keepPolynomialRow, su2passivematrix& C_inv_trunc) const; + static void ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool usePolynomial, su2double radius, + const su2activematrix& coords, int& nPolynomial, + vector& keepPolynomialRow, su2passivematrix& C_inv_trunc); /*! * \brief If the polynomial term is included in the interpolation, and the points lie on a plane, the matrix @@ -86,7 +85,7 @@ class CRadialBasisFunction final : public CInterpolator { * \param[in,out] P - Polynomial part of the interpolation matrix, one row may be eliminated. * \return n_polynomial - Size of the polynomial part on exit (in practice nDim or nDim-1). */ - int CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, su2passivematrix &P) const; + static int CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, su2passivematrix &P); /*! * \brief Prunes (by setting to zero) small interpolation coefficients, i.e. @@ -95,65 +94,6 @@ class CRadialBasisFunction final : public CInterpolator { * \param[in,out] coeffs - The vector of interpolation coefficients. * \return Number of non-zero coefficients after pruning. */ - int PruneSmallCoefficients(passivedouble tolerance, su2passivevector& coeffs) const; - -}; - -/*! - * \brief Helper class used by CRadialBasisFunction to compute the interpolation weights. - * The matrix is symmetric but full storage is used as that gives much better performance - * for some BLAS libraries (notably OpenBLAS). The code should be compiled with LAPACK - * to use optimized matrix inversion and multiplication routines. - */ -class CSymmetricMatrix { -private: - enum DecompositionType { NONE, CHOLESKY, LU }; - - vector val_vec, decomp_vec; - vector perm_vec; - int sz = 0; - bool initialized = false; - DecompositionType decomposed = NONE; - - inline void CheckBounds(int i, int j) const { - assert(initialized && "Matrix not initialized."); - assert(i>=0 && i=0 && j. + */ +#pragma once + +#include +#include "C2DContainer.hpp" + +using namespace std; + +/*! + * \brief The matrix is symmetric but full storage is used as that gives much better + * performance for some BLAS libraries (notably OpenBLAS). The code should be compiled + * with LAPACK to use optimized matrix inversion and multiplication routines. + */ +class CSymmetricMatrix { +private: + enum DecompositionType { NONE, CHOLESKY, LU }; + + vector val_vec, decomp_vec; + vector perm_vec; + int sz = 0; + bool initialized = false; + DecompositionType decomposed = NONE; + + inline void CheckBounds(int i, int j) const { + assert(initialized && "Matrix not initialized."); + assert(i>=0 && i=0 && jGetMarker_n_ZoneInterface())/2; @@ -73,7 +79,7 @@ void CMirror::Set_TransferCoeff(CConfig **config) { */ /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); /*--- On the target side: find the tag of the boundary sharing the interface ---*/ markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); @@ -103,11 +109,6 @@ void CMirror::Set_TransferCoeff(CConfig **config) { nLocalFace_Donor++; } } - Buffer_Send_nFace_Donor= new unsigned long [1]; - Buffer_Send_nFaceNodes_Donor= new unsigned long [1]; - - Buffer_Receive_nFace_Donor = new unsigned long [nProcessor]; - Buffer_Receive_nFaceNodes_Donor = new unsigned long [nProcessor]; Buffer_Send_nFace_Donor[0] = nLocalFace_Donor; Buffer_Send_nFaceNodes_Donor[0] = nLocalFaceNodes_Donor; @@ -116,8 +117,10 @@ void CMirror::Set_TransferCoeff(CConfig **config) { #ifdef HAVE_MPI SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &MaxFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); SU2_MPI::Allreduce(&nLocalFace_Donor, &MaxFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFace_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nFace_Donor, 1, MPI_UNSIGNED_LONG, + Buffer_Receive_nFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, + Buffer_Receive_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); MaxFace_Donor++; #else nGlobalFace_Donor = nLocalFace_Donor; @@ -129,15 +132,15 @@ void CMirror::Set_TransferCoeff(CConfig **config) { #endif /*-- Send donor info --*/ - Buffer_Send_FaceIndex = new unsigned long[MaxFace_Donor]; - Buffer_Send_FaceNodes = new unsigned long[MaxFaceNodes_Donor]; + Buffer_Send_FaceIndex = new unsigned long[MaxFace_Donor]; + Buffer_Send_FaceNodes = new unsigned long[MaxFaceNodes_Donor]; Buffer_Send_GlobalPoint = new long[MaxFaceNodes_Donor]; - Buffer_Send_Coeff = new su2double[MaxFaceNodes_Donor]; + Buffer_Send_Coeff = new su2double[MaxFaceNodes_Donor]; - Buffer_Receive_FaceIndex= new unsigned long[MaxFace_Donor*nProcessor]; - Buffer_Receive_FaceNodes= new unsigned long[MaxFaceNodes_Donor*nProcessor]; + Buffer_Receive_FaceIndex = new unsigned long[MaxFace_Donor*nProcessor]; + Buffer_Receive_FaceNodes = new unsigned long[MaxFaceNodes_Donor*nProcessor]; Buffer_Receive_GlobalPoint = new long[MaxFaceNodes_Donor*nProcessor]; - Buffer_Receive_Coeff = new su2double[MaxFaceNodes_Donor*nProcessor]; + Buffer_Receive_Coeff = new su2double[MaxFaceNodes_Donor*nProcessor]; for (iVertex=0; iVertexvertex[markTarget][iVertex]->GetNode(); - if (target_geometry->node[iPoint]->GetDomain()) { - long Global_Point = target_geometry->node[iPoint]->GetGlobalIndex(); - nNodes = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iFace = 0; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { - faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face - iNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1]- (unsigned int)faceindex; - for (iTarget=0; iTargetnode[iPoint]->GetDomain()) continue; + + long Global_Point = target_geometry->node[iPoint]->GetGlobalIndex(); + nNodes = 0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (iFace = 0; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { + faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face + iNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1]- (unsigned int)faceindex; + for (iTarget=0; iTargetvertex[markTarget][iVertex]->SetnDonorPoints(nNodes); - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); - - iDonor = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iFace = 0; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { - - faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face - iNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1]- (unsigned int)faceindex; - for (iTarget=0; iTargetvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,pGlobalPoint); - target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor,coeff); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, iProcessor); - iDonor++; - } + target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nNodes); + target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); + + iDonor = 0; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (iFace = 0; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { + + faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face + iNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1]- (unsigned int)faceindex; + for (iTarget=0; iTargetvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,pGlobalPoint); + target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor,coeff); + target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, iProcessor); + iDonor++; } } } } } - delete[] Buffer_Send_nFace_Donor; - delete[] Buffer_Send_nFaceNodes_Donor; - - delete[] Buffer_Receive_nFace_Donor; - delete[] Buffer_Receive_nFaceNodes_Donor; delete[] Buffer_Send_FaceIndex; delete[] Buffer_Send_FaceNodes; @@ -238,6 +236,12 @@ void CMirror::Set_TransferCoeff(CConfig **config) { delete[] Buffer_Receive_FaceNodes; delete[] Buffer_Receive_GlobalPoint; delete[] Buffer_Receive_Coeff; - } + + delete[] Buffer_Send_nFace_Donor; + delete[] Buffer_Send_nFaceNodes_Donor; + + delete[] Buffer_Receive_nFace_Donor; + delete[] Buffer_Receive_nFaceNodes_Donor; + } diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp index fd5504ed8c8b..eabd34671bab 100644 --- a/Common/src/interface_interpolation/CRadialBasisFunction.cpp +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -28,23 +28,8 @@ #include "../../include/interface_interpolation/CRadialBasisFunction.hpp" #include "../../include/CConfig.hpp" #include "../../include/geometry/CGeometry.hpp" +#include "../../include/toolboxes/CSymmetricMatrix.hpp" -#if defined(HAVE_MKL) -#include "mkl.h" -#ifndef HAVE_LAPACK -#define HAVE_LAPACK -#endif -#elif defined(HAVE_LAPACK) -/*--- Lapack / Blas routines used in RBF interpolation. ---*/ -extern "C" void dsptrf_(char*, int*, passivedouble*, int*, int*); -extern "C" void dsptri_(char*, int*, passivedouble*, int*, passivedouble*, int*); -extern "C" void dsytrf_(char*, int*, passivedouble*, int*, int*, passivedouble*, int*, int*); -extern "C" void dsytri_(char*, int*, passivedouble*, int*, int*, passivedouble*, int*); -extern "C" void dpotrf_(char*, int*, passivedouble*, int*, int*); -extern "C" void dpotri_(char*, int*, passivedouble*, int*, int*); -extern "C" void dsymm_(char*, char*, int*, int*, passivedouble*, passivedouble*, int*, - passivedouble*, int*, passivedouble*, passivedouble*, int*); -#endif CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { @@ -320,7 +305,7 @@ void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { void CRadialBasisFunction::ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool usePolynomial, su2double radius, const su2activematrix& coords, int& nPolynomial, - vector& keepPolynomialRow, su2passivematrix& C_inv_trunc) const { + vector& keepPolynomialRow, su2passivematrix& C_inv_trunc) { const su2double interfaceCoordTol = 1e6 * numeric_limits::epsilon(); @@ -406,7 +391,7 @@ void CRadialBasisFunction::ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool us } int CRadialBasisFunction::CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, - su2passivematrix &P) const { + su2passivematrix &P) { const int m = P.rows(); const int n = P.cols(); @@ -476,7 +461,7 @@ int CRadialBasisFunction::CheckPolynomialTerms(su2double max_diff_tol, vector 0.0 && "LLT failed, matrix is not SPD."); - Set(j, j, sqrt(sum)); - - for (int i = j+1; i < sz; ++i) { - passivedouble sum = 0.0; - for (int k = 0; k < j; ++k) sum -= Get(i,k) * Get(j,k); - sum += Get(i,j); - Set(i, j, sum / Get(j,j)); - } - } - decomposed = CHOLESKY; -#endif -} - -void CSymmetricMatrix::LUDecompose() -{ -#ifndef HAVE_LAPACK - assert(initialized && "Matrix not initialized."); - - /*--- Copy matrix values to LU matrix, init permutation vec. ---*/ - decomp_vec.resize(sz*sz); - perm_vec.resize(sz); - for (int i = 0; i < sz; ++i) { - perm_vec[i] = i; - for (int j = i; j < sz; ++j) decomp(j,i) = decomp(i,j) = Get(i,j); - } - - /*--- Decompose LU matrix. ---*/ - for (int j = 0; j < sz-1; ++j) { - /*--- Search for maximum pivot and interchange rows. ---*/ - passivedouble pivot = decomp(j,j); - int pivot_idx = j; - for (int i = j+1; i < sz; ++i) - if (abs(decomp(i,j)) > abs(pivot)) { - pivot = decomp(i,j); - pivot_idx = i; - } - - if (pivot_idx != j) { - swap(perm_vec[j], perm_vec[pivot_idx]); - for (int k = 0; k < sz; ++k) - swap(decomp(j,k), decomp(pivot_idx,k)); - } - - /*--- Perform elimination. ---*/ - for (int k = j+1; k < sz; ++k) decomp(k,j) /= pivot; - - for (int k = j+1; k < sz; ++k) - for (int i = j+1; i < sz; ++i) - decomp(i,k) -= decomp(j,k)*decomp(i,j); - } - - decomposed = LU; -#endif -} - -void CSymmetricMatrix::CalcInv() -{ -#ifndef HAVE_LAPACK - assert(initialized && "Matrix not initialized."); - - /*--- Decompose matrix if not done yet. ---*/ - if (decomposed == NONE) { LUDecompose(); } - - /*--- Compute inverse from decomposed matrices. ---*/ - switch (decomposed) { - - case CHOLESKY: - { - /*--- Initialize inverse matrix. ---*/ - vector inv(sz*sz, 0.0); - - /*--- Compute L inverse. ---*/ - /*--- Solve smaller and smaller systems. ---*/ - for (int j = 0; j < sz; ++j) { - /*--- Forward substitution. ---*/ - inv[IdxSym(j,j)] = 1.0 / Get(j,j); - - for (int i = j+1; i < sz; ++i) { - passivedouble sum = 0.0; - for (int k = j; k < i; ++k) sum -= Get(i,k) * inv[IdxSym(k,j)]; - inv[IdxSym(i,j)] = sum / Get(i,i); - } - } // L inverse in inv - - /*--- Multiply inversed matrices overwrite val_vec. ---*/ - for (int j = 0; j < sz; ++j) - for (int i = j; i < sz; ++i) { - passivedouble sum = 0.0; - for (int k = i; k < sz; ++k) sum += inv[IdxSym(k,i)] * inv[IdxSym(k,j)]; - Set(i, j, sum); - } - - break; - } - - case LU: - { - /*--- Alias val_vec. ---*/ - vector& inv = val_vec; - - /*--- Invert L and U matrices in place. ---*/ - for (int j = 0; j < sz; ++j) { - inv[IdxFull(j,j)] = 1.0 / decomp(j,j); - - for (int i = j+1; i < sz; ++i) { - inv[IdxFull(i,j)] = -decomp(i,j); - inv[IdxFull(j,i)] = -decomp(j,i) * inv[IdxFull(j,j)]; - - for (int k = j+1; k < i; ++k) { - inv[IdxFull(i,j)] -= decomp(i,k) * inv[IdxFull(k,j)]; - inv[IdxFull(j,i)] -= decomp(k,i) * inv[IdxFull(j,k)]; - } - if (j+1 <= i) inv[IdxFull(j,i)] /= decomp(i,i); - } - } - // inverses in val_vec - - /*--- Multiply U_inv by L_inv, overwrite decomp_vec. ---*/ - for (int i = 0; i < sz; ++i) - for (int j = 0; j < sz; ++j) { - decomp(i,j) = 0.0; - for (int k = max(i,j); k < sz; ++k) - decomp(i,j) += inv[IdxFull(i,k)] * ((k==j)? 1.0 : inv[IdxFull(k,j)]); - } - - /*--- Permute multiplied matrix to recover A_inv, overwrite val_vec. ---*/ - for (int j = 0; j < sz; ++j) { - int k = perm_vec[j]; - for (int i = k; i < sz; ++i) Set(i, k, decomp(i,j)); - } - - /*--- Decomposition no longer needed. ---*/ - vector().swap(decomp_vec); - - break; - } - default: assert(false && "Default (LU) decomposition failed."); - } - - decomposed = NONE; -#endif -} - -void CSymmetricMatrix::CalcInv_sytri() -{ -#ifdef HAVE_LAPACK - char uplo = 'L'; - int info; - perm_vec.resize(sz); // ipiv array - - /*--- Query the optimum work size. ---*/ - int query = -1; passivedouble tmp; - dsytrf_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), &tmp, &query, &info); - query = static_cast(tmp); - decomp_vec.resize(query); // work array - - /*--- Factorize and invert. ---*/ - dsytrf_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), decomp_vec.data(), &query, &info); - if (info!=0) SU2_MPI::Error("LDLT factorization failed.", CURRENT_FUNCTION); - dsytri_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), decomp_vec.data(), &info); - if (info!=0) SU2_MPI::Error("Inversion with LDLT factorization failed.", CURRENT_FUNCTION); - - decomposed = NONE; -#endif -} - -void CSymmetricMatrix::CalcInv_potri() -{ -#ifdef HAVE_LAPACK - char uplo = 'L'; - int info; - - dpotrf_(&uplo, &sz, val_vec.data(), &sz, &info); - if (info!=0) SU2_MPI::Error("LLT factorization failed.", CURRENT_FUNCTION); - dpotri_(&uplo, &sz, val_vec.data(), &sz, &info); - if (info!=0) SU2_MPI::Error("Inversion with LLT factorization failed.", CURRENT_FUNCTION); - - decomposed = NONE; -#endif -} - -void CSymmetricMatrix::Invert(const bool is_spd) -{ -#ifdef HAVE_LAPACK - if(is_spd) CalcInv_potri(); - else CalcInv_sytri(); -#else - if(!is_spd) LUDecompose(); - else CholeskyDecompose(); - CalcInv(); -#endif -} - -void CSymmetricMatrix::MatVecMult(passivedouble *v) const -{ - passivedouble *tmp_res = new passivedouble [sz]; - - for (int i=0; i. + */ + +#include "../../include/toolboxes/CSymmetricMatrix.hpp" +#include "../../include/mpi_structure.hpp" + +#if defined(HAVE_MKL) +#include "mkl.h" +#ifndef HAVE_LAPACK +#define HAVE_LAPACK +#endif +#elif defined(HAVE_LAPACK) +/*--- Lapack / Blas routines used in RBF interpolation. ---*/ +extern "C" void dsptrf_(char*, int*, passivedouble*, int*, int*); +extern "C" void dsptri_(char*, int*, passivedouble*, int*, passivedouble*, int*); +extern "C" void dsytrf_(char*, int*, passivedouble*, int*, int*, passivedouble*, int*, int*); +extern "C" void dsytri_(char*, int*, passivedouble*, int*, int*, passivedouble*, int*); +extern "C" void dpotrf_(char*, int*, passivedouble*, int*, int*); +extern "C" void dpotri_(char*, int*, passivedouble*, int*, int*); +extern "C" void dsymm_(char*, char*, int*, int*, passivedouble*, passivedouble*, int*, + passivedouble*, int*, passivedouble*, passivedouble*, int*); +#endif + + +void CSymmetricMatrix::Initialize(int N) +{ + sz = N; + val_vec.resize(sz*sz); + initialized = true; +} + +void CSymmetricMatrix::CholeskyDecompose() +{ +#ifndef HAVE_LAPACK + assert(initialized && "Matrix not initialized."); + + for (int j = 0; j < sz; ++j) { + passivedouble sum = 0.0; + for (int k = 0; k < j; ++k) sum -= pow(Get(j,k), 2); + sum += Get(j,j); + assert(sum > 0.0 && "LLT failed, matrix is not SPD."); + Set(j, j, sqrt(sum)); + + for (int i = j+1; i < sz; ++i) { + passivedouble sum = 0.0; + for (int k = 0; k < j; ++k) sum -= Get(i,k) * Get(j,k); + sum += Get(i,j); + Set(i, j, sum / Get(j,j)); + } + } + decomposed = CHOLESKY; +#endif +} + +void CSymmetricMatrix::LUDecompose() +{ +#ifndef HAVE_LAPACK + assert(initialized && "Matrix not initialized."); + + /*--- Copy matrix values to LU matrix, init permutation vec. ---*/ + decomp_vec.resize(sz*sz); + perm_vec.resize(sz); + for (int i = 0; i < sz; ++i) { + perm_vec[i] = i; + for (int j = i; j < sz; ++j) decomp(j,i) = decomp(i,j) = Get(i,j); + } + + /*--- Decompose LU matrix. ---*/ + for (int j = 0; j < sz-1; ++j) { + /*--- Search for maximum pivot and interchange rows. ---*/ + passivedouble pivot = decomp(j,j); + int pivot_idx = j; + for (int i = j+1; i < sz; ++i) + if (abs(decomp(i,j)) > abs(pivot)) { + pivot = decomp(i,j); + pivot_idx = i; + } + + if (pivot_idx != j) { + swap(perm_vec[j], perm_vec[pivot_idx]); + for (int k = 0; k < sz; ++k) + swap(decomp(j,k), decomp(pivot_idx,k)); + } + + /*--- Perform elimination. ---*/ + for (int k = j+1; k < sz; ++k) decomp(k,j) /= pivot; + + for (int k = j+1; k < sz; ++k) + for (int i = j+1; i < sz; ++i) + decomp(i,k) -= decomp(j,k)*decomp(i,j); + } + + decomposed = LU; +#endif +} + +void CSymmetricMatrix::CalcInv() +{ +#ifndef HAVE_LAPACK + assert(initialized && "Matrix not initialized."); + + /*--- Decompose matrix if not done yet. ---*/ + if (decomposed == NONE) { LUDecompose(); } + + /*--- Compute inverse from decomposed matrices. ---*/ + switch (decomposed) { + + case CHOLESKY: + { + /*--- Initialize inverse matrix. ---*/ + vector inv(sz*sz, 0.0); + + /*--- Compute L inverse. ---*/ + /*--- Solve smaller and smaller systems. ---*/ + for (int j = 0; j < sz; ++j) { + /*--- Forward substitution. ---*/ + inv[IdxSym(j,j)] = 1.0 / Get(j,j); + + for (int i = j+1; i < sz; ++i) { + passivedouble sum = 0.0; + for (int k = j; k < i; ++k) sum -= Get(i,k) * inv[IdxSym(k,j)]; + inv[IdxSym(i,j)] = sum / Get(i,i); + } + } // L inverse in inv + + /*--- Multiply inversed matrices overwrite val_vec. ---*/ + for (int j = 0; j < sz; ++j) + for (int i = j; i < sz; ++i) { + passivedouble sum = 0.0; + for (int k = i; k < sz; ++k) sum += inv[IdxSym(k,i)] * inv[IdxSym(k,j)]; + Set(i, j, sum); + } + + break; + } + + case LU: + { + /*--- Alias val_vec. ---*/ + vector& inv = val_vec; + + /*--- Invert L and U matrices in place. ---*/ + for (int j = 0; j < sz; ++j) { + inv[IdxFull(j,j)] = 1.0 / decomp(j,j); + + for (int i = j+1; i < sz; ++i) { + inv[IdxFull(i,j)] = -decomp(i,j); + inv[IdxFull(j,i)] = -decomp(j,i) * inv[IdxFull(j,j)]; + + for (int k = j+1; k < i; ++k) { + inv[IdxFull(i,j)] -= decomp(i,k) * inv[IdxFull(k,j)]; + inv[IdxFull(j,i)] -= decomp(k,i) * inv[IdxFull(j,k)]; + } + if (j+1 <= i) inv[IdxFull(j,i)] /= decomp(i,i); + } + } + // inverses in val_vec + + /*--- Multiply U_inv by L_inv, overwrite decomp_vec. ---*/ + for (int i = 0; i < sz; ++i) + for (int j = 0; j < sz; ++j) { + decomp(i,j) = 0.0; + for (int k = max(i,j); k < sz; ++k) + decomp(i,j) += inv[IdxFull(i,k)] * ((k==j)? 1.0 : inv[IdxFull(k,j)]); + } + + /*--- Permute multiplied matrix to recover A_inv, overwrite val_vec. ---*/ + for (int j = 0; j < sz; ++j) { + int k = perm_vec[j]; + for (int i = k; i < sz; ++i) Set(i, k, decomp(i,j)); + } + + /*--- Decomposition no longer needed. ---*/ + vector().swap(decomp_vec); + + break; + } + default: assert(false && "Default (LU) decomposition failed."); + } + + decomposed = NONE; +#endif +} + +void CSymmetricMatrix::CalcInv_sytri() +{ +#ifdef HAVE_LAPACK + char uplo = 'L'; + int info; + perm_vec.resize(sz); // ipiv array + + /*--- Query the optimum work size. ---*/ + int query = -1; passivedouble tmp; + dsytrf_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), &tmp, &query, &info); + query = static_cast(tmp); + decomp_vec.resize(query); // work array + + /*--- Factorize and invert. ---*/ + dsytrf_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), decomp_vec.data(), &query, &info); + if (info!=0) SU2_MPI::Error("LDLT factorization failed.", CURRENT_FUNCTION); + dsytri_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), decomp_vec.data(), &info); + if (info!=0) SU2_MPI::Error("Inversion with LDLT factorization failed.", CURRENT_FUNCTION); + + decomposed = NONE; +#endif +} + +void CSymmetricMatrix::CalcInv_potri() +{ +#ifdef HAVE_LAPACK + char uplo = 'L'; + int info; + + dpotrf_(&uplo, &sz, val_vec.data(), &sz, &info); + if (info!=0) SU2_MPI::Error("LLT factorization failed.", CURRENT_FUNCTION); + dpotri_(&uplo, &sz, val_vec.data(), &sz, &info); + if (info!=0) SU2_MPI::Error("Inversion with LLT factorization failed.", CURRENT_FUNCTION); + + decomposed = NONE; +#endif +} + +void CSymmetricMatrix::Invert(const bool is_spd) +{ +#ifdef HAVE_LAPACK + if(is_spd) CalcInv_potri(); + else CalcInv_sytri(); +#else + if(!is_spd) LUDecompose(); + else CholeskyDecompose(); + CalcInv(); +#endif +} + +void CSymmetricMatrix::MatVecMult(passivedouble *v) const +{ + passivedouble *tmp_res = new passivedouble [sz]; + + for (int i=0; i Date: Wed, 18 Mar 2020 16:34:31 +0000 Subject: [PATCH 14/79] cleanup CMirror, make search hybrid parallel --- .../src/interface_interpolation/CMirror.cpp | 178 +++++++----------- SU2_CFD/src/SU2_CFD.cpp | 1 - SU2_CFD/src/drivers/CDriver.cpp | 4 +- 3 files changed, 67 insertions(+), 116 deletions(-) diff --git a/Common/src/interface_interpolation/CMirror.cpp b/Common/src/interface_interpolation/CMirror.cpp index 0106de67f214..49bcc91b93c0 100644 --- a/Common/src/interface_interpolation/CMirror.cpp +++ b/Common/src/interface_interpolation/CMirror.cpp @@ -37,29 +37,7 @@ CMirror::CMirror(CGeometry ****geometry_container, CConfig **config, unsigned i void CMirror::Set_TransferCoeff(CConfig **config) { - unsigned long iVertex, jVertex; - unsigned long iPoint; - unsigned short iDonor=0, iFace=0, iTarget=0; - - unsigned short nMarkerInt; - unsigned short iMarkerInt; - - int markDonor=0, markTarget=0; - - unsigned int nNodes=0, iNodes=0; - unsigned long nVertexDonor = 0, nVertexTarget= 0; - unsigned long Point_Donor = 0; - unsigned long pGlobalPoint = 0; - int iProcessor; - - unsigned long nLocalFace_Donor = 0, nLocalFaceNodes_Donor=0; - - unsigned long faceindex; - - int nProcessor = size; - - su2double *Buffer_Send_Coeff, *Buffer_Receive_Coeff; - su2double coeff; + const int nProcessor = size; Buffer_Send_nFace_Donor= new unsigned long [1]; Buffer_Send_nFaceNodes_Donor= new unsigned long [1]; @@ -68,10 +46,10 @@ void CMirror::Set_TransferCoeff(CConfig **config) { Buffer_Receive_nFaceNodes_Donor = new unsigned long [nProcessor]; /*--- Number of markers on the interface ---*/ - nMarkerInt = (config[targetZone]->GetMarker_n_ZoneInterface())/2; + const auto nMarkerInt = (config[targetZone]->GetMarker_n_ZoneInterface())/2; /*--- For the number of markers on the interface... ---*/ - for (iMarkerInt=1; iMarkerInt <= nMarkerInt; iMarkerInt++) { + for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { /*--- Procedure: * - Loop through vertices of the aero grid * - Find nearest element and allocate enough space in the aero grid donor point info @@ -79,33 +57,27 @@ void CMirror::Set_TransferCoeff(CConfig **config) { */ /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + const auto markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); + const auto markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ if(!CheckInterfaceBoundary(markDonor, markTarget)) continue; - if(markDonor != -1) - nVertexDonor = donor_geometry->GetnVertex( markDonor ); - else - nVertexDonor = 0; - - if(markTarget != -1) - nVertexTarget = target_geometry->GetnVertex( markTarget ); - else - nVertexTarget = 0; + unsigned long nVertexDonor = 0, nVertexTarget = 0; + if (markDonor != -1) nVertexDonor = donor_geometry->GetnVertex( markDonor ); + if (markTarget != -1) nVertexTarget = target_geometry->GetnVertex( markTarget ); /*-- Collect the number of donor nodes: re-use 'Face' containers --*/ - nLocalFace_Donor=0; - nLocalFaceNodes_Donor=0; - for (jVertex = 0; jVertexvertex[markDonor][jVertex]->GetNode(); // Local index of jVertex + auto nLocalFace_Donor = 0ul; + auto nLocalFaceNodes_Donor = 0ul; + for (auto jVertex = 0ul; jVertexvertex[markDonor][jVertex]->GetNode(); // Local index of jVertex if (donor_geometry->node[Point_Donor]->GetDomain()) { - nNodes = donor_geometry->vertex[markDonor][jVertex]->GetnDonorPoints(); - nLocalFaceNodes_Donor+=nNodes; + auto nNodes = donor_geometry->vertex[markDonor][jVertex]->GetnDonorPoints(); + nLocalFaceNodes_Donor += nNodes; nLocalFace_Donor++; } } @@ -114,7 +86,6 @@ void CMirror::Set_TransferCoeff(CConfig **config) { Buffer_Send_nFaceNodes_Donor[0] = nLocalFaceNodes_Donor; /*--- Send Interface vertex information --*/ -#ifdef HAVE_MPI SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &MaxFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); SU2_MPI::Allreduce(&nLocalFace_Donor, &MaxFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_nFace_Donor, 1, MPI_UNSIGNED_LONG, @@ -122,58 +93,39 @@ void CMirror::Set_TransferCoeff(CConfig **config) { SU2_MPI::Allgather(Buffer_Send_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); MaxFace_Donor++; -#else - nGlobalFace_Donor = nLocalFace_Donor; - nGlobalFaceNodes_Donor = nLocalFaceNodes_Donor; - MaxFaceNodes_Donor = nLocalFaceNodes_Donor; - MaxFace_Donor = nLocalFace_Donor+1; - Buffer_Receive_nFace_Donor[0] = Buffer_Send_nFace_Donor[0]; - Buffer_Receive_nFaceNodes_Donor[0] = Buffer_Send_nFaceNodes_Donor[0]; -#endif - - /*-- Send donor info --*/ - Buffer_Send_FaceIndex = new unsigned long[MaxFace_Donor]; - Buffer_Send_FaceNodes = new unsigned long[MaxFaceNodes_Donor]; - Buffer_Send_GlobalPoint = new long[MaxFaceNodes_Donor]; - Buffer_Send_Coeff = new su2double[MaxFaceNodes_Donor]; + + /*-- Send donor info and init to 0 --*/ + Buffer_Send_FaceIndex = new unsigned long[MaxFace_Donor] (); + Buffer_Send_FaceNodes = new unsigned long[MaxFaceNodes_Donor] (); + Buffer_Send_GlobalPoint = new long[MaxFaceNodes_Donor] (); + auto Buffer_Send_Coeff = new su2double[MaxFaceNodes_Donor] (); Buffer_Receive_FaceIndex = new unsigned long[MaxFace_Donor*nProcessor]; Buffer_Receive_FaceNodes = new unsigned long[MaxFaceNodes_Donor*nProcessor]; Buffer_Receive_GlobalPoint = new long[MaxFaceNodes_Donor*nProcessor]; - Buffer_Receive_Coeff = new su2double[MaxFaceNodes_Donor*nProcessor]; - - for (iVertex=0; iVertexvertex[markDonor][jVertex]->GetNode(); // Local index of jVertex - if (donor_geometry->node[Point_Donor]->GetDomain()) { - nNodes = donor_geometry->vertex[markDonor][jVertex]->GetnDonorPoints(); - for (iDonor=0; iDonornode[Point_Donor]->GetGlobalIndex(); - Buffer_Send_GlobalPoint[nLocalFaceNodes_Donor] = - donor_geometry->vertex[markDonor][jVertex]->GetInterpDonorPoint(iDonor); - Buffer_Send_Coeff[nLocalFaceNodes_Donor] = - donor_geometry->vertex[markDonor][jVertex]->GetDonorCoeff(iDonor); - nLocalFaceNodes_Donor++; - } - Buffer_Send_FaceIndex[nLocalFace_Donor+1] =Buffer_Send_FaceIndex[nLocalFace_Donor]+nNodes; - nLocalFace_Donor++; + auto Point_Donor = donor_geometry->vertex[markDonor][jVertex]->GetNode(); // Local index of jVertex + + if (!donor_geometry->node[Point_Donor]->GetDomain()) continue; + + auto nNodes = donor_geometry->vertex[markDonor][jVertex]->GetnDonorPoints(); + for (auto iDonor = 0; iDonor < nNodes; iDonor++) { + Buffer_Send_FaceNodes[nLocalFaceNodes_Donor] = donor_geometry->node[Point_Donor]->GetGlobalIndex(); + Buffer_Send_GlobalPoint[nLocalFaceNodes_Donor] = + donor_geometry->vertex[markDonor][jVertex]->GetInterpDonorPoint(iDonor); + Buffer_Send_Coeff[nLocalFaceNodes_Donor] = + donor_geometry->vertex[markDonor][jVertex]->GetDonorCoeff(iDonor); + nLocalFaceNodes_Donor++; } + Buffer_Send_FaceIndex[nLocalFace_Donor+1] =Buffer_Send_FaceIndex[nLocalFace_Donor]+nNodes; + nLocalFace_Donor++; } SU2_MPI::Allgather(Buffer_Send_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, @@ -186,40 +138,42 @@ void CMirror::Set_TransferCoeff(CConfig **config) { Buffer_Receive_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); /*--- Loop over the vertices on the target Marker ---*/ - for (iVertex = 0; iVertexvertex[markTarget][iVertex]; + auto iPoint = target_vertex->GetNode(); - iPoint = target_geometry->vertex[markTarget][iVertex]->GetNode(); if (!target_geometry->node[iPoint]->GetDomain()) continue; - long Global_Point = target_geometry->node[iPoint]->GetGlobalIndex(); - nNodes = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iFace = 0; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { - faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face - iNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1]- (unsigned int)faceindex; - for (iTarget=0; iTargetnode[iPoint]->GetGlobalIndex(); + + auto nNodes = 0; + for (int iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (auto iFace = 0ul; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { + auto faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face + auto iNodes = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1] - faceindex; + for (auto iTarget = 0ul; iTargetvertex[markTarget][iVertex]->SetnDonorPoints(nNodes); - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); - - iDonor = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iFace = 0; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { - - faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face - iNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1]- (unsigned int)faceindex; - for (iTarget=0; iTargetvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,pGlobalPoint); - target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor,coeff); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, iProcessor); + target_vertex->SetnDonorPoints(nNodes); + target_vertex->Allocate_DonorInfo(); + + for (int iProcessor = 0, iDonor = 0; iProcessor < nProcessor; iProcessor++) { + for (auto iFace = 0ul; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { + + auto faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face + auto iNodes = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1] - faceindex; + + for (auto iTarget = 0ul; iTarget < iNodes; iTarget++) { + if (Global_Point == long(Buffer_Receive_GlobalPoint[faceindex+iTarget])) { + auto coeff = Buffer_Receive_Coeff[faceindex+iTarget]; + auto pGlobalPoint = Buffer_Receive_FaceNodes[faceindex+iTarget]; + target_vertex->SetInterpDonorPoint(iDonor,pGlobalPoint); + target_vertex->SetDonorCoeff(iDonor,coeff); + target_vertex->SetInterpDonorProcessor(iDonor, iProcessor); iDonor++; } } diff --git a/SU2_CFD/src/SU2_CFD.cpp b/SU2_CFD/src/SU2_CFD.cpp index 9fac0ec50e99..229aaab1f7e1 100644 --- a/SU2_CFD/src/SU2_CFD.cpp +++ b/SU2_CFD/src/SU2_CFD.cpp @@ -25,7 +25,6 @@ * License along with SU2. If not, see . */ - #include "../include/SU2_CFD.hpp" /* LIBXSMM include files, if supported. */ diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index b1b741c731b6..0d17063686a1 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -3043,11 +3043,9 @@ void CDriver::Turbomachinery_Preprocessing(CConfig** config, CGeometry**** geome } - - - CDriver::~CDriver(void) {} + CFluidDriver::CFluidDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunicator) : CDriver(confFile, val_nZone, MPICommunicator, false) { Max_Iter = config_container[ZONE_0]->GetnInner_Iter(); } From fe8fcc9e6fb4b0a858ab3f490b3555504306d2b1 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Wed, 18 Mar 2020 18:11:19 +0000 Subject: [PATCH 15/79] generalize CNearestNeighbor for KNN --- Common/include/CConfig.hpp | 6 ++ .../CNearestNeighbor.hpp | 7 +- .../interface_interpolation/CSlidingMesh.hpp | 9 ++- Common/src/CConfig.cpp | 10 +-- .../CNearestNeighbor.cpp | 72 ++++++++++++------- .../interface_interpolation/CSlidingMesh.cpp | 11 +-- 6 files changed, 71 insertions(+), 44 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 877f073cc08e..d3f028bcf4b0 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -988,6 +988,7 @@ class CConfig { unsigned short Pred_Order; /*!< \brief Order of the predictor for FSI applications. */ unsigned short Kind_Interpolation; /*!< \brief type of interpolation to use for FSI applications. */ bool ConservativeInterpolation; /*!< \brief Conservative approach for non matching mesh interpolation. */ + unsigned short NumNearestNeighbors; /*!< \brief Number of neighbors used for Nearest Neighbor interpolation. */ unsigned short Kind_RadialBasisFunction; /*!< \brief type of radial basis function to use for radial basis FSI. */ bool RadialBasisFunction_PolynomialOption; /*!< \brief Option of whether to include polynomial terms in Radial Basis Function Interpolation or not. */ su2double RadialBasisFunction_Parameter; /*!< \brief Radial basis function parameter (radius). */ @@ -8793,6 +8794,11 @@ class CConfig { */ su2double GetRadialBasisFunctionPruneTol(void) const { return RadialBasisFunction_PruneTol; } + /*! + * \brief Get the number of donor points to use in Nearest Neighbor interpolation. + */ + unsigned short GetNumNearestNeighbors(void) const { return NumNearestNeighbors; } + /*! * \brief Get the kind of inlet face interpolation function to use. */ diff --git a/Common/include/interface_interpolation/CNearestNeighbor.hpp b/Common/include/interface_interpolation/CNearestNeighbor.hpp index 95dcdfdd3e2f..5c16ed2cdb29 100644 --- a/Common/include/interface_interpolation/CNearestNeighbor.hpp +++ b/Common/include/interface_interpolation/CNearestNeighbor.hpp @@ -29,7 +29,10 @@ #include "CInterpolator.hpp" /*! - * \brief Nearest Neighbor interpolation. + * \brief Nearest Neighbor(s) interpolation. + * \note The closest k neighbors are used for IDW interpolation, the computational + * cost of setting up the interpolation is O(N^2 log(k)), this can be improved + * by using a kd-tree. */ class CNearestNeighbor final : public CInterpolator { public: @@ -43,7 +46,7 @@ class CNearestNeighbor final : public CInterpolator { CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); /*! - * \brief Set up transfer matrix defining relation between two meshes + * \brief Set up transfer matrix defining relation between two meshes. * \param[in] config - Definition of the particular problem. */ void Set_TransferCoeff(CConfig **config) override; diff --git a/Common/include/interface_interpolation/CSlidingMesh.hpp b/Common/include/interface_interpolation/CSlidingMesh.hpp index 43abee84af98..3cbb419d15db 100644 --- a/Common/include/interface_interpolation/CSlidingMesh.hpp +++ b/Common/include/interface_interpolation/CSlidingMesh.hpp @@ -30,6 +30,8 @@ /*! * \brief Sliding mesh approach. + * \note The algorithm is based on Rinaldi et al. "Flux-conserving treatment of non-conformal interfaces + * for finite-volume discritization of conservation laws" 2015, Comp. Fluids, 120, pp 126-139 */ class CSlidingMesh final : public CInterpolator { public: @@ -81,7 +83,8 @@ class CSlidingMesh final : public CInterpolator { * \param[in] B3 - third point of triangle B * \param[in] Direction - vector normal to projection plane */ - su2double Compute_Triangle_Intersection(su2double* A1, su2double* A2, su2double* A3, su2double* B1, su2double* B2, su2double* B3, su2double* Direction); + su2double Compute_Triangle_Intersection(su2double* A1, su2double* A2, su2double* A3, su2double* B1, + su2double* B2, su2double* B3, su2double* Direction); /*! * \brief For 3-Dimensional grids, compute intersection area between two triangle projected on a given plane @@ -93,7 +96,7 @@ class CSlidingMesh final : public CInterpolator { * \param[in] Q2 - second point of triangle B * \param[in] Q3 - third point of triangle B */ - su2double ComputeIntersectionArea( su2double* P1, su2double* P2, su2double* P3, su2double* Q1, su2double* Q2, su2double* Q3 ); + su2double ComputeIntersectionArea(su2double* P1, su2double* P2, su2double* P3, su2double* Q1, su2double* Q2, su2double* Q3); /*! * \brief For 2-Dimensional grids, check whether, and compute, two lines are intersecting @@ -103,7 +106,7 @@ class CSlidingMesh final : public CInterpolator { * \param[in] B2 - second defining second line * \param[in] IntersectionPoint - Container for intersection coordinates */ - void ComputeLineIntersectionPoint( su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* IntersectionPoint ); + void ComputeLineIntersectionPoint(su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* IntersectionPoint); /*! * \brief For N-Dimensional grids, check whether a point is inside a triangle specified by 3 T points diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 2899aab3328f..4f0328015ace 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2457,17 +2457,17 @@ void CConfig::SetConfig_Options() { addBoolOption("WRT_FORCES_BREAKDOWN", Wrt_ForcesBreakdown, false); - - /* DESCRIPTION: Use conservative approach for interpolating between meshes. - * Options: NO, YES \ingroup Config */ - addBoolOption("CONSERVATIVE_INTERPOLATION", ConservativeInterpolation, true); - /*!\par KIND_INTERPOLATION \n * DESCRIPTION: Type of interpolation to use for multi-zone problems. \n OPTIONS: see \link Interpolator_Map \endlink * Sets Kind_Interpolation \ingroup Config */ addEnumOption("KIND_INTERPOLATION", Kind_Interpolation, Interpolator_Map, NEAREST_NEIGHBOR); + /* DESCRIPTION: Use conservative approach for interpolating between meshes. */ + addBoolOption("CONSERVATIVE_INTERPOLATION", ConservativeInterpolation, true); + + addUnsignedShortOption("NUM_NEAREST_NEIGHBORS", NumNearestNeighbors, 1); + /*!\par KIND_INTERPOLATION \n * DESCRIPTION: Type of radial basis function to use for radial basis function interpolation. \n OPTIONS: see \link RadialBasis_Map \endlink * Sets Kind_RadialBasis \ingroup Config diff --git a/Common/src/interface_interpolation/CNearestNeighbor.cpp b/Common/src/interface_interpolation/CNearestNeighbor.cpp index 04843729aa97..7d74a8fb93dc 100644 --- a/Common/src/interface_interpolation/CNearestNeighbor.cpp +++ b/Common/src/interface_interpolation/CNearestNeighbor.cpp @@ -30,6 +30,15 @@ #include "../../include/geometry/CGeometry.hpp" +/*! \brief Helper struct to search sort neighbours according to distance. */ +struct DonorInfo { + su2double dist; + unsigned long pidx; + int proc; + DonorInfo(su2double d = 0.0, unsigned long i = 0, int p = 0) : + dist(d), pidx(i), proc(p) {} +}; + CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { Set_TransferCoeff(config); @@ -37,9 +46,8 @@ CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, CConfig **c void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { - /*--- By definition, one donor point per target point. ---*/ - constexpr auto numDonor = 1; - constexpr auto idxDonor = 0; + /*--- Desired number of donor points. ---*/ + const auto nDonor = config[donorZone]->GetNumNearestNeighbors(); const su2double eps = numeric_limits::epsilon(); @@ -50,6 +58,8 @@ void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { Buffer_Send_nVertex_Donor = new unsigned long [1]; Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; + vector > DonorInfoVec(omp_get_max_threads()); + /*--- Cycle over nMarkersInt interface to determine communication pattern. ---*/ for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { @@ -70,6 +80,9 @@ void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { /* Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor. */ Determine_ArraySize(false, markDonor, markTarget, nVertexDonor, nDim); + const auto nPossibleDonor = accumulate(Buffer_Receive_nVertex_Donor, + Buffer_Receive_nVertex_Donor+nProcessor, 0ul); + Buffer_Send_Coord = new su2double [ MaxLocalVertex_Donor * nDim ]; Buffer_Send_GlobalPoint = new long [ MaxLocalVertex_Donor ]; Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; @@ -78,8 +91,14 @@ void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { /*-- Collect coordinates and global point indices. ---*/ Collect_VertexInfo( false, markDonor, markTarget, nVertexDonor, nDim ); - /*--- Compute the closest donor point to each target. ---*/ - SU2_OMP_PARALLEL_(for schedule(dynamic,roundUpDiv(nVertexTarget,2*omp_get_max_threads()))) + /*--- Find the closest donor points to each target. ---*/ + SU2_OMP_PARALLEL + { + /*--- Working array for this thread. ---*/ + auto& donorInfo = DonorInfoVec[omp_get_thread_num()]; + donorInfo.resize(nPossibleDonor); + + SU2_OMP_FOR_DYN(roundUpDiv(nVertexTarget,2*omp_get_max_threads())) for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; iVertexTarget++) { auto target_vertex = target_geometry->vertex[markTarget][iVertexTarget]; @@ -90,38 +109,41 @@ void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { /*--- Coordinates of the target point. ---*/ const su2double* Coord_i = target_geometry->node[Point_Target]->GetCoord(); - su2double mindist = 1e20; - long pGlobalPoint = 0; - int pProcessor = 0; - - for (int iProcessor = 0; iProcessor < nProcessor; ++iProcessor) { + /*--- Compute all distances. ---*/ + for (int iProcessor = 0, iDonor = 0; iProcessor < nProcessor; ++iProcessor) { for (auto jVertex = 0ul; jVertex < Buffer_Receive_nVertex_Donor[iProcessor]; ++jVertex) { const auto idx = iProcessor*MaxLocalVertex_Donor + jVertex; - + const auto pGlobalPoint = Buffer_Receive_GlobalPoint[idx]; const su2double* Coord_j = &Buffer_Receive_Coord[idx*nDim]; + const auto dist2 = PointsSquareDistance(nDim, Coord_i, Coord_j); - const auto dist = PointsSquareDistance(nDim, Coord_i, Coord_j); + donorInfo[iDonor++] = DonorInfo(dist2, pGlobalPoint, iProcessor); + } + } - if (dist < mindist) { - mindist = dist; - pProcessor = iProcessor; - pGlobalPoint = Buffer_Receive_GlobalPoint[idx]; - } + /*--- Find k closest points. ---*/ + partial_sort(donorInfo.begin(), donorInfo.begin()+nDonor, donorInfo.end(), + [](const DonorInfo& a, const DonorInfo& b){return a.dist < b.dist;}); - /*--- Test for "exact" match. ---*/ - if (dist < eps) break; - } + /*--- Compute interpolation numerators and denominator. ---*/ + su2double denom = 0.0; + for (auto iDonor = 0ul; iDonor < nDonor; ++iDonor) { + donorInfo[iDonor].dist = 1.0 / (donorInfo[iDonor].dist + eps); + denom += donorInfo[iDonor].dist; } - /*--- Store matching pair. ---*/ - target_vertex->SetnDonorPoints(numDonor); + /*--- Set interpolation coefficients. ---*/ + target_vertex->SetnDonorPoints(nDonor); target_vertex->Allocate_DonorInfo(); - target_vertex->SetInterpDonorPoint(idxDonor, pGlobalPoint); - target_vertex->SetInterpDonorProcessor(idxDonor, pProcessor); - target_vertex->SetDonorCoeff(idxDonor, 1.0); + for (auto iDonor = 0ul; iDonor < nDonor; ++iDonor) { + target_vertex->SetInterpDonorPoint(iDonor, donorInfo[iDonor].pidx); + target_vertex->SetInterpDonorProcessor(iDonor, donorInfo[iDonor].proc); + target_vertex->SetDonorCoeff(iDonor, donorInfo[iDonor].dist/denom); + } } + } // end SU2_OMP_PARALLEL delete[] Buffer_Send_Coord; delete[] Buffer_Send_GlobalPoint; diff --git a/Common/src/interface_interpolation/CSlidingMesh.cpp b/Common/src/interface_interpolation/CSlidingMesh.cpp index 62084eb55afd..b76804529b90 100644 --- a/Common/src/interface_interpolation/CSlidingMesh.cpp +++ b/Common/src/interface_interpolation/CSlidingMesh.cpp @@ -37,14 +37,7 @@ CSlidingMesh::CSlidingMesh(CGeometry ****geometry_container, CConfig **config, u void CSlidingMesh::Set_TransferCoeff(CConfig **config) { - /* --- This routine sets the transfer coefficient for sliding mesh approach --- */ - - /* - * The algorithm is based on Rinaldi et al. "Flux-conserving treatment of non-conformal interfaces - * for finite-volume discritization of conservation laws" 2015, Comp. Fluids, 120, pp 126-139 - */ - - /* 0 - Variable declaration - */ + /* 0 - Variable declaration */ /* --- General variables --- */ @@ -102,7 +95,7 @@ void CSlidingMesh::Set_TransferCoeff(CConfig **config) { su2double *donor_iMidEdge_point, *donor_jMidEdge_point; su2double **donor_element, *DonorPoint_Coord; - /* 1 - Variable pre-processing - */ + /* 1 - Variable pre-processing */ nDim = donor_geometry->GetnDim(); From dd1cdcedaf10a294d40a9655d29dec566260c958 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Wed, 18 Mar 2020 19:16:03 +0000 Subject: [PATCH 16/79] more cleanup, try to recover behavior of testcase --- .../CNearestNeighbor.cpp | 31 ++- SU2_CFD/include/interfaces/CInterface.hpp | 22 +- SU2_CFD/src/interfaces/CInterface.cpp | 210 +++--------------- .../src/interfaces/cfd/CSlidingInterface.cpp | 41 +--- 4 files changed, 70 insertions(+), 234 deletions(-) diff --git a/Common/src/interface_interpolation/CNearestNeighbor.cpp b/Common/src/interface_interpolation/CNearestNeighbor.cpp index 7d74a8fb93dc..aa40c4ea433c 100644 --- a/Common/src/interface_interpolation/CNearestNeighbor.cpp +++ b/Common/src/interface_interpolation/CNearestNeighbor.cpp @@ -47,7 +47,7 @@ CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, CConfig **c void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { /*--- Desired number of donor points. ---*/ - const auto nDonor = config[donorZone]->GetNumNearestNeighbors(); + const auto nDonor = max(config[donorZone]->GetNumNearestNeighbors(), 1); const su2double eps = numeric_limits::epsilon(); @@ -126,21 +126,28 @@ void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { partial_sort(donorInfo.begin(), donorInfo.begin()+nDonor, donorInfo.end(), [](const DonorInfo& a, const DonorInfo& b){return a.dist < b.dist;}); - /*--- Compute interpolation numerators and denominator. ---*/ - su2double denom = 0.0; - for (auto iDonor = 0ul; iDonor < nDonor; ++iDonor) { - donorInfo[iDonor].dist = 1.0 / (donorInfo[iDonor].dist + eps); - denom += donorInfo[iDonor].dist; - } - /*--- Set interpolation coefficients. ---*/ target_vertex->SetnDonorPoints(nDonor); target_vertex->Allocate_DonorInfo(); - for (auto iDonor = 0ul; iDonor < nDonor; ++iDonor) { - target_vertex->SetInterpDonorPoint(iDonor, donorInfo[iDonor].pidx); - target_vertex->SetInterpDonorProcessor(iDonor, donorInfo[iDonor].proc); - target_vertex->SetDonorCoeff(iDonor, donorInfo[iDonor].dist/denom); + if (nDonor > 1) { + /*--- Compute interpolation numerators and denominator. ---*/ + su2double denom = 0.0; + for (auto iDonor = 0ul; iDonor < nDonor; ++iDonor) { + donorInfo[iDonor].dist = 1.0 / (donorInfo[iDonor].dist + eps); + denom += donorInfo[iDonor].dist; + } + + for (auto iDonor = 0ul; iDonor < nDonor; ++iDonor) { + target_vertex->SetInterpDonorPoint(iDonor, donorInfo[iDonor].pidx); + target_vertex->SetInterpDonorProcessor(iDonor, donorInfo[iDonor].proc); + target_vertex->SetDonorCoeff(iDonor, donorInfo[iDonor].dist/denom); + } + } + else { + target_vertex->SetInterpDonorPoint(0, donorInfo[0].pidx); + target_vertex->SetInterpDonorProcessor(0, donorInfo[0].proc); + target_vertex->SetDonorCoeff(0, 1.0); } } } // end SU2_OMP_PARALLEL diff --git a/SU2_CFD/include/interfaces/CInterface.hpp b/SU2_CFD/include/interfaces/CInterface.hpp index 6c3a2c8cab84..ecd5b540a4bd 100644 --- a/SU2_CFD/include/interfaces/CInterface.hpp +++ b/SU2_CFD/include/interfaces/CInterface.hpp @@ -7,7 +7,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -56,20 +56,20 @@ using namespace std; class CInterface { protected: - int rank, /*!< \brief MPI Rank. */ - size; /*!< \brief MPI Size. */ + const int rank; /*!< \brief MPI Rank. */ + const int size; /*!< \brief MPI Size. */ - su2double *Physical_Constants; - su2double *Donor_Variable; - su2double *Target_Variable; - bool valAggregated; + su2double *Physical_Constants = nullptr; + su2double *Donor_Variable = nullptr; + su2double *Target_Variable = nullptr; + bool valAggregated = false; /*--- Mixing Plane interface variable ---*/ - su2double *SpanValueCoeffTarget; - unsigned short *SpanLevelDonor; - unsigned short nSpanMaxAllZones; + su2double *SpanValueCoeffTarget = nullptr; + unsigned short *SpanLevelDonor = nullptr; + unsigned short nSpanMaxAllZones = 0; - unsigned short nVar; + unsigned short nVar = 0; public: /*! diff --git a/SU2_CFD/src/interfaces/CInterface.cpp b/SU2_CFD/src/interfaces/CInterface.cpp index 33b5ef6ad62a..455c8b8d96b9 100644 --- a/SU2_CFD/src/interfaces/CInterface.cpp +++ b/SU2_CFD/src/interfaces/CInterface.cpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -26,79 +26,42 @@ */ #include "../../include/interfaces/CInterface.hpp" +#include "../../../Common/include/interface_interpolation/CInterpolator.hpp" -CInterface::CInterface(void) { - - rank = SU2_MPI::GetRank(); - size = SU2_MPI::GetSize(); - - Physical_Constants = NULL; - Donor_Variable = NULL; - Target_Variable = NULL; - SpanLevelDonor = NULL; - SpanValueCoeffTarget = NULL; - - nVar = 0; - +CInterface::CInterface(void) : + rank(SU2_MPI::GetRank()), + size(SU2_MPI::GetSize()) { } -CInterface::CInterface(unsigned short val_nVar, unsigned short val_nConst, CConfig *config) { - - rank = SU2_MPI::GetRank(); - size = SU2_MPI::GetSize(); +CInterface::CInterface(unsigned short val_nVar, unsigned short val_nConst, CConfig *config) : + rank(SU2_MPI::GetRank()), + size(SU2_MPI::GetSize()), + nVar(val_nVar) { - Physical_Constants = NULL; - Donor_Variable = NULL; - Target_Variable = NULL; - - unsigned short iVar; - - Physical_Constants = new su2double[val_nConst]; - Donor_Variable = new su2double[val_nVar]; - Target_Variable = new su2double[val_nVar]; + Physical_Constants = new su2double[val_nConst] (); + Donor_Variable = new su2double[val_nVar] (); + Target_Variable = new su2double[val_nVar] (); /*--- By default, the value is aggregated in the transfer routine ---*/ valAggregated = true; - - nVar = val_nVar; - - for (iVar = 0; iVar < nVar; iVar++) { - Donor_Variable[iVar] = 0.0; - Target_Variable[iVar] = 0.0; - } - - for (iVar = 0; iVar < val_nConst; iVar++) { - Physical_Constants[iVar] = 0.0; - } - - SpanLevelDonor = NULL; - SpanValueCoeffTarget = NULL; - } CInterface::~CInterface(void) { - if (Physical_Constants != NULL) delete [] Physical_Constants; - if (Donor_Variable != NULL) delete [] Donor_Variable; - if (Target_Variable != NULL) delete [] Target_Variable; - - if (SpanValueCoeffTarget != NULL) delete[] SpanValueCoeffTarget; - if (SpanLevelDonor != NULL) delete[] SpanLevelDonor; + delete [] Physical_Constants; + delete [] Donor_Variable; + delete [] Target_Variable; + delete[] SpanValueCoeffTarget; + delete[] SpanLevelDonor; } void CInterface::BroadcastData(CSolver *donor_solution, CSolver *target_solution, CGeometry *donor_geometry, CGeometry *target_geometry, CConfig *donor_config, CConfig *target_config) { - - unsigned short nMarkerInt, nMarkerDonor, nMarkerTarget; // Number of markers on the interface, donor and target side - unsigned short iMarkerInt, iMarkerDonor, iMarkerTarget; // Variables for iteration over markers int Marker_Donor, Marker_Target; - int Target_check, Donor_check; - - unsigned long iVertex; // Variables for iteration over vertices and nodes - + unsigned long iVertex; unsigned short iVar; GetPhysical_Constants(donor_solution, target_solution, donor_geometry, target_geometry, @@ -107,14 +70,8 @@ void CInterface::BroadcastData(CSolver *donor_solution, CSolver *target_solution unsigned long Point_Donor_Global, Donor_Global_Index; unsigned long Point_Donor, Point_Target; -#ifdef HAVE_MPI - int *Buffer_Recv_mark = NULL, iRank; - - if (rank == MASTER_NODE) - Buffer_Recv_mark = new int[size]; -#endif - - unsigned long Buffer_Send_nVertexDonor[1], *Buffer_Recv_nVertexDonor; + unsigned long Buffer_Send_nVertexDonor[1]; + unsigned long *Buffer_Recv_nVertexDonor = new unsigned long[size]; unsigned long iLocalVertex = 0; unsigned long nLocalVertexDonor = 0, nLocalVertexDonorOwned = 0; @@ -125,98 +82,23 @@ void CInterface::BroadcastData(CSolver *donor_solution, CSolver *target_solution unsigned long nBuffer_BcastVariables = 0, nBuffer_BcastIndices = 0; - int nProcessor = 0; + const int nProcessor = size; /*--- Number of markers on the FSI interface ---*/ - nMarkerInt = (donor_config->GetMarker_n_ZoneInterface())/2; - nMarkerTarget = target_config->GetnMarker_All(); - nMarkerDonor = donor_config->GetnMarker_All(); - - nProcessor = size; + const auto nMarkerInt = donor_config->GetMarker_n_ZoneInterface()/2; /*--- Outer loop over the markers on the FSI interface: compute one by one ---*/ /*--- The tags are always an integer greater than 1: loop from 1 to nMarkerFSI ---*/ - for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - - Buffer_Recv_nVertexDonor = NULL; - - Marker_Donor = -1; - Marker_Target = -1; - - /*--- The donor and target markers are tagged with the same index. - *--- This is independent of the MPI domain decomposition. - *--- We need to loop over all markers on both sides and get the number of nodes - *--- that belong to each FSI marker for each processor ---*/ - - /*--- On the donor side ---*/ - - for (iMarkerDonor = 0; iMarkerDonor < nMarkerDonor; iMarkerDonor++) { - /*--- If the tag GetMarker_All_ZoneInterface(iMarkerDonor) equals the index we are looping at ---*/ - if ( donor_config->GetMarker_All_ZoneInterface(iMarkerDonor) == iMarkerInt ) { - /*--- Store the identifier for the structural marker ---*/ - Marker_Donor = iMarkerDonor; - /*--- Exit the for loop: we have found the local index for iMarkerFSI on the FEA side ---*/ - break; - } - } - - /*--- On the target side we only have to identify the marker; - * then we'll loop over it and retrieve from the donor points ---*/ - - for (iMarkerTarget = 0; iMarkerTarget < nMarkerTarget; iMarkerTarget++) { - /*--- If the tag GetMarker_All_ZoneInterface(iMarkerFlow) equals the index we are looping at ---*/ - if ( target_config->GetMarker_All_ZoneInterface(iMarkerTarget) == iMarkerInt ) { - /*--- Store the identifier for the fluid marker ---*/ - Marker_Target = iMarkerTarget; - /*--- Exit the for loop: we have found the local index for iMarkerFSI on the FEA side ---*/ - break; - } - } - -#ifdef HAVE_MPI - - Donor_check = -1; - Target_check = -1; - - /*--- We gather a vector in MASTER_NODE that determines if the boundary is not on the processor - * because of the partition or because the zone does not include it ---*/ - - SU2_MPI::Gather(&Marker_Donor , 1, MPI_INT, Buffer_Recv_mark, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) { - for (iRank = 0; iRank < nProcessor; iRank++) { - if( Buffer_Recv_mark[iRank] != -1 ) { - Donor_check = Buffer_Recv_mark[iRank]; - break; - } - } - } - - SU2_MPI::Bcast(&Donor_check , 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - SU2_MPI::Gather(&Marker_Target, 1, MPI_INT, Buffer_Recv_mark, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) { - for (iRank = 0; iRank < nProcessor; iRank++) { - if( Buffer_Recv_mark[iRank] != -1 ) { - Target_check = Buffer_Recv_mark[iRank]; - break; - } - } - } + for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - SU2_MPI::Bcast(&Target_check, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); + /*--- Check if this interface connects the two zones, if not continue. ---*/ -#else - Donor_check = Marker_Donor; - Target_check = Marker_Target; -#endif + Marker_Donor = CInterpolator::Find_InterfaceMarker(donor_config, iMarkerInt); + Marker_Target = CInterpolator::Find_InterfaceMarker(target_config, iMarkerInt); - if(Target_check == -1 || Donor_check == -1) { - continue; - } + if(!CInterpolator::CheckInterfaceBoundary(Marker_Donor, Marker_Target)) continue; nLocalVertexDonorOwned = 0; nLocalVertexDonor = 0; @@ -233,10 +115,6 @@ void CInterface::BroadcastData(CSolver *donor_solution, CSolver *target_solution Buffer_Send_nVertexDonor[0] = nLocalVertexDonor; // Retrieve total number of vertices on Donor marker - // Allocate memory to receive how many vertices are on each rank on the structural side - if (rank == MASTER_NODE) Buffer_Recv_nVertexDonor = new unsigned long[size]; - -#ifdef HAVE_MPI /*--- We receive MaxLocalVertexDonor as the maximum number of vertices * in one single processor on the donor side---*/ SU2_MPI::Allreduce(&nLocalVertexDonor, &MaxLocalVertexDonor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); @@ -245,13 +123,8 @@ void CInterface::BroadcastData(CSolver *donor_solution, CSolver *target_solution SU2_MPI::Allreduce(&nLocalVertexDonorOwned, &TotalVertexDonor, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); /*--- We gather a vector in MASTER_NODE that determines how many elements are there * on each processor on the structural side ---*/ - SU2_MPI::Gather(&Buffer_Send_nVertexDonor, 1, MPI_UNSIGNED_LONG, Buffer_Recv_nVertexDonor, 1, - MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); -#else - MaxLocalVertexDonor = nLocalVertexDonor; - TotalVertexDonor = nLocalVertexDonorOwned; - Buffer_Recv_nVertexDonor[0] = Buffer_Send_nVertexDonor[0]; -#endif + SU2_MPI::Gather(&Buffer_Send_nVertexDonor, 1, MPI_UNSIGNED_LONG, + Buffer_Recv_nVertexDonor, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD); /*--- We will be gathering the donor information into the master node ---*/ nBuffer_DonorVariables = MaxLocalVertexDonor * nVar; @@ -308,20 +181,12 @@ void CInterface::BroadcastData(CSolver *donor_solution, CSolver *target_solution } -#ifdef HAVE_MPI /*--- Once all the messages have been prepared, we gather them all into the MASTER_NODE ---*/ SU2_MPI::Gather(Buffer_Send_DonorVariables, nBuffer_DonorVariables, MPI_DOUBLE, Buffer_Recv_DonorVariables, nBuffer_DonorVariables, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); SU2_MPI::Gather(Buffer_Send_DonorIndices, nBuffer_DonorIndices, MPI_LONG, Buffer_Recv_DonorIndices, nBuffer_DonorIndices, MPI_LONG, MASTER_NODE, MPI_COMM_WORLD); -#else - for (unsigned long iVariable = 0; iVariable < nBuffer_DonorVariables; iVariable++) - Buffer_Recv_DonorVariables[iVariable] = Buffer_Send_DonorVariables[iVariable]; - for (unsigned long iVariable = 0; iVariable < nBuffer_DonorIndices; iVariable++) - Buffer_Recv_DonorIndices[iVariable] = Buffer_Send_DonorIndices[iVariable]; -#endif - /*--- Now we pack the information to send it over to the different processors ---*/ if (rank == MASTER_NODE) { @@ -352,10 +217,8 @@ void CInterface::BroadcastData(CSolver *donor_solution, CSolver *target_solution } -#ifdef HAVE_MPI SU2_MPI::Bcast(Buffer_Bcast_Variables, nBuffer_BcastVariables, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); SU2_MPI::Bcast(Buffer_Bcast_Indices, nBuffer_BcastIndices, MPI_LONG, MASTER_NODE, MPI_COMM_WORLD); -#endif long indexPoint_iVertex; unsigned short iDonorPoint, nDonorPoints; @@ -418,18 +281,11 @@ void CInterface::BroadcastData(CSolver *donor_solution, CSolver *target_solution delete [] Buffer_Bcast_Variables; delete [] Buffer_Bcast_Indices; - if (rank == MASTER_NODE) { - delete [] Buffer_Recv_nVertexDonor; - delete [] Buffer_Recv_DonorVariables; - delete [] Buffer_Recv_DonorIndices; - } - + delete [] Buffer_Recv_DonorVariables; + delete [] Buffer_Recv_DonorIndices; } -#ifdef HAVE_MPI - if (rank == MASTER_NODE && Buffer_Recv_mark != NULL) - delete [] Buffer_Recv_mark; -#endif + delete [] Buffer_Recv_nVertexDonor; } void CInterface::PreprocessAverage(CGeometry *donor_geometry, CGeometry *target_geometry, @@ -449,7 +305,6 @@ void CInterface::PreprocessAverage(CGeometry *donor_geometry, CGeometry *target_ int *BuffMarkerDonor, *BuffDonorFlag; #endif - nMarkerDonor = donor_geometry->GetnMarker(); nMarkerTarget = target_geometry->GetnMarker(); //TODO turbo this approach only works if all the turboamchinery marker @@ -574,6 +429,7 @@ void CInterface::PreprocessAverage(CGeometry *donor_geometry, CGeometry *target_ void CInterface::AllgatherAverage(CSolver *donor_solution, CSolver *target_solution, CGeometry *donor_geometry, CGeometry *target_geometry, CConfig *donor_config, CConfig *target_config, unsigned short iMarkerInt){ + unsigned short nMarkerDonor, nMarkerTarget; // Number of markers on the interface, donor and target side unsigned short iMarkerDonor, iMarkerTarget; // Variables for iteration over markers unsigned short iSpan, nSpanDonor, nSpanTarget; diff --git a/SU2_CFD/src/interfaces/cfd/CSlidingInterface.cpp b/SU2_CFD/src/interfaces/cfd/CSlidingInterface.cpp index 242a5d6bddc7..a8cf13a71dd5 100644 --- a/SU2_CFD/src/interfaces/cfd/CSlidingInterface.cpp +++ b/SU2_CFD/src/interfaces/cfd/CSlidingInterface.cpp @@ -7,7 +7,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -29,52 +29,25 @@ #include "../../../include/interfaces/cfd/CSlidingInterface.hpp" -CSlidingInterface::CSlidingInterface(void) : CInterface() { - -} +CSlidingInterface::CSlidingInterface(void) : CInterface() { } CSlidingInterface::CSlidingInterface(unsigned short val_nVar, unsigned short val_nConst, CConfig *config) : CInterface() { - rank = SU2_MPI::GetRank(); - size = SU2_MPI::GetSize(); - - Physical_Constants = NULL; - Donor_Variable = NULL; - Target_Variable = NULL; - - unsigned short iVar; - - Physical_Constants = new su2double[val_nConst]; - Donor_Variable = new su2double[val_nVar]; - - Target_Variable = new su2double[val_nVar+1]; + Physical_Constants = new su2double[val_nConst] (); + Donor_Variable = new su2double[val_nVar] (); + Target_Variable = new su2double[val_nVar+1] (); valAggregated = false; nVar = val_nVar; - - for (iVar = 0; iVar < nVar; iVar++) { - Donor_Variable[iVar] = 0.0; - Target_Variable[iVar] = 0.0; - } - - for (iVar = 0; iVar < val_nConst; iVar++) { - Physical_Constants[iVar] = 0.0; - } - -} - -CSlidingInterface::~CSlidingInterface(void) { - } +CSlidingInterface::~CSlidingInterface(void) { } void CSlidingInterface::GetPhysical_Constants(CSolver *donor_solution, CSolver *target_solution, CGeometry *donor_geometry, CGeometry *target_geometry, - CConfig *donor_config, CConfig *target_config) { - -} + CConfig *donor_config, CConfig *target_config) { } void CSlidingInterface::GetDonor_Variable(CSolver *donor_solution, CGeometry *donor_geometry, CConfig *donor_config, unsigned long Marker_Donor, From c0504ff15275d77db3ffe28d797515ba9de9f162 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Wed, 18 Mar 2020 19:56:21 +0000 Subject: [PATCH 17/79] fix build issues --- Common/src/interface_interpolation/CNearestNeighbor.cpp | 9 +++++---- Common/src/linear_algebra/CSysMatrix.cpp | 2 +- SU2_CFD/obj/Makefile.am | 1 - 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Common/src/interface_interpolation/CNearestNeighbor.cpp b/Common/src/interface_interpolation/CNearestNeighbor.cpp index aa40c4ea433c..8322cc0cf50c 100644 --- a/Common/src/interface_interpolation/CNearestNeighbor.cpp +++ b/Common/src/interface_interpolation/CNearestNeighbor.cpp @@ -30,13 +30,14 @@ #include "../../include/geometry/CGeometry.hpp" -/*! \brief Helper struct to search sort neighbours according to distance. */ +/*! \brief Helper struct to (partially) sort neighbours according to distance while + * keeping track of the origin of the point (i.e. index and processor). */ struct DonorInfo { su2double dist; - unsigned long pidx; + unsigned pidx; int proc; - DonorInfo(su2double d = 0.0, unsigned long i = 0, int p = 0) : - dist(d), pidx(i), proc(p) {} + DonorInfo(su2double d = 0.0, unsigned i = 0, int p = 0) : + dist(d), pidx(i), proc(p) { } }; CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, diff --git a/Common/src/linear_algebra/CSysMatrix.cpp b/Common/src/linear_algebra/CSysMatrix.cpp index 2a47d4785a60..60a42b635428 100644 --- a/Common/src/linear_algebra/CSysMatrix.cpp +++ b/Common/src/linear_algebra/CSysMatrix.cpp @@ -1383,7 +1383,7 @@ void CSysMatrix::ComputePastixPreconditioner(const CSysVector void CSysMatrix::BuildPastixPreconditioner(CGeometry *geometry, CConfig *config, unsigned short kind_fact, bool transposed) { diff --git a/SU2_CFD/obj/Makefile.am b/SU2_CFD/obj/Makefile.am index 2ed339136e4e..a46d07ef0b79 100644 --- a/SU2_CFD/obj/Makefile.am +++ b/SU2_CFD/obj/Makefile.am @@ -126,7 +126,6 @@ libSU2Core_sources = ../src/definition_structure.cpp \ ../src/output/CMultizoneOutput.cpp \ ../src/output/COutputFactory.cpp \ ../src/output/output_structure_legacy.cpp \ - ../src/output/COutputFactory.cpp \ ../src/python_wrapper_structure.cpp \ ../src/solvers/CAdjEulerSolver.cpp \ ../src/solvers/CAdjNSSolver.cpp \ From a61f3b808da800fc2bd733b13bb6de554c399bc4 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 19 Mar 2020 10:55:54 +0000 Subject: [PATCH 18/79] const use of CConfig in CInterpolator --- Common/include/CConfig.hpp | 30 ++++++++--------- .../interface_interpolation/CInterpolator.hpp | 4 +-- .../CIsoparametric.hpp | 4 +-- .../interface_interpolation/CMirror.hpp | 4 +-- .../CNearestNeighbor.hpp | 4 +-- .../CRadialBasisFunction.hpp | 5 +-- .../interface_interpolation/CSlidingMesh.hpp | 5 +-- .../interface_interpolation/CInterpolator.cpp | 3 +- .../CIsoparametric.cpp | 4 +-- .../src/interface_interpolation/CMirror.cpp | 4 +-- .../CNearestNeighbor.cpp | 33 ++++++++----------- .../CRadialBasisFunction.cpp | 4 +-- .../interface_interpolation/CSlidingMesh.cpp | 4 +-- SU2_CFD/src/interfaces/CInterface.cpp | 23 ++++--------- 14 files changed, 59 insertions(+), 72 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index d3f028bcf4b0..604f83e10f9b 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -3462,27 +3462,27 @@ class CConfig { unsigned short GetMarker_All_ZoneInterface(unsigned short val_marker) const { return Marker_All_ZoneInterface[val_marker]; } /*! - * \brief Get the MixingPlane interface information for a marker val_marker. - * \param[in] val_marker value of the marker on the grid. - * \return 0 if is not part of the MixingPlane Interface and greater than 1 if it is part. - */ + * \brief Get the MixingPlane interface information for a marker val_marker. + * \param[in] val_marker value of the marker on the grid. + * \return 0 if is not part of the MixingPlane Interface and greater than 1 if it is part. + */ unsigned short GetMarker_All_MixingPlaneInterface(unsigned short val_marker) const { return Marker_All_MixingPlaneInterface[val_marker]; } - /*! - * \brief Get the Turbomachinery information for a marker val_marker. - * \param[in] val_marker value of the marker on the grid. - * \return 0 if is not part of the Turbomachinery and greater than 1 if it is part. - */ + /*! + * \brief Get the Turbomachinery information for a marker val_marker. + * \param[in] val_marker value of the marker on the grid. + * \return 0 if is not part of the Turbomachinery and greater than 1 if it is part. + */ unsigned short GetMarker_All_Turbomachinery(unsigned short val_marker) const { return Marker_All_Turbomachinery[val_marker]; } - /*! - * \brief Get the Turbomachinery flag information for a marker val_marker. - * \param[in] val_marker value of the marker on the grid. - * \return 0 if is not part of the Turbomachinery, flag INFLOW or OUTFLOW if it is part. - */ + /*! + * \brief Get the Turbomachinery flag information for a marker val_marker. + * \param[in] val_marker value of the marker on the grid. + * \return 0 if is not part of the Turbomachinery, flag INFLOW or OUTFLOW if it is part. + */ unsigned short GetMarker_All_TurbomachineryFlag(unsigned short val_marker) const { return Marker_All_TurbomachineryFlag[val_marker]; } - /*! + /*! * \brief Get the number of FSI interface markers val_marker. * \param[in] void. * \return Number of markers belonging to the FSI interface. diff --git a/Common/include/interface_interpolation/CInterpolator.hpp b/Common/include/interface_interpolation/CInterpolator.hpp index 487e5131f345..1bc27bcb3cd5 100644 --- a/Common/include/interface_interpolation/CInterpolator.hpp +++ b/Common/include/interface_interpolation/CInterpolator.hpp @@ -100,7 +100,7 @@ class CInterpolator { * \param[in] iZone - index of the donor zone * \param[in] jZone - index of the target zone */ - CInterpolator(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); + CInterpolator(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone); /*! * \brief No default construction allowed. @@ -117,7 +117,7 @@ class CInterpolator { * \note Main method that derived classes must implement. * \param[in] config - Definition of the particular problem. */ - virtual void Set_TransferCoeff(CConfig **config) = 0; + virtual void Set_TransferCoeff(const CConfig* const* config) = 0; /*! * \brief Find the index of the interface marker shared by that zone diff --git a/Common/include/interface_interpolation/CIsoparametric.hpp b/Common/include/interface_interpolation/CIsoparametric.hpp index 250a7814f15d..1175e3890f2e 100644 --- a/Common/include/interface_interpolation/CIsoparametric.hpp +++ b/Common/include/interface_interpolation/CIsoparametric.hpp @@ -40,13 +40,13 @@ class CIsoparametric final : public CInterpolator { * \param[in] iZone - index of the donor zone * \param[in] jZone - index of the target zone */ - CIsoparametric(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); + CIsoparametric(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone); /*! * \brief Set up transfer matrix defining relation between two meshes * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(CConfig **config) override; + void Set_TransferCoeff(const CConfig* const* config) override; private: /*! diff --git a/Common/include/interface_interpolation/CMirror.hpp b/Common/include/interface_interpolation/CMirror.hpp index c53ebc4bd889..311d54d96a60 100644 --- a/Common/include/interface_interpolation/CMirror.hpp +++ b/Common/include/interface_interpolation/CMirror.hpp @@ -42,12 +42,12 @@ class CMirror final : public CInterpolator { * \param[in] iZone - First zone * \param[in] jZone - Second zone */ - CMirror(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); + CMirror(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone); /*! * \brief Set up transfer matrix defining relation between two meshes * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(CConfig **config) override; + void Set_TransferCoeff(const CConfig* const* config) override; }; diff --git a/Common/include/interface_interpolation/CNearestNeighbor.hpp b/Common/include/interface_interpolation/CNearestNeighbor.hpp index 5c16ed2cdb29..c8efe3998e40 100644 --- a/Common/include/interface_interpolation/CNearestNeighbor.hpp +++ b/Common/include/interface_interpolation/CNearestNeighbor.hpp @@ -43,12 +43,12 @@ class CNearestNeighbor final : public CInterpolator { * \param[in] iZone - index of the donor zone * \param[in] jZone - index of the target zone */ - CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); + CNearestNeighbor(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone); /*! * \brief Set up transfer matrix defining relation between two meshes. * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(CConfig **config) override; + void Set_TransferCoeff(const CConfig* const* config) override; }; diff --git a/Common/include/interface_interpolation/CRadialBasisFunction.hpp b/Common/include/interface_interpolation/CRadialBasisFunction.hpp index 37b75d784940..784ba1b321fd 100644 --- a/Common/include/interface_interpolation/CRadialBasisFunction.hpp +++ b/Common/include/interface_interpolation/CRadialBasisFunction.hpp @@ -42,13 +42,14 @@ class CRadialBasisFunction final : public CInterpolator { * \param[in] iZone - index of the donor zone * \param[in] jZone - index of the target zone */ - CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); + CRadialBasisFunction(CGeometry ****geometry_container, const CConfig* const* config, + unsigned int iZone, unsigned int jZone); /*! * \brief Set up transfer matrix defining relation between two meshes * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(CConfig **config) override; + void Set_TransferCoeff(const CConfig* const* config) override; /*! * \brief Compute the value of a radial basis function, this is static so it can be re-used. diff --git a/Common/include/interface_interpolation/CSlidingMesh.hpp b/Common/include/interface_interpolation/CSlidingMesh.hpp index 3cbb419d15db..e84c4c908a74 100644 --- a/Common/include/interface_interpolation/CSlidingMesh.hpp +++ b/Common/include/interface_interpolation/CSlidingMesh.hpp @@ -42,13 +42,14 @@ class CSlidingMesh final : public CInterpolator { * \param[in] iZone - index of the donor zone * \param[in] jZone - index of the target zone */ - CSlidingMesh(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); + CSlidingMesh(CGeometry ****geometry_container, const CConfig* const* config, + unsigned int iZone, unsigned int jZone); /*! * \brief Set up transfer matrix defining relation between two meshes * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(CConfig **config) override; + void Set_TransferCoeff(const CConfig* const* config) override; private: /*! diff --git a/Common/src/interface_interpolation/CInterpolator.cpp b/Common/src/interface_interpolation/CInterpolator.cpp index 05d54a74fbdf..2c2c0089bb9e 100644 --- a/Common/src/interface_interpolation/CInterpolator.cpp +++ b/Common/src/interface_interpolation/CInterpolator.cpp @@ -30,7 +30,8 @@ #include "../../include/geometry/CGeometry.hpp" -CInterpolator::CInterpolator(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : +CInterpolator::CInterpolator(CGeometry ****geometry_container, const CConfig* const* config, + unsigned int iZone, unsigned int jZone) : rank(SU2_MPI::GetRank()), size(SU2_MPI::GetSize()), donorZone(iZone), diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp index ef3468b86fb3..4e46e5f94ee1 100644 --- a/Common/src/interface_interpolation/CIsoparametric.cpp +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -30,12 +30,12 @@ #include "../../include/geometry/CGeometry.hpp" -CIsoparametric::CIsoparametric(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, +CIsoparametric::CIsoparametric(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { Set_TransferCoeff(config); } -void CIsoparametric::Set_TransferCoeff(CConfig **config) { +void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { unsigned long iVertex, jVertex; unsigned long dPoint, inode, jElem, nElem; diff --git a/Common/src/interface_interpolation/CMirror.cpp b/Common/src/interface_interpolation/CMirror.cpp index 49bcc91b93c0..d64d0451811d 100644 --- a/Common/src/interface_interpolation/CMirror.cpp +++ b/Common/src/interface_interpolation/CMirror.cpp @@ -30,12 +30,12 @@ #include "../../include/geometry/CGeometry.hpp" -CMirror::CMirror(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, +CMirror::CMirror(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { Set_TransferCoeff(config); } -void CMirror::Set_TransferCoeff(CConfig **config) { +void CMirror::Set_TransferCoeff(const CConfig* const* config) { const int nProcessor = size; diff --git a/Common/src/interface_interpolation/CNearestNeighbor.cpp b/Common/src/interface_interpolation/CNearestNeighbor.cpp index 8322cc0cf50c..9d5536e88fe7 100644 --- a/Common/src/interface_interpolation/CNearestNeighbor.cpp +++ b/Common/src/interface_interpolation/CNearestNeighbor.cpp @@ -40,12 +40,12 @@ struct DonorInfo { dist(d), pidx(i), proc(p) { } }; -CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, +CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { Set_TransferCoeff(config); } -void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { +void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { /*--- Desired number of donor points. ---*/ const auto nDonor = max(config[donorZone]->GetNumNearestNeighbors(), 1); @@ -127,28 +127,21 @@ void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { partial_sort(donorInfo.begin(), donorInfo.begin()+nDonor, donorInfo.end(), [](const DonorInfo& a, const DonorInfo& b){return a.dist < b.dist;}); + /*--- Compute interpolation numerators and denominator. ---*/ + su2double denom = 0.0; + for (auto iDonor = 0ul; iDonor < nDonor; ++iDonor) { + donorInfo[iDonor].dist = 1.0 / (donorInfo[iDonor].dist + eps); + denom += donorInfo[iDonor].dist; + } + /*--- Set interpolation coefficients. ---*/ target_vertex->SetnDonorPoints(nDonor); target_vertex->Allocate_DonorInfo(); - if (nDonor > 1) { - /*--- Compute interpolation numerators and denominator. ---*/ - su2double denom = 0.0; - for (auto iDonor = 0ul; iDonor < nDonor; ++iDonor) { - donorInfo[iDonor].dist = 1.0 / (donorInfo[iDonor].dist + eps); - denom += donorInfo[iDonor].dist; - } - - for (auto iDonor = 0ul; iDonor < nDonor; ++iDonor) { - target_vertex->SetInterpDonorPoint(iDonor, donorInfo[iDonor].pidx); - target_vertex->SetInterpDonorProcessor(iDonor, donorInfo[iDonor].proc); - target_vertex->SetDonorCoeff(iDonor, donorInfo[iDonor].dist/denom); - } - } - else { - target_vertex->SetInterpDonorPoint(0, donorInfo[0].pidx); - target_vertex->SetInterpDonorProcessor(0, donorInfo[0].proc); - target_vertex->SetDonorCoeff(0, 1.0); + for (auto iDonor = 0ul; iDonor < nDonor; ++iDonor) { + target_vertex->SetInterpDonorPoint(iDonor, donorInfo[iDonor].pidx); + target_vertex->SetInterpDonorProcessor(iDonor, donorInfo[iDonor].proc); + target_vertex->SetDonorCoeff(iDonor, donorInfo[iDonor].dist/denom); } } } // end SU2_OMP_PARALLEL diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp index eabd34671bab..3edf9bace1b2 100644 --- a/Common/src/interface_interpolation/CRadialBasisFunction.cpp +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -31,7 +31,7 @@ #include "../../include/toolboxes/CSymmetricMatrix.hpp" -CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, +CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { Set_TransferCoeff(config); } @@ -66,7 +66,7 @@ su2double CRadialBasisFunction::Get_RadialBasisValue(ENUM_RADIALBASIS type, cons return rbf; } -void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { +void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { /*--- RBF options. ---*/ const auto kindRBF = static_cast(config[donorZone]->GetKindRadialBasisFunction()); diff --git a/Common/src/interface_interpolation/CSlidingMesh.cpp b/Common/src/interface_interpolation/CSlidingMesh.cpp index b76804529b90..4468b31157e2 100644 --- a/Common/src/interface_interpolation/CSlidingMesh.cpp +++ b/Common/src/interface_interpolation/CSlidingMesh.cpp @@ -30,12 +30,12 @@ #include "../../include/geometry/CGeometry.hpp" -CSlidingMesh::CSlidingMesh(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, +CSlidingMesh::CSlidingMesh(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { Set_TransferCoeff(config); } -void CSlidingMesh::Set_TransferCoeff(CConfig **config) { +void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { /* 0 - Variable declaration */ diff --git a/SU2_CFD/src/interfaces/CInterface.cpp b/SU2_CFD/src/interfaces/CInterface.cpp index 455c8b8d96b9..df0d1ab46490 100644 --- a/SU2_CFD/src/interfaces/CInterface.cpp +++ b/SU2_CFD/src/interfaces/CInterface.cpp @@ -300,11 +300,6 @@ void CInterface::PreprocessAverage(CGeometry *donor_geometry, CGeometry *target_ const su2double *SpanValuesDonor, *SpanValuesTarget; su2double dist, test, dist2, test2; -#ifdef HAVE_MPI - int iSize; - int *BuffMarkerDonor, *BuffDonorFlag; -#endif - nMarkerDonor = donor_geometry->GetnMarker(); nMarkerTarget = target_geometry->GetnMarker(); //TODO turbo this approach only works if all the turboamchinery marker @@ -333,25 +328,23 @@ void CInterface::PreprocessAverage(CGeometry *donor_geometry, CGeometry *target_ } #ifdef HAVE_MPI - BuffMarkerDonor = new int[size]; - BuffDonorFlag = new int[size]; - for (iSize=0; iSize 0.0){ Marker_Donor = BuffMarkerDonor[iSize]; - Donor_Flag = BuffDonorFlag[iSize]; + Donor_Flag = BuffDonorFlag[iSize]; break; } } @@ -623,7 +616,6 @@ void CInterface::AllgatherAverage(CSolver *donor_solution, CSolver *target_solut delete [] BuffAvgKineDonor; delete [] BuffAvgOmegaDonor; delete [] BuffMarkerDonor; - #endif /*--- On the target side we have to identify the marker as well ---*/ @@ -760,4 +752,3 @@ void CInterface::GatherAverageTurboGeoValues(CGeometry *donor_geometry, CGeometr SetAverageTurboGeoValues(donor_geometry, target_geometry, donorZone); } - From 02df871bf41d942aa3d1ca0a448b36d97a9626f9 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 19 Mar 2020 12:12:50 +0000 Subject: [PATCH 19/79] more const correctness --- .../interface_interpolation/CSlidingMesh.hpp | 32 +++-- Common/include/toolboxes/C2DContainer.hpp | 1 + Common/include/toolboxes/CSymmetricMatrix.hpp | 14 ++- .../CRadialBasisFunction.cpp | 7 +- .../interface_interpolation/CSlidingMesh.cpp | 111 +++++++++--------- Common/src/toolboxes/CSymmetricMatrix.cpp | 29 ++--- 6 files changed, 100 insertions(+), 94 deletions(-) diff --git a/Common/include/interface_interpolation/CSlidingMesh.hpp b/Common/include/interface_interpolation/CSlidingMesh.hpp index e84c4c908a74..74ae1d9ae18f 100644 --- a/Common/include/interface_interpolation/CSlidingMesh.hpp +++ b/Common/include/interface_interpolation/CSlidingMesh.hpp @@ -55,24 +55,29 @@ class CSlidingMesh final : public CInterpolator { /*! * \brief For 3-Dimensional grids, build the dual surface element * \param[in] map - array containing the index of the boundary points connected to the node - * \param[in] startIndex - for each vertex specifies the corresponding index in the global array containing the indexes of all its neighbouring vertexes + * \param[in] startIndex - for each vertex specifies the corresponding index in the global + * array containing the indexes of all its neighbouring vertexes * \param[in] nNeighbour - for each vertex specifies the number of its neighbouring vertexes (on the boundary) * \param[in] coord - array containing the coordinates of all the boundary vertexes * \param[in] centralNode - label of the vertex around which the dual surface element is built - * \param[in] element - double array where element node coordinates will be stored + * \param[out] element - double array where element node coordinates will be stored + * \return Number of points included in the element. */ - int Build_3D_surface_element(unsigned long *map, unsigned long *startIndex, unsigned long* nNeighbor, - su2double *coord, unsigned long centralNode, su2double** element); + static int Build_3D_surface_element(const unsigned long *map, const unsigned long *startIndex, + const unsigned long* nNeighbor, const su2double *coord, + unsigned long centralNode, su2double** element); /*! * \brief For 2-Dimensional grids, compute intersection length of two segments projected along a given direction + * \param[in] nDim - Number of dimensions * \param[in] A1 - first point of segment A * \param[in] A2 - second point of segment A * \param[in] B1 - first point of segment B * \param[in] B2 - second point of segment B * \param[in] Direction - along which segments are projected */ - su2double ComputeLineIntersectionLength(su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* Direction); + static su2double ComputeLineIntersectionLength(unsigned short nDim, const su2double* A1, const su2double* A2, + const su2double* B1, const su2double* B2, const su2double* Direction); /*! * \brief For 3-Dimensional grids, compute intersection area between two triangle projected on a given plane @@ -84,8 +89,9 @@ class CSlidingMesh final : public CInterpolator { * \param[in] B3 - third point of triangle B * \param[in] Direction - vector normal to projection plane */ - su2double Compute_Triangle_Intersection(su2double* A1, su2double* A2, su2double* A3, su2double* B1, - su2double* B2, su2double* B3, su2double* Direction); + static su2double Compute_Triangle_Intersection(const su2double* A1, const su2double* A2, const su2double* A3, + const su2double* B1, const su2double* B2, const su2double* B3, + const su2double* Direction); /*! * \brief For 3-Dimensional grids, compute intersection area between two triangle projected on a given plane @@ -97,7 +103,8 @@ class CSlidingMesh final : public CInterpolator { * \param[in] Q2 - second point of triangle B * \param[in] Q3 - third point of triangle B */ - su2double ComputeIntersectionArea(su2double* P1, su2double* P2, su2double* P3, su2double* Q1, su2double* Q2, su2double* Q3); + static su2double ComputeIntersectionArea(const su2double* P1, const su2double* P2, const su2double* P3, + const su2double* Q1, const su2double* Q2, const su2double* Q3); /*! * \brief For 2-Dimensional grids, check whether, and compute, two lines are intersecting @@ -105,9 +112,10 @@ class CSlidingMesh final : public CInterpolator { * \param[in] A2 - second defining first line * \param[in] B1 - first defining second line * \param[in] B2 - second defining second line - * \param[in] IntersectionPoint - Container for intersection coordinates + * \param[out] IntersectionPoint - Container for intersection coordinates */ - void ComputeLineIntersectionPoint(su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* IntersectionPoint); + static void ComputeLineIntersectionPoint(const su2double* A1, const su2double* A2, const su2double* B1, + const su2double* B2, su2double* IntersectionPoint); /*! * \brief For N-Dimensional grids, check whether a point is inside a triangle specified by 3 T points @@ -116,6 +124,6 @@ class CSlidingMesh final : public CInterpolator { * \param[in] T2 - second point of triangle T * \param[in] T3 - third point of triangle T */ - bool CheckPointInsideTriangle(su2double* Point, su2double* T1, su2double* T2, su2double* T3); - + static bool CheckPointInsideTriangle(const su2double* Point, const su2double* T1, + const su2double* T2, const su2double* T3); }; diff --git a/Common/include/toolboxes/C2DContainer.hpp b/Common/include/toolboxes/C2DContainer.hpp index a5c978f2bff3..93f1314766f6 100644 --- a/Common/include/toolboxes/C2DContainer.hpp +++ b/Common/include/toolboxes/C2DContainer.hpp @@ -371,6 +371,7 @@ class C2DContainer : using Base::size; using Index = Index_t; using Scalar = Scalar_t; + static constexpr StorageType Storage = Store; private: /*! diff --git a/Common/include/toolboxes/CSymmetricMatrix.hpp b/Common/include/toolboxes/CSymmetricMatrix.hpp index 24f057cdcd65..b32613a864ae 100644 --- a/Common/include/toolboxes/CSymmetricMatrix.hpp +++ b/Common/include/toolboxes/CSymmetricMatrix.hpp @@ -81,9 +81,19 @@ class CSymmetricMatrix { inline const passivedouble& operator() (int i, int j) const { return val_vec[IdxSym(i,j)]; } - void MatVecMult(passivedouble *v) const; + template + void MatVecMult(ForwardIt vec_in, ForwardIt vec_out) const + { + for (int i = 0; i < sz; ++i) { + *vec_out = 0.0; + auto vec = vec_in; + for (int k = 0; k < sz; ++k) + *vec_out += *(vec++) * Get(i,k); + ++vec_out; + } + } - void MatMatMult(const char side, su2passivematrix& mat_in, su2passivematrix& mat_out); + void MatMatMult(const char side, const su2passivematrix& mat_in, su2passivematrix& mat_out) const; void Invert(const bool is_spd); diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp index 3edf9bace1b2..e25bdbb688d4 100644 --- a/Common/src/interface_interpolation/CRadialBasisFunction.cpp +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -401,6 +401,7 @@ int CRadialBasisFunction::CheckPolynomialTerms(su2double max_diff_tol, vector coeff(n_rows,0.0); + vector rhs(n_rows,0.0), coeff(n_rows); for (int i = 0; i < n_rows; ++i) for (int j = 0; j < n; ++j) - coeff[i] += P(i+1,j); + rhs[i] += P(i+1,j); /*--- Multiply the RHS by the inverse thus obtaining the coefficients. ---*/ - PPT.MatVecMult(coeff.data()); + PPT.MatVecMult(rhs.begin(), coeff.begin()); /*--- Determine the maximum deviation of the points from the fitted plane. ---*/ passivedouble max_diff = 0.0; diff --git a/Common/src/interface_interpolation/CSlidingMesh.cpp b/Common/src/interface_interpolation/CSlidingMesh.cpp index 4468b31157e2..2ac685049af6 100644 --- a/Common/src/interface_interpolation/CSlidingMesh.cpp +++ b/Common/src/interface_interpolation/CSlidingMesh.cpp @@ -43,7 +43,7 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { bool check; - unsigned short iDim, nDim; + unsigned short iDim; unsigned long ii, jj, *uptr; unsigned long vPoint; @@ -97,17 +97,17 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { /* 1 - Variable pre-processing */ - nDim = donor_geometry->GetnDim(); + const unsigned short nDim = donor_geometry->GetnDim(); /*--- Setting up auxiliary vectors ---*/ - Donor_Vect = NULL; - Coeff_Vect = NULL; - storeProc = NULL; + Donor_Vect = nullptr; + Coeff_Vect = nullptr; + storeProc = nullptr; - tmp_Donor_Vect = NULL; - tmp_Coeff_Vect = NULL; - tmp_storeProc = NULL; + tmp_Donor_Vect = nullptr; + tmp_Coeff_Vect = nullptr; + tmp_storeProc = nullptr; Normal = new su2double[nDim]; Direction = new su2double[nDim]; @@ -289,7 +289,7 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; } - LineIntersectionLength = ComputeLineIntersectionLength(target_iMidEdge_point, target_jMidEdge_point, + LineIntersectionLength = ComputeLineIntersectionLength(nDim, target_iMidEdge_point, target_jMidEdge_point, donor_iMidEdge_point, donor_jMidEdge_point, Direction); if ( LineIntersectionLength == 0.0 ){ @@ -313,9 +313,9 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { tmp_Coeff_Vect[ nDonorPoints ] = LineIntersectionLength / length; tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; - if (Donor_Vect != NULL) delete [] Donor_Vect; - if (Coeff_Vect != NULL) delete [] Coeff_Vect; - if (storeProc != NULL) delete [] storeProc; + if (Donor_Vect != nullptr) delete [] Donor_Vect; + if (Coeff_Vect != nullptr) delete [] Coeff_Vect; + if (storeProc != nullptr) delete [] storeProc; Donor_Vect = tmp_Donor_Vect; Coeff_Vect = tmp_Coeff_Vect; @@ -372,7 +372,7 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; } - LineIntersectionLength = ComputeLineIntersectionLength(target_iMidEdge_point, target_jMidEdge_point, + LineIntersectionLength = ComputeLineIntersectionLength(nDim, target_iMidEdge_point, target_jMidEdge_point, donor_iMidEdge_point, donor_jMidEdge_point, Direction); if ( LineIntersectionLength == 0.0 ){ @@ -396,9 +396,9 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; - if (Donor_Vect != NULL) delete [] Donor_Vect; - if (Coeff_Vect != NULL) delete [] Coeff_Vect; - if (storeProc != NULL) delete [] storeProc; + if (Donor_Vect != nullptr) delete [] Donor_Vect; + if (Coeff_Vect != nullptr) delete [] Coeff_Vect; + if (storeProc != nullptr) delete [] storeProc; Donor_Vect = tmp_Donor_Vect; Coeff_Vect = tmp_Coeff_Vect; @@ -554,7 +554,7 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { Area_old = Area; - ToVisit = NULL; + ToVisit = nullptr; nToVisit = 0; for( iNodeVisited = StartVisited; iNodeVisited < nAlreadyVisited; iNodeVisited++ ){ @@ -578,7 +578,7 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { } } - if( check == 0 && ToVisit != NULL){ + if( check == 0 && ToVisit != nullptr){ for( jj = 0; jj < nToVisit; jj++ ) if( donor_iPoint == ToVisit[jj] ){ check = 1; @@ -595,11 +595,11 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { tmpVect[jj] = ToVisit[jj]; tmpVect[nToVisit] = donor_iPoint; - if( ToVisit != NULL ) + if( ToVisit != nullptr ) delete [] ToVisit; ToVisit = tmpVect; - tmpVect = NULL; + tmpVect = nullptr; nToVisit++; @@ -640,17 +640,17 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; - if (Donor_Vect != NULL) {delete [] Donor_Vect; } - if (Coeff_Vect != NULL) {delete [] Coeff_Vect; } - if (storeProc != NULL) {delete [] storeProc; } + if (Donor_Vect != nullptr) {delete [] Donor_Vect; } + if (Coeff_Vect != nullptr) {delete [] Coeff_Vect; } + if (storeProc != nullptr) {delete [] storeProc; } Donor_Vect = tmp_Donor_Vect; Coeff_Vect = tmp_Coeff_Vect; storeProc = tmp_storeProc; - tmp_Coeff_Vect = NULL; - tmp_Donor_Vect = NULL; - tmp_storeProc = NULL; + tmp_Coeff_Vect = nullptr; + tmp_Donor_Vect = nullptr; + tmp_storeProc = nullptr; nDonorPoints++; @@ -671,7 +671,7 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { for( jj = 0; jj < nToVisit; jj++ ) tmpVect[ nAlreadyVisited + jj ] = ToVisit[jj]; - if( alreadyVisitedDonor != NULL ) + if( alreadyVisitedDonor != nullptr ) delete [] alreadyVisitedDonor; alreadyVisitedDonor = tmpVect; @@ -698,9 +698,9 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { delete [] target_element[ii]; delete [] target_element; - delete [] Donor_Vect; Donor_Vect = NULL; - delete [] Coeff_Vect; Coeff_Vect = NULL; - delete [] storeProc; storeProc = NULL; + delete [] Donor_Vect; Donor_Vect = nullptr; + delete [] Coeff_Vect; Coeff_Vect = nullptr; + delete [] storeProc; storeProc = nullptr; } } @@ -723,24 +723,25 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { delete [] Normal; delete [] Direction; - if (Donor_Vect != NULL) delete [] Donor_Vect; - if (Coeff_Vect != NULL) delete [] Coeff_Vect; - if (storeProc != NULL) delete [] storeProc; + if (Donor_Vect != nullptr) delete [] Donor_Vect; + if (Coeff_Vect != nullptr) delete [] Coeff_Vect; + if (storeProc != nullptr) delete [] storeProc; } -int CSlidingMesh::Build_3D_surface_element(unsigned long *map, unsigned long *startIndex, unsigned long* nNeighbor, - su2double *coord, unsigned long centralNode, su2double** element){ +int CSlidingMesh::Build_3D_surface_element(const unsigned long *map, const unsigned long *startIndex, + const unsigned long* nNeighbor, const su2double *coord, + unsigned long centralNode, su2double** element) { /*--- Given a node "centralNode", this routines reconstruct the vertex centered * surface element around the node and store it into "element" ---*/ - /*--- Returns the number of points included in the element ---*/ unsigned long iNode, jNode, kNode, iElementNode, iPoint, jPoint, nOuterNodes; - unsigned short nDim = 3, iDim, nTmp; + constexpr unsigned short nDim = 3; + unsigned short iDim, nTmp; int NextNode, **OuterNodesNeighbour, CurrentNode, StartIndex, count; - unsigned long *OuterNodes, *ptr; + const unsigned long *OuterNodes, *ptr; /* --- Store central node as element first point --- */ @@ -841,15 +842,14 @@ int CSlidingMesh::Build_3D_surface_element(unsigned long *map, unsigned long *st } -su2double CSlidingMesh::ComputeLineIntersectionLength(su2double* A1, su2double* A2, su2double* B1, - su2double* B2, su2double* Direction){ +su2double CSlidingMesh::ComputeLineIntersectionLength(unsigned short nDim, const su2double* A1, const su2double* A2, + const su2double* B1, const su2double* B2, const su2double* Direction) { /*--- Given 2 segments, each defined by 2 points, it projects them along a given direction * and it computes the length of the segment resulting from their intersection ---*/ /*--- The algorithm works for both 2D and 3D problems ---*/ unsigned short iDim; - unsigned short nDim = donor_geometry->GetnDim(); su2double dotA2, dotB1, dotB2; @@ -898,14 +898,15 @@ su2double CSlidingMesh::ComputeLineIntersectionLength(su2double* A1, su2double* return 0.0; } -su2double CSlidingMesh::Compute_Triangle_Intersection(su2double* A1, su2double* A2, su2double* A3, - su2double* B1, su2double* B2, su2double* B3, su2double* Direction){ +su2double CSlidingMesh::Compute_Triangle_Intersection(const su2double* A1, const su2double* A2, const su2double* A3, + const su2double* B1, const su2double* B2, const su2double* B3, + const su2double* Direction) { /* --- This routine is ONLY for 3D grids --- */ /* --- Projects triangle points onto a plane, specified by its normal "Direction", and calls the ComputeIntersectionArea routine --- */ unsigned short iDim; - unsigned short nDim = 3; + constexpr unsigned short nDim = 3; su2double I[3], J[3], K[3]; su2double a1[3], a2[3], a3[3]; @@ -981,21 +982,20 @@ su2double CSlidingMesh::Compute_Triangle_Intersection(su2double* A1, su2double* return ComputeIntersectionArea( a1, a2, a3, b1, b2, b3 ); } -su2double CSlidingMesh::ComputeIntersectionArea(su2double* P1, su2double* P2, su2double* P3, - su2double* Q1, su2double* Q2, su2double* Q3 ){ +su2double CSlidingMesh::ComputeIntersectionArea(const su2double* P1, const su2double* P2, const su2double* P3, + const su2double* Q1, const su2double* Q2, const su2double* Q3) { /* --- This routines computes the area of the polygonal element generated by the superimposition of 2 planar triangle --- */ /* --- The 2 triangle must lie on the same plane --- */ - unsigned short iDim, nPoints, i, j, k; - unsigned short nDim, min_theta_index; + unsigned short iDim, nPoints = 0, i, j, k; + unsigned short min_theta_index; su2double points[16][2], IntersectionPoint[2], theta[6]; su2double TriangleP[4][2], TriangleQ[4][2]; su2double Area, det, dot1, dot2, dtmp, min_theta; - nDim = 2; - nPoints = 0; + constexpr unsigned short nDim = 2; for(iDim = 0; iDim < nDim; iDim++){ TriangleP[0][iDim] = 0; @@ -1139,8 +1139,8 @@ su2double CSlidingMesh::ComputeIntersectionArea(su2double* P1, su2double* P2, su return fabs(Area)/2; } -void CSlidingMesh::ComputeLineIntersectionPoint(su2double* A1, su2double* A2, su2double* B1, su2double* B2, - su2double* IntersectionPoint ){ +void CSlidingMesh::ComputeLineIntersectionPoint(const su2double* A1, const su2double* A2, const su2double* B1, + const su2double* B2, su2double* IntersectionPoint ){ /* --- Uses determinant rule to compute the intersection point between 2 straight segments --- */ /* This works only for lines on a 2D plane, A1, A2 and B1, B2 are respectively the head and the tail points of each segment, @@ -1156,7 +1156,7 @@ void CSlidingMesh::ComputeLineIntersectionPoint(su2double* A1, su2double* A2, su } } -bool CSlidingMesh::CheckPointInsideTriangle(su2double* Point, su2double* T1, su2double* T2, su2double* T3){ +bool CSlidingMesh::CheckPointInsideTriangle(const su2double* Point, const su2double* T1, const su2double* T2, const su2double* T3) { /* --- Check whether a point "Point" lies inside or outside a triangle defined by 3 points "T1", "T2", "T3" --- */ /* For each edge it checks on which side the point lies: @@ -1166,13 +1166,12 @@ bool CSlidingMesh::CheckPointInsideTriangle(su2double* Point, su2double* T1, su2 * - If the check is positive for all the 3 edges, then the point lies within the triangle */ - unsigned short iDim, nDim, check; + unsigned short iDim, check = 0; su2double vect1[2], vect2[2], r[2]; su2double dot; - check = 0; - nDim = 2; + constexpr unsigned short nDim = 2; /* --- Check first edge --- */ diff --git a/Common/src/toolboxes/CSymmetricMatrix.cpp b/Common/src/toolboxes/CSymmetricMatrix.cpp index 8e884d4131ea..8ec0a020ebf7 100644 --- a/Common/src/toolboxes/CSymmetricMatrix.cpp +++ b/Common/src/toolboxes/CSymmetricMatrix.cpp @@ -256,25 +256,12 @@ void CSymmetricMatrix::Invert(const bool is_spd) #endif } -void CSymmetricMatrix::MatVecMult(passivedouble *v) const -{ - passivedouble *tmp_res = new passivedouble [sz]; - - for (int i=0; i(val_vec.data()), + &M, const_cast(mat_in.data()), &N, &beta, mat_out.data(), &N); #endif } /*--- Right_side: mat_out = mat_in * this. ---*/ @@ -324,8 +311,8 @@ void CSymmetricMatrix::MatMatMult(const char side, /*--- Left and lower because matrices are in row major order. ---*/ char side = 'L', uplo = 'L'; passivedouble alpha = 1.0, beta = 0.0; - dsymm_(&side, &uplo, &N, &M, &alpha, val_vec.data(), &N, - mat_in.data(), &N, &beta, mat_out.data(), &N); + dsymm_(&side, &uplo, &N, &M, &alpha, const_cast(val_vec.data()), + &N, const_cast(mat_in.data()), &N, &beta, mat_out.data(), &N); #endif } From 759e8a7e03424995ef1bee2c06abcef1b927de7a Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 19 Mar 2020 19:46:35 +0000 Subject: [PATCH 20/79] more blas 3 optimization of RBF interpolation, some cleanup of CVertex --- Common/include/geometry/dual_grid/CVertex.hpp | 48 ++-- .../interface_interpolation/CInterpolator.hpp | 6 +- .../CRadialBasisFunction.hpp | 37 ++- Common/src/geometry/dual_grid/CVertex.cpp | 60 ++--- .../CIsoparametric.cpp | 15 +- .../src/interface_interpolation/CMirror.cpp | 9 +- .../CNearestNeighbor.cpp | 5 +- .../CRadialBasisFunction.cpp | 233 ++++++++++-------- .../interface_interpolation/CSlidingMesh.cpp | 7 +- Common/src/toolboxes/CSymmetricMatrix.cpp | 32 ++- 10 files changed, 225 insertions(+), 227 deletions(-) diff --git a/Common/include/geometry/dual_grid/CVertex.hpp b/Common/include/geometry/dual_grid/CVertex.hpp index 70bc0dd2492c..084e6e0137ca 100644 --- a/Common/include/geometry/dual_grid/CVertex.hpp +++ b/Common/include/geometry/dual_grid/CVertex.hpp @@ -37,26 +37,25 @@ */ class CVertex : public CDualGrid { protected: - unsigned long *Nodes; /*!< \brief Vector to store the global nodes of an element. */ - su2double *Normal; /*!< \brief Normal coordinates of the element and its center of gravity. */ - su2double Aux_Var; /*!< \brief Auxiliar variable defined only on the surface. */ - su2double CartCoord[3]; /*!< \brief Vertex cartesians coordinates. */ - su2double VarCoord[3]; /*!< \brief Used for storing the coordinate variation due to a surface modification. */ - su2double *VarRot; /*!< \brief Used for storing the rotation variation due to a surface modification. */ - long PeriodicPoint[5]; /*!< \brief Store the periodic point of a boundary (iProcessor, iPoint) */ - bool ActDisk_Perimeter; /*!< \brief Identify nodes at the perimeter of the actuator disk */ - short Rotation_Type; /*!< \brief Type of rotation associated with the vertex (MPI and periodic) */ + unsigned long Nodes[1]; /*!< \brief Vector to store the global nodes of an element. */ + su2double Normal[3]; /*!< \brief Normal coordinates of the element and its center of gravity. */ + su2double Aux_Var; /*!< \brief Auxiliar variable defined only on the surface. */ + su2double CartCoord[3]; /*!< \brief Vertex cartesians coordinates. */ + su2double VarCoord[3]; /*!< \brief Used for storing the coordinate variation due to a surface modification. */ + su2double *VarRot; /*!< \brief Used for storing the rotation variation due to a surface modification. */ + long PeriodicPoint[5]; /*!< \brief Store the periodic point of a boundary (iProcessor, iPoint) */ + bool ActDisk_Perimeter; /*!< \brief Identify nodes at the perimeter of the actuator disk */ + short Rotation_Type; /*!< \brief Type of rotation associated with the vertex (MPI and periodic) */ unsigned long Normal_Neighbor; /*!< \brief Index of the closest neighbor. */ - unsigned long *Donor_Points; /*!< \brief indices of donor points for interpolation across zones */ - unsigned long *Donor_Proc; /*!< \brief indices of donor processor for interpolation across zones in parallel */ - unsigned long Donor_Elem; /*!< \brief Store the donor element for interpolation across zones/ */ - unsigned short Donor_Face; /*!<\brief Store the donor face (w/in donor element) for interpolation across zones */ - su2double Basis_Function[3]; /*!< \brief Basis function values for interpolation across zones. */ - su2double *Donor_Coeff; /*!\brief Store a list of coefficients corresponding to the donor points. */ - unsigned short nDonor_Points; /*!\brief Number of points in Donor_Points; at least there will be one donor point (if the mesh is matching)*/ + unsigned long *Donor_Points; /*!< \brief indices of donor points for interpolation across zones */ + unsigned long *Donor_Proc; /*!< \brief indices of donor processor for interpolation across zones in parallel */ + unsigned long Donor_Elem; /*!< \brief Store the donor element for interpolation across zones/ */ + unsigned short Donor_Face; /*!< \brief Store the donor face (w/in donor element) for interpolation across zones */ + su2double Basis_Function[3]; /*!< \brief Basis function values for interpolation across zones. */ + su2double *Donor_Coeff; /*!< \brief Store a list of coefficients corresponding to the donor points. */ + unsigned short nDonor_Points; /*!< \brief Number of points in Donor_Coeff. */ public: - /*! * \brief Constructor of the class. * \param[in] val_point - Node of the vertex. @@ -358,17 +357,6 @@ class CVertex : public CDualGrid { */ inline unsigned long GetNormal_Neighbor(void) const { return Normal_Neighbor; } - /*! - * \brief Increment the number of donor points by 1. - */ - inline void IncrementnDonor(void) {nDonor_Points++;} - - /*! - * \brief Set the value of nDonor_Points - * \param[in] nDonor - the number of donor points - */ - inline void SetnDonorPoints(unsigned short nDonor) {nDonor_Points = nDonor;} - /*! * \brief Return the value of nDonor_Points * \return nDonor - the number of donor points @@ -419,9 +407,9 @@ class CVertex : public CDualGrid { /*! * \brief Allocate memory based on how many donor points need to be stored. - * Uses nDonor_Points + * \param[in] nDonor - the number of donor points */ - void Allocate_DonorInfo(void); + void Allocate_DonorInfo(unsigned short nDonor); /*! * \brief Get the rotation variation diff --git a/Common/include/interface_interpolation/CInterpolator.hpp b/Common/include/interface_interpolation/CInterpolator.hpp index 1bc27bcb3cd5..6da4e028c4f2 100644 --- a/Common/include/interface_interpolation/CInterpolator.hpp +++ b/Common/include/interface_interpolation/CInterpolator.hpp @@ -55,9 +55,9 @@ class CInterpolator { *Buffer_Receive_nVertex_Donor, /*!< \brief Buffer to store the number of vertices per processor on the Donor domain */ *Buffer_Receive_nFace_Donor, /*!< \brief Buffer to store the number of faces per processor*/ *Buffer_Receive_nFaceNodes_Donor, /*!< \brief Buffer to store the number of nodes associated with faces per processor*/ - *Buffer_Send_nVertex_Donor, /*!< \brief Buffer to send number of vertices on the local processor*/ - *Buffer_Send_nFace_Donor, /*!< \brief Buffer to send number of faces on the local processor*/ - *Buffer_Send_nFaceNodes_Donor, /*!< \brief Buffer to send the number of nodes assocated with faces per processor*/ + Buffer_Send_nVertex_Donor[1], /*!< \brief Buffer to send number of vertices on the local processor*/ + Buffer_Send_nFace_Donor[1], /*!< \brief Buffer to send number of faces on the local processor*/ + Buffer_Send_nFaceNodes_Donor[1], /*!< \brief Buffer to send the number of nodes assocated with faces per processor*/ *Buffer_Send_FaceIndex, /*!< \brief Buffer to send indices pointing to the node indices that define the faces*/ *Buffer_Receive_FaceIndex, /*!< \brief Buffer to receive indices pointing to the node indices that define the faces*/ *Buffer_Send_FaceNodes, /*!< \brief Buffer to send indices pointing to the location of node information in other buffers, defining faces*/ diff --git a/Common/include/interface_interpolation/CRadialBasisFunction.hpp b/Common/include/interface_interpolation/CRadialBasisFunction.hpp index 784ba1b321fd..c5f9cb19e856 100644 --- a/Common/include/interface_interpolation/CRadialBasisFunction.hpp +++ b/Common/include/interface_interpolation/CRadialBasisFunction.hpp @@ -35,6 +35,8 @@ */ class CRadialBasisFunction final : public CInterpolator { public: + static_assert(su2passivematrix::Storage == StorageType::RowMajor, + "This class does not work otherwise."); /*! * \brief Constructor of the class. * \param[in] geometry - Geometrical definition of the problem. @@ -89,12 +91,39 @@ class CRadialBasisFunction final : public CInterpolator { static int CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, su2passivematrix &P); /*! - * \brief Prunes (by setting to zero) small interpolation coefficients, i.e. - * <= tolerance*max(abs(coeffs)). The vector is re-scaled such that sum(coeffs)==1. + * \brief Helper function, prunes (by setting to zero) small interpolation coefficients, + * i.e. <= tolerance*max(abs(coeffs)). The vector is re-scaled such that sum(coeffs)==1. * \param[in] tolerance - Relative pruning tolerance. - * \param[in,out] coeffs - The vector of interpolation coefficients. + * \param[in] size - Size of the coefficient vector. + * \param[in,out] coeffs - Iterator to start of vector of interpolation coefficients. * \return Number of non-zero coefficients after pruning. */ - static int PruneSmallCoefficients(passivedouble tolerance, su2passivevector& coeffs); + template + static Int PruneSmallCoefficients(Float tolerance, Int size, ForwardIt coeffs) { + + /*--- Determine the pruning threshold. ---*/ + Float thresh = 0.0; + auto end = coeffs; + for (Int i = 0; i < size; ++i) + thresh = max(thresh, fabs(*(++end))); + thresh *= tolerance; + + /*--- Prune and count non-zeros. ---*/ + Int numNonZeros = 0; + Float coeffSum = 0.0; + for (auto it = coeffs; it != end; ++it) { + if (fabs(*it) > thresh) { // keep + coeffSum += *it; + ++numNonZeros; + } + else { *it = 0.0; } // prune + } + + /*--- Correct remaining coefficients, sum must be 1 for conservation. ---*/ + Float correction = 1.0 / coeffSum; + for (auto it = coeffs; it != end; ++it) *it *= correction; + + return numNonZeros; + } }; diff --git a/Common/src/geometry/dual_grid/CVertex.cpp b/Common/src/geometry/dual_grid/CVertex.cpp index 4cf14bf19f39..a65c22e63460 100644 --- a/Common/src/geometry/dual_grid/CVertex.cpp +++ b/Common/src/geometry/dual_grid/CVertex.cpp @@ -40,52 +40,35 @@ CVertex::CVertex(unsigned long val_point, unsigned short val_nDim) : CDualGrid(v ActDisk_Perimeter = false; - /*--- Pointers initialization ---*/ - - Nodes = NULL; - Normal = NULL; - - /*--- Allocate node, and face normal ---*/ - - Nodes = new unsigned long[1]; - Normal = new su2double [nDim]; - /*--- Initializate the structure ---*/ Nodes[0] = val_point; - for (iDim = 0; iDim < nDim; iDim ++) - Normal[iDim] = 0.0; + + for (iDim = 0; iDim < 3; iDim ++) Normal[iDim] = 0.0; /*--- Set to zero the variation of the coordinates ---*/ - VarCoord[0] = 0.0; - VarCoord[1] = 0.0; - VarCoord[2] = 0.0; + for (iDim = 0; iDim < 3; iDim ++) VarCoord[iDim] = 0.0; - /*--- Set to NULL variation of the rotation ---*/ + /*--- Set to nullptr variation of the rotation ---*/ - VarRot = NULL; + VarRot = nullptr; - /*--- Set to NULL donor arrays for interpolation ---*/ + /*--- Set to nullptr donor arrays for interpolation ---*/ - Donor_Points = NULL; - Donor_Proc = NULL; - Donor_Coeff = NULL; + Donor_Points = nullptr; + Donor_Proc = nullptr; + Donor_Coeff = nullptr; nDonor_Points = 1; } CVertex::~CVertex() { - if (Normal != NULL) delete[] Normal; - if (Nodes != NULL) delete[] Nodes; - - /*--- donor arrays for interpolation ---*/ - - if (VarRot != NULL) delete[] VarRot; - if (Donor_Coeff != NULL) delete[] Donor_Coeff; - if (Donor_Proc != NULL) delete[] Donor_Proc; - if (Donor_Points != NULL) delete[] Donor_Points; + delete[] VarRot; + delete[] Donor_Coeff; + delete[] Donor_Proc; + delete[] Donor_Points; } @@ -131,13 +114,16 @@ void CVertex::SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_ } -void CVertex::Allocate_DonorInfo(void){ +void CVertex::Allocate_DonorInfo(unsigned short nDonor) { + + nDonor_Points = nDonor; + + delete [] Donor_Points; + delete [] Donor_Proc; + delete [] Donor_Coeff; - if( Donor_Points != NULL ) delete [] Donor_Points; - if( Donor_Proc != NULL ) delete [] Donor_Proc; - if( Donor_Coeff != NULL ) delete [] Donor_Coeff; + Donor_Points = new unsigned long [nDonor_Points]; + Donor_Proc = new unsigned long [nDonor_Points]; + Donor_Coeff = new su2double [nDonor_Points]; - Donor_Points = new unsigned long[nDonor_Points]; - Donor_Proc = new unsigned long[nDonor_Points]; - Donor_Coeff = new su2double[nDonor_Points]; } diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp index 4e46e5f94ee1..d1032f26495b 100644 --- a/Common/src/interface_interpolation/CIsoparametric.cpp +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -77,10 +77,6 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { Coord = new su2double[nDim]; Normal = new su2double[nDim]; - Buffer_Send_nVertex_Donor = new unsigned long [1]; - Buffer_Send_nFace_Donor = new unsigned long [1]; - Buffer_Send_nFaceNodes_Donor = new unsigned long [1]; - Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; Buffer_Receive_nFace_Donor = new unsigned long [nProcessor]; Buffer_Receive_nFaceNodes_Donor = new unsigned long [nProcessor]; @@ -259,7 +255,7 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { /*--- ---*/ nNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1] - - (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; + (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; su2double *X = new su2double[nNodes*(nDim+1)]; faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face @@ -314,7 +310,6 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { /*--- Store info ---*/ donor_elem = temp_donor; target_geometry->vertex[markTarget][iVertex]->SetDonorElem(donor_elem); // in 2D is nearest neighbor - target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nNodes); for (iDonor=0; iDonorvertex[markTarget][iVertex]->GetnDonorPoints(); - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); + target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(nNodes); for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,storeGlobal[iDonor]); @@ -355,10 +350,6 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { delete[] Buffer_Receive_FaceProc; } - delete[] Buffer_Send_nVertex_Donor; - delete[] Buffer_Send_nFace_Donor; - delete[] Buffer_Send_nFaceNodes_Donor; - delete[] Buffer_Receive_nVertex_Donor; delete[] Buffer_Receive_nFace_Donor; delete[] Buffer_Receive_nFaceNodes_Donor; diff --git a/Common/src/interface_interpolation/CMirror.cpp b/Common/src/interface_interpolation/CMirror.cpp index d64d0451811d..089af9eceec1 100644 --- a/Common/src/interface_interpolation/CMirror.cpp +++ b/Common/src/interface_interpolation/CMirror.cpp @@ -39,9 +39,6 @@ void CMirror::Set_TransferCoeff(const CConfig* const* config) { const int nProcessor = size; - Buffer_Send_nFace_Donor= new unsigned long [1]; - Buffer_Send_nFaceNodes_Donor= new unsigned long [1]; - Buffer_Receive_nFace_Donor = new unsigned long [nProcessor]; Buffer_Receive_nFaceNodes_Donor = new unsigned long [nProcessor]; @@ -158,8 +155,7 @@ void CMirror::Set_TransferCoeff(const CConfig* const* config) { } } - target_vertex->SetnDonorPoints(nNodes); - target_vertex->Allocate_DonorInfo(); + target_vertex->Allocate_DonorInfo(nNodes); for (int iProcessor = 0, iDonor = 0; iProcessor < nProcessor; iProcessor++) { for (auto iFace = 0ul; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { @@ -192,9 +188,6 @@ void CMirror::Set_TransferCoeff(const CConfig* const* config) { delete[] Buffer_Receive_Coeff; } - delete[] Buffer_Send_nFace_Donor; - delete[] Buffer_Send_nFaceNodes_Donor; - delete[] Buffer_Receive_nFace_Donor; delete[] Buffer_Receive_nFaceNodes_Donor; diff --git a/Common/src/interface_interpolation/CNearestNeighbor.cpp b/Common/src/interface_interpolation/CNearestNeighbor.cpp index 9d5536e88fe7..3e0a7ee24170 100644 --- a/Common/src/interface_interpolation/CNearestNeighbor.cpp +++ b/Common/src/interface_interpolation/CNearestNeighbor.cpp @@ -56,7 +56,6 @@ void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; const auto nDim = donor_geometry->GetnDim(); - Buffer_Send_nVertex_Donor = new unsigned long [1]; Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; vector > DonorInfoVec(omp_get_max_threads()); @@ -135,8 +134,7 @@ void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { } /*--- Set interpolation coefficients. ---*/ - target_vertex->SetnDonorPoints(nDonor); - target_vertex->Allocate_DonorInfo(); + target_vertex->Allocate_DonorInfo(nDonor); for (auto iDonor = 0ul; iDonor < nDonor; ++iDonor) { target_vertex->SetInterpDonorPoint(iDonor, donorInfo[iDonor].pidx); @@ -154,7 +152,6 @@ void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { } - delete[] Buffer_Send_nVertex_Donor; delete[] Buffer_Receive_nVertex_Donor; } diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp index e25bdbb688d4..f87df1a47460 100644 --- a/Common/src/interface_interpolation/CRadialBasisFunction.cpp +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -30,6 +30,18 @@ #include "../../include/geometry/CGeometry.hpp" #include "../../include/toolboxes/CSymmetricMatrix.hpp" +#if defined(HAVE_MKL) +#include "mkl.h" +#ifndef HAVE_LAPACK +#define HAVE_LAPACK +#endif +#elif defined(HAVE_LAPACK) +// dgemm(opA, opB, m, n, k, alpha, A, lda, B, ldb, beta, C, ldc) +extern "C" void dgemm_(const char*, const char*, const int*, const int*, const int*, + const passivedouble*, const passivedouble*, const int*, const passivedouble*, + const int*, const passivedouble*, passivedouble*, const int*); +#endif + CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { @@ -78,35 +90,35 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { const int nDim = donor_geometry->GetnDim(); const int nProcessor = size; - Buffer_Send_nVertex_Donor = new unsigned long [1]; Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; /*--- Process interface patches in parallel, fetch all donor point coordinates, * then distribute interpolation matrix computation over ranks and threads. * To avoid repeating calls to Collect_VertexInfo we also save the global * indices of the donor points and the mpi rank index that owns them. ---*/ - vector DonorCoordinates(nMarkerInt); - vector > DonorGlobalPoint(nMarkerInt); - vector > DonorProcessor(nMarkerInt); - vector AssignedProcessor(nMarkerInt,-1); - vector TotalWork(nProcessor,0); + + vector donorCoordinates(nMarkerInt); + vector > donorGlobalPoint(nMarkerInt); + vector > donorProcessor(nMarkerInt); + vector assignedProcessor(nMarkerInt,-1); + vector totalWork(nProcessor,0); for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; ++iMarkerInt) { /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ - const auto mark_donor = Find_InterfaceMarker(config[donorZone], iMarkerInt+1); + const auto markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt+1); /*--- On the target side: find the tag of the boundary sharing the interface. ---*/ - const auto mark_target = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); + const auto markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); /*--- If the zone does not contain the interface continue to the next pair of markers. ---*/ - if(!CheckInterfaceBoundary(mark_donor,mark_target)) continue; + if(!CheckInterfaceBoundary(markDonor,markTarget)) continue; unsigned long nVertexDonor = 0; - if(mark_donor != -1) nVertexDonor = donor_geometry->GetnVertex(mark_donor); + if(markDonor != -1) nVertexDonor = donor_geometry->GetnVertex(markDonor); /*--- Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor. ---*/ - Determine_ArraySize(false, mark_donor, mark_target, nVertexDonor, nDim); + Determine_ArraySize(false, markDonor, markTarget, nVertexDonor, nDim); /*--- Compute total number of donor vertices. ---*/ auto nGlobalVertexDonor = accumulate(Buffer_Receive_nVertex_Donor, @@ -118,24 +130,24 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; Buffer_Receive_GlobalPoint = new long [ nProcessor * MaxLocalVertex_Donor ]; - Collect_VertexInfo(false, mark_donor, mark_target, nVertexDonor, nDim); + Collect_VertexInfo(false, markDonor, markTarget, nVertexDonor, nDim); /*--- Compresses the gathered donor point information to simplify computations. ---*/ - auto& DonorCoord = DonorCoordinates[iMarkerInt]; - auto& DonorPoint = DonorGlobalPoint[iMarkerInt]; - auto& DonorProc = DonorProcessor[iMarkerInt]; - DonorCoord.resize(nGlobalVertexDonor, nDim); - DonorPoint.resize(nGlobalVertexDonor); - DonorProc.resize(nGlobalVertexDonor); + auto& donorCoord = donorCoordinates[iMarkerInt]; + auto& donorPoint = donorGlobalPoint[iMarkerInt]; + auto& donorProc = donorProcessor[iMarkerInt]; + donorCoord.resize(nGlobalVertexDonor, nDim); + donorPoint.resize(nGlobalVertexDonor); + donorProc.resize(nGlobalVertexDonor); auto iCount = 0ul; for (int iProcessor = 0; iProcessor < nProcessor; ++iProcessor) { auto offset = iProcessor * MaxLocalVertex_Donor; for (auto iVertex = 0ul; iVertex < Buffer_Receive_nVertex_Donor[iProcessor]; ++iVertex) { for (int iDim = 0; iDim < nDim; ++iDim) - DonorCoord(iCount,iDim) = Buffer_Receive_Coord[(offset+iVertex)*nDim + iDim]; - DonorPoint[iCount] = Buffer_Receive_GlobalPoint[offset+iVertex]; - DonorProc[iCount] = iProcessor; + donorCoord(iCount,iDim) = Buffer_Receive_Coord[(offset+iVertex)*nDim + iDim]; + donorPoint[iCount] = Buffer_Receive_GlobalPoint[offset+iVertex]; + donorProc[iCount] = iProcessor; ++iCount; } } @@ -149,13 +161,14 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { /*--- Static work scheduling over ranks based on which one has less work currently. ---*/ int iProcessor = 0; for (int i = 1; i < nProcessor; ++i) - if (TotalWork[i] < TotalWork[iProcessor]) iProcessor = i; + if (totalWork[i] < totalWork[iProcessor]) iProcessor = i; - TotalWork[iProcessor] += pow(nGlobalVertexDonor,3); // based on matrix inversion. + totalWork[iProcessor] += pow(nGlobalVertexDonor,3); // based on matrix inversion. - AssignedProcessor[iMarkerInt] = iProcessor; + assignedProcessor[iMarkerInt] = iProcessor; } + delete[] Buffer_Receive_nVertex_Donor; /*--- Compute the interpolation matrices for each patch of coordinates * assigned to the rank. Subdivide work further by threads. ---*/ @@ -165,9 +178,9 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { SU2_OMP_PARALLEL_(for schedule(dynamic,1)) for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; ++iMarkerInt) { - if (rank == AssignedProcessor[iMarkerInt]) { + if (rank == assignedProcessor[iMarkerInt]) { ComputeGeneratorMatrix(kindRBF, usePolynomial, paramRBF, - DonorCoordinates[iMarkerInt], nPolynomialVec[iMarkerInt], + donorCoordinates[iMarkerInt], nPolynomialVec[iMarkerInt], keepPolynomialRowVec[iMarkerInt], CinvTrucVec[iMarkerInt]); } } @@ -177,25 +190,25 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; iMarkerInt++) { /*--- Identify the rank that computed the interpolation matrix for this marker. ---*/ - const int iProcessor = AssignedProcessor[iMarkerInt]; + const int iProcessor = assignedProcessor[iMarkerInt]; /*--- If no processor was assigned to work, the zone does not contain the interface. ---*/ if (iProcessor < 0) continue; /*--- Setup target information. ---*/ - const int mark_target = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); + const int markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); unsigned long nVertexTarget = 0; - if(mark_target != -1) nVertexTarget = target_geometry->GetnVertex(mark_target); + if(markTarget != -1) nVertexTarget = target_geometry->GetnVertex(markTarget); /*--- Set references to donor information. ---*/ - auto& DonorCoord = DonorCoordinates[iMarkerInt]; - auto& DonorPoint = DonorGlobalPoint[iMarkerInt]; - auto& DonorProc = DonorProcessor[iMarkerInt]; + auto& donorCoord = donorCoordinates[iMarkerInt]; + auto& donorPoint = donorGlobalPoint[iMarkerInt]; + auto& donorProc = donorProcessor[iMarkerInt]; auto& C_inv_trunc = CinvTrucVec[iMarkerInt]; auto& nPolynomial = nPolynomialVec[iMarkerInt]; auto& keepPolynomialRow = keepPolynomialRowVec[iMarkerInt]; - const auto nGlobalVertexDonor = DonorCoord.rows(); + const auto nGlobalVertexDonor = donorCoord.rows(); #ifdef HAVE_MPI /*--- For simplicity, broadcast small information about the interpolation matrix. ---*/ @@ -221,86 +234,119 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { } #endif - /*--- Compute H (interpolation) matrix, distributing - * target points over the threads in the rank. ---*/ + /*--- Compute interpolation matrix (H). This is a large matrix-matrix product with + * the generator matrix (C_inv_trunc) on the right. We avoid instantiation + * of the entire function matrix (A) and of the result (H), but work + * on a slab (set of rows) of A/H to amortize accesses to C_inv_trunc. ---*/ + + /*--- Fetch domain target vertices. ---*/ + + vector targetVertices; targetVertices.reserve(nVertexTarget); + vector targetCoord; targetCoord.reserve(nVertexTarget); + + for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; ++iVertexTarget) { + + auto targetVertex = target_geometry->vertex[markTarget][iVertexTarget]; + auto pointTarget = targetVertex->GetNode(); + + if (target_geometry->node[pointTarget]->GetDomain()) { + targetVertices.push_back(targetVertex); + targetCoord.push_back(target_geometry->node[pointTarget]->GetCoord()); + } + } + nVertexTarget = targetVertices.size(); + + /*--- Distribute target slabs over the threads in the rank for processing. ---*/ + SU2_OMP_PARALLEL - { - su2passivevector coeff_vec(nGlobalVertexDonor); + if (nVertexTarget > 0) { - SU2_OMP_FOR_DYN(roundUpDiv(nVertexTarget, 2*omp_get_max_threads())) - for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; iVertexTarget++) { + constexpr unsigned long targetSlabSize = 32; - auto target_vertex = target_geometry->vertex[mark_target][iVertexTarget]; - const auto point_target = target_vertex->GetNode(); + su2passivematrix funcMat(targetSlabSize, 1+nPolynomial+nGlobalVertexDonor); + su2passivematrix interpMat(targetSlabSize, nGlobalVertexDonor); - /*--- If not domain point move to next. ---*/ - if (!target_geometry->node[point_target]->GetDomain()) continue; + SU2_OMP_FOR_DYN(1) + for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; iVertexTarget += targetSlabSize) { - const su2double* coord_i = target_geometry->node[point_target]->GetCoord(); + const auto iLastVertex = min(nVertexTarget, iVertexTarget+targetSlabSize); + const auto slabSize = iLastVertex - iVertexTarget; - /*--- Multiply target vector by C_inv_trunc to obtain the interpolation coefficients. - * The target vector is not stored, we consume its entries immediately to avoid - * strided access to C_inv_trunc (as it is row-major). ---*/ + /*--- Prepare matrix of functions A (the targets to donors matrix). ---*/ /*--- Polynominal part: ---*/ if (usePolynomial) { /*--- Constant term. ---*/ - for (auto j = 0ul; j < nGlobalVertexDonor; ++j) - coeff_vec(j) = C_inv_trunc(0,j); + for (auto k = 0ul; k < slabSize; ++k) funcMat(k,0) = 1.0; /*--- Linear terms. ---*/ for (int iDim = 0, idx = 1; iDim < nDim; ++iDim) { /*--- Of which one may have been excluded. ---*/ if (!keepPolynomialRow[iDim]) continue; - for (auto j = 0ul; j < nGlobalVertexDonor; ++j) - coeff_vec(j) += SU2_TYPE::GetValue(coord_i[iDim]) * C_inv_trunc(idx,j); + for (auto k = 0ul; k < slabSize; ++k) + funcMat(k, idx) = SU2_TYPE::GetValue(targetCoord[iVertexTarget+k][iDim]); idx += 1; } } - else { - /*--- Initialize vector to zero. ---*/ - for (auto j = 0ul; j < nGlobalVertexDonor; ++j) coeff_vec(j) = 0.0; - } - /*--- RBF terms: ---*/ for (auto iVertexDonor = 0ul; iVertexDonor < nGlobalVertexDonor; ++iVertexDonor) { - auto w_ij = SU2_TYPE::GetValue(Get_RadialBasisValue(kindRBF, paramRBF, - PointsDistance(nDim, coord_i, DonorCoord[iVertexDonor]))); - - for (auto j = 0ul; j < nGlobalVertexDonor; ++j) - coeff_vec(j) += w_ij * C_inv_trunc(1+nPolynomial+iVertexDonor, j); + for (auto k = 0ul; k < slabSize; ++k) { + auto dist = PointsDistance(nDim, targetCoord[iVertexTarget+k], donorCoord[iVertexDonor]); + auto rbf = Get_RadialBasisValue(kindRBF, paramRBF, dist); + funcMat(k, 1+nPolynomial+iVertexDonor) = SU2_TYPE::GetValue(rbf); + } } - /*--- Prune small coefficients. ---*/ - auto nnz = PruneSmallCoefficients(SU2_TYPE::GetValue(pruneTol), coeff_vec); + /*--- Compute slab of the interpolation matrix. ---*/ +#ifdef HAVE_LAPACK + /*--- interpMat = funcMat * C_inv_trunc, but order of gemm arguments + * is swapped due to row-major storage of su2passivematrix. ---*/ + const char op = 'N'; + const int M = interpMat.cols(), N = slabSize, K = funcMat.cols(); + // lda = C_inv_trunc.cols() = M; ldb = funcMat.cols() = K; ldc = interpMat.cols() = M; + const passivedouble alpha = 1.0, beta = 0.0; + dgemm_(&op, &op, &M, &N, &K, &alpha, C_inv_trunc[0], &M, funcMat[0], &K, &beta, interpMat[0], &M); +#else + /*--- Naive product, loop order considers short-wide + * nature of funcMat and interpMat. ---*/ + interpMat = 0.0; + for (auto k = 0ul; k < funcMat.cols(); ++k) + for (auto i = 0ul; i < slabSize; ++i) + for (auto j = 0ul; j < interpMat.cols(); ++j) + interpMat(i,j) += funcMat(i,k) * C_inv_trunc(k,j); +#endif + /*--- Set interpolation coefficients. ---*/ + + for (auto k = 0ul; k < slabSize; ++k) { + auto targetVertex = targetVertices[iVertexTarget+k]; + + /*--- Prune small coefficients. ---*/ + auto nnz = PruneSmallCoefficients(SU2_TYPE::GetValue(pruneTol), interpMat.cols(), interpMat[k]); - /*--- Allocate and set donor information for this target point. ---*/ - target_vertex->SetnDonorPoints(nnz); - target_vertex->Allocate_DonorInfo(); + /*--- Allocate and set donor information for this target point. ---*/ + targetVertex->Allocate_DonorInfo(nnz); - for (unsigned long iVertex = 0, iSet = 0; iVertex < nGlobalVertexDonor; ++iVertex) { - if (fabs(coeff_vec(iVertex)) > 0.0) { - target_vertex->SetInterpDonorProcessor(iSet, DonorProc[iVertex]); - target_vertex->SetInterpDonorPoint(iSet, DonorPoint[iVertex]); - target_vertex->SetDonorCoeff(iSet, coeff_vec(iVertex)); - ++iSet; + for (unsigned long iVertex = 0, iSet = 0; iVertex < nGlobalVertexDonor; ++iVertex) { + auto coeff = interpMat(k,iVertex); + if (fabs(coeff) > 0.0) { + targetVertex->SetInterpDonorProcessor(iSet, donorProc[iVertex]); + targetVertex->SetInterpDonorPoint(iSet, donorPoint[iVertex]); + targetVertex->SetDonorCoeff(iSet, coeff); + ++iSet; + } } } - } // end target vertex loop } // end SU2_OMP_PARALLEL - /*--- Delete global data that will no longer be used. ---*/ - DonorCoord.resize(0,0); - vector().swap(DonorPoint); - vector().swap(DonorProc); + /*--- Free global data that will no longer be used. ---*/ + donorCoord.resize(0,0); + vector().swap(donorPoint); + vector().swap(donorProc); C_inv_trunc.resize(0,0); } // end loop over interface markers - delete[] Buffer_Send_nVertex_Donor; - delete[] Buffer_Receive_nVertex_Donor; - } void CRadialBasisFunction::ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool usePolynomial, @@ -460,30 +506,3 @@ int CRadialBasisFunction::CheckPolynomialTerms(su2double max_diff_tol, vector thresh) { - coeffSum += coeffs(i); - ++numNonZeros; - } - else coeffs(i) = 0.0; - } - - /*--- Correct remaining coefficients, sum must be 1 for conservation. ---*/ - passivedouble correction = 1.0 / coeffSum; - for (auto i = 0ul; i < coeffs.size(); ++i) coeffs(i) *= correction; - - return numNonZeros; -} diff --git a/Common/src/interface_interpolation/CSlidingMesh.cpp b/Common/src/interface_interpolation/CSlidingMesh.cpp index 2ac685049af6..3fe75ad5c033 100644 --- a/Common/src/interface_interpolation/CSlidingMesh.cpp +++ b/Common/src/interface_interpolation/CSlidingMesh.cpp @@ -412,9 +412,7 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { /*--- Set the communication data structure and copy data from the auxiliary vectors ---*/ - target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nDonorPoints); - - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); + target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(nDonorPoints); for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor, Coeff_Vect[iDonor]); @@ -685,8 +683,7 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { /*--- Set the communication data structure and copy data from the auxiliary vectors ---*/ - target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nDonorPoints); - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); + target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(nDonorPoints); for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor, Coeff_Vect[iDonor]/Area); diff --git a/Common/src/toolboxes/CSymmetricMatrix.cpp b/Common/src/toolboxes/CSymmetricMatrix.cpp index 8ec0a020ebf7..b8eec72c2111 100644 --- a/Common/src/toolboxes/CSymmetricMatrix.cpp +++ b/Common/src/toolboxes/CSymmetricMatrix.cpp @@ -34,15 +34,13 @@ #define HAVE_LAPACK #endif #elif defined(HAVE_LAPACK) -/*--- Lapack / Blas routines used in RBF interpolation. ---*/ -extern "C" void dsptrf_(char*, int*, passivedouble*, int*, int*); -extern "C" void dsptri_(char*, int*, passivedouble*, int*, passivedouble*, int*); -extern "C" void dsytrf_(char*, int*, passivedouble*, int*, int*, passivedouble*, int*, int*); -extern "C" void dsytri_(char*, int*, passivedouble*, int*, int*, passivedouble*, int*); -extern "C" void dpotrf_(char*, int*, passivedouble*, int*, int*); -extern "C" void dpotri_(char*, int*, passivedouble*, int*, int*); -extern "C" void dsymm_(char*, char*, int*, int*, passivedouble*, passivedouble*, int*, - passivedouble*, int*, passivedouble*, passivedouble*, int*); +/*--- Lapack / Blas routines used in CSymmetricMatrix. ---*/ +extern "C" void dsytrf_(const char*, const int*, passivedouble*, const int*, int*, passivedouble*, const int*, int*); +extern "C" void dsytri_(const char*, const int*, passivedouble*, const int*, const int*, passivedouble*, int*); +extern "C" void dpotrf_(const char*, const int*, passivedouble*, const int*, int*); +extern "C" void dpotri_(const char*, const int*, passivedouble*, const int*, int*); +extern "C" void dsymm_(const char*, const char*, const int*, const int*, const passivedouble*, const passivedouble*, + const int*, const passivedouble*, const int*, const passivedouble*, passivedouble*, const int*); #endif @@ -283,10 +281,10 @@ void CSymmetricMatrix::MatMatMult(const char side, val_vec.data(), M, mat_in.data(), N, beta, mat_out.data(), N); #else // BLAS/LAPACK /*--- Right and lower because matrices are in row major order. ---*/ - char side = 'R', uplo = 'L'; - passivedouble alpha = 1.0, beta = 0.0; - dsymm_(&side, &uplo, &N, &M, &alpha, const_cast(val_vec.data()), - &M, const_cast(mat_in.data()), &N, &beta, mat_out.data(), &N); + const char side = 'R', uplo = 'L'; + const passivedouble alpha = 1.0, beta = 0.0; + dsymm_(&side, &uplo, &N, &M, &alpha, val_vec.data(), &M, + mat_in.data(), &N, &beta, mat_out.data(), &N); #endif } /*--- Right_side: mat_out = mat_in * this. ---*/ @@ -309,10 +307,10 @@ void CSymmetricMatrix::MatMatMult(const char side, val_vec.data(), N, mat_in.data(), N, beta, mat_out.data(), N); #else // BLAS/LAPACK /*--- Left and lower because matrices are in row major order. ---*/ - char side = 'L', uplo = 'L'; - passivedouble alpha = 1.0, beta = 0.0; - dsymm_(&side, &uplo, &N, &M, &alpha, const_cast(val_vec.data()), - &N, const_cast(mat_in.data()), &N, &beta, mat_out.data(), &N); + const char side = 'L', uplo = 'L'; + const passivedouble alpha = 1.0, beta = 0.0; + dsymm_(&side, &uplo, &N, &M, &alpha, val_vec.data(), &N, + mat_in.data(), &N, &beta, mat_out.data(), &N); #endif } From 9ef625a042087cfabfc1ca6dd697bb6683c75bca Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 19 Mar 2020 21:28:18 +0000 Subject: [PATCH 21/79] fix deallocation bug in C2DContainer for systems with weird aligned_alloc --- Common/include/toolboxes/C2DContainer.hpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Common/include/toolboxes/C2DContainer.hpp b/Common/include/toolboxes/C2DContainer.hpp index 93f1314766f6..4b3dfcad14f1 100644 --- a/Common/include/toolboxes/C2DContainer.hpp +++ b/Common/include/toolboxes/C2DContainer.hpp @@ -113,15 +113,14 @@ class AccessorImpl \ AccessorImpl& operator= (AccessorImpl&& other) noexcept \ { \ - if(m_data!=nullptr) free(m_data); \ + MemoryAllocation::aligned_free(m_data); \ MOVE; m_data=other.m_data; other.m_data=nullptr; \ return *this; \ } \ \ ~AccessorImpl() \ { \ - if(m_data!=nullptr) \ - MemoryAllocation::aligned_free(m_data); \ + MemoryAllocation::aligned_free(m_data); \ } /*! * Shorthand for when specialization has only one more member than m_data. @@ -381,7 +380,7 @@ class C2DContainer : { /*--- fully static, no allocation needed ---*/ if(StaticRows!=DynamicSize && StaticCols!=DynamicSize) - return StaticRows*StaticCols; + return StaticRows*StaticCols; /*--- dynamic row vector, swap size specification ---*/ if(StaticRows==1 && StaticCols==DynamicSize) {cols = rows; rows = 1;} @@ -400,12 +399,10 @@ class C2DContainer : /*--- compare with current dimensions to determine if deallocation is needed, also makes the container safe against self assignment no need to check for 0 size as the allocators handle that ---*/ - if(m_data!=nullptr) - { - if(rows==this->rows() && cols==this->cols()) - return reqSize; - free(m_data); - } + if(rows==this->rows() && cols==this->cols()) + return reqSize; + + MemoryAllocation::aligned_free(m_data); /*--- request actual allocation to base class as it needs specialization ---*/ size_t bytes = reqSize*sizeof(Scalar_t); From faafa22c194f2037ee0276d8339ae6e46bc3f776 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 19 Mar 2020 21:29:11 +0000 Subject: [PATCH 22/79] more CSymmetricMatrix optimization --- Common/include/toolboxes/CSymmetricMatrix.hpp | 43 ++- .../CRadialBasisFunction.cpp | 8 +- Common/src/toolboxes/CSymmetricMatrix.cpp | 246 ++++++++---------- 3 files changed, 131 insertions(+), 166 deletions(-) diff --git a/Common/include/toolboxes/CSymmetricMatrix.hpp b/Common/include/toolboxes/CSymmetricMatrix.hpp index b32613a864ae..853257dbdf54 100644 --- a/Common/include/toolboxes/CSymmetricMatrix.hpp +++ b/Common/include/toolboxes/CSymmetricMatrix.hpp @@ -37,30 +37,15 @@ using namespace std; * with LAPACK to use optimized matrix inversion and multiplication routines. */ class CSymmetricMatrix { + static_assert(su2passivematrix::Storage == StorageType::RowMajor, + "Row major storage is assumed for LAPACK."); private: - enum DecompositionType { NONE, CHOLESKY, LU }; - - vector val_vec, decomp_vec; - vector perm_vec; - int sz = 0; - bool initialized = false; - DecompositionType decomposed = NONE; - - inline void CheckBounds(int i, int j) const { - assert(initialized && "Matrix not initialized."); - assert(i>=0 && i=0 && j& perm) const; // Matrix inversion using LAPACK routines (LDLT and LLT factorization). void CalcInv_sytri(); void CalcInv_potri(); @@ -71,23 +56,23 @@ class CSymmetricMatrix { void Initialize(int N); - inline int GetSize() const { return sz; } + inline int Size() const { return mat.rows(); } - inline passivedouble Get(int i, int j) const { return val_vec[IdxSym(i,j)]; } + inline passivedouble Get(int i, int j) const { return mat(min(i,j),max(i,j)); } - inline void Set(int i, int j, passivedouble val) { val_vec[IdxSym(i,j)] = val; } + inline void Set(int i, int j, passivedouble val) { mat(min(i,j),max(i,j)) = val; } - inline passivedouble& operator() (int i, int j) { return val_vec[IdxSym(i,j)]; } + inline passivedouble& operator() (int i, int j) { return mat(min(i,j),max(i,j)); } - inline const passivedouble& operator() (int i, int j) const { return val_vec[IdxSym(i,j)]; } + inline const passivedouble& operator() (int i, int j) const { return mat(min(i,j),max(i,j)); } template void MatVecMult(ForwardIt vec_in, ForwardIt vec_out) const { - for (int i = 0; i < sz; ++i) { + for (int i = 0; i < Size(); ++i) { *vec_out = 0.0; auto vec = vec_in; - for (int k = 0; k < sz; ++k) + for (int k = 0; k < Size(); ++k) *vec_out += *(vec++) * Get(i,k); ++vec_out; } @@ -95,6 +80,8 @@ class CSymmetricMatrix { void MatMatMult(const char side, const su2passivematrix& mat_in, su2passivematrix& mat_out) const; - void Invert(const bool is_spd); + void Invert(bool is_spd = false); + + su2passivematrix StealData(); }; diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp index f87df1a47460..ff8d7697ed65 100644 --- a/Common/src/interface_interpolation/CRadialBasisFunction.cpp +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -40,6 +40,7 @@ extern "C" void dgemm_(const char*, const char*, const int*, const int*, const int*, const passivedouble*, const passivedouble*, const int*, const passivedouble*, const int*, const passivedouble*, passivedouble*, const int*); +#define DGEMM dgemm_ #endif @@ -305,7 +306,7 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { const int M = interpMat.cols(), N = slabSize, K = funcMat.cols(); // lda = C_inv_trunc.cols() = M; ldb = funcMat.cols() = K; ldc = interpMat.cols() = M; const passivedouble alpha = 1.0, beta = 0.0; - dgemm_(&op, &op, &M, &N, &K, &alpha, C_inv_trunc[0], &M, funcMat[0], &K, &beta, interpMat[0], &M); + DGEMM(&op, &op, &M, &N, &K, &alpha, C_inv_trunc[0], &M, funcMat[0], &K, &beta, interpMat[0], &M); #else /*--- Naive product, loop order considers short-wide * nature of funcMat and interpMat. ---*/ @@ -427,10 +428,7 @@ void CRadialBasisFunction::ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool us else { /*--- No polynomial term used in the interpolation, C_inv_trunc = M^-1. ---*/ - C_inv_trunc.resize(nVertexDonor, nVertexDonor); - for (auto i = 0ul; i < nVertexDonor; ++i) - for (auto j = 0ul; j < nVertexDonor; ++j) - C_inv_trunc(i,j) = global_M(i,j); + C_inv_trunc = global_M.StealData(); } // end usePolynomial diff --git a/Common/src/toolboxes/CSymmetricMatrix.cpp b/Common/src/toolboxes/CSymmetricMatrix.cpp index b8eec72c2111..f5190a8672e0 100644 --- a/Common/src/toolboxes/CSymmetricMatrix.cpp +++ b/Common/src/toolboxes/CSymmetricMatrix.cpp @@ -41,49 +41,44 @@ extern "C" void dpotrf_(const char*, const int*, passivedouble*, const int*, int extern "C" void dpotri_(const char*, const int*, passivedouble*, const int*, int*); extern "C" void dsymm_(const char*, const char*, const int*, const int*, const passivedouble*, const passivedouble*, const int*, const passivedouble*, const int*, const passivedouble*, passivedouble*, const int*); +#define DSYMM dsymm_ #endif - -void CSymmetricMatrix::Initialize(int N) -{ - sz = N; - val_vec.resize(sz*sz); - initialized = true; -} +void CSymmetricMatrix::Initialize(int N) { mat.resize(N,N); } void CSymmetricMatrix::CholeskyDecompose() { #ifndef HAVE_LAPACK - assert(initialized && "Matrix not initialized."); - - for (int j = 0; j < sz; ++j) { + int j; + for (j = 0; j < Size(); ++j) { passivedouble sum = 0.0; for (int k = 0; k < j; ++k) sum -= pow(Get(j,k), 2); sum += Get(j,j); - assert(sum > 0.0 && "LLT failed, matrix is not SPD."); + if (sum < 0.0) break; // not SPD Set(j, j, sqrt(sum)); - for (int i = j+1; i < sz; ++i) { + for (int i = j+1; i < Size(); ++i) { passivedouble sum = 0.0; for (int k = 0; k < j; ++k) sum -= Get(i,k) * Get(j,k); sum += Get(i,j); Set(i, j, sum / Get(j,j)); } } - decomposed = CHOLESKY; + if (j!=Size()) SU2_MPI::Error("LLT factorization failed.", CURRENT_FUNCTION); #endif } -void CSymmetricMatrix::LUDecompose() +void CSymmetricMatrix::LUDecompose(su2activematrix& decomp, vector& perm) const { #ifndef HAVE_LAPACK - assert(initialized && "Matrix not initialized."); + const int sz = Size(); /*--- Copy matrix values to LU matrix, init permutation vec. ---*/ - decomp_vec.resize(sz*sz); - perm_vec.resize(sz); + decomp.resize(sz,sz); + perm.resize(sz); + for (int i = 0; i < sz; ++i) { - perm_vec[i] = i; + perm[i] = i; for (int j = i; j < sz; ++j) decomp(j,i) = decomp(i,j) = Get(i,j); } @@ -99,7 +94,7 @@ void CSymmetricMatrix::LUDecompose() } if (pivot_idx != j) { - swap(perm_vec[j], perm_vec[pivot_idx]); + swap(perm[j], perm[pivot_idx]); for (int k = 0; k < sz; ++k) swap(decomp(j,k), decomp(pivot_idx,k)); } @@ -111,116 +106,104 @@ void CSymmetricMatrix::LUDecompose() for (int i = j+1; i < sz; ++i) decomp(i,k) -= decomp(j,k)*decomp(i,j); } - - decomposed = LU; #endif } -void CSymmetricMatrix::CalcInv() +void CSymmetricMatrix::CalcInv(bool is_spd) { #ifndef HAVE_LAPACK - assert(initialized && "Matrix not initialized."); - - /*--- Decompose matrix if not done yet. ---*/ - if (decomposed == NONE) { LUDecompose(); } + const int sz = Size(); /*--- Compute inverse from decomposed matrices. ---*/ - switch (decomposed) { - - case CHOLESKY: - { - /*--- Initialize inverse matrix. ---*/ - vector inv(sz*sz, 0.0); - - /*--- Compute L inverse. ---*/ - /*--- Solve smaller and smaller systems. ---*/ - for (int j = 0; j < sz; ++j) { - /*--- Forward substitution. ---*/ - inv[IdxSym(j,j)] = 1.0 / Get(j,j); - - for (int i = j+1; i < sz; ++i) { - passivedouble sum = 0.0; - for (int k = j; k < i; ++k) sum -= Get(i,k) * inv[IdxSym(k,j)]; - inv[IdxSym(i,j)] = sum / Get(i,i); - } - } // L inverse in inv - - /*--- Multiply inversed matrices overwrite val_vec. ---*/ - for (int j = 0; j < sz; ++j) - for (int i = j; i < sz; ++i) { - passivedouble sum = 0.0; - for (int k = i; k < sz; ++k) sum += inv[IdxSym(k,i)] * inv[IdxSym(k,j)]; - Set(i, j, sum); - } - - break; - } - - case LU: - { - /*--- Alias val_vec. ---*/ - vector& inv = val_vec; - - /*--- Invert L and U matrices in place. ---*/ - for (int j = 0; j < sz; ++j) { - inv[IdxFull(j,j)] = 1.0 / decomp(j,j); - - for (int i = j+1; i < sz; ++i) { - inv[IdxFull(i,j)] = -decomp(i,j); - inv[IdxFull(j,i)] = -decomp(j,i) * inv[IdxFull(j,j)]; - - for (int k = j+1; k < i; ++k) { - inv[IdxFull(i,j)] -= decomp(i,k) * inv[IdxFull(k,j)]; - inv[IdxFull(j,i)] -= decomp(k,i) * inv[IdxFull(j,k)]; - } - if (j+1 <= i) inv[IdxFull(j,i)] /= decomp(i,i); - } + if (is_spd) + { + CholeskyDecompose(); + + /*--- Initialize inverse matrix. ---*/ + CSymmetricMatrix inv(sz); + + /*--- Compute L inverse. ---*/ + /*--- Solve smaller and smaller systems. ---*/ + for (int j = 0; j < sz; ++j) { + /*--- Forward substitution. ---*/ + inv(j,j) = 1.0 / Get(j,j); + + for (int i = j+1; i < sz; ++i) { + passivedouble sum = 0.0; + for (int k = j; k < i; ++k) sum -= Get(i,k) * inv(k,j); + inv(i,j) = sum / Get(i,i); } - // inverses in val_vec - - /*--- Multiply U_inv by L_inv, overwrite decomp_vec. ---*/ - for (int i = 0; i < sz; ++i) - for (int j = 0; j < sz; ++j) { - decomp(i,j) = 0.0; - for (int k = max(i,j); k < sz; ++k) - decomp(i,j) += inv[IdxFull(i,k)] * ((k==j)? 1.0 : inv[IdxFull(k,j)]); + } // L inverse in inv + + /*--- Multiply inversed matrices overwrite mat. ---*/ + for (int j = 0; j < sz; ++j) + for (int i = j; i < sz; ++i) { + passivedouble sum = 0.0; + for (int k = i; k < sz; ++k) sum += inv(k,i) * inv(k,j); + Set(i, j, sum); + } + } + else + { + su2passivematrix decomp; + vector perm; + LUDecompose(decomp, perm); + + /*--- Alias mat. ---*/ + auto& inv = mat; + + /*--- Invert L and U matrices in place. ---*/ + for (int j = 0; j < sz; ++j) { + inv(j,j) = 1.0 / decomp(j,j); + + for (int i = j+1; i < sz; ++i) { + inv(i,j) = -decomp(i,j); + inv(j,i) = -decomp(j,i) * inv(j,j); + + for (int k = j+1; k < i; ++k) { + inv(i,j) -= decomp(i,k) * inv(k,j); + inv(j,i) -= decomp(k,i) * inv(j,k); } + if (j+1 <= i) inv(j,i) /= decomp(i,i); + } + } + // inverses in mat - /*--- Permute multiplied matrix to recover A_inv, overwrite val_vec. ---*/ + /*--- Multiply U_inv by L_inv, overwrite decomp_vec. ---*/ + for (int i = 0; i < sz; ++i) for (int j = 0; j < sz; ++j) { - int k = perm_vec[j]; - for (int i = k; i < sz; ++i) Set(i, k, decomp(i,j)); + decomp(i,j) = 0.0; + for (int k = max(i,j); k < sz; ++k) + decomp(i,j) += inv(i,k) * ((k==j)? 1.0 : inv(k,j)); } - /*--- Decomposition no longer needed. ---*/ - vector().swap(decomp_vec); - - break; + /*--- Permute multiplied matrix to recover A_inv, overwrite mat. ---*/ + for (int j = 0; j < sz; ++j) { + int k = perm[j]; + for (int i = k; i < sz; ++i) Set(i, k, decomp(i,j)); } - default: assert(false && "Default (LU) decomposition failed."); } - - decomposed = NONE; #endif } void CSymmetricMatrix::CalcInv_sytri() { #ifdef HAVE_LAPACK - char uplo = 'L'; + const char uplo = 'L'; + const int sz = Size(); int info; - perm_vec.resize(sz); // ipiv array + vector ipiv(sz); /*--- Query the optimum work size. ---*/ int query = -1; passivedouble tmp; - dsytrf_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), &tmp, &query, &info); + dsytrf_(&uplo, &sz, mat.data(), &sz, ipiv.data(), &tmp, &query, &info); query = static_cast(tmp); - decomp_vec.resize(query); // work array + vector work(query); /*--- Factorize and invert. ---*/ - dsytrf_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), decomp_vec.data(), &query, &info); + dsytrf_(&uplo, &sz, mat.data(), &sz, ipiv.data(), work.data(), &query, &info); if (info!=0) SU2_MPI::Error("LDLT factorization failed.", CURRENT_FUNCTION); - dsytri_(&uplo, &sz, val_vec.data(), &sz, perm_vec.data(), decomp_vec.data(), &info); + dsytri_(&uplo, &sz, mat.data(), &sz, ipiv.data(), work.data(), &info); if (info!=0) SU2_MPI::Error("Inversion with LDLT factorization failed.", CURRENT_FUNCTION); decomposed = NONE; @@ -230,12 +213,13 @@ void CSymmetricMatrix::CalcInv_sytri() void CSymmetricMatrix::CalcInv_potri() { #ifdef HAVE_LAPACK - char uplo = 'L'; + const char uplo = 'L'; + const int sz = Size(); int info; - dpotrf_(&uplo, &sz, val_vec.data(), &sz, &info); + dpotrf_(&uplo, &sz, mat.data(), &sz, &info); if (info!=0) SU2_MPI::Error("LLT factorization failed.", CURRENT_FUNCTION); - dpotri_(&uplo, &sz, val_vec.data(), &sz, &info); + dpotri_(&uplo, &sz, mat.data(), &sz, &info); if (info!=0) SU2_MPI::Error("Inversion with LLT factorization failed.", CURRENT_FUNCTION); decomposed = NONE; @@ -248,9 +232,7 @@ void CSymmetricMatrix::Invert(const bool is_spd) if(is_spd) CalcInv_potri(); else CalcInv_sytri(); #else - if(!is_spd) LUDecompose(); - else CholeskyDecompose(); - CalcInv(); + CalcInv(is_spd); #endif } @@ -258,60 +240,58 @@ void CSymmetricMatrix::MatMatMult(const char side, const su2passivematrix& mat_in, su2passivematrix& mat_out) const { - /*--- Assumes row major storage of in/out matrices for LAPACK. ---*/ - static_assert(su2passivematrix::Storage == StorageType::RowMajor,""); - /*--- Left side: mat_out = this * mat_in. ---*/ if (side == 'L' || side == 'l') { - int M = sz, N = mat_in.cols(); + const int M = Size(), N = mat_in.cols(); assert(M == mat_in.rows()); mat_out.resize(M,N); -#if !defined(HAVE_LAPACK) // Naive product +#ifdef HAVE_LAPACK + /*--- Right and lower because matrices are in row major order. ---*/ + const char side = 'R', uplo = 'L'; + const passivedouble alpha = 1.0, beta = 0.0; + DSYMM(&side, &uplo, &N, &M, &alpha, mat.data(), &M, + mat_in.data(), &N, &beta, mat_out.data(), &N); +#else // Naive product for (int i = 0; i < M; ++i) for (int j = 0; j < N; ++j) { mat_out(i,j) = 0.0; for (int k = 0; k < M; ++k) mat_out(i,j) += Get(i,k) * mat_in(k,j); } -#elif defined(HAVE_MKL) - passivedouble alpha = 1.0, beta = 0.0; - cblas_dsymm(CblasRowMajor, CblasLeft, CblasUpper, M, N, alpha, - val_vec.data(), M, mat_in.data(), N, beta, mat_out.data(), N); -#else // BLAS/LAPACK - /*--- Right and lower because matrices are in row major order. ---*/ - const char side = 'R', uplo = 'L'; - const passivedouble alpha = 1.0, beta = 0.0; - dsymm_(&side, &uplo, &N, &M, &alpha, val_vec.data(), &M, - mat_in.data(), &N, &beta, mat_out.data(), &N); #endif } /*--- Right_side: mat_out = mat_in * this. ---*/ else { - int M = mat_in.rows(), N = sz; + const int M = mat_in.rows(), N = Size(); assert(N == mat_in.cols()); mat_out.resize(M,N); -#if !defined(HAVE_LAPACK) // Naive product +#ifdef HAVE_LAPACK + /*--- Left and lower because matrices are in row major order. ---*/ + const char side = 'L', uplo = 'L'; + const passivedouble alpha = 1.0, beta = 0.0; + DSYMM(&side, &uplo, &N, &M, &alpha, mat.data(), &N, + mat_in.data(), &N, &beta, mat_out.data(), &N); +#else // Naive product for (int i = 0; i < M; ++i) for (int j = 0; j < N; ++j) { mat_out(i,j) = 0.0; for (int k = 0; k < N; ++k) mat_out(i,j) += mat_in(i,k) * Get(k,j); } -#elif defined(HAVE_MKL) - passivedouble alpha = 1.0, beta = 0.0; - cblas_dsymm(CblasRowMajor, CblasRight, CblasUpper, M, N, alpha, - val_vec.data(), N, mat_in.data(), N, beta, mat_out.data(), N); -#else // BLAS/LAPACK - /*--- Left and lower because matrices are in row major order. ---*/ - const char side = 'L', uplo = 'L'; - const passivedouble alpha = 1.0, beta = 0.0; - dsymm_(&side, &uplo, &N, &M, &alpha, val_vec.data(), &N, - mat_in.data(), &N, &beta, mat_out.data(), &N); #endif } +} + +su2passivematrix CSymmetricMatrix::StealData() +{ + /*--- Fill lower triangular part. ---*/ + for (int i = 1; i < Size(); ++i) + for (int j = 0; j < i; ++j) + mat(i,j) = mat(j,i); + return move(mat); } From 72da53230a6dffa15b3ecf4b95d2d1e893324f27 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 19 Mar 2020 22:33:22 +0000 Subject: [PATCH 23/79] fix AD build --- Common/include/toolboxes/CSymmetricMatrix.hpp | 2 +- Common/src/toolboxes/CSymmetricMatrix.cpp | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Common/include/toolboxes/CSymmetricMatrix.hpp b/Common/include/toolboxes/CSymmetricMatrix.hpp index 853257dbdf54..bc15264c7049 100644 --- a/Common/include/toolboxes/CSymmetricMatrix.hpp +++ b/Common/include/toolboxes/CSymmetricMatrix.hpp @@ -45,7 +45,7 @@ class CSymmetricMatrix { // Not optimized dense matrix factorization and inversion for portability. void CalcInv(bool is_spd); void CholeskyDecompose(); - void LUDecompose(su2activematrix& decomp, vector& perm) const; + void LUDecompose(su2passivematrix& decomp, vector& perm) const; // Matrix inversion using LAPACK routines (LDLT and LLT factorization). void CalcInv_sytri(); void CalcInv_potri(); diff --git a/Common/src/toolboxes/CSymmetricMatrix.cpp b/Common/src/toolboxes/CSymmetricMatrix.cpp index f5190a8672e0..5845daac5496 100644 --- a/Common/src/toolboxes/CSymmetricMatrix.cpp +++ b/Common/src/toolboxes/CSymmetricMatrix.cpp @@ -68,7 +68,7 @@ void CSymmetricMatrix::CholeskyDecompose() #endif } -void CSymmetricMatrix::LUDecompose(su2activematrix& decomp, vector& perm) const +void CSymmetricMatrix::LUDecompose(su2passivematrix& decomp, vector& perm) const { #ifndef HAVE_LAPACK const int sz = Size(); @@ -205,8 +205,6 @@ void CSymmetricMatrix::CalcInv_sytri() if (info!=0) SU2_MPI::Error("LDLT factorization failed.", CURRENT_FUNCTION); dsytri_(&uplo, &sz, mat.data(), &sz, ipiv.data(), work.data(), &info); if (info!=0) SU2_MPI::Error("Inversion with LDLT factorization failed.", CURRENT_FUNCTION); - - decomposed = NONE; #endif } @@ -221,8 +219,6 @@ void CSymmetricMatrix::CalcInv_potri() if (info!=0) SU2_MPI::Error("LLT factorization failed.", CURRENT_FUNCTION); dpotri_(&uplo, &sz, mat.data(), &sz, &info); if (info!=0) SU2_MPI::Error("Inversion with LLT factorization failed.", CURRENT_FUNCTION); - - decomposed = NONE; #endif } From 6864175cea2601be8cdfccbcbf6e2dbed003be09 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 19 Mar 2020 23:29:26 +0000 Subject: [PATCH 24/79] basic interpolation statistics and error checking --- .../interface_interpolation/CInterpolator.hpp | 7 +++- .../CRadialBasisFunction.hpp | 8 +++++ .../CRadialBasisFunction.cpp | 36 +++++++++++++++++++ SU2_CFD/src/drivers/CDriver.cpp | 16 ++++----- 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/Common/include/interface_interpolation/CInterpolator.hpp b/Common/include/interface_interpolation/CInterpolator.hpp index 6da4e028c4f2..af95221275f0 100644 --- a/Common/include/interface_interpolation/CInterpolator.hpp +++ b/Common/include/interface_interpolation/CInterpolator.hpp @@ -103,7 +103,7 @@ class CInterpolator { CInterpolator(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone); /*! - * \brief No default construction allowed. + * \brief No default construction allowed to force zones and geometry to always be set. */ CInterpolator(void) = delete; @@ -119,6 +119,11 @@ class CInterpolator { */ virtual void Set_TransferCoeff(const CConfig* const* config) = 0; + /*! + * \brief Print information about the interpolation. + */ + virtual void PrintStatistics(void) const { } + /*! * \brief Find the index of the interface marker shared by that zone * \param[in] config - Definition of the particular problem. diff --git a/Common/include/interface_interpolation/CRadialBasisFunction.hpp b/Common/include/interface_interpolation/CRadialBasisFunction.hpp index c5f9cb19e856..01c056ac9b84 100644 --- a/Common/include/interface_interpolation/CRadialBasisFunction.hpp +++ b/Common/include/interface_interpolation/CRadialBasisFunction.hpp @@ -34,6 +34,9 @@ * \brief Radial basis function interpolation. */ class CRadialBasisFunction final : public CInterpolator { +private: + unsigned long MinDonors = 0, AvgDonors = 0, MaxDonors = 0; + public: static_assert(su2passivematrix::Storage == StorageType::RowMajor, "This class does not work otherwise."); @@ -53,6 +56,11 @@ class CRadialBasisFunction final : public CInterpolator { */ void Set_TransferCoeff(const CConfig* const* config) override; + /*! + * \brief Print information about the interpolation. + */ + void PrintStatistics(void) const override; + /*! * \brief Compute the value of a radial basis function, this is static so it can be re-used. * \param[in] type - of radial basis function diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp index ff8d7697ed65..8d503ecaca3c 100644 --- a/Common/src/interface_interpolation/CRadialBasisFunction.cpp +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -49,6 +49,12 @@ CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, con Set_TransferCoeff(config); } +void CRadialBasisFunction::PrintStatistics() const { + if (rank == MASTER_NODE) + cout << "Min / avg / max number of RBF donors per target point: " + << MinDonors << " / " << AvgDonors << " / " << MaxDonors << endl; +} + su2double CRadialBasisFunction::Get_RadialBasisValue(ENUM_RADIALBASIS type, const su2double radius, const su2double dist) { su2double rbf = dist/radius; @@ -188,6 +194,9 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { /*--- Final loop over interface markers to compute the interpolation coefficients. ---*/ + unsigned long totalTargetPoints = 0, totalDonorPoints = 0; + MinDonors = 1<<30; MaxDonors = 0; + for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; iMarkerInt++) { /*--- Identify the rank that computed the interpolation matrix for this marker. ---*/ @@ -256,6 +265,7 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { } } nVertexTarget = targetVertices.size(); + totalTargetPoints += nVertexTarget; /*--- Distribute target slabs over the threads in the rank for processing. ---*/ @@ -267,6 +277,8 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { su2passivematrix funcMat(targetSlabSize, 1+nPolynomial+nGlobalVertexDonor); su2passivematrix interpMat(targetSlabSize, nGlobalVertexDonor); + unsigned long minDonors = 1<<30, maxDonors = 0, totalDonors = 0; + SU2_OMP_FOR_DYN(1) for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; iVertexTarget += targetSlabSize) { @@ -323,6 +335,9 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { /*--- Prune small coefficients. ---*/ auto nnz = PruneSmallCoefficients(SU2_TYPE::GetValue(pruneTol), interpMat.cols(), interpMat[k]); + totalDonors += nnz; + minDonors = min(minDonors, nnz); + maxDonors = max(maxDonors, nnz); /*--- Allocate and set donor information for this target point. ---*/ targetVertex->Allocate_DonorInfo(nnz); @@ -338,6 +353,13 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { } } } // end target vertex loop + + SU2_OMP_CRITICAL + { + totalDonorPoints += totalDonors; + MinDonors = min(MinDonors, minDonors); + MaxDonors = max(MaxDonors, maxDonors); + } } // end SU2_OMP_PARALLEL /*--- Free global data that will no longer be used. ---*/ @@ -348,6 +370,20 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { } // end loop over interface markers + /*--- Final reduction of interpolation statistics. ---*/ + auto Reduce = [](SU2_MPI::Op op, unsigned long &val) { + auto tmp = val; + SU2_MPI::Reduce(&tmp, &val, 1, MPI_UNSIGNED_LONG, op, MASTER_NODE, MPI_COMM_WORLD); + }; + Reduce(MPI_SUM, totalTargetPoints); + Reduce(MPI_SUM, totalDonorPoints); + Reduce(MPI_MIN, MinDonors); + Reduce(MPI_MAX, MaxDonors); + AvgDonors = passivedouble(totalDonorPoints) / totalTargetPoints; + if (MinDonors == 0) + SU2_MPI::Error("One or more target points have no donors, either:\n" + " - The RBF radius is too small.\n" + " - The pruning tolerance is too aggressive.", CURRENT_FUNCTION); } void CRadialBasisFunction::ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool usePolynomial, diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index 0d17063686a1..aec0ab14f9d2 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -100,8 +100,6 @@ CDriver::CDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunica #endif #endif - unsigned short jZone; - SU2_MPI::SetComm(MPICommunicator); rank = SU2_MPI::GetRank(); @@ -149,13 +147,8 @@ CDriver::CDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunica /*--- Allocate transfer and interpolation container --- */ - interface_container[iZone] = new CInterface*[nZone]; - interpolator_container[iZone] = new CInterpolator*[nZone]; - - for (jZone = 0; jZone < nZone; jZone++){ - interface_container[iZone][jZone] = NULL; - interpolator_container[iZone][jZone] = NULL; - } + interface_container[iZone] = new CInterface*[nZone] (); + interpolator_container[iZone] = new CInterpolator*[nZone] (); for (iInst = 0; iInst < nInst[iZone]; iInst++){ @@ -212,7 +205,7 @@ CDriver::CDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunica /*--- Dynamic mesh processing. ---*/ DynamicMesh_Preprocessing(config_container[iZone], geometry_container[iZone][iInst], solver_container[iZone][iInst], - iteration_container[iZone][iInst], grid_movement[iZone][iInst], surface_movement[iZone]); + iteration_container[iZone][iInst], grid_movement[iZone][iInst], surface_movement[iZone]); /*--- Static mesh processing. ---*/ StaticMesh_Preprocessing(config_container[iZone], geometry_container[iZone][iInst], surface_movement[iZone]); @@ -2681,6 +2674,9 @@ void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGe break; } + if (interpolation[donorZone][targetZone]) + interpolation[donorZone][targetZone]->PrintStatistics(); + /*--- Initialize the appropriate transfer strategy ---*/ if (rank == MASTER_NODE) cout << "Transferring "; From f48e235a612b90b273cb331e62578bbca0ba5de5 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Fri, 20 Mar 2020 10:57:32 +0000 Subject: [PATCH 25/79] cleaner computation of RBF polynomial terms --- .../CRadialBasisFunction.hpp | 5 +- .../CRadialBasisFunction.cpp | 99 +++++++++++-------- 2 files changed, 62 insertions(+), 42 deletions(-) diff --git a/Common/include/interface_interpolation/CRadialBasisFunction.hpp b/Common/include/interface_interpolation/CRadialBasisFunction.hpp index 01c056ac9b84..7d75460ea392 100644 --- a/Common/include/interface_interpolation/CRadialBasisFunction.hpp +++ b/Common/include/interface_interpolation/CRadialBasisFunction.hpp @@ -34,12 +34,13 @@ * \brief Radial basis function interpolation. */ class CRadialBasisFunction final : public CInterpolator { + static_assert(su2passivematrix::Storage == StorageType::RowMajor, + "This class relies on row major storage throughout."); private: unsigned long MinDonors = 0, AvgDonors = 0, MaxDonors = 0; + passivedouble Density = 0.0; public: - static_assert(su2passivematrix::Storage == StorageType::RowMajor, - "This class does not work otherwise."); /*! * \brief Constructor of the class. * \param[in] geometry - Geometrical definition of the problem. diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp index 8d503ecaca3c..9bbce09ee271 100644 --- a/Common/src/interface_interpolation/CRadialBasisFunction.cpp +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -50,9 +50,13 @@ CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, con } void CRadialBasisFunction::PrintStatistics() const { - if (rank == MASTER_NODE) - cout << "Min / avg / max number of RBF donors per target point: " - << MinDonors << " / " << AvgDonors << " / " << MaxDonors << endl; + if (rank == MASTER_NODE) { + cout.precision(3); + cout << " Min/avg/max number of RBF donors per target point: " + << MinDonors << "/" << AvgDonors << "/" << MaxDonors + << "\n Interpolation matrix is " << Density << "% dense." << endl; + cout.unsetf(ios::floatfield); + } } su2double CRadialBasisFunction::Get_RadialBasisValue(ENUM_RADIALBASIS type, const su2double radius, const su2double dist) @@ -128,8 +132,8 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { Determine_ArraySize(false, markDonor, markTarget, nVertexDonor, nDim); /*--- Compute total number of donor vertices. ---*/ - auto nGlobalVertexDonor = accumulate(Buffer_Receive_nVertex_Donor, - Buffer_Receive_nVertex_Donor+nProcessor, 0ul); + const auto nGlobalVertexDonor = accumulate(Buffer_Receive_nVertex_Donor, + Buffer_Receive_nVertex_Donor+nProcessor, 0ul); /*--- Gather coordinates and global point indices. ---*/ Buffer_Send_Coord = new su2double [ MaxLocalVertex_Donor * nDim ]; @@ -194,7 +198,8 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { /*--- Final loop over interface markers to compute the interpolation coefficients. ---*/ - unsigned long totalTargetPoints = 0, totalDonorPoints = 0; + /*--- Initialize variables for interpolation statistics. ---*/ + unsigned long totalTargetPoints = 0, totalDonorPoints = 0, denseSize = 0; MinDonors = 1<<30; MaxDonors = 0; for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; iMarkerInt++) { @@ -266,6 +271,7 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { } nVertexTarget = targetVertices.size(); totalTargetPoints += nVertexTarget; + denseSize += nVertexTarget*nGlobalVertexDonor; /*--- Distribute target slabs over the threads in the rank for processing. ---*/ @@ -277,6 +283,7 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { su2passivematrix funcMat(targetSlabSize, 1+nPolynomial+nGlobalVertexDonor); su2passivematrix interpMat(targetSlabSize, nGlobalVertexDonor); + /*--- Thread-local variables for statistics. ---*/ unsigned long minDonors = 1<<30, maxDonors = 0, totalDonors = 0; SU2_OMP_FOR_DYN(1) @@ -370,20 +377,29 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { } // end loop over interface markers - /*--- Final reduction of interpolation statistics. ---*/ + /*--- Final reduction of interpolation statistics and basic sanity checks. ---*/ auto Reduce = [](SU2_MPI::Op op, unsigned long &val) { auto tmp = val; - SU2_MPI::Reduce(&tmp, &val, 1, MPI_UNSIGNED_LONG, op, MASTER_NODE, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&tmp, &val, 1, MPI_UNSIGNED_LONG, op, MPI_COMM_WORLD); }; Reduce(MPI_SUM, totalTargetPoints); Reduce(MPI_SUM, totalDonorPoints); + Reduce(MPI_SUM, denseSize); Reduce(MPI_MIN, MinDonors); Reduce(MPI_MAX, MaxDonors); - AvgDonors = passivedouble(totalDonorPoints) / totalTargetPoints; + + if (totalTargetPoints == 0) + SU2_MPI::Error("Somehow there are no target interpolation points.", CURRENT_FUNCTION); + if (MinDonors == 0) SU2_MPI::Error("One or more target points have no donors, either:\n" + " - The interface surfaces are not in contact.\n" " - The RBF radius is too small.\n" " - The pruning tolerance is too aggressive.", CURRENT_FUNCTION); + + AvgDonors = totalDonorPoints / totalTargetPoints; + Density = totalDonorPoints / (0.01*denseSize); + } void CRadialBasisFunction::ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool usePolynomial, @@ -392,14 +408,14 @@ void CRadialBasisFunction::ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool us const su2double interfaceCoordTol = 1e6 * numeric_limits::epsilon(); - const auto nVertexDonor = coords.rows(); + const int nVertexDonor = coords.rows(); const int nDim = coords.cols(); /*--- Populate interpolation kernel. ---*/ CSymmetricMatrix global_M(nVertexDonor); - for (auto iVertex = 0ul; iVertex < nVertexDonor; ++iVertex) - for (auto jVertex = iVertex; jVertex < nVertexDonor; ++jVertex) + for (int iVertex = 0; iVertex < nVertexDonor; ++iVertex) + for (int jVertex = iVertex; jVertex < nVertexDonor; ++jVertex) global_M(iVertex, jVertex) = SU2_TYPE::GetValue(Get_RadialBasisValue(type, radius, PointsDistance(nDim, coords[iVertex], coords[jVertex]))); @@ -413,7 +429,7 @@ void CRadialBasisFunction::ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool us /*--- Fill P matrix (P for points, with an extra top row of ones). ---*/ su2passivematrix P(1+nDim, nVertexDonor); - for (auto iVertex = 0ul; iVertex < nVertexDonor; iVertex++) { + for (int iVertex = 0; iVertex < nVertexDonor; iVertex++) { P(0, iVertex) = 1.0; for (int iDim = 0; iDim < nDim; ++iDim) P(1+iDim, iVertex) = SU2_TYPE::GetValue(coords(iVertex, iDim)); @@ -422,44 +438,47 @@ void CRadialBasisFunction::ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool us /*--- Check if points lie on a plane and remove one coordinate from P if so. ---*/ nPolynomial = CheckPolynomialTerms(interfaceCoordTol, keepPolynomialRow, P); - /*--- Compute Mp = (P * M^-1 * P^T)^-1 ---*/ - CSymmetricMatrix Mp(nPolynomial+1); + /*--- Compute Q = P * M^-1 ---*/ + su2passivematrix Q; + global_M.MatMatMult('R', P, Q); - su2passivematrix tmp; - global_M.MatMatMult('R', P, tmp); // tmp = P * M^-1 + /*--- Compute Mp = (Q * P^T)^-1 ---*/ + CSymmetricMatrix Mp(nPolynomial+1); - for (int i = 0; i <= nPolynomial; ++i) // Mp = tmp * P + for (int i = 0; i <= nPolynomial; ++i) for (int j = i; j <= nPolynomial; ++j) { Mp(i,j) = 0.0; - for (auto k = 0ul; k < nVertexDonor; ++k) Mp(i,j) += tmp(i,k) * P(j,k); + for (int k = 0; k < nVertexDonor; ++k) + Mp(i,j) += Q(i,k) * P(j,k); } - Mp.Invert(false); // Mp = Mp^-1 + Mp.Invert(false); - /*--- Compute M_p * P * M^-1, the top part of C_inv_trunc. ---*/ - Mp.MatMatMult('L', P, tmp); + /*--- Compute M_p * Q, the top part of C_inv_trunc. ---*/ su2passivematrix C_inv_top; - global_M.MatMatMult('R', tmp, C_inv_top); + Mp.MatMatMult('L', Q, C_inv_top); - /*--- Compute tmp = (I - P^T * M_p * P * M^-1), part of the bottom part of - C_inv_trunc. Note that most of the product is known from the top part. ---*/ - tmp.resize(nVertexDonor, nVertexDonor); - - for (auto i = 0ul; i < nVertexDonor; ++i) { - for (auto j = 0ul; j < nVertexDonor; ++j) { - tmp(i,j) = 0.0; - for (int k = 0; k <= nPolynomial; ++k) tmp(i,j) -= P(k,i) * C_inv_top(k,j); - } - tmp(i,i) += 1.0; // identity part - } - - /*--- Compute M^-1 * (I - P^T * M_p * P * M^-1), finalize bottom of C_inv_trunc. ---*/ - global_M.MatMatMult('L', tmp, C_inv_trunc); + /*--- Compute M^-1 - Q^T * C_inv_top, the bottom (main) part of C_inv_trunc. ---*/ + su2passivematrix C_inv_bot = global_M.StealData(); +#ifdef HAVE_LAPACK + /*--- Order of gemm arguments swapped due to row-major storage. ---*/ + const char opa = 'N', opb = 'T'; + const int M = nVertexDonor, N = nVertexDonor, K = nPolynomial+1; + // lda = C_inv_top.cols() = M; ldb = Q.cols() = M; ldc = C_inv_bot.cols() = M; + const passivedouble alpha = -1.0, beta = 1.0; + DGEMM(&opa, &opb, &M, &N, &K, &alpha, C_inv_top[0], &M, Q[0], &M, &beta, C_inv_bot[0], &M); +#else // naive product + for (int i = 0; i < nVertexDonor; ++i) + for (int j = 0; j < nVertexDonor; ++j) + for (int k = 0; k <= nPolynomial; ++k) + C_inv_bot(i,j) -= Q(k,i) * C_inv_top(k,j); +#endif - /*--- Merge top and bottom of C_inv_trunc. ---*/ - tmp = move(C_inv_trunc); + /*--- Merge top and bottom of C_inv_trunc. More intrusive memory + * management, or separate handling of top and bottom, would + * avoid these copies (and associated temporary vars). ---*/ C_inv_trunc.resize(1+nPolynomial+nVertexDonor, nVertexDonor); memcpy(C_inv_trunc[0], C_inv_top.data(), C_inv_top.size()*sizeof(passivedouble)); - memcpy(C_inv_trunc[1+nPolynomial], tmp.data(), tmp.size()*sizeof(passivedouble)); + memcpy(C_inv_trunc[1+nPolynomial], C_inv_bot.data(), C_inv_bot.size()*sizeof(passivedouble)); } else { /*--- No polynomial term used in the interpolation, C_inv_trunc = M^-1. ---*/ From 2af4b88f841da8e9e904bc8dc0147725b2161bdb Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Fri, 20 Mar 2020 15:59:54 +0000 Subject: [PATCH 26/79] fix bug in pruning of coefficients, more interp stats --- .../CRadialBasisFunction.hpp | 15 ++++---- .../CRadialBasisFunction.cpp | 38 +++++++++++++------ 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/Common/include/interface_interpolation/CRadialBasisFunction.hpp b/Common/include/interface_interpolation/CRadialBasisFunction.hpp index 7d75460ea392..48416ae33053 100644 --- a/Common/include/interface_interpolation/CRadialBasisFunction.hpp +++ b/Common/include/interface_interpolation/CRadialBasisFunction.hpp @@ -38,7 +38,7 @@ class CRadialBasisFunction final : public CInterpolator { "This class relies on row major storage throughout."); private: unsigned long MinDonors = 0, AvgDonors = 0, MaxDonors = 0; - passivedouble Density = 0.0; + passivedouble Density = 0.0, AvgCorrection = 0.0, MaxCorrection = 0.0; public: /*! @@ -99,22 +99,23 @@ class CRadialBasisFunction final : public CInterpolator { */ static int CheckPolynomialTerms(su2double max_diff_tol, vector& keep_row, su2passivematrix &P); +private: /*! * \brief Helper function, prunes (by setting to zero) small interpolation coefficients, * i.e. <= tolerance*max(abs(coeffs)). The vector is re-scaled such that sum(coeffs)==1. * \param[in] tolerance - Relative pruning tolerance. * \param[in] size - Size of the coefficient vector. * \param[in,out] coeffs - Iterator to start of vector of interpolation coefficients. - * \return Number of non-zero coefficients after pruning. + * \return Number of non-zero coefficients after pruning and correction factor. */ - template - static Int PruneSmallCoefficients(Float tolerance, Int size, ForwardIt coeffs) { + template + static pair PruneSmallCoefficients(Float tolerance, Int size, ForwardIt coeffs) { /*--- Determine the pruning threshold. ---*/ Float thresh = 0.0; auto end = coeffs; for (Int i = 0; i < size; ++i) - thresh = max(thresh, fabs(*(++end))); + thresh = max(thresh, fabs(*(end++))); thresh *= tolerance; /*--- Prune and count non-zeros. ---*/ @@ -130,9 +131,9 @@ class CRadialBasisFunction final : public CInterpolator { /*--- Correct remaining coefficients, sum must be 1 for conservation. ---*/ Float correction = 1.0 / coeffSum; - for (auto it = coeffs; it != end; ++it) *it *= correction; + while (coeffs != end) *(coeffs++) *= correction; - return numNonZeros; + return make_pair(numNonZeros, correction); } }; diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp index 9bbce09ee271..7938efb4a364 100644 --- a/Common/src/interface_interpolation/CRadialBasisFunction.cpp +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -50,13 +50,16 @@ CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, con } void CRadialBasisFunction::PrintStatistics() const { - if (rank == MASTER_NODE) { - cout.precision(3); - cout << " Min/avg/max number of RBF donors per target point: " - << MinDonors << "/" << AvgDonors << "/" << MaxDonors - << "\n Interpolation matrix is " << Density << "% dense." << endl; - cout.unsetf(ios::floatfield); - } + if (rank != MASTER_NODE) return; + cout.precision(3); + cout << " Min/avg/max number of RBF donors per target point: " + << MinDonors << "/" << AvgDonors << "/" << MaxDonors << "\n" + << " Avg/max correction factor after pruning: " << AvgCorrection << "/" << MaxCorrection; + if (MaxCorrection < 1.1 || AvgCorrection < 1.02) cout << " (ok)\n"; + else if (MaxCorrection < 2.0 && AvgCorrection < 1.05) cout << " (warning)\n"; + else cout << " <<< WARNING >>>\n"; + cout << " Interpolation matrix is " << Density << "% dense." << endl; + cout.unsetf(ios::floatfield); } su2double CRadialBasisFunction::Get_RadialBasisValue(ENUM_RADIALBASIS type, const su2double radius, const su2double dist) @@ -200,7 +203,7 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { /*--- Initialize variables for interpolation statistics. ---*/ unsigned long totalTargetPoints = 0, totalDonorPoints = 0, denseSize = 0; - MinDonors = 1<<30; MaxDonors = 0; + MinDonors = 1<<30; MaxDonors = 0; MaxCorrection = 0.0; AvgCorrection = 0.0; for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; iMarkerInt++) { @@ -212,7 +215,7 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { /*--- Setup target information. ---*/ const int markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); unsigned long nVertexTarget = 0; - if(markTarget != -1) nVertexTarget = target_geometry->GetnVertex(markTarget); + if (markTarget != -1) nVertexTarget = target_geometry->GetnVertex(markTarget); /*--- Set references to donor information. ---*/ auto& donorCoord = donorCoordinates[iMarkerInt]; @@ -285,6 +288,7 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { /*--- Thread-local variables for statistics. ---*/ unsigned long minDonors = 1<<30, maxDonors = 0, totalDonors = 0; + passivedouble sumCorr = 0.0, maxCorr = 0.0; SU2_OMP_FOR_DYN(1) for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; iVertexTarget += targetSlabSize) { @@ -341,10 +345,14 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { auto targetVertex = targetVertices[iVertexTarget+k]; /*--- Prune small coefficients. ---*/ - auto nnz = PruneSmallCoefficients(SU2_TYPE::GetValue(pruneTol), interpMat.cols(), interpMat[k]); + auto info = PruneSmallCoefficients(SU2_TYPE::GetValue(pruneTol), interpMat.cols(), interpMat[k]); + auto nnz = info.first; totalDonors += nnz; minDonors = min(minDonors, nnz); maxDonors = max(maxDonors, nnz); + auto corr = fabs(info.second-1.0); // far from 1 either way is bad; + sumCorr += corr; + maxCorr = max(maxCorr, corr); /*--- Allocate and set donor information for this target point. ---*/ targetVertex->Allocate_DonorInfo(nnz); @@ -366,6 +374,8 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { totalDonorPoints += totalDonors; MinDonors = min(MinDonors, minDonors); MaxDonors = max(MaxDonors, maxDonors); + AvgCorrection += sumCorr; + MaxCorrection = max(MaxCorrection, maxCorr); } } // end SU2_OMP_PARALLEL @@ -387,7 +397,11 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { Reduce(MPI_SUM, denseSize); Reduce(MPI_MIN, MinDonors); Reduce(MPI_MAX, MaxDonors); - +#ifdef HAVE_MPI + passivedouble tmp1 = AvgCorrection, tmp2 = MaxCorrection; + MPI_Allreduce(&tmp1, &AvgCorrection, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&tmp2, &MaxCorrection, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); +#endif if (totalTargetPoints == 0) SU2_MPI::Error("Somehow there are no target interpolation points.", CURRENT_FUNCTION); @@ -397,6 +411,8 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { " - The RBF radius is too small.\n" " - The pruning tolerance is too aggressive.", CURRENT_FUNCTION); + MaxCorrection += 1.0; // put back the reference "1" + AvgCorrection = AvgCorrection / totalTargetPoints + 1.0; AvgDonors = totalDonorPoints / totalTargetPoints; Density = totalDonorPoints / (0.01*denseSize); From 41598d88a57af0272516176557d376e751ba2df1 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Mon, 23 Mar 2020 12:05:39 +0000 Subject: [PATCH 27/79] some indentation in CConfig --- Common/src/CConfig.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 4f0328015ace..cf65fc655c53 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -935,7 +935,7 @@ void CConfig::SetPointersNull(void) { Kind_SurfaceMovement = NULL; LocationStations = NULL; Motion_Origin = NULL; - Translation_Rate = NULL; + Translation_Rate = NULL; Rotation_Rate = NULL; Pitching_Omega = NULL; Pitching_Ampl = NULL; @@ -943,7 +943,7 @@ void CConfig::SetPointersNull(void) { Plunging_Omega = NULL; Plunging_Ampl = NULL; MarkerMotion_Origin = NULL; - MarkerTranslation_Rate = NULL; + MarkerTranslation_Rate = NULL; MarkerRotation_Rate = NULL; MarkerPitching_Omega = NULL; MarkerPitching_Ampl = NULL; @@ -3827,11 +3827,10 @@ void CConfig::SetPostprocessing(unsigned short val_software, unsigned short val_ /*--- Set number of TurboPerformance markers ---*/ if(GetGrid_Movement() && RampRotatingFrame && !DiscreteAdjoint){ - FinalRotation_Rate_Z = Rotation_Rate[2]; - if(abs(FinalRotation_Rate_Z) > 0.0){ - Rotation_Rate[2] = RampRotatingFrame_Coeff[0]; - } - + FinalRotation_Rate_Z = Rotation_Rate[2]; + if(abs(FinalRotation_Rate_Z) > 0.0){ + Rotation_Rate[2] = RampRotatingFrame_Coeff[0]; + } } if(RampOutletPressure && !DiscreteAdjoint){ From d67df2980e54f873e4d135b86881a9780548b3dd Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Mon, 23 Mar 2020 19:50:48 +0000 Subject: [PATCH 28/79] cleanup CFEAIteration --- SU2_CFD/src/iteration_structure.cpp | 474 +++++++++++++--------------- 1 file changed, 212 insertions(+), 262 deletions(-) diff --git a/SU2_CFD/src/iteration_structure.cpp b/SU2_CFD/src/iteration_structure.cpp index 353816cac7d2..b4f1e6615d67 100644 --- a/SU2_CFD/src/iteration_structure.cpp +++ b/SU2_CFD/src/iteration_structure.cpp @@ -1308,17 +1308,16 @@ CFEAIteration::CFEAIteration(CConfig *config) : CIteration(config) { } CFEAIteration::~CFEAIteration(void) { } void CFEAIteration::Preprocess() { } void CFEAIteration::Iterate(COutput *output, - CIntegration ****integration, - CGeometry ****geometry, - CSolver *****solver, - CNumerics ******numerics, - CConfig **config, - CSurfaceMovement **surface_movement, - CVolumetricMovement ***grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone, - unsigned short val_iInst - ) { + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { su2double loadIncrement; unsigned long IntIter = 0; @@ -1327,227 +1326,176 @@ void CFEAIteration::Iterate(COutput *output, unsigned long iIncrement; unsigned long nIncrements = config[val_iZone]->GetNumberIncrements(); - bool nonlinear = (config[val_iZone]->GetGeometricConditions() == LARGE_DEFORMATIONS); // Geometrically non-linear problems - bool linear = (config[val_iZone]->GetGeometricConditions() == SMALL_DEFORMATIONS); // Geometrically non-linear problems - + bool nonlinear = (config[val_iZone]->GetGeometricConditions() == LARGE_DEFORMATIONS); + bool linear = (config[val_iZone]->GetGeometricConditions() == SMALL_DEFORMATIONS); bool disc_adj_fem = (config[val_iZone]->GetKind_Solver() == DISC_ADJ_FEM); + bool incremental_load = config[val_iZone]->GetIncrementalLoad(); // Loads applied in steps - bool incremental_load = config[val_iZone]->GetIncrementalLoad(); // If an incremental load is applied - - /*--- This is to prevent problems when running a linear solver ---*/ - if (!nonlinear) incremental_load = false; + CIntegration* feaIntegration = integration[val_iZone][val_iInst][FEA_SOL]; + CSolver* feaSolver = solver[val_iZone][val_iInst][MESH_0][FEA_SOL]; /*--- Set the convergence monitor to false, to prevent the solver to stop in intermediate FSI subiterations ---*/ - integration[val_iZone][val_iInst][FEA_SOL]->SetConvergence(false); + feaIntegration->SetConvergence(false); + + /*--- FEA equations ---*/ + config[val_iZone]->SetGlobalParam(FEM_ELASTICITY, RUNTIME_FEA_SYS); if (linear) { config[val_iZone]->SetInnerIter(0); - /*--- FEA equations ---*/ - - config[val_iZone]->SetGlobalParam(FEM_ELASTICITY, RUNTIME_FEA_SYS); - /*--- Run the iteration ---*/ - integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, - config, RUNTIME_FEA_SYS, val_iZone, val_iInst); + feaIntegration->Structural_Iteration(geometry, solver, numerics, config, + RUNTIME_FEA_SYS, val_iZone, val_iInst); - if (!disc_adj_fem){ - Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + if (!disc_adj_fem) { + Monitor(output, integration, geometry, solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); /*--- Set the convergence monitor to true, to prevent the solver to stop in intermediate FSI subiterations ---*/ output->SetConvergence(true); } } - /*--- If the structure is held static and the solver is nonlinear, we don't need to solve for static time, but we need to compute Mass Matrix and Integration constants ---*/ - else if (nonlinear) { + else if (nonlinear && !incremental_load) { /*--- THIS IS THE DIRECT APPROACH (NO INCREMENTAL LOAD APPLIED) ---*/ - if (!incremental_load) { - - /*--- Keep the current inner iter, we need to restore it in discrete adjoint cases as file output depends on it ---*/ - unsigned long CurIter = config[val_iZone]->GetInnerIter(); - - IntIter = 0; - config[val_iZone]->SetInnerIter(IntIter); - - /*--- FEA equations ---*/ + /*--- Keep the current inner iter, we need to restore it in discrete adjoint cases as file output depends on it ---*/ + const auto CurIter = config[val_iZone]->GetInnerIter(); - config[val_iZone]->SetGlobalParam(FEM_ELASTICITY, RUNTIME_FEA_SYS); - - /*--- Run the iteration ---*/ - - integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, - config, RUNTIME_FEA_SYS, val_iZone, val_iInst); - - if (!disc_adj_fem) - Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); - - /*----------------- If the solver is non-linear, we need to subiterate using a Newton-Raphson approach ----------------------*/ - - for (IntIter = 1; IntIter < config[val_iZone]->GetnInner_Iter(); IntIter++) { - - /*--- Limit to only one iteration for the discrete adjoint recording, restore inner iter (see above) ---*/ - if (disc_adj_fem) { - config[val_iZone]->SetInnerIter(CurIter); - break; - } - - config[val_iZone]->SetInnerIter(IntIter); + /*--- Newton-Raphson subiterations ---*/ - integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, - config, RUNTIME_FEA_SYS, val_iZone, val_iInst); - - StopCalc = Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + for (IntIter = 0; IntIter < config[val_iZone]->GetnInner_Iter(); IntIter++) { + config[val_iZone]->SetInnerIter(IntIter); - if (StopCalc) break; + feaIntegration->Structural_Iteration(geometry, solver, numerics, config, + RUNTIME_FEA_SYS, val_iZone, val_iInst); + /*--- Limit to only one iteration for the discrete adjoint recording, restore inner iter (see above) ---*/ + if (disc_adj_fem) { + config[val_iZone]->SetInnerIter(CurIter); + break; } + else { + StopCalc = Monitor(output, integration, geometry, solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + if (StopCalc && (IntIter > 0)) break; + } } - /*--- The incremental load is only used in nonlinear cases ---*/ - else if (incremental_load) { - /*--- Set the initial condition: store the current solution as Solution_Old ---*/ + } + else { + + /*--- THIS IS THE INCREMENTAL LOAD APPROACH (only makes sense for nonlinear) ---*/ - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->SetInitialCondition(geometry[val_iZone][val_iInst], solver[val_iZone][val_iInst], config[val_iZone], TimeIter); + /*--- Set the initial condition: store the current solution as Solution_Old ---*/ - /*--- The load increment is 1.0 ---*/ + feaSolver->SetInitialCondition(geometry[val_iZone][val_iInst], + solver[val_iZone][val_iInst], config[val_iZone], TimeIter); - loadIncrement = 1.0; - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->SetLoad_Increment(loadIncrement); - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->SetForceCoeff(loadIncrement); + /*--- Assume the initial load increment as 1.0 ---*/ - /*--- Set the value of the internal iteration ---*/ + loadIncrement = 1.0; + feaSolver->SetLoad_Increment(loadIncrement); + feaSolver->SetForceCoeff(loadIncrement); + + /*--- Run two nonlinear iterations to check if incremental loading can be skipped ---*/ + + for (IntIter = 0; IntIter < 2; ++IntIter) { - IntIter = 0; config[val_iZone]->SetInnerIter(IntIter); - /*--- FEA equations ---*/ - - config[val_iZone]->SetGlobalParam(FEM_ELASTICITY, RUNTIME_FEA_SYS); - /*--- Run the first iteration ---*/ - integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, - config, RUNTIME_FEA_SYS, val_iZone, val_iInst); - - /*--- Write the convergence history (first, compute Von Mises stress) ---*/ - - Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + feaIntegration->Structural_Iteration(geometry, solver, numerics, config, + RUNTIME_FEA_SYS, val_iZone, val_iInst); - /*--- Run the second iteration ---*/ - - IntIter = 1; - config[val_iZone]->SetInnerIter(IntIter); + /*--- Write the convergence history (first computes Von Mises stress) ---*/ - integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, - config, RUNTIME_FEA_SYS, val_iZone, val_iInst); + Monitor(output, integration, geometry, solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + } - /*--- Write the convergence history (first, compute Von Mises stress) ---*/ - Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + bool meetCriteria; + su2double Residual_UTOL, Residual_RTOL, Residual_ETOL; + su2double Criteria_UTOL, Criteria_RTOL, Criteria_ETOL; - bool meetCriteria; - su2double Residual_UTOL, Residual_RTOL, Residual_ETOL; - su2double Criteria_UTOL, Criteria_RTOL, Criteria_ETOL; + Criteria_UTOL = config[val_iZone]->GetIncLoad_Criteria(0); + Criteria_RTOL = config[val_iZone]->GetIncLoad_Criteria(1); + Criteria_ETOL = config[val_iZone]->GetIncLoad_Criteria(2); - Criteria_UTOL = config[val_iZone]->GetIncLoad_Criteria(0); - Criteria_RTOL = config[val_iZone]->GetIncLoad_Criteria(1); - Criteria_ETOL = config[val_iZone]->GetIncLoad_Criteria(2); + Residual_UTOL = log10(feaSolver->LinSysSol.norm()); + Residual_RTOL = log10(feaSolver->LinSysRes.norm()); + Residual_ETOL = log10(feaSolver->LinSysSol.dot(feaSolver->LinSysRes)); - Residual_UTOL = log10(solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->LinSysSol.norm()); - Residual_RTOL = log10(solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->LinSysRes.norm()); - Residual_ETOL = log10(solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->LinSysSol.dot( - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->LinSysRes)); + meetCriteria = ( ( Residual_UTOL < Criteria_UTOL ) && + ( Residual_RTOL < Criteria_RTOL ) && + ( Residual_ETOL < Criteria_ETOL ) ); - meetCriteria = ( ( Residual_UTOL < Criteria_UTOL ) && - ( Residual_RTOL < Criteria_RTOL ) && - ( Residual_ETOL < Criteria_ETOL ) ); + /*--- If the criteria is met, i.e. the load is not "too big", continue the regular calculation ---*/ - /*--- If the criteria is met and the load is not "too big", do the regular calculation ---*/ - if (meetCriteria) { + if (meetCriteria) { - for (IntIter = 2; IntIter < config[val_iZone]->GetnInner_Iter(); IntIter++) { + /*--- Newton-Raphson subiterations ---*/ - integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, - config, RUNTIME_FEA_SYS, val_iZone, val_iInst); + for (IntIter = 2; IntIter < config[val_iZone]->GetnInner_Iter(); IntIter++) { - /*--- Write the convergence history (first, compute Von Mises stress) ---*/ - StopCalc = Monitor(output, integration, geometry, solver, numerics, config, - surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + config[val_iZone]->SetInnerIter(IntIter); - if (StopCalc) break; + feaIntegration->Structural_Iteration(geometry, solver, numerics, config, + RUNTIME_FEA_SYS, val_iZone, val_iInst); - } + StopCalc = Monitor(output, integration, geometry, solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + if (StopCalc) break; } - /*--- If the criteria is not met, a whole set of subiterations for the different loads must be done ---*/ + } - else { + /*--- If the criteria is not met, a whole set of subiterations for the different loads must be done ---*/ - /*--- Here we have to restart the solution to the original one of the iteration ---*/ - /*--- Retrieve the Solution_Old as the current solution before subiterating ---*/ + else { - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->ResetInitialCondition(geometry[val_iZone][val_iInst], - solver[val_iZone][val_iInst], config[val_iZone], TimeIter); + /*--- Here we have to restore the solution to the one before testing the criteria ---*/ + /*--- Retrieve the Solution_Old as the current solution before subiterating ---*/ - /*--- For the number of increments ---*/ - for (iIncrement = 0; iIncrement < nIncrements; iIncrement++) { + feaSolver->ResetInitialCondition(geometry[val_iZone][val_iInst], + solver[val_iZone][val_iInst], config[val_iZone], TimeIter); - loadIncrement = (iIncrement + 1.0) * (1.0 / nIncrements); + /*--- For the number of increments ---*/ + for (iIncrement = 0; iIncrement < nIncrements; iIncrement++) { - /*--- Set the load increment and the initial condition, and output the parameters of UTOL, RTOL, ETOL for the previous iteration ---*/ + /*--- Set the load increment and the initial condition, and output the + * parameters of UTOL, RTOL, ETOL for the previous iteration ---*/ - /*--- Set the convergence monitor to false, to force se solver to converge every subiteration ---*/ - output->SetConvergence(false); + loadIncrement = (iIncrement + 1.0) * (1.0 / nIncrements); + feaSolver->SetLoad_Increment(loadIncrement); - /*--- FEA equations ---*/ + /*--- Set the convergence monitor to false, to force the solver to converge every subiteration ---*/ + output->SetConvergence(false); - config[val_iZone]->SetGlobalParam(FEM_ELASTICITY, RUNTIME_FEA_SYS); + if (rank == MASTER_NODE) + cout << "\nIncremental load: increment " << iIncrement + 1 << endl; - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->SetLoad_Increment(loadIncrement); + /*--- Newton-Raphson subiterations ---*/ - if (rank == MASTER_NODE) { - cout << endl; - cout << "Incremental load: increment " << iIncrement + 1 << endl; - } + for (IntIter = 0; IntIter < config[val_iZone]->GetnInner_Iter(); IntIter++) { - /*--- Set the value of the internal iteration ---*/ - IntIter = 0; config[val_iZone]->SetInnerIter(IntIter); - /*--- FEA equations ---*/ - - config[val_iZone]->SetGlobalParam(FEM_ELASTICITY, RUNTIME_FEA_SYS); - - /*--- Run the iteration ---*/ - - integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, - config, RUNTIME_FEA_SYS, val_iZone, val_iInst); - - Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); - - - /*----------------- If the solver is non-linear, we need to subiterate using a Newton-Raphson approach ----------------------*/ - - for (IntIter = 1; IntIter < config[val_iZone]->GetnInner_Iter(); IntIter++) { - - config[val_iZone]->SetInnerIter(IntIter); - - integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, - config, RUNTIME_FEA_SYS, val_iZone, val_iInst); + feaIntegration->Structural_Iteration(geometry, solver, numerics, config, + RUNTIME_FEA_SYS, val_iZone, val_iInst); - /*--- Write the convergence history (first, compute Von Mises stress) ---*/ - StopCalc = Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); - - if (StopCalc) break; + /*--- Write the convergence history (first, compute Von Mises stress) ---*/ + StopCalc = Monitor(output, integration, geometry, solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); - } + if (StopCalc && (IntIter > 0)) break; } @@ -1559,59 +1507,66 @@ void CFEAIteration::Iterate(COutput *output, /*--- Finally, we need to compute the objective function, in case that we are running a discrete adjoint solver... ---*/ - switch (config[val_iZone]->GetKind_ObjFunc()){ + switch (config[val_iZone]->GetKind_ObjFunc()) { case REFERENCE_GEOMETRY: - if ((config[val_iZone]->GetDV_FEA() == YOUNG_MODULUS) || (config[val_iZone]->GetDV_FEA() == DENSITY_VAL)){ - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Stiffness_Penalty(geometry[val_iZone][val_iInst][MESH_0],solver[val_iZone][val_iInst][MESH_0], - numerics[val_iZone][val_iInst][MESH_0][FEA_SOL], config[val_iZone]); + if ((config[val_iZone]->GetDV_FEA() == YOUNG_MODULUS) || (config[val_iZone]->GetDV_FEA() == DENSITY_VAL)) { + feaSolver->Stiffness_Penalty(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0], + numerics[val_iZone][val_iInst][MESH_0][FEA_SOL], config[val_iZone]); } - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Compute_OFRefGeom(geometry[val_iZone][val_iInst][MESH_0],solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); + feaSolver->Compute_OFRefGeom(geometry[val_iZone][val_iInst][MESH_0], + solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); break; case REFERENCE_NODE: - if ((config[val_iZone]->GetDV_FEA() == YOUNG_MODULUS) || (config[val_iZone]->GetDV_FEA() == DENSITY_VAL)){ - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Stiffness_Penalty(geometry[val_iZone][val_iInst][MESH_0],solver[val_iZone][val_iInst][MESH_0], - numerics[val_iZone][val_iInst][MESH_0][FEA_SOL], config[val_iZone]); + if ((config[val_iZone]->GetDV_FEA() == YOUNG_MODULUS) || (config[val_iZone]->GetDV_FEA() == DENSITY_VAL)) { + feaSolver->Stiffness_Penalty(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0], + numerics[val_iZone][val_iInst][MESH_0][FEA_SOL], config[val_iZone]); } - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Compute_OFRefNode(geometry[val_iZone][val_iInst][MESH_0],solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); + feaSolver->Compute_OFRefNode(geometry[val_iZone][val_iInst][MESH_0], + solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); break; case VOLUME_FRACTION: case TOPOL_DISCRETENESS: - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Compute_OFVolFrac(geometry[val_iZone][val_iInst][MESH_0],solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); + feaSolver->Compute_OFVolFrac(geometry[val_iZone][val_iInst][MESH_0], + solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); break; case TOPOL_COMPLIANCE: - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Compute_OFCompliance(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); + feaSolver->Compute_OFCompliance(geometry[val_iZone][val_iInst][MESH_0], + solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); break; } } void CFEAIteration::Update(COutput *output, - CIntegration ****integration, - CGeometry ****geometry, - CSolver *****solver, - CNumerics ******numerics, - CConfig **config, - CSurfaceMovement **surface_movement, - CVolumetricMovement ***grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone, - unsigned short val_iInst) { + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { su2double Physical_dt, Physical_t; - unsigned long TimeIter = config[val_iZone]->GetTimeIter(); - bool dynamic = (config[val_iZone]->GetTime_Domain()); // Dynamic problems - bool static_fem = (!config[val_iZone]->GetTime_Domain()); // Static problems - bool fsi = config[val_iZone]->GetFSI_Simulation(); // Fluid-Structure Interaction problems + unsigned long TimeIter = config[val_iZone]->GetTimeIter(); + bool dynamic = (config[val_iZone]->GetTime_Domain()); // Dynamic problems + bool fsi = config[val_iZone]->GetFSI_Simulation(); // Fluid-Structure Interaction problems + + CSolver* feaSolver = solver[val_iZone][val_iInst][MESH_0][FEA_SOL]; /*----------------- Compute averaged nodal stress and reactions ------------------------*/ - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Compute_NodalStress(geometry[val_iZone][val_iInst][MESH_0], numerics[val_iZone][val_iInst][MESH_0][FEA_SOL], config[val_iZone]); + feaSolver->Compute_NodalStress(geometry[val_iZone][val_iInst][MESH_0], + numerics[val_iZone][val_iInst][MESH_0][FEA_SOL], config[val_iZone]); /*----------------- Update structural solver ----------------------*/ if (dynamic) { - integration[val_iZone][val_iInst][FEA_SOL]->SetStructural_Solver(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0], config[val_iZone], MESH_0); + integration[val_iZone][val_iInst][FEA_SOL]->SetStructural_Solver(geometry[val_iZone][val_iInst][MESH_0], + solver[val_iZone][val_iInst][MESH_0], config[val_iZone], MESH_0); integration[val_iZone][val_iInst][FEA_SOL]->SetConvergence(false); /*--- Verify convergence criteria (based on total time) ---*/ @@ -1621,87 +1576,84 @@ void CFEAIteration::Update(COutput *output, if (Physical_t >= config[val_iZone]->GetTotal_DynTime()) integration[val_iZone][val_iInst][FEA_SOL]->SetConvergence(true); - } else if ( static_fem && fsi) { + } else if (fsi) { /*--- For FSI problems, output the relaxed result, which is the one transferred into the fluid domain (for restart purposes) ---*/ - switch (config[val_iZone]->GetKind_TimeIntScheme_FEA()) { - case (NEWMARK_IMPLICIT): - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->ImplicitNewmark_Relaxation(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); - break; + if (config[val_iZone]->GetKind_TimeIntScheme_FEA() == NEWMARK_IMPLICIT) { + feaSolver->ImplicitNewmark_Relaxation(geometry[val_iZone][val_iInst][MESH_0], + solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); } } } void CFEAIteration::Predictor(COutput *output, - CIntegration ****integration, - CGeometry ****geometry, - CSolver *****solver, - CNumerics ******numerics, - CConfig **config, - CSurfaceMovement **surface_movement, - CVolumetricMovement ***grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone, - unsigned short val_iInst) { - + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + CSolver* feaSolver = solver[val_iZone][val_iInst][MESH_0][FEA_SOL]; + /*--- Predict displacements ---*/ - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->PredictStruct_Displacement(geometry[val_iZone][val_iInst], config[val_iZone], - solver[val_iZone][val_iInst]); + feaSolver->PredictStruct_Displacement(geometry[val_iZone][val_iInst], config[val_iZone], solver[val_iZone][val_iInst]); /*--- For parallel simulations we need to communicate the predicted solution before updating the fluid mesh ---*/ - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->InitiateComms(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone], SOLUTION_PRED); - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->CompleteComms(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone], SOLUTION_PRED); + feaSolver->InitiateComms(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone], SOLUTION_PRED); + feaSolver->CompleteComms(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone], SOLUTION_PRED); } void CFEAIteration::Relaxation(COutput *output, - CIntegration ****integration, - CGeometry ****geometry, - CSolver *****solver, - CNumerics ******numerics, - CConfig **config, - CSurfaceMovement **surface_movement, - CVolumetricMovement ***grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone, - unsigned short val_iInst) { - - unsigned long OuterIter = config[val_iZone]->GetOuterIter(); + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + CSolver* feaSolver = solver[val_iZone][val_iInst][MESH_0][FEA_SOL]; /*-------------------- Aitken's relaxation ------------------------*/ /*------------------- Compute the coefficient ---------------------*/ - solver[val_iZone][INST_0][MESH_0][FEA_SOL]->ComputeAitken_Coefficient(geometry[val_iZone][INST_0], config[val_iZone], - solver[val_iZone][INST_0], OuterIter); + feaSolver->ComputeAitken_Coefficient(geometry[val_iZone][INST_0], config[val_iZone], + solver[val_iZone][INST_0], config[val_iZone]->GetOuterIter()); /*----------------- Set the relaxation parameter ------------------*/ - solver[val_iZone][INST_0][MESH_0][FEA_SOL]->SetAitken_Relaxation(geometry[val_iZone][INST_0], config[val_iZone], - solver[val_iZone][INST_0]); + feaSolver->SetAitken_Relaxation(geometry[val_iZone][INST_0], config[val_iZone], solver[val_iZone][INST_0]); /*----------------- Communicate the predicted solution and the old one ------------------*/ - solver[val_iZone][INST_0][MESH_0][FEA_SOL]->InitiateComms(geometry[val_iZone][INST_0][MESH_0], config[val_iZone], SOLUTION_PRED_OLD); - solver[val_iZone][INST_0][MESH_0][FEA_SOL]->CompleteComms(geometry[val_iZone][INST_0][MESH_0], config[val_iZone], SOLUTION_PRED_OLD); + feaSolver->InitiateComms(geometry[val_iZone][INST_0][MESH_0], config[val_iZone], SOLUTION_PRED_OLD); + feaSolver->CompleteComms(geometry[val_iZone][INST_0][MESH_0], config[val_iZone], SOLUTION_PRED_OLD); } bool CFEAIteration::Monitor(COutput *output, - CIntegration ****integration, - CGeometry ****geometry, - CSolver *****solver, - CNumerics ******numerics, - CConfig **config, - CSurfaceMovement **surface_movement, - CVolumetricMovement ***grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone, - unsigned short val_iInst) { - - bool StopCalc = false; + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { #ifndef HAVE_MPI StopTime = su2double(clock())/su2double(CLOCKS_PER_SEC); @@ -1711,32 +1663,20 @@ bool CFEAIteration::Monitor(COutput *output, UsedTime = StopTime - StartTime; solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Compute_NodalStress(geometry[val_iZone][val_iInst][MESH_0], - numerics[val_iZone][val_iInst][MESH_0][FEA_SOL], config[val_iZone]); + numerics[val_iZone][val_iInst][MESH_0][FEA_SOL], + config[val_iZone]); if (config[val_iZone]->GetMultizone_Problem() || config[val_iZone]->GetSinglezone_Driver()){ - output->SetHistory_Output(geometry[val_iZone][INST_0][MESH_0], solver[val_iZone][INST_0][MESH_0], config[val_iZone], - config[val_iZone]->GetTimeIter(), config[val_iZone]->GetOuterIter(), config[val_iZone]->GetInnerIter()); + output->SetHistory_Output(geometry[val_iZone][INST_0][MESH_0], solver[val_iZone][INST_0][MESH_0], + config[val_iZone], config[val_iZone]->GetTimeIter(), + config[val_iZone]->GetOuterIter(), config[val_iZone]->GetInnerIter()); } - StopCalc = output->GetConvergence(); - - return StopCalc; + return output->GetConvergence(); } void CFEAIteration::Postprocess(COutput *output, - CIntegration ****integration, - CGeometry ****geometry, - CSolver *****solver, - CNumerics ******numerics, - CConfig **config, - CSurfaceMovement **surface_movement, - CVolumetricMovement ***grid_movement, - CFreeFormDefBox*** FFDBox, - unsigned short val_iZone, - unsigned short val_iInst) { } - -void CFEAIteration::Solve(COutput *output, CIntegration ****integration, CGeometry ****geometry, CSolver *****solver, @@ -1746,14 +1686,24 @@ void CFEAIteration::Solve(COutput *output, CVolumetricMovement ***grid_movement, CFreeFormDefBox*** FFDBox, unsigned short val_iZone, - unsigned short val_iInst - ) { + unsigned short val_iInst) { } - /*------------------ Structural subiteration ----------------------*/ - Iterate(output, integration, geometry, - solver, numerics, config, - surface_movement, grid_movement, FFDBox, val_iZone, INST_0); +void CFEAIteration::Solve(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst + ) { + /*------------------ Structural subiteration ----------------------*/ + Iterate(output, integration, geometry, solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); /*--- Write the convergence history for the structure (only screen output) ---*/ // if (multizone) output->SetConvHistory_Body(geometry, solver, config, integration, false, 0.0, val_iZone, INST_0); From 429ff42aeaedb7a69082f27760acd8bdbc9e2478 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 24 Mar 2020 09:34:47 +0000 Subject: [PATCH 29/79] nearest neighbor stats --- .../CNearestNeighbor.hpp | 8 +++++ .../CNearestNeighbor.cpp | 31 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/Common/include/interface_interpolation/CNearestNeighbor.hpp b/Common/include/interface_interpolation/CNearestNeighbor.hpp index c8efe3998e40..c86d50add484 100644 --- a/Common/include/interface_interpolation/CNearestNeighbor.hpp +++ b/Common/include/interface_interpolation/CNearestNeighbor.hpp @@ -35,6 +35,9 @@ * by using a kd-tree. */ class CNearestNeighbor final : public CInterpolator { +private: + su2double AvgDistance = 0.0, MaxDistance = 0.0; + public: /*! * \brief Constructor of the class. @@ -51,4 +54,9 @@ class CNearestNeighbor final : public CInterpolator { */ void Set_TransferCoeff(const CConfig* const* config) override; + /*! + * \brief Print interpolation statistics. + */ + void PrintStatistics(void) const override; + }; diff --git a/Common/src/interface_interpolation/CNearestNeighbor.cpp b/Common/src/interface_interpolation/CNearestNeighbor.cpp index 3e0a7ee24170..e1369f19aef0 100644 --- a/Common/src/interface_interpolation/CNearestNeighbor.cpp +++ b/Common/src/interface_interpolation/CNearestNeighbor.cpp @@ -45,11 +45,17 @@ CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, const CConf Set_TransferCoeff(config); } +void CNearestNeighbor::PrintStatistics() const { + if (rank != MASTER_NODE) return; + cout << " Avg/max distance to closest donor point: " << AvgDistance << "/" << MaxDistance << endl; +} + void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { /*--- Desired number of donor points. ---*/ const auto nDonor = max(config[donorZone]->GetNumNearestNeighbors(), 1); + /*--- Epsilon used to avoid division by zero. ---*/ const su2double eps = numeric_limits::epsilon(); const int nProcessor = size; @@ -62,6 +68,9 @@ void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { /*--- Cycle over nMarkersInt interface to determine communication pattern. ---*/ + AvgDistance = MaxDistance = 0.0; + unsigned long totalTargetPoints = 0; + for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ @@ -98,6 +107,9 @@ void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { auto& donorInfo = DonorInfoVec[omp_get_thread_num()]; donorInfo.resize(nPossibleDonor); + su2double avgDist = 0.0, maxDist = 0.0; + unsigned long numTarget = 0; + SU2_OMP_FOR_DYN(roundUpDiv(nVertexTarget,2*omp_get_max_threads())) for (auto iVertexTarget = 0ul; iVertexTarget < nVertexTarget; iVertexTarget++) { @@ -126,6 +138,12 @@ void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { partial_sort(donorInfo.begin(), donorInfo.begin()+nDonor, donorInfo.end(), [](const DonorInfo& a, const DonorInfo& b){return a.dist < b.dist;}); + /*--- Update stats. ---*/ + numTarget += 1; + su2double d = sqrt(donorInfo[0].dist); + avgDist += d; + maxDist = max(maxDist, d); + /*--- Compute interpolation numerators and denominator. ---*/ su2double denom = 0.0; for (auto iDonor = 0ul; iDonor < nDonor; ++iDonor) { @@ -142,6 +160,12 @@ void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { target_vertex->SetDonorCoeff(iDonor, donorInfo[iDonor].dist/denom); } } + SU2_OMP_CRITICAL + { + totalTargetPoints += numTarget; + AvgDistance += avgDist; + MaxDistance = max(MaxDistance, maxDist); + } } // end SU2_OMP_PARALLEL delete[] Buffer_Send_Coord; @@ -154,4 +178,11 @@ void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { delete[] Buffer_Receive_nVertex_Donor; + unsigned long tmp = totalTargetPoints; + SU2_MPI::Allreduce(&tmp, &totalTargetPoints, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + su2double tmp1 = AvgDistance, tmp2 = MaxDistance; + SU2_MPI::Allreduce(&tmp1, &AvgDistance, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&tmp2, &MaxDistance, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); + AvgDistance /= totalTargetPoints; + } From ae7fae5b95126287bdaa831e4108588f022074ce Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 24 Mar 2020 10:20:43 +0000 Subject: [PATCH 30/79] simplify "initial_calc" logic of CFEASolver to avoid confusing user errors --- SU2_CFD/include/solvers/CFEASolver.hpp | 1 + .../integration/CStructuralIntegration.cpp | 23 +++--------- SU2_CFD/src/solvers/CFEASolver.cpp | 37 ++++++++----------- 3 files changed, 21 insertions(+), 40 deletions(-) diff --git a/SU2_CFD/include/solvers/CFEASolver.hpp b/SU2_CFD/include/solvers/CFEASolver.hpp index 948ef934ffef..eae891063a05 100644 --- a/SU2_CFD/include/solvers/CFEASolver.hpp +++ b/SU2_CFD/include/solvers/CFEASolver.hpp @@ -87,6 +87,7 @@ class CFEASolver : public CSolver { bool element_based; /*!< \brief Bool to determine if an element-based file is used. */ bool topol_filter_applied; /*!< \brief True if density filtering has been performed. */ + bool initial_calc = true; /*!< \brief Becomes false after first call to Preprocessing. */ unsigned long nElement; /*!< \brief Number of elements. */ diff --git a/SU2_CFD/src/integration/CStructuralIntegration.cpp b/SU2_CFD/src/integration/CStructuralIntegration.cpp index 1c6ac815f5ef..18bc767675fc 100644 --- a/SU2_CFD/src/integration/CStructuralIntegration.cpp +++ b/SU2_CFD/src/integration/CStructuralIntegration.cpp @@ -71,32 +71,20 @@ void CStructuralIntegration::Structural_Iteration(CGeometry ****geometry, CSolve void CStructuralIntegration::Space_Integration_FEM(CGeometry *geometry, CSolver **solver_container, CNumerics **numerics, CConfig *config, unsigned short RunTime_EqSystem) { - bool dynamic = config->GetTime_Domain(); bool first_iter = (config->GetInnerIter() == 0); bool linear_analysis = (config->GetGeometricConditions() == SMALL_DEFORMATIONS); - bool nonlinear_analysis = (config->GetGeometricConditions() == LARGE_DEFORMATIONS); unsigned short IterativeScheme = config->GetKind_SpaceIteScheme_FEA(); unsigned short MainSolver = config->GetContainerPosition(RunTime_EqSystem); CSolver* solver = solver_container[MainSolver]; - /*--- Initial calculation, different logic for restarted simulations. ---*/ - bool initial_calc = false; - if (config->GetRestart()) - initial_calc = (config->GetTimeIter() == config->GetRestart_Iter()) && first_iter; - else - initial_calc = (config->GetTimeIter() == 0) && first_iter; + /*--- Mass Matrix was computed during preprocessing, see notes therein. ---*/ - /*--- Mass Matrix computed during preprocessing, see notes therein. ---*/ - - /*--- If the analysis is linear, only a the constitutive term of the stiffness matrix has to be computed. ---*/ - /*--- This is done only once, at the beginning of the calculation. From then on, K is constant. ---*/ - /*--- For correct differentiation of dynamic cases the matrix needs to be computed every time. ---*/ - if (linear_analysis && (dynamic || initial_calc)) + if (linear_analysis) { + /*--- If the analysis is linear, only a the constitutive term of the stiffness matrix has to be computed. ---*/ solver->Compute_StiffMatrix(geometry, numerics, config); - - if (nonlinear_analysis) { - + } + else { /*--- If the analysis is nonlinear the stress terms also need to be computed. ---*/ /*--- For full Newton-Raphson the stiffness matrix and the nodal term are updated every time. ---*/ if (IterativeScheme == NEWTON_RAPHSON) { @@ -111,7 +99,6 @@ void CStructuralIntegration::Space_Integration_FEM(CGeometry *geometry, CSolver else solver->Compute_NodalStressRes(geometry, numerics, config); } - } /*--- Apply the NATURAL BOUNDARY CONDITIONS (loads). ---*/ diff --git a/SU2_CFD/src/solvers/CFEASolver.cpp b/SU2_CFD/src/solvers/CFEASolver.cpp index 3819e0b713a1..28e338731015 100644 --- a/SU2_CFD/src/solvers/CFEASolver.cpp +++ b/SU2_CFD/src/solvers/CFEASolver.cpp @@ -97,8 +97,9 @@ CFEASolver::CFEASolver(bool mesh_deform_mode) : CSolver(mesh_deform_mode) { element_container[iTerm] = new CElement* [MAX_FE_KINDS*omp_get_max_threads()](); topol_filter_applied = false; - element_based = false; + initial_calc = true; + } CFEASolver::CFEASolver(CGeometry *geometry, CConfig *config) : CSolver() { @@ -112,8 +113,8 @@ CFEASolver::CFEASolver(CGeometry *geometry, CConfig *config) : CSolver() { /*--- A priori we don't have an element-based input file (most of the applications will be like this) ---*/ element_based = false; - topol_filter_applied = false; + initial_calc = true; nElement = geometry->GetnElem(); nDim = geometry->GetnDim(); @@ -751,25 +752,14 @@ void CFEASolver::Set_ReferenceGeometry(CGeometry *geometry, CConfig *config) { void CFEASolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, CNumerics **numerics, unsigned short iMesh, unsigned long Iteration, unsigned short RunTime_EqSystem, bool Output) { - bool dynamic = config->GetTime_Domain(); - bool first_iter = (config->GetInnerIter() == 0); - - /*--- Initial calculation, different logic for restarted simulations. ---*/ - bool initial_calc = false; - if (config->GetRestart()) - initial_calc = (config->GetTimeIter() == config->GetRestart_Iter()) && first_iter; - else - initial_calc = (config->GetTimeIter() == 0) && first_iter; - - bool disc_adj_fem = (config->GetKind_Solver() == DISC_ADJ_FEM); - - bool body_forces = config->GetDeadLoad(); - - bool fsi = config->GetFSI_Simulation(); - bool consistent_interpolation = (!config->GetConservativeInterpolation() || - (config->GetKindInterpolation() == WEIGHTED_AVERAGE)); - - bool topology_mode = config->GetTopology_Optimization(); + const bool dynamic = config->GetTime_Domain(); + const bool first_iter = (config->GetInnerIter() == 0); + const bool disc_adj_fem = (config->GetKind_Solver() == DISC_ADJ_FEM); + const bool body_forces = config->GetDeadLoad(); + const bool fsi = config->GetFSI_Simulation(); + const bool consistent_interpolation = (!config->GetConservativeInterpolation() || + (config->GetKindInterpolation() == WEIGHTED_AVERAGE)); + const bool topology_mode = config->GetTopology_Optimization(); /* * For topology optimization we apply a filter on the design density field to avoid @@ -802,7 +792,7 @@ void CFEASolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, * * Only initialized once, at the first iteration of the first time step. */ - if (body_forces && initial_calc) + if (body_forces && (initial_calc || disc_adj_fem)) Compute_DeadLoad(geometry, numerics, config); /*--- Clear the linear system solution. ---*/ @@ -819,6 +809,9 @@ void CFEASolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, */ if (fsi && first_iter && consistent_interpolation) Integrate_FSI_Loads(geometry,config); + /*--- Next call to Preprocessing will not be "initial_calc" and linear operations will not be repeated. ---*/ + initial_calc = false; + } void CFEASolver::SetInitialCondition(CGeometry **geometry, CSolver ***solver_container, CConfig *config, unsigned long TimeIter) { From 01d8531fd848828236c41ba5a04c9484b330e777 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Wed, 25 Mar 2020 07:57:56 +0000 Subject: [PATCH 31/79] fix, CFL_REDUCTION_TURB had no effect --- SU2_CFD/src/solvers/CTurbSASolver.cpp | 4 ++-- SU2_CFD/src/solvers/CTurbSSTSolver.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 9d78a28e2b13..3948a6e182b0 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -225,9 +225,9 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor SetImplicitPeriodic(true); - /* Store the initial CFL number for all grid points. */ + /*--- Store the initial CFL number for all grid points. ---*/ - const su2double CFL = config->GetCFL(MGLevel); + const su2double CFL = config->GetCFL(MGLevel)*config->GetCFLRedCoeff_Turb(); for (iPoint = 0; iPoint < nPoint; iPoint++) { nodes->SetLocalCFL(iPoint, CFL); } diff --git a/SU2_CFD/src/solvers/CTurbSSTSolver.cpp b/SU2_CFD/src/solvers/CTurbSSTSolver.cpp index 41fc01aa4890..96cab040c155 100644 --- a/SU2_CFD/src/solvers/CTurbSSTSolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSSTSolver.cpp @@ -226,9 +226,9 @@ CTurbSSTSolver::CTurbSSTSolver(CGeometry *geometry, CConfig *config, unsigned sh SetImplicitPeriodic(true); - /* Store the initial CFL number for all grid points. */ + /*--- Store the initial CFL number for all grid points. ---*/ - const su2double CFL = config->GetCFL(MGLevel); + const su2double CFL = config->GetCFL(MGLevel)*config->GetCFLRedCoeff_Turb(); for (iPoint = 0; iPoint < nPoint; iPoint++) { nodes->SetLocalCFL(iPoint, CFL); } From 3553116797ac147a7bee493dd96c0e3d0635d671 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 26 Mar 2020 08:23:58 +0000 Subject: [PATCH 32/79] update testcases after re-enabling option CFL_REDUCTION_TURB --- .../transonic_stator_2D/transonic_stator.cfg | 4 +--- .../harmonic_balance/hb_rans_preconditioning/davis.cfg | 2 +- TestCases/parallel_regression.py | 4 ++-- TestCases/serial_regression.py | 4 ++-- TestCases/sliding_interface/bars_SST_2D/bars.cfg | 2 +- .../sliding_interface/single_stage/single_stage_NN.cfg | 7 +------ .../sliding_interface/single_stage/single_stage_WA.cfg | 8 +------- TestCases/turbomachinery/axial_stage_2D/Axial_stage2D.cfg | 4 +--- .../centrifugal_blade/centrifugal_blade.cfg | 5 +---- .../centrifugal_stage/centrifugal_stage.cfg | 5 +---- .../transonic_stator_2D/transonic_stator.cfg | 4 +--- .../transonic_stator_2D/transonic_stator_rst.cfg | 4 +--- 12 files changed, 14 insertions(+), 39 deletions(-) diff --git a/TestCases/disc_adj_turbomachinery/transonic_stator_2D/transonic_stator.cfg b/TestCases/disc_adj_turbomachinery/transonic_stator_2D/transonic_stator.cfg index b78895338f5f..8c2c470dcb61 100644 --- a/TestCases/disc_adj_turbomachinery/transonic_stator_2D/transonic_stator.cfg +++ b/TestCases/disc_adj_turbomachinery/transonic_stator_2D/transonic_stator.cfg @@ -277,9 +277,7 @@ SLOPE_LIMITER_TURB= VENKATAKRISHNAN TIME_DISCRE_TURB= EULER_IMPLICIT % % Reduction factor of the CFL coefficient in the turbulence problem -CFL_REDUCTION_TURB= 0.1 -% -% Relaxation coefficient +CFL_REDUCTION_TURB= 1.0 % % % ----------------------- DESIGN VARIABLE PARAMETERS --------------------------% diff --git a/TestCases/harmonic_balance/hb_rans_preconditioning/davis.cfg b/TestCases/harmonic_balance/hb_rans_preconditioning/davis.cfg index 6a41168df502..3463d40b379d 100644 --- a/TestCases/harmonic_balance/hb_rans_preconditioning/davis.cfg +++ b/TestCases/harmonic_balance/hb_rans_preconditioning/davis.cfg @@ -193,7 +193,7 @@ MUSCL_TURB= NO TIME_DISCRE_TURB= EULER_IMPLICIT % % Reduction factor of the CFL coefficient in the turbulence problem -CFL_REDUCTION_TURB= 0.4 +CFL_REDUCTION_TURB= 1.0 % --------------------------- CONVERGENCE PARAMETERS --------------------------% % Convergence criteria (CAUCHY, RESIDUAL) diff --git a/TestCases/parallel_regression.py b/TestCases/parallel_regression.py index 4475490dd1c6..691f5502810e 100644 --- a/TestCases/parallel_regression.py +++ b/TestCases/parallel_regression.py @@ -834,7 +834,7 @@ def main(): Jones_tc.cfg_dir = "turbomachinery/APU_turbocharger" Jones_tc.cfg_file = "Jones.cfg" Jones_tc.test_iter = 5 - Jones_tc.test_vals = [-5.316335, 0.355081, 44.772280, 2.269966] #last 4 columns + Jones_tc.test_vals = [-5.290553, 0.372874, 44.765930, 2.270197] #last 4 columns Jones_tc.su2_exec = "parallel_computation.py -f" Jones_tc.timeout = 1600 Jones_tc.new_output = False @@ -846,7 +846,7 @@ def main(): Jones_tc_rst.cfg_dir = "turbomachinery/APU_turbocharger" Jones_tc_rst.cfg_file = "Jones_rst.cfg" Jones_tc_rst.test_iter = 5 - Jones_tc_rst.test_vals = [-3.034157, 0.013763, 82.263700, 2.792251] #last 4 columns + Jones_tc_rst.test_vals = [-3.030374, 0.017344, 82.263660, 2.792178] #last 4 columns Jones_tc_rst.su2_exec = "parallel_computation.py -f" Jones_tc_rst.timeout = 1600 Jones_tc_rst.new_output = False diff --git a/TestCases/serial_regression.py b/TestCases/serial_regression.py index f57084dc5757..e3f0ceca73d4 100644 --- a/TestCases/serial_regression.py +++ b/TestCases/serial_regression.py @@ -983,7 +983,7 @@ def main(): Jones_tc.cfg_dir = "turbomachinery/APU_turbocharger" Jones_tc.cfg_file = "Jones.cfg" Jones_tc.test_iter = 5 - Jones_tc.test_vals = [-5.316334, 0.355080, 44.772250, 2.269935] #last 4 columns + Jones_tc.test_vals = [-5.290552, 0.372873, 44.765920, 2.270165] #last 4 columns Jones_tc.su2_exec = "SU2_CFD" Jones_tc.new_output = False Jones_tc.timeout = 1600 @@ -995,7 +995,7 @@ def main(): Jones_tc_rst.cfg_dir = "turbomachinery/APU_turbocharger" Jones_tc_rst.cfg_file = "Jones_rst.cfg" Jones_tc_rst.test_iter = 5 - Jones_tc_rst.test_vals = [-3.034158, 0.013762, 82.263710, 2.792251] #last 4 columns + Jones_tc_rst.test_vals = [-3.030374, 0.017342, 82.263670, 2.792178] #last 4 columns Jones_tc_rst.su2_exec = "SU2_CFD" Jones_tc_rst.new_output = False Jones_tc_rst.timeout = 1600 diff --git a/TestCases/sliding_interface/bars_SST_2D/bars.cfg b/TestCases/sliding_interface/bars_SST_2D/bars.cfg index 6778a99dec54..ee4c56a856ba 100644 --- a/TestCases/sliding_interface/bars_SST_2D/bars.cfg +++ b/TestCases/sliding_interface/bars_SST_2D/bars.cfg @@ -252,7 +252,7 @@ SLOPE_LIMITER_TURB= NONE TIME_DISCRE_TURB= EULER_IMPLICIT % % Reduction factor of the CFL coefficient in the turbulence problem -CFL_REDUCTION_TURB= 0.10 +CFL_REDUCTION_TURB= 1.0 % --------------------------- CONVERGENCE PARAMETERS --------------------------% % diff --git a/TestCases/sliding_interface/single_stage/single_stage_NN.cfg b/TestCases/sliding_interface/single_stage/single_stage_NN.cfg index e8bc15224ebd..1abaa6406bdf 100644 --- a/TestCases/sliding_interface/single_stage/single_stage_NN.cfg +++ b/TestCases/sliding_interface/single_stage/single_stage_NN.cfg @@ -217,12 +217,7 @@ SLOPE_LIMITER_TURB= VENKATAKRISHNAN TIME_DISCRE_TURB= EULER_IMPLICIT % % Reduction factor of the CFL coefficient in the turbulence problem -CFL_REDUCTION_TURB= 0.01 -% -% Relaxation coefficient -% -% -% +CFL_REDUCTION_TURB= 1.0 % % --------------------------- CONVERGENCE PARAMETERS --------------------------% % Convergence criteria (CAUCHY, RESIDUAL) diff --git a/TestCases/sliding_interface/single_stage/single_stage_WA.cfg b/TestCases/sliding_interface/single_stage/single_stage_WA.cfg index 69d11c02dfdf..97bb4f23ef55 100644 --- a/TestCases/sliding_interface/single_stage/single_stage_WA.cfg +++ b/TestCases/sliding_interface/single_stage/single_stage_WA.cfg @@ -194,9 +194,6 @@ SLOPE_LIMITER_FLOW= NONE % Time discretization (RUNGE-KUTTA_EXPLICIT, EULER_IMPLICIT, EULER_EXPLICIT) TIME_DISCRE_FLOW= EULER_IMPLICIT % -% Relaxation coefficient -% -% % % % -------------------- TURBULENT NUMERICAL METHOD DEFINITION ------------------% @@ -215,10 +212,7 @@ SLOPE_LIMITER_TURB= VENKATAKRISHNAN TIME_DISCRE_TURB= EULER_IMPLICIT % % Reduction factor of the CFL coefficient in the turbulence problem -CFL_REDUCTION_TURB= 0.01 -% -% Relaxation coefficient -% +CFL_REDUCTION_TURB= 1.0 % % % diff --git a/TestCases/turbomachinery/axial_stage_2D/Axial_stage2D.cfg b/TestCases/turbomachinery/axial_stage_2D/Axial_stage2D.cfg index dc86b6875204..4cedf5e074f3 100755 --- a/TestCases/turbomachinery/axial_stage_2D/Axial_stage2D.cfg +++ b/TestCases/turbomachinery/axial_stage_2D/Axial_stage2D.cfg @@ -260,9 +260,7 @@ SLOPE_LIMITER_TURB= VENKATAKRISHNAN TIME_DISCRE_TURB= EULER_IMPLICIT % % Reduction factor of the CFL coefficient in the turbulence problem -CFL_REDUCTION_TURB= 0.5 -% -% Relaxation coefficient +CFL_REDUCTION_TURB= 1.0 % % % --------------------------- CONVERGENCE PARAMETERS --------------------------% diff --git a/TestCases/turbomachinery/centrifugal_blade/centrifugal_blade.cfg b/TestCases/turbomachinery/centrifugal_blade/centrifugal_blade.cfg index ce87e1e5f692..c853f7b86215 100755 --- a/TestCases/turbomachinery/centrifugal_blade/centrifugal_blade.cfg +++ b/TestCases/turbomachinery/centrifugal_blade/centrifugal_blade.cfg @@ -295,10 +295,7 @@ SLOPE_LIMITER_TURB= VENKATAKRISHNAN TIME_DISCRE_TURB= EULER_IMPLICIT % % Reduction factor of the CFL coefficient in the turbulence problem -CFL_REDUCTION_TURB= 0.01 -% -% Relaxation coefficient -% +CFL_REDUCTION_TURB= 1.0 % % % diff --git a/TestCases/turbomachinery/centrifugal_stage/centrifugal_stage.cfg b/TestCases/turbomachinery/centrifugal_stage/centrifugal_stage.cfg index e650e733a9f1..459b20d83c31 100755 --- a/TestCases/turbomachinery/centrifugal_stage/centrifugal_stage.cfg +++ b/TestCases/turbomachinery/centrifugal_stage/centrifugal_stage.cfg @@ -303,10 +303,7 @@ SLOPE_LIMITER_TURB= VENKATAKRISHNAN TIME_DISCRE_TURB= EULER_IMPLICIT % % Reduction factor of the CFL coefficient in the turbulence problem -CFL_REDUCTION_TURB= 0.01 -% -% Relaxation coefficient -% +CFL_REDUCTION_TURB= 1.0 % % % diff --git a/TestCases/turbomachinery/transonic_stator_2D/transonic_stator.cfg b/TestCases/turbomachinery/transonic_stator_2D/transonic_stator.cfg index dc3a5cbd334b..bb6a6c7c7896 100644 --- a/TestCases/turbomachinery/transonic_stator_2D/transonic_stator.cfg +++ b/TestCases/turbomachinery/transonic_stator_2D/transonic_stator.cfg @@ -268,9 +268,7 @@ SLOPE_LIMITER_TURB= VENKATAKRISHNAN TIME_DISCRE_TURB= EULER_IMPLICIT % % Reduction factor of the CFL coefficient in the turbulence problem -CFL_REDUCTION_TURB= 0.1 -% -% Relaxation coefficient +CFL_REDUCTION_TURB= 1.0 % % % --------------------------- CONVERGENCE PARAMETERS --------------------------% diff --git a/TestCases/turbomachinery/transonic_stator_2D/transonic_stator_rst.cfg b/TestCases/turbomachinery/transonic_stator_2D/transonic_stator_rst.cfg index 404834b6cf9e..323644a7d903 100644 --- a/TestCases/turbomachinery/transonic_stator_2D/transonic_stator_rst.cfg +++ b/TestCases/turbomachinery/transonic_stator_2D/transonic_stator_rst.cfg @@ -273,9 +273,7 @@ SLOPE_LIMITER_TURB= VENKATAKRISHNAN TIME_DISCRE_TURB= EULER_IMPLICIT % % Reduction factor of the CFL coefficient in the turbulence problem -CFL_REDUCTION_TURB= 0.1 -% -% Relaxation coefficient +CFL_REDUCTION_TURB= 1.0 % % % --------------------------- CONVERGENCE PARAMETERS --------------------------% From 51efbb4dca9a8b7f3f4cf2931b77aebb6ec88566 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 26 Mar 2020 08:56:44 +0000 Subject: [PATCH 33/79] remove legacy FSI output --- SU2_CFD/include/output/COutputLegacy.hpp | 11 - SU2_CFD/src/drivers/CDriver.cpp | 9 - .../src/output/output_structure_legacy.cpp | 307 ------------------ SU2_CFD/src/solvers/CMeshSolver.cpp | 266 ++++++++------- 4 files changed, 132 insertions(+), 461 deletions(-) diff --git a/SU2_CFD/include/output/COutputLegacy.hpp b/SU2_CFD/include/output/COutputLegacy.hpp index 74cf92b1fc97..e26ceb7274d4 100644 --- a/SU2_CFD/include/output/COutputLegacy.hpp +++ b/SU2_CFD/include/output/COutputLegacy.hpp @@ -321,17 +321,6 @@ class COutputLegacy { */ void SpecialOutput_Distortion(CSolver *solver, CGeometry *geometry, CConfig *config, bool output); - /*! - * \brief Create and write the file with the FSI convergence history. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] solver_container - Solver for all physical problems. - * \param[in] iExtIter - Current external (time) iteration. - * \param[in] val_iZone - Current zone number in the grid file. - */ - void SpecialOutput_FSI(ofstream *FSIHist_file, CGeometry ****geometry, CSolver *****solver_container, CConfig **config, CIntegration ****integration, - unsigned long iExtIter, unsigned short ZONE_FLOW, unsigned short ZONE_STRUCT, bool header); - /*! * \brief Create and write the file with the FSI convergence history. * \param[in] iIter - Current iteration. diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index aec0ab14f9d2..b0a48b0c6a3b 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -247,15 +247,6 @@ CDriver::CDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunica PythonInterface_Preprocessing(config_container, geometry_container, solver_container); - /*--- Open the FSI convergence history file ---*/ - -// if (fsi){ -// if (rank == MASTER_NODE) cout << endl <<"Opening FSI history file." << endl; -// unsigned short ZONE_FLOW = 0, ZONE_STRUCT = 1; -// output_container->SpecialOutput_FSI(&FSIHist_file, geometry_container, solver_container, -// config_container, integration_container, 0, -// ZONE_FLOW, ZONE_STRUCT, true); -// } /*--- Preprocessing time is reported now, but not included in the next compute portion. ---*/ diff --git a/SU2_CFD/src/output/output_structure_legacy.cpp b/SU2_CFD/src/output/output_structure_legacy.cpp index 6e2ed1e9d5ac..b2fd26df2a71 100644 --- a/SU2_CFD/src/output/output_structure_legacy.cpp +++ b/SU2_CFD/src/output/output_structure_legacy.cpp @@ -11210,313 +11210,6 @@ void COutputLegacy::SpecialOutput_Distortion(CSolver *solver, CGeometry *geometr } -void COutputLegacy::SpecialOutput_FSI(ofstream *FSIHist_file, CGeometry ****geometry, CSolver *****solver_container, - CConfig **config, CIntegration ****integration, unsigned long iExtIter, - unsigned short ZONE_FLOW, unsigned short ZONE_STRUCT, bool header) { - - int rank = MASTER_NODE; -#ifdef HAVE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &rank); -#endif - - /*--- Output only using the Master Node ---*/ - - if ((rank == MASTER_NODE) && (header)){ - - char cstr[200], buffer[50], turb_resid[1000]; - string Monitoring_Tag, monitoring_coeff, aeroelastic_coeff, turbo_coeff; - - bool turbulent = ((config[ZONE_FLOW]->GetKind_Solver() == RANS) || (config[ZONE_FLOW]->GetKind_Solver() == ADJ_RANS) || - (config[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_RANS)); - - unsigned short direct_diff = config[ZONE_FLOW]->GetDirectDiff(); - - /*--- Write file name with extension ---*/ -// string filename = config[ZONE_FLOW]->GetConv_FileName_FSI(); -// strcpy (cstr, filename.data()); - - if (config[ZONE_FLOW]->GetTime_Domain() && config[ZONE_FLOW]->GetRestart()) { - long iExtIter = config[ZONE_FLOW]->GetRestart_Iter(); - if (SU2_TYPE::Int(iExtIter) < 10) SPRINTF (buffer, "_0000%d", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d", SU2_TYPE::Int(iExtIter)); - if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d", SU2_TYPE::Int(iExtIter)); - if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d", SU2_TYPE::Int(iExtIter)); - strcat(cstr, buffer); - } - - if ((config[ZONE_FLOW]->GetTabular_FileFormat() == TAB_TECPLOT)) SPRINTF (buffer, ".dat"); - else if ((config[ZONE_FLOW]->GetTabular_FileFormat() == TAB_CSV)) SPRINTF (buffer, ".vtk"); - strcat(cstr, buffer); - - FSIHist_file->open(cstr, ios::out); - FSIHist_file->precision(15); - - /*--- Begin of the header ---*/ - - char begin[]= "\"ExtIter\",\"BGSIter\""; - - /*--- Header for the coefficients ---*/ - - char flow_coeff[]= ",\"CL\",\"CD\",\"CMx\",\"CMy\",\"CMz\",\"CL/CD\""; - char fem_coeff[]= ",\"VM_Stress\""; - char of_1[] = ",\"TgtGeom\""; - char of_2[] = ",\"TgtNode\""; - - char d_flow_coeff[] = ",\"D(CL)\",\"D(CD)\",\"D(CSF)\",\"D(CMx)\",\"D(CMy)\",\"D(CMz)\",\"D(CFx)\",\"D(CFy)\",\"D(CFz)\",\"D(CL/CD)\",\"D(Custom_ObjFunc)\""; - - /*--- Header for the residuals ---*/ - - char fsi_resid[]= ",\"Res_FSI\",\"RelaxCoeff\",\"ForceCoeff\""; - - char flow_resid[]= ",\"Res_BGS[F0]\",\"Res_BGS[F1]\",\"Res_BGS[F2]\",\"Res_BGS[F3]\",\"Res_BGS[F4]\""; - char adj_flow_resid[]= ",\"Res_AdjFlow[0]\",\"Res_AdjFlow[1]\",\"Res_AdjFlow[2]\",\"Res_AdjFlow[3]\",\"Res_AdjFlow[4]\""; - char fem_resid[]= ",\"Res_BGS[S0]\",\"Res_BGS[S1]\",\"Res_BGS[S2]\""; - - /*--- End of the header ---*/ - - char end[]= ",\"Time(min)\"\n"; - - if ((config[ZONE_FLOW]->GetTabular_FileFormat() == TECPLOT) || - (config[ZONE_FLOW]->GetTabular_FileFormat() == TECPLOT_BINARY)) { - FSIHist_file[0] << "TITLE = \"SU2 FSI Simulation\"" << endl; - FSIHist_file[0] << "VARIABLES = "; - } - - /*--- Write the header, case depending ---*/ - - FSIHist_file[0] << begin; - - FSIHist_file[0] << fsi_resid; - - switch (config[ZONE_FLOW]->GetKind_Solver()) { - - /*--- Flow residual output ---*/ - - case EULER : case NAVIER_STOKES: case RANS : - case INC_EULER : case INC_NAVIER_STOKES: case INC_RANS : - FSIHist_file[0] << flow_resid; - if (turbulent) FSIHist_file[0] << turb_resid; - break; - - case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: - case DISC_ADJ_INC_EULER: case DISC_ADJ_INC_NAVIER_STOKES: case DISC_ADJ_INC_RANS: - FSIHist_file[0] << adj_flow_resid; - break; - - } - - /*--- FEA residual output ---*/ - - switch (config[ZONE_STRUCT]->GetKind_Solver()) { - - case FEM_ELASTICITY: - FSIHist_file[0] << fem_resid; - break; - - case DISC_ADJ_FEM: - FSIHist_file[0] << fem_resid ; - break; - - } - - /*--- Flow coefficients output ---*/ - switch (config[ZONE_FLOW]->GetKind_Solver()) { - - case EULER : case NAVIER_STOKES: case RANS : - case INC_EULER : case INC_NAVIER_STOKES: case INC_RANS : - FSIHist_file[0] << flow_coeff; - if (turbulent) FSIHist_file[0] << turb_resid; - if (direct_diff != NO_DERIVATIVE) { - FSIHist_file[0] << d_flow_coeff; - } - break; - - case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: - case DISC_ADJ_INC_EULER: case DISC_ADJ_INC_NAVIER_STOKES: case DISC_ADJ_INC_RANS: - FSIHist_file[0] << adj_flow_resid; - break; - - } - - switch (config[ZONE_STRUCT]->GetKind_Solver()) { - - case FEM_ELASTICITY: - FSIHist_file[0] << fem_coeff; - break; - - case DISC_ADJ_FEM: - FSIHist_file[0] << fem_coeff; - break; - - } - - switch (config[ZONE_STRUCT]->GetKind_ObjFunc()){ - case REFERENCE_GEOMETRY: - FSIHist_file[0] << of_1; - break; - case REFERENCE_NODE: - FSIHist_file[0] << of_2; - break; - default: - break; - } - - FSIHist_file[0] << end; - - - } - - if ((rank == MASTER_NODE) && (!header)){ - - unsigned short nDim = geometry[ZONE_STRUCT][INST_0][MESH_0]->GetnDim(); - - unsigned long iExtIter = config[ZONE_STRUCT]->GetInnerIter(); - unsigned long ExtIter_OffSet = config[ZONE_STRUCT]->GetExtIter_OffSet(); - unsigned long iOuterIter = config[ZONE_STRUCT]->GetOuterIter(); - su2double dummy = 0.0; - - bool first_iter = ((iExtIter==0) && (iOuterIter == 0)); - - - bool compressible = (config[ZONE_FLOW]->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (config[ZONE_FLOW]->GetKind_Regime() == INCOMPRESSIBLE); - - - bool fem = ((config[ZONE_STRUCT]->GetKind_Solver() == FEM_ELASTICITY) || - (config[ZONE_STRUCT]->GetKind_Solver() == DISC_ADJ_FEM)); - bool linear_analysis = (config[ZONE_STRUCT]->GetGeometricConditions() == SMALL_DEFORMATIONS); - bool nonlinear_analysis = (config[ZONE_STRUCT]->GetGeometricConditions() == LARGE_DEFORMATIONS); - - bool disc_adj_flow = config[ZONE_FLOW]->GetDiscrete_Adjoint(); - bool disc_adj_fem = config[ZONE_STRUCT]->GetDiscrete_Adjoint(); - - - /*--- WARNING: These buffers have hard-coded lengths. Note that you - may have to adjust them to be larger if adding more entries. ---*/ - - char begin[1000], direct_coeff[1000], - fsi_resid[1000], fsi_coeffs[1000], - flow_resid[1000], fem_resid[1000], - objective_function[1000], end[1000]; - - su2double *residual_flow = NULL; - su2double *residual_fem = NULL; - su2double *residual_fsi = NULL; - su2double *coeffs_fsi = NULL; - - /*--- Initialize number of variables ---*/ - unsigned short nVar_FSI = 1, nCoeff_FSI = 2, nVar_Flow = 0, nVar_FEM = 0; - - unsigned short iVar; - - /*--- Direct problem variables ---*/ - if (compressible) nVar_Flow = nDim+2; else nVar_Flow = nDim+1; - - if (fem) { - if (linear_analysis) nVar_FEM = nDim; - if (nonlinear_analysis) nVar_FEM = 3; - if (disc_adj_fem) nVar_FEM = nDim; - } - - residual_flow = new su2double[nVar_Flow]; - residual_fem = new su2double[nVar_FEM]; - residual_fsi = new su2double[nVar_FSI]; - coeffs_fsi = new su2double[nCoeff_FSI]; - - /*--- Initialize variables to store information from all domains (direct solution) ---*/ - - su2double Total_CL = 0.0, Total_CD = 0.0, Total_CMx = 0.0, Total_CMy = 0.0, Total_CMz = 0.0, Total_CEff = 0.0, - Total_OF = 0.0; - - Total_CL = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CL(); - Total_CD = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CD(); - Total_CEff = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CEff(); - Total_CMx = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CMx(); - Total_CMy = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CMy(); - Total_CMz = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CMz(); - - bool print_of = false; - - switch (config[ZONE_STRUCT]->GetKind_ObjFunc()){ - case REFERENCE_GEOMETRY: - Total_OF = solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetTotal_OFRefGeom(); - print_of = true; - break; - case REFERENCE_NODE: - Total_OF = solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetTotal_OFRefNode(); - print_of = true; - break; - default: - break; - } - - if ((!disc_adj_flow) && (!disc_adj_fem)){ - /*--- Flow Residuals ---*/ - for (iVar = 0; iVar < nVar_Flow; iVar++) - residual_flow[iVar] = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetRes_BGS(iVar); - - /*--- FEA Residuals ---*/ - for (iVar = 0; iVar < nVar_FEM; iVar++) - residual_fem[iVar] = solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetRes_BGS(iVar); - - residual_fsi[0] = solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetFSI_Residual(); - coeffs_fsi[0] = solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetRelaxCoeff(); - coeffs_fsi[1] = solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetForceCoeff(); - - } - else{ - /*--- Flow Residuals ---*/ - for (iVar = 0; iVar < nVar_Flow; iVar++) - residual_flow[iVar] = solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->GetRes_BGS(iVar); - /*--- FEA Residuals ---*/ - for (iVar = 0; iVar < nVar_FEM; iVar++) - residual_fem[iVar] = solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->GetRes_BGS(iVar); - } - - /*--- Write the begining of the history file ---*/ - SPRINTF(begin, "%12d, %12d", SU2_TYPE::Int(iExtIter+ExtIter_OffSet), SU2_TYPE::Int(iOuterIter)); - /*--- Write the end of the history file ---*/ - SPRINTF (end, "\n"); - - SPRINTF (fsi_resid, ", %14.8e", log10 (residual_fsi[0])); - SPRINTF (fsi_coeffs, ", %14.8e, %14.8e", coeffs_fsi[0], coeffs_fsi[1]); - - /*--- Flow residual ---*/ - if (nDim == 2) { - if (compressible) SPRINTF (flow_resid, ", %14.8e, %14.8e, %14.8e, %14.8e, %14.8e", log10 (residual_flow[0]), log10 (residual_flow[1]), log10 (residual_flow[2]), log10 (residual_flow[3]), dummy); - if (incompressible) SPRINTF (flow_resid, ", %14.8e, %14.8e, %14.8e, %14.8e, %14.8e", log10 (residual_flow[0]), log10 (residual_flow[1]), log10 (residual_flow[2]), dummy, dummy); - } - else { - if (compressible) SPRINTF (flow_resid, ", %14.8e, %14.8e, %14.8e, %14.8e, %14.8e", log10 (residual_flow[0]), log10 (residual_flow[1]), log10 (residual_flow[2]), log10 (residual_flow[3]), log10 (residual_flow[4]) ); - if (incompressible) SPRINTF (flow_resid, ", %14.8e, %14.8e, %14.8e, %14.8e, %14.8e", log10 (residual_flow[0]), log10 (residual_flow[1]), log10 (residual_flow[2]), log10 (residual_flow[3]), dummy); - } - - /*--- FEM residual ---*/ - if (nDim == 2) SPRINTF (fem_resid, ", %14.8e, %14.8e, %14.8e", log10 (residual_fem[0]), log10 (residual_fem[1]), dummy); - else SPRINTF (fem_resid, ", %14.8e, %14.8e, %14.8e", log10 (residual_fem[0]), log10 (residual_fem[1]), log10 (residual_fem[1])); - - /*--- Direct coefficients ---*/ - SPRINTF (direct_coeff, ", %14.8e, %14.8e, %14.8e, %14.8e, %14.8e, %14.8e",Total_CL, Total_CD, Total_CMx, Total_CMy, Total_CMz, Total_CEff); - - if (print_of) SPRINTF (objective_function, ", %14.8e", Total_OF); - - if (!first_iter){ - if (!print_of) FSIHist_file[0] << begin << fsi_resid << fsi_coeffs << flow_resid << fem_resid << direct_coeff << end; - else FSIHist_file[0] << begin << fsi_resid << fsi_coeffs << flow_resid << fem_resid << direct_coeff << objective_function << end; - FSIHist_file[0].flush(); - } - - delete [] residual_flow; - delete [] residual_fem; - delete [] residual_fsi; - delete [] coeffs_fsi; - - - } - -} - void COutputLegacy::SetSensitivity_Files(CGeometry ***geometry, CConfig **config, unsigned short val_nZone) { unsigned short iMarker,iDim, nDim, iVar, nMarker, nVar; diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index f81748fa4275..415442931c3e 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -839,7 +839,7 @@ void CMeshSolver::Restart_OldGeometry(CGeometry *geometry, CConfig *config) { void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, unsigned long iter, unsigned short iZone) { - + su2double deltaT, time_new, time_old, Lref, *Coord; su2double Center[3], VarCoord[3], Omega[3], Ampl[3], Phase[3]; su2double VarCoordAbs[3] = {0.0, 0.0, 0.0}; @@ -851,17 +851,15 @@ void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, unsigned short iMarker, jMarker, Moving, iDim, nDim = geometry->GetnDim(); unsigned long iPoint, iVertex; string Marker_Tag, Moving_Tag; - - CSolver *solver = NULL; /*--- Initialize the delta variation in coordinates ---*/ VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - + /*--- Retrieve values from the config file ---*/ - + deltaT = config->GetDelta_UnstTimeND(); Lref = config->GetLength_Ref(); - + /*--- Compute delta time based on physical time step ---*/ time_new = static_cast(iter)*deltaT; if (iter == 0) { @@ -877,14 +875,14 @@ void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, Moving = config->GetMarker_All_Moving(iMarker); if (Moving == YES) { for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { - + Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); Marker_Tag = config->GetMarker_All_TagBound(iMarker); - + if (Marker_Tag == Moving_Tag && (config->GetKind_SurfaceMovement(jMarker) == DEFORMING)) { - + /*--- Pitching origin, frequency, and amplitude from config. ---*/ - + for (iDim = 0; iDim < 3; iDim++){ Ampl[iDim] = config->GetMarkerPitching_Ampl(jMarker, iDim)*DEG2RAD; Omega[iDim] = config->GetMarkerPitching_Omega(jMarker, iDim)/config->GetOmega_Ref(); @@ -910,75 +908,75 @@ void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, cout << ") degrees."<< endl; } } - + /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ - + dtheta = -Ampl[0]*(sin(Omega[0]*time_new + Phase[0]) - sin(Omega[0]*time_old + Phase[0])); dphi = -Ampl[1]*(sin(Omega[1]*time_new + Phase[1]) - sin(Omega[1]*time_old + Phase[1])); dpsi = -Ampl[2]*(sin(Omega[2]*time_new + Phase[2]) - sin(Omega[2]*time_old + Phase[2])); - + /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - + cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); - + /*--- Compute the rotation matrix. Note that the implicit ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = cosPhi*sinPsi; rotMatrix[2][0] = -sinPhi; - + rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = sinTheta*cosPhi; - + rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; rotMatrix[2][2] = cosTheta*cosPhi; - + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - + /*--- Index and coordinates of the current point ---*/ - + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); Coord = geometry->node[iPoint]->GetCoord(); - + /*--- Calculate non-dim. position from rotation center ---*/ - + for (iDim = 0; iDim < nDim; iDim++) r[iDim] = (Coord[iDim]-Center[iDim])/Lref; if (nDim == 2) r[nDim] = 0.0; - + /*--- Compute transformed point coordinates ---*/ - + rotCoord[0] = rotMatrix[0][0]*r[0] + rotMatrix[0][1]*r[1] + rotMatrix[0][2]*r[2] + Center[0]; - + rotCoord[1] = rotMatrix[1][0]*r[0] + rotMatrix[1][1]*r[1] + rotMatrix[1][2]*r[2] + Center[1]; - + rotCoord[2] = rotMatrix[2][0]*r[0] + rotMatrix[2][1]*r[1] + rotMatrix[2][2]*r[2] + Center[2]; - + /*--- Calculate delta change in the x, y, & z directions ---*/ for (iDim = 0; iDim < nDim; iDim++) VarCoord[iDim] = (rotCoord[iDim]-Coord[iDim])/Lref; if (nDim == 2) VarCoord[nDim] = 0.0; - + // /*--- Set node displacement for volume deformation ---*/ // geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - + for (iDim = 0; iDim < 3; iDim++){ VarCoordAbs[iDim] = nodes->GetBound_Disp(iPoint, iDim) + VarCoord[iDim]; } - + nodes->SetBound_Disp(iPoint, VarCoordAbs); } } @@ -986,7 +984,7 @@ void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, } } /*--- For pitching we don't update the motion origin and moment reference origin. ---*/ - + } void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, @@ -1001,15 +999,15 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, unsigned short iMarker, jMarker, Moving, iDim, nDim = geometry->GetnDim(); unsigned long iPoint, iVertex; string Marker_Tag, Moving_Tag; - + /*--- Initialize the delta variation in coordinates ---*/ VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - + /*--- Retrieve values from the config file ---*/ - + deltaT = config->GetDelta_UnstTimeND(); Lref = config->GetLength_Ref(); - + /*--- Compute delta time based on physical time step ---*/ time_new = static_cast(iter)*deltaT; if (iter == 0) { @@ -1017,7 +1015,7 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, } else { time_old = static_cast(iter-1)*deltaT; } - + /*--- Store displacement of each node on the rotating surface ---*/ /*--- Loop over markers and find the particular marker(s) (surface) to rotate ---*/ @@ -1025,14 +1023,14 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, Moving = config->GetMarker_All_Moving(iMarker); if (Moving == YES) { for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { - + Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); Marker_Tag = config->GetMarker_All_TagBound(iMarker); - + if (Marker_Tag == Moving_Tag && (config->GetKind_SurfaceMovement(jMarker) == DEFORMING)) { - + /*--- Rotation origin and angular velocity from config. ---*/ - + for (iDim = 0; iDim < 3; iDim++){ Omega[iDim] = config->GetMarkerRotationRate(jMarker, iDim)/config->GetOmega_Ref(); Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); @@ -1050,162 +1048,162 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, cout << ", " << Center[1] << ", " << Center[2] << ")." << endl; } } - + /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ - + dtheta = Omega[0]*(time_new-time_old); dphi = Omega[1]*(time_new-time_old); dpsi = Omega[2]*(time_new-time_old); - + /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - + cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); - + /*--- Compute the rotation matrix. Note that the implicit ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = cosPhi*sinPsi; rotMatrix[2][0] = -sinPhi; - + rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = sinTheta*cosPhi; - + rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; rotMatrix[2][2] = cosTheta*cosPhi; - + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - + /*--- Index and coordinates of the current point ---*/ - + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); Coord = geometry->node[iPoint]->GetCoord(); - + /*--- Calculate non-dim. position from rotation center ---*/ - + for (iDim = 0; iDim < nDim; iDim++) r[iDim] = (Coord[iDim]-Center[iDim])/Lref; if (nDim == 2) r[nDim] = 0.0; - + /*--- Compute transformed point coordinates ---*/ - + rotCoord[0] = rotMatrix[0][0]*r[0] + rotMatrix[0][1]*r[1] + rotMatrix[0][2]*r[2] + Center[0]; - + rotCoord[1] = rotMatrix[1][0]*r[0] + rotMatrix[1][1]*r[1] + rotMatrix[1][2]*r[2] + Center[1]; - + rotCoord[2] = rotMatrix[2][0]*r[0] + rotMatrix[2][1]*r[1] + rotMatrix[2][2]*r[2] + Center[2]; - + /*--- Calculate delta change in the x, y, & z directions ---*/ for (iDim = 0; iDim < nDim; iDim++) VarCoord[iDim] = (rotCoord[iDim]-Coord[iDim])/Lref; if (nDim == 2) VarCoord[nDim] = 0.0; - + // /*--- Set node displacement for volume deformation ---*/ // geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - + for (iDim = 0; iDim < 3; iDim++){ VarCoordAbs[iDim] = nodes->GetBound_Disp(iPoint, iDim) + VarCoord[iDim]; } - + nodes->SetBound_Disp(iPoint, VarCoordAbs); } } } } } - + /*--- When updating the origins it is assumed that all markers have the same rotation movement, because we use the last markers rotation matrix and center ---*/ - + /*--- Set the mesh motion center to the new location after incrementing the position with the rotation. This new location will be used for subsequent mesh motion for the given marker.---*/ - + for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { - + /*-- Check if we want to update the motion origin for the given marker ---*/ - + if (config->GetMoveMotion_Origin(jMarker) == YES) { - + for (iDim = 0; iDim < 3; iDim++){ Center_Aux[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); } - + /*--- Calculate non-dim. position from rotation center ---*/ - + for (iDim = 0; iDim < nDim; iDim++) r[iDim] = (Center_Aux[iDim]-Center[iDim])/Lref; if (nDim == 2) r[nDim] = 0.0; - + /*--- Compute transformed point coordinates ---*/ - + rotCoord[0] = rotMatrix[0][0]*r[0] + rotMatrix[0][1]*r[1] + rotMatrix[0][2]*r[2] + Center[0]; - + rotCoord[1] = rotMatrix[1][0]*r[0] + rotMatrix[1][1]*r[1] + rotMatrix[1][2]*r[2] + Center[1]; - + rotCoord[2] = rotMatrix[2][0]*r[0] + rotMatrix[2][1]*r[1] + rotMatrix[2][2]*r[2] + Center[2]; - + /*--- Calculate delta change in the x, y, & z directions ---*/ for (iDim = 0; iDim < nDim; iDim++) VarCoord[iDim] = (rotCoord[iDim]-Center_Aux[iDim])/Lref; if (nDim == 2) VarCoord[nDim] = 0.0; - + for (iDim = 0; iDim < 3; iDim++){ Center_Aux[iDim] += VarCoord[iDim]; } - config->SetMarkerMotion_Origin(Center_Aux, jMarker); + config->SetMarkerMotion_Origin(Center_Aux, jMarker); } } /*--- Set the moment computation center to the new location after incrementing the position with the rotation. ---*/ - + for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { - + Center_Aux[0] = config->GetRefOriginMoment_X(jMarker); Center_Aux[1] = config->GetRefOriginMoment_Y(jMarker); Center_Aux[2] = config->GetRefOriginMoment_Z(jMarker); /*--- Calculate non-dim. position from rotation center ---*/ - + for (iDim = 0; iDim < nDim; iDim++) r[iDim] = (Center_Aux[iDim]-Center[iDim])/Lref; if (nDim == 2) r[nDim] = 0.0; - + /*--- Compute transformed point coordinates ---*/ - + rotCoord[0] = rotMatrix[0][0]*r[0] + rotMatrix[0][1]*r[1] + rotMatrix[0][2]*r[2] + Center[0]; - + rotCoord[1] = rotMatrix[1][0]*r[0] + rotMatrix[1][1]*r[1] + rotMatrix[1][2]*r[2] + Center[1]; - + rotCoord[2] = rotMatrix[2][0]*r[0] + rotMatrix[2][1]*r[1] + rotMatrix[2][2]*r[2] + Center[2]; - + /*--- Calculate delta change in the x, y, & z directions ---*/ for (iDim = 0; iDim < nDim; iDim++) VarCoord[iDim] = (rotCoord[iDim]-Center_Aux[iDim])/Lref; if (nDim == 2) VarCoord[nDim] = 0.0; - + config->SetRefOriginMoment_X(jMarker, Center_Aux[0]+VarCoord[0]); config->SetRefOriginMoment_Y(jMarker, Center_Aux[1]+VarCoord[1]); config->SetRefOriginMoment_Z(jMarker, Center_Aux[2]+VarCoord[2]); @@ -1222,15 +1220,15 @@ void CMeshSolver::Surface_Plunging(CGeometry *geometry, CConfig *config, unsigned long iPoint, iVertex; string Marker_Tag, Moving_Tag; unsigned short iDim; - + /*--- Initialize the delta variation in coordinates ---*/ VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - + /*--- Retrieve values from the config file ---*/ - + deltaT = config->GetDelta_UnstTimeND(); Lref = config->GetLength_Ref(); - + /*--- Compute delta time based on physical time step ---*/ time_new = static_cast(iter)*deltaT; if (iter == 0) { @@ -1238,22 +1236,22 @@ void CMeshSolver::Surface_Plunging(CGeometry *geometry, CConfig *config, } else { time_old = static_cast(iter-1)*deltaT; } - + /*--- Store displacement of each node on the plunging surface ---*/ /*--- Loop over markers and find the particular marker(s) (surface) to plunge ---*/ - + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { Moving = config->GetMarker_All_Moving(iMarker); if (Moving == YES) { for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { - + Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); Marker_Tag = config->GetMarker_All_TagBound(iMarker); - + if (Marker_Tag == Moving_Tag && (config->GetKind_SurfaceMovement(jMarker) == DEFORMING)) { - + /*--- Plunging frequency and amplitude from config. ---*/ - + for (iDim = 0; iDim < 3; iDim++){ Ampl[iDim] = config->GetMarkerPlunging_Ampl(jMarker, iDim)/Lref; Omega[iDim] = config->GetMarkerPlunging_Omega(jMarker, iDim)/config->GetOmega_Ref(); @@ -1274,15 +1272,15 @@ void CMeshSolver::Surface_Plunging(CGeometry *geometry, CConfig *config, cout << ") degrees."<< endl; } } - + /*--- Compute delta change in the position in the x, y, & z directions. ---*/ - + VarCoord[0] = -Ampl[0]*(sin(Omega[0]*time_new) - sin(Omega[0]*time_old)); VarCoord[1] = -Ampl[1]*(sin(Omega[1]*time_new) - sin(Omega[1]*time_old)); VarCoord[2] = -Ampl[2]*(sin(Omega[2]*time_new) - sin(Omega[2]*time_old)); - + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - + // /*--- Set node displacement for volume deformation ---*/ // geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); @@ -1291,37 +1289,37 @@ void CMeshSolver::Surface_Plunging(CGeometry *geometry, CConfig *config, for (iDim = 0; iDim < 3; iDim++){ VarCoordAbs[iDim] = nodes->GetBound_Disp(iPoint, iDim) + VarCoord[iDim]; } - + nodes->SetBound_Disp(iPoint, VarCoordAbs); - + } } } } } - + /*--- When updating the origins it is assumed that all markers have the same plunging movement, because we use the last VarCoord set ---*/ - + /*--- Set the mesh motion center to the new location after incrementing the position with the translation. This new location will be used for subsequent mesh motion for the given marker.---*/ - + for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { - + /*-- Check if we want to update the motion origin for the given marker ---*/ - + if (config->GetMoveMotion_Origin(jMarker) == YES) { for (iDim = 0; iDim < 3; iDim++){ Center[iDim] += VarCoord[iDim]; } - config->SetMarkerMotion_Origin(Center, jMarker); + config->SetMarkerMotion_Origin(Center, jMarker); } } - + /*--- Set the moment computation center to the new location after incrementing the position with the plunging. ---*/ - + for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { Center[0] = config->GetRefOriginMoment_X(jMarker) + VarCoord[0]; Center[1] = config->GetRefOriginMoment_Y(jMarker) + VarCoord[1]; @@ -1342,14 +1340,14 @@ void CMeshSolver::Surface_Translating(CGeometry *geometry, CConfig *config, unsigned long iPoint, iVertex; string Marker_Tag, Moving_Tag; unsigned short iDim; - + /*--- Initialize the delta variation in coordinates ---*/ VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - + /*--- Retrieve values from the config file ---*/ - + deltaT = config->GetDelta_UnstTimeND(); - + /*--- Compute delta time based on physical time step ---*/ time_new = static_cast(iter)*deltaT; if (iter == 0) { @@ -1357,29 +1355,29 @@ void CMeshSolver::Surface_Translating(CGeometry *geometry, CConfig *config, } else { time_old = static_cast(iter-1)*deltaT; } - + /*--- Store displacement of each node on the translating surface ---*/ /*--- Loop over markers and find the particular marker(s) (surface) to translate ---*/ - + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { Moving = config->GetMarker_All_Moving(iMarker); if (Moving == YES) { for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { - + Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); Marker_Tag = config->GetMarker_All_TagBound(iMarker); - + if (Marker_Tag == Moving_Tag && (config->GetKind_SurfaceMovement(jMarker) == DEFORMING)) { for (iDim = 0; iDim < 3; iDim++){ xDot[iDim] = config->GetMarkerTranslationRate(jMarker, iDim); Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); } - + /*--- Print some information to the console. Be verbose at the first iteration only (mostly for debugging purposes). ---*/ // Note that the MASTER_NODE might not contain all the markers being moved. - + if (rank == MASTER_NODE) { cout << " Storing translating displacement for marker: "; cout << Marker_Tag << "." << endl; @@ -1390,53 +1388,53 @@ void CMeshSolver::Surface_Translating(CGeometry *geometry, CConfig *config, else cout << ") ft/s." << endl; } } - + /*--- Compute delta change in the position in the x, y, & z directions. ---*/ - + VarCoord[0] = xDot[0]*(time_new-time_old); VarCoord[1] = xDot[1]*(time_new-time_old); VarCoord[2] = xDot[2]*(time_new-time_old); - + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - + // /*--- Set node displacement for volume deformation ---*/ // geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); for (iDim = 0; iDim < 3; iDim++){ VarCoordAbs[iDim] = nodes->GetBound_Disp(iPoint, iDim) + VarCoord[iDim]; } - + nodes->SetBound_Disp(iPoint, VarCoordAbs); } } } } } - + /*--- When updating the origins it is assumed that all markers have the same translational velocity, because we use the last VarCoord set ---*/ - + /*--- Set the mesh motion center to the new location after incrementing the position with the translation. This new location will be used for subsequent mesh motion for the given marker.---*/ - + for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { - + /*-- Check if we want to update the motion origin for the given marker ---*/ - + if (config->GetMoveMotion_Origin(jMarker) == YES) { for (iDim = 0; iDim < 3; iDim++){ Center[iDim] += VarCoord[iDim]; } - config->SetMarkerMotion_Origin(Center, jMarker); + config->SetMarkerMotion_Origin(Center, jMarker); } } - + /*--- Set the moment computation center to the new location after incrementing the position with the translation. ---*/ - + for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { Center[0] = config->GetRefOriginMoment_X(jMarker) + VarCoord[0]; Center[1] = config->GetRefOriginMoment_Y(jMarker) + VarCoord[1]; From c355415d65e5752cfacbe336c5af23f6aa9c6b1d Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 26 Mar 2020 09:06:33 +0000 Subject: [PATCH 34/79] remove legacy FSI transfer classes --- Common/include/option_structure.hpp | 2 - .../CDiscAdjDisplacementsInterfaceLegacy.hpp | 94 ------------------- .../fsi/CDisplacementsInterfaceLegacy.hpp | 93 ------------------ SU2_CFD/obj/Makefile.am | 2 - SU2_CFD/src/drivers/CDriver.cpp | 29 ++---- SU2_CFD/src/drivers/CMultizoneDriver.cpp | 14 --- .../CDiscAdjDisplacementsInterfaceLegacy.cpp | 93 ------------------ .../fsi/CDisplacementsInterfaceLegacy.cpp | 72 -------------- SU2_CFD/src/meson.build | 4 +- 9 files changed, 7 insertions(+), 396 deletions(-) delete mode 100644 SU2_CFD/include/interfaces/fsi/CDiscAdjDisplacementsInterfaceLegacy.hpp delete mode 100644 SU2_CFD/include/interfaces/fsi/CDisplacementsInterfaceLegacy.hpp delete mode 100644 SU2_CFD/src/interfaces/fsi/CDiscAdjDisplacementsInterfaceLegacy.cpp delete mode 100644 SU2_CFD/src/interfaces/fsi/CDisplacementsInterfaceLegacy.cpp diff --git a/Common/include/option_structure.hpp b/Common/include/option_structure.hpp index 1387b3227064..20cba60d8d4b 100644 --- a/Common/include/option_structure.hpp +++ b/Common/include/option_structure.hpp @@ -372,9 +372,7 @@ enum ENUM_TRANSFER { NO_COMMON_INTERFACE = 1, /*!< \brief No common interface between the zones (geometrical). */ NO_TRANSFER = 2, /*!< \brief Zones may share a boundary, but still no coupling desired. */ FLOW_TRACTION = 10, /*!< \brief Flow traction coupling (between fluids and solids). */ - STRUCTURAL_DISPLACEMENTS_LEGACY = 11, /*!< \brief Structural displacements (between fluids and solids) - legacy version (to be removed). */ BOUNDARY_DISPLACEMENTS = 21, /*!< \brief Boundary displacements (between fluids and solids) */ - STRUCTURAL_DISPLACEMENTS_DISC_ADJ = 12, /*!< \brief Adjoints of structural displacements (between fluids and solids). */ SLIDING_INTERFACE = 13, /*!< \brief Sliding interface (between fluids). */ CONSERVATIVE_VARIABLES = 14, /*!< \brief General coupling that simply transfers the conservative variables (between same solvers). */ MIXING_PLANE = 15, /*!< \brief Mixing plane between fluids. */ diff --git a/SU2_CFD/include/interfaces/fsi/CDiscAdjDisplacementsInterfaceLegacy.hpp b/SU2_CFD/include/interfaces/fsi/CDiscAdjDisplacementsInterfaceLegacy.hpp deleted file mode 100644 index 2944bc5c9dad..000000000000 --- a/SU2_CFD/include/interfaces/fsi/CDiscAdjDisplacementsInterfaceLegacy.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/*! - * \file CDiscAdjDisplacementsInterfaceLegacy.hpp - * \brief Declaration and inlines of the class to transfer structural displacements - * from a structural zone into a fluid zone in a discrete adjoint simulation. - * \author Ruben Sanchez - * \version 7.0.2 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "../CInterface.hpp" - -class CDiscAdjDisplacementsInterfaceLegacy : public CInterface { - -protected: - -public: - - /*! - * \brief Constructor of the class. - */ - CDiscAdjDisplacementsInterfaceLegacy(void); - - /*! - * \overload - * \param[in] val_nVar - Number of variables that need to be transferred. - * \param[in] config - Definition of the particular problem. - */ - CDiscAdjDisplacementsInterfaceLegacy(unsigned short val_nVar, unsigned short val_nConst, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - virtual ~CDiscAdjDisplacementsInterfaceLegacy(void); - - /*! - * \brief Retrieve some constants needed for the calculations. - * \param[in] donor_solution - Solution from the donor mesh. - * \param[in] target_solution - Solution from the target mesh. - * \param[in] donor_geometry - Geometry of the donor mesh. - * \param[in] target_geometry - Geometry of the target mesh. - * \param[in] donor_config - Definition of the problem at the donor mesh. - * \param[in] target_config - Definition of the problem at the target mesh. - */ - void GetPhysical_Constants(CSolver *donor_solution, CSolver *target_solution, - CGeometry *donor_geometry, CGeometry *target_geometry, - CConfig *donor_config, CConfig *target_config); - - /*! - * \brief Retrieve the variable that will be sent from donor mesh to target mesh. - * \param[in] donor_solution - Solution from the donor mesh. - * \param[in] donor_geometry - Geometry of the donor mesh. - * \param[in] donor_config - Definition of the problem at the donor mesh. - * \param[in] Marker_Donor - Index of the donor marker. - * \param[in] Vertex_Donor - Index of the donor vertex. - */ - void GetDonor_Variable(CSolver *struct_solution, CGeometry *struct_geometry, CConfig *struct_config, - unsigned long Marker_Struct, unsigned long Vertex_Struct, unsigned long Point_Struct); - - /*! - * \brief Set the variable that has been received from the target mesh into the target mesh. - * \param[in] target_solution - Solution from the target mesh. - * \param[in] target_geometry - Geometry of the target mesh. - * \param[in] target_config - Definition of the problem at the target mesh. - * \param[in] Marker_Target - Index of the target marker. - * \param[in] Vertex_Target - Index of the target vertex. - * \param[in] Point_Target - Index of the target point. - */ - void SetTarget_Variable(CSolver *flow_solution, CGeometry *flow_geometry, - CConfig *flow_config, unsigned long Marker_Flow, - unsigned long Vertex_Flow, unsigned long Point_Flow); - -}; - diff --git a/SU2_CFD/include/interfaces/fsi/CDisplacementsInterfaceLegacy.hpp b/SU2_CFD/include/interfaces/fsi/CDisplacementsInterfaceLegacy.hpp deleted file mode 100644 index 0fadb5d9b6d0..000000000000 --- a/SU2_CFD/include/interfaces/fsi/CDisplacementsInterfaceLegacy.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/*! - * \file CDisplacementsInterfaceLegacy.hpp - * \brief Declaration and inlines of the class to transfer structural displacements - * from a structural zone into a fluid zone. - * \author Ruben Sanchez - * \version 7.0.2 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "../CInterface.hpp" - -class CDisplacementsInterfaceLegacy : public CInterface { - -protected: - -public: - - /*! - * \brief Constructor of the class. - */ - CDisplacementsInterfaceLegacy(void); - - /*! - * \overload - * \param[in] val_nVar - Number of variables that need to be transferred. - * \param[in] config - Definition of the particular problem. - */ - CDisplacementsInterfaceLegacy(unsigned short val_nVar, unsigned short val_nConst, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - virtual ~CDisplacementsInterfaceLegacy(void); - - /*! - * \brief Retrieve some constants needed for the calculations. - * \param[in] donor_solution - Solution from the donor mesh. - * \param[in] target_solution - Solution from the target mesh. - * \param[in] donor_geometry - Geometry of the donor mesh. - * \param[in] target_geometry - Geometry of the target mesh. - * \param[in] donor_config - Definition of the problem at the donor mesh. - * \param[in] target_config - Definition of the problem at the target mesh. - */ - void GetPhysical_Constants(CSolver *donor_solution, CSolver *target_solution, - CGeometry *donor_geometry, CGeometry *target_geometry, - CConfig *donor_config, CConfig *target_config); - - /*! - * \brief Retrieve the variable that will be sent from donor mesh to target mesh. - * \param[in] donor_solution - Solution from the donor mesh. - * \param[in] donor_geometry - Geometry of the donor mesh. - * \param[in] donor_config - Definition of the problem at the donor mesh. - * \param[in] Marker_Donor - Index of the donor marker. - * \param[in] Vertex_Donor - Index of the donor vertex. - */ - void GetDonor_Variable(CSolver *struct_solution, CGeometry *struct_geometry, CConfig *struct_config, - unsigned long Marker_Struct, unsigned long Vertex_Struct, unsigned long Point_Struct); - - /*! - * \brief Set the variable that has been received from the target mesh into the target mesh. - * \param[in] target_solution - Solution from the target mesh. - * \param[in] target_geometry - Geometry of the target mesh. - * \param[in] target_config - Definition of the problem at the target mesh. - * \param[in] Marker_Target - Index of the target marker. - * \param[in] Vertex_Target - Index of the target vertex. - * \param[in] Point_Target - Index of the target point. - */ - void SetTarget_Variable(CSolver *flow_solution, CGeometry *flow_geometry, - CConfig *flow_config, unsigned long Marker_Flow, - unsigned long Vertex_Flow, unsigned long Point_Flow); - -}; diff --git a/SU2_CFD/obj/Makefile.am b/SU2_CFD/obj/Makefile.am index a46d07ef0b79..1842aff6fe68 100644 --- a/SU2_CFD/obj/Makefile.am +++ b/SU2_CFD/obj/Makefile.am @@ -163,8 +163,6 @@ libSU2Core_sources = ../src/definition_structure.cpp \ ../src/interfaces/fsi/CDisplacementsInterface.cpp \ ../src/interfaces/fsi/CFlowTractionInterface.cpp \ ../src/interfaces/fsi/CDiscAdjFlowTractionInterface.cpp \ - ../src/interfaces/fsi/CDisplacementsInterfaceLegacy.cpp \ - ../src/interfaces/fsi/CDiscAdjDisplacementsInterfaceLegacy.cpp \ ../src/transport_model.cpp \ ../src/variables/CFEABoundVariable.cpp \ ../src/variables/CRadVariable.cpp \ diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index b0a48b0c6a3b..bc3658c3c9fe 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -51,8 +51,6 @@ #include "../../include/interfaces/fsi/CDisplacementsInterface.hpp" #include "../../include/interfaces/fsi/CFlowTractionInterface.hpp" #include "../../include/interfaces/fsi/CDiscAdjFlowTractionInterface.hpp" -#include "../../include/interfaces/fsi/CDisplacementsInterfaceLegacy.hpp" -#include "../../include/interfaces/fsi/CDiscAdjDisplacementsInterfaceLegacy.hpp" #include "../../include/numerics/template.hpp" #include "../../include/numerics/transition.hpp" @@ -2682,27 +2680,12 @@ void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGe if (rank == MASTER_NODE) cout << "flow tractions. " << endl; } else if (structural_donor && fluid_target) { - /*--- If we are using the new mesh solver, we transfer the total boundary displacements (not incremental) --*/ - if (solver_container[targetZone][INST_0][MESH_0][MESH_SOL] != NULL) { - interface_types[donorZone][targetZone] = BOUNDARY_DISPLACEMENTS; - nVarTransfer = 0; - interface[donorZone][targetZone] = new CDisplacementsInterface(nVar, nVarTransfer, config[donorZone]); - if (rank == MASTER_NODE) cout << "boundary displacements from the structural solver. " << endl; - } - /*--- We keep the legacy method temporarily until FSI-adjoint has been adapted ---*/ - /// TODO: LEGACY CLEANUP remove the "else" part and every class and enum referenced there, - /// add a check above to make sure MESH_SOL has been instantiated. - else { - nVarTransfer = 0; - if(!discrete_adjoint) { - interface_types[donorZone][targetZone] = STRUCTURAL_DISPLACEMENTS_LEGACY; - interface[donorZone][targetZone] = new CDisplacementsInterfaceLegacy(nVar, nVarTransfer, config[donorZone]); - } else { - interface_types[donorZone][targetZone] = STRUCTURAL_DISPLACEMENTS_DISC_ADJ; - interface[donorZone][targetZone] = new CDiscAdjDisplacementsInterfaceLegacy(nVar, nVarTransfer, config[donorZone]); - } - if (rank == MASTER_NODE) cout << "structural displacements (legacy). " << endl; - } + if (solver_container[targetZone][INST_0][MESH_0][MESH_SOL] == nullptr) + SU2_MPI::Error("Mesh deformation was not correctly specified for the fluid zone.", CURRENT_FUNCTION); + interface_types[donorZone][targetZone] = BOUNDARY_DISPLACEMENTS; + nVarTransfer = 0; + interface[donorZone][targetZone] = new CDisplacementsInterface(nVar, nVarTransfer, config[donorZone]); + if (rank == MASTER_NODE) cout << "boundary displacements from the structural solver. " << endl; } else if (fluid_donor && fluid_target) { interface_types[donorZone][targetZone] = SLIDING_INTERFACE; diff --git a/SU2_CFD/src/drivers/CMultizoneDriver.cpp b/SU2_CFD/src/drivers/CMultizoneDriver.cpp index 66db6a2544cc..0f4ebb3727e1 100644 --- a/SU2_CFD/src/drivers/CMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CMultizoneDriver.cpp @@ -617,13 +617,6 @@ bool CMultizoneDriver::Transfer_Data(unsigned short donorZone, unsigned short ta targetSolver = HEAT_SOL; break; } - case STRUCTURAL_DISPLACEMENTS_LEGACY: - { - donorSolver = FEA_SOL; - targetSolver = FLOW_SOL; - UpdateMesh = true; - break; - } case BOUNDARY_DISPLACEMENTS: { donorSolver = FEA_SOL; @@ -631,13 +624,6 @@ bool CMultizoneDriver::Transfer_Data(unsigned short donorZone, unsigned short ta UpdateMesh = true; break; } - case STRUCTURAL_DISPLACEMENTS_DISC_ADJ: - { - donorSolver = FEA_SOL; - targetSolver = FLOW_SOL; - UpdateMesh = true; - break; - } case FLOW_TRACTION: { donorSolver = FLOW_SOL; diff --git a/SU2_CFD/src/interfaces/fsi/CDiscAdjDisplacementsInterfaceLegacy.cpp b/SU2_CFD/src/interfaces/fsi/CDiscAdjDisplacementsInterfaceLegacy.cpp deleted file mode 100644 index 68a431bce165..000000000000 --- a/SU2_CFD/src/interfaces/fsi/CDiscAdjDisplacementsInterfaceLegacy.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/*! - * \file CDiscAdjDisplacementsInterfaceLegacy.cpp - * \brief Declaration and inlines of the class to transfer structural displacements - * from a structural zone into a fluid zone in a discrete adjoint simulation. - * \author Ruben Sanchez - * \version 7.0.2 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#include "../../../include/interfaces/fsi/CDiscAdjDisplacementsInterfaceLegacy.hpp" - -CDiscAdjDisplacementsInterfaceLegacy::CDiscAdjDisplacementsInterfaceLegacy(void) : CInterface() { - -} - -CDiscAdjDisplacementsInterfaceLegacy::CDiscAdjDisplacementsInterfaceLegacy(unsigned short val_nVar, - unsigned short val_nConst, - CConfig *config) - : CInterface(val_nVar, - val_nConst, - config) { - -} - -CDiscAdjDisplacementsInterfaceLegacy::~CDiscAdjDisplacementsInterfaceLegacy(void) { - -} - - -void CDiscAdjDisplacementsInterfaceLegacy::GetPhysical_Constants(CSolver *struct_solution, - CSolver *flow_solution, - CGeometry *struct_geometry, - CGeometry *flow_geometry, - CConfig *struct_config, - CConfig *flow_config) { -} - -void CDiscAdjDisplacementsInterfaceLegacy::GetDonor_Variable(CSolver *struct_solution, - CGeometry *struct_geometry, - CConfig *struct_config, - unsigned long Marker_Struct, - unsigned long Vertex_Struct, - unsigned long Point_Struct) { - - - su2double *Coord_Struct, *Displacement_Struct; - unsigned short iVar; - - Coord_Struct = struct_geometry->node[Point_Struct]->GetCoord(); - - /*--- The displacements come from the predicted solution ---*/ - Displacement_Struct = struct_solution->GetNodes()->GetSolution(Point_Struct); - - for (iVar = 0; iVar < nVar; iVar++) - Donor_Variable[iVar] = Coord_Struct[iVar] + Displacement_Struct[iVar]; -} - -void CDiscAdjDisplacementsInterfaceLegacy::SetTarget_Variable(CSolver *flow_solution, - CGeometry *flow_geometry, - CConfig *flow_config, - unsigned long Marker_Flow, - unsigned long Vertex_Flow, - unsigned long Point_Flow) { - - su2double *Coord, VarCoord[3] = {0.0, 0.0, 0.0}; - unsigned short iVar; - - Coord = flow_geometry->node[Point_Flow]->GetCoord(); - - for (iVar = 0; iVar < nVar; iVar++) - VarCoord[iVar] = Target_Variable[iVar]-Coord[iVar]; - - flow_geometry->vertex[Marker_Flow][Vertex_Flow]->SetVarCoord(VarCoord); -} diff --git a/SU2_CFD/src/interfaces/fsi/CDisplacementsInterfaceLegacy.cpp b/SU2_CFD/src/interfaces/fsi/CDisplacementsInterfaceLegacy.cpp deleted file mode 100644 index 4e0d4d9204f6..000000000000 --- a/SU2_CFD/src/interfaces/fsi/CDisplacementsInterfaceLegacy.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/*! - * \file CDisplacementsInterfaceLegacy.cpp - * \brief Declaration and inlines of the class to transfer structural displacements - * from a structural zone into a fluid zone. - * \author Ruben Sanchez - * \version 7.0.2 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#include "../../../include/interfaces/fsi/CDisplacementsInterfaceLegacy.hpp" - -CDisplacementsInterfaceLegacy::CDisplacementsInterfaceLegacy(void) : CInterface() { - -} - -CDisplacementsInterfaceLegacy::CDisplacementsInterfaceLegacy(unsigned short val_nVar, - unsigned short val_nConst, CConfig *config) : - CInterface(val_nVar, val_nConst, config) { - -} - -CDisplacementsInterfaceLegacy::~CDisplacementsInterfaceLegacy(void) { - -} - - -void CDisplacementsInterfaceLegacy::GetPhysical_Constants(CSolver *struct_solution, CSolver *flow_solution, - CGeometry *struct_geometry, CGeometry *flow_geometry, - CConfig *struct_config, CConfig *flow_config) { -} - -void CDisplacementsInterfaceLegacy::GetDonor_Variable(CSolver *struct_solution, CGeometry *struct_geometry, - CConfig *struct_config, unsigned long Marker_Struct, - unsigned long Vertex_Struct, unsigned long Point_Struct) { - - su2double *DisplacementDonor, *DisplacementDonor_Prev; - unsigned short iVar; - - /*--- The displacements come from the predicted solution ---*/ - DisplacementDonor = struct_solution->GetNodes()->GetSolution_Pred(Point_Struct); - - DisplacementDonor_Prev = struct_solution->GetNodes()->GetSolution_Pred_Old(Point_Struct); - - for (iVar = 0; iVar < nVar; iVar++) - Donor_Variable[iVar] = DisplacementDonor[iVar] - DisplacementDonor_Prev[iVar]; -} - -void CDisplacementsInterfaceLegacy::SetTarget_Variable(CSolver *flow_solution, CGeometry *flow_geometry, - CConfig *flow_config, unsigned long Marker_Flow, - unsigned long Vertex_Flow, unsigned long Point_Flow) { - - flow_geometry->vertex[Marker_Flow][Vertex_Flow]->SetVarCoord(Target_Variable); -} diff --git a/SU2_CFD/src/meson.build b/SU2_CFD/src/meson.build index 20efb35eea45..b45bf0ebda1c 100644 --- a/SU2_CFD/src/meson.build +++ b/SU2_CFD/src/meson.build @@ -131,9 +131,7 @@ su2_cfd_src += files(['interfaces/CInterface.cpp', 'interfaces/cht/CConjugateHeatInterface.cpp', 'interfaces/fsi/CDisplacementsInterface.cpp', 'interfaces/fsi/CFlowTractionInterface.cpp', - 'interfaces/fsi/CDiscAdjFlowTractionInterface.cpp', - 'interfaces/fsi/CDisplacementsInterfaceLegacy.cpp', - 'interfaces/fsi/CDiscAdjDisplacementsInterfaceLegacy.cpp']) + 'interfaces/fsi/CDiscAdjFlowTractionInterface.cpp']) su2_cfd_src += files(['drivers/CDriver.cpp', 'drivers/CMultizoneDriver.cpp', From a0f1bba11d2a762ddeceff531fe3e38d2907cc4f Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 26 Mar 2020 09:11:21 +0000 Subject: [PATCH 35/79] remove CDiscAdjFSIDriver --- SU2_CFD/include/drivers/CDriver.hpp | 266 ----- SU2_CFD/src/SU2_CFD.cpp | 15 +- SU2_CFD/src/drivers/CDriver.cpp | 1544 --------------------------- 3 files changed, 1 insertion(+), 1824 deletions(-) diff --git a/SU2_CFD/include/drivers/CDriver.hpp b/SU2_CFD/include/drivers/CDriver.hpp index 5889aa6cee53..cc2d9a42d75e 100644 --- a/SU2_CFD/include/drivers/CDriver.hpp +++ b/SU2_CFD/include/drivers/CDriver.hpp @@ -1082,269 +1082,3 @@ class CHBDriver : public CFluidDriver { */ void ResetConvergence(); }; - -/*! - * \class CDiscAdjFSIDriver - * \brief Overload: Class for driving a discrete adjoint FSI iteration. - * \author R. Sanchez. - * \version 7.0.2 "Blackbird" - */ -class CDiscAdjFSIDriver : public CDriver { - - COutputLegacy* output_legacy; - - CIteration** direct_iteration; - unsigned short RecordingState; - unsigned short CurrentRecording; /*!< \brief Stores the current status of the recording. */ - unsigned short Kind_Objective_Function; /*!< \brief Stores the kind of objective function of the recording. */ - - su2double *init_res_flow, /*!< \brief Stores the initial residual for the flow. */ - *init_res_struct, /*!< \brief Stores the initial residual for the structure. */ - *residual_flow, /*!< \brief Stores the current residual for the flow. */ - *residual_struct, /*!< \brief Stores the current residual for the structure. */ - *residual_flow_rel, - *residual_struct_rel; - - su2double flow_criteria, - flow_criteria_rel, - structure_criteria, - structure_criteria_rel; - - - enum OF_KIND{ - NO_OBJECTIVE_FUNCTION = 0, /*!< \brief Indicates that there is no objective function. */ - FLOW_OBJECTIVE_FUNCTION = 1, /*!< \brief Indicates that the objective function is only flow-dependent. */ - FEM_OBJECTIVE_FUNCTION = 2 /*!< \brief Indicates that the objective function is only structural-dependent. */ - }; - -public: - - /*! - * \brief Constructor of the class. - * \param[in] confFile - Configuration file name. - * \param[in] val_nZone - Total number of zones. - * \param[in] val_nDim - Total number of dimensions. - * \param[in] MPICommunicator - MPI communicator for SU2. - */ - CDiscAdjFSIDriver(char* confFile, - unsigned short val_nZone, - SU2_Comm MPICommunicator); - - /*! - * \brief Destructor of the class. - */ - ~CDiscAdjFSIDriver(void); - - /*! - * \brief Launch the computation for FSI adjoint (legacy) driver - */ - inline void StartSolver(){ - - /*--- Run the solver. ---*/ - if (rank == MASTER_NODE) - cout << endl <<"------------------------------ Begin Solver -----------------------------" << endl; - Run(); - } - - /*! - * \brief Run a Discrete Adjoint iteration for the FSI problem. - * \param[in] iteration_container - Container vector with all the iteration methods. - * \param[in] output - Pointer to the COutput class. - * \param[in] integration_container - Container vector with all the integration methods. - * \param[in] geometry_container - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] numerics_container - Description of the numerical method (the way in which the equations are solved). - * \param[in] config_container - Definition of the particular problem. - * \param[in] surface_movement - Surface movement classes of the problem. - * \param[in] grid_movement - Volume grid movement classes of the problem. - * \param[in] FFDBox - FFD FFDBoxes of the problem. - */ - - void Run(); - - /*! - * \brief Iterate the direct solver for recording. - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - - void Iterate_Direct(unsigned short ZONE_FLOW, unsigned short ZONE_STRUCT, unsigned short kind_recording); - - /*! - * \brief Run a direct flow iteration. - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - */ - void Fluid_Iteration_Direct(unsigned short ZONE_FLOW, unsigned short ZONE_STRUCT); - - /*! - * \brief Run a direct structural iteration. - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - */ - void Structural_Iteration_Direct(unsigned short ZONE_FLOW, unsigned short ZONE_STRUCT); - - /*! - * \brief Run a direct mesh deformation. - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - */ - void Mesh_Deformation_Direct(unsigned short ZONE_FLOW, unsigned short ZONE_STRUCT); - - /*! - * \brief Set the recording for a Discrete Adjoint iteration for the FSI problem. - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - - void SetRecording(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording); - - /*! - * \brief Load the restarts for fluid, structure and mesh. - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - void Preprocess(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording); - - /*! - * \brief Iterate a certain block for adjoint FSI - may be the whole set of variables or independent and subiterate - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - void Iterate_Block(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording); - - /*! - * \brief Initialize the adjoint - set the objective funcition and the output of the adjoint iteration - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - void InitializeAdjoint(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording); - - /*! - * \brief Extract the adjoint solution variables - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - void ExtractAdjoint(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording); - - - /*! - * \brief Check the convergence of the problem - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - bool CheckConvergence(unsigned long IntIter, - unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording); - - /*! - * \brief Check the convergence of BGS subiteration process - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - bool BGSConvergence(unsigned long IntIter, - unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT); - - - /*! - * \brief Output the convergence history - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - void ConvergenceHistory(unsigned long IntIter, - unsigned long nIntIter, - unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording); - - /*! - * \brief Load the restarts for fluid, structure and mesh. - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - void PrintDirect_Residuals(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording); - - /*! - * \brief Restart the variables to the converged solution. - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - void PrepareRecording(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording); - - /*! - * \brief Register the input variables for adjoint FSI problems: flow conservative, fluid mesh position and structural displacements. - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - void RegisterInput(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording); - - /*! - * \brief Register the input variables for adjoint FSI problems: flow conservative, fluid mesh position and structural displacements. - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - void SetDependencies(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording); - - /*! - * \brief Restart the output variables for adjoint FSI problems: flow conservative, fluid mesh position and structural displacements. - * \param[in] ZONE_FLOW - zone of the fluid solver. - * \param[in] ZONE_STRUCT - zone of the structural solver. - * \param[in] kind_recording - kind of recording (flow, structure, mesh, cross terms) - */ - void RegisterOutput(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording); - - /*! - * \brief Overload, does nothing but avoids dynamic mesh updates in adjoint FSI problems before the iteration - */ - void DynamicMeshUpdate(unsigned long TimeIter); - - /*! - * \brief Transfer the displacements computed on the structural solver into the fluid solver. - * \param[in] donorZone - zone in which the displacements will be transferred. - * \param[in] targetZone - zone which receives the tractions transferred. - */ - void Transfer_Displacements(unsigned short donorZone, unsigned short targetZone); - - /*! - * \brief Transfer the tractions computed on the fluid solver into the structural solver. - * \param[in] donorZone - zone from which the tractions will be transferred. - * \param[in] targetZone - zone which receives the tractions transferred. - */ - void Transfer_Tractions(unsigned short donorZone, unsigned short targetZone); - -}; diff --git a/SU2_CFD/src/SU2_CFD.cpp b/SU2_CFD/src/SU2_CFD.cpp index 229aaab1f7e1..d5c5b3169f8f 100644 --- a/SU2_CFD/src/SU2_CFD.cpp +++ b/SU2_CFD/src/SU2_CFD.cpp @@ -100,7 +100,6 @@ int main(int argc, char *argv[]) { CConfig* config = new CConfig(config_file_name, SU2_CFD); unsigned short nZone = config->GetnZone(); - bool fsi = config->GetFSI_Simulation(); bool turbo = config->GetBoolTurbomachinery(); /*--- First, given the basic information about the number of zones and the @@ -131,7 +130,7 @@ int main(int argc, char *argv[]) { } } - else if (multizone && !turbo && !fsi) { + else if (multizone && !turbo) { /*--- Generic multizone problems. ---*/ if (disc_adj) { @@ -147,18 +146,6 @@ int main(int argc, char *argv[]) { /*--- Harmonic balance problem: instantiate the Harmonic Balance driver class. ---*/ driver = new CHBDriver(config_file_name, nZone, MPICommunicator); - } - else if (fsi && disc_adj) { - - /*--- Discrete adjoint FSI problem with the legacy driver. ---*/ - if (config->GetTime_Domain()) - SU2_MPI::Error("There is no discrete adjoint implementation for dynamic FSI. ", CURRENT_FUNCTION); - - if (nZone != 2) - SU2_MPI::Error("The legacy discrete adjoint FSI driver only works for two-zone problems. ", CURRENT_FUNCTION); - - driver = new CDiscAdjFSIDriver(config_file_name, nZone, MPICommunicator); - } else if (turbo) { diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index bc3658c3c9fe..6ff2d2e85996 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -4113,1547 +4113,3 @@ void CHBDriver::ComputeHB_Operator() { delete [] Omega_HB; } - -CDiscAdjFSIDriver::CDiscAdjFSIDriver(char* confFile, - unsigned short val_nZone, - SU2_Comm MPICommunicator) : CDriver(confFile, - val_nZone, - MPICommunicator, - false) { - - unsigned short iVar; - unsigned short nVar_Flow = 0, nVar_Struct = 0; - RecordingState = 0; - CurrentRecording = 0; - - switch (config_container[ZONE_0]->GetKind_ObjFunc()){ - case DRAG_COEFFICIENT: - case LIFT_COEFFICIENT: - case SIDEFORCE_COEFFICIENT: - case EFFICIENCY: - case MOMENT_X_COEFFICIENT: - case MOMENT_Y_COEFFICIENT: - case MOMENT_Z_COEFFICIENT: - case EQUIVALENT_AREA: - Kind_Objective_Function = FLOW_OBJECTIVE_FUNCTION; - break; - case REFERENCE_GEOMETRY: - case REFERENCE_NODE: - case VOLUME_FRACTION: - case TOPOL_DISCRETENESS: - case TOPOL_COMPLIANCE: - Kind_Objective_Function = FEM_OBJECTIVE_FUNCTION; - break; - default: - Kind_Objective_Function = NO_OBJECTIVE_FUNCTION; - break; - } - - direct_iteration = new CIteration*[nZone]; - - unsigned short iZone; - for (iZone = 0; iZone < nZone; iZone++){ - switch (config_container[iZone]->GetKind_Solver()) { - case DISC_ADJ_INC_RANS: case DISC_ADJ_INC_EULER: case DISC_ADJ_INC_NAVIER_STOKES: - case DISC_ADJ_RANS: case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: - direct_iteration[iZone] = new CFluidIteration(config_container[iZone]); - nVar_Flow = solver_container[iZone][INST_0][MESH_0][ADJFLOW_SOL]->GetnVar(); - flow_criteria = -8.0; // Temporarily hard coded until adapted into new structure - flow_criteria_rel = 3.0; - break; - case DISC_ADJ_FEM: - direct_iteration[iZone] = new CFEAIteration(config_container[iZone]); - nVar_Struct = solver_container[iZone][INST_0][MESH_0][ADJFEA_SOL]->GetnVar(); - structure_criteria = -8.0; - structure_criteria_rel = 3.0; - break; - } - } - - init_res_flow = new su2double[nVar_Flow]; - init_res_struct = new su2double[nVar_Struct]; - - residual_flow = new su2double[nVar_Flow]; - residual_struct = new su2double[nVar_Struct]; - - residual_flow_rel = new su2double[nVar_Flow]; - residual_struct_rel = new su2double[nVar_Struct]; - - for (iVar = 0; iVar < nVar_Flow; iVar++){ - init_res_flow[iVar] = 0.0; - residual_flow[iVar] = 0.0; - residual_flow_rel[iVar] = 0.0; - } - for (iVar = 0; iVar < nVar_Struct; iVar++){ - init_res_struct[iVar] = 0.0; - residual_struct[iVar] = 0.0; - residual_struct_rel[iVar] = 0.0; - } - - - bool write_history = true; - - /*--- Header of the temporary output file ---*/ - if ((write_history) && (rank == MASTER_NODE)){ - ofstream myfile_res; - myfile_res.open ("history_adjoint_FSI.csv"); - - myfile_res << "BGS_Iter\t"; - - for (iVar = 0; iVar < nVar_Flow; iVar++){ - myfile_res << "ResFlow[" << iVar << "]\t"; - } - - for (iVar = 0; iVar < nVar_Struct; iVar++){ - myfile_res << "ResFEA[" << iVar << "]\t"; - } - - - bool de_effects = config_container[ZONE_0]->GetDE_Effects(); - for (iVar = 0; iVar < config_container[ZONE_0]->GetnElasticityMod(); iVar++) - myfile_res << "Sens_E_" << iVar << "\t"; - - for (iVar = 0; iVar < config_container[ZONE_0]->GetnPoissonRatio(); iVar++) - myfile_res << "Sens_Nu_" << iVar << "\t"; - - if (de_effects){ - for (iVar = 0; iVar < config_container[ZONE_0]->GetnElectric_Field(); iVar++) - myfile_res << "Sens_EField_" << iVar << "\t"; - } - - myfile_res << endl; - - myfile_res.close(); - } - - // TEST: for implementation of python framework in standalone structural problems - if ((config_container[ZONE_1]->GetDV_FEA() != NODV_FEA) && (rank == MASTER_NODE)){ - - /*--- Header of the temporary output file ---*/ - ofstream myfile_res; - - switch (config_container[ZONE_1]->GetDV_FEA()) { - case YOUNG_MODULUS: - myfile_res.open("grad_young.opt"); - break; - case POISSON_RATIO: - myfile_res.open("grad_poisson.opt"); - break; - case DENSITY_VAL: - case DEAD_WEIGHT: - myfile_res.open("grad_density.opt"); - break; - case ELECTRIC_FIELD: - myfile_res.open("grad_efield.opt"); - break; - default: - myfile_res.open("grad.opt"); - break; - } - - unsigned short iDV; - unsigned short nDV = solver_container[ZONE_1][INST_0][MESH_0][ADJFEA_SOL]->GetnDVFEA(); - - myfile_res << "INDEX" << "\t" << "GRAD" << endl; - - myfile_res.precision(15); - - for (iDV = 0; iDV < nDV; iDV++){ - myfile_res << iDV; - myfile_res << "\t"; - myfile_res << scientific << solver_container[ZONE_1][INST_0][MESH_0][ADJFEA_SOL]->GetGlobal_Sens_DVFEA(iDV); - myfile_res << endl; - } - - myfile_res.close(); - } - output_legacy = new COutputLegacy(config_container[ZONE_0]); - - /*--- TODO: This is a workaround until the TestCases.py script incorporates new classes for nested loops. ---*/ -// config_container[ZONE_0]->SetnExtIter(1); -// config_container[ZONE_1]->SetnExtIter(1); - ConvHist_file = NULL; - ConvHist_file = new ofstream*[nZone]; - for (iZone = 0; iZone < nZone; iZone++) { - ConvHist_file[iZone] = NULL; - if (rank == MASTER_NODE){ - ConvHist_file[iZone] = new ofstream[nInst[iZone]]; - for (iInst = 0; iInst < nInst[iZone]; iInst++) { - output_legacy->SetConvHistory_Header(&ConvHist_file[iZone][iInst], config_container[iZone], iZone, iInst); - config_container[iZone]->SetHistFile(&ConvHist_file[iZone][INST_0]); - } - } - } -} - -CDiscAdjFSIDriver::~CDiscAdjFSIDriver(void) { - - delete [] direct_iteration; - delete [] init_res_flow; - delete [] init_res_struct; - delete [] residual_flow; - delete [] residual_struct; - delete [] residual_flow_rel; - delete [] residual_struct_rel; - -} - -void CDiscAdjFSIDriver::DynamicMeshUpdate(unsigned long ExtIter){ - -} - -void CDiscAdjFSIDriver::Run( ) { - - /*--- As of now, we are coding it for just 2 zones. ---*/ - /*--- This will become more general, but we need to modify the configuration for that ---*/ - unsigned short ZONE_FLOW = 0, ZONE_STRUCT = 1; - unsigned short iZone; - bool BGS_Converged = false; - - unsigned long IntIter = 0; for (iZone = 0; iZone < nZone; iZone++) config_container[iZone]->SetInnerIter(IntIter); - unsigned long iOuterIter = 0; for (iZone = 0; iZone < nZone; iZone++) config_container[iZone]->SetOuterIter(iOuterIter); - unsigned long nOuterIter = driver_config->GetnOuter_Iter(); - - ofstream myfile_struc, myfile_flow, myfile_geo; - - Preprocess(ZONE_FLOW, ZONE_STRUCT, ALL_VARIABLES); - - for (iOuterIter = 0; iOuterIter < nOuterIter && !BGS_Converged; iOuterIter++){ - - if (rank == MASTER_NODE){ - cout << endl << " ****** BGS ITERATION "; - cout << iOuterIter; - cout << " ******" << endl; - } - - for (iZone = 0; iZone < nZone; iZone++) config_container[iZone]->SetOuterIter(iOuterIter); - - /*--- Start with structural terms if OF is based on displacements ---*/ - - if (Kind_Objective_Function == FEM_OBJECTIVE_FUNCTION) - Iterate_Block(ZONE_FLOW, ZONE_STRUCT, FEA_DISP_VARS); - - /*--- Iterate fluid (including cross term) ---*/ - - Iterate_Block(ZONE_FLOW, ZONE_STRUCT, FLOW_CONS_VARS); - - /*--- Compute mesh (it is a cross term dF / dMv ) ---*/ - - Iterate_Block(ZONE_FLOW, ZONE_STRUCT, MESH_COORDS); - - /*--- Compute mesh cross term (dM / dSv) ---*/ - - Iterate_Block(ZONE_FLOW, ZONE_STRUCT, FEM_CROSS_TERM_GEOMETRY); - - /*--- End with structural terms if OF is based on fluid variables ---*/ - - if (Kind_Objective_Function == FLOW_OBJECTIVE_FUNCTION) - Iterate_Block(ZONE_FLOW, ZONE_STRUCT, FEA_DISP_VARS); - - /*--- Check convergence of the BGS method ---*/ - BGS_Converged = BGSConvergence(iOuterIter, ZONE_FLOW, ZONE_STRUCT); - - } - - output_container[ZONE_FLOW]->SetResult_Files(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW], solver_container[ZONE_FLOW][INST_0][MESH_0], 0, true); - - output_container[ZONE_STRUCT]->SetResult_Files(geometry_container[ZONE_STRUCT][INST_0][MESH_0], - config_container[ZONE_STRUCT], solver_container[ZONE_STRUCT][INST_0][MESH_0], 0, true); - -} - - -void CDiscAdjFSIDriver::Preprocess(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording){ - - unsigned long IntIter = 0, iPoint; - config_container[ZONE_0]->SetInnerIter(IntIter); - unsigned short ExtIter = config_container[ZONE_FLOW]->GetTimeIter(); - - bool dual_time_1st = (config_container[ZONE_FLOW]->GetTime_Marching() == DT_STEPPING_1ST); - bool dual_time_2nd = (config_container[ZONE_FLOW]->GetTime_Marching() == DT_STEPPING_2ND); - bool turbulent = (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_RANS) || - (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_INC_RANS); - bool dual_time = (dual_time_1st || dual_time_2nd); - unsigned short iMesh; - int Direct_Iter_Flow; - bool update_geo = false; - - /*----------------------------------------------------------------------------*/ - /*------------------------------ FLOW SOLUTION -------------------------------*/ - /*----------------------------------------------------------------------------*/ - - /*--- For the unsteady adjoint, load direct solutions from restart files. ---*/ - - if (config_container[ZONE_FLOW]->GetTime_Marching()) { - - Direct_Iter_Flow = SU2_TYPE::Int(config_container[ZONE_FLOW]->GetUnst_AdjointIter()) - SU2_TYPE::Int(ExtIter) - 2; - - /*--- For dual-time stepping we want to load the already converged solution at timestep n ---*/ - - if (dual_time) { - Direct_Iter_Flow += 1; - } - - if (ExtIter == 0){ - - if (dual_time_2nd) { - - /*--- Load solution at timestep n-2 ---*/ - - iteration_container[ZONE_FLOW][INST_0]->LoadUnsteady_Solution(geometry_container, solver_container,config_container, ZONE_FLOW, INST_0, Direct_Iter_Flow-2); - - /*--- Push solution back to correct array ---*/ - - for (iMesh=0; iMesh<=config_container[ZONE_FLOW]->GetnMGLevels();iMesh++) { - solver_container[ZONE_FLOW][INST_0][iMesh][FLOW_SOL]->GetNodes()->Set_Solution_time_n(); - solver_container[ZONE_FLOW][INST_0][iMesh][FLOW_SOL]->GetNodes()->Set_Solution_time_n1(); - if (turbulent) { - solver_container[ZONE_FLOW][INST_0][iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n(); - solver_container[ZONE_FLOW][INST_0][iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n1(); - } - } - } - if (dual_time) { - - /*--- Load solution at timestep n-1 ---*/ - - iteration_container[ZONE_FLOW][INST_0]->LoadUnsteady_Solution(geometry_container, solver_container,config_container, ZONE_FLOW, INST_0, Direct_Iter_Flow-1); - - /*--- Push solution back to correct array ---*/ - - for (iMesh=0; iMesh<=config_container[ZONE_FLOW]->GetnMGLevels();iMesh++) { - solver_container[ZONE_FLOW][INST_0][iMesh][FLOW_SOL]->GetNodes()->Set_Solution_time_n(); - if (turbulent) { - solver_container[ZONE_FLOW][INST_0][iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n(); - } - } - } - - /*--- Load solution timestep n ---*/ - - iteration_container[ZONE_FLOW][INST_0]->LoadUnsteady_Solution(geometry_container, solver_container,config_container, ZONE_FLOW, INST_0, Direct_Iter_Flow); - - } - - - if ((ExtIter > 0) && dual_time){ - - /*--- Load solution timestep n - 2 ---*/ - - iteration_container[ZONE_FLOW][INST_0]->LoadUnsteady_Solution(geometry_container, solver_container,config_container, ZONE_FLOW, INST_0, Direct_Iter_Flow - 2); - - /*--- Temporarily store the loaded solution in the Solution_Old array ---*/ - - for (iMesh=0; iMesh<=config_container[ZONE_FLOW]->GetnMGLevels();iMesh++) { - solver_container[ZONE_FLOW][INST_0][iMesh][FLOW_SOL]->GetNodes()->Set_OldSolution(); - if (turbulent){ - solver_container[ZONE_FLOW][INST_0][iMesh][TURB_SOL]->GetNodes()->Set_OldSolution(); - } - } - - /*--- Set Solution at timestep n to solution at n-1 ---*/ - - for (iMesh=0; iMesh<=config_container[ZONE_FLOW]->GetnMGLevels();iMesh++) { - for(iPoint=0; iPointGetnPoint();iPoint++) { - solver_container[ZONE_FLOW][INST_0][iMesh][FLOW_SOL]->GetNodes()->SetSolution(iPoint, solver_container[ZONE_FLOW][INST_0][iMesh][FLOW_SOL]->GetNodes()->GetSolution_time_n(iPoint)); - if (turbulent) { - solver_container[ZONE_FLOW][INST_0][iMesh][TURB_SOL]->GetNodes()->SetSolution(iPoint, solver_container[ZONE_FLOW][INST_0][iMesh][TURB_SOL]->GetNodes()->GetSolution_time_n(iPoint)); - } - } - } - if (dual_time_1st){ - /*--- Set Solution at timestep n-1 to the previously loaded solution ---*/ - for (iMesh=0; iMesh<=config_container[ZONE_FLOW]->GetnMGLevels();iMesh++) { - for(iPoint=0; iPointGetnPoint();iPoint++) { - solver_container[ZONE_FLOW][INST_0][iMesh][FLOW_SOL]->GetNodes()->Set_Solution_time_n(iPoint, solver_container[ZONE_FLOW][INST_0][iMesh][FLOW_SOL]->GetNodes()->GetSolution_time_n1(iPoint)); - if (turbulent) { - solver_container[ZONE_FLOW][INST_0][iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n(iPoint, solver_container[ZONE_FLOW][INST_0][iMesh][TURB_SOL]->GetNodes()->GetSolution_time_n1(iPoint)); - } - } - } - } - if (dual_time_2nd){ - /*--- Set Solution at timestep n-1 to solution at n-2 ---*/ - for (iMesh=0; iMesh<=config_container[ZONE_FLOW]->GetnMGLevels();iMesh++) { - for(iPoint=0; iPointGetnPoint();iPoint++) { - solver_container[ZONE_FLOW][INST_0][iMesh][FLOW_SOL]->GetNodes()->Set_Solution_time_n(iPoint, solver_container[ZONE_FLOW][INST_0][iMesh][FLOW_SOL]->GetNodes()->GetSolution_time_n1(iPoint)); - if (turbulent) { - solver_container[ZONE_FLOW][INST_0][iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n(iPoint, solver_container[ZONE_FLOW][INST_0][iMesh][TURB_SOL]->GetNodes()->GetSolution_time_n1(iPoint)); - } - } - } - /*--- Set Solution at timestep n-2 to the previously loaded solution ---*/ - for (iMesh=0; iMesh<=config_container[ZONE_FLOW]->GetnMGLevels();iMesh++) { - for(iPoint=0; iPointGetnPoint();iPoint++) { - solver_container[ZONE_FLOW][INST_0][iMesh][FLOW_SOL]->GetNodes()->Set_Solution_time_n1(iPoint, solver_container[ZONE_FLOW][INST_0][iMesh][FLOW_SOL]->GetNodes()->GetSolution_Old(iPoint)); - if (turbulent) { - solver_container[ZONE_FLOW][INST_0][iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n1(iPoint, solver_container[ZONE_FLOW][INST_0][iMesh][TURB_SOL]->GetNodes()->GetSolution_Old(iPoint)); - } - } - } - } - } - } - else{ - - /*--- Load the restart (we need to use the routine in order to get the GEOMETRY, otherwise it's restarted from the base mesh ---*/ - - solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->LoadRestart(geometry_container[ZONE_FLOW][INST_0], solver_container[ZONE_FLOW][INST_0], config_container[ZONE_FLOW], 0, true); - - if (ExtIter == 0 || dual_time) { - - for (iMesh=0; iMesh<=config_container[ZONE_FLOW]->GetnMGLevels();iMesh++) { - for (iPoint = 0; iPoint < geometry_container[ZONE_FLOW][INST_0][iMesh]->GetnPoint(); iPoint++) { - solver_container[ZONE_FLOW][INST_0][iMesh][ADJFLOW_SOL]->GetNodes()->SetSolution_Direct(iPoint, solver_container[ZONE_FLOW][INST_0][iMesh][FLOW_SOL]->GetNodes()->GetSolution(iPoint)); - } - } - if (turbulent && !config_container[ZONE_FLOW]->GetFrozen_Visc_Disc()) { - for (iPoint = 0; iPoint < geometry_container[ZONE_FLOW][INST_0][MESH_0]->GetnPoint(); iPoint++) { - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJTURB_SOL]->GetNodes()->SetSolution_Direct(iPoint, solver_container[ZONE_FLOW][INST_0][MESH_0][TURB_SOL]->GetNodes()->GetSolution(iPoint)); - } - } - } - - /*--- Store geometry of the converged solution also in the adjoint solver in order to be able to reset it later ---*/ - - for (iPoint = 0; iPoint < geometry_container[ZONE_FLOW][INST_0][MESH_0]->GetnPoint(); iPoint++){ - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->GetNodes()->SetGeometry_Direct(iPoint, geometry_container[ZONE_FLOW][INST_0][MESH_0]->node[iPoint]->GetCoord()); - } - - } - - /*----------------------------------------------------------------------------*/ - /*-------------------------- STRUCTURAL SOLUTION -----------------------------*/ - /*----------------------------------------------------------------------------*/ - - IntIter = 0; - config_container[ZONE_STRUCT]->SetInnerIter(IntIter); - ExtIter = config_container[ZONE_STRUCT]->GetTimeIter(); - bool dynamic = (config_container[ZONE_STRUCT]->GetTime_Domain()); - - int Direct_Iter_FEA; - - /*--- For the dynamic adjoint, load direct solutions from restart files. ---*/ - - if (dynamic) { - - Direct_Iter_FEA = SU2_TYPE::Int(config_container[ZONE_STRUCT]->GetUnst_AdjointIter()) - SU2_TYPE::Int(ExtIter) - 1; - - /*--- We want to load the already converged solution at timesteps n and n-1 ---*/ - - /*--- Load solution at timestep n-1 ---*/ - - iteration_container[ZONE_STRUCT][INST_0]->LoadDynamic_Solution(geometry_container, solver_container,config_container, ZONE_STRUCT, INST_0, Direct_Iter_FEA-1); - - /*--- Push solution back to correct array ---*/ - - solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetNodes()->Set_Solution_time_n(); - - /*--- Push solution back to correct array ---*/ - - solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetNodes()->SetSolution_Accel_time_n(); - - /*--- Push solution back to correct array ---*/ - - solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetNodes()->SetSolution_Vel_time_n(); - - /*--- Load solution timestep n ---*/ - - iteration_container[ZONE_STRUCT][INST_0]->LoadDynamic_Solution(geometry_container, solver_container,config_container, ZONE_STRUCT, INST_0, Direct_Iter_FEA); - - /*--- Store FEA solution also in the adjoint solver in order to be able to reset it later ---*/ - - for (iPoint = 0; iPoint < geometry_container[ZONE_STRUCT][INST_0][MESH_0]->GetnPoint(); iPoint++){ - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->GetNodes()->SetSolution_Direct(iPoint, solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetNodes()->GetSolution(iPoint)); - } - - for (iPoint = 0; iPoint < geometry_container[ZONE_STRUCT][INST_0][MESH_0]->GetnPoint(); iPoint++){ - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->GetNodes()->SetSolution_Accel_Direct(iPoint, solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetNodes()->GetSolution_Accel(iPoint)); - } - - for (iPoint = 0; iPoint < geometry_container[ZONE_STRUCT][INST_0][MESH_0]->GetnPoint(); iPoint++){ - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->GetNodes()->SetSolution_Vel_Direct(iPoint, solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetNodes()->GetSolution_Vel(iPoint)); - } - - } - else { - - solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->LoadRestart(geometry_container[ZONE_STRUCT][INST_0], solver_container[ZONE_STRUCT][INST_0], config_container[ZONE_STRUCT], 0, update_geo); - - /*--- Store FEA solution also in the adjoint solver in order to be able to reset it later ---*/ - - for (iPoint = 0; iPoint < geometry_container[ZONE_STRUCT][INST_0][MESH_0]->GetnPoint(); iPoint++){ - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->GetNodes()->SetSolution_Direct(iPoint, solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetNodes()->GetSolution(iPoint)); - } - - } - - /*----------------------------------------------------------------------------*/ - /*--------------------- ADJOINT SOLVER PREPROCESSING -------------------------*/ - /*----------------------------------------------------------------------------*/ - - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->Preprocessing(geometry_container[ZONE_FLOW][INST_0][MESH_0], solver_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW] , MESH_0, 0, RUNTIME_ADJFLOW_SYS, false); - - if (turbulent){ - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJTURB_SOL]->Preprocessing(geometry_container[ZONE_FLOW][INST_0][MESH_0], solver_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW] , MESH_0, 0, RUNTIME_ADJTURB_SYS, false); - } - - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->Preprocessing(geometry_container[ZONE_STRUCT][INST_0][MESH_0], solver_container[ZONE_STRUCT][INST_0][MESH_0], config_container[ZONE_STRUCT] , MESH_0, 0, RUNTIME_ADJFEA_SYS, false); - - - -} - -void CDiscAdjFSIDriver::PrintDirect_Residuals(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording){ - - unsigned short ExtIter = config_container[ZONE_FLOW]->GetTimeIter(); - bool turbulent = (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_RANS) || - (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_INC_RANS); - bool nonlinear_analysis = (config_container[ZONE_STRUCT]->GetGeometricConditions() == LARGE_DEFORMATIONS); // Nonlinear analysis. - bool unsteady = config_container[ZONE_FLOW]->GetTime_Marching() != NONE; - bool dynamic = (config_container[ZONE_STRUCT]->GetTime_Domain()); - - su2double val_OFunction = 0.0; - string kind_OFunction; - - cout.precision(6); - cout.setf(ios::scientific, ios::floatfield); - - if ((kind_recording == FLOW_CONS_VARS) || (kind_recording == MESH_COORDS)) { - - /*--- Print residuals in the first iteration ---*/ - - if (rank == MASTER_NODE && ((ExtIter == 0) || unsteady )){ - cout << "log10[RMS Density]: "<< log10(solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetRes_RMS(0)) - <<", Drag: " <GetTotal_CD() - <<", Lift: " << solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CL() << "." << endl; - - if (turbulent){ - cout << "log10[RMS k]: " << log10(solver_container[ZONE_FLOW][INST_0][MESH_0][TURB_SOL]->GetRes_RMS(0)) << endl; - } - if (Kind_Objective_Function == FLOW_OBJECTIVE_FUNCTION){ - switch (config_container[ZONE_FLOW]->GetKind_ObjFunc()){ - case DRAG_COEFFICIENT: - kind_OFunction = "(Drag coefficient): "; - val_OFunction = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CD(); - break; - case LIFT_COEFFICIENT: - kind_OFunction = "(Lift coefficient): "; - val_OFunction = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CL(); - break; - case SIDEFORCE_COEFFICIENT: - kind_OFunction = "(Sideforce coefficient): "; - val_OFunction = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CSF(); - break; - case EFFICIENCY: - kind_OFunction = "(Efficiency): "; - val_OFunction = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CEff(); - break; - case MOMENT_X_COEFFICIENT: - kind_OFunction = "(Moment X coefficient): "; - val_OFunction = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CMx(); - break; - case MOMENT_Y_COEFFICIENT: - kind_OFunction = "(Moment Y coefficient): "; - val_OFunction = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CMy(); - break; - case MOMENT_Z_COEFFICIENT: - kind_OFunction = "(Moment Z coefficient): "; - val_OFunction = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CMz(); - break; - case EQUIVALENT_AREA: - kind_OFunction = "(Equivalent area): "; - val_OFunction = solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->GetTotal_CEquivArea(); - break; - default: - val_OFunction = 0.0; // If the objective function is computed in a different physical problem - break; - } - cout << "Objective function " << kind_OFunction << val_OFunction << endl; - } - } - - } - - if ((kind_recording == FEA_DISP_VARS) || (kind_recording == FLOW_CROSS_TERM) || (kind_recording == GEOMETRY_CROSS_TERM)) { - - if (rank == MASTER_NODE && ((ExtIter == 0) || dynamic )){ - if (nonlinear_analysis){ - cout << "UTOL-A: " << log10(solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetRes_FEM(0)) - << ", RTOL-A: " << log10(solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetRes_FEM(1)) - << ", ETOL-A: " << log10(solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetRes_FEM(2)) << "." << endl; - } - else{ - if (solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetnVar() == 2){ - cout << "log10[RMS Ux]: " << log10(solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetRes_RMS(0)) - << ", log10[RMS Uy]: " << log10(solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetRes_RMS(1)) << "." << endl; - - } - else{ - cout << "log10[RMS Ux]: " << log10(solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetRes_RMS(0)) - << ", log10[RMS Uy]: " << log10(solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetRes_RMS(1)) - << ", log10[RMS Uz]: " << log10(solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetRes_RMS(2))<< "." << endl; - } - - } - if (Kind_Objective_Function == FEM_OBJECTIVE_FUNCTION){ - switch (config_container[ZONE_STRUCT]->GetKind_ObjFunc()){ - case REFERENCE_GEOMETRY: - kind_OFunction = "(Reference Geometry): "; - val_OFunction = solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetTotal_OFRefGeom(); - break; - case REFERENCE_NODE: - kind_OFunction = "(Reference Node): "; - val_OFunction = solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetTotal_OFRefNode(); - break; - case VOLUME_FRACTION: - kind_OFunction = "(Volume Fraction): "; - val_OFunction = solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetTotal_OFVolFrac(); - break; - case TOPOL_DISCRETENESS: - kind_OFunction = "(Topology discreteness): "; - val_OFunction = solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetTotal_OFVolFrac(); - break; - case TOPOL_COMPLIANCE: - kind_OFunction = "(Topology compliance): "; - val_OFunction = solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->GetTotal_OFCompliance(); - break; - default: - val_OFunction = 0.0; // If the objective function is computed in a different physical problem - break; - } - cout << "Objective function " << kind_OFunction << val_OFunction << endl; - } - } - - } - -} - -void CDiscAdjFSIDriver::Iterate_Direct(unsigned short ZONE_FLOW, unsigned short ZONE_STRUCT, unsigned short kind_recording){ - - if ((kind_recording == FLOW_CONS_VARS) || - (kind_recording == MESH_COORDS)) { - - Fluid_Iteration_Direct(ZONE_FLOW, ZONE_STRUCT); - - - } - - if ((kind_recording == FEA_DISP_VARS) || - (kind_recording == FLOW_CROSS_TERM) || - (kind_recording == GEOMETRY_CROSS_TERM)) { - - Structural_Iteration_Direct(ZONE_FLOW, ZONE_STRUCT); - - } - - - if (kind_recording == FEM_CROSS_TERM_GEOMETRY) { - - Mesh_Deformation_Direct(ZONE_FLOW, ZONE_STRUCT); - - } - - -} - -void CDiscAdjFSIDriver::Fluid_Iteration_Direct(unsigned short ZONE_FLOW, unsigned short ZONE_STRUCT) { - - bool turbulent = (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_RANS) || - (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_INC_RANS); - bool frozen_visc = config_container[ZONE_FLOW]->GetFrozen_Visc_Disc(); - - /*-----------------------------------------------------------------*/ - /*------------------- Set Dependency on Geometry ------------------*/ - /*-----------------------------------------------------------------*/ - - geometry_container[ZONE_FLOW][INST_0][MESH_0]->UpdateGeometry(geometry_container[ZONE_FLOW][INST_0], config_container[ZONE_FLOW]); - - solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->InitiateComms(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], SOLUTION); - solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->CompleteComms(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], SOLUTION); - - solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->Preprocessing(geometry_container[ZONE_FLOW][INST_0][MESH_0],solver_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], MESH_0, NO_RK_ITER, RUNTIME_FLOW_SYS, true); - - if (turbulent && !frozen_visc) { - solver_container[ZONE_FLOW][INST_0][MESH_0][TURB_SOL]->Postprocessing(geometry_container[ZONE_FLOW][INST_0][MESH_0], solver_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], MESH_0); - - solver_container[ZONE_FLOW][INST_0][MESH_0][TURB_SOL]->InitiateComms(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], SOLUTION_EDDY); - solver_container[ZONE_FLOW][INST_0][MESH_0][TURB_SOL]->CompleteComms(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], SOLUTION_EDDY); - - } - - /*-----------------------------------------------------------------*/ - /*----------------- Iterate the flow solver -----------------------*/ - /*---- Sets all the cross dependencies for the flow variables -----*/ - /*-----------------------------------------------------------------*/ - - config_container[ZONE_FLOW]->SetInnerIter(0); - - direct_iteration[ZONE_FLOW]->Iterate(output_container[ZONE_FLOW], integration_container, geometry_container, - solver_container, numerics_container, config_container, - surface_movement, grid_movement, FFDBox, ZONE_FLOW, INST_0); - - /*-----------------------------------------------------------------*/ - /*--------------------- Set MPI Solution --------------------------*/ - /*-----------------------------------------------------------------*/ - - solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->InitiateComms(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], SOLUTION); - solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->CompleteComms(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], SOLUTION); - -} - -void CDiscAdjFSIDriver::Structural_Iteration_Direct(unsigned short ZONE_FLOW, unsigned short ZONE_STRUCT) { - - bool turbulent = (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_RANS) || - (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_INC_RANS); - bool frozen_visc = config_container[ZONE_FLOW]->GetFrozen_Visc_Disc(); - - /*-----------------------------------------------------------------*/ - /*---------- Set Dependencies on Geometry and Flow ----------------*/ - /*-----------------------------------------------------------------*/ - - solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->InitiateComms(geometry_container[ZONE_STRUCT][INST_0][MESH_0], config_container[ZONE_STRUCT], SOLUTION_FEA); - solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->CompleteComms(geometry_container[ZONE_STRUCT][INST_0][MESH_0], config_container[ZONE_STRUCT], SOLUTION_FEA); - - geometry_container[ZONE_FLOW][INST_0][MESH_0]->UpdateGeometry(geometry_container[ZONE_FLOW][INST_0], config_container[ZONE_FLOW]); - - solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->InitiateComms(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], SOLUTION); - solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->CompleteComms(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], SOLUTION); - - solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->Preprocessing(geometry_container[ZONE_FLOW][INST_0][MESH_0],solver_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], MESH_0, NO_RK_ITER, RUNTIME_FLOW_SYS, true); - - if (turbulent && !frozen_visc) { - solver_container[ZONE_FLOW][INST_0][MESH_0][TURB_SOL]->Postprocessing(geometry_container[ZONE_FLOW][INST_0][MESH_0], solver_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], MESH_0); - - solver_container[ZONE_FLOW][INST_0][MESH_0][TURB_SOL]->InitiateComms(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], SOLUTION_EDDY); - solver_container[ZONE_FLOW][INST_0][MESH_0][TURB_SOL]->CompleteComms(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], SOLUTION_EDDY); - - } - - /*-----------------------------------------------------------------*/ - /*-------------------- Transfer Tractions -------------------------*/ - /*-----------------------------------------------------------------*/ - - Transfer_Tractions(ZONE_FLOW, ZONE_STRUCT); - - /*-----------------------------------------------------------------*/ - /*--------------- Iterate the structural solver -------------------*/ - /*-----------------------------------------------------------------*/ - - direct_iteration[ZONE_STRUCT]->Iterate(output_container[ZONE_STRUCT], integration_container, geometry_container, - solver_container, numerics_container, config_container, - surface_movement, grid_movement, FFDBox, ZONE_STRUCT, INST_0); - - /*-----------------------------------------------------------------*/ - /*--------------------- Set MPI Solution --------------------------*/ - /*-----------------------------------------------------------------*/ - - solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->InitiateComms(geometry_container[ZONE_STRUCT][INST_0][MESH_0], config_container[ZONE_STRUCT], SOLUTION_FEA); - solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->CompleteComms(geometry_container[ZONE_STRUCT][INST_0][MESH_0], config_container[ZONE_STRUCT], SOLUTION_FEA); - -} - -void CDiscAdjFSIDriver::Mesh_Deformation_Direct(unsigned short ZONE_FLOW, unsigned short ZONE_STRUCT) { - - unsigned long ExtIter = config_container[ZONE_STRUCT]->GetTimeIter(); - - /*-----------------------------------------------------------------*/ - /*--------------------- Set MPI Solution --------------------------*/ - /*-----------------------------------------------------------------*/ - - geometry_container[ZONE_FLOW][INST_0][MESH_0]->UpdateGeometry(geometry_container[ZONE_FLOW][INST_0], config_container[ZONE_FLOW]); - - solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->InitiateComms(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], SOLUTION); - solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->CompleteComms(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], SOLUTION); - - solver_container[ZONE_FLOW][INST_0][MESH_0][FLOW_SOL]->Preprocessing(geometry_container[ZONE_FLOW][INST_0][MESH_0],solver_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW], MESH_0, NO_RK_ITER, RUNTIME_FLOW_SYS, true); - - solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->InitiateComms(geometry_container[ZONE_STRUCT][INST_0][MESH_0], config_container[ZONE_STRUCT], SOLUTION_FEA); - solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->CompleteComms(geometry_container[ZONE_STRUCT][INST_0][MESH_0], config_container[ZONE_STRUCT], SOLUTION_FEA); - - /*-----------------------------------------------------------------*/ - /*------------------- Transfer Displacements ----------------------*/ - /*-----------------------------------------------------------------*/ - - Transfer_Displacements(ZONE_STRUCT, ZONE_FLOW); - - /*-----------------------------------------------------------------*/ - /*------------------- Set the Grid movement -----------------------*/ - /*---- No longer done in the preprocess of the flow iteration -----*/ - /*---- as the flag Grid_Movement is set to false in this case -----*/ - /*-----------------------------------------------------------------*/ - - direct_iteration[ZONE_FLOW]->SetGrid_Movement(geometry_container[ZONE_FLOW][INST_0], - surface_movement[ZONE_FLOW], grid_movement[ZONE_FLOW][INST_0], - solver_container[ZONE_FLOW][INST_0], config_container[ZONE_FLOW], 0, ExtIter ); - - geometry_container[ZONE_FLOW][INST_0][MESH_0]->UpdateGeometry(geometry_container[ZONE_FLOW][INST_0], config_container[ZONE_FLOW]); - - solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->InitiateComms(geometry_container[ZONE_STRUCT][INST_0][MESH_0], config_container[ZONE_STRUCT], SOLUTION_FEA); - solver_container[ZONE_STRUCT][INST_0][MESH_0][FEA_SOL]->CompleteComms(geometry_container[ZONE_STRUCT][INST_0][MESH_0], config_container[ZONE_STRUCT], SOLUTION_FEA); - -} - -void CDiscAdjFSIDriver::SetRecording(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording){ - - unsigned long IntIter = config_container[ZONE_0]->GetInnerIter(); - bool unsteady = (config_container[ZONE_FLOW]->GetTime_Marching() != NONE); - bool dynamic = (config_container[ZONE_STRUCT]->GetTime_Domain()); - - string kind_DirectIteration = " "; - string kind_AdjointIteration = " "; - - if (unsteady || dynamic){ - SU2_MPI::Error("DYNAMIC ADJOINT SOLVER NOT IMPLEMENTED FOR FSI APPLICATIONS", CURRENT_FUNCTION); - } - - - if (rank == MASTER_NODE){ - cout << endl; - switch (kind_recording){ - case FLOW_CONS_VARS: - kind_AdjointIteration = "Flow iteration: flow input -> flow output"; - kind_DirectIteration = "flow "; - break; - case MESH_COORDS: - kind_AdjointIteration = "Geometry cross term from flow: geometry input -> flow output"; - kind_DirectIteration = "flow "; - break; - case FEA_DISP_VARS: - kind_AdjointIteration = "Structural iteration: structural input -> structural output"; - kind_DirectIteration = "structural "; - break; - case FLOW_CROSS_TERM: - kind_AdjointIteration = "Flow cross term: flow input -> structural output"; - kind_DirectIteration = "structural "; - break; - case GEOMETRY_CROSS_TERM: - kind_AdjointIteration = "Geometry cross term from structure: geometry input -> structural output"; - kind_DirectIteration = "structural "; - break; - case FEM_CROSS_TERM_GEOMETRY: - kind_AdjointIteration = "Structural cross term from geometry: structural input -> geometry output"; - kind_DirectIteration = "mesh deformation "; - break; - } - cout << kind_AdjointIteration << endl; - cout << "Direct " << kind_DirectIteration << "iteration to store computational graph." << endl; - switch (kind_recording){ - case FLOW_CONS_VARS: case MESH_COORDS: - case FEA_DISP_VARS: case FLOW_CROSS_TERM: case GEOMETRY_CROSS_TERM: - cout << "Compute residuals to check the convergence of the direct problem." << endl; break; - case FEM_CROSS_TERM_GEOMETRY: - cout << "Deform the grid using the converged solution of the direct problem." << endl; break; - } - } - - - AD::Reset(); - - if (CurrentRecording != kind_recording && (CurrentRecording != NONE) ){ - - /*--- Clear indices ---*/ - - PrepareRecording(ZONE_FLOW, ZONE_STRUCT, ALL_VARIABLES); - - /*--- Clear indices of coupling variables ---*/ - - SetDependencies(ZONE_FLOW, ZONE_STRUCT, ALL_VARIABLES); - - /*--- Run one iteration while tape is passive - this clears all indices ---*/ - Iterate_Direct(ZONE_FLOW, ZONE_STRUCT, kind_recording); - - } - - /*--- Prepare for recording ---*/ - - PrepareRecording(ZONE_FLOW, ZONE_STRUCT, kind_recording); - - /*--- Start the recording of all operations ---*/ - - AD::StartRecording(); - - /*--- Register input variables ---*/ - - RegisterInput(ZONE_FLOW, ZONE_STRUCT, kind_recording); - - /*--- Set dependencies for flow, geometry and structural solvers ---*/ - - SetDependencies(ZONE_FLOW, ZONE_STRUCT, kind_recording); - - /*--- Run a direct iteration ---*/ - Iterate_Direct(ZONE_FLOW, ZONE_STRUCT, kind_recording); - - /*--- Register objective function and output variables ---*/ - - RegisterOutput(ZONE_FLOW, ZONE_STRUCT, kind_recording); - - /*--- Stop the recording ---*/ - AD::StopRecording(); - - /*--- Set the recording status ---*/ - - CurrentRecording = kind_recording; - - /* --- Reset the number of the internal iterations---*/ - - config_container[ZONE_0]->SetInnerIter(IntIter); - - -} - -void CDiscAdjFSIDriver::PrepareRecording(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording){ - - unsigned short iMesh; - bool turbulent = (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_RANS) || - (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_INC_RANS); - - /*--- Set fluid variables to direct solver values ---*/ - for (iMesh = 0; iMesh <= config_container[ZONE_FLOW]->GetnMGLevels(); iMesh++){ - solver_container[ZONE_FLOW][INST_0][iMesh][ADJFLOW_SOL]->SetRecording(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW]); - } - if (turbulent){ - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJTURB_SOL]->SetRecording(geometry_container[ZONE_FLOW][INST_0][MESH_0], config_container[ZONE_FLOW]); - } - - /*--- Set geometry to the converged values ---*/ - - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->SetMesh_Recording(geometry_container[ZONE_FLOW][INST_0], grid_movement[ZONE_FLOW][INST_0], config_container[ZONE_FLOW]); - - /*--- Set structural variables to direct solver values ---*/ - - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->SetRecording(geometry_container[ZONE_STRUCT][INST_0][MESH_0], config_container[ZONE_STRUCT]); - -} - -void CDiscAdjFSIDriver::RegisterInput(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording){ - - /*--- Register flow variables ---*/ - if (kind_recording == FLOW_CONS_VARS) { - iteration_container[ZONE_FLOW][INST_0]->RegisterInput(solver_container, geometry_container, config_container, ZONE_FLOW, INST_0, kind_recording); - } - - /*--- Register geometry variables ---*/ - if (kind_recording == MESH_COORDS) { - iteration_container[ZONE_FLOW][INST_0]->RegisterInput(solver_container, geometry_container, config_container, ZONE_FLOW, INST_0, kind_recording); - } - - /*--- Register structural variables ---*/ - if (kind_recording == FEM_CROSS_TERM_GEOMETRY) { - iteration_container[ZONE_STRUCT][INST_0]->RegisterInput(solver_container, geometry_container, config_container, ZONE_STRUCT, INST_0, kind_recording); - } - - /*--- Register all variables ---*/ - if (kind_recording == FEA_DISP_VARS) { - iteration_container[ZONE_STRUCT][INST_0]->RegisterInput(solver_container, geometry_container, config_container, ZONE_STRUCT, INST_0, FEA_DISP_VARS); - iteration_container[ZONE_FLOW][INST_0]->RegisterInput(solver_container, geometry_container, config_container, ZONE_FLOW, INST_0, FLOW_CROSS_TERM); - iteration_container[ZONE_FLOW][INST_0]->RegisterInput(solver_container, geometry_container, config_container, ZONE_FLOW, INST_0, GEOMETRY_CROSS_TERM); - } - -} - -void CDiscAdjFSIDriver::SetDependencies(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording){ - - /*--- Add dependencies for geometrical and turbulent variables ---*/ - - iteration_container[ZONE_FLOW][INST_0]->SetDependencies(solver_container, geometry_container, numerics_container, config_container, ZONE_FLOW, INST_0, kind_recording); - - /*--- Add dependencies for E, Nu, Rho, and Rho_DL variables ---*/ - - iteration_container[ZONE_STRUCT][INST_0]->SetDependencies(solver_container, geometry_container, numerics_container, config_container, ZONE_STRUCT, INST_0, kind_recording); - - -} - -void CDiscAdjFSIDriver::RegisterOutput(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording){ - - bool turbulent = (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_RANS) || - (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_INC_RANS); - bool frozen_visc = config_container[ZONE_FLOW]->GetFrozen_Visc_Disc(); - - - /*--- Register a flow-type objective function and the conservative variables of the flow as output of the iteration. ---*/ - if ((kind_recording == FLOW_CONS_VARS) || - (kind_recording == MESH_COORDS)) { - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->RegisterObj_Func(config_container[ZONE_FLOW]); - - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->RegisterOutput(geometry_container[ZONE_FLOW][INST_0][MESH_0],config_container[ZONE_FLOW]); - - if (turbulent && !frozen_visc) { - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJTURB_SOL]->RegisterOutput(geometry_container[ZONE_FLOW][INST_0][MESH_0],config_container[ZONE_FLOW]); - } - } - - - /*--- Register a structural-type objective function and the displacements of the structure as output of the iteration. ---*/ - if (kind_recording == FEA_DISP_VARS) { - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->RegisterObj_Func(config_container[ZONE_STRUCT]); - - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->RegisterOutput(geometry_container[ZONE_STRUCT][INST_0][MESH_0],config_container[ZONE_STRUCT]); - } - - - /*--- The FEM_CROSS_TERM_GEOMETRY evaluates the mesh routines, they do not throw any dependency on the objective function. ---*/ - /*--- Register the displacements of the fluid nodes as output of the iteration. ---*/ - if (kind_recording == FEM_CROSS_TERM_GEOMETRY) { - geometry_container[ZONE_FLOW][INST_0][MESH_0]->RegisterOutput_Coordinates(config_container[ZONE_FLOW]); - } - -} - - -void CDiscAdjFSIDriver::Iterate_Block(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording){ - - unsigned long IntIter=0, nIntIter = 1; - bool dual_time_1st = (config_container[ZONE_0]->GetTime_Marching() == DT_STEPPING_1ST); - bool dual_time_2nd = (config_container[ZONE_0]->GetTime_Marching() == DT_STEPPING_2ND); - bool dual_time = (dual_time_1st || dual_time_2nd); - bool dynamic = (config_container[ZONE_STRUCT]->GetTime_Domain()); - - bool adjoint_convergence = false; - - /*--- Record one direct iteration with kind_recording as input ---*/ - - SetRecording(ZONE_FLOW, ZONE_STRUCT, kind_recording); - - /*--- Print the residuals of the direct subiteration ---*/ - - PrintDirect_Residuals(ZONE_FLOW, ZONE_STRUCT, kind_recording); - - /*--- Run the iteration ---*/ - - switch (kind_recording){ - case FLOW_CONS_VARS: - nIntIter = config_container[ZONE_FLOW]->GetnInner_Iter(); - break; - case FEA_DISP_VARS: - nIntIter = config_container[ZONE_STRUCT]->GetnInner_Iter(); - break; - case MESH_COORDS: - case FEM_CROSS_TERM_GEOMETRY: - case FLOW_CROSS_TERM: - case GEOMETRY_CROSS_TERM: - nIntIter = 1; - break; - } - - for (unsigned short iZone = 0; iZone < config_container[ZONE_FLOW]->GetnZone(); iZone++) - config_container[iZone]->SetInnerIter(IntIter); - - for(IntIter = 0; IntIter < nIntIter; IntIter++){ - - /*--- Set the internal iteration ---*/ - - for (unsigned short iZone = 0; iZone < config_container[ZONE_FLOW]->GetnZone(); iZone++) - config_container[iZone]->SetInnerIter(IntIter); - - /*--- Set the adjoint values of the flow and objective function ---*/ - - InitializeAdjoint(ZONE_FLOW, ZONE_STRUCT, kind_recording); - - /*--- Run the adjoint computation ---*/ - - AD::ComputeAdjoint(); - - /*--- Extract the adjoints of the input variables and store them for the next iteration ---*/ - - ExtractAdjoint(ZONE_FLOW, ZONE_STRUCT, kind_recording); - - /*--- Clear all adjoints to re-use the stored computational graph in the next iteration ---*/ - AD::ClearAdjoints(); - - /*--- Check the convergence of the adjoint block ---*/ - - adjoint_convergence = CheckConvergence(IntIter, ZONE_FLOW, ZONE_STRUCT, kind_recording); - - /*--- Write the convergence history (only screen output) ---*/ - - ConvergenceHistory(IntIter, nIntIter, ZONE_FLOW, ZONE_STRUCT, kind_recording); - - /*--- Break the loop if converged ---*/ - - if (adjoint_convergence) break; - - - } - - if (dual_time){ - integration_container[ZONE_FLOW][INST_0][ADJFLOW_SOL]->SetConvergence(false); - } - if (dynamic){ - integration_container[ZONE_FLOW][INST_0][ADJFLOW_SOL]->SetConvergence(false); - } - -} - - -void CDiscAdjFSIDriver::InitializeAdjoint(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording){ - - bool turbulent = (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_RANS) || - (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_INC_RANS); - bool frozen_visc = config_container[ZONE_FLOW]->GetFrozen_Visc_Disc(); - - /*--- Seed a fluid-type objective function and initialize the adjoints of fluid conservative variables. ---*/ - if ((kind_recording == FLOW_CONS_VARS) || - (kind_recording == MESH_COORDS)) { - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->SetAdj_ObjFunc(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW]); - - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->SetAdjoint_Output(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW]); - if (turbulent && !frozen_visc) { - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJTURB_SOL]->SetAdjoint_Output(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW]); - } - } - - /*--- Seed a structural-type objective function and initialize the adjoints of structural displacements. ---*/ - if (kind_recording == FEA_DISP_VARS) { - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->SetAdj_ObjFunc(geometry_container[ZONE_STRUCT][INST_0][MESH_0], - config_container[ZONE_STRUCT]); - - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->SetAdjoint_Output(geometry_container[ZONE_STRUCT][INST_0][MESH_0], - config_container[ZONE_STRUCT]); - } - - /*--- Initialize the adjoints of fluid grid nodes. ---*/ - if (kind_recording == FEM_CROSS_TERM_GEOMETRY) { - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->SetAdjoint_OutputMesh(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW]); - } -} - -void CDiscAdjFSIDriver::ExtractAdjoint(unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording){ - - bool turbulent = (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_RANS) || - (config_container[ZONE_FLOW]->GetKind_Solver() == DISC_ADJ_INC_RANS); - bool frozen_visc = config_container[ZONE_FLOW]->GetFrozen_Visc_Disc(); - - /*--- Extract the adjoint of the fluid conservative variables ---*/ - - if (kind_recording == FLOW_CONS_VARS) { - - /*--- Extract the adjoints of the conservative input variables and store them for the next iteration ---*/ - - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_Solution(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW]); - - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_Variables(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW]); - - if (turbulent && !frozen_visc) { - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJTURB_SOL]->ExtractAdjoint_Solution(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW]); - } - - } - - /*--- Extract the adjoint of the mesh coordinates ---*/ - - if (kind_recording == MESH_COORDS) { - - /*--- Extract the adjoints of the flow geometry and store them for the next iteration ---*/ - - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_CrossTerm_Geometry_Flow(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW]); - - } - - /*--- Extract the adjoint of the structural displacements ---*/ - - if (kind_recording == FEA_DISP_VARS) { - - /*--- Extract the adjoints of the conservative input variables and store them for the next iteration ---*/ - - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->ExtractAdjoint_Solution(geometry_container[ZONE_STRUCT][INST_0][MESH_0], - config_container[ZONE_STRUCT]); - - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->ExtractAdjoint_Variables(geometry_container[ZONE_STRUCT][INST_0][MESH_0], - config_container[ZONE_STRUCT]); - - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_CrossTerm(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW]); - - if (turbulent && !frozen_visc) - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJTURB_SOL]->ExtractAdjoint_CrossTerm(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW]); - - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_CrossTerm_Geometry(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW]); - } - - - if (kind_recording == FEM_CROSS_TERM_GEOMETRY) { - - /*--- Extract the adjoints of the displacements (input variables) and store them for the next iteration ---*/ - - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->ExtractAdjoint_CrossTerm_Geometry(geometry_container[ZONE_STRUCT][INST_0][MESH_0], - config_container[ZONE_STRUCT]); - } - -} - - -bool CDiscAdjFSIDriver::CheckConvergence(unsigned long IntIter, - unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording){ - - bool flow_convergence = false, - struct_convergence = false, - adjoint_convergence = false; - -// su2double residual_1, residual_2; - -// if (kind_recording == FLOW_CONS_VARS) { - -// /*--- Set the convergence criteria (only residual possible as of now) ---*/ - -// residual_1 = log10(solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->GetRes_RMS(0)); -// residual_2 = log10(solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->GetRes_RMS(1)); - -// flow_convergence = ((residual_1 < config_container[ZONE_FLOW]->GetMinLogResidual()) && -// (residual_2 < config_container[ZONE_FLOW]->GetMinLogResidual())); - -// } - -// if (kind_recording == FEA_DISP_VARS) { - -// /*--- Set the convergence criteria (only residual possible as of now) ---*/ - -// residual_1 = log10(solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->GetRes_RMS(0)); -// residual_2 = log10(solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->GetRes_RMS(1)); - -// // Temporary, until function is added -// struct_convergence = ((residual_1 < config_container[ZONE_STRUCT]->GetResidual_FEM_UTOL()) && -// (residual_2 < config_container[ZONE_STRUCT]->GetResidual_FEM_UTOL())); - -// } - - switch (kind_recording){ - case FLOW_CONS_VARS: adjoint_convergence = flow_convergence; break; - case MESH_COORDS: adjoint_convergence = true; break; - case FEA_DISP_VARS: adjoint_convergence = struct_convergence; break; - case FLOW_CROSS_TERM: adjoint_convergence = true; break; - case FEM_CROSS_TERM_GEOMETRY: adjoint_convergence = true; break; - case GEOMETRY_CROSS_TERM: adjoint_convergence = true; break; - default: adjoint_convergence = false; break; - } - - /*--- Apply the same convergence criteria to all the processors ---*/ - -#ifdef HAVE_MPI - - unsigned short *sbuf_conv = NULL, *rbuf_conv = NULL; - sbuf_conv = new unsigned short[1]; sbuf_conv[0] = 0; - rbuf_conv = new unsigned short[1]; rbuf_conv[0] = 0; - - /*--- Convergence criteria ---*/ - - sbuf_conv[0] = adjoint_convergence; - SU2_MPI::Reduce(sbuf_conv, rbuf_conv, 1, MPI_UNSIGNED_SHORT, MPI_SUM, MASTER_NODE, MPI_COMM_WORLD); - - /*-- Compute global convergence criteria in the master node --*/ - - sbuf_conv[0] = 0; - if (rank == MASTER_NODE) { - if (rbuf_conv[0] == size) sbuf_conv[0] = 1; - else sbuf_conv[0] = 0; - } - - SU2_MPI::Bcast(sbuf_conv, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); - - if (sbuf_conv[0] == 1) { adjoint_convergence = true;} - else { adjoint_convergence = false;} - - delete [] sbuf_conv; - delete [] rbuf_conv; - -#endif - - return adjoint_convergence; - -} - -void CDiscAdjFSIDriver::ConvergenceHistory(unsigned long IntIter, - unsigned long nIntIter, - unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT, - unsigned short kind_recording){ - - unsigned long BGS_Iter = config_container[ZONE_FLOW]->GetOuterIter(); - - - if (rank == MASTER_NODE) - output_legacy->SetConvHistory_Header(&ConvHist_file[ZONE_0][INST_0], config_container[ZONE_0], ZONE_0, INST_0); - - if (kind_recording == FLOW_CONS_VARS) { - - if (rank == MASTER_NODE){ - if (IntIter == 0){ - cout << endl; - cout << " IntIter" << " BGSIter" << " Res[Psi_Rho]" << " Res[Psi_E]" << endl; - } - - if (IntIter % config_container[ZONE_FLOW]->GetWrt_Con_Freq() == 0){ - /*--- Output the flow convergence ---*/ - /*--- This is temporary as it requires several changes in the output structure ---*/ - unsigned short nVar_Flow = solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->GetnVar(); - cout.width(8); cout << IntIter; - cout.width(11); cout << BGS_Iter + 1; - cout.precision(6); cout.setf(ios::fixed, ios::floatfield); - cout.width(15); cout << log10(solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->GetRes_RMS(0)); - cout.width(15); cout << log10(solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->GetRes_RMS(nVar_Flow-1)); - cout << endl; - } - - } - } - - if (kind_recording == FEA_DISP_VARS) { - /*--- Set the convergence criteria (only residual possible) ---*/ - output_legacy->SetConvHistory_Body(NULL, geometry_container, solver_container, config_container, integration_container, true, 0.0, ZONE_STRUCT, INST_0); - - } - - -} - - -bool CDiscAdjFSIDriver::BGSConvergence(unsigned long IntIter, - unsigned short ZONE_FLOW, - unsigned short ZONE_STRUCT){ - - unsigned short nVar_Flow = solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->GetnVar(), - nVar_Struct = solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->GetnVar(); - unsigned short iRes; - - bool flow_converged_absolute = false, - flow_converged_relative = false, - struct_converged_absolute = false, - struct_converged_relative = false; - - bool Convergence = false; - - /*--- Compute the residual for the flow and structural zones ---*/ - - /*--- Flow ---*/ - - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->ComputeResidual_Multizone(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW]); - - /*--- Structure ---*/ - - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->ComputeResidual_Multizone(geometry_container[ZONE_STRUCT][INST_0][MESH_0], - config_container[ZONE_STRUCT]); - - - /*--- Retrieve residuals ---*/ - - /*--- Flow residuals ---*/ - - for (iRes = 0; iRes < nVar_Flow; iRes++){ - residual_flow[iRes] = log10(solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->GetRes_BGS(iRes)); - if (IntIter == 0) init_res_flow[iRes] = residual_flow[iRes]; - residual_flow_rel[iRes] = fabs(residual_flow[iRes] - init_res_flow[iRes]); - } - - /*--- Structure residuals ---*/ - - for (iRes = 0; iRes < nVar_Struct; iRes++){ - residual_struct[iRes] = log10(solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->GetRes_BGS(iRes)); - if (IntIter == 0) init_res_struct[iRes] = residual_struct[iRes]; - residual_struct_rel[iRes] = fabs(residual_struct[iRes] - init_res_struct[iRes]); - } - - /*--- Check convergence ---*/ - flow_converged_absolute = ((residual_flow[0] < flow_criteria) && (residual_flow[nVar_Flow-1] < flow_criteria)); - flow_converged_relative = ((residual_flow_rel[0] > flow_criteria_rel) && (residual_flow_rel[nVar_Flow-1] > flow_criteria_rel)); - - struct_converged_absolute = ((residual_struct[0] < structure_criteria) && (residual_struct[nVar_Flow-1] < structure_criteria)); - struct_converged_relative = ((residual_struct_rel[0] > structure_criteria_rel) && (residual_struct_rel[nVar_Flow-1] > structure_criteria_rel)); - - Convergence = ((flow_converged_absolute && struct_converged_absolute) || - (flow_converged_absolute && struct_converged_relative) || - (flow_converged_relative && struct_converged_relative) || - (flow_converged_relative && struct_converged_absolute)); - - if (rank == MASTER_NODE){ - - cout << "\n-------------------------------------------------------------------------\n\n"; - cout << "Convergence summary for BGS iteration " << IntIter << "\n\n"; - /*--- TODO: This is a workaround until the TestCases.py script incorporates new classes for nested loops. ---*/ - cout << "Iter[ID]" << " BGSRes[Psi_Rho]" << " BGSRes[Psi_E]" << " BGSRes[Psi_Ux]" << " BGSRes[Psi_Uy]\n"; - cout.precision(6); cout.setf(ios::fixed, ios::floatfield); - cout << "|"; cout.width(8); cout << IntIter*1000; - cout << "|"; cout.width(17); cout << residual_flow[0]; - cout << "|"; cout.width(15); cout << residual_flow[nVar_Flow-1]; - cout << "|"; cout.width(16); cout << residual_struct[0]; - cout << "|"; cout.width(16); cout << residual_struct[1]; - cout << "|"; cout << "\n\n-------------------------------------------------------------------------" << endl; - - - bool write_history = true; - unsigned short iVar; - - /*--- Header of the temporary output file ---*/ - if ((write_history) && (rank == MASTER_NODE)){ - ofstream myfile_res; - bool de_effects = config_container[ZONE_STRUCT]->GetDE_Effects(); - - myfile_res.open ("history_adjoint_FSI.csv", ios::app); - - myfile_res << IntIter << "\t"; - - myfile_res.precision(15); - - for (iVar = 0; iVar < nVar_Flow; iVar++){ - myfile_res << fixed << residual_flow[iVar] << "\t"; - } - - for (iVar = 0; iVar < nVar_Struct; iVar++){ - myfile_res << fixed << residual_struct[iVar] << "\t"; - } - - for (iVar = 0; iVar < config_container[ZONE_STRUCT]->GetnElasticityMod(); iVar++) - myfile_res << scientific << solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->GetGlobal_Sens_E(iVar) << "\t"; - for (iVar = 0; iVar < config_container[ZONE_STRUCT]->GetnPoissonRatio(); iVar++) - myfile_res << scientific << solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->GetGlobal_Sens_Nu(iVar) << "\t"; - if (de_effects){ - for (iVar = 0; iVar < config_container[ZONE_STRUCT]->GetnElectric_Field(); iVar++) - myfile_res << scientific << solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->GetGlobal_Sens_EField(0) << "\t"; - } - - myfile_res << endl; - - myfile_res.close(); - } - - // TEST: for implementation of python framework in coupled FSI problems - if ((config_container[ZONE_1]->GetDV_FEA() != NODV_FEA) && (rank == MASTER_NODE)){ - - /*--- Header of the temporary output file ---*/ - ofstream myfile_res; - - switch (config_container[ZONE_1]->GetDV_FEA()) { - case YOUNG_MODULUS: - myfile_res.open("grad_young.opt"); - break; - case POISSON_RATIO: - myfile_res.open("grad_poisson.opt"); - break; - case DENSITY_VAL: - case DEAD_WEIGHT: - myfile_res.open("grad_density.opt"); - break; - case ELECTRIC_FIELD: - myfile_res.open("grad_efield.opt"); - break; - default: - myfile_res.open("grad.opt"); - break; - } - - unsigned short iDV; - unsigned short nDV = solver_container[ZONE_1][INST_0][MESH_0][ADJFEA_SOL]->GetnDVFEA(); - - myfile_res << "INDEX" << "\t" << "GRAD" << endl; - - myfile_res.precision(15); - - for (iDV = 0; iDV < nDV; iDV++){ - myfile_res << iDV; - myfile_res << "\t"; - myfile_res << scientific << solver_container[ZONE_1][INST_0][MESH_0][ADJFEA_SOL]->GetGlobal_Sens_DVFEA(iDV); - myfile_res << endl; - } - - myfile_res.close(); - } - - - } - - /*--- Apply the same convergence criteria to all the processors ---*/ - -#ifdef HAVE_MPI - - unsigned short *sbuf_conv = NULL, *rbuf_conv = NULL; - sbuf_conv = new unsigned short[1]; sbuf_conv[0] = 0; - rbuf_conv = new unsigned short[1]; rbuf_conv[0] = 0; - - /*--- Convergence criteria ---*/ - - sbuf_conv[0] = Convergence; - SU2_MPI::Reduce(sbuf_conv, rbuf_conv, 1, MPI_UNSIGNED_SHORT, MPI_SUM, MASTER_NODE, MPI_COMM_WORLD); - - /*-- Compute global convergence criteria in the master node --*/ - - sbuf_conv[0] = 0; - if (rank == MASTER_NODE) { - if (rbuf_conv[0] == size) sbuf_conv[0] = 1; - else sbuf_conv[0] = 0; - } - - SU2_MPI::Bcast(sbuf_conv, 1, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD); - - if (sbuf_conv[0] == 1) { Convergence = true;} - else { Convergence = false;} - - delete [] sbuf_conv; - delete [] rbuf_conv; - -#endif - - /*--- Update the solution for the flow and structural zones ---*/ - - /*--- Flow ---*/ - - solver_container[ZONE_FLOW][INST_0][MESH_0][ADJFLOW_SOL]->UpdateSolution_BGS(geometry_container[ZONE_FLOW][INST_0][MESH_0], - config_container[ZONE_FLOW]); - - /*--- Structure ---*/ - - solver_container[ZONE_STRUCT][INST_0][MESH_0][ADJFEA_SOL]->UpdateSolution_BGS(geometry_container[ZONE_STRUCT][INST_0][MESH_0], - config_container[ZONE_STRUCT]); - - return Convergence; -} - -void CDiscAdjFSIDriver::Transfer_Displacements(unsigned short donorZone, unsigned short targetZone) { - - - interface_container[donorZone][targetZone]->BroadcastData(solver_container[donorZone][INST_0][MESH_0][FEA_SOL],solver_container[targetZone][INST_0][MESH_0][FLOW_SOL], - geometry_container[donorZone][INST_0][MESH_0],geometry_container[targetZone][INST_0][MESH_0], - config_container[donorZone], config_container[targetZone]); - -} - -void CDiscAdjFSIDriver::Transfer_Tractions(unsigned short donorZone, unsigned short targetZone) { - - interface_container[donorZone][targetZone]->BroadcastData(solver_container[donorZone][INST_0][MESH_0][FEA_SOL],solver_container[targetZone][INST_0][MESH_0][FLOW_SOL], - geometry_container[donorZone][INST_0][MESH_0],geometry_container[targetZone][INST_0][MESH_0], - config_container[donorZone], config_container[targetZone]); -} From 18520a6a8572984144f13b230e25f9e7eafaec3b Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 26 Mar 2020 09:27:43 +0000 Subject: [PATCH 36/79] remove CElasticityMovement --- Common/include/CConfig.hpp | 2 +- Common/include/grid_movement_structure.hpp | 177 ----- Common/include/grid_movement_structure.inl | 4 - Common/include/option_structure.hpp | 2 - Common/src/CConfig.cpp | 5 +- Common/src/grid_movement_structure.cpp | 811 --------------------- SU2_CFD/src/drivers/CDriver.cpp | 13 +- SU2_CFD/src/drivers/CMultizoneDriver.cpp | 2 +- SU2_CFD/src/iteration_structure.cpp | 376 +++++----- 9 files changed, 185 insertions(+), 1207 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 604f83e10f9b..6d6adeca3f76 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -5574,7 +5574,7 @@ class CConfig { * \return TRUE if there is a grid movement; otherwise FALSE. */ bool GetGrid_Movement(void) const { - return (Kind_GridMovement != NO_MOVEMENT) || ((nKind_SurfaceMovement > 0) && !GetSurface_Movement(FLUID_STRUCTURE_STATIC)); + return (Kind_GridMovement != NO_MOVEMENT) || (nKind_SurfaceMovement > 0); } /*! diff --git a/Common/include/grid_movement_structure.hpp b/Common/include/grid_movement_structure.hpp index ccc03acd693b..5b936fd14eb2 100644 --- a/Common/include/grid_movement_structure.hpp +++ b/Common/include/grid_movement_structure.hpp @@ -1290,183 +1290,6 @@ class CVolumetricMovement : public CGridMovement { virtual void Boundary_Dependencies(CGeometry **geometry, CConfig *config); }; -/*! - * \class CElasticityMovement - * \brief Class for moving the volumetric numerical grid using the new linear elasticity solver. - * \author R.Sanchez, based on CVolumetricMovement developments of F. Palacios, A. Bueno, T. Economon, S. Padron - * \version 7.0.2 "Blackbird" - */ -class CElasticityMovement : public CVolumetricMovement { -protected: - - unsigned short nDim; /*!< \brief Number of dimensions. */ - unsigned short nVar; /*!< \brief Number of variables. */ - - unsigned long nPoint; /*!< \brief Number of points. */ - unsigned long nPointDomain; /*!< \brief Number of points in the domain. */ - - unsigned long nIterMesh; /*!< \brief Number of iterations in the mesh update. +*/ - su2double valResidual; - - su2double *Residual, /*!< \brief Auxiliary nDim vector. */ - *Solution; /*!< \brief Auxiliary nDim vector. */ - - su2double **matrixZeros; /*!< \brief Submatrix to make zeros and impose boundary conditions. */ - su2double **matrixId; /*!< \brief Diagonal submatrix to impose boundary conditions. */ - - su2double MinVolume; - su2double MaxVolume; - -#ifndef CODI_FORWARD_TYPE - CSysSolve System; - CSysMatrix StiffMatrix; /*!< \brief Matrix to store the point-to-point stiffness. */ -#else - CSysSolve System; - CSysMatrix StiffMatrix; -#endif - CSysVector LinSysSol; - CSysVector LinSysRes; - - su2double E; /*!< \brief Young's modulus of elasticity. */ - su2double Nu; /*!< \brief Poisson's ratio. */ - - su2double Mu; /*!< \brief Lame's coeficient. */ - su2double Lambda; /*!< \brief Lame's coeficient. */ - - su2double **Jacobian_ij; /*!< \brief Submatrix to store the constitutive term for node ij. */ - - su2double **Ba_Mat, /*!< \brief Matrix B for node a - Auxiliary. */ - **Bb_Mat; /*!< \brief Matrix B for node b - Auxiliary. */ - su2double **KAux_ab; /*!< \brief Stiffness sub-term - Auxiliary. */ - su2double **D_Mat; /*!< \brief Constitutive matrix - Auxiliary. */ - su2double **GradNi_Ref_Mat; /*!< \brief Gradients of Ni - Auxiliary. */ - -public: - - CElement** element_container; /*!< \brief Container which stores the element information. */ - - /*! - * \brief Constructor of the class. - */ - CElasticityMovement(CGeometry *geometry, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CElasticityMovement(void); - - /*! - * \brief Grid deformation using the linear elasticity equations. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] UpdateGeo - Update geometry. - * \param[in] Derivative - Compute the derivative (disabled by default). Does not actually deform the grid if enabled. - */ - void SetVolume_Deformation_Elas(CGeometry *geometry, CConfig *config, bool UpdateGeo, bool screen_output, bool Derivative = false); - - /*! - * \brief Update the value of the coordinates after the grid movement. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void UpdateGridCoord(CGeometry *geometry, CConfig *config); - - /*! - * \brief Update the dual grid after the grid movement (edges and control volumes). - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void UpdateDualGrid(CGeometry *geometry, CConfig *config); - - /*! - * \brief Update the coarse multigrid levels after the grid movement. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void UpdateMultiGrid(CGeometry **geometry, CConfig *config); - - /*! - * \brief Check the boundary vertex that are going to be moved. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetBoundaryDisplacements(CGeometry *geometry, CConfig *config); - - /*! - * \brief Set the boundary displacements to 0. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] val_marker - - */ - void SetClamped_Boundary(CGeometry *geometry, CConfig *config, unsigned short val_marker); - - /*! - * \brief Set the boundary displacements to the imposed external value. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetMoving_Boundary(CGeometry *geometry, CConfig *config, unsigned short val_marker); - - /*! - * \brief Compute the min and max volume for the stiffness matrix for grid deformation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \return Value of the length of the smallest edge of the grid. - */ - void SetMinMaxVolume(CGeometry *geometry, CConfig *config); - - /*! - * \brief Compute the min and max volume for the stiffness matrix for grid deformation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \return Value of the length of the smallest edge of the grid. - */ - void SetStiffnessMatrix(CGeometry *geometry, CConfig *config); - - /*! - * \brief Store the number of iterations when moving the mesh. - * \param[in] val_nIterMesh - Number of iterations. - */ - void Set_nIterMesh(unsigned long val_nIterMesh); - - /*! - * \brief Retrieve the number of iterations when moving the mesh. - * \param[out] Number of iterations. - */ - unsigned long Get_nIterMesh(void); - - /*! - * \brief Compute the stiffness of the element and the parameters Lambda and Mu - */ - void Set_Element_Stiffness(su2double ElemVolume, CConfig *config); - - /*! - * \brief Compute the stiffness of the element and the parameters Lambda and Mu - */ - void Compute_Element_Contribution(CElement *element, CConfig *config); - - /*! - * \brief Compute the constitutive matrix in an element for mesh deformation problems - * \param[in] element_container - Element structure for the particular element integrated. - */ - void Compute_Constitutive_Matrix(void); - - /*! - * \brief Set the boundary displacements in the mesh side of the problem - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void Transfer_Boundary_Displacements(CGeometry *geometry, CConfig *config, unsigned short val_marker); - - /*! - * \brief Set the boundary displacements in the mesh side of the problem - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void Boundary_Dependencies(CGeometry **geometry, CConfig *config); - -}; - /*! * \class CSurfaceMovement * \brief Class for moving the surface numerical grid. diff --git a/Common/include/grid_movement_structure.inl b/Common/include/grid_movement_structure.inl index ce936a85918b..4fdd290c162b 100644 --- a/Common/include/grid_movement_structure.inl +++ b/Common/include/grid_movement_structure.inl @@ -216,10 +216,6 @@ inline void CVolumetricMovement::SetVolume_Deformation_Elas(CGeometry *geometry, inline void CVolumetricMovement::Boundary_Dependencies(CGeometry **geometry, CConfig *config) { } -inline void CElasticityMovement::Set_nIterMesh(unsigned long val_nIterMesh) { nIterMesh = val_nIterMesh; } - -inline unsigned long CElasticityMovement::Get_nIterMesh() { return nIterMesh; } - inline bool CSurfaceMovement::CheckFFDBoxDefinition(CConfig *config, unsigned short iDV) { for (unsigned short iFFDBox = 0; iFFDBox < GetnFFDBox(); iFFDBox++) { if (FFDBox[iFFDBox]->GetTag() == config->GetFFDTag(iDV)) { return true;} diff --git a/Common/include/option_structure.hpp b/Common/include/option_structure.hpp index 20cba60d8d4b..5f85a1a48d8b 100644 --- a/Common/include/option_structure.hpp +++ b/Common/include/option_structure.hpp @@ -648,14 +648,12 @@ enum ENUM_SURFACEMOVEMENT { FLUID_STRUCTURE = 5, /*!< \brief Fluid structure deformation. */ EXTERNAL = 6, /*!< \brief Simulation with external motion. */ EXTERNAL_ROTATION = 7, /*!< \brief Simulation with external rotation motion. */ - FLUID_STRUCTURE_STATIC = 8 /*!< \brief Fluid structure deformation with no grid velocity. */ }; static const MapType SurfaceMovement_Map = { MakePair("DEFORMING", DEFORMING) MakePair("MOVING_WALL", MOVING_WALL) MakePair("AEROELASTIC_RIGID_MOTION", AEROELASTIC_RIGID_MOTION) MakePair("AEROELASTIC", AEROELASTIC) - MakePair("FLUID_STRUCTURE_STATIC", FLUID_STRUCTURE_STATIC) MakePair("FLUID_STRUCTURE", FLUID_STRUCTURE) MakePair("EXTERNAL", EXTERNAL) MakePair("EXTERNAL_ROTATION", EXTERNAL_ROTATION) diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index cf65fc655c53..c8df44966908 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -3572,11 +3572,11 @@ void CConfig::SetPostprocessing(unsigned short val_software, unsigned short val_ } } - if (nKind_SurfaceMovement > 1 && (GetSurface_Movement(FLUID_STRUCTURE) || GetSurface_Movement(FLUID_STRUCTURE_STATIC))){ + if ((nKind_SurfaceMovement > 1) && GetSurface_Movement(FLUID_STRUCTURE)) { SU2_MPI::Error("FSI in combination with moving surfaces is currently not supported.", CURRENT_FUNCTION); } - if (nKind_SurfaceMovement != nMarker_Moving && !(GetSurface_Movement(FLUID_STRUCTURE) || GetSurface_Movement(FLUID_STRUCTURE_STATIC))){ + if ((nKind_SurfaceMovement != nMarker_Moving) && !GetSurface_Movement(FLUID_STRUCTURE)) { SU2_MPI::Error("Number of KIND_SURFACE_MOVEMENT must match number of MARKER_MOVING", CURRENT_FUNCTION); } @@ -8420,7 +8420,6 @@ bool CConfig::GetVolumetric_Movement(){ GetSurface_Movement(DEFORMING) || GetSurface_Movement(AEROELASTIC_RIGID_MOTION)|| GetSurface_Movement(FLUID_STRUCTURE) || - GetSurface_Movement(FLUID_STRUCTURE_STATIC) || GetSurface_Movement(EXTERNAL) || GetSurface_Movement(EXTERNAL_ROTATION)){ volumetric_movement = true; diff --git a/Common/src/grid_movement_structure.cpp b/Common/src/grid_movement_structure.cpp index a430e2f0eabf..86a213ff4714 100644 --- a/Common/src/grid_movement_structure.cpp +++ b/Common/src/grid_movement_structure.cpp @@ -9109,817 +9109,6 @@ su2double CFreeFormDefBox::GetDerivative5(su2double *uvw, unsigned short dim, un return value; } - - -CElasticityMovement::CElasticityMovement(CGeometry *geometry, CConfig *config) : CVolumetricMovement(), System(true) { - - size = SU2_MPI::GetSize(); - rank = SU2_MPI::GetRank(); - - /*--- Initialize the number of spatial dimensions, length of the state - vector (same as spatial dimensions for grid deformation), and grid nodes. ---*/ - - unsigned short iDim, jDim; - - nDim = geometry->GetnDim(); - nVar = geometry->GetnDim(); - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - - nIterMesh = 0; - valResidual = 0.0; - - MinVolume = 0.0; - MaxVolume = 0.0; - - Residual = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Residual[iDim] = 0.0; - Solution = new su2double[nDim]; for (iDim = 0; iDim < nDim; iDim++) Solution[iDim] = 0.0; - - /*--- Initialize matrix, solution, and r.h.s. structures for the linear solver. ---*/ - - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - StiffMatrix.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); - - /*--- Matrices to impose boundary conditions ---*/ - - matrixZeros = new su2double *[nDim]; - matrixId = new su2double *[nDim]; - for(iDim = 0; iDim < nDim; iDim++){ - matrixZeros[iDim] = new su2double[nDim]; - matrixId[iDim] = new su2double[nDim]; - } - - for(iDim = 0; iDim < nDim; iDim++){ - for (jDim = 0; jDim < nDim; jDim++){ - matrixZeros[iDim][jDim] = 0.0; - matrixId[iDim][jDim] = 0.0; - } - matrixId[iDim][iDim] = 1.0; - } - - /*--- Structural parameters ---*/ - - E = config->GetDeform_ElasticityMod(); - Nu = config->GetDeform_PoissonRatio(); - - Mu = E / (2.0*(1.0 + Nu)); - Lambda = Nu*E/((1.0+Nu)*(1.0-2.0*Nu)); - - /*--- Element container structure ---*/ - - element_container = new CElement* [MAX_FE_KINDS]; - for (unsigned short iKind = 0; iKind < MAX_FE_KINDS; iKind++) { - element_container[iKind] = NULL; - } - if (nDim == 2){ - element_container[EL_TRIA] = new CTRIA1(); - element_container[EL_QUAD] = new CQUAD4(); - } - else { - element_container[EL_TETRA] = new CTETRA1(); - element_container[EL_HEXA] = new CHEXA8(); - element_container[EL_PYRAM] = new CPYRAM5(); - element_container[EL_PRISM] = new CPRISM6(); - } - - /*--- Term ij of the Jacobian ---*/ - - Jacobian_ij = new su2double*[nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - Jacobian_ij[iDim] = new su2double [nDim]; - for (jDim = 0; jDim < nDim; jDim++) { - Jacobian_ij[iDim][jDim] = 0.0; - } - } - - KAux_ab = new su2double* [nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - KAux_ab[iDim] = new su2double[nDim]; - } - - unsigned short iVar; - - if (nDim == 2){ - Ba_Mat = new su2double* [3]; - Bb_Mat = new su2double* [3]; - D_Mat = new su2double* [3]; - GradNi_Ref_Mat = new su2double* [4]; - for (iVar = 0; iVar < 3; iVar++) { - Ba_Mat[iVar] = new su2double[nDim]; - Bb_Mat[iVar] = new su2double[nDim]; - D_Mat[iVar] = new su2double[3]; - } - for (iVar = 0; iVar < 4; iVar++) { - GradNi_Ref_Mat[iVar] = new su2double[nDim]; - } - } - else if (nDim == 3){ - Ba_Mat = new su2double* [6]; - Bb_Mat = new su2double* [6]; - D_Mat = new su2double* [6]; - GradNi_Ref_Mat = new su2double* [8]; - for (iVar = 0; iVar < 6; iVar++) { - Ba_Mat[iVar] = new su2double[nDim]; - Bb_Mat[iVar] = new su2double[nDim]; - D_Mat[iVar] = new su2double[6]; - } - for (iVar = 0; iVar < 8; iVar++) { - GradNi_Ref_Mat[iVar] = new su2double[nDim]; - } - } - - - -} - -CElasticityMovement::~CElasticityMovement(void) { - - unsigned short iDim, iVar; - - delete [] Residual; - delete [] Solution; - - for (iDim = 0; iDim < nDim; iDim++) { - delete [] matrixZeros[iDim]; - delete [] matrixId[iDim]; - delete [] Jacobian_ij[iDim]; - delete [] KAux_ab[iDim]; - } - delete [] matrixZeros; - delete [] matrixId; - delete [] Jacobian_ij; - delete [] KAux_ab; - - if (nDim == 2){ - for (iVar = 0; iVar < 3; iVar++){ - delete [] Ba_Mat[iVar]; - delete [] Bb_Mat[iVar]; - delete [] D_Mat[iVar]; - } - for (iVar = 0; iVar < 4; iVar++){ - delete [] GradNi_Ref_Mat[iVar]; - } - } - else if (nDim == 3){ - for (iVar = 0; iVar < 6; iVar++){ - delete [] Ba_Mat[iVar]; - delete [] Bb_Mat[iVar]; - delete [] D_Mat[iVar]; - } - for (iVar = 0; iVar < 8; iVar++){ - delete [] GradNi_Ref_Mat[iVar]; - } - } - - delete [] Ba_Mat; - delete [] Bb_Mat; - delete [] D_Mat; - delete [] GradNi_Ref_Mat; - - if (element_container != NULL) { - for (iVar = 0; iVar < MAX_FE_KINDS; iVar++){ - if (element_container[iVar] != NULL) delete element_container[iVar]; - } - delete [] element_container; - } - -} - - -void CElasticityMovement::SetVolume_Deformation_Elas(CGeometry *geometry, CConfig *config, bool UpdateGeo, bool screen_output, bool Derivative){ - - unsigned long iNonlinear_Iter, Nonlinear_Iter = 0; - - bool discrete_adjoint = config->GetDiscrete_Adjoint(); - - /*--- Retrieve number or internal iterations from config ---*/ - - Nonlinear_Iter = config->GetGridDef_Nonlinear_Iter(); - - /*--- Loop over the total number of grid deformation iterations. The surface - deformation can be divided into increments to help with stability. ---*/ - - for (iNonlinear_Iter = 0; iNonlinear_Iter < Nonlinear_Iter; iNonlinear_Iter++) { - - /*--- Initialize vector and sparse matrix ---*/ - LinSysSol.SetValZero(); - LinSysRes.SetValZero(); - StiffMatrix.SetValZero(); - - if ((rank == MASTER_NODE) && (!discrete_adjoint) && screen_output) - cout << "Computing volumes of the grid elements." << endl; - - /*--- Compute the minimum and maximum area/volume for the mesh. ---*/ - SetMinMaxVolume(geometry, config); - if ((rank == MASTER_NODE) && (!discrete_adjoint) && screen_output) { - if (nDim == 2) cout << scientific << "Min. area: "<< MinVolume <<", max. area: " << MaxVolume <<"." << endl; - else cout << scientific << "Min. volume: "<< MinVolume <<", max. volume: " << MaxVolume <<"." << endl; - } - - /*--- Compute the stiffness matrix. ---*/ - SetStiffnessMatrix(geometry, config); - - /*--- Impose boundary conditions (all of them are ESSENTIAL BC's - displacements). ---*/ - SetBoundaryDisplacements(geometry, config); - - /*--- Solve the linear system. ---*/ - -#ifdef CODI_REVERSE_TYPE - /*--- We need to guard the SendReceive_Solution otherwise the FSI adjoint breaks. ---*/ - bool TapeActive = NO; - if (config->GetDiscrete_Adjoint()) { - TapeActive = AD::globalTape.isActive(); - AD::StopRecording(); - } -#endif - StiffMatrix.InitiateComms(LinSysSol, geometry, config, SOLUTION_MATRIX); - StiffMatrix.CompleteComms(LinSysSol, geometry, config, SOLUTION_MATRIX); - - StiffMatrix.InitiateComms(LinSysRes, geometry, config, SOLUTION_MATRIX); - StiffMatrix.CompleteComms(LinSysRes, geometry, config, SOLUTION_MATRIX); -#ifdef CODI_REVERSE_TYPE - if (TapeActive) AD::StartRecording(); -#endif - nIterMesh = System.Solve(StiffMatrix, LinSysRes, LinSysSol, geometry, config); - valResidual = System.GetResidual(); - - /*--- Update the grid coordinates and cell volumes using the solution - of the linear system (usol contains the x, y, z displacements). ---*/ - UpdateGridCoord(geometry, config); - - if (UpdateGeo) - UpdateDualGrid(geometry, config); - - /*--- Check for failed deformation (negative volumes). ---*/ - /*--- In order to do this, we recompute the minimum and maximum area/volume for the mesh. ---*/ - SetMinMaxVolume(geometry, config); - - if ((rank == MASTER_NODE) && (!discrete_adjoint) && screen_output) { - cout << scientific << "Non-linear iter.: " << iNonlinear_Iter+1 << "/" << Nonlinear_Iter << ". Linear iter.: " << nIterMesh << ". "; - if (nDim == 2) cout << "Min. area: " << MinVolume << ". Error: " << valResidual << "." << endl; - else cout << "Min. volume: " << MinVolume << ". Error: " << valResidual << "." << endl; - } - - } - -} - - -void CElasticityMovement::UpdateGridCoord(CGeometry *geometry, CConfig *config){ - - unsigned short iDim; - unsigned long iPoint, total_index; - su2double new_coord; - - /*--- Update the grid coordinates using the solution of the linear system - after grid deformation (LinSysSol contains the x, y, z displacements). ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint*nDim + iDim; - new_coord = geometry->node[iPoint]->GetCoord(iDim)+LinSysSol[total_index]; - if (fabs(new_coord) < EPS*EPS) new_coord = 0.0; - geometry->node[iPoint]->SetCoord(iDim, new_coord); - } - - /* --- LinSysSol contains the non-transformed displacements in the periodic halo cells. - * Hence we still need a communication of the transformed coordinates, otherwise periodicity - * is not maintained. ---*/ - - geometry->InitiateComms(geometry, config, COORDINATES); - geometry->CompleteComms(geometry, config, COORDINATES); - -} - - -void CElasticityMovement::UpdateDualGrid(CGeometry *geometry, CConfig *config){ - - /*--- After moving all nodes, update the dual mesh. Recompute the edges and - dual mesh control volumes in the domain and on the boundaries. ---*/ - - geometry->SetCoord_CG(); - geometry->SetControlVolume(config, UPDATE); - geometry->SetBoundControlVolume(config, UPDATE); - geometry->SetMaxLength(config); - -} - - -void CElasticityMovement::UpdateMultiGrid(CGeometry **geometry, CConfig *config){ - - unsigned short iMGfine, iMGlevel, nMGlevel = config->GetnMGLevels(); - - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ - - for (iMGlevel = 1; iMGlevel <= nMGlevel; iMGlevel++) { - iMGfine = iMGlevel-1; - geometry[iMGlevel]->SetControlVolume(config, geometry[iMGfine], UPDATE); - geometry[iMGlevel]->SetBoundControlVolume(config, geometry[iMGfine],UPDATE); - geometry[iMGlevel]->SetCoord(geometry[iMGfine]); - if (config->GetGrid_Movement()) - geometry[iMGlevel]->SetRestricted_GridVelocity(geometry[iMGfine], config); - } - -} - -void CElasticityMovement::SetBoundaryDisplacements(CGeometry *geometry, CConfig *config){ - - /*--- Get the SU2 module. SU2_CFD will use this routine for dynamically - deforming meshes (MARKER_FSI_INTERFACE). ---*/ - - unsigned short Kind_SU2 = config->GetKind_SU2(); - - /*--- Share halo vertex displacements across ranks using the solution vector. - The transfer routines do not do this, i.e. halo vertices have wrong values. ---*/ - - unsigned short iMarker, iDim; - unsigned long iNode, iVertex; - - su2double VarIncrement = 1.0/su2double(config->GetGridDef_Nonlinear_Iter()); - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_ZoneInterface(iMarker) != 0 || - config->GetMarker_All_Moving(iMarker)) - && (Kind_SU2 == SU2_CFD)) { - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - /*--- Get node index ---*/ - iNode = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iNode]->GetDomain()) { - - /*--- Get the displacement on the vertex ---*/ - for (iDim = 0; iDim < nDim; iDim++) - Solution[iDim] = geometry->vertex[iMarker][iVertex]->GetVarCoord()[iDim] * VarIncrement; - - /*--- Initialize the solution vector ---*/ - LinSysSol.SetBlock(iNode, Solution); - } - } - } - } - StiffMatrix.InitiateComms(LinSysSol, geometry, config, SOLUTION_MATRIX); - StiffMatrix.CompleteComms(LinSysSol, geometry, config, SOLUTION_MATRIX); - - /*--- Apply displacement boundary conditions to the FSI interfaces. ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_ZoneInterface(iMarker) != 0 || - config->GetMarker_All_Moving(iMarker)) - && (Kind_SU2 == SU2_CFD)) { - SetMoving_Boundary(geometry, config, iMarker); - } - } - - /*--- Now, set to zero displacements of all the other boundary conditions, except the symmetry - plane, the receive boundaries and periodic boundaries. ---*/ - - - /*--- As initialization, set to zero displacements of all the surfaces except the symmetry - plane, the receive boundaries and periodic boundaries. ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (((config->GetMarker_All_KindBC(iMarker) != SYMMETRY_PLANE) && - (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) && - (config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY)) - && !config->GetMarker_All_Moving(iMarker)) { - - /*--- We must note that the FSI surfaces are not clamped ---*/ - if (config->GetMarker_All_ZoneInterface(iMarker) == 0){ - SetClamped_Boundary(geometry, config, iMarker); - } - } - } - - /*--- All others are pending. ---*/ - -} - - -void CElasticityMovement::SetClamped_Boundary(CGeometry *geometry, CConfig *config, unsigned short val_marker){ - - unsigned long iNode, iVertex; - - Solution[0] = 0.0; - Solution[1] = 0.0; - if (nDim==3) Solution[2] = 0.0; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - /*--- Get node index ---*/ - iNode = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Set and enforce solution ---*/ - LinSysSol.SetBlock(iNode, Solution); - StiffMatrix.EnforceSolutionAtNode(iNode, Solution, LinSysRes); - - } - -} - -void CElasticityMovement::SetMoving_Boundary(CGeometry *geometry, CConfig *config, unsigned short val_marker){ - - unsigned long iNode, iVertex; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - /*--- Get node index ---*/ - iNode = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Enforce solution ---*/ - StiffMatrix.EnforceSolutionAtNode(iNode, LinSysSol.GetBlock(iNode), LinSysRes); - - } - -} - -void CElasticityMovement::SetMinMaxVolume(CGeometry *geometry, CConfig *config) { - - unsigned long iElem, ElemCounter = 0; - unsigned short iNode, iDim, nNodes = 0; - unsigned long indexNode[8]={0,0,0,0,0,0,0,0}; - su2double val_Coord; - int EL_KIND = 0; - - bool RightVol = true; - - su2double ElemVolume; - - MaxVolume = -1E22; MinVolume = 1E22; - - /*--- Loops over all the elements ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) {nNodes = 3; EL_KIND = EL_TRIA;} - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) {nNodes = 4; EL_KIND = EL_QUAD;} - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) {nNodes = 4; EL_KIND = EL_TETRA;} - if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) {nNodes = 5; EL_KIND = EL_PYRAM;} - if (geometry->elem[iElem]->GetVTK_Type() == PRISM) {nNodes = 6; EL_KIND = EL_PRISM;} - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) {nNodes = 8; EL_KIND = EL_HEXA;} - - /*--- For the number of nodes, we get the coordinates from the connectivity matrix and the geometry structure ---*/ - - for (iNode = 0; iNode < nNodes; iNode++) { - - indexNode[iNode] = geometry->elem[iElem]->GetNode(iNode); - - for (iDim = 0; iDim < nDim; iDim++) { - val_Coord = geometry->node[indexNode[iNode]]->GetCoord(iDim); - element_container[EL_KIND]->SetRef_Coord(iNode, iDim, val_Coord); - } - - } - - /*--- Compute the volume of the element (or the area in 2D cases ) ---*/ - - if (nDim == 2) ElemVolume = element_container[EL_KIND]->ComputeArea(); - else ElemVolume = element_container[EL_KIND]->ComputeVolume(); - - RightVol = true; - if (ElemVolume < 0.0) RightVol = false; - - MaxVolume = max(MaxVolume, ElemVolume); - MinVolume = min(MinVolume, ElemVolume); - geometry->elem[iElem]->SetVolume(ElemVolume); - - if (!RightVol) ElemCounter++; - - } - -#ifdef HAVE_MPI - unsigned long ElemCounter_Local = ElemCounter; ElemCounter = 0; - su2double MaxVolume_Local = MaxVolume; MaxVolume = 0.0; - su2double MinVolume_Local = MinVolume; MinVolume = 0.0; - SU2_MPI::Allreduce(&ElemCounter_Local, &ElemCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MaxVolume_Local, &MaxVolume, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MinVolume_Local, &MinVolume, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); -#endif - - /*--- Volume from 0 to 1 ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - ElemVolume = geometry->elem[iElem]->GetVolume()/MaxVolume; - geometry->elem[iElem]->SetVolume(ElemVolume); - } - - if ((ElemCounter != 0) && (rank == MASTER_NODE)) - cout <<"There are " << ElemCounter << " elements with negative volume.\n" << endl; - -} - - -void CElasticityMovement::SetStiffnessMatrix(CGeometry *geometry, CConfig *config){ - - unsigned long iElem; - unsigned short iNode, iDim, jDim, nNodes = 0; - unsigned long indexNode[8]={0,0,0,0,0,0,0,0}; - su2double val_Coord; - int EL_KIND = 0; - - const su2double *Kab = NULL; - unsigned short NelNodes, jNode; - - su2double ElemVolume; - - /*--- Loops over all the elements ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) {nNodes = 3; EL_KIND = EL_TRIA;} - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) {nNodes = 4; EL_KIND = EL_QUAD;} - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) {nNodes = 4; EL_KIND = EL_TETRA;} - if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) {nNodes = 5; EL_KIND = EL_PYRAM;} - if (geometry->elem[iElem]->GetVTK_Type() == PRISM) {nNodes = 6; EL_KIND = EL_PRISM;} - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) {nNodes = 8; EL_KIND = EL_HEXA;} - - /*--- For the number of nodes, we get the coordinates from the connectivity matrix and the geometry structure ---*/ - - for (iNode = 0; iNode < nNodes; iNode++) { - - indexNode[iNode] = geometry->elem[iElem]->GetNode(iNode); - - for (iDim = 0; iDim < nDim; iDim++) { - val_Coord = geometry->node[indexNode[iNode]]->GetCoord(iDim); - element_container[EL_KIND]->SetRef_Coord(iNode, iDim, val_Coord); - } - - } - - /*--- Retrieve the volume of the element (previously computed in SetMinMaxVolume()) ---*/ - - ElemVolume = geometry->elem[iElem]->GetVolume(); - - /*--- Compute the stiffness of the element ---*/ - Set_Element_Stiffness(ElemVolume, config); - - /*--- Compute the element contribution to the stiffness matrix ---*/ - - Compute_Element_Contribution(element_container[EL_KIND], config); - - /*--- Retrieve number of nodes ---*/ - - NelNodes = element_container[EL_KIND]->GetnNodes(); - - /*--- Assemble the stiffness matrix ---*/ - - for (iNode = 0; iNode < NelNodes; iNode++){ - - for (jNode = 0; jNode < NelNodes; jNode++){ - - Kab = element_container[EL_KIND]->Get_Kab(iNode, jNode); - - for (iDim = 0; iDim < nDim; iDim++){ - for (jDim = 0; jDim < nDim; jDim++){ - Jacobian_ij[iDim][jDim] = Kab[iDim*nDim+jDim]; - } - } - - StiffMatrix.AddBlock(indexNode[iNode], indexNode[jNode], Jacobian_ij); - - } - - } - - } - -} - - -void CElasticityMovement::Set_Element_Stiffness(su2double ElemVolume, CConfig *config) { - - switch (config->GetDeform_Stiffness_Type()) { - case INVERSE_VOLUME: - E = 1.0 / ElemVolume; // Stiffness inverse of the volume of the element - Nu = config->GetDeform_Coeff(); // Nu is normally a very large number, for rigid-body rotations, see Dwight (2009) - break; - case SOLID_WALL_DISTANCE: - SU2_MPI::Error("SOLID_WALL DISTANCE METHOD NOT YET IMPLEMENTED FOR THIS APPROACH!!", CURRENT_FUNCTION); - break; - case CONSTANT_STIFFNESS: - E = config->GetDeform_ElasticityMod(); - Nu = config->GetDeform_PoissonRatio(); - break; - } - - /*--- Lamé parameters ---*/ - - Mu = E / (2.0*(1.0 + Nu)); - Lambda = Nu*E/((1.0+Nu)*(1.0-2.0*Nu)); - -} - - -void CElasticityMovement::Compute_Element_Contribution(CElement *element, CConfig *config){ - - unsigned short iVar, jVar, kVar; - unsigned short iGauss, nGauss; - unsigned short iNode, jNode, nNode; - unsigned short iDim; - unsigned short bDim; - - su2double Weight, Jac_X; - - su2double AuxMatrix[3][6]; - - /*--- Initialize auxiliary matrices ---*/ - - if (nDim == 2) bDim = 3; - else bDim = 6; - - for (iVar = 0; iVar < bDim; iVar++){ - for (jVar = 0; jVar < nDim; jVar++){ - Ba_Mat[iVar][jVar] = 0.0; - Bb_Mat[iVar][jVar] = 0.0; - } - } - - for (iVar = 0; iVar < 3; iVar++){ - for (jVar = 0; jVar < 6; jVar++){ - AuxMatrix[iVar][jVar] = 0.0; - } - } - - element->ClearElement(); /*--- Restarts the element: avoids adding over previous results in other elements --*/ - element->ComputeGrad_Linear(); - nNode = element->GetnNodes(); - nGauss = element->GetnGaussPoints(); - - /*--- Compute the constitutive matrix (D_Mat) for the element - it only depends on lambda and mu, constant for the element ---*/ - Compute_Constitutive_Matrix(); - - for (iGauss = 0; iGauss < nGauss; iGauss++){ - - Weight = element->GetWeight(iGauss); - Jac_X = element->GetJ_X(iGauss); - - /*--- Retrieve the values of the gradients of the shape functions for each node ---*/ - /*--- This avoids repeated operations ---*/ - for (iNode = 0; iNode < nNode; iNode++){ - for (iDim = 0; iDim < nDim; iDim++){ - GradNi_Ref_Mat[iNode][iDim] = element->GetGradNi_X(iNode,iGauss,iDim); - } - } - - for (iNode = 0; iNode < nNode; iNode++){ - - if (nDim == 2){ - Ba_Mat[0][0] = GradNi_Ref_Mat[iNode][0]; - Ba_Mat[1][1] = GradNi_Ref_Mat[iNode][1]; - Ba_Mat[2][0] = GradNi_Ref_Mat[iNode][1]; - Ba_Mat[2][1] = GradNi_Ref_Mat[iNode][0]; - } - else if (nDim == 3){ - Ba_Mat[0][0] = GradNi_Ref_Mat[iNode][0]; - Ba_Mat[1][1] = GradNi_Ref_Mat[iNode][1]; - Ba_Mat[2][2] = GradNi_Ref_Mat[iNode][2]; - Ba_Mat[3][0] = GradNi_Ref_Mat[iNode][1]; - Ba_Mat[3][1] = GradNi_Ref_Mat[iNode][0]; - Ba_Mat[4][0] = GradNi_Ref_Mat[iNode][2]; - Ba_Mat[4][2] = GradNi_Ref_Mat[iNode][0]; - Ba_Mat[5][1] = GradNi_Ref_Mat[iNode][2]; - Ba_Mat[5][2] = GradNi_Ref_Mat[iNode][1]; - } - - /*--- Compute the BT.D Matrix ---*/ - - for (iVar = 0; iVar < nDim; iVar++){ - for (jVar = 0; jVar < bDim; jVar++){ - AuxMatrix[iVar][jVar] = 0.0; - for (kVar = 0; kVar < bDim; kVar++){ - AuxMatrix[iVar][jVar] += Ba_Mat[kVar][iVar]*D_Mat[kVar][jVar]; - } - } - } - - /*--- Assumming symmetry ---*/ - for (jNode = iNode; jNode < nNode; jNode++){ - if (nDim == 2){ - Bb_Mat[0][0] = GradNi_Ref_Mat[jNode][0]; - Bb_Mat[1][1] = GradNi_Ref_Mat[jNode][1]; - Bb_Mat[2][0] = GradNi_Ref_Mat[jNode][1]; - Bb_Mat[2][1] = GradNi_Ref_Mat[jNode][0]; - } - else if (nDim ==3){ - Bb_Mat[0][0] = GradNi_Ref_Mat[jNode][0]; - Bb_Mat[1][1] = GradNi_Ref_Mat[jNode][1]; - Bb_Mat[2][2] = GradNi_Ref_Mat[jNode][2]; - Bb_Mat[3][0] = GradNi_Ref_Mat[jNode][1]; - Bb_Mat[3][1] = GradNi_Ref_Mat[jNode][0]; - Bb_Mat[4][0] = GradNi_Ref_Mat[jNode][2]; - Bb_Mat[4][2] = GradNi_Ref_Mat[jNode][0]; - Bb_Mat[5][1] = GradNi_Ref_Mat[jNode][2]; - Bb_Mat[5][2] = GradNi_Ref_Mat[jNode][1]; - } - - for (iVar = 0; iVar < nDim; iVar++){ - for (jVar = 0; jVar < nDim; jVar++){ - KAux_ab[iVar][jVar] = 0.0; - for (kVar = 0; kVar < bDim; kVar++){ - KAux_ab[iVar][jVar] += Weight * AuxMatrix[iVar][kVar] * Bb_Mat[kVar][jVar] * Jac_X; - } - } - } - - element->Add_Kab(iNode, jNode, KAux_ab); - /*--- Symmetric terms --*/ - if (iNode != jNode){ - element->Add_Kab_T(jNode, iNode, KAux_ab); - } - - } - - } - - } - -} - -void CElasticityMovement::Compute_Constitutive_Matrix(void){ - - /*--- Compute the D Matrix (for plane strain and 3-D)---*/ - - if (nDim == 2){ - - /*--- Assuming plane strain ---*/ - D_Mat[0][0] = Lambda + 2.0*Mu; D_Mat[0][1] = Lambda; D_Mat[0][2] = 0.0; - D_Mat[1][0] = Lambda; D_Mat[1][1] = Lambda + 2.0*Mu; D_Mat[1][2] = 0.0; - D_Mat[2][0] = 0.0; D_Mat[2][1] = 0.0; D_Mat[2][2] = Mu; - - } - else if (nDim == 3){ - - D_Mat[0][0] = Lambda + 2.0*Mu; D_Mat[0][1] = Lambda; D_Mat[0][2] = Lambda; D_Mat[0][3] = 0.0; D_Mat[0][4] = 0.0; D_Mat[0][5] = 0.0; - D_Mat[1][0] = Lambda; D_Mat[1][1] = Lambda + 2.0*Mu; D_Mat[1][2] = Lambda; D_Mat[1][3] = 0.0; D_Mat[1][4] = 0.0; D_Mat[1][5] = 0.0; - D_Mat[2][0] = Lambda; D_Mat[2][1] = Lambda; D_Mat[2][2] = Lambda + 2.0*Mu; D_Mat[2][3] = 0.0; D_Mat[2][4] = 0.0; D_Mat[2][5] = 0.0; - D_Mat[3][0] = 0.0; D_Mat[3][1] = 0.0; D_Mat[3][2] = 0.0; D_Mat[3][3] = Mu; D_Mat[3][4] = 0.0; D_Mat[3][5] = 0.0; - D_Mat[4][0] = 0.0; D_Mat[4][1] = 0.0; D_Mat[4][2] = 0.0; D_Mat[4][3] = 0.0; D_Mat[4][4] = Mu; D_Mat[4][5] = 0.0; - D_Mat[5][0] = 0.0; D_Mat[5][1] = 0.0; D_Mat[5][2] = 0.0; D_Mat[5][3] = 0.0; D_Mat[5][4] = 0.0; D_Mat[5][5] = Mu; - - } - -} - -void CElasticityMovement::Transfer_Boundary_Displacements(CGeometry *geometry, CConfig *config, unsigned short val_marker){ - - unsigned short iDim; - unsigned long iNode, iVertex; - - su2double *VarCoord; - su2double new_coord; - - for (iVertex = 0; iVertex < geometry->nVertex[val_marker]; iVertex++) { - - /*--- Get node index ---*/ - - iNode = geometry->vertex[val_marker][iVertex]->GetNode(); - - /*--- Get the displacement on the vertex ---*/ - - VarCoord = geometry->vertex[val_marker][iVertex]->GetVarCoord(); - - if (geometry->node[iNode]->GetDomain()) { - - /*--- Update the grid coordinates using the solution of the structural problem - *--- recorded in VarCoord. */ - - for (iDim = 0; iDim < nDim; iDim++) { - new_coord = geometry->node[iNode]->GetCoord(iDim)+VarCoord[iDim]; - if (fabs(new_coord) < EPS*EPS) new_coord = 0.0; - geometry->node[iNode]->SetCoord(iDim, new_coord); - } - } - - } - -} - -void CElasticityMovement::Boundary_Dependencies(CGeometry **geometry, CConfig *config){ - - - unsigned short iMarker; - - /*--- Get the SU2 module. SU2_CFD will use this routine for dynamically - deforming meshes (MARKER_FSI_INTERFACE). ---*/ - - unsigned short Kind_SU2 = config->GetKind_SU2(); - - /*--- Set the dependencies on the FSI interfaces. ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_ZoneInterface(iMarker) != 0) && (Kind_SU2 == SU2_CFD)) { - Transfer_Boundary_Displacements(geometry[MESH_0], config, iMarker); - } - } - - UpdateDualGrid(geometry[MESH_0], config); - -} - - CFreeFormBlending::CFreeFormBlending(){} CFreeFormBlending::~CFreeFormBlending(){} diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index 6ff2d2e85996..5fd3449391cd 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -2454,8 +2454,7 @@ void CDriver::DynamicMesh_Preprocessing(CConfig *config, CGeometry **geometry, C flows on dynamic meshes, including rigid mesh transformations, dynamically deforming meshes, and preprocessing of harmonic balance. ---*/ - if (!fem_solver && (config->GetGrid_Movement() || - (config->GetDirectDiff() == D_DESIGN)) && !config->GetSurface_Movement(FLUID_STRUCTURE_STATIC)) { + if (!fem_solver && (config->GetGrid_Movement() || (config->GetDirectDiff() == D_DESIGN))) { if (rank == MASTER_NODE) cout << "Setting dynamic mesh structure for zone "<< iZone + 1<<"." << endl; grid_movement = new CVolumetricMovement(geometry[MESH_0], config); @@ -2496,14 +2495,6 @@ void CDriver::DynamicMesh_Preprocessing(CConfig *config, CGeometry **geometry, C geometry[MESH_0]->ComputeWall_Distance(config); } - - if (config->GetSurface_Movement(FLUID_STRUCTURE_STATIC)){ - if (rank == MASTER_NODE) - cout << "Setting moving mesh structure for FSI problems." << endl; - /*--- Instantiate the container for the grid movement structure ---*/ - grid_movement = new CElasticityMovement(geometry[MESH_0], config); - } - } void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGeometry**** geometry, @@ -2799,7 +2790,7 @@ void CDriver::StaticMesh_Preprocessing(CConfig *config, CGeometry** geometry, CS break; } - if ((config->GetnMarker_Moving() > 0) && !config->GetSurface_Movement(FLUID_STRUCTURE_STATIC)) { + if (config->GetnMarker_Moving() > 0) { /*--- Fixed wall velocities: set the grid velocities only one time before the first iteration flow solver. ---*/ diff --git a/SU2_CFD/src/drivers/CMultizoneDriver.cpp b/SU2_CFD/src/drivers/CMultizoneDriver.cpp index 0f4ebb3727e1..fbe625899edf 100644 --- a/SU2_CFD/src/drivers/CMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CMultizoneDriver.cpp @@ -546,7 +546,7 @@ void CMultizoneDriver::DynamicMeshUpdate(unsigned long TimeIter) { void CMultizoneDriver::DynamicMeshUpdate(unsigned short val_iZone, unsigned long TimeIter) { /*--- Legacy dynamic mesh update - Only if GRID_MOVEMENT = YES ---*/ - if (config_container[ZONE_0]->GetGrid_Movement() || config_container[ZONE_0]->GetSurface_Movement(FLUID_STRUCTURE_STATIC)) { + if (config_container[ZONE_0]->GetGrid_Movement()) { iteration_container[val_iZone][INST_0]->SetGrid_Movement(geometry_container[val_iZone][INST_0],surface_movement[val_iZone], grid_movement[val_iZone][INST_0], solver_container[val_iZone][INST_0], config_container[val_iZone], 0, TimeIter); diff --git a/SU2_CFD/src/iteration_structure.cpp b/SU2_CFD/src/iteration_structure.cpp index f199dd153106..41c67a314453 100644 --- a/SU2_CFD/src/iteration_structure.cpp +++ b/SU2_CFD/src/iteration_structure.cpp @@ -55,7 +55,6 @@ void CIteration::SetGrid_Movement(CGeometry **geometry, unsigned long nIterMesh; bool stat_mesh = true; bool adjoint = config->GetContinuous_Adjoint(); - bool discrete_adjoint = config->GetDiscrete_Adjoint(); /*--- Only write to screen if this option is enabled ---*/ bool Screen_Output = config->GetDeform_Output(); @@ -67,287 +66,269 @@ void CIteration::SetGrid_Movement(CGeometry **geometry, case RIGID_MOTION: - if (rank == MASTER_NODE) { - cout << endl << " Performing rigid mesh transformation." << endl; - } + if (rank == MASTER_NODE) { + cout << endl << " Performing rigid mesh transformation." << endl; + } - /*--- Move each node in the volume mesh using the specified type - of rigid mesh motion. These routines also compute analytic grid - velocities for the fine mesh. ---*/ + /*--- Move each node in the volume mesh using the specified type + of rigid mesh motion. These routines also compute analytic grid + velocities for the fine mesh. ---*/ - grid_movement->Rigid_Translation(geometry[MESH_0], - config, val_iZone, TimeIter); - grid_movement->Rigid_Plunging(geometry[MESH_0], - config, val_iZone, TimeIter); - grid_movement->Rigid_Pitching(geometry[MESH_0], - config, val_iZone, TimeIter); - grid_movement->Rigid_Rotation(geometry[MESH_0], - config, val_iZone, TimeIter); + grid_movement->Rigid_Translation(geometry[MESH_0], + config, val_iZone, TimeIter); + grid_movement->Rigid_Plunging(geometry[MESH_0], + config, val_iZone, TimeIter); + grid_movement->Rigid_Pitching(geometry[MESH_0], + config, val_iZone, TimeIter); + grid_movement->Rigid_Rotation(geometry[MESH_0], + config, val_iZone, TimeIter); - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ - grid_movement->UpdateMultiGrid(geometry, config); + grid_movement->UpdateMultiGrid(geometry, config); - break; + break; /*--- Already initialized in the static mesh movement routine at driver level. ---*/ - case STEADY_TRANSLATION: case ROTATING_FRAME: + case STEADY_TRANSLATION: + case ROTATING_FRAME: break; } if (config->GetSurface_Movement(DEFORMING)){ - if (rank == MASTER_NODE) - cout << endl << " Updating surface positions." << endl; - - /*--- Translating ---*/ - - /*--- Compute the new node locations for moving markers ---*/ - - if (!config->GetDeform_Mesh()) { - surface_movement->Surface_Translating(geometry[MESH_0], - config, TimeIter, val_iZone); - } - else { - solver[MESH_0][MESH_SOL]->Surface_Translating(geometry[MESH_0], - config, TimeIter, val_iZone); - } - - /*--- Deform the volume grid around the new boundary locations ---*/ - /*--- Set volume deformation if new elastic mesh solver is not used ---*/ - /*--- If Deform_Mesh true, the mesh deformation is handled by SetMesh_Deformation ---*/ - // To Do: What if multiple prescribed movements? E.g., Pitching + Plunging? + if (rank == MASTER_NODE) + cout << endl << " Updating surface positions." << endl; - if (rank == MASTER_NODE && !config->GetDeform_Mesh()) { - cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry[MESH_0], - config, true); - } + /*--- Translating ---*/ - /*--- Plunging ---*/ + /*--- Compute the new node locations for moving markers ---*/ - /*--- Compute the new node locations for moving markers ---*/ + if (!config->GetDeform_Mesh()) { + surface_movement->Surface_Translating(geometry[MESH_0], + config, TimeIter, val_iZone); + } + else { + solver[MESH_0][MESH_SOL]->Surface_Translating(geometry[MESH_0], + config, TimeIter, val_iZone); + } - if (!config->GetDeform_Mesh()) { - surface_movement->Surface_Plunging(geometry[MESH_0], - config, TimeIter, val_iZone); - } - else { - solver[MESH_0][MESH_SOL]->Surface_Plunging(geometry[MESH_0], - config, TimeIter, val_iZone); - } + /*--- Deform the volume grid around the new boundary locations ---*/ + /*--- Set volume deformation if new elastic mesh solver is not used ---*/ + /*--- If Deform_Mesh true, the mesh deformation is handled by SetMesh_Deformation ---*/ + // To Do: What if multiple prescribed movements? E.g., Pitching + Plunging? - /*--- Deform the volume grid around the new boundary locations ---*/ - /*--- Set volume deformation if new elastic mesh solver is not used ---*/ - /*--- If Deform_Mesh true, the mesh deformation is handled by SetMesh_Deformation ---*/ - // To Do: What if multiple prescribed movements? E.g., Pitching + Plunging? + if (rank == MASTER_NODE && !config->GetDeform_Mesh()) { + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry[MESH_0], + config, true); + } - if (rank == MASTER_NODE && !config->GetDeform_Mesh()) { - cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry[MESH_0], - config, true); - } + /*--- Plunging ---*/ - /*--- Pitching ---*/ + /*--- Compute the new node locations for moving markers ---*/ - /*--- Compute the new node locations for moving markers ---*/ + if (!config->GetDeform_Mesh()) { + surface_movement->Surface_Plunging(geometry[MESH_0], + config, TimeIter, val_iZone); + } + else { + solver[MESH_0][MESH_SOL]->Surface_Plunging(geometry[MESH_0], + config, TimeIter, val_iZone); + } - if (!config->GetDeform_Mesh()) { - surface_movement->Surface_Pitching(geometry[MESH_0], - config, TimeIter, val_iZone); - } - else { - solver[MESH_0][MESH_SOL]->Surface_Pitching(geometry[MESH_0], - config, TimeIter, val_iZone); - } + /*--- Deform the volume grid around the new boundary locations ---*/ + /*--- Set volume deformation if new elastic mesh solver is not used ---*/ + /*--- If Deform_Mesh true, the mesh deformation is handled by SetMesh_Deformation ---*/ + // To Do: What if multiple prescribed movements? E.g., Pitching + Plunging? - /*--- Deform the volume grid around the new boundary locations ---*/ - /*--- Set volume deformation if new elastic mesh solver is not used ---*/ - /*--- If Deform_Mesh true, the mesh deformation is handled by SetMesh_Deformation ---*/ - // To Do: What if multiple prescribed movements? E.g., Pitching + Plunging? + if (rank == MASTER_NODE && !config->GetDeform_Mesh()) { + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry[MESH_0], + config, true); + } - if (rank == MASTER_NODE && !config->GetDeform_Mesh()) { - cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry[MESH_0], - config, true); - } + /*--- Pitching ---*/ - /*--- Rotating ---*/ + /*--- Compute the new node locations for moving markers ---*/ - /*--- Compute the new node locations for moving markers ---*/ + if (!config->GetDeform_Mesh()) { + surface_movement->Surface_Pitching(geometry[MESH_0], + config, TimeIter, val_iZone); + } + else { + solver[MESH_0][MESH_SOL]->Surface_Pitching(geometry[MESH_0], + config, TimeIter, val_iZone); + } - if (!config->GetDeform_Mesh()) { - surface_movement->Surface_Rotating(geometry[MESH_0], - config, TimeIter, val_iZone); - } - else { - solver[MESH_0][MESH_SOL]->Surface_Rotating(geometry[MESH_0], - config, TimeIter, val_iZone); - } + /*--- Deform the volume grid around the new boundary locations ---*/ + /*--- Set volume deformation if new elastic mesh solver is not used ---*/ + /*--- If Deform_Mesh true, the mesh deformation is handled by SetMesh_Deformation ---*/ + // To Do: What if multiple prescribed movements? E.g., Pitching + Plunging? - /*--- Deform the volume grid around the new boundary locations ---*/ - /*--- Set volume deformation if new elastic mesh solver is not used ---*/ - /*--- If Deform_Mesh true, the mesh deformation is handled by SetMesh_Deformation ---*/ - // To Do: What if multiple prescribed movements? E.g., Pitching + Plunging? - if (rank == MASTER_NODE && !config->GetDeform_Mesh()) { - cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry[MESH_0], - config, true); - } + if (rank == MASTER_NODE && !config->GetDeform_Mesh()) { + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry[MESH_0], + config, true); + } - /*--- Update the grid velocities on the fine mesh using finite - differencing based on node coordinates at previous times. ---*/ + /*--- Rotating ---*/ - if (!adjoint) { - if (rank == MASTER_NODE) - cout << " Computing grid velocities by finite differencing." << endl; - geometry[MESH_0]->SetGridVelocity(config, TimeIter); - } + /*--- Compute the new node locations for moving markers ---*/ - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ + if (!config->GetDeform_Mesh()) { + surface_movement->Surface_Rotating(geometry[MESH_0], + config, TimeIter, val_iZone); + } + else { + solver[MESH_0][MESH_SOL]->Surface_Rotating(geometry[MESH_0], + config, TimeIter, val_iZone); + } - grid_movement->UpdateMultiGrid(geometry, config); + /*--- Deform the volume grid around the new boundary locations ---*/ + /*--- Set volume deformation if new elastic mesh solver is not used ---*/ + /*--- If Deform_Mesh true, the mesh deformation is handled by SetMesh_Deformation ---*/ + // To Do: What if multiple prescribed movements? E.g., Pitching + Plunging? + if (rank == MASTER_NODE && !config->GetDeform_Mesh()) { + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry[MESH_0], + config, true); + } - } + /*--- Update the grid velocities on the fine mesh using finite + differencing based on node coordinates at previous times. ---*/ - if (config->GetSurface_Movement(AEROELASTIC) - || config->GetSurface_Movement(AEROELASTIC_RIGID_MOTION)){ + if (!adjoint) { + if (rank == MASTER_NODE) + cout << " Computing grid velocities by finite differencing." << endl; + geometry[MESH_0]->SetGridVelocity(config, TimeIter); + } - /*--- Apply rigid mesh transformation to entire grid first, if necessary ---*/ - if (IntIter == 0) { - if (Kind_Grid_Movement == AEROELASTIC_RIGID_MOTION) { + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ - if (rank == MASTER_NODE) { - cout << endl << " Performing rigid mesh transformation." << endl; - } + grid_movement->UpdateMultiGrid(geometry, config); - /*--- Move each node in the volume mesh using the specified type - of rigid mesh motion. These routines also compute analytic grid - velocities for the fine mesh. ---*/ + } - grid_movement->Rigid_Translation(geometry[MESH_0], - config, val_iZone, TimeIter); - grid_movement->Rigid_Plunging(geometry[MESH_0], - config, val_iZone, TimeIter); - grid_movement->Rigid_Pitching(geometry[MESH_0], - config, val_iZone, TimeIter); - grid_movement->Rigid_Rotation(geometry[MESH_0], - config, val_iZone, TimeIter); + if (config->GetSurface_Movement(AEROELASTIC) || + config->GetSurface_Movement(AEROELASTIC_RIGID_MOTION)) { - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ + /*--- Apply rigid mesh transformation to entire grid first, if necessary ---*/ + if (IntIter == 0) { + if (Kind_Grid_Movement == AEROELASTIC_RIGID_MOTION) { - grid_movement->UpdateMultiGrid(geometry, config); + if (rank == MASTER_NODE) { + cout << endl << " Performing rigid mesh transformation." << endl; } - } - - /*--- Use the if statement to move the grid only at selected dual time step iterations. ---*/ - else if (IntIter % config->GetAeroelasticIter() == 0) { - - if (rank == MASTER_NODE) - cout << endl << " Solving aeroelastic equations and updating surface positions." << endl; + /*--- Move each node in the volume mesh using the specified type + of rigid mesh motion. These routines also compute analytic grid + velocities for the fine mesh. ---*/ - /*--- Solve the aeroelastic equations for the new node locations of the moving markers(surfaces) ---*/ + grid_movement->Rigid_Translation(geometry[MESH_0], + config, val_iZone, TimeIter); + grid_movement->Rigid_Plunging(geometry[MESH_0], + config, val_iZone, TimeIter); + grid_movement->Rigid_Pitching(geometry[MESH_0], + config, val_iZone, TimeIter); + grid_movement->Rigid_Rotation(geometry[MESH_0], + config, val_iZone, TimeIter); - solver[MESH_0][FLOW_SOL]->Aeroelastic(surface_movement, geometry[MESH_0], config, TimeIter); + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ - /*--- Deform the volume grid around the new boundary locations ---*/ + grid_movement->UpdateMultiGrid(geometry, config); + } - if (rank == MASTER_NODE) - cout << " Deforming the volume grid due to the aeroelastic movement." << endl; - grid_movement->SetVolume_Deformation(geometry[MESH_0], - config, true); + } - /*--- Update the grid velocities on the fine mesh using finite - differencing based on node coordinates at previous times. ---*/ + /*--- Use the if statement to move the grid only at selected dual time step iterations. ---*/ + else if (IntIter % config->GetAeroelasticIter() == 0) { - if (rank == MASTER_NODE) - cout << " Computing grid velocities by finite differencing." << endl; - geometry[MESH_0]->SetGridVelocity(config, TimeIter); + if (rank == MASTER_NODE) + cout << endl << " Solving aeroelastic equations and updating surface positions." << endl; - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ + /*--- Solve the aeroelastic equations for the new node locations of the moving markers(surfaces) ---*/ - grid_movement->UpdateMultiGrid(geometry, config); - } - } - if (config->GetSurface_Movement(FLUID_STRUCTURE)){ - if (rank == MASTER_NODE && Screen_Output) - cout << endl << "Deforming the grid for Fluid-Structure Interaction applications." << endl; + solver[MESH_0][FLOW_SOL]->Aeroelastic(surface_movement, geometry[MESH_0], config, TimeIter); /*--- Deform the volume grid around the new boundary locations ---*/ - if (rank == MASTER_NODE && Screen_Output) - cout << "Deforming the volume grid." << endl; + if (rank == MASTER_NODE) + cout << " Deforming the volume grid due to the aeroelastic movement." << endl; grid_movement->SetVolume_Deformation(geometry[MESH_0], - config, true, false); + config, true); - nIterMesh = grid_movement->Get_nIterMesh(); - stat_mesh = (nIterMesh == 0); + /*--- Update the grid velocities on the fine mesh using finite + differencing based on node coordinates at previous times. ---*/ - if (!adjoint && !stat_mesh) { - if (rank == MASTER_NODE && Screen_Output) - cout << "Computing grid velocities by finite differencing." << endl; - geometry[MESH_0]->SetGridVelocity(config, TimeIter); - } - else if (stat_mesh) { - if (rank == MASTER_NODE && Screen_Output) - cout << "The mesh is up-to-date. Using previously stored grid velocities." << endl; - } + if (rank == MASTER_NODE) + cout << " Computing grid velocities by finite differencing." << endl; + geometry[MESH_0]->SetGridVelocity(config, TimeIter); /*--- Update the multigrid structure after moving the finest grid, including computing the grid velocities on the coarser levels. ---*/ grid_movement->UpdateMultiGrid(geometry, config); + } } - if (config->GetSurface_Movement(FLUID_STRUCTURE_STATIC)){ - if ((rank == MASTER_NODE) && (!discrete_adjoint) && Screen_Output) - cout << endl << "Deforming the grid for static Fluid-Structure Interaction applications." << endl; + if (config->GetSurface_Movement(FLUID_STRUCTURE)) { + if (rank == MASTER_NODE && Screen_Output) + cout << endl << "Deforming the grid for Fluid-Structure Interaction applications." << endl; - /*--- Deform the volume grid around the new boundary locations ---*/ + /*--- Deform the volume grid around the new boundary locations ---*/ - if ((rank == MASTER_NODE) && (!discrete_adjoint)&& Screen_Output) - cout << "Deforming the volume grid." << endl; + if (rank == MASTER_NODE && Screen_Output) + cout << "Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry[MESH_0], + config, true, false); - grid_movement->SetVolume_Deformation_Elas(geometry[MESH_0], config, true, false); + nIterMesh = grid_movement->Get_nIterMesh(); + stat_mesh = (nIterMesh == 0); - if ((rank == MASTER_NODE) && (!discrete_adjoint)&& Screen_Output) - cout << "There is no grid velocity." << endl; + if (!adjoint && !stat_mesh) { + if (rank == MASTER_NODE && Screen_Output) + cout << "Computing grid velocities by finite differencing." << endl; + geometry[MESH_0]->SetGridVelocity(config, TimeIter); + } + else if (stat_mesh) { + if (rank == MASTER_NODE && Screen_Output) + cout << "The mesh is up-to-date. Using previously stored grid velocities." << endl; + } - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ - grid_movement->UpdateMultiGrid(geometry, config); + grid_movement->UpdateMultiGrid(geometry, config); } - if (config->GetSurface_Movement(EXTERNAL) || config->GetSurface_Movement(EXTERNAL_ROTATION)){ + + if (config->GetSurface_Movement(EXTERNAL) || + config->GetSurface_Movement(EXTERNAL_ROTATION)) { + /*--- Apply rigid rotation to entire grid first, if necessary ---*/ if (Kind_Grid_Movement == EXTERNAL_ROTATION) { if (rank == MASTER_NODE) cout << " Updating node locations by rigid rotation." << endl; - grid_movement->Rigid_Rotation(geometry[MESH_0], - config, val_iZone, TimeIter); + grid_movement->Rigid_Rotation(geometry[MESH_0], config, val_iZone, TimeIter); } /*--- Load new surface node locations from external files ---*/ - if (rank == MASTER_NODE) + if (rank == MASTER_NODE) cout << " Updating surface locations from file." << endl; - surface_movement->SetExternal_Deformation(geometry[MESH_0], - config, val_iZone, TimeIter); + surface_movement->SetExternal_Deformation(geometry[MESH_0], config, val_iZone, TimeIter); /*--- Deform the volume grid around the new boundary locations ---*/ if (rank == MASTER_NODE) cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry[MESH_0], - config, true); + grid_movement->SetVolume_Deformation(geometry[MESH_0], config, true); /*--- Update the grid velocities on the fine mesh using finite differencing based on node coordinates at previous times. ---*/ @@ -356,7 +337,7 @@ void CIteration::SetGrid_Movement(CGeometry **geometry, if (rank == MASTER_NODE) cout << " Computing grid velocities by finite differencing." << endl; geometry[MESH_0]->SetGridVelocity(config, TimeIter); - } + } /*--- Update the multigrid structure after moving the finest grid, including computing the grid velocities on the coarser levels. ---*/ @@ -364,6 +345,7 @@ void CIteration::SetGrid_Movement(CGeometry **geometry, grid_movement->UpdateMultiGrid(geometry, config); } + } void CIteration::SetMesh_Deformation(CGeometry **geometry, From a981935c97adba18f74e394a2b1704a451854c4a Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 26 Mar 2020 11:10:39 +0000 Subject: [PATCH 37/79] remove CVariable and CSolver cross-term handling methods --- SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp | 16 --- SU2_CFD/include/solvers/CDiscAdjSolver.hpp | 24 ----- SU2_CFD/include/solvers/CSolver.hpp | 24 ----- .../include/variables/CDiscAdjFEAVariable.hpp | 32 ------ .../include/variables/CDiscAdjVariable.hpp | 52 ---------- SU2_CFD/include/variables/CVariable.hpp | 37 ------- .../src/output/output_structure_legacy.cpp | 58 ----------- SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp | 71 ++----------- SU2_CFD/src/solvers/CDiscAdjSolver.cpp | 99 ++----------------- SU2_CFD/src/variables/CDiscAdjFEAVariable.cpp | 3 - SU2_CFD/src/variables/CDiscAdjVariable.cpp | 3 - 11 files changed, 13 insertions(+), 406 deletions(-) diff --git a/SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp b/SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp index 6a3fea5051ca..738962d2cc20 100644 --- a/SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp +++ b/SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp @@ -161,22 +161,6 @@ class CDiscAdjFEASolver final : public CSolver { */ void ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config) override; - /*! - * \brief Sets the adjoint values of the structural variables due to cross term contributions - * \param[in] geometry - The geometrical definition of the problem. - * \param[in] solver_container - The solver container holding all solutions. - * \param[in] config - The particular config. - */ - void ExtractAdjoint_CrossTerm(CGeometry *geometry, CConfig *config) override; - - /*! - * \brief A virtual member. - * \param[in] geometry - The geometrical definition of the problem. - * \param[in] solver_container - The solver container holding all solutions. - * \param[in] config - The particular config. - */ - void ExtractAdjoint_CrossTerm_Geometry(CGeometry *geometry, CConfig *config) override; - /*! * \brief Register the objective function as output. * \param[in] geometry - The geometrical definition of the problem. diff --git a/SU2_CFD/include/solvers/CDiscAdjSolver.hpp b/SU2_CFD/include/solvers/CDiscAdjSolver.hpp index 1b85e46e5238..1e7b7e6eb020 100644 --- a/SU2_CFD/include/solvers/CDiscAdjSolver.hpp +++ b/SU2_CFD/include/solvers/CDiscAdjSolver.hpp @@ -140,30 +140,6 @@ class CDiscAdjSolver final : public CSolver { */ void ExtractAdjoint_Geometry(CGeometry *geometry, CConfig *config) override; - /*! - * \brief Sets the adjoint values of the flow variables due to cross term contributions - * \param[in] geometry - The geometrical definition of the problem. - * \param[in] solver_container - The solver container holding all solutions. - * \param[in] config - The particular config. - */ - void ExtractAdjoint_CrossTerm(CGeometry *geometry, CConfig *config) override; - - /*! - * \brief A virtual member. - * \param[in] geometry - The geometrical definition of the problem. - * \param[in] solver_container - The solver container holding all solutions. - * \param[in] config - The particular config. - */ - void ExtractAdjoint_CrossTerm_Geometry(CGeometry *geometry, CConfig *config) override; - - /*! - * \brief A virtual member. - * \param[in] geometry - The geometrical definition of the problem. - * \param[in] solver_container - The solver container holding all solutions. - * \param[in] config - The particular config. - */ - void ExtractAdjoint_CrossTerm_Geometry_Flow(CGeometry *geometry, CConfig *config) override; - /*! * \brief Register the objective function as output. * \param[in] geometry - The geometrical definition of the problem. diff --git a/SU2_CFD/include/solvers/CSolver.hpp b/SU2_CFD/include/solvers/CSolver.hpp index b80e3526e885..80faaa3b6b6a 100644 --- a/SU2_CFD/include/solvers/CSolver.hpp +++ b/SU2_CFD/include/solvers/CSolver.hpp @@ -3907,30 +3907,6 @@ class CSolver { */ inline virtual void ExtractAdjoint_Geometry(CGeometry *geometry, CConfig *config) {} - /*! - * \brief A virtual member. - * \param[in] geometry - The geometrical definition of the problem. - * \param[in] solver_container - The solver container holding all solutions. - * \param[in] config - The particular config. - */ - inline virtual void ExtractAdjoint_CrossTerm(CGeometry *geometry, CConfig *config) {} - - /*! - * \brief A virtual member. - * \param[in] geometry - The geometrical definition of the problem. - * \param[in] solver_container - The solver container holding all solutions. - * \param[in] config - The particular config. - */ - inline virtual void ExtractAdjoint_CrossTerm_Geometry(CGeometry *geometry, CConfig *config) {} - - /*! - * \brief A virtual member. - * \param[in] geometry - The geometrical definition of the problem. - * \param[in] solver_container - The solver container holding all solutions. - * \param[in] config - The particular config. - */ - inline virtual void ExtractAdjoint_CrossTerm_Geometry_Flow(CGeometry *geometry, CConfig *config) {} - /*! * \brief A virtual member * \param[in] geometry - The geometrical definition of the problem. diff --git a/SU2_CFD/include/variables/CDiscAdjFEAVariable.hpp b/SU2_CFD/include/variables/CDiscAdjFEAVariable.hpp index eca9925602e8..e529782c3ac6 100644 --- a/SU2_CFD/include/variables/CDiscAdjFEAVariable.hpp +++ b/SU2_CFD/include/variables/CDiscAdjFEAVariable.hpp @@ -60,9 +60,6 @@ class CDiscAdjFEAVariable : public CVariable { MatrixType Solution_Direct_Vel; MatrixType Solution_Direct_Accel; - MatrixType Cross_Term_Derivative; - MatrixType Geometry_CrossTerm_Derivative; - MatrixType Solution_BGS; /*! @@ -240,35 +237,6 @@ class CDiscAdjFEAVariable : public CVariable { */ void Set_OldSolution_Vel() final; - /*! - * \brief Set the contribution of crossed terms into the derivative. - */ - inline void SetCross_Term_Derivative(unsigned long iPoint, unsigned long iVar, su2double der) final { - Cross_Term_Derivative(iPoint,iVar) = der; - } - - /*! - * \brief Get the contribution of crossed terms into the derivative. - */ - inline su2double GetCross_Term_Derivative(unsigned long iPoint, unsigned long iVar) const final { return Cross_Term_Derivative(iPoint,iVar); } - - /*! - * \brief A virtual member. Get the geometry solution. - * \param[in] iVar - Index of the variable. - * \return Value of the solution for the index iVar. - */ - inline su2double GetGeometry_CrossTerm_Derivative(unsigned long iPoint, unsigned long iVar) const final { - return Geometry_CrossTerm_Derivative(iPoint,iVar); - } - - /*! - * \brief A virtual member. Set the value of the mesh solution (adjoint). - * \param[in] der - cross term derivative. - */ - inline void SetGeometry_CrossTerm_Derivative(unsigned long iPoint, unsigned long iVar, su2double der) final { - Geometry_CrossTerm_Derivative(iPoint,iVar) = der; - } - /*! * \brief Set the value of the adjoint solution in the current BGS subiteration. */ diff --git a/SU2_CFD/include/variables/CDiscAdjVariable.hpp b/SU2_CFD/include/variables/CDiscAdjVariable.hpp index a896b9672d7e..edfd89d776b7 100644 --- a/SU2_CFD/include/variables/CDiscAdjVariable.hpp +++ b/SU2_CFD/include/variables/CDiscAdjVariable.hpp @@ -42,10 +42,6 @@ class CDiscAdjVariable final : public CVariable { MatrixType DualTime_Derivative; MatrixType DualTime_Derivative_n; - MatrixType Cross_Term_Derivative; - MatrixType Geometry_CrossTerm_Derivative; - MatrixType Geometry_CrossTerm_Derivative_Flow; - MatrixType Solution_Geometry; MatrixType Solution_Geometry_Old; MatrixType Geometry_Direct; @@ -143,40 +139,6 @@ class CDiscAdjVariable final : public CVariable { Solution_Geometry(iPoint,iVar) = val_solution_geometry; } - /*! - * \brief A virtual member. Get the geometry solution. - * \param[in] iVar - Index of the variable. - * \return Value of the solution for the index iVar. - */ - inline su2double GetGeometry_CrossTerm_Derivative(unsigned long iPoint, unsigned long iVar) const override { - return Geometry_CrossTerm_Derivative(iPoint,iVar); - } - - /*! - * \brief A virtual member. Set the value of the mesh solution (adjoint). - * \param[in] der - cross term derivative. - */ - inline void SetGeometry_CrossTerm_Derivative(unsigned long iPoint, unsigned long iDim, su2double der) override { - Geometry_CrossTerm_Derivative(iPoint,iDim) = der; - } - - /*! - * \brief Get the mesh cross term derivative from the flow solution. - * \param[in] iVar - Index of the variable. - * \return Value of the solution for the index iVar. - */ - inline su2double GetGeometry_CrossTerm_Derivative_Flow(unsigned long iPoint, unsigned long iVar) const override { - return Geometry_CrossTerm_Derivative_Flow(iPoint,iVar); - } - - /*! - * \brief Set the value of the mesh cross term derivative from the flow solution (adjoint). - * \param[in] der - cross term derivative. - */ - inline void SetGeometry_CrossTerm_Derivative_Flow(unsigned long iPoint, unsigned long iDim, su2double der) override { - Geometry_CrossTerm_Derivative_Flow(iPoint,iDim) = der; - } - /*! * \brief Set the value of the mesh solution (adjoint). */ @@ -203,18 +165,4 @@ class CDiscAdjVariable final : public CVariable { */ inline su2double Get_BGSSolution(unsigned long iPoint, unsigned long iDim) const override { return Solution_BGS(iPoint,iDim);} - /*! - * \brief Set the contribution of crossed terms into the derivative. - */ - inline void SetCross_Term_Derivative(unsigned long iPoint, unsigned long iVar, su2double der) override { - Cross_Term_Derivative(iPoint,iVar) = der; - } - - /*! - * \brief Get the contribution of crossed terms into the derivative. - */ - inline su2double GetCross_Term_Derivative(unsigned long iPoint, unsigned long iVar) const override { - return Cross_Term_Derivative(iPoint,iVar); - } - }; diff --git a/SU2_CFD/include/variables/CVariable.hpp b/SU2_CFD/include/variables/CVariable.hpp index 5e28e972abc8..ffb2d6c59ab2 100644 --- a/SU2_CFD/include/variables/CVariable.hpp +++ b/SU2_CFD/include/variables/CVariable.hpp @@ -2098,32 +2098,6 @@ class CVariable { */ inline virtual void SetSolution_Geometry(unsigned long iPoint, unsigned long iVar, su2double solution_geometry) {} - /*! - * \brief A virtual member. Get the geometry solution. - * \param[in] iVar - Index of the variable. - * \return Value of the solution for the index iVar. - */ - inline virtual su2double GetGeometry_CrossTerm_Derivative(unsigned long iPoint, unsigned long iVar) const { return 0.0; } - - /*! - * \brief A virtual member. Set the value of the mesh solution (adjoint). - * \param[in] solution - Solution of the problem (acceleration). - */ - inline virtual void SetGeometry_CrossTerm_Derivative(unsigned long iPoint, unsigned long iDim, su2double der) {} - - /*! - * \brief A virtual member. Get the geometry solution. - * \param[in] iVar - Index of the variable. - * \return Value of the solution for the index iVar. - */ - inline virtual su2double GetGeometry_CrossTerm_Derivative_Flow(unsigned long iPoint, unsigned long iVar) const { return 0.0;} - - /*! - * \brief A virtual member. Set the value of the mesh solution (adjoint). - * \param[in] solution - Solution of the problem (acceleration). - */ - inline virtual void SetGeometry_CrossTerm_Derivative_Flow(unsigned long iPoint, unsigned long iDim, su2double der) {} - /*! * \brief A virtual member. Set the value of the old geometry solution (adjoint). */ @@ -2171,17 +2145,6 @@ class CVariable { */ inline virtual su2double Get_BGSSolution(unsigned long iPoint, unsigned long iDim) const {return 0.0;} - /*! - * \brief A virtual member. Set the contribution of crossed terms into the derivative. - */ - inline virtual void SetCross_Term_Derivative(unsigned long iPoint, unsigned long iVar, su2double der) {} - - /*! - * \brief A virtual member. Get the contribution of crossed terms into the derivative. - * \return The contribution of crossed terms into the derivative. - */ - inline virtual su2double GetCross_Term_Derivative(unsigned long iPoint, unsigned long iVar) const { return 0.0; } - /*! * \brief A virtual member. Set the direct velocity solution for the adjoint solver. * \param[in] solution_direct - Value of the direct velocity solution. diff --git a/SU2_CFD/src/output/output_structure_legacy.cpp b/SU2_CFD/src/output/output_structure_legacy.cpp index b2fd26df2a71..ff0971c436f6 100644 --- a/SU2_CFD/src/output/output_structure_legacy.cpp +++ b/SU2_CFD/src/output/output_structure_legacy.cpp @@ -3661,64 +3661,6 @@ void COutputLegacy::MergeSolution(CConfig *config, CGeometry *geometry, CSolver } } - if ((Kind_Solver == DISC_ADJ_FEM) && (config->GetFSI_Simulation())) { - /*--- Loop over this partition to collect the current variable ---*/ - - jPoint = 0; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - - /*--- Check for halos & write only if requested ---*/ - - if (!Local_Halo[iPoint] || Wrt_Halo) { - - /*--- Load buffers with the skin friction, heat transfer, y+ variables. ---*/ - - Buffer_Send_Var[jPoint] = solver[ADJFEA_SOL]->GetNodes()->GetGeometry_CrossTerm_Derivative(iPoint, 0); - Buffer_Send_Res[jPoint] = solver[ADJFEA_SOL]->GetNodes()->GetGeometry_CrossTerm_Derivative(iPoint, 1); - if (geometry->GetnDim() == 3) - Buffer_Send_Vol[jPoint] = solver[ADJFEA_SOL]->GetNodes()->GetGeometry_CrossTerm_Derivative(iPoint, 2); - jPoint++; - } - } - - /*--- Gather the data on the master node. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Gather(Buffer_Send_Var, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Var, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Gather(Buffer_Send_Res, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Res, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); - if (nDim == 3) - SU2_MPI::Gather(Buffer_Send_Vol, nBuffer_Scalar, MPI_DOUBLE, Buffer_Recv_Vol, nBuffer_Scalar, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#else - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Var[iPoint] = Buffer_Send_Var[iPoint]; - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Res[iPoint] = Buffer_Send_Res[iPoint]; - if (nDim == 3) - for (iPoint = 0; iPoint < nBuffer_Scalar; iPoint++) Buffer_Recv_Vol[iPoint] = Buffer_Send_Vol[iPoint]; -#endif - - /*--- The master node unpacks and sorts this variable by global index ---*/ - - if (rank == MASTER_NODE) { - jPoint = 0; iVar = iVar_FEA_Extra; - for (iProcessor = 0; iProcessor < size; iProcessor++) { - for (iPoint = 0; iPoint < Buffer_Recv_nPoint[iProcessor]; iPoint++) { - - /*--- Get global index, then loop over each variable and store ---*/ - - iGlobal_Index = Buffer_Recv_GlobalIndex[jPoint]; - Data[iVar+0][iGlobal_Index] = Buffer_Recv_Var[jPoint]; - Data[iVar+1][iGlobal_Index] = Buffer_Recv_Res[jPoint]; - if (nDim == 3) - Data[iVar+2][iGlobal_Index] = Buffer_Recv_Vol[jPoint]; - jPoint++; - } - - /*--- Adjust jPoint to index of next proc's data in the buffers. ---*/ - - jPoint = (iProcessor+1)*nBuffer_Scalar; - } - } - } - if (config->GetExtraOutput()) { for (jVar = 0; jVar < nVar_Extra; jVar++) { diff --git a/SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp b/SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp index 51428d421b20..6e0ef3f48a3d 100644 --- a/SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp +++ b/SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp @@ -741,7 +741,6 @@ void CDiscAdjFEASolver::ExtractAdjoint_Variables(CGeometry *geometry, CConfig *c void CDiscAdjFEASolver::SetAdjoint_Output(CGeometry *geometry, CConfig *config){ bool dynamic = (config->GetTime_Domain()); - bool fsi = config->GetFSI_Simulation(); bool deform_mesh = (config->GetnMarker_Deform_Mesh() > 0); unsigned short iVar; @@ -751,21 +750,11 @@ void CDiscAdjFEASolver::SetAdjoint_Output(CGeometry *geometry, CConfig *config){ for (iVar = 0; iVar < nVar; iVar++){ Solution[iVar] = nodes->GetSolution(iPoint,iVar); } - if (fsi) { - for (iVar = 0; iVar < nVar; iVar++){ - Solution[iVar] += nodes->GetGeometry_CrossTerm_Derivative(iPoint,iVar); - } - for (iVar = 0; iVar < nVar; iVar++){ - Solution[iVar] += nodes->GetCross_Term_Derivative(iPoint,iVar); - } - } - if(deform_mesh){ for (iVar = 0; iVar < nVar; iVar++){ Solution[iVar] += nodes->GetSourceTerm_DispAdjoint(iPoint,iVar); } } - if (dynamic){ for (iVar = 0; iVar < nVar; iVar++){ Solution_Accel[iVar] = nodes->GetSolution_Accel(iPoint,iVar); @@ -815,47 +804,6 @@ void CDiscAdjFEASolver::Preprocessing(CGeometry *geometry, CSolver **solver_cont } -void CDiscAdjFEASolver::ExtractAdjoint_CrossTerm(CGeometry *geometry, CConfig *config){ - - unsigned short iVar; - unsigned long iPoint; - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - - /*--- Extract the adjoint solution ---*/ - - direct_solver->GetNodes()->GetAdjointSolution_LocalIndex(iPoint,Solution); - - for (iVar = 0; iVar < nVar; iVar++) nodes->SetCross_Term_Derivative(iPoint,iVar, Solution[iVar]); - - } - -} - -void CDiscAdjFEASolver::ExtractAdjoint_CrossTerm_Geometry(CGeometry *geometry, CConfig *config){ - - unsigned short iVar; - unsigned long iPoint; - - su2double relax = config->GetAitkenStatRelax(); - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - - /*--- Extract the adjoint solution ---*/ - - direct_solver->GetNodes()->GetAdjointSolution_LocalIndex(iPoint,Solution); - - /*--- Relax and set the solution ---*/ - - for(iVar = 0; iVar < nVar; iVar++) - Solution[iVar] = relax*Solution[iVar] + (1.0-relax)*nodes->GetGeometry_CrossTerm_Derivative(iPoint,iVar); - - for (iVar = 0; iVar < nVar; iVar++) nodes->SetGeometry_CrossTerm_Derivative(iPoint,iVar, Solution[iVar]); - - } - -} - void CDiscAdjFEASolver::SetSensitivity(CGeometry *geometry, CSolver **solver, CConfig *config){ unsigned short iVar; @@ -914,26 +862,21 @@ void CDiscAdjFEASolver::ComputeResidual_Multizone(CGeometry *geometry, CConfig * unsigned short iVar; unsigned long iPoint; - su2double residual, bgs_sol; + su2double residual; /*--- Set Residuals to zero ---*/ - for (iVar = 0; iVar < nVar; iVar++){ SetRes_BGS(iVar,0.0); SetRes_Max_BGS(iVar,0.0,0); } - /*--- Compute the BGS solution (adding the cross term) ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++){ - for (iVar = 0; iVar < nVar; iVar++){ - bgs_sol = nodes->GetSolution(iPoint, iVar) + nodes->GetGeometry_CrossTerm_Derivative(iPoint, iVar); - nodes->Set_BGSSolution(iPoint,iVar, bgs_sol); - } - } - /*--- Set the residuals ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++){ - for (iVar = 0; iVar < nVar; iVar++){ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + + /// TODO: This is only difference to the CSolver version, this method and the BGS var might be reduntant. + nodes->Set_BGSSolution(iPoint, iVar, nodes->GetSolution(iPoint, iVar)); + residual = nodes->Get_BGSSolution(iPoint, iVar) - nodes->Get_BGSSolution_k(iPoint, iVar); AddRes_BGS(iVar,residual*residual); AddRes_Max_BGS(iVar,fabs(residual),geometry->node[iPoint]->GetGlobalIndex(),geometry->node[iPoint]->GetCoord()); diff --git a/SU2_CFD/src/solvers/CDiscAdjSolver.cpp b/SU2_CFD/src/solvers/CDiscAdjSolver.cpp index 332e0420f822..4e28ede0f15f 100644 --- a/SU2_CFD/src/solvers/CDiscAdjSolver.cpp +++ b/SU2_CFD/src/solvers/CDiscAdjSolver.cpp @@ -690,71 +690,10 @@ void CDiscAdjSolver::ExtractAdjoint_Geometry(CGeometry *geometry, CConfig *confi // SetResidual_RMS(geometry, config); } -void CDiscAdjSolver::ExtractAdjoint_CrossTerm(CGeometry *geometry, CConfig *config) { - - unsigned short iVar; - unsigned long iPoint; - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - - /*--- Extract the adjoint solution ---*/ - - direct_solver->GetNodes()->GetAdjointSolution_LocalIndex(iPoint,Solution); - - for (iVar = 0; iVar < nVar; iVar++) nodes->SetCross_Term_Derivative(iPoint,iVar, Solution[iVar]); - - } - -} - -void CDiscAdjSolver::ExtractAdjoint_CrossTerm_Geometry(CGeometry *geometry, CConfig *config) { - - unsigned short iDim; - unsigned long iPoint; - - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - - /*--- Extract the adjoint solution ---*/ - - if (config->GetMultizone_Problem()) - geometry->node[iPoint]->GetAdjointCoord_LocalIndex(Solution_Geometry); - else - geometry->node[iPoint]->GetAdjointCoord(Solution_Geometry); - - for (iDim = 0; iDim < nDim; iDim++) nodes->SetGeometry_CrossTerm_Derivative(iPoint,iDim, Solution_Geometry[iDim]); - - } - -} - -void CDiscAdjSolver::ExtractAdjoint_CrossTerm_Geometry_Flow(CGeometry *geometry, CConfig *config){ - - unsigned short iDim; - unsigned long iPoint; - - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - - /*--- Extract the adjoint solution ---*/ - - if (config->GetMultizone_Problem()) - geometry->node[iPoint]->GetAdjointCoord_LocalIndex(Solution_Geometry); - else - geometry->node[iPoint]->GetAdjointCoord(Solution_Geometry); - - for (iDim = 0; iDim < nDim; iDim++) nodes->SetGeometry_CrossTerm_Derivative_Flow(iPoint,iDim, Solution_Geometry[iDim]); - - } - -} - - void CDiscAdjSolver::SetAdjoint_Output(CGeometry *geometry, CConfig *config) { bool dual_time = (config->GetTime_Marching() == DT_STEPPING_1ST || config->GetTime_Marching() == DT_STEPPING_2ND); - bool fsi = config->GetFSI_Simulation(); unsigned short iVar; unsigned long iPoint; @@ -763,11 +702,6 @@ void CDiscAdjSolver::SetAdjoint_Output(CGeometry *geometry, CConfig *config) { for (iVar = 0; iVar < nVar; iVar++) { Solution[iVar] = nodes->GetSolution(iPoint,iVar); } - if (fsi) { - for (iVar = 0; iVar < nVar; iVar++) { - Solution[iVar] += nodes->GetCross_Term_Derivative(iPoint,iVar); - } - } if (dual_time) { for (iVar = 0; iVar < nVar; iVar++) { Solution[iVar] += nodes->GetDual_Time_Derivative(iPoint,iVar); @@ -787,8 +721,6 @@ void CDiscAdjSolver::SetAdjoint_OutputMesh(CGeometry *geometry, CConfig *config) // bool dual_time = (config->GetUnsteady_Simulation() == DT_STEPPING_1ST || // config->GetUnsteady_Simulation() == DT_STEPPING_2ND); - bool fsi = config->GetFSI_Simulation(); - unsigned short iDim; unsigned long iPoint; @@ -796,14 +728,6 @@ void CDiscAdjSolver::SetAdjoint_OutputMesh(CGeometry *geometry, CConfig *config) for (iDim = 0; iDim < nDim; iDim++){ Solution_Geometry[iDim] = 0.0; } - if (fsi){ - for (iDim = 0; iDim < nDim; iDim++){ - Solution_Geometry[iDim] += nodes->GetGeometry_CrossTerm_Derivative(iPoint,iDim); - } - for (iDim = 0; iDim < nDim; iDim++){ - Solution_Geometry[iDim] += nodes->GetGeometry_CrossTerm_Derivative_Flow(iPoint,iDim); - } - } // if (dual_time){ // for (iDim = 0; iDim < nVar; iDim++){ // Solution_Geometry[iDim] += nodes->GetDual_Time_Derivative_Geometry(iPoint,iDim); @@ -1086,32 +1010,21 @@ void CDiscAdjSolver::ComputeResidual_Multizone(CGeometry *geometry, CConfig *con unsigned short iVar; unsigned long iPoint; - su2double residual, bgs_sol; + su2double residual; /*--- Set Residuals to zero ---*/ - for (iVar = 0; iVar < nVar; iVar++){ SetRes_BGS(iVar,0.0); SetRes_Max_BGS(iVar,0.0,0); } - /*--- Compute the BGS solution (adding the cross term) ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++){ - for (iVar = 0; iVar < nVar; iVar++){ - if(config->GetMultizone_Problem() && !config->GetFSI_Simulation()) { - bgs_sol = nodes->GetSolution(iPoint,iVar); - } - else { - bgs_sol = nodes->GetSolution(iPoint,iVar) + nodes->GetCross_Term_Derivative(iPoint,iVar); - } - nodes->Set_BGSSolution(iPoint, iVar, bgs_sol); - } - } - /*--- Set the residuals ---*/ + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + + /// TODO: This is only difference to the CSolver version, this method and the BGS var might be reduntant. + nodes->Set_BGSSolution(iPoint, iVar, nodes->GetSolution(iPoint, iVar)); - for (iPoint = 0; iPoint < nPointDomain; iPoint++){ - for (iVar = 0; iVar < nVar; iVar++){ residual = nodes->Get_BGSSolution(iPoint,iVar) - nodes->Get_BGSSolution_k(iPoint,iVar); AddRes_BGS(iVar,residual*residual); AddRes_Max_BGS(iVar,fabs(residual),geometry->node[iPoint]->GetGlobalIndex(),geometry->node[iPoint]->GetCoord()); diff --git a/SU2_CFD/src/variables/CDiscAdjFEAVariable.cpp b/SU2_CFD/src/variables/CDiscAdjFEAVariable.cpp index 44f7a7088851..042bec59f027 100644 --- a/SU2_CFD/src/variables/CDiscAdjFEAVariable.cpp +++ b/SU2_CFD/src/variables/CDiscAdjFEAVariable.cpp @@ -43,9 +43,6 @@ CDiscAdjFEAVariable::CDiscAdjFEAVariable(const su2double *disp, const su2double Solution(iPoint,iVar) = disp[iVar]; if (fsi) { - Cross_Term_Derivative.resize(nPoint,nDim) = su2double(0.0); - Geometry_CrossTerm_Derivative.resize(nPoint,nDim) = su2double(0.0); - Solution_BGS.resize(nPoint,nDim) = su2double(0.0); } diff --git a/SU2_CFD/src/variables/CDiscAdjVariable.cpp b/SU2_CFD/src/variables/CDiscAdjVariable.cpp index e0943e850ec3..1ef71c0206d5 100644 --- a/SU2_CFD/src/variables/CDiscAdjVariable.cpp +++ b/SU2_CFD/src/variables/CDiscAdjVariable.cpp @@ -56,9 +56,6 @@ CDiscAdjVariable::CDiscAdjVariable(const su2double* sol, unsigned long npoint, u Geometry_Direct.resize(nPoint,nDim) = su2double(0.0); Solution_Geometry.resize(nPoint,nDim) = su2double(1e-16); Solution_Geometry_Old.resize(nPoint,nDim) = su2double(0.0); - Cross_Term_Derivative.resize(nPoint,nVar) = su2double(0.0); - Geometry_CrossTerm_Derivative.resize(nPoint,nDim) = su2double(0.0); - Geometry_CrossTerm_Derivative_Flow.resize(nPoint,nDim) = su2double(0.0); Solution_BGS.resize(nPoint,nVar) = su2double(0.0); Solution_Geometry_BGS_k.resize(nPoint,nDim) = su2double(0.0); From d30b31e9976d58a90b6450bff3e01522704f31bb Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 26 Mar 2020 11:32:44 +0000 Subject: [PATCH 38/79] remove legacy FSI options --- Common/include/CConfig.hpp | 45 ++++++++------------------------------ Common/src/CConfig.cpp | 37 ++++--------------------------- 2 files changed, 13 insertions(+), 69 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 6d6adeca3f76..f41f799623f9 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -475,15 +475,11 @@ class CConfig { Kind_Deform_Linear_Solver, /*!< Numerical method to deform the grid */ Kind_Deform_Linear_Solver_Prec, /*!< \brief Preconditioner of the linear solver. */ Kind_Linear_Solver, /*!< \brief Numerical solver for the implicit scheme. */ - Kind_Linear_Solver_FSI_Struc, /*!< \brief Numerical solver for the structural part in FSI problems. */ Kind_Linear_Solver_Prec, /*!< \brief Preconditioner of the linear solver. */ - Kind_Linear_Solver_Prec_FSI_Struc, /*!< \brief Preconditioner of the linear solver for the structural part in FSI problems. */ Kind_AdjTurb_Linear_Solver, /*!< \brief Numerical solver for the turbulent adjoint implicit scheme. */ Kind_AdjTurb_Linear_Prec, /*!< \brief Preconditioner of the turbulent adjoint linear solver. */ Kind_DiscAdj_Linear_Solver, /*!< \brief Linear solver for the discrete adjoint system. */ Kind_DiscAdj_Linear_Prec, /*!< \brief Preconditioner of the discrete adjoint linear solver. */ - Kind_DiscAdj_Linear_Solver_FSI_Struc, /*!< \brief Linear solver for the discrete adjoint system in the structural side of FSI problems. */ - Kind_DiscAdj_Linear_Prec_FSI_Struc, /*!< \brief Preconditioner of the discrete adjoint linear solver in the structural side of FSI problems. */ Kind_SlopeLimit, /*!< \brief Global slope limiter. */ Kind_SlopeLimit_Flow, /*!< \brief Slope limiter for flow equations.*/ Kind_SlopeLimit_Turb, /*!< \brief Slope limiter for the turbulence equation.*/ @@ -525,8 +521,6 @@ class CConfig { Kind_FEM_Flow, /*!< \brief Finite element scheme for the flow equations. */ Kind_FEM_DG_Shock, /*!< \brief Shock capturing method for the FEM DG solver. */ Kind_Matrix_Coloring, /*!< \brief Type of matrix coloring for sparse Jacobian computation. */ - Kind_Solver_Fluid_FSI, /*!< \brief Kind of solver for the fluid in FSI applications. */ - Kind_Solver_Struc_FSI, /*!< \brief Kind of solver for the structure in FSI applications. */ Kind_BGS_RelaxMethod, /*!< \brief Kind of relaxation method for Block Gauss Seidel method in FSI problems. */ Kind_CHT_Coupling; /*!< \brief Kind of coupling method used at CHT interfaces. */ bool ReconstructionGradientRequired; /*!< \brief Enable or disable a second gradient calculation for upwind reconstruction only. */ @@ -568,11 +562,9 @@ class CConfig { bool Inc_Inlet_UseNormal; /*!< \brief Flag for whether to use the local normal as the flow direction for an incompressible pressure inlet. */ su2double Linear_Solver_Error; /*!< \brief Min error of the linear solver for the implicit formulation. */ su2double Deform_Linear_Solver_Error; /*!< \brief Min error of the linear solver for the implicit formulation. */ - su2double Linear_Solver_Error_FSI_Struc; /*!< \brief Min error of the linear solver for the implicit formulation in the structural side for FSI problems . */ su2double Linear_Solver_Smoother_Relaxation; /*!< \brief Relaxation factor for iterative linear smoothers. */ unsigned long Linear_Solver_Iter; /*!< \brief Max iterations of the linear solver for the implicit formulation. */ unsigned long Deform_Linear_Solver_Iter; /*!< \brief Max iterations of the linear solver for the implicit formulation. */ - unsigned long Linear_Solver_Iter_FSI_Struc; /*!< \brief Max iterations of the linear solver for FSI applications and structural solver. */ unsigned long Linear_Solver_Restart_Frequency; /*!< \brief Restart frequency of the linear solver for the implicit formulation. */ unsigned long Linear_Solver_Prec_Threads; /*!< \brief Number of threads per rank for ILU and LU_SGS preconditioners. */ unsigned short Linear_Solver_ILU_n; /*!< \brief ILU fill=in level. */ @@ -890,7 +882,6 @@ class CConfig { string RefGeom_FEMFileName; /*!< \brief File name for reference geometry. */ unsigned short RefGeom_FileFormat; /*!< \brief Mesh input format. */ unsigned short Kind_2DElasForm; /*!< \brief Kind of bidimensional elasticity solver. */ - unsigned short nIterFSI; /*!< \brief Number of maximum number of subiterations in a FSI problem. */ unsigned short nIterFSI_Ramp; /*!< \brief Number of FSI subiterations during which a ramp is applied. */ unsigned short iInst; /*!< \brief Current instance value */ su2double AitkenStatRelax; /*!< \brief Aitken's relaxation factor (if set as static) */ @@ -8394,18 +8385,6 @@ class CConfig { */ bool GetFull_Tape(void) const { return FullTape; } - /*! - * \brief Get the indicator whether we want to benchmark the MPI performance of FSI problems - * \return The value for checking - */ - bool CheckFSI_MPI(void); - - /*! - * \brief Get the number of fluid subiterations roblems. - * \return Number of FSI subiters. - */ - unsigned short GetnIterFSI(void) const { return nIterFSI; } - /*! * \brief Get the number of subiterations while a ramp is applied. * \return Number of FSI subiters. @@ -8657,12 +8636,6 @@ class CConfig { */ bool GetFSI_Simulation(void) const { return FSI_Problem || (nMarker_Fluid_Load > 0); } - /*! - * \brief Set that the simulation we are running is a FSI simulation - * \param[in] FSI_sim - boolean that determines is FSI_Problem is true/false. - */ - void SetFSI_Simulation(bool FSI_sim) { FSI_Problem = FSI_sim; } - /*! * \brief Set that the simulation we are running is a multizone simulation * \param[in] MZ_problem - boolean that determines is Multizone_Problem is true/false. @@ -8675,10 +8648,10 @@ class CConfig { */ bool GetMultizone_Problem(void) const { return Multizone_Problem; } - /*! - * \brief Get the ID for the FEA region that we want to compute the gradient for using direct differentiation - * \return ID - */ + /*! + * \brief Get the ID for the FEA region that we want to compute the gradient for using direct differentiation + * \return ID + */ unsigned short GetnID_DV(void) const { return nID_DV; } /*! @@ -8732,7 +8705,7 @@ class CConfig { /*! * \brief Function to make available the multiplication factor theta of the - symmetrizing terms in the DG discretization of the viscous terms. + * symmetrizing terms in the DG discretization of the viscous terms. * \return The specified factor for the DG discretization. */ su2double GetTheta_Interior_Penalty_DGFEM(void) const { return Theta_Interior_Penalty_DGFEM; } @@ -8759,7 +8732,7 @@ class CConfig { /*! * \brief Function to make available whether or not only the exact Jacobian - of the spatial discretization must be computed. + * of the spatial discretization must be computed. * \return The boolean whether or not the Jacobian must be computed. */ bool GetJacobian_Spatial_Discretization_Only(void) const { return Jacobian_Spatial_Discretization_Only; } @@ -8802,17 +8775,17 @@ class CConfig { /*! * \brief Get the kind of inlet face interpolation function to use. */ - inline unsigned short GetKindInletInterpolationFunction(void) const {return Kind_InletInterpolationFunction;} + inline unsigned short GetKindInletInterpolationFunction(void) const { return Kind_InletInterpolationFunction; } /*! * \brief Get the kind of inlet face interpolation data type. */ - inline unsigned short GetKindInletInterpolationType (void) const {return Kind_Inlet_InterpolationType;} + inline unsigned short GetKindInletInterpolationType (void) const { return Kind_Inlet_InterpolationType; } /*! * \brief Get whether to print inlet interpolated data or not. */ - bool GetPrintInlet_InterpolatedData(void) const { return PrintInlet_InterpolatedData;} + bool GetPrintInlet_InterpolatedData(void) const { return PrintInlet_InterpolatedData; } /*! * \brief Get information about using UQ methodology diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index c8df44966908..31f5f75515cc 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -1118,8 +1118,6 @@ void CConfig::SetConfig_Options() { /*!\brief WEAKLY_COUPLED_HEAT_EQUATION \n DESCRIPTION: Enable heat equation for incompressible flows. \ingroup Config*/ addBoolOption("WEAKLY_COUPLED_HEAT_EQUATION", Weakly_Coupled_Heat, NO); - addBoolOption("ADJ_FSI", FSI_Problem, NO); - /*\brief AXISYMMETRIC \n DESCRIPTION: Axisymmetric simulation \n DEFAULT: false \ingroup Config */ addBoolOption("AXISYMMETRIC", Axisymmetric, false); /* DESCRIPTION: Add the gravity force */ @@ -1701,9 +1699,6 @@ void CConfig::SetConfig_Options() { /* DESCRIPTION: Preconditioner for the discrete adjoint Krylov linear solvers */ addEnumOption("DISCADJ_LIN_PREC", Kind_DiscAdj_Linear_Prec, Linear_Solver_Prec_Map, ILU); /* DESCRIPTION: Linear solver for the discete adjoint systems */ - addEnumOption("FSI_DISCADJ_LIN_SOLVER_STRUC", Kind_DiscAdj_Linear_Solver_FSI_Struc, Linear_Solver_Map, CONJUGATE_GRADIENT); - /* DESCRIPTION: Preconditioner for the discrete adjoint Krylov linear solvers */ - addEnumOption("FSI_DISCADJ_LIN_PREC_STRUC", Kind_DiscAdj_Linear_Prec_FSI_Struc, Linear_Solver_Prec_Map, JACOBI); /*!\par CONFIG_CATEGORY: Convergence\ingroup Config*/ /*--- Options related to convergence ---*/ @@ -2394,27 +2389,6 @@ void CConfig::SetConfig_Options() { /* CONFIG_CATEGORY: FSI solver */ /*--- Options related to the FSI solver ---*/ - /*!\brief PHYSICAL_PROBLEM_FLUID_FSI - * DESCRIPTION: Physical governing equations \n - * Options: NONE (default),EULER, NAVIER_STOKES, RANS, - * \ingroup Config*/ - addEnumOption("FSI_FLUID_PROBLEM", Kind_Solver_Fluid_FSI, FSI_Fluid_Solver_Map, NO_SOLVER_FFSI); - - /*!\brief PHYSICAL_PROBLEM_STRUCTURAL_FSI - * DESCRIPTION: Physical governing equations \n - * Options: NONE (default), FEM_ELASTICITY - * \ingroup Config*/ - addEnumOption("FSI_STRUCTURAL_PROBLEM", Kind_Solver_Struc_FSI, FSI_Struc_Solver_Map, NO_SOLVER_SFSI); - - /* DESCRIPTION: Linear solver for the structural side on FSI problems */ - addEnumOption("FSI_LINEAR_SOLVER_STRUC", Kind_Linear_Solver_FSI_Struc, Linear_Solver_Map, FGMRES); - /* DESCRIPTION: Preconditioner for the Krylov linear solvers */ - addEnumOption("FSI_LINEAR_SOLVER_PREC_STRUC", Kind_Linear_Solver_Prec_FSI_Struc, Linear_Solver_Prec_Map, ILU); - /* DESCRIPTION: Maximum number of iterations of the linear solver for the implicit formulation */ - addUnsignedLongOption("FSI_LINEAR_SOLVER_ITER_STRUC", Linear_Solver_Iter_FSI_Struc, 500); - /* DESCRIPTION: Minimum error threshold for the linear solver for the implicit formulation */ - addDoubleOption("FSI_LINEAR_SOLVER_ERROR_STRUC", Linear_Solver_Error_FSI_Struc, 1E-6); - /* DESCRIPTION: ID of the region we want to compute the sensitivities using direct differentiation */ addUnsignedShortOption("FEA_ID_DIRECTDIFF", nID_DV, 0); @@ -2498,8 +2472,6 @@ void CConfig::SetConfig_Options() { addBoolOption("PRINT_INLET_INTERPOLATED_DATA", PrintInlet_InterpolatedData, false); - /* DESCRIPTION: Maximum number of FSI iterations */ - addUnsignedShortOption("FSI_ITER", nIterFSI, 1); /* DESCRIPTION: Number of FSI iterations during which a ramp is applied */ addUnsignedShortOption("RAMP_FSI_ITER", nIterFSI_Ramp, 2); /* DESCRIPTION: Aitken's static relaxation factor */ @@ -5559,14 +5531,13 @@ void CConfig::SetOutput(unsigned short val_software, unsigned short val_izone) { cout << endl <<"----------------- Physical Case Definition ( Zone " << iZone << " ) -------------------" << endl; if (val_software == SU2_CFD) { - if (FSI_Problem) { + if (FSI_Problem) cout << "Fluid-Structure Interaction." << endl; - } - if (DiscreteAdjoint) { - cout <<"Discrete Adjoint equations using Algorithmic Differentiation " << endl; + if (DiscreteAdjoint) { + cout <<"Discrete Adjoint equations using Algorithmic Differentiation\n"; cout <<"based on the physical case: "; - } + } switch (Kind_Solver) { case EULER: case DISC_ADJ_EULER: case INC_EULER: case DISC_ADJ_INC_EULER: From 2cacc2f33998d8ecfb5e60c396105242d609bc1e Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 26 Mar 2020 13:54:16 +0000 Subject: [PATCH 39/79] fix un-init boolean --- Common/include/CConfig.hpp | 2 +- Common/src/CConfig.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index f41f799623f9..9b159898a55b 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -535,7 +535,7 @@ class CConfig { MUSCL_AdjTurb, /*!< \brief MUSCL scheme for the adj turbulence equations.*/ Use_Accurate_Jacobians; /*!< \brief Use numerically computed Jacobians for AUSM+up(2) and SLAU(2). */ bool EulerPersson; /*!< \brief Boolean to determine whether this is an Euler simulation with Persson shock capturing. */ - bool FSI_Problem, /*!< \brief Boolean to determine whether the simulation is FSI or not. */ + bool FSI_Problem = false,/*!< \brief Boolean to determine whether the simulation is FSI or not. */ Multizone_Problem; /*!< \brief Boolean to determine whether we are solving a multizone problem. */ unsigned short nID_DV; /*!< \brief ID for the region of FEM when computed using direct differentiation. */ diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 31f5f75515cc..f12f2fbccd70 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -9794,7 +9794,7 @@ void CConfig::SetMultizone(CConfig *driver_config, CConfig **config_container){ } /*--- If the problem has FSI properties ---*/ - if (fluid_zone && structural_zone) FSI_Problem = true; + FSI_Problem = fluid_zone && structural_zone; Multizone_Residual = true; From 935345f0cde9cc68016506b3a62bf092952c2a49 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 26 Mar 2020 16:28:01 +0000 Subject: [PATCH 40/79] update FSI testcases --- SU2_CFD/src/drivers/CDriver.cpp | 6 +- TestCases/disc_adj_fsi/config.cfg | 7 +- TestCases/disc_adj_fsi/configFEA.cfg | 1 - TestCases/disc_adj_fsi/configFlow.cfg | 23 ++-- TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg | 1 - TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg | 4 +- .../fea_fsi/WallChannel_2d/configFSI_2D.cfg | 108 ------------------ .../fea_fsi/WallChannel_2d/configFlow.cfg | 4 +- .../pitching_naca64a010/turb_NACA64A010.cfg | 2 +- .../pitching_oneram6/turb_ONERAM6.cfg | 2 +- TestCases/parallel_regression.py | 4 +- TestCases/parallel_regression_AD.py | 4 +- .../caradonna_tung/rot_caradonna_tung.cfg | 2 +- TestCases/rotating/naca0012/rot_NACA0012.cfg | 2 +- TestCases/serial_regression.py | 6 +- TestCases/serial_regression_AD.py | 4 +- .../pitching_NACA64A010.cfg | 2 +- .../turb_NACA64A010.cfg | 2 +- 18 files changed, 39 insertions(+), 145 deletions(-) delete mode 100644 TestCases/fea_fsi/WallChannel_2d/configFSI_2D.cfg diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index 5fd3449391cd..105350b8f97a 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -2671,8 +2671,10 @@ void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGe if (rank == MASTER_NODE) cout << "flow tractions. " << endl; } else if (structural_donor && fluid_target) { - if (solver_container[targetZone][INST_0][MESH_0][MESH_SOL] == nullptr) - SU2_MPI::Error("Mesh deformation was not correctly specified for the fluid zone.", CURRENT_FUNCTION); + if (solver_container[targetZone][INST_0][MESH_0][MESH_SOL] == nullptr) { + SU2_MPI::Error("Mesh deformation was not correctly specified for the fluid zone.\n" + "Use DEFORM_MESH=YES, and setup MARKER_DEFORM_MESH=(...)", CURRENT_FUNCTION); + } interface_types[donorZone][targetZone] = BOUNDARY_DISPLACEMENTS; nVarTransfer = 0; interface[donorZone][targetZone] = new CDisplacementsInterface(nVar, nVarTransfer, config[donorZone]); diff --git a/TestCases/disc_adj_fsi/config.cfg b/TestCases/disc_adj_fsi/config.cfg index 97bc1d1a159f..35cf049125dd 100644 --- a/TestCases/disc_adj_fsi/config.cfg +++ b/TestCases/disc_adj_fsi/config.cfg @@ -4,8 +4,11 @@ CONFIG_LIST=(configFlow.cfg, configFEA.cfg) MARKER_ZONE_INTERFACE = (UpperWall, UpperWallS, LowerWall, LowerWallS) -ADJ_FSI= YES -OUTER_ITER= 4 +OUTER_ITER= 7 MESH_FILENAME= mesh.su2 OBJECTIVE_FUNCTION = REFERENCE_GEOMETRY + +SCREEN_OUTPUT= OUTER_ITER, AVG_BGS_RES[0], RMS_ADJ_DENSITY[0], SENS_E[1], SENS_NU[1] + +%WRT_ZONE_CONV= YES diff --git a/TestCases/disc_adj_fsi/configFEA.cfg b/TestCases/disc_adj_fsi/configFEA.cfg index ddb4fec151af..9571f489f2ff 100644 --- a/TestCases/disc_adj_fsi/configFEA.cfg +++ b/TestCases/disc_adj_fsi/configFEA.cfg @@ -45,7 +45,6 @@ NONLINEAR_FEM_SOLUTION_METHOD = NEWTON_RAPHSON INNER_ITER= 5 MARKER_CLAMPED = ( Clamped_Right, Clamped_Left ) -MARKER_PRESSURE= ( LowerWallS, 0, UpperWallS, 0) MARKER_FLUID_LOAD= ( LowerWallS, UpperWallS) WRT_CON_FREQ= 1 diff --git a/TestCases/disc_adj_fsi/configFlow.cfg b/TestCases/disc_adj_fsi/configFlow.cfg index b45526bf36ba..3510bde95fd0 100644 --- a/TestCases/disc_adj_fsi/configFlow.cfg +++ b/TestCases/disc_adj_fsi/configFlow.cfg @@ -45,7 +45,9 @@ MARKER_HEATFLUX= ( Wall, 0.0, UpperWall, 0.0, LowerWall, 0.0) MARKER_FAR = ( Farfield ) MARKER_PLOTTING= ( UpperWall, LowerWall, Wall) MARKER_MONITORING= ( UpperWall, LowerWall, Wall) -SURFACE_MOVEMENT= FLUID_STRUCTURE_STATIC + +DEFORM_MESH= YES +MARKER_DEFORM_MESH= ( UpperWall, LowerWall ) WRT_CON_FREQ= 1 WRT_CON_FREQ_DUALTIME= 1 @@ -54,33 +56,30 @@ WRT_SOL_FREQ_DUALTIME= 5 DEFORM_STIFFNESS_TYPE = INVERSE_VOLUME DEFORM_LINEAR_SOLVER = CONJUGATE_GRADIENT - -DEFORM_LINEAR_SOLVER_PREC = JACOBI -DEFORM_LINEAR_SOLVER_ERROR = 1E-5 -DEFORM_LINEAR_SOLVER_ITER = 5000 +DEFORM_LINEAR_SOLVER_PREC = ILU +DEFORM_LINEAR_SOLVER_ERROR = 1E-8 +DEFORM_LINEAR_SOLVER_ITER = 1000 NUM_METHOD_GRAD= WEIGHTED_LEAST_SQUARES -CFL_NUMBER= 1.0 -RK_ALPHA_COEFF= ( 0.66667, 0.66667, 1.000000 ) +CFL_NUMBER= 100.0 LINEAR_SOLVER= FGMRES LINEAR_SOLVER_PREC= LU_SGS -LINEAR_SOLVER_ERROR= 1E-6 -LINEAR_SOLVER_ITER= 2 +LINEAR_SOLVER_ERROR= 1E-3 +LINEAR_SOLVER_ITER= 20 DISCADJ_LIN_SOLVER= FGMRES -DISCADJ_LIN_PREC= JACOBI +DISCADJ_LIN_PREC= ILU CONV_NUM_METHOD_FLOW= ROE MUSCL_FLOW= YES SLOPE_LIMITER_FLOW= VENKATAKRISHNAN VENKAT_LIMITER_COEFF= 1.0 -JST_SENSOR_COEFF=( 0.5, 0.02 ) TIME_DISCRE_FLOW= EULER_IMPLICIT CONV_CRITERIA= RESIDUAL CONV_RESIDUAL_MINVAL= -10 -CONV_STARTITER= 10 +CONV_STARTITER= 0 CONV_CAUCHY_ELEMS= 100 CONV_CAUCHY_EPS= 1E-5 diff --git a/TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg b/TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg index eff2d6ed2b36..58c25d418df8 100644 --- a/TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg +++ b/TestCases/fea_fsi/Airfoil_RBF/configFEA.cfg @@ -25,7 +25,6 @@ POISSON_RATIO= 0.35 MATERIAL_DENSITY= 2700.0 % % Boundary conditions -------------------------------------------------- % -MARKER_PRESSURE= ( pressure_side_s,0.0, suction_side_s,0.0 ) MARKER_FLUID_LOAD= ( pressure_side_s, suction_side_s, clamped ) MARKER_CLAMPED= ( clamped ) % diff --git a/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg b/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg index 9efc636b33d4..306246304418 100644 --- a/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg +++ b/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg @@ -86,8 +86,8 @@ MG_DAMP_RESTRICTION= 0.75 MG_DAMP_PROLONGATION= 0.75 % % Grid deformation ----------------------------------------------------- % -SURFACE_MOVEMENT= FLUID_STRUCTURE_STATIC -MARKER_MOVING= ( leading_edge, pressure_side, suction_side ) +DEFORM_MESH= YES +MARKER_DEFORM_MESH= ( leading_edge, pressure_side, suction_side ) DEFORM_NONLINEAR_ITER= 1 DEFORM_STIFFNESS_TYPE= INVERSE_VOLUME DEFORM_CONSOLE_OUTPUT= NO diff --git a/TestCases/fea_fsi/WallChannel_2d/configFSI_2D.cfg b/TestCases/fea_fsi/WallChannel_2d/configFSI_2D.cfg deleted file mode 100644 index 9d1cd59e1af1..000000000000 --- a/TestCases/fea_fsi/WallChannel_2d/configFSI_2D.cfg +++ /dev/null @@ -1,108 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% SU2 configuration file % -% Case description: Fluid Structure Interaction - Wall in channel % -% Author: R.Sanchez % -% Institution: Imperial College London % -% Date: 2016.02.01 % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -MULTIZONE=YES -TIME_ITER=3 -TIME_STEP= 0.005 -RESTART_ITER=2 - - -SURFACE_MOVEMENT=FLUID_STRUCTURE -SOLVER= FLUID_STRUCTURE_INTERACTION -FSI_FLUID_PROBLEM = NAVIER_STOKES -FSI_STRUCTURAL_PROBLEM = ELASTICITY -MATH_PROBLEM= DIRECT -RESTART_SOL= YES -WRT_BINARY_RESTART= NO -READ_BINARY_RESTART= NO -RESTART_ITER= 2 -FSI_ITER= 5 -MARKER_ZONE_INTERFACE = (wallUpwF, wallUpwS, wallUpperF, wallUpperS, wallDownF, wallDownS) -CONSERVATIVE_INTERPOLATION = YES -BGS_RELAXATION = FIXED_PARAMETER -STAT_RELAX_PARAMETER= 0.5 -CONV_RESIDUAL_MINVAL_FSI= -8 -TIME_MARCHING= DUAL_TIME_STEPPING-2ND_ORDER -MAX_TIME= 4.01 -INNER_ITER= 50 -KIND_TURB_MODEL= NONE -AOA= 0.0 -SIDESLIP_ANGLE= 0.0 -REYNOLDS_NUMBER= 10 -MACH_NUMBER = 0.2 -MACH_MOTION = 0.2 -INIT_OPTION = TD_CONDITIONS -FREESTREAM_OPTION = DENSITY_FS -FREESTREAM_DENSITY = 1.0 -FREESTREAM_PRESSURE = 17.85714286 -FREESTREAM_TEMPERATURE = 0.062207438 -VISCOSITY_MODEL = CONSTANT_VISCOSITY -MU_CONSTANT = 1.6E-3 -REF_ORIGIN_MOMENT_X = 0.00 -REF_ORIGIN_MOMENT_Y = 0.00 -REF_ORIGIN_MOMENT_Z = 0.00 -REF_LENGTH= 0.016 -REF_AREA= 0.016 -REYNOLDS_LENGTH=0.016 -MARKER_HEATFLUX= ( wallUpwF, 0.0, wallDownF, 0.0, wallUpperF, 0.0) -MARKER_INLET= ( inlet, 0.062207438, 18.36216288, 1.0, 0.0, 0.0 ) -MARKER_OUTLET= ( outlet, 17.85714286) -MARKER_EULER= ( upper, lower ) -MARKER_PLOTTING= ( wallUpwF, wallDownF, wallUpperF ) -MARKER_MONITORING= ( wallUpwF, wallDownF, wallUpperF ) -NUM_METHOD_GRAD= WEIGHTED_LEAST_SQUARES -RK_ALPHA_COEFF= ( 0.66667, 0.66667, 1.000000 ) -LINEAR_SOLVER= FGMRES -LINEAR_SOLVER_PREC= LU_SGS -LINEAR_SOLVER_ERROR= 1E-6 -LINEAR_SOLVER_ITER= 2 -CONV_NUM_METHOD_FLOW= ROE -MUSCL_FLOW= YES -VENKAT_LIMITER_COEFF= 1.0 -JST_SENSOR_COEFF= ( 0.5, 0.02 ) -TIME_DISCRE_FLOW= EULER_IMPLICIT -CONV_CRITERIA= RESIDUAL -CONV_RESIDUAL_MINVAL= -10 -CONV_STARTITER= 10 -CONV_CAUCHY_ELEMS= 100 -CONV_CAUCHY_EPS= 1E-5 -ELASTICITY_MODULUS=5E4 -MATERIAL_DENSITY=50 -FORMULATION_ELASTICITY_2D = PLANE_STRESS -POISSON_RATIO=0.3 -DYNAMIC_ANALYSIS= YES -DYN_TIME= 4.01 -TIME_DISCRE_FEA= NEWMARK_IMPLICIT -NEWMARK_BETA=0.36 -NEWMARK_GAMMA=0.7 -GEOMETRIC_CONDITIONS= LARGE_DEFORMATIONS -MATERIAL_MODEL= NEO_HOOKEAN -NONLINEAR_FEM_INT_ITER = 10 -FSI_LINEAR_SOLVER_PREC_STRUC= LU_SGS -FSI_LINEAR_SOLVER_ITER_STRUC = 1000 -MARKER_CLAMPED = ( clamped ) -MARKER_PRESSURE= ( wallDownS, 0.0, wallUpperS, 0.0, wallUpwS, 0.0) -MESH_FILENAME= meshFSI_2D.su2 -DEFORM_NONLINEAR_ITER= 1 -DEFORM_LINEAR_SOLVER= FGMRES -DEFORM_LINEAR_SOLVER_PREC= LU_SGS -DEFORM_LINEAR_SOLVER_ITER= 500 -DEFORM_STIFFNESS_TYPE= INVERSE_VOLUME -MESH_FORMAT= SU2 -TABULAR_FORMAT= CSV -WRT_CON_FREQ= 100 -WRT_CON_FREQ_DUALTIME= 100 -WRT_SOL_FREQ= 100 -WRT_SOL_FREQ_DUALTIME= 100 -VOLUME_FILENAME= results_flow -RESTART_FILENAME= restart_flow.dat -SOLUTION_FILENAME= solution_flow.dat -VOLUME_STRUCTURE_FILENAME= results_wall -RESTART_STRUCTURE_FILENAME= restart_wall.dat -SOLUTION_STRUCTURE_FILENAME= solution_wall.dat -WRT_SRF_SOL = NO -WRT_CSV_SOL = NO diff --git a/TestCases/fea_fsi/WallChannel_2d/configFlow.cfg b/TestCases/fea_fsi/WallChannel_2d/configFlow.cfg index 82578ee2194c..08d5716c6698 100644 --- a/TestCases/fea_fsi/WallChannel_2d/configFlow.cfg +++ b/TestCases/fea_fsi/WallChannel_2d/configFlow.cfg @@ -7,8 +7,8 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SOLVER= NAVIER_STOKES -SURFACE_MOVEMENT = FLUID_STRUCTURE -MARKER_MOVING=(wallUpwF, wallDownF, wallUpperF) +DEFORM_MESH= YES +MARKER_DEFORM_MESH= (wallUpwF, wallDownF, wallUpperF) INNER_ITER=50 %SCREEN_OUTPUT=(TIME_ITER, OUTER_ITER, INNER_ITER, BGS_DENSITY, BGS_ENERGY) diff --git a/TestCases/optimization_rans/pitching_naca64a010/turb_NACA64A010.cfg b/TestCases/optimization_rans/pitching_naca64a010/turb_NACA64A010.cfg index d4388c6850bd..6d6449ccf15f 100644 --- a/TestCases/optimization_rans/pitching_naca64a010/turb_NACA64A010.cfg +++ b/TestCases/optimization_rans/pitching_naca64a010/turb_NACA64A010.cfg @@ -47,7 +47,7 @@ INNER_ITER= 2000 % Direct iteration number at which to begin unsteady adjoint UNST_ADJOINT_ITER= 251 % -% Type of mesh motion (NONE, FLUTTER, RIGID_MOTION, FLUID_STRUCTURE) +% Type of mesh motion (NONE, FLUTTER, RIGID_MOTION) GRID_MOVEMENT= RIGID_MOTION % % Mach number (non-dimensional, based on the mesh velocity and freestream vals.) diff --git a/TestCases/optimization_rans/pitching_oneram6/turb_ONERAM6.cfg b/TestCases/optimization_rans/pitching_oneram6/turb_ONERAM6.cfg index 6dad685b8ef0..e2d25b385c3f 100644 --- a/TestCases/optimization_rans/pitching_oneram6/turb_ONERAM6.cfg +++ b/TestCases/optimization_rans/pitching_oneram6/turb_ONERAM6.cfg @@ -68,7 +68,7 @@ UNST_ADJOINT_ITER= 176 % ----------------------- DYNAMIC MESH DEFINITION -----------------------------% % Type of dynamic mesh (NONE, RIGID_MOTION, DEFORMING, ROTATING_FRAME, -% MOVING_WALL, FLUID_STRUCTURE, AEROELASTIC, EXTERNAL) +% MOVING_WALL, AEROELASTIC, EXTERNAL) GRID_MOVEMENT= RIGID_MOTION % % Motion mach number (non-dimensional). Used for intitializing a viscous flow diff --git a/TestCases/parallel_regression.py b/TestCases/parallel_regression.py index 691f5502810e..c04ef2bb0fdb 100644 --- a/TestCases/parallel_regression.py +++ b/TestCases/parallel_regression.py @@ -1039,7 +1039,7 @@ def main(): fsi2d.cfg_dir = "fea_fsi/WallChannel_2d" fsi2d.cfg_file = "configFSI.cfg" fsi2d.test_iter = 4 - fsi2d.test_vals = [4.000000, 0.000000, -3.801272, -4.123968] #last 4 columns + fsi2d.test_vals = [4, 0, -3.764076, -4.081142] #last 4 columns fsi2d.su2_exec = "parallel_computation_fsi.py -f" fsi2d.timeout = 1600 fsi2d.multizone= True @@ -1196,7 +1196,7 @@ def main(): pywrapper_fsi2d.cfg_dir = "fea_fsi/WallChannel_2d" pywrapper_fsi2d.cfg_file = "configFSI.cfg" pywrapper_fsi2d.test_iter = 4 - pywrapper_fsi2d.test_vals = [4.000000, 0.000000, -3.801272, -4.123968] #last 4 columns + pywrapper_fsi2d.test_vals = [4, 0, -3.764076, -4.081142] #last 4 columns pywrapper_fsi2d.su2_exec = "mpirun -np 2 SU2_CFD.py --nZone 2 --fsi True --parallel -f" pywrapper_fsi2d.timeout = 1600 pywrapper_fsi2d.unsteady = True diff --git a/TestCases/parallel_regression_AD.py b/TestCases/parallel_regression_AD.py index a1c17b61e2c2..c02efe7512b6 100644 --- a/TestCases/parallel_regression_AD.py +++ b/TestCases/parallel_regression_AD.py @@ -291,8 +291,8 @@ def main(): discadj_fsi = TestCase('discadj_fsi') discadj_fsi.cfg_dir = "disc_adj_fsi" discadj_fsi.cfg_file = "config.cfg" - discadj_fsi.test_iter = 3000 - discadj_fsi.test_vals = [0.958848,-0.157601,2.726147,1.798362] #last 4 columns + discadj_fsi.test_iter = 6 + discadj_fsi.test_vals = [6, -1.563852, -3.075167, 4.3991e-04, -1.0631] #last 5 columns discadj_fsi.su2_exec = "mpirun -n 2 SU2_CFD_AD" discadj_fsi.timeout = 1600 discadj_fsi.tol = 0.00001 diff --git a/TestCases/rotating/caradonna_tung/rot_caradonna_tung.cfg b/TestCases/rotating/caradonna_tung/rot_caradonna_tung.cfg index 495442ccdc52..2c74231eb369 100644 --- a/TestCases/rotating/caradonna_tung/rot_caradonna_tung.cfg +++ b/TestCases/rotating/caradonna_tung/rot_caradonna_tung.cfg @@ -55,7 +55,7 @@ REF_AREA= 1.0 % ----------------------- DYNAMIC MESH DEFINITION -----------------------------% % % Type of dynamic mesh (NONE, RIGID_MOTION, DEFORMING, ROTATING_FRAME, -% MOVING_WALL, FLUID_STRUCTURE, AEROELASTIC, EXTERNAL) +% MOVING_WALL, AEROELASTIC, EXTERNAL) GRID_MOVEMENT= ROTATING_FRAME % % Motion mach number (non-dimensional). Used for intitializing a viscous flow diff --git a/TestCases/rotating/naca0012/rot_NACA0012.cfg b/TestCases/rotating/naca0012/rot_NACA0012.cfg index aaff10897078..0fce2d573015 100644 --- a/TestCases/rotating/naca0012/rot_NACA0012.cfg +++ b/TestCases/rotating/naca0012/rot_NACA0012.cfg @@ -55,7 +55,7 @@ REF_AREA= 1.0 % ----------------------- DYNAMIC MESH DEFINITION -----------------------------% % % Type of dynamic mesh (NONE, RIGID_MOTION, DEFORMING, ROTATING_FRAME, -% MOVING_WALL, FLUID_STRUCTURE, AEROELASTIC, EXTERNAL) +% MOVING_WALL, AEROELASTIC, EXTERNAL) GRID_MOVEMENT= ROTATING_FRAME % % Motion mach number (non-dimensional). Used for intitializing a viscous flow diff --git a/TestCases/serial_regression.py b/TestCases/serial_regression.py index 0514a1aecd89..a9d9a85d5b34 100644 --- a/TestCases/serial_regression.py +++ b/TestCases/serial_regression.py @@ -1230,7 +1230,7 @@ def main(): fsi2d.cfg_dir = "fea_fsi/WallChannel_2d" fsi2d.cfg_file = "configFSI.cfg" fsi2d.test_iter = 4 - fsi2d.test_vals = [4.000000, 0.000000, -3.801272, -4.123970] #last 4 columns + fsi2d.test_vals = [4, 0, -3.764077, -4.081143] #last 4 columns fsi2d.su2_exec = "SU2_CFD" fsi2d.timeout = 1600 fsi2d.multizone = True @@ -1280,7 +1280,7 @@ def main(): airfoilRBF.cfg_dir = "fea_fsi/Airfoil_RBF" airfoilRBF.cfg_file = "config.cfg" airfoilRBF.test_iter = 1 - airfoilRBF.test_vals = [1.000000, -2.980686, -4.866015] + airfoilRBF.test_vals = [1.000000, -2.989055, -4.895265] airfoilRBF.su2_exec = "SU2_CFD" airfoilRBF.timeout = 1600 airfoilRBF.multizone = True @@ -1772,7 +1772,7 @@ def main(): pywrapper_fsi2d.cfg_dir = "fea_fsi/WallChannel_2d" pywrapper_fsi2d.cfg_file = "configFSI.cfg" pywrapper_fsi2d.test_iter = 4 - pywrapper_fsi2d.test_vals = [4.000000, 0.000000, -3.801272, -4.123970] #last 4 columns + pywrapper_fsi2d.test_vals = [4, 0, -3.764077, -4.081143] #last 4 columns pywrapper_fsi2d.su2_exec = "SU2_CFD.py --nZone 2 --fsi True -f" pywrapper_fsi2d.new_output = True pywrapper_fsi2d.unsteady = True diff --git a/TestCases/serial_regression_AD.py b/TestCases/serial_regression_AD.py index 23dba104af65..0f29c3310384 100644 --- a/TestCases/serial_regression_AD.py +++ b/TestCases/serial_regression_AD.py @@ -270,8 +270,8 @@ def main(): discadj_fsi = TestCase('discadj_fsi') discadj_fsi.cfg_dir = "disc_adj_fsi" discadj_fsi.cfg_file = "config.cfg" - discadj_fsi.test_iter = 3000 - discadj_fsi.test_vals = [0.958848,-0.157601,2.726147,1.798362] #last 4 columns + discadj_fsi.test_iter = 6 + discadj_fsi.test_vals = [6, -1.572702, -3.084381, 4.3990e-04, -1.0631] #last 5 columns discadj_fsi.su2_exec = "SU2_CFD_AD" discadj_fsi.timeout = 1600 discadj_fsi.tol = 0.00001 diff --git a/TestCases/unsteady/pitching_naca64a010_euler/pitching_NACA64A010.cfg b/TestCases/unsteady/pitching_naca64a010_euler/pitching_NACA64A010.cfg index 025ab1270fa7..9a663b396cdc 100644 --- a/TestCases/unsteady/pitching_naca64a010_euler/pitching_NACA64A010.cfg +++ b/TestCases/unsteady/pitching_naca64a010_euler/pitching_NACA64A010.cfg @@ -47,7 +47,7 @@ INNER_ITER= 110 UNST_ADJOINT_ITER= 251 % ----------------------- DYNAMIC MESH DEFINITION -----------------------------% -% Type of mesh motion (NONE, FLUTTER, RIGID_MOTION, FLUID_STRUCTURE) +% Type of mesh motion (NONE, FLUTTER, RIGID_MOTION) %GRID_MOVEMENT= RIGID_MOTION % SURFACE_MOVEMENT= DEFORMING diff --git a/TestCases/unsteady/pitching_naca64a010_rans/turb_NACA64A010.cfg b/TestCases/unsteady/pitching_naca64a010_rans/turb_NACA64A010.cfg index 704b843fc18f..81cf192fdb45 100644 --- a/TestCases/unsteady/pitching_naca64a010_rans/turb_NACA64A010.cfg +++ b/TestCases/unsteady/pitching_naca64a010_rans/turb_NACA64A010.cfg @@ -47,7 +47,7 @@ INNER_ITER= 2000 % Direct iteration number at which to begin unsteady adjoint UNST_ADJOINT_ITER= 251 % -% Type of mesh motion (NONE, FLUTTER, RIGID_MOTION, FLUID_STRUCTURE) +% Type of mesh motion (NONE, FLUTTER, RIGID_MOTION) GRID_MOVEMENT= RIGID_MOTION % % Mach number (non-dimensional, based on the mesh velocity and freestream vals.) From 05758ff22f4536a511481a102bb45db701042e90 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 26 Mar 2020 17:49:42 +0000 Subject: [PATCH 41/79] temporarily move some surface motions to CMeshSolver to avoid duplication --- Common/include/CConfig.hpp | 198 +++---- Common/include/grid_movement_structure.hpp | 40 -- Common/src/CConfig.cpp | 215 ++++---- Common/src/grid_movement_structure.cpp | 581 --------------------- SU2_CFD/include/solvers/CMeshSolver.hpp | 16 +- SU2_CFD/include/solvers/CSolver.hpp | 36 -- SU2_CFD/src/iteration_structure.cpp | 151 +----- SU2_CFD/src/solvers/CMeshSolver.cpp | 25 +- 8 files changed, 238 insertions(+), 1024 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 9b159898a55b..99515ee63dfa 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -4667,7 +4667,7 @@ class CConfig { * \brief Get the type of incompressible inlet from the list. * \return Kind of the incompressible inlet. */ - unsigned short GetKind_Inc_Inlet(string val_marker); + unsigned short GetKind_Inc_Inlet(string val_marker) const; /*! * \brief Get the total number of types in Kind_Inc_Inlet list @@ -4685,7 +4685,7 @@ class CConfig { * \brief Get the type of incompressible outlet from the list. * \return Kind of the incompressible outlet. */ - unsigned short GetKind_Inc_Outlet(string val_marker); + unsigned short GetKind_Inc_Outlet(string val_marker) const; /*! * \brief Get the damping factor applied to velocity updates at incompressible pressure inlets. @@ -5578,7 +5578,7 @@ class CConfig { * \brief Get information about the volumetric movement. * \return TRUE if there is a volumetric movement is required; otherwise FALSE. */ - bool GetVolumetric_Movement(void); + bool GetVolumetric_Movement(void) const; /*! * \brief Get information about deforming markers. @@ -6302,102 +6302,104 @@ class CConfig { * \brief Get the rotationally periodic donor marker for boundary val_marker. * \return Periodic donor marker from the config information for the marker val_marker. */ - unsigned short GetMarker_Periodic_Donor(string val_marker); + unsigned short GetMarker_Periodic_Donor(string val_marker) const; /*! * \brief Get the origin of the actuator disk. */ - su2double GetActDisk_NetThrust(string val_marker); + su2double GetActDisk_NetThrust(string val_marker) const; /*! * \brief Get the origin of the actuator disk. */ - su2double GetActDisk_Power(string val_marker); + su2double GetActDisk_Power(string val_marker) const; /*! * \brief Get the origin of the actuator disk. */ - su2double GetActDisk_MassFlow(string val_marker); + su2double GetActDisk_MassFlow(string val_marker) const; + /*! * \brief Get the origin of the actuator disk. */ - su2double GetActDisk_Mach(string val_marker); + su2double GetActDisk_Mach(string val_marker) const; + /*! * \brief Get the origin of the actuator disk. */ - su2double GetActDisk_Force(string val_marker); + su2double GetActDisk_Force(string val_marker) const; /*! * \brief Get the origin of the actuator disk. */ - su2double GetActDisk_BCThrust(string val_marker); + su2double GetActDisk_BCThrust(string val_marker) const; /*! * \brief Get the origin of the actuator disk. */ - su2double GetActDisk_BCThrust_Old(string val_marker); + su2double GetActDisk_BCThrust_Old(string val_marker) const; /*! * \brief Get the tip radius of th actuator disk. */ - su2double GetActDisk_Area(string val_marker); + su2double GetActDisk_Area(string val_marker) const; /*! * \brief Get the tip radius of th actuator disk. */ - su2double GetActDisk_ReverseMassFlow(string val_marker); + su2double GetActDisk_ReverseMassFlow(string val_marker) const; /*! * \brief Get the thrust corffient of the actuator disk. */ - su2double GetActDisk_PressJump(string val_marker, unsigned short val_index); + su2double GetActDisk_PressJump(string val_marker, unsigned short val_index) const; /*! * \brief Get the thrust corffient of the actuator disk. */ - su2double GetActDisk_TempJump(string val_marker, unsigned short val_index); + su2double GetActDisk_TempJump(string val_marker, unsigned short val_index) const; /*! * \brief Get the rev / min of the actuator disk. */ - su2double GetActDisk_Omega(string val_marker, unsigned short val_index); + su2double GetActDisk_Omega(string val_marker, unsigned short val_index) const; /*! * \brief Get Actuator Disk Outlet for boundary val_marker (actuator disk inlet). * \return Actuator Disk Outlet from the config information for the marker val_marker. */ - unsigned short GetMarker_CfgFile_ActDiskOutlet(string val_marker); + unsigned short GetMarker_CfgFile_ActDiskOutlet(string val_marker) const; /*! * \brief Get Actuator Disk Outlet for boundary val_marker (actuator disk inlet). * \return Actuator Disk Outlet from the config information for the marker val_marker. */ - unsigned short GetMarker_CfgFile_EngineExhaust(string val_marker); + unsigned short GetMarker_CfgFile_EngineExhaust(string val_marker) const; /*! * \brief Get the internal index for a moving boundary val_marker. * \return Internal index for a moving boundary val_marker. */ - unsigned short GetMarker_Moving(string val_marker); + unsigned short GetMarker_Moving(string val_marker) const; /*! * \brief Get bool if marker is moving. val_marker. * \param[in] val_marker - String of the marker to test. * \return Bool if the marker is a moving boundary val_marker. */ - bool GetMarker_Moving_Bool(string val_marker); + bool GetMarker_Moving_Bool(string val_marker) const; /*! * \brief Get the internal index for a DEFORM_MESH boundary val_marker. * \return Internal index for a DEFORM_MESH boundary val_marker. */ - unsigned short GetMarker_Deform_Mesh(string val_marker); + unsigned short GetMarker_Deform_Mesh(string val_marker) const; /*! * \brief Get the internal index for a Fluid_Load boundary val_marker. * \return Internal index for a Fluid_Load boundary val_marker. */ - unsigned short GetMarker_Fluid_Load(string val_marker); + unsigned short GetMarker_Fluid_Load(string val_marker) const; /*! * \brief Get the name of the surface defined in the geometry file. @@ -6444,28 +6446,28 @@ class CConfig { * \param[in] val_index - Index corresponding to the inlet boundary. * \return The total temperature. */ - su2double GetExhaust_Temperature_Target(string val_index); + su2double GetExhaust_Temperature_Target(string val_index) const; /*! * \brief Get the total temperature at an inlet boundary. * \param[in] val_index - Index corresponding to the inlet boundary. * \return The total temperature. */ - su2double GetInlet_Ttotal(string val_index); + su2double GetInlet_Ttotal(string val_index) const; /*! * \brief Get the temperature at a supersonic inlet boundary. * \param[in] val_index - Index corresponding to the inlet boundary. * \return The inlet density. */ - su2double GetInlet_Temperature(string val_index); + su2double GetInlet_Temperature(string val_index) const; /*! * \brief Get the pressure at a supersonic inlet boundary. * \param[in] val_index - Index corresponding to the inlet boundary. * \return The inlet pressure. */ - su2double GetInlet_Pressure(string val_index); + su2double GetInlet_Pressure(string val_index) const; /*! * \brief Get the velocity vector at a supersonic inlet boundary. @@ -6479,7 +6481,7 @@ class CConfig { * \param[in] val_index - Index corresponding to the inlet boundary. * \return The total pressure. */ - su2double GetInlet_Ptotal(string val_index); + su2double GetInlet_Ptotal(string val_index) const; /*! * \brief Set the total pressure at an inlet boundary. @@ -6493,7 +6495,7 @@ class CConfig { * \param[in] val_index - Index corresponding to the inlet boundary. * \return The total pressure. */ - su2double GetExhaust_Pressure_Target(string val_index); + su2double GetExhaust_Pressure_Target(string val_index) const; /*! * \brief Value of the CFL reduction in LevelSet problems. @@ -6513,7 +6515,7 @@ class CConfig { * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetOutlet_Pressure(string val_index); + su2double GetOutlet_Pressure(string val_index) const; /*! * \brief Set the back pressure (static) at an outlet boundary. @@ -6527,14 +6529,14 @@ class CConfig { * \param[in] val_marker - Index corresponding to the Riemann boundary. * \return The var1 */ - su2double GetRiemann_Var1(string val_marker); + su2double GetRiemann_Var1(string val_marker) const; /*! * \brief Get the var 2 at Riemann boundary. * \param[in] val_marker - Index corresponding to the Riemann boundary. * \return The var2 */ - su2double GetRiemann_Var2(string val_marker); + su2double GetRiemann_Var2(string val_marker) const; /*! * \brief Get the Flowdir at Riemann boundary. @@ -6548,21 +6550,21 @@ class CConfig { * \param[in] val_marker - Index corresponding to the Riemann boundary. * \return Kind data */ - unsigned short GetKind_Data_Riemann(string val_marker); + unsigned short GetKind_Data_Riemann(string val_marker) const; /*! * \brief Get the var 1 for the Giels BC. * \param[in] val_marker - Index corresponding to the Giles BC. * \return The var1 */ - su2double GetGiles_Var1(string val_marker); + su2double GetGiles_Var1(string val_marker) const; /*! * \brief Get the var 2 for the Giles boundary. * \param[in] val_marker - Index corresponding to the Giles BC. * \return The var2 */ - su2double GetGiles_Var2(string val_marker); + su2double GetGiles_Var2(string val_marker) const; /*! * \brief Get the Flowdir for the Giles BC. @@ -6576,7 +6578,7 @@ class CConfig { * \param[in] val_marker - Index corresponding to the Giles BC. * \return Kind data */ - unsigned short GetKind_Data_Giles(string val_marker); + unsigned short GetKind_Data_Giles(string val_marker) const; /*! * \brief Set the var 1 for Giles BC. @@ -6589,20 +6591,20 @@ class CConfig { * \param[in] val_marker - Index corresponding to the Giles BC. * \return The relax factor for the average component */ - su2double GetGiles_RelaxFactorAverage(string val_marker); + su2double GetGiles_RelaxFactorAverage(string val_marker) const; /*! * \brief Get the relax factor for the fourier component for the Giles BC. * \param[in] val_marker - Index corresponding to the Giles BC. * \return The relax factor for the fourier component */ - su2double GetGiles_RelaxFactorFourier(string val_marker); + su2double GetGiles_RelaxFactorFourier(string val_marker) const; /*! * \brief Get the outlet pressure imposed as BC for internal flow. * \return outlet pressure */ - su2double GetPressureOut_BC(); + su2double GetPressureOut_BC() const; /*! * \brief Set the outlet pressure imposed as BC for internal flow. @@ -6614,7 +6616,7 @@ class CConfig { * \brief Get the inlet velocity or pressure imposed for incompressible flow. * \return inlet velocity or pressure */ - su2double GetIncInlet_BC(); + su2double GetIncInlet_BC() const; /*! * \brief Set the inlet velocity or pressure imposed as BC for incompressible flow. @@ -6626,7 +6628,7 @@ class CConfig { * \brief Get the inlet temperature imposed as BC for incompressible flow. * \return inlet temperature */ - su2double GetIncTemperature_BC(); + su2double GetIncTemperature_BC() const; /*! * \brief Set the inlet temperature imposed as BC for incompressible flow. @@ -6638,7 +6640,7 @@ class CConfig { * \brief Get the outlet pressure imposed as BC for incompressible flow. * \return outlet pressure */ - su2double GetIncPressureOut_BC(); + su2double GetIncPressureOut_BC() const; /*! * \brief Set the outlet pressure imposed as BC for incompressible flow. @@ -6650,13 +6652,13 @@ class CConfig { * \brief Get the inlet total pressure imposed as BC for internal flow. * \return inlet total pressure */ - su2double GetTotalPressureIn_BC(); + su2double GetTotalPressureIn_BC() const; /*! * \brief Get the inlet total temperature imposed as BC for internal flow. * \return inlet total temperature */ - su2double GetTotalTemperatureIn_BC(); + su2double GetTotalTemperatureIn_BC() const; /*! * \brief Set the inlet total temperature imposed as BC for internal flow. @@ -6668,28 +6670,28 @@ class CConfig { * \brief Get the inlet flow angle imposed as BC for internal flow. * \return inlet flow angle */ - su2double GetFlowAngleIn_BC(); + su2double GetFlowAngleIn_BC() const; /*! * \brief Get the wall temperature (static) at an isothermal boundary. * \param[in] val_index - Index corresponding to the isothermal boundary. * \return The wall temperature. */ - su2double GetIsothermal_Temperature(string val_index); + su2double GetIsothermal_Temperature(string val_index) const; /*! * \brief Get the wall heat flux on a constant heat flux boundary. * \param[in] val_index - Index corresponding to the constant heat flux boundary. * \return The heat flux. */ - su2double GetWall_HeatFlux(string val_index); + su2double GetWall_HeatFlux(string val_index) const; /*! * \brief Get the wall function treatment for the given boundary marker. * \param[in] val_marker - String of the viscous wall marker. * \return The type of wall function treatment. */ - unsigned short GetWallFunction_Treatment(string val_marker); + unsigned short GetWallFunction_Treatment(string val_marker) const; /*! * \brief Get the additional integer info for the wall function treatment @@ -6712,35 +6714,35 @@ class CConfig { * \param[in] val_index - Index corresponding to the engine inflow boundary. * \return Target (pressure, massflow, etc) . */ - su2double GetEngineInflow_Target(string val_marker); + su2double GetEngineInflow_Target(string val_marker) const; /*! * \brief Get the fan face Mach number at an engine inflow boundary. * \param[in] val_marker - Name of the boundary. * \return The fan face Mach number. */ - su2double GetInflow_Mach(string val_marker); + su2double GetInflow_Mach(string val_marker) const; /*! * \brief Get the back pressure (static) at an engine inflow boundary. * \param[in] val_marker - Name of the boundary. * \return The engine inflow pressure. */ - su2double GetInflow_Pressure(string val_marker); + su2double GetInflow_Pressure(string val_marker) const; /*! * \brief Get the mass flow rate at an engine inflow boundary. * \param[in] val_marker - Name of the boundary. * \return The engine mass flow rate. */ - su2double GetInflow_MassFlow(string val_marker); + su2double GetInflow_MassFlow(string val_marker) const; /*! * \brief Get the percentage of reverse flow at an engine inflow boundary. * \param[in] val_marker - Name of the boundary. * \return The percentage of reverse flow. */ - su2double GetInflow_ReverseMassFlow(string val_marker); + su2double GetInflow_ReverseMassFlow(string val_marker) const; /*! * \brief Get the percentage of reverse flow at an engine inflow boundary. @@ -6754,98 +6756,98 @@ class CConfig { * \param[in] val_marker - Name of the boundary. * \return The total pressure. */ - su2double GetInflow_TotalPressure(string val_marker); + su2double GetInflow_TotalPressure(string val_marker) const; /*! * \brief Get the temperature (static) at an engine inflow boundary. * \param[in] val_marker - Name of the boundary. * \return The engine inflow temperature. */ - su2double GetInflow_Temperature(string val_marker); + su2double GetInflow_Temperature(string val_marker) const; /*! * \brief Get the total temperature at an engine inflow boundary. * \param[in] val_marker - Name of the boundary. * \return The engine inflow total temperature. */ - su2double GetInflow_TotalTemperature(string val_marker); + su2double GetInflow_TotalTemperature(string val_marker) const; /*! * \brief Get the ram drag at an engine inflow boundary. * \param[in] val_marker - Name of the boundary. * \return The engine inflow ram drag. */ - su2double GetInflow_RamDrag(string val_marker); + su2double GetInflow_RamDrag(string val_marker) const; /*! * \brief Get the force balance at an engine inflow boundary. * \param[in] val_marker - Name of the boundary. * \return The engine inflow force balance. */ - su2double GetInflow_Force(string val_marker); + su2double GetInflow_Force(string val_marker) const; /*! * \brief Get the power at an engine inflow boundary. * \param[in] val_marker - Name of the boundary. * \return The engine inflow power. */ - su2double GetInflow_Power(string val_marker); + su2double GetInflow_Power(string val_marker) const; /*! * \brief Get the back pressure (static) at an engine exhaust boundary. * \param[in] val_marker - Name of the boundary. * \return The engine exhaust pressure. */ - su2double GetExhaust_Pressure(string val_marker); + su2double GetExhaust_Pressure(string val_marker) const; /*! * \brief Get the temperature (static) at an engine exhaust boundary. * \param[in] val_marker - Name of the boundary. * \return The engine exhaust temperature. */ - su2double GetExhaust_Temperature(string val_marker); + su2double GetExhaust_Temperature(string val_marker) const; /*! * \brief Get the massflow at an engine exhaust boundary. * \param[in] val_marker - Name of the boundary. * \return The engine exhaust massflow. */ - su2double GetExhaust_MassFlow(string val_marker); + su2double GetExhaust_MassFlow(string val_marker) const; /*! * \brief Get the total pressure at an engine exhaust boundary. * \param[in] val_marker - Name of the boundary. * \return The engine exhaust total pressure. */ - su2double GetExhaust_TotalPressure(string val_marker); + su2double GetExhaust_TotalPressure(string val_marker) const; /*! * \brief Get the total temperature at an engine exhaust boundary. * \param[in] val_marker - Name of the boundary. * \return The total temperature. */ - su2double GetExhaust_TotalTemperature(string val_marker); + su2double GetExhaust_TotalTemperature(string val_marker) const; /*! * \brief Get the gross thrust at an engine exhaust boundary. * \param[in] val_marker - Name of the boundary. * \return Gross thrust. */ - su2double GetExhaust_GrossThrust(string val_marker); + su2double GetExhaust_GrossThrust(string val_marker) const; /*! * \brief Get the force balance at an engine exhaust boundary. * \param[in] val_marker - Name of the boundary. * \return Force balance. */ - su2double GetExhaust_Force(string val_marker); + su2double GetExhaust_Force(string val_marker) const; /*! * \brief Get the power at an engine exhaust boundary. * \param[in] val_marker - Name of the boundary. * \return Power. */ - su2double GetExhaust_Power(string val_marker); + su2double GetExhaust_Power(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. @@ -7077,14 +7079,14 @@ class CConfig { * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskInlet_Temperature(string val_marker); + su2double GetActDiskInlet_Temperature(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskInlet_TotalTemperature(string val_marker); + su2double GetActDiskInlet_TotalTemperature(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. @@ -7105,21 +7107,21 @@ class CConfig { * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskOutlet_Temperature(string val_marker); + su2double GetActDiskOutlet_Temperature(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskOutlet_TotalTemperature(string val_marker); + su2double GetActDiskOutlet_TotalTemperature(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskInlet_MassFlow(string val_marker); + su2double GetActDiskInlet_MassFlow(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. @@ -7133,7 +7135,7 @@ class CConfig { * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskOutlet_MassFlow(string val_marker); + su2double GetActDiskOutlet_MassFlow(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. @@ -7147,14 +7149,14 @@ class CConfig { * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskInlet_Pressure(string val_marker); + su2double GetActDiskInlet_Pressure(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskInlet_TotalPressure(string val_marker); + su2double GetActDiskInlet_TotalPressure(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. @@ -7245,21 +7247,21 @@ class CConfig { * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskInlet_RamDrag(string val_marker); + su2double GetActDiskInlet_RamDrag(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskInlet_Force(string val_marker); + su2double GetActDiskInlet_Force(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskInlet_Power(string val_marker); + su2double GetActDiskInlet_Power(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. @@ -7315,7 +7317,7 @@ class CConfig { * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetOutlet_MassFlow(string val_marker); + su2double GetOutlet_MassFlow(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. @@ -7329,7 +7331,7 @@ class CConfig { * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetOutlet_Density(string val_marker); + su2double GetOutlet_Density(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. @@ -7343,7 +7345,7 @@ class CConfig { * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetOutlet_Area(string val_marker); + su2double GetOutlet_Area(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. @@ -7749,35 +7751,35 @@ class CConfig { * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskOutlet_Pressure(string val_marker); + su2double GetActDiskOutlet_Pressure(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskOutlet_TotalPressure(string val_marker); + su2double GetActDiskOutlet_TotalPressure(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskOutlet_GrossThrust(string val_marker); + su2double GetActDiskOutlet_GrossThrust(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskOutlet_Force(string val_marker); + su2double GetActDiskOutlet_Force(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. * \param[in] val_index - Index corresponding to the outlet boundary. * \return The outlet pressure. */ - su2double GetActDiskOutlet_Power(string val_marker); + su2double GetActDiskOutlet_Power(string val_marker) const; /*! * \brief Get the back pressure (static) at an outlet boundary. @@ -7819,91 +7821,91 @@ class CConfig { * \param[in] val_index - Index corresponding to the displacement boundary. * \return The displacement value. */ - su2double GetDispl_Value(string val_index); + su2double GetDispl_Value(string val_index) const; /*! * \brief Get the force value at an load boundary. * \param[in] val_index - Index corresponding to the load boundary. * \return The load value. */ - su2double GetLoad_Value(string val_index); + su2double GetLoad_Value(string val_index) const; /*! * \brief Get the constant value at a damper boundary. * \param[in] val_index - Index corresponding to the load boundary. * \return The damper constant. */ - su2double GetDamper_Constant(string val_index); + su2double GetDamper_Constant(string val_index) const; /*! * \brief Get the force value at a load boundary defined in cartesian coordinates. * \param[in] val_index - Index corresponding to the load boundary. * \return The load value. */ - su2double GetLoad_Dir_Value(string val_index); + su2double GetLoad_Dir_Value(string val_index) const; /*! * \brief Get the force multiplier at a load boundary in cartesian coordinates. * \param[in] val_index - Index corresponding to the load boundary. * \return The load multiplier. */ - su2double GetLoad_Dir_Multiplier(string val_index); + su2double GetLoad_Dir_Multiplier(string val_index) const; /*! * \brief Get the force value at a load boundary defined in cartesian coordinates. * \param[in] val_index - Index corresponding to the load boundary. * \return The load value. */ - su2double GetDisp_Dir_Value(string val_index); + su2double GetDisp_Dir_Value(string val_index) const; /*! * \brief Get the force multiplier at a load boundary in cartesian coordinates. * \param[in] val_index - Index corresponding to the load boundary. * \return The load multiplier. */ - su2double GetDisp_Dir_Multiplier(string val_index); + su2double GetDisp_Dir_Multiplier(string val_index) const; /*! * \brief Get the force direction at a loaded boundary in cartesian coordinates. * \param[in] val_index - Index corresponding to the load boundary. * \return The load direction. */ - su2double* GetLoad_Dir(string val_index); + const su2double* GetLoad_Dir(string val_index) const; /*! * \brief Get the force direction at a loaded boundary in cartesian coordinates. * \param[in] val_index - Index corresponding to the load boundary. * \return The load direction. */ - su2double* GetDisp_Dir(string val_index); + const su2double* GetDisp_Dir(string val_index) const; /*! * \brief Get the amplitude of the sine-wave at a load boundary defined in cartesian coordinates. * \param[in] val_index - Index corresponding to the load boundary. * \return The load value. */ - su2double GetLoad_Sine_Amplitude(string val_index); + su2double GetLoad_Sine_Amplitude(string val_index) const; /*! * \brief Get the frequency of the sine-wave at a load boundary in cartesian coordinates. * \param[in] val_index - Index corresponding to the load boundary. * \return The load frequency. */ - su2double GetLoad_Sine_Frequency(string val_index); + su2double GetLoad_Sine_Frequency(string val_index) const; /*! * \brief Get the force direction at a sine-wave loaded boundary in cartesian coordinates. * \param[in] val_index - Index corresponding to the load boundary. * \return The load direction. */ - su2double* GetLoad_Sine_Dir(string val_index); + const su2double* GetLoad_Sine_Dir(string val_index) const; /*! * \brief Get the force value at an load boundary. * \param[in] val_index - Index corresponding to the load boundary. * \return The load value. */ - su2double GetFlowLoad_Value(string val_index); + su2double GetFlowLoad_Value(string val_index) const; /*! * \brief Cyclic pitch amplitude for rotor blades. diff --git a/Common/include/grid_movement_structure.hpp b/Common/include/grid_movement_structure.hpp index 5b936fd14eb2..b1e9a51d74ea 100644 --- a/Common/include/grid_movement_structure.hpp +++ b/Common/include/grid_movement_structure.hpp @@ -1394,46 +1394,6 @@ class CSurfaceMovement : public CGridMovement { */ void Moving_Walls(CGeometry *geometry, CConfig *config, unsigned short iZone, unsigned long iter); - /*! - * \brief Computes the displacement of a translating surface for a dynamic mesh simulation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current physical time iteration. - * \param[in] iZone - Zone number in the mesh. - */ - void Surface_Translating(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone); - - /*! - * \brief Computes the displacement of a plunging surface for a dynamic mesh simulation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current physical time iteration. - * \param[in] iZone - Zone number in the mesh. - */ - void Surface_Plunging(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone); - - /*! - * \brief Computes the displacement of a pitching surface for a dynamic mesh simulation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current physical time iteration. - * \param[in] iZone - Zone number in the mesh. - */ - void Surface_Pitching(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone); - - /*! - * \brief Computes the displacement of a rotating surface for a dynamic mesh simulation. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current physical time iteration. - * \param[in] iZone - Zone number in the mesh. - */ - void Surface_Rotating(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone); - /*! * \brief Computes the displacement of a rotating surface for a dynamic mesh simulation. * \param[in] geometry - Geometrical definition of the problem. diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index f12f2fbccd70..f8129011feed 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -4897,6 +4897,9 @@ void CConfig::SetPostprocessing(unsigned short val_software, unsigned short val_ /*--- 0 in the config file means "disable" which can be done using a very large group. ---*/ if (edgeColorGroupSize==0) edgeColorGroupSize = 1<<30; + /*--- Specifying a deforming surface requires a mesh deformation solver. ---*/ + if (GetSurface_Movement(DEFORMING)) Deform_Mesh = true; + } void CConfig::SetMarkers(unsigned short val_software) { @@ -8201,7 +8204,7 @@ su2double* CConfig::GetPeriodicTranslation(string val_marker) { return Periodic_Translation[iMarker_PerBound]; } -unsigned short CConfig::GetMarker_Periodic_Donor(string val_marker) { +unsigned short CConfig::GetMarker_Periodic_Donor(string val_marker) const { unsigned short iMarker_PerBound, jMarker_PerBound, kMarker_All; /*--- Find the marker for this periodic boundary. ---*/ @@ -8219,7 +8222,7 @@ unsigned short CConfig::GetMarker_Periodic_Donor(string val_marker) { return kMarker_All; } -su2double CConfig::GetActDisk_NetThrust(string val_marker) { +su2double CConfig::GetActDisk_NetThrust(string val_marker) const { unsigned short iMarker_ActDisk; for (iMarker_ActDisk = 0; iMarker_ActDisk < nMarker_ActDiskInlet; iMarker_ActDisk++) if ((Marker_ActDiskInlet[iMarker_ActDisk] == val_marker) || @@ -8227,7 +8230,7 @@ su2double CConfig::GetActDisk_NetThrust(string val_marker) { return ActDisk_NetThrust[iMarker_ActDisk]; } -su2double CConfig::GetActDisk_Power(string val_marker) { +su2double CConfig::GetActDisk_Power(string val_marker) const { unsigned short iMarker_ActDisk; for (iMarker_ActDisk = 0; iMarker_ActDisk < nMarker_ActDiskInlet; iMarker_ActDisk++) if ((Marker_ActDiskInlet[iMarker_ActDisk] == val_marker) || @@ -8235,7 +8238,7 @@ su2double CConfig::GetActDisk_Power(string val_marker) { return ActDisk_Power[iMarker_ActDisk]; } -su2double CConfig::GetActDisk_MassFlow(string val_marker) { +su2double CConfig::GetActDisk_MassFlow(string val_marker) const { unsigned short iMarker_ActDisk; for (iMarker_ActDisk = 0; iMarker_ActDisk < nMarker_ActDiskInlet; iMarker_ActDisk++) if ((Marker_ActDiskInlet[iMarker_ActDisk] == val_marker) || @@ -8243,7 +8246,7 @@ su2double CConfig::GetActDisk_MassFlow(string val_marker) { return ActDisk_MassFlow[iMarker_ActDisk]; } -su2double CConfig::GetActDisk_Mach(string val_marker) { +su2double CConfig::GetActDisk_Mach(string val_marker) const { unsigned short iMarker_ActDisk; for (iMarker_ActDisk = 0; iMarker_ActDisk < nMarker_ActDiskInlet; iMarker_ActDisk++) if ((Marker_ActDiskInlet[iMarker_ActDisk] == val_marker) || @@ -8251,7 +8254,7 @@ su2double CConfig::GetActDisk_Mach(string val_marker) { return ActDisk_Mach[iMarker_ActDisk]; } -su2double CConfig::GetActDisk_Force(string val_marker) { +su2double CConfig::GetActDisk_Force(string val_marker) const { unsigned short iMarker_ActDisk; for (iMarker_ActDisk = 0; iMarker_ActDisk < nMarker_ActDiskInlet; iMarker_ActDisk++) if ((Marker_ActDiskInlet[iMarker_ActDisk] == val_marker) || @@ -8259,7 +8262,7 @@ su2double CConfig::GetActDisk_Force(string val_marker) { return ActDisk_Force[iMarker_ActDisk]; } -su2double CConfig::GetActDisk_BCThrust(string val_marker) { +su2double CConfig::GetActDisk_BCThrust(string val_marker) const { unsigned short iMarker_ActDisk; for (iMarker_ActDisk = 0; iMarker_ActDisk < nMarker_ActDiskInlet; iMarker_ActDisk++) if ((Marker_ActDiskInlet[iMarker_ActDisk] == val_marker) || @@ -8267,7 +8270,7 @@ su2double CConfig::GetActDisk_BCThrust(string val_marker) { return ActDisk_BCThrust[iMarker_ActDisk]; } -su2double CConfig::GetActDisk_BCThrust_Old(string val_marker) { +su2double CConfig::GetActDisk_BCThrust_Old(string val_marker) const { unsigned short iMarker_ActDisk; for (iMarker_ActDisk = 0; iMarker_ActDisk < nMarker_ActDiskInlet; iMarker_ActDisk++) if ((Marker_ActDiskInlet[iMarker_ActDisk] == val_marker) || @@ -8291,7 +8294,7 @@ void CConfig::SetActDisk_BCThrust_Old(string val_marker, su2double val_actdisk_b ActDisk_BCThrust_Old[iMarker_ActDisk] = val_actdisk_bcthrust_old; } -su2double CConfig::GetActDisk_Area(string val_marker) { +su2double CConfig::GetActDisk_Area(string val_marker) const { unsigned short iMarker_ActDisk; for (iMarker_ActDisk = 0; iMarker_ActDisk < nMarker_ActDiskInlet; iMarker_ActDisk++) if ((Marker_ActDiskInlet[iMarker_ActDisk] == val_marker) || @@ -8299,7 +8302,7 @@ su2double CConfig::GetActDisk_Area(string val_marker) { return ActDisk_Area[iMarker_ActDisk]; } -su2double CConfig::GetActDisk_ReverseMassFlow(string val_marker) { +su2double CConfig::GetActDisk_ReverseMassFlow(string val_marker) const { unsigned short iMarker_ActDisk; for (iMarker_ActDisk = 0; iMarker_ActDisk < nMarker_ActDiskInlet; iMarker_ActDisk++) if ((Marker_ActDiskInlet[iMarker_ActDisk] == val_marker) || @@ -8307,7 +8310,7 @@ su2double CConfig::GetActDisk_ReverseMassFlow(string val_marker) { return ActDisk_ReverseMassFlow[iMarker_ActDisk]; } -su2double CConfig::GetActDisk_PressJump(string val_marker, unsigned short val_value) { +su2double CConfig::GetActDisk_PressJump(string val_marker, unsigned short val_value) const { unsigned short iMarker_ActDisk; for (iMarker_ActDisk = 0; iMarker_ActDisk < nMarker_ActDiskInlet; iMarker_ActDisk++) if ((Marker_ActDiskInlet[iMarker_ActDisk] == val_marker) || @@ -8315,7 +8318,7 @@ su2double CConfig::GetActDisk_PressJump(string val_marker, unsigned short val_va return ActDisk_PressJump[iMarker_ActDisk][val_value]; } -su2double CConfig::GetActDisk_TempJump(string val_marker, unsigned short val_value) { +su2double CConfig::GetActDisk_TempJump(string val_marker, unsigned short val_value) const { unsigned short iMarker_ActDisk; for (iMarker_ActDisk = 0; iMarker_ActDisk < nMarker_ActDiskInlet; iMarker_ActDisk++) if ((Marker_ActDiskInlet[iMarker_ActDisk] == val_marker) || @@ -8323,7 +8326,7 @@ su2double CConfig::GetActDisk_TempJump(string val_marker, unsigned short val_val return ActDisk_TempJump[iMarker_ActDisk][val_value];; } -su2double CConfig::GetActDisk_Omega(string val_marker, unsigned short val_value) { +su2double CConfig::GetActDisk_Omega(string val_marker, unsigned short val_value) const { unsigned short iMarker_ActDisk; for (iMarker_ActDisk = 0; iMarker_ActDisk < nMarker_ActDiskInlet; iMarker_ActDisk++) if ((Marker_ActDiskInlet[iMarker_ActDisk] == val_marker) || @@ -8331,28 +8334,28 @@ su2double CConfig::GetActDisk_Omega(string val_marker, unsigned short val_value) return ActDisk_Omega[iMarker_ActDisk][val_value];; } -su2double CConfig::GetOutlet_MassFlow(string val_marker) { +su2double CConfig::GetOutlet_MassFlow(string val_marker) const { unsigned short iMarker_Outlet; for (iMarker_Outlet = 0; iMarker_Outlet < nMarker_Outlet; iMarker_Outlet++) if ((Marker_Outlet[iMarker_Outlet] == val_marker)) break; return Outlet_MassFlow[iMarker_Outlet]; } -su2double CConfig::GetOutlet_Density(string val_marker) { +su2double CConfig::GetOutlet_Density(string val_marker) const { unsigned short iMarker_Outlet; for (iMarker_Outlet = 0; iMarker_Outlet < nMarker_Outlet; iMarker_Outlet++) if ((Marker_Outlet[iMarker_Outlet] == val_marker)) break; return Outlet_Density[iMarker_Outlet]; } -su2double CConfig::GetOutlet_Area(string val_marker) { +su2double CConfig::GetOutlet_Area(string val_marker) const { unsigned short iMarker_Outlet; for (iMarker_Outlet = 0; iMarker_Outlet < nMarker_Outlet; iMarker_Outlet++) if ((Marker_Outlet[iMarker_Outlet] == val_marker)) break; return Outlet_Area[iMarker_Outlet]; } -unsigned short CConfig::GetMarker_CfgFile_ActDiskOutlet(string val_marker) { +unsigned short CConfig::GetMarker_CfgFile_ActDiskOutlet(string val_marker) const { unsigned short iMarker_ActDisk, kMarker_All; /*--- Find the marker for this actuator disk inlet. ---*/ @@ -8368,7 +8371,7 @@ unsigned short CConfig::GetMarker_CfgFile_ActDiskOutlet(string val_marker) { return kMarker_All; } -unsigned short CConfig::GetMarker_CfgFile_EngineExhaust(string val_marker) { +unsigned short CConfig::GetMarker_CfgFile_EngineExhaust(string val_marker) const { unsigned short iMarker_Engine, kMarker_All; /*--- Find the marker for this engine inflow. ---*/ @@ -8384,11 +8387,10 @@ unsigned short CConfig::GetMarker_CfgFile_EngineExhaust(string val_marker) { return kMarker_All; } -bool CConfig::GetVolumetric_Movement(){ +bool CConfig::GetVolumetric_Movement() const { bool volumetric_movement = false; if (GetSurface_Movement(AEROELASTIC) || - GetSurface_Movement(DEFORMING) || GetSurface_Movement(AEROELASTIC_RIGID_MOTION)|| GetSurface_Movement(FLUID_STRUCTURE) || GetSurface_Movement(EXTERNAL) || @@ -8412,7 +8414,7 @@ bool CConfig::GetSurface_Movement(unsigned short kind_movement) const { return false; } -unsigned short CConfig::GetMarker_Moving(string val_marker) { +unsigned short CConfig::GetMarker_Moving(string val_marker) const { unsigned short iMarker_Moving; /*--- Find the marker for this moving boundary. ---*/ @@ -8422,7 +8424,7 @@ unsigned short CConfig::GetMarker_Moving(string val_marker) { return iMarker_Moving; } -bool CConfig::GetMarker_Moving_Bool(string val_marker) { +bool CConfig::GetMarker_Moving_Bool(string val_marker) const { unsigned short iMarker_Moving; /*--- Find the marker for this moving boundary, if it exists. ---*/ @@ -8432,7 +8434,7 @@ bool CConfig::GetMarker_Moving_Bool(string val_marker) { return false; } -unsigned short CConfig::GetMarker_Deform_Mesh(string val_marker) { +unsigned short CConfig::GetMarker_Deform_Mesh(string val_marker) const { unsigned short iMarker_Deform_Mesh; /*--- Find the marker for this interface boundary. ---*/ @@ -8442,7 +8444,7 @@ unsigned short CConfig::GetMarker_Deform_Mesh(string val_marker) { return iMarker_Deform_Mesh; } -unsigned short CConfig::GetMarker_Fluid_Load(string val_marker) { +unsigned short CConfig::GetMarker_Fluid_Load(string val_marker) const { unsigned short iMarker_Fluid_Load; /*--- Find the marker for this interface boundary. ---*/ @@ -8452,42 +8454,42 @@ unsigned short CConfig::GetMarker_Fluid_Load(string val_marker) { return iMarker_Fluid_Load; } -su2double CConfig::GetExhaust_Temperature_Target(string val_marker) { +su2double CConfig::GetExhaust_Temperature_Target(string val_marker) const { unsigned short iMarker_EngineExhaust; for (iMarker_EngineExhaust = 0; iMarker_EngineExhaust < nMarker_EngineExhaust; iMarker_EngineExhaust++) if (Marker_EngineExhaust[iMarker_EngineExhaust] == val_marker) break; return Exhaust_Temperature_Target[iMarker_EngineExhaust]; } -su2double CConfig::GetExhaust_Pressure_Target(string val_marker) { +su2double CConfig::GetExhaust_Pressure_Target(string val_marker) const { unsigned short iMarker_EngineExhaust; for (iMarker_EngineExhaust = 0; iMarker_EngineExhaust < nMarker_EngineExhaust; iMarker_EngineExhaust++) if (Marker_EngineExhaust[iMarker_EngineExhaust] == val_marker) break; return Exhaust_Pressure_Target[iMarker_EngineExhaust]; } -unsigned short CConfig::GetKind_Inc_Inlet(string val_marker) { +unsigned short CConfig::GetKind_Inc_Inlet(string val_marker) const { unsigned short iMarker_Inlet; for (iMarker_Inlet = 0; iMarker_Inlet < nMarker_Inlet; iMarker_Inlet++) if (Marker_Inlet[iMarker_Inlet] == val_marker) break; return Kind_Inc_Inlet[iMarker_Inlet]; } -unsigned short CConfig::GetKind_Inc_Outlet(string val_marker) { +unsigned short CConfig::GetKind_Inc_Outlet(string val_marker) const { unsigned short iMarker_Outlet; for (iMarker_Outlet = 0; iMarker_Outlet < nMarker_Outlet; iMarker_Outlet++) if (Marker_Outlet[iMarker_Outlet] == val_marker) break; return Kind_Inc_Outlet[iMarker_Outlet]; } -su2double CConfig::GetInlet_Ttotal(string val_marker) { +su2double CConfig::GetInlet_Ttotal(string val_marker) const { unsigned short iMarker_Inlet; for (iMarker_Inlet = 0; iMarker_Inlet < nMarker_Inlet; iMarker_Inlet++) if (Marker_Inlet[iMarker_Inlet] == val_marker) break; return Inlet_Ttotal[iMarker_Inlet]; } -su2double CConfig::GetInlet_Ptotal(string val_marker) { +su2double CConfig::GetInlet_Ptotal(string val_marker) const { unsigned short iMarker_Inlet; for (iMarker_Inlet = 0; iMarker_Inlet < nMarker_Inlet; iMarker_Inlet++) if (Marker_Inlet[iMarker_Inlet] == val_marker) break; @@ -8508,14 +8510,14 @@ su2double* CConfig::GetInlet_FlowDir(string val_marker) { return Inlet_FlowDir[iMarker_Inlet]; } -su2double CConfig::GetInlet_Temperature(string val_marker) { +su2double CConfig::GetInlet_Temperature(string val_marker) const { unsigned short iMarker_Supersonic_Inlet; for (iMarker_Supersonic_Inlet = 0; iMarker_Supersonic_Inlet < nMarker_Supersonic_Inlet; iMarker_Supersonic_Inlet++) if (Marker_Supersonic_Inlet[iMarker_Supersonic_Inlet] == val_marker) break; return Inlet_Temperature[iMarker_Supersonic_Inlet]; } -su2double CConfig::GetInlet_Pressure(string val_marker) { +su2double CConfig::GetInlet_Pressure(string val_marker) const { unsigned short iMarker_Supersonic_Inlet; for (iMarker_Supersonic_Inlet = 0; iMarker_Supersonic_Inlet < nMarker_Supersonic_Inlet; iMarker_Supersonic_Inlet++) if (Marker_Supersonic_Inlet[iMarker_Supersonic_Inlet] == val_marker) break; @@ -8529,7 +8531,7 @@ su2double* CConfig::GetInlet_Velocity(string val_marker) { return Inlet_Velocity[iMarker_Supersonic_Inlet]; } -su2double CConfig::GetOutlet_Pressure(string val_marker) { +su2double CConfig::GetOutlet_Pressure(string val_marker) const { unsigned short iMarker_Outlet; for (iMarker_Outlet = 0; iMarker_Outlet < nMarker_Outlet; iMarker_Outlet++) if (Marker_Outlet[iMarker_Outlet] == val_marker) break; @@ -8543,14 +8545,14 @@ void CConfig::SetOutlet_Pressure(su2double val_pressure, string val_marker) { Outlet_Pressure[iMarker_Outlet] = val_pressure; } -su2double CConfig::GetRiemann_Var1(string val_marker) { +su2double CConfig::GetRiemann_Var1(string val_marker) const { unsigned short iMarker_Riemann; for (iMarker_Riemann = 0; iMarker_Riemann < nMarker_Riemann; iMarker_Riemann++) if (Marker_Riemann[iMarker_Riemann] == val_marker) break; return Riemann_Var1[iMarker_Riemann]; } -su2double CConfig::GetRiemann_Var2(string val_marker) { +su2double CConfig::GetRiemann_Var2(string val_marker) const { unsigned short iMarker_Riemann; for (iMarker_Riemann = 0; iMarker_Riemann < nMarker_Riemann; iMarker_Riemann++) if (Marker_Riemann[iMarker_Riemann] == val_marker) break; @@ -8564,7 +8566,7 @@ su2double* CConfig::GetRiemann_FlowDir(string val_marker) { return Riemann_FlowDir[iMarker_Riemann]; } -unsigned short CConfig::GetKind_Data_Riemann(string val_marker) { +unsigned short CConfig::GetKind_Data_Riemann(string val_marker) const { unsigned short iMarker_Riemann; for (iMarker_Riemann = 0; iMarker_Riemann < nMarker_Riemann; iMarker_Riemann++) if (Marker_Riemann[iMarker_Riemann] == val_marker) break; @@ -8572,7 +8574,7 @@ unsigned short CConfig::GetKind_Data_Riemann(string val_marker) { } -su2double CConfig::GetGiles_Var1(string val_marker) { +su2double CConfig::GetGiles_Var1(string val_marker) const { unsigned short iMarker_Giles; for (iMarker_Giles = 0; iMarker_Giles < nMarker_Giles; iMarker_Giles++) if (Marker_Giles[iMarker_Giles] == val_marker) break; @@ -8586,21 +8588,21 @@ void CConfig::SetGiles_Var1(su2double newVar1, string val_marker) { Giles_Var1[iMarker_Giles] = newVar1; } -su2double CConfig::GetGiles_Var2(string val_marker) { +su2double CConfig::GetGiles_Var2(string val_marker) const { unsigned short iMarker_Giles; for (iMarker_Giles = 0; iMarker_Giles < nMarker_Giles; iMarker_Giles++) if (Marker_Giles[iMarker_Giles] == val_marker) break; return Giles_Var2[iMarker_Giles]; } -su2double CConfig::GetGiles_RelaxFactorAverage(string val_marker) { +su2double CConfig::GetGiles_RelaxFactorAverage(string val_marker) const { unsigned short iMarker_Giles; for (iMarker_Giles = 0; iMarker_Giles < nMarker_Giles; iMarker_Giles++) if (Marker_Giles[iMarker_Giles] == val_marker) break; return RelaxFactorAverage[iMarker_Giles]; } -su2double CConfig::GetGiles_RelaxFactorFourier(string val_marker) { +su2double CConfig::GetGiles_RelaxFactorFourier(string val_marker) const { unsigned short iMarker_Giles; for (iMarker_Giles = 0; iMarker_Giles < nMarker_Giles; iMarker_Giles++) if (Marker_Giles[iMarker_Giles] == val_marker) break; @@ -8614,15 +8616,14 @@ su2double* CConfig::GetGiles_FlowDir(string val_marker) { return Giles_FlowDir[iMarker_Giles]; } -unsigned short CConfig::GetKind_Data_Giles(string val_marker) { +unsigned short CConfig::GetKind_Data_Giles(string val_marker) const { unsigned short iMarker_Giles; for (iMarker_Giles = 0; iMarker_Giles < nMarker_Giles; iMarker_Giles++) if (Marker_Giles[iMarker_Giles] == val_marker) break; return Kind_Data_Giles[iMarker_Giles]; } - -su2double CConfig::GetPressureOut_BC() { +su2double CConfig::GetPressureOut_BC() const { unsigned short iMarker_BC; su2double pres_out = 0.0; for (iMarker_BC = 0; iMarker_BC < nMarker_Giles; iMarker_BC++){ @@ -8638,7 +8639,6 @@ su2double CConfig::GetPressureOut_BC() { return pres_out/Pressure_Ref; } - void CConfig::SetPressureOut_BC(su2double val_press) { unsigned short iMarker_BC; for (iMarker_BC = 0; iMarker_BC < nMarker_Giles; iMarker_BC++){ @@ -8653,7 +8653,7 @@ void CConfig::SetPressureOut_BC(su2double val_press) { } } -su2double CConfig::GetTotalPressureIn_BC() { +su2double CConfig::GetTotalPressureIn_BC() const { unsigned short iMarker_BC; su2double tot_pres_in = 0.0; for (iMarker_BC = 0; iMarker_BC < nMarker_Giles; iMarker_BC++){ @@ -8672,7 +8672,7 @@ su2double CConfig::GetTotalPressureIn_BC() { return tot_pres_in/Pressure_Ref; } -su2double CConfig::GetTotalTemperatureIn_BC() { +su2double CConfig::GetTotalTemperatureIn_BC() const { unsigned short iMarker_BC; su2double tot_temp_in = 0.0; for (iMarker_BC = 0; iMarker_BC < nMarker_Giles; iMarker_BC++){ @@ -8710,7 +8710,7 @@ void CConfig::SetTotalTemperatureIn_BC(su2double val_temp) { } } -su2double CConfig::GetFlowAngleIn_BC() { +su2double CConfig::GetFlowAngleIn_BC() const { unsigned short iMarker_BC; su2double alpha_in = 0.0; for (iMarker_BC = 0; iMarker_BC < nMarker_Giles; iMarker_BC++){ @@ -8731,7 +8731,7 @@ su2double CConfig::GetFlowAngleIn_BC() { return alpha_in; } -su2double CConfig::GetIncInlet_BC() { +su2double CConfig::GetIncInlet_BC() const { su2double val_out = 0.0; @@ -8753,29 +8753,24 @@ void CConfig::SetIncInlet_BC(su2double val_in) { else if (Kind_Inc_Inlet[0] == PRESSURE_INLET) Inlet_Ptotal[0] = val_in*Pressure_Ref; } - } -su2double CConfig::GetIncTemperature_BC() { +su2double CConfig::GetIncTemperature_BC() const { su2double val_out = 0.0; - if (nMarker_Inlet > 0) { - val_out = Inlet_Ttotal[0]/Temperature_Ref; - } + if (nMarker_Inlet > 0) + val_out = Inlet_Ttotal[0]/Temperature_Ref; return val_out; } void CConfig::SetIncTemperature_BC(su2double val_temperature) { - - if (nMarker_Inlet > 0) { - Inlet_Ttotal[0] = val_temperature*Temperature_Ref; - } - + if (nMarker_Inlet > 0) + Inlet_Ttotal[0] = val_temperature*Temperature_Ref; } -su2double CConfig::GetIncPressureOut_BC() { +su2double CConfig::GetIncPressureOut_BC() const { su2double pressure_out = 0.0; @@ -8798,7 +8793,7 @@ void CConfig::SetIncPressureOut_BC(su2double val_pressure) { } -su2double CConfig::GetIsothermal_Temperature(string val_marker) { +su2double CConfig::GetIsothermal_Temperature(string val_marker) const { unsigned short iMarker_Isothermal = 0; @@ -8810,7 +8805,7 @@ su2double CConfig::GetIsothermal_Temperature(string val_marker) { return Isothermal_Temperature[iMarker_Isothermal]; } -su2double CConfig::GetWall_HeatFlux(string val_marker) { +su2double CConfig::GetWall_HeatFlux(string val_marker) const { unsigned short iMarker_HeatFlux = 0; if (nMarker_HeatFlux > 0) { @@ -8821,7 +8816,7 @@ su2double CConfig::GetWall_HeatFlux(string val_marker) { return Heat_Flux[iMarker_HeatFlux]; } -unsigned short CConfig::GetWallFunction_Treatment(string val_marker) { +unsigned short CConfig::GetWallFunction_Treatment(string val_marker) const { unsigned short WallFunction = NO_WALL_FUNCTION; for(unsigned short iMarker=0; iMarkerGetDelta_UnstTimeND(); - - /*--- Compute delta time based on physical time step ---*/ - time_new = static_cast(iter)*deltaT; - if (iter == 0) { - time_old = time_new; - } else { - time_old = static_cast(iter-1)*deltaT; - } - - /*--- Store displacement of each node on the translating surface ---*/ - /*--- Loop over markers and find the particular marker(s) (surface) to translate ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Moving = config->GetMarker_All_Moving(iMarker); - if (Moving == YES) { - for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { - - Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - - if (Marker_Tag == Moving_Tag && (config->GetKind_SurfaceMovement(jMarker) == DEFORMING)) { - - for (iDim = 0; iDim < 3; iDim++){ - xDot[iDim] = config->GetMarkerTranslationRate(jMarker, iDim); - Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); - } - - /*--- Print some information to the console. Be verbose at the first - iteration only (mostly for debugging purposes). ---*/ - // Note that the MASTER_NODE might not contain all the markers being moved. - - if (rank == MASTER_NODE) { - cout << " Storing translating displacement for marker: "; - cout << Marker_Tag << "." << endl; - if (iter == 0) { - cout << " Translational velocity: (" << xDot[0]*config->GetVelocity_Ref() << ", " << xDot[1]*config->GetVelocity_Ref(); - cout << ", " << xDot[2]*config->GetVelocity_Ref(); - if (config->GetSystemMeasurements() == SI) cout << ") m/s." << endl; - else cout << ") ft/s." << endl; - } - } - - /*--- Compute delta change in the position in the x, y, & z directions. ---*/ - - VarCoord[0] = xDot[0]*(time_new-time_old); - VarCoord[1] = xDot[1]*(time_new-time_old); - VarCoord[2] = xDot[2]*(time_new-time_old); - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - /*--- Set node displacement for volume deformation ---*/ - geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - - } - } - } - } - } - - /*--- When updating the origins it is assumed that all markers have the - same translational velocity, because we use the last VarCoord set ---*/ - - /*--- Set the mesh motion center to the new location after - incrementing the position with the translation. This new - location will be used for subsequent mesh motion for the given marker.---*/ - - for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { - - /*-- Check if we want to update the motion origin for the given marker ---*/ - - if (config->GetMoveMotion_Origin(jMarker) == YES) { - for (iDim = 0; iDim < 3; iDim++){ - Center[iDim] += VarCoord[iDim]; - } - config->SetMarkerMotion_Origin(Center, jMarker); - } - } - - /*--- Set the moment computation center to the new location after - incrementing the position with the translation. ---*/ - - for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { - Center[0] = config->GetRefOriginMoment_X(jMarker) + VarCoord[0]; - Center[1] = config->GetRefOriginMoment_Y(jMarker) + VarCoord[1]; - Center[2] = config->GetRefOriginMoment_Z(jMarker) + VarCoord[2]; - config->SetRefOriginMoment_X(jMarker, Center[0]); - config->SetRefOriginMoment_Y(jMarker, Center[1]); - config->SetRefOriginMoment_Z(jMarker, Center[2]); - } -} - -void CSurfaceMovement::Surface_Plunging(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone) { - - su2double deltaT, time_new, time_old, Lref; - su2double Center[3] = {0.0, 0.0, 0.0}, VarCoord[3], Omega[3], Ampl[3]; - su2double DEG2RAD = PI_NUMBER/180.0; - unsigned short iMarker, jMarker, Moving; - unsigned long iVertex; - string Marker_Tag, Moving_Tag; - unsigned short iDim; - - /*--- Initialize the delta variation in coordinates ---*/ - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - - /*--- Retrieve values from the config file ---*/ - - deltaT = config->GetDelta_UnstTimeND(); - Lref = config->GetLength_Ref(); - - /*--- Compute delta time based on physical time step ---*/ - time_new = static_cast(iter)*deltaT; - if (iter == 0) { - time_old = time_new; - } else { - time_old = static_cast(iter-1)*deltaT; - } - - /*--- Store displacement of each node on the plunging surface ---*/ - /*--- Loop over markers and find the particular marker(s) (surface) to plunge ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Moving = config->GetMarker_All_Moving(iMarker); - if (Moving == YES) { - for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { - - Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - - if (Marker_Tag == Moving_Tag && (config->GetKind_SurfaceMovement(jMarker) == DEFORMING)) { - - /*--- Plunging frequency and amplitude from config. ---*/ - - for (iDim = 0; iDim < 3; iDim++){ - Ampl[iDim] = config->GetMarkerPlunging_Ampl(jMarker, iDim)/Lref; - Omega[iDim] = config->GetMarkerPlunging_Omega(jMarker, iDim)/config->GetOmega_Ref(); - Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); - } - /*--- Print some information to the console. Be verbose at the first - iteration only (mostly for debugging purposes). ---*/ - // Note that the MASTER_NODE might not contain all the markers being moved. - - if (rank == MASTER_NODE) { - cout << " Storing plunging displacement for marker: "; - cout << Marker_Tag << "." << endl; - if (iter == 0) { - cout << " Plunging frequency: (" << Omega[0] << ", " << Omega[1]; - cout << ", " << Omega[2] << ") rad/s." << endl; - cout << " Plunging amplitude: (" << Ampl[0]/DEG2RAD; - cout << ", " << Ampl[1]/DEG2RAD << ", " << Ampl[2]/DEG2RAD; - cout << ") degrees."<< endl; - } - } - - /*--- Compute delta change in the position in the x, y, & z directions. ---*/ - - VarCoord[0] = -Ampl[0]*(sin(Omega[0]*time_new) - sin(Omega[0]*time_old)); - VarCoord[1] = -Ampl[1]*(sin(Omega[1]*time_new) - sin(Omega[1]*time_old)); - VarCoord[2] = -Ampl[2]*(sin(Omega[2]*time_new) - sin(Omega[2]*time_old)); - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - /*--- Set node displacement for volume deformation ---*/ - geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - - } - } - } - } - } - - /*--- When updating the origins it is assumed that all markers have the - same plunging movement, because we use the last VarCoord set ---*/ - - /*--- Set the mesh motion center to the new location after - incrementing the position with the translation. This new - location will be used for subsequent mesh motion for the given marker.---*/ - - for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { - - /*-- Check if we want to update the motion origin for the given marker ---*/ - - if (config->GetMoveMotion_Origin(jMarker) == YES) { - for (iDim = 0; iDim < 3; iDim++){ - Center[iDim] += VarCoord[iDim]; - } - config->SetMarkerMotion_Origin(Center, jMarker); - } - } - - /*--- Set the moment computation center to the new location after - incrementing the position with the plunging. ---*/ - - for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { - Center[0] = config->GetRefOriginMoment_X(jMarker) + VarCoord[0]; - Center[1] = config->GetRefOriginMoment_Y(jMarker) + VarCoord[1]; - Center[2] = config->GetRefOriginMoment_Z(jMarker) + VarCoord[2]; - config->SetRefOriginMoment_X(jMarker, Center[0]); - config->SetRefOriginMoment_Y(jMarker, Center[1]); - config->SetRefOriginMoment_Z(jMarker, Center[2]); - } -} - -void CSurfaceMovement::Surface_Pitching(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone) { - - su2double deltaT, time_new, time_old, Lref, *Coord; - su2double Center[3], VarCoord[3], Omega[3], Ampl[3], Phase[3]; - su2double rotCoord[3], r[3] = {0.0,0.0,0.0}; - su2double rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; - su2double dtheta, dphi, dpsi, cosTheta, sinTheta; - su2double cosPhi, sinPhi, cosPsi, sinPsi; - su2double DEG2RAD = PI_NUMBER/180.0; - unsigned short iMarker, jMarker, Moving, iDim, nDim = geometry->GetnDim(); - unsigned long iPoint, iVertex; - string Marker_Tag, Moving_Tag; - - /*--- Initialize the delta variation in coordinates ---*/ - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - - /*--- Retrieve values from the config file ---*/ - - deltaT = config->GetDelta_UnstTimeND(); - Lref = config->GetLength_Ref(); - - /*--- Compute delta time based on physical time step ---*/ - time_new = static_cast(iter)*deltaT; - if (iter == 0) { - time_old = time_new; - } else { - time_old = static_cast(iter-1)*deltaT; - } - - /*--- Store displacement of each node on the pitching surface ---*/ - /*--- Loop over markers and find the particular marker(s) (surface) to pitch ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Moving = config->GetMarker_All_Moving(iMarker); - if (Moving == YES) { - for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { - - Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - - if (Marker_Tag == Moving_Tag && (config->GetKind_SurfaceMovement(jMarker) == DEFORMING)) { - - /*--- Pitching origin, frequency, and amplitude from config. ---*/ - - for (iDim = 0; iDim < 3; iDim++){ - Ampl[iDim] = config->GetMarkerPitching_Ampl(jMarker, iDim)*DEG2RAD; - Omega[iDim] = config->GetMarkerPitching_Omega(jMarker, iDim)/config->GetOmega_Ref(); - Phase[iDim] = config->GetMarkerPitching_Phase(jMarker, iDim)*DEG2RAD; - Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); - } - /*--- Print some information to the console. Be verbose at the first - iteration only (mostly for debugging purposes). ---*/ - // Note that the MASTER_NODE might not contain all the markers being moved. - - if (rank == MASTER_NODE) { - cout << " Storing pitching displacement for marker: "; - cout << Marker_Tag << "." << endl; - if (iter == 0) { - cout << " Pitching frequency: (" << Omega[0] << ", " << Omega[1]; - cout << ", " << Omega[2] << ") rad/s about origin: (" << Center[0]; - cout << ", " << Center[1] << ", " << Center[2] << ")." << endl; - cout << " Pitching amplitude about origin: (" << Ampl[0]/DEG2RAD; - cout << ", " << Ampl[1]/DEG2RAD << ", " << Ampl[2]/DEG2RAD; - cout << ") degrees."<< endl; - cout << " Pitching phase lag about origin: (" << Phase[0]/DEG2RAD; - cout << ", " << Phase[1]/DEG2RAD <<", "<< Phase[2]/DEG2RAD; - cout << ") degrees."<< endl; - } - } - - /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ - - dtheta = -Ampl[0]*(sin(Omega[0]*time_new + Phase[0]) - - sin(Omega[0]*time_old + Phase[0])); - dphi = -Ampl[1]*(sin(Omega[1]*time_new + Phase[1]) - - sin(Omega[1]*time_old + Phase[1])); - dpsi = -Ampl[2]*(sin(Omega[2]*time_new + Phase[2]) - - sin(Omega[2]*time_old + Phase[2])); - - /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - - cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); - sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - - rotMatrix[0][0] = cosPhi*cosPsi; - rotMatrix[1][0] = cosPhi*sinPsi; - rotMatrix[2][0] = -sinPhi; - - rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; - rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; - rotMatrix[2][1] = sinTheta*cosPhi; - - rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[2][2] = cosTheta*cosPhi; - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - /*--- Index and coordinates of the current point ---*/ - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Coord = geometry->node[iPoint]->GetCoord(); - - /*--- Calculate non-dim. position from rotation center ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Coord[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; - - /*--- Compute transformed point coordinates ---*/ - - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2] + Center[0]; - - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2] + Center[1]; - - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2] + Center[2]; - - /*--- Calculate delta change in the x, y, & z directions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = (rotCoord[iDim]-Coord[iDim])/Lref; - if (nDim == 2) VarCoord[nDim] = 0.0; - - /*--- Set node displacement for volume deformation ---*/ - geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - - } - } - } - } - } - /*--- For pitching we don't update the motion origin and moment reference origin. ---*/ -} - -void CSurfaceMovement::Surface_Rotating(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone) { - - su2double deltaT, time_new, time_old, Lref, *Coord; - su2double Center[3] = {0.0,0.0,0.0}, VarCoord[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}, - rotCoord[3] = {0.0,0.0,0.0}, r[3] = {0.0,0.0,0.0}, Center_Aux[3] = {0.0,0.0,0.0}; - su2double rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; - su2double dtheta, dphi, dpsi, cosTheta, sinTheta; - su2double cosPhi, sinPhi, cosPsi, sinPsi; - unsigned short iMarker, jMarker, Moving, iDim, nDim = geometry->GetnDim(); - unsigned long iPoint, iVertex; - string Marker_Tag, Moving_Tag; - - /*--- Initialize the delta variation in coordinates ---*/ - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - - /*--- Retrieve values from the config file ---*/ - - deltaT = config->GetDelta_UnstTimeND(); - Lref = config->GetLength_Ref(); - - /*--- Compute delta time based on physical time step ---*/ - time_new = static_cast(iter)*deltaT; - if (iter == 0) { - time_old = time_new; - } else { - time_old = static_cast(iter-1)*deltaT; - } - - /*--- Store displacement of each node on the rotating surface ---*/ - /*--- Loop over markers and find the particular marker(s) (surface) to rotate ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Moving = config->GetMarker_All_Moving(iMarker); - if (Moving == YES) { - for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { - - Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - - if (Marker_Tag == Moving_Tag && (config->GetKind_SurfaceMovement(jMarker) == DEFORMING)) { - - /*--- Rotation origin and angular velocity from config. ---*/ - - for (iDim = 0; iDim < 3; iDim++){ - Omega[iDim] = config->GetMarkerRotationRate(jMarker, iDim)/config->GetOmega_Ref(); - Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); - } - /*--- Print some information to the console. Be verbose at the first - iteration only (mostly for debugging purposes). ---*/ - // Note that the MASTER_NODE might not contain all the markers being moved. - - if (rank == MASTER_NODE) { - cout << " Storing rotating displacement for marker: "; - cout << Marker_Tag << "." << endl; - if (iter == 0) { - cout << " Angular velocity: (" << Omega[0] << ", " << Omega[1]; - cout << ", " << Omega[2] << ") rad/s about origin: (" << Center[0]; - cout << ", " << Center[1] << ", " << Center[2] << ")." << endl; - } - } - - /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ - - dtheta = Omega[0]*(time_new-time_old); - dphi = Omega[1]*(time_new-time_old); - dpsi = Omega[2]*(time_new-time_old); - - /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - - cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); - sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - - rotMatrix[0][0] = cosPhi*cosPsi; - rotMatrix[1][0] = cosPhi*sinPsi; - rotMatrix[2][0] = -sinPhi; - - rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; - rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; - rotMatrix[2][1] = sinTheta*cosPhi; - - rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[2][2] = cosTheta*cosPhi; - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - /*--- Index and coordinates of the current point ---*/ - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Coord = geometry->node[iPoint]->GetCoord(); - - /*--- Calculate non-dim. position from rotation center ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Coord[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; - - /*--- Compute transformed point coordinates ---*/ - - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2] + Center[0]; - - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2] + Center[1]; - - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2] + Center[2]; - - /*--- Calculate delta change in the x, y, & z directions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = (rotCoord[iDim]-Coord[iDim])/Lref; - if (nDim == 2) VarCoord[nDim] = 0.0; - - /*--- Set node displacement for volume deformation ---*/ - geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); - - } - } - } - } - } - - /*--- When updating the origins it is assumed that all markers have the - same rotation movement, because we use the last markers rotation matrix and center ---*/ - - /*--- Set the mesh motion center to the new location after - incrementing the position with the rotation. This new - location will be used for subsequent mesh motion for the given marker.---*/ - - for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { - - /*-- Check if we want to update the motion origin for the given marker ---*/ - - if (config->GetMoveMotion_Origin(jMarker) == YES) { - - for (iDim = 0; iDim < 3; iDim++){ - Center_Aux[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); - } - - /*--- Calculate non-dim. position from rotation center ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Center_Aux[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; - - /*--- Compute transformed point coordinates ---*/ - - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2] + Center[0]; - - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2] + Center[1]; - - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2] + Center[2]; - - /*--- Calculate delta change in the x, y, & z directions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = (rotCoord[iDim]-Center_Aux[iDim])/Lref; - if (nDim == 2) VarCoord[nDim] = 0.0; - - for (iDim = 0; iDim < 3; iDim++){ - Center_Aux[iDim] += VarCoord[iDim]; - } - config->SetMarkerMotion_Origin(Center_Aux, jMarker); - } - } - - /*--- Set the moment computation center to the new location after - incrementing the position with the rotation. ---*/ - - for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { - - Center_Aux[0] = config->GetRefOriginMoment_X(jMarker); - Center_Aux[1] = config->GetRefOriginMoment_Y(jMarker); - Center_Aux[2] = config->GetRefOriginMoment_Z(jMarker); - - /*--- Calculate non-dim. position from rotation center ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Center_Aux[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; - - /*--- Compute transformed point coordinates ---*/ - - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2] + Center[0]; - - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2] + Center[1]; - - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2] + Center[2]; - - /*--- Calculate delta change in the x, y, & z directions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = (rotCoord[iDim]-Center_Aux[iDim])/Lref; - if (nDim == 2) VarCoord[nDim] = 0.0; - - config->SetRefOriginMoment_X(jMarker, Center_Aux[0]+VarCoord[0]); - config->SetRefOriginMoment_Y(jMarker, Center_Aux[1]+VarCoord[1]); - config->SetRefOriginMoment_Z(jMarker, Center_Aux[2]+VarCoord[2]); - } -} - void CSurfaceMovement::AeroelasticDeform(CGeometry *geometry, CConfig *config, unsigned long TimeIter, unsigned short iMarker, unsigned short iMarker_Monitoring, vector& displacements) { /* The sign conventions of these are those of the Typical Section Wing Model, below the signs are corrected */ diff --git a/SU2_CFD/include/solvers/CMeshSolver.hpp b/SU2_CFD/include/solvers/CMeshSolver.hpp index 576aa2cb8f76..79c9f5b9e007 100644 --- a/SU2_CFD/include/solvers/CMeshSolver.hpp +++ b/SU2_CFD/include/solvers/CMeshSolver.hpp @@ -178,39 +178,31 @@ class CMeshSolver final : public CFEASolver { * \param[in] geometry - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. * \param[in] iter - Current time iteration number - * \param[in] iZone - Current zone */ - void Surface_Pitching(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone); + void Surface_Pitching(CGeometry *geometry, CConfig *config, unsigned long iter); /*! * \brief Rotating definition for deforming mesh * \param[in] geometry - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. * \param[in] iter - Current time iteration number - * \param[in] iZone - Current zone */ - void Surface_Rotating(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone); + void Surface_Rotating(CGeometry *geometry, CConfig *config, unsigned long iter); /*! * \brief Plunging definition for deforming mesh * \param[in] geometry - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. * \param[in] iter - Current time iteration number - * \param[in] iZone - Current zone */ - void Surface_Plunging(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone); + void Surface_Plunging(CGeometry *geometry, CConfig *config, unsigned long iter); /*! * \brief Translating definition for deforming mesh * \param[in] geometry - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. * \param[in] iter - Current time iteration number - * \param[in] iZone - Current zone */ - void Surface_Translating(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone); + void Surface_Translating(CGeometry *geometry, CConfig *config, unsigned long iter); }; diff --git a/SU2_CFD/include/solvers/CSolver.hpp b/SU2_CFD/include/solvers/CSolver.hpp index 80faaa3b6b6a..14ed1949ddd9 100644 --- a/SU2_CFD/include/solvers/CSolver.hpp +++ b/SU2_CFD/include/solvers/CSolver.hpp @@ -4553,42 +4553,6 @@ class CSolver { CNumerics **numerics, CConfig *config) { } - /*! - * \brief Pitching definition for deforming mesh - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current time iteration number - * \param[in] iZone - Current zone - */ - inline virtual void Surface_Pitching(CGeometry *geometry, CConfig *config, unsigned long iter, unsigned short iZone) { } - - /*! - * \brief Rotating definition for deforming mesh - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current time iteration number - * \param[in] iZone - Current zone - */ - inline virtual void Surface_Rotating(CGeometry *geometry, CConfig *config, unsigned long iter, unsigned short iZone) { } - - /*! - * \brief Plunging definition for deforming mesh - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current time iteration number - * \param[in] iZone - Current zone - */ - inline virtual void Surface_Plunging(CGeometry *geometry, CConfig *config, unsigned long iter, unsigned short iZone) { } - - /*! - * \brief Translating definition for deforming mesh - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current time iteration number - * \param[in] iZone - Current zone - */ - inline virtual void Surface_Translating(CGeometry *geometry, CConfig *config, unsigned long iter, unsigned short iZone) { } - /*! * \brief A virtual member. * \param[in] geometry - Geometrical definition. diff --git a/SU2_CFD/src/iteration_structure.cpp b/SU2_CFD/src/iteration_structure.cpp index 41c67a314453..f7d3205bfd35 100644 --- a/SU2_CFD/src/iteration_structure.cpp +++ b/SU2_CFD/src/iteration_structure.cpp @@ -66,22 +66,17 @@ void CIteration::SetGrid_Movement(CGeometry **geometry, case RIGID_MOTION: - if (rank == MASTER_NODE) { + if (rank == MASTER_NODE) cout << endl << " Performing rigid mesh transformation." << endl; - } /*--- Move each node in the volume mesh using the specified type of rigid mesh motion. These routines also compute analytic grid velocities for the fine mesh. ---*/ - grid_movement->Rigid_Translation(geometry[MESH_0], - config, val_iZone, TimeIter); - grid_movement->Rigid_Plunging(geometry[MESH_0], - config, val_iZone, TimeIter); - grid_movement->Rigid_Pitching(geometry[MESH_0], - config, val_iZone, TimeIter); - grid_movement->Rigid_Rotation(geometry[MESH_0], - config, val_iZone, TimeIter); + grid_movement->Rigid_Translation(geometry[MESH_0], config, val_iZone, TimeIter); + grid_movement->Rigid_Plunging(geometry[MESH_0], config, val_iZone, TimeIter); + grid_movement->Rigid_Pitching(geometry[MESH_0], config, val_iZone, TimeIter); + grid_movement->Rigid_Rotation(geometry[MESH_0], config, val_iZone, TimeIter); /*--- Update the multigrid structure after moving the finest grid, including computing the grid velocities on the coarser levels. ---*/ @@ -97,121 +92,6 @@ void CIteration::SetGrid_Movement(CGeometry **geometry, } - if (config->GetSurface_Movement(DEFORMING)){ - if (rank == MASTER_NODE) - cout << endl << " Updating surface positions." << endl; - - /*--- Translating ---*/ - - /*--- Compute the new node locations for moving markers ---*/ - - if (!config->GetDeform_Mesh()) { - surface_movement->Surface_Translating(geometry[MESH_0], - config, TimeIter, val_iZone); - } - else { - solver[MESH_0][MESH_SOL]->Surface_Translating(geometry[MESH_0], - config, TimeIter, val_iZone); - } - - /*--- Deform the volume grid around the new boundary locations ---*/ - /*--- Set volume deformation if new elastic mesh solver is not used ---*/ - /*--- If Deform_Mesh true, the mesh deformation is handled by SetMesh_Deformation ---*/ - // To Do: What if multiple prescribed movements? E.g., Pitching + Plunging? - - if (rank == MASTER_NODE && !config->GetDeform_Mesh()) { - cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry[MESH_0], - config, true); - } - - /*--- Plunging ---*/ - - /*--- Compute the new node locations for moving markers ---*/ - - if (!config->GetDeform_Mesh()) { - surface_movement->Surface_Plunging(geometry[MESH_0], - config, TimeIter, val_iZone); - } - else { - solver[MESH_0][MESH_SOL]->Surface_Plunging(geometry[MESH_0], - config, TimeIter, val_iZone); - } - - /*--- Deform the volume grid around the new boundary locations ---*/ - /*--- Set volume deformation if new elastic mesh solver is not used ---*/ - /*--- If Deform_Mesh true, the mesh deformation is handled by SetMesh_Deformation ---*/ - // To Do: What if multiple prescribed movements? E.g., Pitching + Plunging? - - if (rank == MASTER_NODE && !config->GetDeform_Mesh()) { - cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry[MESH_0], - config, true); - } - - /*--- Pitching ---*/ - - /*--- Compute the new node locations for moving markers ---*/ - - if (!config->GetDeform_Mesh()) { - surface_movement->Surface_Pitching(geometry[MESH_0], - config, TimeIter, val_iZone); - } - else { - solver[MESH_0][MESH_SOL]->Surface_Pitching(geometry[MESH_0], - config, TimeIter, val_iZone); - } - - /*--- Deform the volume grid around the new boundary locations ---*/ - /*--- Set volume deformation if new elastic mesh solver is not used ---*/ - /*--- If Deform_Mesh true, the mesh deformation is handled by SetMesh_Deformation ---*/ - // To Do: What if multiple prescribed movements? E.g., Pitching + Plunging? - - if (rank == MASTER_NODE && !config->GetDeform_Mesh()) { - cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry[MESH_0], - config, true); - } - - /*--- Rotating ---*/ - - /*--- Compute the new node locations for moving markers ---*/ - - if (!config->GetDeform_Mesh()) { - surface_movement->Surface_Rotating(geometry[MESH_0], - config, TimeIter, val_iZone); - } - else { - solver[MESH_0][MESH_SOL]->Surface_Rotating(geometry[MESH_0], - config, TimeIter, val_iZone); - } - - /*--- Deform the volume grid around the new boundary locations ---*/ - /*--- Set volume deformation if new elastic mesh solver is not used ---*/ - /*--- If Deform_Mesh true, the mesh deformation is handled by SetMesh_Deformation ---*/ - // To Do: What if multiple prescribed movements? E.g., Pitching + Plunging? - if (rank == MASTER_NODE && !config->GetDeform_Mesh()) { - cout << " Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry[MESH_0], - config, true); - } - - /*--- Update the grid velocities on the fine mesh using finite - differencing based on node coordinates at previous times. ---*/ - - if (!adjoint) { - if (rank == MASTER_NODE) - cout << " Computing grid velocities by finite differencing." << endl; - geometry[MESH_0]->SetGridVelocity(config, TimeIter); - } - - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ - - grid_movement->UpdateMultiGrid(geometry, config); - - } - if (config->GetSurface_Movement(AEROELASTIC) || config->GetSurface_Movement(AEROELASTIC_RIGID_MOTION)) { @@ -219,22 +99,17 @@ void CIteration::SetGrid_Movement(CGeometry **geometry, if (IntIter == 0) { if (Kind_Grid_Movement == AEROELASTIC_RIGID_MOTION) { - if (rank == MASTER_NODE) { + if (rank == MASTER_NODE) cout << endl << " Performing rigid mesh transformation." << endl; - } /*--- Move each node in the volume mesh using the specified type of rigid mesh motion. These routines also compute analytic grid velocities for the fine mesh. ---*/ - grid_movement->Rigid_Translation(geometry[MESH_0], - config, val_iZone, TimeIter); - grid_movement->Rigid_Plunging(geometry[MESH_0], - config, val_iZone, TimeIter); - grid_movement->Rigid_Pitching(geometry[MESH_0], - config, val_iZone, TimeIter); - grid_movement->Rigid_Rotation(geometry[MESH_0], - config, val_iZone, TimeIter); + grid_movement->Rigid_Translation(geometry[MESH_0], config, val_iZone, TimeIter); + grid_movement->Rigid_Plunging(geometry[MESH_0], config, val_iZone, TimeIter); + grid_movement->Rigid_Pitching(geometry[MESH_0], config, val_iZone, TimeIter); + grid_movement->Rigid_Rotation(geometry[MESH_0], config, val_iZone, TimeIter); /*--- Update the multigrid structure after moving the finest grid, including computing the grid velocities on the coarser levels. ---*/ @@ -258,8 +133,7 @@ void CIteration::SetGrid_Movement(CGeometry **geometry, if (rank == MASTER_NODE) cout << " Deforming the volume grid due to the aeroelastic movement." << endl; - grid_movement->SetVolume_Deformation(geometry[MESH_0], - config, true); + grid_movement->SetVolume_Deformation(geometry[MESH_0], config, true); /*--- Update the grid velocities on the fine mesh using finite differencing based on node coordinates at previous times. ---*/ @@ -284,8 +158,7 @@ void CIteration::SetGrid_Movement(CGeometry **geometry, if (rank == MASTER_NODE && Screen_Output) cout << "Deforming the volume grid." << endl; - grid_movement->SetVolume_Deformation(geometry[MESH_0], - config, true, false); + grid_movement->SetVolume_Deformation(geometry[MESH_0], config, true, false); nIterMesh = grid_movement->Get_nIterMesh(); stat_mesh = (nIterMesh == 0); diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index 415442931c3e..92ccc167ad7b 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -586,6 +586,16 @@ void CMeshSolver::UpdateMultiGrid(CGeometry **geometry, CConfig *config){ void CMeshSolver::SetBoundaryDisplacements(CGeometry *geometry, CNumerics *numerics, CConfig *config){ + if (config->GetSurface_Movement(DEFORMING)) { + if (rank == MASTER_NODE) + cout << endl << " Updating surface positions." << endl; + + Surface_Translating(geometry, config, config->GetTimeIter()); + Surface_Plunging(geometry, config, config->GetTimeIter()); + Surface_Pitching(geometry, config, config->GetTimeIter()); + Surface_Rotating(geometry, config, config->GetTimeIter()); + } + unsigned short iMarker; /*--- Impose zero displacements of all non-moving surfaces (also at nodes in multiple moving/non-moving boundaries). ---*/ @@ -837,8 +847,7 @@ void CMeshSolver::Restart_OldGeometry(CGeometry *geometry, CConfig *config) { } -void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone) { +void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, unsigned long iter) { su2double deltaT, time_new, time_old, Lref, *Coord; su2double Center[3], VarCoord[3], Omega[3], Ampl[3], Phase[3]; @@ -987,8 +996,8 @@ void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, } -void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone) { +void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, unsigned long iter) { + su2double deltaT, time_new, time_old, Lref, *Coord; su2double VarCoordAbs[3] = {0.0, 0.0, 0.0}; su2double Center[3] = {0.0,0.0,0.0}, VarCoord[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}, @@ -1210,8 +1219,8 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, } } -void CMeshSolver::Surface_Plunging(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone) { +void CMeshSolver::Surface_Plunging(CGeometry *geometry, CConfig *config, unsigned long iter) { + su2double deltaT, time_new, time_old, Lref; su2double Center[3] = {0.0, 0.0, 0.0}, VarCoord[3], Omega[3], Ampl[3]; su2double VarCoordAbs[3] = {0.0, 0.0, 0.0}; @@ -1330,8 +1339,8 @@ void CMeshSolver::Surface_Plunging(CGeometry *geometry, CConfig *config, } } -void CMeshSolver::Surface_Translating(CGeometry *geometry, CConfig *config, - unsigned long iter, unsigned short iZone) { +void CMeshSolver::Surface_Translating(CGeometry *geometry, CConfig *config, unsigned long iter) { + su2double deltaT, time_new, time_old; su2double Center[3] = {0.0,0.0,0.0}, VarCoord[3] = {0.0,0.0,0.0}; su2double VarCoordAbs[3] = {0.0, 0.0, 0.0}; From 56b7c55b363692b2a38209180e17f02fa3b07c0a Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 28 Mar 2020 15:30:16 +0000 Subject: [PATCH 42/79] option to define a region of maximum mesh stiffness around deforming boundaries --- Common/include/CConfig.hpp | 14 +++-- .../interface_interpolation/CInterpolator.hpp | 4 +- Common/src/CConfig.cpp | 8 ++- .../elasticity/CFEALinearElasticity.cpp | 1 - SU2_CFD/src/solvers/CMeshSolver.cpp | 55 ++++++++++++------- 5 files changed, 53 insertions(+), 29 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 604f83e10f9b..eec6a12d5b94 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -605,7 +605,7 @@ class CConfig { su2double Min_Beta_RoeTurkel, /*!< \brief Minimum value of Beta for the Roe-Turkel low Mach preconditioner. */ Max_Beta_RoeTurkel; /*!< \brief Maximum value of Beta for the Roe-Turkel low Mach preconditioner. */ unsigned long GridDef_Nonlinear_Iter; /*!< \brief Number of nonlinear increments for grid deformation. */ - unsigned short Deform_Stiffness_Type; /*!< \brief Type of element stiffness imposed for FEA mesh deformation. */ + unsigned short Deform_StiffnessType; /*!< \brief Type of element stiffness imposed for FEA mesh deformation. */ bool Deform_Mesh; /*!< \brief Determines whether the mesh will be deformed. */ bool Deform_Output; /*!< \brief Print the residuals during mesh deformation to the console. */ su2double Deform_Tol_Factor; /*!< \brief Factor to multiply smallest volume for deform tolerance (0.001 default) */ @@ -613,8 +613,9 @@ class CConfig { su2double Deform_Limit; /*!< \brief Deform limit */ unsigned short FFD_Continuity; /*!< \brief Surface continuity at the intersection with the FFD */ unsigned short FFD_CoordSystem; /*!< \brief Define the coordinates system */ - su2double Deform_ElasticityMod, - Deform_PoissonRatio; /*!< \brief Young's Modulus and poisson ratio for volume deformation stiffness model */ + su2double Deform_ElasticityMod, /*!< \brief Young's modulus for volume deformation stiffness model */ + Deform_PoissonRatio, /*!< \brief Poisson's ratio for volume deformation stiffness model */ + Deform_StiffLayerSize; /*!< \brief Size of the layer of highest stiffness for wall distance-based mesh stiffness */ bool Visualize_Surface_Def; /*!< \brief Flag to visualize the surface deformacion in SU2_DEF. */ bool Visualize_Volume_Def; /*!< \brief Flag to visualize the volume deformation in SU2_DEF. */ bool FFD_Symmetry_Plane; /*!< \brief FFD symmetry plane. */ @@ -4105,7 +4106,12 @@ class CConfig { * \brief Get the type of stiffness to impose for FEA mesh deformation. * \return type of stiffness to impose for FEA mesh deformation. */ - unsigned short GetDeform_Stiffness_Type(void) const { return Deform_Stiffness_Type; } + unsigned short GetDeform_Stiffness_Type(void) const { return Deform_StiffnessType; } + + /*! + * \brief Get the size of the layer of highest stiffness for wall distance-based mesh stiffness. + */ + su2double GetDeform_StiffLayerSize(void) const { return Deform_StiffLayerSize; } /*! * \brief Creates a tecplot file to visualize the volume deformation deformation made by the DEF software. diff --git a/Common/include/interface_interpolation/CInterpolator.hpp b/Common/include/interface_interpolation/CInterpolator.hpp index af95221275f0..f8254b17ea09 100644 --- a/Common/include/interface_interpolation/CInterpolator.hpp +++ b/Common/include/interface_interpolation/CInterpolator.hpp @@ -39,8 +39,8 @@ class CGeometry; */ class CInterpolator { protected: - const int rank; /*!< \brief MPI Rank. */ - const int size; /*!< \brief MPI Size. */ + const int rank; /*!< \brief MPI Rank. */ + const int size; /*!< \brief MPI Size. */ const unsigned donorZone; /*!< \brief Index of donor zone. */ const unsigned targetZone; /*!< \brief Index of target zone. */ diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index cf65fc655c53..7434dbac56df 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2221,11 +2221,13 @@ void CConfig::SetConfig_Options() { /* DESCRIPTION: Deform limit in m or inches */ addDoubleOption("DEFORM_LIMIT", Deform_Limit, 1E6); /* DESCRIPTION: Type of element stiffness imposed for FEA mesh deformation (INVERSE_VOLUME, WALL_DISTANCE, CONSTANT_STIFFNESS) */ - addEnumOption("DEFORM_STIFFNESS_TYPE", Deform_Stiffness_Type, Deform_Stiffness_Map, SOLID_WALL_DISTANCE); - /* DESCRIPTION: Poisson's ratio for constant stiffness FEA method of grid deformation*/ + addEnumOption("DEFORM_STIFFNESS_TYPE", Deform_StiffnessType, Deform_Stiffness_Map, SOLID_WALL_DISTANCE); + /* DESCRIPTION: Poisson's ratio for constant stiffness FEA method of grid deformation */ addDoubleOption("DEFORM_ELASTICITY_MODULUS", Deform_ElasticityMod, 2E11); - /* DESCRIPTION: Young's modulus and Poisson's ratio for constant stiffness FEA method of grid deformation*/ + /* DESCRIPTION: Young's modulus and Poisson's ratio for constant stiffness FEA method of grid deformation */ addDoubleOption("DEFORM_POISSONS_RATIO", Deform_PoissonRatio, 0.3); + /* DESCRIPTION: Size of the layer of highest stiffness for wall distance-based mesh stiffness */ + addDoubleOption("DEFORM_STIFF_LAYER_SIZE", Deform_StiffLayerSize, 0.0); /* DESCRIPTION: Linear solver for the mesh deformation\n OPTIONS: see \link Linear_Solver_Map \endlink \n DEFAULT: FGMRES \ingroup Config*/ addEnumOption("DEFORM_LINEAR_SOLVER", Kind_Deform_Linear_Solver, Linear_Solver_Map, FGMRES); /* \n DESCRIPTION: Preconditioner for the Krylov linear solvers \n OPTIONS: see \link Linear_Solver_Prec_Map \endlink \n DEFAULT: LU_SGS \ingroup Config*/ diff --git a/SU2_CFD/src/numerics/elasticity/CFEALinearElasticity.cpp b/SU2_CFD/src/numerics/elasticity/CFEALinearElasticity.cpp index 7e09c1410b90..25d0d0b3b360 100644 --- a/SU2_CFD/src/numerics/elasticity/CFEALinearElasticity.cpp +++ b/SU2_CFD/src/numerics/elasticity/CFEALinearElasticity.cpp @@ -366,7 +366,6 @@ CFEAMeshElasticity::CFEAMeshElasticity(unsigned short val_nDim, unsigned short v case INVERSE_VOLUME: case SOLID_WALL_DISTANCE: element_based = true; - Nu = config->GetDeform_Coeff(); break; case CONSTANT_STIFFNESS: element_based = false; diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index 25e4b711fc9f..0af54d960a2e 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -388,6 +388,8 @@ void CMeshSolver::SetWallDistance(CGeometry *geometry, CConfig *config) { void CMeshSolver::SetMesh_Stiffness(CGeometry **geometry, CNumerics **numerics, CConfig *config){ + if (stiffness_set) return; + /*--- Use the config option as an upper bound on elasticity modulus. * For RANS meshes the range of element volume or wall distance is * very large and leads to an ill-conditioned stiffness matrix. @@ -396,31 +398,46 @@ void CMeshSolver::SetMesh_Stiffness(CGeometry **geometry, CNumerics **numerics, * boundary conditions are essential (Dirichlet). ---*/ const su2double maxE = config->GetDeform_ElasticityMod(); - if (!stiffness_set) { - /*--- All threads must execute the entire loop (no worksharing), - * each sets the stiffnesses for its numerics instance. ---*/ - SU2_OMP_PARALLEL - { - CNumerics* myNumerics = numerics[FEA_TERM + omp_get_thread_num()*MAX_TERMS]; - - for (unsigned long iElem = 0; iElem < nElement; iElem++) { - - su2double E = 1.0; + /*--- All threads must execute the entire loop (no worksharing), + * each sets the stiffnesses for its numerics instance. ---*/ + SU2_OMP_PARALLEL + { + CNumerics* myNumerics = numerics[FEA_TERM + omp_get_thread_num()*MAX_TERMS]; - switch (config->GetDeform_Stiffness_Type()) { - /*--- Stiffness inverse of the volume of the element ---*/ - case INVERSE_VOLUME: E = 1.0 / element[iElem].GetRef_Volume(); break; + switch (config->GetDeform_Stiffness_Type()) { - /*--- Stiffness inverse of the distance of the element to the closest wall ---*/ - case SOLID_WALL_DISTANCE: E = 1.0 / element[iElem].GetWallDistance(); break; + /*--- Stiffness inverse of the volume of the element. ---*/ + case INVERSE_VOLUME: + for (unsigned long iElem = 0; iElem < nElement; iElem++) { + su2double E = 1.0 / element[iElem].GetRef_Volume(); + myNumerics->SetMeshElasticProperties(iElem, min(E,maxE)); } + break; - /*--- Set the element elastic properties in the numerics container ---*/ - myNumerics->SetMeshElasticProperties(iElem, min(E,maxE)); - } + /*--- Stiffness inverse of the distance of the element to the closest wall. ---*/ + case SOLID_WALL_DISTANCE: { + const su2double offset = config->GetDeform_StiffLayerSize(); + if (fabs(offset) > 0.0) { + /*--- With prescribed layer of maximum stiffness (reaches max and holds). ---*/ + su2double d0 = offset / MaxDistance; + su2double dmin = 1.0 / maxE; + su2double scale = 1.0 / (1.0 - d0); + for (unsigned long iElem = 0; iElem < nElement; iElem++) { + su2double E = 1.0 / max(dmin, (element[iElem].GetWallDistance() - d0)*scale); + myNumerics->SetMeshElasticProperties(iElem, E); + } + } else { + /*--- Without prescribed layer of maximum stiffness (may not reach max). ---*/ + for (unsigned long iElem = 0; iElem < nElement; iElem++) { + su2double E = 1.0 / element[iElem].GetWallDistance(); + myNumerics->SetMeshElasticProperties(iElem, min(E,maxE)); + } + } } - stiffness_set = true; + break; + } } + stiffness_set = true; } From 1fa58dafce81f11385b4fa79f0224b1cc183291b Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 28 Mar 2020 19:40:39 +0000 Subject: [PATCH 43/79] initialize the linear system solution of CMeshSolver --- Common/src/linear_algebra/CSysSolve.cpp | 18 +----------------- SU2_CFD/src/solvers/CFEASolver.cpp | 15 +-------------- SU2_CFD/src/solvers/CMeshSolver.cpp | 10 ++++++++-- 3 files changed, 10 insertions(+), 33 deletions(-) diff --git a/Common/src/linear_algebra/CSysSolve.cpp b/Common/src/linear_algebra/CSysSolve.cpp index 6f041e89f8bb..0e97709bd330 100644 --- a/Common/src/linear_algebra/CSysSolve.cpp +++ b/Common/src/linear_algebra/CSysSolve.cpp @@ -239,10 +239,6 @@ unsigned long CSysSolve::CG_LinSolver(const CSysVector & return 0; } - /*--- Set the norm to the initial initial residual value ---*/ - - norm0 = norm_r; - /*--- Output header information including initial residual ---*/ if ((monitoring) && (master)) { @@ -398,10 +394,6 @@ unsigned long CSysSolve::FGMRES_LinSolver(const CSysVector::BCGSTAB_LinSolver(const CSysVector::Smoother_LinSolver(const CSysVector::Solve_b(CSysMatrix & Jacobian, /*--- Enforce a hard limit on total number of iterations ---*/ unsigned long IterLimit = min(RestartIter, MaxIter-IterLinSol); IterLinSol += FGMRES_LinSolver(*LinSysRes_ptr, *LinSysSol_ptr, mat_vec, *precond, SolverTol , IterLimit, Residual, ScreenOutput, config); - if ( Residual < SolverTol*Norm0 ) break; + if ( Residual <= SolverTol*Norm0 ) break; } break; case PASTIX_LDLT : case PASTIX_LU: diff --git a/SU2_CFD/src/solvers/CFEASolver.cpp b/SU2_CFD/src/solvers/CFEASolver.cpp index 28e338731015..2db9d13fb60a 100644 --- a/SU2_CFD/src/solvers/CFEASolver.cpp +++ b/SU2_CFD/src/solvers/CFEASolver.cpp @@ -2768,19 +2768,6 @@ void CFEASolver::Solve_System(CGeometry *geometry, CConfig *config) { SU2_OMP_PARALLEL { - /*--- Initialize residual and solution at the ghost points ---*/ - - SU2_OMP(sections) - { - SU2_OMP(section) - for (auto iPoint = nPointDomain; iPoint < nPoint; iPoint++) - LinSysRes.SetBlock_Zero(iPoint); - - SU2_OMP(section) - for (auto iPoint = nPointDomain; iPoint < nPoint; iPoint++) - LinSysSol.SetBlock_Zero(iPoint); - } - /*--- Solve or smooth the linear system. ---*/ auto iter = System.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); @@ -2789,7 +2776,7 @@ void CFEASolver::Solve_System(CGeometry *geometry, CConfig *config) { SetIterLinSolver(iter); SetResLinSolver(System.GetResidual()); } - SU2_OMP_BARRIER + //SU2_OMP_BARRIER } // end SU2_OMP_PARALLEL } diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index 0af54d960a2e..f2c0df295c60 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -448,10 +448,9 @@ void CMeshSolver::DeformMesh(CGeometry **geometry, CNumerics **numerics, CConfig /*--- Compute the stiffness matrix. ---*/ Compute_StiffMatrix(geometry[MESH_0], numerics, config); - /*--- Initialize vectors and clean residual. ---*/ + /*--- Clean residual, we do not want an incremental solution. ---*/ SU2_OMP_PARALLEL { - LinSysSol.SetValZero(); LinSysRes.SetValZero(); } @@ -706,6 +705,13 @@ void CMeshSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig * geometry[MESH_0]->InitiateComms(geometry[MESH_0], config, COORDINATES); geometry[MESH_0]->CompleteComms(geometry[MESH_0], config, COORDINATES); + /*--- Init the linear system solution. ---*/ + for (unsigned long iPoint = 0; iPoint < nPoint; ++iPoint) { + for (unsigned short iDim = 0; iDim < nDim; ++iDim) { + LinSysSol(iPoint, iDim) = nodes->GetSolution(iPoint, iDim); + } + } + /*--- Recompute the edges and dual mesh control volumes in the domain and on the boundaries. ---*/ UpdateDualGrid(geometry[MESH_0], config); From afa41549bbca126a3071d5991b9581f6abd50c30 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Mon, 30 Mar 2020 15:16:05 +0100 Subject: [PATCH 44/79] mitigate bug affecting displacement boundary conditions caused by partitioning of markers --- Common/src/geometry/CPhysicalGeometry.cpp | 73 +++++++--------------- SU2_CFD/include/solvers/CFEASolver.hpp | 12 ++++ SU2_CFD/src/solvers/CFEASolver.cpp | 76 ++++++++++++++++++++++- SU2_CFD/src/solvers/CMeshSolver.cpp | 12 ++++ 4 files changed, 121 insertions(+), 52 deletions(-) diff --git a/Common/src/geometry/CPhysicalGeometry.cpp b/Common/src/geometry/CPhysicalGeometry.cpp index 8f8ea74fe17a..a57784a49431 100644 --- a/Common/src/geometry/CPhysicalGeometry.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -3070,61 +3070,32 @@ void CPhysicalGeometry::LoadSurfaceElements(CConfig *config, CGeometry *geometry /*--- Initialize pointers for turbomachinery computations ---*/ - nSpanWiseSections = new unsigned short[2]; - nSpanSectionsByMarker = new unsigned short[nMarker]; - SpanWiseValue = new su2double*[2]; - for (unsigned short iMarker = 0; iMarker < 2; iMarker++){ - nSpanWiseSections[iMarker] = 0; - SpanWiseValue[iMarker] = NULL; - } - - nVertexSpan = new long* [nMarker]; - nTotVertexSpan = new unsigned long* [nMarker]; - turbovertex = new CTurboVertex***[nMarker]; - AverageTurboNormal = new su2double**[nMarker]; - AverageNormal = new su2double**[nMarker]; - AverageGridVel = new su2double**[nMarker]; - AverageTangGridVel = new su2double*[nMarker]; - SpanArea = new su2double*[nMarker]; - TurboRadius = new su2double*[nMarker]; - MaxAngularCoord = new su2double*[nMarker]; - MinAngularCoord = new su2double*[nMarker]; - MinRelAngularCoord = new su2double*[nMarker]; - - for (unsigned short iMarker = 0; iMarker < nMarker; iMarker++){ - nSpanSectionsByMarker[iMarker] = 0; - nVertexSpan[iMarker] = NULL; - nTotVertexSpan[iMarker] = NULL; - turbovertex[iMarker] = NULL; - AverageTurboNormal[iMarker] = NULL; - AverageNormal[iMarker] = NULL; - AverageGridVel[iMarker] = NULL; - AverageTangGridVel[iMarker] = NULL; - SpanArea[iMarker] = NULL; - TurboRadius[iMarker] = NULL; - MaxAngularCoord[iMarker] = NULL; - MinAngularCoord[iMarker] = NULL; - MinRelAngularCoord[iMarker] = NULL; - } + nSpanWiseSections = new unsigned short[2] (); + SpanWiseValue = new su2double*[2] (); + + nSpanSectionsByMarker = new unsigned short[nMarker] (); + nVertexSpan = new long* [nMarker] (); + nTotVertexSpan = new unsigned long* [nMarker] (); + turbovertex = new CTurboVertex***[nMarker] (); + AverageTurboNormal = new su2double**[nMarker] (); + AverageNormal = new su2double**[nMarker] (); + AverageGridVel = new su2double**[nMarker] (); + AverageTangGridVel = new su2double*[nMarker] (); + SpanArea = new su2double*[nMarker] (); + TurboRadius = new su2double*[nMarker] (); + MaxAngularCoord = new su2double*[nMarker] (); + MinAngularCoord = new su2double*[nMarker] (); + MinRelAngularCoord = new su2double*[nMarker] (); /*--- Initialize pointers for turbomachinery performance computation ---*/ nTurboPerf = config->GetnMarker_TurboPerformance(); - TangGridVelIn = new su2double*[config->GetnMarker_TurboPerformance()]; - SpanAreaIn = new su2double*[config->GetnMarker_TurboPerformance()]; - TurboRadiusIn = new su2double*[config->GetnMarker_TurboPerformance()]; - TangGridVelOut = new su2double*[config->GetnMarker_TurboPerformance()]; - SpanAreaOut = new su2double*[config->GetnMarker_TurboPerformance()]; - TurboRadiusOut = new su2double*[config->GetnMarker_TurboPerformance()]; - - for (unsigned short iMarker = 0; iMarker < config->GetnMarker_TurboPerformance(); iMarker++){ - TangGridVelIn[iMarker] = NULL; - SpanAreaIn[iMarker] = NULL; - TurboRadiusIn[iMarker] = NULL; - TangGridVelOut[iMarker] = NULL; - SpanAreaOut[iMarker] = NULL; - TurboRadiusOut[iMarker] = NULL; - } + TangGridVelIn = new su2double*[nTurboPerf] (); + SpanAreaIn = new su2double*[nTurboPerf] (); + TurboRadiusIn = new su2double*[nTurboPerf] (); + TangGridVelOut = new su2double*[nTurboPerf] (); + SpanAreaOut = new su2double*[nTurboPerf] (); + TurboRadiusOut = new su2double*[nTurboPerf] (); } diff --git a/SU2_CFD/include/solvers/CFEASolver.hpp b/SU2_CFD/include/solvers/CFEASolver.hpp index eae891063a05..04d012b14b13 100644 --- a/SU2_CFD/include/solvers/CFEASolver.hpp +++ b/SU2_CFD/include/solvers/CFEASolver.hpp @@ -91,6 +91,9 @@ class CFEASolver : public CSolver { unsigned long nElement; /*!< \brief Number of elements. */ + /*--- Extra vertices for row/column elimination, see Set_VertexEliminationSchedule. ---*/ + vector ExtraVerticesToEliminate; + /*! * \brief The highest level in the variable hierarchy this solver can safely use, * CVariable is the common denominator between the FEA and Mesh deformation variables. @@ -147,6 +150,15 @@ class CFEASolver : public CSolver { */ void Set_Prestretch(CGeometry *geometry, CConfig *config); + /*! + * \brief Mitigation for an issue with Dirichlet boundary conditions and MPI, + * some ranks do not get enough of the markers to cover their halo points. + * This breaks the symmetry of the global matrix as columns are not fully eliminated. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] markers - List of essential BC markers. + */ + void Set_VertexEliminationSchedule(CGeometry *geometry, const vector& markers); + /*! * \brief Compute constants for time integration. * \param[in] config - Definition of the particular problem. diff --git a/SU2_CFD/src/solvers/CFEASolver.cpp b/SU2_CFD/src/solvers/CFEASolver.cpp index 2db9d13fb60a..030950aefcdc 100644 --- a/SU2_CFD/src/solvers/CFEASolver.cpp +++ b/SU2_CFD/src/solvers/CFEASolver.cpp @@ -29,6 +29,8 @@ #include "../../include/variables/CFEABoundVariable.hpp" #include "../../../Common/include/toolboxes/printing_toolbox.hpp" #include +#include +#include /*! * \brief Anonymous namespace with helper functions of the FEA solver. @@ -284,11 +286,24 @@ CFEASolver::CFEASolver(CGeometry *geometry, CConfig *config) : CSolver() { /*--- If dynamic, we also need to communicate the old solution ---*/ - if(dynamic) { + if (dynamic) { InitiateComms(geometry, config, SOLUTION_FEA_OLD); CompleteComms(geometry, config, SOLUTION_FEA_OLD); } + if (size != SINGLE_NODE) { + vector essentialMarkers; + for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + const auto kindBnd = config->GetMarker_All_KindBC(iMarker); + if ((kindBnd == CLAMPED_BOUNDARY) || + (kindBnd == DISP_DIR_BOUNDARY) || + (kindBnd == DISPLACEMENT_BOUNDARY)) { + essentialMarkers.push_back(iMarker); + } + } + Set_VertexEliminationSchedule(geometry, essentialMarkers); + } + /*--- Add the solver name (max 8 characters) ---*/ SolverName = "FEA"; } @@ -748,6 +763,56 @@ void CFEASolver::Set_ReferenceGeometry(CGeometry *geometry, CConfig *config) { } +void CFEASolver::Set_VertexEliminationSchedule(CGeometry *geometry, const vector& markers) { + + /*--- Store global point indices of essential BC markers. ---*/ + vector myPoints; + + for (auto iMarker : markers) { + for (auto iVertex = 0ul; iVertex < geometry->nVertex[iMarker]; iVertex++) { + auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + myPoints.push_back(geometry->node[iPoint]->GetGlobalIndex()); + } + } + + const unordered_set markerPoints(myPoints.begin(), myPoints.end()); + + vector numPoints(size); + unsigned long num = myPoints.size(); + SU2_MPI::Allgather(&num, 1, MPI_UNSIGNED_LONG, numPoints.data(), 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + /*--- Global to local map for the halo points of the rank (not covered by the CGeometry map). ---*/ + unordered_map Global2Local; + for (auto iPoint = nPointDomain; iPoint < nPoint; ++iPoint) { + Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; + } + + /*--- Populate elimination list. ---*/ + ExtraVerticesToEliminate.clear(); + + for (int i = 0; i < size; ++i) { + /*--- Send our point list. ---*/ + if (rank == i) { + SU2_MPI::Bcast(myPoints.data(), numPoints[i], MPI_UNSIGNED_LONG, rank, MPI_COMM_WORLD); + continue; + } + + /*--- Receive point list. ---*/ + vector theirPoints(numPoints[i]); + SU2_MPI::Bcast(theirPoints.data(), numPoints[i], MPI_UNSIGNED_LONG, i, MPI_COMM_WORLD); + + for (auto iPointGlobal : theirPoints) { + /*--- Check if the rank has the point. ---*/ + auto it = Global2Local.find(iPointGlobal); + if (it == Global2Local.end()) continue; + + /*--- If the point is not covered by this rank's markers, mark it for elimination. ---*/ + if (markerPoints.count(iPointGlobal) == 0) + ExtraVerticesToEliminate.push_back(it->second); + } + } + +} void CFEASolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, CNumerics **numerics, unsigned short iMesh, unsigned long Iteration, unsigned short RunTime_EqSystem, bool Output) { @@ -2768,6 +2833,15 @@ void CFEASolver::Solve_System(CGeometry *geometry, CConfig *config) { SU2_OMP_PARALLEL { + /*--- Enforce solution at some halo points possibly not covered by essential BC markers. ---*/ + + Jacobian.InitiateComms(LinSysSol, geometry, config, SOLUTION_MATRIX); + Jacobian.CompleteComms(LinSysSol, geometry, config, SOLUTION_MATRIX); + + for (auto iPoint : ExtraVerticesToEliminate) { + Jacobian.EnforceSolutionAtNode(iPoint, LinSysSol.GetBlock(iPoint), LinSysRes); + } + /*--- Solve or smooth the linear system. ---*/ auto iter = System.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index f2c0df295c60..f1db24ec395a 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -157,6 +157,18 @@ CMeshSolver::CMeshSolver(CGeometry *geometry, CConfig *config) : CFEASolver(true /*--- Compute the wall distance using the reference coordinates ---*/ SetWallDistance(geometry, config); + if (size != SINGLE_NODE) { + vector essentialMarkers; + /*--- Markers types covered in SetBoundaryDisplacements. ---*/ + for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (((config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) && + (config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY)) || + (config->GetMarker_All_Deform_Mesh(iMarker) == YES)) { + essentialMarkers.push_back(iMarker); + } + } + Set_VertexEliminationSchedule(geometry, essentialMarkers); + } } void CMeshSolver::SetMinMaxVolume(CGeometry *geometry, CConfig *config, bool updated) { From f9aa579337d481c8786f39eef9d51f587d94c6fb Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Mon, 30 Mar 2020 15:50:05 +0100 Subject: [PATCH 45/79] small fix --- SU2_CFD/src/solvers/CFEASolver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SU2_CFD/src/solvers/CFEASolver.cpp b/SU2_CFD/src/solvers/CFEASolver.cpp index 030950aefcdc..ce4a66a00350 100644 --- a/SU2_CFD/src/solvers/CFEASolver.cpp +++ b/SU2_CFD/src/solvers/CFEASolver.cpp @@ -2125,7 +2125,7 @@ void CFEASolver::BC_Damper(CGeometry *geometry, CNumerics *numerics, CConfig *co unsigned short iNode, iDim; unsigned long indexNode[4] = {0}; - su2double nodeCoord[4][3] = {0.0}; + su2double nodeCoord[4][3] = {{0.0}}; bool quad = (geometry->bound[val_marker][iElem]->GetVTK_Type() == QUADRILATERAL); unsigned short nNodes = quad? 4 : nDim; @@ -2831,8 +2831,6 @@ void CFEASolver::GeneralizedAlpha_UpdateLoads(CGeometry *geometry, CSolver **sol void CFEASolver::Solve_System(CGeometry *geometry, CConfig *config) { - SU2_OMP_PARALLEL - { /*--- Enforce solution at some halo points possibly not covered by essential BC markers. ---*/ Jacobian.InitiateComms(LinSysSol, geometry, config, SOLUTION_MATRIX); @@ -2842,6 +2840,8 @@ void CFEASolver::Solve_System(CGeometry *geometry, CConfig *config) { Jacobian.EnforceSolutionAtNode(iPoint, LinSysSol.GetBlock(iPoint), LinSysRes); } + SU2_OMP_PARALLEL + { /*--- Solve or smooth the linear system. ---*/ auto iter = System.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); @@ -2851,8 +2851,8 @@ void CFEASolver::Solve_System(CGeometry *geometry, CConfig *config) { SetResLinSolver(System.GetResidual()); } //SU2_OMP_BARRIER - } // end SU2_OMP_PARALLEL + } From bf4366b4d31a9852314a90471425e544801fce33 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Mon, 30 Mar 2020 23:22:50 +0100 Subject: [PATCH 46/79] ensure MPI-independence (consistent ordering of donor points) of RBF interpolation --- .../CRadialBasisFunction.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp index 7938efb4a364..80647309fdaf 100644 --- a/Common/src/interface_interpolation/CRadialBasisFunction.cpp +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -172,6 +172,22 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { delete[] Buffer_Receive_Coord; delete[] Buffer_Receive_GlobalPoint; + /*--- Give an MPI-independent order to the points (required due to high condition + * number of the RBF matrix, avoids diff results with diff number of ranks. ---*/ + vector order(nGlobalVertexDonor); + iota(order.begin(), order.end(), 0); + sort(order.begin(), order.end(), [&donorPoint](int i, int j){return donorPoint[i] < donorPoint[j];}); + + for (int i = 0; i < int(nGlobalVertexDonor); ++i) { + int j = order[i]; + while (j < i) j = order[j]; + if (i == j) continue; + swap(donorProc[i], donorProc[j]); + swap(donorPoint[i], donorPoint[j]); + for (int iDim = 0; iDim < nDim; ++iDim) + swap(donorCoord(i,iDim), donorCoord(j,iDim)); + } + /*--- Static work scheduling over ranks based on which one has less work currently. ---*/ int iProcessor = 0; for (int i = 1; i < nProcessor; ++i) From c120270be3239468986de06f048a267667191168 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 31 Mar 2020 08:56:40 +0100 Subject: [PATCH 47/79] MPI-independent nearest neighbor search --- Common/src/interface_interpolation/CNearestNeighbor.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Common/src/interface_interpolation/CNearestNeighbor.cpp b/Common/src/interface_interpolation/CNearestNeighbor.cpp index e1369f19aef0..2d6f4289d54a 100644 --- a/Common/src/interface_interpolation/CNearestNeighbor.cpp +++ b/Common/src/interface_interpolation/CNearestNeighbor.cpp @@ -38,6 +38,10 @@ struct DonorInfo { int proc; DonorInfo(su2double d = 0.0, unsigned i = 0, int p = 0) : dist(d), pidx(i), proc(p) { } + bool operator< (const DonorInfo& other) const { + /*--- Global index is used as tie-breaker to make sorted order independent of initial. ---*/ + return (dist != other.dist)? (dist < other.dist) : (pidx < other.pidx); + } }; CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, @@ -135,8 +139,7 @@ void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { } /*--- Find k closest points. ---*/ - partial_sort(donorInfo.begin(), donorInfo.begin()+nDonor, donorInfo.end(), - [](const DonorInfo& a, const DonorInfo& b){return a.dist < b.dist;}); + partial_sort(donorInfo.begin(), donorInfo.begin()+nDonor, donorInfo.end()); /*--- Update stats. ---*/ numTarget += 1; From 259a77093d71a3695e6569ec4564437659e4c438 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 31 Mar 2020 10:47:46 +0100 Subject: [PATCH 48/79] simplify (and fix) FSI load integration --- SU2_CFD/src/solvers/CFEASolver.cpp | 167 ++++++----------------------- 1 file changed, 33 insertions(+), 134 deletions(-) diff --git a/SU2_CFD/src/solvers/CFEASolver.cpp b/SU2_CFD/src/solvers/CFEASolver.cpp index ce4a66a00350..da0e84e5f078 100644 --- a/SU2_CFD/src/solvers/CFEASolver.cpp +++ b/SU2_CFD/src/solvers/CFEASolver.cpp @@ -2195,44 +2195,38 @@ void CFEASolver::BC_Deforming(CGeometry *geometry, CNumerics *numerics, CConfig void CFEASolver::Integrate_FSI_Loads(CGeometry *geometry, CConfig *config) { - unsigned short iDim, iNode, nNode; - unsigned long iPoint, iElem, nElem; + const auto nMarker = config->GetnMarker_All(); + const auto nMarkerInt = config->GetMarker_n_ZoneInterface()/2u; - unsigned short iMarkerInt, nMarkerInt = config->GetMarker_n_ZoneInterface()/2, - iMarker, nMarker = config->GetnMarker_All(); + unordered_map vertexArea; - /*--- Temporary storage to store the forces on the element faces ---*/ - vector forces; + /*--- Compute current area associated with each vertex. ---*/ - /*--- Loop through the FSI interface pairs ---*/ - /*--- 1st pass to compute forces ---*/ - for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; ++iMarkerInt) { - /*--- Find the marker index associated with the pair ---*/ + for (auto iMarkerInt = 1u; iMarkerInt <= nMarkerInt; ++iMarkerInt) { + /*--- Find the marker index associated with the pair. ---*/ + unsigned short iMarker; for (iMarker = 0; iMarker < nMarker; ++iMarker) if (config->GetMarker_All_ZoneInterface(iMarker) == iMarkerInt) break; - /*--- The current mpi rank may not have this marker ---*/ + /*--- The current mpi rank may not have this marker. ---*/ if (iMarker == nMarker) continue; - nElem = geometry->GetnElem_Bound(iMarker); - - for (iElem = 0; iElem < nElem; ++iElem) { - /*--- Define the boundary element ---*/ - unsigned long nodeList[4]; - su2double coords[4][3]; + for (auto iElem = 0u; iElem < geometry->GetnElem_Bound(iMarker); ++iElem) { + /*--- Define the boundary element. ---*/ + unsigned long nodeList[4] = {0}; + su2double coords[4][3] = {{0.0}}; bool quad = geometry->bound[iMarker][iElem]->GetVTK_Type() == QUADRILATERAL; - nNode = quad? 4 : nDim; + auto nNode = quad? 4u : nDim; - for (iNode = 0; iNode < nNode; ++iNode) { + for (auto iNode = 0u; iNode < nNode; ++iNode) { nodeList[iNode] = geometry->bound[iMarker][iElem]->GetNode(iNode); - for (iDim = 0; iDim < nDim; ++iDim) + for (auto iDim = 0u; iDim < nDim; ++iDim) coords[iNode][iDim] = geometry->node[nodeList[iNode]]->GetCoord(iDim)+ nodes->GetSolution(nodeList[iNode],iDim); } - /*--- Compute the area ---*/ - - su2double normal[3] = {0.0, 0.0, 0.0}; + /*--- Compute the area contribution to each node. ---*/ + su2double normal[3] = {0.0}; switch (nNode) { case 2: LineNormal(coords, normal); break; @@ -2240,125 +2234,30 @@ void CFEASolver::Integrate_FSI_Loads(CGeometry *geometry, CConfig *config) { case 4: QuadrilateralNormal(coords, normal); break; } - su2double area = sqrt(pow(normal[0],2) + pow(normal[1],2) + pow(normal[2],2)); - - /*--- Integrate ---*/ - passivedouble weight = 1.0/nNode; - su2double force[3] = {0.0, 0.0, 0.0}; - - for (iNode = 0; iNode < nNode; ++iNode) - for (iDim = 0; iDim < nDim; ++iDim) - force[iDim] += weight*area*nodes->Get_FlowTraction(nodeList[iNode],iDim); - - for (iDim = 0; iDim < nDim; ++iDim) forces.push_back(force[iDim]); - } - } - - /*--- 2nd pass to set values. This is to account for overlap in the markers. ---*/ - /*--- By putting the integrated values back into the nodes no changes have to be made elsewhere. ---*/ - nodes->Clear_FlowTraction(); - - vector::iterator force_it = forces.begin(); - - for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; ++iMarkerInt) { - /*--- Find the marker index associated with the pair ---*/ - for (iMarker = 0; iMarker < nMarker; ++iMarker) - if (config->GetMarker_All_ZoneInterface(iMarker) == iMarkerInt) - break; - /*--- The current mpi rank may not have this marker ---*/ - if (iMarker == nMarker) continue; - - nElem = geometry->GetnElem_Bound(iMarker); - - for (iElem = 0; iElem < nElem; ++iElem) { - bool quad = geometry->bound[iMarker][iElem]->GetVTK_Type() == QUADRILATERAL; - nNode = quad? 4 : nDim; - passivedouble weight = 1.0/nNode; - - su2double force[3]; - for (iDim = 0; iDim < nDim; ++iDim) force[iDim] = *(force_it++)*weight; + su2double area = sqrt(pow(normal[0],2) + pow(normal[1],2) + pow(normal[2],2)) / nNode; - for (iNode = 0; iNode < nNode; ++iNode) { - iPoint = geometry->bound[iMarker][iElem]->GetNode(iNode); - nodes->Add_FlowTraction(iPoint,force); + /*--- Update area of nodes. ---*/ + for (auto iNode = 0u; iNode < nNode; ++iNode) { + auto iPoint = nodeList[iNode]; + if (vertexArea.count(iPoint) == 0) + vertexArea[iPoint] = area; + else + vertexArea[iPoint] += area; } } } -#ifdef HAVE_MPI - /*--- Perform a global reduction, every rank will get the nodal values of all halo elements ---*/ - /*--- This should be cheaper than the "normal" way, since very few points are both halo and interface ---*/ - vector halo_point_loc, halo_point_glb; - vector halo_force; - - for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; ++iMarkerInt) { - /*--- Find the marker index associated with the pair ---*/ - for (iMarker = 0; iMarker < nMarker; ++iMarker) - if (config->GetMarker_All_ZoneInterface(iMarker) == iMarkerInt) - break; - /*--- The current mpi rank may not have this marker ---*/ - if (iMarker == nMarker) continue; - - nElem = geometry->GetnElem_Bound(iMarker); - - for (iElem = 0; iElem < nElem; ++iElem) { - bool quad = geometry->bound[iMarker][iElem]->GetVTK_Type() == QUADRILATERAL; - nNode = quad? 4 : nDim; + /*--- Integrate tractions. ---*/ - /*--- If this is an halo element we share the nodal forces ---*/ - for (iNode = 0; iNode < nNode; ++iNode) - if (!geometry->node[geometry->bound[iMarker][iElem]->GetNode(iNode)]->GetDomain()) - break; - - if (iNode < nNode) { - for (iNode = 0; iNode < nNode; ++iNode) { - iPoint = geometry->bound[iMarker][iElem]->GetNode(iNode); - /*--- local is for when later we update the values in this rank ---*/ - halo_point_loc.push_back(iPoint); - halo_point_glb.push_back(geometry->node[iPoint]->GetGlobalIndex()); - for (iDim = 0; iDim < nDim; ++iDim) - halo_force.push_back(nodes->Get_FlowTraction(iPoint,iDim)); - } - } - } - } - /*--- Determine the size of the arrays we need ---*/ - unsigned long nHaloLoc = halo_point_loc.size(); - unsigned long nHaloMax; - MPI_Allreduce(&nHaloLoc,&nHaloMax,1,MPI_UNSIGNED_LONG,MPI_MAX,MPI_COMM_WORLD); - - /*--- Shared arrays, all the: number of halo points; halo point global indices; respective forces ---*/ - unsigned long *halo_point_num = new unsigned long[size]; - unsigned long *halo_point_all = new unsigned long[size*nHaloMax]; - su2double *halo_force_all = new su2double[size*nHaloMax*nDim]; - - /*--- Make "allgathers" extra safe by resizing all vectors to the same size (some - issues observed when nHaloLoc = 0, especially with the discrete adjoint. ---*/ - halo_point_glb.resize(nHaloMax,0); - halo_force.resize(nHaloMax*nDim,0.0); - - MPI_Allgather(&nHaloLoc,1,MPI_UNSIGNED_LONG,halo_point_num,1,MPI_UNSIGNED_LONG,MPI_COMM_WORLD); - MPI_Allgather(halo_point_glb.data(),nHaloMax,MPI_UNSIGNED_LONG,halo_point_all,nHaloMax,MPI_UNSIGNED_LONG,MPI_COMM_WORLD); - SU2_MPI::Allgather(halo_force.data(),nHaloMax*nDim,MPI_DOUBLE,halo_force_all,nHaloMax*nDim,MPI_DOUBLE,MPI_COMM_WORLD); - - /*--- Find shared points with other ranks and update our values ---*/ - for (int proc = 0; proc < size; ++proc) - if (proc != rank) { - unsigned long offset = proc*nHaloMax; - for (iPoint = 0; iPoint < halo_point_num[proc]; ++iPoint) { - unsigned long iPoint_glb = halo_point_all[offset+iPoint]; - ptrdiff_t pos = find(halo_point_glb.begin(),halo_point_glb.end(),iPoint_glb)-halo_point_glb.begin(); - if (pos < long(halo_point_glb.size())) { - unsigned long iPoint_loc = halo_point_loc[pos]; - nodes->Add_FlowTraction(iPoint_loc,&halo_force_all[(offset+iPoint)*nDim]); - } - } + for (auto it = vertexArea.begin(); it != vertexArea.end(); ++it) { + auto iPoint = it->first; + su2double area = it->second; + su2double force[3] = {0.0}; + for (auto iDim = 0u; iDim < nDim; ++iDim) + force[iDim] = nodes->Get_FlowTraction(iPoint,iDim)*area; + nodes->Set_FlowTraction(iPoint, force); } - delete [] halo_point_num; - delete [] halo_point_all; - delete [] halo_force_all; -#endif } su2double CFEASolver::Compute_LoadCoefficient(su2double CurrentTime, su2double RampTime, CConfig *config){ From cf259f3e4359671166d72231f0ee66b993a0164a Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 31 Mar 2020 10:57:41 +0100 Subject: [PATCH 49/79] update jones turbo case from merge with develop --- TestCases/parallel_regression.py | 4 ++-- TestCases/serial_regression.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/TestCases/parallel_regression.py b/TestCases/parallel_regression.py index 1cfcf1f85b62..cdb016b222fa 100644 --- a/TestCases/parallel_regression.py +++ b/TestCases/parallel_regression.py @@ -834,7 +834,7 @@ def main(): Jones_tc.cfg_dir = "turbomachinery/APU_turbocharger" Jones_tc.cfg_file = "Jones.cfg" Jones_tc.test_iter = 5 - Jones_tc.test_vals = [-5.300315, 0.365966, 44.731500, 2.271371] #last 4 columns + Jones_tc.test_vals = [-5.280323, 0.379654, 44.725390, 2.271597] #last 4 columns Jones_tc.su2_exec = "parallel_computation.py -f" Jones_tc.timeout = 1600 Jones_tc.new_output = False @@ -846,7 +846,7 @@ def main(): Jones_tc_rst.cfg_dir = "turbomachinery/APU_turbocharger" Jones_tc_rst.cfg_file = "Jones_rst.cfg" Jones_tc_rst.test_iter = 5 - Jones_tc_rst.test_vals = [-4.626438, -1.570818, 34.014660, 10.187090] #last 4 columns + Jones_tc_rst.test_vals = [-4.625216, -1.569511, 34.013520, 10.187670] #last 4 columns Jones_tc_rst.su2_exec = "parallel_computation.py -f" Jones_tc_rst.timeout = 1600 Jones_tc_rst.new_output = False diff --git a/TestCases/serial_regression.py b/TestCases/serial_regression.py index 69cd1536926e..065017913e88 100644 --- a/TestCases/serial_regression.py +++ b/TestCases/serial_regression.py @@ -983,7 +983,7 @@ def main(): Jones_tc.cfg_dir = "turbomachinery/APU_turbocharger" Jones_tc.cfg_file = "Jones.cfg" Jones_tc.test_iter = 5 - Jones_tc.test_vals = [-5.300315, 0.365965, 44.731520, 2.271338] #last 4 columns + Jones_tc.test_vals = [-5.280323, 0.379653, 44.725410, 2.271564] #last 4 columns Jones_tc.su2_exec = "SU2_CFD" Jones_tc.new_output = False Jones_tc.timeout = 1600 @@ -995,7 +995,7 @@ def main(): Jones_tc_rst.cfg_dir = "turbomachinery/APU_turbocharger" Jones_tc_rst.cfg_file = "Jones_rst.cfg" Jones_tc_rst.test_iter = 5 - Jones_tc_rst.test_vals = [-4.626481, -1.570875, 34.015260, 10.187090] #last 4 columns + Jones_tc_rst.test_vals = [-4.625262, -1.569571, 34.014130, 10.187660] #last 4 columns Jones_tc_rst.su2_exec = "SU2_CFD" Jones_tc_rst.new_output = False Jones_tc_rst.timeout = 1600 From 96802c6d584e2111f89cfd428d863ef133401ef5 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 31 Mar 2020 12:05:16 +0100 Subject: [PATCH 50/79] avoid residual changes for mesh deformation cases --- Common/include/linear_algebra/CSysSolve.hpp | 11 +++++++++++ Common/src/linear_algebra/CSysSolve.cpp | 20 ++++++++++++++++++++ SU2_CFD/src/solvers/CMeshSolver.cpp | 1 + 3 files changed, 32 insertions(+) diff --git a/Common/include/linear_algebra/CSysSolve.hpp b/Common/include/linear_algebra/CSysSolve.hpp index df2848de37da..8f514a1c5bc3 100644 --- a/Common/include/linear_algebra/CSysSolve.hpp +++ b/Common/include/linear_algebra/CSysSolve.hpp @@ -48,6 +48,10 @@ template class CPreconditioner; using namespace std; +/*--- Relative tolerance, target residual is tol*||b-Ax||, + * Absolute tolerance, target residual is tol*||b||. ---*/ +enum class LinearToleranceType {RELATIVE, ABSOLUTE}; + /*! * \class CSysSolve * \brief Class for solving linear systems using classical and Krylov-subspace iterative methods @@ -98,6 +102,8 @@ class CSysSolve { VectorType* LinSysSol_ptr; /*!< \brief Pointer to appropriate LinSysSol (set to original or temporary in call to Solve). */ const VectorType* LinSysRes_ptr; /*!< \brief Pointer to appropriate LinSysRes (set to original or temporary in call to Solve). */ + LinearToleranceType tol_type = LinearToleranceType::RELATIVE; /*!< \brief How the linear solvers interpret the tolerance. */ + /*! * \brief sign transfer function * \param[in] x - value having sign prescribed @@ -313,4 +319,9 @@ class CSysSolve { */ inline ScalarType GetResidual(void) const { return Residual; } + /*! + * \brief Set the type of the tolerance for stoping the linear solvers (RELATIVE or ABSOLUTE). + */ + inline void SetToleranceType(LinearToleranceType type) {tol_type = type;} + }; diff --git a/Common/src/linear_algebra/CSysSolve.cpp b/Common/src/linear_algebra/CSysSolve.cpp index 334654f157bb..8e3118832f3c 100644 --- a/Common/src/linear_algebra/CSysSolve.cpp +++ b/Common/src/linear_algebra/CSysSolve.cpp @@ -239,6 +239,11 @@ unsigned long CSysSolve::CG_LinSolver(const CSysVector & return 0; } + /*--- Set the norm to the initial initial residual value ---*/ + + if (tol_type == LinearToleranceType::RELATIVE) + norm0 = norm_r; + /*--- Output header information including initial residual ---*/ if ((monitoring) && (master)) { @@ -394,6 +399,11 @@ unsigned long CSysSolve::FGMRES_LinSolver(const CSysVector::BCGSTAB_LinSolver(const CSysVector::Smoother_LinSolver(const CSysVector Date: Tue, 31 Mar 2020 12:09:53 +0100 Subject: [PATCH 51/79] re-delete files after merge with develop --- Common/include/interpolation_structure.hpp | 491 --- Common/src/interpolation_structure.cpp | 3849 -------------------- 2 files changed, 4340 deletions(-) delete mode 100644 Common/include/interpolation_structure.hpp delete mode 100644 Common/src/interpolation_structure.cpp diff --git a/Common/include/interpolation_structure.hpp b/Common/include/interpolation_structure.hpp deleted file mode 100644 index 3ea27b746b9d..000000000000 --- a/Common/include/interpolation_structure.hpp +++ /dev/null @@ -1,491 +0,0 @@ -/*! - * \file interpolation_structure.hpp - * \brief Headers of classes used for multiphysics interpolation. - * The implementation is in the interpolation_structure.cpp file. - * \author H. Kline - * \version 7.0.3 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ - -#pragma once - -#include "../../Common/include/mpi_structure.hpp" - -#include -#include -#include -#include -#include - -#include "CConfig.hpp" -#include "geometry/CGeometry.hpp" - -using namespace std; - - -/*! - * \class CInterpolator - * \brief Main class for defining the interpolator, it requires - * a child class for each particular interpolation method - * \author H. Kline - */ -class CInterpolator { -protected: - int rank, /*!< \brief MPI Rank. */ - size; /*!< \brief MPI Size. */ - unsigned int nZone; /*!< \brief Number of zones*/ - unsigned int donorZone, - targetZone; /*!< \brief Type of MPI zone */ - - unsigned long - MaxLocalVertex_Donor, /*!< \brief Maximum vertices per processor*/ - nGlobalFace_Donor, /*!< \brief Number of global donor faces*/ - nGlobalFaceNodes_Donor, /*!< \brief Number of global donor face nodes*/ - MaxFace_Donor, /*!< \brief Maximum faces per processor*/ - MaxFaceNodes_Donor; /*!< \brief Maximum nodes associated with faces per processor*/ - - unsigned long - *Buffer_Receive_nVertex_Donor, /*!< \brief Buffer to store the number of vertices per processor on the Donor domain */ - *Buffer_Receive_nFace_Donor, /*!< \brief Buffer to store the number of faces per processor*/ - *Buffer_Receive_nFaceNodes_Donor, /*!< \brief Buffer to store the number of nodes associated with faces per processor*/ - *Buffer_Send_nVertex_Donor, /*!< \brief Buffer to send number of vertices on the local processor*/ - *Buffer_Send_nFace_Donor, /*!< \brief Buffer to send number of faces on the local processor*/ - *Buffer_Send_nFaceNodes_Donor, /*!< \brief Buffer to send the number of nodes assocated with faces per processor*/ - *Buffer_Send_FaceIndex, /*!< \brief Buffer to send indices pointing to the node indices that define the faces*/ - *Buffer_Receive_FaceIndex, /*!< \brief Buffer to receive indices pointing to the node indices that define the faces*/ - *Buffer_Send_FaceNodes, /*!< \brief Buffer to send indices pointing to the location of node information in other buffers, defining faces*/ - *Buffer_Receive_FaceNodes, /*!< \brief Buffer to receive indices pointing to the location of node information in other buffers, defining faces*/ - *Buffer_Send_FaceProc, /*!< \brief Buffer to send processor which stores the node indicated in Buffer_Receive_FaceNodes*/ - *Buffer_Receive_FaceProc; /*!< \brief Buffer to receive processor which stores the node indicated in Buffer_Receive_FaceNodes*/ - - long *Buffer_Send_GlobalPoint, /*!< \brief Buffer to send global point indices*/ - *Buffer_Receive_GlobalPoint; /*!< \brief Buffer to receive global point indices*/ - - su2double *Buffer_Send_Coord, /*!< \brief Buffer to send coordinate values*/ - *Buffer_Send_Normal, /*!< \brief Buffer to send normal vector values */ - *Buffer_Receive_Coord, /*!< \brief Buffer to receive coordinate values*/ - *Buffer_Receive_Normal; /*!< \brief Buffer to receive normal vector values*/ - - unsigned long *Receive_GlobalPoint, /*!< \brief Buffer to receive Global point indexes*/ - *Buffer_Receive_nLinkedNodes, /*!< \brief Buffer to receive the number of edges connected to each node*/ - *Buffer_Receive_LinkedNodes, /*!< \brief Buffer to receive the list of notes connected to the nodes through an edge*/ - *Buffer_Receive_StartLinkedNodes, /*!< \brief Buffer to receive the index of the Receive_LinkedNodes buffer where corresponding list of linked nodes begins */ - *Buffer_Receive_Proc; /*!< \brief Buffer to receive the thread that owns the node*/ - - unsigned long nGlobalVertex_Target, /*!< \brief Global number of vertex of the target boundary*/ - nLocalVertex_Target, /*!< \brief Number of vertex of the target boundary owned by the thread*/ - nGlobalVertex_Donor, /*!< \brief Global number of vertex of the donor boundary*/ - nLocalVertex_Donor, /*!< \brief Number of vertex of the donor boundary owned by the thread*/ - nGlobalVertex, /*!< \brief Dummy variable to temporarily store the global number of vertex of a boundary*/ - nLocalLinkedNodes; /*!< \brief Dummy variable to temporarily store the number of vertex of a boundary*/ - -public: - CGeometry**** Geometry; /*! \brief Vector which stores n zones of geometry. */ - CGeometry* donor_geometry; /*! \brief Vector which stores the donor geometry. */ - CGeometry* target_geometry; /*! \brief Vector which stores the target geometry. */ - - /*! - * \brief Constructor of the class. - */ - CInterpolator(void); - - /*! - * \brief Constructor of the class. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - index of the donor zone - * \param[in] jZone - index of the target zone - */ - CInterpolator(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - - /*! - * \brief Destructor of the class. - */ - virtual ~CInterpolator(void); - - /*! - * \brief Find the index of the interface marker shared by that zone - * \param[in] config - Definition of the particular problem. - * \param[in] val_marker_interface - Interface tag. - */ - int Find_InterfaceMarker(CConfig *config, unsigned short val_marker_interface); - - /*! - * \brief Check whether the interface should be processed or not - * \param[in] val_markDonor - Marker tag from donor zone. - * \param[in] val_markTarget - Marker tag from target zone. - */ - bool CheckInterfaceBoundary(int val_markDonor, int val_markTarget); - - /*! - * \brief Recontstruct the boundary connectivity from parallel partitioning and broadcasts it to all threads - * \param[in] val_zone - index of the zone - * \param[in] val_marker - index of the marker - */ - void ReconstructBoundary(unsigned long val_zone, int val_marker); - - /*! - * \brief compute distance between 2 points - * \param[in] point_i - * \param[in] point_i - */ - su2double PointsDistance(su2double *point_i, su2double *point_j); - - /*! - * \brief Set up transfer matrix defining relation between two meshes - * \param[in] config - Definition of the particular problem. - */ - virtual void Set_TransferCoeff(CConfig **config); - - /*! - * \brief Determine array sizes used to collect and send coordinate and global point - * information. - * \param[in] faces - boolean that determines whether or not to set face information as well - * \param[in] markDonor - Index of the boundary on the donor domain. - * \param[in] markTarget - Index of the boundary on the target domain. - * \param[in] nVertexDonor - Number of vertices on the donor boundary. - * \param[in] nDim - number of physical dimensions. - */ - void Determine_ArraySize(bool faces, int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim); - - /*! - * \brief Collect and communicate vertex info: coord, global point, and if faces=true the normal vector - * \param[in] faces - boolean that determines whether or not to set face information as well - * \param[in] markDonor - Index of the boundary on the donor domain. - * \param[in] markTarget - Index of the boundary on the target domain. - * \param[in] nVertexDonor - Number of vertices on the donor boundary. - * \param[in] nDim - number of physical dimensions. - */ - void Collect_VertexInfo(bool faces, int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim); - -}; - -/*! - * \brief Nearest Neighbor interpolation - */ -class CNearestNeighbor : public CInterpolator { -public: - - /*! - * \brief Constructor of the class. - */ - CNearestNeighbor(void); - - /*! - * \brief Constructor of the class. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - index of the donor zone - * \param[in] jZone - index of the target zone - */ - CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - - /*! - * \brief Destructor of the class. - */ - ~CNearestNeighbor(void); - - /*! - * \brief Set up transfer matrix defining relation between two meshes - * \param[in] config - Definition of the particular problem. - */ - void Set_TransferCoeff(CConfig **config); - -}; - -/*! - * \brief Isoparametric interpolation - */ -class CIsoparametric : public CInterpolator { -public: - - /*! - * \brief Constructor of the class. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - index of the donor zone - * \param[in] jZone - index of the target zone - */ - CIsoparametric(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - - /*! - * \brief Destructor of the class. - */ - ~CIsoparametric(void); - - /*! - * \brief Set up transfer matrix defining relation between two meshes - * \param[in] config - Definition of the particular problem. - */ - void Set_TransferCoeff(CConfig **config); - - /*! - * \brief Calculate the isoparametric representation of point iVertex in marker iZone_0 by nodes of element donor_elem in marker jMarker of zone iZone_1. - * \param[in] iVertex - vertex index of the point being interpolated. - * \param[in] nDim - the dimension of the coordinates. - * \param[in] iZone_1 - zone index of the element to use for interpolation (the DONOR zone) - * \param[in] donor_elem - element index of the element to use for interpolation (or global index of a point in 2D) - * \param[in] nDonorPoints - number of donor points in the element. - * \param[in] xj - point projected onto the plane of the donor element. - * \param[out] isoparams - isoparametric coefficients. Must be allocated to size nNodes ahead of time. (size> nDonors) - * - * If the problem is 2D, the 'face' projected onto is actually an edge; the local index - * of the edge is then stored in iFace, and the global index of the node (from which the edge - * is referenced) - */ - void Isoparameters(unsigned short nDim, unsigned short nDonor, su2double *X, su2double *xj,su2double* isoparams); - -}; - -/*! - * \brief Mirror interpolation: copy point linking and coefficient values from the opposing mesh - * Assumes that the oppoosing mesh has already run interpolation. (otherwise this will result in empty/trivial interpolation) - */ -class CMirror : public CInterpolator { -public: - - /*! - * \brief Constructor of the class. - * \param[in] geometry_container - * \param[in] config - config container - * \param[in] iZone - First zone - * \param[in] jZone - Second zone - * - * Data is set in geometry[targetZone] - * - */ - CMirror(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - - /*! - * \brief Destructor of the class. - */ - ~CMirror(void); - - /*! - * \brief Set up transfer matrix defining relation between two meshes - * \param[in] config - Definition of the particular problem. - */ - void Set_TransferCoeff(CConfig **config); - -}; - -/*! - * \brief Sliding mesh approach - */ -class CSlidingMesh : public CInterpolator { -public: - - /*! - * \brief Constructor of the class. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - index of the donor zone - * \param[in] jZone - index of the target zone - */ - CSlidingMesh(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - - /*! - * \brief Destructor of the class. - */ - ~CSlidingMesh(void); - - /*! - * \brief Set up transfer matrix defining relation between two meshes - * \param[in] config - Definition of the particular problem. - */ - void Set_TransferCoeff(CConfig **config); - - /*! - * \brief For 3-Dimensional grids, build the dual surface element - * \param[in] map - array containing the index of the boundary points connected to the node - * \param[in] startIndex - for each vertex specifies the corresponding index in the global array containing the indexes of all its neighbouring vertexes - * \param[in] nNeighbour - for each vertex specifies the number of its neighbouring vertexes (on the boundary) - * \param[in] coord - array containing the coordinates of all the boundary vertexes - * \param[in] centralNode - label of the vertex around which the dual surface element is built - * \param[in] element - double array where element node coordinates will be stored - */ - int Build_3D_surface_element(unsigned long *map, unsigned long *startIndex, unsigned long* nNeighbor, su2double *coord, unsigned long centralNode, su2double** element); - - /*! - * \brief For 2-Dimensional grids, compute intersection length of two segments projected along a given direction - * \param[in] A1 - first point of segment A - * \param[in] A2 - second point of segment A - * \param[in] B1 - first point of segment B - * \param[in] B2 - second point of segment B - * \param[in] Direction - along which segments are projected - */ - su2double ComputeLineIntersectionLength(su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* Direction); - - /*! - * \brief For 3-Dimensional grids, compute intersection area between two triangle projected on a given plane - * \param[in] A1 - first point of triangle A - * \param[in] A2 - second point of triangle A - * \param[in] A3 - third point of triangle A - * \param[in] B1 - first point of triangle B - * \param[in] B2 - second point of triangle B - * \param[in] B3 - third point of triangle B - * \param[in] Direction - vector normal to projection plane - */ - su2double Compute_Triangle_Intersection(su2double* A1, su2double* A2, su2double* A3, su2double* B1, su2double* B2, su2double* B3, su2double* Direction); - - /*! - * \brief For 3-Dimensional grids, compute intersection area between two triangle projected on a given plane - * P1 from triangle P MUST be inside triangle Q, points order doesn't matter - * \param[in] P1 - first point of triangle A - * \param[in] P2 - second point of triangle A - * \param[in] P3 - third point of triangle A - * \param[in] Q1 - first point of triangle B - * \param[in] Q2 - second point of triangle B - * \param[in] Q3 - third point of triangle B - */ - su2double ComputeIntersectionArea( su2double* P1, su2double* P2, su2double* P3, su2double* Q1, su2double* Q2, su2double* Q3 ); - - /*! - * \brief For 2-Dimensional grids, check whether, and compute, two lines are intersecting - * \param[in] A1 - first defining first line - * \param[in] A2 - second defining first line - * \param[in] B1 - first defining second line - * \param[in] B2 - second defining second line - * \param[in] IntersectionPoint - Container for intersection coordinates - */ - void ComputeLineIntersectionPoint( su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* IntersectionPoint ); - - /*! - * \brief For N-Dimensional grids, check whether a point is inside a triangle specified by 3 T points - * \param[in] Point - query point - * \param[in] T1 - first point of triangle T - * \param[in] T2 - second point of triangle T - * \param[in] T3 - third point of triangle T - */ - bool CheckPointInsideTriangle(su2double* Point, su2double* T1, su2double* T2, su2double* T3); -}; - -/*! - * \brief Radial basis function interpolation - */ -class CRadialBasisFunction : public CInterpolator { -public: - - /*! - * \brief Constructor of the class. - */ - CRadialBasisFunction(void); - - /*! - * \brief Constructor of the class. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iZone - index of the donor zone - * \param[in] jZone - index of the target zone - */ - CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone); - - /*! - * \brief Destructor of the class. - */ - ~CRadialBasisFunction(void); - - /*! - * \brief Set up transfer matrix defining relation between two meshes - * \param[in] config - Definition of the particular problem. - */ - void Set_TransferCoeff(CConfig **config); - - /*! - * \brief Compute the value of a radial basis function, this is static so it can be re-used. - * \param[in] type - of radial basis function - * \param[in] radius - the characteristic dimension - * \param[in] dist - distance - */ - static su2double Get_RadialBasisValue(const short unsigned int type, const su2double &radius, const su2double &dist); - -private: - /*! - * \brief If the polynomial term is included in the interpolation, and the points lie on a plane, the matrix becomes rank deficient - * and cannot be inverted. This method detects that condition and corrects it by removing a row from P (the polynomial part of the matrix). - * \param[in] m - number of rows of P - * \param[in] n - number of columns of P - * \param[in] skip_row - marks the row of P which is all ones (by construction) - * \param[in] max_diff_tol_in - tolerance to detect points are on a plane - * \param[out] keep_row - marks the rows of P kept - * \param[out] n_polynomial - size of the polynomial part on exit (i.e. new number of rows) - * \param[in,out] P - polynomial part of the matrix, may be changed or not! - */ - void Check_PolynomialTerms(int m, unsigned long n, const int *skip_row, su2double max_diff_tol_in, int *keep_row, int &n_polynomial, su2double *P); - -}; - -/*! - * \brief Helper class used by CRadialBasisFunction to calculate the interpolation weights. - * This does not inherit from CSysMatrix because: it is a dense format rather than block sparse; - * as the interpolation is done on a single core there are no methods for communication. - * The code can be compiled with LAPACK to use optimized matrix inversion and multiplication routines. - * CPPFLAGS="-DHAVE_LAPACK" LDFLAGS=-L/path/to/lapack_lib LIBS="-llapack -lrefblas -lgfortran" - */ -class CSymmetricMatrix{ - - private: - - bool initialized, inversed; - int sz, num_val; - int *perm_vec; - passivedouble *val_vec, *decompose_vec, *inv_val_vec; - - enum DecompositionType { none, cholesky, lu }; - - DecompositionType decomposed; - - inline int CalcIdx(int i, int j); - inline int CalcIdxFull(int i, int j); - inline void CheckBounds(int i, int j); - - passivedouble ReadL(int i, int j); - passivedouble ReadU(int i, int j); - passivedouble ReadInv(int i,int j); - - // not optimized dense matrix factorization and inversion for portability - void CholeskyDecompose(bool overwrite); - void LUDecompose(); - void CalcInv(bool overwrite); - // matrix inversion using LAPACK routines (LDLT factorization) - void CalcInv_sptri(); - void CalcInv_potri() {}; // LLT not implemented yet - - public: - - /*--- Methods ---*/ - CSymmetricMatrix(); - ~CSymmetricMatrix(); - - void Initialize(int N); - void Initialize(int N, su2double *formed_val_vec); - - inline int GetSize(); - - void Write(int i, int j, const su2double& val); - passivedouble Read(int i, int j); - - void MatVecMult(passivedouble *v); - void MatMatMult(bool left_mult, su2double *mat_vec, int N); - void Invert(const bool is_spd); - -}; diff --git a/Common/src/interpolation_structure.cpp b/Common/src/interpolation_structure.cpp deleted file mode 100644 index 2cf20d8ec7e5..000000000000 --- a/Common/src/interpolation_structure.cpp +++ /dev/null @@ -1,3849 +0,0 @@ -/*! - * \file interpolation_structure.cpp - * \brief Main subroutines used by SU2_FSI - * \author H. Kline - * \version 7.0.3 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ -#include "../include/interpolation_structure.hpp" - -#if defined(HAVE_MKL) -#include "mkl.h" -#ifndef HAVE_LAPACK -#define HAVE_LAPACK -#endif -#elif defined(HAVE_LAPACK) -/*--- Lapack / Blas routines used in RBF interpolation. ---*/ -extern "C" void dsptrf_(char*, int*, passivedouble*, int*, int*); -extern "C" void dsptri_(char*, int*, passivedouble*, int*, passivedouble*, int*); -extern "C" void dsymm_(char*, char*, int*, int*, passivedouble*, passivedouble*, int*, - passivedouble*, int*, passivedouble*, passivedouble*, int*); -#endif - -CInterpolator::CInterpolator(void) { - - size = SU2_MPI::GetSize(); - rank = SU2_MPI::GetRank(); - - nZone = 0; - Geometry = NULL; - - donor_geometry = NULL; - target_geometry = NULL; - - donorZone = 0; - targetZone = 0; - - Buffer_Receive_nVertex_Donor = NULL; - Buffer_Receive_nFace_Donor = NULL; - Buffer_Receive_nFaceNodes_Donor = NULL; - Buffer_Send_nVertex_Donor = NULL; - Buffer_Send_nFace_Donor = NULL; - Buffer_Send_nFaceNodes_Donor = NULL; - Buffer_Receive_GlobalPoint = NULL; - Buffer_Send_GlobalPoint = NULL; - Buffer_Send_FaceIndex = NULL; - Buffer_Receive_FaceIndex = NULL; - Buffer_Send_FaceNodes = NULL; - Buffer_Receive_FaceNodes = NULL; - Buffer_Send_FaceProc = NULL; - Buffer_Receive_FaceProc = NULL; - - Buffer_Send_Coord = NULL; - Buffer_Send_Normal = NULL; - Buffer_Receive_Coord = NULL; - Buffer_Receive_Normal = NULL; - - Receive_GlobalPoint = NULL; - Buffer_Receive_nLinkedNodes = NULL; - Buffer_Receive_LinkedNodes = NULL; - Buffer_Receive_StartLinkedNodes = NULL; - Buffer_Receive_Proc = NULL; - -} - -CInterpolator::~CInterpolator(void) { - - //if (Buffer_Receive_nVertex_Donor!= NULL) delete[] Buffer_Receive_nVertex_Donor; -} - - -CInterpolator::CInterpolator(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) { - - size = SU2_MPI::GetSize(); - rank = SU2_MPI::GetRank(); - - /* Store pointers*/ - Geometry = geometry_container; - - donorZone = iZone; - targetZone = jZone; - - donor_geometry = geometry_container[donorZone][INST_0][MESH_0]; - target_geometry = geometry_container[targetZone][INST_0][MESH_0]; - - /*--- Initialize transfer coefficients between the zones ---*/ - /* Since this is a virtual function, call it in the child class constructor */ - //Set_TransferCoeff(targetZone,donorZone,config); - /*--- Initialize transfer coefficients between the zones ---*/ - //Set_TransferCoeff(Zones,config); - - //Buffer_Receive_nVertex_Donor = NULL; - -} - -inline void CInterpolator::Set_TransferCoeff(CConfig **config) { } - -void CInterpolator::Determine_ArraySize(bool faces, int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim) { - unsigned long nLocalVertex_Donor = 0, nLocalFaceNodes_Donor=0, nLocalFace_Donor=0; - unsigned long iVertex, iPointDonor = 0; - /* Only needed if face data is also collected */ - unsigned long inode; - unsigned long donor_elem, jElem, jPoint; - unsigned short iDonor; - unsigned int nFaces=0, iFace, nNodes=0; - bool face_on_marker = true; - - for (iVertex = 0; iVertex < nVertexDonor; iVertex++) { - iPointDonor = donor_geometry->vertex[markDonor][iVertex]->GetNode(); - if (donor_geometry->node[iPointDonor]->GetDomain()) { - nLocalVertex_Donor++; - if (faces) { - /*--- On Donor geometry also communicate face info ---*/ - if (nDim==3) { - for (jElem=0; jElemnode[iPointDonor]->GetnElem(); jElem++) { - donor_elem = donor_geometry->node[iPointDonor]->GetElem(jElem); - nFaces = donor_geometry->elem[donor_elem]->GetnFaces(); - for (iFace=0; iFaceelem[donor_elem]->GetnNodesFace(iFace); - for (iDonor=0; iDonorelem[donor_elem]->GetFaces(iFace, iDonor); - jPoint = donor_geometry->elem[donor_elem]->GetNode(inode); - face_on_marker = (face_on_marker && (donor_geometry->node[jPoint]->GetVertex(markDonor) !=-1)); - } - if (face_on_marker ) { - nLocalFace_Donor++; - nLocalFaceNodes_Donor+=nNodes; - } - } - } - } - else { - /*--- in 2D we use the edges ---*/ - nNodes=2; - nFaces = donor_geometry->node[iPointDonor]->GetnPoint(); - for (iFace=0; iFacenode[iPointDonor]->GetEdge(iFace); - jPoint = donor_geometry->edge[inode]->GetNode(iDonor); - face_on_marker = (face_on_marker && (donor_geometry->node[jPoint]->GetVertex(markDonor) !=-1)); - } - if (face_on_marker ) { - nLocalFace_Donor++; - nLocalFaceNodes_Donor+=nNodes; - } - } - } - } - } - } - - Buffer_Send_nVertex_Donor[0] = nLocalVertex_Donor; - if (faces) { - Buffer_Send_nFace_Donor[0] = nLocalFace_Donor; - Buffer_Send_nFaceNodes_Donor[0] = nLocalFaceNodes_Donor; - } - - /*--- Send Interface vertex information --*/ -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&nLocalVertex_Donor, &MaxLocalVertex_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nVertex_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - if (faces) { - SU2_MPI::Allreduce(&nLocalFace_Donor, &nGlobalFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalFace_Donor, &MaxFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &nGlobalFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &MaxFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFace_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - MaxFace_Donor++; - } -#else - MaxLocalVertex_Donor = nLocalVertex_Donor; - Buffer_Receive_nVertex_Donor[0] = Buffer_Send_nVertex_Donor[0]; - if (faces) { - nGlobalFace_Donor = nLocalFace_Donor; - nGlobalFaceNodes_Donor = nLocalFaceNodes_Donor; - MaxFaceNodes_Donor = nLocalFaceNodes_Donor; - MaxFace_Donor = nLocalFace_Donor+1; - Buffer_Receive_nFace_Donor[0] = Buffer_Send_nFace_Donor[0]; - Buffer_Receive_nFaceNodes_Donor[0] = Buffer_Send_nFaceNodes_Donor[0]; - } -#endif - -} - -void CInterpolator::Collect_VertexInfo(bool faces, int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim) -{ - unsigned long iVertex, iPointDonor = 0, iVertexDonor, nBuffer_Coord, nBuffer_Point, nLocalVertex_Donor; - unsigned short iDim; - - /* Only needed if face data is also collected */ - su2double *Normal; - - for (iVertex = 0; iVertex < MaxLocalVertex_Donor; iVertex++) { - Buffer_Send_GlobalPoint[iVertex] = -1; - for (iDim = 0; iDim < nDim; iDim++) { - Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; - if (faces) - Buffer_Send_Normal[iVertex*nDim+iDim] = 0.0; - } - } - - /*--- Copy coordinates and point to the auxiliar vector --*/ - nLocalVertex_Donor = 0; - - for (iVertexDonor = 0; iVertexDonor < nVertexDonor; iVertexDonor++) { - iPointDonor = donor_geometry->vertex[markDonor][iVertexDonor]->GetNode(); - if (donor_geometry->node[iPointDonor]->GetDomain()) { - Buffer_Send_GlobalPoint[nLocalVertex_Donor] = donor_geometry->node[iPointDonor]->GetGlobalIndex(); - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[nLocalVertex_Donor*nDim+iDim] = donor_geometry->node[iPointDonor]->GetCoord(iDim); - - if (faces) { - Normal = donor_geometry->vertex[markDonor][iVertexDonor]->GetNormal(); - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Normal[nLocalVertex_Donor*nDim+iDim] = Normal[iDim]; - } - nLocalVertex_Donor++; - } - } - nBuffer_Coord = MaxLocalVertex_Donor*nDim; - nBuffer_Point = MaxLocalVertex_Donor; - -#ifdef HAVE_MPI - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_GlobalPoint, nBuffer_Point, MPI_LONG, Buffer_Receive_GlobalPoint, nBuffer_Point, MPI_LONG, MPI_COMM_WORLD); - if (faces) { - SU2_MPI::Allgather(Buffer_Send_Normal, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Normal, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); - } -#else - for (iVertex = 0; iVertex < nBuffer_Coord; iVertex++) - Buffer_Receive_Coord[iVertex] = Buffer_Send_Coord[iVertex]; - - for (iVertex = 0; iVertex < nBuffer_Point; iVertex++) - Buffer_Receive_GlobalPoint[iVertex] = Buffer_Send_GlobalPoint[iVertex]; - - if (faces) { - for (iVertex = 0; iVertex < nBuffer_Coord; iVertex++) - Buffer_Receive_Normal[iVertex] = Buffer_Send_Normal[iVertex]; - } -#endif -} - -int CInterpolator::Find_InterfaceMarker(CConfig *config, unsigned short val_marker_interface) { - - unsigned short nMarker = config->GetnMarker_All(); - unsigned short iMarker; - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - /*--- If the tag GetMarker_All_ZoneInterface(iMarker) equals the index we are looping at ---*/ - if (config->GetMarker_All_ZoneInterface(iMarker) == val_marker_interface ) { - - /*--- We have identified the identifier for the interface marker ---*/ - return iMarker; - } - } - - return -1; -} - - -void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ - - CGeometry *geom = Geometry[val_zone][INST_0][MESH_0]; - - unsigned long iVertex, jVertex, kVertex; - - unsigned long count, iTmp, *uptr, dPoint, EdgeIndex, jEdge, nEdges, nNodes, nVertex, iDim, nDim, iPoint; - - unsigned long nGlobalLinkedNodes, nLocalVertex, nLocalLinkedNodes; - - nDim = geom->GetnDim(); - - if( val_marker != -1 ) - nVertex = geom->GetnVertex( val_marker ); - else - nVertex = 0; - - - su2double *Buffer_Send_Coord = new su2double [ nVertex * nDim ]; - unsigned long *Buffer_Send_GlobalPoint = new unsigned long [ nVertex ]; - - unsigned long *Buffer_Send_nLinkedNodes = new unsigned long [ nVertex ]; - unsigned long *Buffer_Send_StartLinkedNodes = new unsigned long [ nVertex ]; - unsigned long **Aux_Send_Map = new unsigned long*[ nVertex ]; - -#ifdef HAVE_MPI - int nProcessor = size, iRank; - unsigned long iTmp2, tmp_index, tmp_index_2; -#endif - - /*--- Copy coordinates and point to the auxiliar vector ---*/ - - nGlobalVertex = 0; - nLocalVertex = 0; - nLocalLinkedNodes = 0; - - for (iVertex = 0; iVertex < nVertex; iVertex++) { - - Buffer_Send_nLinkedNodes[iVertex] = 0; - Aux_Send_Map[iVertex] = NULL; - - iPoint = geom->vertex[val_marker][iVertex]->GetNode(); - - if (geom->node[iPoint]->GetDomain()) { - Buffer_Send_GlobalPoint[nLocalVertex] = geom->node[iPoint]->GetGlobalIndex(); - - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[nLocalVertex*nDim+iDim] = geom->node[iPoint]->GetCoord(iDim); - - nNodes = 0; - nEdges = geom->node[iPoint]->GetnPoint(); - - for (jEdge = 0; jEdge < nEdges; jEdge++){ - EdgeIndex = geom->node[iPoint]->GetEdge(jEdge); - - if( iPoint == geom->edge[EdgeIndex]->GetNode(0) ) - dPoint = geom->edge[EdgeIndex]->GetNode(1); - else - dPoint = geom->edge[EdgeIndex]->GetNode(0); - - if ( geom->node[dPoint]->GetVertex(val_marker) != -1 ) - nNodes++; - } - - Buffer_Send_StartLinkedNodes[nLocalVertex] = nLocalLinkedNodes; - Buffer_Send_nLinkedNodes[nLocalVertex] = nNodes; - - nLocalLinkedNodes += nNodes; - - Aux_Send_Map[nLocalVertex] = new unsigned long[ nNodes ]; - nNodes = 0; - - for (jEdge = 0; jEdge < nEdges; jEdge++){ - EdgeIndex = geom->node[iPoint]->GetEdge(jEdge); - - if( iPoint == geom->edge[EdgeIndex]->GetNode(0) ) - dPoint = geom->edge[EdgeIndex]->GetNode(1); - else - dPoint = geom->edge[EdgeIndex]->GetNode(0); - - if ( geom->node[dPoint]->GetVertex(val_marker) != -1 ){ - Aux_Send_Map[nLocalVertex][nNodes] = geom->node[dPoint]->GetGlobalIndex(); - nNodes++; - } - } - nLocalVertex++; - } - } - - unsigned long *Buffer_Send_LinkedNodes = new unsigned long [ nLocalLinkedNodes ]; - - nLocalLinkedNodes = 0; - - for (iVertex = 0; iVertex < nLocalVertex; iVertex++){ - for (jEdge = 0; jEdge < Buffer_Send_nLinkedNodes[iVertex]; jEdge++){ - Buffer_Send_LinkedNodes[nLocalLinkedNodes] = Aux_Send_Map[iVertex][jEdge]; - nLocalLinkedNodes++; - } - } - - for (iVertex = 0; iVertex < nVertex; iVertex++){ - if( Aux_Send_Map[iVertex] != NULL ) - delete [] Aux_Send_Map[iVertex]; - } - delete [] Aux_Send_Map; Aux_Send_Map = NULL; - - /*--- Reconstruct boundary by gathering data from all ranks ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Allreduce( &nLocalVertex, &nGlobalVertex, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalLinkedNodes, &nGlobalLinkedNodes, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#else - nGlobalVertex = nLocalVertex; - nGlobalLinkedNodes = nLocalLinkedNodes; -#endif - - Buffer_Receive_Coord = new su2double [ nGlobalVertex * nDim ]; - Buffer_Receive_GlobalPoint = new long[ nGlobalVertex ]; - Buffer_Receive_Proc = new unsigned long[ nGlobalVertex ]; - - Buffer_Receive_nLinkedNodes = new unsigned long[ nGlobalVertex ]; - Buffer_Receive_LinkedNodes = new unsigned long[ nGlobalLinkedNodes ]; - Buffer_Receive_StartLinkedNodes = new unsigned long[ nGlobalVertex ]; - -#ifdef HAVE_MPI - if (rank == MASTER_NODE){ - - for (iVertex = 0; iVertex < nDim*nLocalVertex; iVertex++) - Buffer_Receive_Coord[iVertex] = Buffer_Send_Coord[iVertex]; - - for (iVertex = 0; iVertex < nLocalVertex; iVertex++){ - Buffer_Receive_GlobalPoint[iVertex] = Buffer_Send_GlobalPoint[iVertex]; - Buffer_Receive_Proc[iVertex] = MASTER_NODE; - Buffer_Receive_nLinkedNodes[iVertex] = Buffer_Send_nLinkedNodes[iVertex]; - Buffer_Receive_StartLinkedNodes[iVertex] = Buffer_Send_StartLinkedNodes[iVertex]; - } - - for (iVertex = 0; iVertex < nLocalLinkedNodes; iVertex++) - Buffer_Receive_LinkedNodes[iVertex] = Buffer_Send_LinkedNodes[iVertex]; - - tmp_index = nLocalVertex; - tmp_index_2 = nLocalLinkedNodes; - - for(iRank = 1; iRank < nProcessor; iRank++){ - - SU2_MPI::Recv( &iTmp2, 1, MPI_UNSIGNED_LONG, iRank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - SU2_MPI::Recv(&Buffer_Receive_LinkedNodes[tmp_index_2], iTmp2, MPI_UNSIGNED_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - - SU2_MPI::Recv( &iTmp, 1, MPI_UNSIGNED_LONG, iRank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - SU2_MPI::Recv(&Buffer_Receive_Coord[tmp_index*nDim], nDim*iTmp, MPI_DOUBLE, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - - SU2_MPI::Recv( &Buffer_Receive_GlobalPoint[tmp_index], iTmp, MPI_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - SU2_MPI::Recv( &Buffer_Receive_nLinkedNodes[tmp_index], iTmp, MPI_UNSIGNED_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - SU2_MPI::Recv(&Buffer_Receive_StartLinkedNodes[tmp_index], iTmp, MPI_UNSIGNED_LONG, iRank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - - for (iVertex = 0; iVertex < iTmp; iVertex++){ - Buffer_Receive_Proc[ tmp_index + iVertex ] = iRank; - Buffer_Receive_StartLinkedNodes[ tmp_index + iVertex ] += tmp_index_2; - } - - tmp_index += iTmp; - tmp_index_2 += iTmp2; - } - } - else{ - SU2_MPI::Send( &nLocalLinkedNodes, 1, MPI_UNSIGNED_LONG, 0, 0, MPI_COMM_WORLD); - SU2_MPI::Send(Buffer_Send_LinkedNodes, nLocalLinkedNodes, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); - - SU2_MPI::Send( &nLocalVertex, 1, MPI_UNSIGNED_LONG, 0, 0, MPI_COMM_WORLD); - SU2_MPI::Send(Buffer_Send_Coord, nDim * nLocalVertex, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD); - - SU2_MPI::Send( Buffer_Send_GlobalPoint, nLocalVertex, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); - SU2_MPI::Send( Buffer_Send_nLinkedNodes, nLocalVertex, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); - SU2_MPI::Send(Buffer_Send_StartLinkedNodes, nLocalVertex, MPI_UNSIGNED_LONG, 0, 1, MPI_COMM_WORLD); - } -#else - for (iVertex = 0; iVertex < nDim * nGlobalVertex; iVertex++) - Buffer_Receive_Coord[iVertex] = Buffer_Send_Coord[iVertex]; - - for (iVertex = 0; iVertex < nGlobalVertex; iVertex++){ - Buffer_Receive_GlobalPoint[iVertex] = Buffer_Send_GlobalPoint[iVertex]; - Buffer_Receive_Proc[iVertex] = MASTER_NODE; - Buffer_Receive_nLinkedNodes[iVertex] = Buffer_Send_nLinkedNodes[iVertex]; - Buffer_Receive_StartLinkedNodes[iVertex] = Buffer_Send_StartLinkedNodes[iVertex]; - } - - for (iVertex = 0; iVertex < nGlobalLinkedNodes; iVertex++) - Buffer_Receive_LinkedNodes[iVertex] = Buffer_Send_LinkedNodes[iVertex]; -#endif - - if (rank == MASTER_NODE){ - for (iVertex = 0; iVertex < nGlobalVertex; iVertex++){ - count = 0; - uptr = &Buffer_Receive_LinkedNodes[ Buffer_Receive_StartLinkedNodes[iVertex] ]; - - for (jVertex = 0; jVertex < Buffer_Receive_nLinkedNodes[iVertex]; jVertex++){ - iTmp = uptr[ jVertex ]; - for (kVertex = 0; kVertex < nGlobalVertex; kVertex++){ - if( Buffer_Receive_GlobalPoint[kVertex] == long(iTmp) ){ - uptr[ jVertex ] = kVertex; - count++; - break; - } - } - - if( count != (jVertex+1) ){ - for (kVertex = jVertex; kVertex < Buffer_Receive_nLinkedNodes[iVertex]-1; kVertex++){ - uptr[ kVertex ] = uptr[ kVertex + 1]; - } - Buffer_Receive_nLinkedNodes[iVertex]--; - jVertex--; - } - } - } - } - -#ifdef HAVE_MPI - SU2_MPI::Bcast( Buffer_Receive_Coord, nGlobalVertex * nDim, MPI_DOUBLE, 0, MPI_COMM_WORLD); - SU2_MPI::Bcast(Buffer_Receive_GlobalPoint, nGlobalVertex, MPI_LONG, 0, MPI_COMM_WORLD); - SU2_MPI::Bcast( Buffer_Receive_Proc, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD ); - - SU2_MPI::Bcast( Buffer_Receive_nLinkedNodes, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); - SU2_MPI::Bcast(Buffer_Receive_StartLinkedNodes, nGlobalVertex, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); - SU2_MPI::Bcast( Buffer_Receive_LinkedNodes, nGlobalLinkedNodes, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); -#endif - - if( Buffer_Send_Coord != NULL) {delete [] Buffer_Send_Coord; Buffer_Send_Coord = NULL;} - if( Buffer_Send_GlobalPoint != NULL) {delete [] Buffer_Send_GlobalPoint; Buffer_Send_GlobalPoint = NULL;} - if( Buffer_Send_LinkedNodes != NULL) {delete [] Buffer_Send_LinkedNodes; Buffer_Send_LinkedNodes = NULL;} - if( Buffer_Send_nLinkedNodes != NULL) {delete [] Buffer_Send_nLinkedNodes; Buffer_Send_nLinkedNodes = NULL;} - if( Buffer_Send_StartLinkedNodes != NULL) {delete [] Buffer_Send_StartLinkedNodes; Buffer_Send_StartLinkedNodes = NULL;} -} - -bool CInterpolator::CheckInterfaceBoundary(int markDonor, int markTarget){ - - int Donor_check, Target_check; - - #ifdef HAVE_MPI - - int *Buffer_Recv_mark = NULL; - int iRank, nProcessor = size; - - if (rank == MASTER_NODE) - Buffer_Recv_mark = new int[nProcessor]; - - Donor_check = -1; - Target_check = -1; - - /*--- We gather a vector in MASTER_NODE to determine whether the boundary is not on the processor because of the partition or because the zone does not include it ---*/ - - SU2_MPI::Gather(&markDonor , 1, MPI_INT, Buffer_Recv_mark, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) - for (iRank = 0; iRank < nProcessor; iRank++) - if( Buffer_Recv_mark[iRank] != -1 ){ - Donor_check = Buffer_Recv_mark[iRank]; - break; - } - - SU2_MPI::Bcast(&Donor_check , 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - - SU2_MPI::Gather(&markTarget, 1, MPI_INT, Buffer_Recv_mark, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) - for (iRank = 0; iRank < nProcessor; iRank++) - if( Buffer_Recv_mark[iRank] != -1 ){ - Target_check = Buffer_Recv_mark[iRank]; - break; - } - - - SU2_MPI::Bcast(&Target_check, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) - delete [] Buffer_Recv_mark; - -#else - Donor_check = markDonor; - Target_check = markTarget; -#endif - - if(Target_check == -1 || Donor_check == -1) - return false; - else - return true; -} - -su2double CInterpolator::PointsDistance(su2double *point_i, su2double *point_j){ - - /*--- Compute distance between 2 points ---*/ - - unsigned short iDim, nDim = donor_geometry->GetnDim(); - su2double m; - - m = 0 ; - for(iDim = 0; iDim < nDim; iDim++) - m += (point_j[iDim] - point_i[iDim])*(point_j[iDim] - point_i[iDim]); - - return sqrt(m); -} - -/* Nearest Neighbor Interpolator */ -CNearestNeighbor::CNearestNeighbor(void): CInterpolator() { } - -CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { - - /*--- Initialize transfer coefficients between the zones ---*/ - Set_TransferCoeff(config); -} - -CNearestNeighbor::~CNearestNeighbor() {} - -void CNearestNeighbor::Set_TransferCoeff(CConfig **config) { - - int iProcessor, pProcessor, nProcessor = size; - int markDonor, markTarget; - - unsigned short nDim, iMarkerInt, nMarkerInt, iDonor; - - unsigned long nVertexDonor, nVertexTarget, Point_Target, jVertex, iVertexTarget; - unsigned long Global_Point_Donor; - long pGlobalPoint = 0; - - su2double *Coord_i, *Coord_j, dist, mindist, maxdist; - - /*--- Initialize variables --- */ - - nMarkerInt = (int) ( config[donorZone]->GetMarker_n_ZoneInterface() / 2 ); - - nDim = donor_geometry->GetnDim(); - - iDonor = 0; - - Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; - - - /*--- Cycle over nMarkersInt interface to determine communication pattern ---*/ - - for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - - - /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - - /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); - - /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ - if( !CheckInterfaceBoundary(markDonor, markTarget) ) - continue; - - if(markDonor != -1) - nVertexDonor = donor_geometry->GetnVertex( markDonor ); - else - nVertexDonor = 0; - - if(markTarget != -1) - nVertexTarget = target_geometry->GetnVertex( markTarget ); - else - nVertexTarget = 0; - - Buffer_Send_nVertex_Donor = new unsigned long [ 1 ]; - - /* Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor */ - Determine_ArraySize(false, markDonor, markTarget, nVertexDonor, nDim); - - Buffer_Send_Coord = new su2double [ MaxLocalVertex_Donor * nDim ]; - Buffer_Send_GlobalPoint = new long [ MaxLocalVertex_Donor ]; - Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; - Buffer_Receive_GlobalPoint = new long [ nProcessor * MaxLocalVertex_Donor ]; - - /*-- Collect coordinates, global points, and normal vectors ---*/ - Collect_VertexInfo( false, markDonor, markTarget, nVertexDonor, nDim ); - - /*--- Compute the closest point to a Near-Field boundary point ---*/ - maxdist = 0.0; - - for (iVertexTarget = 0; iVertexTarget < nVertexTarget; iVertexTarget++) { - - Point_Target = target_geometry->vertex[markTarget][iVertexTarget]->GetNode(); - - if ( target_geometry->node[Point_Target]->GetDomain() ) { - - target_geometry->vertex[markTarget][iVertexTarget]->SetnDonorPoints(1); - target_geometry->vertex[markTarget][iVertexTarget]->Allocate_DonorInfo(); // Possible meme leak? - - /*--- Coordinates of the boundary point ---*/ - Coord_i = target_geometry->node[Point_Target]->GetCoord(); - - mindist = 1E6; - pProcessor = 0; - - /*--- Loop over all the boundaries to find the pair ---*/ - - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (jVertex = 0; jVertex < MaxLocalVertex_Donor; jVertex++) { - - Global_Point_Donor = iProcessor*MaxLocalVertex_Donor+jVertex; - - if (Buffer_Receive_GlobalPoint[Global_Point_Donor] != -1){ - - Coord_j = &Buffer_Receive_Coord[ Global_Point_Donor*nDim]; - - dist = PointsDistance(Coord_i, Coord_j); - - if (dist < mindist) { - mindist = dist; pProcessor = iProcessor; - pGlobalPoint = Buffer_Receive_GlobalPoint[Global_Point_Donor]; - } - - if (dist == 0.0) break; - } - } - } - - /*--- Store the value of the pair ---*/ - maxdist = max(maxdist, mindist); - target_geometry->vertex[markTarget][iVertexTarget]->SetInterpDonorPoint(iDonor, pGlobalPoint); - target_geometry->vertex[markTarget][iVertexTarget]->SetInterpDonorProcessor(iDonor, pProcessor); - target_geometry->vertex[markTarget][iVertexTarget]->SetDonorCoeff(iDonor, 1.0); - } - } - - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_GlobalPoint; - - delete[] Buffer_Receive_Coord; - delete[] Buffer_Receive_GlobalPoint; - - delete[] Buffer_Send_nVertex_Donor; - - } - - delete[] Buffer_Receive_nVertex_Donor; -} - - - -CIsoparametric::CIsoparametric(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { - - /*--- Initialize transfer coefficients between the zones ---*/ - Set_TransferCoeff(config); - - /*--- For fluid-structure interaction data interpolated with have nDim dimensions ---*/ - // InitializeData(Zones,nDim); -} - -CIsoparametric::~CIsoparametric() {} - -void CIsoparametric::Set_TransferCoeff(CConfig **config) { - unsigned long iVertex, jVertex; - unsigned long dPoint, inode, jElem, nElem; - unsigned short iDim, iDonor=0, iFace; - - unsigned short nDim = donor_geometry->GetnDim(); - - unsigned short nMarkerInt; - unsigned short iMarkerInt; - - int markDonor=0, markTarget=0; - - long donor_elem=0, temp_donor=0; - unsigned int nNodes=0; - /*--- Restricted to 2-zone for now ---*/ - unsigned int nFaces=1; //For 2D cases, we want to look at edges, not faces, as the 'interface' - bool face_on_marker=true; - - unsigned long nVertexDonor = 0, nVertexTarget= 0; - unsigned long Point_Target = 0; - - unsigned long iVertexDonor, iPointDonor = 0; - int iProcessor; - - unsigned long nLocalFace_Donor = 0, nLocalFaceNodes_Donor=0; - - unsigned long faceindex; - - su2double dist = 0.0, mindist=1E6, *Coord, *Coord_i; - su2double myCoeff[10]; // Maximum # of donor points - su2double *Normal; - su2double *projected_point = new su2double[nDim]; - su2double tmp, tmp2; - su2double storeCoeff[10]; - unsigned long storeGlobal[10]; - int storeProc[10]; - - int nProcessor = size; - Coord = new su2double[nDim]; - Normal = new su2double[nDim]; - - nMarkerInt = (config[donorZone]->GetMarker_n_ZoneInterface())/2; - - /*--- For the number of markers on the interface... ---*/ - for (iMarkerInt=1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - /*--- Procedure: - * -Loop through vertices of the aero grid - * -Find nearest element and allocate enough space in the aero grid donor point info - * -set the transfer coefficient values - */ - - /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - - /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); - - /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ - if( !CheckInterfaceBoundary(markDonor, markTarget) ) - continue; - - if(markDonor != -1) - nVertexDonor = donor_geometry->GetnVertex( markDonor ); - else - nVertexDonor = 0; - - if(markTarget != -1) - nVertexTarget = target_geometry->GetnVertex( markTarget ); - else - nVertexTarget = 0; - - Buffer_Send_nVertex_Donor = new unsigned long [1]; - Buffer_Send_nFace_Donor = new unsigned long [1]; - Buffer_Send_nFaceNodes_Donor = new unsigned long [1]; - - Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; - Buffer_Receive_nFace_Donor = new unsigned long [nProcessor]; - Buffer_Receive_nFaceNodes_Donor = new unsigned long [nProcessor]; - - /* Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor */ - Determine_ArraySize(true, markDonor, markTarget, nVertexDonor, nDim); - - Buffer_Send_Coord = new su2double [MaxLocalVertex_Donor*nDim]; - Buffer_Send_Normal = new su2double [MaxLocalVertex_Donor*nDim]; - Buffer_Send_GlobalPoint = new long [MaxLocalVertex_Donor]; - - Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_Donor*nDim]; - Buffer_Receive_Normal = new su2double [nProcessor*MaxLocalVertex_Donor*nDim]; - Buffer_Receive_GlobalPoint = new long [nProcessor*MaxLocalVertex_Donor]; - - /*-- Collect coordinates, global points, and normal vectors ---*/ - Collect_VertexInfo(true, markDonor,markTarget,nVertexDonor,nDim); - - Buffer_Send_FaceIndex = new unsigned long[MaxFace_Donor]; - Buffer_Send_FaceNodes = new unsigned long[MaxFaceNodes_Donor]; - Buffer_Send_FaceProc = new unsigned long[MaxFaceNodes_Donor]; - - Buffer_Receive_FaceIndex = new unsigned long[MaxFace_Donor*nProcessor]; - Buffer_Receive_FaceNodes = new unsigned long[MaxFaceNodes_Donor*nProcessor]; - Buffer_Receive_FaceProc = new unsigned long[MaxFaceNodes_Donor*nProcessor]; - - nLocalFace_Donor=0; - nLocalFaceNodes_Donor=0; - - /*--- Collect Face info ---*/ - - for (iVertex = 0; iVertex < MaxFace_Donor; iVertex++) { - Buffer_Send_FaceIndex[iVertex] = 0; - } - for (iVertex=0; iVertexvertex[markDonor][iVertexDonor]->GetNode(); - - if (donor_geometry->node[iPointDonor]->GetDomain()) { - - if (nDim==3) nElem = donor_geometry->node[iPointDonor]->GetnElem(); - else nElem =donor_geometry->node[iPointDonor]->GetnPoint(); - - for (jElem=0; jElem < nElem; jElem++) { - if (nDim==3) { - temp_donor = donor_geometry->node[iPointDonor]->GetElem(jElem); - nFaces = donor_geometry->elem[temp_donor]->GetnFaces(); - for (iFace=0; iFaceelem[temp_donor]->GetnNodesFace(iFace); - for (iDonor=0; iDonorelem[temp_donor]->GetFaces(iFace, iDonor); - dPoint = donor_geometry->elem[temp_donor]->GetNode(inode); - face_on_marker = (face_on_marker && (donor_geometry->node[dPoint]->GetVertex(markDonor) !=-1)); - } - - if (face_on_marker ) { - for (iDonor=0; iDonorelem[temp_donor]->GetFaces(iFace, iDonor); - dPoint = donor_geometry->elem[temp_donor]->GetNode(inode); - // Match node on the face to the correct global index - long jGlobalPoint = donor_geometry->node[dPoint]->GetGlobalIndex(); - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (jVertex = 0; jVertex < Buffer_Receive_nVertex_Donor[iProcessor]; jVertex++) { - if (jGlobalPoint == Buffer_Receive_GlobalPoint[MaxLocalVertex_Donor*iProcessor+jVertex]) { - Buffer_Send_FaceNodes[nLocalFaceNodes_Donor]=MaxLocalVertex_Donor*iProcessor+jVertex; - Buffer_Send_FaceProc[nLocalFaceNodes_Donor]=iProcessor; - } - } - } - nLocalFaceNodes_Donor++; // Increment total number of face-nodes / processor - } - /* Store the indices */ - Buffer_Send_FaceIndex[nLocalFace_Donor+1] = Buffer_Send_FaceIndex[nLocalFace_Donor]+nNodes; - nLocalFace_Donor++; // Increment number of faces / processor - } - } - } - else { - /*-- Determine whether this face/edge is on the marker --*/ - face_on_marker=true; - for (iDonor=0; iDonornode[iPointDonor]->GetEdge(jElem); - dPoint = donor_geometry->edge[inode]->GetNode(iDonor); - face_on_marker = (face_on_marker && (donor_geometry->node[dPoint]->GetVertex(markDonor) !=-1)); - } - if (face_on_marker ) { - for (iDonor=0; iDonornode[iPointDonor]->GetEdge(jElem); - dPoint = donor_geometry->edge[inode]->GetNode(iDonor); - // Match node on the face to the correct global index - long jGlobalPoint = donor_geometry->node[dPoint]->GetGlobalIndex(); - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (jVertex = 0; jVertex < Buffer_Receive_nVertex_Donor[iProcessor]; jVertex++) { - if (jGlobalPoint == Buffer_Receive_GlobalPoint[MaxLocalVertex_Donor*iProcessor+jVertex]) { - Buffer_Send_FaceNodes[nLocalFaceNodes_Donor]=MaxLocalVertex_Donor*iProcessor+jVertex; - Buffer_Send_FaceProc[nLocalFaceNodes_Donor]=iProcessor; - } - } - } - nLocalFaceNodes_Donor++; // Increment total number of face-nodes / processor - } - /* Store the indices */ - Buffer_Send_FaceIndex[nLocalFace_Donor+1] = Buffer_Send_FaceIndex[nLocalFace_Donor]+nNodes; - nLocalFace_Donor++; // Increment number of faces / processor - } - } - } - } - } - - //Buffer_Send_FaceIndex[nLocalFace_Donor+1] = MaxFaceNodes_Donor*rank+nLocalFaceNodes_Donor; -#ifdef HAVE_MPI - SU2_MPI::Allgather(Buffer_Send_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, Buffer_Receive_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_FaceProc, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, Buffer_Receive_FaceProc, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, Buffer_Receive_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#else - for (iFace=0; iFacevertex[markTarget][iVertex]->GetNode(); - - if (target_geometry->node[Point_Target]->GetDomain()) { - - Coord_i = target_geometry->node[Point_Target]->GetCoord(); - /*---Loop over the faces previously communicated/stored ---*/ - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - - nFaces = (unsigned int)Buffer_Receive_nFace_Donor[iProcessor]; - - for (iFace = 0; iFace< nFaces; iFace++) { - /*--- ---*/ - - nNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1] - - (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; - - su2double *X = new su2double[nNodes*(nDim+1)]; - faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face - for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetDonorElem(donor_elem); // in 2D is nearest neighbor - target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nNodes); - for (iDonor=0; iDonorvertex[markTarget][iVertex]->GetnDonorPoints(); - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); - - for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,storeGlobal[iDonor]); - //cout <vertex[markTarget][iVertex]->SetDonorCoeff(iDonor,storeCoeff[iDonor]); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); - } - } - } - - delete[] Buffer_Send_nVertex_Donor; - delete[] Buffer_Send_nFace_Donor; - delete[] Buffer_Send_nFaceNodes_Donor; - - delete[] Buffer_Receive_nVertex_Donor; - delete[] Buffer_Receive_nFace_Donor; - delete[] Buffer_Receive_nFaceNodes_Donor; - - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_Normal; - delete[] Buffer_Send_GlobalPoint; - - delete[] Buffer_Receive_Coord; - delete[] Buffer_Receive_Normal; - delete[] Buffer_Receive_GlobalPoint; - - delete[] Buffer_Send_FaceIndex; - delete[] Buffer_Send_FaceNodes; - delete[] Buffer_Send_FaceProc; - - delete[] Buffer_Receive_FaceIndex; - delete[] Buffer_Receive_FaceNodes; - delete[] Buffer_Receive_FaceProc; - } - delete [] Coord; - delete [] Normal; - - delete [] projected_point; -} - -void CIsoparametric::Isoparameters(unsigned short nDim, unsigned short nDonor, - su2double *X, su2double *xj, su2double *isoparams) { - short iDonor,iDim,k; // indices - su2double tmp, tmp2; - - su2double *x = new su2double[nDim+1]; - su2double *x_tmp = new su2double[nDim+1]; - su2double *Q = new su2double[nDonor*nDonor]; - su2double *R = new su2double[nDonor*nDonor]; - su2double *A = new su2double[(nDim+2)*nDonor]; - su2double *A2 = NULL; - su2double *x2 = new su2double[nDim+1]; - - bool *test = new bool[nDim+1]; - bool *testi = new bool[nDim+1]; - - su2double eps = 1E-10; - - short n = nDim+1; - - if (nDonor>2) { - /*--- Create Matrix A: 1st row all 1's, 2nd row x coordinates, 3rd row y coordinates, etc ---*/ - /*--- Right hand side is [1, \vec{x}']'---*/ - for (iDonor=0; iDonoreps && iDonor=0; iDonor--) { - if (R[iDonor*nDonor+iDonor]>eps) - isoparams[iDonor]=x_tmp[iDonor]/R[iDonor*nDonor+iDonor]; - else - isoparams[iDonor]=0; - for (k=0; k1.0) xi=1.0; - if (xi<-1.0) xi=-1.0; - if (eta>1.0) eta=1.0; - if (eta<-1.0) eta=-1.0; - isoparams[0]=0.25*(1-xi)*(1-eta); - isoparams[1]=0.25*(1+xi)*(1-eta); - isoparams[2]=0.25*(1+xi)*(1+eta); - isoparams[3]=0.25*(1-xi)*(1+eta); - - } - if (nDonor<4) { - tmp = 0.0; // value for normalization - tmp2=0; // check for maximum value, to be used to id nearest neighbor if necessary - k=0; // index for maximum value - for (iDonor=0; iDonor< nDonor; iDonor++) { - if (isoparams[iDonor]>tmp2) { - k=iDonor; - tmp2=isoparams[iDonor]; - } - // [0,1] - if (isoparams[iDonor]<0) isoparams[iDonor]=0; - if (isoparams[iDonor]>1) isoparams[iDonor] = 1; - tmp +=isoparams[iDonor]; - } - if (tmp>0) - for (iDonor=0; iDonor< nDonor; iDonor++) - isoparams[iDonor]=isoparams[iDonor]/tmp; - else { - isoparams[k] = 1.0; - } - } - - delete [] x; - delete [] x_tmp; - delete [] Q; - delete [] R; - delete [] A; - if (A2 != NULL) delete [] A2; - delete [] x2; - - delete [] test; - delete [] testi; - -} - - -/* Mirror Interpolator */ -CMirror::CMirror(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { - - /*--- Initialize transfer coefficients between the zones ---*/ - Set_TransferCoeff(config); - -} - -CMirror::~CMirror() {} - -void CMirror::Set_TransferCoeff(CConfig **config) { - unsigned long iVertex, jVertex; - unsigned long iPoint; - unsigned short iDonor=0, iFace=0, iTarget=0; - - unsigned short nMarkerInt; - unsigned short iMarkerInt; - - int markDonor=0, markTarget=0; - - unsigned int nNodes=0, iNodes=0; - unsigned long nVertexDonor = 0, nVertexTarget= 0; - unsigned long Point_Donor = 0; - unsigned long pGlobalPoint = 0; - int iProcessor; - - unsigned long nLocalFace_Donor = 0, nLocalFaceNodes_Donor=0; - - unsigned long faceindex; - - int nProcessor = size; - - su2double *Buffer_Send_Coeff, *Buffer_Receive_Coeff; - su2double coeff; - - /*--- Number of markers on the interface ---*/ - nMarkerInt = (config[targetZone]->GetMarker_n_ZoneInterface())/2; - - /*--- For the number of markers on the interface... ---*/ - for (iMarkerInt=1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - /*--- Procedure: - * -Loop through vertices of the aero grid - * -Find nearest element and allocate enough space in the aero grid donor point info - * -set the transfer coefficient values - */ - - /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - - /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); - - /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ - if( !CheckInterfaceBoundary(markDonor, markTarget) ) - continue; - - if(markDonor != -1) - nVertexDonor = donor_geometry->GetnVertex( markDonor ); - else - nVertexDonor = 0; - - if(markTarget != -1) - nVertexTarget = target_geometry->GetnVertex( markTarget ); - else - nVertexTarget = 0; - - /*-- Collect the number of donor nodes: re-use 'Face' containers --*/ - nLocalFace_Donor=0; - nLocalFaceNodes_Donor=0; - for (jVertex = 0; jVertexvertex[markDonor][jVertex]->GetNode(); // Local index of jVertex - - if (donor_geometry->node[Point_Donor]->GetDomain()) { - nNodes = donor_geometry->vertex[markDonor][jVertex]->GetnDonorPoints(); - nLocalFaceNodes_Donor+=nNodes; - nLocalFace_Donor++; - } - } - Buffer_Send_nFace_Donor= new unsigned long [1]; - Buffer_Send_nFaceNodes_Donor= new unsigned long [1]; - - Buffer_Receive_nFace_Donor = new unsigned long [nProcessor]; - Buffer_Receive_nFaceNodes_Donor = new unsigned long [nProcessor]; - - Buffer_Send_nFace_Donor[0] = nLocalFace_Donor; - Buffer_Send_nFaceNodes_Donor[0] = nLocalFaceNodes_Donor; - - /*--- Send Interface vertex information --*/ -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &MaxFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalFace_Donor, &MaxFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFace_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - MaxFace_Donor++; -#else - nGlobalFace_Donor = nLocalFace_Donor; - nGlobalFaceNodes_Donor = nLocalFaceNodes_Donor; - MaxFaceNodes_Donor = nLocalFaceNodes_Donor; - MaxFace_Donor = nLocalFace_Donor+1; - Buffer_Receive_nFace_Donor[0] = Buffer_Send_nFace_Donor[0]; - Buffer_Receive_nFaceNodes_Donor[0] = Buffer_Send_nFaceNodes_Donor[0]; -#endif - - /*-- Send donor info --*/ - Buffer_Send_FaceIndex = new unsigned long[MaxFace_Donor]; - Buffer_Send_FaceNodes = new unsigned long[MaxFaceNodes_Donor]; - Buffer_Send_GlobalPoint = new long[MaxFaceNodes_Donor]; - Buffer_Send_Coeff = new su2double[MaxFaceNodes_Donor]; - - Buffer_Receive_FaceIndex= new unsigned long[MaxFace_Donor*nProcessor]; - Buffer_Receive_FaceNodes= new unsigned long[MaxFaceNodes_Donor*nProcessor]; - Buffer_Receive_GlobalPoint = new long[MaxFaceNodes_Donor*nProcessor]; - Buffer_Receive_Coeff = new su2double[MaxFaceNodes_Donor*nProcessor]; - - for (iVertex=0; iVertexvertex[markDonor][jVertex]->GetNode(); // Local index of jVertex - if (donor_geometry->node[Point_Donor]->GetDomain()) { - nNodes = donor_geometry->vertex[markDonor][jVertex]->GetnDonorPoints(); - for (iDonor=0; iDonornode[Point_Donor]->GetGlobalIndex(); - Buffer_Send_GlobalPoint[nLocalFaceNodes_Donor] = - donor_geometry->vertex[markDonor][jVertex]->GetInterpDonorPoint(iDonor); - Buffer_Send_Coeff[nLocalFaceNodes_Donor] = - donor_geometry->vertex[markDonor][jVertex]->GetDonorCoeff(iDonor); - nLocalFaceNodes_Donor++; - } - Buffer_Send_FaceIndex[nLocalFace_Donor+1] =Buffer_Send_FaceIndex[nLocalFace_Donor]+nNodes; - nLocalFace_Donor++; - } - } - -#ifdef HAVE_MPI - SU2_MPI::Allgather(Buffer_Send_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, Buffer_Receive_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_GlobalPoint, MaxFaceNodes_Donor, MPI_LONG,Buffer_Receive_GlobalPoint, MaxFaceNodes_Donor, MPI_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_Coeff, MaxFaceNodes_Donor, MPI_DOUBLE,Buffer_Receive_Coeff, MaxFaceNodes_Donor, MPI_DOUBLE, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, Buffer_Receive_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#else - for (iFace=0; iFacevertex[markTarget][iVertex]->GetNode(); - if (target_geometry->node[iPoint]->GetDomain()) { - long Global_Point = target_geometry->node[iPoint]->GetGlobalIndex(); - nNodes = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iFace = 0; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { - faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face - iNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1]- (unsigned int)faceindex; - for (iTarget=0; iTargetvertex[markTarget][iVertex]->SetnDonorPoints(nNodes); - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); - - iDonor = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iFace = 0; iFace < Buffer_Receive_nFace_Donor[iProcessor]; iFace++) { - - faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face - iNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1]- (unsigned int)faceindex; - for (iTarget=0; iTargetvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,pGlobalPoint); - target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor,coeff); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, iProcessor); - iDonor++; - } - } - } - } - } - } - delete[] Buffer_Send_nFace_Donor; - delete[] Buffer_Send_nFaceNodes_Donor; - - delete[] Buffer_Receive_nFace_Donor; - delete[] Buffer_Receive_nFaceNodes_Donor; - - delete[] Buffer_Send_FaceIndex; - delete[] Buffer_Send_FaceNodes; - delete[] Buffer_Send_GlobalPoint; - delete[] Buffer_Send_Coeff; - - delete[] Buffer_Receive_FaceIndex; - delete[] Buffer_Receive_FaceNodes; - delete[] Buffer_Receive_GlobalPoint; - delete[] Buffer_Receive_Coeff; - - } -} - -CSlidingMesh::CSlidingMesh(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone){ - - /*--- Initialize transfer coefficients between the zones ---*/ - Set_TransferCoeff(config); - - /*--- For fluid-structure interaction data interpolated with have nDim dimensions ---*/ - // InitializeData(Zones,nDim); -} - -CSlidingMesh::~CSlidingMesh(){} - -void CSlidingMesh::Set_TransferCoeff(CConfig **config){ - - /* --- This routine sets the transfer coefficient for sliding mesh approach --- */ - - /* - * The algorithm is based on Rinaldi et al. "Flux-conserving treatment of non-conformal interfaces - * for finite-volume discritization of conservaation laws" 2015, Comp. Fluids, 120, pp 126-139 - */ - - /* 0 - Variable declaration - */ - - /* --- General variables --- */ - - bool check; - - unsigned short iDim, nDim; - - unsigned long ii, jj, *uptr; - unsigned long vPoint; - unsigned long iEdgeVisited, nEdgeVisited, iNodeVisited; - unsigned long nAlreadyVisited, nToVisit, StartVisited; - - unsigned long *alreadyVisitedDonor, *ToVisit, *tmpVect; - unsigned long *storeProc, *tmp_storeProc; - - su2double dTMP; - su2double *Coeff_Vect, *tmp_Coeff_Vect; - - /* --- Geometrical variables --- */ - - su2double *Coord_i, *Coord_j, dist, mindist, *Normal; - su2double Area, Area_old, tmp_Area; - su2double LineIntersectionLength, *Direction, length; - - - /* --- Markers Variables --- */ - - unsigned short iMarkerInt, nMarkerInt; - - unsigned long iVertex, nVertexTarget; - - int markDonor, markTarget; - - /* --- Target variables --- */ - - unsigned long target_iPoint, jVertexTarget; - unsigned long nEdges_target, nNode_target; - - unsigned long *Target_nLinkedNodes, *Target_LinkedNodes, *Target_StartLinkedNodes, *target_segment; - unsigned long *Target_Proc; - long *Target_GlobalPoint, *Donor_GlobalPoint; - - su2double *TargetPoint_Coord, *target_iMidEdge_point, *target_jMidEdge_point, **target_element; - - /* --- Donor variables --- */ - - unsigned long donor_StartIndex, donor_forward_point, donor_backward_point, donor_iPoint, donor_OldiPoint; - unsigned long nEdges_donor, nNode_donor, nGlobalVertex_Donor; - - unsigned long nDonorPoints, iDonor; - unsigned long *Donor_Vect, *tmp_Donor_Vect; - unsigned long *Donor_nLinkedNodes, *Donor_LinkedNodes, *Donor_StartLinkedNodes; - unsigned long *Donor_Proc; - - su2double *donor_iMidEdge_point, *donor_jMidEdge_point; - su2double **donor_element, *DonorPoint_Coord; - - /* 1 - Variable pre-processing - */ - - nDim = donor_geometry->GetnDim(); - - /*--- Setting up auxiliary vectors ---*/ - - Donor_Vect = NULL; - Coeff_Vect = NULL; - storeProc = NULL; - - tmp_Donor_Vect = NULL; - tmp_Coeff_Vect = NULL; - tmp_storeProc = NULL; - - Normal = new su2double[nDim]; - Direction = new su2double[nDim]; - - - /* 2 - Find boundary tag between touching grids */ - - /*--- Number of markers on the FSI interface ---*/ - nMarkerInt = (int)( config[ donorZone ]->GetMarker_n_ZoneInterface() ) / 2; - - /*--- For the number of markers on the interface... ---*/ - for ( iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++ ){ - - /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - - /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); - - /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ - if( !CheckInterfaceBoundary(markDonor, markTarget) ) - continue; - - if(markTarget != -1) - nVertexTarget = target_geometry->GetnVertex( markTarget ); - else - nVertexTarget = 0; - - /* - 3 -Reconstruct the boundaries from parallel partitioning - */ - - /*--- Target boundary ---*/ - ReconstructBoundary(targetZone, markTarget); - - nGlobalVertex_Target = nGlobalVertex; - - TargetPoint_Coord = Buffer_Receive_Coord; - Target_GlobalPoint = Buffer_Receive_GlobalPoint; - Target_nLinkedNodes = Buffer_Receive_nLinkedNodes; - Target_StartLinkedNodes = Buffer_Receive_StartLinkedNodes; - Target_LinkedNodes = Buffer_Receive_LinkedNodes; - Target_Proc = Buffer_Receive_Proc; - - /*--- Donor boundary ---*/ - ReconstructBoundary(donorZone, markDonor); - - nGlobalVertex_Donor = nGlobalVertex; - - DonorPoint_Coord = Buffer_Receive_Coord; - Donor_GlobalPoint = Buffer_Receive_GlobalPoint; - Donor_nLinkedNodes = Buffer_Receive_nLinkedNodes; - Donor_StartLinkedNodes = Buffer_Receive_StartLinkedNodes; - Donor_LinkedNodes = Buffer_Receive_LinkedNodes; - Donor_Proc = Buffer_Receive_Proc; - - /*--- Starts building the supermesh layer (2D or 3D) ---*/ - /* - For each target node, it first finds the closest donor point - * - Then it creates the supermesh in the close proximity of the target point: - * - Starting from the closest donor node, it expands the supermesh by including - * donor elements neighboring the initial one, until the overall target area is fully covered. - */ - - if(nDim == 2){ - - target_iMidEdge_point = new su2double[nDim]; - target_jMidEdge_point = new su2double[nDim]; - - donor_iMidEdge_point = new su2double[nDim]; - donor_jMidEdge_point = new su2double[nDim]; - - /*--- Starts with supermesh reconstruction ---*/ - - target_segment = new unsigned long[2]; - - for (iVertex = 0; iVertex < nVertexTarget; iVertex++) { - - nDonorPoints = 0; - - /*--- Stores coordinates of the target node ---*/ - - target_iPoint = target_geometry->vertex[markTarget][iVertex]->GetNode(); - - if (target_geometry->node[target_iPoint]->GetDomain()){ - - Coord_i = target_geometry->node[target_iPoint]->GetCoord(); - - /*--- Brute force to find the closest donor_node ---*/ - - mindist = 1E6; - donor_StartIndex = 0; - - for (donor_iPoint = 0; donor_iPoint < nGlobalVertex_Donor; donor_iPoint++) { - - Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; - - dist = PointsDistance(Coord_i, Coord_j); - - if (dist < mindist) { - mindist = dist; - donor_StartIndex = donor_iPoint; - } - - if (dist == 0.0){ - donor_StartIndex = donor_iPoint; - break; - } - } - - donor_iPoint = donor_StartIndex; - donor_OldiPoint = donor_iPoint; - - /*--- Contruct information regarding the target cell ---*/ - - long dPoint = target_geometry->node[target_iPoint]->GetGlobalIndex(); - for (jVertexTarget = 0; jVertexTarget < nGlobalVertex_Target; jVertexTarget++) - if( dPoint == Target_GlobalPoint[jVertexTarget] ) - break; - - if ( Target_nLinkedNodes[jVertexTarget] == 1 ){ - target_segment[0] = Target_LinkedNodes[ Target_StartLinkedNodes[jVertexTarget] ]; - target_segment[1] = jVertexTarget; - } - else{ - target_segment[0] = Target_LinkedNodes[ Target_StartLinkedNodes[jVertexTarget] ]; - target_segment[1] = Target_LinkedNodes[ Target_StartLinkedNodes[jVertexTarget] + 1]; - } - - dTMP = 0; - for(iDim = 0; iDim < nDim; iDim++){ - target_iMidEdge_point[iDim] = ( TargetPoint_Coord[ nDim * target_segment[0] + iDim ] + target_geometry->node[ target_iPoint ]->GetCoord(iDim) ) / 2; - target_jMidEdge_point[iDim] = ( TargetPoint_Coord[ nDim * target_segment[1] + iDim ] + target_geometry->node[ target_iPoint ]->GetCoord(iDim) ) / 2; - - Direction[iDim] = target_jMidEdge_point[iDim] - target_iMidEdge_point[iDim]; - dTMP += Direction[iDim] * Direction[iDim]; - } - - dTMP = sqrt(dTMP); - for(iDim = 0; iDim < nDim; iDim++) - Direction[iDim] /= dTMP; - - length = PointsDistance(target_iMidEdge_point, target_jMidEdge_point); - - check = false; - - /*--- Proceeds along the forward direction (depending on which connected boundary node is found first) ---*/ - - while( !check ){ - - /*--- Proceeds until the value of the intersection area is null ---*/ - - if ( Donor_nLinkedNodes[donor_iPoint] == 1 ){ - donor_forward_point = Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_iPoint] ]; - donor_backward_point = donor_iPoint; - } - else{ - uptr = &Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_iPoint] ]; - - if( donor_OldiPoint != uptr[0] ){ - donor_forward_point = uptr[0]; - donor_backward_point = uptr[1]; - } - else{ - donor_forward_point = uptr[1]; - donor_backward_point = uptr[0]; - } - } - - if(donor_iPoint >= nGlobalVertex_Donor){ - check = true; - continue; - } - - for(iDim = 0; iDim < nDim; iDim++){ - donor_iMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_forward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; - donor_jMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_backward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; - } - - LineIntersectionLength = ComputeLineIntersectionLength(target_iMidEdge_point, target_jMidEdge_point, donor_iMidEdge_point, donor_jMidEdge_point, Direction); - - if ( LineIntersectionLength == 0.0 ){ - check = true; - continue; - } - - /*--- In case the element intersects the target cell, update the auxiliary communication data structure ---*/ - - tmp_Coeff_Vect = new su2double[ nDonorPoints + 1 ]; - tmp_Donor_Vect = new unsigned long[ nDonorPoints + 1 ]; - tmp_storeProc = new unsigned long[ nDonorPoints + 1 ]; - - for( iDonor = 0; iDonor < nDonorPoints; iDonor++){ - tmp_Donor_Vect[iDonor] = Donor_Vect[iDonor]; - tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; - tmp_storeProc[iDonor] = storeProc[iDonor]; - } - - tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; - tmp_Coeff_Vect[ nDonorPoints ] = LineIntersectionLength / length; - tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; - - if (Donor_Vect != NULL) delete [] Donor_Vect; - if (Coeff_Vect != NULL) delete [] Coeff_Vect; - if (storeProc != NULL) delete [] storeProc; - - Donor_Vect = tmp_Donor_Vect; - Coeff_Vect = tmp_Coeff_Vect; - storeProc = tmp_storeProc; - - donor_OldiPoint = donor_iPoint; - donor_iPoint = donor_forward_point; - - nDonorPoints++; - } - - if ( Donor_nLinkedNodes[donor_StartIndex] == 2 ){ - check = false; - - uptr = &Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_StartIndex] ]; - - donor_iPoint = uptr[1]; - donor_OldiPoint = donor_StartIndex; - } - else - check = true; - - /*--- Proceeds along the backward direction (depending on which connected boundary node is found first) ---*/ - - while( !check ){ - - /*--- Proceeds until the value of the intersection length is null ---*/ - if ( Donor_nLinkedNodes[donor_iPoint] == 1 ){ - donor_forward_point = donor_OldiPoint; - donor_backward_point = donor_iPoint; - } - else{ - uptr = &Donor_LinkedNodes[ Donor_StartLinkedNodes[donor_iPoint] ]; - - if( donor_OldiPoint != uptr[0] ){ - donor_forward_point = uptr[0]; - donor_backward_point = uptr[1]; - } - else{ - donor_forward_point = uptr[1]; - donor_backward_point = uptr[0]; - } - } - - if(donor_iPoint >= nGlobalVertex_Donor){ - check = true; - continue; - } - - for(iDim = 0; iDim < nDim; iDim++){ - donor_iMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_forward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; - donor_jMidEdge_point[iDim] = ( DonorPoint_Coord[ donor_backward_point * nDim + iDim] + DonorPoint_Coord[ donor_iPoint * nDim + iDim] ) / 2; - } - - LineIntersectionLength = ComputeLineIntersectionLength(target_iMidEdge_point, target_jMidEdge_point, donor_iMidEdge_point, donor_jMidEdge_point, Direction); - - if ( LineIntersectionLength == 0.0 ){ - check = true; - continue; - } - - /*--- In case the element intersects the target cell, update the auxiliary communication data structure ---*/ - - tmp_Coeff_Vect = new su2double[ nDonorPoints + 1 ]; - tmp_Donor_Vect = new unsigned long[ nDonorPoints + 1 ]; - tmp_storeProc = new unsigned long[ nDonorPoints + 1 ]; - - for( iDonor = 0; iDonor < nDonorPoints; iDonor++){ - tmp_Donor_Vect[iDonor] = Donor_Vect[iDonor]; - tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; - tmp_storeProc[iDonor] = storeProc[iDonor]; - } - - tmp_Coeff_Vect[ nDonorPoints ] = LineIntersectionLength / length; - tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; - tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; - - if (Donor_Vect != NULL) delete [] Donor_Vect; - if (Coeff_Vect != NULL) delete [] Coeff_Vect; - if (storeProc != NULL) delete [] storeProc; - - Donor_Vect = tmp_Donor_Vect; - Coeff_Vect = tmp_Coeff_Vect; - storeProc = tmp_storeProc; - - donor_OldiPoint = donor_iPoint; - donor_iPoint = donor_forward_point; - - nDonorPoints++; - } - - /*--- Set the communication data structure and copy data from the auxiliary vectors ---*/ - - target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nDonorPoints); - - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); - - for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ - target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff( iDonor, Coeff_Vect[iDonor]); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorPoint( iDonor, Donor_GlobalPoint[ Donor_Vect[iDonor] ]); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); - } - } - } - - delete [] target_segment; - - delete [] target_iMidEdge_point; - delete [] target_jMidEdge_point; - - delete [] donor_iMidEdge_point; - delete [] donor_jMidEdge_point; - } - else{ - /* --- 3D geometry, creates a superficial super-mesh --- */ - - for (iVertex = 0; iVertex < nVertexTarget; iVertex++) { - - nDonorPoints = 0; - - /*--- Stores coordinates of the target node ---*/ - - target_iPoint = target_geometry->vertex[markTarget][iVertex]->GetNode(); - - if (target_geometry->node[target_iPoint]->GetDomain()){ - - Coord_i = target_geometry->node[target_iPoint]->GetCoord(); - - target_geometry->vertex[markTarget][iVertex]->GetNormal(Normal); - - /*--- The value of Area computed here includes also portion of boundary belonging to different marker ---*/ - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - - for (iDim = 0; iDim < nDim; iDim++) - Normal[iDim] /= Area; - - for (iDim = 0; iDim < nDim; iDim++) - Coord_i[iDim] = target_geometry->node[target_iPoint]->GetCoord(iDim); - - long dPoint = target_geometry->node[target_iPoint]->GetGlobalIndex(); - for (target_iPoint = 0; target_iPoint < nGlobalVertex_Target; target_iPoint++){ - if( dPoint == Target_GlobalPoint[target_iPoint] ) - break; - } - - /*--- Build local surface dual mesh for target element ---*/ - - nEdges_target = Target_nLinkedNodes[target_iPoint]; - - nNode_target = 2*(nEdges_target + 1); - - target_element = new su2double*[nNode_target]; - for (ii = 0; ii < nNode_target; ii++) - target_element[ii] = new su2double[nDim]; - - nNode_target = Build_3D_surface_element(Target_LinkedNodes, Target_StartLinkedNodes, Target_nLinkedNodes, TargetPoint_Coord, target_iPoint, target_element); - - /*--- Brute force to find the closest donor_node ---*/ - - mindist = 1E6; - donor_StartIndex = 0; - - for (donor_iPoint = 0; donor_iPoint < nGlobalVertex_Donor; donor_iPoint++) { - - Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; - - dist = PointsDistance(Coord_i, Coord_j); - - if (dist < mindist) { - mindist = dist; - donor_StartIndex = donor_iPoint; - } - - if (dist == 0.0){ - donor_StartIndex = donor_iPoint; - break; - } - } - - donor_iPoint = donor_StartIndex; - - nEdges_donor = Donor_nLinkedNodes[donor_iPoint]; - - donor_element = new su2double*[ 2*nEdges_donor + 2 ]; - for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - donor_element[ii] = new su2double[nDim]; - - nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); - - Area = 0; - for (ii = 1; ii < nNode_target-1; ii++){ - for (jj = 1; jj < nNode_donor-1; jj++){ - Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal); - //cout << Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal) << endl; - } - } - - for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - delete [] donor_element[ii]; - delete [] donor_element; - - nDonorPoints = 1; - - /*--- In case the element intersect the target cell update the auxiliary communication data structure ---*/ - - Coeff_Vect = new su2double[ nDonorPoints ]; - Donor_Vect = new unsigned long[ nDonorPoints ]; - storeProc = new unsigned long[ nDonorPoints ]; - - Coeff_Vect[0] = Area; - Donor_Vect[0] = donor_iPoint; - storeProc[0] = Donor_Proc[donor_iPoint]; - - alreadyVisitedDonor = new unsigned long[1]; - - alreadyVisitedDonor[0] = donor_iPoint; - nAlreadyVisited = 1; - StartVisited = 0; - - Area_old = -1; - - while( Area > Area_old ){ - - /* - * - Starting from the closest donor_point, it expands the supermesh by a countour search pattern. - * - The closest donor element becomes the core, at each iteration a new layer of elements around the core is taken into account - */ - - Area_old = Area; - - ToVisit = NULL; - nToVisit = 0; - - for( iNodeVisited = StartVisited; iNodeVisited < nAlreadyVisited; iNodeVisited++ ){ - - vPoint = alreadyVisitedDonor[ iNodeVisited ]; - - nEdgeVisited = Donor_nLinkedNodes[vPoint]; - - for (iEdgeVisited = 0; iEdgeVisited < nEdgeVisited; iEdgeVisited++){ - - donor_iPoint = Donor_LinkedNodes[ Donor_StartLinkedNodes[vPoint] + iEdgeVisited]; - - /*--- Check if the node to visit is already listed in the data structure to avoid double visits ---*/ - - check = 0; - - for( jj = 0; jj < nAlreadyVisited; jj++ ){ - if( donor_iPoint == alreadyVisitedDonor[jj] ){ - check = 1; - break; - } - } - - if( check == 0 && ToVisit != NULL){ - for( jj = 0; jj < nToVisit; jj++ ) - if( donor_iPoint == ToVisit[jj] ){ - check = 1; - break; - } - } - - if( check == 0 ){ - /*--- If the node was not already visited, visit it and list it into data structure ---*/ - - tmpVect = new unsigned long[ nToVisit + 1 ]; - - for( jj = 0; jj < nToVisit; jj++ ) - tmpVect[jj] = ToVisit[jj]; - tmpVect[nToVisit] = donor_iPoint; - - if( ToVisit != NULL ) - delete [] ToVisit; - - ToVisit = tmpVect; - tmpVect = NULL; - - nToVisit++; - - /*--- Find the value of the intersection area between the current donor element and the target element --- */ - - nEdges_donor = Donor_nLinkedNodes[donor_iPoint]; - - donor_element = new su2double*[ 2*nEdges_donor + 2 ]; - for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - donor_element[ii] = new su2double[nDim]; - - nNode_donor = Build_3D_surface_element(Donor_LinkedNodes, Donor_StartLinkedNodes, Donor_nLinkedNodes, DonorPoint_Coord, donor_iPoint, donor_element); - - tmp_Area = 0; - for (ii = 1; ii < nNode_target-1; ii++) - for (jj = 1; jj < nNode_donor-1; jj++) - tmp_Area += Compute_Triangle_Intersection(target_element[0], target_element[ii], target_element[ii+1], donor_element[0], donor_element[jj], donor_element[jj+1], Normal); - - for (ii = 0; ii < 2*nEdges_donor + 2; ii++) - delete [] donor_element[ii]; - delete [] donor_element; - - /*--- In case the element intersect the target cell update the auxiliary communication data structure ---*/ - - tmp_Coeff_Vect = new su2double[ nDonorPoints + 1 ]; - tmp_Donor_Vect = new unsigned long[ nDonorPoints + 1 ]; - tmp_storeProc = new unsigned long[ nDonorPoints + 1 ]; - - for( iDonor = 0; iDonor < nDonorPoints; iDonor++){ - tmp_Donor_Vect[iDonor] = Donor_Vect[iDonor]; - tmp_Coeff_Vect[iDonor] = Coeff_Vect[iDonor]; - tmp_storeProc[iDonor] = storeProc[iDonor]; - } - - tmp_Coeff_Vect[ nDonorPoints ] = tmp_Area; - tmp_Donor_Vect[ nDonorPoints ] = donor_iPoint; - tmp_storeProc[ nDonorPoints ] = Donor_Proc[donor_iPoint]; - - if (Donor_Vect != NULL) {delete [] Donor_Vect; } - if (Coeff_Vect != NULL) {delete [] Coeff_Vect; } - if (storeProc != NULL) {delete [] storeProc; } - - Donor_Vect = tmp_Donor_Vect; - Coeff_Vect = tmp_Coeff_Vect; - storeProc = tmp_storeProc; - - tmp_Coeff_Vect = NULL; - tmp_Donor_Vect = NULL; - tmp_storeProc = NULL; - - nDonorPoints++; - - Area += tmp_Area; - } - } - } - - /*--- Update auxiliary data structure ---*/ - - StartVisited = nAlreadyVisited; - - tmpVect = new unsigned long[ nAlreadyVisited + nToVisit ]; - - for( jj = 0; jj < nAlreadyVisited; jj++ ) - tmpVect[jj] = alreadyVisitedDonor[jj]; - - for( jj = 0; jj < nToVisit; jj++ ) - tmpVect[ nAlreadyVisited + jj ] = ToVisit[jj]; - - if( alreadyVisitedDonor != NULL ) - delete [] alreadyVisitedDonor; - - alreadyVisitedDonor = tmpVect; - - nAlreadyVisited += nToVisit; - - delete [] ToVisit; - } - - delete [] alreadyVisitedDonor; - - /*--- Set the communication data structure and copy data from the auxiliary vectors ---*/ - - target_geometry->vertex[markTarget][iVertex]->SetnDonorPoints(nDonorPoints); - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(); - - for ( iDonor = 0; iDonor < nDonorPoints; iDonor++ ){ - target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor, Coeff_Vect[iDonor]/Area); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorPoint( iDonor, Donor_GlobalPoint[ Donor_Vect[iDonor] ] ); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); - //cout <GetnDim(); - - su2double dotA2, dotB1, dotB2; - - dotA2 = 0; - for(iDim = 0; iDim < nDim; iDim++) - dotA2 += ( A2[iDim] - A1[iDim] ) * Direction[iDim]; - - if( dotA2 >= 0 ){ - dotB1 = 0; - dotB2 = 0; - for(iDim = 0; iDim < nDim; iDim++){ - dotB1 += ( B1[iDim] - A1[iDim] ) * Direction[iDim]; - dotB2 += ( B2[iDim] - A1[iDim] ) * Direction[iDim]; - } - } - else{ - dotA2 *= -1; - - dotB1 = 0; - dotB2 = 0; - for(iDim = 0; iDim < nDim; iDim++){ - dotB1 -= ( B1[iDim] - A1[iDim] ) * Direction[iDim]; - dotB2 -= ( B2[iDim] - A1[iDim] ) * Direction[iDim]; - } - } - - if( dotB1 >= 0 && dotB1 <= dotA2 ){ - if ( dotB2 < 0 ) - return fabs( dotB1 ); - if ( dotB2 > dotA2 ) - return fabs( dotA2 - dotB1 ); - - return fabs( dotB1 - dotB2 ); - } - - if( dotB2 >= 0 && dotB2 <= dotA2 ){ - if ( dotB1 < 0 ) - return fabs(dotB2); - if ( dotB1 > dotA2 ) - return fabs( dotA2 - dotB2 ); - } - - if( ( dotB1 <= 0 && dotA2 <= dotB2 ) || ( dotB2 <= 0 && dotA2 <= dotB1 ) ) - return fabs( dotA2 ); - - return 0.0; -} - -su2double CSlidingMesh::Compute_Triangle_Intersection(su2double* A1, su2double* A2, su2double* A3, su2double* B1, su2double* B2, su2double* B3, su2double* Direction){ - - /* --- This routine is ONLY for 3D grids --- */ - /* --- Projects triangle points onto a plane, specified by its normal "Direction", and calls the ComputeIntersectionArea routine --- */ - - unsigned short iDim; - unsigned short nDim = 3; - - su2double I[3], J[3], K[3]; - su2double a1[3], a2[3], a3[3]; - su2double b1[3], b2[3], b3[3]; - su2double m1, m2; - - /* --- Reference frame is determined by: x = A1A2 y = x ^ ( -Direction ) --- */ - - for(iDim = 0; iDim < 3; iDim++){ - a1[iDim] = 0; - a2[iDim] = 0; - a3[iDim] = 0; - - b1[iDim] = 0; - b2[iDim] = 0; - b3[iDim] = 0; - } - - m1 = 0; - for(iDim = 0; iDim < nDim; iDim++){ - K[iDim] = Direction[iDim]; - - m1 += K[iDim] * K[iDim]; - } - - for(iDim = 0; iDim < nDim; iDim++) - K[iDim] /= sqrt(m1); - - m2 = 0; - for(iDim = 0; iDim < nDim; iDim++) - m2 += (A2[iDim] - A1[iDim]) * K[iDim]; - - m1 = 0; - for(iDim = 0; iDim < nDim; iDim++){ - I[iDim] = (A2[iDim] - A1[iDim]) - m2 * K[iDim]; - m1 += I[iDim] * I[iDim]; - } - - for(iDim = 0; iDim < nDim; iDim++) - I[iDim] /= sqrt(m1); - - // Cross product to find Y - J[0] = K[1]*I[2] - K[2]*I[1]; - J[1] = -(K[0]*I[2] - K[2]*I[0]); - J[2] = K[0]*I[1] - K[1]*I[0]; - - /* --- Project all points on the plane specified by Direction and change their reference frame taking A1 as origin --- */ - - for(iDim = 0; iDim < nDim; iDim++){ - a2[0] += (A2[iDim] - A1[iDim]) * I[iDim]; - a2[1] += (A2[iDim] - A1[iDim]) * J[iDim]; - a2[2] += (A2[iDim] - A1[iDim]) * K[iDim]; - - a3[0] += (A3[iDim] - A1[iDim]) * I[iDim]; - a3[1] += (A3[iDim] - A1[iDim]) * J[iDim]; - a3[2] += (A3[iDim] - A1[iDim]) * K[iDim]; - - b1[0] += (B1[iDim] - A1[iDim]) * I[iDim]; - b1[1] += (B1[iDim] - A1[iDim]) * J[iDim]; - b1[2] += (B1[iDim] - A1[iDim]) * K[iDim]; - - b2[0] += (B2[iDim] - A1[iDim]) * I[iDim]; - b2[1] += (B2[iDim] - A1[iDim]) * J[iDim]; - b2[2] += (B2[iDim] - A1[iDim]) * K[iDim]; - - b3[0] += (B3[iDim] - A1[iDim]) * I[iDim]; - b3[1] += (B3[iDim] - A1[iDim]) * J[iDim]; - b3[2] += (B3[iDim] - A1[iDim]) * K[iDim]; - } - - /* --- Compute intersection area --- */ - - return ComputeIntersectionArea( a1, a2, a3, b1, b2, b3 ); -} - -su2double CSlidingMesh::ComputeIntersectionArea( su2double* P1, su2double* P2, su2double* P3, su2double* Q1, su2double* Q2, su2double* Q3 ){ - - /* --- This routines computes the area of the polygonal element generated by the superimposition of 2 planar triangle --- */ - /* --- The 2 triangle must lie on the same plane --- */ - - unsigned short iDim, nPoints, i, j, k; - unsigned short nDim, min_theta_index; - - su2double points[16][2], IntersectionPoint[2], theta[6]; - su2double TriangleP[4][2], TriangleQ[4][2]; - su2double Area, det, dot1, dot2, dtmp, min_theta; - - nDim = 2; - nPoints = 0; - - for(iDim = 0; iDim < nDim; iDim++){ - TriangleP[0][iDim] = 0; - TriangleP[1][iDim] = P2[iDim] - P1[iDim]; - TriangleP[2][iDim] = P3[iDim] - P1[iDim]; - TriangleP[3][iDim] = 0; - - TriangleQ[0][iDim] = Q1[iDim] - P1[iDim]; - TriangleQ[1][iDim] = Q2[iDim] - P1[iDim]; - TriangleQ[2][iDim] = Q3[iDim] - P1[iDim]; - TriangleQ[3][iDim] = Q1[iDim] - P1[iDim]; - } - - - for( j = 0; j < 3; j++){ - if( CheckPointInsideTriangle(TriangleP[j], TriangleQ[0], TriangleQ[1], TriangleQ[2]) ){ - - // Then P1 is also inside triangle Q, so store it - for(iDim = 0; iDim < nDim; iDim++) - points[nPoints][iDim] = TriangleP[j][iDim]; - - nPoints++; - } - } - - for( j = 0; j < 3; j++){ - if( CheckPointInsideTriangle(TriangleQ[j], TriangleP[0], TriangleP[1], TriangleP[2]) ){ - - // Then Q1 is also inside triangle P, so store it - for(iDim = 0; iDim < nDim; iDim++) - points[nPoints][iDim] = TriangleQ[j][iDim]; - - nPoints++; - } - } - - - // Compute all edge intersections - - for( j = 0; j < 3; j++){ - for( i = 0; i < 3; i++){ - - det = (TriangleP[j][0] - TriangleP[j+1][0]) * ( TriangleQ[i][1] - TriangleQ[i+1][1] ) - (TriangleP[j][1] - TriangleP[j+1][1]) * (TriangleQ[i][0] - TriangleQ[i+1][0]); - - if ( det != 0.0 ){ - ComputeLineIntersectionPoint( TriangleP[j], TriangleP[j+1], TriangleQ[i], TriangleQ[i+1], IntersectionPoint ); - - dot1 = 0; - dot2 = 0; - for(iDim = 0; iDim < nDim; iDim++){ - dot1 += ( TriangleP[j][iDim] - IntersectionPoint[iDim] ) * ( TriangleP[j+1][iDim] - IntersectionPoint[iDim] ); - dot2 += ( TriangleQ[i][iDim] - IntersectionPoint[iDim] ) * ( TriangleQ[i+1][iDim] - IntersectionPoint[iDim] ); - } - - if( dot1 <= 0 && dot2 <= 0 ){ // It found one intersection - - // Store temporarily the intersection point - - for(iDim = 0; iDim < nDim; iDim++) - points[nPoints][iDim] = IntersectionPoint[iDim]; - - nPoints++; - } - } - } - } - - // Remove double points, if any - - for( i = 0; i < nPoints; i++){ - for( j = i+1; j < nPoints; j++){ - if(points[j][0] == points[i][0] && points[j][1] == points[i][1]){ - for( k = j; k < nPoints-1; k++){ - points[k][0] = points[k+1][0]; - points[k][1] = points[k+1][1]; - } - nPoints--; - j--; - } - } - } - - // Re-order nodes - - for( i = 1; i < nPoints; i++){ // Change again reference frame - for(iDim = 0; iDim < nDim; iDim++) - points[i][iDim] -= points[0][iDim]; - - // Compute polar azimuth for each node but the first - theta[i] = atan2(points[i][1], points[i][0]); - } - - for(iDim = 0; iDim < nDim; iDim++) - points[0][iDim] = 0; - - for( i = 1; i < nPoints; i++){ - - min_theta = theta[i]; - min_theta_index = 0; - - for( j = i + 1; j < nPoints; j++){ - - if( theta[j] < min_theta ){ - min_theta = theta[j]; - min_theta_index = j; - } - } - - if( min_theta_index != 0 ){ - dtmp = theta[i]; - theta[i] = theta[min_theta_index]; - theta[min_theta_index] = dtmp; - - dtmp = points[i][0]; - points[i][0] = points[min_theta_index][0]; - points[min_theta_index][0] = dtmp; - - dtmp = points[i][1]; - points[i][1] = points[min_theta_index][1]; - points[min_theta_index][1] = dtmp; - } - } - - // compute area using cross product rule, points position are referred to the 2-dimensional, local, reference frame centered in points[0] - - Area = 0; - - if (nPoints > 2){ - for( i = 1; i < nPoints-1; i++ ){ - - // Ax*By - Area += ( points[i][0] - points[0][0] ) * ( points[i+1][1] - points[0][1] ); - - // Ay*Bx - Area -= ( points[i][1] - points[0][1] ) * ( points[i+1][0] - points[0][0] ); - } - } - - return fabs(Area)/2; -} - -void CSlidingMesh::ComputeLineIntersectionPoint( su2double* A1, su2double* A2, su2double* B1, su2double* B2, su2double* IntersectionPoint ){ - - /* --- Uses determinant rule to compute the intersection point between 2 straight segments --- */ - /* This works only for lines on a 2D plane, A1, A2 and B1, B2 are respectively the head and the tail points of each segment, - * since they're on a 2D plane they are defined by a 2-elements array containing their coordinates */ - - su2double det; - - det = (A1[0] - A2[0]) * (B1[1] - B2[1]) - (A1[1] - A2[1]) * (B1[0] - B2[0]); - - if ( det != 0.0 ){ // else there is no intersection point - IntersectionPoint[0] = ( ( A1[0]*A2[1] - A1[1]*A2[0] ) * ( B1[0] - B2[0] ) - ( B1[0]*B2[1] - B1[1]*B2[0] ) * ( A1[0] - A2[0] ) ) / det; - IntersectionPoint[1] = ( ( A1[0]*A2[1] - A1[1]*A2[0] ) * ( B1[1] - B2[1] ) - ( B1[0]*B2[1] - B1[1]*B2[0] ) * ( A1[1] - A2[1] ) ) / det; - } - - return; -} - -bool CSlidingMesh::CheckPointInsideTriangle(su2double* Point, su2double* T1, su2double* T2, su2double* T3){ - - /* --- Check whether a point "Point" lies inside or outside a triangle defined by 3 points "T1", "T2", "T3" --- */ - /* For each edge it checks on which side the point lies: - * - Computes the unit vector pointing at the internal side of the edge - * - Comutes the vector that connects the point to a point along the edge - * - If the dot product is positive it means that the point is on the internal side of the edge - * - If the check is positive for all the 3 edges, then the point lies within the triangle - */ - - unsigned short iDim, nDim, check; - - su2double vect1[2], vect2[2], r[2]; - su2double dot; - - check = 0; - nDim = 2; - - /* --- Check first edge --- */ - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++){ - vect1[iDim] = T3[iDim] - T1[iDim]; // vec 1 is aligned to the edge - vect2[iDim] = T2[iDim] - T1[iDim]; // vect 2 is the vector connecting one edge point to the third triangle vertex - - r[iDim] = Point[iDim] - T1[iDim]; // Connects point to vertex T1 - - dot += vect2[iDim] * vect2[iDim]; - } - dot = sqrt(dot); - - for(iDim = 0; iDim < nDim; iDim++) - vect2[iDim] /= dot; - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++) - dot += vect1[iDim] * vect2[iDim]; - - for(iDim = 0; iDim < nDim; iDim++) - vect1[iDim] = T3[iDim] - (T1[iDim] + dot * vect2[iDim]); // Computes the inward unit vector - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++) // Checs that the point lies on the internal plane - dot += vect1[iDim] * r[iDim]; - - if (dot >= 0) - check++; - - /* --- Check second edge --- */ - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++){ - vect1[iDim] = T1[iDim] - T2[iDim]; - vect2[iDim] = T3[iDim] - T2[iDim]; - - r[iDim] = Point[iDim] - T2[iDim]; - - dot += vect2[iDim] * vect2[iDim]; - } - dot = sqrt(dot); - - for(iDim = 0; iDim < nDim; iDim++) - vect2[iDim] /= dot; - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++) - dot += vect1[iDim] * vect2[iDim]; - - for(iDim = 0; iDim < nDim; iDim++) - vect1[iDim] = T1[iDim] - (T2[iDim] + dot * vect2[iDim]); - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++) - dot += vect1[iDim] * r[iDim]; - - if (dot >= 0) - check++; - - /* --- Check third edge --- */ - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++){ - vect1[iDim] = T2[iDim] - T3[iDim]; - vect2[iDim] = T1[iDim] - T3[iDim]; - - r[iDim] = Point[iDim] - T3[iDim]; - - dot += vect2[iDim] * vect2[iDim]; - } - dot = sqrt(dot); - - for(iDim = 0; iDim < nDim; iDim++) - vect2[iDim] /= dot; - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++) - dot += vect1[iDim] * vect2[iDim]; - - for(iDim = 0; iDim < nDim; iDim++) - vect1[iDim] = T2[iDim] - (T3[iDim] + dot * vect2[iDim]); - - dot = 0; - for(iDim = 0; iDim < nDim; iDim++) - dot += vect1[iDim] * r[iDim]; - - if (dot >= 0) - check++; - - return (check == 3); -} - -/*--- Radial Basis Function Interpolator ---*/ -CRadialBasisFunction::CRadialBasisFunction(void): CInterpolator() { } - -CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, CConfig **config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { - - /*--- Initialize transfer coefficients between the zones ---*/ - Set_TransferCoeff(config); - -} - -CRadialBasisFunction::~CRadialBasisFunction() {} - -void CRadialBasisFunction::Set_TransferCoeff(CConfig **config) { - - int iProcessor, nProcessor = size; - int nPolynomial = 0; - int mark_donor, mark_target, target_check, donor_check; - int *skip_row = NULL, *calc_polynomial_check; - - unsigned short iDim, nDim, iMarkerInt, nMarkerInt; - - unsigned long iVertexDonor, jVertexDonor, iVertexTarget, iCount, jCount; - unsigned long nVertexDonor, nVertexTarget, nVertexDonorInDomain; - unsigned long nGlobalVertexDonor, iGlobalVertexDonor_end, nLocalM; - unsigned long point_donor, point_target; - unsigned long *nLocalM_arr; - - su2double val_i, val_j; - su2double interface_coord_tol=1e6*numeric_limits::epsilon(); - su2double *Coord_i, *Coord_j; - su2double *local_M; - su2double *P = NULL; - su2double *C_inv_trunc = NULL, *C_tmp = NULL; - su2double *target_vec, *coeff_vec; - - CSymmetricMatrix *global_M = NULL, *Mp = NULL; - -#ifdef HAVE_MPI - unsigned long iLocalM; - su2double *global_M_val_arr = NULL, *Buffer_recv_local_M; - int *Buffer_Recv_mark = new int[nProcessor], iRank; -#endif - - /*--- Initialize variables --- */ - - nMarkerInt = (int) ( config[donorZone]->GetMarker_n_ZoneInterface() / 2 ); - - nDim = donor_geometry->GetnDim(); - - - Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; - - - /*--- Cycle over nMarkersInt interface to determine communication pattern ---*/ - - for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - - /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - mark_donor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - - /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - mark_target = Find_InterfaceMarker(config[targetZone], iMarkerInt); - -#ifdef HAVE_MPI - - donor_check = -1; - target_check = -1; - - /*--- We gather a vector in MASTER_NODE to determines whether the boundary is not on the processor because of the partition or because the zone does not include it ---*/ - - SU2_MPI::Gather(&mark_donor , 1, MPI_INT, Buffer_Recv_mark, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) - for (iRank = 0; iRank < nProcessor; iRank++) - if( Buffer_Recv_mark[iRank] != -1 ) { - donor_check = Buffer_Recv_mark[iRank]; - break; - } - - SU2_MPI::Bcast(&donor_check , 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - - SU2_MPI::Gather(&mark_target, 1, MPI_INT, Buffer_Recv_mark, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - if (rank == MASTER_NODE) - for (iRank = 0; iRank < nProcessor; iRank++) - if( Buffer_Recv_mark[iRank] != -1 ) { - target_check = Buffer_Recv_mark[iRank]; - break; - } - - SU2_MPI::Bcast(&target_check, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - -#else - donor_check = mark_donor; - target_check = mark_target; -#endif - - /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ - if(target_check == -1 || donor_check == -1) - continue; - - if(mark_donor != -1) - nVertexDonor = donor_geometry->GetnVertex( mark_donor ); - else - nVertexDonor = 0; - - if(mark_target != -1) - nVertexTarget = target_geometry->GetnVertex( mark_target ); - else - nVertexTarget = 0; - - Buffer_Send_nVertex_Donor = new unsigned long [ 1 ]; - - /*--- Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor ---*/ - Determine_ArraySize(false, mark_donor, mark_target, nVertexDonor, nDim); - - /*--- Collect information about number of donor vertices in domain. - Calculate total number of donor vertices across all ranks and - number of vertices on boundary prior to current rank. ---*/ - nVertexDonorInDomain = Buffer_Send_nVertex_Donor[0]; - iGlobalVertexDonor_end = nGlobalVertexDonor = 0; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) - { - nGlobalVertexDonor += Buffer_Receive_nVertex_Donor[iProcessor]; - if (iProcessor<=rank) iGlobalVertexDonor_end += Buffer_Receive_nVertex_Donor[iProcessor]; - } - - /*-- Collect coordinates, global points, and normal vectors ---*/ - Buffer_Send_Coord = new su2double [ MaxLocalVertex_Donor * nDim ]; - Buffer_Send_GlobalPoint = new long [ MaxLocalVertex_Donor ]; - Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; - Buffer_Receive_GlobalPoint = new long [ nProcessor * MaxLocalVertex_Donor ]; - - Collect_VertexInfo( false, mark_donor, mark_target, nVertexDonor, nDim); - - /*--- Send information about size of local_M array ---*/ - nLocalM = nVertexDonorInDomain*(nVertexDonorInDomain+1)/2 \ - + nVertexDonorInDomain*(nGlobalVertexDonor-iGlobalVertexDonor_end); - - nLocalM_arr = new unsigned long [nProcessor]; -#ifdef HAVE_MPI - SU2_MPI::Allgather(&nLocalM, 1, MPI_UNSIGNED_LONG, nLocalM_arr, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#else - nLocalM_arr[MASTER_NODE] = nLocalM; -#endif - - /*--- Initialize local M array and calculate values ---*/ - local_M = new su2double [nLocalM]; - Coord_i = new su2double [nDim]; - Coord_j = new su2double [nDim]; - iCount=0; - for (iVertexDonor=0; iVertexDonorGetKindRadialBasisFunction(), - config[donorZone]->GetRadialBasisFunctionParameter(), - PointsDistance(Coord_i, Coord_j)); - } - - for (iProcessor=rank+1; iProcessorGetKindRadialBasisFunction(), - config[donorZone]->GetRadialBasisFunctionParameter(), - PointsDistance(Coord_i, Coord_j)); - } - } - } - -#ifdef HAVE_MPI - if (rank != MASTER_NODE) { - SU2_MPI::Send(local_M, nLocalM, MPI_DOUBLE, MASTER_NODE, 0, MPI_COMM_WORLD); - } - - /*--- Assemble global_M ---*/ - if (rank == MASTER_NODE) { - global_M_val_arr = new su2double [nGlobalVertexDonor*(nGlobalVertexDonor+1)/2]; - - /*--- Copy master node local_M to global_M ---*/ - iCount = 0; - for (iLocalM=0; iLocalM SINGLE_NODE) { - for (iProcessor=1; iProcessorInitialize(nGlobalVertexDonor, global_M_val_arr); - } - -#else - global_M = new CSymmetricMatrix; - global_M->Initialize((int)nVertexDonorInDomain, local_M); -#endif - - /*--- Invert M matrix ---*/ - if (rank == MASTER_NODE) { - switch (config[donorZone]->GetKindRadialBasisFunction()) - { - /*--- Basis functions that make M positive definite ---*/ - case WENDLAND_C2: - case INV_MULTI_QUADRIC: - case GAUSSIAN: - global_M->Invert(true); - break; - - case THIN_PLATE_SPLINE: - case MULTI_QUADRIC: - global_M->Invert(false); - break; - } - } - - calc_polynomial_check = new int [nDim]; - - /*--- Calculate C_inv_trunc ---*/ - if (rank == MASTER_NODE) { - - if ( config[donorZone]->GetRadialBasisFunctionPolynomialOption() ) { - - /*--- Fill P matrix and get minimum and maximum values ---*/ - P = new su2double [nGlobalVertexDonor*(nDim+1)]; - iCount = 0; - for (iProcessor=MASTER_NODE; iProcessorInitialize(nPolynomial+1); - for (int m=0; mRead((int)iVertexDonor, (int)jVertexDonor)*P[jVertexDonor*(nPolynomial+1)+n]; - } - val_i += val_j*P[iVertexDonor*(nPolynomial+1)+m]; - } - Mp->Write(m, n, val_i); - } - } - Mp->Invert(false); - - /*--- Calculate M_p*P*M_inv ---*/ - C_inv_trunc = new su2double [(nGlobalVertexDonor+nPolynomial+1)*nGlobalVertexDonor]; - for (int m=0; mRead((int)jVertexDonor, (int)iVertexDonor); - } - val_i += val_j*Mp->Read(m, n); - } - /*--- Save in row major order ---*/ - C_inv_trunc[m*nGlobalVertexDonor+iVertexDonor] = val_i; - } - } - - /*--- Calculate (I - P'*M_p*P*M_inv) ---*/ - C_tmp = new su2double [nGlobalVertexDonor*nGlobalVertexDonor]; - for (iVertexDonor=0; iVertexDonorMatMatMult(true, C_tmp, (int)nGlobalVertexDonor); - - /*--- Write to C_inv_trunc matrix ---*/ - for (iVertexDonor=0; iVertexDonorRead((int)iVertexDonor, (int)jVertexDonor); - - } // endif GetRadialBasisFunctionPolynomialOption - } // endif (rank == MASTER_NODE) - -#ifdef HAVE_MPI - SU2_MPI::Bcast(&nPolynomial, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - SU2_MPI::Bcast(calc_polynomial_check, nDim, MPI_INT, MASTER_NODE, MPI_COMM_WORLD); - - if (rank != MASTER_NODE) { - C_inv_trunc = new su2double [(nGlobalVertexDonor+nPolynomial+1)*nGlobalVertexDonor]; - } - - SU2_MPI::Bcast(C_inv_trunc, (nGlobalVertexDonor+nPolynomial+1)*nGlobalVertexDonor, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); -#endif - - /*--- Calculate H matrix ---*/ - if (config[donorZone]->GetRadialBasisFunctionPolynomialOption()) - target_vec = new su2double [nGlobalVertexDonor+nPolynomial+1]; - else - target_vec = new su2double [nGlobalVertexDonor]; - - coeff_vec = new su2double [nGlobalVertexDonor]; - - for (iVertexTarget = 0; iVertexTarget < nVertexTarget; iVertexTarget++) { - - point_target = target_geometry->vertex[mark_target][iVertexTarget]->GetNode(); - - if ( target_geometry->node[point_target]->GetDomain() ) { - iCount = 0; - if (config[donorZone]->GetRadialBasisFunctionPolynomialOption()) { - target_vec[iCount] = 1; - iCount++; - } - - for (iDim=0; iDimnode[point_target]->GetCoord(iDim); - if (config[donorZone]->GetRadialBasisFunctionPolynomialOption()) { - if (calc_polynomial_check[iDim] == 1) { - target_vec[iCount] = Coord_i[iDim]; - iCount++; - } - } - } - - for (iProcessor=0; iProcessorGetKindRadialBasisFunction(), - config[donorZone]->GetRadialBasisFunctionParameter(), - PointsDistance(Coord_i, Coord_j)); - } - } - - for (iVertexDonor=0; iVertexDonorvertex[mark_target][iVertexTarget]->SetnDonorPoints(iCount); - target_geometry->vertex[mark_target][iVertexTarget]->Allocate_DonorInfo(); - - iCount = 0; - jCount = 0; - for (iProcessor=0; iProcessorvertex[mark_target][iVertexTarget]->SetInterpDonorPoint(jCount, point_donor); - target_geometry->vertex[mark_target][iVertexTarget]->SetInterpDonorProcessor(jCount, iProcessor); - target_geometry->vertex[mark_target][iVertexTarget]->SetDonorCoeff(jCount, coeff_vec[iCount]); - jCount++; - } - iCount++; - } - } - } // endif - } // endfor - - /*--- Memory management ---*/ - delete [] nLocalM_arr; - delete [] local_M; - delete [] Coord_i; - delete [] Coord_j; - delete [] calc_polynomial_check; - delete [] C_inv_trunc; - delete [] target_vec; - delete [] coeff_vec; - - if ( rank == MASTER_NODE ) { - delete global_M; - - if ( config[donorZone]->GetRadialBasisFunctionPolynomialOption() ) { - delete [] skip_row; - delete [] P; - delete Mp; - delete [] C_tmp; - } - } - - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_GlobalPoint; - - delete[] Buffer_Receive_Coord; - delete[] Buffer_Receive_GlobalPoint; - - delete[] Buffer_Send_nVertex_Donor; - -#ifdef HAVE_MPI - if (rank == MASTER_NODE) - delete [] global_M_val_arr; -#endif - } // end loop over markers - - delete[] Buffer_Receive_nVertex_Donor; - -#ifdef HAVE_MPI - if (rank == MASTER_NODE) - delete [] Buffer_Recv_mark; -#endif -} - -void CRadialBasisFunction::Check_PolynomialTerms(int m, unsigned long n, const int *skip_row, su2double max_diff_tol_in, int *keep_row, int &n_polynomial, su2double *P) -{ - /*--- This routine keeps the AD information in P but the calculations are done in passivedouble as their purpose - is to decide which (if any) row of P to remove, and that process is not differentiable anyway. ---*/ - - int *write_row = NULL; - unsigned long iCount, jCount, n_rows; - passivedouble sum, max_diff, max_coeff, *coeff = NULL, max_diff_tol = SU2_TYPE::GetValue(max_diff_tol_in); - CSymmetricMatrix *PPT; - su2double *P_tmp = NULL; - - n_rows = 0; - for (int i=0; iInitialize((int)n_rows); - - iCount = 0; - for (int i = 0; i < m; i ++) { - if (skip_row[i] == 0) { - - jCount = 0; - for (int j = 0; j < m; j ++){ - if (skip_row[j] == 0) { - - sum = 0.0; - for (unsigned long k = 0; k < n; k ++) - { - sum += SU2_TYPE::GetValue(P[k*m+i]*P[k*m+j]); - } - PPT->Write((int)iCount, (int)jCount, sum); - - jCount++; - } - } - - iCount++; - } - } - - PPT->Invert(true); - - /*--- RHS for the least squares fit (vector of ones times P) ---*/ - coeff = new passivedouble [n_rows]; - iCount = 0; - for (int i = 0; i < m; i ++) { - if (skip_row[i] == 0) { - coeff[iCount] = 0; - for (unsigned long j = 0; j < n; j += 1) - { - coeff[iCount] += SU2_TYPE::GetValue(P[j*m+i]); - } - iCount++; - } - } - - /*--- Multiply the RHS by the inverse thus obtaining the coefficients ---*/ - PPT->MatVecMult(coeff); - - /*--- Determine the maximum deviation of the points from the fitted plane ---*/ - max_diff = 0; - for (unsigned long i = 0; i < n; i ++) - { - sum = 0; - iCount = 0; - for (int j = 0; j < m; j ++) - { - if (skip_row[j] == 0) { - sum += coeff[iCount]*SU2_TYPE::GetValue(P[i*m+j]); - iCount++; - } - } - /*--- 1.0 is the arbitrary constant we are assuming when fitting the plane ---*/ - max_diff = max(abs(1.0-sum), max_diff); - } - - for (unsigned long i=0; i max_coeff) iCount = i; - } - - for (unsigned long i=0; i::min()) rbf = 0.0; - else rbf *= rbf*log(rbf); - break; - - case MULTI_QUADRIC: - case INV_MULTI_QUADRIC: - rbf = sqrt(1.0+rbf*rbf); - if(type == INV_MULTI_QUADRIC) rbf = 1.0/rbf; - break; - } - - return rbf; -} - -/*--- Symmetric matrix class definitions ---*/ -CSymmetricMatrix::CSymmetricMatrix() -{ - initialized = false; - inversed = false; - decomposed = none; - - val_vec = NULL; - decompose_vec = NULL; - inv_val_vec = NULL; - perm_vec = NULL; -} - -CSymmetricMatrix::~CSymmetricMatrix() -{ - if(val_vec) {delete [] val_vec;} - if(decompose_vec) {delete [] decompose_vec;} - if(inv_val_vec) {delete [] inv_val_vec;} - if(perm_vec) {delete [] perm_vec;} -} - -void CSymmetricMatrix::Initialize(int N) -{ - int i; - - sz = N; - num_val = sz*(sz+1)/2; - val_vec = new passivedouble [num_val]; - for (i=0; i abs(pivot) ) { - pivot = decompose_vec[CalcIdxFull(i, j)]; - pivot_idx = i; - interchange_row = true; - } - } - - if ( interchange_row ) { - for ( k=0; k=sz || j<0 || j>=sz) { - throw out_of_range("Index to access matrix out of bounds."); - } -} - -void CSymmetricMatrix::Write(int i, int j, const su2double& val) -{ - CheckBounds(i,j); - val_vec[CalcIdx(i, j)] = SU2_TYPE::GetValue(val); -} - -passivedouble CSymmetricMatrix::Read(int i, int j) -{ - CheckBounds(i,j); - return val_vec[CalcIdx(i, j)]; -} - -passivedouble CSymmetricMatrix::ReadL(int i, int j) -{ - passivedouble *p = NULL; - - CheckBounds(i,j); - - if (decompose_vec) { p = decompose_vec; } - else { p = val_vec; } - - switch (decomposed) { - case cholesky: - if (i>=j) return p[CalcIdx(i, j)]; - else return 0.0; - - case lu: - if (i>j) return p[CalcIdxFull(i, j)]; - else return passivedouble(i==j); - - default: - throw invalid_argument("Matrix not decomposed yet or results have been deleted."); - } -} - -passivedouble CSymmetricMatrix::ReadU(int i, int j) -{ - passivedouble *p = NULL; - - CheckBounds(i,j); - - if (decompose_vec){ p = decompose_vec; } - else {p = val_vec;} - - switch (decomposed) { - case cholesky: - return 0.0; - - case lu: - if (j>=i) return p[CalcIdxFull(j, i)]; - else return 0.0; - - default: - throw invalid_argument("Matrix not decomposed yet or results have been deleted."); - } -} - -double CSymmetricMatrix::ReadInv(int i, int j) -{ - passivedouble *p = NULL; - - CheckBounds(i,j); - - if (inversed) { - if (inv_val_vec) { p = inv_val_vec; } - else { p = val_vec; } - - return p[CalcIdx(i, j)]; - } - else { - throw invalid_argument("Matrix inverse not calculated yet."); - } -} From 123f008a84fe7b9d5d4648604beba96a1ef483cb Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 31 Mar 2020 16:47:54 +0100 Subject: [PATCH 52/79] update primal FSI cases due to initialized mesh deformation --- TestCases/parallel_regression.py | 6 +++--- TestCases/serial_regression.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/TestCases/parallel_regression.py b/TestCases/parallel_regression.py index 36b5cc768bc2..a21b75b97ce5 100644 --- a/TestCases/parallel_regression.py +++ b/TestCases/parallel_regression.py @@ -1052,7 +1052,7 @@ def main(): stat_fsi.cfg_dir = "fea_fsi/stat_fsi" stat_fsi.cfg_file = "config.cfg" stat_fsi.test_iter = 7 - stat_fsi.test_vals = [-3.313322, -4.963786, 0.000000, 46.000000] #last 5 columns + stat_fsi.test_vals = [-3.313612, -4.957573, 0.000000, 7.000000] #last 4 columns stat_fsi.su2_exec = "mpirun -n 2 SU2_CFD" stat_fsi.multizone = True stat_fsi.timeout = 1600 @@ -1064,7 +1064,7 @@ def main(): dyn_fsi.cfg_dir = "fea_fsi/dyn_fsi" dyn_fsi.cfg_file = "config.cfg" dyn_fsi.test_iter = 4 - dyn_fsi.test_vals = [-4.389734, -4.060117, 0.000000, 64.000000] #last 5 columns + dyn_fsi.test_vals = [-4.379832, -4.005999, 0.000000, 0.000000] #last 4 columns dyn_fsi.multizone = True dyn_fsi.unsteady = True dyn_fsi.su2_exec = "mpirun -n 2 SU2_CFD" @@ -1077,7 +1077,7 @@ def main(): stat_fsi_restart.cfg_dir = "fea_fsi/stat_fsi" stat_fsi_restart.cfg_file = "config_restart.cfg" stat_fsi_restart.test_iter = 1 - stat_fsi_restart.test_vals = [-3.422307, -4.212725, 0.000000, 46.000000] #last 5 columns + stat_fsi_restart.test_vals = [-3.422425, -4.289201, 0.000000, 27.000000] #last 4 columns stat_fsi_restart.su2_exec = "mpirun -n 2 SU2_CFD" stat_fsi_restart.multizone = True stat_fsi_restart.timeout = 1600 diff --git a/TestCases/serial_regression.py b/TestCases/serial_regression.py index c322903f1ece..06ba6e448457 100644 --- a/TestCases/serial_regression.py +++ b/TestCases/serial_regression.py @@ -1231,7 +1231,7 @@ def main(): stat_fsi.cfg_dir = "fea_fsi/stat_fsi" stat_fsi.cfg_file = "config.cfg" stat_fsi.test_iter = 7 - stat_fsi.test_vals = [-3.323551, -4.982863, 0.000000, 47.000000] #last 5 columns + stat_fsi.test_vals = [-3.326934, -4.981505, 0.000000, 7.000000] #last 5 columns stat_fsi.su2_exec = "SU2_CFD" stat_fsi.timeout = 1600 stat_fsi.multizone = True @@ -1243,7 +1243,7 @@ def main(): stat_fsi_restart.cfg_dir = "fea_fsi/stat_fsi" stat_fsi_restart.cfg_file = "config_restart.cfg" stat_fsi_restart.test_iter = 1 - stat_fsi_restart.test_vals = [-3.407098, -4.248366, 0.000000, 47.000000] #last 5 columns + stat_fsi_restart.test_vals = [-3.407486, -4.339837, 0.000000, 27.000000] #last 5 columns stat_fsi_restart.multizone = True stat_fsi_restart.su2_exec = "SU2_CFD" stat_fsi_restart.timeout = 1600 @@ -1255,7 +1255,7 @@ def main(): dyn_fsi.cfg_dir = "fea_fsi/dyn_fsi" dyn_fsi.cfg_file = "config.cfg" dyn_fsi.test_iter = 4 - dyn_fsi.test_vals = [-4.389732, -4.060110, 0.000000, 59.000000] #last 5 columns + dyn_fsi.test_vals = [-4.379829, -4.005994, 0.000000, 0.000000] #last 5 columns dyn_fsi.multizone = True dyn_fsi.unsteady = True dyn_fsi.su2_exec = "SU2_CFD" From 83bb15d55f9fe06d662c397d62f90104d47ae834 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 31 Mar 2020 16:48:26 +0100 Subject: [PATCH 53/79] fix for disc adj FEA problems --- SU2_CFD/include/limiters/computeLimiters_impl.hpp | 6 +----- SU2_CFD/src/solvers/CFEASolver.cpp | 4 ++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SU2_CFD/include/limiters/computeLimiters_impl.hpp b/SU2_CFD/include/limiters/computeLimiters_impl.hpp index 9b4cd2fd3888..47c257349989 100644 --- a/SU2_CFD/include/limiters/computeLimiters_impl.hpp +++ b/SU2_CFD/include/limiters/computeLimiters_impl.hpp @@ -98,15 +98,13 @@ void computeLimiters_impl(CSolver* solver, omp_get_max_threads(), OMP_MAX_CHUNK); #endif -#ifdef CODI_REVERSE_TYPE bool tapeActive = false; if (config.GetDiscrete_Adjoint() && config.GetFrozen_Limiter_Disc()) { /*--- If limiters are frozen do not record the computation ---*/ - tapeActive = AD::globalTape.isActive(); + tapeActive = AD::TapeActive(); AD::StopRecording(); } -#endif CLimiterDetails limiterDetails; @@ -248,8 +246,6 @@ void computeLimiters_impl(CSolver* solver, } SU2_OMP_BARRIER -#ifdef CODI_REVERSE_TYPE if (tapeActive) AD::StartRecording(); -#endif } diff --git a/SU2_CFD/src/solvers/CFEASolver.cpp b/SU2_CFD/src/solvers/CFEASolver.cpp index 8dc172501e92..e68759d4e69c 100644 --- a/SU2_CFD/src/solvers/CFEASolver.cpp +++ b/SU2_CFD/src/solvers/CFEASolver.cpp @@ -2741,6 +2741,10 @@ void CFEASolver::Solve_System(CGeometry *geometry, CConfig *config) { SU2_OMP_PARALLEL { + /*--- This is required for the discrete adjoint. ---*/ + SU2_OMP_FOR_STAT(OMP_MIN_SIZE) + for (auto i = nPointDomain*nVar; i < nPoint*nVar; ++i) LinSysRes[i] = 0.0; + /*--- Solve or smooth the linear system. ---*/ auto iter = System.Solve(Jacobian, LinSysRes, LinSysSol, geometry, config); From 5e5237cf468b7774dc85670a02a0fa12021b53cd Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 31 Mar 2020 18:19:54 +0100 Subject: [PATCH 54/79] updates and fixes for testcases --- TestCases/parallel_regression_AD.py | 2 +- .../py_wrapper/disc_adj_flow/mesh_disp_sens/configAD_flow.cfg | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/TestCases/parallel_regression_AD.py b/TestCases/parallel_regression_AD.py index e8e1d10790eb..d1d23b143a49 100644 --- a/TestCases/parallel_regression_AD.py +++ b/TestCases/parallel_regression_AD.py @@ -303,7 +303,7 @@ def main(): discadj_fsi2.cfg_dir = "disc_adj_fsi/Airfoil_2d" discadj_fsi2.cfg_file = "config.cfg" discadj_fsi2.test_iter = 8 - discadj_fsi2.test_vals = [-5.070991, -2.5239e-13] #last 2 columns + discadj_fsi2.test_vals = [-5.071003, -2.5250e-13] #last 2 columns discadj_fsi2.su2_exec = "mpirun -n 2 SU2_CFD_AD" discadj_fsi2.timeout = 1600 discadj_fsi2.tol = 1e-16 diff --git a/TestCases/py_wrapper/disc_adj_flow/mesh_disp_sens/configAD_flow.cfg b/TestCases/py_wrapper/disc_adj_flow/mesh_disp_sens/configAD_flow.cfg index 6f8f5a69fecb..4d48d3472619 100644 --- a/TestCases/py_wrapper/disc_adj_flow/mesh_disp_sens/configAD_flow.cfg +++ b/TestCases/py_wrapper/disc_adj_flow/mesh_disp_sens/configAD_flow.cfg @@ -155,6 +155,7 @@ WRT_CON_FREQ_DUALTIME= 1 DEFORM_MESH = YES DEFORM_STIFFNESS_TYPE = WALL_DISTANCE +DEFORM_POISSONS_RATIO = 1E6 DEFORM_LINEAR_SOLVER = CONJUGATE_GRADIENT DEFORM_LINEAR_SOLVER_PREC = ILU From f73eec5ba876ea2ba8213e24ef962c9fb90a453a Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 31 Mar 2020 18:23:01 +0100 Subject: [PATCH 55/79] version update in new file --- TestCases/disc_adj_rans/naca0012/naca0012.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TestCases/disc_adj_rans/naca0012/naca0012.cfg b/TestCases/disc_adj_rans/naca0012/naca0012.cfg index 121f6adc3a08..dd94734aa705 100644 --- a/TestCases/disc_adj_rans/naca0012/naca0012.cfg +++ b/TestCases/disc_adj_rans/naca0012/naca0012.cfg @@ -5,7 +5,7 @@ % Author: Steffen Schotthöfer % % Institution: TU Kaiserslautern % % Date: Mar 16, 2017 % -% File Version 7.0.2 "Blackbird" % +% File Version 7.0.3 "Blackbird" % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% From 4944e2e83c842508f38abdff552830df98a6a92e Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Wed, 1 Apr 2020 13:12:18 +0100 Subject: [PATCH 56/79] fix #915 --- SU2_CFD/src/output/CFlowCompOutput.cpp | 1 + SU2_CFD/src/output/CFlowIncOutput.cpp | 1 + SU2_CFD/src/solvers/CEulerSolver.cpp | 27 +++++++++----------- SU2_CFD/src/solvers/CIncEulerSolver.cpp | 33 ++++++------------------- 4 files changed, 21 insertions(+), 41 deletions(-) diff --git a/SU2_CFD/src/output/CFlowCompOutput.cpp b/SU2_CFD/src/output/CFlowCompOutput.cpp index d52ade6b9124..1d64d91625b1 100644 --- a/SU2_CFD/src/output/CFlowCompOutput.cpp +++ b/SU2_CFD/src/output/CFlowCompOutput.cpp @@ -58,6 +58,7 @@ CFlowCompOutput::CFlowCompOutput(CConfig *config, unsigned short nDim) : CFlowOu requestedVolumeFields.emplace_back("COORDINATES"); requestedVolumeFields.emplace_back("SOLUTION"); requestedVolumeFields.emplace_back("PRIMITIVE"); + if (config->GetGrid_Movement()) requestedVolumeFields.emplace_back("GRID_VELOCITY"); nRequestedVolumeFields = requestedVolumeFields.size(); } diff --git a/SU2_CFD/src/output/CFlowIncOutput.cpp b/SU2_CFD/src/output/CFlowIncOutput.cpp index 64dd61c090d8..b631a6a20b65 100644 --- a/SU2_CFD/src/output/CFlowIncOutput.cpp +++ b/SU2_CFD/src/output/CFlowIncOutput.cpp @@ -60,6 +60,7 @@ CFlowIncOutput::CFlowIncOutput(CConfig *config, unsigned short nDim) : CFlowOutp requestedVolumeFields.emplace_back("COORDINATES"); requestedVolumeFields.emplace_back("SOLUTION"); requestedVolumeFields.emplace_back("PRIMITIVE"); + if (config->GetGrid_Movement()) requestedVolumeFields.emplace_back("GRID_VELOCITY"); nRequestedVolumeFields = requestedVolumeFields.size(); } diff --git a/SU2_CFD/src/solvers/CEulerSolver.cpp b/SU2_CFD/src/solvers/CEulerSolver.cpp index 327a50b5c92e..06d623de796f 100644 --- a/SU2_CFD/src/solvers/CEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CEulerSolver.cpp @@ -11483,19 +11483,14 @@ void CEulerSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig unsigned short iDim, iVar, iMesh, iMeshFine; unsigned long iPoint, index, iChildren, Point_Fine; unsigned short turb_model = config->GetKind_Turb_Model(); - su2double Area_Children, Area_Parent, *Coord, *Solution_Fine; + su2double Area_Children, Area_Parent, Coord[MAXNDIM] = {0.0}, *Solution_Fine; bool dual_time = ((config->GetTime_Marching() == DT_STEPPING_1ST) || (config->GetTime_Marching() == DT_STEPPING_2ND)); - bool static_fsi = ((config->GetTime_Marching() == STEADY) && - config->GetFSI_Simulation()); + bool static_fsi = ((config->GetTime_Marching() == STEADY) && config->GetFSI_Simulation()); bool steady_restart = config->GetSteadyRestart(); - bool turbulent = (config->GetKind_Turb_Model() != NONE); - - string restart_filename = config->GetFilename(config->GetSolution_FileName(), "", val_iter); + bool turbulent = (config->GetKind_Turb_Model() != NONE); - Coord = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Coord[iDim] = 0.0; + string restart_filename = config->GetFilename(config->GetSolution_FileName(), "", val_iter); int counter = 0; long iPoint_Local = 0; unsigned long iPoint_Global = 0; @@ -11550,13 +11545,12 @@ void CEulerSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig /*--- If we are restarting the solution from a previously computed static calculation (no grid movement) ---*/ /*--- the grid velocities are set to 0. This is useful for FSI computations ---*/ + /*--- Rewind the index to retrieve the Coords. ---*/ + index = counter*Restart_Vars[1]; + for (iDim = 0; iDim < nDim; iDim++) { Coord[iDim] = Restart_Data[index+iDim]; } + su2double GridVel[3] = {0.0,0.0,0.0}; if (!steady_restart) { - - /*--- Rewind the index to retrieve the Coords. ---*/ - index = counter*Restart_Vars[1]; - for (iDim = 0; iDim < nDim; iDim++) { Coord[iDim] = Restart_Data[index+iDim]; } - /*--- Move the index forward to get the grid velocities. ---*/ index = counter*Restart_Vars[1] + skipVars + nVar + turbVars; for (iDim = 0; iDim < nDim; iDim++) { GridVel[iDim] = Restart_Data[index+iDim]; } @@ -11568,6 +11562,9 @@ void CEulerSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig } } + /*--- For static FSI problems, grid_movement is 0 but we need to read in and store the + grid coordinates for each node (but not the grid velocities, as there are none). ---*/ + if (static_fsi && val_update_geo) { /*--- Rewind the index to retrieve the Coords. ---*/ index = counter*Restart_Vars[1]; @@ -11691,8 +11688,6 @@ void CEulerSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig if (dual_time && config->GetGrid_Movement() && (config->GetKind_GridMovement() != RIGID_MOTION)) Restart_OldGeometry(geometry[MESH_0], config); - delete [] Coord; - /*--- Delete the class memory that is used to load the restart. ---*/ delete [] Restart_Vars; Restart_Vars = nullptr; diff --git a/SU2_CFD/src/solvers/CIncEulerSolver.cpp b/SU2_CFD/src/solvers/CIncEulerSolver.cpp index 2a7a0d8427be..0e20070e169f 100644 --- a/SU2_CFD/src/solvers/CIncEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CIncEulerSolver.cpp @@ -5830,24 +5830,18 @@ void CIncEulerSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConf unsigned short iDim, iVar, iMesh, iMeshFine; unsigned long iPoint, index, iChildren, Point_Fine; unsigned short turb_model = config->GetKind_Turb_Model(); - su2double Area_Children, Area_Parent, *Coord, *Solution_Fine; - bool static_fsi = ((config->GetTime_Marching() == STEADY) && - (config->GetFSI_Simulation())); + su2double Area_Children, Area_Parent, Coord[3] = {0.0}, *Solution_Fine; + bool static_fsi = ((config->GetTime_Marching() == STEADY) && config->GetFSI_Simulation()); bool dual_time = ((config->GetTime_Marching() == DT_STEPPING_1ST) || (config->GetTime_Marching() == DT_STEPPING_2ND)); bool steady_restart = config->GetSteadyRestart(); - bool turbulent = (config->GetKind_Solver() == INC_RANS) || (config->GetKind_Solver() == DISC_ADJ_INC_RANS); + bool turbulent = (config->GetKind_Solver() == INC_RANS) || (config->GetKind_Solver() == DISC_ADJ_INC_RANS); string restart_filename = config->GetFilename(config->GetSolution_FileName(), "", val_iter); - Coord = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) - Coord[iDim] = 0.0; - int counter = 0; long iPoint_Local = 0; unsigned long iPoint_Global = 0; unsigned long iPoint_Global_Local = 0; - unsigned short rbuf_NotMatching = 0, sbuf_NotMatching = 0; /*--- Skip coordinates ---*/ @@ -5910,13 +5904,12 @@ void CIncEulerSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConf /*--- If we are restarting the solution from a previously computed static calculation (no grid movement) ---*/ /*--- the grid velocities are set to 0. This is useful for FSI computations ---*/ + /*--- Rewind the index to retrieve the Coords. ---*/ + index = counter*Restart_Vars[1]; + for (iDim = 0; iDim < nDim; iDim++) { Coord[iDim] = Restart_Data[index+iDim]; } + su2double GridVel[3] = {0.0,0.0,0.0}; if (!steady_restart) { - - /*--- Rewind the index to retrieve the Coords. ---*/ - index = counter*Restart_Vars[1]; - for (iDim = 0; iDim < nDim; iDim++) { Coord[iDim] = Restart_Data[index+iDim]; } - /*--- Move the index forward to get the grid velocities. ---*/ index = counter*Restart_Vars[1] + skipVars + nVar_Restart + turbVars; for (iDim = 0; iDim < nDim; iDim++) { GridVel[iDim] = Restart_Data[index+iDim]; } @@ -5928,7 +5921,6 @@ void CIncEulerSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConf } } - /*--- For static FSI problems, grid_movement is 0 but we need to read in and store the grid coordinates for each node (but not the grid velocities, as there are none). ---*/ @@ -5950,14 +5942,7 @@ void CIncEulerSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConf /*--- Detect a wrong solution file ---*/ - if (iPoint_Global_Local < nPointDomain) { sbuf_NotMatching = 1; } - -#ifndef HAVE_MPI - rbuf_NotMatching = sbuf_NotMatching; -#else - SU2_MPI::Allreduce(&sbuf_NotMatching, &rbuf_NotMatching, 1, MPI_UNSIGNED_SHORT, MPI_SUM, MPI_COMM_WORLD); -#endif - if (rbuf_NotMatching != 0) { + if (iPoint_Global_Local < nPointDomain) { SU2_MPI::Error(string("The solution file ") + restart_filename + string(" doesn't match with the mesh file!\n") + string("It could be empty lines at the end of the file."), CURRENT_FUNCTION); } @@ -6057,8 +6042,6 @@ void CIncEulerSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConf if (dual_time && config->GetGrid_Movement() && (config->GetKind_GridMovement() != RIGID_MOTION)) Restart_OldGeometry(geometry[MESH_0], config); - delete [] Coord; - /*--- Delete the class memory that is used to load the restart. ---*/ if (Restart_Vars != NULL) delete [] Restart_Vars; From 0015fb551a462f6de4f83549f84b340f28a41f13 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 2 Apr 2020 16:20:10 +0100 Subject: [PATCH 57/79] refactor isoparametric interpolation --- Common/include/geometry/dual_grid/CVertex.hpp | 26 - Common/include/geometry/elements/CElement.hpp | 22 +- .../interface_interpolation/CInterpolator.hpp | 52 +- .../CIsoparametric.hpp | 53 +- Common/include/toolboxes/geometry_toolbox.hpp | 116 +++ Common/src/geometry/elements/CQUAD4.cpp | 20 +- .../interface_interpolation/CInterpolator.cpp | 172 ++-- .../CIsoparametric.cpp | 762 ++++++++---------- .../CNearestNeighbor.cpp | 15 +- .../CRadialBasisFunction.cpp | 13 +- .../interface_interpolation/CSlidingMesh.cpp | 7 +- SU2_CFD/src/solvers/CFEASolver.cpp | 48 +- 12 files changed, 617 insertions(+), 689 deletions(-) create mode 100644 Common/include/toolboxes/geometry_toolbox.hpp diff --git a/Common/include/geometry/dual_grid/CVertex.hpp b/Common/include/geometry/dual_grid/CVertex.hpp index 6d5915dd9ed6..41c2fc4da20d 100644 --- a/Common/include/geometry/dual_grid/CVertex.hpp +++ b/Common/include/geometry/dual_grid/CVertex.hpp @@ -49,8 +49,6 @@ class CVertex : public CDualGrid { unsigned long Normal_Neighbor; /*!< \brief Index of the closest neighbor. */ unsigned long *Donor_Points; /*!< \brief indices of donor points for interpolation across zones */ unsigned long *Donor_Proc; /*!< \brief indices of donor processor for interpolation across zones in parallel */ - unsigned long Donor_Elem; /*!< \brief Store the donor element for interpolation across zones/ */ - unsigned short Donor_Face; /*!< \brief Store the donor face (w/in donor element) for interpolation across zones */ su2double Basis_Function[3]; /*!< \brief Basis function values for interpolation across zones. */ su2double *Donor_Coeff; /*!< \brief Store a list of coefficients corresponding to the donor points. */ unsigned short nDonor_Points; /*!< \brief Number of points in Donor_Coeff. */ @@ -307,30 +305,6 @@ class CVertex : public CDualGrid { */ inline bool GetActDisk_Perimeter(void) const { return ActDisk_Perimeter; } - /*! - * \brief Set the donor element of a vertex for interpolation across zones. - * \param[in] val_donorelem - donor element index. - */ - inline void SetDonorElem(long val_donorelem) { Donor_Elem = val_donorelem; } - - /*! - * \brief Get the donor element of a vertex for interpolation across zones. - * \return Value of the donor element of a vertex. - */ - inline long GetDonorElem(void) const { return Donor_Elem; } - - /*! - * \brief Set the donor face of a vertex for interpolation across zones. - * \param[in] val_donorface- donor face index (w/in donor elem). - */ - inline void SetDonorFace(unsigned short val_donorface) { Donor_Face = val_donorface; } - - /*! - * \brief Get the donor face of a vertex for interpolation across zones. - * \return Value of the donor face index (w/in donor elem). - */ - inline unsigned short GetDonorFace(void) const { return Donor_Face; } - /*! * \brief Set the finite element basis functions needed for interpolation. * \param[in] val_node - a node index of the owner element. diff --git a/Common/include/geometry/elements/CElement.hpp b/Common/include/geometry/elements/CElement.hpp index 20975dd2b9fc..c3aae53ef255 100644 --- a/Common/include/geometry/elements/CElement.hpp +++ b/Common/include/geometry/elements/CElement.hpp @@ -7,7 +7,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -627,6 +627,26 @@ class CQUAD4 final : public CElementWithKnownSizes<4,4,2> { */ CQUAD4(); + /*! + * \brief Shape functions (Ni) evaluated at point Xi,Eta. + */ + inline static void ShapeFunctions(su2double Xi, su2double Eta, su2double* Ni) { + Ni[0] = 0.25*(1.0-Xi)*(1.0-Eta); + Ni[1] = 0.25*(1.0+Xi)*(1.0-Eta); + Ni[2] = 0.25*(1.0+Xi)*(1.0+Eta); + Ni[3] = 0.25*(1.0-Xi)*(1.0+Eta); + } + + /*! + * \brief Shape function Jacobian (dNi) evaluated at point Xi,Eta. + */ + inline static void ShapeFunctionJacobian(su2double Xi, su2double Eta, su2double dNi[][2]) { + dNi[0][0] = -0.25*(1.0-Eta); dNi[0][1] = -0.25*(1.0-Xi); + dNi[1][0] = 0.25*(1.0-Eta); dNi[1][1] = -0.25*(1.0+Xi); + dNi[2][0] = 0.25*(1.0+Eta); dNi[2][1] = 0.25*(1.0+Xi); + dNi[3][0] = -0.25*(1.0+Eta); dNi[3][1] = 0.25*(1.0-Xi); + } + /*! * \brief Compute the value of the area of the element. * \param[in] mode - Type of coordinates to consider in the computation. diff --git a/Common/include/interface_interpolation/CInterpolator.hpp b/Common/include/interface_interpolation/CInterpolator.hpp index ec15bd712db1..de0754b94d0d 100644 --- a/Common/include/interface_interpolation/CInterpolator.hpp +++ b/Common/include/interface_interpolation/CInterpolator.hpp @@ -27,10 +27,14 @@ #pragma once #include "../../include/datatype_structure.hpp" +#include "../../include/toolboxes/C2DContainer.hpp" +#include class CConfig; class CGeometry; +using namespace std; + /*! * \class CInterpolator * \brief Main class for defining the interpolator, it requires @@ -147,47 +151,35 @@ class CInterpolator { void ReconstructBoundary(unsigned long val_zone, int val_marker); /*! - * \brief compute squared distance between 2 points - * \param[in] nDim - number of dimensions - * \param[in] point_i - coordinates of point i - * \param[in] point_j - coordinates of point j - */ - static inline su2double PointsSquareDistance(unsigned short nDim, const su2double *point_i, const su2double *point_j) { - su2double d = 0.0; - for(unsigned short iDim = 0; iDim < nDim; iDim++) - d += pow(point_j[iDim] - point_i[iDim], 2); - return d; - } - - /*! - * \brief compute distance between 2 points - * \param[in] nDim - number of dimensions - * \param[in] point_i - coordinates of point i - * \param[in] point_j - coordinates of point j - */ - static inline su2double PointsDistance(unsigned short nDim, const su2double *point_i, const su2double *point_j) { - return sqrt(PointsSquareDistance(nDim, point_i, point_j)); - } - - /*! - * \brief Determine array sizes used to collect and send coordinate and global point - * information. - * \param[in] faces - boolean that determines whether or not to set face information as well + * \brief Determine array sizes used to collect and send coordinate and global point information. * \param[in] markDonor - Index of the boundary on the donor domain. * \param[in] markTarget - Index of the boundary on the target domain. * \param[in] nVertexDonor - Number of vertices on the donor boundary. * \param[in] nDim - number of physical dimensions. */ - void Determine_ArraySize(bool faces, int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim); + void Determine_ArraySize(int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim); /*! - * \brief Collect and communicate vertex info: coord, global point, and if faces=true the normal vector - * \param[in] faces - boolean that determines whether or not to set face information as well + * \brief Collect and communicate vertex info: coord, global point. * \param[in] markDonor - Index of the boundary on the donor domain. * \param[in] markTarget - Index of the boundary on the target domain. * \param[in] nVertexDonor - Number of vertices on the donor boundary. * \param[in] nDim - number of physical dimensions. */ - void Collect_VertexInfo(bool faces, int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim); + void Collect_VertexInfo(int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim); + /*! + * \brief Collect all donor elements in an interface pair. + * \param[in] markDonor - Index of the boundary on the donor domain. + * \param[in] nDim - number of physical dimensions. + * \param[in] compress - Squeeze the information (Allgatherv instead of Allgather). + * \param[out] allNumElem - Number of donor element per rank. + * \param[out] numNodes - Number of nodes for each element. + * \param[out] idxNodes - Index (global) of those nodes. + * \return Number of collected donor elements. + * \note The last two outputs are always sized for Allgather. + */ + unsigned long Collect_ElementInfo(int markDonor, unsigned short nDim, bool compress, + vector& allNumElem, vector& numNodes, + su2matrix& idxNodes) const; }; diff --git a/Common/include/interface_interpolation/CIsoparametric.hpp b/Common/include/interface_interpolation/CIsoparametric.hpp index 7b81bc765270..2990026e40d3 100644 --- a/Common/include/interface_interpolation/CIsoparametric.hpp +++ b/Common/include/interface_interpolation/CIsoparametric.hpp @@ -1,7 +1,7 @@ /*! * \file CIsoparametric.hpp * \brief Isoparametric interpolation using FE shape functions. - * \author H. Kline + * \author H. Kline, P. Gomes * \version 7.0.3 "Blackbird" * * SU2 Project Website: https://su2code.github.io @@ -32,6 +32,10 @@ * \brief Isoparametric interpolation. */ class CIsoparametric final : public CInterpolator { +private: + su2double MaxDistance = 0.0, ErrorRate = 0.0; + unsigned long ErrorCounter = 0; + public: /*! * \brief Constructor of the class. @@ -40,7 +44,8 @@ class CIsoparametric final : public CInterpolator { * \param[in] iZone - index of the donor zone * \param[in] jZone - index of the target zone */ - CIsoparametric(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone); + CIsoparametric(CGeometry ****geometry_container, const CConfig* const* config, + unsigned int iZone, unsigned int jZone); /*! * \brief Set up transfer matrix defining relation between two meshes @@ -48,23 +53,37 @@ class CIsoparametric final : public CInterpolator { */ void Set_TransferCoeff(const CConfig* const* config) override; + /*! + * \brief Print information about the interpolation. + */ + void PrintStatistics(void) const override; + private: /*! - * \brief Calculate the isoparametric representation of point iVertex in marker iZone_0 by - * nodes of element donor_elem in marker jMarker of zone iZone_1. - * \param[in] iVertex - vertex index of the point being interpolated. - * \param[in] nDim - the dimension of the coordinates. - * \param[in] iZone_1 - zone index of the element to use for interpolation (the DONOR zone) - * \param[in] donor_elem - element index of the element to use for interpolation (or global index of a point in 2D) - * \param[in] nDonorPoints - number of donor points in the element. - * \param[in] xj - point projected onto the plane of the donor element. - * \param[out] isoparams - isoparametric coefficients. Must be allocated to size nNodes ahead of time. (size> nDonors) - * - * \note If the problem is 2D, the 'face' projected onto is actually an edge; the local index - * of the edge is then stored in iFace, and the global index of the node (from which the edge - * is referenced) + * \brief Compute the isoparametric interpolation coefficients for a 2D line element. + * \param[in] X - Coordinate matrix defining the line. + * \param[in] xj - Coordinates of the target point projected onto the plane of the element. + * \param[out] isoparams - Isoparametric coefficients. + * \return 0 on success, 1 if xj is outside element bounds. + */ + static int LineIsoparameters(const su2double X[][3], const su2double *xj, su2double* isoparams); + + /*! + * \brief Compute the isoparametric interpolation coefficients for a 3D triangle element. + * \param[in] X - Coordinate matrix defining the triangle. + * \param[in] xj - Coordinates of the target point projected onto the plane of the element. + * \param[out] isoparams - Isoparametric coefficients. + * \return 0 on success, 1 if xj is outside element bounds. + */ + static int TriangleIsoparameters(const su2double X[][3], const su2double *xj, su2double* isoparams); + + /*! + * \brief Compute the isoparametric interpolation coefficients for a 3D quadrilateral element. + * \param[in] X - Coordinate matrix defining the quadrilateral. + * \param[in] xj - Coordinates of the target point projected onto the plane of the element. + * \param[out] isoparams - Isoparametric coefficients. + * \return 0 on success, 1 if xj is outside element bounds. */ - void Isoparameters(unsigned short nDim, unsigned short nDonor, const su2double *X, - const su2double *xj, su2double* isoparams) const; + static int QuadrilateralIsoparameters(const su2double X[][3], const su2double *xj, su2double* isoparams); }; diff --git a/Common/include/toolboxes/geometry_toolbox.hpp b/Common/include/toolboxes/geometry_toolbox.hpp new file mode 100644 index 000000000000..7891ae89f1b4 --- /dev/null +++ b/Common/include/toolboxes/geometry_toolbox.hpp @@ -0,0 +1,116 @@ +/*! + * \file geometry_toolbox.hpp + * \brief Collection of common lightweight geometry-oriented methods. + * \version 7.0.3 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +namespace GeometryToolbox { + +/*! \return ||a-b||^2 */ +template +inline T SquaredDistance(Int nDim, const T* a, const T* b) { + T d(0); + for(Int i = 0; i < nDim; i++) d += pow(a[i]-b[i], 2); + return d; +} + +/*! \return ||a-b|| */ +template +inline T Distance(Int nDim, const T* a, const T* b) { + return sqrt(SquaredDistance(nDim, a, b)); +} + +/*! \brief d = a-b */ +template +inline void Distance(Int nDim, const T* a, const T* b, T* d) { + for(Int i = 0; i < nDim; i++) d[i] = a[i] - b[i]; +} + +/*! \return a.b */ +template +inline T DotProduct(Int nDim, const T* a, const T* b) { + T d(0); + for (Int i = 0; i < nDim; ++i) d += a[i]*b[i]; + return d; +} + +/*! \return ||a||^2 */ +template +inline T SquaredNorm(Int nDim, const T* a) { + return DotProduct(nDim, a, a); +} + +/*! \return ||a|| */ +template +inline T Norm(Int nDim, const T* a) { + return sqrt(SquaredNorm(nDim, a)); +} + +/*! \brief c = a x b */ +template +inline void CrossProduct(const T* a, const T* b, T* c) { + c[0] = a[1]*b[2] - a[2]*b[1]; + c[1] = a[2]*b[0] - a[0]*b[2]; + c[2] = a[0]*b[1] - a[1]*b[0]; +} + +/*! \brief Set U as the normal to a 2D line defined by coords[iPoint][iDim]. */ +template +inline void LineNormal(const T& coords, U* normal) { + normal[0] = coords[0][1] - coords[1][1]; + normal[1] = coords[1][0] - coords[0][0]; +} + +/*! \brief Normal vector of a triangle, cross product of two sides. */ +template +inline void TriangleNormal(const T& coords, U* normal) { + + U a[3], b[3]; + + for (int iDim = 0; iDim < 3; iDim++) { + a[iDim] = coords[1][iDim] - coords[0][iDim]; + b[iDim] = coords[2][iDim] - coords[0][iDim]; + } + + CrossProduct(a, b, normal); + normal[0] *= 0.5; normal[1] *= 0.5; normal[2] *= 0.5; +} + +/*! \brief Normal vector of a quadrilateral, cross product of the two diagonals. */ +template +inline void QuadrilateralNormal(const T& coords, U* normal) { + + U a[3], b[3]; + + for (int iDim = 0; iDim < 3; iDim++) { + a[iDim] = coords[2][iDim] - coords[0][iDim]; + b[iDim] = coords[3][iDim] - coords[1][iDim]; + } + + CrossProduct(a, b, normal); + normal[0] *= 0.5; normal[1] *= 0.5; normal[2] *= 0.5; +} + +} diff --git a/Common/src/geometry/elements/CQUAD4.cpp b/Common/src/geometry/elements/CQUAD4.cpp index a47051f36e0e..7661a2da251b 100644 --- a/Common/src/geometry/elements/CQUAD4.cpp +++ b/Common/src/geometry/elements/CQUAD4.cpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -41,25 +41,23 @@ CQUAD4::CQUAD4() : CElementWithKnownSizes() { /*--- Store the values of the shape functions and their derivatives ---*/ - unsigned short iNode, iGauss; - su2double Xi, Eta, val_Ni; + unsigned short iNode, iGauss, jGauss; + su2double Xi, Eta; for (iGauss = 0; iGauss < NGAUSS; iGauss++) { Xi = GaussCoord[iGauss][0]; Eta = GaussCoord[iGauss][1]; - val_Ni = 0.25*(1.0-Xi)*(1.0-Eta); GaussPoint[iGauss].SetNi(val_Ni,0); - val_Ni = 0.25*(1.0+Xi)*(1.0-Eta); GaussPoint[iGauss].SetNi(val_Ni,1); - val_Ni = 0.25*(1.0+Xi)*(1.0+Eta); GaussPoint[iGauss].SetNi(val_Ni,2); - val_Ni = 0.25*(1.0-Xi)*(1.0+Eta); GaussPoint[iGauss].SetNi(val_Ni,3); + su2double Ni[4] = {0.0}; + ShapeFunctions(Xi, Eta, Ni); + + for (jGauss = 0; jGauss < NGAUSS; jGauss++) + GaussPoint[iGauss].SetNi(Ni[jGauss], jGauss); /*--- dN/d xi, dN/d eta ---*/ - dNiXj[iGauss][0][0] = -0.25*(1.0-Eta); dNiXj[iGauss][0][1] = -0.25*(1.0-Xi); - dNiXj[iGauss][1][0] = 0.25*(1.0-Eta); dNiXj[iGauss][1][1] = -0.25*(1.0+Xi); - dNiXj[iGauss][2][0] = 0.25*(1.0+Eta); dNiXj[iGauss][2][1] = 0.25*(1.0+Xi); - dNiXj[iGauss][3][0] = -0.25*(1.0+Eta); dNiXj[iGauss][3][1] = 0.25*(1.0-Xi); + ShapeFunctionJacobian(Xi, Eta, dNiXj[iGauss]); } diff --git a/Common/src/interface_interpolation/CInterpolator.cpp b/Common/src/interface_interpolation/CInterpolator.cpp index cef2fa431b9b..d8e3f931350d 100644 --- a/Common/src/interface_interpolation/CInterpolator.cpp +++ b/Common/src/interface_interpolation/CInterpolator.cpp @@ -60,132 +60,110 @@ bool CInterpolator::CheckInterfaceBoundary(int markDonor, int markTarget) { return (donorCheck != -1) && (targetCheck != -1); } -void CInterpolator::Determine_ArraySize(bool faces, int markDonor, int markTarget, - unsigned long nVertexDonor, unsigned short nDim) { - - unsigned long nLocalVertex_Donor = 0, nLocalFaceNodes_Donor=0, nLocalFace_Donor=0; - unsigned long iVertex, iPointDonor = 0; - /* Only needed if face data is also collected */ - unsigned long inode; - unsigned long donor_elem, jElem, jPoint; - unsigned short iDonor; - unsigned int nFaces=0, iFace, nNodes=0; - bool face_on_marker = true; - - for (iVertex = 0; iVertex < nVertexDonor; iVertex++) { - iPointDonor = donor_geometry->vertex[markDonor][iVertex]->GetNode(); - - if (!donor_geometry->node[iPointDonor]->GetDomain()) continue; - - nLocalVertex_Donor++; - - if (!faces) continue; - - /*--- On Donor geometry also communicate face info ---*/ - if (nDim==3) { - for (jElem=0; jElemnode[iPointDonor]->GetnElem(); jElem++) { - donor_elem = donor_geometry->node[iPointDonor]->GetElem(jElem); - nFaces = donor_geometry->elem[donor_elem]->GetnFaces(); - for (iFace=0; iFaceelem[donor_elem]->GetnNodesFace(iFace); - for (iDonor=0; iDonorelem[donor_elem]->GetFaces(iFace, iDonor); - jPoint = donor_geometry->elem[donor_elem]->GetNode(inode); - face_on_marker = (face_on_marker && (donor_geometry->node[jPoint]->GetVertex(markDonor) !=-1)); - } - if (face_on_marker ) { - nLocalFace_Donor++; - nLocalFaceNodes_Donor+=nNodes; - } - } - } - } - else { - /*--- in 2D we use the edges ---*/ - nNodes=2; - nFaces = donor_geometry->node[iPointDonor]->GetnPoint(); - for (iFace=0; iFacenode[iPointDonor]->GetEdge(iFace); - jPoint = donor_geometry->edge[inode]->GetNode(iDonor); - face_on_marker = (face_on_marker && (donor_geometry->node[jPoint]->GetVertex(markDonor) !=-1)); - } - if (face_on_marker ) { - nLocalFace_Donor++; - nLocalFaceNodes_Donor+=nNodes; - } - } - } +void CInterpolator::Determine_ArraySize(int markDonor, int markTarget, + unsigned long nVertexDonor, unsigned short nDim) { + + /*--- Count donor vertices. ---*/ + auto nLocalVertex_Donor = 0ul; + for (auto iVertex = 0ul; iVertex < nVertexDonor; iVertex++) { + auto iPointDonor = donor_geometry->vertex[markDonor][iVertex]->GetNode(); + nLocalVertex_Donor += donor_geometry->node[iPointDonor]->GetDomain(); } Buffer_Send_nVertex_Donor[0] = nLocalVertex_Donor; - if (faces) { - Buffer_Send_nFace_Donor[0] = nLocalFace_Donor; - Buffer_Send_nFaceNodes_Donor[0] = nLocalFaceNodes_Donor; - } /*--- Send Interface vertex information --*/ SU2_MPI::Allreduce(&nLocalVertex_Donor, &MaxLocalVertex_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_nVertex_Donor, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - if (faces) { - SU2_MPI::Allreduce(&nLocalFace_Donor, &nGlobalFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalFace_Donor, &MaxFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &nGlobalFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&nLocalFaceNodes_Donor, &MaxFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFace_Donor, 1, MPI_UNSIGNED_LONG, - Buffer_Receive_nFace_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, - Buffer_Receive_nFaceNodes_Donor, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - MaxFace_Donor++; - } } -void CInterpolator::Collect_VertexInfo(bool faces, int markDonor, int markTarget, - unsigned long nVertexDonor, unsigned short nDim) { +void CInterpolator::Collect_VertexInfo(int markDonor, int markTarget, + unsigned long nVertexDonor, unsigned short nDim) { - unsigned long iVertex, iPointDonor = 0, iVertexDonor, nBuffer_Coord, nBuffer_Point, nLocalVertex_Donor; + unsigned long iVertex; unsigned short iDim; for (iVertex = 0; iVertex < MaxLocalVertex_Donor; iVertex++) Buffer_Send_GlobalPoint[iVertex] = -1; for (iVertex = 0; iVertex < MaxLocalVertex_Donor*nDim; iVertex++) Buffer_Send_Coord[iVertex] = 0.0; - if(faces) - for (iVertex = 0; iVertex < MaxLocalVertex_Donor*nDim; iVertex++) Buffer_Send_Normal[iVertex] = 0.0; - /*--- Copy coordinates and point to the auxiliar vector --*/ - nLocalVertex_Donor = 0; + auto iLocalVertexDonor = 0ul; - for (iVertexDonor = 0; iVertexDonor < nVertexDonor; iVertexDonor++) { - iPointDonor = donor_geometry->vertex[markDonor][iVertexDonor]->GetNode(); + for (iVertex = 0; iVertex < nVertexDonor; iVertex++) { + auto iPointDonor = donor_geometry->vertex[markDonor][iVertex]->GetNode(); if (donor_geometry->node[iPointDonor]->GetDomain()) { - Buffer_Send_GlobalPoint[nLocalVertex_Donor] = donor_geometry->node[iPointDonor]->GetGlobalIndex(); + Buffer_Send_GlobalPoint[iLocalVertexDonor] = donor_geometry->node[iPointDonor]->GetGlobalIndex(); for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[nLocalVertex_Donor*nDim+iDim] = donor_geometry->node[iPointDonor]->GetCoord(iDim); - - if (faces) { - const su2double* Normal = donor_geometry->vertex[markDonor][iVertexDonor]->GetNormal(); - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Normal[nLocalVertex_Donor*nDim+iDim] = Normal[iDim]; - } - nLocalVertex_Donor++; + Buffer_Send_Coord[iLocalVertexDonor*nDim+iDim] = donor_geometry->node[iPointDonor]->GetCoord(iDim); + iLocalVertexDonor++; } } - nBuffer_Coord = MaxLocalVertex_Donor*nDim; - nBuffer_Point = MaxLocalVertex_Donor; + auto nBuffer_Coord = MaxLocalVertex_Donor*nDim; + auto nBuffer_Point = MaxLocalVertex_Donor; SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_GlobalPoint, nBuffer_Point, MPI_LONG, Buffer_Receive_GlobalPoint, nBuffer_Point, MPI_LONG, MPI_COMM_WORLD); - if (faces) { - SU2_MPI::Allgather(Buffer_Send_Normal, nBuffer_Coord, MPI_DOUBLE, - Buffer_Receive_Normal, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); +} + +unsigned long CInterpolator::Collect_ElementInfo(int markDonor, unsigned short nDim, bool compress, + vector& allNumElem, vector& numNodes, + su2matrix& idxNodes) const { + + const auto maxElemNodes = (nDim == 2u)? 2u : 4u; // line and quad respectively + + unsigned long nElemDonor = 0; + if (markDonor != -1) nElemDonor = donor_geometry->GetnElem_Bound(markDonor); + + allNumElem.resize(size); + SU2_MPI::Allgather(&nElemDonor, 1, MPI_UNSIGNED_LONG, allNumElem.data(), 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + auto nMaxElemDonor = *max_element(allNumElem.begin(), allNumElem.end()); + + vector bufferSendNum(nMaxElemDonor); + su2matrix bufferSendIdx(nMaxElemDonor, maxElemNodes); + + numNodes.resize(nMaxElemDonor*size); + idxNodes.resize(nMaxElemDonor*size, maxElemNodes); + + for (auto iElem = 0ul; iElem < nElemDonor; ++iElem) { + + const auto nNode = donor_geometry->bound[markDonor][iElem]->GetnNodes(); + bufferSendNum[iElem] = nNode; + assert(nNode < maxElemNodes && "Donor element has too many nodes."); + + for (auto iNode = 0u; iNode < nNode; ++iNode) { + auto iPoint = donor_geometry->bound[markDonor][iElem]->GetNode(iNode); + auto iPointGlobal = donor_geometry->node[iPoint]->GetGlobalIndex(); + bufferSendIdx(iElem, iNode) = iPointGlobal; + } } + + SU2_MPI::Allgather(bufferSendNum.data(), bufferSendNum.size(), MPI_UNSIGNED_SHORT, + numNodes.data(), bufferSendNum.size(), MPI_UNSIGNED_SHORT, MPI_COMM_WORLD); + SU2_MPI::Allgather(bufferSendIdx.data(), bufferSendIdx.size(), MPI_LONG, + idxNodes.data(), bufferSendIdx.size(), MPI_LONG, MPI_COMM_WORLD); + + if (!compress) + return accumulate(allNumElem.begin(), allNumElem.end(), 0ul); + + /*--- Compress the information (overlapping copy do not use memcpy). ---*/ + + unsigned long dstIdx = 0; + for (int iProcessor = 0; iProcessor < size; ++iProcessor) { + auto srcOffset = iProcessor * nMaxElemDonor; + for (auto idx = 0u; idx < allNumElem[iProcessor]; ++idx) { + numNodes[dstIdx] = numNodes[srcOffset+idx]; + for (auto iNode = 0u; iNode < maxElemNodes; ++iNode) + idxNodes(dstIdx, iNode) = idxNodes(srcOffset+idx, iNode); + ++dstIdx; + } + } + + return dstIdx; } void CInterpolator::ReconstructBoundary(unsigned long val_zone, int val_marker){ diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp index e83a4902d17c..3312a39f878d 100644 --- a/Common/src/interface_interpolation/CIsoparametric.cpp +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -1,7 +1,7 @@ /*! * \file CIsoparametric.cpp * \brief Implementation isoparametric interpolation (using FE shape functions). - * \author H. Kline + * \author H. Kline, P. Gomes * \version 7.0.3 "Blackbird" * * SU2 Project Website: https://su2code.github.io @@ -28,6 +28,11 @@ #include "../../include/interface_interpolation/CIsoparametric.hpp" #include "../../include/CConfig.hpp" #include "../../include/geometry/CGeometry.hpp" +#include "../../include/geometry/elements/CElement.hpp" +#include "../../include/toolboxes/geometry_toolbox.hpp" +#include + +using namespace GeometryToolbox; CIsoparametric::CIsoparametric(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, @@ -35,520 +40,387 @@ CIsoparametric::CIsoparametric(CGeometry ****geometry_container, const CConfig* Set_TransferCoeff(config); } +void CIsoparametric::PrintStatistics(void) const { + if (rank != MASTER_NODE) return; + cout << " Maximum distance to closest donor element: " << MaxDistance << ".\n" + << " Interpolation mitigated on " << ErrorCounter << " (" << ErrorRate << "%) target vertices." << endl; +} + void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { - unsigned long iVertex, jVertex; - unsigned long dPoint, inode, jElem, nElem; - unsigned short iDim, iDonor=0, iFace; + /*--- Angle between target and donor below which we trigger fallback measures. ---*/ + const su2double thetaMin = 80.0/180.0*PI_NUMBER; - unsigned short nDim = donor_geometry->GetnDim(); + const int nProcessor = size; + const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; + const auto nDim = donor_geometry->GetnDim(); - unsigned short nMarkerInt; - unsigned short iMarkerInt; + Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; - int markDonor=0, markTarget=0; + /*--- Init stats. ---*/ + MaxDistance = 0.0; ErrorCounter = 0; + unsigned long nGlobalVertexTarget = 0; - long donor_elem=0, temp_donor=0; - unsigned int nNodes=0; - /*--- Restricted to 2-zone for now ---*/ - unsigned int nFaces=1; //For 2D cases, we want to look at edges, not faces, as the 'interface' - bool face_on_marker=true; + /*--- Cycle over nMarkersInt interface to determine communication pattern. ---*/ - unsigned long nVertexDonor = 0, nVertexTarget= 0; - unsigned long Point_Target = 0; + for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - unsigned long iVertexDonor, iPointDonor = 0; - int iProcessor; + /* High level procedure: + * - Loop through vertices of the target grid; + * - Find nearest element; + * - Compute and set the transfer coefficients. + */ - unsigned long nLocalFace_Donor = 0, nLocalFaceNodes_Donor=0; + /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ + const auto markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); - unsigned long faceindex; + /*--- On the target side: find the tag of the boundary sharing the interface. ---*/ + const auto markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); - su2double dist = 0.0, mindist=1E6, *Coord, *Coord_i; - su2double myCoeff[10]; // Maximum # of donor points - su2double *Normal; - su2double *projected_point = new su2double[nDim]; - su2double tmp, tmp2; - su2double storeCoeff[10]; - unsigned long storeGlobal[10]; - int storeProc[10]; + /*--- Checks if the zone contains the interface, if not continue to the next step. ---*/ + if (!CheckInterfaceBoundary(markDonor, markTarget)) continue; - int nProcessor = size; - Coord = new su2double[nDim]; - Normal = new su2double[nDim]; + unsigned long nVertexDonor = 0, nVertexTarget = 0; + if (markDonor != -1) nVertexDonor = donor_geometry->GetnVertex(markDonor); + if (markTarget != -1) nVertexTarget = target_geometry->GetnVertex(markTarget); - Buffer_Receive_nVertex_Donor = new unsigned long [nProcessor]; - Buffer_Receive_nFace_Donor = new unsigned long [nProcessor]; - Buffer_Receive_nFaceNodes_Donor = new unsigned long [nProcessor]; + /*--- Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor. ---*/ + Determine_ArraySize(markDonor, markTarget, nVertexDonor, nDim); - nMarkerInt = (config[donorZone]->GetMarker_n_ZoneInterface())/2; + const auto nGlobalVertexDonor = accumulate(Buffer_Receive_nVertex_Donor, + Buffer_Receive_nVertex_Donor+nProcessor, 0ul); - /*--- For the number of markers on the interface... ---*/ - for (iMarkerInt=1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - /*--- Procedure: - * -Loop through vertices of the aero grid - * -Find nearest element and allocate enough space in the aero grid donor point info - * -set the transfer coefficient values - */ + Buffer_Send_Coord = new su2double [ MaxLocalVertex_Donor * nDim ]; + Buffer_Send_GlobalPoint = new long [ MaxLocalVertex_Donor ]; + Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; + Buffer_Receive_GlobalPoint = new long [ nProcessor * MaxLocalVertex_Donor ]; - /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + /*--- Collect coordinates and global point indices. ---*/ + Collect_VertexInfo(markDonor, markTarget, nVertexDonor, nDim); - /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); + /*--- Compress the vertex information, and build a map of global point to "compressed + * index" to then reconstruct the donor elements in local index space. ---*/ - /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ - if(!CheckInterfaceBoundary(markDonor, markTarget)) continue; + su2activematrix donorCoord(nGlobalVertexDonor, nDim); + vector donorPoint(nGlobalVertexDonor); + vector donorProc(nGlobalVertexDonor); + unordered_map globalToLocalMap; - if(markDonor != -1) - nVertexDonor = donor_geometry->GetnVertex( markDonor ); - else - nVertexDonor = 0; + auto iCount = 0ul; + for (int iProcessor = 0; iProcessor < nProcessor; ++iProcessor) { + auto offset = iProcessor * MaxLocalVertex_Donor; + for (auto iVertex = 0ul; iVertex < Buffer_Receive_nVertex_Donor[iProcessor]; ++iVertex) { + for (int iDim = 0; iDim < nDim; ++iDim) + donorCoord(iCount,iDim) = Buffer_Receive_Coord[(offset+iVertex)*nDim + iDim]; + donorPoint[iCount] = Buffer_Receive_GlobalPoint[offset+iVertex]; + donorProc[iCount] = iProcessor; + assert((globalToLocalMap.count(donorPoint[iCount]) == 0) && "Duplicate donor point found."); + globalToLocalMap[donorPoint[iCount]] = iCount; + ++iCount; + } + } + assert((iCount == nGlobalVertexDonor) && "Global donor point count mismatch."); - if(markTarget != -1) - nVertexTarget = target_geometry->GetnVertex( markTarget ); - else - nVertexTarget = 0; + delete[] Buffer_Send_Coord; + delete[] Buffer_Send_GlobalPoint; + delete[] Buffer_Receive_Coord; + delete[] Buffer_Receive_GlobalPoint; - /* Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor */ - Determine_ArraySize(true, markDonor, markTarget, nVertexDonor, nDim); + /*--- Collect donor element (face) information. ---*/ - Buffer_Send_Coord = new su2double [MaxLocalVertex_Donor*nDim]; - Buffer_Send_Normal = new su2double [MaxLocalVertex_Donor*nDim]; - Buffer_Send_GlobalPoint = new long [MaxLocalVertex_Donor]; + vector allNumElem; + vector elemNumNodes; + su2matrix elemIdxNodes; - Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_Donor*nDim]; - Buffer_Receive_Normal = new su2double [nProcessor*MaxLocalVertex_Donor*nDim]; - Buffer_Receive_GlobalPoint = new long [nProcessor*MaxLocalVertex_Donor]; + auto nGlobalElemDonor = Collect_ElementInfo(markDonor, nDim, true, + allNumElem, elemNumNodes, elemIdxNodes); - /*-- Collect coordinates, global points, and normal vectors ---*/ - Collect_VertexInfo(true, markDonor,markTarget,nVertexDonor,nDim); + su2activematrix elemCentroid(nGlobalElemDonor, nDim); - Buffer_Send_FaceIndex = new unsigned long[MaxFace_Donor]; - Buffer_Send_FaceNodes = new unsigned long[MaxFaceNodes_Donor]; - Buffer_Send_FaceProc = new unsigned long[MaxFaceNodes_Donor]; + SU2_OMP_PARALLEL + { + /*--- Compute element centroids to then find the closest one to a given target point. ---*/ - Buffer_Receive_FaceIndex = new unsigned long[MaxFace_Donor*nProcessor]; - Buffer_Receive_FaceNodes = new unsigned long[MaxFaceNodes_Donor*nProcessor]; - Buffer_Receive_FaceProc = new unsigned long[MaxFaceNodes_Donor*nProcessor]; + SU2_OMP_FOR_STAT(roundUpDiv(nGlobalElemDonor,omp_get_max_threads())) + for (auto iElem = 0u; iElem < nGlobalElemDonor; ++iElem) { - nLocalFace_Donor=0; - nLocalFaceNodes_Donor=0; + const auto nNode = elemNumNodes[iElem]; - /*--- Collect Face info ---*/ + for (auto iDim = 0u; iDim < nDim; ++iDim) + elemCentroid(iElem, iDim) = 0.0; - for (iVertex = 0; iVertex < MaxFace_Donor; iVertex++) { - Buffer_Send_FaceIndex[iVertex] = 0; - } - for (iVertex=0; iVertexvertex[markDonor][iVertexDonor]->GetNode(); - - if (donor_geometry->node[iPointDonor]->GetDomain()) { - - if (nDim==3) nElem = donor_geometry->node[iPointDonor]->GetnElem(); - else nElem =donor_geometry->node[iPointDonor]->GetnPoint(); - - for (jElem=0; jElem < nElem; jElem++) { - if (nDim==3) { - temp_donor = donor_geometry->node[iPointDonor]->GetElem(jElem); - nFaces = donor_geometry->elem[temp_donor]->GetnFaces(); - for (iFace=0; iFaceelem[temp_donor]->GetnNodesFace(iFace); - for (iDonor=0; iDonorelem[temp_donor]->GetFaces(iFace, iDonor); - dPoint = donor_geometry->elem[temp_donor]->GetNode(inode); - face_on_marker = (face_on_marker && (donor_geometry->node[dPoint]->GetVertex(markDonor) !=-1)); - } - - if (face_on_marker ) { - for (iDonor=0; iDonorelem[temp_donor]->GetFaces(iFace, iDonor); - dPoint = donor_geometry->elem[temp_donor]->GetNode(inode); - // Match node on the face to the correct global index - long jGlobalPoint = donor_geometry->node[dPoint]->GetGlobalIndex(); - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (jVertex = 0; jVertex < Buffer_Receive_nVertex_Donor[iProcessor]; jVertex++) { - if (jGlobalPoint == Buffer_Receive_GlobalPoint[MaxLocalVertex_Donor*iProcessor+jVertex]) { - Buffer_Send_FaceNodes[nLocalFaceNodes_Donor]=MaxLocalVertex_Donor*iProcessor+jVertex; - Buffer_Send_FaceProc[nLocalFaceNodes_Donor]=iProcessor; - } - } - } - nLocalFaceNodes_Donor++; // Increment total number of face-nodes / processor - } - /* Store the indices */ - Buffer_Send_FaceIndex[nLocalFace_Donor+1] = Buffer_Send_FaceIndex[nLocalFace_Donor]+nNodes; - nLocalFace_Donor++; // Increment number of faces / processor - } + /*--- Compute transfer coefficients for each target point. ---*/ + su2double maxDist = 0.0; + unsigned long errorCount = 0, totalCount = 0; + + SU2_OMP_FOR_DYN(roundUpDiv(nVertexTarget,2*omp_get_max_threads())) + for (auto iVertex = 0u; iVertex < nVertexTarget; ++iVertex) { + + auto target_vertex = target_geometry->vertex[markTarget][iVertex]; + const auto iPoint = target_vertex->GetNode(); + + if (!target_geometry->node[iPoint]->GetDomain()) continue; + totalCount += 1; + + /*--- Coordinates and normal of the target point. ---*/ + const su2double* coord_i = target_geometry->node[iPoint]->GetCoord(); + const su2double* normal_i = target_vertex->GetNormal(); + + /*--- Find closest element (the naive way). ---*/ + su2double minDist = 1e20; + auto iElemDonor = 0u; + for (auto iElem = 0u; iElem < nGlobalElemDonor; ++iElem) { + su2double dist = SquaredDistance(nDim, coord_i, elemCentroid[iElem]); + if (dist < minDist) { + minDist = dist; + iElemDonor = iElem; } } - else { - /*-- Determine whether this face/edge is on the marker --*/ - face_on_marker=true; - for (iDonor=0; iDonornode[iPointDonor]->GetEdge(jElem); - dPoint = donor_geometry->edge[inode]->GetNode(iDonor); - face_on_marker = (face_on_marker && (donor_geometry->node[dPoint]->GetVertex(markDonor) !=-1)); - } - if (face_on_marker ) { - for (iDonor=0; iDonornode[iPointDonor]->GetEdge(jElem); - dPoint = donor_geometry->edge[inode]->GetNode(iDonor); - // Match node on the face to the correct global index - long jGlobalPoint = donor_geometry->node[dPoint]->GetGlobalIndex(); - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (jVertex = 0; jVertex < Buffer_Receive_nVertex_Donor[iProcessor]; jVertex++) { - if (jGlobalPoint == Buffer_Receive_GlobalPoint[MaxLocalVertex_Donor*iProcessor+jVertex]) { - Buffer_Send_FaceNodes[nLocalFaceNodes_Donor]=MaxLocalVertex_Donor*iProcessor+jVertex; - Buffer_Send_FaceProc[nLocalFaceNodes_Donor]=iProcessor; - } - } - } - nLocalFaceNodes_Donor++; // Increment total number of face-nodes / processor - } - /* Store the indices */ - Buffer_Send_FaceIndex[nLocalFace_Donor+1] = Buffer_Send_FaceIndex[nLocalFace_Donor]+nNodes; - nLocalFace_Donor++; // Increment number of faces / processor - } + + /*--- Fetch donor element info. ---*/ + int procList[4] = {0}; + long nodeList[4] = {0}; + su2double coords[4][3] = {{0.0}}; + + const auto nNode = elemNumNodes[iElemDonor]; + + for (auto iNode = 0u; iNode < nNode; ++iNode) { + const auto iVertex = elemIdxNodes(iElemDonor, iNode); + procList[iNode] = donorProc[iVertex]; + nodeList[iNode] = donorPoint[iVertex]; + for (auto iDim = 0u; iDim < nDim; ++iDim) + coords[iNode][iDim] = donorCoord(iVertex,iDim); } - } + + const su2double* coord_j = elemCentroid[iElemDonor]; + su2double normal_j[3] = {0.0}; + + switch (nNode) { + case 2: LineNormal(coords, normal_j); break; + case 3: TriangleNormal(coords, normal_j); break; + case 4: QuadrilateralNormal(coords, normal_j); break; } - } - //Buffer_Send_FaceIndex[nLocalFace_Donor+1] = MaxFaceNodes_Donor*rank+nLocalFaceNodes_Donor; - - SU2_MPI::Allgather(Buffer_Send_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, - Buffer_Receive_FaceNodes, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_FaceProc, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, - Buffer_Receive_FaceProc, MaxFaceNodes_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, - Buffer_Receive_FaceIndex, MaxFace_Donor, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - /*--- Loop over the vertices on the target Marker ---*/ - for (iVertex = 0; iVertexvertex[markTarget][iVertex]->GetNode(); - - if (!target_geometry->node[Point_Target]->GetDomain()) continue; - - Coord_i = target_geometry->node[Point_Target]->GetCoord(); - /*---Loop over the faces previously communicated/stored ---*/ - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - - nFaces = (unsigned int)Buffer_Receive_nFace_Donor[iProcessor]; - - for (iFace = 0; iFace< nFaces; iFace++) { - /*--- ---*/ - - nNodes = (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace+1] - - (unsigned int)Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; - - su2double *X = new su2double[nNodes*(nDim+1)]; - faceindex = Buffer_Receive_FaceIndex[iProcessor*MaxFace_Donor+iFace]; // first index of this face - for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetDonorElem(donor_elem); // in 2D is nearest neighbor - for (iDonor=0; iDonor= thetaMin) { + su2double dist_ij[3] = {0.0}; + Distance(nDim, coord_j, coord_i, dist_ij); + proj = DotProduct(nDim, dist_ij, normal_j) / proj; + for (auto iDim = 0u; iDim < nDim; ++iDim) + projCoord[iDim] = coord_i[iDim] + proj*dist_ij[iDim]; + + maxDist = max(maxDist, proj*Norm(nDim, dist_ij)); } + else { + /*--- Target and donor are too out of alignement, as fallback + * use the element centroid as the projected coordinate. ---*/ + for (auto iDim = 0u; iDim < nDim; ++iDim) + projCoord[iDim] = coord_j[iDim]; - /*--- Set the appropriate amount of memory and fill ---*/ - target_geometry->vertex[markTarget][iVertex]->Allocate_DonorInfo(nNodes); + errorCount += 1; + maxDist = max(maxDist, sqrt(minDist)); + } - for (iDonor=0; iDonorvertex[markTarget][iVertex]->SetInterpDonorPoint(iDonor,storeGlobal[iDonor]); - target_geometry->vertex[markTarget][iVertex]->SetDonorCoeff(iDonor,storeCoeff[iDonor]); - target_geometry->vertex[markTarget][iVertex]->SetInterpDonorProcessor(iDonor, storeProc[iDonor]); + /*--- Compute and set interpolation coefficients. ---*/ + + su2double isoparams[4] = {0.0}; + switch (nNode) { + case 2: errorCount += LineIsoparameters(coords, projCoord, isoparams); break; + case 3: errorCount += TriangleIsoparameters(coords, projCoord, isoparams); break; + case 4: errorCount += QuadrilateralIsoparameters(coords, projCoord, isoparams); break; } + target_vertex->Allocate_DonorInfo(nNode); + + for (auto iDonor = 0u; iDonor < nNode; ++iDonor) { + target_vertex->SetDonorCoeff(iDonor, isoparams[iDonor]); + target_vertex->SetInterpDonorPoint(iDonor, nodeList[iDonor]); + target_vertex->SetInterpDonorProcessor(iDonor, procList[iDonor]); + } + + } + SU2_OMP_CRITICAL + { + MaxDistance = max(MaxDistance,maxDist); + ErrorCounter += errorCount; + nGlobalVertexTarget += totalCount; } + } // end SU2_OMP_PARALLEL - delete[] Buffer_Send_Coord; - delete[] Buffer_Send_Normal; - delete[] Buffer_Send_GlobalPoint; + } // end nMarkerInt loop - delete[] Buffer_Receive_Coord; - delete[] Buffer_Receive_Normal; - delete[] Buffer_Receive_GlobalPoint; + /*--- Final reduction of statistics. ---*/ + su2double tmp = MaxDistance; + unsigned long tmp1 = ErrorCounter, tmp2 = nGlobalVertexTarget; + SU2_MPI::Allreduce(&tmp, &MaxDistance, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&tmp1, &ErrorCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&tmp2, &nGlobalVertexTarget, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - delete[] Buffer_Send_FaceIndex; - delete[] Buffer_Send_FaceNodes; - delete[] Buffer_Send_FaceProc; + ErrorRate = 100*su2double(ErrorCounter) / nGlobalVertexTarget; - delete[] Buffer_Receive_FaceIndex; - delete[] Buffer_Receive_FaceNodes; - delete[] Buffer_Receive_FaceProc; +} + +int CIsoparametric::LineIsoparameters(const su2double X[][3], const su2double *xj, su2double *isoparams) { + + su2double l01 = Distance(2, X[0], X[1]); + su2double l0j = Distance(2, X[0], xj); + su2double lj1 = Distance(2, xj, X[1]); + + /*--- Detect out of bounds point. ---*/ + + const int outOfBounds = (l0j+lj1) > l01; + + if (outOfBounds) { + l0j = (l0j > lj1)? l01 : 0.0; // which ever is closest becomes the donor + lj1 = l01 - l0j; } - delete[] Buffer_Receive_nVertex_Donor; - delete[] Buffer_Receive_nFace_Donor; - delete[] Buffer_Receive_nFaceNodes_Donor; + isoparams[0] = lj1 / l01; + isoparams[1] = 1.0 - isoparams[0]; - delete [] Coord; - delete [] Normal; + return outOfBounds; +} + +int CIsoparametric::TriangleIsoparameters(const su2double X[][3], const su2double *xj, su2double *isoparams) { + + /*--- The isoparameters are the solution to the determined system X^T * isoparams = xj. + * This is consistent with the shape functions of the linear triangular element. ---*/ + + su2double A[3][3] = {{0.0}}; // = X^T + + for (int i = 0; i < 3; ++i) { + isoparams[i] = xj[i]; // use isoparams as rhs + for (int j = 0; j < 3; ++j) + A[i][j] = X[j][i]; + } - delete [] projected_point; + /*--- Solve normal system by in-place Gaussian elimination without pivoting. ---*/ + + /*--- Transform system in Upper Matrix. ---*/ + for (int i = 1; i < 3; ++i) { + for (int j = 0; j < i; ++j) { + su2double w = A[i][j] / A[j][j]; + for (int k = j; k < 3; ++k) + A[i][k] -= w * A[j][k]; + isoparams[i] -= w * isoparams[j]; + } + } + + /*--- Backwards substitution. ---*/ + for (int i = 2; i >= 0; --i) { + for (int j = i+1; j < 3; ++j) + isoparams[i] -= A[i][j] * isoparams[j]; + isoparams[i] /= A[i][i]; + } + + /*--- Detect out of bounds point. ---*/ + const int outOfBounds = (isoparams[0] < 0.0) || (isoparams[1] < 0.0) || (isoparams[2] < 0.0); + + /*--- Simple mitigation. ---*/ + if (outOfBounds) + isoparams[0] = isoparams[1] = isoparams[2] = 1.0/3.0; + + return outOfBounds; } -void CIsoparametric::Isoparameters(unsigned short nDim, unsigned short nDonor, - const su2double *X, const su2double *xj, su2double *isoparams) const { +int CIsoparametric::QuadrilateralIsoparameters(const su2double X[][3], const su2double *xj, su2double *isoparams) { - short iDonor,iDim,k; // indices - su2double tmp, tmp2; + /*--- The isoparameters are the shape functions (Ni) evaluated at xj, for that we need + * the corresponding Xi and Eta, which are obtained by solving the overdetermined + * nonlinear system xj - X^T * Ni(Xi,Eta) = 0 via the Gauss-Newton method. ---*/ - su2double *x = new su2double[nDim+1]; - su2double *x_tmp = new su2double[nDim+1]; - su2double *Q = new su2double[nDonor*nDonor]; - su2double *R = new su2double[nDonor*nDonor]; - su2double *A = new su2double[(nDim+2)*nDonor]; - su2double *A2 = NULL; - su2double *x2 = new su2double[nDim+1]; + constexpr int NITER = 10; + const su2double tol = 1e-12; - bool *test = new bool[nDim+1]; - bool *testi = new bool[nDim+1]; + su2double Xi = 0.0, Eta = 0.0, eps; - su2double eps = 1E-10; + /*--- Finding Xi and Eta is a "third order" effect that we do not + * differentiate (also because we need to iterate). ---*/ + const bool tapeActive = AD::TapeActive(); + AD::StopRecording(); - short n = nDim+1; + for (int iter = 0; iter < NITER; ++iter) { - if (nDonor>2) { - /*--- Create Matrix A: 1st row all 1's, 2nd row x coordinates, 3rd row y coordinates, etc ---*/ - /*--- Right hand side is [1, \vec{x}']'---*/ - for (iDonor=0; iDonoreps && iDonor=0; iDonor--) { - if (R[iDonor*nDonor+iDonor]>eps) - isoparams[iDonor]=x_tmp[iDonor]/R[iDonor*nDonor+iDonor]; - else - isoparams[iDonor]=0; - for (k=0; k1.0) xi=1.0; - if (xi<-1.0) xi=-1.0; - if (eta>1.0) eta=1.0; - if (eta<-1.0) eta=-1.0; - isoparams[0]=0.25*(1-xi)*(1-eta); - isoparams[1]=0.25*(1+xi)*(1-eta); - isoparams[2]=0.25*(1+xi)*(1+eta); - isoparams[3]=0.25*(1-xi)*(1+eta); + if (tapeActive) AD::StartRecording(); + + int outOfBounds = 0; + if (eps > 0.01) { + /*--- Iteration did not converge. ---*/ + Xi = Eta = 0.0; + outOfBounds = 1; } - if (nDonor<4) { - tmp = 0.0; // value for normalization - tmp2=0; // check for maximum value, to be used to id nearest neighbor if necessary - k=0; // index for maximum value - for (iDonor=0; iDonor< nDonor; iDonor++) { - if (isoparams[iDonor]>tmp2) { - k=iDonor; - tmp2=isoparams[iDonor]; - } - // [0,1] - if (isoparams[iDonor]<0) isoparams[iDonor]=0; - if (isoparams[iDonor]>1) isoparams[iDonor] = 1; - tmp +=isoparams[iDonor]; - } - if (tmp>0) - for (iDonor=0; iDonor< nDonor; iDonor++) - isoparams[iDonor]=isoparams[iDonor]/tmp; - else { - isoparams[k] = 1.0; + else { + /*--- Check bounds. ---*/ + outOfBounds = (fabs(Xi) > 1.0) || (fabs(Eta) > 1.0); + + /*--- Mitigate by clamping coordinates. ---*/ + if (outOfBounds) { + Xi = max(-1.0, min(Xi, 1.0)); + Eta = max(-1.0, min(Eta, 1.0)); } } - delete [] x; - delete [] x_tmp; - delete [] Q; - delete [] R; - delete [] A; - delete [] A2; - delete [] x2; - - delete [] test; - delete [] testi; + /*--- Evaluate isoparameters. ---*/ + CQUAD4::ShapeFunctions(Xi, Eta, isoparams); + return outOfBounds; } diff --git a/Common/src/interface_interpolation/CNearestNeighbor.cpp b/Common/src/interface_interpolation/CNearestNeighbor.cpp index b94457b16c62..580dcb7e460b 100644 --- a/Common/src/interface_interpolation/CNearestNeighbor.cpp +++ b/Common/src/interface_interpolation/CNearestNeighbor.cpp @@ -28,6 +28,7 @@ #include "../../include/interface_interpolation/CNearestNeighbor.hpp" #include "../../include/CConfig.hpp" #include "../../include/geometry/CGeometry.hpp" +#include "../../include/toolboxes/geometry_toolbox.hpp" /*! \brief Helper struct to (partially) sort neighbours according to distance while @@ -87,11 +88,11 @@ void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { if (!CheckInterfaceBoundary(markDonor, markTarget)) continue; unsigned long nVertexDonor = 0, nVertexTarget = 0; - if(markDonor != -1) nVertexDonor = donor_geometry->GetnVertex( markDonor ); - if(markTarget != -1) nVertexTarget = target_geometry->GetnVertex( markTarget ); + if (markDonor != -1) nVertexDonor = donor_geometry->GetnVertex(markDonor); + if (markTarget != -1) nVertexTarget = target_geometry->GetnVertex(markTarget); - /* Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor. */ - Determine_ArraySize(false, markDonor, markTarget, nVertexDonor, nDim); + /*--- Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor. ---*/ + Determine_ArraySize(markDonor, markTarget, nVertexDonor, nDim); const auto nPossibleDonor = accumulate(Buffer_Receive_nVertex_Donor, Buffer_Receive_nVertex_Donor+nProcessor, 0ul); @@ -101,8 +102,8 @@ void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; Buffer_Receive_GlobalPoint = new long [ nProcessor * MaxLocalVertex_Donor ]; - /*-- Collect coordinates and global point indices. ---*/ - Collect_VertexInfo( false, markDonor, markTarget, nVertexDonor, nDim ); + /*--- Collect coordinates and global point indices. ---*/ + Collect_VertexInfo(markDonor, markTarget, nVertexDonor, nDim); /*--- Find the closest donor points to each target. ---*/ SU2_OMP_PARALLEL @@ -132,7 +133,7 @@ void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { const auto idx = iProcessor*MaxLocalVertex_Donor + jVertex; const auto pGlobalPoint = Buffer_Receive_GlobalPoint[idx]; const su2double* Coord_j = &Buffer_Receive_Coord[idx*nDim]; - const auto dist2 = PointsSquareDistance(nDim, Coord_i, Coord_j); + const auto dist2 = GeometryToolbox::SquaredDistance(nDim, Coord_i, Coord_j); donorInfo[iDonor++] = DonorInfo(dist2, pGlobalPoint, iProcessor); } diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp index 1ab414476f9a..4eb5d574be45 100644 --- a/Common/src/interface_interpolation/CRadialBasisFunction.cpp +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -29,6 +29,7 @@ #include "../../include/CConfig.hpp" #include "../../include/geometry/CGeometry.hpp" #include "../../include/toolboxes/CSymmetricMatrix.hpp" +#include "../../include/toolboxes/geometry_toolbox.hpp" #if defined(HAVE_MKL) #include "mkl.h" @@ -126,13 +127,13 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { const auto markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); /*--- If the zone does not contain the interface continue to the next pair of markers. ---*/ - if(!CheckInterfaceBoundary(markDonor,markTarget)) continue; + if (!CheckInterfaceBoundary(markDonor,markTarget)) continue; unsigned long nVertexDonor = 0; - if(markDonor != -1) nVertexDonor = donor_geometry->GetnVertex(markDonor); + if (markDonor != -1) nVertexDonor = donor_geometry->GetnVertex(markDonor); /*--- Sets MaxLocalVertex_Donor, Buffer_Receive_nVertex_Donor. ---*/ - Determine_ArraySize(false, markDonor, markTarget, nVertexDonor, nDim); + Determine_ArraySize(markDonor, markTarget, nVertexDonor, nDim); /*--- Compute total number of donor vertices. ---*/ const auto nGlobalVertexDonor = accumulate(Buffer_Receive_nVertex_Donor, @@ -144,7 +145,7 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { Buffer_Receive_Coord = new su2double [ nProcessor * MaxLocalVertex_Donor * nDim ]; Buffer_Receive_GlobalPoint = new long [ nProcessor * MaxLocalVertex_Donor ]; - Collect_VertexInfo(false, markDonor, markTarget, nVertexDonor, nDim); + Collect_VertexInfo(markDonor, markTarget, nVertexDonor, nDim); /*--- Compresses the gathered donor point information to simplify computations. ---*/ auto& donorCoord = donorCoordinates[iMarkerInt]; @@ -331,7 +332,7 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { /*--- RBF terms: ---*/ for (auto iVertexDonor = 0ul; iVertexDonor < nGlobalVertexDonor; ++iVertexDonor) { for (auto k = 0ul; k < slabSize; ++k) { - auto dist = PointsDistance(nDim, targetCoord[iVertexTarget+k], donorCoord[iVertexDonor]); + auto dist = GeometryToolbox::Distance(nDim, targetCoord[iVertexTarget+k], donorCoord[iVertexDonor]); auto rbf = Get_RadialBasisValue(kindRBF, paramRBF, dist); funcMat(k, 1+nPolynomial+iVertexDonor) = SU2_TYPE::GetValue(rbf); } @@ -449,7 +450,7 @@ void CRadialBasisFunction::ComputeGeneratorMatrix(ENUM_RADIALBASIS type, bool us for (int iVertex = 0; iVertex < nVertexDonor; ++iVertex) for (int jVertex = iVertex; jVertex < nVertexDonor; ++jVertex) global_M(iVertex, jVertex) = SU2_TYPE::GetValue(Get_RadialBasisValue(type, radius, - PointsDistance(nDim, coords[iVertex], coords[jVertex]))); + GeometryToolbox::Distance(nDim, coords[iVertex], coords[jVertex]))); /*--- Invert M matrix (operation is in-place). ---*/ const bool kernelIsSPD = (type==WENDLAND_C2) || (type==GAUSSIAN) || (type==INV_MULTI_QUADRIC); diff --git a/Common/src/interface_interpolation/CSlidingMesh.cpp b/Common/src/interface_interpolation/CSlidingMesh.cpp index b4791cff96b7..a79b96dbd593 100644 --- a/Common/src/interface_interpolation/CSlidingMesh.cpp +++ b/Common/src/interface_interpolation/CSlidingMesh.cpp @@ -28,6 +28,7 @@ #include "../../include/interface_interpolation/CSlidingMesh.hpp" #include "../../include/CConfig.hpp" #include "../../include/geometry/CGeometry.hpp" +#include "../../include/toolboxes/geometry_toolbox.hpp" CSlidingMesh::CSlidingMesh(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, @@ -203,7 +204,7 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; - dist = PointsDistance(nDim, Coord_i, Coord_j); + dist = GeometryToolbox::Distance(nDim, Coord_i, Coord_j); if (dist < mindist) { mindist = dist; @@ -250,7 +251,7 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { for(iDim = 0; iDim < nDim; iDim++) Direction[iDim] /= dTMP; - length = PointsDistance(nDim, target_iMidEdge_point, target_jMidEdge_point); + length = GeometryToolbox::Distance(nDim, target_iMidEdge_point, target_jMidEdge_point); check = false; @@ -487,7 +488,7 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { Coord_j = &DonorPoint_Coord[ donor_iPoint * nDim ]; - dist = PointsDistance(nDim, Coord_i, Coord_j); + dist = GeometryToolbox::Distance(nDim, Coord_i, Coord_j); if (dist < mindist) { mindist = dist; diff --git a/SU2_CFD/src/solvers/CFEASolver.cpp b/SU2_CFD/src/solvers/CFEASolver.cpp index e68759d4e69c..e95c1e4697ab 100644 --- a/SU2_CFD/src/solvers/CFEASolver.cpp +++ b/SU2_CFD/src/solvers/CFEASolver.cpp @@ -28,57 +28,13 @@ #include "../../include/solvers/CFEASolver.hpp" #include "../../include/variables/CFEABoundVariable.hpp" #include "../../../Common/include/toolboxes/printing_toolbox.hpp" +#include "../../../Common/include/toolboxes/geometry_toolbox.hpp" #include #include #include -/*! - * \brief Anonymous namespace with helper functions of the FEA solver. - */ -namespace { - - template - void CrossProduct(const T* a, const T* b, T* c) { - c[0] = a[1]*b[2] - a[2]*b[1]; - c[1] = a[2]*b[0] - a[0]*b[2]; - c[2] = a[0]*b[1] - a[1]*b[0]; - } - - template - void LineNormal(const T& coords, U* normal) { - normal[0] = coords[0][1] - coords[1][1]; - normal[1] = coords[1][0] - coords[0][0]; - } - - template - void TriangleNormal(const T& coords, U* normal) { - /*--- Cross product of two sides. ---*/ - U a[3], b[3]; - - for (int iDim = 0; iDim < 3; iDim++) { - a[iDim] = coords[1][iDim] - coords[0][iDim]; - b[iDim] = coords[2][iDim] - coords[0][iDim]; - } +using namespace GeometryToolbox; - CrossProduct(a, b, normal); - normal[0] *= 0.5; normal[1] *= 0.5; normal[2] *= 0.5; - } - - template - void QuadrilateralNormal(const T& coords, U* normal) { - /*--- Cross product of the two diagonals. ---*/ - U a[3], b[3]; - - for (int iDim = 0; iDim < 3; iDim++) { - a[iDim] = coords[2][iDim] - coords[0][iDim]; - b[iDim] = coords[3][iDim] - coords[1][iDim]; - } - - CrossProduct(a, b, normal); - normal[0] *= 0.5; normal[1] *= 0.5; normal[2] *= 0.5; - } - -} CFEASolver::CFEASolver(bool mesh_deform_mode) : CSolver(mesh_deform_mode) { From 8fc82a5b6f83928c2325d19a613bca363afd2d2a Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 2 Apr 2020 17:46:26 +0100 Subject: [PATCH 58/79] small fixes --- Common/include/geometry/dual_grid/CVertex.hpp | 5 +++ .../interface_interpolation/CInterpolator.hpp | 6 +-- .../CIsoparametric.hpp | 2 +- .../interface_interpolation/CInterpolator.cpp | 2 +- .../CIsoparametric.cpp | 40 ++++++++++++------- 5 files changed, 34 insertions(+), 21 deletions(-) diff --git a/Common/include/geometry/dual_grid/CVertex.hpp b/Common/include/geometry/dual_grid/CVertex.hpp index 41c2fc4da20d..a63f5a51be52 100644 --- a/Common/include/geometry/dual_grid/CVertex.hpp +++ b/Common/include/geometry/dual_grid/CVertex.hpp @@ -110,6 +110,11 @@ class CVertex : public CDualGrid { */ inline su2double *GetNormal(void) override { return Normal; } + /*! + * \brief Get the ith component of the normal. + */ + inline su2double GetNormal(unsigned short iDim) const { return Normal[iDim]; } + /*! * \brief Initialize normal vector. */ diff --git a/Common/include/interface_interpolation/CInterpolator.hpp b/Common/include/interface_interpolation/CInterpolator.hpp index de0754b94d0d..3d7a0b3f9f19 100644 --- a/Common/include/interface_interpolation/CInterpolator.hpp +++ b/Common/include/interface_interpolation/CInterpolator.hpp @@ -38,7 +38,7 @@ using namespace std; /*! * \class CInterpolator * \brief Main class for defining the interpolator, it requires - * a child class for each particular interpolation method + * a child class for each particular interpolation method. * \author H. Kline */ class CInterpolator { @@ -65,9 +65,7 @@ class CInterpolator { *Buffer_Send_FaceIndex, /*!< \brief Buffer to send indices pointing to the node indices that define the faces*/ *Buffer_Receive_FaceIndex, /*!< \brief Buffer to receive indices pointing to the node indices that define the faces*/ *Buffer_Send_FaceNodes, /*!< \brief Buffer to send indices pointing to the location of node information in other buffers, defining faces*/ - *Buffer_Receive_FaceNodes, /*!< \brief Buffer to receive indices pointing to the location of node information in other buffers, defining faces*/ - *Buffer_Send_FaceProc, /*!< \brief Buffer to send processor which stores the node indicated in Buffer_Receive_FaceNodes*/ - *Buffer_Receive_FaceProc; /*!< \brief Buffer to receive processor which stores the node indicated in Buffer_Receive_FaceNodes*/ + *Buffer_Receive_FaceNodes; /*!< \brief Buffer to receive indices pointing to the location of node information in other buffers, defining faces*/ long *Buffer_Send_GlobalPoint, /*!< \brief Buffer to send global point indices*/ *Buffer_Receive_GlobalPoint; /*!< \brief Buffer to receive global point indices*/ diff --git a/Common/include/interface_interpolation/CIsoparametric.hpp b/Common/include/interface_interpolation/CIsoparametric.hpp index 2990026e40d3..d55c98a68b81 100644 --- a/Common/include/interface_interpolation/CIsoparametric.hpp +++ b/Common/include/interface_interpolation/CIsoparametric.hpp @@ -1,7 +1,7 @@ /*! * \file CIsoparametric.hpp * \brief Isoparametric interpolation using FE shape functions. - * \author H. Kline, P. Gomes + * \author P. Gomes * \version 7.0.3 "Blackbird" * * SU2 Project Website: https://su2code.github.io diff --git a/Common/src/interface_interpolation/CInterpolator.cpp b/Common/src/interface_interpolation/CInterpolator.cpp index d8e3f931350d..5386304e94a7 100644 --- a/Common/src/interface_interpolation/CInterpolator.cpp +++ b/Common/src/interface_interpolation/CInterpolator.cpp @@ -133,7 +133,7 @@ unsigned long CInterpolator::Collect_ElementInfo(int markDonor, unsigned short n const auto nNode = donor_geometry->bound[markDonor][iElem]->GetnNodes(); bufferSendNum[iElem] = nNode; - assert(nNode < maxElemNodes && "Donor element has too many nodes."); + assert(nNode <= maxElemNodes && "Donor element has too many nodes."); for (auto iNode = 0u; iNode < nNode; ++iNode) { auto iPoint = donor_geometry->bound[markDonor][iElem]->GetNode(iNode); diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp index 3312a39f878d..c41c92c2c463 100644 --- a/Common/src/interface_interpolation/CIsoparametric.cpp +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -1,7 +1,7 @@ /*! * \file CIsoparametric.cpp * \brief Implementation isoparametric interpolation (using FE shape functions). - * \author H. Kline, P. Gomes + * \author P. Gomes * \version 7.0.3 "Blackbird" * * SU2 Project Website: https://su2code.github.io @@ -48,8 +48,8 @@ void CIsoparametric::PrintStatistics(void) const { void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { - /*--- Angle between target and donor below which we trigger fallback measures. ---*/ - const su2double thetaMin = 80.0/180.0*PI_NUMBER; + /*--- Angle between target and donor above which we trigger fallback measures. ---*/ + const su2double thetaMax = 20.0/180.0*PI_NUMBER; const int nProcessor = size; const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; @@ -174,9 +174,12 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { if (!target_geometry->node[iPoint]->GetDomain()) continue; totalCount += 1; - /*--- Coordinates and normal of the target point. ---*/ + /*--- Coordinates and unit normal of the target point. ---*/ const su2double* coord_i = target_geometry->node[iPoint]->GetCoord(); - const su2double* normal_i = target_vertex->GetNormal(); + const su2double area_i = Norm(nDim, target_vertex->GetNormal()); + su2double unitNormal_i[3] = {0.0}; + for (auto iDim = 0u; iDim < nDim; ++iDim) + unitNormal_i[iDim] = target_vertex->GetNormal(iDim) / area_i; /*--- Find closest element (the naive way). ---*/ su2double minDist = 1e20; @@ -215,19 +218,19 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { /*--- Project the target onto the donor plane, as grids may not be exactly conformal. * For quadrilaterals this is approximate as the element may be warped. ---*/ - su2double proj = DotProduct(nDim, normal_i, normal_j); - su2double theta = acos(fabs(proj) / (Norm(nDim, normal_i)*Norm(nDim, normal_j))); + su2double proj = DotProduct(nDim, unitNormal_i, normal_j); + su2double theta = acos(fabs(proj) / Norm(nDim, normal_j)); su2double projCoord[3] = {0.0}; - if (theta >= thetaMin) { + if (theta < thetaMax) { su2double dist_ij[3] = {0.0}; Distance(nDim, coord_j, coord_i, dist_ij); proj = DotProduct(nDim, dist_ij, normal_j) / proj; for (auto iDim = 0u; iDim < nDim; ++iDim) - projCoord[iDim] = coord_i[iDim] + proj*dist_ij[iDim]; + projCoord[iDim] = coord_i[iDim] + proj*unitNormal_i[iDim]; - maxDist = max(maxDist, proj*Norm(nDim, dist_ij)); + maxDist = max(maxDist, fabs(proj)); } else { /*--- Target and donor are too out of alignement, as fallback @@ -280,13 +283,15 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { int CIsoparametric::LineIsoparameters(const su2double X[][3], const su2double *xj, su2double *isoparams) { + const su2double extrapTol = 1.01; + su2double l01 = Distance(2, X[0], X[1]); su2double l0j = Distance(2, X[0], xj); su2double lj1 = Distance(2, xj, X[1]); /*--- Detect out of bounds point. ---*/ - const int outOfBounds = (l0j+lj1) > l01; + const int outOfBounds = (l0j+lj1) > (extrapTol*l01); if (outOfBounds) { l0j = (l0j > lj1)? l01 : 0.0; // which ever is closest becomes the donor @@ -304,6 +309,8 @@ int CIsoparametric::TriangleIsoparameters(const su2double X[][3], const su2doubl /*--- The isoparameters are the solution to the determined system X^T * isoparams = xj. * This is consistent with the shape functions of the linear triangular element. ---*/ + const su2double extrapTol = -0.01; + su2double A[3][3] = {{0.0}}; // = X^T for (int i = 0; i < 3; ++i) { @@ -312,7 +319,7 @@ int CIsoparametric::TriangleIsoparameters(const su2double X[][3], const su2doubl A[i][j] = X[j][i]; } - /*--- Solve normal system by in-place Gaussian elimination without pivoting. ---*/ + /*--- Solve system by in-place Gaussian elimination without pivoting. ---*/ /*--- Transform system in Upper Matrix. ---*/ for (int i = 1; i < 3; ++i) { @@ -323,7 +330,6 @@ int CIsoparametric::TriangleIsoparameters(const su2double X[][3], const su2doubl isoparams[i] -= w * isoparams[j]; } } - /*--- Backwards substitution. ---*/ for (int i = 2; i >= 0; --i) { for (int j = i+1; j < 3; ++j) @@ -332,7 +338,9 @@ int CIsoparametric::TriangleIsoparameters(const su2double X[][3], const su2doubl } /*--- Detect out of bounds point. ---*/ - const int outOfBounds = (isoparams[0] < 0.0) || (isoparams[1] < 0.0) || (isoparams[2] < 0.0); + const int outOfBounds = (isoparams[0] < extrapTol) || + (isoparams[1] < extrapTol) || + (isoparams[2] < extrapTol); /*--- Simple mitigation. ---*/ if (outOfBounds) @@ -347,6 +355,8 @@ int CIsoparametric::QuadrilateralIsoparameters(const su2double X[][3], const su2 * the corresponding Xi and Eta, which are obtained by solving the overdetermined * nonlinear system xj - X^T * Ni(Xi,Eta) = 0 via the Gauss-Newton method. ---*/ + const su2double extrapTol = 1.01; + constexpr int NITER = 10; const su2double tol = 1e-12; @@ -410,7 +420,7 @@ int CIsoparametric::QuadrilateralIsoparameters(const su2double X[][3], const su2 } else { /*--- Check bounds. ---*/ - outOfBounds = (fabs(Xi) > 1.0) || (fabs(Eta) > 1.0); + outOfBounds = (fabs(Xi) > extrapTol) || (fabs(Eta) > extrapTol); /*--- Mitigate by clamping coordinates. ---*/ if (outOfBounds) { From 66cef8928cdc29ca2cd982d31cb83fbf29e4c839 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 2 Apr 2020 19:01:14 +0100 Subject: [PATCH 59/79] tuning parameters --- .../src/interface_interpolation/CIsoparametric.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp index c41c92c2c463..880d01de0a39 100644 --- a/Common/src/interface_interpolation/CIsoparametric.cpp +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -49,7 +49,7 @@ void CIsoparametric::PrintStatistics(void) const { void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { /*--- Angle between target and donor above which we trigger fallback measures. ---*/ - const su2double thetaMax = 20.0/180.0*PI_NUMBER; + const su2double thetaMax = 30.0/180.0*PI_NUMBER; const int nProcessor = size; const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; @@ -262,7 +262,7 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { } SU2_OMP_CRITICAL { - MaxDistance = max(MaxDistance,maxDist); + MaxDistance = max(MaxDistance, maxDist); ErrorCounter += errorCount; nGlobalVertexTarget += totalCount; } @@ -357,8 +357,8 @@ int CIsoparametric::QuadrilateralIsoparameters(const su2double X[][3], const su2 const su2double extrapTol = 1.01; - constexpr int NITER = 10; - const su2double tol = 1e-12; + constexpr int NITER = 200; + const su2double tol = 1e-5, relax = 0.8; su2double Xi = 0.0, Eta = 0.0, eps; @@ -402,8 +402,8 @@ int CIsoparametric::QuadrilateralIsoparameters(const su2double X[][3], const su2 su2double detA = 1.0 / (A[0][0]*A[1][1] - A[0][1]*A[1][0]); su2double dXi = (b[0]*A[1][1] - b[1]*A[0][1]) * detA; su2double dEta = (A[0][0]*b[1] - A[1][0]*b[0]) * detA; - Xi -= dXi; - Eta -= dEta; + Xi -= relax * dXi; + Eta -= relax * dEta; eps = fabs(dXi)+fabs(dEta); if (eps < tol) break; @@ -414,7 +414,7 @@ int CIsoparametric::QuadrilateralIsoparameters(const su2double X[][3], const su2 int outOfBounds = 0; if (eps > 0.01) { - /*--- Iteration did not converge. ---*/ + /*--- Iteration diverged. ---*/ Xi = Eta = 0.0; outOfBounds = 1; } From 209c7f30f657cd784b9e57f3d111fbe6a8efd701 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 2 Apr 2020 19:51:49 +0100 Subject: [PATCH 60/79] fix uninit variable --- Common/src/interface_interpolation/CIsoparametric.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp index 880d01de0a39..d81892d53611 100644 --- a/Common/src/interface_interpolation/CIsoparametric.cpp +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -381,7 +381,7 @@ int CIsoparametric::QuadrilateralIsoparameters(const su2double X[][3], const su2 su2double dNi[4][2] = {{0.0}}; CQUAD4::ShapeFunctionJacobian(Xi, Eta, dNi); - su2double jac[3][2]; + su2double jac[3][2] = {{0.0}}; for (int i = 0; i < 3; ++i) for (int j = 0; j < 2; ++j) for (int k = 0; k < 4; ++k) From 74ffc2e21484ee485cdaced59f2623bdbdc19e6e Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Thu, 2 Apr 2020 20:40:57 +0100 Subject: [PATCH 61/79] small tweaks --- .../CIsoparametric.cpp | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp index d81892d53611..bb46dbe2991f 100644 --- a/Common/src/interface_interpolation/CIsoparametric.cpp +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -43,7 +43,7 @@ CIsoparametric::CIsoparametric(CGeometry ****geometry_container, const CConfig* void CIsoparametric::PrintStatistics(void) const { if (rank != MASTER_NODE) return; cout << " Maximum distance to closest donor element: " << MaxDistance << ".\n" - << " Interpolation mitigated on " << ErrorCounter << " (" << ErrorRate << "%) target vertices." << endl; + << " Interpolation mitigated for " << ErrorCounter << " (" << ErrorRate << "%) target vertices." << endl; } void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { @@ -283,7 +283,7 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { int CIsoparametric::LineIsoparameters(const su2double X[][3], const su2double *xj, su2double *isoparams) { - const su2double extrapTol = 1.01; + const su2double extrapTol = 1.05; su2double l01 = Distance(2, X[0], X[1]); su2double l0j = Distance(2, X[0], xj); @@ -293,12 +293,7 @@ int CIsoparametric::LineIsoparameters(const su2double X[][3], const su2double *x const int outOfBounds = (l0j+lj1) > (extrapTol*l01); - if (outOfBounds) { - l0j = (l0j > lj1)? l01 : 0.0; // which ever is closest becomes the donor - lj1 = l01 - l0j; - } - - isoparams[0] = lj1 / l01; + isoparams[0] = max(1.0-extrapTol, min(lj1/l01, extrapTol)); isoparams[1] = 1.0 - isoparams[0]; return outOfBounds; @@ -309,7 +304,7 @@ int CIsoparametric::TriangleIsoparameters(const su2double X[][3], const su2doubl /*--- The isoparameters are the solution to the determined system X^T * isoparams = xj. * This is consistent with the shape functions of the linear triangular element. ---*/ - const su2double extrapTol = -0.01; + const su2double extrapTol = -0.05; su2double A[3][3] = {{0.0}}; // = X^T @@ -342,9 +337,18 @@ int CIsoparametric::TriangleIsoparameters(const su2double X[][3], const su2doubl (isoparams[1] < extrapTol) || (isoparams[2] < extrapTol); - /*--- Simple mitigation. ---*/ - if (outOfBounds) - isoparams[0] = isoparams[1] = isoparams[2] = 1.0/3.0; + /*--- Mitigation. ---*/ + if (outOfBounds) { + /*--- Clamp. ---*/ + su2double sum = 0.0; + for (int i = 0; i < 3; ++i) { + isoparams[i] = max(isoparams[i], extrapTol); + sum += isoparams[i]; + } + /*--- Enforce unit sum. ---*/ + for (int i = 0; i < 3; ++i) + isoparams[i] /= sum; + } return outOfBounds; } @@ -353,12 +357,12 @@ int CIsoparametric::QuadrilateralIsoparameters(const su2double X[][3], const su2 /*--- The isoparameters are the shape functions (Ni) evaluated at xj, for that we need * the corresponding Xi and Eta, which are obtained by solving the overdetermined - * nonlinear system xj - X^T * Ni(Xi,Eta) = 0 via the Gauss-Newton method. ---*/ + * nonlinear system xj - X^T * Ni(Xi,Eta) = 0 via the modified Marquardt method. ---*/ - const su2double extrapTol = 1.01; + const su2double extrapTol = 1.05; - constexpr int NITER = 200; - const su2double tol = 1e-5, relax = 0.8; + constexpr int NITER = 20; + const su2double tol = 1e-10, lambda = 0.05; su2double Xi = 0.0, Eta = 0.0, eps; @@ -393,17 +397,19 @@ int CIsoparametric::QuadrilateralIsoparameters(const su2double X[][3], const su2 for (int j = i; j < 2; ++j) for (int k = 0; k < 3; ++k) A[i][j] += jac[k][i] * jac[k][j]; - A[1][0] = A[0][1]; + + A[i][i] *= (1.0+lambda); for (int k = 0; k < 3; ++k) b[i] += jac[k][i] * r[k]; } + A[1][0] = A[0][1]; su2double detA = 1.0 / (A[0][0]*A[1][1] - A[0][1]*A[1][0]); su2double dXi = (b[0]*A[1][1] - b[1]*A[0][1]) * detA; su2double dEta = (A[0][0]*b[1] - A[1][0]*b[0]) * detA; - Xi -= relax * dXi; - Eta -= relax * dEta; + Xi -= dXi; + Eta -= dEta; eps = fabs(dXi)+fabs(dEta); if (eps < tol) break; @@ -414,7 +420,7 @@ int CIsoparametric::QuadrilateralIsoparameters(const su2double X[][3], const su2 int outOfBounds = 0; if (eps > 0.01) { - /*--- Iteration diverged. ---*/ + /*--- Iteration diverged, hard fallback. ---*/ Xi = Eta = 0.0; outOfBounds = 1; } @@ -424,8 +430,8 @@ int CIsoparametric::QuadrilateralIsoparameters(const su2double X[][3], const su2 /*--- Mitigate by clamping coordinates. ---*/ if (outOfBounds) { - Xi = max(-1.0, min(Xi, 1.0)); - Eta = max(-1.0, min(Eta, 1.0)); + Xi = max(-extrapTol, min(Xi, extrapTol)); + Eta = max(-extrapTol, min(Eta, extrapTol)); } } From abf5b0f4a55390fddf744754a638de52cc1ced80 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Fri, 3 Apr 2020 15:50:04 +0100 Subject: [PATCH 62/79] robustness improvements --- .../CIsoparametric.hpp | 14 +- Common/include/toolboxes/geometry_toolbox.hpp | 25 +++ .../CIsoparametric.cpp | 171 +++++++++--------- 3 files changed, 122 insertions(+), 88 deletions(-) diff --git a/Common/include/interface_interpolation/CIsoparametric.hpp b/Common/include/interface_interpolation/CIsoparametric.hpp index d55c98a68b81..600414b77c11 100644 --- a/Common/include/interface_interpolation/CIsoparametric.hpp +++ b/Common/include/interface_interpolation/CIsoparametric.hpp @@ -33,6 +33,8 @@ */ class CIsoparametric final : public CInterpolator { private: + static constexpr auto NUM_CANDIDATE_DONORS = 8ul; /*!< \brief Test this many nearby donor elements for "best fit". */ + /*--- Statistics. ---*/ su2double MaxDistance = 0.0, ErrorRate = 0.0; unsigned long ErrorCounter = 0; @@ -62,27 +64,27 @@ class CIsoparametric final : public CInterpolator { /*! * \brief Compute the isoparametric interpolation coefficients for a 2D line element. * \param[in] X - Coordinate matrix defining the line. - * \param[in] xj - Coordinates of the target point projected onto the plane of the element. + * \param[in] xj - Coordinates of the target point. * \param[out] isoparams - Isoparametric coefficients. - * \return 0 on success, 1 if xj is outside element bounds. + * \return 0 on success, 1 if xj is too far outside element bounds. */ static int LineIsoparameters(const su2double X[][3], const su2double *xj, su2double* isoparams); /*! * \brief Compute the isoparametric interpolation coefficients for a 3D triangle element. * \param[in] X - Coordinate matrix defining the triangle. - * \param[in] xj - Coordinates of the target point projected onto the plane of the element. + * \param[in] xj - Coordinates of the target point. * \param[out] isoparams - Isoparametric coefficients. - * \return 0 on success, 1 if xj is outside element bounds. + * \return 0 on success, 1 if xj is too far outside element bounds. */ static int TriangleIsoparameters(const su2double X[][3], const su2double *xj, su2double* isoparams); /*! * \brief Compute the isoparametric interpolation coefficients for a 3D quadrilateral element. * \param[in] X - Coordinate matrix defining the quadrilateral. - * \param[in] xj - Coordinates of the target point projected onto the plane of the element. + * \param[in] xj - Coordinates of the target point. * \param[out] isoparams - Isoparametric coefficients. - * \return 0 on success, 1 if xj is outside element bounds. + * \return 0 on success, 1 if xj is too far outside element bounds. */ static int QuadrilateralIsoparameters(const su2double X[][3], const su2double *xj, su2double* isoparams); diff --git a/Common/include/toolboxes/geometry_toolbox.hpp b/Common/include/toolboxes/geometry_toolbox.hpp index 7891ae89f1b4..76e9339e72d8 100644 --- a/Common/include/toolboxes/geometry_toolbox.hpp +++ b/Common/include/toolboxes/geometry_toolbox.hpp @@ -76,6 +76,31 @@ inline void CrossProduct(const T* a, const T* b, T* c) { c[2] = a[0]*b[1] - a[1]*b[0]; } +/*! + * \brief Compute the coordinate (c) where the line defined by coordinate l0 and + * direction d intersects the plane defined by point p0 and normal n. + * \return The intersection distance. + */ +template +inline T LinePlaneIntersection(const T* l0, const T* d, const T* p0, const T* n, T* c) { + T dist[nDim] = {0.0}; + Distance(nDim, p0, l0, dist); + T alpha = DotProduct(nDim, dist, n) / DotProduct(nDim, d, n); + for (int iDim = 0; iDim < nDim; ++iDim) + c[iDim] = l0[iDim] + alpha * d[iDim]; + return fabs(alpha) * Norm(nDim,d); +} + +/*! + * \brief Compute the coordinate (c) where point p1 intersects the plane defined + * by point p0 and normal n if projected perpendicular to it. + * \return The normal distance. + */ +template +inline T PointPlaneProjection(const T* p1, const T* p0, const T* n, T* c) { + return LinePlaneIntersection(p1, n, p0, n, c); +} + /*! \brief Set U as the normal to a 2D line defined by coords[iPoint][iDim]. */ template inline void LineNormal(const T& coords, U* normal) { diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp index bb46dbe2991f..9745b5b9d70b 100644 --- a/Common/src/interface_interpolation/CIsoparametric.cpp +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -34,6 +34,19 @@ using namespace GeometryToolbox; +/*! \brief Helper struct to store information about candidate donor elements. */ +struct DonorInfo { + su2double isoparams[4] = {0.0}; /*!< \brief Interpolation coefficients. */ + su2double distance = 0.0; /*!< \brief Distance from target to final mapped point on donor plane. */ + unsigned iElem = 0; /*!< \brief Identification of the element. */ + int error = 2; /*!< \brief If the mapped point is "outside" of the donor. */ + + bool operator< (const DonorInfo& other) const { + /*--- Best donor is one for which the mapped point is within bounds and closest to target. ---*/ + return (error == other.error)? (distance < other.distance) : (error < other.error); + } +}; + CIsoparametric::CIsoparametric(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { @@ -48,9 +61,6 @@ void CIsoparametric::PrintStatistics(void) const { void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { - /*--- Angle between target and donor above which we trigger fallback measures. ---*/ - const su2double thetaMax = 30.0/180.0*PI_NUMBER; - const int nProcessor = size; const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; const auto nDim = donor_geometry->GetnDim(); @@ -132,8 +142,8 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { vector elemNumNodes; su2matrix elemIdxNodes; - auto nGlobalElemDonor = Collect_ElementInfo(markDonor, nDim, true, - allNumElem, elemNumNodes, elemIdxNodes); + const auto nGlobalElemDonor = Collect_ElementInfo(markDonor, nDim, true, + allNumElem, elemNumNodes, elemIdxNodes); su2activematrix elemCentroid(nGlobalElemDonor, nDim); @@ -164,6 +174,7 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { /*--- Compute transfer coefficients for each target point. ---*/ su2double maxDist = 0.0; unsigned long errorCount = 0, totalCount = 0; + vector nearElems(nGlobalElemDonor); SU2_OMP_FOR_DYN(roundUpDiv(nVertexTarget,2*omp_get_max_threads())) for (auto iVertex = 0u; iVertex < nVertexTarget; ++iVertex) { @@ -174,89 +185,74 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { if (!target_geometry->node[iPoint]->GetDomain()) continue; totalCount += 1; - /*--- Coordinates and unit normal of the target point. ---*/ + /*--- Coordinates of the target point. ---*/ const su2double* coord_i = target_geometry->node[iPoint]->GetCoord(); - const su2double area_i = Norm(nDim, target_vertex->GetNormal()); - su2double unitNormal_i[3] = {0.0}; - for (auto iDim = 0u; iDim < nDim; ++iDim) - unitNormal_i[iDim] = target_vertex->GetNormal(iDim) / area_i; - - /*--- Find closest element (the naive way). ---*/ - su2double minDist = 1e20; - auto iElemDonor = 0u; - for (auto iElem = 0u; iElem < nGlobalElemDonor; ++iElem) { - su2double dist = SquaredDistance(nDim, coord_i, elemCentroid[iElem]); - if (dist < minDist) { - minDist = dist; - iElemDonor = iElem; - } - } - /*--- Fetch donor element info. ---*/ - int procList[4] = {0}; - long nodeList[4] = {0}; - su2double coords[4][3] = {{0.0}}; - - const auto nNode = elemNumNodes[iElemDonor]; + /*--- Find "n" closest candidate donor elements (the naive way). ---*/ + iota(nearElems.begin(), nearElems.end(), 0); + auto last = nearElems.begin() + min(NUM_CANDIDATE_DONORS, nGlobalElemDonor); + partial_sort(nearElems.begin(), last, nearElems.end(), + [&](unsigned iElem, unsigned jElem) { + return SquaredDistance(nDim, coord_i, elemCentroid[iElem]) < + SquaredDistance(nDim, coord_i, elemCentroid[jElem]); + } + ); - for (auto iNode = 0u; iNode < nNode; ++iNode) { - const auto iVertex = elemIdxNodes(iElemDonor, iNode); - procList[iNode] = donorProc[iVertex]; - nodeList[iNode] = donorPoint[iVertex]; - for (auto iDim = 0u; iDim < nDim; ++iDim) - coords[iNode][iDim] = donorCoord(iVertex,iDim); - } + /*--- Evaluate interpolation for the candidates. ---*/ + array candidateElems; - const su2double* coord_j = elemCentroid[iElemDonor]; - su2double normal_j[3] = {0.0}; + for (auto i = 0u; i < min(NUM_CANDIDATE_DONORS, nGlobalElemDonor); ++i) { + const auto iElem = nearElems[i]; - switch (nNode) { - case 2: LineNormal(coords, normal_j); break; - case 3: TriangleNormal(coords, normal_j); break; - case 4: QuadrilateralNormal(coords, normal_j); break; - } + /*--- Fetch element info. ---*/ + auto& candidate = candidateElems[i]; + candidate.iElem = iElem; + const auto nNode = elemNumNodes[iElem]; + su2double coords[4][3] = {{0.0}}; - /*--- Project the target onto the donor plane, as grids may not be exactly conformal. - * For quadrilaterals this is approximate as the element may be warped. ---*/ - su2double proj = DotProduct(nDim, unitNormal_i, normal_j); - su2double theta = acos(fabs(proj) / Norm(nDim, normal_j)); + for (auto iNode = 0u; iNode < nNode; ++iNode) { + const auto iVertex = elemIdxNodes(iElem, iNode); + for (auto iDim = 0u; iDim < nDim; ++iDim) + coords[iNode][iDim] = donorCoord(iVertex,iDim); + } - su2double projCoord[3] = {0.0}; + /*--- Compute the interpolation coefficients. ---*/ + switch (nNode) { + case 2: candidate.error = LineIsoparameters(coords, coord_i, candidate.isoparams); break; + case 3: candidate.error = TriangleIsoparameters(coords, coord_i, candidate.isoparams); break; + case 4: candidate.error = QuadrilateralIsoparameters(coords, coord_i, candidate.isoparams); break; + } - if (theta < thetaMax) { - su2double dist_ij[3] = {0.0}; - Distance(nDim, coord_j, coord_i, dist_ij); - proj = DotProduct(nDim, dist_ij, normal_j) / proj; + /*--- Evaluate distance from target to final mapped point. ---*/ + su2double finalCoord[3] = {0.0}; for (auto iDim = 0u; iDim < nDim; ++iDim) - projCoord[iDim] = coord_i[iDim] + proj*unitNormal_i[iDim]; + for (auto iNode = 0u; iNode < nNode; ++iNode) + finalCoord[iDim] += coords[iNode][iDim] * candidate.isoparams[iNode]; - maxDist = max(maxDist, fabs(proj)); + candidate.distance = Distance(nDim, coord_i, finalCoord); + if (candidate.distance != candidate.distance) // NaN check + candidate.error = 2; } - else { - /*--- Target and donor are too out of alignement, as fallback - * use the element centroid as the projected coordinate. ---*/ - for (auto iDim = 0u; iDim < nDim; ++iDim) - projCoord[iDim] = coord_j[iDim]; - errorCount += 1; - maxDist = max(maxDist, sqrt(minDist)); - } + /*--- Find best donor. ---*/ + partial_sort(candidateElems.begin(), candidateElems.begin()+1, candidateElems.end()); + const auto& donor = candidateElems[0]; - /*--- Compute and set interpolation coefficients. ---*/ + if (donor.error > 1) + SU2_MPI::Error("Isoparametric interpolation failed, NaN detected.", CURRENT_FUNCTION); - su2double isoparams[4] = {0.0}; - switch (nNode) { - case 2: errorCount += LineIsoparameters(coords, projCoord, isoparams); break; - case 3: errorCount += TriangleIsoparameters(coords, projCoord, isoparams); break; - case 4: errorCount += QuadrilateralIsoparameters(coords, projCoord, isoparams); break; - } + errorCount += donor.error; + maxDist = max(maxDist, donor.distance); + + const auto nNode = elemNumNodes[donor.iElem]; target_vertex->Allocate_DonorInfo(nNode); - for (auto iDonor = 0u; iDonor < nNode; ++iDonor) { - target_vertex->SetDonorCoeff(iDonor, isoparams[iDonor]); - target_vertex->SetInterpDonorPoint(iDonor, nodeList[iDonor]); - target_vertex->SetInterpDonorProcessor(iDonor, procList[iDonor]); + for (auto iNode = 0u; iNode < nNode; ++iNode) { + const auto iVertex = elemIdxNodes(donor.iElem, iNode); + target_vertex->SetDonorCoeff(iNode, donor.isoparams[iNode]); + target_vertex->SetInterpDonorPoint(iNode, donorPoint[iVertex]); + target_vertex->SetInterpDonorProcessor(iNode, donorProc[iVertex]); } } @@ -283,11 +279,18 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { int CIsoparametric::LineIsoparameters(const su2double X[][3], const su2double *xj, su2double *isoparams) { - const su2double extrapTol = 1.05; + const su2double extrapTol = 1.5; + + /*--- Project the target point onto the line. ---*/ + + su2double normal[2] = {0.0}; + LineNormal(X, normal); + su2double xprj[2] = {0.0}; + PointPlaneProjection(xj, X[0], normal, xprj); su2double l01 = Distance(2, X[0], X[1]); - su2double l0j = Distance(2, X[0], xj); - su2double lj1 = Distance(2, xj, X[1]); + su2double l0j = Distance(2, X[0], xprj); + su2double lj1 = Distance(2, xprj, X[1]); /*--- Detect out of bounds point. ---*/ @@ -304,15 +307,18 @@ int CIsoparametric::TriangleIsoparameters(const su2double X[][3], const su2doubl /*--- The isoparameters are the solution to the determined system X^T * isoparams = xj. * This is consistent with the shape functions of the linear triangular element. ---*/ - const su2double extrapTol = -0.05; + const su2double extrapTol = -0.5; - su2double A[3][3] = {{0.0}}; // = X^T + /*--- Project the target point onto the triangle. ---*/ - for (int i = 0; i < 3; ++i) { - isoparams[i] = xj[i]; // use isoparams as rhs + su2double normal[3] = {0.0}; + TriangleNormal(X, normal); + PointPlaneProjection(xj, X[0], normal, isoparams); // use isoparams as rhs + + su2double A[3][3]; // = X^T + for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) A[i][j] = X[j][i]; - } /*--- Solve system by in-place Gaussian elimination without pivoting. ---*/ @@ -357,9 +363,10 @@ int CIsoparametric::QuadrilateralIsoparameters(const su2double X[][3], const su2 /*--- The isoparameters are the shape functions (Ni) evaluated at xj, for that we need * the corresponding Xi and Eta, which are obtained by solving the overdetermined - * nonlinear system xj - X^T * Ni(Xi,Eta) = 0 via the modified Marquardt method. ---*/ + * nonlinear system r = xj - X^T * Ni(Xi,Eta) = 0 via the modified Marquardt method. + * It is not necessary to project the point as minimizing ||r|| is equivalent. ---*/ - const su2double extrapTol = 1.05; + const su2double extrapTol = 3.0; constexpr int NITER = 20; const su2double tol = 1e-10, lambda = 0.05; @@ -435,7 +442,7 @@ int CIsoparametric::QuadrilateralIsoparameters(const su2double X[][3], const su2 } } - /*--- Evaluate isoparameters. ---*/ + /*--- Evaluate isoparameters at final Xi and Eta. ---*/ CQUAD4::ShapeFunctions(Xi, Eta, isoparams); return outOfBounds; From 79dcfaef0a4d596831496e6c321702b641fe84b8 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Fri, 3 Apr 2020 15:55:10 +0100 Subject: [PATCH 63/79] old compiler fixes --- Common/include/interface_interpolation/CIsoparametric.hpp | 2 +- Common/src/interface_interpolation/CIsoparametric.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Common/include/interface_interpolation/CIsoparametric.hpp b/Common/include/interface_interpolation/CIsoparametric.hpp index 600414b77c11..cd2d1562aa0f 100644 --- a/Common/include/interface_interpolation/CIsoparametric.hpp +++ b/Common/include/interface_interpolation/CIsoparametric.hpp @@ -33,7 +33,7 @@ */ class CIsoparametric final : public CInterpolator { private: - static constexpr auto NUM_CANDIDATE_DONORS = 8ul; /*!< \brief Test this many nearby donor elements for "best fit". */ + enum: unsigned long { NUM_CANDIDATE_DONORS = 8 }; /*!< \brief Test this many nearby donor elements for "best fit". */ /*--- Statistics. ---*/ su2double MaxDistance = 0.0, ErrorRate = 0.0; unsigned long ErrorCounter = 0; diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp index 9745b5b9d70b..6c2cc7ca9a55 100644 --- a/Common/src/interface_interpolation/CIsoparametric.cpp +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -190,7 +190,7 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { /*--- Find "n" closest candidate donor elements (the naive way). ---*/ iota(nearElems.begin(), nearElems.end(), 0); - auto last = nearElems.begin() + min(NUM_CANDIDATE_DONORS, nGlobalElemDonor); + auto last = nearElems.begin() + min(NUM_CANDIDATE_DONORS, nGlobalElemDonor); partial_sort(nearElems.begin(), last, nearElems.end(), [&](unsigned iElem, unsigned jElem) { return SquaredDistance(nDim, coord_i, elemCentroid[iElem]) < @@ -201,7 +201,7 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { /*--- Evaluate interpolation for the candidates. ---*/ array candidateElems; - for (auto i = 0u; i < min(NUM_CANDIDATE_DONORS, nGlobalElemDonor); ++i) { + for (auto i = 0u; i < min(NUM_CANDIDATE_DONORS, nGlobalElemDonor); ++i) { const auto iElem = nearElems[i]; /*--- Fetch element info. ---*/ From a86857ba5771ba47f3d8d4245d142d9fe592dde3 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 4 Apr 2020 10:11:08 +0100 Subject: [PATCH 64/79] adding DEFORM_POISSONS_RATIO to testcases due to bug fix --- .../naca0012_pitching/inv_NACA0012_pitching_deform.cfg | 1 + .../naca0012_pitching/inv_NACA0012_pitching_deform_ad.cfg | 1 + TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg | 1 + TestCases/fea_fsi/WallChannel_2d/configFlow.cfg | 1 + 4 files changed, 4 insertions(+) diff --git a/TestCases/disc_adj_euler/naca0012_pitching/inv_NACA0012_pitching_deform.cfg b/TestCases/disc_adj_euler/naca0012_pitching/inv_NACA0012_pitching_deform.cfg index 2387eaa95368..d42b48c31735 100644 --- a/TestCases/disc_adj_euler/naca0012_pitching/inv_NACA0012_pitching_deform.cfg +++ b/TestCases/disc_adj_euler/naca0012_pitching/inv_NACA0012_pitching_deform.cfg @@ -101,6 +101,7 @@ DEFORM_NONLINEAR_ITER= 1 DEFORM_CONSOLE_OUTPUT= YES DEFORM_LINEAR_SOLVER_ERROR= 0.000000001 DEFORM_STIFFNESS_TYPE= INVERSE_VOLUME +DEFORM_POISSONS_RATIO= 1e6 % --------------------------- CONVERGENCE PARAMETERS --------------------------% CONV_CRITERIA= RESIDUAL diff --git a/TestCases/disc_adj_euler/naca0012_pitching/inv_NACA0012_pitching_deform_ad.cfg b/TestCases/disc_adj_euler/naca0012_pitching/inv_NACA0012_pitching_deform_ad.cfg index c07290c332fa..11b0672a9f7c 100644 --- a/TestCases/disc_adj_euler/naca0012_pitching/inv_NACA0012_pitching_deform_ad.cfg +++ b/TestCases/disc_adj_euler/naca0012_pitching/inv_NACA0012_pitching_deform_ad.cfg @@ -101,6 +101,7 @@ DEFORM_NONLINEAR_ITER= 1 DEFORM_CONSOLE_OUTPUT= YES DEFORM_LINEAR_SOLVER_ERROR= 0.000000001 DEFORM_STIFFNESS_TYPE= INVERSE_VOLUME +DEFORM_POISSONS_RATIO= 1e6 % --------------------------- CONVERGENCE PARAMETERS --------------------------% CONV_CRITERIA= RESIDUAL diff --git a/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg b/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg index b739517205ca..92fadd9fe108 100644 --- a/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg +++ b/TestCases/fea_fsi/Airfoil_RBF/configFlow.cfg @@ -90,6 +90,7 @@ DEFORM_MESH= YES MARKER_DEFORM_MESH= ( leading_edge, pressure_side, suction_side ) DEFORM_NONLINEAR_ITER= 1 DEFORM_STIFFNESS_TYPE= INVERSE_VOLUME +DEFORM_POISSONS_RATIO= 1e6 DEFORM_CONSOLE_OUTPUT= NO % % Linear solvers ------------------------------------------------------- % diff --git a/TestCases/fea_fsi/WallChannel_2d/configFlow.cfg b/TestCases/fea_fsi/WallChannel_2d/configFlow.cfg index 08d5716c6698..2a5372db08f5 100644 --- a/TestCases/fea_fsi/WallChannel_2d/configFlow.cfg +++ b/TestCases/fea_fsi/WallChannel_2d/configFlow.cfg @@ -70,6 +70,7 @@ DEFORM_LINEAR_SOLVER= FGMRES DEFORM_LINEAR_SOLVER_PREC= LU_SGS DEFORM_LINEAR_SOLVER_ITER= 500 DEFORM_STIFFNESS_TYPE= WALL_DISTANCE +DEFORM_POISSONS_RATIO= 1e6 MESH_FORMAT= SU2 TABULAR_FORMAT= CSV From c4eb4f6f9842023fe8d0e0a1d0d009de2a81e96d Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 4 Apr 2020 11:10:55 +0100 Subject: [PATCH 65/79] cleanup and small fixes --- SU2_CFD/src/drivers/CMultizoneDriver.cpp | 19 +- SU2_CFD/src/drivers/CSinglezoneDriver.cpp | 22 +- SU2_CFD/src/iteration_structure.cpp | 43 +- SU2_CFD/src/solvers/CMeshSolver.cpp | 624 ++++++++++------------ 4 files changed, 321 insertions(+), 387 deletions(-) diff --git a/SU2_CFD/src/drivers/CMultizoneDriver.cpp b/SU2_CFD/src/drivers/CMultizoneDriver.cpp index ef97feda069c..e05af44e2e7e 100644 --- a/SU2_CFD/src/drivers/CMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CMultizoneDriver.cpp @@ -545,22 +545,21 @@ void CMultizoneDriver::DynamicMeshUpdate(unsigned long TimeIter) { void CMultizoneDriver::DynamicMeshUpdate(unsigned short val_iZone, unsigned long TimeIter) { + auto iteration = iteration_container[val_iZone][INST_0]; + /*--- Legacy dynamic mesh update - Only if GRID_MOVEMENT = YES ---*/ if (config_container[ZONE_0]->GetGrid_Movement()) { - iteration_container[val_iZone][INST_0]->SetGrid_Movement(geometry_container[val_iZone][INST_0],surface_movement[val_iZone], - grid_movement[val_iZone][INST_0], solver_container[val_iZone][INST_0], - config_container[val_iZone], 0, TimeIter); + iteration->SetGrid_Movement(geometry_container[val_iZone][INST_0],surface_movement[val_iZone], + grid_movement[val_iZone][INST_0], solver_container[val_iZone][INST_0], + config_container[val_iZone], 0, TimeIter); } /*--- New solver - all the other routines in SetGrid_Movement should be adapted to this one ---*/ /*--- Works if DEFORM_MESH = YES ---*/ - if (config_container[ZONE_0]->GetDeform_Mesh()) { - iteration_container[val_iZone][INST_0]->SetMesh_Deformation(geometry_container[val_iZone][INST_0], - solver_container[val_iZone][INST_0][MESH_0], - numerics_container[val_iZone][INST_0][MESH_0], - config_container[ZONE_0], - NONE); - } + iteration->SetMesh_Deformation(geometry_container[val_iZone][INST_0], + solver_container[val_iZone][INST_0][MESH_0], + numerics_container[val_iZone][INST_0][MESH_0], + config_container[val_iZone], NONE); } diff --git a/SU2_CFD/src/drivers/CSinglezoneDriver.cpp b/SU2_CFD/src/drivers/CSinglezoneDriver.cpp index a1ab4f317c61..abb2837c9a87 100644 --- a/SU2_CFD/src/drivers/CSinglezoneDriver.cpp +++ b/SU2_CFD/src/drivers/CSinglezoneDriver.cpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -226,23 +226,21 @@ void CSinglezoneDriver::Output(unsigned long TimeIter) { void CSinglezoneDriver::DynamicMeshUpdate(unsigned long TimeIter) { + auto iteration = iteration_container[ZONE_0][INST_0]; + /*--- Legacy dynamic mesh update - Only if GRID_MOVEMENT = YES ---*/ if (config_container[ZONE_0]->GetGrid_Movement()) { - iteration_container[ZONE_0][INST_0]->SetGrid_Movement(geometry_container[ZONE_0][INST_0],surface_movement[ZONE_0], - grid_movement[ZONE_0][INST_0], solver_container[ZONE_0][INST_0], - config_container[ZONE_0], 0, TimeIter); + iteration->SetGrid_Movement(geometry_container[ZONE_0][INST_0],surface_movement[ZONE_0], + grid_movement[ZONE_0][INST_0], solver_container[ZONE_0][INST_0], + config_container[ZONE_0], 0, TimeIter); } /*--- New solver - all the other routines in SetGrid_Movement should be adapted to this one ---*/ /*--- Works if DEFORM_MESH = YES ---*/ - if (config_container[ZONE_0]->GetDeform_Mesh()) { - iteration_container[ZONE_0][INST_0]->SetMesh_Deformation(geometry_container[ZONE_0][INST_0], - solver_container[ZONE_0][INST_0][MESH_0], - numerics_container[ZONE_0][INST_0][MESH_0], - config_container[ZONE_0], - NONE); - } - + iteration->SetMesh_Deformation(geometry_container[ZONE_0][INST_0], + solver_container[ZONE_0][INST_0][MESH_0], + numerics_container[ZONE_0][INST_0][MESH_0], + config_container[ZONE_0], NONE); } diff --git a/SU2_CFD/src/iteration_structure.cpp b/SU2_CFD/src/iteration_structure.cpp index 63af720ef232..4821565942d2 100644 --- a/SU2_CFD/src/iteration_structure.cpp +++ b/SU2_CFD/src/iteration_structure.cpp @@ -179,7 +179,7 @@ void CIteration::SetGrid_Movement(CGeometry **geometry, grid_movement->UpdateMultiGrid(geometry, config); } - + if (config->GetSurface_Movement(EXTERNAL) || config->GetSurface_Movement(EXTERNAL_ROTATION)) { @@ -227,35 +227,30 @@ void CIteration::SetMesh_Deformation(CGeometry **geometry, CConfig *config, unsigned short kind_recording) { - bool ActiveTape = NO; + if (!config->GetDeform_Mesh()) return; /*--- Perform the elasticity mesh movement ---*/ - if (config->GetDeform_Mesh()) { - if ((kind_recording != MESH_DEFORM) && !config->GetMultizone_Problem()) { - /*--- In a primal run, AD::TapeActive returns a false ---*/ - /*--- In any other recordings, the tape is passive during the deformation ---*/ - ActiveTape = AD::TapeActive(); - AD::StopRecording(); - } + bool ActiveTape = AD::TapeActive(); - /*--- Set the stiffness of each element mesh into the mesh numerics ---*/ + if ((kind_recording != MESH_DEFORM) && !config->GetMultizone_Problem()) { + /*--- In a primal run, AD::TapeActive returns a false ---*/ + /*--- In any other recordings, the tape is passive during the deformation. ---*/ + AD::StopRecording(); + } - solver[MESH_SOL]->SetMesh_Stiffness(geometry, numerics[MESH_SOL], config); + /*--- Set the stiffness of each element mesh into the mesh numerics ---*/ - /*--- Deform the volume grid around the new boundary locations ---*/ + solver[MESH_SOL]->SetMesh_Stiffness(geometry, numerics[MESH_SOL], config); - solver[MESH_SOL]->DeformMesh(geometry, numerics[MESH_SOL], config); + /*--- Deform the volume grid around the new boundary locations ---*/ - if (ActiveTape) { - /*--- Start recording if it was stopped ---*/ - AD::StartRecording(); - } - } - -} + solver[MESH_SOL]->DeformMesh(geometry, numerics[MESH_SOL], config); + /*--- Continue recording. ---*/ + if (ActiveTape) AD::StartRecording(); +} void CIteration::Preprocess(COutput *output, CIntegration ****integration, @@ -1287,7 +1282,7 @@ void CFEAIteration::Iterate(COutput *output, } else { - + /*--- THIS IS THE INCREMENTAL LOAD APPROACH (only makes sense for nonlinear) ---*/ /*--- Set the initial condition: store the current solution as Solution_Old ---*/ @@ -1300,9 +1295,9 @@ void CFEAIteration::Iterate(COutput *output, loadIncrement = 1.0; feaSolver->SetLoad_Increment(loadIncrement); feaSolver->SetForceCoeff(loadIncrement); - + /*--- Run two nonlinear iterations to check if incremental loading can be skipped ---*/ - + for (IntIter = 0; IntIter < 2; ++IntIter) { config[val_iZone]->SetInnerIter(IntIter); @@ -1498,7 +1493,7 @@ void CFEAIteration::Predictor(COutput *output, unsigned short val_iInst) { CSolver* feaSolver = solver[val_iZone][val_iInst][MESH_0][FEA_SOL]; - + /*--- Predict displacements ---*/ feaSolver->PredictStruct_Displacement(geometry[val_iZone][val_iInst], config[val_iZone], solver[val_iZone][val_iInst]); diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index 269af120261d..50f3700fac6f 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -885,146 +885,136 @@ void CMeshSolver::Restart_OldGeometry(CGeometry *geometry, CConfig *config) { void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, unsigned long iter) { - su2double deltaT, time_new, time_old, Lref, *Coord; - su2double Center[3], VarCoord[3], Omega[3], Ampl[3], Phase[3]; - su2double VarCoordAbs[3] = {0.0, 0.0, 0.0}; - su2double rotCoord[3], r[3] = {0.0,0.0,0.0}; - su2double rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; + su2double deltaT, time_new, time_old, Lref; + const su2double* Coord = nullptr; + su2double Center[3] = {0.0}, VarCoord[3] = {0.0}, Omega[3] = {0.0}, Ampl[3] = {0.0}, Phase[3] = {0.0}; + su2double VarCoordAbs[3] = {0.0}; + su2double rotCoord[3] = {0.0}, r[3] = {0.0}; + su2double rotMatrix[3][3] = {{0.0}}; su2double dtheta, dphi, dpsi, cosTheta, sinTheta; su2double cosPhi, sinPhi, cosPsi, sinPsi; - su2double DEG2RAD = PI_NUMBER/180.0; - unsigned short iMarker, jMarker, Moving, iDim, nDim = geometry->GetnDim(); + const su2double DEG2RAD = PI_NUMBER/180.0; + unsigned short iMarker, jMarker, iDim; unsigned long iPoint, iVertex; string Marker_Tag, Moving_Tag; - /*--- Initialize the delta variation in coordinates ---*/ - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - /*--- Retrieve values from the config file ---*/ deltaT = config->GetDelta_UnstTimeND(); Lref = config->GetLength_Ref(); /*--- Compute delta time based on physical time step ---*/ - time_new = static_cast(iter)*deltaT; - if (iter == 0) { - time_old = time_new; - } else { - time_old = static_cast(iter-1)*deltaT; - } + + time_new = iter*deltaT; + if (iter == 0) time_old = time_new; + else time_old = (iter-1)*deltaT; + + auto Rotate = [](const su2double mat[][3], const su2double* r, const su2double* o, su2double* c) { + c[0] = mat[0][0]*r[0] + mat[0][1]*r[1] + mat[0][2]*r[2] + o[0]; + c[1] = mat[1][0]*r[0] + mat[1][1]*r[1] + mat[1][2]*r[2] + o[1]; + c[2] = mat[2][0]*r[0] + mat[2][1]*r[1] + mat[2][2]*r[2] + o[2]; + }; /*--- Store displacement of each node on the pitching surface ---*/ /*--- Loop over markers and find the particular marker(s) (surface) to pitch ---*/ for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Moving = config->GetMarker_All_Moving(iMarker); - if (Moving == YES) { - for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { + if (config->GetMarker_All_Moving(iMarker) != YES) continue; - Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); + Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if (Marker_Tag == Moving_Tag && (config->GetKind_SurfaceMovement(jMarker) == DEFORMING)) { + for (jMarker = 0; jMarker < config->GetnMarker_Moving(); jMarker++) { - /*--- Pitching origin, frequency, and amplitude from config. ---*/ + Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); - for (iDim = 0; iDim < 3; iDim++){ - Ampl[iDim] = config->GetMarkerPitching_Ampl(jMarker, iDim)*DEG2RAD; - Omega[iDim] = config->GetMarkerPitching_Omega(jMarker, iDim)/config->GetOmega_Ref(); - Phase[iDim] = config->GetMarkerPitching_Phase(jMarker, iDim)*DEG2RAD; - Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); - } - /*--- Print some information to the console. Be verbose at the first - iteration only (mostly for debugging purposes). ---*/ - // Note that the MASTER_NODE might not contain all the markers being moved. - - if (rank == MASTER_NODE) { - cout << " Storing pitching displacement for marker: "; - cout << Marker_Tag << "." << endl; - if (iter == 0) { - cout << " Pitching frequency: (" << Omega[0] << ", " << Omega[1]; - cout << ", " << Omega[2] << ") rad/s about origin: (" << Center[0]; - cout << ", " << Center[1] << ", " << Center[2] << ")." << endl; - cout << " Pitching amplitude about origin: (" << Ampl[0]/DEG2RAD; - cout << ", " << Ampl[1]/DEG2RAD << ", " << Ampl[2]/DEG2RAD; - cout << ") degrees."<< endl; - cout << " Pitching phase lag about origin: (" << Phase[0]/DEG2RAD; - cout << ", " << Phase[1]/DEG2RAD <<", "<< Phase[2]/DEG2RAD; - cout << ") degrees."<< endl; - } - } - - /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ + if ((Marker_Tag != Moving_Tag) || (config->GetKind_SurfaceMovement(jMarker) != DEFORMING)) { + continue; + } - dtheta = -Ampl[0]*(sin(Omega[0]*time_new + Phase[0]) - - sin(Omega[0]*time_old + Phase[0])); - dphi = -Ampl[1]*(sin(Omega[1]*time_new + Phase[1]) - - sin(Omega[1]*time_old + Phase[1])); - dpsi = -Ampl[2]*(sin(Omega[2]*time_new + Phase[2]) - - sin(Omega[2]*time_old + Phase[2])); + /*--- Pitching origin, frequency, and amplitude from config. ---*/ - /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ + for (iDim = 0; iDim < 3; iDim++){ + Ampl[iDim] = config->GetMarkerPitching_Ampl(jMarker, iDim)*DEG2RAD; + Omega[iDim] = config->GetMarkerPitching_Omega(jMarker, iDim)/config->GetOmega_Ref(); + Phase[iDim] = config->GetMarkerPitching_Phase(jMarker, iDim)*DEG2RAD; + Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); + } + /*--- Print some information to the console. Be verbose at the first + iteration only (mostly for debugging purposes). ---*/ + // Note that the MASTER_NODE might not contain all the markers being moved. + + if (rank == MASTER_NODE) { + cout << " Storing pitching displacement for marker: "; + cout << Marker_Tag << "." << endl; + if (iter == 0) { + cout << " Pitching frequency: (" << Omega[0] << ", " << Omega[1]; + cout << ", " << Omega[2] << ") rad/s about origin: (" << Center[0]; + cout << ", " << Center[1] << ", " << Center[2] << ")." << endl; + cout << " Pitching amplitude about origin: (" << Ampl[0]/DEG2RAD; + cout << ", " << Ampl[1]/DEG2RAD << ", " << Ampl[2]/DEG2RAD; + cout << ") degrees."<< endl; + cout << " Pitching phase lag about origin: (" << Phase[0]/DEG2RAD; + cout << ", " << Phase[1]/DEG2RAD <<", "<< Phase[2]/DEG2RAD; + cout << ") degrees."<< endl; + } + } - cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); - sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); + /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ + dtheta = -Ampl[0]*(sin(Omega[0]*time_new + Phase[0]) + - sin(Omega[0]*time_old + Phase[0])); + dphi = -Ampl[1]*(sin(Omega[1]*time_new + Phase[1]) + - sin(Omega[1]*time_old + Phase[1])); + dpsi = -Ampl[2]*(sin(Omega[2]*time_new + Phase[2]) + - sin(Omega[2]*time_old + Phase[2])); - rotMatrix[0][0] = cosPhi*cosPsi; - rotMatrix[1][0] = cosPhi*sinPsi; - rotMatrix[2][0] = -sinPhi; + /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; - rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; - rotMatrix[2][1] = sinTheta*cosPhi; + cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); + sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); - rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[2][2] = cosTheta*cosPhi; + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + rotMatrix[0][0] = cosPhi*cosPsi; + rotMatrix[1][0] = cosPhi*sinPsi; + rotMatrix[2][0] = -sinPhi; - /*--- Index and coordinates of the current point ---*/ + rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; + rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; + rotMatrix[2][1] = sinTheta*cosPhi; - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Coord = geometry->node[iPoint]->GetCoord(); + rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[2][2] = cosTheta*cosPhi; - /*--- Calculate non-dim. position from rotation center ---*/ + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Coord[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; + /*--- Index and coordinates of the current point ---*/ - /*--- Compute transformed point coordinates ---*/ + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Coord = geometry->node[iPoint]->GetCoord(); - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2] + Center[0]; + /*--- Calculate non-dim. position from rotation center ---*/ - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2] + Center[1]; + for (iDim = 0; iDim < nDim; iDim++) + r[iDim] = (Coord[iDim]-Center[iDim])/Lref; - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2] + Center[2]; + /*--- Compute transformed point coordinates ---*/ - /*--- Calculate delta change in the x, y, & z directions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = (rotCoord[iDim]-Coord[iDim])/Lref; - if (nDim == 2) VarCoord[nDim] = 0.0; + Rotate(rotMatrix, r, Center, rotCoord); - // /*--- Set node displacement for volume deformation ---*/ - // geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + /*--- Calculate delta change in the x, y, & z directions ---*/ + for (iDim = 0; iDim < nDim; iDim++) + VarCoord[iDim] = (rotCoord[iDim]-Coord[iDim])/Lref; - for (iDim = 0; iDim < 3; iDim++){ - VarCoordAbs[iDim] = nodes->GetBound_Disp(iPoint, iDim) + VarCoord[iDim]; - } + /*--- Set node displacement for volume deformation ---*/ - nodes->SetBound_Disp(iPoint, VarCoordAbs); - } + for (iDim = 0; iDim < nDim; iDim++){ + VarCoordAbs[iDim] = nodes->GetBound_Disp(iPoint, iDim) + VarCoord[iDim]; } + + nodes->SetBound_Disp(iPoint, VarCoordAbs); } } } @@ -1034,134 +1024,123 @@ void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, unsigne void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, unsigned long iter) { - su2double deltaT, time_new, time_old, Lref, *Coord; - su2double VarCoordAbs[3] = {0.0, 0.0, 0.0}; - su2double Center[3] = {0.0,0.0,0.0}, VarCoord[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}, - rotCoord[3] = {0.0,0.0,0.0}, r[3] = {0.0,0.0,0.0}, Center_Aux[3] = {0.0,0.0,0.0}; - su2double rotMatrix[3][3] = {{0.0,0.0,0.0}, {0.0,0.0,0.0}, {0.0,0.0,0.0}}; + su2double deltaT, time_new, time_old, Lref; + const su2double* Coord = nullptr; + su2double VarCoordAbs[3] = {0.0}; + su2double Center[3] = {0.0}, VarCoord[3] = {0.0}, Omega[3] = {0.0}, + rotCoord[3] = {0.0}, r[3] = {0.0}, Center_Aux[3] = {0.0}; + su2double rotMatrix[3][3] = {{0.0}}; su2double dtheta, dphi, dpsi, cosTheta, sinTheta; su2double cosPhi, sinPhi, cosPsi, sinPsi; - unsigned short iMarker, jMarker, Moving, iDim, nDim = geometry->GetnDim(); + unsigned short iMarker, jMarker, iDim; unsigned long iPoint, iVertex; string Marker_Tag, Moving_Tag; - /*--- Initialize the delta variation in coordinates ---*/ - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - /*--- Retrieve values from the config file ---*/ deltaT = config->GetDelta_UnstTimeND(); Lref = config->GetLength_Ref(); /*--- Compute delta time based on physical time step ---*/ - time_new = static_cast(iter)*deltaT; - if (iter == 0) { - time_old = time_new; - } else { - time_old = static_cast(iter-1)*deltaT; - } + + time_new = iter*deltaT; + if (iter == 0) time_old = time_new; + else time_old = (iter-1)*deltaT; + + auto Rotate = [](const su2double mat[][3], const su2double* r, const su2double* o, su2double* c) { + c[0] = mat[0][0]*r[0] + mat[0][1]*r[1] + mat[0][2]*r[2] + o[0]; + c[1] = mat[1][0]*r[0] + mat[1][1]*r[1] + mat[1][2]*r[2] + o[1]; + c[2] = mat[2][0]*r[0] + mat[2][1]*r[1] + mat[2][2]*r[2] + o[2]; + }; /*--- Store displacement of each node on the rotating surface ---*/ - /*--- Loop over markers and find the particular marker(s) (surface) to rotate ---*/ + /*--- Loop over markers and find the particular marker(s) (surface) to rotate ---*/ for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Moving = config->GetMarker_All_Moving(iMarker); - if (Moving == YES) { - for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { + if (config->GetMarker_All_Moving(iMarker) != YES) continue; - Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); + Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if (Marker_Tag == Moving_Tag && (config->GetKind_SurfaceMovement(jMarker) == DEFORMING)) { + for (jMarker = 0; jMarker < config->GetnMarker_Moving(); jMarker++) { - /*--- Rotation origin and angular velocity from config. ---*/ + Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); - for (iDim = 0; iDim < 3; iDim++){ - Omega[iDim] = config->GetMarkerRotationRate(jMarker, iDim)/config->GetOmega_Ref(); - Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); - } - /*--- Print some information to the console. Be verbose at the first - iteration only (mostly for debugging purposes). ---*/ - // Note that the MASTER_NODE might not contain all the markers being moved. - - if (rank == MASTER_NODE) { - cout << " Storing rotating displacement for marker: "; - cout << Marker_Tag << "." << endl; - if (iter == 0) { - cout << " Angular velocity: (" << Omega[0] << ", " << Omega[1]; - cout << ", " << Omega[2] << ") rad/s about origin: (" << Center[0]; - cout << ", " << Center[1] << ", " << Center[2] << ")." << endl; - } - } + if ((Marker_Tag != Moving_Tag) || (config->GetKind_SurfaceMovement(jMarker) != DEFORMING)) { + continue; + } - /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ + /*--- Rotation origin and angular velocity from config. ---*/ - dtheta = Omega[0]*(time_new-time_old); - dphi = Omega[1]*(time_new-time_old); - dpsi = Omega[2]*(time_new-time_old); + for (iDim = 0; iDim < 3; iDim++){ + Omega[iDim] = config->GetMarkerRotationRate(jMarker, iDim)/config->GetOmega_Ref(); + Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); + } - /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ + /*--- Print some information to the console. Be verbose at the first + iteration only (mostly for debugging purposes). ---*/ + // Note that the MASTER_NODE might not contain all the markers being moved. + + if (rank == MASTER_NODE) { + cout << " Storing rotating displacement for marker: "; + cout << Marker_Tag << "." << endl; + if (iter == 0) { + cout << " Angular velocity: (" << Omega[0] << ", " << Omega[1]; + cout << ", " << Omega[2] << ") rad/s about origin: (" << Center[0]; + cout << ", " << Center[1] << ", " << Center[2] << ")." << endl; + } + } - cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); - sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); + /*--- Compute delta change in the angle about the x, y, & z axes. ---*/ - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ + dtheta = Omega[0]*(time_new-time_old); + dphi = Omega[1]*(time_new-time_old); + dpsi = Omega[2]*(time_new-time_old); - rotMatrix[0][0] = cosPhi*cosPsi; - rotMatrix[1][0] = cosPhi*sinPsi; - rotMatrix[2][0] = -sinPhi; + /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; - rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; - rotMatrix[2][1] = sinTheta*cosPhi; + cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); + sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); - rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[2][2] = cosTheta*cosPhi; + /*--- Compute the rotation matrix. Note that the implicit + ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + rotMatrix[0][0] = cosPhi*cosPsi; + rotMatrix[1][0] = cosPhi*sinPsi; + rotMatrix[2][0] = -sinPhi; - /*--- Index and coordinates of the current point ---*/ + rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; + rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; + rotMatrix[2][1] = sinTheta*cosPhi; - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - Coord = geometry->node[iPoint]->GetCoord(); + rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + rotMatrix[2][2] = cosTheta*cosPhi; - /*--- Calculate non-dim. position from rotation center ---*/ + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Coord[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; + /*--- Index and coordinates of the current point ---*/ - /*--- Compute transformed point coordinates ---*/ + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + Coord = geometry->node[iPoint]->GetCoord(); - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2] + Center[0]; + /*--- Calculate non-dim. position from rotation center ---*/ - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2] + Center[1]; + for (iDim = 0; iDim < nDim; iDim++) + r[iDim] = (Coord[iDim]-Center[iDim])/Lref; - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2] + Center[2]; + /*--- Compute transformed point coordinates ---*/ - /*--- Calculate delta change in the x, y, & z directions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = (rotCoord[iDim]-Coord[iDim])/Lref; - if (nDim == 2) VarCoord[nDim] = 0.0; + Rotate(rotMatrix, r, Center, rotCoord); - // /*--- Set node displacement for volume deformation ---*/ - // geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + /*--- Calculate delta change in the x, y, & z directions ---*/ + for (iDim = 0; iDim < nDim; iDim++) + VarCoord[iDim] = (rotCoord[iDim]-Coord[iDim])/Lref; - for (iDim = 0; iDim < 3; iDim++){ - VarCoordAbs[iDim] = nodes->GetBound_Disp(iPoint, iDim) + VarCoord[iDim]; - } + /*--- Set node displacement for volume deformation ---*/ + for (iDim = 0; iDim < nDim; iDim++) + VarCoordAbs[iDim] = nodes->GetBound_Disp(iPoint, iDim) + VarCoord[iDim]; - nodes->SetBound_Disp(iPoint, VarCoordAbs); - } - } + nodes->SetBound_Disp(iPoint, VarCoordAbs); } } } @@ -1173,46 +1152,32 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, unsigne incrementing the position with the rotation. This new location will be used for subsequent mesh motion for the given marker.---*/ - for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { + for (jMarker=0; jMarker < config->GetnMarker_Moving(); jMarker++) { /*-- Check if we want to update the motion origin for the given marker ---*/ - if (config->GetMoveMotion_Origin(jMarker) == YES) { - - for (iDim = 0; iDim < 3; iDim++){ - Center_Aux[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); - } + if (config->GetMoveMotion_Origin(jMarker) != YES) continue; - /*--- Calculate non-dim. position from rotation center ---*/ + for (iDim = 0; iDim < 3; iDim++) + Center_Aux[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); - for (iDim = 0; iDim < nDim; iDim++) - r[iDim] = (Center_Aux[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; + /*--- Calculate non-dim. position from rotation center ---*/ - /*--- Compute transformed point coordinates ---*/ + for (iDim = 0; iDim < nDim; iDim++) + r[iDim] = (Center_Aux[iDim]-Center[iDim])/Lref; - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2] + Center[0]; + /*--- Compute transformed point coordinates ---*/ - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2] + Center[1]; + Rotate(rotMatrix, r, Center, rotCoord); - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2] + Center[2]; + /*--- Calculate delta change in the x, y, & z directions ---*/ + for (iDim = 0; iDim < nDim; iDim++) + VarCoord[iDim] = (rotCoord[iDim]-Center_Aux[iDim])/Lref; - /*--- Calculate delta change in the x, y, & z directions ---*/ - for (iDim = 0; iDim < nDim; iDim++) - VarCoord[iDim] = (rotCoord[iDim]-Center_Aux[iDim])/Lref; - if (nDim == 2) VarCoord[nDim] = 0.0; + for (iDim = 0; iDim < 3; iDim++) + Center_Aux[iDim] += VarCoord[iDim]; - for (iDim = 0; iDim < 3; iDim++){ - Center_Aux[iDim] += VarCoord[iDim]; - } - config->SetMarkerMotion_Origin(Center_Aux, jMarker); - } + config->SetMarkerMotion_Origin(Center_Aux, jMarker); } /*--- Set the moment computation center to the new location after @@ -1228,26 +1193,14 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, unsigne for (iDim = 0; iDim < nDim; iDim++) r[iDim] = (Center_Aux[iDim]-Center[iDim])/Lref; - if (nDim == 2) r[nDim] = 0.0; /*--- Compute transformed point coordinates ---*/ - rotCoord[0] = rotMatrix[0][0]*r[0] - + rotMatrix[0][1]*r[1] - + rotMatrix[0][2]*r[2] + Center[0]; - - rotCoord[1] = rotMatrix[1][0]*r[0] - + rotMatrix[1][1]*r[1] - + rotMatrix[1][2]*r[2] + Center[1]; - - rotCoord[2] = rotMatrix[2][0]*r[0] - + rotMatrix[2][1]*r[1] - + rotMatrix[2][2]*r[2] + Center[2]; + Rotate(rotMatrix, r, Center, rotCoord); /*--- Calculate delta change in the x, y, & z directions ---*/ for (iDim = 0; iDim < nDim; iDim++) VarCoord[iDim] = (rotCoord[iDim]-Center_Aux[iDim])/Lref; - if (nDim == 2) VarCoord[nDim] = 0.0; config->SetRefOriginMoment_X(jMarker, Center_Aux[0]+VarCoord[0]); config->SetRefOriginMoment_Y(jMarker, Center_Aux[1]+VarCoord[1]); @@ -1258,87 +1211,82 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, unsigne void CMeshSolver::Surface_Plunging(CGeometry *geometry, CConfig *config, unsigned long iter) { su2double deltaT, time_new, time_old, Lref; - su2double Center[3] = {0.0, 0.0, 0.0}, VarCoord[3], Omega[3], Ampl[3]; - su2double VarCoordAbs[3] = {0.0, 0.0, 0.0}; - su2double DEG2RAD = PI_NUMBER/180.0; - unsigned short iMarker, jMarker, Moving; + su2double Center[3] = {0.0}, VarCoord[3] = {0.0}, Omega[3] = {0.0}, Ampl[3] = {0.0}; + su2double VarCoordAbs[3] = {0.0}; + const su2double DEG2RAD = PI_NUMBER/180.0; + unsigned short iMarker, jMarker; unsigned long iPoint, iVertex; string Marker_Tag, Moving_Tag; unsigned short iDim; - /*--- Initialize the delta variation in coordinates ---*/ - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - /*--- Retrieve values from the config file ---*/ deltaT = config->GetDelta_UnstTimeND(); Lref = config->GetLength_Ref(); /*--- Compute delta time based on physical time step ---*/ - time_new = static_cast(iter)*deltaT; - if (iter == 0) { - time_old = time_new; - } else { - time_old = static_cast(iter-1)*deltaT; - } + + time_new = iter*deltaT; + if (iter == 0) time_old = time_new; + else time_old = (iter-1)*deltaT; /*--- Store displacement of each node on the plunging surface ---*/ - /*--- Loop over markers and find the particular marker(s) (surface) to plunge ---*/ + /*--- Loop over markers and find the particular marker(s) (surface) to plunge ---*/ for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Moving = config->GetMarker_All_Moving(iMarker); - if (Moving == YES) { - for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { + if (config->GetMarker_All_Moving(iMarker) != YES) continue; - Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); + Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if (Marker_Tag == Moving_Tag && (config->GetKind_SurfaceMovement(jMarker) == DEFORMING)) { + for (jMarker = 0; jMarker < config->GetnMarker_Moving(); jMarker++) { - /*--- Plunging frequency and amplitude from config. ---*/ + Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); - for (iDim = 0; iDim < 3; iDim++){ - Ampl[iDim] = config->GetMarkerPlunging_Ampl(jMarker, iDim)/Lref; - Omega[iDim] = config->GetMarkerPlunging_Omega(jMarker, iDim)/config->GetOmega_Ref(); - Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); - } - /*--- Print some information to the console. Be verbose at the first - iteration only (mostly for debugging purposes). ---*/ - // Note that the MASTER_NODE might not contain all the markers being moved. - - if (rank == MASTER_NODE) { - cout << " Storing plunging displacement for marker: "; - cout << Marker_Tag << "." << endl; - if (iter == 0) { - cout << " Plunging frequency: (" << Omega[0] << ", " << Omega[1]; - cout << ", " << Omega[2] << ") rad/s." << endl; - cout << " Plunging amplitude: (" << Ampl[0]/DEG2RAD; - cout << ", " << Ampl[1]/DEG2RAD << ", " << Ampl[2]/DEG2RAD; - cout << ") degrees."<< endl; - } - } + if ((Marker_Tag != Moving_Tag) || (config->GetKind_SurfaceMovement(jMarker) != DEFORMING)) { + continue; + } - /*--- Compute delta change in the position in the x, y, & z directions. ---*/ + /*--- Plunging frequency and amplitude from config. ---*/ - VarCoord[0] = -Ampl[0]*(sin(Omega[0]*time_new) - sin(Omega[0]*time_old)); - VarCoord[1] = -Ampl[1]*(sin(Omega[1]*time_new) - sin(Omega[1]*time_old)); - VarCoord[2] = -Ampl[2]*(sin(Omega[2]*time_new) - sin(Omega[2]*time_old)); + for (iDim = 0; iDim < 3; iDim++){ + Ampl[iDim] = config->GetMarkerPlunging_Ampl(jMarker, iDim)/Lref; + Omega[iDim] = config->GetMarkerPlunging_Omega(jMarker, iDim)/config->GetOmega_Ref(); + Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); + } - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + /*--- Print some information to the console. Be verbose at the first + iteration only (mostly for debugging purposes). ---*/ + // Note that the MASTER_NODE might not contain all the markers being moved. + + if (rank == MASTER_NODE) { + cout << " Storing plunging displacement for marker: "; + cout << Marker_Tag << "." << endl; + if (iter == 0) { + cout << " Plunging frequency: (" << Omega[0] << ", " << Omega[1]; + cout << ", " << Omega[2] << ") rad/s." << endl; + cout << " Plunging amplitude: (" << Ampl[0]/DEG2RAD; + cout << ", " << Ampl[1]/DEG2RAD << ", " << Ampl[2]/DEG2RAD; + cout << ") degrees."<< endl; + } + } - // /*--- Set node displacement for volume deformation ---*/ - // geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + /*--- Compute delta change in the position in the x, y, & z directions. ---*/ - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + VarCoord[0] = -Ampl[0]*(sin(Omega[0]*time_new) - sin(Omega[0]*time_old)); + VarCoord[1] = -Ampl[1]*(sin(Omega[1]*time_new) - sin(Omega[1]*time_old)); + VarCoord[2] = -Ampl[2]*(sin(Omega[2]*time_new) - sin(Omega[2]*time_old)); - for (iDim = 0; iDim < 3; iDim++){ - VarCoordAbs[iDim] = nodes->GetBound_Disp(iPoint, iDim) + VarCoord[iDim]; - } + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - nodes->SetBound_Disp(iPoint, VarCoordAbs); + /*--- Set node displacement for volume deformation ---*/ + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + for (iDim = 0; iDim < nDim; iDim++) + VarCoordAbs[iDim] = nodes->GetBound_Disp(iPoint, iDim) + VarCoord[iDim]; + + nodes->SetBound_Disp(iPoint, VarCoordAbs); - } - } } } } @@ -1355,9 +1303,9 @@ void CMeshSolver::Surface_Plunging(CGeometry *geometry, CConfig *config, unsigne /*-- Check if we want to update the motion origin for the given marker ---*/ if (config->GetMoveMotion_Origin(jMarker) == YES) { - for (iDim = 0; iDim < 3; iDim++){ + for (iDim = 0; iDim < 3; iDim++) Center[iDim] += VarCoord[iDim]; - } + config->SetMarkerMotion_Origin(Center, jMarker); } } @@ -1365,7 +1313,7 @@ void CMeshSolver::Surface_Plunging(CGeometry *geometry, CConfig *config, unsigne /*--- Set the moment computation center to the new location after incrementing the position with the plunging. ---*/ - for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { + for (jMarker=0; jMarker < config->GetnMarker_Monitoring(); jMarker++) { Center[0] = config->GetRefOriginMoment_X(jMarker) + VarCoord[0]; Center[1] = config->GetRefOriginMoment_Y(jMarker) + VarCoord[1]; Center[2] = config->GetRefOriginMoment_Z(jMarker) + VarCoord[2]; @@ -1378,82 +1326,76 @@ void CMeshSolver::Surface_Plunging(CGeometry *geometry, CConfig *config, unsigne void CMeshSolver::Surface_Translating(CGeometry *geometry, CConfig *config, unsigned long iter) { su2double deltaT, time_new, time_old; - su2double Center[3] = {0.0,0.0,0.0}, VarCoord[3] = {0.0,0.0,0.0}; - su2double VarCoordAbs[3] = {0.0, 0.0, 0.0}; - su2double xDot[3] = {0.0,0.0,0.0}; - unsigned short iMarker, jMarker, Moving; + su2double Center[3] = {0.0}, VarCoord[3] = {0.0}; + su2double VarCoordAbs[3] = {0.0}; + su2double xDot[3] = {0.0}; + unsigned short iMarker, jMarker; unsigned long iPoint, iVertex; string Marker_Tag, Moving_Tag; unsigned short iDim; - /*--- Initialize the delta variation in coordinates ---*/ - VarCoord[0] = 0.0; VarCoord[1] = 0.0; VarCoord[2] = 0.0; - /*--- Retrieve values from the config file ---*/ deltaT = config->GetDelta_UnstTimeND(); /*--- Compute delta time based on physical time step ---*/ - time_new = static_cast(iter)*deltaT; - if (iter == 0) { - time_old = time_new; - } else { - time_old = static_cast(iter-1)*deltaT; - } + + time_new = iter*deltaT; + if (iter == 0) time_old = time_new; + else time_old = (iter-1)*deltaT; /*--- Store displacement of each node on the translating surface ---*/ - /*--- Loop over markers and find the particular marker(s) (surface) to translate ---*/ + /*--- Loop over markers and find the particular marker(s) (surface) to translate ---*/ for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - Moving = config->GetMarker_All_Moving(iMarker); - if (Moving == YES) { - for (jMarker = 0; jMarkerGetnMarker_Moving(); jMarker++) { + if (config->GetMarker_All_Moving(iMarker) != YES) continue; - Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); + Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if (Marker_Tag == Moving_Tag && (config->GetKind_SurfaceMovement(jMarker) == DEFORMING)) { + for (jMarker = 0; jMarker < config->GetnMarker_Moving(); jMarker++) { - for (iDim = 0; iDim < 3; iDim++){ - xDot[iDim] = config->GetMarkerTranslationRate(jMarker, iDim); - Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); - } + Moving_Tag = config->GetMarker_Moving_TagBound(jMarker); - /*--- Print some information to the console. Be verbose at the first - iteration only (mostly for debugging purposes). ---*/ - // Note that the MASTER_NODE might not contain all the markers being moved. - - if (rank == MASTER_NODE) { - cout << " Storing translating displacement for marker: "; - cout << Marker_Tag << "." << endl; - if (iter == 0) { - cout << " Translational velocity: (" << xDot[0]*config->GetVelocity_Ref() << ", " << xDot[1]*config->GetVelocity_Ref(); - cout << ", " << xDot[2]*config->GetVelocity_Ref(); - if (config->GetSystemMeasurements() == SI) cout << ") m/s." << endl; - else cout << ") ft/s." << endl; - } - } + if ((Marker_Tag != Moving_Tag) || (config->GetKind_SurfaceMovement(jMarker) != DEFORMING)) { + continue; + } - /*--- Compute delta change in the position in the x, y, & z directions. ---*/ + for (iDim = 0; iDim < 3; iDim++) { + xDot[iDim] = config->GetMarkerTranslationRate(jMarker, iDim); + Center[iDim] = config->GetMarkerMotion_Origin(jMarker, iDim); + } - VarCoord[0] = xDot[0]*(time_new-time_old); - VarCoord[1] = xDot[1]*(time_new-time_old); - VarCoord[2] = xDot[2]*(time_new-time_old); + /*--- Print some information to the console. Be verbose at the first + iteration only (mostly for debugging purposes). ---*/ + // Note that the MASTER_NODE might not contain all the markers being moved. + + if (rank == MASTER_NODE) { + cout << " Storing translating displacement for marker: "; + cout << Marker_Tag << "." << endl; + if (iter == 0) { + cout << " Translational velocity: (" << xDot[0]*config->GetVelocity_Ref() << ", " << xDot[1]*config->GetVelocity_Ref(); + cout << ", " << xDot[2]*config->GetVelocity_Ref(); + if (config->GetSystemMeasurements() == SI) cout << ") m/s." << endl; + else cout << ") ft/s." << endl; + } + } - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + /*--- Compute delta change in the position in the x, y, & z directions. ---*/ - // /*--- Set node displacement for volume deformation ---*/ - // geometry->vertex[iMarker][iVertex]->SetVarCoord(VarCoord); + VarCoord[0] = xDot[0]*(time_new-time_old); + VarCoord[1] = xDot[1]*(time_new-time_old); + VarCoord[2] = xDot[2]*(time_new-time_old); - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - for (iDim = 0; iDim < 3; iDim++){ - VarCoordAbs[iDim] = nodes->GetBound_Disp(iPoint, iDim) + VarCoord[iDim]; - } + /*--- Set node displacement for volume deformation ---*/ - nodes->SetBound_Disp(iPoint, VarCoordAbs); - } - } + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + for (iDim = 0; iDim < nDim; iDim++) + VarCoordAbs[iDim] = nodes->GetBound_Disp(iPoint, iDim) + VarCoord[iDim]; + + nodes->SetBound_Disp(iPoint, VarCoordAbs); } } } @@ -1465,7 +1407,7 @@ void CMeshSolver::Surface_Translating(CGeometry *geometry, CConfig *config, unsi incrementing the position with the translation. This new location will be used for subsequent mesh motion for the given marker.---*/ - for (jMarker=0; jMarkerGetnMarker_Moving(); jMarker++) { + for (jMarker=0; jMarker < config->GetnMarker_Moving(); jMarker++) { /*-- Check if we want to update the motion origin for the given marker ---*/ @@ -1480,7 +1422,7 @@ void CMeshSolver::Surface_Translating(CGeometry *geometry, CConfig *config, unsi /*--- Set the moment computation center to the new location after incrementing the position with the translation. ---*/ - for (jMarker=0; jMarkerGetnMarker_Monitoring(); jMarker++) { + for (jMarker=0; jMarker < config->GetnMarker_Monitoring(); jMarker++) { Center[0] = config->GetRefOriginMoment_X(jMarker) + VarCoord[0]; Center[1] = config->GetRefOriginMoment_Y(jMarker) + VarCoord[1]; Center[2] = config->GetRefOriginMoment_Z(jMarker) + VarCoord[2]; From 60564a74185fc8bea8707efd6fbffa5222ce0804 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 4 Apr 2020 11:57:34 +0100 Subject: [PATCH 66/79] update RBF case residuals after changes in point ordering from #914 --- TestCases/disc_adj_fsi/configFlow.cfg | 1 + TestCases/serial_regression.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/TestCases/disc_adj_fsi/configFlow.cfg b/TestCases/disc_adj_fsi/configFlow.cfg index c17aae1a9013..c05d1b748ee1 100644 --- a/TestCases/disc_adj_fsi/configFlow.cfg +++ b/TestCases/disc_adj_fsi/configFlow.cfg @@ -55,6 +55,7 @@ WRT_SOL_FREQ= 1 WRT_SOL_FREQ_DUALTIME= 5 DEFORM_STIFFNESS_TYPE = INVERSE_VOLUME +DEFORM_POISSONS_RATIO = 1e6 DEFORM_LINEAR_SOLVER = CONJUGATE_GRADIENT DEFORM_LINEAR_SOLVER_PREC = ILU DEFORM_LINEAR_SOLVER_ERROR = 1E-8 diff --git a/TestCases/serial_regression.py b/TestCases/serial_regression.py index 7be3b4f49ae3..9310dcf4f621 100644 --- a/TestCases/serial_regression.py +++ b/TestCases/serial_regression.py @@ -1280,7 +1280,7 @@ def main(): airfoilRBF.cfg_dir = "fea_fsi/Airfoil_RBF" airfoilRBF.cfg_file = "config.cfg" airfoilRBF.test_iter = 1 - airfoilRBF.test_vals = [1.000000, -2.989055, -4.895265] + airfoilRBF.test_vals = [1.000000, -2.791154, -4.961536] airfoilRBF.su2_exec = "SU2_CFD" airfoilRBF.timeout = 1600 airfoilRBF.multizone = True From 5fab28cbe2ea2f81d080980756da05df1542a2cf Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 4 Apr 2020 16:13:33 +0100 Subject: [PATCH 67/79] cleanup --- .../src/drivers/CDiscAdjMultizoneDriver.cpp | 81 +++++++------------ .../disc_adj_fsi/Airfoil_2d/configFlow.cfg | 1 + TestCases/parallel_regression_AD.py | 2 +- 3 files changed, 29 insertions(+), 55 deletions(-) diff --git a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp index f1c5395de08b..f8a89a6bace0 100644 --- a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -288,7 +288,7 @@ void CDiscAdjMultizoneDriver::Run() { for (unsigned short jZone = 0; jZone < nZone; jZone++) { - if (jZone != iZone && interface_container[jZone][iZone] != NULL) { + if (jZone != iZone && interface_container[jZone][iZone] != nullptr) { /*--- Extracting adjoints for solvers in jZone w.r.t. to the output of all solvers in iZone, * that is, for the cases iZone != jZone we are evaluating cross derivatives between zones. ---*/ @@ -424,11 +424,8 @@ void CDiscAdjMultizoneDriver::SetRecording(unsigned short kind_recording, Kind_T for(iZone = 0; iZone < nZone; iZone++) { for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; - if (solver != NULL) { - if (solver->GetAdjoint()) { - solver->SetRecording(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); - } - } + if (solver && solver->GetAdjoint()) + solver->SetRecording(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); } } @@ -792,12 +789,12 @@ void CDiscAdjMultizoneDriver::SetAdj_ObjFunction() { unsigned long IterAvg_Obj = config_container[ZONE_0]->GetIter_Avg_Objective(); su2double seeding = 1.0; - CWindowingTools windowEvaluator = CWindowingTools(); - if (time_stepping){ if (TimeIter < IterAvg_Obj){ // Default behavior (in case no specific window is chosen) is to use Square-Windowing, i.e. the numerator equals 1.0 - seeding = windowEvaluator.GetWndWeight(config_container[ZONE_0]->GetKindWindow(),TimeIter, IterAvg_Obj-1)/ (static_cast(IterAvg_Obj)); + auto windowEvaluator = CWindowingTools(); + su2double weight = windowEvaluator.GetWndWeight(config_container[ZONE_0]->GetKindWindow(), TimeIter, IterAvg_Obj-1); + seeding = weight / IterAvg_Obj; } else{ seeding = 0.0; @@ -844,7 +841,7 @@ void CDiscAdjMultizoneDriver::InitializeCrossTerms() { for(unsigned short iZone = 0; iZone < nZone; iZone++) { for (unsigned short jZone = 0; jZone < nZone; jZone++) { - if (iZone != jZone || interface_container[jZone][iZone] != NULL) { + if (iZone != jZone || interface_container[jZone][iZone] != nullptr) { /*--- If jZone contributes to iZone in the primal problem, then * iZone contributes to jZone in the adjoint problem. ---*/ @@ -853,12 +850,10 @@ void CDiscAdjMultizoneDriver::InitializeCrossTerms() { for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { CSolver* solver = solver_container[jZone][INST_0][MESH_0][iSol]; - if (solver != NULL) { - if (solver->GetAdjoint()) { - unsigned long nPoint = geometry_container[jZone][INST_0][MESH_0]->GetnPoint(); - unsigned short nVar = solver->GetnVar(); - Cross_Terms[iZone][jZone][iSol].resize(nPoint,nVar) = 0.0; - } + if (solver && solver->GetAdjoint()) { + unsigned long nPoint = geometry_container[jZone][INST_0][MESH_0]->GetnPoint(); + unsigned short nVar = solver->GetnVar(); + Cross_Terms[iZone][jZone][iSol].resize(nPoint,nVar) = 0.0; } } } @@ -878,7 +873,7 @@ void CDiscAdjMultizoneDriver::HandleDataTransfer() { /*--- Transfer from all the remaining zones ---*/ for (unsigned short jZone = 0; jZone < nZone; jZone++){ /*--- The target zone is iZone ---*/ - if (jZone != iZone && interface_container[iZone][jZone] != NULL) { + if (jZone != iZone && interface_container[iZone][jZone] != nullptr) { DeformMesh = DeformMesh || Transfer_Data(jZone, iZone); } } @@ -893,11 +888,8 @@ void CDiscAdjMultizoneDriver::Add_Solution_To_External(unsigned short iZone) { for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; - if (solver != nullptr) { - if (solver->GetAdjoint()) { - solver->Add_Solution_To_External(); - } - } + if (solver && solver->GetAdjoint()) + solver->Add_Solution_To_External(); } } @@ -905,11 +897,8 @@ void CDiscAdjMultizoneDriver::Add_External_To_Solution(unsigned short iZone) { for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; - if (solver != nullptr) { - if (solver->GetAdjoint()) { - solver->Add_External_To_Solution(); - } - } + if (solver && solver->GetAdjoint()) + solver->Add_External_To_Solution(); } } @@ -917,11 +906,8 @@ void CDiscAdjMultizoneDriver::Update_Cross_Term(unsigned short iZone, unsigned s for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { auto solver = solver_container[jZone][INST_0][MESH_0][iSol]; - if (solver != nullptr) { - if (solver->GetAdjoint()) { - solver->Update_Cross_Term(config_container[jZone], Cross_Terms[iZone][jZone][iSol]); - } - } + if (solver && solver->GetAdjoint()) + solver->Update_Cross_Term(config_container[jZone], Cross_Terms[iZone][jZone][iSol]); } } @@ -929,11 +915,8 @@ void CDiscAdjMultizoneDriver::Set_BGSSolution(unsigned short iZone) { for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; - if (solver != nullptr) { - if (solver->GetAdjoint()) { - solver->UpdateSolution_BGS(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); - } - } + if (solver && solver->GetAdjoint()) + solver->UpdateSolution_BGS(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); } } @@ -941,11 +924,8 @@ void CDiscAdjMultizoneDriver::Set_Solution_To_BGSSolution_k(unsigned short iZone for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; - if (solver != nullptr) { - if (solver->GetAdjoint()) { - solver->GetNodes()->Restore_BGSSolution_k(); - } - } + if (solver && solver->GetAdjoint()) + solver->GetNodes()->Restore_BGSSolution_k(); } } @@ -953,11 +933,8 @@ void CDiscAdjMultizoneDriver::Set_BGSSolution_k_To_Solution(unsigned short iZone for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; - if (solver != nullptr) { - if (solver->GetAdjoint()) { - solver->GetNodes()->Set_BGSSolution_k(); - } - } + if (solver && solver->GetAdjoint()) + solver->GetNodes()->Set_BGSSolution_k(); } } @@ -965,11 +942,7 @@ void CDiscAdjMultizoneDriver::SetResidual_BGS(unsigned short iZone) { for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; - if (solver != nullptr) { - if (solver->GetAdjoint()) { - solver->ComputeResidual_Multizone(geometry_container[iZone][INST_0][MESH_0], - config_container[iZone]); - } - } + if (solver && solver->GetAdjoint()) + solver->ComputeResidual_Multizone(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); } } diff --git a/TestCases/disc_adj_fsi/Airfoil_2d/configFlow.cfg b/TestCases/disc_adj_fsi/Airfoil_2d/configFlow.cfg index 917ebb6ec744..50d96b094de1 100755 --- a/TestCases/disc_adj_fsi/Airfoil_2d/configFlow.cfg +++ b/TestCases/disc_adj_fsi/Airfoil_2d/configFlow.cfg @@ -87,6 +87,7 @@ CONV_STARTITER= 0 CONV_RESIDUAL_MINVAL= -9 % grid deformation DEFORM_STIFFNESS_TYPE= INVERSE_VOLUME +DEFORM_POISSONS_RATIO= 1e6 % % In\Out --------------------------------------------------------------- % MESH_FILENAME= mesh.su2 diff --git a/TestCases/parallel_regression_AD.py b/TestCases/parallel_regression_AD.py index e5fda45fd69a..830e45ad5ee0 100644 --- a/TestCases/parallel_regression_AD.py +++ b/TestCases/parallel_regression_AD.py @@ -302,7 +302,7 @@ def main(): discadj_fsi2.cfg_dir = "disc_adj_fsi/Airfoil_2d" discadj_fsi2.cfg_file = "config.cfg" discadj_fsi2.test_iter = 8 - discadj_fsi2.test_vals = [-5.071003, -2.5250e-13] #last 2 columns + discadj_fsi2.test_vals = [-5.071100, -2.5237e-13] #last 2 columns discadj_fsi2.su2_exec = "mpirun -n 2 SU2_CFD_AD" discadj_fsi2.timeout = 1600 discadj_fsi2.tol = 1e-16 From e7e2d3053d66d5560d62d0178f17c1716d6d021f Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 4 Apr 2020 18:12:11 +0100 Subject: [PATCH 68/79] remove obsolete BGSSolution and duplication of ComputeResidualMultizone --- .../drivers/CDiscAdjMultizoneDriver.hpp | 8 +--- SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp | 7 ---- .../include/solvers/CDiscAdjMeshSolver.hpp | 6 --- SU2_CFD/include/solvers/CDiscAdjSolver.hpp | 7 ---- SU2_CFD/include/solvers/CSolver.hpp | 7 +--- .../include/variables/CDiscAdjFEAVariable.hpp | 15 +------ .../variables/CDiscAdjMeshBoundVariable.hpp | 26 ++++++++++-- .../include/variables/CDiscAdjVariable.hpp | 16 +------- SU2_CFD/include/variables/CVariable.hpp | 24 +++++------ .../src/drivers/CDiscAdjMultizoneDriver.cpp | 15 +------ SU2_CFD/src/drivers/CMultizoneDriver.cpp | 40 ++++++++----------- SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp | 29 -------------- SU2_CFD/src/solvers/CDiscAdjMeshSolver.cpp | 33 --------------- SU2_CFD/src/solvers/CDiscAdjSolver.cpp | 34 +--------------- SU2_CFD/src/solvers/CSolver.cpp | 25 +++++------- SU2_CFD/src/variables/CDiscAdjFEAVariable.cpp | 10 +---- .../variables/CDiscAdjMeshBoundVariable.cpp | 14 +++++-- SU2_CFD/src/variables/CDiscAdjVariable.cpp | 6 +-- TestCases/parallel_regression_AD.py | 2 +- 19 files changed, 84 insertions(+), 240 deletions(-) diff --git a/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp b/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp index 4e6126c93c64..1041ad8941a7 100644 --- a/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp +++ b/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -187,12 +187,6 @@ class CDiscAdjMultizoneDriver : public CMultizoneDriver { */ void Update_Cross_Term(unsigned short iZone, unsigned short jZone); - /*! - * \brief Saves the current (adjoint) Solution vector to Solution_BGS_k. - * \param[in] iZone - Zone index. - */ - void Set_BGSSolution(unsigned short iZone); - /*! * \brief Compute BGS residuals. * \param[in] iZone - Zone where solver residuals are computed. diff --git a/SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp b/SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp index 7994f595f23c..4e0919a696bc 100644 --- a/SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp +++ b/SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp @@ -370,11 +370,4 @@ class CDiscAdjFEASolver final : public CSolver { int val_iter, bool val_update_geo) override; - /*! - * \brief Compute the multizone residual. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual_Multizone(CGeometry *geometry, CConfig *config) override; - }; diff --git a/SU2_CFD/include/solvers/CDiscAdjMeshSolver.hpp b/SU2_CFD/include/solvers/CDiscAdjMeshSolver.hpp index 3a3b2ce6a72d..f128389ea832 100644 --- a/SU2_CFD/include/solvers/CDiscAdjMeshSolver.hpp +++ b/SU2_CFD/include/solvers/CDiscAdjMeshSolver.hpp @@ -102,12 +102,6 @@ class CDiscAdjMeshSolver final : public CSolver { */ void SetSensitivity(CGeometry *geometry, CSolver **solver, CConfig *config) override; - /*! - * \brief Set the value of the max residual and RMS residual. - * \param[in] val_iterlinsolver - Number of linear iterations. - */ - void ComputeResidual_Multizone(CGeometry *geometry, CConfig *config) override; - /*! * \brief Prepare the solver for a new recording. * \param[in] kind_recording - Kind of AD recording. diff --git a/SU2_CFD/include/solvers/CDiscAdjSolver.hpp b/SU2_CFD/include/solvers/CDiscAdjSolver.hpp index c7833232f567..f654c2637356 100644 --- a/SU2_CFD/include/solvers/CDiscAdjSolver.hpp +++ b/SU2_CFD/include/solvers/CDiscAdjSolver.hpp @@ -297,11 +297,4 @@ class CDiscAdjSolver final : public CSolver { int val_iter, bool val_update_geo) override; - /*! - * \brief Compute the multizone residual. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void ComputeResidual_Multizone(CGeometry *geometry, CConfig *config) override; - }; diff --git a/SU2_CFD/include/solvers/CSolver.hpp b/SU2_CFD/include/solvers/CSolver.hpp index 1f76ab2fd4c0..d2bf6e363e6a 100644 --- a/SU2_CFD/include/solvers/CSolver.hpp +++ b/SU2_CFD/include/solvers/CSolver.hpp @@ -272,18 +272,13 @@ class CSolver { * \brief Set the value of the max residual and RMS residual. * \param[in] val_iterlinsolver - Number of linear iterations. */ - virtual void ComputeResidual_Multizone(CGeometry *geometry, CConfig *config); + void ComputeResidual_Multizone(CGeometry *geometry, CConfig *config); /*! * \brief Move the mesh in time */ inline virtual void SetDualTime_Mesh(void){ } - /*! - * \brief Store the BGS solution in the previous subiteration in the corresponding vector. - */ - void UpdateSolution_BGS(CGeometry *geometry, CConfig *config); - /*! * \brief Set the solver nondimensionalization. * \param[in] config - Definition of the particular problem. diff --git a/SU2_CFD/include/variables/CDiscAdjFEAVariable.hpp b/SU2_CFD/include/variables/CDiscAdjFEAVariable.hpp index ba74d096ad5b..5e0f9fa8aef1 100644 --- a/SU2_CFD/include/variables/CDiscAdjFEAVariable.hpp +++ b/SU2_CFD/include/variables/CDiscAdjFEAVariable.hpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -60,8 +60,6 @@ class CDiscAdjFEAVariable : public CVariable { MatrixType Solution_Direct_Vel; MatrixType Solution_Direct_Accel; - MatrixType Solution_BGS; - /*! * \brief Constructor of the class. * \param[in] disp - Pointer to the adjoint value (initialization value). @@ -237,15 +235,4 @@ class CDiscAdjFEAVariable : public CVariable { */ void Set_OldSolution_Vel() final; - /*! - * \brief Set the value of the adjoint solution in the current BGS subiteration. - */ - inline void Set_BGSSolution(unsigned long iPoint, unsigned long iDim, su2double val_solution) final { Solution_BGS(iPoint,iDim) = val_solution; } - - /*! - * \brief Get the value of the adjoint solution in the previous BGS subiteration. - * \param[out] val_solution - adjoint solution in the previous BGS subiteration. - */ - inline su2double Get_BGSSolution(unsigned long iPoint, unsigned long iDim) const final { return Solution_BGS(iPoint,iDim); } - }; diff --git a/SU2_CFD/include/variables/CDiscAdjMeshBoundVariable.hpp b/SU2_CFD/include/variables/CDiscAdjMeshBoundVariable.hpp index 47b38adfac67..4eaeb801f413 100644 --- a/SU2_CFD/include/variables/CDiscAdjMeshBoundVariable.hpp +++ b/SU2_CFD/include/variables/CDiscAdjMeshBoundVariable.hpp @@ -7,7 +7,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -37,8 +37,6 @@ class CDiscAdjMeshBoundVariable final : public CVariable { MatrixType Bound_Disp_Sens; /*!< \brief Store the reference coordinates of the mesh. */ MatrixType Bound_Disp_Direct; /*!< \brief Store the reference boundary displacements of the mesh. */ - MatrixType Solution_BGS_k; /*!< \brief BGS solution to compute overall convergence. */ - CVertexMap VertexMap; /*!< \brief Object that controls accesses to the variables of this class. */ public: @@ -115,11 +113,24 @@ class CDiscAdjMeshBoundVariable final : public CVariable { VertexMap.SetIsVertex(iPoint,isVertex); } + /*! + * \brief Get the value of the BGS solution. + */ + inline su2double Get_BGSSolution(unsigned long iPoint, unsigned long iDim) const override { + if (!VertexMap.GetVertexIndex(iPoint)) return 0.0; + return Bound_Disp_Sens(iPoint,iDim); + } + /*! * \brief Set the value of the solution in the previous BGS subiteration. */ void Set_BGSSolution_k() override; + /*! + * \brief Restore the previous BGS subiteration to solution. + */ + void Restore_BGSSolution_k() override; + /*! * \brief Get the value of the solution in the previous BGS subiteration. * \param[out] val_solution - solution in the previous BGS subiteration. @@ -129,4 +140,13 @@ class CDiscAdjMeshBoundVariable final : public CVariable { return Solution_BGS_k(iPoint,iDim); } + /*! + * \brief Get the value of the solution in the previous BGS subiteration. + * \param[out] val_solution - solution in the previous BGS subiteration. + */ + inline void Set_BGSSolution_k(unsigned long iPoint, unsigned long iDim, su2double val) override { + if (!VertexMap.GetVertexIndex(iPoint)) return; + Solution_BGS_k(iPoint,iDim) = val; + } + }; diff --git a/SU2_CFD/include/variables/CDiscAdjVariable.hpp b/SU2_CFD/include/variables/CDiscAdjVariable.hpp index 1fb23601bd22..b0526199f38e 100644 --- a/SU2_CFD/include/variables/CDiscAdjVariable.hpp +++ b/SU2_CFD/include/variables/CDiscAdjVariable.hpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -46,7 +46,6 @@ class CDiscAdjVariable final : public CVariable { MatrixType Solution_Geometry_Old; MatrixType Geometry_Direct; - MatrixType Solution_BGS; MatrixType Solution_Geometry_BGS_k; public: @@ -152,17 +151,4 @@ class CDiscAdjVariable final : public CVariable { return Solution_Geometry_Old(iPoint,iDim); } - /*! - * \brief Set the value of the adjoint solution in the current BGS subiteration. - */ - inline void Set_BGSSolution(unsigned long iPoint, unsigned long iDim, su2double val_solution) override { - Solution_BGS(iPoint,iDim) = val_solution; - } - - /*! - * \brief Get the value of the adjoint solution in the previous BGS subiteration. - * \param[out] val_solution - adjoint solution in the previous BGS subiteration. - */ - inline su2double Get_BGSSolution(unsigned long iPoint, unsigned long iDim) const override { return Solution_BGS(iPoint,iDim);} - }; diff --git a/SU2_CFD/include/variables/CVariable.hpp b/SU2_CFD/include/variables/CVariable.hpp index 1f32f41e054d..5f4850025498 100644 --- a/SU2_CFD/include/variables/CVariable.hpp +++ b/SU2_CFD/include/variables/CVariable.hpp @@ -129,10 +129,10 @@ class CVariable { unsigned long nSecondaryVar = 0; /*!< \brief Number of secondary variables. */ unsigned long nSecondaryVarGrad = 0; /*!< \brief Number of secondaries for which a gradient is computed. */ + /*--- Only allow default construction by derived classes. ---*/ + CVariable() = default; public: - - /*--- Disable default construction copy and assignment. ---*/ - CVariable() = delete; + /*--- Disable copy and assignment. ---*/ CVariable(const CVariable&) = delete; CVariable(CVariable&&) = delete; CVariable& operator= (const CVariable&) = delete; @@ -2110,9 +2110,13 @@ class CVariable { inline virtual su2double Get_OldSolution_Geometry(unsigned long iPoint, unsigned long iDim) const { return 0.0; } /*! - * \brief A virtual member. Set the value of the old geometry solution (adjoint). + * \brief Get BGS solution to compute the BGS residual (difference between BGS and BGS_k). + * \note This is virtual because for some classes the result of a BGS iteration is not "Solution". + * If this method is overriden, the BGSSolution_k ones proabably have to be too. */ - inline virtual void Set_BGSSolution(unsigned long iPoint, unsigned long iDim, su2double solution) {} + inline virtual su2double Get_BGSSolution(unsigned long iPoint, unsigned long iVar) const { + return Solution(iPoint, iVar); + } /*! * \brief Set the value of the solution in the previous BGS subiteration. @@ -2122,12 +2126,12 @@ class CVariable { /*! * \brief Restore the previous BGS subiteration to solution. */ - void Restore_BGSSolution_k(); + virtual void Restore_BGSSolution_k(); /*! * \brief Set the value of the solution in the previous BGS subiteration. */ - inline void Set_BGSSolution_k(unsigned long iPoint, unsigned long iVar, su2double val_var) { + inline virtual void Set_BGSSolution_k(unsigned long iPoint, unsigned long iVar, su2double val_var) { Solution_BGS_k(iPoint,iVar) = val_var; } @@ -2139,12 +2143,6 @@ class CVariable { return Solution_BGS_k(iPoint,iVar); } - /*! - * \brief A virtual member. Get the value of the old geometry solution (adjoint). - * \param[out] val_solution - old adjoint solution for coordinate iDim - */ - inline virtual su2double Get_BGSSolution(unsigned long iPoint, unsigned long iDim) const {return 0.0;} - /*! * \brief A virtual member. Set the direct velocity solution for the adjoint solver. * \param[in] solution_direct - Value of the direct velocity solution. diff --git a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp index f8a89a6bace0..b5be9b5a904d 100644 --- a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp @@ -303,14 +303,10 @@ void CDiscAdjMultizoneDriver::Run() { } } - /*--- Save Solution to Solution_BGS and compute residual from Solution_BGS and Solution_BGS_k. ---*/ + /*--- Compute residual from Solution and Solution_BGS_k and update the latter. ---*/ SetResidual_BGS(iZone); - /*--- Save Solution to Solution_BGS_k for a next outer iteration. - * (Solution might be overwritten when entering another zone because of cross derivatives.) ---*/ - - Set_BGSSolution(iZone); } /*--- Set the multizone output. ---*/ @@ -911,15 +907,6 @@ void CDiscAdjMultizoneDriver::Update_Cross_Term(unsigned short iZone, unsigned s } } -void CDiscAdjMultizoneDriver::Set_BGSSolution(unsigned short iZone) { - - for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { - auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; - if (solver && solver->GetAdjoint()) - solver->UpdateSolution_BGS(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); - } -} - void CDiscAdjMultizoneDriver::Set_Solution_To_BGSSolution_k(unsigned short iZone) { for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { diff --git a/SU2_CFD/src/drivers/CMultizoneDriver.cpp b/SU2_CFD/src/drivers/CMultizoneDriver.cpp index e05af44e2e7e..62696f542350 100644 --- a/SU2_CFD/src/drivers/CMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CMultizoneDriver.cpp @@ -405,45 +405,37 @@ void CMultizoneDriver::Run_Jacobi() { void CMultizoneDriver::Corrector(unsigned short val_iZone) { - if (config_container[val_iZone]->GetRelaxation()) - iteration_container[val_iZone][INST_0]->Relaxation(output_container[ZONE_0], integration_container, geometry_container, solver_container, - numerics_container, config_container, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); - + if (config_container[val_iZone]->GetRelaxation()) + iteration_container[val_iZone][INST_0]->Relaxation(output_container[ZONE_0], integration_container, + geometry_container, solver_container, numerics_container, config_container, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); } bool CMultizoneDriver::OuterConvergence(unsigned long OuterIter) { - /*--- Update the residual for the all the zones ---*/ + /*--- Update the residual for the all the zones. ---*/ - for (iZone = 0; iZone < nZone; iZone++){ + for (iZone = 0; iZone < nZone; iZone++) { - /*--- Account for all the solvers ---*/ + /*--- Account for all the solvers in this zone. ---*/ + + auto solvers = solver_container[iZone][INST_0][MESH_0]; for (unsigned short iSol = 0; iSol < MAX_SOLS; iSol++){ - if (solver_container[iZone][INST_0][MESH_0][iSol] != nullptr){ - solver_container[iZone][INST_0][MESH_0][iSol]->ComputeResidual_Multizone(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); - } + if (solvers[iSol] != nullptr) + solvers[iSol]->ComputeResidual_Multizone(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); } - /*--- make sure that everything is loaded into the output container ---*/ + /*--- Make sure that everything is loaded into the output container. ---*/ - output_container[iZone]->SetHistory_Output(geometry_container[iZone][INST_0][MESH_0],solver_container[iZone][INST_0][MESH_0], config_container[iZone]); + output_container[iZone]->SetHistory_Output(geometry_container[iZone][INST_0][MESH_0], solvers, config_container[iZone]); } - /*--- Update the residual for the all the zones ---*/ - for (iZone = 0; iZone < nZone; iZone++){ - /*--- Accounting for all the solvers ---*/ - for (unsigned short iSol = 0; iSol < MAX_SOLS; iSol++){ - /*-- If the solver position iSol is enabled --*/ - if (solver_container[iZone][INST_0][MESH_0][iSol] != nullptr){ - solver_container[iZone][INST_0][MESH_0][iSol]->UpdateSolution_BGS(geometry_container[iZone][INST_0][MESH_0], - config_container[iZone]);} - } - } + /*--- Print out the convergence data to screen and history file. ---*/ - /*--- Print out the convergence data to screen and history file ---*/ - driver_output->SetMultizoneHistory_Output(output_container, config_container, driver_config, driver_config->GetTimeIter(), driver_config->GetOuterIter()); + driver_output->SetMultizoneHistory_Output(output_container, config_container, driver_config, + driver_config->GetTimeIter(), driver_config->GetOuterIter()); return driver_output->GetConvergence(); diff --git a/SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp b/SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp index 3868e6f37aec..6bf7e05d468a 100644 --- a/SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp +++ b/SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp @@ -858,35 +858,6 @@ void CDiscAdjFEASolver::SetSurface_Sensitivity(CGeometry *geometry, CConfig *con } -void CDiscAdjFEASolver::ComputeResidual_Multizone(CGeometry *geometry, CConfig *config){ - - unsigned short iVar; - unsigned long iPoint; - su2double residual; - - /*--- Set Residuals to zero ---*/ - for (iVar = 0; iVar < nVar; iVar++){ - SetRes_BGS(iVar,0.0); - SetRes_Max_BGS(iVar,0.0,0); - } - - /*--- Set the residuals ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - - /// TODO: This is only difference to the CSolver version, this method and the BGS var might be reduntant. - nodes->Set_BGSSolution(iPoint, iVar, nodes->GetSolution(iPoint, iVar)); - - residual = nodes->Get_BGSSolution(iPoint, iVar) - nodes->Get_BGSSolution_k(iPoint, iVar); - AddRes_BGS(iVar,residual*residual); - AddRes_Max_BGS(iVar,fabs(residual),geometry->node[iPoint]->GetGlobalIndex(),geometry->node[iPoint]->GetCoord()); - } - } - - SetResidual_BGS(geometry, config); - -} - void CDiscAdjFEASolver::ReadDV(CConfig *config) { unsigned long index; diff --git a/SU2_CFD/src/solvers/CDiscAdjMeshSolver.cpp b/SU2_CFD/src/solvers/CDiscAdjMeshSolver.cpp index cab39bc108ea..9b920b1a6c48 100644 --- a/SU2_CFD/src/solvers/CDiscAdjMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CDiscAdjMeshSolver.cpp @@ -239,39 +239,6 @@ void CDiscAdjMeshSolver::SetSensitivity(CGeometry *geometry, CSolver **solver, C } -void CDiscAdjMeshSolver::ComputeResidual_Multizone(CGeometry *geometry, CConfig *config){ - - // ToDo: Can this be made generic to use the CSolver impl - - unsigned short iVar; - unsigned long iPoint; - su2double residual; - - /*--- Set Residuals to zero ---*/ - - for (iVar = 0; iVar < nVar; iVar++){ - SetRes_BGS(iVar,0.0); - SetRes_Max_BGS(iVar,0.0,0); - } - - /*--- Set the residuals ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++){ - /*--- Only for the boundary vertices ---*/ - if (nodes->Get_isVertex(iPoint)){ - for (iVar = 0; iVar < nVar; iVar++){ - /*--- Compute only for the sensitivities of the boundary displacements ---*/ - residual = nodes->GetBoundDisp_Sens(iPoint,iVar) - nodes->Get_BGSSolution_k(iPoint,iVar); - AddRes_BGS(iVar,residual*residual); - AddRes_Max_BGS(iVar,fabs(residual),geometry->node[iPoint]->GetGlobalIndex(),geometry->node[iPoint]->GetCoord()); - } - } - } - - SetResidual_BGS(geometry, config); - -} - void CDiscAdjMeshSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig *config, int val_iter, bool val_update_geo) { } - diff --git a/SU2_CFD/src/solvers/CDiscAdjSolver.cpp b/SU2_CFD/src/solvers/CDiscAdjSolver.cpp index 9adeecb70b69..6523ea691858 100644 --- a/SU2_CFD/src/solvers/CDiscAdjSolver.cpp +++ b/SU2_CFD/src/solvers/CDiscAdjSolver.cpp @@ -1000,37 +1000,7 @@ void CDiscAdjSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfi /*--- Delete the class memory that is used to load the restart. ---*/ - if (Restart_Vars != NULL) delete [] Restart_Vars; - if (Restart_Data != NULL) delete [] Restart_Data; - Restart_Vars = NULL; Restart_Data = NULL; - -} - -void CDiscAdjSolver::ComputeResidual_Multizone(CGeometry *geometry, CConfig *config) { - - unsigned short iVar; - unsigned long iPoint; - su2double residual; - - /*--- Set Residuals to zero ---*/ - for (iVar = 0; iVar < nVar; iVar++){ - SetRes_BGS(iVar,0.0); - SetRes_Max_BGS(iVar,0.0,0); - } - - /*--- Set the residuals ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) { - - /// TODO: This is only difference to the CSolver version, this method and the BGS var might be reduntant. - nodes->Set_BGSSolution(iPoint, iVar, nodes->GetSolution(iPoint, iVar)); - - residual = nodes->Get_BGSSolution(iPoint,iVar) - nodes->Get_BGSSolution_k(iPoint,iVar); - AddRes_BGS(iVar,residual*residual); - AddRes_Max_BGS(iVar,fabs(residual),geometry->node[iPoint]->GetGlobalIndex(),geometry->node[iPoint]->GetCoord()); - } - } - - SetResidual_BGS(geometry, config); + delete [] Restart_Vars; Restart_Vars = nullptr; + delete [] Restart_Data; Restart_Data = nullptr; } diff --git a/SU2_CFD/src/solvers/CSolver.cpp b/SU2_CFD/src/solvers/CSolver.cpp index 66b2c2f31fa1..ff5329fedf6d 100644 --- a/SU2_CFD/src/solvers/CSolver.cpp +++ b/SU2_CFD/src/solvers/CSolver.cpp @@ -4749,28 +4749,25 @@ void CSolver::ComputeResidual_Multizone(CGeometry *geometry, CConfig *config){ su2double residual; /*--- Set Residuals to zero ---*/ - for (iVar = 0; iVar < nVar; iVar++){ SetRes_BGS(iVar,0.0); SetRes_Max_BGS(iVar,0.0,0); } - /*--- Set the residuals ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++){ - for (iVar = 0; iVar < nVar; iVar++){ - residual = base_nodes->GetSolution(iPoint,iVar) - base_nodes->Get_BGSSolution_k(iPoint,iVar); - AddRes_BGS(iVar,residual*residual); - AddRes_Max_BGS(iVar,fabs(residual),geometry->node[iPoint]->GetGlobalIndex(),geometry->node[iPoint]->GetCoord()); + /*--- Set the residuals and BGSSolution_k to solution for next multizone outer iteration. ---*/ + for (iPoint = 0; iPoint < nPoint; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) { + residual = base_nodes->Get_BGSSolution(iPoint,iVar) - base_nodes->Get_BGSSolution_k(iPoint,iVar); + base_nodes->Set_BGSSolution_k(iPoint,iVar, base_nodes->Get_BGSSolution(iPoint,iVar)); + AddRes_BGS(iVar, residual*residual); + AddRes_Max_BGS(iVar, fabs(residual), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); } } + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { + for (iVar = 0; iVar < nVar; iVar++) + base_nodes->Set_BGSSolution_k(iPoint,iVar, base_nodes->Get_BGSSolution(iPoint,iVar)); + } SetResidual_BGS(geometry, config); } - - -void CSolver::UpdateSolution_BGS(CGeometry *geometry, CConfig *config){ - - /*--- To nPoint: The solution must be communicated beforehand ---*/ - base_nodes->Set_BGSSolution_k(); -} diff --git a/SU2_CFD/src/variables/CDiscAdjFEAVariable.cpp b/SU2_CFD/src/variables/CDiscAdjFEAVariable.cpp index c03abf0c2c53..1fe4bd72edf2 100644 --- a/SU2_CFD/src/variables/CDiscAdjFEAVariable.cpp +++ b/SU2_CFD/src/variables/CDiscAdjFEAVariable.cpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -32,8 +32,6 @@ CDiscAdjFEAVariable::CDiscAdjFEAVariable(const su2double *disp, const su2double *vel, const su2double *accel, unsigned long npoint, unsigned long ndim, unsigned long nvar, bool unsteady, CConfig *config) : CVariable(npoint, ndim, nvar, config) { - bool fsi = config->GetFSI_Simulation(); - Solution_Direct.resize(nPoint,nVar); Sensitivity.resize(nPoint,nDim) = su2double(0.0); @@ -42,11 +40,7 @@ CDiscAdjFEAVariable::CDiscAdjFEAVariable(const su2double *disp, const su2double for (unsigned long iVar = 0; iVar < nVar; iVar++) Solution(iPoint,iVar) = disp[iVar]; - if (fsi) { - Solution_BGS.resize(nPoint,nDim) = su2double(0.0); - } - - if (config->GetMultizone_Problem()) { + if (config->GetMultizone_Problem() && config->GetDiscrete_Adjoint()) { External.resize(nPoint,nVar) = su2double(0.0); } diff --git a/SU2_CFD/src/variables/CDiscAdjMeshBoundVariable.cpp b/SU2_CFD/src/variables/CDiscAdjMeshBoundVariable.cpp index 6e232a06264d..29851b845afe 100644 --- a/SU2_CFD/src/variables/CDiscAdjMeshBoundVariable.cpp +++ b/SU2_CFD/src/variables/CDiscAdjMeshBoundVariable.cpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -29,11 +29,15 @@ #include "../../include/variables/CDiscAdjMeshBoundVariable.hpp" -CDiscAdjMeshBoundVariable::CDiscAdjMeshBoundVariable(unsigned long npoint, unsigned long ndim, CConfig *config) : - CVariable(npoint, ndim, config) { +CDiscAdjMeshBoundVariable::CDiscAdjMeshBoundVariable(unsigned long npoint, unsigned long ndim, CConfig *config) { + nPoint = npoint; + nVar = ndim; nDim = ndim; + /*--- Allocate the solution array. ---*/ + Solution.resize(nPoint,nVar) = su2double(0.0); + VertexMap.Reset(nPoint); } @@ -63,3 +67,7 @@ void CDiscAdjMeshBoundVariable::AllocateBoundaryVariables(CConfig *config) { void CDiscAdjMeshBoundVariable::Set_BGSSolution_k() { Solution_BGS_k = Bound_Disp_Sens; } + +void CDiscAdjMeshBoundVariable::Restore_BGSSolution_k() { + Bound_Disp_Sens = Solution_BGS_k; +} diff --git a/SU2_CFD/src/variables/CDiscAdjVariable.cpp b/SU2_CFD/src/variables/CDiscAdjVariable.cpp index 66afff80e1fb..9244aa1a49b3 100644 --- a/SU2_CFD/src/variables/CDiscAdjVariable.cpp +++ b/SU2_CFD/src/variables/CDiscAdjVariable.cpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -57,13 +57,11 @@ CDiscAdjVariable::CDiscAdjVariable(const su2double* sol, unsigned long npoint, u Solution_Geometry.resize(nPoint,nDim) = su2double(1e-16); Solution_Geometry_Old.resize(nPoint,nDim) = su2double(0.0); - Solution_BGS.resize(nPoint,nVar) = su2double(0.0); Solution_Geometry_BGS_k.resize(nPoint,nDim) = su2double(0.0); } - if (config->GetMultizone_Problem()) { + if (config->GetMultizone_Problem() && config->GetDiscrete_Adjoint()) { External.resize(nPoint,nVar) = su2double(0.0); - Solution_BGS.resize(nPoint,nVar) = su2double(0.0); } } diff --git a/TestCases/parallel_regression_AD.py b/TestCases/parallel_regression_AD.py index 830e45ad5ee0..1d65ca6df2fe 100644 --- a/TestCases/parallel_regression_AD.py +++ b/TestCases/parallel_regression_AD.py @@ -302,7 +302,7 @@ def main(): discadj_fsi2.cfg_dir = "disc_adj_fsi/Airfoil_2d" discadj_fsi2.cfg_file = "config.cfg" discadj_fsi2.test_iter = 8 - discadj_fsi2.test_vals = [-5.071100, -2.5237e-13] #last 2 columns + discadj_fsi2.test_vals = [-5.071028 -2.5253e-13] #last 2 columns discadj_fsi2.su2_exec = "mpirun -n 2 SU2_CFD_AD" discadj_fsi2.timeout = 1600 discadj_fsi2.tol = 1e-16 From f6bf33e7e14054681d3d3c119877cb45392cd564 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 4 Apr 2020 18:25:23 +0100 Subject: [PATCH 69/79] small fix --- SU2_CFD/src/solvers/CSolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SU2_CFD/src/solvers/CSolver.cpp b/SU2_CFD/src/solvers/CSolver.cpp index ff5329fedf6d..6e2e335e23de 100644 --- a/SU2_CFD/src/solvers/CSolver.cpp +++ b/SU2_CFD/src/solvers/CSolver.cpp @@ -4755,7 +4755,7 @@ void CSolver::ComputeResidual_Multizone(CGeometry *geometry, CConfig *config){ } /*--- Set the residuals and BGSSolution_k to solution for next multizone outer iteration. ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++) { + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { for (iVar = 0; iVar < nVar; iVar++) { residual = base_nodes->Get_BGSSolution(iPoint,iVar) - base_nodes->Get_BGSSolution_k(iPoint,iVar); base_nodes->Set_BGSSolution_k(iPoint,iVar, base_nodes->Get_BGSSolution(iPoint,iVar)); From 3d6cacfe7aa42e13425ab06a420f62b69b9b3725 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 4 Apr 2020 18:28:20 +0100 Subject: [PATCH 70/79] cleanup --- SU2_CFD/src/solvers/CSolver.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/SU2_CFD/src/solvers/CSolver.cpp b/SU2_CFD/src/solvers/CSolver.cpp index 6e2e335e23de..f6d450e7bbfd 100644 --- a/SU2_CFD/src/solvers/CSolver.cpp +++ b/SU2_CFD/src/solvers/CSolver.cpp @@ -4755,18 +4755,15 @@ void CSolver::ComputeResidual_Multizone(CGeometry *geometry, CConfig *config){ } /*--- Set the residuals and BGSSolution_k to solution for next multizone outer iteration. ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++) { + for (iPoint = 0; iPoint < nPoint; iPoint++) { + const su2double domain = (iPoint < nPointDomain); for (iVar = 0; iVar < nVar; iVar++) { - residual = base_nodes->Get_BGSSolution(iPoint,iVar) - base_nodes->Get_BGSSolution_k(iPoint,iVar); + residual = (base_nodes->Get_BGSSolution(iPoint,iVar) - base_nodes->Get_BGSSolution_k(iPoint,iVar))*domain; base_nodes->Set_BGSSolution_k(iPoint,iVar, base_nodes->Get_BGSSolution(iPoint,iVar)); AddRes_BGS(iVar, residual*residual); AddRes_Max_BGS(iVar, fabs(residual), geometry->node[iPoint]->GetGlobalIndex(), geometry->node[iPoint]->GetCoord()); } } - for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { - for (iVar = 0; iVar < nVar; iVar++) - base_nodes->Set_BGSSolution_k(iPoint,iVar, base_nodes->Get_BGSSolution(iPoint,iVar)); - } SetResidual_BGS(geometry, config); From 33b30f36eec7eebd58b49eacf1e7978669184d1c Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 4 Apr 2020 19:05:44 +0100 Subject: [PATCH 71/79] forgot a coma --- TestCases/parallel_regression_AD.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TestCases/parallel_regression_AD.py b/TestCases/parallel_regression_AD.py index 1d65ca6df2fe..7b13db9c3fb1 100644 --- a/TestCases/parallel_regression_AD.py +++ b/TestCases/parallel_regression_AD.py @@ -302,7 +302,7 @@ def main(): discadj_fsi2.cfg_dir = "disc_adj_fsi/Airfoil_2d" discadj_fsi2.cfg_file = "config.cfg" discadj_fsi2.test_iter = 8 - discadj_fsi2.test_vals = [-5.071028 -2.5253e-13] #last 2 columns + discadj_fsi2.test_vals = [-5.071028, -2.5253e-13] #last 2 columns discadj_fsi2.su2_exec = "mpirun -n 2 SU2_CFD_AD" discadj_fsi2.timeout = 1600 discadj_fsi2.tol = 1e-16 From 35a3fd6cadb0df48d9700062a86cc8cd578002c1 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 4 Apr 2020 22:10:06 +0100 Subject: [PATCH 72/79] more duplication cleanup --- Common/include/toolboxes/geometry_toolbox.hpp | 45 ++++++++++++ SU2_CFD/src/solvers/CMeshSolver.cpp | 72 +++++-------------- 2 files changed, 61 insertions(+), 56 deletions(-) diff --git a/Common/include/toolboxes/geometry_toolbox.hpp b/Common/include/toolboxes/geometry_toolbox.hpp index 76e9339e72d8..4fcb616a5f7f 100644 --- a/Common/include/toolboxes/geometry_toolbox.hpp +++ b/Common/include/toolboxes/geometry_toolbox.hpp @@ -138,4 +138,49 @@ inline void QuadrilateralNormal(const T& coords, U* normal) { normal[0] *= 0.5; normal[1] *= 0.5; normal[2] *= 0.5; } +/*! + * \brief Compute a 3D rotation matrix. + * \note The implicit ordering is rotation about the x, y, and then z axis. + */ +template +inline void RotationMatrix(Scalar theta, Scalar phi, Scalar psi, Matrix& mat) { + + Scalar cosTheta = cos(theta); Scalar cosPhi = cos(phi); Scalar cosPsi = cos(psi); + Scalar sinTheta = sin(theta); Scalar sinPhi = sin(phi); Scalar sinPsi = sin(psi); + + mat[0][0] = cosPhi*cosPsi; + mat[1][0] = cosPhi*sinPsi; + mat[2][0] = -sinPhi; + + mat[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; + mat[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; + mat[2][1] = sinTheta*cosPhi; + + mat[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; + mat[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; + mat[2][2] = cosTheta*cosPhi; +} + +/*! \brief Compute a 2D rotation matrix. */ +template +inline void RotationMatrix(Scalar psi, Matrix& mat) { + + Scalar cosPsi = cos(psi); + Scalar sinPsi = sin(psi); + + mat[0][0] = cosPsi; mat[0][1] =-sinPsi; + mat[1][0] = sinPsi; mat[1][1] = cosPsi; +} + +/*! \brief Apply a rotation matrix (R) about origin (O) to a point at + * distance (d) from it to obtain new coordinate (c). */ +template +inline void Rotate(const Scalar R[][nDim], const Scalar* O, const Scalar* d, Scalar* c) { + + for (int iDim = 0; iDim < nDim; ++iDim) { + c[iDim] = O[iDim]; + for (int k = 0; k < nDim; ++k) c[iDim] += R[iDim][k] * d[k]; + } +} + } diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index 50f3700fac6f..dfb7f0421336 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -25,11 +25,13 @@ * License along with SU2. If not, see . */ - #include "../../../Common/include/adt_structure.hpp" #include "../../../Common/include/omp_structure.hpp" #include "../../include/solvers/CMeshSolver.hpp" #include "../../include/variables/CMeshBoundVariable.hpp" +#include "../../../Common/include/toolboxes/geometry_toolbox.hpp" + +using namespace GeometryToolbox; CMeshSolver::CMeshSolver(CGeometry *geometry, CConfig *config) : CFEASolver(true) { @@ -891,8 +893,7 @@ void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, unsigne su2double VarCoordAbs[3] = {0.0}; su2double rotCoord[3] = {0.0}, r[3] = {0.0}; su2double rotMatrix[3][3] = {{0.0}}; - su2double dtheta, dphi, dpsi, cosTheta, sinTheta; - su2double cosPhi, sinPhi, cosPsi, sinPsi; + su2double dtheta, dphi, dpsi; const su2double DEG2RAD = PI_NUMBER/180.0; unsigned short iMarker, jMarker, iDim; unsigned long iPoint, iVertex; @@ -909,14 +910,8 @@ void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, unsigne if (iter == 0) time_old = time_new; else time_old = (iter-1)*deltaT; - auto Rotate = [](const su2double mat[][3], const su2double* r, const su2double* o, su2double* c) { - c[0] = mat[0][0]*r[0] + mat[0][1]*r[1] + mat[0][2]*r[2] + o[0]; - c[1] = mat[1][0]*r[0] + mat[1][1]*r[1] + mat[1][2]*r[2] + o[1]; - c[2] = mat[2][0]*r[0] + mat[2][1]*r[1] + mat[2][2]*r[2] + o[2]; - }; - /*--- Store displacement of each node on the pitching surface ---*/ - /*--- Loop over markers and find the particular marker(s) (surface) to pitch ---*/ + /*--- Loop over markers and find the particular marker(s) (surface) to pitch ---*/ for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { if (config->GetMarker_All_Moving(iMarker) != YES) continue; @@ -968,25 +963,11 @@ void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, unsigne dpsi = -Ampl[2]*(sin(Omega[2]*time_new + Phase[2]) - sin(Omega[2]*time_old + Phase[2])); - /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - - cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); - sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ + /*--- Compute rotation matrix. ---*/ - rotMatrix[0][0] = cosPhi*cosPsi; - rotMatrix[1][0] = cosPhi*sinPsi; - rotMatrix[2][0] = -sinPhi; + RotationMatrix(dtheta, dphi, dpsi, rotMatrix); - rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; - rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; - rotMatrix[2][1] = sinTheta*cosPhi; - - rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[2][2] = cosTheta*cosPhi; + /*--- Apply rotation to the vertices. ---*/ for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { @@ -1002,7 +983,7 @@ void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, unsigne /*--- Compute transformed point coordinates ---*/ - Rotate(rotMatrix, r, Center, rotCoord); + Rotate(rotMatrix, Center, r, rotCoord); /*--- Calculate delta change in the x, y, & z directions ---*/ for (iDim = 0; iDim < nDim; iDim++) @@ -1030,8 +1011,7 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, unsigne su2double Center[3] = {0.0}, VarCoord[3] = {0.0}, Omega[3] = {0.0}, rotCoord[3] = {0.0}, r[3] = {0.0}, Center_Aux[3] = {0.0}; su2double rotMatrix[3][3] = {{0.0}}; - su2double dtheta, dphi, dpsi, cosTheta, sinTheta; - su2double cosPhi, sinPhi, cosPsi, sinPsi; + su2double dtheta, dphi, dpsi; unsigned short iMarker, jMarker, iDim; unsigned long iPoint, iVertex; string Marker_Tag, Moving_Tag; @@ -1047,12 +1027,6 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, unsigne if (iter == 0) time_old = time_new; else time_old = (iter-1)*deltaT; - auto Rotate = [](const su2double mat[][3], const su2double* r, const su2double* o, su2double* c) { - c[0] = mat[0][0]*r[0] + mat[0][1]*r[1] + mat[0][2]*r[2] + o[0]; - c[1] = mat[1][0]*r[0] + mat[1][1]*r[1] + mat[1][2]*r[2] + o[1]; - c[2] = mat[2][0]*r[0] + mat[2][1]*r[1] + mat[2][2]*r[2] + o[2]; - }; - /*--- Store displacement of each node on the rotating surface ---*/ /*--- Loop over markers and find the particular marker(s) (surface) to rotate ---*/ @@ -1096,25 +1070,11 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, unsigne dphi = Omega[1]*(time_new-time_old); dpsi = Omega[2]*(time_new-time_old); - /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - - cosTheta = cos(dtheta); cosPhi = cos(dphi); cosPsi = cos(dpsi); - sinTheta = sin(dtheta); sinPhi = sin(dphi); sinPsi = sin(dpsi); - - /*--- Compute the rotation matrix. Note that the implicit - ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - - rotMatrix[0][0] = cosPhi*cosPsi; - rotMatrix[1][0] = cosPhi*sinPsi; - rotMatrix[2][0] = -sinPhi; + /*--- Compute rotation matrix. ---*/ - rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; - rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; - rotMatrix[2][1] = sinTheta*cosPhi; + RotationMatrix(dtheta, dphi, dpsi, rotMatrix); - rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; - rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; - rotMatrix[2][2] = cosTheta*cosPhi; + /*--- Apply rotation to the vertices. ---*/ for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { @@ -1130,7 +1090,7 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, unsigne /*--- Compute transformed point coordinates ---*/ - Rotate(rotMatrix, r, Center, rotCoord); + Rotate(rotMatrix, Center, r, rotCoord); /*--- Calculate delta change in the x, y, & z directions ---*/ for (iDim = 0; iDim < nDim; iDim++) @@ -1168,7 +1128,7 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, unsigne /*--- Compute transformed point coordinates ---*/ - Rotate(rotMatrix, r, Center, rotCoord); + Rotate(rotMatrix, Center, r, rotCoord); /*--- Calculate delta change in the x, y, & z directions ---*/ for (iDim = 0; iDim < nDim; iDim++) @@ -1196,7 +1156,7 @@ void CMeshSolver::Surface_Rotating(CGeometry *geometry, CConfig *config, unsigne /*--- Compute transformed point coordinates ---*/ - Rotate(rotMatrix, r, Center, rotCoord); + Rotate(rotMatrix, Center, r, rotCoord); /*--- Calculate delta change in the x, y, & z directions ---*/ for (iDim = 0; iDim < nDim; iDim++) From 213d4d2da9fcacf3f9e86594bbd74e4aa41295a8 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 4 Apr 2020 22:51:35 +0100 Subject: [PATCH 73/79] fix (??) for the pitching deforming adjoint case --- SU2_CFD/include/solvers/CMeshSolver.hpp | 4 ++-- SU2_CFD/src/solvers/CEulerSolver.cpp | 4 ++-- SU2_CFD/src/solvers/CMeshSolver.cpp | 13 +++---------- SU2_CFD/src/solvers/CSolver.cpp | 17 ++--------------- 4 files changed, 9 insertions(+), 29 deletions(-) diff --git a/SU2_CFD/include/solvers/CMeshSolver.hpp b/SU2_CFD/include/solvers/CMeshSolver.hpp index f2dd42892722..3dcd474c7e5a 100644 --- a/SU2_CFD/include/solvers/CMeshSolver.hpp +++ b/SU2_CFD/include/solvers/CMeshSolver.hpp @@ -172,12 +172,12 @@ class CMeshSolver final : public CFEASolver { * \return */ inline su2double GetMaximum_Volume() const override {return MaxVolume_Curr;} - + /*! * \brief Pitching definition for deforming mesh * \param[in] geometry - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current time iteration number + * \param[in] iter - Current time iteration number */ void Surface_Pitching(CGeometry *geometry, CConfig *config, unsigned long iter); diff --git a/SU2_CFD/src/solvers/CEulerSolver.cpp b/SU2_CFD/src/solvers/CEulerSolver.cpp index 06f8c542ce62..692a25b7f7d8 100644 --- a/SU2_CFD/src/solvers/CEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CEulerSolver.cpp @@ -11584,8 +11584,8 @@ void CEulerSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig /*--- Detect a wrong solution file ---*/ if (iPoint_Global_Local < nPointDomain) { - SU2_MPI::Error(string("The solution file ") + restart_filename + string(" doesn't match with the mesh file!\n") + - string("It could be empty lines at the end of the file."), CURRENT_FUNCTION); + SU2_MPI::Error(string("The solution file ") + restart_filename + string(" doesn't match with the mesh file!\n") + + string("It could be empty lines at the end of the file."), CURRENT_FUNCTION); } /*--- Communicate the loaded solution on the fine grid before we transfer diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index dfb7f0421336..f3faee5dd87f 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -617,7 +617,7 @@ void CMeshSolver::UpdateMultiGrid(CGeometry **geometry, CConfig *config){ void CMeshSolver::SetBoundaryDisplacements(CGeometry *geometry, CNumerics *numerics, CConfig *config){ - if (config->GetSurface_Movement(DEFORMING)) { + if (config->GetSurface_Movement(DEFORMING) && !config->GetDiscrete_Adjoint()) { if (rank == MASTER_NODE) cout << endl << " Updating surface positions." << endl; @@ -810,15 +810,8 @@ void CMeshSolver::Restart_OldGeometry(CGeometry *geometry, CConfig *config) { if (rank == MASTER_NODE) cout << "Requested mesh restart filename is negative. Setting known solution" << endl; /*--- Set loaded solution into correct previous time containers. ---*/ - unsigned long iPoint; - for (iPoint = 0; iPoint < nPoint; iPoint++ ) { - for (unsigned short iDim = 0; iDim < nDim; iDim++){ - if(iStep==1) - nodes->Set_Solution_time_n(iPoint, iDim, nodes->GetSolution(iPoint, iDim)); - else - nodes->Set_Solution_time_n1(iPoint, iDim, nodes->GetSolution_time_n(iPoint, iDim)); - } - } + if(iStep==1) nodes->Set_Solution_time_n(); + else nodes->Set_Solution_time_n1(); } else { string filename_n = config->GetUnsteady_FileName(filename, Unst_RestartIter, ""); diff --git a/SU2_CFD/src/solvers/CSolver.cpp b/SU2_CFD/src/solvers/CSolver.cpp index f6d450e7bbfd..92f9b81a4e60 100644 --- a/SU2_CFD/src/solvers/CSolver.cpp +++ b/SU2_CFD/src/solvers/CSolver.cpp @@ -3439,7 +3439,6 @@ void CSolver::Restart_OldGeometry(CGeometry *geometry, CConfig *config) { string text_line; long iPoint_Local; unsigned long iPoint_Global_Local = 0, iPoint_Global = 0; - unsigned short rbuf_NotMatching, sbuf_NotMatching; /*--- First, we load the restart file for time n ---*/ @@ -3491,13 +3490,7 @@ void CSolver::Restart_OldGeometry(CGeometry *geometry, CConfig *config) { /*--- Detect a wrong solution file ---*/ - rbuf_NotMatching = 0; sbuf_NotMatching = 0; - - if (iPoint_Global_Local < geometry->GetnPointDomain()) { sbuf_NotMatching = 1; } - - SU2_MPI::Allreduce(&sbuf_NotMatching, &rbuf_NotMatching, 1, MPI_UNSIGNED_SHORT, MPI_SUM, MPI_COMM_WORLD); - - if (rbuf_NotMatching != 0) { + if (iPoint_Global_Local < geometry->GetnPointDomain()) { SU2_MPI::Error(string("The solution file ") + filename + string(" doesn't match with the mesh file!\n") + string("It could be empty lines at the end of the file."), CURRENT_FUNCTION); } @@ -3565,13 +3558,7 @@ void CSolver::Restart_OldGeometry(CGeometry *geometry, CConfig *config) { /*--- Detect a wrong solution file ---*/ - rbuf_NotMatching = 0; sbuf_NotMatching = 0; - - if (iPoint_Global_Local < geometry->GetnPointDomain()) { sbuf_NotMatching = 1; } - - SU2_MPI::Allreduce(&sbuf_NotMatching, &rbuf_NotMatching, 1, MPI_UNSIGNED_SHORT, MPI_SUM, MPI_COMM_WORLD); - - if (rbuf_NotMatching != 0) { + if (iPoint_Global_Local < geometry->GetnPointDomain()) { SU2_MPI::Error(string("The solution file ") + filename + string(" doesn't match with the mesh file!\n") + string("It could be empty lines at the end of the file."), CURRENT_FUNCTION); } From 26a60384c83ca3db35f87299ed60535e95d6b36f Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sun, 5 Apr 2020 11:30:59 +0100 Subject: [PATCH 74/79] CInterpolatorFactory --- Common/include/CConfig.hpp | 32 ++- .../interface_interpolation/CInterpolator.hpp | 11 +- .../CIsoparametric.hpp | 2 +- .../interface_interpolation/CMirror.hpp | 2 +- .../CNearestNeighbor.hpp | 2 +- .../CRadialBasisFunction.hpp | 2 +- .../interface_interpolation/CSlidingMesh.hpp | 2 +- Common/lib/Makefile.am | 1 + .../interface_interpolation/CInterpolator.cpp | 12 +- .../CIsoparametric.cpp | 10 +- .../src/interface_interpolation/CMirror.cpp | 14 +- .../CNearestNeighbor.cpp | 8 +- .../CRadialBasisFunction.cpp | 10 +- .../interface_interpolation/CSlidingMesh.cpp | 8 +- .../src/interface_interpolation/meson.build | 3 +- SU2_CFD/include/drivers/CDriver.hpp | 2 +- SU2_CFD/src/drivers/CDriver.cpp | 263 +++++------------- SU2_CFD/src/drivers/CMultizoneDriver.cpp | 2 +- SU2_CFD/src/interfaces/CInterface.cpp | 4 +- SU2_CFD/src/solvers/CMeshSolver.cpp | 4 +- 20 files changed, 163 insertions(+), 231 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index aac162b292e9..927d1231ff93 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -3613,13 +3613,41 @@ class CConfig { */ void SetKind_Solver(unsigned short val_solver) { Kind_Solver = val_solver; } + /*! + * \brief Return true if a fluid solver is in use. + */ + bool GetFluidProblem(void) const { + switch (Kind_Solver) { + case EULER : case NAVIER_STOKES: case RANS: + case INC_EULER : case INC_NAVIER_STOKES: case INC_RANS: + case DISC_ADJ_INC_EULER: case DISC_ADJ_INC_NAVIER_STOKES: case DISC_ADJ_INC_RANS: + case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: + return true; + default: + return false; + } + } + + /*! + * \brief Return true if a structural solver is in use. + */ + bool GetStructuralProblem(void) const { + return (Kind_Solver == FEM_ELASTICITY) || (Kind_Solver == DISC_ADJ_FEM); + } + + /*! + * \brief Return true if a heat solver is in use. + */ + bool GetHeatProblem(void) const { + return (Kind_Solver == HEAT_EQUATION) || (Kind_Solver == DISC_ADJ_HEAT); + } + /*! * \brief Kind of Multizone Solver. * \return Governing equation that we are solving. */ unsigned short GetKind_MZSolver(void) const { return Kind_MZSolver; } - /*! * \brief Governing equations of the flow (it can be different from the run time equation). * \param[in] val_zone - Zone where the soler is applied. @@ -8753,7 +8781,7 @@ class CConfig { /*! * \brief Get option of whether to use conservative interpolation between zones. */ - bool GetConservativeInterpolation(void) const { return ConservativeInterpolation; } + bool GetConservativeInterpolation(void) const { return ConservativeInterpolation && GetStructuralProblem(); } /*! * \brief Get the basis function to use for radial basis function interpolation for FSI. diff --git a/Common/include/interface_interpolation/CInterpolator.hpp b/Common/include/interface_interpolation/CInterpolator.hpp index 3d7a0b3f9f19..32ffae355dba 100644 --- a/Common/include/interface_interpolation/CInterpolator.hpp +++ b/Common/include/interface_interpolation/CInterpolator.hpp @@ -119,7 +119,7 @@ class CInterpolator { * \note Main method that derived classes must implement. * \param[in] config - Definition of the particular problem. */ - virtual void Set_TransferCoeff(const CConfig* const* config) = 0; + virtual void SetTransferCoeff(const CConfig* const* config) = 0; /*! * \brief Print information about the interpolation. @@ -131,7 +131,7 @@ class CInterpolator { * \param[in] config - Definition of the particular problem. * \param[in] val_marker_interface - Interface tag. */ - static int Find_InterfaceMarker(const CConfig *config, unsigned short val_marker_interface); + static int FindInterfaceMarker(const CConfig *config, unsigned short val_marker_interface); /*! * \brief Check whether an interface should be processed or not, i.e. if it is part of the zones. @@ -140,6 +140,13 @@ class CInterpolator { */ static bool CheckInterfaceBoundary(int val_markDonor, int val_markTarget); + /*! + * \brief Check whether two zones have a common interface. + * \param[in] donor - Configuration of the donor zone. + * \param[in] target - Configuration of the target zone. + */ + static bool CheckZonesInterface(const CConfig* donor, const CConfig* target); + protected: /*! * \brief Recontstruct the boundary connectivity from parallel partitioning and broadcasts it to all threads diff --git a/Common/include/interface_interpolation/CIsoparametric.hpp b/Common/include/interface_interpolation/CIsoparametric.hpp index cd2d1562aa0f..e4c27c6bb9c8 100644 --- a/Common/include/interface_interpolation/CIsoparametric.hpp +++ b/Common/include/interface_interpolation/CIsoparametric.hpp @@ -53,7 +53,7 @@ class CIsoparametric final : public CInterpolator { * \brief Set up transfer matrix defining relation between two meshes * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(const CConfig* const* config) override; + void SetTransferCoeff(const CConfig* const* config) override; /*! * \brief Print information about the interpolation. diff --git a/Common/include/interface_interpolation/CMirror.hpp b/Common/include/interface_interpolation/CMirror.hpp index fe155c5cb2ae..e884b70b40e0 100644 --- a/Common/include/interface_interpolation/CMirror.hpp +++ b/Common/include/interface_interpolation/CMirror.hpp @@ -48,6 +48,6 @@ class CMirror final : public CInterpolator { * \brief Set up transfer matrix defining relation between two meshes * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(const CConfig* const* config) override; + void SetTransferCoeff(const CConfig* const* config) override; }; diff --git a/Common/include/interface_interpolation/CNearestNeighbor.hpp b/Common/include/interface_interpolation/CNearestNeighbor.hpp index 8bc031e11c84..53a2f92478ed 100644 --- a/Common/include/interface_interpolation/CNearestNeighbor.hpp +++ b/Common/include/interface_interpolation/CNearestNeighbor.hpp @@ -52,7 +52,7 @@ class CNearestNeighbor final : public CInterpolator { * \brief Set up transfer matrix defining relation between two meshes. * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(const CConfig* const* config) override; + void SetTransferCoeff(const CConfig* const* config) override; /*! * \brief Print interpolation statistics. diff --git a/Common/include/interface_interpolation/CRadialBasisFunction.hpp b/Common/include/interface_interpolation/CRadialBasisFunction.hpp index 516b04192685..61e154b0afcb 100644 --- a/Common/include/interface_interpolation/CRadialBasisFunction.hpp +++ b/Common/include/interface_interpolation/CRadialBasisFunction.hpp @@ -55,7 +55,7 @@ class CRadialBasisFunction final : public CInterpolator { * \brief Set up transfer matrix defining relation between two meshes * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(const CConfig* const* config) override; + void SetTransferCoeff(const CConfig* const* config) override; /*! * \brief Print information about the interpolation. diff --git a/Common/include/interface_interpolation/CSlidingMesh.hpp b/Common/include/interface_interpolation/CSlidingMesh.hpp index 190a92e31401..25f77886b8a5 100644 --- a/Common/include/interface_interpolation/CSlidingMesh.hpp +++ b/Common/include/interface_interpolation/CSlidingMesh.hpp @@ -49,7 +49,7 @@ class CSlidingMesh final : public CInterpolator { * \brief Set up transfer matrix defining relation between two meshes * \param[in] config - Definition of the particular problem. */ - void Set_TransferCoeff(const CConfig* const* config) override; + void SetTransferCoeff(const CConfig* const* config) override; private: /*! diff --git a/Common/lib/Makefile.am b/Common/lib/Makefile.am index fde044c838bb..59f08d78e097 100644 --- a/Common/lib/Makefile.am +++ b/Common/lib/Makefile.am @@ -93,6 +93,7 @@ lib_sources = \ ../src/geometry/primal_grid/CTetrahedron.cpp \ ../src/geometry/primal_grid/CQuadrilateral.cpp \ ../src/geometry/primal_grid/CVertexMPI.cpp \ + ../src/interface_interpolation/CInterpolatorFactory.cpp \ ../src/interface_interpolation/CInterpolator.cpp \ ../src/interface_interpolation/CMirror.cpp \ ../src/interface_interpolation/CSlidingMesh.cpp \ diff --git a/Common/src/interface_interpolation/CInterpolator.cpp b/Common/src/interface_interpolation/CInterpolator.cpp index 5386304e94a7..977fe378a621 100644 --- a/Common/src/interface_interpolation/CInterpolator.cpp +++ b/Common/src/interface_interpolation/CInterpolator.cpp @@ -41,7 +41,7 @@ CInterpolator::CInterpolator(CGeometry ****geometry_container, const CConfig* co target_geometry(geometry_container[jZone][INST_0][MESH_0]) { } -int CInterpolator::Find_InterfaceMarker(const CConfig *config, unsigned short val_marker_interface) { +int CInterpolator::FindInterfaceMarker(const CConfig *config, unsigned short val_marker_interface) { for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { /*--- If the tag GetMarker_All_ZoneInterface(iMarker) equals the interface we are looking for. ---*/ @@ -60,6 +60,16 @@ bool CInterpolator::CheckInterfaceBoundary(int markDonor, int markTarget) { return (donorCheck != -1) && (targetCheck != -1); } +bool CInterpolator::CheckZonesInterface(const CConfig* donor, const CConfig* target) { + + /*--- Loop over all interface markers to find if the 2 zones share any interface boundary. ---*/ + for (auto iInter = 1u; iInter <= (donor->GetMarker_n_ZoneInterface()/2); iInter++) { + if (CheckInterfaceBoundary(FindInterfaceMarker(donor, iInter), FindInterfaceMarker(target, iInter))) + return true; + } + return false; +} + void CInterpolator::Determine_ArraySize(int markDonor, int markTarget, unsigned long nVertexDonor, unsigned short nDim) { diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp index 6c2cc7ca9a55..fcad8d936d9a 100644 --- a/Common/src/interface_interpolation/CIsoparametric.cpp +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -34,6 +34,7 @@ using namespace GeometryToolbox; + /*! \brief Helper struct to store information about candidate donor elements. */ struct DonorInfo { su2double isoparams[4] = {0.0}; /*!< \brief Interpolation coefficients. */ @@ -47,10 +48,9 @@ struct DonorInfo { } }; - CIsoparametric::CIsoparametric(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { - Set_TransferCoeff(config); + SetTransferCoeff(config); } void CIsoparametric::PrintStatistics(void) const { @@ -59,7 +59,7 @@ void CIsoparametric::PrintStatistics(void) const { << " Interpolation mitigated for " << ErrorCounter << " (" << ErrorRate << "%) target vertices." << endl; } -void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { +void CIsoparametric::SetTransferCoeff(const CConfig* const* config) { const int nProcessor = size; const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface()/2; @@ -82,10 +82,10 @@ void CIsoparametric::Set_TransferCoeff(const CConfig* const* config) { */ /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ - const auto markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + const auto markDonor = FindInterfaceMarker(config[donorZone], iMarkerInt); /*--- On the target side: find the tag of the boundary sharing the interface. ---*/ - const auto markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); + const auto markTarget = FindInterfaceMarker(config[targetZone], iMarkerInt); /*--- Checks if the zone contains the interface, if not continue to the next step. ---*/ if (!CheckInterfaceBoundary(markDonor, markTarget)) continue; diff --git a/Common/src/interface_interpolation/CMirror.cpp b/Common/src/interface_interpolation/CMirror.cpp index 86045d0d353c..88d65c24c92e 100644 --- a/Common/src/interface_interpolation/CMirror.cpp +++ b/Common/src/interface_interpolation/CMirror.cpp @@ -28,14 +28,20 @@ #include "../../include/interface_interpolation/CMirror.hpp" #include "../../include/CConfig.hpp" #include "../../include/geometry/CGeometry.hpp" +#include "../../include/toolboxes/printing_toolbox.hpp" CMirror::CMirror(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { - Set_TransferCoeff(config); + using PrintingToolbox::to_string; + if (jZone < iZone) { + SU2_MPI::Error(string("The order of the zones does not allow conservative interpolation to be setup.\n" + "Swap zones ") + to_string(iZone) + string(" and ") + to_string(jZone) + string("."),CURRENT_FUNCTION); + } + SetTransferCoeff(config); } -void CMirror::Set_TransferCoeff(const CConfig* const* config) { +void CMirror::SetTransferCoeff(const CConfig* const* config) { const int nProcessor = size; @@ -54,10 +60,10 @@ void CMirror::Set_TransferCoeff(const CConfig* const* config) { */ /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - const auto markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + const auto markDonor = FindInterfaceMarker(config[donorZone], iMarkerInt); /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - const auto markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); + const auto markTarget = FindInterfaceMarker(config[targetZone], iMarkerInt); /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ if(!CheckInterfaceBoundary(markDonor, markTarget)) continue; diff --git a/Common/src/interface_interpolation/CNearestNeighbor.cpp b/Common/src/interface_interpolation/CNearestNeighbor.cpp index 580dcb7e460b..ff7569129a2a 100644 --- a/Common/src/interface_interpolation/CNearestNeighbor.cpp +++ b/Common/src/interface_interpolation/CNearestNeighbor.cpp @@ -47,7 +47,7 @@ struct DonorInfo { CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { - Set_TransferCoeff(config); + SetTransferCoeff(config); } void CNearestNeighbor::PrintStatistics() const { @@ -55,7 +55,7 @@ void CNearestNeighbor::PrintStatistics() const { cout << " Avg/max distance to closest donor point: " << AvgDistance << "/" << MaxDistance << endl; } -void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { +void CNearestNeighbor::SetTransferCoeff(const CConfig* const* config) { /*--- Desired number of donor points. ---*/ const auto nDonor = max(config[donorZone]->GetNumNearestNeighbors(), 1); @@ -79,10 +79,10 @@ void CNearestNeighbor::Set_TransferCoeff(const CConfig* const* config) { for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ - const auto markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + const auto markDonor = FindInterfaceMarker(config[donorZone], iMarkerInt); /*--- On the target side: find the tag of the boundary sharing the interface. ---*/ - const auto markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); + const auto markTarget = FindInterfaceMarker(config[targetZone], iMarkerInt); /*--- Checks if the zone contains the interface, if not continue to the next step. ---*/ if (!CheckInterfaceBoundary(markDonor, markTarget)) continue; diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp index 4eb5d574be45..7881ee994b4d 100644 --- a/Common/src/interface_interpolation/CRadialBasisFunction.cpp +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -47,7 +47,7 @@ extern "C" void dgemm_(const char*, const char*, const int*, const int*, const i CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { - Set_TransferCoeff(config); + SetTransferCoeff(config); } void CRadialBasisFunction::PrintStatistics() const { @@ -93,7 +93,7 @@ su2double CRadialBasisFunction::Get_RadialBasisValue(ENUM_RADIALBASIS type, cons return rbf; } -void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { +void CRadialBasisFunction::SetTransferCoeff(const CConfig* const* config) { /*--- RBF options. ---*/ const auto kindRBF = static_cast(config[donorZone]->GetKindRadialBasisFunction()); @@ -121,10 +121,10 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { for (unsigned short iMarkerInt = 0; iMarkerInt < nMarkerInt; ++iMarkerInt) { /*--- On the donor side: find the tag of the boundary sharing the interface. ---*/ - const auto markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt+1); + const auto markDonor = FindInterfaceMarker(config[donorZone], iMarkerInt+1); /*--- On the target side: find the tag of the boundary sharing the interface. ---*/ - const auto markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); + const auto markTarget = FindInterfaceMarker(config[targetZone], iMarkerInt+1); /*--- If the zone does not contain the interface continue to the next pair of markers. ---*/ if (!CheckInterfaceBoundary(markDonor,markTarget)) continue; @@ -230,7 +230,7 @@ void CRadialBasisFunction::Set_TransferCoeff(const CConfig* const* config) { if (iProcessor < 0) continue; /*--- Setup target information. ---*/ - const int markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt+1); + const int markTarget = FindInterfaceMarker(config[targetZone], iMarkerInt+1); unsigned long nVertexTarget = 0; if (markTarget != -1) nVertexTarget = target_geometry->GetnVertex(markTarget); diff --git a/Common/src/interface_interpolation/CSlidingMesh.cpp b/Common/src/interface_interpolation/CSlidingMesh.cpp index a79b96dbd593..979d3df45e74 100644 --- a/Common/src/interface_interpolation/CSlidingMesh.cpp +++ b/Common/src/interface_interpolation/CSlidingMesh.cpp @@ -33,10 +33,10 @@ CSlidingMesh::CSlidingMesh(CGeometry ****geometry_container, const CConfig* const* config, unsigned int iZone, unsigned int jZone) : CInterpolator(geometry_container, config, iZone, jZone) { - Set_TransferCoeff(config); + SetTransferCoeff(config); } -void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { +void CSlidingMesh::SetTransferCoeff(const CConfig* const* config) { /* 0 - Variable declaration */ @@ -123,10 +123,10 @@ void CSlidingMesh::Set_TransferCoeff(const CConfig* const* config) { for ( iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++ ){ /*--- On the donor side: find the tag of the boundary sharing the interface ---*/ - markDonor = Find_InterfaceMarker(config[donorZone], iMarkerInt); + markDonor = FindInterfaceMarker(config[donorZone], iMarkerInt); /*--- On the target side: find the tag of the boundary sharing the interface ---*/ - markTarget = Find_InterfaceMarker(config[targetZone], iMarkerInt); + markTarget = FindInterfaceMarker(config[targetZone], iMarkerInt); /*--- Checks if the zone contains the interface, if not continue to the next step ---*/ if(!CheckInterfaceBoundary(markDonor, markTarget)) continue; diff --git a/Common/src/interface_interpolation/meson.build b/Common/src/interface_interpolation/meson.build index 3e1d1a49b2e4..8624b3ad4fa8 100644 --- a/Common/src/interface_interpolation/meson.build +++ b/Common/src/interface_interpolation/meson.build @@ -1,4 +1,5 @@ -common_src += files(['CInterpolator.cpp', +common_src += files(['CInterpolatorFactory.cpp', + 'CInterpolator.cpp', 'CMirror.cpp', 'CSlidingMesh.cpp', 'CIsoparametric.cpp', diff --git a/SU2_CFD/include/drivers/CDriver.hpp b/SU2_CFD/include/drivers/CDriver.hpp index b73b1b114908..3a1f0595f79c 100644 --- a/SU2_CFD/include/drivers/CDriver.hpp +++ b/SU2_CFD/include/drivers/CDriver.hpp @@ -205,7 +205,7 @@ class CDriver { */ void Interface_Preprocessing(CConfig **config, CSolver *****solver, CGeometry ****geometry, unsigned short **interface_types, CInterface ***&interface, - CInterpolator ***&interpolation); + CInterpolator ***interpolation); /*! * \brief Definition and allocation of all solver classes. diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index a30f52500411..88090402a667 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -38,11 +38,8 @@ #include "../../include/output/COutputFactory.hpp" #include "../../include/output/COutputLegacy.hpp" -#include "../../../Common/include/interface_interpolation/CMirror.hpp" -#include "../../../Common/include/interface_interpolation/CSlidingMesh.hpp" -#include "../../../Common/include/interface_interpolation/CIsoparametric.hpp" -#include "../../../Common/include/interface_interpolation/CNearestNeighbor.hpp" -#include "../../../Common/include/interface_interpolation/CRadialBasisFunction.hpp" +#include "../../../Common/include/interface_interpolation/CInterpolator.hpp" +#include "../../../Common/include/interface_interpolation/CInterpolatorFactory.hpp" #include "../../include/interfaces/cfd/CConservativeVarsInterface.hpp" #include "../../include/interfaces/cfd/CMixingPlaneInterface.hpp" @@ -2499,171 +2496,64 @@ void CDriver::DynamicMesh_Preprocessing(CConfig *config, CGeometry **geometry, C void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGeometry**** geometry, unsigned short** interface_types, CInterface ***&interface, - CInterpolator ***&interpolation) { + CInterpolator ***interpolation) { - unsigned short donorZone, targetZone; - unsigned short nVar, nVarTransfer; + /*--- Setup interpolation and transfer for all possible donor/target pairs. ---*/ - /*--- Initialize some useful booleans ---*/ - bool fluid_donor, structural_donor, heat_donor; - bool fluid_target, structural_target, heat_target; - - const bool discrete_adjoint = config[ZONE_0]->GetDiscrete_Adjoint(); + for (auto targetZone = 0u; targetZone < nZone; targetZone++) { - /*--- Coupling between zones ---*/ - // There's a limit here, the interface boundary must connect only 2 zones + for (auto donorZone = 0u; donorZone < nZone; donorZone++) { - /*--- Loops over all target and donor zones to find which ones are connected through - *--- an interface boundary (fsi or sliding mesh) ---*/ - for (targetZone = 0; targetZone < nZone; targetZone++) { - - for (donorZone = 0; donorZone < nZone; donorZone++) { + /*--- Alias to make code less verbose. ---*/ + auto& interface_type = interface_types[donorZone][targetZone]; - interface_types[donorZone][targetZone] = NO_TRANSFER; - - if ( donorZone == targetZone ) { - interface_types[donorZone][targetZone] = ZONES_ARE_EQUAL; - // We're processing the same zone, so skip the following + if (donorZone == targetZone) { + interface_type = ZONES_ARE_EQUAL; continue; } + interface_type = NO_TRANSFER; - const auto nMarkerInt = config[donorZone]->GetMarker_n_ZoneInterface() / 2; - - /*--- Loops on Interface markers to find if the 2 zones are sharing the boundary and to - *--- determine donor and target marker tag ---*/ - for (unsigned short iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { - - /* --- Check if zones are actually sharing the interface boundary, if not skip. ---*/ - if(!CInterpolator::CheckInterfaceBoundary(CInterpolator::Find_InterfaceMarker(config[donorZone],iMarkerInt), - CInterpolator::Find_InterfaceMarker(config[targetZone],iMarkerInt))) { - interface_types[donorZone][targetZone] = NO_COMMON_INTERFACE; - continue; - } - - /*--- Set some boolean to properly allocate data structure later ---*/ - fluid_target = false; - structural_target = false; - - fluid_donor = false; - structural_donor = false; - - heat_donor = false; - heat_target = false; - - switch ( config[targetZone]->GetKind_Solver() ) { - - case EULER : case NAVIER_STOKES: case RANS: - case INC_EULER : case INC_NAVIER_STOKES: case INC_RANS: - case DISC_ADJ_INC_EULER: case DISC_ADJ_INC_NAVIER_STOKES: case DISC_ADJ_INC_RANS: - case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: - fluid_target = true; - break; - - case FEM_ELASTICITY: case DISC_ADJ_FEM: - structural_target = true; - break; - - case HEAT_EQUATION: case DISC_ADJ_HEAT: - heat_target = true; - break; - } - - switch ( config[donorZone]->GetKind_Solver() ) { - - case EULER : case NAVIER_STOKES: case RANS: - case INC_EULER : case INC_NAVIER_STOKES: case INC_RANS: - case DISC_ADJ_INC_EULER: case DISC_ADJ_INC_NAVIER_STOKES: case DISC_ADJ_INC_RANS: - case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: - fluid_donor = true; - break; - - case FEM_ELASTICITY: case DISC_ADJ_FEM: - structural_donor = true; - break; - - case HEAT_EQUATION : case DISC_ADJ_HEAT: - heat_donor = true; - break; - } + /*--- If there is a common interface setup the interpolation and transfer. ---*/ + if (!CInterpolator::CheckZonesInterface(config[donorZone], config[targetZone])) { + interface_type = NO_COMMON_INTERFACE; + } + else { /*--- Begin the creation of the communication pattern among zones ---*/ - /*--- Retrieve the number of conservative variables (for problems not involving structural analysis ---*/ - if (fluid_donor && fluid_target) - nVar = solver[donorZone][INST_0][MESH_0][FLOW_SOL]->GetnVar(); - else - /*--- If at least one of the components is structural ---*/ - nVar = nDim; - if (rank == MASTER_NODE) cout << "From zone " << donorZone << " to zone " << targetZone << ": "; - /*--- Match Zones ---*/ - if (rank == MASTER_NODE) cout << "Setting coupling "; - - bool conservative_interp = config[donorZone]->GetConservativeInterpolation(); + /*--- Setup the interpolation. ---*/ - /*--- Conditions for conservative interpolation are not met, we cannot fallback on the consistent approach - because CFlowTractionInterface relies on the information in config to be correct. ---*/ - if ( conservative_interp && targetZone == 0 && structural_target ) - SU2_MPI::Error("Conservative interpolation assumes the structural model mesh is evaluated second, " - "somehow this has not happened.",CURRENT_FUNCTION); + interpolation[donorZone][targetZone] = CInterpolatorFactory::createInterpolator(geometry, config, donorZone, targetZone); - switch (config[donorZone]->GetKindInterpolation()) { + /*--- The type of variables transferred depends on the donor/target physics. ---*/ - case NEAREST_NEIGHBOR: - if ( conservative_interp && targetZone > 0 && structural_target ) { - interpolation[donorZone][targetZone] = new CMirror(geometry, config, donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using a mirror approach: matching coefficients " - "from opposite mesh." << endl; - } - else { - interpolation[donorZone][targetZone] = new CNearestNeighbor(geometry, config, donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using a nearest-neighbor approach." << endl; - } - break; + const bool heat_target = config[targetZone]->GetHeatProblem(); + const bool fluid_target = config[targetZone]->GetFluidProblem(); + const bool structural_target = config[targetZone]->GetStructuralProblem(); - case ISOPARAMETRIC: - if ( conservative_interp && targetZone > 0 && structural_target ) { - interpolation[donorZone][targetZone] = new CMirror(geometry, config, donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using a mirror approach: matching coefficients " - "from opposite mesh." << endl; - } - else { - interpolation[donorZone][targetZone] = new CIsoparametric(geometry, config, donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using an isoparametric approach." << endl; - } - break; + const bool heat_donor = config[donorZone]->GetHeatProblem(); + const bool fluid_donor = config[donorZone]->GetFluidProblem(); + const bool structural_donor = config[donorZone]->GetStructuralProblem(); - case WEIGHTED_AVERAGE: - interpolation[donorZone][targetZone] = new CSlidingMesh(geometry, config, donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using an sliding mesh approach." << endl; + /*--- Retrieve the number of conservative variables as default. ---*/ - break; + auto nVar = solver[donorZone][INST_0][MESH_0][FLOW_SOL]->GetnVar(); - case RADIAL_BASIS_FUNCTION: - if ( conservative_interp && targetZone > 0 && structural_target ) { - interpolation[donorZone][targetZone] = new CMirror(geometry, config, donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using a mirror approach: matching coefficients " - "from opposite mesh." << endl; - } - else { - interpolation[donorZone][targetZone] = new CRadialBasisFunction(geometry, config, - donorZone, targetZone); - if (rank == MASTER_NODE) cout << "using a radial basis function approach." << endl; - } - break; - } + /*--- If at least one of the zones is structural. ---*/ + if (structural_donor || structural_target) nVar = nDim; - if (interpolation[donorZone][targetZone]) - interpolation[donorZone][targetZone]->PrintStatistics(); + /*--- If at least one of the zones has heat transfer. ---*/ + if (heat_donor || heat_target) nVar = 4; /*--- Initialize the appropriate transfer strategy ---*/ if (rank == MASTER_NODE) cout << "Transferring "; if (fluid_donor && structural_target) { - interface_types[donorZone][targetZone] = FLOW_TRACTION; - nVarTransfer = 2; - if(!discrete_adjoint) { + interface_type = FLOW_TRACTION; + auto nVarTransfer = 2; + if(!config[ZONE_0]->GetDiscrete_Adjoint()) { interface[donorZone][targetZone] = new CFlowTractionInterface(nVar, nVarTransfer, config[donorZone]); } else { interface[donorZone][targetZone] = new CDiscAdjFlowTractionInterface(nVar, nVarTransfer, config[donorZone]); @@ -2675,62 +2565,51 @@ void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGe SU2_MPI::Error("Mesh deformation was not correctly specified for the fluid zone.\n" "Use DEFORM_MESH=YES, and setup MARKER_DEFORM_MESH=(...)", CURRENT_FUNCTION); } - interface_types[donorZone][targetZone] = BOUNDARY_DISPLACEMENTS; - nVarTransfer = 0; - interface[donorZone][targetZone] = new CDisplacementsInterface(nVar, nVarTransfer, config[donorZone]); - if (rank == MASTER_NODE) cout << "boundary displacements from the structural solver. " << endl; + interface_type = BOUNDARY_DISPLACEMENTS; + interface[donorZone][targetZone] = new CDisplacementsInterface(nVar, 0, config[donorZone]); + if (rank == MASTER_NODE) cout << "boundary displacements from the structural solver." << endl; } else if (fluid_donor && fluid_target) { - interface_types[donorZone][targetZone] = SLIDING_INTERFACE; - nVarTransfer = 0; + interface_type = SLIDING_INTERFACE; nVar = solver[donorZone][INST_0][MESH_0][FLOW_SOL]->GetnPrimVar(); - interface[donorZone][targetZone] = new CSlidingInterface(nVar, nVarTransfer, config[donorZone]); - if (rank == MASTER_NODE) cout << "sliding interface. " << endl; - } - else if (fluid_donor && heat_target) { - nVarTransfer = 0; - nVar = 4; - if(config[donorZone]->GetEnergy_Equation() || (config[donorZone]->GetKind_Regime() == COMPRESSIBLE)) - interface_types[donorZone][targetZone] = CONJUGATE_HEAT_FS; - else if (config[donorZone]->GetWeakly_Coupled_Heat()) - interface_types[donorZone][targetZone] = CONJUGATE_HEAT_WEAKLY_FS; - else { } - interface[donorZone][targetZone] = new CConjugateHeatInterface(nVar, nVarTransfer, config[donorZone]); - if (rank == MASTER_NODE) cout << "conjugate heat variables. " << endl; + interface[donorZone][targetZone] = new CSlidingInterface(nVar, 0, config[donorZone]); + if (rank == MASTER_NODE) cout << "sliding interface." << endl; } - else if (heat_donor && fluid_target) { - nVarTransfer = 0; - nVar = 4; - if(config[targetZone]->GetEnergy_Equation() || (config[targetZone]->GetKind_Regime() == COMPRESSIBLE)) - interface_types[donorZone][targetZone] = CONJUGATE_HEAT_SF; - else if (config[targetZone]->GetWeakly_Coupled_Heat()) - interface_types[donorZone][targetZone] = CONJUGATE_HEAT_WEAKLY_SF; - else { } - interface[donorZone][targetZone] = new CConjugateHeatInterface(nVar, nVarTransfer, config[donorZone]); - if (rank == MASTER_NODE) cout << "conjugate heat variables. " << endl; - } - else if (heat_donor && heat_target) { - SU2_MPI::Error("Conjugate heat transfer between solids not implemented yet.", CURRENT_FUNCTION); + else if (heat_donor || heat_target) { + if (heat_donor && heat_target) + SU2_MPI::Error("Conjugate heat transfer between solids is not implemented.", CURRENT_FUNCTION); + + const auto fluidZone = heat_target? donorZone : targetZone; + + if(config[fluidZone]->GetEnergy_Equation() || (config[fluidZone]->GetKind_Regime() == COMPRESSIBLE)) + interface_type = heat_target? CONJUGATE_HEAT_FS : CONJUGATE_HEAT_SF; + else if (config[fluidZone]->GetWeakly_Coupled_Heat()) + interface_type = heat_target? CONJUGATE_HEAT_WEAKLY_FS : CONJUGATE_HEAT_WEAKLY_SF; + else + interface_type = NO_TRANSFER; + + if (interface_type != NO_TRANSFER) { + interface[donorZone][targetZone] = new CConjugateHeatInterface(nVar, 0, config[donorZone]); + if (rank == MASTER_NODE) cout << "conjugate heat variables." << endl; + } } else { - interface_types[donorZone][targetZone] = CONSERVATIVE_VARIABLES; - nVarTransfer = 0; - interface[donorZone][targetZone] = new CConservativeVarsInterface(nVar, nVarTransfer, config[donorZone]); - if (rank == MASTER_NODE) cout << "generic conservative variables. " << endl; + interface_type = CONSERVATIVE_VARIABLES; + interface[donorZone][targetZone] = new CConservativeVarsInterface(nVar, 0, config[donorZone]); + if (rank == MASTER_NODE) cout << "generic conservative variables." << endl; } - - break; - } - if (config[donorZone]->GetBoolMixingPlaneInterface()){ - interface_types[donorZone][targetZone] = MIXING_PLANE; - nVarTransfer = 0; - nVar = solver[donorZone][INST_0][MESH_0][FLOW_SOL]->GetnVar(); - interface[donorZone][targetZone] = new CMixingPlaneInterface(nVar, nVarTransfer, - config[donorZone], config[targetZone]); - if (rank == MASTER_NODE) cout << "Set mixing-plane interface from donor zone "<< donorZone - << " to target zone " << targetZone <<"."<GetBoolMixingPlaneInterface()) { + interface_type = MIXING_PLANE; + auto nVar = solver[donorZone][INST_0][MESH_0][FLOW_SOL]->GetnVar(); + interface[donorZone][targetZone] = new CMixingPlaneInterface(nVar, 0, config[donorZone], config[targetZone]); + if (rank == MASTER_NODE) { + cout << "Set mixing-plane interface from donor zone " + << donorZone << " to target zone " << targetZone << "." << endl; + } } } @@ -3143,7 +3022,7 @@ void CFluidDriver::Run() { for (iZone = 0; iZone < nZone; iZone++) { for (jZone = 0; jZone < nZone; jZone++) if(jZone != iZone && interpolator_container[iZone][jZone] != NULL) - interpolator_container[iZone][jZone]->Set_TransferCoeff(config_container); + interpolator_container[iZone][jZone]->SetTransferCoeff(config_container); } } diff --git a/SU2_CFD/src/drivers/CMultizoneDriver.cpp b/SU2_CFD/src/drivers/CMultizoneDriver.cpp index 62696f542350..ec76280e1d38 100644 --- a/SU2_CFD/src/drivers/CMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CMultizoneDriver.cpp @@ -285,7 +285,7 @@ void CMultizoneDriver::Preprocess(unsigned long TimeIter) { for (iZone = 0; iZone < nZone; iZone++) { for (unsigned short jZone = 0; jZone < nZone; jZone++){ if(jZone != iZone && interpolator_container[iZone][jZone] != NULL && prefixed_motion[iZone]) - interpolator_container[iZone][jZone]->Set_TransferCoeff(config_container); + interpolator_container[iZone][jZone]->SetTransferCoeff(config_container); } } } diff --git a/SU2_CFD/src/interfaces/CInterface.cpp b/SU2_CFD/src/interfaces/CInterface.cpp index 3c83c3cf4a88..b871cb8a4c18 100644 --- a/SU2_CFD/src/interfaces/CInterface.cpp +++ b/SU2_CFD/src/interfaces/CInterface.cpp @@ -95,8 +95,8 @@ void CInterface::BroadcastData(CSolver *donor_solution, CSolver *target_solution /*--- Check if this interface connects the two zones, if not continue. ---*/ - Marker_Donor = CInterpolator::Find_InterfaceMarker(donor_config, iMarkerInt); - Marker_Target = CInterpolator::Find_InterfaceMarker(target_config, iMarkerInt); + Marker_Donor = CInterpolator::FindInterfaceMarker(donor_config, iMarkerInt); + Marker_Target = CInterpolator::FindInterfaceMarker(target_config, iMarkerInt); if(!CInterpolator::CheckInterfaceBoundary(Marker_Donor, Marker_Target)) continue; diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index f3faee5dd87f..1a62c80feb77 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -1365,9 +1365,9 @@ void CMeshSolver::Surface_Translating(CGeometry *geometry, CConfig *config, unsi /*-- Check if we want to update the motion origin for the given marker ---*/ if (config->GetMoveMotion_Origin(jMarker) == YES) { - for (iDim = 0; iDim < 3; iDim++){ + for (iDim = 0; iDim < 3; iDim++) Center[iDim] += VarCoord[iDim]; - } + config->SetMarkerMotion_Origin(Center, jMarker); } } From 34143137c70e8f67c70b43ed196a71431dc20933 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sun, 5 Apr 2020 11:31:44 +0100 Subject: [PATCH 75/79] missing new files --- .../CInterpolatorFactory.hpp | 52 +++++++++++ .../CInterpolatorFactory.cpp | 90 +++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 Common/include/interface_interpolation/CInterpolatorFactory.hpp create mode 100644 Common/src/interface_interpolation/CInterpolatorFactory.cpp diff --git a/Common/include/interface_interpolation/CInterpolatorFactory.hpp b/Common/include/interface_interpolation/CInterpolatorFactory.hpp new file mode 100644 index 000000000000..72189e6e7a07 --- /dev/null +++ b/Common/include/interface_interpolation/CInterpolatorFactory.hpp @@ -0,0 +1,52 @@ +/*! + * \file CInterpolatorFactory.hpp + * \brief Factory to generate interpolator objects. + * \version 7.0.3 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#pragma once + +class CConfig; +class CGeometry; +class CInterpolator; + +/*! + * \namespace CInterpolatorFactory + * \brief Factory methods for CInterpolator objects. + */ +namespace CInterpolatorFactory { + +/*! + * \brief The factory method. + * \param[in] geometry_container - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the donor zone. + * \param[in] jZone - Index of the target zone. + * \param[in] verbose - If true, print information to screen. + * \return Pointer to interpolator on the heap, caller is responsible for deletion. + */ +CInterpolator* createInterpolator(CGeometry ****geometry_container, + const CConfig* const* config, + unsigned iZone, unsigned jZone, + bool verbose = true); + +} diff --git a/Common/src/interface_interpolation/CInterpolatorFactory.cpp b/Common/src/interface_interpolation/CInterpolatorFactory.cpp new file mode 100644 index 000000000000..94385c893330 --- /dev/null +++ b/Common/src/interface_interpolation/CInterpolatorFactory.cpp @@ -0,0 +1,90 @@ +/*! + * \file CInterpolatorFactory.cpp + * \brief Factory to generate interpolator objects. + * \version 7.0.3 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "../../include/CConfig.hpp" + +#include "../../include/interface_interpolation/CInterpolatorFactory.hpp" +#include "../../include/interface_interpolation/CIsoparametric.hpp" +#include "../../include/interface_interpolation/CMirror.hpp" +#include "../../include/interface_interpolation/CNearestNeighbor.hpp" +#include "../../include/interface_interpolation/CRadialBasisFunction.hpp" +#include "../../include/interface_interpolation/CSlidingMesh.hpp" + +namespace CInterpolatorFactory { +CInterpolator* createInterpolator(CGeometry ****geometry_container, + const CConfig* const* config, + unsigned iZone, unsigned jZone, bool verbose) { + + CInterpolator* interpolator = nullptr; + + /*--- Only print information on master node. ---*/ + verbose &= (SU2_MPI::GetRank() == MASTER_NODE); + + /*--- Type of interpolation defined by donor. ---*/ + const auto type = config[iZone]->GetKindInterpolation(); + + if (verbose) cout << "Setting coupling "; + + /*--- Conservative interpolation is not applicable to the sliding + * mesh approach so that case is handled first. Then we either + * return a CMirror if the target requires conservative inter- + * polation, or the type of interpolator defined by "type". ---*/ + + if (type == WEIGHTED_AVERAGE) { + if (verbose) cout << "using a sliding mesh approach." << endl; + interpolator = new CSlidingMesh(geometry_container, config, iZone, jZone); + } + else if (config[jZone]->GetConservativeInterpolation()) { + if (verbose) cout << "using a mirror approach, \"transposing\" coefficients from opposite mesh." << endl; + interpolator = new CMirror(geometry_container, config, iZone, jZone); + } + else { + switch(type) { + case ISOPARAMETRIC: + if (verbose) cout << "using the isoparametric approach." << endl; + interpolator = new CIsoparametric(geometry_container, config, iZone, jZone); + break; + + case NEAREST_NEIGHBOR: + if (verbose) cout << "using a nearest-neighbor approach." << endl; + interpolator = new CNearestNeighbor(geometry_container, config, iZone, jZone); + break; + + case RADIAL_BASIS_FUNCTION: + if (verbose) cout << "using a radial basis function approach." << endl; + interpolator = new CRadialBasisFunction(geometry_container, config, iZone, jZone); + break; + + default: + SU2_MPI::Error("Unknown type of interpolation.", CURRENT_FUNCTION); + } + } + + if (verbose) interpolator->PrintStatistics(); + + return interpolator; +} +} // end namespace From 3068862a559e6cd8d26820b7640c5c297ad41f96 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sun, 5 Apr 2020 16:14:25 +0100 Subject: [PATCH 76/79] fix fsi and cht problems --- .../CInterpolatorFactory.cpp | 2 +- .../CIsoparametric.cpp | 4 +- .../CNearestNeighbor.cpp | 2 +- .../CRadialBasisFunction.cpp | 6 +- SU2_CFD/include/drivers/CDriver.hpp | 2 +- .../fsi/CDiscAdjFlowTractionInterface.hpp | 21 +---- .../interfaces/fsi/CFlowTractionInterface.hpp | 29 +++---- SU2_CFD/src/drivers/CDriver.cpp | 81 +++++++++---------- .../fsi/CDiscAdjFlowTractionInterface.cpp | 13 +-- .../interfaces/fsi/CFlowTractionInterface.cpp | 34 +++----- SU2_CFD/src/solvers/CFEASolver.cpp | 3 +- SU2_CFD/src/solvers/CMeshSolver.cpp | 9 ++- 12 files changed, 85 insertions(+), 121 deletions(-) diff --git a/Common/src/interface_interpolation/CInterpolatorFactory.cpp b/Common/src/interface_interpolation/CInterpolatorFactory.cpp index 94385c893330..7a02ebabb1a7 100644 --- a/Common/src/interface_interpolation/CInterpolatorFactory.cpp +++ b/Common/src/interface_interpolation/CInterpolatorFactory.cpp @@ -46,7 +46,7 @@ CInterpolator* createInterpolator(CGeometry ****geometry_container, /*--- Type of interpolation defined by donor. ---*/ const auto type = config[iZone]->GetKindInterpolation(); - if (verbose) cout << "Setting coupling "; + if (verbose) cout << " Setting coupling "; /*--- Conservative interpolation is not applicable to the sliding * mesh approach so that case is handled first. Then we either diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp index fcad8d936d9a..fc64e5e9a720 100644 --- a/Common/src/interface_interpolation/CIsoparametric.cpp +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -55,8 +55,8 @@ CIsoparametric::CIsoparametric(CGeometry ****geometry_container, const CConfig* void CIsoparametric::PrintStatistics(void) const { if (rank != MASTER_NODE) return; - cout << " Maximum distance to closest donor element: " << MaxDistance << ".\n" - << " Interpolation mitigated for " << ErrorCounter << " (" << ErrorRate << "%) target vertices." << endl; + cout << " Maximum distance to closest donor element: " << MaxDistance << ".\n" + << " Interpolation mitigated for " << ErrorCounter << " (" << ErrorRate << "%) target vertices." << endl; } void CIsoparametric::SetTransferCoeff(const CConfig* const* config) { diff --git a/Common/src/interface_interpolation/CNearestNeighbor.cpp b/Common/src/interface_interpolation/CNearestNeighbor.cpp index ff7569129a2a..1ab489bd8d94 100644 --- a/Common/src/interface_interpolation/CNearestNeighbor.cpp +++ b/Common/src/interface_interpolation/CNearestNeighbor.cpp @@ -52,7 +52,7 @@ CNearestNeighbor::CNearestNeighbor(CGeometry ****geometry_container, const CConf void CNearestNeighbor::PrintStatistics() const { if (rank != MASTER_NODE) return; - cout << " Avg/max distance to closest donor point: " << AvgDistance << "/" << MaxDistance << endl; + cout << " Avg/max distance to closest donor point: " << AvgDistance << "/" << MaxDistance << endl; } void CNearestNeighbor::SetTransferCoeff(const CConfig* const* config) { diff --git a/Common/src/interface_interpolation/CRadialBasisFunction.cpp b/Common/src/interface_interpolation/CRadialBasisFunction.cpp index 7881ee994b4d..909f852eb535 100644 --- a/Common/src/interface_interpolation/CRadialBasisFunction.cpp +++ b/Common/src/interface_interpolation/CRadialBasisFunction.cpp @@ -53,13 +53,13 @@ CRadialBasisFunction::CRadialBasisFunction(CGeometry ****geometry_container, con void CRadialBasisFunction::PrintStatistics() const { if (rank != MASTER_NODE) return; cout.precision(3); - cout << " Min/avg/max number of RBF donors per target point: " + cout << " Min/avg/max number of RBF donors per target point: " << MinDonors << "/" << AvgDonors << "/" << MaxDonors << "\n" - << " Avg/max correction factor after pruning: " << AvgCorrection << "/" << MaxCorrection; + << " Avg/max correction factor after pruning: " << AvgCorrection << "/" << MaxCorrection; if (MaxCorrection < 1.1 || AvgCorrection < 1.02) cout << " (ok)\n"; else if (MaxCorrection < 2.0 && AvgCorrection < 1.05) cout << " (warning)\n"; else cout << " <<< WARNING >>>\n"; - cout << " Interpolation matrix is " << Density << "% dense." << endl; + cout << " Interpolation matrix is " << Density << "% dense." << endl; cout.unsetf(ios::floatfield); } diff --git a/SU2_CFD/include/drivers/CDriver.hpp b/SU2_CFD/include/drivers/CDriver.hpp index 3a1f0595f79c..c104b344fd40 100644 --- a/SU2_CFD/include/drivers/CDriver.hpp +++ b/SU2_CFD/include/drivers/CDriver.hpp @@ -204,7 +204,7 @@ class CDriver { * \brief Definition and allocation of all interface classes. */ void Interface_Preprocessing(CConfig **config, CSolver *****solver, CGeometry ****geometry, - unsigned short **interface_types, CInterface ***&interface, + unsigned short **interface_types, CInterface ***interface, CInterpolator ***interpolation); /*! diff --git a/SU2_CFD/include/interfaces/fsi/CDiscAdjFlowTractionInterface.hpp b/SU2_CFD/include/interfaces/fsi/CDiscAdjFlowTractionInterface.hpp index 8dd8dd5cf216..303ba00f5160 100644 --- a/SU2_CFD/include/interfaces/fsi/CDiscAdjFlowTractionInterface.hpp +++ b/SU2_CFD/include/interfaces/fsi/CDiscAdjFlowTractionInterface.hpp @@ -7,7 +7,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -31,27 +31,14 @@ #include "CFlowTractionInterface.hpp" class CDiscAdjFlowTractionInterface : public CFlowTractionInterface { - -protected: - public: - - /*! - * \brief Constructor of the class. - */ - CDiscAdjFlowTractionInterface(void); - /*! * \overload * \param[in] val_nVar - Number of variables that need to be transferred. * \param[in] config - Definition of the particular problem. */ - CDiscAdjFlowTractionInterface(unsigned short val_nVar, unsigned short val_nConst, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - virtual ~CDiscAdjFlowTractionInterface(void); + CDiscAdjFlowTractionInterface(unsigned short val_nVar, unsigned short val_nConst, + CConfig *config, bool integrate_tractions_); /*! * \brief Retrieve some constants needed for the calculations. @@ -64,6 +51,6 @@ class CDiscAdjFlowTractionInterface : public CFlowTractionInterface { */ void GetPhysical_Constants(CSolver *donor_solution, CSolver *target_solution, CGeometry *donor_geometry, CGeometry *target_geometry, - CConfig *donor_config, CConfig *target_config); + CConfig *donor_config, CConfig *target_config) override; }; diff --git a/SU2_CFD/include/interfaces/fsi/CFlowTractionInterface.hpp b/SU2_CFD/include/interfaces/fsi/CFlowTractionInterface.hpp index fefd56afa569..2e338f5cf875 100644 --- a/SU2_CFD/include/interfaces/fsi/CFlowTractionInterface.hpp +++ b/SU2_CFD/include/interfaces/fsi/CFlowTractionInterface.hpp @@ -7,7 +7,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -31,10 +31,10 @@ #include "../CInterface.hpp" class CFlowTractionInterface : public CInterface { +private: + bool integrate_tractions; protected: - bool consistent_interpolation; - /*! * \brief Sets the dimensional factor for pressure and the consistent_interpolation flag * \param[in] flow_config - Definition of the fluid (donor) problem. @@ -42,23 +42,16 @@ class CFlowTractionInterface : public CInterface { void Preprocess(CConfig *flow_config); public: - - /*! - * \brief Constructor of the class. - */ - CFlowTractionInterface(void); - /*! * \overload * \param[in] val_nVar - Number of variables that need to be transferred. + * \param[in] val_nConst - Number of constants. * \param[in] config - Definition of the particular problem. + * \param[in] integrate_tractions_ - Whether to integrate the fluid tractions + * (to transfer forces when using conservative interpolation). */ - CFlowTractionInterface(unsigned short val_nVar, unsigned short val_nConst, CConfig *config); - - /*! - * \brief Destructor of the class. - */ - virtual ~CFlowTractionInterface(void); + CFlowTractionInterface(unsigned short val_nVar, unsigned short val_nConst, + CConfig *config, bool integrate_tractions_); /*! * \brief Retrieve some constants needed for the calculations. @@ -71,7 +64,7 @@ class CFlowTractionInterface : public CInterface { */ void GetPhysical_Constants(CSolver *donor_solution, CSolver *target_solution, CGeometry *donor_geometry, CGeometry *target_geometry, - CConfig *donor_config, CConfig *target_config); + CConfig *donor_config, CConfig *target_config) override; /*! * \brief Retrieve the variable that will be sent from donor mesh to target mesh. @@ -82,7 +75,7 @@ class CFlowTractionInterface : public CInterface { * \param[in] Vertex_Donor - Index of the donor vertex. */ void GetDonor_Variable(CSolver *flow_solution, CGeometry *flow_geometry, CConfig *flow_config, - unsigned long Marker_Flow, unsigned long Vertex_Flow, unsigned long Point_Flow); + unsigned long Marker_Flow, unsigned long Vertex_Flow, unsigned long Point_Flow) override; /*! * \brief Set the variable that has been received from the target mesh into the target mesh. @@ -95,6 +88,6 @@ class CFlowTractionInterface : public CInterface { */ void SetTarget_Variable(CSolver *fea_solution, CGeometry *fea_geometry, CConfig *fea_config, unsigned long Marker_Struct, - unsigned long Vertex_Struct, unsigned long Point_Struct); + unsigned long Vertex_Struct, unsigned long Point_Struct) override; }; diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index 88090402a667..bfc54ad39feb 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -2495,19 +2495,19 @@ void CDriver::DynamicMesh_Preprocessing(CConfig *config, CGeometry **geometry, C } void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGeometry**** geometry, - unsigned short** interface_types, CInterface ***&interface, + unsigned short** interface_types, CInterface ***interface, CInterpolator ***interpolation) { /*--- Setup interpolation and transfer for all possible donor/target pairs. ---*/ - for (auto targetZone = 0u; targetZone < nZone; targetZone++) { + for (auto target = 0u; target < nZone; target++) { - for (auto donorZone = 0u; donorZone < nZone; donorZone++) { + for (auto donor = 0u; donor < nZone; donor++) { - /*--- Alias to make code less verbose. ---*/ - auto& interface_type = interface_types[donorZone][targetZone]; + /*--- Aliases to make code less verbose. ---*/ + auto& interface_type = interface_types[donor][target]; - if (donorZone == targetZone) { + if (donor == target) { interface_type = ZONES_ARE_EQUAL; continue; } @@ -2515,73 +2515,65 @@ void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGe /*--- If there is a common interface setup the interpolation and transfer. ---*/ - if (!CInterpolator::CheckZonesInterface(config[donorZone], config[targetZone])) { + if (!CInterpolator::CheckZonesInterface(config[donor], config[target])) { interface_type = NO_COMMON_INTERFACE; } else { - /*--- Begin the creation of the communication pattern among zones ---*/ + /*--- Begin the creation of the communication pattern among zones. ---*/ - if (rank == MASTER_NODE) cout << "From zone " << donorZone << " to zone " << targetZone << ": "; + if (rank == MASTER_NODE) cout << "From zone " << donor << " to zone " << target << ":" << endl; /*--- Setup the interpolation. ---*/ - interpolation[donorZone][targetZone] = CInterpolatorFactory::createInterpolator(geometry, config, donorZone, targetZone); + interpolation[donor][target] = CInterpolatorFactory::createInterpolator(geometry, config, donor, target); /*--- The type of variables transferred depends on the donor/target physics. ---*/ - const bool heat_target = config[targetZone]->GetHeatProblem(); - const bool fluid_target = config[targetZone]->GetFluidProblem(); - const bool structural_target = config[targetZone]->GetStructuralProblem(); + const bool heat_target = config[target]->GetHeatProblem(); + const bool fluid_target = config[target]->GetFluidProblem(); + const bool structural_target = config[target]->GetStructuralProblem(); - const bool heat_donor = config[donorZone]->GetHeatProblem(); - const bool fluid_donor = config[donorZone]->GetFluidProblem(); - const bool structural_donor = config[donorZone]->GetStructuralProblem(); + const bool heat_donor = config[donor]->GetHeatProblem(); + const bool fluid_donor = config[donor]->GetFluidProblem(); + const bool structural_donor = config[donor]->GetStructuralProblem(); - /*--- Retrieve the number of conservative variables as default. ---*/ + /*--- Initialize the appropriate transfer strategy. ---*/ - auto nVar = solver[donorZone][INST_0][MESH_0][FLOW_SOL]->GetnVar(); - - /*--- If at least one of the zones is structural. ---*/ - if (structural_donor || structural_target) nVar = nDim; - - /*--- If at least one of the zones has heat transfer. ---*/ - if (heat_donor || heat_target) nVar = 4; - - /*--- Initialize the appropriate transfer strategy ---*/ - if (rank == MASTER_NODE) cout << "Transferring "; + if (rank == MASTER_NODE) cout << " Transferring "; if (fluid_donor && structural_target) { interface_type = FLOW_TRACTION; - auto nVarTransfer = 2; + auto nConst = 2; + bool conservative = config[target]->GetConservativeInterpolation(); if(!config[ZONE_0]->GetDiscrete_Adjoint()) { - interface[donorZone][targetZone] = new CFlowTractionInterface(nVar, nVarTransfer, config[donorZone]); + interface[donor][target] = new CFlowTractionInterface(nDim, nConst, config[donor], conservative); } else { - interface[donorZone][targetZone] = new CDiscAdjFlowTractionInterface(nVar, nVarTransfer, config[donorZone]); + interface[donor][target] = new CDiscAdjFlowTractionInterface(nDim, nConst, config[donor], conservative); } if (rank == MASTER_NODE) cout << "flow tractions. " << endl; } else if (structural_donor && fluid_target) { - if (solver_container[targetZone][INST_0][MESH_0][MESH_SOL] == nullptr) { + if (solver_container[target][INST_0][MESH_0][MESH_SOL] == nullptr) { SU2_MPI::Error("Mesh deformation was not correctly specified for the fluid zone.\n" "Use DEFORM_MESH=YES, and setup MARKER_DEFORM_MESH=(...)", CURRENT_FUNCTION); } interface_type = BOUNDARY_DISPLACEMENTS; - interface[donorZone][targetZone] = new CDisplacementsInterface(nVar, 0, config[donorZone]); + interface[donor][target] = new CDisplacementsInterface(nDim, 0, config[donor]); if (rank == MASTER_NODE) cout << "boundary displacements from the structural solver." << endl; } else if (fluid_donor && fluid_target) { interface_type = SLIDING_INTERFACE; - nVar = solver[donorZone][INST_0][MESH_0][FLOW_SOL]->GetnPrimVar(); - interface[donorZone][targetZone] = new CSlidingInterface(nVar, 0, config[donorZone]); + auto nVar = solver[donor][INST_0][MESH_0][FLOW_SOL]->GetnPrimVar(); + interface[donor][target] = new CSlidingInterface(nVar, 0, config[donor]); if (rank == MASTER_NODE) cout << "sliding interface." << endl; } else if (heat_donor || heat_target) { if (heat_donor && heat_target) SU2_MPI::Error("Conjugate heat transfer between solids is not implemented.", CURRENT_FUNCTION); - const auto fluidZone = heat_target? donorZone : targetZone; + const auto fluidZone = heat_target? donor : target; - if(config[fluidZone]->GetEnergy_Equation() || (config[fluidZone]->GetKind_Regime() == COMPRESSIBLE)) + if (config[fluidZone]->GetEnergy_Equation() || (config[fluidZone]->GetKind_Regime() == COMPRESSIBLE)) interface_type = heat_target? CONJUGATE_HEAT_FS : CONJUGATE_HEAT_SF; else if (config[fluidZone]->GetWeakly_Coupled_Heat()) interface_type = heat_target? CONJUGATE_HEAT_WEAKLY_FS : CONJUGATE_HEAT_WEAKLY_SF; @@ -2589,26 +2581,31 @@ void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGe interface_type = NO_TRANSFER; if (interface_type != NO_TRANSFER) { - interface[donorZone][targetZone] = new CConjugateHeatInterface(nVar, 0, config[donorZone]); + auto nVar = 4; + interface[donor][target] = new CConjugateHeatInterface(nVar, 0, config[donor]); if (rank == MASTER_NODE) cout << "conjugate heat variables." << endl; } } else { + if (solver[donor][INST_0][MESH_0][FLOW_SOL] == nullptr) + SU2_MPI::Error("Could not determine the number of variables for transfer.", CURRENT_FUNCTION); + + auto nVar = solver[donor][INST_0][MESH_0][FLOW_SOL]->GetnVar(); interface_type = CONSERVATIVE_VARIABLES; - interface[donorZone][targetZone] = new CConservativeVarsInterface(nVar, 0, config[donorZone]); + interface[donor][target] = new CConservativeVarsInterface(nVar, 0, config[donor]); if (rank == MASTER_NODE) cout << "generic conservative variables." << endl; } } /*--- Mixing plane for turbo machinery applications. ---*/ - if (config[donorZone]->GetBoolMixingPlaneInterface()) { + if (config[donor]->GetBoolMixingPlaneInterface()) { interface_type = MIXING_PLANE; - auto nVar = solver[donorZone][INST_0][MESH_0][FLOW_SOL]->GetnVar(); - interface[donorZone][targetZone] = new CMixingPlaneInterface(nVar, 0, config[donorZone], config[targetZone]); + auto nVar = solver[donor][INST_0][MESH_0][FLOW_SOL]->GetnVar(); + interface[donor][target] = new CMixingPlaneInterface(nVar, 0, config[donor], config[target]); if (rank == MASTER_NODE) { cout << "Set mixing-plane interface from donor zone " - << donorZone << " to target zone " << targetZone << "." << endl; + << donor << " to target zone " << target << "." << endl; } } diff --git a/SU2_CFD/src/interfaces/fsi/CDiscAdjFlowTractionInterface.cpp b/SU2_CFD/src/interfaces/fsi/CDiscAdjFlowTractionInterface.cpp index dda569a7be2b..74b565c098a3 100644 --- a/SU2_CFD/src/interfaces/fsi/CDiscAdjFlowTractionInterface.cpp +++ b/SU2_CFD/src/interfaces/fsi/CDiscAdjFlowTractionInterface.cpp @@ -7,7 +7,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -28,17 +28,10 @@ #include "../../../include/interfaces/fsi/CDiscAdjFlowTractionInterface.hpp" -CDiscAdjFlowTractionInterface::CDiscAdjFlowTractionInterface(void) : CFlowTractionInterface() { - -} CDiscAdjFlowTractionInterface::CDiscAdjFlowTractionInterface(unsigned short val_nVar, unsigned short val_nConst, - CConfig *config) : - CFlowTractionInterface(val_nVar, val_nConst, config) { - -} - -CDiscAdjFlowTractionInterface::~CDiscAdjFlowTractionInterface(void) { + CConfig *config, bool integrate_tractions_) : + CFlowTractionInterface(val_nVar, val_nConst, config, integrate_tractions_) { } diff --git a/SU2_CFD/src/interfaces/fsi/CFlowTractionInterface.cpp b/SU2_CFD/src/interfaces/fsi/CFlowTractionInterface.cpp index 94a51431fa47..3b17dc2a1985 100644 --- a/SU2_CFD/src/interfaces/fsi/CFlowTractionInterface.cpp +++ b/SU2_CFD/src/interfaces/fsi/CFlowTractionInterface.cpp @@ -7,7 +7,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2020, SU2 Contributors (cf. AUTHORS.md) @@ -28,26 +28,16 @@ #include "../../../include/interfaces/fsi/CFlowTractionInterface.hpp" -CFlowTractionInterface::CFlowTractionInterface(void) : CInterface() { -} - -CFlowTractionInterface::CFlowTractionInterface(unsigned short val_nVar, unsigned short val_nConst, CConfig *config) : - CInterface(val_nVar, val_nConst, config) { - -} - -CFlowTractionInterface::~CFlowTractionInterface(void) { +CFlowTractionInterface::CFlowTractionInterface(unsigned short val_nVar, unsigned short val_nConst, + CConfig *config, bool integrate_tractions_) : + CInterface(val_nVar, val_nConst, config), + integrate_tractions(integrate_tractions_) { } void CFlowTractionInterface::Preprocess(CConfig *flow_config) { - /*--- Store if consistent interpolation is in use, in which case we need to transfer stresses - and integrate on the structural side rather than directly transferring forces. ---*/ - consistent_interpolation = (!flow_config->GetConservativeInterpolation() || - (flow_config->GetKindInterpolation() == WEIGHTED_AVERAGE)); - /*--- Compute the constant factor to dimensionalize pressure and shear stress. ---*/ su2double *Velocity_ND, *Velocity_Real; su2double Density_ND, Density_Real, Velocity2_Real, Velocity2_ND; @@ -139,7 +129,7 @@ void CFlowTractionInterface::GetDonor_Variable(CSolver *flow_solution, CGeometry su2double Tau[3][3] = {{0.0, 0.0, 0.0},{0.0, 0.0, 0.0},{0.0, 0.0, 0.0}}; su2double Grad_Vel[3][3] = {{0.0, 0.0, 0.0},{0.0, 0.0, 0.0},{0.0, 0.0, 0.0}}; su2double delta[3][3] = {{1.0, 0.0, 0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}; - su2double area = 0.0; + su2double oneOnArea = 1.0; su2double Pinf = flow_solution->GetPressure_Inf(); @@ -147,11 +137,11 @@ void CFlowTractionInterface::GetDonor_Variable(CSolver *flow_solution, CGeometry // Get the normal at the vertex: this normal goes inside the fluid domain. Normal_Flow = flow_geometry->vertex[Marker_Flow][Vertex_Flow]->GetNormal(); - if (consistent_interpolation) - for (iVar = 0; iVar < nVar; ++iVar) area += Normal_Flow[iVar]*Normal_Flow[iVar]; - else - area = 1.0; - area = sqrt(area); + // If we do not want integrated tractions, i.e. forces, we will need to divide by area. + if (!integrate_tractions) { + for (iVar = 0; iVar < nVar; ++iVar) oneOnArea += pow(Normal_Flow[iVar], 2); + oneOnArea = 1.0 / sqrt(oneOnArea); + } // Retrieve the values of pressure @@ -192,7 +182,7 @@ void CFlowTractionInterface::GetDonor_Variable(CSolver *flow_solution, CGeometry // Redimensionalize and take into account ramp transfer of the loads for (iVar = 0; iVar < nVar; iVar++) { - Donor_Variable[iVar] *= Physical_Constants[0] * Physical_Constants[1] / area; + Donor_Variable[iVar] *= Physical_Constants[0] * Physical_Constants[1] * oneOnArea; } } diff --git a/SU2_CFD/src/solvers/CFEASolver.cpp b/SU2_CFD/src/solvers/CFEASolver.cpp index e95c1e4697ab..4393c26a26a2 100644 --- a/SU2_CFD/src/solvers/CFEASolver.cpp +++ b/SU2_CFD/src/solvers/CFEASolver.cpp @@ -778,8 +778,7 @@ void CFEASolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, const bool disc_adj_fem = (config->GetKind_Solver() == DISC_ADJ_FEM); const bool body_forces = config->GetDeadLoad(); const bool fsi = config->GetFSI_Simulation(); - const bool consistent_interpolation = (!config->GetConservativeInterpolation() || - (config->GetKindInterpolation() == WEIGHTED_AVERAGE)); + const bool consistent_interpolation = !config->GetConservativeInterpolation(); const bool topology_mode = config->GetTopology_Optimization(); /* diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index 1a62c80feb77..ad40f2493c22 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -617,6 +617,12 @@ void CMeshSolver::UpdateMultiGrid(CGeometry **geometry, CConfig *config){ void CMeshSolver::SetBoundaryDisplacements(CGeometry *geometry, CNumerics *numerics, CConfig *config){ + /* Surface motions are not applied during discrete adjoint runs as the corresponding + * boundary displacements are computed when loading the primal solution, and it + * would be complex to account for the incremental nature of these motions. + * The derivatives are still correct since the motion does not depend on the solution, + * but this means that (for now) we cannot get derivatives w.r.t. motion parameters. */ + if (config->GetSurface_Movement(DEFORMING) && !config->GetDiscrete_Adjoint()) { if (rank == MASTER_NODE) cout << endl << " Updating surface positions." << endl; @@ -984,9 +990,8 @@ void CMeshSolver::Surface_Pitching(CGeometry *geometry, CConfig *config, unsigne /*--- Set node displacement for volume deformation ---*/ - for (iDim = 0; iDim < nDim; iDim++){ + for (iDim = 0; iDim < nDim; iDim++) VarCoordAbs[iDim] = nodes->GetBound_Disp(iPoint, iDim) + VarCoord[iDim]; - } nodes->SetBound_Disp(iPoint, VarCoordAbs); } From 68aa56a9fefdf2d4e33af5fbf66595d2bf4f3b75 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sun, 5 Apr 2020 17:49:51 +0100 Subject: [PATCH 77/79] keep settings backwards compatible --- Common/src/CConfig.cpp | 350 ++++++------------ SU2_CFD/src/solvers/CMeshSolver.cpp | 13 +- .../inv_NACA0012_pitching_deform.cfg | 3 - .../inv_NACA0012_pitching_deform_ad.cfg | 3 - 4 files changed, 123 insertions(+), 246 deletions(-) diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index a35e0a2a5bb9..2f0e07136ffc 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -4949,126 +4949,72 @@ void CConfig::SetMarkers(unsigned short val_software) { /*--- Allocate the memory (markers in each domain) ---*/ Marker_All_TagBound = new string[nMarker_All]; // Store the tag that correspond with each marker. - Marker_All_SendRecv = new short[nMarker_All]; // +#domain (send), -#domain (receive). - Marker_All_KindBC = new unsigned short[nMarker_All]; // Store the kind of boundary condition. - Marker_All_Monitoring = new unsigned short[nMarker_All]; // Store whether the boundary should be monitored. - Marker_All_Designing = new unsigned short[nMarker_All]; // Store whether the boundary should be designed. - Marker_All_Plotting = new unsigned short[nMarker_All]; // Store whether the boundary should be plotted. - Marker_All_Analyze = new unsigned short[nMarker_All]; // Store whether the boundary should be plotted. - Marker_All_ZoneInterface = new unsigned short[nMarker_All]; // Store whether the boundary is in the FSI interface. - Marker_All_GeoEval = new unsigned short[nMarker_All]; // Store whether the boundary should be geometry evaluation. - Marker_All_DV = new unsigned short[nMarker_All]; // Store whether the boundary should be affected by design variables. - Marker_All_Moving = new unsigned short[nMarker_All]; // Store whether the boundary should be in motion. - Marker_All_Deform_Mesh = new unsigned short[nMarker_All]; // Store whether the boundary is deformable. - Marker_All_Fluid_Load = new unsigned short[nMarker_All]; // Store whether the boundary computes/applies fluid loads. - Marker_All_PyCustom = new unsigned short[nMarker_All]; // Store whether the boundary is Python customizable. - Marker_All_PerBound = new short[nMarker_All]; // Store whether the boundary belongs to a periodic boundary. - Marker_All_Turbomachinery = new unsigned short[nMarker_All]; // Store whether the boundary is in needed for Turbomachinery computations. - Marker_All_TurbomachineryFlag = new unsigned short[nMarker_All]; // Store whether the boundary has a flag for Turbomachinery computations. - Marker_All_MixingPlaneInterface = new unsigned short[nMarker_All]; // Store whether the boundary has a in the MixingPlane interface. - + Marker_All_SendRecv = new short[nMarker_All] (); // +#domain (send), -#domain (receive). + Marker_All_KindBC = new unsigned short[nMarker_All] (); // Store the kind of boundary condition. + Marker_All_Monitoring = new unsigned short[nMarker_All] (); // Store whether the boundary should be monitored. + Marker_All_Designing = new unsigned short[nMarker_All] (); // Store whether the boundary should be designed. + Marker_All_Plotting = new unsigned short[nMarker_All] (); // Store whether the boundary should be plotted. + Marker_All_Analyze = new unsigned short[nMarker_All] (); // Store whether the boundary should be plotted. + Marker_All_ZoneInterface = new unsigned short[nMarker_All] (); // Store whether the boundary is in the FSI interface. + Marker_All_GeoEval = new unsigned short[nMarker_All] (); // Store whether the boundary should be geometry evaluation. + Marker_All_DV = new unsigned short[nMarker_All] (); // Store whether the boundary should be affected by design variables. + Marker_All_Moving = new unsigned short[nMarker_All] (); // Store whether the boundary should be in motion. + Marker_All_Deform_Mesh = new unsigned short[nMarker_All] (); // Store whether the boundary is deformable. + Marker_All_Fluid_Load = new unsigned short[nMarker_All] (); // Store whether the boundary computes/applies fluid loads. + Marker_All_PyCustom = new unsigned short[nMarker_All] (); // Store whether the boundary is Python customizable. + Marker_All_PerBound = new short[nMarker_All] (); // Store whether the boundary belongs to a periodic boundary. + Marker_All_Turbomachinery = new unsigned short[nMarker_All] (); // Store whether the boundary is in needed for Turbomachinery computations. + Marker_All_TurbomachineryFlag = new unsigned short[nMarker_All] (); // Store whether the boundary has a flag for Turbomachinery computations. + Marker_All_MixingPlaneInterface = new unsigned short[nMarker_All] (); // Store whether the boundary has a in the MixingPlane interface. for (iMarker_All = 0; iMarker_All < nMarker_All; iMarker_All++) { - Marker_All_TagBound[iMarker_All] = "SEND_RECEIVE"; - Marker_All_SendRecv[iMarker_All] = 0; - Marker_All_KindBC[iMarker_All] = 0; - Marker_All_Monitoring[iMarker_All] = 0; - Marker_All_GeoEval[iMarker_All] = 0; - Marker_All_Designing[iMarker_All] = 0; - Marker_All_Plotting[iMarker_All] = 0; - Marker_All_Analyze[iMarker_All] = 0; - Marker_All_ZoneInterface[iMarker_All] = 0; - Marker_All_DV[iMarker_All] = 0; - Marker_All_Moving[iMarker_All] = 0; - Marker_All_Deform_Mesh[iMarker_All] = 0; - Marker_All_Fluid_Load[iMarker_All] = 0; - Marker_All_PerBound[iMarker_All] = 0; - Marker_All_Turbomachinery[iMarker_All] = 0; - Marker_All_TurbomachineryFlag[iMarker_All] = 0; - Marker_All_MixingPlaneInterface[iMarker_All] = 0; - Marker_All_PyCustom[iMarker_All] = 0; + Marker_All_TagBound[iMarker_All] = "SEND_RECEIVE"; } /*--- Allocate the memory (markers in the config file) ---*/ Marker_CfgFile_TagBound = new string[nMarker_CfgFile]; - Marker_CfgFile_KindBC = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_Monitoring = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_Designing = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_Plotting = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_Analyze = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_GeoEval = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_ZoneInterface = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_DV = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_Moving = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_Deform_Mesh = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_Fluid_Load = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_PerBound = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_Turbomachinery = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_TurbomachineryFlag = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_MixingPlaneInterface = new unsigned short[nMarker_CfgFile]; - Marker_CfgFile_PyCustom = new unsigned short[nMarker_CfgFile]; + Marker_CfgFile_KindBC = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_Monitoring = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_Designing = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_Plotting = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_Analyze = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_GeoEval = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_ZoneInterface = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_DV = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_Moving = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_Deform_Mesh = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_Fluid_Load = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_PerBound = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_Turbomachinery = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_TurbomachineryFlag = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_MixingPlaneInterface = new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_PyCustom = new unsigned short[nMarker_CfgFile] (); for (iMarker_CfgFile = 0; iMarker_CfgFile < nMarker_CfgFile; iMarker_CfgFile++) { - Marker_CfgFile_TagBound[iMarker_CfgFile] = "SEND_RECEIVE"; - Marker_CfgFile_KindBC[iMarker_CfgFile] = 0; - Marker_CfgFile_Monitoring[iMarker_CfgFile] = 0; - Marker_CfgFile_GeoEval[iMarker_CfgFile] = 0; - Marker_CfgFile_Designing[iMarker_CfgFile] = 0; - Marker_CfgFile_Plotting[iMarker_CfgFile] = 0; - Marker_CfgFile_Analyze[iMarker_CfgFile] = 0; - Marker_CfgFile_ZoneInterface[iMarker_CfgFile] = 0; - Marker_CfgFile_DV[iMarker_CfgFile] = 0; - Marker_CfgFile_Moving[iMarker_CfgFile] = 0; - Marker_CfgFile_Deform_Mesh[iMarker_CfgFile] = 0; - Marker_CfgFile_Fluid_Load[iMarker_CfgFile] = 0; - Marker_CfgFile_PerBound[iMarker_CfgFile] = 0; - Marker_CfgFile_Turbomachinery[iMarker_CfgFile] = 0; - Marker_CfgFile_TurbomachineryFlag[iMarker_CfgFile] = 0; - Marker_CfgFile_MixingPlaneInterface[iMarker_CfgFile] = 0; - Marker_CfgFile_PyCustom[iMarker_CfgFile] = 0; + Marker_CfgFile_TagBound[iMarker_CfgFile] = "SEND_RECEIVE"; } /*--- Allocate memory to store surface information (Analyze BC) ---*/ - Surface_MassFlow = new su2double[nMarker_Analyze]; - Surface_Mach = new su2double[nMarker_Analyze]; - Surface_Temperature = new su2double[nMarker_Analyze]; - Surface_Pressure = new su2double[nMarker_Analyze]; - Surface_Density = new su2double[nMarker_Analyze]; - Surface_Enthalpy = new su2double[nMarker_Analyze]; - Surface_NormalVelocity = new su2double[nMarker_Analyze]; - Surface_Uniformity = new su2double[nMarker_Analyze]; - Surface_SecondaryStrength = new su2double[nMarker_Analyze]; - Surface_SecondOverUniform = new su2double[nMarker_Analyze]; - Surface_MomentumDistortion = new su2double[nMarker_Analyze]; - Surface_TotalTemperature = new su2double[nMarker_Analyze]; - Surface_TotalPressure = new su2double[nMarker_Analyze]; - Surface_PressureDrop = new su2double[nMarker_Analyze]; - Surface_DC60 = new su2double[nMarker_Analyze]; - Surface_IDC = new su2double[nMarker_Analyze]; - Surface_IDC_Mach = new su2double[nMarker_Analyze]; - Surface_IDR = new su2double[nMarker_Analyze]; - for (iMarker_Analyze = 0; iMarker_Analyze < nMarker_Analyze; iMarker_Analyze++) { - Surface_MassFlow[iMarker_Analyze] = 0.0; - Surface_Mach[iMarker_Analyze] = 0.0; - Surface_Temperature[iMarker_Analyze] = 0.0; - Surface_Pressure[iMarker_Analyze] = 0.0; - Surface_Density[iMarker_Analyze] = 0.0; - Surface_Enthalpy[iMarker_Analyze] = 0.0; - Surface_NormalVelocity[iMarker_Analyze] = 0.0; - Surface_Uniformity[iMarker_Analyze] = 0.0; - Surface_SecondaryStrength[iMarker_Analyze] = 0.0; - Surface_SecondOverUniform[iMarker_Analyze] = 0.0; - Surface_MomentumDistortion[iMarker_Analyze] = 0.0; - Surface_TotalTemperature[iMarker_Analyze] = 0.0; - Surface_TotalPressure[iMarker_Analyze] = 0.0; - Surface_PressureDrop[iMarker_Analyze] = 0.0; - Surface_DC60[iMarker_Analyze] = 0.0; - Surface_IDC[iMarker_Analyze] = 0.0; - Surface_IDC_Mach[iMarker_Analyze] = 0.0; - Surface_IDR[iMarker_Analyze] = 0.0; - } + Surface_MassFlow = new su2double[nMarker_Analyze] (); + Surface_Mach = new su2double[nMarker_Analyze] (); + Surface_Temperature = new su2double[nMarker_Analyze] (); + Surface_Pressure = new su2double[nMarker_Analyze] (); + Surface_Density = new su2double[nMarker_Analyze] (); + Surface_Enthalpy = new su2double[nMarker_Analyze] (); + Surface_NormalVelocity = new su2double[nMarker_Analyze] (); + Surface_Uniformity = new su2double[nMarker_Analyze] (); + Surface_SecondaryStrength = new su2double[nMarker_Analyze] (); + Surface_SecondOverUniform = new su2double[nMarker_Analyze] (); + Surface_MomentumDistortion = new su2double[nMarker_Analyze] (); + Surface_TotalTemperature = new su2double[nMarker_Analyze] (); + Surface_TotalPressure = new su2double[nMarker_Analyze] (); + Surface_PressureDrop = new su2double[nMarker_Analyze] (); + Surface_DC60 = new su2double[nMarker_Analyze] (); + Surface_IDC = new su2double[nMarker_Analyze] (); + Surface_IDC_Mach = new su2double[nMarker_Analyze] (); + Surface_IDR = new su2double[nMarker_Analyze] (); /*--- Populate the marker information in the config file (all domains) ---*/ @@ -5098,97 +5044,56 @@ void CConfig::SetMarkers(unsigned short val_software) { iMarker_CfgFile++; } - ActDisk_DeltaPress = new su2double[nMarker_ActDiskInlet]; - ActDisk_DeltaTemp = new su2double[nMarker_ActDiskInlet]; - ActDisk_TotalPressRatio = new su2double[nMarker_ActDiskInlet]; - ActDisk_TotalTempRatio = new su2double[nMarker_ActDiskInlet]; - ActDisk_StaticPressRatio = new su2double[nMarker_ActDiskInlet]; - ActDisk_StaticTempRatio = new su2double[nMarker_ActDiskInlet]; - ActDisk_Power = new su2double[nMarker_ActDiskInlet]; - ActDisk_MassFlow = new su2double[nMarker_ActDiskInlet]; - ActDisk_Mach = new su2double[nMarker_ActDiskInlet]; - ActDisk_Force = new su2double[nMarker_ActDiskInlet]; - ActDisk_NetThrust = new su2double[nMarker_ActDiskInlet]; - ActDisk_BCThrust = new su2double[nMarker_ActDiskInlet]; - ActDisk_BCThrust_Old = new su2double[nMarker_ActDiskInlet]; - ActDisk_GrossThrust = new su2double[nMarker_ActDiskInlet]; - ActDisk_Area = new su2double[nMarker_ActDiskInlet]; - ActDisk_ReverseMassFlow = new su2double[nMarker_ActDiskInlet]; - - for (iMarker_ActDiskInlet = 0; iMarker_ActDiskInlet < nMarker_ActDiskInlet; iMarker_ActDiskInlet++) { - ActDisk_DeltaPress[iMarker_ActDiskInlet] = 0.0; - ActDisk_DeltaTemp[iMarker_ActDiskInlet] = 0.0; - ActDisk_TotalPressRatio[iMarker_ActDiskInlet] = 0.0; - ActDisk_TotalTempRatio[iMarker_ActDiskInlet] = 0.0; - ActDisk_StaticPressRatio[iMarker_ActDiskInlet] = 0.0; - ActDisk_StaticTempRatio[iMarker_ActDiskInlet] = 0.0; - ActDisk_Power[iMarker_ActDiskInlet] = 0.0; - ActDisk_MassFlow[iMarker_ActDiskInlet] = 0.0; - ActDisk_Mach[iMarker_ActDiskInlet] = 0.0; - ActDisk_Force[iMarker_ActDiskInlet] = 0.0; - ActDisk_NetThrust[iMarker_ActDiskInlet] = 0.0; - ActDisk_BCThrust[iMarker_ActDiskInlet] = 0.0; - ActDisk_BCThrust_Old[iMarker_ActDiskInlet] = 0.0; - ActDisk_GrossThrust[iMarker_ActDiskInlet] = 0.0; - ActDisk_Area[iMarker_ActDiskInlet] = 0.0; - ActDisk_ReverseMassFlow[iMarker_ActDiskInlet] = 0.0; - } - - - ActDiskInlet_MassFlow = new su2double[nMarker_ActDiskInlet]; - ActDiskInlet_Temperature = new su2double[nMarker_ActDiskInlet]; - ActDiskInlet_TotalTemperature = new su2double[nMarker_ActDiskInlet]; - ActDiskInlet_Pressure = new su2double[nMarker_ActDiskInlet]; - ActDiskInlet_TotalPressure = new su2double[nMarker_ActDiskInlet]; - ActDiskInlet_RamDrag = new su2double[nMarker_ActDiskInlet]; - ActDiskInlet_Force = new su2double[nMarker_ActDiskInlet]; - ActDiskInlet_Power = new su2double[nMarker_ActDiskInlet]; + ActDisk_DeltaPress = new su2double[nMarker_ActDiskInlet] (); + ActDisk_DeltaTemp = new su2double[nMarker_ActDiskInlet] (); + ActDisk_TotalPressRatio = new su2double[nMarker_ActDiskInlet] (); + ActDisk_TotalTempRatio = new su2double[nMarker_ActDiskInlet] (); + ActDisk_StaticPressRatio = new su2double[nMarker_ActDiskInlet] (); + ActDisk_StaticTempRatio = new su2double[nMarker_ActDiskInlet] (); + ActDisk_Power = new su2double[nMarker_ActDiskInlet] (); + ActDisk_MassFlow = new su2double[nMarker_ActDiskInlet] (); + ActDisk_Mach = new su2double[nMarker_ActDiskInlet] (); + ActDisk_Force = new su2double[nMarker_ActDiskInlet] (); + ActDisk_NetThrust = new su2double[nMarker_ActDiskInlet] (); + ActDisk_BCThrust = new su2double[nMarker_ActDiskInlet] (); + ActDisk_BCThrust_Old = new su2double[nMarker_ActDiskInlet] (); + ActDisk_GrossThrust = new su2double[nMarker_ActDiskInlet] (); + ActDisk_Area = new su2double[nMarker_ActDiskInlet] (); + ActDisk_ReverseMassFlow = new su2double[nMarker_ActDiskInlet] (); + + ActDiskInlet_MassFlow = new su2double[nMarker_ActDiskInlet] (); + ActDiskInlet_Temperature = new su2double[nMarker_ActDiskInlet] (); + ActDiskInlet_TotalTemperature = new su2double[nMarker_ActDiskInlet] (); + ActDiskInlet_Pressure = new su2double[nMarker_ActDiskInlet] (); + ActDiskInlet_TotalPressure = new su2double[nMarker_ActDiskInlet] (); + ActDiskInlet_RamDrag = new su2double[nMarker_ActDiskInlet] (); + ActDiskInlet_Force = new su2double[nMarker_ActDiskInlet] (); + ActDiskInlet_Power = new su2double[nMarker_ActDiskInlet] (); for (iMarker_ActDiskInlet = 0; iMarker_ActDiskInlet < nMarker_ActDiskInlet; iMarker_ActDiskInlet++) { Marker_CfgFile_TagBound[iMarker_CfgFile] = Marker_ActDiskInlet[iMarker_ActDiskInlet]; Marker_CfgFile_KindBC[iMarker_CfgFile] = ACTDISK_INLET; - ActDiskInlet_MassFlow[iMarker_ActDiskInlet] = 0.0; - ActDiskInlet_Temperature[iMarker_ActDiskInlet] = 0.0; - ActDiskInlet_TotalTemperature[iMarker_ActDiskInlet] = 0.0; - ActDiskInlet_Pressure[iMarker_ActDiskInlet] = 0.0; - ActDiskInlet_TotalPressure[iMarker_ActDiskInlet] = 0.0; - ActDiskInlet_RamDrag[iMarker_ActDiskInlet] = 0.0; - ActDiskInlet_Force[iMarker_ActDiskInlet] = 0.0; - ActDiskInlet_Power[iMarker_ActDiskInlet] = 0.0; iMarker_CfgFile++; } - ActDiskOutlet_MassFlow = new su2double[nMarker_ActDiskOutlet]; - ActDiskOutlet_Temperature = new su2double[nMarker_ActDiskOutlet]; - ActDiskOutlet_TotalTemperature = new su2double[nMarker_ActDiskOutlet]; - ActDiskOutlet_Pressure = new su2double[nMarker_ActDiskOutlet]; - ActDiskOutlet_TotalPressure = new su2double[nMarker_ActDiskOutlet]; - ActDiskOutlet_GrossThrust = new su2double[nMarker_ActDiskOutlet]; - ActDiskOutlet_Force = new su2double[nMarker_ActDiskOutlet]; - ActDiskOutlet_Power = new su2double[nMarker_ActDiskOutlet]; + ActDiskOutlet_MassFlow = new su2double[nMarker_ActDiskOutlet] (); + ActDiskOutlet_Temperature = new su2double[nMarker_ActDiskOutlet] (); + ActDiskOutlet_TotalTemperature = new su2double[nMarker_ActDiskOutlet] (); + ActDiskOutlet_Pressure = new su2double[nMarker_ActDiskOutlet] (); + ActDiskOutlet_TotalPressure = new su2double[nMarker_ActDiskOutlet] (); + ActDiskOutlet_GrossThrust = new su2double[nMarker_ActDiskOutlet] (); + ActDiskOutlet_Force = new su2double[nMarker_ActDiskOutlet] (); + ActDiskOutlet_Power = new su2double[nMarker_ActDiskOutlet] (); for (iMarker_ActDiskOutlet = 0; iMarker_ActDiskOutlet < nMarker_ActDiskOutlet; iMarker_ActDiskOutlet++) { Marker_CfgFile_TagBound[iMarker_CfgFile] = Marker_ActDiskOutlet[iMarker_ActDiskOutlet]; Marker_CfgFile_KindBC[iMarker_CfgFile] = ACTDISK_OUTLET; - ActDiskOutlet_MassFlow[iMarker_ActDiskOutlet] = 0.0; - ActDiskOutlet_Temperature[iMarker_ActDiskOutlet] = 0.0; - ActDiskOutlet_TotalTemperature[iMarker_ActDiskOutlet] = 0.0; - ActDiskOutlet_Pressure[iMarker_ActDiskOutlet] = 0.0; - ActDiskOutlet_TotalPressure[iMarker_ActDiskOutlet] = 0.0; - ActDiskOutlet_GrossThrust[iMarker_ActDiskOutlet] = 0.0; - ActDiskOutlet_Force[iMarker_ActDiskOutlet] = 0.0; - ActDiskOutlet_Power[iMarker_ActDiskOutlet] = 0.0; iMarker_CfgFile++; } - Outlet_MassFlow = new su2double[nMarker_Outlet]; - Outlet_Density = new su2double[nMarker_Outlet]; - Outlet_Area = new su2double[nMarker_Outlet]; - for (iMarker_Outlet = 0; iMarker_Outlet < nMarker_Outlet; iMarker_Outlet++) { - Outlet_MassFlow[iMarker_Outlet] = 0.0; - Outlet_Density[iMarker_Outlet] = 0.0; - Outlet_Area[iMarker_Outlet] = 0.0; - } + Outlet_MassFlow = new su2double[nMarker_Outlet] (); + Outlet_Density = new su2double[nMarker_Outlet] (); + Outlet_Area = new su2double[nMarker_Outlet] (); for (iMarker_NearFieldBound = 0; iMarker_NearFieldBound < nMarker_NearFieldBound; iMarker_NearFieldBound++) { Marker_CfgFile_TagBound[iMarker_CfgFile] = Marker_NearFieldBound[iMarker_NearFieldBound]; @@ -5226,69 +5131,42 @@ void CConfig::SetMarkers(unsigned short val_software) { iMarker_CfgFile++; } - Engine_Power = new su2double[nMarker_EngineInflow]; - Engine_Mach = new su2double[nMarker_EngineInflow]; - Engine_Force = new su2double[nMarker_EngineInflow]; - Engine_NetThrust = new su2double[nMarker_EngineInflow]; - Engine_GrossThrust = new su2double[nMarker_EngineInflow]; - Engine_Area = new su2double[nMarker_EngineInflow]; - - for (iMarker_EngineInflow = 0; iMarker_EngineInflow < nMarker_EngineInflow; iMarker_EngineInflow++) { - Engine_Power[iMarker_EngineInflow] = 0.0; - Engine_Mach[iMarker_EngineInflow] = 0.0; - Engine_Force[iMarker_EngineInflow] = 0.0; - Engine_NetThrust[iMarker_EngineInflow] = 0.0; - Engine_GrossThrust[iMarker_EngineInflow] = 0.0; - Engine_Area[iMarker_EngineInflow] = 0.0; - } - - Inflow_Mach = new su2double[nMarker_EngineInflow]; - Inflow_Pressure = new su2double[nMarker_EngineInflow]; - Inflow_MassFlow = new su2double[nMarker_EngineInflow]; - Inflow_ReverseMassFlow = new su2double[nMarker_EngineInflow]; - Inflow_TotalPressure = new su2double[nMarker_EngineInflow]; - Inflow_Temperature = new su2double[nMarker_EngineInflow]; - Inflow_TotalTemperature = new su2double[nMarker_EngineInflow]; - Inflow_RamDrag = new su2double[nMarker_EngineInflow]; - Inflow_Force = new su2double[nMarker_EngineInflow]; - Inflow_Power = new su2double[nMarker_EngineInflow]; + Engine_Power = new su2double[nMarker_EngineInflow] (); + Engine_Mach = new su2double[nMarker_EngineInflow] (); + Engine_Force = new su2double[nMarker_EngineInflow] (); + Engine_NetThrust = new su2double[nMarker_EngineInflow] (); + Engine_GrossThrust = new su2double[nMarker_EngineInflow] (); + Engine_Area = new su2double[nMarker_EngineInflow] (); + + Inflow_Mach = new su2double[nMarker_EngineInflow] (); + Inflow_Pressure = new su2double[nMarker_EngineInflow] (); + Inflow_MassFlow = new su2double[nMarker_EngineInflow] (); + Inflow_ReverseMassFlow = new su2double[nMarker_EngineInflow] (); + Inflow_TotalPressure = new su2double[nMarker_EngineInflow] (); + Inflow_Temperature = new su2double[nMarker_EngineInflow] (); + Inflow_TotalTemperature = new su2double[nMarker_EngineInflow] (); + Inflow_RamDrag = new su2double[nMarker_EngineInflow] (); + Inflow_Force = new su2double[nMarker_EngineInflow] (); + Inflow_Power = new su2double[nMarker_EngineInflow] (); for (iMarker_EngineInflow = 0; iMarker_EngineInflow < nMarker_EngineInflow; iMarker_EngineInflow++) { Marker_CfgFile_TagBound[iMarker_CfgFile] = Marker_EngineInflow[iMarker_EngineInflow]; Marker_CfgFile_KindBC[iMarker_CfgFile] = ENGINE_INFLOW; - Inflow_Mach[iMarker_EngineInflow] = 0.0; - Inflow_Pressure[iMarker_EngineInflow] = 0.0; - Inflow_MassFlow[iMarker_EngineInflow] = 0.0; - Inflow_ReverseMassFlow[iMarker_EngineInflow] = 0.0; - Inflow_TotalPressure[iMarker_EngineInflow] = 0.0; - Inflow_Temperature[iMarker_EngineInflow] = 0.0; - Inflow_TotalTemperature[iMarker_EngineInflow] = 0.0; - Inflow_RamDrag[iMarker_EngineInflow] = 0.0; - Inflow_Force[iMarker_EngineInflow] = 0.0; - Inflow_Power[iMarker_EngineInflow] = 0.0; iMarker_CfgFile++; } - Exhaust_Pressure = new su2double[nMarker_EngineExhaust]; - Exhaust_Temperature = new su2double[nMarker_EngineExhaust]; - Exhaust_MassFlow = new su2double[nMarker_EngineExhaust]; - Exhaust_TotalPressure = new su2double[nMarker_EngineExhaust]; - Exhaust_TotalTemperature = new su2double[nMarker_EngineExhaust]; - Exhaust_GrossThrust = new su2double[nMarker_EngineExhaust]; - Exhaust_Force = new su2double[nMarker_EngineExhaust]; - Exhaust_Power = new su2double[nMarker_EngineExhaust]; + Exhaust_Pressure = new su2double[nMarker_EngineExhaust] (); + Exhaust_Temperature = new su2double[nMarker_EngineExhaust] (); + Exhaust_MassFlow = new su2double[nMarker_EngineExhaust] (); + Exhaust_TotalPressure = new su2double[nMarker_EngineExhaust] (); + Exhaust_TotalTemperature = new su2double[nMarker_EngineExhaust] (); + Exhaust_GrossThrust = new su2double[nMarker_EngineExhaust] (); + Exhaust_Force = new su2double[nMarker_EngineExhaust] (); + Exhaust_Power = new su2double[nMarker_EngineExhaust] (); for (iMarker_EngineExhaust = 0; iMarker_EngineExhaust < nMarker_EngineExhaust; iMarker_EngineExhaust++) { Marker_CfgFile_TagBound[iMarker_CfgFile] = Marker_EngineExhaust[iMarker_EngineExhaust]; Marker_CfgFile_KindBC[iMarker_CfgFile] = ENGINE_EXHAUST; - Exhaust_Pressure[iMarker_EngineExhaust] = 0.0; - Exhaust_Temperature[iMarker_EngineExhaust] = 0.0; - Exhaust_MassFlow[iMarker_EngineExhaust] = 0.0; - Exhaust_TotalPressure[iMarker_EngineExhaust] = 0.0; - Exhaust_TotalTemperature[iMarker_EngineExhaust] = 0.0; - Exhaust_GrossThrust[iMarker_EngineExhaust] = 0.0; - Exhaust_Force[iMarker_EngineExhaust] = 0.0; - Exhaust_Power[iMarker_EngineExhaust] = 0.0; iMarker_CfgFile++; } diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index ad40f2493c22..434eb4a69c9e 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -166,7 +166,8 @@ CMeshSolver::CMeshSolver(CGeometry *geometry, CConfig *config) : CFEASolver(true for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { if (((config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) && (config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY)) || - (config->GetMarker_All_Deform_Mesh(iMarker) == YES)) { + (config->GetMarker_All_Deform_Mesh(iMarker) == YES) || + (config->GetMarker_All_Moving(iMarker) == YES)) { essentialMarkers.push_back(iMarker); } } @@ -639,6 +640,7 @@ void CMeshSolver::SetBoundaryDisplacements(CGeometry *geometry, CNumerics *numer /*--- Exceptions: symmetry plane, the receive boundaries and periodic boundaries should get a different treatment. ---*/ for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { if ((config->GetMarker_All_Deform_Mesh(iMarker) == NO) && + (config->GetMarker_All_Moving(iMarker) == NO) && (config->GetMarker_All_KindBC(iMarker) != SYMMETRY_PLANE) && (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) && (config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY)) { @@ -647,9 +649,10 @@ void CMeshSolver::SetBoundaryDisplacements(CGeometry *geometry, CNumerics *numer } } - /*--- Symmetry plane is, for now, clamped. ---*/ + /*--- Symmetry plane is clamped, for now. ---*/ for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { if ((config->GetMarker_All_Deform_Mesh(iMarker) == NO) && + (config->GetMarker_All_Moving(iMarker) == NO) && (config->GetMarker_All_KindBC(iMarker) == SYMMETRY_PLANE)) { BC_Clamped(geometry, numerics, config, iMarker); @@ -658,7 +661,8 @@ void CMeshSolver::SetBoundaryDisplacements(CGeometry *geometry, CNumerics *numer /*--- Impose displacement boundary conditions. ---*/ for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_Deform_Mesh(iMarker) == YES) { + if ((config->GetMarker_All_Deform_Mesh(iMarker) == YES) || + (config->GetMarker_All_Moving(iMarker) == YES)) { BC_Deforming(geometry, numerics, config, iMarker); } @@ -765,7 +769,8 @@ void CMeshSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig * for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_Deform_Mesh(iMarker) == YES) { + if ((config->GetMarker_All_Deform_Mesh(iMarker) == YES) || + (config->GetMarker_All_Moving(iMarker) == YES)) { for (unsigned long iVertex = 0; iVertex < geometry[MESH_0]->nVertex[iMarker]; iVertex++) { diff --git a/TestCases/disc_adj_euler/naca0012_pitching_def/inv_NACA0012_pitching_deform.cfg b/TestCases/disc_adj_euler/naca0012_pitching_def/inv_NACA0012_pitching_deform.cfg index d42b48c31735..cd2eda32fb8e 100644 --- a/TestCases/disc_adj_euler/naca0012_pitching_def/inv_NACA0012_pitching_deform.cfg +++ b/TestCases/disc_adj_euler/naca0012_pitching_def/inv_NACA0012_pitching_deform.cfg @@ -14,9 +14,6 @@ UNST_RESTART_ITER= 5 UNST_ADJOINT_ITER= 5 % ----------------------- DYNAMIC MESH DEFINITION -----------------------------% -DEFORM_MESH= YES -MARKER_DEFORM_MESH= (airfoil) - SURFACE_MOVEMENT= DEFORMING MARKER_MOVING= ( airfoil ) SURFACE_MOTION_ORIGIN= (0.248 0.0 0.0) diff --git a/TestCases/disc_adj_euler/naca0012_pitching_def/inv_NACA0012_pitching_deform_ad.cfg b/TestCases/disc_adj_euler/naca0012_pitching_def/inv_NACA0012_pitching_deform_ad.cfg index 11b0672a9f7c..ec65eb46b12e 100644 --- a/TestCases/disc_adj_euler/naca0012_pitching_def/inv_NACA0012_pitching_deform_ad.cfg +++ b/TestCases/disc_adj_euler/naca0012_pitching_def/inv_NACA0012_pitching_deform_ad.cfg @@ -14,9 +14,6 @@ UNST_RESTART_ITER= 5 UNST_ADJOINT_ITER= 5 % ----------------------- DYNAMIC MESH DEFINITION -----------------------------% -DEFORM_MESH= YES -MARKER_DEFORM_MESH= (airfoil) - SURFACE_MOVEMENT= DEFORMING MARKER_MOVING= ( airfoil ) SURFACE_MOTION_ORIGIN= (0.248 0.0 0.0) From 8ee9946d851e384465f26ffa3c1f71fa7197a154 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sun, 5 Apr 2020 22:07:39 +0100 Subject: [PATCH 78/79] cleanup and minor fixes --- SU2_CFD/include/solvers/CFEASolver.hpp | 2 +- SU2_CFD/src/drivers/CDriver.cpp | 2 +- .../interfaces/fsi/CFlowTractionInterface.cpp | 70 +++++++------------ SU2_CFD/src/solvers/CFEASolver.cpp | 10 +-- SU2_CFD/src/solvers/CMeshSolver.cpp | 4 +- .../disc_adj_fsi/Airfoil_2d/configFEA.cfg | 6 -- .../disc_adj_fsi/Airfoil_2d/configFlow.cfg | 12 +--- 7 files changed, 39 insertions(+), 67 deletions(-) diff --git a/SU2_CFD/include/solvers/CFEASolver.hpp b/SU2_CFD/include/solvers/CFEASolver.hpp index e4f1578f57bc..02b6f463ae4f 100644 --- a/SU2_CFD/include/solvers/CFEASolver.hpp +++ b/SU2_CFD/include/solvers/CFEASolver.hpp @@ -467,7 +467,7 @@ class CFEASolver : public CSolver { * \param[in] geometry - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. */ - void Integrate_FSI_Loads(CGeometry *geometry, CConfig *config); + void Integrate_FSI_Loads(CGeometry *geometry, const CConfig *config); /*! * \brief Update the solution using an implicit solver. diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index bfc54ad39feb..0261c5f6774c 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -2550,7 +2550,7 @@ void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGe } else { interface[donor][target] = new CDiscAdjFlowTractionInterface(nDim, nConst, config[donor], conservative); } - if (rank == MASTER_NODE) cout << "flow tractions. " << endl; + if (rank == MASTER_NODE) cout << "fluid " << (conservative? "forces." : "tractions.") << endl; } else if (structural_donor && fluid_target) { if (solver_container[target][INST_0][MESH_0][MESH_SOL] == nullptr) { diff --git a/SU2_CFD/src/interfaces/fsi/CFlowTractionInterface.cpp b/SU2_CFD/src/interfaces/fsi/CFlowTractionInterface.cpp index 3b17dc2a1985..d9769706b831 100644 --- a/SU2_CFD/src/interfaces/fsi/CFlowTractionInterface.cpp +++ b/SU2_CFD/src/interfaces/fsi/CFlowTractionInterface.cpp @@ -39,7 +39,7 @@ CFlowTractionInterface::CFlowTractionInterface(unsigned short val_nVar, unsigned void CFlowTractionInterface::Preprocess(CConfig *flow_config) { /*--- Compute the constant factor to dimensionalize pressure and shear stress. ---*/ - su2double *Velocity_ND, *Velocity_Real; + const su2double *Velocity_ND, *Velocity_Real; su2double Density_ND, Density_Real, Velocity2_Real, Velocity2_ND; Velocity_Real = flow_config->GetVelocity_FreeStream(); @@ -100,82 +100,66 @@ void CFlowTractionInterface::GetPhysical_Constants(CSolver *flow_solution, CSolv void CFlowTractionInterface::GetDonor_Variable(CSolver *flow_solution, CGeometry *flow_geometry, CConfig *flow_config, unsigned long Marker_Flow, unsigned long Vertex_Flow, unsigned long Point_Struct) { - - unsigned short iVar, jVar; - unsigned long Point_Flow; - su2double const *Normal_Flow; // Check the kind of fluid problem - bool compressible = (flow_config->GetKind_Regime() == COMPRESSIBLE); - bool incompressible = (flow_config->GetKind_Regime() == INCOMPRESSIBLE); - bool viscous_flow = ((flow_config->GetKind_Solver() == NAVIER_STOKES) || - (flow_config->GetKind_Solver() == RANS) || - (flow_config->GetKind_Solver() == INC_NAVIER_STOKES) || - (flow_config->GetKind_Solver() == INC_RANS) || - (flow_config->GetKind_Solver() == DISC_ADJ_NAVIER_STOKES) || - (flow_config->GetKind_Solver() == DISC_ADJ_RANS) || - (flow_config->GetKind_Solver() == DISC_ADJ_INC_NAVIER_STOKES) || - (flow_config->GetKind_Solver() == DISC_ADJ_INC_RANS)); - - // Parameters for the calculations - // Pn: Pressure - // Pinf: Pressure_infinite - // div_vel: Velocity divergence - // Dij: Dirac delta - // area: area of the face, needed if we transfer stress instead of force - su2double Pn = 0.0, div_vel = 0.0; - su2double Viscosity = 0.0; - su2double Tau[3][3] = {{0.0, 0.0, 0.0},{0.0, 0.0, 0.0},{0.0, 0.0, 0.0}}; - su2double Grad_Vel[3][3] = {{0.0, 0.0, 0.0},{0.0, 0.0, 0.0},{0.0, 0.0, 0.0}}; - su2double delta[3][3] = {{1.0, 0.0, 0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}; - su2double oneOnArea = 1.0; + bool viscous_flow; + switch (flow_config->GetKind_Solver()) { + case RANS: case INC_RANS: + case NAVIER_STOKES: case INC_NAVIER_STOKES: + case DISC_ADJ_RANS: case DISC_ADJ_INC_RANS: + case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_INC_NAVIER_STOKES: + viscous_flow = true; break; + default: + viscous_flow = false; break; + } - su2double Pinf = flow_solution->GetPressure_Inf(); + const auto Point_Flow = flow_geometry->vertex[Marker_Flow][Vertex_Flow]->GetNode(); - Point_Flow = flow_geometry->vertex[Marker_Flow][Vertex_Flow]->GetNode(); // Get the normal at the vertex: this normal goes inside the fluid domain. - Normal_Flow = flow_geometry->vertex[Marker_Flow][Vertex_Flow]->GetNormal(); + const su2double* Normal_Flow = flow_geometry->vertex[Marker_Flow][Vertex_Flow]->GetNormal(); // If we do not want integrated tractions, i.e. forces, we will need to divide by area. + su2double oneOnArea = 1.0; if (!integrate_tractions) { + oneOnArea = 0.0; for (iVar = 0; iVar < nVar; ++iVar) oneOnArea += pow(Normal_Flow[iVar], 2); oneOnArea = 1.0 / sqrt(oneOnArea); } // Retrieve the values of pressure - Pn = flow_solution->GetNodes()->GetPressure(Point_Flow); + CVariable* flow_nodes = flow_solution->GetNodes(); + su2double Pinf = flow_solution->GetPressure_Inf(); + su2double Pn = flow_nodes->GetPressure(Point_Flow); // Calculate tn in the fluid nodes for the inviscid term --> Units of force (non-dimensional). + for (iVar = 0; iVar < nVar; iVar++) Donor_Variable[iVar] = -(Pn-Pinf)*Normal_Flow[iVar]; // Calculate tn in the fluid nodes for the viscous term - if ((incompressible || compressible) && viscous_flow) { + if (viscous_flow) { - Viscosity = flow_solution->GetNodes()->GetLaminarViscosity(Point_Flow); + su2double Viscosity = flow_nodes->GetLaminarViscosity(Point_Flow); - for (iVar = 0; iVar < nVar; iVar++) { - for (jVar = 0 ; jVar < nVar; jVar++) { - Grad_Vel[iVar][jVar] = flow_solution->GetNodes()->GetGradient_Primitive(Point_Flow, iVar+1, jVar); - } - } + const su2double* const* GradVel = &flow_nodes->GetGradient_Primitive(Point_Flow)[1]; // Divergence of the velocity - div_vel = 0.0; for (iVar = 0; iVar < nVar; iVar++) div_vel += Grad_Vel[iVar][iVar]; + su2double DivVel = 0.0; + for (iVar = 0; iVar < nVar; iVar++) DivVel += GradVel[iVar][iVar]; for (iVar = 0; iVar < nVar; iVar++) { for (jVar = 0 ; jVar < nVar; jVar++) { // Viscous stress - Tau[iVar][jVar] = Viscosity*(Grad_Vel[jVar][iVar] + Grad_Vel[iVar][jVar]) - - TWO3*Viscosity*div_vel*delta[iVar][jVar]; + su2double delta_ij = (iVar == jVar); + su2double tau_ij = Viscosity*(GradVel[jVar][iVar] + GradVel[iVar][jVar] - TWO3*DivVel*delta_ij); // Viscous component in the tn vector --> Units of force (non-dimensional). - Donor_Variable[iVar] += Tau[iVar][jVar]*Normal_Flow[jVar]; + Donor_Variable[iVar] += tau_ij * Normal_Flow[jVar]; } } } diff --git a/SU2_CFD/src/solvers/CFEASolver.cpp b/SU2_CFD/src/solvers/CFEASolver.cpp index 4393c26a26a2..5a24ace56ff1 100644 --- a/SU2_CFD/src/solvers/CFEASolver.cpp +++ b/SU2_CFD/src/solvers/CFEASolver.cpp @@ -778,7 +778,6 @@ void CFEASolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, const bool disc_adj_fem = (config->GetKind_Solver() == DISC_ADJ_FEM); const bool body_forces = config->GetDeadLoad(); const bool fsi = config->GetFSI_Simulation(); - const bool consistent_interpolation = !config->GetConservativeInterpolation(); const bool topology_mode = config->GetTopology_Optimization(); /* @@ -791,7 +790,7 @@ void CFEASolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, */ if (topology_mode && !topol_filter_applied) { geometry->SetElemVolume(config); - FilterElementDensities(geometry,config); + FilterElementDensities(geometry, config); topol_filter_applied = true; } @@ -827,7 +826,7 @@ void CFEASolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, /* * FSI loads (computed upstream) need to be integrated if a nonconservative interpolation scheme is in use */ - if (fsi && first_iter && consistent_interpolation) Integrate_FSI_Loads(geometry,config); + if (fsi && first_iter) Integrate_FSI_Loads(geometry, config); /*--- Next call to Preprocessing will not be "initial_calc" and linear operations will not be repeated. ---*/ initial_calc = false; @@ -2148,7 +2147,10 @@ void CFEASolver::BC_Deforming(CGeometry *geometry, CNumerics *numerics, CConfig } -void CFEASolver::Integrate_FSI_Loads(CGeometry *geometry, CConfig *config) { +void CFEASolver::Integrate_FSI_Loads(CGeometry *geometry, const CConfig *config) { + + /*--- The conservative approach transfers forces directly, no integration needed. ---*/ + if (config->GetConservativeInterpolation()) return; const auto nMarker = config->GetnMarker_All(); const auto nMarkerInt = config->GetMarker_n_ZoneInterface()/2u; diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index 434eb4a69c9e..8fcd4392e01c 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -581,8 +581,8 @@ void CMeshSolver::ComputeGridVelocity(CGeometry *geometry, CConfig *config){ if (config->GetTime_Marching() == DT_STEPPING_1ST) GridVel = ( Disp_nP1[iDim] - Disp_n[iDim] ) / TimeStep; if (config->GetTime_Marching() == DT_STEPPING_2ND) - GridVel = ( 3.0*Disp_nP1[iDim] - 4.0*Disp_n[iDim] - + 1.0*Disp_nM1[iDim] ) / (2.0*TimeStep); + GridVel = ( 3.0*Disp_nP1[iDim] - 4.0*Disp_n[iDim] + + 1.0*Disp_nM1[iDim] ) / (2.0*TimeStep); /*--- Store grid velocity for this point ---*/ diff --git a/TestCases/disc_adj_fsi/Airfoil_2d/configFEA.cfg b/TestCases/disc_adj_fsi/Airfoil_2d/configFEA.cfg index 61069f8b033e..65d6aa959100 100755 --- a/TestCases/disc_adj_fsi/Airfoil_2d/configFEA.cfg +++ b/TestCases/disc_adj_fsi/Airfoil_2d/configFEA.cfg @@ -15,10 +15,6 @@ POISSON_RATIO= 0.35 MATERIAL_DENSITY= 2700.0 % % Boundary conditions -------------------------------------------------- % -% interface -% this needs to appear before the normal load marker -CONSERVATIVE_INTERPOLATION= NO -% solid MARKER_CLAMPED= ( clamped ) MARKER_FLUID_LOAD= ( pressure_side_s, suction_side_s ) % @@ -40,8 +36,6 @@ BGS_RELAXATION= FIXED_PARAMETER STAT_RELAX_PARAMETER= 1.0 % solid INNER_ITER= 11 -% grid deformation -DEFORM_STIFFNESS_TYPE= INVERSE_VOLUME % % In\Out --------------------------------------------------------------- % MESH_FILENAME= mesh.su2 diff --git a/TestCases/disc_adj_fsi/Airfoil_2d/configFlow.cfg b/TestCases/disc_adj_fsi/Airfoil_2d/configFlow.cfg index 50d96b094de1..498b75828333 100755 --- a/TestCases/disc_adj_fsi/Airfoil_2d/configFlow.cfg +++ b/TestCases/disc_adj_fsi/Airfoil_2d/configFlow.cfg @@ -21,14 +21,7 @@ GAS_CONSTANT= 287.87 VISCOSITY_MODEL= CONSTANT_VISCOSITY MU_CONSTANT= 1.716E-5 % -% Solid properties ----------------------------------------------------- % -MATERIAL_MODEL= NEO_HOOKEAN -ELASTICITY_MODULUS= 7E9 -POISSON_RATIO= 0.35 -MATERIAL_DENSITY= 2700.0 -% % Boundary conditions -------------------------------------------------- % -% fluid MARKER_FAR= ( farfield ) MARKER_EULER= ( leading_edge, pressure_side, suction_side) MARKER_DEFORM_MESH= ( leading_edge, pressure_side, suction_side ) @@ -74,6 +67,8 @@ DEFORM_LINEAR_SOLVER= CONJUGATE_GRADIENT DEFORM_LINEAR_SOLVER_PREC= ILU DEFORM_LINEAR_SOLVER_ERROR= 1e-8 DEFORM_LINEAR_SOLVER_ITER= 1000 +DEFORM_STIFFNESS_TYPE= INVERSE_VOLUME +DEFORM_POISSONS_RATIO= 1e6 % % Convergence criteria ------------------------------------------------- % % interaction @@ -85,9 +80,6 @@ INNER_ITER= 51 CONV_CRITERIA= RESIDUAL CONV_STARTITER= 0 CONV_RESIDUAL_MINVAL= -9 -% grid deformation -DEFORM_STIFFNESS_TYPE= INVERSE_VOLUME -DEFORM_POISSONS_RATIO= 1e6 % % In\Out --------------------------------------------------------------- % MESH_FILENAME= mesh.su2 From af67917f852cd0286119142640d466563490eddd Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Mon, 6 Apr 2020 12:59:58 +0100 Subject: [PATCH 79/79] fix mpi consistency issues for isoparametric interpolation --- .../CIsoparametric.cpp | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/Common/src/interface_interpolation/CIsoparametric.cpp b/Common/src/interface_interpolation/CIsoparametric.cpp index fc64e5e9a720..9a6fc0934dc3 100644 --- a/Common/src/interface_interpolation/CIsoparametric.cpp +++ b/Common/src/interface_interpolation/CIsoparametric.cpp @@ -39,12 +39,13 @@ using namespace GeometryToolbox; struct DonorInfo { su2double isoparams[4] = {0.0}; /*!< \brief Interpolation coefficients. */ su2double distance = 0.0; /*!< \brief Distance from target to final mapped point on donor plane. */ + su2double checkSum = 0.0; /*!< \brief Sum of absolute coefficients (should be 1). */ unsigned iElem = 0; /*!< \brief Identification of the element. */ - int error = 2; /*!< \brief If the mapped point is "outside" of the donor. */ + int error = 0; /*!< \brief If the mapped point is "outside" of the donor. */ bool operator< (const DonorInfo& other) const { /*--- Best donor is one for which the mapped point is within bounds and closest to target. ---*/ - return (error == other.error)? (distance < other.distance) : (error < other.error); + return (fabs(checkSum-other.checkSum)<1e-6)? (distance < other.distance) : (checkSum < other.checkSum); } }; @@ -175,11 +176,12 @@ void CIsoparametric::SetTransferCoeff(const CConfig* const* config) { su2double maxDist = 0.0; unsigned long errorCount = 0, totalCount = 0; vector nearElems(nGlobalElemDonor); + vector candidateElems(min(NUM_CANDIDATE_DONORS, nGlobalElemDonor)); SU2_OMP_FOR_DYN(roundUpDiv(nVertexTarget,2*omp_get_max_threads())) - for (auto iVertex = 0u; iVertex < nVertexTarget; ++iVertex) { + for (auto iVertexTarget = 0u; iVertexTarget < nVertexTarget; ++iVertexTarget) { - auto target_vertex = target_geometry->vertex[markTarget][iVertex]; + auto target_vertex = target_geometry->vertex[markTarget][iVertexTarget]; const auto iPoint = target_vertex->GetNode(); if (!target_geometry->node[iPoint]->GetDomain()) continue; @@ -190,8 +192,7 @@ void CIsoparametric::SetTransferCoeff(const CConfig* const* config) { /*--- Find "n" closest candidate donor elements (the naive way). ---*/ iota(nearElems.begin(), nearElems.end(), 0); - auto last = nearElems.begin() + min(NUM_CANDIDATE_DONORS, nGlobalElemDonor); - partial_sort(nearElems.begin(), last, nearElems.end(), + partial_sort(nearElems.begin(), nearElems.begin()+candidateElems.size(), nearElems.end(), [&](unsigned iElem, unsigned jElem) { return SquaredDistance(nDim, coord_i, elemCentroid[iElem]) < SquaredDistance(nDim, coord_i, elemCentroid[jElem]); @@ -199,9 +200,7 @@ void CIsoparametric::SetTransferCoeff(const CConfig* const* config) { ); /*--- Evaluate interpolation for the candidates. ---*/ - array candidateElems; - - for (auto i = 0u; i < min(NUM_CANDIDATE_DONORS, nGlobalElemDonor); ++i) { + for (auto i = 0u; i < candidateElems.size(); ++i) { const auto iElem = nearElems[i]; /*--- Fetch element info. ---*/ @@ -229,28 +228,31 @@ void CIsoparametric::SetTransferCoeff(const CConfig* const* config) { for (auto iNode = 0u; iNode < nNode; ++iNode) finalCoord[iDim] += coords[iNode][iDim] * candidate.isoparams[iNode]; + candidate.checkSum = 0.0; + for (auto iNode = 0u; iNode < nNode; ++iNode) + candidate.checkSum += fabs(candidate.isoparams[iNode]); + candidate.distance = Distance(nDim, coord_i, finalCoord); if (candidate.distance != candidate.distance) // NaN check candidate.error = 2; } /*--- Find best donor. ---*/ - partial_sort(candidateElems.begin(), candidateElems.begin()+1, candidateElems.end()); - const auto& donor = candidateElems[0]; + const auto donor = min_element(candidateElems.begin(), candidateElems.end()); - if (donor.error > 1) + if (donor->error > 1) SU2_MPI::Error("Isoparametric interpolation failed, NaN detected.", CURRENT_FUNCTION); - errorCount += donor.error; - maxDist = max(maxDist, donor.distance); + errorCount += donor->error; + maxDist = max(maxDist, donor->distance); - const auto nNode = elemNumNodes[donor.iElem]; + const auto nNode = elemNumNodes[donor->iElem]; target_vertex->Allocate_DonorInfo(nNode); for (auto iNode = 0u; iNode < nNode; ++iNode) { - const auto iVertex = elemIdxNodes(donor.iElem, iNode); - target_vertex->SetDonorCoeff(iNode, donor.isoparams[iNode]); + const auto iVertex = elemIdxNodes(donor->iElem, iNode); + target_vertex->SetDonorCoeff(iNode, donor->isoparams[iNode]); target_vertex->SetInterpDonorPoint(iNode, donorPoint[iVertex]); target_vertex->SetInterpDonorProcessor(iNode, donorProc[iVertex]); }