rperformancefor-loopsequencesequential

How to make more efficient sequential analysis in R


I want to implement a battery system for a renewable plant of energy who feeds a machine. For example, The machine requires 1000 kw/h or the energy closest to that amount. If the energy generated exceeds 1000 kw/h, the surplus could be used to charge the battery, which, let's say, is 100 kw. If the energy produced is less than 1000 kw/h and there is energy in the battery, the energy from the battery should be used to power the machine. An example generated energy dataset could be the following:

data set energia

Path Hour 1 Hour 2 Hour 3 Hour 4 Hour 5 Hour 6 ... Hour 8760
1 950,0 947,1 982,4 1013,5 1003,0 1087,7 ...
2 1046,9 947,9 981,9 1031,9 984,8 931,8 ...
3 996,1 1031,0 978,8 972,7 826,8 952,0 ...
4 943,4 1015,2 1007,2 994,8 1017,4 979,8 ...

Where should I obtain a new energy and battery charge level data set as follows:

data set Bateria

Path Hour 1 Hour 2 Hour 3 Hour 4 Hour 5 Hour 6
1 0,0 0,0 0,0 13,5 16,5 100,0
2 46,9 0,0 0,0 31,9 16,7 0,0
3 0,0 31,0 9,8 0,0 0,0 0,0
4 0,0 15,2 22,3 17,2 34,6 14,4

New data set Energia

Path Hour 1 Hour 2 Hour 3 Hour 4 Hour 5 Hour 6
1 950,0 947,1 982,4 1013,5 1003,0 1087,7
2 1046,9 994,8 981,9 1031,9 1000,0 948,5
3 996,1 1031,0 1000,0 982,5 826,8 952,0
4 943,4 1015,2 1007,2 1000,0 1017,4 1000,0

I am doing the simulation for-loop each of the hours in 1 year (8760) with a thousand possible paths of energy generation values. I am currently making a for for each column where I check the conditions (ther is more conditions), the code is the next:

carga_bateria<- data.frame(matrix(0, nrow = 1040, ncol = 8760))
for (i in 2:8760) {  
cond1<-energia[,i]>pot_elec
carga_bateria[cond1,i]=carga_bateria[cond1,i-1]*(1-0.02/100)+pmin(n_bat*7.55-carga_bateria[cond1,i-1]*(1-0.02/100),(energia[cond1,i]-pot_elec)*0.85)
# si la energia generada es mayor a la necsitada entonces la bateria queda con la carga anterior con la perdida de 0.02% + el minimo entre
#la bateria que hace falta y el excedente generado incluyendo la perdida de eficiencia al cargar de 85%.

cond2<-(energia[,i]+pmax(carga_bateria[,i-1]*(1-0.02/100)-n_bat*7.55*0.2,0))<pot_elec*0.3#cuando ni incluyendo la bateria en t-1 llega al 30% de la capacidad del electrolizador, entonces tambien se carga bateria
carga_bateria[cond2,i]=carga_bateria[cond2,i-1]*(1-0.02/100)+pmin(n_bat*7.55-carga_bateria[cond2,i-1]*(1-0.02/100),(energia[cond2,i])*0.85)

cond3<- pot_elec>energia[,i]&(pot_elec-energia[,i])<(carga_bateria[,i-1]*(1-0.02/100)-n_bat*7.55*0.2)#Caso desacarga parcial bateria, si el faltante lo puede cubrir la bateria
carga_bateria[cond3,i]=carga_bateria[cond3,i-1]*(1-0.02/100)-(pot_elec-energia[cond3,i]) #la bateria se descargaga en ese faltante
energia[cond3,i]<- pot_elec #la energia llega a la capacidad

cond4<- (energia[,i]+pmax(carga_bateria[,i-1]*(1-0.02/100)-n_bat*7.55*0.2,0))>pot_elec*0.3&(energia[,i]+pmax(carga_bateria[,i-1]*(1-0.02/100)-n_bat*7.55*0.2,0))<pot_elec# caso de descarga total
carga_bateria[cond4,i]= n_bat*7.55*0.2#la bateria se descargaga totalmente
energia[cond4,i]<- energia[cond4,i]+(carga_bateria[cond4,i-1]*(1-0.02/100)-n_bat*7.55*0.2) #la energia llega a la capacidad


cond99<-!cond1&!cond2&!cond3&!cond4
carga_bateria[cond99,i]=carga_bateria[cond99,i-1]*(1-0.02/100)
validacion[1,i]<-sum(cond1);validacion[2,i]<-sum(cond2);validacion[3,i]<-sum(cond3);validacion[4,i]<-sum(cond4)
validacion[5,i]<- sum(cond1,cond2,cond3,cond4)

}

but I want to make the process as efficient as possible. I would believe that parallelization is not an option since the analysis is sequential and conditional, although I don't know.


