Skip to content
Maintankadin

Theck's MATLAB TPS analysis - WotLK/3.x

theckhd
Mon Feb 23, 2009 6:15 pm
That actually wouldn't be a bad idea. Even if it was just a simple text-based addon that could spit out your expected DPS to the chat frame every time you swapped gear.

Maybe if I find some time I could throw something simple together. Or someone could write it as a Tankadin2 module.
bfraz71
Mon Feb 23, 2009 7:13 pm
Nice job overall, but I think there's a small error with the plots.

Since you are plotting against Character Sheet Strength on the x-axis, you are actually plotting vs. 1.265*x (scaled by both Divine Strength and Blessing of Kings). The stats you are comparing (Hit, AP, etc.) are not affected by either of these modifiers, so you need to scale them appropriately in order to preserve the units. This will reduce the slope of the lines and push out your cross over points a little bit.

Edit: I think only the Divine Strength modifier is included when determining the x-axis.
Majiben
Mon Feb 23, 2009 7:14 pm
Would be interesting but could be problematic. It could either give you the numbers based upon your current stats on the the character sheet making it cover a raid situation only when in a raid. But if assumed raid buffs you would need to draw information directly from the gear and the players talent spec (though you could have the player enter that part manually in the addon).
theckhd
Mon Feb 23, 2009 8:33 pm
bfraz71 wrote:Nice job overall, but I think there's a small error with the plots.

Since you are plotting against Character Sheet Strength on the x-axis, you are actually plotting vs. 1.265*x (scaled by both Divine Strength and Blessing of Kings). The stats you are comparing (Hit, AP, etc.) are not affected by either of these modifiers, so you need to scale them appropriately in order to preserve the units. This will reduce the slope of the lines and push out your cross over points a little bit.

Er... I don't think so. The plots should be correct as is. There's no reason to scale any of the other stats. If your character sheet reads X strength, it reads X strength, not 1.265*X.

In other words, the DPS values are not directly calculated from the x-axis labels. Both the DPS values and the x-axis labels are calculated from an input array representing the total strength contributed by a player's gear. I.e.:

input:
Code: Select all
Gear_STR=linspace(500,2500);


Outputs:
Code: Select all
x=(Base_STR+Gear_STR).*DS;  <-- this is the x-axis labels
DPS= big ugly sequence of functions that depends on Gear_STR

The plots are actually generated by calculating the DPS twice - once with the base values, and once with the base values + 10 itemization points of the stat in question. I then subtract the two to get the net benefit that stat afforded you in each case.

Majiben wrote:Would be interesting but could be problematic. It could either give you the numbers based upon your current stats on the the character sheet making it cover a raid situation only when in a raid. But if assumed raid buffs you would need to draw information directly from the gear and the players talent spec (though you could have the player enter that part manually in the addon).

We can pull off most of the relevant stats with:
GetCombatRating()
UnitStat()
UnitAttackSpeed
UnitAttackPower
UnitDamage
It would take some testing to make sure the returns from all of these functions are exactly what we want, and the equations modified as appropriate.
theckhd
Tue Feb 24, 2009 8:32 pm
So, with the PTR going up this week, it got me to thinking about where this project is headed. I don't see too much point in fine-tuning the formulas for 3.0.8 at the moment - the results won't change too significantly, and the graphs have pretty much done their jobs.

I would like to update it for 3.1 because I can imagine it being a useful tool. The original intent was to be able to extend Jonesy's spreadsheet to be able to do things that a spreadsheet can't easily do, like recalculating the output thousands of times very quickly for different input parameters. Oh, and making pretty graphs, because pretty graphs are fun. But there's no reason that it would be limited to just gear - I can imagine analyzing all sorts of aspects of tanking, including rotations, specs, and so forth. It could be a reasonably powerful simulation tool.

