def __init__(self): # {{{ ''' Generate montecarlo cfast.in. Log what was drawn to psql. ''' self.json = Json() self.hrrpua = 0 self.alpha = 0 self.fire_origin = None self.conf = self.json.read("{}/conf.json".format( os.environ['AAMKS_PROJECT'])) if self.conf['fire_model'] == 'FDS': return self.s = Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT'])) self.p = Psql() self._psql_collector = OrderedDict() self.s.query( "CREATE TABLE fire_origin(name,is_room,x,y,z,floor,sim_id)") si = SimIterations(self.conf['project_id'], self.conf['scenario_id'], self.conf['number_of_simulations']) for self._sim_id in range(*si.get()): seed(self._sim_id) self._new_psql_log() self._make_cfast() self._write()
def __init__(self): self.losses = dict() self.labels = [] self.losses_num = [] self.t_k = 0 self.total = 0 self.dead = 0 self.dir = sys.argv[1] self.configs = self._get_json('{}/conf.json'.format(self.dir)) self.p = Psql() if os.path.exists('{}/picts'.format(self.dir)): shutil.rmtree('{}/picts'.format(self.dir)) os.makedirs('{}/picts'.format(self.dir))
def __init__(self): # {{{ ''' Stuff that happens at the beggining of the project ''' if len(sys.argv) > 1: os.environ["AAMKS_PROJECT"] = sys.argv[1] self.json = Json() self.conf = self.json.read("{}/conf.json".format( os.environ['AAMKS_PROJECT'])) self.project_id = self.conf['project_id'] self.p = Psql() self._clear_srv_anims() self._clear_sqlite() self._setup_simulations()
def __init__(self): # {{{ ''' Stuff that happens at the beggining of the project ''' if len(sys.argv) > 1: os.environ["AAMKS_PROJECT"] = sys.argv[1] if len(sys.argv) > 2: os.environ["AAMKS_USER_ID"] = sys.argv[2] self.json = Json() self.conf = self.json.read("{}/conf.json".format( os.environ['AAMKS_PROJECT'])) self.project_id = self.conf['project_id'] self.scenario_id = self.conf['scenario_id'] self.p = Psql() self._clear_srv_anims() self._clear_sqlite() self.s = Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT'])) self._setup_simulations() self._create_sqlite_tables()
def __init__(self): # {{{ ''' Generate montecarlo cfast.in. Log what was drawn to psql. ''' self.s = Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT'])) self.p = Psql() self.json = Json() self.conf = self.json.read("{}/conf.json".format( os.environ['AAMKS_PROJECT'])) self._psql_collector = OrderedDict() si = SimIterations(self.conf['project_id'], self.conf['number_of_simulations']) for self._sim_id in range(*si.get()): seed(self._sim_id) self._new_psql_log() self._make_cfast() self._write()
def __init__(self): # {{{ ''' Stuff that happens at the end of the project ''' self.json = Json() self.conf = self.json.read("{}/conf.json".format( os.environ['AAMKS_PROJECT'])) self.project_id = self.conf['project_id'] self.p = Psql() self._gearman_register_works()
def psql_report(self): p = Psql() fed = json.dumps(self.meta['psql']['fed']) rset = json.dumps(self.meta['psql']['rset']) p.query( "UPDATE simulations SET fed = '{}', wcbe='{}', run_time = {}, dcbe_time = {}, min_vis_compa = {}, max_temp = {}, host = '{}', min_hgt_compa = {}, min_vis_cor = {}, min_hgt_cor = {} WHERE project=%s AND iteration=%s" .format( fed, rset, self.meta['psql']['runtime'], self.meta['psql']['cross_building_results']['dcbe'], self.meta['psql']['cross_building_results'] ['min_vis_compa'], self.meta['psql'] ['cross_building_results']['max_temp_compa'], self.meta['worker'], self.meta['psql'] ['cross_building_results']['min_hgt_compa'], self.meta['psql']['cross_building_results']['min_vis_cor'], self.meta['psql']['cross_building_results'] ['min_hgt_cor']), (self.meta['project_id'], self.meta['sim_id']))
def __init__(self): # {{{ ''' Stuff that happens at the end of the project ''' self.json = Json() self.conf = self.json.read("{}/conf.json".format( os.environ['AAMKS_PROJECT'])) self.s = Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT'])) self.project_id = self.conf['project_id'] self.scenario_id = self.conf['scenario_id'] self.p = Psql() if self.conf['navmesh_debug'] == 1: self._navmeshes_for_floors() Vis({ 'highlight_geom': None, 'anim': None, 'title': "OnEnd()", 'srv': 1 }) self._gearman_register_works()
class processDists: def __init__(self): self.losses = dict() self.labels = [] self.losses_num = [] self.t_k = 0 self.total = 0 self.dead = 0 self.dir = sys.argv[1] self.configs = self._get_json('{}/conf.json'.format(self.dir)) self.p = Psql() if os.path.exists('{}/picts'.format(self.dir)): shutil.rmtree('{}/picts'.format(self.dir)) os.makedirs('{}/picts'.format(self.dir)) def plot_dcbe_dist(self, project_list): # plt.clf() n = 1 for proj in project_list: query = "SELECT dcbe_time FROM simulations where project = {} AND dcbe_time is not null AND dcbe_time < 9999".format( proj) results = self.p.query(query) dcbe = [int(i[0]) for i in results] sns_plot = sns.distplot(dcbe, kde_kws={ 'cumulative': True, 'label': 'CDF A{}'.format(n) }, bins=50) n += 1 fig = sns_plot.get_figure() fig.savefig("{}/picts/m_dcbe.png".format(self.dir)) plt.clf() def plot_wcbe_dist(self, project_list): n = 1 for proj in project_list: add = 0 query = "SELECT wcbe FROM simulations where project = {} AND dcbe_time is not null".format( proj) if proj == 4: add = lognorm(s=1, loc=899, scale=5.92).rvs() * binomial( 1, 0.3) results = self.p.query(query) wcbe = list() dcbe = [json.loads(i[0]) for i in results] for i in dcbe: for value in i.values(): if proj == 4: wcbe.append( lognorm(s=1, loc=30, scale=2.92).rvs() + add) if value > 0: wcbe.append(value) sns_plot = sns.distplot(wcbe, kde_kws={ 'cumulative': True, 'label': 'CDF A{}'.format(n) }, bins=50) n += 1 # plt.xlabel('WCBE [s]') # plt.ylabel('Prawdopodobieństwo') fig = sns_plot.get_figure() fig.savefig("{}/picts/m_wcbe.png".format(self.dir)) plt.clf() def plot_min_height(self): query = "SELECT min_hgt_compa * 100 FROM simulations where project = {} AND min_hgt_compa < 12.8"\ .format(self.configs['project_id']) results = self.p.query(query) dcbe = [float(i[0]) for i in results] sns_plot = sns.distplot(dcbe, hist_kws={'cumulative': True}, kde_kws={ 'cumulative': True, 'label': 'CDF' }, bins=50) # sns.plt.xlabel('Wysokość warstwy dymu [cm]') # sns.plt.ylabel('Prawdopodobieństwo') fig = sns_plot.get_figure() fig.savefig("{}/picts/height.png".format(self.dir)) plt.clf() def plot_run_time(self, project_list): n = 1 for proj in project_list: query = "SELECT run_time FROM simulations where project = {} AND dcbe_time is not null ".format( proj) results = self.p.query(query) dcbe = [int(i[0]) for i in results] sns_plot = sns.distplot(dcbe, kde_kws={ 'cumulative': True, 'label': 'Runtime CDF A{}'.format(n) }, bins=50) # sns.plt.xlabel('Wysokość warstwy dymu [cm]') # sns.plt.ylabel('Prawdopodobieństwo') n += 1 fig = sns_plot.get_figure() fig.savefig("{}/picts/runtime.png".format(self.dir)) plt.clf() def plot_min_height_cor(self): query = "SELECT min_hgt_cor * 100 FROM simulations where project = {} AND min_hgt_cor < 12.8"\ .format(self.configs['project_id']) results = self.p.query(query) dcbe = [float(i[0]) for i in results] sns_plot = sns.distplot(dcbe, hist_kws={'cumulative': True}, kde_kws={ 'cumulative': True, 'label': 'CDF' }, bins=50) # sns.plt.xlabel('Wysokość warstwy dymu [cm]') # sns.plt.ylabel('Prawdopodobieństwo') fig = sns_plot.get_figure() fig.savefig("{}/picts/hgt_cor.png".format(self.dir)) plt.clf() def plot_min_vis(self): query = "SELECT min_vis_compa FROM simulations where project = {} AND min_vis_compa < 60".format( self.configs['project_id']) results = self.p.query(query) vis = [float(i[0]) for i in results] sns_plot = sns.distplot(vis, hist_kws={'cumulative': True}, kde_kws={ 'cumulative': True, 'label': 'CDF' }, bins=50) # sns.plt.xlabel('Zasięg widzialności [m]') # sns.plt.ylabel('Prawdopodobieństwo') fig = sns_plot.get_figure() fig.savefig("{}/picts/vis.png".format(self.dir)) plt.clf() def plot_min_vis_cor(self): query = "SELECT min_vis_cor FROM simulations where project = {} AND min_vis_cor < 60".format( self.configs['project_id']) results = self.p.query(query) vis = [float(i[0]) for i in results] sns_plot = sns.distplot(vis, hist_kws={'cumulative': True}, kde_kws={ 'cumulative': True, 'label': 'CDF' }, bins=50) #sns.plt.xlabel('Zasięg widzialności [m]') #sns.plt.ylabel('Prawdopodobieństwo') fig = sns_plot.get_figure() fig.savefig("{}/picts/vis_cor.png".format(self.dir)) plt.clf() def plot_max_temp(self): query = "SELECT max_temp FROM simulations where project = {} and dcbe_time is " \ "not null".format(self.configs['project_id']) results = self.p.query(query) dcbe = [float(i[0]) for i in results] dist = getattr(stat, 'norm') param = dist.fit(dcbe) #print(param) dcbe_n = np.array(dcbe) self.t_k = len(dcbe_n[dcbe_n > 450]) sns_plot = sns.distplot(dcbe, hist_kws={'cumulative': True}, kde_kws={ 'cumulative': True, 'label': 'CDF' }, bins=50) # sns.plt.xlabel('Temperatura ') # sns.plt.ylabel('Prawdopodobieństwo') fig = sns_plot.get_figure() fig.savefig("{}/picts/temp.png".format(self.dir)) plt.clf() def calculate_ccdf(self, project_list): fig = plt.figure(figsize=(12, 3)) axs = [ fig.add_subplot(131), fig.add_subplot(132), fig.add_subplot(133) ] xtic = tic.MaxNLocator(3) n = 1 for proj in project_list: losses = OrderedDict() losses = { 'fatalities': list(), 'heavy injured': list(), 'light injured': list(), 'neglegible': list() } query = "SELECT fed, id FROM simulations where project = {} " \ "and dcbe_time IS NOT NULL".format(proj) results = self.p.query(query) self.total = len(results) row = [json.loads(i[0]) for i in results] fed = list() for i in row: for values in i.values(): fed.append(collections.Counter(np.array(values))) for item in fed: for key in item.keys(): if key == 'H': losses['fatalities'].append(item[key]) if key == 'M': losses['heavy injured'].append(item[key]) if key == 'L': losses['light injured'].append(item[key]) if key == 'N': losses['neglegible'].append(item[key]) wykres = 0 for key in losses.keys(): if key == 'neglegible': continue if len(losses[key]) == 0: continue dane = ecdf(losses[key]) axs[wykres].plot(sorted(losses[key]), 1 - dane(sorted(losses[key])), label='A{}'.format(n)) axs[wykres].legend() axs[wykres].set_xlabel('Number of people') axs[wykres].set_ylabel('Likelihood') axs[wykres].set_title(key) wykres += 1 #axs[i].xaxis.set_major_formatter(tic.FormatStrFormatter('%4.f')) n += 1 fig.tight_layout() fig.savefig('{}/picts/m_ccdf.png'.format(self.dir)) fig.clf() def plot_ccdf_percentage(self): fig = plt.figure(figsize=(12, 3)) axs = [ fig.add_subplot(131), fig.add_subplot(132), fig.add_subplot(133) ] for i in range(3): l_updated = np.array(self.losses[i]) dane = ecdf(l_updated) axs[i].plot(sorted(l_updated), (1 - dane(sorted(l_updated))) * 100) axs[i].set_xlabel('Number of people') axs[i].set_ylabel('Share %') axs[i].set_title(self.labels[i]) #axs[i].xaxis.set_major_formatter(tic.FormatStrFormatter('%4.f')) fig.tight_layout() fig.savefig('{}/picts/ccdf_per.png'.format(self.dir)) fig.clf() def _get_json(self, path): f = open(path, 'r') dump = json.load(f, object_pairs_hook=OrderedDict) f.close() return dump def plot_event_tree(self): t = Tree("((1:0.001, 0.1:0.23, 0.001, >0.001), NIE);") t = Tree( "((D: 0.723274, F: 0.567784)1.000000: 0.067192, (B: 0.279326, H: 0.756049)1.000000: 0.807788);" ) t.support = 0.1 ts = TreeStyle() ts.show_leaf_name = True ts.show_branch_length = True ts.show_branch_support = True t.add_face(TextFace(" hola "), column=0, position='branch-right') t.show(tree_style=ts) def plot_losses_hist(self): labels = ['Death', 'Heavy injury', 'Light injury', 'Neglegible'] wykres = 0 for key in self.losses.keys(): if len(self.losses[key]) == 0: continue fig = plt.figure() plt.hist(self.losses[key], bins=20) plt.title(key) plt.xlabel('Number of casualities') plt.ylabel('Number of scenarios ') fig.savefig('{}/picts/losses{}.png'.format(self.dir, key)) fig.clf() def plot_pie_fault(self): fig = plt.figure() sizes = [ len(self.losses['dead']), self.total - len(self.losses['dead']) ] labels = 'Success', 'Failure' colors = ['lightskyblue', 'lightcoral'] explode = (0.1, 0) plt.pie(sizes, explode=explode, labels=labels, colors=colors, autopct='%1.1f%%', shadow=True) plt.axis('equal') fig.savefig('{}/picts/pie_fault.png'.format(self.dir)) fig.clf() def calculate_barrois(self, area): other_building = [1.18, 1e-4, -1.87, -0.20] office = [0.056, 3e-6, -0.65, -0.05] warehouse = [3.82, 2e-6, -2.08, -0.05] commercial = [7e-5, 6e-6, -0.65, -0.05] nursing = [2e-4, 5e-6, -0.61, -0.05] educational = [0.003, 3e-6, -1.26, -0.05] building = { 'other_building': other_building, 'office': office, 'warehouse': warehouse, 'commercial': commercial, 'nursing': nursing, 'educational': educational } b_type = 'educational' ignition = building[b_type][0]*(area) ** (building[b_type][2]) + \ building[b_type][1] * (area) ** (building[b_type][3]) return ignition def dcbe_values(self): query = "SELECT count(*) FROM simulations where project = {} AND dcbe_time < 9999".format( self.configs['project_id']) results = self.p.query(query) lower = results[0][0] / self.total query = "SELECT avg(dcbe_time) FROM simulations where project = {} AND dcbe_time < 9999".format( self.configs['project_id']) results = self.p.query(query) mean = results[0][0] return [lower, mean] def wcbe_values(self): query = "SELECT avg(wcbe) FROM simulations where project = {} AND dcbe_time IS NOT NULL".format( self.configs['project_id']) results = self.p.query(query) return results[0][0] def min_height_values(self): query = "SELECT count(*) FROM simulations where project = {} AND min_hgt_cor < 0.5" \ .format(self.configs['project_id']) results = self.p.query(query) lower = results[0][0] / self.total query = "SELECT avg(min_hgt_compa) FROM simulations where project = {} AND min_hgt_cor < 1.8" \ .format(self.configs['project_id']) results = self.p.query(query) mean = results[0][0] return [lower, mean] def vis_values(self): query = "SELECT count(*) FROM simulations where project = {} AND min_vis_cor < 30".format( self.configs['project_id']) results = self.p.query(query) lower = results[0][0] / self.total query = "SELECT avg(min_vis_compa) FROM simulations where project = {} AND min_vis_cor < 60".format( self.configs['project_id']) results = self.p.query(query) mean = results[0][0] return [lower, mean] def temp_values(self): query = "SELECT count(*) FROM simulations where project = {} AND max_temp > 450".format( self.configs['project_id']) results = self.p.query(query) lower = results[0][0] / self.total query = "SELECT avg(max_temp) FROM simulations where project = {} and dcbe_time is " \ "not null".format(self.configs['project_id']) results = self.p.query(query) mean = results[0][0] return [lower, mean] def calculate_building_area(self): s = Sqlite("{}/aamks.sqlite".format(self.dir)) result = s.p.query("SELECT sum(room_area) as total FROM aamks_geom") return result[0]['total']
class CfastMcarlo(): def __init__(self): # {{{ ''' Generate montecarlo cfast.in. Log what was drawn to psql. ''' self.json = Json() self.hrrpua = 0 self.alpha = 0 self.fire_origin = None self.conf = self.json.read("{}/conf.json".format( os.environ['AAMKS_PROJECT'])) if self.conf['fire_model'] == 'FDS': return self.s = Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT'])) self.p = Psql() self._psql_collector = OrderedDict() self.s.query( "CREATE TABLE fire_origin(name,is_room,x,y,z,floor,sim_id)") si = SimIterations(self.conf['project_id'], self.conf['scenario_id'], self.conf['number_of_simulations']) for self._sim_id in range(*si.get()): seed(self._sim_id) self._new_psql_log() self._make_cfast() self._write() # }}} # DISTRIBUTIONS / DRAWS def _draw_outdoor_temp(self): # {{{ outdoor_temp = round( normal(self.conf['outdoor_temperature']['mean'], self.conf['outdoor_temperature']['sd']), 2) self._psql_log_variable('outdoort', outdoor_temp) return outdoor_temp # }}} def _save_fire_origin(self, fire_origin): # {{{ fire_origin.append(self._sim_id) self.s.query('INSERT INTO fire_origin VALUES (?,?,?,?,?,?,?)', fire_origin) self._psql_log_variable('fireorigname', fire_origin[0]) self._psql_log_variable('fireorig', fire_origin[1]) # }}} def _draw_fire_origin(self): # {{{ is_origin_in_room = binomial(1, self.conf['fire_starts_in_a_room']) self.all_corridors_and_halls = [ z['name'] for z in self.s.query( "SELECT name FROM aamks_geom WHERE type_pri='COMPA' AND fire_model_ignore!=1 AND type_sec in('COR','HALL') ORDER BY global_type_id" ) ] self.all_rooms = [ z['name'] for z in self.s.query( "SELECT name FROM aamks_geom WHERE type_sec='ROOM' ORDER BY global_type_id" ) ] fire_origin = [] if is_origin_in_room == 1 or len(self.all_corridors_and_halls) == 0: fire_origin.append(str(choice(self.all_rooms))) fire_origin.append('room') else: fire_origin.append(str(choice(self.all_corridors_and_halls))) fire_origin.append('non_room') compa = self.s.query("SELECT * FROM aamks_geom WHERE name=?", (fire_origin[0], ))[0] x = int(compa['x0'] + compa['width'] / 2.0) y = int(compa['y0'] + compa['depth'] / 2.0) z = int(compa['height'] * (1 - math.log10(uniform(1, 10)))) fire_origin += [x, y, z] fire_origin += [compa['floor']] self._save_fire_origin(fire_origin) self.fire_origin = fire_origin collect = ('FIRE', compa['global_type_id'], round(compa['width'] / (2.0 * 100), 2), round(compa['depth'] / (2.0 * 100), 2), z, 1, 'TIME', '0', '0', '0', '0', 'medium') return (','.join(str(i) for i in collect)) # }}} def _fire_origin(self): # {{{ ''' Either deterministic fire from Apainter, or probabilistic (_draw_fire_origin()). ''' if len(self.s.query( "SELECT * FROM aamks_geom WHERE type_pri='FIRE'")) > 0: z = self.s.query("SELECT * FROM aamks_geom WHERE type_pri='FIRE'") i = z[0] x = i['center_x'] y = i['center_y'] z = i['z1'] - i['z0'] room = self.s.query( "SELECT floor,name,type_sec,global_type_id FROM aamks_geom WHERE floor=? AND type_pri='COMPA' AND fire_model_ignore!=1 AND x0<=? AND y0<=? AND x1>=? AND y1>=?", (i['floor'], i['x0'], i['y0'], i['x1'], i['y1'])) if room[0]['type_sec'] in ('COR', 'HALL'): fire_origin = [ room[0]['name'], 'non_room', x, y, z, room[0]['floor'] ] else: fire_origin = [ room[0]['name'], 'room', x, y, z, room[0]['floor'] ] self._save_fire_origin(fire_origin) collect = ('FIRE', room[0]['global_type_id'], x * 100, y * 100, z * 100, 1, 'TIME', '0', '0', '0', '0', 'medium') cfast_fire = (','.join(str(i) for i in collect)) else: cfast_fire = self._draw_fire_origin() return cfast_fire # }}} def _draw_fire_properties(self, intervals): # {{{ i = OrderedDict() i['coyield'] = round(uniform(0.01, 0.043), 3) i['sootyield'] = round(uniform(0.11, 0.17), 3) i['trace'] = 0 i['q_star'] = round(uniform(0.5, 2), 3) i['heigh'] = 0 i['radfrac'] = round(gamma(124.48, 0.00217), 3) i['heatcom'] = round(uniform(16400000, 27000000), 1) for k, v in i.items(): self._psql_log_variable(k, v) result = OrderedDict() result['sootyield'] = 'SOOT,{}'.format(','.join([str(i['sootyield'])] * intervals)) result['coyield'] = 'CO,{}'.format(','.join([str(i['coyield'])] * intervals)) result['trace'] = 'TRACE,{}'.format(','.join([str(i['trace'])] * intervals)) result['q_star'] = i['q_star'] result['heigh'] = 'HEIGH,{}'.format(','.join([str(i['heigh'])] * intervals)) result['radfrac'] = str(i['radfrac']) result['heatcom'] = str(i['heatcom']) return result # }}} def _draw_fire_development(self): # {{{ ''' Generate fire. Alpha t square on the left, then constant in the middle, then fading on the right. At the end read hrrs at given times. ''' hrrpua_d = self.conf['hrrpua'] hrr_alpha = self.conf['hrr_alpha'] ''' Fire area is draw from pareto distrubution regarding the BS PD-7974-7. There is lack of vent condition - underventilated fires ''' p = pareto(b=0.668, scale=0.775) fire_area = p.rvs(size=1)[0] fire_origin = self.fire_origin orig_area = self.s.query( "SELECT (width * depth)/10000 as area FROM aamks_geom WHERE name='{}'" .format(fire_origin[0]))[0]['area'] if fire_area > orig_area: fire_area = orig_area self.hrrpua = int( triangular(hrrpua_d['min'], hrrpua_d['mode'], hrrpua_d['max'])) hrr_peak = int(self.hrrpua * 1000 * fire_area) self.alpha = int( triangular(hrr_alpha['min'], hrr_alpha['mode'], hrr_alpha['max']) * 1000) self._psql_log_variable('hrrpeak', hrr_peak / 1000) self._psql_log_variable('alpha', self.alpha / 1000.0) # left t_up_to_hrr_peak = int((hrr_peak / self.alpha)**0.5) interval = int(round(t_up_to_hrr_peak / 10)) times0 = list(range(0, t_up_to_hrr_peak, interval)) + [t_up_to_hrr_peak] hrrs0 = [int((self.alpha * t**2)) for t in times0] # middle t_up_to_starts_dropping = 15 * 60 times1 = [t_up_to_starts_dropping] hrrs1 = [hrr_peak] # right t_up_to_drops_to_zero = t_up_to_starts_dropping + t_up_to_hrr_peak interval = int( round((t_up_to_drops_to_zero - t_up_to_starts_dropping) / 10)) times2 = list( range(t_up_to_starts_dropping, t_up_to_drops_to_zero, interval)) + [t_up_to_drops_to_zero] hrrs2 = [ int((self.alpha * (t - t_up_to_drops_to_zero)**2)) for t in times2 ] times = list(times0 + times1 + times2) hrrs = list(hrrs0 + hrrs1 + hrrs2) return times, hrrs # }}} def _draw_window_opening(self, outdoor_temp): # {{{ ''' Windows are open / close based on outside temperatures but even still, there's a distribution of users willing to open/close the windows. Windows can be full-open (1), quarter-open (0.25) or closed (0). ''' draw_value = uniform(0, 1) for i in self.conf['windows']: if outdoor_temp > i['min'] and outdoor_temp <= i['max']: if draw_value < i['full']: how_much_open = 1 elif draw_value < i['full'] + i['quarter']: how_much_open = 0.25 else: how_much_open = 0 self._psql_log_variable('w', how_much_open) return how_much_open # }}} def _draw_door_and_hole_opening(self, Type): # {{{ ''' Door may be open or closed, but Hole is always open and we don't need to log that. ''' vents = self.conf['vents_open'] if Type == 'HOLE': how_much_open = 1 else: how_much_open = binomial(1, vents[Type]) self._psql_log_variable(Type.lower(), how_much_open) return how_much_open # }}} def _draw_heat_detectors_triggers(self): # {{{ mean = self.conf['heat_detectors']['temp_mean'] sd = self.conf['heat_detectors']['temp_sd'] zero_or_one = binomial(1, self.conf['heat_detectors']['not_broken']) chosen = round(normal(mean, sd), 2) * zero_or_one self._psql_log_variable('heat_detectors', chosen) return str(chosen) # }}} def _draw_smoke_detectors_triggers(self): # {{{ mean = self.conf['smoke_detectors']['temp_mean'] sd = self.conf['smoke_detectors']['temp_sd'] zero_or_one = binomial(1, self.conf['smoke_detectors']['not_broken']) chosen = round(normal(mean, sd), 2) * zero_or_one self._psql_log_variable('smoke_detectors', chosen) return str(chosen) # }}} def _draw_sprinklers_triggers(self): # {{{ mean = self.conf['sprinklers']['temp_mean'] sd = self.conf['sprinklers']['temp_sd'] zero_or_one = binomial(1, self.conf['sprinklers']['not_broken']) chosen = round(normal(mean, sd), 2) * zero_or_one self._psql_log_variable('sprinklers', chosen) return str(chosen) # }}} def _psql_log_variable(self, attr, val): #{{{ self._psql_collector[self._sim_id][attr].append(val) # }}} # CFAST SECTIONS def _make_cfast(self): # {{{ ''' Compose cfast.in sections ''' outdoor_temp = self._draw_outdoor_temp() txt = ( self._section_preamble(outdoor_temp), self._section_matl(), self._section_compa(), self._section_halls_onez(), self._section_windows(outdoor_temp), self._section_doors_and_holes(), self._section_vvent(), self._section_mvent(), self._section_fire(), self._section_heat_detectors(), self._section_smoke_detectors(), self._section_sprinklers(), ) with open( "{}/workers/{}/cfast.in".format(os.environ['AAMKS_PROJECT'], self._sim_id), "w") as output: output.write("\n".join(filter(None, txt))) # }}} def _section_preamble(self, outdoor_temp): # {{{ ''' We use 600 as time, since Cfast will be killed by aamks. ''' txt = ( 'VERSN,7,{}_{}'.format('SIM', self.conf['project_id']), 'TIMES,{},-120,10,10'.format(self.conf['simulation_time']), 'EAMB,{},101300,0'.format(273 + outdoor_temp), 'TAMB,293.15,101300,0,50', 'DTCHECK,1.E-9,100', '', ) return "\n".join(txt) # }}} def _section_matl(self): # {{{ txt = ( '!! MATL,name,param1,param2,param3,param4,param5,param6', 'MATL,concrete,1.7,840,2500,0.4,0.9,concrete', 'MATL,gypsum,0.3,1000,1000,0.02,0.85,gipsum', 'MATL,glass,0.8,840,2500,0.013,0.9,glass', 'MATL,block,0.3,840,800,0.03,0.85,floor', 'MATL,brick,0.3,840,800,0.03,0.85,brick', '', ) return "\n".join(txt) # }}} def _section_compa(self): # {{{ txt = [ '!! COMPA,name,width,depth,height,x,y,z,matl_ceiling,matl_floor,matl_wall' ] for v in self.s.query( "SELECT * from aamks_geom WHERE type_pri='COMPA' AND fire_model_ignore!=1 ORDER BY global_type_id" ): collect = [] collect.append('COMPA') # COMPA collect.append(v['name']) # NAME collect.append(round(v['width'] / 100.0, 2)) # WIDTH collect.append(round(v['depth'] / 100.0, 2)) # DEPTH collect.append(round(v['height'] / 100.0, 2)) # INTERNAL_HEIGHT collect.append(round(v['x0'] / 100.0, 2)) # ABSOLUTE_X_POSITION collect.append(round(v['y0'] / 100.0, 2)) # ABSOLUTE_Y_POSITION collect.append(round(v['z0'] / 100.0, 2)) # ABSOLUTE_Z_POSITION collect.append(v['material_ceiling']) # CEILING_MATERIAL_NAME collect.append(v['material_floor']) # FLOOR_MATERIAL_NAME collect.append(v['material_wall']) # WALL_MATERIAL_NAME txt.append(','.join(str(i) for i in collect)) return "\n".join(txt) + "\n" if len(txt) > 1 else "" # }}} def _section_halls_onez(self): # {{{ txt = ['!! ONEZ,id'] for v in self.s.query( "SELECT * from aamks_geom WHERE type_sec in ('STAI', 'COR') AND fire_model_ignore!=1 order by type_sec" ): collect = [] if v['type_sec'] == 'COR': collect.append('HALL') else: collect.append('ONEZ') collect.append(v['global_type_id']) txt.append(','.join(str(i) for i in collect)) return "\n".join(txt) + "\n" if len(txt) > 1 else "" # }}} def _section_windows(self, outdoor_temp): # {{{ ''' Randomize how windows are opened/closed. ''' txt = ['!! WINDOWS, from,to,id,width,soffit,sill,offset,face,open'] windows_setup = [] for v in self.s.query( "SELECT * FROM aamks_geom WHERE type_tri='WIN' ORDER BY vent_from,vent_to" ): collect = [] collect.append('HVENT') # HVENT collect.append(v['vent_from']) # COMPARTMENT1 collect.append(v['vent_to']) # COMPARTMENT2 collect.append(v['hvent_room_seq']) # HVENT_NUMBER collect.append(round(v['cfast_width'] / 100.0, 2)) # WIDTH collect.append(round( (v['sill'] + v['height']) / 100.0, 2 )) # SOFFIT (height of the top of the hvent relative to the floor) collect.append(round(v['sill'] / 100.0, 2)) # SILL collect.append(round(v['face_offset'] / 100.0, 2)) # COMPARTMENT1_OFFSET collect.append(v['face']) # FACE how_much_open = self._draw_window_opening(outdoor_temp) windows_setup.append((how_much_open, v['name'])) collect.append(how_much_open) txt.append(','.join(str(i) for i in collect)) self.s.executemany( 'UPDATE aamks_geom SET how_much_open=? WHERE name=?', windows_setup) return "\n".join(txt) + "\n" if len(txt) > 1 else "" # }}} def _section_doors_and_holes(self): # {{{ ''' Randomize how doors are opened/close. ''' txt = ['!! DOORS, from,to,id,width,soffit,sill,offset,face,open'] hvents_setup = [] for v in self.s.query( "SELECT * FROM aamks_geom WHERE type_tri='DOOR' ORDER BY vent_from,vent_to" ): collect = [] collect.append('HVENT') # HVENT collect.append(v['vent_from']) # COMPARTMENT1 collect.append(v['vent_to']) # COMPARTMENT2 collect.append(v['hvent_room_seq']) # VENT_NUMBER collect.append(round(v['cfast_width'] / 100.0, 2)) # WIDTH collect.append(round( (v['sill'] + v['height']) / 100.0, 2 )) # SOFFIT (height of the top of the hvent relative to the floor) collect.append(round(v['sill'] / 100.0, 2)) # SILL collect.append(round(v['face_offset'] / 100.0, 2)) # COMPARTMENT1_OFFSET collect.append(v['face']) # FACE how_much_open = self._draw_door_and_hole_opening( v['type_sec']) # HOLE_CLOSE hvents_setup.append((how_much_open, v['name'])) collect.append(how_much_open) txt.append(','.join(str(i) for i in collect)) self.s.executemany( 'UPDATE aamks_geom SET how_much_open=? WHERE name=?', hvents_setup) return "\n".join(txt) + "\n" if len(txt) > 1 else "" # }}} def _section_vvent(self): # {{{ # VVENT AREA, SHAPE, INITIAL_FRACTION txt = [ '!! VVENT,top,bottom,id,area,shape,rel_type,criterion,target,i_time, i_frac, f_time, f_frac, offset_x, offset_y' ] #for v in self.s.query("SELECT distinct v.room_area, v.type_sec, v.vent_from, v.vent_to, v.vvent_room_seq, v.width, v.depth, (v.x0 - c.x0) + 0.5*v.width as x0, (v.y0 - c.y0) + 0.5*v.depth as y0 FROM aamks_geom v JOIN aamks_geom c on v.vent_to_name = c.name WHERE v.type_pri='VVENTS' AND c.type_pri = 'COMPA' ORDER BY v.vent_from,v.vent_to"): for v in self.s.query( "SELECT distinct v.room_area, v.type_sec, v.vent_from, v.vent_to, v.vvent_room_seq, v.width, v.depth, (v.x0 - c.x0) + 0.5*v.width as x0, (v.y0 - c.y0) + 0.5*v.depth as y0 FROM aamks_geom v JOIN aamks_geom c on v.vent_to_name = c.name WHERE v.type_sec='VVENT' ORDER BY v.vent_from,v.vent_to" ): collect = [] collect.append('VVENT') # VVENT AREA, SHAPE, INITIAL_FRACTION collect.append(v['vent_from']) # COMPARTMENT1 collect.append(v['vent_to']) # COMPARTMENT2 collect.append(v['vvent_room_seq']) # VENT_NUMBER collect.append( round((v['width'] * v['depth']) / 1e4, 2) ) # AREA OF THE ROOM, feb.2018: previously: round((v['width']*v['depth'])/1e4, 2) collect.append(2) # Type of dumper 1 - round, 2 - squere collect.append('TIME') # Type of realease collect.append('') # empty for time release collect.append('') # empty for time release collect.append(60) # start work on time collect.append(0) # intial state before triggering collect.append(120) # end work on time #collect.append(1) # end state with probability of working collect.append(self._draw_door_and_hole_opening( v['type_sec'])) # end state with probability of working collect.append(round(v['x0'] / 100, 2)) # Offset_x collect.append(round(v['y0'] / 100, 2)) # Offset_y txt.append(','.join(str(i) for i in collect)) return "\n".join(txt) + "\n" if len(txt) > 1 else "" # }}} def _section_mvent(self): # {{{ # VVENT AREA, SHAPE, INITIAL_FRACTION txt = [ '!!VVENT,first_comp,second_comp,id,orientation1,height_in,area_in,orientation2,height_out,area_out,flowm3/s,press_l,press_u,release,nix,nix,initial_time,initial_fraction,final_time,final_fraction' ] collect = [] #collect.append('MVENT,28,35,1,V,2.3,0.48,H,3,0.48,1.7,200,300,TIME,,,60,0,70,1,1,1') #collect.append('MVENT,28,35,2,V,2.3,0.48,H,3,0.48,1.7,200,300,TIME,,,60,0,70,1,2.5,1') #collect.append('MVENT,35,28,3,V,2.3,0.48,H,3,0.48,1.7,200,300,TIME,,,60,0,70,1,10,1') #collect.append('MVENT,35,28,4,V,2.3,0.48,H,3,0.48,1.7,200,300,TIME,,,60,0,70,1,11,1') #collect.append('MVENT,30,35,1,V,2.3,0.48,H,3,0.48,1.7,200,300,TIME,,,60,0,70,1,1,1') #collect.append('MVENT,31,35,2,V,2.3,0.48,H,3,0.48,1.7,200,300,TIME,,,60,0,70,1,1,1') #collect.append('MVENT,35,30,3,V,2.3,0.48,H,3,0.48,1.7,200,300,TIME,,,60,0,70,1,1,4') #collect.append('MVENT,35,31,4,V,2.3,0.48,H,3,0.48,1.7,200,300,TIME,,,60,0,70,1,2,1') txt.append('\n'.join(str(i) for i in collect)) return "\n".join(txt) + "\n" if len(txt) > 1 else "" # }}} def _section_heat_detectors(self): # {{{ txt = [ '!! DETECTORS,type,compa,temp,width,depth,height,rti,supress,density' ] for v in self.s.query( "SELECT * from aamks_geom WHERE type_pri='COMPA' AND fire_model_ignore!=1 AND heat_detectors=1" ): temp = self._draw_heat_detectors_triggers( ) # ACTIVATION_TEMPERATURE, if temp == '0.0': collect = [] else: collect = [] collect.append('DETECT') # DETECT, collect.append('HEAT') # TYPE: HEAT,SMOKE,SPRINKLER collect.append(v['global_type_id']) # COMPARTMENT, collect.append(temp) # ACTIVATION_TEMPERATURE, collect.append(round(v['width'] / (2.0 * 100), 2)) # WIDTH collect.append(round(v['depth'] / (2.0 * 100), 2)) # DEPTH collect.append(round(v['height'] / 100.0, 2)) # HEIGHT collect.append(80) # RTI, collect.append(0) # SUPPRESSION, collect.append(7E-05) # SPRAY_DENSITY txt.append(','.join(str(i) for i in collect)) return "\n".join(txt) + "\n" if len(txt) > 1 else "" # }}} def _section_smoke_detectors(self): # {{{ txt = [ '!! DETECTORS,type,compa,temp,width,depth,height,rti,supress,density' ] for v in self.s.query( "SELECT * from aamks_geom WHERE type_pri='COMPA' AND fire_model_ignore!=1 AND smoke_detectors=1" ): temp = self._draw_smoke_detectors_triggers( ) # ACTIVATION_TEMPERATURE, if temp == '0.0': collect = [] else: collect = [] collect.append('DETECT') # DETECT, collect.append('SMOKE') # TYPE: HEAT,SMOKE,SPRINKLER collect.append(v['global_type_id']) # COMPARTMENT, collect.append(temp) # ACTIVATION_TEMPERATURE, collect.append(round(v['width'] / (2.0 * 100), 2)) # WIDTH collect.append(round(v['depth'] / (2.0 * 100), 2)) # DEPTH collect.append(round(v['height'] / 100.0, 2)) # HEIGHT collect.append(80) # RTI, collect.append(0) # SUPPRESSION, collect.append(7E-05) # SPRAY_DENSITY txt.append(','.join(str(i) for i in collect)) return "\n".join(txt) + "\n" if len(txt) > 1 else "" # }}} def _section_sprinklers(self): # {{{ txt = [ '!! SPRINKLERS,type,compa,temp,width,depth,height,rti,supress,density' ] for v in self.s.query( "SELECT * from aamks_geom WHERE type_pri='COMPA' AND fire_model_ignore!=1 AND sprinklers=1" ): temp = self._draw_sprinklers_triggers() # ACTIVATION_TEMPERATURE, if temp == '0.0': collect = [] else: collect = [] collect.append('DETECT') # DETECT, collect.append('SPRINKLER') # TYPE: HEAT,SMOKE,SPRINKLER collect.append(v['global_type_id']) # COMPARTMENT, collect.append(temp) # ACTIVATION_TEMPERATURE, collect.append(round(v['width'] / (2.0 * 100), 2)) # WIDTH collect.append(round(v['depth'] / (2.0 * 100), 2)) # DEPTH collect.append(round(v['height'] / 100.0, 2)) # HEIGHT collect.append(50) # RTI, collect.append(1) # SUPPRESSION, collect.append(7E-05) # SPRAY_DENSITY txt.append(','.join(str(i) for i in collect)) return "\n".join(txt) + "\n" if len(txt) > 1 else "" # }}} def _section_fire(self): # {{{ fire_origin = self._fire_origin() times, hrrs = self._draw_fire_development() fire_properties = self._draw_fire_properties(len(times)) self._fire_obstacle() area = nround(npa(hrrs) / (self.hrrpua * 1000) + 0.1, decimals=1) fire_origin = self._fire_origin() txt = ( '!! FIRE,compa,x,y,z,fire_number,ignition_type,ignition_criterion,ignition_target,?,?,name', fire_origin, '', '!! CHEMI,?,?,?,?', 'CHEMI,1,1.8,0.3,0.05,0,0.283,{}'.format( fire_properties['heatcom']), '', 'TIME,' + ','.join(str(i) for i in times), 'HRR,' + ','.join(str(round(i, 3)) for i in hrrs), fire_properties['sootyield'], fire_properties['coyield'], fire_properties['trace'], 'AREA,' + ','.join(str(i) for i in area), fire_properties['heigh'], ) return "\n".join(txt) + "\n" # }}} def _new_psql_log(self): #{{{ ''' Init the collector for storing montecarlo cfast setup. Variables will be registered later one at a time. ''' self._psql_collector[self._sim_id] = OrderedDict([ ('fireorig', []), ('fireorigname', []), ('heat_detectors', []), ('smoke_detectors', []), ('hrrpeak', []), ('sootyield', []), ('coyield', []), ('alpha', []), ('trace', []), ('area', []), ('q_star', []), ('heigh', []), ('w', []), ('outdoort', []), ('dcloser', []), ('door', []), ('sprinklers', []), ('heatcom', []), ('delectr', []), ('vvent', []), ('radfrac', []), ]) #}}} def _write(self): #{{{ ''' Write cfast variables to postgres. Both column names and the values for psql come from trusted source, so there should be no security issues with just joining dict data (non-parametrized query). ''' pairs = [] for k, v in self._psql_collector[self._sim_id].items(): pairs.append("{}='{}'".format(k, ','.join(str(x) for x in v))) data = ', '.join(pairs) self.p.query( "UPDATE simulations SET {} WHERE project=%s AND scenario_id=%s AND iteration=%s" .format(data), (self.conf['project_id'], self.conf['scenario_id'], self._sim_id))
class OnInit(): def __init__(self): # {{{ ''' Stuff that happens at the beggining of the project ''' if len(sys.argv) > 1: os.environ["AAMKS_PROJECT"] = sys.argv[1] self.json = Json() self.conf = self.json.read("{}/conf.json".format( os.environ['AAMKS_PROJECT'])) self.project_id = self.conf['project_id'] self.scenario_id = self.conf['scenario_id'] self.p = Psql() self._clear_srv_anims() self._clear_sqlite() self._setup_simulations() # }}} def _clear_srv_anims(self): # {{{ ''' Need to detect and remove obsolete srv animations. Server always overwrites anims.json and we need to prevent the dumplicates in Animator right menu entries. We try: because there may be no anims.json just yet. TODO: it is possible we could just remove this file and remove all server animations. But would it hurt workers animations? ''' try: anims = self.json.read("{}/workers/anims.json".format( os.environ['AAMKS_PROJECT'])) new_anims = [] for a in anims: if a['srv'] != 1: new_anims.append(a) self.json.write( new_anims, "{}/workers/anims.json".format(os.environ['AAMKS_PROJECT'])) except: pass # }}} def _clear_sqlite(self): # {{{ try: os.remove("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT'])) except: pass # }}} def _create_iterations_sequence(self): # {{{ ''' For a given project we may run simulation 0 to 999. Then we may wish to run 100 simulations more and have them numbered here: from=1000 to=1099 These from and to numbers are unique for the project and are used as rand seeds in later aamks modules. This is similar, but distinct from SimIterations() - we are creating the sequence, and the later reads the sequence from/to. Remember that range(1,4) returns 1,2,3; hence SELECT max(iteration)+1 ''' how_many = self.conf['number_of_simulations'] r = [] try: # If the project already exists in simulations table (e.g. adding 100 simulations to existing 1000); try: fails on addition on int+None. r.append( self.p.query( 'SELECT max(iteration)+1 FROM simulations WHERE project=%s AND scenario_id=%s', (self.project_id, self.scenario_id))[0][0]) r.append(r[0] + how_many) except: # If a new project r = [1, how_many + 1] return r # }}} def _setup_simulations(self): # {{{ ''' Simulation dir maps to id from psql's simulations table''' workers_dir = "{}/workers".format(os.environ['AAMKS_PROJECT']) os.makedirs(workers_dir, exist_ok=True) irange = self._create_iterations_sequence() for i in range(*irange): sim_dir = "{}/{}".format(workers_dir, i) os.makedirs(sim_dir, exist_ok=True) self.p.query( "INSERT INTO simulations(iteration,project,scenario_id) VALUES(%s,%s,%s)", (i, self.project_id, self.scenario_id))