MMO News and theorycrafting for advanced MMO gamers. News and articles that relate to your gameplay. World of Warcraft, SWTOR, Guild Wars 2, Rift, TERA, Eve Online, Star Wars the Old Republic, Diablo3, The Secret World and all Western AAA MMOs

Your login from any MMO-Mechanics forum or site will work here.

Hello There, Guest! Register

Post Reply 
DPS Excel calculator for Sorcerer / Sage
01-08-2012, 04:42 AM
Post: #11
RE: DPS Excel calculator for SI Sorcerer
(01-08-2012 04:34 AM)Kor Wrote:  I modified my old Harnessed Darkness simulator to check on Conduction stacks, and it apparently is a very chaotic system. The program itself lets you specify a range of casting intervals, plus a step interval along that range (range must be evenly divisible by the step interval). It will output the results to a file for easy access.

I ran the simulation at 100000 iterations per step, from a cast interval of 1.5 seconds (spammed) to 9 seconds, and I ran that same simulation 5 times, averaging the results. Here are the results for average number of stacks at each interval:

Nice, this probably save me from writing my own simulation ;p

But can you post average values for lower frequencies than 9sec (for example once in 15, 20, 25 and 30sec)?

It would be good to have those few additional data points until 30sec - since after 30sec it is simple to calculate. Then I can plug those points into interpolation table I already use in excel - right now I just filled that with some guesstimated data.
Find all posts by this user
Quote this message in a reply
01-08-2012, 05:20 AM (This post was last modified: 01-08-2012 05:29 AM by Kaedis.)
Post: #12
RE: DPS Excel calculator for SI Sorcerer
30 is simple, it can never refresh the buff, so it has a 30% chance of 30 seconds of buff each duration, so 30% uptime at 1 stack, 0.3 stacks average.

here's 10-25 in 5 second steps:

Code:
Intv  Average     Iterations----------------------------------------------
10    0.653638    0.676758    0.841029    0.583018    0.924142    0.243242
15    0.698535    0.798290    0.698723    0.744937    0.616169    0.634558
20    0.654924    0.981560    0.402000    1.022820    0.298138    0.570102
25    0.401180    0.337051    0.332634    0.306882    0.579488    0.449847

Side note, and I probably should have included this in my original post. My sim uses a random cast system as well as a random proc chance. In other words, if you tell it to cast at an interval of 5 seconds, it doesn't cast every 5 seconds. Instead, every step (0.5 seconds default), it gives you a step/interval (in this case, 10%) chance of starting a cast at that time. This is to simulate the fact that LS doesn't get cast precisely at those intervals, and to simulate periods of higher or lower LS casting due to fight mechanics and such. The variability of the results of the simulation would probably be cut down significantly if I used a static casting interval instead, and I may go back and alter the program to do so and post the results with that if I have time in the next few hours.

Edit: actually, going to do that, since I believe my math on that was wrong anyway. My 1.5 interval set actually only has a 0.333% chance each step to cast, when it should have a 100% chance (since it skips the steps during the cast).

Even Angels must kill from time to time...
Find all posts by this user
Quote this message in a reply
01-08-2012, 09:11 AM
Post: #13
RE: DPS Excel calculator for SI Sorcerer
Here's the updated data with the rebuilt simulator (code below). Sim now casts every seconds, rather than randomly at a chance designed to meet that interval. Slightly less accurate representation of reality, significantly less chaotic and thus more reliable results:

Code:
Intv   Average     StDev       Iterations                
1.5    2.911478    0.027258    2.91919    2.87551    2.92025    2.94722    2.89522
3.0    2.599370    0.202097    2.81081    2.30539    2.76660    2.57559    2.53846
4.5    2.251296    0.368155    2.60544    1.74872    2.61722    2.20000    2.08510
6.0    1.808940    0.469897    2.36090    1.46014    2.19643    1.77082    1.25641
7.5    1.412733    0.609129    1.97436    1.91999    1.58461    0.55557    1.02913
9      1.283724    0.612461    1.79321    1.94203    1.33962    0.50505    0.83871
10     1.133451    0.203444    1.05140    1.01996    0.90512    1.38999    1.30078
15     0.648147    0.242290    0.45863    0.51774    0.55096    0.65000    1.06341
20     0.545223    0.245237    0.24324    0.75000    0.36384    0.55085    0.81818
25     0.466578    0.213076    0.21908    0.49130    0.37778    0.44444    0.80029
30     0.232993    0.166307    0.16667    0.37500    0.14286    0.04294    0.43750

