How to use LinkedHashMaps in Anylogic - anylogic

I want to have a cumulative number of sows that enter the Sink (deadSowsCulledSows and
sowDeaths) over the last 52 weeks. I have created variables for weekly sow
deaths at these sink locations using cyclic events. I want this cumulative number to be calculated for every week of the simulation. For example, at week 10 – I want to have a cumulative
number of deaths for weeks 1 to 10; at week 52 – I want to have a cumulative number for week 1
to 52, and for week 53 – I want to have a cumulative number between weeks 2 and 53,
and so on.
It has been suggested that I use a LinkedHashMap, and I agree, but I don't know where to begin with setting this up? I want to use week as the value and weekly deaths as the key. Where do I insert the code to have the values put into the LinkedHashMap?
I feel like I am missing components in order to achieve this.

It sounds like you want a moving window of the last 52 weeks.
There are a few options here but the easiest one I would suggest for you is to make use of the AnyLogic DataSet object as it already has this "keep up to a maximum number of samples" functionality which is what you need.
Setup a data set where you set the maximum number of samples to keep to 52, do not update automatically and do not use time as x-axis as we will set this up ourselves.
In the sink block you increase the weekly variable. (Which I assume you are already doing)
Create a HashMap. I would suggest you use the week as the key and the number of deaths as the value (You had it the other way around in your question)
Then you have some event that saves the weekly sum of values to the dataset, reset the variable to 0.
Then gets the sum of the data set and save it to the LinkedHasMap.
The code for your weekly event can be as below
weekCounter ++;
deaths.add(weekCounter, weeklyDeaths);
weeklyDeaths = 0;
int tempSum = 0;
for (int i = 0; i < deaths.size(); i ++) {
tempSum += deaths.getY(i);
}
mapOfDeathsPerWeek.put(weekCounter, tempSum);
Where weekCounter is just another variable that I created that I can increase every week to keep track of the weeks.

Related

Using request.security data to use for calculations

I want to achieve the following...
For every candle, I want to calculate the "max range" of the previous x candles.
I then want to use this max range values and compare it with the ATR of the daily timeframe, to get the "max range" value as a percentage of the daily ATR
Point 1, was the easy part and I was able to achieve that with the below code.
// USER INPUTS
iLookBack = input.int(defval = 4, title = "Lookback Period")
// MAX RANGE OF THE LAST x CANDLES
maxRange = math.abs(ta.highest(iLookBack) - ta.lowest(iLookBack))
plot(maxRange, color = color.aqua)
Below a picture of it.
Point 2 is where I got stuck, and where your help is needed.
I tried fetching the daily ATR data using the request.security function
datr = request.security(syminfo.tickerid,"D", ta.atr(14))
On the current day, I get a DATR reading on all candles of the day.
But on the prior day, I only get a DATR reading on the FIRST CANDLE OF THE DAY.
So far so good...
But when using the DATR data and trying to plot the result of the calculation (below) I only get the result of the calculation plotted for the 1st candle of the day.
plot(maxRange/datr)
And the result is looking like this..
This is not what I want..
What I want is, that for every candle, I want to compare the "maxRange" with the DATR reading. And that this result is being plotted.
My guess is, that the data fetched using the request.security function is only valid for ONE candle at the lower timeframe? I'm actually not sure.
I looked up the documentation but couldn't find the answer to my problem..
I hope my problem is clear. And what I'm trying to achieve is making sense to you.
Thank you very much in advance.

AnyLogic variable for cumulative sum in system dynamics

Good morning, in a System Dynamics model created on AnyLogic, I would like to compute the cumulative sum of a flow of the previous 7 days.
My purpose is to calculate the reproduction ratio of a disease starting from the infectious population at time t over the cumulative sum of the infectious in a fixed time interval. The formula is the following:
Formula
where:
I(t) = infectious population at time t --> I(t) is a flow in the model that changes a stock
I(t-s) = infectious population at time t-s
w(s) = gamma distribution
s represents the time interval of the previous 7 days
I have all the data but I am not able to calculate the sum of I(t-s).
Thanks.
You have to do this manually. Create a variable mySum of type double. Then, add a cyclic event that regularly adds to it from the stock (something like myVar += myStock).
You may need to use an additional variable that stores the temporary stock value from the last time you added, so you only add what was "new" since the last cycle.
In short: use a cyclic event to "approximate" your integral.

Detecting patterns in data with Tableau

