Skip to content
Snippets Groups Projects
Commit 1d381ad7 authored by Alexander Jaust's avatar Alexander Jaust
Browse files

[precice] precice adapter lives in this repository now

parent 98f5d422
No related branches found
No related tags found
1 merge request!6Feature/ff pm coupling fvca cleanup (to be moved into dumux-pub/jaust2020a)
Showing with 16268 additions and 1 deletion
precice-adapter @ 51f724ee
Subproject commit 51f724ee6cef653c99e99d78fa54066864a714a2
# build system clutter
build-*
Testing
# auto-saved files
*~
# hidden files
.cproject
.project
# left overs from git rebase
*.orig
*.rej
# latex clutter
*.pdf
*.aux
*.blg
*.log
*.bbl
*.dvi
*.idx
*.out
*.tdo
*.toc
*.synctex.gz
# always consider files containing source code regardless of their name
!*.cc
!*.hh
!*.c
!*.h
!*.sh
_deps
# dumux-precice-wrapper
A preCICE adapter toolbox for DuMuX
## Ideas for a tighter integration
- Minimum requirement of what should work
- Coupling of conjugate heat flow problem (flow over heated plate)
- Tutorial test case with horizontal flow over a porous medium. See https://git.iws.uni-stuttgart.de/dumux-repositories/dumux-course/tree/master/exercises/exercise-coupling-ff-pm
- Coupling in both directions should be done
- Have specific function depending on coupling?!
- `Pressure`
- `Velocity`
- `Temperature`
- `HeatFlux`
- `NormalVelocity`
- `TangentialVelocity` <-- Is this necessary?
- Derive from coupling manager in DuMuX.
- What can I do 1 to 1 as in the coupling manager?
- How can we iterate several times for a time step? This should be done "internally" so that the user does not see itz
- Template the adapter wrt to dimension
#ifndef PRECICEWRAPPER_HH
#define PRECICEWRAPPER_HH
#include<string>
#include<ostream>
#include<precice/SolverInterface.hpp>
#include "../src/dumuxpreciceindexwrapper.hh"
namespace precice_adapter{
class PreciceAdapter
{
private:
bool wasCreated_;
std::unique_ptr<precice::SolverInterface> precice_;
PreciceAdapter();
bool checkIfActionIsRequired( const std::string& condition );
void actionIsFulfilled( const std::string& condition );
void readBlockScalarDataFromPrecice( const int dataID, std::vector<double>& data );
void writeBlockScalarDataToPrecice( const int dataID, std::vector<double>& data );
size_t numberOfQuantities() const { return dataNames_.size(); }
bool meshWasCreated_;
bool preciceWasInitialized_;
bool hasIndexMapper_;
int meshID_;
double timeStepSize_;
std::vector< std::string > dataNames_;
std::vector< int > preciceDataID_;
std::vector< std::vector< double > > dataVectors_;
std::vector<int> vertexIDs_; //should be size_t
DumuxPreciceIndexMapper<int> indexMapper_;
size_t getNumberOfQuantities() const { return dataNames_.size(); }
static constexpr size_t reserveSize_ = 4;
~PreciceAdapter();
public:
PreciceAdapter(const PreciceAdapter&) = delete;
void operator=(const PreciceAdapter&) = delete;
static PreciceAdapter& getInstance();
void announceSolver( const std::string& name,
const std::string configurationFileName,
const int rank,
const int size );
size_t announceQuantity( const std::string& name );
int getDimensions() const;
bool hasToReadIterationCheckpoint();
void announceIterationCheckpointRead();
bool hasToWriteIterationCheckpoint();
void announceIterationCheckpointWritten();
bool hasToWriteInitialData();
void announceInitialDataWritten();
void setMesh( const std::string& meshName,
const size_t numPoints,
std::vector<double>& coordinates );
double initialize();
void createIndexMapping( const std::vector<int>& dumuxFaceIDs );
double setMeshAndInitialize( const std::string& meshName,
const size_t numPoints,
std::vector<double>& coordinates) ;
void initializeData();
void finalize();
double advance( const double computedTimeStepLength );
bool isCouplingOngoing();
size_t getNumberOfVertices();
double getScalarQuantityOnFace( const size_t dataID, const int faceID ) const;
const std::vector<double>& getVectorScalarQuantityOnFace( const size_t dataID, const int faceID ) const;
void writeScalarQuantityOnFace( const size_t dataID,
const int faceID,
const double value );
// void writeVectorQuantityOnFace( const size_t dataID,
// const int faceID,
// const double* value,
// const size_t size );
std::vector<double>& getQuantityVector( const size_t dataID );
const std::vector<double>& getQuantityVector( const size_t dataID ) const;
void writeScalarQuantityVector( const size_t dataID,
std::vector<double>& values );
void writeScalarQuantityToOtherSolver( const size_t dataID );
void readScalarQuantityFromOtherSolver( const size_t dataID );
bool isCoupledEntity( const int faceID ) const;
size_t getIdFromName( const std::string& dataName) const;
std::string getNameFromId( const size_t dataID ) const;
void print( std::ostream& os );
};
}
#endif
#include "dumuxpreciceindexwrapper.hh"
#ifndef DUMUXPRECICEINDEXWRAPPER_H
#define DUMUXPRECICEINDEXWRAPPER_H
#include<cassert>
#include<iostream>
#include<map>
#include<ostream>
#include<vector>
template<typename T>
class DumuxPreciceIndexMapper
{
private:
// Use a boost bimap?
std::map<T, T> dumuxFaceIndexToPreciceIndex_;
std::map<T, T> preciceVertexToDumuxFaceIndex_;
// AJ: I think we should not rely on the fact that the preCICE vertexIDs start at 0.
// It might happen that we have more than one interface?! We should check the performance.
//std::vector<T> preciceVertexToDumuxFaceIndex_;
bool mappingWasCreated_;
size_t size_;
public:
DumuxPreciceIndexMapper() : mappingWasCreated_(false), size_(0)
{}
void createMapping(const std::vector<T>& dumuxIndices,
const std::vector<T>& preciceIndices )
{
assert( dumuxIndices.size() == preciceIndices.size() );
size_ = dumuxIndices.size();
for (T i = 0; i < size_; i++)
{
preciceVertexToDumuxFaceIndex_.emplace( preciceIndices[i], dumuxIndices[i] );
dumuxFaceIndexToPreciceIndex_.emplace( dumuxIndices[i], preciceIndices[i] );
}
mappingWasCreated_ = true;
}
const T getPreciceId( const T dumuxId ) const
{
assert( isDumuxIdMapped( dumuxId ) );
return dumuxFaceIndexToPreciceIndex_.at(dumuxId);
}
const T getDumuxId( const T preciceId ) const
{
assert( isPreciceIdMapped(preciceId) );
return preciceVertexToDumuxFaceIndex_.at(preciceId);
}
bool isDumuxIdMapped( const T dumuxId ) const
{
return dumuxFaceIndexToPreciceIndex_.count( dumuxId ) == 1;
}
bool isPreciceIdMapped( const T preciceId ) const
{
return preciceVertexToDumuxFaceIndex_.count(preciceId) == 1;
}
size_t getSize() const
{
return preciceVertexToDumuxFaceIndex_.size();
}
virtual ~DumuxPreciceIndexMapper()
{}
template<typename U>
friend std::ostream& operator<<(std::ostream& os, const DumuxPreciceIndexMapper<U>& wrapper );
};
template<typename T>
std::ostream& operator<<(std::ostream& os, const DumuxPreciceIndexMapper<T>& wrapper )
{
os << "preCICE to DuMuX mapping " << "\n";
for (const auto& v: wrapper.preciceVertexToDumuxFaceIndex_)
{
os << v.first << " -> " << wrapper.getDumuxId(v.first) << "\n";
}
os << "\n\n";
os << "Dumux to preCICE mapping " << "\n";
for (const auto& v: wrapper.dumuxFaceIndexToPreciceIndex_ )
{
os << v.first << " -> " << wrapper.getPreciceId(v.first) << "\n";
}
return os;
}
#endif // DUMUXPRECICEINDEXWRAPPER_H
#include "../include/preciceadapter.hh"
#include <algorithm>
#include <exception>
#include <cassert>
using namespace precice_adapter;
PreciceAdapter::PreciceAdapter():
wasCreated_(false), precice_(nullptr), meshWasCreated_(false), preciceWasInitialized_(false), hasIndexMapper_(false),
meshID_(0), timeStepSize_(0.)
{
preciceDataID_.reserve(reserveSize_);
dataNames_.reserve(reserveSize_);
dataVectors_.reserve(reserveSize_);
}
PreciceAdapter& PreciceAdapter::getInstance()
{
static PreciceAdapter instance;
return instance;
}
void PreciceAdapter::announceSolver(const std::string &name, const std::string configurationFileName, const int rank, const int size)
{
assert( precice_ == nullptr );
precice_ = std::make_unique<precice::SolverInterface>(name, rank, size);
wasCreated_ = true;
precice_->configure( configurationFileName );
}
size_t PreciceAdapter::announceQuantity(const std::string &name)
{
assert( meshWasCreated_ );
auto it = std::find(dataNames_.begin(), dataNames_.end(), name);
if ( it != dataNames_.end() )
{
throw( std::runtime_error(" Error! Duplicate quantity announced! ") );
}
dataNames_.push_back( name );
preciceDataID_.push_back( precice_->getDataID( name, meshID_ ) );
dataVectors_.push_back( std::vector<double>( vertexIDs_.size() ) );
return getNumberOfQuantities()-1;
}
int PreciceAdapter::getDimensions() const
{
assert( wasCreated_ );
return precice_->getDimensions();
}
/*
void PreciceAdapter::setMeshName(const std::string& meshName)
{
assert( wasCreated_ );
meshID_ = precice_->getMeshID(meshName);
}
*/
void PreciceAdapter::setMesh(const std::string& meshName,
const size_t numPoints,
std::vector<double>& coordinates)
{
assert( wasCreated_ );
assert( numPoints == coordinates.size() / getDimensions() );
meshID_ = precice_->getMeshID(meshName);
vertexIDs_.resize( numPoints );
precice_->setMeshVertices( meshID_, numPoints, coordinates.data(), vertexIDs_.data() );
meshWasCreated_ = true;
}
double PreciceAdapter::initialize()
{
assert( wasCreated_ );
assert( meshWasCreated_ );
assert( !preciceWasInitialized_ );
timeStepSize_ = precice_->initialize();
assert( timeStepSize_ > 0 );
preciceWasInitialized_ = true;
return timeStepSize_;
}
void PreciceAdapter::createIndexMapping( const std::vector<int>& dumuxFaceIDs )
{
assert( meshWasCreated_ );
indexMapper_.createMapping( dumuxFaceIDs, vertexIDs_);
hasIndexMapper_ = true;
}
double PreciceAdapter::setMeshAndInitialize(const std::string& meshName,
const size_t numPoints,
std::vector<double>& coordinates)
{
setMesh( meshName, numPoints, coordinates );
return initialize();
}
void PreciceAdapter::initializeData()
{
assert( preciceWasInitialized_ );
precice_->initializeData();
}
void PreciceAdapter::finalize()
{
assert( wasCreated_ );
if (preciceWasInitialized_) precice_->finalize();
}
double PreciceAdapter::advance( const double computedTimeStepLength )
{
assert( wasCreated_ );
return precice_->advance( computedTimeStepLength );
}
bool PreciceAdapter::isCouplingOngoing()
{
assert( wasCreated_ );
return precice_->isCouplingOngoing();
}
size_t PreciceAdapter::getNumberOfVertices()
{
assert( wasCreated_ );
return vertexIDs_.size();
}
double PreciceAdapter::getScalarQuantityOnFace(const size_t dataID, const int faceID) const
{
assert( wasCreated_ );
assert( hasIndexMapper_ );
if ( !hasIndexMapper_ )
{
throw std::runtime_error("Reading quantity using faceID, but index mapping was not created!");
}
const auto idx = indexMapper_.getPreciceId( faceID );
assert( dataID < dataVectors_.size() );
const std::vector<double>& quantityVector = dataVectors_[ dataID ];
assert(idx < quantityVector.size() );
return quantityVector[idx];
}
void PreciceAdapter::writeScalarQuantityOnFace(const size_t dataID, const int faceID, const double value)
{
assert( wasCreated_ );
assert( hasIndexMapper_ );
if ( !hasIndexMapper_ )
{
throw std::runtime_error("Writing quantity using faceID, but index mapping was not created!");
}
const auto idx = indexMapper_.getPreciceId( faceID );
assert( dataID < dataVectors_.size() );
std::vector<double>& quantityVector = dataVectors_[ dataID ];
assert( idx < quantityVector.size() );
quantityVector[idx] = value;
}
//void PreciceAdapter::writeVectorQuantityOnFace(const size_t dataID,
// const int faceID,
// const double* value,
// const size_t size)
//{
// assert( wasCreated_ );
// assert( hasIndexMapper_ );
// assert( size == getDimensions() );
// if ( !hasIndexMapper_ )
// {
// throw std::runtime_error("Writing quantity using faceID, but index mapping was not created!");
// }
// const auto idx = indexMapper_.getPreciceId( faceID ) * size;
// assert( dataID < dataVectors_.size() );
// std::vector<double>& quantityVector = dataVectors_[ dataID ];
// assert( idx < quantityVector.size() );
// //quantityVector[idx] = value;
// std::copy_n( value, size, quantityVector[idx] );
//}
std::vector<double>& PreciceAdapter::getQuantityVector(const size_t dataID )
{
assert( wasCreated_ );
assert( dataID < dataVectors_.size() );
return dataVectors_[dataID];
}
const std::vector<double> &PreciceAdapter::getQuantityVector(const size_t dataID ) const
{
assert( wasCreated_ );
return getQuantityVector( dataID );
}
void PreciceAdapter::writeScalarQuantityVector(const size_t dataID,
std::vector<double> &values)
{
assert( wasCreated_);
assert( dataID < dataVectors_.size() );
assert( dataVectors_[dataID].size() == values.size() );
dataVectors_[dataID] = values;
}
void PreciceAdapter::writeScalarQuantityToOtherSolver(const size_t dataID)
{
assert( wasCreated_ );
assert( dataID < dataVectors_.size() );
assert( dataID < preciceDataID_.size() );
assert( dataID < std::numeric_limits<int>::max() );
writeBlockScalarDataToPrecice( preciceDataID_[dataID], dataVectors_[dataID] );
}
void PreciceAdapter::readScalarQuantityFromOtherSolver(const size_t dataID)
{
assert( wasCreated_ );
assert( dataID < dataVectors_.size() );
assert( dataID < preciceDataID_.size() );
assert( dataID < std::numeric_limits<int>::max() );
readBlockScalarDataFromPrecice( preciceDataID_[dataID], dataVectors_[dataID] );
}
bool PreciceAdapter::isCoupledEntity(const int faceID) const
{
assert( wasCreated_ );
return indexMapper_.isDumuxIdMapped( faceID );
}
size_t PreciceAdapter::getIdFromName(const std::string &dataName) const
{
assert( wasCreated_ );
const auto it = std::find( dataNames_.begin(), dataNames_.end(), dataName );
if ( it == dataNames_.end() )
{
throw( std::runtime_error(" Error! Name of data not found! ") );
}
const auto idx = std::distance( dataNames_.begin(), it );
assert( idx > -1 );
return size_t(idx);
}
std::string PreciceAdapter::getNameFromId(const size_t dataID) const
{
assert( wasCreated_ );
assert( dataID < dataNames_.size() );
return dataNames_[dataID];
}
void PreciceAdapter::print(std::ostream& os)
{
os << indexMapper_;
}
bool PreciceAdapter::checkIfActionIsRequired( const std::string& condition )
{
assert( wasCreated_ );
return precice_->isActionRequired( condition );
}
void PreciceAdapter::actionIsFulfilled(const std::string& condition)
{
assert( wasCreated_ );
precice_->fulfilledAction( condition );
}
void PreciceAdapter::readBlockScalarDataFromPrecice(const int dataID, std::vector<double> &data)
{
assert( wasCreated_ );
assert( vertexIDs_.size() == data.size() );
precice_->readBlockScalarData( dataID, vertexIDs_.size(), vertexIDs_.data(), data.data() );
}
void PreciceAdapter::writeBlockScalarDataToPrecice(const int dataID, std::vector<double> &data)
{
assert( wasCreated_ );
assert( vertexIDs_.size() == data.size() );
precice_->writeBlockScalarData( dataID, vertexIDs_.size(), vertexIDs_.data(), data.data() );
}
bool PreciceAdapter::hasToWriteInitialData()
{
assert( wasCreated_ );
return checkIfActionIsRequired(precice::constants::actionWriteInitialData());
}
void PreciceAdapter::announceInitialDataWritten()
{
assert( wasCreated_ );
precice_->fulfilledAction( precice::constants::actionWriteInitialData() );
}
bool PreciceAdapter::hasToReadIterationCheckpoint()
{
assert( wasCreated_ );
return checkIfActionIsRequired(precice::constants::actionReadIterationCheckpoint());
}
void PreciceAdapter::announceIterationCheckpointRead()
{
assert( wasCreated_ );
actionIsFulfilled( precice::constants::actionReadIterationCheckpoint() );
}
bool PreciceAdapter::hasToWriteIterationCheckpoint()
{
assert( wasCreated_ );
return checkIfActionIsRequired(precice::constants::actionWriteIterationCheckpoint());
}
void PreciceAdapter::announceIterationCheckpointWritten()
{
assert( wasCreated_ );
actionIsFulfilled( precice::constants::actionWriteIterationCheckpoint() );
}
PreciceAdapter::~PreciceAdapter()
{
}
#include "thirdparty/catch2/catch.hpp"
#include<random>
#include<vector>
#include "../src/dumuxpreciceindexwrapper.hh"
template<typename T>
void fillVectors( std::vector<T>& preciceIndices,
std::vector<T>& solverIndices,
const T offset)
{
REQUIRE( preciceIndices.size() == solverIndices.size() );
const size_t numIndices = preciceIndices.size();
for (size_t i = 0; i < numIndices; ++i)
{
preciceIndices[i] = i;
solverIndices[i] = i + offset;
}
}
template<typename T>
void checkDumuxIdMapping( DumuxPreciceIndexMapper<T>& indexMapper,
std::vector<T>& preciceIndices,
std::vector<T>& solverIndices )
{
const size_t numIndices = preciceIndices.size();
for (size_t i = 0; i < numIndices; ++i)
{
REQUIRE( indexMapper.getDumuxId( solverIndices[i] ) == preciceIndices[i] );
}
}
template<typename T>
void checkPreciceIdMapping( DumuxPreciceIndexMapper<T>& indexMapper,
std::vector<T>& preciceIndices,
std::vector<T>& solverIndices )
{
const size_t numIndices = preciceIndices.size();
for (size_t i = 0; i < numIndices; ++i)
{
REQUIRE( indexMapper.getPreciceId( preciceIndices[i] ) == solverIndices[i] );
}
}
template<typename T>
void checkMapper( DumuxPreciceIndexMapper<T>& indexMapper,
std::vector<T>& preciceIndices,
std::vector<T>& solverIndices,
const T numIndices )
{
indexMapper.createMapping( preciceIndices, solverIndices );
SECTION( "Check size" )
{
REQUIRE( indexMapper.getSize() == numIndices );
}
SECTION( "Mapping with offset get solver ID" )
{
checkDumuxIdMapping( indexMapper, preciceIndices, solverIndices );
}
SECTION( "Mapping with offset get precice ID" )
{
checkPreciceIdMapping( indexMapper, preciceIndices, solverIndices );
}
}
TEST_CASE( "DumuxPreciceIndexMapper mapping", "[DumuxPreciceIndexMapper]" )
{
DumuxPreciceIndexMapper<size_t> indexMapper;
const size_t numIndices = 200;
std::vector<size_t> preciceIndices( numIndices );
std::vector<size_t> solverIndices( numIndices );
REQUIRE( preciceIndices.size() == numIndices );
REQUIRE( solverIndices.size() >= numIndices );
SECTION( "Mapping with offset 1" )
{
const size_t offset = 1;
fillVectors( preciceIndices, solverIndices, offset );
checkMapper( indexMapper, preciceIndices, solverIndices, numIndices );
}
SECTION( "Mapping with offset 5" )
{
const size_t offset = 5;
fillVectors( preciceIndices, solverIndices, offset );
checkMapper( indexMapper, preciceIndices, solverIndices, numIndices );
}
SECTION( "Mapping with offset 5" )
{
const size_t offset = 3;
fillVectors( preciceIndices, solverIndices, offset );
std::mt19937 g( 42 );
std::shuffle(preciceIndices.begin(), preciceIndices.end(), g);
std::shuffle(solverIndices.begin(), solverIndices.end(), g);
checkMapper( indexMapper, preciceIndices, solverIndices, numIndices );
}
}
<?xml version="1.0"?>
<precice-configuration>
<log>
<sink type="stream" output="stdout" filter= "(%Severity% > debug) or (%Severity% >= trace and %Module% contains SolverInterfaceImpl)" enabled="false" />
<sink type="stream" output="stdout" enabled="false" />
</log>
<solver-interface dimensions="2">
<data:scalar name="Foo"/>
<data:scalar name="Bar"/>
<mesh name="SolverAMesh">
<use-data name="Foo" />
<use-data name="Bar" />
</mesh>
<mesh name="SolverBMesh">
<use-data name="Foo" />
<use-data name="Bar" />
</mesh>
<participant name="SolverA">
<use-mesh name="SolverAMesh" provide="yes"/>
<use-mesh name="SolverBMesh" from="SolverB"/>
<write-data name="Foo" mesh="SolverAMesh"/>
<read-data name="Bar" mesh="SolverAMesh"/>
</participant>
<participant name="SolverB">
<use-mesh name="SolverBMesh" provide="yes"/>
<use-mesh name="SolverAMesh" from="SolverA"/>
<read-data name="Foo" mesh="SolverBMesh"/>
<write-data name="Bar" mesh="SolverBMesh"/>
<mapping:nearest-neighbor direction="write" from="SolverBMesh" to="SolverAMesh" constraint="consistent"/>
<mapping:nearest-neighbor direction="read" from="SolverAMesh" to="SolverBMesh" constraint="consistent"/>
</participant>
<m2n:sockets from="SolverA" to="SolverB" distribution-type="gather-scatter" network="lo" exchange-directory="." />
<coupling-scheme:serial-explicit>
<participants first="SolverA" second="SolverB"/>
<max-time value="1"/>
<timestep-length value="1" />
<exchange data="Foo" mesh="SolverAMesh" from="SolverA" to="SolverB" initialize="false" />
<exchange data="Bar" mesh="SolverAMesh" from="SolverB" to="SolverA" initialize="false" />
</coupling-scheme:serial-explicit>
</solver-interface>
</precice-configuration>
#include "thirdparty/catch2/catch.hpp"
#include "../include/preciceadapter.hh"
TEST_CASE( "PreciceAdapter without data mapping", "[PreciceAdapter]" )
{
using namespace precice_adapter;
PreciceAdapter& couplingInterface = PreciceAdapter::getInstance();
couplingInterface.announceSolver("SolverA", "precice-basic-test-config.xml", 0, 1);
REQUIRE( couplingInterface.getDimensions() == 2 );
const size_t dim = couplingInterface.getDimensions();
const size_t meshSize = 20;
std::vector<double> coords(meshSize*dim);
for (size_t i = 0; i < meshSize; ++i)
{
coords[dim * i] = double(i);
coords[dim * i + 1] = 0.;
}
couplingInterface.setMesh( "SolverAMesh", meshSize, coords );
// SECTION("Check: Get data ID from string")
{
REQUIRE( couplingInterface.getNumberOfVertices() == meshSize );
}
const auto fooId = couplingInterface.announceQuantity( "Foo" );
const auto barId = couplingInterface.announceQuantity( "Bar" );
// SECTION("Check: Get data ID from string")
{
REQUIRE( couplingInterface.getIdFromName( "Foo" ) == fooId );
REQUIRE( couplingInterface.getIdFromName( "Bar" ) == barId );
}
// SECTION("Check: Get data name from ID")
{
REQUIRE( couplingInterface.getNameFromId( fooId ) == "Foo" );
REQUIRE( couplingInterface.getNameFromId( barId ) == "Bar" );
}
//fooId data
{
//Should be zero since unitilialized
const auto& readData = couplingInterface.getQuantityVector( fooId );
REQUIRE( readData.size() == meshSize );
for (size_t i = 0; i < meshSize; ++i)
{
REQUIRE( readData[i] == Approx( 0. ) );
}
}
{
// Scalar data
std::vector<double> data(meshSize);
for (size_t i = 0; i < meshSize; ++i)
{
data[i] = double(i);
}
std::mt19937 g( 42 );
std::shuffle( data.begin(), data.end(), g);
couplingInterface.writeScalarQuantityVector( fooId, data );
const auto& readData = couplingInterface.getQuantityVector( fooId );
REQUIRE( readData.size() == data.size() );
for (size_t i = 0; i < meshSize; ++i)
{
REQUIRE( readData[i] == Approx(data[i]) );
}
}
//barId data
{
//Should be zero since unitilialized
const auto& readData = couplingInterface.getQuantityVector( barId );
REQUIRE( readData.size() == meshSize );
for (size_t i = 0; i < meshSize; ++i)
{
REQUIRE( readData[i] == Approx( 0. ) );
}
}
{
// Scalar data
std::vector<double> data(meshSize);
for (size_t i = 0; i < meshSize; ++i)
{
data[i] = double(i);
}
std::mt19937 g( 42 );
std::shuffle( data.begin(), data.end(), g);
couplingInterface.writeScalarQuantityVector( barId, data );
const auto& readData = couplingInterface.getQuantityVector( barId );
REQUIRE( readData.size() == data.size() );
for (size_t i = 0; i < meshSize; ++i)
{
REQUIRE( readData[i] == Approx(data[i]) );
}
}
couplingInterface.finalize();
}
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "thirdparty/catch2/catch.hpp"
unsigned int Factorial( unsigned int number ) {
return number > 1 ? Factorial(number-1)*number : 1;
}
TEST_CASE( "Factorials are computed", "[factorial]" ) {
REQUIRE( Factorial(0) == 1 );
REQUIRE( Factorial(1) == 1 );
REQUIRE( Factorial(2) == 2 );
REQUIRE( Factorial(3) == 6 );
REQUIRE( Factorial(10) == 3628800 );
}
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment