DPsimMain.cpp 5.99 KB
Newer Older
1
#include <Python.h>
2
3

#include <condition_variable>
Markus Mirz's avatar
Markus Mirz committed
4
#include <iostream>
5
#include <mutex>
Markus Mirz's avatar
Markus Mirz committed
6
#include <string>
7
8
#include <thread>

9
#include "CIMReader.h"
10
#include "PyComponent.h"
11
#include "PySimulation.h"
12
#include "Simulation.h"
13
#include "ShmemInterface.h"
Markus Mirz's avatar
Markus Mirz committed
14

15
16
using namespace DPsim;

17
void usage() {
Georg Martin Reinke's avatar
Georg Martin Reinke committed
18
	std::cerr << "usage: DPsolver [OPTIONS] CIM_FILE..." << std::endl
19
	  << "Possible options:" << std::endl
Georg Martin Reinke's avatar
Georg Martin Reinke committed
20
21
22
	  << "  -h/--help:                show this help and exit" << std::endl
	  << "  -i/--interface OBJ_NAME:  prefix for the names of the shmem objects used for communication (default: /dpsim)" << std::endl
	  << "  -n/--node NODE_ID:        RDF id of the node where the interfacing voltage/current source should be placed" << std::endl
Georg Martin Reinke's avatar
Georg Martin Reinke committed
23
	  << "  -r/--realtime:            enable realtime simulation " << std::endl
24
	  << "  -s/--split INDEX:         index of this instance for distributed simulation (0 or 1)" << std::endl;
25
26
27
28
29
30
31
32
}

bool parseFloat(const char *s, double *d) {
	char *end;
	*d = std::strtod(s, &end);
	return (end != s && !*end);
}

33
34
35
36
37
38
bool parseInt(const char *s, int *i) {
	char *end;
	*i = strtol(s, &end, 0);
	return (end != s && !*end);
}

39
40
41
42
43
static PyMethodDef pyModuleMethods[] = {
	{"load_cim", pyLoadCim, METH_VARARGS, "Load a network from CIM file(s)."},
	{0}
};

44
static PyModuleDef dpsimModule = {
45
	PyModuleDef_HEAD_INIT, "dpsim", NULL, -1, pyModuleMethods,
46
	NULL, NULL, NULL, NULL
47
48
};

49
50
static PyObject* PyInit_dpsim(void) {
	PyObject* m;
51

52
53
	if (PyType_Ready(&PyComponentType) < 0)
		return nullptr;
54
	if (PyType_Ready(&PySimulationType) < 0)
55
56
		return nullptr;

57
58
	m = PyModule_Create(&dpsimModule);
	if (!m)
59
60
		return nullptr;

61
62
	Py_INCREF(&PySimulationType);
	PyModule_AddObject(m, "Simulation", (PyObject*) &PySimulationType);
63
64
	Py_INCREF(&PyComponentType);
	PyModule_AddObject(m, "Component", (PyObject*) &PyComponentType);
65
	return m;
66
67
}

68
void doPythonLoop() {
69
70
71
72
73
74
75
76
77
78
79
	PyImport_AppendInittab("dpsim", &PyInit_dpsim);
	Py_Initialize();

	while (std::cin.good() && Py_IsInitialized()) {
		std::cout << "> ";
		std::string line;
		std::getline(std::cin, line);
		PyRun_SimpleString(line.c_str());
	}
}

Georg Martin Reinke's avatar
Georg Martin Reinke committed
80
81
// TODO: that many platform-dependent ifdefs inside main are kind of ugly
int cimMain(int argc, const char* argv[]) {
82
	bool rt = false;
83
84
85
	int i, split = -1;
	std::string interfaceBase = "/dpsim";
	std::string splitNode = "";
Georg Martin Reinke's avatar
Georg Martin Reinke committed
86
87
	std::string outName, inName, logName("log.txt"), llogName("lvector.csv"), rlogName("rvector.csv");
#ifdef __linux__
88
	ShmemInterface *intf = nullptr;
Georg Martin Reinke's avatar
Georg Martin Reinke committed
89
#endif
90
91
92

	// Parse arguments
	for (i = 1; i < argc; i++) {
93
		if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
94
95
			usage();
			return 0;
96
97
98
99
100
101
102
103
104
105
		} else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--interface")) {
			if (i == argc-1) {
				std::cerr << "Missing argument for -i/--interface; see 'DPsim --help' for usage" << std::endl;
				return 1;
			}
			if (argv[++i][0] != '/') {
				std::cerr << "Shmem interface object name must start with a '/'" << std::endl;
				return 1;
			}
			interfaceBase = std::string(argv[i]);
106
107
108
109
110
111
112
113
		} else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "--node")) {
			if (i == argc-1) {
				std::cerr << "Missing argument for -n/--node; see 'DPsim --help' for usage" << std::endl;
				return 1;
			}
			splitNode = std::string(argv[++i]);
		} else if (!strcmp(argv[i], "-r") || !strcmp(argv[i], "--realtime")) {
			rt = true;
114
115
116
117
118
119
120
121
122
		} else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--split")) {
			if (i == argc-1) {
				std::cerr << "Missing argument for -s/--split; see 'DPsim --help' for usage" << std::endl;
				return 1;
			}
			if (!parseInt(argv[++i], &split) || split < 0 || split > 1) {
				std::cerr << "Invalid setting " << argv[i] << " for the split index" << std::endl;
				return 1;
			}
