From 9d08619ed8cb7758469f229f4ab14ae4f3e90a1c Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Wed, 21 Sep 2022 09:10:32 +0200 Subject: [PATCH 1/9] FIX: removing 'json' from requirements, not needed --- docs/user/requirements.rst | 1 - requirements.txt | 1 - setup.py | 1 - 3 files changed, 3 deletions(-) diff --git a/docs/user/requirements.rst b/docs/user/requirements.rst index 22c2b8c9b..93557e1b4 100644 --- a/docs/user/requirements.rst +++ b/docs/user/requirements.rst @@ -27,7 +27,6 @@ The following packages are needed in order to run RocketPy: - timezonefinder - simplekml - ipywidgets >= 7.6.3 -- json All of these packages, with the exception of netCDF4, should be automatically installed when RocketPy is installed using either ``pip`` or ``conda``. diff --git a/requirements.txt b/requirements.txt index 74bfac2a7..997c86e1f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,4 +8,3 @@ requests pytz timezonefinder simplekml -json diff --git a/setup.py b/setup.py index 1b5775993..767c8d76b 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,6 @@ "pytz", "timezonefinder", "simplekml", - "json", ], maintainer="RocketPy Developers", author="Giovani Hidalgo Ceotto", From 506503dcfa00b6291dd19b7e1b9a1963fc983fcc Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Wed, 21 Sep 2022 15:37:32 +0200 Subject: [PATCH 2/9] ENH: Finally reading the .json correctly --- rocketpy/EnvironmentAnalysis.py | 73 ++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/rocketpy/EnvironmentAnalysis.py b/rocketpy/EnvironmentAnalysis.py index 5a1447f5b..c65630c04 100644 --- a/rocketpy/EnvironmentAnalysis.py +++ b/rocketpy/EnvironmentAnalysis.py @@ -5,6 +5,7 @@ __license__ = "MIT" import bisect +import copy import json import warnings from collections import defaultdict @@ -125,6 +126,7 @@ def __init__( self.pressureLevelDataFile = pressureLevelDataFile self.preferred_timezone = timezone self.load_previous_data = load_previous_data + self.unit_system = unit_system # Manage units and timezones self.__init_data_parsing_units() @@ -140,7 +142,7 @@ def __init__( # Convert units self.set_unit_system(unit_system) - else: + else: # In case of loading previous data, still need to test if all the other functions will work! # Opening JSON file try: with open(self.load_previous_data) as json_file: @@ -150,8 +152,39 @@ def __init__( "Unable to read json file from previous ran Environment Analysis. Please try again." ) + # Load dictionary self.surfaceDataDict = self.loaded_data["surfaceDataDict"] self.pressureLevelDataDict = self.loaded_data["pressureLevelDataDict"] + + # Initialize variables again, to accomplish to the data available at the loaded file + self.elevation = self.loaded_data["elevation"] + self.latitude = self.loaded_data["latitude"] + self.longitude = self.loaded_data["longitude"] + + # Convert back to Function objects, then we will be able to process set_unit_system + ## Use the units on the files, and then convert to the final/selected units + decodeDict = { + "pressure": ["Height Above Sea Level (m)", "Pressure ({})".format(self.loaded_data["unit_system"]['pressure'])], + "temperature": ["Height Above Sea Level (m)", "Temperature ({})".format(self.loaded_data["unit_system"]['temperature'])], + "windDirection": ["Height Above Sea Level (m)", "Wind Direction ({})".format(self.loaded_data["unit_system"]['angle'])], + "windHeading": ["Height Above Sea Level (m)", "Wind Heading ({})".format(self.loaded_data["unit_system"]['angle'])], + "windSpeed": ["Height Above Sea Level (m)", "Wind Speed ({})".format(self.loaded_data["unit_system"]['wind_speed'])], + "windVelocityX": ["Height Above Sea Level (m)", "Wind Velocity X ({})".format(self.loaded_data["unit_system"]['velocity'])], + "windVelocityY": ["Height Above Sea Level (m)", "Wind Velocity Y ({})".format(self.loaded_data["unit_system"]['velocity'])], + } + + # TODO: document this + for days in self.pressureLevelDataDict.keys(): + for hours in self.pressureLevelDataDict[days].keys(): + for variable in decodeDict.keys(): + lst = self.pressureLevelDataDict[days][hours][variable] + self.pressureLevelDataDict[days][hours][variable] = Function( + source= np.column_stack(([item[0] for item in lst], [item[1] for item in lst])), + inputs=[decodeDict[variable][0]], + outputs=[decodeDict[variable][1]], + interpolation='linear', + extrapolation='constant') + print( "Information of the data loaded from previous Environment Analysis.\n" ) @@ -174,8 +207,19 @@ def __init__( print( "Pressure level data file: ", self.loaded_data["pressureLevelDataFile"] ) - print("User timezone: ", self.loaded_data["preferred_timezone"]) - print("User unit system: ", self.loaded_data["unit_system"]) + print("File timezone: ", self.loaded_data["timeZone"]) + print("File unit system: ", self.loaded_data["unit_system"]) + print() + if self.loaded_data["unit_system"] != self.unit_system: + print( + "The unit system of the loaded data is different from the selected unit system. Therefore all the values will be converted to the following unit system: " + ) + # Convert units + self.set_unit_system(unit_system) + print(self.unit_system) + print() + print("Alright, the previous data file were completely loaded, all set to go!") + # Initialize result variables self.average_max_temperature = 0 @@ -631,7 +675,7 @@ def parsePressureLevelData(self): variablePointsArray = np.array([heightAboveSeaLevelArray, valueArray]).T variableFunction = Function( variablePointsArray, - inputs="Height Above Ground Level (m)", + inputs="Height Above Ground Level (m)", # TODO: Check if it is really AGL or ASL here outputs=key, extrapolation="constant", ) @@ -881,7 +925,7 @@ def convertSurfaceData(self): # Calculations def process_data(self): """Process data that is shown in the allInfo method.""" - self.calculate_pressure_stats() + # TODO: self.calculate_pressure_stats() self.calculate_average_max_temperature() self.calculate_average_min_temperature() self.calculate_record_max_temperature() @@ -897,9 +941,9 @@ def process_data(self): self.calculate_average_min_surface_100m_wind_speed() self.calculate_record_max_surface_100m_wind_speed() self.calculate_record_min_surface_100m_wind_speed() - self.calculate_percentage_of_days_with_precipitation() - self.calculate_average_cloud_base_height() - self.calculate_min_cloud_base_height() + # TODO: self.calculate_percentage_of_days_with_precipitation() + # TODO: self.calculate_average_cloud_base_height() + # TODO: self.calculate_min_cloud_base_height() self.calculate_percentage_of_days_with_no_cloud_coverage() @property @@ -2818,6 +2862,15 @@ def saveEnvAnalysisDict(self, filename="EnvAnalysisDict"): TODO: Improve docs """ + # Refactor Function Objects in the pressureLevelDict so it can be converted to .json file as lists + pressureLevelDataDictCopy = copy.deepcopy(self.pressureLevelDataDict) + + for days in pressureLevelDataDictCopy.keys(): + for hours in pressureLevelDataDictCopy[days].keys(): + for variable in pressureLevelDataDictCopy[days][hours].keys(): + pressureLevelDataDictCopy[days][hours][variable] = np.column_stack( (pressureLevelDataDictCopy[days][hours][variable].getSource()[:,0], pressureLevelDataDictCopy[days][hours][variable].getSource()[:,1])).tolist() + + self.EnvAnalysisDict = { "start_date": self.start_date.strftime("%Y-%m-%d"), "end_date": self.end_date.strftime("%Y-%m-%d"), @@ -2832,7 +2885,7 @@ def saveEnvAnalysisDict(self, filename="EnvAnalysisDict"): "surfaceDataFile": self.surfaceDataFile, "pressureLevelDataFile": self.pressureLevelDataFile, "surfaceDataDict": self.surfaceDataDict, - "pressureLevelDataDict": self.pressureLevelDataDict, + "pressureLevelDataDict": pressureLevelDataDictCopy, } # Convert to json @@ -2851,7 +2904,7 @@ def saveEnvAnalysisDict(self, filename="EnvAnalysisDict"): + ".json" ) print( - "You can use it in the future by using the customAtmosphere atmospheric model." + "You can use it in the future by using the load_previous_data of EnvironmentAnalysis Class." ) return None From c96db9d8195d06bb877d47dee003da287e0cf105 Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Wed, 21 Sep 2022 15:46:42 +0200 Subject: [PATCH 3/9] MAINT: formatting with black --- rocketpy/EnvironmentAnalysis.py | 89 +++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 22 deletions(-) diff --git a/rocketpy/EnvironmentAnalysis.py b/rocketpy/EnvironmentAnalysis.py index c65630c04..4f462324a 100644 --- a/rocketpy/EnvironmentAnalysis.py +++ b/rocketpy/EnvironmentAnalysis.py @@ -142,7 +142,7 @@ def __init__( # Convert units self.set_unit_system(unit_system) - else: # In case of loading previous data, still need to test if all the other functions will work! + else: # In case of loading previous data, still need to test if all the other functions will work! # Opening JSON file try: with open(self.load_previous_data) as json_file: @@ -155,7 +155,7 @@ def __init__( # Load dictionary self.surfaceDataDict = self.loaded_data["surfaceDataDict"] self.pressureLevelDataDict = self.loaded_data["pressureLevelDataDict"] - + # Initialize variables again, to accomplish to the data available at the loaded file self.elevation = self.loaded_data["elevation"] self.latitude = self.loaded_data["latitude"] @@ -164,13 +164,46 @@ def __init__( # Convert back to Function objects, then we will be able to process set_unit_system ## Use the units on the files, and then convert to the final/selected units decodeDict = { - "pressure": ["Height Above Sea Level (m)", "Pressure ({})".format(self.loaded_data["unit_system"]['pressure'])], - "temperature": ["Height Above Sea Level (m)", "Temperature ({})".format(self.loaded_data["unit_system"]['temperature'])], - "windDirection": ["Height Above Sea Level (m)", "Wind Direction ({})".format(self.loaded_data["unit_system"]['angle'])], - "windHeading": ["Height Above Sea Level (m)", "Wind Heading ({})".format(self.loaded_data["unit_system"]['angle'])], - "windSpeed": ["Height Above Sea Level (m)", "Wind Speed ({})".format(self.loaded_data["unit_system"]['wind_speed'])], - "windVelocityX": ["Height Above Sea Level (m)", "Wind Velocity X ({})".format(self.loaded_data["unit_system"]['velocity'])], - "windVelocityY": ["Height Above Sea Level (m)", "Wind Velocity Y ({})".format(self.loaded_data["unit_system"]['velocity'])], + "pressure": [ + "Height Above Sea Level (m)", + "Pressure ({})".format(self.loaded_data["unit_system"]["pressure"]), + ], + "temperature": [ + "Height Above Sea Level (m)", + "Temperature ({})".format( + self.loaded_data["unit_system"]["temperature"] + ), + ], + "windDirection": [ + "Height Above Sea Level (m)", + "Wind Direction ({})".format( + self.loaded_data["unit_system"]["angle"] + ), + ], + "windHeading": [ + "Height Above Sea Level (m)", + "Wind Heading ({})".format( + self.loaded_data["unit_system"]["angle"] + ), + ], + "windSpeed": [ + "Height Above Sea Level (m)", + "Wind Speed ({})".format( + self.loaded_data["unit_system"]["wind_speed"] + ), + ], + "windVelocityX": [ + "Height Above Sea Level (m)", + "Wind Velocity X ({})".format( + self.loaded_data["unit_system"]["velocity"] + ), + ], + "windVelocityY": [ + "Height Above Sea Level (m)", + "Wind Velocity Y ({})".format( + self.loaded_data["unit_system"]["velocity"] + ), + ], } # TODO: document this @@ -179,11 +212,14 @@ def __init__( for variable in decodeDict.keys(): lst = self.pressureLevelDataDict[days][hours][variable] self.pressureLevelDataDict[days][hours][variable] = Function( - source= np.column_stack(([item[0] for item in lst], [item[1] for item in lst])), + source=np.column_stack( + ([item[0] for item in lst], [item[1] for item in lst]) + ), inputs=[decodeDict[variable][0]], - outputs=[decodeDict[variable][1]], - interpolation='linear', - extrapolation='constant') + outputs=[decodeDict[variable][1]], + interpolation="linear", + extrapolation="constant", + ) print( "Information of the data loaded from previous Environment Analysis.\n" @@ -218,8 +254,9 @@ def __init__( self.set_unit_system(unit_system) print(self.unit_system) print() - print("Alright, the previous data file were completely loaded, all set to go!") - + print( + "Alright, the previous data file were completely loaded, all set to go!" + ) # Initialize result variables self.average_max_temperature = 0 @@ -675,7 +712,7 @@ def parsePressureLevelData(self): variablePointsArray = np.array([heightAboveSeaLevelArray, valueArray]).T variableFunction = Function( variablePointsArray, - inputs="Height Above Ground Level (m)", # TODO: Check if it is really AGL or ASL here + inputs="Height Above Ground Level (m)", # TODO: Check if it is really AGL or ASL here outputs=key, extrapolation="constant", ) @@ -925,7 +962,7 @@ def convertSurfaceData(self): # Calculations def process_data(self): """Process data that is shown in the allInfo method.""" - # TODO: self.calculate_pressure_stats() + self.calculate_pressure_stats() self.calculate_average_max_temperature() self.calculate_average_min_temperature() self.calculate_record_max_temperature() @@ -941,9 +978,9 @@ def process_data(self): self.calculate_average_min_surface_100m_wind_speed() self.calculate_record_max_surface_100m_wind_speed() self.calculate_record_min_surface_100m_wind_speed() - # TODO: self.calculate_percentage_of_days_with_precipitation() - # TODO: self.calculate_average_cloud_base_height() - # TODO: self.calculate_min_cloud_base_height() + self.calculate_percentage_of_days_with_precipitation() + self.calculate_average_cloud_base_height() + self.calculate_min_cloud_base_height() self.calculate_percentage_of_days_with_no_cloud_coverage() @property @@ -2868,8 +2905,16 @@ def saveEnvAnalysisDict(self, filename="EnvAnalysisDict"): for days in pressureLevelDataDictCopy.keys(): for hours in pressureLevelDataDictCopy[days].keys(): for variable in pressureLevelDataDictCopy[days][hours].keys(): - pressureLevelDataDictCopy[days][hours][variable] = np.column_stack( (pressureLevelDataDictCopy[days][hours][variable].getSource()[:,0], pressureLevelDataDictCopy[days][hours][variable].getSource()[:,1])).tolist() - + pressureLevelDataDictCopy[days][hours][variable] = np.column_stack( + ( + pressureLevelDataDictCopy[days][hours][ + variable + ].getSource()[:, 0], + pressureLevelDataDictCopy[days][hours][ + variable + ].getSource()[:, 1], + ) + ).tolist() self.EnvAnalysisDict = { "start_date": self.start_date.strftime("%Y-%m-%d"), From 19ebc44d475c6d1f837da2f921d08b95821529ef Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Wed, 21 Sep 2022 16:44:25 +0200 Subject: [PATCH 4/9] FIX: partially solve masks on json using nan --- rocketpy/EnvironmentAnalysis.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/rocketpy/EnvironmentAnalysis.py b/rocketpy/EnvironmentAnalysis.py index 4f462324a..0e200b1e7 100644 --- a/rocketpy/EnvironmentAnalysis.py +++ b/rocketpy/EnvironmentAnalysis.py @@ -156,6 +156,14 @@ def __init__( self.surfaceDataDict = self.loaded_data["surfaceDataDict"] self.pressureLevelDataDict = self.loaded_data["pressureLevelDataDict"] + # Fix old masked values on surface data + for days in self.surfaceDataDict.keys(): + for hours in self.surfaceDataDict[days].keys(): + for variables in self.surfaceDataDict[days][hours].keys(): + if self.surfaceDataDict[days][hours][variables] == "--": + # TODO: is there any other value that we can use to prevent "NaN"? + self.surfaceDataDict[days][hours][variables] = float("NaN") + # Initialize variables again, to accomplish to the data available at the loaded file self.elevation = self.loaded_data["elevation"] self.latitude = self.loaded_data["latitude"] @@ -979,8 +987,8 @@ def process_data(self): self.calculate_record_max_surface_100m_wind_speed() self.calculate_record_min_surface_100m_wind_speed() self.calculate_percentage_of_days_with_precipitation() - self.calculate_average_cloud_base_height() - self.calculate_min_cloud_base_height() + self.calculate_average_cloud_base_height() # Having problems with masks! + self.calculate_min_cloud_base_height() # Having problems with masks! self.calculate_percentage_of_days_with_no_cloud_coverage() @property From cda9198712723228437eb5661c85f5e3a24a96ab Mon Sep 17 00:00:00 2001 From: patrick Date: Thu, 22 Sep 2022 14:59:01 +0200 Subject: [PATCH 5/9] Enh: Using jsonpickle to serialize EnvAnal --- requirements.txt | 1 + rocketpy/EnvironmentAnalysis.py | 68 +++++---------------------------- 2 files changed, 11 insertions(+), 58 deletions(-) diff --git a/requirements.txt b/requirements.txt index 997c86e1f..ccfdb4f15 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ requests pytz timezonefinder simplekml +jsonpickle diff --git a/rocketpy/EnvironmentAnalysis.py b/rocketpy/EnvironmentAnalysis.py index 0e200b1e7..da85d128d 100644 --- a/rocketpy/EnvironmentAnalysis.py +++ b/rocketpy/EnvironmentAnalysis.py @@ -11,6 +11,7 @@ from collections import defaultdict import ipywidgets as widgets +import jsonpickle import matplotlib.ticker as mtick import netCDF4 import numpy as np @@ -2900,64 +2901,15 @@ def exportMeanProfiles(self, filename="export_env_analysis"): return None - def saveEnvAnalysisDict(self, filename="EnvAnalysisDict"): - """ - Saves the Environment Analysis dictionary to a file in order to it - be load again in the future. - TODO: Improve docs - """ - - # Refactor Function Objects in the pressureLevelDict so it can be converted to .json file as lists - pressureLevelDataDictCopy = copy.deepcopy(self.pressureLevelDataDict) - - for days in pressureLevelDataDictCopy.keys(): - for hours in pressureLevelDataDictCopy[days].keys(): - for variable in pressureLevelDataDictCopy[days][hours].keys(): - pressureLevelDataDictCopy[days][hours][variable] = np.column_stack( - ( - pressureLevelDataDictCopy[days][hours][ - variable - ].getSource()[:, 0], - pressureLevelDataDictCopy[days][hours][ - variable - ].getSource()[:, 1], - ) - ).tolist() - - self.EnvAnalysisDict = { - "start_date": self.start_date.strftime("%Y-%m-%d"), - "end_date": self.end_date.strftime("%Y-%m-%d"), - "start_hour": self.start_hour, - "end_hour": self.end_hour, - "latitude": self.latitude, - "longitude": self.longitude, - "elevation": self.elevation, - "timeZone": str(self.preferred_timezone), - "unit_system": self.unit_system, - # "maxExpectedHeight": 80000, # TODO: Implement this parameter at EnvAnalysis Class - "surfaceDataFile": self.surfaceDataFile, - "pressureLevelDataFile": self.pressureLevelDataFile, - "surfaceDataDict": self.surfaceDataDict, - "pressureLevelDataDict": pressureLevelDataDictCopy, - } + @classmethod + def load(self, filename="EnvAnalysisDict"): + encoded_class = open(filename).read() + return jsonpickle.decode(encoded_class) - # Convert to json - f = open(filename + ".json", "w") - - # write json object to file - f.write( - json.dumps(self.EnvAnalysisDict, sort_keys=False, indent=4, default=str) - ) - - # close file - f.close() - print( - "Your Environment Analysis file was saved, check it out: " - + filename - + ".json" - ) - print( - "You can use it in the future by using the load_previous_data of EnvironmentAnalysis Class." - ) + def save(self, filename="EnvAnalysisDict"): + encoded_class = jsonpickle.encode(self) + file = open(filename, "w") + file.write(encoded_class) + file.close() return None From badea3b11f0cb0fc35e9cddb6a563af29f1839b1 Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Fri, 23 Sep 2022 01:00:15 +0200 Subject: [PATCH 6/9] ENH: Cleaning unused codelines --- rocketpy/EnvironmentAnalysis.py | 170 ++++++-------------------------- 1 file changed, 31 insertions(+), 139 deletions(-) diff --git a/rocketpy/EnvironmentAnalysis.py b/rocketpy/EnvironmentAnalysis.py index da85d128d..d0ec63ffc 100644 --- a/rocketpy/EnvironmentAnalysis.py +++ b/rocketpy/EnvironmentAnalysis.py @@ -5,8 +5,6 @@ __license__ = "MIT" import bisect -import copy -import json import warnings from collections import defaultdict @@ -69,7 +67,6 @@ def __init__( pressureLevelDataFile=None, timezone=None, unit_system="metric", - load_previous_data=None, ): """Constructor for the EnvironmentAnalysis class. Parameters @@ -104,10 +101,6 @@ def __init__( unit_system : str, optional Unit system to be used when displaying results. Options are: SI, metric, imperial. Default is metric. - load_previous_data : str, optional - If True, the class will try to load the data from a previous ran Environment Analysis. - Use .json file resulted from ... as input. - Default is None. Returns ------- None @@ -126,7 +119,6 @@ def __init__( self.surfaceDataFile = surfaceDataFile self.pressureLevelDataFile = pressureLevelDataFile self.preferred_timezone = timezone - self.load_previous_data = load_previous_data self.unit_system = unit_system # Manage units and timezones @@ -134,138 +126,13 @@ def __init__( self.__find_preferred_timezone() self.__localize_input_dates() - # Parse data files, surface goes first to calculate elevation - if load_previous_data is None: - self.surfaceDataDict = {} - self.parseSurfaceData() - self.pressureLevelDataDict = {} - self.parsePressureLevelData() - - # Convert units - self.set_unit_system(unit_system) - else: # In case of loading previous data, still need to test if all the other functions will work! - # Opening JSON file - try: - with open(self.load_previous_data) as json_file: - self.loaded_data = json.load(json_file) - except: - raise RuntimeError( - "Unable to read json file from previous ran Environment Analysis. Please try again." - ) - - # Load dictionary - self.surfaceDataDict = self.loaded_data["surfaceDataDict"] - self.pressureLevelDataDict = self.loaded_data["pressureLevelDataDict"] - - # Fix old masked values on surface data - for days in self.surfaceDataDict.keys(): - for hours in self.surfaceDataDict[days].keys(): - for variables in self.surfaceDataDict[days][hours].keys(): - if self.surfaceDataDict[days][hours][variables] == "--": - # TODO: is there any other value that we can use to prevent "NaN"? - self.surfaceDataDict[days][hours][variables] = float("NaN") - - # Initialize variables again, to accomplish to the data available at the loaded file - self.elevation = self.loaded_data["elevation"] - self.latitude = self.loaded_data["latitude"] - self.longitude = self.loaded_data["longitude"] - - # Convert back to Function objects, then we will be able to process set_unit_system - ## Use the units on the files, and then convert to the final/selected units - decodeDict = { - "pressure": [ - "Height Above Sea Level (m)", - "Pressure ({})".format(self.loaded_data["unit_system"]["pressure"]), - ], - "temperature": [ - "Height Above Sea Level (m)", - "Temperature ({})".format( - self.loaded_data["unit_system"]["temperature"] - ), - ], - "windDirection": [ - "Height Above Sea Level (m)", - "Wind Direction ({})".format( - self.loaded_data["unit_system"]["angle"] - ), - ], - "windHeading": [ - "Height Above Sea Level (m)", - "Wind Heading ({})".format( - self.loaded_data["unit_system"]["angle"] - ), - ], - "windSpeed": [ - "Height Above Sea Level (m)", - "Wind Speed ({})".format( - self.loaded_data["unit_system"]["wind_speed"] - ), - ], - "windVelocityX": [ - "Height Above Sea Level (m)", - "Wind Velocity X ({})".format( - self.loaded_data["unit_system"]["velocity"] - ), - ], - "windVelocityY": [ - "Height Above Sea Level (m)", - "Wind Velocity Y ({})".format( - self.loaded_data["unit_system"]["velocity"] - ), - ], - } - - # TODO: document this - for days in self.pressureLevelDataDict.keys(): - for hours in self.pressureLevelDataDict[days].keys(): - for variable in decodeDict.keys(): - lst = self.pressureLevelDataDict[days][hours][variable] - self.pressureLevelDataDict[days][hours][variable] = Function( - source=np.column_stack( - ([item[0] for item in lst], [item[1] for item in lst]) - ), - inputs=[decodeDict[variable][0]], - outputs=[decodeDict[variable][1]], - interpolation="linear", - extrapolation="constant", - ) + self.surfaceDataDict = {} + self.parseSurfaceData() + self.pressureLevelDataDict = {} + self.parsePressureLevelData() - print( - "Information of the data loaded from previous Environment Analysis.\n" - ) - print( - "Available dates: ", - self.loaded_data["start_date"], - " to ", - self.loaded_data["end_date"], - ) - print( - "Available hours: ", - self.loaded_data["start_hour"], - " to ", - self.loaded_data["end_hour"], - ) - print("Latitude", self.loaded_data["latitude"]) - print("Longitude", self.loaded_data["longitude"]) - print("Elevation:", self.loaded_data["elevation"]) - print("Surface data file: ", self.loaded_data["surfaceDataFile"]) - print( - "Pressure level data file: ", self.loaded_data["pressureLevelDataFile"] - ) - print("File timezone: ", self.loaded_data["timeZone"]) - print("File unit system: ", self.loaded_data["unit_system"]) - print() - if self.loaded_data["unit_system"] != self.unit_system: - print( - "The unit system of the loaded data is different from the selected unit system. Therefore all the values will be converted to the following unit system: " - ) - # Convert units - self.set_unit_system(unit_system) - print(self.unit_system) - print() - print( - "Alright, the previous data file were completely loaded, all set to go!" - ) + # Convert units + self.set_unit_system(unit_system) # Initialize result variables self.average_max_temperature = 0 @@ -2903,13 +2770,38 @@ def exportMeanProfiles(self, filename="export_env_analysis"): @classmethod def load(self, filename="EnvAnalysisDict"): + """Load a previously saved Environment Analysis file. + Example: EnvA = EnvironmentAnalysis.load("filename"). + + Parameters + ---------- + filename : str, optional + Name of the previous saved file, by default "EnvAnalysisDict" + + Returns + ------- + EnvironmentAnalysis object + + """ encoded_class = open(filename).read() return jsonpickle.decode(encoded_class) def save(self, filename="EnvAnalysisDict"): + """Save the Environment Analysis object to a file so it can be used later. + + Parameters + ---------- + filename : str, optional + Name of the file where to be saved, by default "EnvAnalysisDict" + + Returns + ------- + None + """ encoded_class = jsonpickle.encode(self) file = open(filename, "w") file.write(encoded_class) file.close() + print("Your Environment Analysis file was saved, check it out: " + filename) return None From c5d65176c7ed7c32a199838bef95c70dfcf517b9 Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Fri, 23 Sep 2022 01:07:01 +0200 Subject: [PATCH 7/9] MAINT: Improve methods docs --- rocketpy/EnvironmentAnalysis.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/rocketpy/EnvironmentAnalysis.py b/rocketpy/EnvironmentAnalysis.py index d0ec63ffc..0e8ab7f56 100644 --- a/rocketpy/EnvironmentAnalysis.py +++ b/rocketpy/EnvironmentAnalysis.py @@ -6,6 +6,7 @@ import bisect import warnings +import json from collections import defaultdict import ipywidgets as widgets @@ -2687,7 +2688,15 @@ def exportMeanProfiles(self, filename="export_env_analysis"): Exports the mean profiles of the weather data to a file in order to it be used as inputs on Environment Class by using the CustomAtmosphere model. - TODO: Improve docs + + Parameters + ---------- + filename : str, optional + Name of the file where to be saved, by default "EnvAnalysisDict" + + Returns + ------- + None """ self.process_temperature_profile_over_average_day() From e55ddec1ae5fbcea06208c18bb571fb61919e0e6 Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Fri, 23 Sep 2022 01:09:14 +0200 Subject: [PATCH 8/9] MAINT: Add jsonpickle as requirement --- docs/user/requirements.rst | 1 + setup.py | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/user/requirements.rst b/docs/user/requirements.rst index 93557e1b4..afc2c2c7f 100644 --- a/docs/user/requirements.rst +++ b/docs/user/requirements.rst @@ -49,6 +49,7 @@ The packages needed can be installed via ``pip`` by running the following lines pip install pytz pip install timezonefinder pip install simplekml + pip install jsonpickle Installing Required Packages Using ``conda`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/setup.py b/setup.py index 767c8d76b..3469308da 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ "pytz", "timezonefinder", "simplekml", + "jsonpickle", ], maintainer="RocketPy Developers", author="Giovani Hidalgo Ceotto", From 0e577270054b32af6cafeae24bc27a009b6d9f33 Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Fri, 23 Sep 2022 01:19:38 +0200 Subject: [PATCH 9/9] MAINT: removing undesired comments --- docs/user/requirements.rst | 1 + rocketpy/EnvironmentAnalysis.py | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/user/requirements.rst b/docs/user/requirements.rst index afc2c2c7f..63b419607 100644 --- a/docs/user/requirements.rst +++ b/docs/user/requirements.rst @@ -27,6 +27,7 @@ The following packages are needed in order to run RocketPy: - timezonefinder - simplekml - ipywidgets >= 7.6.3 +- jsonpickle All of these packages, with the exception of netCDF4, should be automatically installed when RocketPy is installed using either ``pip`` or ``conda``. diff --git a/rocketpy/EnvironmentAnalysis.py b/rocketpy/EnvironmentAnalysis.py index 0e8ab7f56..eec8c3917 100644 --- a/rocketpy/EnvironmentAnalysis.py +++ b/rocketpy/EnvironmentAnalysis.py @@ -5,8 +5,8 @@ __license__ = "MIT" import bisect -import warnings import json +import warnings from collections import defaultdict import ipywidgets as widgets @@ -127,6 +127,7 @@ def __init__( self.__find_preferred_timezone() self.__localize_input_dates() + # Parse data files, surface goes first to calculate elevation self.surfaceDataDict = {} self.parseSurfaceData() self.pressureLevelDataDict = {} @@ -589,7 +590,7 @@ def parsePressureLevelData(self): variablePointsArray = np.array([heightAboveSeaLevelArray, valueArray]).T variableFunction = Function( variablePointsArray, - inputs="Height Above Ground Level (m)", # TODO: Check if it is really AGL or ASL here + inputs="Height Above Ground Level (m)", # TODO: Check if it is really AGL or ASL here, see 3 lines above outputs=key, extrapolation="constant", ) @@ -856,8 +857,8 @@ def process_data(self): self.calculate_record_max_surface_100m_wind_speed() self.calculate_record_min_surface_100m_wind_speed() self.calculate_percentage_of_days_with_precipitation() - self.calculate_average_cloud_base_height() # Having problems with masks! - self.calculate_min_cloud_base_height() # Having problems with masks! + self.calculate_average_cloud_base_height() + self.calculate_min_cloud_base_height() self.calculate_percentage_of_days_with_no_cloud_coverage() @property @@ -2748,8 +2749,6 @@ def exportMeanProfiles(self, filename="export_env_analysis"): # "maxExpectedHeight": 80000, # TODO: Implement this parameter at EnvAnalysis Class "surfaceDataFile": self.surfaceDataFile, "pressureLevelDataFile": self.pressureLevelDataFile, - # "surfaceDataDict": self.surfaceDataDict, # TODO: Too large, make it optional - # "pressureLevelDataDict": self.pressureLevelDataDict, # TODO: Too large, make it optional "atmosphericModelPressureProfile": organized_pressure_dict, "atmosphericModelTemperatureProfile": organized_temperature_dict, "atmosphericModelWindVelocityXProfile": organized_windX_dict,