Updated code:

Code:
// PROVIDED BY: Kor
// CONTACT E-MAIL: [redacted]
// FILE: conduction_simulator.cxx
// VERSION: 1.0.3.r
// PURPOSE: Simulate the SI Sorc talent Conduction for the MMO SW:TOR

// DIRECTIVES -----------------------------------------------------------------
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cmath>
#include <cassert>
#include <ctime>
using namespace std;
// ----------------------------------------------------------------------------

// GLOBAL CONSTANTS -----------------------------------------------------------
const size_t MINLENGTH = 180;    // Minimum iteration length in seconds
const size_t MAXLENGTH = 300;    // Maximum iteration length in seconds

const size_t MAXSTACKS = 3;        // Maximum stack size
const double CHANCE = 0.3;        // Chance of proc
const double DURATION = 30;        // Duration of proc
const double MIN = 1.5;
const double MAX = 30;
// ----------------------------------------------------------------------------

// MODELS ---------------------------------------------------------------------
// Holds all information for a single simulation iteration.  Also used for
// minimum, maximum, and average
struct iteration
{
    double duration;                // Duration in seconds of the iteration

    double stacks[MAXSTACKS + 1];    // Duration in seconds at each stack count
};
// ----------------------------------------------------------------------------

// FUNCTION PROTOTYPES --------------------------------------------------------
iteration sim(size_t duration, double interval);
// ----------------------------------------------------------------------------

// ============================================================================
int main()
{
    ofstream file;
    
    // Clear file before writing to it
    file.open ("conduction_sim_output.txt");
    file.close();
    
    file.open ("conduction_sim_output.txt", ios::out | ios::app);
    size_t numits;
    double minspread;
    double maxspread;
    double interval;
    size_t duration;
    double avg = 0;
    
    // Request number of iterations
    cout << "Number of iterations? ";
    cin >> numits;
    
    if(numits <= 0)
    {
        cout << "Can't have zero iterations!" << endl;
        exit(0);
    }
        
    // Request minspread
    cout << "Minimum spread in seconds? ";
    cin >> minspread;
    
    if(minspread < MIN)
    {
        cout << "Minimum spread too small!" << endl;
        exit(0);
    }
    
    // Request maxspread
    cout << "Maximum spread in seconds? ";
    cin >> maxspread;
    
    if(maxspread > MAX)
    {
        cout << "Max spread too large!" << endl;
        exit(0);
    }
    
    // Request maxspread
    cout << "Spread interval? ";
    cin >> interval;

    if(interval > 0 && (maxspread-minspread)/interval != floor((maxspread-minspread)/interval))
    {
        cout << "Interval not even divisor of spread range." << endl;
        exit(0);
    }
    
    size_t steps = int((maxspread-minspread)/interval + 1);
    
    iteration average[steps], min[steps], max[steps], its;
    
    // Repeat test as necessary for interval
    for(size_t j = 0; j < steps; ++j)
    {
        // Run simulation specified number of times
        for(size_t c = 0; c < numits; c++)
        {
            // Generate a random duration between the minimum and maximum (inclusive)
            duration = MINLENGTH + (rand()%(MAXLENGTH - MINLENGTH + 1));
            
            its = sim(duration, minspread + j*interval);
            
            if(!c)
            { // Initialize on first run
                min[j].duration = its.duration;
                max[j].duration = its.duration;
                average[j].duration = its.duration;

                for(size_t k = 0; k <= MAXSTACKS; ++k)
                {
                    min[j].stacks[k] = its.stacks[k];
                    max[j].stacks[k] = its.stacks[k];
                    average[j].stacks[k] = its.stacks[k];
                }
            }
            else
            { // Track Min, Max, and Average
                if(its.duration < min[j].duration)
                    min[j].duration = its.duration;
    
                if(its.duration > max[j].duration)
                    max[j].duration = its.duration;

                average[j].duration = ((average[j].duration * c) + its.duration)/(c + 1);

                for(size_t k = 0; k <= MAXSTACKS; ++k)
                {
                    if(its.stacks[k] < min[j].stacks[k])
                        min[j].stacks[k] = its.stacks[k];

                    if(its.stacks[k] < max[j].stacks[k])
                        max[j].stacks[k] = its.stacks[k];

                    average[j].stacks[k] = ((average[j].stacks[k] * c) + its.stacks[k])/(c + 1);
                }
            }
        }
    }
    

    // Output to file
    cout << "Simulation complete, check conduction_sim_output.txt for results" << endl;

    file << "Cast interval range: " << minspread << " - " << maxspread << "(stepsize " << interval << ")" << endl;
    file << "Iterations per interval: " << numits << endl;
    file << "Results format: MINIMUM | AVERAGE | MAXIMUM" << endl;
    for(size_t c = 0; c < steps; ++c)
    {
        file << "--------------------------------------" << endl;
        file << "Cast Interval:   " << minspread + interval*c << endl;
        file << "Duration:        " << min[c].duration << " | " << average[c].duration << " | " << max[c].duration << endl;

        avg = 0;
        for(size_t k = 0; k <= MAXSTACKS; ++k)
        {
            file << "Sec at " << k << " Stacks: "  << min[c].stacks[k] << " | " << average[c].stacks[k] << " | " << max[c].stacks[k] << endl;
            avg += average[c].stacks[k]*k;
        }
        file << "Average stacks: " << avg/average[c].duration << endl;
    }
    
    
    file.close();
    
    return 0;
}
// ============================================================================