123
124
125
126
127
128
129
130
		} else if (argv[i][0] == '-') {
			std::cerr << "Unknown option " << argv[i] << " ; see 'DPsim --help' for usage" << std::endl;
			return 1;
		} else {
			// remaining arguments treated as input files
			break;
		}
	}
131
	// TODO: treat remaining arguments as initial python scripts
Georg Martin Reinke's avatar
Georg Martin Reinke committed
132
133
134
135
136
137
138
139
140
#ifndef __linux__
	if (split >= 0 || splitNode.length() != 0) {
		std::cerr << "Distributed simulation not supported on this platform" << std::endl;
		return 1;
	} else if (rt) {
		std::cerr << "Realtime simulation not supported on this platform" << std::endl;
		return 1;
	}
#endif
141
	if (split >= 0 || splitNode.length() != 0 || rt) {
142
143
144
		std::cerr << "Realtime and distributed simulation currently not supported in combination with Python" << std::endl;
		return 1;
	}
145

146
147
	// TODO: RT / shmem interface with python
	/*
Georg Martin Reinke's avatar
Georg Martin Reinke committed
148
#ifdef __linux__
149
150
151
152
153
154
155
156
	// TODO: this is a simple, pretty much fixed setup. Make this more flexible / configurable
	if (split >= 0) {
		int node = reader.mapTopologicalNode(splitNode);
		if (node < 0) {
			std::cerr << "Invalid / missing split node" << std::endl;
			return 1;
		}
		if (split == 0) {
157
158
			outName = interfaceBase + ".0.out";
			inName = interfaceBase + ".0.in";
159
160
161
162
163
			intf = new ShmemInterface(outName.c_str(), inName.c_str());
			ExternalVoltageSource *evs = new ExternalVoltageSource("v_int", node, 0, 0, 0, reader.getNumVoltageSources()+1);
			intf->registerVoltageSource(evs, 0, 1);
			intf->registerExportedCurrent(evs, 0, 1);
			components.push_back(evs);
164
165
166
167
			// TODO make log names configurable
			logName = "cim0.log";
			llogName = "lvector-cim0.csv";
			rlogName = "rvector-cim0.csv";
168
		} else {
169
170
			outName = interfaceBase + ".1.out";
			inName = interfaceBase + ".1.in";
171
172
173
174
175
			intf = new ShmemInterface(outName.c_str(), inName.c_str());
			ExternalCurrentSource *ecs = new ExternalCurrentSource("i_int", node, 0, 0, 0);
			intf->registerCurrentSource(ecs, 0, 1);
			intf->registerExportedVoltage(node, 0, 0, 1);
			components.push_back(ecs);
176
177
178
			logName = "cim1.log";
			llogName = "lvector-cim1.csv";
			rlogName = "rvector-cim1.csv";
179
180
		}
	}
Georg Martin Reinke's avatar
Georg Martin Reinke committed
181
#endif
182
	*/
183
	
184
185
186
	doPythonLoop();

	/*
Georg Martin Reinke's avatar
Georg Martin Reinke committed
187
#ifdef __linux__
188
189
		if (intf)
			sim.addExternalInterface(intf);
Georg Martin Reinke's avatar
Georg Martin Reinke committed
190

191
192
193
194
195
196
		if (rt) {
			sim.runRT(RTTimerFD, true, log, llog, rlog);
		} else {
			while (sim.step(log, llog, rlog))
				sim.increaseByTimeStep();
		}
Georg Martin Reinke's avatar
Georg Martin Reinke committed
197

198
199
		if (intf)
			delete intf;
Georg Martin Reinke's avatar
Georg Martin Reinke committed
200
#endif
201
	*/
202
	return 0;
203
204
}

Georg Martin Reinke's avatar
Georg Martin Reinke committed
205
int main(int argc, const char* argv[]) {
206
	return cimMain(argc, argv);
Georg Martin Reinke's avatar
Georg Martin Reinke committed
207
}