DPsim
MNASolverPlugin.cpp
1 /* Copyright 2017-2021 Institute for Automation of Complex Power Systems,
2  * EONERC, RWTH Aachen University
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7  *********************************************************************************/
8 
9 #include <Eigen/Eigen>
10 #include <dlfcn.h>
11 #include <dpsim/MNASolverPlugin.h>
12 #include <dpsim/SequentialScheduler.h>
13 
14 using namespace DPsim;
15 using namespace CPS;
16 
17 namespace DPsim {
18 
19 template <typename VarType>
20 MnaSolverPlugin<VarType>::MnaSolverPlugin(String pluginName, String name,
21  CPS::Domain domain,
22  CPS::Logger::Level logLevel)
23  : MnaSolverDirect<VarType>(name, domain, logLevel), mPluginName(pluginName),
24  mPlugin(nullptr), mDlHandle(nullptr) {}
25 
26 template <typename VarType> MnaSolverPlugin<VarType>::~MnaSolverPlugin() {
27  if (mPlugin != nullptr) {
28  mPlugin->cleanup();
29  }
30  if (mDlHandle != nullptr) {
31  dlclose(mDlHandle);
32  }
33 }
34 
35 extern "C" void pluginLogger(const char *str) {
36  CPS::Logger::Log log = CPS::Logger::get("Plugin", CPS::Logger::Level::debug,
37  CPS::Logger::Level::debug);
38  log->info(str);
39 }
40 
41 template <typename VarType>
43  // Start from base matrix
44  this->mVariableSystemMatrix = this->mBaseSystemMatrix;
45 
46  // Now stamp switches into matrix
47  for (auto sw : this->mMNAIntfSwitches)
48  sw->mnaApplySystemMatrixStamp(this->mVariableSystemMatrix);
49 
50  // Now stamp variable elements into matrix
51  for (auto comp : this->mMNAIntfVariableComps)
52  comp->mnaApplySystemMatrixStamp(this->mVariableSystemMatrix);
53 
54  int size = this->mRightSideVector.rows();
55  int nnz = this->mVariableSystemMatrix.nonZeros();
56  struct dpsim_csr_matrix matrix = {
57  .values = this->mVariableSystemMatrix.valuePtr(),
58  .rowIndex = this->mVariableSystemMatrix.outerIndexPtr(),
59  .colIndex = this->mVariableSystemMatrix.innerIndexPtr(),
60  .row_number = size,
61  .nnz = nnz,
62  };
63  // Refactorization of matrix assuming that structure remained
64  // constant by omitting analyzePattern
65  if (mPlugin->lu_decomp(&matrix) != 0) {
66  SPDLOG_LOGGER_ERROR(this->mSLog, "error recomputing decomposition");
67  return;
68  }
69  ++this->mNumRecomputations;
70 }
71 
72 template <typename VarType> void MnaSolverPlugin<VarType>::initialize() {
74  int size = this->mRightSideVector.rows();
75  auto hMat = this->mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)];
76  int nnz = hMat[0].nonZeros();
77 
78  struct dpsim_mna_plugin *(*get_mna_plugin)(const char *);
79 
80  String pluginFileName = mPluginName + ".so";
81 
82  if ((mDlHandle = dlopen(pluginFileName.c_str(), RTLD_NOW)) == nullptr) {
83  SPDLOG_LOGGER_ERROR(this->mSLog, "error opening dynamic library {}: {}",
84  mPluginName, dlerror());
85  throw CPS::SystemError("error opening dynamic library.");
86  }
87 
88  get_mna_plugin = (struct dpsim_mna_plugin * (*)(const char *))
89  dlsym(mDlHandle, "get_mna_plugin");
90  if (get_mna_plugin == NULL) {
91  SPDLOG_LOGGER_ERROR(this->mSLog, "error reading symbol from library {}: {}",
92  mPluginName, dlerror());
93  throw CPS::SystemError("error reading symbol from library.");
94  }
95 
96  if ((mPlugin = get_mna_plugin(mPluginName.c_str())) == nullptr) {
97  SPDLOG_LOGGER_ERROR(this->mSLog, "error getting plugin class");
98  throw CPS::SystemError("error getting plugin class.");
99  }
100 
101  mPlugin->log = pluginLogger;
102 
103  struct dpsim_csr_matrix matrix = {
104  .values = hMat[0].valuePtr(),
105  .rowIndex = hMat[0].outerIndexPtr(),
106  .colIndex = hMat[0].innerIndexPtr(),
107  .row_number = size,
108  .nnz = nnz,
109  };
110 
111  if (mPlugin->init(&matrix) != 0) {
112  SPDLOG_LOGGER_ERROR(this->mSLog, "error initializing plugin");
113  return;
114  }
115 }
116 
117 template <typename VarType> Task::List MnaSolverPlugin<VarType>::getTasks() {
118  Task::List l;
119 
120  for (auto comp : this->mMNAComponents) {
121  for (auto task : comp->mnaTasks()) {
122  l.push_back(task);
123  }
124  }
125  for (auto node : this->mNodes) {
126  for (auto task : node->mnaTasks())
127  l.push_back(task);
128  }
129  // TODO signal components should be moved out of MNA solver
130  for (auto comp : this->mSimSignalComps) {
131  for (auto task : comp->getTasks()) {
132  l.push_back(task);
133  }
134  }
135  l.push_back(std::make_shared<MnaSolverPlugin<VarType>::SolveTask>(*this));
136  l.push_back(std::make_shared<MnaSolverPlugin<VarType>::LogTask>(*this));
137  return l;
138 }
139 
140 template <typename VarType>
141 void MnaSolverPlugin<VarType>::solve(Real time, Int timeStepCount) {
142  // Reset source vector
143  this->mRightSideVector.setZero();
144 
145  // Add together the right side vector (computed by the components'
146  // pre-step tasks)
147  for (const auto &stamp : this->mRightVectorStamps)
148  this->mRightSideVector += *stamp;
149 
150  if (!this->mIsInInitialization)
151  this->updateSwitchStatus();
152 
153  mPlugin->solve((double *)this->mRightSideVector.data(),
154  (double *)this->leftSideVector().data());
155 
156  // TODO split into separate task? (dependent on x, updating all v attributes)
157  for (UInt nodeIdx = 0; nodeIdx < this->mNumNetNodes; ++nodeIdx)
158  this->mNodes[nodeIdx]->mnaUpdateVoltage(**(this->mLeftSideVector));
159 
160  // Components' states will be updated by the post-step tasks
161 }
162 
163 } // namespace DPsim
164 template class DPsim::MnaSolverPlugin<Real>;
165 template class DPsim::MnaSolverPlugin<Complex>;
Solver class using Modified Nodal Analysis (MNA).
Solver class using Modified Nodal Analysis (MNA).
Definition: MNASolver.h:38