9 #include "dpsim/MNASolverFactory.h"
12 #include <dpsim/Config.h>
13 #include <dpsim/Utils.h>
15 using namespace DPsim;
16 using namespace DPsim::Utils;
22 #include <dpsim/Compat/getopt.h>
25 CommandLineArgs::CommandLineArgs(
int argc,
char *argv[], String nm, Real dt,
26 Real d, Real sf, Int s, CPS::Logger::Level ll,
27 CPS::Logger::Level clill, Bool ss, Bool b,
29 DirectLinearSolverImpl mi, String spn,
31 : mProgramName(argv[0]),
33 {
"start-synch", no_argument, 0,
'S', NULL,
""},
34 {
"steady-init", no_argument, 0,
'I', NULL,
""},
35 {
"blocking", no_argument, 0,
'b', NULL,
""},
36 {
"help", no_argument, 0,
'h', NULL,
""},
37 {
"timestep", required_argument, 0,
't',
"SECS",
38 "Simulation time-step"},
39 {
"duration", required_argument, 0,
'd',
"SECS",
40 "Simulation duration"},
41 {
"system-freq", required_argument, 0,
'f',
"HZ",
"System Frequency"},
42 {
"scenario", required_argument, 0,
's',
"NUM",
"Scenario selection"},
43 {
"log-level", required_argument, 0,
'l',
"(NONE|INFO|DEBUG|WARN|ERR)",
45 {
"start-at", required_argument, 0,
'a',
"ISO8601",
46 "Start time of real-time simulation"},
47 {
"start-in", required_argument, 0,
'i',
"SECS",
""},
48 {
"solver-domain", required_argument, 0,
'D',
"(SP|DP|EMT)",
50 {
"solver-type", required_argument, 0,
'T',
"(NRP|MNA)",
52 {
"linear-solver-impl", required_argument, 0,
'U',
53 "(DenseLU|SparseLU|KLU|CUDADense|CUDASparse)",
54 "Type of direct linear solver implementation"},
55 {
"option", required_argument, 0,
'o',
"KEY=VALUE",
56 "User-definable options"},
57 {
"name", required_argument, 0,
'n',
"NAME",
"Name of log files"},
58 {
"params", required_argument, 0,
'p',
"PATH",
59 "Json file containing parametrization"},
61 timeStep(dt), duration(d), sysFreq(sf), scenario(s), logLevel(ll),
62 cliLogLevel(clill), name(nm), params(ps), startSynch(ss), blocking(b),
63 steadyInit(si), solver{sd, st}, directImpl(mi), solverPluginName(spn) {
64 parseArguments(argc, argv);
67 CommandLineArgs::CommandLineArgs(String nm, Real dt, Real d, Real sf, Int s,
68 CPS::Logger::Level ll,
69 CPS::Logger::Level clill, Bool ss, Bool b,
71 DirectLinearSolverImpl mi, String spn)
72 : mProgramName(
"dpsim"),
74 {
"start-synch", no_argument, 0,
'S', NULL,
""},
75 {
"steady-init", no_argument, 0,
'I', NULL,
""},
76 {
"blocking", no_argument, 0,
'b', NULL,
""},
77 {
"help", no_argument, 0,
'h', NULL,
""},
78 {
"timestep", required_argument, 0,
't',
"SECS",
79 "Simulation time-step"},
80 {
"duration", required_argument, 0,
'd',
"SECS",
81 "Simulation duration"},
82 {
"system-freq", required_argument, 0,
'f',
"HZ",
"System Frequency"},
83 {
"scenario", required_argument, 0,
's',
"NUM",
"Scenario selection"},
84 {
"log-level", required_argument, 0,
'l',
"(NONE|INFO|DEBUG|WARN|ERR)",
86 {
"start-at", required_argument, 0,
'a',
"ISO8601",
87 "Start time of real-time simulation"},
88 {
"start-in", required_argument, 0,
'i',
"SECS",
""},
89 {
"solver-domain", required_argument, 0,
'D',
"(SP|DP|EMT)",
91 {
"solver-type", required_argument, 0,
'T',
"(NRP|MNA)",
93 {
"linear-solver-impl", required_argument, 0,
'U',
94 "(DenseLU|SparseLU|KLU|CUDADense|CUDASparse)",
95 "Type of direct linear solver implementation"},
96 {
"option", required_argument, 0,
'o',
"KEY=VALUE",
97 "User-definable options"},
98 {
"name", required_argument, 0,
'n',
"NAME",
"Name of log files"},
100 timeStep(dt), duration(d), sysFreq(sf), scenario(s), logLevel(ll),
101 cliLogLevel(clill), name(nm), startSynch(ss), blocking(b), steadyInit(si),
102 solver{sd, st}, directImpl(mi), solverPluginName(spn) {}
104 void CommandLineArgs::parseArguments(
int argc,
char *argv[]) {
105 mProgramName = argv[0];
106 std::vector<option> long_options;
107 for (
auto a : mArguments)
108 long_options.push_back({a.name, a.has_arg, a.flag, a.val});
113 int option_index = 0;
115 c = getopt_long(argc, argv,
116 "ht:d:s:l:a:i:f:D:P:T:U:o:Sbn:", long_options.data(),
137 timeStep = std::stod(optarg);
141 duration = std::stod(optarg);
145 sysFreq = std::stod(optarg);
149 scenario = std::stoi(optarg);
155 auto p = arg.find(
"=");
156 auto key = arg.substr(0, p);
157 auto value = arg.substr(p + 1);
158 if (p != String::npos)
159 options[key] = value;
168 logLevel = Logger::Level::debug;
169 else if (arg ==
"INFO")
170 logLevel = Logger::Level::info;
171 else if (arg ==
"ERR")
172 logLevel = Logger::Level::err;
173 else if (arg ==
"WARN")
174 logLevel = Logger::Level::warn;
175 else if (arg ==
"NONE")
176 logLevel = Logger::Level::off;
178 throw std::invalid_argument(
"Invalid value for --log-level: must be a "
179 "string of DEBUG, INFO, ERR, WARN or NONE");
187 solver.domain = Domain::DP;
188 else if (arg ==
"EMT")
189 solver.domain = Domain::EMT;
190 else if (arg ==
"SP")
191 solver.domain = Domain::SP;
193 throw std::invalid_argument(
"Invalid value for --solver-domain: must "
194 "be a string of SP, DP, EMT");
202 solver.type = Solver::Type::MNA;
203 else if (arg ==
"NRP")
204 solver.type = Solver::Type::NRP;
206 throw std::invalid_argument(
207 "Invalid value for --solver-type: must be a string of NRP or MNA");
212 if (arg ==
"DenseLU") {
213 directImpl = DirectLinearSolverImpl::DenseLU;
214 }
else if (arg ==
"SparseLU") {
215 directImpl = DirectLinearSolverImpl::SparseLU;
216 }
else if (arg ==
"KLU") {
217 directImpl = DirectLinearSolverImpl::KLU;
218 }
else if (arg ==
"CUDADense") {
219 directImpl = DirectLinearSolverImpl::CUDADense;
220 }
else if (arg ==
"CUDASparse") {
221 directImpl = DirectLinearSolverImpl::CUDASparse;
222 }
else if (arg ==
"CUDAMagma") {
223 directImpl = DirectLinearSolverImpl::CUDAMagma;
224 }
else if (arg ==
"Plugin") {
225 directImpl = DirectLinearSolverImpl::Plugin;
227 throw std::invalid_argument(
"Invalid value for --solver-mna-impl");
232 solverPluginName = optarg;
237 double deltaT = std::stod(optarg);
239 startTime = Timer::StartClock::now() +
240 std::chrono::milliseconds(
static_cast<int>(deltaT * 1e3));
247 std::istringstream ss(optarg);
249 ss >> std::get_time(&t,
"%Y%m%dT%H%M%S");
252 throw std::invalid_argument(
253 "Invalid value for --start-at: must be a ISO8601 date");
255 std::time_t tt = std::mktime(&t);
257 startTime = Timer::StartClock::from_time_t(tt);
282 while (optind < argc)
283 positional.push_back(argv[optind++]);
286 void CommandLineArgs::showUsage() {
287 std::cout <<
"Usage: " << mProgramName <<
" [OPTIONS] [FILES]" << std::endl;
288 std::cout << std::endl;
289 std::cout <<
" Available options:" << std::endl;
291 for (
auto a : mArguments) {
295 std::cout <<
" -" <<
static_cast<char>(a.val) <<
", --" << a.name;
298 std::cout <<
" " << a.valdesc;
301 std::cout <<
" " << a.desc;
303 std::cout << std::endl;
306 std::cout << std::endl;
309 std::list<fs::path> CommandLineArgs::positionalPaths()
const {
310 std::list<fs::path> paths;
312 for (
auto p : positional) {
313 paths.emplace_back(p);
319 String DPsim::Utils::encodeXml(String &data) {
321 buffer.reserve(data.size());
322 for (
size_t pos = 0; pos != data.size(); ++pos) {
325 buffer.append(
"&");
328 buffer.append(
""");
331 buffer.append(
"'");
334 buffer.append(
"<");
337 buffer.append(
">");
340 buffer.append(&data[pos], 1);
348 std::vector<std::string> DPsim::Utils::tokenize(std::string s,
char delimiter) {
349 std::vector<std::string> tokens;
354 while ((curentPos = s.find(delimiter, lastPos)) != std::string::npos) {
355 const size_t tokenLength = curentPos - lastPos;
356 tokens.push_back(s.substr(lastPos, tokenLength));
359 lastPos = curentPos + 1;
363 if (lastPos != s.length()) {
364 const size_t lastTokenLength = s.length() - lastPos;
365 tokens.push_back(s.substr(lastPos, lastTokenLength));
371 fs::path DPsim::Utils::findFile(
const fs::path &name,
const fs::path &hint,
372 const std::string &useEnv) {
379 std::vector<fs::path> searchPaths = {fs::current_path()};
382 searchPaths.push_back(hint);
385 if (!useEnv.empty() && getenv(useEnv.c_str())) {
386 std::vector<std::string> envPaths = tokenize(getenv(useEnv.c_str()), sep);
388 for (std::string envPath : envPaths) {
389 searchPaths.emplace_back(envPath);
393 for (
auto searchPath : searchPaths) {
396 if (searchPath.is_relative())
397 fullPath /= fs::current_path();
399 fullPath /= searchPath;
402 if (fs::exists(fullPath)) {
403 return fs::absolute(fullPath);
407 String searchPathsString;
408 for (
auto searchPath : searchPaths)
409 searchPathsString.append(searchPath.string().append(
"\n"));
411 throw std::runtime_error(fmt::format(
"File not found: {}\nSearch paths:\n{}",
412 name.string(), searchPathsString));
415 std::list<fs::path> DPsim::Utils::findFiles(std::list<fs::path> filennames,
416 const fs::path &hint,
417 const std::string &useEnv) {
419 std::list<fs::path> foundnames;
421 for (
auto filename : filennames) {
422 auto foundname = findFile(filename, hint, useEnv);
424 foundnames.emplace_back(foundname);
430 void DPsim::Utils::applySimulationParametersFromJson(
const json config,
432 if (config.contains(
"timestep"))
433 sim.setTimeStep(config[
"timestep"].get<double>());
434 if (config.contains(
"duration"))
435 sim.setFinalTime(config[
"duration"].get<double>());
438 void DPsim::Utils::applySynchronousGeneratorParametersFromJson(
440 std::shared_ptr<CPS::EMT::Ph3::SynchronGeneratorDQ> syngen) {
441 if (config.contains(
"options")) {
442 Bool containsSyngenOptions =
false;
443 for (String attrName : syngen->attrParamNames) {
444 if (config[
"options"].contains(attrName)) {
445 syngen->attributeTyped<Real>(attrName)->set(
446 config[
"options"][attrName].get<double>());
447 containsSyngenOptions =
true;
450 if (containsSyngenOptions)
451 syngen->applyParametersOperationalPerUnit();
The Simulation holds a SystemTopology and a Solver.