Changeset - r21443:e0525f7288a8
[Not reviewed]
master
0 8 0
fonsinchen - 11 years ago 2014-05-01 14:50:52
fonsinchen@openttd.org
(svn r26549) -Change: better estimation for link capacities during full load
8 files changed with 98 insertions and 74 deletions:
0 comments (0 inline, 0 general)
src/economy.cpp
Show inline comments
 
@@ -1718,13 +1718,13 @@ static void LoadUnloadVehicle(Vehicle *f
 

	
 
			/* Refresh next hop stats if we're full loading to make the links
 
			 * known to the distribution algorithm and allow cargo to be sent
 
			 * along them. Otherwise the vehicle could wait for cargo
 
			 * indefinitely if it hasn't visited the other links yet, or if the
 
			 * links die while it's loading. */
 
			if (!finished_loading) LinkRefresher::Run(front);
 
			if (!finished_loading) LinkRefresher::Run(front, true, true);
 
		}
 

	
 
		SB(front->vehicle_flags, VF_LOADING_FINISHED, 1, finished_loading);
 
	}
 

	
 
	/* Calculate the loading indicator fill percent and display
src/linkgraph/linkgraph.cpp
Show inline comments
 
@@ -194,53 +194,47 @@ NodeID LinkGraph::AddNode(const Station 
 
		this->edges[i][new_node].Init(distance);
 
	}
 
	return new_node;
 
}
 

	
 
/**
 
 * Fill an edge with values from a link. If usage < capacity set the usage,
 
 * otherwise set the restricted or unrestricted update timestamp.
 
 * Fill an edge with values from a link. Set the restricted or unrestricted
 
 * update timestamp according to the given update mode.
 
 * @param to Destination node of the link.
 
 * @param capacity Capacity of the link.
 
 * @param usage Usage to be added or REFRESH_UNRESTRICTED or REFRESH_RESTRICTED.
 
 * @param usage Usage to be added.
 
 * @param mode Update mode to be used.
 
 */
 
void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage)
 
void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode)
 
{
 
	assert(this->index != to);
 
	BaseEdge &edge = this->edges[to];
 
	BaseEdge &first = this->edges[this->index];
 
	edge.capacity = capacity;
 
	edge.usage = usage;
 
	edge.next_edge = first.next_edge;
 
	first.next_edge = to;
 
	switch (usage) {
 
		case REFRESH_UNRESTRICTED:
 
			edge.last_unrestricted_update = _date;
 
			break;
 
		case REFRESH_RESTRICTED:
 
			edge.last_restricted_update = _date;
 
			break;
 
		default:
 
			edge.usage = usage;
 
			break;
 
	}
 
	if (mode & EUM_UNRESTRICTED)  edge.last_unrestricted_update = _date;
 
	if (mode & EUM_RESTRICTED) edge.last_restricted_update = _date;
 
}
 

	
 
/**
 
 * Creates an edge if none exists yet or updates an existing edge.
 
 * @param to Target node.
 
 * @param capacity Capacity of the link.
 
 * @param usage Usage to be added or REFRESH_UNRESTRICTED or REFRESH_RESTRICTED.
 
 * @param usage Usage to be added.
 
 * @param mode Update mode to be used.
 
 */
 
void LinkGraph::Node::UpdateEdge(NodeID to, uint capacity, uint usage)
 
void LinkGraph::Node::UpdateEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode)
 
{
 
	assert(capacity > 0);
 
	assert(usage <= capacity || usage == REFRESH_RESTRICTED || usage == REFRESH_UNRESTRICTED);
 
	assert(usage <= capacity);
 
	if (this->edges[to].capacity == 0) {
 
		this->AddEdge(to, capacity, usage);
 
		this->AddEdge(to, capacity, usage, mode);
 
	} else {
 
		(*this)[to].Update(capacity, usage);
 
		(*this)[to].Update(capacity, usage, mode);
 
	}
 
}
 

	
 
