IAP GITLAB

Skip to content
Snippets Groups Projects
Commit 79fc8447 authored by ralfulrich's avatar ralfulrich
Browse files

More consistent with style guide, added some more test functions

parent ca19dd14
No related branches found
No related tags found
No related merge requests found
......@@ -19,51 +19,88 @@
namespace corsika::stack {
/**
* @class CombinedParticleInterface
*
* You may combine two StackData object, see class CombinedStackImpl
* below, into one Stack, using a combined StackIterator (aka
* CombinedParticleInterface) interface class.
*
* This allows to add specific information to a given Stack, could
* be special information on a subset of entries
* (e.g. NuclearStackExtension) or also (multi) thinning weights for
* all particles.
*
* Many Stacks can be combined into more complex object.
*
* The two sub-stacks must both provide their independent
* ParticleInterface classes.
*
*/
template <template <typename> typename ParticleInterface,
template <typename> typename ParticleInterfaceAdd, typename StackIterator>
template <template <typename> typename ParticleInterfaceA,
template <typename> typename ParticleInterfaceB, typename StackIterator>
class CombinedParticleInterface
: public ParticleInterfaceAdd<ParticleInterface<StackIterator>> {
: public ParticleInterfaceB<ParticleInterfaceA<StackIterator>> {
using C =
CombinedParticleInterface<ParticleInterface, ParticleInterfaceAdd, StackIterator>;
using T = ParticleInterfaceAdd<ParticleInterface<StackIterator>>;
using I = ParticleInterface<StackIterator>;
using PI_C =
CombinedParticleInterface<ParticleInterfaceA, ParticleInterfaceB, StackIterator>;
using PI_A = ParticleInterfaceA<StackIterator>;
using PI_B = ParticleInterfaceB<ParticleInterfaceA<StackIterator>>;
protected:
using T::GetIndex;
using T::GetStackData;
using PI_B::GetIndex; // choose B, A would also work
using PI_B::GetStackData; // choose B, A would also work
public:
/**
* @name wrapper for user functions
* @{
*
* In this set of functions we call the user-provide
* ParticleInterface SetParticleData(...) methods, either with
* parent particle reference, or w/o.
*
* There is one implicit assumption here: if only one data tuple
* is provided for SetParticleData, the data is passed on to
* ParticleInterfaceA and the ParticleInterfaceB is
* default-initialized. There are many occasions where this is the
* desired behaviour, e.g. for thinning etc.
*
*/
template <typename... Args1>
void SetParticleData(const std::tuple<Args1...> vA) {
I::SetParticleData(vA);
T::SetParticleData();
PI_A::SetParticleData(vA);
PI_B::SetParticleData();
}
template <typename... Args1, typename... Args2>
void SetParticleData(const std::tuple<Args1...> vA, const std::tuple<Args2...> vB) {
I::SetParticleData(vA);
T::SetParticleData(vB);
PI_A::SetParticleData(vA);
PI_B::SetParticleData(vB);
}
template <typename... Args1>
void SetParticleData(C& p, const std::tuple<Args1...> vA) {
void SetParticleData(PI_C& p, const std::tuple<Args1...> vA) {
// static_assert(MT<I>::has_not, "error");
I::SetParticleData(static_cast<I&>(p), vA); // original stack
T::SetParticleData(static_cast<T&>(p)); // addon stack
PI_A::SetParticleData(static_cast<PI_A&>(p), vA); // original stack
PI_B::SetParticleData(static_cast<PI_B&>(p)); // addon stack
}
template <typename... Args1, typename... Args2>
void SetParticleData(C& p, const std::tuple<Args1...> vA,
void SetParticleData(PI_C& p, const std::tuple<Args1...> vA,
const std::tuple<Args2...> vB) {
I::SetParticleData(static_cast<I&>(p), vA);
T::SetParticleData(static_cast<T&>(p), vB);
PI_A::SetParticleData(static_cast<PI_A&>(p), vA);
PI_B::SetParticleData(static_cast<PI_B&>(p), vB);
}
///@}
};
/**
* Memory implementation of the most simple (stupid) particle stack object.
* @class CombinedStackImpl
*
* Memory implementation of a combined data stack.
*
* The two stack data user objects Stack1Impl and Stack2Impl are
* merged into one consistent Stack container object providing
* access to the combined number of data entries.
*/
template <typename Stack1Impl, typename Stack2Impl>
class CombinedStackImpl : public Stack1Impl, public Stack2Impl {
......@@ -118,11 +155,17 @@ namespace corsika::stack {
Stack2Impl::DecrementSize();
}
private:
/// the actual memory to store particle data
}; // end class CombinedStackImpl
/**
* Helper template alias `CombinedStack` to construct new combined
* stack from two stack data objects and a particle readout interface.
*
* Note that the Stack2Impl provides only /additional/ data to
* Stack1Impl. This is important (see above) since tuple data for
* initialization are forwarded to Stack1Impl (first).
*/
template <typename Stack1Impl, typename Stack2Impl, template <typename> typename _PI>
using CombinedStack = Stack<CombinedStackImpl<Stack1Impl, Stack2Impl>, _PI>;
......
......@@ -73,8 +73,8 @@ namespace corsika::stack {
* args is a variadic list of input data that has to match the
* function description in the user defined ParticleInterface::AddSecondary(...)
*/
template <typename... Args>
StackIterator AddSecondary(const Args... args) {
template <typename... TArgs>
StackIterator AddSecondary(const TArgs... args) {
return GetStack().AddSecondary(GetIterator(), args...);
}
......
......@@ -68,10 +68,10 @@ namespace corsika::stack {
* the constructor of the SecondaryView class
* @{
*/
using InnerStackTypeV = Stack<StackDataType, ParticleInterface>;
typedef StackIteratorInterface<typename std::remove_reference<StackDataType>::type,
ParticleInterface, InnerStackTypeV>
StackIteratorV;
using InnerStackTypeValue = Stack<StackDataType, ParticleInterface>;
using StackIteratorValue =
StackIteratorInterface<typename std::remove_reference<StackDataType>::type,
ParticleInterface, InnerStackTypeValue>;
/// @}
public:
......@@ -85,7 +85,8 @@ namespace corsika::stack {
/**
* this is the full type of the declared ParticleInterface: typedef typename
*/
using ParticleType = typename StackIterator::ParticleInterfaceType;
using ParticleType = StackIterator;
using ParticleInterfaceType = typename StackIterator::ParticleInterfaceType;
friend class StackIteratorInterface<
typename std::remove_reference<StackDataType>::type, ParticleInterface, ViewType>;
......@@ -102,22 +103,27 @@ namespace corsika::stack {
SecondaryView(Args... args);
public:
SecondaryView(StackIteratorV& vP)
: Stack<StackDataType&, ParticleInterface>(vP.GetStackData())
, fProjectileIndex(vP.GetIndex()) {}
SecondaryView(StackIteratorValue& vI)
: Stack<StackDataType&, ParticleInterface>(vI.GetStackData())
, fProjectileIndex(vI.GetIndex()) {}
auto GetProjectile() {
StackIterator GetProjectile() {
// NOTE: 0 is special marker here for PROJECTILE, see GetIndexFromIterator
return StackIterator(*this, 0);
}
template <typename... Args>
auto AddSecondary(const Args... v) {
StackIterator proj = GetProjectile();
return AddSecondary(proj, v...);
}
template <typename... Args>
auto AddSecondary(StackIterator& proj, const Args... v) {
InnerStackType::GetStackData().IncrementSize();
const unsigned int idSec = GetSize();
const unsigned int index = InnerStackType::GetStackData().GetSize() - 1;
fIndices.push_back(index);
StackIterator proj = GetProjectile();
// NOTE: "+1" is since "0" is special marker here for PROJECTILE, see
// GetIndexFromIterator
return StackIterator(*this, idSec + 1, proj, v...);
......@@ -164,7 +170,7 @@ namespace corsika::stack {
/**
* need overwrite Stack::Delete, since we want to call SecondaryView::DeleteLast
*/
void Delete(ParticleType p) { Delete(p.GetIterator()); }
void Delete(ParticleInterfaceType p) { Delete(p.GetIterator()); }
/**
* delete last particle on stack by decrementing stack size
......
......@@ -98,8 +98,8 @@ namespace corsika::stack {
typedef StackDataType
StackImpl; ///< this is the type of the user-provided data structure
template <typename SI> //, bool IsBase>
using PIType = ParticleInterface<SI>; //, IsBase>;
template <typename _SI> //, bool IsBase>
using PIType = ParticleInterface<_SI>; //, IsBase>;
/**
* Via the StackIteratorInterface and ConstStackIteratorInterface
......
......@@ -58,20 +58,20 @@ namespace corsika::stack {
ParticleInterface, in this example StackDataType::GetData(const unsigned int
vIndex).
For an example see stack_example.cc, or the
For two examples see stack_example.cc, or the
corsika::processes::sibyll::SibStack class
*/
template <typename StackDataType, template <typename> typename ParticleInterface,
typename StackType =
Stack<StackDataType, ParticleInterface>> //, bool IsBase=true >
typename StackType = Stack<StackDataType, ParticleInterface>>
class StackIteratorInterface
: public ParticleInterface<StackIteratorInterface<StackDataType, ParticleInterface,
StackType>> { //,IsBase> {
: public ParticleInterface<
StackIteratorInterface<StackDataType, ParticleInterface, StackType>> {
public:
using ParticleInterfaceType = ParticleInterface<
StackIteratorInterface<StackDataType, ParticleInterface, StackType>>; //,IsBase>;
using ParticleInterfaceType =
ParticleInterface<corsika::stack::StackIteratorInterface<
StackDataType, ParticleInterface, StackType>>;
// friends are needed for access to protected methods
friend class Stack<StackDataType,
......@@ -110,8 +110,7 @@ namespace corsika::stack {
StackIteratorInterface(StackType& data, const unsigned int index, const Args... args)
: fIndex(index)
, fData(&data) {
ParticleInterfaceType& p = **this;
p.SetParticleData(args...);
(**this).SetParticleData(args...);
}
/** constructor that also sets new values on particle data object, including reference
......@@ -129,9 +128,7 @@ namespace corsika::stack {
StackIteratorInterface& parent, const Args... args)
: fIndex(index)
, fData(&data) {
ParticleInterfaceType& p = **this;
ParticleInterfaceType& pa = *parent;
p.SetParticleData(pa, args...);
(**this).SetParticleData(*parent, args...);
}
public:
......@@ -200,12 +197,12 @@ namespace corsika::stack {
template <typename StackDataType, template <typename> typename ParticleInterface,
typename StackType = Stack<StackDataType, ParticleInterface>>
class ConstStackIteratorInterface
: public ParticleInterface<ConstStackIteratorInterface<
StackDataType, ParticleInterface, StackType>> { //,IsBase> {
: public ParticleInterface<
ConstStackIteratorInterface<StackDataType, ParticleInterface, StackType>> {
public:
typedef ParticleInterface<ConstStackIteratorInterface<
StackDataType, ParticleInterface, StackType>> //,IsBase>
typedef ParticleInterface<
ConstStackIteratorInterface<StackDataType, ParticleInterface, StackType>>
ParticleInterfaceType;
friend class Stack<StackDataType, ParticleInterface>; // for access to GetIndex
......
......@@ -10,6 +10,7 @@
*/
#include <corsika/stack/CombinedStack.h>
#include <corsika/stack/SecondaryView.h>
#include <corsika/stack/Stack.h>
#include <testTestStack.h> // for testing: simple stack. This is a
......@@ -31,6 +32,10 @@ using namespace corsika;
using namespace corsika::stack;
using namespace std;
////////////////////////////////////////////////////////////
// first level test: combine two stacks:
// StackTest = (TestStackData + TestStackData2)
// definition of stack-data object
class TestStackData2 {
......@@ -82,7 +87,7 @@ public:
double GetData2() const { return GetStackData().GetData2(GetIndex()); }
};
// combined stack
// combined stack: StackTest = (TestStackData + TestStackData2)
template <typename StackIter>
using CombinedTestInterfaceType =
corsika::stack::CombinedParticleInterface<TestParticleInterface,
......@@ -196,6 +201,8 @@ TEST_CASE("Combined Stack", "[stack]") {
}
////////////////////////////////////////////////////////////
// next level: combine three stacks:
// combined stack: StackTest2 = ((TestStackData + TestStackData2) + TestStackData3)
// definition of stack-data object
class TestStackData3 {
......@@ -228,6 +235,7 @@ private:
std::vector<double> fData3;
};
// ---------------------------------------
// defintion of a stack-readout object, the iteractor dereference
// operator will deliver access to these function
template <typename T>
......@@ -248,7 +256,7 @@ public:
double GetData3() const { return GetStackData().GetData3(GetIndex()); }
};
// double combined stack
// double combined stack:
// combined stack
template <typename StackIter>
using CombinedTestInterfaceType2 =
......@@ -264,12 +272,14 @@ TEST_CASE("Combined Stack - multi", "[stack]") {
StackTest2 s;
REQUIRE(s.GetSize() == 0);
// add new particle, only provide tuple data for StackTest
auto p1 = s.AddParticle(std::tuple{9.9});
// add new particle, provide tuple data for both StackTest and TestStackData3
auto p2 = s.AddParticle(std::tuple{8.8}, std::tuple{0.1});
// examples to explicitly change data on stack
p2.SetData2(0.1); // not clear why this is needed, need to check
// SetParticleData workflow for more complicated
// settings
// auto p3 = s.AddParticle( std::tuple {8.8}, std::tuple{1.}, std::tuple{0.1} );
p1.SetData3(20.2);
p2.SetData3(10.3);
......@@ -301,3 +311,49 @@ TEST_CASE("Combined Stack - multi", "[stack]") {
REQUIRE(s.GetSize() == 0);
}
}
////////////////////////////////////////////////////////////
// final level test, create SecondaryView on StackTest2
/*
See Issue 161
unfortunately clang does not support this in the same way (yet) as
gcc, so we have to distinguish here. If clang cataches up, we could
remove the clang branch here and also in corsika::Cascade. The gcc
code is much more generic and universal.
*/
template <typename StackIter>
using CombinedTestInterfaceType2 =
corsika::stack::CombinedParticleInterface<StackTest::PIType, TestParticleInterface3,
StackIter>;
using StackTest2 = CombinedStack<typename StackTest::StackImpl, TestStackData3,
CombinedTestInterfaceType2>;
#if defined(__clang__)
using StackTestView = SecondaryView<TestStackData, TestParticleInterface>;
#elif defined(__GNUC__) || defined(__GNUG__)
template <typename S, template <typename> typename _PIType = S::template PIType>
struct MakeView {
using type = corsika::stack::SecondaryView<typename S::StackImpl, _PIType>;
};
using StackTestView = MakeView<StackTest2>::type;
#endif
TEST_CASE("Combined Stack - secondary view") {
SECTION("create secondaries via secondaryview") {
StackTest2 stack;
auto particle = stack.AddParticle(std::tuple{9.9});
StackTestView view(particle);
auto projectile = view.GetProjectile();
projectile.AddSecondary(std::tuple{8.8});
REQUIRE(stack.GetSize() == 2);
}
}
......@@ -33,6 +33,24 @@ using namespace std;
typedef Stack<TestStackData, TestParticleInterface> StackTest;
/*
See Issue 161
unfortunately clang does not support this in the same way (yet) as
gcc, so we have to distinguish here. If clang cataches up, we could
remove the clang branch here and also in corsika::Cascade. The gcc
code is much more generic and universal.
*/
#if defined(__clang__)
using StackTestView = SecondaryView<TestStackData, TestParticleInterface>;
#elif defined(__GNUC__) || defined(__GNUG__)
template <typename S, template <typename> typename _PIType = S::template PIType>
struct MakeView {
using type = corsika::stack::SecondaryView<typename S::StackImpl, _PIType>;
};
using StackTestView = MakeView<StackTest>::type;
#endif
TEST_CASE("SecondaryStack", "[stack]") {
// helper function for sum over stack data
......@@ -51,55 +69,71 @@ TEST_CASE("SecondaryStack", "[stack]") {
auto particle = s.GetNextParticle();
typedef SecondaryView<TestStackData, TestParticleInterface> StackTestView;
StackTestView v(particle);
REQUIRE(v.GetSize() == 0);
StackTestView view(particle);
REQUIRE(view.GetSize() == 0);
{
auto proj = v.GetProjectile();
auto proj = view.GetProjectile();
REQUIRE(proj.GetData() == particle.GetData());
proj.AddSecondary(std::tuple{4.4});
}
v.AddSecondary(std::tuple{4.4});
v.AddSecondary(std::tuple{4.5});
v.AddSecondary(std::tuple{4.6});
view.AddSecondary(std::tuple{4.5});
view.AddSecondary(std::tuple{4.6});
REQUIRE(v.GetSize() == 3);
REQUIRE(view.GetSize() == 3);
REQUIRE(s.GetSize() == 5);
REQUIRE(!v.IsEmpty());
REQUIRE(!view.IsEmpty());
auto sumView = [](const StackTestView& stack) {
double v = 0;
for (const auto& p : stack) { v += p.GetData(); }
return v;
double value = 0;
for (const auto& p : stack) { value += p.GetData(); }
return value;
};
REQUIRE(sum(s) == sumS + 4.4 + 4.5 + 4.6);
REQUIRE(sumView(v) == 4.4 + 4.5 + 4.6);
REQUIRE(sumView(view) == 4.4 + 4.5 + 4.6);
v.DeleteLast();
REQUIRE(v.GetSize() == 2);
view.DeleteLast();
REQUIRE(view.GetSize() == 2);
REQUIRE(s.GetSize() == 4);
REQUIRE(sum(s) == sumS + 4.4 + 4.5);
REQUIRE(sumView(v) == 4.4 + 4.5);
REQUIRE(sumView(view) == 4.4 + 4.5);
auto pDel = v.GetNextParticle();
v.Delete(pDel);
REQUIRE(v.GetSize() == 1);
auto pDel = view.GetNextParticle();
view.Delete(pDel);
REQUIRE(view.GetSize() == 1);
REQUIRE(s.GetSize() == 3);
REQUIRE(sum(s) == sumS + 4.4 + 4.5 - pDel.GetData());
REQUIRE(sumView(v) == 4.4 + 4.5 - pDel.GetData());
REQUIRE(sumView(view) == 4.4 + 4.5 - pDel.GetData());
v.Delete(v.GetNextParticle());
view.Delete(view.GetNextParticle());
REQUIRE(sum(s) == sumS);
REQUIRE(sumView(v) == 0);
REQUIRE(v.IsEmpty());
REQUIRE(sumView(view) == 0);
REQUIRE(view.IsEmpty());
{
auto proj = v.GetProjectile();
auto proj = view.GetProjectile();
REQUIRE(proj.GetData() == particle.GetData());
}
}
SECTION("secondary view, construct from ParticleType") {
StackTest s;
REQUIRE(s.GetSize() == 0);
s.AddParticle(std::tuple{9.9});
s.AddParticle(std::tuple{8.8});
auto iterator = s.GetNextParticle();
typename StackTest::ParticleType& particle = iterator; // as in corsika::Cascade
StackTestView view(particle);
REQUIRE(view.GetSize() == 0);
view.AddSecondary(std::tuple{4.4});
REQUIRE(view.GetSize() == 1);
}
}
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