9#include <dpsim-models/Utils.h>
10#include <dpsim/DiakopticsSolver.h>
11#include <dpsim/MNASolver.h>
12#include <dpsim/MNASolverFactory.h>
13#include <dpsim/PFSolverPowerPolar.h>
14#include <dpsim/PFSolverPowerPolarSparse.h>
15#include <dpsim/SequentialScheduler.h>
16#include <dpsim/Simulation.h>
17#include <dpsim/Utils.h>
19#include <spdlog/sinks/stdout_color_sinks.h>
22#include <dpsim-models/CIM/Reader.h>
26#include <dpsim-models/Solver/ODEInterface.h>
27#include <dpsim/DAESolver.h>
28#include <dpsim/ODESolver.h>
65 mLogLevel(args.logLevel), mDomain(args.solver.domain),
66 mSolverType(args.solver.type), mDirectImpl(args.directImpl) {
75 Eigen::setNbThreads(1);
108 switch (mSolverType) {
109 case Solver::Type::MNA:
114 case Solver::Type::DAE:
116 mSolvers.push_back(solver);
120 case Solver::Type::NRP: {
121 std::shared_ptr<PFSolver> pfSolver;
122#if defined(WITH_KLU) || defined(WITH_SPARSE)
124 pfSolver = std::make_shared<PFSolverPowerPolarSparse>(
127 pfSolver = std::make_shared<PFSolverPowerPolar>(**
mName,
mSystem,
131 pfSolver = std::make_shared<PFSolverPowerPolar>(**
mName,
mSystem,
135 pfSolver->setKeepLastSolution(**mPFKeepLastSolution);
144 solver->doInitFromNodesAndTerminals(mInitFromNodesAndTerminals);
145 solver->setSolverAndComponentBehaviour(mSolverBehaviour);
146 solver->initialize();
148 mSolvers.push_back(solver);
159 for (
auto comp :
mSystem.mComponents) {
160 auto odeComp = std::dynamic_pointer_cast<ODEInterface>(comp);
163 auto odeSolver = std::make_shared<ODESolver>(
164 odeComp->mAttributeList->attributeTyped<String>(
"name")->get() +
167 mSolvers.push_back(odeSolver);
175 std::vector<SystemTopology> subnets;
179 mSystem.splitSubnets<VarType>(subnets);
183 for (UInt net = 0; net < subnets.size(); ++net) {
185 if (subnets.size() > 1)
186 copySuffix =
"_" + std::to_string(net);
192 throw std::logic_error(
"MNA state-space extraction does not support "
193 "Diakoptics/tearing.");
196 solver = std::make_shared<DiakopticsSolver<VarType>>(
213 solver->setSystem(subnets[net]);
214 solver->setSolverAndComponentBehaviour(mSolverBehaviour);
215 solver->doInitFromNodesAndTerminals(mInitFromNodesAndTerminals);
217 solver->setDirectLinearSolverConfiguration(
218 mDirectLinearSolverConfiguration);
219 solver->initialize();
222 mSolvers.push_back(solver);
227 SPDLOG_LOGGER_INFO(
mLog,
"Start synchronization with remotes on interfaces");
235 SPDLOG_LOGGER_INFO(
mLog,
"Synchronized simulation start with remotes");
240 mTaskOutEdges.clear();
242 for (
auto solver : mSolvers) {
243 for (
auto t : solver->getTasks()) {
249 for (
auto t : intf->getTasks()) {
255 mTasks.push_back(logger->getTask());
258 mScheduler = std::make_shared<SequentialScheduler>();
264 SPDLOG_LOGGER_INFO(
mLog,
"Scheduling tasks.");
267 SPDLOG_LOGGER_INFO(
mLog,
"Scheduling done.");
275 std::map<CPS::Task::Ptr, Scheduler::TaskTime> avgTimes;
276 std::map<CPS::Task::Ptr, String> fillColors;
278 auto isScheduled = [
this](Task::Ptr task) -> Bool {
279 return !mTaskOutEdges[task].empty();
282 auto getColor = [](Task::Ptr task) -> String {
283 static std::map<std::type_index, String> colorMap;
284 auto tid = std::type_index(
typeid(task.get()));
286 if (colorMap.find(tid) != colorMap.end()) {
288 String(
"/paired9/") + std::to_string(1 + colorMap.size() % 9);
291 return colorMap[tid];
294 auto avgTimeWorst = Scheduler::TaskTime::min();
295 for (
auto task :
mTasks) {
296 avgTimes[task] =
mScheduler->getAveragedMeasurement(task);
298 if (avgTimes[task] > avgTimeWorst)
299 avgTimeWorst = avgTimes[task];
306 Graph::Graph g(
"dependencies", Graph::Type::directed);
307 for (
auto task :
mTasks) {
308 String name = task->toString();
309 String type = CPS::Utils::className(task.get(),
"DPsim::");
311 auto *n = g.addNode(name);
313 std::stringstream label;
315 label <<
"<B>" << Utils::encodeXml(name) <<
"</B><BR/>";
316 label <<
"<FONT POINT-SIZE=\"10\" COLOR=\"gray28\">"
317 << Utils::encodeXml(type) <<
"<BR/>";
319 if (isScheduled(task))
320 label <<
"Avg. time: " << avgTimes[task].count() <<
"ns<BR/>";
322 label <<
"Unscheduled"
327 n->set(
"color", getColor(task));
328 n->set(
"label", label.str(),
true);
329 n->set(
"style",
"rounded,filled,bold");
330 n->set(
"shape",
"rectangle");
332 if (isScheduled(task)) {
334 auto grad = (float)avgTimes[task].count() / avgTimeWorst.count();
335 n->set(
"fillcolor", CPS::Utils::Rgb::gradient(grad).hex());
336 SPDLOG_LOGGER_INFO(
mLog,
"{} {}", task->toString(),
337 CPS::Utils::Rgb::gradient(grad).hex());
340 n->set(
"fillcolor",
"white");
343 for (
auto from :
mTasks) {
344 for (
auto to : mTaskOutEdges[from]) {
345 g.addEdge(
"", g.node(from->toString()), g.node(to->toString()));
349 g.set(
"splines",
"ortho");
354void Simulation::setPFKeepLastSolution(Bool value) {
355 **mPFKeepLastSolution = value;
358Bool Simulation::getPFKeepLastSolution()
const {
return **mPFKeepLastSolution; }
360void Simulation::setPFBaseApparentPowerFallback(Real value) {
364Real Simulation::getPFBaseApparentPowerFallback()
const {
368void Simulation::setPFMaxIterations(CPS::UInt value) {
372CPS::UInt Simulation::getPFMaxIterations()
const {
return **
mPFMaxIterations; }
374void Simulation::setPFSolverUseSparse(Bool value) {
380void Simulation::setPFSolverEnforceReactiveLimits(Bool value) {
384Bool Simulation::getPFSolverEnforceReactiveLimits()
const {
388void Simulation::setPFSolverBaseVoltageLooseTolerance(Real tolerance) {
392Real Simulation::getPFSolverBaseVoltageLooseTolerance()
const {
396void Simulation::setPFSolverBaseVoltageStrictTolerance(Real tolerance) {
400Real Simulation::getPFSolverBaseVoltageStrictTolerance()
const {
405 SPDLOG_LOGGER_INFO(
mLog,
"Initialize simulation: {}", **
mName);
412 SPDLOG_LOGGER_INFO(
mLog,
"Opening interfaces.");
419 SPDLOG_LOGGER_INFO(
mLog,
"Start simulation: {}", **
mName);
425 if (mSolverType != Solver::Type::NRP) {
441 SPDLOG_LOGGER_INFO(
mLog,
"Simulation calculation time: {:.6f}",
452 SPDLOG_LOGGER_INFO(
mLog,
"Simulation finished.");
476 std::chrono::steady_clock::time_point
start;
478 start = std::chrono::steady_clock::now();
488 auto end = std::chrono::steady_clock::now();
489 std::chrono::duration<double> diff = end -
start;
496 auto stepTimeLog = Logger::get(logName, Logger::Level::info);
498 SPDLOG_LOGGER_WARN(
mLog,
"Collection of step times has been disabled.");
501 Logger::setLogPattern(stepTimeLog,
"%v");
502 SPDLOG_LOGGER_INFO(stepTimeLog,
"step_time");
504 Real stepTimeSum = 0;
507 SPDLOG_LOGGER_INFO(stepTimeLog,
"{:.9f}", meas);
509 SPDLOG_LOGGER_INFO(
mLog,
"Average step time: {:.9f}",
514 auto stepTimeLog = Logger::get(logName, Logger::Level::info);
515 Logger::setLogPattern(stepTimeLog,
"%v");
516 SPDLOG_LOGGER_INFO(stepTimeLog,
"overruns");
522 SPDLOG_LOGGER_INFO(
mLog,
"overrun detected {}: {:.9f}", overruns, meas);
525 SPDLOG_LOGGER_INFO(
mLog,
"Detected {} overruns.", overruns);
529 for (
auto solver : mSolvers) {
530 solver->logLUTimes();
536 if (solverIndex >= mSolvers.size()) {
537 throw std::out_of_range(
538 "Simulation::getStateSpaceExtractor(): solver index out of range.");
541 if (
const auto realMnaSolver =
543 return realMnaSolver->getStateSpaceExtractor();
546 if (
const auto complexMnaSolver =
548 mSolvers[solverIndex])) {
549 return complexMnaSolver->getStateSpaceExtractor();
552 throw std::logic_error(
553 "Simulation::getStateSpaceExtractor(): selected solver is not an "
558 const String &attr) {
566 CPS::AttributeBase::Ptr attrPtr = idObj->attribute(attr);
570 mLog,
"Attribute with name {} not found on component {}", attr, comp);
574 SPDLOG_LOGGER_ERROR(
mLog,
"Component or node with name {} not found", comp);
579void Simulation::logIdObjAttribute(
const String &comp,
const String &attr) {
581 String name = comp +
"." + attr;
587 mLoggers[0]->logAttribute(name, attr);
589 throw SystemError(
"Cannot log attributes when no logger is configured for "
static std::shared_ptr< MnaSolver< VarType > > factory(String name, CPS::Domain domain=CPS::Domain::DP, CPS::Logger::Level logLevel=CPS::Logger::Level::info, DirectLinearSolverImpl implementation=mSupportedSolverImpls().back(), String pluginName="plugin.so")
sovlerImpl: choose the most advanced solver implementation available by default
Solver class using Modified Nodal Analysis (MNA).
std::chrono::steady_clock::duration TaskTime
Time measurement for the task execution.
Bool mStateSpaceExtraction
Enable extraction of the MNA-coupled discrete-time state matrix.
std::chrono::duration< double > mSimulationCalculationTime
Measured calculation time for simulation.
void logLUTimes()
Write LU decomposition times measurements to log file.
void sync() const
Synchronize simulation with remotes by exchanging intial state over interfaces.
CPS::IdentifiedObject::List mTearComponents
CPS::Logger::Level mLogLevel
Simulation log level.
virtual Real step()
Solve system A * x = z for x and current time.
Scheduler::Edges mTaskInEdges
Task dependencies as incoming / outgoing edges.
const CPS::Attribute< Real >::Ptr mTimeStep
Simulation timestep.
const CPS::Attribute< CPS::UInt >::Ptr mPFMaxIterations
Maximum number of Newton-Raphson iterations for the PF solver.
const CPS::Attribute< Bool >::Ptr mSteadyStateInit
const CPS::Attribute< Real >::Ptr mPFBaseVoltageStrictTolerance
Strict tolerance between authoritative base-voltage sources in a zone; default 0.01.
Real next()
Run until next time step.
void logStepTimes(String logName)
Write step time measurements to log file.
String mSolverPluginName
If there we use a solver plugin, this specifies its name (excluding .so)
void initialize()
Create solver instances etc.
std::vector< Real > mStepTimes
(Real) time needed for the timesteps
const CPS::Attribute< Real >::Ptr mFinalTime
Final time of the simulation.
void prepSchedule()
Prepare schedule for simulation.
Int mTimeStepCount
Number of step which have been executed for this simulation.
const CPS::Attribute< Real >::Ptr mPFBaseApparentPowerFallback
Real mSteadStIniTimeLimit
steady state initialization time limit
CPS::Task::List mTasks
List of all tasks to be scheduled.
const CPS::Attribute< Bool >::Ptr mSplitSubnets
std::shared_ptr< Scheduler > mScheduler
Scheduler used for task scheduling.
std::vector< Interface::Ptr > mInterfaces
Vector of Interfaces.
Bool mLogStepTimes
activate collection of step times
void create()
Helper function for constructors.
CPS::SystemTopology mSystem
System list.
void checkForOverruns(String logName)
Check for overruns.
Simulation(String name, CommandLineArgs &args)
Creates simulation with name and CommandLineArgs.
const CPS::Attribute< Bool >::Ptr mPFEnforceReactiveLimits
CPS::AttributeBase::Ptr getIdObjAttribute(const String &comp, const String &attr)
CHECK: Can these be deleted? getIdObjAttribute + "**attr =" should suffice.
void start()
Start simulation without advancing in time.
EventQueue mEvents
The simulation event queue.
void schedule()
Create the schedule for the independent tasks.
const CPS::Attribute< Bool >::Ptr mPFSolverUseSparse
std::chrono::time_point< std::chrono::steady_clock > mSimulationStartTimePoint
Start time point to measure calculation time.
Real mTime
Time variable that is incremented at every step.
Bool mSystemMatrixRecomputation
Enable recomputation of system matrix during simulation.
Real mSteadStIniAccLimit
steady state initialization accuracy limit
const CPS::Attribute< Real >::Ptr mPFBaseVoltageLooseTolerance
Loose tolerance for a zone's Load base-voltage vs. its rating; default 0.1.
void createMNASolver()
Subroutine for MNA only because there are many MNA options.
void run()
Run simulation until total time is elapsed.
void logAttribute(String name, CPS::AttributeBase::Ptr attr)
CHECK: Can we store the attribute name / UID intrinsically inside the attribute?
DataLoggerInterface::List mLoggers
The data loggers.
const MNAStateSpaceExtractor & getStateSpaceExtractor(UInt solverIndex=0) const
void createSolvers()
Create solvers depending on simulation settings.
const CPS::Attribute< String >::Ptr mName
Simulation name.
CPS::Logger::Log mLog
Simulation logger.
void stop()
Stop simulation including scheduler and interfaces.
std::chrono::time_point< std::chrono::steady_clock > mSimulationEndTimePoint
End time point to measure calculation time.