diff --git a/AMDiS/CMakeLists.txt b/AMDiS/CMakeLists.txt index 3b9b8190a3b362d1d44b7f1da6d040ad3699c4d3..07cce3d2a4fb75d09258065ce4033396fd613a2c 100644 --- a/AMDiS/CMakeLists.txt +++ b/AMDiS/CMakeLists.txt @@ -335,6 +335,45 @@ if(ENABLE_BDDCML) endif(ENABLE_BDDCML) +if(ENABLE_EXTENSIONS) + find_path(EXTENSIONS_DIR NAMES ${SOURCE_DIR}/../../extensions/Helpers.h DOC "Path to AMDiS extensions.") + if (EXTENSIONS_DIR) + if (NOT EXISTS ${EXTENSIONS_DIR}/Helpers.h OR NOT EXISTS ${EXTENSIONS_DIR}/base_problems/BaseProblem.h) + message(FATAL_ERROR "Wrong extensions directory! Directory must contain the 'Helpers.h' and the subdirectory 'base_problems'") + else() + + SET(EXTENSIONS_SRC + ${EXTENSIONS_DIR}/Helpers.cc + ${EXTENSIONS_DIR}/BackgroundMesh.cc + ${EXTENSIONS_DIR}/GeometryTools.cc + ${EXTENSIONS_DIR}/POperators.cc + ${EXTENSIONS_DIR}/time/ExtendedRosenbrockStationary.cc + ${EXTENSIONS_DIR}/pugixml/src/pugixml.cpp) + list(APPEND COMPILEFLAGS "-DHAVE_EXTENSIONS=1") + + + if(ENABLE_BASE_PROBLEMS) + SET(BASE_PROBLEMS_SRC + ${EXTENSIONS_DIR}/base_problems/CahnHilliard.cc +# ${EXTENSIONS_DIR}/base_problems/DiffuseDomainFsi.cc + ${EXTENSIONS_DIR}/base_problems/LinearElasticity.cc + ${EXTENSIONS_DIR}/base_problems/LinearElasticityPhase.cc +# ${EXTENSIONS_DIR}/base_problems/NavierStokes_Chorin.cc +# ${EXTENSIONS_DIR}/base_problems/NavierStokesPhase_Chorin.cc + ${EXTENSIONS_DIR}/base_problems/NavierStokesPhase_TaylorHood.cc + ${EXTENSIONS_DIR}/base_problems/NavierStokes_TaylorHood.cc + ${EXTENSIONS_DIR}/base_problems/NavierStokes_TaylorHood_RB.cc + ${EXTENSIONS_DIR}/base_problems/NavierStokes_TH_MultiPhase.cc + ${EXTENSIONS_DIR}/base_problems/NavierStokes_TH_MultiPhase_RB.cc + ${EXTENSIONS_DIR}/base_problems/PhaseFieldCrystal_Base.cc +# ${EXTENSIONS_DIR}/base_problems/PhaseFieldCrystal.cc + ${EXTENSIONS_DIR}/base_problems/PhaseFieldCrystal_Phase.cc + ${EXTENSIONS_DIR}/base_problems/PhaseFieldCrystal_RB.cc) + list(APPEND COMPILEFLAGS "-DHAVE_BASE_PROBLEMS=1") + + endif(ENABLE_BASE_PROBLEMS) +endif(ENABLE_EXTENSIONS) + SET(COMPOSITE_SOURCE_DIR ${SOURCE_DIR}/compositeFEM) SET(COMPOSITE_FEM_SRC ${COMPOSITE_SOURCE_DIR}/CFE_Integration.cc @@ -361,6 +400,14 @@ list(APPEND AMDIS_INCLUDE_DIRS ${MUPARSER_SOURCE_DIR}/include) list(APPEND AMDIS_INCLUDE_DIRS ${MTL_INCLUDE_DIR}) #include_directories(${MTL_INCLUDE_DIR}) list(APPEND AMDIS_INCLUDE_DIRS ${SOURCE_DIR}) + +if(ENABLE_EXTENSIONS) + list(APPEND AMDIS_INCLUDE_DIRS ${EXTENSIONS_DIR}) + if(ENABLE_BASE_PROBLEMS) + list(APPEND AMDIS_INCLUDE_DIRS ${EXTENSIONS_DIR}/base_problems) + endif(ENABLE_BASE_PROBLEMS) +endif(ENABLE_EXTENSIONS) + #include_directories(${SOURCE_DIR}) include_directories(${AMDIS_INCLUDE_DIRS}) @@ -368,9 +415,23 @@ add_library(amdis SHARED ${AMDIS_SRC} ${PARALLEL_DOMAIN_AMDIS_SRC}) add_library(compositeFEM SHARED ${COMPOSITE_FEM_SRC}) add_library(reinit SHARED ${REINIT_SRC}) add_library(muparser SHARED ${MUPARSER_SRC}) + +if(ENABLE_EXTENSIONS) + add_library(extensions SHARED ${EXTENSIONS_SRC}) + if(ENABLE_BASE_PROBLEMS) + add_library(base_problems SHARED ${BASE_PROBLEMS_SRC}) + endif(ENABLE_BASE_PROBLEMS) +endif(ENABLE_EXTENSIONS) + #target_link_libraries(compositeFEM amdis) #target_link_libraries(reinit amdis) list(APPEND AMDIS_LIBS amdis ${Boost_LIBRARIES}) +if(ENABLE_EXTENSIONS) + list(APPEND AMDIS_LIBS extensions) + if(ENABLE_BASE_PROBLEMS) + list(APPEND AMDIS_LIBS base_problems) + endif(ENABLE_BASE_PROBLEMS) +endif(ENABLE_EXTENSIONS) if(WIN32) list(APPEND COMPILEFLAGS "-D_SCL_SECURE_NO_WARNINGS" "-D_CRT_SECURE_NO_WARNINGS") @@ -428,6 +489,52 @@ FILE(GLOB HEADERS "${SOURCE_DIR}/io/*.hh") INSTALL(FILES ${HEADERS} DESTINATION include/amdis/io) +# ========== (begin) extensions ========================== +if (ENABLE_EXTENSIONS) + FILE(GLOB HEADERS "${EXTENSIONS_DIR}/*.h") + INSTALL(FILES ${HEADERS} + DESTINATION include/amdis/extensions/) + FILE(GLOB HEADERS "${EXTENSIONS_DIR}/*.hh") + INSTALL(FILES ${HEADERS} + DESTINATION include/amdis/extensions/) + + list(APPEND deb_add_dirs "include/amdis/extensions") + + FILE(GLOB HEADERS "${EXTENSIONS_DIR}/time/*.h") + INSTALL(FILES ${HEADERS} + DESTINATION include/amdis/extensions/time/) + FILE(GLOB HEADERS "${EXTENSIONS_DIR}/time/*.hh") + INSTALL(FILES ${HEADERS} + DESTINATION include/amdis/extensions/time/) + + list(APPEND deb_add_dirs "include/amdis/extensions/time") + + FILE(GLOB HEADERS "${EXTENSIONS_DIR}/nanoflann/*.hpp") + INSTALL(FILES ${HEADERS} + DESTINATION include/amdis/extensions/nanoflann/) + + list(APPEND deb_add_dirs "include/amdis/extensions/nanoflann") + + FILE(GLOB HEADERS "${EXTENSIONS_DIR}/pugixml/src/*.hpp") + INSTALL(FILES ${HEADERS} + DESTINATION include/amdis/extensions/pugixml/) + + list(APPEND deb_add_dirs "include/amdis/extensions/pugixml") + + if(ENABLE_BASE_PROBLEMS) + FILE(GLOB HEADERS "${EXTENSIONS_DIR}/base_problems/*.h") + INSTALL(FILES ${HEADERS} + DESTINATION include/amdis/base_problems/) + FILE(GLOB HEADERS "${EXTENSIONS_DIR}/base_problems/*.hh") + INSTALL(FILES ${HEADERS} + DESTINATION include/amdis/base_problems/) + + list(APPEND deb_add_dirs "include/amdis/base_problems") + + endif(ENABLE_BASE_PROBLEMS) +endif(ENABLE_EXTENSIONS) +# ========== (end) extensions ========================== + FILE(GLOB HEADERS "${REINIT_SOURCE_DIR}/*.h") INSTALL(FILES ${HEADERS} DESTINATION include/amdis/reinit) @@ -447,6 +554,17 @@ list(APPEND deb_add_dirs "lib/amdis") install(TARGETS amdis compositeFEM reinit muparser LIBRARY DESTINATION lib/amdis/ ) +if (ENABLE_EXTENSIONS) + list(APPEND deb_add_dirs "lib/amdis/extensions") + install(TARGETS extensions + LIBRARY DESTINATION lib/amdis/extensions/ ) + if(ENABLE_BASE_PROBLEMS) + list(APPEND deb_add_dirs "lib/amdis/extensions/base_problems") + install(TARGETS base_problems + LIBRARY DESTINATION lib/amdis/base_problems/ ) + endif(ENABLE_BASE_PROBLEMS) +endif(ENABLE_EXTENSIONS) + configure_file(${AMDIS_SOURCE_DIR}/AMDISConfig.cmake.in ${AMDIS_BINARY_DIR}/AMDISConfig.cmake @ONLY diff --git a/AMDiS/src/Functors.h b/AMDiS/src/Functors.h index d0555a7315f223b238fe9c86316823b6731d123a..73cdb35c132a401e1710a10d0f98313ca5234588 100644 --- a/AMDiS/src/Functors.h +++ b/AMDiS/src/Functors.h @@ -100,18 +100,6 @@ struct Diff : public BinaryAbstractFunction<T,T,T> T operator()(const T &v1, const T &v2) const { return abs(v1-v2); } }; -template<typename T> -struct L1Diff : public BinaryAbstractFunction<T,T,T> -{ - T operator()(const T &v1, const T &v2) const { return abs(v1-v2); } -}; - -template<typename T> -struct L2Diff : public BinaryAbstractFunction<T,T,T> -{ - T operator()(const T &v1, const T &v2) const { return sqr(v1-v2); } -}; - template<typename T> struct Abs : public AbstractFunction<T,T> { @@ -181,6 +169,18 @@ struct Norm2Sqr_comp3 : public TertiaryAbstractFunction<T,T,T,T> T operator()(const T &v1, const T &v2, const T &v3) const { return sqr(v1)+sqr(v2)+sqr(v3); } }; +template<typename T> +struct L1Diff : public BinaryAbstractFunction<T,T,T> +{ + T operator()(const T &v1, const T &v2) const { return abs(v1-v2); } +}; + +template<typename TOut, typename T=TOut> +struct L2Diff : public BinaryAbstractFunction<TOut,T,T> +{ + TOut operator()(const T &v1, const T &v2) const { return Norm2<TOut, T>()(v1-v2); } +}; + template<typename T> struct Vec1WorldVec : public AbstractFunction<WorldVector<T>,T> { diff --git a/AMDiS/src/io/VtkVectorWriter.h b/AMDiS/src/io/VtkVectorWriter.h index 081cab83b27c99027ee327838fd8c1bec867af22..128e0fc5878800d7cb060354d49fa02c8974c647 100644 --- a/AMDiS/src/io/VtkVectorWriter.h +++ b/AMDiS/src/io/VtkVectorWriter.h @@ -104,8 +104,11 @@ namespace AMDiS { inline void writeCoord(boost::iostreams::filtering_ostream &file, WorldVector<double> coord) { + file << std::scientific; + file.precision(15); + for (int i = 0; i < Global::getGeo(WORLD); i++) - file << " " << std::scientific << coord[i]; + file << " " << coord[i]; for (int i = Global::getGeo(WORLD); i < 3; i++) file << " "<<0.0; @@ -115,8 +118,11 @@ namespace AMDiS { /// Writes a world coordinate to a given file. inline void writeCoord(std::ofstream &file, WorldVector<double> coord) { + file << std::scientific; + file.precision(15); + for (int i = 0; i < Global::getGeo(WORLD); i++) - file << " " << std::scientific << coord[i]; + file << " " << coord[i]; for (int i = Global::getGeo(WORLD); i < 3; i++) file << " "<<0.0; diff --git a/AMDiS/src/io/VtkVectorWriter.hh b/AMDiS/src/io/VtkVectorWriter.hh index 965d9e987934791be1ba621231c0973c7f410e05..cf1818e9535c863eb9e61d0f16a1f7c8d4023cfb 100644 --- a/AMDiS/src/io/VtkVectorWriter.hh +++ b/AMDiS/src/io/VtkVectorWriter.hh @@ -251,7 +251,7 @@ namespace AMDiS { DOFVector< std::list<WorldVector<double> > >::Iterator coordIt(dofCoords, USED_DOFS); file << std::scientific; - file.precision(5); + file.precision(15); // Write the values for all vertex DOFs. for (intPointIt.reset(), valueIt.reset(), coordIt.reset(); diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt index af25bdb426d1d243608331d133954e0bcc89e016..24a0a85675347c241fb9dcaf029a201d0c87c54a 100644 --- a/demo/CMakeLists.txt +++ b/demo/CMakeLists.txt @@ -124,6 +124,31 @@ if (TOOLS_DIR) add_executable("navierStokesDd" ${navierStokesDd}) target_link_libraries("navierStokesDd" ${BASIS_LIBS}) + set(linearElasticityDd ${TOOLS_DIR}/baseProblems/LinearElasticityPhase.cc + ${TOOLS_DIR}/diffuseDomain/POperators.cc + /home/spraetor/projects/src/common/GeometryTools.cc + src/linearElasticity.cc) + add_executable("linearElasticityDd" ${linearElasticityDd}) + target_link_libraries("linearElasticityDd" ${BASIS_LIBS}) + + set(fsi ${TOOLS_DIR}/baseProblems/LinearElasticityPhase.cc + ${TOOLS_DIR}/baseProblems/NavierStokes_TaylorHood.cc + ${TOOLS_DIR}/baseProblems/NavierStokesPhase_TaylorHood.cc + ${TOOLS_DIR}/misc/Helpers.cc + ${TOOLS_DIR}/diffuseDomain/POperators.cc + /home/spraetor/projects/src/common/GeometryTools.cc + src/fsi/fluidStructureInteraction.cc) + add_executable("fsi" ${fsi}) + target_link_libraries("fsi" ${BASIS_LIBS}) + + set(ddFsi ${TOOLS_DIR}/baseProblems/DiffuseDomainFsi.cc + ${TOOLS_DIR}/misc/Helpers.cc + ${TOOLS_DIR}/diffuseDomain/POperators.cc + /home/spraetor/projects/src/common/GeometryTools.cc + src/diffuseDomainFsi.cc) + add_executable("ddFsi" ${ddFsi}) + target_link_libraries("ddFsi" ${BASIS_LIBS}) + endif() else() message(WARNING "No tools directory specified! Some demos will not be build.") diff --git a/demo/init/linearElasticity.inc.2d b/demo/init/linearElasticity.inc.2d index 1b167a12eb3d433d3cf67e7be9647f174dd42393..d8c73da92ed44f40f83fbbb0e2c22ece8da177de 100644 --- a/demo/init/linearElasticity.inc.2d +++ b/demo/init/linearElasticity.inc.2d @@ -25,7 +25,7 @@ elasticity->space->solver: umfpack elasticity->space->solver->symmetric strategy: 0 elasticity->space->solver->ell: 3 elasticity->space->solver->max iteration: 500 -elasticity->space->solver->tolerance: 1.e-8 +elasticity->space->solver->tolerance: 10% 1.e-8 elasticity->space->solver->info: 1 elasticity->space->solver->left precon: ilu diff --git a/demo/init/navierStokesDd.dat.2d b/demo/init/navierStokesDd.dat.2d index 19df53b0543e88f8d457f4e9739037f2489850e7..6209e51e65dfd64fff960e81b4f2ca535149ea4e 100644 --- a/demo/init/navierStokesDd.dat.2d +++ b/demo/init/navierStokesDd.dat.2d @@ -2,7 +2,7 @@ dimension of world: 2 % ====================== VARIABLES ======================== output_folder: output -output_postfix: _phase +output_postfix: _phase2 mesh_name: mesh polynomial-degree: 1 diff --git a/demo/init/navierStokes_TaylorHood.inc.2d b/demo/init/navierStokes_TaylorHood.inc.2d index 94d008eecbffdaeff792609e0171dde26e6354d2..868aff11896b70ce32132f9e3bdbce792d290398 100644 --- a/demo/init/navierStokes_TaylorHood.inc.2d +++ b/demo/init/navierStokes_TaylorHood.inc.2d @@ -42,7 +42,7 @@ ns->space->solver->symmetric strategy: 0 ns->space->solver->ell: 3 ns->space->solver->max iteration: 500 ns->space->solver->restart: 10 % only used for GMRES -ns->space->solver->tolerance: 1.e-8 +ns->space->solver->tolerance: 10 %1.e-8 ns->space->solver->info: 1 ns->space->solver->left precon: ilu diff --git a/demo/src/navierStokes.h b/demo/src/navierStokes.h index a97d758b1037ec5d2637fc79ddb52c865195f40a..f01bdd0c867dd419c7a43fbc710026f95cec1e32 100644 --- a/demo/src/navierStokes.h +++ b/demo/src/navierStokes.h @@ -4,7 +4,6 @@ #define NAVIER_STOKES_H #include "AMDiS.h" -#include "Views.h" #include "GeometryTools.h" struct InflowBC : AbstractFunction<double, WorldVector<double> > @@ -19,63 +18,18 @@ protected: }; -class Polygon : public AbstractFunction<double, WorldVector<double> > +struct MinWrapper : AbstractFunction<double, WorldVector<double> > { -public: - - Polygon(WorldVector<double> x0_, WorldVector<double> x1_, WorldVector<double> x2_, WorldVector<double> x3_) - { - vertices.push_back(x0_); - vertices.push_back(x1_); - vertices.push_back(x2_); - vertices.push_back(x3_); - vertices.push_back(x0_); - } - - Polygon(std::vector<WorldVector<double> > xi_) : vertices(xi_) { } + MinWrapper(AbstractFunction<double, WorldVector<double> >* dist1_, AbstractFunction<double, WorldVector<double> >* dist2_) + : dist1(dist1_), dist2(dist2_) {} double operator()(const WorldVector<double>& x) const { - double result = 1.e15; - for (size_t i = 0; i < vertices.size()-1; i++) - result = std::min(result, meshconv::distance_point_line_2d(x.begin(), vertices[i].begin(), vertices[i+1].begin())); - return result * (meshconv::point_in_polygon(x.begin(), vertices) ? -1.0 : 1.0); - } - - void refine(int np) - { - std::vector<WorldVector<double> > newVertices; - - for (size_t i = 0; i < vertices.size()-1; i++) { - for (size_t j = 0; j < np-1; j++) { - double lambda = static_cast<double>(j)/static_cast<double>(np - 1.0); - WorldVector<double> p = lambda*vertices[i+1] + (1.0-lambda)*vertices[i]; - newVertices.push_back(p); - } - } - swap(vertices, newVertices); + return std::min((*dist1)(x), (*dist2)(x)); } - - void move(const DOFVector<WorldVector<double> >* velocity) - { - for (size_t i = 0; i < vertices.size()-1; i++) { - WorldVector<double> shift = evalAtPoint(*velocity, vertices[i]); - vertices[i] += shift; - } - vertices[vertices.size()-1] = vertices[0]; - } - - void move(AbstractFunction<WorldVector<double>, WorldVector<double> >* velocity) - { - for (size_t i = 0; i < vertices.size()-1; i++) { - WorldVector<double> shift = (*velocity)(vertices[i]); - vertices[i] += shift; - } - vertices[vertices.size()-1] = vertices[0]; - } - private: - std::vector<WorldVector<double> > vertices; + AbstractFunction<double, WorldVector<double> >* dist1; + AbstractFunction<double, WorldVector<double> >* dist2; }; #endif diff --git a/demo/src/navierStokes_diffuseDomain.cc b/demo/src/navierStokes_diffuseDomain.cc index e80d05bf5c116313e86790f0133963be472c2ef2..b2a226c3dae933b0af629eaaf51bcc33e9d18ed1 100644 --- a/demo/src/navierStokes_diffuseDomain.cc +++ b/demo/src/navierStokes_diffuseDomain.cc @@ -13,11 +13,21 @@ using namespace boost::posix_time; struct BeamDisplacement1d : AbstractFunction<double, double> { - BeamDisplacement1d(double P_, double L_, double EI_, double* time_, double tau_) : P(P_), L(L_), EI(EI_), time(time_), tau(tau_) {} + BeamDisplacement1d(double P_, double L_, double EI_, double* time_ = NULL, double* tau_ = NULL) : P(P_), L(L_), EI(EI_), time(time_), tau(tau_) {} double operator()(const double& x) const { - return (*time < DBL_TOL ? 0.0 : (sin(*time)-sin(*time - tau))*P*sqr(x)*(3.0*L-x)/(6.0*EI)); + return (*time < DBL_TOL ? 0.0 : (sin(*time)-sin(*time - *tau))*P*sqr(x)*(3.0*L-x)/(6.0*EI)); + } + + void setTimePtr(double* time_) + { + time = time_; + } + + void setTauPtr(double* tau_) + { + tau = tau_; } private: @@ -25,12 +35,12 @@ private: double L; double EI; double* time; - double tau; + double* tau; }; struct BeamDisplacement : AbstractFunction<WorldVector<double>, WorldVector<double> > { - BeamDisplacement(double P, double L, double EI, double* time, double tau, WorldVector<double> fixedPoint_) + BeamDisplacement(double P, double L, double EI, WorldVector<double> fixedPoint_, double* time = NULL, double* tau = NULL) : fct(new BeamDisplacement1d(P, L, EI, time, tau)), fixedPoint(fixedPoint_) {} WorldVector<double> operator()(const WorldVector<double>& x) const @@ -39,9 +49,19 @@ struct BeamDisplacement : AbstractFunction<WorldVector<double>, WorldVector<doub displacement[1] = (x[0] >= fixedPoint[0] ? (*fct)(x[0] - fixedPoint[0]) : 0.0); return displacement; } - + + void setTimePtr(double* time_) + { + fct->setTimePtr(time_); + } + + void setTauPtr(double* tau_) + { + fct->setTauPtr(tau_); + } + private: - AbstractFunction<double, double>* fct; + BeamDisplacement1d* fct; WorldVector<double> fixedPoint; }; @@ -93,14 +113,8 @@ public: refinement->refine(10); phaseField->interpol(new SignedDistFctToPhaseField(getEpsilon(), obstacle, -3.0)); - - double P = 0.1, L = 2.0, EI = 1.0; - WorldVector<double> fixedPoint; fixedPoint[0] = 2.5; fixedPoint[1] = 2.0; - Parameters::get("obstacle->P",P); - Parameters::get("obstacle->L",L); - Parameters::get("obstacle->EI",EI); - Parameters::get("obstacle->fixed point",fixedPoint); - beamDisplacement = new BeamDisplacement(P, L, EI, adaptInfo->getTimePtr(), adaptInfo->getTimestep(), fixedPoint); + beamDisplacement->setTimePtr(adaptInfo->getTimePtr()); + beamDisplacement->setTauPtr(adaptInfo->getTimestepPtr()); obstacle->refine(10); } @@ -112,9 +126,14 @@ protected: AbstractFunction<double, WorldVector<double> > *zero = new AMDiS::Const<double, WorldVector<double> >(0.0); size_t dow = Global::getGeo(WORLD); - WorldVector<double> nullVec; nullVec.set(0.0); - AbstractFunction<WorldVector<double>, WorldVector<double> > *zeroVec = new AMDiS::Const<WorldVector<double>, WorldVector<double> >(nullVec); - super::setBcFct(zeroVec); + double P = 0.1, L = 2.0, EI = 1.0; + WorldVector<double> fixedPoint; fixedPoint[0] = 2.5; fixedPoint[1] = 2.0; + Parameters::get("obstacle->P",P); + Parameters::get("obstacle->L",L); + Parameters::get("obstacle->EI",EI); + Parameters::get("obstacle->fixed point",fixedPoint); + beamDisplacement = new BeamDisplacement(P, L, EI, fixedPoint); + super::setBcFct(beamDisplacement); super::fillBoundaryConditions(); @@ -139,8 +158,8 @@ protected: Parameters::get("ns->Um",Um); /// at left wall: prescribed velocity - getProblem(0)->addDirichletBC(2, 0, 0, new InflowBC(H,Um)); - getProblem(0)->addDirichletBC(2, 1, 1, zero); +// getProblem(0)->addDirichletBC(2, 0, 0, new InflowBC(H,Um)); +// getProblem(0)->addDirichletBC(2, 1, 1, zero); } void initTimestep(AdaptInfo* adaptInfo) @@ -156,7 +175,7 @@ protected: private: DOFVector<double>* phaseField; - AbstractFunction<WorldVector<double>, WorldVector<double> >* beamDisplacement; + BeamDisplacement* beamDisplacement; Polygon* obstacle; SignedDistRefinement* refFunction; diff --git a/extensions/BackgroundMesh.cc b/extensions/BackgroundMesh.cc new file mode 100644 index 0000000000000000000000000000000000000000..9e098169eb28c47bce819fb7d5fc880490a4f9b6 --- /dev/null +++ b/extensions/BackgroundMesh.cc @@ -0,0 +1,373 @@ +#include "BackgroundMesh.h" +#include "VectorOperations.h" // getMin, sort, CompairPair +#include "Initfile.h" + +namespace experimental { + + std::map<const FiniteElemSpace*, std::pair<int, Box*> > Box::boxMap; + + + Box::Box(int DOW_, std::vector<int> N_) + : DOW(DOW_), N(N_), boxFilled(false) + { + min_corner.set(-1.0); + max_corner.set(1.0); + init(); + } + + + Box::Box(int DOW_, PointType min_corner_, PointType max_corner_, std::vector<int> N_) + : DOW(DOW_), + min_corner(min_corner_), + max_corner(max_corner_), + N(N_), boxFilled(false) + { + init(); + } + + + void Box::fillBox(const FiniteElemSpace* feSpace) + { + DOFVector<WorldVector<double> > coords(feSpace, "coords"); + feSpace->getMesh()->dofCompress(); + feSpace->getMesh()->getDofIndexCoords(feSpace, coords); + + for (DegreeOfFreedom i = 0; i < coords.getUsedSize(); i++) { + PointType location(coords[i]); + addData(location, std::make_pair(i, location)); + } + boxFilled = true; + } + + + void Box::clearBox() + { + boxData.clear(); + } + + + void Box::clearBoxData() + { + for (size_t i = 0; i < boxData.size(); i++) { + boxData[i].clear(); + } + } + + + int Box::getMaxBoxSize() + { + size_t maxSize = 0; + for (size_t i = 0; i < boxData.size(); i++) { + maxSize = std::max(maxSize, boxData[i].size()); + } + return maxSize; + } + + + bool Box::inBox(PointType& x) + { + for (size_t i = 0; i < DOW; i++) + if (min_corner[i] > x[i] || max_corner[i] < x[i]) + return false; + return true; + } + + + /** + * + * Ny=2 + * ^---------------- + * | 4 | 5 | 6 | 7 | + * ----+---+---+---- + * | 0 | 1 | 2 | 3 | + * -----------------> Nx=4 + **/ + int Box::getBox(PointType& x) + { + std::vector<int> idx(DOW); + for (size_t i = 0; i < DOW; i++) + idx[i] = static_cast<int>((x[i]-min_corner[i])*N[i]/(max_corner[i]-min_corner[i])); +// idx[i] = static_cast<int>(floor((x[i]-min_corner[i])*N[i]/(max_corner[i]-min_corner[i]))); + return idx2nr(idx); + } + + + bool Box::getNearestData(PointType& x, DataType& data) + { + if (!inBox(x)) + return false; + + int nr = getBox(x); + unsigned int n = boxData[nr].size(); + // Box, in der x liegt, ist leer + if (n == 0) { + std::vector<DataType> datas; + getNearestData(x, datas, 1); + data = datas[0]; + return true; + } + // suche Punkt in aktueller Box, der am nächsten zu x liegt + std::vector<double> distances; + std::vector<DataType>::iterator dataIter; + for (dataIter = boxData[nr].begin(); dataIter != boxData[nr].end(); dataIter++) { + distances.push_back(distance2(x, (*dataIter).second, DOW)); + } + double minDist = 1.e15; + size_t minIdx = 0; + vector_operations::getMin(distances, minDist, minIdx); + data = boxData[nr][minIdx]; + return true; + } + + + bool Box::getNearestData(PointType& x, std::vector<DataType>& data, int nData) + { + if (!inBox(x)) + return false; + int center_box = getBox(x); + + std::set<int> nrs; nrs.insert(center_box); + double boxBoundaryDist = getBoxBoundaryDist(center_box, x); + std::vector<double> distances; + std::set<int>::iterator nrIter; + int level = 0; + for (int level = 0; data.size() < nData && nrs.size() > 0; level++) { + int oldDataSize = data.size(); + for (nrIter = nrs.begin(); nrIter != nrs.end(); nrIter++) { + data.insert(data.end(), boxData[*nrIter].begin(), boxData[*nrIter].end()); + } + int addon = data.size()-oldDataSize; + if (addon > 0) { + // 1.) bestimme Abstand zu x + int n = distances.size(); + TEST_EXIT(n + addon == data.size() && oldDataSize == n)("hier ist ein Index falsch: distances.size = %d, addon = %d, data.size = %d, oldDataSize = %d!\n",n,addon,data.size(),oldDataSize); + for (size_t i = 0; i < addon; i++) { + distances.push_back(distance2(x, data[n+i].second, DOW)); + } + // 2.) sortiere Paare aus dist und data + comparePair<double, DataType, 0> comp; + vector_operations::sort(distances, data, comp); + } + + // 3.) wenn noch nicht genügend Punkte, dann umgebende Boxen mit durchsuchen + if (data.size() < nData + || (level == 0 && distances[distances.size()-1] > boxBoundaryDist)) + { + getSurroundingBoxes(center_box, level+1, nrs); + } + } + data.resize(nData); + return true; + } + + + Box* Box::provideBackgroundMesh(const FiniteElemSpace* feSpace) + { + if (boxMap.find(feSpace) != boxMap.end()) { + if (boxMap[feSpace].first != feSpace->getMesh()->getChangeIndex()) { + boxMap[feSpace].second->clearBox(); + boxMap[feSpace].second->init(); + boxMap[feSpace].second->fillBox(feSpace); + boxMap[feSpace].first = feSpace->getMesh()->getChangeIndex(); + std::cout<<"max #data/box = "<<boxMap[feSpace].second->getMaxBoxSize()<<"\n"; + } + } else { + int N_const = 1<<Global::getGeo(WORLD); + PointType min_corner_; min_corner_.set(-1.0); + PointType max_corner_; max_corner_.set(1.0); + Parameters::get("backgroundMesh->N", N_const); // Gesamtanzahl an Boxen + Parameters::get("backgroundMesh->min_corner", min_corner_); + Parameters::get("backgroundMesh->max_corner", max_corner_); + + // Anzahl an Box je Dimension anhand der Größe des gesamten Box bestimmen + double sum_lengths = 0.0; + std::vector<double> lengths; + for (int i = 0; i < Global::getGeo(WORLD); i++) { + lengths.push_back(abs(max_corner_[i]-min_corner_[i])); + sum_lengths += lengths[i]; + } + std::vector<int> N_; + int N_sum = 0; + for (int i = 0; i < Global::getGeo(WORLD); i++) { + N_.push_back(static_cast<int>(round(pow(static_cast<double>(N_const),lengths[i]/sum_lengths)))); + N_sum += N_[i]; + } + + Box* box = new Box(Global::getGeo(WORLD), min_corner_, max_corner_, N_); + box->fillBox(feSpace); + + boxMap[feSpace] = std::make_pair(feSpace->getMesh()->getChangeIndex(), box); + std::cout<<"max #data/box = "<<boxMap[feSpace].second->getMaxBoxSize()<<"\n"; + } + + return boxMap[feSpace].second; + } + + + void Box::delete_all() + { + std::map<const FiniteElemSpace*, std::pair<int, Box*> >::iterator boxIter; + for (boxIter = boxMap.begin(); boxIter != boxMap.end(); boxIter++) { + (*boxIter).second.second->clearBox(); + delete (*boxIter).second.second; + } + boxMap.clear(); + } + + + void Box::init() + { + int maxNr = 1.0; + for (size_t i = 0; i < DOW; i++) + maxNr *= N[i]; + boxData.resize(maxNr); + + std::cout<<"\n background mesh\n"; + std::cout<<"=================\n"; + std::cout<<"min_corner: "<<min_corner<<"\n"; + std::cout<<"max_corner: "<<max_corner<<"\n"; + std::cout<<"N: "<<N<<"\n\n"; + + PointType tolerance; tolerance.set(2.0*DBL_TOL); + min_corner -= tolerance; + max_corner += tolerance; + } + + +/// protected methods +///_____________________________________________________________________________________________ + + + inline int Box::idx2nr(std::vector<int>& idx) + { + int nr = idx.back(); + std::vector<int>::reverse_iterator iIter, nIter; + for (iIter = idx.rbegin()+1, nIter = N.rbegin()+1; iIter < idx.rend(); iIter++,nIter++) { + nr = *iIter + nr*(*nIter); + } + return nr; + } + + + inline void Box::nr2idx(int nr, std::vector<int>& idx) + { + idx.resize(DOW); + switch (DOW) { + case 1: + idx[0] = nr % N[0]; + break; + case 2: + idx[1] = nr / N[0]; + idx[0] = nr % N[0]; + break; + case 3: + idx[2] = nr / (N[1]*N[0]); + nr = nr % (N[1]*N[0]); + idx[1] = nr / N[0]; + idx[0] = nr % N[0]; + break; + default: + throw(std::runtime_error("DOW="+boost::lexical_cast<std::string>(DOW)+", nur die Version für DOW=1 verwendet!")); + break; + } + } + + + void Box::getSurroundingBoxes(int center, int radius, std::set<int> &nrs) + { + std::set<int> newNrs; + std::vector<int> idx, newIdx; + nr2idx(center, idx); // --> idx + newIdx.resize(idx.size()); + double incr = m_pi/3.0/radius; + switch(DOW) { + case 1: + if (idx[0]-radius >= 0) { newIdx[0] = idx[0]-radius; newNrs.insert(idx2nr(newIdx)); } + if (idx[0]+radius < N[0]) { newIdx[0] = idx[0]+radius; newNrs.insert(idx2nr(newIdx)); } + break; + case 2: + for (double phi = 0.0; phi < 2.0*m_pi; phi += incr) { + newIdx[0] = idx[0] + static_cast<int>(round(radius*cos(phi))); + newIdx[1] = idx[1] + static_cast<int>(round(radius*sin(phi))); + if (newIdx[0] >= 0 && newIdx[0] < N[0] + && newIdx[1] >= 0 && newIdx[1] < N[1]) + newNrs.insert(idx2nr(newIdx)); + } + break; + case 3: + for (double phi = -m_pi; phi < m_pi; phi += incr) { + for (double theta = 0.0; theta < m_pi; theta += incr) { + newIdx[0] = idx[0] + static_cast<int>(round(radius*sin(theta)*cos(phi))); + newIdx[1] = idx[1] + static_cast<int>(round(radius*sin(theta)*sin(phi))); + newIdx[2] = idx[2] + static_cast<int>(round(radius*cos(theta))); + if (newIdx[0] >= 0 && newIdx[0] < N[0] + && newIdx[1] >= 0 && newIdx[1] < N[1] + && newIdx[2] >= 0 && newIdx[2] < N[2]) + newNrs.insert(idx2nr(newIdx)); + } + } + break; + default: + ERROR("unknown dimension!\n"); + } + + std::set<int>::iterator nrsIter; + for (nrsIter = nrs.begin(); nrsIter != nrs.end(); nrsIter++) + newNrs.erase(*nrsIter); + swap(nrs, newNrs); + } + + + void Box::getSurroundingBoxes(int nr, std::set<int> &surrounding_nrs) + { + std::vector<int> idx; + nr2idx(nr, idx); // --> idx + + for (size_t i = 0; i < DOW; i++) { + std::vector<int> idx_i = idx; + idx_i[i] = std::min(N[i]-1, idx_i[i]+1); + surrounding_nrs.insert(idx2nr(idx_i)); + idx_i[i] = std::max(0, idx_i[i]-2); + surrounding_nrs.insert(idx2nr(idx_i)); + } + surrounding_nrs.erase(nr); + } + + + void Box::getSurroundingBoxes(std::set<int> &nrs, std::set<int> &surrounding_nrs) + { + std::set<int>::iterator nrsIter; + for (nrsIter = nrs.begin(); nrsIter != nrs.end(); nrsIter++) + getSurroundingBoxes(*nrsIter, surrounding_nrs); + + for (nrsIter = nrs.begin(); nrsIter != nrs.end(); nrsIter++) + surrounding_nrs.erase(*nrsIter); + } + + + /// berechne die minimale Entfernung der Ränder der Box zu x + double Box::getBoxBoundaryDist(int nr, PointType& x) + { + std::vector<int> idx; + nr2idx(nr, idx); + PointType min_c, max_c; + for (size_t i = 0; i < DOW; i++) { + min_c[i] = min_corner[i] + (max_corner[i]-min_corner[i])*idx[i]/N[i]; + max_c[i] = min_corner[i] + (max_corner[i]-min_corner[i])*(idx[i]+1)/N[i]; + } + double dist = 1.e15; + for (int i = 0; i < DOW; i++) + dist = std::min(dist, std::min(abs(max_c[i]-x[i]), abs(min_c[i]-x[i]))); + return dist; + } + + + void Box::addData(PointType x, DataType data) + { + int nr = getBox(x); + if (nr < 0 || nr >= boxData.size()) + throw(std::runtime_error("box-nr out of range: nr = "+boost::lexical_cast<std::string>(nr)+", x = "+boost::lexical_cast<std::string>(x)+", boxSize = "+boost::lexical_cast<std::string>(boxData.size()))); + boxData[nr].push_back(data); + } + +} \ No newline at end of file diff --git a/extensions/BackgroundMesh.h b/extensions/BackgroundMesh.h new file mode 100644 index 0000000000000000000000000000000000000000..05d0e7b427958dcd00665f7e33554670dc7d1782 --- /dev/null +++ b/extensions/BackgroundMesh.h @@ -0,0 +1,117 @@ +/** \file BackgroundMesh.h */ + +#ifndef BACKGROUND_MESH_H +#define BACKGROUND_MESH_H + +// AMDiS-includes +#include "DOFVector.h" // DOFVector +#include "FiniteElemSpace.h" // FiniteElemSpace +#include "FixVec.h" // WorldVector +#include "Global.h" // DegreeOfFreedom + +#ifndef USE_EXPERIMENTAL +#define USE_EXPERIMENTAL +#endif + +namespace experimental { + + using namespace AMDiS; + + typedef WorldVector<double> PointType; + + inline double distance(PointType &x, PointType &y, unsigned int n) + { + double d = 0.0; + for (unsigned int i = 0; i < n; i++) + d += sqr(x[i]-y[i]); + return sqrt(d); + } + + inline double distance2(PointType &x, PointType &y, unsigned int n) + { + double d = 0.0; + for (unsigned int i = 0; i < n; i++) + d += sqr(x[i]-y[i]); + return d; + } + + typedef std::pair<DegreeOfFreedom, PointType> DataType; + + struct Box { + + Box(int DOW_, std::vector<int> N_); + Box(int DOW_, PointType min_corner_, PointType max_corner_, std::vector<int> N_); + void init(); + + void fillBox(const FiniteElemSpace* feSpace); + void clearBox(); + void clearBoxData(); + + int getMaxBoxSize(); + + bool inBox(PointType& x); + int getBox(PointType& x); + + bool getNearestData(PointType& x, DataType& data); + bool getNearestData(PointType& x, std::vector<DataType>& data, int nData); + + /** + * strategies: + * 0 .. get nearest point to x and eval DOFVector at this DOF-index + * 1 .. get n nearest points, calc weighted sum of data at these points + * 2 .. get n nearest points, calc regression plane and eval at x + * 3 .. get n nearest points, calc weighted regression plane and eval at x + **/ + template<typename T> + T evalAtPoint(DOFVector<T>& vec, PointType& x, int strategy = 0, int nrOfPoints = -1); + + static Box* provideBackgroundMesh(const FiniteElemSpace* feSpace); + static void delete_all(); + + void addData(PointType x, DataType data); + + protected: + + template<typename T> + T evalAtPoint_simple(DOFVector<T>& vec, PointType& x); + + template<typename T> + T evalAtPoint_weighted_sum(DOFVector<T>& vec, PointType& x, int nrOfPoints); + + template<typename T> + T evalAtPoint_regression(DOFVector<T>& vec, PointType& x, int nrOfPoints); + + template<typename T> + T evalAtPoint_weighted_regression(DOFVector<T>& vec, PointType& x, int nrOfPoints); + + inline int idx2nr(std::vector<int>& idx); + + inline void nr2idx(int nr, std::vector<int>& idx); + + + void getSurroundingBoxes(int nr, std::set<int> &surrounding_nrs); + void getSurroundingBoxes(int center, int radius, std::set<int> &nrs); + void getSurroundingBoxes(std::set<int> &nrs, std::set<int> &surrounding_nrs); + + /// berechne die minimale Entfernung der Ränder der Box zu x + double getBoxBoundaryDist(int nr, PointType& x); + + static std::map<const FiniteElemSpace*, std::pair<int, Box*> > boxMap; + + private: + + int DOW; + std::vector<int> N; + bool boxFilled; + + PointType min_corner; + PointType max_corner; + + std::vector<std::vector<DataType> > boxData; + }; + +} // end namespace experimental + +#include "BackgroundMesh.hh" + +#endif // BACKGROUND_MESH_H diff --git a/extensions/BackgroundMesh.hh b/extensions/BackgroundMesh.hh new file mode 100644 index 0000000000000000000000000000000000000000..d77c6574d160147b2ae97a56bc68ad6c4f68089a --- /dev/null +++ b/extensions/BackgroundMesh.hh @@ -0,0 +1,133 @@ +#include "Tools.h" // tools::Regression + +namespace experimental { + + /** + * strategies: + * 0 .. get nearest point to x and eval DOFVector at this DOF-index + * 1 .. get n nearest points, calc weighted sum of data at these points + * 2 .. get n nearest points, calc regression plane and eval at x + * 3 .. get n nearest points, calc weighted regression plane and eval at x + **/ + template<typename T> + T Box::evalAtPoint(DOFVector<T>& vec, PointType& x, int strategy, int nrOfPoints) + { + T value; + switch (strategy) { + case 0: + value = evalAtPoint_simple(vec, x); + break; + case 1: + value = evalAtPoint_weighted_sum(vec, x, nrOfPoints); + break; + case 2: + value = evalAtPoint_regression(vec, x, nrOfPoints); + break; + case 3: + value = evalAtPoint_weighted_regression(vec, x, nrOfPoints); + break; + default: + ERROR("ERROR: unknown strategy [%d]!\n",strategy); + break; + } + return value; + } + + + template<typename T> + T Box::evalAtPoint_simple(DOFVector<T>& vec, PointType& x) + { + DataType dof; + T value; nullify(value); + if (getNearestData(x, dof)) + value = vec[dof.first]; + return value; + } + + + template<typename T> + T Box::evalAtPoint_weighted_sum(DOFVector<T>& vec, PointType& x, int nrOfPoints) + { + T value; nullify(value); + + std::vector<DataType> dofs; + int nPoints = (nrOfPoints > 0 ? nrOfPoints : vec.getFeSpace()->getBasisFcts()->getNumber()+1); + + bool inside = getNearestData(x, dofs, nPoints); + if (!inside) + return value; + + // gewichtete Summe der einzelnen Funktionswerte in der Nähe von x + std::vector<double> weights; + for (size_t i = 0; i < dofs.size(); i++) { + double dist = distance(x, dofs[i].second, DOW); + weights.push_back(1.0/std::max(1.e-8, dist)); + } + + double weight = 0.0; + for (size_t i = 0; i < dofs.size(); i++) { + value += vec[dofs[i].first] * weights[i]; + weight += weights[i]; + } + value *= 1.0/weight; + + return value; + } + + + template<typename T> + T Box::evalAtPoint_regression(DOFVector<T>& vec, PointType& x, int nrOfPoints) + { + T value; nullify(value); + + std::vector<DataType> dofs; + int nPoints = (nrOfPoints > 0 ? nrOfPoints : vec.getFeSpace()->getBasisFcts()->getNumber()+1); + + bool inside = getNearestData(x, dofs, nPoints); + if (!inside) + return value; + + std::vector<WorldVector<double> > points; + std::vector<double> values; + for (size_t i = 0; i < dofs.size(); i++) { + points.push_back(dofs[i].second); + values.push_back(vec[dofs[i].first]); + } + + tools::Regression reg(DOW); + reg.apply(points, values); + value = reg.value(x); + return value; + } + + + template<typename T> + T Box::evalAtPoint_weighted_regression(DOFVector<T>& vec, PointType& x, int nrOfPoints) + { + T value; nullify(value); + + std::vector<DataType> dofs; + int nPoints = (nrOfPoints > 0 ? nrOfPoints : vec.getFeSpace()->getBasisFcts()->getNumber()+1); + + bool inside = getNearestData(x, dofs, nPoints); + if (!inside) + return value; + + std::vector<WorldVector<double> > points; + std::vector<double> values,weights; + for (size_t i = 0; i < dofs.size(); i++) { + points.push_back(dofs[i].second); + values.push_back(vec[dofs[i].first]); + + double dist = distance(x, dofs[i].second, DOW); + weights.push_back(1.0/std::max(1.e-8, dist)); + } + + tools::Regression reg(DOW); + reg.apply(points, values, weights); + value = reg.value(x); + + return value; + } + +} // end namespace experimental diff --git a/extensions/BackgroundMesh2.h b/extensions/BackgroundMesh2.h new file mode 100644 index 0000000000000000000000000000000000000000..c6b0b8f35e310479454219721cb21ae022bbb47f --- /dev/null +++ b/extensions/BackgroundMesh2.h @@ -0,0 +1,345 @@ +/** \file BackgroundMesh2.h */ + +#ifndef BACKGROUND_MESH2_H +#define BACKGROUND_MESH2_H + +#include "AMDiS.h" +#include "Tools.h" + +#define USE_EXPERIMENTAL + +namespace experimental { + +typedef WorldVector<double> PointType_; +typedef boost::tuple<const MacroElement*, int, unsigned long> ElInfoDataType; // data to recover elInfo +typedef std::pair<ElInfoDataType, PointType_> DataType_; + +template<typename PointType, typename DataType> +struct ElementBox { + + ElementBox(int DOW_, std::vector<int> N_) + : DOW(DOW_), N(N_), boxFilled(false) + { + min_corner.set(-1.0); + max_corner.set(1.0); + init(); + } + + ElementBox(int DOW_, PointType min_corner_, PointType max_corner_, std::vector<int> N_) + : DOW(DOW_), + min_corner(min_corner_), + max_corner(max_corner_), + N(N_), boxFilled(false) + { + init(); + } + + + void fillBox(const FiniteElemSpace* feSpace); + + void clearBox() + { + boxData.clear(); + } + + + int getMaxBoxSize() + { + size_t maxSize = 0; + for (size_t i = 0; i < boxData.size(); i++) { + maxSize = std::max(maxSize, boxData[i].size()); + } + return maxSize; + } + + + bool inBox(PointType& x) + { + for (size_t i = 0; i < DOW; i++) + if (min_corner[i] > x[i] || max_corner[i] < x[i]) + return false; + return true; + } + + /** + * + * Ny=2 + * ^---------------- + * | 4 | 5 | 6 | 7 | + * ----+---+---+---- + * | 0 | 1 | 2 | 3 | + * -----------------> Nx=4 + **/ + + int getBox(PointType& x) + { + std::vector<int> idx(DOW); + for (size_t i = 0; i < DOW; i++) + idx[i] = static_cast<int>(floor((x[i]-min_corner[i])*N[i]/(max_corner[i]-min_corner[i]))); + return idx2nr(idx); + } + + + bool getNearestElInfo(PointType &x, ElInfo*& minElInfo); + + + bool getNearestData(PointType& x, DataType& data) + { + if (!inBox(x)) + return false; + + int nr = getBox(x); + if (boxData[nr].size() == 0) { + std::vector<DataType> datas; + getNearestData(x, datas, 1); + data = datas[0]; + return true; + } + std::vector<double> distances; + typename std::vector<DataType>::iterator dataIter; + for (dataIter = boxData[nr].begin(); dataIter != boxData[nr].end(); dataIter++) { + distances.push_back(norm(x - (*dataIter).second)); + } + double minDist = 1.e15; + size_t minIdx = 0; + vector_operations::getMin(distances, minDist, minIdx); + data = boxData[nr][minIdx]; + return true; + } + + bool getNearestData(PointType& x, std::vector<DataType>& data, int nData) + { + if (!inBox(x)) + return false; + + std::set<int> nrs; nrs.insert(getBox(x)); + double boxBoundaryDist = getBoxBoundaryDist(*(nrs.begin()), x); + std::vector<int> visited; + std::vector<int>::iterator visitedIter; + std::set<int>::iterator nrIter; + int level = 0; + for (int level = 0; data.size() < nData && nrs.size() > 0; level++) { + for (nrIter = nrs.begin(); nrIter != nrs.end(); nrIter++) { + data.insert(data.end(), boxData[*nrIter].begin(), boxData[*nrIter].end()); + } + visited.insert(visited.end(), nrs.begin(), nrs.end()); + + std::vector<double> distances; + if (data.size() > 0) { + // 1.) bestimme Abstand zu x + for (size_t i = 0; i < data.size(); i++) { + distances.push_back(norm(x - data[i].second)); + } + // 2.) sortiere Paare aus dist und data + compare0<double, DataType> comp; + vector_operations::sort(distances, data, comp); + } + + // 3.) wenn noch nicht genügend Punkte, dann umgebende Boxen mit durchsuchen + if (data.size() < nData + || (level == 0 && distances[std::min(nData,static_cast<int>(distances.size()))-1] > boxBoundaryDist)) + { + std::set<int> surrounding_nrs; + getSurroundingBoxes(nrs, surrounding_nrs); + swap (nrs, surrounding_nrs); + } + + for (visitedIter = visited.begin(); visitedIter != visited.end(); visitedIter++) + nrs.erase(*visitedIter); + } + data.resize(nData); + return true; + } + + /** + * strategies: + * 0 .. get nearest point to x and eval DOFVector at this DOF-index + * 1 .. get n nearest points, calc weighted sum of data at these points + * 2 .. get n nearest points, calc regression plane and eval at x + * 3 .. get n nearest points, calc weighted regression plane and eval at x + **/ + template<typename T> + T evalAtPoint(DOFVector<T>& vec, PointType& x, int strategy = 0, int nrOfPoints = -1) + { + T value; + switch (strategy) { + case 0: + value = evalAtPoint_simple(vec, x); + break; + default: + ERROR("ERROR: unknown strategy [%d]!\n",strategy); + break; + } + return value; + } + + + static ElementBox<PointType, DataType>* provideBackgroundMesh(const FiniteElemSpace* feSpace) + { + if (boxMap.find(feSpace) != boxMap.end()) { + if (boxMap[feSpace].first != feSpace->getMesh()->getChangeIndex()) { + boxMap[feSpace].second->clearBox(); + boxMap[feSpace].second->init(); + boxMap[feSpace].second->fillBox(feSpace); + boxMap[feSpace].first = feSpace->getMesh()->getChangeIndex(); + std::cout<<"max box size = "<<boxMap[feSpace].second->getMaxBoxSize()<<"\n"; + } + } else { + int N_const = 2; + PointType min_corner_; min_corner_.set(-1.0); + PointType max_corner_; max_corner_.set(1.0); + Parameters::get("backgroundMesh->N", N_const); + Parameters::get("backgroundMesh->min_corner", min_corner_); + Parameters::get("backgroundMesh->max_corner", max_corner_); + std::vector<int> N_(Global::getGeo(WORLD), N_const); + ElementBox<PointType, DataType>* box = new ElementBox<PointType, DataType>(Global::getGeo(WORLD), min_corner_, max_corner_, N_); + box->fillBox(feSpace); + + boxMap[feSpace] = std::make_pair(feSpace->getMesh()->getChangeIndex(), box); + std::cout<<"max box size = "<<boxMap[feSpace].second->getMaxBoxSize()<<"\n"; + } + + return boxMap[feSpace].second; + } + + static void delete_all() + { + typename std::map<const FiniteElemSpace*, std::pair<int, ElementBox<PointType, DataType>*> >::iterator boxIter; + for (boxIter = boxMap.begin(); boxIter != boxMap.end(); boxIter++) { + (*boxIter).second.second->clearBox(); + delete (*boxIter).second.second; + } + boxMap.clear(); + } + + void init() + { + int maxNr = 1.0; + for (size_t i = 0; i < DOW; i++) + maxNr *= N[i]; + boxData.resize(maxNr); + + std::cout<<"\n background mesh\n"; + std::cout<<"=================\n"; + std::cout<<"min_corner: "<<min_corner<<"\n"; + std::cout<<"max_corner: "<<max_corner<<"\n"; + std::cout<<"N: "<<N<<"\n\n"; + + PointType tolerance; tolerance.set(2.0*DBL_TOL); + min_corner -= tolerance; + max_corner += tolerance; + } + +protected: + + template<typename T> + T evalAtPoint_simple(DOFVector<T>& vec, PointType& x); + + inline int idx2nr(std::vector<int>& idx) + { + int nr = idx.back(); + std::vector<int>::reverse_iterator iIter, nIter; + for (iIter = idx.rbegin()+1, nIter = N.rbegin()+1; iIter < idx.rend(); iIter++,nIter++) { + nr = *iIter + nr*(*nIter); + } + return nr; + } + + inline void nr2idx(int nr, std::vector<int>& idx) // template specialization see below + { + switch (DOW) { + case 1: + idx.resize(1); + idx[0] = nr % N[0]; + break; + case 2: + idx.resize(2); + idx[1] = nr / N[0]; + idx[0] = nr % N[0]; + break; + case 3: + idx.resize(3); + idx[2] = nr / (N[1]*N[0]); + nr = nr % (N[1]*N[0]); + idx[1] = nr / N[0]; + idx[0] = nr % N[0]; + break; + default: + throw(std::runtime_error("DOW="+boost::lexical_cast<std::string>(DOW)+", nur die Version für DOW=1 verwendet!")); + break; + } + } + + + void getSurroundingBoxes(int nr, std::set<int> &surrounding_nrs) + { + std::vector<int> idx; + nr2idx(nr, idx); // --> idx + + for (size_t i = 0; i < DOW; i++) { + std::vector<int> idx_i = idx; + idx_i[i] = std::min(N[i]-1, idx_i[i]+1); + surrounding_nrs.insert(idx2nr(idx_i)); + idx_i[i] = std::max(0, idx_i[i]-2); + surrounding_nrs.insert(idx2nr(idx_i)); + } + surrounding_nrs.erase(nr); + } + + void getSurroundingBoxes(std::set<int> &nrs, std::set<int> &surrounding_nrs) + { + std::set<int>::iterator nrsIter; + for (nrsIter = nrs.begin(); nrsIter != nrs.end(); nrsIter++) + getSurroundingBoxes(*nrsIter, surrounding_nrs); + + for (nrsIter = nrs.begin(); nrsIter != nrs.end(); nrsIter++) + surrounding_nrs.erase(*nrsIter); + } + + /// berechne die minimale Entfernung der Ränder der Box zu x + double getBoxBoundaryDist(int nr, PointType& x) + { + std::vector<int> idx; + nr2idx(nr, idx); + PointType min_c, max_c; + for (size_t i = 0; i < DOW; i++) { + min_c[i] = min_corner[i] + (max_corner[i]-min_corner[i])*idx[i]/N[i]; + max_c[i] = min_corner[i] + (max_corner[i]-min_corner[i])*(idx[i]+1)/N[i]; + } + double dist = 1.e15; + for (int i = 0; i < DOW; i++) + dist = std::min(dist, std::min(abs(max_c[i]-x[i]), abs(min_c[i]-x[i]))); + return dist; + } + + void addData(PointType x, DataType data) + { + int nr = getBox(x); + if (nr < 0 || nr >= boxData.size()) + throw(std::runtime_error("box-nr out of range: nr = "+boost::lexical_cast<std::string>(nr)+", boxSize = "+boost::lexical_cast<std::string>(boxData.size()))); + boxData[nr].push_back(data); + } + + + static typename std::map<const FiniteElemSpace*, std::pair<int, ElementBox<PointType, DataType>*> > boxMap; + +protected: + + int DOW; + std::vector<int> N; + bool boxFilled; + + PointType min_corner; + PointType max_corner; + + std::vector<std::vector<DataType> > boxData; +}; + +template<typename PointType, typename DataType> +std::map<const FiniteElemSpace*, std::pair<int, ElementBox<PointType, DataType>*> > ElementBox<PointType, DataType>::boxMap; + +} // end namespace tools + +#include "BackgroundMesh2.hh" + +#endif // BACKGROUND_MESH_H diff --git a/extensions/BackgroundMesh2.hh b/extensions/BackgroundMesh2.hh new file mode 100644 index 0000000000000000000000000000000000000000..777d8ca41731549e667f69dc8cc6a7204c1a58d2 --- /dev/null +++ b/extensions/BackgroundMesh2.hh @@ -0,0 +1,71 @@ +#include "ElementFunction.h" + +namespace experimental { + + template<> + void ElementBox<PointType_, std::pair<ElInfoDataType, PointType_> >::fillBox(const FiniteElemSpace* feSpace) + { + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(feSpace->getMesh(), -1, Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS); + + int dim = feSpace->getMesh()->getDim(); + while (elInfo) { + ElInfo* macroElInfo = feSpace->getMesh()->createNewElInfo(); + macroElInfo->fillMacroInfo(elInfo->getMacroElement()); + stack.fillRefinementPath(*elInfo, *macroElInfo); + + ElInfoDataType elInfoData = boost::tuples::make_tuple(elInfo->getMacroElement(), elInfo->getRefinementPathLength(), elInfo->getRefinementPath()); + + WorldVector<double> centroid = elInfo->getCoord(0); + for (int i = 1; i < dim+1; i++) + centroid += elInfo->getCoord(i); + centroid *= 1.0/(dim+1.0); + + addData(centroid, std::make_pair(elInfoData, centroid)); + + elInfo = stack.traverseNext(elInfo); + } + boxFilled = true; + } + + + template<> + bool ElementBox<PointType_, DataType_>::getNearestElInfo(PointType_ &x, ElInfo*& minElInfo) + { + DataType_ data; + if (getNearestData(x, data)) { + minElInfo->fillElInfo(data.first.get<0>(), data.first.get<1>(), data.first.get<2>()); + return true; + } else + return false; + } + + + template<typename PointType, typename DataType> + template<typename T> + T ElementBox<PointType,DataType>::evalAtPoint_simple(DOFVector<T>& vec, PointType& x) + { + ElInfo* elInfo = vec.getFeSpace()->getMesh()->createNewElInfo(); + elInfo->setFillFlag(Mesh::FILL_COORDS); + T value; nullify(value); + if (getNearestElInfo(x, elInfo)) { + std::cout<<"elInfo = "<<elInfo->getElement()->getIndex()<<"\n"; + int dim = vec.getFeSpace()->getMesh()->getDim(); + DimVec<double> lambda(dim, NO_INIT); + for (int i = 0; i < dim+1; i++) + lambda[i] = 1.0/std::max(1.e-8, norm(x - elInfo->getCoord(i))); + // normalize barycentric coords + double sum = 0.0; + for (int i = 0; i < dim+1; i++) + sum += lambda[i]; + for (int i = 0; i < dim+1; i++) + lambda[i] *= 1.0/sum; + + ElementFunctionDOFVec<T> elFct(&vec); + elFct.setElInfo(elInfo); + value = elFct(lambda); + } + return value; + } + +} // end namespace experimental diff --git a/extensions/BoundaryFunctions.h b/extensions/BoundaryFunctions.h new file mode 100644 index 0000000000000000000000000000000000000000..b7d643759ed2eb347a8c266e4d63ca9243d3473c --- /dev/null +++ b/extensions/BoundaryFunctions.h @@ -0,0 +1,247 @@ +/** \file BoundaryFunctions.h */ + +#ifndef BOUNDARY_FUNCTIONS_H +#define BOUNDARY_FUNCTIONS_H + +#include "AMDiS.h" +#include <time.h> + +using namespace std; +using namespace AMDiS; + + +// parabolic inflow +class ParabolicInflow: public AbstractFunction<double, WorldVector<double> > +{ +public: + ParabolicInflow() : AbstractFunction<double, WorldVector<double> >(2), dim(1.0),c(1.0), dir(1) {}; + ParabolicInflow(double dim_, double c_, int dir_= 0) : AbstractFunction<double, WorldVector<double> >(2), dim(dim_),c(c_),dir(dir_) {}; + double operator()(const WorldVector<double>& x) const { + return c*std::max(0.0, 1.0-sqr(x[1-dir])/sqr(dim)); + }; +protected: + double dim,c; + int dir; +}; + +// parabolic inflow +class ParabolicInflowPressure: public AbstractFunction<double, WorldVector<double> > +{ +public: + ParabolicInflowPressure() : AbstractFunction<double, WorldVector<double> >(2), dim(1.0),c(1.0), dir(1), viscosity(1.0) {}; + ParabolicInflowPressure(double dim_, double c_, int dir_= 0, double viscosity_= 1.0) : AbstractFunction<double, WorldVector<double> >(2), dim(dim_),c(c_),dir(dir_),viscosity(viscosity_) {}; + double operator()(const WorldVector<double>& x) const { + return -2.0*c*viscosity*x[dir]/sqr(dim); + }; +protected: + double dim,c,viscosity; + int dir; +}; + +class ParabolicInflow_robin: public AbstractFunction<double, WorldVector<double> > +{ +public: + ParabolicInflow_robin() : AbstractFunction<double, WorldVector<double> >(1), y(1.0),c(1.0) {}; + ParabolicInflow_robin(double y_, double c_) : AbstractFunction<double, WorldVector<double> >(1), y(y_),c(c_) {}; + double operator()(const WorldVector<double>& x) const { + double result = c*(1.0-sqr(x[1])/sqr(y)); + double n = (x[0]<0.0?-1.0:1.0); + return -1.0*result*n; + }; +protected: + double y,c; +}; + +// parabolic inflow 2 +class BoundaryFct1: public AbstractFunction<double, WorldVector<double> > +{ +public: + BoundaryFct1() : AbstractFunction<double, WorldVector<double> >(1), y(0.205), c(6.0) {}; + BoundaryFct1(double y_, double c_) : AbstractFunction<double, WorldVector<double> >(1), y(y_),c(c_) {}; + double operator()(const WorldVector<double>& x) const { + return 1.0/sqr(2.0*y)*c*(y+x[1])*(y-x[1]); + }; +protected: + double y,c; +}; + +class BoundaryFct1_robin: public AbstractFunction<double, WorldVector<double> > +{ +public: + BoundaryFct1_robin() : AbstractFunction<double, WorldVector<double> >(1), y(0.205), c(6.0) {}; + BoundaryFct1_robin(double y_, double c_) : AbstractFunction<double, WorldVector<double> >(1), y(y_),c(c_) {}; + double operator()(const WorldVector<double>& x) const { + double result = 1.0/sqr(2.0*y)*c*(y+x[1])*(y-x[1]); + double n = (x[0]<0.0?-1.0:1.0); + return -1.0*result*n; + }; +protected: + double y,c; +}; + +// time-dependent inflow +class BoundaryFct2: public AbstractFunction<double, WorldVector<double> >, public TimedObject +{ +public: + BoundaryFct2() : AbstractFunction<double, WorldVector<double> >(1), y(0.205), c(6.0) {}; + BoundaryFct2(double y_, double c_) : AbstractFunction<double, WorldVector<double> >(1), y(y_),c(c_) {}; + double operator()(const WorldVector<double>& x) const { + return 1.0/sqr(2.0*y) * sin(M_PI*(*timePtr)/8.0)*c*(y+x[1])*(y-x[1]); + }; +protected: + double y,c; +}; + +class BoundaryFct2_robin: public AbstractFunction<double, WorldVector<double> >, public TimedObject +{ +public: + BoundaryFct2_robin() : AbstractFunction<double, WorldVector<double> >(1), y(0.205), c(6.0) {}; + BoundaryFct2_robin(double y_, double c_) : AbstractFunction<double, WorldVector<double> >(1), y(y_),c(c_) {}; + double operator()(const WorldVector<double>& x) const { + double result = 1.0/sqr(2.0*y) * sin(M_PI*(*timePtr)/8.0)*c*(y+x[1])*(y-x[1]); + double n = (x[0]<0.0?-1.0:1.0); + return -1.0*result*n; + }; +protected: + double y,c; +}; + +// Stokes flow (analytic definition) +class StokesFlow : public AbstractFunction<WorldVector<double>, WorldVector<double> > +{ + public: + StokesFlow(double peclet_) : AbstractFunction<WorldVector<double>, WorldVector<double> >(6), peclet(peclet_) { + // parameters for pfc + double R=0.5, density=-0.3, r=0.1, D=1.0; + Initfile::get("user parameter->colloidal radius",R, 1); + Initfile::get("pfc-parameter->density",density, 1); + Initfile::get("pfc-parameter->r",r, 1); + radius = R/(1.0-R) * 2.0*M_PI/sqrt(3.0); + D = radius + 2.0*M_PI/sqrt(3.0); + + center.set(0.0); + Initfile::get("user parameter->colloids position[0]",center, 1); + + c.set(0.0); + c[0] = peclet/D*abs(r/density); + } + WorldVector<double> operator()(const WorldVector<double> &x) const { + WorldVector<double> xTrans = x-center; + WorldVector<double> result; + + if(norm(xTrans)<radius) + result.set(0.0); + else { + result = c-(3.0*radius/(4.0*norm(xTrans)))*(1.0+sqr(radius)/(3.0*sqr(norm(xTrans))))*c; + result+= 3*radius/(4.0*norm(xTrans)*sqr(norm(xTrans)))*(xTrans*c)*(sqr(radius)/sqr(norm(xTrans))-1.0)*xTrans; + } + + return result; + } + protected: + double peclet; + double radius; + WorldVector<double> center,c; +}; +class StokesFlow_component : public AbstractFunction<double, WorldVector<double> > +{ + public: + StokesFlow_component(double peclet_, int comp_) : AbstractFunction<double, WorldVector<double> >(6), peclet(peclet_),comp(comp_) { + // parameters for pfc + double R=0.5, density=-0.3, r=0.1, D=1.0; + Initfile::get("user parameter->colloidal radius",R, 1); + Initfile::get("pfc-parameter->density",density, 1); + Initfile::get("pfc-parameter->r",r, 1); + radius = R/(1.0-R) * 2.0*M_PI/sqrt(3.0); + D = radius + 2.0*M_PI/sqrt(3.0); + + center.set(0.0); + Initfile::get("user parameter->colloids position[0]",center, 1); + + c.set(0.0); + c[0] = peclet/D*abs(r/density); + } + double operator()(const WorldVector<double> &x) const { + WorldVector<double> xTrans = x-center; + WorldVector<double> result; + + if(norm(xTrans)<radius) + result.set(0.0); + else { + result = c-(3.0*radius/(4.0*norm(xTrans)))*(1.0+sqr(radius)/(3.0*sqr(norm(xTrans))))*c; + result+= 3*radius/(4.0*norm(xTrans)*sqr(norm(xTrans)))*(xTrans*c)*(sqr(radius)/sqr(norm(xTrans))-1.0)*xTrans; + } + + return result[comp]; + } + protected: + double peclet; + int comp; + double radius; + WorldVector<double> center,c; +}; +class StokesFlow_robin : public AbstractFunction<double, WorldVector<double> > +{ + public: + StokesFlow_robin(double y_, double peclet_) : AbstractFunction<double, WorldVector<double> >(6), y(y_), peclet(peclet_) { + // parameters for pfc + double R=0.5, density=-0.3, r=0.1, D=1.0; + Initfile::get("user parameter->colloidal radius",R, 1); + Initfile::get("pfc-parameter->density",density, 1); + Initfile::get("pfc-parameter->r",r, 1); + radius = R/(1.0-R) * 2.0*M_PI/sqrt(3.0); + D = radius + 2.0*M_PI/sqrt(3.0); + + center.set(0.0); + Initfile::get("user parameter->colloids position[0]",center, 1); + + c.set(0.0); + c[0] = peclet/D*abs(r/density); + } + double operator()(const WorldVector<double> &x) const { + WorldVector<double> xTrans = x-center; + WorldVector<double> result; + + if(norm(xTrans)<radius) + result.set(0.0); + else { + result = c-(3.0*radius/(4.0*norm(xTrans)))*(1.0+sqr(radius)/(3.0*sqr(norm(xTrans))))*c; + result+= 3*radius/(4.0*norm(xTrans)*sqr(norm(xTrans)))*(xTrans*c)*(sqr(radius)/sqr(norm(xTrans))-1.0)*xTrans; + } + + WorldVector<double> n; + n[0] = (abs(x[1])<y-1.e-8?(x[0]<0.0?-1.0:1.0):0.0); + n[1] = (abs(x[1])>y-1.e-8?(x[1]<0.0?-1.0:1.0):0.0); + return -1.0*n*result; + } + protected: + double y,peclet; + double radius; + WorldVector<double> center,c; +}; + +// constant inflow +class ConstantFct : public AbstractFunction<double, WorldVector<double> > +{ +public: + ConstantFct(double c) + : AbstractFunction<double, WorldVector<double> >(1), constant(c) {}; + double operator()(const WorldVector<double>& x) const { return constant; } + +protected: + double constant; +}; + +// constant inflow +class ConstantTimeFct : public AbstractFunction<double, WorldVector<double> >, public TimedObject +{ +public: + ConstantTimeFct(double c, double endTime_) + : AbstractFunction<double, WorldVector<double> >(1), constant(c), endTime(endTime_) {}; + double operator()(const WorldVector<double>& x) const { return constant*max(0.0, std::min(1.0, (endTime-(*timePtr))/endTime)); } + +protected: + double constant; + double endTime; +}; +#endif // BOUNDARY_FUNCTIONS_H diff --git a/extensions/ExtendedProblemStat.h b/extensions/ExtendedProblemStat.h new file mode 100644 index 0000000000000000000000000000000000000000..adbbc4c4563678a1a1680c4455e766bdb591b8e9 --- /dev/null +++ b/extensions/ExtendedProblemStat.h @@ -0,0 +1,473 @@ +/** \file ExtendedProblemStat.h */ + +#ifndef EXTENDED_PROBLEM_STAT_H +#define EXTENDED_PROBLEM_STAT_H + +#include "AMDiS.h" +#include "SingularDirichletBC.h" +#if defined NONLIN_PROBLEM + #include "nonlin/ProblemNonLin.h" +#endif + +#ifdef HAVE_PARALLEL_DOMAIN_AMDIS + #include "parallel/PetscProblemStat.h" +#endif + +using namespace AMDiS; + +const Flag INIT_EXACT_SOLUTION = 0X2000L; +const Flag UPDATE_PERIODIC_BC = 0X4000L; +const Flag UPDATE_DIRICHLET_BC = 0X8000L; + +#if defined NONLIN_PROBLEM +typedef ProblemNonLin ProblemStat_; +#else +typedef ProblemStat ProblemStat_; +#endif +class ExtendedProblemStat : public ProblemStat_ +{ +public: + + ExtendedProblemStat(std::string nameStr, ProblemIterationInterface *problemIteration = NULL) + : + #if defined NONLIN_PROBLEM + ProblemStat_(nameStr) + #else + ProblemStat_(nameStr, problemIteration) + #endif + , oldMeshChangeIdx(0) + { + exactSolutions.resize(nComponents); + for (int i = 0; i < nComponents; ++i) + exactSolutions[i] = NULL; + +#ifdef HAVE_PARALLEL_DOMAIN_AMDIS + ksp_type = "bcgs"; + pc_type = "bjacobi"; + pc_factor_mat_solver_package = "mumps"; + ksp_rtol = 0.0; + ksp_abstol = 1.e-8; + ksp_maxits = 500; + + Parameters::get(nameStr + "->petsc->ksp_type",ksp_type); + Parameters::get(nameStr + "->petsc->pc_type",pc_type); + Parameters::get(nameStr + "->petsc->pc_factor_mat_solver_package",pc_factor_mat_solver_package); + Parameters::get(nameStr + "->petsc->rtol",ksp_rtol); + Parameters::get(nameStr + "->petsc->abstol",ksp_abstol); + Parameters::get(nameStr + "->petsc->maxits",ksp_maxits); +#endif + } + + void initialize(Flag initFlag, + ProblemStatSeq *adoptProblem = NULL, + Flag adoptFlag = INIT_NOTHING) + { + ProblemStat_::initialize(initFlag, adoptProblem, adoptFlag); + +// if (initFlag.isSet(INIT_EXACT_SOLUTION)) { + for (int i = 0; i < nComponents; ++i) + exactSolutions[i] = new DOFVector< double >(getFeSpace(i), "exact_solution"); +// } + } + + inline DOFVector<double>* getRhsVector(int i = 0) + { + return rhs->getDOFVector(i); + } + + /// + void setExactSolution(DOFVector<double> *dof, int component) + { + TEST_EXIT(exactSolutions[component] != NULL) + ("You have to initialize the exactSolutions vector! Set the initFlag INIT_EXACT_SOLUTION for the problem.\n"); + exactSolutions[component]->copy(*dof); + } + + /// + inline DOFVector<double> *getExactSolution(int i = 0) + { + TEST_EXIT(exactSolutions[i] != NULL) + ("You have to initialize the exactSolutions vector! Set the initFlag INIT_EXACT_SOLUTION for the problem.\n"); + return exactSolutions[i]; + } + + void buildAfterCoarsen(AdaptInfo *adaptInfo, Flag flag, + bool asmMatrix, bool asmVector) + { FUNCNAME("ExtendedProblemStat::buildAfterCoarsen()"); + + ProblemStat_::buildAfterCoarsen(adaptInfo, flag, asmMatrix, asmVector); + +#ifndef HAVE_PARALLEL_DOMAIN_AMDIS + // update periodic data + if (oldMeshChangeIdx != getMesh()->getChangeIndex() + || flag.isSet(UPDATE_PERIODIC_BC) + || (PeriodicBcDataList.size() > 0 && manualPeriodicBC.size() == 0)) { + manualPeriodicBC.clear(); + std::vector<PeriodicBcData>::iterator it; + for (it = PeriodicBcDataList.begin(); it != PeriodicBcDataList.end(); it++) + it->addToList(getFeSpace(), manualPeriodicBC); + } + + // update dirichlet data + if (oldMeshChangeIdx != getMesh()->getChangeIndex() + || flag.isSet(UPDATE_DIRICHLET_BC) + || (DirichletBcDataList.size() > 0 && singularDirichletBC.size() == 0)) { + singularDirichletBC.clear(); + std::vector<DirichletBcData>::iterator it; + for (it = DirichletBcDataList.begin(); it != DirichletBcDataList.end(); it++) { + it->addToList(getFeSpace(it->row), singularDirichletBC); + } + } + + // apply periodic boundary conditions + for (size_t k = 0; k < manualPeriodicBC.size(); k++) + applyPeriodicBC(manualPeriodicBC[k], asmMatrix, asmVector); + + // apply dirichlet boundary conditions + for (size_t k = 0; k < singularDirichletBC.size(); k++) + applyDirichletBC(singularDirichletBC[k], asmMatrix, asmVector); + + // update solverMatrix + if (asmMatrix && (singularDirichletBC.size() > 0 || manualPeriodicBC.size() > 0)) { + solverMatrix.setMatrix(*getSystemMatrix()); + } +#endif + } + + void solve(AdaptInfo *adaptInfo, + bool createMatrixData = true, + bool storeMatrixData = false) + { FUNCNAME("ExtendedProblemStat::solve()"); + +#ifdef HAVE_PARALLEL_DOMAIN_AMDIS + TEST_EXIT(meshDistributor)("Should not happen!\n"); + TEST_EXIT(singularDirichletBC.size() == 0) + ("Singular Dirichlet BC not implemented for parallel computing!\n"); + + double wtime = MPI::Wtime(); + + if (createMatrixData) { + petscSolver->setMeshDistributor(meshDistributor); + petscSolver->fillPetscMatrix(systemMatrix); + } + + petscSolver->fillPetscRhs(rhs); + + MSG("set PETSC-Parameters...\n"); + KSPSetType(petscSolver->getSolver(), ksp_type.c_str()); + KSPSetTolerances(petscSolver->getSolver(), ksp_rtol, ksp_abstol, PETSC_DEFAULT, ksp_maxits); + if (ksp_type == "preonly") { + KSPSetInitialGuessNonzero(petscSolver->getSolver(), PETSC_FALSE); + } + PCSetType(petscSolver->getPc(), pc_type.c_str()); + if (pc_type == "lu") { + PCFactorSetMatSolverPackage(petscSolver->getPc(), pc_factor_mat_solver_package.c_str()); + } + + petscSolver->solvePetscMatrix(*solution, adaptInfo); + + if (!storeMatrixData) + petscSolver->destroyMatrixData(); + + INFO(info, 8)("solution of discrete system needed %.5f seconds\n", + MPI::Wtime() - wtime); +#endif + + ProblemStat_::solve(adaptInfo, createMatrixData, storeMatrixData); + + oldMeshChangeIdx = getMesh()->getChangeIndex(); + } + + /// Add arbitrary boundary condition to system + void addBoundaryCondition(BoundaryCondition *bc, int row, int col) + { + FUNCNAME("ProblemStatType::addBoundaryCondition()"); + + boundaryConditionSet = true; + + if (systemMatrix && (*systemMatrix)[row][col]) + (*systemMatrix)[row][col]->getBoundaryManager()->addBoundaryCondition(bc); + if (rhs) + rhs->getDOFVector(row)->getBoundaryManager()->addBoundaryCondition(bc); + } + + /** + * Dirichlet boundary condition at DOF-Index of vertex near to coords 'pos'. + * Value defined by AbstractFunction, that is evaluated at 'pos' + **/ + template<typename ValueContainer> + void addSingularDirichletBC(WorldVector<double> &pos, int row, int col, + ValueContainer &values) + { + DirichletBcDataList.push_back(DirichletBcData(row, col, pos, values)); + } + + /** + * Dirichlet boundary condition at DOF-Index 'idx'. Value defined by double. + **/ + template<typename ValueContainer> + void addSingularDirichletBC(DegreeOfFreedom idx, int row, int col, + ValueContainer &values) + { + DirichletBcDataList.push_back(DirichletBcData(row, col, idx, values)); + } + + /** + * set dirichlet boundary condition on implicitly defined boundary by zero levelset + * of signed distance function. + * An algebraic equation is forced in the region with dist<0 + * + **/ + template<typename ValueContainer> + void addImplicitDirichletBC(DOFVector<double> &signedDist, + int row, int col, + ValueContainer &values) + { + DirichletBcDataList.push_back(DirichletBcData(row, col, &signedDist, values)); + } + + template<typename ValueContainer> + void addImplicitDirichletBC(AbstractFunction<double, WorldVector<double> > &signedDist, + int row, int col, + ValueContainer &values) + { + DirichletBcDataList.push_back(DirichletBcData(row, col, &signedDist, values)); + } + + template<typename ValueContainer> + void addManualDirichletBC(BoundaryType nr, AbstractFunction<bool, WorldVector<double> >* meshIndicator, + int row, int col, + ValueContainer &values) + { + DirichletBcDataList.push_back(DirichletBcData(row, col, nr, meshIndicator, values)); + } + + + template<typename ValueContainer> + void addManualDirichletBC(AbstractFunction<bool, WorldVector<double> >* meshIndicator, + int row, int col, + ValueContainer &values) + { + DirichletBcDataList.push_back(DirichletBcData(row, col, meshIndicator, values)); + } + + + void addManualPeriodicBC(int row, + BoundaryType nr, AbstractFunction<bool, WorldVector<double> >* meshIndicator, + AbstractFunction<WorldVector<double>, WorldVector<double> >* periodicMap) + { + PeriodicBcDataList.push_back(PeriodicBcData(row, nr, meshIndicator, periodicMap)); + } + + void addManualPeriodicBC(int row, + AbstractFunction<bool, WorldVector<double> >* meshIndicator, + AbstractFunction<WorldVector<double>, WorldVector<double> >* periodicMap) + { + PeriodicBcDataList.push_back(PeriodicBcData(row, meshIndicator, periodicMap)); + } + + /// write Systemmatrix to file in matlab-format + void writeMatrix(std::string filename) + { + mtl::io::matrix_market_ostream out(filename); + SolverMatrix<Matrix<DOFMatrix*> > solverMatrix; + solverMatrix.setMatrix(*getSystemMatrix()); + out << solverMatrix.getMatrix(); + out.close(); + } + + /// Returns the name of the problem + inline string getComponentName(int comp = 0) + { + TEST_EXIT(comp < static_cast<int>(componentNames.size()) && comp >= 0) + ("invalid component number\n"); + return componentNames[comp]; + } + +protected: + + // traverse matrix rows and set unity row where dirichlet condition shall be applied. + void applyDirichletBC(size_t row_, size_t col_, DegreeOfFreedom idx, double value, bool asmMatrix = true, bool asmVector = true) + { + using namespace mtl; + typedef DOFMatrix::base_matrix_type Matrix; + + Matrix::size_type idx_= idx; + bool value1set = false; + + if (asmMatrix) { + typedef traits::range_generator<tag::row, Matrix>::type c_type; + typedef traits::range_generator<tag::nz, c_type>::type ic_type; + + for (size_t col = 0; col < getNumComponents(); col++) { + TEST_EXIT(getSystemMatrix(row_, col) != NULL || col != col_) + ("SystemMatrix block (%d,%d) must not be NULL! Insert a Simple_ZOT(0.0) as Workaround.\n",row_,col); + if (getSystemMatrix(row_, col) == NULL) + continue; + + // set Dirichlet-row in matrix + Matrix &m = getSystemMatrix(row_, col)->getBaseMatrix(); + + traits::row<Matrix>::type r(m); + traits::col<Matrix>::type c(m); + traits::value<Matrix>::type v(m); + + c_type cursor(begin<tag::row>(m)+idx_); + for (ic_type icursor(begin<tag::nz>(cursor)), icend(end<tag::nz>(cursor)); icursor != icend; ++icursor) { + value1set = value1set || r(*icursor) == c(*icursor) && col == col_; + v(*icursor, (r(*icursor) == c(*icursor) && col == col_ ? 1.0 : 0.0)); + } + } + + if (!value1set) { + matrix::inserter<Matrix, update_plus<double> > ins(getSystemMatrix(row_, col_)->getBaseMatrix()); + ins[row_][col_] << 1.0; + } + } + if (asmVector) + (*getRhsVector(row_))[idx] = value; // set Dirichlet-Value at rhs-vector + + (*solution->getDOFVector(row_))[idx] = value; // set Dirichlet-value for solution component + } + + void applyDirichletBC(SingularDirichletBC &sbc, bool asmMatrix = true, bool asmVector = true) + { + applyDirichletBC(sbc.row, sbc.col, sbc.idx, sbc.value, asmMatrix, asmVector); + } + + void applyPeriodicBC(size_t row, std::vector<std::pair<DegreeOfFreedom, DegreeOfFreedom> > &indices, bool asmMatrix = true, bool asmVector = true) + { + using namespace mtl; + typedef DOFMatrix::base_matrix_type Matrix; + + typedef traits::range_generator<tag::row, Matrix>::type c_type; + typedef traits::range_generator<tag::nz, c_type>::type ic_type; + + for (size_t col = 0; col < getNumComponents(); col++) { + TEST_EXIT(getSystemMatrix(row, col) != NULL) + ("SystemMatrix block (%d,%d) must not be NULL! Insert a Simple_ZOT(0.0) as Workaround.\n",row,col); + + Matrix &m = getSystemMatrix(row, col)->getBaseMatrix(); + + traits::row<Matrix>::type r(m); + traits::col<Matrix>::type c(m); + traits::value<Matrix>::type v(m); + + std::vector<std::vector<std::pair<DegreeOfFreedom, double> > > row_values; + row_values.resize(indices.size()); + + // erase the rows for all first indices + for (size_t i = 0; i < indices.size(); i++) { + if (asmMatrix) { + c_type cursor(begin<tag::row>(m)+indices[i].first); + for (ic_type icursor(begin<tag::nz>(cursor)), icend(end<tag::nz>(cursor)); icursor != icend; ++icursor) { + row_values[i].push_back(std::make_pair(c(*icursor), v(*icursor))); + v(*icursor, 0.0); + } + } + if (asmVector) { + (*(getRhsVector(row)))[indices[i].second] += (*(getRhsVector(row)))[indices[i].first]; + (*(getRhsVector(row)))[indices[i].first] = 0.0; + } + } + + // add periodic associations of first and second indices, but only in the diagonal blocks + if (asmMatrix) { + matrix::inserter<Matrix, update_plus<double> > ins(m); + if (row == col) { + for (size_t i = 0; i < indices.size(); i++) { + ins[indices[i].first][indices[i].first] << 1.0; + ins[indices[i].first][indices[i].second] << -1.0; + } + } + for (size_t i = 0; i < indices.size(); i++) { + for (size_t j = 0; j < row_values[i].size(); j++) { + ins[indices[i].second][row_values[i][j].first] << row_values[i][j].second; + } + } + } + } + } + + void applyPeriodicBC(ManualPeriodicBC &pbc, bool asmMatrix = true, bool asmVector = true) + { + applyPeriodicBC(pbc.row, pbc.indices, asmMatrix, asmVector); + } + + void applyAlgebraicEquation(size_t row, + std::vector<DegreeOfFreedom> &row_idx, + std::vector<std::vector<double> > &coefficients, + std::vector<double> &rhs) + { + using namespace mtl; + typedef DOFMatrix::base_matrix_type Matrix; + + typedef traits::range_generator<tag::row, Matrix>::type c_type; + typedef traits::range_generator<tag::nz, c_type>::type ic_type; + + TEST_EXIT(row_idx.size() == coefficients.size() && row_idx.size() == rhs.size() && rhs.size()>0) + ("rhs_idx, coefficients and rhs must have the same size and size >! 0\n"); + TEST_EXIT(coefficients[0].size() == getNumComponents()) + ("You have to give coefficients for all variables\n"); + + for (size_t col = 0; col < getNumComponents(); col++) { + TEST_EXIT(getSystemMatrix(row, col) != NULL) + ("SystemMatrix block (%d,%d) must not be NULL! Insert a Simple_ZOT(0.0) as Workaround.\n",row,col); + + Matrix &m = getSystemMatrix(row, col)->getBaseMatrix(); + + traits::row<Matrix>::type r(m); + traits::col<Matrix>::type c(m); + traits::value<Matrix>::type v(m); + + // erase the rows for all row-indices and set rhs values + for (size_t i = 0; i < coefficients.size(); i++) { + c_type cursor(begin<tag::row>(m)+row_idx[i]); + for (ic_type icursor(begin<tag::nz>(cursor)), icend(end<tag::nz>(cursor)); icursor != icend; ++icursor) { + v(*icursor, (r(*icursor) == c(*icursor) ? coefficients[i][col] : 0.0)); + } + (*(getRhsVector(row)))[row_idx[i]] = rhs[i]; + } + } + } + + void applyAlgebraicEquation(size_t row, + DegreeOfFreedom &row_idx0, + std::vector<double> &coefficients0, + double rhs0) + { + std::vector<DegreeOfFreedom> row_idx; row_idx.push_back(row_idx0); + std::vector<std::vector<double> > coefficients; coefficients.push_back(coefficients0); + std::vector<double> rhs; rhs.push_back(rhs0); + + applyAlgebraicEquation(row, row_idx, coefficients, rhs); + } + +private: + + int oldMeshChangeIdx; + std::vector<DOFVector<double>*> exactSolutions; + + // data for periodic boundary conditions + std::vector<ManualPeriodicBC> manualPeriodicBC; + std::vector<PeriodicBcData> PeriodicBcDataList; + + // data for dirichlet boundary conditions + std::vector<SingularDirichletBC> singularDirichletBC; + std::vector<DirichletBcData> DirichletBcDataList; + + std::map<const FiniteElemSpace*, bool> feSpaceVisited; + +#ifdef HAVE_PARALLEL_DOMAIN_AMDIS + std::string ksp_type; + std::string pc_type; + std::string pc_factor_mat_solver_package; + + double ksp_rtol; + double ksp_abstol; + + int ksp_maxits; +#endif + +}; +#endif // EXTENDED_PROBLEM_STAT_H diff --git a/extensions/GeometryTools.cc b/extensions/GeometryTools.cc new file mode 100644 index 0000000000000000000000000000000000000000..f59ea8d37299506c992b909a0c2630ae0ccc1ade --- /dev/null +++ b/extensions/GeometryTools.cc @@ -0,0 +1,1503 @@ +#include "GeometryTools.h" + +#define EPSILON FLT_EPSILON + +namespace meshconv { + +// ############### +// ## General ## +// ############### + +//----------------------------------------< coordinate_extrema_triangle > +//returns in 'small_coord' the smallest coordinate of 'sm' in the given dimension and in 'big_coord' the +//biggest coordinate in the given dimension. Note: 'sm' has to be a triangle in a 2d or 3d world. +// void coordinate_extrema_triangle(mesh &m, element &sm, long dimension, double &small_coord, +// double &big_coord){ +// if(m.vertices[sm.v[0]][dimension] <= m.vertices[sm.v[1]][dimension]){ +// if(m.vertices[sm.v[0]][dimension] <= m.vertices[sm.v[2]][dimension]){ +// small_coord = m.vertices[sm.v[0]][dimension]; +// if(m.vertices[sm.v[1]][dimension] >= m.vertices[sm.v[2]][dimension]) +// big_coord = m.vertices[sm.v[1]][dimension]; +// else +// big_coord = m.vertices[sm.v[2]][dimension]; +// } +// else{ +// small_coord = m.vertices[sm.v[2]][dimension]; +// big_coord = m.vertices[sm.v[1]][dimension]; +// } +// } +// else{ +// if(m.vertices[sm.v[1]][dimension] <= m.vertices[sm.v[2]][dimension]){ +// small_coord = m.vertices[sm.v[1]][dimension]; +// if(m.vertices[sm.v[0]][dimension] >= m.vertices[sm.v[2]][dimension]) +// big_coord = m.vertices[sm.v[0]][dimension]; +// else +// big_coord = m.vertices[sm.v[2]][dimension]; +// } +// else{ +// small_coord = m.vertices[sm.v[2]][dimension]; +// big_coord = m.vertices[sm.v[0]][dimension]; +// } +// } +// } + +//----------------------------------------< solve_determinant4 > +double solve_determinant4(double x11, double x12, double x13, double x14, + double x21, double x22, double x23, double x24, + double x31, double x32, double x33, double x34, + double x41, double x42, double x43, double x44){ + return x11*(x22*x33*x44 + x23*x34*x42 + x24*x32*x43 - x24*x33*x42 - x23*x32*x44 - x22*x34*x43) + -x12*(x21*x33*x44 + x23*x34*x41 + x24*x31*x43 - x24*x33*x41 - x23*x31*x44 - x21*x34*x43) + +x13*(x21*x32*x44 + x22*x34*x41 + x24*x31*x42 - x24*x32*x41 - x22*x31*x44 - x21*x34*x42) + -x14*(x21*x32*x43 + x22*x33*x41 + x23*x31*x42 - x23*x32*x41 - x22*x31*x43 - x21*x33*x42); +} + +// ################# +// ## 2D Worlds ## +// ################# + +//----------------------------------------< edge_length_2d > +double edge_length_2d(double lin0[], double lin1[]){ + long i; + double p[2]; + + for(i=0; i<2; ++i) p[i] = lin0[i] - lin1[i]; + return sqrt(p[0] * p[0] + p[1] * p[1]); +} + +//----------------------------------------< boundingbox_triangle_2d > +void boundingbox_triangle_2d(double tri0[], double tri1[], double tri2[], + double min_corner[], double max_corner[]){ + min_corner[0] = std::min(std::min(tri0[0],tri1[0]),tri2[0]); + min_corner[1] = std::min(std::min(tri0[1],tri1[1]),tri2[1]); + max_corner[0] = std::max(std::max(tri0[0],tri1[0]),tri2[0]); + max_corner[1] = std::max(std::max(tri0[1],tri1[1]),tri2[1]); +} + +//----------------------------------------< centroid_of_box_2d > +void centroid_of_box_2d(double min_corner[], double max_corner[], double c[]){ + c[0] = 0.5*(max_corner[0]+min_corner[0]); + c[1] = 0.5*(max_corner[1]+min_corner[1]); +} + +//----------------------------------------< centroid_of_triangle_2d > +void centroid_of_triangle_2d(double tri0[], double tri1[], double tri2[], double c[]){ + c[0] = (tri0[0]+tri1[0],tri2[0])/3.0; + c[1] = (tri0[1]+tri1[1],tri2[1])/3.0; +} + +//----------------------------------------< point_in_triangle_2d > +bool point_in_triangle_2d(double p[], double a[], double b[], double c[]){ + long i; + double v0[2], v1[2], v2[2]; + double dot00, dot01, dot02, dot11, dot12, invDenom, u, v; + + //compute direction vectors + for(i=0; i<2; i++) v0[i] = c[i] - a[i]; + for(i=0; i<2; i++) v1[i] = b[i] - a[i]; + for(i=0; i<2; i++) v2[i] = p[i] - a[i]; + + //compute dot products + dot00 = v0[0]*v0[0] + v0[1]*v0[1]; //dot(v0, v0) + dot01 = v0[0]*v1[0] + v0[1]*v1[1]; //dot(v0, v1) + dot02 = v0[0]*v2[0] + v0[1]*v2[1]; //dot(v0, v2) + dot11 = v1[0]*v1[0] + v1[1]*v1[1]; //dot(v1, v1) + dot12 = v1[0]*v2[0] + v1[1]*v2[1]; //dot(v1, v2) + + //compute barycentric coordinates + invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01); + u = (dot11 * dot02 - dot01 * dot12) * invDenom; + v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + //check if point is in triangle + return (u >= 0.0) && (v >= 0.0) && (u + v <= 1.0); +} + +//----------------------------------------< point_in_triangle_generous_2d > +bool point_in_triangle_generous_2d(double p[], double a[], double b[], double c[]){ + long i; + double v0[2], v1[2], v2[2]; + double dot00, dot01, dot02, dot11, dot12, invDenom, u, v; + + //compute direction vectors + for(i=0; i<2; i++) v0[i] = c[i] - a[i]; + for(i=0; i<2; i++) v1[i] = b[i] - a[i]; + for(i=0; i<2; i++) v2[i] = p[i] - a[i]; + + //compute dot products + dot00 = v0[0]*v0[0] + v0[1]*v0[1]; //dot(v0, v0) + dot01 = v0[0]*v1[0] + v0[1]*v1[1]; //dot(v0, v1) + dot02 = v0[0]*v2[0] + v0[1]*v2[1]; //dot(v0, v2) + dot11 = v1[0]*v1[0] + v1[1]*v1[1]; //dot(v1, v1) + dot12 = v1[0]*v2[0] + v1[1]*v2[1]; //dot(v1, v2) + + //compute barycentric coordinates + invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01); + u = (dot11 * dot02 - dot01 * dot12) * invDenom; + v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + //check if point is in triangle + return (u >= -EPSILON) && (v >= -EPSILON) && (u + v - 1.0 <= EPSILON); +} + + +//----------------------------------------< point_in_box_2d > +bool point_in_box_2d(double p[], double min_corner[], double max_corner[]){ + + return (p[0] >= min_corner[0]) && (p[0] <= max_corner[0]) && + (p[1] >= min_corner[1]) && (p[1] <= max_corner[1]); +} + +//----------------------------------------< point_in_box_generous_2d > +bool point_in_box_generous_2d(double p[], double min_corner[], double max_corner[]){ + + return (p[0]-min_corner[0] >= -EPSILON) && (p[0]-max_corner[0] <= EPSILON) && + (p[1]-min_corner[1] >= -EPSILON) && (p[1]-max_corner[1] <= EPSILON); +} + +//----------------------------------------< intersection_line_line_2d > +//tests whether the line segment defined by end points 'lin0' and 'lin1' intersects the connection +//between lamp and new_dof. If the line segment is intersected in one of its vertices the index of that +//vertex (0 or 1) is returned in hit_vertex otherwise hit_vertex is set to -1. +bool intersection_line_line_2d(double lin0[], double lin1[], + double lamp[], double new_dof[], long &hit_vertex){ + long i; + double x=-1.0, y=-1.0, tmp; + double p3[2], q3[2]; + hit_vertex = -1; + + for(i=0; i<2; ++i){ + p3[i] = lin1[i] - lin0[i]; + q3[i] = new_dof[i] - lamp[i]; + } + + //partial coincidence of small element and center-connection is a special case, it does not count as an + //intersection + tmp = p3[0]*q3[1] - p3[1]*q3[0]; + if(abs(tmp) > EPSILON){ + + //no partial coincidence; test for intersection + if(abs(q3[0]) < EPSILON){ + if(abs(p3[0]) > EPSILON){ + x = (lamp[0] - lin0[0]) / p3[0]; + y = (lamp[1] - lin0[1] - p3[1]*x) / -q3[1]; + } + } + else if(abs(q3[1]) < EPSILON){ + if(abs(p3[1]) > EPSILON){ + x = (lamp[1] - lin0[1]) / p3[1]; + y = (lamp[0] - lin0[0] - p3[0]*x) / -q3[0]; + } + } + else{ + if(abs(tmp) > EPSILON){ + x = ((lamp[0]-lin0[0])*q3[1] - (lamp[1]-lin0[1])*q3[0]) / tmp; + y = (lamp[0] - lin0[0] - p3[0]*x) / -q3[0]; + } + } + + if(x>-EPSILON && x-1<EPSILON && y>-EPSILON && y-1<-EPSILON){ + if(x<EPSILON) hit_vertex = 0; + else if(x-1>-EPSILON) hit_vertex = 1; + return true; + } + } + + return false; +} + +//----------------------------------------< intersection_line_triangle_2d > +bool intersection_line_triangle_2d(double lin0[], double lin1[], + double tri0[], double tri1[], double tri2[]){ + if(point_in_triangle_generous_2d(lin0, tri0, tri1, tri2)){ + return true; + } + if(point_in_triangle_generous_2d(lin1, tri0, tri1, tri2)){ + return true; + } + + long hit_vertex; + if(intersection_line_line_2d(tri0, tri1, lin0, lin1, hit_vertex)){ + return true; + } + if(intersection_line_line_2d(tri1, tri2, lin0, lin1, hit_vertex)){ + return true; + } + if(intersection_line_line_2d(tri2, tri0, lin0, lin1, hit_vertex)){ + return true; + } + + return false; +} + +//----------------------------------------< intersection_line_box_2d > +bool intersection_line_box_2d(double lin0[], double lin1[], + double min_corner[], double max_corner[]){ + double p0[2]; + double p1[2]; + p0[0] = min_corner[0]; p0[1] = max_corner[1]; + p1[0] = max_corner[0]; p1[1] = min_corner[1]; + + long hit_vertex; + if (intersection_line_line_2d(lin0,lin1,min_corner,p0,hit_vertex)) + return true; + if (intersection_line_line_2d(lin0,lin1,min_corner,p1,hit_vertex)) + return true; + if (intersection_line_line_2d(lin0,lin1,max_corner,p0,hit_vertex)) + return true; + if (intersection_line_line_2d(lin0,lin1,max_corner,p1,hit_vertex)) + return true; + + return false; +} + +//----------------------------------------< intersection_box_box_2d > +bool intersection_box_box_2d(double min_corner0[], double max_corner0[], + double min_corner1[], double max_corner1[]){ + double p[2]; + + if (edge_length_2d(min_corner0,max_corner0) < edge_length_2d(min_corner1,max_corner1)) { + // box0 is smaller than box1 + if (point_in_box_2d(min_corner0, min_corner1, max_corner1)) + return true; + if (point_in_box_2d(max_corner0, min_corner1, max_corner1)) + return true; + + p[0] = min_corner0[0]; p[1] = max_corner0[1]; + if (point_in_box_2d(p, min_corner1, max_corner1)) + return true; + + p[0] = max_corner0[0]; p[1] = min_corner0[1]; + if (point_in_box_2d(p, min_corner1, max_corner1)) + return true; + } else { + // box1 is smaller than box0 + if (point_in_box_2d(min_corner1, min_corner0, max_corner0)) + return true; + if (point_in_box_2d(max_corner1, min_corner0, max_corner0)) + return true; + + p[0] = min_corner1[0]; p[1] = max_corner1[1]; + if (point_in_box_2d(p, min_corner0, max_corner0)) + return true; + + p[0] = max_corner1[0]; p[1] = min_corner1[1]; + if (point_in_box_2d(p, min_corner0, max_corner0)) + return true; + } +} + +//----------------------------------------< intersection_triangle_box_2d > +bool intersection_triangle_box_2d(double tri0[], double tri1[], double tri2[], + double min_corner[], double max_corner[]){ + // vertices of triangle covered by box + if (point_in_box_generous_2d(tri0,min_corner,max_corner)) + return true; + if (point_in_box_generous_2d(tri1,min_corner,max_corner)) + return true; + if (point_in_box_generous_2d(tri2,min_corner,max_corner)) + return true; + + // bounding box of triangle does not intersect the box + double p0[2]; + double p1[2]; + boundingbox_triangle_2d(tri0,tri1,tri2,p0,p1); + if (!intersection_box_box_2d(min_corner,max_corner,p0,p1)) + return false; + + // vertices of box covered by triangle + if (point_in_triangle_generous_2d(min_corner, tri0, tri1, tri2)) + return true; + if (point_in_triangle_generous_2d(max_corner, tri0, tri1, tri2)) + return true; + + p0[0] = min_corner[0]; p0[1] = max_corner[1]; + if (point_in_triangle_generous_2d(p0, tri0, tri1, tri2)) + return true; + + p1[0] = max_corner[0]; p1[1] = min_corner[1]; + if (point_in_triangle_generous_2d(p1, tri0, tri1, tri2)) + return true; + + // edges of triangle intersect box + if (intersection_line_box_2d(tri0,tri1,min_corner,max_corner)) + return true; + if (intersection_line_box_2d(tri1,tri2,min_corner,max_corner)) + return true; + if (intersection_line_box_2d(tri2,tri0,min_corner,max_corner)) + return true; + + return false; +} + +//----------------------------------------< distance_point_line_2d > +//calculates the distance between a given point and the line segment between 'lin0' and 'lin1'. +double distance_point_line_2d(double point[], double lin0[], double lin1[]){ + double gx, gy, fx, fy, dx, dy, t; + //the (complete) line through 'lin0' and 'lin1' is given by 'l = lin0 + t*g' with g as follows: + gx = lin1[0] - lin0[0]; + gy = lin1[1] - lin0[1]; + + //the normal-vector from 'point' to l is 'v = lin0 + t*g - point' for some t which is determined + // by 'v*g = 0' + t = (-gx * (lin0[0]-point[0]) - gy * (lin0[1]-point[1])) / (gx*gx + gy*gy); + + //if the orthogonal projection of 'point' onto l is not on the given line segment then one of the + //vertices 'lin0' or 'lin1' is the nearest point to 'point' + if(t<0){ + //'lin0' is nearest + fx = lin0[0]; + fy = lin0[1]; + } + else if(t>1){ + //'lin1' is nearest + fx = lin1[0]; + fy = lin1[1]; + } + else{ + //orthogonal projection is nearest + fx = lin0[0] + t * gx; + fy = lin0[1] + t * gy; + } + + //calculate distance + dx = point[0] - fx; + dy = point[1] - fy; + return sqrt(dx*dx + dy*dy); +} + +//----------------------------------------< distance_point_line_with_intersection_2d > +//calculates the distance between a given point and the line-segment between 'lin0' and 'lin1'. +//This version also returns the intersection-point of the perpendicular with the given line-segment. +double distance_point_line_with_intersection_2d(double point[], double lin0[], double lin1[], + double intersection[]){ + double gx, gy, dx, dy, t; + //the (complete) line through 'lin0' and 'lin1' is given by 'l = lin0 + t*g' with g as follows: + gx = lin1[0] - lin0[0]; + gy = lin1[1] - lin0[1]; + + //the normal-vector from 'point' to l is 'v = lin0 + t*g - point' for some t which is determined + // by 'v*g = 0' + t = (-gx * (lin0[0]-point[0]) - gy * (lin0[1]-point[1])) / (gx*gx + gy*gy); + + //if the orthogonal projection of 'point' onto l is not on the given line segment then one of the + //vertices 'lin0' or 'lin1' is the nearest point to 'point' + if(t<0){ + //'lin0' is nearest + intersection[0] = lin0[0]; + intersection[1] = lin0[1]; + } + else if(t>1){ + //'lin1' is nearest + intersection[0] = lin1[0]; + intersection[1] = lin1[1]; + } + else{ + //orthogonal projection is nearest + intersection[0] = lin0[0] + t * gx; + intersection[1] = lin0[1] + t * gy; + } + + //calculate distance + dx = point[0] - intersection[0]; + dy = point[1] - intersection[1]; + return sqrt(dx*dx + dy*dy); +} + + +//----------------------------------------< distance_point_box_2d > +double distance_point_box_2d(double point[], double min_corner[], double max_corner[]){ + if (point_in_box_2d(point,min_corner,max_corner)) + return 0.0; + + double p[2]; + double dist = edge_length_2d(point, min_corner); + dist = std::min(dist, edge_length_2d(point, min_corner)); + p[0] = min_corner[0]; p[1] = max_corner[1]; + dist = std::min(dist, edge_length_2d(point, p)); + p[0] = max_corner[0]; p[1] = min_corner[1]; + dist = std::min(dist, edge_length_2d(point, p)); + + return dist; +} + +//----------------------------------------< distance_point_triangle_2d > +double distance_point_triangle_2d(double point[], double tri0[], double tri1[], double tri2[]){ + if (point_in_triangle_2d(point,tri0,tri1,tri2)) + return 0.0; + + double dist = edge_length_2d(point, tri0); + dist = std::min(dist, edge_length_2d(point, tri1)); + dist = std::min(dist, edge_length_2d(point, tri2)); + + return dist; +} + +bool point_in_polygon(double point[], const std::vector<AMDiS::WorldVector<double> > &vertices) { + bool inside = false; + + int i, j; + for (i = 0, j = vertices.size()-1; i < vertices.size(); j = i++) { + if ((((vertices[i][1] <= point[1]) && (point[1] < vertices[j][1])) || + ((vertices[j][1] <= point[1]) && (point[1] < vertices[i][1]))) && + (point[0] < (vertices[j][0] - vertices[i][0]) * (point[1] - vertices[i][1]) / (vertices[j][1] - vertices[i][1]) + vertices[i][0])) + inside = !inside; + } + + return inside; +} + +// ################# +// ## 3D Worlds ## +// ################# + +//----------------------------------------< points_identical_3d > +bool points_identical_3d(double p1[], double p2[]){ + long i; + + for(i=0; i<3; ++i){ + if(abs(p1[i] - p2[i]) > EPSILON) break; + } + if(i == 3){ + return true; + }else{ + return false; + } +} + +//----------------------------------------< normal_vector_3d > +void normal_vector_3d(double tri0[], double tri1[], double tri2[], double normal[]){ + long i; + double p[3], q[3]; + + for(i=0; i<3; ++i) p[i] = tri0[i] - tri1[i]; + for(i=0; i<3; ++i) q[i] = tri0[i] - tri2[i]; + normal[0] = p[1] * q[2] - p[2] * q[1]; + normal[1] = p[2] * q[0] - p[0] * q[2]; + normal[2] = p[0] * q[1] - p[1] * q[0]; +} + +//----------------------------------------< triangle_area_3d > +double triangle_area_3d(double tri0[], double tri1[], double tri2[]){ + long i; + double p[3], q[3], n[3]; + + for(i=0; i<3; ++i) p[i] = tri0[i] - tri1[i]; + for(i=0; i<3; ++i) q[i] = tri0[i] - tri2[i]; + n[0] = p[1] * q[2] - p[2] * q[1]; + n[1] = p[2] * q[0] - p[0] * q[2]; + n[2] = p[0] * q[1] - p[1] * q[0]; + return sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]) / 2; +} + +//----------------------------------------< edge_length_3d > +double edge_length_3d(double lin0[], double lin1[]){ + long i; + double p[3]; + + for(i=0; i<3; ++i) p[i] = lin0[i] - lin1[i]; + return sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]); +} + +//----------------------------------------< triangle_max_edge_length_3d > +double triangle_max_edge_length_3d(double tri0[], double tri1[], double tri2[]){ + long i; + double p[3], max_el, a; + + for(i=0; i<3; ++i) p[i] = tri0[i] - tri1[i]; + a = p[0] * p[0] + p[1] * p[1] + p[2] * p[2]; + max_el = a; + + for(i=0; i<3; ++i) p[i] = tri1[i] - tri2[i]; + a = p[0] * p[0] + p[1] * p[1] + p[2] * p[2]; + if(a > max_el) max_el = a; + + for(i=0; i<3; ++i) p[i] = tri2[i] - tri0[i]; + a = p[0] * p[0] + p[1] * p[1] + p[2] * p[2]; + if(a > max_el) max_el = a; + + return sqrt(max_el); +} + +//----------------------------------------< unit_normal_vector_3d > +void unit_normal_vector_3d(double tri0[], double tri1[], double tri2[], double normal[]){ + long i; + double b; + double p[3], q[3]; + + for(i=0; i<3; ++i) p[i] = tri0[i] - tri1[i]; + for(i=0; i<3; ++i) q[i] = tri0[i] - tri2[i]; + normal[0] = p[1] * q[2] - p[2] * q[1]; + normal[1] = p[2] * q[0] - p[0] * q[2]; + normal[2] = p[0] * q[1] - p[1] * q[0]; + b = sqrt(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]); + for(i=0; i<3; ++i) normal[i] /= b; +} + +//----------------------------------------< degenerate_triangle_3d > +bool degenerate_triangle_3d(double tri0[], double tri1[], double tri2[]){ + long i; + double p[3], q[3], n[3]; + + for(i=0; i<3; ++i) p[i] = tri0[i] - tri1[i]; + for(i=0; i<3; ++i) q[i] = tri0[i] - tri2[i]; + n[0] = p[1] * q[2] - p[2] * q[1]; + n[1] = p[2] * q[0] - p[0] * q[2]; + n[2] = p[0] * q[1] - p[1] * q[0]; + if(abs(n[0])<EPSILON && abs(n[1])<EPSILON && abs(n[2])<EPSILON){ + return true; + }else{ + return false; + } +} + +//----------------------------------------< boundingbox_triangle_3d > +void boundingbox_triangle_3d(double tri0[], double tri1[], double tri2[], + double min_corner[], double max_corner[]){ + min_corner[0] = std::min(std::min(tri0[0],tri1[0]),tri2[0]); + min_corner[1] = std::min(std::min(tri0[1],tri1[1]),tri2[1]); + min_corner[2] = std::min(std::min(tri0[2],tri1[2]),tri2[2]); + max_corner[0] = std::max(std::max(tri0[0],tri1[0]),tri2[0]); + max_corner[1] = std::max(std::max(tri0[1],tri1[1]),tri2[1]); + max_corner[2] = std::max(std::max(tri0[2],tri1[2]),tri2[2]); +} + +//----------------------------------------< centroid_of_box_3d > +void centroid_of_box_3d(double min_corner[], double max_corner[], double c[]){ + c[0] = 0.5*(max_corner[0]+min_corner[0]); + c[1] = 0.5*(max_corner[1]+min_corner[1]); + c[2] = 0.5*(max_corner[2]+min_corner[2]); +} + +//----------------------------------------< centroid_of_triangle_3d > +void centroid_of_triangle_3d(double tri0[], double tri1[], double tri2[], double c[]){ + c[0] = (tri0[0]+tri1[0],tri2[0])/3.0; + c[1] = (tri0[1]+tri1[1],tri2[1])/3.0; + c[2] = (tri0[2]+tri1[2],tri2[2])/3.0; +} + +//----------------------------------------< point_in_box_3d > +bool point_in_box_3d(double p[], double min_corner[], double max_corner[]){ + + return (p[0] >= min_corner[0]) && (p[0] <= max_corner[0]) && + (p[1] >= min_corner[1]) && (p[1] <= max_corner[1]) && + (p[2] >= min_corner[2]) && (p[2] <= max_corner[2]); +} + +//----------------------------------------< point_in_box_generous_3d > +bool point_in_box_generous_3d(double p[], double min_corner[], double max_corner[]){ + + return (p[0]-min_corner[0] >= -EPSILON) && (p[0]-max_corner[0] <= EPSILON) && + (p[1]-min_corner[1] >= -EPSILON) && (p[1]-max_corner[1] <= EPSILON) && + (p[2]-min_corner[2] >= -EPSILON) && (p[2]-max_corner[2] <= EPSILON); +} + +//----------------------------------------< point_in_tetrahedron_3d > +bool point_in_tetrahedron_3d(double p[], double a[], double b[], double c[], double d[]){ + double d0, d1, d2, d3, d4; + + d0 = solve_determinant4(a[0], a[1], a[2], 1.0, b[0], b[1], b[2], 1.0, + c[0], c[1], c[2], 1.0, d[0], d[1], d[2], 1.0); + d1 = solve_determinant4(p[0], p[1], p[2], 1.0, b[0], b[1], b[2], 1.0, + c[0], c[1], c[2], 1.0, d[0], d[1], d[2], 1.0); + d2 = solve_determinant4(a[0], a[1], a[2], 1.0, p[0], p[1], p[2], 1.0, + c[0], c[1], c[2], 1.0, d[0], d[1], d[2], 1.0); + d3 = solve_determinant4(a[0], a[1], a[2], 1.0, b[0], b[1], b[2], 1.0, + p[0], p[1], p[2], 1.0, d[0], d[1], d[2], 1.0); + d4 = solve_determinant4(a[0], a[1], a[2], 1.0, b[0], b[1], b[2], 1.0, + c[0], c[1], c[2], 1.0, p[0], p[1], p[2], 1.0); + //if(d0>=0.0){ + // return (d1>=0.0 && d2>=0.0 && d3>=0.0 && d4>=0.0); + //}else{ + // return (d1<=0.0 && d2<=0.0 && d3<=0.0 && d4<=0.0); + //} + //the following code is highly experimental and should not be trusted! + if(d0>=0.0){ + return (d1>=-EPSILON && d2>=-EPSILON && d3>=-EPSILON && d4>=-EPSILON); + }else{ + return (d1<=EPSILON && d2<=EPSILON && d3<=EPSILON && d4<=EPSILON); + } +} + +//----------------------------------------< intersection_line_line_3d > +bool intersection_line_line_3d(double p1[], double p2[], double p3[], double p4[]){ + double p13[3], p43[3], p21[3]; + double d1343, d4321, d1321, d4343, d2121; + double numer, denom; + double mua, mub; + + p13[0] = p1[0] - p3[0]; + p13[1] = p1[1] - p3[1]; + p13[2] = p1[2] - p3[2]; + p43[0] = p4[0] - p3[0]; + p43[1] = p4[1] - p3[1]; + p43[2] = p4[2] - p3[2]; + p21[0] = p2[0] - p1[0]; + p21[1] = p2[1] - p1[1]; + p21[2] = p2[2] - p1[2]; + + //test for collinearity + if( abs(p21[1]*p43[2] - p21[2]*p43[1]) < EPSILON + && abs(p21[2]*p43[0] - p21[0]*p43[2]) < EPSILON + && abs(p21[0]*p43[1] - p21[1]*p43[0]) < EPSILON ){ + //lines are collinear; now test for an intersection + double x11, x12, x21, x22, y11, y12, y21, y22, z11, z12, z21, z22; + if(p1[0]<=p2[0]){ + x11 = p1[0]; + x12 = p2[0]; + } + else{ + x11 = p2[0]; + x12 = p1[0]; + } + if(p1[1]<=p2[1]){ + y11 = p1[1]; + y12 = p2[1]; + } + else{ + y11 = p2[1]; + y12 = p1[1]; + } + if(p1[2]<=p2[2]){ + z11 = p1[2]; + z12 = p2[2]; + } + else{ + z11 = p2[2]; + z12 = p1[2]; + } + if(p3[0]<=p4[0]){ + x21 = p3[0]; + x22 = p4[0]; + } + else{ + x21 = p4[0]; + x22 = p3[0]; + } + if(p3[1]<=p4[1]){ + y21 = p3[1]; + y22 = p4[1]; + } + else{ + y21 = p4[1]; + y22 = p3[1]; + } + if(p3[2]<=p4[2]){ + z21 = p3[2]; + z22 = p4[2]; + } + else{ + z21 = p4[2]; + z22 = p3[2]; + } + if(x11<=x22 && x12>=x21 && y11<=y22 && y12>=y21 && z11<=z22 && z12>=z21){ + if(abs(p21[0]) > EPSILON){ + mua = -p13[0]/p21[0]; + if(abs(p1[1] + p21[1]*mua - p3[1]) < EPSILON && abs(p1[2] + p21[2]*mua - p3[2]) < EPSILON){ + return true; + } + }else if(abs(p21[1]) > EPSILON){ + mua = -p13[1]/p21[1]; + if(abs(p1[0] + p21[0]*mua - p3[0]) < EPSILON && abs(p1[2] + p21[2]*mua - p3[2]) < EPSILON){ + return true; + } + }else{ + mua = -p13[2]/p21[2]; + if(abs(p1[0] + p21[0]*mua - p3[0]) < EPSILON && abs(p1[1] + p21[1]*mua - p3[1]) < EPSILON){ + return true; + } + } + } + return false; + } + + d1343 = p13[0] * p43[0] + p13[1] * p43[1] + p13[2] * p43[2]; + d4321 = p43[0] * p21[0] + p43[1] * p21[1] + p43[2] * p21[2]; + d1321 = p13[0] * p21[0] + p13[1] * p21[1] + p13[2] * p21[2]; + d4343 = p43[0] * p43[0] + p43[1] * p43[1] + p43[2] * p43[2]; + d2121 = p21[0] * p21[0] + p21[1] * p21[1] + p21[2] * p21[2]; + + denom = d2121 * d4343 - d4321 * d4321; + if(abs(denom) < EPSILON){ + return false; + } + numer = d1343 * d4321 - d1321 * d4343; + + mua = numer / denom; + mub = (d1343 + d4321 * mua) / d4343; + + if(mua<-EPSILON || mua-1>EPSILON || mub<-EPSILON || mub-1>EPSILON){ + return false; + } + if(abs(p1[0] + mua * p21[0] - p3[0] - mub * p43[0]) < EPSILON + && abs(p1[1] + mua * p21[1] - p3[1] - mub * p43[1]) < EPSILON + && abs(p1[2] + mua * p21[2] - p3[2] - mub * p43[2]) < EPSILON){ + return true; + }else{ + return false; + } +} + +//----------------------------------------< intersection_line_line_with_intersection_3d > +bool intersection_line_line_with_intersection_3d(double p1[], double p2[], double p3[], double p4[], + double intersection[]){ + double p13[3], p43[3], p21[3]; + double d1343, d4321, d1321, d4343, d2121; + double numer, denom; + double mua, mub; + int ci = -1; + + p13[0] = p1[0] - p3[0]; + p13[1] = p1[1] - p3[1]; + p13[2] = p1[2] - p3[2]; + p43[0] = p4[0] - p3[0]; + p43[1] = p4[1] - p3[1]; + p43[2] = p4[2] - p3[2]; + p21[0] = p2[0] - p1[0]; + p21[1] = p2[1] - p1[1]; + p21[2] = p2[2] - p1[2]; + + //test for collinearity + if( abs(p21[1]*p43[2] - p21[2]*p43[1]) < EPSILON + && abs(p21[2]*p43[0] - p21[0]*p43[2]) < EPSILON + && abs(p21[0]*p43[1] - p21[1]*p43[0]) < EPSILON ){ + //lines are collinear; now test for an intersection + double x11, x12, x21, x22, y11, y12, y21, y22, z11, z12, z21, z22; + if(p1[0]<=p2[0]){ + x11 = p1[0]; + x12 = p2[0]; + } + else{ + x11 = p2[0]; + x12 = p1[0]; + } + if(p1[1]<=p2[1]){ + y11 = p1[1]; + y12 = p2[1]; + } + else{ + y11 = p2[1]; + y12 = p1[1]; + } + if(p1[2]<=p2[2]){ + z11 = p1[2]; + z12 = p2[2]; + } + else{ + z11 = p2[2]; + z12 = p1[2]; + } + if(p3[0]<=p4[0]){ + x21 = p3[0]; + x22 = p4[0]; + } + else{ + x21 = p4[0]; + x22 = p3[0]; + } + if(p3[1]<=p4[1]){ + y21 = p3[1]; + y22 = p4[1]; + } + else{ + y21 = p4[1]; + y22 = p3[1]; + } + if(p3[2]<=p4[2]){ + z21 = p3[2]; + z22 = p4[2]; + } + else{ + z21 = p4[2]; + z22 = p3[2]; + } + if(x11<=x22 && x12>=x21 && y11<=y22 && y12>=y21 && z11<=z22 && z12>=z21){ + if(abs(p21[0]) > EPSILON){ + mua = -p13[0] / p21[0]; + if(abs(p1[1] + p21[1]*mua - p3[1]) < EPSILON && abs(p1[2] + p21[2]*mua - p3[2]) < EPSILON) ci = 0; + }else if(abs(p21[1]) > EPSILON){ + mua = -p13[1] / p21[1]; + if(abs(p1[0] + p21[0]*mua - p3[0]) < EPSILON && abs(p1[2] + p21[2]*mua - p3[2]) < EPSILON) ci = 1; + }else{ + mua = -p13[2] / p21[2]; + if(abs(p1[0] + p21[0]*mua - p3[0]) < EPSILON && abs(p1[1] + p21[1]*mua - p3[1]) < EPSILON) ci = 2; + } + if(ci != -1){ + //determine best intersection-point + //priority is p3(*) > p4 > p3 > p2 (one of these three points must be part of both line segments + //(*): p3 is only priorized over p4 if it is not a vertex of the first line segment + if(mua > EPSILON && mua-1< -EPSILON){ + intersection[0] = p3[0]; + intersection[1] = p3[1]; + intersection[2] = p3[2]; + }else{ + mub = (p4[ci]-p1[ci]) / p21[ci]; + if(mub > -EPSILON && mub-1 < EPSILON){ + intersection[0] = p4[0]; + intersection[1] = p4[1]; + intersection[2] = p4[2]; + }else if(mua > -EPSILON && mua-1 < EPSILON){ + intersection[0] = p3[0]; + intersection[1] = p3[1]; + intersection[2] = p3[2]; + }else{ + intersection[0] = p2[0]; + intersection[1] = p2[1]; + intersection[2] = p2[2]; + } + } + return true; + } + } + return false; + } + + d1343 = p13[0] * p43[0] + p13[1] * p43[1] + p13[2] * p43[2]; + d4321 = p43[0] * p21[0] + p43[1] * p21[1] + p43[2] * p21[2]; + d1321 = p13[0] * p21[0] + p13[1] * p21[1] + p13[2] * p21[2]; + d4343 = p43[0] * p43[0] + p43[1] * p43[1] + p43[2] * p43[2]; + d2121 = p21[0] * p21[0] + p21[1] * p21[1] + p21[2] * p21[2]; + + denom = d2121 * d4343 - d4321 * d4321; + if(abs(denom) < EPSILON){ + return false; + } + numer = d1343 * d4321 - d1321 * d4343; + + mua = numer / denom; + mub = (d1343 + d4321 * mua) / d4343; + if(mua<-EPSILON || mua-1>EPSILON || mub<-EPSILON || mub-1>EPSILON){ + return false; + } + + //determine potential intersection-point + intersection[0] = p1[0] + mua * p21[0]; + intersection[1] = p1[1] + mua * p21[1]; + intersection[2] = p1[2] + mua * p21[2]; + + //check if this really is an intersection + if(abs(intersection[0] - p3[0] - mub * p43[0]) < EPSILON + && abs(intersection[1] - p3[1] - mub * p43[1]) < EPSILON + && abs(intersection[2] - p3[2] - mub * p43[2]) < EPSILON){ + return true; + }else{ + return false; + } +} + +//----------------------------------------< intersection_line_triangle_3d_chirkov > +//ATTENTION: function does not work for lines almost in the plane of the triangle! +//calculates the intersection of a line segment and a triangle if it exists. The intersection-point is not +//calculated, the last argument "sol" remains unchanged. +// input: a line segment (lin0, lin1), and a triangle (tri0, tri1, tri2) +// return: 0 disjoint +// 1 intersection inside triangle +// 2,3,4 intersection in edge of triangle (edge_index is 0, 1, 2 respectively) +//this algorithm is based on an implementation by Nick Chirkov (journal of graphics tools 10(3):13-18, 2005). +int intersection_line_triangle_3d(double tri0[], double tri1[], double tri2[], + double lin0[], double lin1[], double sol[]){ + long i, type; + double org[3]; + double end[3]; + double dir[3]; + double x, y, z, d; + + //cube-collision-detection to determine necessity of real intersection check + //note: this does not seem to improve performance unfortunately. + //double p3[3],q3[3],p4[3],q4[3]; + //for(i=0; i<3; ++i){ + // if(tri0[i] <= tri1[i]){ + // if(tri0[i] <= tri2[i]){ + // p3[i] = tri0[i]; + // q3[i] = ((tri1[i]>=tri2[i])? tri1[i] : tri2[i]); + // } + // else{ + // p3[i] = tri2[i]; + // q3[i] = tri1[i]; + // } + // } + // else{ + // if(tri1[i] <= tri2[i]){ + // p3[i] = tri1[i]; + // q3[i] = ((tri0[i]>=tri2[i])? tri2[i] : tri0[i]); + // } + // else{ + // p3[i] = tri2[i]; + // q3[i] = tri0[i]; + // } + // } + // if(lin0[i] <= lin1[i]){ + // p4[i] = lin0[i]; + // q4[i] = lin1[i]; + // } + // else{ + // p4[i] = lin1[i]; + // q4[i] = lin0[i]; + // } + //} + //if(p3[0]>q4[0] || q3[0]<p4[0] || p3[1]>q4[1] || q3[1]<p4[1] || p3[2]>q4[2] || q3[2]<p4[2]){ + // return 0; + //} + + double ax = tri1[0] - tri0[0]; + double ay = tri1[1] - tri0[1]; + double az = tri1[2] - tri0[2]; + double bx = tri2[0] - tri0[0]; + double by = tri2[1] - tri0[1]; + double bz = tri2[2] - tri0[2]; + x = ay * bz - az * by; + y = az * bx - ax * bz; + z = ax * by - ay * bx; + d = x*tri0[0] + y*tri0[1] + z*tri0[2]; + + static const double SQ = sqrt(1.0/3.0); + double len = (x*x + y*y + z*z)*SQ; + + if(fabs(x)>len) type = 1; + else if(fabs(y)>len) type = 2; + else type = 3; + + for(i=0;i<=2;i++){ + org[i] = lin0[i]; //todo: org can be replaced by lin0 throughout the whole function + end[i] = lin1[i]; //todo: replace end by lin1 + dir[i] = end[i] - org[i]; + } + + //determine intersection + double signSrc = x*org[0] + y*org[1] + z*org[2] - d; + double signDst = x*end[0] + y*end[1] + z*end[2] - d; + if(signSrc*signDst > 0.0){ + return 0; + } + + double di = signSrc - signDst; + + if(type == 1){ + double basey = org[1] - tri0[1]; + double basez = org[2] - tri0[2]; + double adelx = signSrc*(ay * dir[2] - az * dir[1]); + if((adelx + di * (ay*basez-az*basey)) + * (signSrc*(dir[1]*bz-dir[2]*by) + di * (basey*bz-basez*by)) > 0.0){ + double e2y = tri1[1] - tri2[1]; + double e2z = tri1[2] - tri2[2]; + basey = org[1] - tri1[1]; + basez = org[2] - tri1[2]; + if((adelx + di * (ay*basez-az*basey)) + * (signSrc*(dir[1]*e2z-dir[2]*e2y) + di * (basey*e2z-basez*e2y)) > 0.0){ + goto test_edges; + } + } + } + else if(type == 2){ + double basex = org[0] - tri0[0]; + double basez = org[2] - tri0[2]; + double adely = signSrc*(az * dir[0] - ax * dir[2]); + if((adely + di * (az*basex-ax*basez)) + * (signSrc*(dir[2]*bx-dir[0]*bz) + di * (basez*bx-basex*bz)) > 0.0){ + double e2x = tri1[0] - tri2[0]; + double e2z = tri1[2] - tri2[2]; + basex = org[0] - tri1[0]; + basez = org[2] - tri1[2]; + if((adely + di * (az*basex-ax*basez)) + * (signSrc*(dir[2]*e2x-dir[0]*e2z) + di * (basez*e2x-basex*e2z)) > 0.0){ + goto test_edges; + } + } + } + else{ + double basex = org[0] - tri0[0]; + double basey = org[1] - tri0[1]; + double adelz = signSrc*(ax * dir[1] - ay * dir[0]); + if((adelz + di * (ax*basey-ay*basex)) + * (signSrc*(dir[0]*by-dir[1]*bx) + di * (basex*by-basey*bx)) > 0.0){ + double e2x = tri1[0] - tri2[0]; + double e2y = tri1[1] - tri2[1]; + basex = org[0] - tri1[0]; + basey = org[1] - tri1[1]; + if((adelz + di * (ax*basey-ay*basex)) + * (signSrc*(dir[0]*e2y-dir[1]*e2x) + di * (basex*e2y-basey*e2x)) > 0.0){ + goto test_edges; + } + } + } + + return 0; + + test_edges:; + if(intersection_line_line_3d(tri0, tri1, lin0, lin1)){ + return 4; + }else if(intersection_line_line_3d(tri1, tri2, lin0, lin1)){ + return 2; + }else if(intersection_line_line_3d(tri2, tri0, lin0, lin1)){ + return 3; + } + return 1; +} + +//----------------------------------------< intersection_line_triangle_3d_softsurfer > +// Copyright 2001, softSurfer (www.softsurfer.com) +// This code may be freely used and modified for any purpose +// providing that this copyright notice is included with it. +// SoftSurfer makes no warranty for this code, and cannot be held +// liable for any real or imagined damage resulting from its use. +// Users of this code must verify correctness for their application. + +//calculates the intersection point of a line segment and a triangle if it exists +// input: a line segment (lin0, lin1), and a triangle (tri0, tri1, tri2) +// output: sol = intersection point (if it exists) +// return: 0 disjoint +// 1 intersection inside triangle +// 2,3,4 intersection in edge of triangle (edge_index is 0, 1, 2 respectively) +int intersection_line_triangle_3d_softsurfer(double tri0[], double tri1[], double tri2[], + double lin0[], double lin1[], double sol[]){ + double u[3], v[3], n[3]; //triangle vectors + double dir[3], w0[3], w[3]; //ray vectors + double r, a, b; //params to calc ray-plane intersect + long i, e; + double EPSILON2 = 100 * EPSILON; + + double uu, uv, vv, wu, wv, D; + double s, t; + double distances[3]; + + //get triangle edge vectors and plane normal + for(i=0; i<3; i++) u[i] = tri1[i] - tri0[i]; + for(i=0; i<3; i++) v[i] = tri2[i] - tri0[i]; + n[0] = u[1]*v[2] - u[2]*v[1]; + n[1] = u[2]*v[0] - u[0]*v[2]; + n[2] = u[0]*v[1] - u[1]*v[0]; + if(abs(n[0])<EPSILON && abs(n[1])<EPSILON && abs(n[2])<EPSILON){ + if(intersection_line_line_with_intersection_3d(tri0, tri1, lin0, lin1, sol)){ + return 4; + }else if(intersection_line_line_with_intersection_3d(tri1, tri2, lin0, lin1, sol)){ + return 2; + }else if(intersection_line_line_with_intersection_3d(tri2, tri0, lin0, lin1, sol)){ + return 3; + } + } + + for(i=0; i<3; i++) dir[i] = lin1[i] - lin0[i]; //line direction vector + for(i=0; i<3; i++) w0[i] = lin0[i] - tri0[i]; + a = -(n[0] * w0[0] + n[1] * w0[1] + n[2] * w0[2]); + b = n[0] * dir[0] + n[1] * dir[1] + n[2] * dir[2]; + if(abs(b) < EPSILON){ //ray is parallel to triangle plane + if(abs(a) < EPSILON){ + //test whether one of the line's vertices lies inside the triangle + for(e=0; e<2; e++){ + if(e==0) for(i=0; i<3; i++) sol[i] = lin0[i]; + else for(i=0; i<3; i++) sol[i] = lin1[i]; + + uu = u[0] * u[0] + u[1] * u[1] + u[2] * u[2]; + uv = u[0] * v[0] + u[1] * v[1] + u[2] * v[2]; + vv = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; + for(i=0; i<3; i++) w[i] = sol[i] - tri0[i]; + + wu = w[0] * u[0] + w[1] * u[1] + w[2] * u[2]; + wv = w[0] * v[0] + w[1] * v[1] + w[2] * v[2]; + D = uv * uv - uu * vv; + + s = (uv * wv - vv * wu) / D; + if (s < -EPSILON || s-1.0 > EPSILON) continue; //sol is outside triangle + t = (uv * wu - uu * wv) / D; + if (t < -EPSILON || (s + t-1.0) > EPSILON) continue; //sol is outside triangle + + distances[0] = distance_point_line_3d(sol, tri0, tri1); + distances[1] = distance_point_line_3d(sol, tri1, tri2); + distances[2] = distance_point_line_3d(sol, tri2, tri0); + if(distances[0]>EPSILON2 && distances[1]>EPSILON2 && distances[2]>EPSILON2){ + return 1; + } + } + + //test whether ray intersects one of the triangle's edges + if(intersection_line_line_with_intersection_3d(tri0, tri1, lin0, lin1, sol)){ + return 4; + }else if(intersection_line_line_with_intersection_3d(tri1, tri2, lin0, lin1, sol)){ + return 2; + }else if(intersection_line_line_with_intersection_3d(tri2, tri0, lin0, lin1, sol)){ + return 3; + } + } + return 0; //ray disjoint from plane + } + + //get intersection point of ray with triangle plane + r = a / b; + if(r < -EPSILON || r-1.0 > EPSILON){ + return 0; //ray goes away from triangle => no intersection + } + for(i=0; i<3; i++) sol[i] = lin0[i] + r * dir[i]; + + //is sol inside triangle? + uu = u[0] * u[0] + u[1] * u[1] + u[2] * u[2]; + uv = u[0] * v[0] + u[1] * v[1] + u[2] * v[2]; + vv = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; + for(i=0; i<3; i++) w[i] = sol[i] - tri0[i]; + + wu = w[0] * u[0] + w[1] * u[1] + w[2] * u[2]; + wv = w[0] * v[0] + w[1] * v[1] + w[2] * v[2]; + D = uv * uv - uu * vv; + + //get and test parametric coords + s = (uv * wv - vv * wu) / D; + if (s < -EPSILON || s-1.0 > EPSILON){ + return 0; //sol is outside triangle + } + t = (uv * wu - uu * wv) / D; + if (t < -EPSILON || (s + t-1.0) > EPSILON){ + return 0; //sol is outside triangle + } + + //calculate distance of sol with each edge of the triangle + distances[0] = distance_point_line_3d(sol, tri0, tri1); + if(distances[0]<EPSILON2){ + return 4; + } + distances[1] = distance_point_line_3d(sol, tri1, tri2); + if(distances[1]<EPSILON2){ + return 2; + } + distances[2] = distance_point_line_3d(sol, tri2, tri0); + if(distances[2]<EPSILON2){ + return 3; + } + return 1; //sol is inside triangle +} + +//----------------------------------------< intersection_line_tetrahedron_3d > +bool intersection_line_tetrahedron_3d(double lin0[], double lin1[], double tet0[], double tet1[], + double tet2[], double tet3[]){ + double sol[3]; + //test intersection with faces + if(intersection_line_triangle_3d(tet0, tet1, tet2, lin0, lin1, sol)){ + return true; + } + if(intersection_line_triangle_3d(tet0, tet1, tet3, lin0, lin1, sol)){ + return true; + } + if(intersection_line_triangle_3d(tet0, tet2, tet3, lin0, lin1, sol)){ + return true; + } + if(intersection_line_triangle_3d(tet1, tet2, tet3, lin0, lin1, sol)){ + return true; + } + //test intersection with edges + if(intersection_line_line_3d(tet0, tet1, lin0, lin1)){ + return true; + } + if(intersection_line_line_3d(tet0, tet2, lin0, lin1)){ + return true; + } + if(intersection_line_line_3d(tet0, tet3, lin0, lin1)){ + return true; + } + if(intersection_line_line_3d(tet1, tet2, lin0, lin1)){ + return true; + } + if(intersection_line_line_3d(tet1, tet3, lin0, lin1)){ + return true; + } + if(intersection_line_line_3d(tet2, tet3, lin0, lin1)){ + return true; + } + //test intersection with volume + if(point_in_tetrahedron_3d(lin0, tet0, tet1, tet2, tet3) + || point_in_tetrahedron_3d(lin1, tet0, tet1, tet2, tet3)){ + return true; + } + return false; +} + +//----------------------------------------< intersection_triangle_tetrahedron_3d > +bool intersection_triangle_tetrahedron_3d(double tri0[], double tri1[], double tri2[], + double tet0[], double tet1[], double tet2[], double tet3[]){ + //test intersection with volume + if(point_in_tetrahedron_3d(tri0, tet0, tet1, tet2, tet3) + || point_in_tetrahedron_3d(tri1, tet0, tet1, tet2, tet3) + || point_in_tetrahedron_3d(tri2, tet0, tet1, tet2, tet3)){ + return true; + } + //test intersection of triangle-edges with tetrahedron + if(intersection_line_tetrahedron_3d(tri0, tri1, tet0, tet1, tet2, tet3)){ + return true; + } + if(intersection_line_tetrahedron_3d(tri1, tri2, tet0, tet1, tet2, tet3)){ + return true; + } + if(intersection_line_tetrahedron_3d(tri2, tri0, tet0, tet1, tet2, tet3)){ + return true; + } + //test intersection of tetrahedron-edges with triangle + double sol[3]; + if(intersection_line_triangle_3d(tri0, tri1, tri2, tet0, tet1, sol)){ + return true; + } + if(intersection_line_triangle_3d(tri0, tri1, tri2, tet0, tet2, sol)){ + return true; + } + if(intersection_line_triangle_3d(tri0, tri1, tri2, tet0, tet3, sol)){ + return true; + } + if(intersection_line_triangle_3d(tri0, tri1, tri2, tet1, tet2, sol)){ + return true; + } + if(intersection_line_triangle_3d(tri0, tri1, tri2, tet1, tet3, sol)){ + return true; + } + if(intersection_line_triangle_3d(tri0, tri1, tri2, tet2, tet3, sol)){ + return true; + } + return false; +} + +//----------------------------------------< intersection_box_box_3d > +bool intersection_box_box_3d(double min_corner0[], double max_corner0[], + double min_corner1[], double max_corner1[]){ + double p[3]; + + if (edge_length_3d(min_corner0,max_corner0) < edge_length_3d(min_corner1,max_corner1)) { + // box0 is smaller than box1 + if (point_in_box_3d(min_corner0, min_corner1, max_corner1)) + return true; + if (point_in_box_3d(max_corner0, min_corner1, max_corner1)) + return true; + + p[0] = min_corner0[0]; p[1] = min_corner0[1]; p[2] = max_corner0[2]; + if (point_in_box_3d(p, min_corner1, max_corner1)) + return true; + p[0] = min_corner0[0]; p[1] = max_corner0[1]; p[2] = min_corner0[2]; + if (point_in_box_3d(p, min_corner1, max_corner1)) + return true; + p[0] = min_corner0[0]; p[1] = max_corner0[1]; p[2] = max_corner0[2]; + if (point_in_box_3d(p, min_corner1, max_corner1)) + return true; + + p[0] = max_corner0[0]; p[1] = max_corner0[1]; p[2] = min_corner0[2]; + if (point_in_box_3d(p, min_corner1, max_corner1)) + return true; + p[0] = max_corner0[0]; p[1] = min_corner0[1]; p[2] = max_corner0[2]; + if (point_in_box_3d(p, min_corner1, max_corner1)) + return true; + p[0] = max_corner0[0]; p[1] = min_corner0[1]; p[2] = min_corner0[2]; + if (point_in_box_3d(p, min_corner1, max_corner1)) + return true; + + } else { + // box1 is smaller than box0 + if (point_in_box_3d(min_corner1, min_corner0, max_corner0)) + return true; + if (point_in_box_3d(max_corner1, min_corner0, max_corner0)) + return true; + + p[0] = min_corner1[0]; p[1] = min_corner1[1]; p[2] = max_corner1[2]; + if (point_in_box_3d(p, min_corner0, max_corner0)) + return true; + p[0] = min_corner1[0]; p[1] = max_corner1[1]; p[2] = min_corner1[2]; + if (point_in_box_3d(p, min_corner0, max_corner0)) + return true; + p[0] = min_corner1[0]; p[1] = max_corner1[1]; p[2] = max_corner1[2]; + if (point_in_box_3d(p, min_corner0, max_corner0)) + return true; + + p[0] = max_corner1[0]; p[1] = max_corner1[1]; p[2] = min_corner1[2]; + if (point_in_box_3d(p, min_corner0, max_corner0)) + return true; + p[0] = max_corner1[0]; p[1] = min_corner1[1]; p[2] = max_corner1[2]; + if (point_in_box_3d(p, min_corner0, max_corner0)) + return true; + p[0] = max_corner1[0]; p[1] = min_corner1[1]; p[2] = min_corner1[2]; + if (point_in_box_3d(p, min_corner0, max_corner0)) + return true; + } +} + +//----------------------------------------< intersection_triangle_box_3d > +bool intersection_triangle_box_3d(double tri0[], double tri1[], double tri2[], + double min_corner[], double max_corner[]){ + // vertices of triangle covered by box + if (point_in_box_generous_3d(tri0,min_corner,max_corner)) + return true; + if (point_in_box_generous_3d(tri1,min_corner,max_corner)) + return true; + if (point_in_box_generous_3d(tri2,min_corner,max_corner)) + return true; + + // bounding box of triangle does not intersect the box + double p0[3]; + double p1[3]; + boundingbox_triangle_3d(tri0,tri1,tri2,p0,p1); + if (!intersection_box_box_3d(min_corner,max_corner,p0,p1)) + return false; + + double p2[3]; + + // edges of box intersect triangle + p0[0] = min_corner[0]; p0[1] = min_corner[1]; p0[2] = max_corner[2]; + if (intersection_line_triangle_3d(tri0,tri1,tri2, min_corner, p0, p2)) + return true; + + p1[0] = max_corner[0]; p1[1] = min_corner[1]; p1[2] = max_corner[2]; + if (intersection_line_triangle_3d(tri0,tri1,tri2, max_corner, p1, p2)) + return true; + if (intersection_line_triangle_3d(tri0,tri1,tri2, p0, p1, p2)) + return true; + + p1[0] = min_corner[0]; p1[1] = max_corner[1]; p1[2] = max_corner[2]; + if (intersection_line_triangle_3d(tri0,tri1,tri2, max_corner, p1, p2)) + return true; + if (intersection_line_triangle_3d(tri0,tri1,tri2, p0, p1, p2)) + return true; + + p0[0] = min_corner[0]; p0[1] = max_corner[1]; p0[2] = min_corner[2]; + if (intersection_line_triangle_3d(tri0,tri1,tri2, min_corner, p0, p2)) + return true; + if (intersection_line_triangle_3d(tri0,tri1,tri2, p0, p1, p2)) + return true; + + p1[0] = max_corner[0]; p1[1] = max_corner[1]; p1[2] = min_corner[2]; + if (intersection_line_triangle_3d(tri0,tri1,tri2, max_corner, p1, p2)) + return true; + if (intersection_line_triangle_3d(tri0,tri1,tri2, p0, p1, p2)) + return true; + + p0[0] = max_corner[0]; p0[1] = min_corner[1]; p0[2] = min_corner[2]; + if (intersection_line_triangle_3d(tri0,tri1,tri2, min_corner, p0, p2)) + return true; + if (intersection_line_triangle_3d(tri0,tri1,tri2, p0, p1, p2)) + return true; + + p1[0] = max_corner[0]; p1[1] = min_corner[1]; p1[2] = max_corner[2]; + if (intersection_line_triangle_3d(tri0,tri1,tri2, p0, p1, p2)) + return true; + + return false; +} + +//----------------------------------------< distance_point_line_3d > +//calculates the distance between a given point and the line segment between 'lin0' and 'lin1'. +double distance_point_line_3d(double point[], double lin0[], double lin1[]){ + double gx, gy, gz, fx, fy, fz, dx, dy, dz, t; + + //the (complete) line through 'lin0' and 'lin1' is given by 'l = lin0 + t*g' with g as follows: + gx = lin1[0] - lin0[0]; + gy = lin1[1] - lin0[1]; + gz = lin1[2] - lin0[2]; + + //the normal-vector from 'point' to l is 'v = lin0 + t*g - point' for some t which is determined + // by 'v*g = 0' + t = (-gx * (lin0[0]-point[0]) - gy * (lin0[1]-point[1]) - gz * (lin0[2]-point[2])) + / (gx*gx + gy*gy + gz*gz); + + //if the orthogonal projection of 'point' onto l is not on the given line segment then one of the + //vertices 'lin0' or 'lin1' is the nearest point to 'point' + if(t<0){ + //'lin0' is nearest + fx = lin0[0]; + fy = lin0[1]; + fz = lin0[2]; + } + else if(t>1){ + //'lin1' is nearest + fx = lin1[0]; + fy = lin1[1]; + fz = lin1[2]; + } + else{ + //orthogonal projection is nearest + fx = lin0[0] + t * gx; + fy = lin0[1] + t * gy; + fz = lin0[2] + t * gz; + } + + //calculate distance + dx = point[0] - fx; + dy = point[1] - fy; + dz = point[2] - fz; + return sqrt(dx*dx + dy*dy + dz*dz); +} + + +//----------------------------------------< distance_point_box_2d > +double distance_point_box_3d(double point[], double min_corner[], double max_corner[]){ + if (point_in_box_3d(point,min_corner,max_corner)) + return 0.0; + + double p[3]; + double dist = edge_length_3d(point, min_corner); + dist = std::min(dist, edge_length_3d(point, min_corner)); + + p[0] = min_corner[0]; p[1] = min_corner[1]; p[2] = max_corner[2]; + dist = std::min(dist, edge_length_3d(point, p)); + p[0] = min_corner[0]; p[1] = max_corner[1]; p[2] = min_corner[2]; + dist = std::min(dist, edge_length_3d(point, p)); + p[0] = min_corner[0]; p[1] = max_corner[1]; p[2] = max_corner[2]; + dist = std::min(dist, edge_length_3d(point, p)); + + p[0] = max_corner[0]; p[1] = max_corner[1]; p[2] = min_corner[2]; + dist = std::min(dist, edge_length_3d(point, p)); + p[0] = max_corner[0]; p[1] = min_corner[1]; p[2] = max_corner[2]; + dist = std::min(dist, edge_length_3d(point, p)); + p[0] = max_corner[0]; p[1] = min_corner[1]; p[2] = min_corner[2]; + dist = std::min(dist, edge_length_3d(point, p)); + + return dist; +} + +//----------------------------------------< distance_point_triangle_3d > +//calculates the distance between a given 'point' and the triangle given by 'tri0', 'tri1', 'tri2'. +double distance_point_triangle_3d(double point[], double tri0[], double tri1[], double tri2[]){ + double gx, gy, gz, hx, hy, hz, fx, fy, fz, u, v; + double c1, c2, b1, b2, a1, distance, tmp; + + //triangle lies in plane 'p = tri0 + u*g + v*h', where g and h are defined as follows: + gx = tri1[0] - tri0[0]; + gy = tri1[1] - tri0[1]; + gz = tri1[2] - tri0[2]; + hx = tri2[0] - tri0[0]; + hy = tri2[1] - tri0[1]; + hz = tri2[2] - tri0[2]; + + //a vector from 'point' to p can be described by 'l = tri0 + u*g + v*h - point' and since we search the + //distance we need such a vector that is orthogonal to p. Thus 'l*g = 0' and 'l*h = 0'. We get a system + //of two equations of the form: + //a1*u + b1*v = c1 + //b1*u + b2*v = c2 + //with a1, b1, b2, c1, c2 as follows: + b1 = gx*hx + gy*hy + gz*hz; + c2 = -hx*(tri0[0]-point[0]) - hy*(tri0[1]-point[1]) - hz*(tri0[2]-point[2]); + b2 = hx*hx + hy*hy + hz*hz; + c1 = -gx*(tri0[0]-point[0]) - gy*(tri0[1]-point[1]) - gz*(tri0[2]-point[2]); + a1 = gx*gx + gy*gy + gz*gz; + + //solve the system: + if(abs(b1) < EPSILON){ + v = c2/b2; + u = c1/a1; + } + else{ + v = (c1*b1 - c2*a1) / (b1*b1 - b2*a1); + u = (c1 - v*b1) / a1; + } + + //now test whether the orthogonal projection of 'point' onto p lies inside the triangle + if(u>=0 && v>=0 && u+v<=1){ + //yes, inside. The length of the normal-vector is the desired distance + fx = point[0] - tri0[0] - u*gx - v*hx; + fy = point[1] - tri0[1] - u*gy - v*hy; + fz = point[2] - tri0[2] - u*gz - v*hz; + distance = sqrt(fx*fx + fy*fy + fz*fz); + } + else{ + //no, not inside. The desired distance is the distance to one of the triangle-edges + distance = 9999999.0; + tmp = distance_point_line_3d(point, tri0, tri1); + if(tmp<distance) distance = tmp; + tmp = distance_point_line_3d(point, tri1, tri2); + if(tmp<distance) distance = tmp; + tmp = distance_point_line_3d(point, tri2, tri0); + if(tmp<distance) distance = tmp; + } + return distance; +} + +} diff --git a/extensions/GeometryTools.h b/extensions/GeometryTools.h new file mode 100644 index 0000000000000000000000000000000000000000..874a19b925a585f55ab06be4e3b128bb70a57430 --- /dev/null +++ b/extensions/GeometryTools.h @@ -0,0 +1,250 @@ +/** \file GeometryTools.h */ + +#ifndef GEOMETRY_TOOLBOX_H +#define GEOMETRY_TOOLBOX_H + +#include "AMDiS.h" + +namespace meshconv { + +// ############### +// ## General ## +// ############### + +//----------------------------------------< coordinate_extrema_triangle > +//returns in 'small_coord' the smallest coordinate of 'sm' in the given dimension and in 'big_coord' the +//biggest coordinate in the given dimension. Note: 'sm' has to be a triangle in a 2d or 3d world. +// void coordinate_extrema_triangle(mesh &m, element &sm, long dimension, double &small_coord, +// double &big_coord); + +//----------------------------------------< solve_determinant4 > +double solve_determinant4(double x11, double x12, double x13, double x14, + double x21, double x22, double x23, double x24, + double x31, double x32, double x33, double x34, + double x41, double x42, double x43, double x44); + +// ################# +// ## 2D Worlds ## +// ################# + +//----------------------------------------< edge_length_2d > +double edge_length_2d(double lin0[], double lin1[]); + +//----------------------------------------< boundingbox_triangle_2d > +void boundingbox_triangle_2d(double tri0[], double tri1[], double tri2[], + double min_corner[], double max_corner[]); + +//----------------------------------------< centroid_of_box_2d > +void centroid_of_box_2d(double min_corner[], double max_corner[], double c[]); + +//----------------------------------------< centroid_of_triangle_2d > +void centroid_of_triangle_2d(double tri0[], double tri1[], double tri2[], double c[]); + +//----------------------------------------< point_in_triangle_2d > +bool point_in_triangle_2d(double p[], double a[], double b[], double c[]); + +//----------------------------------------< point_in_triangle_generous_2d > +bool point_in_triangle_generous_2d(double p[], double a[], double b[], double c[]); + +//----------------------------------------< point_in_box_2d > +bool point_in_box_2d(double p[], double min_corner[], double max_corner[]); + +//----------------------------------------< point_in_box_generous_2d > +bool point_in_box_generous_2d(double p[], double min_corner[], double max_corner[]); + +//----------------------------------------< intersection_line_line_2d > +//tests whether the line segment defined by end points 'lin0' and 'lin1' intersects the connection +//between lamp and new_dof. If the line segment is intersected in one of its vertices the index of that +//vertex (0 or 1) is returned in hit_vertex otherwise hit_vertex is set to -1. +bool intersection_line_line_2d(double lin0[], double lin1[], + double lamp[], double new_dof[], long &hit_vertex); + +//----------------------------------------< intersection_line_triangle_2d > +bool intersection_line_triangle_2d(double lin0[], double lin1[], + double tri0[], double tri1[], double tri2[]); + +//----------------------------------------< intersection_line_box_2d > +bool intersection_line_box_2d(double lin0[], double lin1[], + double min_corner[], double max_corner[]); + +//----------------------------------------< intersection_box_box_2d > +bool intersection_box_box_2d(double min_corner0[], double max_corner0[], + double min_corner1[], double max_corner1[]); + +//----------------------------------------< intersection_triangle_box_2d > +bool intersection_triangle_box_2d(double tri0[], double tri1[], double tri2[], + double min_corner[], double max_corner[]); + +//----------------------------------------< distance_point_line_2d > +//calculates the distance between a given point and the line segment between 'lin0' and 'lin1'. +double distance_point_line_2d(double point[], double lin0[], double lin1[]); + +//----------------------------------------< distance_point_line_with_intersection_2d > +//calculates the distance between a given point and the line-segment between 'lin0' and 'lin1'. +//This version also returns the intersection-point of the perpendicular with the given line-segment. +double distance_point_line_with_intersection_2d(double point[], double lin0[], double lin1[], + double intersection[]); + +//----------------------------------------< distance_point_box_2d > +double distance_point_box_2d(double point[], double min_corner[], double max_corner[]); + +//----------------------------------------< distance_point_triangle_2d > +double distance_point_triangle_2d(double point[], double tri0[], double tri1[], double tri2[]); + +bool point_in_polygon(double point[], const std::vector<AMDiS::WorldVector<double> > &vertices); + +// ################# +// ## 3D Worlds ## +// ################# + +//----------------------------------------< points_identical_3d > +bool points_identical_3d(double p1[], double p2[]); + +//----------------------------------------< normal_vector_3d > +void normal_vector_3d(double tri0[], double tri1[], double tri2[], double normal[]); + +//----------------------------------------< triangle_area_3d > +double triangle_area_3d(double tri0[], double tri1[], double tri2[]); + +//----------------------------------------< edge_length_3d > +double edge_length_3d(double lin0[], double lin1[]); + +//----------------------------------------< triangle_max_edge_length_3d > +double triangle_max_edge_length_3d(double tri0[], double tri1[], double tri2[]); + +//----------------------------------------< unit_normal_vector_3d > +void unit_normal_vector_3d(double tri0[], double tri1[], double tri2[], double normal[]); + +//----------------------------------------< degenerate_triangle_3d > +bool degenerate_triangle_3d(double tri0[], double tri1[], double tri2[]); + + +//----------------------------------------< boundingbox_triangle_3d > +void boundingbox_triangle_3d(double tri0[], double tri1[], double tri2[], + double min_corner[], double max_corner[]); + +//----------------------------------------< centroid_of_box_3d > +void centroid_of_box_3d(double min_corner[], double max_corner[], double c[]); + +//----------------------------------------< centroid_of_triangle_3d > +void centroid_of_triangle_3d(double tri0[], double tri1[], double tri2[], double c[]); + +//----------------------------------------< point_in_box_3d > +bool point_in_box_3d(double p[], double min_corner[], double max_corner[]); + +//----------------------------------------< point_in_box_generous_3d > +bool point_in_box_generous_3d(double p[], double min_corner[], double max_corner[]); + +//----------------------------------------< point_in_tetrahedron_3d > +bool point_in_tetrahedron_3d(double p[], double a[], double b[], double c[], double d[]); + +//----------------------------------------< intersection_line_line_3d > +bool intersection_line_line_3d(double p1[], double p2[], double p3[], double p4[]); + +//----------------------------------------< intersection_line_line_with_intersection_3d > +bool intersection_line_line_with_intersection_3d(double p1[], double p2[], double p3[], double p4[], + double intersection[]); + +//----------------------------------------< intersection_line_triangle_3d_chirkov > +//ATTENTION: function does not work for lines almost in the plane of the triangle! +//calculates the intersection of a line segment and a triangle if it exists. The intersection-point is not +//calculated, the last argument "sol" remains unchanged. +// input: a line segment (lin0, lin1), and a triangle (tri0, tri1, tri2) +// return: 0 disjoint +// 1 intersection inside triangle +// 2,3,4 intersection in edge of triangle (edge_index is 0, 1, 2 respectively) +//this algorithm is based on an implementation by Nick Chirkov (journal of graphics tools 10(3):13-18, 2005). +int intersection_line_triangle_3d(double tri0[], double tri1[], double tri2[], + double lin0[], double lin1[], double sol[]); + +//----------------------------------------< global variables > +// int (*intersection_line_triangle_3d)(double tri0[], double tri1[], double tri2[], +// double lin0[], double lin1[], double sol[]) = intersection_line_triangle_3d_chirkov; + +//----------------------------------------< intersection_line_triangle_3d_softsurfer > +// Copyright 2001, softSurfer (www.softsurfer.com) +// This code may be freely used and modified for any purpose +// providing that this copyright notice is included with it. +// SoftSurfer makes no warranty for this code, and cannot be held +// liable for any real or imagined damage resulting from its use. +// Users of this code must verify correctness for their application. + +//calculates the intersection point of a line segment and a triangle if it exists +// input: a line segment (lin0, lin1), and a triangle (tri0, tri1, tri2) +// output: sol = intersection point (if it exists) +// return: 0 disjoint +// 1 intersection inside triangle +// 2,3,4 intersection in edge of triangle (edge_index is 0, 1, 2 respectively) +int intersection_line_triangle_3d_softsurfer(double tri0[], double tri1[], double tri2[], + double lin0[], double lin1[], double sol[]); + +//----------------------------------------< intersection_line_tetrahedron_3d > +bool intersection_line_tetrahedron_3d(double lin0[], double lin1[], double tet0[], double tet1[], + double tet2[], double tet3[]); + +//----------------------------------------< intersection_triangle_tetrahedron_3d > +bool intersection_triangle_tetrahedron_3d(double tri0[], double tri1[], double tri2[], + double tet0[], double tet1[], double tet2[], double tet3[]); + +//----------------------------------------< intersection_box_box_3d > +bool intersection_box_box_3d(double min_corner0[], double max_corner0[], + double min_corner1[], double max_corner1[]); + +//----------------------------------------< intersection_triangle_box_3d > +bool intersection_triangle_box_3d(double tri0[], double tri1[], double tri2[], + double min_corner[], double max_corner[]); + +//----------------------------------------< distance_point_line_3d > +//calculates the distance between a given point and the line segment between 'lin0' and 'lin1'. +double distance_point_line_3d(double point[], double lin0[], double lin1[]); + + +//----------------------------------------< distance_point_box_3d > +double distance_point_box_3d(double point[], double min_corner[], double max_corner[]); + +//----------------------------------------< distance_point_triangle_3d > +//calculates the distance between a given 'point' and the triangle given by 'tri0', 'tri1', 'tri2'. +double distance_point_triangle_3d(double point[], double tri0[], double tri1[], double tri2[]); + + +template<int dow> +void coordinate_transform(double x[], double shift[], double scale[], double alpha=0.0, double beta=0.0) +{ + mtl::dense2D<double> Rx(dow,dow),Ry(dow,dow),T(dow,dow),S(dow,dow); + Rx = 1.0; + Ry = 1.0; + S = 1.0; + if (dow == 3) { + Rx(1,1) = cos(alpha); Rx(1,2) = -sin(alpha); + Rx(2,1) = sin(alpha); Rx(2,2) = cos(alpha); + + Ry(0,0) = cos(beta); Ry(0,2) = sin(beta); + Ry(2,0) = -sin(beta); Ry(2,2) = cos(beta); + + S(0,0) = scale[0]; S(1,1) = scale[1]; S(2,2) = scale[2]; + } else if (dow == 2) { + Rx(0,0) = cos(alpha); Rx(0,1) = -sin(alpha); + Rx(1,0) = sin(alpha); Rx(1,1) = cos(alpha); + + Ry = 1.0; + + S(0,0) = scale[0]; S(1,1) = scale[1]; + } else { + S(0,0) = scale[0]; + } + + T = Ry*Rx*S; + + mtl::dense_vector<double> coords(dow); + for (int i = 0; i < dow; i++) + coords[i] = x[i]; + + coords = T*coords; + + for (int i = 0; i < dow; i++) + x[i] = coords[i]+shift[i]; +} + +} + +#endif // GEOMETRY_TOOLBOX_H diff --git a/extensions/Helpers.cc b/extensions/Helpers.cc new file mode 100644 index 0000000000000000000000000000000000000000..d4069348c82e023355328b36e89d6a7ff6a356d8 --- /dev/null +++ b/extensions/Helpers.cc @@ -0,0 +1,524 @@ +#include "Helpers.h" + +using namespace AMDiS; + + +void Helpers::copyDOF(std::vector<DOFVector<double>*> dof1, std::vector<DOFVector<double>*> dof2, WorldVector<double> shift, double fillValue) +{ FUNCNAME("Helpers::copyDOF()"); + + TEST_EXIT(dof1.size() == dof2.size())("number of components to copy must be the same!\n"); + TEST_EXIT(dof1.size() > 0)("Minimum 1 DOFVector to copy\n"); + + const FiniteElemSpace* feSpace1 = dof1[0]->getFeSpace(); + const FiniteElemSpace* feSpace2 = dof2[0]->getFeSpace(); + + Mesh* mesh1 = feSpace1->getMesh(); + Mesh* mesh2 = feSpace2->getMesh(); + + DOFVector<WorldVector<double> > coords(feSpace2, "coords"); + mesh2->getDofIndexCoords(feSpace2, coords); + + ElInfo *elInfo = mesh1->createNewElInfo(); + MacroElement *oldMacro = NULL; + DimVec<double> lambda(mesh1->getDim(), NO_INIT); + + std::vector<DegreeOfFreedom> localIndices; // DOF-indices of all DOFs in trinangle + mtl::dense_vector<double> uh; // evaluation of DOFVectors at QPs + + localIndices.resize(feSpace1->getBasisFcts()->getNumber()); + uh.change_dim(mesh1->getDim()+1); + + MSG("map source-DOFVectors to target mesh...\n"); + for (DegreeOfFreedom i = 0; i < coords.getSize(); i++) { + WorldVector<double> x = coords[i]+shift;; + + bool inMesh; + if (oldMacro == NULL) + inMesh = mesh1->findElInfoAtPoint(x, elInfo, lambda, NULL, NULL, NULL); + else + inMesh = mesh1->findElInfoAtPoint(x, elInfo, lambda, oldMacro, NULL, NULL); + + // calculate values! + for (int j = 0; j < dof1.size(); j++) { + double value = fillValue; + if (inMesh) { + feSpace1->getBasisFcts()->getLocalIndices(elInfo->getElement(), feSpace1->getAdmin(), localIndices); + for (int l = 0; l < lambda.size(); l++) + uh[l] = (*dof1[j])[localIndices[l]]; + value = feSpace1->getBasisFcts()->evalUh(lambda, uh); + } + (*dof2[j])[i] = value; + } + + oldMacro = elInfo->getMacroElement(); + } +}; + +void Helpers::calcMaxOnXAxis(DOFVector<double> *rho, std::vector<std::pair<WorldVector<double>, double> > &maxima) +{ FUNCNAME("Helpers::calcMaxOnXAxis()"); + + std::vector<WorldVector<double> > x; + std::vector<double> y; + + double dimX=1.0,dimY=1.0; + Parameters::get("mesh->dimension[x]",dimX); + Parameters::get("mesh->dimension[y]",dimY); + + interpolOverLine(*rho,-dimX,0.0,dimX,0.0,1000,x,y); + if (x.size() != y.size()) + throw(std::runtime_error("x.size /= y.size! Sollte nicht passieren!")); + + if(x.size()>0) { + for(unsigned i=1; i<x.size()-1; ++i) { + if(y[i-1]<y[i] && y[i+1]<y[i]) { + maxima.push_back(std::make_pair(x[i],y[i])); + } + } + } +}; + +void Helpers::calcMaxOnYAxis(DOFVector<double> *rho, std::vector<std::pair<WorldVector<double>, double> > &maxima) +{ FUNCNAME("Helpers::calcMaxOnYAxis()"); + + std::vector<WorldVector<double> > x; + std::vector<double> y; + + double dimX,dimY; + Parameters::get("mesh->dimension[x]",dimX); + Parameters::get("mesh->dimension[y]",dimY); + + interpolOverLine(*rho,0.0,-dimY,0.0,dimY,1000,x,y); + + #ifdef HAVE_PARALLEL_DOMAIN_AMDIS + if (MPI::COMM_WORLD.Get_rank() == 0) + #endif + { + for(unsigned i=1; i<x.size()-1; ++i) { + if(y[i-1]<y[i] && y[i+1]<y[i]) { + maxima.push_back(make_pair(x[i],y[i])); + } + } + } +}; + + +void Helpers::transformMesh(Mesh *mesh, WorldVector<double> scale, WorldVector<double> shift, WorldVector<double> rotate) +{ FUNCNAME("Helpers::scaleMesh()"); + + int dow = Global::getGeo(WORLD); + mtl::dense2D<double> Rx(dow,dow),Ry(dow,dow),Rz(dow,dow),T_(dow,dow),S(dow,dow); + Rx = 1.0; + Ry = 1.0; + Rz = 1.0; + S = 1.0; + if (dow == 3) { + Rx[1][1] = cos(rotate[0]); Rx[1][2] = -sin(rotate[0]); + Rx[2][1] = sin(rotate[0]); Rx[2][2] = cos(rotate[0]); + + Ry[0][0] = cos(rotate[1]); Ry[0][2] = sin(rotate[1]); + Ry[2][0] = -sin(rotate[1]); Ry[2][2] = cos(rotate[1]); + + Rz[0][0] = cos(rotate[2]); Rz[0][1] = -sin(rotate[2]); + Rz[1][0] = sin(rotate[2]); Rz[1][1] = cos(rotate[2]); + + S[0][0] = scale[0]; S[1][1] = scale[1]; S[2][2] = scale[2]; + } else if (dow == 2) { + Rx[0][0] = cos(rotate[0]); Rx[0][1] = -sin(rotate[0]); + Rx[1][0] = sin(rotate[0]); Rx[1][1] = cos(rotate[0]); + + Ry = 1.0; + Rz = 1.0; + + S[0][0] = scale[0]; S[1][1] = scale[1]; + } else { + S[0][0] = scale[0]; + } + + T_ = Rz*Ry*Rx*S; + + WorldMatrix<double> T; + vector_operations::fillMatrix(T,T_); + + FixVec<WorldVector<double>, VERTEX> coords; + deque<MacroElement*>::iterator macro; + + for(macro = mesh->firstMacroElement(); macro != mesh->endOfMacroElements(); macro++) { + for (int i = 0; i < mesh->getDim()+1; ++i) { + WorldVector<double> x = (*macro)->getCoord(i); + WorldVector<double> x_temp = x; + x.multMatrixVec(T,x_temp); + x+= shift; + (*macro)->setCoord(i, x); + } + } +}; + +void Helpers::scaleMesh(Mesh *mesh, WorldVector<double> shift, WorldVector<double> scale) +{ FUNCNAME("Helpers::scaleMesh()"); + + deque<MacroElement*>::iterator macro; + int dim = Global::getGeo(WORLD); + + for(macro = mesh->firstMacroElement(); macro != mesh->endOfMacroElements(); macro++) { + for (int i = 0; i < mesh->getDim()+1; ++i) { + WorldVector<double> x = (*macro)->getCoord(i); + x *= scale; + x += shift; + (*macro)->setCoord(i, x); + } + } +}; + +// scale by different values in all directions +void Helpers::scaleMesh(Mesh *mesh, WorldVector<double> scale) +{ FUNCNAME("Helpers::scaleMesh()"); + + WorldVector<double> shift; shift.set(0.0); + scaleMesh(mesh,shift,scale); +} + +// scale by different values in all directions +void Helpers::scaleMesh(std::vector<Mesh*> meshes, WorldVector<double> scale) +{ FUNCNAME("Helpers::scaleMesh()"); + + WorldVector<double> shift; shift.set(0.0); + for (size_t i = 0; i < meshes.size(); i++) + scaleMesh(meshes[i],shift,scale); +} + +// scale and shift by the same values in all directions +void Helpers::scaleMesh(Mesh *mesh, double shift, double scale) +{ FUNCNAME("Helpers::scaleMesh()"); + + WorldVector<double> wShift, wScale; + wShift.set(shift); + wScale.set(scale); + scaleMesh(mesh,wShift,wScale); +} + +void Helpers::read_dof_vector(const std::string file, DOFVector<double> *dofvec, long size) +{ FUNCNAME("Helpers::read_dof_vector()"); + + ifstream in; + string buf; + long i; + + in.open(file.c_str()); + if (!in) + throw(std::runtime_error("ERROR! Could not read value file.")); + + DOFIterator<double> dofIter(dofvec, USED_DOFS); + + getline(in, buf); + while(buf.substr(0,14) != "vertex values:") getline(in, buf); + for (i = 0, dofIter.reset(); !dofIter.end(); ++i, ++dofIter){ + in >> buf; + (*dofIter) = atof(buf.c_str()); + } + in.close(); + + if (i != size) + throw(std::runtime_error("#vertices != dofIter.size()")); +} + +WorldVector<double> Helpers::getMeshDimension(Mesh *mesh) +{ FUNCNAME("Helpers::getMeshDimension()"); + + WorldVector<double> dimension; dimension.set(-1.e10); + + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, 0, Mesh::CALL_EL_LEVEL | Mesh::FILL_COORDS); + while (elInfo) { + for (int i = 0; i <= mesh->getDim(); i++) { + WorldVector<double> &coords = elInfo->getMacroElement()->getCoord(i); + for(int j = 0; j < coords.getSize(); ++j) { + dimension[j] = std::max(dimension[j], coords[j]); + } + } + elInfo = stack.traverseNext(elInfo); + } + return dimension; +} + +void Helpers::getMeshDimension(Mesh *mesh, WorldVector<double> &min_corner, WorldVector<double> &max_corner) +{ FUNCNAME("Helpers::getMeshDimension()"); + + max_corner.set(-1.e10); + min_corner.set(1.e10); + + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, 0, Mesh::CALL_EL_LEVEL | Mesh::FILL_COORDS); + while (elInfo) { + for (int i = 0; i <= mesh->getDim(); i++) { + WorldVector<double> &coords = elInfo->getMacroElement()->getCoord(i); + for(int j = 0; j < coords.getSize(); ++j) { + max_corner[j] = std::max(max_corner[j], coords[j]); + min_corner[j] = std::min(min_corner[j], coords[j]); + } + } + elInfo = stack.traverseNext(elInfo); + } +} + +void Helpers::getNormalsWeighted(FiniteElemSpace *feSpace, DOFVector<WorldVector<double> > *normals) +{ + Mesh *mesh = feSpace->getMesh(); + const BasisFunction *basisFcts = feSpace->getBasisFcts(); + int nBasisFcts = basisFcts->getNumber(); + + std::vector<DegreeOfFreedom> localIndices(nBasisFcts); + + DOFVector<double> numNormals(feSpace, "numNormals"); + numNormals.set(0.0); + + WorldVector<double> normal; normal.set(0.0); + normals->set(normal); + TraverseStack stack; + ElInfo *elInfo = + stack.traverseFirst(mesh, -1, + Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS); + + while (elInfo) { + elInfo->getElementNormal(normal); + Element *el = elInfo->getElement(); + double det = elInfo->getDet(); + if (det <= DBL_TOL) + det = elInfo->calcDet(); + + basisFcts->getLocalIndices(el, feSpace->getAdmin(), localIndices); + + for (int i = 0; i < nBasisFcts; i++) { + (*normals)[localIndices[i]] += normal*(1.0/det); + } + + elInfo = stack.traverseNext(elInfo); + } + + DOFIterator<WorldVector<double> > normalsIter(normals, USED_DOFS); normalsIter.reset(); + for (; !normalsIter.end(); normalsIter++) + { + *normalsIter *= 1.0/norm(*normalsIter); + } +} + +void Helpers::getNormals(FiniteElemSpace *feSpace, DOFVector<WorldVector<double> > *normals, DOFVector<WorldMatrix<double> > *gradNormals) +{ + using namespace mtl; + using namespace itl; + + Mesh *mesh = feSpace->getMesh(); + const BasisFunction *basisFcts = feSpace->getBasisFcts(); + int nBasisFcts = basisFcts->getNumber(); + + std::vector<DegreeOfFreedom> localIndices(nBasisFcts); + DOFVector<std::set<DegreeOfFreedom> > neighbors(feSpace, "neighbors"); + + TraverseStack stack; + ElInfo *elInfo = + stack.traverseFirst(mesh, -1, + Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS); + + while (elInfo) { + basisFcts->getLocalIndices(elInfo->getElement(), feSpace->getAdmin(), localIndices); + + for (size_t i = 0; i < nBasisFcts; i++) { + for (size_t j = 0; j < nBasisFcts; j++) { + neighbors[localIndices[i]].insert(localIndices[j]); + } + } + elInfo = stack.traverseNext(elInfo); + } + + DOFVector<WorldVector<double> > coordsDOF(feSpace, "coords"); + mesh->getDofIndexCoords(feSpace, coordsDOF); + + Helpers::getNormalsWeighted(feSpace, normals); + VtkWriter::writeFile(normals, "normals_weighted.vtu"); + +// DOFVector<WorldMatrix<double> > *grdDOF = gradNormals; +// if (grdDOF == NULL) +// grdDOF = new DOFVector<WorldMatrix<double> >(feSpace, "grd"); + + DOFIterator<WorldVector<double> > normalsIter(normals, USED_DOFS); normalsIter.reset(); + DOFIterator<WorldVector<double> > coordsIter(&coordsDOF, USED_DOFS); coordsIter.reset(); +/* DOFIterator<WorldMatrix<double> > grdIter(grdDOF, USED_DOFS); grdIter.reset();*/ + DOFIterator<std::set<DegreeOfFreedom> > neighborsIter(&neighbors, USED_DOFS); neighborsIter.reset(); + for (; !neighborsIter.end(); neighborsIter++, normalsIter++, coordsIter++/*, grdIter++*/) + { + int numPoints = 10; // 6 oder 10 + std::set<DegreeOfFreedom> idx = *neighborsIter; + std::set<DegreeOfFreedom>::iterator it, it2; + + for (int i = 1; i<3 && idx.size() < numPoints; i++) { + for (it = idx.begin(); it != idx.end() && idx.size() < numPoints; it++) { + for (it2 = (neighbors[*it]).begin(); it2 != (neighbors[*it]).end() && idx.size() < numPoints; it2++) { + idx.insert(*it2); + } + } + } + TEST_EXIT(idx.size()>=numPoints)("Nicht genügend Stützstellen gefunden!\n"); + size_t i = 0; + mtl::dense2D<double> A(numPoints,6), B(6,6); + mtl::dense_vector<double> b(numPoints, 1.0), c(6), y(6, 1.0); + + for (it = idx.begin(); it != idx.end() && i < numPoints; it++, i++) { + WorldVector<double> x = coordsDOF[*it]; + A[i][0] = sqr(x[0]); A[i][1] = sqr(x[1]); A[i][2] = sqr(x[2]); + A[i][3] = x[0]*x[1]; A[i][4] = x[0]*x[2]; A[i][5] = x[1]*x[2]; +// if(numPoints>6) +// A[i][6] = x[0]; A[i][7] = x[1]; A[i][8] = x[2]; A[i][9] = 1.0; + } + c = trans(A)*b; + B = trans(A)*A; +// pc::ilu_0<mtl::dense2D<double> > P(B); +// basic_iteration<double> iter(c, 100, 1.e-6); + +// Solve Ax == b with left preconditioner P +// bicgstab(B, y, c, P, iter); + + y = mtl::matrix::lu_solve(B,c); + + WorldVector<double> oldNormal = (*normalsIter); + + (*normalsIter)[0] = 2.0*y[0]*(*coordsIter)[0] + y[3]*(*coordsIter)[1] + y[4]*(*coordsIter)[2]/* + (numPoints==10?y[6]:0.0)*/; + (*normalsIter)[1] = 2.0*y[1]*(*coordsIter)[1] + y[3]*(*coordsIter)[0] + y[5]*(*coordsIter)[2]/* + (numPoints==10?y[7]:0.0)*/; + (*normalsIter)[2] = 2.0*y[2]*(*coordsIter)[2] + y[4]*(*coordsIter)[0] + y[5]*(*coordsIter)[1]/* + (numPoints==10?y[8]:0.0)*/; + + double nrm = norm(*normalsIter); + double diff = norm(oldNormal - *normalsIter); + double signFactor = 1.0; + if (diff > nrm) + signFactor = -1.0; + *normalsIter *= signFactor/nrm; + +// if(gradNormals != NULL) { +// WorldMatrix<double> grad; +// grad[0][0] = 2.0*y[0]; grad[0][1] = y[3]; grad[0][2] = y[4]; +// grad[1][0] = y[3]; grad[1][1] = 2.0*y[1]; grad[1][2] = y[5]; +// grad[2][0] = y[4]; grad[2][1] = y[5]; grad[2][2] = 2.0*y[2]; +// grad *= signFactor; +// +// double trace_ = 0.0; +// for (int i=0;i<3;i++) +// trace_ += (grad[i][i]/nrm-sqr((*normalsIter)[i])); +// std::cout<<"nrm(n)="<<nrm<<std::endl; +// std::cout<<"trace(grad(n))="<<vector_operations::trace(grad)/nrm<<"="<<trace_<<std::endl; +// +// WorldMatrix<double> NN; +// NN.vecProduct(*normalsIter, *normalsIter); +// +// grad -= NN; +// grad *= 1.0/nrm; +// +// *grdIter = grad; +// +// } + } + +// if(gradNormals == NULL) +// delete grdDOF; +} + +void Helpers::getCurvature(DOFVector<WorldVector<double> >* normals,DOFVector<double>* curvature) +{ + int dim = normals->getFeSpace()->getMesh()->getDim(); + int dow = Global::getGeo(WORLD); + + WorldVector<DOFVector<double>*> normalsVec; + WorldVector<DOFVector<WorldVector<double> >*> gradNormals; + for (int i = 0; i < dow; i++) { + normalsVec[i] = new DOFVector<double>(normals->getFeSpace(), "n_i"); + gradNormals[i] = new DOFVector<WorldVector<double> >(normals->getFeSpace(), "grad_i"); + } + transform(normals, &normalsVec); + for (int i = 0; i < dow; i++) + normalsVec[i]->getRecoveryGradient(gradNormals[i]); + + DOFIterator<WorldVector<double> > grd0Iter(gradNormals[0], USED_DOFS); grd0Iter.reset(); + DOFIterator<WorldVector<double> > grd1Iter(gradNormals[1], USED_DOFS); grd1Iter.reset(); + DOFIterator<WorldVector<double> > grd2Iter(gradNormals[2], USED_DOFS); grd2Iter.reset(); + DOFIterator<double> hIter(curvature, USED_DOFS); hIter.reset(); + + for (; !grd0Iter.end(); grd0Iter++,grd1Iter++,grd2Iter++,hIter++) + { + *hIter = ((*grd0Iter)[0] + (*grd1Iter)[1] + (*grd2Iter)[2])/static_cast<double>(dim); + } + + for (int i = 0; i < dow; i++) { + delete normalsVec[i]; + delete gradNormals[i]; + } +} + +void Helpers::process_mem_usage(double& vm_usage, double& resident_set) +{ + using std::ios_base; + using std::ifstream; + using std::string; + + vm_usage = 0.0; + resident_set = 0.0; + + // 'file' stat seems to give the most reliable results + // + ifstream stat_stream("/proc/self/stat",ios_base::in); + + // dummy vars for leading entries in stat that we don't care about + // + string pid, comm, state, ppid, pgrp, session, tty_nr; + string tpgid, flags, minflt, cminflt, majflt, cmajflt; + string utime, stime, cutime, cstime, priority, nice; + string O, itrealvalue, starttime; + + // the two fields we want + // + unsigned long vsize; + long rss; + + stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr + >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt + >> utime >> stime >> cutime >> cstime >> priority >> nice + >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest + + long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages + vm_usage = vsize / 1024.0; + resident_set = rss * page_size_kb; +} + +// plots a vector with ascii-code +void Helpers::plot(std::vector<double> &values, int numRows, int numCols, std::string symbol) +{ + unsigned num=values.size(); + unsigned cols=std::min(numCols,(int)num), rows=std::min(numRows,(int)num); + unsigned step=(unsigned)floor(num/(double)cols); + cols=(unsigned)ceil(num/(double)step); + + double maxVal=*max_element(values.begin(),values.end()); + double minVal=*min_element(values.begin(),values.end()); + std::stringstream ssMax; ssMax.setf(std::ios::fixed,std::ios::floatfield); ssMax.precision(2); ssMax<<maxVal; + std::stringstream ssMin; ssMin.setf(std::ios::fixed,std::ios::floatfield); ssMin.precision(2); ssMin<<minVal; + unsigned cols0 = std::max(ssMax.str().length(),ssMin.str().length()); + std::stringstream ssNum; ssNum<<num; + + std::string emptyLine(cols+cols0,' ');emptyLine.replace(cols0-1,1,"|"); + std::vector<std::string> lines(rows+1,emptyLine); + + double range=maxVal-minVal; + + for(unsigned i=0;i<cols; i+=1) { + int v=(int)round((rows-1)*(values[i*step]-minVal)/range,0); + int r=rows-v-1, c=i+cols0; + + lines[r].replace(c,1,symbol); + lines[rows].replace(c,1,"-"); + } + + lines[0].replace(cols0-ssMax.str().length(),ssMax.str().length(),ssMax.str()); + lines[rows-1].replace(cols0-ssMin.str().length(),ssMin.str().length(),ssMin.str()); + lines[rows].replace(cols0-1,2," 0"); + lines[rows].erase(cols+cols0-1,1); + lines[rows].append(ssNum.str()); + + for(unsigned i=0;i<lines.size(); ++i) + std::cout<<lines[i]<<std::endl; +} diff --git a/extensions/Helpers.h b/extensions/Helpers.h new file mode 100644 index 0000000000000000000000000000000000000000..f65b55eff1eb6fa1735d8156f24dc17119ea8a21 --- /dev/null +++ b/extensions/Helpers.h @@ -0,0 +1,390 @@ +/** \file Helpers.h */ + +#ifndef MY_HELPERS_H +#define MY_HELPERS_H + +#include "AMDiS.h" + +#if HAVE_PARALLEL_DOMAIN_AMDIS +#include "parallel/StdMpi.h" +#endif + +#include <unistd.h> +#include <ios> +#include <iostream> +#include <fstream> +#include <string> +#include <boost/numeric/mtl/mtl.hpp> +#include <boost/numeric/itl/itl.hpp> +#include "boost/lexical_cast.hpp" +#include "boost/date_time/posix_time/posix_time.hpp" +#include <time.h> +#include <stdarg.h> + +#include "VectorOperations.h" + +#define TEST_WARNING(test) if ((test));else WARNING + +using namespace std; +using namespace AMDiS; + +static long random_seed_initial_value=0; + +class Helpers { +public: + + /// math routines + /// ============== + + static double cint(double x){ + double intpart; + if (modf(x,&intpart)>=.5) + return x>=0?ceil(x):floor(x); + else + return x<0?ceil(x):floor(x); + } + + static double round(double r, double places){ + double off= pow(10.0, places); + return cint(r*off)/off; + } + + static bool isNumber(double val) { return !isnan(val) && !isinf(val); }; + static double signum(double val, double tol=1.e-10) { return (val>tol?1.0:(val<-tol?-1.0:0.0)); } + static int signum(int val) { return (val>0?1:(val<0?-1:0)); } + static int signum(bool val) { return (val?1:-1); } + static int toInt(bool val) { return (val?1:0); } + + /// routines for conversion to string + /// ================================= + + template<typename T> + static std::string toString(const T &value, ios_base::fmtflags flag= ios_base::scientific) + { + std::stringstream ss; + ss.setf(flag); + ss.precision(6); + if (!(ss<<value)) + throw(std::runtime_error("toString() not possible")); + return ss.str(); + }; + + static std::string toString(const int &value) + { + return boost::lexical_cast<std::string>(value); + }; + + template<typename T> + static std::string toString(const WorldVector<T> &value, bool brackets= true, ios_base::fmtflags flag= ios_base::scientific) + { + std::stringstream ss; + if (brackets) ss<<"["; + ss.setf(flag); + ss.precision(6); + if (!(ss<<value)) + throw(std::runtime_error("toString() not possible")); + + if (brackets) ss<<"]"; + return ss.str(); + }; + + template<typename T> + static std::string toString(const std::vector<T> &vec, bool brackets= true, ios_base::fmtflags flag= ios_base::scientific) + { + std::stringstream ss; + if (brackets) ss<<"["; + ss.setf(flag); + ss.precision(6); + for (size_t i = 0; i < vec.size(); ++i) { + if (!(ss<<(i>0?", ":"")<<vec[i])) + throw(std::runtime_error("toString() not possible")); + } + if (brackets) ss<<"]"; + return ss.str(); + }; + + template<class T> + static T fromString(const std::string& s) + { + std::istringstream stream(s); + T t; + stream >> t; + return t; + }; + + static std::string fillString(int length, char c, int numValues, ...) + { + va_list values; + int value; + va_start(values, numValues); + + int len = length; + for(int i=0; i<numValues; i++) { + value = va_arg(values, int); + double tmp = static_cast<double>(value); + while (true) { + len --; + tmp /= 10.0; + if (tmp < 1.0 - DBL_TOL) + break; + } + } + va_end(values); + + return std::string(len, c); + }; + + // process printable string of memory + static std::string memoryToString(double mem, int startIdx=0) { + int idx = startIdx; + double mem_ = mem; + while (mem_/1024.0 > 1.0) { + mem_ /= 1024.0; + idx++; + } + std::string result = toString(mem_)+" "+(idx==0?"B":(idx==1?"KB":(idx==2?"MB":"GB"))); + return result; + }; + + + /// some mesh routines + /// =========================== + + static void transformMesh(Mesh *mesh, WorldVector<double> scale, WorldVector<double> shift, WorldVector<double> rotate); + + static void scaleMesh(std::vector<Mesh*> meshes, WorldVector<double> scale); + // scale and shift by different values in all directions + static void scaleMesh(Mesh *mesh, WorldVector<double> shift, WorldVector<double> scale); + // scale by different values in all directions + static void scaleMesh(Mesh *mesh, WorldVector<double> scale); + // scale and shift by the same values in all directions + static void scaleMesh(Mesh *mesh, double shift=0.0, double scale=1.0); + + /// calculate the dimension of a mesh + static WorldVector<double> getMeshDimension(Mesh *mesh); + static void getMeshDimension(Mesh *mesh, WorldVector<double> &min_corner, WorldVector<double> &max_corner); + + /// read DOFVector from AMDiS .dat-files + static void read_dof_vector(const std::string file, DOFVector<double> *dofvec, long size); + + /// copy DOFVectors that live on different meshes + static void copyDOF(std::vector<DOFVector<double>*> dof1, std::vector<DOFVector<double>*> dof2, WorldVector<double> shift, double fillValue = 0.0); + + static void copyDOF(DOFVector<double>* dof1, DOFVector<double>* dof2) { + WorldVector<double> shift; shift.set(0.0); + std::vector<DOFVector<double>*> dof1Vec; dof1Vec.push_back(dof1); + std::vector<DOFVector<double>*> dof2Vec; dof2Vec.push_back(dof2); + copyDOF(dof1Vec, dof2Vec, shift); + }; + + /// some linear algebra methods + /// =========================== + + static double determinant(mtl::dense2D<double> &A) // only for 3x3 - matrices + { + if(num_rows(A)==3 && num_cols(A)==3) { + double det = A(0,0)*A(1,1)*A(2,2)+A(0,1)*A(1,2)*A(2,0)+A(0,2)*A(1,0)*A(2,1); + return det-(A(0,2)*A(1,1)*A(2,0)+A(0,1)*A(1,0)*A(2,2)+A(0,0)*A(1,2)*A(2,1)); + } + return 1.0; + }; + + static double determinant(WorldMatrix<double> &A) // only for 3x3 - matrices + { + if(A.getNumRows()==3 && A.getNumCols()==3) { + double det = A[0][0]*A[1][1]*A[2][2]+A[0][1]*A[1][2]*A[2][0]+A[0][2]*A[1][0]*A[2][1]; + return det-(A[0][2]*A[1][1]*A[2][0]+A[0][1]*A[1][0]*A[2][2]+A[0][0]*A[1][2]*A[2][1]); + } + return 1.0; + }; + + /// inverse power method to find minimal eigenvalue of matrix A and appropriate eigenvector x, using m iterations + template <class LinearSolver, class Matrix, class EigenVector> + static double inverse_iteration(LinearSolver& solver, const Matrix& A, EigenVector& x, int m) + { FUNCNAME("Helpers::inverse_iteration()"); + + EigenVector y( size(x) ), res( size(x) ); + double lambda = 0.0, lambda_old = 0.0, relErr; + mtl::seed<double> seed; + random(x, seed); + x /= two_norm(x); + + solver.setMultipleRhs(true); + for (int i = 0; i < m; ++i) { + solver.solveSystem(A, y, x ); // solve Ay=x --> y + lambda_old=lambda; + lambda = dot(y,x)/dot(y,y); + relErr = abs((lambda-lambda_old)/lambda); + if(relErr<1.e-5) break; + x = y / two_norm(y); + } + solver.setMultipleRhs(false); + + return lambda ; + }; + + /// calculate approximation to condition number of matrix A using the OEMSolver solver + template <class LinearSolver, class Matrix> + static double condition(LinearSolver& solver, const Matrix& A, int m=10) + { FUNCNAME("Helpers::condition()"); + + mtl::dense_vector<double> x(num_rows(A)), y(num_rows(A)); + mtl::seed<double> seed; + random(x, seed); + + double lambda = 0.0, lambda_old = 0.0, relErr, result1; + x /= two_norm(x); + for (int i = 0; i < m; ++i) { + y = A * x; + lambda_old=lambda; + lambda = mtl::dot(y,x); + relErr = abs((lambda-lambda_old)/lambda); + if(relErr<1.e-5) break; + x = y / two_norm(y) ; + } + result1 = std::abs(lambda / inverse_iteration(solver, A, x, m)); + return result1; + }; + + /// interpolate values of DOFVector along line from (x1,y1) -> (x2,y1) with nPoints points + template<typename Container> + static void interpolOverLine(const Container &vec, + double x1, double y1, double x2, double y2, + int nPoints, + std::vector<WorldVector<double> > &x, std::vector<double> &y); + + /// calculate maxima of DOFVector along line, using interpolOverLine + static void calcMaxOnXAxis(DOFVector<double> *rho, std::vector<std::pair<WorldVector<double>, double> > &maxima); + static void calcMaxOnYAxis(DOFVector<double> *rho, std::vector<std::pair<WorldVector<double>, double> > &maxima); + + /// calc normal vectors of surface from element normals by averaging + static void getNormalsWeighted(FiniteElemSpace *feSpace, DOFVector<WorldVector<double> > *normals); + + /// calc normal vectors of surface from element normals by local approximation by quartic + static void getNormals(FiniteElemSpace *feSpace, DOFVector<WorldVector<double> > *normals, DOFVector<WorldMatrix<double> > *gradNormals = NULL); + + /// calc curvature from given normal vectors + static void getCurvature(DOFVector<WorldVector<double> >* normals, DOFVector<double>* curvature); + + /// misc routines + /// ============= + + static void plot(std::vector<double> &values, int numRows=7, int numCols=20, std::string symbol="*"); + + // process_mem_usage(double &, double &) - takes two doubles by reference, + // attempts to read the system-dependent data for a process' virtual memory + // size and resident set size, and return the results in KB. + // + // On failure, returns 0.0, 0.0 + static void process_mem_usage(double& vm_usage, double& resident_set); + + static long getMicroTimestamp() { + using namespace boost::posix_time; + ptime t0(min_date_time); + ptime now = microsec_clock::local_time(); + time_duration td = now-t0; + return td.total_microseconds(); + }; + + static long getRandomSeed(int param=0) { + using namespace boost::posix_time; + ptime t0(min_date_time); + ptime now = microsec_clock::local_time(); + time_duration td = now-t0; + long value0 = td.total_microseconds(); + long value1 = clock(); + long value2 = random_seed_initial_value++; + + return value0+value1+value2+param; + }; +}; + + + +/** \ingroup DOFAdministration + * \brief + * Implements a DOFIterator for a DOFIndexed<T> object + */ +template<typename T> +class DOFConstIterator : public DOFIteratorBase +{ +public: + /// Constructs a DOFIterator for cont of type t + DOFConstIterator(const DOFIndexed<T> *obj, DOFIteratorType t) + : DOFIteratorBase(dynamic_cast<DOFAdmin*>(obj->getFeSpace()->getAdmin()), t), + iteratedObject(obj) + {} + + /// Constructs a DOFIterator for cont of type t + DOFConstIterator(DOFAdmin *admin, + const DOFIndexed<T> *obj, + DOFIteratorType t) + : DOFIteratorBase(admin, t), + iteratedObject(obj) + {} + + /// Dereference operator + inline const T& operator*() + { + return *it; + } + + /// Dereference operator + inline const T* operator->() + { + return &(*it); + } + + inline bool operator!=(const DOFIterator<T>& rhs) + { + if (this->iteratedObject != rhs.iteratedObject) + return true; + + if (this->it != rhs.it) + return true; + + return false; + } + + inline bool operator==(const DOFIterator<T>& rhs) + { + return !(this->operator==(rhs)); + } + +protected: + /// Implementation of DOFIteratorBase::goToBeginOfIteratedObject() + inline void goToBeginOfIteratedObject() + { + it = iteratedObject->begin(); + } + + /// Implementation of DOFIteratorBase::goToEndOfIteratedObject() + inline void goToEndOfIteratedObject() + { + it = iteratedObject->end(); + } + + /// Implementation of DOFIteratorBase::incObjectIterator() + inline void incObjectIterator() + { + ++it; + } + + /// Implementation of DOFIteratorBase::incObjectIterator() + inline void decObjectIterator() + { + --it; + } + +protected: + /// Object that is iterated + const DOFIndexed<T> *iteratedObject; + + /// Iterator for \ref iteratedObject + typename std::vector<T>::const_iterator it; +}; + +#include "Helpers.hh" + + +#endif diff --git a/extensions/Helpers.hh b/extensions/Helpers.hh new file mode 100644 index 0000000000000000000000000000000000000000..72a94805b4f1f89bc560e8834716d2e8704b8e37 --- /dev/null +++ b/extensions/Helpers.hh @@ -0,0 +1,26 @@ + +#include "Views.h" + +template<typename Container> +void Helpers::interpolOverLine(const Container &vec, + double x1, double y1, double x2, double y2, + int nPoints, + std::vector<WorldVector<double> > &x, std::vector<double> &y) +{ FUNCNAME("Helpers::interpolOverLine()"); + + WorldVector<double> p; + bool inside; + + if (nPoints <= 1) + throw(std::runtime_error("Zu wenig Punkte fuer eine Interpolation!")); + + for (int i = 0; i < nPoints; ++i) { + double lambda = static_cast<double>(i)/static_cast<double>(nPoints - 1.0); + p[0] = lambda*x2 + (1.0-lambda)*x1; + p[1] = lambda*y2 + (1.0-lambda)*y1; + + double value = vec.evalAtPoint(p); + x.push_back(p); + y.push_back(value); + } +}; diff --git a/extensions/MeshFunction_Level.h b/extensions/MeshFunction_Level.h new file mode 100644 index 0000000000000000000000000000000000000000..71eb8feb15ab432ddac2afc0d47befd899cb94b2 --- /dev/null +++ b/extensions/MeshFunction_Level.h @@ -0,0 +1,326 @@ +/** \file MeshFunction_Level.h */ + +#ifndef MESH_FUNCTION_LEVEL_H +#define MESH_FUNCTION_LEVEL_H + +using namespace AMDiS; + + +/** \brief + * Base-Implementation of a MeshRefinementFunction for refinement of phase-field + * interfaces. operator() must be overwritten in subclasses. Class provides + * basic parameters for the refinement like refinement-level values on interface + * or in the interesting domain and defines the refinement range for the phase- + * field variable, i.e. interface is defined in [0.05, 0.95] + **/ +template<typename T> +class PhaseFieldRefinementBase : public MeshRefinementFunction<T, int> +{ +public: + + PhaseFieldRefinementBase(Mesh *mesh) : + MeshRefinementFunction<T, int>(mesh), + lInner(10), + lOuter(10), + lInterface(14), + minPhase(0.05), + maxPhase(0.95), + minOuterPhase(0.001), + maxOuterPhase(0.999) + { + Parameters::get("mesh->refinement->level in inner domain",lInner); + Parameters::get("mesh->refinement->level in outer domain",lOuter); + Parameters::get("mesh->refinement->level on interface",lInterface); + + lInterface-= mesh->getMacroElementLevel(); + lInner-= mesh->getMacroElementLevel(); + lOuter-= mesh->getMacroElementLevel(); + + int local_globalSize = 10; + Parameters::get("mesh->refinement->initial level", local_globalSize); + MeshRefinementFunction<T, int>::globalSize = local_globalSize; + + Parameters::get("mesh->refinement->min interface value",minPhase); + Parameters::get("mesh->refinement->max interface value",maxPhase); + Parameters::get("mesh->refinement->min outer interface value",minOuterPhase); + Parameters::get("mesh->refinement->max outer interface value",maxOuterPhase); + } + + double meshSize() { return levelToH(MeshRefinementFunction<T, int>::globalSize); } + +protected: + + int lInner; + int lOuter; + int lInterface; + + double minPhase; + double maxPhase; + double minOuterPhase; + double maxOuterPhase; +}; + + +/** \brief + * Implementation of PhaseFieldRefinementBase. Provides the method operator() + * that defines the regions for interface refinement and domain refinement, etc. + **/ +class PhaseFieldRefinement : public PhaseFieldRefinementBase<double> +{ +public: + + PhaseFieldRefinement(Mesh* mesh_) : PhaseFieldRefinementBase<double>(mesh_) {}; + + int operator()(const double& phase) const { + int result= lOuter; + if (minPhase < phase && phase < maxPhase) + result= lInterface; // auf dem Interface + else if (phase > minOuterPhase && phase <= minPhase) + result= std::max(lOuter, static_cast<int>(floor((lOuter+lInterface)/2.0))); + else if (phase < maxOuterPhase && phase >= maxPhase) + result= std::max(lInner, static_cast<int>(floor((lInner+lInterface)/2.0))); + else if (phase > (minPhase+maxPhase)/2.0) + result= lInner; + return result; + } +}; + + +/** \brief + * Implementation of PhaseFieldRefinementBase. Provides the method operator() + * that defines the regions for interface refinement and domain refinement, etc. + * Additionally to the phase-field value a list of refinement points can be given + * where the mesh should be refined up to the a given level, e.g. in corners of + * the macro-mesh. + **/ +class PhaseFieldCoordsRefinement : public PhaseFieldRefinementBase< std::pair<WorldVector<double>, double> > +{ +public: + PhaseFieldCoordsRefinement(Mesh* mesh_, std::vector<WorldVector<double> > points_, double radius_) : + PhaseFieldRefinementBase< std::pair<WorldVector<double>, double> >(mesh_), + points(points_), + radius(radius_), + lPoints(14) + { + Parameters::get("mesh->refinement->level on points",lPoints); + lPoints-= mesh->getMacroElementLevel(); + } + + int operator()(const std::pair<WorldVector<double>, double>& data) const { + double phase = data.second; + int result= lOuter; + if (minPhase < phase && phase < maxPhase) + result = lInterface; // auf dem Interface + else if ((phase > minOuterPhase && phase <= minPhase) || (phase < maxOuterPhase && phase >= maxPhase)) + result = std::max(lInner, static_cast<int>(floor((lOuter+lInterface)/2.0))); + else if (phase > 0.5) + result = lInner; + + WorldVector<double> x = data.first; + double minDist = 1.e15; + for (unsigned i = 0; i < points.size(); ++i) { + minDist = std::min(minDist, norm(points[i]-x)); + } + double lambda = std::max(0.0, 1.0 - minDist/radius); + result = std::max(result, static_cast<int>(floor(lOuter+lambda*(lPoints-lOuter)))); + + return result; + } + +private: + + int lPoints; + + std::vector<WorldVector<double> > points; + + double radius; +}; + + +/** \brief + * Implementation of MeshRefinementFunction. Provides the method operator() + * that defines a list of refinement points where the mesh should be refined + * up to the a given level, e.g. in corners of the macro-mesh. + **/ +class CoordsRefinement : public MeshRefinementFunction< WorldVector<double>, int > +{ +public: + CoordsRefinement(Mesh* mesh_, std::vector<WorldVector<double> > points_, double radius_) + : + MeshRefinementFunction< WorldVector<double>, int >(mesh_), + points(points_), + radius(radius_) + { + lInner= 15; lPoints = 20; + Parameters::get("mesh->refinement->level on points",lPoints); + Parameters::get("mesh->refinement->level in inner domain",lInner); + lPoints-= mesh->getMacroElementLevel(); + lInner-= mesh->getMacroElementLevel(); + + globalSize= lInner; + } + + int operator()(const WorldVector<double>& x) const { + double minDist = 1.e15; + for (unsigned i = 0; i < points.size(); ++i) { + minDist = std::min(minDist, norm(points[i]-x)); + } + int result = lInner; + double lambda = std::max(0.0, 1.0 - minDist/radius); + result = std::max(result, static_cast<int>(floor(lInner+lambda*(lPoints-lInner)))); + + return result; + } + double meshSize() { return levelToH(lInner); } + +private: + int lInner, lPoints; + std::vector<WorldVector<double> > points; + double radius; +}; + + +/** \brief + * Implementation of PhaseFieldRefinementBase. Provides the method operator() + * that defines the level of refinement depending on a list of phase-fields, e.g. + * a diffuse-domain representation and a Cahn-Hilliard field. + **/ +class PhaseFieldChRefinement : public PhaseFieldRefinementBase< std::vector<double> > +{ +public: + PhaseFieldChRefinement(Mesh* mesh_) + : + PhaseFieldRefinementBase< std::vector<double> >(mesh_), + lInterfaceDomain(14) + { + Parameters::get("mesh->refinement->level on domain interface",lInterfaceDomain); + lInterfaceDomain-= mesh->getMacroElementLevel(); + + Parameters::get("mesh->refinement->initial level", globalSize); + } + + int operator()(const std::vector<double>& phases) const + { + int result= lOuter; + for (unsigned i = 0; i < phases.size(); ++i) { + int localResult= lOuter; + if (minPhase < phases[i] && phases[i] < maxPhase + && (i < 1 || phases[i-1] > 0.5)) + localResult= (i==0 ? lInterfaceDomain : lInterface); // auf dem Interface + else if (phases[i] > 0.5 + && (i < 1 || phases[i-1] > 0.5)) + localResult= lInner; // im Innern des Gebietes + if (((phases[i] > minOuterPhase && phases[i] <= minPhase) || (phases[i] < maxOuterPhase && phases[i] >= maxPhase)) + && (i < 1 || phases[i-1] > 0.5)) + localResult= static_cast<int>(floor((lInner + lInterface) / 2.0)); + result= std::max(result, localResult); + } + return result; + } + +private: + + int lInterfaceDomain; +}; + + +/** \brief + * Base-Implementation of a MeshRefinementFunction for refinement of phase-field + * interfaces. operator() must be overwritten in subclasses. Class provides + * basic parameters for the refinement like refinement-level values on interface + * or in the interesting domain and defines the refinement range for the phase- + * field variable, i.e. interface is defined in [0.05, 0.95] + **/ +template<typename T> +class SignedDistRefinementBase : public MeshRefinementFunction<T, int> +{ +public: + + SignedDistRefinementBase(Mesh *mesh) : + MeshRefinementFunction<T, int>(mesh), + lInner(10), + lOuter(10), + lInterface(14), + interfaceWidth(0.2), + fadeOutWidth(0.0), + signInInnerDomain(-1.0) + { + Parameters::get("mesh->refinement->level in inner domain",lInner); + Parameters::get("mesh->refinement->level in outer domain",lOuter); + Parameters::get("mesh->refinement->level on interface",lInterface); + + lInterface-= mesh->getMacroElementLevel(); + lInner-= mesh->getMacroElementLevel(); + lOuter-= mesh->getMacroElementLevel(); + + int local_globalSize = 10; + Parameters::get("mesh->refinement->initial level", local_globalSize); + MeshRefinementFunction<T, int>::globalSize = local_globalSize; + + Parameters::get("mesh->refinement->interface width",interfaceWidth); + Parameters::get("mesh->refinement->fade out width",fadeOutWidth); + Parameters::get("mesh->refinement->sign in inner domain",signInInnerDomain); + } + + double meshSize() { return levelToH(MeshRefinementFunction<T, int>::globalSize); } + +protected: + + int lInner; + int lOuter; + int lInterface; + + double interfaceWidth; + double fadeOutWidth; + double signInInnerDomain; +}; + + +/** \brief + * Implementation of PhaseFieldRefinementBase. Provides the method operator() + * that defines the regions for interface refinement and domain refinement, etc. + **/ +class SignedDistRefinement : public SignedDistRefinementBase<double> +{ +public: + + SignedDistRefinement(Mesh* mesh_) : SignedDistRefinementBase<double>(mesh_) {}; + + int operator()(const double& dist) const { + int result= lOuter; + if (abs(dist) < interfaceWidth) + result= lInterface; // auf dem Interface + else if (abs(dist) < fadeOutWidth+interfaceWidth && signInInnerDomain*dist < 0.0) { + double lambda = abs(dist)/fadeOutWidth - interfaceWidth/fadeOutWidth; + result= static_cast<int>(floor(lambda*lInner+(1.0-lambda)*lInterface)); + } else if (abs(dist) < fadeOutWidth+interfaceWidth && signInInnerDomain*dist > 0.0) { + double lambda = abs(dist)/fadeOutWidth - interfaceWidth/fadeOutWidth; + result= static_cast<int>(floor(lambda*lOuter+(1.0-lambda)*lInterface)); + } else if (signInInnerDomain*dist < 0.0) + result= lInner; + return result; + } +}; + +class ESIndicator : public MeshRefinementFunction< std::vector<double>, int > +{ +public: + ESIndicator(Mesh* mesh_) + : + MeshRefinementFunction< std::vector<double>, int >(mesh_) + { + Parameters::get("mesh->refinement->initial level", globalSize); + } + + int operator()(const std::vector<double>& means) const + { + double tol = means[0]; + return (abs(means[1]-means[2]) > tol ? 0 : -1); + } + + double indicator(const std::vector<double>& means) const + { + return abs(means[1]-means[2]); + } +}; +#endif // MESH_FUNCTION_LEVEL diff --git a/extensions/MeshIndicator.h b/extensions/MeshIndicator.h new file mode 100644 index 0000000000000000000000000000000000000000..6b3e86522c3111bf50329bdafeb2ac10171b534d --- /dev/null +++ b/extensions/MeshIndicator.h @@ -0,0 +1,369 @@ +/** \file MeshIndicator.h */ + +#ifndef MESH_INDICATOR_H +#define MESH_INDICATOR_H + +#include "AMDiS.h" + +using namespace AMDiS; + +namespace tools { + + struct MeshIndicator + { + MeshIndicator(WorldVector<double> dimension_) : boundary_index(0), dimension(dimension_) { } + + MeshIndicator(Mesh* mesh) : boundary_index(0) + { + dimension = Helpers::getMeshDimension(mesh); + } + + virtual bool operator()(const WorldVector<double>& x) const + { + return true; + } + + virtual bool operator()(const ElInfo* elInfo) const + { + bool result = true; + for (int i = 0; i < elInfo->getMesh()->getDim()+1; i++) { + result = result && operator()(elInfo->getCoord(i)); + if (!result) + break; + } + return true; + } + + void set_boundary_index(int boundary_index_) + { + boundary_index = boundary_index_; + } + + protected: + + bool on_boundary() + { + return boundary_index != 0; + } + + protected: + + int boundary_index; + WorldVector<double> dimension; + }; + + + template<typename T> + T integrate(const DOFVector<T> &vec, MeshIndicator *meshIndicator) + { + FUNCNAME("integrate(MeshIndicator)"); + + TEST_EXIT(meshIndicator)("No MeshIndicator defined!\n"); + + int deg = 2 * vec.getFeSpace()->getBasisFcts()->getDegree(); + Quadrature* quad = + Quadrature::provideQuadrature(vec.getFeSpace()->getMesh()->getDim(), deg); + FastQuadrature *fastQuad = + FastQuadrature::provideFastQuadrature(vec.getFeSpace()->getBasisFcts(), *quad, INIT_PHI); + + mtl::dense_vector<T> qp(fastQuad->getNumPoints()); + + T value; nullify(value); + + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(vec.getFeSpace()->getMesh(), -1, traverseFlag); + while (elInfo) { + if ((*meshIndicator)(elInfo)) { + vec.getVecAtQPs(elInfo, quad, fastQuad, qp); + T tmp; nullify(tmp); + for (int iq = 0; iq < fastQuad->getNumPoints(); iq++) { + tmp += fastQuad->getWeight(iq) * qp[iq]; + } + value += tmp * elInfo->getDet(); + } + elInfo = stack.traverseNext(elInfo); + } + + #ifdef HAVE_PARALLEL_DOMAIN_AMDIS + mpi::globalAdd(value); + #endif + + return value; + } + + + template<typename TOut> + TOut integrate_Coords(const FiniteElemSpace* feSpace, + AbstractFunction<TOut, WorldVector<double> > *fct, MeshIndicator *meshIndicator) + { + FUNCNAME("integrate_Coords()"); + + TEST_EXIT(fct)("No function defined!\n"); + TEST_EXIT(meshIndicator)("No MeshIndicator defined!\n"); + + int deg = std::max(fct->getDegree(), feSpace->getBasisFcts()->getDegree()); + Quadrature* quad = + Quadrature::provideQuadrature(feSpace->getMesh()->getDim(), deg); + FastQuadrature *fastQuad = + FastQuadrature::provideFastQuadrature(feSpace->getBasisFcts(), *quad, INIT_PHI); + + WorldVector<double> coords; + + TOut value; nullify(value); + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(feSpace->getMesh(), -1, traverseFlag); + while (elInfo) { + if ((*meshIndicator)(elInfo)) { + TOut tmp; nullify(tmp); + for (int iq = 0; iq < fastQuad->getNumPoints(); iq++) { + elInfo->coordToWorld(fastQuad->getLambda(iq), coords); + tmp += fastQuad->getWeight(iq) * (*fct)(coords); + } + + value += tmp * elInfo->getDet(); + } + elInfo = stack.traverseNext(elInfo); + } + + #ifdef HAVE_PARALLEL_DOMAIN_AMDIS + mpi::globalAdd(value); + #endif + + return value; + } + + template<typename TOut, typename T> + TOut integrate_Vec(const DOFVector<T> &vec, AbstractFunction<TOut, T> *fct, MeshIndicator *meshIndicator) + { + FUNCNAME("integrate(MeshIndicator)"); + + TEST_EXIT(fct)("No function defined!\n"); + TEST_EXIT(meshIndicator)("No MeshIndicator defined!\n"); + + int deg = std::max(fct->getDegree(), + 2 * vec.getFeSpace()->getBasisFcts()->getDegree()); + + Quadrature* quad = + Quadrature::provideQuadrature(vec.getFeSpace()->getMesh()->getDim(), deg); + FastQuadrature *fastQuad = + FastQuadrature::provideFastQuadrature(vec.getFeSpace()->getBasisFcts(), *quad, INIT_PHI); + + mtl::dense_vector<T> qp(fastQuad->getNumPoints()); + + TOut value; nullify(value); + + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(vec.getFeSpace()->getMesh(), -1, traverseFlag); + while (elInfo) { + if ((*meshIndicator)(elInfo)) { + vec.getVecAtQPs(elInfo, quad, fastQuad, qp); + TOut tmp; nullify(tmp); + for (int iq = 0; iq < fastQuad->getNumPoints(); iq++) { + tmp += fastQuad->getWeight(iq) * (*fct)(qp[iq]); + } + value += tmp * elInfo->getDet(); + } + elInfo = stack.traverseNext(elInfo); + } + + #ifdef HAVE_PARALLEL_DOMAIN_AMDIS + mpi::globalAdd(value); + #endif + + return value; + } + + + template<typename TOut, typename T1, typename T2> + TOut integrate_Vec2(const DOFVector<T1> &vec1, + const DOFVector<T2> &vec2, + BinaryAbstractFunction<TOut, T1, T2> *fct, MeshIndicator *meshIndicator) + { + FUNCNAME("intDualmesh()"); + + TEST_EXIT(fct)("No function defined!\n"); + TEST_EXIT(meshIndicator)("No MeshIndicator defined!\n"); + + int deg = std::max(fct->getDegree(), + 2 * vec1.getFeSpace()->getBasisFcts()->getDegree()); + Quadrature* quad = + Quadrature::provideQuadrature(vec1.getFeSpace()->getMesh()->getDim(), deg); + FastQuadrature *fastQuad = + FastQuadrature::provideFastQuadrature(vec1.getFeSpace()->getBasisFcts(), *quad, INIT_PHI); + + mtl::dense_vector<T1> qp1(fastQuad->getNumPoints()); + mtl::dense_vector<T2> qp2(fastQuad->getNumPoints()); + + TOut value; nullify(value); + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(vec1.getFeSpace()->getMesh(), -1, traverseFlag); + while (elInfo) { + if ((*meshIndicator)(elInfo)) { + vec1.getVecAtQPs(elInfo, quad, fastQuad, qp1); + vec2.getVecAtQPs(elInfo, quad, fastQuad, qp2); + + TOut tmp; nullify(tmp); + for (int iq = 0; iq < fastQuad->getNumPoints(); iq++) + tmp += fastQuad->getWeight(iq) * (*fct)(qp1[iq], qp2[iq]); + value += tmp * elInfo->getDet(); + } + elInfo = stack.traverseNext(elInfo); + } + + #ifdef HAVE_PARALLEL_DOMAIN_AMDIS + mpi::globalAdd(value); + #endif + + return value; + } + + + template<typename T1, typename T2> + typename ProductType<T1,T2>::type integrate_VecTimesCoords(const DOFVector<T1> &vec, + AbstractFunction<T2, WorldVector<double> > *fct, MeshIndicator *meshIndicator) + { + FUNCNAME("integrate_VecTimesCoords()"); + + TEST_EXIT(fct)("No function defined!\n"); + TEST_EXIT(meshIndicator)("No MeshIndicator defined!\n"); + + typedef typename ProductType<T1,T2>::type TOut; + + const FiniteElemSpace *feSpace = vec.getFeSpace(); + Mesh *mesh = feSpace->getMesh(); + + int deg = std::max(fct->getDegree(), 2 * feSpace->getBasisFcts()->getDegree()); + Quadrature* quad = Quadrature::provideQuadrature(mesh->getDim(), deg); + FastQuadrature *fastQuad = + FastQuadrature::provideFastQuadrature(feSpace->getBasisFcts(), *quad, INIT_PHI); + + mtl::dense_vector<T1> qp(fastQuad->getNumPoints()); + WorldVector<double> coords; + + TOut value; nullify(value); + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + while (elInfo) { + if ((*meshIndicator)(elInfo)) { + vec.getVecAtQPs(elInfo, quad, fastQuad, qp); + + TOut tmp; nullify(tmp); + for (int iq = 0; iq < fastQuad->getNumPoints(); iq++) { + elInfo->coordToWorld(fastQuad->getLambda(iq), coords); + tmp += fastQuad->getWeight(iq) * (qp[iq] * (*fct)(coords)); + } + + value += tmp * elInfo->getDet(); + } + elInfo = stack.traverseNext(elInfo); + } + + #ifdef HAVE_PARALLEL_DOMAIN_AMDIS + mpi::globalAdd(value); + #endif + + return value; + } + + + template<typename TOut, typename T> + TOut integrate_VecAndCoords(const DOFVector<T> &vec, + BinaryAbstractFunction<TOut, T, WorldVector<double> > *fct, MeshIndicator *meshIndicator) + { + FUNCNAME("integrate_VecAndCoords()"); + + TEST_EXIT(fct)("No function defined!\n"); + TEST_EXIT(meshIndicator)("No MeshIndicator defined!\n"); + + int deg = std::max(fct->getDegree(), + 2 * vec.getFeSpace()->getBasisFcts()->getDegree()); + Quadrature* quad = + Quadrature::provideQuadrature(vec.getFeSpace()->getMesh()->getDim(), deg); + FastQuadrature *fastQuad = + FastQuadrature::provideFastQuadrature(vec.getFeSpace()->getBasisFcts(), *quad, INIT_PHI); + + mtl::dense_vector<T> qp(fastQuad->getNumPoints()); + WorldVector<double> coordsAtQP; + + TOut value; nullify(value); + + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(vec.getFeSpace()->getMesh(), -1, traverseFlag); + while (elInfo) { + if ((*meshIndicator)(elInfo)) { + vec.getVecAtQPs(elInfo, quad, fastQuad, qp); + TOut tmp; nullify(tmp); + for (int iq = 0; iq < fastQuad->getNumPoints(); iq++) { + elInfo->coordToWorld(fastQuad->getLambda(iq), coordsAtQP); + tmp += fastQuad->getWeight(iq) * (*fct)(qp[iq], coordsAtQP); + } + value += tmp * elInfo->getDet(); + } + elInfo = stack.traverseNext(elInfo); + } + + #ifdef HAVE_PARALLEL_DOMAIN_AMDIS + mpi::globalAdd(value); + #endif + + return value; + } + + + template<typename TOut, typename T> + TOut integrateGeneral(const std::vector<DOFVector<T>*> &vecs, + AbstractFunction<TOut, std::vector<T> > *fct, MeshIndicator *meshIndicator) + { + FUNCNAME("integrateGeneral()"); + + TEST_EXIT(fct)("No function defined!\n"); + TEST_EXIT(vecs.size()>0)("No DOFVectors provided!\n"); + + int deg = std::max(fct->getDegree(), + 2 * vecs[0]->getFeSpace()->getBasisFcts()->getDegree()); + Quadrature* quad = + Quadrature::provideQuadrature(vecs[0]->getFeSpace()->getMesh()->getDim(), deg); + FastQuadrature *fastQuad = + FastQuadrature::provideFastQuadrature(vecs[0]->getFeSpace()->getBasisFcts(), *quad, INIT_PHI); + + std::vector<mtl::dense_vector<T> > qp(vecs.size()); + std::vector<T> qp_local(vecs.size()); + for (size_t i = 0; i < vecs.size(); i++) + qp[i].change_dim(fastQuad->getNumPoints()); + + TOut value; nullify(value); + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(vecs[0]->getFeSpace()->getMesh(), -1, traverseFlag); + while (elInfo) { + if ((*meshIndicator)(elInfo)) { + for (size_t i = 0; i < vecs.size(); i++) + vecs[i]->getVecAtQPs(elInfo, quad, fastQuad, qp[i]); + + TOut tmp; nullify(tmp); + for (int iq = 0; iq < fastQuad->getNumPoints(); iq++) { + for (size_t i = 0; i < vecs.size(); i++) + qp_local[i] = qp[i][iq]; + tmp += fastQuad->getWeight(iq) * (*fct)(qp_local); + } + value += tmp * elInfo->getDet(); + } + elInfo = stack.traverseNext(elInfo); + } + + #ifdef HAVE_PARALLEL_DOMAIN_AMDIS + mpi::globalAdd(value); + #endif + + return value; + } + +} // namespace tools + +#endif // MESH_INDICATOR_H diff --git a/extensions/MetaTools.h b/extensions/MetaTools.h new file mode 100644 index 0000000000000000000000000000000000000000..d2f946427687b58440c98778971189c89761b8fc --- /dev/null +++ b/extensions/MetaTools.h @@ -0,0 +1,518 @@ +/** \file MetaTools.h */ + +#ifndef META_TOOLS_H +#define META_TOOLS_H + +// #include "AMDiS.h" +#include <boost/mpl/if.hpp> +#include <boost/mpl/arithmetic.hpp> +#include <boost/mpl/comparison.hpp> +#include <boost/mpl/logical.hpp> +#include <boost/utility/enable_if.hpp> + +#define GET_LOOP_INDEX(VAR, SEQ, IDX) static const long VAR = boost::mpl::at_c<SEQ,IDX>::type::value; + +// namespace boost { +// namespace fusion { +// template<int I> inline double at_c(WorldVector<double> &x) { return x[I]; } +// } +// } + +namespace tools { + + /// binomial coefficients + /// _______________________________________________________________________________ + + namespace details { + + template <int N, int K, bool N_pos = true, bool K_pos = true> + struct Binomial + { + BOOST_STATIC_CONSTANT(int, value = (details::Binomial<N-1, K-1, (N-1>0), (K-1>0) >::value + + details::Binomial<N-1, K, (N-1>0), (K>0) >::value) ); + }; + + template <int N, bool N_pos> + struct Binomial<N, N, N_pos, true> // K > 0, N > 0, K==N + { + BOOST_STATIC_CONSTANT(int, value = 1); + }; + + template <int N, int K, bool N_pos> + struct Binomial<N, K, N_pos, false> // K <= 0 + { + BOOST_STATIC_CONSTANT(int, value = 1); + }; + + template <int N, int K> + struct Binomial<N, K, false, true> // K > 0, N <= 0 + { + BOOST_STATIC_CONSTANT(int, value = 0); + }; + } + + // interface to calc binomial coefficients (N, K) at compile-time for N,K >= 0 + template <int N, int K> + struct Binomial + { + BOOST_STATIC_CONSTANT(int, value = (details::Binomial<N, K, (N>0), (K>0)>::value) ); + }; + + /// some mathematical basics + /// ____________________________________________________________________________ + + // check divisibility + template <int u, int v> + struct Divisible + { + BOOST_STATIC_CONSTANT(bool, value = u % v == 0 ? true : false ); + }; + + // check divide by zero condition + template <int u> + struct Divisible<u, 0> + { + BOOST_STATIC_CONSTANT(bool, value = false ); // better: static assert + }; + + // check number is even or not + template <int u> + struct IsEven + { + BOOST_STATIC_CONSTANT(bool, value = (Divisible<u, 2>::value) ); + }; + + // check number is odd or not + template <int u> + struct IsOdd + { + BOOST_STATIC_CONSTANT(bool, value = (-Divisible<u, 2>::value) ); + }; + + template <int N> + struct Abs + { + BOOST_STATIC_CONSTANT(bool, value = (N >= 0) ? N : -N ); + }; + + // greatest common devisor and least common multiple + // ________________________________________________________________________ + + // calculate gcd + template <int u, int v> + struct Gcd + { + BOOST_STATIC_CONSTANT(int, value = (Gcd<v, u % v>::value) ); + }; + + template <int u> + struct Gcd<u, 0> + { + BOOST_STATIC_CONSTANT(int, value = u ); + }; + + template <> + struct Gcd<0, 0> + { + BOOST_STATIC_CONSTANT(int, value = -1 ); + }; + + // calculate lcm + template <int u, int v> + struct Lcm + { + BOOST_STATIC_CONSTANT(int, value = (Abs<u * v>::value / Gcd<u, v>::value) ); + }; + + + // powers of values + // _______________________________________________________________________________ + + // to calculate the power + template <int a, int p> + struct Pow + { + BOOST_STATIC_CONSTANT(int, value = (a * Pow<a, p-1>::value) ); + }; + + template <int a> + struct Pow<a, 1> + { + BOOST_STATIC_CONSTANT(int, value = a ); + }; + + template <int a> + struct Pow<a, 0> + { + BOOST_STATIC_CONSTANT(int, value = 1 ); + }; + + template <int n> + struct Sqr + { + BOOST_STATIC_CONSTANT(int, value = (Pow<n, 2>::value) ); + }; + + // roots of values + // _______________________________________________________________________________ + + // template to compute sqrt(N) via iteration + template <int a, int I=1> + struct Sqrt { + // instantiate next step or result type as branch + typedef typename boost::mpl::if_c< (I*I < a), + Sqrt<a, I+1>, + boost::mpl::int_<I> + >::type impl; + + // use the result of branch type + BOOST_STATIC_CONSTANT(int, value = impl::value ); + }; + + // partial specialization to end the iteration + template<int a> + struct Sqrt<a, a> { + BOOST_STATIC_CONSTANT(int, value = a ); + }; + template<int I> + struct Sqrt<0, I> { + BOOST_STATIC_CONSTANT(int, value = 0 ); + }; + + // template to compute sqrt(N) via iteration + template <int a, int N, int I=1> + struct Root { + // instantiate next step or result type as branch + typedef typename boost::mpl::if_c<Pow<I, N>::value < a, + Root<a, N, I+1>, + boost::mpl::int_<I> + >::type impl; + + // use the result of branch type + BOOST_STATIC_CONSTANT(int, value = impl::value ); + }; + + // partial specialization to end the iteration + template<int a, int N> + struct Root<a, N, a> { + BOOST_STATIC_CONSTANT(int, value = a ); + }; + template<int N, int I> + struct Root<0, N, I> { + BOOST_STATIC_CONSTANT(int, value = 0 ); + }; + + + /// monomials and polynomials + /// _______________________________________________________________________________ + + template<int N> + struct Monomial { + typedef double result_type; + result_type operator()(double x) { return x*Monomial<N-1>()(x); } + }; + + template<> + struct Monomial<1> { + typedef double result_type; + result_type operator()(double x) { return x; } + }; + + template<> + struct Monomial<0> { + typedef double result_type; + result_type operator()(double x) { return 1.0; } + }; + + template<typename Coefficients, int I, int N> + struct Horner { + typedef double result_type; + Horner(Coefficients& coefficients_) : coefficients(coefficients_) {} + result_type operator()(double x) { + return boost::fusion::at_c<I>(coefficients) + x*(Horner<Coefficients, I+1, N>(coefficients)(x)); + } + private: + Coefficients& coefficients; + }; + + template<typename Coefficients, int N> + struct Horner<Coefficients, N, N> { + typedef double result_type; + Horner(Coefficients& coefficients_) : coefficients(coefficients_) {} + result_type operator()(double x) { + return boost::fusion::at_c<N>(coefficients); + } + private: + Coefficients& coefficients; + }; + + template<typename Coefficients> + struct Polynomial { + typedef double result_type; + Polynomial(Coefficients& coefficients_) : coefficients(coefficients_) {} + result_type operator()(double x) { + return Horner<Coefficients, 0, boost::fusion::result_of::size<Coefficients>::value - 1>(coefficients)(x); + } + private: + Coefficients& coefficients; + }; + + /// Bernstein polynomials and Bezier-Surfaces + /// ____________________________________________________________________________ + + template<int I, int order> + struct BernsteinPolynomial + { + static inline double value(double x) { + return Binomial<order, I>::value + * std::pow(x, I) * std::pow(1.0 - x, order - I); + } + }; + + template<int I, int order, bool valid = true> + struct BernsteinPolynomial_ + { + static inline double value(double x) { + return (1.0 - x) * BernsteinPolynomial_<I, order - 1, I >= 0 && I <= (order-1)>::value(x) + + x * BernsteinPolynomial_<I - 1, order - 1, (I-1) >= 0 && (I-1) <= (order-1)>::value(x); + } + }; + + template<> + struct BernsteinPolynomial_<0, 0, true> + { + static inline double value(double x) { + return 1.0; + } + }; + + template<int I, int order> + struct BernsteinPolynomial_<I, order, false> + { + static inline double value(double x) { + return 0.0; + } + }; + + template<int I, int J, int order> + struct BernsteinPolynomial2 + { + static inline double value(double x, double y) { + return BernsteinPolynomial<I, order>::value(x) * BernsteinPolynomial<J, order>::value(x); + } + }; + + template<int I, int J, int K, int order> + struct BernsteinPolynomial3 + { + static inline double value(double x, double y, double z) { + return BernsteinPolynomial<I, order>::value(x) * BernsteinPolynomial<J, order>::value(x) * BernsteinPolynomial<K, order>::value(z); + } + }; + + // Bezier-Polynomial + //________________________________________________________________________ + + namespace details { + + // sum_{I=0}^N B_I^N(x)*c_I + template<int I, int N> + struct BezierPolynomial + { + template<typename Coefficients> + static double value(Coefficients& coefficients, double x) { + return boost::fusion::at_c<I>(coefficients)*BernsteinPolynomial<I, N>::value(x) + details::BezierPolynomial<I+1, N>::value(coefficients, x); + } + }; + + template<int N> + struct BezierPolynomial<N, N> + { + template<typename Coefficients> + static double value(Coefficients& coefficients, double x) { + return boost::fusion::at_c<N>(coefficients)*BernsteinPolynomial<N,N>::value(x); + } + }; + } + + template<typename Coefficients, int DOW=1> + struct BezierPolynomial + { + BOOST_STATIC_CONSTANT(int, N = (boost::mpl::minus< boost::mpl::int_< Root< boost::fusion::result_of::size<Coefficients>::value, + DOW >::value >, + boost::mpl::int_<1> >::type::value) ); // N = rootN(coeff.size, DOW)-1 + + BezierPolynomial(Coefficients& coefficients_) : coefficients(coefficients_) {} + double value(double x) { + return details::BezierPolynomial<0, N>::value(coefficients, x); + } + private: + Coefficients& coefficients; + }; + + // Bezier-Polynomial 2d + //________________________________________________________________________ + + namespace details { + + template<int IJ, int N, bool finished=false> // IJ = I + J*N, max(IJ) = N*N - 2 + struct BezierPolynomial2 + { + template<typename Coefficients> + static double value(Coefficients& coefficients, double x, double y) { + return boost::fusion::at_c<N>(coefficients) * BernsteinPolynomial2<IJ%N, IJ/N, N>::value(x, y) + + details::BezierPolynomial2<IJ + 1, N, IJ == (N+1)*(N+1)>::value(coefficients, x, y); + } + }; + + template<int IJ, int N> + struct BezierPolynomial2<IJ, N, true> + { + template<typename Coefficients> + static double value(Coefficients& coefficients, double x, double y) { + return 0.0; + } + }; + } + + // interface for bezier-surfaces of order (N,N) + template<typename Coefficients> + struct BezierPolynomial2 + { + BOOST_STATIC_CONSTANT(int, N = (boost::mpl::minus< + boost::mpl::int_< + Root< + boost::fusion::result_of::size<Coefficients>::value, + 2 + >::value + >, + boost::mpl::int_<1> + >::type::value) ); // N = rootN(coeff.size, 2)-1 + + BezierPolynomial2(Coefficients& coefficients_) : coefficients(coefficients_) {} + double value(double x, double y) { + return details::BezierPolynomial2<0, N, N == 0>::value(coefficients, x, y); + } + private: + Coefficients& coefficients; // p in points is element of result_type + }; + + + /// for loops: for<i, n [,{incr,decr}]>, for<mpl::range_c>, for<mpl::vector_c> + ///____________________________________________________________________________ + + template<int I> struct incr { BOOST_STATIC_CONSTANT(int, value = I+1); }; + template<int I> struct decr { BOOST_STATIC_CONSTANT(int, value = I-1); }; + + template<int I, int N, template<int> class op, bool finished, template<int> class F> + struct FOR_LOOP { + static void loop() { + F<I>::eval(); // your implementation here + FOR_LOOP<op<I>::value, N, op, op<I>::value == N, F>::loop(); + } + }; + + // initial/break condition for 'for-loop': e.g. I==N + template<int I, int N, template<int> class op, template<int> class F> + struct FOR_LOOP<I, N, op, true, F> + { + static void loop() {} + }; + + // 'for-loop', for I<N + template<int I, int N, bool plus, bool finished, template<int> class F> + struct FOR_LOOP_CHECK + { + static void loop() { FOR_LOOP<I, N, incr, finished, F>::loop(); } + }; + + // 'for-loop', for I>N + template<int I, int N, bool finished, template<int> class F> + struct FOR_LOOP_CHECK<I,N,false,finished, F> + { + static void loop() { FOR_LOOP<I, N, decr, finished, F>::loop(); } + }; + + // interface for classical for loop: for j=I..N + // the index will be incremented, if I<N and decremented otherwise + template<int I, int N, template<int> class F> + struct FOR + { + static void loop() { FOR_LOOP_CHECK<I, N, I < N, I == N, F>::loop(); } + }; + + // 'for-loop' over sequence of values + template<typename Seq, long I, long N, template<int> class F> + struct FOR_SUBSEQ + { + static void loop() { + GET_LOOP_INDEX (i, Seq, I); + F<i>::eval(); // your implementation here + FOR_SUBSEQ<Seq, I+1, N, F>::loop(); + } + }; + + // initial/break condition for 'for-loop' over sequences: I==N + template<typename Seq, long N, template<int> class F> + struct FOR_SUBSEQ<Seq,N,N,F> + { + static void loop() {} + }; + + // interface for loop over sequence of values + // for i in {seq[0]..seq[end]} + template<typename Seq, template<int> class F> + struct FOR_SEQ + { + static void loop() { FOR_SUBSEQ<Seq, 0, boost::mpl::size<Seq>::value, F>::loop(); } + }; + + + /// for-each loops + ///____________________________________________________________________________ + + template<int I> struct for_each + { + template<typename Container1, typename Container2, typename Binary_Functor> + static void eval(Container1& vec1, Container2& vec2, Binary_Functor& f); + + template<typename Container1, typename Container2, typename T, typename Tertiary_Functor> + static void accumulate(Container1& vec1, Container2& vec2, T& value, Tertiary_Functor& f); + }; + + template<> struct for_each<0> + { + template<typename Container1, typename Container2, typename Binary_Functor> + static void eval(Container1& vec1, Container2& vec2, Binary_Functor& f); + + template<typename Container1, typename Container2, typename T, typename Tertiary_Functor> + static void accumulate(Container1& vec1, Container2& vec2, T& value, Tertiary_Functor& f); + }; + + template<int I> + template<typename Container1, typename Container2, typename Binary_Functor> + void for_each<I>::eval(Container1& vec1, Container2& vec2, Binary_Functor& f) { + f(boost::fusion::at_c<I>(vec1), boost::fusion::at_c<I>(vec2)); + for_each<I-1>::eval(vec1,vec2,f); + }; + + template<int I> + template<typename Container1, typename Container2, typename T, typename Tertiary_Functor> + void for_each<I>::accumulate(Container1& vec1, Container2& vec2, T& value, Tertiary_Functor& f) { + f(boost::fusion::at_c<I>(vec1), boost::fusion::at_c<I>(vec2), value); + for_each<I-1>::accumulate(vec1,vec2,value,f); + }; + + template<typename Container1, typename Container2, typename Binary_Functor> + void for_each<0>::eval(Container1& vec1, Container2& vec2, Binary_Functor& f) { + f(boost::fusion::at_c<0>(vec1), boost::fusion::at_c<0>(vec2)); + }; + + template<typename Container1, typename Container2, typename T, typename Tertiary_Functor> + void for_each<0>::accumulate(Container1& vec1, Container2& vec2, T& value, Tertiary_Functor& f) { + f(boost::fusion::at_c<0>(vec1), boost::fusion::at_c<0>(vec2),value); + }; + +} // namespace tools + +#endif // META_TOOLS_H diff --git a/extensions/NewtonCotesQuad.h b/extensions/NewtonCotesQuad.h new file mode 100644 index 0000000000000000000000000000000000000000..878689d6a388871863299aeaf386affea53f99fd --- /dev/null +++ b/extensions/NewtonCotesQuad.h @@ -0,0 +1,138 @@ +/** \file NewtonCotesQuad.h */ + +#ifndef NEWTON_COTES_QUAD_H +#define NEWTON_COTES_QUAD_H + +#include <boost/array.hpp> +#include "Tools.h" + +namespace tools { + + template<int deg> + struct NewtonCotesQuad + { + typedef boost::array<double,1> Container; + typedef GeneralQuad<Container> type; + + static type& provide() + { + ERROR("ERROR: no, or unknown degree, for quadrature rule given!\n"); + static Container xi = {{0.0}}; + static Container ci = {{1.0}}; + return *(new type(xi,ci)); + } + }; + + template<> + struct NewtonCotesQuad<1> + { + typedef boost::array<double,1> Container; + typedef GeneralQuad<Container> type; + + static type& provide() + { + static Container xi = {{0.5}}; + static Container ci = {{1.0}}; + return *(new type(xi,ci)); + } + }; + + template<> + struct NewtonCotesQuad<2> + { + typedef boost::array<double,2> Container; + typedef GeneralQuad<Container> type; + + static type& provide() + { + static Container xi = {{-0.5/sqrt(3.0)+0.5, 0.5/sqrt(3.0)+0.5}}; + static Container ci = {{0.5, 0.5}}; + return *(new type(xi,ci)); + } + }; + + template<> + struct NewtonCotesQuad<3> + { + typedef boost::array<double,2> Container; + typedef GeneralQuad<Container> type; + + static type& provide() + { + static Container xi = {{-0.5/sqrt(3.0)+0.5, 0.5/sqrt(3.0)+0.5}}; + static Container ci = {{0.5, 0.5}}; + return *(new type(xi,ci)); + } + }; + + template<> + struct NewtonCotesQuad<4> + { + typedef boost::array<double,3> Container; + typedef GeneralQuad<Container> type; + + static type& provide() + { + static Container xi = {{-sqrt(3.0/5.0)/2.0+0.5, 0.5, sqrt(3.0/5.0)/2.0+0.5}}; + static Container ci = {{5.0/18.0, 8.0/18.0, 5.0/18.0}}; + return *(new type(xi,ci)); + } + }; + + template<> + struct NewtonCotesQuad<5> + { + typedef boost::array<double,3> Container; + typedef GeneralQuad<Container> type; + + static type& provide() + { + static Container xi = {{-sqrt(3.0/5.0)/2.0+0.5, 0.5, sqrt(3.0/5.0)/2.0+0.5}}; + static Container ci = {{5.0/18.0, 8.0/18.0, 5.0/18.0}}; + return *(new type(xi,ci)); + } + }; + + template<> + struct NewtonCotesQuad<6> + { + typedef boost::array<double,4> Container; + typedef GeneralQuad<Container> type; + + static type& provide() + { + static Container xi = {{-sqrt(3.0/7.0 + 2.0/7.0 * sqrt(6.0/5.0))/2.0 + 0.5, + -sqrt(3.0/7.0 - 2.0/7.0 * sqrt(6.0/5.0))/2.0 + 0.5, + sqrt(3.0/7.0 - 2.0/7.0 * sqrt(6.0/5.0))/2.0 + 0.5, + sqrt(3.0/7.0 + 2.0/7.0 * sqrt(6.0/5.0))/2.0 + 0.5}}; + static Container ci = {{(18.0-sqrt(30.0))/72.0, + (18.0+sqrt(30.0))/72.0, + (18.0+sqrt(30.0))/72.0, + (18.0-sqrt(30.0))/72.0}}; + return *(new type(xi,ci)); + } + }; + + template<> + struct NewtonCotesQuad<7> + { + typedef boost::array<double,4> Container; + typedef GeneralQuad<Container> type; + + static type& provide() + { + static Container xi = {{-sqrt(3.0/7.0 + 2.0/7.0 * sqrt(6.0/5.0))/2.0 + 0.5, + -sqrt(3.0/7.0 - 2.0/7.0 * sqrt(6.0/5.0))/2.0 + 0.5, + sqrt(3.0/7.0 - 2.0/7.0 * sqrt(6.0/5.0))/2.0 + 0.5, + sqrt(3.0/7.0 + 2.0/7.0 * sqrt(6.0/5.0))/2.0 + 0.5}}; + static Container ci = {{(18.0-sqrt(30.0))/72.0, + (18.0+sqrt(30.0))/72.0, + (18.0+sqrt(30.0))/72.0, + (18.0-sqrt(30.0))/72.0}}; + return *(new type(xi,ci)); + } + }; + +} // end namespace + +#endif // NEWTON_COTES_QUAD_H diff --git a/extensions/POperators.cc b/extensions/POperators.cc new file mode 100644 index 0000000000000000000000000000000000000000..0023fa8bf55d503fee12cab258316f5cd630eaec --- /dev/null +++ b/extensions/POperators.cc @@ -0,0 +1,2286 @@ +#include "POperators.h" +#include "Helpers.h" + +using namespace std; +using namespace AMDiS; + +Phase_SOT::Phase_SOT(DOFVectorBase<double>* phaseDV_,double fac_) : + SecondOrderTerm(6), phaseDV(phaseDV_), fac(fac_) +{ + TEST_EXIT(phaseDV_)("no vector phase!\n"); + auxFeSpaces.insert(phaseDV_->getFeSpace()); +}; +void Phase_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(phaseDV, elInfo, subAssembler, quad, phase); +}; +void Phase_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(phaseDV, smallElInfo, largeElInfo, subAssembler, quad, phase); +}; +void Phase_SOT::getLALt(const ElInfo *elInfo, + vector<mtl::dense2D<double> > &LALt) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(LALt.size()); + + for (int iq = 0; iq < nPoints; iq++) + l1lt(Lambda, LALt[iq], f(iq) * phase[iq] * fac); +}; +void Phase_SOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + if (num_rows(D2UhAtQP) > 0) { + for (int iq = 0; iq < nPoints; iq++) { + double feval = f(iq) * phase[iq] * opFactor * fac; + double resultQP = 0.0; + for (int i = 0; i < dimOfWorld; i++) + resultQP += D2UhAtQP[iq][i][i]; + result[iq] += feval * resultQP; + } + } +}; +void Phase_SOT::weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result) +{ + int nPoints = grdUhAtQP.size(); + for (int iq = 0; iq < nPoints; iq++) { + double factor = f(iq) * phase[iq] * fac; + axpy(factor, grdUhAtQP[iq], result[iq]); + } +}; +double Phase_SOT::f(const int iq) const +{ + return 1.0; +}; + +/* ----------------------------------------------------------- */ + +Phase_FOT::Phase_FOT(DOFVectorBase<double>* phaseDV_,double fac_) : + FirstOrderTerm(6), phaseDV(phaseDV_), fac(fac_) +{ + TEST_EXIT(phaseDV_)("no vector phase!\n"); + auxFeSpaces.insert(phaseDV_->getFeSpace()); +}; +void Phase_FOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(phaseDV, elInfo, subAssembler, quad, phase); +}; +void Phase_FOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(phaseDV, smallElInfo, largeElInfo, subAssembler, quad, phase); +}; +void Phase_FOT::getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(result.size()); + + for (int iq = 0; iq < nPoints; iq++) { + lb(Lambda, f(iq), result[iq], phase[iq]*fac); + } +}; +void Phase_FOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = fac * opFactor; + for (int iq = 0; iq < nPoints; iq++) { + double resultQP = grdUhAtQP[iq] * f(iq); + result[iq] += phase[iq] * factor * resultQP; + } +}; +WorldVector<double> Phase_FOT::f(const int iq) const +{ + WorldVector<double> result; + result.set(1.0); + return result; +}; + +/* ----------------------------------------------------------- */ + +Phase_ZOT::Phase_ZOT(DOFVectorBase<double>* phaseDV_, double fac_) : ZeroOrderTerm(6), + phaseDV(phaseDV_), fac(fac_) +{ + TEST_EXIT(phaseDV_)("No vector Phase!\n"); + + auxFeSpaces.insert(phaseDV_->getFeSpace()); +}; +void Phase_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(phaseDV, elInfo, subAssembler, quad, phase); +}; +void Phase_ZOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(phaseDV, smallElInfo, largeElInfo, subAssembler, quad, phase); +}; +void Phase_ZOT::getC(const ElInfo *elInfo, int nPoints, ElementVector &C) +{ + for (int iq = 0; iq < nPoints; iq++) + C[iq] += f(iq) * phase[iq] * fac; +}; +void Phase_ZOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = opFactor * fac; + for (int iq = 0; iq < nPoints; iq++) + result[iq] += factor * f(iq) * phase[iq] * uhAtQP[iq]; +}; +double Phase_ZOT::f(const int iq) const +{ + return 1.0; +}; + +/* ----------------------------------------------------------- */ + +PhaseInverse_ZOT::PhaseInverse_ZOT(DOFVectorBase<double>* phaseDV_, double fac_) : ZeroOrderTerm(6), + phaseDV(phaseDV_), fac(fac_), component(0) +{ + TEST_EXIT(phaseDV_)("No vector Phase!\n"); + facVec = new WorldVector<double>(); + facVec->set(1.0); + + auxFeSpaces.insert(phaseDV_->getFeSpace()); +}; +PhaseInverse_ZOT::PhaseInverse_ZOT(DOFVectorBase<double>* phaseDV_, double fac_, WorldVector<double> *facVec_, int component_) : ZeroOrderTerm(6), + phaseDV(phaseDV_), fac(fac_), component(component_), facVec(facVec_) +{ + TEST_EXIT(phaseDV_)("No vector Phase!\n"); + + auxFeSpaces.insert(phaseDV_->getFeSpace()); +}; +void PhaseInverse_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(phaseDV, elInfo, subAssembler, quad, phase); +}; +void PhaseInverse_ZOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(phaseDV, smallElInfo, largeElInfo, subAssembler, quad, phase); +}; +void PhaseInverse_ZOT::getC(const ElInfo *, int nPoints, ElementVector &C) +{ + double factor = fac * (*facVec)[component]; + for (int iq = 0; iq < nPoints; iq++) + C[iq] += f(iq) * factor; +}; +void PhaseInverse_ZOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = opFactor * fac * (*facVec)[component]; + for (int iq = 0; iq < nPoints; iq++) + result[iq] += factor * f(iq) * uhAtQP[iq]; +}; +double PhaseInverse_ZOT::f(const int iq) const +{ + return std::max(0.0, std::min( 1.0, (1.0-phase[iq]) ) ); +}; + +/* ----------------------------------------------------------- */ + +Pow3_ZOT::Pow3_ZOT(DOFVectorBase<double> *rhoDV_, double fac_) : + ZeroOrderTerm(3), rhoDV(rhoDV_), fac(fac_) +{ + TEST_EXIT(rhoDV_)("No vector rho!\n"); + auxFeSpaces.insert(rhoDV_->getFeSpace()); +}; + +void Pow3_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(rhoDV, elInfo, subAssembler, quad, rho); +}; +void Pow3_ZOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(rhoDV, smallElInfo, largeElInfo, subAssembler, quad, rho); +}; +void Pow3_ZOT::getC(const ElInfo *elInfo, int nPoints, ElementVector &C) +{ + for (int iq = 0; iq < nPoints; iq++) + C[iq] += f(iq) * fac; +}; +void Pow3_ZOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = opFactor * fac; + for (int iq = 0; iq < nPoints; iq++) + result[iq] += factor * f(iq) * uhAtQP[iq]; +}; +double Pow3_ZOT::f(const int iq) const +{ + return rho[iq]*sqr(rho[iq]); +}; + +/* ----------------------------------------------------------- */ + +Pow3Phase_ZOT::Pow3Phase_ZOT(DOFVectorBase<double>* phaseDV, DOFVectorBase<double> *rhoDV_, double fac_) : + Phase_ZOT(phaseDV, fac_), rhoDV(rhoDV_) +{ + TEST_EXIT(rhoDV_)("No vector rho!\n"); + auxFeSpaces.insert(rhoDV_->getFeSpace()); +}; + +void Pow3Phase_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + Phase_ZOT::initElement(elInfo,subAssembler,quad); + getVectorAtQPs(rhoDV, elInfo, subAssembler, quad, rho); +}; +void Pow3Phase_ZOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + Phase_ZOT::initElement(largeElInfo,smallElInfo,subAssembler,quad); + getVectorAtQPs(rhoDV, smallElInfo, largeElInfo, subAssembler, quad, rho); +}; +double Pow3Phase_ZOT::f(const int iq) const +{ + return rho[iq]*sqr(rho[iq]); +}; + +/* ----------------------------------------------------------- */ + +Pow2_ZOT::Pow2_ZOT(DOFVectorBase<double> *rhoDV_, double fac_) : + ZeroOrderTerm(2), rhoDV(rhoDV_), fac(fac_) +{ + TEST_EXIT(rhoDV_)("No vector rho!\n"); + auxFeSpaces.insert(rhoDV_->getFeSpace()); +}; + +void Pow2_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(rhoDV, elInfo, subAssembler, quad, rho); +}; +void Pow2_ZOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(rhoDV, smallElInfo, largeElInfo, subAssembler, quad, rho); +}; +void Pow2_ZOT::getC(const ElInfo *elInfo, int nPoints, ElementVector &C) +{ + for (int iq = 0; iq < nPoints; iq++) + C[iq] += f(iq) * fac; +}; +void Pow2_ZOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = opFactor * fac; + for (int iq = 0; iq < nPoints; iq++) + result[iq] += factor * f(iq) * uhAtQP[iq]; +}; +double Pow2_ZOT::f(const int iq) const +{ + return sqr(rho[iq]); +}; + +/* ----------------------------------------------------------- */ + +Pow2Phase_ZOT::Pow2Phase_ZOT(DOFVectorBase<double>* phaseDV, DOFVectorBase<double> *rhoDV_, double fac_) : + Phase_ZOT(phaseDV, fac_), rhoDV(rhoDV_) +{ + TEST_EXIT(rhoDV_)("No vector rho!\n"); + auxFeSpaces.insert(rhoDV_->getFeSpace()); +}; + +void Pow2Phase_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + Phase_ZOT::initElement(elInfo,subAssembler,quad); + getVectorAtQPs(rhoDV, elInfo, subAssembler, quad, rho); +}; +void Pow2Phase_ZOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + Phase_ZOT::initElement(largeElInfo,smallElInfo,subAssembler,quad); + getVectorAtQPs(rhoDV, smallElInfo, largeElInfo, subAssembler, quad, rho); +}; +double Pow2Phase_ZOT::f(const int iq) const +{ + return sqr(rho[iq]); +}; +/* ----------------------------------------------------------- + 1/(rho+0.9) +*/ + +ConstrainedFrac_ZOT::ConstrainedFrac_ZOT(DOFVectorBase<double> *phaseDV_, DOFVectorBase<double> *rhoDV_, double fac_) : + Phase_ZOT(phaseDV_,fac_), rhoDV(rhoDV_) +{ + TEST_EXIT(rhoDV_)("No vector rho!\n"); + auxFeSpaces.insert(rhoDV_->getFeSpace()); +}; + +void ConstrainedFrac_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + Phase_ZOT::initElement(elInfo, subAssembler,quad); + getVectorAtQPs(rhoDV, elInfo, subAssembler, quad, rho); +}; +void ConstrainedFrac_ZOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + Phase_ZOT::initElement(largeElInfo, smallElInfo, subAssembler,quad); + getVectorAtQPs(rhoDV, smallElInfo, largeElInfo, subAssembler, quad, rho); +}; +double ConstrainedFrac_ZOT::f(const int iq) const +{ + return 1.0/std::max(1.e-6, rho[iq]+0.9); +}; + +/* ----------------------------------------------------------- + -1/(rho+0.9)^2 +*/ + +ConstrainedFracSqr_ZOT::ConstrainedFracSqr_ZOT(DOFVectorBase<double> *phaseDV_, DOFVectorBase<double> *rhoDV_, double factor_) : + Phase_ZOT(phaseDV_,factor_), rhoDV(rhoDV_) +{ + TEST_EXIT(rhoDV_)("No vector rho!\n"); + auxFeSpaces.insert(rhoDV_->getFeSpace()); +}; + +void ConstrainedFracSqr_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + Phase_ZOT::initElement(elInfo, subAssembler,quad); + getVectorAtQPs(rhoDV, elInfo, subAssembler, quad, rho); +}; +void ConstrainedFracSqr_ZOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + Phase_ZOT::initElement(largeElInfo, smallElInfo, subAssembler,quad); + getVectorAtQPs(rhoDV, smallElInfo, largeElInfo, subAssembler, quad, rho); +}; +double ConstrainedFracSqr_ZOT::f(const int iq) const +{ + return -1.0/std::max(1.e-6, sqr(rho[iq]+0.9)); +}; + + +ConstrainedPowImpl_ZOT::ConstrainedPowImpl_ZOT(DOFVectorBase<double> *rhoDV_, double p_, double rhoMin_, double fac_) : + ZeroOrderTerm(2), rhoDV(rhoDV_), p(p_), rhoMin(rhoMin_), fac(fac_) +{ + TEST_EXIT(rhoDV_)("No vector rho!\n"); + auxFeSpaces.insert(rhoDV_->getFeSpace()); +}; + +void ConstrainedPowImpl_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(rhoDV, elInfo, subAssembler, quad, rho); +}; +void ConstrainedPowImpl_ZOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(rhoDV, smallElInfo, largeElInfo, subAssembler, quad, rho); +}; +void ConstrainedPowImpl_ZOT::getC(const ElInfo *elInfo, int nPoints, ElementVector &C) +{ + for (int iq = 0; iq < nPoints; iq++) + C[iq] += f(iq)*fac; +}; +void ConstrainedPowImpl_ZOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = opFactor*fac; + for (int iq = 0; iq < nPoints; iq++) + result[iq] += factor * f(iq) * uhAtQP[iq]; +}; +double ConstrainedPowImpl_ZOT::f(const int iq) const +{ + return 2.0*p*Helpers::toInt(0.0<=rhoMin-rho[iq]); +}; + + +ConstrainedPowExpl_ZOT::ConstrainedPowExpl_ZOT(DOFVectorBase<double> *rhoDV_, double p_, double rhoMin_, double fac_) : + ZeroOrderTerm(2), rhoDV(rhoDV_), p(p_), rhoMin(rhoMin_), fac(fac_) +{ + TEST_EXIT(rhoDV_)("No vector rho!\n"); + auxFeSpaces.insert(rhoDV_->getFeSpace()); +}; + +void ConstrainedPowExpl_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(rhoDV, elInfo, subAssembler, quad, rho); +}; +void ConstrainedPowExpl_ZOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(rhoDV, smallElInfo, largeElInfo, subAssembler, quad, rho); +}; +void ConstrainedPowExpl_ZOT::getC(const ElInfo *elInfo, int nPoints, ElementVector &C) +{ + for (int iq = 0; iq < nPoints; iq++) + C[iq] += f(iq)*fac; +}; +void ConstrainedPowExpl_ZOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = opFactor*fac; + for (int iq = 0; iq < nPoints; iq++) + result[iq] += factor * f(iq) * uhAtQP[iq]; +}; +double ConstrainedPowExpl_ZOT::f(const int iq) const +{ + return -2.0*p*std::max(0.0, rhoMin-rho[iq]); +}; + +ConstrainedPow_ZOT::ConstrainedPow_ZOT(DOFVectorBase<double> *rhoDV_, double p_, double rhoMin_, double fac_) : + ZeroOrderTerm(2), rhoDV(rhoDV_), p(p_), rhoMin(rhoMin_), fac(fac_) +{ + TEST_EXIT(rhoDV_)("No vector rho!\n"); + auxFeSpaces.insert(rhoDV_->getFeSpace()); +}; + +void ConstrainedPow_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(rhoDV, elInfo, subAssembler, quad, rho); +}; +void ConstrainedPow_ZOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(rhoDV, smallElInfo, largeElInfo, subAssembler, quad, rho); +}; +void ConstrainedPow_ZOT::getC(const ElInfo *elInfo, int nPoints, ElementVector &C) +{ + for (int iq = 0; iq < nPoints; iq++) + C[iq] += f(iq)*fac; +}; +void ConstrainedPow_ZOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = opFactor*fac; + for (int iq = 0; iq < nPoints; iq++) + result[iq] += factor * f(iq) * uhAtQP[iq]; +}; +double ConstrainedPow_ZOT::f(const int iq) const +{ + return -2.0*p*std::max(0.0, rhoMin-rho[iq]); +}; + +/* ----------------------------------------------------------- + phi*rho + --------- */ + +FactorPhase_ZOT::FactorPhase_ZOT(DOFVectorBase<double> *phaseDV_, DOFVectorBase<double> *rhoDV_, double fac_) : + Phase_ZOT(phaseDV_,fac_), rhoDV(rhoDV_) +{ + TEST_EXIT(rhoDV_)("No vector rho!\n"); + auxFeSpaces.insert(rhoDV_->getFeSpace()); +}; + +void FactorPhase_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + Phase_ZOT::initElement(elInfo, subAssembler,quad); + getVectorAtQPs(rhoDV, elInfo, subAssembler, quad, rho); +}; +void FactorPhase_ZOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + Phase_ZOT::initElement(largeElInfo, smallElInfo, subAssembler,quad); + getVectorAtQPs(rhoDV, smallElInfo, largeElInfo, subAssembler, quad, rho); +}; +double FactorPhase_ZOT::f(const int iq) const +{ + return rho[iq]; +}; + +/* ----------------------------------------------------------- */ + +WorldVecAndVecFct_FOT::WorldVecAndVecFct_FOT(WorldVector<DOFVectorBase<double>*> vecs_, DOFVectorBase<double> *phaseDV_, double fac_) + : FirstOrderTerm(2), phaseDV(phaseDV_), fac(fac_) +{ + numVecs=vecs_.size(); + TEST_EXIT(numVecs==2 || numVecs==3)("Only Dim=2 or Dim=3 possible\n"); + + TEST_EXIT(phaseDV_)("phaseDV is NULL!\n"); + for (int i = 0; i < numVecs; i++) { + TEST_EXIT(vecs_[i])("One vector is NULL!\n"); + + auxFeSpaces.insert(vecs_[i]->getFeSpace()); + } + + vec0DV=vecs_[0]; + vec1DV=vecs_[1]; + if(numVecs>=3) vec2DV=vecs_[2]; +}; +void WorldVecAndVecFct_FOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec0DV, elInfo, subAssembler, quad, vec0); + getVectorAtQPs(vec1DV, elInfo, subAssembler, quad, vec1); + if(numVecs>=3) getVectorAtQPs(vec2DV, elInfo, subAssembler, quad, vec2); + getVectorAtQPs(phaseDV, elInfo, subAssembler, quad, phase); +}; +void WorldVecAndVecFct_FOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec0DV, smallElInfo, largeElInfo, subAssembler, quad, vec0); + getVectorAtQPs(vec1DV, smallElInfo, largeElInfo, subAssembler, quad, vec1); + if(numVecs>=3) getVectorAtQPs(vec2DV, smallElInfo, largeElInfo, subAssembler, quad, vec2); + getVectorAtQPs(phaseDV, smallElInfo, largeElInfo, subAssembler, quad, phase); +}; +void WorldVecAndVecFct_FOT::getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(result.size()); + + for (int iq = 0; iq < nPoints; iq++) { + WorldVector<double> vec; + vec[0]=vec0[iq]; + vec[1]=vec1[iq]; + if(numVecs>=3) vec[2]=vec2[iq]; + lb(Lambda, vec, result[iq], phase[iq]*fac); + } +}; +void WorldVecAndVecFct_FOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = fac * opFactor; + for (int iq = 0; iq < nPoints; iq++) { + double resultQP = 0.0; + + resultQP += grdUhAtQP[iq][0] * vec0[iq]; + resultQP += grdUhAtQP[iq][1] * vec1[iq]; + if(numVecs>=3) resultQP += grdUhAtQP[iq][2] * vec2[iq]; + + result[iq] += phase[iq] * factor * resultQP; + } +}; + +/* ----------------------------------------------------------- */ + +WorldVec_FOT::WorldVec_FOT(WorldVector<DOFVector<double>*> vecs_, double fac_) + : FirstOrderTerm(2), fac(fac_) +{ + numVecs=vecs_.size(); + TEST_EXIT(numVecs==2 || numVecs==3)("Only Dim=2 or Dim=3 possible\n"); + + for (int i = 0; i < numVecs; i++) { + TEST_EXIT(vecs_[i])("One vector is NULL!\n"); + auxFeSpaces.insert(vecs_[i]->getFeSpace()); + } + + vec0DV=vecs_[0]; + vec1DV=vecs_[1]; + if(numVecs>=3) vec2DV=vecs_[2]; +}; +void WorldVec_FOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec0DV, elInfo, subAssembler, quad, vec0); + getVectorAtQPs(vec1DV, elInfo, subAssembler, quad, vec1); + if(numVecs>=3) getVectorAtQPs(vec2DV, elInfo, subAssembler, quad, vec2); +}; +void WorldVec_FOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec0DV, smallElInfo, largeElInfo, subAssembler, quad, vec0); + getVectorAtQPs(vec1DV, smallElInfo, largeElInfo, subAssembler, quad, vec1); + if(numVecs>=3) getVectorAtQPs(vec2DV, smallElInfo, largeElInfo, subAssembler, quad, vec2); +}; +void WorldVec_FOT::getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(result.size()); + + for (int iq = 0; iq < nPoints; iq++) { + WorldVector<double> vec; + vec[0]=vec0[iq]; + vec[1]=vec1[iq]; + if(numVecs>=3) vec[2]=vec2[iq]; + lb(Lambda, vec, result[iq], fac); + } +}; +void WorldVec_FOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = fac * opFactor; + for (int iq = 0; iq < nPoints; iq++) { + double resultQP = 0.0; + + resultQP += grdUhAtQP[iq][0] * vec0[iq]; + resultQP += grdUhAtQP[iq][1] * vec1[iq]; + if(numVecs>=3) resultQP += grdUhAtQP[iq][2] * vec2[iq]; + + result[iq] += factor * resultQP; + } +}; + +/* ----------------------------------------------------------- */ + +WorldVector_FOT::WorldVector_FOT(DOFVector<WorldVector<double> >* dv, double fac_) +: FirstOrderTerm(1), + vec(dv), + fac(fac_) +{ + TEST_EXIT(dv)("No vector!\n"); + + auxFeSpaces.insert(dv->getFeSpace()); +} + + +void WorldVector_FOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec, elInfo, subAssembler, quad, vecAtQPs); +} + + +void WorldVector_FOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec, smallElInfo, largeElInfo, subAssembler, quad, vecAtQPs); +} + + +void WorldVector_FOT::getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& Lb) const +{ + const DimVec<WorldVector<double> > &grdLambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(Lb.size()); + + for (int iq = 0; iq < nPoints; iq++) + lb(grdLambda, vecAtQPs[iq], Lb[iq], fac); +} + + +void WorldVector_FOT::eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + if (num_rows(grdUhAtQP) > 0) { + double fac_ = fac * opFactor; + for (int iq = 0; iq < nPoints; iq++) + result[iq] += (vecAtQPs[iq] * grdUhAtQP[iq]) * fac_; + } +} + +/* ----------------------------------------------------------- */ + +WorldVecPhase_FOT::WorldVecPhase_FOT(DOFVectorBase<double> *phaseDV_, WorldVector<DOFVector<double>*> vecs_,double fac_) + : FirstOrderTerm(2), phaseDV(phaseDV_), fac(fac_) +{ + numVecs=vecs_.size(); + TEST_EXIT(numVecs==2 || numVecs==3)("Only Dim=2 or Dim=3 possible\n"); + + TEST_EXIT(phaseDV_)("phaseDV is NULL!\n"); + for (int i = 0; i < numVecs; i++) { + TEST_EXIT(vecs_[i])("One vector is NULL!\n"); + + auxFeSpaces.insert(vecs_[i]->getFeSpace()); + } + auxFeSpaces.insert(phaseDV_->getFeSpace()); + + vec0DV=vecs_[0]; + vec1DV=vecs_[1]; + if(numVecs>=3) vec2DV=vecs_[2]; +}; +void WorldVecPhase_FOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec0DV, elInfo, subAssembler, quad, vec0); + getVectorAtQPs(vec1DV, elInfo, subAssembler, quad, vec1); + if(numVecs>=3) getVectorAtQPs(vec2DV, elInfo, subAssembler, quad, vec2); + getVectorAtQPs(phaseDV, elInfo, subAssembler, quad, phase); +}; +void WorldVecPhase_FOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec0DV, smallElInfo, largeElInfo, subAssembler, quad, vec0); + getVectorAtQPs(vec1DV, smallElInfo, largeElInfo, subAssembler, quad, vec1); + if(numVecs>=3) getVectorAtQPs(vec2DV, smallElInfo, largeElInfo, subAssembler, quad, vec2); + getVectorAtQPs(phaseDV, smallElInfo, largeElInfo, subAssembler, quad, phase); +}; +void WorldVecPhase_FOT::getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(result.size()); + + for (int iq = 0; iq < nPoints; iq++) { + WorldVector<double> vec; + vec[0]=vec0[iq]; + vec[1]=vec1[iq]; + if(numVecs>=3) vec[2]=vec2[iq]; + lb(Lambda, vec, result[iq], phase[iq]*fac); + } +}; +void WorldVecPhase_FOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = fac * opFactor; + for (int iq = 0; iq < nPoints; iq++) { + double resultQP = 0.0; + + resultQP += grdUhAtQP[iq][0] * vec0[iq]; + resultQP += grdUhAtQP[iq][1] * vec1[iq]; + if(numVecs>=3) resultQP += grdUhAtQP[iq][2] * vec2[iq]; + + result[iq] += phase[iq] * factor * resultQP; + } +}; + +/* ----------------------------------------------------------- */ + +// vec1*vec2*d/dxi(...) +VecAndPartialDerivative_FOT::VecAndPartialDerivative_FOT(DOFVectorBase<double> *dv1, + int component_, double fac_) +: FirstOrderTerm(3), vec1DV(dv1), fac(fac_), component(component_) +{ + auxFeSpaces.insert(vec1DV->getFeSpace()); + + setB(component); +} + +void VecAndPartialDerivative_FOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec1DV, elInfo, subAssembler, quad, vec1); +}; +void VecAndPartialDerivative_FOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec1DV, smallElInfo, largeElInfo, subAssembler, quad, vec1); +}; +void VecAndPartialDerivative_FOT::getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(result.size()); + + for(int iq = 0; iq < nPoints; iq++) { + lb_one(Lambda, result[iq], vec1[iq] * fac); + } +}; +void VecAndPartialDerivative_FOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + for(int iq = 0; iq < nPoints; iq++) + result[iq] += opFactor * vec1[iq] * grdUhAtQP[iq][component] * fac; +}; + +/* ----------------------------------------------------------- */ + +// vec1*vec2*d/dxi(...) +PhaseAndViscosityPartialDerivativeBoundary_FOT::PhaseAndViscosityPartialDerivativeBoundary_FOT(DOFVectorBase<double> *phaseDV_, DOFVectorBase<double> *chDV_, + int component_, int normalComponent_, double viscosity1_, double viscosity2_) +: FirstOrderTerm(3), phaseDV(phaseDV_), chDV(chDV_), component(component_), normalComponent(normalComponent_), v1(viscosity1_), v2(viscosity2_) +{ + auxFeSpaces.insert(phaseDV->getFeSpace()); + auxFeSpaces.insert(chDV->getFeSpace()); + + setB(component); +} + +void PhaseAndViscosityPartialDerivativeBoundary_FOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(phaseDV, elInfo, subAssembler, quad, phase); + getVectorAtQPs(chDV, elInfo, subAssembler, quad, ch); + + WorldVector<double> normal; + int side= -1; + for (int i= 0; i < elInfo->getMesh()->getDim()+1; ++i) { + if(elInfo->getBoundary(i) > 2) { + side= i; + break; + } + } +// elInfo->getNormal(side, normal); + normalJ = 1.0; //normal[normalComponent]; +}; +void PhaseAndViscosityPartialDerivativeBoundary_FOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(phaseDV, smallElInfo, largeElInfo, subAssembler, quad, phase); + getVectorAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, ch); + + WorldVector<double> normal; + int side= -1; + for (int i= 0; i < largeElInfo->getMesh()->getDim()+1; ++i) { + if(largeElInfo->getBoundary(i) > 2) { + side= i; + break; + } + } +// largeElInfo->getNormal(side, normal); + normalJ = 1.0; //normal[normalComponent]; +}; +void PhaseAndViscosityPartialDerivativeBoundary_FOT::getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(result.size()); + + for(int iq = 0; iq < nPoints; iq++) { + lb_one(Lambda, result[iq], phase[iq] * normalJ * f(iq)); + } +}; +void PhaseAndViscosityPartialDerivativeBoundary_FOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + for(int iq = 0; iq < nPoints; iq++) + result[iq] += opFactor * phase[iq] * grdUhAtQP[iq][component] * normalJ * f(iq); +}; + +double PhaseAndViscosityPartialDerivativeBoundary_FOT::f(const int iq) const +{ + double ph= std::max(-1.0,std::min(1.0,ch[iq])); + double viscosity= v1*0.5*(ph+1.0)-v2*0.5*(ph-1.0); + return viscosity; +}; + +/* ----------------------------------------------------------- */ + +// vec1*vec2*d/dxi(...) +ViscosityPartialDerivativeBoundary_FOT::ViscosityPartialDerivativeBoundary_FOT(DOFVectorBase<double> *chDV_, + int component_, int normalComponent_, double viscosity1_, double viscosity2_) +: FirstOrderTerm(3), chDV(chDV_), component(component_), normalComponent(normalComponent_), v1(viscosity1_), v2(viscosity2_) +{ + auxFeSpaces.insert(chDV->getFeSpace()); + + setB(component); +} + +void ViscosityPartialDerivativeBoundary_FOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(chDV, elInfo, subAssembler, quad, ch); + + WorldVector<double> normal; + int side= -1; + for (int i= 0; i < elInfo->getMesh()->getDim()+1; ++i) { + if(elInfo->getBoundary(i) > 2) { + side= i; + break; + } + } +// elInfo->getNormal(side, normal); + normalJ = 1.0; //normal[normalComponent]; +}; +void ViscosityPartialDerivativeBoundary_FOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, ch); + + WorldVector<double> normal; + int side= -1; + for (int i= 0; i < largeElInfo->getMesh()->getDim()+1; ++i) { + if(largeElInfo->getBoundary(i) > 2) { + side= i; + break; + } + } +// largeElInfo->getNormal(side, normal); + normalJ = 1.0; //normal[normalComponent]; +}; +void ViscosityPartialDerivativeBoundary_FOT::getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(result.size()); + + for(int iq = 0; iq < nPoints; iq++) { + lb_one(Lambda, result[iq], normalJ * f(iq)); + } +}; +void ViscosityPartialDerivativeBoundary_FOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + for(int iq = 0; iq < nPoints; iq++) + result[iq] += opFactor * grdUhAtQP[iq][component] * normalJ * f(iq); +}; + +double ViscosityPartialDerivativeBoundary_FOT::f(const int iq) const +{ + double ph= std::max(-1.0,std::min(1.0,ch[iq])); + double viscosity= v1*0.5*(ph+1.0)-v2*0.5*(ph-1.0); + return viscosity; +}; +/* ----------------------------------------------------------- */ + +// vec1*vec2*d/dxi(...) +Vec2ProductPartial_FOT::Vec2ProductPartial_FOT(DOFVectorBase<double> *dv1, DOFVectorBase<double> *dv2, + int component_, double fac_) +: FirstOrderTerm(3), vec1DV(dv1), vec2DV(dv2), fac(fac_), component(component_) +{ + auxFeSpaces.insert(vec1DV->getFeSpace()); + auxFeSpaces.insert(vec2DV->getFeSpace()); + + setB(component); +} + +void Vec2ProductPartial_FOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec1DV, elInfo, subAssembler, quad, vec1); + getVectorAtQPs(vec2DV, elInfo, subAssembler, quad, vec2); +}; +void Vec2ProductPartial_FOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec1DV, smallElInfo, largeElInfo, subAssembler, quad, vec1); + getVectorAtQPs(vec2DV, smallElInfo, largeElInfo, subAssembler, quad, vec2); +}; +void Vec2ProductPartial_FOT::getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(result.size()); + + for(int iq = 0; iq < nPoints; iq++) { + lb_one(Lambda, result[iq], vec1[iq] * vec2[iq] * fac); + } +}; +void Vec2ProductPartial_FOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + for(int iq = 0; iq < nPoints; iq++) + result[iq] += opFactor * vec1[iq] * vec2[iq] * grdUhAtQP[iq][component] * fac; +}; + +/* ----------------------------------------------------------- */ + +PartialDerivative_FOT::PartialDerivative_FOT(int component_, double fac_) + : FirstOrderTerm(1), component(component_), fac(fac_) +{ + setB(component); +}; +void PartialDerivative_FOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) {}; +void PartialDerivative_FOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) {}; +void PartialDerivative_FOT::getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(result.size()); + + for (int iq = 0; iq < nPoints; iq++) { + lb_one(Lambda, result[iq], fac); + } +}; +void PartialDerivative_FOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + for (int iq = 0; iq < nPoints; iq++) { + result[iq] += opFactor * grdUhAtQP[iq][component] * fac; + } +}; + +/* ----------------------------------------------------------- */ + +PartialDerivative_ZOT::PartialDerivative_ZOT(DOFVectorBase<double> *vecDV_, int component_, double fac_) + : ZeroOrderTerm(1), vecDV(vecDV_), fac(fac_), component(component_) +{ + TEST_EXIT(vecDV_)("No first vector!\n"); + auxFeSpaces.insert(vecDV_->getFeSpace()); + + facVec = new WorldVector<double>(); facVec->set(1.0); + component2 = 0; +}; +PartialDerivative_ZOT::PartialDerivative_ZOT(DOFVectorBase<double> *vecDV_, int component_, double fac_, WorldVector<double> *facVec_, int component2_) + : ZeroOrderTerm(1), vecDV(vecDV_), fac(fac_), facVec(facVec_), component(component_), component2(component2_) +{ + TEST_EXIT(vecDV_)("No first vector!\n"); + auxFeSpaces.insert(vecDV_->getFeSpace()); +}; +void PartialDerivative_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getGradientsAtQPs(vecDV, elInfo, subAssembler, quad, grad); +}; +void PartialDerivative_ZOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getGradientsAtQPs(vecDV, smallElInfo, largeElInfo, subAssembler, quad, grad); +}; +void PartialDerivative_ZOT::getC(const ElInfo *, int nPoints, ElementVector &C) +{ + double factor = fac * (*facVec)[component2]; + for (int iq = 0; iq < nPoints; iq++) + C[iq] += grad[iq][component]*factor; +}; +void PartialDerivative_ZOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = opFactor * fac * (*facVec)[component2]; + for (int iq = 0; iq < nPoints; iq++) { + result[iq] += grad[iq][component] * uhAtQP[iq] * factor; + } +}; + + +/* ----------------------------------------------------------- */ + +VecAndPartialDerivative_ZOT::VecAndPartialDerivative_ZOT(DOFVectorBase<double> *vecDV_, DOFVectorBase<double> *gradDV_, int component_, double fac_) +: ZeroOrderTerm(2), + vecDV(vecDV_), + gradDV(gradDV_), + component(component_), + fac(fac_) +{ + TEST_EXIT(vecDV_)("No value vector!\n"); + TEST_EXIT(gradDV_)("No gradient vector!\n"); + + auxFeSpaces.insert(vecDV_->getFeSpace()); + auxFeSpaces.insert(gradDV_->getFeSpace()); +} + + +void VecAndPartialDerivative_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vecDV, elInfo, subAssembler, quad, vec); + getGradientsAtQPs(gradDV, elInfo, subAssembler, quad, grad); +} + + +void VecAndPartialDerivative_ZOT::initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vecDV, smallElInfo, largeElInfo, subAssembler, quad, vec); + getGradientsAtQPs(gradDV, smallElInfo, largeElInfo, subAssembler, quad, grad); +} + + +void VecAndPartialDerivative_ZOT::getC(const ElInfo *, int nPoints, ElementVector &C) +{ + for (int iq = 0; iq < nPoints; iq++) + C[iq] += vec[iq] * grad[iq][component] * fac; +} + + +void VecAndPartialDerivative_ZOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double fac_ = fac * opFactor; + for (int iq = 0; iq < nPoints; iq++) + result[iq] += vec[iq] * grad[iq][component] * uhAtQP[iq] * fac_; +} + +/* ----------------------------------------------------------- */ + +Vec2AndPartialDerivative_ZOT::Vec2AndPartialDerivative_ZOT(DOFVectorBase<double> *vec1DV_, DOFVectorBase<double> *vec2DV_, DOFVectorBase<double> *gradDV_,int component_, double fac_) + : ZeroOrderTerm(3), vec1DV(vec1DV_), vec2DV(vec2DV_), gradDV(gradDV_), fac(fac_), component(component_) +{ + TEST_EXIT(vec1DV_)("No first vector!\n"); + TEST_EXIT(vec2DV_)("No second vector!\n"); + TEST_EXIT(gradDV_)("No gradient vector!\n"); + auxFeSpaces.insert(vec1DV_->getFeSpace()); + auxFeSpaces.insert(vec2DV_->getFeSpace()); + auxFeSpaces.insert(gradDV_->getFeSpace()); +}; +void Vec2AndPartialDerivative_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec1DV, elInfo, subAssembler, quad, vec1); + getVectorAtQPs(vec2DV, elInfo, subAssembler, quad, vec2); + getGradientsAtQPs(gradDV, elInfo, subAssembler, quad, grad); +}; +void Vec2AndPartialDerivative_ZOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getVectorAtQPs(vec1DV, smallElInfo, largeElInfo, subAssembler, quad, vec1); + getVectorAtQPs(vec2DV, smallElInfo, largeElInfo, subAssembler, quad, vec2); + getGradientsAtQPs(gradDV, smallElInfo, largeElInfo, subAssembler, quad, grad); +}; +void Vec2AndPartialDerivative_ZOT::getC(const ElInfo *, int nPoints, ElementVector &C) +{ + for (int iq = 0; iq < nPoints; iq++) + C[iq] += vec1[iq]*vec2[iq]*grad[iq][component]*fac; +}; +void Vec2AndPartialDerivative_ZOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + for (int iq = 0; iq < nPoints; iq++) { + result[iq] += (vec1[iq] * vec2[iq]) * grad[iq][component] * uhAtQP[iq] * opFactor * fac; + } +}; + +/* ----------------------------------------------------------- */ + +Mobility_SOT::Mobility_SOT(DOFVectorBase<double> *rhoDV_, double factor_) + : SecondOrderTerm(6), rhoDV(rhoDV_), factor(factor_) +{ + setSymmetric(true); + + TEST_EXIT(rhoDV)("No vector!\n"); + auxFeSpaces.insert(rhoDV->getFeSpace()); + eps= 1.e-5; + + rho0= 1.0; + density= -0.3; + Parameters::get("pfc->rho0",rho0, 1); + Parameters::get("pfc->density",density, 1); +}; +void Mobility_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + getVectorAtQPs(rhoDV, elInfo, subAssembler, quad, rho); +}; +void Mobility_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + getVectorAtQPs(rhoDV, smallElInfo, largeElInfo, subAssembler, quad, rho); +}; +void Mobility_SOT::getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(LALt.size()); + + for (int iq = 0; iq < nPoints; iq++) + l1lt(Lambda, LALt[iq], f(iq) * factor); +}; +void Mobility_SOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + if (num_rows(D2UhAtQP) > 0) { + for (int iq = 0; iq < nPoints; iq++) { + double feval = f(iq) * opFactor * factor; + double resultQP = 0.0; + for (int i = 0; i < dimOfWorld; i++) + resultQP += D2UhAtQP[iq][i][i]; + result[iq] += feval * resultQP; + } + } +}; +void Mobility_SOT::weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result) +{ + int nPoints = grdUhAtQP.size(); + for (int iq = 0; iq < nPoints; iq++) { + double fac = f(iq) * factor; + axpy(fac, grdUhAtQP[iq], result[iq]); + } +}; +double Mobility_SOT::f(const int iq) const +{ + double mobility= 0.5*(3.0-rho[iq]/density)*rho0; +// double phase = 0.5*(1.0-tanh(3.0*(eps-mobility)/0.1)); + return std::max(mobility, eps); +}; + +/* ----------------------------------------------------------- */ + +MobilityCH_SOT::MobilityCH_SOT(DOFVectorBase<double> *chDV_, double factor_) + : SecondOrderTerm(4), chDV(chDV_), factor(factor_) +{ + setSymmetric(true); + + TEST_EXIT(chDV)("No vector!\n"); + auxFeSpaces.insert(chDV->getFeSpace()); + delta = 1.e-6; +}; +void MobilityCH_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + getVectorAtQPs(chDV, elInfo, subAssembler, quad, ch); +}; +void MobilityCH_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + getVectorAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, ch); +}; +void MobilityCH_SOT::getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(LALt.size()); + + for (int iq = 0; iq < nPoints; iq++) + l1lt(Lambda, LALt[iq], f(iq) * factor); +}; +void MobilityCH_SOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + if (num_rows(D2UhAtQP) > 0) { + for (int iq = 0; iq < nPoints; iq++) { + double feval = f(iq) * opFactor * factor; + double resultQP = 0.0; + for (int i = 0; i < dimOfWorld; i++) + resultQP += D2UhAtQP[iq][i][i]; + result[iq] += feval * resultQP; + } + } +}; +void MobilityCH_SOT::weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result) +{ + int nPoints = grdUhAtQP.size(); + for (int iq = 0; iq < nPoints; iq++) { + double fac = f(iq) * factor; + axpy(fac, grdUhAtQP[iq], result[iq]); + } +}; +double MobilityCH_SOT::f(const int iq) const +{ + double phase= std::max(-1.0,std::min(1.0,ch[iq])); + double mobility= 0.25*sqr(sqr(phase)-1.0); + return std::max(mobility, delta); +}; + + +/* ----------------------------------------------------------- */ + +MobilityCH2_SOT::MobilityCH2_SOT(DOFVectorBase<double> *chDV_, double factor_) + : SecondOrderTerm(4), chDV(chDV_), factor(factor_) +{ + setSymmetric(true); + + TEST_EXIT(chDV)("No vector!\n"); + auxFeSpaces.insert(chDV->getFeSpace()); + delta = 1.e-6; +}; +void MobilityCH2_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + getVectorAtQPs(chDV, elInfo, subAssembler, quad, ch); +}; +void MobilityCH2_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + getVectorAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, ch); +}; +void MobilityCH2_SOT::getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(LALt.size()); + + for (int iq = 0; iq < nPoints; iq++) + l1lt(Lambda, LALt[iq], f(iq) * factor); +}; +void MobilityCH2_SOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + if (num_rows(D2UhAtQP) > 0) { + for (int iq = 0; iq < nPoints; iq++) { + double feval = f(iq) * opFactor * factor; + double resultQP = 0.0; + for (int i = 0; i < dimOfWorld; i++) + resultQP += D2UhAtQP[iq][i][i]; + result[iq] += feval * resultQP; + } + } +}; +void MobilityCH2_SOT::weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result) +{ + int nPoints = grdUhAtQP.size(); + for (int iq = 0; iq < nPoints; iq++) { + double fac = f(iq) * factor; + axpy(fac, grdUhAtQP[iq], result[iq]); + } +}; +double MobilityCH2_SOT::f(const int iq) const +{ + double phase= std::max(0.0,std::min(1.0,ch[iq])); + + double mobility= 0.25*sqr(phase)*sqr(phase-1.0); + return std::max(mobility, delta); +}; + +/* ----------------------------------------------------------- */ + +MobilityCHPhase_SOT::MobilityCHPhase_SOT(DOFVectorBase<double>* phaseDV_, DOFVectorBase<double> *chDV_, double factor_) + : Phase_SOT(phaseDV_, factor_), chDV(chDV_) +{ + setSymmetric(true); + + TEST_EXIT(chDV)("No vector!\n"); + auxFeSpaces.insert(chDV->getFeSpace()); + delta = 1.e-6; +}; +void MobilityCHPhase_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + Phase_SOT::initElement(elInfo,subAssembler,quad); + getVectorAtQPs(chDV, elInfo, subAssembler, quad, ch); +}; +void MobilityCHPhase_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + Phase_SOT::initElement(largeElInfo, smallElInfo,subAssembler,quad); + getVectorAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, ch); +}; +double MobilityCHPhase_SOT::f(const int iq) const +{ + double phase= std::max(-1.0,std::min(1.0,ch[iq])); + double mobility= 0.25*sqr(sqr(phase)-1.0); + + return std::max(mobility, delta); +}; + + +/* ----------------------------------------------------------- */ + +Mobility2CHPhase_FOT::Mobility2CHPhase_FOT( + DOFVectorBase<double>* phaseDV_, + DOFVectorBase<double> *chDV_, + DOFVectorBase<double> *muDV_, + double factor_) + : Phase_FOT(phaseDV_, factor_), chDV(chDV_), muDV(muDV_) +{ + TEST_EXIT(chDV)("No vector!\n"); + auxFeSpaces.insert(chDV->getFeSpace()); + auxFeSpaces.insert(muDV->getFeSpace()); + delta = 1.e-6; +}; +void Mobility2CHPhase_FOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + Phase_FOT::initElement(elInfo,subAssembler,quad); + getVectorAtQPs(chDV, elInfo, subAssembler, quad, ch); + getGradientsAtQPs(muDV, elInfo, subAssembler, quad, grdMu); +}; +void Mobility2CHPhase_FOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + Phase_FOT::initElement(largeElInfo, smallElInfo,subAssembler,quad); + getVectorAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, ch); + getGradientsAtQPs(muDV, smallElInfo, largeElInfo, subAssembler, quad, grdMu); +}; +WorldVector<double> Mobility2CHPhase_FOT::f(const int iq) const +{ + double mobility= sqr(ch[iq])*ch[iq]-ch[iq]; + return mobility*grdMu[iq]; +}; + +/* ----------------------------------------------------------- */ + + +MatrixPhase_SOT::MatrixPhase_SOT(DOFVectorBase<double>* phaseDV_, int comp_, double fac_) : + SecondOrderTerm(6), phaseDV(phaseDV_), comp(comp_), fac(fac_), symmetric(true) +{ + TEST_EXIT(phaseDV_)("no vector phase!\n"); + auxFeSpaces.insert(phaseDV_->getFeSpace()); +}; +void MatrixPhase_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(phaseDV, elInfo, subAssembler, quad, phase); +}; +void MatrixPhase_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(phaseDV, smallElInfo, largeElInfo, subAssembler, quad, phase); +}; + +/// Evaluation of \f$ \Lambda \cdot A \cdot \Lambda^t\f$ for A equal to the diagonal matrix. +void MatrixPhase_SOT::lDlt(const DimVec<WorldVector<double> >& Lambda, + const WorldVector<double>& vec, + mtl::dense2D<double>& LALt, + double factor) const +{ + const int dim = num_rows(LALt); + + for (int i = 0; i < dim; i++) { + double val = 0.0; + for (int k = 0; k < dimOfWorld; k++) + val += vec[k] * Lambda[i][k] * Lambda[i][k]; + val *= factor; + LALt[i][i] += val; + for (int j = i + 1; j < dim; j++) { + val = 0.0; + for (int k = 0; k < dimOfWorld; k++) + val += vec[k] * Lambda[i][k] * Lambda[j][k]; + val *= factor; + LALt[i][j] += val; + LALt[j][i] += val; + } + } +}; +void MatrixPhase_SOT::getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(LALt.size()); + + for (int iq = 0; iq < nPoints; iq++) { + lDlt(Lambda, f(iq), LALt[iq], phase[iq] * fac); + } +}; +void MatrixPhase_SOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + if (num_rows(D2UhAtQP) > 0) { + double factor = opFactor * fac; + for (int iq = 0; iq < nPoints; iq++) { + WorldVector<double> D = f(iq); + double resultQP = 0.0; + + for (int i = 0; i < dimOfWorld; i++) { + double resultI= 0.0; + for (int j = 0; j < dimOfWorld; j++) { + resultI += D2UhAtQP[iq][j][i]; + } + resultQP+= D[i] * resultI; + } + result[iq] += resultQP * factor * phase[iq]; + } + } +}; +void MatrixPhase_SOT::weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result) +{ + const int nPoints = static_cast<int>(grdUhAtQP.size()); + for (int iq = 0; iq < nPoints; iq++) { + WorldVector<double> multVec = f(iq); + for (int i = 0; i < grdUhAtQP[iq].getSize(); ++i) + multVec[i]*= grdUhAtQP[iq][i]; + result[iq] += multVec * (phase[iq] * fac); + } +}; +WorldVector<double> MatrixPhase_SOT::f(const int iq) const +{ + WorldVector<double> result; + result[1-comp]=1.0; + result[comp]=2.0; + return result; +}; + + +/* ----------------------------------------------------------- */ + + +MatrixIJ_SOT::MatrixIJ_SOT(int row_, int col_, double fac_) : + SecondOrderTerm(1), row(row_), col(col_), fac(fac_), symmetric(true) +{ +}; +void MatrixIJ_SOT::getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(LALt.size()); + + for (int iq = 0; iq < nPoints; iq++) { + lalt_kl(Lambda, row, col, LALt[iq], fac); + } +}; +void MatrixIJ_SOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = opFactor * fac; + if (num_rows(D2UhAtQP) > 0) { + for (int iq = 0; iq < nPoints; iq++) { + result[iq] += D2UhAtQP[iq][row][col] * factor; + } + } +}; +void MatrixIJ_SOT::weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result) +{ + const int nPoints = static_cast<int>(grdUhAtQP.size()); + for (int iq = 0; iq < nPoints; iq++) { + result[iq][row] += grdUhAtQP[iq][col] * fac; + } +}; + +/* ----------------------------------------------------------- */ + + +MatrixIJPhase_SOT::MatrixIJPhase_SOT(DOFVectorBase<double>* phaseDV_, int row_, int col_, double fac_) : + SecondOrderTerm(6), phaseDV(phaseDV_), row(row_), col(col_), fac(fac_), symmetric(true) +{ + TEST_EXIT(phaseDV_)("no vector phase!\n"); + auxFeSpaces.insert(phaseDV_->getFeSpace()); +}; +void MatrixIJPhase_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(phaseDV, elInfo, subAssembler, quad, phase); +}; +void MatrixIJPhase_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(phaseDV, smallElInfo, largeElInfo, subAssembler, quad, phase); +}; +void MatrixIJPhase_SOT::getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(LALt.size()); + + for (int iq = 0; iq < nPoints; iq++) { + lalt_kl(Lambda, row, col, LALt[iq], phase[iq] * fac); + } +}; +void MatrixIJPhase_SOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = opFactor * fac; + if (num_rows(D2UhAtQP) > 0) { + for (int iq = 0; iq < nPoints; iq++) { + result[iq] += D2UhAtQP[iq][row][col] * factor; + } + } +}; +void MatrixIJPhase_SOT::weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result) +{ + const int nPoints = static_cast<int>(grdUhAtQP.size()); + for (int iq = 0; iq < nPoints; iq++) { + result[iq][row] += grdUhAtQP[iq][col] * fac; + } +}; + +/* ----------------------------------------------------------- */ + +MatrixIJViscosityPhase_SOT::MatrixIJViscosityPhase_SOT(DOFVectorBase<double>* phaseDV_, DOFVectorBase<double>* chDV_, int row_, int col_, double v1_, double v2_, double fac_) : + SecondOrderTerm(6), phaseDV(phaseDV_), chDV(chDV_), row(row_), col(col_), v1(v1_), v2(v2_), fac(fac_), symmetric(true) +{ + TEST_EXIT(phaseDV_)("no vector phase!\n"); + auxFeSpaces.insert(phaseDV_->getFeSpace()); + auxFeSpaces.insert(chDV_->getFeSpace()); +}; +void MatrixIJViscosityPhase_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(phaseDV, elInfo, subAssembler, quad, phase); + getVectorAtQPs(chDV, elInfo, subAssembler, quad, ch); +}; +void MatrixIJViscosityPhase_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(phaseDV, smallElInfo, largeElInfo, subAssembler, quad, phase); + getVectorAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, ch); +}; +void MatrixIJViscosityPhase_SOT::getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(LALt.size()); + + for (int iq = 0; iq < nPoints; iq++) { + lalt_kl(Lambda, row, col, LALt[iq], phase[iq] * f(iq) * fac); + } +}; +void MatrixIJViscosityPhase_SOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = opFactor * fac; + if (num_rows(D2UhAtQP) > 0) { + for (int iq = 0; iq < nPoints; iq++) { + result[iq] += D2UhAtQP[iq][row][col] * phase[iq] * f(iq) * factor; + } + } +}; +void MatrixIJViscosityPhase_SOT::weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result) +{ + const int nPoints = static_cast<int>(grdUhAtQP.size()); + for (int iq = 0; iq < nPoints; iq++) { + result[iq][row] += grdUhAtQP[iq][col] * phase[iq] * f(iq) * fac; + } +}; +double MatrixIJViscosityPhase_SOT::f(const int iq) const +{ + double phase= std::max(-1.0,std::min(1.0,ch[iq])); + double viscosity= v1*0.5*(phase+1.0)-v2*0.5*(phase-1.0); + return viscosity; +}; + +/* ----------------------------------------------------------- */ + +MatrixIJViscosity_SOT::MatrixIJViscosity_SOT(DOFVectorBase<double>* chDV_, int row_, int col_, double v1_, double v2_, double fac_) : + SecondOrderTerm(6), chDV(chDV_), row(row_), col(col_), v1(v1_), v2(v2_), fac(fac_), symmetric(true) +{ + TEST_EXIT(chDV_)("no vector phase!\n"); + auxFeSpaces.insert(chDV_->getFeSpace()); +}; +void MatrixIJViscosity_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(chDV, elInfo, subAssembler, quad, ch); +}; +void MatrixIJViscosity_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, ch); +}; +void MatrixIJViscosity_SOT::getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(LALt.size()); + + for (int iq = 0; iq < nPoints; iq++) { + lalt_kl(Lambda, row, col, LALt[iq], f(iq) * fac); + } +}; +void MatrixIJViscosity_SOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = opFactor * fac; + if (num_rows(D2UhAtQP) > 0) { + for (int iq = 0; iq < nPoints; iq++) { + result[iq] += D2UhAtQP[iq][row][col] * f(iq) * factor; + } + } +}; +void MatrixIJViscosity_SOT::weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result) +{ + const int nPoints = static_cast<int>(grdUhAtQP.size()); + for (int iq = 0; iq < nPoints; iq++) { + result[iq][row] += grdUhAtQP[iq][col] * f(iq) * fac; + } +}; +double MatrixIJViscosity_SOT::f(const int iq) const +{ + double phase= std::max(-1.0,std::min(1.0,ch[iq])); + double viscosity= v1*0.5*(phase+1.0)-v2*0.5*(phase-1.0); + return viscosity; +}; + +/* ----------------------------------------------------------- */ + + +MatrixIJViscosityPhase2_SOT::MatrixIJViscosityPhase2_SOT(DOFVectorBase<double>* phaseDV_, DOFVectorBase<double>* chDV_, int row_, int col_, double v1_, double v2_, double fac_) : + SecondOrderTerm(6), phaseDV(phaseDV_), chDV(chDV_), row(row_), col(col_), v1(v1_), v2(v2_), fac(fac_), symmetric(true) +{ + TEST_EXIT(phaseDV_)("no vector phase!\n"); + auxFeSpaces.insert(phaseDV_->getFeSpace()); + auxFeSpaces.insert(chDV_->getFeSpace()); +}; +void MatrixIJViscosityPhase2_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(phaseDV, elInfo, subAssembler, quad, phase); + getVectorAtQPs(chDV, elInfo, subAssembler, quad, ch); +}; +void MatrixIJViscosityPhase2_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getVectorAtQPs(phaseDV, smallElInfo, largeElInfo, subAssembler, quad, phase); + getVectorAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, ch); +}; +void MatrixIJViscosityPhase2_SOT::getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(LALt.size()); + + for (int iq = 0; iq < nPoints; iq++) { + lalt_kl(Lambda, row, col, LALt[iq], phase[iq] * f(iq) * fac); + } +}; +void MatrixIJViscosityPhase2_SOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = opFactor * fac; + if (num_rows(D2UhAtQP) > 0) { + for (int iq = 0; iq < nPoints; iq++) { + result[iq] += D2UhAtQP[iq][row][col] * phase[iq] * f(iq) * factor; + } + } +}; +void MatrixIJViscosityPhase2_SOT::weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result) +{ + const int nPoints = static_cast<int>(grdUhAtQP.size()); + for (int iq = 0; iq < nPoints; iq++) { + result[iq][row] += grdUhAtQP[iq][col] * phase[iq] * f(iq) * fac; + } +}; +double MatrixIJViscosityPhase2_SOT::f(const int iq) const +{ + double phase= std::max(0.0,std::min(1.0,ch[iq])); + double viscosity= v1*phase+v2*(1.0-phase); + return viscosity; +}; + +/* ----------------------------------------------------------- */ + +WettingAngle_ZOT::WettingAngle_ZOT(DOFVectorBase<double> *vecDV_, DOFVectorBase<double> *gradDV_, double fac_) + : ZeroOrderTerm(1), vecDV(vecDV_), gradDV(gradDV_), fac(fac_) +{ + TEST_EXIT(vecDV_)("No first vector!\n"); + auxFeSpaces.insert(vecDV_->getFeSpace()); + auxFeSpaces.insert(gradDV_->getFeSpace()); +}; +void WettingAngle_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ +// getVectorAtQPs(vecDV, elInfo, subAssembler, quad, vec); + getGradientsAtQPs(vecDV, elInfo, subAssembler, quad, gradC); + getGradientsAtQPs(gradDV, elInfo, subAssembler, quad, grad); +}; +void WettingAngle_ZOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ +// getVectorAtQPs(vecDV, smallElInfo, largeElInfo, subAssembler, quad, vec); + getGradientsAtQPs(vecDV, smallElInfo, largeElInfo, subAssembler, quad, gradC); + getGradientsAtQPs(gradDV, smallElInfo, largeElInfo, subAssembler, quad, grad); +}; +void WettingAngle_ZOT::getC(const ElInfo *, int nPoints, ElementVector &C) +{ + for (int iq = 0; iq < nPoints; iq++) + C[iq] += f(iq)*fac; +}; +void WettingAngle_ZOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + for (int iq = 0; iq < nPoints; iq++) { + result[iq] += f(iq) * uhAtQP[iq] * opFactor * fac; + } +}; +double WettingAngle_ZOT::f(const int iq) const +{ +// double c= std::max(-1.0, std::min(1.0, vec[iq]) ); + return norm(gradC[iq])*norm(grad[iq]); +}; + +/* ----------------------------------------------------------- */ + +WettingAngleExpl_ZOT::WettingAngleExpl_ZOT(DOFVectorBase<double> *vecDV_, DOFVectorBase<double> *gradDV_, double fac_) + : WettingAngle_ZOT(vecDV_,gradDV_,fac_) +{ + ERROR("Not implementet!\n"); +}; +double WettingAngleExpl_ZOT::f(const int iq) const +{ +// double c= std::max(-1.0, std::min(1.0, vec[iq]) ); + return 1.0*norm(grad[iq]); +}; + +/* ----------------------------------------------------------- */ + +WettingAngleImpl_ZOT::WettingAngleImpl_ZOT(DOFVectorBase<double> *vecDV_, DOFVectorBase<double> *gradDV_, double fac_) + : WettingAngle_ZOT(vecDV_,gradDV_,fac_) +{ + ERROR("Not implementet!\n"); +}; +double WettingAngleImpl_ZOT::f(const int iq) const +{ +// double c= std::max(-1.0, std::min(1.0, vec[iq]) ); + return 2.0*norm(grad[iq]); +}; + + +/* ----------------------------------------------------------- */ + +WettingAngleImpl_FOT::WettingAngleImpl_FOT(DOFVectorBase<double>* chDV_,DOFVectorBase<double>* phaseDV_,double fac_) : + FirstOrderTerm(2), chDV(chDV_), phaseDV(phaseDV_), fac(fac_) +{ + TEST_EXIT(phaseDV_)("no vector phase!\n"); + auxFeSpaces.insert(chDV_->getFeSpace()); + auxFeSpaces.insert(phaseDV_->getFeSpace()); +}; +void WettingAngleImpl_FOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getGradientsAtQPs(chDV, elInfo, subAssembler, quad, gradCh); + getGradientsAtQPs(phaseDV, elInfo, subAssembler, quad, gradPhase); +}; +void WettingAngleImpl_FOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) { + getGradientsAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, gradCh); + getGradientsAtQPs(phaseDV, smallElInfo, largeElInfo, subAssembler, quad, gradPhase); +}; +void WettingAngleImpl_FOT::getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(result.size()); + + for (int iq = 0; iq < nPoints; iq++) { + lb(Lambda, f(iq), result[iq], fac); + } +}; +void WettingAngleImpl_FOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + double factor = fac * opFactor; + for (int iq = 0; iq < nPoints; iq++) { + double resultQP = grdUhAtQP[iq] * f(iq); + result[iq] += factor * resultQP; + } +}; + +WorldVector<double> WettingAngleImpl_FOT::f(const int iq) const +{ + WorldVector<double> result; result.set(0.0); + double nrmGradCh = norm(gradCh[iq]); + if (nrmGradCh > DBL_TOL) { + result = (2.0 * norm(gradPhase[iq]) / nrmGradCh) * gradCh[iq]; + } + return result; +}; + +/* ----------------------------------------------------------- */ +/* ----------------------------------------------------------- */ + +WettingAngle_Sharp_ZOT::WettingAngle_Sharp_ZOT(DOFVectorBase<double> *vecDV_, double fac_) + : ZeroOrderTerm(1), vecDV(vecDV_), fac(fac_) +{ + TEST_EXIT(vecDV_)("No first vector!\n"); + auxFeSpaces.insert(vecDV_->getFeSpace()); +}; +void WettingAngle_Sharp_ZOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getGradientsAtQPs(vecDV, elInfo, subAssembler, quad, grad); +}; +void WettingAngle_Sharp_ZOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad) +{ + getGradientsAtQPs(vecDV, smallElInfo, largeElInfo, subAssembler, quad, grad); +}; +void WettingAngle_Sharp_ZOT::getC(const ElInfo *, int nPoints, ElementVector &C) +{ + for (int iq = 0; iq < nPoints; iq++) + C[iq] += f(iq)*fac; +}; +void WettingAngle_Sharp_ZOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + for (int iq = 0; iq < nPoints; iq++) { + result[iq] += f(iq) * uhAtQP[iq] * opFactor * fac; + } +}; +double WettingAngle_Sharp_ZOT::f(const int iq) const +{ + double c= norm(grad[iq]); + return c; +}; + +/* ----------------------------------------------------------- */ + +WettingAngleExpl_Sharp_ZOT::WettingAngleExpl_Sharp_ZOT(DOFVectorBase<double> *vecDV_, double fac_) + : WettingAngle_Sharp_ZOT(vecDV_,fac_) +{ + ERROR("Not implementet!\n"); +}; +double WettingAngleExpl_Sharp_ZOT::f(const int iq) const +{ +// double c= std::max(-1.0, std::min(1.0, vec[iq]) ); + return 1.0; +}; + +/* ----------------------------------------------------------- */ + +WettingAngleImpl_Sharp_ZOT::WettingAngleImpl_Sharp_ZOT(DOFVectorBase<double> *vecDV_, double fac_) + : WettingAngle_Sharp_ZOT(vecDV_,fac_) +{ + ERROR("Not implementet!\n"); +}; +double WettingAngleImpl_Sharp_ZOT::f(const int iq) const +{ +// double c= std::max(-1.0, std::min(1.0, vec[iq]) ); + return 2.0; +}; + + +/* ----------------------------------------------------------- */ + +ViscosityPhase_SOT::ViscosityPhase_SOT(DOFVectorBase<double> *phaseDV_, DOFVectorBase<double> *chDV_, double v1_, double v2_, double factor_) + : Phase_SOT(phaseDV_,factor_), chDV(chDV_), v1(v1_), v2(v2_) +{ + setSymmetric(true); + + TEST_EXIT(chDV)("No vector!\n"); + auxFeSpaces.insert(chDV->getFeSpace()); +}; +void ViscosityPhase_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + Phase_SOT::initElement(elInfo, subAssembler, quad); + getVectorAtQPs(chDV, elInfo, subAssembler, quad, ch); +}; +void ViscosityPhase_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + Phase_SOT::initElement(smallElInfo, largeElInfo, subAssembler, quad); + getVectorAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, ch); +}; +double ViscosityPhase_SOT::f(const int iq) const +{ + double phase= std::max(-1.0,std::min(1.0,ch[iq])); + double viscosity= v1*0.5*(phase+1.0)-v2*0.5*(phase-1.0); + return viscosity; +}; + +/* ----------------------------------------------------------- */ + +Viscosity_SOT::Viscosity_SOT(DOFVectorBase<double> *chDV_, double v1_, double v2_, double factor_) + : SecondOrderTerm(1), chDV(chDV_), v1(v1_), v2(v2_), factor(factor_) +{ + setSymmetric(true); + + TEST_EXIT(chDV)("No vector!\n"); + auxFeSpaces.insert(chDV->getFeSpace()); +}; +void Viscosity_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + getVectorAtQPs(chDV, elInfo, subAssembler, quad, ch); +}; +void Viscosity_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + getVectorAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, ch); +}; +void Viscosity_SOT::getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(LALt.size()); + + for (int iq = 0; iq < nPoints; iq++) + l1lt(Lambda, LALt[iq], f(iq) * factor); +}; +void Viscosity_SOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + if (num_rows(D2UhAtQP) > 0) { + for (int iq = 0; iq < nPoints; iq++) { + double feval = f(iq) * opFactor * factor; + double resultQP = 0.0; + for (int i = 0; i < dimOfWorld; i++) + resultQP += D2UhAtQP[iq][i][i]; + result[iq] += feval * resultQP; + } + } +}; +void Viscosity_SOT::weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result) +{ + int nPoints = grdUhAtQP.size(); + for (int iq = 0; iq < nPoints; iq++) { + double fac = f(iq) * factor; + axpy(fac, grdUhAtQP[iq], result[iq]); + } +}; +double Viscosity_SOT::f(const int iq) const +{ + double phase= std::max(-1.0,std::min(1.0,ch[iq])); + double viscosity= v1*0.5*(phase+1.0)-v2*0.5*(phase-1.0); + return viscosity; +}; + +/* ----------------------------------------------------------- */ + +/* ----------------------------------------------------------- */ + +ViscosityPhase2_SOT::ViscosityPhase2_SOT(DOFVectorBase<double> *phaseDV_, DOFVectorBase<double> *chDV_, double v1_, double v2_, double factor_) + : Phase_SOT(phaseDV_,factor_), chDV(chDV_), v1(v1_), v2(v2_) +{ + setSymmetric(true); + + TEST_EXIT(chDV)("No vector!\n"); + auxFeSpaces.insert(chDV->getFeSpace()); +}; +void ViscosityPhase2_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + Phase_SOT::initElement(elInfo, subAssembler, quad); + getVectorAtQPs(chDV, elInfo, subAssembler, quad, ch); +}; +void ViscosityPhase2_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + Phase_SOT::initElement(smallElInfo, largeElInfo, subAssembler, quad); + getVectorAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, ch); +}; +double ViscosityPhase2_SOT::f(const int iq) const +{ + double phase= std::max(0.0,std::min(1.0,ch[iq])); + double viscosity= v1*phase+v2*(1.0-phase); + return viscosity; +}; + +/* ----------------------------------------------------------- */ + +Viscosity2_SOT::Viscosity2_SOT(DOFVectorBase<double> *chDV_, double v1_, double v2_, double factor_) + : SecondOrderTerm(1), chDV(chDV_), v1(v1_), v2(v2_), factor(factor_) +{ + setSymmetric(true); + + TEST_EXIT(chDV)("No vector!\n"); + auxFeSpaces.insert(chDV->getFeSpace()); +}; +void Viscosity2_SOT::initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + getVectorAtQPs(chDV, elInfo, subAssembler, quad, ch); +}; +void Viscosity2_SOT::initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature* quad) +{ + getVectorAtQPs(chDV, smallElInfo, largeElInfo, subAssembler, quad, ch); +}; +void Viscosity2_SOT::getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const +{ + const DimVec<WorldVector<double> > &Lambda = elInfo->getGrdLambda(); + const int nPoints = static_cast<int>(LALt.size()); + + for (int iq = 0; iq < nPoints; iq++) + l1lt(Lambda, LALt[iq], f(iq) * factor); +}; +void Viscosity2_SOT::eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor) +{ + if (num_rows(D2UhAtQP) > 0) { + for (int iq = 0; iq < nPoints; iq++) { + double feval = f(iq) * opFactor * factor; + double resultQP = 0.0; + for (int i = 0; i < dimOfWorld; i++) + resultQP += D2UhAtQP[iq][i][i]; + result[iq] += feval * resultQP; + } + } +}; +void Viscosity2_SOT::weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result) +{ + int nPoints = grdUhAtQP.size(); + for (int iq = 0; iq < nPoints; iq++) { + double fac = f(iq) * factor; + axpy(fac, grdUhAtQP[iq], result[iq]); + } +}; +double Viscosity2_SOT::f(const int iq) const +{ + double phase= std::max(0.0,std::min(1.0,ch[iq])); + double viscosity= v1*phase+v2*(1.0-phase); + return viscosity; +}; diff --git a/extensions/POperators.h b/extensions/POperators.h new file mode 100644 index 0000000000000000000000000000000000000000..c134970536a7ab0087d3988c31f91dc6b189b6aa --- /dev/null +++ b/extensions/POperators.h @@ -0,0 +1,10 @@ +/** \file POperators.h */ + +#ifndef P_OPERATORS_H +#define P_OPERATORS_H + +#include "POperators_ZOT.h" +#include "POperators_FOT.h" +#include "POperators_SOT.h" + +#endif // P_OPERATORS_H diff --git a/extensions/POperators_FOT.h b/extensions/POperators_FOT.h new file mode 100644 index 0000000000000000000000000000000000000000..af232352f38032ed3e175b2fdc75a649eb9a7659 --- /dev/null +++ b/extensions/POperators_FOT.h @@ -0,0 +1,422 @@ +/** \file POperators_FOT.h */ + +#ifndef P_OPERATORS_FOT_H +#define P_OPERATORS_FOT_H + +#include "AMDiS.h" + +using namespace std; +using namespace AMDiS; + + +/// < factor*phase*grad(u) , grad(psi) > +class Phase_FOT : public FirstOrderTerm +{ +public: +/// Constructor. +Phase_FOT(DOFVectorBase<double>* phaseDV, double fac=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implementation of \ref OperatorTerm::initElement() for multilpe meshes. +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +void getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const; + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +virtual WorldVector<double> f(const int iq) const; +void setFactor(const double fac_) { fac=fac_; } + +protected: +DOFVectorBase<double> *phaseDV; +mtl::dense_vector<double> phase; +double fac; +}; + +/// < phase*(vecs*grad(u)) , psi > or < phase*vecs*u , grad(psi) > where vecs in R^n +class WorldVecAndVecFct_FOT : public FirstOrderTerm +{ +public: +WorldVecAndVecFct_FOT(WorldVector<DOFVectorBase<double>*> vecs, + DOFVectorBase<double>* phaseDV_, double fac=1.0); + +void initElement(const ElInfo*, + SubAssembler* , + Quadrature *quad= NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + +void getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const; + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +protected: +DOFVectorBase<double> *vec0DV, *vec1DV, *vec2DV, *phaseDV; +mtl::dense_vector<double> phase, vec0, vec1, vec2; +double fac; +int numVecs; +}; + + + +/* -------------------------------------------------------------- */ + +/// < vecs*grad(u) , psi > or < vecs*u , grad(psi) > where vecs in R^n +class WorldVec_FOT : public FirstOrderTerm +{ +public: +WorldVec_FOT(WorldVector<DOFVector<double>*> vecs,double fac=1.0); + +void initElement(const ElInfo*, + SubAssembler* , + Quadrature *quad= NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + +void getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const; + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +protected: +DOFVectorBase<double> *vec0DV, *vec1DV, *vec2DV; +mtl::dense_vector<double> vec0, vec1, vec2; +double fac; +int numVecs; +}; + +/* -------------------------------------------------------------- */ + +/// First order term: \f$ < \vec{v}(\vec{x}) \cdot \nabla u(\vec{x}) , \theta > or < \vec{v}(\vec{x}) \cdot u(\vec{x}) , \nabla \theta >\f$. +class WorldVector_FOT : public FirstOrderTerm +{ +public: + /// Constructor. + WorldVector_FOT(DOFVector<WorldVector<double> > *dv, double fac_=1.0); + + /// Implementation of \ref OperatorTerm::initElement(). + void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + + void initElement(const ElInfo* largeElInfo, + const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + + /// Implements FirstOrderTerm::getLb(). + void getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& Lb) const; + + /// Implements FirstOrderTerm::eval(). + void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double factor); + +protected: + DOFVector<WorldVector<double> >* vec; + + /// Gradient of v at quadrature points. + mtl::dense_vector<WorldVector<double> > vecAtQPs; + + double fac; +}; + +/// < phase*(vecs*grad(u)) , psi > or < phase*vecs*u , grad(psi) > where vecs in R^n +class WorldVecPhase_FOT : public FirstOrderTerm +{ +public: +WorldVecPhase_FOT(DOFVectorBase<double>* phaseDV_, WorldVector<DOFVector<double>*> vecs, + double fac=1.0); + +void initElement(const ElInfo*, + SubAssembler* , + Quadrature *quad= NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + +void getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const; + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +protected: +DOFVectorBase<double> *vec0DV, *vec1DV, *vec2DV, *phaseDV; +mtl::dense_vector<double> phase, vec0, vec1, vec2; +double fac; +int numVecs; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*d_i(u) , psi > or < factor*u , d_i(psi) > +class PartialDerivative_FOT : public FirstOrderTerm +{ +public: +PartialDerivative_FOT(int component_, double fac_=1.0); + +void initElement(const ElInfo*, + SubAssembler*, + Quadrature *quad= NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + +void getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const; + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +protected: +int component; +double fac; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*v1*d_i(u) , psi > or < factor*v1*u , d_i(psi) > +class VecAndPartialDerivative_FOT : public FirstOrderTerm +{ +public: + +VecAndPartialDerivative_FOT(DOFVectorBase<double> *dv1, int component_, + double fac_=1.0); + +void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +void getLb(const ElInfo *elInfo, vector<mtl::dense_vector<double> >& result) const; + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +protected: +DOFVectorBase<double>* vec1DV; +mtl::dense_vector<double> vec1; +double fac; +int component; +}; +/* -------------------------------------------------------------- */ + + +/// < phase*d_i(u) * n_j , psi > or < phase*u*n_j , d_i(psi) > where vecs in R^n +class PhaseAndViscosityPartialDerivativeBoundary_FOT : public FirstOrderTerm +{ +public: +PhaseAndViscosityPartialDerivativeBoundary_FOT(DOFVectorBase<double>* phaseDV_, DOFVectorBase<double>* chDV_, int component, int normalComponent, double viscosity1=1.0, double viscosity2=1.0); + +void initElement(const ElInfo*, + SubAssembler* , + Quadrature *quad= NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + +void getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const; + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +double f(const int iq) const; +protected: +DOFVectorBase<double> *phaseDV, *chDV; +mtl::dense_vector<double> phase, ch; +double v1, v2, normalJ; +int component, normalComponent; +}; + +/* -------------------------------------------------------------- */ + + +/// < d_i(u) * n_j , psi > or < u*n_j , d_i(psi) > where vecs in R^n +class ViscosityPartialDerivativeBoundary_FOT : public FirstOrderTerm +{ +public: +ViscosityPartialDerivativeBoundary_FOT(DOFVectorBase<double>* chDV_, int component, int normalComponent, double viscosity1=1.0, double viscosity2=1.0); + +void initElement(const ElInfo*, + SubAssembler* , + Quadrature *quad= NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + +void getLb(const ElInfo *elInfo, + vector<mtl::dense_vector<double> >& result) const; + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); +double f(const int iq) const; +protected: +DOFVectorBase<double> *chDV; +mtl::dense_vector<double> ch; +double v1, v2, normalJ; +int component, normalComponent; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*v1*v2*d_i(u) , psi > or < factor*v1*v2*u , d_i(psi) > +class Vec2ProductPartial_FOT : public FirstOrderTerm +{ +public: + +Vec2ProductPartial_FOT(DOFVectorBase<double> *dv1, DOFVectorBase<double> *dv2, + int component_, double fac_=1.0); + +void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +void getLb(const ElInfo *elInfo, vector<mtl::dense_vector<double> >& result) const; + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +protected: +DOFVectorBase<double>* vec1DV; +DOFVectorBase<double>* vec2DV; +mtl::dense_vector<double> vec1,vec2; +double fac; +int component; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*phase*grad(u) , grad(psi) > +class WettingAngleImpl_FOT : public FirstOrderTerm +{ +public: +/// Constructor. +WettingAngleImpl_FOT(DOFVectorBase<double>* chDV, DOFVectorBase<double>* phaseDV, double fac=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implementation of \ref OperatorTerm::initElement() for multilpe meshes. +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +void getLb(const ElInfo *elInfo, vector<mtl::dense_vector<double> >& result) const; + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +inline WorldVector<double> f(const int iq) const; +void setFactor(const double fac_) { fac=fac_; } + +protected: +DOFVectorBase<double> *phaseDV, *chDV; + +mtl::dense_vector<WorldVector<double> > gradPhase, gradCh; +double fac; +}; +/* -------------------------------------------------------------- */ + +class Mobility2CHPhase_FOT : public Phase_FOT +{ +public: +/// Constructor. +Mobility2CHPhase_FOT( + DOFVectorBase<double>* phaseDV, + DOFVectorBase<double> *chDV_, + DOFVectorBase<double> *muDV_, + double factor_=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implementation of \ref OperatorTerm::initElement() for multilpe meshes. +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +inline WorldVector<double> f(const int iq) const; + +protected: + +/** \brief +* DOFVector to be evaluated at quadrature points. +*/ +DOFVectorBase<double>* chDV; +DOFVectorBase<double>* muDV; + +/** \brief +* Vector v at quadrature points. +*/ +mtl::dense_vector<double> ch; +mtl::dense_vector<WorldVector<double> > grdMu; +double delta; + +}; + +#endif // P_OPERATORS_FOT_H diff --git a/extensions/POperators_SOT.h b/extensions/POperators_SOT.h new file mode 100644 index 0000000000000000000000000000000000000000..aea50850b1f666ead10e83e072c818314eaf67cf --- /dev/null +++ b/extensions/POperators_SOT.h @@ -0,0 +1,625 @@ +/** \file POperators_SOT.h */ + +#ifndef P_OPERATORS_SOT_H +#define P_OPERATORS_SOT_H + +#include "AMDiS.h" + +using namespace std; +using namespace AMDiS; + +/// < factor*phase*grad(u) , grad(psi) > +class Phase_SOT : public SecondOrderTerm +{ +public: +/// Constructor. +Phase_SOT(DOFVectorBase<double>* phaseDV, double fac=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implementation of \ref OperatorTerm::initElement() for multilpe meshes. +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implements SecondOrderTerm::getLALt(). +inline void getLALt(const ElInfo *elInfo, std::vector<mtl::dense2D<double> > &LALt) const; + +/// Implenetation of SecondOrderTerm::eval(). +inline void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +/// Implenetation of SecondOrderTerm::weakEval(). +void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result); + +virtual double f(const int iq) const; +void setFactor(const double fac_) { fac=fac_; } + +protected: +DOFVectorBase<double> *phaseDV; +mtl::dense_vector<double> phase; +double fac; +}; + +/* -------------------------------------------------------------- */ + +class Mobility_SOT : public SecondOrderTerm +{ +public: +/// Constructor. +Mobility_SOT(DOFVectorBase<double> *rhoDV_, double factor_=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implementation of \ref OperatorTerm::initElement() for multilpe meshes. +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +void getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const; + +void eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result); + +inline double f(const int iq) const; + +protected: + +/** \brief +* DOFVector to be evaluated at quadrature points. +*/ +DOFVectorBase<double>* rhoDV; + +/** \brief +* Vector v at quadrature points. +*/ +mtl::dense_vector<double> rho; +double factor, eps, rho0, density, mobilityDerivative; + +}; + +/* -------------------------------------------------------------- */ + +class MobilityCH_SOT : public SecondOrderTerm +{ +public: +/// Constructor. +MobilityCH_SOT(DOFVectorBase<double> *chDV_, double factor_=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implementation of \ref OperatorTerm::initElement() for multilpe meshes. +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +void getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const; + +void eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result); + +inline double f(const int iq) const; + +protected: + +/** \brief +* DOFVector to be evaluated at quadrature points. +*/ +DOFVectorBase<double>* chDV; + +/** \brief +* Vector v at quadrature points. +*/ +mtl::dense_vector<double> ch; +double factor, delta; + +}; + +/* -------------------------------------------------------------- */ + +class MobilityCHPhase_SOT : public Phase_SOT +{ +public: +/// Constructor. +MobilityCHPhase_SOT(DOFVectorBase<double>* phaseDV, DOFVectorBase<double> *chDV_, double factor_=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implementation of \ref OperatorTerm::initElement() for multilpe meshes. +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +inline double f(const int iq) const; + +protected: + +/** \brief +* DOFVector to be evaluated at quadrature points. +*/ +DOFVectorBase<double>* chDV; + +/** \brief +* Vector v at quadrature points. +*/ +mtl::dense_vector<double> ch; +double delta; + +}; + +/* -------------------------------------------------------------- */ + +class MobilityCH2_SOT : public SecondOrderTerm +{ +public: +/// Constructor. +MobilityCH2_SOT(DOFVectorBase<double> *chDV_, double factor_=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implementation of \ref OperatorTerm::initElement() for multilpe meshes. +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +void getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const; + +void eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result); + +inline double f(const int iq) const; + +protected: + +/** \brief +* DOFVector to be evaluated at quadrature points. +*/ +DOFVectorBase<double>* chDV; + +/** \brief +* Vector v at quadrature points. +*/ +mtl::dense_vector<double> ch; +double factor, delta; + +}; + +/* -------------------------------------------------------------- */ + +class ViscosityPhase_SOT : public Phase_SOT +{ +public: +/// Constructor. +ViscosityPhase_SOT(DOFVectorBase<double> *phaseDV_, DOFVectorBase<double> *chDV_, double v1_=1.0, double v2_=1.0, double factor_=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implementation of \ref OperatorTerm::initElement() for multilpe meshes. +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +inline double f(const int iq) const; + +protected: + +/** \brief +* DOFVector to be evaluated at quadrature points. +*/ +DOFVectorBase<double>* chDV; + +/** \brief +* Vector v at quadrature points. +*/ +mtl::dense_vector<double> ch; +double v1,v2; + +}; + +/* -------------------------------------------------------------- */ + +class ViscosityPhase2_SOT : public Phase_SOT +{ +public: +/// Constructor. +ViscosityPhase2_SOT(DOFVectorBase<double> *phaseDV_, DOFVectorBase<double> *chDV_, double v1_=1.0, double v2_=1.0, double factor_=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implementation of \ref OperatorTerm::initElement() for multilpe meshes. +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +inline double f(const int iq) const; + +protected: + +/** \brief +* DOFVector to be evaluated at quadrature points. +*/ +DOFVectorBase<double>* chDV; + +/** \brief +* Vector v at quadrature points. +*/ +mtl::dense_vector<double> ch; +double v1,v2; + +}; + +/* -------------------------------------------------------------- */ + +class Viscosity_SOT : public SecondOrderTerm +{ +public: +/// Constructor. +Viscosity_SOT(DOFVectorBase<double> *chDV_, double v1_=1.0, double v2_=1.0, double factor_=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implementation of \ref OperatorTerm::initElement() for multilpe meshes. +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +void getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const; + +void eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result); + +inline double f(const int iq) const; + +protected: + +/** \brief +* DOFVector to be evaluated at quadrature points. +*/ +DOFVectorBase<double>* chDV; + +/** \brief +* Vector v at quadrature points. +*/ +mtl::dense_vector<double> ch; +double v1,v2; +double factor; + +}; + +/* -------------------------------------------------------------- */ + +class Viscosity2_SOT : public SecondOrderTerm +{ +public: +/// Constructor. +Viscosity2_SOT(DOFVectorBase<double> *chDV_, double v1_=1.0, double v2_=1.0, double factor_=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implementation of \ref OperatorTerm::initElement() for multilpe meshes. +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +void getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const; + +void eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result); + +inline double f(const int iq) const; + +protected: + +/** \brief +* DOFVector to be evaluated at quadrature points. +*/ +DOFVectorBase<double>* chDV; + +/** \brief +* Vector v at quadrature points. +*/ +mtl::dense_vector<double> ch; +double v1,v2; +double factor; + +}; + +/* -------------------------------------------------------------- */ + +/// < factor*phase*A*grad(u) , grad(psi) > ... 'I' kann ueberladen werden +class MatrixPhase_SOT : public SecondOrderTerm +{ +public: +/// Constructor +MatrixPhase_SOT(DOFVectorBase<double>* phaseDV, int comp, double fac=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); +inline void lDlt(const DimVec<WorldVector<double> >& Lambda, + const WorldVector<double>& vec, + mtl::dense2D<double>& LALt, + double factor) const; +void getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const; + +void eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result); + +inline WorldVector<double> f(const int iq) const; +void setFactor(const double fac_) { fac=fac_; } + +protected: +DOFVectorBase<double> *phaseDV; +mtl::dense_vector<double> phase; +int comp; +double fac; +bool symmetric; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*()_ij*grad(u) , grad(psi) > +class MatrixIJ_SOT : public SecondOrderTerm +{ +public: +/// Constructor +MatrixIJ_SOT(int row, int col, double fac=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL) {} +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL) {} +void getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const; +void eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); +void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result); +void setFactor(const double fac_) { fac=fac_; } + +protected: +int row,col; +double fac; +bool symmetric; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*phase*A*grad(u) , grad(psi) > ... 'I' kann ueberladen werden +class MatrixIJPhase_SOT : public SecondOrderTerm +{ +public: +/// Constructor +MatrixIJPhase_SOT(DOFVectorBase<double>* phaseDV, int row, int col, double fac=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); +void getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const; +void eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); +void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result); +void setFactor(const double fac_) { fac=fac_; } + +protected: +DOFVectorBase<double> *phaseDV; +mtl::dense_vector<double> phase; +int row,col; +double fac; +bool symmetric; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*phase*A*grad(u) , grad(psi) > ... 'I' kann ueberladen werden +class MatrixIJViscosityPhase_SOT : public SecondOrderTerm +{ +public: +/// Constructor +MatrixIJViscosityPhase_SOT(DOFVectorBase<double>* phaseDV, DOFVectorBase<double>* chDV, int row, int col, double v1_, double v2_, double fac=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); +void getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const; +void eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); +void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result); +void setFactor(const double fac_) { fac=fac_; } +inline double f(const int iq) const; + +protected: +DOFVectorBase<double> *phaseDV; +DOFVectorBase<double>* chDV; + +mtl::dense_vector<double> ch; +mtl::dense_vector<double> phase; +int row,col; +double v1,v2; +double fac; +bool symmetric; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*A*grad(u) , grad(psi) > ... 'I' kann ueberladen werden +class MatrixIJViscosity_SOT : public SecondOrderTerm +{ +public: +/// Constructor +MatrixIJViscosity_SOT(DOFVectorBase<double>* chDV, int row, int col, double v1_, double v2_, double fac=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); +void getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const; +void eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); +void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result); +void setFactor(const double fac_) { fac=fac_; } +inline double f(const int iq) const; + +protected: +DOFVectorBase<double>* chDV; + +mtl::dense_vector<double> ch; +int row,col; +double v1,v2; +double fac; +bool symmetric; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*phase*A*grad(u) , grad(psi) > ... 'I' kann ueberladen werden +class MatrixIJViscosityPhase2_SOT : public SecondOrderTerm +{ +public: +/// Constructor +MatrixIJViscosityPhase2_SOT(DOFVectorBase<double>* phaseDV, DOFVectorBase<double>* chDV, int row, int col, double v1_, double v2_, double fac=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); +void getLALt(const ElInfo *elInfo, + std::vector<mtl::dense2D<double> > &LALt) const; +void eval(int nPoints, + const mtl::dense_vector<double>& uhAtQP, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); +void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, + std::vector<WorldVector<double> > &result); +void setFactor(const double fac_) { fac=fac_; } +inline double f(const int iq) const; + +protected: +DOFVectorBase<double> *phaseDV; +DOFVectorBase<double>* chDV; + +mtl::dense_vector<double> ch; +mtl::dense_vector<double> phase; +int row,col; +double v1,v2; +double fac; +bool symmetric; +}; + +#endif // P_OPERATORS_SOT_H diff --git a/extensions/POperators_ZOT.h b/extensions/POperators_ZOT.h new file mode 100644 index 0000000000000000000000000000000000000000..6671c8133f2004da8d44219755efa33f5e040b2d --- /dev/null +++ b/extensions/POperators_ZOT.h @@ -0,0 +1,560 @@ +/** \file POperators_ZOT.h */ + +#ifndef P_OPERATORS_ZOT_H +#define P_OPERATORS_ZOT_H + +#include "AMDiS.h" + +using namespace std; +using namespace AMDiS; + +/// < factor*phase*u , psi > +class Phase_ZOT : public ZeroOrderTerm +{ +public: +Phase_ZOT(DOFVectorBase<double>* phaseDV, double fac=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); + +inline void getC(const ElInfo *, int nPoints, ElementVector &C); + +inline void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +virtual double f(const int iq) const; +void setFactor(const double fac_) { fac=fac_; } + +protected: +DOFVectorBase<double> *phaseDV; +mtl::dense_vector<double> phase; +double fac; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*phase*v*u , psi > +class FactorPhase_ZOT : public Phase_ZOT +{ +public: + FactorPhase_ZOT(DOFVectorBase<double> *phaseDV_, DOFVectorBase<double> *rhoDV_, double fac_=1.0); + void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + inline double f(const int iq) const; +protected: + DOFVectorBase<double> *rhoDV; + mtl::dense_vector<double> rho; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*(1-phase)*u , psi > or < factor*v[i]*(1-phase)*u , psi > where v in R^n +class PhaseInverse_ZOT : public ZeroOrderTerm +{ +public: +PhaseInverse_ZOT(DOFVectorBase<double>* phaseDV, double fac=1.0); +PhaseInverse_ZOT(DOFVectorBase<double>* phaseDV, double fac, WorldVector<double>* facVec, int component); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad=NULL); + +inline void getC(const ElInfo *, int nPoints, ElementVector &C); + +inline void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +inline double f(const int iq) const; +void setFactor(const double fac_) { fac=fac_; } + +protected: +DOFVectorBase<double> *phaseDV; +mtl::dense_vector<double> phase; +double fac; +int component; +WorldVector<double>* facVec; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*(v^3)*u , psi > +class Pow3_ZOT : public ZeroOrderTerm +{ +public: + Pow3_ZOT(DOFVectorBase<double> *rhoDV_, double fac_=1.0); + void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); +inline void getC(const ElInfo *, int nPoints, ElementVector &C); + +inline void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + inline double f(const int iq) const; +protected: + DOFVectorBase<double> *rhoDV; + mtl::dense_vector<double> rho; + double fac; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*(v^3)*phi*u , psi > +class Pow3Phase_ZOT : public Phase_ZOT +{ +public: + Pow3Phase_ZOT(DOFVectorBase<double>* phaseDV, DOFVectorBase<double> *rhoDV_, double fac_=1.0); + void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + inline double f(const int iq) const; +protected: + DOFVectorBase<double> *rhoDV; + mtl::dense_vector<double> rho; +}; +/* -------------------------------------------------------------- */ + +/// < factor*(v^2)*u , psi > +class Pow2_ZOT : public ZeroOrderTerm +{ +public: + Pow2_ZOT(DOFVectorBase<double> *rhoDV_, double fac_=1.0); + void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); +inline void getC(const ElInfo *, int nPoints, ElementVector &C); + +inline void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + inline double f(const int iq) const; +protected: + DOFVectorBase<double> *rhoDV; + mtl::dense_vector<double> rho; + double fac; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*(v^2)*phi*u , psi > +class Pow2Phase_ZOT : public Phase_ZOT +{ +public: + Pow2Phase_ZOT(DOFVectorBase<double>* phaseDV, DOFVectorBase<double> *rhoDV_, double fac_=1.0); + void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + inline double f(const int iq) const; +protected: + DOFVectorBase<double> *rhoDV; + mtl::dense_vector<double> rho; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*phase*(-1/max(1e-6, sqr(v+0.9)))*u , psi > +class ConstrainedFracSqr_ZOT : public Phase_ZOT +{ +public: + ConstrainedFracSqr_ZOT(DOFVectorBase<double> *phaseDV_, DOFVectorBase<double> *rhoDV_, double fac_=1.0); + void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + inline double f(const int iq) const; +protected: + DOFVectorBase<double> *rhoDV; + mtl::dense_vector<double> rho; +}; + +/// < factor*phase*(1/max(1e-6, v+0.9))*u , psi > +class ConstrainedFrac_ZOT : public Phase_ZOT +{ +public: + ConstrainedFrac_ZOT(DOFVectorBase<double> *phaseDV_, DOFVectorBase<double> *rhoDV_, double fac_=1.0); + void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + inline double f(const int iq) const; +protected: + DOFVectorBase<double> *rhoDV; + mtl::dense_vector<double> rho; +}; + +/// < (...)*u , psi > +class ConstrainedPowImpl_ZOT : public ZeroOrderTerm +{ +public: + ConstrainedPowImpl_ZOT(DOFVectorBase<double> *rhoDV_, double p_=20.0, double rhoMin_=-0.9, double fac_=1.0); + void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + void getC(const ElInfo *, int nPoints, ElementVector &C); + void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + inline double f(const int iq) const; +protected: + DOFVectorBase<double> *rhoDV; + mtl::dense_vector<double> rho; + double p,rhoMin,fac; +}; + +/// < (...)*u , psi > +class ConstrainedPowExpl_ZOT : public ZeroOrderTerm +{ +public: + ConstrainedPowExpl_ZOT(DOFVectorBase<double> *rhoDV_, double p_=20.0, double rhoMin_=-0.9, double fac_=1.0); + void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + void getC(const ElInfo *, int nPoints, ElementVector &C); + void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + inline double f(const int iq) const; +protected: + DOFVectorBase<double> *rhoDV; + mtl::dense_vector<double> rho; + double p,rhoMin,fac; +}; + +/// < (...)*u , psi > +class ConstrainedPow_ZOT : public ZeroOrderTerm +{ +public: + ConstrainedPow_ZOT(DOFVectorBase<double> *rhoDV_, double p_=20.0, double rhoMin_=-0.9, double fac_=1.0); + void initElement(const ElInfo* elInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + void getC(const ElInfo *, int nPoints, ElementVector &C); + void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + inline double f(const int iq) const; +protected: + DOFVectorBase<double> *rhoDV; + mtl::dense_vector<double> rho; + double p,rhoMin,fac; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*d_i(v)*u , psi > or < factor*b[j]*d_i(v)*u , psi > +class PartialDerivative_ZOT : public ZeroOrderTerm +{ +public: +PartialDerivative_ZOT(DOFVectorBase<double>* vecDV_, int component_, double fac_=1.0); +PartialDerivative_ZOT(DOFVectorBase<double>* vecDV_, int component_, double fac_, WorldVector<double>* vec, int component2_); + +void initElement(const ElInfo*, + SubAssembler*, + Quadrature *quad= NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + +void getC(const ElInfo *, int nPoints, ElementVector &C); + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +protected: +DOFVectorBase<double> *vecDV; +mtl::dense_vector<WorldVector<double> > grad; +double fac; +WorldVector<double>* facVec; +int component, component2; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*v*d_i(w)*u , psi > +class VecAndPartialDerivative_ZOT : public ZeroOrderTerm +{ +public: +VecAndPartialDerivative_ZOT(DOFVectorBase<double>* vecDV_, DOFVectorBase<double>* gradDV_, int component_, double fac_=1.0); + +void initElement(const ElInfo*, + SubAssembler*, + Quadrature *quad= NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + +void getC(const ElInfo *, int nPoints, ElementVector &C); + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +protected: +DOFVectorBase<double> *vecDV, *gradDV; +mtl::dense_vector<double> vec; +double fac; +mtl::dense_vector<WorldVector<double> > grad; +int component; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*v1*v2*d_i(w)*u , psi > +class Vec2AndPartialDerivative_ZOT : public ZeroOrderTerm +{ +public: +Vec2AndPartialDerivative_ZOT(DOFVectorBase<double>* vec1DV_, DOFVectorBase<double>* vec2DV_, DOFVectorBase<double>* gradDV_, int component_, double fac_=1.0); + +void initElement(const ElInfo*, + SubAssembler*, + Quadrature *quad= NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + +void getC(const ElInfo *, int nPoints, ElementVector &C); + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); + +protected: +DOFVectorBase<double> *vec1DV, *vec2DV, *gradDV; +mtl::dense_vector<double> vec1, vec2; +double fac; +mtl::dense_vector<WorldVector<double> > grad; +int component; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*v*d_i(w)*u , psi > +class WettingAngle_ZOT : public ZeroOrderTerm +{ +public: +WettingAngle_ZOT(DOFVectorBase<double>* vecDV_, DOFVectorBase<double>* gradDV_, double fac_=1.0); + +void initElement(const ElInfo*, + SubAssembler*, + Quadrature *quad= NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + +void getC(const ElInfo *, int nPoints, ElementVector &C); + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); +inline double f(const int iq) const; + +protected: +DOFVectorBase<double> *vecDV, *gradDV; +// mtl::dense_vector<double> vec; +double fac; +mtl::dense_vector<WorldVector<double> > grad; +mtl::dense_vector<WorldVector<double> > gradC; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*v*d_i(w)*u , psi > +class WettingAngleExpl_ZOT : public WettingAngle_ZOT +{ +public: +WettingAngleExpl_ZOT(DOFVectorBase<double>* vecDV_, DOFVectorBase<double>* gradDV_, double fac_=1.0); + +inline double f(const int iq) const; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*v*d_i(w)*u , psi > +class WettingAngleImpl_ZOT : public WettingAngle_ZOT +{ +public: +WettingAngleImpl_ZOT(DOFVectorBase<double>* vecDV_, DOFVectorBase<double>* gradDV_, double fac_=1.0); + +inline double f(const int iq) const; +}; + +/* -------------------------------------------------------------- */ + +class WettingAngleLowerOrder_ZOT : public ZeroOrderTerm +{ +public: +/// Constructor. +WettingAngleLowerOrder_ZOT( + DOFVectorBase<double> *chDV_, + DOFVectorBase<double>* phaseDV, + double factor_=1.0); + +/// Implementation of \ref OperatorTerm::initElement(). +void initElement(const ElInfo* elInfo, SubAssembler* subAssembler, + Quadrature *quad = NULL); + +/// Implementation of \ref OperatorTerm::initElement() for multilpe meshes. +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler* subAssembler, + Quadrature *quad = NULL); + +void getC(const ElInfo *, int nPoints, ElementVector &C); + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); +inline double f(const int iq) const; + +protected: + +/** \brief +* DOFVector to be evaluated at quadrature points. +*/ +DOFVectorBase<double>* chDV; +DOFVectorBase<double>* phaseDV; + +/** \brief +* Vector v at quadrature points. +*/ +mtl::dense_vector<double> ch; +mtl::dense_vector<double> phase; +mtl::dense_vector<WorldVector<double> > grdCh; +mtl::dense_vector<WorldVector<double> > grdPhase; + +double fac; +}; + +/* -------------------------------------------------------------- */ + + +/* -------------------------------------------------------------- */ + +/// < factor*v*d_i(w)*u , psi > +class WettingAngle_Sharp_ZOT : public ZeroOrderTerm +{ +public: +WettingAngle_Sharp_ZOT(DOFVectorBase<double>* vecDV_, double fac_=1.0); + +void initElement(const ElInfo*, + SubAssembler*, + Quadrature *quad= NULL); +void initElement(const ElInfo* largeElInfo, const ElInfo* smallElInfo, + SubAssembler*, + Quadrature *quad = NULL); + +void getC(const ElInfo *, int nPoints, ElementVector &C); + +void eval(int nPoints, + const mtl::dense_vector<double>&, + const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, + const mtl::dense_vector<WorldMatrix<double> >& D2UhAtQP, + mtl::dense_vector<double>& result, + double opFactor); +inline double f(const int iq) const; + +protected: +DOFVectorBase<double> *vecDV; +mtl::dense_vector<WorldVector<double> > grad; +double fac; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*v*d_i(w)*u , psi > +class WettingAngleExpl_Sharp_ZOT : public WettingAngle_Sharp_ZOT +{ +public: +WettingAngleExpl_Sharp_ZOT(DOFVectorBase<double>* vecDV_, double fac_=1.0); + +inline double f(const int iq) const; +}; + +/* -------------------------------------------------------------- */ + +/// < factor*v*d_i(w)*u , psi > +class WettingAngleImpl_Sharp_ZOT : public WettingAngle_Sharp_ZOT +{ +public: +WettingAngleImpl_Sharp_ZOT(DOFVectorBase<double>* vecDV_, double fac_=1.0); + +inline double f(const int iq) const; +}; + +#endif // P_OPERATORS_ZOT_H diff --git a/extensions/PhaseFieldConvert.h b/extensions/PhaseFieldConvert.h new file mode 100644 index 0000000000000000000000000000000000000000..4dddd39cf579d65ca98e95234fb406ea24a3fedd --- /dev/null +++ b/extensions/PhaseFieldConvert.h @@ -0,0 +1,174 @@ +/** \file PhaseFieldConvert.h */ + +#ifndef PHASE_FIELD_CONVERT_H +#define PHASE_FIELD_CONVERT_H + +using namespace AMDiS; + +struct SignedDistFctToPhaseField : AbstractFunction<double, WorldVector<double> > +{ + SignedDistFctToPhaseField(double epsilon_, + AbstractFunction<double,WorldVector<double> > *dist_, + double scalingFactor_ = 1.0/sqrt(2.0)) + : AbstractFunction<double, WorldVector<double> >(6), + epsilon(epsilon_), + dist(dist_), + scalingFactor(scalingFactor_) {}; + + double operator()(const WorldVector<double> &x) const + { + return 0.5 * (1.0 - tanh(scalingFactor * (*dist)(x) / epsilon)); + } + +private: + + double epsilon; + AbstractFunction<double,WorldVector<double> > *dist; + double scalingFactor; +}; + +struct SignedDistFctListToPhaseField : AbstractFunction<double, WorldVector<double> > +{ + SignedDistFctListToPhaseField(double epsilon_, + std::vector<AbstractFunction<double,WorldVector<double> >*> dist_, + double scalingFactor_ = 1.0/sqrt(2.0)) + : AbstractFunction<double, WorldVector<double> >(6), + epsilon(epsilon_), + dist(dist_), + scalingFactor(scalingFactor_) {}; + + double operator()(const WorldVector<double> &x) const + { + double d = 1.e12; + for (size_t i = 0; i < dist.size(); ++i) { + d = std::min((*(dist[i]))(x), d); + } + return 0.5 * (1.0 - tanh(scalingFactor * d / epsilon)); + } + +private: + + double epsilon; + std::vector<AbstractFunction<double,WorldVector<double> >*> dist; + double scalingFactor; +}; + + +struct SignedDistList : AbstractFunction<double, WorldVector<double> > +{ + SignedDistList(std::vector<AbstractFunction<double,WorldVector<double> >*> dist_) + : AbstractFunction<double, WorldVector<double> >(1), + dist(dist_) {}; + + double operator()(const WorldVector<double> &x) const + { + d.setX(x); + return std::for_each(dist.begin(), dist.end(), d); + } + +private: + struct MyMax { + mutable double val; + mutable WorldVector< double > x; + MyMax() + : val(-1.0e12) {} + + void operator()(const AbstractFunction<double,WorldVector<double> >* v) const + { + val = max((*v)(x), val); + } + + void setX(const WorldVector<double> &x_) const + { + x= x_; + } + + inline operator double() { return val; } + } d; + + std::vector<AbstractFunction<double,WorldVector<double> >*> dist; +}; + +struct PhaseFieldToSignedDist : AbstractFunction<double, double> +{ + PhaseFieldToSignedDist(double epsilon_= -1.0, double scalingFactor_ = 1.0/sqrt(2.0)) + : AbstractFunction<double, double>(6), + epsilon(epsilon_), + scalingFactor(scalingFactor_) + { + if (epsilon < 0.0) + Parameters::get("mesh->refinement->epsilon", epsilon); + } + + double operator()(const double &phi) const + { + double z = std::max(-1.0 + 1.e-10, std::min(1.0 - 1.e-10, -phi)); + return (epsilon/scalingFactor) * atanh(z); + } + +private: + double epsilon; + double scalingFactor; +}; + +struct SignedDistToPhaseField : AbstractFunction<double, double> +{ + SignedDistToPhaseField(double epsilon_ = -1.0, double scalingFactor_ = 1.0/sqrt(2.0)) + : AbstractFunction<double, double>(6), + epsilon(epsilon_), + scalingFactor(scalingFactor_) + { + if (epsilon < 0.0) + Parameters::get("mesh->refinement->epsilon", epsilon); + } + + double operator()(const double &dist) const + { + return 0.5 * (1.0 - tanh(scalingFactor * dist / epsilon)); + } + +private: + double epsilon; + double scalingFactor; +}; + +struct SignedDistToCh : AbstractFunction<double, double> +{ + SignedDistToCh(double epsilon_ = -1.0, double scalingFactor_ = 1.0/sqrt(2.0)) + : AbstractFunction<double, double>(6), + epsilon(epsilon_), + scalingFactor(scalingFactor_) + { + if (epsilon < 0.0) + Parameters::get("mesh->refinement->epsilon", epsilon); + } + + double operator()(const double &dist) const + { + return -tanh(scalingFactor * dist / epsilon); + } + +private: + double epsilon; + double scalingFactor; +}; + +struct ChToPhaseField : AbstractFunction<double, double> +{ + ChToPhaseField() : AbstractFunction<double, double>(1) {}; + double operator()(const double &c) const + { + return std::max(0.0, std::min(1.0, 0.5 * (c + 1.0))); + } +}; + +struct PhaseFieldToCh : AbstractFunction<double, double> +{ + PhaseFieldToCh() : AbstractFunction<double, double>(1) {}; + double operator()(const double &c) const + { + return std::max(-1.0, std::min(1.0, 2.0 * c - 1.0)); + } +}; + +#endif // PHASE_FIELD_CONVERT_H diff --git a/extensions/Refinement.h b/extensions/Refinement.h new file mode 100644 index 0000000000000000000000000000000000000000..08df6caf2a4ac9a4b13b4955fcb777adfdcfa128 --- /dev/null +++ b/extensions/Refinement.h @@ -0,0 +1,272 @@ +/** \file Refinement.h */ + +#ifndef REFINEMENT_H +#define REFINEMENT_H + +#include "ElementFunction.h" + +using namespace AMDiS; + + +/** \brief + * Abstract class that can be passed to RefinementLevel* as indicator where + * to refine the mesh up to which level. It is an AbstractFunction that + * overloads the operator() method to return a level or a meshsize depending + * on the coords/data passed to the operator. + * You can switch between meshsize and level with the methods hToLevel(double) and + * levelToH(int) + **/ +template<typename T, typename T2> +class MeshRefinementFunction : public AbstractFunction<T2, T> +{ +public: + + MeshRefinementFunction(Mesh* mesh_) : + AbstractFunction<T2, T>(0), + mesh(mesh_), + globalSize(0) + { + h0 = getMacroMeshSize(mesh); + reduction = 1.0 / sqrt(2.0); // if dim==2 + } + + int getGlobalSize() { return globalSize; } + + double meshSize() { return h0; } + + virtual T2 operator()(const T &value) const { return globalSize; } + + virtual double indicator(const T &value) const { return 1.0; } + +protected: + + int hToLevel(double h) { + int level = static_cast<int>(floor(log(h / h0) / log(reduction))); + return level; + } + + double levelToH(int level) { + double h = pow(reduction,level)*h0; + return h; + } + + double getMacroMeshSize(Mesh* mesh) { + FixVec<WorldVector<double>, VERTEX> coords = mesh->getMacroElement(0)->getCoord(); + double h = 0.0; + for (int i = 0; i < coords.size(); ++i) + for (int j = i + 1; j < coords.size(); ++j) + h = std::max(h, norm(coords[i]-coords[j])); + return h; + } + +protected: + + Mesh* mesh; + + int globalSize; + + double h0; + double reduction; +}; + + +/** \brief + * Base class for Refinement structure to perform local anisotropic refinement + */ +template<typename T, typename T2> +class RefinementLevel +{ +public: + + RefinementLevel(const FiniteElemSpace *feSpace_, MeshRefinementFunction<T,T2>* refineFct_) : + feSpace(feSpace_), + refineFct(refineFct_), + numRefinements0(15), + globalRefined(false) + { + mesh = feSpace->getMesh(); + switch (mesh->getDim()) { + case 1: + coarseningManager = new CoarseningManager1d(); + refinementManager = new RefinementManager1d(); + break; + case 2: + coarseningManager = new CoarseningManager2d(); + refinementManager = new RefinementManager2d(); + break; + case 3: + coarseningManager = new CoarseningManager3d(); + refinementManager = new RefinementManager3d(); + break; + default: + ERROR_EXIT("invalid dim!\n"); + } + + numRefinements = numRefinements0; + } + + ~RefinementLevel() { + delete coarseningManager; + delete refinementManager; + } + + void refine(bool onlyRefine= false) + { + FUNCNAME("RefinementLevel::refine()"); + + if (!globalRefined) { + MSG_DBG("nr of global refinements: %d\n", refineFct->getGlobalSize()); + refinementManager->globalRefine(mesh, refineFct->getGlobalSize()); + globalRefined = true; + } + double minH = 0.0, maxH = 1.0; + int minLevel = 100, maxLevel = 0; + + // build mesh for phasefield-function + bool meshChanged = true; + Flag markFlag; + int oldMinLevel = 100, oldMaxLevel = 0, oldNr = 0, oldOldNr = 0; + int i = 0; + while (meshChanged && i < numRefinements) { + markElements(markFlag); + meshChanged = refineMesh(markFlag, onlyRefine); + + calcMeshSizes(minH, maxH, minLevel, maxLevel); + int nr = mesh->getNumberOfVertices(); + meshChanged = meshChanged && oldOldNr!=nr && oldNr!=nr; + if (meshChanged) { + MSG_DBG("Mesh sizes: [%f, %f], Vs: %d, ELs: %d\n", + minH, maxH, nr, mesh->getNumberOfElements()); + } + i++; + + oldMinLevel = minLevel; + oldMaxLevel = maxLevel; + oldOldNr = oldNr; + oldNr = nr; + } + calcMeshSizes(minH, maxH, minLevel, maxLevel); + MSG("Final mesh: [%f, %f], Vs: %d, ELs: %d, Level: [%d, %d]\n", + minH, maxH, mesh->getNumberOfVertices(), mesh->getNumberOfElements(), minLevel, maxLevel); + } + + void refine(int numRefinements_, bool onlyRefine= false) { + numRefinements = numRefinements_; + refine(onlyRefine); + numRefinements = numRefinements0; + } + + int getNumRefinements(){ + return numRefinements; + } + + void calcMeshSizes(double& minH, double& maxH, int& minLevel, int& maxLevel) + { + FUNCNAME("RefinementLevel::calcMeshSizes()"); + + FixVec<WorldVector<double>, VERTEX> coords(mesh->getDim(), NO_INIT); + + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS); + minH = 1e15; maxH = 0.0; + int k = 0; + minLevel = 100; + maxLevel = 0; + while (elInfo) { + maxLevel = std::max(maxLevel,elInfo->getLevel()); + minLevel = std::min(minLevel,elInfo->getLevel()); + coords = elInfo->getCoords(); + double h = 0.0; + for (int i = 0; i < coords.size(); i++) { + for (int j = 0; j < coords.size(); j++) { + if (i != j) + h = std::max(h,norm(coords[i]-coords[j])); + } + } + minH = std::min(h, minH); + maxH = std::max(h, maxH); + elInfo = stack.traverseNext(elInfo); + k++; + } + minLevel += mesh->getMacroElementLevel(); + maxLevel += mesh->getMacroElementLevel(); + } + + + double calcMeshSize(ElInfo *elInfo) + { + FUNCNAME("RefinementLevel::calcMeshSizes()"); + + FixVec<WorldVector<double>, VERTEX> coords(mesh->getDim(), NO_INIT); + coords = elInfo->getCoords(); + double h = 0.0; + for (int i = 0; i < coords.size(); i++) { + for (int j = 0; j < coords.size(); j++) { + if (i != j) + h = std::max(h,norm(coords[i]-coords[j])); + } + } + + return h; + } + + + int calcMark(double refineH, double currentH) + { + return (refineH < currentH ? + 1 : (refineH > currentH * (mesh->getDim() == 1 ? + 2.0 : (mesh->getDim() == 2 ? + sqrt(2.0) : + sqrt(2.0)/2.0 + 0.5)) ? + -1 : + 0)); + } + + + virtual int calcMark(int refineLevel, int currentLevel) + { + int levelDiff = refineLevel - currentLevel; + return (levelDiff > 0 ? 1 : (levelDiff < 0 ? -1 : 0)); + } + + + bool refineMesh(Flag markFlag, bool onlyRefine) + { + FUNCNAME("RefinementLevel::refineMesh()"); + + int oldSize = mesh->getNumberOfVertices(); + if (markFlag.isSet(1)) + refinementManager->refineMesh(mesh); + if (markFlag.isSet(2) && !onlyRefine) + coarseningManager->coarsenMesh(mesh); + if (markFlag.isSet(1) || markFlag.isSet(2)) { + int newSize = mesh->getNumberOfVertices(); + if (oldSize != newSize) + return true; + } + return false; + } + + virtual void markElements(Flag &markFlag) = 0; + + void setGlobalRefined(bool refined) { globalRefined = refined; } + RefinementManager* getRefinementManager() { return refinementManager; } + CoarseningManager* getCoarseningManager() { return coarseningManager; } + +protected: + + const FiniteElemSpace *feSpace; + Mesh* mesh; + MeshRefinementFunction<T,T2>* refineFct; + RefinementManager* refinementManager; + CoarseningManager* coarseningManager; + + int numRefinements; + int numRefinements0; + bool globalRefined; +}; + +#include "Refinement_Level.h" +#include "Refinement_MeshSize.h" + +#endif // REFINEMENT_H diff --git a/extensions/Refinement_DOFView.h b/extensions/Refinement_DOFView.h new file mode 100644 index 0000000000000000000000000000000000000000..4ccacc702db51624736609f966d8910c40a12805 --- /dev/null +++ b/extensions/Refinement_DOFView.h @@ -0,0 +1,487 @@ +/** \file Refinement_DOFView.h */ + +#ifndef REFINEMENT_DOFVIEW_H +#define REFINEMENT_DOFVIEW_H + +#include "Refinement.h" +#include "Views.h" +#include "MeshFunction_Level.h" + +using namespace AMDiS; + + +/** \brief + * Refinement structure to perform local anisotropic refinement depending + * on a refineFunction that defines the local refinement level to a given + * value, like phase-value or distance-value. + **/ +class RefinementLevelDOFView : public RefinementLevel<double, int> +{ +public: + typedef double T; + +public: + RefinementLevelDOFView(const FiniteElemSpace *feSpace_, + MeshRefinementFunction<T, int>* refineFct_, + DOFView<double> *vec_) + : RefinementLevel<T, int>(feSpace_, refineFct_), + vec(vec_) { }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelDOFView::markElements()"); + + T meanValue; nullify(meanValue); + WorldVector<double> centroid; + + bool elMarkRefine = false, elMarkCoarsen = false; + + int dim = mesh->getDim(); + + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + MacroElement* foundMacro = new MacroElement(dim); + bool found = false; + while (elInfo) { + centroid = elInfo->getCoord(0); + for (int i = 1; i < dim+1; i++) + centroid += elInfo->getCoord(i); + centroid *= 1.0/(dim+1.0); + + meanValue = evalAtPoint<T>(*vec, centroid); + + int refineLevel = (*refineFct)(meanValue); + int oldLevel = elInfo->getLevel(); + elInfo->getElement()->setMark( calcMark(refineLevel, oldLevel) ); + + elMarkRefine |= elInfo->getElement()->getMark() >= 1; + elMarkCoarsen |= elInfo->getElement()->getMark() <= -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag = 0; + if (elMarkRefine) + markFlag = 1; + if (elMarkCoarsen) + markFlag |= 2; + }; + +private: + + DOFView<double>* vec; +}; + + + +/** \brief + * Specialization of RefinementLevel, that uses an arbitrary container 'data' + * that gives the phase-field value or the distance value, or something that + * can be handled by the reine-function. + * For the Container a free function evalAtPoint must be implemented, + * e.g. DOFVector, DOFView, AbstractFunction, POD-Type. + **/ +template<typename Container> +class RefinementLevel1 : public RefinementLevel<double, int> +{ +public: + typedef double T; + +public: + RefinementLevel1(const FiniteElemSpace *feSpace_, + MeshRefinementFunction<T, int>* refineFct_, + Container &data_) + : RefinementLevel<T, int>(feSpace_, refineFct_), + data(data_) { }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelDOFView::markElements()"); + + bool elMarkRefine = false, elMarkCoarsen = false; + + int dim = mesh->getDim(); + + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + + while (elInfo) { + WorldVector<double> centroid = elInfo->getCoord(0); + for (int i = 1; i < dim+1; i++) + centroid += elInfo->getCoord(i); + centroid *= 1.0/(dim+1.0); + + typename ValueType<Container>::type meanValue = evalAtPoint<typename ValueType<Container>::type>(data, centroid, elInfo); + + int refineLevel = (*refineFct)(meanValue); + int oldLevel = elInfo->getLevel(); + elInfo->getElement()->setMark( calcMark(refineLevel, oldLevel) ); + + elMarkRefine |= elInfo->getElement()->getMark() >= 1; + elMarkCoarsen |= elInfo->getElement()->getMark() <= -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag = 0; + if (elMarkRefine) + markFlag = 1; + if (elMarkCoarsen) + markFlag |= 2; + }; + +private: + Container& data; +}; + + +/** \brief + * Specialization of RefinementLevel, that uses two arbitrary containers 'data1', 'data2' + * that give the phase-field values or the distance values, or something that + * can be handled by the reine-function. + * For the Containers free functions evalAtPoint must be implemented, + * e.g. DOFVector, DOFView, AbstractFunction, POD-Type. + **/ +template<typename Container1, typename Container2> +class RefinementLevel2 : public RefinementLevel<boost::tuple<double, double>, int> +{ +public: + typedef boost::tuple<double, double> T; + +public: + RefinementLevel2(const FiniteElemSpace *feSpace_, + MeshRefinementFunction<T, int>* refineFct_, + Container1 &data1_, + Container2 &data2_) + : RefinementLevel<T, int>(feSpace_, refineFct_), + data1(data1_), + data2(data2_) { }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelDOFView::markElements()"); + + bool elMarkRefine = false, elMarkCoarsen = false; + + int dim = mesh->getDim(); + + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + + while (elInfo) { + WorldVector<double> centroid = elInfo->getCoord(0); + for (int i = 1; i < dim+1; i++) + centroid += elInfo->getCoord(i); + centroid *= 1.0/(dim+1.0); + + typename ValueType<Container1>::type meanValue1 = evalAtPoint<typename ValueType<Container1>::type>(data1, centroid, elInfo); + typename ValueType<Container1>::type meanValue2 = evalAtPoint<typename ValueType<Container2>::type>(data2, centroid, elInfo); + + int refineLevel = (*refineFct)(boost::tuples::make_tuple(meanValue1, meanValue2)); + int oldLevel = elInfo->getLevel(); + elInfo->getElement()->setMark( calcMark(refineLevel, oldLevel) ); + + elMarkRefine |= elInfo->getElement()->getMark() >= 1; + elMarkCoarsen |= elInfo->getElement()->getMark() <= -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag = 0; + if (elMarkRefine) + markFlag |= 1; + if (elMarkCoarsen) + markFlag |= 2; + }; + +private: + Container1& data1; + Container2& data2; +}; + + +/** \brief + * Specialization of RefinementLevel, that uses two arbitrary containers 'data1', 'data2' + * that give the phase-field values or the distance values, or something that + * can be handled by the reine-function. + * For the Containers free functions evalAtPoint must be implemented, + * e.g. DOFVector, DOFView, AbstractFunction, POD-Type. + **/ +template<typename Container1, typename Container2, typename Container3> +class RefinementLevel3 : public RefinementLevel<boost::tuple<double, double, double>, int> +{ +public: + typedef boost::tuple<double, double, double> T; + +public: + RefinementLevel3(const FiniteElemSpace *feSpace_, + MeshRefinementFunction<T, int>* refineFct_, + Container1 &data1_, + Container2 &data2_, + Container3 &data3_) + : RefinementLevel<T, int>(feSpace_, refineFct_), + data1(data1_), + data2(data2_), + data3(data3_) { }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelDOFView::markElements()"); + + bool elMarkRefine = false, elMarkCoarsen = false; + + int dim = mesh->getDim(); + + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + + while (elInfo) { + WorldVector<double> centroid = elInfo->getCoord(0); + for (int i = 1; i < dim+1; i++) + centroid += elInfo->getCoord(i); + centroid *= 1.0/(dim+1.0); + + typename ValueType<Container1>::type meanValue1 = evalAtPoint<typename ValueType<Container1>::type>(data1, centroid, elInfo); + typename ValueType<Container2>::type meanValue2 = evalAtPoint<typename ValueType<Container2>::type>(data2, centroid, elInfo); + typename ValueType<Container3>::type meanValue3 = evalAtPoint<typename ValueType<Container3>::type>(data3, centroid, elInfo); + + int refineLevel = (*refineFct)(boost::tuples::make_tuple(meanValue1, meanValue2, meanValue3)); + int oldLevel = elInfo->getLevel(); + elInfo->getElement()->setMark( calcMark(refineLevel, oldLevel) ); + + elMarkRefine |= elInfo->getElement()->getMark() >= 1; + elMarkCoarsen |= elInfo->getElement()->getMark() <= -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag = 0; + if (elMarkRefine) + markFlag = 1; + if (elMarkCoarsen) + markFlag |= 2; + }; + +private: + Container1& data1; + Container2& data2; + Container3& data3; +}; + + +/** \brief + * Refinement structure to perform local anisotropic refinement depending + * on a refineFunction that defines the local refinement level to a given + * list of values, like phase-values or distance-values. + **/ +class RefinementLevelDOF2 : public RefinementLevel< boost::tuple<double, double>, int > +{ +public: + typedef boost::tuple<double, double> value_Type; + +public: + RefinementLevelDOF2( + const FiniteElemSpace *feSpace_, + MeshRefinementFunction< value_Type, int >* refineFct_, + DOFVector<double>* vec0_, + DOFVector<double>* vec1_) + : RefinementLevel< value_Type, int >(feSpace_, refineFct_), + vec0(vec0_), + vec1(vec1_) { }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelDOFViewAndDOFVector::markElements()"); + + const DOFAdmin* admin = feSpace->getAdmin(); + const BasisFunction *basFcts = feSpace->getBasisFcts(); + int numBasFcts = basFcts->getNumber(); + + DegreeOfFreedom *localIndices = new DegreeOfFreedom[numBasFcts]; + + bool elMarkRefine = false, elMarkCoarsen = false; + + ElementFunctionDOFVec<double> elFct0(vec0); + ElementFunctionDOFVec<double> elFct1(vec1); + DimVec<double> lambda(mesh->getDim(), NO_INIT); + for (int i = 0; i < lambda.getSize(); ++i) + lambda[i] = 1.0 / lambda.getSize(); + + int dim = mesh->getDim(); + Flag traverseFlag = Mesh::CALL_LEAF_EL; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + while(elInfo) { + // eval DOFVector0 + elFct0.setElInfo(elInfo); + double meanValue0 = elFct0(lambda); + + // eval DOFVector1 + elFct1.setElInfo(elInfo); + double meanValue1 = elFct1(lambda); + + int refineLevel = (*refineFct)(boost::tuples::make_tuple(meanValue0, meanValue1)); + int oldLevel = elInfo->getLevel(); + elInfo->getElement()->setMark( calcMark(refineLevel, oldLevel) ); + + elMarkRefine |= elInfo->getElement()->getMark() == 1; + elMarkCoarsen |= elInfo->getElement()->getMark() == -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag= 0; + if(elMarkRefine) + markFlag = 1; + if(elMarkCoarsen) + markFlag |= 2; + + delete [] localIndices; + }; + + +private: + + DOFVector<double>* vec0; + DOFVector<double>* vec1; +}; + +/** \brief + * Refinement structure to perform local anisotropic refinement depending + * on a refineFunction that defines the local refinement level to a given + * list of values, like phase-values or distance-values. + **/ +class RefinementLevelDOFViewAndDOFVector : public RefinementLevel< boost::tuple<double, double>, int > +{ +public: + typedef boost::tuple<double, double> value_Type; + +public: + RefinementLevelDOFViewAndDOFVector( + const FiniteElemSpace *feSpace_, + MeshRefinementFunction< value_Type, int >* refineFct_, + DOFView<double>* vec0_, + DOFVector<double>* vec1_) + : RefinementLevel< value_Type, int >(feSpace_, refineFct_), + vec0(vec0_), + vec1(vec1_) { }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelDOFViewAndDOFVector::markElements()"); + + const DOFAdmin* admin = feSpace->getAdmin(); + const BasisFunction *basFcts = feSpace->getBasisFcts(); + int numBasFcts = basFcts->getNumber(); + + DegreeOfFreedom *localIndices = new DegreeOfFreedom[numBasFcts]; + + bool elMarkRefine = false, elMarkCoarsen = false; + + ElementFunctionDOFVec<double> elFct(vec1); + DimVec<double> lambda(mesh->getDim(), NO_INIT); + for (int i = 0; i < lambda.getSize(); ++i) + lambda[i] = 1.0 / lambda.getSize(); + + int dim = mesh->getDim(); + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + WorldVector<double> border; border.set(0.0); border[0] = 0.5; + while (elInfo) { + WorldVector<double> centroid = elInfo->getCoord(0); + for (int i = 1; i < dim+1; i++) + centroid += elInfo->getCoord(i); + centroid *= 1.0/(dim+1.0); + + // eval DOFView + double meanValue0 = evalAtPoint<double>(*vec0, centroid); + // eval DOFVector + elFct.setElInfo(elInfo); + double meanValue1 = elFct(lambda); + + int refineLevel = (*refineFct)(boost::tuples::make_tuple(meanValue0, meanValue1)); + int oldLevel = elInfo->getLevel(); + elInfo->getElement()->setMark( calcMark(refineLevel, oldLevel) ); + + elMarkRefine |= elInfo->getElement()->getMark() == 1; + elMarkCoarsen |= elInfo->getElement()->getMark() == -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag = 0; + if(elMarkRefine) + markFlag = 1; + if(elMarkCoarsen) + markFlag |= 2; + + delete [] localIndices; + } + +private: + + DOFView<double>* vec0; + DOFVector<double>* vec1; +}; + + + +/** \brief + * Implementation of PhaseFieldRefinementBase. Provides the method operator() + * that defines the regions for interface refinement and domain refinement, etc. + **/ +class PhaseField2Refinement : public PhaseFieldRefinementBase<boost::tuple<double, double> > +{ +public: + + PhaseField2Refinement(Mesh* mesh_) : PhaseFieldRefinementBase<boost::tuple<double, double> >(mesh_) {}; + + int operator()(const boost::tuple<double, double>& phases) const { + int result0= lOuter; + if (minPhase < phases.get<0>() && phases.get<0>() < maxPhase) + result0= lInterface; // auf dem Interface + else if (phases.get<0>() > minOuterPhase && phases.get<0>() <= minPhase) + result0= std::max(lOuter, static_cast<int>(floor((lOuter+lInterface)/2.0))); + else if (phases.get<0>() < maxOuterPhase && phases.get<0>() >= maxPhase) + result0= std::max(lInner, static_cast<int>(floor((lInner+lInterface)/2.0))); + else if (phases.get<0>() > (minPhase+maxPhase)/2.0) + result0= lInner; + + int result1= lOuter; + if (minPhase < phases.get<1>() && phases.get<1>() < maxPhase) + result1= lInterface; // auf dem Interface + else if (phases.get<1>() > minOuterPhase && phases.get<1>() <= minPhase) + result1= std::max(lOuter, static_cast<int>(floor((lOuter+lInterface)/2.0))); + else if (phases.get<1>() < maxOuterPhase && phases.get<1>() >= maxPhase) + result1= std::max(lInner, static_cast<int>(floor((lInner+lInterface)/2.0))); + else if (phases.get<1>() > (minPhase+maxPhase)/2.0) + result1= lInner; + + return std::max(result0, result1); + } +}; + + +/** \brief + * Implementation of PhaseFieldRefinementBase. Provides the method operator() + * that defines the regions for interface refinement and domain refinement, etc. + **/ +class PhaseField2Refinement_simple : public PhaseFieldRefinementBase<boost::tuple<double, double> > +{ +public: + + PhaseField2Refinement_simple(Mesh* mesh_) : PhaseFieldRefinementBase<boost::tuple<double, double> >(mesh_) {}; + + int operator()(const boost::tuple<double, double>& phases) const { + int result0 = lOuter; + if (minPhase < phases.get<0>() && phases.get<0>() < maxPhase) + result0 = lInterface; // auf dem Interface vom Phase 1 + + int result1 = lOuter; + if (minPhase < phases.get<1>() && phases.get<1>() < maxPhase) + result1 = lInterface; // auf dem Interface von Phase 2 + + return std::max(result0, result1); + } +}; + +#endif // REFINEMENT_DOFVIEW_H diff --git a/extensions/Refinement_Level.h b/extensions/Refinement_Level.h new file mode 100644 index 0000000000000000000000000000000000000000..e1e5e608edaba05c0777aefe33d0ff18d3c9e15b --- /dev/null +++ b/extensions/Refinement_Level.h @@ -0,0 +1,413 @@ +/** \file Refinement_Level.h */ + +#ifndef REFINEMENT_LEVEL_PHASEFIELD_H +#define REFINEMENT_LEVEL_PHASEFIELD_H + +#include "ElementFunction.h" + +using namespace AMDiS; + +/** \brief + * Refinement structure to perform local anisotropic refinement depending + * on a refineFunction that defines the local refinement level to given + * coordinates. + **/ +class RefinementLevelCoords : public RefinementLevel<WorldVector<double>, int > +{ +public: + RefinementLevelCoords(const FiniteElemSpace *feSpace_, MeshRefinementFunction<WorldVector<double>, int >* refineFct_) : + RefinementLevel<WorldVector<double>, int >(feSpace_, refineFct_) { }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelCoords::markElements()"); + + FixVec<WorldVector<double>, VERTEX> coords(mesh->getDim(), NO_INIT); + WorldVector<double> center; + + bool elMarkRefine = false, elMarkCoarsen = false; + + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + while (elInfo) { + coords = elInfo->getCoords(); + center.set(0.0); + for (int i = 0; i < coords.size(); ++i) { + center += coords[i]; + } + center *= 1.0 / static_cast<double>(coords.size()); + int refineLevel = (*refineFct)(center); + int oldLevel = elInfo->getLevel(); + elInfo->getElement()->setMark( calcMark(refineLevel, oldLevel) ); + + elMarkRefine |= elInfo->getElement()->getMark() == 1; + elMarkCoarsen |= elInfo->getElement()->getMark() == -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag = 0; + if (elMarkRefine) + markFlag = 1; + if (elMarkCoarsen) + markFlag |= 2; + }; +}; + + +/** \brief + * Refinement structure to perform local anisotropic refinement depending + * on a refineFunction that defines the local refinement level to given + * coordinates. + **/ +class RefinementLevelCoords2 : public RefinementLevel<double, int > +{ +public: + RefinementLevelCoords2(const FiniteElemSpace *feSpace_, MeshRefinementFunction<double, int >* refineFct_, AbstractFunction<double, WorldVector<double> > *fct_) : + RefinementLevel<double, int >(feSpace_, refineFct_), fct(fct_) { }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelCoords::markElements()"); + + FixVec<WorldVector<double>, VERTEX> coords(mesh->getDim(), NO_INIT); + WorldVector<double> center; + + bool elMarkRefine = false, elMarkCoarsen = false; + + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + while (elInfo) { + coords = elInfo->getCoords(); + center.set(0.0); + for (int i = 0; i < coords.size(); ++i) { + center += coords[i]; + } + center *= 1.0 / static_cast<double>(coords.size()); + double value = (*fct)(center); + int refineLevel = (*refineFct)(value); + int oldLevel = elInfo->getLevel(); + elInfo->getElement()->setMark( calcMark(refineLevel, oldLevel) ); + + elMarkRefine |= elInfo->getElement()->getMark() == 1; + elMarkCoarsen |= elInfo->getElement()->getMark() == -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag = 0; + if (elMarkRefine) + markFlag = 1; + if (elMarkCoarsen) + markFlag |= 2; + }; + +private: + AbstractFunction<double, WorldVector<double> > *fct; +}; + + +/** \brief + * Refinement structure to perform local anisotropic refinement depending + * on a refineFunction that defines the local refinement level to a given + * value, like phase-value or distance-value. + **/ +class RefinementLevelDOF : public RefinementLevel<double, int> +{ +public: + RefinementLevelDOF(const FiniteElemSpace *feSpace_, MeshRefinementFunction<double, int>* refineFct_, DOFVector<double> *vec_) : + RefinementLevel<double, int>(feSpace_, refineFct_), + vec(vec_) { }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelDOF::markElements()"); + + double meanValue; + + ElementFunctionDOFVec<double> elFct(vec); + DimVec<double> lambda(mesh->getDim(), NO_INIT); + for (int i = 0; i < lambda.getSize(); ++i) + lambda[i] = 1.0 / lambda.getSize(); + + bool elMarkRefine = false, elMarkCoarsen = false; + + Flag traverseFlag = Mesh::CALL_LEAF_EL; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + while (elInfo) { + elFct.setElInfo(elInfo); + meanValue = elFct(lambda); + + int refineLevel = (*refineFct)(meanValue); + int oldLevel = elInfo->getLevel(); + elInfo->getElement()->setMark( calcMark(refineLevel, oldLevel) ); + + elMarkRefine |= elInfo->getElement()->getMark() == 1; + elMarkCoarsen |= elInfo->getElement()->getMark() == -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag = 0; + if (elMarkRefine) + markFlag = 1; + if (elMarkCoarsen) + markFlag |= 2; + }; + +private: + + DOFVector<double>* vec; +}; + + +/** \brief + * Refinement structure to perform local anisotropic refinement depending + * on a refineFunction that defines the local refinement level to a given + * value, like phase-value or distance-value, and the center coords of the + * element. + **/ +class RefinementLevelCoordsDOF : public RefinementLevel<std::pair<WorldVector<double>, double>, int > +{ +public: + + RefinementLevelCoordsDOF(const FiniteElemSpace *feSpace_, MeshRefinementFunction<std::pair<WorldVector<double>, double>, int >* refineFct_, DOFVector<double> *vec_) : + RefinementLevel<std::pair<WorldVector<double>, double>, int >(feSpace_, refineFct_), vec(vec_) { }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelCoordsDOF::markElements()"); + + double meanValue; + FixVec<WorldVector<double>, VERTEX> coords(mesh->getDim(), NO_INIT); + WorldVector<double> center; + + ElementFunctionDOFVec<double> elFct(vec); + DimVec<double> lambda(mesh->getDim(), NO_INIT); + for (int i= 0; i<lambda.getSize(); ++i) + lambda[i]= 1.0/lambda.getSize(); + + bool elMarkRefine= false, elMarkCoarsen= false; + + Flag traverseFlag= Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS; + TraverseStack stack; + ElInfo *elInfo= stack.traverseFirst(mesh, -1, traverseFlag); + while (elInfo) { + elFct.setElInfo(elInfo); + meanValue = elFct(lambda); + coords = elInfo->getCoords(); + center.set(0.0); + for (int i = 0; i < coords.size(); ++i) { + center += coords[i]; + } + center *= 1.0 / static_cast<double>(coords.size()); + + int refineLevel = (*refineFct)(std::make_pair<WorldVector<double>, double>(center, meanValue)); + int oldLevel = elInfo->getLevel(); + elInfo->getElement()->setMark( calcMark(refineLevel, oldLevel) ); + + elMarkRefine |= elInfo->getElement()->getMark() == 1; + elMarkCoarsen |= elInfo->getElement()->getMark() == -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag = 0; + if (elMarkRefine) + markFlag = 1; + if (elMarkCoarsen) + markFlag |= 2; + }; + +private: + + DOFVector<double>* vec; +}; + + +/** \brief + * Refinement structure to perform local anisotropic refinement depending + * on a refineFunction that defines the local refinement level to a given + * list of values, like phase-values or distance-values. + **/ +class RefinementLevelDOFList : public RefinementLevel< std::vector<double>, int > +{ +public: + RefinementLevelDOFList( + const FiniteElemSpace *feSpace_, + MeshRefinementFunction< std::vector<double>, int >* refineFct_, + DOFVector<double>* vec1_, + DOFVector<double>* vec2_ = NULL, + DOFVector<double>* vec3_ = NULL) : + RefinementLevel< std::vector<double>, int >(feSpace_, refineFct_) + { + vecs.push_back(vec1_); + if(vec2_ != NULL) vecs.push_back(vec2_); + if(vec3_ != NULL) vecs.push_back(vec3_); + }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelDOF::markElements()"); + + const DOFAdmin* admin = feSpace->getAdmin(); + const BasisFunction *basFcts = feSpace->getBasisFcts(); + int numBasFcts = basFcts->getNumber(); + + DegreeOfFreedom *localIndices = new DegreeOfFreedom[numBasFcts]; + FixVec<WorldVector<double>, VERTEX> coords(mesh->getDim(), NO_INIT); + double meanValue; + + bool elMarkRefine = false, elMarkCoarsen = false; + + std::vector<ElementFunctionDOFVec<double>*> elFcts; + for (unsigned i = 0; i < vecs.size(); ++i) { + elFcts.push_back(new ElementFunctionDOFVec<double>(vecs[i])); + } + DimVec<double> lambda(mesh->getDim(), NO_INIT); + for (int i= 0; i < lambda.getSize(); ++i) + lambda[i] = 1.0 / lambda.getSize(); + + Flag traverseFlag = Mesh::CALL_LEAF_EL; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + while(elInfo) { + std::vector<double> meanValues; + for (unsigned v = 0; v < vecs.size(); ++v) { + elFcts[v]->setElInfo(elInfo); + meanValues.push_back( (*(elFcts[v]))(lambda) ); + } + + int refineLevel = (*refineFct)(meanValues); + int oldLevel = elInfo->getLevel(); + elInfo->getElement()->setMark( calcMark(refineLevel, oldLevel) ); + + elMarkRefine |= elInfo->getElement()->getMark() == 1; + elMarkCoarsen |= elInfo->getElement()->getMark() == -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag= 0; + if(elMarkRefine) + markFlag= 1; + if(elMarkCoarsen) + markFlag|= 2; + + delete [] localIndices; + }; +private: + std::vector<DOFVector<double>*> vecs; +}; + + + +/** \brief + * Refinement structure to perform local anisotropic refinement depending + * on a refineFunction that defines the local refinement level to a given + * list of values, like phase-values or distance-values. + **/ +class RefinementLevelES : public RefinementLevel< std::vector<double>, int > +{ +public: + RefinementLevelES( + const FiniteElemSpace *feSpace_, + MeshRefinementFunction< std::vector<double>, int >* refineFct_, + DOFVector<double>* vec1_, + DOFVector<double>* vec2_, + DOFVector<double>* phase_, + double tol_) : + RefinementLevel< std::vector<double>, int >(feSpace_, refineFct_), + phase(phase_), + tol(tol_) + { + vecs.push_back(vec1_); + vecs.push_back(vec2_); + }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelDOF::markElements()"); + + const DOFAdmin* admin = feSpace->getAdmin(); + const BasisFunction *basFcts = feSpace->getBasisFcts(); + int numBasFcts = basFcts->getNumber(); + + DegreeOfFreedom *localIndices = new DegreeOfFreedom[numBasFcts]; + FixVec<WorldVector<double>, VERTEX> coords(mesh->getDim(), NO_INIT); + double meanValue; + + bool elMarkRefine = false, elMarkCoarsen = false; + + std::vector<ElementFunctionDOFVec<double>*> elFcts; + for (unsigned i = 0; i < vecs.size(); ++i) { + elFcts.push_back(new ElementFunctionDOFVec<double>(vecs[i])); + } + ElementFunctionDOFVec<double>* elFct_phase = new ElementFunctionDOFVec<double>(phase); + DimVec<double> lambda(mesh->getDim(), NO_INIT); + for (int i= 0; i < lambda.getSize(); ++i) + lambda[i] = 1.0 / lambda.getSize(); + + Flag traverseFlag = Mesh::CALL_LEAF_EL; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + +// int n = 0; +// double mean = 0.0; +// while(elInfo) { +// elFct_phase->setElInfo(elInfo); +// if ((*elFct_phase)(lambda) > 0.001) { +// std::vector<double> meanValues; +// meanValues.push_back(0.0); +// for (unsigned v = 0; v < vecs.size(); ++v) { +// elFcts[v]->setElInfo(elInfo); +// meanValues.push_back( (*(elFcts[v]))(lambda) ); +// } +// +// double value = refineFct->indicator(meanValues); +// mean += value; +// n++; +// } +// elInfo = stack.traverseNext(elInfo); +// } +// mean /= n; +// MSG("mean value = %e\n", mean); + + elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + int nCoarse = 0; + while(elInfo) { + elFct_phase->setElInfo(elInfo); + if ((*elFct_phase)(lambda) > 0.0001) { + std::vector<double> meanValues; + meanValues.push_back(tol); + for (unsigned v = 0; v < vecs.size(); ++v) { + elFcts[v]->setElInfo(elInfo); + meanValues.push_back( (*(elFcts[v]))(lambda) ); + } + + int refineLevel = (*refineFct)(meanValues); + nCoarse += refineLevel; + elInfo->getElement()->setMark( refineLevel ); + } else { + elInfo->getElement()->setMark( -1 ); + } + + elMarkRefine |= elInfo->getElement()->getMark() == 1; + elMarkCoarsen |= elInfo->getElement()->getMark() == -1; + elInfo = stack.traverseNext(elInfo); + } + MSG("number of elements marked for coarsening: %d\n", abs(nCoarse)); + + markFlag= 0; + if(elMarkRefine) + markFlag= 1; + if(elMarkCoarsen) + markFlag|= 2; + + delete [] localIndices; + }; +private: + std::vector<DOFVector<double>*> vecs; + DOFVector<double>* phase; + double tol; +}; +#endif // REFINEMENT_LEVEL_PHASEFIELD_H + diff --git a/extensions/Refinement_MeshSize.h b/extensions/Refinement_MeshSize.h new file mode 100644 index 0000000000000000000000000000000000000000..1348e59adcdd502b287da00e0663ddfee91afa66 --- /dev/null +++ b/extensions/Refinement_MeshSize.h @@ -0,0 +1,251 @@ +/** \file Refinement_MeshSize.h */ + +#ifndef REFINEMENT_MESHSIZE_H +#define REFINEMENT_MESHSIZE_H + +using namespace AMDiS; + +/** \brief + * Refinement structure to perform local anisotropic refinement depending + * on a refineFunction that defines the local refinement level to given + * coordinates. + **/ +class RefinementMeshSizeCoords : public RefinementLevel<WorldVector<double>, double > +{ +public: + RefinementMeshSizeCoords(FiniteElemSpace *feSpace_, MeshRefinementFunction<WorldVector<double>, double >* refineFct_) : + RefinementLevel<WorldVector<double>, double >(feSpace_, refineFct_) { }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelCoords::markElements()"); + + FixVec<WorldVector<double>, VERTEX> coords(mesh->getDim(), NO_INIT); + WorldVector<double> center; + + bool elMarkRefine = false, elMarkCoarsen = false; + + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + while (elInfo) { + coords = elInfo->getCoords(); + center.set(0.0); + for (int i = 0; i < coords.size(); ++i) { + center += coords[i]; + } + center *= 1.0 / static_cast<double>(coords.size()); + + double refineH = (*refineFct)(center); + double oldH = calcMeshSize(elInfo); + elInfo->getElement()->setMark( calcMark(refineH, oldH) ); + + elMarkRefine |= elInfo->getElement()->getMark() == 1; + elMarkCoarsen |= elInfo->getElement()->getMark() == -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag = 0; + if (elMarkRefine) + markFlag = 1; + if (elMarkCoarsen) + markFlag |= 2; + }; +}; + + +/** \brief + * Refinement structure to perform local anisotropic refinement depending + * on a refineFunction that defines the local refinement level to a given + * value, like phase-value or distance-value. + **/ +class RefinementMeshSizeDOF : public RefinementLevel<double, double> +{ +public: + RefinementMeshSizeDOF(FiniteElemSpace *feSpace_, MeshRefinementFunction<double, double>* refineFct_, DOFVector<double> *vec_) : + RefinementLevel<double, double>(feSpace_, refineFct_), + vec(vec_) { }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelDOF::markElements()"); + + double meanValue; + + ElementFunctionDOFVec<double> elFct(vec); + DimVec<double> lambda(mesh->getDim(), NO_INIT); + for (int i = 0; i < lambda.getSize(); ++i) + lambda[i] = 1.0 / lambda.getSize(); + + bool elMarkRefine = false, elMarkCoarsen = false; + + Flag traverseFlag = Mesh::CALL_LEAF_EL; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + while (elInfo) { + elFct.setElInfo(elInfo); + meanValue = elFct(lambda); + + double refineH = (*refineFct)(meanValue); + double oldH = calcMeshSize(elInfo); + elInfo->getElement()->setMark( calcMark(refineH, oldH) ); + + + elMarkRefine |= elInfo->getElement()->getMark() == 1; + elMarkCoarsen |= elInfo->getElement()->getMark() == -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag = 0; + if (elMarkRefine) + markFlag = 1; + if (elMarkCoarsen) + markFlag |= 2; + }; + +private: + + DOFVector<double>* vec; +}; + + +/** \brief + * Refinement structure to perform local anisotropic refinement depending + * on a refineFunction that defines the local refinement level to a given + * value, like phase-value or distance-value, and the center coords of the + * element. + **/ +class RefinementMeshSizeCoordsDOF : public RefinementLevel<std::pair<WorldVector<double>, double>, double > +{ +public: + + RefinementMeshSizeCoordsDOF(FiniteElemSpace *feSpace_, MeshRefinementFunction<std::pair<WorldVector<double>, double>, double >* refineFct_, DOFVector<double> *vec_) : + RefinementLevel<std::pair<WorldVector<double>, double>, double >(feSpace_, refineFct_), vec(vec_) { }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelCoordsDOF::markElements()"); + + double meanValue; + FixVec<WorldVector<double>, VERTEX> coords(mesh->getDim(), NO_INIT); + WorldVector<double> center; + + ElementFunctionDOFVec<double> elFct(vec); + DimVec<double> lambda(mesh->getDim(), NO_INIT); + for (int i= 0; i<lambda.getSize(); ++i) + lambda[i]= 1.0/lambda.getSize(); + + bool elMarkRefine= false, elMarkCoarsen= false; + + Flag traverseFlag= Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS; + TraverseStack stack; + ElInfo *elInfo= stack.traverseFirst(mesh, -1, traverseFlag); + while (elInfo) { + elFct.setElInfo(elInfo); + meanValue = elFct(lambda); + coords = elInfo->getCoords(); + center.set(0.0); + for (int i = 0; i < coords.size(); ++i) { + center += coords[i]; + } + center *= 1.0 / static_cast<double>(coords.size()); + + double refineH = (*refineFct)(std::make_pair<WorldVector<double>, double>(center, meanValue)); + double oldH = calcMeshSize(elInfo); + elInfo->getElement()->setMark( calcMark(refineH, oldH) ); + + elMarkRefine |= elInfo->getElement()->getMark() == 1; + elMarkCoarsen |= elInfo->getElement()->getMark() == -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag = 0; + if (elMarkRefine) + markFlag = 1; + if (elMarkCoarsen) + markFlag |= 2; + }; + +private: + + DOFVector<double>* vec; +}; + + +/** \brief + * Refinement structure to perform local anisotropic refinement depending + * on a refineFunction that defines the local refinement level to a given + * list of values, like phase-values or distance-values. + **/ +class RefinementMeshSizeDOFList : public RefinementLevel< std::vector<double>, double > +{ +public: + RefinementMeshSizeDOFList( + FiniteElemSpace *feSpace_, + MeshRefinementFunction< std::vector<double>, double >* refineFct_, + DOFVector<double>* vec1_, + DOFVector<double>* vec2_ = NULL, + DOFVector<double>* vec3_ = NULL) : + RefinementLevel< std::vector<double>, double >(feSpace_, refineFct_) + { + vecs.push_back(vec1_); + if(vec2_ != NULL) vecs.push_back(vec2_); + if(vec3_ != NULL) vecs.push_back(vec3_); + }; + + void markElements(Flag &markFlag) + { + FUNCNAME("RefinementLevelDOF::markElements()"); + + const DOFAdmin* admin = feSpace->getAdmin(); + const BasisFunction *basFcts = feSpace->getBasisFcts(); + int numBasFcts = basFcts->getNumber(); + + DegreeOfFreedom *localIndices = new DegreeOfFreedom[numBasFcts]; + FixVec<WorldVector<double>, VERTEX> coords(mesh->getDim(), NO_INIT); + double meanValue; + + bool elMarkRefine = false, elMarkCoarsen = false; + + std::vector<ElementFunctionDOFVec<double>*> elFcts; + for (unsigned i = 0; i < vecs.size(); ++i) { + elFcts.push_back(new ElementFunctionDOFVec<double>(vecs[i])); + } + DimVec<double> lambda(mesh->getDim(), NO_INIT); + for (int i= 0; i < lambda.getSize(); ++i) + lambda[i] = 1.0 / lambda.getSize(); + + Flag traverseFlag = Mesh::CALL_LEAF_EL; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); + while(elInfo) { + std::vector<double> meanValues; + for (unsigned v = 0; v < vecs.size(); ++v) { + elFcts[v]->setElInfo(elInfo); + meanValues.push_back( (*(elFcts[v]))(lambda) ); + } + + double refineH = (*refineFct)(meanValues); + double oldH = calcMeshSize(elInfo); + elInfo->getElement()->setMark( calcMark(refineH, oldH) ); + + elMarkRefine |= elInfo->getElement()->getMark() == 1; + elMarkCoarsen |= elInfo->getElement()->getMark() == -1; + elInfo = stack.traverseNext(elInfo); + } + + markFlag= 0; + if(elMarkRefine) + markFlag= 1; + if(elMarkCoarsen) + markFlag|= 2; + + delete [] localIndices; + }; +private: + std::vector<DOFVector<double>*> vecs; +}; + + +#endif // REFINEMENT_MESHSIZE_H + diff --git a/extensions/SignedDistFunctors.h b/extensions/SignedDistFunctors.h new file mode 100644 index 0000000000000000000000000000000000000000..09d0a376e207d37c0910b90ef553bfd5a9570a3c --- /dev/null +++ b/extensions/SignedDistFunctors.h @@ -0,0 +1,608 @@ +/** \file SignedDistFunctors.h */ + +#ifndef SIGNED_DIST_FUNCTORS_H +#define SIGNED_DIST_FUNCTORS_H + +#include "VectorOperations.h" +#include "GeometryTools.h" + +using namespace std; +using namespace AMDiS; +using namespace vector_operations; + +/** + * A collection of signed-dist function describing several gemoetric objects: + * - Circle(radius [, center]) + * - PerturbedCircle(radius [, center]) + * - TwoCircles(radius, center1, center2) + * - InverseCircle(radius [, center]) + * - InverseCircles(radius, vector(centers)) + * - Rectangle(width, height [, center]) + * - Ellipse(a,b [, center]) + * - Lemniskate(width, center) + * - Plane(shift) + * - PlaneRotation(shift, angle) + * - Propeller(radius, angle) + * - Torus(radius1, radius2) + * - Polygon(v0, v1, v2, v2), or Polygon(vec(v_i)) + **/ + +// signed distance functions for surfaces in polar coords +static double signedDist2D(const WorldVector<double> x, const WorldVector<double> midPoint, + AbstractFunction<double, double> *radius, double eps) +{ + FUNCNAME("signedDist2D"); + WorldVector<double> x_trans; + double norm_xy; + double alpha; + + TEST_EXIT(x.getSize() == 2)("Dimension of world must be 2 to use signedDist2D-function. Use signedDist3D instead!"); + + x_trans.fill(0.0); + for (int k = 0; k < x.getSize(); k++) { + x_trans[k] = x[k] - midPoint[k]; + } + + norm_xy = epsNorm(x_trans, eps); + + if (x_trans[0] >= 0.0) { + alpha = acos(x_trans[0] / norm_xy); + } else { + alpha = 2.0*M_PI - acos(x_trans[0] / norm_xy); + } + + return (norm_xy - (*radius)(alpha)); +}; + +static double signedDist3D(const WorldVector<double> x, const WorldVector<double> midPoint, + BinaryAbstractFunction<double, double, double> *radius, double eps) +{ + FUNCNAME("signedDist3D"); + WorldVector<double> x_trans; + double norm_xyz, norm_xy; + double alpha, beta; + + TEST_EXIT(x.getSize() == 3)("Dimension of world must be 3 to use signedDist3D-function. Use signedDist2D instead!"); + + x_trans.fill(0.0); + for (int k = 0; k < x.getSize(); k++) { + x_trans[k] = x[k] - midPoint[k]; + } + + norm_xyz = epsNorm(x_trans, eps); + norm_xy = sqrt(sqr(x_trans[0]) + sqr(x_trans[1]) + sqr(eps)); + + if(x_trans[1]>=0) { + alpha = acos(x_trans[0]/norm_xy); + } else { + alpha = 2.0*M_PI - acos(x_trans[0]/norm_xy); + } + beta = 0.5*M_PI - atan(x_trans[2]/norm_xy); + + return (norm_xyz - (*radius)(alpha, beta)); +}; + +// radius-functions +// ================ + +class CircleRadius : public AbstractFunction<double, double> +{ +public: + CircleRadius(double radius_) : radius(radius_) {}; + double operator()(const double& alpha) const { return radius; }; +protected: + double radius; +}; + +class BallRadius : public BinaryAbstractFunction<double, double, double> +{ +public: + BallRadius(double radius_) : radius(radius_) {}; + double operator()(const double &alpha, const double &beta) const { return radius; }; +protected: + double radius; +}; + +class PerturbedCircleRadius : public AbstractFunction<double, double> +{ +public: + + PerturbedCircleRadius(const double radius_, const double strength_, const int period_) : + radius(radius_), strength(strength_), rotation(0.0), period(period_) {}; + PerturbedCircleRadius(const double radius_, const double strength_, const int period_, const double rotation_) : + radius(radius_), strength(strength_), rotation(rotation_), period(period_) {}; + double operator()(const double &alpha) const + { + double result = 1.0 + strength * cos(period * alpha + rotation); + result *= radius; + return result; + }; + +protected: + + double radius; + double strength; + double rotation; + int period; +}; + +class PerturbedBallRadius : public BinaryAbstractFunction<double, double, double> +{ +public: + + PerturbedBallRadius(const double radius_, const double strength_, const int period_) : + radius(radius_), strength(strength_), period(period_) {}; + double operator()(const double &alpha, const double &beta) const + { + double result = 1.0 + strength * (cos(period*alpha) + cos(period*beta) * cos(period*alpha)); + result *= radius; + return result; + }; + +protected: + + double radius; + double strength; + int period; +}; + +// lemniscate of Bernoulli +class LemniskateRadius : public AbstractFunction<double, double> +{ +public: + + LemniskateRadius(const double breite_) : breite(breite_) {}; + double operator()(const double &alpha) const + { + double result = 2*cos(2*alpha); + result = breite*result; + return result; + }; + +protected: + + double breite; +}; + +// lemniscate of Bernoulli in 3D +class Lemniskate3D : public BinaryAbstractFunction<double, double, double> +{ +public: + + Lemniskate3D(const double breite_) : breite(breite_) {}; + double operator()(const double &alpha, const double &beta) const + { + double result = 2*breite*cos(2*alpha)*sin(beta); + return result; + }; + +protected: + + double breite; +}; + +class EllipseRadius : public AbstractFunction<double, double> +{ +public: + + EllipseRadius(const double a_, const double b_) : + a(a_), b(b_) {}; + double operator()(const double &alpha) const + { + double x=b*cos(alpha), y=a*sin(alpha); + return a*b / sqrt(x*x+y*y); + }; + +protected: + + double a,b; +}; + +class EllipsoidRadius : public BinaryAbstractFunction<double, double, double> +{ +public: + + EllipsoidRadius(const double a_, const double b_, const double c_) : + a(a_), b(b_), c(c_) {}; + double operator()(const double &alpha, const double &beta) const + { + double sa = sin(alpha), sb = sin(beta); + double ca = cos(alpha), cb = cos(beta); + double x = a*sa*cb, y = b*sa*sb, z = c*ca; + + return sqrt(x*x+y*y+z*z); + }; + +protected: + + double a,b,c; +}; + +// ============================================================= + +class PlaneRotation : public AbstractFunction<double, WorldVector<double> > +{ +public: + + PlaneRotation(double shift_, double theta_, double factor_=1.0) : + shift(shift_), theta(theta_), factor(factor_) {} + double operator()(const WorldVector<double>& x) const + { + double x_temp; + x_temp= cos(theta)*x[0] - sin(theta)*x[1]; +// x_temp[1]= sin(theta)*x[0] + cos(theta)*x[1]; + return factor*(shift-x_temp); + }; + +private: + + double shift; + int comp; + double theta; + double factor; +}; + +class Plane : public AbstractFunction<double, WorldVector<double> > +{ +public: + + Plane(double shift_, double factor_=1.0) : + shift(shift_), factor(factor_) {} + double operator()(const WorldVector<double>& x) const + { + return factor*(shift-x[1]); + }; + +private: + + double shift; + int comp; + double factor; +}; + +class One : public AbstractFunction<double, WorldVector<double> > +{ +public: + double operator()(const WorldVector<double>& x) const + { + return 1.0; + }; +}; + +class Rectangle : public AbstractFunction<double, WorldVector<double> > +{ +public: + + Rectangle(double width_, double height_) : width(width_), height(height_) {shift.set(0.0);only2D();} + Rectangle(double width_, double height_, WorldVector<double> shift_) : width(width_), height(height_),shift(shift_) {only2D();} + double operator()(const WorldVector<double>& x0) const + { + WorldVector<double> x=x0-shift; + double result=0.0; + if(abs(x[0])<width/2.0 && abs(x[1])<height/2.0) { + result = -std::min(abs(abs(x[0])-width/2.0),abs(abs(x[1])-height/2.0)); + } else if(abs(x[0])<width/2.0) { + result = abs(abs(x[1])-height/2.0); + } else if(abs(x[1])<height/2.0) { + result = abs(abs(x[0])-width/2.0); + } else { + WorldVector<double> corner; + corner[0] = abs(x[0])-width/2.0; + corner[1] = abs(x[1])-height/2.0; + result = norm(corner); + } + return result; + }; + void only2D() { TEST_EXIT(shift.getSize()==2)("Rectangle is defined only for 2 dimension!\n"); } + +private: + + double width,height; + WorldVector<double> shift; +}; + +// simple circle: phi_0(x,y) := sqrt(x^2+y^2)-r +class Circle : public AbstractFunction<double, WorldVector<double> > +{ +public: + + Circle(double radius_, WorldVector<double> midPoint_, double factor_ = 1.0) : + radius(radius_), midPoint(midPoint_), factor(factor_) {} + Circle(double radius_, double factor_ = 1.0) : + radius(radius_), factor(factor_) { midPoint.set(0.0); } + double operator()(const WorldVector<double>& x) const + { + double result = 0.0; + + for(int k=0; k<x.getSize(); k++) { + result += sqr(x[k]-midPoint[k]); + } + result = sqrt(result)-radius; + return factor * result; + }; + +private: + + double radius; + WorldVector<double> midPoint; + double factor; +}; + +class InverseCircle : public AbstractFunction<double, WorldVector<double> > +{ +public: + + InverseCircle(double radius_, WorldVector<double> midPoint_) : + radius(radius_), midPoint(midPoint_) {} + InverseCircle(double radius_) : + radius(radius_) { midPoint.set(0.0); } + double operator()(const WorldVector<double>& x) const + { + double result = 0.0; + + for(int k=0; k<x.getSize(); k++) { + result += sqr(x[k]-midPoint[k]); + } + result = sqrt(result)-radius; + return -result; + }; + +private: + + double radius; + WorldVector<double> midPoint; +}; + + +class InverseCircles : public AbstractFunction<double, WorldVector<double> > +{ +public: + InverseCircles(double radius_, std::vector<WorldVector<double> > pos_) : + radius(radius_), pos(pos_) {} + InverseCircles(double radius_) : + radius(radius_) + { + WorldVector<double> center; center.set(0.0); + pos.push_back(center); + } + + double operator()(const WorldVector<double>& x) const + { + std::vector<double> result(pos.size(),0.0); + + for(int k=0; k<x.getSize(); k++) { + for (int j=0; j<pos.size(); j++) { + result[j] += sqr(x[k]-pos[j][k]); + } + } + double minResult = 1.e10; + for (int j=0; j<pos.size(); j++) { + minResult = std::min(minResult, sqrt(result[j])-radius); + } + return -minResult; + } +private: + double radius; + std::vector<WorldVector<double> > pos; +}; + + +class TwoCircles : public AbstractFunction<double, WorldVector<double> > +{ +public: + + TwoCircles(double radius_, WorldVector<double> pos1_, WorldVector<double> pos2_) : + radius(radius_), pos1(pos1_), pos2(pos2_) {} + double operator()(const WorldVector<double>& x) const + { + double result1=0.0, result2=0.0; + + for(int k=0; k<x.getSize(); k++) { + result1 += sqr(x[k]-pos1[k]); + result2 += sqr(x[k]-pos2[k]); + } + result1 = sqrt(result1)-radius; + result2 = sqrt(result2)-radius; + return -std::min(result1,result2); + }; + +private: + + double radius; + WorldVector<double> pos1,pos2; +}; + +// perturbed circle +class PertCircle : public AbstractFunction<double, WorldVector<double> > +{ +public: + + PertCircle(double radius_, double strength_, int period_) : + radius(radius_), strength(strength_), period(period_) { midPoint.set(0.0); } + PertCircle(double radius_, double strength_, int period_, WorldVector<double> midPoint_) : + radius(radius_), strength(strength_), period(period_), midPoint(midPoint_) {} + double operator()(const WorldVector<double>& x) const + { + double result=0.0; + if(x.getSize()==2) { + PerturbedCircleRadius perturbedCircle(radius, strength, period); + result = signedDist2D(x, midPoint, &perturbedCircle, 1.e-6); + } else { + PerturbedBallRadius perturbedBall(radius, strength, period); + result = signedDist3D(x, midPoint, &perturbedBall, 1.e-6); + } + return result; + }; + +private: + + double radius; + double strength; + int period; + WorldVector<double> midPoint; +}; + +class Propeller : public AbstractFunction<double, WorldVector<double> > +{ +public: + + Propeller(double radius_, double rotation_) : + radius(radius_), rotation(rotation_) { midPoint.set(0.0); } + Propeller(WorldVector<double> midPoint_, double radius_, double rotation_) : + radius(radius_), rotation(rotation_),midPoint(midPoint_) {} + double operator()(const WorldVector<double>& x) const + { + double result=0.0; + PerturbedCircleRadius perturbedCircle(radius, 1.0, 3, rotation); + result = signedDist2D(x, midPoint, &perturbedCircle, 1.e-6); + return -result; + }; + +private: + + double radius; + double rotation; + WorldVector<double> midPoint; +}; + +class Lemniskate : public AbstractFunction<double, WorldVector<double> > +{ +public: + + Lemniskate(double breite_, WorldVector<double> midPoint_) : + breite(breite_), midPoint(midPoint_) {} + double operator()(const WorldVector<double>& x) const + { + double result=0.0; + if(x.getSize()==2) { + LemniskateRadius lemniskate(breite); + result = signedDist2D(x, midPoint, &lemniskate, 1.e-6); + } else { + Lemniskate3D lemniskate(breite); + result = signedDist3D(x, midPoint, &lemniskate, 1.e-6); + } + return result; + }; + +private: + + double breite; + WorldVector<double> midPoint; +}; + +class Ellipse : public AbstractFunction<double, WorldVector<double> > +{ +public: + + Ellipse(double a_, double b_) : + a(a_), b(b_), c(0.0) { midPoint.set(0.0); } + Ellipse(double a_, double b_, WorldVector<double> midPoint_) : + a(a_), b(b_), c(0.0), midPoint(midPoint_) {} + Ellipse(double a_, double b_, double c_) : + a(a_), b(b_), c(c_) { midPoint.set(0.0); } + Ellipse(double a_, double b_, double c_, WorldVector<double> midPoint_) : + a(a_), b(b_), c(c_), midPoint(midPoint_) {} + double operator()(const WorldVector<double>& x) const + { + double result = sqr(x[0]-midPoint[0])/sqr(a); + result+= sqr(x[1]-midPoint[1])/sqr(b); + if(x.getSize()>2) { + result+= sqr(x[2]-midPoint[2])/sqr(c); + } + result = 1.0-sqrt(result); + return result; + }; + +private: + + double a,b,c; + WorldVector<double> midPoint; +}; + +class Torus : public AbstractFunction<double, WorldVector<double> > +{ +public: + + Torus(double r1_, double r2_) : + r1(r1_), r2(r2_) { midPoint.set(0.0); only3D(); } + Torus(double r1_, double r2_, WorldVector<double> midPoint_) : + r1(r1_), r2(r2_), midPoint(midPoint_) { only3D(); } + void only3D() { TEST_EXIT(midPoint.getSize()==3)("Torus is defined in 3D only!\n"); } + double operator()(const WorldVector<double>& x) const + { + double result=0.0; + result = sqr(x[0]-midPoint[0])+sqr(x[1]-midPoint[1]); + result = sqr(sqrt(result)-r1)+ sqr(x[2]-midPoint[2]); + result = sqrt(result)-r2; + + return result; + }; + +private: + + double r1,r2; + WorldVector<double> midPoint; +}; + + +class Polygon : public AbstractFunction<double, WorldVector<double> > +{ +public: + + Polygon(WorldVector<double> x0_, WorldVector<double> x1_, WorldVector<double> x2_, WorldVector<double> x3_, double factor_=1.0) : factor(factor_) + { + vertices.push_back(x0_); + vertices.push_back(x1_); + vertices.push_back(x2_); + vertices.push_back(x3_); + vertices.push_back(x0_); + } + + Polygon(std::vector<WorldVector<double> > xi_, double factor_=1.0) : vertices(xi_), factor(factor_) { } + + double operator()(const WorldVector<double>& x) const + { + double result = 1.e15; + for (size_t i = 0; i < vertices.size()-1; i++) + result = std::min(result, meshconv::distance_point_line_2d(x.begin(), vertices[i].begin(), vertices[i+1].begin())); + return factor * result * (meshconv::point_in_polygon(x.begin(), vertices) ? -1.0 : 1.0); + } + + void refine(int np) + { + std::vector<WorldVector<double> > newVertices; + + for (size_t i = 0; i < vertices.size()-1; i++) { + for (size_t j = 0; j < np-1; j++) { + double lambda = static_cast<double>(j)/static_cast<double>(np - 1.0); + WorldVector<double> p = lambda*vertices[i+1] + (1.0-lambda)*vertices[i]; + newVertices.push_back(p); + } + } + swap(vertices, newVertices); + } + + void move(const DOFVector<WorldVector<double> >* velocity) + { + for (size_t i = 0; i < vertices.size()-1; i++) { + WorldVector<double> shift = evalAtPoint(*velocity, vertices[i]); + vertices[i] += shift; + } + vertices[vertices.size()-1] = vertices[0]; + } + + void move(AbstractFunction<WorldVector<double>, WorldVector<double> >* velocity) + { + for (size_t i = 0; i < vertices.size()-1; i++) { + WorldVector<double> shift = (*velocity)(vertices[i]); + vertices[i] += shift; + } + vertices[vertices.size()-1] = vertices[0]; + } + +private: + std::vector<WorldVector<double> > vertices; + double factor; +}; + +#endif // SIGNED_DIST_FUNCTORS_H diff --git a/extensions/SingularDirichletBC.h b/extensions/SingularDirichletBC.h new file mode 100644 index 0000000000000000000000000000000000000000..da686272a221e3aed03269ff881df7b42c16ea0c --- /dev/null +++ b/extensions/SingularDirichletBC.h @@ -0,0 +1,501 @@ +/** \file SingularDirichletBC.h */ + +#ifndef SINGULAR_DIRICHLET_BC_H +#define SINGULAR_DIRICHLET_BC_H + +#include "AMDiS.h" + +namespace AMDiS { + +/** + * data structure that holds DOF-Index and double value for singular dirichlet boundary condition. + **/ +struct SingularDirichletBC { + SingularDirichletBC(int i_, int j_, DegreeOfFreedom idx_, double value_) : + row(i_), col(j_), idx(idx_), value(value_) {} + + int row, col; + DegreeOfFreedom idx; + double value; +}; + +/** + * data structure that holds all periodic associations. + **/ +struct ManualPeriodicBC { + ManualPeriodicBC(size_t row_, std::vector<std::pair<DegreeOfFreedom, DegreeOfFreedom> > &indices_) : + row(row_), indices(indices_) {} + + size_t row; + std::vector<std::pair<DegreeOfFreedom, DegreeOfFreedom> > indices; +}; + +namespace details { + + /** + * traverses the mesh and stores all DegreeOfFreedom, that lie on the boundary with index 'nr' + * and have coordinates that give true in the 'meshIndicator', into a vector of 'indices'. + **/ + inline void getBoundaryIndices(const FiniteElemSpace* feSpace, + BoundaryType nr, + AbstractFunction<bool, WorldVector<double> >* meshIndicator, + std::vector<DegreeOfFreedom> &indices) + { + Mesh* mesh = feSpace->getMesh(); + int dim = mesh->getDim(); + const BasisFunction *basFcts = feSpace->getBasisFcts(); + int numBasFcts = basFcts->getNumber(); + std::vector<DegreeOfFreedom> localIndices(numBasFcts); + + indices.clear(); + + WorldVector<double> coord; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, + Mesh::CALL_LEAF_EL | Mesh::FILL_BOUND | Mesh::FILL_COORDS); + while (elInfo) { + for (int face = 0; face < dim + 1; face++) { + if (elInfo->getBoundary(face) == nr) { + basFcts->getLocalIndices(elInfo->getElement(), feSpace->getAdmin(), localIndices); + + for (int i = 0; i < numBasFcts; i++) { + elInfo->coordToWorld(*(basFcts->getCoords(i)), coord); + if ((*meshIndicator)(coord)) + indices.push_back(localIndices[i]); + } + break; + } + } + + elInfo = stack.traverseNext(elInfo); + } + } + + /** + * traverses the mesh and stores all DegreeOfFreedom, that have coordinates that give true + * in the 'meshIndicator', into a vector of 'indices'. + **/ + inline void getBoundaryIndices(const FiniteElemSpace* feSpace, + AbstractFunction<bool, WorldVector<double> >* meshIndicator, + std::vector<DegreeOfFreedom> &indices) + { + Mesh* mesh = feSpace->getMesh(); + int dim = mesh->getDim(); + const BasisFunction *basFcts = feSpace->getBasisFcts(); + int numBasFcts = basFcts->getNumber(); + std::vector<DegreeOfFreedom> localIndices(numBasFcts); + + indices.clear(); + + WorldVector<double> coord; + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, + Mesh::CALL_LEAF_EL | Mesh::FILL_BOUND | Mesh::FILL_COORDS); + while (elInfo) { + for (int face = 0; face < dim + 1; face++) { + if (elInfo->getBoundary(face) != 0) { + basFcts->getLocalIndices(elInfo->getElement(), feSpace->getAdmin(), localIndices); + + for (int i = 0; i < numBasFcts; i++) { + elInfo->coordToWorld(*(basFcts->getCoords(i)), coord); + if ((*meshIndicator)(coord)) + indices.push_back(localIndices[i]); + } + break; + } + } + + elInfo = stack.traverseNext(elInfo); + } + } + + inline void getImplicitIndices(const FiniteElemSpace* feSpace, + AbstractFunction<double, WorldVector<double> >* signedDistFct, + std::vector<DegreeOfFreedom> &indices) + { + const BasisFunction *vecBasisFcts = feSpace->getBasisFcts(); + int nVecBasisFcts = vecBasisFcts->getNumber(); + + std::vector<DegreeOfFreedom> vecLocalIndices(nVecBasisFcts); + + DOFVector<short int> visited(feSpace, "visited"); visited.set(0); + WorldVector<double> coord; + TraverseStack stack; + Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS; + ElInfo *elInfo = stack.traverseFirst(feSpace->getMesh(), -1, traverseFlag); + + while (elInfo) { + Element *el = elInfo->getElement(); + vecBasisFcts->getLocalIndices(el, feSpace->getAdmin(), vecLocalIndices); + + for (int i = 0; i < nVecBasisFcts; i++) { + if ( visited[vecLocalIndices[i]] == 0 ) { + elInfo->coordToWorld(*(vecBasisFcts->getCoords(i)), coord); + if ( (*signedDistFct)(coord) <= DBL_TOL ) { // eventuell nur Koordinaten an Gitterknoten bekommen! + indices.push_back(vecLocalIndices[i]); + } + visited[vecLocalIndices[i]] = 1; + } + } + elInfo = stack.traverseNext(elInfo); + } + } + + inline void getImplicitIndices(const FiniteElemSpace* feSpace, + DOFVector<double>* signedDistDOF, + std::vector<DegreeOfFreedom> &indices) + { + + const BasisFunction *vecBasisFcts = feSpace->getBasisFcts(); + int nVecBasisFcts = vecBasisFcts->getNumber(); + + std::vector<DegreeOfFreedom> vecLocalIndices(nVecBasisFcts); + ElementVector signedDistLocalCoeffs(nVecBasisFcts); + + DimVec<double> *baryCoords = NULL; + DOFVector<short int> visited(feSpace, "visited"); visited.set(0); + TraverseStack stack; + Flag traverseFlag = Mesh::CALL_LEAF_EL; + ElInfo *elInfo = stack.traverseFirst(feSpace->getMesh(), -1, traverseFlag); + + while (elInfo) { + Element *el = elInfo->getElement(); + + vecBasisFcts->getLocalIndices(el, feSpace->getAdmin(), vecLocalIndices); + signedDistDOF->getLocalVector(el, signedDistLocalCoeffs); + + for (int i = 0; i < nVecBasisFcts; i++) { + if ( visited[vecLocalIndices[i]] == 0 ) { + baryCoords = vecBasisFcts->getCoords(i); + + double dist = vecBasisFcts->evalUh(*baryCoords, signedDistLocalCoeffs); + if (dist <= DBL_TOL) { + indices.push_back(vecLocalIndices[i]); + } + visited[vecLocalIndices[i]] = 1; + } + } + elInfo = stack.traverseNext(elInfo); + } + } + + /** + * get al list of pairs that describes wich DegreeOfFreedom are assiciated in the given mesh + * with given feSpace. Uses the function getBoundaryIndices(). + * The 'nr' and 'meshIndicator' describe one boundary of the mesh and to each DegreeOfFreedom + * the 'periodicMap' associates a second DegreeOfFreedom. + **/ + inline void getPeriodicAssociation(const FiniteElemSpace* feSpace, + BoundaryType nr, + AbstractFunction<bool, WorldVector<double> >* meshIndicator, + AbstractFunction<WorldVector<double>, WorldVector<double> >* periodicMap, + std::vector<std::pair<DegreeOfFreedom, DegreeOfFreedom> > &association) + { + std::vector<DegreeOfFreedom> indices; + details::getBoundaryIndices(feSpace, nr, meshIndicator, indices); + + association.clear(); + + DOFVector<WorldVector<double> > coords(feSpace, "coords"); + feSpace->getMesh()->getDofIndexCoords(feSpace, coords); + for (size_t i = 0; i < indices.size(); i++) + { + DegreeOfFreedom idx2; + WorldVector<double> p; + p = (*periodicMap)(coords[indices[i]]); + TEST_EXIT(coords.getDofIdxAtPoint(p,idx2))("periodic association not found!\n"); + + association.push_back(std::make_pair(indices[i], idx2)); + } + } + + /** + * get al list of pairs that describes wich DegreeOfFreedom are assiciated in the given mesh + * with given feSpace. Uses the function getBoundaryIndices(). + * The 'meshIndicator' describes one boundary of the mesh and to each DegreeOfFreedom + * the 'periodicMap' associates a second DegreeOfFreedom. + **/ + inline void getPeriodicAssociation(const FiniteElemSpace* feSpace, + AbstractFunction<bool, WorldVector<double> >* meshIndicator, + AbstractFunction<WorldVector<double>, WorldVector<double> >* periodicMap, + std::vector<std::pair<DegreeOfFreedom, DegreeOfFreedom> > &association) + { + std::vector<DegreeOfFreedom> indices; + details::getBoundaryIndices(feSpace, meshIndicator, indices); + + association.clear(); + + DOFVector<WorldVector<double> > coords(feSpace, "coords"); + feSpace->getMesh()->getDofIndexCoords(feSpace, coords); + for (size_t i = 0; i < indices.size(); i++) + { + DegreeOfFreedom idx2; + WorldVector<double> p; + p = (*periodicMap)(coords[indices[i]]); + TEST_EXIT(coords.getDofIdxAtPoint(p,idx2))("periodic association not found!\n"); + + association.push_back(std::make_pair(indices[i], idx2)); + } + } + + inline void getDOFValues(const FiniteElemSpace* feSpace, AbstractFunction<double, WorldVector<double> >* values, std::vector<DegreeOfFreedom> &indices, std::vector<double> &dofValues) + { + WorldVector<double> x; + for (size_t i = 0; i < indices.size(); i++) { + if (feSpace->getMesh()->getDofIndexCoords(indices[i], feSpace, x)) + dofValues.push_back((*values)(x)); + } + } + + inline void getDOFValues(const FiniteElemSpace* feSpace, DOFVector<double>* values, std::vector<DegreeOfFreedom> &indices, std::vector<double> &dofValues) + { + for (size_t i = 0; i < indices.size(); i++) { + dofValues.push_back((*values)[indices[i]]); + } + } +} // end namespace + + + +/** + * data structure that holds all possible variation of description of coords and value + * of (singular/implicit) dirichlet boundary condition. + **/ +struct DirichletBcData { + + // pos = WorldVector + DirichletBcData(int i_, int j_, WorldVector<double> pos_, double val_) + : row(i_), col(j_), pos(pos_), val0(val_), + posType(0), valueType(0), + idx(0), SignedDistFct(NULL), SignedDistDOF(NULL), val1(NULL), val2(NULL), + boundary_nr(0), meshIndicator(NULL) {} + + DirichletBcData(int i_, int j_, WorldVector<double> pos_, DOFVector<double> &val_) + : row(i_), col(j_), pos(pos_), val1(&val_), + posType(0), valueType(1), + idx(0), SignedDistFct(NULL), SignedDistDOF(NULL), val0(0.0), val2(NULL), + boundary_nr(0), meshIndicator(NULL) {} + + DirichletBcData(int i_, int j_, WorldVector<double> pos_, AbstractFunction<double, WorldVector<double> > &val_) + : row(i_), col(j_), pos(pos_), val2(&val_), + posType(0), valueType(2), + idx(0), SignedDistFct(NULL), SignedDistDOF(NULL), val0(0.0), val1(NULL), + boundary_nr(0), meshIndicator(NULL) {} + + // pos = idx + DirichletBcData(int i_, int j_, DegreeOfFreedom idx_, double val_) + : row(i_), col(j_), idx(idx_), val0(val_), + posType(1), valueType(0), + SignedDistFct(NULL), SignedDistDOF(NULL), val1(NULL), val2(NULL), + boundary_nr(0), meshIndicator(NULL) { pos.set(0.0); } + + DirichletBcData(int i_, int j_, DegreeOfFreedom idx_, DOFVector<double> &val_) + : row(i_), col(j_), idx(idx_), val1(&val_), + posType(1), valueType(1), + SignedDistFct(NULL), SignedDistDOF(NULL), val0(0.0), val2(NULL), + boundary_nr(0), meshIndicator(NULL) { pos.set(0.0); } + + DirichletBcData(int i_, int j_, DegreeOfFreedom idx_, AbstractFunction<double, WorldVector<double> > &val_) + : row(i_), col(j_), idx(idx_), val2(&val_), + posType(1), valueType(2), + SignedDistFct(NULL), SignedDistDOF(NULL), val0(0.0), val1(NULL), + boundary_nr(0), meshIndicator(NULL) { pos.set(0.0); } + + // pos = SignedDistFct + DirichletBcData(int i_, int j_, AbstractFunction<double, WorldVector<double> > *SignedDistFct_, double val_) + : row(i_), col(j_), SignedDistFct(SignedDistFct_), val0(val_), + posType(2), valueType(0), + idx(0), SignedDistDOF(NULL), val1(NULL), val2(NULL), + boundary_nr(0), meshIndicator(NULL) { pos.set(0.0); } + + DirichletBcData(int i_, int j_, AbstractFunction<double, WorldVector<double> > *SignedDistFct_, DOFVector<double> &val_) + : row(i_), col(j_), SignedDistFct(SignedDistFct_), val1(&val_), + posType(2), valueType(1), + idx(0), SignedDistDOF(NULL), val0(0.0), val2(NULL), + boundary_nr(0), meshIndicator(NULL) { pos.set(0.0); } + + DirichletBcData(int i_, int j_, AbstractFunction<double, WorldVector<double> > *SignedDistFct_, AbstractFunction<double, WorldVector<double> > &val_) + : row(i_), col(j_), SignedDistFct(SignedDistFct_), val2(&val_), + posType(2), valueType(2), + idx(0), SignedDistDOF(NULL), val0(0.0), val1(NULL), + boundary_nr(0), meshIndicator(NULL) { pos.set(0.0); } + + // pos = SignedDistDOF + DirichletBcData(int i_, int j_, DOFVector<double> *SignedDistDOF_, double val_) + : row(i_), col(j_), SignedDistDOF(SignedDistDOF_), val0(val_), + posType(3), valueType(0), + idx(0), SignedDistFct(NULL), val1(NULL), val2(NULL), + boundary_nr(0), meshIndicator(NULL) { pos.set(0.0); } + + DirichletBcData(int i_, int j_, DOFVector<double> *SignedDistDOF_, DOFVector<double> &val_) + : row(i_), col(j_), SignedDistDOF(SignedDistDOF_), val1(&val_), + posType(3), valueType(1), + idx(0), SignedDistFct(NULL), val0(0.0), val2(NULL), + boundary_nr(0), meshIndicator(NULL) { pos.set(0.0); } + + DirichletBcData(int i_, int j_, DOFVector<double> *SignedDistDOF_, AbstractFunction<double, WorldVector<double> > &val_) + : row(i_), col(j_), SignedDistDOF(SignedDistDOF_), val2(&val_), + posType(3), valueType(2), + idx(0), SignedDistFct(NULL), val0(0.0), val1(NULL), + boundary_nr(0), meshIndicator(NULL) { pos.set(0.0); } + + // pos = meshindicator + boundary_nr + DirichletBcData(int i_, int j_, BoundaryType nr, AbstractFunction<bool, WorldVector<double> > *meshIndicator_, double val_) + : row(i_), col(j_), SignedDistDOF(NULL), val0(val_), + posType(4), valueType(0), + idx(0), SignedDistFct(NULL), val1(NULL), val2(NULL), + boundary_nr(nr), meshIndicator(meshIndicator_) { pos.set(0.0); } + + DirichletBcData(int i_, int j_, BoundaryType nr, AbstractFunction<bool, WorldVector<double> > *meshIndicator_, DOFVector<double> &val_) + : row(i_), col(j_), SignedDistDOF(NULL), val1(&val_), + posType(4), valueType(1), + idx(0), SignedDistFct(NULL), val0(0.0), val2(NULL), + boundary_nr(nr), meshIndicator(meshIndicator_) { pos.set(0.0); } + + DirichletBcData(int i_, int j_, BoundaryType nr, AbstractFunction<bool, WorldVector<double> > *meshIndicator_, AbstractFunction<double, WorldVector<double> > &val_) + : row(i_), col(j_), SignedDistDOF(NULL), val2(&val_), + posType(4), valueType(2), + idx(0), SignedDistFct(NULL), val0(0.0), val1(NULL), + boundary_nr(nr), meshIndicator(meshIndicator_) { pos.set(0.0); } + + // pos = meshindicator + DirichletBcData(int i_, int j_, AbstractFunction<bool, WorldVector<double> > *meshIndicator_, double val_) + : row(i_), col(j_), SignedDistDOF(NULL), val0(val_), + posType(4), valueType(0), + idx(0), SignedDistFct(NULL), val1(NULL), val2(NULL), + boundary_nr(0), meshIndicator(meshIndicator_) { pos.set(0.0); } + + DirichletBcData(int i_, int j_, AbstractFunction<bool, WorldVector<double> > *meshIndicator_, DOFVector<double> &val_) + : row(i_), col(j_), SignedDistDOF(NULL), val1(&val_), + posType(4), valueType(1), + idx(0), SignedDistFct(NULL), val0(0.0), val2(NULL), + boundary_nr(0), meshIndicator(meshIndicator_) { pos.set(0.0); } + + DirichletBcData(int i_, int j_, AbstractFunction<bool, WorldVector<double> > *meshIndicator_, AbstractFunction<double, WorldVector<double> > &val_) + : row(i_), col(j_), SignedDistDOF(NULL), val2(&val_), + posType(4), valueType(2), + idx(0), SignedDistFct(NULL), val0(0.0), val1(NULL), + boundary_nr(0), meshIndicator(meshIndicator_) { pos.set(0.0); } + + void addToList(const FiniteElemSpace *feSpace, std::vector<SingularDirichletBC> &list) + { + std::vector<DegreeOfFreedom> indices_; + std::vector<double> values_; + DegreeOfFreedom idx_ = 0; + + switch (posType) { + case 0: + if (val1 == NULL && SignedDistDOF == NULL) { + val1 = new DOFVector<double>(feSpace, "vel1"); + } + if (val1 != NULL) { + if (!val1->getDofIdxAtPoint(pos, idx_)) + idx_ = 0; + } else if (SignedDistDOF != NULL) { + if (!SignedDistDOF->getDofIdxAtPoint(pos, idx_)) + idx_ = 0; + } + indices_.push_back(idx_); + break; + + case 1: + indices_.push_back(idx); + break; + + case 2: + details::getImplicitIndices(feSpace, SignedDistFct, indices_); + break; + + case 3: + details::getImplicitIndices(feSpace, SignedDistDOF, indices_); + break; + + case 4: + if (boundary_nr == 0) + details:: getBoundaryIndices(feSpace, meshIndicator, indices_); + else + details:: getBoundaryIndices(feSpace, boundary_nr, meshIndicator, indices_); + break; + } + + switch (valueType) { + case 0: + values_.resize(indices_.size(), val0); + break; + + case 1: + details::getDOFValues(feSpace, val1, indices_, values_); + break; + + case 2: + details::getDOFValues(feSpace, val2, indices_, values_); + break; + } + + DOFVector<WorldVector<double> > coords(feSpace, "coords"); + feSpace->getMesh()->getDofIndexCoords(feSpace, coords); + + + for (size_t i = 0; i < indices_.size(); i++) { + list.push_back(SingularDirichletBC(row, col, indices_[i], values_[i])); + } + + MSG_DBG("Dirichle BC at %d DOFs added.\n",indices_.size()); + } + + + int row,col; + +private: + int posType; // 0..WorldVector, 1..DegreeOfFreedom, 2..SignedDistFct, 3..signedDistDOF, 4..meshIndicator + int valueType; // 0..double, 1..DOFVector, 2..AbstractFunction + + // pos + WorldVector<double> pos; + DegreeOfFreedom idx; + AbstractFunction<double, WorldVector<double> > *SignedDistFct; + DOFVector<double> *SignedDistDOF; + + BoundaryType boundary_nr; + AbstractFunction<bool, WorldVector<double> >* meshIndicator; + + // value + double val0; + DOFVector<double> *val1; + AbstractFunction<double, WorldVector<double> > *val2; +}; + + +struct PeriodicBcData { + + // pos = WorldVector + PeriodicBcData(int row_, BoundaryType nr_, AbstractFunction<bool, WorldVector<double> >* meshIndicator_, + AbstractFunction<WorldVector<double>, WorldVector<double> >* periodicMap_) + : row(row_), nr(nr_), meshIndicator(meshIndicator_), periodicMap(periodicMap_) {} + + PeriodicBcData(int row_, AbstractFunction<bool, WorldVector<double> >* meshIndicator_, + AbstractFunction<WorldVector<double>, WorldVector<double> >* periodicMap_) + : row(row_), nr(0), meshIndicator(meshIndicator_), periodicMap(periodicMap_) {} + + void addToList(const FiniteElemSpace *feSpace, std::vector<ManualPeriodicBC> &list) + { + std::vector<std::pair<DegreeOfFreedom, DegreeOfFreedom> > associations; + if (nr == 0) + details::getPeriodicAssociation(feSpace, meshIndicator, periodicMap, associations); + else + details::getPeriodicAssociation(feSpace, nr, meshIndicator, periodicMap, associations); + list.push_back(ManualPeriodicBC(row, associations)); + } + +protected: + + int row; + + BoundaryType nr; + AbstractFunction<bool, WorldVector<double> >* meshIndicator; + AbstractFunction<WorldVector<double>, WorldVector<double> >* periodicMap; +}; + +} // end namespace + +#endif // SINGULAR_DIRICHLET_BC_H diff --git a/extensions/Tools.h b/extensions/Tools.h new file mode 100644 index 0000000000000000000000000000000000000000..16c856ddcc2eb56d198b1806385cfb38ce259c5d --- /dev/null +++ b/extensions/Tools.h @@ -0,0 +1,186 @@ +/** \file Tools.h */ + +#ifndef TOOLS_H +#define TOOLS_H + +#include <boost/array.hpp> +#include <boost/fusion/container/vector.hpp> +#include <boost/fusion/include/at_c.hpp> +#include <boost/fusion/include/boost_array.hpp> + +#include "MetaTools.h" + +namespace tools { + +/// Quadrature Rules +///____________________________________________________________________________________ + + struct SimpsonQuad + { + template<typename Functor, typename T> /// requires Callable1<Functor, T>, Addable<T>, Multiplicable<T> + T quad(Functor& f, T a, T b) + { + return (b - a) * (f(a) * (1.0 / 6.0) + f((a + b) * 0.5) * (4.0 / 6.0) + f(b) * (1.0 / 6.0)); + } + }; + + + template<typename Container> + struct GeneralQuad + { + GeneralQuad(Container& xi_, Container& ci_) : xi(xi_), ci(ci_) {} + + template<typename Functor, typename T> + struct IntegralValue { + IntegralValue(Functor& f_, T a_, T b_) : f(f_), a(a_), b(b_) + { + h = b - a; + } + void operator()(double& x, double& c, T& value) + { + value += f(a + x * h) * c; + } + Functor& f; + T a, b, h; + }; + + template<typename Functor, typename T> /// requires Callable1<Functor, T>, Addable<T>, Multiplicable<T>, Nullifyable<T> + T quad(Functor& f, T a, T b) + { + T I; nullify(I); + + IntegralValue<Functor, T> integralValue(f,a,b); + for_each<boost::fusion::result_of::size<Container>::value - 1>::accumulate(xi, ci, I, integralValue); + + return (b - a) * I; + } + + private: + Container& xi; // intermediate points + Container& ci; // weights + }; + + + template<typename Quad> + struct CompositeQuad + { + CompositeQuad() : q(*(new SimpsonQuad)), n(1) {} + CompositeQuad(Quad& q_, unsigned int n_) : q(q_), n(n_) {} + + template<typename Functor, typename T> /// requires Callable1<Functor, T>, Addable<T>, Multiplicable<T>, Nullifyable<T> + T quad(Functor& f, T a, T b) + { + T h = (b - a) * (1.0 / (n - 1.0)); + T I; nullify(I); + for (unsigned int i = 1; i < n; i++) + I += q.quad(f, a + (i - 1.0) * h, a + i * h); + return h * I; + } + + template<typename Functor, typename Vector, typename T> /// requires Callable1<Functor, T>, Addable<T>, Multiplicable<T>, Nullifyable<T> + T quad(Functor& f, Vector& x) + { + typename Vector::iterator xIter; + T I; nullify(I); + for (xIter = x.begin(); xIter+1 != x.end(); xIter++) + I += (*(xIter+1) - *xIter) * q.quad(f, *xIter, *(xIter+1)); + return I; + } + + private: + Quad& q; // quadrature rule + unsigned int n; // number of points + }; + + + struct SequenceQuad + { + // integration zwischen zwei Punkten mittels Trapezregel + template<typename Vector1, typename Vector2, typename T> /// requires Callable1<Functor, T>, Addable<T>, Multiplicable<T>, Nullifyable<T> + T quad(Vector1& y, Vector2& x) + { + T I; nullify(I); + for (size_t i = 0; i < x.size()-1; i++) + I += (x[i+1] - x[i]) * 0.5*(y[i] + y[i+1]); + return I; + } + }; + + +/// Regression, Interpolation and Approximation +///____________________________________________________________________________________ + + + struct Regression + { + Regression(int DOW_) : DOW(DOW_) + { + coefficients = std::vector<double>(DOW+1, 0.0); + } + + template<typename Vector1, typename Vector2> + void apply(Vector1& points, Vector2& values) { + int row = points.size(); + int col = DOW + 1; + mtl::dense2D<double> A(row, col); + mtl::dense_vector<double> b(row); + for (size_t i = 0; i < row; i++) { + for (size_t j = 0; j < col-1; j++) + A(i,j) = points[i][j]; + A(i,DOW) = 1.0; + b[i] = values[i]; + } + mtl::dense2D<double> Q(row, row), Qt(row, row), R(row, col); + boost::tie(Q, R) = mtl::matrix::qr_factors(A); + + mtl::dense_vector<double> bQ(col), x(col); + using mtl::iall; + using mtl::irange; + irange cols(0, col); + bQ = trans(Q[iall][cols])*b; + x = mtl::matrix::upper_trisolve(R[cols][cols], bQ[cols]); + for (int i = 0; i < DOW+1; i++) + coefficients[i] = x[i]; + } + + template<typename Vector1, typename Vector2, typename Vector3> + void apply(Vector1& points, Vector2& values, Vector3& weights) { + int row = points.size(); + int col = DOW + 1; + mtl::dense2D<double> A(row, col); + mtl::dense_vector<double> b(row); + for (size_t i = 0; i < row; i++) { + for (size_t j = 0; j < col-1; j++) + A(i,j) = weights[i] * points[i][j]; + A(i,DOW) = weights[i]; + b[i] = weights[i] * values[i]; + } + mtl::dense2D<double> Q(row, row), Qt(row, row), R(row, col); + boost::tie(Q, R) = mtl::matrix::qr_factors(A); + + mtl::dense_vector<double> bQ(col), x(col); + using mtl::iall; + using mtl::irange; + irange cols(0, col); + bQ = trans(Q[iall][cols])*b; + x = mtl::matrix::upper_trisolve(R[cols][cols], bQ[cols]); + for (int i = 0; i < DOW+1; i++) + coefficients[i] = x[i]; + } + + template<typename Coords> + double value(Coords& x) { + double f = coefficients[DOW]; + for (int i = 0; i < DOW; i++) + f += coefficients[i]*x[i]; + return f; + } + + private: + int DOW; + std::vector<double> coefficients; // c[0]*x[0] + c[1]*x[1] + c[2] + }; + +} // end namespace + +#endif // TOOLS_H diff --git a/extensions/VectorOperations.h b/extensions/VectorOperations.h new file mode 100644 index 0000000000000000000000000000000000000000..de8572e6c8d286e9bc5ea2e7ab42395789e5b776 --- /dev/null +++ b/extensions/VectorOperations.h @@ -0,0 +1,533 @@ +/** \file VectorOperations.h */ + +#ifndef VECTOR_OPERATIONS_H +#define VECTOR_OPERATIONS_H + +#include "AMDiS.h" + +#if HAVE_PARALLEL_DOMAIN_AMDIS +#include "parallel/StdMpi.h" +#endif + +#include <unistd.h> +#include <ios> +#include <iostream> +#include <fstream> +#include <string> +#include <boost/numeric/mtl/mtl.hpp> +#include <boost/numeric/itl/itl.hpp> + +using namespace AMDiS; + +template<typename T> +const WorldVector<T>& operator*=(WorldVector<T>& v1, const WorldVector<T>& v2) +{ + T* v1It, *v2It; + for (v1It = v1.begin(), v2It = v2.begin(); + v1It != v1.end(); + v1It++, v2It++) + *v1It *= *v2It; + + return v1; +}; + +// x ~= y +template<typename T> +class compareTol : public binary_function<T, T, bool> { +public: + compareTol(double tol_) : tol(tol_) {} + bool operator()(const T &x, const T &y) const { return sqrt((x-y)*(x-y))<tol; } + double tol; +}; +template<typename T1, typename T2, int component> +struct comparePair : public binary_function<std::pair<T1, T2>, std::pair<T1, T2>, bool> +{ + bool operator()(const std::pair<T1, T2> &x, const std::pair<T1, T2> &y) const + { + return (component==0?(x.first<y.first):(x.second<y.second)); + } +}; + +template<typename T1, typename T2> +struct compare0 : public binary_function<std::pair<T1, T2>, std::pair<T1, T2>, bool> +{ + bool operator()(const std::pair<T1, T2> &x, const std::pair<T1, T2> &y) const + { + return x.first<y.first; + } +}; +template<typename T1, typename T2> +struct compare1 : public binary_function<std::pair<T1, T2>, std::pair<T1, T2>, bool> +{ + bool operator()(const std::pair<T1, T2> &x, const std::pair<T1, T2> &y) const + { + return x.second<y.second; + } +}; + +class SortPair : public binary_function<std::pair<WorldVector<double>, double>, std::pair<WorldVector<double>, double>, bool> { +public: + SortPair(int component_=1,int idx_=0) : component(component_),idx(idx_) {} + bool operator()(const std::pair<WorldVector<double>, double> &x, + const std::pair<WorldVector<double>, double> &y) const { + return (component==1?(x.first)[idx]<(y.first)[idx]:x.second<y.second); } + int component,idx; +}; + +namespace vector_operations { + + // num_rows for vector types + template<typename T> + size_t num_rows(WorldVector<T> &v) { + return static_cast<size_t>(v.getSize()); + }; + template<typename T> + size_t num_rows(const WorldVector<T> &v) { + return static_cast<size_t>(v.getSize()); + }; + template<typename T> + size_t num_rows(std::vector<T> &v) { + return static_cast<size_t>(v.size()); + }; + template<typename T> + size_t num_rows(const std::vector<T> &v) { + return static_cast<size_t>(v.size()); + }; + + // num_rows/num_cols for matrix types + template<typename T> + size_t num_rows(WorldMatrix<T> &m) { + return static_cast<size_t>(m.getNumRows()); + }; + template<typename T> + size_t num_rows(const WorldMatrix<T> &m) { + return static_cast<size_t>(m.getNumRows()); + }; + template<typename T> + size_t num_cols(WorldMatrix<T> &m) { + return static_cast<size_t>(m.getNumCols()); + }; + template<typename T> + size_t num_cols(const WorldMatrix<T> &m) { + return static_cast<size_t>(m.getNumCols()); + }; + + // common interface to resize vectors + template<typename T> + void resize(WorldVector<T> &v, size_t dim) { + TEST_EXIT(dim==v.getSize())("WorldVectors can not be resized to the given dimension!\n"); + }; + template<typename T> + void resize(std::vector<T> &v, size_t dim) { + v.resize(dim); + }; + template<typename T> + void resize(mtl::dense_vector<T> &v, size_t dim) { + v.change_dim(dim); + }; + + + + // B(phi)=phi^2*(1-phi)^2 + template<typename T> + T norm(mtl::dense_vector<T> &b) { return two_norm(b); }; + + template<typename T> + T norm(std::vector<T> &b) + { + T value = 0.0; + for (size_t i = 0; i < b.size(); ++i) + value += sqr(b[i]); + return sqrt(value); + }; + + template<typename Matrix> + double matrix_norm(Matrix &M) + { + typename Matrix::value_type asum; + asum = 0.0; + for (size_t i = 0; i < num_rows(M); ++i) { + for (size_t j = 0; j < num_cols(M); ++j) + asum += abs(M[i][j]); + } + return static_cast<double>(asum/(num_rows(M)*num_cols(M))); + }; + + // |x|_eps + inline double epsNorm(const WorldVector<double> &x, const double &eps) { return std::max(AMDiS::norm(x),eps); }; + + // 1/|x|_eps + inline double epsNormInv(const WorldVector<double> &x, const double &eps) { return 1.0/epsNorm(x,eps); }; + + // 1/[|x|_eps]^3 + inline double epsNormInv3(const WorldVector<double> &x, const double &eps) + { + double result = epsNorm(x,eps); + result = 1.0/(result*sqr(result)); + return result; + }; + + // y:=x/|x|_eps + inline void epsNormalize(const WorldVector<double> &x, const double &eps, WorldVector<double> &y) + { + double nrmInv = epsNormInv(x,eps); + for(int k=0; k<x.getSize(); k++) { + y[k] = x[k] * nrmInv; + } + }; + + template<typename Matrix> + double trace(Matrix &M) + { + TEST_EXIT(num_rows(M)==num_cols(M))("Matrix dimensions must be equal!\n"); + typename Matrix::value_type sum; + sum = 0.0; + for (size_t i = 0; i < num_rows(M); ++i) { + sum += M[i][i]; + } + return static_cast<double>(sum); + }; + + template<typename T> + Vector<T> mult(const Vector<T>& v1, const Vector<T>& v2) + { + TEST_EXIT(v1.getSize()==v2.getSize())("Vectors must have the same size!\n"); + Vector<T> result(v1.getSize()); + Vector<T> *v1It, *v2It, *resultIt; + for (v1It = v1.begin(), v2It = v2.begin(), resultIt = result.begin(); v1It != v1.end(); ++v1It, ++v2It, ++resultIt) + *resultIt = *v1It * *v2It; + return result; + }; + + inline WorldVector<double> mult(const mtl::dense2D<double> &A, const WorldVector<double> &x) + { + TEST_EXIT(num_rows(A)==x.getSize())("Falsche Dimensionen multipliziert!"); + WorldVector<double> result; + for (unsigned i = 0; i < x.getSize(); ++i) { + result[i] = 0.0; + for (unsigned j = 0; j < x.getSize(); ++j) + result[i] += A[i][j]*x[j]; + } + return result; + }; + + template<typename ResultVector, typename Matrix, typename Vector1, typename Vector2> + ResultVector Axpy(const Matrix &A, const Vector1 &x, const Vector2 &y) + { + size_t n = num_rows(x); + TEST_EXIT(num_rows(A)==n && num_cols(A)==n && num_rows(y)==n)("Falsche Dimensionen multipliziert!"); + ResultVector result; + resize(result, n); + for (unsigned i = 0; i < n; ++i) { + result[i] = y[i]; + for (unsigned j = 0; j < n; ++j) + result[i] += A[i][j]*x[j]; + } + return result; + }; + + inline void unitVector(WorldVector<double> &b, int &idx) { + TEST_EXIT(idx>=0 && idx<b.getSize())("Unit-Vector component does not exist!\n"); + b.set(0.0); + b[idx]=1.0; + }; + + inline WorldVector<double> *unitVector(int &idx) { + WorldVector<double> *result = new WorldVector<double>; + TEST_EXIT(idx>=0 && idx<result->size())("Unit-Vector component does not exist!\n"); + (*result)[idx]=1.0; + return result; + }; + + template<typename T> + void copy(std::vector<T> &v, WorldVector<T> &w) + { + for(int i=0; i<std::min((int)v.size(),(int)w.getSize()); i++) + w[i]=v[i]; + }; + + template<typename T> + void copy(mtl::dense_vector<T> &v, WorldVector<T> &w) + { + for(int i=0; i<std::min((int)num_rows(v),(int)w.getSize()); i++) + w[i]=v[i]; + }; + + template<typename T> + void copy(WorldVector<T> &w, mtl::dense_vector<T> &v) + { + for(int i=0; i<std::min((int)num_rows(v),(int)w.getSize()); i++) + v[i]=w[i]; + }; + + template<typename T> + void merge(std::vector<T> &v1, std::vector<T> &v2, std::vector<T> &v3) + { + v3.resize(v1.size()+v2.size()); + for(int i=0;i<v1.size();i++) + v3[i]=v1[i]; + for(int j=0;j<v2.size();j++) + v3[j+v1.size()]=v2[j]; + }; + + template<typename T> + void getMin(mtl::dense_vector<T> &v, T &minVal, unsigned &minIdx) + { + if(num_rows(v)==0) { + minVal = numeric_limits<T>::infinity(); + } else { + minVal=v[0]; minIdx=0; + for(unsigned i=1; i<num_rows(v); i++) { + if(v[i]<minVal) { minVal=v[i]; minIdx=i; } + } + } + }; + + template<typename T> + void getMin(std::vector<T> &v, T &minVal, size_t &minIdx) + { + if (v.size() == 0) { + minVal = numeric_limits<T>::infinity(); + } else { + minVal = v[0]; + minIdx = 0; + for(size_t i = 1; i < v.size(); i++) { + if (v[i] < minVal) { + minVal=v[i]; + minIdx=i; + } + } + } + }; + + template<typename T> + void getMax(mtl::dense_vector<T> &v, T &maxVal, unsigned &maxIdx) + { + if(num_rows(v)==0) { + maxVal = -numeric_limits<T>::infinity(); + } else { + maxVal=v[0]; maxIdx=0; + for(unsigned i=1; i<num_rows(v); i++) { + if(v[i]>maxVal) { maxVal=v[i]; maxIdx=i; } + } + } + }; + + template<typename T> + T max(const std::vector<T> &vec) + { + double maxVal; + if(vec.size()==0) { + maxVal = -numeric_limits<T>::infinity(); + } else { + maxVal=vec[0]; + for(size_t i=1; i<vec.size(); i++) { + if(vec[i]>maxVal) { maxVal=vec[i]; } + } + } + return maxVal; + }; + + template<typename T> + T min(const std::vector<T> &vec) + { + double minVal; + if(vec.size()==0) { + minVal = numeric_limits<T>::infinity(); + } else { + minVal=vec[0]; + for(size_t i=1; i<vec.size(); i++) { + if(vec[i]<minVal) { minVal=vec[i]; } + } + } + return minVal; + }; + + template<typename T> + T absmax(std::vector<T> &vec) + { + double maxVal; + if(vec.size()==0) { + maxVal = -numeric_limits<T>::infinity(); + } else { + maxVal=abs(vec[0]); + for(size_t i=1; i<vec.size(); i++) { + if(abs(vec[i])>maxVal) { maxVal=abs(vec[i]); } + } + } + return maxVal; + }; + + template<typename T> + T sum(std::vector<T> &vec) + { + unsigned N=vec.size(); + T value = 0; + if(N>0) { + value = vec[0]; + for(unsigned i=1; i<N; ++i) { + value += vec[i]; + } + } + return value; + }; + + template<typename T> + void getMean(std::vector<T> &vec, T &meanValue) + { + unsigned N=vec.size(); + meanValue = sum(vec)/double(N); + }; + +// template<typename Vector1, typename Vector2> +// struct VectorPair { +// typedef typename Vector1::size_type size_type; +// typedef typename Vector1::value_type T1; +// typedef typename Vector2::value_type T2; +// typedef typename Vector1::iterator iterator1; +// typedef typename Vector2::iterator iterator2; +// typedef typename std::pair<T1, T2>& reference; +// typedef typename const std::pair<T1, T2>& const_reference; +// +// typedef struct PairIterator : public iterator<random_access_iterator_tag> { +// PairIterator(iterator1& iter1_, iterator2& iter2_) : iter1(iter1_), iter2(iter2_) {} +// PairIterator(const PairIterator& piter) : iter1(piter.iter1), iter2(piter.iter2) {} +// PairIterator& operator++() {++iter1; ++iter2; return *this;} +// PairIterator& operator--() {--iter1; --iter2; return *this;} +// PairIterator& operator+(int n) {PairIterator tmp(*this); tmp.iter1+=n; tmp.iter2+=n; return tmp;} +// PairIterator& operator-(int n) {PairIterator tmp(*this); tmp.iter1-=n; tmp.iter2-=n; return tmp;} +// PairIterator& operator+=(int n) {iter1+=n; iter2+=n; return *this;} +// PairIterator& operator-=(int n) {iter1-=n; iter2-=n; return *this;} +// // PairIterator operator++(int) {PairIterator tmp(*this); operator++(); return tmp;} //?1 +// bool operator==(const PairIterator& rhs) {return iter1 == rhs.iter1 && iter2 == rhs.iter2;} +// bool operator<(const PairIterator& rhs) {return iter1 < rhs.iter1 && iter2 < rhs.iter2;} +// bool operator>(const PairIterator& rhs) {return iter1 > rhs.iter1 && iter2 > rhs.iter2;} +// bool operator<=(const PairIterator& rhs) {return iter1 <= rhs.iter1 && iter2 <= rhs.iter2;} +// bool operator>=(const PairIterator& rhs) {return iter1 >= rhs.iter1 && iter2 >= rhs.iter2;} +// bool operator!=(const PairIterator& rhs) {return iter1 != rhs.iter1 || iter2 != rhs.iter2;} +// std::pair<T1&, T2&>& operator*() {return std::make_pair(*iter1, *iter2);} +// std::pair<T1&, T2&>& operator[](int n) {return std::make_pair(*(iter1+n), *(iter2+n));} +// +// protected: +// iterator1 iter1; +// iterator2 iter2; +// } iterator; +// }; + + template<typename T1, typename T2, typename Compare> + void sort(std::vector<T1> &vec1, std::vector<T2> &vec2, Compare &comp) + { + std::vector<pair<T1,T2> > order(vec1.size()); + + // create vector of pairs + for (int i=0; i<vec1.size(); ++i) + order[i] = make_pair(vec1[i], vec2[i]); + + // sort vector of pairs + sort(order.begin(), order.end(), comp); + + // copy sorted pairs back to vectors + for (int i=0; i<vec1.size(); ++i) { + vec1[i] = order[i].first; + vec2[i] = order[i].second; + } + }; + + template<typename T1, typename T2, typename Compare> + void sort(std::vector<std::pair<T1,T2> > &vec, Compare &comp) + { + std::sort(vec.begin(), vec.end(), comp); + }; + + inline void unique(std::vector<WorldVector<double> > &vec, double tol, std::vector<unsigned> &ind) + { + compareTol<WorldVector<double> > comp(tol); + unsigned newVec=0; + for(unsigned i=0; i<vec.size();++i) { + bool inNew=false; + for(unsigned j=0;j<newVec;++j) { + inNew=inNew||comp(vec[i],vec[j]); + if(inNew) break; + } + if(!inNew) {vec[newVec]=vec[i]; newVec++; ind.push_back(i);} + } + vec.erase(vec.begin()+newVec,vec.end()); + }; + + template<typename T1, typename T2> + void unique(std::vector<std::pair<T1,T2> > &vec, double tol, int uniqueBy=1) + { +// comparePair comp = comparePair(tol,uniqueBy); +// unsigned newVec=0; +// for(unsigned i=0; i<vec.size();++i) { +// bool inNew=false; +// for(unsigned j=0;j<newVec;++j) { +// inNew=inNew||comp(vec[i],vec[j]); +// if(inNew) break; +// } +// if(!inNew) {vec[newVec]=vec[i]; newVec++;} +// } +// vec.erase(vec.begin()+newVec,vec.end()); + }; + + inline void filter(std::vector<WorldVector<double> > &x, std::vector<bool> &filter) + { + unsigned j=0; + for(unsigned i=0; i<x.size(); ++i) { + if(filter[i]) { + x[j]=x[i]; + j++; + } + } + x.erase(x.begin()+j,x.end()); + }; + + inline void filter(std::vector<WorldVector<double> > &x, std::vector<int> &filter) + { + unsigned j=0; + for(unsigned i=0; i<filter.size(); ++i) { + x[j]=x[filter[i]]; + j++; + } + x.erase(x.begin()+j,x.end()); + }; + template<typename T, typename T1, typename T2> + T dot(std::vector<T1> &vec1, std::vector<T2> &vec2) + { + unsigned N=vec1.size(); + T value = 0; + if(N>0) { + value = static_cast<T>(vec1[0])*static_cast<T>(vec2[0]); + for(unsigned i=1; i<N; ++i) { + value += static_cast<T>(vec1[i])*static_cast<T>(vec2[i]); + } + } + return value; + }; + template<typename T, typename T1, typename T2> + T dot(mtl::dense_vector<T1> &vec1, WorldVector<T2> &vec2) + { + unsigned N=vec2.getSize(); + T value = 0; + if(N>0) { + value = static_cast<T>(vec1[0])*static_cast<T>(vec2[0]); + for(unsigned i=1; i<N; ++i) { + value += static_cast<T>(vec1[i])*static_cast<T>(vec2[i]); + } + } + return value; + }; + + template<class T> + static void fillMatrix(WorldMatrix<T> &m, mtl::dense2D<T> &m_in) + { + m.resize(num_rows(m_in),num_cols(m_in)); + for (size_t i = 0; i < num_rows(m_in); ++i) { + for (size_t j = 0; j < num_cols(m_in); ++j) { + m[i][j] = m_in(i,j); + } + } + }; +} + +#endif // VECTOR_OPERATIONS_H diff --git a/extensions/Views.h b/extensions/Views.h new file mode 100644 index 0000000000000000000000000000000000000000..0c2f7ba76262a96f3629df9df7c024e6284a1e6f --- /dev/null +++ b/extensions/Views.h @@ -0,0 +1,558 @@ +/** \file Views.h */ + +#ifndef MY_VIEWS_H +#define MY_VIEWS_H + +#include <stdexcept> +#include <boost/type_traits/is_base_of.hpp> +#include <boost/utility/enable_if.hpp> + +#include "AMDiS.h" +#ifdef USE_BACKGROUNDMESH + #include "BackgroundMesh.h" +#endif +#ifdef USE_KD_TREE + #include "kdtree_nanoflann_dof.h" +#endif + +using namespace AMDiS; + +/// Abstract-Function-Views +/// ________________________________________________________________________________________________ + +/// result = 0.5*(f(x)+1) +template<typename T> +struct PhaseView : AbstractFunction<T, WorldVector<double> > { + PhaseView(AbstractFunction<T, WorldVector<double> > &fct_) : fct(fct_) {} + PhaseView(AbstractFunction<T, WorldVector<double> > *fct_) : fct(*fct_) {} + T operator()(const WorldVector<double>& x) const { + return std::max(0.0, std::min(1.0, 0.5*(fct(x)+1.0))); + } +private: + AbstractFunction<T, WorldVector<double> > fct; +}; + +/// result = 2*f(x)-1 +template<typename T> +struct ChView : AbstractFunction<T, WorldVector<double> > { + ChView(AbstractFunction<T, WorldVector<double> > &fct_) : fct(fct_) {} + ChView(AbstractFunction<T, WorldVector<double> > *fct_) : fct(*fct_) {} + T operator()(const WorldVector<double>& x) const { + return std::max(-1.0, std::min(1.0, 2.0*fct(x)-1.0)); + } +private: + AbstractFunction<T, WorldVector<double> > fct; +}; + +template<typename T> +struct MultView : AbstractFunction<T, WorldVector<double> > { + MultView(AbstractFunction<T, WorldVector<double> > &fct_, double factor_) : fct(fct_), factor(factor_) {} + MultView(AbstractFunction<T, WorldVector<double> > *fct_, double factor_) : fct(*fct_), factor(factor_) {} + T operator()(const WorldVector<double>& x) const { + return factor*fct(x); + } +private: + AbstractFunction<T, WorldVector<double> > fct; + double factor; +}; + +/// DOFVector-Views +/// ________________________________________________________________________________________________ + +template<typename T> +struct DOFView : public DOFVector<T> { + typedef T result_type; + + DOFView(DOFVector<T> *vec_) + : DOFVector<T>(vec_->getFeSpace(), "dof_view"), + vector(vec_) + { + nullify(value0); + } + + DOFView(DOFVector<T> &vec_) + : DOFVector<T>(vec_.getFeSpace(), "dof_view"), + vector(&vec_) + { + nullify(value0); + } + + /// Returns \ref vec[i] + inline const T& operator[](WorldVector<double> &x) const + { + FUNCNAME("DOFVector<T>::operator[x]"); + DegreeOfFreedom idx = -1; + WorldVector<double> x_ = coordsView(x); + bool inside = vector->getDofIdxAtPoint(x_, idx); + + return (inside ? operator[](idx) : value0); + } + + /// Returns \ref vec[i] + inline T& operator[](WorldVector<double> &x) + { + FUNCNAME("DOFVector<T>::operator[x]"); + DegreeOfFreedom idx = -1; + WorldVector<double> x_ = coordsView(x); + bool inside = vector->getDofIdxAtPoint(x_, idx); + + return (inside ? operator[](idx) : value0); + } + + inline T& operator[](DegreeOfFreedom idx) + { + DOFVector<T>::operator[](idx)= valueView(idx); + return DOFVector<T>::operator[](idx); + } + + inline const T& operator[](DegreeOfFreedom idx) const + { + const T& swap(valueView(idx)); + T& swap2 = const_cast<T&>(DOFVector<T>::operator[](idx)); + swap2 = swap; + return swap2; + } + + inline const T evalAtPoint(WorldVector<double> &p, + ElInfo *oldElInfo = NULL, + T* valueReturn = NULL + ) const + { + FUNCNAME("DOFVector<T>::operator[x]"); + + WorldVector<double> x_ = coordsView(p); + const FiniteElemSpace* feSpace = vector->getFeSpace(); + + if (oldElInfo && feSpace->getMesh() == oldElInfo->getMesh()) { + Mesh* mesh = feSpace->getMesh(); + DimVec<double> lambda(mesh->getDim(), NO_INIT); + int k = oldElInfo->worldToCoord(x_, &lambda); + if (k < 0) { + std::vector<DegreeOfFreedom> localIndices; // DOF-indices of all DOFs in trinangle + mtl::dense_vector<double> uh; // evaluation of DOFVectors at QPs + + localIndices.resize(feSpace->getBasisFcts()->getNumber()); + uh.change_dim(mesh->getDim()+1); + + feSpace->getBasisFcts()->getLocalIndices(oldElInfo->getElement(), feSpace->getAdmin(), localIndices); + for (int l = 0; l < feSpace->getBasisFcts()->getNumber(); l++) + uh[l] = (*vector)[localIndices[l]]; + T value = feSpace->getBasisFcts()->evalUh(lambda, uh); + return value; + } + } + +#ifdef USE_BACKGROUNDMESH + using namespace experimental; + bool use_backgroundmesh = false; + Parameters::get("backgroundMesh->enabled",use_backgroundmesh); + if (use_backgroundmesh) { + Box* box = Box::provideBackgroundMesh(feSpace); + int evaluation_accuracy = 0; + Parameters::get("backgroundMesh->evaluation accuracy",evaluation_accuracy); + T value = box->evalAtPoint(*vector, x_, evaluation_accuracy); + return value; + } +#endif +#ifdef USE_KD_TREE + using namespace experimental; + bool use_kdtree = false; + Parameters::get("KD-Tree->enabled",use_kdtree); + if (use_kdtree) { + KD_Tree* tree = provideKDTree(feSpace); + T value = tree->evalAtPoint(*vector, x_); + return value; + } +#endif + DegreeOfFreedom idx = -1; + T value = value0; + Mesh* mesh = feSpace->getMesh(); + + ElInfo *elInfo = mesh->createNewElInfo(); + DimVec<double> lambda(mesh->getDim(), NO_INIT); + + bool inside = mesh->findElInfoAtPoint(x_, elInfo, lambda, (oldElInfo ? oldElInfo->getMacroElement() : NULL), NULL, NULL); + + if (inside) { + std::vector<DegreeOfFreedom> localIndices; + mtl::dense_vector<T> uh; + + localIndices.resize(feSpace->getBasisFcts()->getNumber()); + uh.change_dim(feSpace->getBasisFcts()->getNumber()); + + feSpace->getBasisFcts()->getLocalIndices(elInfo->getElement(), feSpace->getAdmin(), localIndices); + for (int l = 0; l < feSpace->getBasisFcts()->getNumber(); l++) + uh[l] = valueView(localIndices[l]); + value = feSpace->getBasisFcts()->evalUh(lambda, uh); + } + if (valueReturn) + *valueReturn = value; + delete elInfo; + + return value; + } + +protected: + + virtual inline T valueView(DegreeOfFreedom idx) const + { + return (*vector)[idx]; + } + + virtual inline WorldVector<double> coordsView(WorldVector<double> &x) const + { + return x; + } + + void setDefaultValue(T& value0_) + { + value0 = value0_; + }; + + DOFVector<T> *vector; + T value0; +}; + +/// DOFVector-Views ... Value-Views +/// ________________________________________________________________________________________________ + +template<typename T> +struct PhaseDOFView : public DOFView<T> { + typedef T result_type; + + PhaseDOFView(DOFVector<T> &vec_) : DOFView<T>(&vec_) {} + PhaseDOFView(DOFVector<T> *vec_) : DOFView<T>(vec_) {} + +protected: + + inline T valueView(DegreeOfFreedom idx) const + { + return std::max(0.0, std::min(1.0, 0.5*((*DOFView<T>::vector)[idx]+1.0))); + } +}; + + +template<typename T> +struct InvPhaseView : public DOFView<T> { + typedef T result_type; + + InvPhaseView(DOFVector<T> &vec_) : DOFView<T>(&vec_) {} + InvPhaseView(DOFVector<T> *vec_) : DOFView<T>(vec_) {} + +protected: + + inline T valueView(DegreeOfFreedom idx) const + { + return -(*DOFView<T>::vector)[idx]; + } +}; + +/// DOFVector-Views ... Coord-Views +/// ________________________________________________________________________________________________ + +/// vec[x] := vec.evalAtPoint(R^(-1) * x) +template<typename T> +struct RotateView : public DOFView<T> { + typedef T result_type; + + RotateView(DOFVector<T> &vec_, WorldMatrix<double> R_) : DOFView<T>(&vec_), R(R_) {} + RotateView(DOFVector<T> *vec_, WorldMatrix<double> R_) : DOFView<T>(vec_), R(R_) {} + + RotateView(DOFVector<T> &vec_, double alpha) : DOFView<T>(&vec_) { + R.setDiag(1.0); + R[0][0] = cos(alpha); R[0][1] = -sin(alpha); + R[1][0] = sin(alpha); R[1][1] = cos(alpha); + } + RotateView(DOFVector<T> *vec_, double alpha) : DOFView<T>(vec_) { + R.setDiag(1.0); + R[0][0] = cos(alpha); R[0][1] = -sin(alpha); + R[1][0] = sin(alpha); R[1][1] = cos(alpha); + } + +protected: + + inline WorldVector<double> coordsView(WorldVector<double> &x) const + { + WorldVector<double> x_; + WorldMatrix<double> R_ = R; + for (int i = 0; i < R_.getNumRows(); i++) + for (int j = 0; j < i; j++) + std::swap(R_[i][j], R_[j][i]); + x_.multMatrixVec(R_, x); + return x_; + } + +private: + + WorldMatrix<double> R; +}; + + +/// vec[x] := vec.evalAtPoint(x ./ scale) +template<typename T> +struct ScaleView : public DOFView<T> { + typedef T result_type; + + ScaleView(DOFVector<T> &vec_, WorldVector<double> scale_) : DOFView<T>(&vec_), scale(scale_) {} + ScaleView(DOFVector<T> *vec_, WorldVector<double> scale_) : DOFView<T>(vec_), scale(scale_) {} + + ScaleView(DOFVector<T> &vec_, double scale_) : DOFView<T>(&vec_) { scale.set(scale_); } + ScaleView(DOFVector<T> *vec_, double scale_) : DOFView<T>(vec_) { scale.set(scale_); } + +protected: + + inline WorldVector<double> coordsView(WorldVector<double> &x) const + { + WorldVector<double> x_; + for (int i = 0; i < x_.getSize(); i++) + x_[i] = x[i]/scale[i]; + return x_; + } + +private: + + WorldVector<double> scale; +}; + +/// vec[x] := vec.evalAtPoint(x - shift) +template<typename T> +struct ShiftView : public DOFView<T> { + typedef T result_type; + + ShiftView(DOFVector<T> &vec_, WorldVector<double> shift_) : DOFView<T>(&vec_), shift(shift_) {} + ShiftView(DOFVector<T> *vec_, WorldVector<double> shift_) : DOFView<T>(vec_), shift(shift_) {} + + void setShift(WorldVector<double> &shift_) { shift = shift_; } + +protected: + + inline WorldVector<double> coordsView(WorldVector<double> &x) const + { + WorldVector<double> x_; + for (int i = 0; i < x_.getSize(); i++) + x_[i] = x[i]-shift[i]; + return x_; + } + +private: + + WorldVector<double> shift; +}; + +/// evalAtPoint for several Data-Structures +/// ________________________________________________________________________________________________ + +// DOFVector can be accessed by locating the elInfo and than using barycentric coordinates +// The default value, if p outside of geometry, is 0.0 +template<typename T> +inline T evalAtPoint(const DOFVector<T> &obj, WorldVector<double> &p, ElInfo* oldElInfo = NULL) +{ + const FiniteElemSpace* feSpace = obj.getFeSpace(); + Mesh* mesh = feSpace->getMesh(); + + if (oldElInfo && feSpace->getMesh() == oldElInfo->getMesh()) { + DimVec<double> lambda(mesh->getDim(), NO_INIT); + oldElInfo->worldToCoord(p, &lambda); + + std::vector<DegreeOfFreedom> localIndices; // DOF-indices of all DOFs in trinangle + mtl::dense_vector<T> uh; // evaluation of DOFVectors at QPs + + localIndices.resize(feSpace->getBasisFcts()->getNumber()); + uh.change_dim(mesh->getDim()+1); + + feSpace->getBasisFcts()->getLocalIndices(oldElInfo->getElement(), feSpace->getAdmin(), localIndices); + for (int l = 0; l < feSpace->getBasisFcts()->getNumber(); l++) + uh[l] = obj[localIndices[l]]; + T value = feSpace->getBasisFcts()->evalUh(lambda, uh); + return value; + } + +#ifdef USE_BACKGROUNDMESH + using namespace experimental; + bool use_backgroundmesh = false; + Parameters::get("backgroundMesh->enabled",use_backgroundmesh); + if (use_backgroundmesh) { + Box* box = Box::provideBackgroundMesh(feSpace); + int evaluation_accuracy = 0; + Parameters::get("backgroundMesh->evaluation accuracy",evaluation_accuracy); + T value = box->evalAtPoint(obj, p, evaluation_accuracy); + return value; + } +#endif +#ifdef USE_KD_TREE + using namespace experimental; + bool use_kdtree = false; + Parameters::get("KD-Tree->enabled",use_kdtree); + if (use_kdtree) { + KD_Tree* tree = provideKDTree(feSpace); + T value = tree->evalAtPoint(obj, p); + return value; + } +#endif + T value; nullify(value); + + ElInfo *elInfo = mesh->createNewElInfo(); + DimVec<double> lambda(mesh->getDim(), NO_INIT); + + std::vector<DegreeOfFreedom> localIndices; // DOF-indices of all DOFs in trinangle + mtl::dense_vector<T> uh; + + localIndices.resize(feSpace->getBasisFcts()->getNumber()); + uh.change_dim(feSpace->getBasisFcts()->getNumber()); + + bool inside = mesh->findElInfoAtPoint(p, elInfo, lambda, NULL, NULL, NULL); + + if (inside) { + feSpace->getBasisFcts()->getLocalIndices(elInfo->getElement(), obj.getFeSpace()->getAdmin(), localIndices); + for (int l = 0; l < feSpace->getBasisFcts()->getNumber(); l++) + uh[l] = obj[localIndices[l]]; + value = feSpace->getBasisFcts()->evalUh(lambda, uh); + } + delete elInfo; + return value; +}; + +// DOFView can be accessed by own method +template<typename T > +inline T evalAtPoint(const DOFView<T> &obj, WorldVector<double> &p, ElInfo* elInfo = NULL) +{ + return obj.evalAtPoint(p, elInfo); +}; + +// intrinsic types can return values directly +template<typename T> +inline T evalAtPoint(T &obj, WorldVector<double> &p, ElInfo* elInfo = NULL) +{ + return obj; +}; + +// AbstractFunctions with argument-type = WorldVector can be accessed directly +template<typename T> +inline T evalAtPoint(AbstractFunction<T, WorldVector<double> > &obj, WorldVector<double> &p, ElInfo* elInfo = NULL) +{ + return obj(p); +}; + +/// Type-Traits for value_type of Data-Structures +/// ________________________________________________________________________________________________ + +template<typename T, typename enable=void> struct ValueType { typedef T type; }; +template<typename T> struct ValueType<DOFVector<T> > { typedef T type; }; +template<typename Derived> struct ValueType<Derived, typename boost::enable_if<boost::is_base_of<DOFView<double>, Derived > >::type> { typedef double type; }; +template<typename Derived> struct ValueType<Derived, typename boost::enable_if<boost::is_base_of<DOFView<WorldVector<double> >, Derived > >::type> { typedef WorldVector<double> type; }; +template<typename Derived> struct ValueType<Derived, typename boost::enable_if<boost::is_base_of<AbstractFunction<double, WorldVector<double> >, Derived > >::type> { typedef double type; }; +template<typename Derived> struct ValueType<Derived, typename boost::enable_if<boost::is_base_of<AbstractFunction<WorldVector<double>, WorldVector<double> >, Derived > >::type> { typedef WorldVector<double> type; }; + +/// transformDOF by coords (independent of mesh and feSpace) +/// ________________________________________________________________________________________________ + +// result = vec +template<typename TOut, typename Vector> +inline void interpol_coords(Vector &vec, DOFVector<TOut> &result) +{ + typedef typename ValueType<Vector>::type T; + DOFVector<WorldVector<double> > coords(result.getFeSpace(), "coords"); + result.getFeSpace()->getMesh()->getDofIndexCoords(result.getFeSpace(), coords); + + DOFIterator<WorldVector<double> > it_coords(&coords, USED_DOFS); + DOFIterator<TOut> it_result(&result, USED_DOFS); + for (it_coords.reset(), it_result.reset(); !it_coords.end(); ++it_coords, ++it_result) { + *it_result = evalAtPoint<T>(vec, *it_coords); + } +}; + +// result = op(vec) +template<typename TOut, typename Vector> +inline void transformDOF_coords(Vector &vec, + DOFVector<TOut> &result, + AbstractFunction<TOut, typename ValueType<Vector>::type> *op) +{ + typedef typename ValueType<Vector>::type T; + DOFVector<WorldVector<double> > coords(result.getFeSpace(), "coords"); + result.getFeSpace()->getMesh()->getDofIndexCoords(result.getFeSpace(), coords); + + DOFIterator<WorldVector<double> > it_coords(&coords, USED_DOFS); + DOFIterator<TOut> it_result(&result, USED_DOFS); + for (it_coords.reset(), it_result.reset(); !it_coords.end(); ++it_coords, ++it_result) { + T value = evalAtPoint<T>(vec, *it_coords); + *it_result = (*op)(value); + } +}; + +// result = binary_op(vec1, vec2) +template<typename TOut, typename Vector1, typename Vector2> +inline void transformDOF_coords(Vector1 &vec1, Vector2 &vec2, + DOFVector<TOut> &result, + BinaryAbstractFunction<TOut, typename ValueType<Vector1>::type, + typename ValueType<Vector2>::type> *binary_op) +{ + typedef typename ValueType<Vector1>::type T1; + typedef typename ValueType<Vector2>::type T2; + DOFVector<WorldVector<double> > coords(result.getFeSpace(), "coords"); + result.getFeSpace()->getMesh()->getDofIndexCoords(result.getFeSpace(), coords); + + DOFIterator<WorldVector<double> > it_coords(&coords, USED_DOFS); + DOFIterator<TOut> it_result(&result, USED_DOFS); + for (it_coords.reset(), it_result.reset(); !it_coords.end(); ++it_coords, ++it_result) { + T1 value1 = evalAtPoint<T1>(vec1, *it_coords); + T2 value2 = evalAtPoint<T2>(vec2, *it_coords); + + *it_result = (*binary_op)(value1, value2); + } +}; + +// result = tertiary_op(vec1, vec2, vec3) +template<typename TOut, typename Vector1, typename Vector2, typename Vector3> +inline void transformDOF_coords(Vector1 &vec1, Vector2 &vec2, Vector3 &vec3, + DOFVector<TOut> &result, + TertiaryAbstractFunction<TOut, typename ValueType<Vector1>::type, + typename ValueType<Vector2>::type, + typename ValueType<Vector3>::type> *tertiary_op) +{ + typedef typename ValueType<Vector1>::type T1; + typedef typename ValueType<Vector2>::type T2; + typedef typename ValueType<Vector3>::type T3; + DOFVector<WorldVector<double> > coords(result.getFeSpace(), "coords"); + result.getFeSpace()->getMesh()->getDofIndexCoords(result.getFeSpace(), coords); + + DOFIterator<WorldVector<double> > it_coords(&coords, USED_DOFS); + DOFIterator<TOut> it_result(&result, USED_DOFS); + for (it_coords.reset(), it_result.reset(); !it_coords.end(); ++it_coords, ++it_result) { + T1 value1 = evalAtPoint<T1>(vec1, *it_coords); + T2 value2 = evalAtPoint<T2>(vec2, *it_coords); + T3 value3 = evalAtPoint<T3>(vec3, *it_coords); + + *it_result = (*tertiary_op)(value1, value2, value3); + } +}; + + +// result = quart_op(vec1, vec2, vec3, vec4) +template<typename TOut, typename Vector1, typename Vector2, typename Vector3, typename Vector4> +inline void transformDOF_coords(Vector1 &vec1, Vector2 &vec2, Vector3 &vec3, Vector4 &vec4, + DOFVector<TOut> &result, + QuartAbstractFunction<TOut, typename ValueType<Vector1>::type, + typename ValueType<Vector2>::type, + typename ValueType<Vector3>::type, + typename ValueType<Vector4>::type> *quart_op) +{ + typedef typename ValueType<Vector1>::type T1; + typedef typename ValueType<Vector2>::type T2; + typedef typename ValueType<Vector3>::type T3; + typedef typename ValueType<Vector4>::type T4; + DOFVector<WorldVector<double> > coords(result.getFeSpace(), "coords"); + result.getFeSpace()->getMesh()->getDofIndexCoords(result.getFeSpace(), coords); + + DOFIterator<WorldVector<double> > it_coords(&coords, USED_DOFS); + DOFIterator<TOut> it_result(&result, USED_DOFS); + for (it_coords.reset(), it_result.reset(); !it_coords.end(); ++it_coords, ++it_result) { + T1 value1 = evalAtPoint<T1>(vec1, *it_coords); + T2 value2 = evalAtPoint<T2>(vec2, *it_coords); + T3 value3 = evalAtPoint<T3>(vec3, *it_coords); + T4 value4 = evalAtPoint<T3>(vec4, *it_coords); + + *it_result = (*quart_op)(value1, value2, value3, value4); + } +}; + +#endif // MY_VIEWS_H diff --git a/extensions/VtuReader.h b/extensions/VtuReader.h new file mode 100644 index 0000000000000000000000000000000000000000..2b85e8f1de94d063b0acba226faeee8591708661 --- /dev/null +++ b/extensions/VtuReader.h @@ -0,0 +1,276 @@ +// ============================================================================ +// == == +// == AMDiS - Adaptive multidimensional simulations == +// == == +// == http://www.amdis-fem.org == +// == == +// ============================================================================ +// +// Software License for AMDiS +// +// Copyright (c) 2010 Dresden University of Technology +// All rights reserved. +// Authors: Simon Vey, Thomas Witkowski et al. +// +// This file is part of AMDiS +// +// See also license.opensource.txt in the distribution. + + + +/** \file VtuReader.h */ + +#ifndef AMDIS_VTUREADER_H +#define AMDIS_VTUREADER_H + +#include <cstring> +#include "DOFVector.h" +#include "Mesh.h" +#include "boost/filesystem.hpp" +#include "pugixml/src/pugixml.hpp" +#include "kdtree_nanoflann.h" + +namespace AMDiS { + + namespace VtuReader { + + /// Copies the values of a VTU-file to a DOF vector. + template<typename T> + inline void readValue(std::string filename, + Mesh *mesh, + DOFVector<T> *dofVector, + std::string componentName); + + /// Copies the values of a VTU-file to a vector of DOF vectors. + template<typename T> + inline void readValue(std::string filename, + Mesh *mesh, + std::vector<DOFVector<T>*> dofVectors, + std::vector<std::string> componentNames); + + + namespace details { + + // num_rows for scalar types + template<typename T> + size_t num_rows(T &v) { + return 1; + }; + // for WorldVectors print 3 components + template<typename T> + size_t num_rows(WorldVector<T> &v) { + return static_cast<size_t>(v.getSize()); + } + // num_rows for vector types + template<typename T> + size_t num_rows(std::vector<T> &v) { + return v.size(); + }; + template<typename T> + size_t num_rows(const std::vector<T> &v) { + return v.size(); + }; + template<typename T> + size_t num_rows(mtl::dense_vector<T> &v) { + return mtl::num_rows(v); + }; + template<typename T> + size_t num_rows(const mtl::dense_vector<T> &v) { + return mtl::num_rows(v); + }; + + template<typename T> + struct LessPairEps + { + LessPairEps() : eps(1.e-7) {} + bool operator()(const std::pair<WorldVector<double>, T>& lhs, const std::pair<WorldVector<double>, T>& rhs) const + { + return (lhs.first.getSize()==1 ? vertexi_compare1(lhs.first, rhs.first) : + (lhs.first.getSize()==2 ? vertexi_compare2(lhs.first, rhs.first) : + (lhs.first.getSize()==3 ? vertexi_compare3(lhs.first, rhs.first) : false))); + } + bool operator()(const std::pair<WorldVector<double>, T>& lhs, const WorldVector<double>& rhs) const + { + return (lhs.first.getSize()==1 ? vertexi_compare1(lhs.first, rhs) : + (lhs.first.getSize()==2 ? vertexi_compare2(lhs.first, rhs) : + (lhs.first.getSize()==3 ? vertexi_compare3(lhs.first, rhs) : false))); + } + bool operator()(const WorldVector<double>& lhs, const std::pair<WorldVector<double>, T>& rhs) const + { + return (lhs.getSize()==1 ? vertexi_compare1(lhs, rhs.first) : + (lhs.getSize()==2 ? vertexi_compare2(lhs, rhs.first) : + (lhs.getSize()==3 ? vertexi_compare3(lhs, rhs.first) : false))); + } + bool operator()(const WorldVector<double>& lhs, const WorldVector<double>& rhs) const + { + return (lhs.getSize()==1 ? vertexi_compare1(lhs, rhs) : + (lhs.getSize()==2 ? vertexi_compare2(lhs, rhs) : + (lhs.getSize()==3 ? vertexi_compare3(lhs, rhs) : false))); + } + private: + double eps; + + //returns true if vertex lhs is "smaller" than vertex rhs + //----------------------------------------< vertexi_compare1 > + bool vertexi_compare1(const WorldVector<double> lhs, const WorldVector<double> rhs) const { + return (lhs[0]-rhs[0]>eps); + } + + //----------------------------------------< vertexi_compare2 > + bool vertexi_compare2(const WorldVector<double> lhs, const WorldVector<double> rhs) const { + return (lhs[0]-rhs[0]>eps) + || (abs(lhs[0]-rhs[0])<=eps && lhs[1]-rhs[1]>eps); + } + + //----------------------------------------< vertexi_compare3 > + bool vertexi_compare3(const WorldVector<double> lhs, const WorldVector<double> rhs) const { + return (lhs[0]-rhs[0]>eps) + || (abs(lhs[0]-rhs[0])<=eps && lhs[1]-rhs[1]>eps) + || (abs(lhs[0]-rhs[0])<=eps && abs(lhs[1]-rhs[1])<=eps + && lhs[2]-rhs[2]>eps); + } + }; + + + inline void string2pointList(std::string& input, std::vector<WorldVector<double> >& pointList) + { + int dow = Global::getGeo(WORLD); + int dowExplicit = 3; + + std::vector<std::string> valueStringList; + std::stringstream ss(input); + std::string buf; + while (ss >> buf) + valueStringList.push_back(buf); + + pointList.clear(); + + std::vector<std::string>::iterator it; + size_t j = 0; + for (it = valueStringList.begin(); it != valueStringList.end();j++) { + WorldVector<double> p; + for (int i = 0; i < dowExplicit && it != valueStringList.end(); i++, it++) + if (i < dow) + p[i] = boost::lexical_cast<double>(*it); + pointList.push_back(p); + } + } + + template<typename T> + inline void string2valueList(std::string& input, std::vector<T>& valueList, int numComponent = 1, int numComponentMax = -1) + { + if (numComponentMax < 0) + numComponentMax = numComponent; + + std::vector<std::string> valueStringList; + std::stringstream ss(input); + std::string buf; + while (ss >> buf) + valueStringList.push_back(buf); + + valueList.clear(); + + std::vector<std::string>::iterator it; + for (it = valueStringList.begin(); it != valueStringList.end();) { + std::vector<double> p; + for (int i = 0; i < numComponentMax && it != valueStringList.end(); i++, it++) + if (i < numComponent) + p.push_back(boost::lexical_cast<double>(*it)); + T value; valueVector2type(p, value); + valueList.push_back(value); + } + } + + + template<typename T> + inline void string2dataMap(std::string& strPoints, std::string& strValues, std::map<WorldVector<double>, T, LessPairEps<T> >& dataList, int numComponent = 1, int numComponentMax = -1) + { + int dow = Global::getGeo(WORLD); + int dowExplicit = 3; + if (numComponentMax < 0) + numComponentMax = numComponent; + std::string buf; + + std::vector<std::string> pointStringList; + std::stringstream ss1(strPoints); + while (ss1 >> buf) + pointStringList.push_back(buf); + + std::vector<std::string> valueStringList; + std::stringstream ss2(strValues); + while (ss2 >> buf) + valueStringList.push_back(buf); + + if (pointStringList.size()/dowExplicit != valueStringList.size()/numComponentMax) + throw(std::runtime_error("Coordinates and values do not match! nPoints=" + + boost::lexical_cast<std::string>(pointStringList.size()/dowExplicit) + + ", nValues=" + + boost::lexical_cast<std::string>(valueStringList.size()/numComponentMax))); + + std::vector<std::string>::iterator it1, it2; + it1 = pointStringList.begin(); + it2 = valueStringList.begin(); + for (; it1 != pointStringList.end() && it2 != valueStringList.end();) { + WorldVector<double> p; + for (int i = 0; i < dowExplicit && it1 != pointStringList.end(); i++, it1++) + if (i < dow) + p[i] = boost::lexical_cast<double>(*it1); + + std::vector<double> v; + for (int i = 0; i < numComponentMax && it2 != valueStringList.end(); i++, it2++) + if (i < numComponent) + v.push_back(boost::lexical_cast<double>(*it2)); + T value; valueVector2type(v, value); + + dataList[p] = value; + } + } + + inline void valueVector2type(std::vector<double> p, double& value) + { + if (p.size() == 0) + throw(std::runtime_error("Not enough data for assignment!\n")); + value = p[0]; + } + + inline void valueVector2type(std::vector<double> p, WorldVector<double>& value) + { + if (p.size() != Global::getGeo(WORLD)) + throw(std::runtime_error("Not enough data for assignment!\n")); + for (int i = 0; i < Global::getGeo(WORLD); i++) + value[i] = p[i]; + } + + inline void valueVector2type(std::vector<double> p, std::vector<double>& value) + { + if (p.size() == 0) + throw(std::runtime_error("Not enough data for assignment!\n")); + for (int i = 0; i < p.size(); i++) + value.push_back(p[i]); + } + + + // find point in mesh using KD-tree structure + inline size_t getNearestIndex(experimental::KD_Tree& tree, WorldVector<double>& x) + { + // do a knn search + const size_t num_nnp = 1; + std::vector<size_t> ret_indexes(num_nnp); + std::vector<double> out_dists_sqr(num_nnp); + + nanoflann::KNNResultSet<double> resultSet(num_nnp); + resultSet.init(&ret_indexes[0], &out_dists_sqr[0] ); + + tree.index->findNeighbors(resultSet, x.begin(), nanoflann::SearchParams(10)); + return ret_indexes[0]; + } + + } // end namespace details + + } // end namespace VtuReader + +} // end namespace AMDiS + +#include "VtuReader.hh" + +#endif // AMDIS_VTUREADER_H diff --git a/extensions/VtuReader.hh b/extensions/VtuReader.hh new file mode 100644 index 0000000000000000000000000000000000000000..8187d2536643e9bee44e82683e718116a01a1750 --- /dev/null +++ b/extensions/VtuReader.hh @@ -0,0 +1,121 @@ +// +// Software License for AMDiS +// +// Copyright (c) 2010 Dresden University of Technology +// All rights reserved. +// Authors: Simon Vey, Thomas Witkowski et al. +// +// This file is part of AMDiS +// +// See also license.opensource.txt in the distribution. + +/** \file VtuReader.hh */ + +namespace AMDiS { + + namespace VtuReader { + + /** \brief + * Copies the values of a VTU file to a DOF vector. + * + * The DOF vector must have been created by a corresponding mesh file. The + * function now reads the corresponding VTU file and + * copies the values to the correct positions in the DOF vector. + */ + template<typename T> + void readValue(std::string filename, + Mesh *mesh, + DOFVector<T> *dofVector, + std::string componentName) + { + std::vector<DOFVector<T>*> dofVectors; dofVectors.push_back(dofVector); + std::vector<std::string> componentNames; componentNames.push_back(componentName); + + readValue(filename, mesh, dofVectors, componentNames); + } + + template<typename T> + void readValue(std::string filename, + Mesh *mesh, + std::vector<DOFVector<T>*> dofVectors, + std::vector<std::string> componentNames) + { + using namespace pugi; + using namespace VtuReader::details; + + FUNCNAME("VtuReader::readValue()"); + + TEST_EXIT(filename != "")("Filename not specified!\n"); + TEST_EXIT(mesh)("no mesh specified\n"); + TEST_EXIT(dofVectors.size() > 0)("no DOF vectors specified\n"); + TEST_EXIT(componentNames.size() > 0)("no componentName specified\n"); + + + if(!boost::filesystem::exists(filename)) + throw(std::runtime_error(filename + " does not exist!")); + + xml_document vtu; + if(!vtu.load_file(filename.c_str())) + throw(std::runtime_error("Could not load vtu file! Error in xml structure.")); + + xml_node VTKFile = vtu.child("VTKFile"); + xml_node UnstructuredGrid = VTKFile.child("UnstructuredGrid"); + xml_node Piece = UnstructuredGrid.child("Piece"); + xml_node PointData = Piece.child("PointData"); + xml_node Points = Piece.child("Points"); + + std::string points = Points.child_value("DataArray"); + typedef std::vector<WorldVector<double> > PL; + PL pointList; + string2pointList(points, pointList); + + std::vector<std::vector<T> > valueList(dofVectors.size()); + T test; + + for (xml_node DataArray = PointData.child("DataArray"); DataArray; DataArray = DataArray.next_sibling("DataArray")) { + std::string Name = DataArray.attribute("Name").value(); + for (size_t i = 0; i < componentNames.size(); i++) { + if (Name == componentNames[i]) { + std::string values = DataArray.last_child().value(); + int nComponents = -1; + if (DataArray.attribute("NumberOfComponents")) + nComponents = DataArray.attribute("NumberOfComponents").as_int(); + if (nComponents != -1 && num_rows(test) > nComponents) + throw(std::runtime_error("Can not store values in DOFVector with given value type. Too many components!")); + string2valueList(values, valueList[i], num_rows(test), nComponents); + break; + } + } + } + for (size_t i = 0; i < dofVectors.size(); i++) { + if (valueList[i].size() == 0) + throw(std::runtime_error("no values found for component name '"+componentNames[i]+"'!")); + if (pointList.size() != valueList[i].size()) + throw(std::runtime_error("Coordinates and values["+boost::lexical_cast<std::string>(i)+"] do not match!")); + } + + DOFVector<WorldVector<double> > coords(dofVectors[0]->getFeSpace(), "coords"); + dofVectors[0]->getFeSpace()->getMesh()->getDofIndexCoords(dofVectors[0]->getFeSpace(), coords); + + experimental::KD_Tree tree(Global::getGeo(WORLD), pointList, 10); + tree.index->buildIndex(); + + DOFIterator<WorldVector<double> > it_coords(&coords, USED_DOFS); + std::vector<DOFIterator<T>*> it_results; + for (size_t i = 0; i < dofVectors.size(); i++) { + it_results.push_back(new DOFIterator<T>(dofVectors[i], USED_DOFS)); + it_results[i]->reset(); + } + for (it_coords.reset(); !it_coords.end(); ++it_coords) { + size_t idx = getNearestIndex(tree, *it_coords); + + for (size_t i = 0; i < dofVectors.size(); i++) { + if (valueList[i].size() > idx) + *(*it_results[i]) = valueList[i][idx]; + (*it_results[i])++; + } + } + } + } // end namespace VtuReader + +} // end namespace diff --git a/extensions/base_problems/BaseProblem.h b/extensions/base_problems/BaseProblem.h new file mode 100644 index 0000000000000000000000000000000000000000..443a880436127f54b17208bd14ff4cb5b84158e5 --- /dev/null +++ b/extensions/base_problems/BaseProblem.h @@ -0,0 +1,184 @@ +/** \file BaseProblem.h */ + +#ifndef BASE_PROBLEM_H +#define BASE_PROBLEM_H + +#include "AMDiS.h" +#include "time/RosenbrockStationary.h" +#include "CouplingTimeInterface.h" + +using namespace AMDiS; + +const Flag MESH_ADOPTED = 1<<2; +const Flag DATA_ADOPTED = 1<<3; + +template<typename ProblemType=ProblemStat> +class BaseProblem : public ProblemIterationInterface, + public ProblemInstatBase +{ +public: + + BaseProblem(const std::string &name_); + ~BaseProblem() + { + delete prob; + } + + /// Initialisation of the problem. + virtual void initialize(Flag initFlag, + ProblemStat *adoptProblem = NULL, + Flag adoptFlag = INIT_NOTHING); + + /// Initialisation of DOFVectors and AbstractFunctions, + /// is called in \ref initTimeInteface after feSpace and mesh are initialized + virtual void initData() {}; + + /// calls \ref initData, \ref fillOperators and \ref fillBoundaryConditions in this ordering + virtual void initTimeInterface() + { FUNCNAME("BaseProblem::initTimeInterface()"); + initData(); + fillOperators(); + fillBoundaryConditions(); + }; + + /// read solution DOFVectors from .arh or .dat files + virtual Flag initDataFromFile(AdaptInfo *adaptInfo); + + /// calls \ref initDataFromFile + virtual void solveInitialProblem(AdaptInfo *adaptInfo) + { FUNCNAME("BaseProblem::solveInitialProblem()"); + Flag initFlag = initDataFromFile(adaptInfo); + }; + + /// calls \ref writeFiles + virtual void transferInitialSolution(AdaptInfo *adaptInfo) + { FUNCNAME("BaseProblem::transferInitialSolution()"); + oldMeshChangeIdx = getMesh()->getChangeIndex(); + writeFiles(adaptInfo, false); + }; + + /// This method is called before \ref beginIteration, \ref oneIteration and \ref endIteration. + virtual void initTimestep(AdaptInfo *adaptInfo) {}; + + /// calls \ref writeFiles + virtual void closeTimestep(AdaptInfo *adaptInfo); + + virtual void beginIteration(AdaptInfo *adaptInfo); + virtual Flag oneIteration(AdaptInfo *adaptInfo, Flag toDo = FULL_ITERATION); + virtual void endIteration(AdaptInfo *adaptInfo); + + /// Calls writeFiles of the problem + virtual void writeFiles(AdaptInfo *adaptInfo, bool force) + { FUNCNAME("BaseProblem::writeFiles()"); + prob->writeFiles(adaptInfo, force); + }; + + // getting methods + + /// pointer to the solution of the problem + SystemVector *getSolution() + { + return prob->getSolution(); + } + + /// pointer to the mesh of the problem + inline Mesh* getMesh(int comp = 0) + { + return prob->getMesh(comp); + } + + /// pointer to the feSpace of the problem + inline FiniteElemSpace* getFeSpace(int comp = 0) + { + return prob->getFeSpace(comp); + } + + /// name of the baseBroblem + std::string getName() + { + return name; + }; + + int getNumProblems() + { + return 1; + }; + + int getNumComponents() + { + return prob->getNumComponents(); + }; + + ProblemType *getProblem(int number= 0) + { + if (number<0 || number >= getNumProblems()) + throw(std::runtime_error("problem with given number does not exist")); + if (number == 0) + return prob; + }; + + ProblemType *getProblem(std::string name) + { + if (name == "prob") + return prob; + else + throw(std::runtime_error("problem with given name '" + name + "' does not exist")); + }; + + // setting methods + + void setAssembleMatrixOnlyOnce_butTimestepChange(int i, int j) + { + fixedMatrixTimestep.push_back(std::make_pair(i,j)); + } + + void setNumberOfTimesteps(int nTimesteps_) + { + nTimesteps= nTimesteps_; + } + + void serialize(std::ostream&) {}; + void deserialize(std::istream&) {}; + + /// method where operators are added to the problem + virtual void fillOperators() {}; + + /// method where boundary conditions are added to the problem + virtual void fillBoundaryConditions() {}; + + /// classical backward-euler time-discretization + void addTimeOperator(ProblemStat *prob, int i, int j); + + /// for rosenbrock-problems a special time-operator can be added + void addTimeOperator(RosenbrockStationary *prob, int i, int j); + +protected: + + ProblemType *prob; + + /// catch errors and exceptions in solve-block and continue with last iteration on failure + /// standard: false + bool secureIteration; + + /// dimension of the mesh (set in \ref initialize(...) ) + unsigned dim; + + /// dimension of world (set in constructur) + unsigned dow; + + int nTimesteps; + int oldMeshChangeIdx; + + double oldTimestep; + +private: + + std::vector<std::pair<int,int> > fixedMatrixTimestep; + +}; + +#include "BaseProblem.hh" + +typedef BaseProblem<ProblemStat> StandardBaseProblem; + +#endif // BASE_PROBLEM_H diff --git a/extensions/base_problems/BaseProblem.hh b/extensions/base_problems/BaseProblem.hh new file mode 100644 index 0000000000000000000000000000000000000000..15f69de7ba0de9e63a3985266d31a95999bf8e3e --- /dev/null +++ b/extensions/base_problems/BaseProblem.hh @@ -0,0 +1,213 @@ +using namespace AMDiS; + +template<typename ProblemType> +BaseProblem<ProblemType>::BaseProblem(const std::string &name_) : + ProblemInstatBase(name_,NULL), + prob(NULL), + secureIteration(false), + oldMeshChangeIdx(0), + nTimesteps(-1), + dim(1), + dow(1), + oldTimestep(0.0) +{ + // create basic problems + prob = new ProblemType(name + "->space"); + dow = Global::getGeo(WORLD); + + Initfile::get(name + "->secure iteration", secureIteration); +}; + + +template<typename ProblemType> +void BaseProblem<ProblemType>::initialize(Flag initFlag, + ProblemStat *adoptProblem, + Flag adoptFlag) +{ FUNCNAME("BaseProblem::initialize()"); + + prob->initialize(initFlag, adoptProblem, adoptFlag); + dim = getMesh()->getDim(); +}; + + +template<typename ProblemType> +Flag BaseProblem<ProblemType>::initDataFromFile(AdaptInfo *adaptInfo) +{ FUNCNAME("BaseProblem::initDataFromFile()"); + + Flag initFlag; + bool readDataFromFile = false, readArhFiles = false, readDatFiles = false; + Initfile::get(name + "->read data from file", readDataFromFile, 2); + if (!readDataFromFile) + return initFlag; + + Initfile::get(name + "->read arh files", readArhFiles, 2); + Initfile::get(name + "->read dat files", readDatFiles, 2); + if (readArhFiles && readDatFiles) { + WARNING("You can not read data from both formats, .arh and .dat! The .arh-format is selected.\n"); + } + + std::string data_file="", phase_file=""; + + // read data and mesh from arh-files/dat-files + MSG("read data from file...\n"); + if (readArhFiles) { + Initfile::get(name + "->data file", data_file); + if (data_file.size() == 0) return initFlag; + if (!file_exists(data_file)) + throw(std::runtime_error("The file '" + data_file + "' does not exist!")); + + std::vector<DOFVector<double>*> solutions; + for (size_t i = 0; i < prob->getNumComponents(); i++) + solutions.push_back(prob->getSolution()->getDOFVector(i)); + ArhReader::read(data_file, prob->getMesh(), solutions); + } else if(readDatFiles) { + bool preserveMacroFileInfo = false; + Parameters::get(prob->getMesh()->getName() + "->preserve macroFileInfo", preserveMacroFileInfo); + if (prob->getMesh()->getMacroFileInfo() == NULL || !preserveMacroFileInfo) + throw(std::runtime_error("Yout have to set the flag 'mesh_name->preserve macroFileInfo' to 'true' ("+boost::lexical_cast<std::string>(preserveMacroFileInfo)+"), in order to read .dat-files")); + + std::string filename = ""; + for (size_t i = 0; i < prob->getNumComponents(); i++) { + Parameters::get(name + "->value file["+boost::lexical_cast<std::string>(i)+"]",filename); + if (!file_exists(filename)) + throw(std::runtime_error("The file '" + filename + "'does not exist!")); + ValueReader::readValue(filename,prob->getMesh(),prob->getSolution()->getDOFVector(i),prob->getMesh()->getMacroFileInfo()); + } + } else + throw(std::runtime_error("Parameter 'read data from file' set to 'true', but no input format specified!")); + + initFlag.setFlag(DATA_ADOPTED); + initFlag.setFlag(MESH_ADOPTED); + + return initFlag; +}; + + +template<typename ProblemType> +void BaseProblem<ProblemType>::beginIteration(AdaptInfo *adaptInfo) +{ FUNCNAME("BaseProblem::beginIteration()"); + + MSG("\n"); + MSG(("[[ <"+name+"> iteration ]]\n").c_str()); + + // assemble some blocks only once, if some conditions are fullfilled + #ifdef HAVE_PARALLEL_DOMAIN_AMDIS + bool fixedMatrixCell = false; + #else + bool fixedMatrixCell = adaptInfo->getTimestepNumber() > 0 + && std::abs(adaptInfo->getTimestep() - oldTimestep) < DBL_TOL + && oldMeshChangeIdx == getMesh()->getChangeIndex(); + #endif + for(size_t i = 0; i < fixedMatrixTimestep.size(); ++i) { + prob->setAssembleMatrixOnlyOnce( + fixedMatrixTimestep[i].first, + fixedMatrixTimestep[i].second, + fixedMatrixCell); + } +}; + + +template<typename ProblemType> +Flag BaseProblem<ProblemType>::oneIteration(AdaptInfo *adaptInfo, + Flag toDo) +{ FUNCNAME("BaseProblem::oneIteration()"); + + Flag flag, markFlag; + + if (toDo.isSet(MARK)) + markFlag = prob->markElements(adaptInfo); + else + markFlag = 3; + + // refine + if (toDo.isSet(ADAPT) && markFlag.isSet(MESH_REFINED)) + flag = prob->refineMesh(adaptInfo); + // coarsen + if (toDo.isSet(ADAPT) && markFlag.isSet(MESH_COARSENED)) + flag |= prob->coarsenMesh(adaptInfo); + + #ifdef HAVE_PARALLEL_DOMAIN_AMDIS + MPI::COMM_WORLD.Barrier(); + #endif + + #ifndef NONLIN_PROBLEM + if (toDo.isSet(BUILD)) { + prob->getSolver()->setMultipleRhs(false); + prob->buildAfterCoarsen(adaptInfo, markFlag, true, true); + } + #endif + + if (toDo.isSet(SOLVE)) { + if (secureIteration) { + try { + prob->solve(adaptInfo); + } catch(std::exception &e) { + WARNING(("Could not solve system. Simulation will be stoped here! ERROR: " + + std::string(e.what()) + "\n").c_str()); + adaptInfo->setTime(adaptInfo->getEndTime()); + adaptInfo->setTimestepNumber(adaptInfo->getNumberOfTimesteps()); + return flag; + } catch(...) { + WARNING("Could not solve system. Simulation will be stoped here! Unknown ERROR\n"); + adaptInfo->setTime(adaptInfo->getEndTime()); + adaptInfo->setTimestepNumber(adaptInfo->getNumberOfTimesteps()); + return flag; + } + } else { + prob->solve(adaptInfo); + } + } + + if (toDo.isSet(ESTIMATE)) + prob->estimate(adaptInfo); + + oldTimestep = adaptInfo->getTimestep(); + oldMeshChangeIdx = getMesh()->getChangeIndex(); + + return flag; +}; + + +template<typename ProblemType> +void BaseProblem<ProblemType>::endIteration(AdaptInfo *adaptInfo) +{ FUNCNAME("BaseProblem::endIteration()"); + + MSG("\n"); + MSG(("[[ end of <"+name+"> iteration ]]\n").c_str()); +}; + + +template<typename ProblemType> +void BaseProblem<ProblemType>::closeTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("BaseProblem::closeTimestep()"); + + int outputPeriod = 1; + Initfile::get("user parameter->write every ith timestep", outputPeriod); + if (adaptInfo->getTimestepNumber() % outputPeriod == 0 + && adaptInfo->getStartTime() < adaptInfo->getEndTime()) { + writeFiles(adaptInfo, false); + } +}; + + + +template<typename ProblemType> +void BaseProblem<ProblemType>::addTimeOperator(ProblemStat *prob, int i, int j) +{ FUNCNAME("BaseProblem::addTimeOperator()"); + + Operator *op = new Operator(prob->getFeSpace(i), prob->getFeSpace(j)); + op->addZeroOrderTerm(new Simple_ZOT); + Operator *opRhs = new Operator(prob->getFeSpace(i)); + opRhs->addZeroOrderTerm(new VecAtQP_ZOT(prob->getSolution()->getDOFVector(j), NULL)); + + prob->addMatrixOperator(op, i, j, getInvTau(), getInvTau()); + prob->addVectorOperator(opRhs, i, getInvTau(), getInvTau()); +}; + + +template<typename ProblemType> +void BaseProblem<ProblemType>::addTimeOperator(RosenbrockStationary *prob, int i, int j) +{ FUNCNAME("BaseProblem::addTimeOperator()"); + + prob->addTimeOperator(i,j); +}; diff --git a/extensions/base_problems/CahnHilliard.cc b/extensions/base_problems/CahnHilliard.cc new file mode 100644 index 0000000000000000000000000000000000000000..1ce6f74ee6c716ebf0016a75145ff332a54c4512 --- /dev/null +++ b/extensions/base_problems/CahnHilliard.cc @@ -0,0 +1,193 @@ +#include "CahnHilliard.h" +#include "Views.h" +#include "SignedDistFunctors.h" +#include "PhaseFieldConvert.h" + +using namespace AMDiS; + +CahnHilliard::CahnHilliard(const std::string &name_) : + super(name_), + useMobility(false), + doubleWell(0), + gamma(1.0), + eps(0.1), + minusEps(-0.1), + epsInv(10.0), + minusEpsInv(-10.0), + epsSqr(0.01), + minusEpsSqr(-0.01), + reinit(NULL) +{ + // parameters for CH + Parameters::get(name + "->use mobility", useMobility); // mobility + Parameters::get(name + "->gamma", gamma); // mobility + Parameters::get(name + "->epsilon", eps); // interface width + + // type of double well: 0= [0,1], 1= [-1,1] + Parameters::get(name + "->double-well type", doubleWell); + + // transformation of the parameters + minusEps = -eps; + epsInv = 1.0/eps; + minusEpsInv = -epsInv; + epsSqr = sqr(eps); + minusEpsSqr = -epsSqr; +} + + +CahnHilliard::~CahnHilliard() +{ FUNCNAME("CahnHilliard::~CahnHilliard()"); + + if (reinit) + delete reinit; +} + + +void CahnHilliard::initData() +{ FUNCNAME("CahnHilliard::initData()"); + + // create instance redistancing class + reinit = new HL_SignedDistTraverse("reinit", getMesh()->getDim()); + + super::initData(); +} + + +void CahnHilliard::solveInitialProblem(AdaptInfo *adaptInfo) +{ FUNCNAME("CahnHilliard::solveInitialProblem()"); + + Flag initFlag = initDataFromFile(adaptInfo); + + if (!initFlag.isSet(DATA_ADOPTED)) { + int initialInterface = 0; + Initfile::get(name + "->initial interface", initialInterface); + double initialEps = eps; + Initfile::get(name + "->initial epsilon", initialEps); + + if (initialInterface == 0) { + /// horizontale Linie + double a= 0.0, dir= -1.0; + Initfile::get(name + "->line->pos", a); + Initfile::get(name + "->line->direction", dir); + prob->getSolution()->getDOFVector(0)->interpol(new Plane(a, dir)); + } + else if (initialInterface == 1) { + /// schraege Linie + double theta = m_pi/4.0; + prob->getSolution()->getDOFVector(0)->interpol(new PlaneRotation(0.0, theta, 1.0)); + transformDOFInterpolation(prob->getSolution()->getDOFVector(0),new PlaneRotation(0.0, -theta, -1.0), new AMDiS::Min<double>); + } + else if (initialInterface == 2) { + /// Ellipse + double a= 1.0, b= 1.0; + Initfile::get(name + "->ellipse->a", a); + Initfile::get(name + "->ellipse->b", b); + prob->getSolution()->getDOFVector(0)->interpol(new Ellipse(a,b)); + } + else if (initialInterface == 3) { + /// zwei horizontale Linien + double a= 0.75, b= 0.375; + Initfile::get(name + "->lines->pos1", a); + Initfile::get(name + "->lines->pos2", b); + prob->getSolution()->getDOFVector(0)->interpol(new Plane(a, -1.0)); + transformDOFInterpolation(prob->getSolution()->getDOFVector(0),new Plane(b, 1.0), new AMDiS::Max<double>); + } + else if (initialInterface == 4) { + /// Kreis + double radius= 1.0; + Initfile::get(name + "->kreis->radius", radius); + prob->getSolution()->getDOFVector(0)->interpol(new Circle(radius)); + } else if (initialInterface == 5) { + /// Rechteck + double width = 0.5; + double height = 0.3; + WorldVector<double> center; center.set(0.5); + Initfile::get(name + "->rectangle->width", width); + Initfile::get(name + "->rectangle->height", height); + Initfile::get(name + "->rectangle->center", center); + prob->getSolution()->getDOFVector(0)->interpol(new Rectangle(width, height, center)); + } + + /// create phase-field from signed-dist-function + if (doubleWell == 0) { + transformDOF(prob->getSolution()->getDOFVector(0), + new SignedDistToPhaseField(initialEps)); + } else { + transformDOF(prob->getSolution()->getDOFVector(0), + new SignedDistToCh(initialEps)); + } + } +} + + +void CahnHilliard::fillOperators() +{ FUNCNAME("CahnHilliard::fillOperators()"); + MSG("CahnHilliard::fillOperators()\n"); + + // c + Operator *opChMnew = new Operator(prob->getFeSpace(0),prob->getFeSpace(0)); + opChMnew->addZeroOrderTerm(new Simple_ZOT); + Operator *opChMold = new Operator(prob->getFeSpace(0),prob->getFeSpace(0)); + opChMold->addZeroOrderTerm(new VecAtQP_ZOT(prob->getSolution()->getDOFVector(0))); + // -nabla*(grad(c)) + Operator *opChL = new Operator(prob->getFeSpace(1),prob->getFeSpace(0)); + opChL->addSecondOrderTerm(new Simple_SOT); + + // div(M(c)grad(mu)), with M(c)=gamma/4*(c^2-1)^2 + Operator *opChLM = new Operator(prob->getFeSpace(0),prob->getFeSpace(1)); + if (useMobility) { + if (doubleWell == 0) + opChLM->addSecondOrderTerm(new VecAtQP_SOT( + prob->getSolution()->getDOFVector(0), + new MobilityCH0(gamma))); + else + opChLM->addSecondOrderTerm(new VecAtQP_SOT( + prob->getSolution()->getDOFVector(0), + new MobilityCH1(gamma))); + } else + opChLM->addSecondOrderTerm(new Simple_SOT(gamma)); + + // -2*c_old^3 + 3/2*c_old^2 + Operator *opChMPowExpl = new Operator(prob->getFeSpace(1),prob->getFeSpace(0)); + opChMPowExpl->addZeroOrderTerm(new VecAtQP_ZOT( + prob->getSolution()->getDOFVector(0), + new Pow3Functor(-2.0))); + if (doubleWell == 0) { + opChMPowExpl->addZeroOrderTerm(new VecAtQP_ZOT( + prob->getSolution()->getDOFVector(0), + new Pow2Functor(3.0/2.0))); + } + + // -3*c_old^2 * c + Operator *opChMPowImpl = new Operator(prob->getFeSpace(1),prob->getFeSpace(0)); + opChMPowImpl->addZeroOrderTerm(new VecAtQP_ZOT( + prob->getSolution()->getDOFVector(0), + new Pow2Functor(-3.0))); + if (doubleWell == 0) { + opChMPowImpl->addZeroOrderTerm(new VecAtQP_ZOT( + prob->getSolution()->getDOFVector(0), + new AMDiS::Factor<double>(3.0))); + opChMPowImpl->addZeroOrderTerm(new Simple_ZOT(-0.5)); + } else { + opChMPowImpl->addZeroOrderTerm(new Simple_ZOT(1.0)); + } + + // dt(c) = laplace(mu) - u*grad(c) + // ----------------------------------- + prob->addMatrixOperator(*opChMnew,0,0, getInvTau()); /// < phi*c/tau , psi > + prob->addMatrixOperator(*opChLM,0,1); /// < phi*grad(mu) , grad(psi) > + // . . . vectorOperators . . . . . . . . . . . . . . . + prob->addVectorOperator(*opChMold,0, getInvTau()); /// < phi*c^old/tau , psi > + +// setAssembleMatrixOnlyOnce_butTimestepChange(0,0); + + // mu + eps^2*laplace(c) + c - 3*(c_old^2)*c = -2*c_old^3 [+ BC] + // ---------------------------------------------------------------------- + prob->addMatrixOperator(*opChMPowImpl,1,0); /// < -3*phi*c*c_old^2 , psi > + prob->addMatrixOperator(*opChL,1,0, &minusEpsSqr); /// < -eps^2*phi*grad(c) , grad(psi) > + prob->addMatrixOperator(*opChMnew,1,1); /// < phi*mu , psi > + // . . . vectorOperators . . . . . . . . . . . . . . . + prob->addVectorOperator(*opChMPowExpl,1); /// < -2*phi*c_old^3 , psi > + +// setAssembleMatrixOnlyOnce_butTimestepChange(1,1); +} diff --git a/extensions/base_problems/CahnHilliard.h b/extensions/base_problems/CahnHilliard.h new file mode 100644 index 0000000000000000000000000000000000000000..abff846b159de9a3c016b3731859a89823264bd5 --- /dev/null +++ b/extensions/base_problems/CahnHilliard.h @@ -0,0 +1,141 @@ +/** \file CahnHilliard.h */ + +#ifndef CAHN_HILLIARD_H +#define CAHN_HILLIARD_H + +#include "AMDiS.h" +#include "BaseProblem.h" +#include "ExtendedProblemStat.h" +#include "HL_SignedDistTraverse.h" + +using namespace AMDiS; + +class CahnHilliard : public BaseProblem<ExtendedProblemStat> +{ +public: // definition of types + + typedef BaseProblem<ExtendedProblemStat> super; + +public: // public methods + + CahnHilliard(const std::string &name_); + ~CahnHilliard(); + + virtual void initData(); + virtual void solveInitialProblem(AdaptInfo *adaptInfo); + + double getEpsilon() { return eps; } + int getDoubleWellType() { return doubleWell; } + +protected: // protected methods + + virtual void fillOperators(); + virtual void fillBoundaryConditions() {} + +protected: // protected variables + + HL_SignedDistTraverse *reinit; + + bool useMobility; + + unsigned dim; + + int doubleWell; + + double gamma; + double eps; + double minusEps; + double epsInv; + double minusEpsInv; + double epsSqr; + double minusEpsSqr; +}; + + +/** \brief + * Abstract function for Cahn-Hilliard mobility + */ +class MobilityCH0 : public AbstractFunction<double,double> +{ + public: + MobilityCH0(double gamma_=1.0) : + AbstractFunction<double,double>(4), + gamma(gamma_), + delta(1.e-6) { } + double operator()(const double &ch) const + { + double phase = std::max(0.0, std::min(1.0, ch)); + double mobility = 0.25*sqr(phase)*sqr(phase-1.0); + return gamma * std::max(mobility, delta); + } + + protected: + double gamma; + double delta; +}; + +class MobilityCH1 : public AbstractFunction<double,double> +{ + public: + MobilityCH1(double gamma_=1.0) : + AbstractFunction<double,double>(4), + gamma(gamma_), + delta(1.e-6) { } + double operator()(const double &ch) const + { + double phase = std::max(-1.0, std::min(1.0, ch)); + double mobility = 0.25*sqr(sqr(phase)-1.0); + return gamma * std::max(mobility, delta); + } + + protected: + double gamma; + double delta; +}; + +class ScaleFunctor : public AbstractFunction<double,double> +{ + public: + ScaleFunctor(double factor_=1.0) : + AbstractFunction<double,double>(1), + factor(factor_) { } + double operator()(const double &ch) const + { + return factor * ch; + } + + protected: + double factor; +}; + +class Pow2Functor : public AbstractFunction<double,double> +{ + public: + Pow2Functor(double factor_=1.0) : + AbstractFunction<double,double>(2), + factor(factor_) { } + double operator()(const double &ch) const + { + return factor * sqr(ch); + } + + protected: + double factor; +}; + +class Pow3Functor : public AbstractFunction<double,double> +{ + public: + Pow3Functor(double factor_=1.0) : + AbstractFunction<double,double>(3), + factor(factor_) { } + double operator()(const double &ch) const + { + return factor * sqr(ch) * ch; + } + + protected: + double factor; +}; + +#endif // CAHN_HILLIARD_H diff --git a/extensions/base_problems/DiffuseDomainFsi.cc b/extensions/base_problems/DiffuseDomainFsi.cc new file mode 100644 index 0000000000000000000000000000000000000000..0b034703054357566410782a94c36ee559191111 --- /dev/null +++ b/extensions/base_problems/DiffuseDomainFsi.cc @@ -0,0 +1,245 @@ +#include "DiffuseDomainFsi.h" + +using namespace std; +using namespace AMDiS; + +DiffuseDomainFsi::DiffuseDomainFsi(const std::string &name_) : + super(name_), + phase(NULL), + phaseInv(NULL), + velocity(NULL), + displacement(NULL), + beta(1.0), + epsilon(1.e-1), + alpha(3.0), + mu(1.0), + viscosity(1.0), + density(1.0), + lambda(1.0), + rho(1.0), + fileWriterPhase(NULL), + fileWriterVelocity(NULL), + fileWriterDisplacement(NULL) +{ + + Parameters::get(name + "->beta", beta); + Parameters::get(name + "->epsilon", epsilon); + Parameters::get(name + "->alpha", alpha); + + // parameters for navier-stokes + Initfile::get(name + "->viscosity", viscosity); + Initfile::get(name + "->density", density); + // parameters for linear elasticity + Parameters::get(name + "->mu", mu); + Parameters::get(name + "->lambda", lambda); + Parameters::get(name + "->rho", rho); +}; + +DiffuseDomainFsi::~DiffuseDomainFsi() +{ + if (fileWriterPhase != NULL) + delete fileWriterPhase; + if (fileWriterVelocity != NULL) + delete fileWriterVelocity; + if (fileWriterDisplacement != NULL) + delete fileWriterDisplacement; +} + +void DiffuseDomainFsi::initData() +{ + super::initData(); + + phaseInv = new DOFVector<double>(getFeSpace(dow+1), "phaseInv"); + velocity = new DOFVector<WorldVector<double> >(getFeSpace(0), "velocity"); + displacement = new DOFVector<WorldVector<double> >(getFeSpace(dow+1), "displacement"); + + dbc_factor = beta/pow(epsilon, alpha); + MSG_DBG("dbc_factor = %f\n", dbc_factor); + pressure_factor = -(lambda+(2.0/3.0)*mu); + MSG_DBG("pressure_factor = %f\n", pressure_factor); +} + + +void DiffuseDomainFsi::transferInitialSolution(AdaptInfo *adaptInfo) +{ FUNCNAME("DiffuseDomainFsi::transferInitialSolution()"); + + fileWriterPhase = new FileWriter(name + "->phase->output", getFeSpace()->getMesh(), phase); + fileWriterVelocity = new FileVectorWriter(name + "->velocity->output", getFeSpace()->getMesh(), velocity); + fileWriterDisplacement = new FileVectorWriter(name + "->displacement->output", getFeSpace()->getMesh(), displacement); + + super::transferInitialSolution(adaptInfo); + transformDOF(1.0, phase, phaseInv, new Subtract<double>); + + calcVelocity(); + calcDisplacement(); + + for (int i = 0; i < prob->getNumComponents(); i++) + prob->setExactSolution(prob->getSolution()->getDOFVector(i), i); + + writeFiles(adaptInfo, false); + + // initial parameters for detecting mesh changes + oldMeshChangeIdx = getMesh()->getChangeIndex(); +} + + +void DiffuseDomainFsi::closeTimestep(AdaptInfo *adaptInfo) +{ + calcVelocity(); + calcDisplacement(); + + super::closeTimestep(adaptInfo); +} + + +void DiffuseDomainFsi::fillOperators() +{ FUNCNAME("DiffuseDomainFsi::fillOperators()"); + + WorldVector<DOFVector<double>* > vel; + for (size_t i = 0; i < dow; i++) + vel[i] = prob->getSolution()->getDOFVector(i); + + TEST_EXIT(phase != NULL && phaseInv != NULL)("PhaseField is not set!\n"); + + for (size_t i = 0; i < dow; ++i) { + // time-derivative + // =============== + + /// < (1/tau)*u'_i , psi > + Operator *opTime = new Operator(prob->getFeSpace(i), prob->getFeSpace(i)); + opTime->addTerm(new Simple_ZOT(density)); + prob->addMatrixOperator(*opTime, i, i, getInvTau()); + /// < (1/tau)*u_i^old , psi > + Operator *opTimeOld = new Operator(prob->getFeSpace(i), prob->getFeSpace(i)); + opTimeOld->addTerm(new VecAtQP_ZOT(prob->getSolution()->getDOFVector(i), new Factor<double>(density))); + prob->addVectorOperator(*opTimeOld, i, getInvTau()); + + /// < (1/tau)*(1-phase)*eta_i , psi > + Operator *opTimeE = new Operator(getFeSpace(dow+1+i), getFeSpace(dow+1+i)); + opTimeE->addTerm(new VecAtQP_ZOT(phaseInv)); + prob->addMatrixOperator(*opTimeE, dow+1+i, dow+1+i, getInvTau(), getInvTau()); + /// < (1/tau)*(1-phase)*eta_i^old , psi > + Operator *opTimeEOld = new Operator(getFeSpace(i+dow)); + opTimeEOld->addTerm(new Vec2AtQP_ZOT(phaseInv, prob->getSolution()->getDOFVector(dow+1+i))); + prob->addVectorOperator(*opTimeEOld, dow+1+i, getInvTau(), getInvTau()); + + /// < (1-phase)*u , psi > + Operator *opU = new Operator(getFeSpace(dow+1+i), getFeSpace(i)); + opU->addTerm(new Phase_ZOT(phaseInv, -1.0)); + prob->addMatrixOperator(*opU, dow+1+i, dow+1+i); + + // nonlinear terms + // =============== + + /// < u^old*grad(u_i^old) , psi > + Operator *opUGradU0 = new Operator(getFeSpace(i), getFeSpace(i)); + opUGradU0->addTerm(new WorldVector_FOT(velocity, -density), GRD_PHI); + opUGradU0->setUhOld(prob->getSolution()->getDOFVector(i)); + if (nonLinTerm == 0) + prob->addVectorOperator(*opUGradU0, i); + + if (nonLinTerm == 1) { + /// < u'*grad(u_i^old) , psi > + for (unsigned j = 0; j < dow; ++j) { + Operator *opUGradU1 = new Operator(getFeSpace(i),getFeSpace(i)); + opUGradU1->addTerm(new PartialDerivative_ZOT( + prob->getSolution()->getDOFVector(i), j, density)); + prob->addMatrixOperator(*opUGradU1, i, j); + } + } else if (nonLinTerm == 2) { + /// < u^old*grad(u'_i) , psi > + for(unsigned j = 0; j < dow; ++j) { + Operator *opUGradU2 = new Operator(getFeSpace(i),getFeSpace(i)); + opUGradU2->addTerm(new VecAndPartialDerivative_FOT( + prob->getSolution()->getDOFVector(j), j, density), GRD_PHI); + prob->addMatrixOperator(*opUGradU2, i, i); + } + } + + // ==================== + + /// < u^old*grad(u_i^old) , psi > + Operator *opUGradE0 = new Operator(prob->getFeSpace(i),prob->getFeSpace(dow+1+i)); + opUGradE0->addTerm(new WorldVecPhase_FOT(phaseInv, vel), GRD_PHI); + opUGradE0->setUhOld(prob->getSolution()->getDOFVector(dow+1+i)); + if (nonLinTerm == 0) + prob->addVectorOperator(*opUGradE0, dow+1+i); + + if (nonLinTerm == 1) { + /// < u'*grad(u_i^old) , psi > + for (size_t j = 0; j < dow; ++j) { + Operator *opUGradE1 = new Operator(prob->getFeSpace(i),prob->getFeSpace(dow+1+i)); + opUGradE1->addTerm(new VecAndPartialDerivative_ZOT( + phaseInv, + prob->getSolution()->getDOFVector(dow+1+i), j)); + prob->addMatrixOperator(*opUGradE1, dow+1+i, j); + } + } else if (nonLinTerm == 2) { + /// < u^old*grad(u'_i) , psi > + for(size_t j = 0; j < dow; ++j) { + Operator *opUGradE2 = new Operator(prob->getFeSpace(i),prob->getFeSpace(i)); + opUGradE2->addTerm(new Vec2ProductPartial_FOT( + phaseInv, + prob->getSolution()->getDOFVector(j), j, density), GRD_PHI); + prob->addMatrixOperator(*opUGradE2, dow+1+i, dow+1+i); + } + } + + /// Diffusion-Operator (including Stress-Tensor for space-dependent viscosity) + addLaplaceTerm(i); + } + + /// phase*div(u) +(1 - phase)*(p - (lambda + 2/3*mu)*div(eta)) + for (size_t i = 0; i < dow; ++i) { + /// < phase*d_i(u_i) , psi > + Operator *opDivU = new Operator(prob->getFeSpace(dow),prob->getFeSpace(i)); + opDivU->addTerm(new VecAndPartialDerivative_FOT(phase, i), GRD_PHI); + prob->addMatrixOperator(*opDivU, dow, i); + + /// < (1-phase)*d_i(eta_i) , psi > + Operator *opDivEta = new Operator(prob->getFeSpace(dow),prob->getFeSpace(dow+1+i)); + opDivEta->addTerm(new VecAndPartialDerivative_FOT(phaseInv, i, pressure_factor), GRD_PHI); + prob->addMatrixOperator(*opDivEta, dow, dow+1+i); + } + + /// < (1-phase)*p , psi > + Operator *opP = new Operator(prob->getFeSpace(dow),prob->getFeSpace(dow)); + opP->addTerm(new VecAtQP_ZOT(phaseInv)); + prob->addMatrixOperator(*opP, dow, dow); + +} + + +void DiffuseDomainFsi::addLaplaceTerm(int i) +{ FUNCNAME("DiffuseDomainFsi::addLaplaceTerm()"); + + for (size_t j = 0; j < dow; ++j) { + /// < nu*[grad(u)+grad(u)^t] , grad(psi) > + Operator *opLaplaceUi1 = new Operator(prob->getFeSpace(i), prob->getFeSpace(j)); + opLaplaceUi1->addTerm(new MatrixIJPhase_SOT(phase, 1-i, 1-j, viscosity)); + prob->addMatrixOperator(*opLaplaceUi1, i, j); + + /// < (mu+lambda)*[grad(u)+grad(u)^t] , grad(psi) > + Operator *opLaplaceEi1 = new Operator(prob->getFeSpace(dow+1+i), prob->getFeSpace(dow+1+j)); + opLaplaceEi1->addTerm(new MatrixIJPhase_SOT(phaseInv, 1-i, 1-j, mu+lambda)); + prob->addMatrixOperator(*opLaplaceEi1, dow+1+i, dow+1+j); + } + + /// < nu*grad(u_i) , grad(psi) > + Operator *opLaplaceUi = new Operator(prob->getFeSpace(i), prob->getFeSpace(i)); + opLaplaceUi->addTerm(new Phase_SOT(phase, viscosity)); + prob->addMatrixOperator(*opLaplaceUi, i, i); + + /// < mu*grad(eta_i) , grad(psi) > + Operator *opLaplaceEi = new Operator(prob->getFeSpace(dow+1+i), prob->getFeSpace(dow+1+i)); + opLaplaceEi->addTerm(new Phase_SOT(phaseInv, mu)); + prob->addMatrixOperator(*opLaplaceEi, dow+1+i, dow+1+i); + + /// < p , d_i(psi) > + Operator *opGradP = new Operator(prob->getFeSpace(i),prob->getFeSpace(dow)); + opGradP->addTerm(new VecAndPartialDerivative_FOT(phase,i, -1.0), GRD_PSI); + prob->addMatrixOperator(*opGradP, i, dow); + Operator *opGradP2 = new Operator(prob->getFeSpace(i),prob->getFeSpace(dow)); + opGradP2->addTerm(new PartialDerivative_ZOT(phase,i, -1.0)); + prob->addMatrixOperator(*opGradP2, i, dow); +} diff --git a/extensions/base_problems/DiffuseDomainFsi.h b/extensions/base_problems/DiffuseDomainFsi.h new file mode 100644 index 0000000000000000000000000000000000000000..f54cb1a2a08d6209cebd8b9a2f49084401383559 --- /dev/null +++ b/extensions/base_problems/DiffuseDomainFsi.h @@ -0,0 +1,176 @@ +/** \file DiffuseDomainFsi.h */ + +#ifndef DIFFUSE_DOMAIN_FSI_H +#define DIFFUSE_DOMAIN_FSI_H + +#include "AMDiS.h" +#include "BaseProblem.h" +#include "ExtendedProblemStat.h" +#include "Helpers.h" +#include "POperators.h" + +using namespace AMDiS; + +/** \ingroup NavierStokes_TaylorHood + * \brief + * fully coupled fluid structure interaction using diffuse doamins + * + * dt(u_j) + u*grad(u_j) - div(phase*sigma_f) - div((1-phase)*sigma_s) = 0; j=1...d + * div(phase*u) = grad(phase)*u + * (1-phase)*(dt(eta_j)+u*grad(eta_j)) = (1-phase)*u_j; j=1...d + */ +class DiffuseDomainFsi : public BaseProblem<ExtendedProblemStat> +{ +public: // typedefs + + typedef BaseProblem<ExtendedProblemStat> super; + +public: // methods + + DiffuseDomainFsi(const std::string &name_); + ~DiffuseDomainFsi(); + + virtual void initData(); + virtual void transferInitialSolution(AdaptInfo *adaptInfo); + virtual void closeTimestep(AdaptInfo *adaptInfo); + + // === getting/setting methods === + + DOFVector<double> *getPhase() + { + return phase; + } + + double getEpsilon() + { + return epsilon; + } + + DOFVector<WorldVector<double> >* getVelocity() + { + return velocity; + } + + DOFVector<WorldVector<double> >* getDisplacement() + { + return displacement; + } + + void setPhase(DOFVector<double>* phase_) + { + phase = phase_; + } + + void setEpsilon(double epsilon_) + { + epsilon = epsilon_; + } + + void writeFiles(AdaptInfo* adaptInfo, bool force = false) + { + fileWriterPhase->writeFiles(adaptInfo, force); + fileWriterVelocity->writeFiles(adaptInfo, force); + fileWriterDisplacement->writeFiles(adaptInfo, force); + super::writeFiles(adaptInfo, force); + } + +// protected: // methods + + virtual void fillOperators(); +// virtual void fillBoundaryConditions(); + virtual void addLaplaceTerm(int i); + +protected: // variables + + double dbc_factor; // beta/epsilon^alpha + double pressure_factor; // -(lambda+2/3*mu) + double beta; + double epsilon; + double alpha; + + int laplaceType; + int nonLinTerm; + + double oldTimestep; + + // navier-stokes parameters + double viscosity; + double density; + // elasticity parameters + double mu; + double lambda; + double rho; + + DOFVector<double> *phase; + DOFVector<double> *phaseInv; + + DOFVector<WorldVector<double> >* velocity; + + void calcVelocity() + { + if (dow == 1) + transformDOF(prob->getSolution()->getDOFVector(0), velocity, new AMDiS::Vec1WorldVec<double>); + else if (dow == 2) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), velocity, new AMDiS::Vec2WorldVec<double>); + else if (dow == 3) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), prob->getSolution()->getDOFVector(2), velocity, new AMDiS::Vec3WorldVec<double>); + } + + DOFVector<WorldVector<double> >* displacement; + + void calcDisplacement() + { + if (dow == 1) + transformDOF(prob->getSolution()->getDOFVector(dow+1), displacement, new AMDiS::Vec1WorldVec<double>); + else if (dow == 2) + transformDOF(prob->getSolution()->getDOFVector(dow+1), prob->getSolution()->getDOFVector(dow+2), displacement, new AMDiS::Vec2WorldVec<double>); + else if (dow == 3) + transformDOF(prob->getSolution()->getDOFVector(dow+1), prob->getSolution()->getDOFVector(dow+2), prob->getSolution()->getDOFVector(dow+3), displacement, new AMDiS::Vec3WorldVec<double>); + } + + FileWriter* fileWriterPhase; + FileVectorWriter* fileWriterVelocity; + FileVectorWriter* fileWriterDisplacement; +}; + + +struct ComponentExtractor : AbstractFunction<double, WorldVector<double> > +{ + ComponentExtractor(AbstractFunction<WorldVector<double>, WorldVector<double> >* fct_, int comp_, double factor_=1.0) + : AbstractFunction<double, WorldVector<double> >(fct_->getDegree()), + fct(fct_), + comp(comp_), + factor(factor_) {} + + double operator()(const WorldVector<double>& x) const { + WorldVector<double> result = (*fct)(x); + return factor*result[comp]; + } + +private: + AbstractFunction<WorldVector<double>, WorldVector<double> >* fct; + int comp; + double factor; +}; + + +struct VecAndComponentExtractor : BinaryAbstractFunction<double, double, WorldVector<double> > +{ + VecAndComponentExtractor(AbstractFunction<WorldVector<double>, WorldVector<double> >* fct_, int comp_, double factor_=1.0) + : BinaryAbstractFunction<double, double, WorldVector<double> >(fct_->getDegree()+1), + fct(fct_), + comp(comp_), + factor(factor_) {} + + double operator()(const double& vec, const WorldVector<double>& x) const { + WorldVector<double> result = (*fct)(x); + return factor*vec*result[comp]; + } + +private: + AbstractFunction<WorldVector<double>, WorldVector<double> >* fct; + int comp; + double factor; +}; + +#endif // DIFFUSE_DOMAIN_FSI_H diff --git a/extensions/base_problems/LinearElasticity.cc b/extensions/base_problems/LinearElasticity.cc new file mode 100644 index 0000000000000000000000000000000000000000..05755a5b713c9a013fca0681ad0708d64f2f8574 --- /dev/null +++ b/extensions/base_problems/LinearElasticity.cc @@ -0,0 +1,158 @@ +#include "LinearElasticity.h" + +using namespace std; +using namespace AMDiS; + +LinearElasticity::LinearElasticity(const std::string &name_) : + super(name_), + mu(1.0), + lambda(1.0), + rho(1.0), + displacement(NULL) +{ + Parameters::get(name + "->mu", mu); + Parameters::get(name + "->lambda", lambda); + Parameters::get(name + "->rho", rho); + + force.set(0.0); + Parameters::get(name + "->force", force); +} + + +LinearElasticity::~LinearElasticity() +{ FUNCNAME("LinearElasticity::~LinearElasticity()"); + + if (displacement != NULL) + delete displacement; + delete fileWriter; +} + + +void LinearElasticity::initData() +{ FUNCNAME("LinearElasticity::initTimeInterface()"); + + if (displacement == NULL) + displacement = new DOFVector<WorldVector<double> >(getFeSpace(0), "displacement"); + fileWriter = new FileVectorWriter(name + "->displacement->output", getFeSpace()->getMesh(), displacement); + + super::initData(); +} + + +void LinearElasticity::solveInitialProblem(AdaptInfo *adaptInfo) +{ FUNCNAME("LinearElasticity::solveInitialProblem()"); + + for (size_t i = 0; i < 2*dow-1; i++) + prob->getSolution()->getDOFVector(i)->set(0.0); +} + + +void LinearElasticity::transferInitialSolution(AdaptInfo *adaptInfo) +{ FUNCNAME("LinearElasticity::transferInitialSolution()"); + + if (dow == 1) + transformDOF(prob->getSolution()->getDOFVector(0), displacement, new AMDiS::Vec1WorldVec<double>); + else if (dow == 2) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), displacement, new AMDiS::Vec2WorldVec<double>); + else if (dow == 3) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), prob->getSolution()->getDOFVector(2), displacement, new AMDiS::Vec3WorldVec<double>); + + fileWriter->writeFiles(adaptInfo, false); + writeFiles(adaptInfo, false); + + // initial parameters for detecting mesh changes + oldMeshChangeIdx= getMesh()->getChangeIndex(); +} + + +void LinearElasticity::fillOperators() +{ FUNCNAME("LinearElasticity::fillOperators()"); + MSG("LinearElasticity::fillOperators()\n"); + + // fill operators for prob + for (size_t i = 0; i < dow; ++i) { + /// dt(u) - v = 0 + /// ____________________________________________________________________________ + + if (abs(rho) > DBL_TOL) { + // < (1/tau)*u_i , psi > + Operator *opTimeU = new Operator(getFeSpace(i+dow), getFeSpace(i)); + opTimeU->addTerm(new Simple_ZOT); + prob->addMatrixOperator(*opTimeU, i+dow, i, getInvTau(), getInvTau()); + // < (1/tau)*u_i^old , psi > + Operator *opTimeUOld = new Operator(getFeSpace(i+dow)); + opTimeUOld->addTerm(new VecAtQP_ZOT(prob->getSolution()->getDOFVector(i))); + prob->addVectorOperator(*opTimeUOld, i+dow, getInvTau(), getInvTau()); + } + // < v , psi > + Operator *opV = new Operator(getFeSpace(i+dow), getFeSpace(i+dow)); + opV->addTerm(new Simple_ZOT(abs(rho) > DBL_TOL ? -1.0/rho : -1.0)); + prob->addMatrixOperator(*opV, i+dow, i+dow); + + /// dt(v) - mu*div(grad(u)) - (mu+lambda)*grad(div(u)) = F + /// ____________________________________________________________________________ + + + if (abs(rho) > DBL_TOL) { + // < (1/tau)*v_i , psi > + Operator *opTimeV = new Operator(getFeSpace(i), getFeSpace(i+dow)); + opTimeV->addTerm(new Simple_ZOT); + prob->addMatrixOperator(*opTimeV, i, i+dow, getInvTau(), getInvTau()); + // < (1/tau)*v_i^old , psi > + Operator *opTimeVOld = new Operator(getFeSpace(i)); + opTimeVOld->addTerm(new VecAtQP_ZOT(prob->getSolution()->getDOFVector(i+dow))); + prob->addVectorOperator(*opTimeVOld, i, getInvTau(), getInvTau()); + } + + // < grad(u_i) , grad(psi) > + Operator *opDivGradU = new Operator(getFeSpace(i), getFeSpace(i)); + opDivGradU->addTerm(new Simple_SOT(mu)); + prob->addMatrixOperator(*opDivGradU, i, i); + + // < d_j(u_j) , d_i(psi) > + for (size_t j = 0; j < dow; j++) { + Operator *opGradDivU = new Operator(getFeSpace(i), getFeSpace(j)); + opGradDivU->addTerm(new FactorIJ_SOT(i, j, mu+lambda)); + prob->addMatrixOperator(*opGradDivU, i, j); + } + + // external force, i.e. gravitational force + if (norm(force) > DBL_TOL) { + Operator *opForce = new Operator(getFeSpace(i), getFeSpace(i)); + opForce->addTerm(new Simple_ZOT(force[i])); + prob->addVectorOperator(*opForce, i); + } + } +} + + +void LinearElasticity::fillBoundaryConditions() +{ FUNCNAME("LinearElasticity::fillBoundaryConditions()"); + +// ERROR("You have to implement some boundary conditions!\n"); + AbstractFunction<double, WorldVector<double> > *zero = new AMDiS::Const<double, WorldVector<double> >(0.0); + for (size_t i = 0; i < 2*dow-1; i++) { + prob->addDirichletBC(1, i, i, zero); + } +} + + +// void LinearElasticity::initTimestep(AdaptInfo *adaptInfo) +// { FUNCNAME("LinearElasticity::initTimestep()"); +// +// } + + +void LinearElasticity::closeTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("LinearElasticity::closeTimestep()"); + + if (dow == 1) + transformDOF(prob->getSolution()->getDOFVector(0), displacement, new AMDiS::Vec1WorldVec<double>); + else if (dow == 2) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), displacement, new AMDiS::Vec2WorldVec<double>); + else if (dow == 3) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), prob->getSolution()->getDOFVector(2), displacement, new AMDiS::Vec3WorldVec<double>); + + fileWriter->writeFiles(adaptInfo, false); + writeFiles(adaptInfo, false); +} diff --git a/extensions/base_problems/LinearElasticity.h b/extensions/base_problems/LinearElasticity.h new file mode 100644 index 0000000000000000000000000000000000000000..f757b82eb2a4c6264a460696a327d221739924db --- /dev/null +++ b/extensions/base_problems/LinearElasticity.h @@ -0,0 +1,56 @@ +/** \file LinearElasticity.h */ + +#ifndef LINEAR_ELASTICITY_H +#define LINEAR_ELASTICITY_H + +#include "AMDiS.h" +#include "BaseProblem.h" +#include "ExtendedProblemStat.h" + +using namespace AMDiS; + +/** \ingroup Elasticity + * \brief + * Elastodynamics – the wave equation + */ +class LinearElasticity : public BaseProblem<ExtendedProblemStat> +{ +public: // typedefs + + typedef BaseProblem<ExtendedProblemStat> super; + +public: // methods + + LinearElasticity(const std::string &name_); + + /// if initialVelocityIsSet is true delete initialX and initialY + ~LinearElasticity(); + + virtual void initData(); + virtual void solveInitialProblem(AdaptInfo *adaptInfo); + + virtual void transferInitialSolution(AdaptInfo *adaptInfo); + +// virtual void initTimestep(AdaptInfo *adaptInfo); + /// Implementation of ProblemTimeInterface::closeTimestep(). + virtual void closeTimestep(AdaptInfo *adaptInfo); + + // === getting/setting methods === + +protected: // methods + + virtual void fillOperators(); + virtual void fillBoundaryConditions(); + +protected: // variables + + double mu; + double lambda; + double rho; + + WorldVector<double> force; + DOFVector<WorldVector<double> >* displacement; + + FileVectorWriter *fileWriter; +}; +#endif // LINEAR_ELASTICITY_H diff --git a/extensions/base_problems/LinearElasticityPhase.cc b/extensions/base_problems/LinearElasticityPhase.cc new file mode 100644 index 0000000000000000000000000000000000000000..7d58b6c52d0871d56c99a475c5316473dd5c1750 --- /dev/null +++ b/extensions/base_problems/LinearElasticityPhase.cc @@ -0,0 +1,198 @@ +#include "LinearElasticityPhase.h" +#include "POperators.h" + +using namespace std; +using namespace AMDiS; + +LinearElasticityPhase::LinearElasticityPhase(const std::string &name_) : + super(name_), + mu(1.0), + lambda(1.0), + rho(1.0), + epsilon(1.e-1), + beta(1.0), + alpha(3.0), + displacement(NULL), + phase(NULL), + phaseOld(NULL), + dirichletPhase(NULL), + bcFct(NULL) +{ + for (int i = 0; i < bcDOF.getSize(); ++i) + bcDOF[i] = NULL; + + Parameters::get(name + "->mu", mu); + Parameters::get(name + "->lambda", lambda); + Parameters::get(name + "->rho", rho); + Parameters::get(name + "->epsilon", epsilon); + + Parameters::get(name + "->beta", beta); + Parameters::get(name + "->alpha", alpha); + + force.set(0.0); + Parameters::get(name + "->force", force); +} + + +LinearElasticityPhase::~LinearElasticityPhase() +{ FUNCNAME("LinearElasticityPhase::~LinearElasticityPhase()"); + + if (displacement != NULL) + delete displacement; + delete fileWriter; +} + + +void LinearElasticityPhase::initData() +{ FUNCNAME("LinearElasticityPhase::initTimeInterface()"); + + if (displacement == NULL) + displacement = new DOFVector<WorldVector<double> >(getFeSpace(0), "displacement"); + phaseOld = new DOFVector<double>(getFeSpace(0), "phaseOld"); + fileWriter = new FileVectorWriter(name + "->displacement->output", getFeSpace()->getMesh(), displacement); + + super::initData(); + + dbc_factor = beta/pow(epsilon, alpha); + MSG_DBG("dbc_factor = %f\n", dbc_factor); +} + + +void LinearElasticityPhase::solveInitialProblem(AdaptInfo *adaptInfo) +{ FUNCNAME("LinearElasticityPhase::solveInitialProblem()"); + + super::solveInitialProblem(adaptInfo); + + for (size_t i = 0; i < 2*dow-1; i++) + prob->getSolution()->getDOFVector(i)->set(0.0); +} + + +void LinearElasticityPhase::transferInitialSolution(AdaptInfo *adaptInfo) +{ FUNCNAME("LinearElasticityPhase::transferInitialSolution()"); + + if (dow == 1) + transformDOF(prob->getSolution()->getDOFVector(0), displacement, new AMDiS::Vec1WorldVec<double>); + else if (dow == 2) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), displacement, new AMDiS::Vec2WorldVec<double>); + else if (dow == 3) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), prob->getSolution()->getDOFVector(2), displacement, new AMDiS::Vec3WorldVec<double>); + + fileWriter->writeFiles(adaptInfo, false); + writeFiles(adaptInfo, false); + + // initial parameters for detecting mesh changes + oldMeshChangeIdx= getMesh()->getChangeIndex(); +} + + +void LinearElasticityPhase::fillOperators() +{ FUNCNAME("LinearElasticityPhase::fillOperators()"); + MSG("LinearElasticityPhase::fillOperators()\n"); + + // fill operators for prob + for (size_t i = 0; i < dow; ++i) { + /// dt(u) - v = 0 + /// ____________________________________________________________________________ + + if (abs(rho) > DBL_TOL) { + // < (1/tau)*u_i , psi > + Operator *opTimeU = new Operator(getFeSpace(i+dow), getFeSpace(i)); + opTimeU->addTerm(new VecAtQP_ZOT(phase)); + prob->addMatrixOperator(*opTimeU, i+dow, i, getInvTau(), getInvTau()); + // < (1/tau)*u_i^old , psi > + Operator *opTimeUOld = new Operator(getFeSpace(i+dow)); + opTimeUOld->addTerm(new Vec2AtQP_ZOT(phaseOld, prob->getSolution()->getDOFVector(i))); + prob->addVectorOperator(*opTimeUOld, i+dow, getInvTau(), getInvTau()); + } + // < v , psi > + Operator *opV = new Operator(getFeSpace(i+dow), getFeSpace(i+dow)); + opV->addTerm(new Phase_ZOT(phase, -1.0)); + prob->addMatrixOperator(*opV, i+dow, i+dow); + + /// dt(v) - mu*div(grad(u)) - (mu+lambda)*grad(div(u)) = F + /// ____________________________________________________________________________ + + + if (abs(rho) > DBL_TOL) { + // < (1/tau)*v_i , psi > + Operator *opTimeV = new Operator(getFeSpace(i), getFeSpace(i+dow)); + opTimeV->addTerm(new VecAtQP_ZOT(phase, new AMDiS::Factor<double>(rho))); + prob->addMatrixOperator(*opTimeV, i, i+dow, getInvTau(), getInvTau()); + // < (1/tau)*v_i^old , psi > + Operator *opTimeVOld = new Operator(getFeSpace(i)); + opTimeVOld->addTerm(new Vec2AtQP_ZOT(phase, prob->getSolution()->getDOFVector(i+dow), new AMDiS::MultScal<double>(rho))); + prob->addVectorOperator(*opTimeVOld, i, getInvTau(), getInvTau()); + } + + // < grad(u_i) , grad(psi) > + Operator *opDivGradU = new Operator(getFeSpace(i), getFeSpace(i)); + opDivGradU->addTerm(new Phase_SOT(phase, mu)); + prob->addMatrixOperator(*opDivGradU, i, i); + + // < d_j(u_j) , d_i(psi) > + for (size_t j = 0; j < dow; j++) { + Operator *opGradDivU = new Operator(getFeSpace(i), getFeSpace(j)); + opGradDivU->addTerm(new MatrixIJPhase_SOT(phase, i, j, mu+lambda)); + prob->addMatrixOperator(*opGradDivU, i, j); + } + + // external force, i.e. gravitational force + if (norm(force) > DBL_TOL) { + Operator *opForce = new Operator(getFeSpace(i), getFeSpace(i)); + opForce->addTerm(new Phase_ZOT(phase, force[i])); + prob->addVectorOperator(*opForce, i); + } + } +} + + +void LinearElasticityPhase::fillBoundaryConditions() +{ FUNCNAME("LinearElasticityPhase::fillBoundaryConditions()"); + + /// neumann boundary condition + for (size_t i = 0; i < dow; i++) { + Operator *opNeumannForce = new Operator(getFeSpace(i), getFeSpace(i)); + if (bcDOF[i] != NULL) { + opNeumannForce->addTerm(new VecAndGradVecAtQP_ZOT(bcDOF[i], phase, new NeumannBCDof)); + } else if (bcFct != NULL) { + opNeumannForce->addTerm(new FctGradientCoords_ZOT(phase, new NeumannBCFct(new ComponentExtractor_(bcFct, i)))); + } + prob->addVectorOperator(*opNeumannForce, i); + } + + /// dirichlet boundary condition + if (dirichletPhase != NULL) { + for (size_t i = 0; i < dow; ++i) { + /// dirichlet boundary condition + /// beta/eps^alpha (1-phase)*(u_i - g_i), with g_i = 0 + Operator *opDbcPhaseInvU = new Operator(prob->getFeSpace(i), prob->getFeSpace(i)); + opDbcPhaseInvU->addTerm(new Simple_ZOT(dbc_factor)); + opDbcPhaseInvU->addTerm(new Phase_ZOT(dirichletPhase, -dbc_factor)); + prob->addMatrixOperator(*opDbcPhaseInvU, i, i); + } + } +} + + +void LinearElasticityPhase::initTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("LinearElasticityPhase::initTimestep()"); + + super::initTimestep(adaptInfo); + phaseOld->interpol(phase); +} + + +void LinearElasticityPhase::closeTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("LinearElasticityPhase::closeTimestep()"); + + if (dow == 1) + transformDOF(prob->getSolution()->getDOFVector(0), displacement, new AMDiS::Vec1WorldVec<double>); + else if (dow == 2) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), displacement, new AMDiS::Vec2WorldVec<double>); + else if (dow == 3) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), prob->getSolution()->getDOFVector(2), displacement, new AMDiS::Vec3WorldVec<double>); + + fileWriter->writeFiles(adaptInfo, false); + writeFiles(adaptInfo, false); +} diff --git a/extensions/base_problems/LinearElasticityPhase.h b/extensions/base_problems/LinearElasticityPhase.h new file mode 100644 index 0000000000000000000000000000000000000000..6876401c9b68382188dd51c9b1b96c1a6c1d2f68 --- /dev/null +++ b/extensions/base_problems/LinearElasticityPhase.h @@ -0,0 +1,147 @@ +/** \file LinearElasticityPhase.h */ + +#ifndef LINEAR_ELASTICITY_H +#define LINEAR_ELASTICITY_H + +#include "AMDiS.h" +#include "BaseProblem.h" +#include "ExtendedProblemStat.h" + +using namespace AMDiS; + +/** \ingroup Elasticity + * \brief + * Elastodynamics – the wave equation + */ +class LinearElasticityPhase : public BaseProblem<ExtendedProblemStat> +{ +public: // typedefs + + typedef BaseProblem<ExtendedProblemStat> super; + +public: // methods + + LinearElasticityPhase(const std::string &name_); + + /// if initialVelocityIsSet is true delete initialX and initialY + ~LinearElasticityPhase(); + + virtual void initData(); + virtual void solveInitialProblem(AdaptInfo *adaptInfo); + + virtual void transferInitialSolution(AdaptInfo *adaptInfo); + + virtual void initTimestep(AdaptInfo *adaptInfo); + virtual void closeTimestep(AdaptInfo *adaptInfo); + + // === getting/setting methods === + + DOFVector<double> *getPhase() + { + return phase; + } + + double getEpsilon() + { + return epsilon; + } + + void setPhase(DOFVector<double>* phase_) + { + phase = phase_; + } + + void setDirichletPhase(DOFVector<double>* phase_) + { + dirichletPhase = phase_; + } + + void setBcDOF(DOFVector<double>* bcDOF_i, int i) + { + bcDOF[i] = bcDOF_i; + } + + void setBcFct(AbstractFunction<WorldVector<double>, WorldVector<double> >* fct_) + { + bcFct = fct_; + } + + void setEpsilon(double epsilon_) + { + epsilon = epsilon_; + } + +// protected: // methods + + virtual void fillOperators(); + virtual void fillBoundaryConditions(); + +protected: // variables + + double mu; + double lambda; + double rho; + double epsilon; + double beta; + double alpha; + double dbc_factor; + + WorldVector<double> force; + DOFVector<WorldVector<double> >* displacement; + + DOFVector<double> *phase; + DOFVector<double> *phaseOld; + + WorldVector<DOFVector<double>*> bcDOF; + AbstractFunction<WorldVector<double>, WorldVector<double> >* bcFct; + + DOFVector<double>* dirichletPhase; + + FileVectorWriter *fileWriter; +}; + +struct NeumannBCDof : BinaryAbstractFunction<double, double, WorldVector<double> > +{ + NeumannBCDof() : BinaryAbstractFunction<double, double, WorldVector<double> >(5) {} + + double operator()(const double& g, const WorldVector<double>& grdPhase) const + { + return g/* * AMDiS::Norm2<double, WorldVector<double> >()(grdPhase)*/; + } +}; + +struct NeumannBCFct : BinaryAbstractFunction<double, WorldVector<double>, WorldVector<double> > +{ + NeumannBCFct(AbstractFunction<double, WorldVector<double> >* g_) + : BinaryAbstractFunction<double, WorldVector<double>, WorldVector<double> >(g_->getDegree() + 3), + g(g_) {} + + double operator()(const WorldVector<double>& grdPhase, const WorldVector<double>& x) const + { + return (*g)(x)/* * AMDiS::Norm2<double, WorldVector<double> >()(grdPhase)*/; + } + +private: + AbstractFunction<double, WorldVector<double> >* g; +}; + +struct ComponentExtractor_ : AbstractFunction<double, WorldVector<double> > +{ + ComponentExtractor_(AbstractFunction<WorldVector<double>, WorldVector<double> >* fct_, int comp_, double factor_=1.0) + : AbstractFunction<double, WorldVector<double> >(fct_->getDegree()), + fct(fct_), + comp(comp_), + factor(factor_) {} + + double operator()(const WorldVector<double>& x) const { + WorldVector<double> result = (*fct)(x); + return factor*result[comp]; + } + +private: + AbstractFunction<WorldVector<double>, WorldVector<double> >* fct; + int comp; + double factor; +}; + +#endif // LINEAR_ELASTICITY_H diff --git a/extensions/base_problems/NavierStokesPhase_Chorin.cc b/extensions/base_problems/NavierStokesPhase_Chorin.cc new file mode 100644 index 0000000000000000000000000000000000000000..4a46db3c5725564443d01ccb7b72cb851de7166a --- /dev/null +++ b/extensions/base_problems/NavierStokesPhase_Chorin.cc @@ -0,0 +1,271 @@ +#include "NavierStokesPhase_Chorin.h" + +#define UPDATE_VELOCITY_SYSTEM + +using namespace std; +using namespace AMDiS; + +NavierStokesPhase_Chorin::NavierStokesPhase_Chorin(const std::string &name_, WorldVector<AbstractFunction<double, WorldVector<double> >* > initialVelocityFcts_, DiffuseDomain* geometryProb_) : + super(name_, initialVelocityFcts_), + geometryProb(geometryProb_), + beta(1.0), + epsPhase2(1.0) +{ + Initfile::get(name + "->beta", beta); // penalization of boundary condition + double exponent = 2.7; + Initfile::get(name + "->exponent", exponent); // penalization of boundary condition + epsPhase2 = beta/pow(geometryProb->getEpsilon(), exponent); + + writer = new MyFileWriter(); + writer->initFile("diff"); +}; + + +void NavierStokesPhase_Chorin::solveInitialProblem(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokesPhase_Chorin::solveInitialProblem()"); +MSG_DBG("NavierStokesPhase_Chorin::solveInitialProblem()\n"); + + NavierStokes_Chorin::solveInitialProblem(adaptInfo); + + if (initialVelocityIsSet) { + for (unsigned i = 0; i < dim; ++i) { + transformDOF(predictorProb->getSolution()->getDOFVector(i), + geometryProb->getPhasefield(), + predictorProb->getSolution()->getDOFVector(i), + new Mult<double>); + } + } + tau = 0.1; + +}; + + +void NavierStokesPhase_Chorin::fillOperators() +{ FUNCNAME("NavierStokesPhase_Chorin::fillOperators()"); + MSG_DBG("NavierStokesPhase_Chorin::fillOperators()\n"); + + WorldVector<DOFVector<double>* > vel; + for (unsigned i = 0; i < dim; i++) + vel[i]= correctorProb->getSolution()->getDOFVector(i); + + // fill operators for predictorProb + for (unsigned i = 0; i < dim; ++i) { + /// < (1/tau)*u'_i , psi > + Operator *opTime = new Operator(predictorProb->getFeSpace(i), predictorProb->getFeSpace(i)); + opTime->addZeroOrderTerm(new Phase_ZOT(geometryProb->getPhasefield())); + predictorProb->addMatrixOperator(*opTime, i, i, getInvTau()); + /// < (1/tau)*u_i^old , psi > + opTime->setUhOld(correctorProb->getSolution()->getDOFVector(i)); + predictorProb->addVectorOperator(*opTime, i, getInvTau()); + + // boundary condition: u=0 on Gamma + /// < (beta/eps^3)*(1-phi)*u'_i , psi > + Operator *bound0 = new Operator(predictorProb->getFeSpace(i), predictorProb->getFeSpace(i)); + bound0->addTerm(new PhaseInverse_ZOT( + geometryProb->getPhasefield(), + epsPhase2)); + predictorProb->addMatrixOperator(*bound0, i, i); + bound0->setUhOld(boundaryDOF[i]); + predictorProb->addVectorOperator(*bound0, i); + + if (nonLinTerm == 0) { + /// < phi*u^old*grad(u_i^old) , psi > + Operator *opUGradU = new Operator(predictorProb->getFeSpace(i), predictorProb->getFeSpace(i)); + opUGradU->addTerm(new WorldVecPhase_FOT(geometryProb->getPhasefield(), vel, -1.0), GRD_PHI); + opUGradU->setUhOld(correctorProb->getSolution()->getDOFVector(i)); + predictorProb->addVectorOperator(*opUGradU, i); + } else if (nonLinTerm == 1) { + /// < phi*u'*grad(u_i^old) , psi > + for (unsigned j = 0; j < dim; ++j) { + Operator *opUGradU = new Operator(predictorProb->getFeSpace(i),predictorProb->getFeSpace(i)); + opUGradU->addTerm(new VecAndPartialDerivative_ZOT( + geometryProb->getPhasefield(), + correctorProb->getSolution()->getDOFVector(i), j)); + predictorProb->addMatrixOperator(*opUGradU, i, j); + } + } else { + /// < phi*u^old*grad(u'_i) , psi > + for (unsigned j = 0; j < dim; ++j) { + Operator *opUGradU = new Operator(predictorProb->getFeSpace(i),predictorProb->getFeSpace(i)); + opUGradU->addTerm(new Vec2ProductPartial_FOT( + geometryProb->getPhasefield(), + correctorProb->getSolution()->getDOFVector(j), + j), GRD_PHI); + predictorProb->addMatrixOperator(*opUGradU, i, i); + } + } + + /// Diffusion-Operator (including Stress-Tensor for space-dependent viscosity + addLaplaceTerm(i); + + /// < p , d_i(psi) > TODO: Add boundary-integral for neumann-boundary + Operator *opGradP2 = new Operator(predictorProb->getFeSpace(i),pressureProb->getFeSpace(0)); + opGradP2->addFirstOrderTerm(new VecAndPartialDerivative_FOT(geometryProb->getPhasefield(), i, -1.0), GRD_PHI); + opGradP2->setUhOld(pressureProb->getSolution()->getDOFVector(0)); + predictorProb->addVectorOperator(*opGradP2, i, getPressureStep()); + + + /// external force, i.e. gravitational force + if (norm(force) > DBL_TOL) { + Operator *opForce = new Operator(predictorProb->getFeSpace(i), predictorProb->getFeSpace(i)); + opForce->addZeroOrderTerm(new Phase_ZOT(geometryProb->getPhasefield(),force[i])); + predictorProb->addVectorOperator(*opForce, i); + } + } + + // preassure-calculation: tau*div(phi*grad(p)) = div(phi*u')-grad(phi)*g + // --------------------------------------------------------------------- + for(unsigned i = 0; i < dim; ++i) { + /// < (1/tau)*phi*d_i(u'_i) , psi > + Operator *opDivU = new Operator(pressureProb->getFeSpace(0),predictorProb->getFeSpace(i)); + opDivU->addTerm(new VecAndPartialDerivative_ZOT( + geometryProb->getPhasefieldDisturbed(), + predictorProb->getSolution()->getDOFVector(i),i)); + pressureProb->addVectorOperator(opDivU,0); + /// < 1/tau*d_i(phi)*u'_i , psi > + Operator *gradPhiU = new Operator(pressureProb->getFeSpace(0), predictorProb->getFeSpace(i)); + gradPhiU->addTerm(new VecAndPartialDerivative_ZOT( + predictorProb->getSolution()->getDOFVector(i), + geometryProb->getPhasefieldDisturbed(),i)); + pressureProb->addVectorOperator(gradPhiU,0); + /// < 1/tau*d_i(phi)*g , psi > + Operator *gradPhiG = new Operator(pressureProb->getFeSpace(0), predictorProb->getFeSpace(i)); + gradPhiG->addTerm(new VecAndPartialDerivative_ZOT( + boundaryDOF[i], + geometryProb->getPhasefieldDisturbed(),i,-1.0)); + pressureProb->addVectorOperator(gradPhiG,0); + } + /// < -grad(p) , grad(psi) > + Operator *laplaceP = new Operator(pressureProb->getFeSpace(0), pressureProb->getFeSpace(0)); + laplaceP->addSecondOrderTerm(new Phase_SOT(geometryProb->getPhasefieldDisturbed(), -1.0)); + pressureProb->addMatrixOperator(*laplaceP, 0, 0, getTau()); + + // corrector step: u = u' - tau*grad(p) + // --------------------------------------- + for(unsigned i = 0; i < dim; ++i) { + /// < u_i , psi > + Operator *opSimple = new Operator(correctorProb->getFeSpace(i),correctorProb->getFeSpace(i)); + opSimple->addZeroOrderTerm(new Simple_ZOT); + correctorProb->addMatrixOperator(*opSimple, i, i); + /// < u'_i , psi > + opSimple->setUhOld(predictorProb->getSolution()->getDOFVector(i)); + correctorProb->addVectorOperator(*opSimple, i); + /// < -tau*d_i(p) , psi > + Operator *opGradQ = new Operator(correctorProb->getFeSpace(i),pressureProb->getFeSpace(0)); + opGradQ->addFirstOrderTerm(new PartialDerivative_FOT(i, -1.0), GRD_PHI); + opGradQ->setUhOld(pressureProb->getSolution()->getDOFVector(0)); + correctorProb->addVectorOperator(*opGradQ, i, getTau()); + } +}; + + +void NavierStokesPhase_Chorin::addLaplaceTerm(int i) +{ + MSG_DBG("NavierStokesPhase_Chorin::addLaplaceTerm()\n"); + /// < alpha*[grad(u)+grad(u)^t] , grad(psi) > + if (laplaceType == 1) { + for (unsigned j = 0; j < dim; ++j) { + Operator *opLaplaceUi1 = new Operator(predictorProb->getFeSpace(i), predictorProb->getFeSpace(j)); + opLaplaceUi1->addSecondOrderTerm(new MatrixIJPhase_SOT(geometryProb->getPhasefield(), 1-i, 1-j, viscosity)); + predictorProb->addMatrixOperator(*opLaplaceUi1, i, j); + } + } + + /// < alpha*grad(u'_i) , grad(psi) > + Operator *opLaplaceUi = new Operator(predictorProb->getFeSpace(i), predictorProb->getFeSpace(i)); + opLaplaceUi->addSecondOrderTerm(new Phase_SOT(geometryProb->getPhasefield(), viscosity)); + predictorProb->addMatrixOperator(*opLaplaceUi, i, i); + +// Operator *opLaplaceUi_mod = new Operator(predictorProb->getFeSpace(i), predictorProb->getFeSpace(i)); +// opLaplaceUi_mod->addFirstOrderTerm(new VectorGradient_FOT(geometryProb->getPhasefield(), new Factor<WorldVector<double> >(viscosity))); +// predictorProb->addMatrixOperator(*opLaplaceUi_mod, i, i); +}; + + +void NavierStokesPhase_Chorin::fillBoundaryConditions() +{ FUNCNAME("NavierStokesPhase_Chorin::fillBoundaryConditions()"); + MSG_DBG("NavierStokesPhase_Chorin::fillBoundaryConditions()\n"); + + DOFVector<double> *zeroDOF = new DOFVector<double>(predictorProb->getFeSpace(0), "zero"); + zeroDOF->set(0.0); + + /// at rigid wall: no-slip boundary condition + for (unsigned j = 0; j < dim; ++j) { + predictorProb->addDirichletBC(LINKS, j, j, zeroDOF); + predictorProb->addDirichletBC(RECHTS, j, j, zeroDOF); + } + + /// at inflow: prescribed velocity + for (unsigned j = 0; j < dim; ++j) { + predictorProb->addDirichletBC(UNTEN, j, j, boundaryDOF[j]); + //predictorProb->addDirichletBC(OBEN, j, j, boundaryDOF[j]); /// test: Dirichlet-BC at outflow boundary + } + + /// at outflow: constant pressure + pressureProb->addDirichletBC(UNTEN, 0,0, zeroDOF); + pressureProb->addDirichletBC(OBEN, 0,0, zeroDOF); + + + /// boundaryManager wird von Diagonale kopiert, wenn MatrixOperator hinzugefuegt wird -> erst MatrixOperatoren, danach erst BoundaryOperatoren +// for (unsigned i = 0; i < dim; ++i) { +// for (unsigned j = 0; j < dim; ++j) { +// Operator *opLaplaceBoundary = new Operator(predictorProb->getFeSpace(i), predictorProb->getFeSpace(j)); +// opLaplaceBoundary->addFirstOrderTerm(new ViscosityPartialDerivativeBoundary_FOT( +// chProb.getSolution()->getDOFVector(0), i, j, viscosity1, viscosity2), GRD_PHI); +// for (unsigned b= 0; b < nsNeumannBC.size(); ++b) { +// if (nsNeumannBC[b] != 0) { +// predictorProb->addBoundaryMatrixOperator(nsNeumannBC[b], opLaplaceBoundary, i, j); +// } +// } +// } +// } +}; + + +void NavierStokesPhase_Chorin::initTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokesPhase_Chorin::initTimestep()"); + MSG_DBG("NavierStokesPhase_Chorin::initTimestep()\n"); + + if (adaptInfo->getTimestepNumber() > 1) { + WorldVector<DOFVector<double>* > gradPressure; + for (int i = 0; i < gradPressure.getSize(); ++i) + gradPressure[i] = new DOFVector<double>(correctorProb->getFeSpace(0), "gradPressure_i"); + DOFVector<WorldVector<double> > gradPressure_temp(correctorProb->getFeSpace(0), "gradPressure"); + + pressureProb->getSolution()->getDOFVector(0)->getRecoveryGradient(&gradPressure_temp); + transform(&gradPressure_temp, &gradPressure); + + for (int i = 0; i < gradPressure.getSize(); ++i) { + transformDOF(predictorProb->getExactSolution(i), + gradPressure[i], + boundaryDOF[i], new AddFactor<double>(*getTau())); + transformDOF(boundaryDOF[i], + geometryProb->getPhasefield(), + boundaryDOF[i], new Mult<double>); + } + + // delete garbage + for(int i= 0; i<gradPressure.getSize(); ++i) + delete gradPressure[i]; + } +}; + + +void NavierStokesPhase_Chorin::closeTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokesPhase_Chorin::closeTimestep()"); + MSG_DBG("NavierStokesPhase_Chorin::closeTimestep()\n"); + + for (int i = 0; i < correctorProb->getNumComponents(); ++i) { + transformDOF(correctorProb->getSolution()->getDOFVector(0), + geometryProb->getPhasefield(), + correctorProb->getSolution()->getDOFVector(0), new Mult<double>); + } + + int outputPeriod = 1; + Initfile::get("user parameter->write every ith timestep", outputPeriod); + if (adaptInfo->getTimestepNumber() % outputPeriod == 0 + && adaptInfo->getStartTime() < adaptInfo->getEndTime()) { + writeFiles(adaptInfo, false); + } +}; + diff --git a/extensions/base_problems/NavierStokesPhase_Chorin.h b/extensions/base_problems/NavierStokesPhase_Chorin.h new file mode 100644 index 0000000000000000000000000000000000000000..4900a6b5d36c2446373fb6a5bf84867f57db3126 --- /dev/null +++ b/extensions/base_problems/NavierStokesPhase_Chorin.h @@ -0,0 +1,72 @@ +/** \file NavierStokesPhase_Chorin.h */ + +#ifndef NAVIER_STOKES_PHASE_CHORIN_H +#define NAVIER_STOKES_PHASE_CHORIN_H + +#include "MyGlobal.h" +#include "NavierStokes_Chorin.h" +#include "Helpers.h" +#include "POperators.h" +#include "BoundaryFunctions.h" +#include "Refinement.h" +#include "MeshFunction_Level.h" +#include "MyFileWriter.h" +#include "DiffuseDomain.h" +#include <boost/numeric/mtl/mtl.hpp> +#include <boost/numeric/mtl/utility/property_map.hpp> + + +#define LINKS 1 +#define RECHTS 2 +#define UNTEN 3 +#define OBEN 4 + +using namespace AMDiS; + +/** \ingroup NavierStokesPhase_Chorin + * \brief + * Navier-Stokes problem in diffuse domain, using projection method { + * a.) Burgers equation (predictortProb) + * b.) Pressure Poisson problem + * c.) Burgers equation including pressure (predictorProb) + * d.) Pressure Poisson problem + * e.) Velocity update (correctorProb) + * } + */ +class NavierStokesPhase_Chorin : public NavierStokes_Chorin +{ +public: // typedefs + + typedef NavierStokes_Chorin super; + +public: // methods + + NavierStokesPhase_Chorin(const std::string &name_, WorldVector<AbstractFunction<double, WorldVector<double> >* > initialVelocityFcts_, DiffuseDomain* geometryProb); + + virtual void solveInitialProblem(AdaptInfo *adaptInfo); + + /// Implementation of ProblemTimeInterface::initTimestep(). + virtual void initTimestep(AdaptInfo *adaptInfo); + + /// Implementation of ProblemTimeInterface::closeTimestep(). + virtual void closeTimestep(AdaptInfo *adaptInfo); + +protected: // methods + + virtual void fillOperators(); + virtual void fillBoundaryConditions(); + + virtual void addLaplaceTerm(int i); + +protected: // variables + + DiffuseDomain *geometryProb; + MyFileWriter *writer; + + double beta; + double epsPhase2; + +private: + +}; +#endif // NAVIER_STOKES_CHORIN_H diff --git a/extensions/base_problems/NavierStokesPhase_TaylorHood.cc b/extensions/base_problems/NavierStokesPhase_TaylorHood.cc new file mode 100644 index 0000000000000000000000000000000000000000..b0350dad243d546b1b2b2ed66d7bf69cb28e462a --- /dev/null +++ b/extensions/base_problems/NavierStokesPhase_TaylorHood.cc @@ -0,0 +1,219 @@ +#include "NavierStokesPhase_TaylorHood.h" + +using namespace std; +using namespace AMDiS; + +NavierStokesPhase_TaylorHood::NavierStokesPhase_TaylorHood(const std::string &name_) : + super(name_), + phase(NULL), + bcFct(NULL), + beta(1.0), + epsilon(1.e-1), + alpha(3.0), + fileWriterPhase(NULL) +{ + for (int i = 0; i < bcDOF.getSize(); ++i) + bcDOF[i] = NULL; + + Parameters::get(name + "->beta", beta); + Parameters::get(name + "->epsilon", epsilon); + Parameters::get(name + "->alpha", alpha); + +}; + +NavierStokesPhase_TaylorHood::~NavierStokesPhase_TaylorHood() +{ + if (fileWriterPhase != NULL) + delete fileWriterPhase; +} + +void NavierStokesPhase_TaylorHood::initData() +{ + super::initData(); + phaseOld = new DOFVector<double>(getFeSpace(0), "phaseOld"); + + dbc_factor = beta/pow(epsilon, alpha); + MSG_DBG("dbc_factor = %f\n", dbc_factor); +} + + +void NavierStokesPhase_TaylorHood::transferInitialSolution(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokesPhase_TaylorHood::transferInitialSolution()"); + + fileWriterPhase = new FileWriter(name + "->phase->output", getFeSpace()->getMesh(), phase); + for (int i = 0; i < dow; i++) + transformDOF(prob->getSolution()->getDOFVector(0), phase, prob->getSolution()->getDOFVector(0), new AMDiS::Mult<double>); + + super::transferInitialSolution(AdaptInfo *adaptInfo); + phaseOld->interpol(phase); +} + + +void NavierStokesPhase_TaylorHood::closeTimestep(AdaptInfo *adaptInfo) +{ + super::closeTimestep(adaptInfo); + + phaseOld->interpol(phase); + fileWriterPhase->writeFiles(adaptInfo, false); +} + + +void NavierStokesPhase_TaylorHood::fillOperators() +{ FUNCNAME("NavierStokesPhase_TaylorHood::fillOperators()"); + + WorldVector<DOFVector<double>* > vel; + for (size_t i = 0; i < dow; i++) + vel[i] = prob->getSolution()->getDOFVector(i); + + TEST_EXIT(phase!=NULL && phaseOld!=NULL)("PhaseField is not set!\n"); + + // fill operators for prob + for (size_t i = 0; i < dow; ++i) { + /// < (1/tau)*u'_i , psi > + Operator *opTime = new Operator(prob->getFeSpace(i), prob->getFeSpace(i)); + opTime->addTerm(new Phase_ZOT(phase, density)); + prob->addMatrixOperator(*opTime, i, i, getInvTau()); + /// < (1/tau)*u_i^old , psi > + Operator *opTimeOld = new Operator(prob->getFeSpace(i), prob->getFeSpace(i)); + opTimeOld->addTerm(new Phase_ZOT(phaseOld, density)); + opTimeOld->setUhOld(prob->getSolution()->getDOFVector(i)); + prob->addVectorOperator(*opTimeOld, i, getInvTau()); + + /// < u^old*grad(u_i^old) , psi > + Operator *opUGradU0 = new Operator(prob->getFeSpace(i),prob->getFeSpace(i)); + opUGradU0->addTerm(new WorldVecPhase_FOT(phase,vel, -density), GRD_PHI); + opUGradU0->setUhOld(prob->getSolution()->getDOFVector(i)); + if (nonLinTerm == 0) { + prob->addVectorOperator(*opUGradU0, i); + } else { + prob->addVectorOperator(*opUGradU0, i, &theta1); + } + + if (nonLinTerm == 1) { + /// < u'*grad(u_i^old) , psi > + for (unsigned j = 0; j < dow; ++j) { + Operator *opUGradU1 = new Operator(prob->getFeSpace(i),prob->getFeSpace(i)); + opUGradU1->addTerm(new VecAndPartialDerivative_ZOT( + phase, + prob->getSolution()->getDOFVector(i), j, density)); + prob->addMatrixOperator(*opUGradU1, i, j, &theta); + } + } else if (nonLinTerm == 2) { + /// < u^old*grad(u'_i) , psi > + for(unsigned j = 0; j < dow; ++j) { + Operator *opUGradU2 = new Operator(prob->getFeSpace(i),prob->getFeSpace(i)); + opUGradU2->addTerm(new Vec2ProductPartial_FOT( + phase, + prob->getSolution()->getDOFVector(j), j, density), GRD_PHI); + prob->addMatrixOperator(*opUGradU2, i, i, &theta); + } + } + + /// Diffusion-Operator (including Stress-Tensor for space-dependent viscosity + addLaplaceTerm(i); + + /// < p , d_i(psi) > + Operator *opGradP = new Operator(prob->getFeSpace(i),prob->getFeSpace(dow)); + opGradP->addTerm(new VecAndPartialDerivative_FOT(phase,i, -1.0), GRD_PSI); + prob->addMatrixOperator(*opGradP, i, dow); + Operator *opGradP2 = new Operator(prob->getFeSpace(i),prob->getFeSpace(dow)); + opGradP2->addTerm(new PartialDerivative_ZOT(phase,i, -1.0)); + prob->addMatrixOperator(*opGradP2, i, dow); + + /// external force, i.e. gravitational force + if (norm(force) > DBL_TOL) { + Operator *opForce = new Operator(prob->getFeSpace(i), prob->getFeSpace(i)); + opForce->addTerm(new Phase_ZOT(phase,force[i])); + prob->addVectorOperator(*opForce, i); + } + } + + /// div(u) = grad(phi)*g + for (size_t i = 0; i < dow; ++i) { + /// < d_i(u'_i) , psi > + Operator *opDivU = new Operator(prob->getFeSpace(dow),prob->getFeSpace(i)); + opDivU->addTerm(new VecAndPartialDerivative_FOT(phase,i), GRD_PHI); + prob->addMatrixOperator(*opDivU, dow, i); + Operator *opDivU2 = new Operator(prob->getFeSpace(dow),prob->getFeSpace(i)); + opDivU2->addTerm(new PartialDerivative_ZOT(phase,i)); + prob->addMatrixOperator(*opDivU2, dow, i); + } +} + + +void NavierStokesPhase_TaylorHood::addLaplaceTerm(int i) +{ FUNCNAME("NavierStokesPhase_TaylorHood::addLaplaceTerm()"); + + /// < alpha*[grad(u)+grad(u)^t] , grad(psi) > + if (laplaceType == 1) { + for (unsigned j = 0; j < dow; ++j) { + Operator *opLaplaceUi1 = new Operator(prob->getFeSpace(i), prob->getFeSpace(j)); + opLaplaceUi1->addTerm(new MatrixIJPhase_SOT(phase, 1-i, 1-j, viscosity)); + prob->addMatrixOperator(*opLaplaceUi1, i, j, &theta); + + opLaplaceUi1->setUhOld(prob->getSolution()->getDOFVector(j)); + prob->addVectorOperator(*opLaplaceUi1, i, &minusTheta1); + } + } + + /// < alpha*grad(u'_i) , grad(psi) > + Operator *opLaplaceUi = new Operator(prob->getFeSpace(i), prob->getFeSpace(i)); + opLaplaceUi->addTerm(new Phase_SOT(phase, viscosity)); + prob->addMatrixOperator(*opLaplaceUi, i, i, &theta); + + opLaplaceUi->setUhOld(prob->getSolution()->getDOFVector(i)); + prob->addVectorOperator(*opLaplaceUi, i, &minusTheta1); +} + + +void NavierStokesPhase_TaylorHood::fillBoundaryConditions() +{ FUNCNAME("NavierStokesPhase_TaylorHood::fillBoundaryConditions()"); + + for (size_t i = 0; i < dow; ++i) { + /// dirichlet boundary condition + /// beta/eps^alpha (1-phase)*(u_i - g_i) + Operator *opDbcPhaseInvU = new Operator(prob->getFeSpace(i), prob->getFeSpace(i)); + opDbcPhaseInvU->addTerm(new Simple_ZOT(dbc_factor)); + opDbcPhaseInvU->addTerm(new Phase_ZOT(phase, -dbc_factor)); + prob->addMatrixOperator(*opDbcPhaseInvU, i, i); + + if (bcDOF[i] != NULL) { + opDbcPhaseInvU->setUhOld(bcDOF[i]); + prob->addVectorOperator(*opDbcPhaseInvU, i); + } else if (bcFct != NULL) { + Operator *opDbcPhaseInvG = new Operator(prob->getFeSpace(i)); + opDbcPhaseInvG->addTerm(new CoordsAtQP_ZOT(new ComponentExtractor(bcFct, i, dbc_factor))); + opDbcPhaseInvG->addTerm(new VecAndCoordsAtQP_ZOT(phase, new VecAndComponentExtractor(bcFct, i, -dbc_factor))); + prob->addVectorOperator(*opDbcPhaseInvG, i); + } + } + + /// < grad(phi)*G , psi > + if (bcDOF[0] != NULL) { + Operator *opGradPhiG = new Operator(prob->getFeSpace(dow),prob->getFeSpace(0)); + opGradPhiG->addTerm(new WorldVec_FOT(bcDOF), GRD_PHI); + opGradPhiG->setUhOld(phase); + prob->addVectorOperator(*opGradPhiG, dow); + } + + /// < grad(phi)*G(x) , psi > + if (bcFct != NULL) { + Operator *opGradPhiG = new Operator(prob->getFeSpace(dow),prob->getFeSpace(0)); + opGradPhiG->addTerm(new VecFctAtQP_FOT(bcFct), GRD_PHI); + opGradPhiG->setUhOld(phase); + prob->addVectorOperator(*opGradPhiG, dow); + } + + // test for implicit boundary condition + if (bcFct == NULL) { + bool bcCond = false; + for (size_t i = 0; i < dow; i++) + bcCond = bcCond || bcDOF[i] != NULL; + TEST_EXIT(bcCond)("no implicit boundary condition specified!\n"); + } else { + bool bcCond = false; + for (size_t i = 0; i < dow; i++) + bcCond = bcCond || bcDOF[i] != NULL; + TEST_EXIT(!bcCond)("implicit boundary condition specified twice, by bcFct and bcDOF. This is not allowed!\n"); + } +} diff --git a/extensions/base_problems/NavierStokesPhase_TaylorHood.h b/extensions/base_problems/NavierStokesPhase_TaylorHood.h new file mode 100644 index 0000000000000000000000000000000000000000..480fc8273de5b7fb02e694ee9aa0b585e1a1cdcf --- /dev/null +++ b/extensions/base_problems/NavierStokesPhase_TaylorHood.h @@ -0,0 +1,136 @@ +/** \file NavierStokesPhase_TaylorHood.h */ + +#ifndef NAVIER_STOKES_PHASE_TAYLOR_HOOD_H +#define NAVIER_STOKES_PHASE_TAYLOR_HOOD_H + +#include "NavierStokes_TaylorHood.h" + +using namespace AMDiS; + +/** \ingroup NavierStokes_TaylorHood + * \brief + * Navier-Stokes problem in diffuse domain, using Taylor Hood elements + * + * dt(phase*u_j) + phase*u*grad(u_j) = phase*d_j(p) - nu*div(phase*grad(u_j)) - beta/eps^alpha (1-phase)*(u_j - g_j); j=1...d + * div(phase*u) = grad(phase)*g + */ +class NavierStokesPhase_TaylorHood : public NavierStokes_TaylorHood +{ +public: // typedefs + + typedef NavierStokes_TaylorHood super; + +public: // methods + + NavierStokesPhase_TaylorHood(const std::string &name_); + ~NavierStokesPhase_TaylorHood(); + + virtual void initData(); + virtual void transferInitialSolution(AdaptInfo *adaptInfo); + virtual void closeTimestep(AdaptInfo *adaptInfo); + + // === getting/setting methods === + + DOFVector<double> *getPhase() + { + return phase; + } + + DOFVector<double> *getBcDOF(int i) + { + return bcDOF[i]; + } + + AbstractFunction<WorldVector<double>, WorldVector<double> >* getBcFct() + { + return bcFct; + } + + double getEpsilon() + { + return epsilon; + } + + void setPhase(DOFVector<double>* phase_) + { + phase = phase_; + } + + void setBcDOF(DOFVector<double>* bcDOF_i, int i) + { + bcDOF[i] = bcDOF_i; + } + + void setBcFct(AbstractFunction<WorldVector<double>, WorldVector<double> >* fct_) + { + bcFct = fct_; + } + + void setEpsilon(double epsilon_) + { + epsilon = epsilon_; + } + +// protected: // methods + + virtual void fillOperators(); + virtual void fillBoundaryConditions(); + virtual void addLaplaceTerm(int i); + +private: // variables + + double dbc_factor; // beta/epsilon^alpha + double beta; + double epsilon; + double alpha; + + DOFVector<double> *phase; + DOFVector<double> *phaseOld; + + WorldVector<DOFVector<double>*> bcDOF; + AbstractFunction<WorldVector<double>, WorldVector<double> >* bcFct; + + FileWriter *fileWriterPhase; +}; + + +struct ComponentExtractor : AbstractFunction<double, WorldVector<double> > +{ + ComponentExtractor(AbstractFunction<WorldVector<double>, WorldVector<double> >* fct_, int comp_, double factor_=1.0) + : AbstractFunction<double, WorldVector<double> >(fct_->getDegree()), + fct(fct_), + comp(comp_), + factor(factor_) {} + + double operator()(const WorldVector<double>& x) const { + WorldVector<double> result = (*fct)(x); + return factor*result[comp]; + } + +private: + AbstractFunction<WorldVector<double>, WorldVector<double> >* fct; + int comp; + double factor; +}; + + +struct VecAndComponentExtractor : BinaryAbstractFunction<double, double, WorldVector<double> > +{ + VecAndComponentExtractor(AbstractFunction<WorldVector<double>, WorldVector<double> >* fct_, int comp_, double factor_=1.0) + : BinaryAbstractFunction<double, double, WorldVector<double> >(fct_->getDegree()+1), + fct(fct_), + comp(comp_), + factor(factor_) {} + + double operator()(const double& vec, const WorldVector<double>& x) const { + WorldVector<double> result = (*fct)(x); + return factor*vec*result[comp]; + } + +private: + AbstractFunction<WorldVector<double>, WorldVector<double> >* fct; + int comp; + double factor; +}; + +#endif // NAVIER_STOKES_PHASE_TAYLOR_HOOD_H diff --git a/extensions/base_problems/NavierStokes_Chorin.cc b/extensions/base_problems/NavierStokes_Chorin.cc new file mode 100644 index 0000000000000000000000000000000000000000..2547d23dbef28f45e27d192bfa31c367853a62a6 --- /dev/null +++ b/extensions/base_problems/NavierStokes_Chorin.cc @@ -0,0 +1,594 @@ +#include "NavierStokes_Chorin.h" + +#define UPDATE_VELOCITY_SYSTEM + +using namespace std; +using namespace AMDiS; + +NavierStokes_Chorin::NavierStokes_Chorin(const std::string &name_, WorldVector<AbstractFunction<double, WorldVector<double> >* > initialVelocityFcts_) : + ProblemInstatBase(name_,NULL), + initialVelocityFcts(initialVelocityFcts_), + predictorProb(NULL), + pressureProb(NULL), + correctorProb(NULL), + calcPressure(false), + forceDBC(false), + initialVelocityIsSet(false), + oldMeshChangeIdx(0), + nTimesteps(-1), + simpleAlg(2), + poissonPertubation(0), + laplaceType(0), + nonLinTerm(2), + oldTimestep(0.0), + pressureStep(0.0), + viscosity(1.0), + c(0.0) +{ + dim = Global::getGeo(WORLD); + + // create basic problems + predictorProb = new ProblemStatType(name + "->predictor"); + pressureProb = new ProblemStatType(name + "->pressure"); + correctorProb = new ProblemStatType(name + "->corrector"); + + // set Pointer to main problem + nsProb = predictorProb; + + // type of SIMPLE-algorithm + Initfile::get(name + "->simple algorithm",simpleAlg); +// if (simpleAlg < 1 || simpleAlg > 2) +// throw(std::runtime_error("SIMPLE-algorithm: Possible values in {1,2}!")); + + // modification of the neumann-poisson-problem by additional pertubation or + // fixing of one dirichlet-node. Can be set to 0 if other dirichlet BC are set + Initfile::get(name + "->poisson problem pertubation", poissonPertubation); + + // force the homogeniouse dirichlet BC if combination of dirichlet and neumann BC + // are set and AMDiS can not handle this combination automatically + Initfile::get(name + "->force dirichlet bc", forceDBC); + + + // parameters for navier-stokes + Initfile::get(name + "->viscosity", viscosity); + // type of laplace operator: 0... div(nu*grad(u)), 1... div(0.5*nu*(grad(u)+grad(u)^T)) + Initfile::get(name + "->laplace operator", laplaceType); + // type of non-linear term: 0... u^old*grad(u_i^old), 1... u'*grad(u_i^old), 2... u^old*grad(u'_i) + Initfile::get(name + "->non-linear term", nonLinTerm); + + force.set(0.0); + Initfile::get(name + "->force", force, DEBUG_INFO); +}; + + +NavierStokes_Chorin::~NavierStokes_Chorin() +{ FUNCNAME("NavierStokes_Chorin::~NavierStokes_Chorin()"); + + if (calcPressure) + delete pressure; + if (initialVelocityIsSet) { + delete initialX; + delete initialY; + } +}; + + +void NavierStokes_Chorin::initialize( Flag initFlag, + ProblemStatType *adoptProblem, + Flag adoptFlag) +{ FUNCNAME("NavierStokes_Chorin::initialize()"); + + Flag localInitFlag = INIT_ALL - INIT_MESH - CREATE_MESH - INIT_FE_SPACE; + Flag localAdoptFlag = INIT_MESH + INIT_FE_SPACE; + + predictorProb->initialize(initFlag, adoptProblem, adoptFlag); + pressureProb->initialize(localInitFlag, predictorProb, localAdoptFlag); + correctorProb->initialize(localInitFlag, predictorProb, localAdoptFlag); +}; + + +void NavierStokes_Chorin::initTimeInterface() +{ +MSG("NavierStokes_Chorin::initTimeInterface()\n"); + + for (int i = 0; i < boundaryDOF.getSize(); ++i) + boundaryDOF[i] = new DOFVector<double>(predictorProb->getFeSpace(i), "boundary_i"); + + fillOperators(); + fillBoundaryConditions(); +}; + + +void NavierStokes_Chorin::solveInitialProblem(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_Chorin::solveInitialProblem()"); +MSG("NavierStokes_Chorin::solveInitialProblem()\n"); + + if (initialVelocityFcts.size() > 0) { + initialVelocityIsSet = true; + + MSG("interpol initial velocity fcts (%d)...\n",initialVelocityFcts.size()); + for (unsigned i = 0; i < dim; ++i) { + predictorProb->getSolution()->getDOFVector(i)->interpol(initialVelocityFcts[i]); + predictorProb->setExactSolutionFct(initialVelocityFcts[i], i); + } + } + + // initial pressure + MSG("initial pressure...\n"); + pressureProb->getSolution()->getDOFVector(0)->set(0.0); + pressureProb->setExactSolution(pressureProb->getSolution()->getDOFVector(0), 0); + + // initial parameters for detecting mesh changes + MSG("oldMeshChangeIdx...\n"); + oldMeshChangeIdx= predictorProb->getMesh()->getChangeIndex(); + + // calc pressure by normalization and correction of the value + MSG("pressureDOF...\n"); + Initfile::get(name + "->calculate pressure", calcPressure); + if (calcPressure) + pressure= new DOFVector<double>(pressureProb->getFeSpace(0), "pressure"); + + MSG("[finished]\n"); +}; + + +void NavierStokes_Chorin::transferInitialSolution(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_Chorin::transferInitialSolution()"); +MSG("NavierStokes_Chorin::transferInitialSolution()\n"); + + for (unsigned i = 0; i < boundaryDOF.size(); ++i) + boundaryDOF[i]->copy(*predictorProb->getSolution()->getDOFVector(i)); + + if (abs(c) > DBL_TOL) { + INFO(DEBUG_INFO,2)("correct pressure...\n"); + solvePressureProb(adaptInfo); + + INFO(DEBUG_INFO,2)("correct velocity...\n"); + solveCorrectorProb(adaptInfo); + } else + correctorProb->getSolution()->copy(*predictorProb->getSolution()); + + predictorProb->setExactSolution(correctorProb->getSolution()->getDOFVector(0), 0); + predictorProb->setExactSolution(correctorProb->getSolution()->getDOFVector(1), 1); + +// for (unsigned i = 0; i < boundaryDOF.size(); ++i) +// boundaryDOF[i]->copy(*correctorProb->getSolution()->getDOFVector(i)); + + writeFiles(adaptInfo, false); +}; + + +void NavierStokes_Chorin::beginIteration(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_Chorin::beginIteration()"); +MSG("NavierStokes_Chorin::beginIteration()\n"); + + MSG("\n"); + MSG("[[ Navier-Stokes iteration ]]\n"); + + // assemble some blocks only once, if some conditions are fullfilled + #ifdef HAVE_PARALLEL_DOMAIN_AMDIS + bool fixedMatrixCell= false; + #else + bool fixedMatrixCell= adaptInfo->getTimestepNumber() > 0 + && std::abs(adaptInfo->getTimestep() - oldTimestep) < DBL_TOL + && oldMeshChangeIdx == getMesh()->getChangeIndex(); + #endif + for(unsigned i= 0; i < fixedMatrixTimestep.size(); ++i) { + predictorProb->setAssembleMatrixOnlyOnce( + fixedMatrixTimestep[i].first, + fixedMatrixTimestep[i].second, + fixedMatrixCell); + } +}; + + +Flag NavierStokes_Chorin::solvePredictorProb( AdaptInfo *adaptInfo, + Flag toDo, + bool fixedMatrix) +{ FUNCNAME("NavierStokes_Chorin::solvePredictorProb()"); +MSG("NavierStokes_Chorin::solvePredictorProb()\n"); + + Flag markFlag; + + if (toDo.isSet(BUILD)) { + predictorProb->getSolver()->setMultipleRhs(fixedMatrix); + predictorProb->buildAfterCoarsen(adaptInfo, markFlag,!fixedMatrix,true); + } + + if (toDo.isSet(SOLVE)) + predictorProb->solve(adaptInfo); + + return markFlag; +}; + + +Flag NavierStokes_Chorin::solvePressureProb(AdaptInfo *adaptInfo, + Flag toDo, + bool fixedMatrix) +{ FUNCNAME("NavierStokes_Chorin::solvePressureProb()"); + + Flag markFlag; + + if (toDo.isSet(BUILD)) { + pressureProb->getSolver()->setMultipleRhs(fixedMatrix); + pressureProb->buildAfterCoarsen(adaptInfo, markFlag,!fixedMatrix,true); + + SolverMatrix<Matrix<DOFMatrix*> > solverMatrix; + if (!fixedMatrix && poissonPertubation > 0) { + INFO(DEBUG_INFO,2)("apply Matrix Pertubation(%d)...\n", poissonPertubation); + if (poissonPertubation == 1) + applySingularPertubation(pressureProb->getSystemMatrix(0,0)->getBaseMatrix()); + else if (poissonPertubation == 2) { + WorldVector<double> p; + p[0]= 0.0; + p[1]= -1.0; //dimension[1]; + getMesh()->dofCompress(); + DegreeOfFreedom idx; + bool inside = pressureProb->getSolution()->getDOFVector(0)->getDofIdxAtPoint(p, idx); + + if (inside) { + if (pressureProb->getSystemMatrix(0,0) != NULL) + applyDbc(pressureProb->getSystemMatrix(0,0)->getBaseMatrix(), *pressureProb->getRhsVector(0), idx, true, 0.0); + } + } + + solverMatrix.setMatrix(*pressureProb->getSystemMatrix()); + pressureProb->setSolverMatrix(solverMatrix); + } + } + + if (toDo.isSet(SOLVE)) { + pressureProb->solve(adaptInfo); + + if (calcPressure == 1) { + normalizePressure(pressureProb->getSolution()->getDOFVector(0), 0.0); + transformDOF(pressure, + pressureProb->getSolution()->getDOFVector(0), + pressure, new Add<double>); + } + } + + return markFlag; +}; + + +Flag NavierStokes_Chorin::solveCorrectorProb( AdaptInfo *adaptInfo, + Flag toDo, + bool fixedMatrix) +{ FUNCNAME("NavierStokes_Chorin::solveCorrectorProb()"); + + Flag markFlag; + + #if defined UPDATE_VELOCITY_DIRECT + DOFVector<double> *pressure_temp; + if (pressureProb->getFeSpace(0) != correctorProb->getFeSpace(0)) { + INFO(DEBUG_INFO,2)("create new DOFVector for pressure interpolation...\n"); + pressure_temp = new DOFVector<double>(correctorProb->getFeSpace(0), "pressure"); + pressure_temp->interpol(pressureProb->getSolution()->getDOFVector(0)); + } else { + INFO(DEBUG_INFO,2)("use exististing DOFVector for pressure...\n"); + pressure_temp = pressureProb->getSolution()->getDOFVector(0); + } + + WorldVector<DOFVector<double>* > gradPressure; + for (int i = 0; i < gradPressure.getSize(); ++i) + gradPressure[i] = new DOFVector<double>(correctorProb->getFeSpace(0), "gradPressure_i"); + DOFVector<WorldVector<double> > gradPressure_temp(correctorProb->getFeSpace(0), "gradPressure"); + + pressure_temp->getRecoveryGradient(&gradPressure_temp); + // pressure_temp->getGradient(&gradPressure_temp); + INFO(DEBUG_INFO,2)("transform gradient of DOFVector...\n"); + transform(&gradPressure_temp, &gradPressure); + + for (int i = 0; i < gradPressure.getSize(); ++i) { + transformDOF(predictorProb->getSolution()->getDOFVector(i), + gradPressure[i], + correctorProb->getSolution()->getDOFVector(i), new Subtract<double>); + } + + // delete garbage + if(pressureProb->getFeSpace(0)!=correctorProb->getFeSpace(0)) + delete pressure_temp; + for(int i= 0; i<gradPressure.getSize(); ++i) + delete gradPressure[i]; + #else + correctorProb->getSolver()->setMultipleRhs(fixedMatrix); + correctorProb->buildAfterCoarsen(adaptInfo, markFlag,!fixedMatrix,true); + correctorProb->solve(adaptInfo); + #endif + + return markFlag; +}; + + +Flag NavierStokes_Chorin::oneIteration( AdaptInfo *adaptInfo, + Flag toDo) +{ FUNCNAME("NavierStokes_Chorin::oneIteration()"); + + Flag flag, markFlag; + + for (int i = 0; i < simpleAlg; i++) { + MSG("solve predictorProb...\n"); + pressureStep = std::min(1.0, static_cast<double>(i)); + bool fixedMatrixPredictor = adaptInfo->getTimestepNumber() > 0 + && std::abs(adaptInfo->getTimestep() - oldTimestep) < DBL_TOL + && oldMeshChangeIdx == getMesh()->getChangeIndex(); + solvePredictorProb(adaptInfo, toDo, false); + + MSG("solve pressureProb...\n"); + bool fixedMatrixPressure = oldMeshChangeIdx == getMesh()->getChangeIndex(); + solvePressureProb(adaptInfo, toDo, false); + } + + MSG("solve correctorProb...\n"); + bool fixedMatrixCorrector = oldMeshChangeIdx == getMesh()->getChangeIndex(); + solveCorrectorProb(adaptInfo, toDo, false); + + if (calcPressure == 1) + pressureProb->getSolution()->getDOFVector(0)->copy(*pressure); + + oldTimestep= adaptInfo->getTimestep(); + oldMeshChangeIdx= getMesh()->getChangeIndex(); + + return flag; +}; + + +void NavierStokes_Chorin::endIteration(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_Chorin::endIteration()"); + + MSG("\n"); + MSG("[[ end of Navier-Stokes iteration ]]\n"); +}; + + +void NavierStokes_Chorin::clean() +{ FUNCNAME("NavierStokes_Chorin::clean()"); + + // delete problems that are not necessary any more +// Helpers::cleanProblem(predictorProb); +// Helpers::cleanProblem(pressureProb); +// Helpers::cleanProblem(correctorProb, DELETE_ALL - DELETE_SOLUTION); +}; + + +void NavierStokes_Chorin::normalizePressure(DOFVector<double> *p, + double mean) +{ FUNCNAME("NavierStokes_Chorin::normalizePressure()"); + + if (calcPressure != 1) + throw(std::runtime_error("Flag 'calc pressure' must be set to 1!")); + + double intP = -1.0; + double area = 1.0; + + if (!Helpers::isNumber(area) || area <= 0.0) + throw(std::runtime_error("Area must be > 0!\n")); + + int i; + for (i= 0; abs(intP-mean) > 1.e-8 && i < 10; ++i) { + intP= p->Int(); + if (!Helpers::isNumber(intP)) + throw(std::runtime_error("pressureProb containes non-valid values!")); + transformDOF(p,(mean-intP)/area,p, new Add<double>); + } + MSG("normalizePressure... %d steps\n",i+1); +}; + + +void NavierStokes_Chorin::fillOperators() +{ FUNCNAME("NavierStokes_Chorin::fillOperators()"); + MSG("NavierStokes_Chorin::fillOperators()\n"); + + fillPredictorProb(); + fillPressureProb(); + fillCorrectorProb(); +}; + + +void NavierStokes_Chorin::fillPredictorProb() +{ FUNCNAME("NavierStokes_Chorin::fillPredictorProb()"); + MSG("NavierStokes_Chorin::fillPredictorProb()\n"); + + WorldVector<DOFVector<double>* > vel; + for (unsigned i = 0; i < dim; i++) + vel[i]= correctorProb->getSolution()->getDOFVector(i); + + // fill operators for predictorProb + for (unsigned i = 0; i < dim; ++i) { + /// < (1/tau)*u'_i , psi > + Operator *opTime = new Operator(predictorProb->getFeSpace(i), predictorProb->getFeSpace(i)); + opTime->addZeroOrderTerm(new Simple_ZOT); + predictorProb->addMatrixOperator(*opTime, i, i, getInvTau()); + /// < (1/tau)*u_i^old , psi > + opTime->setUhOld(correctorProb->getSolution()->getDOFVector(i)); + predictorProb->addVectorOperator(*opTime, i, getInvTau()); + + if (nonLinTerm == 0) { + /// < u^old*grad(u_i^old) , psi > + Operator *opUGradU = new Operator(predictorProb->getFeSpace(i),predictorProb->getFeSpace(i)); + opUGradU->addFirstOrderTerm(new WorldVec_FOT(vel, -1.0), GRD_PHI); + opUGradU->setUhOld(correctorProb->getSolution()->getDOFVector(i)); + predictorProb->addVectorOperator(*opUGradU, i); + } else if (nonLinTerm == 1) { + /// < u'*grad(u_i^old) , psi > + for (unsigned j = 0; j < dim; ++j) { + Operator *opUGradU = new Operator(predictorProb->getFeSpace(i),predictorProb->getFeSpace(i)); + opUGradU->addZeroOrderTerm(new PartialDerivative_ZOT( + correctorProb->getSolution()->getDOFVector(i), j)); + predictorProb->addMatrixOperator(*opUGradU, i, j); + } + } else { + /// < u^old*grad(u'_i) , psi > + for(unsigned j = 0; j < dim; ++j) { + Operator *opUGradU = new Operator(predictorProb->getFeSpace(i),predictorProb->getFeSpace(i)); + opUGradU->addFirstOrderTerm(new VecAndPartialDerivative_FOT( + correctorProb->getSolution()->getDOFVector(j), j), GRD_PHI); + predictorProb->addMatrixOperator(*opUGradU, i, i); + } + } + + /// Diffusion-Operator (including Stress-Tensor for space-dependent viscosity + addLaplaceTerm(i); + + /// < p , d_i(psi) > TODO: Add boundary-integral for neumann-boundary + Operator *opGradP2 = new Operator(predictorProb->getFeSpace(i),pressureProb->getFeSpace(0)); + opGradP2->addFirstOrderTerm(new PartialDerivative_FOT(i, -1.0), GRD_PHI); + opGradP2->setUhOld(pressureProb->getSolution()->getDOFVector(0)); + predictorProb->addVectorOperator(*opGradP2, i, getPressureStep()); + + /// external force, i.e. gravitational force + if (norm(force) > DBL_TOL) { + Operator *opForce = new Operator(predictorProb->getFeSpace(i), predictorProb->getFeSpace(i)); + opForce->addZeroOrderTerm(new Simple_ZOT(force[i])); + predictorProb->addVectorOperator(*opForce, i); + } + } +}; + + +void NavierStokes_Chorin::fillPressureProb() +{ FUNCNAME("NavierStokes_Chorin::fillPressureProb()"); + MSG("NavierStokes_Chorin::fillPressureProb()\n"); + + // preassure-calculation: div(grad(p)) = 1/tau*div(u') + // ------------------------------------------------------------- + for(unsigned i = 0; i < dim; ++i) { + /// < (1/tau)*d_i(u'_i) , psi > + Operator *opDivU = new Operator(pressureProb->getFeSpace(0),predictorProb->getFeSpace(i)); + opDivU->addZeroOrderTerm(new PartialDerivative_ZOT( + predictorProb->getSolution()->getDOFVector(i), i)); + pressureProb->addVectorOperator(*opDivU, 0, getInvTau()); + } + /// < -grad(p) , grad(psi) > + Operator *laplaceP = new Operator(pressureProb->getFeSpace(0), pressureProb->getFeSpace(0)); + laplaceP->addSecondOrderTerm(new Simple_SOT(-1.0)); + pressureProb->addMatrixOperator(*laplaceP, 0, 0); +}; + + +void NavierStokes_Chorin::fillCorrectorProb() +{ FUNCNAME("NavierStokes_Chorin::fillCorrectorProb()"); + MSG("NavierStokes_Chorin::fillCorrectorProb()\n"); + + // corrector step: u = u' - tau*grad(p) + // --------------------------------------- + for(unsigned i = 0; i < dim; ++i) { + /// < u_i , psi > + Operator *opSimple = new Operator(correctorProb->getFeSpace(i),correctorProb->getFeSpace(i)); + opSimple->addZeroOrderTerm(new Simple_ZOT); + correctorProb->addMatrixOperator(*opSimple, i, i); + /// < u'_i , psi > + opSimple->setUhOld(predictorProb->getSolution()->getDOFVector(i)); + correctorProb->addVectorOperator(*opSimple, i); + /// < -tau*d_i(p) , psi > + Operator *opGradQ = new Operator(correctorProb->getFeSpace(i),pressureProb->getFeSpace(0)); + opGradQ->addFirstOrderTerm(new PartialDerivative_FOT(i, -1.0), GRD_PHI); + opGradQ->setUhOld(pressureProb->getSolution()->getDOFVector(0)); + correctorProb->addVectorOperator(*opGradQ, i, getTau()); + } +}; + + +void NavierStokes_Chorin::addLaplaceTerm(int i) +{ FUNCNAME("NavierStokes_Chorin::addLaplaceTerm()"); + MSG("NavierStokes_Chorin::addLaplaceTerm(%d)\n",i); + + /// < alpha*[grad(u)+grad(u)^t] , grad(psi) > + if (laplaceType == 1) { + for (unsigned j = 0; j < dim; ++j) { + Operator *opLaplaceUi1 = new Operator(predictorProb->getFeSpace(i), predictorProb->getFeSpace(j)); + opLaplaceUi1->addSecondOrderTerm(new MatrixIJ_SOT(1-i, 1-j, viscosity)); + predictorProb->addMatrixOperator(*opLaplaceUi1, i, j); + } + } + + /// < alpha*grad(u'_i) , grad(psi) > + Operator *opLaplaceUi = new Operator(predictorProb->getFeSpace(i), predictorProb->getFeSpace(i)); + opLaplaceUi->addSecondOrderTerm(new Simple_SOT(viscosity)); + predictorProb->addMatrixOperator(*opLaplaceUi, i, i); +}; + + +/// TODO: Boundary-Conditions verallgemeinern +void NavierStokes_Chorin::fillBoundaryConditions() +{ FUNCNAME("NavierStokes_Chorin::fillBoundaryConditions()"); + MSG("NavierStokes_Chorin::fillBoundaryConditions()\n"); + + DOFVector<double> *zeroDOF = new DOFVector<double>(predictorProb->getFeSpace(0), "zero"); + zeroDOF->set(0.0); + + /// at rigid wall: no-slip boundary condition + for (unsigned j = 0; j < dim; ++j) { + predictorProb->addDirichletBC(LINKS, j, j, boundaryDOF[j]); + predictorProb->addDirichletBC(RECHTS, j, j, boundaryDOF[j]); + } + + /// at inflow: prescribed velocity + for (unsigned j = 0; j < dim; ++j) { + predictorProb->addDirichletBC(OBEN, j, j, boundaryDOF[j]); +// predictorProb->addDirichletBC(OBEN, j, j, predictorProb->getExactSolution(j)); /// test: Dirichlet-BC at outflow boundary + } + + /// at outflow: constant pressure + pressureProb->addDirichletBC(UNTEN, 0,0, zeroDOF); +// pressureProb->addDirichletBC(OBEN, 0,0, zeroDOF); + + + /// boundaryManager wird von Diagonale kopiert, wenn MatrixOperator hinzugefuegt wird -> erst MatrixOperatoren, danach erst BoundaryOperatoren +// for (unsigned i = 0; i < dim; ++i) { +// for (unsigned j = 0; j < dim; ++j) { +// Operator *opLaplaceBoundary = new Operator(predictorProb->getFeSpace(i), predictorProb->getFeSpace(j)); +// opLaplaceBoundary->addFirstOrderTerm(new ViscosityPartialDerivativeBoundary_FOT( +// chProb.getSolution()->getDOFVector(0), i, j, viscosity1, viscosity2), GRD_PHI); +// for (unsigned b= 0; b < nsNeumannBC.size(); ++b) { +// if (nsNeumannBC[b] != 0) { +// predictorProb->addBoundaryMatrixOperator(nsNeumannBC[b], opLaplaceBoundary, i, j); +// } +// } +// } +// } +}; + + +void NavierStokes_Chorin::initTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_Chorin::initTimestep()"); + + WorldVector<DOFVector<double>* > gradPressure; + for (int i = 0; i < gradPressure.getSize(); ++i) + gradPressure[i] = new DOFVector<double>(correctorProb->getFeSpace(0), "gradPressure_i"); + DOFVector<WorldVector<double> > gradPressure_temp(correctorProb->getFeSpace(0), "gradPressure"); + + pressureProb->getSolution()->getDOFVector(0)->getRecoveryGradient(&gradPressure_temp); + transform(&gradPressure_temp, &gradPressure); + + for (int i = 0; i < gradPressure.getSize(); ++i) { + transformDOF(predictorProb->getExactSolution(i), + gradPressure[i], + boundaryDOF[i], new AddFactor<double>(*getTau())); + } + + // delete garbage + for(int i= 0; i<gradPressure.getSize(); ++i) + delete gradPressure[i]; +}; + + +void NavierStokes_Chorin::closeTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_Chorin::closeTimestep()"); + + int outputPeriod = 1; + Initfile::get("user parameter->write every ith timestep", outputPeriod, DEBUG_INFO); + if (adaptInfo->getTimestepNumber() % outputPeriod == 0 + && adaptInfo->getStartTime() < adaptInfo->getEndTime()) { + writeFiles(adaptInfo, false); + } +}; + + +void NavierStokes_Chorin::writeFiles(AdaptInfo *adaptInfo, bool force) +{ + predictorProb->writeFiles(adaptInfo, force); + pressureProb->writeFiles(adaptInfo, force); + correctorProb->writeFiles(adaptInfo, force); +}; diff --git a/extensions/base_problems/NavierStokes_Chorin.h b/extensions/base_problems/NavierStokes_Chorin.h new file mode 100644 index 0000000000000000000000000000000000000000..0e3dff2fdff9c0d808b559fa871db90b710bdd0b --- /dev/null +++ b/extensions/base_problems/NavierStokes_Chorin.h @@ -0,0 +1,216 @@ +/** \file NavierStokes_Chorin.h */ + +#ifndef NAVIER_STOKES_CHORIN_H +#define NAVIER_STOKES_CHORIN_H + +#include "MyGlobal.h" +#include "Helpers.h" +#include "POperators.h" +#include "BoundaryFunctions.h" +#include <boost/numeric/mtl/mtl.hpp> +#include <boost/numeric/mtl/utility/property_map.hpp> + + +#define LINKS 1 +#define RECHTS 2 +#define UNTEN 3 +#define OBEN 4 + +using namespace AMDiS; + +/** \ingroup NavierStokes_Chorin + * \brief + * Navier-Stokes problem, using projection method { + * a.) Burgers equation (predictortProb) + * b.) Pressure Poisson problem + * c.) Burgers equation including pressure (predictorProb) + * d.) Pressure Poisson problem + * e.) Velocity update (correctorProb) + * } + */ +class NavierStokes_Chorin : public ProblemIterationInterface, + public ProblemInstatBase +{ +public: + + NavierStokes_Chorin(const std::string &name_, WorldVector<AbstractFunction<double, WorldVector<double> >* > initialVelocityFcts_); + ~NavierStokes_Chorin(); + + /// Initialisation of the problem. + virtual void initialize(Flag initFlag, + ProblemStatType *adoptProblem = NULL, + Flag adoptFlag = INIT_NOTHING); + + virtual void initTimeInterface(); + virtual void solveInitialProblem(AdaptInfo *adaptInfo); + + virtual void transferInitialSolution(AdaptInfo *adaptInfo); + + /// Implementation of ProblemTimeInterface::initTimestep(). + virtual void initTimestep(AdaptInfo *adaptInfo); + + /// Implementation of ProblemTimeInterface::closeTimestep(). + virtual void closeTimestep(AdaptInfo *adaptInfo); + + virtual void beginIteration(AdaptInfo *adaptInfo); + virtual Flag oneIteration(AdaptInfo *adaptInfo, Flag toDo= FULL_ITERATION); + virtual void endIteration(AdaptInfo *adaptInfo); + + void clean(); + + // === getting methods === + + SystemVector *getSolution() + { + return correctorProb->getSolution(); + } + + double* getPressureStep() { return &pressureStep; } + + inline Mesh* getMesh(int comp = 0) + { FUNCNAME("NavierStokes_Chorin::getMesh()"); + + return predictorProb->getMesh(comp); + } + + std::string getName() { return name; }; + + int getNumProblems() { return 3; }; + + ProblemStatType *getProblem(int number= 0) + { FUNCNAME("NavierStokes_Chorin::getProblem()"); + + if (number == 0) + return predictorProb; + else if (number == 1) + return pressureProb; + else if (number == 2) + return correctorProb; + else + throw(std::runtime_error("problem with given number does not exist")); + }; + + ProblemStatType *getProblem(std::string name) + { FUNCNAME("NavierStokes_Chorin::getProblem()"); + + if (name == "correctorProb") + return correctorProb; + else if (name == "predictorProb") + return predictorProb; + else if (name == "pressureProb") + return pressureProb; + else + throw(std::runtime_error("problem with given name '" + name + "' does not exist")); + }; + + /// setting methods + + void setAssembleMatrixOnlyOnce_butTimestepChange(int i, int j) + { FUNCNAME("NavierStokes_Chorin::setAssembleMatrixOnlyOnce_butTimestepChange()"); + + fixedMatrixTimestep.push_back(std::make_pair(i,j)); + } + + void setNumberOfTimesteps(int nTimesteps_) + { FUNCNAME("NavierStokes_Chorin::setNumberOfTimesteps()"); + + nTimesteps= nTimesteps_; + } + + void writeFiles(AdaptInfo *adaptInfo, bool force); + void serialize(std::ostream&) {}; + void deserialize(std::istream&) {}; + +protected: + + virtual Flag solvePredictorProb(AdaptInfo *adaptInfo, Flag toDo = FULL_ITERATION, bool fixedMatrix = false); + virtual Flag solvePressureProb(AdaptInfo *adaptInfo, Flag toDo = FULL_ITERATION, bool fixedMatrix = false); + virtual Flag solveCorrectorProb(AdaptInfo *adaptInfo, Flag toDo = FULL_ITERATION, bool fixedMatrix = false); + + virtual void fillOperators(); + virtual void fillBoundaryConditions(); + + virtual void fillPredictorProb(); + virtual void fillPressureProb(); + virtual void fillCorrectorProb(); + virtual void addLaplaceTerm(int i); + +private: + + void normalizePressure(DOFVector<double> *p, double mean); + + template <typename Matrix> + void applySingularPertubation(Matrix& m) + { + using namespace mtl; + typedef typename mtl::Collection<Matrix>::value_type value_type; + int nnz= m.nnz_local(m.num_rows() - 1); + matrix::inserter<Matrix, update_times<value_type> > ins(m, nnz); + + ins[m.num_rows() - 1][m.num_rows() - 1] << 1.0 + 1.e-5; + } + + + template <typename Matrix, typename Vector> + void applyDbc(Matrix& m, Vector& vec, DegreeOfFreedom idx, bool setDiagonal, double value) + { + using namespace mtl; + typename Matrix::size_type idx_= idx; + + typename traits::row<Matrix>::type r(m); + typename traits::col<Matrix>::type c(m); + typename traits::value<Matrix>::type v(m); + typedef typename traits::range_generator<tag::row, Matrix>::type c_type; + typedef typename traits::range_generator<tag::nz, c_type>::type ic_type; + + for (c_type cursor(begin<tag::row>(m)+idx_), cend(begin<tag::row>(m) + idx_ + 1); cursor != cend; ++cursor) { + for (ic_type icursor(begin<tag::nz>(cursor)), icend(end<tag::nz>(cursor)); icursor != icend; ++icursor) { + v(*icursor, (r(*icursor) == c(*icursor) && setDiagonal ? 1.0 : 0.0)); + } + break; + } + + if (setDiagonal) + vec[idx]= value; + } + +protected: + + ProblemStatType *predictorProb; + ProblemStatType *pressureProb; + ProblemStatType *correctorProb; + + ProblemStatType *nsProb; + + DOFVector<double> *pressure; + WorldVector<DOFVector<double>*> boundaryDOF; + AbstractFunction<double, WorldVector<double> > *initialX, *initialY; + WorldVector<AbstractFunction<double, WorldVector<double> >* > initialVelocityFcts; + WorldVector<DOFVector<double>*> initialVel; + + bool forceDBC; + bool calcPressure; + bool initialVelocityIsSet; + + unsigned dim; + + int simpleAlg; + int nTimesteps; + int oldMeshChangeIdx; + int poissonPertubation; + int laplaceType; + int nonLinTerm; + + double pressureStep; + double oldTimestep; + double viscosity; + double c; + + WorldVector<double> force; + + std::vector<std::pair<int,int> > fixedMatrixTimestep; + +private: + +}; +#endif // NAVIER_STOKES_CHORIN_H diff --git a/extensions/base_problems/NavierStokes_TH_MultiPhase.cc b/extensions/base_problems/NavierStokes_TH_MultiPhase.cc new file mode 100644 index 0000000000000000000000000000000000000000..93509542c5130c403d552d5eb73e58998e9f6303 --- /dev/null +++ b/extensions/base_problems/NavierStokes_TH_MultiPhase.cc @@ -0,0 +1,159 @@ +#include "NavierStokes_TH_MultiPhase.h" + +using namespace std; +using namespace AMDiS; + +NavierStokes_TH_MultiPhase::NavierStokes_TH_MultiPhase(const std::string &name_) : + super(name_), + multiPhase(NULL), + densityPhase(NULL), + viscosityPhase(NULL), + viscosity1(-1.0), + viscosity2(1.0), + density1(1.0), + density2(1.0) +{ + Initfile::get(name + "->viscosity1", viscosity1); // viscosity of fluid 1 + Initfile::get(name + "->viscosity2", viscosity2); // viscosity of fluid 2 + Initfile::get(name + "->density1", density1); // density of fluid 1 + Initfile::get(name + "->density2", density2); // density of fluid 2 + + if (viscosity1 <= 0.0) + viscosity1 = viscosity; +}; + + +NavierStokes_TH_MultiPhase::~NavierStokes_TH_MultiPhase() +{ FUNCNAME("NavierStokes_TH_MultiPhase::~NavierStokes_TH_MultiPhase()"); + + delete multiPhase; + delete densityPhase; + delete viscosityPhase; +}; + + +void NavierStokes_TH_MultiPhase::initData() +{ FUNCNAME("NavierStokes_TH_MultiPhase::initTimeInterface()"); + + multiPhase = new DOFVector<double>(prob->getFeSpace(0), "multiPhase"); + densityPhase = new DOFVector<double>(prob->getFeSpace(0), "densityPhase"); + viscosityPhase = new DOFVector<double>(prob->getFeSpace(0), "viscosityPhase"); + + multiPhase->set(1.0); + densityPhase->set(density1); + viscosityPhase->set(viscosity1); + + super::initData(); +}; + +void NavierStokes_TH_MultiPhase::initTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_TH_MultiPhase::initTimestep()"); + + super::initTimestep(adaptInfo); + + transformDOF(multiPhase, densityPhase, new LinearInterpolation(density1, density2)); + transformDOF(multiPhase, viscosityPhase, new LinearInterpolation(viscosity1, viscosity2)); +}; + + +void NavierStokes_TH_MultiPhase::fillOperators() +{ FUNCNAME("NavierStokes_TH_MultiPhase::fillOperators()"); + + WorldVector<DOFVector<double>* > vel; + for (unsigned i = 0; i < dim; i++) + vel[i]= prob->getSolution()->getDOFVector(i); + + // fill operators for prob + for (unsigned i = 0; i < dim; ++i) { + /// < (1/tau)*rho*u'_i , psi > + Operator *opTime = new Operator(getFeSpace(i), getFeSpace(i)); + opTime->addTerm(new VecAtQP_ZOT(densityPhase, NULL)); + prob->addMatrixOperator(*opTime, i, i, getInvTau(), getInvTau()); + /// < (1/tau)*rho*u_i^old , psi > + Operator *opTimeOld = new Operator(getFeSpace(i), getFeSpace(i)); + opTimeOld->addTerm(new Vec2AtQP_ZOT(densityPhase, prob->getSolution()->getDOFVector(i), NULL)); + prob->addVectorOperator(*opTimeOld, i, getInvTau(), getInvTau()); + + /// < u^old*grad(u_i^old) , psi > + Operator *opUGradU0 = new Operator(getFeSpace(i),getFeSpace(i)); + opUGradU0->addTerm(new WorldVecPhase_FOT(densityPhase, vel, -1.0), GRD_PHI); + opUGradU0->setUhOld(prob->getSolution()->getDOFVector(i)); + if (nonLinTerm == 0) { + prob->addVectorOperator(*opUGradU0, i); + } else { + prob->addVectorOperator(*opUGradU0, i, &theta1, &theta1); + } + + if (nonLinTerm == 1) { + /// < u'*grad(u_i^old) , psi > + for (unsigned j = 0; j < dim; ++j) { + Operator *opUGradU1 = new Operator(getFeSpace(i),getFeSpace(i)); + opUGradU1->addTerm(new VecAndPartialDerivative_ZOT( + densityPhase, + prob->getSolution()->getDOFVector(i), j)); + prob->addMatrixOperator(*opUGradU1, i, j, &theta, &theta); + } + } else if (nonLinTerm == 2) { + /// < u^old*grad(u'_i) , psi > + for(unsigned j = 0; j < dim; ++j) { + Operator *opUGradU2 = new Operator(getFeSpace(i),getFeSpace(i)); + opUGradU2->addTerm(new Vec2ProductPartial_FOT( + densityPhase, + prob->getSolution()->getDOFVector(j), j), GRD_PHI); + prob->addMatrixOperator(*opUGradU2, i, i, &theta, &theta); + } + } + + /// Diffusion-Operator (including Stress-Tensor for space-dependent viscosity + addLaplaceTerm(i); + + /// < p , d_i(psi) > + Operator *opGradP = new Operator(getFeSpace(i),getFeSpace(dim)); + opGradP->addTerm(new PartialDerivative_FOT(i, -1.0), GRD_PSI); + prob->addMatrixOperator(*opGradP, i, dim); + + /// external force, i.e. gravitational force + if (norm(force) > DBL_TOL) { + Operator *opForce = new Operator(getFeSpace(i), getFeSpace(i)); + opForce->addZeroOrderTerm(new Phase_ZOT(densityPhase, force[i])); + prob->addVectorOperator(*opForce, i); + } + } + + /// div(u) = 0 + for (unsigned i = 0; i < dim; ++i) { + /// < d_i(u'_i) , psi > + Operator *opDivU = new Operator(getFeSpace(dim),getFeSpace(i)); + opDivU->addTerm(new PartialDerivative_FOT(i), GRD_PHI); + prob->addMatrixOperator(*opDivU, dim, i); + } +}; + + +void NavierStokes_TH_MultiPhase::addLaplaceTerm(int i) +{ FUNCNAME("NavierStokes_TH_MultiPhase::addLaplaceTerm()"); + + /// < alpha*[grad(u)+grad(u)^t] , grad(psi) > + if (laplaceType == 1) { + for (unsigned j = 0; j < dim; ++j) { + Operator *opLaplaceUi1 = new Operator(getFeSpace(i), getFeSpace(j)); + opLaplaceUi1->addTerm(new VecAtQP_IJ_SOT( + viscosityPhase, NULL, 1-i, 1-j)); + prob->addMatrixOperator(*opLaplaceUi1, i, j, &theta, &theta); + + Operator *opLaplaceUi1_rhs = new Operator(getFeSpace(i), getFeSpace(j)); + opLaplaceUi1_rhs->addTerm(new Vec2AtQP_IJ_SOT( + viscosityPhase, prob->getSolution()->getDOFVector(j), NULL, 1-i, 1-j)); + prob->addVectorOperator(*opLaplaceUi1_rhs, i, &minusTheta1, &minusTheta1); + } + } + + /// < alpha*grad(u'_i) , grad(psi) > + Operator *opLaplaceUi = new Operator(getFeSpace(i), getFeSpace(i)); + opLaplaceUi->addTerm(new VecAtQP_SOT(viscosityPhase, NULL)); + prob->addMatrixOperator(*opLaplaceUi, i, i, &theta, &theta); + + Operator *opLaplaceUi_rhs = new Operator(getFeSpace(i), getFeSpace(i)); + opLaplaceUi_rhs->addTerm(new Vec2AtQP_SOT(viscosityPhase, prob->getSolution()->getDOFVector(i), NULL)); + prob->addVectorOperator(*opLaplaceUi_rhs, i, &minusTheta1, &minusTheta1); +}; diff --git a/extensions/base_problems/NavierStokes_TH_MultiPhase.h b/extensions/base_problems/NavierStokes_TH_MultiPhase.h new file mode 100644 index 0000000000000000000000000000000000000000..780c331f0d3ec73e27634a383000a45852c9e8a3 --- /dev/null +++ b/extensions/base_problems/NavierStokes_TH_MultiPhase.h @@ -0,0 +1,126 @@ +/** \file NavierStokes_TH_MultiPhase.h */ + +#ifndef NAVIER_STOKES_TAYLOR_HOOD_MULTIPHASE_H +#define NAVIER_STOKES_TAYLOR_HOOD_MULTIPHASE_H + +#include "NavierStokes_TaylorHood.h" + +#define LINKS 1 +#define RECHTS 2 +#define UNTEN 3 +#define OBEN 4 + +using namespace AMDiS; + +/** \ingroup NavierStokes_TaylorHood + * \brief + * Navier-Stokes multi-phase problem, using Taylor Hood elements + * Standard implementation for two phases, but can be extended to + * many more, by defining the multiPhase variable and overloading + * the initTimestep, where densityPhase and viscosityPhase are defined + * depending on the phases + */ +class NavierStokes_TH_MultiPhase : public NavierStokes_TaylorHood +{ +public: // typedefs + + typedef NavierStokes_TaylorHood super; + +public: // methods + + NavierStokes_TH_MultiPhase(const std::string &name_); + + /// deletes multiPhase, viscosityPhase and densityPhase + ~NavierStokes_TH_MultiPhase(); + + /** definition of constant multiPhase and const + * viscosity/density DOFVectors, + * initTimeInterface of super + **/ + virtual void initData(); + + /** initTimestep of super and + * initialization of densityPhase and viscosityPhase + **/ + virtual void initTimestep(AdaptInfo *adaptInfo); + + /** pointer to the multiPhase DOFVector, that + * indicates the different phases. Will be initialized + * in \ref initTimeInterface with const 1 + **/ + DOFVector<double> *getMultiPhase() { return multiPhase; } + +protected: // methods + + virtual void fillOperators(); + virtual void addLaplaceTerm(int i); + +protected: // variables + + ///viscosity of phase 1 + double viscosity1; + + ///viscosity of phase 2 + double viscosity2; + + ///density of phase 1 + double density1; + + ///density of phase 2 + double density2; + + /// phase dependent density + DOFVector<double> *densityPhase; + + /// phase dependent viscosity + DOFVector<double> *viscosityPhase; + + /// phase inticator + DOFVector<double> *multiPhase; + +}; + + +/** linear interpolation between two values (like density, viscosity) + * using a phase-field variable in [-1,1] + **/ +class LinearInterpolation : public AbstractFunction<double, double> +{ +public: + + LinearInterpolation(double val1_, double val2_) : + AbstractFunction<double, double>(1), + val1(val1_), val2(val2_) {} + + double operator()(const double &phase) const { + return 0.5*(phase+1.0)*val1 - 0.5*(phase-1.0)*val2; + } + +private: + + double val1; + double val2; +}; + +/** linear interpolation between two values (like density, viscosity) + * using a phase-field variable in [0,1] + **/ +class LinearInterpolation0 : public AbstractFunction<double, double> +{ +public: + + LinearInterpolation0(double val1_, double val2_) : + AbstractFunction<double, double>(1), + val1(val1_), val2(val2_) {} + + double operator()(const double &phase) const { + return phase*val1 + (1.0-phase)*val2; + } + +private: + + double val1; + double val2; +}; + +#endif // NAVIER_STOKES_TAYLOR_HOOD_MULTIPHASE_H diff --git a/extensions/base_problems/NavierStokes_TH_MultiPhase_RB.cc b/extensions/base_problems/NavierStokes_TH_MultiPhase_RB.cc new file mode 100644 index 0000000000000000000000000000000000000000..aaeee0fbf7486b36dfc6225d485f23f244b8a101 --- /dev/null +++ b/extensions/base_problems/NavierStokes_TH_MultiPhase_RB.cc @@ -0,0 +1,151 @@ +#include "NavierStokes_TH_MultiPhase_RB.h" + +using namespace std; +using namespace AMDiS; + +NavierStokes_TH_MultiPhase_RB::NavierStokes_TH_MultiPhase_RB(const std::string &name_) : + super(name_), + multiPhase(NULL), + densityPhase(NULL), + viscosityPhase(NULL), + viscosity1(-1.0), + viscosity2(1.0), + density1(1.0), + density2(1.0) +{ + Initfile::get(name + "->viscosity1", viscosity1); // viscosity of fluid 1 + Initfile::get(name + "->viscosity2", viscosity2); // viscosity of fluid 2 + Initfile::get(name + "->density1", density1); // density of fluid 1 + Initfile::get(name + "->density2", density2); // density of fluid 2 + + if (viscosity1 <= 0.0) + viscosity1 = viscosity; +}; + + +NavierStokes_TH_MultiPhase_RB::~NavierStokes_TH_MultiPhase_RB() +{ FUNCNAME("NavierStokes_TH_MultiPhase_RB::~NavierStokes_TH_MultiPhase_RB()"); + + delete multiPhase; + delete densityPhase; + delete viscosityPhase; +}; + + +void NavierStokes_TH_MultiPhase_RB::initData() +{ FUNCNAME("NavierStokes_TH_MultiPhase_RB::initTimeInterface()"); + + multiPhase = new DOFVector<double>(prob->getFeSpace(0), "multiPhase"); + densityPhase = new DOFVector<double>(prob->getFeSpace(0), "densityPhase"); + viscosityPhase = new DOFVector<double>(prob->getFeSpace(0), "viscosityPhase"); + + multiPhase->set(1.0); + densityPhase->set(density1); + viscosityPhase->set(viscosity1); + + super::initData(); +}; + +void NavierStokes_TH_MultiPhase_RB::initTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_TH_MultiPhase_RB::initTimestep()"); + + super::initTimestep(adaptInfo); + + transformDOF(multiPhase, densityPhase, new LinearInterpolation(density1, density2)); + transformDOF(multiPhase, viscosityPhase, new LinearInterpolation(viscosity1, viscosity2)); +}; + + +void NavierStokes_TH_MultiPhase_RB::fillOperators() +{ FUNCNAME("NavierStokes_TH_MultiPhase_RB::fillOperators()"); + + WorldVector<DOFVector<double>* > vel; + for (unsigned i = 0; i < dim; i++) + vel[i]= prob->getSolution()->getDOFVector(i); + + WorldVector<DOFVector<double>*> stage_velocity; + WorldVector<DOFVector<double>*> un_velocity; + for (unsigned i = 0; i < dow; ++i) { + stage_velocity[i] = prob->getStageSolution(i); + un_velocity[i] = prob->getUnVec(i); + } + + // fill operators for prob + for (unsigned i = 0; i < dim; ++i) { + /// < d_t(u_i) , psi > + Operator *opTime = new Operator(getFeSpace(i), getFeSpace(i)); + opTime->addZeroOrderTerm(new VecAtQP_ZOT(densityPhase, NULL)); + prob->addMatrixOperator(opTime, i, i, prob->getInvTauGamma(), prob->getInvTauGamma()); + + Operator *opTimeOld = new Operator(getFeSpace(i)); + opTimeOld->addZeroOrderTerm(new Vec2AtQP_ZOT(densityPhase, prob->getTimeRhsVec(i), NULL)); + prob->addVectorOperator(opTimeOld, i, &minus1, &minus1); + + /// < u*grad(u_i) , psi > + Operator *opUGradU = new Operator(getFeSpace(i), getFeSpace(i)); + opUGradU->addTerm(new WorldVecPhase_FOT(densityPhase, stage_velocity, -1.0), GRD_PHI); + opUGradU->setUhOld(stage_velocity[i]); + prob->addVectorOperator(*opUGradU, i); + + Operator *opUGradV = new Operator(getFeSpace(i), getFeSpace(i)); + opUGradV->addTerm(new WorldVecPhase_FOT(densityPhase, un_velocity, -1.0), GRD_PHI); + prob->addMatrixOperator(*opUGradV, i, i, &minus1, &minus1); + + for (unsigned j = 0; j < dow; ++j) { + Operator *opVGradU = new Operator(getFeSpace(i), getFeSpace(j)); + opVGradU->addTerm(new VecAndPartialDerivative_ZOT(densityPhase, un_velocity[i], j, -1.0)); + prob->addMatrixOperator(*opVGradU, i, j, &minus1, &minus1); + } + + /// Diffusion-Operator (including Stress-Tensor for space-dependent viscosity + addLaplaceTerm(i); + + /// < p , d_i(psi) > + Operator *opGradP = new Operator(getFeSpace(i),getFeSpace(dow)); + opGradP->addTerm(new PartialDerivative_FOT(i, -1.0), GRD_PSI); + opGradP->setUhOld(prob->getStageSolution(dow)); + prob->addVectorOperator(*opGradP, i); + prob->addMatrixOperator(*opGradP, i, dow, &minus1, &minus1); + + /// external force, i.e. gravitational force + if (norm(force) > DBL_TOL) { + Operator *opForce = new Operator(getFeSpace(i), getFeSpace(i)); + opForce->addZeroOrderTerm(new Phase_ZOT(densityPhase, force[i])); + prob->addVectorOperator(*opForce, i); + } + } + + /// div(u) = 0 + for (unsigned i = 0; i < dow; ++i) { + /// < d_i(u'_i) , psi > + Operator *opDivU = new Operator(getFeSpace(dow),getFeSpace(i)); + opDivU->addTerm(new PartialDerivative_FOT(i), GRD_PHI); + opDivU->setUhOld(stage_velocity[i]); + prob->addVectorOperator(*opDivU, dow); + prob->addMatrixOperator(*opDivU, dow, i, &minus1, &minus1); + } +}; + + +void NavierStokes_TH_MultiPhase_RB::addLaplaceTerm(int i) +{ FUNCNAME("NavierStokes_TH_MultiPhase_RB::addLaplaceTerm()"); + + /// < alpha*[grad(u)+grad(u)^t] , grad(psi) > + if (laplaceType == 1) { + for (unsigned j = 0; j < dim; ++j) { + Operator *opLaplaceUi1 = new Operator(getFeSpace(i), getFeSpace(j)); + opLaplaceUi1->addTerm(new VecAtQP_IJ_SOT( + viscosityPhase, NULL, 1-i, 1-j)); + opLaplaceUi1->setUhOld(prob->getStageSolution(j)); + prob->addVectorOperator(*opLaplaceUi1, i, &minus1, &minus1); + prob->addMatrixOperator(*opLaplaceUi1, i, j); + } + } + + /// < alpha*grad(u'_i) , grad(psi) > + Operator *opLaplaceUi = new Operator(getFeSpace(i), getFeSpace(i)); + opLaplaceUi->addTerm(new VecAtQP_SOT(viscosityPhase, NULL)); + opLaplaceUi->setUhOld(prob->getStageSolution(i)); + prob->addVectorOperator(*opLaplaceUi, i, &minus1, &minus1); + prob->addMatrixOperator(*opLaplaceUi, i, i); +}; diff --git a/extensions/base_problems/NavierStokes_TH_MultiPhase_RB.h b/extensions/base_problems/NavierStokes_TH_MultiPhase_RB.h new file mode 100644 index 0000000000000000000000000000000000000000..95e335d8fc9d5a606efbcdb92fc23053ed9f16a8 --- /dev/null +++ b/extensions/base_problems/NavierStokes_TH_MultiPhase_RB.h @@ -0,0 +1,126 @@ +/** \file NavierStokes_TH_MultiPhase.h */ + +#ifndef NAVIER_STOKES_TAYLOR_HOOD_MULTIPHASE_H +#define NAVIER_STOKES_TAYLOR_HOOD_MULTIPHASE_H + +#include "NavierStokes_TaylorHood_RB.h" + +#define LINKS 1 +#define RECHTS 2 +#define UNTEN 3 +#define OBEN 4 + +using namespace AMDiS; + +/** \ingroup NavierStokes_TaylorHood + * \brief + * Navier-Stokes multi-phase problem, using Taylor Hood elements + * Standard implementation for two phases, but can be extended to + * many more, by defining the multiPhase variable and overloading + * the initTimestep, where densityPhase and viscosityPhase are defined + * depending on the phases + */ +class NavierStokes_TH_MultiPhase_RB : public NavierStokes_TaylorHood_RB +{ +public: // typedefs + + typedef NavierStokes_TaylorHood_RB super; + +public: // methods + + NavierStokes_TH_MultiPhase_RB(const std::string &name_); + + /// deletes multiPhase, viscosityPhase and densityPhase + ~NavierStokes_TH_MultiPhase_RB(); + + /** definition of constant multiPhase and const + * viscosity/density DOFVectors, + * initTimeInterface of super + **/ + virtual void initData(); + + /** initTimestep of super and + * initialization of densityPhase and viscosityPhase + **/ + virtual void initTimestep(AdaptInfo *adaptInfo); + + /** pointer to the multiPhase DOFVector, that + * indicates the different phases. Will be initialized + * in \ref initTimeInterface with const 1 + **/ + DOFVector<double> *getMultiPhase() { return multiPhase; } + +protected: // methods + + virtual void fillOperators(); + virtual void addLaplaceTerm(int i); + +protected: // variables + + ///viscosity of phase 1 + double viscosity1; + + ///viscosity of phase 2 + double viscosity2; + + ///density of phase 1 + double density1; + + ///density of phase 2 + double density2; + + /// phase dependent density + DOFVector<double> *densityPhase; + + /// phase dependent viscosity + DOFVector<double> *viscosityPhase; + + /// phase inticator + DOFVector<double> *multiPhase; + +}; + + +/** linear interpolation between two values (like density, viscosity) + * using a phase-field variable in [-1,1] + **/ +class LinearInterpolation : public AbstractFunction<double, double> +{ +public: + + LinearInterpolation(double val1_, double val2_) : + AbstractFunction<double, double>(1), + val1(val1_), val2(val2_) {} + + double operator()(const double &phase) const { + return 0.5*(phase+1.0)*val1 - 0.5*(phase-1.0)*val2; + } + +private: + + double val1; + double val2; +}; + +/** linear interpolation between two values (like density, viscosity) + * using a phase-field variable in [0,1] + **/ +class LinearInterpolation0 : public AbstractFunction<double, double> +{ +public: + + LinearInterpolation0(double val1_, double val2_) : + AbstractFunction<double, double>(1), + val1(val1_), val2(val2_) {} + + double operator()(const double &phase) const { + return phase*val1 + (1.0-phase)*val2; + } + +private: + + double val1; + double val2; +}; + +#endif // NAVIER_STOKES_TAYLOR_HOOD_MULTIPHASE_H diff --git a/extensions/base_problems/NavierStokes_TaylorHood.cc b/extensions/base_problems/NavierStokes_TaylorHood.cc new file mode 100644 index 0000000000000000000000000000000000000000..b8d676bf1297324afba8ed8cc3eeadcbd7df67fc --- /dev/null +++ b/extensions/base_problems/NavierStokes_TaylorHood.cc @@ -0,0 +1,249 @@ +#include "NavierStokes_TaylorHood.h" + +using namespace std; +using namespace AMDiS; + +NavierStokes_TaylorHood::NavierStokes_TaylorHood(const std::string &name_) : + super(name_), + forceDBC(false), + initialVelocityIsSet(false), + laplaceType(0), + nonLinTerm(2), + oldTimestep(0.0), + viscosity(1.0), + density(1.0), + c(0.0), + theta(0.5), + theta1(0.5), + minusTheta1(-0.5), + velocity(NULL) +{ + // force the homogeniouse dirichlet BC if combination of dirichlet and neumann BC + // are set and AMDiS can not handle this combination automatically + Initfile::get(name + "->force dirichlet bc", forceDBC); + if (forceDBC) { + int numDirichletPoints = 0; + Initfile::get("number of dirichlet points", numDirichletPoints); + dirichletPoints.resize(numDirichletPoints); + for (int i = 0; i < numDirichletPoints; i++) + Initfile::get("dirichlet point[" + Helpers::toString(i) + "]",dirichletPoints[i]); + } + + // parameters for navier-stokes + Initfile::get(name + "->viscosity", viscosity); + Initfile::get(name + "->density", density); + // type of laplace operator: 0... div(nu*grad(u)), 1... div(0.5*nu*(grad(u)+grad(u)^T)) + Initfile::get(name + "->laplace operator", laplaceType); + // type of non-linear term: 0... u^old*grad(u_i^old), 1... u'*grad(u_i^old), 2... u^old*grad(u'_i) + Initfile::get(name + "->non-linear term", nonLinTerm); + + Initfile::get(name + "->theta", theta); + theta1 = 1.0-theta; + minusTheta1 = -theta1; + + force.set(0.0); + Initfile::get(name + "->force", force); + + bool scaleMesh = false; + Initfile::get("mesh->scale mesh",scaleMesh); + if (scaleMesh) { + Initfile::get("mesh->scale",dimension); + } else + dimension.set(1.0); +} + + +NavierStokes_TaylorHood::~NavierStokes_TaylorHood() +{ FUNCNAME("NavierStokes_TaylorHood::~NavierStokes_TaylorHood()"); + + if (initialVelocityIsSet) { + delete initialX; + delete initialY; + } + if (velocity != NULL) + delete velocity; + delete fileWriter; +} + + +void NavierStokes_TaylorHood::initData() +{ FUNCNAME("NavierStokes_TaylorHood::initTimeInterface()"); + + if (velocity == NULL) + velocity = new DOFVector<WorldVector<double> >(getFeSpace(0), "velocity"); + fileWriter = new FileVectorWriter(name + "->velocity->output", getFeSpace()->getMesh(), velocity); + + super::initData(); +} + + +void NavierStokes_TaylorHood::solveInitialProblem(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_TaylorHood::solveInitialProblem()"); + + int initialVelocity = 0, flowDirection = 1; + Initfile::get(name + "->initial velocity", initialVelocity); + Initfile::get(name + "->initial velocity->value", c); + Initfile::get(name + "->initial velocity->flow direction", flowDirection); + + std::vector<AbstractFunction<double, WorldVector<double> >*> initialFcts(2); + if (initialVelocity == 0) { // no initial velocity + initialFcts[0]= new ConstantFct(0.0); + initialFcts[1]= new ConstantFct(0.0); + } else if(initialVelocity == 1) { // constant inflow + initialFcts[flowDirection] = new ConstantFct(c); + initialFcts[1-flowDirection] = new ConstantFct(0.0); + } else if(initialVelocity == 2) { // parabolic inflow + double dist = -1.0; + Initfile::get(name + "->initial velocity->parabolic inflow->boundary dist", dist); + if (dist <= 0.0) + dist = 2.0*dimension[1-flowDirection]; + initialFcts[flowDirection] = new ParabolicInflow(dist/2.0, c, flowDirection); + initialFcts[1-flowDirection] = new ConstantFct(0.0); + } else + throw(std::runtime_error("Unknown initial velocity.")); + + initialX = initialFcts[0]; + initialY = initialFcts[1]; + initialVelocityIsSet = true; + + MSG("solve initial problem...\n"); + for (unsigned i = 0; i < dow; ++i) { + prob->getSolution()->getDOFVector(i)->interpol(initialFcts[i]); + prob->setExactSolutionFct(initialFcts[i], i); + } + +} + + +void NavierStokes_TaylorHood::transferInitialSolution(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_TaylorHood::transferInitialSolution()"); + + calcVelocity(); + + for (int i = 0; i < dow; i++) + prob->setExactSolution(prob->getSolution()->getDOFVector(i), i); + + fileWriter->writeFiles(adaptInfo, false); + writeFiles(adaptInfo, false); + + // initial parameters for detecting mesh changes + oldMeshChangeIdx= getMesh()->getChangeIndex(); +} + + +void NavierStokes_TaylorHood::fillOperators() +{ FUNCNAME("NavierStokes_TaylorHood::fillOperators()"); + + // fill operators for prob + for (unsigned i = 0; i < dow; ++i) { + /// < (1/tau)*u'_i , psi > + Operator *opTime = new Operator(getFeSpace(i), getFeSpace(i)); + opTime->addTerm(new Simple_ZOT(density)); + prob->addMatrixOperator(*opTime, i, i, getInvTau(), getInvTau()); + /// < (1/tau)*u_i^old , psi > + opTime->setUhOld(prob->getSolution()->getDOFVector(i)); + prob->addVectorOperator(*opTime, i, getInvTau(), getInvTau()); + + /// < u^old*grad(u_i^old) , psi > + Operator *opUGradU0 = new Operator(getFeSpace(i), getFeSpace(i)); + opUGradU0->addTerm(new WorldVector_FOT(velocity, -density), GRD_PHI); + opUGradU0->setUhOld(prob->getSolution()->getDOFVector(i)); + if (nonLinTerm == 0) { + prob->addVectorOperator(*opUGradU0, i); + } else if (abs(theta1) > DBL_TOL) { + prob->addVectorOperator(*opUGradU0, i, &theta1, &theta1); + } + + if (nonLinTerm == 1) { + /// < u'*grad(u_i^old) , psi > + for (unsigned j = 0; j < dow; ++j) { + Operator *opUGradU1 = new Operator(getFeSpace(i),getFeSpace(i)); + opUGradU1->addTerm(new PartialDerivative_ZOT( + prob->getSolution()->getDOFVector(i), j, density)); + prob->addMatrixOperator(*opUGradU1, i, j, &theta, &theta); + } + } else if (nonLinTerm == 2) { + /// < u^old*grad(u'_i) , psi > + for(unsigned j = 0; j < dow; ++j) { + Operator *opUGradU2 = new Operator(getFeSpace(i),getFeSpace(i)); + opUGradU2->addTerm(new VecAndPartialDerivative_FOT( + prob->getSolution()->getDOFVector(j), j, density), GRD_PHI); + prob->addMatrixOperator(*opUGradU2, i, i, &theta, &theta); + } + } + + for (int j = 0; j < dow; ++j) { + Operator *opNull = new Operator(getFeSpace(i), getFeSpace(j)); + opNull->addTerm(new Simple_ZOT(0.0)); + prob->addMatrixOperator(*opNull, i, j); + } + + /// Diffusion-Operator (including Stress-Tensor for space-dependent viscosity + addLaplaceTerm(i); + + /// < p , d_i(psi) > + Operator *opGradP = new Operator(getFeSpace(i),getFeSpace(dow)); + opGradP->addTerm(new PartialDerivative_FOT(i, -1.0), GRD_PSI); + prob->addMatrixOperator(*opGradP, i, dow); + + /// external force, i.e. gravitational force + if (norm(force) > DBL_TOL) { + Operator *opForce = new Operator(getFeSpace(i), getFeSpace(i)); + opForce->addTerm(new Simple_ZOT(force[i])); + prob->addVectorOperator(*opForce, i); + } + } + + /// div(u) = 0 + for (unsigned i = 0; i < dow; ++i) { + /// < d_i(u'_i) , psi > + Operator *opDivU = new Operator(getFeSpace(dow),getFeSpace(i)); + opDivU->addTerm(new PartialDerivative_FOT(i), GRD_PHI); + prob->addMatrixOperator(*opDivU, dow, i); + } +} + + +void NavierStokes_TaylorHood::addLaplaceTerm(int i) +{ FUNCNAME("NavierStokes_TaylorHood::addLaplaceTerm()"); + + /// < alpha*[grad(u)+grad(u)^t] , grad(psi) > + if (laplaceType == 1) { + for (unsigned j = 0; j < dow; ++j) { + Operator *opLaplaceUi1 = new Operator(getFeSpace(i), getFeSpace(j)); + opLaplaceUi1->addTerm(new MatrixIJ_SOT(1-i, 1-j, viscosity)); + prob->addMatrixOperator(*opLaplaceUi1, i, j, &theta, &theta); + + if (abs(minusTheta1) > DBL_TOL) { + opLaplaceUi1->setUhOld(prob->getSolution()->getDOFVector(j)); + prob->addVectorOperator(*opLaplaceUi1, i, &minusTheta1, &minusTheta1); + } + } + } + + /// < alpha*grad(u'_i) , grad(psi) > + Operator *opLaplaceUi = new Operator(getFeSpace(i), getFeSpace(i)); + opLaplaceUi->addTerm(new Simple_SOT(viscosity)); + prob->addMatrixOperator(*opLaplaceUi, i, i, &theta, &theta); + + if (abs(minusTheta1) > DBL_TOL) { + opLaplaceUi->setUhOld(prob->getSolution()->getDOFVector(i)); + prob->addVectorOperator(*opLaplaceUi, i, &minusTheta1, &minusTheta1); + } +} + + +void NavierStokes_TaylorHood::fillBoundaryConditions() +{ FUNCNAME("NavierStokes_TaylorHood::fillBoundaryConditions()"); + + ERROR("You have to implement some boundary conditions!\n"); +} + + +void NavierStokes_TaylorHood::closeTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_TaylorHood::closeTimestep()"); + + calcVelocity(); + fileWriter->writeFiles(adaptInfo, false); + writeFiles(adaptInfo, false); +} diff --git a/extensions/base_problems/NavierStokes_TaylorHood.h b/extensions/base_problems/NavierStokes_TaylorHood.h new file mode 100644 index 0000000000000000000000000000000000000000..7e78ae0215c9b42a3b855db947f1e80bb3bf9666 --- /dev/null +++ b/extensions/base_problems/NavierStokes_TaylorHood.h @@ -0,0 +1,103 @@ +/** \file NavierStokes_TaylorHood.h */ + +#ifndef NAVIER_STOKES_TAYLOR_HOOD_H +#define NAVIER_STOKES_TAYLOR_HOOD_H + +#include "AMDiS.h" +#include "Helpers.h" +#include "POperators.h" +#include "BoundaryFunctions.h" +#include "BaseProblem.h" +#include "ExtendedProblemStat.h" +#include <boost/numeric/mtl/mtl.hpp> +#include <boost/numeric/mtl/utility/property_map.hpp> + +// boundary numbers +#define LINKS 1 +#define RECHTS 2 +#define UNTEN 3 +#define OBEN 4 + +using namespace AMDiS; + +/** \ingroup NavierStokes_TaylorHood + * \brief + * Navier-Stokes problem, using Taylor Hood elements + */ +class NavierStokes_TaylorHood : public BaseProblem<ExtendedProblemStat> +{ +public: // typedefs + + typedef BaseProblem<ExtendedProblemStat> super; + +public: // methods + + NavierStokes_TaylorHood(const std::string &name_); + + /// if initialVelocityIsSet is true delete initialX and initialY + ~NavierStokes_TaylorHood(); + + virtual void initData(); + virtual void solveInitialProblem(AdaptInfo *adaptInfo); + + virtual void transferInitialSolution(AdaptInfo *adaptInfo); + + virtual void closeTimestep(AdaptInfo *adaptInfo); + + // === getting/setting methods === + + /// set dimension of the macro-mesh + void setDimension(WorldVector<double> dimension_) { dimension = dimension_; } + + DOFVector<WorldVector<double> >* getVelocity() + { + if (velocity == NULL) + velocity = new DOFVector<WorldVector<double> >(getFeSpace(0), "velocity"); + return velocity; + } + +// protected: // methods + + virtual void fillOperators(); + virtual void fillBoundaryConditions(); + + virtual void addLaplaceTerm(int i); + +protected: // variables + + AbstractFunction<double, WorldVector<double> > *initialX, *initialY; + WorldVector<DOFVector<double>*> initialVel; + std::vector<WorldVector<double> > dirichletPoints; + + DOFVector<WorldVector<double> >* velocity; + + void calcVelocity() + { + if (dow == 1) + transformDOF(prob->getSolution()->getDOFVector(0), velocity, new AMDiS::Vec1WorldVec<double>); + else if (dow == 2) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), velocity, new AMDiS::Vec2WorldVec<double>); + else if (dow == 3) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), prob->getSolution()->getDOFVector(2), velocity, new AMDiS::Vec3WorldVec<double>); + } + + bool forceDBC; + bool initialVelocityIsSet; + + int laplaceType; + int nonLinTerm; + + double oldTimestep; + double viscosity; + double density; + double c; + double theta; + double theta1; + double minusTheta1; + + WorldVector<double> force; + WorldVector<double> dimension; + + FileVectorWriter *fileWriter; +}; +#endif // NAVIER_STOKES_TAYLOR_HOOD_H diff --git a/extensions/base_problems/NavierStokes_TaylorHood_RB.cc b/extensions/base_problems/NavierStokes_TaylorHood_RB.cc new file mode 100644 index 0000000000000000000000000000000000000000..c6bf53f7b9ec57d4516584dcc00c5d3e4e53917d --- /dev/null +++ b/extensions/base_problems/NavierStokes_TaylorHood_RB.cc @@ -0,0 +1,265 @@ +#include "NavierStokes_TaylorHood_RB.h" + +using namespace std; +using namespace AMDiS; + +NavierStokes_TaylorHood_RB::NavierStokes_TaylorHood_RB(const std::string &name_) : + super(name_), + forceDBC(false), + initialVelocityIsSet(false), + laplaceType(0), + nonLinTerm(2), + oldTimestep(0.0), + viscosity(1.0), + c(0.0), + minus1(-1.0), + velocity(NULL) +{ + // force the homogeniouse dirichlet BC if combination of dirichlet and neumann BC + // are set and AMDiS can not handle this combination automatically + Initfile::get(name + "->force dirichlet bc", forceDBC); + if (forceDBC) { + int numDirichletPoints = 0; + Initfile::get("number of dirichlet points", numDirichletPoints); + dirichletPoints.resize(numDirichletPoints); + for (int i = 0; i < numDirichletPoints; i++) + Initfile::get("dirichlet point[" + Helpers::toString(i) + "]",dirichletPoints[i]); + } + + // parameters for navier-stokes + Initfile::get(name + "->viscosity", viscosity); + // type of laplace operator: 0... div(nu*grad(u)), 1... div(0.5*nu*(grad(u)+grad(u)^T)) + Initfile::get(name + "->laplace operator", laplaceType); + // type of non-linear term: 0... u^old*grad(u_i^old), 1... u'*grad(u_i^old), 2... u^old*grad(u'_i) + Initfile::get(name + "->non-linear term", nonLinTerm); + + force.set(0.0); + Initfile::get(name + "->force", force); + + bool scaleMesh = false; + Initfile::get("mesh->scale mesh",scaleMesh); + if (scaleMesh) { + Initfile::get("mesh->scale",dimension); + } else + dimension.set(1.0); +} + + +NavierStokes_TaylorHood_RB::~NavierStokes_TaylorHood_RB() +{ FUNCNAME("NavierStokes_TaylorHood_RB::~NavierStokes_TaylorHood_RB()"); + + if (initialVelocityIsSet) { + delete initialX; + delete initialY; + } + if (velocity != NULL) + delete velocity; + delete fileWriter; +} + + +void NavierStokes_TaylorHood_RB::initData() +{ FUNCNAME("NavierStokes_TaylorHood_RB::initTimeInterface()"); + + if (velocity == NULL) + velocity = new DOFVector<WorldVector<double> >(getFeSpace(0), "velocity"); + fileWriter = new FileVectorWriter(name + "->velocity->output", getFeSpace()->getMesh(), velocity); + + super::initData(); +} + + +void NavierStokes_TaylorHood_RB::solveInitialProblem(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_TaylorHood_RB::solveInitialProblem()"); + + int initialVelocity = 0, flowDirection = 1; + Initfile::get(name + "->initial velocity", initialVelocity); + Initfile::get(name + "->initial velocity->value", c); + Initfile::get(name + "->initial velocity->flow direction", flowDirection); + + std::vector<AbstractFunction<double, WorldVector<double> >*> initialFcts(2); + if (initialVelocity == 0) { // no initial velocity + initialFcts[0]= new ConstantFct(0.0); + initialFcts[1]= new ConstantFct(0.0); + } else if(initialVelocity == 1) { // constant inflow + initialFcts[flowDirection] = new ConstantFct(c); + initialFcts[1-flowDirection] = new ConstantFct(0.0); + } else if(initialVelocity == 2) { // parabolic inflow + double dist = -1.0; + Initfile::get(name + "->initial velocity->parabolic inflow->boundary dist", dist); + if (dist <= 0.0) + dist = 2.0*dimension[1-flowDirection]; + initialFcts[flowDirection] = new ParabolicInflow(dist/2.0, c, flowDirection); + initialFcts[1-flowDirection] = new ConstantFct(0.0); + } else + throw(std::runtime_error("Unknown initial velocity.")); + + initialX = initialFcts[0]; + initialY = initialFcts[1]; + initialVelocityIsSet = true; + + for (unsigned i = 0; i < dow; ++i) { + prob->setExactSolutionFct(initialFcts[i], i); + } +} + + +void NavierStokes_TaylorHood_RB::transferInitialSolution(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_TaylorHood_RB::transferInitialSolution()"); + + MSG("solve initial problem...\n"); + for (unsigned i = 0; i < dow; ++i) { + prob->getSolution()->getDOFVector(i)->interpol(prob->getExactSolutionFct(i)); + } + + if (dow == 1) + transformDOF(prob->getSolution()->getDOFVector(0), velocity, new AMDiS::Vec1WorldVec<double>); + else if (dow == 2) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), velocity, new AMDiS::Vec2WorldVec<double>); + else if (dow == 3) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), prob->getSolution()->getDOFVector(2), velocity, new AMDiS::Vec3WorldVec<double>); + + for (int i = 0; i < dow; i++) + prob->setExactSolution(prob->getSolution()->getDOFVector(i), i); + + fileWriter->writeFiles(adaptInfo, false); + writeFiles(adaptInfo, false); + + // initial parameters for detecting mesh changes + oldMeshChangeIdx= getMesh()->getChangeIndex(); +} + + +void NavierStokes_TaylorHood_RB::fillOperators() +{ FUNCNAME("NavierStokes_TaylorHood_RB::fillOperators()"); + MSG("NavierStokes_TaylorHood_RB::fillOperators()\n"); + + WorldVector<DOFVector<double>*> stage_velocity; + WorldVector<DOFVector<double>*> un_velocity; + for (unsigned i = 0; i < dow; ++i) { + stage_velocity[i] = prob->getStageSolution(i); + un_velocity[i] = prob->getUnVec(i); + } + + // fill operators for prob + for (unsigned i = 0; i < dow; ++i) { + /// < d_t(u_i) , psi > + prob->addTimeOperator(i, i); + + /// < u*grad(u_i) , psi > + Operator *opUGradU = new Operator(getFeSpace(i), getFeSpace(i)); + opUGradU->addTerm(new WorldVec_FOT(stage_velocity, -1.0), GRD_PHI); + opUGradU->setUhOld(stage_velocity[i]); + prob->addVectorOperator(*opUGradU, i); + + Operator *opUGradV = new Operator(getFeSpace(i), getFeSpace(i)); + opUGradV->addTerm(new WorldVec_FOT(un_velocity, -1.0), GRD_PHI); + prob->addMatrixOperator(*opUGradV, i, i, &minus1, &minus1); + + for (unsigned j = 0; j < dow; ++j) { + Operator *opVGradU = new Operator(getFeSpace(i), getFeSpace(j)); + opVGradU->addTerm(new PartialDerivative_ZOT(un_velocity[i], j, -1.0)); + prob->addMatrixOperator(*opVGradU, i, j, &minus1, &minus1); + } + + /// Diffusion-Operator (including Stress-Tensor for space-dependent viscosity) + addLaplaceTerm(i); + + /// < p , d_i(psi) > + Operator *opGradP = new Operator(getFeSpace(i),getFeSpace(dow)); + opGradP->addTerm(new PartialDerivative_FOT(i, -1.0), GRD_PSI); + opGradP->setUhOld(prob->getStageSolution(dow)); + prob->addVectorOperator(*opGradP, i); + prob->addMatrixOperator(*opGradP, i, dow, &minus1, &minus1); + + /// external force, i.e. gravitational force + if (norm(force) > DBL_TOL) { + Operator *opForce = new Operator(getFeSpace(i), getFeSpace(i)); + opForce->addTerm(new Simple_ZOT(force[i])); + prob->addVectorOperator(*opForce, i); + } + } + + /// div(u) = 0 + for (unsigned i = 0; i < dow; ++i) { + /// < d_i(u'_i) , psi > + Operator *opDivU = new Operator(getFeSpace(dow),getFeSpace(i)); + opDivU->addTerm(new PartialDerivative_FOT(i), GRD_PHI); + opDivU->setUhOld(stage_velocity[i]); + prob->addVectorOperator(*opDivU, dow); + prob->addMatrixOperator(*opDivU, dow, i, &minus1, &minus1); + } +} + + +void NavierStokes_TaylorHood_RB::addLaplaceTerm(int i) +{ FUNCNAME("NavierStokes_TaylorHood_RB::addLaplaceTerm()"); + MSG("NavierStokes_TaylorHood_RB::addLaplaceTerm(%d)\n",i); + + /// < alpha*[grad(u)+grad(u)^t] , grad(psi) > + if (laplaceType == 1) { + for (unsigned j = 0; j < dow; ++j) { + Operator *opLaplaceUi1 = new Operator(getFeSpace(i), getFeSpace(j)); + opLaplaceUi1->addTerm(new MatrixIJ_SOT(1-i, 1-j, viscosity)); + opLaplaceUi1->setUhOld(prob->getStageSolution(j)); + prob->addVectorOperator(*opLaplaceUi1, i, &minus1, &minus1); + prob->addMatrixOperator(*opLaplaceUi1, i, j); + } + } + + /// < alpha*grad(u'_i) , grad(psi) > + Operator *opLaplaceUi = new Operator(getFeSpace(i), getFeSpace(i)); + opLaplaceUi->addTerm(new Simple_SOT(viscosity)); + opLaplaceUi->setUhOld(prob->getStageSolution(i)); + prob->addVectorOperator(*opLaplaceUi, i, &minus1, &minus1); + prob->addMatrixOperator(*opLaplaceUi, i, i); +} + + +void NavierStokes_TaylorHood_RB::fillBoundaryConditions() +{ FUNCNAME("NavierStokes_TaylorHood_RB::fillBoundaryConditions()"); + + ERROR("You have to implement some boundary conditions!\n"); + +// DOFVector<double> *zeroDOF = new DOFVector<double>(prob->getFeSpace(0), "zero"); +// zeroDOF->set(0.0); +// +// /// at rigid wall: no-slip boundary condition +// for (unsigned j = 0; j < dow; ++j) { +// prob->addDirichletBC(LINKS, j, j, boundaryDOF[j]); +// prob->addDirichletBC(RECHTS, j, j, boundaryDOF[j]); +// } +// +// /// at inflow: prescribed velocity +// for (unsigned j = 0; j < dow; ++j) { +// prob->addDirichletBC(OBEN, j, j, boundaryDOF[j]); +// // prob->addDirichletBC(OBEN, j, j, prob->getExactSolution(j)); /// test: Dirichlet-BC at outflow boundary +// } +// +// for (unsigned i = 0; i < dirichletPoints.size(); ++i) { +// for (unsigned row = 0; row < dow; row++) { +// prob->addSingularDirichletBC(dirichletPoints[i], row, row, 0.0); +// } +// } +} + + +void NavierStokes_TaylorHood_RB::initTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_TaylorHood_RB::initTimestep()"); + +} + + +void NavierStokes_TaylorHood_RB::closeTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_TaylorHood_RB::closeTimestep()"); + + if (dow == 1) + transformDOF(prob->getSolution()->getDOFVector(0), velocity, new AMDiS::Vec1WorldVec<double>); + else if (dow == 2) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), velocity, new AMDiS::Vec2WorldVec<double>); + else if (dow == 3) + transformDOF(prob->getSolution()->getDOFVector(0), prob->getSolution()->getDOFVector(1), prob->getSolution()->getDOFVector(2), velocity, new AMDiS::Vec3WorldVec<double>); + + fileWriter->writeFiles(adaptInfo, false); + writeFiles(adaptInfo, false); +} diff --git a/extensions/base_problems/NavierStokes_TaylorHood_RB.h b/extensions/base_problems/NavierStokes_TaylorHood_RB.h new file mode 100644 index 0000000000000000000000000000000000000000..56834b4fa24458dcaa8dafd4a226d4f50cabea60 --- /dev/null +++ b/extensions/base_problems/NavierStokes_TaylorHood_RB.h @@ -0,0 +1,109 @@ +/** \file NavierStokes_TaylorHood.h */ + +#ifndef NAVIER_STOKES_TAYLOR_HOOD_H +#define NAVIER_STOKES_TAYLOR_HOOD_H + +#include "AMDiS.h" +#include "Helpers.h" +#include "POperators.h" +#include "BoundaryFunctions.h" +#include "BaseProblem.h" +#include "time/ExtendedRosenbrockStationary.h" +#include <boost/numeric/mtl/mtl.hpp> +#include <boost/numeric/mtl/utility/property_map.hpp> + +// boundary numbers +#define LINKS 1 +#define RECHTS 2 +#define UNTEN 3 +#define OBEN 4 + +using namespace AMDiS; + +/** \ingroup NavierStokes_TaylorHood + * \brief + * Navier-Stokes problem, using Taylor Hood elements + */ +class NavierStokes_TaylorHood_RB : public BaseProblem<ExtendedRosenbrockStationary> +{ +public: // typedefs + + typedef BaseProblem<ExtendedRosenbrockStationary> super; + +public: // methods + + NavierStokes_TaylorHood_RB(const std::string &name_); + + /// if initialVelocityIsSet is true delete initialX and initialY + ~NavierStokes_TaylorHood_RB(); + + virtual void initData(); + virtual void solveInitialProblem(AdaptInfo *adaptInfo); + + virtual void transferInitialSolution(AdaptInfo *adaptInfo); + + virtual void initTimestep(AdaptInfo *adaptInfo); + /// Implementation of ProblemTimeInterface::closeTimestep(). + virtual void closeTimestep(AdaptInfo *adaptInfo); + + // === getting/setting methods === + + /// set dimension of the macro-mesh + void setDimension(WorldVector<double> dimension_) { dimension = dimension_; } + + DOFVector<WorldVector<double> >* getVelocity() + { + if (velocity == NULL) + velocity = new DOFVector<WorldVector<double> >(getFeSpace(0), "velocity"); + return velocity; + } + +// Rosenbrock methods +//_________________________________________________________________________ + +public: + + void acceptTimestep() { prob->acceptTimestep(); } + void reset() { prob->reset(); } + + void setRosenbrockMethod(RosenbrockMethod *method) { prob->setRosenbrockMethod(method); } + void setTau(double *ptr) { prob->setTau(ptr); } + void setTauGamma(double *ptr0, double *ptr1, double *ptr2, double *ptr3) { prob->setTauGamma(ptr0,ptr1,ptr2,ptr3); } + + double* getTauGamma() { return prob->getTauGamma(); } + double* getMinusTauGamma() { return prob->getMinusTauGamma(); } + double* getInvTauGamma() { return prob->getInvTauGamma(); } + double* getMinusInvTauGamma() { return prob->getMinusInvTauGamma(); } + +protected: // methods + + virtual void fillOperators(); + virtual void fillBoundaryConditions(); + + virtual void addLaplaceTerm(int i); + +protected: // variables + + AbstractFunction<double, WorldVector<double> > *initialX, *initialY; + WorldVector<DOFVector<double>*> initialVel; + std::vector<WorldVector<double> > dirichletPoints; + + DOFVector<WorldVector<double> >* velocity; + + bool forceDBC; + bool initialVelocityIsSet; + + int laplaceType; + int nonLinTerm; + + double minus1; + double oldTimestep; + double viscosity; + double c; + + WorldVector<double> force; + WorldVector<double> dimension; + + FileVectorWriter *fileWriter; +}; +#endif // NAVIER_STOKES_TAYLOR_HOOD_H diff --git a/extensions/base_problems/PhaseFieldCrystal.cc b/extensions/base_problems/PhaseFieldCrystal.cc new file mode 100644 index 0000000000000000000000000000000000000000..b18b31560671a703a880036c3490543ef7fe3579 --- /dev/null +++ b/extensions/base_problems/PhaseFieldCrystal.cc @@ -0,0 +1,266 @@ +#include "PhaseFieldCrystal.h" + +using namespace std; +using namespace AMDiS; + +PhaseFieldCrystal::PhaseFieldCrystal(const std::string &name_) : + ProblemInstatBase(name_,NULL), + prob(NULL), + useMobility(false), + oldMeshChangeIdx(0), + nTimesteps(-1), + oldTimestep(0.0), + tempParameter(-0.6), + r(-0.4), + rho0(1.0), + density(-0.1), + two(2.0), + minus2(-2.0) +{ + // create basic problems + prob = new ProblemStat(name + "->space"); + + dow = Global::getGeo(WORLD); + + Parameters::get(name + "->r",r); + Parameters::get(name + "->rho0", rho0); + Parameters::get(name + "->density", density); + Parameters::get(name + "->use mobility", useMobility); + tempParameter= -(1.0+r); +}; + + +PhaseFieldCrystal::~PhaseFieldCrystal() +{ FUNCNAME("PhaseFieldCrystal::~PhaseFieldCrystal()"); +}; + + +void PhaseFieldCrystal::initialize(Flag initFlag, + ProblemStat *adoptProblem, + Flag adoptFlag) +{ FUNCNAME("PhaseFieldCrystal::initialize()"); + + prob->initialize(initFlag, adoptProblem, adoptFlag); + dim = getMesh()->getDim(); +}; + + +void PhaseFieldCrystal::initTimeInterface() +{ + fillOperators(); + fillBoundaryConditions(); +}; + + +Flag PhaseFieldCrystal::initDataFromFile(AdaptInfo *adaptInfo) +{ FUNCNAME("PhaseFieldCrystal::initDataFromFile()"); + + Flag initFlag; + int readDataFromFile = 0, readArhFiles = 0; + Initfile::get("user parameter->read data from file", readDataFromFile); + Initfile::get("user parameter->read arh files", readArhFiles); + if (readDataFromFile == 0) return initFlag; + + std::string pfc_file = ""; + Initfile::get("user parameter->data file[pfc]", pfc_file); + // read data and mesh from arh-files + + if (pfc_file.length() > 0) { MSG_DBG("pfc...\n"); + ArhReader::read(pfc_file, prob->getMesh(), + prob->getSolution()->getDOFVector(0), + prob->getSolution()->getDOFVector(1), + prob->getSolution()->getDOFVector(2)); + initFlag.setFlag(PFC_ADOPTED); + initFlag.setFlag(PFC_MESH_ADOPTED); } + + return initFlag; +}; + + +void PhaseFieldCrystal::solveInitialProblem(AdaptInfo *adaptInfo) +{ FUNCNAME("PhaseFieldCrystal::solveInitialProblem()"); + MSG_DBG("PhaseFieldCrystal::solveInitialProblem()\n"); + + Flag initFlag = initDataFromFile(adaptInfo); +}; + + +void PhaseFieldCrystal::transferInitialSolution(AdaptInfo *adaptInfo) +{ FUNCNAME("PhaseFieldCrystal::transferInitialSolution()"); + + writeFiles(adaptInfo, false); +}; + + +void PhaseFieldCrystal::beginIteration(AdaptInfo *adaptInfo) +{ FUNCNAME("PhaseFieldCrystal::beginIteration()"); + + MSG("\n"); + MSG("[[ PFC iteration ]]\n"); + + // assemble some blocks only once, if some conditions are fullfilled + #ifdef HAVE_PARALLEL_DOMAIN_AMDIS + bool fixedMatrixCell= false; + #else + bool fixedMatrixCell= adaptInfo->getTimestepNumber() > 0 + && std::abs(adaptInfo->getTimestep() - oldTimestep) < DBL_TOL + && oldMeshChangeIdx == getMesh()->getChangeIndex(); + #endif + for(unsigned i= 0; i < fixedMatrixTimestep.size(); ++i) { + prob->setAssembleMatrixOnlyOnce( + fixedMatrixTimestep[i].first, + fixedMatrixTimestep[i].second, + fixedMatrixCell); + } +}; + + +Flag PhaseFieldCrystal::oneIteration( AdaptInfo *adaptInfo, + Flag toDo) +{ FUNCNAME("PhaseFieldCrystal::oneIteration()"); + + Flag flag, markFlag; + + if (toDo.isSet(MARK)) + markFlag = prob->markElements(adaptInfo); + else + markFlag = 3; + + // refine + if (toDo.isSet(ADAPT) && markFlag.isSet(MESH_REFINED)) + flag = prob->refineMesh(adaptInfo); + // coarsen + if (toDo.isSet(ADAPT) && markFlag.isSet(MESH_COARSENED)) + flag |= prob->coarsenMesh(adaptInfo); + + #ifdef HAVE_PARALLEL_DOMAIN_AMDIS + MPI::COMM_WORLD.Barrier(); + #endif + + #ifndef NONLIN_PROBLEM + if (toDo.isSet(BUILD)) { + prob->getSolver()->setMultipleRhs(false); + prob->buildAfterCoarsen(adaptInfo, markFlag, true, true); + } + #endif + + if (toDo.isSet(SOLVE)) { + try { + MSG("solve prob..\n"); + prob->solve(adaptInfo, false); + } catch(std::exception &e) { + WARNING(("Could not solve system. Simulation will be stoped here! UMFPACK-ERROR: " + + std::string(e.what()) + "\n").c_str()); + adaptInfo->setTime(adaptInfo->getEndTime()); + adaptInfo->setTimestepNumber(adaptInfo->getNumberOfTimesteps()); + return flag; + } catch(...) { + WARNING("Could not solve system. Simulation will be stoped here! Unknown ERROR\n"); + adaptInfo->setTime(adaptInfo->getEndTime()); + adaptInfo->setTimestepNumber(adaptInfo->getNumberOfTimesteps()); + return flag; + } + } + + if (toDo.isSet(ESTIMATE)) + prob->estimate(adaptInfo); + + oldTimestep = adaptInfo->getTimestep(); + oldMeshChangeIdx = prob->getMesh()->getChangeIndex(); + + return flag; +}; + + +void PhaseFieldCrystal::endIteration(AdaptInfo *adaptInfo) +{ FUNCNAME("NavierStokes_Chorin::endIteration()"); + + MSG("\n"); + MSG("[[ end of PFC iteration ]]\n"); +}; + + +void PhaseFieldCrystal::fillOperators() +{ FUNCNAME("PhaseFieldCrystal::fillOperators()"); + MSG_DBG("PhaseFieldCrystal::fillOperators()\n"); + + // phi*rho + Operator *opMnew = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMnew->addTerm(new Simple_ZOT); + Operator *opMold = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMold->addTerm(new VecAtQP_ZOT(prob->getSolution()->getDOFVector(0), NULL)); + + // -nabla*(phi*grad(rho)) + Operator *opL = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opL->addTerm(new Simple_SOT); + + Operator *opLM = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + if (useMobility) // non-constant mobility + opLM->addTerm(new VecAtQP_SOT( + prob->getSolution()->getDOFVector(0), + new MobilityPfc(density, rho0))); + else // constant mobility + opLM->addTerm(new Simple_SOT); + + // -(1+r)*phi*rho + Operator *opMTemp = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMTemp->addZeroOrderTerm(new Simple_ZOT()); + // -2*rho_old^3 + Operator *opMPowExpl = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMPowExpl->addZeroOrderTerm(new Pow3_ZOT(prob->getSolution()->getDOFVector(0),-2.0)); + // -3*rho_old^2 + Operator *opMPowImpl = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMPowImpl->addZeroOrderTerm(new Pow2_ZOT(prob->getSolution()->getDOFVector(0),-3.0)); + + // 0 = nu-laplace(rho) + // ------------------- + prob->addMatrixOperator(opL, 0, 0); // -laplace(rho) + prob->addMatrixOperator(opMnew, 0, 2); // nu + + // dt(rho) = laplace(mu) - u*grad(rho) + // ----------------------------------- + prob->addMatrixOperator(opMnew, 1, 0, getInvTau()); + prob->addMatrixOperator(opLM, 1, 1); // -laplace(mu) + // . . . vectorOperators . . . . . . . . . . . . . . . + prob->addVectorOperator(opMold, 1, getInvTau()); + + // mu-2*nu-laplace(nu)-(1+r)*rho = (rho_old^3) + ExtPot - eps^2/(rho_old+0.9) + // ---------------------------------------------------------------------- + prob->addMatrixOperator(opMTemp, 2, 0, getTempParameter()); // -phi*(1+r)*rho + prob->addMatrixOperator(opMPowImpl, 2, 0); // -3*rho*rho_old^2 + prob->addMatrixOperator(opL, 2, 0, &two); // -2*phi*laplace(rho) * psi + prob->addMatrixOperator(opMnew, 2, 1); // phi*mu * psi + prob->addMatrixOperator(opL, 2, 2); // phi*grad(nu) * grad(psi) + // prob.addMatrixOperator(opMnew,2,2,&minus2); + // . . . vectorOperators . . . . . . . . . . . . . . . + prob->addVectorOperator(opMPowExpl, 2); // -2*phi^old*rho_old^3 +}; + + +void PhaseFieldCrystal::fillBoundaryConditions() +{ FUNCNAME("PhaseFieldCrystal::fillBoundaryConditions()"); + MSG_DBG("PhaseFieldCrystal::fillBoundaryConditions()\n"); +}; + + +void PhaseFieldCrystal::initTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("PhaseFieldCrystal::initTimestep()"); +}; + + +void PhaseFieldCrystal::closeTimestep(AdaptInfo *adaptInfo) +{ FUNCNAME("PhaseFieldCrystal::closeTimestep()"); + + int outputPeriod = 1; + Initfile::get("user parameter->write every ith timestep", outputPeriod); + if (adaptInfo->getTimestepNumber() % outputPeriod == 0 + && adaptInfo->getStartTime() < adaptInfo->getEndTime()) { + writeFiles(adaptInfo, false); + } +}; + + +void PhaseFieldCrystal::writeFiles(AdaptInfo *adaptInfo, bool force) +{ + prob->writeFiles(adaptInfo, force); +}; diff --git a/extensions/base_problems/PhaseFieldCrystal.h b/extensions/base_problems/PhaseFieldCrystal.h new file mode 100644 index 0000000000000000000000000000000000000000..e277b7b9401c749f75028370a301148c6e0371fa --- /dev/null +++ b/extensions/base_problems/PhaseFieldCrystal.h @@ -0,0 +1,173 @@ +/** \file PhaseFieldCrystal.h */ + +#ifndef PHASE_FIELD_CRYSTAL_H +#define PHASE_FIELD_CRYSTAL_H + +#include "AMDiS.h" +#include "MyProblemVec.h" +#include "Helpers.h" +#include "POperators.h" + +using namespace AMDiS; + +const Flag PFC_MESH_ADOPTED = 1<<2; +const Flag PFC_ADOPTED = 1<<3; + +/** Phase-field Crystal problem + */ +class PhaseFieldCrystal : public ProblemIterationInterface, + public ProblemInstatBase +{ +public: + + PhaseFieldCrystal(const std::string &name_); + ~PhaseFieldCrystal(); + + /// Initialisation of the problem. + virtual void initialize(Flag initFlag, + ProblemStat *adoptProblem = NULL, + Flag adoptFlag = INIT_NOTHING); + virtual void initTimeInterface(); + + virtual Flag initDataFromFile(AdaptInfo *adaptInfo); + virtual void solveInitialProblem(AdaptInfo *adaptInfo); + virtual void transferInitialSolution(AdaptInfo *adaptInfo); + + /// Implementation of ProblemTimeInterface::initTimestep(). + virtual void initTimestep(AdaptInfo *adaptInfo); + + /// Implementation of ProblemTimeInterface::closeTimestep(). + virtual void closeTimestep(AdaptInfo *adaptInfo); + + virtual void beginIteration(AdaptInfo *adaptInfo); + virtual Flag oneIteration(AdaptInfo *adaptInfo, Flag toDo= FULL_ITERATION); + virtual void endIteration(AdaptInfo *adaptInfo); + + /// getting methods + SystemVector *getSolution() + { + return prob->getSolution(); + } + + double *getTempParameter() { return &tempParameter; } + + inline Mesh* getMesh(int comp = 0) + { + return prob->getMesh(comp); + } + + inline FiniteElemSpace* getFeSpace(int comp = 0) + { + return prob->getFeSpace(comp); + } + + std::string getName() + { + return name; + }; + + int getNumProblems() + { + return 1; + }; + + ProblemStat *getProblem(int number= 0) + { + if (number<0 || number >= getNumProblems()) + throw(std::runtime_error("problem with given number does not exist")); + if (number == 0) + return prob; + }; + + ProblemStat *getProblem(std::string name) + { + if (name == "pfc") + return prob; + else + throw(std::runtime_error("problem with given name '" + name + "' does not exist")); + }; + + /// setting methods + + void setAssembleMatrixOnlyOnce_butTimestepChange(int i, int j) + { + fixedMatrixTimestep.push_back(std::make_pair(i,j)); + } + + void setNumberOfTimesteps(int nTimesteps_) + { + nTimesteps= nTimesteps_; + } + + void writeFiles(AdaptInfo *adaptInfo, bool force); + void serialize(std::ostream&) {}; + void deserialize(std::istream&) {}; + +protected: + + virtual void fillOperators(); + virtual void fillBoundaryConditions(); + +protected: + + ProblemStat *prob; + + bool useMobility; + + unsigned dim; + unsigned dow; + + int nTimesteps; + int oldMeshChangeIdx; + + double oldTimestep; + double tempParameter; + double r; + double rho0; + double density; + double two; + double minus2; + +private: + + std::vector<std::pair<int,int> > fixedMatrixTimestep; + +}; + + +/** \ingroup MainInstat + * \brief + * Abstract function to calculate the pure PFC-Energy + */ +class Energy : public BinaryAbstractFunction<double,double,double> +{ + public: + Energy() : BinaryAbstractFunction<double,double,double>(4) { } + + double operator()(const double &rho, const double &mu) const { + return -0.25*sqr(sqr(rho)) + 0.5*rho*mu; } +}; + + +class MobilityPfc : public AbstractFunction<double,double> +{ + public: + MobilityPfc(double density_ = -0.3, double factor_ = 1.0) : + AbstractFunction<double,double>(1), + density(density_), + factor(factor_), + delta(1.e-6) { } + + double operator()(const double &rho) const + { + double mobility= abs(rho - 3.0*density)*factor; + return std::max(mobility, delta); + } + + protected: + double density; + double factor; + double delta; +}; + +#endif // PHASE_FIELD_CRYSTAL_H diff --git a/extensions/base_problems/PhaseFieldCrystal_Base.cc b/extensions/base_problems/PhaseFieldCrystal_Base.cc new file mode 100644 index 0000000000000000000000000000000000000000..295c22df104ed9c040bbeefac14c0d88fba69789 --- /dev/null +++ b/extensions/base_problems/PhaseFieldCrystal_Base.cc @@ -0,0 +1,90 @@ +#include "PhaseFieldCrystal_Base.h" + +using namespace std; +using namespace AMDiS; + +PhaseFieldCrystal::PhaseFieldCrystal(const std::string &name_) : + super(name_), + useMobility(false), + tempParameter(-0.6), + r(-0.4), // temperature deviation + rho0(1.0), // liquid density + density(-0.3), // mean density + two(2.0), + minus2(-2.0) +{ + Parameters::get(name + "->r",r); + Parameters::get(name + "->rho0", rho0); + Parameters::get(name + "->density", density); + Parameters::get(name + "->use mobility", useMobility); + tempParameter= -(1.0+r); +}; + + +void PhaseFieldCrystal::fillOperators() +{ FUNCNAME("PhaseFieldCrystal::fillOperators()"); + + // phi*rho + Operator *opMnew = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMnew->addTerm(new Simple_ZOT); + Operator *opMold = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMold->addTerm(new VecAtQP_ZOT(prob->getSolution()->getDOFVector(0), NULL)); + + // -nabla*(phi*grad(rho)) + Operator *opL = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opL->addTerm(new Simple_SOT); + + Operator *opLM = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + if (useMobility) // non-constant mobility + opLM->addTerm(new VecAtQP_SOT( + prob->getSolution()->getDOFVector(0), + new MobilityPfc(density, rho0))); + else // constant mobility + opLM->addTerm(new Simple_SOT); + + // -(1+r)*phi*rho + Operator *opMTemp = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMTemp->addZeroOrderTerm(new Simple_ZOT()); + // -2*rho_old^3 + Operator *opMPowExpl = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMPowExpl->addZeroOrderTerm(new VecAtQP_ZOT(prob->getSolution()->getDOFVector(0),new Pow3Functor(-2.0))); + // -3*rho_old^2 + Operator *opMPowImpl = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMPowImpl->addZeroOrderTerm(new VecAtQP_ZOT(prob->getSolution()->getDOFVector(0),new Pow2Functor(-3.0))); + + // 0 = nu-laplace(rho) + // ------------------- + prob->addMatrixOperator(opL, 0, 0); // -laplace(rho) + prob->addMatrixOperator(opMnew, 0, 2); // nu + setAssembleMatrixOnlyOnce_butTimestepChange(0,0); + setAssembleMatrixOnlyOnce_butTimestepChange(0,2); + + // dt(rho) = laplace(mu) - u*grad(rho) + // ----------------------------------- + prob->addMatrixOperator(opMnew, 1, 0, getInvTau(), getInvTau()); + prob->addMatrixOperator(opLM, 1, 1); // -laplace(mu) + // . . . vectorOperators . . . . . . . . . . . . . . . + prob->addVectorOperator(opMold, 1, getInvTau(), getInvTau()); + setAssembleMatrixOnlyOnce_butTimestepChange(1,0); + if (!useMobility) + setAssembleMatrixOnlyOnce_butTimestepChange(1,1); + + // mu-2*nu-laplace(nu)-(1+r)*rho = (rho_old^3) + ExtPot - eps^2/(rho_old+0.9) + // ---------------------------------------------------------------------- + prob->addMatrixOperator(opMTemp, 2, 0, getTempParameter(), getTempParameter()); // -phi*(1+r)*rho + prob->addMatrixOperator(opMPowImpl, 2, 0); // -3*rho*rho_old^2 + prob->addMatrixOperator(opL, 2, 0, &two, &two); // -2*phi*laplace(rho) * psi + prob->addMatrixOperator(opMnew, 2, 1); // phi*mu * psi + prob->addMatrixOperator(opL, 2, 2); // phi*grad(nu) * grad(psi) + // prob.addMatrixOperator(opMnew,2,2,&minus2); + // . . . vectorOperators . . . . . . . . . . . . . . . + prob->addVectorOperator(opMPowExpl, 2); // -2*phi^old*rho_old^3 + + setAssembleMatrixOnlyOnce_butTimestepChange(2,1); + setAssembleMatrixOnlyOnce_butTimestepChange(2,2); +}; + + +void PhaseFieldCrystal::fillBoundaryConditions() +{ FUNCNAME("PhaseFieldCrystal::fillBoundaryConditions()"); +}; diff --git a/extensions/base_problems/PhaseFieldCrystal_Base.h b/extensions/base_problems/PhaseFieldCrystal_Base.h new file mode 100644 index 0000000000000000000000000000000000000000..7e3937838e67a4d928b6f5ca848ac9a1c58ab465 --- /dev/null +++ b/extensions/base_problems/PhaseFieldCrystal_Base.h @@ -0,0 +1,109 @@ +/** \file PhaseFieldCrystal.h */ + +#ifndef PHASE_FIELD_CRYSTAL_H +#define PHASE_FIELD_CRYSTAL_H + +#include "AMDiS.h" +#include "BaseProblem.h" + +using namespace AMDiS; + +/** Phase-field Crystal problem + */ +class PhaseFieldCrystal : public StandardBaseProblem +{ +public: // typedefs + + typedef StandardBaseProblem super; + +public: + + PhaseFieldCrystal(const std::string &name_); + ~PhaseFieldCrystal() {}; + + double *getTempParameter() { return &tempParameter; } + +protected: + + virtual void fillOperators(); + virtual void fillBoundaryConditions(); + +protected: + + bool useMobility; + + double tempParameter; + double r; + double rho0; + double density; + double two; + double minus2; +}; + + +/** \ingroup MainInstat + * \brief + * Abstract function to calculate the pure PFC-Energy + */ +class Energy : public BinaryAbstractFunction<double,double,double> +{ + public: + Energy() : BinaryAbstractFunction<double,double,double>(4) { } + + double operator()(const double &rho, const double &mu) const { + return -0.25*sqr(sqr(rho)) + 0.5*rho*mu; } +}; + + +class MobilityPfc : public AbstractFunction<double,double> +{ + public: + MobilityPfc(double density_ = -0.3, double factor_ = 1.0) : + AbstractFunction<double,double>(1), + density(density_), + factor(factor_), + delta(1.e-6) { } + + double operator()(const double &rho) const + { + double mobility= abs(rho - 3.0*density)*factor; + return std::max(mobility, delta); + } + + protected: + double density; + double factor; + double delta; +}; + +class Pow2Functor : public AbstractFunction<double,double> +{ + public: + Pow2Functor(double factor_=1.0) : + AbstractFunction<double,double>(2), + factor(factor_) { } + double operator()(const double &ch) const + { + return factor * sqr(ch); + } + + protected: + double factor; +}; + +class Pow3Functor : public AbstractFunction<double,double> +{ + public: + Pow3Functor(double factor_=1.0) : + AbstractFunction<double,double>(3), + factor(factor_) { } + double operator()(const double &ch) const + { + return factor * sqr(ch) * ch; + } + + protected: + double factor; +}; + +#endif // PHASE_FIELD_CRYSTAL_H diff --git a/extensions/base_problems/PhaseFieldCrystal_Phase.cc b/extensions/base_problems/PhaseFieldCrystal_Phase.cc new file mode 100644 index 0000000000000000000000000000000000000000..96978b149dceef1132e2cb30abac37b20d1df2c7 --- /dev/null +++ b/extensions/base_problems/PhaseFieldCrystal_Phase.cc @@ -0,0 +1,83 @@ +#include "PhaseFieldCrystal_Phase.h" + +using namespace std; +using namespace AMDiS; + +PhaseFieldCrystal_Phase::PhaseFieldCrystal_Phase(const std::string &name_) : + PhaseFieldCrystal(name_), + phase(NULL), + phaseDisturbed(NULL) +{}; + + +PhaseFieldCrystal_Phase::~PhaseFieldCrystal_Phase() +{ + delete phase; + delete phaseDisturbed; +} + + +void PhaseFieldCrystal_Phase::initTimeInterface() +{ FUNCNAME("PhaseFieldCrystal_Phase::initTimeInterface()"); + + PhaseFieldCrystal::initTimeInterface(); +}; + + +void PhaseFieldCrystal_Phase::fillOperators() +{ FUNCNAME("PhaseFieldCrystal_Phase::fillOperators()"); + MSG_DBG("PhaseFieldCrystal_Phase::fillOperators()\n"); + + // phi*rho + Operator *opMnew = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMnew->addTerm(new Phase_ZOT(phaseDisturbed)); + Operator *opMold = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMold->addTerm(new Phase_ZOT(phaseDisturbed)); + + // -nabla*(phi*grad(rho)) + Operator *opL = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opL->addTerm(new Phase_SOT(phaseDisturbed)); + + Operator *opLM = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + if (useMobility) // non-constant mobility + opLM->addTerm(new Vec2AtQP_SOT( + phaseDisturbed, + prob->getSolution()->getDOFVector(0), + new MobilityPhasePfc(density, rho0))); + else // constant mobility + opLM->addTerm(new Phase_SOT(phaseDisturbed)); + + // -(1+r)*phi*rho + Operator *opMTemp = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMTemp->addZeroOrderTerm(new Phase_ZOT(phaseDisturbed)); + // -2*rho_old^3 + Operator *opMPowExpl = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMPowExpl->addZeroOrderTerm(new Pow3Phase_ZOT(phaseDisturbed,prob->getSolution()->getDOFVector(0),-2.0)); + // -3*rho_old^2 + Operator *opMPowImpl = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opMPowImpl->addZeroOrderTerm(new Pow2Phase_ZOT(phaseDisturbed,prob->getSolution()->getDOFVector(0),-3.0)); + + // 0 = nu-laplace(rho) + // ------------------- + prob->addMatrixOperator(opL, 0, 0); // -laplace(rho) + prob->addMatrixOperator(opMnew, 0, 2); // nu + + // dt(rho) = laplace(mu) - u*grad(rho) + // ----------------------------------- + prob->addMatrixOperator(opMnew, 1, 0, getInvTau()); + prob->addMatrixOperator(opLM, 1, 1); // -laplace(mu) + // . . . vectorOperators . . . . . . . . . . . . . . . + opMold->setUhOld(prob->getSolution()->getDOFVector(0)); + prob->addVectorOperator(opMold, 1, getInvTau()); + + // mu-2*nu-laplace(nu)-(1+r)*rho = (rho_old^3) + ExtPot - eps^2/(rho_old+0.9) + // ---------------------------------------------------------------------- + prob->addMatrixOperator(opMTemp, 2, 0, getTempParameter()); // -phi*(1+r)*rho + prob->addMatrixOperator(opMPowImpl, 2, 0); // -3*rho*rho_old^2 + prob->addMatrixOperator(opL, 2, 0, &two); // -2*phi*laplace(rho) * psi + prob->addMatrixOperator(opMnew, 2, 1); // phi*mu * psi + prob->addMatrixOperator(opL, 2, 2); // phi*grad(nu) * grad(psi) + // prob.addMatrixOperator(opMnew,2,2,&minus2); + // . . . vectorOperators . . . . . . . . . . . . . . . + prob->addVectorOperator(opMPowExpl, 2); // -2*phi^old*rho_old^3 +}; diff --git a/extensions/base_problems/PhaseFieldCrystal_Phase.h b/extensions/base_problems/PhaseFieldCrystal_Phase.h new file mode 100644 index 0000000000000000000000000000000000000000..38bb9ef72bdb53a1121f769d3a500aa4d96af917 --- /dev/null +++ b/extensions/base_problems/PhaseFieldCrystal_Phase.h @@ -0,0 +1,85 @@ +/** \file PhaseFieldCrystal_Phase.h */ + +#ifndef PHASE_FIELD_CRYSTAL_PHASE_H +#define PHASE_FIELD_CRYSTAL_PHASE_H + +#include "PhaseFieldCrystal.h" +#include "PhaseFieldConvert.h" + +using namespace AMDiS; + +/** Phase-field Crystal problem in diffuse domain + */ +class PhaseFieldCrystal_Phase : public PhaseFieldCrystal +{ +public: // typedefs + + typedef NavierStokes_Chorin super; + +public: // methods + + PhaseFieldCrystal_Phase(const std::string &name_); + ~PhaseFieldCrystal_Phase(); + + void initTimeInterface(); + + DOFVector<double> *getPhase() + { + return phase; + } + + void setPhase(DOFVector<double>* phase_) + { + if (phase == NULL) + phase = new DOFVector<double>(prob->getFeSpace(0), "phase"); + if (phaseDisturbed == NULL) + phaseDisturbed = new DOFVector<double>(prob->getFeSpace(0), "phaseDisturbed"); + + phase->interpol(phase_); + transformDOF(phase, 1.e-6, phaseDisturbed, new Max<double>); + }; + +protected: // methods + + void fillOperators(); + +private: // variables + + DOFVector<double> *phase; + DOFVector<double> *phaseDisturbed; +}; + + +///Abstract function to calculate the pure PFC-Energy +class EnergyPhase : public TertiaryAbstractFunction<double,double,double,double> +{ + public: + EnergyPhase() : TertiaryAbstractFunction<double,double,double,double>(5) { } + + double operator()(const double &phase, const double &rho, const double &mu) const { + return phase * (-0.25*sqr(sqr(rho)) + 0.5*rho*mu); } +}; + +/// AbstractFunction that defines the pfc-mobility, depending on the density an minimal density +class MobilityPhasePfc : public BinaryAbstractFunction<double,double,double> +{ + public: + MobilityPhasePfc(double density_ = -0.3, double factor_ = 1.0) : + BinaryAbstractFunction<double,double,double>(2), + density(density_), + factor(factor_), + delta(1.e-6) { } + + double operator()(const double &phase, const double &rho) const + { + double mobility= abs(rho - 3.0*density)*factor; + return std::max(phase*mobility, delta); + } + + protected: + double density; + double factor; + double delta; +}; + +#endif // PHASE_FIELD_CRYSTAL_PHASE_H diff --git a/extensions/base_problems/PhaseFieldCrystal_RB.cc b/extensions/base_problems/PhaseFieldCrystal_RB.cc new file mode 100644 index 0000000000000000000000000000000000000000..9f2935c93391ecbb5b0ee05d8163dc118713b9ae --- /dev/null +++ b/extensions/base_problems/PhaseFieldCrystal_RB.cc @@ -0,0 +1,105 @@ +#include "PhaseFieldCrystal_RB.h" + +using namespace std; +using namespace AMDiS; + +PhaseFieldCrystal::PhaseFieldCrystal(const std::string &name_) : + super(name_), + useMobility(false), + tempParameter(-0.6), + r(-0.4), // temperature deviation + rho0(1.0), // liquid density + density(-0.3), // mean density + two(2.0), + minus2(-2.0), + minus1(-1.0) +{ + Parameters::get(name + "->r",r); + Parameters::get(name + "->rho0", rho0); + Parameters::get(name + "->density", density); + Parameters::get(name + "->use mobility", useMobility); + tempParameter= -(1.0+r); +}; + + +void PhaseFieldCrystal::fillOperators() +{ FUNCNAME("PhaseFieldCrystal::fillOperators()"); + + // rho + Operator *opMnu = new Operator(prob->getFeSpace(0), prob->getFeSpace(2)); + opMnu->addTerm(new Simple_ZOT); + Operator *opMmu = new Operator(prob->getFeSpace(2), prob->getFeSpace(1)); + opMmu->addTerm(new Simple_ZOT); + Operator *opMr = new Operator(prob->getFeSpace(2), prob->getFeSpace(0)); + opMr->addTerm(new Simple_ZOT(tempParameter)); + + // -nabla*(grad(rho)) + Operator *opL = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + opL->addTerm(new Simple_SOT); + Operator *opL2 = new Operator(prob->getFeSpace(2), prob->getFeSpace(0)); + opL2->addTerm(new Simple_SOT(2.0)); + Operator *opLnu = new Operator(prob->getFeSpace(2), prob->getFeSpace(2)); + opLnu->addTerm(new Simple_SOT); + + Operator *opLM = new Operator(prob->getFeSpace(0), prob->getFeSpace(0)); + if (useMobility) // non-constant mobility + opLM->addTerm(new VecAtQP_SOT( + prob->getSolution()->getDOFVector(0), + new MobilityPfc(density, rho0))); + else // constant mobility + opLM->addTerm(new Simple_SOT); + + // -rho_old^3 + Operator *opMPowExpl = new Operator(prob->getFeSpace(2), prob->getFeSpace(0)); + opMPowExpl->addZeroOrderTerm(new VecAtQP_ZOT( + prob->getStageSolution(0), new Pow3Functor(-1.0))); + // 3*rho_old^2 + Operator *opMPowImpl = new Operator(prob->getFeSpace(2), prob->getFeSpace(0)); + opMPowImpl->addZeroOrderTerm(new VecAtQP_ZOT( + prob->getUnVec(0), new Pow2Functor(3.0))); + + // 0 = nu-laplace(rho) + // ------------------- + opL->setUhOld(prob->getStageSolution(0)); + prob->addVectorOperator(opL, 0); // -laplace(rho) + prob->addMatrixOperator(opL, 0, 0, &minus1); // -laplace(rho) + + opMnu->setUhOld(prob->getStageSolution(2)); + prob->addVectorOperator(opMnu, 0); // nu + prob->addMatrixOperator(opMnu, 0, 2, &minus1); // nu + + // dt(rho) = laplace(mu) - u*grad(rho) + // ----------------------------------- + prob->addTimeOperator(1, 0); // dt(rho) + + opLM->setUhOld(prob->getStageSolution(1)); + prob->addVectorOperator(opLM, 1, &minus1); // -laplace(mu) + prob->addMatrixOperator(opLM, 1, 1); // -laplace(mu) + + // mu-2*nu-laplace(nu)-(1+r)*rho = (rho_old^3) + ExtPot - eps^2/(rho_old+0.9) + // ---------------------------------------------------------------------- + opMr->setUhOld(prob->getStageSolution(0)); + prob->addVectorOperator(opMr, 2); // -(1+r)*rho + prob->addMatrixOperator(opMr, 2, 0, &minus1); // -(1+r)*rho + + opL2->setUhOld(prob->getStageSolution(0)); + prob->addVectorOperator(opL2, 2); // -2*laplace(rho) + prob->addMatrixOperator(opL2, 2, 0, &minus1); // -2*laplace(rho) + + opMmu->setUhOld(prob->getStageSolution(1)); + prob->addVectorOperator(opMmu, 2); // mu + prob->addMatrixOperator(opMmu, 2, 1, &minus1); // mu + + opLnu->setUhOld(prob->getStageSolution(2)); + prob->addVectorOperator(opLnu, 2); // -laplace(nu) + prob->addMatrixOperator(opLnu, 2, 2, &minus1); // -laplace(nu) + + // . . . nonlinear terms . . . . . . . . . . . . . . . + prob->addMatrixOperator(opMPowImpl, 2, 0); // 3*rho*rho_old^2 + prob->addVectorOperator(opMPowExpl, 2); // -rho'^3 +}; + + +void PhaseFieldCrystal::fillBoundaryConditions() +{ FUNCNAME("PhaseFieldCrystal::fillBoundaryConditions()"); +}; diff --git a/extensions/base_problems/PhaseFieldCrystal_RB.h b/extensions/base_problems/PhaseFieldCrystal_RB.h new file mode 100644 index 0000000000000000000000000000000000000000..5765706eb8cd0bc5d71647aa638b22cd3a1c5e9f --- /dev/null +++ b/extensions/base_problems/PhaseFieldCrystal_RB.h @@ -0,0 +1,126 @@ +/** \file PhaseFieldCrystal.h */ + +#ifndef PHASE_FIELD_CRYSTAL_H +#define PHASE_FIELD_CRYSTAL_H + +#include "AMDiS.h" +#include "BaseProblem.h" +#include "time/RosenbrockStationary.h" + +using namespace AMDiS; + +/** Phase-field Crystal problem + */ +class PhaseFieldCrystal : public BaseProblem<RosenbrockStationary> +{ +public: // typedefs + + typedef BaseProblem<RosenbrockStationary> super; + +public: + + PhaseFieldCrystal(const std::string &name_); + ~PhaseFieldCrystal() {}; + +protected: + + virtual void fillOperators(); + virtual void fillBoundaryConditions(); + +protected: + + bool useMobility; + + double tempParameter; + double r; + double rho0; + double density; + double two; + double minus2; + double minus1; + +// Rosenbrock methods +//_________________________________________________________________________ + +public: + + void acceptTimestep() { prob->acceptTimestep(); } + void reset() { prob->reset(); } + + void setRosenbrockMethod(RosenbrockMethod *method) { prob->setRosenbrockMethod(method); } + void setTau(double *ptr) { prob->setTau(ptr); } + void setTauGamma(double *ptr0, double *ptr1, double *ptr2, double *ptr3) { prob->setTauGamma(ptr0,ptr1,ptr2,ptr3); } + + double* getTauGamma() { return prob->getTauGamma(); } + double* getMinusTauGamma() { return prob->getMinusTauGamma(); } + double* getInvTauGamma() { return prob->getInvTauGamma(); } + double* getMinusInvTauGamma() { return prob->getMinusInvTauGamma(); } +}; + + +/** \ingroup MainInstat + * \brief + * Abstract function to calculate the pure PFC-Energy + */ +class Energy : public BinaryAbstractFunction<double,double,double> +{ + public: + Energy() : BinaryAbstractFunction<double,double,double>(4) { } + + double operator()(const double &rho, const double &mu) const { + return -0.25*sqr(sqr(rho)) + 0.5*rho*mu; } +}; + + +class MobilityPfc : public AbstractFunction<double,double> +{ + public: + MobilityPfc(double density_ = -0.3, double factor_ = 1.0) : + AbstractFunction<double,double>(1), + density(density_), + factor(factor_), + delta(1.e-6) { } + + double operator()(const double &rho) const + { + double mobility= abs(rho - 3.0*density)*factor; + return std::max(mobility, delta); + } + + protected: + double density; + double factor; + double delta; +}; + +class Pow2Functor : public AbstractFunction<double,double> +{ + public: + Pow2Functor(double factor_=1.0) : + AbstractFunction<double,double>(2), + factor(factor_) { } + double operator()(const double &ch) const + { + return factor * sqr(ch); + } + + protected: + double factor; +}; + +class Pow3Functor : public AbstractFunction<double,double> +{ + public: + Pow3Functor(double factor_=1.0) : + AbstractFunction<double,double>(3), + factor(factor_) { } + double operator()(const double &ch) const + { + return factor * sqr(ch) * ch; + } + + protected: + double factor; +}; + +#endif // PHASE_FIELD_CRYSTAL_H diff --git a/extensions/kdtree_nanoflann.h b/extensions/kdtree_nanoflann.h new file mode 100644 index 0000000000000000000000000000000000000000..97c882d970f6c9567097a4ad03ca260459e31ba9 --- /dev/null +++ b/extensions/kdtree_nanoflann.h @@ -0,0 +1,139 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2011 Jose Luis Blanco (joseluisblancoc@gmail.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ + +#include <nanoflann.hpp> + +#include <cstdlib> +#include <iostream> + +#include "FixVec.h" + +using namespace nanoflann; +using namespace AMDiS; + +namespace experimental { + +// ===================================================================================== +typedef std::vector<WorldVector<double> > my_vector_of_vectors_t; +// ===================================================================================== + + +/** A simple vector-of-vectors adaptor for nanoflann, without duplicating the storage. + * The i'th vector represents a point in the state space. + * + * \tparam DIM If set to >0, it specifies a compile-time fixed dimensionality for the points in the data set, allowing more compiler optimizations. + * \tparam num_t The type of the point coordinates (typically, double or float). + * \tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. + * \tparam IndexType The type for indices in the KD-tree index (typically, size_t of int) + */ +template <class VectorOfVectorsType, typename num_t = double, int DIM = -1, class Distance = nanoflann::metric_L2_Simple, typename IndexType = size_t> +struct KDTreeVectorOfWorldVectorsAdaptor +{ + typedef KDTreeVectorOfWorldVectorsAdaptor<VectorOfVectorsType,num_t,DIM,Distance> self_t; + typedef typename Distance::template traits<num_t,self_t>::distance_t metric_t; + typedef KDTreeSingleIndexAdaptor< metric_t,self_t,DIM,IndexType> index_t; + + index_t* index; //! The kd-tree index for the user to call its methods as usual with any other FLANN index. + + /// Constructor: takes a const ref to the vector of vectors object with the data points + KDTreeVectorOfWorldVectorsAdaptor(const int dimensionality, const VectorOfVectorsType &mat, const int leaf_max_size = 10) : m_data(mat) + { + assert(mat.size()!=0 && mat[0].getSize()!=0); + const size_t dims = mat[0].getSize(); + if (DIM>0 && static_cast<int>(dims)!=DIM) + throw std::runtime_error("Data set dimensionality does not match the 'DIM' template argument"); + index = new index_t( dims, *this /* adaptor */, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size, dims ) ); + index->buildIndex(); + } + + ~KDTreeVectorOfWorldVectorsAdaptor() { + delete index; + } + + const VectorOfVectorsType &m_data; + + /** Query for the \a num_closest closest points to a given point (entered as query_point[0:dim-1]). + * Note that this is a short-cut method for index->findNeighbors(). + * The user can also call index->... methods as desired. + * \note nChecks_IGNORED is ignored but kept for compatibility with the original FLANN interface. + */ + inline void query(const num_t *query_point, const size_t num_closest, IndexType *out_indices, num_t *out_distances_sq, const int nChecks_IGNORED = 10) const + { + nanoflann::KNNResultSet<typename VectorOfVectorsType::Scalar,IndexType> resultSet(num_closest); + resultSet.init(out_indices, out_distances_sq); + index->findNeighbors(resultSet, query_point, nanoflann::SearchParams()); + } + + /** @name Interface expected by KDTreeSingleIndexAdaptor + * @{ */ + + const self_t & derived() const { + return *this; + } + self_t & derived() { + return *this; + } + + // Must return the number of data points + inline size_t kdtree_get_point_count() const { + return m_data.size(); + } + + // Returns the distance between the vector "p1[0:size-1]" and the data point with index "idx_p2" stored in the class: + inline num_t kdtree_distance(const num_t *p1, const size_t idx_p2,size_t size) const + { + num_t s=0; + for (size_t i=0; i<size; i++) { + const num_t d= p1[i]-m_data[idx_p2][i]; + s+=d*d; + } + return s; + } + + // Returns the dim'th component of the idx'th point in the class: + inline num_t kdtree_get_pt(const size_t idx, int dim) const { + return m_data[idx][dim]; + } + + // Optional bounding-box computation: return false to default to a standard bbox computation loop. + // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again. + // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) + template <class BBOX> + bool kdtree_get_bbox(BBOX &bb) const { + return false; + } + + /** @} */ + +}; // end of KDTreeVectorOfVectorsAdaptor + +typedef KDTreeVectorOfWorldVectorsAdaptor< my_vector_of_vectors_t, double > KD_Tree; + +} // end namespace experimental + + diff --git a/extensions/kdtree_nanoflann_dof.h b/extensions/kdtree_nanoflann_dof.h new file mode 100644 index 0000000000000000000000000000000000000000..0e0f25454c0f1971256a4e87b808b065ceab3709 --- /dev/null +++ b/extensions/kdtree_nanoflann_dof.h @@ -0,0 +1,213 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2011 Jose Luis Blanco (joseluisblancoc@gmail.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ +/** \file kdtree_nanoflann_dof.h */ + +#ifndef KDTREE_NANOFLANN_DOF_H +#define KDTREE_NANOFLANN_DOF_H + +#include <nanoflann.hpp> + +#include <cstdlib> +#include <iostream> + +#include "AMDiS.h" + +using namespace nanoflann; +using namespace AMDiS; + +namespace experimental { + +// ===================================================================================== +typedef WorldVector<double> PointType; +typedef DOFVector<PointType> my_vector_of_vectors_t; +// ===================================================================================== + + + /** A simple vector-of-vectors adaptor for nanoflann, without duplicating the storage. + * The i'th vector represents a point in the state space. + * + * \tparam DIM If set to >0, it specifies a compile-time fixed dimensionality for the points in the data set, allowing more compiler optimizations. + * \tparam value_type The type of the point coordinates (typically, double or float). + * \tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. + * \tparam index_type The type for indices in the KD-tree index (typically, size_t of int) + */ + template < class VectorOfVectorsType, + typename value_type = double, + int DIM = -1, + class Distance = nanoflann::metric_L2_Simple, + typename index_type = DegreeOfFreedom > + struct KDTreeVectorOfWorldVectorsAdaptor + { + typedef KDTreeVectorOfWorldVectorsAdaptor< VectorOfVectorsType, + value_type, + DIM, + Distance > self_t; + typedef typename Distance::template traits<value_type, self_t>::distance_t metric_t; + typedef KDTreeSingleIndexAdaptor< metric_t, + self_t, + DIM, + index_type > index_t; + + index_t* index; //! The kd-tree index for the user to call its methods as usual with any other FLANN index. + + /// Constructor: takes a const ref to the vector of vectors object with the data points + KDTreeVectorOfWorldVectorsAdaptor(const int dimensionality, + VectorOfVectorsType &mat, + const int leaf_max_size = 10) : m_data(mat) + { + const size_t dims = (*mat.begin()).getSize(); + assert(mat.getUsedSize() != 0 && dims != 0); + if (DIM > 0 && static_cast<int>(dims) != DIM) + throw std::runtime_error("Data set dimensionality does not match the 'DIM' template argument"); + index = new index_t( dims, *this /* adaptor */, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size, dims ) ); + index->buildIndex(); + } + + ~KDTreeVectorOfWorldVectorsAdaptor() { + delete index; + } + + void reinit(const int leaf_max_size = 10) + { + delete index; + const size_t dims = (*m_data.begin()).getSize(); + index = new index_t( dims, *this /* adaptor */, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size, dims ) ); + index->buildIndex(); + } + + VectorOfVectorsType &m_data; + + /** Query for the \a num_closest closest points to a given point (entered as query_point[0:dim-1]). + * Note that this is a short-cut method for index->findNeighbors(). + * The user can also call index->... methods as desired. + * \note nChecks_IGNORED is ignored but kept for compatibility with the original FLANN interface. + */ + inline void query(const value_type *query_point, + const size_t num_closest, + index_type *out_indices, + value_type *out_distances_sq, + const int nChecks_IGNORED = 10) const + { + nanoflann::KNNResultSet<value_type, index_type> resultSet(num_closest); + resultSet.init(out_indices, out_distances_sq); + index->findNeighbors(resultSet, query_point, nanoflann::SearchParams()); + } + + /** @name Interface expected by KDTreeSingleIndexAdaptor + * @{ */ + + const self_t & derived() const { + return *this; + } + self_t & derived() { + return *this; + } + + // Must return the number of data points + inline size_t kdtree_get_point_count() const { + return m_data.getUsedSize(); + } + + // Returns the distance between the vector "p1[0:size-1]" and the data point with index "idx_p2" stored in the class: + inline value_type kdtree_distance(const value_type *p1, + const index_type idx_p2, + size_t size) const + { + value_type s = 0.0; + for (size_t i = 0; i < size; i++) { + const value_type d = p1[i] - m_data[idx_p2][i]; + s += d*d; + } + return s; + } + + // Returns the dim'th component of the idx'th point in the class: + inline value_type kdtree_get_pt(const index_type idx, size_t dim) const { + return m_data[idx][dim]; + } + + // Optional bounding-box computation: return false to default to a standard bbox computation loop. + // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again. + // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) + template <class BBOX> + bool kdtree_get_bbox(BBOX &bb) const { + return false; + } + + /** @} */ + + + /** + * strategy and nrOfPoints are ignored + * == evalAtPoint_simple + **/ + template<typename T> + T evalAtPoint(DOFVector<T>& vec, PointType& x, int strategy = 0, int nrOfPoints = -1) + { + const size_t nnp = 1; + std::vector<DegreeOfFreedom> ret_indexes(nnp); + std::vector<double> out_dists_sqr(nnp); + nanoflann::KNNResultSet<double, DegreeOfFreedom> resultSet(nnp); + + double eps = 0.0; + Parameters::get("KD-Tree->eps",eps); + resultSet.init(&ret_indexes[0], &out_dists_sqr[0]); + index->findNeighbors(resultSet, x.begin(), nanoflann::SearchParams(10, eps)); + + T value; nullify(value); + value = vec[ret_indexes[0]]; + return value; + } + + }; // end of KDTreeVectorOfVectorsAdaptor + + typedef KDTreeVectorOfWorldVectorsAdaptor< my_vector_of_vectors_t, double > KD_Tree; + static std::map<const FiniteElemSpace*, std::pair<int, KD_Tree*> > kdtreeMap; + + inline KD_Tree* provideKDTree(const FiniteElemSpace* feSpace) + { + if (kdtreeMap.find(feSpace) != kdtreeMap.end()) { + if (kdtreeMap[feSpace].first != feSpace->getMesh()->getChangeIndex()) { + feSpace->getMesh()->getDofIndexCoords(feSpace, kdtreeMap[feSpace].second->m_data); + kdtreeMap[feSpace].second->reinit(); + kdtreeMap[feSpace].first = feSpace->getMesh()->getChangeIndex(); + } + } else { + DOFVector<WorldVector<double> >* coords = new DOFVector<WorldVector<double> >(feSpace, "coords"); + feSpace->getMesh()->getDofIndexCoords(feSpace, *coords); + + KD_Tree* kdtree = new KD_Tree(Global::getGeo(WORLD), *coords); + kdtreeMap[feSpace] = std::make_pair(feSpace->getMesh()->getChangeIndex(), kdtree); + } + + return kdtreeMap[feSpace].second; + } + +} // end namespace + +#endif diff --git a/extensions/kdtree_nanoflann_mesh.h b/extensions/kdtree_nanoflann_mesh.h new file mode 100644 index 0000000000000000000000000000000000000000..dce0514ff9dbc98e61f6c2b02273bfe5aedf688b --- /dev/null +++ b/extensions/kdtree_nanoflann_mesh.h @@ -0,0 +1,272 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2011 Jose Luis Blanco (joseluisblancoc@gmail.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ +/** \file kdtree_nanoflann_mesh.h */ + +#ifndef KDTREE_NANOFLANN_MESH_H +#define KDTREE_NANOFLANN_MESH_H + +#include <nanoflann.hpp> + +#include <cstdlib> +#include <iostream> + +#include "AMDiS.h" + +using namespace nanoflann; +using namespace AMDiS; + +namespace experimental { + +// ===================================================================================== +typedef WorldVector<double> PointType; +typedef boost::tuple<const MacroElement*, int, unsigned long> DataType; +typedef std::vector<PointType> VectorOfPointsType; +typedef std::vector<DataType> VectorOfDataType; +// ===================================================================================== + + + /** A simple vector-of-vectors adaptor for nanoflann, without duplicating the storage. + * The i'th vector represents a point in the state space. + * + * \tparam DIM If set to >0, it specifies a compile-time fixed dimensionality for the points in the data set, allowing more compiler optimizations. + * \tparam value_type The type of the point coordinates (typically, double or float). + * \tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. + * \tparam index_type The type for indices in the KD-tree index (typically, size_t of int) + */ + template < class VectorOfPointsType_, + class VectorOfDataType_, + typename value_type = double, + int DIM = -1, + class Distance = nanoflann::metric_L2_Simple, + typename index_type = DegreeOfFreedom > + struct KDTreeMeshAdaptor + { + typedef KDTreeMeshAdaptor< VectorOfPointsType_, + value_type, + DIM, + Distance > self_t; + typedef typename Distance::template traits<value_type, self_t>::distance_t metric_t; + typedef KDTreeSingleIndexAdaptor< metric_t, + self_t, + DIM, + index_type > index_t; + + index_t* index; //! The kd-tree index for the user to call its methods as usual with any other FLANN index. + + /// Constructor: takes a const ref to the vector of vectors object with the data points + KDTreeVectorOfWorldVectorsAdaptor(const int dimensionality, + Mesh* mesh_, + const int leaf_max_size = 10) + : mesh(mesh_) + { + const size_t dims = Global::getGeo(WORLD); + if (mesh->getNumberOfLeaves() == 0) + mesh->updateNumberOfLeaves(); + + assert(mesh->getNumberOfLeaves() != 0 && dims != 0); + if (DIM > 0 && static_cast<int>(dims) != DIM) + throw std::runtime_error("Point dimensionality does not match the 'DIM' template argument"); + + init(); + + index = new index_t( dims, *this /* adaptor */, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size, dims ) ); + index->buildIndex(); + } + + ~KDTreeVectorOfWorldVectorsAdaptor() { + delete index; + } + + void init() + { + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS); + + int dim = mesh->getDim(); + while (elInfo) { + ElInfo* macroElInfo = mesh->createNewElInfo(); + macroElInfo->fillMacroInfo(elInfo->getMacroElement()); + stack.fillRefinementPath(*elInfo, *macroElInfo); + + DataType elInfoData = boost::tuples::make_tuple(elInfo->getMacroElement(), elInfo->getRefinementPathLength(), elInfo->getRefinementPath()); + + WorldVector<double> centroid = elInfo->getCoord(0); + for (int i = 1; i < dim+1; i++) + centroid += elInfo->getCoord(i); + centroid *= 1.0/(dim+1.0); + + m_points.push_back(centroid); + m_data.push_back(elInfoData); + + elInfo = stack.traverseNext(elInfo); + } + } + + void reinit(const int leaf_max_size = 10) + { + delete index; + const size_t dims = Global::getGeo(WORLD); + m_points.clear(); + m_data.clear(); + init(); + index = new index_t( dims, *this /* adaptor */, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size, dims ) ); + index->buildIndex(); + } + + VectorOfPointsType_ &m_points; + VectorOfDataType_ &m_data; + + /** Query for the \a num_closest closest points to a given point (entered as query_point[0:dim-1]). + * Note that this is a short-cut method for index->findNeighbors(). + * The user can also call index->... methods as desired. + * \note nChecks_IGNORED is ignored but kept for compatibility with the original FLANN interface. + */ + inline void query(const value_type *query_point, + const size_t num_closest, + index_type *out_indices, + value_type *out_distances_sq, + const int nChecks_IGNORED = 10) const + { + nanoflann::KNNResultSet<value_type, index_type> resultSet(num_closest); + resultSet.init(out_indices, out_distances_sq); + index->findNeighbors(resultSet, query_point, nanoflann::SearchParams()); + } + + /** @name Interface expected by KDTreeSingleIndexAdaptor + * @{ */ + + const self_t & derived() const { + return *this; + } + self_t & derived() { + return *this; + } + + // Must return the number of data points + inline size_t kdtree_get_point_count() const { + return m_points.getUsedSize(); + } + + // Returns the distance between the vector "p1[0:size-1]" and the data point with index "idx_p2" stored in the class: + inline value_type kdtree_distance(const value_type *p1, + const index_type idx_p2, + size_t size) const + { + value_type s = 0.0; + for (size_t i = 0; i < size; i++) { + const value_type d = p1[i] - m_points[idx_p2][i]; + s += d*d; + } + return s; + } + + // Returns the dim'th component of the idx'th point in the class: + inline value_type kdtree_get_pt(const index_type idx, size_t dim) const { + return m_points[idx][dim]; + } + + // Optional bounding-box computation: return false to default to a standard bbox computation loop. + // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again. + // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) + template <class BBOX> + bool kdtree_get_bbox(BBOX &bb) const { + return false; + } + + /** @} */ + + + /** + * strategy and nrOfPoints are ignored + * == evalAtPoint_simple + **/ + template<typename T> + T evalAtPoint(DOFVector<T>& vec, PointType& x, int strategy = 0, int nrOfPoints = -1) + { + ElInfo* elInfo = vec.getFeSpace()->getMesh()->createNewElInfo(); + elInfo->setFillFlag(Mesh::FILL_COORDS); + T value; nullify(value); + if (getNearestElInfo(x, elInfo)) { + int dim = vec.getFeSpace()->getMesh()->getDim(); + DimVec<double> lambda(dim, NO_INIT); + for (int i = 0; i < dim+1; i++) + lambda[i] = 1.0/std::max(1.e-8, norm(x - elInfo->getCoord(i))); + // normalize barycentric coords + double sum = 0.0; + for (int i = 0; i < dim+1; i++) + sum += lambda[i]; + for (int i = 0; i < dim+1; i++) + lambda[i] *= 1.0/sum; + + ElementFunctionDOFVec<T> elFct(&vec); + elFct.setElInfo(elInfo); + value = elFct(lambda); + } + return value; + } + + + bool getNearestElInfo(PointType &x, ElInfo*& elInfo) + { + const size_t nnp = 1; + std::vector<DegreeOfFreedom> ret_indexes(nnp); + std::vector<double> out_dists_sqr(nnp); + nanoflann::KNNResultSet<double, DegreeOfFreedom> resultSet(nnp); + + resultSet.init(&ret_indexes[0], &out_dists_sqr[0]); + index->findNeighbors(resultSet, x.begin(), nanoflann::SearchParams()); + + DataType data = m_data[ret_indexes[0]]; + elInfo->fillElInfo(data.get<0>(), data.get<1>(), data.get<2>()); + + return true; + } + + }; // end of KDTreeMeshAdaptor + + typedef KDTreeMeshAdaptor< VectorOfPointsType, VectorOfDataType, double > KD_Tree; + static std::map<const FiniteElemSpace*, std::pair<int, KD_Tree*> > kdtreeMap; + + inline KD_Tree* provideKDTree(const FiniteElemSpace* feSpace) + { + if (kdtreeMap.find(feSpace) != kdtreeMap.end()) { + if (kdtreeMap[feSpace].first != feSpace->getMesh()->getChangeIndex()) { + kdtreeMap[feSpace].second->reinit(); + kdtreeMap[feSpace].first = feSpace->getMesh()->getChangeIndex(); + } + } else { + KD_Tree* kdtree = new KD_Tree(Global::getGeo(WORLD), feSpace->getMesh()); + kdtreeMap[feSpace] = std::make_pair(feSpace->getMesh()->getChangeIndex(), kdtree); + } + + return kdtreeMap[feSpace].second; + } + +} // end namespace + +#endif diff --git a/extensions/nanoflann/CHANGELOG.txt b/extensions/nanoflann/CHANGELOG.txt new file mode 100644 index 0000000000000000000000000000000000000000..a33f5b632d4ff7ebe7c9787a68c328fd339dcf6b --- /dev/null +++ b/extensions/nanoflann/CHANGELOG.txt @@ -0,0 +1,36 @@ +nanoflann 1.1.3: Released Jun 6, 2012 + * GTest sources are now embedded, due to the changes in newer Ubuntu packages which don't carry the precompiled libs. + * Added asserts to detect whether the user passes NULL as query points. + * New method RadiusResultSet::worst_item() + * New method RadiusResultSet::set_radius_and_clear() + * Avoid potential collision of min/max macros with <windows.h> + * Removed unneeded #include's of std headers. + * New sample code for vectors of vectors. + * Fixed building of tests for MSVC in Windows. + * Allow manually setting the path to Eigen3 (mainly for building examples under Windows). + +nanoflann 1.1.2: Released May 2, 2012 + * Better documentation and added graphs of a benchmarking for helping choosing "leaf_max_size". + * Now KDTreeSingleIndexAdaptor::buildIndex() can be called several times + even when the dataset size changes (Thanks to Rob McDonald for reporting!) + +nanoflann 1.1.1: Released Feb 1, 2012 + * Some fixes to kd_tree index and L1/L2 metrics to allow distinct types + in data elements and in the distances. This is mainly to permit elements + being vectors of integers (e.g. uint8_t) but distances being real numbers. + * Examples and unit tests have been corrected to use template arguments + instead of being hard-wired to "float" data types (Thanks Thomas Vincent + for noticing!). + +nanoflann 1.1.0: Released Dec 15, 2011 + * Fixed warnings for MSVC and for GCC with "-Wall -pedantic" + * Updated performance tests to work with the final nanoflann code (they were + written for a very early version). + * All main classes now have new template arguments for the type of indice, + which now defaults to "size_t" instead of "int". In case this breaks + backward compatibility in user code, especify "int" to override the default + template arguments, although "size_t" it's recommended. + +nanoflann 1.0.0: Released Aug 30, 2011 + * Initial version + diff --git a/extensions/nanoflann/COPYING b/extensions/nanoflann/COPYING new file mode 100644 index 0000000000000000000000000000000000000000..bdc4cfec258c46e93604320b80c59cfaa42156e7 --- /dev/null +++ b/extensions/nanoflann/COPYING @@ -0,0 +1,29 @@ +Software License Agreement (BSD License) + +Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. +Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. +Copyright 2011 Jose L. Blanco (joseluisblancoc@gmail.com). All rights reserved. + +THE BSD LICENSE + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/extensions/nanoflann/nanoflann.hpp b/extensions/nanoflann/nanoflann.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4b997a69ba49bdf977ec8c5d47054c44f6737fa6 --- /dev/null +++ b/extensions/nanoflann/nanoflann.hpp @@ -0,0 +1,1302 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. + * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. + * Copyright 2011 Jose Luis Blanco (joseluisblancoc@gmail.com). + * All rights reserved. + * + * THE BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ + +#ifndef NANOFLANN_HPP_ +#define NANOFLANN_HPP_ + +#include <vector> +#include <cassert> +#include <algorithm> +#include <stdexcept> +#include <cstdio> // for fwrite() +#include <cmath> // for fabs(),... +#include <limits> + +// Avoid conflicting declaration of min/max macros in windows headers +#if !defined(NOMINMAX) && (defined(_WIN32) || defined(_WIN32_) || defined(WIN32) || defined(_WIN64)) +# define NOMINMAX +# ifdef max +# undef max +# undef min +# endif +#endif + +namespace nanoflann +{ +/** @addtogroup nanoflann_grp nanoflann C++ library for ANN + * @{ */ + + /** Library version: 0xMmP (M=Major,m=minor,P=path) */ + #define NANOFLANN_VERSION 0x113 + + /** @addtogroup result_sets_grp Result set classes + * @{ */ + template <typename DistanceType, typename IndexType = size_t, typename CountType = size_t> + class KNNResultSet + { + IndexType * indices; + DistanceType* dists; + CountType capacity; + CountType count; + + public: + inline KNNResultSet(CountType capacity_) : capacity(capacity_), count(0) + { + } + + inline void init(IndexType* indices_, DistanceType* dists_) + { + indices = indices_; + dists = dists_; + count = 0; + dists[capacity-1] = (std::numeric_limits<DistanceType>::max)(); + } + + inline CountType size() const + { + return count; + } + + inline bool full() const + { + return count == capacity; + } + + + inline void addPoint(DistanceType dist, IndexType index) + { + CountType i; + for (i=count; i>0; --i) { +#ifdef NANOFLANN_FIRST_MATCH // If defined and two poins have the same distance, the one with the lowest-index will be returned first. + if ( (dists[i-1]>dist) || ((dist==dists[i-1])&&(indices[i-1]>index)) ) { +#else + if (dists[i-1]>dist) { +#endif + if (i<capacity) { + dists[i] = dists[i-1]; + indices[i] = indices[i-1]; + } + } + else break; + } + if (i<capacity) { + dists[i] = dist; + indices[i] = index; + } + if (count<capacity) count++; + } + + inline DistanceType worstDist() const + { + return dists[capacity-1]; + } + }; + + + /** + * A result-set class used when performing a radius based search. + */ + template <typename DistanceType, typename IndexType = size_t> + class RadiusResultSet + { + public: + const DistanceType radius; + + std::vector<std::pair<IndexType,DistanceType> >& m_indices_dists; + + inline RadiusResultSet(DistanceType radius_, std::vector<std::pair<IndexType,DistanceType> >& indices_dists) : radius(radius_), m_indices_dists(indices_dists) + { + init(); + } + + inline ~RadiusResultSet() { } + + inline void init() { clear(); } + inline void clear() { m_indices_dists.clear(); } + + inline size_t size() const { return m_indices_dists.size(); } + + inline bool full() const { return true; } + + inline void addPoint(DistanceType dist, IndexType index) + { + if (dist<radius) + m_indices_dists.push_back(std::make_pair<IndexType,DistanceType>(index,dist)); + } + + inline DistanceType worstDist() const { return radius; } + + /** Clears the result set and adjusts the search radius. */ + inline void set_radius_and_clear( const DistanceType r ) + { + radius = r; + clear(); + } + + /** + * Find the worst result (furtherest neighbor) without copying or sorting + * Pre-conditions: size() > 0 + */ + std::pair<IndexType,DistanceType> worst_item() const + { + if (m_indices_dists.empty()) throw std::runtime_error("Cannot invoke RadiusResultSet::worst_item() on an empty list of results."); + typedef typename std::vector<std::pair<IndexType,DistanceType> >::const_iterator DistIt; + DistIt it = std::max_element(m_indices_dists.begin(), m_indices_dists.end()); + return *it; + } + }; + + /** operator "<" for std::sort() */ + struct IndexDist_Sorter + { + /** PairType will be typically: std::pair<IndexType,DistanceType> */ + template <typename PairType> + inline bool operator()(const PairType &p1, const PairType &p2) const { + return p1.second < p2.second; + } + }; + + /** @} */ + + + /** @addtogroup loadsave_grp Load/save auxiliary functions + * @{ */ + template<typename T> + void save_value(FILE* stream, const T& value, size_t count = 1) + { + fwrite(&value, sizeof(value),count, stream); + } + + template<typename T> + void save_value(FILE* stream, const std::vector<T>& value) + { + size_t size = value.size(); + fwrite(&size, sizeof(size_t), 1, stream); + fwrite(&value[0], sizeof(T), size, stream); + } + + template<typename T> + void load_value(FILE* stream, T& value, size_t count = 1) + { + size_t read_cnt = fread(&value, sizeof(value), count, stream); + if (read_cnt != count) { + throw std::runtime_error("Cannot read from file"); + } + } + + + template<typename T> + void load_value(FILE* stream, std::vector<T>& value) + { + size_t size; + size_t read_cnt = fread(&size, sizeof(size_t), 1, stream); + if (read_cnt!=1) { + throw std::runtime_error("Cannot read from file"); + } + value.resize(size); + read_cnt = fread(&value[0], sizeof(T), size, stream); + if (read_cnt!=size) { + throw std::runtime_error("Cannot read from file"); + } + } + /** @} */ + + + /** @addtogroup metric_grp Metric (distance) classes + * @{ */ + + template<typename T> inline T abs(T x) { return (x<0) ? -x : x; } + template<> inline int abs<int>(int x) { return ::abs(x); } + template<> inline float abs<float>(float x) { return fabsf(x); } + template<> inline double abs<double>(double x) { return fabs(x); } + template<> inline long double abs<long double>(long double x) { return fabsl(x); } + + /** Manhattan distance functor (generic version, optimized for high-dimensionality data sets). + * Corresponding distance traits: nanoflann::metric_L1 + * \tparam T Type of the elements (e.g. double, float, uint8_t) + * \tparam DistanceType Type of distance variables (must be signed) (e.g. float, double, int64_t) + */ + template<class T, class DataSource, typename _DistanceType = T> + struct L1_Adaptor + { + typedef T ElementType; + typedef _DistanceType DistanceType; + + const DataSource &data_source; + + L1_Adaptor(const DataSource &_data_source) : data_source(_data_source) { } + + inline DistanceType operator()(const T* a, const size_t b_idx, size_t size, DistanceType worst_dist = -1) const + { + DistanceType result = DistanceType(); + const T* last = a + size; + const T* lastgroup = last - 3; + size_t d = 0; + + /* Process 4 items with each loop for efficiency. */ + while (a < lastgroup) { + const DistanceType diff0 = nanoflann::abs(a[0] - data_source.kdtree_get_pt(b_idx,d++)); + const DistanceType diff1 = nanoflann::abs(a[1] - data_source.kdtree_get_pt(b_idx,d++)); + const DistanceType diff2 = nanoflann::abs(a[2] - data_source.kdtree_get_pt(b_idx,d++)); + const DistanceType diff3 = nanoflann::abs(a[3] - data_source.kdtree_get_pt(b_idx,d++)); + result += diff0 + diff1 + diff2 + diff3; + a += 4; + if ((worst_dist>0)&&(result>worst_dist)) { + return result; + } + } + /* Process last 0-3 components. Not needed for standard vector lengths. */ + while (a < last) { + result += nanoflann::abs( *a++ - data_source.kdtree_get_pt(b_idx,d++) ); + } + return result; + } + + template <typename U, typename V> + inline DistanceType accum_dist(const U a, const V b, int dim) const + { + return (a-b)*(a-b); + } + }; + + /** Squared Euclidean distance functor (generic version, optimized for high-dimensionality data sets). + * Corresponding distance traits: nanoflann::metric_L2 + * \tparam T Type of the elements (e.g. double, float, uint8_t) + * \tparam DistanceType Type of distance variables (must be signed) (e.g. float, double, int64_t) + */ + template<class T, class DataSource, typename _DistanceType = T> + struct L2_Adaptor + { + typedef T ElementType; + typedef _DistanceType DistanceType; + + const DataSource &data_source; + + L2_Adaptor(const DataSource &_data_source) : data_source(_data_source) { } + + inline DistanceType operator()(const T* a, const size_t b_idx, size_t size, DistanceType worst_dist = -1) const + { + DistanceType result = DistanceType(); + const T* last = a + size; + const T* lastgroup = last - 3; + size_t d = 0; + + /* Process 4 items with each loop for efficiency. */ + while (a < lastgroup) { + const DistanceType diff0 = a[0] - data_source.kdtree_get_pt(b_idx,d++); + const DistanceType diff1 = a[1] - data_source.kdtree_get_pt(b_idx,d++); + const DistanceType diff2 = a[2] - data_source.kdtree_get_pt(b_idx,d++); + const DistanceType diff3 = a[3] - data_source.kdtree_get_pt(b_idx,d++); + result += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3; + a += 4; + if ((worst_dist>0)&&(result>worst_dist)) { + return result; + } + } + /* Process last 0-3 components. Not needed for standard vector lengths. */ + while (a < last) { + const DistanceType diff0 = *a++ - data_source.kdtree_get_pt(b_idx,d++); + result += diff0 * diff0; + } + return result; + } + + template <typename U, typename V> + inline DistanceType accum_dist(const U a, const V b, int dim) const + { + return (a-b)*(a-b); + } + }; + + /** Squared Euclidean distance functor (suitable for low-dimensionality datasets, like 2D or 3D point clouds) + * Corresponding distance traits: nanoflann::metric_L2_Simple + * \tparam T Type of the elements (e.g. double, float, uint8_t) + * \tparam DistanceType Type of distance variables (must be signed) (e.g. float, double, int64_t) + */ + template<class T, class DataSource, typename _DistanceType = T> + struct L2_Simple_Adaptor + { + typedef T ElementType; + typedef _DistanceType DistanceType; + + const DataSource &data_source; + + L2_Simple_Adaptor(const DataSource &_data_source) : data_source(_data_source) { } + + inline DistanceType operator()(const T* a, const size_t b_idx, size_t size) const { + return data_source.kdtree_distance(a,b_idx,size); + } + + template <typename U, typename V> + inline DistanceType accum_dist(const U a, const V b, int dim) const + { + return (a-b)*(a-b); + } + }; + + /** Metaprogramming helper traits class for the L1 (Manhattan) metric */ + struct metric_L1 { + template<class T, class DataSource> + struct traits { + typedef L1_Adaptor<T,DataSource> distance_t; + }; + }; + /** Metaprogramming helper traits class for the L2 (Euclidean) metric */ + struct metric_L2 { + template<class T, class DataSource> + struct traits { + typedef L2_Adaptor<T,DataSource> distance_t; + }; + }; + /** Metaprogramming helper traits class for the L2_simple (Euclidean) metric */ + struct metric_L2_Simple { + template<class T, class DataSource> + struct traits { + typedef L2_Simple_Adaptor<T,DataSource> distance_t; + }; + }; + + /** @} */ + + + + /** @addtogroup param_grp Parameter structs + * @{ */ + + /** Parameters (see http://code.google.com/p/nanoflann/ for help choosing the parameters) + */ + struct KDTreeSingleIndexAdaptorParams + { + KDTreeSingleIndexAdaptorParams(size_t _leaf_max_size = 10, int dim_ = -1) : + leaf_max_size(_leaf_max_size), dim(dim_) + {} + + size_t leaf_max_size; + int dim; + }; + + /** Search options for KDTreeSingleIndexAdaptor::findNeighbors() */ + struct SearchParams + { + /** Note: The first argument (checks_IGNORED_) is ignored, but kept for compatibility with the FLANN interface */ + SearchParams(int checks_IGNORED_ = 32, float eps_ = 0, bool sorted_ = true ) : + eps(eps_), sorted(sorted_) {} + + int checks; //!< Ignored parameter (Kept for compatibility with the FLANN interface). + float eps; //!< search for eps-approximate neighbours (default: 0) + bool sorted; //!< only for radius search, require neighbours sorted by distance (default: true) + }; + /** @} */ + + + /** @addtogroup memalloc_grp Memory allocation + * @{ */ + + /** + * Allocates (using C's malloc) a generic type T. + * + * Params: + * count = number of instances to allocate. + * Returns: pointer (of type T*) to memory buffer + */ + template <typename T> + inline T* allocate(size_t count = 1) + { + T* mem = (T*) ::malloc(sizeof(T)*count); + return mem; + } + + + /** + * Pooled storage allocator + * + * The following routines allow for the efficient allocation of storage in + * small chunks from a specified pool. Rather than allowing each structure + * to be freed individually, an entire pool of storage is freed at once. + * This method has two advantages over just using malloc() and free(). First, + * it is far more efficient for allocating small objects, as there is + * no overhead for remembering all the information needed to free each + * object or consolidating fragmented memory. Second, the decision about + * how long to keep an object is made at the time of allocation, and there + * is no need to track down all the objects to free them. + * + */ + + const size_t WORDSIZE=16; + const size_t BLOCKSIZE=8192; + + class PooledAllocator + { + /* We maintain memory alignment to word boundaries by requiring that all + allocations be in multiples of the machine wordsize. */ + /* Size of machine word in bytes. Must be power of 2. */ + /* Minimum number of bytes requested at a time from the system. Must be multiple of WORDSIZE. */ + + + size_t remaining; /* Number of bytes left in current block of storage. */ + void* base; /* Pointer to base of current block of storage. */ + void* loc; /* Current location in block to next allocate memory. */ + size_t blocksize; + + + public: + size_t usedMemory; + size_t wastedMemory; + + /** + Default constructor. Initializes a new pool. + */ + PooledAllocator(const size_t blocksize = BLOCKSIZE) + { + this->blocksize = blocksize; + remaining = 0; + base = NULL; + + usedMemory = 0; + wastedMemory = 0; + } + + /** + * Destructor. Frees all the memory allocated in this pool. + */ + ~PooledAllocator() + { + while (base != NULL) { + void *prev = *((void**) base); /* Get pointer to prev block. */ + ::free(base); + base = prev; + } + } + + /** + * Returns a pointer to a piece of new memory of the given size in bytes + * allocated from the pool. + */ + void* malloc(const size_t req_size) + { + /* Round size up to a multiple of wordsize. The following expression + only works for WORDSIZE that is a power of 2, by masking last bits of + incremented size to zero. + */ + const size_t size = (req_size + (WORDSIZE - 1)) & ~(WORDSIZE - 1); + + /* Check whether a new block must be allocated. Note that the first word + of a block is reserved for a pointer to the previous block. + */ + if (size > remaining) { + + wastedMemory += remaining; + + /* Allocate new storage. */ + const size_t blocksize = (size + sizeof(void*) + (WORDSIZE-1) > BLOCKSIZE) ? + size + sizeof(void*) + (WORDSIZE-1) : BLOCKSIZE; + + // use the standard C malloc to allocate memory + void* m = ::malloc(blocksize); + if (!m) { + fprintf(stderr,"Failed to allocate memory.\n"); + return NULL; + } + + /* Fill first word of new block with pointer to previous block. */ + ((void**) m)[0] = base; + base = m; + + size_t shift = 0; + //int size_t = (WORDSIZE - ( (((size_t)m) + sizeof(void*)) & (WORDSIZE-1))) & (WORDSIZE-1); + + remaining = blocksize - sizeof(void*) - shift; + loc = ((char*)m + sizeof(void*) + shift); + } + void* rloc = loc; + loc = (char*)loc + size; + remaining -= size; + + usedMemory += size; + + return rloc; + } + + /** + * Allocates (using this pool) a generic type T. + * + * Params: + * count = number of instances to allocate. + * Returns: pointer (of type T*) to memory buffer + */ + template <typename T> + T* allocate(const size_t count = 1) + { + T* mem = (T*) this->malloc(sizeof(T)*count); + return mem; + } + + }; + /** @} */ + + + /** @addtogroup kdtrees_grp KD-tree classes and adaptors + * @{ */ + + /** kd-tree index + * + * Contains the k-d trees and other information for indexing a set of points + * for nearest-neighbor matching. + * + * The class "DatasetAdaptor" must provide the following interface (can be non-virtual, inlined methods): + * + * \code + * // Must return the number of data points + * inline size_t kdtree_get_point_count() const { ... } + * + * // Must return the Euclidean (L2) distance between the vector "p1[0:size-1]" and the data point with index "idx_p2" stored in the class: + * inline DistanceType kdtree_distance(const T *p1, const size_t idx_p2,size_t size) const { ... } + * + * // Must return the dim'th component of the idx'th point in the class: + * inline T kdtree_get_pt(const size_t idx, int dim) const { ... } + * + * // Optional bounding-box computation: return false to default to a standard bbox computation loop. + * // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again. + * // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) + * template <class BBOX> + * bool kdtree_get_bbox(BBOX &bb) const + * { + * bb[0].low = ...; bb[0].high = ...; // 0th dimension limits + * bb[1].low = ...; bb[1].high = ...; // 1st dimension limits + * ... + * return true; + * } + * + * \endcode + * + * \tparam IndexType Will be typically size_t or int + */ + template <typename Distance, class DatasetAdaptor,int DIM = -1, typename IndexType = size_t> + class KDTreeSingleIndexAdaptor + { + public: + typedef typename Distance::ElementType ElementType; + typedef typename Distance::DistanceType DistanceType; + protected: + + /** + * Array of indices to vectors in the dataset. + */ + std::vector<IndexType> vind; + + size_t m_leaf_max_size; + + + /** + * The dataset used by this index + */ + const DatasetAdaptor &dataset; //!< The source of our data + + const KDTreeSingleIndexAdaptorParams index_params; + + size_t m_size; + int dim; //!< Dimensionality of each data point + + + /*--------------------- Internal Data Structures --------------------------*/ + struct Node + { + union { + struct + { + /** + * Indices of points in leaf node + */ + IndexType left, right; + } lr; + struct + { + /** + * Dimension used for subdivision. + */ + int divfeat; + /** + * The values used for subdivision. + */ + DistanceType divlow, divhigh; + } sub; + }; + /** + * The child nodes. + */ + Node* child1, * child2; + }; + typedef Node* NodePtr; + + + struct Interval + { + ElementType low, high; + }; + + typedef std::vector<Interval> BoundingBox; + + + /** This record represents a branch point when finding neighbors in + the tree. It contains a record of the minimum distance to the query + point, as well as the node at which the search resumes. + */ + template <typename T, typename DistanceType> + struct BranchStruct + { + T node; /* Tree node at which search resumes */ + DistanceType mindist; /* Minimum distance to query for all nodes below. */ + + BranchStruct() {} + BranchStruct(const T& aNode, DistanceType dist) : node(aNode), mindist(dist) {} + + inline bool operator<(const BranchStruct<T, DistanceType>& rhs) const + { + return mindist<rhs.mindist; + } + }; + + /** + * Array of k-d trees used to find neighbours. + */ + NodePtr root_node; + typedef BranchStruct<NodePtr, DistanceType> BranchSt; + typedef BranchSt* Branch; + + BoundingBox root_bbox; + + /** + * Pooled memory allocator. + * + * Using a pooled memory allocator is more efficient + * than allocating memory directly when there is a large + * number small of memory allocations. + */ + PooledAllocator pool; + + public: + + Distance distance; + + /** + * KDTree constructor + * + * Params: + * inputData = dataset with the input features + * params = parameters passed to the kdtree algorithm (see http://code.google.com/p/nanoflann/ for help choosing the parameters) + */ + KDTreeSingleIndexAdaptor(const int dimensionality, const DatasetAdaptor& inputData, const KDTreeSingleIndexAdaptorParams& params = KDTreeSingleIndexAdaptorParams() ) : + dataset(inputData), index_params(params), distance(inputData) + { + m_size = dataset.kdtree_get_point_count(); + dim = dimensionality; + if (DIM>0) dim=DIM; + else { + if (params.dim>0) dim = params.dim; + } + m_leaf_max_size = params.leaf_max_size; + + // Create a permutable array of indices to the input vectors. + init_vind(); + } + + /** + * Standard destructor + */ + ~KDTreeSingleIndexAdaptor() + { + } + + /** + * Builds the index + */ + void buildIndex() + { + init_vind(); + computeBoundingBox(root_bbox); + root_node = divideTree(0, m_size, root_bbox ); // construct the tree + } + + /** + * Returns size of index. + */ + size_t size() const + { + return m_size; + } + + /** + * Returns the length of an index feature. + */ + size_t veclen() const + { + return static_cast<size_t>(DIM>0 ? DIM : dim); + } + + /** + * Computes the inde memory usage + * Returns: memory used by the index + */ + size_t usedMemory() const + { + return pool.usedMemory+pool.wastedMemory+dataset.kdtree_get_point_count()*sizeof(IndexType); // pool memory and vind array memory + } + + /** \name Query methods + * @{ */ + + /** + * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored inside + * the result object. + * + * Params: + * result = the result object in which the indices of the nearest-neighbors are stored + * vec = the vector for which to search the nearest neighbors + * + * \tparam RESULTSET Should be any ResultSet<DistanceType> + * \sa knnSearch, radiusSearch + */ + template <typename RESULTSET> + void findNeighbors(RESULTSET& result, const ElementType* vec, const SearchParams& searchParams) const + { + assert(vec); + float epsError = 1+searchParams.eps; + + std::vector<DistanceType> dists( (DIM>0 ? DIM : dim) ,0); + DistanceType distsq = computeInitialDistances(vec, dists); + searchLevel(result, vec, root_node, distsq, dists, epsError); // "count_leaf" parameter removed since was neither used nor returned to the user. + } + + /** + * Find the "num_closest" nearest neighbors to the \a query_point[0:dim-1]. Their indices are stored inside + * the result object. + * \sa radiusSearch, findNeighbors + * \note nChecks_IGNORED is ignored but kept for compatibility with the original FLANN interface. + */ + inline void knnSearch(const ElementType *query_point, const size_t num_closest, IndexType *out_indices, DistanceType *out_distances_sq, const int nChecks_IGNORED = 10) const + { + nanoflann::KNNResultSet<DistanceType,IndexType> resultSet(num_closest); + resultSet.init(out_indices, out_distances_sq); + this->findNeighbors(resultSet, query_point, nanoflann::SearchParams()); + } + + /** + * Find all the neighbors to \a query_point[0:dim-1] within a maximum radius. + * The output is given as a vector of pairs, of which the first element is a point index and the second the corresponding distance. + * Previous contents of \a IndicesDists are cleared. + * + * If searchParams.sorted==true, the output list is sorted by ascending distances. + * + * For a better performance, it is advisable to do a .reserve() on the vector if you have any wild guess about the number of expected matches. + * + * \sa knnSearch, findNeighbors + * \return The number of points within the given radius (i.e. indices.size() or dists.size() ) + */ + size_t radiusSearch(const ElementType *query_point,const DistanceType radius, std::vector<std::pair<IndexType,DistanceType> >& IndicesDists, const SearchParams& searchParams) const + { + RadiusResultSet<DistanceType,IndexType> resultSet(radius,IndicesDists); + this->findNeighbors(resultSet, query_point, searchParams); + + if (searchParams.sorted) + std::sort(IndicesDists.begin(),IndicesDists.end(), IndexDist_Sorter() ); + + return resultSet.size(); + } + + /** @} */ + + private: + /** Make sure the auxiliary list \a vind has the same size than the current dataset, and re-generate if size has changed. */ + void init_vind() + { + // Create a permutable array of indices to the input vectors. + m_size = dataset.kdtree_get_point_count(); + if (vind.size()!=m_size) + { + vind.resize(m_size); + for (size_t i = 0; i < m_size; i++) vind[i] = i; + } + } + + /// Helper accessor to the dataset points: + inline ElementType dataset_get(size_t idx, int component) const { + return dataset.kdtree_get_pt(idx,component); + } + + + void save_tree(FILE* stream, NodePtr tree) + { + save_value(stream, *tree); + if (tree->child1!=NULL) { + save_tree(stream, tree->child1); + } + if (tree->child2!=NULL) { + save_tree(stream, tree->child2); + } + } + + + void load_tree(FILE* stream, NodePtr& tree) + { + tree = pool.allocate<Node>(); + load_value(stream, *tree); + if (tree->child1!=NULL) { + load_tree(stream, tree->child1); + } + if (tree->child2!=NULL) { + load_tree(stream, tree->child2); + } + } + + + void computeBoundingBox(BoundingBox& bbox) + { + bbox.resize((DIM>0 ? DIM : dim)); + if (dataset.kdtree_get_bbox(bbox)) + { + // Done! It was implemented in derived class + } + else + { + for (int i=0; i<(DIM>0 ? DIM : dim); ++i) { + bbox[i].low = + bbox[i].high = dataset_get(0,i); + } + const size_t N = dataset.kdtree_get_point_count(); + for (size_t k=1; k<N; ++k) { + for (int i=0; i<(DIM>0 ? DIM : dim); ++i) { + if (dataset_get(k,i)<bbox[i].low) bbox[i].low = dataset_get(k,i); + if (dataset_get(k,i)>bbox[i].high) bbox[i].high = dataset_get(k,i); + } + } + } + } + + + /** + * Create a tree node that subdivides the list of vecs from vind[first] + * to vind[last]. The routine is called recursively on each sublist. + * Place a pointer to this new tree node in the location pTree. + * + * Params: pTree = the new node to create + * first = index of the first vector + * last = index of the last vector + */ + NodePtr divideTree(const IndexType left, const IndexType right, BoundingBox& bbox) + { + NodePtr node = pool.allocate<Node>(); // allocate memory + + /* If too few exemplars remain, then make this a leaf node. */ + if ( (right-left) <= m_leaf_max_size) { + node->child1 = node->child2 = NULL; /* Mark as leaf node. */ + node->lr.left = left; + node->lr.right = right; + + // compute bounding-box of leaf points + for (int i=0; i<(DIM>0 ? DIM : dim); ++i) { + bbox[i].low = dataset_get(vind[left],i); + bbox[i].high = dataset_get(vind[left],i); + } + for (IndexType k=left+1; k<right; ++k) { + for (int i=0; i<(DIM>0 ? DIM : dim); ++i) { + if (bbox[i].low>dataset_get(vind[k],i)) bbox[i].low=dataset_get(vind[k],i); + if (bbox[i].high<dataset_get(vind[k],i)) bbox[i].high=dataset_get(vind[k],i); + } + } + } + else { + IndexType idx; + int cutfeat; + DistanceType cutval; + middleSplit_(&vind[0]+left, right-left, idx, cutfeat, cutval, bbox); + + node->sub.divfeat = cutfeat; + + BoundingBox left_bbox(bbox); + left_bbox[cutfeat].high = cutval; + node->child1 = divideTree(left, left+idx, left_bbox); + + BoundingBox right_bbox(bbox); + right_bbox[cutfeat].low = cutval; + node->child2 = divideTree(left+idx, right, right_bbox); + + node->sub.divlow = left_bbox[cutfeat].high; + node->sub.divhigh = right_bbox[cutfeat].low; + + for (int i=0; i<(DIM>0 ? DIM : dim); ++i) { + bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low); + bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high); + } + } + + return node; + } + + void computeMinMax(IndexType* ind, IndexType count, int element, ElementType& min_elem, ElementType& max_elem) + { + min_elem = dataset_get(ind[0],element); + max_elem = dataset_get(ind[0],element); + for (IndexType i=1; i<count; ++i) { + ElementType val = dataset_get(ind[i],element); + if (val<min_elem) min_elem = val; + if (val>max_elem) max_elem = val; + } + } + + void middleSplit(IndexType* ind, IndexType count, IndexType& index, int& cutfeat, DistanceType& cutval, const BoundingBox& bbox) + { + // find the largest span from the approximate bounding box + ElementType max_span = bbox[0].high-bbox[0].low; + cutfeat = 0; + cutval = (bbox[0].high+bbox[0].low)/2; + for (int i=1; i<(DIM>0 ? DIM : dim); ++i) { + ElementType span = bbox[i].low-bbox[i].low; + if (span>max_span) { + max_span = span; + cutfeat = i; + cutval = (bbox[i].high+bbox[i].low)/2; + } + } + + // compute exact span on the found dimension + ElementType min_elem, max_elem; + computeMinMax(ind, count, cutfeat, min_elem, max_elem); + cutval = (min_elem+max_elem)/2; + max_span = max_elem - min_elem; + + // check if a dimension of a largest span exists + size_t k = cutfeat; + for (size_t i=0; i<(DIM>0 ? DIM : dim); ++i) { + if (i==k) continue; + ElementType span = bbox[i].high-bbox[i].low; + if (span>max_span) { + computeMinMax(ind, count, i, min_elem, max_elem); + span = max_elem - min_elem; + if (span>max_span) { + max_span = span; + cutfeat = i; + cutval = (min_elem+max_elem)/2; + } + } + } + IndexType lim1, lim2; + planeSplit(ind, count, cutfeat, cutval, lim1, lim2); + + if (lim1>count/2) index = lim1; + else if (lim2<count/2) index = lim2; + else index = count/2; + } + + + void middleSplit_(IndexType* ind, IndexType count, IndexType& index, int& cutfeat, DistanceType& cutval, const BoundingBox& bbox) + { + const DistanceType EPS=static_cast<DistanceType>(0.00001); + ElementType max_span = bbox[0].high-bbox[0].low; + for (int i=1; i<(DIM>0 ? DIM : dim); ++i) { + ElementType span = bbox[i].high-bbox[i].low; + if (span>max_span) { + max_span = span; + } + } + ElementType max_spread = -1; + cutfeat = 0; + for (int i=0; i<(DIM>0 ? DIM : dim); ++i) { + ElementType span = bbox[i].high-bbox[i].low; + if (span>(1-EPS)*max_span) { + ElementType min_elem, max_elem; + computeMinMax(ind, count, cutfeat, min_elem, max_elem); + ElementType spread = max_elem-min_elem;; + if (spread>max_spread) { + cutfeat = i; + max_spread = spread; + } + } + } + // split in the middle + DistanceType split_val = (bbox[cutfeat].low+bbox[cutfeat].high)/2; + ElementType min_elem, max_elem; + computeMinMax(ind, count, cutfeat, min_elem, max_elem); + + if (split_val<min_elem) cutval = min_elem; + else if (split_val>max_elem) cutval = max_elem; + else cutval = split_val; + + IndexType lim1, lim2; + planeSplit(ind, count, cutfeat, cutval, lim1, lim2); + + if (lim1>count/2) index = lim1; + else if (lim2<count/2) index = lim2; + else index = count/2; + } + + + /** + * Subdivide the list of points by a plane perpendicular on axe corresponding + * to the 'cutfeat' dimension at 'cutval' position. + * + * On return: + * dataset[ind[0..lim1-1]][cutfeat]<cutval + * dataset[ind[lim1..lim2-1]][cutfeat]==cutval + * dataset[ind[lim2..count]][cutfeat]>cutval + */ + void planeSplit(IndexType* ind, const IndexType count, int cutfeat, DistanceType cutval, IndexType& lim1, IndexType& lim2) + { + /* Move vector indices for left subtree to front of list. */ + IndexType left = 0; + IndexType right = count-1; + for (;; ) { + while (left<=right && dataset_get(ind[left],cutfeat)<cutval) ++left; + while (right && left<=right && dataset_get(ind[right],cutfeat)>=cutval) --right; + if (left>right || !right) break; // "!right" was added to support unsigned Index types + std::swap(ind[left], ind[right]); + ++left; + --right; + } + /* If either list is empty, it means that all remaining features + * are identical. Split in the middle to maintain a balanced tree. + */ + lim1 = left; + right = count-1; + for (;; ) { + while (left<=right && dataset_get(ind[left],cutfeat)<=cutval) ++left; + while (right && left<=right && dataset_get(ind[right],cutfeat)>cutval) --right; + if (left>right || !right) break; // "!right" was added to support unsigned Index types + std::swap(ind[left], ind[right]); + ++left; + --right; + } + lim2 = left; + } + + DistanceType computeInitialDistances(const ElementType* vec, std::vector<DistanceType>& dists) const + { + assert(vec); + DistanceType distsq = 0.0; + + for (int i = 0; i < (DIM>0 ? DIM : dim); ++i) { + if (vec[i] < root_bbox[i].low) { + dists[i] = distance.accum_dist(vec[i], root_bbox[i].low, i); + distsq += dists[i]; + } + if (vec[i] > root_bbox[i].high) { + dists[i] = distance.accum_dist(vec[i], root_bbox[i].high, i); + distsq += dists[i]; + } + } + + return distsq; + } + + /** + * Performs an exact search in the tree starting from a node. + * \tparam RESULTSET Should be any ResultSet<DistanceType> + */ + template <class RESULTSET> + void searchLevel(RESULTSET& result_set, const ElementType* vec, const NodePtr node, DistanceType mindistsq, + std::vector<DistanceType>& dists, const float epsError) const + { + /* If this is a leaf node, then do check and return. */ + if ((node->child1 == NULL)&&(node->child2 == NULL)) { + //count_leaf += (node->lr.right-node->lr.left); // Removed since was neither used nor returned to the user. + DistanceType worst_dist = result_set.worstDist(); + for (IndexType i=node->lr.left; i<node->lr.right; ++i) { + const IndexType index = vind[i];// reorder... : i; + DistanceType dist = distance(vec, index, (DIM>0 ? DIM : dim)); + if (dist<worst_dist) { + result_set.addPoint(dist,vind[i]); + } + } + return; + } + + /* Which child branch should be taken first? */ + int idx = node->sub.divfeat; + ElementType val = vec[idx]; + DistanceType diff1 = val - node->sub.divlow; + DistanceType diff2 = val - node->sub.divhigh; + + NodePtr bestChild; + NodePtr otherChild; + DistanceType cut_dist; + if ((diff1+diff2)<0) { + bestChild = node->child1; + otherChild = node->child2; + cut_dist = distance.accum_dist(val, node->sub.divhigh, idx); + } + else { + bestChild = node->child2; + otherChild = node->child1; + cut_dist = distance.accum_dist( val, node->sub.divlow, idx); + } + + /* Call recursively to search next level down. */ + searchLevel(result_set, vec, bestChild, mindistsq, dists, epsError); + + DistanceType dst = dists[idx]; + mindistsq = mindistsq + cut_dist - dst; + dists[idx] = cut_dist; + if (mindistsq*epsError<=result_set.worstDist()) { + searchLevel(result_set, vec, otherChild, mindistsq, dists, epsError); + } + dists[idx] = dst; + } + + + void saveIndex(FILE* stream) + { + save_value(stream, m_size); + save_value(stream, dim); + save_value(stream, root_bbox); + save_value(stream, m_leaf_max_size); + save_value(stream, vind); + save_tree(stream, root_node); + } + + void loadIndex(FILE* stream) + { + load_value(stream, m_size); + load_value(stream, dim); + load_value(stream, root_bbox); + load_value(stream, m_leaf_max_size); + load_value(stream, vind); + load_tree(stream, root_node); + } + + }; // class KDTree + + + /** A simple KD-tree adaptor for working with data directly stored in an Eigen Matrix, without duplicating the data storage. + * Each row in the matrix represents a point in the state space. + * + * Example of usage: + * \code + * Eigen::Matrix<num_t,Dynamic,Dynamic> mat; + * // Fill out "mat"... + * + * typedef KDTreeEigenMatrixAdaptor< Eigen::Matrix<num_t,Dynamic,Dynamic> > my_kd_tree_t; + * const int max_leaf = 10; + * my_kd_tree_t mat_index(dimdim, mat, max_leaf ); + * mat_index.index->buildIndex(); + * mat_index.index->... + * \endcode + * + * \tparam DIM If set to >0, it specifies a compile-time fixed dimensionality for the points in the data set, allowing more compiler optimizations. + * \tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc. + * \tparam IndexType The type for indices in the KD-tree index (typically, size_t of int) + */ + template <class MatrixType, int DIM = -1, class Distance = nanoflann::metric_L2, typename IndexType = size_t> + struct KDTreeEigenMatrixAdaptor + { + typedef KDTreeEigenMatrixAdaptor<MatrixType,DIM,Distance> self_t; + typedef typename MatrixType::Scalar num_t; + typedef typename Distance::template traits<num_t,self_t>::distance_t metric_t; + typedef KDTreeSingleIndexAdaptor< metric_t,self_t,DIM,IndexType> index_t; + + index_t* index; //! The kd-tree index for the user to call its methods as usual with any other FLANN index. + + /// Constructor: takes a const ref to the matrix object with the data points + KDTreeEigenMatrixAdaptor(const int dimensionality, const MatrixType &mat, const int leaf_max_size = 10) : m_data_matrix(mat) + { + const size_t dims = mat.cols(); + if (DIM>0 && static_cast<int>(dims)!=DIM) + throw std::runtime_error("Data set dimensionality does not match the 'DIM' template argument"); + index = new index_t( dims, *this /* adaptor */, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size, dims ) ); + index->buildIndex(); + } + + ~KDTreeEigenMatrixAdaptor() { + delete index; + } + + const MatrixType &m_data_matrix; + + /** Query for the \a num_closest closest points to a given point (entered as query_point[0:dim-1]). + * Note that this is a short-cut method for index->findNeighbors(). + * The user can also call index->... methods as desired. + * \note nChecks_IGNORED is ignored but kept for compatibility with the original FLANN interface. + */ + inline void query(const num_t *query_point, const size_t num_closest, IndexType *out_indices, num_t *out_distances_sq, const int nChecks_IGNORED = 10) const + { + nanoflann::KNNResultSet<typename MatrixType::Scalar,IndexType> resultSet(num_closest); + resultSet.init(out_indices, out_distances_sq); + index->findNeighbors(resultSet, query_point, nanoflann::SearchParams()); + } + + /** @name Interface expected by KDTreeSingleIndexAdaptor + * @{ */ + + const self_t & derived() const { + return *this; + } + self_t & derived() { + return *this; + } + + // Must return the number of data points + inline size_t kdtree_get_point_count() const { + return m_data_matrix.rows(); + } + + // Returns the distance between the vector "p1[0:size-1]" and the data point with index "idx_p2" stored in the class: + inline num_t kdtree_distance(const num_t *p1, const size_t idx_p2,size_t size) const + { + num_t s=0; + for (size_t i=0; i<size; i++) { + const num_t d= p1[i]-m_data_matrix.coeff(idx_p2,i); + s+=d*d; + } + return s; + } + + // Returns the dim'th component of the idx'th point in the class: + inline num_t kdtree_get_pt(const size_t idx, int dim) const { + return m_data_matrix.coeff(idx,dim); + } + + // Optional bounding-box computation: return false to default to a standard bbox computation loop. + // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again. + // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) + template <class BBOX> + bool kdtree_get_bbox(BBOX &bb) const { + return false; + } + + /** @} */ + + }; // end of KDTreeEigenMatrixAdaptor + /** @} */ + +/** @} */ // end of grouping +} // end of NS + + +#endif /* NANOFLANN_HPP_ */ diff --git a/extensions/nanoflann/version b/extensions/nanoflann/version new file mode 100644 index 0000000000000000000000000000000000000000..9c1218c201fd26e5fc200c5443872cbf14f1c947 --- /dev/null +++ b/extensions/nanoflann/version @@ -0,0 +1 @@ +1.1.3 \ No newline at end of file diff --git a/extensions/pugixml/contrib/foreach.hpp b/extensions/pugixml/contrib/foreach.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c413f1de712df9a41fc5350e3963b7443e154fbc --- /dev/null +++ b/extensions/pugixml/contrib/foreach.hpp @@ -0,0 +1,102 @@ +/* + * Boost.Foreach support for pugixml classes. + * This file is provided to the public domain. + * Written by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + */ + +#ifndef HEADER_PUGIXML_FOREACH_HPP +#define HEADER_PUGIXML_FOREACH_HPP + +#include "pugixml.hpp" + +/* + * These types add support for BOOST_FOREACH macro to xml_node and xml_document classes (child iteration only). + * Example usage: + * BOOST_FOREACH(xml_node n, doc) {} + */ + +namespace boost +{ + template <typename> struct range_mutable_iterator; + template <typename> struct range_const_iterator; + + template<> struct range_mutable_iterator<pugi::xml_node> + { + typedef pugi::xml_node::iterator type; + }; + + template<> struct range_const_iterator<pugi::xml_node> + { + typedef pugi::xml_node::iterator type; + }; + + template<> struct range_mutable_iterator<pugi::xml_document> + { + typedef pugi::xml_document::iterator type; + }; + + template<> struct range_const_iterator<pugi::xml_document> + { + typedef pugi::xml_document::iterator type; + }; +} + +/* + * These types add support for BOOST_FOREACH macro to xml_node and xml_document classes (child/attribute iteration). + * Example usage: + * BOOST_FOREACH(xml_node n, children(doc)) {} + * BOOST_FOREACH(xml_node n, attributes(doc)) {} + */ + +namespace pugi +{ + struct xml_node_children_adapter + { + typedef pugi::xml_node::iterator iterator; + typedef pugi::xml_node::iterator const_iterator; + + xml_node node; + + const_iterator begin() const + { + return node.begin(); + } + + const_iterator end() const + { + return node.end(); + } + }; + + xml_node_children_adapter children(const pugi::xml_node& node) + { + xml_node_children_adapter result = {node}; + return result; + } + + struct xml_node_attribute_adapter + { + typedef pugi::xml_node::attribute_iterator iterator; + typedef pugi::xml_node::attribute_iterator const_iterator; + + xml_node node; + + const_iterator begin() const + { + return node.attributes_begin(); + } + + const_iterator end() const + { + return node.attributes_end(); + } + }; + + xml_node_attribute_adapter attributes(const pugi::xml_node& node) + { + xml_node_attribute_adapter result = {node}; + return result; + } +} + +#endif diff --git a/extensions/pugixml/readme.txt b/extensions/pugixml/readme.txt new file mode 100644 index 0000000000000000000000000000000000000000..cf8892d0a98cc175affec3c1029619742787aab9 --- /dev/null +++ b/extensions/pugixml/readme.txt @@ -0,0 +1,52 @@ +pugixml 1.0 - an XML processing library + +Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +Report bugs and download new versions at http://pugixml.org/ + +This is the distribution of pugixml, which is a C++ XML processing library, +which consists of a DOM-like interface with rich traversal/modification +capabilities, an extremely fast XML parser which constructs the DOM tree from +an XML file/buffer, and an XPath 1.0 implementation for complex data-driven +tree queries. Full Unicode support is also available, with Unicode interface +variants and conversions between different Unicode encodings (which happen +automatically during parsing/saving). + +The distribution contains the following folders: + + contrib/ - various contributions to pugixml + + docs/ - documentation + docs/samples - pugixml usage examples + docs/quickstart.html - quick start guide + docs/manual.html - complete manual + + scripts/ - project files for IDE/build systems + + src/ - header and source files + + readme.txt - this file. + +This library is distributed under the MIT License: + +Copyright (c) 2006-2010 Arseny Kapoulkine + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/extensions/pugixml/src/pugiconfig.hpp b/extensions/pugixml/src/pugiconfig.hpp new file mode 100644 index 0000000000000000000000000000000000000000..90b81e11739e2a2b16efba281a6aafd10b558bdd --- /dev/null +++ b/extensions/pugixml/src/pugiconfig.hpp @@ -0,0 +1,62 @@ +/** + * pugixml parser - version 1.0 + * -------------------------------------------------------- + * Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Report bugs and download new versions at http://pugixml.org/ + * + * This library is distributed under the MIT License. See notice at the end + * of this file. + * + * This work is based on the pugxml parser, which is: + * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) + */ + +#ifndef HEADER_PUGICONFIG_HPP +#define HEADER_PUGICONFIG_HPP + +// Uncomment this to enable wchar_t mode +// #define PUGIXML_WCHAR_MODE + +// Uncomment this to disable XPath +// #define PUGIXML_NO_XPATH + +// Uncomment this to disable STL +// Note: you can't use XPath with PUGIXML_NO_STL +// #define PUGIXML_NO_STL + +// Uncomment this to disable exceptions +// Note: you can't use XPath with PUGIXML_NO_EXCEPTIONS +// #define PUGIXML_NO_EXCEPTIONS + +// Set this to control attributes for public classes/functions, i.e.: +// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL +// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL +// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall +// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead + +#endif + +/** + * Copyright (c) 2006-2010 Arseny Kapoulkine + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ diff --git a/extensions/pugixml/src/pugixml.cpp b/extensions/pugixml/src/pugixml.cpp new file mode 100644 index 0000000000000000000000000000000000000000..901731a9b8ff95295c8e84519797143b91d485aa --- /dev/null +++ b/extensions/pugixml/src/pugixml.cpp @@ -0,0 +1,9576 @@ +/** + * pugixml parser - version 1.0 + * -------------------------------------------------------- + * Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Report bugs and download new versions at http://pugixml.org/ + * + * This library is distributed under the MIT License. See notice at the end + * of this file. + * + * This work is based on the pugxml parser, which is: + * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) + */ + +#include "pugixml.hpp" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <setjmp.h> +#include <wchar.h> + +#ifndef PUGIXML_NO_XPATH +# include <math.h> +# include <float.h> +#endif + +#ifndef PUGIXML_NO_STL +# include <istream> +# include <ostream> +# include <string> +#endif + +// For placement new +#include <new> + +#ifdef _MSC_VER +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4324) // structure was padded due to __declspec(align()) +# pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable +# pragma warning(disable: 4702) // unreachable code +# pragma warning(disable: 4996) // this function or variable may be unsafe +#endif + +#ifdef __INTEL_COMPILER +# pragma warning(disable: 177) // function was declared but never referenced +# pragma warning(disable: 1478 1786) // function was declared "deprecated" +#endif + +#ifdef __BORLANDC__ +# pragma warn -8008 // condition is always false +# pragma warn -8066 // unreachable code +#endif + +#ifdef __SNC__ +# pragma diag_suppress=178 // function was declared but never referenced +# pragma diag_suppress=237 // controlling expression is constant +#endif + +// uintptr_t +#if !defined(_MSC_VER) || _MSC_VER >= 1600 +# include <stdint.h> +#else +# if _MSC_VER < 1300 +// No native uintptr_t in MSVC6 +typedef size_t uintptr_t; +# endif +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef __int32 int32_t; +#endif + +// Inlining controls +#if defined(_MSC_VER) && _MSC_VER >= 1300 +# define PUGIXML_NO_INLINE __declspec(noinline) +#elif defined(__GNUC__) +# define PUGIXML_NO_INLINE __attribute__((noinline)) +#else +# define PUGIXML_NO_INLINE +#endif + +// Simple static assertion +#define STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; } + +// Digital Mars C++ bug workaround for passing char loaded from memory via stack +#ifdef __DMC__ +# define DMC_VOLATILE volatile +#else +# define DMC_VOLATILE +#endif + +using namespace pugi; + +// Memory allocation +namespace +{ + void* default_allocate(size_t size) + { + return malloc(size); + } + + void default_deallocate(void* ptr) + { + free(ptr); + } + + allocation_function global_allocate = default_allocate; + deallocation_function global_deallocate = default_deallocate; +} + +// String utilities +namespace +{ + // Get string length + size_t strlength(const char_t* s) + { + assert(s); + + #ifdef PUGIXML_WCHAR_MODE + return wcslen(s); + #else + return strlen(s); + #endif + } + + // Compare two strings + bool strequal(const char_t* src, const char_t* dst) + { + assert(src && dst); + + #ifdef PUGIXML_WCHAR_MODE + return wcscmp(src, dst) == 0; + #else + return strcmp(src, dst) == 0; + #endif + } + + // Compare lhs with [rhs_begin, rhs_end) + bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) + { + for (size_t i = 0; i < count; ++i) + if (lhs[i] != rhs[i]) + return false; + + return lhs[count] == 0; + } + +#ifdef PUGIXML_WCHAR_MODE + // Convert string to wide string, assuming all symbols are ASCII + void widen_ascii(wchar_t* dest, const char* source) + { + for (const char* i = source; *i; ++i) *dest++ = *i; + *dest = 0; + } +#endif +} + +#if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH) +// auto_ptr-like buffer holder for exception recovery +namespace +{ + struct buffer_holder + { + void* data; + void (*deleter)(void*); + + buffer_holder(void* data, void (*deleter)(void*)): data(data), deleter(deleter) + { + } + + ~buffer_holder() + { + if (data) deleter(data); + } + + void* release() + { + void* result = data; + data = 0; + return result; + } + }; +} +#endif + +namespace +{ + static const size_t xml_memory_page_size = 32768; + + static const uintptr_t xml_memory_page_alignment = 32; + static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1); + static const uintptr_t xml_memory_page_name_allocated_mask = 16; + static const uintptr_t xml_memory_page_value_allocated_mask = 8; + static const uintptr_t xml_memory_page_type_mask = 7; + + struct xml_allocator; + + struct xml_memory_page + { + static xml_memory_page* construct(void* memory) + { + if (!memory) return 0; //$ redundant, left for performance + + xml_memory_page* result = static_cast<xml_memory_page*>(memory); + + result->allocator = 0; + result->memory = 0; + result->prev = 0; + result->next = 0; + result->busy_size = 0; + result->freed_size = 0; + + return result; + } + + xml_allocator* allocator; + + void* memory; + + xml_memory_page* prev; + xml_memory_page* next; + + size_t busy_size; + size_t freed_size; + + char data[1]; + }; + + struct xml_memory_string_header + { + uint16_t page_offset; // offset from page->data + uint16_t full_size; // 0 if string occupies whole page + }; + + struct xml_allocator + { + xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size) + { + } + + xml_memory_page* allocate_page(size_t data_size) + { + size_t size = offsetof(xml_memory_page, data) + data_size; + + // allocate block with some alignment, leaving memory for worst-case padding + void* memory = global_allocate(size + xml_memory_page_alignment); + if (!memory) return 0; + + // align upwards to page boundary + void* page_memory = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1)); + + // prepare page structure + xml_memory_page* page = xml_memory_page::construct(page_memory); + + page->memory = memory; + page->allocator = _root->allocator; + + return page; + } + + static void deallocate_page(xml_memory_page* page) + { + global_deallocate(page->memory); + } + + void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); + + void* allocate_memory(size_t size, xml_memory_page*& out_page) + { + if (_busy_size + size > xml_memory_page_size) return allocate_memory_oob(size, out_page); + + void* buf = _root->data + _busy_size; + + _busy_size += size; + + out_page = _root; + + return buf; + } + + void deallocate_memory(void* ptr, size_t size, xml_memory_page* page) + { + if (page == _root) page->busy_size = _busy_size; + + assert(ptr >= page->data && ptr < page->data + page->busy_size); + (void)!ptr; + + page->freed_size += size; + assert(page->freed_size <= page->busy_size); + + if (page->freed_size == page->busy_size) + { + if (page->next == 0) + { + assert(_root == page); + + // top page freed, just reset sizes + page->busy_size = page->freed_size = 0; + _busy_size = 0; + } + else + { + assert(_root != page); + assert(page->prev); + + // remove from the list + page->prev->next = page->next; + page->next->prev = page->prev; + + // deallocate + deallocate_page(page); + } + } + } + + char_t* allocate_string(size_t length) + { + // allocate memory for string and header block + size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); + + // round size up to pointer alignment boundary + size_t full_size = (size + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1); + + xml_memory_page* page; + xml_memory_string_header* header = static_cast<xml_memory_string_header*>(allocate_memory(full_size, page)); + + if (!header) return 0; + + // setup header + ptrdiff_t page_offset = reinterpret_cast<char*>(header) - page->data; + + assert(page_offset >= 0 && page_offset < (1 << 16)); + header->page_offset = static_cast<uint16_t>(page_offset); + + // full_size == 0 for large strings that occupy the whole page + assert(full_size < (1 << 16) || (page->busy_size == full_size && page_offset == 0)); + header->full_size = static_cast<uint16_t>(full_size < (1 << 16) ? full_size : 0); + + return reinterpret_cast<char_t*>(header + 1); + } + + void deallocate_string(char_t* string) + { + // get header + xml_memory_string_header* header = reinterpret_cast<xml_memory_string_header*>(string) - 1; + + // deallocate + size_t page_offset = offsetof(xml_memory_page, data) + header->page_offset; + xml_memory_page* page = reinterpret_cast<xml_memory_page*>(reinterpret_cast<char*>(header) - page_offset); + + // if full_size == 0 then this string occupies the whole page + size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size; + + deallocate_memory(header, full_size, page); + } + + xml_memory_page* _root; + size_t _busy_size; + }; + + PUGIXML_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page) + { + const size_t large_allocation_threshold = xml_memory_page_size / 4; + + xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size); + if (!page) return 0; + + if (size <= large_allocation_threshold) + { + _root->busy_size = _busy_size; + + // insert page at the end of linked list + page->prev = _root; + _root->next = page; + _root = page; + + _busy_size = size; + } + else + { + // insert page before the end of linked list, so that it is deleted as soon as possible + // the last page is not deleted even if it's empty (see deallocate_memory) + assert(_root->prev); + + page->prev = _root->prev; + page->next = _root; + + _root->prev->next = page; + _root->prev = page; + } + + // allocate inside page + page->busy_size = size; + + out_page = page; + return page->data; + } +} + +namespace pugi +{ + /// A 'name=value' XML attribute structure. + struct xml_attribute_struct + { + /// Default ctor + xml_attribute_struct(xml_memory_page* page): header(reinterpret_cast<uintptr_t>(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0) + { + } + + uintptr_t header; + + char_t* name; ///< Pointer to attribute name. + char_t* value; ///< Pointer to attribute value. + + xml_attribute_struct* prev_attribute_c; ///< Previous attribute (cyclic list) + xml_attribute_struct* next_attribute; ///< Next attribute + }; + + /// An XML document tree node. + struct xml_node_struct + { + /// Default ctor + /// \param type - node type + xml_node_struct(xml_memory_page* page, xml_node_type type): header(reinterpret_cast<uintptr_t>(page) | (type - 1)), parent(0), name(0), value(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) + { + } + + uintptr_t header; + + xml_node_struct* parent; ///< Pointer to parent + + char_t* name; ///< Pointer to element name. + char_t* value; ///< Pointer to any associated string data. + + xml_node_struct* first_child; ///< First child + + xml_node_struct* prev_sibling_c; ///< Left brother (cyclic list) + xml_node_struct* next_sibling; ///< Right brother + + xml_attribute_struct* first_attribute; ///< First attribute + }; +} + +namespace +{ + struct xml_document_struct: public xml_node_struct, public xml_allocator + { + xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0) + { + } + + const char_t* buffer; + }; + + static inline xml_allocator& get_allocator(const xml_node_struct* node) + { + assert(node); + + return *reinterpret_cast<xml_memory_page*>(node->header & xml_memory_page_pointer_mask)->allocator; + } +} + +// Low-level DOM operations +namespace +{ + inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc) + { + xml_memory_page* page; + void* memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page); + + return new (memory) xml_attribute_struct(page); + } + + inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type) + { + xml_memory_page* page; + void* memory = alloc.allocate_memory(sizeof(xml_node_struct), page); + + return new (memory) xml_node_struct(page, type); + } + + inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc) + { + uintptr_t header = a->header; + + if (header & xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name); + if (header & xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value); + + alloc.deallocate_memory(a, sizeof(xml_attribute_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)); + } + + inline void destroy_node(xml_node_struct* n, xml_allocator& alloc) + { + uintptr_t header = n->header; + + if (header & xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name); + if (header & xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value); + + for (xml_attribute_struct* attr = n->first_attribute; attr; ) + { + xml_attribute_struct* next = attr->next_attribute; + + destroy_attribute(attr, alloc); + + attr = next; + } + + for (xml_node_struct* child = n->first_child; child; ) + { + xml_node_struct* next = child->next_sibling; + + destroy_node(child, alloc); + + child = next; + } + + alloc.deallocate_memory(n, sizeof(xml_node_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)); + } + + PUGIXML_NO_INLINE xml_node_struct* append_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element) + { + xml_node_struct* child = allocate_node(alloc, type); + if (!child) return 0; + + child->parent = node; + + xml_node_struct* first_child = node->first_child; + + if (first_child) + { + xml_node_struct* last_child = first_child->prev_sibling_c; + + last_child->next_sibling = child; + child->prev_sibling_c = last_child; + first_child->prev_sibling_c = child; + } + else + { + node->first_child = child; + child->prev_sibling_c = child; + } + + return child; + } + + PUGIXML_NO_INLINE xml_attribute_struct* append_attribute_ll(xml_node_struct* node, xml_allocator& alloc) + { + xml_attribute_struct* a = allocate_attribute(alloc); + if (!a) return 0; + + xml_attribute_struct* first_attribute = node->first_attribute; + + if (first_attribute) + { + xml_attribute_struct* last_attribute = first_attribute->prev_attribute_c; + + last_attribute->next_attribute = a; + a->prev_attribute_c = last_attribute; + first_attribute->prev_attribute_c = a; + } + else + { + node->first_attribute = a; + a->prev_attribute_c = a; + } + + return a; + } +} + +// Helper classes for code generation +namespace +{ + struct opt_false + { + enum { value = 0 }; + }; + + struct opt_true + { + enum { value = 1 }; + }; +} + +// Unicode utilities +namespace +{ + inline uint16_t endian_swap(uint16_t value) + { + return static_cast<uint16_t>(((value & 0xff) << 8) | (value >> 8)); + } + + inline uint32_t endian_swap(uint32_t value) + { + return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24); + } + + struct utf8_counter + { + typedef size_t value_type; + + static value_type low(value_type result, uint32_t ch) + { + // U+0000..U+007F + if (ch < 0x80) return result + 1; + // U+0080..U+07FF + else if (ch < 0x800) return result + 2; + // U+0800..U+FFFF + else return result + 3; + } + + static value_type high(value_type result, uint32_t) + { + // U+10000..U+10FFFF + return result + 4; + } + }; + + struct utf8_writer + { + typedef uint8_t* value_type; + + static value_type low(value_type result, uint32_t ch) + { + // U+0000..U+007F + if (ch < 0x80) + { + *result = static_cast<uint8_t>(ch); + return result + 1; + } + // U+0080..U+07FF + else if (ch < 0x800) + { + result[0] = static_cast<uint8_t>(0xC0 | (ch >> 6)); + result[1] = static_cast<uint8_t>(0x80 | (ch & 0x3F)); + return result + 2; + } + // U+0800..U+FFFF + else + { + result[0] = static_cast<uint8_t>(0xE0 | (ch >> 12)); + result[1] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F)); + result[2] = static_cast<uint8_t>(0x80 | (ch & 0x3F)); + return result + 3; + } + } + + static value_type high(value_type result, uint32_t ch) + { + // U+10000..U+10FFFF + result[0] = static_cast<uint8_t>(0xF0 | (ch >> 18)); + result[1] = static_cast<uint8_t>(0x80 | ((ch >> 12) & 0x3F)); + result[2] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F)); + result[3] = static_cast<uint8_t>(0x80 | (ch & 0x3F)); + return result + 4; + } + + static value_type any(value_type result, uint32_t ch) + { + return (ch < 0x10000) ? low(result, ch) : high(result, ch); + } + }; + + struct utf16_counter + { + typedef size_t value_type; + + static value_type low(value_type result, uint32_t) + { + return result + 1; + } + + static value_type high(value_type result, uint32_t) + { + return result + 2; + } + }; + + struct utf16_writer + { + typedef uint16_t* value_type; + + static value_type low(value_type result, uint32_t ch) + { + *result = static_cast<uint16_t>(ch); + + return result + 1; + } + + static value_type high(value_type result, uint32_t ch) + { + uint32_t msh = (uint32_t)(ch - 0x10000) >> 10; + uint32_t lsh = (uint32_t)(ch - 0x10000) & 0x3ff; + + result[0] = static_cast<uint16_t>(0xD800 + msh); + result[1] = static_cast<uint16_t>(0xDC00 + lsh); + + return result + 2; + } + + static value_type any(value_type result, uint32_t ch) + { + return (ch < 0x10000) ? low(result, ch) : high(result, ch); + } + }; + + struct utf32_counter + { + typedef size_t value_type; + + static value_type low(value_type result, uint32_t) + { + return result + 1; + } + + static value_type high(value_type result, uint32_t) + { + return result + 1; + } + }; + + struct utf32_writer + { + typedef uint32_t* value_type; + + static value_type low(value_type result, uint32_t ch) + { + *result = ch; + + return result + 1; + } + + static value_type high(value_type result, uint32_t ch) + { + *result = ch; + + return result + 1; + } + + static value_type any(value_type result, uint32_t ch) + { + *result = ch; + + return result + 1; + } + }; + + template <size_t size> struct wchar_selector; + + template <> struct wchar_selector<2> + { + typedef uint16_t type; + typedef utf16_counter counter; + typedef utf16_writer writer; + }; + + template <> struct wchar_selector<4> + { + typedef uint32_t type; + typedef utf32_counter counter; + typedef utf32_writer writer; + }; + + typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter; + typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer; + + template <typename Traits, typename opt_swap = opt_false> struct utf_decoder + { + static inline typename Traits::value_type decode_utf8_block(const uint8_t* data, size_t size, typename Traits::value_type result) + { + const uint8_t utf8_byte_mask = 0x3f; + + while (size) + { + uint8_t lead = *data; + + // 0xxxxxxx -> U+0000..U+007F + if (lead < 0x80) + { + result = Traits::low(result, lead); + data += 1; + size -= 1; + + // process aligned single-byte (ascii) blocks + if ((reinterpret_cast<uintptr_t>(data) & 3) == 0) + { + while (size >= 4 && (*reinterpret_cast<const uint32_t*>(data) & 0x80808080) == 0) + { + result = Traits::low(result, data[0]); + result = Traits::low(result, data[1]); + result = Traits::low(result, data[2]); + result = Traits::low(result, data[3]); + data += 4; + size -= 4; + } + } + } + // 110xxxxx -> U+0080..U+07FF + else if ((unsigned)(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80) + { + result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask)); + data += 2; + size -= 2; + } + // 1110xxxx -> U+0800-U+FFFF + else if ((unsigned)(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80) + { + result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask)); + data += 3; + size -= 3; + } + // 11110xxx -> U+10000..U+10FFFF + else if ((unsigned)(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80) + { + result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask)); + data += 4; + size -= 4; + } + // 10xxxxxx or 11111xxx -> invalid + else + { + data += 1; + size -= 1; + } + } + + return result; + } + + static inline typename Traits::value_type decode_utf16_block(const uint16_t* data, size_t size, typename Traits::value_type result) + { + const uint16_t* end = data + size; + + while (data < end) + { + uint16_t lead = opt_swap::value ? endian_swap(*data) : *data; + + // U+0000..U+D7FF + if (lead < 0xD800) + { + result = Traits::low(result, lead); + data += 1; + } + // U+E000..U+FFFF + else if ((unsigned)(lead - 0xE000) < 0x2000) + { + result = Traits::low(result, lead); + data += 1; + } + // surrogate pair lead + else if ((unsigned)(lead - 0xD800) < 0x400 && data + 1 < end) + { + uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1]; + + if ((unsigned)(next - 0xDC00) < 0x400) + { + result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff)); + data += 2; + } + else + { + data += 1; + } + } + else + { + data += 1; + } + } + + return result; + } + + static inline typename Traits::value_type decode_utf32_block(const uint32_t* data, size_t size, typename Traits::value_type result) + { + const uint32_t* end = data + size; + + while (data < end) + { + uint32_t lead = opt_swap::value ? endian_swap(*data) : *data; + + // U+0000..U+FFFF + if (lead < 0x10000) + { + result = Traits::low(result, lead); + data += 1; + } + // U+10000..U+10FFFF + else + { + result = Traits::high(result, lead); + data += 1; + } + } + + return result; + } + }; + + template <typename T> inline void convert_utf_endian_swap(T* result, const T* data, size_t length) + { + for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]); + } + + inline void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) + { + for (size_t i = 0; i < length; ++i) result[i] = static_cast<wchar_t>(endian_swap(static_cast<wchar_selector<sizeof(wchar_t)>::type>(data[i]))); + } +} + +namespace +{ + enum chartype_t + { + ct_parse_pcdata = 1, // \0, &, \r, < + ct_parse_attr = 2, // \0, &, \r, ', " + ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab + ct_space = 8, // \r, \n, space, tab + ct_parse_cdata = 16, // \0, ], >, \r + ct_parse_comment = 32, // \0, -, >, \r + ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, . + ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, : + }; + + const unsigned char chartype_table[256] = + { + 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 + 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47 + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63 + 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79 + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95 + 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111 + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127 + + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+ + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192 + }; + + enum chartypex_t + { + ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, > + ctx_special_attr = 2, // Any symbol >= 0 and < 32 (except \t), &, <, >, " + ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _ + ctx_digit = 8, // 0-9 + ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . + }; + + const unsigned char chartypex_table[256] = + { + 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31 + 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47 + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0, // 48-63 + + 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95 + 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127 + + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+ + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 + }; + +#ifdef PUGIXML_WCHAR_MODE + #define IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct)) +#else + #define IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct)) +#endif + + #define IS_CHARTYPE(c, ct) IS_CHARTYPE_IMPL(c, ct, chartype_table) + #define IS_CHARTYPEX(c, ct) IS_CHARTYPE_IMPL(c, ct, chartypex_table) + + bool is_little_endian() + { + unsigned int ui = 1; + + return *reinterpret_cast<unsigned char*>(&ui) == 1; + } + + xml_encoding get_wchar_encoding() + { + STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); + + if (sizeof(wchar_t) == 2) + return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + else + return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + } + + xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) + { + // look for BOM in first few bytes + if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; + if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; + if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be; + if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le; + if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8; + + // look for <, <? or <?xm in various encodings + if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c) return encoding_utf32_be; + if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0) return encoding_utf32_le; + if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be; + if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le; + if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d) return encoding_utf8; + + // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early) + if (d0 == 0 && d1 == 0x3c) return encoding_utf16_be; + if (d0 == 0x3c && d1 == 0) return encoding_utf16_le; + + // no known BOM detected, assume utf8 + return encoding_utf8; + } + + xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size) + { + // replace wchar encoding with utf implementation + if (encoding == encoding_wchar) return get_wchar_encoding(); + + // replace utf16 encoding with utf16 with specific endianness + if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + // replace utf32 encoding with utf32 with specific endianness + if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + // only do autodetection if no explicit encoding is requested + if (encoding != encoding_auto) return encoding; + + // skip encoding autodetection if input buffer is too small + if (size < 4) return encoding_utf8; + + // try to guess encoding (based on XML specification, Appendix F.1) + const uint8_t* data = static_cast<const uint8_t*>(contents); + + DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; + + return guess_buffer_encoding(d0, d1, d2, d3); + } + + bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) + { + if (is_mutable) + { + out_buffer = static_cast<char_t*>(const_cast<void*>(contents)); + } + else + { + void* buffer = global_allocate(size > 0 ? size : 1); + if (!buffer) return false; + + memcpy(buffer, contents, size); + + out_buffer = static_cast<char_t*>(buffer); + } + + out_length = size / sizeof(char_t); + + return true; + } + +#ifdef PUGIXML_WCHAR_MODE + inline bool need_endian_swap_utf(xml_encoding le, xml_encoding re) + { + return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) || + (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be); + } + + bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) + { + const char_t* data = static_cast<const char_t*>(contents); + + if (is_mutable) + { + out_buffer = const_cast<char_t*>(data); + } + else + { + out_buffer = static_cast<char_t*>(global_allocate(size > 0 ? size : 1)); + if (!out_buffer) return false; + } + + out_length = size / sizeof(char_t); + + convert_wchar_endian_swap(out_buffer, data, out_length); + + return true; + } + + bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) + { + const uint8_t* data = static_cast<const uint8_t*>(contents); + + // first pass: get length in wchar_t units + out_length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0); + + // allocate buffer of suitable length + out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf8 input to wchar_t + wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer); + wchar_writer::value_type out_end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + template <typename opt_swap> bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint16_t* data = static_cast<const uint16_t*>(contents); + size_t length = size / sizeof(uint16_t); + + // first pass: get length in wchar_t units + out_length = utf_decoder<wchar_counter, opt_swap>::decode_utf16_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf16 input to wchar_t + wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer); + wchar_writer::value_type out_end = utf_decoder<wchar_writer, opt_swap>::decode_utf16_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + template <typename opt_swap> bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint32_t* data = static_cast<const uint32_t*>(contents); + size_t length = size / sizeof(uint32_t); + + // first pass: get length in wchar_t units + out_length = utf_decoder<wchar_counter, opt_swap>::decode_utf32_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf32 input to wchar_t + wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer); + wchar_writer::value_type out_end = utf_decoder<wchar_writer, opt_swap>::decode_utf32_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) + { + // get native encoding + xml_encoding wchar_encoding = get_wchar_encoding(); + + // fast path: no conversion required + if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); + + // only endian-swapping is required + if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); + + // source encoding is utf8 + if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size); + + // source encoding is utf16 + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + return (native_encoding == encoding) ? + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); + } + + // source encoding is utf32 + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + return (native_encoding == encoding) ? + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); + } + + assert(!"Invalid encoding"); + return false; + } +#else + template <typename opt_swap> bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint16_t* data = static_cast<const uint16_t*>(contents); + size_t length = size / sizeof(uint16_t); + + // first pass: get length in utf8 units + out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf16_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf16 input to utf8 + uint8_t* out_begin = reinterpret_cast<uint8_t*>(out_buffer); + uint8_t* out_end = utf_decoder<utf8_writer, opt_swap>::decode_utf16_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + template <typename opt_swap> bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint32_t* data = static_cast<const uint32_t*>(contents); + size_t length = size / sizeof(uint32_t); + + // first pass: get length in utf8 units + out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf32_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf32 input to utf8 + uint8_t* out_begin = reinterpret_cast<uint8_t*>(out_buffer); + uint8_t* out_end = utf_decoder<utf8_writer, opt_swap>::decode_utf32_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) + { + // fast path: no conversion required + if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); + + // source encoding is utf16 + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + return (native_encoding == encoding) ? + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); + } + + // source encoding is utf32 + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + return (native_encoding == encoding) ? + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); + } + + assert(!"Invalid encoding"); + return false; + } +#endif + + size_t as_utf8_begin(const wchar_t* str, size_t length) + { + STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); + + // get length in utf8 characters + return sizeof(wchar_t) == 2 ? + utf_decoder<utf8_counter>::decode_utf16_block(reinterpret_cast<const uint16_t*>(str), length, 0) : + utf_decoder<utf8_counter>::decode_utf32_block(reinterpret_cast<const uint32_t*>(str), length, 0); + } + + void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) + { + STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); + + // convert to utf8 + uint8_t* begin = reinterpret_cast<uint8_t*>(buffer); + uint8_t* end = sizeof(wchar_t) == 2 ? + utf_decoder<utf8_writer>::decode_utf16_block(reinterpret_cast<const uint16_t*>(str), length, begin) : + utf_decoder<utf8_writer>::decode_utf32_block(reinterpret_cast<const uint32_t*>(str), length, begin); + + assert(begin + size == end); + (void)!end; + + // zero-terminate + buffer[size] = 0; + } + +#ifndef PUGIXML_NO_STL + std::string as_utf8_impl(const wchar_t* str, size_t length) + { + // first pass: get length in utf8 characters + size_t size = as_utf8_begin(str, length); + + // allocate resulting string + std::string result; + result.resize(size); + + // second pass: convert to utf8 + if (size > 0) as_utf8_end(&result[0], size, str, length); + + return result; + } + + std::wstring as_wide_impl(const char* str, size_t size) + { + const uint8_t* data = reinterpret_cast<const uint8_t*>(str); + + // first pass: get length in wchar_t units + size_t length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0); + + // allocate resulting string + std::wstring result; + result.resize(length); + + // second pass: convert to wchar_t + if (length > 0) + { + wchar_writer::value_type begin = reinterpret_cast<wchar_writer::value_type>(&result[0]); + wchar_writer::value_type end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, begin); + + assert(begin + length == end); + (void)!end; + } + + return result; + } +#endif + + inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t* target) + { + assert(target); + size_t target_length = strlength(target); + + // always reuse document buffer memory if possible + if (!allocated) return target_length >= length; + + // reuse heap memory if waste is not too great + const size_t reuse_threshold = 32; + + return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2); + } + + bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source) + { + size_t source_length = strlength(source); + + if (source_length == 0) + { + // empty string and null pointer are equivalent, so just deallocate old memory + xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator; + + if (header & header_mask) alloc->deallocate_string(dest); + + // mark the string as not allocated + dest = 0; + header &= ~header_mask; + + return true; + } + else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest)) + { + // we can reuse old buffer, so just copy the new data (including zero terminator) + memcpy(dest, source, (source_length + 1) * sizeof(char_t)); + + return true; + } + else + { + xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator; + + // allocate new buffer + char_t* buf = alloc->allocate_string(source_length + 1); + if (!buf) return false; + + // copy the string (including zero terminator) + memcpy(buf, source, (source_length + 1) * sizeof(char_t)); + + // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) + if (header & header_mask) alloc->deallocate_string(dest); + + // the string is now allocated, so set the flag + dest = buf; + header |= header_mask; + + return true; + } + } + + struct gap + { + char_t* end; + size_t size; + + gap(): end(0), size(0) + { + } + + // Push new gap, move s count bytes further (skipping the gap). + // Collapse previous gap. + void push(char_t*& s, size_t count) + { + if (end) // there was a gap already; collapse it + { + // Move [old_gap_end, new_gap_start) to [old_gap_start, ...) + assert(s >= end); + memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end)); + } + + s += count; // end of current gap + + // "merge" two gaps + end = s; + size += count; + } + + // Collapse all gaps, return past-the-end pointer + char_t* flush(char_t* s) + { + if (end) + { + // Move [old_gap_end, current_pos) to [old_gap_start, ...) + assert(s >= end); + memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end)); + + return s - size; + } + else return s; + } + }; + + char_t* strconv_escape(char_t* s, gap& g) + { + char_t* stre = s + 1; + + switch (*stre) + { + case '#': // &#... + { + unsigned int ucsc = 0; + + if (stre[1] == 'x') // &#x... (hex code) + { + stre += 2; + + char_t ch = *stre; + + if (ch == ';') return stre; + + for (;;) + { + if (static_cast<unsigned int>(ch - '0') <= 9) + ucsc = 16 * ucsc + (ch - '0'); + else if (static_cast<unsigned int>((ch | ' ') - 'a') <= 5) + ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10); + else if (ch == ';') + break; + else // cancel + return stre; + + ch = *++stre; + } + + ++stre; + } + else // &#... (dec code) + { + char_t ch = *++stre; + + if (ch == ';') return stre; + + for (;;) + { + if (static_cast<unsigned int>(ch - '0') <= 9) + ucsc = 10 * ucsc + (ch - '0'); + else if (ch == ';') + break; + else // cancel + return stre; + + ch = *++stre; + } + + ++stre; + } + + #ifdef PUGIXML_WCHAR_MODE + s = reinterpret_cast<char_t*>(wchar_writer::any(reinterpret_cast<wchar_writer::value_type>(s), ucsc)); + #else + s = reinterpret_cast<char_t*>(utf8_writer::any(reinterpret_cast<uint8_t*>(s), ucsc)); + #endif + + g.push(s, stre - s); + return stre; + } + case 'a': // &a + { + ++stre; + + if (*stre == 'm') // &am + { + if (*++stre == 'p' && *++stre == ';') // & + { + *s++ = '&'; + ++stre; + + g.push(s, stre - s); + return stre; + } + } + else if (*stre == 'p') // &ap + { + if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // ' + { + *s++ = '\''; + ++stre; + + g.push(s, stre - s); + return stre; + } + } + break; + } + case 'g': // &g + { + if (*++stre == 't' && *++stre == ';') // > + { + *s++ = '>'; + ++stre; + + g.push(s, stre - s); + return stre; + } + break; + } + case 'l': // &l + { + if (*++stre == 't' && *++stre == ';') // < + { + *s++ = '<'; + ++stre; + + g.push(s, stre - s); + return stre; + } + break; + } + case 'q': // &q + { + if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // " + { + *s++ = '"'; + ++stre; + + g.push(s, stre - s); + return stre; + } + break; + } + } + + return stre; + } + + // Utility macro for last character handling + #define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) + + char_t* strconv_comment(char_t* s, char_t endch) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_comment)) ++s; + + if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair + { + *s++ = '\n'; // replace first one with 0x0a + + if (*s == '\n') g.push(s, 1); + } + else if (s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')) // comment ends here + { + *g.flush(s) = 0; + + return s + (s[2] == '>' ? 3 : 2); + } + else if (*s == 0) + { + return 0; + } + else ++s; + } + } + + char_t* strconv_cdata(char_t* s, char_t endch) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_cdata)) ++s; + + if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair + { + *s++ = '\n'; // replace first one with 0x0a + + if (*s == '\n') g.push(s, 1); + } + else if (s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')) // CDATA ends here + { + *g.flush(s) = 0; + + return s + 1; + } + else if (*s == 0) + { + return 0; + } + else ++s; + } + } + + typedef char_t* (*strconv_pcdata_t)(char_t*); + + template <typename opt_eol, typename opt_escape> struct strconv_pcdata_impl + { + static char_t* parse(char_t* s) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_pcdata)) ++s; + + if (*s == '<') // PCDATA ends here + { + *g.flush(s) = 0; + + return s + 1; + } + else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair + { + *s++ = '\n'; // replace first one with 0x0a + + if (*s == '\n') g.push(s, 1); + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (*s == 0) + { + return s; + } + else ++s; + } + } + }; + + strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) + { + STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20); + + switch ((optmask >> 4) & 3) // get bitmask for flags (eol escapes) + { + case 0: return strconv_pcdata_impl<opt_false, opt_false>::parse; + case 1: return strconv_pcdata_impl<opt_false, opt_true>::parse; + case 2: return strconv_pcdata_impl<opt_true, opt_false>::parse; + case 3: return strconv_pcdata_impl<opt_true, opt_true>::parse; + default: return 0; // should not get here + } + } + + typedef char_t* (*strconv_attribute_t)(char_t*, char_t); + + template <typename opt_escape> struct strconv_attribute_impl + { + static char_t* parse_wnorm(char_t* s, char_t end_quote) + { + gap g; + + // trim leading whitespaces + if (IS_CHARTYPE(*s, ct_space)) + { + char_t* str = s; + + do ++str; + while (IS_CHARTYPE(*str, ct_space)); + + g.push(s, str - s); + } + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_attr_ws | ct_space)) ++s; + + if (*s == end_quote) + { + char_t* str = g.flush(s); + + do *str-- = 0; + while (IS_CHARTYPE(*str, ct_space)); + + return s + 1; + } + else if (IS_CHARTYPE(*s, ct_space)) + { + *s++ = ' '; + + if (IS_CHARTYPE(*s, ct_space)) + { + char_t* str = s + 1; + while (IS_CHARTYPE(*str, ct_space)) ++str; + + g.push(s, str - s); + } + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + + static char_t* parse_wconv(char_t* s, char_t end_quote) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_attr_ws)) ++s; + + if (*s == end_quote) + { + *g.flush(s) = 0; + + return s + 1; + } + else if (IS_CHARTYPE(*s, ct_space)) + { + if (*s == '\r') + { + *s++ = ' '; + + if (*s == '\n') g.push(s, 1); + } + else *s++ = ' '; + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + + static char_t* parse_eol(char_t* s, char_t end_quote) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_attr)) ++s; + + if (*s == end_quote) + { + *g.flush(s) = 0; + + return s + 1; + } + else if (*s == '\r') + { + *s++ = '\n'; + + if (*s == '\n') g.push(s, 1); + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + + static char_t* parse_simple(char_t* s, char_t end_quote) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_attr)) ++s; + + if (*s == end_quote) + { + *g.flush(s) = 0; + + return s + 1; + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + }; + + strconv_attribute_t get_strconv_attribute(unsigned int optmask) + { + STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); + + switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes) + { + case 0: return strconv_attribute_impl<opt_false>::parse_simple; + case 1: return strconv_attribute_impl<opt_true>::parse_simple; + case 2: return strconv_attribute_impl<opt_false>::parse_eol; + case 3: return strconv_attribute_impl<opt_true>::parse_eol; + case 4: return strconv_attribute_impl<opt_false>::parse_wconv; + case 5: return strconv_attribute_impl<opt_true>::parse_wconv; + case 6: return strconv_attribute_impl<opt_false>::parse_wconv; + case 7: return strconv_attribute_impl<opt_true>::parse_wconv; + case 8: return strconv_attribute_impl<opt_false>::parse_wnorm; + case 9: return strconv_attribute_impl<opt_true>::parse_wnorm; + case 10: return strconv_attribute_impl<opt_false>::parse_wnorm; + case 11: return strconv_attribute_impl<opt_true>::parse_wnorm; + case 12: return strconv_attribute_impl<opt_false>::parse_wnorm; + case 13: return strconv_attribute_impl<opt_true>::parse_wnorm; + case 14: return strconv_attribute_impl<opt_false>::parse_wnorm; + case 15: return strconv_attribute_impl<opt_true>::parse_wnorm; + default: return 0; // should not get here + } + } + + inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0) + { + xml_parse_result result; + result.status = status; + result.offset = offset; + + return result; + } + + struct xml_parser + { + xml_allocator alloc; + char_t* error_offset; + jmp_buf error_handler; + + // Parser utilities. + #define SKIPWS() { while (IS_CHARTYPE(*s, ct_space)) ++s; } + #define OPTSET(OPT) ( optmsk & OPT ) + #define PUSHNODE(TYPE) { cursor = append_node(cursor, alloc, TYPE); if (!cursor) THROW_ERROR(status_out_of_memory, s); } + #define POPNODE() { cursor = cursor->parent; } + #define SCANFOR(X) { while (*s != 0 && !(X)) ++s; } + #define SCANWHILE(X) { while ((X)) ++s; } + #define ENDSEG() { ch = *s; *s = 0; ++s; } + #define THROW_ERROR(err, m) error_offset = m, longjmp(error_handler, err) + #define CHECK_ERROR(err, m) { if (*s == 0) THROW_ERROR(err, m); } + + xml_parser(const xml_allocator& alloc): alloc(alloc), error_offset(0) + { + } + + // DOCTYPE consists of nested sections of the following possible types: + // <!-- ... -->, <? ... ?>, "...", '...' + // <![...]]> + // <!...> + // First group can not contain nested groups + // Second group can contain nested groups of the same type + // Third group can contain all other groups + char_t* parse_doctype_primitive(char_t* s) + { + if (*s == '"' || *s == '\'') + { + // quoted string + char_t ch = *s++; + SCANFOR(*s == ch); + if (!*s) THROW_ERROR(status_bad_doctype, s); + + s++; + } + else if (s[0] == '<' && s[1] == '?') + { + // <? ... ?> + s += 2; + SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype + if (!*s) THROW_ERROR(status_bad_doctype, s); + + s += 2; + } + else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-') + { + s += 4; + SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype + if (!*s) THROW_ERROR(status_bad_doctype, s); + + s += 4; + } + else THROW_ERROR(status_bad_doctype, s); + + return s; + } + + char_t* parse_doctype_ignore(char_t* s) + { + assert(s[0] == '<' && s[1] == '!' && s[2] == '['); + s++; + + while (*s) + { + if (s[0] == '<' && s[1] == '!' && s[2] == '[') + { + // nested ignore section + s = parse_doctype_ignore(s); + } + else if (s[0] == ']' && s[1] == ']' && s[2] == '>') + { + // ignore section end + s += 3; + + return s; + } + else s++; + } + + THROW_ERROR(status_bad_doctype, s); + + return s; + } + + char_t* parse_doctype_group(char_t* s, char_t endch, bool toplevel) + { + assert(s[0] == '<' && s[1] == '!'); + s++; + + while (*s) + { + if (s[0] == '<' && s[1] == '!' && s[2] != '-') + { + if (s[2] == '[') + { + // ignore + s = parse_doctype_ignore(s); + } + else + { + // some control group + s = parse_doctype_group(s, endch, false); + } + } + else if (s[0] == '<' || s[0] == '"' || s[0] == '\'') + { + // unknown tag (forbidden), or some primitive group + s = parse_doctype_primitive(s); + } + else if (*s == '>') + { + s++; + + return s; + } + else s++; + } + + if (!toplevel || endch != '>') THROW_ERROR(status_bad_doctype, s); + + return s; + } + + char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch) + { + // parse node contents, starting with exclamation mark + ++s; + + if (*s == '-') // '<!-...' + { + ++s; + + if (*s == '-') // '<!--...' + { + ++s; + + if (OPTSET(parse_comments)) + { + PUSHNODE(node_comment); // Append a new node on the tree. + cursor->value = s; // Save the offset. + } + + if (OPTSET(parse_eol) && OPTSET(parse_comments)) + { + s = strconv_comment(s, endch); + + if (!s) THROW_ERROR(status_bad_comment, cursor->value); + } + else + { + // Scan for terminating '-->'. + SCANFOR(s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')); + CHECK_ERROR(status_bad_comment, s); + + if (OPTSET(parse_comments)) + *s = 0; // Zero-terminate this segment at the first terminating '-'. + + s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'. + } + } + else THROW_ERROR(status_bad_comment, s); + } + else if (*s == '[') + { + // '<![CDATA[...' + if (*++s=='C' && *++s=='D' && *++s=='A' && *++s=='T' && *++s=='A' && *++s == '[') + { + ++s; + + if (OPTSET(parse_cdata)) + { + PUSHNODE(node_cdata); // Append a new node on the tree. + cursor->value = s; // Save the offset. + + if (OPTSET(parse_eol)) + { + s = strconv_cdata(s, endch); + + if (!s) THROW_ERROR(status_bad_cdata, cursor->value); + } + else + { + // Scan for terminating ']]>'. + SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')); + CHECK_ERROR(status_bad_cdata, s); + + *s++ = 0; // Zero-terminate this segment. + } + } + else // Flagged for discard, but we still have to scan for the terminator. + { + // Scan for terminating ']]>'. + SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')); + CHECK_ERROR(status_bad_cdata, s); + + ++s; + } + + s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'. + } + else THROW_ERROR(status_bad_cdata, s); + } + else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && ENDSWITH(s[6], 'E')) + { + s -= 2; + + if (cursor->parent) THROW_ERROR(status_bad_doctype, s); + + char_t* mark = s + 9; + + s = parse_doctype_group(s, endch, true); + + if (OPTSET(parse_doctype)) + { + while (IS_CHARTYPE(*mark, ct_space)) ++mark; + + PUSHNODE(node_doctype); + + cursor->value = mark; + + assert((s[0] == 0 && endch == '>') || s[-1] == '>'); + s[*s == 0 ? 0 : -1] = 0; + + POPNODE(); + } + } + else if (*s == 0 && endch == '-') THROW_ERROR(status_bad_comment, s); + else if (*s == 0 && endch == '[') THROW_ERROR(status_bad_cdata, s); + else THROW_ERROR(status_unrecognized_tag, s); + + return s; + } + + char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch) + { + // load into registers + xml_node_struct* cursor = ref_cursor; + char_t ch = 0; + + // parse node contents, starting with question mark + ++s; + + // read PI target + char_t* target = s; + + if (!IS_CHARTYPE(*s, ct_start_symbol)) THROW_ERROR(status_bad_pi, s); + + SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); + CHECK_ERROR(status_bad_pi, s); + + // determine node type; stricmp / strcasecmp is not portable + bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s; + + if (declaration ? OPTSET(parse_declaration) : OPTSET(parse_pi)) + { + if (declaration) + { + // disallow non top-level declarations + if (cursor->parent) THROW_ERROR(status_bad_pi, s); + + PUSHNODE(node_declaration); + } + else + { + PUSHNODE(node_pi); + } + + cursor->name = target; + + ENDSEG(); + + // parse value/attributes + if (ch == '?') + { + // empty node + if (!ENDSWITH(*s, '>')) THROW_ERROR(status_bad_pi, s); + s += (*s == '>'); + + POPNODE(); + } + else if (IS_CHARTYPE(ch, ct_space)) + { + SKIPWS(); + + // scan for tag end + char_t* value = s; + + SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); + CHECK_ERROR(status_bad_pi, s); + + if (declaration) + { + // replace ending ? with / so that 'element' terminates properly + *s = '/'; + + // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES + s = value; + } + else + { + // store value and step over > + cursor->value = value; + POPNODE(); + + ENDSEG(); + + s += (*s == '>'); + } + } + else THROW_ERROR(status_bad_pi, s); + } + else + { + // scan for tag end + SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); + CHECK_ERROR(status_bad_pi, s); + + s += (s[1] == '>' ? 2 : 1); + } + + // store from registers + ref_cursor = cursor; + + return s; + } + + void parse(char_t* s, xml_node_struct* xmldoc, unsigned int optmsk, char_t endch) + { + strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); + strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); + + char_t ch = 0; + xml_node_struct* cursor = xmldoc; + char_t* mark = s; + + while (*s != 0) + { + if (*s == '<') + { + ++s; + + LOC_TAG: + if (IS_CHARTYPE(*s, ct_start_symbol)) // '<#...' + { + PUSHNODE(node_element); // Append a new node to the tree. + + cursor->name = s; + + SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator. + ENDSEG(); // Save char in 'ch', terminate & step over. + + if (ch == '>') + { + // end of tag + } + else if (IS_CHARTYPE(ch, ct_space)) + { + LOC_ATTRIBUTES: + while (true) + { + SKIPWS(); // Eat any whitespace. + + if (IS_CHARTYPE(*s, ct_start_symbol)) // <... #... + { + xml_attribute_struct* a = append_attribute_ll(cursor, alloc); // Make space for this attribute. + if (!a) THROW_ERROR(status_out_of_memory, s); + + a->name = s; // Save the offset. + + SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator. + CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance + + ENDSEG(); // Save char in 'ch', terminate & step over. + CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance + + if (IS_CHARTYPE(ch, ct_space)) + { + SKIPWS(); // Eat any whitespace. + CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance + + ch = *s; + ++s; + } + + if (ch == '=') // '<... #=...' + { + SKIPWS(); // Eat any whitespace. + + if (*s == '"' || *s == '\'') // '<... #="...' + { + ch = *s; // Save quote char to avoid breaking on "''" -or- '""'. + ++s; // Step over the quote. + a->value = s; // Save the offset. + + s = strconv_attribute(s, ch); + + if (!s) THROW_ERROR(status_bad_attribute, a->value); + + // After this line the loop continues from the start; + // Whitespaces, / and > are ok, symbols and EOF are wrong, + // everything else will be detected + if (IS_CHARTYPE(*s, ct_start_symbol)) THROW_ERROR(status_bad_attribute, s); + } + else THROW_ERROR(status_bad_attribute, s); + } + else THROW_ERROR(status_bad_attribute, s); + } + else if (*s == '/') + { + ++s; + + if (*s == '>') + { + POPNODE(); + s++; + break; + } + else if (*s == 0 && endch == '>') + { + POPNODE(); + break; + } + else THROW_ERROR(status_bad_start_element, s); + } + else if (*s == '>') + { + ++s; + + break; + } + else if (*s == 0 && endch == '>') + { + break; + } + else THROW_ERROR(status_bad_start_element, s); + } + + // !!! + } + else if (ch == '/') // '<#.../' + { + if (!ENDSWITH(*s, '>')) THROW_ERROR(status_bad_start_element, s); + + POPNODE(); // Pop. + + s += (*s == '>'); + } + else if (ch == 0) + { + // we stepped over null terminator, backtrack & handle closing tag + --s; + + if (endch != '>') THROW_ERROR(status_bad_start_element, s); + } + else THROW_ERROR(status_bad_start_element, s); + } + else if (*s == '/') + { + ++s; + + char_t* name = cursor->name; + if (!name) THROW_ERROR(status_end_element_mismatch, s); + + while (IS_CHARTYPE(*s, ct_symbol)) + { + if (*s++ != *name++) THROW_ERROR(status_end_element_mismatch, s); + } + + if (*name) + { + if (*s == 0 && name[0] == endch && name[1] == 0) THROW_ERROR(status_bad_end_element, s); + else THROW_ERROR(status_end_element_mismatch, s); + } + + POPNODE(); // Pop. + + SKIPWS(); + + if (*s == 0) + { + if (endch != '>') THROW_ERROR(status_bad_end_element, s); + } + else + { + if (*s != '>') THROW_ERROR(status_bad_end_element, s); + ++s; + } + } + else if (*s == '?') // '<?...' + { + s = parse_question(s, cursor, optmsk, endch); + + assert(cursor); + if ((cursor->header & xml_memory_page_type_mask) + 1 == node_declaration) goto LOC_ATTRIBUTES; + } + else if (*s == '!') // '<!...' + { + s = parse_exclamation(s, cursor, optmsk, endch); + } + else if (*s == 0 && endch == '?') THROW_ERROR(status_bad_pi, s); + else THROW_ERROR(status_unrecognized_tag, s); + } + else + { + mark = s; // Save this offset while searching for a terminator. + + SKIPWS(); // Eat whitespace if no genuine PCDATA here. + + if ((!OPTSET(parse_ws_pcdata) || mark == s) && (*s == '<' || !*s)) + { + continue; + } + + s = mark; + + if (cursor->parent) + { + PUSHNODE(node_pcdata); // Append a new node on the tree. + cursor->value = s; // Save the offset. + + s = strconv_pcdata(s); + + POPNODE(); // Pop since this is a standalone. + + if (!*s) break; + } + else + { + SCANFOR(*s == '<'); // '...<' + if (!*s) break; + + ++s; + } + + // We're after '<' + goto LOC_TAG; + } + } + + // check that last tag is closed + if (cursor != xmldoc) THROW_ERROR(status_end_element_mismatch, s); + } + + static xml_parse_result parse(char_t* buffer, size_t length, xml_node_struct* root, unsigned int optmsk) + { + xml_document_struct* xmldoc = static_cast<xml_document_struct*>(root); + + // store buffer for offset_debug + xmldoc->buffer = buffer; + + // early-out for empty documents + if (length == 0) return make_parse_result(status_ok); + + // create parser on stack + xml_parser parser(*xmldoc); + + // save last character and make buffer zero-terminated (speeds up parsing) + char_t endch = buffer[length - 1]; + buffer[length - 1] = 0; + + // perform actual parsing + int error = setjmp(parser.error_handler); + + if (error == 0) + { + parser.parse(buffer, xmldoc, optmsk, endch); + } + + xml_parse_result result = make_parse_result(static_cast<xml_parse_status>(error), parser.error_offset ? parser.error_offset - buffer : 0); + assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length); + + // update allocator state + *static_cast<xml_allocator*>(xmldoc) = parser.alloc; + + // since we removed last character, we have to handle the only possible false positive + if (result && endch == '<') + { + // there's no possible well-formed document with < at the end + return make_parse_result(status_unrecognized_tag, length); + } + + return result; + } + }; + + // Output facilities + xml_encoding get_write_native_encoding() + { + #ifdef PUGIXML_WCHAR_MODE + return get_wchar_encoding(); + #else + return encoding_utf8; + #endif + } + + xml_encoding get_write_encoding(xml_encoding encoding) + { + // replace wchar encoding with utf implementation + if (encoding == encoding_wchar) return get_wchar_encoding(); + + // replace utf16 encoding with utf16 with specific endianness + if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + // replace utf32 encoding with utf32 with specific endianness + if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + // only do autodetection if no explicit encoding is requested + if (encoding != encoding_auto) return encoding; + + // assume utf8 encoding + return encoding_utf8; + } + +#ifdef PUGIXML_WCHAR_MODE + size_t get_valid_length(const char_t* data, size_t length) + { + assert(length > 0); + + // discard last character if it's the lead of a surrogate pair + return (sizeof(wchar_t) == 2 && (unsigned)(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; + } + + size_t convert_buffer(char* result, const char_t* data, size_t length, xml_encoding encoding) + { + // only endian-swapping is required + if (need_endian_swap_utf(encoding, get_wchar_encoding())) + { + convert_wchar_endian_swap(reinterpret_cast<char_t*>(result), data, length); + + return length * sizeof(char_t); + } + + // convert to utf8 + if (encoding == encoding_utf8) + { + uint8_t* dest = reinterpret_cast<uint8_t*>(result); + + uint8_t* end = sizeof(wchar_t) == 2 ? + utf_decoder<utf8_writer>::decode_utf16_block(reinterpret_cast<const uint16_t*>(data), length, dest) : + utf_decoder<utf8_writer>::decode_utf32_block(reinterpret_cast<const uint32_t*>(data), length, dest); + + return static_cast<size_t>(end - dest); + } + + // convert to utf16 + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + uint16_t* dest = reinterpret_cast<uint16_t*>(result); + + // convert to native utf16 + uint16_t* end = utf_decoder<utf16_writer>::decode_utf32_block(reinterpret_cast<const uint32_t*>(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest)); + + return static_cast<size_t>(end - dest) * sizeof(uint16_t); + } + + // convert to utf32 + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + uint32_t* dest = reinterpret_cast<uint32_t*>(result); + + // convert to native utf32 + uint32_t* end = utf_decoder<utf32_writer>::decode_utf16_block(reinterpret_cast<const uint16_t*>(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest)); + + return static_cast<size_t>(end - dest) * sizeof(uint32_t); + } + + assert(!"Invalid encoding"); + return 0; + } +#else + size_t get_valid_length(const char_t* data, size_t length) + { + assert(length > 4); + + for (size_t i = 1; i <= 4; ++i) + { + uint8_t ch = static_cast<uint8_t>(data[length - i]); + + // either a standalone character or a leading one + if ((ch & 0xc0) != 0x80) return length - i; + } + + // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk + return length; + } + + size_t convert_buffer(char* result, const char_t* data, size_t length, xml_encoding encoding) + { + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + uint16_t* dest = reinterpret_cast<uint16_t*>(result); + + // convert to native utf16 + uint16_t* end = utf_decoder<utf16_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest)); + + return static_cast<size_t>(end - dest) * sizeof(uint16_t); + } + + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + uint32_t* dest = reinterpret_cast<uint32_t*>(result); + + // convert to native utf32 + uint32_t* end = utf_decoder<utf32_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest)); + + return static_cast<size_t>(end - dest) * sizeof(uint32_t); + } + + assert(!"Invalid encoding"); + return 0; + } +#endif + + class xml_buffered_writer + { + xml_buffered_writer(const xml_buffered_writer&); + xml_buffered_writer& operator=(const xml_buffered_writer&); + + public: + xml_buffered_writer(xml_writer& writer, xml_encoding user_encoding): writer(writer), bufsize(0), encoding(get_write_encoding(user_encoding)) + { + } + + ~xml_buffered_writer() + { + flush(); + } + + void flush() + { + flush(buffer, bufsize); + bufsize = 0; + } + + void flush(const char_t* data, size_t size) + { + if (size == 0) return; + + // fast path, just write data + if (encoding == get_write_native_encoding()) + writer.write(data, size * sizeof(char_t)); + else + { + // convert chunk + size_t result = convert_buffer(scratch, data, size, encoding); + assert(result <= sizeof(scratch)); + + // write data + writer.write(scratch, result); + } + } + + void write(const char_t* data, size_t length) + { + if (bufsize + length > bufcapacity) + { + // flush the remaining buffer contents + flush(); + + // handle large chunks + if (length > bufcapacity) + { + if (encoding == get_write_native_encoding()) + { + // fast path, can just write data chunk + writer.write(data, length * sizeof(char_t)); + return; + } + + // need to convert in suitable chunks + while (length > bufcapacity) + { + // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer + // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary) + size_t chunk_size = get_valid_length(data, bufcapacity); + + // convert chunk and write + flush(data, chunk_size); + + // iterate + data += chunk_size; + length -= chunk_size; + } + + // small tail is copied below + bufsize = 0; + } + } + + memcpy(buffer + bufsize, data, length * sizeof(char_t)); + bufsize += length; + } + + void write(const char_t* data) + { + write(data, strlength(data)); + } + + void write(char_t d0) + { + if (bufsize + 1 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + bufsize += 1; + } + + void write(char_t d0, char_t d1) + { + if (bufsize + 2 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + bufsize += 2; + } + + void write(char_t d0, char_t d1, char_t d2) + { + if (bufsize + 3 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + bufsize += 3; + } + + void write(char_t d0, char_t d1, char_t d2, char_t d3) + { + if (bufsize + 4 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + buffer[bufsize + 3] = d3; + bufsize += 4; + } + + void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4) + { + if (bufsize + 5 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + buffer[bufsize + 3] = d3; + buffer[bufsize + 4] = d4; + bufsize += 5; + } + + void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5) + { + if (bufsize + 6 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + buffer[bufsize + 3] = d3; + buffer[bufsize + 4] = d4; + buffer[bufsize + 5] = d5; + bufsize += 6; + } + + // utf8 maximum expansion: x4 (-> utf32) + // utf16 maximum expansion: x2 (-> utf32) + // utf32 maximum expansion: x1 + enum { bufcapacity = 2048 }; + + char_t buffer[bufcapacity]; + char scratch[4 * bufcapacity]; + + xml_writer& writer; + size_t bufsize; + xml_encoding encoding; + }; + + void write_bom(xml_writer& writer, xml_encoding encoding) + { + switch (encoding) + { + case encoding_utf8: + writer.write("\xef\xbb\xbf", 3); + break; + + case encoding_utf16_be: + writer.write("\xfe\xff", 2); + break; + + case encoding_utf16_le: + writer.write("\xff\xfe", 2); + break; + + case encoding_utf32_be: + writer.write("\x00\x00\xfe\xff", 4); + break; + + case encoding_utf32_le: + writer.write("\xff\xfe\x00\x00", 4); + break; + + default: + assert(!"Invalid encoding"); + } + } + + void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type) + { + while (*s) + { + const char_t* prev = s; + + // While *s is a usual symbol + while (!IS_CHARTYPEX(*s, type)) ++s; + + writer.write(prev, static_cast<size_t>(s - prev)); + + switch (*s) + { + case 0: break; + case '&': + writer.write('&', 'a', 'm', 'p', ';'); + ++s; + break; + case '<': + writer.write('&', 'l', 't', ';'); + ++s; + break; + case '>': + writer.write('&', 'g', 't', ';'); + ++s; + break; + case '"': + writer.write('&', 'q', 'u', 'o', 't', ';'); + ++s; + break; + default: // s is not a usual symbol + { + unsigned int ch = static_cast<unsigned int>(*s++); + assert(ch < 32); + + writer.write('&', '#', static_cast<char_t>((ch / 10) + '0'), static_cast<char_t>((ch % 10) + '0'), ';'); + } + } + } + } + + void text_output_cdata(xml_buffered_writer& writer, const char_t* s) + { + do + { + writer.write('<', '!', '[', 'C', 'D'); + writer.write('A', 'T', 'A', '['); + + const char_t* prev = s; + + // look for ]]> sequence - we can't output it as is since it terminates CDATA + while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s; + + // skip ]] if we stopped at ]]>, > will go to the next CDATA section + if (*s) s += 2; + + writer.write(prev, static_cast<size_t>(s - prev)); + + writer.write(']', ']', '>'); + } + while (*s); + } + + void node_output_attributes(xml_buffered_writer& writer, const xml_node& node) + { + const char_t* default_name = PUGIXML_TEXT(":anonymous"); + + for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute()) + { + writer.write(' '); + writer.write(a.name()[0] ? a.name() : default_name); + writer.write('=', '"'); + + text_output_escaped(writer, a.value(), ctx_special_attr); + + writer.write('"'); + } + } + + void node_output(xml_buffered_writer& writer, const xml_node& node, const char_t* indent, unsigned int flags, unsigned int depth) + { + const char_t* default_name = PUGIXML_TEXT(":anonymous"); + + if ((flags & format_indent) != 0 && (flags & format_raw) == 0) + for (unsigned int i = 0; i < depth; ++i) writer.write(indent); + + switch (node.type()) + { + case node_document: + { + for (xml_node n = node.first_child(); n; n = n.next_sibling()) + node_output(writer, n, indent, flags, depth); + break; + } + + case node_element: + { + const char_t* name = node.name()[0] ? node.name() : default_name; + + writer.write('<'); + writer.write(name); + + node_output_attributes(writer, node); + + if (flags & format_raw) + { + if (!node.first_child()) + writer.write(' ', '/', '>'); + else + { + writer.write('>'); + + for (xml_node n = node.first_child(); n; n = n.next_sibling()) + node_output(writer, n, indent, flags, depth + 1); + + writer.write('<', '/'); + writer.write(name); + writer.write('>'); + } + } + else if (!node.first_child()) + writer.write(' ', '/', '>', '\n'); + else if (node.first_child() == node.last_child() && (node.first_child().type() == node_pcdata || node.first_child().type() == node_cdata)) + { + writer.write('>'); + + if (node.first_child().type() == node_pcdata) + text_output_escaped(writer, node.first_child().value(), ctx_special_pcdata); + else + text_output_cdata(writer, node.first_child().value()); + + writer.write('<', '/'); + writer.write(name); + writer.write('>', '\n'); + } + else + { + writer.write('>', '\n'); + + for (xml_node n = node.first_child(); n; n = n.next_sibling()) + node_output(writer, n, indent, flags, depth + 1); + + if ((flags & format_indent) != 0 && (flags & format_raw) == 0) + for (unsigned int i = 0; i < depth; ++i) writer.write(indent); + + writer.write('<', '/'); + writer.write(name); + writer.write('>', '\n'); + } + + break; + } + + case node_pcdata: + text_output_escaped(writer, node.value(), ctx_special_pcdata); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_cdata: + text_output_cdata(writer, node.value()); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_comment: + writer.write('<', '!', '-', '-'); + writer.write(node.value()); + writer.write('-', '-', '>'); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_pi: + case node_declaration: + writer.write('<', '?'); + writer.write(node.name()[0] ? node.name() : default_name); + + if (node.type() == node_declaration) + { + node_output_attributes(writer, node); + } + else if (node.value()[0]) + { + writer.write(' '); + writer.write(node.value()); + } + + writer.write('?', '>'); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_doctype: + writer.write('<', '!', 'D', 'O', 'C'); + writer.write('T', 'Y', 'P', 'E'); + + if (node.value()[0]) + { + writer.write(' '); + writer.write(node.value()); + } + + writer.write('>'); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + default: + assert(!"Invalid node type"); + } + } + + inline bool has_declaration(const xml_node& node) + { + for (xml_node child = node.first_child(); child; child = child.next_sibling()) + { + xml_node_type type = child.type(); + + if (type == node_declaration) return true; + if (type == node_element) return false; + } + + return false; + } + + inline bool allow_insert_child(xml_node_type parent, xml_node_type child) + { + if (parent != node_document && parent != node_element) return false; + if (child == node_document || child == node_null) return false; + if (parent != node_document && (child == node_declaration || child == node_doctype)) return false; + + return true; + } + + void recursive_copy_skip(xml_node& dest, const xml_node& source, const xml_node& skip) + { + assert(dest.type() == source.type()); + + switch (source.type()) + { + case node_element: + { + dest.set_name(source.name()); + + for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute()) + dest.append_attribute(a.name()).set_value(a.value()); + + for (xml_node c = source.first_child(); c; c = c.next_sibling()) + { + if (c == skip) continue; + + xml_node cc = dest.append_child(c.type()); + assert(cc); + + recursive_copy_skip(cc, c, skip); + } + + break; + } + + case node_pcdata: + case node_cdata: + case node_comment: + case node_doctype: + dest.set_value(source.value()); + break; + + case node_pi: + dest.set_name(source.name()); + dest.set_value(source.value()); + break; + + case node_declaration: + { + dest.set_name(source.name()); + + for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute()) + dest.append_attribute(a.name()).set_value(a.value()); + + break; + } + + default: + assert(!"Invalid node type"); + } + } + + // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick + xml_parse_status get_file_size(FILE* file, size_t& out_result) + { + #if defined(_MSC_VER) && _MSC_VER >= 1400 + // there are 64-bit versions of fseek/ftell, let's use them + typedef __int64 length_type; + + _fseeki64(file, 0, SEEK_END); + length_type length = _ftelli64(file); + _fseeki64(file, 0, SEEK_SET); + #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__) + // there are 64-bit versions of fseek/ftell, let's use them + typedef off64_t length_type; + + fseeko64(file, 0, SEEK_END); + length_type length = ftello64(file); + fseeko64(file, 0, SEEK_SET); + #else + // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway. + typedef long length_type; + + fseek(file, 0, SEEK_END); + length_type length = ftell(file); + fseek(file, 0, SEEK_SET); + #endif + + // check for I/O errors + if (length < 0) return status_io_error; + + // check for overflow + size_t result = static_cast<size_t>(length); + + if (static_cast<length_type>(result) != length) return status_out_of_memory; + + // finalize + out_result = result; + + return status_ok; + } + + xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding) + { + if (!file) return make_parse_result(status_file_not_found); + + // get file size (can result in I/O errors) + size_t size = 0; + xml_parse_status size_status = get_file_size(file, size); + + if (size_status != status_ok) + { + fclose(file); + return make_parse_result(size_status); + } + + // allocate buffer for the whole file + char* contents = static_cast<char*>(global_allocate(size > 0 ? size : 1)); + + if (!contents) + { + fclose(file); + return make_parse_result(status_out_of_memory); + } + + // read file in memory + size_t read_size = fread(contents, 1, size, file); + fclose(file); + + if (read_size != size) + { + global_deallocate(contents); + return make_parse_result(status_io_error); + } + + return doc.load_buffer_inplace_own(contents, size, options, encoding); + } + +#ifndef PUGIXML_NO_STL + template <typename T> xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream<T>& stream, unsigned int options, xml_encoding encoding) + { + // get length of remaining data in stream + typename std::basic_istream<T>::pos_type pos = stream.tellg(); + stream.seekg(0, std::ios::end); + std::streamoff length = stream.tellg() - pos; + stream.seekg(pos); + + if (stream.fail() || pos < 0) return make_parse_result(status_io_error); + + // guard against huge files + size_t read_length = static_cast<size_t>(length); + + if (static_cast<std::streamsize>(read_length) != length || length < 0) return make_parse_result(status_out_of_memory); + + // read stream data into memory (guard against stream exceptions with buffer holder) + buffer_holder buffer(global_allocate((read_length > 0 ? read_length : 1) * sizeof(T)), global_deallocate); + if (!buffer.data) return make_parse_result(status_out_of_memory); + + stream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length)); + + // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors + if (stream.bad()) return make_parse_result(status_io_error); + + // load data from buffer + size_t actual_length = static_cast<size_t>(stream.gcount()); + assert(actual_length <= read_length); + + return doc.load_buffer_inplace_own(buffer.release(), actual_length * sizeof(T), options, encoding); + } +#endif + +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) + { + return _wfopen(path, mode); + } +#else + char* convert_path_heap(const wchar_t* str) + { + assert(str); + + // first pass: get length in utf8 characters + size_t length = wcslen(str); + size_t size = as_utf8_begin(str, length); + + // allocate resulting string + char* result = static_cast<char*>(global_allocate(size + 1)); + if (!result) return 0; + + // second pass: convert to utf8 + as_utf8_end(result, size, str, length); + + return result; + } + + FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) + { + // there is no standard function to open wide paths, so our best bet is to try utf8 path + char* path_utf8 = convert_path_heap(path); + if (!path_utf8) return 0; + + // convert mode to ASCII (we mirror _wfopen interface) + char mode_ascii[4] = {0}; + for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast<char>(mode[i]); + + // try to open the utf8 path + FILE* result = fopen(path_utf8, mode_ascii); + + // free dummy buffer + global_deallocate(path_utf8); + + return result; + } +#endif +} + +namespace pugi +{ + xml_writer_file::xml_writer_file(void* file): file(file) + { + } + + void xml_writer_file::write(const void* data, size_t size) + { + fwrite(data, size, 1, static_cast<FILE*>(file)); + } + +#ifndef PUGIXML_NO_STL + xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0) + { + } + + xml_writer_stream::xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream): narrow_stream(0), wide_stream(&stream) + { + } + + void xml_writer_stream::write(const void* data, size_t size) + { + if (narrow_stream) + { + assert(!wide_stream); + narrow_stream->write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size)); + } + else + { + assert(wide_stream); + assert(size % sizeof(wchar_t) == 0); + + wide_stream->write(reinterpret_cast<const wchar_t*>(data), static_cast<std::streamsize>(size / sizeof(wchar_t))); + } + } +#endif + + xml_tree_walker::xml_tree_walker(): _depth(0) + { + } + + xml_tree_walker::~xml_tree_walker() + { + } + + int xml_tree_walker::depth() const + { + return _depth; + } + + bool xml_tree_walker::begin(xml_node&) + { + return true; + } + + bool xml_tree_walker::end(xml_node&) + { + return true; + } + + xml_attribute::xml_attribute(): _attr(0) + { + } + + xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr) + { + } + + xml_attribute::operator xml_attribute::unspecified_bool_type() const + { + return _attr ? &xml_attribute::_attr : 0; + } + + bool xml_attribute::operator!() const + { + return !_attr; + } + + bool xml_attribute::operator==(const xml_attribute& r) const + { + return (_attr == r._attr); + } + + bool xml_attribute::operator!=(const xml_attribute& r) const + { + return (_attr != r._attr); + } + + bool xml_attribute::operator<(const xml_attribute& r) const + { + return (_attr < r._attr); + } + + bool xml_attribute::operator>(const xml_attribute& r) const + { + return (_attr > r._attr); + } + + bool xml_attribute::operator<=(const xml_attribute& r) const + { + return (_attr <= r._attr); + } + + bool xml_attribute::operator>=(const xml_attribute& r) const + { + return (_attr >= r._attr); + } + + xml_attribute xml_attribute::next_attribute() const + { + return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute(); + } + + xml_attribute xml_attribute::previous_attribute() const + { + return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute(); + } + + int xml_attribute::as_int() const + { + if (!_attr || !_attr->value) return 0; + + #ifdef PUGIXML_WCHAR_MODE + return (int)wcstol(_attr->value, 0, 10); + #else + return (int)strtol(_attr->value, 0, 10); + #endif + } + + unsigned int xml_attribute::as_uint() const + { + if (!_attr || !_attr->value) return 0; + + #ifdef PUGIXML_WCHAR_MODE + return (unsigned int)wcstoul(_attr->value, 0, 10); + #else + return (unsigned int)strtoul(_attr->value, 0, 10); + #endif + } + + double xml_attribute::as_double() const + { + if (!_attr || !_attr->value) return 0; + + #ifdef PUGIXML_WCHAR_MODE + return wcstod(_attr->value, 0); + #else + return strtod(_attr->value, 0); + #endif + } + + float xml_attribute::as_float() const + { + if (!_attr || !_attr->value) return 0; + + #ifdef PUGIXML_WCHAR_MODE + return (float)wcstod(_attr->value, 0); + #else + return (float)strtod(_attr->value, 0); + #endif + } + + bool xml_attribute::as_bool() const + { + if (!_attr || !_attr->value) return false; + + // only look at first char + char_t first = *_attr->value; + + // 1*, t* (true), T* (True), y* (yes), Y* (YES) + return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y'); + } + + bool xml_attribute::empty() const + { + return !_attr; + } + + const char_t* xml_attribute::name() const + { + return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT(""); + } + + const char_t* xml_attribute::value() const + { + return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT(""); + } + + size_t xml_attribute::hash_value() const + { + return static_cast<size_t>(reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct)); + } + + xml_attribute_struct* xml_attribute::internal_object() const + { + return _attr; + } + + xml_attribute& xml_attribute::operator=(const char_t* rhs) + { + set_value(rhs); + return *this; + } + + xml_attribute& xml_attribute::operator=(int rhs) + { + set_value(rhs); + return *this; + } + + xml_attribute& xml_attribute::operator=(unsigned int rhs) + { + set_value(rhs); + return *this; + } + + xml_attribute& xml_attribute::operator=(double rhs) + { + set_value(rhs); + return *this; + } + + xml_attribute& xml_attribute::operator=(bool rhs) + { + set_value(rhs); + return *this; + } + + bool xml_attribute::set_name(const char_t* rhs) + { + if (!_attr) return false; + + return strcpy_insitu(_attr->name, _attr->header, xml_memory_page_name_allocated_mask, rhs); + } + + bool xml_attribute::set_value(const char_t* rhs) + { + if (!_attr) return false; + + return strcpy_insitu(_attr->value, _attr->header, xml_memory_page_value_allocated_mask, rhs); + } + + bool xml_attribute::set_value(int rhs) + { + char buf[128]; + sprintf(buf, "%d", rhs); + + #ifdef PUGIXML_WCHAR_MODE + char_t wbuf[128]; + widen_ascii(wbuf, buf); + + return set_value(wbuf); + #else + return set_value(buf); + #endif + } + + bool xml_attribute::set_value(unsigned int rhs) + { + char buf[128]; + sprintf(buf, "%u", rhs); + + #ifdef PUGIXML_WCHAR_MODE + char_t wbuf[128]; + widen_ascii(wbuf, buf); + + return set_value(wbuf); + #else + return set_value(buf); + #endif + } + + bool xml_attribute::set_value(double rhs) + { + char buf[128]; + sprintf(buf, "%g", rhs); + + #ifdef PUGIXML_WCHAR_MODE + char_t wbuf[128]; + widen_ascii(wbuf, buf); + + return set_value(wbuf); + #else + return set_value(buf); + #endif + } + + bool xml_attribute::set_value(bool rhs) + { + return set_value(rhs ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); + } + +#ifdef __BORLANDC__ + bool operator&&(const xml_attribute& lhs, bool rhs) + { + return (bool)lhs && rhs; + } + + bool operator||(const xml_attribute& lhs, bool rhs) + { + return (bool)lhs || rhs; + } +#endif + + xml_node::xml_node(): _root(0) + { + } + + xml_node::xml_node(xml_node_struct* p): _root(p) + { + } + + xml_node::operator xml_node::unspecified_bool_type() const + { + return _root ? &xml_node::_root : 0; + } + + bool xml_node::operator!() const + { + return !_root; + } + + xml_node::iterator xml_node::begin() const + { + return iterator(_root ? _root->first_child : 0, _root); + } + + xml_node::iterator xml_node::end() const + { + return iterator(0, _root); + } + + xml_node::attribute_iterator xml_node::attributes_begin() const + { + return attribute_iterator(_root ? _root->first_attribute : 0, _root); + } + + xml_node::attribute_iterator xml_node::attributes_end() const + { + return attribute_iterator(0, _root); + } + + bool xml_node::operator==(const xml_node& r) const + { + return (_root == r._root); + } + + bool xml_node::operator!=(const xml_node& r) const + { + return (_root != r._root); + } + + bool xml_node::operator<(const xml_node& r) const + { + return (_root < r._root); + } + + bool xml_node::operator>(const xml_node& r) const + { + return (_root > r._root); + } + + bool xml_node::operator<=(const xml_node& r) const + { + return (_root <= r._root); + } + + bool xml_node::operator>=(const xml_node& r) const + { + return (_root >= r._root); + } + + bool xml_node::empty() const + { + return !_root; + } + + const char_t* xml_node::name() const + { + return (_root && _root->name) ? _root->name : PUGIXML_TEXT(""); + } + + xml_node_type xml_node::type() const + { + return _root ? static_cast<xml_node_type>((_root->header & xml_memory_page_type_mask) + 1) : node_null; + } + + const char_t* xml_node::value() const + { + return (_root && _root->value) ? _root->value : PUGIXML_TEXT(""); + } + + xml_node xml_node::child(const char_t* name) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if (i->name && strequal(name, i->name)) return xml_node(i); + + return xml_node(); + } + + xml_attribute xml_node::attribute(const char_t* name) const + { + if (!_root) return xml_attribute(); + + for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) + if (i->name && strequal(name, i->name)) + return xml_attribute(i); + + return xml_attribute(); + } + + xml_node xml_node::next_sibling(const char_t* name) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) + if (i->name && strequal(name, i->name)) return xml_node(i); + + return xml_node(); + } + + xml_node xml_node::next_sibling() const + { + if (!_root) return xml_node(); + + if (_root->next_sibling) return xml_node(_root->next_sibling); + else return xml_node(); + } + + xml_node xml_node::previous_sibling(const char_t* name) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) + if (i->name && strequal(name, i->name)) return xml_node(i); + + return xml_node(); + } + + xml_node xml_node::previous_sibling() const + { + if (!_root) return xml_node(); + + if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); + else return xml_node(); + } + + xml_node xml_node::parent() const + { + return _root ? xml_node(_root->parent) : xml_node(); + } + + xml_node xml_node::root() const + { + if (!_root) return xml_node(); + + xml_memory_page* page = reinterpret_cast<xml_memory_page*>(_root->header & xml_memory_page_pointer_mask); + + return xml_node(static_cast<xml_document_struct*>(page->allocator)); + } + + const char_t* xml_node::child_value() const + { + if (!_root) return PUGIXML_TEXT(""); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + { + xml_node_type type = static_cast<xml_node_type>((i->header & xml_memory_page_type_mask) + 1); + + if (i->value && (type == node_pcdata || type == node_cdata)) + return i->value; + } + + return PUGIXML_TEXT(""); + } + + const char_t* xml_node::child_value(const char_t* name) const + { + return child(name).child_value(); + } + + xml_attribute xml_node::first_attribute() const + { + return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); + } + + xml_attribute xml_node::last_attribute() const + { + return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute(); + } + + xml_node xml_node::first_child() const + { + return _root ? xml_node(_root->first_child) : xml_node(); + } + + xml_node xml_node::last_child() const + { + return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); + } + + bool xml_node::set_name(const char_t* rhs) + { + switch (type()) + { + case node_pi: + case node_declaration: + case node_element: + return strcpy_insitu(_root->name, _root->header, xml_memory_page_name_allocated_mask, rhs); + + default: + return false; + } + } + + bool xml_node::set_value(const char_t* rhs) + { + switch (type()) + { + case node_pi: + case node_cdata: + case node_pcdata: + case node_comment: + case node_doctype: + return strcpy_insitu(_root->value, _root->header, xml_memory_page_value_allocated_mask, rhs); + + default: + return false; + } + } + + xml_attribute xml_node::append_attribute(const char_t* name) + { + if (type() != node_element && type() != node_declaration) return xml_attribute(); + + xml_attribute a(append_attribute_ll(_root, get_allocator(_root))); + a.set_name(name); + + return a; + } + + xml_attribute xml_node::prepend_attribute(const char_t* name) + { + if (type() != node_element && type() != node_declaration) return xml_attribute(); + + xml_attribute a(allocate_attribute(get_allocator(_root))); + if (!a) return xml_attribute(); + + a.set_name(name); + + xml_attribute_struct* head = _root->first_attribute; + + if (head) + { + a._attr->prev_attribute_c = head->prev_attribute_c; + head->prev_attribute_c = a._attr; + } + else + a._attr->prev_attribute_c = a._attr; + + a._attr->next_attribute = head; + _root->first_attribute = a._attr; + + return a; + } + + xml_attribute xml_node::insert_attribute_before(const char_t* name, const xml_attribute& attr) + { + if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute(); + + // check that attribute belongs to *this + xml_attribute_struct* cur = attr._attr; + + while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c; + + if (cur != _root->first_attribute) return xml_attribute(); + + xml_attribute a(allocate_attribute(get_allocator(_root))); + if (!a) return xml_attribute(); + + a.set_name(name); + + if (attr._attr->prev_attribute_c->next_attribute) + attr._attr->prev_attribute_c->next_attribute = a._attr; + else + _root->first_attribute = a._attr; + + a._attr->prev_attribute_c = attr._attr->prev_attribute_c; + a._attr->next_attribute = attr._attr; + attr._attr->prev_attribute_c = a._attr; + + return a; + } + + xml_attribute xml_node::insert_attribute_after(const char_t* name, const xml_attribute& attr) + { + if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute(); + + // check that attribute belongs to *this + xml_attribute_struct* cur = attr._attr; + + while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c; + + if (cur != _root->first_attribute) return xml_attribute(); + + xml_attribute a(allocate_attribute(get_allocator(_root))); + if (!a) return xml_attribute(); + + a.set_name(name); + + if (attr._attr->next_attribute) + attr._attr->next_attribute->prev_attribute_c = a._attr; + else + _root->first_attribute->prev_attribute_c = a._attr; + + a._attr->next_attribute = attr._attr->next_attribute; + a._attr->prev_attribute_c = attr._attr; + attr._attr->next_attribute = a._attr; + + return a; + } + + xml_attribute xml_node::append_copy(const xml_attribute& proto) + { + if (!proto) return xml_attribute(); + + xml_attribute result = append_attribute(proto.name()); + result.set_value(proto.value()); + + return result; + } + + xml_attribute xml_node::prepend_copy(const xml_attribute& proto) + { + if (!proto) return xml_attribute(); + + xml_attribute result = prepend_attribute(proto.name()); + result.set_value(proto.value()); + + return result; + } + + xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr) + { + if (!proto) return xml_attribute(); + + xml_attribute result = insert_attribute_after(proto.name(), attr); + result.set_value(proto.value()); + + return result; + } + + xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr) + { + if (!proto) return xml_attribute(); + + xml_attribute result = insert_attribute_before(proto.name(), attr); + result.set_value(proto.value()); + + return result; + } + + xml_node xml_node::append_child(xml_node_type type) + { + if (!allow_insert_child(this->type(), type)) return xml_node(); + + xml_node n(append_node(_root, get_allocator(_root), type)); + + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + xml_node xml_node::prepend_child(xml_node_type type) + { + if (!allow_insert_child(this->type(), type)) return xml_node(); + + xml_node n(allocate_node(get_allocator(_root), type)); + if (!n) return xml_node(); + + n._root->parent = _root; + + xml_node_struct* head = _root->first_child; + + if (head) + { + n._root->prev_sibling_c = head->prev_sibling_c; + head->prev_sibling_c = n._root; + } + else + n._root->prev_sibling_c = n._root; + + n._root->next_sibling = head; + _root->first_child = n._root; + + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + xml_node xml_node::insert_child_before(xml_node_type type, const xml_node& node) + { + if (!allow_insert_child(this->type(), type)) return xml_node(); + if (!node._root || node._root->parent != _root) return xml_node(); + + xml_node n(allocate_node(get_allocator(_root), type)); + if (!n) return xml_node(); + + n._root->parent = _root; + + if (node._root->prev_sibling_c->next_sibling) + node._root->prev_sibling_c->next_sibling = n._root; + else + _root->first_child = n._root; + + n._root->prev_sibling_c = node._root->prev_sibling_c; + n._root->next_sibling = node._root; + node._root->prev_sibling_c = n._root; + + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + xml_node xml_node::insert_child_after(xml_node_type type, const xml_node& node) + { + if (!allow_insert_child(this->type(), type)) return xml_node(); + if (!node._root || node._root->parent != _root) return xml_node(); + + xml_node n(allocate_node(get_allocator(_root), type)); + if (!n) return xml_node(); + + n._root->parent = _root; + + if (node._root->next_sibling) + node._root->next_sibling->prev_sibling_c = n._root; + else + _root->first_child->prev_sibling_c = n._root; + + n._root->next_sibling = node._root->next_sibling; + n._root->prev_sibling_c = node._root; + node._root->next_sibling = n._root; + + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + xml_node xml_node::append_child(const char_t* name) + { + xml_node result = append_child(node_element); + + result.set_name(name); + + return result; + } + + xml_node xml_node::prepend_child(const char_t* name) + { + xml_node result = prepend_child(node_element); + + result.set_name(name); + + return result; + } + + xml_node xml_node::insert_child_after(const char_t* name, const xml_node& node) + { + xml_node result = insert_child_after(node_element, node); + + result.set_name(name); + + return result; + } + + xml_node xml_node::insert_child_before(const char_t* name, const xml_node& node) + { + xml_node result = insert_child_before(node_element, node); + + result.set_name(name); + + return result; + } + + xml_node xml_node::append_copy(const xml_node& proto) + { + xml_node result = append_child(proto.type()); + + if (result) recursive_copy_skip(result, proto, result); + + return result; + } + + xml_node xml_node::prepend_copy(const xml_node& proto) + { + xml_node result = prepend_child(proto.type()); + + if (result) recursive_copy_skip(result, proto, result); + + return result; + } + + xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) + { + xml_node result = insert_child_after(proto.type(), node); + + if (result) recursive_copy_skip(result, proto, result); + + return result; + } + + xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) + { + xml_node result = insert_child_before(proto.type(), node); + + if (result) recursive_copy_skip(result, proto, result); + + return result; + } + + bool xml_node::remove_attribute(const char_t* name) + { + return remove_attribute(attribute(name)); + } + + bool xml_node::remove_attribute(const xml_attribute& a) + { + if (!_root || !a._attr) return false; + + // check that attribute belongs to *this + xml_attribute_struct* attr = a._attr; + + while (attr->prev_attribute_c->next_attribute) attr = attr->prev_attribute_c; + + if (attr != _root->first_attribute) return false; + + if (a._attr->next_attribute) a._attr->next_attribute->prev_attribute_c = a._attr->prev_attribute_c; + else if (_root->first_attribute) _root->first_attribute->prev_attribute_c = a._attr->prev_attribute_c; + + if (a._attr->prev_attribute_c->next_attribute) a._attr->prev_attribute_c->next_attribute = a._attr->next_attribute; + else _root->first_attribute = a._attr->next_attribute; + + destroy_attribute(a._attr, get_allocator(_root)); + + return true; + } + + bool xml_node::remove_child(const char_t* name) + { + return remove_child(child(name)); + } + + bool xml_node::remove_child(const xml_node& n) + { + if (!_root || !n._root || n._root->parent != _root) return false; + + if (n._root->next_sibling) n._root->next_sibling->prev_sibling_c = n._root->prev_sibling_c; + else if (_root->first_child) _root->first_child->prev_sibling_c = n._root->prev_sibling_c; + + if (n._root->prev_sibling_c->next_sibling) n._root->prev_sibling_c->next_sibling = n._root->next_sibling; + else _root->first_child = n._root->next_sibling; + + destroy_node(n._root, get_allocator(_root)); + + return true; + } + + xml_node xml_node::find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if (i->name && strequal(name, i->name)) + { + for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) + if (strequal(attr_name, a->name) && strequal(attr_value, a->value)) + return xml_node(i); + } + + return xml_node(); + } + + xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) + if (strequal(attr_name, a->name) && strequal(attr_value, a->value)) + return xml_node(i); + + return xml_node(); + } + +#ifndef PUGIXML_NO_STL + string_t xml_node::path(char_t delimiter) const + { + string_t path; + + xml_node cursor = *this; // Make a copy. + + path = cursor.name(); + + while (cursor.parent()) + { + cursor = cursor.parent(); + + string_t temp = cursor.name(); + temp += delimiter; + temp += path; + path.swap(temp); + } + + return path; + } +#endif + + xml_node xml_node::first_element_by_path(const char_t* path, char_t delimiter) const + { + xml_node found = *this; // Current search context. + + if (!_root || !path || !path[0]) return found; + + if (path[0] == delimiter) + { + // Absolute path; e.g. '/foo/bar' + found = found.root(); + ++path; + } + + const char_t* path_segment = path; + + while (*path_segment == delimiter) ++path_segment; + + const char_t* path_segment_end = path_segment; + + while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end; + + if (path_segment == path_segment_end) return found; + + const char_t* next_segment = path_segment_end; + + while (*next_segment == delimiter) ++next_segment; + + if (*path_segment == '.' && path_segment + 1 == path_segment_end) + return found.first_element_by_path(next_segment, delimiter); + else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end) + return found.parent().first_element_by_path(next_segment, delimiter); + else + { + for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling) + { + if (j->name && strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment))) + { + xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter); + + if (subsearch) return subsearch; + } + } + + return xml_node(); + } + } + + bool xml_node::traverse(xml_tree_walker& walker) + { + walker._depth = -1; + + xml_node arg_begin = *this; + if (!walker.begin(arg_begin)) return false; + + xml_node cur = first_child(); + + if (cur) + { + ++walker._depth; + + do + { + xml_node arg_for_each = cur; + if (!walker.for_each(arg_for_each)) + return false; + + if (cur.first_child()) + { + ++walker._depth; + cur = cur.first_child(); + } + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + // Borland C++ workaround + while (!cur.next_sibling() && cur != *this && (bool)cur.parent()) + { + --walker._depth; + cur = cur.parent(); + } + + if (cur != *this) + cur = cur.next_sibling(); + } + } + while (cur && cur != *this); + } + + assert(walker._depth == -1); + + xml_node arg_end = *this; + return walker.end(arg_end); + } + + size_t xml_node::hash_value() const + { + return static_cast<size_t>(reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct)); + } + + xml_node_struct* xml_node::internal_object() const + { + return _root; + } + + void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const + { + if (!_root) return; + + xml_buffered_writer buffered_writer(writer, encoding); + + node_output(buffered_writer, *this, indent, flags, depth); + } + +#ifndef PUGIXML_NO_STL + void xml_node::print(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const + { + xml_writer_stream writer(stream); + + print(writer, indent, flags, encoding, depth); + } + + void xml_node::print(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const + { + xml_writer_stream writer(stream); + + print(writer, indent, flags, encoding_wchar, depth); + } +#endif + + ptrdiff_t xml_node::offset_debug() const + { + xml_node_struct* r = root()._root; + + if (!r) return -1; + + const char_t* buffer = static_cast<xml_document_struct*>(r)->buffer; + + if (!buffer) return -1; + + switch (type()) + { + case node_document: + return 0; + + case node_element: + case node_declaration: + case node_pi: + return (_root->header & xml_memory_page_name_allocated_mask) ? -1 : _root->name - buffer; + + case node_pcdata: + case node_cdata: + case node_comment: + case node_doctype: + return (_root->header & xml_memory_page_value_allocated_mask) ? -1 : _root->value - buffer; + + default: + return -1; + } + } + +#ifdef __BORLANDC__ + bool operator&&(const xml_node& lhs, bool rhs) + { + return (bool)lhs && rhs; + } + + bool operator||(const xml_node& lhs, bool rhs) + { + return (bool)lhs || rhs; + } +#endif + + xml_node_iterator::xml_node_iterator() + { + } + + xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent()) + { + } + + xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) + { + } + + bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const + { + return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; + } + + bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const + { + return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; + } + + xml_node& xml_node_iterator::operator*() + { + assert(_wrap._root); + return _wrap; + } + + xml_node* xml_node_iterator::operator->() + { + assert(_wrap._root); + return &_wrap; + } + + const xml_node_iterator& xml_node_iterator::operator++() + { + assert(_wrap._root); + _wrap._root = _wrap._root->next_sibling; + return *this; + } + + xml_node_iterator xml_node_iterator::operator++(int) + { + xml_node_iterator temp = *this; + ++*this; + return temp; + } + + const xml_node_iterator& xml_node_iterator::operator--() + { + _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child(); + return *this; + } + + xml_node_iterator xml_node_iterator::operator--(int) + { + xml_node_iterator temp = *this; + --*this; + return temp; + } + + xml_attribute_iterator::xml_attribute_iterator() + { + } + + xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent) + { + } + + xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) + { + } + + bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const + { + return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; + } + + bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const + { + return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; + } + + xml_attribute& xml_attribute_iterator::operator*() + { + assert(_wrap._attr); + return _wrap; + } + + xml_attribute* xml_attribute_iterator::operator->() + { + assert(_wrap._attr); + return &_wrap; + } + + const xml_attribute_iterator& xml_attribute_iterator::operator++() + { + assert(_wrap._attr); + _wrap._attr = _wrap._attr->next_attribute; + return *this; + } + + xml_attribute_iterator xml_attribute_iterator::operator++(int) + { + xml_attribute_iterator temp = *this; + ++*this; + return temp; + } + + const xml_attribute_iterator& xml_attribute_iterator::operator--() + { + _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute(); + return *this; + } + + xml_attribute_iterator xml_attribute_iterator::operator--(int) + { + xml_attribute_iterator temp = *this; + --*this; + return temp; + } + + xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto) + { + } + + xml_parse_result::operator bool() const + { + return status == status_ok; + } + + const char* xml_parse_result::description() const + { + switch (status) + { + case status_ok: return "No error"; + + case status_file_not_found: return "File was not found"; + case status_io_error: return "Error reading from file/stream"; + case status_out_of_memory: return "Could not allocate memory"; + case status_internal_error: return "Internal error occurred"; + + case status_unrecognized_tag: return "Could not determine tag type"; + + case status_bad_pi: return "Error parsing document declaration/processing instruction"; + case status_bad_comment: return "Error parsing comment"; + case status_bad_cdata: return "Error parsing CDATA section"; + case status_bad_doctype: return "Error parsing document type declaration"; + case status_bad_pcdata: return "Error parsing PCDATA section"; + case status_bad_start_element: return "Error parsing start element tag"; + case status_bad_attribute: return "Error parsing element attribute"; + case status_bad_end_element: return "Error parsing end element tag"; + case status_end_element_mismatch: return "Start-end tags mismatch"; + + default: return "Unknown error"; + } + } + + xml_document::xml_document(): _buffer(0) + { + create(); + } + + xml_document::~xml_document() + { + destroy(); + } + + void xml_document::reset() + { + destroy(); + create(); + } + + void xml_document::reset(const xml_document& proto) + { + reset(); + + for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) + append_copy(cur); + } + + void xml_document::create() + { + // initialize sentinel page + STATIC_ASSERT(offsetof(xml_memory_page, data) + sizeof(xml_document_struct) + xml_memory_page_alignment <= sizeof(_memory)); + + // align upwards to page boundary + void* page_memory = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(_memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1)); + + // prepare page structure + xml_memory_page* page = xml_memory_page::construct(page_memory); + + page->busy_size = xml_memory_page_size; + + // allocate new root + _root = new (page->data) xml_document_struct(page); + _root->prev_sibling_c = _root; + + // setup sentinel page + page->allocator = static_cast<xml_document_struct*>(_root); + } + + void xml_document::destroy() + { + // destroy static storage + if (_buffer) + { + global_deallocate(_buffer); + _buffer = 0; + } + + // destroy dynamic storage, leave sentinel page (it's in static memory) + if (_root) + { + xml_memory_page* root_page = reinterpret_cast<xml_memory_page*>(_root->header & xml_memory_page_pointer_mask); + assert(root_page && !root_page->prev && !root_page->memory); + + // destroy all pages + for (xml_memory_page* page = root_page->next; page; ) + { + xml_memory_page* next = page->next; + + xml_allocator::deallocate_page(page); + + page = next; + } + + // cleanup root page + root_page->allocator = 0; + root_page->next = 0; + root_page->busy_size = root_page->freed_size = 0; + + _root = 0; + } + } + +#ifndef PUGIXML_NO_STL + xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options, xml_encoding encoding) + { + reset(); + + return load_stream_impl(*this, stream, options, encoding); + } + + xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options) + { + reset(); + + return load_stream_impl(*this, stream, options, encoding_wchar); + } +#endif + + xml_parse_result xml_document::load(const char_t* contents, unsigned int options) + { + // Force native encoding (skip autodetection) + #ifdef PUGIXML_WCHAR_MODE + xml_encoding encoding = encoding_wchar; + #else + xml_encoding encoding = encoding_utf8; + #endif + + return load_buffer(contents, strlength(contents) * sizeof(char_t), options, encoding); + } + + xml_parse_result xml_document::load_file(const char* path, unsigned int options, xml_encoding encoding) + { + reset(); + + FILE* file = fopen(path, "rb"); + + return load_file_impl(*this, file, options, encoding); + } + + xml_parse_result xml_document::load_file(const wchar_t* path, unsigned int options, xml_encoding encoding) + { + reset(); + + FILE* file = open_file_wide(path, L"rb"); + + return load_file_impl(*this, file, options, encoding); + } + + xml_parse_result xml_document::load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own) + { + reset(); + + // check input buffer + assert(contents || size == 0); + + // get actual encoding + xml_encoding buffer_encoding = get_buffer_encoding(encoding, contents, size); + + // get private buffer + char_t* buffer = 0; + size_t length = 0; + + if (!convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return make_parse_result(status_out_of_memory); + + // delete original buffer if we performed a conversion + if (own && buffer != contents && contents) global_deallocate(contents); + + // parse + xml_parse_result res = xml_parser::parse(buffer, length, _root, options); + + // remember encoding + res.encoding = buffer_encoding; + + // grab onto buffer if it's our buffer, user is responsible for deallocating contens himself + if (own || buffer != contents) _buffer = buffer; + + return res; + } + + xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) + { + return load_buffer_impl(const_cast<void*>(contents), size, options, encoding, false, false); + } + + xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding) + { + return load_buffer_impl(contents, size, options, encoding, true, false); + } + + xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding) + { + return load_buffer_impl(contents, size, options, encoding, true, true); + } + + void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + if (flags & format_write_bom) write_bom(writer, get_write_encoding(encoding)); + + xml_buffered_writer buffered_writer(writer, encoding); + + if (!(flags & format_no_declaration) && !has_declaration(*this)) + { + buffered_writer.write(PUGIXML_TEXT("<?xml version=\"1.0\"?>")); + if (!(flags & format_raw)) buffered_writer.write('\n'); + } + + node_output(buffered_writer, *this, indent, flags, 0); + } + +#ifndef PUGIXML_NO_STL + void xml_document::save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + xml_writer_stream writer(stream); + + save(writer, indent, flags, encoding); + } + + void xml_document::save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags) const + { + xml_writer_stream writer(stream); + + save(writer, indent, flags, encoding_wchar); + } +#endif + + bool xml_document::save_file(const char* path, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + FILE* file = fopen(path, "wb"); + if (!file) return false; + + xml_writer_file writer(file); + save(writer, indent, flags, encoding); + + fclose(file); + + return true; + } + + bool xml_document::save_file(const wchar_t* path, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + FILE* file = open_file_wide(path, L"wb"); + if (!file) return false; + + xml_writer_file writer(file); + save(writer, indent, flags, encoding); + + fclose(file); + + return true; + } + + xml_node xml_document::document_element() const + { + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if ((i->header & xml_memory_page_type_mask) + 1 == node_element) + return xml_node(i); + + return xml_node(); + } + +#ifndef PUGIXML_NO_STL + std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) + { + assert(str); + + return as_utf8_impl(str, wcslen(str)); + } + + std::string PUGIXML_FUNCTION as_utf8(const std::wstring& str) + { + return as_utf8_impl(str.c_str(), str.size()); + } + + std::wstring PUGIXML_FUNCTION as_wide(const char* str) + { + assert(str); + + return as_wide_impl(str, strlen(str)); + } + + std::wstring PUGIXML_FUNCTION as_wide(const std::string& str) + { + return as_wide_impl(str.c_str(), str.size()); + } +#endif + + void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate) + { + global_allocate = allocate; + global_deallocate = deallocate; + } + + allocation_function PUGIXML_FUNCTION get_memory_allocation_function() + { + return global_allocate; + } + + deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function() + { + return global_deallocate; + } +} + +#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) +namespace std +{ + // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) + std::bidirectional_iterator_tag _Iter_cat(const xml_node_iterator&) + { + return std::bidirectional_iterator_tag(); + } + + std::bidirectional_iterator_tag _Iter_cat(const xml_attribute_iterator&) + { + return std::bidirectional_iterator_tag(); + } +} +#endif + +#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) +namespace std +{ + // Workarounds for (non-standard) iterator category detection + std::bidirectional_iterator_tag __iterator_category(const xml_node_iterator&) + { + return std::bidirectional_iterator_tag(); + } + + std::bidirectional_iterator_tag __iterator_category(const xml_attribute_iterator&) + { + return std::bidirectional_iterator_tag(); + } +} +#endif + +#ifndef PUGIXML_NO_XPATH + +// STL replacements +namespace +{ + struct equal_to + { + template <typename T> bool operator()(const T& lhs, const T& rhs) const + { + return lhs == rhs; + } + }; + + struct not_equal_to + { + template <typename T> bool operator()(const T& lhs, const T& rhs) const + { + return lhs != rhs; + } + }; + + struct less + { + template <typename T> bool operator()(const T& lhs, const T& rhs) const + { + return lhs < rhs; + } + }; + + struct less_equal + { + template <typename T> bool operator()(const T& lhs, const T& rhs) const + { + return lhs <= rhs; + } + }; + + template <typename T> void swap(T& lhs, T& rhs) + { + T temp = lhs; + lhs = rhs; + rhs = temp; + } + + template <typename I, typename Pred> I min_element(I begin, I end, const Pred& pred) + { + I result = begin; + + for (I it = begin + 1; it != end; ++it) + if (pred(*it, *result)) + result = it; + + return result; + } + + template <typename I> void reverse(I begin, I end) + { + while (begin + 1 < end) swap(*begin++, *--end); + } + + template <typename I> I unique(I begin, I end) + { + // fast skip head + while (begin + 1 < end && *begin != *(begin + 1)) begin++; + + if (begin == end) return begin; + + // last written element + I write = begin++; + + // merge unique elements + while (begin != end) + { + if (*begin != *write) + *++write = *begin++; + else + begin++; + } + + // past-the-end (write points to live element) + return write + 1; + } + + template <typename I> void copy_backwards(I begin, I end, I target) + { + while (begin != end) *--target = *--end; + } + + template <typename I, typename Pred, typename T> void insertion_sort(I begin, I end, const Pred& pred, T*) + { + assert(begin != end); + + for (I it = begin + 1; it != end; ++it) + { + T val = *it; + + if (pred(val, *begin)) + { + // move to front + copy_backwards(begin, it, it + 1); + *begin = val; + } + else + { + I hole = it; + + // move hole backwards + while (pred(val, *(hole - 1))) + { + *hole = *(hole - 1); + hole--; + } + + // fill hole with element + *hole = val; + } + } + } + + // std variant for elements with == + template <typename I, typename Pred> void partition(I begin, I middle, I end, const Pred& pred, I* out_eqbeg, I* out_eqend) + { + I eqbeg = middle, eqend = middle + 1; + + // expand equal range + while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg; + while (eqend != end && *eqend == *eqbeg) ++eqend; + + // process outer elements + I ltend = eqbeg, gtbeg = eqend; + + for (;;) + { + // find the element from the right side that belongs to the left one + for (; gtbeg != end; ++gtbeg) + if (!pred(*eqbeg, *gtbeg)) + { + if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++); + else break; + } + + // find the element from the left side that belongs to the right one + for (; ltend != begin; --ltend) + if (!pred(*(ltend - 1), *eqbeg)) + { + if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg); + else break; + } + + // scanned all elements + if (gtbeg == end && ltend == begin) + { + *out_eqbeg = eqbeg; + *out_eqend = eqend; + return; + } + + // make room for elements by moving equal area + if (gtbeg == end) + { + if (--ltend != --eqbeg) swap(*ltend, *eqbeg); + swap(*eqbeg, *--eqend); + } + else if (ltend == begin) + { + if (eqend != gtbeg) swap(*eqbeg, *eqend); + ++eqend; + swap(*gtbeg++, *eqbeg++); + } + else swap(*gtbeg++, *--ltend); + } + } + + template <typename I, typename Pred> void median3(I first, I middle, I last, const Pred& pred) + { + if (pred(*middle, *first)) swap(*middle, *first); + if (pred(*last, *middle)) swap(*last, *middle); + if (pred(*middle, *first)) swap(*middle, *first); + } + + template <typename I, typename Pred> void median(I first, I middle, I last, const Pred& pred) + { + if (last - first <= 40) + { + // median of three for small chunks + median3(first, middle, last, pred); + } + else + { + // median of nine + size_t step = (last - first + 1) / 8; + + median3(first, first + step, first + 2 * step, pred); + median3(middle - step, middle, middle + step, pred); + median3(last - 2 * step, last - step, last, pred); + median3(first + step, middle, last - step, pred); + } + } + + template <typename I, typename Pred> void sort(I begin, I end, const Pred& pred) + { + // sort large chunks + while (end - begin > 32) + { + // find median element + I middle = begin + (end - begin) / 2; + median(begin, middle, end - 1, pred); + + // partition in three chunks (< = >) + I eqbeg, eqend; + partition(begin, middle, end, pred, &eqbeg, &eqend); + + // loop on larger half + if (eqbeg - begin > end - eqend) + { + sort(eqend, end, pred); + end = eqbeg; + } + else + { + sort(begin, eqbeg, pred); + begin = eqend; + } + } + + // insertion sort small chunk + if (begin != end) insertion_sort(begin, end, pred, &*begin); + } +} + +// Allocator used for AST and evaluation stacks +namespace +{ + struct xpath_memory_block + { + xpath_memory_block* next; + + char data[4096]; + }; + + class xpath_allocator + { + xpath_memory_block* _root; + size_t _root_size; + + public: + #ifdef PUGIXML_NO_EXCEPTIONS + jmp_buf* error_handler; + #endif + + xpath_allocator(xpath_memory_block* root, size_t root_size = 0): _root(root), _root_size(root_size) + { + #ifdef PUGIXML_NO_EXCEPTIONS + error_handler = 0; + #endif + } + + void* allocate_nothrow(size_t size) + { + const size_t block_capacity = sizeof(_root->data); + + // align size so that we're able to store pointers in subsequent blocks + size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + + if (_root_size + size <= block_capacity) + { + void* buf = _root->data + _root_size; + _root_size += size; + return buf; + } + else + { + size_t block_data_size = (size > block_capacity) ? size : block_capacity; + size_t block_size = block_data_size + offsetof(xpath_memory_block, data); + + xpath_memory_block* block = static_cast<xpath_memory_block*>(global_allocate(block_size)); + if (!block) return 0; + + block->next = _root; + + _root = block; + _root_size = size; + + return block->data; + } + } + + void* allocate(size_t size) + { + void* result = allocate_nothrow(size); + + if (!result) + { + #ifdef PUGIXML_NO_EXCEPTIONS + assert(error_handler); + longjmp(*error_handler, 1); + #else + throw std::bad_alloc(); + #endif + } + + return result; + } + + void* reallocate(void* ptr, size_t old_size, size_t new_size) + { + // align size so that we're able to store pointers in subsequent blocks + old_size = (old_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + new_size = (new_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + + // we can only reallocate the last object + assert(ptr == 0 || static_cast<char*>(ptr) + old_size == _root->data + _root_size); + + // adjust root size so that we have not allocated the object at all + bool only_object = (_root_size == old_size); + + if (ptr) _root_size -= old_size; + + // allocate a new version (this will obviously reuse the memory if possible) + void* result = allocate(new_size); + assert(result); + + // we have a new block + if (result != ptr && ptr) + { + // copy old data + assert(new_size > old_size); + memcpy(result, ptr, old_size); + + // free the previous page if it had no other objects + if (only_object) + { + assert(_root->data == result); + assert(_root->next); + + xpath_memory_block* next = _root->next->next; + + if (next) + { + // deallocate the whole page, unless it was the first one + global_deallocate(_root->next); + _root->next = next; + } + } + } + + return result; + } + + void revert(const xpath_allocator& state) + { + // free all new pages + xpath_memory_block* cur = _root; + + while (cur != state._root) + { + xpath_memory_block* next = cur->next; + + global_deallocate(cur); + + cur = next; + } + + // restore state + _root = state._root; + _root_size = state._root_size; + } + + void release() + { + xpath_memory_block* cur = _root; + assert(cur); + + while (cur->next) + { + xpath_memory_block* next = cur->next; + + global_deallocate(cur); + + cur = next; + } + } + }; + + struct xpath_allocator_capture + { + xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc) + { + } + + ~xpath_allocator_capture() + { + _target->revert(_state); + } + + xpath_allocator* _target; + xpath_allocator _state; + }; + + struct xpath_stack + { + xpath_allocator* result; + xpath_allocator* temp; + }; + + struct xpath_stack_data + { + xpath_memory_block blocks[2]; + xpath_allocator result; + xpath_allocator temp; + xpath_stack stack; + + #ifdef PUGIXML_NO_EXCEPTIONS + jmp_buf error_handler; + #endif + + xpath_stack_data(): result(blocks + 0), temp(blocks + 1) + { + blocks[0].next = blocks[1].next = 0; + + stack.result = &result; + stack.temp = &temp; + + #ifdef PUGIXML_NO_EXCEPTIONS + result.error_handler = temp.error_handler = &error_handler; + #endif + } + + ~xpath_stack_data() + { + result.release(); + temp.release(); + } + }; +} + +// String class +namespace +{ + class xpath_string + { + const char_t* _buffer; + bool _uses_heap; + + static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc) + { + char_t* result = static_cast<char_t*>(alloc->allocate((length + 1) * sizeof(char_t))); + assert(result); + + memcpy(result, string, length * sizeof(char_t)); + result[length] = 0; + + return result; + } + + static char_t* duplicate_string(const char_t* string, xpath_allocator* alloc) + { + return duplicate_string(string, strlength(string), alloc); + } + + public: + xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false) + { + } + + explicit xpath_string(const char_t* str, xpath_allocator* alloc) + { + bool empty = (*str == 0); + + _buffer = empty ? PUGIXML_TEXT("") : duplicate_string(str, alloc); + _uses_heap = !empty; + } + + explicit xpath_string(const char_t* str, bool use_heap): _buffer(str), _uses_heap(use_heap) + { + } + + xpath_string(const char_t* begin, const char_t* end, xpath_allocator* alloc) + { + assert(begin <= end); + + bool empty = (begin == end); + + _buffer = empty ? PUGIXML_TEXT("") : duplicate_string(begin, static_cast<size_t>(end - begin), alloc); + _uses_heap = !empty; + } + + void append(const xpath_string& o, xpath_allocator* alloc) + { + // skip empty sources + if (!*o._buffer) return; + + // fast append for constant empty target and constant source + if (!*_buffer && !_uses_heap && !o._uses_heap) + { + _buffer = o._buffer; + } + else + { + // need to make heap copy + size_t target_length = strlength(_buffer); + size_t source_length = strlength(o._buffer); + size_t length = target_length + source_length; + + // allocate new buffer + char_t* result = static_cast<char_t*>(alloc->reallocate(_uses_heap ? const_cast<char_t*>(_buffer) : 0, (target_length + 1) * sizeof(char_t), (length + 1) * sizeof(char_t))); + assert(result); + + // append first string to the new buffer in case there was no reallocation + if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t)); + + // append second string to the new buffer + memcpy(result + target_length, o._buffer, source_length * sizeof(char_t)); + result[length] = 0; + + // finalize + _buffer = result; + _uses_heap = true; + } + } + + const char_t* c_str() const + { + return _buffer; + } + + size_t length() const + { + return strlength(_buffer); + } + + char_t* data(xpath_allocator* alloc) + { + // make private heap copy + if (!_uses_heap) + { + _buffer = duplicate_string(_buffer, alloc); + _uses_heap = true; + } + + return const_cast<char_t*>(_buffer); + } + + bool empty() const + { + return *_buffer == 0; + } + + bool operator==(const xpath_string& o) const + { + return strequal(_buffer, o._buffer); + } + + bool operator!=(const xpath_string& o) const + { + return !strequal(_buffer, o._buffer); + } + + bool uses_heap() const + { + return _uses_heap; + } + }; + + xpath_string xpath_string_const(const char_t* str) + { + return xpath_string(str, false); + } +} + +namespace +{ + bool starts_with(const char_t* string, const char_t* pattern) + { + while (*pattern && *string == *pattern) + { + string++; + pattern++; + } + + return *pattern == 0; + } + + const char_t* find_char(const char_t* s, char_t c) + { + #ifdef PUGIXML_WCHAR_MODE + return wcschr(s, c); + #else + return strchr(s, c); + #endif + } + + const char_t* find_substring(const char_t* s, const char_t* p) + { + #ifdef PUGIXML_WCHAR_MODE + // MSVC6 wcsstr bug workaround (if s is empty it always returns 0) + return (*p == 0) ? s : wcsstr(s, p); + #else + return strstr(s, p); + #endif + } + + // Converts symbol to lower case, if it is an ASCII one + char_t tolower_ascii(char_t ch) + { + return static_cast<unsigned int>(ch - 'A') < 26 ? static_cast<char_t>(ch | ' ') : ch; + } + + xpath_string string_value(const xpath_node& na, xpath_allocator* alloc) + { + if (na.attribute()) + return xpath_string_const(na.attribute().value()); + else + { + const xml_node& n = na.node(); + + switch (n.type()) + { + case node_pcdata: + case node_cdata: + case node_comment: + case node_pi: + return xpath_string_const(n.value()); + + case node_document: + case node_element: + { + xpath_string result; + + xml_node cur = n.first_child(); + + while (cur && cur != n) + { + if (cur.type() == node_pcdata || cur.type() == node_cdata) + result.append(xpath_string_const(cur.value()), alloc); + + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (!cur.next_sibling() && cur != n) + cur = cur.parent(); + + if (cur != n) cur = cur.next_sibling(); + } + } + + return result; + } + + default: + return xpath_string(); + } + } + } + + unsigned int node_height(xml_node n) + { + unsigned int result = 0; + + while (n) + { + ++result; + n = n.parent(); + } + + return result; + } + + bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh) + { + // normalize heights + for (unsigned int i = rh; i < lh; i++) ln = ln.parent(); + for (unsigned int j = lh; j < rh; j++) rn = rn.parent(); + + // one node is the ancestor of the other + if (ln == rn) return lh < rh; + + // find common ancestor + while (ln.parent() != rn.parent()) + { + ln = ln.parent(); + rn = rn.parent(); + } + + // there is no common ancestor (the shared parent is null), nodes are from different documents + if (!ln.parent()) return ln < rn; + + // determine sibling order + for (; ln; ln = ln.next_sibling()) + if (ln == rn) + return true; + + return false; + } + + bool node_is_ancestor(xml_node parent, xml_node node) + { + while (node && node != parent) node = node.parent(); + + return parent && node == parent; + } + + const void* document_order(const xpath_node& xnode) + { + xml_node_struct* node = xnode.node().internal_object(); + + if (node) + { + if (node->name && (node->header & xml_memory_page_name_allocated_mask) == 0) return node->name; + if (node->value && (node->header & xml_memory_page_value_allocated_mask) == 0) return node->value; + return 0; + } + + xml_attribute_struct* attr = xnode.attribute().internal_object(); + + if (attr) + { + if ((attr->header & xml_memory_page_name_allocated_mask) == 0) return attr->name; + if ((attr->header & xml_memory_page_value_allocated_mask) == 0) return attr->value; + return 0; + } + + return 0; + } + + struct document_order_comparator + { + bool operator()(const xpath_node& lhs, const xpath_node& rhs) const + { + // optimized document order based check + const void* lo = document_order(lhs); + const void* ro = document_order(rhs); + + if (lo && ro) return lo < ro; + + // slow comparison + xml_node ln = lhs.node(), rn = rhs.node(); + + // compare attributes + if (lhs.attribute() && rhs.attribute()) + { + // shared parent + if (lhs.parent() == rhs.parent()) + { + // determine sibling order + for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) + if (a == rhs.attribute()) + return true; + + return false; + } + + // compare attribute parents + ln = lhs.parent(); + rn = rhs.parent(); + } + else if (lhs.attribute()) + { + // attributes go after the parent element + if (lhs.parent() == rhs.node()) return false; + + ln = lhs.parent(); + } + else if (rhs.attribute()) + { + // attributes go after the parent element + if (rhs.parent() == lhs.node()) return true; + + rn = rhs.parent(); + } + + if (ln == rn) return false; + + unsigned int lh = node_height(ln); + unsigned int rh = node_height(rn); + + return node_is_before(ln, lh, rn, rh); + } + }; + + struct duplicate_comparator + { + bool operator()(const xpath_node& lhs, const xpath_node& rhs) const + { + if (lhs.attribute()) return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true; + else return rhs.attribute() ? false : lhs.node() < rhs.node(); + } + }; + + double gen_nan() + { + #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) + union { float f; int32_t i; } u[sizeof(float) == sizeof(int32_t) ? 1 : -1]; + u[0].i = 0x7fc00000; + return u[0].f; + #else + // fallback + const volatile double zero = 0.0; + return zero / zero; + #endif + } + + bool is_nan(double value) + { + #if defined(_MSC_VER) || defined(__BORLANDC__) + return !!_isnan(value); + #elif defined(fpclassify) && defined(FP_NAN) + return fpclassify(value) == FP_NAN; + #else + // fallback + const volatile double v = value; + return v != v; + #endif + } + + const char_t* convert_number_to_string_special(double value) + { + #if defined(_MSC_VER) || defined(__BORLANDC__) + if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; + if (_isnan(value)) return PUGIXML_TEXT("NaN"); + return PUGIXML_TEXT("-Infinity") + (value > 0); + #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) + switch (fpclassify(value)) + { + case FP_NAN: + return PUGIXML_TEXT("NaN"); + + case FP_INFINITE: + return PUGIXML_TEXT("-Infinity") + (value > 0); + + case FP_ZERO: + return PUGIXML_TEXT("0"); + + default: + return 0; + } + #else + // fallback + const volatile double v = value; + + if (v == 0) return PUGIXML_TEXT("0"); + if (v != v) return PUGIXML_TEXT("NaN"); + if (v * 2 == v) return PUGIXML_TEXT("-Infinity") + (value > 0); + return 0; + #endif + } + + bool convert_number_to_boolean(double value) + { + return (value != 0 && !is_nan(value)); + } + + void truncate_zeros(char* begin, char* end) + { + while (begin != end && end[-1] == '0') end--; + + *end = 0; + } + + // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent +#if defined(_MSC_VER) && _MSC_VER >= 1400 + void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) + { + // get base values + int sign, exponent; + _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign); + + // truncate redundant zeros + truncate_zeros(buffer, buffer + strlen(buffer)); + + // fill results + *out_mantissa = buffer; + *out_exponent = exponent; + } +#else + void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) + { + // get a scientific notation value with IEEE DBL_DIG decimals + sprintf(buffer, "%.*e", DBL_DIG, value); + assert(strlen(buffer) < buffer_size); + (void)!buffer_size; + + // get the exponent (possibly negative) + char* exponent_string = strchr(buffer, 'e'); + assert(exponent_string); + + int exponent = atoi(exponent_string + 1); + + // extract mantissa string: skip sign + char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer; + assert(mantissa[0] != '0' && mantissa[1] == '.'); + + // divide mantissa by 10 to eliminate integer part + mantissa[1] = mantissa[0]; + mantissa++; + exponent++; + + // remove extra mantissa digits and zero-terminate mantissa + truncate_zeros(mantissa, exponent_string); + + // fill results + *out_mantissa = mantissa; + *out_exponent = exponent; + } +#endif + + xpath_string convert_number_to_string(double value, xpath_allocator* alloc) + { + // try special number conversion + const char_t* special = convert_number_to_string_special(value); + if (special) return xpath_string_const(special); + + // get mantissa + exponent form + char mantissa_buffer[64]; + + char* mantissa; + int exponent; + convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent); + + // make the number! + char_t result[512]; + char_t* s = result; + + // sign + if (value < 0) *s++ = '-'; + + // integer part + if (exponent <= 0) + { + *s++ = '0'; + } + else + { + while (exponent > 0) + { + assert(*mantissa == 0 || (unsigned)(*mantissa - '0') <= 9); + *s++ = *mantissa ? *mantissa++ : '0'; + exponent--; + } + } + + // fractional part + if (*mantissa) + { + // decimal point + *s++ = '.'; + + // extra zeroes from negative exponent + while (exponent < 0) + { + *s++ = '0'; + exponent++; + } + + // extra mantissa digits + while (*mantissa) + { + assert((unsigned)(*mantissa - '0') <= 9); + *s++ = *mantissa++; + } + } + + // zero-terminate + assert(s < result + sizeof(result) / sizeof(result[0])); + *s = 0; + + return xpath_string(result, alloc); + } + + bool check_string_to_number_format(const char_t* string) + { + // parse leading whitespace + while (IS_CHARTYPE(*string, ct_space)) ++string; + + // parse sign + if (*string == '-') ++string; + + if (!*string) return false; + + // if there is no integer part, there should be a decimal part with at least one digit + if (!IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !IS_CHARTYPEX(string[1], ctx_digit))) return false; + + // parse integer part + while (IS_CHARTYPEX(*string, ctx_digit)) ++string; + + // parse decimal part + if (*string == '.') + { + ++string; + + while (IS_CHARTYPEX(*string, ctx_digit)) ++string; + } + + // parse trailing whitespace + while (IS_CHARTYPE(*string, ct_space)) ++string; + + return *string == 0; + } + + double convert_string_to_number(const char_t* string) + { + // check string format + if (!check_string_to_number_format(string)) return gen_nan(); + + // parse string + #ifdef PUGIXML_WCHAR_MODE + return wcstod(string, 0); + #else + return atof(string); + #endif + } + + bool convert_string_to_number(const char_t* begin, const char_t* end, double* out_result) + { + char_t buffer[32]; + + size_t length = static_cast<size_t>(end - begin); + char_t* scratch = buffer; + + if (length >= sizeof(buffer) / sizeof(buffer[0])) + { + // need to make dummy on-heap copy + scratch = static_cast<char_t*>(global_allocate((length + 1) * sizeof(char_t))); + if (!scratch) return false; + } + + // copy string to zero-terminated buffer and perform conversion + memcpy(scratch, begin, length * sizeof(char_t)); + scratch[length] = 0; + + *out_result = convert_string_to_number(scratch); + + // free dummy buffer + if (scratch != buffer) global_deallocate(scratch); + + return true; + } + + double round_nearest(double value) + { + return floor(value + 0.5); + } + + double round_nearest_nzero(double value) + { + // same as round_nearest, but returns -0 for [-0.5, -0] + // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) + return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); + } + + const char_t* qualified_name(const xpath_node& node) + { + return node.attribute() ? node.attribute().name() : node.node().name(); + } + + const char_t* local_name(const xpath_node& node) + { + const char_t* name = qualified_name(node); + const char_t* p = find_char(name, ':'); + + return p ? p + 1 : name; + } + + struct namespace_uri_predicate + { + const char_t* prefix; + size_t prefix_length; + + namespace_uri_predicate(const char_t* name) + { + const char_t* pos = find_char(name, ':'); + + prefix = pos ? name : 0; + prefix_length = pos ? static_cast<size_t>(pos - name) : 0; + } + + bool operator()(const xml_attribute& a) const + { + const char_t* name = a.name(); + + if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false; + + return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0; + } + }; + + const char_t* namespace_uri(const xml_node& node) + { + namespace_uri_predicate pred = node.name(); + + xml_node p = node; + + while (p) + { + xml_attribute a = p.find_attribute(pred); + + if (a) return a.value(); + + p = p.parent(); + } + + return PUGIXML_TEXT(""); + } + + const char_t* namespace_uri(const xml_attribute& attr, const xml_node& parent) + { + namespace_uri_predicate pred = attr.name(); + + // Default namespace does not apply to attributes + if (!pred.prefix) return PUGIXML_TEXT(""); + + xml_node p = parent; + + while (p) + { + xml_attribute a = p.find_attribute(pred); + + if (a) return a.value(); + + p = p.parent(); + } + + return PUGIXML_TEXT(""); + } + + const char_t* namespace_uri(const xpath_node& node) + { + return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node()); + } + + void normalize_space(char_t* buffer) + { + char_t* write = buffer; + + for (char_t* it = buffer; *it; ) + { + char_t ch = *it++; + + if (IS_CHARTYPE(ch, ct_space)) + { + // replace whitespace sequence with single space + while (IS_CHARTYPE(*it, ct_space)) it++; + + // avoid leading spaces + if (write != buffer) *write++ = ' '; + } + else *write++ = ch; + } + + // remove trailing space + if (write != buffer && IS_CHARTYPE(write[-1], ct_space)) write--; + + // zero-terminate + *write = 0; + } + + void translate(char_t* buffer, const char_t* from, const char_t* to) + { + size_t to_length = strlength(to); + + char_t* write = buffer; + + while (*buffer) + { + DMC_VOLATILE char_t ch = *buffer++; + + const char_t* pos = find_char(from, ch); + + if (!pos) + *write++ = ch; // do not process + else if (static_cast<size_t>(pos - from) < to_length) + *write++ = to[pos - from]; // replace + } + + // zero-terminate + *write = 0; + } + + struct xpath_variable_boolean: xpath_variable + { + xpath_variable_boolean(): value(false) + { + } + + bool value; + char_t name[1]; + }; + + struct xpath_variable_number: xpath_variable + { + xpath_variable_number(): value(0) + { + } + + double value; + char_t name[1]; + }; + + struct xpath_variable_string: xpath_variable + { + xpath_variable_string(): value(0) + { + } + + ~xpath_variable_string() + { + if (value) global_deallocate(value); + } + + char_t* value; + char_t name[1]; + }; + + struct xpath_variable_node_set: xpath_variable + { + xpath_node_set value; + char_t name[1]; + }; + + const xpath_node_set dummy_node_set; + + unsigned int hash_string(const char_t* str) + { + // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time) + unsigned int result = 0; + + while (*str) + { + result += static_cast<unsigned int>(*str++); + result += result << 10; + result ^= result >> 6; + } + + result += result << 3; + result ^= result >> 11; + result += result << 15; + + return result; + } + + template <typename T> T* new_xpath_variable(const char_t* name) + { + size_t length = strlength(name); + if (length == 0) return 0; // empty variable names are invalid + + // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters + void* memory = global_allocate(sizeof(T) + length * sizeof(char_t)); + if (!memory) return 0; + + T* result = new (memory) T(); + + memcpy(result->name, name, (length + 1) * sizeof(char_t)); + + return result; + } + + xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name) + { + switch (type) + { + case xpath_type_node_set: + return new_xpath_variable<xpath_variable_node_set>(name); + + case xpath_type_number: + return new_xpath_variable<xpath_variable_number>(name); + + case xpath_type_string: + return new_xpath_variable<xpath_variable_string>(name); + + case xpath_type_boolean: + return new_xpath_variable<xpath_variable_boolean>(name); + + default: + return 0; + } + } + + template <typename T> void delete_xpath_variable(T* var) + { + var->~T(); + global_deallocate(var); + } + + void delete_xpath_variable(xpath_value_type type, xpath_variable* var) + { + switch (type) + { + case xpath_type_node_set: + delete_xpath_variable(static_cast<xpath_variable_node_set*>(var)); + break; + + case xpath_type_number: + delete_xpath_variable(static_cast<xpath_variable_number*>(var)); + break; + + case xpath_type_string: + delete_xpath_variable(static_cast<xpath_variable_string*>(var)); + break; + + case xpath_type_boolean: + delete_xpath_variable(static_cast<xpath_variable_boolean*>(var)); + break; + + default: + assert(!"Invalid variable type"); + } + } + + xpath_variable* get_variable(xpath_variable_set* set, const char_t* begin, const char_t* end) + { + char_t buffer[32]; + + size_t length = static_cast<size_t>(end - begin); + char_t* scratch = buffer; + + if (length >= sizeof(buffer) / sizeof(buffer[0])) + { + // need to make dummy on-heap copy + scratch = static_cast<char_t*>(global_allocate((length + 1) * sizeof(char_t))); + if (!scratch) return 0; + } + + // copy string to zero-terminated buffer and perform lookup + memcpy(scratch, begin, length * sizeof(char_t)); + scratch[length] = 0; + + xpath_variable* result = set->get(scratch); + + // free dummy buffer + if (scratch != buffer) global_deallocate(scratch); + + return result; + } +} + +// Internal node set class +namespace +{ + xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev) + { + xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; + + if (type == xpath_node_set::type_unsorted) + { + sort(begin, end, document_order_comparator()); + + type = xpath_node_set::type_sorted; + } + + if (type != order) reverse(begin, end); + + return order; + } + + xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) + { + if (begin == end) return xpath_node(); + + switch (type) + { + case xpath_node_set::type_sorted: + return *begin; + + case xpath_node_set::type_sorted_reverse: + return *(end - 1); + + case xpath_node_set::type_unsorted: + return *min_element(begin, end, document_order_comparator()); + + default: + assert(!"Invalid node set type"); + return xpath_node(); + } + } + class xpath_node_set_raw + { + xpath_node_set::type_t _type; + + xpath_node* _begin; + xpath_node* _end; + xpath_node* _eos; + + public: + xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0) + { + } + + xpath_node* begin() const + { + return _begin; + } + + xpath_node* end() const + { + return _end; + } + + bool empty() const + { + return _begin == _end; + } + + size_t size() const + { + return static_cast<size_t>(_end - _begin); + } + + xpath_node first() const + { + return xpath_first(_begin, _end, _type); + } + + void push_back(const xpath_node& node, xpath_allocator* alloc) + { + if (_end == _eos) + { + size_t capacity = static_cast<size_t>(_eos - _begin); + + // get new capacity (1.5x rule) + size_t new_capacity = capacity + capacity / 2 + 1; + + // reallocate the old array or allocate a new one + xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node))); + assert(data); + + // finalize + _begin = data; + _end = data + capacity; + _eos = data + new_capacity; + } + + *_end++ = node; + } + + void append(const xpath_node* begin, const xpath_node* end, xpath_allocator* alloc) + { + size_t size = static_cast<size_t>(_end - _begin); + size_t capacity = static_cast<size_t>(_eos - _begin); + size_t count = static_cast<size_t>(end - begin); + + if (size + count > capacity) + { + // reallocate the old array or allocate a new one + xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size + count) * sizeof(xpath_node))); + assert(data); + + // finalize + _begin = data; + _end = data + size; + _eos = data + size + count; + } + + memcpy(_end, begin, count * sizeof(xpath_node)); + _end += count; + } + + void sort_do() + { + _type = xpath_sort(_begin, _end, _type, false); + } + + void truncate(xpath_node* pos) + { + assert(_begin <= pos && pos <= _end); + + _end = pos; + } + + void remove_duplicates() + { + if (_type == xpath_node_set::type_unsorted) + sort(_begin, _end, duplicate_comparator()); + + _end = unique(_begin, _end); + } + + xpath_node_set::type_t type() const + { + return _type; + } + + void set_type(xpath_node_set::type_t type) + { + _type = type; + } + }; +} + +namespace +{ + struct xpath_context + { + xpath_node n; + size_t position, size; + + xpath_context(const xpath_node& n, size_t position, size_t size): n(n), position(position), size(size) + { + } + }; + + enum lexeme_t + { + lex_none = 0, + lex_equal, + lex_not_equal, + lex_less, + lex_greater, + lex_less_or_equal, + lex_greater_or_equal, + lex_plus, + lex_minus, + lex_multiply, + lex_union, + lex_var_ref, + lex_open_brace, + lex_close_brace, + lex_quoted_string, + lex_number, + lex_slash, + lex_double_slash, + lex_open_square_brace, + lex_close_square_brace, + lex_string, + lex_comma, + lex_axis_attribute, + lex_dot, + lex_double_dot, + lex_double_colon, + lex_eof + }; + + struct xpath_lexer_string + { + const char_t* begin; + const char_t* end; + + xpath_lexer_string(): begin(0), end(0) + { + } + + bool operator==(const char_t* other) const + { + size_t length = static_cast<size_t>(end - begin); + + return strequalrange(other, begin, length); + } + }; + + class xpath_lexer + { + const char_t* _cur; + const char_t* _cur_lexeme_pos; + xpath_lexer_string _cur_lexeme_contents; + + lexeme_t _cur_lexeme; + + public: + explicit xpath_lexer(const char_t* query): _cur(query) + { + next(); + } + + const char_t* state() const + { + return _cur; + } + + void next() + { + const char_t* cur = _cur; + + while (IS_CHARTYPE(*cur, ct_space)) ++cur; + + // save lexeme position for error reporting + _cur_lexeme_pos = cur; + + switch (*cur) + { + case 0: + _cur_lexeme = lex_eof; + break; + + case '>': + if (*(cur+1) == '=') + { + cur += 2; + _cur_lexeme = lex_greater_or_equal; + } + else + { + cur += 1; + _cur_lexeme = lex_greater; + } + break; + + case '<': + if (*(cur+1) == '=') + { + cur += 2; + _cur_lexeme = lex_less_or_equal; + } + else + { + cur += 1; + _cur_lexeme = lex_less; + } + break; + + case '!': + if (*(cur+1) == '=') + { + cur += 2; + _cur_lexeme = lex_not_equal; + } + else + { + _cur_lexeme = lex_none; + } + break; + + case '=': + cur += 1; + _cur_lexeme = lex_equal; + + break; + + case '+': + cur += 1; + _cur_lexeme = lex_plus; + + break; + + case '-': + cur += 1; + _cur_lexeme = lex_minus; + + break; + + case '*': + cur += 1; + _cur_lexeme = lex_multiply; + + break; + + case '|': + cur += 1; + _cur_lexeme = lex_union; + + break; + + case '$': + cur += 1; + + if (IS_CHARTYPEX(*cur, ctx_start_symbol)) + { + _cur_lexeme_contents.begin = cur; + + while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + + if (cur[0] == ':' && IS_CHARTYPEX(cur[1], ctx_symbol)) // qname + { + cur++; // : + + while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + } + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_var_ref; + } + else + { + _cur_lexeme = lex_none; + } + + break; + + case '(': + cur += 1; + _cur_lexeme = lex_open_brace; + + break; + + case ')': + cur += 1; + _cur_lexeme = lex_close_brace; + + break; + + case '[': + cur += 1; + _cur_lexeme = lex_open_square_brace; + + break; + + case ']': + cur += 1; + _cur_lexeme = lex_close_square_brace; + + break; + + case ',': + cur += 1; + _cur_lexeme = lex_comma; + + break; + + case '/': + if (*(cur+1) == '/') + { + cur += 2; + _cur_lexeme = lex_double_slash; + } + else + { + cur += 1; + _cur_lexeme = lex_slash; + } + break; + + case '.': + if (*(cur+1) == '.') + { + cur += 2; + _cur_lexeme = lex_double_dot; + } + else if (IS_CHARTYPEX(*(cur+1), ctx_digit)) + { + _cur_lexeme_contents.begin = cur; // . + + ++cur; + + while (IS_CHARTYPEX(*cur, ctx_digit)) cur++; + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_number; + } + else + { + cur += 1; + _cur_lexeme = lex_dot; + } + break; + + case '@': + cur += 1; + _cur_lexeme = lex_axis_attribute; + + break; + + case '"': + case '\'': + { + char_t terminator = *cur; + + ++cur; + + _cur_lexeme_contents.begin = cur; + while (*cur && *cur != terminator) cur++; + _cur_lexeme_contents.end = cur; + + if (!*cur) + _cur_lexeme = lex_none; + else + { + cur += 1; + _cur_lexeme = lex_quoted_string; + } + + break; + } + + case ':': + if (*(cur+1) == ':') + { + cur += 2; + _cur_lexeme = lex_double_colon; + } + else + { + _cur_lexeme = lex_none; + } + break; + + default: + if (IS_CHARTYPEX(*cur, ctx_digit)) + { + _cur_lexeme_contents.begin = cur; + + while (IS_CHARTYPEX(*cur, ctx_digit)) cur++; + + if (*cur == '.') + { + cur++; + + while (IS_CHARTYPEX(*cur, ctx_digit)) cur++; + } + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_number; + } + else if (IS_CHARTYPEX(*cur, ctx_start_symbol)) + { + _cur_lexeme_contents.begin = cur; + + while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + + if (cur[0] == ':') + { + if (cur[1] == '*') // namespace test ncname:* + { + cur += 2; // :* + } + else if (IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname + { + cur++; // : + + while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + } + } + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_string; + } + else + { + _cur_lexeme = lex_none; + } + } + + _cur = cur; + } + + lexeme_t current() const + { + return _cur_lexeme; + } + + const char_t* current_pos() const + { + return _cur_lexeme_pos; + } + + const xpath_lexer_string& contents() const + { + assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string); + + return _cur_lexeme_contents; + } + }; + + enum ast_type_t + { + ast_op_or, // left or right + ast_op_and, // left and right + ast_op_equal, // left = right + ast_op_not_equal, // left != right + ast_op_less, // left < right + ast_op_greater, // left > right + ast_op_less_or_equal, // left <= right + ast_op_greater_or_equal, // left >= right + ast_op_add, // left + right + ast_op_subtract, // left - right + ast_op_multiply, // left * right + ast_op_divide, // left / right + ast_op_mod, // left % right + ast_op_negate, // left - right + ast_op_union, // left | right + ast_predicate, // apply predicate to set; next points to next predicate + ast_filter, // select * from left where right + ast_filter_posinv, // select * from left where right; proximity position invariant + ast_string_constant, // string constant + ast_number_constant, // number constant + ast_variable, // variable + ast_func_last, // last() + ast_func_position, // position() + ast_func_count, // count(left) + ast_func_id, // id(left) + ast_func_local_name_0, // local-name() + ast_func_local_name_1, // local-name(left) + ast_func_namespace_uri_0, // namespace-uri() + ast_func_namespace_uri_1, // namespace-uri(left) + ast_func_name_0, // name() + ast_func_name_1, // name(left) + ast_func_string_0, // string() + ast_func_string_1, // string(left) + ast_func_concat, // concat(left, right, siblings) + ast_func_starts_with, // starts_with(left, right) + ast_func_contains, // contains(left, right) + ast_func_substring_before, // substring-before(left, right) + ast_func_substring_after, // substring-after(left, right) + ast_func_substring_2, // substring(left, right) + ast_func_substring_3, // substring(left, right, third) + ast_func_string_length_0, // string-length() + ast_func_string_length_1, // string-length(left) + ast_func_normalize_space_0, // normalize-space() + ast_func_normalize_space_1, // normalize-space(left) + ast_func_translate, // translate(left, right, third) + ast_func_boolean, // boolean(left) + ast_func_not, // not(left) + ast_func_true, // true() + ast_func_false, // false() + ast_func_lang, // lang(left) + ast_func_number_0, // number() + ast_func_number_1, // number(left) + ast_func_sum, // sum(left) + ast_func_floor, // floor(left) + ast_func_ceiling, // ceiling(left) + ast_func_round, // round(left) + ast_step, // process set left with step + ast_step_root // select root node + }; + + enum axis_t + { + axis_ancestor, + axis_ancestor_or_self, + axis_attribute, + axis_child, + axis_descendant, + axis_descendant_or_self, + axis_following, + axis_following_sibling, + axis_namespace, + axis_parent, + axis_preceding, + axis_preceding_sibling, + axis_self + }; + + enum nodetest_t + { + nodetest_none, + nodetest_name, + nodetest_type_node, + nodetest_type_comment, + nodetest_type_pi, + nodetest_type_text, + nodetest_pi, + nodetest_all, + nodetest_all_in_namespace + }; + + template <axis_t N> struct axis_to_type + { + static const axis_t axis; + }; + + template <axis_t N> const axis_t axis_to_type<N>::axis = N; + + class xpath_ast_node + { + private: + // node type + char _type; + char _rettype; + + // for ast_step / ast_predicate + char _axis; + char _test; + + // tree node structure + xpath_ast_node* _left; + xpath_ast_node* _right; + xpath_ast_node* _next; + + union + { + // value for ast_string_constant + const char_t* string; + // value for ast_number_constant + double number; + // variable for ast_variable + xpath_variable* variable; + // node test for ast_step (node name/namespace/node type/pi target) + const char_t* nodetest; + } _data; + + xpath_ast_node(const xpath_ast_node&); + xpath_ast_node& operator=(const xpath_ast_node&); + + template <class Comp> static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) + { + xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); + + if (lt != xpath_type_node_set && rt != xpath_type_node_set) + { + if (lt == xpath_type_boolean || rt == xpath_type_boolean) + return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); + else if (lt == xpath_type_number || rt == xpath_type_number) + return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); + else if (lt == xpath_type_string || rt == xpath_type_string) + { + xpath_allocator_capture cr(stack.result); + + xpath_string ls = lhs->eval_string(c, stack); + xpath_string rs = rhs->eval_string(c, stack); + + return comp(ls, rs); + } + } + else if (lt == xpath_type_node_set && rt == xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ls = lhs->eval_node_set(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(string_value(*li, stack.result), string_value(*ri, stack.result))) + return true; + } + + return false; + } + else + { + if (lt == xpath_type_node_set) + { + swap(lhs, rhs); + swap(lt, rt); + } + + if (lt == xpath_type_boolean) + return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); + else if (lt == xpath_type_number) + { + xpath_allocator_capture cr(stack.result); + + double l = lhs->eval_number(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) + return true; + } + + return false; + } + else if (lt == xpath_type_string) + { + xpath_allocator_capture cr(stack.result); + + xpath_string l = lhs->eval_string(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(l, string_value(*ri, stack.result))) + return true; + } + + return false; + } + } + + assert(!"Wrong types"); + return false; + } + + template <class Comp> static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) + { + xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); + + if (lt != xpath_type_node_set && rt != xpath_type_node_set) + return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); + else if (lt == xpath_type_node_set && rt == xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ls = lhs->eval_node_set(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) + { + xpath_allocator_capture cri(stack.result); + + double l = convert_string_to_number(string_value(*li, stack.result).c_str()); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture crii(stack.result); + + if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) + return true; + } + } + + return false; + } + else if (lt != xpath_type_node_set && rt == xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + double l = lhs->eval_number(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) + return true; + } + + return false; + } + else if (lt == xpath_type_node_set && rt != xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ls = lhs->eval_node_set(c, stack); + double r = rhs->eval_number(c, stack); + + for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) + { + xpath_allocator_capture cri(stack.result); + + if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r)) + return true; + } + + return false; + } + else + { + assert(!"Wrong types"); + return false; + } + } + + void apply_predicate(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack) + { + assert(ns.size() >= first); + + size_t i = 1; + size_t size = ns.size() - first; + + xpath_node* last = ns.begin() + first; + + // remove_if... or well, sort of + for (xpath_node* it = last; it != ns.end(); ++it, ++i) + { + xpath_context c(*it, i, size); + + if (expr->rettype() == xpath_type_number) + { + if (expr->eval_number(c, stack) == i) + *last++ = *it; + } + else if (expr->eval_boolean(c, stack)) + *last++ = *it; + } + + ns.truncate(last); + } + + void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack) + { + if (ns.size() == first) return; + + for (xpath_ast_node* pred = _right; pred; pred = pred->_next) + { + apply_predicate(ns, first, pred->_left, stack); + } + } + + void step_push(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& parent, xpath_allocator* alloc) + { + if (!a) return; + + const char_t* name = a.name(); + + // There are no attribute nodes corresponding to attributes that declare namespaces + // That is, "xmlns:..." or "xmlns" + if (starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')) return; + + switch (_test) + { + case nodetest_name: + if (strequal(name, _data.nodetest)) ns.push_back(xpath_node(a, parent), alloc); + break; + + case nodetest_type_node: + case nodetest_all: + ns.push_back(xpath_node(a, parent), alloc); + break; + + case nodetest_all_in_namespace: + if (starts_with(name, _data.nodetest)) + ns.push_back(xpath_node(a, parent), alloc); + break; + + default: + ; + } + } + + void step_push(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc) + { + if (!n) return; + + switch (_test) + { + case nodetest_name: + if (n.type() == node_element && strequal(n.name(), _data.nodetest)) ns.push_back(n, alloc); + break; + + case nodetest_type_node: + ns.push_back(n, alloc); + break; + + case nodetest_type_comment: + if (n.type() == node_comment) + ns.push_back(n, alloc); + break; + + case nodetest_type_text: + if (n.type() == node_pcdata || n.type() == node_cdata) + ns.push_back(n, alloc); + break; + + case nodetest_type_pi: + if (n.type() == node_pi) + ns.push_back(n, alloc); + break; + + case nodetest_pi: + if (n.type() == node_pi && strequal(n.name(), _data.nodetest)) + ns.push_back(n, alloc); + break; + + case nodetest_all: + if (n.type() == node_element) + ns.push_back(n, alloc); + break; + + case nodetest_all_in_namespace: + if (n.type() == node_element && starts_with(n.name(), _data.nodetest)) + ns.push_back(n, alloc); + break; + + default: + assert(!"Unknown axis"); + } + } + + template <class T> void step_fill(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc, T) + { + const axis_t axis = T::axis; + + switch (axis) + { + case axis_attribute: + { + for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute()) + step_push(ns, a, n, alloc); + + break; + } + + case axis_child: + { + for (xml_node c = n.first_child(); c; c = c.next_sibling()) + step_push(ns, c, alloc); + + break; + } + + case axis_descendant: + case axis_descendant_or_self: + { + if (axis == axis_descendant_or_self) + step_push(ns, n, alloc); + + xml_node cur = n.first_child(); + + while (cur && cur != n) + { + step_push(ns, cur, alloc); + + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (!cur.next_sibling() && cur != n) + cur = cur.parent(); + + if (cur != n) cur = cur.next_sibling(); + } + } + + break; + } + + case axis_following_sibling: + { + for (xml_node c = n.next_sibling(); c; c = c.next_sibling()) + step_push(ns, c, alloc); + + break; + } + + case axis_preceding_sibling: + { + for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling()) + step_push(ns, c, alloc); + + break; + } + + case axis_following: + { + xml_node cur = n; + + // exit from this node so that we don't include descendants + while (cur && !cur.next_sibling()) cur = cur.parent(); + cur = cur.next_sibling(); + + for (;;) + { + step_push(ns, cur, alloc); + + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (cur && !cur.next_sibling()) cur = cur.parent(); + cur = cur.next_sibling(); + + if (!cur) break; + } + } + + break; + } + + case axis_preceding: + { + xml_node cur = n; + + while (cur && !cur.previous_sibling()) cur = cur.parent(); + cur = cur.previous_sibling(); + + for (;;) + { + if (cur.last_child()) + cur = cur.last_child(); + else + { + // leaf node, can't be ancestor + step_push(ns, cur, alloc); + + if (cur.previous_sibling()) + cur = cur.previous_sibling(); + else + { + do + { + cur = cur.parent(); + if (!cur) break; + + if (!node_is_ancestor(cur, n)) step_push(ns, cur, alloc); + } + while (!cur.previous_sibling()); + + cur = cur.previous_sibling(); + + if (!cur) break; + } + } + } + + break; + } + + case axis_ancestor: + case axis_ancestor_or_self: + { + if (axis == axis_ancestor_or_self) + step_push(ns, n, alloc); + + xml_node cur = n.parent(); + + while (cur) + { + step_push(ns, cur, alloc); + + cur = cur.parent(); + } + + break; + } + + case axis_self: + { + step_push(ns, n, alloc); + + break; + } + + case axis_parent: + { + if (n.parent()) step_push(ns, n.parent(), alloc); + + break; + } + + default: + assert(!"Unimplemented axis"); + } + } + + template <class T> void step_fill(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& p, xpath_allocator* alloc, T v) + { + const axis_t axis = T::axis; + + switch (axis) + { + case axis_ancestor: + case axis_ancestor_or_self: + { + if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test + step_push(ns, a, p, alloc); + + xml_node cur = p; + + while (cur) + { + step_push(ns, cur, alloc); + + cur = cur.parent(); + } + + break; + } + + case axis_descendant_or_self: + case axis_self: + { + if (_test == nodetest_type_node) // reject attributes based on principal node type test + step_push(ns, a, p, alloc); + + break; + } + + case axis_following: + { + xml_node cur = p; + + for (;;) + { + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (cur && !cur.next_sibling()) cur = cur.parent(); + cur = cur.next_sibling(); + + if (!cur) break; + } + + step_push(ns, cur, alloc); + } + + break; + } + + case axis_parent: + { + step_push(ns, p, alloc); + + break; + } + + case axis_preceding: + { + // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding + step_fill(ns, p, alloc, v); + break; + } + + default: + assert(!"Unimplemented axis"); + } + } + + template <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, T v) + { + const axis_t axis = T::axis; + bool attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self); + + xpath_node_set_raw ns; + ns.set_type((axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling) ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted); + + if (_left) + { + xpath_node_set_raw s = _left->eval_node_set(c, stack); + + // self axis preserves the original order + if (axis == axis_self) ns.set_type(s.type()); + + for (const xpath_node* it = s.begin(); it != s.end(); ++it) + { + size_t size = ns.size(); + + // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes + if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); + + if (it->node()) + step_fill(ns, it->node(), stack.result, v); + else if (attributes) + step_fill(ns, it->attribute(), it->parent(), stack.result, v); + + apply_predicates(ns, size, stack); + } + } + else + { + if (c.n.node()) + step_fill(ns, c.n.node(), stack.result, v); + else if (attributes) + step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v); + + apply_predicates(ns, 0, stack); + } + + // child, attribute and self axes always generate unique set of nodes + // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice + if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted) + ns.remove_duplicates(); + + return ns; + } + + public: + xpath_ast_node(ast_type_t type, xpath_value_type rettype, const char_t* value): + _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0) + { + assert(type == ast_string_constant); + _data.string = value; + } + + xpath_ast_node(ast_type_t type, xpath_value_type rettype, double value): + _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0) + { + assert(type == ast_number_constant); + _data.number = value; + } + + xpath_ast_node(ast_type_t type, xpath_value_type rettype, xpath_variable* value): + _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0) + { + assert(type == ast_variable); + _data.variable = value; + } + + xpath_ast_node(ast_type_t type, xpath_value_type rettype, xpath_ast_node* left = 0, xpath_ast_node* right = 0): + _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(left), _right(right), _next(0) + { + } + + xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents): + _type((char)type), _rettype(xpath_type_node_set), _axis((char)axis), _test((char)test), _left(left), _right(0), _next(0) + { + _data.nodetest = contents; + } + + void set_next(xpath_ast_node* value) + { + _next = value; + } + + void set_right(xpath_ast_node* value) + { + _right = value; + } + + bool eval_boolean(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_op_or: + return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); + + case ast_op_and: + return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); + + case ast_op_equal: + return compare_eq(_left, _right, c, stack, equal_to()); + + case ast_op_not_equal: + return compare_eq(_left, _right, c, stack, not_equal_to()); + + case ast_op_less: + return compare_rel(_left, _right, c, stack, less()); + + case ast_op_greater: + return compare_rel(_right, _left, c, stack, less()); + + case ast_op_less_or_equal: + return compare_rel(_left, _right, c, stack, less_equal()); + + case ast_op_greater_or_equal: + return compare_rel(_right, _left, c, stack, less_equal()); + + case ast_func_starts_with: + { + xpath_allocator_capture cr(stack.result); + + xpath_string lr = _left->eval_string(c, stack); + xpath_string rr = _right->eval_string(c, stack); + + return starts_with(lr.c_str(), rr.c_str()); + } + + case ast_func_contains: + { + xpath_allocator_capture cr(stack.result); + + xpath_string lr = _left->eval_string(c, stack); + xpath_string rr = _right->eval_string(c, stack); + + return find_substring(lr.c_str(), rr.c_str()) != 0; + } + + case ast_func_boolean: + return _left->eval_boolean(c, stack); + + case ast_func_not: + return !_left->eval_boolean(c, stack); + + case ast_func_true: + return true; + + case ast_func_false: + return false; + + case ast_func_lang: + { + if (c.n.attribute()) return false; + + xpath_allocator_capture cr(stack.result); + + xpath_string lang = _left->eval_string(c, stack); + + for (xml_node n = c.n.node(); n; n = n.parent()) + { + xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); + + if (a) + { + const char_t* value = a.value(); + + // strnicmp / strncasecmp is not portable + for (const char_t* lit = lang.c_str(); *lit; ++lit) + { + if (tolower_ascii(*lit) != tolower_ascii(*value)) return false; + ++value; + } + + return *value == 0 || *value == '-'; + } + } + + return false; + } + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_boolean) + return _data.variable->get_boolean(); + + // fallthrough to type conversion + } + + default: + { + switch (_rettype) + { + case xpath_type_number: + return convert_number_to_boolean(eval_number(c, stack)); + + case xpath_type_string: + { + xpath_allocator_capture cr(stack.result); + + return !eval_string(c, stack).empty(); + } + + case xpath_type_node_set: + { + xpath_allocator_capture cr(stack.result); + + return !eval_node_set(c, stack).empty(); + } + + default: + assert(!"Wrong expression for return type boolean"); + return false; + } + } + } + } + + double eval_number(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_op_add: + return _left->eval_number(c, stack) + _right->eval_number(c, stack); + + case ast_op_subtract: + return _left->eval_number(c, stack) - _right->eval_number(c, stack); + + case ast_op_multiply: + return _left->eval_number(c, stack) * _right->eval_number(c, stack); + + case ast_op_divide: + return _left->eval_number(c, stack) / _right->eval_number(c, stack); + + case ast_op_mod: + return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack)); + + case ast_op_negate: + return -_left->eval_number(c, stack); + + case ast_number_constant: + return _data.number; + + case ast_func_last: + return (double)c.size; + + case ast_func_position: + return (double)c.position; + + case ast_func_count: + { + xpath_allocator_capture cr(stack.result); + + return (double)_left->eval_node_set(c, stack).size(); + } + + case ast_func_string_length_0: + { + xpath_allocator_capture cr(stack.result); + + return (double)string_value(c.n, stack.result).length(); + } + + case ast_func_string_length_1: + { + xpath_allocator_capture cr(stack.result); + + return (double)_left->eval_string(c, stack).length(); + } + + case ast_func_number_0: + { + xpath_allocator_capture cr(stack.result); + + return convert_string_to_number(string_value(c.n, stack.result).c_str()); + } + + case ast_func_number_1: + return _left->eval_number(c, stack); + + case ast_func_sum: + { + xpath_allocator_capture cr(stack.result); + + double r = 0; + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + + for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) + { + xpath_allocator_capture cri(stack.result); + + r += convert_string_to_number(string_value(*it, stack.result).c_str()); + } + + return r; + } + + case ast_func_floor: + { + double r = _left->eval_number(c, stack); + + return r == r ? floor(r) : r; + } + + case ast_func_ceiling: + { + double r = _left->eval_number(c, stack); + + return r == r ? ceil(r) : r; + } + + case ast_func_round: + return round_nearest_nzero(_left->eval_number(c, stack)); + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_number) + return _data.variable->get_number(); + + // fallthrough to type conversion + } + + default: + { + switch (_rettype) + { + case xpath_type_boolean: + return eval_boolean(c, stack) ? 1 : 0; + + case xpath_type_string: + { + xpath_allocator_capture cr(stack.result); + + return convert_string_to_number(eval_string(c, stack).c_str()); + } + + case xpath_type_node_set: + { + xpath_allocator_capture cr(stack.result); + + return convert_string_to_number(eval_string(c, stack).c_str()); + } + + default: + assert(!"Wrong expression for return type number"); + return 0; + } + + } + } + } + + xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) + { + assert(_type == ast_func_concat); + + xpath_allocator_capture ct(stack.temp); + + // count the string number + size_t count = 1; + for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++; + + // gather all strings + xpath_string static_buffer[4]; + xpath_string* buffer = static_buffer; + + // allocate on-heap for large concats + if (count > sizeof(static_buffer) / sizeof(static_buffer[0])) + { + buffer = static_cast<xpath_string*>(stack.temp->allocate(count * sizeof(xpath_string))); + assert(buffer); + } + + // evaluate all strings to temporary stack + xpath_stack swapped_stack = {stack.temp, stack.result}; + + buffer[0] = _left->eval_string(c, swapped_stack); + + size_t pos = 1; + for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack); + assert(pos == count); + + // get total length + size_t length = 0; + for (size_t i = 0; i < count; ++i) length += buffer[i].length(); + + // create final string + char_t* result = static_cast<char_t*>(stack.result->allocate((length + 1) * sizeof(char_t))); + assert(result); + + char_t* ri = result; + + for (size_t j = 0; j < count; ++j) + for (const char_t* bi = buffer[j].c_str(); *bi; ++bi) + *ri++ = *bi; + + *ri = 0; + + return xpath_string(result, true); + } + + xpath_string eval_string(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_string_constant: + return xpath_string_const(_data.string); + + case ast_func_local_name_0: + { + xpath_node na = c.n; + + return xpath_string_const(local_name(na)); + } + + case ast_func_local_name_1: + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + xpath_node na = ns.first(); + + return xpath_string_const(local_name(na)); + } + + case ast_func_name_0: + { + xpath_node na = c.n; + + return xpath_string_const(qualified_name(na)); + } + + case ast_func_name_1: + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + xpath_node na = ns.first(); + + return xpath_string_const(qualified_name(na)); + } + + case ast_func_namespace_uri_0: + { + xpath_node na = c.n; + + return xpath_string_const(namespace_uri(na)); + } + + case ast_func_namespace_uri_1: + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + xpath_node na = ns.first(); + + return xpath_string_const(namespace_uri(na)); + } + + case ast_func_string_0: + return string_value(c.n, stack.result); + + case ast_func_string_1: + return _left->eval_string(c, stack); + + case ast_func_concat: + return eval_string_concat(c, stack); + + case ast_func_substring_before: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + xpath_string p = _right->eval_string(c, swapped_stack); + + const char_t* pos = find_substring(s.c_str(), p.c_str()); + + return pos ? xpath_string(s.c_str(), pos, stack.result) : xpath_string(); + } + + case ast_func_substring_after: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + xpath_string p = _right->eval_string(c, swapped_stack); + + const char_t* pos = find_substring(s.c_str(), p.c_str()); + if (!pos) return xpath_string(); + + const char_t* result = pos + p.length(); + + return s.uses_heap() ? xpath_string(result, stack.result) : xpath_string_const(result); + } + + case ast_func_substring_2: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + size_t s_length = s.length(); + + double first = round_nearest(_right->eval_number(c, stack)); + + if (is_nan(first)) return xpath_string(); // NaN + else if (first >= s_length + 1) return xpath_string(); + + size_t pos = first < 1 ? 1 : (size_t)first; + assert(1 <= pos && pos <= s_length + 1); + + const char_t* rbegin = s.c_str() + (pos - 1); + + return s.uses_heap() ? xpath_string(rbegin, stack.result) : xpath_string_const(rbegin); + } + + case ast_func_substring_3: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + size_t s_length = s.length(); + + double first = round_nearest(_right->eval_number(c, stack)); + double last = first + round_nearest(_right->_next->eval_number(c, stack)); + + if (is_nan(first) || is_nan(last)) return xpath_string(); + else if (first >= s_length + 1) return xpath_string(); + else if (first >= last) return xpath_string(); + else if (last < 1) return xpath_string(); + + size_t pos = first < 1 ? 1 : (size_t)first; + size_t end = last >= s_length + 1 ? s_length + 1 : (size_t)last; + + assert(1 <= pos && pos <= end && end <= s_length + 1); + const char_t* rbegin = s.c_str() + (pos - 1); + const char_t* rend = s.c_str() + (end - 1); + + return (end == s_length + 1 && !s.uses_heap()) ? xpath_string_const(rbegin) : xpath_string(rbegin, rend, stack.result); + } + + case ast_func_normalize_space_0: + { + xpath_string s = string_value(c.n, stack.result); + + normalize_space(s.data(stack.result)); + + return s; + } + + case ast_func_normalize_space_1: + { + xpath_string s = _left->eval_string(c, stack); + + normalize_space(s.data(stack.result)); + + return s; + } + + case ast_func_translate: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, stack); + xpath_string from = _right->eval_string(c, swapped_stack); + xpath_string to = _right->_next->eval_string(c, swapped_stack); + + translate(s.data(stack.result), from.c_str(), to.c_str()); + + return s; + } + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_string) + return xpath_string_const(_data.variable->get_string()); + + // fallthrough to type conversion + } + + default: + { + switch (_rettype) + { + case xpath_type_boolean: + return xpath_string_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); + + case xpath_type_number: + return convert_number_to_string(eval_number(c, stack), stack.result); + + case xpath_type_node_set: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_node_set_raw ns = eval_node_set(c, swapped_stack); + return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); + } + + default: + assert(!"Wrong expression for return type string"); + return xpath_string(); + } + } + } + } + + xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_op_union: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack); + xpath_node_set_raw rs = _right->eval_node_set(c, stack); + + // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother + rs.set_type(xpath_node_set::type_unsorted); + + rs.append(ls.begin(), ls.end(), stack.result); + rs.remove_duplicates(); + + return rs; + } + + case ast_filter: + case ast_filter_posinv: + { + xpath_node_set_raw set = _left->eval_node_set(c, stack); + + // either expression is a number or it contains position() call; sort by document order + if (_type == ast_filter) set.sort_do(); + + apply_predicate(set, 0, _right, stack); + + return set; + } + + case ast_func_id: + return xpath_node_set_raw(); + + case ast_step: + { + switch (_axis) + { + case axis_ancestor: + return step_do(c, stack, axis_to_type<axis_ancestor>()); + + case axis_ancestor_or_self: + return step_do(c, stack, axis_to_type<axis_ancestor_or_self>()); + + case axis_attribute: + return step_do(c, stack, axis_to_type<axis_attribute>()); + + case axis_child: + return step_do(c, stack, axis_to_type<axis_child>()); + + case axis_descendant: + return step_do(c, stack, axis_to_type<axis_descendant>()); + + case axis_descendant_or_self: + return step_do(c, stack, axis_to_type<axis_descendant_or_self>()); + + case axis_following: + return step_do(c, stack, axis_to_type<axis_following>()); + + case axis_following_sibling: + return step_do(c, stack, axis_to_type<axis_following_sibling>()); + + case axis_namespace: + // namespaced axis is not supported + return xpath_node_set_raw(); + + case axis_parent: + return step_do(c, stack, axis_to_type<axis_parent>()); + + case axis_preceding: + return step_do(c, stack, axis_to_type<axis_preceding>()); + + case axis_preceding_sibling: + return step_do(c, stack, axis_to_type<axis_preceding_sibling>()); + + case axis_self: + return step_do(c, stack, axis_to_type<axis_self>()); + } + } + + case ast_step_root: + { + assert(!_right); // root step can't have any predicates + + xpath_node_set_raw ns; + + ns.set_type(xpath_node_set::type_sorted); + + if (c.n.node()) ns.push_back(c.n.node().root(), stack.result); + else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result); + + return ns; + } + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_node_set) + { + const xpath_node_set& s = _data.variable->get_node_set(); + + xpath_node_set_raw ns; + + ns.set_type(s.type()); + ns.append(s.begin(), s.end(), stack.result); + + return ns; + } + + // fallthrough to type conversion + } + + default: + assert(!"Wrong expression for return type node set"); + return xpath_node_set_raw(); + } + } + + bool is_posinv() + { + switch (_type) + { + case ast_func_position: + return false; + + case ast_string_constant: + case ast_number_constant: + case ast_variable: + return true; + + case ast_step: + case ast_step_root: + return true; + + case ast_predicate: + case ast_filter: + case ast_filter_posinv: + return true; + + default: + if (_left && !_left->is_posinv()) return false; + + for (xpath_ast_node* n = _right; n; n = n->_next) + if (!n->is_posinv()) return false; + + return true; + } + } + + xpath_value_type rettype() const + { + return static_cast<xpath_value_type>(_rettype); + } + }; + + struct xpath_parser + { + xpath_allocator* _alloc; + xpath_lexer _lexer; + + const char_t* _query; + xpath_variable_set* _variables; + + xpath_parse_result* _result; + + #ifdef PUGIXML_NO_EXCEPTIONS + jmp_buf _error_handler; + #endif + + void throw_error(const char* message) + { + _result->error = message; + _result->offset = _lexer.current_pos() - _query; + + #ifdef PUGIXML_NO_EXCEPTIONS + longjmp(_error_handler, 1); + #else + throw xpath_exception(*_result); + #endif + } + + void throw_error_oom() + { + #ifdef PUGIXML_NO_EXCEPTIONS + throw_error("Out of memory"); + #else + throw std::bad_alloc(); + #endif + } + + void* alloc_node() + { + void* result = _alloc->allocate_nothrow(sizeof(xpath_ast_node)); + + if (!result) throw_error_oom(); + + return result; + } + + const char_t* alloc_string(const xpath_lexer_string& value) + { + if (value.begin) + { + size_t length = static_cast<size_t>(value.end - value.begin); + + char_t* c = static_cast<char_t*>(_alloc->allocate_nothrow((length + 1) * sizeof(char_t))); + if (!c) throw_error_oom(); + + memcpy(c, value.begin, length * sizeof(char_t)); + c[length] = 0; + + return c; + } + else return 0; + } + + xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2]) + { + assert(argc <= 1); + + if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + + return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]); + } + + xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2]) + { + switch (name.begin[0]) + { + case 'b': + if (name == PUGIXML_TEXT("boolean") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]); + + break; + + case 'c': + if (name == PUGIXML_TEXT("count") && argc == 1) + { + if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]); + } + else if (name == PUGIXML_TEXT("contains") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("concat") && argc >= 2) + return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("ceiling") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]); + + break; + + case 'f': + if (name == PUGIXML_TEXT("false") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean); + else if (name == PUGIXML_TEXT("floor") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]); + + break; + + case 'i': + if (name == PUGIXML_TEXT("id") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]); + + break; + + case 'l': + if (name == PUGIXML_TEXT("last") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number); + else if (name == PUGIXML_TEXT("lang") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]); + else if (name == PUGIXML_TEXT("local-name") && argc <= 1) + return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args); + + break; + + case 'n': + if (name == PUGIXML_TEXT("name") && argc <= 1) + return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args); + else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) + return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args); + else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("not") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]); + else if (name == PUGIXML_TEXT("number") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); + + break; + + case 'p': + if (name == PUGIXML_TEXT("position") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number); + + break; + + case 'r': + if (name == PUGIXML_TEXT("round") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]); + + break; + + case 's': + if (name == PUGIXML_TEXT("string") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); + else if (name == PUGIXML_TEXT("string-length") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_string, args[0]); + else if (name == PUGIXML_TEXT("starts-with") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring-before") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring-after") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3)) + return new (alloc_node()) xpath_ast_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("sum") && argc == 1) + { + if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]); + } + + break; + + case 't': + if (name == PUGIXML_TEXT("translate") && argc == 3) + return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("true") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean); + + break; + } + + throw_error("Unrecognized function or wrong parameter count"); + + return 0; + } + + axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified) + { + specified = true; + + switch (name.begin[0]) + { + case 'a': + if (name == PUGIXML_TEXT("ancestor")) + return axis_ancestor; + else if (name == PUGIXML_TEXT("ancestor-or-self")) + return axis_ancestor_or_self; + else if (name == PUGIXML_TEXT("attribute")) + return axis_attribute; + + break; + + case 'c': + if (name == PUGIXML_TEXT("child")) + return axis_child; + + break; + + case 'd': + if (name == PUGIXML_TEXT("descendant")) + return axis_descendant; + else if (name == PUGIXML_TEXT("descendant-or-self")) + return axis_descendant_or_self; + + break; + + case 'f': + if (name == PUGIXML_TEXT("following")) + return axis_following; + else if (name == PUGIXML_TEXT("following-sibling")) + return axis_following_sibling; + + break; + + case 'n': + if (name == PUGIXML_TEXT("namespace")) + return axis_namespace; + + break; + + case 'p': + if (name == PUGIXML_TEXT("parent")) + return axis_parent; + else if (name == PUGIXML_TEXT("preceding")) + return axis_preceding; + else if (name == PUGIXML_TEXT("preceding-sibling")) + return axis_preceding_sibling; + + break; + + case 's': + if (name == PUGIXML_TEXT("self")) + return axis_self; + + break; + } + + specified = false; + return axis_child; + } + + nodetest_t parse_node_test_type(const xpath_lexer_string& name) + { + switch (name.begin[0]) + { + case 'c': + if (name == PUGIXML_TEXT("comment")) + return nodetest_type_comment; + + break; + + case 'n': + if (name == PUGIXML_TEXT("node")) + return nodetest_type_node; + + break; + + case 'p': + if (name == PUGIXML_TEXT("processing-instruction")) + return nodetest_type_pi; + + break; + + case 't': + if (name == PUGIXML_TEXT("text")) + return nodetest_type_text; + + break; + } + + return nodetest_none; + } + + // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall + xpath_ast_node* parse_primary_expression() + { + switch (_lexer.current()) + { + case lex_var_ref: + { + xpath_lexer_string name = _lexer.contents(); + + if (!_variables) + throw_error("Unknown variable: variable set is not provided"); + + xpath_variable* var = get_variable(_variables, name.begin, name.end); + + if (!var) + throw_error("Unknown variable: variable set does not contain the given name"); + + _lexer.next(); + + return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var); + } + + case lex_open_brace: + { + _lexer.next(); + + xpath_ast_node* n = parse_expression(); + + if (_lexer.current() != lex_close_brace) + throw_error("Unmatched braces"); + + _lexer.next(); + + return n; + } + + case lex_quoted_string: + { + const char_t* value = alloc_string(_lexer.contents()); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value); + _lexer.next(); + + return n; + } + + case lex_number: + { + double value = 0; + + if (!convert_string_to_number(_lexer.contents().begin, _lexer.contents().end, &value)) + throw_error_oom(); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value); + _lexer.next(); + + return n; + } + + case lex_string: + { + xpath_ast_node* args[2] = {0}; + size_t argc = 0; + + xpath_lexer_string function = _lexer.contents(); + _lexer.next(); + + xpath_ast_node* last_arg = 0; + + if (_lexer.current() != lex_open_brace) + throw_error("Unrecognized function call"); + _lexer.next(); + + if (_lexer.current() != lex_close_brace) + args[argc++] = parse_expression(); + + while (_lexer.current() != lex_close_brace) + { + if (_lexer.current() != lex_comma) + throw_error("No comma between function arguments"); + _lexer.next(); + + xpath_ast_node* n = parse_expression(); + + if (argc < 2) args[argc] = n; + else last_arg->set_next(n); + + argc++; + last_arg = n; + } + + _lexer.next(); + + return parse_function(function, argc, args); + } + + default: + throw_error("Unrecognizable primary expression"); + + return 0; + } + } + + // FilterExpr ::= PrimaryExpr | FilterExpr Predicate + // Predicate ::= '[' PredicateExpr ']' + // PredicateExpr ::= Expr + xpath_ast_node* parse_filter_expression() + { + xpath_ast_node* n = parse_primary_expression(); + + while (_lexer.current() == lex_open_square_brace) + { + _lexer.next(); + + xpath_ast_node* expr = parse_expression(); + + if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set"); + + bool posinv = expr->rettype() != xpath_type_number && expr->is_posinv(); + + n = new (alloc_node()) xpath_ast_node(posinv ? ast_filter_posinv : ast_filter, xpath_type_node_set, n, expr); + + if (_lexer.current() != lex_close_square_brace) + throw_error("Unmatched square brace"); + + _lexer.next(); + } + + return n; + } + + // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep + // AxisSpecifier ::= AxisName '::' | '@'? + // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' + // NameTest ::= '*' | NCName ':' '*' | QName + // AbbreviatedStep ::= '.' | '..' + xpath_ast_node* parse_step(xpath_ast_node* set) + { + if (set && set->rettype() != xpath_type_node_set) + throw_error("Step has to be applied to node set"); + + bool axis_specified = false; + axis_t axis = axis_child; // implied child axis + + if (_lexer.current() == lex_axis_attribute) + { + axis = axis_attribute; + axis_specified = true; + + _lexer.next(); + } + else if (_lexer.current() == lex_dot) + { + _lexer.next(); + + return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0); + } + else if (_lexer.current() == lex_double_dot) + { + _lexer.next(); + + return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0); + } + + nodetest_t nt_type = nodetest_none; + xpath_lexer_string nt_name; + + if (_lexer.current() == lex_string) + { + // node name test + nt_name = _lexer.contents(); + _lexer.next(); + + // was it an axis name? + if (_lexer.current() == lex_double_colon) + { + // parse axis name + if (axis_specified) throw_error("Two axis specifiers in one step"); + + axis = parse_axis_name(nt_name, axis_specified); + + if (!axis_specified) throw_error("Unknown axis"); + + // read actual node test + _lexer.next(); + + if (_lexer.current() == lex_multiply) + { + nt_type = nodetest_all; + nt_name = xpath_lexer_string(); + _lexer.next(); + } + else if (_lexer.current() == lex_string) + { + nt_name = _lexer.contents(); + _lexer.next(); + } + else throw_error("Unrecognized node test"); + } + + if (nt_type == nodetest_none) + { + // node type test or processing-instruction + if (_lexer.current() == lex_open_brace) + { + _lexer.next(); + + if (_lexer.current() == lex_close_brace) + { + _lexer.next(); + + nt_type = parse_node_test_type(nt_name); + + if (nt_type == nodetest_none) throw_error("Unrecognized node type"); + + nt_name = xpath_lexer_string(); + } + else if (nt_name == PUGIXML_TEXT("processing-instruction")) + { + if (_lexer.current() != lex_quoted_string) + throw_error("Only literals are allowed as arguments to processing-instruction()"); + + nt_type = nodetest_pi; + nt_name = _lexer.contents(); + _lexer.next(); + + if (_lexer.current() != lex_close_brace) + throw_error("Unmatched brace near processing-instruction()"); + _lexer.next(); + } + else + throw_error("Unmatched brace near node type test"); + + } + // QName or NCName:* + else + { + if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* + { + nt_name.end--; // erase * + + nt_type = nodetest_all_in_namespace; + } + else nt_type = nodetest_name; + } + } + } + else if (_lexer.current() == lex_multiply) + { + nt_type = nodetest_all; + _lexer.next(); + } + else throw_error("Unrecognized node test"); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name)); + + xpath_ast_node* last = 0; + + while (_lexer.current() == lex_open_square_brace) + { + _lexer.next(); + + xpath_ast_node* expr = parse_expression(); + + xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, xpath_type_node_set, expr); + + if (_lexer.current() != lex_close_square_brace) + throw_error("Unmatched square brace"); + _lexer.next(); + + if (last) last->set_next(pred); + else n->set_right(pred); + + last = pred; + } + + return n; + } + + // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step + xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) + { + xpath_ast_node* n = parse_step(set); + + while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) + { + lexeme_t l = _lexer.current(); + _lexer.next(); + + if (l == lex_double_slash) + n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + + n = parse_step(n); + } + + return n; + } + + // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath + // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath + xpath_ast_node* parse_location_path() + { + if (_lexer.current() == lex_slash) + { + _lexer.next(); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); + + // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path + lexeme_t l = _lexer.current(); + + if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply) + return parse_relative_location_path(n); + else + return n; + } + else if (_lexer.current() == lex_double_slash) + { + _lexer.next(); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); + n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + + return parse_relative_location_path(n); + } + + // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 + return parse_relative_location_path(0); + } + + // PathExpr ::= LocationPath + // | FilterExpr + // | FilterExpr '/' RelativeLocationPath + // | FilterExpr '//' RelativeLocationPath + xpath_ast_node* parse_path_expression() + { + // Clarification. + // PathExpr begins with either LocationPath or FilterExpr. + // FilterExpr begins with PrimaryExpr + // PrimaryExpr begins with '$' in case of it being a variable reference, + // '(' in case of it being an expression, string literal, number constant or + // function call. + + if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || + _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || + _lexer.current() == lex_string) + { + if (_lexer.current() == lex_string) + { + // This is either a function call, or not - if not, we shall proceed with location path + const char_t* state = _lexer.state(); + + while (IS_CHARTYPE(*state, ct_space)) ++state; + + if (*state != '(') return parse_location_path(); + + // This looks like a function call; however this still can be a node-test. Check it. + if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path(); + } + + xpath_ast_node* n = parse_filter_expression(); + + if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) + { + lexeme_t l = _lexer.current(); + _lexer.next(); + + if (l == lex_double_slash) + { + if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set"); + + n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + } + + // select from location path + return parse_relative_location_path(n); + } + + return n; + } + else return parse_location_path(); + } + + // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr + xpath_ast_node* parse_union_expression() + { + xpath_ast_node* n = parse_path_expression(); + + while (_lexer.current() == lex_union) + { + _lexer.next(); + + xpath_ast_node* expr = parse_union_expression(); + + if (n->rettype() != xpath_type_node_set || expr->rettype() != xpath_type_node_set) + throw_error("Union operator has to be applied to node sets"); + + n = new (alloc_node()) xpath_ast_node(ast_op_union, xpath_type_node_set, n, expr); + } + + return n; + } + + // UnaryExpr ::= UnionExpr | '-' UnaryExpr + xpath_ast_node* parse_unary_expression() + { + if (_lexer.current() == lex_minus) + { + _lexer.next(); + + xpath_ast_node* expr = parse_unary_expression(); + + return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr); + } + else return parse_union_expression(); + } + + // MultiplicativeExpr ::= UnaryExpr + // | MultiplicativeExpr '*' UnaryExpr + // | MultiplicativeExpr 'div' UnaryExpr + // | MultiplicativeExpr 'mod' UnaryExpr + xpath_ast_node* parse_multiplicative_expression() + { + xpath_ast_node* n = parse_unary_expression(); + + while (_lexer.current() == lex_multiply || (_lexer.current() == lex_string && + (_lexer.contents() == PUGIXML_TEXT("mod") || _lexer.contents() == PUGIXML_TEXT("div")))) + { + ast_type_t op = _lexer.current() == lex_multiply ? ast_op_multiply : + _lexer.contents().begin[0] == 'd' ? ast_op_divide : ast_op_mod; + _lexer.next(); + + xpath_ast_node* expr = parse_unary_expression(); + + n = new (alloc_node()) xpath_ast_node(op, xpath_type_number, n, expr); + } + + return n; + } + + // AdditiveExpr ::= MultiplicativeExpr + // | AdditiveExpr '+' MultiplicativeExpr + // | AdditiveExpr '-' MultiplicativeExpr + xpath_ast_node* parse_additive_expression() + { + xpath_ast_node* n = parse_multiplicative_expression(); + + while (_lexer.current() == lex_plus || _lexer.current() == lex_minus) + { + lexeme_t l = _lexer.current(); + + _lexer.next(); + + xpath_ast_node* expr = parse_multiplicative_expression(); + + n = new (alloc_node()) xpath_ast_node(l == lex_plus ? ast_op_add : ast_op_subtract, xpath_type_number, n, expr); + } + + return n; + } + + // RelationalExpr ::= AdditiveExpr + // | RelationalExpr '<' AdditiveExpr + // | RelationalExpr '>' AdditiveExpr + // | RelationalExpr '<=' AdditiveExpr + // | RelationalExpr '>=' AdditiveExpr + xpath_ast_node* parse_relational_expression() + { + xpath_ast_node* n = parse_additive_expression(); + + while (_lexer.current() == lex_less || _lexer.current() == lex_less_or_equal || + _lexer.current() == lex_greater || _lexer.current() == lex_greater_or_equal) + { + lexeme_t l = _lexer.current(); + _lexer.next(); + + xpath_ast_node* expr = parse_additive_expression(); + + n = new (alloc_node()) xpath_ast_node(l == lex_less ? ast_op_less : l == lex_greater ? ast_op_greater : + l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal, xpath_type_boolean, n, expr); + } + + return n; + } + + // EqualityExpr ::= RelationalExpr + // | EqualityExpr '=' RelationalExpr + // | EqualityExpr '!=' RelationalExpr + xpath_ast_node* parse_equality_expression() + { + xpath_ast_node* n = parse_relational_expression(); + + while (_lexer.current() == lex_equal || _lexer.current() == lex_not_equal) + { + lexeme_t l = _lexer.current(); + + _lexer.next(); + + xpath_ast_node* expr = parse_relational_expression(); + + n = new (alloc_node()) xpath_ast_node(l == lex_equal ? ast_op_equal : ast_op_not_equal, xpath_type_boolean, n, expr); + } + + return n; + } + + // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr + xpath_ast_node* parse_and_expression() + { + xpath_ast_node* n = parse_equality_expression(); + + while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("and")) + { + _lexer.next(); + + xpath_ast_node* expr = parse_equality_expression(); + + n = new (alloc_node()) xpath_ast_node(ast_op_and, xpath_type_boolean, n, expr); + } + + return n; + } + + // OrExpr ::= AndExpr | OrExpr 'or' AndExpr + xpath_ast_node* parse_or_expression() + { + xpath_ast_node* n = parse_and_expression(); + + while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("or")) + { + _lexer.next(); + + xpath_ast_node* expr = parse_and_expression(); + + n = new (alloc_node()) xpath_ast_node(ast_op_or, xpath_type_boolean, n, expr); + } + + return n; + } + + // Expr ::= OrExpr + xpath_ast_node* parse_expression() + { + return parse_or_expression(); + } + + xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result) + { + } + + xpath_ast_node* parse() + { + xpath_ast_node* result = parse_expression(); + + if (_lexer.current() != lex_eof) + { + // there are still unparsed tokens left, error + throw_error("Incorrect query"); + } + + return result; + } + + static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result) + { + xpath_parser parser(query, variables, alloc, result); + + #ifdef PUGIXML_NO_EXCEPTIONS + int error = setjmp(parser._error_handler); + + return (error == 0) ? parser.parse() : 0; + #else + return parser.parse(); + #endif + } + }; + + struct xpath_query_impl + { + static xpath_query_impl* create() + { + void* memory = global_allocate(sizeof(xpath_query_impl)); + + return new (memory) xpath_query_impl(); + } + + static void destroy(void* ptr) + { + if (!ptr) return; + + // free all allocated pages + static_cast<xpath_query_impl*>(ptr)->alloc.release(); + + // free allocator memory (with the first page) + global_deallocate(ptr); + } + + xpath_query_impl(): root(0), alloc(&block) + { + block.next = 0; + } + + xpath_ast_node* root; + xpath_allocator alloc; + xpath_memory_block block; + }; + + xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd) + { + if (!impl) return xpath_string(); + + #ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return xpath_string(); + #endif + + xpath_context c(n, 1, 1); + + return impl->root->eval_string(c, sd.stack); + } +} + +namespace pugi +{ +#ifndef PUGIXML_NO_EXCEPTIONS + xpath_exception::xpath_exception(const xpath_parse_result& result): _result(result) + { + assert(result.error); + } + + const char* xpath_exception::what() const throw() + { + return _result.error; + } + + const xpath_parse_result& xpath_exception::result() const + { + return _result; + } +#endif + + xpath_node::xpath_node() + { + } + + xpath_node::xpath_node(const xml_node& node): _node(node) + { + } + + xpath_node::xpath_node(const xml_attribute& attribute, const xml_node& parent): _node(attribute ? parent : xml_node()), _attribute(attribute) + { + } + + xml_node xpath_node::node() const + { + return _attribute ? xml_node() : _node; + } + + xml_attribute xpath_node::attribute() const + { + return _attribute; + } + + xml_node xpath_node::parent() const + { + return _attribute ? _node : _node.parent(); + } + + xpath_node::operator xpath_node::unspecified_bool_type() const + { + return (_node || _attribute) ? &xpath_node::_node : 0; + } + + bool xpath_node::operator!() const + { + return !(_node || _attribute); + } + + bool xpath_node::operator==(const xpath_node& n) const + { + return _node == n._node && _attribute == n._attribute; + } + + bool xpath_node::operator!=(const xpath_node& n) const + { + return _node != n._node || _attribute != n._attribute; + } + +#ifdef __BORLANDC__ + bool operator&&(const xpath_node& lhs, bool rhs) + { + return (bool)lhs && rhs; + } + + bool operator||(const xpath_node& lhs, bool rhs) + { + return (bool)lhs || rhs; + } +#endif + + void xpath_node_set::_assign(const_iterator begin, const_iterator end) + { + assert(begin <= end); + + size_t size = static_cast<size_t>(end - begin); + + if (size <= 1) + { + // deallocate old buffer + if (_begin != &_storage) global_deallocate(_begin); + + // use internal buffer + if (begin != end) _storage = *begin; + + _begin = &_storage; + _end = &_storage + size; + } + else + { + // make heap copy + xpath_node* storage = static_cast<xpath_node*>(global_allocate(size * sizeof(xpath_node))); + + if (!storage) + { + #ifdef PUGIXML_NO_EXCEPTIONS + return; + #else + throw std::bad_alloc(); + #endif + } + + memcpy(storage, begin, size * sizeof(xpath_node)); + + // deallocate old buffer + if (_begin != &_storage) global_deallocate(_begin); + + // finalize + _begin = storage; + _end = storage + size; + } + } + + xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage) + { + } + + xpath_node_set::xpath_node_set(const_iterator begin, const_iterator end, type_t type): _type(type), _begin(&_storage), _end(&_storage) + { + _assign(begin, end); + } + + xpath_node_set::~xpath_node_set() + { + if (_begin != &_storage) global_deallocate(_begin); + } + + xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage) + { + _assign(ns._begin, ns._end); + } + + xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) + { + if (this == &ns) return *this; + + _type = ns._type; + _assign(ns._begin, ns._end); + + return *this; + } + + xpath_node_set::type_t xpath_node_set::type() const + { + return _type; + } + + size_t xpath_node_set::size() const + { + return _end - _begin; + } + + bool xpath_node_set::empty() const + { + return _begin == _end; + } + + const xpath_node& xpath_node_set::operator[](size_t index) const + { + assert(index < size()); + return _begin[index]; + } + + xpath_node_set::const_iterator xpath_node_set::begin() const + { + return _begin; + } + + xpath_node_set::const_iterator xpath_node_set::end() const + { + return _end; + } + + void xpath_node_set::sort(bool reverse) + { + _type = xpath_sort(_begin, _end, _type, reverse); + } + + xpath_node xpath_node_set::first() const + { + return xpath_first(_begin, _end, _type); + } + + xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0) + { + } + + xpath_parse_result::operator bool() const + { + return error == 0; + } + const char* xpath_parse_result::description() const + { + return error ? error : "No error"; + } + + xpath_variable::xpath_variable() + { + } + + const char_t* xpath_variable::name() const + { + switch (_type) + { + case xpath_type_node_set: + return static_cast<const xpath_variable_node_set*>(this)->name; + + case xpath_type_number: + return static_cast<const xpath_variable_number*>(this)->name; + + case xpath_type_string: + return static_cast<const xpath_variable_string*>(this)->name; + + case xpath_type_boolean: + return static_cast<const xpath_variable_boolean*>(this)->name; + + default: + assert(!"Invalid variable type"); + return 0; + } + } + + xpath_value_type xpath_variable::type() const + { + return _type; + } + + bool xpath_variable::get_boolean() const + { + return (_type == xpath_type_boolean) ? static_cast<const xpath_variable_boolean*>(this)->value : false; + } + + double xpath_variable::get_number() const + { + return (_type == xpath_type_number) ? static_cast<const xpath_variable_number*>(this)->value : gen_nan(); + } + + const char_t* xpath_variable::get_string() const + { + const char_t* value = (_type == xpath_type_string) ? static_cast<const xpath_variable_string*>(this)->value : 0; + return value ? value : PUGIXML_TEXT(""); + } + + const xpath_node_set& xpath_variable::get_node_set() const + { + return (_type == xpath_type_node_set) ? static_cast<const xpath_variable_node_set*>(this)->value : dummy_node_set; + } + + bool xpath_variable::set(bool value) + { + if (_type != xpath_type_boolean) return false; + + static_cast<xpath_variable_boolean*>(this)->value = value; + return true; + } + + bool xpath_variable::set(double value) + { + if (_type != xpath_type_number) return false; + + static_cast<xpath_variable_number*>(this)->value = value; + return true; + } + + bool xpath_variable::set(const char_t* value) + { + if (_type != xpath_type_string) return false; + + xpath_variable_string* var = static_cast<xpath_variable_string*>(this); + + // duplicate string + size_t size = (strlength(value) + 1) * sizeof(char_t); + + char_t* copy = static_cast<char_t*>(global_allocate(size)); + if (!copy) return false; + + memcpy(copy, value, size); + + // replace old string + if (var->value) global_deallocate(var->value); + var->value = copy; + + return true; + } + + bool xpath_variable::set(const xpath_node_set& value) + { + if (_type != xpath_type_node_set) return false; + + static_cast<xpath_variable_node_set*>(this)->value = value; + return true; + } + + xpath_variable_set::xpath_variable_set() + { + for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0; + } + + xpath_variable_set::~xpath_variable_set() + { + for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) + { + xpath_variable* var = _data[i]; + + while (var) + { + xpath_variable* next = var->_next; + + delete_xpath_variable(var->_type, var); + + var = next; + } + } + } + + xpath_variable* xpath_variable_set::find(const char_t* name) const + { + const size_t hash_size = sizeof(_data) / sizeof(_data[0]); + size_t hash = hash_string(name) % hash_size; + + // look for existing variable + for (xpath_variable* var = _data[hash]; var; var = var->_next) + if (strequal(var->name(), name)) + return var; + + return 0; + } + + xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type) + { + const size_t hash_size = sizeof(_data) / sizeof(_data[0]); + size_t hash = hash_string(name) % hash_size; + + // look for existing variable + for (xpath_variable* var = _data[hash]; var; var = var->_next) + if (strequal(var->name(), name)) + return var->type() == type ? var : 0; + + // add new variable + xpath_variable* result = new_xpath_variable(type, name); + + if (result) + { + result->_type = type; + result->_next = _data[hash]; + + _data[hash] = result; + } + + return result; + } + + bool xpath_variable_set::set(const char_t* name, bool value) + { + xpath_variable* var = add(name, xpath_type_boolean); + return var ? var->set(value) : false; + } + + bool xpath_variable_set::set(const char_t* name, double value) + { + xpath_variable* var = add(name, xpath_type_number); + return var ? var->set(value) : false; + } + + bool xpath_variable_set::set(const char_t* name, const char_t* value) + { + xpath_variable* var = add(name, xpath_type_string); + return var ? var->set(value) : false; + } + + bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value) + { + xpath_variable* var = add(name, xpath_type_node_set); + return var ? var->set(value) : false; + } + + xpath_variable* xpath_variable_set::get(const char_t* name) + { + return find(name); + } + + const xpath_variable* xpath_variable_set::get(const char_t* name) const + { + return find(name); + } + + xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0) + { + xpath_query_impl* impl = xpath_query_impl::create(); + + if (!impl) + { + #ifdef PUGIXML_NO_EXCEPTIONS + _result.error = "Out of memory"; + #else + throw std::bad_alloc(); + #endif + } + else + { + buffer_holder impl_holder(impl, xpath_query_impl::destroy); + + impl->root = xpath_parser::parse(query, variables, &impl->alloc, &_result); + + if (impl->root) + { + _impl = static_cast<xpath_query_impl*>(impl_holder.release()); + _result.error = 0; + } + } + } + + xpath_query::~xpath_query() + { + xpath_query_impl::destroy(_impl); + } + + xpath_value_type xpath_query::return_type() const + { + if (!_impl) return xpath_type_none; + + return static_cast<xpath_query_impl*>(_impl)->root->rettype(); + } + + bool xpath_query::evaluate_boolean(const xpath_node& n) const + { + if (!_impl) return false; + + xpath_context c(n, 1, 1); + xpath_stack_data sd; + + #ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return false; + #endif + + return static_cast<xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack); + } + + double xpath_query::evaluate_number(const xpath_node& n) const + { + if (!_impl) return gen_nan(); + + xpath_context c(n, 1, 1); + xpath_stack_data sd; + + #ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return gen_nan(); + #endif + + return static_cast<xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack); + } + +#ifndef PUGIXML_NO_STL + string_t xpath_query::evaluate_string(const xpath_node& n) const + { + xpath_stack_data sd; + + return evaluate_string_impl(static_cast<xpath_query_impl*>(_impl), n, sd).c_str(); + } +#endif + + size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const + { + xpath_stack_data sd; + + xpath_string r = evaluate_string_impl(static_cast<xpath_query_impl*>(_impl), n, sd); + + size_t full_size = r.length() + 1; + + if (capacity > 0) + { + size_t size = (full_size < capacity) ? full_size : capacity; + assert(size > 0); + + memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); + buffer[size - 1] = 0; + } + + return full_size; + } + + xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const + { + if (!_impl) return xpath_node_set(); + + xpath_ast_node* root = static_cast<xpath_query_impl*>(_impl)->root; + + if (root->rettype() != xpath_type_node_set) + { + #ifdef PUGIXML_NO_EXCEPTIONS + return xpath_node_set(); + #else + xpath_parse_result result; + result.error = "Expression does not evaluate to node set"; + + throw xpath_exception(result); + #endif + } + + xpath_context c(n, 1, 1); + xpath_stack_data sd; + + #ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return xpath_node_set(); + #endif + + xpath_node_set_raw r = root->eval_node_set(c, sd.stack); + + return xpath_node_set(r.begin(), r.end(), r.type()); + } + + const xpath_parse_result& xpath_query::result() const + { + return _result; + } + + xpath_query::operator xpath_query::unspecified_bool_type() const + { + return _impl ? &xpath_query::_impl : 0; + } + + bool xpath_query::operator!() const + { + return !_impl; + } + + xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const + { + xpath_query q(query, variables); + return select_single_node(q); + } + + xpath_node xml_node::select_single_node(const xpath_query& query) const + { + xpath_node_set s = query.evaluate_node_set(*this); + return s.empty() ? xpath_node() : s.first(); + } + + xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const + { + xpath_query q(query, variables); + return select_nodes(q); + } + + xpath_node_set xml_node::select_nodes(const xpath_query& query) const + { + return query.evaluate_node_set(*this); + } +} + +#endif + +/** + * Copyright (c) 2006-2010 Arseny Kapoulkine + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ diff --git a/extensions/pugixml/src/pugixml.hpp b/extensions/pugixml/src/pugixml.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4360996282234d5b917c8955b9d024e58533ac73 --- /dev/null +++ b/extensions/pugixml/src/pugixml.hpp @@ -0,0 +1,1131 @@ +/** + * pugixml parser - version 1.0 + * -------------------------------------------------------- + * Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Report bugs and download new versions at http://pugixml.org/ + * + * This library is distributed under the MIT License. See notice at the end + * of this file. + * + * This work is based on the pugxml parser, which is: + * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) + */ + +#ifndef HEADER_PUGIXML_HPP +#define HEADER_PUGIXML_HPP + +#include "pugiconfig.hpp" + +#ifndef PUGIXML_NO_STL +namespace std +{ + struct bidirectional_iterator_tag; + +#ifdef __SUNPRO_CC + // Sun C++ compiler has a bug which forces template argument names in forward declarations to be the same as in actual definitions + template <class _T> class allocator; + template <class _charT> struct char_traits; + template <class _charT, class _Traits> class basic_istream; + template <class _charT, class _Traits> class basic_ostream; + template <class _charT, class _Traits, class _Allocator> class basic_string; +#else + // Borland C++ compiler has a bug which forces template argument names in forward declarations to be the same as in actual definitions + template <class _Ty> class allocator; + template <class _Ty> struct char_traits; + template <class _Elem, class _Traits> class basic_istream; + template <class _Elem, class _Traits> class basic_ostream; + template <class _Elem, class _Traits, class _Ax> class basic_string; +#endif + + // Digital Mars compiler has a bug which requires a forward declaration for explicit instantiation (otherwise type selection is messed up later, producing link errors) + // Also note that we have to declare char_traits as a class here, since it's defined that way +#ifdef __DMC__ + template <> class char_traits<char>; +#endif +} +#endif + +// Macro for deprecated features +#ifndef PUGIXML_DEPRECATED +# if defined(__GNUC__) +# define PUGIXML_DEPRECATED __attribute__((deprecated)) +# elif defined(_MSC_VER) && _MSC_VER >= 1300 +# define PUGIXML_DEPRECATED __declspec(deprecated) +# else +# define PUGIXML_DEPRECATED +# endif +#endif + +// Include exception header for XPath +#if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS) +# include <exception> +#endif + +// If no API is defined, assume default +#ifndef PUGIXML_API +# define PUGIXML_API +#endif + +// If no API for classes is defined, assume default +#ifndef PUGIXML_CLASS +# define PUGIXML_CLASS PUGIXML_API +#endif + +// If no API for functions is defined, assume default +#ifndef PUGIXML_FUNCTION +# define PUGIXML_FUNCTION PUGIXML_API +#endif + +#include <stddef.h> + +// Character interface macros +#ifdef PUGIXML_WCHAR_MODE +# define PUGIXML_TEXT(t) L ## t +# define PUGIXML_CHAR wchar_t +#else +# define PUGIXML_TEXT(t) t +# define PUGIXML_CHAR char +#endif + +namespace pugi +{ + // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE + typedef PUGIXML_CHAR char_t; + +#ifndef PUGIXML_NO_STL + // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE + typedef std::basic_string<PUGIXML_CHAR, std::char_traits<PUGIXML_CHAR>, std::allocator<PUGIXML_CHAR> > string_t; +#endif +} + +// The PugiXML namespace +namespace pugi +{ + // Tree node types + enum xml_node_type + { + node_null, // Empty (null) node handle + node_document, // A document tree's absolute root + node_element, // Element tag, i.e. '<node/>' + node_pcdata, // Plain character data, i.e. 'text' + node_cdata, // Character data, i.e. '<![CDATA[text]]>' + node_comment, // Comment tag, i.e. '<!-- text -->' + node_pi, // Processing instruction, i.e. '<?name?>' + node_declaration, // Document declaration, i.e. '<?xml version="1.0"?>' + node_doctype // Document type declaration, i.e. '<!DOCTYPE doc>' + }; + + // Parsing options + + // Minimal parsing mode (equivalent to turning all other flags off). + // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed. + const unsigned int parse_minimal = 0x0000; + + // This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default. + const unsigned int parse_pi = 0x0001; + + // This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default. + const unsigned int parse_comments = 0x0002; + + // This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default. + const unsigned int parse_cdata = 0x0004; + + // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree. + // This flag is off by default; turning it on usually results in slower parsing and more memory consumption. + const unsigned int parse_ws_pcdata = 0x0008; + + // This flag determines if character and entity references are expanded during parsing. This flag is on by default. + const unsigned int parse_escapes = 0x0010; + + // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default. + const unsigned int parse_eol = 0x0020; + + // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default. + const unsigned int parse_wconv_attribute = 0x0040; + + // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default. + const unsigned int parse_wnorm_attribute = 0x0080; + + // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default. + const unsigned int parse_declaration = 0x0100; + + // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default. + const unsigned int parse_doctype = 0x0200; + + // The default parsing mode. + // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, + // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. + const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol; + + // The full parsing mode. + // Nodes of all types are added to the DOM tree, character/reference entities are expanded, + // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. + const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype; + + // These flags determine the encoding of input data for XML document + enum xml_encoding + { + encoding_auto, // Auto-detect input encoding using BOM or < / <? detection; use UTF8 if BOM is not found + encoding_utf8, // UTF8 encoding + encoding_utf16_le, // Little-endian UTF16 + encoding_utf16_be, // Big-endian UTF16 + encoding_utf16, // UTF16 with native endianness + encoding_utf32_le, // Little-endian UTF32 + encoding_utf32_be, // Big-endian UTF32 + encoding_utf32, // UTF32 with native endianness + encoding_wchar // The same encoding wchar_t has (either UTF16 or UTF32) + }; + + // Formatting flags + + // Indent the nodes that are written to output stream with as many indentation strings as deep the node is in DOM tree. This flag is on by default. + const unsigned int format_indent = 0x01; + + // Write encoding-specific BOM to the output stream. This flag is off by default. + const unsigned int format_write_bom = 0x02; + + // Use raw output mode (no indentation and no line breaks are written). This flag is off by default. + const unsigned int format_raw = 0x04; + + // Omit default XML declaration even if there is no declaration in the document. This flag is off by default. + const unsigned int format_no_declaration = 0x08; + + // The default set of formatting flags. + // Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none. + const unsigned int format_default = format_indent; + + // Forward declarations + struct xml_attribute_struct; + struct xml_node_struct; + + class xml_node_iterator; + class xml_attribute_iterator; + + class xml_tree_walker; + + class xml_node; + + #ifndef PUGIXML_NO_XPATH + class xpath_node; + class xpath_node_set; + class xpath_query; + class xpath_variable_set; + #endif + + // Writer interface for node printing (see xml_node::print) + class PUGIXML_CLASS xml_writer + { + public: + virtual ~xml_writer() {} + + // Write memory chunk into stream/file/whatever + virtual void write(const void* data, size_t size) = 0; + }; + + // xml_writer implementation for FILE* + class PUGIXML_CLASS xml_writer_file: public xml_writer + { + public: + // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio + xml_writer_file(void* file); + + virtual void write(const void* data, size_t size); + + private: + void* file; + }; + + #ifndef PUGIXML_NO_STL + // xml_writer implementation for streams + class PUGIXML_CLASS xml_writer_stream: public xml_writer + { + public: + // Construct writer from an output stream object + xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream); + xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream); + + virtual void write(const void* data, size_t size); + + private: + std::basic_ostream<char, std::char_traits<char> >* narrow_stream; + std::basic_ostream<wchar_t, std::char_traits<wchar_t> >* wide_stream; + }; + #endif + + // A light-weight handle for manipulating attributes in DOM tree + class PUGIXML_CLASS xml_attribute + { + friend class xml_attribute_iterator; + friend class xml_node; + + private: + xml_attribute_struct* _attr; + + typedef xml_attribute_struct* xml_attribute::*unspecified_bool_type; + + public: + // Default constructor. Constructs an empty attribute. + xml_attribute(); + + // Constructs attribute from internal pointer + explicit xml_attribute(xml_attribute_struct* attr); + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + + // Comparison operators (compares wrapped attribute pointers) + bool operator==(const xml_attribute& r) const; + bool operator!=(const xml_attribute& r) const; + bool operator<(const xml_attribute& r) const; + bool operator>(const xml_attribute& r) const; + bool operator<=(const xml_attribute& r) const; + bool operator>=(const xml_attribute& r) const; + + // Check if attribute is empty + bool empty() const; + + // Get attribute name/value, or "" if attribute is empty + const char_t* name() const; + const char_t* value() const; + + // Get attribute value as a number, or 0 if conversion did not succeed or attribute is empty + int as_int() const; + unsigned int as_uint() const; + double as_double() const; + float as_float() const; + + // Get attribute value as bool (returns true if first character is in '1tTyY' set), or false if attribute is empty + bool as_bool() const; + + // Set attribute name/value (returns false if attribute is empty or there is not enough memory) + bool set_name(const char_t* rhs); + bool set_value(const char_t* rhs); + + // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") + bool set_value(int rhs); + bool set_value(unsigned int rhs); + bool set_value(double rhs); + bool set_value(bool rhs); + + // Set attribute value (equivalent to set_value without error checking) + xml_attribute& operator=(const char_t* rhs); + xml_attribute& operator=(int rhs); + xml_attribute& operator=(unsigned int rhs); + xml_attribute& operator=(double rhs); + xml_attribute& operator=(bool rhs); + + // Get next/previous attribute in the attribute list of the parent node + xml_attribute next_attribute() const; + xml_attribute previous_attribute() const; + + // Get hash value (unique for handles to the same object) + size_t hash_value() const; + + // Get internal pointer + xml_attribute_struct* internal_object() const; + }; + +#ifdef __BORLANDC__ + // Borland C++ workaround + bool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs); + bool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs); +#endif + + // A light-weight handle for manipulating nodes in DOM tree + class PUGIXML_CLASS xml_node + { + friend class xml_attribute_iterator; + friend class xml_node_iterator; + + protected: + xml_node_struct* _root; + + typedef xml_node_struct* xml_node::*unspecified_bool_type; + + public: + // Default constructor. Constructs an empty node. + xml_node(); + + // Constructs node from internal pointer + explicit xml_node(xml_node_struct* p); + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + + // Comparison operators (compares wrapped node pointers) + bool operator==(const xml_node& r) const; + bool operator!=(const xml_node& r) const; + bool operator<(const xml_node& r) const; + bool operator>(const xml_node& r) const; + bool operator<=(const xml_node& r) const; + bool operator>=(const xml_node& r) const; + + // Check if node is empty. + bool empty() const; + + // Get node type + xml_node_type type() const; + + // Get node name/value, or "" if node is empty or it has no name/value + const char_t* name() const; + const char_t* value() const; + + // Get attribute list + xml_attribute first_attribute() const; + xml_attribute last_attribute() const; + + // Get children list + xml_node first_child() const; + xml_node last_child() const; + + // Get next/previous sibling in the children list of the parent node + xml_node next_sibling() const; + xml_node previous_sibling() const; + + // Get parent node + xml_node parent() const; + + // Get root of DOM tree this node belongs to + xml_node root() const; + + // Get child, attribute or next/previous sibling with the specified name + xml_node child(const char_t* name) const; + xml_attribute attribute(const char_t* name) const; + xml_node next_sibling(const char_t* name) const; + xml_node previous_sibling(const char_t* name) const; + + // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA + const char_t* child_value() const; + + // Get child value of child with specified name. Equivalent to child(name).child_value(). + const char_t* child_value(const char_t* name) const; + + // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) + bool set_name(const char_t* rhs); + bool set_value(const char_t* rhs); + + // Add attribute with specified name. Returns added attribute, or empty attribute on errors. + xml_attribute append_attribute(const char_t* name); + xml_attribute prepend_attribute(const char_t* name); + xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr); + xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr); + + // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. + xml_attribute append_copy(const xml_attribute& proto); + xml_attribute prepend_copy(const xml_attribute& proto); + xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr); + xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr); + + // Add child node with specified type. Returns added node, or empty node on errors. + xml_node append_child(xml_node_type type = node_element); + xml_node prepend_child(xml_node_type type = node_element); + xml_node insert_child_after(xml_node_type type, const xml_node& node); + xml_node insert_child_before(xml_node_type type, const xml_node& node); + + // Add child element with specified name. Returns added node, or empty node on errors. + xml_node append_child(const char_t* name); + xml_node prepend_child(const char_t* name); + xml_node insert_child_after(const char_t* name, const xml_node& node); + xml_node insert_child_before(const char_t* name, const xml_node& node); + + // Add a copy of the specified node as a child. Returns added node, or empty node on errors. + xml_node append_copy(const xml_node& proto); + xml_node prepend_copy(const xml_node& proto); + xml_node insert_copy_after(const xml_node& proto, const xml_node& node); + xml_node insert_copy_before(const xml_node& proto, const xml_node& node); + + // Remove specified attribute + bool remove_attribute(const xml_attribute& a); + bool remove_attribute(const char_t* name); + + // Remove specified child + bool remove_child(const xml_node& n); + bool remove_child(const char_t* name); + + // Find attribute using predicate. Returns first attribute for which predicate returned true. + template <typename Predicate> xml_attribute find_attribute(Predicate pred) const + { + if (!_root) return xml_attribute(); + + for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute()) + if (pred(attrib)) + return attrib; + + return xml_attribute(); + } + + // Find child node using predicate. Returns first child for which predicate returned true. + template <typename Predicate> xml_node find_child(Predicate pred) const + { + if (!_root) return xml_node(); + + for (xml_node node = first_child(); node; node = node.next_sibling()) + if (pred(node)) + return node; + + return xml_node(); + } + + // Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true. + template <typename Predicate> xml_node find_node(Predicate pred) const + { + if (!_root) return xml_node(); + + xml_node cur = first_child(); + + while (cur._root && cur._root != _root) + { + if (pred(cur)) return cur; + + if (cur.first_child()) cur = cur.first_child(); + else if (cur.next_sibling()) cur = cur.next_sibling(); + else + { + while (!cur.next_sibling() && cur._root != _root) cur = cur.parent(); + + if (cur._root != _root) cur = cur.next_sibling(); + } + } + + return xml_node(); + } + + // Find child node by attribute name/value + xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const; + xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const; + + #ifndef PUGIXML_NO_STL + // Get the absolute node path from root as a text string. + string_t path(char_t delimiter = '/') const; + #endif + + // Search for a node by path consisting of node names and . or .. elements. + xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const; + + // Recursively traverse subtree with xml_tree_walker + bool traverse(xml_tree_walker& walker); + + #ifndef PUGIXML_NO_XPATH + // Select single node by evaluating XPath query. Returns first node from the resulting node set. + xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; + xpath_node select_single_node(const xpath_query& query) const; + + // Select node set by evaluating XPath query + xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const; + xpath_node_set select_nodes(const xpath_query& query) const; + #endif + + // Print subtree using a writer object + void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; + + #ifndef PUGIXML_NO_STL + // Print subtree to stream + void print(std::basic_ostream<char, std::char_traits<char> >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; + void print(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const; + #endif + + // Child nodes iterators + typedef xml_node_iterator iterator; + + iterator begin() const; + iterator end() const; + + // Attribute iterators + typedef xml_attribute_iterator attribute_iterator; + + attribute_iterator attributes_begin() const; + attribute_iterator attributes_end() const; + + // Get node offset in parsed file/string (in char_t units) for debugging purposes + ptrdiff_t offset_debug() const; + + // Get hash value (unique for handles to the same object) + size_t hash_value() const; + + // Get internal pointer + xml_node_struct* internal_object() const; + }; + +#ifdef __BORLANDC__ + // Borland C++ workaround + bool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs); + bool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs); +#endif + + // Child node iterator (a bidirectional iterator over a collection of xml_node) + class PUGIXML_CLASS xml_node_iterator + { + friend class xml_node; + + private: + xml_node _wrap; + xml_node _parent; + + xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent); + + public: + // Iterator traits + typedef ptrdiff_t difference_type; + typedef xml_node value_type; + typedef xml_node* pointer; + typedef xml_node& reference; + + #ifndef PUGIXML_NO_STL + typedef std::bidirectional_iterator_tag iterator_category; + #endif + + // Default constructor + xml_node_iterator(); + + // Construct an iterator which points to the specified node + xml_node_iterator(const xml_node& node); + + // Iterator operators + bool operator==(const xml_node_iterator& rhs) const; + bool operator!=(const xml_node_iterator& rhs) const; + + xml_node& operator*(); + xml_node* operator->(); + + const xml_node_iterator& operator++(); + xml_node_iterator operator++(int); + + const xml_node_iterator& operator--(); + xml_node_iterator operator--(int); + }; + + // Attribute iterator (a bidirectional iterator over a collection of xml_attribute) + class PUGIXML_CLASS xml_attribute_iterator + { + friend class xml_node; + + private: + xml_attribute _wrap; + xml_node _parent; + + xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent); + + public: + // Iterator traits + typedef ptrdiff_t difference_type; + typedef xml_attribute value_type; + typedef xml_attribute* pointer; + typedef xml_attribute& reference; + + #ifndef PUGIXML_NO_STL + typedef std::bidirectional_iterator_tag iterator_category; + #endif + + // Default constructor + xml_attribute_iterator(); + + // Construct an iterator which points to the specified attribute + xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent); + + // Iterator operators + bool operator==(const xml_attribute_iterator& rhs) const; + bool operator!=(const xml_attribute_iterator& rhs) const; + + xml_attribute& operator*(); + xml_attribute* operator->(); + + const xml_attribute_iterator& operator++(); + xml_attribute_iterator operator++(int); + + const xml_attribute_iterator& operator--(); + xml_attribute_iterator operator--(int); + }; + + // Abstract tree walker class (see xml_node::traverse) + class PUGIXML_CLASS xml_tree_walker + { + friend class xml_node; + + private: + int _depth; + + protected: + // Get current traversal depth + int depth() const; + + public: + xml_tree_walker(); + virtual ~xml_tree_walker(); + + // Callback that is called when traversal begins + virtual bool begin(xml_node& node); + + // Callback that is called for each node traversed + virtual bool for_each(xml_node& node) = 0; + + // Callback that is called when traversal ends + virtual bool end(xml_node& node); + }; + + // Parsing status, returned as part of xml_parse_result object + enum xml_parse_status + { + status_ok = 0, // No error + + status_file_not_found, // File was not found during load_file() + status_io_error, // Error reading from file/stream + status_out_of_memory, // Could not allocate memory + status_internal_error, // Internal error occurred + + status_unrecognized_tag, // Parser could not determine tag type + + status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction + status_bad_comment, // Parsing error occurred while parsing comment + status_bad_cdata, // Parsing error occurred while parsing CDATA section + status_bad_doctype, // Parsing error occurred while parsing document type declaration + status_bad_pcdata, // Parsing error occurred while parsing PCDATA section + status_bad_start_element, // Parsing error occurred while parsing start element tag + status_bad_attribute, // Parsing error occurred while parsing element attribute + status_bad_end_element, // Parsing error occurred while parsing end element tag + status_end_element_mismatch // There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag) + }; + + // Parsing result + struct PUGIXML_CLASS xml_parse_result + { + // Parsing status (see xml_parse_status) + xml_parse_status status; + + // Last parsed offset (in char_t units from start of input data) + ptrdiff_t offset; + + // Source document encoding + xml_encoding encoding; + + // Default constructor, initializes object to failed state + xml_parse_result(); + + // Cast to bool operator + operator bool() const; + + // Get error description + const char* description() const; + }; + + // Document class (DOM tree root) + class PUGIXML_CLASS xml_document: public xml_node + { + private: + char_t* _buffer; + + char _memory[192]; + + // Non-copyable semantics + xml_document(const xml_document&); + const xml_document& operator=(const xml_document&); + + void create(); + void destroy(); + + xml_parse_result load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own); + + public: + // Default constructor, makes empty document + xml_document(); + + // Destructor, invalidates all node/attribute handles to this document + ~xml_document(); + + // Removes all nodes, leaving the empty document + void reset(); + + // Removes all nodes, then copies the entire contents of the specified document + void reset(const xml_document& proto); + + #ifndef PUGIXML_NO_STL + // Load document from stream. + xml_parse_result load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + xml_parse_result load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options = parse_default); + #endif + + // Load document from zero-terminated string. No encoding conversions are applied. + xml_parse_result load(const char_t* contents, unsigned int options = parse_default); + + // Load document from file + xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns. + xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). + // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed. + xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). + // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore). + xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details). + void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + + #ifndef PUGIXML_NO_STL + // Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details). + void save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + void save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const; + #endif + + // Save XML to file + bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + + // Get document element + xml_node document_element() const; + }; + +#ifndef PUGIXML_NO_XPATH + // XPath query return type + enum xpath_value_type + { + xpath_type_none, // Unknown type (query failed to compile) + xpath_type_node_set, // Node set (xpath_node_set) + xpath_type_number, // Number + xpath_type_string, // String + xpath_type_boolean // Boolean + }; + + // XPath parsing result + struct PUGIXML_CLASS xpath_parse_result + { + // Error message (0 if no error) + const char* error; + + // Last parsed offset (in char_t units from string start) + ptrdiff_t offset; + + // Default constructor, initializes object to failed state + xpath_parse_result(); + + // Cast to bool operator + operator bool() const; + + // Get error description + const char* description() const; + }; + + // A single XPath variable + class PUGIXML_CLASS xpath_variable + { + friend class xpath_variable_set; + + protected: + xpath_value_type _type; + xpath_variable* _next; + + xpath_variable(); + + // Non-copyable semantics + xpath_variable(const xpath_variable&); + xpath_variable& operator=(const xpath_variable&); + + public: + // Get variable name + const char_t* name() const; + + // Get variable type + xpath_value_type type() const; + + // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error + bool get_boolean() const; + double get_number() const; + const char_t* get_string() const; + const xpath_node_set& get_node_set() const; + + // Set variable value; no type conversion is performed, false is returned on type mismatch error + bool set(bool value); + bool set(double value); + bool set(const char_t* value); + bool set(const xpath_node_set& value); + }; + + // A set of XPath variables + class PUGIXML_CLASS xpath_variable_set + { + private: + xpath_variable* _data[64]; + + // Non-copyable semantics + xpath_variable_set(const xpath_variable_set&); + xpath_variable_set& operator=(const xpath_variable_set&); + + xpath_variable* find(const char_t* name) const; + + public: + // Default constructor/destructor + xpath_variable_set(); + ~xpath_variable_set(); + + // Add a new variable or get the existing one, if the types match + xpath_variable* add(const char_t* name, xpath_value_type type); + + // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch + bool set(const char_t* name, bool value); + bool set(const char_t* name, double value); + bool set(const char_t* name, const char_t* value); + bool set(const char_t* name, const xpath_node_set& value); + + // Get existing variable by name + xpath_variable* get(const char_t* name); + const xpath_variable* get(const char_t* name) const; + }; + + // A compiled XPath query object + class PUGIXML_CLASS xpath_query + { + private: + void* _impl; + xpath_parse_result _result; + + typedef void* xpath_query::*unspecified_bool_type; + + // Non-copyable semantics + xpath_query(const xpath_query&); + xpath_query& operator=(const xpath_query&); + + public: + // Construct a compiled object from XPath expression. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors. + explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0); + + // Destructor + ~xpath_query(); + + // Get query expression return type + xpath_value_type return_type() const; + + // Evaluate expression as boolean value in the specified context; performs type conversion if necessary. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + bool evaluate_boolean(const xpath_node& n) const; + + // Evaluate expression as double value in the specified context; performs type conversion if necessary. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + double evaluate_number(const xpath_node& n) const; + + #ifndef PUGIXML_NO_STL + // Evaluate expression as string value in the specified context; performs type conversion if necessary. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + string_t evaluate_string(const xpath_node& n) const; + #endif + + // Evaluate expression as string value in the specified context; performs type conversion if necessary. + // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero). + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + // If PUGIXML_NO_EXCEPTIONS is defined, returns empty set instead. + size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const; + + // Evaluate expression as node set in the specified context. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. + // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead. + xpath_node_set evaluate_node_set(const xpath_node& n) const; + + // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode) + const xpath_parse_result& result() const; + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + }; + + #ifndef PUGIXML_NO_EXCEPTIONS + // XPath exception class + class PUGIXML_CLASS xpath_exception: public std::exception + { + private: + xpath_parse_result _result; + + public: + // Construct exception from parse result + explicit xpath_exception(const xpath_parse_result& result); + + // Get error message + virtual const char* what() const throw(); + + // Get parse result + const xpath_parse_result& result() const; + }; + #endif + + // XPath node class (either xml_node or xml_attribute) + class PUGIXML_CLASS xpath_node + { + private: + xml_node _node; + xml_attribute _attribute; + + typedef xml_node xpath_node::*unspecified_bool_type; + + public: + // Default constructor; constructs empty XPath node + xpath_node(); + + // Construct XPath node from XML node/attribute + xpath_node(const xml_node& node); + xpath_node(const xml_attribute& attribute, const xml_node& parent); + + // Get node/attribute, if any + xml_node node() const; + xml_attribute attribute() const; + + // Get parent of contained node/attribute + xml_node parent() const; + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + + // Comparison operators + bool operator==(const xpath_node& n) const; + bool operator!=(const xpath_node& n) const; + }; + +#ifdef __BORLANDC__ + // Borland C++ workaround + bool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs); + bool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs); +#endif + + // A fixed-size collection of XPath nodes + class PUGIXML_CLASS xpath_node_set + { + public: + // Collection type + enum type_t + { + type_unsorted, // Not ordered + type_sorted, // Sorted by document order (ascending) + type_sorted_reverse // Sorted by document order (descending) + }; + + // Constant iterator type + typedef const xpath_node* const_iterator; + + // Default constructor. Constructs empty set. + xpath_node_set(); + + // Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful + xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted); + + // Destructor + ~xpath_node_set(); + + // Copy constructor/assignment operator + xpath_node_set(const xpath_node_set& ns); + xpath_node_set& operator=(const xpath_node_set& ns); + + // Get collection type + type_t type() const; + + // Get collection size + size_t size() const; + + // Indexing operator + const xpath_node& operator[](size_t index) const; + + // Collection iterators + const_iterator begin() const; + const_iterator end() const; + + // Sort the collection in ascending/descending order by document order + void sort(bool reverse = false); + + // Get first node in the collection by document order + xpath_node first() const; + + // Check if collection is empty + bool empty() const; + + private: + type_t _type; + + xpath_node _storage; + + xpath_node* _begin; + xpath_node* _end; + + void _assign(const_iterator begin, const_iterator end); + }; +#endif + +#ifndef PUGIXML_NO_STL + // Convert wide string to UTF8 + std::basic_string<char, std::char_traits<char>, std::allocator<char> > PUGIXML_FUNCTION as_utf8(const wchar_t* str); + std::basic_string<char, std::char_traits<char>, std::allocator<char> > PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >& str); + + // Convert UTF8 to wide string + std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > PUGIXML_FUNCTION as_wide(const char* str); + std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > PUGIXML_FUNCTION as_wide(const std::basic_string<char, std::char_traits<char>, std::allocator<char> >& str); +#endif + + // Memory allocation function interface; returns pointer to allocated memory or NULL on failure + typedef void* (*allocation_function)(size_t size); + + // Memory deallocation function interface + typedef void (*deallocation_function)(void* ptr); + + // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions. + void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate); + + // Get current memory management functions + allocation_function PUGIXML_FUNCTION get_memory_allocation_function(); + deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function(); +} + +#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) +namespace std +{ + // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) + std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&); + std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&); +} +#endif + +#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) +namespace std +{ + // Workarounds for (non-standard) iterator category detection + std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&); + std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&); +} +#endif + +#endif + +/** + * Copyright (c) 2006-2010 Arseny Kapoulkine + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ diff --git a/extensions/time/ExtendedRosenbrockAdaptInstationary.h b/extensions/time/ExtendedRosenbrockAdaptInstationary.h new file mode 100644 index 0000000000000000000000000000000000000000..d41c6e5d241f6e778ca32b7e8e4636ebb2e6be65 --- /dev/null +++ b/extensions/time/ExtendedRosenbrockAdaptInstationary.h @@ -0,0 +1,131 @@ +// ============================================================================ +// == == +// == AMDiS - Adaptive multidimensional simulations == +// == == +// == http://www.amdis-fem.org == +// == == +// ============================================================================ +// +// Software License for AMDiS +// +// Copyright (c) 2010 Dresden University of Technology +// All rights reserved. +// Authors: Simon Vey, Thomas Witkowski et al. +// +// This file is part of AMDiS +// +// See also license.opensource.txt in the distribution. + + + +/** \file ExtendedRosenbrockAdaptInstationary.h */ + +#ifndef MY_ROSENBROCKADAPTINSTATIONARY_H +#define MY_ROSENBROCKADAPTINSTATIONARY_H + +#include "AMDiS_fwd.h" +#include "time/RosenbrockMethod.h" +#include "AdaptInstationary.h" +#include "CreatorMap.h" + +namespace AMDiS { + + template<typename ProblemStationary> + class ExtendedRosenbrockAdaptInstationary : public AdaptInstationary + { + public: + /** \brief + * Creates a AdaptInstationary object for Rosenbrock method + * with the given name for the time + * dependent problem problemInstat. TODO: Make obsolete! + */ + ExtendedRosenbrockAdaptInstationary(std::string name, + ProblemStationary *problemStat, + AdaptInfo *info, + ProblemTimeInterface *problemInstat, + AdaptInfo *initialInfo, + time_t initialTimestamp = 0); + + /** \brief + * Creates a AdaptInstationary object for Rosenbrock method + * with the given name for the time + * dependent problem problemInstat. + */ + ExtendedRosenbrockAdaptInstationary(std::string name, + ProblemStationary &problemStat, + AdaptInfo &info, + ProblemTimeInterface &problemInstat, + AdaptInfo &initialInfo, + time_t initialTimestamp = 0); + + /// Runs the Rosenbrock loop until one timestep is accepted. + void oneTimestep(); + + /** \brief + * This funciton is used only to avoid double code in both constructors. If the + * obsolte constructure, which uses pointers instead of references, will be + * removed, remove also this function. + * TODO: Remove if obsolete constructor will be removed. + */ + void initConstructor(ProblemStationary *problemStat); + + void reset(); + + protected: + /// Pointer to the Rosenbrock method that should be used. + RosenbrockMethod *rosenbrockMethod; + + /// Pointer to the stationary problem; + ProblemStationary *rosenbrockStat; + + /// Indicates, if this is the very first timestep. + bool firstTimestep; + + /// If true, the last timestep was rejected. + bool lastTimestepRejected; + + + /// If true, more than one of the last timesteps were rejected. + bool succRejection; + + /// If greater than 0, than for the first given number of timesteps the timestep + /// will be not changed and is set to the very first one. + int fixFirstTimesteps; + + /// Timestep of the last accepted time iteration. + double tauAcc; + + /// Error estimation of the last accepted time iteration. + double estAcc; + + /// Timestep of the last rejected time iteration. + double tauRej; + + /// Error estimation of the last rejected time iteration. + double estRej; + + /// Current timestep. + double tau; + + /// The value tau * gamma, where gamma is a value of the used + /// Rosenbrock method. + double tauGamma, minusTauGamma, invTauGamma, minusInvTauGamma; + + /// If true, the first timestep is calculated with different timesteps. + /// This is usually used to make a study how the time error estimator + /// behavous for different timesteps. + bool dbgTimestepStudy; + + /// If \ref dbgTimestepStudy is set to true, then this array contains the + /// timesteps for which the first timestep should be calculated. + vector<double> dbgTimesteps; + + vector<double> errorEstWeights; + + }; + +} + +#include "ExtendedRosenbrockAdaptInstationary.hh" + +#endif // MY_ROSENBROCKADAPTINSTATIONARY_H diff --git a/extensions/time/ExtendedRosenbrockAdaptInstationary.hh b/extensions/time/ExtendedRosenbrockAdaptInstationary.hh new file mode 100644 index 0000000000000000000000000000000000000000..7a4192fdd84eba96ae1095552193922c600ec603 --- /dev/null +++ b/extensions/time/ExtendedRosenbrockAdaptInstationary.hh @@ -0,0 +1,273 @@ +// +// Software License for AMDiS +// +// Copyright (c) 2010 Dresden University of Technology +// All rights reserved. +// Authors: Simon Vey, Thomas Witkowski et al. +// +// This file is part of AMDiS +// +// See also license.opensource.txt in the distribution. + + +#include "time/ExtendedRosenbrockAdaptInstationary.h" +#include "AdaptInfo.h" +#include "ProblemTimeInterface.h" +#include "VectorOperations.h" + +namespace AMDiS { + + template<typename ProblemStationary> + ExtendedRosenbrockAdaptInstationary<ProblemStationary>::ExtendedRosenbrockAdaptInstationary(std::string name, + ProblemStationary *problemStat, + AdaptInfo *info, + ProblemTimeInterface *problemInstat, + AdaptInfo *initialInfo, + time_t initialTimestamp) + : AdaptInstationary(name, problemStat, info, problemInstat, initialInfo, initialTimestamp), + rosenbrockStat(problemStat), + firstTimestep(true), + lastTimestepRejected(false), + succRejection(false), + fixFirstTimesteps(0), + tau(1.0), + tauGamma(1.0), + minusTauGamma(-1.0), + invTauGamma(1.0), + minusInvTauGamma(-1.0), + dbgTimestepStudy(false) + { + FUNCNAME("ExtendedRosenbrockAdaptInstationary::ExtendedRosenbrockAdaptInstationary()"); + initConstructor(problemStat); + } + + + template<typename ProblemStationary> + ExtendedRosenbrockAdaptInstationary<ProblemStationary>::ExtendedRosenbrockAdaptInstationary(std::string name, + ProblemStationary &problemStat, + AdaptInfo &info, + ProblemTimeInterface &problemInstat, + AdaptInfo &initialInfo, + time_t initialTimestamp) + : AdaptInstationary(name, problemStat, info, problemInstat, initialInfo, initialTimestamp), + rosenbrockStat(&problemStat), + firstTimestep(true), + lastTimestepRejected(false), + succRejection(false), + fixFirstTimesteps(0), + tau(1.0), + tauGamma(1.0), + minusTauGamma(-1.0), + invTauGamma(1.0), + minusInvTauGamma(-1.0), + dbgTimestepStudy(false) + { + FUNCNAME("ExtendedRosenbrockAdaptInstationary::ExtendedRosenbrockAdaptInstationary()"); + initConstructor(&problemStat); + } + + + template<typename ProblemStationary> + void ExtendedRosenbrockAdaptInstationary<ProblemStationary>::initConstructor(ProblemStationary *problemStat) + { + FUNCNAME("ExtendedRosenbrockAdaptInstationary::initConstructor()"); + + std::string str(""); + std::string initFileStr(name + "->rosenbrock method"); + Parameters::get(initFileStr, str); + RosenbrockMethodCreator *creator = + dynamic_cast<RosenbrockMethodCreator*>(CreatorMap<RosenbrockMethod>::getCreator(str, initFileStr)); + rosenbrockMethod = creator->create(); + + TEST_EXIT_DBG(rosenbrockMethod)("This should not happen!\n"); + + Parameters::get(name + "->fix first timesteps", fixFirstTimesteps); + rosenbrockStat->setRosenbrockMethod(rosenbrockMethod); + + adaptInfo->setRosenbrockMode(true); + + rosenbrockStat->setTauGamma(&tauGamma, &minusTauGamma, + &invTauGamma, &minusInvTauGamma); + rosenbrockStat->setTau(&tau); + + Parameters::get(name + "->rosenbrock->timestep study", dbgTimestepStudy); + Parameters::get(name + "->rosenbrock->timestep study steps", dbgTimesteps); + + Parameters::get(name + "->rosenbrock->error weights", errorEstWeights); + if (errorEstWeights.size() == 0) { + WARNING("No weights for time-error estimation given.\n"); + } + + errorEstWeights.resize(adaptInfo->getSize(), 0.0); + double SumErrorEstWeights = vector_operations::sum(errorEstWeights); + if (SumErrorEstWeights<DBL_TOL) { + WARNING("Using equal weights for all components!\n"); + for (size_t i = 0; i < errorEstWeights.size(); i++) + errorEstWeights[i] = 1.0/static_cast<double>(adaptInfo->getSize()); + } else { + for (size_t i = 0; i < errorEstWeights.size(); i++) + errorEstWeights[i] *= 1.0/SumErrorEstWeights; + } + } + + + template<typename ProblemStationary> + void ExtendedRosenbrockAdaptInstationary<ProblemStationary>::reset() + { + FUNCNAME("ExtendedRosenbrockAdaptInstationary::reset()"); + + firstTimestep = true; + lastTimestepRejected = false; + succRejection = false; + fixFirstTimesteps = 0; + tau = 1.0; + tauGamma = 1.0; + minusTauGamma = -1.0; + invTauGamma = 1.0; + minusInvTauGamma = -1.0; + } + + + template<typename ProblemStationary> + void ExtendedRosenbrockAdaptInstationary<ProblemStationary>::oneTimestep() + { + FUNCNAME("ExtendedRosenbrockAdaptInstationary::oneTimestep()"); + + // estimate before first adaption + if (adaptInfo->getTime() <= adaptInfo->getStartTime()) + problemIteration->oneIteration(adaptInfo, ESTIMATE); + + bool rejected = false; + double timeTol = adaptInfo->getTimeTolerance(0); + + int studyTimestep = -1; + + do { + if (dbgTimestepStudy) { + if (studyTimestep >= 0) + adaptInfo->setTime(adaptInfo->getTime() - dbgTimesteps[studyTimestep]); + + studyTimestep++; + TEST_EXIT(studyTimestep < dbgTimesteps.size())("Should not happen!\n"); + + adaptInfo->setTimestep(dbgTimesteps[studyTimestep]); + } + + // increment time + adaptInfo->setTime(adaptInfo->getTime() + adaptInfo->getTimestep()); + problemTime->setTime(adaptInfo); + tau = adaptInfo->getTimestep(); + + tauGamma = tau * rosenbrockMethod->getGamma(); + minusTauGamma = -tauGamma; + invTauGamma = 1.0 / (tau * rosenbrockMethod->getGamma()); + minusInvTauGamma = -1.0; + + INFO(info, 6)("time = %e timestep = %e\n", + adaptInfo->getTime(), adaptInfo->getTimestep()); + + adaptInfo->setSpaceIteration(0); + + // do the iteration + problemIteration->beginIteration(adaptInfo); + problemIteration->oneIteration(adaptInfo, FULL_ITERATION); + problemIteration->endIteration(adaptInfo); + + double errorEst = 0.0; + for (size_t i = 0; i < adaptInfo->getSize(); i++) { + errorEst += errorEstWeights[i] * adaptInfo->getTimeEstSum(i); + } + + double newTimestep = 0.0; + double order = rosenbrockMethod->getOrder(); + + if (errorEst < timeTol || fixFirstTimesteps > 0 || firstTimestep) { + double fac = 1.0; + + if (fixFirstTimesteps > 0) { + newTimestep = adaptInfo->getTimestep(); + } else { + if (firstTimestep || succRejection) { + fac = pow((timeTol / errorEst), 1.0 / order); + } else { + fac = adaptInfo->getTimestep() / tauAcc * + pow((timeTol * estAcc / (errorEst * errorEst)), 1.0 / order); + } + fac = std::min(fac, 3.0); + newTimestep = fac * adaptInfo->getTimestep(); + newTimestep *= 0.95; + } + + tauAcc = adaptInfo->getTimestep(); + estAcc = errorEst; + + lastTimestepRejected = false; + succRejection = false; + } else { + if (lastTimestepRejected) { + succRejection = true; + + double reducedP = + log(errorEst / estRej) / log(adaptInfo->getTimestep() / tauRej); + + if (reducedP < order && reducedP > 0.0) + order = reducedP; + } + + newTimestep = pow((timeTol / errorEst), 1.0 / order) * adaptInfo->getTimestep(); + newTimestep *= 0.95; + + tauRej = adaptInfo->getTimestep(); + estRej = errorEst; + + lastTimestepRejected = true; + } + + + if (errorEst < timeTol || fixFirstTimesteps + || !(adaptInfo->getTimestep()>adaptInfo->getMinTimestep()) ) { + INFO(info, 6)("Accepted timestep at time = %e with timestep = %e\n", + adaptInfo->getTime() - adaptInfo->getTimestep(), + adaptInfo->getTimestep()); + + adaptInfo->setTimestep(newTimestep); + + rejected = false; + + for (int i = 0; i < adaptInfo->getSize(); i++) + INFO(info, 6)("time estimate for component %d = %e\n", + i, adaptInfo->getTimeEstSum(i)); + + if (errorEst > timeTol) + MSG("Accepted timestep but tolerance not reached \n"); + + } else { + for (int i = 0; i < adaptInfo->getSize(); i++) + INFO(info, 6)("time estimate for component %d = %e\n", + i, adaptInfo->getTimeEstSum(i)); + + INFO(info, 6)("Rejected timestep at time = %e with timestep = %e\n", + adaptInfo->getTime() - adaptInfo->getTimestep(), + adaptInfo->getTimestep()); + + adaptInfo->setTime(adaptInfo->getTime() - adaptInfo->getTimestep()); + adaptInfo->setTimestep(newTimestep); + + rejected = true; + } + + if (firstTimestep) + firstTimestep = false; + + if (fixFirstTimesteps > 0) + fixFirstTimesteps--; + } while (rejected || + (dbgTimestepStudy && (studyTimestep + 1 < dbgTimesteps.size()))); + + rosenbrockStat->acceptTimestep(); + + adaptInfo->setLastProcessedTimestep(adaptInfo->getTimestep()); + adaptInfo->incTimestepNumber(); + } + +} diff --git a/extensions/time/ExtendedRosenbrockStationary.cc b/extensions/time/ExtendedRosenbrockStationary.cc new file mode 100644 index 0000000000000000000000000000000000000000..e8c5db1028c6aeebfe93d6aa25b97f88ffd15765 --- /dev/null +++ b/extensions/time/ExtendedRosenbrockStationary.cc @@ -0,0 +1,232 @@ +// +// Software License for AMDiS +// +// Copyright (c) 2010 Dresden University of Technology +// All rights reserved. +// Authors: Simon Vey, Thomas Witkowski et al. +// +// This file is part of AMDiS +// +// See also license.opensource.txt in the distribution. + + +#include "time/ExtendedRosenbrockStationary.h" +#include "io/VtkWriter.h" +#include "ExtendedRosenbrockStationary.h" +#include "SystemVector.h" +#include "OEMSolver.h" +#include "Debug.h" + +#ifdef HAVE_PARALLEL_DOMAIN_AMDIS +#include "parallel/MeshDistributor.h" +#endif + +using namespace AMDiS; + + void ExtendedRosenbrockStationary::acceptTimestep() + { + *solution = *newUn; + *unVec = *newUn; + } + + + void ExtendedRosenbrockStationary::init() + { + stageSolution = new SystemVector(*solution); + unVec = new SystemVector(*solution); + timeRhsVec = new SystemVector(*solution); + newUn = new SystemVector(*solution); + tmp = new SystemVector(*solution); + lowSol = new SystemVector(*solution); + + stageSolution->set(0.0); + unVec->set(0.0); + + stageSolutions.resize(rm->getStages()); + for (int i = 0; i < rm->getStages(); i++) { + stageSolutions[i] = new SystemVector(*solution); + stageSolutions[i]->set(0.0); + } + } + + + void ExtendedRosenbrockStationary::buildAfterCoarsen(AdaptInfo *adaptInfo, Flag flag, + bool asmMatrix, bool asmVector) + { + FUNCNAME("ExtendedRosenbrockStationary::buildAfterCoarsen()"); + + TEST_EXIT(tauPtr)("No tau pointer defined in stationary problem!\n"); + + if (first) { + first = false; + *unVec = *solution; + } + + *newUn = *unVec; + *lowSol = *unVec; + + for (int i = 0; i < rm->getStages(); i++) { + *stageSolution = *unVec; + for (int j = 0; j < i; j++) { + *tmp = *(stageSolutions[j]); + *tmp *= rm->getA(i, j); + *stageSolution += *tmp; + } + + for (unsigned int j = 0; j < boundaries.size(); j++) { + boundaries[j].vec->interpol(boundaries[j].fct); + *(boundaries[j].vec) -= *(stageSolution->getDOFVector(boundaries[j].row)); + } + + timeRhsVec->set(0.0); + for (int j = 0; j < i; j++) { + *tmp = *(stageSolutions[j]); + *tmp *= (rm->getC(i, j) / *tauPtr); + *timeRhsVec += *tmp; + } + + super::buildAfterCoarsen(adaptInfo, flag | UPDATE_DIRICHLET_BC, (i == 0), asmVector); + super::solve(adaptInfo, i == 0, i + 1 < rm->getStages()); + + *(stageSolutions[i]) = *solution; + + *tmp = *solution; + *tmp *= rm->getM1(i); + + *newUn += *tmp; + + *tmp = *solution; + *tmp *= rm->getM2(i); + *lowSol += *tmp; + } + + for (int i = 0; i < nComponents; i++) { + (*(lowSol->getDOFVector(i))) -= (*(newUn->getDOFVector(i))); + adaptInfo->setTimeEstSum(lowSol->getDOFVector(i)->l2norm(), i+componentShift); + } + } + + + void ExtendedRosenbrockStationary::solve(AdaptInfo *adaptInfo, bool, bool) + {} + + + void ExtendedRosenbrockStationary::addOperator(Operator &op, int row, int col, + double *factor, double *estFactor) + { + FUNCNAME("ExtendedRosenbrockStationary::addOperator()"); + + TEST_EXIT(op.getUhOld() == NULL)("UhOld is not allowed to be set!\n"); + + op.setUhOld(stageSolution->getDOFVector(col)); + super::addVectorOperator(op, row, factor, estFactor); + } + + + void ExtendedRosenbrockStationary::addJacobianOperator(Operator &op, int row, int col, + double *factor, double *estFactor) + { + FUNCNAME("ExtendedRosenbrockStationary::addJacobianOperator()"); + + TEST_EXIT(factor == NULL)("Not yet implemented!\n"); + TEST_EXIT(estFactor == NULL)("Not yet implemented!\n"); + + super::addMatrixOperator(op, row, col, &minusOne, &minusOne); + } + + + void ExtendedRosenbrockStationary::addTimeOperator(int row, int col) + { + FUNCNAME("ExtendedRosenbrockStationary::addTimeOperator()"); + + TEST_EXIT(invTauGamma)("This should not happen!\n"); + + Operator *op = new Operator(componentSpaces[row], componentSpaces[col]); + op->addZeroOrderTerm(new Simple_ZOT); + super::addMatrixOperator(op, row, col, invTauGamma, invTauGamma); + + Operator *opRhs = new Operator(componentSpaces[row]); + opRhs->addZeroOrderTerm(new VecAtQP_ZOT(timeRhsVec->getDOFVector(col))); + super::addVectorOperator(opRhs, row, &minusOne, &minusOne); + } + + + void ExtendedRosenbrockStationary::addDirichletBC(BoundaryType type, int row, int col, + AbstractFunction<double, WorldVector<double> > *fct) + { + FUNCNAME("ExtendedRosenbrockStationary::addDirichletBC()"); + + DOFVector<double>* vec = new DOFVector<double>(componentSpaces[row], "vec"); + MyRosenbrockBoundary bound = {fct, vec, row, col}; + boundaries.push_back(bound); + + super::addDirichletBC(type, row, col, vec); + } + + + void ExtendedRosenbrockStationary::addSingularDirichletBC(WorldVector<double> &pos, int row, int col, + AbstractFunction<double, WorldVector<double> > &fct) + { + DOFVector<double>* vec = new DOFVector<double>(componentSpaces[row], "vec"); + MyRosenbrockBoundary bound = {&fct, vec, row, col}; + boundaries.push_back(bound); + + super::addSingularDirichletBC(pos, row, col, *vec); + } + + + void ExtendedRosenbrockStationary::addSingularDirichletBC(DegreeOfFreedom idx, int row, int col, + AbstractFunction<double, WorldVector<double> > &fct) + { + DOFVector<double>* vec = new DOFVector<double>(componentSpaces[row], "vec"); + MyRosenbrockBoundary bound = {&fct, vec, row, col}; + boundaries.push_back(bound); + + super::addSingularDirichletBC(idx, row, col, *vec); + } + + + void ExtendedRosenbrockStationary::addImplicitDirichletBC(AbstractFunction<double, WorldVector<double> > &signedDist, int row, int col, + AbstractFunction<double, WorldVector<double> > &fct) + { + DOFVector<double>* vec = new DOFVector<double>(componentSpaces[row], "vec"); + MyRosenbrockBoundary bound = {&fct, vec, row, col}; + boundaries.push_back(bound); + + super::addImplicitDirichletBC(signedDist, row, col, *vec); + } + + + void ExtendedRosenbrockStationary::addImplicitDirichletBC(DOFVector<double> &signedDist, int row, int col, + AbstractFunction<double, WorldVector<double> > &fct) + { + DOFVector<double>* vec = new DOFVector<double>(componentSpaces[row], "vec"); + MyRosenbrockBoundary bound = {&fct, vec, row, col}; + boundaries.push_back(bound); + + super::addImplicitDirichletBC(signedDist, row, col, *vec); + } + + + void ExtendedRosenbrockStationary::addManualDirichletBC(BoundaryType nr, AbstractFunction<bool, WorldVector<double> >* meshIndicator, + int row, int col, + AbstractFunction<double, WorldVector<double> > &fct) + { + DOFVector<double>* vec = new DOFVector<double>(componentSpaces[row], "vec"); + MyRosenbrockBoundary bound = {&fct, vec, row, col}; + boundaries.push_back(bound); + + super::addManualDirichletBC(nr, meshIndicator, row, col, *vec); + } + + + void ExtendedRosenbrockStationary::addManualDirichletBC(AbstractFunction<bool, WorldVector<double> >* meshIndicator, + int row, int col, + AbstractFunction<double, WorldVector<double> > &fct) + { + DOFVector<double>* vec = new DOFVector<double>(componentSpaces[row], "vec"); + MyRosenbrockBoundary bound = {&fct, vec, row, col}; + boundaries.push_back(bound); + + super::addManualDirichletBC(meshIndicator, row, col, *vec); + } diff --git a/extensions/time/ExtendedRosenbrockStationary.h b/extensions/time/ExtendedRosenbrockStationary.h new file mode 100644 index 0000000000000000000000000000000000000000..181eed911fd2b23bb3b6ad9a3210f49149ec3095 --- /dev/null +++ b/extensions/time/ExtendedRosenbrockStationary.h @@ -0,0 +1,250 @@ +// ============================================================================ +// == == +// == AMDiS - Adaptive multidimensional simulations == +// == == +// == http://www.amdis-fem.org == +// == == +// ============================================================================ +// +// Software License for AMDiS +// +// Copyright (c) 2010 Dresden University of Technology +// All rights reserved. +// Authors: Simon Vey, Thomas Witkowski et al. +// +// This file is part of AMDiS +// +// See also license.opensource.txt in the distribution. + + + +/** \file ExtendedRosenbrockStationary.h */ + +#ifndef MY_ROSENBROCKSTATIONARY_H +#define MY_ROSENBROCKSTATIONARY_H + +#include "AMDiS_fwd.h" +#include "ExtendedProblemStat.h" +#include "SystemVector.h" +#include "time/RosenbrockMethod.h" + +#ifdef HAVE_PARALLEL_DOMAIN_AMDIS +#ifdef HAVE_PARALLEL_MTL4 +#include "parallel/Mtl4Solver.h" +#else +#include "parallel/PetscProblemStat.h" +#endif +#endif + +using namespace AMDiS; + + struct MyRosenbrockBoundary + { + AbstractFunction<double, WorldVector<double> > *fct; + + DOFVector<double> *vec; + + int row; + + int col; + }; + + + class ExtendedRosenbrockStationary : public ExtendedProblemStat + { + public: // typedefs + typedef ExtendedProblemStat super; + + public: + ExtendedRosenbrockStationary(std::string name, int componentShift_ = 0) + : super(name), + componentShift(componentShift_), + first(true), + minusOne(-1.0), + tauPtr(NULL), + tauGamma(NULL), + minusTauGamma(NULL), + invTauGamma(NULL), + minusInvTauGamma(NULL) + {} + + DOFVector<double>* getUnVec(int i) + { + return unVec->getDOFVector(i); + } + + DOFVector<double>* getStageSolution(int i) + { + return stageSolution->getDOFVector(i); + } + + DOFVector<double>* getTimeRhsVec(int i) + { + return timeRhsVec->getDOFVector(i); + } + + void acceptTimestep(); + + void buildAfterCoarsen(AdaptInfo *adaptInfo, Flag flag, + bool asmMatrix, bool asmVector); + + void solve(AdaptInfo *adaptInfo, bool a = true, bool b = false); + + void setRosenbrockMethod(RosenbrockMethod *method) + { + rm = method; + init(); + } + + void reset() + { + first = true; + stageSolution->set(0.0); + unVec->set(0.0); + for (int i = 0; i < rm->getStages(); i++) + stageSolutions[i]->set(0.0); + } + + void addOperator(Operator &op, int row, int col, + double *factor = NULL, double *estFactor = NULL); + + void addJacobianOperator(Operator &op, int row, int col, + double *factor = NULL, double *estFactor = NULL); + + void addTimeOperator(int i, int j); + + void setTau(double *ptr) + { + tauPtr = ptr; + } + + void setTauGamma(double *ptr0, double *ptr1, double *ptr2, double *ptr3) + { + tauGamma = ptr0; + minusTauGamma = ptr1; + invTauGamma = ptr2; + minusInvTauGamma = ptr3; + } + + double* getTauGamma() + { + return tauGamma; + } + + double* getMinusTauGamma() + { + return minusTauGamma; + } + + double* getInvTauGamma() + { + return invTauGamma; + } + + double* getMinusInvTauGamma() + { + return minusInvTauGamma; + } + + /// Adds a Dirichlet boundary condition, where the rhs is given by an + /// abstract function. + void addDirichletBC(BoundaryType type, int row, int col, + AbstractFunction<double, WorldVector<double> > *b); + + /// Adds a Dirichlet boundary condition, where the rhs is given by a DOF + /// vector. + void addDirichletBC(BoundaryType type, int row, int col, + DOFVector<double> *vec) + { + FUNCNAME("ExtendedRosenbrockStationary::addDirichletBC()"); + + ERROR_EXIT("Not yet supported!\n"); + } + + /// Adds a Neumann boundary condition, where the rhs is given by an + /// abstract function. + void addNeumannBC(BoundaryType type, int row, int col, + AbstractFunction<double, WorldVector<double> > *n) + { + FUNCNAME("ExtendedRosenbrockStationary::addNeumannBC()"); + + ERROR_EXIT("Not yet supported!\n"); + } + + /// Adds a Neumann boundary condition, where the rhs is given by an DOF + /// vector. + void addNeumannBC(BoundaryType type, int row, int col, + DOFVector<double> *n) + { + FUNCNAME("ExtendedRosenbrockStationary::addNeumannBC()"); + + ERROR_EXIT("Not yet supported!\n"); + } + + /// Adds Robin boundary condition. + void addRobinBC(BoundaryType type, int row, int col, + AbstractFunction<double, WorldVector<double> > *n, + AbstractFunction<double, WorldVector<double> > *r) + { + FUNCNAME("ExtendedRosenbrockStationary::addRobinBC()"); + + ERROR_EXIT("Not yet supported!\n"); + } + + /// special boundary conditions defined in ExtendedProblemStat + + void addSingularDirichletBC(WorldVector<double> &pos, int row, int col, + AbstractFunction<double, WorldVector<double> > &fct); + + void addSingularDirichletBC(DegreeOfFreedom idx, int row, int col, + AbstractFunction<double, WorldVector<double> > &fct); + + void addImplicitDirichletBC(AbstractFunction<double, WorldVector<double> > &signedDist, int row, int col, + AbstractFunction<double, WorldVector<double> > &fct); + + void addImplicitDirichletBC(DOFVector<double> &signedDist, int row, int col, + AbstractFunction<double, WorldVector<double> > &fct); + + void addManualDirichletBC(BoundaryType nr, AbstractFunction<bool, WorldVector<double> >* meshIndicator, + int row, int col, + AbstractFunction<double, WorldVector<double> > &fct); + + void addManualDirichletBC(AbstractFunction<bool, WorldVector<double> >* meshIndicator, + int row, int col, + AbstractFunction<double, WorldVector<double> > &fct); + +#if 0 + /// Adds a periodic boundary condition. + void addPeriodicBC(BoundaryType type, int row, int col) + { + FUNCNAME("ExtendedRosenbrockStationary::addPeriodicBC()"); + + ERROR_EXIT("Not yet supported!\n"); + } +#endif + + protected: + void init(); + + protected: + RosenbrockMethod *rm; + + SystemVector *stageSolution, *unVec, *timeRhsVec, *newUn, *tmp, *lowSol; + + std::vector<SystemVector*> stageSolutions; + + int componentShift; + + bool first; + + double minusOne; + + double *tauPtr; + + double *tauGamma, *minusTauGamma, *invTauGamma, *minusInvTauGamma; + + std::vector<MyRosenbrockBoundary> boundaries; + }; + + +#endif // MY_ROSENBROCKSTATIONARY_H