/**
 
 * Remove an outgoing edge from this node.
 
 * @param to ID of destination node.
 
@@ -267,40 +261,36 @@ void LinkGraph::Node::RemoveEdge(NodeID 
 
			next = this->edges[next].next_edge;
 
		}
 
	}
 
}
 

	
 
/**
 
 * Create a new edge or update an existing one. If usage is REFRESH_UNRESTRICTED
 
 * or REFRESH_RESTRICTED refresh the edge to have at least the given capacity
 
 * and also update the respective update timestamp, otherwise add the capacity.
 
 * Update an edge. If mode contains UM_REFRESH refresh the edge to have at
 
 * least the given capacity and usage, otherwise add the capacity and usage.
 
 * In any case set the respective update timestamp(s), according to the given
 
 * mode.
 
 * @param from Start node of the edge.
 
 * @param to End node of the edge.
 
 * @param capacity Capacity to be added/updated.
 
 * @param usage Usage to be added or REFRESH_UNRESTRICTED or REFRESH_RESTRICTED.
 
 * @param usage Usage to be added.
 
 * @param mode Update mode to be applied.
 
 */
 
void LinkGraph::Edge::Update(uint capacity, uint usage)
 
void LinkGraph::Edge::Update(uint capacity, uint usage, EdgeUpdateMode mode)
 
{
 
	assert(this->edge.capacity > 0);
 
	if (usage > capacity) {
 
		this->edge.capacity = max(this->edge.capacity, capacity);
 
		switch (usage) {
 
			case REFRESH_UNRESTRICTED:
 
				this->edge.last_unrestricted_update = _date;
 
				break;
 
			case REFRESH_RESTRICTED:
 
				this->edge.last_restricted_update = _date;
 
				break;
 
			default:
 
				NOT_REACHED();
 
				break;
 
		}
 
	} else {
 
	assert(capacity >= usage);
 

	
 
	if (mode & EUM_INCREASE) {
 
		this->edge.capacity += capacity;
 
		this->edge.usage += usage;
 
	} else if (mode & EUM_REFRESH) {
 
		this->edge.capacity = max(this->edge.capacity, capacity);
 
		this->edge.usage = max(this->edge.usage, usage);
 
	}
 
	if (mode & EUM_UNRESTRICTED) this->edge.last_unrestricted_update = _date;
 
	if (mode & EUM_RESTRICTED) this->edge.last_restricted_update = _date;
 
}
 

	
 
/**
 
 * Resize the component and fill it with empty nodes and edges. Used when
 
 * loading from save games. The component is expected to be empty before.
 
 * @param size New size of the component.
src/linkgraph/linkgraph.h
Show inline comments
 
@@ -38,28 +38,12 @@ extern LinkGraphPool _link_graph_pool;
 
 * might change between the creation and join time so we can't rely on them.
 
 */
 
class LinkGraph : public LinkGraphPool::PoolItem<&_link_graph_pool> {
 
public:
 

	
 
	/**
 
	 * Special modes for updating links. 'Restricted' means that vehicles with
 
	 * 'no loading' orders are serving the link. If a link is only served by
 
	 * such vehicles it's 'fully restricted'. This means the link can be used
 
	 * by cargo arriving in such vehicles, but not by cargo generated or
 
	 * transferring at the source station of the link. In order to find out
 
	 * about this condition we keep two update timestamps in each link, one for
 
	 * the restricted and one for the unrestricted part of it. If either one
 
	 * times out while the other is still valid the link becomes fully
 
	 * restricted or fully unrestricted, respectively.
 
	 */
 
	enum UpdateMode {
 
		REFRESH_RESTRICTED = UINT_MAX - 1, ///< Refresh restricted link.
 
		REFRESH_UNRESTRICTED = UINT_MAX    ///< Refresh unrestricted link.
 
	};
 

	
 
	/**
 
	 * Node of the link graph. contains all relevant information from the associated
 
	 * station. It's copied so that the link graph job can work on its own data set
 
	 * in a separate thread.
 
	 */
 
	struct BaseNode {
 
		uint supply;             ///< Supply at the station.
 
@@ -310,13 +294,13 @@ public:
 
	public:
 
		/**
 
		 * Constructor
 
		 * @param edge Edge to be wrapped.
 
		 */
 
		Edge(BaseEdge &edge) : EdgeWrapper<BaseEdge>(edge) {}
 
		void Update(uint capacity, uint usage);
 
		void Update(uint capacity, uint usage, EdgeUpdateMode mode);
 
		void Restrict() { this->edge.last_unrestricted_update = INVALID_DATE; }
 
		void Release() { this->edge.last_restricted_update = INVALID_DATE; }
 
	};
 

	
 
	/**
 
	 * An iterator for const edges. Cannot be typedef'ed because of
 
@@ -434,14 +418,14 @@ public:
 
		 */
 
		void SetDemand(uint demand)
 
		{
 
			this->node.demand = demand;
 
		}
 

	
 
		void AddEdge(NodeID to, uint capacity, uint usage = 0);
 
		void UpdateEdge(NodeID to, uint capacity, uint usage = 0);
 
		void AddEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode);
 
		void UpdateEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode);
 
		void RemoveEdge(NodeID to);
 
	};
 

	
 
	typedef SmallVector<BaseNode, 16> NodeVector;
 
	typedef SmallMatrix<BaseEdge> EdgeMatrix;
 

	