If that's where this is headed, then it requires two basic things:
  1. One is a slight adjustment to the framework, to make it more modular. For example, ability_recalc.m inherently assumes 969 in its calculations - but it wouldn't need to. If instead it calculated each ability's damage, which it then passed to a "rotation" module that took those values and used them to figure out DPS/TPS, testing different rotations would be as simple as swapping out the rotation module for a different one.

    As an example flowchart, it would go something like this:
    • base stats
    • talents, glyphs, raid buffs, set bonuses, etc. - could be divided into sub-modules
    • ability damage calculations
    • rotation
    with a master function calling each of these as appropriate.

    This would make the program more versatile - for example, if we want to test out scaling for Ret, it's as simple as writing an ability module that includes the equations for the Ret abilities, and a rotation function that models FCFS, or whatever rotation / priority system they end up with after the changes are more finalized.

    Since this is mostly bookkeeping and shuffling code around from one file to another, I can handle this part easily enough.
  2. The other requirement is updated equations that accurately reflect the abilities post-3.1. A lot of things are changing with this patch, but luckily we have a lot of time to play with them on the PTR. Unfortunately, I don't have the free time to do all of it myself. If people would be willing to post updated formulas for abilities as we discover the changes, that would cut down the workload significantly. It doesn't have to be in the same code structure as the matlab program, just in a pseudocode format that I can read.


As it stands, I can imagine translating this into an addon eventually, though I'm not sure I'll have the time to do that part personally. All it would require for a proof-of-concept is to be able to grab the information provided in the "base stats" module though, once you have that everything else is just algebra crunching.
theckhd
Wed Feb 25, 2009 8:34 pm
So, I had some time today and I re-arranged the code into a more modular format. The basic idea is that you build a master simulation file that calls the different modules. For example, PallyTPS is now a master file that looks like this:
Code: Select all
clear       %clears workspace   
base_stats      %loads base stats into memory
talents         %loads talent spec modifiers
glyphs          %loads glyph modifiers
gear            %loads gear statistics
buffs_debuffs   %loads buff and debuff modifiers
stats_recalc    %calculates the net character statistics required for ability calcs
ability_recalc  %calculates the Damage of each ability
rotation_969    %calculates DPS and TPS based on a 969 rotation
[DPS TPS]       %spit the DPS and TPS out to workspace

Each of the lines in here is calling a module by the same name, which applies the appropriate modifiers as explained by the code comments.

The files can be found here for anyone that wants to peruse them. Here are the direct links for the modules:
base_stats
talents
glyphs
gear
buffs_debuffs
stats_recalc
ability_recalc
rotation_969

ability_recalc now calculates the total damage done by the ability so that it's more portable across different rotation modules (more on that in a minute). rotaiton_969 models the 969 rotation by taking the ability damage values and weighting them appropriately.

To demonstrate the usefulness of this rework (and to justify spending the last hour or two on it), let's take a look at something that people have been asking about a lot lately - How does Exorcism fit into our normal rotation? I've added Exorcism to the ability_recalc module as:

Code: Select all
Exorcism = (1087 + 0.15.*AP + 0.15.*SP).* ...    %inherent
    (100+(spell_crit + HotC).*Crit_Meta - boss_spell_resist - boss_scrit_supp)./100 * ... %hit, crit, HotC
    (OHWS.*Crusade.*SU.*Exor).* ...           %talents/glyphs
    (CoE.*SanctRet) ...                 %buffs/debuffs
    .*boss_resist_reduce;               %boss resist

I based this off of Consecrate and Holy Shield, neither of which can crit, but can resist. Since the "boss spell resistance" line in each of those spells mimics the format of the hit/crit lines for the melee skills, I assumed that format but substituted spell_crit for melee_crit, boss_spell_resist for boss_miss, and boss_scrit_supp for boss_mcrit_supp (crit suppression).

Since I'm not sure if this is entirely correct, all of the calculations are preliminary, once I get confirmation that this is right (or someone corrects it) we'll have more confidence in the numbers the script puts out.
theckhd
Wed Feb 25, 2009 8:42 pm
Exorcism Rotation Testing
For the moment, let's assume a cookie-cutter 5/59/6 spec (so no ret dps talents outside of 1/2 Imp Judgment). For the first pass, we'll only use the glyphs for Judgment and SoV, but we'll add the Exorcism glyph in later for good measure.

