LCOV - code coverage report
Current view: top level - app/src/Com/http - staticSimulationPost.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 98 0.0 %
Date: 2023-08-17 16:45:52 Functions: 0 4 0.0 %

          Line data    Source code
       1             : #include <spdlog/spdlog.h>
       2             : 
       3             : #include <cstdlib>
       4             : #include <nlohmann/json.hpp>
       5             : #include <stdexcept>
       6             : 
       7             : #include "Com/HTTPServer.hpp"
       8             : #include "GlobalState.hpp"
       9             : #include "Log/ProgressLoggerIgnore.hpp"
      10             : #include "Log/ProgressLoggerJsonOStream.hpp"
      11             : #include "Log/ProgressLoggerTableOStream.hpp"
      12             : #include "Opt/QuadraticGuessSolver.hpp"
      13             : #include "Opt/QuadraticSolver.hpp"
      14             : #include "Static/Solution.hpp"
      15             : #include "Static/algos/ConjugateFrankWolfe.hpp"
      16             : #include "Static/algos/DijkstraAoN.hpp"
      17             : #include "Static/algos/IterativeEquilibration.hpp"
      18             : #include "Static/supply/BPRConvexNetwork.hpp"
      19             : #include "Static/supply/BPRNetwork.hpp"
      20             : #include "Static/supply/BPRNotConvexNetwork.hpp"
      21             : #include "data/SUMO/EdgeData.hpp"
      22             : #include "data/SUMO/NetworkTAZ.hpp"
      23             : #include "data/SUMO/Routes.hpp"
      24             : #include "utils/invertMap.hpp"
      25             : #include "utils/require_env.hpp"
      26             : 
      27             : using namespace std;
      28             : using namespace Com;
      29             : using namespace utils::stringify;
      30             : 
      31             : using json = nlohmann::json;
      32             : 
      33             : enum class StaticSimulationType : int {
      34             :     CONVEX,
      35             :     NONCONVEX
      36             : };
      37             : 
      38             : namespace utils::stringify {
      39             : template<>
      40             : class stringify<StaticSimulationType> {
      41             :    public:
      42             :     static StaticSimulationType fromString(const string &s);
      43             : 
      44             :     static string toString(const StaticSimulationType &t);
      45             : };
      46             : }  // namespace utils::stringify
      47             : 
      48             : // clang-format off
      49             : const unordered_map<string, StaticSimulationType> str2staticSimulationType = {
      50             :     {"convex"   , StaticSimulationType::CONVEX      },
      51             :     {"nonconvex", StaticSimulationType::NONCONVEX   }
      52             : };
      53             : const unordered_map<StaticSimulationType, string> staticSimulationType2str = utils::invertMap(str2staticSimulationType);
      54             : // clang-format on
      55             : 
      56           0 : StaticSimulationType stringify<StaticSimulationType>::fromString(const string &s) {
      57           0 :     return str2staticSimulationType.at(s);
      58             : }
      59             : 
      60           0 : string stringify<StaticSimulationType>::toString(const StaticSimulationType &t) {
      61           0 :     return staticSimulationType2str.at(t);
      62             : }
      63             : 
      64             : /**yaml POST /static/simulation/{id}
      65             :  * summary: Run static simulation.
      66             :  * tags:
      67             :  *   - Static
      68             :  * consumes:
      69             :  *   - application/json
      70             :  * parameters:
      71             :  *   - name: id
      72             :  *     in: path
      73             :  *     required: true
      74             :  *     description: ID of simulation
      75             :  *     schema:
      76             :  *       type: string
      77             :  *       pattern: '^[\w\-]+$'
      78             :  * requestBody:
      79             :  *   description: Configuration of simulation to run.
      80             :  *   content:
      81             :  *     application/json:
      82             :  *       schema:
      83             :  *         $ref: '#/components/schemas/StaticSimulation'
      84             :  * responses:
      85             :  *   '200':
      86             :  *     description: Simulation executed successfully
      87             :  */
      88           0 : void HTTPServer::staticSimulationPost(const httplib::Request &req, httplib::Response &res) {
      89           0 :     const string WS_HOST = utils::require_env("WS_HOST");
      90             : 
      91           0 :     json data = json::parse(req.body);
      92             : 
      93           0 :     const string &resourceID = req.matches[0];
      94             : 
      95           0 :     string netPath, tazPath, demandPath, outEdgesPath, outRoutesPath;
      96           0 :     try {
      97           0 :         netPath       = data.at("netPath");
      98           0 :         tazPath       = data.at("tazPath");
      99           0 :         demandPath    = data.at("demandPath");
     100           0 :         outEdgesPath  = data.at("outEdgesPath");
     101           0 :         outRoutesPath = data.at("outRoutesPath");
     102           0 :     } catch(const json::out_of_range &e) {
     103           0 :         res.status = 400;
     104           0 :         return;
     105             :     }
     106             : 
     107           0 :     StaticSimulationType type = StaticSimulationType::NONCONVEX;
     108           0 :     if(data.contains("type")) {
     109           0 :         type = stringify<StaticSimulationType>::fromString(data.at("type"));
     110             :     }
     111             : 
     112           0 :     try {
     113           0 :         GlobalState::ResourceID taskID = "task://"s + resourceID;
     114             : 
     115             :         // Create stringstream resource
     116           0 :         GlobalState::ResourceID streamID = "stream://"s + resourceID;
     117           0 :         utils::pipestream      &ios      = GlobalState::streams.create(streamID);
     118             : 
     119             :         // Create task
     120             :         // clang-format off
     121           0 :         GlobalState::tasks.create(
     122             :             taskID,
     123           0 :             [
     124             :                 netPath,
     125             :                 tazPath,
     126             :                 demandPath,
     127             :                 type,
     128             :                 outEdgesPath,
     129             :                 outRoutesPath,
     130             :                 taskID,
     131             :                 streamID,
     132             :                 &ios
     133           0 :             ]() -> GlobalState::TaskReturn {
     134           0 :                 try {
     135           0 :                     Log::ProgressLoggerJsonOStream logger(ios.o());
     136             : 
     137             :                     // Supply
     138           0 :                     shared_ptr<SUMO::Network> sumoNetwork = SUMO::Network::loadFromFile(netPath);
     139           0 :                     SUMO::TAZs    sumoTAZs    = SUMO::TAZ::loadFromFile(tazPath);
     140           0 :                     SUMO::NetworkTAZs sumo{*sumoNetwork, sumoTAZs};
     141             : 
     142             :                     // Demand
     143           0 :                     VISUM::OFormatDemand oDemand = VISUM::OFormatDemand::loadFromFile(demandPath);
     144           0 :                     Static::Demand::Loader<const VISUM::OFormatDemand &, const Static::SUMOAdapter &> demandLoader;
     145             : 
     146             :                     // Model
     147           0 :                     Static::BPRNetwork::Loader<SUMO::NetworkTAZs> *loader = nullptr;
     148           0 :                     switch(type) {
     149           0 :                         case StaticSimulationType::CONVEX:
     150           0 :                             loader = new Static::BPRNetwork::Loader<SUMO::NetworkTAZs>();
     151           0 :                             break;
     152           0 :                         case StaticSimulationType::NONCONVEX:
     153           0 :                             loader = new Static::BPRNotConvexNetwork::Loader<SUMO::NetworkTAZs>();
     154           0 :                             break;
     155           0 :                         default:
     156           0 :                             throw out_of_range("Invalid static simulation type");
     157             :                     }
     158             : 
     159           0 :                     Static::BPRNetwork *network = loader->load(sumo);
     160             : 
     161           0 :                     Static::Demand       demand  = demandLoader.load(oDemand, loader->adapter);
     162             : 
     163             :                     // Solve
     164             : 
     165             :                     // All or Nothing
     166           0 :                     Static::DijkstraAoN aon;
     167           0 :                     Static::Solution    x0 = aon.solve(*network, demand);
     168             : 
     169             :                     // Solver
     170           0 :                     Opt::QuadraticSolver      innerSolver;
     171           0 :                     Opt::QuadraticGuessSolver solver(
     172             :                         innerSolver,
     173             :                         0.5,
     174             :                         0.2,
     175             :                         0.845,
     176             :                         0.365
     177           0 :                     );
     178           0 :                     solver.setStopCriteria(0.01);
     179             : 
     180           0 :                     Static::Solution x;
     181           0 :                     switch(type){
     182           0 :                         case StaticSimulationType::CONVEX: {
     183             :                             // Frank-Wolfe
     184           0 :                             Static::ConjugateFrankWolfe fw(aon, solver, logger);
     185           0 :                             fw.setStopCriteria(1.0);
     186           0 :                             x = fw.solve(*network, demand, x0);
     187             : 
     188           0 :                             break;
     189             :                         }
     190           0 :                         case StaticSimulationType::NONCONVEX: {
     191             :                             // Iterative Equilibration
     192           0 :                             Static::ConjugateFrankWolfe fw(aon, solver, Log::ProgressLoggerIgnore::INSTANCE);
     193             : 
     194           0 :                             fw.setStopCriteria(0.0);
     195           0 :                             fw.setIterations(5);
     196             : 
     197           0 :                             Static::IterativeEquilibration<Static::BPRNotConvexNetwork, Static::ConjugateFrankWolfe> ie(fw, logger);
     198           0 :                             ie.setIterations(10);
     199             : 
     200           0 :                             Static::BPRNotConvexNetwork *networkNotConvex = dynamic_cast<Static::BPRNotConvexNetwork *>(network);
     201           0 :                             if(networkNotConvex == nullptr)
     202           0 :                                 throw logic_error("Network is not BPRNotConvexNetwork");
     203             : 
     204           0 :                             x = ie.solve(*networkNotConvex, demand, x0);
     205             : 
     206           0 :                             break;
     207             :                         }
     208           0 :                         default:
     209           0 :                             throw out_of_range("Invalid static simulation type " + to_string(static_cast<int>(type)));
     210             :                     }
     211             : 
     212             :                     // Save edgeData
     213             :                     // clang-format off
     214           0 :                     SUMO::EdgeData::Loader<
     215             :                         const SUMO::NetworkTAZs &,
     216             :                         const Static::BPRNetwork &,
     217             :                         const Static::Solution &,
     218             :                         const Static::SUMOAdapter &
     219             :                     > edgeDataLoader;
     220             :                     // clang-format on
     221           0 :                     SUMO::EdgeData edgeData = edgeDataLoader.load(sumo, *network, x, loader->adapter);
     222           0 :                     edgeData.saveToFile(outEdgesPath);
     223             : 
     224             :                     // Save routes
     225             :                     // clang-format off
     226           0 :                     SUMO::Routes::Loader<
     227             :                         const Static::Network &,
     228             :                         const Static::Solution &,
     229             :                         const Static::SUMOAdapter &
     230             :                     > routesLoader;
     231             :                     // clang-format on
     232           0 :                     SUMO::Routes routes = routesLoader.load(*network, x, loader->adapter);
     233           0 :                     routes.saveToFile(outRoutesPath);
     234             : 
     235           0 :                     delete network;
     236           0 :                     delete loader;
     237             : 
     238           0 :                     ios.closeWrite();
     239           0 :                     GlobalState::streams.erase(streamID);
     240             : 
     241           0 :                 } catch(const GlobalState::ResourceException &e) {
     242           0 :                     spdlog::error("Task {} aborted, what(): {}", taskID, e.what());
     243           0 :                     return {400, "what(): "s + e.what()};
     244           0 :                 } catch(const ios_base::failure &e) {
     245           0 :                     spdlog::error("Task {} aborted, what(): {}", taskID, e.what());
     246           0 :                     return {400, "what(): "s + e.what()};
     247             :                 }
     248             : 
     249           0 :                 return {200, ""};
     250             :             }
     251           0 :         );
     252             :         // clang-format on
     253             : 
     254             :         // clang-format off
     255           0 :         json resData = {
     256             :             {"log", {
     257             :                 {"resourceID", resourceID},
     258           0 :                 {"url", "ws://" + WS_HOST + resourceID + "/log"}
     259             :             }}
     260           0 :         };
     261             :         // clang-format on
     262           0 :         res.set_content(resData.dump(), "application/json");
     263             : 
     264           0 :     } catch(const exception &e) {
     265           0 :         res.status = 500;
     266           0 :         res.set_content("what(): "s + e.what(), "text/plain");
     267             :     }
     268             : }

Generated by: LCOV version 1.14