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  std::vector<SparseMatrix> hMat;
76  int nnz = 0;
77  if (this->mSystemMatrixRecomputation) {
78  SPDLOG_LOGGER_ERROR(this->mSLog, "System matrix recomputation not supported");
79  return;
80  } else {
81  hMat = this->mSwitchedMatrices[std::bitset<SWITCH_NUM>(0)];
82  nnz = hMat[0].nonZeros();
83  }
84 
85  struct dpsim_mna_plugin *(*get_mna_plugin)(const char *);
86 
87  String pluginFileName = mPluginName + ".so";
88 
89  if ((mDlHandle = dlopen(pluginFileName.c_str(), RTLD_NOW)) == nullptr) {
90  SPDLOG_LOGGER_ERROR(this->mSLog, "error opening dynamic library {}: {}",
91  mPluginName, dlerror());
92  throw CPS::SystemError("error opening dynamic library.");
93  }
94 
95  get_mna_plugin = (struct dpsim_mna_plugin * (*)(const char *))
96  dlsym(mDlHandle, "get_mna_plugin");
97  if (get_mna_plugin == NULL) {
98  SPDLOG_LOGGER_ERROR(this->mSLog, "error reading symbol from library {}: {}",
99  mPluginName, dlerror());
100  throw CPS::SystemError("error reading symbol from library.");
101  }
102 
103  if ((mPlugin = get_mna_plugin(mPluginName.c_str())) == nullptr) {
104  SPDLOG_LOGGER_ERROR(this->mSLog, "error getting plugin class");
105  throw CPS::SystemError("error getting plugin class.");
106  }
107 
108  mPlugin->log = pluginLogger;
109 
110  struct dpsim_csr_matrix matrix = {
111  .values = hMat[0].valuePtr(),
112  .rowIndex = hMat[0].outerIndexPtr(),
113  .colIndex = hMat[0].innerIndexPtr(),
114  .row_number = size,
115  .nnz = nnz,
116  };
117 
118  if (mPlugin->init(&matrix) != 0) {
119  SPDLOG_LOGGER_ERROR(this->mSLog, "error initializing plugin");
120  return;
121  }
122 }
123 
124 template <typename VarType> Task::List MnaSolverPlugin<VarType>::getTasks() {
125  Task::List l;
126 
127  for (auto comp : this->mMNAComponents) {
128  for (auto task : comp->mnaTasks()) {
129  l.push_back(task);
130  }
131  }
132  for (auto node : this->mNodes) {
133  for (auto task : node->mnaTasks())
134  l.push_back(task);
135  }
136  // TODO signal components should be moved out of MNA solver
137  for (auto comp : this->mSimSignalComps) {
138  for (auto task : comp->getTasks()) {
139  l.push_back(task);
140  }
141  }
142  l.push_back(std::make_shared<MnaSolverPlugin<VarType>::SolveTask>(*this));
143  l.push_back(std::make_shared<MnaSolverPlugin<VarType>::LogTask>(*this));
144  return l;
145 }
146 
147 template <typename VarType>
148 void MnaSolverPlugin<VarType>::solve(Real time, Int timeStepCount) {
149  // Reset source vector
150  this->mRightSideVector.setZero();
151 
152  // Add together the right side vector (computed by the components'
153  // pre-step tasks)
154  for (const auto &stamp : this->mRightVectorStamps)
155  this->mRightSideVector += *stamp;
156 
157  if (!this->mIsInInitialization)
158  this->updateSwitchStatus();
159 
160  mPlugin->solve((double *)this->mRightSideVector.data(),
161  (double *)this->leftSideVector().data());
162 
163  // TODO split into separate task? (dependent on x, updating all v attributes)
164  for (UInt nodeIdx = 0; nodeIdx < this->mNumNetNodes; ++nodeIdx)
165  this->mNodes[nodeIdx]->mnaUpdateVoltage(**(this->mLeftSideVector));
166 
167  // Components' states will be updated by the post-step tasks
168 }
169 
170 } // namespace DPsim
171 template class DPsim::MnaSolverPlugin<Real>;
172 template class DPsim::MnaSolverPlugin<Complex>;
Solver class using Modified Nodal Analysis (MNA).
Solver class using Modified Nodal Analysis (MNA).
Definition: MNASolver.h:38