Hello!
A small suggestion to the ramping part of the grid cost
-
with the current implementation you don’t encourage a smooth load change. As an example here is an image with 3 load patterns, all consume the same amount of energy, and the ramping is A: 8, B:16, C: 8. In other words it is the same for buildings A and C, while I expect C is much more preferable for the grid.
-
a very simple adaptation in your formula is to take changes in load to the power of 2 instead of the absolute. Later, if needed, you can take a square root of the result, which will make the ramping as A: 4, B:5.7, C: 1.3.

In any case here is the code for the example if you want to check:
import pandas as pd
import numpy as np
a = pd.Series(np.zeros(shape=48))
a[2:14] = 2
a[26:38] = 2
b = pd.Series(np.zeros(shape=48))
b[2:12] = 2
b[14:16] = 2
b[26:36] = 2
b[38:40] = 2
c = pd.Series(np.sin(np.arange(-np.pi*0.5,np.pi*3.5,np.pi/12))+1)
df = a.to_frame('A').join(b.to_frame('B')).join(c.to_frame('C'))
df.index+=1
df.loc[0,:] = 0
print((df-df.shift(1)).abs().sum())
print((df-df.shift(1)).pow(2).sum())
print((df-df.shift(1)).pow(2).sum()**(0.5))