def update(self, area_key): # Select all cells in this area and derive a bounding box for them cell_query = (self.cell_model.querykey(self.session, area_key) .filter(self.cell_model.lat.isnot(None)) .filter(self.cell_model.lon.isnot(None))) cells = cell_query.all() area_query = self.cell_area_model.querykey(self.session, area_key) if len(cells) == 0: # If there are no more underlying cells, delete the area entry area_query.delete() else: # Otherwise update the area entry based on all the cells area = area_query.first() points = [(c.lat, c.lon) for c in cells] min_lat = min([c.min_lat for c in cells]) min_lon = min([c.min_lon for c in cells]) max_lat = max([c.max_lat for c in cells]) max_lon = max([c.max_lon for c in cells]) bbox_points = [(min_lat, min_lon), (min_lat, max_lon), (max_lat, min_lon), (max_lat, max_lon)] ctr = centroid(points) rng = range_to_points(ctr, bbox_points) # Switch units back to meters ctr_lat = ctr[0] ctr_lon = ctr[1] rng = int(round(rng * 1000.0)) # Now create or update the area num_cells = len(cells) avg_cell_range = int(sum( [cell.range for cell in cells]) / float(num_cells)) if area is None: area = self.cell_area_model( created=self.utcnow, modified=self.utcnow, lat=ctr_lat, lon=ctr_lon, range=rng, avg_cell_range=avg_cell_range, num_cells=num_cells, **area_key.__dict__) self.session.add(area) else: area.modified = self.utcnow area.lat = ctr_lat area.lon = ctr_lon area.range = rng area.avg_cell_range = avg_cell_range area.num_cells = num_cells
def update_lac(self, radio, mcc, mnc, lac): with self.db_session() as session: # Select all the cells in this LAC that aren't the virtual # cell itself, and derive a bounding box for them. q = session.query(Cell).filter(Cell.radio == radio).filter( Cell.mcc == mcc).filter(Cell.mnc == mnc).filter( Cell.lac == lac).filter(Cell.cid != CELLID_LAC) cells = q.all() points = [(to_degrees(c.lat), to_degrees(c.lon)) for c in cells] min_lat = to_degrees(min([c.min_lat for c in cells])) min_lon = to_degrees(min([c.min_lon for c in cells])) max_lat = to_degrees(max([c.max_lat for c in cells])) max_lon = to_degrees(max([c.max_lon for c in cells])) bbox_points = [(min_lat, min_lon), (min_lat, max_lon), (max_lat, min_lon), (max_lat, max_lon)] ctr = centroid(points) rng = range_to_points(ctr, bbox_points) # switch units back to DB preferred centimicrodegres angle # and meters distance. ctr_lat = from_degrees(ctr[0]) ctr_lon = from_degrees(ctr[1]) rng = int(round(rng * 1000.0)) # Now create or update the LAC virtual cell q = session.query(Cell).filter(Cell.radio == radio).filter( Cell.mcc == mcc).filter(Cell.mnc == mnc).filter( Cell.lac == lac).filter(Cell.cid == CELLID_LAC) lac = q.first() if lac is None: lac = Cell(radio=radio, mcc=mcc, mnc=mnc, lac=lac, cid=CELLID_LAC, lat=ctr_lat, lon=ctr_lon, range=rng) else: lac.new_measures = 0 lac.lat = ctr_lat lac.lon = ctr_lon lac.range = rng session.commit()
def update(self, area_key): # Select all cells in this area and derive a bounding box for them cell_query = (self.cell_model.querykey(self.session, area_key).filter( self.cell_model.lat.isnot(None)).filter( self.cell_model.lon.isnot(None))) cells = cell_query.all() area_query = self.cell_area_model.querykey(self.session, area_key) if len(cells) == 0: # If there are no more underlying cells, delete the area entry area_query.delete() else: # Otherwise update the area entry based on all the cells area = area_query.first() points = [(c.lat, c.lon) for c in cells] min_lat = min([c.min_lat for c in cells]) min_lon = min([c.min_lon for c in cells]) max_lat = max([c.max_lat for c in cells]) max_lon = max([c.max_lon for c in cells]) bbox_points = [(min_lat, min_lon), (min_lat, max_lon), (max_lat, min_lon), (max_lat, max_lon)] ctr = centroid(points) rng = range_to_points(ctr, bbox_points) # Switch units back to meters ctr_lat = ctr[0] ctr_lon = ctr[1] rng = int(round(rng * 1000.0)) # Now create or update the area num_cells = len(cells) avg_cell_range = int( sum([cell.range for cell in cells]) / float(num_cells)) if area is None: area = self.cell_area_model(created=self.utcnow, modified=self.utcnow, lat=ctr_lat, lon=ctr_lon, range=rng, avg_cell_range=avg_cell_range, num_cells=num_cells, **area_key.__dict__) self.session.add(area) else: area.modified = self.utcnow area.lat = ctr_lat area.lon = ctr_lon area.range = rng area.avg_cell_range = avg_cell_range area.num_cells = num_cells
def update_lac(self, radio, mcc, mnc, lac): with self.db_session() as session: # Select all the cells in this LAC that aren't the virtual # cell itself, and derive a bounding box for them. q = session.query(Cell).filter( Cell.radio == radio).filter( Cell.mcc == mcc).filter( Cell.mnc == mnc).filter( Cell.lac == lac).filter( Cell.cid != CELLID_LAC).filter( Cell.new_measures == 0).filter( Cell.lat.isnot(None)).filter( Cell.lon.isnot(None)) cells = q.all() if len(cells) == 0: return points = [(to_degrees(c.lat), to_degrees(c.lon)) for c in cells] min_lat = to_degrees(min([c.min_lat for c in cells])) min_lon = to_degrees(min([c.min_lon for c in cells])) max_lat = to_degrees(max([c.max_lat for c in cells])) max_lon = to_degrees(max([c.max_lon for c in cells])) bbox_points = [(min_lat, min_lon), (min_lat, max_lon), (max_lat, min_lon), (max_lat, max_lon)] ctr = centroid(points) rng = range_to_points(ctr, bbox_points) # switch units back to DB preferred centimicrodegres angle # and meters distance. ctr_lat = from_degrees(ctr[0]) ctr_lon = from_degrees(ctr[1]) rng = int(round(rng * 1000.0)) # Now create or update the LAC virtual cell q = session.query(Cell).filter( Cell.radio == radio).filter( Cell.mcc == mcc).filter( Cell.mnc == mnc).filter( Cell.lac == lac).filter( Cell.cid == CELLID_LAC) lac = q.first() if lac is None: lac = Cell(radio=radio, mcc=mcc, mnc=mnc, lac=lac, cid=CELLID_LAC, lat=ctr_lat, lon=ctr_lon, range=rng) else: lac.new_measures = 0 lac.lat = ctr_lat lac.lon = ctr_lon lac.range = rng session.commit()
def calculate_new_position(station, measures, moving_stations, max_dist_km, backfill=True): # if backfill is true, we work on older measures for which # the new/total counters where never updated length = len(measures) latitudes = [w[0] for w in measures] longitudes = [w[1] for w in measures] new_lat = sum(latitudes) // length new_lon = sum(longitudes) // length if station.lat and station.lon: latitudes.append(station.lat) longitudes.append(station.lon) existing_station = True else: station.lat = new_lat station.lon = new_lon existing_station = False # calculate extremes of measures, existing location estimate # and existing extreme values def extreme(vals, attr, function): new = function(vals) old = getattr(station, attr, None) if old is not None: return function(new, old) else: return new min_lat = extreme(latitudes, 'min_lat', min) min_lon = extreme(longitudes, 'min_lon', min) max_lat = extreme(latitudes, 'max_lat', max) max_lon = extreme(longitudes, 'max_lon', max) # calculate sphere-distance from opposite corners of # bounding box containing current location estimate # and new measurements; if too big, station is moving box_dist = distance(to_degrees(min_lat), to_degrees(min_lon), to_degrees(max_lat), to_degrees(max_lon)) if existing_station: if box_dist > max_dist_km: # add to moving list, return early without updating # station since it will be deleted by caller momentarily moving_stations.add(station) return if backfill: new_total = station.total_measures + length old_length = station.total_measures # update total to account for new measures # new counter never got updated to include the measures station.total_measures = new_total else: new_total = station.total_measures old_length = new_total - length station.lat = ((station.lat * old_length) + (new_lat * length)) // new_total station.lon = ((station.lon * old_length) + (new_lon * length)) // new_total if not backfill: # decrease new counter, total is already correct # in the backfill case new counter was never increased station.new_measures = station.new_measures - length # update max/min lat/lon columns station.min_lat = min_lat station.min_lon = min_lon station.max_lat = max_lat station.max_lon = max_lon # give radio-range estimate between extreme values and centroid ctr = (to_degrees(station.lat), to_degrees(station.lon)) points = [(to_degrees(min_lat), to_degrees(min_lon)), (to_degrees(min_lat), to_degrees(max_lon)), (to_degrees(max_lat), to_degrees(min_lon)), (to_degrees(max_lat), to_degrees(max_lon))] station.range = range_to_points(ctr, points) * 1000.0
def calculate_new_position(self, station, observations): # This function returns True if the station was found to be moving. length = len(observations) latitudes = [obs.lat for obs in observations] longitudes = [obs.lon for obs in observations] new_lat = sum(latitudes) / length new_lon = sum(longitudes) / length if station.lat and station.lon: latitudes.append(station.lat) longitudes.append(station.lon) existing_station = True else: station.lat = new_lat station.lon = new_lon existing_station = False # calculate extremes of observations, existing location estimate # and existing extreme values def extreme(vals, attr, function): new = function(vals) old = getattr(station, attr, None) if old is not None: return function(new, old) else: return new min_lat = extreme(latitudes, 'min_lat', min) min_lon = extreme(longitudes, 'min_lon', min) max_lat = extreme(latitudes, 'max_lat', max) max_lon = extreme(longitudes, 'max_lon', max) # calculate sphere-distance from opposite corners of # bounding box containing current location estimate # and new observations; if too big, station is moving box_dist = distance(min_lat, min_lon, max_lat, max_lon) if existing_station: if box_dist > self.max_dist_km: # Signal a moving station and return early without updating # the station since it will be deleted by caller momentarily return True # limit the maximum weight of the old station estimate old_weight = min(station.total_measures - length, self.MAX_OLD_OBSERVATIONS) new_weight = old_weight + length station.lat = ((station.lat * old_weight) + (new_lat * length)) / new_weight station.lon = ((station.lon * old_weight) + (new_lon * length)) / new_weight # decrease new counter, total is already correct station.new_measures = station.new_measures - length # update max/min lat/lon columns station.min_lat = min_lat station.min_lon = min_lon station.max_lat = max_lat station.max_lon = max_lon # give radio-range estimate between extreme values and centroid ctr = (station.lat, station.lon) points = [(min_lat, min_lon), (min_lat, max_lon), (max_lat, min_lon), (max_lat, max_lon)] station.range = range_to_points(ctr, points) * 1000.0 station.modified = util.utcnow()
def update_lac(self, radio, mcc, mnc, lac): try: utcnow = util.utcnow() with self.db_session() as session: # Select all the cells in this LAC that aren't the virtual # cell itself, and derive a bounding box for them. cell_query = session.query(Cell).filter( Cell.radio == radio).filter( Cell.mcc == mcc).filter( Cell.mnc == mnc).filter( Cell.lac == lac).filter( Cell.cid != CELLID_LAC).filter( Cell.lat.isnot(None)).filter( Cell.lon.isnot(None)) cells = cell_query.all() lac_query = session.query(Cell).filter( Cell.radio == radio).filter( Cell.mcc == mcc).filter( Cell.mnc == mnc).filter( Cell.lac == lac).filter( Cell.cid == CELLID_LAC) if len(cells) == 0: # If there are no more underlying cells, delete the lac entry lac_query.delete() else: # Otherwise update the lac entry based on all the cells lac_obj = lac_query.first() points = [(c.lat, c.lon) for c in cells] min_lat = min([c.min_lat for c in cells]) min_lon = min([c.min_lon for c in cells]) max_lat = max([c.max_lat for c in cells]) max_lon = max([c.max_lon for c in cells]) bbox_points = [(min_lat, min_lon), (min_lat, max_lon), (max_lat, min_lon), (max_lat, max_lon)] ctr = centroid(points) rng = range_to_points(ctr, bbox_points) # Switch units back to DB preferred centimicrodegres angle # and meters distance. ctr_lat = ctr[0] ctr_lon = ctr[1] rng = int(round(rng * 1000.0)) # Now create or update the LAC virtual cell if lac_obj is None: lac_obj = Cell(radio=radio, mcc=mcc, mnc=mnc, lac=lac, cid=CELLID_LAC, lat=ctr_lat, lon=ctr_lon, created=utcnow, modified=utcnow, range=rng, total_measures=len(cells)) session.add(lac_obj) else: lac_obj.total_measures = len(cells) lac_obj.lat = ctr_lat lac_obj.lon = ctr_lon lac_obj.modified = utcnow lac_obj.range = rng session.commit() except Exception as exc: # pragma: no cover self.heka_client.raven('error') raise self.retry(exc=exc)
def update_lac(self, radio, mcc, mnc, lac, cell_model_key='cell', cell_area_model_key='cell_area'): utcnow = util.utcnow() with self.db_session() as session: # Select all the cells in this LAC that aren't the virtual # cell itself, and derive a bounding box for them. cell_model = CELL_MODEL_KEYS[cell_model_key] cell_query = (session.query(cell_model).filter( cell_model.radio == radio).filter(cell_model.mcc == mcc).filter( cell_model.mnc == mnc).filter(cell_model.lac == lac).filter( cell_model.lat.isnot(None)).filter( cell_model.lon.isnot(None))) cells = cell_query.all() cell_area_model = CELL_MODEL_KEYS[cell_area_model_key] lac_query = (session.query(cell_area_model).filter( cell_area_model.radio == radio).filter( cell_area_model.mcc == mcc).filter( cell_area_model.mnc == mnc).filter( cell_area_model.lac == lac)) if len(cells) == 0: # If there are no more underlying cells, delete the lac entry lac_query.delete() else: # Otherwise update the lac entry based on all the cells lac_obj = lac_query.first() points = [(c.lat, c.lon) for c in cells] min_lat = min([c.min_lat for c in cells]) min_lon = min([c.min_lon for c in cells]) max_lat = max([c.max_lat for c in cells]) max_lon = max([c.max_lon for c in cells]) bbox_points = [(min_lat, min_lon), (min_lat, max_lon), (max_lat, min_lon), (max_lat, max_lon)] ctr = centroid(points) rng = range_to_points(ctr, bbox_points) # Switch units back to DB preferred centimicrodegres angle # and meters distance. ctr_lat = ctr[0] ctr_lon = ctr[1] rng = int(round(rng * 1000.0)) # Now create or update the LAC virtual cell num_cells = len(cells) avg_cell_range = int( sum([cell.range for cell in cells]) / float(num_cells)) if lac_obj is None: lac_obj = cell_area_model( created=utcnow, modified=utcnow, radio=radio, mcc=mcc, mnc=mnc, lac=lac, lat=ctr_lat, lon=ctr_lon, range=rng, avg_cell_range=avg_cell_range, num_cells=num_cells, ) session.add(lac_obj) else: lac_obj.modified = utcnow lac_obj.lat = ctr_lat lac_obj.lon = ctr_lon lac_obj.range = rng lac_obj.avg_cell_range = avg_cell_range lac_obj.num_cells = num_cells session.commit()
def update_lac(self, radio, mcc, mnc, lac): try: utcnow = util.utcnow() with self.db_session() as session: # Select all the cells in this LAC that aren't the virtual # cell itself, and derive a bounding box for them. cell_query = session.query(Cell).filter( Cell.radio == radio).filter(Cell.mcc == mcc).filter( Cell.mnc == mnc).filter( Cell.lac == lac).filter(Cell.cid != CELLID_LAC).filter( Cell.lat.isnot(None)).filter(Cell.lon.isnot(None)) cells = cell_query.all() lac_query = session.query(Cell).filter(Cell.radio == radio).filter( Cell.mcc == mcc).filter(Cell.mnc == mnc).filter( Cell.lac == lac).filter(Cell.cid == CELLID_LAC) if len(cells) == 0: # If there are no more underlying cells, delete the lac entry lac_query.delete() else: # Otherwise update the lac entry based on all the cells lac_obj = lac_query.first() points = [(c.lat, c.lon) for c in cells] min_lat = min([c.min_lat for c in cells]) min_lon = min([c.min_lon for c in cells]) max_lat = max([c.max_lat for c in cells]) max_lon = max([c.max_lon for c in cells]) bbox_points = [(min_lat, min_lon), (min_lat, max_lon), (max_lat, min_lon), (max_lat, max_lon)] ctr = centroid(points) rng = range_to_points(ctr, bbox_points) # Switch units back to DB preferred centimicrodegres angle # and meters distance. ctr_lat = ctr[0] ctr_lon = ctr[1] rng = int(round(rng * 1000.0)) # Now create or update the LAC virtual cell if lac_obj is None: lac_obj = Cell(radio=radio, mcc=mcc, mnc=mnc, lac=lac, cid=CELLID_LAC, lat=ctr_lat, lon=ctr_lon, created=utcnow, modified=utcnow, range=rng, total_measures=len(cells)) session.add(lac_obj) else: lac_obj.total_measures = len(cells) lac_obj.lat = ctr_lat lac_obj.lon = ctr_lon lac_obj.modified = utcnow lac_obj.range = rng session.commit() except Exception as exc: # pragma: no cover self.heka_client.raven('error') raise self.retry(exc=exc)