diff --git a/CMakeLists.txt b/CMakeLists.txt index d2c69e2fe..c523f0b68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -165,7 +165,7 @@ else() src/ASM/TimeDomain.h src/ASM/ASMs?D.h src/ASM/ASM?D.h src/ASM/ASM??DLag.h src/ASM/ASMLagBase.h src/ASM/ASMutils.h src/ASM/DomainDecomposition.h src/ASM/ItgPoint.h - src/ASM/ReactionsOnly.h + src/ASM/ReactionsOnly.h src/ASM/ASMsupel.h src/LinAlg/*.h src/SIM/*.h src/Utility/*.h 3rdparty/*.h ${CMAKE_BINARY_DIR}/IFEM.h) diff --git a/cmake/Modules/FindFMX.cmake b/cmake/Modules/FindFMX.cmake new file mode 100644 index 000000000..0c55ccd93 --- /dev/null +++ b/cmake/Modules/FindFMX.cmake @@ -0,0 +1,12 @@ +IF(FMX_LIBRARY) + SET(FMX_FIND_QUIETLY TRUE) +ENDIF(FMX_LIBRARY) + +FIND_LIBRARY(FMX_LIBRARY NAMES fmxWriter + PATHS $ENV{HOME}/lib $ENV{HOME}/.local/lib /usr/local/lib +) + +MARK_AS_ADVANCED(FMX_LIBRARY) + +INCLUDE(FindPackageHandleStandardArgs) +find_package_handle_standard_args(FMX DEFAULT_MSG FMX_LIBRARY) diff --git a/cmake/Modules/FindIFEMDeps.cmake b/cmake/Modules/FindIFEMDeps.cmake index 3dd8215ba..11f5d0e45 100644 --- a/cmake/Modules/FindIFEMDeps.cmake +++ b/cmake/Modules/FindIFEMDeps.cmake @@ -190,10 +190,9 @@ ENDIF(SPR_USE_INT4 OR SPR_USE_INT8) IF(IFEM_USE_SAMG) FIND_PACKAGE(SAMG) IF(SAMG_LIBRARIES AND SAMG_INCLUDES) - SET(IFEM_DEPLIBS ${IFEM_DEPLIBS} ${SAMG_LIBRARIES}) - SET(IFEM_DEPINCLUDES ${IFEM_DEPINCLUDES} ${SAMG_INCLUDES}) - SET(IFEM_BUILD_CXX_FLAGS "${IFEM_BUILD_CXX_FLAGS} -DHAS_SAMG -DSAMG_UNIX_LINUX=1 -DSAMG_LCASE_USCORE") - list(APPEND IFEM_DEFINITIONS -DHAS_SAMG -DSAMG_UNIX_LINUX=1 -DSAMG_LCASE_USCORE) + list(APPEND IFEM_DEPLIBS ${SAMG_LIBRARIES}) + list(APPEND IFEM_DEPINCLUDES ${SAMG_INCLUDES}) + string(APPEND IFEM_BUILD_CXX_FLAGS " -DHAS_SAMG -DSAMG_UNIX_LINUX=1 -DSAMG_LCASE_USCORE") ENDIF(SAMG_LIBRARIES AND SAMG_INCLUDES) ENDIF(IFEM_USE_SAMG) @@ -201,10 +200,8 @@ ENDIF(IFEM_USE_SAMG) IF(IFEM_USE_VTFWRITER) FIND_PACKAGE(VTFWriter) IF(VTFWRITER_LIBRARIES AND VTFWRITER_INCLUDES) - SET(IFEM_DEPLIBS ${IFEM_DEPLIBS} ${VTFWRITER_LIBRARIES}) - SET(IFEM_DEPINCLUDES ${IFEM_DEPINCLUDES} ${VTFWRITER_INCLUDES}) - SET(IFEM_CXX_FLAGS "${IFEM_CXX_FLAGS} -DHAS_VTFAPI=${VTFAPI}") - SET(IFEM_BUILD_CXX_FLAGS "${IFEM_BUILD_CXX_FLAGS} -DHAS_VTFAPI=${VTFAPI}") + list(APPEND IFEM_DEPLIBS ${VTFWRITER_LIBRARIES}) + list(APPEND IFEM_DEPINCLUDES ${VTFWRITER_INCLUDES}) list(APPEND IFEM_DEFINITIONS -DHAS_VTFAPI=${VTFAPI}) ENDIF(VTFWRITER_LIBRARIES AND VTFWRITER_INCLUDES) ENDIF(IFEM_USE_VTFWRITER) @@ -213,8 +210,8 @@ ENDIF(IFEM_USE_VTFWRITER) IF(IFEM_USE_OPENMP) FIND_PACKAGE(OpenMP) IF(OPENMP_FOUND) - SET(IFEM_CXX_FLAGS "${IFEM_CXX_FLAGS} ${OpenMP_CXX_FLAGS} -DUSE_OPENMP") - SET(IFEM_BUILD_CXX_FLAGS "${IFEM_BUILD_CXX_FLAGS} ${OpenMP_CXX_FLAGS} -DUSE_OPENMP") + string(APPEND IFEM_CXX_FLAGS " ${OpenMP_CXX_FLAGS} -DUSE_OPENMP") + string(APPEND IFEM_BUILD_CXX_FLAGS " ${OpenMP_CXX_FLAGS} -DUSE_OPENMP") list(APPEND IFEM_DEFINITIONS -DUSE_OPENMP=1) ENDIF(OPENMP_FOUND) ENDIF(IFEM_USE_OPENMP) @@ -274,13 +271,23 @@ if(IFEM_USE_TRACY) endif() endif() +# FMX matrix files +if(IFEM_USE_FMX) + find_package(FMX) + if(FMX_FOUND) + list(APPEND IFEM_DEPLIBS ${FMX_LIBRARY}) + string(APPEND IFEM_BUILD_CXX_FLAGS " -DHAS_FMXREADER=1") + message(STATUS "FMX matrix file support enabled") + endif() +endif() + # Portability issues include(CheckFunctionExists) set(CMAKE_REQUIRED_DEFINITIONS) set(CMAKE_REQUIRED_FLAGS) check_function_exists(get_current_dir_name unistd.h HAVE_GET_CURRENT_DIR_NAME) # lacks on osx if(HAVE_GET_CURRENT_DIR_NAME) - set(IFEM_CXX_FLAGS "${IFEM_CXX_FLAGS} -DHAVE_GET_CURRENT_DIR_NAME=1") + string(APPEND IFEM_CXX_FLAGS " -DHAVE_GET_CURRENT_DIR_NAME=1") list(APPEND IFEM_DEFINITIONS -DHAVE_GET_CURRENT_DIR_NAME=1) endif() @@ -298,10 +305,10 @@ include(CheckCXXCompilerFlag) check_cxx_compiler_flag(-Wall HAS_WALL) check_cxx_compiler_flag(-Wno-parentheses HAS_PARENTHESES) if(HAS_WALL) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") + string(APPEND CMAKE_CXX_FLAGS " -Wall") endif() if(HAS_PARENTHESES) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-parentheses") + string(APPEND CMAKE_CXX_FLAGS " -Wno-parentheses") endif() set(IFEM_REGTEST_SCRIPT ${IFEM_PATH}/Apps/Common/scripts/regtest.sh.in) diff --git a/cmake/Modules/IFEMOptions.cmake b/cmake/Modules/IFEMOptions.cmake index 9ac47d6ae..938b07efb 100644 --- a/cmake/Modules/IFEMOptions.cmake +++ b/cmake/Modules/IFEMOptions.cmake @@ -8,13 +8,13 @@ OPTION(IFEM_USE_ISTL "Compile with dune-istl support?" ON) OPTION(IFEM_USE_SLEPC "Compile with SLEPc support?" OFF) set(IFEM_USE_SPR "OFF" CACHE STRING "Compile with SPR support?") set_property(CACHE IFEM_USE_SPR PROPERTY STRINGS ON I32 I64 OFF) -OPTION(IFEM_USE_SPR "Compile with SPR support?" OFF) OPTION(IFEM_USE_SAMG "Compile with SAMG support?" OFF) -OPTION(IFEM_USE_HDF5 "Compile with HDF5 support?" ON) -OPTION(IFEM_USE_VTFWRITER "Compile with VTFWriter support?" ON) OPTION(IFEM_USE_UMFPACK "Compile with UMFPACK support?" ON) +OPTION(IFEM_USE_VTFWRITER "Compile with VTFWriter support?" ON) +OPTION(IFEM_USE_HDF5 "Compile with HDF5 support?" ON) OPTION(IFEM_USE_CEREAL "Compile with cereal support?" ON) OPTION(IFEM_USE_ZOLTAN "Compile with zoltan support?" OFF) +OPTION(IFEM_USE_FMX "Compile with FMX-file support?" OFF) OPTION(IFEM_AS_SUBMODULE "Compile IFEM as a submodule of apps?" OFF) OPTION(IFEM_WHOLE_PROG_OPTIM "Compile IFEM with link-time optimizations?" OFF) OPTION(IFEM_TEST_MEMCHECK "Run tests through valgrind?" OFF) diff --git a/src/ASM/ASMsupel.C b/src/ASM/ASMsupel.C index 8e10aabb5..cd6931a62 100644 --- a/src/ASM/ASMsupel.C +++ b/src/ASM/ASMsupel.C @@ -19,6 +19,19 @@ #include "Vec3Oper.h" #include +#ifdef HAS_FMXREADER +extern "C" { + void initfmx_(); + int readfmx_(const char* fname, const int* itype, + double* data, const int* nval, const int nchar); + int readfsm_(const char* fname, + int* ndof, int* ndof1, int* ndof2, int* nceq, int* nmmceq, + int* meqn, int* meqn1, int* meqn2, + int* mmceq, int* mpmceq, double* ttcc, + const int nchar = 0); +} +#endif + bool ASMsupel::read (std::istream& is) { @@ -31,55 +44,243 @@ bool ASMsupel::read (std::istream& is) for (Vec3& Xn : Xsup) is >> Xn; }; - myElmMat.resize(1,1); + // Lambda function for reading a FEDEM superelement matrix file. + auto&& readFMX = [&is](Matrix& M, int itype) -> int + { + int m, n, ierr = -99; + std::string fileName; + is >> m >> n >> fileName; + M.resize(m,n); +#ifdef HAS_FMXREADER + initfmx_(); + int ndim = m*n; + ierr = readfmx_(fileName.c_str(),&itype,M.ptr(),&ndim,fileName.size()); +#endif + if (ierr < 0) + std::cerr <<" *** readFMX: Failed to read matrix file \"" + << fileName <<"\" of type "<< itype + <<" (ierr = "<< ierr <<")" << std::endl; + + return ierr; + }; + + // Lambda function for reading a SAM data file from FEDEM. + auto&& readFSM = [&is](MiniSAM& sam) -> int + { + int ierr = -99; + std::string fileName; + is >> fileName; +#ifdef HAS_FMXREADER + initfmx_(); + double dummy = 0.0; + int ndof, ndof1, ndof2, nceq, nmmceq; + ierr = readfsm_(fileName.c_str(),&ndof,&ndof1,&ndof2,&nceq,&nmmceq, + &ierr,&ierr,&ierr,&ierr,&ierr,&dummy,fileName.size()); + if (ierr >= 0) + { + sam.meqn.resize(ndof); + sam.meqn1.resize(ndof1); + sam.meqn2.resize(ndof2); + sam.ttcc.resize(nmmceq); + sam.mmceq.resize(nmmceq); + sam.mpmceq.resize(nceq+1); + ierr = readfsm_("",&ndof,&ndof1,&ndof2,&nceq,&nmmceq, + sam.meqn.data(),sam.meqn1.data(),sam.meqn2.data(), + sam.mmceq.data(),sam.mpmceq.data(),sam.ttcc.data()); + } +#endif + if (ierr < 0) + std::cerr <<" *** readFSM: Failed to read SAM arrays from file \"" + << fileName <<"\" (ierr = "<< ierr <<")" << std::endl; + else + sam.findDofP2(); + + return ierr; + }; + + // Lambda function checking if myElmMat needs to be allocated, + // and whether we are reading a binary file or not. + auto&& checkMatrix = [&is,this](bool fmx = false) -> bool + { + if (myElmMat.empty()) + myElmMat.resize(2,1,3); + if (fmx) + { + char c = 0; + if (is.get(c) && c == 'x') + return true; + else if (is) + is.putback(c); + } + return false; + }; - char c; - int readMat = 0; - while (readMat < 7 && is.get(c)) + char c = 0; + Matrix tmpMat; + std::string comment; + int readMat = 0, ierr = 0; + while (readMat < 7 && is.get(c) && ierr >= 0) switch (c) { case 'K': case 'k': - is >> myElmMat.A.front(); - if (c == 'K') // assume stored column-wise - myElmMat.A.front().transpose(); + // Read stiffness matrix file + if (checkMatrix(true)) + ierr = readFMX(myElmMat.A.front(),1); + else + { + is >> myElmMat.A.front(); + if (c == 'K') // assume stored column-wise + myElmMat.A.front().transpose(); + } readMat |= 1; break; + + case 'M': + case 'm': + // Read mass matrix file + if (checkMatrix(true)) + ierr = readFMX(myElmMat.A.back(),2); + else + { + is >> myElmMat.A.back(); + if (c == 'M') // assume stored column-wise + myElmMat.A.back().transpose(); + } + readMat |= 1; + break; + + case 'B': + // Read recovery matrix file (binary only) + if (is.get(c) && c == 'x') + ierr = readFMX(myRecMat,4); + else if (is) + is.putback(c); + break; + + case 'S': + // Read SAM matrix file (binary only) + if (is.get(c) && c == 'x') + ierr = readFSM(mySAM); + else if (is) + is.putback(c); + break; + + case 'g': + // Read gravity forces file (binary only) + if (checkMatrix(true)) + { + if ((ierr = readFMX(tmpMat,3)) >= 0 && !gravity.isZero()) + if (!tmpMat.multiply(gravity.vec(),myElmMat.b.front())) + return false; + readMat |= 2; + } + break; + case 'R': + // Read right-hand-side vector + checkMatrix(); is >> myElmMat.b.front(); readMat |= 2; break; + case 'L': - { - // The load vector is stored as a ndof x 1 matrix and not a vector - Matrix tmpMat; - is >> tmpMat; - myElmMat.b.front() = tmpMat.getColumn(1); - } + // Read load vector. + // It is assumed stored as a ndof x 1 matrix and not a vector. + checkMatrix(); + is >> tmpMat; + myElmMat.b.front() = tmpMat.getColumn(1); readMat |= 2; break; + case 'G': + // Read supernode coordinates readCoord(myNodes); readMat |= 4; break; + + case '#': + // Comment line - print and ignore + if (std::getline(is,comment)) + std::cout << comment << std::endl; + break; + case '\n': + // Blank line - skip break; + default: is.putback(c); if (readMat) { - std::cerr <<" *** ASMsupel::read: Unknown label "<< c << std::endl; + std::cerr <<" *** ASMsupel::read: Unknown label "<< c + <<" ("<< static_cast(c) <<")"<< std::endl; return false; } else { // Assuming the order G, K, L but without the labels + checkMatrix(); readCoord(myNodes); is >> myElmMat.A.front() >> myElmMat.b.front(); readMat = 7; } } - return readMat == 7 && is.good(); + // Calculate the total external force + for (size_t i = 0; i < myElmMat.c.size() && i < 3; i++) + myElmMat.c[i] = myElmMat.b.front().sum(i,nf); + + return readMat == 7 && is.good() && ierr >= 0; +} + + +void ASMsupel::MiniSAM::findDofP2 () +{ + dofP2.clear(); + dofP2.reserve(meqn2.size()); + + int ipos = 0; + for (int ieq : meqn) + if ((ipos = utl::findIndex(meqn2,ieq)) >= 0) + dofP2.push_back(ipos+1); +} + + +void ASMsupel::MiniSAM::print (std::ostream& os) const +{ + if (meqn.empty()) + return; + + if (mpmceq.size() > 1) + { + os <<"\nSAM constraints:"; + for (size_t iceq = 1; iceq < mpmceq.size(); iceq++) + { + int ip = mpmceq[iceq-1]; + if (ip < mpmceq[iceq]) + { + os <<"\n"<< iceq <<": "<< mmceq[ip-1]; + if (fabs(ttcc[ip-1]) > 1.0e-15) + os <<"*("<< ttcc[ip-1] <<")"; + while (++ip < mpmceq[iceq]) + os <<" "<< mmceq[ip-1] <<"*("<< ttcc[ip-1] <<")"; + } + } + } + + os <<"\nSAM meqn:"; + for (size_t idof = 0; idof < meqn.size(); idof++) + os << (idof%6 ? " " : "\n") << meqn[idof]; + os <<"\nSAM meqn1:"; + for (size_t i1 = 0; i1 < meqn1.size(); i1++) + os << (i1%6 ? " " : "\n") << meqn1[i1]; + os <<"\nSAM meqn2:"; + for (size_t i2 = 0; i2 < meqn2.size(); i2++) + os << (i2%6 ? " " : "\n") << meqn2[i2]; + os <<"\nSAM dofP2:"; + for (size_t i = 0; i < dofP2.size(); i++) + os << (i%6 ? " " : "\n") << dofP2[i]; + os << std::endl; } @@ -144,6 +345,15 @@ const IntVec& ASMsupel::getNodeSet (int iset) const } +bool ASMsupel::isInNodeSet (int iset, int inod) const +{ + if (iset < 1 || iset > static_cast(nodeSets.size())) + return false; + + return utl::findIndex(nodeSets[iset-1].second,inod) >= 0; +} + + int ASMsupel::parseNodeSet (const std::string& setName, const char* cset) { int iset = this->getNodeSetIdx(setName)-1; @@ -281,3 +491,58 @@ bool ASMsupel::transform (const Matrix& Tlg) return true; } + + +bool ASMsupel::recoverInternals (const Vector& supSol, Vector& fullSol) const +{ +#if SP_DEBUG > 2 + mySAM.print(std::cout); +#endif + + // Reorder supSol to match the expected ordering of the recovery matrix + Vector ve(mySAM.meqn2.size()), vi; + for (size_t i = 1; i <= mySAM.dofP2.size(); i++) + ve(mySAM.dofP2[i-1]) = supSol(i); + + // Calculate the internal DOFs; vi = myRecMat * ve + if (!myRecMat.multiply(ve,vi)) + return false; + + // Establish the total equation-order solution vector, svec + int nceq = mySAM.mpmceq.size()-1; + int ndof = mySAM.meqn.size(); + int neq = *std::max_element(mySAM.meqn.begin(),mySAM.meqn.end()); + Vector sveq(neq); + for (size_t i1 = 1; i1 <= mySAM.meqn1.size(); i1++) + sveq(mySAM.meqn1[i1-1]) = vi(i1); + for (size_t i2 = 1; i2 <= mySAM.meqn2.size(); i2++) + sveq(mySAM.meqn2[i2-1]) = ve(i2); + +#if SP_DEBUG > 2 + std::cout <<"ve:"<< std::scientific << ve; + std::cout.unsetf(std::ios_base::floatfield); + std::cout <<"vi:"<< vi <<"sveq:"<< sveq; +#endif + + // Expand to DOF-order while accounting for constraint equations + fullSol.resize(ndof,true); + for (int idof = 1; idof <= ndof; idof++) + { + int ieq = mySAM.meqn[idof-1]; + int iceq = -ieq; + int jdof = 0; + if (ieq > 0 && ieq <= neq) + fullSol(idof) = sveq(ieq); + else if (iceq > 0 && iceq <= nceq) + for (int ip = mySAM.mpmceq[iceq-1]; ip < mySAM.mpmceq[iceq]-1; ip++) + if ((jdof = mySAM.mmceq[ip]) > 0 && jdof <= ndof) + if ((ieq = mySAM.meqn[jdof-1]) > 0 && ieq <= neq) + fullSol(idof) += mySAM.ttcc[ip]*sveq[ieq-1]; + } + +#ifdef SP_DEBUG + std::cout <<"\nExpanded solution vector for substructure "<< idx+1 + << fullSol; +#endif + return true; +} diff --git a/src/ASM/ASMsupel.h b/src/ASM/ASMsupel.h index 8596585a4..3adb44200 100644 --- a/src/ASM/ASMsupel.h +++ b/src/ASM/ASMsupel.h @@ -24,6 +24,7 @@ \brief Driver for assembly of general superelements. \details This class contains methods for assembly of superelements resulting from static condensation or reduced order modeling. + It also supports reading superelement matrix files from FEDEM (fmx-files). */ class ASMsupel : public ASMbase @@ -35,8 +36,6 @@ class ASMsupel : public ASMbase ASMsupel(const ASMsupel& patch, unsigned char n_f) : ASMbase(patch,n_f) {} //! \brief Default copy constructor copying everything. ASMsupel(const ASMsupel& patch) : ASMbase(patch) {} - //! \brief Empty destructor. - virtual ~ASMsupel() {} //! \brief Creates an instance by reading the given input stream. virtual bool read(std::istream& is); @@ -51,6 +50,8 @@ class ASMsupel : public ASMbase virtual int getNodeSetIdx(const std::string& setName) const; //! \brief Returns an indexed pre-defined node set. virtual const IntVec& getNodeSet(int iset) const; + //! \brief Checks if node \a inod is within predefined node set \a iset. + virtual bool isInNodeSet(int iset, int inod) const; //! \brief Defines a node set by parsing a list of node numbers. virtual int parseNodeSet(const std::string& setName, const char* cset); @@ -92,7 +93,7 @@ class ASMsupel : public ASMbase virtual bool integrate(Integrand& integrand, GlobalIntegral& glbInt, const TimeDomain&); - //! \brief Dummy method (patch patch boundaries are not defined). + //! \brief Dummy method doing nothing (patch boundaries are not defined). virtual bool integrate(Integrand&, int, GlobalIntegral&, const TimeDomain&) { return false; } @@ -117,11 +118,43 @@ class ASMsupel : public ASMbase //! \brief Applies a transformation matrix from local to global system. virtual bool transform(const Matrix& Tlg); + //! \brief Assigns the acceleration vector of gravity. + void setGravity(const Vec3& g) { gravity = g; } + + //! \brief Checks if recovery data has been read from file. + bool hasRecovery() const { return !myRecMat.empty() && !mySAM.meqn.empty(); } + + //! \brief Recovers the internal DOFs from the supernode DOFs. + //! \param[in] supSol Supernode values of the solution vector + //! \param[out] fullSol Solution values for all FE DOFs + bool recoverInternals(const Vector& supSol, Vector& fullSol) const; + private: + //! \brief Struct holding the SAM data needed for superelement recovery. + struct MiniSAM + { + RealArray ttcc; //!< Table of tables of constraint coefficients + IntVec mmceq; //!< Matrix of matrices of constraint equations + IntVec mpmceq; //!< Matrix of pointers to MCEQs + IntVec meqn; //!< Matrix of equation numbers for all DOFs + IntVec meqn1; //!< Matrix of status 1 equation numbers + IntVec meqn2; //!< Matrix of status 2 equation numbers + IntVec dofP2; //!< DOF-positions in the Schur-complement matrix + + //! \brief Computes the \ref dofP2 array. + void findDofP2(); + //! \brief Prints the SAM data to the given output stream. + void print(std::ostream& os) const; + }; + + MiniSAM mySAM; //!< Subset of SAM data needed for recovery Vec3Vec myNodes; //!< Supernode coordinates - ElmMats myElmMat; //!< Duperelement matrices + ElmMats myElmMat; //!< Superelement matrices + Matrix myRecMat; //!< Recovery matrix std::vector nodeSets; //!< Node sets for Dirichlet BCs + + Vec3 gravity; //!< Gravitation vector (for calculation of g-force load vector) }; #endif diff --git a/src/ASM/Test/TestASMsupel.C b/src/ASM/Test/TestASMsupel.C index 700d2def2..a91ca6ad8 100644 --- a/src/ASM/Test/TestASMsupel.C +++ b/src/ASM/Test/TestASMsupel.C @@ -24,14 +24,13 @@ struct TestCase class TestASMsup : public testing::Test, - public testing::WithParamInterface -{ -}; + public testing::WithParamInterface {}; TEST_P(TestASMsup, Read) { ASMsupel pch; + pch.setGravity({0.0,0.0,-9.81}); ASMbase::resetNumbering(); std::cout <<"Checking "<< GetParam().file << std::endl; std::ifstream is(GetParam().file); @@ -43,6 +42,9 @@ TEST_P(TestASMsup, Read) const std::vector testFiles = { +#ifdef HAS_FMXREADER + { "src/ASM/Test/refdata/CQUAD04.dat", 2U }, +#endif { "src/ASM/Test/refdata/Supel.dat", 2U }, { "src/ASM/Test/refdata/kjoint.dat", 4U }}; diff --git a/src/ASM/Test/refdata/CQUAD04.dat b/src/ASM/Test/refdata/CQUAD04.dat new file mode 100644 index 000000000..80a65e221 --- /dev/null +++ b/src/ASM/Test/refdata/CQUAD04.dat @@ -0,0 +1,8 @@ +Kx 12 12 src/ASM/Test/refdata/CQUAD04_ +Mx 12 12 src/ASM/Test/refdata/CQUAD04_ +gx 12 3 src/ASM/Test/refdata/CQUAD04_ +Bx 126 12 src/ASM/Test/refdata/CQUAD04_ +Sx src/ASM/Test/refdata/CQUAD04_ +G 2 +0.0 0.0 -1.0 +0.0 0.0 0.0 diff --git a/src/ASM/Test/refdata/CQUAD04__B.fmx b/src/ASM/Test/refdata/CQUAD04__B.fmx new file mode 100644 index 000000000..f77ec7761 Binary files /dev/null and b/src/ASM/Test/refdata/CQUAD04__B.fmx differ diff --git a/src/ASM/Test/refdata/CQUAD04__G.fmx b/src/ASM/Test/refdata/CQUAD04__G.fmx new file mode 100644 index 000000000..22b0c9dac Binary files /dev/null and b/src/ASM/Test/refdata/CQUAD04__G.fmx differ diff --git a/src/ASM/Test/refdata/CQUAD04__M.fmx b/src/ASM/Test/refdata/CQUAD04__M.fmx new file mode 100644 index 000000000..0ef954a3a Binary files /dev/null and b/src/ASM/Test/refdata/CQUAD04__M.fmx differ diff --git a/src/ASM/Test/refdata/CQUAD04__S.fmx b/src/ASM/Test/refdata/CQUAD04__S.fmx new file mode 100644 index 000000000..018580790 Binary files /dev/null and b/src/ASM/Test/refdata/CQUAD04__S.fmx differ diff --git a/src/ASM/Test/refdata/CQUAD04__SAM.fsm b/src/ASM/Test/refdata/CQUAD04__SAM.fsm new file mode 100644 index 000000000..1fedcdba2 Binary files /dev/null and b/src/ASM/Test/refdata/CQUAD04__SAM.fsm differ diff --git a/src/SIM/SIMoutput.h b/src/SIM/SIMoutput.h index a33fb7ddf..4693395a9 100644 --- a/src/SIM/SIMoutput.h +++ b/src/SIM/SIMoutput.h @@ -94,7 +94,7 @@ class SIMoutput : public SIMinput //! \brief Writes boundary conditions as scalar fields to the VTF-file. //! \param nBlock Running result block counter //! \param[in] iStep Load/time step identifier - bool writeGlvBC(int& nBlock, int iStep = 1) const; + virtual bool writeGlvBC(int& nBlock, int iStep = 1) const; //! \brief Writes global node numbers as scalar fields to the VTF-file. //! \param nBlock Running result block counter diff --git a/src/SIM/SIMsupel.C b/src/SIM/SIMsupel.C index 12a5443ed..48991b946 100644 --- a/src/SIM/SIMsupel.C +++ b/src/SIM/SIMsupel.C @@ -12,9 +12,9 @@ //============================================================================== #include "SIMsupel.h" -#include "ASMbase.h" +#include "ASMsupel.h" #include "ASM3D.h" -#include "IntegrandBase.h" +#include "HasGravityBase.h" #include "SAM.h" #include "Utilities.h" #include "IFEM.h" @@ -105,6 +105,10 @@ ASMbase* SIMsupel::readPatch (std::istream& isp, int pchInd, const CharVec&, ASMbase* pch = ASM3D::create(ASM::SuperElm,ncmp); if (pch) { + // Need to assign gravity vector before parsing superelement data + HasGravityBase* itgr = dynamic_cast(myProblem); + if (itgr && !itgr->getGravity().isZero()) + static_cast(pch)->setGravity(itgr->getGravity()); if (!pch->read(isp) || this->getLocalPatchIndex(pchInd+1) < 1) { delete pch; diff --git a/src/SIM/SIMsupel.h b/src/SIM/SIMsupel.h index 151f8acc5..b64193822 100644 --- a/src/SIM/SIMsupel.h +++ b/src/SIM/SIMsupel.h @@ -50,6 +50,9 @@ class SIMsupel : public SIMdummy //! \brief Returns the name of this simulator. virtual std::string getName() const { return "SIMsupel"; } + //! \brief Overridden to not write BC codes for superelement models. + virtual bool writeGlvBC(int&, int) const { return true; } + //! \brief Performs recovery of the internal DOFs for superelements. //! \param[in] glbSol Global solution vector bool recoverInternalDOFs(const Vector& glbSol);