src/linkgraph/linkgraph_type.h
Show inline comments
 
@@ -36,7 +36,29 @@ enum DistributionType {
 
/* It needs to be 8bits, because we save and load it as such
 
 * Define basic enum properties
 
 */
 
template <> struct EnumPropsT<DistributionType> : MakeEnumPropsT<DistributionType, byte, DT_BEGIN, DT_END, DT_NUM> {};
 
typedef TinyEnumT<DistributionType> DistributionTypeByte; // typedefing-enumification of DistributionType
 

	
 
/**
 
 * Special modes for updating links. 'Restricted' means that vehicles with
 
 * 'no loading' orders are serving the link. If a link is only served by
 
 * such vehicles it's 'fully restricted'. This means the link can be used
 
 * by cargo arriving in such vehicles, but not by cargo generated or
 
 * transferring at the source station of the link. In order to find out
 
 * about this condition we keep two update timestamps in each link, one for
 
 * the restricted and one for the unrestricted part of it. If either one
 
 * times out while the other is still valid the link becomes fully
 
 * restricted or fully unrestricted, respectively.
 
 * Refreshing a link makes just sure a minimum capacity is kept. Increasing
 
 * actually adds the given capacity.
 
 */
 
enum EdgeUpdateMode {
 
	EUM_INCREASE     = 1,      ///< Increase capacity.
 
	EUM_REFRESH      = 1 << 1, ///< Refresh capacity.
 
	EUM_RESTRICTED   = 1 << 2, ///< Use restricted link.
 
	EUM_UNRESTRICTED = 1 << 3, ///< Use unrestricted link.
 
};
 

	
 
DECLARE_ENUM_AS_BIT_SET(EdgeUpdateMode)
 

	
 
#endif /* LINKGRAPH_TYPE_H */
src/linkgraph/refresh.cpp
Show inline comments
 
@@ -20,24 +20,25 @@
 
#include "../safeguards.h"
 

	
 
/**
 
 * Refresh all links the given vehicle will visit.
 
 * @param v Vehicle to refresh links for.
 
 * @param allow_merge If the refresher is allowed to merge or extend link graphs.
 
 * @param is_full_loading If the vehicle is full loading.
 
 */
 
/* static */ void LinkRefresher::Run(Vehicle *v, bool allow_merge)
 
/* static */ void LinkRefresher::Run(Vehicle *v, bool allow_merge, bool is_full_loading)
 
{
 
	/* If there are no orders we can't predict anything.*/
 
	if (v->orders.list == NULL) return;
 

	
 
	/* Make sure the first order is a useful order. */
 
	const Order *first = v->orders.list->GetNextDecisionNode(v->GetOrder(v->cur_implicit_order_index), 0);
 
	if (first == NULL) return;
 

	
 
	HopSet seen_hops;
 
	LinkRefresher refresher(v, &seen_hops, allow_merge);
 
	LinkRefresher refresher(v, &seen_hops, allow_merge, is_full_loading);
 

	
 
	refresher.RefreshLinks(first, first, v->last_loading_station != INVALID_STATION ? 1 << HAS_CARGO : 0);
 
}
 

	
 
/**
 
 * Comparison operator to allow hops to be used in a std::set.
 
@@ -62,15 +63,17 @@ bool LinkRefresher::Hop::operator<(const
 
/**
 
 * Constructor for link refreshing algorithm.
 
 * @param vehicle Vehicle to refresh links for.
 
 * @param seen_hops Set of hops already seen. This is shared between this
 
 *                  refresher and all its children.
 
 * @param allow_merge If the refresher is allowed to merge or extend link graphs.
 
 * @param is_full_loading If the vehicle is full loading.
 
 */
 
LinkRefresher::LinkRefresher(Vehicle *vehicle, HopSet *seen_hops, bool allow_merge) :
 
		vehicle(vehicle), seen_hops(seen_hops), cargo(CT_INVALID), allow_merge(allow_merge)
 
LinkRefresher::LinkRefresher(Vehicle *vehicle, HopSet *seen_hops, bool allow_merge, bool is_full_loading) :
 
	vehicle(vehicle), seen_hops(seen_hops), cargo(CT_INVALID), allow_merge(allow_merge),
 
	is_full_loading(is_full_loading)
 
{
 
	/* Assemble list of capacities and set last loading stations to 0. */
 
	for (Vehicle *v = this->vehicle; v != NULL; v = v->Next()) {
 
		this->refit_capacities.push_back(RefitDesc(v->cargo_type, v->cargo_cap, v->refit_cap));
 
		if (v->refit_cap > 0) this->capacities[v->cargo_type] += v->refit_cap;
 
	}
 
@@ -202,16 +205,38 @@ void LinkRefresher::RefreshStats(const O
 
			/* If not allowed to merge link graphs, make sure the stations are
 
			 * already in the same link graph. */
 
			if (!this->allow_merge && st->goods[c].link_graph != Station::Get(next_station)->goods[c].link_graph) {
 
				continue;
 
			}
 

	
 
			/* A link is at least partly restricted if a
 
			 * vehicle can't load at its source. */
 
			IncreaseStats(st, c, next_station, i->second,
 
					(cur->GetLoadType() & OLFB_NO_LOAD) == 0 ? LinkGraph::REFRESH_UNRESTRICTED : LinkGraph::REFRESH_RESTRICTED);
 
			/* A link is at least partly restricted if a vehicle can't load at its source. */
 
			EdgeUpdateMode restricted_mode = (cur->GetLoadType() & OLFB_NO_LOAD) == 0 ?
 
						EUM_UNRESTRICTED : EUM_RESTRICTED;
 

	
 
			/* If the vehicle is currently full loading, increase the capacities at the station
 
			 * where it is loading by an estimate of what it would have transported if it wasn't
 
			 * loading. Don't do that if the vehicle has been waiting for longer than the entire
 
			 * order list is supposed to take, though. If that is the case the total duration is
 
			 * probably far off and we'd greatly overestimate the capacity by increasing.*/
 
			if (this->is_full_loading && this->vehicle->orders.list != NULL &&
 
					st->index == vehicle->last_station_visited &&
 
					this->vehicle->orders.list->GetTotalDuration() >
 
					(Ticks)this->vehicle->current_order_time) {
 
				uint effective_capacity = i->second * this->vehicle->load_unload_ticks;
 
				if (effective_capacity > (uint)this->vehicle->orders.list->GetTotalDuration()) {
 
					IncreaseStats(st, c, next_station, effective_capacity /
 
							this->vehicle->orders.list->GetTotalDuration(), 0,
 
							EUM_INCREASE | restricted_mode);
 
				} else if (RandomRange(this->vehicle->orders.list->GetTotalDuration()) < effective_capacity) {
 
					IncreaseStats(st, c, next_station, 1, 0, EUM_INCREASE | restricted_mode);
 
				} else {
 
					IncreaseStats(st, c, next_station, i->second, 0, EUM_REFRESH | restricted_mode);
 
				}
 
			} else {
 
				IncreaseStats(st, c, next_station, i->second, 0, EUM_REFRESH | restricted_mode);
 
			}
 
		}
 
	}
 
}
 

	
 
