GT++ Multiblocks

Introduction
Around EV/IV tier, a player will suddenly have access to GT++ multiblocks. These multiblocks functionally act as a more efficient version of their single-block counterpart. As of GT:NH 2.0.4.6, there are the following multiblocks:


 * Industrial Centrifuge (125% faster, 90% eu/t, 6 operations per tier)
 * Industrial Material Press (500% faster, 100% eu/t, 4 operations per tier)
 * Industrial Electrolyzer (180% faster, 90% eu/t, 2 operations per tier)
 * Industrial Mixing Machine (250% faster, 100% eu/t, 8 operations per tier)
 * Industrial Sifter (400% faster, 75% eu/t, 4 operations per tier)
 * Industrial Thermal Centrifuge (150% faster, 80% eu/t, 8 operations per tier)
 * Industrial Ore Washing Plant (400% faster, 100% eu/t, 4 operations per tier)
 * Industrial Extrusion Machine (250% faster, 100% eu/t, 4 operations per tier)
 * Industrial Cutting Factory (200% faster, 75% eu/t, 4 operations per tier)
 * Large Processing Factory (250% faster, 80% eu/t, 2 operations per tier)
 * Maceration Stack Controller (60% faster, 100% eu/t, 8 operations per tier)
 * Wire Factory Controller (200% faster, 75% eu/t, 4 operations per tier)
 * Amazon Warehousing Depot (???% faster, 75% eu/t, 5 operations per tier)
 * Cryogenic Freezer (100% faster, 100% eu/t, 4 operations at all tiers)
 * Advanced EBF (120% faster, 100% eu/t, 4 operations at all tiers)
 * Advanced Implosion Compressor
 * Zhuhai Fishing Port
 * Large Scale Auto-Assembler (200% faster, 100% eu/t, 2 operations per tier; this multi will work with a GT++ version newer than 1.7.02.02-fresh)

Note that this is not a complete list of GT++ multiblocks. This is a list of those multiblocks that exist to be a better version of either their singleblock counterpart, or their normal Gregtrech multiblock counterpart.

Many GT++ multiblocks also create pollution, usually stated on the controller block.

How to Build
Every multiblock has their own strict set of construction rules described in the controller block. Some key things to note are:


 * A large ore washer requires water in its input hatch (this will physically fill the ore washer with water).
 * Some multiblocks require a very specific location for their maintenance hatches.
 * Most GT++ multiblocks need muffler hatches now
 * Some multiblocks have multiple modes, that replace different GT machines. You can see this in the NEI description under Machine Type. They can be cycled by using a screwdriver on the controller. In case of the Large Processing Factory you also need a numbered circuits in the input busses to select the mode for that specific bus.

Multiblock Calculations
The aforementioned list of GT++ multi's have their own speed bonus, eu discount, and number of parallel operations per Gregtech voltage tier. Here is an incredibly informal explanation of how exactly the multiblock logic works (from https://github.com/draknyte1/GTplusplus/wiki/Multiblock-Processing-Logic):

