def handle(self, *args, **options): vals = FireDepartment.objects.filter(dist_model_score__isnull=True) dists = [] with PostgresBackend(dict(host='localhost')) as backend: for fd in vals: results = backend.get_firespread_counts(query=RESIDENTIAL_FIRES_BY_FDID_STATE, query_params=(fd.fdid, fd.state)) ahs_building_size = ahs_building_areas(fd.fdid, fd.state) if ahs_building_size is not None: results.update(dict(building_area_draw=ahs_building_size)) dist = DIST(floor_extent=False, **results) try: fd.dist_model_score = dist.gibbs_sample() except ZeroDivisionError: continue #print 'Updating {0} with the new DIST score: {1}.'.format(fd.name, fd.dist_model_score) if not options.get('dry_run'): fd.save() dists.append((fd.id, fd.dist_model_score)) print 'Updated dist scores: ', dists
def update_performance_score(id, dry_run=False): """ Updates department performance scores. """ try: cursor = connections['nfirs'].cursor() fd = FireDepartment.objects.get(id=id) except (ConnectionDoesNotExist, FireDepartment.DoesNotExist): return cursor.execute(RESIDENTIAL_FIRES_BY_FDID_STATE, (fd.fdid, fd.state)) results = dictfetchall(cursor) old_score = fd.dist_model_score counts = dict(object_of_origin=0, room_of_origin=0, floor_of_origin=0, building_of_origin=0, beyond=0) for result in results: if result['fire_sprd'] == '1': counts['object_of_origin'] += result['count'] if result['fire_sprd'] == '2': counts['room_of_origin'] += result['count'] if result['fire_sprd'] == '3': counts['floor_of_origin'] += result['count'] if result['fire_sprd'] == '4': counts['building_of_origin'] += result['count'] if result['fire_sprd'] == '5': counts['beyond'] += result['count'] ahs_building_size = ahs_building_areas(fd.fdid, fd.state) if ahs_building_size is not None: counts['building_area_draw'] = ahs_building_size response_times = response_time_distributions.get('{0}-{1}'.format(fd.fdid, fd.state)) if response_times: counts['arrival_time_draw'] = LogNormalDraw(*response_times, multiplier=60) try: dist = DIST(floor_extent=False, **counts) fd.dist_model_score = dist.gibbs_sample() except (NotEnoughRecords, ZeroDivisionError): fd.dist_model_score = None print 'updating fdid: {2} from: {0} to {1}.'.format(old_score, fd.dist_model_score, fd.id) if dry_run: return fd.save()
def update_performance_score(id, dry_run=False): """ Updates department performance scores. """ print "updating performance score for {}".format(id) try: cursor = connections['nfirs'].cursor() fd = FireDepartment.objects.get(id=id) except (ConnectionDoesNotExist, FireDepartment.DoesNotExist): return # Hack to get around inline SQL string execution and argument escaping in a tuple fds = ["''{}''".format(x) for x in fd.fdids] RESIDENTIAL_FIRES_BY_FDID_STATE = """ SELECT * FROM crosstab( 'select COALESCE(y.risk_category, ''N/A'') as risk_category, fire_sprd, count(*) FROM joint_buildingfires a left join ( SELECT state, fdid, inc_date, inc_no, exp_no, geom, x.parcel_id, x.risk_category FROM (select * from joint_incidentaddress a left join parcel_risk_category_local b using (parcel_id) ) AS x ) AS y using (state, inc_date, exp_no, fdid, inc_no) where a.state='%(state)s' and a.fdid in ({fds}) and prop_use in (''419'',''429'',''439'',''449'',''459'',''460'',''462'',''464'',''400'') and fire_sprd is not null and fire_sprd != '''' group by risk_category, fire_sprd order by risk_category, fire_sprd ASC') AS ct(risk_category text, "object_of_origin" bigint, "room_of_origin" bigint, "floor_of_origin" bigint, "building_of_origin" bigint, "beyond" bigint); """.format(fds=','.join(fds)) cursor.execute(RESIDENTIAL_FIRES_BY_FDID_STATE, {'state': fd.state}) results = dictfetchall(cursor) all_counts = dict(object_of_origin=0, room_of_origin=0, floor_of_origin=0, building_of_origin=0, beyond=0) risk_mapping = {'Low': 1, 'Medium': 2, 'High': 4, 'N/A': 5} ahs_building_size = ahs_building_areas(fd.fdid, fd.state) for result in results: if result.get('risk_category') not in risk_mapping: continue dist_model = dist_model_for_hazard_level(result.get('risk_category')) # Use floor draws based on the LogNormal of the structure type distribution for med/high risk categories # TODO: Detect support for number_of_floors_draw on risk model vs being explicit on hazard levels used :/ if result.get('risk_category') in ['Medium', 'High']: rm, _ = fd.firedepartmentriskmodels_set.get_or_create( level=risk_mapping[result['risk_category']]) if rm.floor_count_coefficients: pass # TODO # dist_model.number_of_floors_draw = LogNormalDraw(*rm.floor_count_coefficients) counts = dict(object_of_origin=result['object_of_origin'] or 0, room_of_origin=result['room_of_origin'] or 0, floor_of_origin=result['floor_of_origin'] or 0, building_of_origin=result['building_of_origin'] or 0, beyond=result['beyond'] or 0) # add current risk category to the all risk category for key, value in counts.items(): all_counts[key] += value if ahs_building_size is not None: counts['building_area_draw'] = ahs_building_size response_times = response_time_distributions.get('{0}-{1}'.format( fd.fdid, fd.state)) if response_times: counts['arrival_time_draw'] = LogNormalDraw(*response_times, multiplier=60) record, _ = fd.firedepartmentriskmodels_set.get_or_create( level=risk_mapping[result['risk_category']]) old_score = record.dist_model_score try: dist = dist_model(floor_extent=False, **counts) record.dist_model_score = dist.gibbs_sample() record.dist_model_score_fire_count = dist.total_fires print 'updating fdid: {2} - {3} performance score from: {0} to {1}.'.format( old_score, record.dist_model_score, fd.id, HazardLevels(record.level).name) except (NotEnoughRecords, ZeroDivisionError): print 'Error updating DIST score: {}.'.format( traceback.format_exc()) record.dist_model_score = None if not dry_run: record.save() # Clear out scores for missing hazard levels if not dry_run: missing_categories = set(risk_mapping.keys()) - set( map(lambda x: x.get('risk_category'), results)) for r in missing_categories: print 'clearing {0} level from {1} due to missing categories in aggregation'.format( r, fd.id) record, _ = fd.firedepartmentriskmodels_set.get_or_create( level=risk_mapping[r]) record.dist_model_score = None record.save() record, _ = fd.firedepartmentriskmodels_set.get_or_create( level=HazardLevels.All.value) old_score = record.dist_model_score dist_model = dist_model_for_hazard_level('All') try: if ahs_building_size is not None: all_counts['building_area_draw'] = ahs_building_size response_times = response_time_distributions.get('{0}-{1}'.format( fd.fdid, fd.state)) if response_times: all_counts['arrival_time_draw'] = LogNormalDraw(*response_times, multiplier=60) dist = dist_model(floor_extent=False, **all_counts) record.dist_model_score = dist.gibbs_sample() print 'updating fdid: {2} - {3} performance score from: {0} to {1}.'.format( old_score, record.dist_model_score, fd.id, HazardLevels(record.level).name) except (NotEnoughRecords, ZeroDivisionError): print 'Error updating DIST score: {}.'.format(traceback.format_exc()) record.dist_model_score = None if not dry_run: record.save() print "...updated performance score for {}".format(id)