/**
 
 * Iterate over orders starting at \a cur and \a next and refresh links
src/linkgraph/refresh.h
Show inline comments
 
@@ -20,13 +20,13 @@
 

	
 
/**
 
 * Utility to refresh links a consist will visit.
 
 */
 
class LinkRefresher {
 
public:
 
	static void Run(Vehicle *v, bool allow_merge = true);
 
	static void Run(Vehicle *v, bool allow_merge = true, bool is_full_loading = false);
 

	
 
protected:
 
	/**
 
	 * Various flags about properties of the last examined link that might have
 
	 * an influence on the next one.
 
	 */
 
@@ -85,14 +85,15 @@ protected:
 
	Vehicle *vehicle;           ///< Vehicle for which the links should be refreshed.
 
	CapacitiesMap capacities;   ///< Current added capacities per cargo ID in the consist.
 
	RefitList refit_capacities; ///< Current state of capacity remaining from previous refits versus overall capacity per vehicle in the consist.
 
	HopSet *seen_hops;          ///< Hops already seen. If the same hop is seen twice we stop the algorithm. This is shared between all Refreshers of the same run.
 
	CargoID cargo;              ///< Cargo given in last refit order.
 
	bool allow_merge;           ///< If the refresher is allowed to merge or extend link graphs.
 
