Skip to content

Commit c8ec782

Browse files
authored
Implement Kinsol as non-linear solver for non-linear loops over components (#815)
This reverts commit 839c272.
1 parent d26544e commit c8ec782

14 files changed

Lines changed: 785 additions & 146 deletions

src/OMSimulatorLib/AlgLoop.cpp

Lines changed: 541 additions & 0 deletions
Large diffs are not rendered by default.

src/OMSimulatorLib/AlgLoop.h

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* This file is part of OpenModelica.
3+
*
4+
* Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC),
5+
* c/o Linköpings universitet, Department of Computer and Information Science,
6+
* SE-58183 Linköping, Sweden.
7+
*
8+
* All rights reserved.
9+
*
10+
* THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR
11+
* THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2.
12+
* ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13+
* RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3,
14+
* ACCORDING TO RECIPIENTS CHOICE.
15+
*
16+
* The OpenModelica software and the Open Source Modelica
17+
* Consortium (OSMC) Public License (OSMC-PL) are obtained
18+
* from OSMC, either from the above address,
19+
* from the URLs: http://www.ida.liu.se/projects/OpenModelica or
20+
* http://www.openmodelica.org, and in the OpenModelica distribution.
21+
* GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html.
22+
*
23+
* This program is distributed WITHOUT ANY WARRANTY; without
24+
* even the implied warranty of MERCHANTABILITY or FITNESS
25+
* FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
26+
* IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
27+
*
28+
* See the full OSMC Public License conditions for more details.
29+
*
30+
*/
31+
32+
#ifndef _OMS_ALGLOOP_H_
33+
#define _OMS_ALGLOOP_H_
34+
35+
#include <string>
36+
#include <vector>
37+
#include "Types.h"
38+
#include "DirectedGraph.h"
39+
40+
#include <kinsol/kinsol.h>
41+
#include <nvector/nvector_serial.h>
42+
#include <sunlinsol/sunlinsol_dense.h> /* Default dense linear solver */
43+
44+
namespace oms
45+
{
46+
class System;
47+
class DirectedGraph;
48+
49+
typedef struct KINSOL_USER_DATA {
50+
System* syst;
51+
DirectedGraph* graph;
52+
const int algLoopNumber;
53+
}KINSOL_USER_DATA;
54+
55+
class KinsolSolver
56+
{
57+
public:
58+
~KinsolSolver();
59+
static KinsolSolver* NewKinsolSolver(const int algLoopNum, const unsigned int size, double absoluteTolerance);
60+
oms_status_enu_t kinsolSolve(System& syst, DirectedGraph& graph);
61+
62+
private:
63+
/* tolerances */
64+
double fnormtol; /* function tolerance */
65+
66+
/* work arrays */
67+
N_Vector initialGuess;
68+
N_Vector uScale; /* Scaling vector for u */
69+
N_Vector fScale; /* Scaling vector for f(u) */
70+
N_Vector fTmp; /* Vector used for tmp computations */
71+
72+
/* kinsol internal data */
73+
void* kinsolMemory;
74+
void* userData;
75+
int size;
76+
77+
/* linear solver data */
78+
SUNLinearSolver linSol; /* Linear solver object used by KINSOL */
79+
N_Vector y; /* Template for cloning vectors needed inside linear solver */
80+
SUNMatrix J; /* (Non-)Sparse matrix template for cloning matrices needed within linear solver */
81+
82+
/* member function */
83+
static int nlsKinsolResiduals(N_Vector uu, N_Vector fval, void *userData);
84+
static void sundialsErrorHandlerFunction(int error_code, const char *module, const char *function, char *msg, void *userData);
85+
static void sundialsInfoHandlerFunction(const char *module, const char *function, char *msg, void *userData);
86+
};
87+
88+
class AlgLoop
89+
{
90+
public:
91+
AlgLoop(oms_alg_solver_enu_t method, double absTol, oms_ssc_t SCC, const int systNumber);
92+
93+
oms_ssc_t getSCC() {return SCC;}
94+
oms_status_enu_t solveAlgLoop(System& syst, DirectedGraph& graph);
95+
std::string getAlgSolverName();
96+
std::string dumpLoopVars(DirectedGraph& graph);
97+
98+
private:
99+
oms_alg_solver_enu_t algSolverMethod;
100+
oms_status_enu_t fixPointIteration(System& syst, DirectedGraph& graph);
101+
102+
KinsolSolver* kinsolData;
103+
104+
/* Loop data */
105+
const oms_ssc_t SCC; ///< Strong connected components
106+
const int systNumber;
107+
double absoluteTolerance;
108+
};
109+
}
110+
111+
#endif // _OMS_ALGLOOP_H_

