LCOV - code coverage report
Current view: top level - src/utils/emissions - CharacteristicMap.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 67.2 % 128 86
Test Date: 2024-11-21 15:56:26 Functions: 60.0 % 10 6

            Line data    Source code
       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              : /****************************************************************************/
      14              : /// @file    CharacteristicMap.cpp
      15              : /// @author  Kevin Badalian (badalian_k@mmp.rwth-aachen.de)
      16              : /// @date    2021-02
      17              : ///
      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              : 
      27              : #include <utils/common/StringTokenizer.h>
      28              : #include <utils/emissions/CharacteristicMap.h>
      29              : 
      30              : 
      31              : // ===========================================================================
      32              : // method definitions
      33              : // ===========================================================================
      34              : void
      35       319539 : CharacteristicMap::determineStrides() {
      36              :     strides.clear();
      37       319539 :     strides.reserve(domainDim);
      38       319539 :     strides.push_back(imageDim);
      39       639078 :     for (int i = 1; i < domainDim; i++) {
      40       319539 :         strides.push_back((int)axes[i - 1].size() * strides[i - 1]);
      41              :     }
      42       319539 : }
      43              : 
      44              : 
      45              : int
      46         9740 : CharacteristicMap::calcFlatIdx(const std::vector<int>& ref_idxs) const {
      47         9740 :     if (static_cast<int>(ref_idxs.size()) != domainDim) {
      48              :         throw std::runtime_error("The number of indices differs from the map's"
      49            0 :                                  " domain dimension.");
      50              :     }
      51              : 
      52              :     int flatIdx = 0;
      53        29220 :     for (int i = 0; i < domainDim; i++) {
      54        19480 :         if (ref_idxs[i] < 0) {
      55            0 :             throw std::runtime_error("The argument indices aren't non-negative.");
      56              :         }
      57        19480 :         flatIdx += ref_idxs[i] * strides[i];
      58              :     }
      59         9740 :     return flatIdx;
      60              : }
      61              : 
      62              : 
      63              : int
      64         5280 : CharacteristicMap::findNearestNeighborIdxs(const std::vector<double>& ref_p,
      65              :         std::vector<int>& ref_idxs, double eps) const {
      66         5280 :     if (static_cast<int>(ref_p.size()) != domainDim) {
      67              :         throw std::runtime_error("The argument point's size doesn't match the"
      68            0 :                                  " domain dimension.");
      69              :     }
      70              : 
      71         5280 :     ref_idxs = std::vector<int>(domainDim, -1);
      72        15840 :     for (int i = 0; i < domainDim; i++) {
      73        10560 :         if (axes[i][0] - eps <= ref_p[i] && ref_p[i] < axes[i][0]) {
      74            0 :             ref_idxs[i] = 0;
      75        10560 :         } else if (axes[i][axes[i].size() - 1] <= ref_p[i]
      76        10560 :                    && ref_p[i] < axes[i][axes[i].size() - 1] + eps) {
      77            0 :             ref_idxs[i] = (int)axes[i].size() - 1;
      78              :         } else {
      79        73418 :             for (int j = 0; j < static_cast<int>(axes[i].size()) - 1; j++) {
      80        73418 :                 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        10560 :                     if (ref_p[i] - axes[i][j] <= axes[i][j + 1] - ref_p[i]) {
      83         8252 :                         ref_idxs[i] = j;
      84         8252 :                         break;
      85              :                     } else {
      86         2308 :                         ref_idxs[i] = j + 1;
      87         2308 :                         break;
      88              :                     }
      89              :                 }
      90              :             }
      91              :         }
      92              : 
      93              :         // The point lies outside of the valid range
      94        10560 :         if (ref_idxs[i] == -1) {
      95              :             return -1;
      96              :         }
      97              :     }
      98              : 
      99              :     return 0;
     100              : }
     101              : 
     102              : 
     103              : std::vector<double>
     104         9740 : CharacteristicMap::at(const std::vector<int>& ref_idxs) const {
     105         9740 :     if (static_cast<int>(ref_idxs.size()) != domainDim) {
     106              :         throw std::runtime_error("The number of indices differs from the map's"
     107            0 :                                  " domain dimension.");
     108              :     }
     109              : 
     110         9740 :     int flatIdx = calcFlatIdx(ref_idxs);
     111              :     return std::vector<double>(flattenedMap.begin() + flatIdx,
     112         9740 :                                flattenedMap.begin() + flatIdx + imageDim);
     113              : }
     114              : 
     115              : 
     116            0 : CharacteristicMap::CharacteristicMap(int domainDim, int imageDim,
     117              :                                      const std::vector<std::vector<double>>& ref_axes,
     118            0 :                                      const std::vector<double>& ref_flattenedMap)
     119            0 :     : domainDim(domainDim),
     120            0 :       imageDim(imageDim),
     121            0 :       axes(ref_axes),
     122            0 :       flattenedMap(ref_flattenedMap) {
     123              :     // Check whether the dimensions are consistent
     124            0 :     if (static_cast<int>(axes.size()) != domainDim) {
     125              :         throw std::runtime_error("The number of axes doesn't match the specified"
     126            0 :                                  " domain dimension.");
     127              :     }
     128              :     int expectedEntryCnt = imageDim;
     129            0 :     for (auto& ref_axis : axes) {
     130            0 :         expectedEntryCnt *= (int)ref_axis.size();
     131              :     }
     132            0 :     if (static_cast<int>(flattenedMap.size()) != expectedEntryCnt) {
     133              :         throw std::runtime_error("The number of map entries isn't equal to the"
     134            0 :                                  " product of the axes' dimensions times the image dimension.");
     135              :     }
     136              : 
     137            0 :     determineStrides();
     138            0 : }
     139              : 
     140              : 
     141       319539 : CharacteristicMap::CharacteristicMap(const std::string& ref_mapString) {
     142              :     // Split the map string into its three main parts
     143       958617 :     const std::vector<std::string> tokens = StringTokenizer(ref_mapString, "|").getVector();
     144       319539 :     if (tokens.size() != 3) {
     145              :         throw std::runtime_error("The map string isn't made up of the 3 parts"
     146            0 :                                  " dimensions, axes, and flattened entries.");
     147              :     }
     148              : 
     149              :     // Extract the domain and image dimensions
     150       958617 :     const std::vector<std::string> dimensionTokens = StringTokenizer(tokens[0], ",").getVector();
     151       319539 :     if (dimensionTokens.size() != 2) {
     152              :         throw std::runtime_error("The domain and image dimensions aren't specified"
     153            0 :                                  " correctly.");
     154              :     }
     155       319539 :     domainDim = std::stoi(dimensionTokens[0]);
     156       319539 :     imageDim = std::stoi(dimensionTokens[1]);
     157              : 
     158              :     // Create the map axes
     159       958617 :     const std::vector<std::string> axisTokens = StringTokenizer(tokens[1], ";").getVector();
     160       319539 :     if (static_cast<int>(axisTokens.size()) != domainDim) {
     161              :         throw std::runtime_error("The number of axes doesn't match the specified"
     162            0 :                                  " domain dimension.");
     163              :     }
     164       958617 :     for (auto& ref_axisToken : axisTokens) {
     165      1917234 :         std::vector<std::string> axisEntryTokens = StringTokenizer(ref_axisToken, ",").getVector();
     166              :         std::vector<double> axisEntries;
     167      1919010 :         for (auto& ref_axisEntryToken : axisEntryTokens) {
     168      1279932 :             axisEntries.push_back(std::stod(ref_axisEntryToken));
     169              :         }
     170       639078 :         axes.push_back(axisEntries);
     171       639078 :     }
     172              : 
     173              :     // Create the flattened map
     174       958617 :     const std::vector<std::string> flattenedMapTokens = StringTokenizer(tokens[2], ",").getVector();
     175       319539 :     int expectedEntryCnt = imageDim;
     176       958617 :     for (auto& ref_axis : axes) {
     177       639078 :         expectedEntryCnt *= (int)ref_axis.size();
     178              :     }
     179       319539 :     if (static_cast<int>(flattenedMapTokens.size()) != expectedEntryCnt) {
     180              :         throw std::runtime_error("The number of map entries isn't equal to the"
     181            0 :                                  " product of the axes' dimensions times the image dimension.");
     182              :     }
     183       319539 :     flattenedMap.reserve(expectedEntryCnt);
     184      1627455 :     for (auto& ref_flattenedMapToken : flattenedMapTokens) {
     185      1307916 :         flattenedMap.push_back(std::stod(ref_flattenedMapToken));
     186              :     }
     187              : 
     188       319539 :     determineStrides();
     189       319539 : }
     190              : 
     191              : 
     192              : std::string
     193            0 : CharacteristicMap::toString() const {
     194              :     // Write the domain and image dimensions
     195            0 :     std::string mapString = std::to_string(domainDim) + ","
     196            0 :                             + std::to_string(imageDim) + "|";
     197              : 
     198              :     // Add the axes
     199            0 :     for (int i = 0; i < static_cast<int>(axes.size()); i++) {
     200            0 :         for (int j = 0; j < static_cast<int>(axes[i].size()); j++) {
     201            0 :             mapString += std::to_string(axes[i][j])
     202            0 :                          + (j == static_cast<int>(axes[i].size()) - 1 ? "" : ",");
     203              :         }
     204            0 :         mapString += (i == static_cast<int>(axes.size()) - 1 ? "|" : ";");
     205              :     }
     206              : 
     207              :     // Append the flattened map entries
     208            0 :     for (int i = 0; i < static_cast<int>(flattenedMap.size()); i++) {
     209            0 :         mapString += std::to_string(flattenedMap[i])
     210            0 :                      + (i == static_cast<int>(flattenedMap.size()) - 1 ? "" : ",");
     211              :     }
     212              : 
     213            0 :     return mapString;
     214              : }
     215              : 
     216              : 
     217              : int
     218            0 : CharacteristicMap::getDomainDim() const {
     219            0 :     return domainDim;
     220              : }
     221              : 
     222              : 
     223              : int
     224            0 : CharacteristicMap::getImageDim() const {
     225            0 :     return imageDim;
     226              : }
     227              : 
     228              : 
     229              : std::vector<double>
     230         5280 : CharacteristicMap::eval(const std::vector<double>& ref_p, double eps) const {
     231         5280 :     if (static_cast<int>(ref_p.size()) != domainDim) {
     232              :         throw std::runtime_error("The argument's size doesn't match the domain"
     233            0 :                                  " dimension.");
     234              :     }
     235              : 
     236              :     // Find the nearest neighbor and its image values
     237              :     std::vector<int> nnIdxs;
     238         5280 :     if (findNearestNeighborIdxs(ref_p, nnIdxs, eps)) {
     239            0 :         return std::vector<double>(imageDim, std::stod("nan"));
     240              :     }
     241              :     // Image values of the nearest neighbor
     242         5280 :     const std::vector<double> y_nn = at(nnIdxs);
     243              :     // The result is based on the image values of the nearest neighbor
     244         5280 :     std::vector<double> y = y_nn;
     245              : 
     246              :     // Interpolate
     247        15840 :     for (int i = 0; i < domainDim; i++) {
     248              :         // Depending on the configuration of the points, different neighbors will be
     249              :         // used for interpolation
     250        10560 :         const double s = ref_p[i] - axes[i][nnIdxs[i]];
     251        10560 :         if (std::abs(s) <= eps) {
     252         6100 :             continue;
     253              :         }
     254         4460 :         bool b_constellation1 = s < 0 && nnIdxs[i] > 0;
     255              :         bool b_constellation2 = s >= 0
     256         2152 :                                 && nnIdxs[i] == static_cast<int>(axes[i].size()) - 1
     257         4460 :                                 && nnIdxs[i] > 0;
     258         2308 :         bool b_constellation3 = s < 0 && nnIdxs[i] == 0
     259         4460 :                                 && nnIdxs[i] < static_cast<int>(axes[i].size()) - 1;
     260              :         bool b_constellation4 = s >= 0
     261         4460 :                                 && 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         4460 :         std::vector<int> anIdxs = nnIdxs;
     266         4460 :         if (b_constellation1 || b_constellation2) {
     267         2308 :             anIdxs[i] -= 1;
     268         2308 :             dx = axes[i][nnIdxs[i]] - axes[i][anIdxs[i]];
     269         2152 :         } else if (b_constellation3 || b_constellation4) {
     270         2152 :             anIdxs[i] += 1;
     271         2152 :             dx = axes[i][anIdxs[i]] - axes[i][nnIdxs[i]];
     272              :         } else {
     273              :             continue;
     274              :         }
     275              :         // Image values of the axis neighbor
     276         4460 :         const std::vector<double> y_an = at(anIdxs);
     277              : 
     278         8920 :         for (int j = 0; j < imageDim; j++) {
     279              :             double dy = 0;
     280         4460 :             if (b_constellation1 || b_constellation2) {
     281         2308 :                 dy = y_nn[j] - y_an[j];
     282              :             } else {
     283         2152 :                 dy = y_an[j] - y_nn[j];
     284              :             }
     285              : 
     286              :             // Update
     287         4460 :             y[j] += s * dy / dx;
     288              :         }
     289         4460 :     }
     290              : 
     291              :     return y;
     292         5280 : }
        

Generated by: LCOV version 2.0-1