	bool is_full_loading;       ///< If the vehicle is full loading.
 

	
 
	LinkRefresher(Vehicle *v, HopSet *seen_hops, bool allow_merge);
 
	LinkRefresher(Vehicle *v, HopSet *seen_hops, bool allow_merge, bool is_full_loading);
 

	
 
	void HandleRefit(const Order *next);
 
	void ResetRefit();
 
	void RefreshStats(const Order *cur, const Order *next);
 
	const Order *PredictNextOrder(const Order *cur, const Order *next, uint8 flags, uint num_hops = 0);
 

	
src/station_cmd.cpp
Show inline comments
 
@@ -3502,15 +3502,16 @@ void DeleteStaleLinks(Station *from)
 
/**
 
 * Increase capacity for a link stat given by station cargo and next hop.
 
 * @param st Station to get the link stats from.
 
 * @param cargo Cargo to increase stat for.
 
 * @param next_station_id Station the consist will be travelling to next.
 
 * @param capacity Capacity to add to link stat.
 
 * @param usage Usage to add to link stat. If UINT_MAX refresh the link instead of increasing.
 
 * @param usage Usage to add to link stat.
 
 * @param mode Update mode to be applied.
 
 */
 
void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage)
 
void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, EdgeUpdateMode mode)
 
{
 
	GoodsEntry &ge1 = st->goods[cargo];
 
	Station *st2 = Station::Get(next_station_id);
 
	GoodsEntry &ge2 = st2->goods[cargo];
 
	LinkGraph *lg = NULL;
 
	if (ge1.link_graph == INVALID_LINK_GRAPH) {
 
@@ -3546,13 +3547,13 @@ void IncreaseStats(Station *st, CargoID 
 
				LinkGraphSchedule::Instance()->Unqueue(lg2);
 
				lg->Merge(lg2); // Updates GoodsEntries of lg2
 
			}
 
		}
 
	}
 
	if (lg != NULL) {
 
		(*lg)[ge1.node].UpdateEdge(ge2.node, capacity, usage);
 
		(*lg)[ge1.node].UpdateEdge(ge2.node, capacity, usage, mode);
 
	}
 
}
 

	
 
/**
 
 * Increase capacity for all link stats associated with vehicles in the given consist.
 
 * @param st Station to get the link stats from.
 
@@ -3567,13 +3568,13 @@ void IncreaseStats(Station *st, const Ve
 
			 * wagons have been auto-replaced and subsequently auto-
 
			 * refitted to a higher capacity. The cargo gets redistributed
 
			 * among the wagons in that case.
 
			 * As usage is not such an important figure anyway we just
 
			 * ignore the additional cargo then.*/
 
			IncreaseStats(st, v->cargo_type, next_station_id, v->refit_cap,
 
				min(v->refit_cap, v->cargo.StoredCount()));
 
				min(v->refit_cap, v->cargo.StoredCount()), EUM_INCREASE);
 
		}
 
	}
 
}
 

	
 
/* called for every station each tick */
 
static void StationHandleSmallTick(BaseStation *st)
src/station_func.h
Show inline comments
 
@@ -15,12 +15,13 @@
 
#include "sprite.h"
 
#include "rail_type.h"
 
#include "road_type.h"
 
#include "vehicle_type.h"
 
#include "economy_func.h"
 
#include "rail.h"
 
#include "linkgraph/linkgraph_type.h"
 

	
 
void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius);
 

	
 
void FindStationsAroundTiles(const TileArea &location, StationList *stations);
 

	
 
void ShowStationViewWindow(StationID station);
 
@@ -46,13 +47,13 @@ bool CanStationTileHaveWires(TileIndex t
 

	
 
void UpdateAirportsNoise();
 

	
 
bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrackOffset *overlay_offset);
 

	
 
void IncreaseStats(Station *st, const Vehicle *v, StationID next_station_id);
 
void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage);
 
void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, EdgeUpdateMode mode);
 
void RerouteCargo(Station *st, CargoID c, StationID avoid, StationID avoid2);
 

	
 
/**
 
 * Calculates the maintenance cost of a number of station tiles.
 
 * @param num Number of station tiles.
 
 * @return Total cost.
0 comments (0 inline, 0 general)