def get_settings_batteries(batterylist, interval, mysql=False): dt = parser.parse(gridlabd.get_global('clock')) #Better: getstart time! #prev_timedate = dt - timedelta(minutes=interval/60) #Prepare dataframe to save settings and current state cols_battery = [ 'battery_name', 'house_name', 'SOC_min', 'SOC_max', 'i_max', 'u_max', 'efficiency', 'SOC_t', 'active_t-1', 'active_t', 'threshold_sell', 'threshold_buy' ] df_battery = pandas.DataFrame(columns=cols_battery) for battery in batterylist: battery_obj = gridlabd.get_object(battery) house_name = 'GLD_' + battery[8:] #Fills TABLE market_appliances SOC_min = float(battery_obj['reserve_state_of_charge']) #in % SOC_max = float( battery_obj['battery_capacity']) / 1000 #Wh in Gridlabd -> kWh str_i_max = battery_obj['I_Max'].replace('-', '+') i_max = str_i_max.split('+')[1] u_max = float(battery_obj['V_Max']) * float( i_max) / 1000 #W -> kW #better inverter? eff = float(battery_obj['base_efficiency']) #Fills TABLE market_appliance_meter SOC_0 = float(battery_obj['state_of_charge']) * SOC_max df_battery = df_battery.append(pandas.Series([ battery, house_name, SOC_min, SOC_max, i_max, u_max, eff, SOC_0, 0, 0, 0.0, 0.0 ], index=cols_battery), ignore_index=True) df_battery.set_index('battery_name', inplace=True) return df_battery
def get_settings_EVs_rnd(EVlist, interval, mysql=False): cols_EV = [ 'EV_name', 'house_name', 'SOC_max', 'i_max', 'v_max', 'u_max', 'efficiency', 'charging_type', 'k', 'soc_t', 'SOC_t', 'connected', 'next_event', 'active_t-1', 'active_t' ] df_EV = pandas.DataFrame(columns=cols_EV) start_time = dt_sim_time = parser.parse( gridlabd.get_global('clock')).replace(tzinfo=None) for EV in EVlist: house_name = 'GLD_' + EV[3:] EV_obj = gridlabd.get_object(EV) #Determine some values v_max = float(EV_obj['V_Max']) #keep v_max constant for now SOC_max = np.random.choice(list_SOC) #in kWh gridlabd.set_value(EV, 'battery_capacity', str(SOC_max * 1000)) u_max = np.random.choice(list_u) #in kW i_max = 1000 * u_max / v_max gridlabd.set_value(EV, 'I_Max', str(i_max)) eff = float(EV_obj['base_efficiency']) charging_type = EV_obj['charging_type'] k = float(EV_obj['k']) #no market: always highest wllingsness to pay #Randomly generate SOC at midnight soc_t = np.random.uniform(0.2, 0.8) #relative soc soc_t = soc_t + ( 1. - soc_t ) / 2. #No EV connected yet - at midnight, initialize with 50% charged already gridlabd.set_value(EV, 'state_of_charge', str(soc_t)) SOC_t = soc_t * SOC_max connected = 1 #Set EV gridlabd.set_value(EV, 'generator_status', 'ONLINE') #gridlabd.set_value(EV,'state_of_charge',str(next_soc)) #gridlabd.set_value(EV,'battery_capacity',str(next_socmax*1000)) #i_max = 1000*next_u/df_EV_state['v_max'].loc[EV] #gridlabd.set_value(EV,'I_Max',str(i_max)) gridlabd.set_value(EV, 'P_Max', str(u_max * 1000)) gridlabd.set_value(EV, 'E_Max', str(u_max * 1000 * 1)) EV_inv = 'EV_inverter' + EV[2:] #import pdb; pdb.set_trace() gridlabd.set_value(EV_inv, 'rated_power', str(1.2 * u_max * 1000)) gridlabd.set_value(EV_inv, 'rated_battery_power', str(1.2 * u_max * 1000)) #import pdb; pdb.set_trace() next_event = start_time + pandas.Timedelta( hours=np.random.choice(dep_hours), minutes=np.random.choice(range(60))) #Next event: disconnection #Save df_EV = df_EV.append(pandas.Series([ EV, house_name, SOC_max, i_max, v_max, u_max, eff, charging_type, k, soc_t, SOC_t, connected, next_event, 0, 0 ], index=cols_EV), ignore_index=True) df_EV.set_index('EV_name', inplace=True) #Maybe drop all columns which are not used in this glm #import pdb; pdb.set_trace() return df_EV
def get_settings_houses(houselist,interval,mysql=False): dt = parser.parse(gridlabd.get_global('clock')) #Better: getstart time! prev_timedate = dt - timedelta(minutes=interval/60) #Prepare dataframe to save settings and current state cols_market_hvac = ['house_name','appliance_name','k','T_min','T_max','P_heat','P_cool','heating_setpoint','cooling_setpoint','air_temperature','active'] df_market_hvac = pandas.DataFrame(columns=cols_market_hvac) #cols_market_hvac_meter = ['system_mode','av_power','active','timedate','appliance_id'] #df_market_hvac_meter = pandas.DataFrame(columns=cols_market_hvac_meter) #Iterate through all houses and collect characteristics relevant for bidding for house in houselist: #Table with all relevant settings house_obj = gridlabd.get_object(house) k = float(house_obj['k']) T_min = float(house_obj['T_min']) T_max = float(house_obj['T_max']) heat_q = float(house_obj['heating_demand']) #heating_demand is in kW hvac_q = float(house_obj['cooling_demand']) #cooling_demand is in kW heating_setpoint = float(house_obj['heating_setpoint']) cooling_setpoint = float(house_obj['cooling_setpoint']) T_air = float(house_obj['air_temperature']) df_market_hvac = df_market_hvac.append(pandas.Series([house,'HVAC_'+house[4:],k,T_min,T_max,heat_q,hvac_q,heating_setpoint,cooling_setpoint,T_air,0],index=cols_market_hvac),ignore_index=True) #DB structure according to AWS structure #if mysql: # mysql_functions.set_values('market_houses', '(house_name)',(house,)) # mysql_functions.set_values('market_HVAC', '(house_name,appliance_name,k,T_min,T_max,P_heat,P_cool)',(house,'HVAC_'+house[4:],k,T_min,T_max,heat_q,hvac_q,)) # mysql_functions.set_values('market_HVAC_meter', '(system_mode,av_power,heating_setpoint,cooling_setpoint,active,timedate,appliance_id)',('OFF',0.0,heating_setpoint,cooling_setpoint,0,prev_timedate,int(house.split('_')[-1]),)) #df_market_hvac.to_sql('market_HVAC',mycursor,if_exists='append') #, flavor='mysql') #Index = house_number df_market_hvac.index = df_market_hvac.index + 1 return df_market_hvac
def on_sync(t): """GridLAB-D synchronization event handler Parameter: t (int): target timestamp Return: int: timestamp of next desired sync event call """ global property_list global limit_list # get the current timestamp in human readable form dt = datetime.datetime.fromtimestamp(t) gridlabd.debug(f"*** onsync({dt}) ***") # determine whether a violation has occurred violation_active = int(gridlabd.get_global("powerflow::violation_active")) if violation_active: gridlabd.debug(f"{dt}: violation detected (violation_active={violation_active})") # start by assuming there's nothing left to do with the property being considered done = None # if there's still a property to consider if property_list: # get the object name of the property to consider (the first one in the list of keys objname = list(property_list.keys())[0] gridlabd.debug(f"{dt}: updating {objname}") if objname not in limit_list: limit_list[objname] = {} # get the properties being considered for this object proplist = property_list[objname] # if the property list is non-empty if proplist: # for each property in the object's property list for propname, specs in proplist.items(): if propname not in limit_list[objname]: limit_list[objname][propname] = {} # get the property name and the property's original value prop = specs[0] base = specs[1] limit = specs[2] # if the original value is zero if base.real == 0.0: # consider property by fixed increment specified by delta and reactive_ratio value = prop.get_value() - complex(delta,delta*reactive_ratio) # original value is non-zero else: # consider property by relative increments specified by delta value = prop.get_value() - base/base.real*delta # if a violation has occurred if violation_active: gridlabd.debug(f"{dt}: resetting {objname}.{propname} to base {base}") # reset the property to its original value prop.set_value(base) # record the load limit if not objname in limit_list.keys() or not propname in limit_list[objname].keys(): load_limit = base - value limit_list[objname][propname] = { "timestamp" : str(datetime.datetime.fromtimestamp(t)), "real" : load_limit.real, "reactive" : load_limit.imag} limit_list[objname][propname]["violation"] = gridlabd.get_value(objname,"violation_detected") # flag that processing is done done = objname # if the maximum solar limit is reached elif power_limit and value.real < power_limit and limit == "POWER": gridlabd.debug(f"{dt}: power limit reach for {objname}.{propname} = {value}") # reset the property to its original value prop.set_value(base) # record the load limit if not objname in limit_list.keys() or not propname in limit_list[objname].keys(): load_limit = base - value limit_list[objname][propname] = { "timestamp" : str(datetime.datetime.fromtimestamp(t)), "real" : load_limit.real, "reactive" : load_limit.imag} limit_list[objname][propname]["violation"] = "POWERLIMIT" # flag that processing is done done = objname # if the maximum solar limit is reached elif voltage_limit and base.real != 0.0 and abs((value.real-base.real)/base.real) > voltage_limit and limit == "VOLTAGE": gridlabd.debug(f"{dt}: power deviation limit reach for {objname}.{propname} = {value}") # reset the property to its original value prop.set_value(base) # record the load limit if not objname in limit_list.keys() or not propname in limit_list[objname].keys(): load_limit = base - value limit_list[objname][propname] = { "timestamp" : str(datetime.datetime.fromtimestamp(t)), "real" : load_limit.real, "reactive" : load_limit.imag} limit_list[objname][propname]["violation"] = "VOLTAGELIMIT" # flag that processing is done done = objname # if no violation has occurred else: gridlabd.debug(f"{dt}: updating {objname}.{propname} = {value}") # set the new value of the property prop.set_value(value) # compute the load limit implied by this value load_limit = base - value # record the load limit limit_list[objname][propname] = { "timestamp":str(datetime.datetime.fromtimestamp(t)), "real":load_limit.real, "reactive":load_limit.imag, "violation" : "NONE" } # the property list is empty else: # flag that processing is done done = objname # if done if done: gridlabd.debug(f"{dt}: finished with {objname}") # if property list is empty if proplist == {}: # remove the object from the list of properties to consider del property_list[objname] # the property list is not empty else: # clear the property list (this will allow an extra solver iteration to clear the violation) property_list[objname] = {} # if the property list is non-empty if property_list: gridlabd.debug(f"{dt}: next is {list(property_list.keys())[0]}") # if a violation occurred if violation_active: # clear the violation gridlabd.debug(f"{dt}: clearing violation") gridlabd.set_global("powerflow::violation_active","0") # wait 1 minute for controls to settle before trying the next value tt = t+60 gridlabd.debug(f"updating to {datetime.datetime.fromtimestamp(tt)}") return tt # no objects or properties left to consider else: # nothing left to do gridlabd.debug(f"updating to NEVER") return gridlabd.NEVER
def on_init(t): """GridLAB-D initialization event handler Parameter: t (int): initial timestamp Return: bool: success (True) or failure (False) """ global output_folder global object_list global target_properties # get the output folder name from the global variable list output_folder = gridlabd.get_global("OUTPUT") # if none is defined if not output_folder: # use the current working direction output_folder = "." # if objects to consider are not specified if not object_list: # use list of all objects object_list = gridlabd.get("objects") # for each object in the object list for objname in object_list: # the object's class classname = gridlabd.get_value(objname,"class") # if the class is listed among the targets for classname, target_list in target_properties.items(): # get the object's data objdata = gridlabd.get_object(objname) # if the object has phase data if "phases" in objdata.keys(): # get the object's class structure classdata = gridlabd.get_class(classname) # for each property in the class's target property list for property_name, limittype in target_list.items(): # get the property pattern to use, and replace phase information pattern, if any pattern = property_name.replace("{phases}",f"[{objdata['phases']}]") # for each property in the class for propname in classdata.keys(): # if the property matches the pattern if re.match(pattern,propname): # add the property to the list of properties to consider add_property(objname,propname,limittype,nonzero=False) # successfully initialized return True
# construct the command line (gridlabd hasn't started yet) gridlabd.command('example.glm') # start gridlabd and wait for it to complete gridlabd.start('wait') # send the final model state to a file gridlabd.save('done.json') # # Part 2 - plot the results # # gather the results collected by on_term t = np.array(gridlabd.result["t"]) t = t - t[0] x = np.array(gridlabd.result["x"]) # plot the result plt.figure() plt.plot(t / 3600.0, x, label=gridlabd.graph_label) plt.xlabel(gridlabd.graph_xlabel) plt.ylabel(gridlabd.graph_ylabel) plt.grid() plt.legend() modelname = gridlabd.get_global("modelname") title_name = gridlabd.graph_title plt.title(title_name) plt.savefig(modelname.replace(".glm", ".png"))
def compute_bill(gridlabd, **kwargs): global csvwriter verbose = gridlabd.get_global("verbose") == "TRUE" global csvfile # get data classname = kwargs['classname'] id = kwargs['id'] data = kwargs['data'] bill_name = f"{classname}:{id}" bill = gridlabd.get_object(bill_name) bill_name = bill["name"] baseline = to_float(bill["baseline_demand"]) tariff = gridlabd.get_object(bill["tariff"]) meter = gridlabd.get_object(bill["meter"]) energy = to_float(meter["measured_real_energy"]) / 1000 # units in kW # get duration clock = to_datetime(gridlabd.get_global('clock'), '%Y-%m-%d %H:%M:%S %Z') if not "lastreading" in data.keys(): duration = timedelta(0) else: duration = clock - data["lastreading"] data["lastreading"] = clock billing_days = (duration.total_seconds() / 86400) # seconds in a day # compute energy usage if not "lastenergy" in data.keys(): usage = 0.0 else: usage = energy - data["lastenergy"] data["lastenergy"] = energy # calculate bill tariff_name = tariff["name"] meter_name = meter["name"] if verbose: gridlabd.output( f"Bill '{bill_name}' for meter '{meter_name}' on tariff '{tariff_name}' at time '{clock}':" ) gridlabd.output(f" Billing days..... %5.0f days" % (billing_days)) gridlabd.output(f" Meter reading.... %7.1f kWh" % (energy)) if baseline == 0.0: if verbose: gridlabd.output(f" Energy usage..... %7.1f kWh" % (usage)) charges = usage * to_float(tariff["energy_charge_base"]) else: tier1 = min(usage, baseline * billing_days) tier2 = min(usage - tier1, baseline * billing_days * 4) tier3 = usage - tier1 - tier2 if verbose: gridlabd.output(f" Tier 1 usage..... %7.1f kWh" % (tier1)) if tier2 > 0: gridlabd.output(f" Tier 2 usage..... %7.1f kWh" % (tier2)) if tier3 > 0: gridlabd.output(f" Tier 3 usage..... %7.1f kWh" % (tier3)) charges = tier1 * to_float( tariff["energy_charge_base"]) + tier2 * to_float( tariff["energy_charge_100"]) + tier3 * to_float( tariff["energy_charge_400"]) # apply discount, if any discount = to_float(tariff["discount"]) if discount > 0: charges -= usage * discount # apply daily minimum minimum = to_float(tariff["minimum_daily_charge"]) if charges < minimum * billing_days: charges = minimum * billing_days if verbose: gridlabd.output(f" Energy charges... %8.2f US$" % (charges)) # output billing record only if charges are non-zero if charges > 0: csvwriter.writerow([ clock.strftime('%Y-%m-%d'), meter_name, tariff_name, int(billing_days), round(usage, 1), 0, round(charges, 2) ]) csvfile.flush() # update billing data gridlabd.set_value(bill_name, "total_bill", str(to_float(bill["total_bill"]) + charges)) gridlabd.set_value(bill_name, "billing_days", str(billing_days)) gridlabd.set_value(bill_name, "energy_charges", str(to_float(bill["energy_charges"]) + charges)) gridlabd.set_value(bill_name, "total_charges", str(to_float(bill["total_charges"]) + charges))