src/OMSimulatorLib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ ELSE ()
2828
set(TLM_STRING "-notlm")
2929
ENDIF ()
3030

31+
list(APPEND OMSIMULATORLIB_SOURCES AlgLoop.cpp)
3132
list(APPEND OMSIMULATORLIB_SOURCES BusConnector.cpp)
3233
list(APPEND OMSIMULATORLIB_SOURCES Clock.cpp)
3334
list(APPEND OMSIMULATORLIB_SOURCES Clocks.cpp)

src/OMSimulatorLib/DirectedGraph.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ void oms::DirectedGraph::includeGraph(const oms::DirectedGraph& graph, const oms
145145
addEdge(graph.nodes[graph.edges[i].first].addPrefix(prefix), graph.nodes[graph.edges[i].second].addPrefix(prefix));
146146
}
147147

148-
int oms::DirectedGraph::getEdgeIndex(const std::vector< std::pair<int, int> >& edges, int from, int to)
148+
int oms::DirectedGraph::getEdgeIndex(const oms_ssc_t& edges, int from, int to)
149149
{
150150
for (int i = 0; i < edges.size(); ++i)
151151
if (edges[i].first == from && edges[i].second == to)
@@ -243,7 +243,7 @@ std::deque< std::vector<int> > oms::DirectedGraph::getSCCs()
243243
return components;
244244
}
245245

