/* * Copyright (c) 2017-2019 Daniel Drzisga, Dominik Thoennes, Marcus Mohr, Nils Kohl. * * This file is part of HyTeG * (see https://i10git.cs.fau.de/hyteg/hyteg). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "hyteg/Levelinfo.hpp" #include "hyteg/types/matrix.hpp" #include "hyteg/p1functionspace/VertexDoFMemory.hpp" #include "hyteg/p1functionspace/VertexDoFIndexing.hpp" #include "hyteg/facedofspace/FaceDoFIndexing.hpp" #include "hyteg/petsc/PETScWrapper.hpp" #include "hyteg/indexing/Common.hpp" #include "hyteg/primitives/Cell.hpp" #include "hyteg/Algorithms.hpp" #include "hyteg/indexing/DistanceCoordinateSystem.hpp" #include "hyteg/sparseassembly/SparseMatrixProxy.hpp" #include "hyteg/sparseassembly/VectorProxy.hpp" #include "core/math/KahanSummation.h" #include "core/DataTypes.h" #ifdef DEBUG_ELEMENTWISE #include "hyteg/format.hpp" #endif namespace hyteg { namespace vertexdof { namespace macroedge { using walberla::real_c; using indexing::Index; inline indexing::Index getIndexInNeighboringMacroCell( const indexing::Index& vertexDoFIndexInMacroEdge, const Edge& edge, const uint_t& neighborCellID, const PrimitiveStorage& storage, const uint_t& level ) { const Cell& neighborCell = *( storage.getCell( edge.neighborCells().at( neighborCellID ) ) ); const uint_t localEdgeID = neighborCell.getLocalEdgeID( edge.getID() ); const std::array< uint_t, 4 > localVertexIDsAtCell = algorithms::getMissingIntegersAscending< 2, 4 >( {neighborCell.getEdgeLocalVertexToCellLocalVertexMaps().at( localEdgeID ).at( 0 ), neighborCell.getEdgeLocalVertexToCellLocalVertexMaps().at( localEdgeID ).at( 1 )} ); const auto indexInMacroCell = indexing::basisConversion( vertexDoFIndexInMacroEdge, localVertexIDsAtCell, {0, 1, 2, 3}, levelinfo::num_microvertices_per_edge( level ) ); return indexInMacroCell; } inline Point3D coordinateFromIndex( const uint_t & level, const Edge & edge, const Index & index ) { const real_t stepFrequency = 1.0 / levelinfo::num_microedges_per_edge( level ); const Point3D step = ( edge.getCoordinates()[1] - edge.getCoordinates()[0] ) * stepFrequency; return edge.getCoordinates()[0] + step * real_c( index.x() ); } template inline ValueType assembleLocal(const uint_t & level, uint_t pos, const Matrix3r& localMatrix, double* src, double* coeff, const std::array< stencilDirection, 3 >& vertices, const std::array& idx) { ValueType meanCoeff = 1.0/3.0 * (coeff[vertexdof::macroedge::indexFromVertex( level, pos, vertices[0] )] + coeff[vertexdof::macroedge::indexFromVertex( level, pos, vertices[1] )] + coeff[vertexdof::macroedge::indexFromVertex( level, pos, vertices[2] )]); ValueType tmp; tmp = localMatrix(idx[0],idx[0]) * src[vertexdof::macroedge::indexFromVertex( level, pos, vertices[0] )] + localMatrix(idx[0],idx[1]) * src[vertexdof::macroedge::indexFromVertex( level, pos, vertices[1] )] + localMatrix(idx[0],idx[2]) * src[vertexdof::macroedge::indexFromVertex( level, pos, vertices[2] )]; return meanCoeff * tmp; } template inline void assembleLocalStencil(uint_t level, uint_t pos, const Matrix3r& localMatrix, real_t* opr_data, real_t* coeff, const std::array< stencilDirection, 3 >& vertices, const std::array& idx) { ValueType meanCoeff = 1.0/3.0 * (coeff[ vertexdof::macroedge::indexFromVertex( level, pos, vertices[ 0 ] ) ] + coeff[ vertexdof::macroedge::indexFromVertex( level, pos, vertices[ 1 ] ) ] + coeff[ vertexdof::macroedge::indexFromVertex( level, pos, vertices[ 2 ] ) ]); opr_data[vertexdof::stencilIndexFromVertex( vertices[0] )] += meanCoeff * localMatrix(idx[0],idx[0]); opr_data[vertexdof::stencilIndexFromVertex( vertices[1] )] += meanCoeff * localMatrix(idx[0],idx[1]); opr_data[vertexdof::stencilIndexFromVertex( vertices[2] )] += meanCoeff * localMatrix(idx[0],idx[2]); } template< typename ValueType > inline void interpolate(const uint_t & level, Edge &edge, const PrimitiveDataID< FunctionMemory< ValueType >, Edge> &edgeMemoryId, const ValueType & scalar ) { size_t rowsize = levelinfo::num_microvertices_per_edge(level); auto edgeData = edge.getData(edgeMemoryId)->getPointer( level ); for (size_t i = 1; i < rowsize - 1; ++i) { edgeData[i] = scalar; } } template< typename ValueType > inline void interpolate(const uint_t & level, Edge &edge, const PrimitiveDataID< FunctionMemory< ValueType >, Edge> &edgeMemoryId, const std::vector, Edge>> &srcIds, const std::function&)> &expr) { ValueType * edgeData = edge.getData( edgeMemoryId )->getPointer( level ); std::vector< ValueType * > srcPtr; for( const auto & src : srcIds ) { srcPtr.push_back( edge.getData(src)->getPointer( level ) ); } std::vector srcVector( srcIds.size() ); Point3D xBlend; for ( const auto & it : vertexdof::macroedge::Iterator( level, 1 ) ) { const Point3D coordinate = coordinateFromIndex( level, edge, it ); const uint_t idx = vertexdof::macroedge::indexFromVertex( level, it.x(), stencilDirection::VERTEX_C ); for ( uint_t k = 0; k < srcPtr.size(); ++k ) { srcVector[ k ] = srcPtr[ k ][ idx ]; } edge.getGeometryMap()->evalF(coordinate, xBlend); edgeData[ idx ] = expr( xBlend, srcVector ); } } template< typename ValueType > inline void swap( const uint_t & level, Edge & edge, const PrimitiveDataID< FunctionMemory< ValueType >, Edge > & srcID, const PrimitiveDataID< FunctionMemory< ValueType >, Edge > & dstID ) { auto srcData = edge.getData( srcID ); auto dstData = edge.getData( dstID ); srcData->swap( *dstData, level ); } template< typename ValueType > inline void assign( const uint_t & level, Edge &edge, const std::vector &scalars, const std::vector, Edge>> &srcIds, const PrimitiveDataID< FunctionMemory< ValueType >, Edge> &dstId) { size_t rowsize = levelinfo::num_microvertices_per_edge(level); for (size_t i = 1; i < rowsize - 1; ++i) { ValueType tmp = scalars[0]*edge.getData(srcIds[0])->getPointer( level )[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )]; for (size_t k = 1; k < srcIds.size(); ++k) { tmp += scalars[k]*edge.getData(srcIds[k])->getPointer( level )[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )]; } edge.getData(dstId)->getPointer( level )[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] = tmp; } } template< typename ValueType > inline void add(const uint_t & level, const Edge & edge, const ValueType & scalar, const PrimitiveDataID, Edge> & dstId ) { size_t rowsize = levelinfo::num_microvertices_per_edge(level); for (size_t i = 1; i < rowsize - 1; ++i) { edge.getData(dstId)->getPointer( level )[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] += scalar; } } template< typename ValueType > inline void add( const uint_t & level, Edge &edge, const std::vector &scalars, const std::vector, Edge>> &srcIds, const PrimitiveDataID, Edge> &dstId) { size_t rowsize = levelinfo::num_microvertices_per_edge(level); for (size_t i = 1; i < rowsize - 1; ++i) { auto tmp = ValueType( 0 ); for (size_t k = 0; k < srcIds.size(); ++k) { tmp += scalars[k]*edge.getData(srcIds[k])->getPointer( level )[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )]; } edge.getData(dstId)->getPointer( level )[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] += tmp; } } template< typename ValueType > inline void multElementwise( const uint_t & level, Edge &edge, const std::vector, Edge>> &srcIds, const PrimitiveDataID, Edge> &dstId) { size_t rowsize = levelinfo::num_microvertices_per_edge(level); auto dst = edge.getData( dstId )->getPointer( level ); for (size_t i = 1; i < rowsize - 1; ++i) { const uint_t idx = vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C ); ValueType tmp = edge.getData(srcIds[0])->getPointer( level )[idx]; for (size_t k = 1; k < srcIds.size(); ++k) { tmp *= edge.getData(srcIds[k])->getPointer( level )[idx]; } dst[idx] = tmp; } } template< typename ValueType > inline ValueType dot( const uint_t & level, Edge &edge, const PrimitiveDataID, Edge> &lhsMemoryId, const PrimitiveDataID, Edge> &rhsMemoryId) { walberla::math::KahanAccumulator< ValueType > scalarProduct; size_t rowsize = levelinfo::num_microvertices_per_edge(level); for (size_t i = 1; i < rowsize - 1; ++i) { scalarProduct += edge.getData(lhsMemoryId)->getPointer( level )[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] * edge.getData(rhsMemoryId)->getPointer( level )[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )]; } return scalarProduct.get(); } template< typename ValueType > inline ValueType sum( const uint_t & level, const Edge & edge, const PrimitiveDataID, Edge> &dataID, const bool & absolute) { auto sum = ValueType(0); size_t rowsize = levelinfo::num_microvertices_per_edge(level); auto data = edge.getData( dataID )->getPointer( level ); for (size_t i = 1; i < rowsize - 1; ++i) { if ( absolute ) { sum += std::abs( data[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] ); } else { sum += data[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )]; } } return sum; } template< typename ValueType > inline void apply( const uint_t & level, Edge &edge, const PrimitiveDataID< StencilMemory< ValueType >, Edge> &operatorId, const PrimitiveDataID, Edge> &srcId, const PrimitiveDataID, Edge> &dstId, UpdateType update) { typedef stencilDirection sD; size_t rowsize = levelinfo::num_microvertices_per_edge(level); auto opr_data = edge.getData(operatorId)->getPointer( level ); auto src = edge.getData(srcId)->getPointer( level ); auto dst = edge.getData(dstId)->getPointer( level ); ValueType tmp; for (size_t i = 1; i < rowsize - 1; ++i) { const auto stencilIdxW = vertexdof::macroedge::stencilIndexOnEdge( sD::VERTEX_W ); const auto stencilIdxC = vertexdof::macroedge::stencilIndexOnEdge( sD::VERTEX_C ); const auto stencilIdxE = vertexdof::macroedge::stencilIndexOnEdge( sD::VERTEX_E ); const auto dofIdxW = vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_W ); const auto dofIdxC = vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C ); const auto dofIdxE = vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_E ); tmp = opr_data[ stencilIdxW ] * src[ dofIdxW ] + opr_data[ stencilIdxC ] * src[ dofIdxC ] + opr_data[ stencilIdxE ] * src[ dofIdxE ]; for ( uint_t neighborFace = 0; neighborFace < edge.getNumNeighborFaces(); neighborFace++ ) { const auto stencilIdxWNeighborFace = vertexdof::macroedge::stencilIndexOnNeighborFace( sD::VERTEX_W, neighborFace ); const auto stencilIdxENeighborFace = vertexdof::macroedge::stencilIndexOnNeighborFace( sD::VERTEX_E, neighborFace ); const auto stencilWeightW = opr_data[ stencilIdxWNeighborFace ]; const auto stencilWeightE = opr_data[ stencilIdxENeighborFace ]; const auto dofIdxWNeighborFace = vertexdof::macroedge::indexFromVertexOnNeighborFace( level, i, neighborFace, sD::VERTEX_W ); const auto dofIdxENeighborFace = vertexdof::macroedge::indexFromVertexOnNeighborFace( level, i, neighborFace, sD::VERTEX_E ); tmp += stencilWeightW * src[dofIdxWNeighborFace] + stencilWeightE * src[dofIdxENeighborFace]; } for ( uint_t neighborCell = 0; neighborCell < edge.getNumNeighborCells(); neighborCell++ ) { const auto stencilIdx = vertexdof::macroedge::stencilIndexOnNeighborCell( neighborCell, edge.getNumNeighborFaces() ); const auto dofIdx = vertexdof::macroedge::indexFromVertexOnNeighborCell( level, i, neighborCell, edge.getNumNeighborFaces() ); tmp += opr_data[ stencilIdx ] * src[ dofIdx ]; } if (update == Replace) { dst[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] = tmp; } else if (update == Add) { dst[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] += tmp; } } } template< typename ValueType > inline void applyPointwise( const uint_t & level, const Edge &edge, const PrimitiveDataID< StencilMemory< ValueType >, Edge> &operatorId, const PrimitiveDataID, Edge> &srcId, const PrimitiveDataID, Edge> &dstId, UpdateType update) { typedef stencilDirection sD; size_t rowsize = levelinfo::num_microvertices_per_edge(level); auto opr_data = edge.getData(operatorId)->getPointer( level ); auto src = edge.getData(srcId)->getPointer( level ); auto dst = edge.getData(dstId)->getPointer( level ); ValueType tmp; const auto stencilSize = 3 + 2 * edge.getNumNeighborFaces(); for (size_t i = 1; i < rowsize - 1; ++i) { const auto offset = vertexdof::macroedge::innerIndex( level, i ) * stencilSize; const auto stencilIdxW = offset + vertexdof::macroedge::stencilIndexOnEdge( sD::VERTEX_W ); const auto stencilIdxC = offset + vertexdof::macroedge::stencilIndexOnEdge( sD::VERTEX_C ); const auto stencilIdxE = offset + vertexdof::macroedge::stencilIndexOnEdge( sD::VERTEX_E ); const auto dofIdxW = vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_W ); const auto dofIdxC = vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C ); const auto dofIdxE = vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_E ); tmp = opr_data[ stencilIdxW ] * src[ dofIdxW ] + opr_data[ stencilIdxC ] * src[ dofIdxC ] + opr_data[ stencilIdxE ] * src[ dofIdxE ]; for ( uint_t neighborFace = 0; neighborFace < edge.getNumNeighborFaces(); neighborFace++ ) { const auto stencilIdxWNeighborFace = offset + vertexdof::macroedge::stencilIndexOnNeighborFace( sD::VERTEX_W, neighborFace ); const auto stencilIdxENeighborFace = offset + vertexdof::macroedge::stencilIndexOnNeighborFace( sD::VERTEX_E, neighborFace ); const auto stencilWeightW = opr_data[ stencilIdxWNeighborFace ]; const auto stencilWeightE = opr_data[ stencilIdxENeighborFace ]; const auto dofIdxWNeighborFace = vertexdof::macroedge::indexFromVertexOnNeighborFace( level, i, neighborFace, sD::VERTEX_W ); const auto dofIdxENeighborFace = vertexdof::macroedge::indexFromVertexOnNeighborFace( level, i, neighborFace, sD::VERTEX_E ); tmp += stencilWeightW * src[dofIdxWNeighborFace] + stencilWeightE * src[dofIdxENeighborFace]; } for ( uint_t neighborCell = 0; neighborCell < edge.getNumNeighborCells(); neighborCell++ ) { const auto stencilIdx = vertexdof::macroedge::stencilIndexOnNeighborCell( neighborCell, edge.getNumNeighborFaces() ); const auto dofIdx = vertexdof::macroedge::indexFromVertexOnNeighborCell( level, i, neighborCell, edge.getNumNeighborFaces() ); tmp += opr_data[ stencilIdx ] * src[ dofIdx ]; } if (update == Replace) { dst[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] = tmp; } else if (update == Add) { dst[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] += tmp; } } } template< typename ValueType > inline void smooth_gs( const uint_t & level, Edge &edge, const PrimitiveDataID< StencilMemory< ValueType >, Edge> &operatorId, const PrimitiveDataID, Edge> &dstId, const PrimitiveDataID, Edge> &rhsId) { typedef stencilDirection sD; size_t rowsize = levelinfo::num_microvertices_per_edge(level); auto opr_data = edge.getData(operatorId)->getPointer( level ); auto rhs = edge.getData(rhsId)->getPointer( level ); auto dst = edge.getData(dstId)->getPointer( level ); const auto stencilIdxW = vertexdof::macroedge::stencilIndexOnEdge( sD::VERTEX_W ); const auto stencilIdxC = vertexdof::macroedge::stencilIndexOnEdge( sD::VERTEX_C ); const auto stencilIdxE = vertexdof::macroedge::stencilIndexOnEdge( sD::VERTEX_E ); const auto invCenterWeight = 1.0 / opr_data[ stencilIdxC ]; ValueType tmp; for (size_t i = 1; i < rowsize - 1; ++i) { const auto dofIdxW = vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_W ); const auto dofIdxC = vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C ); const auto dofIdxE = vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_E ); tmp = rhs[ dofIdxC ]; tmp -= opr_data[ stencilIdxW ] * dst[ dofIdxW ] + opr_data[ stencilIdxE ] * dst[ dofIdxE ]; for ( uint_t neighborFace = 0; neighborFace < edge.getNumNeighborFaces(); neighborFace++ ) { const auto stencilIdxWNeighborFace = vertexdof::macroedge::stencilIndexOnNeighborFace( sD::VERTEX_W, neighborFace ); const auto stencilIdxENeighborFace = vertexdof::macroedge::stencilIndexOnNeighborFace( sD::VERTEX_E, neighborFace ); const auto stencilWeightW = opr_data[ stencilIdxWNeighborFace ]; const auto stencilWeightE = opr_data[ stencilIdxENeighborFace ]; const auto dofIdxWNeighborFace = vertexdof::macroedge::indexFromVertexOnNeighborFace( level, i, neighborFace, sD::VERTEX_W ); const auto dofIdxENeighborFace = vertexdof::macroedge::indexFromVertexOnNeighborFace( level, i, neighborFace, sD::VERTEX_E ); tmp -= stencilWeightW * dst[dofIdxWNeighborFace] + stencilWeightE * dst[dofIdxENeighborFace]; } for ( uint_t neighborCell = 0; neighborCell < edge.getNumNeighborCells(); neighborCell++ ) { const auto stencilIdx = vertexdof::macroedge::stencilIndexOnNeighborCell( neighborCell, edge.getNumNeighborFaces() ); const auto dofIdx = vertexdof::macroedge::indexFromVertexOnNeighborCell( level, i, neighborCell, edge.getNumNeighborFaces() ); tmp -= opr_data[ stencilIdx ] * dst[ dofIdx ]; } dst[ dofIdxC ] = invCenterWeight * tmp; } } template< typename ValueType > inline void smooth_sor(const uint_t & level, Edge &edge, const PrimitiveDataID< StencilMemory< ValueType >, Edge> &operatorId, const PrimitiveDataID, Edge> &dstId, const PrimitiveDataID, Edge> &rhsId, ValueType relax, const bool & backwards = false ) { typedef stencilDirection sD; size_t rowsize = levelinfo::num_microvertices_per_edge(level); auto opr_data = edge.getData(operatorId)->getPointer( level ); auto rhs = edge.getData(rhsId)->getPointer( level ); auto dst = edge.getData(dstId)->getPointer( level ); const auto stencilIdxW = vertexdof::macroedge::stencilIndexOnEdge( sD::VERTEX_W ); const auto stencilIdxC = vertexdof::macroedge::stencilIndexOnEdge( sD::VERTEX_C ); const auto stencilIdxE = vertexdof::macroedge::stencilIndexOnEdge( sD::VERTEX_E ); const auto invCenterWeight = 1.0 / opr_data[ stencilIdxC ]; ValueType tmp; const int start = backwards ? (int)rowsize - 2 : 1; const int stop = backwards ? 0 : (int)rowsize - 1; const int incr = backwards ? -1 : 1; for (int ii = start; ii != stop; ii += incr) { const uint_t i = uint_c(ii); const auto dofIdxW = vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_W ); const auto dofIdxC = vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C ); const auto dofIdxE = vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_E ); tmp = rhs[ dofIdxC ]; tmp -= opr_data[ stencilIdxW ] * dst[ dofIdxW ] + opr_data[ stencilIdxE ] * dst[ dofIdxE ]; for ( uint_t neighborFace = 0; neighborFace < edge.getNumNeighborFaces(); neighborFace++ ) { const auto stencilIdxWNeighborFace = vertexdof::macroedge::stencilIndexOnNeighborFace( sD::VERTEX_W, neighborFace ); const auto stencilIdxENeighborFace = vertexdof::macroedge::stencilIndexOnNeighborFace( sD::VERTEX_E, neighborFace ); const auto stencilWeightW = opr_data[ stencilIdxWNeighborFace ]; const auto stencilWeightE = opr_data[ stencilIdxENeighborFace ]; const auto dofIdxWNeighborFace = vertexdof::macroedge::indexFromVertexOnNeighborFace( level, i, neighborFace, sD::VERTEX_W ); const auto dofIdxENeighborFace = vertexdof::macroedge::indexFromVertexOnNeighborFace( level, i, neighborFace, sD::VERTEX_E ); tmp -= stencilWeightW * dst[dofIdxWNeighborFace] + stencilWeightE * dst[dofIdxENeighborFace]; } for ( uint_t neighborCell = 0; neighborCell < edge.getNumNeighborCells(); neighborCell++ ) { const auto stencilIdx = vertexdof::macroedge::stencilIndexOnNeighborCell( neighborCell, edge.getNumNeighborFaces() ); const auto dofIdx = vertexdof::macroedge::indexFromVertexOnNeighborCell( level, i, neighborCell, edge.getNumNeighborFaces() ); tmp -= opr_data[ stencilIdx ] * dst[ dofIdx ]; } dst[ dofIdxC ] = (1.0 - relax) * dst[ dofIdxC ] + relax * invCenterWeight * tmp; } } template< typename ValueType > inline void smooth_jac(const uint_t & level, Edge &edge, const PrimitiveDataID< StencilMemory< ValueType >, Edge> &operatorId, const PrimitiveDataID, Edge> &dstId, const PrimitiveDataID, Edge> &rhsId, const PrimitiveDataID, Edge> &tmpId) { size_t rowsize = levelinfo::num_microvertices_per_edge(level); auto opr_data = edge.getData(operatorId)->getPointer( level ); auto dst = edge.getData(dstId)->getPointer( level ); auto rhs = edge.getData(rhsId)->getPointer( level ); auto tmp = edge.getData(tmpId)->getPointer( level ); for (size_t i = 1; i < rowsize - 1; ++i) { dst[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] = rhs[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )]; for (auto& neighbor : vertexdof::macroedge::neighborsOnEdgeFromVertexDoF ) { dst[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] -= opr_data[ vertexdof::stencilIndexFromVertex( neighbor ) ] * tmp[vertexdof::macroedge::indexFromVertex( level, i, neighbor )]; } for (auto& neighbor : vertexdof::macroedge::neighborsOnSouthFaceFromVertexDoF ) { dst[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] -= opr_data[ vertexdof::stencilIndexFromVertex( neighbor ) ] * tmp[vertexdof::macroedge::indexFromVertex( level, i, neighbor )]; } if (edge.getNumNeighborFaces() == 2) { for (auto& neighbor : vertexdof::macroedge::neighborsOnNorthFaceFromVertexDoF ) { dst[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] -= opr_data[ vertexdof::stencilIndexFromVertex( neighbor ) ] * tmp[vertexdof::macroedge::indexFromVertex( level, i, neighbor )]; } } dst[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] /= opr_data[vertexdof::stencilIndexFromVertex( stencilDirection::VERTEX_C ) ]; } } template< typename ValueType > inline void enumerate( const uint_t & level, Edge &edge, const PrimitiveDataID, Edge> &dstId, ValueType& num) { size_t rowsize = levelinfo::num_microvertices_per_edge(level); for (size_t i = 1; i < rowsize - 1; ++i) { edge.getData(dstId)->getPointer( level )[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] = num; num++; } } template< typename ValueType > inline void integrateDG(const uint_t & level, Edge &edge, const std::shared_ptr< PrimitiveStorage >& storage, const PrimitiveDataID, Edge> &rhsId, const PrimitiveDataID, Edge> &rhsP1Id, const PrimitiveDataID, Edge> &dstId) { typedef stencilDirection sD; size_t rowsize = levelinfo::num_microvertices_per_edge(level); auto rhs = edge.getData(rhsId)->getPointer( level ); auto rhsP1 = edge.getData(rhsP1Id)->getPointer( level ); auto dst = edge.getData(dstId)->getPointer( level ); real_t tmp; Face* face = storage->getFace(edge.neighborFaces()[0]); real_t weightedFaceArea0 = std::pow(4.0, -walberla::real_c(level)) * face->area / 3.0; real_t weightedFaceArea1 = real_c( 0 ); if (edge.getNumNeighborFaces() == 2) { face = storage->getFace(edge.neighborFaces()[1]); weightedFaceArea1 = std::pow(4.0, -walberla::real_c(level)) * face->area / 3.0; } for (size_t i = 1; i < rowsize - 1; ++i) { tmp = weightedFaceArea0 * rhs[facedof::macroedge::indexFaceFromVertex( level, i, sD::CELL_GRAY_SW )] * ( 0.5 * 0.5 * ( rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C )] + rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_W )] ) + 0.5 * 0.5 * ( rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C )] + rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_S )] )); tmp += weightedFaceArea0 * rhs[facedof::macroedge::indexFaceFromVertex( level, i, sD::CELL_BLUE_SE )] * ( 0.5 * 0.5 * ( rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C )] + rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_S )] ) + 0.5 * 0.5 * ( rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C )] + rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_SE )] )); tmp += weightedFaceArea0 * rhs[facedof::macroedge::indexFaceFromVertex( level, i, sD::CELL_GRAY_SE )] * ( 0.5 * 0.5 * ( rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C )] + rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_SE )] ) + 0.5 * 0.5 * ( rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C )] + rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_E )] )); if (edge.getNumNeighborFaces() == 2) { tmp += weightedFaceArea1 * rhs[facedof::macroedge::indexFaceFromVertex( level, i, sD::CELL_GRAY_NW )] * ( 0.5 * 0.5 * ( rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C )] + rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_W )]) + 0.5 * 0.5 * ( rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C )] + rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_NW )])); tmp += weightedFaceArea1 * rhs[facedof::macroedge::indexFaceFromVertex( level, i, sD::CELL_BLUE_NW )] * ( 0.5 * 0.5 * ( rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C )] + rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_NW )]) + 0.5 * 0.5 * ( rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C )] + rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_N )])); tmp += weightedFaceArea1 * rhs[facedof::macroedge::indexFaceFromVertex( level, i, sD::CELL_GRAY_NE )] * ( 0.5 * 0.5 * ( rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C )] + rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_N )]) + 0.5 * 0.5 * ( rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C )] + rhsP1[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_E )])); } dst[vertexdof::macroedge::indexFromVertex( level, i, sD::VERTEX_C )] = ValueType( tmp ); } } template< typename ValueType > inline void printFunctionMemory( const uint_t & level, const Edge& edge, const PrimitiveDataID, Edge> &dstId){ ValueType* edgeMemory = edge.getData(dstId)->getPointer( level ); using namespace std; cout << setfill('=') << setw(100) << "" << endl; cout << edge << std::left << setprecision(1) << fixed << setfill(' ') << endl; uint_t rowsize = levelinfo::num_microvertices_per_edge( level ); if(edge.getNumNeighborFaces() == 2) { for (uint_t i = 0; i < (rowsize - 1); ++i) { cout << setw(5) << edgeMemory[hyteg::vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_N )] << "|"; } cout << endl; } for(uint_t i = 0; i < rowsize; ++i){ cout << setw(5) << edgeMemory[hyteg::vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )] << "|"; } cout << endl << " |"; for(uint_t i = 1; i < rowsize; ++i){ cout << setw(5) << edgeMemory[hyteg::vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_S )] << "|"; } cout << endl << setfill('=') << setw(100) << "" << endl << setfill(' '); } template< typename ValueType > inline ValueType getMaxValue( const uint_t & level, Edge &edge, const PrimitiveDataID, Edge> &srcId ) { uint_t rowsize = levelinfo::num_microvertices_per_edge( level ); auto src = edge.getData( srcId )->getPointer( level ); auto localMax = -std::numeric_limits< ValueType >::max(); for( size_t i = 1; i < rowsize - 1; ++i ) { localMax = std::max( localMax, src[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C ) ] ); } return localMax; } template< typename ValueType > inline ValueType getMaxMagnitude( const uint_t & level, Edge &edge, const PrimitiveDataID, Edge> &srcId ) { uint_t rowsize = levelinfo::num_microvertices_per_edge( level ); auto src = edge.getData( srcId )->getPointer( level ); auto localMax = ValueType(0.0); for( size_t i = 1; i < rowsize - 1; ++i ) { localMax = std::max( localMax, std::abs( src[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C ) ] )); } return localMax; } template< typename ValueType > inline ValueType getMinValue( const uint_t & level, Edge &edge, const PrimitiveDataID, Edge> &srcId ) { uint_t rowsize = levelinfo::num_microvertices_per_edge( level ); auto src = edge.getData( srcId )->getPointer( level ); auto localMin = std::numeric_limits< ValueType >::max(); for( size_t i = 1; i < rowsize - 1; ++i ) { localMin = std::min( localMin, src[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C ) ] ); } return localMin; } #ifdef HYTEG_BUILD_WITH_PETSC inline void saveOperator( const uint_t& level, Edge& edge, const PrimitiveStorage& storage, const PrimitiveDataID< StencilMemory< real_t >, Edge >& operatorId, const PrimitiveDataID< FunctionMemory< idx_t >, Edge >& srcId, const PrimitiveDataID< FunctionMemory< idx_t >, Edge >& dstId, const std::shared_ptr< SparseMatrixProxy >& mat ) { size_t rowsize = levelinfo::num_microvertices_per_edge( level ); auto opr_data = edge.getData( operatorId )->getPointer( level ); auto src = edge.getData( srcId )->getPointer( level ); auto dst = edge.getData( dstId )->getPointer( level ); for ( uint_t i = 1; i < rowsize - 1; ++i ) { idx_t dstint = dst[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )]; idx_t srcint = src[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )]; mat->addValue( uint_c( dstint ), uint_c( srcint ), opr_data[vertexdof::stencilIndexFromVertex( stencilDirection::VERTEX_C )] ); for ( const auto& neighbor : vertexdof::macroedge::neighborsOnEdgeFromVertexDoF ) { srcint = src[vertexdof::macroedge::indexFromVertex( level, i, neighbor )]; mat->addValue( uint_c( dstint ), uint_c( srcint ), opr_data[vertexdof::stencilIndexFromVertex( neighbor )] ); } for ( uint_t neighborFace = 0; neighborFace < edge.getNumNeighborFaces(); neighborFace++ ) { srcint = src[vertexdof::macroedge::indexFromVertexOnNeighborFace( level, i, neighborFace, stencilDirection::VERTEX_W )]; mat->addValue( uint_c( dstint ), uint_c( srcint ), opr_data[vertexdof::macroedge::stencilIndexOnNeighborFace( stencilDirection::VERTEX_W, neighborFace )] ); srcint = src[vertexdof::macroedge::indexFromVertexOnNeighborFace( level, i, neighborFace, stencilDirection::VERTEX_E )]; mat->addValue( uint_c( dstint ), uint_c( srcint ), opr_data[vertexdof::macroedge::stencilIndexOnNeighborFace( stencilDirection::VERTEX_E, neighborFace )] ); } for ( uint_t neighborCellID = 0; neighborCellID < edge.getNumNeighborCells(); neighborCellID++ ) { const auto& neighborCell = *( storage.getCell( edge.neighborCells().at( neighborCellID ) ) ); const auto localEdgeIDOnNeighborCell = neighborCell.getLocalEdgeID( edge.getID() ); if ( localEdgeIDOnNeighborCell == 1 || localEdgeIDOnNeighborCell == 4 ) { // Since the functions we access here carry the petsc vector indices, we cannot simply also loop over // ghost layer DoFs that do not exist. In the apply kernel this is okay, as we only add zeros in that case. // Therefore we check if there are inner vertices - this only applies for macro-edge IDs 1 and 4. srcint = src[vertexdof::macroedge::indexFromVertexOnNeighborCell( level, i, neighborCellID, edge.getNumNeighborFaces() )]; mat->addValue( uint_c( dstint ), uint_c( srcint ), opr_data[vertexdof::macroedge::stencilIndexOnNeighborCell( neighborCellID, edge.getNumNeighborFaces() )] ); } } } } inline void saveIdentityOperator( const uint_t& level, Edge& edge, const PrimitiveDataID< FunctionMemory< idx_t >, Edge >& dstId, const std::shared_ptr< SparseMatrixProxy >& mat ) { size_t rowsize = levelinfo::num_microvertices_per_edge( level ); auto dst = edge.getData( dstId )->getPointer( level ); for ( uint_t i = 1; i < rowsize - 1; ++i ) { idx_t dstint = dst[vertexdof::macroedge::indexFromVertex( level, i, stencilDirection::VERTEX_C )]; mat->addValue( uint_c( dstint ), uint_c( dstint ), 1.0 ); } } template < typename ValueType > inline void createVectorFromFunction( const uint_t& level, Edge& edge, const PrimitiveDataID< FunctionMemory< ValueType >, Edge >& srcId, const PrimitiveDataID< FunctionMemory< idx_t >, Edge >& numeratorId, const std::shared_ptr< VectorProxy >& vec ) { idx_t rowsize = (idx_t) levelinfo::num_microvertices_per_edge( level ); auto src = edge.getData( srcId )->getPointer( level ); auto numerator = edge.getData( numeratorId )->getPointer( level ); for ( uint_t i = 1; i < uint_c( rowsize - 1 ); i++ ) { vec->setValue( numerator[i], src[i] ); } } template < typename ValueType > inline void createFunctionFromVector( const uint_t& level, Edge& edge, const PrimitiveDataID< FunctionMemory< ValueType >, Edge >& srcId, const PrimitiveDataID< FunctionMemory< idx_t >, Edge >& numeratorId, const std::shared_ptr< VectorProxy >& vec ) { idx_t rowsize = (idx_t) levelinfo::num_microvertices_per_edge( level ); auto numerator = edge.getData( numeratorId )->getPointer( level ); for ( uint_t i = 1; i < uint_c( rowsize - 1 ); i++ ) { edge.getData( srcId )->getPointer( level )[i] = vec->getValue( numerator[i] ); } } inline void applyDirichletBC( const uint_t& level, Edge& edge, std::vector< idx_t >& mat, const PrimitiveDataID< FunctionMemory< idx_t >, Edge >& numeratorId ) { size_t rowsize = levelinfo::num_microvertices_per_edge( level ); for ( uint_t i = 1; i < rowsize - 1; i++ ) { mat.push_back( edge.getData( numeratorId )->getPointer( level )[i] ); } } #endif } // namespace macroedge } // namespace vertexdof } // namespace hyteg