// ----------------------------------------------------------------------------
iteration sim(size_t duration, double interval)
{
    iteration it;
    size_t stacks = 0;
    double stackdur = 0;
    
    it.duration = 0;
    for(size_t k = 0; k <= MAXSTACKS; ++k)
        it.stacks[k] = 0;
    
    // Seed random
    srand(time(NULL));
    
    while(it.duration < duration)
    {
        if((rand()%32768)/32767.0 < CHANCE)
        {
            stackdur = DURATION;
            if(stacks < MAXSTACKS)
                stacks++;
        }

        it.duration += interval;    
        
        if(stackdur > interval)
        {
            it.stacks[stacks] += interval;
            stackdur -= interval;
        }
        else
        {
            it.stacks[stacks] += stackdur;
            it.stacks[0] += interval - stackdur;
            stackdur = 0;
            stacks = 0;
        }
        
    }
        
    return it;
}
// ----------------------------------------------------------------------------

Even Angels must kill from time to time...
Find all posts by this user
Quote this message in a reply
01-08-2012, 10:28 AM (This post was last modified: 01-08-2012 10:32 AM by lostdummy.)
Post: #14
RE: DPS Excel calculator for SI Sorcerer
(01-08-2012 09:11 AM)Kor Wrote:  Here's the updated data with the rebuilt simulator (code below). Sim now casts every seconds, rather than randomly at a chance designed to meet that interval. Slightly less accurate representation of reality, significantly less chaotic and thus more reliable results:

I did simulation also, to double check numbers, and results are :

Code:
Cst     Cst/      Avg
every     buff   stacks
-----------------------
01.5    20.00    2.910
03.0    10.00    2.662
04.5    06.67    2.267
06.0    05.00    1.827
07.5    04.00    1.493
09.0    03.33    1.349
10.0    03.00    1.101
15.0    02.00    0.682
20.0    01.50    0.540
25.0    01.20    0.456
30.0    01.00    0.300
-----------------------

Second column is 'number of casts per buff duration' , essentially number of LS per 30sec - since I used that metrics in my interpolation data table in excel. But this table I simulated in 'cast every X sec' increments, to be similar to your results.

Results appear fairly similar, although there is slight difference. My simulation did 1 million runs for each data point, and each run did all casts in one 300sec fight - so for 1.5sec casts thats 200 steps per run, while for 30sec casts that is 10 steps per run. Also, results are exactly same (at 3 decimal points) every run (and each run randomize different seed).

But numbers are close enough that we can assume they will be accurate for excel interpolation ;p

Just in case, here is my code:


