Using DAX for Production Planning - powerpivot

My question is based on building a ramp up for planning production lines.
I have a WIP where a ramp up category is selected to be used for each MSO (Master Sew Order). The Ramp up is based on hour fences (for example 1-6 hours,6-12 hours,etc).
On the WIP, an MSO will have units (example 1,920 units), divided by capacity per hour (80 pcs/hr), to give time needed 24 hours. This then needs to be
calculated based on ramp up, for hours 1-6, 6-12, 12-18, and 18-24 and multiply our by related efficiency.
For example:
Hours 1-6: 20% efficiency * 80 units = 16 units/hr (6 x 16 = 96 units produced)
Hours 6-12: 40% efficiency * 80 units = 32 units/hr (192 units)
Hours 12-18: 60% efficiency * 80 Units = 48 units/hr (288 units)
Hours 18-24: 80% efficiency * 80 units = 64 units/hr (384 units)
Hours 24+: 100% efficiency * 80 units = 80 units/hr ((1920-960)/80)= 12 hours remaining
TOTAL TIME = 36 hours to produce
How would Power BI know to divide up the original 24 hour estimate into parts, multiply by respective efficiency, and return a new result of 36 hours?
Thank you so much in advance!
Kurt
Relationships

I'm not sure how to do this in DAX but you tagged PowerQuery so here's a custom query that computes 36 based on your parameters:
let
MSO = 1920,
Capacity = 80,
Efficiency = {
{6, 0.2},
{12, 0.4},
{18, 0.6},
{24, 0.8},
{#infinity, 1.0}
},
Accumulated = List.Accumulate(Efficiency, [
Remaining = MSO,
RunningHours = 0
], (state, current) =>
let
until = current{0},
eff = current{1},
currentCapacity = eff * Capacity,
RemainingHours = state[Remaining] / currentCapacity,
CappedHours = List.Min({RemainingHours, until - state[RunningHours]})
in [
Remaining = state[Remaining] - currentCapacity * CappedHours,
RunningHours = state[RunningHours] + CappedHours
]),
Result = if Accumulated[Remaining] = 0
then Accumulated[RunningHours]
else error "Not enough time to finish!"
in
Result
The inner lists for Efficiency are of the form time-efficiency-ends,efficiency-value. Plug in infinity to mean the last efficiency never stops.
In a normal iterative programming language you could update state with a for-loop, but in M you need to use List.Accumulate and package all your state into one value.

In your data model you may have MSO in one table containing 2 fields, [Units] and [UnitsPerHour], and another table called EffTable which may store the efficiencies broken out by the hour fences.
Create 4 new calculated columns in your MSO table, one for each hour fence, eg [1--6]:
=
6 * LOOKUPVALUE ( EffTable[Efficiency], EffTable[Hours], "1--6" )
* [UnitsPerHour]
These are fields that hold how many units you would produce in the 4 time slots. Create a new calculated field for the total, [RampUpUnits]:
=
[1--6Hours] + [6--12Hours] + [12--18Hours] + [18--24Hours]
Finally calculate the total time as:
=
24
+ ( [Units] - [RampUpUnits] )
/ [UnitsPerHour]
This calculates the number of hours required for the remaining units and adds it to 24 for the ramp up time.

Related

Is there a way to use cumsum with a threshold to create bins?

Is there a way to use numpy to add numbers in a series up to a threshold, then restart the counter. The intention is to form groupby based on the categories created.
amount price
0 27 22.372505
1 17 126.562276
2 33 101.061767
3 78 152.076373
4 15 103.482099
5 96 41.662766
6 108 98.460743
7 143 126.125865
8 82 87.749286
9 70 56.065133
The only solutions I found iterate with .loc which is slow. I tried building a solution based on this answer https://stackoverflow.com/a/56904899:
sumvals = np.frompyfunc(lambda a,b: a+b if a <= 100 else b,2,1)
df['cumvals'] = sumvals.accumulate(df['amount'], dtype=np.object)
The use-case is to find the average price of every 75 sold amounts of the thing.
Solution #1 Interpreting the following one way will get my solution below: "The use-case is to find the average price of every 75 sold amounts of the thing." If you are trying to do this calculation the "hard way" instead of pd.cut, then here is a solution that will work well but the speed / memory will depend on the cumsum() of the amount column, which you can find out if you do df['amount'].cumsum(). The output will take about 1 second per every 10 million of the cumsum, as that is how many rows is created with np.repeat. Again, this solution is not horrible if you have less than ~10 million in cumsum (1 second) or even 100 million in cumsum (~10 seconds):
i = 75
df = np.repeat(df['price'], df['amount']).to_frame().reset_index(drop=True)
g = df.index // i
df = df.groupby(g)['price'].mean()
df.index = (df.index * i).astype(str) + '-' + (df.index * i +75).astype(str)
df
Out[1]:
0-75 78.513748
75-150 150.715984
150-225 61.387540
225-300 67.411182
300-375 98.829611
375-450 126.125865
450-525 122.032363
525-600 87.326831
600-675 56.065133
Name: price, dtype: float64
Solution #2 (I believe this is wrong but keeping just in case)
I do not believe you are tying to do it this way, which was my initial solution, but I will keep it here in case, as you haven't included expected output. You can create a new series with cumsum and then use pd.cut and pass bins=np.arange(0, df['Group'].max(), 75) to create groups of cumulative 75. Then, groupby the groups of cumulative 75 and take the mean. Finally, use pd.IntervalIndex to clean up the format and change to a sting:
df['Group'] = df['amount'].cumsum()
s = pd.cut(df['Group'], bins=np.arange(0, df['Group'].max(), 75))
df = df.groupby(s)['price'].mean().reset_index()
df['Group'] = pd.IntervalIndex(df['Group']).left.astype(str) + '-' + pd.IntervalIndex(df['Group']).right.astype(str)
df
Out[1]:
Group price
0 0-75 74.467390
1 75-150 101.061767
2 150-225 127.779236
3 225-300 41.662766
4 300-375 98.460743
5 375-450 NaN
6 450-525 126.125865
7 525-600 87.749286

pandas transform moving average daily base to weekly base

I have a moving average with data points on everyday base e.g. 14 days MA.
Now I want to take this MA and display it on a bar chart e.g. one bar represents a week.
How I calculate the MA for this bar?
Is it the sum of the daily MA points over the week?
1,2,3,4,5,6,7
So the MA is 28? but the base is still daily?
Can someone try to explain if this makes sense and is correct?
Yes, Moving Average (MA) for the bar is the average of daily MA (daily count).
So
# Calculating MA
MA(week1) = (MA1 + MA2 + MA3 + MA4 + MA5 + MA6 + MA7)/7
MA(week1) = (1 + 2 + 3 + 4 + 5 + 6 + 7)/7 = 4
# Bar value 4
Incase your data is 14-day MA, you will have to make some assumptions and calculate the weekly MA. Have a look at the example to get a better understanding.
# 14-day MA -> Weekly MA
(W1 + W2)/2 = MA1
(W2 + W3)/2 = MA2
...
(Wn-1 + Wn)/2 = MAn-1
# Assume W1 == W2, you can estimate the per weekly MA
Example to calculate Moving Average

Increase or decrease a variable or parameter over a period of time in GAMS

Please how can i increase or decrease the value of a variable or parameter over a period of time generated using an ordered set? 1-24 hours.
I am modelling the charging and discharging of electric vehicles and I need to increase or decrease the State of charge SOC(battery level) after every period (depending on whether it is charging or discharging).
I have tried several methods but it isn't working. Also will it be best to model the battery level as a parameter or variable? I am trying to minimize the cost of customers charging their vehicles while also ensuring they get the maximum charge needed. Here is a snippet of my code.
Objective function is minimize( ∑Cost of charging -∑cost of discharging +∑Cost of unfulfilled charge)
isoc is initial state of charge
fsoc is final or expected state of charge
v1 = vehicle 1
v2 = vehicle 2
Set
t 'hours' / 1*10 /
i 'number of vehicles' / v1*v2 /;
Table vehdata(i,*) 'Vehicle characteristics'
at dt isoc fsoc
v1 1 8 4 50
v2 3 6 6 70
Scalar charging_power 'Charging power at station' / 6.6 /;
*Energy cost in dollars per kWh
Parameter energy_cost(t) / 1 0.03, 2 0.028, 3 0.025, 4 0.025, 5 0.026, 6 0.028,
7 0.041, 8 0.051, 9 0.048, 10 0.047 /;
Variable
Icharge(i,t)'charging decision'
Idischarge(i,t)'discharging decision'
z 'total cost of charging'
soc(i,t) 'State of charge'
Binary Variable Icharge, Idischarge;
soc.lo(i,t) = vehdata(i,"isoc");
soc.up(i,t) = vehdata(i,"fsoc");
Equation
costCharging 'define objective function'
soc_const1(i,t) 'Charging or discharging only takes place between arrival and departure'
soc_const2(i,t) 'SOC cannot charge and discharge at same time'
soc_const3(i,t) 'Increase or decrease state of charge after every period';
costCharging.. z =e= sum((i,t), (Icharge(i,t)*energy_cost(t) * charging_power)) -sum((i,t),(Idischarge(i,t)*energy_cost(t) * charging_power)) + sum((i,t), (vehdata(i,"tsoc") - soc(i, t))* energy_cost(t));
soc_const1(i,t).. Icharge(i,t) =e= 0$(vehdata(i,"at")> ord(t) and vehdata(i,"dt")< ord(t));
soc_const2(i,t).. Icharge(i,t) + Idischarge(i,t) =e= 1;
soc_const3(i,t).. soc(i,t) =e= soc(i,t+1) + (Icharge(i,t) * charging_power) - (Idischarge(i,t) * charging_power) ;
Model op_charging / all /;
solve op_charging using mip minimizing z;
display soc.l;
Firstful your model has some errors based on given. You should add ";" end of table vehdata like "v2 3 6 6 70;". Also, I think you want that the first constraint works on "at" and "dt" for each vehicle. Therefore I change it like:
soc_const1(i,t)$(vehdata(i,"at") = ord(t) or vehdata(i,"dt") = ord(t)).. Icharge(i,t) =e= 0;
Now you have a working model. But I think that it has logical errors. Therefore you should work on constraints.

Solar energy conversion w/m^2 to mj/m^2

i am new here, I am using MERRA monthly solar radiation data. I want to convert w/M^2 to MJ/m^2
I am bit confused, how to convert solar radiation monthly average data W/m^2 to MJ/m^2
so far i understood by reading different sources,
Firstly i have to convert w/m^2 to kw/m^2
after kw/m^2 to mj/m^2 .......
Am i doing correctly
Just i am taking one instance:
For may month i have value 294 w/m^2
So 294 * 0.001 = 0.294 kw/m^2
0.294 * 24 (kw to kwh (m^/day)) = 7.056 kwh/m^2/day
7.056 * 3.6 (kwh to mj) = 25.40 mj/day
i am confused i am doing right or wrong .
Not sure why you would take the kWh step in between.
Your panels do 294 Watt per m², i.e. 294 Joule per sec per m². So that's 24*60*60 * 294 = 25401600 Joule per m² per day, or 25.4016 MJ per m² per day.
So if:
1 W/m2 = 1 J/m2 s
Then:
294 W/m2 = 294 J/m2 s
if you want it in days then:
1 day = 60s * 60min *24h = 86400s
294 J/m2 s x 86000s/1day = 25284000 J/m2 day
25284000 J/m2 day x 1MJ/1000000J = 25.284 MJ/m2 day
all together:
294 W/m2 = 294/(1000000/86400) = 25.4016 MJ/m2 day
A watt is the unit of power and Joules are the units of energy, they are related by time. 1 watt is 1 Joule per second 1W = 1 J/s. So the extension of that equation is that 1J = 1w x 1second. 1J = 1Ws. A loose analogy is if you say Litre is a unit of volume and L/S is a unit of flow. So your calculation needs to consider how long you are gathering the solar energy. So the number of Joules, if the sunlight shines at 90degrees to the solar panel for 1 hour is 294W/m2 x 3600s and would give ~1 x 10^7 joules per square metre. Of course as the inclination [the angle of light] varies away from 90 degrees, this will cause the effective power and hence the energy absorbed to drop, as a function of the sine of the angle to the sun. 90 degrees gives a sine of 1 and is full power.

Counting the number of datapoints within a Euclidean distance MS SQL

Have 2 data sets
list of 300 geocordinates
list of over 2million geocordinates
For each entry in list 1, I am trying to count the number of entries from list 2 that lie within 5 mile radius.
I've decided to use the euclidean distance as i am only dealing with relatively small distances.
Here is my code. It takes forever to run. Any suggestions on how I can improve the code.
Select
DistFilter.storenumber,
count(companynumber) as sohoCount
from
(Select
UKStoreCoord.storenumber,
UKStoreCoord.latitude as SLat,
UKStoreCoord.longitude as SLng,
SohoCoordinates.companynumber,
SohoCoordinates.latitude,
SohoCoordinates.longitude
from UKStoreCoord, SohoCoordinates
where abs(UKStoreCoord.latitude - SohoCoordinates.latitude)<0.1 and abs(SohoCoordinates.longitude - UKStoreCoord.longitude)<0.1
group by
UKStoreCoord.storenumber,
UKStoreCoord.latitude,
UKStoreCoord.longitude,
SohoCoordinates.companynumber,
SohoCoordinates.latitude,
SohoCoordinates.longitude) as DistFilter
where (((Distfilter.latitude - Distfilter.SLat) * 69) ^2 + ((Distfilter.longitude - Distfilter.SLng) * 46) ^2) <25
group by
DistFilter.storenumber
cheers