Source code for pysolorie.report

#    Copyright 2023 Alireza Aghamohammadi

#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at

#        http://www.apache.org/licenses/LICENSE-2.0

#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

import csv
import json
import xml.etree.ElementTree as ET
from pathlib import Path
from typing import Dict, List, Union

from .logger import logger_decorator
from .numerical_integration import IrradiationCalculator


[docs] class ReportGenerator: r""" A class to generate reports for the optimal orientation of solar panels and the total direct irradiation. """ @logger_decorator def _calculate_optimal_orientation_and_irradiation( self, irradiation_calculator: IrradiationCalculator, from_day: int, to_day: int, ) -> List[Dict[str, Union[int, float]]]: r""" This private method calculates the optimal solar panel orientation and total direct irradiation for a range of days. :param irradiation_calculator: An instance of the IrradiationCalculator class. :type irradiation_calculator: pysolorie.IrradiationCalculator :param from_day: The starting day of the report. :type from_day: int :param to_day: The ending day of the report. :type to_day: int :return: A list of dictionaries, each containing the day, optimal orientation (beta), and total direct irradiation. :rtype: List[Dict[str, Union[int, float]]] """ data = [] for day in range(from_day, to_day): beta = irradiation_calculator.find_optimal_orientation(day) total_direct_irradiation = ( irradiation_calculator.calculate_direct_irradiation(beta, day) ) self.logger.info( # type: ignore f"On day {day}, the solar panel's optimal orientation is " f"{beta} degrees, and the total direct irradiation is " f"{total_direct_irradiation} Megajoules per square meter." ) # Append the result to the data list data.append( { "Day": day, "Beta (degrees)": beta, "Direct Irradiation " "(Megajoules per square meter)": total_direct_irradiation, } ) return data
[docs] @logger_decorator def generate_optimal_orientation_csv_report( self, path: Path, irradiation_calculator: IrradiationCalculator, from_day: int, to_day: int, ) -> None: r""" This method generates a report of optimal solar panel orientation in CSV format. It uses the ``_calculate_optimal_orientation_and_irradiation`` method to get the data. :param path: A Path object that points to the CSV file where the report will be written. :type path: Path :param irradiation_calculator: An instance of the IrradiationCalculator class. :type irradiation_calculator: pysolorie.IrradiationCalculator :param from_day: The starting day of the report. :type from_day: int :param to_day: The ending day of the report. :type to_day: int """ data = self._calculate_optimal_orientation_and_irradiation( irradiation_calculator, from_day, to_day ) with open(path, "w", newline="") as file: writer = csv.writer(file) writer.writerow( [ "Day", "Beta (degrees)", "Direct Irradiation (Megajoules per square meter)", ] ) for row in data: writer.writerow( [ row["Day"], row["Beta (degrees)"], row["Direct Irradiation (Megajoules per square meter)"], ] )
[docs] @logger_decorator def generate_optimal_orientation_json_report( self, path: Path, irradiation_calculator: IrradiationCalculator, from_day: int, to_day: int, ) -> None: r""" This method generates a report of optimal solar panel orientation in JSON format. It uses the ``_calculate_optimal_orientation_and_irradiation`` method to get the data. :param path: A Path object that points to the JSON file where the report will be written. :type path: Path :param irradiation_calculator: An instance of the IrradiationCalculator class. :type irradiation_calculator: pysolorie.IrradiationCalculator :param from_day: The starting day of the report. :type from_day: int :param to_day: The ending day of the report. :type to_day: int """ data = self._calculate_optimal_orientation_and_irradiation( irradiation_calculator, from_day, to_day ) # Write the data list to the JSON file with open(path, "w") as file: json.dump(data, file, indent=4)
[docs] @logger_decorator def generate_optimal_orientation_xml_report( self, path: Path, irradiation_calculator: IrradiationCalculator, from_day: int, to_day: int, ) -> None: r""" This method generates a report of optimal solar panel orientation in XML format. It uses the ``_calculate_optimal_orientation_and_irradiation`` method to get the data. :param path: A Path object that points to the XML file where the report will be written. :type path: Path :param irradiation_calculator: An instance of the IrradiationCalculator class. :type irradiation_calculator: pysolorie.IrradiationCalculator :param from_day: The starting day of the report. :type from_day: int :param to_day: The ending day of the report. :type to_day: int """ data = self._calculate_optimal_orientation_and_irradiation( irradiation_calculator, from_day, to_day ) # Create the root element root = ET.Element("Report") for row in data: # Create a 'Day' element for each day day_element = ET.SubElement(root, "Day") day_element.set("id", str(row["Day"])) # Create 'Beta' and 'DirectIrradiation' elements for each day beta_element = ET.SubElement(day_element, "Beta") beta_element.text = str(row["Beta (degrees)"]) tdi_element = ET.SubElement(day_element, "DirectIrradiation") tdi_element.text = str( row["Direct Irradiation (Megajoules per square meter)"] ) # Write the XML data to the file tree = ET.ElementTree(root) tree.write(path)