import os import json import random from datetime import datetime from server.consts import LAKE_RELATIONS_PATH from server.ModelFromNVE.icemodellingscripts.getIceThicknessLakes import get_raw_dates, ice_prognosis_raw_data def get_measurements(self, lake_name): """ Retrieves LiDar data for a given lake, and adds weather data to each subdivision. Parameters: self (BaseHTTPRequestHandler): A instance of a BaseHTTPRequestHandler lake_name (str): The name of the requested file/lake """ try: # Define file path to lidar data file file_path = os.path.join(LAKE_RELATIONS_PATH, lake_name + '_lidar_data.json') # Lists to store processed data sub_div_ids = [] measurements = [] # Some lakes may not have any recent lidar data, so must check if the file exists if os.path.exists(file_path): # Read the newest lidar data from JSON file with open(file_path, 'r') as file: lidar_data = json.load(file) # Iterate over all fetched rows for measurement in lidar_data: processed_subdivs = [] # Create new measurement object new_measurement = { 'MeasurementID': measurement['MeasurementID'], 'TimeMeasured': str(datetime.now()), 'CenterLat': measurement['CenterLat'], 'CenterLon': measurement['CenterLon'], 'Sensor': measurement['Sensor'], 'Subdivisions': [], } for sub_division in measurement['Subdivisions']: subdiv_id = sub_division['SubdivID'] center_lat = sub_division['CenLatitude'] center_lng = sub_division['CenLongitude'] thicknesses = sub_division['Heights'] # Create new subdivision object sub_division = { 'SubdivID': subdiv_id, 'GroupID': 0, 'MinThickness': sub_division['MinThickness'], 'AvgThickness': sub_division['AvgThickness'], 'CenLatitude': center_lat, 'CenLongitude': center_lng, 'Accuracy': sub_division['Accuracy'], 'Color': calculateColor(sub_division['MinThickness'], ), # NB color calculated based on average thickness, should be minimum # Fetch weather data from the NVE model 'IceStats': get_raw_dates( ice_prognosis_raw_data(sub_div_id=subdiv_id, x=center_lat, y=center_lng)) } sub_div_ids.append(subdiv_id) # Append processed subdivision data processed_subdivs.append(sub_division) # Append processed measurement and subdivisions new_measurement['Subdivisions'].append(processed_subdivs) measurements.append(new_measurement) # Populate remaining non-processed subdivisions and create "invalid" or "proxy" measurement to store them remaining_sub_divs = fill_remaining_subdivisions(lake_name, sub_div_ids) print("Len remaining_sub_divs: ", len(remaining_sub_divs)) print("Sub_div_ids: ", sub_div_ids) print("Len measurements: ", len(measurements)) measurements[-1] = { 'MeasurementID': -1, 'TimeMeasured': str(datetime.now()), 'CenterLat': None, 'CenterLon': None, 'Sensor': None, 'Subdivisions': remaining_sub_divs } # Write the newest measurements to file with open(LAKE_RELATIONS_PATH + lake_name.lower() + '_measurements.json', 'w') as f: json.dump(measurements, f) if len(measurements) == 0: response_data = json.dumps(['no measurements']) else: # Convert list of dictionaries to JSON response_data = json.dumps(measurements, indent=4) except Exception as e: print(f"Error in getting measurements: {e}") response_data = '[]' # Set headers self.send_response(500) self.send_header("Content-type", "application/json") self.end_headers() # Set headers self.send_response(200) self.send_header("Content-type", "application/json") self.end_headers() # Write processed data to response object self.wfile.write(response_data.encode('utf-8')) def fill_remaining_subdivisions(lake_name: str, sub_div_ids: list): """ Returns a list of subdivision dictionaries for subdivisions without measurements. Parameters: lake_name (str): The name of the requested file/lake sub_div_ids (list): A list of ids (int) of all subdivisions that have already been processed Returns: sub_divisions (list): A list of subdivision dictionaries """ try: # Read the lake relation for the requested lake with open(LAKE_RELATIONS_PATH + lake_name + '_div.json', 'r') as file: relation = json.load(file) sub_divisions = [] # Loop through each feature and extract all subdivisions for sub_div in relation['features']: sub_div_id = int(sub_div['properties']['sub_div_id']) # Only get subdivisions that are not in the list if sub_div_id not in sub_div_ids: center_lat = sub_div['properties']['sub_div_center'][0] center_lng = sub_div['properties']['sub_div_center'][1] # Fetch weather data for each subdivision from the NVE model ice_stats = get_raw_dates(ice_prognosis_raw_data(sub_div_id=sub_div_id, x=center_lat, y=center_lng)) total_ice_thickness = ice_stats[0]['Total ice (m)'] # Create new subdivision object sub_division = { 'SubdivID': sub_div_id, 'GroupID': None, 'MinThickness': total_ice_thickness, 'AvgThickness': total_ice_thickness, 'CenLatitude': center_lat, 'CenLongitude': center_lng, 'Accuracy': None, # Calculate ice thickness based on total ice, temporary # 'Color': calculateColor(ice_stats[0]['Total ice (m)']), 'Color': calculateColor(random.randint(0, 20)), # NB placeholder 'IceStats': ice_stats, } sub_divisions.append(sub_division) return sub_divisions except FileNotFoundError as e: print("Failed to find relation file: ", e) except Exception as e: print("Failed to add remaining subdivisions: ", e) def calculateColor(thickness: float): # NB neither final colors nor ranges if 0 < thickness <= 4: return 0xFFff0000 # Red elif 4 < thickness <= 6: return 0xffff6a00 # Orange elif 6 < thickness <= 8: return 0xFFb1ff00 # Green elif thickness > 8: return 0xFF00d6ff # Blue else: return 0xFF8C8C8C # Grey