GT++ machines can have EU_DISCOUNT ("only uses x% of the eu/t normally required"), MAX_PARALLEL ([input tier] * [# parallel items per tier]) or simply a static value in the case of the ebf/vac/etc, and SPEED_BOOST ("x% faster than using single block") ex. a% faster = (1+a%/100)x speed increase. First, apply EU_DISCOUNT to the recipe's EU/t value. Call this value x. Second, calculate xy, respecting these two conditions: -y is MAX_PARALLEL -x is Recipe_Voltage post EU discount As this value xy can exceed the input voltage, you need a way to calculate the actual y that the multi will use. We will call this y(real). An easy way to do this is to use a function such as rounddown(min(y, InputTierVoltage/x)). As the multis will parallelelize before overclocking, and seemingly not reduce parallels to account for another overclock for Max speed, it's safe to simply use this function. The min selects either the max parallels that type of multi can do at that tier, or if it doesn't have the power it will choose the option that fits within your input tier voltage. The rounddown will ensure that you aren't calculating with partial parallels, as they need to be integers. It's important to distinguish between input voltage, and input voltage tier. A multi will overclock and do parallels based on the tier of multi, but not the amount it can pull. Multi tier is calculated similarly to normal GT. Assume each hatch can input 1A, and multiply hatch# by inputVoltage. 1 hatch runs at Hatch_Tier, 2-4 gives Hatch_Tier+1, 4-16 gives Hatch_Tier+2, etc With the running cost now calculated with xy(real), let's call this TOTAL_EU_PER_TICK. Third, apply SPEED_BOOST to your recipe's time. In this code, if something says "x% faster", we mean multiply the recipe time by 100/(x+100). This way, all speed bonuses will be phrased as fractions of run time, and can be multiplied by a recipe time to give the time post speed bonus. Assuming a new recipe EU/t value of TOTAL_EU_PER_TICK, calculate the overclocks possible at your multi tier. This can be calculated in many ways, buy a simple function to describe it would be rounddown(ln(MultiTierVoltage/TOTAL_EU_PER_TICK)/ln(4)). This gives the amount of overclocks that can be preformed given the tier of your multi, and the EU/t of your recipe, post EU discount and post parallel recipes. If we call this overclock factor Ok, call the time of the recipe in ticks T, call the speed bonus S, and call parallels (defined by y(real) above) P, we can figure out the speed of the recipe easily with the equation T*S/(P*2^(Ok)). The resulting EU/t and time taken are what is reported by a scanner. Recipes can't exceed speeds of 1 tick, so we can somewhat edit our equation above to account for this. Max(T*S/(2^(Ok)), 1)*P. Isolating the individual processes, and capping them at 1 tick, ensures you won't calculate a recipe below what it can be. Last step is to ensure that you aren't accounting for individual recipes running at fractions of ticks, by implementing a rounding function into the left side of the max function. Max(Roundup(T*s/(2^(Ok))), 1)*P. This does assume recipes will round up in ticks, which should probably be checked, but seems to be the standard GT uses. We can combine all of these equations into one, but it's sometimes easier to calculate the individual steps instead, as seeing parallels is useful for knowing how much to input, and seeing eu/t is useful for knowing how much power to allocate to a multi.

Here's an example:

A Large Thermal Centrifuge has: 80% eu discount, 8 items per tier, and 150% faster.

You are doing a recipe that is 48 EU/t and 25 seconds long, at UV tier.

So we have MAX_PARALLEL = 64, EU_DISCOUNT = 0.8, SPEED_BOOST = 0.4 x = 38.4 eu/t y = MAX_PARALLEL in our case, so x * y = 2457.6 eu/t NEW_RECIPE_TIME = 25 * 0.4 = 10 seconds, TOTAL_EU_PER_TICK = 2457.6 eu/t Now, we GT overclock from these base numbers as many times as possible: 9830.4 eu/t, 5 seconds, LuV tier 39321.6 eu/t, 2.5 seconds, ZPM tier 157286.4 eu/t, 1.25 seconds, UV tier

So the large thermal centrifuge should do 64 operations every 1.25 seconds at 157286.4 EU/t at UV-tier

Comparison to a Processing Array
When comparing to a processing array, the most important thing to take away from the GT++ multiblock algorithm is that a recipe time cannot be reduced below 1 second. This means that when looking at a graph of Operations per second vs Gregtech Tier, a GT++ multiblock will inevitably flatline. On the other hand, a Gregtech Processing Array has no such restriction and can theoretically work even faster than a GT++ multiblock. However, this only really happens when a player is at or above ZPM tier (it's actually difficult to pinpoint where exactly this breakoff point is due to the variability of recipe times and eu costs, as well as the different speed bonuses, eu discounts, and parallel operations that differs from multiblock to multiblock).

For example, let's compare a maceration stack to a PA full of pulverizers. A standard ore pulverization recipe is 2 eu/t at 20 seconds per operation. A UV-tier maceration stack will get GT++ boosted to have a recipe cost of 128 eu/t and base time of 12.5 seconds. This means at UV-tier, at best, it will GT overclock to 64 ores per second. This is because the recipe time cannot be reduced below 1 second. Note that if the 1 second recipe time limit were not in place, the UV maceration stack would be doing 64 operations every 0.1953125 seconds, which would be equivalent to 327.68 ores per second.

A ZPM-tier PA can hold 64 LuV-tier pulverizers. This is because the eu cost of pulverizing ores is 2 eu/t. This means that it can do 64 ores every 0.625 seconds, or 102.4 ores per second.

The result is that a ZPM-tier PA can give a faster operation rate than a UV-tier maceration stack. Similar results will inevitably happen to all other GT++ multiblock vs PA comparisons.

Around the time a player unlocks the GT++ multiblocks, it is in his or her favor to build one of these multiblocks because of their spike in efficiency and speed compared to PA's around the IV/LuV tiers. Once a player hits ZPM or UV, however, it might be better to recalculate their desired operations per second because it might be more space and power efficient to switch over to a PA.

How to Get More Performance
Just like a PA can be optimized to use all of its input voltage (via higher tier machines), so can a GT++ multiblock.

Here's an example:

Ore processing is 2 eu/t at 20s.

The maceration stack is 60% faster, no eu discount, 8 operations per tier.

Let's say we have an HV maceration stack. This means it will do 24 operations simulaneously with a base recipe of: 48 eu/t at 12.5s, mv tier 192 eu/t at 6.25, hv tier

So it does 24 operations every 6.25s or 3.84 ores/s.

You'll notice it only eats 192 eu/t, far from the given input of 512 eu/t. We can actually make it eat more voltage at HV tier by doing the following:

Instead of feeding the maceration stack 24 ores, feed it 16 ores. This will make it so the base recipe is now:

32 eu/t at 12.5s, lv tier 128 eu/t at 6.25s, mv tier 512 eu/t at 3.125s, hv tier

So it does 16 operations every 3.125s or 5.12 ores/s.

If you noticed, I forced the base recipe to be 1 tier lower than usual by lowering the amount of items I fed it. This forced an additional overclock, making it faster than the "default" HV rate.

This is actually possible to do right now. By rate limiting the amount of input your GT++ machines take (via something like SFM), the GT++ multi can make the most out of your amp.

This is based off the idea that: if the number of parallel operations at your current tier is not DOUBLE the previous tier's number of parallel operations, then it's better to force a GT overclock (via underfeeding) from the previous tier rather than use the increased number of parallel operations at your current tier (since, in general for all gt++ machines, the number of parallel operations per tier increases linearly not exponentially, so you'll run into this case quite often for almost all the machines). However, some when tiered up will not be able to benefit from this action. If you're using 60% of an amp at full parallels, dropping to an overclockable amount will put you at a slower speed.

The general idea is if you're using <50% of an amp this can be useful. This is only part of it, but is because of what overclocking does vs what it needs. To overclock you'll need to drop down to <25% of an amp worth of parallels, which will net you a 2x bonus speed to those parallels. However if you're loosing more than 2x of your parallels, this is detrimental.

There is one more value of importance here. With using 50% of an amp and an even parallel quantity as an example (64v, 256v, 1024v, etc, it doesn't really matter), you would need to loose exactly half your parallels. This only gives you a 2x boost however, so you're simply back at the speed you started with, but using 2x the energy. This brings us to the final important constraint. You will need to have 1 more than half the parallels you had to start with. If the initial parallel count is odd, you will need to have the integer above half your initial count. This ensures that it will have any impact.

While it's a little ugly, this expression will provide a decent explanation of how it would work. You would want to overclock when

Rounddown(parallelCount/2)+1 <= .25A

Depending how you calculate the rest you could do it differently but that's the basic idea of what ensures this success. I find separating tier of parallels to be useful, and increase it by 1 if this check passes.