246-
const std::vector< std::vector< std::pair<int, int> > >& oms::DirectedGraph::getSortedConnections()
246+
const std::vector< oms_ssc_t >& oms::DirectedGraph::getSortedConnections()
247247
{
248248
if (!sortedConnectionsAreValid)
249249
calculateSortedConnections();
@@ -253,7 +253,7 @@ const std::vector< std::vector< std::pair<int, int> > >& oms::DirectedGraph::get
253253
void oms::DirectedGraph::calculateSortedConnections()
254254
{
255255
std::deque< std::vector<int> > components = getSCCs();
256-
std::vector< std::pair<int, int> > SCC;
256+
oms_ssc_t SCC;
257257
sortedConnections.clear();
258258

259259
for (int i = 0; i < components.size(); ++i)

src/OMSimulatorLib/DirectedGraph.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@
4343
#include <string>
4444
#include <vector>
4545

46+
/**
47+
* @brief Strong connected components data type.
48+
*
49+
* A vector of pairs of connected components.
50+
*/
51+
typedef std::vector< std::pair<int, int> > oms_ssc_t;
52+
4653
namespace oms
4754
{
4855
class DirectedGraph
@@ -60,24 +67,24 @@ namespace oms
6067

6168
void includeGraph(const DirectedGraph& graph, const ComRef& prefix);
6269

63-
const std::vector< std::vector< std::pair<int, int> > >& getSortedConnections();
70+
const std::vector< oms_ssc_t >& getSortedConnections();
6471

6572
const std::vector<Connector>& getNodes() const {return nodes;}
66-
const std::vector< std::pair<int, int> >& getEdges() const {return edges;}
73+
const oms_ssc_t& getEdges() const {return edges;}
6774

6875
private:
6976
std::deque< std::vector<int> > getSCCs();
7077
void calculateSortedConnections();
7178
void strongconnect(int v, std::vector< std::vector<int> > G, int& index, int *d, int *low, std::stack<int>& S, bool *stacked, std::deque< std::vector<int> >& components);
7279

73-
static int getEdgeIndex(const std::vector< std::pair<int, int> >& edges, int from, int to);
80+
static int getEdgeIndex(const oms_ssc_t& edges, int from, int to);
7481

7582
private:
7683
std::vector<Connector> nodes;
77-
std::vector< std::pair<int, int> > edges;
84+
oms_ssc_t edges;
7885

7986
std::vector< std::vector<int> > G;
80-
std::vector< std::vector< std::pair<int, int> > > sortedConnections;
87+
std::vector< oms_ssc_t > sortedConnections;
8188
bool sortedConnectionsAreValid;
8289
};
8390
}

src/OMSimulatorLib/Flags.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ oms::Flags::~Flags()
6262
void oms::Flags::setDefaults()
6363
{
6464
addParametersToCSV = false;
65+
algLoopSolver = oms_alg_solver_fixedpoint;
6566
defaultModeIsCS = false;
6667
deleteTempFiles = true;
6768
emitEvents = true;
@@ -178,6 +179,17 @@ oms_status_enu_t oms::Flags::AddParametersToCSV(const std::string& value)
178179
return oms_status_ok;
179180
}
180181

182+
oms_status_enu_t oms::Flags::AlgLoopSolver(const std::string& value)
183+
{
184+
if (value == "fixedpoint")
185+
GetInstance().algLoopSolver = oms_alg_solver_fixedpoint;
186+
else if (value == "kinsol")
187+
GetInstance().algLoopSolver = oms_alg_solver_kinsol;
188+
else
189+
return logError("Invalid solver method");
190+
return oms_status_ok;
191+
}
192+
181193
oms_status_enu_t oms::Flags::ClearAllOptions(const std::string& value)
182194
{
183195
GetInstance().setDefaults();

src/OMSimulatorLib/Flags.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ namespace oms
5555
public:
5656
static oms_status_enu_t SetCommandLineOption(const std::string& cmd);
5757

58+
static oms_alg_solver_enu_t AlgLoopSolver() {return GetInstance().algLoopSolver;}
5859
static bool AddParametersToCSV() {return GetInstance().addParametersToCSV;}
5960
static bool DefaultModeIsCS() {return GetInstance().defaultModeIsCS;}
6061
static bool DeleteTempFiles() {return GetInstance().deleteTempFiles;}
@@ -83,6 +84,7 @@ namespace oms
8384

8485
private:
8586
bool addParametersToCSV;
87+
oms_alg_solver_enu_t algLoopSolver;
8688
bool defaultModeIsCS;
8789
bool deleteTempFiles;
8890
bool emitEvents;
@@ -133,6 +135,7 @@ namespace oms
133135
const std::vector<Flag> flags = {
134136
{"", "", "FMU or SSP file", re_filename, Flags::Filename, false},
135137
{"--addParametersToCSV", "", "Export parameters to .csv file (true, [false])", re_default, Flags::AddParametersToCSV, false},
138+
{"--algLoopSolver", "", "Specifies the alg. loop solver method ([fixedpoint], kinsol) used for algebraic loops spanning over multiple components.", re_default, Flags::AlgLoopSolver, false},
136139
{"--clearAllOptions", "", "Reset all flags to default values", re_void, Flags::ClearAllOptions, false},
137140
{"--deleteTempFiles", "", "Deletes temp files as soon as they are no longer needed ([true], false)", re_bool, Flags::DeleteTempFiles, false},
138141
{"--emitEvents", "", "Specifies whether events should be emitted or not ([true], false)", re_bool, Flags::EmitEvents, false},
@@ -168,6 +171,7 @@ namespace oms
168171
};
169172

170173
static oms_status_enu_t AddParametersToCSV(const std::string& value);
174+
static oms_status_enu_t AlgLoopSolver(const std::string& value);
171175
static oms_status_enu_t ClearAllOptions(const std::string& value);
172176
static oms_status_enu_t DeleteTempFiles(const std::string& value);
173177
static oms_status_enu_t EmitEvents(const std::string& value);

src/OMSimulatorLib/System.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
#include "System.h"
3333

34+
#include "AlgLoop.h"
3435
#include "Component.h"
3536
#include "ComponentFMUCS.h"
3637
#include "ComponentFMUME.h"
@@ -2365,6 +2366,29 @@ oms_status_enu_t oms::System::importBusConnectorGeometry(const pugi::xml_node& n
23652366
return oms_status_ok;
23662367
}
23672368

2369+
oms::AlgLoop* oms::System::getAlgLoop(const int systemNumber)
2370+
{
2371+
if (systemNumber > algLoops.size()-1 || systemNumber < 0)
2372+
{
2373+
logError("Invalid system number for algebraic loop.");
2374+
return NULL;
2375+
}
2376+
2377+
return &algLoops[systemNumber];
2378+
}
2379+
2380+
oms_status_enu_t oms::System::addAlgLoop(oms_ssc_t SCC, const int algLoopNum)
2381+
{
2382+
if (loopsNeedUpdate)
2383+
{
2384+
algLoops.clear();
2385+
loopsNeedUpdate = false;
2386+
}
2387+
algLoops.push_back( AlgLoop( Flags::AlgLoopSolver(), absoluteTolerance, SCC, algLoopNum ));
2388+
2389+
return oms_status_ok;
2390+
}
2391+
23682392
oms_status_enu_t oms::System::importStartValuesFromSSV()
23692393
{
23702394
for (const auto& file : startValuesFileSources)
@@ -2489,6 +2513,26 @@ oms_status_enu_t oms::System::importStartValuesFromSSVHelper(std::string fileNam
24892513
return oms_status_ok;
24902514
}
24912515

2516+
oms_status_enu_t oms::System::updateAlgebraicLoops(const std::vector< oms_ssc_t >& sortedConnections)
2517+
{
2518+
// Instantiate loops
2519+
if (loopsNeedUpdate)
2520+
{
2521+
int systCount = 0;
2522+
for(int i=0; i<sortedConnections.size(); i++)
2523+
{
2524+
if (sortedConnections[i].size() > 1)
2525+
{
2526+
addAlgLoop(sortedConnections[i], systCount);
2527+
systCount++;
2528+
}
2529+
}
2530+
loopsNeedUpdate = false;
2531+
}
2532+
2533+
return oms_status_ok;
2534+
}
2535+
24922536
oms_status_enu_t oms::System::importParameterMappingFromSSM(std::string fileName, std::multimap<ComRef, ComRef> &mappedEntry)
24932537
{
24942538
std::string tempdir = getModel()->getTempDirectory();
@@ -2528,3 +2572,8 @@ oms_status_enu_t oms::System::importParameterMappingFromSSM(std::string fileName
25282572

25292573
return oms_status_ok;
25302574
}
2575+
2576+
oms_status_enu_t oms::System::solveAlgLoop(DirectedGraph& graph, int loopNumber)
2577+
{
2578+
return algLoops[loopNumber].solveAlgLoop(*this, graph);
2579+
}

src/OMSimulatorLib/System.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#ifndef _OMS_SYSTEM_H_
3333
#define _OMS_SYSTEM_H_
3434

35+
#include "AlgLoop.h"
3536
#include "BusConnector.h"
3637
#include "Clock.h"
3738
#include "ComRef.h"
@@ -58,6 +59,7 @@
5859

5960
namespace oms
6061
{
62+
class AlgLoop;
6163
class Component;
6264
class Model;
6365
class Variable;
@@ -132,6 +134,8 @@ namespace oms
132134
virtual oms_status_enu_t reset() = 0;
133135
virtual oms_status_enu_t stepUntil(double stopTime, void (*cb)(const char* ident, double time, oms_status_enu_t status)) = 0;
134136

137+
double getTime() const {return time;}
138+
135139
oms_status_enu_t getBoolean(const ComRef& cref, bool& value);
136140
oms_status_enu_t getInteger(const ComRef& cref, int& value);
137141
oms_status_enu_t getReal(const ComRef& cref, double& value);
@@ -160,12 +164,18 @@ namespace oms
160164
double getMaximumStepSize() {return maximumStepSize;}
161165
oms_solver_enu_t getSolver() {return solverMethod;}
162166

167+
AlgLoop* getAlgLoop(const int systemNumber);
168+
oms_status_enu_t addAlgLoop(oms_ssc_t SCC, const int algLoopNum);
169+
oms_status_enu_t updateAlgebraicLoops(const std::vector< oms_ssc_t >& sortedConnections);
170+
oms_status_enu_t solveAlgLoop(DirectedGraph& graph, int loopNumber);
171+
163172
bool useThreadPool();
164173
ctpl::thread_pool& getThreadPool();
165174

166175
std::string getUniqueID() const;
167176
std::map<std::string, std::string> startValuesFileSources; ///< ssvFileSource mapped with ssmFilesource if mapping is provided, otherwise only ssvFilesource entry is made
168177
protected:
178+
double time;
169179
System(const ComRef& cref, oms_system_enu_t type, Model* parentModel, System* parentSystem, oms_solver_enu_t solverMethod);
170180

171181
// stop the compiler generating methods copying the object
@@ -190,6 +200,9 @@ namespace oms
190200
std::unordered_map<unsigned int /*result file var ID*/, unsigned int /*allVariables ID*/> resultFileMapping;
191201
std::unordered_map<ComRef, bool> exportConnectors;
192202

203+
protected:
204+
bool loopsNeedUpdate = true;
205+
193206
private:
194207
ComRef cref;
195208
oms_system_enu_t type;
@@ -217,6 +230,8 @@ namespace oms
217230
oms_status_enu_t importStartValuesFromSSV();
218231
oms_status_enu_t importStartValuesFromSSVHelper(std::string fileName, std::multimap<ComRef, ComRef> &mappedEntry);
219232
oms_status_enu_t importParameterMappingFromSSM(std::string fileName, std::multimap<ComRef, ComRef> &mappedEntry);
233+
234+
std::vector<AlgLoop> algLoops; ///< Vector of algebraic loop objects
220235
};
221236
}
222237

0 commit comments

Comments
 (0)