diff --git a/AMDiS/cmake3/CMakeLists.txt b/AMDiS/cmake3/CMakeLists.txt index 11d5a09ec054cf44b7a41421be783ca0833fdd1c..6c8ad2b11871772f277166100023a82efd9810db 100644 --- a/AMDiS/cmake3/CMakeLists.txt +++ b/AMDiS/cmake3/CMakeLists.txt @@ -72,6 +72,7 @@ add_library(amdis ${SOURCE_DIR}/DOFAdmin.cc ${SOURCE_DIR}/DOFIndexed.cc ${SOURCE_DIR}/DOFMatrix.cc + ${SOURCE_DIR}/DOFSerializer.cc ${SOURCE_DIR}/DOFVector.cc ${SOURCE_DIR}/DirichletBC.cc ${SOURCE_DIR}/DualTraverse.cc diff --git a/AMDiS/cmake3/target_enable_boost.cmake b/AMDiS/cmake3/target_enable_boost.cmake index 5c41b01100c6d2f374298dcf47bc53ac51a0e2a3..cdf5f05bb817750dd4d69c80e604c0958da804ea 100644 --- a/AMDiS/cmake3/target_enable_boost.cmake +++ b/AMDiS/cmake3/target_enable_boost.cmake @@ -13,7 +13,7 @@ macro(target_enable_boost _TARGET_ _SCOPE_) endif (BOOST_LIBRARYDIR) set(BOOST_VERSION "1.48") - set(BOOST_LIBS_REQUIRED system iostreams filesystem program_options date_time thread) + set(BOOST_LIBS_REQUIRED system iostreams filesystem program_options date_time) if (WIN32) list(APPEND BOOST_LIBS_REQUIRED zlib) if (ENABLE_COMPRESSION OR AMDIS_NEED_COMPRESSION) diff --git a/AMDiS/src/DOFAdmin.h b/AMDiS/src/DOFAdmin.h index 4583f00339aa0fd45c16a2c4132c3896363d6464..1a148267202738362b15465dc231e70fa2501be3 100644 --- a/AMDiS/src/DOFAdmin.h +++ b/AMDiS/src/DOFAdmin.h @@ -182,6 +182,12 @@ namespace AMDiS { return mesh; } + /// Returns \ref mesh + inline Mesh* getMesh() + { + return mesh; + } + /// Returns \ref dofFree, the array denoting DOFs to be either free or used. inline const std::vector<bool>& getDofFree() const { diff --git a/AMDiS/src/DOFSerializer.cc b/AMDiS/src/DOFSerializer.cc new file mode 100644 index 0000000000000000000000000000000000000000..4f93377f1444b95a878426d1f2431c120ec47d25 --- /dev/null +++ b/AMDiS/src/DOFSerializer.cc @@ -0,0 +1,129 @@ +#include "DOFSerializer.h" + +#include <algorithm> + +#include "DOFVector.h" +#include "Global.h" +#include "Traverse.h" + +namespace AMDiS +{ + +// satre values of DOFVector on all macro elements to internal container +void DOFSerializer::gather(DOFVector<double> const* vec, std::vector<double>& values) +{ + std::fill(visited_.begin(), visited_.end(), false); + values.clear(); + + for (auto* macroEl : mesh_->getMacroElements()) + gather(macroEl->getIndex(), vec, values, false); +} + + +// satre values of DOFVector on macro element `macroIndex` to internal container +void DOFSerializer::gather(int macroIndex, DOFVector<double> const* vec, std::vector<double>& values, bool reset) +{ + if (reset) { + std::fill(visited_.begin(), visited_.end(), false); + values.clear(); + } + + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirstOneMacro(mesh_, macroIndex, -1, Mesh::CALL_EVERY_EL_PREORDER); + while (elInfo) { + Element *el = elInfo->getElement(); + + if (el->isLeaf()) { + gather(VERTEX, elInfo, vec, values); + if (mesh_->getDim() > 1) + gather(EDGE, elInfo, vec, values); + if (mesh_->getDim() == 3) + gather(FACE, elInfo, vec, values); + gather(CENTER, elInfo, vec, values); + } + + elInfo = stack.traverseNext(elInfo); + } +} + + +void DOFSerializer::gather(GeoIndex geo, ElInfo* elInfo, DOFVector<double> const* vec, std::vector<double>& values) +{ + int nd; + if ((nd = admin_->getNumberOfDofs(geo))) { + int vertices = mesh_->getGeo(geo); + int nd0 = admin_->getNumberOfPreDofs(geo); + int n0 = mesh_->getNode(geo); + for (int n = 0; n < vertices; n++) { + for(int d = 0; d < nd; d++) { + DegreeOfFreedom globalDof = elInfo->getElement()->getDof(n0 + n, nd0 + d); + if (!visited_[globalDof]) { + visited_[globalDof] = true; + values.push_back((*vec)[globalDof]); + } + } + } + } +} + + +// assign stored values to DOFVector, for all macro elements +void DOFSerializer::scatter(std::vector<double> const& values, DOFVector<double>* vec) const +{ + std::fill(visited_.begin(), visited_.end(), false); + counter_ = 0u; + + for (auto* macroEl : mesh_->getMacroElements()) + scatter(macroEl->getIndex(), values, vec, false); +} + + +// assign stored values to DOFVector, on macroElement with index `macroIndex` +void DOFSerializer::scatter(int macroIndex, std::vector<double> const& values, DOFVector<double>* vec, bool reset) const +{ + if (reset) { + std::fill(visited_.begin(), visited_.end(), false); + counter_ = 0u; + } + + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirstOneMacro(mesh_, macroIndex, -1, Mesh::CALL_EVERY_EL_PREORDER); + while (elInfo) { + Element *el = elInfo->getElement(); + + if (el->isLeaf()) { + scatter(VERTEX, elInfo, values, vec); + if (mesh_->getDim() > 1) + scatter(EDGE, elInfo, values, vec); + if (mesh_->getDim() == 3) + scatter(FACE, elInfo, values, vec); + scatter(CENTER, elInfo, values, vec); + } + + elInfo = stack.traverseNext(elInfo); + } +} + + +void DOFSerializer::scatter(GeoIndex geo, ElInfo* elInfo, std::vector<double> const& values, DOFVector<double>* vec) const +{ + int nd; + if ((nd = admin_->getNumberOfDofs(geo))) { + int vertices = mesh_->getGeo(geo); + int nd0 = admin_->getNumberOfPreDofs(geo); + int n0 = mesh_->getNode(geo); + for (int n = 0; n < vertices; n++) { + for(int d = 0; d < nd; d++) { + DegreeOfFreedom globalDof = elInfo->getElement()->getDof(n0 + n, nd0 + d); + if (!visited_[globalDof]) { + visited_[globalDof] = true; + assert( values.size() < counter_); + (*vec)[globalDof] = values[counter_++]; + } + } + } + } +} + + +} // end namespace AMDiS diff --git a/AMDiS/src/DOFSerializer.h b/AMDiS/src/DOFSerializer.h new file mode 100644 index 0000000000000000000000000000000000000000..3327c4562e3ab1eb349f9dfc9d5e4d2aeea7ac35 --- /dev/null +++ b/AMDiS/src/DOFSerializer.h @@ -0,0 +1,91 @@ +/****************************************************************************** + * + * AMDiS - Adaptive multidimensional simulations + * + * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved. + * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis + * + * Authors: + * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * + * This file is part of AMDiS + * + * See also license.opensource.txt in the distribution. + * + ******************************************************************************/ + + + +/** \file DOFSerializer.h */ + +#ifndef AMDIS_DOFSERIALIZER_H +#define AMDIS_DOFSERIALIZER_H + +#include <vector> +#include <algorithm> + +#include "DOFAdmin.h" +#include "ElInfo.h" +#include "Global.h" +#include "Mesh.h" +#include "Traverse.h" + +namespace AMDiS +{ + // Collect all DOFValues into a std::vector, by traversing the mesh macro-elenment wise + // Can be used to transfer data on macro elements or to store values in a file, e.g. in ARHWriter + class DOFSerializer + { + public: + + /// Constructor, stores a pointer to the DOFAdmin. If the number of values to store can be estimated, + /// pass a second argument `numValues` + DOFSerializer(DOFAdmin* admin, std::size_t numValues = 0) + : admin_(admin) + , mesh_(admin->getMesh()) + , visited_(admin->getUsedSize(), false) + {} + + + // satre values of DOFVector on all macro elements to internal container + void gather(DOFVector<double> const* vec, std::vector<double>& values); + + // satre values of DOFVector on macro element `macroIndex` to internal container + void gather(int macroIndex, DOFVector<double> const* vec, std::vector<double>& values, bool reset = true); + + + // assign stored values to DOFVector, for all macro elements + void scatter(std::vector<double> const& values, DOFVector<double>* vec) const; + + // assign stored values to DOFVector, on macroElement with index `macroIndex` + void scatter(int macroIndex, std::vector<double> const& values, DOFVector<double>* vec, bool reset = true) const; + + + protected: + + // collect values of one geometry-type + void gather(GeoIndex geo, ElInfo* elInfo, DOFVector<double> const* vec, std::vector<double>& values); + + // assign values of one geometry type + void scatter(GeoIndex geo, ElInfo* elInfo, std::vector<double> const& values, DOFVector<double>* vec) const; + + + protected: + + DOFAdmin* admin_; + Mesh* mesh_; + + // stored which DOFs were already visited during traversal + mutable std::vector<bool> visited_; + + // a counter used during assignment of values. To guarantee the same order as during gather + mutable std::size_t counter_ = 0u; + }; + +} // end namespace AMDiS + +#endif // AMDIS_DOFSERIALIZER_H diff --git a/AMDiS/src/DualTraverse.cc b/AMDiS/src/DualTraverse.cc index 8a90e6445a9678acd58ce54474d8800d46adc512..32932afe04263ccce0ca5f26f1f9e56ba77a10ea 100644 --- a/AMDiS/src/DualTraverse.cc +++ b/AMDiS/src/DualTraverse.cc @@ -111,6 +111,93 @@ namespace AMDiS { } + bool DualTraverse::traverseFirstOneMacro(Mesh *mesh1, + Mesh *mesh2, + int macroIndex, + int level1, + int level2, + Flag flag1, + Flag flag2, + ElInfo **elInfo1, + ElInfo **elInfo2, + ElInfo **elInfoSmall, + ElInfo **elInfoLarge) + { + FUNCNAME("DualTraverse::traverseFirst()"); + // replace CALL_EL_LEVEL by CALL_MG_LEVEL (covers whole domain) + if (flag1.isSet(Mesh::CALL_EL_LEVEL)) { + flag1 &= ~Mesh::CALL_EL_LEVEL; + flag1 |= Mesh::CALL_MG_LEVEL; + level1_ = level1; + } else { + level1_ = -1; + } + + if (flag2.isSet(Mesh::CALL_EL_LEVEL)) { + flag2 &= ~Mesh::CALL_EL_LEVEL; + flag2 |= Mesh::CALL_MG_LEVEL; + level2_ = level2; + } else { + level2_ = -1; + } + + // replace CALL_LEAF_EL_LEVEL by CALL_MG_LEVEL (covers whole domain) + if (flag1.isSet(Mesh::CALL_LEAF_EL_LEVEL)) { + flag1 &= ~Mesh::CALL_LEAF_EL_LEVEL; + flag1 |= Mesh::CALL_MG_LEVEL; + level1_ = level1; + callLeafElLevel1_ = true; + } else { + level1_ = -1; + callLeafElLevel1_ = false; + } + + if (flag2.isSet(Mesh::CALL_LEAF_EL_LEVEL)) { + flag2 &= ~Mesh::CALL_LEAF_EL_LEVEL; + flag2 |= Mesh::CALL_MG_LEVEL; + level2_ = level2; + callLeafElLevel2_ = true; + } else { + level2_ = -1; + callLeafElLevel2_ = false; + } + + // call standard traverse + *elInfo1 = stack1.traverseFirstOneMacro(mesh1, macroIndex, level1, flag1); + while (*elInfo1 != NULL && skipEl1(*elInfo1)) { + *elInfo1 = stack1.traverseNext(*elInfo1); + } + + *elInfo2 = stack2.traverseFirstOneMacro(mesh2, macroIndex, level2, flag2); + while (*elInfo2 != NULL && skipEl2(*elInfo2)) { + *elInfo2 = stack2.traverseNext(*elInfo2); + } + + // finished ? + if (*elInfo1 == NULL || *elInfo2 == NULL) { + TEST_EXIT(*elInfo1 == *elInfo2)("invalid dual traverse\n"); + return false; + } + + rest = 1.0; + + bool accepted = check(elInfo1, elInfo2, elInfoSmall, elInfoLarge); + + // check for non domain covering level traverse + if (!accepted || + (level1_ != -1 && (*elInfo1)->getLevel() != level1_) || + (callLeafElLevel1_ && !(*elInfo1)->getElement()->isLeaf()) || + (level2_ != -1 && (*elInfo2)->getLevel() != level2_) || + (callLeafElLevel2_ && !(*elInfo2)->getElement()->isLeaf())) { + return traverseNext(elInfo1, elInfo2, elInfoSmall, elInfoLarge); + } + + fillSubElInfo(*elInfo1, *elInfo2, *elInfoSmall, *elInfoLarge); + + return true; + } + + bool DualTraverse::traverseNext(ElInfo **elInfo1, ElInfo **elInfo2, ElInfo **elInfoSmall, diff --git a/AMDiS/src/DualTraverse.h b/AMDiS/src/DualTraverse.h index f5990540ca9ad82882d04211810aff8f3d0d4c36..3a43e2a864b836a8550b2e2fad075372fb3c8bdf 100644 --- a/AMDiS/src/DualTraverse.h +++ b/AMDiS/src/DualTraverse.h @@ -78,6 +78,18 @@ namespace AMDiS { &(dualElInfo.smallElInfo), &(dualElInfo.largeElInfo)); } + + bool traverseFirstOneMacro(Mesh *mesh1, + Mesh *mesh2, + int macroIndex, + int level1, + int level2, + Flag flag1, + Flag flag2, + ElInfo **elInfo1, + ElInfo **elInfo2, + ElInfo **elInfoSmall, + ElInfo **elInfoLarge); /// Get next ElInfo combination bool traverseNext(ElInfo **elInfoNext1, diff --git a/AMDiS/src/MeshStructure.cc b/AMDiS/src/MeshStructure.cc index 4cadb1d40e7f23fad6fc8bc4b51c003dd30ceb70..059d4356b0707e7dca87ecf80d7ee3a668a4cf55 100644 --- a/AMDiS/src/MeshStructure.cc +++ b/AMDiS/src/MeshStructure.cc @@ -504,7 +504,7 @@ namespace AMDiS { elInfo = stack.traverseNext(elInfo); } } - + void MeshStructure::setMeshStructureValues(int macroElIndex, DOFVector<double>* vec, @@ -519,8 +519,8 @@ namespace AMDiS { Mesh *mesh = feSpace->getMesh(); bool feSpaceHasNonVertexDofs = (feSpace->getBasisFcts()->getDegree() > 1); int nVertexPreDofs = feSpace->getAdmin()->getNumberOfPreDofs(VERTEX); - unsigned int counter = 0; - + + std::size_t counter = 0; if (withElIndex) { TEST_EXIT(static_cast<int>(values[0]) == macroElIndex) ("Value structure code was created for macro element index %d, but should be set to macro element index %d\n", @@ -568,5 +568,4 @@ namespace AMDiS { TEST_EXIT_DBG(values.size() == counter) ("Should not happen! values size %d, counter %d\n", values.size(), counter); } - } diff --git a/AMDiS/src/Timer.cc b/AMDiS/src/Timer.cc index 10598c806703101a9608d8b618323140d630264a..31718f6854c84e4f1742e83a13cedc6732214bdf 100644 --- a/AMDiS/src/Timer.cc +++ b/AMDiS/src/Timer.cc @@ -42,7 +42,7 @@ namespace AMDiS { #endif } - double Timer::elapsed() + double Timer::elapsed() const { #ifdef HAVE_PARALLEL_DOMAIN_AMDIS return MPI::Wtime() - first_mpi; diff --git a/AMDiS/src/Timer.h b/AMDiS/src/Timer.h index 2620c73f67934a5d4203429fb7831123f0da9999..7b71a85b1fb423a960ffacc993c1cadc4d494e83 100644 --- a/AMDiS/src/Timer.h +++ b/AMDiS/src/Timer.h @@ -42,7 +42,7 @@ namespace AMDiS { void reset(); /// returns the elapsed time (from construction or last reset) to now in seconds - double elapsed(); + double elapsed() const; }; } diff --git a/configure.sh b/configure.sh index cd193f64aa7d447807b142d845c0011307375a9d..af4b439bcd5f4903cf39fedd689efa1d00383879 100755 --- a/configure.sh +++ b/configure.sh @@ -196,7 +196,7 @@ if [ "${DOWNLOAD_BOOST}" -eq "1" ]; then BOOST_PREFIX=${SRC_DIR}/packages/boost/${BOOST_VERSION} cd /tmp/src/boost - ./bootstrap.sh --prefix=${BOOST_PREFIX} --with-libraries=system,iostreams,filesystem,program_options,date_time,test,thread + ./bootstrap.sh --prefix=${BOOST_PREFIX} --with-libraries=system,iostreams,filesystem,program_options,date_time,test,thread,mpi,serialization if [ "${ENABLE_COMPRESSION}" = "ON" ]; then ./b2 -s cxxflags="-std=c++14" --build-type=minimal variant=release install else diff --git a/tools/install_boost.sh b/tools/install_boost.sh index 36b56bfa012b52ec5bccdea16d9ff6e7f4a05b53..a71c33cb3150a0b463f228fb2d9fa510b860f670 100755 --- a/tools/install_boost.sh +++ b/tools/install_boost.sh @@ -5,22 +5,23 @@ set -x ROOT=${PWD} -BOOST_VERSION="1.62.0" +BOOST_VERSION="1.64.0" BOOST_FILENAME="boost_${BOOST_VERSION//[.]/_}.tar.gz" -INSTALL_PREFIX=${ROOT}/install -mkdir -p ${INSTALL_PREFIX} +BOOST_PREFIX=${ROOT}/../packages/boost/${BOOST_VERSION} +mkdir -p ${BOOST_PREFIX} BUILD_DIR=/tmp/$USER/boost_build mkdir -p ${BUILD_DIR} +# download boost +curl -SL "http://netcologne.dl.sourceforge.net/project/boost/boost/${BOOST_VERSION}/${BOOST_FILENAME}" \ + | tar --strip-components=1 -xzC ${BUILD_DIR} +cd ${BUILD_DIR} + # install boost -if [ ! -d ${INSTALL_PREFIX}/boost ]; then - curl -SL "http://netcologne.dl.sourceforge.net/project/boost/boost/${BOOST_VERSION}/${BOOST_FILENAME}" \ - | tar --strip-components=1 -xzC ${BUILD_DIR} - cd ${BUILD_DIR} - ./bootstrap.sh --prefix=${INSTALL_PREFIX}/boost \ - --with-libraries=system,iostreams,filesystem,program_options,date_time,test - ./b2 -s NO_BZIP2=1 cxxflags="-std=c++11" --build-type=minimal variant=release -j 4 install - rm -rf ${BUILD_DIR} -fi +./bootstrap.sh --prefix=${BOOST_PREFIX} \ + --with-libraries=system,iostreams,filesystem,program_options,date_time,test,thread,mpi,serialization +echo "using mpi ;" >> project-config.jam +./b2 -s NO_BZIP2=1 -s NO_ZLIB=1 cxxflags="-std=c++14" --build-type=minimal variant=release install +rm -rf ${BUILD_DIR}