Solution

  • Vectorizing what we can. Additional speed would probably have to come from Rcpp.

    Example data:

    energia <- matrix(rnorm(876e4, 1e3, 20), 1e3)
    

    Process:

    system.time({
      Bateria <- array(0, dim(energia))
      Energia <- energia - 1e3
      Bateria[,1] <- pmax(pmin(Energia[,1], 100), 0)
      for (i in 2:ncol(energia)) {
        Bateria[,i] <- pmax(pmin(Bateria[,i - 1] + Energia[,i], 100), 0)
      }
      Energia[,1] <- energia[,1]
      Energia[,-1] <- energia[,-1] - pmin(0, Rfast::coldiffs(Bateria))
    })
    #>    user  system elapsed 
    #>    0.49    0.15    0.62
    

    Resulting in

    energia[1:10, 1:7]
    #>            [,1]      [,2]      [,3]      [,4]      [,5]      [,6]      [,7]
    #>  [1,] 1020.3650  973.7161 1012.1916 1011.4977 1003.0202  999.4796 1036.0359
    #>  [2,] 1029.7795  988.7669  994.9009  958.9296  995.9292  958.8030  983.2274
    #>  [3,]  977.9996 1000.7481  995.8109  972.9857  990.2269 1000.8311  992.5563
    #>  [4,] 1003.8806  998.7856  985.7410 1015.4744 1023.4497 1001.2701 1017.1896
    #>  [5,] 1013.1368 1035.9297  998.8231  990.3747 1013.2639  983.5665 1000.1635
    #>  [6,] 1011.3533 1021.4186 1012.0547  988.0986  982.9560 1045.1527  972.7560
    #>  [7,]  994.0441  997.9712  996.2793  983.3372  954.3548  998.1092 1005.5494
    #>  [8,]  970.3797 1005.9268 1033.7725 1008.7859 1015.1895 1037.7978  986.7629
    #>  [9,]  966.4012  999.3218  998.5642  977.3220 1018.2797 1007.8780 1009.1757
    #> [10,] 1038.1993 1002.0838 1002.3877 1001.0923  975.2968  930.2707 1002.9185
    Bateria[1:10, 1:7]
    #>           [,1]       [,2]     [,3]     [,4]     [,5]        [,6]      [,7]
    #>  [1,] 20.36501  0.0000000 12.19160 23.68929 26.70945  26.1890759 62.225017
    #>  [2,] 29.77954 18.5464758 13.44736  0.00000  0.00000   0.0000000  0.000000
    #>  [3,]  0.00000  0.7481351  0.00000  0.00000  0.00000   0.8311082  0.000000
    #>  [4,]  3.88059  2.6661657  0.00000 15.47445 38.92413  40.1942133 57.383772
    #>  [5,] 13.13683 49.0665635 47.88970 38.26436 51.52831  35.0948033 35.258318
    #>  [6,] 11.35329 32.7718892 44.82658 32.92519 15.88119  61.0338416 33.789819
    #>  [7,]  0.00000  0.0000000  0.00000  0.00000  0.00000   0.0000000  5.549418
    #>  [8,]  0.00000  5.9267888 39.69932 48.48522 63.67473 100.0000000 86.762890
    #>  [9,]  0.00000  0.0000000  0.00000  0.00000 18.27970  26.1576981 35.333428
    #> [10,] 38.19931 40.2830995 42.67077 43.76306 19.05989   0.0000000  2.918507
    Energia[1:10, 1:7]
    #>            [,1]      [,2]      [,3]      [,4]      [,5]      [,6]      [,7]
    #>  [1,] 1020.3650  994.0811 1012.1916 1011.4977 1003.0202 1000.0000 1036.0359
    #>  [2,] 1029.7795 1000.0000 1000.0000  972.3769  995.9292  958.8030  983.2274
    #>  [3,]  977.9996 1000.7481  996.5590  972.9857  990.2269 1000.8311  993.3874
    #>  [4,] 1003.8806 1000.0000  988.4071 1015.4744 1023.4497 1001.2701 1017.1896
    #>  [5,] 1013.1368 1035.9297 1000.0000 1000.0000 1013.2639 1000.0000 1000.1635
    #>  [6,] 1011.3533 1021.4186 1012.0547 1000.0000 1000.0000 1045.1527 1000.0000
    #>  [7,]  994.0441  997.9712  996.2793  983.3372  954.3548  998.1092 1005.5494
    #>  [8,]  970.3797 1005.9268 1033.7725 1008.7859 1015.1895 1037.7978 1000.0000
    #>  [9,]  966.4012  999.3218  998.5642  977.3220 1018.2797 1007.8780 1009.1757
    #> [10,] 1038.1993 1002.0838 1002.3877 1001.0923 1000.0000  949.3306 1002.9185