Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
CharacteristicMap.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2002-2024 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
18// Characteristic map for vehicle type parameters as needed by the MMPEVEM model
19// Teaching and Research Area Mechatronics in Mobile Propulsion (MMP), RWTH Aachen
20/****************************************************************************/
21#include <config.h>
22
23#include <cmath>
24#include <cstring>
25#include <stdexcept>
26
29
30
31// ===========================================================================
32// method definitions
33// ===========================================================================
34void
36 strides.clear();
37 strides.reserve(domainDim);
38 strides.push_back(imageDim);
39 for (int i = 1; i < domainDim; i++) {
40 strides.push_back((int)axes[i - 1].size() * strides[i - 1]);
41 }
42}
43
44
45int
46CharacteristicMap::calcFlatIdx(const std::vector<int>& ref_idxs) const {
47 if (static_cast<int>(ref_idxs.size()) != domainDim) {
48 throw std::runtime_error("The number of indices differs from the map's"
49 " domain dimension.");
50 }
51
52 int flatIdx = 0;
53 for (int i = 0; i < domainDim; i++) {
54 if (ref_idxs[i] < 0) {
55 throw std::runtime_error("The argument indices aren't non-negative.");
56 }
57 flatIdx += ref_idxs[i] * strides[i];
58 }
59 return flatIdx;
60}
61
62
63int
64CharacteristicMap::findNearestNeighborIdxs(const std::vector<double>& ref_p,
65 std::vector<int>& ref_idxs, double eps) const {
66 if (static_cast<int>(ref_p.size()) != domainDim) {
67 throw std::runtime_error("The argument point's size doesn't match the"
68 " domain dimension.");
69 }
70
71 ref_idxs = std::vector<int>(domainDim, -1);
72 for (int i = 0; i < domainDim; i++) {
73 if (axes[i][0] - eps <= ref_p[i] && ref_p[i] < axes[i][0]) {
74 ref_idxs[i] = 0;
75 } else if (axes[i][axes[i].size() - 1] <= ref_p[i]
76 && ref_p[i] < axes[i][axes[i].size() - 1] + eps) {
77 ref_idxs[i] = (int)axes[i].size() - 1;
78 } else {
79 for (int j = 0; j < static_cast<int>(axes[i].size()) - 1; j++) {
80 if (axes[i][j] <= ref_p[i] && ref_p[i] < axes[i][j + 1]) {
81 // Pick the index that is closest to the point
82 if (ref_p[i] - axes[i][j] <= axes[i][j + 1] - ref_p[i]) {
83 ref_idxs[i] = j;
84 break;
85 } else {
86 ref_idxs[i] = j + 1;
87 break;
88 }
89 }
90 }
91 }
92
93 // The point lies outside of the valid range
94 if (ref_idxs[i] == -1) {
95 return -1;
96 }
97 }
98
99 return 0;
100}
101
102
103std::vector<double>
104CharacteristicMap::at(const std::vector<int>& ref_idxs) const {
105 if (static_cast<int>(ref_idxs.size()) != domainDim) {
106 throw std::runtime_error("The number of indices differs from the map's"
107 " domain dimension.");
108 }
109
110 int flatIdx = calcFlatIdx(ref_idxs);
111 return std::vector<double>(flattenedMap.begin() + flatIdx,
112 flattenedMap.begin() + flatIdx + imageDim);
113}
114
115
116CharacteristicMap::CharacteristicMap(int domainDim, int imageDim,
117 const std::vector<std::vector<double>>& ref_axes,
118 const std::vector<double>& ref_flattenedMap)
119 : domainDim(domainDim),
120 imageDim(imageDim),
121 axes(ref_axes),
122 flattenedMap(ref_flattenedMap) {
123 // Check whether the dimensions are consistent
124 if (static_cast<int>(axes.size()) != domainDim) {
125 throw std::runtime_error("The number of axes doesn't match the specified"
126 " domain dimension.");
127 }
128 int expectedEntryCnt = imageDim;
129 for (auto& ref_axis : axes) {
130 expectedEntryCnt *= (int)ref_axis.size();
131 }
132 if (static_cast<int>(flattenedMap.size()) != expectedEntryCnt) {
133 throw std::runtime_error("The number of map entries isn't equal to the"
134 " product of the axes' dimensions times the image dimension.");
135 }
136
138}
139
140
141CharacteristicMap::CharacteristicMap(const std::string& ref_mapString) {
142 // Split the map string into its three main parts
143 const std::vector<std::string> tokens = StringTokenizer(ref_mapString, "|").getVector();
144 if (tokens.size() != 3) {
145 throw std::runtime_error("The map string isn't made up of the 3 parts"
146 " dimensions, axes, and flattened entries.");
147 }
148
149 // Extract the domain and image dimensions
150 const std::vector<std::string> dimensionTokens = StringTokenizer(tokens[0], ",").getVector();
151 if (dimensionTokens.size() != 2) {
152 throw std::runtime_error("The domain and image dimensions aren't specified"
153 " correctly.");
154 }
155 domainDim = std::stoi(dimensionTokens[0]);
156 imageDim = std::stoi(dimensionTokens[1]);
157
158 // Create the map axes
159 const std::vector<std::string> axisTokens = StringTokenizer(tokens[1], ";").getVector();
160 if (static_cast<int>(axisTokens.size()) != domainDim) {
161 throw std::runtime_error("The number of axes doesn't match the specified"
162 " domain dimension.");
163 }
164 for (auto& ref_axisToken : axisTokens) {
165 std::vector<std::string> axisEntryTokens = StringTokenizer(ref_axisToken, ",").getVector();
166 std::vector<double> axisEntries;
167 for (auto& ref_axisEntryToken : axisEntryTokens) {
168 axisEntries.push_back(std::stod(ref_axisEntryToken));
169 }
170 axes.push_back(axisEntries);
171 }
172
173 // Create the flattened map
174 const std::vector<std::string> flattenedMapTokens = StringTokenizer(tokens[2], ",").getVector();
175 int expectedEntryCnt = imageDim;
176 for (auto& ref_axis : axes) {
177 expectedEntryCnt *= (int)ref_axis.size();
178 }
179 if (static_cast<int>(flattenedMapTokens.size()) != expectedEntryCnt) {
180 throw std::runtime_error("The number of map entries isn't equal to the"
181 " product of the axes' dimensions times the image dimension.");
182 }
183 flattenedMap.reserve(expectedEntryCnt);
184 for (auto& ref_flattenedMapToken : flattenedMapTokens) {
185 flattenedMap.push_back(std::stod(ref_flattenedMapToken));
186 }
187
189}
190
191
192std::string
194 // Write the domain and image dimensions
195 std::string mapString = std::to_string(domainDim) + ","
196 + std::to_string(imageDim) + "|";
197
198 // Add the axes
199 for (int i = 0; i < static_cast<int>(axes.size()); i++) {
200 for (int j = 0; j < static_cast<int>(axes[i].size()); j++) {
201 mapString += std::to_string(axes[i][j])
202 + (j == static_cast<int>(axes[i].size()) - 1 ? "" : ",");
203 }
204 mapString += (i == static_cast<int>(axes.size()) - 1 ? "|" : ";");
205 }
206
207 // Append the flattened map entries
208 for (int i = 0; i < static_cast<int>(flattenedMap.size()); i++) {
209 mapString += std::to_string(flattenedMap[i])
210 + (i == static_cast<int>(flattenedMap.size()) - 1 ? "" : ",");
211 }
212
213 return mapString;
214}
215
216
217int
221
222
223int
225 return imageDim;
226}
227
228
229std::vector<double>
230CharacteristicMap::eval(const std::vector<double>& ref_p, double eps) const {
231 if (static_cast<int>(ref_p.size()) != domainDim) {
232 throw std::runtime_error("The argument's size doesn't match the domain"
233 " dimension.");
234 }
235
236 // Find the nearest neighbor and its image values
237 std::vector<int> nnIdxs;
238 if (findNearestNeighborIdxs(ref_p, nnIdxs, eps)) {
239 return std::vector<double>(imageDim, std::stod("nan"));
240 }
241 // Image values of the nearest neighbor
242 const std::vector<double> y_nn = at(nnIdxs);
243 // The result is based on the image values of the nearest neighbor
244 std::vector<double> y = y_nn;
245
246 // Interpolate
247 for (int i = 0; i < domainDim; i++) {
248 // Depending on the configuration of the points, different neighbors will be
249 // used for interpolation
250 const double s = ref_p[i] - axes[i][nnIdxs[i]];
251 if (std::abs(s) <= eps) {
252 continue;
253 }
254 bool b_constellation1 = s < 0 && nnIdxs[i] > 0;
255 bool b_constellation2 = s >= 0
256 && nnIdxs[i] == static_cast<int>(axes[i].size()) - 1
257 && nnIdxs[i] > 0;
258 bool b_constellation3 = s < 0 && nnIdxs[i] == 0
259 && nnIdxs[i] < static_cast<int>(axes[i].size()) - 1;
260 bool b_constellation4 = s >= 0
261 && nnIdxs[i] < static_cast<int>(axes[i].size()) - 1;
262
263 double dx = 1;
264 // Axis neighbor indices (i.e. the indices of the second support point)
265 std::vector<int> anIdxs = nnIdxs;
266 if (b_constellation1 || b_constellation2) {
267 anIdxs[i] -= 1;
268 dx = axes[i][nnIdxs[i]] - axes[i][anIdxs[i]];
269 } else if (b_constellation3 || b_constellation4) {
270 anIdxs[i] += 1;
271 dx = axes[i][anIdxs[i]] - axes[i][nnIdxs[i]];
272 } else {
273 continue;
274 }
275 // Image values of the axis neighbor
276 const std::vector<double> y_an = at(anIdxs);
277
278 for (int j = 0; j < imageDim; j++) {
279 double dy = 0;
280 if (b_constellation1 || b_constellation2) {
281 dy = y_nn[j] - y_an[j];
282 } else {
283 dy = y_an[j] - y_nn[j];
284 }
285
286 // Update
287 y[j] += s * dy / dx;
288 }
289 }
290
291 return y;
292}
int imageDim
Image dimension of the map.
int calcFlatIdx(const std::vector< int > &ref_idxs) const
Compute the index of a map entry in the flattened map.
std::vector< int > strides
Stride for each domain dimension in the flattened map.
std::vector< double > flattenedMap
Flattened map entries.
std::vector< double > eval(const std::vector< double > &ref_p, double eps=1e-6) const
Evaluate a point in the map using linear interpolation.
int getDomainDim() const
Get the dimension of the map's domain.
std::vector< std::vector< double > > axes
Vector containing the values along each domain axis in ascending order.
int findNearestNeighborIdxs(const std::vector< double > &ref_p, std::vector< int > &ref_idxs, double eps=1e-6) const
Determine the indices of the nearest neighbor of a point in the map.
void determineStrides()
Determine the stride for each map dimension in the flattened map.
std::vector< double > at(const std::vector< int > &ref_idxs) const
Access a map entry using its indices.
int domainDim
Dimension of the map's domain.
std::string toString() const
Encode the map as a string.
CharacteristicMap(int domainDim, int imageDim, const std::vector< std::vector< double > > &ref_axes, const std::vector< double > &ref_flattenedMap)
Constructor.
int getImageDim() const
Get the image dimension of the map.
std::vector< std::string > getVector()
return vector of strings