Patch correctif TP2
This commit is contained in:
@@ -28,24 +28,22 @@
|
||||
#define ARTIS_FACTORY_FACTORY_GRAPH_MANAGER_HPP
|
||||
|
||||
#include "Base.hpp"
|
||||
#include "FactoryGraphManagerParameters.hpp"
|
||||
#include "ItemStock.hpp"
|
||||
#include "JsonReader.hpp"
|
||||
#include "PoolRouter.hpp"
|
||||
#include "Router.hpp"
|
||||
#include "Sink.hpp"
|
||||
#include "Stock.hpp"
|
||||
|
||||
#include <artis-star/kernel/pdevs/GraphManager.hpp>
|
||||
|
||||
namespace artis::factory {
|
||||
|
||||
struct FactoryGraphManagerParameters {
|
||||
Factory factory;
|
||||
};
|
||||
|
||||
class FactoryGraphManager
|
||||
: public artis::pdevs::GraphManager<artis::common::DoubleTime, artis::common::NoParameters, FactoryGraphManagerParameters> {
|
||||
public:
|
||||
enum sub_models {
|
||||
GENERATOR, ROUTER, POOL_ROUTER, MACHINE = 10000
|
||||
GENERATOR, ROUTER, POOL_ROUTER, MACHINE = 10000, ITEM_STOCK = 20000, STOCK = 30000
|
||||
};
|
||||
|
||||
FactoryGraphManager(Coordinator *coordinator, const artis::common::NoParameters ¶meters,
|
||||
@@ -53,27 +51,13 @@ public:
|
||||
artis::pdevs::GraphManager<artis::common::DoubleTime, artis::common::NoParameters, FactoryGraphManagerParameters>(
|
||||
coordinator, parameters, graph_parameters) {
|
||||
unsigned int machine_index = 0;
|
||||
std::map<unsigned int, Program> programs;
|
||||
|
||||
for (const auto &product: graph_parameters.factory._products) {
|
||||
unsigned int product_id = product.first;
|
||||
Program program;
|
||||
|
||||
for (const auto &pool_job: product.second._pool_jobs) {
|
||||
std::vector<uint8_t> machines;
|
||||
|
||||
for (const auto &machine_job: pool_job._machine_jobs) {
|
||||
machines.push_back(machine_job._machine_id);
|
||||
}
|
||||
program.emplace_back((uint8_t) pool_job._pool_id, machines);
|
||||
}
|
||||
programs[product_id] = program;
|
||||
}
|
||||
|
||||
ProductionOrderGeneratorParameters generator_parameters{programs,
|
||||
ProductionOrderGeneratorParameters generator_parameters{graph_parameters.get_programs(),
|
||||
graph_parameters.factory._generator._random_seed,
|
||||
graph_parameters.factory._generator._min_send_speed_rate,
|
||||
graph_parameters.factory._generator._max_send_speed_rate};
|
||||
graph_parameters.factory._generator._max_send_speed_rate,
|
||||
graph_parameters.factory._generator._po_number,
|
||||
graph_parameters.factory._generator._po_order};
|
||||
|
||||
_generator = new GeneratorSimulator("G", generator_parameters);
|
||||
_router = new RouterSimulator("R", {graph_parameters.factory._pools.size()});
|
||||
@@ -81,45 +65,131 @@ public:
|
||||
this->add_child(ROUTER, _router);
|
||||
this->add_child(GENERATOR, _generator);
|
||||
|
||||
// item stocks
|
||||
for (const auto &p: graph_parameters.factory._stocks) {
|
||||
_item_stocks.push_back(
|
||||
new ItemStockSimulator("I_S_" + std::to_string(p._id),
|
||||
ItemStockParameters{graph_parameters.get_item_stock(p._id),
|
||||
graph_parameters.get_machines_to_item_stock(p._id)}));
|
||||
this->add_child(ITEM_STOCK + p._id, _item_stocks.back());
|
||||
}
|
||||
|
||||
// intermediate stocks
|
||||
for (const auto &p: graph_parameters.factory._pools) {
|
||||
unsigned int pool_id = std::get<0>(p);
|
||||
for (const auto &s: std::get<3>(p)) {
|
||||
_stocks[std::make_pair(pool_id, s._id)] = new StockSimulator(
|
||||
"S_" + std::to_string(pool_id) + "_" + std::to_string(s._id),
|
||||
StockParameters{graph_parameters.get_machines_to_in_stock(pool_id, s._id),
|
||||
graph_parameters.get_machines_to_out_stock(pool_id, s._id),
|
||||
s._capacity});
|
||||
this->add_child(STOCK + pool_id * 100 + s._id, _stocks[std::make_pair(pool_id, s._id)]);
|
||||
}
|
||||
}
|
||||
|
||||
// pool + machines
|
||||
for (const auto &p: graph_parameters.factory._pools) {
|
||||
unsigned int pool_id = std::get<0>(p);
|
||||
std::map<unsigned int, unsigned int> capacities;
|
||||
|
||||
for (const auto &m: std::get<2>(p)) {
|
||||
capacities[m->machine_id] = m->capacity;
|
||||
}
|
||||
_pool_routers.push_back(
|
||||
new PoolRouterSimulator("P_R_" + std::to_string(std::get<0>(p)),
|
||||
PoolRouterParameters{std::get<1>(p), std::get<2>(p).size()}));
|
||||
new PoolRouterSimulator("P_R_" + std::to_string(pool_id), PoolRouterParameters{std::get<1>(p), capacities}));
|
||||
this->add_child(POOL_ROUTER + std::get<0>(p), _pool_routers.back());
|
||||
out({_router, artis::factory::Router::outputs::OUT_P + std::get<0>(p)})
|
||||
out({_router, artis::factory::Router::outputs::OUT_P + pool_id})
|
||||
>> in({_pool_routers.back(), artis::factory::PoolRouter::inputs::IN});
|
||||
out({_pool_routers.back(), artis::factory::PoolRouter::outputs::OUT})
|
||||
>> in({_router, artis::factory::Router::inputs::IN_P + std::get<0>(p)});
|
||||
>> in({_router, artis::factory::Router::inputs::IN_P + pool_id});
|
||||
|
||||
// machines
|
||||
for (const auto &m: std::get<2>(p)) {
|
||||
switch (m->machine_type) {
|
||||
case PROCESSOR: {
|
||||
auto &processor_parameters = (ProcessorParameters &) (*m);
|
||||
auto new_processor = new ProcessorSimulator(
|
||||
"M_" + std::to_string(m->pool_id) + "_" + std::to_string(m->machine_id), (ProcessorParameters &) (*m));
|
||||
"M_" + std::to_string(m->pool_id) + "_" + std::to_string(m->machine_id), processor_parameters);
|
||||
|
||||
_processors.push_back(new_processor);
|
||||
this->add_child(MACHINE + machine_index, new_processor);
|
||||
|
||||
// connection processor <-> pool router
|
||||
out({_pool_routers.back(), artis::factory::PoolRouter::outputs::OUT_M + m->machine_id})
|
||||
>> in({new_processor, artis::factory::Processor::inputs::IN});
|
||||
out({new_processor, artis::factory::Processor::outputs::OUT})
|
||||
>> in({_pool_routers.back(), artis::factory::PoolRouter::inputs::IN_M + m->machine_id});
|
||||
|
||||
// connection processor <-> item stock
|
||||
std::vector<unsigned int> item_stocks;
|
||||
|
||||
for (const auto &q: processor_parameters.in_out) {
|
||||
for (const auto &r: q.second._ins) {
|
||||
if (r._source._pool_id == -1) {
|
||||
item_stocks.push_back(r._source._stock_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &q: item_stocks) {
|
||||
out({new_processor, artis::factory::Processor::outputs::OUT_ITEM_DEMAND + q})
|
||||
>> in({_item_stocks.back(), artis::factory::ItemStock::inputs::IN + m->machine_id});
|
||||
out({_item_stocks.back(), artis::factory::ItemStock::outputs::OUT + m->machine_id})
|
||||
>> in({new_processor, artis::factory::Processor::inputs::IN_ITEM});
|
||||
}
|
||||
// connection processor <-> intermediate stock
|
||||
std::vector<std::pair<unsigned int, unsigned int>> stocks;
|
||||
|
||||
for (const auto &q: processor_parameters.in_out) {
|
||||
for (const auto &r: q.second._outs) {
|
||||
auto u = std::make_pair((unsigned int) r._destination._pool_id, r._destination._stock_id);
|
||||
|
||||
if (r._destination._pool_id != -1 and std::find(stocks.cbegin(), stocks.cend(), u) == stocks.cend()) {
|
||||
stocks.push_back(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &q: stocks) {
|
||||
out({new_processor, artis::factory::Processor::outputs::OUT_STOCK + (q.first * 100 + q.second)})
|
||||
>> in({_stocks[q], artis::factory::Stock::inputs::IN});
|
||||
out({new_processor, artis::factory::Processor::outputs::OUT_STOCK_AVAILABLE + (q.first * 100 + q.second)})
|
||||
>> in({_stocks[q], artis::factory::Stock::inputs::IN_STOCK_AVAILABLE + m->machine_id});
|
||||
out({_stocks[q], artis::factory::Stock::outputs::OUT_STOCK_AVAILABLE + m->machine_id})
|
||||
>> in(
|
||||
{new_processor, artis::factory::Processor::inputs::IN_STOCK_AVAILABLE + (q.first * 100 + q.second)});
|
||||
}
|
||||
stocks.clear();
|
||||
for (const auto &q: processor_parameters.in_out) {
|
||||
for (const auto &r: q.second._ins) {
|
||||
auto u = std::make_pair((unsigned int) r._source._pool_id, r._source._stock_id);
|
||||
|
||||
if (r._source._pool_id != -1 and std::find(stocks.cbegin(), stocks.cend(), u) == stocks.cend()) {
|
||||
stocks.push_back(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &q: stocks) {
|
||||
out({new_processor, artis::factory::Processor::outputs::OUT_STOCK_DEMAND + (q.first * 100 + q.second)})
|
||||
>> in({_stocks[q], artis::factory::Stock::inputs::IN_DEMAND + m->machine_id});
|
||||
out({_stocks[q], artis::factory::Stock::outputs::OUT + m->machine_id})
|
||||
>> in({new_processor, artis::factory::Processor::inputs::IN_STOCK});
|
||||
}
|
||||
++machine_index;
|
||||
break;
|
||||
}
|
||||
case SINK: {
|
||||
auto new_sink = new SinkSimulator(
|
||||
"M_" + std::to_string(m->pool_id) + "_" + std::to_string(m->machine_id),
|
||||
SinkParameters{}
|
||||
);
|
||||
auto new_sink = new SinkSimulator(
|
||||
"M_" + std::to_string(m->pool_id) + "_" + std::to_string(m->machine_id), (SinkParameters &) (*m));
|
||||
|
||||
_sinks.push_back(new_sink);
|
||||
this->add_child(MACHINE + machine_index, new_sink);
|
||||
_sinks.push_back(new_sink);
|
||||
this->add_child(MACHINE + machine_index, new_sink);
|
||||
|
||||
// PoolRouter -> Sink
|
||||
out({_pool_routers.back(), artis::factory::PoolRouter::outputs::OUT_M + m->machine_id})
|
||||
>> in({_sinks.back(), artis::factory::Sink::inputs::IN});
|
||||
|
||||
++machine_index;
|
||||
break;
|
||||
// connection sink <-> pool router
|
||||
out({_pool_routers.back(), artis::factory::PoolRouter::outputs::OUT_M + m->machine_id})
|
||||
>> in({new_sink, artis::factory::Sink::inputs::IN});
|
||||
out({new_sink, artis::factory::Sink::outputs::OUT})
|
||||
>> in({_pool_routers.back(), artis::factory::PoolRouter::inputs::FINISH});
|
||||
++machine_index;
|
||||
break;
|
||||
}
|
||||
case SEPARATOR: {
|
||||
// TODO
|
||||
@@ -129,11 +199,12 @@ public:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
case CONVEYOR :{
|
||||
case CONVEYOR : {
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
default: {}
|
||||
default: {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,12 +218,16 @@ private:
|
||||
typedef artis::pdevs::Simulator<artis::common::DoubleTime, artis::factory::PoolRouter, artis::factory::PoolRouterParameters> PoolRouterSimulator;
|
||||
typedef artis::pdevs::Simulator<artis::common::DoubleTime, artis::factory::Processor, artis::factory::ProcessorParameters> ProcessorSimulator;
|
||||
typedef artis::pdevs::Simulator<artis::common::DoubleTime, artis::factory::Sink, artis::factory::SinkParameters> SinkSimulator;
|
||||
typedef artis::pdevs::Simulator<artis::common::DoubleTime, artis::factory::ItemStock, artis::factory::ItemStockParameters> ItemStockSimulator;
|
||||
typedef artis::pdevs::Simulator<artis::common::DoubleTime, artis::factory::Stock, artis::factory::StockParameters> StockSimulator;
|
||||
|
||||
GeneratorSimulator *_generator;
|
||||
RouterSimulator *_router;
|
||||
std::vector<PoolRouterSimulator *> _pool_routers;
|
||||
std::vector<ProcessorSimulator *> _processors;
|
||||
std::vector<SinkSimulator *> _sinks;
|
||||
std::vector<ItemStockSimulator *> _item_stocks;
|
||||
std::map<std::pair<unsigned int, unsigned int>, StockSimulator *> _stocks;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
128
src/FactoryGraphManagerParameters.hpp
Normal file
128
src/FactoryGraphManagerParameters.hpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @file FactoryGraphManagerParameters.hpp
|
||||
* @author The ARTIS Development Team
|
||||
* See the AUTHORS or Authors.txt file
|
||||
*/
|
||||
|
||||
/*
|
||||
* ARTIS - the multimodeling and simulation environment
|
||||
* This file is a part of the ARTIS environment
|
||||
*
|
||||
* Copyright (C) 2013-2023 ULCO http://www.univ-littoral.fr
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ARTIS_FACTORY_FACTORY_GRAPH_MANAGER_PARAMETERS_HPP
|
||||
#define ARTIS_FACTORY_FACTORY_GRAPH_MANAGER_PARAMETERS_HPP
|
||||
|
||||
#include "JsonReader.hpp"
|
||||
|
||||
namespace artis::factory {
|
||||
|
||||
struct FactoryGraphManagerParameters {
|
||||
Factory factory;
|
||||
|
||||
std::map<unsigned int, int> get_item_stock(unsigned int id) const {
|
||||
std::map<unsigned int, int> items;
|
||||
|
||||
auto it = std::find_if(factory._stocks.cbegin(), factory._stocks.cend(),
|
||||
[id](const auto &e) { return e._id == id; });
|
||||
if (it != factory._stocks.cend()) {
|
||||
for (const auto &e: it->_items) {
|
||||
items[e._id] = e._quantity;
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
std::vector<unsigned int> get_machines_to_item_stock(unsigned int id) const {
|
||||
std::vector<unsigned int> machines;
|
||||
|
||||
for (const auto &p: factory._products) {
|
||||
for (const auto &q: p.second._pool_jobs) {
|
||||
for (const auto &r: q._machine_jobs) {
|
||||
for (const auto &s: r._ins) {
|
||||
if (s._source._stock_id == id and
|
||||
std::find(machines.cbegin(), machines.cend(), r._machine_id) == machines.cend()) {
|
||||
machines.push_back(r._machine_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return machines;
|
||||
}
|
||||
|
||||
std::vector<unsigned int> get_machines_to_in_stock(unsigned int pool_id, unsigned int stock_id) const {
|
||||
std::vector<unsigned int> machines;
|
||||
|
||||
for (const auto &p: factory._products) {
|
||||
for (const auto &q: p.second._pool_jobs) {
|
||||
for (const auto &r: q._machine_jobs) {
|
||||
for (const auto &s: r._ins) {
|
||||
if (s._source._pool_id == (int) pool_id and s._source._stock_id == stock_id and
|
||||
std::find(machines.cbegin(), machines.cend(), r._machine_id) == machines.cend()) {
|
||||
machines.push_back(r._machine_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return machines;
|
||||
}
|
||||
|
||||
std::vector<unsigned int> get_machines_to_out_stock(unsigned int pool_id, unsigned int stock_id) const {
|
||||
std::vector<unsigned int> machines;
|
||||
|
||||
for (const auto &p: factory._products) {
|
||||
for (const auto &q: p.second._pool_jobs) {
|
||||
for (const auto &r: q._machine_jobs) {
|
||||
for (const auto &s: r._outs) {
|
||||
if (s._destination._pool_id == (int) pool_id and s._destination._stock_id == stock_id and
|
||||
std::find(machines.cbegin(), machines.cend(), r._machine_id) == machines.cend()) {
|
||||
machines.push_back(r._machine_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return machines;
|
||||
}
|
||||
|
||||
std::map<unsigned int, Program> get_programs() const {
|
||||
std::map<unsigned int, Program> programs;
|
||||
|
||||
for (const auto &product: factory._products) {
|
||||
unsigned int product_id = product.first;
|
||||
Program program;
|
||||
|
||||
for (const auto &pool_job: product.second._pool_jobs) {
|
||||
std::vector<uint8_t> machines;
|
||||
|
||||
for (const auto &machine_job: pool_job._machine_jobs) {
|
||||
machines.push_back(machine_job._machine_id);
|
||||
}
|
||||
program.emplace_back((uint8_t) pool_job._pool_id, machines);
|
||||
}
|
||||
programs[product_id] = program;
|
||||
}
|
||||
return programs;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //ARTIS_FACTORY_FACTORY_GRAPH_MANAGER_PARAMETERS_HPP
|
||||
14
src/Item.hpp
14
src/Item.hpp
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file Item.hpp
|
||||
* @file Item.hpp
|
||||
* @author The ARTIS Development Team
|
||||
* See the AUTHORS or Authors.txt file
|
||||
*/
|
||||
@@ -29,13 +29,13 @@
|
||||
|
||||
namespace artis::factory {
|
||||
|
||||
struct BaseItem {
|
||||
unsigned int _id;
|
||||
};
|
||||
struct BaseItem {
|
||||
unsigned int _id;
|
||||
};
|
||||
|
||||
struct Item {
|
||||
unsigned int _po_id;
|
||||
};
|
||||
struct Item {
|
||||
unsigned int _po_id;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -29,28 +29,58 @@
|
||||
namespace artis::factory {
|
||||
|
||||
void ItemStock::dint(const Time & /* t */) {
|
||||
// TODO
|
||||
switch (_phase) {
|
||||
case Phase::SEND: {
|
||||
_demands.clear();
|
||||
_phase = Phase::WAIT;
|
||||
break;
|
||||
}
|
||||
case Phase::WAIT: {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ItemStock::dext(const Time & /* t */, const Time & /* e */, const Bag &bag) {
|
||||
std::for_each(bag.begin(), bag.end(), [](const ExternalEvent & /* event */) {
|
||||
// TODO
|
||||
std::for_each(bag.begin(), bag.end(), [this](const ExternalEvent &event) {
|
||||
ItemDemand demand;
|
||||
|
||||
event.data()(demand);
|
||||
if (_items[demand.item_id] == -1 or _items[demand.item_id] >= (int) demand.quantity) {
|
||||
_demands.push_back(std::make_pair(event.port_index() - inputs::IN, demand));
|
||||
if (_items[demand.item_id] != -1) {
|
||||
_items[demand.item_id] -= (int) demand.quantity;
|
||||
}
|
||||
_phase = Phase::SEND;
|
||||
} else {
|
||||
_unsatisfied_demands.push_back(std::make_pair(event.port_index() - inputs::IN, demand));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ItemStock::start(const Time & /* t */) {
|
||||
// TODO
|
||||
_phase = Phase::WAIT;
|
||||
_items = _parameters._items;
|
||||
}
|
||||
|
||||
Time ItemStock::ta(const Time & /* t */) const {
|
||||
// TODO
|
||||
switch (_phase) {
|
||||
case Phase::WAIT:
|
||||
return artis::common::DoubleTime::infinity;
|
||||
case Phase::SEND:
|
||||
return 0;
|
||||
}
|
||||
return artis::common::DoubleTime::infinity;
|
||||
}
|
||||
|
||||
Bag ItemStock::lambda(const Time & /* t */) const {
|
||||
Bag bag;
|
||||
|
||||
// TODO
|
||||
if (_phase == Phase::SEND) {
|
||||
for (const auto &e: _demands) {
|
||||
bag.push_back(ExternalEvent(outputs::OUT + e.first, ItemResponse(e.second.item_id, e.second.po_id)));
|
||||
}
|
||||
}
|
||||
return bag;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,42 @@
|
||||
|
||||
namespace artis::factory {
|
||||
|
||||
struct ItemDemand {
|
||||
int item_id;
|
||||
int po_id;
|
||||
unsigned int quantity;
|
||||
|
||||
ItemDemand(int item_id = -1, int po_id = -1, unsigned int quantity = 0) : item_id(item_id), po_id(po_id),
|
||||
quantity(quantity) {}
|
||||
|
||||
bool operator==(const ItemDemand &other) const {
|
||||
return item_id == other.item_id and po_id == other.po_id and quantity == other.quantity;
|
||||
}
|
||||
|
||||
std::string to_string() const {
|
||||
return "Demand < " + std::to_string(item_id) + " | " + std::to_string(po_id) + " | " + std::to_string(quantity) +
|
||||
" >";
|
||||
}
|
||||
};
|
||||
|
||||
struct ItemResponse {
|
||||
int item_id;
|
||||
int po_id;
|
||||
|
||||
ItemResponse(int item_id = -1, int po_id = -1) : item_id(item_id), po_id(po_id) {}
|
||||
|
||||
bool operator==(const ItemResponse &other) const {
|
||||
return item_id == other.item_id and po_id == other.po_id;
|
||||
}
|
||||
|
||||
std::string to_string() const {
|
||||
return "Response < " + std::to_string(item_id) + " | " + std::to_string(po_id) + " >";
|
||||
}
|
||||
};
|
||||
|
||||
struct ItemStockParameters {
|
||||
std::map<unsigned int, int> _items;
|
||||
std::vector<unsigned int> _machines;
|
||||
};
|
||||
|
||||
class ItemStock : public Dynamics<ItemStock, ItemStockParameters> {
|
||||
@@ -55,9 +90,11 @@ public:
|
||||
};
|
||||
|
||||
ItemStock(const std::string &name, const Context<ItemStock, ItemStockParameters> &context)
|
||||
: Dynamics<ItemStock, ItemStockParameters>(name, context) {
|
||||
input_port({inputs::IN, "in"});
|
||||
output_port({outputs::OUT, "out"});
|
||||
: Dynamics<ItemStock, ItemStockParameters>(name, context), _parameters(context.parameters()) {
|
||||
for (const auto &m: _parameters._machines) {
|
||||
input_port({inputs::IN + m, "in_" + std::to_string(m)});
|
||||
output_port({outputs::OUT + m, "out_" + std::to_string(m)});
|
||||
}
|
||||
}
|
||||
|
||||
~ItemStock() override = default;
|
||||
@@ -75,7 +112,29 @@ public:
|
||||
artis::common::event::Value observe(const Time &t, unsigned int index) const override;
|
||||
|
||||
private:
|
||||
// TODO (state)
|
||||
struct Phase {
|
||||
enum values {
|
||||
WAIT,
|
||||
SEND
|
||||
};
|
||||
|
||||
static std::string to_string(const values &value) {
|
||||
switch (value) {
|
||||
case WAIT:
|
||||
return "WAIT";
|
||||
case SEND:
|
||||
return "SEND";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
ItemStockParameters _parameters;
|
||||
|
||||
Phase::values _phase;
|
||||
std::map<unsigned int, int> _items;
|
||||
std::vector<std::pair<unsigned int, ItemDemand>> _demands;
|
||||
std::vector<std::pair<unsigned int, ItemDemand>> _unsatisfied_demands;
|
||||
};
|
||||
|
||||
} // namespace artis::factory
|
||||
|
||||
@@ -39,27 +39,11 @@
|
||||
|
||||
namespace artis::factory {
|
||||
|
||||
struct Location {
|
||||
int _pool_id;
|
||||
unsigned int _stock_id;
|
||||
};
|
||||
|
||||
struct In {
|
||||
int _id; // -1 if global
|
||||
Location _source;
|
||||
unsigned int _quantity;
|
||||
};
|
||||
|
||||
struct Out {
|
||||
int _id; // -1 if global
|
||||
Location _destination;
|
||||
unsigned int _quantity;
|
||||
};
|
||||
|
||||
struct MachineJob {
|
||||
unsigned int _machine_id;
|
||||
std::vector<In> _ins;
|
||||
std::vector<Out> _outs;
|
||||
std::shared_ptr<Durations> _durations;
|
||||
};
|
||||
|
||||
struct PoolJob {
|
||||
@@ -69,16 +53,20 @@ struct PoolJob {
|
||||
|
||||
struct Product {
|
||||
unsigned int _id;
|
||||
std::vector<std::pair<unsigned int, unsigned int>> _components;
|
||||
std::vector<PoolJob> _pool_jobs;
|
||||
bool final;
|
||||
};
|
||||
|
||||
struct Generator {
|
||||
uint _random_seed;
|
||||
uint _min_send_speed_rate;
|
||||
uint _max_send_speed_rate;
|
||||
int _po_number;
|
||||
std::vector<unsigned int> _po_order;
|
||||
};
|
||||
|
||||
struct Stock {
|
||||
struct IntermediateStock {
|
||||
unsigned int _id;
|
||||
int _capacity; // if -1 then infinity
|
||||
};
|
||||
@@ -88,16 +76,16 @@ struct Item {
|
||||
int _quantity; // if -1 then infinity
|
||||
};
|
||||
|
||||
struct ItemStock {
|
||||
struct GlobalStock {
|
||||
unsigned int _id;
|
||||
std::vector<Item> _items;
|
||||
};
|
||||
|
||||
struct Factory {
|
||||
Generator _generator;
|
||||
std::vector<std::tuple<unsigned int, unsigned int, std::vector<std::shared_ptr<MachineParameters>>, std::vector<Stock> >> _pools;
|
||||
std::vector<std::tuple<unsigned int, unsigned int, std::vector<std::shared_ptr<MachineParameters>>, std::vector<IntermediateStock> >> _pools;
|
||||
std::map<unsigned int, Product> _products;
|
||||
std::vector<ItemStock> _stocks;
|
||||
std::vector<GlobalStock> _stocks;
|
||||
};
|
||||
|
||||
class JsonReader {
|
||||
@@ -114,6 +102,7 @@ public:
|
||||
parse_products(data["products"]);
|
||||
parse_generator(data["generator"]);
|
||||
parse_pools(data["pools"]);
|
||||
parse_product_job_durations(data["products"]);
|
||||
if (data.contains("stocks")) {
|
||||
parse_item_stocks(data["stocks"]);
|
||||
}
|
||||
@@ -123,7 +112,8 @@ private:
|
||||
void parse_generator(const nlohmann::json &data) {
|
||||
_factory._generator = Generator{data["random_seed"].get<unsigned int>(),
|
||||
data["min_send_speed_rate"].get<unsigned int>(),
|
||||
data["max_send_speed_rate"].get<unsigned int>()};
|
||||
data["max_send_speed_rate"].get<unsigned int>(),
|
||||
-1, {}};
|
||||
}
|
||||
|
||||
std::vector<In> parse_ins(const nlohmann::json &data) {
|
||||
@@ -144,8 +134,22 @@ private:
|
||||
std::vector<std::shared_ptr<MachineParameters>> machines;
|
||||
|
||||
for (const nlohmann::json &machine: data) {
|
||||
unsigned int machine_id = machine["id"].get<unsigned int>();
|
||||
unsigned int machine_type = machine["type"].get<unsigned int>();
|
||||
unsigned int capacity = machine.contains("capacity") ? machine["capacity"].get<unsigned int>() : 1;
|
||||
std::map<unsigned int, InOut> in_out;
|
||||
|
||||
for (const auto &product: _factory._products) {
|
||||
for (const auto &pool_job: product.second._pool_jobs) {
|
||||
if (pool_job._pool_id == pool_id) {
|
||||
for (const auto &machine_job: pool_job._machine_jobs) {
|
||||
if (machine_job._machine_id == machine_id) {
|
||||
in_out[product.first] = InOut{machine_job._ins, machine_job._outs};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (machine_type) {
|
||||
case PROCESSOR: {
|
||||
unsigned int load_time = machine.contains("load_time") ? machine["load_time"].get<unsigned int>() : 0;
|
||||
@@ -154,32 +158,32 @@ private:
|
||||
unsigned int unload_time = machine.contains("unload_time") ? machine["unload_time"].get<unsigned int>() : 0;
|
||||
|
||||
machines.push_back(
|
||||
std::make_shared<ProcessorParameters>(ProcessorParameters{{machine["id"].get<unsigned int>(), machine_type,
|
||||
pool_id}, load_time, processing_time,
|
||||
unload_time}));
|
||||
std::make_shared<ProcessorParameters>(ProcessorParameters{{machine_id, machine_type, pool_id, capacity},
|
||||
ProcessorDurations{{}, load_time, processing_time,
|
||||
unload_time}, in_out, {}}));
|
||||
break;
|
||||
}
|
||||
case SINK: {
|
||||
machines.push_back(std::make_shared<SinkParameters>(
|
||||
SinkParameters{{machine["id"].get<unsigned int>(), machine_type, pool_id}}));
|
||||
machines.push_back(
|
||||
std::make_shared<SinkParameters>(SinkParameters{{machine_id, machine_type, pool_id, capacity}}));
|
||||
break;
|
||||
}
|
||||
case SEPARATOR: {
|
||||
// TODO
|
||||
machines.push_back(std::make_shared<SeparatorParameters>(
|
||||
SeparatorParameters{{machine["id"].get<unsigned int>(), machine_type, pool_id}}));
|
||||
machines.push_back(
|
||||
std::make_shared<SeparatorParameters>(SeparatorParameters{{machine_id, machine_type, pool_id, capacity}}));
|
||||
break;
|
||||
}
|
||||
case COMBINER : {
|
||||
// TODO
|
||||
machines.push_back(std::make_shared<CombinerParameters>(
|
||||
CombinerParameters{{machine["id"].get<unsigned int>(), machine_type, pool_id}}));
|
||||
machines.push_back(
|
||||
std::make_shared<CombinerParameters>(CombinerParameters{{machine_id, machine_type, pool_id, capacity}}));
|
||||
break;
|
||||
}
|
||||
case CONVEYOR : {
|
||||
// TODO
|
||||
machines.push_back(std::make_shared<ConveyorParameters>(
|
||||
ConveyorParameters{{machine["id"].get<unsigned int>(), machine_type, pool_id}}));
|
||||
machines.push_back(
|
||||
std::make_shared<ConveyorParameters>(ConveyorParameters{{machine_id, machine_type, pool_id, capacity}}));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -207,7 +211,7 @@ private:
|
||||
for (const nlohmann::json &pool: data) {
|
||||
unsigned int pool_id = pool["id"].get<unsigned int>();
|
||||
unsigned int pool_type = pool["type"].get<unsigned int>();
|
||||
std::vector<Stock> stocks;
|
||||
std::vector<IntermediateStock> stocks;
|
||||
|
||||
if (pool.contains("stocks")) {
|
||||
for (const nlohmann::json &stock: pool["stocks"]) {
|
||||
@@ -224,8 +228,54 @@ private:
|
||||
void parse_products(const nlohmann::json &data) {
|
||||
for (const nlohmann::json &product: data) {
|
||||
unsigned int product_id = product["id"].get<unsigned int>();
|
||||
bool final = product.contains("final") ? product["final"].get<bool>() : true;
|
||||
std::vector<std::pair<unsigned int, unsigned int>> components;
|
||||
|
||||
_factory._products[product_id] = Product{product_id, parse_program(product["program"])};
|
||||
if (product.contains("components")) {
|
||||
for (const nlohmann::json &component: product["components"]) {
|
||||
components.emplace_back(component["id"].get<unsigned int>(), component["number"].get<unsigned int>());
|
||||
}
|
||||
}
|
||||
_factory._products[product_id] = Product{product_id, components, parse_program(product["program"]), final};
|
||||
}
|
||||
}
|
||||
|
||||
void parse_product_job_durations(const nlohmann::json &data) {
|
||||
for (const nlohmann::json &product: data) {
|
||||
unsigned int product_id = product["id"].get<unsigned int>();
|
||||
unsigned int pool_index = 0;
|
||||
|
||||
for (const nlohmann::json &pool_machine: product["program"]) {
|
||||
unsigned int pool_id = pool_machine["poolID"].get<unsigned int>();
|
||||
const auto &pool = *std::find_if(_factory._pools.cbegin(), _factory._pools.cend(),
|
||||
[pool_id](const auto &e) { return std::get<0>(e) == pool_id; });
|
||||
const auto &machines = std::get<2>(pool);
|
||||
unsigned int sequence_index = 0;
|
||||
|
||||
for (const nlohmann::json &machine: pool_machine["sequence"]) {
|
||||
if (machine.is_object()) {
|
||||
unsigned int machine_id = machine["machineID"].get<unsigned int>();
|
||||
const auto &m = *std::find_if(machines.cbegin(), machines.cend(),
|
||||
[machine_id](const auto &e) { return e->machine_id == machine_id; });
|
||||
|
||||
if (m->machine_type == PROCESSOR) {
|
||||
auto &M = (ProcessorParameters &) (*m);
|
||||
auto d = std::make_shared<ProcessorDurations>(
|
||||
ProcessorDurations{{},
|
||||
machine.contains("load_time") ? machine["load_time"].get<unsigned int>() : 0,
|
||||
machine.contains("processing_time")
|
||||
? machine["processing_time"].get<unsigned int>() : 0,
|
||||
machine.contains("unload_time") ? machine["unload_time"].get<unsigned int>() : 0
|
||||
});
|
||||
|
||||
_factory._products[product_id]._pool_jobs[pool_index]._machine_jobs[sequence_index]._durations = d;
|
||||
M.product_durations[product_id] = d;
|
||||
}
|
||||
}
|
||||
++sequence_index;
|
||||
}
|
||||
++pool_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,9 +304,9 @@ private:
|
||||
if (machine.contains("outs")) {
|
||||
outs = parse_outs(machine["outs"]);
|
||||
}
|
||||
sequence.push_back(MachineJob{machine["machineID"].get<unsigned int>(), ins, outs});
|
||||
sequence.push_back(MachineJob{machine["machineID"].get<unsigned int>(), ins, outs, {}});
|
||||
} else {
|
||||
sequence.push_back(MachineJob{machine.get<unsigned int>(), {}, {}});
|
||||
sequence.push_back(MachineJob{machine.get<unsigned int>(), {}, {}, {}});
|
||||
}
|
||||
}
|
||||
return sequence;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file Machine.hpp
|
||||
* @file Machine.hpp
|
||||
* @author The ARTIS Development Team
|
||||
* See the AUTHORS or Authors.txt file
|
||||
*/
|
||||
@@ -32,11 +32,15 @@
|
||||
|
||||
namespace artis::factory {
|
||||
|
||||
struct MachineParameters {
|
||||
uint machine_id;
|
||||
uint machine_type;
|
||||
uint pool_id;
|
||||
};
|
||||
struct MachineParameters {
|
||||
uint machine_id;
|
||||
uint machine_type;
|
||||
uint pool_id;
|
||||
uint capacity;
|
||||
};
|
||||
|
||||
struct Durations {
|
||||
};
|
||||
|
||||
} // namespace artis::factory
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
*/
|
||||
|
||||
#include "PoolRouter.hpp"
|
||||
#include "Sink.hpp"
|
||||
|
||||
namespace artis::factory {
|
||||
|
||||
@@ -43,25 +42,13 @@ void PoolRouter::dint(const Time & /* t */) {
|
||||
|
||||
assert(it != _pending_po.cend());
|
||||
|
||||
if ((*it)->is_finish()) {
|
||||
_available_machines[(*it)->last_operation()->get_loc_index()] = true;
|
||||
} else if ((*it)->current_operation().get_type() == CHANGE_POOL_TYPE) {
|
||||
_available_machines[(*it)->previous_operation()->get_loc_index()] = true;
|
||||
} else {
|
||||
//_available_machines[(*it)->current_operation().get_loc_index()] = false;
|
||||
auto idx = (*it)->current_operation().get_loc_index();
|
||||
|
||||
// Modifié pour gérer le Sink
|
||||
if (idx == _available_machines.size()-1) {// Par simplicité, je considère que la dernière machine connectée est le Sink
|
||||
_available_machines[idx] = true;// Et si idx est le dernier index, alors cette "machine" reste disponible
|
||||
} else {
|
||||
_available_machines[idx] = false;
|
||||
}
|
||||
if (not (*it)->is_finish() and (*it)->current_operation().get_type() != CHANGE_POOL_TYPE) {
|
||||
_available_machines[(*it)->current_operation().get_loc_index()]--;
|
||||
}
|
||||
_pending_po.erase(it);
|
||||
if (std::find_if(_pending_po.cbegin(), _pending_po.cend(), [this](const auto &e) {
|
||||
return e->is_finish() or e->current_operation().get_type() == CHANGE_POOL_TYPE or
|
||||
_available_machines[e->current_operation().get_loc_index()];
|
||||
_available_machines[e->current_operation().get_loc_index()] > 0;
|
||||
}) != _pending_po.cend()) {
|
||||
_phase = Phase::SEND;
|
||||
} else {
|
||||
@@ -80,19 +67,24 @@ void PoolRouter::dext(const Time &t, const Time & /* e */, const Bag &bag) {
|
||||
event.data()(data);
|
||||
_pending_po.push_back(std::make_unique<ProductionOrder>(data, event.data().size()));
|
||||
_pending_po.back()->next();
|
||||
} else if (event.port_index() == inputs::FINISH) {
|
||||
unsigned int index;
|
||||
|
||||
event.data()(index);
|
||||
_available_machines[index]++;
|
||||
} else if (event.port_index() >= inputs::IN_M) {
|
||||
uint8_t *data = nullptr;
|
||||
|
||||
event.data()(data);
|
||||
_pending_po.push_back(std::make_unique<ProductionOrder>(data, event.data().size()));
|
||||
_available_machines[event.port_index() - inputs::IN_M] = true;
|
||||
_available_machines[event.port_index() - inputs::IN_M]++;
|
||||
_pending_po.back()->next();
|
||||
}
|
||||
}
|
||||
);
|
||||
if (std::find_if(_pending_po.cbegin(), _pending_po.cend(), [this](const auto &e) {
|
||||
return e->is_finish() or e->current_operation().get_type() == CHANGE_POOL_TYPE or
|
||||
_available_machines[e->current_operation().get_loc_index()];
|
||||
_available_machines[e->current_operation().get_loc_index()] > 0;
|
||||
}) != _pending_po.cend()) {
|
||||
_phase = Phase::SEND;
|
||||
} else {
|
||||
@@ -102,6 +94,9 @@ void PoolRouter::dext(const Time &t, const Time & /* e */, const Bag &bag) {
|
||||
|
||||
void PoolRouter::start(const Time & /* t */) {
|
||||
_phase = Phase::INIT;
|
||||
for (const auto &e: _parameters.capacities) {
|
||||
_available_machines[e.first] = e.second;
|
||||
}
|
||||
}
|
||||
|
||||
Time PoolRouter::ta(const Time & /* t */) const {
|
||||
@@ -155,8 +150,8 @@ PoolRouter::ProductionOrders::const_iterator PoolRouter::next_po() const {
|
||||
return it;
|
||||
} else {
|
||||
return std::find_if(_pending_po.cbegin(), _pending_po.cend(),
|
||||
[this](const auto &e) { return _available_machines[e->current_operation().get_loc_index()]; });
|
||||
[this](const auto &e) { return _available_machines.at(e->current_operation().get_loc_index()) > 0; });
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace artis::factory
|
||||
} // namespace artis::factory
|
||||
@@ -36,14 +36,14 @@ namespace artis::factory {
|
||||
|
||||
struct PoolRouterParameters {
|
||||
uint type;
|
||||
std::size_t machine_number;
|
||||
std::map<unsigned int, unsigned int> capacities;
|
||||
};
|
||||
|
||||
class PoolRouter : public Dynamics<PoolRouter, PoolRouterParameters> {
|
||||
public:
|
||||
struct inputs {
|
||||
enum values {
|
||||
IN, IN_M = 1000
|
||||
IN, FINISH, IN_M = 1000
|
||||
};
|
||||
};
|
||||
|
||||
@@ -60,14 +60,13 @@ public:
|
||||
};
|
||||
|
||||
PoolRouter(const std::string &name, const Context<PoolRouter, PoolRouterParameters> &context)
|
||||
: Dynamics<PoolRouter, PoolRouterParameters>(name, context),
|
||||
_parameters(context.parameters()), _available_machines(context.parameters().machine_number) {
|
||||
input_port({inputs::IN, "in"});
|
||||
: Dynamics<PoolRouter, PoolRouterParameters>(name, context), _parameters(context.parameters()) {
|
||||
input_ports({{inputs::IN, "in"},
|
||||
{inputs::FINISH, "finish"}});
|
||||
output_port({outputs::OUT, "out"});
|
||||
for (unsigned int i = 0; i < context.parameters().machine_number; ++i) {
|
||||
output_port({outputs::OUT_M + i, "out_m" + std::to_string(i)});
|
||||
input_port({inputs::IN_M + i, "in_m" + std::to_string(i)});
|
||||
_available_machines[i] = true;
|
||||
for (const auto &e: context.parameters().capacities) {
|
||||
output_port({outputs::OUT_M + e.first, "out_m_" + std::to_string(e.first)});
|
||||
input_port({inputs::IN_M + e.first, "in_m_" + std::to_string(e.first)});
|
||||
}
|
||||
observables({{vars::WAITING_PO_NUMBER, "waiting_po_number"}});
|
||||
}
|
||||
@@ -115,7 +114,7 @@ private:
|
||||
// state
|
||||
Phase::values _phase;
|
||||
ProductionOrders _pending_po;
|
||||
std::vector<bool> _available_machines;
|
||||
std::map<unsigned int, unsigned int> _available_machines;
|
||||
};
|
||||
|
||||
} // namespace artis::factory
|
||||
|
||||
@@ -24,63 +24,97 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ItemStock.hpp"
|
||||
#include "Processor.hpp"
|
||||
#include "Stock.hpp"
|
||||
|
||||
namespace artis::factory {
|
||||
|
||||
void Processor::dint(const Time & t) {
|
||||
switch (_phase) {
|
||||
case Phase::INIT: {
|
||||
_phase = Phase::WAIT;
|
||||
break;
|
||||
}
|
||||
case Phase::READY:
|
||||
_po.reset(nullptr);
|
||||
_phase = Phase::WAIT;
|
||||
break;
|
||||
case Phase::WAIT:
|
||||
assert(false);
|
||||
break;
|
||||
case Phase::LOADING: {
|
||||
_phase = Phase::PROCESSING;
|
||||
break;
|
||||
}
|
||||
case Phase::PROCESSING: {
|
||||
_phase = Phase::UNLOADING;
|
||||
break;
|
||||
}
|
||||
case Phase::UNLOADING: {
|
||||
_phase = Phase::READY;
|
||||
|
||||
#ifdef WITH_TRACE
|
||||
Trace::trace()
|
||||
<< TraceElement(get_name(), t,
|
||||
artis::common::FormalismType::PDEVS,
|
||||
artis::common::FunctionType::DELTA_INT,
|
||||
artis::common::LevelType::USER)
|
||||
<< "FINISH po = " << _po->to_string();
|
||||
Trace::trace().flush();
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
void Processor::dint(const Time &t) {
|
||||
for (auto it = _jobs.cbegin(); it != _jobs.cend();) {
|
||||
if (it->second._next_time == t and it->second._phase == Phase::READY) {
|
||||
it = _jobs.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
for (auto &j: _jobs) {
|
||||
auto &job = j.second;
|
||||
|
||||
if (job._next_time == t) {
|
||||
switch (job._phase) {
|
||||
case Phase::DEMAND_SUPPLY:
|
||||
job._phase = Phase::WAIT_SUPPLY;
|
||||
job._next_time = artis::common::DoubleTime::infinity;
|
||||
break;
|
||||
case Phase::WAIT_SUPPLY:
|
||||
case Phase::WAIT:
|
||||
assert(false);
|
||||
break;
|
||||
case Phase::LOADING: {
|
||||
job._phase = Phase::PROCESSING;
|
||||
job._next_time = t + durations(job._po->get_productID()).processing_time;
|
||||
break;
|
||||
}
|
||||
case Phase::PROCESSING: {
|
||||
job._phase = Phase::UNLOADING;
|
||||
job._next_time = t + durations(job._po->get_productID()).unload_time;
|
||||
break;
|
||||
}
|
||||
case Phase::UNLOADING: {
|
||||
auto it = _parameters.in_out.find(job._po->get_productID());
|
||||
|
||||
void Processor::dext(const Time &t, const Time & /* e */, const Bag &bag) {
|
||||
if (it != _parameters.in_out.cend() and not it->second._outs.empty()) {
|
||||
job._phase = Phase::SEND_STOCK_AVAILABLE;
|
||||
job._next_time = t;
|
||||
} else {
|
||||
job._phase = Phase::READY;
|
||||
job._next_time = t;
|
||||
}
|
||||
|
||||
#ifdef WITH_TRACE
|
||||
Trace::trace()
|
||||
<< TraceElement(get_name(), t,
|
||||
artis::common::FormalismType::PDEVS,
|
||||
artis::common::FunctionType::DELTA_INT,
|
||||
artis::common::LevelType::USER)
|
||||
<< "FINISH po = " << job._po->to_string();
|
||||
Trace::trace().flush();
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
case Phase::SEND_STOCK_AVAILABLE: {
|
||||
job._phase = Phase::WAIT_STOCK_AVAILABLE;
|
||||
job._next_time = artis::common::DoubleTime::infinity;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Processor::dext(const Time &t, const Time & /* e */, const Bag &bag) {
|
||||
std::for_each(bag.begin(), bag.end(), [this, t](const ExternalEvent &event) {
|
||||
if (event.port_index() == inputs::IN) {
|
||||
if (event.on_port(inputs::IN)) {
|
||||
uint8_t *data = nullptr;
|
||||
|
||||
// TODO
|
||||
assert(_po == nullptr);
|
||||
assert(_jobs.size() < _parameters.capacity);
|
||||
|
||||
event.data()(data);
|
||||
_po = std::make_unique<ProductionOrder>(data, event.data().size());
|
||||
_phase = Phase::LOADING;
|
||||
|
||||
auto po = std::make_unique<ProductionOrder>(data, event.data().size());
|
||||
auto po_id = po->getID();
|
||||
auto product_id = po->get_productID();
|
||||
auto it = _parameters.in_out.find(po->get_productID());
|
||||
|
||||
if (it == _parameters.in_out.end() or it->second._ins.empty()) {
|
||||
_jobs[po_id] = Job{Phase::LOADING, std::move(po), 0, t + durations(product_id).load_time};
|
||||
} else {
|
||||
_jobs[po_id] = Job{Phase::DEMAND_SUPPLY, std::move(po), (unsigned int) it->second._ins.size(), t};
|
||||
}
|
||||
|
||||
#ifdef WITH_TRACE
|
||||
Trace::trace()
|
||||
@@ -88,43 +122,125 @@ namespace artis::factory {
|
||||
artis::common::FormalismType::PDEVS,
|
||||
artis::common::FunctionType::DELTA_EXT,
|
||||
artis::common::LevelType::USER)
|
||||
<< "START po = " << _po->to_string();
|
||||
<< "START po = " << _jobs[po_id]._po->to_string();
|
||||
Trace::trace().flush();
|
||||
#endif
|
||||
|
||||
} else if (event.on_port(inputs::IN_ITEM)) {
|
||||
ItemResponse response;
|
||||
|
||||
event.data()(response);
|
||||
|
||||
assert(_jobs.find(response.po_id) != _jobs.end());
|
||||
|
||||
auto &job = _jobs[response.po_id];
|
||||
job._demand_number--;
|
||||
if (job._demand_number == 0) {
|
||||
job._phase = Phase::LOADING;
|
||||
job._next_time = t + durations(job._po->get_productID()).load_time;
|
||||
}
|
||||
} else if (event.on_port(inputs::IN_STOCK)) {
|
||||
ProductResponse response;
|
||||
|
||||
event.data()(response);
|
||||
|
||||
assert(_jobs.find(response.po_id) != _jobs.end());
|
||||
|
||||
auto &job = _jobs[response.po_id];
|
||||
|
||||
job._demand_number--;
|
||||
if (job._demand_number == 0) {
|
||||
job._phase = Phase::LOADING;
|
||||
job._next_time = t + durations(job._po->get_productID()).load_time;
|
||||
}
|
||||
} else if (event.port_index() >= inputs::IN_STOCK_AVAILABLE) {
|
||||
StockAvailableResponse response;
|
||||
|
||||
event.data()(response);
|
||||
|
||||
assert(_jobs.find(response.po_id) != _jobs.end());
|
||||
|
||||
auto &job = _jobs[response.po_id];
|
||||
|
||||
switch (response.response) {
|
||||
case StockAvailableResponse::AVAILABLE: {
|
||||
job._phase = Phase::READY;
|
||||
job._next_time = t;
|
||||
break;
|
||||
}
|
||||
case StockAvailableResponse::NOT_AVAILABLE: {
|
||||
job._phase = Phase::WAIT_STOCK_AVAILABLE;
|
||||
job._next_time = artis::common::DoubleTime::infinity;
|
||||
break;
|
||||
}
|
||||
case StockAvailableResponse::NEW_AVAILABLE: {
|
||||
job._phase = Phase::SEND_STOCK_AVAILABLE;
|
||||
job._next_time = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Processor::start(const Time & /* t */) {
|
||||
// TODO
|
||||
_phase = Phase::INIT;
|
||||
}
|
||||
|
||||
Time Processor::ta(const Time & /* t */) const {
|
||||
// TODO
|
||||
switch (_phase) {
|
||||
case Phase::INIT:
|
||||
case Phase::READY:
|
||||
return 0;
|
||||
case Phase::WAIT:
|
||||
return artis::common::DoubleTime::infinity;
|
||||
case Phase::LOADING:
|
||||
return _parameters.load_time;
|
||||
case Phase::PROCESSING:
|
||||
return _parameters.processing_time;
|
||||
case Phase::UNLOADING:
|
||||
return _parameters.unload_time;
|
||||
Time Processor::ta(const Time &t) const {
|
||||
if (not _jobs.empty()) {
|
||||
return std::min_element(_jobs.cbegin(), _jobs.cend(), [](const auto &lhs, const auto &rhs) {
|
||||
return (lhs.second._next_time != artis::common::DoubleTime::infinity and
|
||||
lhs.second._next_time < rhs.second._next_time) or
|
||||
rhs.second._next_time == artis::common::DoubleTime::infinity;
|
||||
})->second._next_time - t;
|
||||
}
|
||||
return artis::common::DoubleTime::infinity;
|
||||
}
|
||||
|
||||
Bag Processor::lambda(const Time & /* t */) const {
|
||||
Bag Processor::lambda(const Time &t) const {
|
||||
Bag bag;
|
||||
|
||||
// TODO
|
||||
if (_phase == Phase::READY) {
|
||||
bag.push_back(ExternalEvent(outputs::OUT, common::event::Value(_po->_buffer, _po->_size)));
|
||||
for (const auto &e: _jobs) {
|
||||
const auto &job = e.second;
|
||||
|
||||
if (job._next_time == t) {
|
||||
if (job._phase == Phase::READY) {
|
||||
bag.push_back(ExternalEvent(outputs::OUT, common::event::Value(job._po->_buffer, job._po->_size)));
|
||||
|
||||
auto it = _parameters.in_out.find(job._po->get_productID());
|
||||
|
||||
if (it != _parameters.in_out.cend() and not it->second._outs.empty()) {
|
||||
const auto &p = it->second._outs.front()._destination;
|
||||
|
||||
bag.push_back(ExternalEvent(outputs::OUT_STOCK + int(p._pool_id * 100 + p._stock_id),
|
||||
StockEntry(e.first, job._po->operation_index(),
|
||||
job._po->get_productID(), 1)));
|
||||
}
|
||||
} else if (job._phase == Phase::DEMAND_SUPPLY) {
|
||||
auto it = _parameters.in_out.find(job._po->get_productID());
|
||||
|
||||
for (const auto &item: it->second._ins) {
|
||||
if (item._source._pool_id == -1) {
|
||||
bag.push_back(ExternalEvent(outputs::OUT_ITEM_DEMAND + (int) item._source._stock_id,
|
||||
ItemDemand(item._id, e.first, item._quantity)));
|
||||
} else {
|
||||
bag.push_back(
|
||||
ExternalEvent(outputs::OUT_STOCK_DEMAND + (int) (item._source._pool_id * 100 + item._source._stock_id),
|
||||
ProductDemand(e.first, job._po->operation_index() - (job._po->get_operation(
|
||||
job._po->operation_index() - 1)->get_type() == CHANGE_POOL_TYPE ? 2 : 1),
|
||||
job._po->get_productID(), 1)));
|
||||
}
|
||||
}
|
||||
} else if (job._phase == Phase::SEND_STOCK_AVAILABLE) {
|
||||
auto it = _parameters.in_out.find(job._po->get_productID());
|
||||
|
||||
if (it != _parameters.in_out.cend() and not it->second._outs.empty()) {
|
||||
const auto &p = it->second._outs.front()._destination;
|
||||
|
||||
bag.push_back(ExternalEvent(outputs::OUT_STOCK_AVAILABLE + int(p._pool_id * 100 + p._stock_id), e.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bag;
|
||||
}
|
||||
@@ -133,4 +249,4 @@ artis::common::event::Value Processor::observe(const Time & /* t */, unsigned in
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace artis::factory
|
||||
} // namespace artis::factory
|
||||
@@ -33,23 +33,51 @@
|
||||
|
||||
namespace artis::factory {
|
||||
|
||||
struct ProcessorParameters : MachineParameters {
|
||||
struct Location {
|
||||
int _pool_id; // -1 if global
|
||||
unsigned int _stock_id;
|
||||
};
|
||||
|
||||
struct In {
|
||||
int _id; // -1 if current product
|
||||
Location _source;
|
||||
unsigned int _quantity;
|
||||
};
|
||||
|
||||
struct Out {
|
||||
int _id; // -1 if current product
|
||||
Location _destination;
|
||||
unsigned int _quantity;
|
||||
};
|
||||
|
||||
struct InOut {
|
||||
std::vector<In> _ins;
|
||||
std::vector<Out> _outs;
|
||||
};
|
||||
|
||||
struct ProcessorDurations : Durations {
|
||||
uint load_time;
|
||||
uint processing_time;
|
||||
uint unload_time;
|
||||
};
|
||||
|
||||
struct ProcessorParameters : MachineParameters {
|
||||
ProcessorDurations durations;
|
||||
std::map<unsigned int, InOut> in_out;
|
||||
std::map<unsigned int, std::shared_ptr<ProcessorDurations>> product_durations;
|
||||
};
|
||||
|
||||
class Processor : public Dynamics<Processor, ProcessorParameters> {
|
||||
public:
|
||||
struct inputs {
|
||||
enum values {
|
||||
IN
|
||||
IN, IN_ITEM, IN_STOCK, IN_STOCK_AVAILABLE = 4000
|
||||
};
|
||||
};
|
||||
|
||||
struct outputs {
|
||||
enum values {
|
||||
OUT
|
||||
OUT, OUT_ITEM_DEMAND = 1000, OUT_STOCK = 2000, OUT_STOCK_DEMAND = 3000, OUT_STOCK_AVAILABLE = 4000
|
||||
};
|
||||
};
|
||||
|
||||
@@ -60,8 +88,66 @@ public:
|
||||
|
||||
Processor(const std::string &name, const Context<Processor, ProcessorParameters> &context)
|
||||
: Dynamics<Processor, ProcessorParameters>(name, context), _parameters(context.parameters()) {
|
||||
input_port({inputs::IN, "in"});
|
||||
input_ports({{inputs::IN, "in"},
|
||||
{inputs::IN_ITEM, "in_supply"},
|
||||
{inputs::IN_STOCK, "in_stock"}});
|
||||
output_port({outputs::OUT, "out"});
|
||||
|
||||
// demand: processor -> item stocks
|
||||
std::vector<unsigned int> item_stocks;
|
||||
|
||||
for (const auto &p: _parameters.in_out) {
|
||||
for (const auto &q: p.second._ins) {
|
||||
if (q._source._pool_id == -1 and
|
||||
std::find(item_stocks.cbegin(), item_stocks.cend(), q._source._stock_id) == item_stocks.cend()) {
|
||||
item_stocks.push_back(q._source._stock_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &p: item_stocks) {
|
||||
output_port({outputs::OUT_ITEM_DEMAND + p, "out_demand_supply_" + std::to_string(p)});
|
||||
}
|
||||
|
||||
// processor -> intermediate stocks
|
||||
std::vector<std::pair<unsigned int, unsigned int>> stocks;
|
||||
|
||||
for (const auto &p: _parameters.in_out) {
|
||||
for (const auto &q: p.second._outs) {
|
||||
auto r = std::make_pair((unsigned int) q._destination._pool_id, q._destination._stock_id);
|
||||
|
||||
if (q._destination._pool_id != -1 and std::find(stocks.cbegin(), stocks.cend(), r) == stocks.cend()) {
|
||||
stocks.push_back(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &p: stocks) {
|
||||
output_port(
|
||||
{outputs::OUT_STOCK + (p.first * 100 + p.second),
|
||||
"out_stock_" + std::to_string(p.first) + "_" + std::to_string(p.second)});
|
||||
output_port(
|
||||
{outputs::OUT_STOCK_AVAILABLE + (p.first * 100 + p.second),
|
||||
"out_stock_available_" + std::to_string(p.first) + "_" + std::to_string(p.second)});
|
||||
input_port(
|
||||
{inputs::IN_STOCK_AVAILABLE + (p.first * 100 + p.second),
|
||||
"in_stock_available_" + std::to_string(p.first) + "_" + std::to_string(p.second)});
|
||||
}
|
||||
|
||||
// demand: processor -> intermediate stocks
|
||||
stocks.clear();
|
||||
for (const auto &p: _parameters.in_out) {
|
||||
for (const auto &q: p.second._ins) {
|
||||
auto r = std::make_pair((unsigned int) q._source._pool_id, q._source._stock_id);
|
||||
|
||||
if (q._source._pool_id != -1 and std::find(stocks.cbegin(), stocks.cend(), r) == stocks.cend()) {
|
||||
stocks.push_back(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &p: stocks) {
|
||||
output_port(
|
||||
{outputs::OUT_STOCK_DEMAND + (p.first * 100 + p.second),
|
||||
"out_stock_demand_" + std::to_string(p.first) + "_" + std::to_string(p.second)});
|
||||
}
|
||||
}
|
||||
|
||||
~Processor() override = default;
|
||||
@@ -79,21 +165,29 @@ public:
|
||||
artis::common::event::Value observe(const Time &t, unsigned int index) const override;
|
||||
|
||||
private:
|
||||
const ProcessorDurations &durations(unsigned int product_id) const {
|
||||
if (_parameters.product_durations.find(product_id) == _parameters.product_durations.cend()) {
|
||||
return _parameters.durations;
|
||||
} else {
|
||||
return *_parameters.product_durations.at(product_id);
|
||||
}
|
||||
}
|
||||
|
||||
struct Phase {
|
||||
enum values {
|
||||
INIT,
|
||||
READY,
|
||||
WAIT,
|
||||
LOADING,
|
||||
PROCESSING,
|
||||
UNLOADING
|
||||
UNLOADING,
|
||||
DEMAND_SUPPLY,
|
||||
WAIT_SUPPLY,
|
||||
SEND_STOCK_AVAILABLE,
|
||||
WAIT_STOCK_AVAILABLE
|
||||
};
|
||||
|
||||
static std::string to_string(const values &value) {
|
||||
switch (value) {
|
||||
case INIT:
|
||||
return "INIT";
|
||||
case READY:
|
||||
return "READY";
|
||||
case WAIT:
|
||||
@@ -104,19 +198,33 @@ private:
|
||||
return "PROCESSING";
|
||||
case UNLOADING:
|
||||
return "UNLOADING";
|
||||
case DEMAND_SUPPLY:
|
||||
return "DEMAND SUPPLY";
|
||||
case WAIT_SUPPLY:
|
||||
return "WAIT SUPPLY";
|
||||
case SEND_STOCK_AVAILABLE:
|
||||
return "SEND STOCK AVAILABLE";
|
||||
case WAIT_STOCK_AVAILABLE:
|
||||
return "WAIT STOCK AVAILABLE";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
// parameters
|
||||
struct Job {
|
||||
Phase::values _phase;
|
||||
std::unique_ptr<ProductionOrder> _po;
|
||||
unsigned int _demand_number;
|
||||
Time _next_time;
|
||||
};
|
||||
|
||||
// parameters
|
||||
ProcessorParameters _parameters;
|
||||
|
||||
// state
|
||||
Phase::values _phase;
|
||||
std::unique_ptr<ProductionOrder> _po;
|
||||
// state
|
||||
std::map<unsigned int, Job> _jobs; // key = po_id
|
||||
};
|
||||
|
||||
} // namespace artis::factory
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -84,7 +84,8 @@ ProductionOrder::ProductionOrder(uint8_t *buffer, std::size_t size)
|
||||
_is_finish = _buffer[INDEX_POSITION] + 1 >= _buffer[OPERATION_NUMBER_POSITION];
|
||||
}
|
||||
|
||||
ProductionOrder::ProductionOrder(uint16_t ID, uint16_t product_ID, const Program &program) : _is_finish(false) {
|
||||
ProductionOrder::ProductionOrder(uint16_t ID, uint16_t parent_ID, uint32_t due_date, uint16_t product_ID,
|
||||
const Program &program) : _is_finish(false) {
|
||||
Reference reference{0, 0};
|
||||
std::size_t operation_number = 0;
|
||||
|
||||
@@ -108,6 +109,16 @@ ProductionOrder::ProductionOrder(uint16_t ID, uint16_t product_ID, const Program
|
||||
_buffer[reference._byte_index++] = (uint8_t) (ID >> 8);
|
||||
_buffer[reference._byte_index++] = (uint8_t) (ID & 0xFF);
|
||||
|
||||
// parent ID
|
||||
_buffer[reference._byte_index++] = (uint8_t) (parent_ID >> 8);
|
||||
_buffer[reference._byte_index++] = (uint8_t) (parent_ID & 0xFF);
|
||||
|
||||
// due date
|
||||
_buffer[reference._byte_index++] = (uint8_t) (due_date >> 24);
|
||||
_buffer[reference._byte_index++] = (uint8_t) ((due_date >> 16) & 0xFF);
|
||||
_buffer[reference._byte_index++] = (uint8_t) ((due_date >> 8) & 0xFF);
|
||||
_buffer[reference._byte_index++] = (uint8_t) (due_date & 0xFF);
|
||||
|
||||
// product ID
|
||||
_buffer[reference._byte_index++] = (uint8_t) (product_ID >> 8);
|
||||
_buffer[reference._byte_index++] = (uint8_t) (product_ID & 0xFF);
|
||||
@@ -199,8 +210,14 @@ std::unique_ptr<Operation> ProductionOrder::previous_operation() const {
|
||||
std::string ProductionOrder::to_string() const {
|
||||
std::string str = "[ ";
|
||||
uint16_t ID = (_buffer[ID_POSITION] << 8) + _buffer[ID_POSITION + 1];
|
||||
uint16_t parentID = (_buffer[PARENT_ID_POSITION] << 8) + _buffer[PARENT_ID_POSITION + 1];
|
||||
|
||||
str += std::to_string(ID) + " ][ ";
|
||||
str += std::to_string(ID);
|
||||
if (ID != parentID) {
|
||||
str += + "/" + std::to_string(parentID) +" ][ ";
|
||||
|
||||
}
|
||||
str += " ][ ";
|
||||
for (uint8_t i = 0; i < _buffer[OPERATION_NUMBER_POSITION]; ++i) {
|
||||
if (_buffer[INDEX_POSITION] == i) {
|
||||
str += "<";
|
||||
|
||||
@@ -34,15 +34,17 @@
|
||||
|
||||
namespace artis::factory {
|
||||
|
||||
// HEADER = [bit number (16 bits)][ID (16 bits)][Product ID (16 bits)][index (8 bits)][operation number (8 bits)]
|
||||
const std::size_t POOL_SIZE = 7; // bit number
|
||||
const std::size_t MACHINE_SIZE = 4; // bit number
|
||||
const std::size_t TYPE_SIZE = 2; // bit number
|
||||
const std::size_t HEADER_SIZE = 8; // byte number
|
||||
// HEADER = [bit number (16 bits)][ID (16 bits)][parent ID (16 bits)][Due date (32 bits)][Product ID (16 bits)][index (8 bits)][operation number (8 bits)]
|
||||
const std::size_t POOL_SIZE = 7; // bit number
|
||||
const std::size_t MACHINE_SIZE = 4; // bit number
|
||||
const std::size_t TYPE_SIZE = 2; // bitModifier le générateur de PO afin de générer tous les PO number
|
||||
const std::size_t HEADER_SIZE = 14; // byte number
|
||||
|
||||
const std::size_t BIT_NUMBER_POSITION = 0;
|
||||
const std::size_t ID_POSITION = BIT_NUMBER_POSITION + 2;
|
||||
const std::size_t PRODUCT_ID_POSITION = ID_POSITION + 2;
|
||||
const std::size_t PARENT_ID_POSITION = ID_POSITION + 2;
|
||||
const std::size_t DUE_DATE_POSITION = PARENT_ID_POSITION + 2;
|
||||
const std::size_t PRODUCT_ID_POSITION = DUE_DATE_POSITION + 4;
|
||||
const std::size_t INDEX_POSITION = PRODUCT_ID_POSITION + 2;
|
||||
const std::size_t OPERATION_NUMBER_POSITION = INDEX_POSITION + 1;
|
||||
|
||||
@@ -139,7 +141,7 @@ struct ProductionOrder {
|
||||
|
||||
~ProductionOrder() { delete[] _buffer; }
|
||||
|
||||
ProductionOrder(uint16_t ID, uint16_t product_ID, const Program &program);
|
||||
ProductionOrder(uint16_t ID, uint16_t parent_ID, uint32_t due_date, uint16_t product_ID, const Program &program);
|
||||
|
||||
const Operation ¤t_operation() const { return *_current_operation; }
|
||||
|
||||
@@ -147,8 +149,17 @@ struct ProductionOrder {
|
||||
return (_buffer[ID_POSITION] << 8) + _buffer[ID_POSITION + 1];
|
||||
}
|
||||
|
||||
uint32_t get_due_date() const {
|
||||
return (_buffer[DUE_DATE_POSITION] << 24) + (_buffer[DUE_DATE_POSITION] << 16) + (_buffer[DUE_DATE_POSITION] << 8) +
|
||||
_buffer[DUE_DATE_POSITION + 1];
|
||||
}
|
||||
|
||||
std::unique_ptr<Operation> get_operation(uint8_t index) const;
|
||||
|
||||
uint16_t get_parentID() const {
|
||||
return (_buffer[PARENT_ID_POSITION] << 8) + _buffer[PARENT_ID_POSITION + 1];
|
||||
}
|
||||
|
||||
uint16_t get_productID() const {
|
||||
return (_buffer[PRODUCT_ID_POSITION] << 8) + _buffer[PRODUCT_ID_POSITION + 1];
|
||||
}
|
||||
|
||||
@@ -28,20 +28,30 @@
|
||||
|
||||
namespace artis::factory {
|
||||
|
||||
void ProductionOrderGenerator::dint(const Time & /* &t */) {
|
||||
void ProductionOrderGenerator::dint(const Time &t) {
|
||||
switch (_phase) {
|
||||
case Phase::INIT:
|
||||
_phase = Phase::SEND;
|
||||
break;
|
||||
case Phase::SEND: {
|
||||
_current_id++;
|
||||
_po_counter++;
|
||||
_productID = _productIDs[_distrib_product(_rng)];
|
||||
_po = std::make_unique<ProductionOrder>(_current_id, _productID, _parameters.programs[_productID]);
|
||||
_send_speed = _distrib_send_speed(_rng);
|
||||
_phase = Phase::SEND;
|
||||
if (_parameters.po_number == -1) {
|
||||
generate_production_orders(t);
|
||||
_sigma = _distrib_send_speed(_rng);
|
||||
_phase = Phase::SEND;
|
||||
} else {
|
||||
if (_po_index < (unsigned int) _parameters.po_number - 1) {
|
||||
_po_index++;
|
||||
if (not _parameters.po_order.empty()) {
|
||||
_sigma = 0;
|
||||
}
|
||||
} else {
|
||||
_phase = Phase::FINISH;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Phase::FINISH:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,14 +61,18 @@ void ProductionOrderGenerator::dext(const Time & /* t */, const Time & /* e */,
|
||||
});
|
||||
}
|
||||
|
||||
void ProductionOrderGenerator::start(const Time & /* t */) {
|
||||
void ProductionOrderGenerator::start(const Time &t) {
|
||||
_phase = Phase::INIT;
|
||||
_po = nullptr;
|
||||
_current_id = 0;
|
||||
_productID = _productIDs[_distrib_product(_rng)];
|
||||
_po = std::make_unique<ProductionOrder>(_current_id, _productID, _parameters.programs[_productID]);
|
||||
_po_counter = 0;
|
||||
_send_speed = 0; // _distrib_send_speed(_rng);
|
||||
_po_index = 0;
|
||||
if (_parameters.po_number == -1) {
|
||||
generate_production_orders(t);
|
||||
} else {
|
||||
for (unsigned int i = 0; i < (unsigned int) _parameters.po_number; ++i) {
|
||||
generate_production_orders(t);
|
||||
}
|
||||
}
|
||||
_sigma = 0;
|
||||
}
|
||||
|
||||
Time ProductionOrderGenerator::ta(const Time & /* t */) const {
|
||||
@@ -66,7 +80,9 @@ Time ProductionOrderGenerator::ta(const Time & /* t */) const {
|
||||
case Phase::INIT:
|
||||
return 0;
|
||||
case Phase::SEND:
|
||||
return _send_speed;
|
||||
return _sigma;
|
||||
case Phase::FINISH:
|
||||
return artis::common::DoubleTime::infinity;
|
||||
}
|
||||
return artis::common::DoubleTime::infinity;
|
||||
}
|
||||
@@ -75,8 +91,12 @@ Bag ProductionOrderGenerator::lambda(const Time & /* t */) const {
|
||||
Bag bag;
|
||||
|
||||
if (_phase == Phase::SEND) {
|
||||
if (_po) {
|
||||
bag.push_back(ExternalEvent(outputs::OUT, common::event::Value(_po->_buffer, _po->_size)));
|
||||
if (_parameters.po_order.empty()) {
|
||||
bag.push_back(ExternalEvent(outputs::OUT, common::event::Value(_pos[_po_index]->_buffer, _pos[_po_index]->_size)));
|
||||
} else {
|
||||
const auto &po = _pos[_parameters.po_order[_po_index]];
|
||||
|
||||
bag.push_back(ExternalEvent(outputs::OUT, common::event::Value(po->_buffer, po->_size)));
|
||||
}
|
||||
}
|
||||
return bag;
|
||||
@@ -85,9 +105,16 @@ Bag ProductionOrderGenerator::lambda(const Time & /* t */) const {
|
||||
artis::common::event::Value ProductionOrderGenerator::observe(const Time & /* t */, unsigned int index) const {
|
||||
switch (index) {
|
||||
case vars::TOTAL_PO_NUMBER:
|
||||
return (unsigned int) _po_counter;
|
||||
return (unsigned int) _po_index;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void ProductionOrderGenerator::generate_production_orders(const Time &t) {
|
||||
_productID = _productIDs[_distrib_product(_rng)];
|
||||
_pos.push_back(std::make_unique<ProductionOrder>(_current_id, _current_id, t + 8 * 60 * 60, _productID,
|
||||
_parameters.programs[_productID]));
|
||||
_current_id++;
|
||||
}
|
||||
|
||||
} // namespace artis::factory
|
||||
|
||||
@@ -42,6 +42,8 @@ struct ProductionOrderGeneratorParameters {
|
||||
uint random_seed;
|
||||
uint min_send_speed_rate;
|
||||
uint max_send_speed_rate;
|
||||
int po_number{-1};
|
||||
std::vector<unsigned int> po_order{};
|
||||
};
|
||||
|
||||
class ProductionOrderGenerator
|
||||
@@ -89,9 +91,11 @@ public:
|
||||
artis::common::event::Value observe(const Time &t, unsigned int index) const override;
|
||||
|
||||
private:
|
||||
void generate_production_orders(const Time & t);
|
||||
|
||||
struct Phase {
|
||||
enum values {
|
||||
INIT, SEND
|
||||
INIT, SEND, FINISH
|
||||
};
|
||||
|
||||
static std::string to_string(const values &value) {
|
||||
@@ -100,6 +104,8 @@ private:
|
||||
return "INIT";
|
||||
case SEND:
|
||||
return "SEND";
|
||||
case FINISH:
|
||||
return "FINISH";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -119,11 +125,11 @@ private:
|
||||
std::vector<unsigned int> _productIDs;
|
||||
|
||||
unsigned int _productID;
|
||||
std::unique_ptr<ProductionOrder> _po;
|
||||
std::vector<std::unique_ptr<ProductionOrder>> _pos;
|
||||
|
||||
unsigned int _current_id;
|
||||
std::size_t _po_counter;
|
||||
unsigned int _send_speed;
|
||||
std::size_t _po_index;
|
||||
unsigned int _sigma;
|
||||
};
|
||||
|
||||
} // namespace artis::factory
|
||||
|
||||
66
src/Sink.cpp
66
src/Sink.cpp
@@ -28,52 +28,51 @@
|
||||
|
||||
namespace artis::factory {
|
||||
|
||||
void Sink::dint(const Time &/*t*/) {
|
||||
// TODO
|
||||
// Inutile si l'on consiède que cet élément ce fait que recevoir des POs. Il ne fait rien par lui-même, et ne varie que en fonction de son environnement.
|
||||
void Sink::dint(const Time & /* t */) {
|
||||
switch (_phase) {
|
||||
case Phase::WAIT: {
|
||||
assert(false);
|
||||
}
|
||||
case Phase::SEND: {
|
||||
_phase = Phase::WAIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sink::dext(const Time &t, const Time & /* e */, const Bag &bag) {
|
||||
std::for_each(bag.begin(), bag.end(), [this, t](const ExternalEvent &event) {
|
||||
|
||||
std::for_each(bag.begin(), bag.end(), [t, this](const ExternalEvent &event) {
|
||||
if (event.port_index() == inputs::IN) {
|
||||
uint8_t *data = nullptr;
|
||||
|
||||
event.data()(data);
|
||||
std::unique_ptr<ProductionOrder> po = std::make_unique<ProductionOrder>(data, event.data().size());
|
||||
#ifdef WITH_TRACE
|
||||
Trace::trace()
|
||||
<< TraceElement(get_name(), t,
|
||||
artis::common::FormalismType::PDEVS,
|
||||
artis::common::FunctionType::DELTA_EXT,
|
||||
artis::common::LevelType::USER)
|
||||
<< "Sink received po = " << po->to_string();
|
||||
Trace::trace().flush();
|
||||
#endif
|
||||
_pos.push_back(std::move(po));//Je ne peux pas dupliquer ce pointer unique dans la liste, je dois explicitement le déplacer.
|
||||
_phase = Phase::LOADED;
|
||||
_finished_po.push_back(std::make_unique<ProductionOrder>(data, event.data().size()));
|
||||
_phase = Phase::SEND;
|
||||
|
||||
#ifdef WITH_TRACE
|
||||
Trace::trace()
|
||||
<< TraceElement(get_name(), t,
|
||||
artis::common::FormalismType::PDEVS,
|
||||
artis::common::FunctionType::DELTA_EXT,
|
||||
artis::common::LevelType::USER)
|
||||
<< "FINISH po = " << _finished_po.back()->to_string();
|
||||
Trace::trace().flush();
|
||||
#endif
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Sink::start(const Time & /* t */) {
|
||||
_phase = Phase::INIT;
|
||||
// Préparation du modèle, j'imagine que ce n'est pas utile donc passage immédiat en READY
|
||||
_phase = Phase::READY;
|
||||
// Le modèle est prêt, on attend des PO
|
||||
_phase = Phase::WAIT;
|
||||
}
|
||||
|
||||
Time Sink::ta(const Time & /* t */) const {
|
||||
switch (_phase) {
|
||||
case Phase::INIT:// Phase transitoire, je n'y reste pas, le modèle ne fait qu'y passer
|
||||
case Phase::READY:// Idem
|
||||
//case Phase::UNLOADING:// Déchargement des PO dans la sortie, ce n'est que transitoire
|
||||
return 0;
|
||||
case Phase::WAIT:// J'attends un premier PO, potentiellement infini
|
||||
case Phase::LOADED:// J'ai un PO en stock, j'attends d'en faire quelque chose,ce qui est potentiellement infini
|
||||
case Phase::WAIT: {
|
||||
return artis::common::DoubleTime::infinity;
|
||||
}
|
||||
case Phase::SEND: {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return artis::common::DoubleTime::infinity;
|
||||
}
|
||||
@@ -81,13 +80,18 @@ Time Sink::ta(const Time & /* t */) const {
|
||||
Bag Sink::lambda(const Time & /* t */) const {
|
||||
Bag bag;
|
||||
|
||||
// TODO
|
||||
// Pour le moment, Sink ne laisse pas sortir les POs arrivés dedans. Inutile de définir ceci.
|
||||
if (_phase == Phase::SEND) {
|
||||
bag.push_back(ExternalEvent(outputs::OUT, (unsigned int) _parameters.machine_id));
|
||||
}
|
||||
return bag;
|
||||
}
|
||||
|
||||
artis::common::event::Value Sink::observe(const Time & /* t */, unsigned int /* index */) const {
|
||||
artis::common::event::Value Sink::observe(const Time & /* t */, unsigned int index) const {
|
||||
switch (index) {
|
||||
case vars::FINISHED_PO_NUMBER:
|
||||
return (unsigned int) _finished_po.size();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace artis::factory
|
||||
} // namespace artis::factory
|
||||
53
src/Sink.hpp
53
src/Sink.hpp
@@ -34,7 +34,6 @@
|
||||
namespace artis::factory {
|
||||
|
||||
struct SinkParameters : MachineParameters {
|
||||
|
||||
};
|
||||
|
||||
class Sink : public Dynamics<Sink, SinkParameters> {
|
||||
@@ -53,13 +52,15 @@ public:
|
||||
|
||||
struct vars {
|
||||
enum values {
|
||||
FINISHED_PO_NUMBER
|
||||
};
|
||||
};
|
||||
|
||||
Sink(const std::string &name, const Context<Sink, SinkParameters> &context)
|
||||
: Dynamics<Sink, SinkParameters>(name, context) {
|
||||
: Dynamics<Sink, SinkParameters>(name, context), _parameters(context.parameters()) {
|
||||
input_port({inputs::IN, "in"});
|
||||
output_port({outputs::OUT, "out"});
|
||||
observables({{vars::FINISHED_PO_NUMBER, "finished_po_number"}});
|
||||
}
|
||||
|
||||
~Sink() override = default;
|
||||
@@ -77,38 +78,30 @@ public:
|
||||
artis::common::event::Value observe(const Time &t, unsigned int index) const override;
|
||||
|
||||
private:
|
||||
struct Phase {
|
||||
enum values {
|
||||
INIT,
|
||||
READY,
|
||||
WAIT,
|
||||
LOADED,
|
||||
//UNLOADING
|
||||
};
|
||||
|
||||
static std::string to_string(const values &value) {
|
||||
switch (value) {
|
||||
case INIT:
|
||||
return "INIT";
|
||||
case READY:
|
||||
return "READY";
|
||||
case WAIT:
|
||||
return "WAIT";
|
||||
case LOADED:
|
||||
return "LOADED";
|
||||
/*case UNLOADING:
|
||||
return "UNLOADING";*/
|
||||
}
|
||||
return "";
|
||||
}
|
||||
struct Phase {
|
||||
enum values {
|
||||
WAIT, SEND
|
||||
};
|
||||
|
||||
static std::string to_string(const values &value) {
|
||||
switch (value) {
|
||||
case WAIT:
|
||||
return "WAIT";
|
||||
case SEND:
|
||||
return "SEND";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::deque<std::unique_ptr<ProductionOrder>> ProductionOrders;
|
||||
|
||||
Phase::values _phase;
|
||||
std::vector<std::unique_ptr<ProductionOrder>> _pos;
|
||||
}; // class Sink
|
||||
SinkParameters _parameters;
|
||||
|
||||
Phase::values _phase;
|
||||
ProductionOrders _finished_po;
|
||||
};
|
||||
|
||||
} // namespace artis::factory
|
||||
|
||||
#endif // ARTIS_FACTORY_SINK_HPP
|
||||
#endif
|
||||
103
src/Stock.cpp
103
src/Stock.cpp
@@ -29,32 +29,119 @@
|
||||
namespace artis::factory {
|
||||
|
||||
void Stock::dint(const Time & /* t */) {
|
||||
// TODO
|
||||
switch (_phase) {
|
||||
case Phase::SEND_AVAILABLE: {
|
||||
_available_demands.clear();
|
||||
_phase = Phase::WAIT;
|
||||
break;
|
||||
}
|
||||
case Phase::SEND: {
|
||||
_demands.clear();
|
||||
_phase = Phase::WAIT;
|
||||
break;
|
||||
}
|
||||
case Phase::WAIT: {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Stock::dext(const Time & /* t */, const Time & /* e */, const Bag &bag) {
|
||||
std::for_each(bag.begin(), bag.end(), [](const ExternalEvent & /* event */) {
|
||||
// TODO
|
||||
void Stock::dext(const Time &t, const Time & /* e */, const Bag &bag) {
|
||||
std::for_each(bag.begin(), bag.end(), [t, this](const ExternalEvent &event) {
|
||||
if (event.on_port(inputs::IN)) {
|
||||
StockEntry entry;
|
||||
|
||||
event.data()(entry);
|
||||
if (_parameters._capacity == -1 or (int) _entries.size() < _parameters._capacity) {
|
||||
_entries.push_back({t, entry.po_id, entry.po_index, entry.product_id, entry.quantity});
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
} else if (event.port_index() >= inputs::IN_DEMAND and event.port_index() < inputs::IN_STOCK_AVAILABLE) {
|
||||
ProductDemand demand;
|
||||
|
||||
event.data()(demand);
|
||||
auto it = std::find_if(_entries.begin(), _entries.end(), [demand](const auto &e) {
|
||||
return e._po_id == demand.po_id and e._po_index == demand.po_index and e._product_id == demand.product_id
|
||||
and e._quantity >= demand.quantity;
|
||||
});
|
||||
|
||||
if (it != _entries.end()) {
|
||||
if (it->_quantity == demand.quantity) {
|
||||
_entries.erase(it);
|
||||
} else {
|
||||
it->_quantity -= demand.quantity;
|
||||
}
|
||||
_demands.push_back(std::make_pair(event.port_index() - inputs::IN_DEMAND, demand));
|
||||
_phase = Phase::SEND;
|
||||
}
|
||||
} else if (event.port_index() >= inputs::IN_STOCK_AVAILABLE) {
|
||||
unsigned int machine_id = event.port_index() - inputs::IN_STOCK_AVAILABLE;
|
||||
unsigned int po_id;
|
||||
|
||||
event.data()(po_id);
|
||||
_available_demands.push_back(AvailableDemand{machine_id, po_id, false});
|
||||
if (_parameters._capacity == -1 or (int) _entries.size() < _parameters._capacity) {
|
||||
auto it = std::find_if(_waiting_machine_ids.begin(), _waiting_machine_ids.end(),
|
||||
[machine_id, po_id](const auto &e) {
|
||||
return machine_id == e.first and po_id == e.second;
|
||||
});
|
||||
|
||||
if (it != _waiting_machine_ids.end()) {
|
||||
_waiting_machine_ids.erase(it);
|
||||
}
|
||||
_available_demands.back()._available = true;
|
||||
_phase = Phase::SEND_AVAILABLE;
|
||||
} else {
|
||||
_waiting_machine_ids.push_back(std::make_pair(machine_id, po_id));
|
||||
_phase = Phase::SEND_AVAILABLE;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Stock::start(const Time & /* t */) {
|
||||
// TODO
|
||||
_phase = Phase::WAIT;
|
||||
}
|
||||
|
||||
Time Stock::ta(const Time & /* t */) const {
|
||||
// TODO
|
||||
switch (_phase) {
|
||||
case Phase::WAIT:
|
||||
return artis::common::DoubleTime::infinity;
|
||||
case Phase::SEND:
|
||||
case Phase::SEND_AVAILABLE:
|
||||
return 0;
|
||||
}
|
||||
return artis::common::DoubleTime::infinity;
|
||||
}
|
||||
|
||||
Bag Stock::lambda(const Time & /* t */) const {
|
||||
Bag bag;
|
||||
|
||||
// TODO
|
||||
if (_phase == Phase::SEND) {
|
||||
for (const auto &e: _waiting_machine_ids) {
|
||||
bag.push_back(ExternalEvent(outputs::OUT_STOCK_AVAILABLE + e.first,
|
||||
StockAvailableResponse(e.second, StockAvailableResponse::NEW_AVAILABLE)));
|
||||
}
|
||||
for (const auto &e: _demands) {
|
||||
bag.push_back(ExternalEvent(outputs::OUT + e.first, ProductResponse(e.second.product_id, e.second.po_id)));
|
||||
}
|
||||
} else if (_phase == Phase::SEND_AVAILABLE) {
|
||||
for (const auto &demand: _available_demands) {
|
||||
bag.push_back(ExternalEvent(outputs::OUT_STOCK_AVAILABLE + demand._machine_id,
|
||||
StockAvailableResponse(demand._po_id,
|
||||
demand._available ? StockAvailableResponse::AVAILABLE
|
||||
: StockAvailableResponse::NOT_AVAILABLE)));
|
||||
}
|
||||
}
|
||||
return bag;
|
||||
}
|
||||
|
||||
artis::common::event::Value Stock::observe(const Time & /* t */, unsigned int /* index */) const {
|
||||
artis::common::event::Value Stock::observe(const Time & /* t */, unsigned int index) const {
|
||||
switch (index) {
|
||||
case vars::ENTRY_NUMBER:
|
||||
return (unsigned int) _entries.size();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
140
src/Stock.hpp
140
src/Stock.hpp
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file Stock.hpp
|
||||
* @file IntermediateStock.hpp
|
||||
* @author The ARTIS Development Team
|
||||
* See the AUTHORS or Authors.txt file
|
||||
*/
|
||||
@@ -32,32 +32,120 @@
|
||||
|
||||
namespace artis::factory {
|
||||
|
||||
struct StockEntry {
|
||||
unsigned int po_id;
|
||||
unsigned int po_index;
|
||||
unsigned int product_id;
|
||||
unsigned int quantity;
|
||||
|
||||
StockEntry(unsigned int po_id = 0, unsigned int po_index = 0, unsigned int product_id = 0, unsigned int quantity = 0)
|
||||
: po_id(po_id), po_index(po_index), product_id(product_id), quantity(quantity) {}
|
||||
|
||||
bool operator==(const StockEntry &other) const {
|
||||
return po_id == other.po_id and po_index == other.po_index and product_id == other.product_id and
|
||||
quantity == other.quantity;
|
||||
}
|
||||
|
||||
std::string to_string() const {
|
||||
return "StockEntry < " + std::to_string(po_id) + " | " + std::to_string(po_index) + " | " +
|
||||
std::to_string(product_id) + " | " + std::to_string(quantity) + " >";
|
||||
}
|
||||
};
|
||||
|
||||
struct ProductDemand {
|
||||
unsigned int po_id;
|
||||
unsigned int po_index;
|
||||
unsigned int product_id;
|
||||
unsigned int quantity;
|
||||
|
||||
ProductDemand(unsigned int po_id = 0, unsigned int po_index = 0, unsigned int product_id = 0,
|
||||
unsigned int quantity = 0)
|
||||
: po_id(po_id), po_index(po_index), product_id(product_id), quantity(quantity) {}
|
||||
|
||||
bool operator==(const ProductDemand &other) const {
|
||||
return po_id == other.po_id and po_index == other.po_index and product_id == other.product_id and
|
||||
quantity == other.quantity;
|
||||
}
|
||||
|
||||
std::string to_string() const {
|
||||
return "ProductDemand < " + std::to_string(po_id) + " | " + std::to_string(po_index) + " | " +
|
||||
std::to_string(product_id) + " | " + std::to_string(quantity) + " >";
|
||||
}
|
||||
};
|
||||
|
||||
struct StockAvailableResponse {
|
||||
int po_id;
|
||||
|
||||
enum values {
|
||||
AVAILABLE, NOT_AVAILABLE, NEW_AVAILABLE
|
||||
} response;
|
||||
|
||||
StockAvailableResponse(unsigned int po_id = 0, values response = NOT_AVAILABLE)
|
||||
: po_id(po_id), response(response) {}
|
||||
|
||||
bool operator==(const StockAvailableResponse &other) const {
|
||||
return po_id == other.po_id and response == other.response;
|
||||
}
|
||||
|
||||
std::string to_string() const {
|
||||
return "StockAvailableResponse < " + std::to_string(po_id) + " | " +
|
||||
(response == AVAILABLE ? "AVAILABLE" : (response == NOT_AVAILABLE ? "NOT AVAILABLE" : "NEW AVAILABLE")) + " >";
|
||||
}
|
||||
};
|
||||
|
||||
struct ProductResponse {
|
||||
int product_id;
|
||||
int po_id;
|
||||
|
||||
ProductResponse(int product_id = -1, int po_id = -1) : product_id(product_id), po_id(po_id) {}
|
||||
|
||||
bool operator==(const ProductResponse &other) const {
|
||||
return product_id == other.product_id and po_id == other.po_id;
|
||||
}
|
||||
|
||||
std::string to_string() const {
|
||||
return "Response < " + std::to_string(product_id) + " | " + std::to_string(po_id) + " >";
|
||||
}
|
||||
};
|
||||
|
||||
struct StockParameters {
|
||||
std::vector<unsigned int> _in_machines;
|
||||
std::vector<unsigned int> _out_machines;
|
||||
int _capacity; // if -1 then infinity
|
||||
};
|
||||
|
||||
class Stock : public Dynamics<Stock, StockParameters> {
|
||||
public:
|
||||
struct inputs {
|
||||
enum values {
|
||||
IN
|
||||
IN, IN_DEMAND = 1000, IN_STOCK_AVAILABLE = 2000
|
||||
};
|
||||
};
|
||||
|
||||
struct outputs {
|
||||
enum values {
|
||||
OUT
|
||||
OUT = 1000, OUT_STOCK_AVAILABLE = 2000
|
||||
};
|
||||
};
|
||||
|
||||
struct vars {
|
||||
enum values {
|
||||
ENTRY_NUMBER
|
||||
};
|
||||
};
|
||||
|
||||
Stock(const std::string &name, const Context<Stock, StockParameters> &context)
|
||||
: Dynamics<Stock, StockParameters>(name, context) {
|
||||
: Dynamics<Stock, StockParameters>(name, context), _parameters(context.parameters()) {
|
||||
input_port({inputs::IN, "in"});
|
||||
output_port({outputs::OUT, "out"});
|
||||
for (const auto &m: _parameters._in_machines) {
|
||||
output_port({outputs::OUT + m, "out_" + std::to_string(m)});
|
||||
input_port({inputs::IN_DEMAND + m, "in_demand_" + std::to_string(m)});
|
||||
}
|
||||
for (const auto &m: _parameters._out_machines) {
|
||||
output_port({outputs::OUT_STOCK_AVAILABLE + m, "out_stock_available_" + std::to_string(m)});
|
||||
input_port({inputs::IN_STOCK_AVAILABLE + m, "in_stock_available_" + std::to_string(m)});
|
||||
}
|
||||
observables({{vars::ENTRY_NUMBER, "entry number"}});
|
||||
}
|
||||
|
||||
~Stock() override = default;
|
||||
@@ -75,7 +163,47 @@ public:
|
||||
artis::common::event::Value observe(const Time &t, unsigned int index) const override;
|
||||
|
||||
private:
|
||||
// TODO (state)
|
||||
struct Phase {
|
||||
enum values {
|
||||
WAIT,
|
||||
SEND,
|
||||
SEND_AVAILABLE
|
||||
};
|
||||
|
||||
static std::string to_string(const values &value) {
|
||||
switch (value) {
|
||||
case WAIT:
|
||||
return "WAIT";
|
||||
case SEND:
|
||||
return "SEND";
|
||||
case SEND_AVAILABLE:
|
||||
return "SEND AVAILABLE";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
struct Entry {
|
||||
Time _t;
|
||||
unsigned int _po_id;
|
||||
unsigned int _po_index;
|
||||
unsigned int _product_id;
|
||||
unsigned int _quantity;
|
||||
};
|
||||
|
||||
struct AvailableDemand {
|
||||
unsigned int _machine_id;
|
||||
unsigned int _po_id;
|
||||
bool _available;
|
||||
};
|
||||
|
||||
StockParameters _parameters;
|
||||
|
||||
Phase::values _phase;
|
||||
std::vector<Entry> _entries;
|
||||
std::vector<std::pair<unsigned int, ProductDemand>> _demands;
|
||||
std::vector<AvailableDemand> _available_demands;
|
||||
std::deque<std::pair<unsigned int, unsigned int>> _waiting_machine_ids; // pair(machine_id,po_id)
|
||||
};
|
||||
|
||||
} // namespace artis::factory
|
||||
|
||||
Reference in New Issue
Block a user