diff --git a/docs/get-involved/modularization/python-template/cost_estimation/cost_estimation.py b/docs/get-involved/modularization/python-template/cost_estimation/cost_estimation.py index 0a16cd5eaee48b75b3a63e6a791703045ef2f6b9..3a0d3bae96be7f2d4582bb52e7baf97e34c487a7 100644 --- a/docs/get-involved/modularization/python-template/cost_estimation/cost_estimation.py +++ b/docs/get-involved/modularization/python-template/cost_estimation/cost_estimation.py @@ -1,88 +1,89 @@ -"""Calculation module main file.""" -# Import standard modules. -import logging -import traceback -from sys import argv, exit - -# Import own modules. -from runmodule import run_module -from src.datapreprocessing import data_preprocessing -from src.datapostprocessing import data_postprocessing - - -def main(): - """Execute the main program for cost estimation. - - This function serves as the main entry point for performing the cost estimation. - It goes through the following key steps: - (1) Preprocessing - Acquire necessary data and paths: Call the 'data_preprocessing' function from - 'datapreprocessing.py' to set up data and routing information. - (2) Run (main processing) - Execute code depending on method layers: Execute the 'run_module' function from the - 'methodexecutionpackage' library. The 'run_module' function is responsible for the programs primary logic. - (3) Postprocessing - Write data to the aircraft exchange file and generate plots and reports: Call the - 'data_postprocessing' function from 'datapostprocessing.py' to handle postprocessing tasks. This step receives - data from both the preprocessing and the main processing step. - - Note: The 'routing_dict' dictionary is used to manage the routing and execution of different program components. - - :raises Exception: Raised to handle other exceptions - :return: None - """ - - # Initialize exception string and runtime output logger. - tool_name = 'cost estimation' - runtime_output = logging.getLogger('module_logger') - - try: - """Preprocessing: Acquire necessary data and paths.""" - # Run 'data_preprocessing' function from 'datapreprocessing.py'. - paths_and_names, routing_dict, runtime_output = data_preprocessing('cost_estimation_conf.xml', argv) - runtime_output.print('Cost estimation started...') - - """Run: Execute code depending on method layers.""" - # Execute 'run_module' function from 'methodexecutionpackage' library. This function is responsible for the main - # logic of the program. - run_output_dict = run_module(paths_and_names, routing_dict, runtime_output) - - """Postprocessing: Write data to aircraft exchange file and generate plots and reports.""" - # Run 'data_postprocessing' function from 'datapostprocessing.py' to handle postprocessing tasks. Receives data - # from preprocessing and main processing step. - data_postprocessing(paths_and_names, routing_dict, run_output_dict, runtime_output) - runtime_output.print('Operating cost estimation finished.') - - except Exception as e: # pylint: disable=broad-exception-caught - # Handle other exceptions. - runtime_output.critical(exception_string_msg(e, tool_name)) - exit(1) - - -def exception_string_msg(error, tool_name: str): - """Generate exception message. - - Generate a formatted string detailing the type and location of an exception, along with an error message, for - diagnostic purposes. This function is particularly useful for logging or displaying comprehensive error information - when an exception occurs in a specific module or function. - - :param exception error: Caught exception object from which details will be extracted - :param str tool_name: Name of the tool or module where the error occurred, used in the final error message - :return str: String including error type, file name, function/method name, line number, code that caused the error, - and error message. - """ - error_type = str(type(error).__name__) - error_trace = traceback.extract_tb(error.__traceback__) - error_file, error_line, error_func, error_code = error_trace[-1] - error_file = error_file.split('/')[-1] - - exception_string = f"{error_type}: \n" - exception_string += f" - File : {error_file} \n" - exception_string += f" - Function / Method: {error_func} \n" - exception_string += f" - Line : {error_line} \n" - exception_string += f" - Code : {error_code} \n" - exception_string += f" - Error message : {str(error)} \n" - - return exception_string + f"Main execution of {tool_name} module failed! \n" \ - f"Program aborted." - - -if __name__ == "__main__": - main() +"""Calculation module main file.""" +# Import standard modules. +import logging +import traceback +from sys import argv, exit + +# Import own modules. +from runmodule import run_module +from src.datapreprocessing import data_preprocessing +from src.datapostprocessing import data_postprocessing + + +def main(): + """Execute the main program for cost estimation. + + This function serves as the main entry point for performing the cost estimation. + It goes through the following key steps: + (1) Preprocessing - Acquire necessary data and paths: Call the 'data_preprocessing' function from + 'datapreprocessing.py' to set up data and routing information. + (2) Run (main processing) - Execute code depending on method layers: Execute the 'run_module' function from the + 'methodexecutionpackage' library. The 'run_module' function is responsible for the programs primary logic. + (3) Postprocessing - Write data to the aircraft exchange file and generate plots and reports: Call the + 'data_postprocessing' function from 'datapostprocessing.py' to handle postprocessing tasks. This step receives + data from both the preprocessing and the main processing step. + + Note: The 'routing_dict' dictionary is used to manage the routing and execution of different program components. + + :raises Exception: Raised to handle other exceptions + :return: None + """ + + # Initialize exception string and runtime output logger. + tool_name = 'cost estimation' + tool_version = '0.5.0' + runtime_output = logging.getLogger('module_logger') + + try: + """Preprocessing: Acquire necessary data and paths.""" + # Run 'data_preprocessing' function from 'datapreprocessing.py'. + paths_and_names, routing_dict, runtime_output = data_preprocessing('cost_estimation_conf.xml', tool_version, argv) + runtime_output.print('Cost estimation started...') + + """Run: Execute code depending on method layers.""" + # Execute 'run_module' function from 'methodexecutionpackage' library. This function is responsible for the main + # logic of the program. + run_output_dict = run_module(paths_and_names, routing_dict, runtime_output) + + """Postprocessing: Write data to aircraft exchange file and generate plots and reports.""" + # Run 'data_postprocessing' function from 'datapostprocessing.py' to handle postprocessing tasks. Receives data + # from preprocessing and main processing step. + data_postprocessing(paths_and_names, routing_dict, run_output_dict, runtime_output) + runtime_output.print('Operating cost estimation finished.') + + except Exception as e: # pylint: disable=broad-exception-caught + # Handle other exceptions. + runtime_output.critical(exception_string_msg(e, tool_name)) + exit(1) + + +def exception_string_msg(error, tool_name: str): + """Generate exception message. + + Generate a formatted string detailing the type and location of an exception, along with an error message, for + diagnostic purposes. This function is particularly useful for logging or displaying comprehensive error information + when an exception occurs in a specific module or function. + + :param exception error: Caught exception object from which details will be extracted + :param str tool_name: Name of the tool or module where the error occurred, used in the final error message + :return str: String including error type, file name, function/method name, line number, code that caused the error, + and error message. + """ + error_type = str(type(error).__name__) + error_trace = traceback.extract_tb(error.__traceback__) + error_file, error_line, error_func, error_code = error_trace[-1] + error_file = error_file.split('/')[-1] + + exception_string = f"{error_type}: \n" + exception_string += f" - File : {error_file} \n" + exception_string += f" - Function / Method: {error_func} \n" + exception_string += f" - Line : {error_line} \n" + exception_string += f" - Code : {error_code} \n" + exception_string += f" - Error message : {str(error)} \n" + + return exception_string + f"Main execution of {tool_name} module failed! \n" \ + f"Program aborted." + + +if __name__ == "__main__": + main() diff --git a/docs/get-involved/modularization/python-template/cost_estimation/src/datapreprocessing.py b/docs/get-involved/modularization/python-template/cost_estimation/src/datapreprocessing.py index 8ac87546f3daa0f7ec18644426478d76d44d0668..f84e3b2788040af6f03a4b7c56ca9ca69e6b41be 100644 --- a/docs/get-involved/modularization/python-template/cost_estimation/src/datapreprocessing.py +++ b/docs/get-involved/modularization/python-template/cost_estimation/src/datapreprocessing.py @@ -1,126 +1,127 @@ -"""Module providing functions for data preprocessing.""" -# Import standard modules. -import importlib -import sys - -# Import own modules. -from datapreprocessingmodule import get_paths_and_names, read_routing_values_from_xml -from src.readlayertext import read_energy_carrier - - -def data_preprocessing(module_configuration_file, argv): - """Conduct data preprocessing. - - This function provides data preprocessing functionalities. It sets up the necessary data and imports relevant - modules. The importlib module is used to dynamically import necessary modules. - - The output dictionary 'preprocessing_dict' contains the following values: - - 'layer_1': First routing layer (aircraft configuration) (str) - - 'layer_2': Second routing layer (calculation method fidelity) (str) - - 'layer_3': Third routing layer (calculation method) (str) - - 'user_layer': Last routing layer (fuel type) (user layer) (str) - - 'tool_level': Tool level of current tool (str) - - 'module_import_name': Dynamic string for dynamically generated module import name based on layers (str) - - 'module_name': Module name (name of the module configuration file without its file extension) (str) - - 'func_user_method_data_input_preparation': Reference to 'user_method_data_input_preparation' function - - 'func_user_method_data_output_preparation': Reference to 'user_method_data_output_preparation' function - - 'func_user_method_plot': Reference to 'method_plot' function - - 'func_user_method_html_report': Reference to 'method_html_report' function - - 'func_user_method_xml_export': Reference to 'method_xml_export' function - - :param str module_configuration_file: Name of module configuration file - :param list argv: List with optional input arguments - :raises ModuleNotFoundError: Raised if module import failed - :returns: - - dict paths_and_names: Dictionary containing system paths and ElementTrees - - dict preprocessing_dict: Dictionary containing data preprocessing results - - logging.Logger runtime_output: Logging object used for capturing log messages in the module - - """ - - """Get paths, names, and xml trees for module configuration and aircraft exchange file.""" - # Call 'get_paths_and_names' function to obtain various paths and names. - paths_and_names, runtime_output = get_paths_and_names(module_configuration_file, argv) - # Note: It is the exclusive responsibility of the module manager to modify the following information! - # Create layer description dictionary according to the number of individual layers. The dictionary associates - # layers with their respective XML paths and expected data types according to the following scheme: - # layer_description_dict = {'layer_1': [path, expected data type], 'layer_2': [...]} - # If any information cannot be directly extracted from a specific aircraft exchange file path, please write 'None' - # and manually add the missing value afterward. - aircraft_exchange_tmp_path = 'aircraft_exchange_file/requirements_and_specifications/design_specification/' - module_configuration_tmp_path = 'module_configuration_file/program_settings/configuration/' - layer_description_dict = { - 'layer_1': [aircraft_exchange_tmp_path + 'configuration/configuration_type/value', float], - 'layer_2': [module_configuration_tmp_path + 'fidelity_name/value', str], - 'layer_3': [module_configuration_tmp_path + 'method_name/value', str], - 'user_layer': [None, str] - } - - """ Extract data from aircraft exchange and module configuration file.""" - # Extract root and path to aircraft exchange file and write key data to aircraft exchange file. - root_of_aircraft_exchange_tree = paths_and_names['root_of_aircraft_exchange_tree'] - root_of_module_configuration_file = paths_and_names['root_of_module_config_tree'] - # Extract data from *.xml files based on the provided layer description (if no path information given ('None'), - # the entry has to be specified manually afterward). The result is stored in the 'preprocessing_dict' dictionary. - # It has the following output format (all values are strings): - # dict_out = {'layer_1': value, 'layer_2': value, 'layer_3': value, 'user_layer': value, 'tool_level': value} - preprocessing_dict = read_routing_values_from_xml(layer_description_dict, root_of_aircraft_exchange_tree, - root_of_module_configuration_file, runtime_output) - # Manual specification of missing layer values ('None' entry layer). - preprocessing_dict['user_layer'] = read_energy_carrier(root_of_aircraft_exchange_tree, runtime_output) - - """Prepare and import modules.""" - # Generate a dynamic import name 'module_import_name' for the selected calculation method modules based on the - # provided layer values according to the following scheme: - # 'src.[value of layer_1].[value of layer_2].[value of layer_3]' - module_import_name = 'src' - for _, value in list(preprocessing_dict.items())[:-2]: - module_import_name += '.' + value - # Create import commands by appending the python file name (incl. sub-folders, if necessary) to the generated - # 'module_import_name'. E.g., the import command for the module import from the 'usermethoddatapreparation.py' file - # is as follows: - # 'src.[value of layer_1].[value of layer_2].[value of layer_3].usermethoddatapreparation' - # The import command for the module import from the 'methodplot.py' file in the 'general' folder is as follows: - # 'src.[value of layer_1].[value of layer_2].[value of layer_3].general.methodplot' - # This step is executed for the following python files: - # * 'usermethoddatapreparation.py' - # * 'methodplot.py' - # * 'methodhtmlreport.py' - # * 'methodxmlexport.py' - # * 'methodtexoutput'.py' - import_command_user_method_data_preparation = module_import_name + '.usermethoddatapreparation' - import_command_user_method_plot = module_import_name + '.general.methodplot' - import_command_user_method_html_report = module_import_name + '.general.methodhtmlreport' - import_command_user_method_xml_export = module_import_name + '.general.methodxmlexport' - import_command_user_method_tex_output = module_import_name + '.general.methodtexoutput' - - # Add module name and tool level to the preprocessing_dict. - preprocessing_dict['module_import_name'] = module_import_name - preprocessing_dict['module_name'] = module_configuration_file[:-9] - - # Dynamically import modules and functions based on the generated import commands. - try: - # Import functions from the specified modules. - import_user_method_data_preparation = importlib.import_module(import_command_user_method_data_preparation) - import_user_method_plot = importlib.import_module(import_command_user_method_plot) - import_user_method_html_report = importlib.import_module(import_command_user_method_html_report) - import_user_method_xml_export = importlib.import_module(import_command_user_method_xml_export) - import_user_method_tex_output = importlib.import_module(import_command_user_method_tex_output) - # Save the imported functions as variables in the 'preprocessing_dict' dictionary. - preprocessing_dict['func_user_method_data_input_preparation'] \ - = import_user_method_data_preparation.user_method_data_input_preparation - preprocessing_dict['func_user_method_data_output_preparation'] \ - = import_user_method_data_preparation.user_method_data_output_preparation - preprocessing_dict['func_user_method_plot'] = import_user_method_plot.method_plot - preprocessing_dict['func_user_method_html_report'] = import_user_method_html_report.method_html_report - preprocessing_dict['func_user_method_xml_export'] = import_user_method_xml_export.method_xml_export - preprocessing_dict['func_user_method_tex_output'] = import_user_method_tex_output.method_tex_output - # Exception handling for module import error. - except ModuleNotFoundError as module_import_error: - runtime_output_string = ('Error: ' + str(module_import_error) + ' found in ' - + preprocessing_dict['module_name'] + '.\n' - + ' Program aborted.') - runtime_output.critical(runtime_output_string) - sys.exit(1) - - return paths_and_names, preprocessing_dict, runtime_output +"""Module providing functions for data preprocessing.""" +# Import standard modules. +import importlib +import sys + +# Import own modules. +from datapreprocessingmodule import get_paths_and_names, read_routing_values_from_xml +from src.readlayertext import read_energy_carrier + + +def data_preprocessing(module_configuration_file, tool_version, argv): + """Conduct data preprocessing. + + This function provides data preprocessing functionalities. It sets up the necessary data and imports relevant + modules. The importlib module is used to dynamically import necessary modules. + + The output dictionary 'preprocessing_dict' contains the following values: + - 'layer_1': First routing layer (aircraft configuration) (str) + - 'layer_2': Second routing layer (calculation method fidelity) (str) + - 'layer_3': Third routing layer (calculation method) (str) + - 'user_layer': Last routing layer (fuel type) (user layer) (str) + - 'tool_level': Tool level of current tool (str) + - 'module_import_name': Dynamic string for dynamically generated module import name based on layers (str) + - 'module_name': Module name (name of the module configuration file without its file extension) (str) + - 'func_user_method_data_input_preparation': Reference to 'user_method_data_input_preparation' function + - 'func_user_method_data_output_preparation': Reference to 'user_method_data_output_preparation' function + - 'func_user_method_plot': Reference to 'method_plot' function + - 'func_user_method_html_report': Reference to 'method_html_report' function + - 'func_user_method_xml_export': Reference to 'method_xml_export' function + + :param str module_configuration_file: Name of module configuration file + :param list argv: List with optional input arguments + :raises ModuleNotFoundError: Raised if module import failed + :returns: + - dict paths_and_names: Dictionary containing system paths and ElementTrees + - dict preprocessing_dict: Dictionary containing data preprocessing results + - logging.Logger runtime_output: Logging object used for capturing log messages in the module + + """ + + """Get paths, names, and xml trees for module configuration and aircraft exchange file.""" + # Call 'get_paths_and_names' function to obtain various paths and names. + paths_and_names, runtime_output = get_paths_and_names(module_configuration_file, argv) + paths_and_names['tool_version'] = tool_version + # Note: It is the exclusive responsibility of the module manager to modify the following information! + # Create layer description dictionary according to the number of individual layers. The dictionary associates + # layers with their respective XML paths and expected data types according to the following scheme: + # layer_description_dict = {'layer_1': [path, expected data type], 'layer_2': [...]} + # If any information cannot be directly extracted from a specific aircraft exchange file path, please write 'None' + # and manually add the missing value afterward. + aircraft_exchange_tmp_path = 'aircraft_exchange_file/requirements_and_specifications/design_specification/' + module_configuration_tmp_path = 'module_configuration_file/program_settings/configuration/' + layer_description_dict = { + 'layer_1': [aircraft_exchange_tmp_path + 'configuration/configuration_type/value', float], + 'layer_2': [module_configuration_tmp_path + 'fidelity_name/value', str], + 'layer_3': [module_configuration_tmp_path + 'method_name/value', str], + 'user_layer': [None, str] + } + + """ Extract data from aircraft exchange and module configuration file.""" + # Extract root and path to aircraft exchange file and write key data to aircraft exchange file. + root_of_aircraft_exchange_tree = paths_and_names['root_of_aircraft_exchange_tree'] + root_of_module_configuration_file = paths_and_names['root_of_module_config_tree'] + # Extract data from *.xml files based on the provided layer description (if no path information given ('None'), + # the entry has to be specified manually afterward). The result is stored in the 'preprocessing_dict' dictionary. + # It has the following output format (all values are strings): + # dict_out = {'layer_1': value, 'layer_2': value, 'layer_3': value, 'user_layer': value, 'tool_level': value} + preprocessing_dict = read_routing_values_from_xml(layer_description_dict, root_of_aircraft_exchange_tree, + root_of_module_configuration_file, runtime_output) + # Manual specification of missing layer values ('None' entry layer). + preprocessing_dict['user_layer'] = read_energy_carrier(root_of_aircraft_exchange_tree, runtime_output) + + """Prepare and import modules.""" + # Generate a dynamic import name 'module_import_name' for the selected calculation method modules based on the + # provided layer values according to the following scheme: + # 'src.[value of layer_1].[value of layer_2].[value of layer_3]' + module_import_name = 'src' + for _, value in list(preprocessing_dict.items())[:-2]: + module_import_name += '.' + value + # Create import commands by appending the python file name (incl. sub-folders, if necessary) to the generated + # 'module_import_name'. E.g., the import command for the module import from the 'usermethoddatapreparation.py' file + # is as follows: + # 'src.[value of layer_1].[value of layer_2].[value of layer_3].usermethoddatapreparation' + # The import command for the module import from the 'methodplot.py' file in the 'general' folder is as follows: + # 'src.[value of layer_1].[value of layer_2].[value of layer_3].general.methodplot' + # This step is executed for the following python files: + # * 'usermethoddatapreparation.py' + # * 'methodplot.py' + # * 'methodhtmlreport.py' + # * 'methodxmlexport.py' + # * 'methodtexoutput'.py' + import_command_user_method_data_preparation = module_import_name + '.usermethoddatapreparation' + import_command_user_method_plot = module_import_name + '.general.methodplot' + import_command_user_method_html_report = module_import_name + '.general.methodhtmlreport' + import_command_user_method_xml_export = module_import_name + '.general.methodxmlexport' + import_command_user_method_tex_output = module_import_name + '.general.methodtexoutput' + + # Add module name and tool level to the preprocessing_dict. + preprocessing_dict['module_import_name'] = module_import_name + preprocessing_dict['module_name'] = module_configuration_file[:-9] + + # Dynamically import modules and functions based on the generated import commands. + try: + # Import functions from the specified modules. + import_user_method_data_preparation = importlib.import_module(import_command_user_method_data_preparation) + import_user_method_plot = importlib.import_module(import_command_user_method_plot) + import_user_method_html_report = importlib.import_module(import_command_user_method_html_report) + import_user_method_xml_export = importlib.import_module(import_command_user_method_xml_export) + import_user_method_tex_output = importlib.import_module(import_command_user_method_tex_output) + # Save the imported functions as variables in the 'preprocessing_dict' dictionary. + preprocessing_dict['func_user_method_data_input_preparation'] \ + = import_user_method_data_preparation.user_method_data_input_preparation + preprocessing_dict['func_user_method_data_output_preparation'] \ + = import_user_method_data_preparation.user_method_data_output_preparation + preprocessing_dict['func_user_method_plot'] = import_user_method_plot.method_plot + preprocessing_dict['func_user_method_html_report'] = import_user_method_html_report.method_html_report + preprocessing_dict['func_user_method_xml_export'] = import_user_method_xml_export.method_xml_export + preprocessing_dict['func_user_method_tex_output'] = import_user_method_tex_output.method_tex_output + # Exception handling for module import error. + except ModuleNotFoundError as module_import_error: + runtime_output_string = ('Error: ' + str(module_import_error) + ' found in ' + + preprocessing_dict['module_name'] + '.\n' + + ' Program aborted.') + runtime_output.critical(runtime_output_string) + sys.exit(1) + + return paths_and_names, preprocessing_dict, runtime_output