To test this, we'll have to write a new rotation module to model weaving Exorcism into the 969. That file is rotation_969_with_Exor. All of what I'm about to write is summarized in the comments of that file, but I'll repeat it here so you don't need to dig through the files if you don't want to.

There are 3 obvious ways to weave Exorcism into the 969. The first is to replace every other Consecration with Exorcism, which reduces Consecration's contribution to your sustained DPS by half, but adds one Exorcism every 18 seconds. This is modeled in the program as:
Code: Select all
DPS1=((1-player_avoid)./swing_timer).*Holy_Shield + ...  %Holy Shield
    Shield_of_Righteousness./6 + ...    %ShoR every 6 seconds
    Judgement_of_Vengeance./9 + ...     %Judgment every 9 seconds
    Vengeance_DOT./15 +  ...            %Vengeance DOT - total damage for a 5-stack done over 15 seconds
    Hammer_of_the_Righteous./6 + ...    %Hammer every 6 seconds
    Consecrate./18 + ...                %Consecrate every 18 seconds
    Exorcism./18 + ...                  %Exorcism every 18 seconds
    Melee_Swing_DPS;                    %DPS done by melee swings

(Side note, why did it take me until just now to realize I misspelled Judgment in the MATLAB code. Oops. How embarrassing)

The next obvious choice is to replace every other Judgment with Exorcism. Again, this is done fairly trivially in the code:
Code: Select all
DPS2=((1-player_avoid)./swing_timer).*Holy_Shield + ...  %Holy Shield
    Shield_of_Righteousness./6 + ...    %ShoR every 6 seconds
    Judgement_of_Vengeance./18 + ...     %Judgment every 9 seconds
    Vengeance_DOT./15 +  ...            %Vengeance DOT - total damage for a 5-stack done over 15 seconds
    Hammer_of_the_Righteous./6 + ...    %Hammer every 6 seconds
    Consecrate./9 + ...                %Consecrate every 18 seconds
    Exorcism./18 + ...                  %Exorcism every 18 seconds
    Melee_Swing_DPS;                    %DPS done by melee swings


The third way is to use Exorcism on cooldown in a 9 slot. It will always fall in a 9-slot if used this way in a 9-slot the first time, due to the 15 second cooldown. Unfortunately, this complicates the rotation quite a bit. From the code:
Code: Select all
% 0.0 - (9) Holy Shield #1
% 1.5 - (6) Hammer of the Righteous #1
% 3.0 -  (9) Exorcism #1 - next at 18
% 4.5 -  (6) Shield of Righteousness #1
% 6.0 -  (9) Judgment #1
% 7.5 -  (6) HotR #2
% 9.0 - (9) Consecration #1     Holy shield drops off at 10.0 (2s gap)
%10.5 - (6) ShoR #2
%12.0 - (9) Holy Shield #2
%13.5 - (6) HotR #3
%15.0 - (9) Judgment #2
%16.5 - (6) ShoR #3
%18.0 - (9) Exorcism #2 - next at 33
%19.5 - (6) HotR #4
%21.0 - (9) Consecration #2      Holy shield drops off at 22.0 (2s gap)
%22.5 - (6) ShoR #4
%24.0 - (9) Holy Shield #3
%25.5 - (6) HotR #5
%27.0 - (9) Judgment #3
%28.5 - (6) ShoR #5
%30.0 - (9) Consecration #3
%31.5 - (6) HotR #6
%33.0 - (9) Exorcism #3 - next at 48,  Holy shield drops off at 34.0 (2s gap)
%34.5 - (6) ShoR #6
%36.0 - (9) Holy Shield #4
%37.5 - (6) HotR #7
%39.0 - (9) Judgment #4
%40.5 - (6) ShoR #7
%42.0 - (9) Consecration #4
%43.5 - (6) HotR #8
%45.0 - (9) Holy Shield  - refreshed before it expires
%46.5 - (6) ShoR
%48.0 - (9) Exorcism  - next at 63

