DPsim
Loading...
Searching...
No Matches
ODESolver.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/ODESolver.h>
11
12using namespace DPsim;
13
14ODESolver::ODESolver(String name, const CPS::ODEInterface::Ptr &comp,
15 bool implicit_integration, Real timestep)
16 : Solver(name, CPS::Logger::Level::info), mComponent(comp),
17 mImplicitIntegration(implicit_integration), mTimestep(timestep) {
18 mProbDim = mComponent->mOdePreState->get().rows();
19 initialize();
20}
21
23 mStates = N_VNew_Serial(mProbDim);
24 // Set initial value: (Different from DAESolver), only for already initialized components!
25 // XXX
26 N_VSetArrayPointer((**mComponent->mOdePostState).data(), mStates);
27 // Forbid SUNdials from deleting the underlying state vector (which is managed
28 // by our attribute / shared_ptr system)
29 NV_OWN_DATA_S(mStates) = false;
30
31 // Analogous to DAESolver
32 CPS::ODEInterface::Ptr dummy = mComponent;
33 mStSpFunction = [dummy](double t, const double y[], double ydot[]) {
34 dummy->odeStateSpace(t, y, ydot);
35 };
36 mJacFunction = [dummy](double t, const double y[], double fy[], double J[],
37 double tmp1[], double tmp2[], double tmp3[]) {
38 dummy->odeJacobian(t, y, fy, J, tmp1, tmp2, tmp3);
39 };
40}
41
42int ODESolver::StateSpaceWrapper(realtype t, N_Vector y, N_Vector ydot,
43 void *user_data) {
44 ODESolver *self = reinterpret_cast<ODESolver *>(user_data);
45 return self->StateSpace(t, y, ydot);
46}
47
48int ODESolver::StateSpace(realtype t, N_Vector y, N_Vector ydot) {
49 mStSpFunction(t, NV_DATA_S(y), NV_DATA_S(ydot));
50 return 0;
51}
52
53int ODESolver::JacobianWrapper(realtype t, N_Vector y, N_Vector fy, SUNMatrix J,
54 void *user_data, N_Vector tmp1, N_Vector tmp2,
55 N_Vector tmp3) {
56 ODESolver *self = reinterpret_cast<ODESolver *>(user_data);
57 return self->Jacobian(t, y, fy, J, tmp1, tmp2, tmp3);
58}
59
60int ODESolver::Jacobian(realtype t, N_Vector y, N_Vector fy, SUNMatrix J,
61 N_Vector tmp1, N_Vector tmp2, N_Vector tmp3) {
62 mJacFunction(t, NV_DATA_S(y), NV_DATA_S(fy), SM_DATA_D(J), NV_DATA_S(tmp1),
63 NV_DATA_S(tmp2), NV_DATA_S(tmp3));
64 return 0;
65}
66
67Real ODESolver::step(Real initial_time) {
68 // Not absolutely necessary; realtype by default double (same as Real)
69 realtype T0 = (realtype)initial_time;
70 realtype Tf = (realtype)initial_time + mTimestep;
71
73 long int nst;
75 long int netf;
76
77 mComponent->mOdePostState->set(mComponent->mOdePreState->get());
78
79 // Better allocate the arkode memory here to prevent numerical problems
80 mArkode_mem = ARKodeCreate();
81 if (check_flag(mArkode_mem, "ARKodeCreate", 0))
82 mFlag = 1;
83
84 mFlag = ARKodeSetUserData(mArkode_mem, this);
85 if (check_flag(&mFlag, "ARKodeSetUserData", 1))
86 mFlag = 1;
87
88 /* Call ARKodeInit to initialize the integrator memory and specify the
89 * right-hand side function in y'=f(t,y), the inital time T0, and
90 * the initial dependent variable vector y(fluxes+mech. vars).
91 */
94 initial_time, mStates);
95 if (check_flag(&mFlag, "ARKodeInit", 1))
96 throw CPS::Exception();
97
98 // Initialize dense matrix data structure
99 A = SUNDenseMatrix(mProbDim, mProbDim);
100 if (check_flag((void *)A, "SUNDenseMatrix", 0))
101 throw CPS::Exception();
102
103 // Initialize linear solver
104 LS = SUNDenseLinearSolver(mStates, A);
105 if (check_flag((void *)LS, "SUNDenseLinearSolver", 0))
106 throw CPS::Exception();
107
108 // Attach matrix and linear solver
109 mFlag = ARKDlsSetLinearSolver(mArkode_mem, LS, A);
110 if (check_flag(&mFlag, "ARKDlsSetLinearSolver", 1))
111 throw CPS::Exception();
112
113 // Set Jacobian routine
114 mFlag = ARKDlsSetJacFn(mArkode_mem, &ODESolver::JacobianWrapper);
115 if (check_flag(&mFlag, "ARKDlsSetJacFn", 1))
116 throw CPS::Exception();
117 } else {
119 initial_time, mStates);
120 if (check_flag(&mFlag, "ARKodeInit", 1))
121 throw CPS::Exception();
122 }
123
124 mFlag = ARKodeSStolerances(mArkode_mem, reltol, abstol);
125 if (check_flag(&mFlag, "ARKodeSStolerances", 1))
126 mFlag = 1;
127
128 // Main integrator loop
129 realtype t = T0;
130 while (Tf - t > 1.0e-15) {
131 mFlag = ARKode(mArkode_mem, Tf, mStates, &t, ARK_NORMAL);
132 if (check_flag(&mFlag, "ARKode", 1))
133 break;
134 }
135
136 // Get some statistics to check for numerical problems (instability, blow-up etc)
137 mFlag = ARKodeGetNumSteps(mArkode_mem, &nst);
138 if (check_flag(&mFlag, "ARKodeGetNumSteps", 1))
139 return 1;
140 mFlag = ARKodeGetNumErrTestFails(mArkode_mem, &netf);
141 if (check_flag(&mFlag, "ARKodeGetNumErrTestFails", 1))
142 return 1;
143
144 ARKodeFree(&mArkode_mem);
145 SUNLinSolFree(LS);
146 SUNMatDestroy(A);
147
148 // Print statistics:
149 //std::cout << "Number Computing Steps: "<< nst << " Number Error-Test-Fails: " << netf << std::endl;
150 return Tf;
151}
152
153void ODESolver::SolveTask::execute(Real time, Int timeStepCount) {
154 mSolver.step(time);
155}
156
157// ARKode-Error checking functions
158// Check function return value...
159// opt == 0 means SUNDIALS function allocates memory so check if
160// returned NULL pointer
161// opt == 1 means SUNDIALS function returns a flag so check if
162// flag >= 0
163// opt == 2 means function allocates memory so check if returned
164// NULL pointer
165int ODESolver::check_flag(void *flagvalue, const std::string &funcname,
166 int opt) {
167 int *errflag;
168
169 // Check if SUNDIALS function returned NULL pointer - no memory allocated
170 if (opt == 0 && flagvalue == NULL) {
171 std::cout << "\nSUNDIALS_ERROR: " << funcname
172 << " failed - returned NULL pointer\n\n";
173 return 1;
174 }
175
176 // Check if flag < 0
177 else if (opt == 1) {
178 errflag = (int *)flagvalue;
179 if (*errflag < 0) {
180 std::cout << "\nSUNDIALS_ERROR: " << funcname
181 << " failed with flag = " << *errflag << "\n\n";
182 return 1;
183 }
184 }
185
186 // Check if function returned NULL pointer - no memory allocated
187 else if (opt == 2 && flagvalue == NULL) {
188 std::cout << "\nMEMORY_ERROR: " << funcname
189 << " failed - returned NULL pointer\n\n";
190 return 1;
191 }
192
193 return 0;
194}
195
Solver class for ODE (Ordinary Differential Equation) systems.
Definition ODESolver.h:25
ODESolver(String name, const CPS::ODEInterface::Ptr &comp, bool implicit_integration, Real timestep)
Create solve object with corresponding component and information on the integration type.
Definition ODESolver.cpp:14
CPS::ODEInterface::Ptr mComponent
Component to simulate, possible specialized component needed.
Definition ODESolver.h:28
Real step(Real initial_time)
Solve system for the current time.
Definition ODESolver.cpp:67
void * mArkode_mem
Memory block allocated by ARKode.
Definition ODESolver.h:35
int mFlag
Reusable error-checking flag.
Definition ODESolver.h:57
realtype abstol
Scalar absolute tolerance.
Definition ODESolver.h:54
SUNLinearSolver LS
Empty linear solver object.
Definition ODESolver.h:45
int check_flag(void *flagvalue, const std::string &funcname, int opt)
ARKode- standard error detection function; in DAE-solver not detection function is used -> for effici...
N_Vector mStates
State vector.
Definition ODESolver.h:37
void initialize()
Initialize ARKode-solve_environment.
Definition ODESolver.cpp:22
bool mImplicitIntegration
Indicates whether the ODE shall be solved using an implicit scheme.
Definition ODESolver.h:41
~ODESolver()
Deallocate all memory.
Real mTimestep
Constant time step.
Definition ODESolver.h:48
SUNMatrix A
Empty matrix for linear solve in each Newton step while solving the Jacobian Matrix.
Definition ODESolver.h:43
Int mProbDim
Number of differential Variables (states)
Definition ODESolver.h:31
realtype reltol
Relative tolerance.
Definition ODESolver.h:52
static int StateSpaceWrapper(realtype t, N_Vector y, N_Vector ydot, void *user_data)
Use wrappers similar to DAE_Solver.
Definition ODESolver.cpp:42