Code:
begin
  nSim:=1000000;
  castEvery:=1.5;
  mymsg('  Cst     Cst/      Avg');
  mymsg('every     buff   stacks');
  mymsg('-----------------------');
  while  (castEvery<=30)do
  begin
    nCstPerBuff:=30/castEvery
    TotTicks:=round(10*nCstPerBuff);  // 300sec
    aRes:=0;
    Randomize;
    ct:=0;
    for ni:=1 to nSim do
    begin
      nTicksLeft:=TotTicks;
      stack:=0;
      avgStack:=0;
      nTicksNoProc:=0;
      while nTicksLeft>0 do
      begin
        // check proc
        if random<=0.3 then
        begin
          stack:=stack+1;
          if stack>3 then stack:=3;
          nTicksNoProc:=0;
        end;
        // check if buff will drop before next tick, and use partial coverage
        inc(nTicksNoProc);
        if (nTicksNoProc>= nCstPerBuff) then
        begin
          avgStack:=avgStack+(1-(nTicksNoProc- nCstPerBuff))*stack;
          stack:=0;
        end else
          // add current stack count, based on previous tick state
          avgStack:=avgStack+stack;
        //next
        dec(nTicksLeft);
      end;
      aRes:=aRes+avgStack/totTicks;
    end;
    aRes:=aRes/nSim;
    mymsg(FormatFloat(' '+'00.0',castEvery)+'    '+FormatFloat('00.00',nCstPerBuff)+'    '+FormatFloat('0.000',aRes));
    // next step
    if castEvery<10 then castEvery:=castEvery+1.5
                      else castEvery:=castEvery+5;
    if CastEvery=10.5 then CastEvery:=10;
  end;
end;
Find all posts by this user
Quote this message in a reply
01-08-2012, 10:30 AM
Post: #15
RE: DPS Excel calculator for SI Sorcerer
Quote:Results appear fairly similar, although there is slight difference. My simulation did 1 million runs for each data point, and each run did all casts in one 300sec fight - so for 1.5sec casts thats 200 steps per run, while for 30sec casts that is 10 steps per run.

I should note, for my 10-30 data points, I did a million iterations each as well, though mine have variable durations between 180 and 300.

Even Angels must kill from time to time...
Find all posts by this user
Quote this message in a reply
01-08-2012, 11:00 AM
Post: #16
RE: DPS Excel calculator for SI Sorcerer
(01-08-2012 10:30 AM)Kor Wrote:  I should note, for my 10-30 data points, I did a million iterations each as well, though mine have variable durations between 180 and 300.

Very good point - duration does have effect on average stacks, and I only calculated for 300sec (ie same as default fight duration on excel).

For example, for 450sec fight duration, results are:

Code:
Cst     Cst/      Avg
every     buff   stacks
-----------------------
01.5    20.00    2.938
03.0    10.00    2.708
04.5    06.67    2.315
06.0    05.00    1.866
07.5    04.00    1.524
09.0    03.33    1.381
10.0    03.00    1.122
15.0    02.00    0.691
20.0    01.50    0.547
25.0    01.20    0.463
30.0    01.00    0.300
-----------------------

while for 180sec fight :

Code:
Cst     Cst/      Avg
every     buff   stacks
-----------------------
01.5    20.00    2.854
03.0    10.00    2.570
04.5    06.67    2.170
06.0    05.00    1.749
07.5    04.00    1.431
09.0    03.33    1.288
10.0    03.00    1.060
15.0    02.00    0.663
20.0    01.50    0.525
25.0    01.20    0.444
30.0    01.00    0.300
-----------------------

Close to each other, but not exactly same. And just as in excel, I dont really know what will be average operation boss fight duration ;p
Find all posts by this user
Quote this message in a reply
01-08-2012, 12:05 PM
Post: #17
RE: DPS Excel calculator for SI Sorcerer
Quote:Close to each other, but not exactly same. And just as in excel, I dont really know what will be average operation boss fight duration ;p