At this point the pattern emerges (though you might have guessed it ahead of time). At 45.0 we have Holy Shield followed by Exorcism on the 9's, which is how we started the rotation. The 6's are flipped though, we have a ShoR there. However, if we continue this pattern for another 45 seconds (45-90), we'll end up where we started, since the 6's will flip again.

What does this mean? Well, the 9's work on a 45-second cycle that's the same for 0-45 as 45-90. In this cycle, we get off:
  • 3 Exorcisms - DPS=Exorcism*3/45 = Exorcism/15, as expected if we're using it on cooldown
  • 4 Judgments - DPS=Judgment*4/45
  • 4 Consecrations - DPS=Consecration*4/45
  • 4 Holy Shields - this one is trickier, since we also have 3 gaps of 2 seconds each between applications. The net uptime is 39/45.
We're sill using ShoR and HotR on cooldown, so the DPS for those is the same as in the 969 (check: 15 of each in a 90s rotation, 15/90=1/6).

Thus, the DPS calculation would be
Code: Select all
DPS3=((1-player_avoid)./swing_timer).*Holy_Shield.*39./45 + ...  %Holy Shield
    Shield_of_Righteousness./6 + ...    %ShoR every 6 seconds
    Judgement_of_Vengeance.*4./45 + ...     %Judgment every 9 seconds
    Vengeance_DOT./15 +  ...            %Vengeance DOT - total damage for a 5-stack done over 15 seconds
    Hammer_of_the_Righteous./6 + ...    %Hammer every 6 seconds
    Consecrate.*4./45 + ...                %Consecrate every 18 seconds
    Exorcism./15 + ...                  %Exorcism every 18 seconds
    Melee_Swing_DPS;                    %DPS done by melee swings


I wrote a quick master file (Exorcism_rotation_testing) to calculate the DPS for all of these systems. With the Judgment and SoV glyphs (but not the Exorcism one), we have:

Regular 969 - DPS = 3162, TPS = 8181
Cons replace - DPS = 3113, TPS = 8046
Jud replace - DPS = 3149, TPS = 8145
Exor on c/d - DPS = 3170, TPS = 8202

If we include the Exorcism Glyph without removing Judgment, we get:
Regular 969 - DPS = 3162, TPS = 8181
Cons replace - DPS = 3140, TPS = 8120
Jud replace - DPS = 3176, TPS = 8219
Exor on c/d - DPS = 3202, TPS = 8291

Finally, if we drop the Judgment glyph, but keep SoV and Exorcism, we have:
Regular 969 - DPS = 3135, TPS = 8107
Cons replace - DPS = 3113, TPS = 8046
Jud replace - DPS = 3162, TPS = 8182
Exor on c/d - DPS = 3180, TPS = 8231

We see a few things here:
  • We actually lose DPS and TPS with the Consecration replacement rotation, regardless of glyph choices
  • Judgment replacement is worse if Exorcism is unglyphed, of no benefit if Judgment is unglyphed (as compared to regular 969 with Judgment glyph), but about a 14 DPS upgrade if we have both glyphs
  • Exorcism on cooldown is always better, and provides a 40 DPS improvement if we use both damage glyphs. Without the Judgment glyph, it's farther ahead of 969, but only about 20 DPS better than a regular 969 with the Judgment glyph


I'm going to quickly whip up some stats for a Holy Shield replacement rotation, and maybe for a 6's substitution rotation, just to see how those compare
Majiben
Wed Feb 25, 2009 8:46 pm
Test the consecrate replacement scenario when the consecrate glyph is used. +25% consecrate damage might change things.
Sabindeus
Wed Feb 25, 2009 9:05 pm
Also, how about Undead/Demon situations (Exorcism always crits)?
Sabindeus
Wed Feb 25, 2009 9:06 pm
btw Theck just wanted to say this is pro work, good job. :)