DPsimMain.cpp 6.39 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() {
18
	std::cerr << "usage: DPsolver [OPTIONS] [PYTHON_FILE...]" << std::endl
19
	  << "Possible options:" << std::endl
20
	  << "  -b/--batch:               don't show an interactive prompt after reading files" << std::endl
Georg Martin Reinke's avatar
Georg Martin Reinke committed
21
22
23
	  << "  -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
24
	  << "  -r/--realtime:            enable realtime simulation " << std::endl
25
26
	  << "  -s/--split INDEX:         index of this instance for distributed simulation (0 or 1)" << std::endl
	  << "Remaining arguments are treated as Python files and executed in order." << std::endl;
27
28
29
30
31
32
33
34
}

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

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

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

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

51
52
static PyObject* PyInit_dpsim(void) {
	PyObject* m;
53

54
55
	if (PyType_Ready(&PyComponentType) < 0)
		return nullptr;
56
	if (PyType_Ready(&PySimulationType) < 0)
57
58
		return nullptr;

59
60
	m = PyModule_Create(&dpsimModule);
	if (!m)
61
62
		return nullptr;

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

Georg Martin Reinke's avatar
Georg Martin Reinke committed
70
71
// TODO: that many platform-dependent ifdefs inside main are kind of ugly
int cimMain(int argc, const char* argv[]) {
72
	bool rt = false, batch = false;
73
74
75
	int i, split = -1;
	std::string interfaceBase = "/dpsim";
	std::string splitNode = "";
Georg Martin Reinke's avatar
Georg Martin Reinke committed
76
77
	std::string outName, inName, logName("log.txt"), llogName("lvector.csv"), rlogName("rvector.csv");
#ifdef __linux__
78
	ShmemInterface *intf = nullptr;
Georg Martin Reinke's avatar
Georg Martin Reinke committed
79
#endif
80
81
82

	// Parse arguments
	for (i = 1; i < argc; i++) {
83
84
85
		if (!strcmp(argv[i], "-b") || !strcmp(argv[i], "--batch")) {
			batch = true;
		} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
86
87
			usage();
			return 0;
88
89
90
91
92
93
94
95
96
97
		} 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]);
98
99
100
101
102
103
104
105
		} 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;
106
107
108
109
110
111
112
113
114
		} 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;
			}
115
116
117
118
119
120
121
122
		} 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;
		}
	}
Georg Martin Reinke's avatar
Georg Martin Reinke committed
123
124
125
126
127
128
129
130
131
#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
132
	if (split >= 0 || splitNode.length() != 0 || rt) {
133
134
135
		std::cerr << "Realtime and distributed simulation currently not supported in combination with Python" << std::endl;
		return 1;
	}
136

137
138
	// TODO: RT / shmem interface with python
	/*
Georg Martin Reinke's avatar
Georg Martin Reinke committed
139
#ifdef __linux__
140
141
142
143
144
145
146
147
	// 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) {
148
149
			outName = interfaceBase + ".0.out";
			inName = interfaceBase + ".0.in";
150
151
152
153
154
			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);
155
156
157
158
			// TODO make log names configurable
			logName = "cim0.log";
			llogName = "lvector-cim0.csv";
			rlogName = "rvector-cim0.csv";
159
		} else {
160
161
			outName = interfaceBase + ".1.out";
			inName = interfaceBase + ".1.in";
162
163
164
165
166
			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);
167
168
169
			logName = "cim1.log";
			llogName = "lvector-cim1.csv";
			rlogName = "rvector-cim1.csv";
170
171
		}
	}
Georg Martin Reinke's avatar
Georg Martin Reinke committed
172
#endif
173
	*/
174
	
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
	PyImport_AppendInittab("dpsim", &PyInit_dpsim);
	Py_Initialize();
	for (; i < argc; i++) {
		FILE* f = fopen(argv[i], "r");
		if (!f) {
			std::cerr << "Failed to open ";
			std::perror(argv[i]);
			return 1;
		}
		PyRun_SimpleFile(f, argv[i]);
		fclose(f);
	}

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

	/*
Georg Martin Reinke's avatar
Georg Martin Reinke committed
198
#ifdef __linux__
199
200
		if (intf)
			sim.addExternalInterface(intf);
Georg Martin Reinke's avatar
Georg Martin Reinke committed
201

202
203
204
205
206
207
		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
208

209
210
		if (intf)
			delete intf;
Georg Martin Reinke's avatar
Georg Martin Reinke committed
211
#endif
212
	*/
213
	return 0;
214
215
}

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