That could simply be deviation in the randomness. Theoretically, any multiple of 30 seconds should have roughly the same values, with longer fights coming closer to the actual value (since we're starting at 0 stacks).

Even Angels must kill from time to time...
Find all posts by this user
Quote this message in a reply
01-08-2012, 08:46 PM (This post was last modified: 01-08-2012 09:14 PM by lostdummy.)
Post: #18
RE: DPS Excel calculator for SI Sorcerer
(01-08-2012 12:05 PM)Kor Wrote:  
Quote:Close to each other, but not exactly same. And just as in excel, I dont really know what will be average operation boss fight duration ;p

That could simply be deviation in the randomness. Theoretically, any multiple of 30 seconds should have roughly the same values, with longer fights coming closer to the actual value (since we're starting at 0 stacks).

Exactly - any multiple but initial one - and that explain why shorter duration fights have lower average stacks. For 180sec fight, initial 30sec (with lower average stack) is significant part, compared to 450sec fight.

But it would also suggest that number difference is not just due to deviation in randomness, which my simulation support - even for low fight duration, when I run simulation I always get same (lower) numbers up to 2nd-3rd decimal.

Since we will not have fights getting infinitely long, if there is actual difference in stack coverage at some realistical fight durations (for example, 3min vs 6min), I wonder if I should model that too in excel... or just take average value - or value at most usual fight duration.

I could model that behavior also , by making "2 dimensional interpolation" in excel - for example, for fight duration at 2,3,4,5,7,10 min ... but I'm not sure if it pays to complicate calculation of one value so much, where difference from 'default' 300sec would be fairly small, and final influence of that difference on DPS even smaller.

*Edit* Just compared values from 3min, 4min, 5min and 6min stacks, and roughly compared to 5min values it looks like:
Code:
3 min: -5%
4 min: -1.5%
5 min:
6 min: +1%
10min: +3%
Since those values influence DPS as multiple of 1%, it means if I use 5min values for 6min fight, I introduce error in DPS of 0.01%. Even for worse case, 3min fight, error in DPS from using 5min values is only 0.05%.
Therefore it seem safe to use only value set from 300sec fight for interpolation.
Find all posts by this user
Quote this message in a reply
01-08-2012, 09:43 PM (This post was last modified: 01-09-2012 06:15 AM by lostdummy.)
Post: #19
RE: DPS Excel calculator for SI Sorcerer
I uploaded new version, with Conduction interpolated based on this simulation data.

In general, reducing (incorrect) effect of Conduction from 3% to these lower values, resulted in slightly lowering Lightning build DPS. And since all builds are very close in DPS, small changes in DPS can change which build appears to be 'best DPS'.

For example, now Lightning shows as some 3% more DPS than Madness, and some 3% lower DPS than Balanced build.

*Edit*
Also found that CL in excel was not benefiting from 20% Wrath bonus if used under Wrath instead of under Light Storm.. and after fixing that, using more CLs are beneficial even on Balanced build, which has side effect of making that build also force limited unless Light Effusion is talented. So returned that skill to default Balanced build instead of Creeping Death and 1pt Force Horrors.
Find all posts by this user
Quote this message in a reply
01-09-2012, 04:37 PM
Post: #20
RE: DPS Excel calculator for SI Sorcerer
(01-08-2012 09:43 PM)lostdummy Wrote:  I uploaded new version, with Conduction interpolated based on this simulation data.

In general, reducing (incorrect) effect of Conduction from 3% to these lower values, resulted in slightly lowering Lightning build DPS. And since all builds are very close in DPS, small changes in DPS can change which build appears to be 'best DPS'.

For example, now Lightning shows as some 3% more DPS than Madness, and some 3% lower DPS than Balanced build.

*Edit*
Also found that CL in excel was not benefiting from 20% Wrath bonus if used under Wrath instead of under Light Storm.. and after fixing that, using more CLs are beneficial even on Balanced build, which has side effect of making that build also force limited unless Light Effusion is talented. So returned that skill to default Balanced build instead of Creeping Death and 1pt Force Horrors.


I think you need to recheck your builds. The Balanced build currently has too many points spent. It's 3/17/24 atm, which is 3 too many.

To get Force Horrors 1/2, Death Mark, and Lingering Nightmares, you need 24 points in Madness. You have to fill 4 points in non-DPS talents to get to the 20pt tier. You've also spent 17 points in Lightning, but only list 16 (Lightning Spire or going 3/3 in Electric Induction are required before you can take Lightning Effusion).
Find all posts by this user
Quote this message in a reply
Post Reply 


Forum Jump:


User(s) browsing this thread: 1 Guest(s)