DPsim
Loading...
Searching...
No Matches
DAESolver.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 <dpsim-models/SimPowerComp.h>
10#include <dpsim-models/Solver/MNAInterface.h>
11#include <dpsim/DAESolver.h>
12
13using namespace DPsim;
14using namespace CPS;
15
16//#define NVECTOR_DATA(vec) NV_DATA_S (vec) // Returns pointer to the first element of array vec
17
18DAESolver::DAESolver(String name, const CPS::SystemTopology &system, Real dt,
19 Real t0)
20 : Solver(name, CPS::Logger::Level::info), mSystem(system), mTimestep(dt) {
21
22 // Defines offset vector of the residual which is composed as follows:
23 // mOffset[0] = # nodal voltage equations
24 // mOffset[1] = # of components and their respective equations (1 per component for now as inductance is not yet considered)
25
26 mOffsets.push_back(0);
27 mOffsets.push_back(0);
28
29 // Set initial values of all required variables and create IDA solver environment
30 for (IdentifiedObject::Ptr comp : mSystem.mComponents) {
31 auto daeComp = std::dynamic_pointer_cast<DAEInterface>(comp);
32 std::cout << "Added Comp" << std::endl;
33 if (!daeComp)
34 throw CPS::
35 Exception(); // Component does not support the DAE solver interface
36
37 mComponents.push_back(comp);
38 }
39
40 for (auto baseNode : mSystem.mNodes) {
41 // Add nodes to the list and ignore ground nodes.
42 if (!baseNode->isGround()) {
43 auto node = std::dynamic_pointer_cast<CPS::SimNode<Complex>>(baseNode);
44 mNodes.push_back(node);
45 std::cout << "Added Node" << std::endl;
46 }
47 }
48
49 mNEQ = mComponents.size() + (2 * mNodes.size());
50 std::cout << std::endl;
51 std::cout << "Number of Eqn. " << mNEQ << std::endl;
52
53 std::cout << "Processing Nodes" << std::endl;
54 UInt matrixNodeIndexIdx = 0;
55
56 for (UInt idx = 0; idx < mNodes.size(); ++idx) {
57
58 mNodes[idx]->setMatrixNodeIndex(0, matrixNodeIndexIdx);
59 ++matrixNodeIndexIdx;
60 if (mNodes[idx]->phaseType() == PhaseType::ABC) {
61 mNodes[idx]->setMatrixNodeIndex(1, matrixNodeIndexIdx);
62 ++matrixNodeIndexIdx;
63 mNodes[idx]->setMatrixNodeIndex(2, matrixNodeIndexIdx);
64 ++matrixNodeIndexIdx;
65 }
66 }
67
68 std::cout << "Nodes Setup Done" << std::endl;
69 mT0 = t0;
70 initialize();
71}
72
74 int ret;
75 int counter = 0;
76 realtype *sval = NULL, *s_dtval = NULL;
77 std::cout << "Init states" << std::endl;
78
79 // Allocate state vectors
80 state = N_VNew_Serial(mNEQ);
81 dstate_dt = N_VNew_Serial(mNEQ);
82
83 std::cout << "State Init done" << std::endl;
84 std::cout << "Pointer Init" << std::endl;
85 sval = N_VGetArrayPointer_Serial(state);
86 s_dtval = N_VGetArrayPointer_Serial(dstate_dt);
87 std::cout << "Pointer Init done" << std::endl << std::endl;
88
89 for (auto node : mNodes) {
90 // Initialize nodal voltages of state vector
91 Real tempVolt;
92 PhaseType phase = node->phaseType();
93 tempVolt = std::real(node->initialSingleVoltage(phase));
94
95 std::cout << "Node Volt " << counter << ": " << tempVolt << std::endl;
96 sval[counter++] = tempVolt;
97 }
98
99 for (IdentifiedObject::Ptr comp : mComponents) {
100 auto emtComp = std::dynamic_pointer_cast<SimPowerComp<Complex>>(comp);
101 if (emtComp) {
102 emtComp->initializeFromNodesAndTerminals(
103 mSystem.mSystemFrequency); // Set initial values of all components
104 }
105
106 auto daeComp = std::dynamic_pointer_cast<DAEInterface>(comp);
107 if (!daeComp)
108 throw CPS::Exception();
109
110 // Initialize component values of state vector
111 sval[counter++] = std::real(daeComp->daeInitialize());
112 std::cout << "Comp Volt " << counter - 1 << ": " << sval[counter - 1]
113 << std::endl;
114 // sval[counter++] = component inductance;
115
116 // Register residual functions of components
117
118 mResidualFunctions.push_back(
119 [daeComp](double ttime, const double state[], const double dstate_dt[],
120 double resid[], std::vector<int> &off) {
121 daeComp->daeResidual(ttime, state, dstate_dt, resid, off);
122 });
123 }
124
125 for (int j = 0; j < (int)mNodes.size(); j++) {
126 // Initialize nodal current equations
127 sval[counter++] = 0; //TODO: check for correctness
128 std::cout << "Nodal Equation value " << sval[counter - 1] << std::endl;
129 }
130
131 std::cout << std::endl;
132
133 // Set initial values for state derivative for now all equal to 0
134 for (int i = 0; i < (mNEQ); i++) {
135 s_dtval[i] = 0; // TODO: add derivative calculation
136 std::cout << "derivative " << i << ": " << s_dtval[i] << std::endl;
137 }
138
139 std::cout << std::endl;
140
141 std::cout << "Init Tolerances" << std::endl;
142 rtol = RCONST(1.0e-10); // Set relative tolerance
143 abstol = RCONST(1.0e-4); // Set absolute error
144 std::cout << "Init Tolerances done" << std::endl;
145
146 mem = IDACreate();
147 if (mem != NULL)
148 std::cout << "Memory Ok" << std::endl;
149 std::cout << "Define Userdata" << std::endl;
150 // This passes the solver instance as the user_data argument to the residual functions
151 ret = IDASetUserData(mem, this);
152
153 std::cout << "Call IDAInit" << std::endl;
154
155 ret =
157
158 std::cout << "Call IDATolerances" << std::endl;
159 ret = IDASStolerances(mem, rtol, abstol);
160
161 std::cout << "Call IDA Solver Stuff" << std::endl;
162 // Allocate and connect Matrix A and solver LS to IDA
163 A = SUNDenseMatrix(mNEQ, mNEQ);
164 LS = SUNDenseLinearSolver(state, A);
165 ret = IDADlsSetLinearSolver(mem, LS, A);
166
167 //TODO: Optional IDA input functions
168 //ret = IDASetMaxNumSteps(mem, -1); //Max. number of timesteps until tout (-1 = unlimited)
169 //ret = IDASetMaxConvFails(mem, 100); //Max. number of convergence failures at one step
170 (void)ret;
171}
172
173int DAESolver::residualFunctionWrapper(realtype ttime, N_Vector state,
174 N_Vector dstate_dt, N_Vector resid,
175 void *user_data) {
176 DAESolver *self = reinterpret_cast<DAESolver *>(user_data);
177
178 return self->residualFunction(ttime, state, dstate_dt, resid);
179}
180
181int DAESolver::residualFunction(realtype ttime, N_Vector state,
182 N_Vector dstate_dt, N_Vector resid) {
183 mOffsets[0] = 0; // Reset Offset
184 mOffsets[1] = 0; // Reset Offset
185 double *residual = NV_DATA_S(resid);
186 double *tempstate = NV_DATA_S(state);
187 // Solve for all node Voltages
188 for (auto node : mNodes) {
189
190 Real tempVolt = 0;
191
192 tempVolt += std::real(node->singleVoltage());
193
194 residual[mOffsets[0]] = tempVolt - tempstate[mOffsets[0]];
195 mOffsets[0] += 1;
196 }
197
198 // Call all registered component residual functions
199 for (auto resFn : mResidualFunctions) {
200 resFn(ttime, NV_DATA_S(state), NV_DATA_S(dstate_dt), NV_DATA_S(resid),
201 mOffsets);
202 }
203
204 // If successful; positive value if recoverable error, negative if fatal error
205 // TODO: Error handling
206 return 0;
207}
208
209Real DAESolver::step(Real time) {
210
211 Real NextTime = time + mTimestep;
212 std::cout << "Current Time " << NextTime << std::endl;
213 int ret = IDASolve(mem, NextTime, &tret, state, dstate_dt,
214 IDA_NORMAL); // TODO: find alternative to IDA_NORMAL
215
216 if (ret == IDA_SUCCESS) {
217 return NextTime;
218 } else {
219 std::cout << "Ida Error " << ret << std::endl;
220 //throw CPS::Exception();
221 void(IDAGetNumSteps(mem, &interalSteps));
222 void(IDAGetNumResEvals(mem, &resEval));
223 std::cout << "Interal steps: " << interalSteps << std::endl;
224 std::cout << "Res Eval :" << resEval << std::endl;
225 return NextTime;
226 }
227}
228
230 // TODO
231 return Task::List();
232}
233
235 // Releasing all memory allocated by IDA
236 IDAFree(&mem);
237 N_VDestroy(state);
238 N_VDestroy(dstate_dt);
239 SUNLinSolFree(LS);
240 SUNMatDestroy(A);
241}
void * mem
Memory block allocated by IDA.
Definition DAESolver.h:50
N_Vector state
Vector of problem variables.
Definition DAESolver.h:52
N_Vector dstate_dt
Derivates of the state vector with respect to time.
Definition DAESolver.h:54
SUNLinearSolver LS
Linear solver object.
Definition DAESolver.h:64
Real step(Real time)
Solve system for the current time.
Int mNEQ
Number of equations in problem.
Definition DAESolver.h:39
CPS::Task::List getTasks() override
Get tasks for scheduler.
std::vector< Int > mOffsets
Offsets vector for adding new equations to the residual vector.
Definition DAESolver.h:35
Real mTimestep
Constant time step.
Definition DAESolver.h:37
~DAESolver()
Deallocate all memory.
CPS::SimNode< Complex >::List mNodes
Nodes of the Problem.
Definition DAESolver.h:43
DAESolver(String name, const CPS::SystemTopology &system, Real dt, Real mT0)
Create solve object with given parameters.
Definition DAESolver.cpp:18
realtype rtol
Relative tolerance.
Definition DAESolver.h:60
realtype abstol
Scalar absolute tolerance.
Definition DAESolver.h:58
void initialize() final
Initialize Components & Nodes with initial values.
Definition DAESolver.cpp:73
CPS::IdentifiedObject::List mComponents
Components of the Problem.
Definition DAESolver.h:41
static int residualFunctionWrapper(realtype ttime, N_Vector state, N_Vector dstate_dt, N_Vector resid, void *user_data)
Residual Function of entire System.
realtype tret
Time IDA reached while solving.
Definition DAESolver.h:56
SUNMatrix A
Template Jacobian Matrix.
Definition DAESolver.h:62