i'm totally new to Tableau but that is what I could potentially use at the workplace, so asking this question to decide if its worth it.
I've a monthly values dataset and I'd like the tool (Tableau) to generate a report to point out anomalies - the ones i have in mind right now are:
1) same data value for x months in a row
2) data value is 0
3) 5 parameters been reported last 3 months and all of sudden only 4 are reported
Is this possible in Tableau?
You can certainly do this. The below is a general example for doing anomaly detection (one standard deviation outside of mean) but you can modify the calc to fit your criteria. If you place your date field in the column position and your metric, lets say Sales, in the row position you can then create this calculated field to label the anomalies.
IF SUM([Sales]) < (WINDOW_AVG(SUM([Sales])) – WINDOW_STDEV(SUM([Sales]))) THEN “Bad
Anomaly”
ELSEIF SUM([Sales]) > (WINDOW_AVG(SUM([Sales])) + WINDOW_STDEV(SUM([Sales]))) THEN
“Good Anomaly”
ELSE “Expected”
END
You can then place the new field on your color mark to highlight each of the results.

How to get monthly totals from linearly interpolated data

I am working with a data set of 10,000s of variables which have been repeatedly measured since the 1980s. The first meassurements for each variable are not on the same date and the variables are irregularly measured - sometimes measurements are only a month apart, in a small number of cases they are decades apart.
I want to get the change in each variable per month.
So far I have a cell of dates of measurements,and interpolated rates of change between measurements (each cell represents a single variable in either, and I've only posted the first 5 cells in each array)
DateNumss= {[736614;736641;736669] [736636;736666] 736672 [736631;736659;736685] 736686}
LinearInterpss={[17.7777777777778;20.7142857142857;0] [0.200000000000000;0] 0 [2.57142857142857;2.80769230769231;0]}
How do I get monthly sums of the interpolated change in variable?
i.e.
If the first measurement for a variable is made on the January 1st, and the linearly interpolated change between that an the next measurement is 1 per day; and the next measurement is on Febuary the 5th and the corresponding linearly interpolated change is 2; then January has a total change of 1*31 (31 days at 1) and febuary has a total change of 1*5+2*23 (5 days at 1, 23 days at 2).
You would need the points in the serial dates that correspond with the change of a month.
mat(:,1)=sort(repmat(1980:1989,[1,12]));
mat(:,2)=repmat(1:12,[1,size(mat,1)/12]);
mat(:,3)=1;
monthseps=datenum(mat);
This gives you a list of all 120 changes of months in the eighties.
Now you want, for each month, the change per day, and sum it. If you take the original data it is easier, since you can just interpolate each day's value using matlab. If you only have the "LinearInterpss" you need to map it on the days using interp1 with the method 'previous'.
for ct = 2:length(monthseps)
days = monthseps(ct-1):(monthseps(ct)-1); %days in the month
%now we need each day assigned a certain change. This value depends on your "LinearInterpss". interp1 with method 'previous' searches LineairInterpss for the last value.
vals = interp1(DateNumss,LinearInterpss,days,'previous');
sum(vals); %the sum over the change in each day is the total change in a month
end

how to simulate date for one year in kdb

i would like to simulate random timestamp data.
100 records in a day for one year.
How am I am able to do that?
when i set a:2013.01.01D00:00:00.000000000
100?a
the randomize data doesn't stay in a day.
thanks for your input
I am not sure, if this can be done easily. But you may generate 100 random timestamps for every day of 2013 in the next way
daysInYear: 365;
year: 2013.01.01D00:00:00.000000000;
//array of 365 elements, where every element represents corresponding date of year
dates: year + 01D * til daysInYear;
//array of 365 elements, where every element is an array of 100 random timestamps [0 .. 1D)
randomNanos: cut[100; (100 * daysInYear)?1D];
//array of 365 elements, where each element is an array of 100 random dateTimes for given day
result: dates + randomNanos;
//put all the dates in single array
raze result
The short version which does the same is below:
raze (2013.01.01D+01D * til 365) + cut[100; (100*365)?1D]
In order to simulate data for a single day, it's possible to generate random times (as floats less than one) and add them to the day you would like to generate data for. In this case:
D:2016.03.01;
D+100?1f
Will return 100 random times on 2016.03.01. If you want to generate data within a time range you can restrict the size of the float to something less than 1, or greater than a certain minimum value.
If you want to handle leap years... Not sure of a better way at the minute other than adding the max number of days onto the start of the year and asking whether it's the 31st. Adding on 366, it can either be 31st or 1st. If it's the 31st good, otherwise drop off the last date.
/e.g.
q)last 2015.01.01+til 365
2015.12.31
q)last 2016.01.01+til 365
2016.12.30 /we are a day short
q)
/return the dates and the number of days based on whether its a leap year
q)dd:$[31i~`dd$last d:2016.01.01+til 366;(366;d);(365;-1_d)]
q)/returns (366;2016.01.01 2016.01.02...)
q)/the actual logic below is pretty much the same as the other answer
q)raze{[n;dy;dt] dt+n cut(n*dy)?.z.N}[100;].dd
2016.01.01D16:06:53.957527121 2016.01.01D10:55:10.892935198 2016.01.01D15:36:..