News:

Simutrans.com Portal
Our Simutrans site. You can find everything about Simutrans from here.

[11.35] Industry demand and max in-transit

Started by Octavius, August 24, 2014, 12:21:24 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Octavius

There have been various discussions about industry demand and maximum goods in transit. Right now, the idea is
Quote from: jamespetts on May 12, 2014, 09:31:03 AMNow, the two numbers are added together and the maximum in-transit percentage is doubled: if the number of goods in transit and in the factory's input store combined exceed 2x the maximum in-transit percentage, demand will stop.
I think this should work reasonably well, but I (and others) still see many industries only producing at about 50%, even when their raw materials are available and can be transported to the factory to make it run at 100%.

So I had a look at the source code and think I found a small bug. The source code (version 11.35, in simfab.cc) statesreturn max_intransit_percentages.get(typ->get_catg()) == 0 ? (i.menge < i.max) : ((i.transit + (i.menge >> fabrik_t::precision_bits)) * 200) < ((i.max >> fabrik_t::precision_bits) * (sint32)max_intransit_percentages.get(typ->get_catg()));If I read this correctly, it puts the factor 2 on the left side of the inequality instead of the right side, so that no more goods are sent in transit when the current in-transit reaches half the max in-transit, or even less when the input buffer is not empty – but it is always nearly empty, as not enough is delivered. This explains why industries work at 50%. The correct line would bereturn max_intransit_percentages.get(typ->get_catg()) == 0 ? (i.menge < i.max) : ((i.transit + (i.menge >> fabrik_t::precision_bits)) * 50) < ((i.max >> fabrik_t::precision_bits) * (sint32)max_intransit_percentages.get(typ->get_catg()));

One very good thing about the way it is supposed to work is that it has negative feedback, by adding the contents of the input buffer and the in-transit together and comparing that to the max in-transit. If the capacity of the line is (temporarily) too low, goods will pile up at the pickup station. This increases wait times, which increases maximum in-transit, which increases the pile at the pickup station until it gets overcrowded. When the capacity of the line is restored, the wait time is reduced, but as long as the pickup stations remains overcrowded, the maximum in-transit will be high enough to keep the pickup station overcrowded. With the negative feedback in the form of comparing the maximum in-transit to the stock and in-transit combined, the in-transit will be reduced when the stock increases again, solving overcrowding at the pickup station.

Furthermore, this negative feedback prevents episodic production at the producing industry, which would otherwise produce one batch right after one was delivered to the consuming industry. This episodic production may destabilise the system. So that's why every working solution must have some kind of negative feedback.

The intended formula tries to keep the in-transit on average equal to what should be in transit to keep the production running (i.e., maximum consumption rate times lead time) and tries to do so with the stock on average equal to the in-transit. This means that consumers at the end of long and slow supply lines will keep more stock.

Unfortunately, the size of the input buffer of the consuming industry is ignored:
100 * max_intransit = input_capacity * max_intransit_percentage
= input_capacity * ratio * base_max_intransit_percentage / 1000
= input_capacity * lead_time * 1000 / time_to_consume * base_max_intransit_percentage / 1000
= input_capacity * lead_time * 1000 / (input_capacity / input_consumed_per_month) * base_max_intransit_percentage / 1000
= lead_time * input_consumed_per_month * base_max_intransit_percentage

As a result, the formula gives rise to something that we probably don't want. Players can always use the convoy with the lowest cost per ton, whatever its capacity is. If you use a convoy with a very large capacity running at a very low frequency, the wait time and therefore lead time gets very long and the in-transit and stock will increase accordingly. The greengrocers will be perfectly happy when they get just one huge shipment of fruit every three months (if longer, the waiting time may be forgotten).

So I did an experiment. I modified the aforementioned line of source code toreturn max_intransit_percentages.get(typ->get_catg()) == 0 ? (i.menge < i.max) : ((i.transit + (i.menge >> fabrik_t::precision_bits) - (i.max >> (fabrik_t::precision_bits + 1))) * 100) < ((i.max >> fabrik_t::precision_bits) * (sint32)max_intransit_percentages.get(typ->get_catg()));This also has negative feedback as is adds the current stock to the in-transit, but then subtracts half the buffer size. This makes in-transit on average equal to max in-transit when the amount of goods in the buffer of the consuming industry is on average about 50% of the buffer size. In practice the buffer can be a little fuller on average, both because of the 110% base max in-transit percentage and because of fluctuations in demand, but it doesn't get too high once the startup fluctuations die out. Industries all work at 100%, even on the more complicated chains, unless they get supplied in batches larger than their buffer. With the buffer sometimes overfull, it has to compensate by keeping it empty at other times.

I think it worked quite satisfactory. Stable consumers, like coal power plants, kept their input buffer always between 40% and 80% full.

jamespetts

Thank you very much for looking into this and for your careful work: this is really very helpful. I am afraid that, because I am in the (rather slow) process of moving house, I do not have my normal computer set up and cannot readily make alterations to the code nor compile the code, so it may be a bit of a while before I can implement your suggested changes, but I am most grateful for them.

In the meantime, I should be interested in others' views on this, especially the second change.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

DrSuperGood

QuoteWhen the capacity of the line is restored, the wait time is reduced, but as long as the pickup stations remains overcrowded, the maximum in-transit will be high enough to keep the pickup station overcrowded.
Generally there is no pickup bottleneck. For example on the server I use the supplying ships to return with extra goods in a time-tabled manner assuring that there is sufficient capacity to ship from and to the industry. Since ships are cheap this is very easy to do. The only overcrowding are at transfers which it does not mater as no passengers are involved.

From my understanding it was meant to be that waiting times were ignored when computing the max in-transit and instead only the in-transit times (time between stops) was used. From my experience this is the case since a bottleneck to a coal merchant only results in at most 10,000 units pooling in the transfer hub and not an infinitely growing number as you suggest (as little as 10% was being shipped out so waiting time was growing by 90%). Maybe due to the first bug this did not used to happen.

jamespetts

I have now incorporated your fix and suggested amendment into the way-improvements branch. Apologies that it has taken me so long to review and incorporate this: I have, for reasons already given, been rather preoccupied with things other than Simutrans of late.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.