models.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /**
  2. * @file tests/multithreading/simple/models.hpp
  3. * @author The ARTIS Development Team
  4. * See the AUTHORS or Authors.txt file
  5. */
  6. /*
  7. * ARTIS - the multimodeling and simulation environment
  8. * This file is a part of the ARTIS environment
  9. *
  10. * Copyright (C) 2013-2019 ULCO http://www.univ-littoral.fr
  11. *
  12. * This program is free software: you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation, either version 3 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. */
  25. #ifndef TESTS_MULTITHREADING_SIMPLE_MODELS_HPP
  26. #define TESTS_MULTITHREADING_SIMPLE_MODELS_HPP
  27. #include <artis-star/common/time/DoubleTime.hpp>
  28. #include <artis-star/kernel/pdevs/Dynamics.hpp>
  29. #include <random>
  30. #include <iostream>
  31. namespace artis {
  32. namespace tests {
  33. namespace multithreading {
  34. namespace simple {
  35. void delay()
  36. {
  37. for (unsigned int i = 0; i < 1000; ++i) {
  38. std::vector < int > v;
  39. for (unsigned int j = 1000; j > 0; --j) {
  40. v.push_back(j);
  41. }
  42. std::sort(v.begin(), v.end());
  43. }
  44. }
  45. struct State {
  46. enum values {
  47. STOP, UP, MAX, DOWN
  48. };
  49. };
  50. struct Vehicle {
  51. unsigned int index;
  52. double v_max;
  53. double acceleration;
  54. State::values state;
  55. artis::common::DoubleTime::type next_time;
  56. };
  57. struct GeneratorParameters {
  58. double v_max;
  59. double mean;
  60. double stddev;
  61. unsigned long seed;
  62. };
  63. class Generator
  64. : public artis::pdevs::Dynamics<artis::common::DoubleTime, Generator, GeneratorParameters> {
  65. public:
  66. struct outputs {
  67. enum values {
  68. OUT
  69. };
  70. };
  71. Generator(const std::string& name,
  72. const artis::pdevs::Context<artis::common::DoubleTime, Generator, GeneratorParameters>& context)
  73. :
  74. artis::pdevs::Dynamics<artis::common::DoubleTime, Generator, GeneratorParameters>(
  75. name, context),
  76. _v_max(context.parameters().v_max),
  77. _distribution(context.parameters().mean, context.parameters().stddev),
  78. _v_max_distribution(0.5, 1.),
  79. _port_distribution(0, 7)
  80. {
  81. _generator.seed(context.parameters().seed);
  82. output_ports({{outputs::OUT, "out_1"}});
  83. output_ports({{outputs::OUT + 1, "out_2"}});
  84. output_ports({{outputs::OUT + 2, "out_3"}});
  85. output_ports({{outputs::OUT + 3, "out_4"}});
  86. output_ports({{outputs::OUT + 4, "out_5"}});
  87. output_ports({{outputs::OUT + 5, "out_6"}});
  88. output_ports({{outputs::OUT + 6, "out_7"}});
  89. output_ports({{outputs::OUT + 7, "out_8"}});
  90. }
  91. ~Generator() override = default;
  92. void dint(const artis::common::DoubleTime::type& t) override
  93. {
  94. _last_time = t;
  95. _sigma = _distribution(_generator);
  96. _sigma = _sigma <= 0 ? 0.1 : _sigma;
  97. _next_v_max = _v_max * _v_max_distribution(_generator);
  98. _next_port = _port_distribution(_generator);
  99. ++_index;
  100. }
  101. void start(const artis::common::DoubleTime::type& t) override
  102. {
  103. _last_time = t;
  104. _sigma = _distribution(_generator);
  105. _sigma = _sigma <= 0 ? 0.1 : _sigma;
  106. _next_v_max = _v_max * _v_max_distribution(_generator);
  107. _next_port = _port_distribution(_generator);
  108. _index = 1;
  109. }
  110. artis::common::DoubleTime::type
  111. ta(const artis::common::DoubleTime::type& /* t */) const override { return _sigma; }
  112. artis::common::Bag<artis::common::DoubleTime>
  113. lambda(const artis::common::DoubleTime::type& t) const override
  114. {
  115. artis::common::Bag<artis::common::DoubleTime> bag;
  116. if (t > 0) {
  117. Vehicle vehicle = {_index, _next_v_max, 0.5, State::STOP, t};
  118. bag.push_back(
  119. artis::common::ExternalEvent<artis::common::DoubleTime>(
  120. outputs::OUT + _next_port, vehicle));
  121. }
  122. return bag;
  123. }
  124. common::DoubleTime::type
  125. lookahead(const common::DoubleTime::type& /* t */) const override
  126. {
  127. return _last_time + _sigma;
  128. }
  129. private:
  130. // parameters
  131. double _v_max;
  132. // state
  133. artis::common::DoubleTime::type _sigma;
  134. artis::common::DoubleTime::type _last_time;
  135. std::default_random_engine _generator;
  136. std::normal_distribution<double> _distribution;
  137. std::uniform_real_distribution<double> _v_max_distribution;
  138. std::uniform_int_distribution<int> _port_distribution;
  139. double _next_v_max;
  140. int _next_port;
  141. unsigned int _index;
  142. };
  143. class Counter
  144. : public artis::pdevs::Dynamics<artis::common::DoubleTime, Counter> {
  145. public:
  146. struct inputs {
  147. enum values {
  148. IN
  149. };
  150. };
  151. struct vars {
  152. enum values {
  153. COUNTER
  154. };
  155. };
  156. Counter(const std::string& name,
  157. const artis::pdevs::Context<artis::common::DoubleTime, Counter>& context)
  158. :
  159. artis::pdevs::Dynamics<artis::common::DoubleTime, Counter>(name,
  160. context)
  161. {
  162. input_port({inputs::IN, "in"});
  163. observable({vars::COUNTER, "counter"});
  164. }
  165. ~Counter() override = default;
  166. void
  167. dext(const artis::common::DoubleTime::type& /* t */,
  168. const artis::common::DoubleTime::type& /* e */,
  169. const artis::common::Bag<artis::common::DoubleTime>& bag) override
  170. {
  171. // std::cout << t << ": " << _counter << std::endl;
  172. _counter += bag.size();
  173. }
  174. void start(const artis::common::DoubleTime::type& /* t */) override
  175. {
  176. _counter = 0;
  177. }
  178. artis::common::DoubleTime::type
  179. ta(const artis::common::DoubleTime::type& /* t */) const override
  180. {
  181. return artis::common::DoubleTime::infinity;
  182. }
  183. artis::common::Value
  184. observe(const artis::common::DoubleTime::type& /* t */,
  185. unsigned int index) const override
  186. {
  187. if (index == vars::COUNTER) {
  188. return _counter;
  189. } else {
  190. return artis::common::Value();
  191. }
  192. }
  193. common::DoubleTime::type
  194. lookahead(const common::DoubleTime::type& /* t */) const override
  195. {
  196. return common::DoubleTime::infinity;
  197. }
  198. private:
  199. unsigned int _counter;
  200. };
  201. class Link :
  202. public artis::pdevs::Dynamics<common::DoubleTime, Link> {
  203. public :
  204. struct inputs {
  205. enum values {
  206. IN
  207. };
  208. };
  209. struct outputs {
  210. enum values {
  211. OUT
  212. };
  213. };
  214. Link(const std::string& name,
  215. const artis::pdevs::Context<common::DoubleTime, Link>& context)
  216. :artis::pdevs::Dynamics<common::DoubleTime, Link>(name, context)
  217. {
  218. input_port({inputs::IN, "in"});
  219. output_port({outputs::OUT, "out"});
  220. }
  221. ~ Link() override = default;
  222. void dint(const artis::common::DoubleTime::type& t) override
  223. {
  224. delay();
  225. auto it = _vehicles.begin();
  226. while (it != _vehicles.end()) {
  227. if (it->next_time == t and it->state == State::STOP) {
  228. _vehicles.erase(it);
  229. it = _vehicles.begin();
  230. } else {
  231. ++it;
  232. }
  233. }
  234. for (auto& vehicle: _vehicles) {
  235. if (vehicle.next_time == t) {
  236. switch (vehicle.state) {
  237. case State::UP: {
  238. double duration = vehicle.v_max / vehicle.acceleration;
  239. double acceleration_distance =
  240. 0.5 * vehicle.acceleration * duration * duration;
  241. vehicle.state = State::MAX;
  242. vehicle.next_time = t +
  243. (_length - 2 * acceleration_distance) / vehicle.v_max;
  244. break;
  245. }
  246. case State::MAX: {
  247. vehicle.state = State::DOWN;
  248. vehicle.next_time = t + vehicle.v_max / vehicle.acceleration;
  249. break;
  250. }
  251. case State::DOWN: {
  252. vehicle.state = State::STOP;
  253. vehicle.next_time = t;
  254. break;
  255. }
  256. case State::STOP: {
  257. assert(false);
  258. break;
  259. }
  260. }
  261. }
  262. }
  263. update_sigma(t);
  264. }
  265. void dext(const artis::common::DoubleTime::type& t,
  266. const artis::common::DoubleTime::type& /* e */,
  267. const artis::common::Bag<artis::common::DoubleTime>& bag) override
  268. {
  269. std::for_each(bag.begin(), bag.end(),
  270. [this, t](const common::ExternalEvent<common::DoubleTime>& event) {
  271. if (event.on_port(inputs::IN)) {
  272. Vehicle vehicle;
  273. event.data()(vehicle);
  274. vehicle.next_time =
  275. t + vehicle.v_max / vehicle.acceleration;
  276. vehicle.state = State::UP;
  277. _vehicles.push_back(vehicle);
  278. }
  279. });
  280. update_sigma(t);
  281. }
  282. artis::common::DoubleTime::type
  283. ta(const artis::common::DoubleTime::type& /* t */) const override { return _sigma; }
  284. artis::common::Bag<artis::common::DoubleTime>
  285. lambda(const artis::common::DoubleTime::type& t) const override
  286. {
  287. artis::common::Bag<artis::common::DoubleTime> bag;
  288. for (auto vehicle: _vehicles) {
  289. if (vehicle.next_time == t and vehicle.state == State::STOP) {
  290. bag.push_back(
  291. artis::common::ExternalEvent<artis::common::DoubleTime>(
  292. outputs::OUT, vehicle));
  293. }
  294. }
  295. return bag;
  296. }
  297. void
  298. start(const artis::common::DoubleTime::type& /* t */) override { }
  299. common::DoubleTime::type
  300. lookahead(const common::DoubleTime::type& t) const override
  301. {
  302. double eot = artis::common::DoubleTime::infinity;
  303. for (auto vehicle: _vehicles) {
  304. double eot_i = artis::common::DoubleTime::infinity;
  305. if (vehicle.next_time == t and vehicle.state == State::STOP) {
  306. eot_i = t;
  307. } else if (vehicle.state == State::DOWN) {
  308. eot_i = vehicle.next_time;
  309. } else if (vehicle.state == State::MAX) {
  310. eot_i = vehicle.next_time + vehicle.v_max / vehicle.acceleration;
  311. } else if (vehicle.state == State::UP) {
  312. double duration = vehicle.v_max / vehicle.acceleration;
  313. double acceleration_distance =
  314. 0.5 * vehicle.acceleration * duration * duration;
  315. eot_i = vehicle.next_time
  316. + (_length - 2 * acceleration_distance) / vehicle.v_max
  317. + vehicle.v_max / vehicle.acceleration;
  318. }
  319. if (eot_i < eot) {
  320. eot = eot_i;
  321. }
  322. }
  323. return eot;
  324. }
  325. private:
  326. void update_sigma(const artis::common::DoubleTime::type& t)
  327. {
  328. if (_vehicles.empty()) {
  329. _sigma = artis::common::DoubleTime::infinity;
  330. } else {
  331. _sigma = std::min_element(_vehicles.begin(), _vehicles.end(),
  332. [](const Vehicle& e1, const Vehicle& e2) {
  333. return e1.next_time < e2.next_time;
  334. })->next_time - t;
  335. }
  336. }
  337. const double _length = 500;
  338. std::deque<Vehicle> _vehicles;
  339. artis::common::DoubleTime::type _sigma;
  340. };
  341. }
  342. }
  343. }
  344. } // namespace artis tests multithreading simple
  345. #endif