Aufgrund einer Störung des s3 Storage, könnten in nächster Zeit folgende GitLab Funktionen nicht zur Verfügung stehen: LFS, Container Registry, Job Artifacs, Uploads (Wiki, Bilder, Projekt-Exporte). Wir bitten um Verständnis. Es wird mit Hochdruck an der Behebung des Problems gearbeitet. Weitere Informationen zur Störung des Object Storage finden Sie hier: https://maintenance.itc.rwth-aachen.de/ticket/status/messages/59-object-storage-pilot

Commit 875f558c authored by Niklas Eiling's avatar Niklas Eiling
Browse files

refactor MNASolver so that we can choose an implementation at runtime rather than compile time



move sparse and dense Eigen implementation to new files and keep MNASolver as abstract base class for all MNASolver implementations.
For now the GPU implementations still inherit from MNASolverDense and Sparse, but it probably makes sense to change that.
There is no regression, i.e., we can still use MNASolver without caring about the specific implementation. We only need to use the new MNASolverFactory::factory function to create instances of the solver. By default, the factory choses the most advances implementation available (that is GPUSparse > GPUDense > EigenSparse > EigenDense).
In-depth testing still to be done.
Signed-off-by: Niklas Eiling's avatarNiklas Eiling <niklas.eiling@eonerc.rwth-aachen.de>
parent d1d8e71e
/* Copyright 2017-2020 Institute for Automation of Complex Power Systems,
* EONERC, RWTH Aachen University
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*********************************************************************************/
* EONERC, RWTH Aachen University
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*********************************************************************************/
#pragma once
......@@ -31,22 +31,7 @@
**/
#define SWITCH_NUM sizeof(std::size_t)*8
#ifdef WITH_SPARSE
#define MAT_TYPE SparseMatrix
#else
#define MAT_TYPE Matrix
#endif
namespace DPsim {
/// \brief The implementations of the MNA solvers MnaSolver can support.
///
enum MnaSolverImpl {
EigenDense,
EigenSparse,
CUDADense,
CUDASparse,
};
/// Solver class using Modified Nodal Analysis (MNA).
template <typename VarType>
class MnaSolver : public Solver, public CPS::AttributeList {
......@@ -73,11 +58,6 @@ namespace DPsim {
/// List of simulation nodes
typename CPS::SimNode<VarType>::List mNodes;
/// MNA implementations supported by this compilation
static const std::vector<MnaSolverImpl> mSupportedSolverImpls;
/// MNA implementation chosen for this instance
MnaSolverImpl mSolverImpl;
// #### MNA specific attributes ####
/// List of MNA components with static stamp into system matrix
CPS::MNAInterface::List mMNAComponents;
......@@ -106,17 +86,7 @@ namespace DPsim {
std::vector<Matrix> mLeftSideVectorHarm;
std::vector< CPS::Attribute<Matrix>::Ptr > mLeftVectorHarmAttributes;
/// Base matrix that includes all static MNA elements to speed up recomputation
MAT_TYPE mBaseSystemMatrix;
/// Map of system matrices where the key is the bitset describing the switch states
std::unordered_map< std::bitset<SWITCH_NUM>, MAT_TYPE > mSwitchedMatrices;
std::unordered_map< std::bitset<SWITCH_NUM>, std::vector<Matrix> > mSwitchedMatricesHarm;
#ifdef WITH_SPARSE
/// Map of LU factorizations related to the system matrices
std::unordered_map< std::bitset<SWITCH_NUM>, CPS::LUFactorizedSparse > mLuFactorizations;
#else
std::unordered_map< std::bitset<SWITCH_NUM>, CPS::LUFactorized > mLuFactorizations;
#endif
std::unordered_map< std::bitset<SWITCH_NUM>, std::vector<CPS::LUFactorized> > mLuFactorizationsHarm;
// #### Attributes related to switching ####
......@@ -135,6 +105,11 @@ namespace DPsim {
/// Right side vector logger
std::shared_ptr<DataLogger> mRightVectorLog;
/// Constructor should not be called by users but by Simulation
MnaSolver(String name,
CPS::Domain domain = CPS::Domain::DP,
CPS::Logger::Level logLevel = CPS::Logger::Level::info);
/// Initialization of individual components
void initializeComponents();
/// Initialization of system matrices and source vector
......@@ -154,108 +129,46 @@ namespace DPsim {
void steadyStateInitialization();
/// Create left and right side vector
void createEmptyVectors();
/// Create system matrix
void createEmptySystemMatrix();
/// Logging of system matrices and source vector
void logSystemMatrices();
virtual void logSystemMatrices() = 0;
/// Sets all entries in the matrix with the given switch index to zero
virtual void switchedMatrixEmpty(std::size_t index) = 0;
/// Create system matrix
virtual void createEmptySystemMatrix() = 0;
/// Applies a component stamp to the matrix with the given switch index
virtual void switchedMatrixStamp(std::size_t index, std::vector<std::shared_ptr<CPS::MNAInterface>>& comp) = 0;
/// Create a solve task for this solver implementation
virtual std::shared_ptr<CPS::Task> createSolveTask() = 0;
/// Create a solve task for this solver implementation
virtual std::shared_ptr<CPS::Task> createLogTask() = 0;
/// Create a solve task for this solver implementation
virtual std::shared_ptr<CPS::Task> createSolveTaskHarm(UInt freqIdx) = 0;
// #### Scheduler Task Methods ####
/// Solves system for single frequency
virtual void solve(Real time, Int timeStepCount);
virtual void solve(Real time, Int timeStepCount) = 0;
/// Solves system for multiple frequencies
void solveWithHarmonics(Real time, Int timeStepCount, Int freqIdx);
virtual void solveWithHarmonics(Real time, Int timeStepCount, Int freqIdx) = 0;
/// Logs left and right vector
void log(Real time, Int timeStepCount);
virtual void log(Real time, Int timeStepCount) override;
public:
/// Constructor should not be called by users but by Simulation
/// sovlerImpl: choose the most advanced solver implementation available by default
MnaSolver(String name,
CPS::Domain domain = CPS::Domain::DP,
CPS::Logger::Level logLevel = CPS::Logger::Level::info,
MnaSolverImpl solverImpl = *mSupportedSolverImpls.end());
/// Destructor
virtual ~MnaSolver() { };
/// Calls subroutines to set up everything that is required before simulation
void initialize();
virtual void initialize() override;
// #### Setter and Getter ####
///
void setSystem(const CPS::SystemTopology &system);
virtual void setSystem(const CPS::SystemTopology &system) override;
///
Matrix& leftSideVector() { return mLeftSideVector; }
///
Matrix& rightSideVector() { return mRightSideVector; }
///
virtual CPS::Task::List getTasks();
///
MAT_TYPE& systemMatrix() {
return mSwitchedMatrices[mCurrentSwitchStatus];
}
// #### MNA Solver Tasks ####
///
class SolveTask : public CPS::Task {
public:
SolveTask(MnaSolver<VarType>& solver) :
Task(solver.mName + ".Solve"), mSolver(solver) {
for (auto it : solver.mMNAComponents) {
if (it->template attribute<Matrix>("right_vector")->get().size() != 0)
mAttributeDependencies.push_back(it->attribute("right_vector"));
}
for (auto node : solver.mNodes) {
mModifiedAttributes.push_back(node->attribute("v"));
}
mModifiedAttributes.push_back(solver.attribute("left_vector"));
}
void execute(Real time, Int timeStepCount) { mSolver.solve(time, timeStepCount); }
private:
MnaSolver<VarType>& mSolver;
};
///
class SolveTaskHarm : public CPS::Task {
public:
SolveTaskHarm(MnaSolver<VarType>& solver, UInt freqIdx) :
Task(solver.mName + ".Solve"), mSolver(solver), mFreqIdx(freqIdx) {
for (auto it : solver.mMNAComponents) {
if (it->template attribute<Matrix>("right_vector")->get().size() != 0)
mAttributeDependencies.push_back(it->attribute("right_vector"));
}
for (auto node : solver.mNodes) {
mModifiedAttributes.push_back(node->attribute("v"));
}
for(Int freq = 0; freq < solver.mSystem.mFrequencies.size(); ++freq) {
mModifiedAttributes.push_back(solver.attribute("left_vector_"+std::to_string(freq)));
}
}
void execute(Real time, Int timeStepCount) { mSolver.solveWithHarmonics(time, timeStepCount, mFreqIdx); }
private:
MnaSolver<VarType>& mSolver;
UInt mFreqIdx;
};
///
class LogTask : public CPS::Task {
public:
LogTask(MnaSolver<VarType>& solver) :
Task(solver.mName + ".Log"), mSolver(solver) {
mAttributeDependencies.push_back(solver.attribute("left_vector"));
mModifiedAttributes.push_back(Scheduler::external);
}
void execute(Real time, Int timeStepCount) { mSolver.log(time, timeStepCount); }
virtual CPS::Task::List getTasks() override;
private:
MnaSolver<VarType>& mSolver;
};
};
}
/* Copyright 2017-2020 Institute for Automation of Complex Power Systems,
* EONERC, RWTH Aachen University
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*********************************************************************************/
#pragma once
#include <iostream>
#include <vector>
#include <list>
#include <unordered_map>
#include <bitset>
#include <dpsim/Config.h>
#include <dpsim/Solver.h>
#include <dpsim/DataLogger.h>
#include <cps/AttributeList.h>
#include <cps/Solver/MNASwitchInterface.h>
#include <cps/Solver/MNAVariableCompInterface.h>
#include <cps/SimSignalComp.h>
#include <cps/SimPowerComp.h>
#include <dpsim/MNASolver.h>
namespace DPsim {
/// Solver class using Modified Nodal Analysis (MNA).
template <typename VarType>
class MnaSolverEigenDense : public MnaSolver<VarType> {
protected:
/// Base matrix that includes all static MNA elements to speed up recomputation
Matrix mBaseSystemMatrix;
/// Map of system matrices where the key is the bitset describing the switch states
std::unordered_map< std::bitset<SWITCH_NUM>, Matrix > mSwitchedMatrices;
/// Map of LU factorizations related to the system matrices
std::unordered_map< std::bitset<SWITCH_NUM>, CPS::LUFactorized > mLuFactorizations;
using MnaSolver<VarType>::mSwitches;
using MnaSolver<VarType>::mRightSideVector;
using MnaSolver<VarType>::mLeftSideVector;
using MnaSolver<VarType>::mCurrentSwitchStatus;
using MnaSolver<VarType>::mRightVectorStamps;
using MnaSolver<VarType>::mNumNetNodes;
using MnaSolver<VarType>::mNodes;
using MnaSolver<VarType>::mIsInInitialization;
using MnaSolver<VarType>::mRightSideVectorHarm;
using MnaSolver<VarType>::mLeftSideVectorHarm;
using MnaSolver<VarType>::mLuFactorizationsHarm;
using MnaSolver<VarType>::mFrequencyParallel;
using MnaSolver<VarType>::mSwitchedMatricesHarm;
using MnaSolver<VarType>::mSLog;
/// Sets all entries in the matrix with the given switch index to zero
virtual void switchedMatrixEmpty(std::size_t index) override;
/// Create system matrix
virtual void createEmptySystemMatrix() override;
/// Applies a component stamp to the matrix with the given switch index
virtual void switchedMatrixStamp(std::size_t index, std::vector<std::shared_ptr<CPS::MNAInterface>>& comp) override;
/// Create a solve task for this solver implementation
virtual std::shared_ptr<CPS::Task> createSolveTask() override;
/// Create a solve task for this solver implementation
virtual std::shared_ptr<CPS::Task> createLogTask() override;
/// Create a solve task for this solver implementation
virtual std::shared_ptr<CPS::Task> createSolveTaskHarm(UInt freqIdx) override;
/// Logging of system matrices and source vector
virtual void logSystemMatrices() override;
// #### Scheduler Task Methods ####
/// Solves system for single frequency
virtual void solve(Real time, Int timeStepCount) override;
/// Solves system for multiple frequencies
virtual void solveWithHarmonics(Real time, Int timeStepCount, Int freqIdx) override;
public:
/// Constructor should not be called by users but by Simulation
/// sovlerImpl: choose the most advanced solver implementation available by default
MnaSolverEigenDense(String name,
CPS::Domain domain = CPS::Domain::DP,
CPS::Logger::Level logLevel = CPS::Logger::Level::info);
/// Destructor
virtual ~MnaSolverEigenDense() { };
// #### MNA Solver Tasks ####
///
class SolveTask : public CPS::Task {
public:
SolveTask(MnaSolverEigenDense<VarType>& solver) :
Task(solver.mName + ".Solve"), mSolver(solver) {
for (auto it : solver.mMNAComponents) {
if (it->template attribute<Matrix>("right_vector")->get().size() != 0)
mAttributeDependencies.push_back(it->attribute("right_vector"));
}
for (auto node : solver.mNodes) {
mModifiedAttributes.push_back(node->attribute("v"));
}
mModifiedAttributes.push_back(solver.attribute("left_vector"));
}
void execute(Real time, Int timeStepCount) { mSolver.solve(time, timeStepCount); }
private:
MnaSolverEigenDense<VarType>& mSolver;
};
///
class SolveTaskHarm : public CPS::Task {
public:
SolveTaskHarm(MnaSolverEigenDense<VarType>& solver, UInt freqIdx) :
Task(solver.mName + ".Solve"), mSolver(solver), mFreqIdx(freqIdx) {
for (auto it : solver.mMNAComponents) {
if (it->template attribute<Matrix>("right_vector")->get().size() != 0)
mAttributeDependencies.push_back(it->attribute("right_vector"));
}
for (auto node : solver.mNodes) {
mModifiedAttributes.push_back(node->attribute("v"));
}
for(Int freq = 0; freq < solver.mSystem.mFrequencies.size(); ++freq) {
mModifiedAttributes.push_back(solver.attribute("left_vector_"+std::to_string(freq)));
}
}
void execute(Real time, Int timeStepCount) { mSolver.solveWithHarmonics(time, timeStepCount, mFreqIdx); }
private:
MnaSolverEigenDense<VarType>& mSolver;
UInt mFreqIdx;
};
///
class LogTask : public CPS::Task {
public:
LogTask(MnaSolverEigenDense<VarType>& solver) :
Task(solver.mName + ".Log"), mSolver(solver) {
mAttributeDependencies.push_back(solver.attribute("left_vector"));
mModifiedAttributes.push_back(Scheduler::external);
}
void execute(Real time, Int timeStepCount) { mSolver.log(time, timeStepCount); }
private:
MnaSolverEigenDense<VarType>& mSolver;
};
};
}
/* Copyright 2017-2020 Institute for Automation of Complex Power Systems,
* EONERC, RWTH Aachen University
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*********************************************************************************/
#pragma once
#include <iostream>
#include <vector>
#include <list>
#include <unordered_map>
#include <bitset>
#include <dpsim/Config.h>
#include <dpsim/Solver.h>
#include <dpsim/DataLogger.h>
#include <cps/AttributeList.h>
#include <cps/Solver/MNASwitchInterface.h>
#include <cps/Solver/MNAVariableCompInterface.h>
#include <cps/SimSignalComp.h>
#include <cps/SimPowerComp.h>
#include <dpsim/MNASolver.h>
namespace DPsim {
/// Solver class using Modified Nodal Analysis (MNA).
template <typename VarType>
class MnaSolverEigenSparse : public MnaSolver<VarType> {
protected:
/// Base matrix that includes all static MNA elements to speed up recomputation
SparseMatrix mBaseSystemMatrix;
/// Map of system matrices where the key is the bitset describing the switch states
std::unordered_map< std::bitset<SWITCH_NUM>, SparseMatrix > mSwitchedMatrices;
/// Map of LU factorizations related to the system matrices
std::unordered_map< std::bitset<SWITCH_NUM>, CPS::LUFactorizedSparse > mLuFactorizations;
using MnaSolver<VarType>::mSwitches;
using MnaSolver<VarType>::mRightSideVector;
using MnaSolver<VarType>::mLeftSideVector;
using MnaSolver<VarType>::mCurrentSwitchStatus;
using MnaSolver<VarType>::mRightVectorStamps;
using MnaSolver<VarType>::mNumNetNodes;
using MnaSolver<VarType>::mNodes;
using MnaSolver<VarType>::mIsInInitialization;
using MnaSolver<VarType>::mRightSideVectorHarm;
using MnaSolver<VarType>::mLeftSideVectorHarm;
using MnaSolver<VarType>::mLuFactorizationsHarm;
using MnaSolver<VarType>::mFrequencyParallel;
using MnaSolver<VarType>::mSwitchedMatricesHarm;
using MnaSolver<VarType>::mSLog;
/// Sets all entries in the matrix with the given switch index to zero
virtual void switchedMatrixEmpty(std::size_t index) override;
/// Create system matrix
virtual void createEmptySystemMatrix() override;
/// Applies a component stamp to the matrix with the given switch index
virtual void switchedMatrixStamp(std::size_t index, std::vector<std::shared_ptr<CPS::MNAInterface>>& comp) override;
/// Create a solve task for this solver implementation
virtual std::shared_ptr<CPS::Task> createSolveTask() override;
/// Create a solve task for this solver implementation
virtual std::shared_ptr<CPS::Task> createLogTask() override;
/// Create a solve task for this solver implementation
virtual std::shared_ptr<CPS::Task> createSolveTaskHarm(UInt freqIdx) override;
/// Logging of system matrices and source vector
virtual void logSystemMatrices() override;
// #### Scheduler Task Methods ####
/// Solves system for single frequency
virtual void solve(Real time, Int timeStepCount) override;
/// Solves system for multiple frequencies
virtual void solveWithHarmonics(Real time, Int timeStepCount, Int freqIdx) override;
public:
/// Constructor should not be called by users but by Simulation
/// sovlerImpl: choose the most advanced solver implementation available by default
MnaSolverEigenSparse(String name,
CPS::Domain domain = CPS::Domain::DP,
CPS::Logger::Level logLevel = CPS::Logger::Level::info);
/// Destructor
virtual ~MnaSolverEigenSparse() { };
// #### MNA Solver Tasks ####
///
class SolveTask : public CPS::Task {
public:
SolveTask(MnaSolverEigenSparse<VarType>& solver) :
Task(solver.mName + ".Solve"), mSolver(solver) {
for (auto it : solver.mMNAComponents) {
if (it->template attribute<Matrix>("right_vector")->get().size() != 0)
mAttributeDependencies.push_back(it->attribute("right_vector"));
}
for (auto node : solver.mNodes) {
mModifiedAttributes.push_back(node->attribute("v"));
}
mModifiedAttributes.push_back(solver.attribute("left_vector"));
}
void execute(Real time, Int timeStepCount) { mSolver.solve(time, timeStepCount); }
private:
MnaSolverEigenSparse<VarType>& mSolver;
};
///
class SolveTaskHarm : public CPS::Task {
public:
SolveTaskHarm(MnaSolverEigenSparse<VarType>& solver, UInt freqIdx) :
Task(solver.mName + ".Solve"), mSolver(solver), mFreqIdx(freqIdx) {
for (auto it : solver.mMNAComponents) {
if (it->template attribute<Matrix>("right_vector")->get().size() != 0)
mAttributeDependencies.push_back(it->attribute("right_vector"));
}
for (auto node : solver.mNodes) {
mModifiedAttributes.push_back(node->attribute("v"));
}
for(Int freq = 0; freq < solver.mSystem.mFrequencies.size(); ++freq) {
mModifiedAttributes.push_back(solver.attribute("left_vector_"+std::to_string(freq)));
}
}
void execute(Real time, Int timeStepCount) { mSolver.solveWithHarmonics(time, timeStepCount, mFreqIdx); }
private:
MnaSolverEigenSparse<VarType>& mSolver;
UInt mFreqIdx;
};
///
class LogTask : public CPS::Task {
public:
LogTask(MnaSolverEigenSparse<VarType>& solver) :
Task(solver.mName + ".Log"), mSolver(solver) {
mAttributeDependencies.push_back(solver.attribute("left_vector"));
mModifiedAttributes.push_back(Scheduler::external);
}
void execute(Real time, Int timeStepCount) { mSolver.log(time, timeStepCount); }
private:
MnaSolverEigenSparse<VarType>& mSolver;
};
};
}
/* Copyright 2017-2020 Institute for Automation of Complex Power Systems,
* EONERC, RWTH Aachen University
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*********************************************************************************/
#pragma once
#include <dpsim/MNASolver.h>
#include <dpsim/MNASolverEigenDense.h>
#ifdef WITH_SPARSE
#include <dpsim/MNASolverEigenSparse.h>
#endif
#ifdef WITH_CUDA
#include <dpsim/MNASolverGpuDense.h>
#ifdef WITH_SPARSE
#include <dpsim/MNASolverGpuSparse.h>
#endif
#endif
namespace DPsim {
class MnaSolverFactory {
public:
/// \brief The implementations of the MNA solvers MnaSolver can support.
///
enum MnaSolverImpl {
EigenDense,
EigenSparse,
CUDADense,
CUDASparse,
};
/// MNA implementations supported by this compilation
static const std::vector<MnaSolverImpl> mSupportedSolverImpls(void) {
static std::vector<MnaSolverImpl> ret = {
EigenDense,
#ifdef WITH_SPARSE
EigenSparse,
#endif //WITH_SPARSE
#ifdef WITH_CUDA
CUDADense,
#ifdef WITH_SPARSE
CUDASparse,
#endif //WITH_SPARSE
#endif //WITH_CUDA
};
return ret;
}
/// sovlerImpl: choose the most advanced solver implementation available by default
template <typename VarType>
static std::shared_ptr<MnaSolver<VarType>> factory(String name,
CPS::Domain domain = CPS::Domain::DP,
CPS::Logger::Level logLevel = CPS::Logger::Level::info,
MnaSolverImpl implementation = *mSupportedSolverImpls().end())
{
switch(implementation) {
case MnaSolverImpl::EigenDense:
return std::make_shared<MnaSolverEigenDense<VarType>>(name, domain, logLevel);
#ifdef WITH_SPARSE
case MnaSolverImpl::EigenSparse:
return std::make_shared<MnaSolverEigenSparse<VarType>>(name, domain, logLevel);
#endif
#ifdef WITH_CUDA
case MnaSolverImpl::CUDADense:
return std::make_shared<MnaSolverGpuDense<VarType>>(name, domain, logLevel);
#ifdef WITH_SPARSE
case MnaSolverImpl::CUDASparse:
return std::make_shared<MnaSolverGpuSparse<VarType>>(name, domain, logLevel);
#endif
#endif
default:
throw CPS::SystemError("unsupported MNA implementation.");
}
}
};