def populateMeetingsForRoomAllocNSchedule(self, meetings): """Populate meetings from configuration files""" for k, v in meetings.iteritems(): tw = [] for sk, sv in v.iteritems(): if sk.startswith("W"): st = datetime.strptime(sv.get('Start'), "%Y-%m-%d %H:%M") et = datetime.strptime(sv.get('End'), "%Y-%m-%d %H:%M") if et < st: logging.critical("Meeting[%s] Invalid time windows [%s]. End Time earlier than Start Time." %(k,sk)) return EAMS_Error().eams_meeting_invalid_time_windows() elif self._validateOverlappedTimeWindows(tw, st, et) < 0: logging.critical("Meeting[%s] Invalid time windows [%s]. Duplicate time windows." %(k,sk)) return EAMS_Error().eams_meeting_overlapped_time_windows() else: tw.append([st,et]) stw = sorted(tw, key=itemgetter(0)) if 'Preferred_Room' in v: self.mlist.append(self.mdesc(k, stw, int(v['Duration']), v['Preferred_Room'], v['Attendees'])) else: self.mlist.append(self.mdesc(k, stw, int(v['Duration']), "", v['Attendees'])) # debug only logging.debug(self.mlist) for i in xrange(len(self.mlist)): logging.debug("Meeting [%s]" %(self.mlist[i].Key)) for j in xrange(len(self.mlist[i].TimeWindows)): logging.debug(self.mlist[i].TimeWindows[j]) return 0
def __init__(self): """Initialization""" self.err = EAMS_Error() self.rooms = {} self.zones = {} self.zonelist = {} self.roomlist = [] self.roomcapa = [] self.room_neighbours = []
def populateMeetingsForRoomAllocNSchedule(self, TSC): """Populate meetings from configuration files""" num_m = 0 for k, v in self.meetings.iteritems(): tw = [] for sk, sv in v.iteritems(): if sk.startswith("W"): st = datetime.strptime(sv.get('Start'), "%Y-%m-%d %H:%M") et = datetime.strptime(sv.get('End'), "%Y-%m-%d %H:%M") if et < st: logging.critical( "Meeting[%s] Invalid time windows [%s]. End Time earlier than Start Time." % (k, sk)) return EAMS_Error().eams_meeting_invalid_time_windows() elif self._validateOverlappedTimeWindows(tw, st, et) < 0: logging.critical( "Meeting[%s] Invalid time windows [%s]. Duplicate time windows." % (k, sk)) return EAMS_Error( ).eams_meeting_overlapped_time_windows() else: tw.append([st, et]) stw = sorted(tw, key=itemgetter(0)) tw_offset = [] for i in xrange(len(stw)): sidx = TSC.getTimeSlotIdxByDatetime(stw[i][0]) eidx = TSC.getTimeSlotIdxByDatetime(stw[i][1]) - 1 tw_offset.append([sidx, eidx]) logging.debug( "Meeting %s start at %s[slot %d], deadline at %s[slot %d], duration of %s slot(s)" % (k, stw[i][0], sidx, stw[i][1], eidx, int(v['Duration']))) if 'Preferred_Room' in v: self.mlist.append( self.mdesc( num_m, k, None, stw, tw_offset, int(v['Duration']), v['Preferred_Room'], v['Attendees'], datetime.strptime(v['CreateTime'], "%Y-%m-%d %H:%M"))) else: self.mlist.append( self.mdesc( num_m, k, None, stw, tw_offset, int(v['Duration']), "", v['Attendees'], datetime.strptime(v['CreateTime'], "%Y-%m-%d %H:%M"))) num_m += 1 logging.debug(self.mlist) return 0
def __init__(self, rl, rh, cl, ch, sl, sm, sh): """Initialization""" self.err = EAMS_Error() self.ROOM_CONFIG = None self.WALL_RESISTANCE_LOW = rl self.WALL_RESISTANCE_HIGH = rh self.WALL_CAPACITANCE_LOW = cl self.WALL_CAPACITANCE_HIGH = ch self.SOLAR_GAIN_LOW = sl self.SOLAR_GAIN_MEDIUM = sm self.SOLAR_GAIN_HIGH = sh # self.ROOM_CONFIG_SPEC = 'Data/eams_room_spec.cfg' self.ROOM_CONFIG_SPEC = 'Data/ConfigSpecs/eams_room_spec.cfg' self.rooms = {} self.zones = {} self.zonelist = {} self.roomlist = [] self.roomcapa = [] self.room_neighbours = []
def loadMeetings(self, mfile): """Load meeting requests from MEETINGS_CONFIG""" self.MEETINGS_CONFIG = mfile logging.info("Loading meeting requests from %s" % self.MEETINGS_CONFIG) try: meetings = ConfigObj(self.MEETINGS_CONFIG, file_error=True) #TODO: any validation required? Eg. Faulty datetime (end time earlier than start time etc), non-exists room, same people at same meeting time etc... self.meetings = meetings except (ConfigObjError, IOError), e: logging.error('%s' % (e)) return EAMS_Error().eams_config_meeting_err()
class OutdoorTemperature: def __init__(self): self.err = EAMS_Error() self.OUTDOOR_TEMP_DATA = None self.temperature = {} def loadOutdoorTemperature(self, tfile): """Load outdoor temperature from OUTDOOR_TEMP_DATA""" logging.info("Loading outdoor temperature data from %s" %tfile) try: df = open(tfile, 'r') data = ''.join(df.readlines()) df.close() self._parseOutdoorTemperature(data) except (IOError), e: logging.error('%s' % (e)) return self.err.eams_config_otc_err() return 0
def init_room_temperature(self): solver = Solver_MILP(self.SCHE_MASTER, self.EAMS, self.GUROBI_LOGFILE, 0, [[], [], []], [], None, self.CASECFG, 0, -1, 0) ret = solver.solve() if ret == EAMS_Error().eams_infeasible(): if self.OSG_LOG_RESULT: self.logCaseEnergy(0, '*') print "initial model infeasible" else: if self.OSG_LOG_RESULT: self.SCHE_MASTER.calcEnergyConsumption( self.EAMS.SCHEDULING_INTERVAL) self.logCaseEnergy( 0, str(round(np.sum(self.SCHE_MASTER.MSTR_power), 2)), str(round(np.sum(self.SCHE_MASTER.MSTR_energy_kWh), 2)), 0, 0) logging.info("MSTR_CAV_T_LK: %s" % self.SCHE_MASTER.MSTR_CAV_T_LK) logging.info("MSTR_CDV_T_SA_LK: %s" % self.SCHE_MASTER.MSTR_CDV_T_SA_LK) logging.info("MSTR_CDV_A_SA_LK: %s" % self.SCHE_MASTER.MSTR_CDV_A_SA_LK)
def __init__(self): self.err = EAMS_Error() self.half_hourly = 30 self.hourly = 60 self.OUTDOOR_TEMP_DATA = None self.temperature = {}
class RoomConfig: def __init__(self): """Initialization""" self.err = EAMS_Error() self.rooms = {} self.zones = {} self.zonelist = {} self.roomlist = [] self.roomcapa = [] self.room_neighbours = [] def _getRoomAdjacentWalls(self, room): """Get adjacent room of a given room's ID""" aw = [] aw.append(room['Wall1']['AdjRoom']) aw.append(room['Wall2']['AdjRoom']) aw.append(room['Wall3']['AdjRoom']) aw.append(room['Wall4']['AdjRoom']) return aw def _validateAdjacentWallConfig(self, rooms): """Validate consistency of adjacent wall(s) configurations in ROOM_CONFIG """ logging.info("Validating adjacent walls configuration...") awls = {} for k, v in rooms.iteritems(): awls[k] = self._getRoomAdjacentWalls(v) logging.debug("Room [%s]'s adjacent rooms [%s]" % (k, ','.join(awls[k]))) logging.debug("Rooms' adjacent wall's: %s" % awls) for k, v in awls.iteritems(): nls = v # get awls{'k'} neighbors # Check duplicate adjacent wall dls = collections.Counter(nls) if len([j for j in dls if j != 'Outdoor' and dls[j] > 1]) != 0: logging.error( "Duplicate adjacent wall for the room[%s]: %s. HALT." % (k, dls)) return self.err.eams_config_room_duplicate_wall_err() # Check if neighbor rooms has also set room{'k'}'s wall as adjacent wall. for j in range(len(nls)): nnls = awls.get(nls[j]) if nnls is not None and k not in nnls: logging.error("[%s] is not adjacent to [%s]. HALT." % (k, nls[j])) return self.err.eams_config_room_invalid_wall_err() logging.info("Adjacent wall configurations, result: True.") return 0 def loadRoomConfig(self, rfile): """Load room configuration from ROOM_CONFIG""" self.ROOM_CONFIG = rfile logging.info("Loading room configuration from %s" % self.ROOM_CONFIG) ret = 0 try: if self.ROOM_CONFIG == "": raise IOError("ROOM_CONFIG is not configured. Error.") rooms = ConfigObj(self.ROOM_CONFIG, file_error=True) logging.debug("Room properties: %s" % rooms) logging.debug("Total number of room: %d [%s]" % (len(rooms), ', '.join(rooms.keys()))) ret = self._validateAdjacentWallConfig(rooms) if ret < 0: raise ValidateError() self.rooms = rooms except (ConfigObjError, IOError), e: logging.critical('%s' % (e)) ret = self.err.eams_config_room_err() except (ValidateError), e: logging.critical("%s validation error. %d" % (self.ROOM_CONFIG, ret))
class RoomConfig: def __init__(self, rl, rh, cl, ch, sl, sm, sh): """Initialization""" self.err = EAMS_Error() self.ROOM_CONFIG = None self.WALL_RESISTANCE_LOW = rl self.WALL_RESISTANCE_HIGH = rh self.WALL_CAPACITANCE_LOW = cl self.WALL_CAPACITANCE_HIGH = ch self.SOLAR_GAIN_LOW = sl self.SOLAR_GAIN_MEDIUM = sm self.SOLAR_GAIN_HIGH = sh # self.ROOM_CONFIG_SPEC = 'Data/eams_room_spec.cfg' self.ROOM_CONFIG_SPEC = 'Data/ConfigSpecs/eams_room_spec.cfg' self.rooms = {} self.zones = {} self.zonelist = {} self.roomlist = [] self.roomcapa = [] self.room_neighbours = [] def _getRoomAdjacentWalls(self, room): """Get adjacent room of a given room's ID""" aw = [] aw.append(room['Wall1']['AdjRoom']) aw.append(room['Wall2']['AdjRoom']) aw.append(room['Wall3']['AdjRoom']) aw.append(room['Wall4']['AdjRoom']) return aw def _validateAdjacentWallConfig(self, rooms): """Validate consistency of adjacent wall(s) configurations in ROOM_CONFIG """ logging.info("Validating adjacent walls configuration...") awls = {} for k, v in rooms.iteritems(): awls[k] = self._getRoomAdjacentWalls(v) logging.debug("Room [%s]'s adjacent rooms [%s]" % (k, ','.join(awls[k]))) logging.debug("Rooms' adjacent wall's: %s" % awls) for k, v in awls.iteritems(): #range(len(awls)): #k = awls.keys()[i] # In room awls{'k'} nls = v #awls.get(k) # get awls{'k'} neighbors # Check duplicate adjacent wall dls = collections.Counter(nls) if len([j for j in dls if j != 'Outdoor' and dls[j] > 1]) != 0: logging.error( "Duplicate adjacent wall for the room[%s]: %s. HALT." % (k, dls)) return self.err.eams_config_room_duplicate_wall_err() # Check if neighbor rooms has also set room{'k'}'s wall as adjacent wall. for j in range(len(nls)): nnls = awls.get( nls[j]) # get awls{'k'} neighbors[j]'s neighbors # logging.debug("neighbor of %s: [%s]" %(nls[j], nnls)) # (nnls is None) : Some adjacent room has no configuration in ROOM_CONFIG. It's OK to ignore. if nnls is not None and k not in nnls: logging.error("[%s] is not adjacent to [%s]. HALT." % (k, nls[j])) return self.err.eams_config_room_invalid_wall_err() logging.info("Adjacent wall configurations, result: True.") return 0 def _validateRoomConfig(self, rooms): """Validate ROOM_CONFIG input value based on specification in ROOM_CONFIG_SPEC""" validator = Validator() results = rooms.validate(validator) logging.info("Validating room configuration, result: %s" % results) if results != True: for (section_list, key, _) in flatten_errors(rooms, results): if key is not None: logging.error( 'The "%s" key in the section "%s" failed validation' % (key, ', '.join(section_list))) else: logging.error( "Configuration error in %s. Either some section was missing, duplicate key(s) etc..." % self.ROOM_CONFIG) return self.err.eams_config_room_err() return 0 def loadRoomConfig(self, rfile): """Load room configuration from ROOM_CONFIG""" self.ROOM_CONFIG = rfile logging.info("Loading room configuration from %s" % self.ROOM_CONFIG) ret = 0 try: if self.ROOM_CONFIG == "": raise IOError("ROOM_CONFIG is not configured. Error.") rooms = ConfigObj(self.ROOM_CONFIG, configspec=self.ROOM_CONFIG_SPEC, file_error=True) for _, v in rooms.iteritems(): for sk, sv in v.iteritems(): if sk == 'Wall1' or sk == 'Wall2' or sk == 'Wall3' or sk == 'Wall4' or sk == 'Ceiling' or sk == 'Floor': for wk, wv in sv.iteritems(): if (wk == 'R1' or wk == 'R2' or wk == 'R3' or wk == 'RW') and (wv == 'LR'): sv[wk] = self.WALL_RESISTANCE_LOW if (wk == 'R1' or wk == 'R2' or wk == 'R3' or wk == 'RW') and (wv == 'HR'): sv[wk] = self.WALL_RESISTANCE_HIGH if (wk == 'C1' or wk == 'C2') and (wv == 'LC'): sv[wk] = self.WALL_CAPACITANCE_LOW if (wk == 'C1' or wk == 'C2') and (wv == 'HC'): sv[wk] = self.WALL_CAPACITANCE_HIGH if (wk == 'QS_AM' or wk == 'QS_NOON' or wk == 'QS_PM') and (wv == 'HG'): sv[wk] = self.SOLAR_GAIN_HIGH if (wk == 'QS_AM' or wk == 'QS_NOON' or wk == 'QS_PM') and (wv == 'MG'): sv[wk] = self.SOLAR_GAIN_MEDIUM if (wk == 'QS_AM' or wk == 'QS_NOON' or wk == 'QS_PM') and (wv == 'LG'): sv[wk] = self.SOLAR_GAIN_LOW elif sk == 'CR': if sv == 'LC': v[sk] = self.WALL_CAPACITANCE_LOW elif sv == 'HC': v[sk] = self.WALL_CAPACITANCE_HIGH logging.debug("Room properties: %s" % rooms) logging.debug("Total number of room: %d [%s]" % (len(rooms), ', '.join(rooms.keys()))) ret = self._validateRoomConfig(rooms) if ret < 0: raise ValidateError() ret = self._validateAdjacentWallConfig(rooms) if ret < 0: raise ValidateError() self.rooms = rooms except (ConfigObjError, IOError), e: logging.critical('%s' % (e)) ret = self.err.eams_config_room_err() except (ValidateError), e: logging.critical("%s validation error. %d" % (self.ROOM_CONFIG, ret))
def run(self): is_infea = 0 logging.info( "\n\n\n===============================================================" ) logging.info("Online Scheduling Start...") logging.info( "===============================================================") case_start_time = datetime.now() self._initialize() # Initialize room temperature (assume no meeting) self.ck = '_init' self.init_room_temperature() # Start scheduling while True: # get a list of recently arrived meetings CURR_M = self._MEETING_GEN.get_meetings( self.CURRENT_SCHEDULING_CLOCK) if CURR_M == None: if not self._continue_schedule(): break else: continue else: logging.info( "======================================================") logging.info("Scheduling for %s " % (self.CURRENT_SCHEDULING_CLOCK)) logging.info( "======================================================") start_time = datetime.now() delta = self._MEETING_GEN._roundUpNearestInterval( self.CURRENT_SCHEDULING_CLOCK.minute, self.EAMS. SCHEDULING_INTERVAL) - self.CURRENT_SCHEDULING_CLOCK.minute curr_timeslot = self.CURRENT_SCHEDULING_CLOCK + timedelta( minutes=delta) curr_k = self.EAMS.TSC.getTimeSlotIdxByDatetime(curr_timeslot) logging.info("curr k time: %s [%d]" % (curr_timeslot, curr_k)) self.ck = curr_k logging.info("CURR_M: %s" % CURR_M) [CURR_MTYPE_ID, CURR_MTYPE, CURR_MTYPE_MID] = self._get_mtype(CURR_M) logging.info("CURR_MTYPE_ID: %s" % CURR_MTYPE_ID) logging.info("CURR_MTYPE: %s" % CURR_MTYPE) logging.info("CURR_MTYPE_MID: %s" % CURR_MTYPE_MID) [CURR_CMT, CURR_UNIQ_CMT] = self._get_cmt(CURR_MTYPE_ID, CURR_MTYPE) logging.info("CURR_CMT: %s" % CURR_CMT) logging.info("CURR_UNIQ_CMT: %s" % CURR_UNIQ_CMT) CURR_OCCUPIED_K = self._get_occupied_K_by_conflict_meetings( CURR_CMT, CURR_MTYPE_ID) solver = Solver_LNS( self.SCHE_MASTER, self.EAMS, self.GUROBI_LOGFILE, self.LNS_TIME_LIMIT, self.MIP_TIME_LIMIT, curr_k, [CURR_MTYPE_ID, CURR_MTYPE, CURR_MTYPE_MID], CURR_UNIQ_CMT, CURR_OCCUPIED_K, self.CASECFG, self.LNS_SEED, self.DYNBOUND_MODE, self.DYNBOUND_FIXED_SLACK, self.DYNBOUND_DELTA, self.DYNBOUND_PROBGUAR) ret = solver.run() run_time = ((datetime.now() - start_time).total_seconds()) logging.info("Current round takes %d s" % (run_time)) if ret == EAMS_Error().eams_infeasible(): is_infea = 1 if self.OSG_LOG_RESULT: self.logCaseEnergy(curr_k, '*', '*', '*', '*') break else: if self.OSG_LOG_RESULT: self.logAlloc(0) self.SCHE_MASTER.calcEnergyConsumption( self.EAMS.SCHEDULING_INTERVAL) self.SCHE_MASTER.calcThermalComfortViolation( float(self.EAMS.TEMPERATURE_UNOCC_MIN) + float( self.EAMS.TEMPERATURE_OCC_COMFORT_RANGE_INCR), float(self.EAMS.TEMPERATURE_UNOCC_MAX) - float( self.EAMS.TEMPERATURE_OCC_COMFORT_RANGE_DECR)) self.logCaseEnergy( curr_k, str(round(np.sum(self.SCHE_MASTER.MSTR_power), 2)), str( round(np.sum(self.SCHE_MASTER.MSTR_energy_kWh), 2)), str( round( self.SCHE_MASTER. MSTR_max_comfort_violation, 2)), str( round(self.SCHE_MASTER.MSTR_comfort_violation, 2))) self.SCHE_MASTER.diagnose() if not self._continue_schedule(): break case_run_time = ((datetime.now() - case_start_time).total_seconds()) logging.info("Total run takes %d s" % (case_run_time)) if is_infea: if self.DYNBOUND_MODE is not 'DEF': self.logResults(self.CASECFG, '*', '*', '*', '*', case_run_time, self.DYNBOUND_FIXED_SLACK, self.DYNBOUND_DELTA, self.DYNBOUND_PROBGUAR) else: self.logResults(self.CASECFG, '*', '*', '*', '*', case_run_time) if self.OSG_LOG_WARMSTART: self._log_for_warmstart(0) self._log_infea_currk(self.CASECFG, curr_k) if self.OSG_LOG_TEMPERATURE: self._log_temperature(0) else: self.logAlloc(0) # To write to separate file, set to logAlloc(1) self.SCHE_MASTER.calcEnergyConsumption( self.EAMS.SCHEDULING_INTERVAL) self.SCHE_MASTER.calcThermalComfortViolation( float(self.EAMS.TEMPERATURE_UNOCC_MIN) + float(self.EAMS.TEMPERATURE_OCC_COMFORT_RANGE_INCR), float(self.EAMS.TEMPERATURE_UNOCC_MAX) - float(self.EAMS.TEMPERATURE_OCC_COMFORT_RANGE_DECR)) if self.DYNBOUND_MODE is not 'DEF': self.logResults( self.CASECFG, str(round(np.sum(self.SCHE_MASTER.MSTR_power), 2)), str(round(np.sum(self.SCHE_MASTER.MSTR_energy_kWh), 2)), str(round(self.SCHE_MASTER.MSTR_max_comfort_violation, 2)), str(round(self.SCHE_MASTER.MSTR_comfort_violation, 2)), case_run_time, self.DYNBOUND_FIXED_SLACK, self.DYNBOUND_DELTA, self.DYNBOUND_PROBGUAR) else: self.logResults( self.CASECFG, str(round(np.sum(self.SCHE_MASTER.MSTR_power), 2)), str(round(np.sum(self.SCHE_MASTER.MSTR_energy_kWh), 2)), str(round(self.SCHE_MASTER.MSTR_max_comfort_violation, 2)), str(round(self.SCHE_MASTER.MSTR_comfort_violation, 2)), case_run_time) self.SCHE_MASTER.diagnose() if self.OSG_LOG_WARMSTART: self._log_for_warmstart(1) self._log_infea_currk(self.CASECFG, '*') if self.OSG_LOG_TEMPERATURE: self._log_temperature()
def __init__(self, enableLog): self.err = EAMS_Error() self.PROBLEM_CONFIG_SPEC = 'Data/ConfigSpecs/eams_prob_spec.cfg' if enableLog: # # activate log self.logger = logging.getLogger() self.logger.setLevel(logging.INFO) # self.logger.setLevel(logging.DEBUG) self.Z = None #======================================================================= # Zone -> Room. Eg: {'1': {'Room1': {'ZoneID': '1', 'Width': 10.0, 'Length': 6.0 ... #======================================================================= self.ZL = None #====================================================================== # Zone -> Room Name. Eg: {'1': ['Room1'], '3': ['Room3'], '2': ['Room2']} #====================================================================== self.RL = None #======================================================================= # Room list. Eg: ['Room1', 'Room3', 'Room2'] #======================================================================= self.TS = None #======================================================================= # Idx -> datetime. Eg: {0: datetime.datetime(2013, 1, 1, 8, 0), 1: datetime.datetime(2013, 1, 1, 8, 30), 2: datetime.datetime(2013, 1, 1, 9, 0), 3: datetime.datetime(2013, 1, 1, 9, 30), 4: datetime.datetime(2013, 1, 1, 10, 0), #======================================================================= self.ML = None #======================================================================= # List of namedtuple('Meeting_Desc', 'Key TimeWindows Duration Room Attendees') # [Meeting_Desc(Key='M110133', TimeWindows=[[datetime.datetime(2013, 1, 1, 9, 0), datetime.datetime(2013, 1, 1, 10, 30)], [datetime.datetime(2013, 1, 1, 12, 0), datetime.datetime(2013, 1, 1, 14, 0)], [datetime.datetime(2013, 1, 2, 14, 0), datetime.datetime(2013, 1, 2, 16, 0)]], Duration='3', Room='', Attendees=['1119', '2578', '3470', '4601', '6823', '7105', '7908', '12736', '12996', '20479']), Meeting_Desc(Key='M316335', TimeWindows=[[datetime.datetime(2013, 1, 1, 9, 0), datetime.datetime(2013, 1, 1, 18, 0)]], Duration='7', Room='', Attendees=['219', '246', '2852', '3304', '4095', '6845', '8495', '8811', '8927', '15695']), Meeting_Desc(Key='M325401', TimeWindows=[[datetime.datetime(2013, 1, 1, 9, 0), datetime.datetime(2013, 1, 1, 18, 0)]], Duration='7', Room='', Attendees=['264', '2165', '2528', '2890', '3167', '4273', '5258', '5363', '10719', '20204']), Meeting_Desc(Key='M433676', TimeWindows=[[datetime.datetime(2013, 1, 1, 9, 0), datetime.datetime(2013, 1, 1, 18, 0)]], Duration='7', Room='', Attendees=['413', '1104', '2192', '2674', '3201', '6866', '13958', '13998', '14601', '14607'])] #======================================================================= self.CALS = {} #======================================================================= # List of Conflicting Meetings follow the sequence of self.ML # eg. For ML[1] is conflict with ML[2] because of attendee['6153', '2425', '895'] # 0 : {} # 1 : {2: ['6153', '2425', '895'], 3: ['6153']} # 2 : {1: ['6153', '2425', '895'], 3: ['1068', '6153']} # 3 : {1: ['6153'], 2: ['1068', '6153']} #======================================================================= self.MTYPE = [] self.mtdesc = namedtuple('Meeting_Type', 'MTW MA MD MCA MLS') #======================================================================= # List of Meeting Clique # Meeting_Type(MTW=(66, 81, 162, 177), MA=15, MD=None, MCA=['6153', '2425', '895'], MLS=[1]) # Meeting_Type(MTW=(66, 81, 162, 177), MA=15, MD=None, MCA=['6153', '2425', '895', '1068'], MLS=[2]) # Meeting_Type(MTW=(66, 81, 162, 177), MA=15, MD=None, MCA=['6153', '1068'], MLS=[3]) # Meeting_Type(MTW=(66, 81, 162, 177), MA=15, MD=None, MCA=[], MLS=[4, 9]) # Meeting_Type(MTW=(66, 81), MA=15, MD=None, MCA=[], MLS=[6, 8]) # Meeting_Type(MTW=(162, 177), MA=15, MD=None, MCA=[], MLS=[0, 5, 7]) #======================================================================= self.CMT = {} #======================================================================= # List of Conflicting Meeting Type because of an attendee # Key: Attendee ID, Value: Follow offset of Meeting Type in self.MTYPE # {'1068': [1, 2], '6153': [0, 1, 2], '2425': [0, 1], '895': [0, 1]} #======================================================================= self.OAT = None #======================================================================= # Sorted outdoor temperature. Eg: OrderedDict([(datetime.datetime(2013, 1, 1, 8, 0), '26.00'), (datetime.datetime(2013, 1, 1, 8, 30), '26.00'), (datetime.datetime(2013, 1, 1, 9, 0), '28.00') #======================================================================= self.SH = None #======================================================================= # A list follow the sequence of TS #======================================================================= self.MTW = None #======================================================================= # A Double array follow the sequence of self.ML # [ # [[18, 21], [24, 28], [76, 80]], <- array of time windows [Start_Time, End_Time] # [[18, 36]], # [[18, 36]] # ] #======================================================================= self.MR = None #======================================================================= # A Double array follow the sequence of self.ML # #======================================================================= self.MOM = None #======================================================================= # A Double array follow the sequence of self.ML with list of meetings which has similar attendee(s) # [ # [1, 2], # [2], # [] # ] #======================================================================= self.MODE_CONFIG = "" self.STANDBY_MODE = "" self.MEETINGS_CONFIG_DATA = "" self.OUTDOOR_TEMP_DATA = "" self.ROOM_CONFIG_DATA = "" self.SCHEDULING_START_DATETIME = "" self.SCHEDULING_END_DATETIME = "" self.SCHEDULING_INTERVAL = -1 self.DAILY_WORKING_HOUR_START = "" self.DAILY_WORKING_HOUR_END = "" self.HVAC_NON_PEAK_OFF = -1 self.HVAC_SHUT_DOWN = "" self.HVAC_TURN_ON = "" self.SOLAR_GAIN_LOW = -1 self.SOLAR_GAIN_MEDIUM = -1 self.SOLAR_GAIN_HIGH = -1 self.SOLAR_RADIATION_AM_START = "" self.SOLAR_RADIATION_NOON_START = "" self.SOLAR_RADIATION_PM_START = "" self.SOLAR_RADIATION_NIGHT_START = "" self.WALL_RESISTANCE_LOW = -1 self.WALL_RESISTANCE_HIGH = -1 self.WALL_CAPACITANCE_LOW = -1 self.WALL_CAPACITANCE_HIGH = -1 self.INITIAL_TEMPERATURE_MODE = -1 self.INITIAL_TEMPERATURE = -1 self.TEMPERATURE_UNOCC_MIN = -1 self.TEMPERATURE_UNOCC_RANGE_INCR = -1 self.TEMPERATURE_OCC_COMFORT_RANGE_INCR = -1 self.TEMPERATURE_UNOCC_MAX = -1 self.TEMPERATURE_OCC_COMFORT_RANGE_DECR = -1 self.TEMPERATURE_CONDITIONED_AIR = -1 self.TEMPERATURE_SUPPLY_AIR_HIGH = -1 self.ALPHA_IAQ_FACTOR_OF_SAFETY = -1 self.BETA_FAN_POWER_CONSTANT = -1 self.AIR_HEAT_CAPACITY_AT_CONSTANT_PRESSURE = -1 self.INITIAL_TEMPERATURE_SUPPLY_AIR_OCC = -1 self.INITIAL_TEMPERATURE_SUPPLY_AIR_UNOCC = -1 self.INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_OCC = -1 self.INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_UNOCC = -1 self.MASS_AIR_FLOW_SUPPLY_AIR_MIN = -1 self.MASS_AIR_FLOW_SUPPLY_AIR_MAX = -1 self.MASS_AIR_FLOW_SUPPLY_AIR_PER_PERSON = -1 self.MASS_AIR_FLOW_OUTSIDE_AIR_PER_PERSON = -1 self.MASS_AIR_FLOW_OUTSIDE_AIR_PER_METER_SQUARE = -1 self.MASS_AIR_FLOW_RETURN_AIR_RATIO = -1 self.OCCUPANT_SENSIBLE_HEAT_GAIN = -1 self.OCCUPANT_WATER_VAPOR_RATE = -1 self.PLOT_INTERVAL = -1 self.PLOT_STEP = -1 self.ZOOMPLOT_START_DATETIME = "" self.ZOOMPLOT_END_DATETIME = "" self.ZOOMPLOT_INTERVAL = -1 self.ZOOMPLOT_STEP = -1
class EAMS(): def __init__(self, enableLog): self.err = EAMS_Error() self.PROBLEM_CONFIG_SPEC = 'Data/ConfigSpecs/eams_prob_spec.cfg' if enableLog: # # activate log self.logger = logging.getLogger() self.logger.setLevel(logging.INFO) # self.logger.setLevel(logging.DEBUG) self.Z = None #======================================================================= # Zone -> Room. Eg: {'1': {'Room1': {'ZoneID': '1', 'Width': 10.0, 'Length': 6.0 ... #======================================================================= self.ZL = None #====================================================================== # Zone -> Room Name. Eg: {'1': ['Room1'], '3': ['Room3'], '2': ['Room2']} #====================================================================== self.RL = None #======================================================================= # Room list. Eg: ['Room1', 'Room3', 'Room2'] #======================================================================= self.TS = None #======================================================================= # Idx -> datetime. Eg: {0: datetime.datetime(2013, 1, 1, 8, 0), 1: datetime.datetime(2013, 1, 1, 8, 30), 2: datetime.datetime(2013, 1, 1, 9, 0), 3: datetime.datetime(2013, 1, 1, 9, 30), 4: datetime.datetime(2013, 1, 1, 10, 0), #======================================================================= self.ML = None #======================================================================= # List of namedtuple('Meeting_Desc', 'Key TimeWindows Duration Room Attendees') # [Meeting_Desc(Key='M110133', TimeWindows=[[datetime.datetime(2013, 1, 1, 9, 0), datetime.datetime(2013, 1, 1, 10, 30)], [datetime.datetime(2013, 1, 1, 12, 0), datetime.datetime(2013, 1, 1, 14, 0)], [datetime.datetime(2013, 1, 2, 14, 0), datetime.datetime(2013, 1, 2, 16, 0)]], Duration='3', Room='', Attendees=['1119', '2578', '3470', '4601', '6823', '7105', '7908', '12736', '12996', '20479']), Meeting_Desc(Key='M316335', TimeWindows=[[datetime.datetime(2013, 1, 1, 9, 0), datetime.datetime(2013, 1, 1, 18, 0)]], Duration='7', Room='', Attendees=['219', '246', '2852', '3304', '4095', '6845', '8495', '8811', '8927', '15695']), Meeting_Desc(Key='M325401', TimeWindows=[[datetime.datetime(2013, 1, 1, 9, 0), datetime.datetime(2013, 1, 1, 18, 0)]], Duration='7', Room='', Attendees=['264', '2165', '2528', '2890', '3167', '4273', '5258', '5363', '10719', '20204']), Meeting_Desc(Key='M433676', TimeWindows=[[datetime.datetime(2013, 1, 1, 9, 0), datetime.datetime(2013, 1, 1, 18, 0)]], Duration='7', Room='', Attendees=['413', '1104', '2192', '2674', '3201', '6866', '13958', '13998', '14601', '14607'])] #======================================================================= self.CALS = {} #======================================================================= # List of Conflicting Meetings follow the sequence of self.ML # eg. For ML[1] is conflict with ML[2] because of attendee['6153', '2425', '895'] # 0 : {} # 1 : {2: ['6153', '2425', '895'], 3: ['6153']} # 2 : {1: ['6153', '2425', '895'], 3: ['1068', '6153']} # 3 : {1: ['6153'], 2: ['1068', '6153']} #======================================================================= self.MTYPE = [] self.mtdesc = namedtuple('Meeting_Type', 'MTW MA MD MCA MLS') #======================================================================= # List of Meeting Clique # Meeting_Type(MTW=(66, 81, 162, 177), MA=15, MD=None, MCA=['6153', '2425', '895'], MLS=[1]) # Meeting_Type(MTW=(66, 81, 162, 177), MA=15, MD=None, MCA=['6153', '2425', '895', '1068'], MLS=[2]) # Meeting_Type(MTW=(66, 81, 162, 177), MA=15, MD=None, MCA=['6153', '1068'], MLS=[3]) # Meeting_Type(MTW=(66, 81, 162, 177), MA=15, MD=None, MCA=[], MLS=[4, 9]) # Meeting_Type(MTW=(66, 81), MA=15, MD=None, MCA=[], MLS=[6, 8]) # Meeting_Type(MTW=(162, 177), MA=15, MD=None, MCA=[], MLS=[0, 5, 7]) #======================================================================= self.CMT = {} #======================================================================= # List of Conflicting Meeting Type because of an attendee # Key: Attendee ID, Value: Follow offset of Meeting Type in self.MTYPE # {'1068': [1, 2], '6153': [0, 1, 2], '2425': [0, 1], '895': [0, 1]} #======================================================================= self.OAT = None #======================================================================= # Sorted outdoor temperature. Eg: OrderedDict([(datetime.datetime(2013, 1, 1, 8, 0), '26.00'), (datetime.datetime(2013, 1, 1, 8, 30), '26.00'), (datetime.datetime(2013, 1, 1, 9, 0), '28.00') #======================================================================= self.SH = None #======================================================================= # A list follow the sequence of TS #======================================================================= self.MTW = None #======================================================================= # A Double array follow the sequence of self.ML # [ # [[18, 21], [24, 28], [76, 80]], <- array of time windows [Start_Time, End_Time] # [[18, 36]], # [[18, 36]] # ] #======================================================================= self.MR = None #======================================================================= # A Double array follow the sequence of self.ML # #======================================================================= self.MOM = None #======================================================================= # A Double array follow the sequence of self.ML with list of meetings which has similar attendee(s) # [ # [1, 2], # [2], # [] # ] #======================================================================= self.MODE_CONFIG = "" self.STANDBY_MODE = "" self.MEETINGS_CONFIG_DATA = "" self.OUTDOOR_TEMP_DATA = "" self.ROOM_CONFIG_DATA = "" self.SCHEDULING_START_DATETIME = "" self.SCHEDULING_END_DATETIME = "" self.SCHEDULING_INTERVAL = -1 self.DAILY_WORKING_HOUR_START = "" self.DAILY_WORKING_HOUR_END = "" self.HVAC_NON_PEAK_OFF = -1 self.HVAC_SHUT_DOWN = "" self.HVAC_TURN_ON = "" self.SOLAR_GAIN_LOW = -1 self.SOLAR_GAIN_MEDIUM = -1 self.SOLAR_GAIN_HIGH = -1 self.SOLAR_RADIATION_AM_START = "" self.SOLAR_RADIATION_NOON_START = "" self.SOLAR_RADIATION_PM_START = "" self.SOLAR_RADIATION_NIGHT_START = "" self.WALL_RESISTANCE_LOW = -1 self.WALL_RESISTANCE_HIGH = -1 self.WALL_CAPACITANCE_LOW = -1 self.WALL_CAPACITANCE_HIGH = -1 self.INITIAL_TEMPERATURE_MODE = -1 self.INITIAL_TEMPERATURE = -1 self.TEMPERATURE_UNOCC_MIN = -1 self.TEMPERATURE_UNOCC_RANGE_INCR = -1 self.TEMPERATURE_OCC_COMFORT_RANGE_INCR = -1 self.TEMPERATURE_UNOCC_MAX = -1 self.TEMPERATURE_OCC_COMFORT_RANGE_DECR = -1 self.TEMPERATURE_CONDITIONED_AIR = -1 self.TEMPERATURE_SUPPLY_AIR_HIGH = -1 self.ALPHA_IAQ_FACTOR_OF_SAFETY = -1 self.BETA_FAN_POWER_CONSTANT = -1 self.AIR_HEAT_CAPACITY_AT_CONSTANT_PRESSURE = -1 self.INITIAL_TEMPERATURE_SUPPLY_AIR_OCC = -1 self.INITIAL_TEMPERATURE_SUPPLY_AIR_UNOCC = -1 self.INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_OCC = -1 self.INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_UNOCC = -1 self.MASS_AIR_FLOW_SUPPLY_AIR_MIN = -1 self.MASS_AIR_FLOW_SUPPLY_AIR_MAX = -1 self.MASS_AIR_FLOW_SUPPLY_AIR_PER_PERSON = -1 self.MASS_AIR_FLOW_OUTSIDE_AIR_PER_PERSON = -1 self.MASS_AIR_FLOW_OUTSIDE_AIR_PER_METER_SQUARE = -1 self.MASS_AIR_FLOW_RETURN_AIR_RATIO = -1 self.OCCUPANT_SENSIBLE_HEAT_GAIN = -1 self.OCCUPANT_WATER_VAPOR_RATE = -1 self.PLOT_INTERVAL = -1 self.PLOT_STEP = -1 self.ZOOMPLOT_START_DATETIME = "" self.ZOOMPLOT_END_DATETIME = "" self.ZOOMPLOT_INTERVAL = -1 self.ZOOMPLOT_STEP = -1 def activateLogFile(self, f): # remove old handler for old_handler in self.logger.handlers: self.logger.removeHandler(old_handler) # create a handler with the name defined by the variable f handler = logging.FileHandler(f) # add that handler to the logger self.logger.addHandler(handler) def _critical_err(self): sys.exit("Pop, Bang, Whooo, Boom... Fire Alarm! Evacuate! EAMS exit.") def _validateProblemConfig(self, config): validator = Validator() results = config.validate(validator) logging.info("Validating problem configuration, result: %s" % results) if results != True: for (_, key, _) in flatten_errors(config, results): if key is not None: logging.error('The "%s" key failed validation' % (key)) else: logging.error( "Configuration error. Either some section was missing, duplicate key(s) etc..." ) return self.err.eams_config_problem_err() return 0 def _loadProblemConfig(self, config): #TODO: should cast these variables according to their type here, so you need not cast them later on! self.MODE_CONFIG = config['MODE_CONFIG'] self.STANDBY_MODE = config['STANDBY_MODE'] self.MEETINGS_CONFIG_DATA = config['MEETINGS_CONFIG_DATA'] self.OUTDOOR_TEMP_DATA = config['OUTDOOR_TEMP_DATA'] self.ROOM_CONFIG_DATA = config['ROOM_CONFIG_DATA'] self.SCHEDULING_START_DATETIME = config['SCHEDULING_START_DATETIME'] self.SCHEDULING_END_DATETIME = config['SCHEDULING_END_DATETIME'] self.SCHEDULING_INTERVAL = int(config['SCHEDULING_INTERVAL']) self.DAILY_WORKING_HOUR_START = config['DAILY_WORKING_HOUR_START'] self.DAILY_WORKING_HOUR_END = config['DAILY_WORKING_HOUR_END'] self.HVAC_NON_PEAK_OFF = config['HVAC_NON_PEAK_OFF'] self.HVAC_SHUT_DOWN = config['HVAC_SHUT_DOWN'] self.HVAC_TURN_ON = config['HVAC_TURN_ON'] self.SOLAR_GAIN_LOW = config['SOLAR_GAIN_LOW'] self.SOLAR_GAIN_MEDIUM = config['SOLAR_GAIN_MEDIUM'] self.SOLAR_GAIN_HIGH = config['SOLAR_GAIN_HIGH'] self.SOLAR_RADIATION_AM_START = config['SOLAR_RADIATION_AM_START'] self.SOLAR_RADIATION_NOON_START = config['SOLAR_RADIATION_NOON_START'] self.SOLAR_RADIATION_PM_START = config['SOLAR_RADIATION_PM_START'] self.SOLAR_RADIATION_NIGHT_START = config[ 'SOLAR_RADIATION_NIGHT_START'] self.WALL_RESISTANCE_LOW = config['WALL_RESISTANCE_LOW'] self.WALL_RESISTANCE_HIGH = config['WALL_RESISTANCE_HIGH'] self.WALL_CAPACITANCE_LOW = config['WALL_CAPACITANCE_LOW'] self.WALL_CAPACITANCE_HIGH = config['WALL_CAPACITANCE_HIGH'] self.INITIAL_TEMPERATURE_MODE = config['INITIAL_TEMPERATURE_MODE'] self.INITIAL_TEMPERATURE = config['INITIAL_TEMPERATURE'] self.TEMPERATURE_UNOCC_MIN = float(config['TEMPERATURE_UNOCC_MIN']) self.TEMPERATURE_UNOCC_RANGE_INCR = float( config['TEMPERATURE_UNOCC_RANGE_INCR']) self.TEMPERATURE_OCC_COMFORT_RANGE_INCR = float( config['TEMPERATURE_OCC_COMFORT_RANGE_INCR']) self.TEMPERATURE_UNOCC_MAX = float(config['TEMPERATURE_UNOCC_MAX']) self.TEMPERATURE_OCC_COMFORT_RANGE_DECR = float( config['TEMPERATURE_OCC_COMFORT_RANGE_DECR']) self.TEMPERATURE_CONDITIONED_AIR = float( config['TEMPERATURE_CONDITIONED_AIR']) self.TEMPERATURE_SUPPLY_AIR_HIGH = float( config['TEMPERATURE_SUPPLY_AIR_HIGH']) self.ALPHA_IAQ_FACTOR_OF_SAFETY = config['ALPHA_IAQ_FACTOR_OF_SAFETY'] self.BETA_FAN_POWER_CONSTANT = config['BETA_FAN_POWER_CONSTANT'] self.AIR_HEAT_CAPACITY_AT_CONSTANT_PRESSURE = float( config['AIR_HEAT_CAPACITY_AT_CONSTANT_PRESSURE']) self.INITIAL_TEMPERATURE_SUPPLY_AIR_OCC = float( config['INITIAL_TEMPERATURE_SUPPLY_AIR_OCC']) self.INITIAL_TEMPERATURE_SUPPLY_AIR_UNOCC = float( config['INITIAL_TEMPERATURE_SUPPLY_AIR_UNOCC']) self.INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_OCC = float( config['INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_OCC']) self.INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_UNOCC = float( config['INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_UNOCC']) self.MASS_AIR_FLOW_SUPPLY_AIR_MIN = float( config['MASS_AIR_FLOW_SUPPLY_AIR_MIN']) self.MASS_AIR_FLOW_SUPPLY_AIR_MAX = float( config['MASS_AIR_FLOW_SUPPLY_AIR_MAX']) self.MASS_AIR_FLOW_SUPPLY_AIR_PER_PERSON = float( config['MASS_AIR_FLOW_SUPPLY_AIR_PER_PERSON']) self.MASS_AIR_FLOW_OUTSIDE_AIR_PER_PERSON = float( config['MASS_AIR_FLOW_OUTSIDE_AIR_PER_PERSON']) self.MASS_AIR_FLOW_OUTSIDE_AIR_PER_METER_SQUARE = float( config['MASS_AIR_FLOW_OUTSIDE_AIR_PER_METER_SQUARE']) self.MASS_AIR_FLOW_RETURN_AIR_RATIO = float( config['MASS_AIR_FLOW_RETURN_AIR_RATIO']) self.OCCUPANT_SENSIBLE_HEAT_GAIN = float( config['OCCUPANT_SENSIBLE_HEAT_GAIN']) self.OCCUPANT_WATER_VAPOR_RATE = float( config['OCCUPANT_WATER_VAPOR_RATE']) self.PLOT_INTERVAL = config['PLOT_INTERVAL'] self.PLOT_STEP = config['PLOT_STEP'] self.ZOOMPLOT_START_DATETIME = config['ZOOMPLOT_START_DATETIME'] self.ZOOMPLOT_END_DATETIME = config['ZOOMPLOT_END_DATETIME'] self.ZOOMPLOT_INTERVAL = config['ZOOMPLOT_INTERVAL'] self.ZOOMPLOT_STEP = config['ZOOMPLOT_STEP'] logging.info("Problem configuration initialized.") def _diagMode(self): logging.info( "===============================================================") if self.MODE_CONFIG == 'TSRA': logging.info("EAMS for Room Allocation & Time Scheduling.") elif self.MODE_CONFIG == 'TS': logging.info("EAMS for Time Scheduling only.") else: logging.critical("Unknown or Unsupported mode < %s >" % (self.MODE_CONFIG)) return self.err.eams_config_problem_err() logging.info( "===============================================================") return 0 def _populateRoomConfig(self): self.RC = RoomConfig(self.WALL_RESISTANCE_LOW, self.WALL_RESISTANCE_HIGH, self.WALL_CAPACITANCE_LOW, self.WALL_CAPACITANCE_HIGH, self.SOLAR_GAIN_LOW, self.SOLAR_GAIN_MEDIUM, self.SOLAR_GAIN_HIGH) ret = self.RC.loadRoomConfig(self.ROOM_CONFIG_DATA) if ret == 0: self.RC.populateRoomByZone() self.Z = self.RC.getRoomsInfoByZone("All") self.ZL = self.RC.getZoneList() self.RL = self.RC.getRoomList() self.RCL = self.RC.getRoomCapaList() self.RNL = self.RC.getRoomNeighboursList() logging.debug("Get rooms: %s" % self.Z) logging.debug("Get zonelist: %s" % (self.ZL)) logging.debug("Get roomlist: %s" % (self.RL)) logging.debug("Get room capa list: %s" % (self.RCL)) logging.debug("Get room neighbours list: %s" % (self.RNL)) # DEBUG_ONLY # self.Z = self.RC.getRoomsInfoByZone("1") # DEBUG_ONLY return ret def _populateOutdoorTemperature(self): self.OTC = OutdoorTemperature() ret = self.OTC.loadOutdoorTemperature(self.OUTDOOR_TEMP_DATA) if ret == 0: # Populate outdoor temperature # option 1: # if int(self.SCHEDULING_INTERVAL) >= 30: # self.OAT = self.OTC.getSingleDayOutdoorTemperature(self.SCHEDULING_START_DATETIME, self.SCHEDULING_END_DATETIME, self.SCHEDULING_INTERVAL) # else: # self.OAT = self.OTC.getSingleDayOutdoorTemperatureShortInterval(self.SCHEDULING_START_DATETIME, self.SCHEDULING_END_DATETIME, self.SCHEDULING_INTERVAL) # option 2: self.OAT = self.OTC.getOutdoorTemperature( self.SCHEDULING_START_DATETIME, self.SCHEDULING_END_DATETIME, self.SCHEDULING_INTERVAL) logging.debug("OAT: %s" % (self.OAT)) # for k, v in self.OAT.iteritems(): # logging.debug("[%s]:[%s]" %(k,v)) logging.debug("len: %s" % (len(self.OAT))) if len(self.OAT) == 0: return self.err.eams_no_outdoor_temp_in_scheduling_range() # Set initial temperature is set to outdoor temperature at first slot # option 1: override eams_probN.cfg INITIAL_TEMPERATURE if self.INITIAL_TEMPERATURE_MODE == '1': self.INITIAL_TEMPERATURE = float( self.OAT.get( datetime.strptime(self.SCHEDULING_START_DATETIME, "%Y-%m-%d %H:%M"))) logging.debug("Initial OAT: %s" % (self.INITIAL_TEMPERATURE)) # option 2: # self.INITIAL_TEMPERATURE = self.INITIAL_TEMPERATURE logging.debug("Set Initial Temperature : %.2f" % (self.INITIAL_TEMPERATURE)) return ret def _populateMeetingConfig(self): self.MC = MeetingConfig() ret = self.MC.loadMeetings(self.MEETINGS_CONFIG_DATA) if ret == 0: mr = self.MC.getMeetings() self.M = Meeting() ret = self.M.populateMeetingsForRoomAllocNSchedule(mr) if ret < 0: return ret self.ML = self.M.getMeetingsList() logging.debug("Total number of meetings: %d" % (len(self.ML))) logging.debug(self.ML) return ret def _populateSchedulingTimeSlot(self): """Form timeslot based on given work week and time slot interval""" self.TSC = TimeSlot(self.SCHEDULING_START_DATETIME, self.SCHEDULING_END_DATETIME, (int)(self.SCHEDULING_INTERVAL)) self.TS = self.TSC.getTimeSlots() logging.debug("Timeslot: %s" % self.TS) logging.debug("Total number of timeslot: %d" % len(self.TS)) def _populateHVACStdTimeslot(self): """Populate binary indicator list which denotes if the timeslot is in standard operating hour of HVAC (i.e. always on) """ self.SH = [] if self.HVAC_NON_PEAK_OFF == '1': s = datetime.strptime(self.HVAC_SHUT_DOWN, "%H:%M") e = datetime.strptime(self.HVAC_TURN_ON, "%H:%M") for _, v in self.TS.iteritems(): if (v.time() >= s.time() or v.time() < e.time()): self.SH.append(0) #off HVAC else: self.SH.append(1) else: for _, v in self.TS.iteritems(): self.SH.append(1) logging.debug("HVAC Standard Hours:\n%s" % (self.SH)) def _populateMeetingRequestTimeslot(self): """Populate slot index of meetings' time windows """ self.MTW = [] for i in xrange(len(self.ML)): self.MTW.append([]) for j in xrange(len(self.ML[i].TimeWindows)): s = self.ML[i].TimeWindows[j][0] e = self.ML[i].TimeWindows[j][1] sidx = self.TSC.getTimeSlotIdxByDatetime(s) eidx = self.TSC.getTimeSlotIdxByDatetime(e) if sidx is None: logging.error( "Meeting request falls outside of timeslot range. HALT." ) return self.err.eams_meeting_out_of_timeslot_range() if eidx is None: logging.error("Meeting ends outside of timeslot range. ") return self.err.eams_meeting_out_of_timeslot_range() logging.debug( "Meeting %s start at %s [slot %d], deadline at %s[slot %d], duration of %s slot(s)" % (self.ML[i].Key, s, sidx, e, eidx - 1, self.ML[i].Duration)) # logging.debug("sidx=%s eidx=%s d=%d" %(sidx, eidx-1, int(self.ML[i].Duration))) if (eidx - sidx) < int(self.ML[i].Duration): logging.error( "Meeting duration longer than Earliest-Start-Time to Latest-Finished-Time timeslot. HALT." ) return self.err.eams_meeting_invalid_duration() self.MTW[i].append([ sidx, eidx - 1 ]) #Note: Meeting end at the slot before 'End' time, hence -1 logging.debug("Meetings' time windows:") logging.debug(self.MTW) return 0 def _populateFeasibleRoomsForMeeting(self): """Does location l has the capacity to accommodate meeting midx? """ logging.info("Populate feasible rooms for meeting(s)...") self.MR = [] for i in xrange(len(self.ML)): self.MR.append([]) a = len(self.ML[i].Attendees) if not self.ML[i].Room: # no preferred room for j in xrange(len(self.RCL)): if a <= self.RCL[j]: self.MR[i].append(j) if not self.MR[i]: logging.error("No feasible room for meeting [%d]" % i) return self.err.eams_meeting_no_feasible_room() else: # has preferred room if self.ML[i].Room not in self.RL: logging.critical( "Mode Config: %s. Preferred room [%s] for meeting [%s] does not exist in room list." % (self.MODE_CONFIG, self.ML[i].Room, self.ML[i].Key)) return self.err.eams_config_meeting_err() ridx = self.RL.index(self.ML[i].Room) if len(self.ML[i].Attendees) > self.RCL[ridx]: logging.critical( "Mode Config: %s. Preferred room [%s] for meeting [%s] has smaller capacity (only for %d people) than the number of attendee." % (self.MODE_CONFIG, self.ML[i].Room, self.ML[i].Key, self.RCL[ridx])) return self.err.eams_config_meeting_err() self.MR[i].append( ridx) # limit feasible room to preferred room logging.debug( "Feasible rooms based on meetings' attendees and room capacity:") logging.debug(self.MR) return 0 def _populateMeetingsWithSimilarAttendees(self): """Does meeting m has similar attendee(s) as meeting om""" self.MOM = [] for mx in xrange(len(self.ML)): self.MOM.append([]) # TODO: use set.intersection instead! See _populateMeetingConflicts() mx_multiset = Counter(self.ML[mx].Attendees) for my in xrange(mx + 1, len(self.ML)): # logging.debug("checking m[%d, %d]" %(mx, my)) my_multiset = Counter(self.ML[my].Attendees) if (list((mx_multiset & my_multiset).elements())): logging.debug("Meeting %d and %d have similar attendees" % (mx, my)) self.MOM[mx].append(my) logging.debug("Meetings which has similar attendee(s)") logging.debug(self.MOM) def _populateRoomThermalCfg(self): """Populate individual room config to be used by Gurobi""" self.RTC = RoomThermalCfg(self.Z, self.TS, self.SOLAR_RADIATION_AM_START, self.SOLAR_RADIATION_NOON_START, self.SOLAR_RADIATION_PM_START, self.SOLAR_RADIATION_NIGHT_START) def _populateMeetingConflicts(self): """Which meeting is conflict with m, and who are the attendee that cause the conflict""" self.CALS = {} for mx in xrange(len(self.ML)): for my in xrange(mx + 1, len(self.ML)): oa = set(self.ML[mx].Attendees) & set(self.ML[my].Attendees) if oa: if mx in self.CALS.keys(): self.CALS.get(mx).update({my: list(oa)}) else: self.CALS[mx] = {my: list(oa)} if my in self.CALS.keys(): self.CALS.get(my).update({mx: list(oa)}) else: self.CALS[my] = {mx: list(oa)} # for k, v in self.CALS.iteritems(): # print k, ": ", v # print "" # Add empty set for meetings w/o conflicts! no_conflict = list( set(list(xrange(len(self.ML)))).difference(set(self.CALS.keys()))) for i in xrange(len(no_conflict)): self.CALS[no_conflict[i]] = {} # debug_only---------------------------------------- # for k, v in self.CALS.iteritems(): # print k, ": ", v # print "" # # for mx in xrange(len(self.ML)): # for my in xrange(mx+1, len(self.ML)): # print "[", mx, "," , my, "] =", self._hasSameConflictProperties(mx, my) # print "" # # for m in xrange(len(self.ML)): # print 'Meeting', m # print 'Attendees with multiple meetings:', self._getConflictAttendees(m) # print 'Meetings with same attendee:', self._getConflictMeetings(m) # print "" # debug_only---------------------------------------- # debug_only---------------------------------------- # def _hasSameConflictProperties(self, m1, m2): # # True: if both meeting has the same conflict attendees and conflict meetings. # if (self.CALS[m1].values() != self.CALS[m2].values()): # return False # # if m2 in self.CALS[m1].keys() and m1 in self.CALS[m2].keys(): # k1 = deepcopy(self.CALS[m1].keys())#.remove(m2) # k2 = deepcopy(self.CALS[m2].keys())#.remove(m1) # k1.remove(m2) # k2.remove(m1) # if k1 == k2: # return True # else: # return False # debug_only---------------------------------------- def _getConflictAttendees(self, m): return self.CALS[m].values() def _getConflictMeetings(self, m): return self.CALS[m].keys() # TODO: move this to new file which compute meeting clique! # TODO: For simplicity, we do not classify meeting further based on duration and room. def _populateMeetingClique(self): self.MTYPE = [] # Group based on time window logging.debug("Group based on time window... ") dg_mtw = {} for i in xrange(len(self.ML)): # print "ML[", i, "]=", self.ML[i].Key # print "MTW[", i, "]:", self.MTW[i] # print "MOM[", i, "]:", self.MOM[i] # print "MA:", len(self.ML[i].Attendees) # print "MD:", self.ML[i].Duration # print "MR:", self.MR[i] mtw_tup = ( ) # create tuple for MTW object [[66, 81], [114, 129]] --> (66, 81, 114, 129) for j in xrange(len(self.MTW[i])): mtw_tup = mtw_tup + tuple(self.MTW[i][j]) if mtw_tup in dg_mtw.keys( ): # use tuple as key, store index of ML which has that MTW properties dg_mtw.get(mtw_tup).append( i ) # (66, 81, 114, 129): [4] --> ML[4] has [[66, 81], [114, 129] else: dg_mtw[mtw_tup] = [i] logging.debug("Num MTW group:%d" % len(dg_mtw)) logging.debug("%s" % dg_mtw) # Re-group based on number of attendee logging.debug( "\nWithin group of same time window, re-group based on number of attendee... " ) logging.debug( "For simplicity, meetings are grouped based on 2-5, 6-15, 16-30 ppl" ) for k, v in dg_mtw.iteritems(): logging.debug("k=%s, ---v=%s" % (k, v)) numals = { 5: [], 15: [], 30: [], 100: [] } # a dict of based on number of attendee (num attendee less than 'key') for m in xrange(len(v)): mid = v[m] numa = len(self.ML[mid].Attendees) if numa <= 5: numals.get(5).append(mid) elif numa <= 15: numals.get(15).append(mid) elif numa <= 30: numals.get(30).append(mid) else: numals.get(100).append(mid) for nk, nv in numals.iteritems(): if len(nv): self.MTYPE.append(self.mtdesc(k, nk, None, None, nv)) logging.debug("%s" % (self.MTYPE)) logging.debug("Num meeting type:%d" % len(self.MTYPE)) # Re-group based on attendee conflict logging.debug( "\nWithin group of same time window & same num attendee group, Re-group based on attendee conflict... " ) new_mtype = [] for i in xrange(len(self.MTYPE)): mls = self.MTYPE[i].MLS logging.debug("Evaluating MTYPE %d: %s" % (i, mls)) tmp_mtype = [] for x in xrange(len(mls)): stat = False m = mls[x] mca = self._getConflictAttendees(m) # Get a unique list of mca uniq_mca = [] for a in xrange(len(mca)): for b in xrange(len(mca[a])): if mca[a][b] not in uniq_mca: uniq_mca.append(mca[a][b]) logging.debug(uniq_mca) for y in xrange(len(tmp_mtype)): # print "tmp_mtype[y].MCA:", tmp_mtype[y].MCA # print "uniq_mca:", uniq_mca # print tmp_mtype[y].MCA == uniq_mca if tmp_mtype[y].MCA == uniq_mca: tmp_mtype[y].MLS.append(m) stat = True break if stat == False: tmp_mtype.append( self.mtdesc(self.MTYPE[i].MTW, self.MTYPE[i].MA, None, uniq_mca, [m])) for j in xrange(len(tmp_mtype)): new_mtype.append(tmp_mtype[j]) logging.info("%s" % new_mtype) logging.info("Number of new MTYPE:%d" % len(new_mtype)) # # debug only ------------- # for i in xrange(len(new_mtype)): # print new_mtype[i] # print "Num MTYPE:" + str(len(new_mtype)) # # debug only ------------- for i in xrange(len(new_mtype)): logging.info("MTYPE[%d]:%s" % (i, str(new_mtype[i]))) # Overwrite MTYPE self.MTYPE = new_mtype def _populateConflictMeetingTypesBasedOnAttendee(self): self.CMT = {} for i in xrange(len(self.MTYPE)): for j in xrange(len(self.MTYPE[i].MCA)): aid = self.MTYPE[i].MCA[j] if aid not in self.CMT.keys(): self.CMT[aid] = [i] else: self.CMT.get(aid).append(i) logging.debug("ConflictMeetingTypes: %s" % self.CMT) def _populateProbData(self, filename): ret = 0 try: # Load problem configuration config = ConfigObj(filename, configspec=self.PROBLEM_CONFIG_SPEC, file_error=True) ret = self._validateProblemConfig(config) if ret < 0: raise ValidateError() self._loadProblemConfig(config) ret = self._diagMode() if ret < 0: raise ValueError("Invalid problem configuration.") # Initialize & load room, meeting, timeslot, outdoor temperature etc information ret = self._populateRoomConfig() if ret < 0: raise ValueError("Invalid room configuration.") ret = self._populateMeetingConfig() if ret < 0: raise ValueError("Invalid meeting configuration.") ret = self._populateOutdoorTemperature() if ret < 0: raise ValueError("Invalid outdoor temperature configuration.") self._populateSchedulingTimeSlot() ret = self._populateMeetingRequestTimeslot() if ret < 0: raise ValueError("Meeting request out of timeslot range.") ret = self._populateFeasibleRoomsForMeeting() if ret < 0: raise ValueError("Invalid room configuration for a meeting.") self._populateHVACStdTimeslot() self._populateMeetingsWithSimilarAttendees() self._populateMeetingConflicts() self._populateMeetingClique() self._populateConflictMeetingTypesBasedOnAttendee() self._populateRoomThermalCfg() except (ConfigObjError, IOError), e: logging.critical('%s' % (e)) return self.err.eams_config_problem_err() except (ValidateError), e: logging.critical("%s validation error. %d" % (filename, ret))
def __init__(self): self.err = EAMS_Error() self.MEETINGS_CONFIG = None self.meetings = {}
def _validateOverlappedTimeWindows(self, twlist, s, e): for i in xrange(len(twlist)): if twlist[i][0] == s and twlist[i][1] == e: return EAMS_Error().eams_meeting_overlapped_time_windows() return 0
def __init__(self): self.err = EAMS_Error() self.OUTDOOR_TEMP_DATA = None self.temperature = {}
class EAMS(): def __init__(self): self.err = EAMS_Error() self.PROBLEM_CONFIG_SPEC = 'Data/ConfigSpecs/eams_prob_spec.cfg' # activate log self.logger = logging.getLogger() self.logger.setLevel(logging.INFO) # self.logger.setLevel(logging.DEBUG) self.Z = None #======================================================================= # Zone -> Room. Eg: {'1': {'Room1': {'ZoneID': '1', 'Width': 10.0, 'Length': 6.0 ... #======================================================================= self.ZL = None #====================================================================== # Zone -> Room Name. Eg: {'1': ['Room1'], '3': ['Room3'], '2': ['Room2']} #====================================================================== self.RL = None #======================================================================= # Room list. Eg: ['Room1', 'Room3', 'Room2'] #======================================================================= self.TS = None #======================================================================= # Idx -> datetime. Eg: {0: datetime.datetime(2013, 1, 1, 8, 0), 1: datetime.datetime(2013, 1, 1, 8, 30), 2: datetime.datetime(2013, 1, 1, 9, 0), 3: datetime.datetime(2013, 1, 1, 9, 30), 4: datetime.datetime(2013, 1, 1, 10, 0), #======================================================================= self.ML = None #======================================================================= # List of namedtuple('Meeting_Desc', 'Key TimeWindows Duration Room Attendees') # [Meeting_Desc(Key='M110133', TimeWindows=[[datetime.datetime(2013, 1, 1, 9, 0), datetime.datetime(2013, 1, 1, 10, 30)], [datetime.datetime(2013, 1, 1, 12, 0), datetime.datetime(2013, 1, 1, 14, 0)], [datetime.datetime(2013, 1, 2, 14, 0), datetime.datetime(2013, 1, 2, 16, 0)]], Duration='3', Room='', Attendees=['1119', '2578', '3470', '4601', '6823', '7105', '7908', '12736', '12996', '20479']), Meeting_Desc(Key='M316335', TimeWindows=[[datetime.datetime(2013, 1, 1, 9, 0), datetime.datetime(2013, 1, 1, 18, 0)]], Duration='7', Room='', Attendees=['219', '246', '2852', '3304', '4095', '6845', '8495', '8811', '8927', '15695']), Meeting_Desc(Key='M325401', TimeWindows=[[datetime.datetime(2013, 1, 1, 9, 0), datetime.datetime(2013, 1, 1, 18, 0)]], Duration='7', Room='', Attendees=['264', '2165', '2528', '2890', '3167', '4273', '5258', '5363', '10719', '20204']), Meeting_Desc(Key='M433676', TimeWindows=[[datetime.datetime(2013, 1, 1, 9, 0), datetime.datetime(2013, 1, 1, 18, 0)]], Duration='7', Room='', Attendees=['413', '1104', '2192', '2674', '3201', '6866', '13958', '13998', '14601', '14607'])] #======================================================================= self.OAT = None #======================================================================= # Sorted outdoor temperature. Eg: OrderedDict([(datetime.datetime(2013, 1, 1, 8, 0), '26.00'), (datetime.datetime(2013, 1, 1, 8, 30), '26.00'), (datetime.datetime(2013, 1, 1, 9, 0), '28.00') #======================================================================= self.SH = None #======================================================================= # A list follow the sequence of TS #======================================================================= self.MTW = None #======================================================================= # A Double array follow the sequence of self.ML # [ # [[18, 21], [24, 28], [76, 80]], <- array of time windows [Start_Time, End_Time] # [[18, 36]], # [[18, 36]] # ] #======================================================================= self.MR = None #======================================================================= # A Double array follow the sequence of self.ML # #======================================================================= self.MOM = None #======================================================================= # A Double array follow the sequence of self.ML with list of meetings which has similar attendee(s) # [ # [1, 2], # [2], # [] # ] #======================================================================= self.MODE_CONFIG = "" self.STANDBY_MODE = "" self.MEETINGS_CONFIG_DATA = "" self.OUTDOOR_TEMP_DATA = "" self.ROOM_CONFIG_DATA = "" self.SCHEDULING_START_DATETIME = "" self.SCHEDULING_END_DATETIME = "" self.SCHEDULING_INTERVAL = -1 self.DAILY_WORKING_HOUR_START = "" self.DAILY_WORKING_HOUR_END = "" self.HVAC_NON_PEAK_OFF = -1 self.HVAC_SHUT_DOWN = "" self.HVAC_TURN_ON = "" self.SOLAR_GAIN_LOW = -1 self.SOLAR_GAIN_MEDIUM = -1 self.SOLAR_GAIN_HIGH = -1 self.SOLAR_RADIATION_AM_START = "" self.SOLAR_RADIATION_NOON_START = "" self.SOLAR_RADIATION_PM_START = "" self.SOLAR_RADIATION_NIGHT_START = "" self.WALL_RESISTANCE_LOW = -1 self.WALL_RESISTANCE_HIGH = -1 self.WALL_CAPACITANCE_LOW = -1 self.WALL_CAPACITANCE_HIGH = -1 self.INITIAL_TEMPERATURE_MODE = -1 self.INITIAL_TEMPERATURE = -1 self.TEMPERATURE_UNOCC_MIN = -1 self.TEMPERATURE_UNOCC_RANGE_INCR = -1 self.TEMPERATURE_OCC_COMFORT_RANGE_INCR = -1 self.TEMPERATURE_UNOCC_MAX = -1 self.TEMPERATURE_OCC_COMFORT_RANGE_DECR = -1 self.TEMPERATURE_CONDITIONED_AIR = -1 self.TEMPERATURE_SUPPLY_AIR_HIGH = -1 self.ALPHA_IAQ_FACTOR_OF_SAFETY = -1 self.BETA_FAN_POWER_CONSTANT = -1 self.AIR_HEAT_CAPACITY_AT_CONSTANT_PRESSURE = -1 self.INITIAL_TEMPERATURE_SUPPLY_AIR_OCC = -1 self.INITIAL_TEMPERATURE_SUPPLY_AIR_UNOCC = -1 self.INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_OCC = -1 self.INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_UNOCC = -1 self.MASS_AIR_FLOW_SUPPLY_AIR_MIN = -1 self.MASS_AIR_FLOW_SUPPLY_AIR_MAX = -1 self.MASS_AIR_FLOW_SUPPLY_AIR_PER_PERSON = -1 self.MASS_AIR_FLOW_OUTSIDE_AIR_PER_PERSON = -1 self.MASS_AIR_FLOW_OUTSIDE_AIR_PER_METER_SQUARE = -1 self.MASS_AIR_FLOW_RETURN_AIR_RATIO = -1 self.OCCUPANT_SENSIBLE_HEAT_GAIN = -1 self.OCCUPANT_WATER_VAPOR_RATE = -1 self.PLOT_INTERVAL = -1 self.PLOT_STEP = -1 self.ZOOMPLOT_START_DATETIME = "" self.ZOOMPLOT_END_DATETIME = "" self.ZOOMPLOT_INTERVAL = -1 self.ZOOMPLOT_STEP = -1 def activateLogFile(self, f): # remove old handler for old_handler in self.logger.handlers: self.logger.removeHandler(old_handler) # create a handler with the name defined by the variable f handler = logging.FileHandler(f) # add that handler to the logger self.logger.addHandler(handler) def _critical_err(self): sys.exit("Pop, Bang, Whooo, Boom... Fire Alarm! Evacuate! EAMS exit.") def _validateProblemConfig(self, config): validator = Validator() results = config.validate(validator) logging.info("Validating problem configuration, result: %s" % results) if results != True: for (_, key, _) in flatten_errors(config, results): if key is not None: logging.error('The "%s" key failed validation' % (key)) else: logging.error( "Configuration error. Either some section was missing, duplicate key(s) etc..." ) return self.err.eams_config_problem_err() return 0 def _loadProblemConfig(self, config): #TODO: should cast these variables according to their type here, so you need not cast them later on! self.MODE_CONFIG = config['MODE_CONFIG'] self.STANDBY_MODE = config['STANDBY_MODE'] self.MEETINGS_CONFIG_DATA = config['MEETINGS_CONFIG_DATA'] self.OUTDOOR_TEMP_DATA = config['OUTDOOR_TEMP_DATA'] self.ROOM_CONFIG_DATA = config['ROOM_CONFIG_DATA'] self.SCHEDULING_START_DATETIME = config['SCHEDULING_START_DATETIME'] self.SCHEDULING_END_DATETIME = config['SCHEDULING_END_DATETIME'] self.SCHEDULING_INTERVAL = int(config['SCHEDULING_INTERVAL']) self.DAILY_WORKING_HOUR_START = config['DAILY_WORKING_HOUR_START'] self.DAILY_WORKING_HOUR_END = config['DAILY_WORKING_HOUR_END'] self.HVAC_NON_PEAK_OFF = config['HVAC_NON_PEAK_OFF'] self.HVAC_SHUT_DOWN = config['HVAC_SHUT_DOWN'] self.HVAC_TURN_ON = config['HVAC_TURN_ON'] self.SOLAR_GAIN_LOW = config['SOLAR_GAIN_LOW'] self.SOLAR_GAIN_MEDIUM = config['SOLAR_GAIN_MEDIUM'] self.SOLAR_GAIN_HIGH = config['SOLAR_GAIN_HIGH'] self.SOLAR_RADIATION_AM_START = config['SOLAR_RADIATION_AM_START'] self.SOLAR_RADIATION_NOON_START = config['SOLAR_RADIATION_NOON_START'] self.SOLAR_RADIATION_PM_START = config['SOLAR_RADIATION_PM_START'] self.SOLAR_RADIATION_NIGHT_START = config[ 'SOLAR_RADIATION_NIGHT_START'] self.WALL_RESISTANCE_LOW = config['WALL_RESISTANCE_LOW'] self.WALL_RESISTANCE_HIGH = config['WALL_RESISTANCE_HIGH'] self.WALL_CAPACITANCE_LOW = config['WALL_CAPACITANCE_LOW'] self.WALL_CAPACITANCE_HIGH = config['WALL_CAPACITANCE_HIGH'] self.INITIAL_TEMPERATURE_MODE = config['INITIAL_TEMPERATURE_MODE'] self.INITIAL_TEMPERATURE = config['INITIAL_TEMPERATURE'] self.TEMPERATURE_UNOCC_MIN = float(config['TEMPERATURE_UNOCC_MIN']) self.TEMPERATURE_UNOCC_RANGE_INCR = float( config['TEMPERATURE_UNOCC_RANGE_INCR']) self.TEMPERATURE_OCC_COMFORT_RANGE_INCR = float( config['TEMPERATURE_OCC_COMFORT_RANGE_INCR']) self.TEMPERATURE_UNOCC_MAX = float(config['TEMPERATURE_UNOCC_MAX']) self.TEMPERATURE_OCC_COMFORT_RANGE_DECR = float( config['TEMPERATURE_OCC_COMFORT_RANGE_DECR']) self.TEMPERATURE_CONDITIONED_AIR = float( config['TEMPERATURE_CONDITIONED_AIR']) self.TEMPERATURE_SUPPLY_AIR_HIGH = float( config['TEMPERATURE_SUPPLY_AIR_HIGH']) self.ALPHA_IAQ_FACTOR_OF_SAFETY = config['ALPHA_IAQ_FACTOR_OF_SAFETY'] self.BETA_FAN_POWER_CONSTANT = config['BETA_FAN_POWER_CONSTANT'] self.AIR_HEAT_CAPACITY_AT_CONSTANT_PRESSURE = float( config['AIR_HEAT_CAPACITY_AT_CONSTANT_PRESSURE']) self.INITIAL_TEMPERATURE_SUPPLY_AIR_OCC = float( config['INITIAL_TEMPERATURE_SUPPLY_AIR_OCC']) self.INITIAL_TEMPERATURE_SUPPLY_AIR_UNOCC = float( config['INITIAL_TEMPERATURE_SUPPLY_AIR_UNOCC']) self.INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_OCC = float( config['INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_OCC']) self.INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_UNOCC = float( config['INITIAL_MASS_AIR_FLOW_SUPPLY_AIR_UNOCC']) self.MASS_AIR_FLOW_SUPPLY_AIR_MIN = float( config['MASS_AIR_FLOW_SUPPLY_AIR_MIN']) self.MASS_AIR_FLOW_SUPPLY_AIR_MAX = float( config['MASS_AIR_FLOW_SUPPLY_AIR_MAX']) self.MASS_AIR_FLOW_SUPPLY_AIR_PER_PERSON = float( config['MASS_AIR_FLOW_SUPPLY_AIR_PER_PERSON']) self.MASS_AIR_FLOW_OUTSIDE_AIR_PER_PERSON = float( config['MASS_AIR_FLOW_OUTSIDE_AIR_PER_PERSON']) self.MASS_AIR_FLOW_OUTSIDE_AIR_PER_METER_SQUARE = float( config['MASS_AIR_FLOW_OUTSIDE_AIR_PER_METER_SQUARE']) self.MASS_AIR_FLOW_RETURN_AIR_RATIO = float( config['MASS_AIR_FLOW_RETURN_AIR_RATIO']) self.OCCUPANT_SENSIBLE_HEAT_GAIN = float( config['OCCUPANT_SENSIBLE_HEAT_GAIN']) self.OCCUPANT_WATER_VAPOR_RATE = float( config['OCCUPANT_WATER_VAPOR_RATE']) self.PLOT_INTERVAL = config['PLOT_INTERVAL'] self.PLOT_STEP = config['PLOT_STEP'] self.ZOOMPLOT_START_DATETIME = config['ZOOMPLOT_START_DATETIME'] self.ZOOMPLOT_END_DATETIME = config['ZOOMPLOT_END_DATETIME'] self.ZOOMPLOT_INTERVAL = config['ZOOMPLOT_INTERVAL'] self.ZOOMPLOT_STEP = config['ZOOMPLOT_STEP'] logging.info("Problem configuration initialized.") def _diagMode(self): logging.info( "===============================================================") if self.MODE_CONFIG == 'TSRA': logging.info("EAMS for Room Allocation & Time Scheduling.") elif self.MODE_CONFIG == 'TS': logging.info("EAMS for Time Scheduling only.") else: logging.critical("Unknown or Unsupported mode < %s >" % (self.MODE_CONFIG)) return self.err.eams_config_problem_err() logging.info( "===============================================================") return 0 def _populateRoomConfig(self): self.RC = RoomConfig(self.WALL_RESISTANCE_LOW, self.WALL_RESISTANCE_HIGH, self.WALL_CAPACITANCE_LOW, self.WALL_CAPACITANCE_HIGH, self.SOLAR_GAIN_LOW, self.SOLAR_GAIN_MEDIUM, self.SOLAR_GAIN_HIGH) ret = self.RC.loadRoomConfig(self.ROOM_CONFIG_DATA) if ret == 0: self.RC.populateRoomByZone() self.Z = self.RC.getRoomsInfoByZone("All") self.ZL = self.RC.getZoneList() self.RL = self.RC.getRoomList() self.RCL = self.RC.getRoomCapaList() self.RNL = self.RC.getRoomNeighboursList() logging.debug("Get rooms: %s" % self.Z) logging.debug("Get zonelist: %s" % (self.ZL)) logging.debug("Get roomlist: %s" % (self.RL)) logging.debug("Get room capa list: %s" % (self.RCL)) logging.debug("Get room neighbours list: %s" % (self.RNL)) # DEBUG_ONLY # self.Z = self.RC.getRoomsInfoByZone("1") # DEBUG_ONLY return ret def _populateOutdoorTemperature(self): self.OTC = OutdoorTemperature() ret = self.OTC.loadOutdoorTemperature(self.OUTDOOR_TEMP_DATA) if ret == 0: # Populate outdoor temperature # option 1: # if int(self.SCHEDULING_INTERVAL) >= 30: # self.OAT = self.OTC.getSingleDayOutdoorTemperature(self.SCHEDULING_START_DATETIME, self.SCHEDULING_END_DATETIME, self.SCHEDULING_INTERVAL) # else: # self.OAT = self.OTC.getSingleDayOutdoorTemperatureShortInterval(self.SCHEDULING_START_DATETIME, self.SCHEDULING_END_DATETIME, self.SCHEDULING_INTERVAL) # option 2: self.OAT = self.OTC.getOutdoorTemperature( self.SCHEDULING_START_DATETIME, self.SCHEDULING_END_DATETIME, self.SCHEDULING_INTERVAL) logging.debug("OAT: %s" % (self.OAT)) # for k, v in self.OAT.iteritems(): # logging.debug("[%s]:[%s]" %(k,v)) logging.debug("len: %s" % (len(self.OAT))) if len(self.OAT) == 0: return self.err.eams_no_outdoor_temp_in_scheduling_range() # Set initial temperature is set to outdoor temperature at first slot # option 1: override eams_probN.cfg INITIAL_TEMPERATURE if self.INITIAL_TEMPERATURE_MODE == '1': logging.debug("Initial OAT: %s" % (self.OAT.get( datetime.strptime(self.SCHEDULING_START_DATETIME, "%Y-%m-%d %H:%M")))) self.INITIAL_TEMPERATURE = float( self.OAT.get( datetime.strptime(self.SCHEDULING_START_DATETIME, "%Y-%m-%d %H:%M"))) # option 2: # self.INITIAL_TEMPERATURE = self.INITIAL_TEMPERATURE logging.debug("Set Initial Temperature : %.2f" % (self.INITIAL_TEMPERATURE)) return ret def _populateMeetingConfig(self): self.MC = MeetingConfig() ret = self.MC.loadMeetings(self.MEETINGS_CONFIG_DATA) if ret == 0: mr = self.MC.getMeetings() self.M = Meeting() # if self.MODE_CONFIG == 'RA': # self.M.populateMeetingsWithFixedScheduleForRoomAlloc(mr) # elif self.MODE_CONFIG == 'FIXED': # self.M.populateMeetingsWithFixedScheduleFixedRoom(mr) # else: ret = self.M.populateMeetingsForRoomAllocNSchedule(mr) if ret < 0: return ret self.ML = self.M.getMeetingsList() logging.debug("Total number of meetings: %d" % (len(self.ML))) logging.debug(self.ML) return ret def _populateSchedulingTimeSlot(self): """Form timeslot based on given work week and time slot interval""" self.TSC = TimeSlot(self.SCHEDULING_START_DATETIME, self.SCHEDULING_END_DATETIME, (int)(self.SCHEDULING_INTERVAL)) self.TS = self.TSC.getTimeSlots() logging.debug("Timeslot: %s" % self.TS) logging.debug("Total number of timeslot: %d" % len(self.TS)) def _populateHVACStdTimeslot(self): """Populate binary indicator list which denotes if the timeslot is in standard operating hour of HVAC (i.e. always on) """ self.SH = [] if self.HVAC_NON_PEAK_OFF == '1': s = datetime.strptime(self.HVAC_SHUT_DOWN, "%H:%M") e = datetime.strptime(self.HVAC_TURN_ON, "%H:%M") for _, v in self.TS.iteritems(): if (v.time() >= s.time() or v.time() < e.time()): self.SH.append(0) #off HVAC else: self.SH.append(1) else: for _, v in self.TS.iteritems(): self.SH.append(1) logging.debug("HVAC Standard Hours:\n%s" % (self.SH)) def _populateMeetingRequestTimeslot(self): """Populate slot index of meetings' time windows """ self.MTW = [] for i in xrange(len(self.ML)): self.MTW.append([]) for j in xrange(len(self.ML[i].TimeWindows)): s = self.ML[i].TimeWindows[j][0] e = self.ML[i].TimeWindows[j][1] sidx = self.TSC.getTimeSlotIdxByDatetime(s) eidx = self.TSC.getTimeSlotIdxByDatetime(e) if sidx is None: logging.error( "Meeting request falls outside of timeslot range. HALT." ) return self.err.eams_meeting_out_of_timeslot_range() if eidx is None: logging.error("Meeting ends outside of timeslot range. ") return self.err.eams_meeting_out_of_timeslot_range() logging.debug( "Meeting %s start at %s [slot %d], deadline at %s[slot %d], duration of %s slot(s)" % (self.ML[i].Key, s, sidx, e, eidx - 1, self.ML[i].Duration)) # logging.debug("sidx=%s eidx=%s d=%d" %(sidx, eidx-1, int(self.ML[i].Duration))) if (eidx - sidx) < int(self.ML[i].Duration): logging.error( "Meeting duration longer than Earliest-Start-Time to Latest-Finished-Time timeslot. HALT." ) return self.err.eams_meeting_invalid_duration() self.MTW[i].append([ sidx, eidx - 1 ]) #Note: Meeting end at the slot before 'End' time, hence -1 logging.debug("Meetings' time windows:") logging.debug(self.MTW) return 0 def _populateFeasibleRoomsForMeeting(self): """Does location l has the capacity to accommodate meeting midx? """ logging.info("Populate feasible rooms for meeting(s)...") self.MR = [] for i in xrange(len(self.ML)): self.MR.append([]) a = len(self.ML[i].Attendees) if not self.ML[i].Room: # no preferred room for j in xrange(len(self.RCL)): if a <= self.RCL[j]: self.MR[i].append(j) if not self.MR[i]: logging.error("No feasible room for meeting [%d]" % i) return self.err.eams_meeting_no_feasible_room() else: # has preferred room if self.ML[i].Room not in self.RL: logging.critical( "Mode Config: %s. Preferred room [%s] for meeting [%s] does not exist in room list." % (self.MODE_CONFIG, self.ML[i].Room, self.ML[i].Key)) return self.err.eams_config_meeting_err() ridx = self.RL.index(self.ML[i].Room) if len(self.ML[i].Attendees) > self.RCL[ridx]: logging.critical( "Mode Config: %s. Preferred room [%s] for meeting [%s] has smaller capacity (only for %d people) than the number of attendee." % (self.MODE_CONFIG, self.ML[i].Room, self.ML[i].Key, self.RCL[ridx])) return self.err.eams_config_meeting_err() self.MR[i].append( ridx) # limit feasible room to preferred room logging.debug( "Feasible rooms based on meetings' attendees and room capacity:") logging.debug(self.MR) return 0 def _populateMeetingsWithSimilarAttendees(self): """Does meeting m has similar attendee(s) as meeting om""" self.MOM = [] for mx in xrange(len(self.ML)): self.MOM.append([]) mx_multiset = Counter(self.ML[mx].Attendees) for my in xrange(mx + 1, len(self.ML)): # logging.debug("checking m[%d, %d]" %(mx, my)) my_multiset = Counter(self.ML[my].Attendees) if (list((mx_multiset & my_multiset).elements())): logging.debug("Meeting %d and %d have similar attendees" % (mx, my)) self.MOM[mx].append(my) logging.debug("Meetings which has similar attendee(s)") logging.debug(self.MOM) def _populateRoomThermalCfg(self): """Populate individual room config to be used by Gurobi""" self.RTC = RoomThermalCfg(self.Z, self.TS, self.SOLAR_RADIATION_AM_START, self.SOLAR_RADIATION_NOON_START, self.SOLAR_RADIATION_PM_START, self.SOLAR_RADIATION_NIGHT_START) def _populateProbData(self, filename): ret = 0 try: # Load problem configuration config = ConfigObj(filename, configspec=self.PROBLEM_CONFIG_SPEC, file_error=True) ret = self._validateProblemConfig(config) if ret < 0: raise ValidateError() self._loadProblemConfig(config) ret = self._diagMode() if ret < 0: raise ValueError("Invalid problem configuration.") # Initialize & load room, meeting, timeslot, outdoor temperature etc information ret = self._populateRoomConfig() if ret < 0: raise ValueError("Invalid room configuration.") ret = self._populateMeetingConfig() if ret < 0: raise ValueError("Invalid meeting configuration.") ret = self._populateOutdoorTemperature() if ret < 0: raise ValueError("Invalid outdoor temperature configuration.") self._populateSchedulingTimeSlot() ret = self._populateMeetingRequestTimeslot() if ret < 0: raise ValueError("Meeting request out of timeslot range.") ret = self._populateFeasibleRoomsForMeeting() if ret < 0: raise ValueError("Invalid room configuration for a meeting.") self._populateHVACStdTimeslot() self._populateMeetingsWithSimilarAttendees() self._populateRoomThermalCfg() except (ConfigObjError, IOError), e: logging.critical('%s' % (e)) return self.err.eams_config_problem_err() except (ValidateError), e: logging.critical("%s validation error. %d" % (filename, ret))