Skip to content

Commit

Permalink
separate ui logic
Browse files Browse the repository at this point in the history
  • Loading branch information
ThibClnt committed Jan 19, 2024
1 parent e3cb62d commit 368029c
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 111 deletions.
162 changes: 58 additions & 104 deletions src/main/scala/UI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,124 +9,46 @@ import PowerTemperatureAnalysis._
*/
object UI {

/** Menu options with their associated actions to perform
* @return
* a chunk of tuples (name, action), action being a function that takes LoadedData and returns a ZIO effect that will return Unit
*/
val menuOptions: Chunk[(String, (LoadedData) => ZIO[Any, Any, Unit])] = Chunk(
"Get stats for a specific day" -> ((data) =>
for {
_ <- printLine("Please enter a date (dd/MM/yyyy): ")
date <- readDate
_ <- printLine(s"Stats for $date:")
} yield ()
),
"Global statistics for a given period" -> ((data) =>
for {
_ <- printLine("Please enter a start date (dd/MM/yyyy): ")
startDate <- readDate
_ <- printLine("Please enter an end date (dd/MM/yyyy): ")
endDate <- readDate
_ <- printLine(
GlobalStatisticsAnalysis.formatStatisticsTable(
"Environmental impact of electricity production and consumption",
GlobalStatisticsAnalysis.getCarbonIntensityStatistics(data, startDate, endDate),
s"Data between $startDate and $endDate"
)
)
_ <- printLine(
"\n\n" +
GlobalStatisticsAnalysis.formatStatisticsTable(
"Electricty consumption and temperature",
GlobalStatisticsAnalysis.getTemperatureAndConsumptionStatistics(data, startDate, endDate),
s"Data between $startDate and $endDate"
)
)
_ <- printLine(
"\n\n" +
GlobalStatisticsAnalysis.formatStatisticsTable(
"Production (MW) by supply chain",
GlobalStatisticsAnalysis.getProductionBySupplyChain(data, startDate, endDate),
s"Data between $startDate and $endDate"
)
)
} yield ()
),
"Case study: Temperature vs power peak" -> ((data) => printLine(formatPowerPeakAndTemperature(data)))
)

/** Retrieves the information about maximum power peak and minimum temperature entries for each year and formats it into a newline-separated string.
*
* @param data
* The loaded data containing daily power peak with temperature information.
* @return
* A formatted string containing information about maximum power peak and minimum temperature entries for each year, with each entry on a new line.
*/
def formatPowerPeakAndTemperature(data: LoadedData): String = {
val title = "+-------------------------------------------------------------------------+\n" +
"| Case Study : Power and Temperature Summary |\n" +
"+-------------------------------------------------------------------------+\n" +
"| We want to know the maximum power peak and the minimum temperature for |\n" +
"| each year. |\n" +
"+-------------------------------------------------------------------------+\n"

val output = powerPeakTemperatureGroupedByYear(data)
.flatMap {
case (year, yearData) => {
val (maxPowerEntry, minTemperatureEntry) = maxPowerPeakAndMinTemperature(yearData)
Some(
f"| Year $year |\n" +
"+-------------------------------------------------------------------------+\n" +
f"| Max Power Peak: ${maxPowerEntry.powerPeak}%10.2f MW on ${maxPowerEntry.date} |\n" +
f"| Min Temperature: ${minTemperatureEntry.meanTemperature}%10.2f C on ${minTemperatureEntry.date} |\n" +
"+-------------------------------------------------------------------------+\n".stripMargin.trim
)
}
}
.mkString("\n")

val pearsonCoef = temperatureAndPowerPeakPearsonCorrelation(data.dailyPowerPeakWithTemperature)
val pearsonCoefFormatted =
f"\n| Temperature And PowerPeak Pearson Correlation: $pearsonCoef%5.2f |\n" +
"+-------------------------------------------------------------------------+\n"

val conclusion =
"| Final Conclusion |\n" +
"+-------------------------------------------------------------------------+\n" +
"| - The correlation coefficient indicates a strong correlation. |\n" +
"| - As temperatures decrease, power peak tends to increase. |\n" +
"| - People tend to use more electricity for heating purposes when |\n" +
"| temperatures fall |\n" +
"+-------------------------------------------------------------------------+\n"

title + output + pearsonCoefFormatted + conclusion
}

val choiceMenu: String =
"Welcome to our energy analysis tool!\n\nHere are all the interesting interactions you can have with it:\n"
+ menuOptions.zipWithIndex
.map { case ((name, _), index) =>
s"${index + 1}. $name"
}
.mkString("\n")
+ "\n\nPlease enter your choice: "

/** Main ZIO console loop
* @return
* a ZIO effect that will return Unit
*/
def consoleLoop(data: LoadedData): ZIO[Any, Any, Unit] = {
for {
_ <- printLine(choiceMenu)
_ <- printLine(menuString)
input <- readLine
_ <- menuOptions.lift(input.toInt - 1) match {
_ <- menuChoices.lift(input.toInt - 1) match {
case Some((_, action)) => action(data)
case None => printLineError("Invalid choice")
}
_ <- consoleLoop(data)
} yield ()
}

/** Menu options with their associated actions to perform
* @return
* a chunk of tuples (name, action), action being a function that takes LoadedData and returns a ZIO effect that will return Unit
*/
val menuChoices: Chunk[(String, (LoadedData) => ZIO[Any, Any, Unit])] =
Chunk(
("Get stats for a specific day", printDailyStats),
("Global statistics for a given period", printGlobalStats),
("Case study: Temperature vs power peak", printCaseStudy)
)

/** Menu string
* @return
* a String containing the menu and its options
*/
val menuString: String =
"Welcome to our energy analysis tool!\n\nHere are all the interesting interactions you can have with it:\n"
+ menuChoices.zipWithIndex
.map { case ((name, _), index) =>
s"${index + 1}. $name"
}
.mkString("\n")
+ "\n\nPlease enter your choice: "

/** Reads a date from the console
* @return
* a ZIO effect that will return a LocalDate
Expand All @@ -139,4 +61,36 @@ object UI {
case None => printLineError("You entered an invalid date, retry.\n") *> readDate
}
} yield date

def printDailyStats(data: LoadedData): ZIO[Any, Any, Unit] = {
for {
_ <- printLine("Please enter a date (dd/MM/yyyy): ")
date <- readDate
_ <- printLine(s"Stats for $date:")
} yield ()
}

def printGlobalStats(data: LoadedData): ZIO[Any, Any, Unit] = {
for {
_ <- printLine("Please enter a start date (dd/MM/yyyy): ")
startDate <- readDate
_ <- printLine("Please enter an end date (dd/MM/yyyy): ")
endDate <- readDate

_ <- printLine("\n\n" + GlobalStatisticsAnalysis.carbonIntensityTab(data, startDate, endDate))
_ <- printLine("\n\n" + GlobalStatisticsAnalysis.productionBySupplyChainTab(data, startDate, endDate))
_ <- printLine("\n\n" + GlobalStatisticsAnalysis.consumptionAndTemperatureTab(data, startDate, endDate) + "\n")
} yield ()
}

def printCaseStudy(data: LoadedData): ZIO[Any, Any, Unit] = {
for {
_ <- printLine(
formatPowerPeakAndTemperature(
maxPowerPeaksAndMinTemperaturesByYear(data),
temperatureAndPowerPeakPearsonCorrelation(data)
)
)
} yield ()
}
}
56 changes: 55 additions & 1 deletion src/main/scala/analysis/GlobalStatisticsAnalysis.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ object GlobalStatisticsAnalysis {
val count = values.size

Statistics(fieldName, average, stdDev, min, max, count)
}.toList
}.toList
}

/** Get a formatted table of statistics.
Expand Down Expand Up @@ -215,4 +215,58 @@ object GlobalStatisticsAnalysis {
end
)
}

/** Get a formatted table of statistics about the carbon intensity of electricity production and consumption, given a period of time.
*
* @param data
* The data to analyse.
* @param startDate
* The start date of the period.
* @param endDate
* The end date of the period.
* @return
* A formatted table
*/
def carbonIntensityTab(data: LoadedData, startDate: LocalDate, endDate: LocalDate): String =
GlobalStatisticsAnalysis.formatStatisticsTable(
"Environmental impact of electricity production and consumption",
GlobalStatisticsAnalysis.getCarbonIntensityStatistics(data, startDate, endDate),
s"Data between $startDate and $endDate"
)

/** Get a formatted table of statistics about the temperature and power consumption, given a period of time.
*
* @param data
* The data to analyse.
* @param startDate
* The start date of the period.
* @param endDate
* The end date of the period.
* @return
* A formatted table
*/
def consumptionAndTemperatureTab(data: LoadedData, startDate: LocalDate, endDate: LocalDate): String =
GlobalStatisticsAnalysis.formatStatisticsTable(
"Electricty consumption and temperature",
GlobalStatisticsAnalysis.getTemperatureAndConsumptionStatistics(data, startDate, endDate),
s"Data between $startDate and $endDate"
)

/** Get a formatted table of statistics about the production by supply chain, given a period of time.
*
* @param data
* The data to analyse.
* @param startDate
* The start date of the period.
* @param endDate
* The end date of the period.
* @return
* A formatted table
*/
def productionBySupplyChainTab(data: LoadedData, startDate: LocalDate, endDate: LocalDate): String =
GlobalStatisticsAnalysis.formatStatisticsTable(
"Production (MW) by supply chain",
GlobalStatisticsAnalysis.getProductionBySupplyChain(data, startDate, endDate),
s"Data between $startDate and $endDate"
)
}
71 changes: 65 additions & 6 deletions src/main/scala/analysis/PowerTemperatureAnalysis.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ object PowerTemperatureAnalysis {
* @return
* A Map where the key is the year and the value is a List of daily power peak with temperature entries for that year.
*/
def powerPeakTemperatureGroupedByYear(data: LoadedData): Map[Int, List[DailyPowerPeakWithTemperature]] = {
data.dailyPowerPeakWithTemperature.toList.groupBy(pp => pp.date.getYear)
def powerPeakTemperatureGroupedByYear(data: LoadedData): Map[Int, Chunk[DailyPowerPeakWithTemperature]] = {
data.dailyPowerPeakWithTemperature.groupBy(pp => pp.date.getYear)
}

/** Finds the maximum power peak and minimum temperature entries in the given list of daily power peak with temperature data for a specific year.
Expand All @@ -23,18 +23,77 @@ object PowerTemperatureAnalysis {
* @return
* A tuple containing the maximum power peak entry and the minimum temperature entry for the specified year.
*/
def maxPowerPeakAndMinTemperature(yearData: List[DailyPowerPeakWithTemperature]): (DailyPowerPeakWithTemperature, DailyPowerPeakWithTemperature) =
def maxPowerPeakAndMinTemperatureOfYear(yearData: Chunk[DailyPowerPeakWithTemperature]): (DailyPowerPeakWithTemperature, DailyPowerPeakWithTemperature) =
(yearData.maxBy(_.powerPeak), yearData.minBy(_.meanTemperature))

/** Retrieves the information about maximum power peak and minimum temperature entries for each year.
*
* @param data
* The loaded data containing daily power peak with temperature information.
* @return
* A chunk of tuples containing the year, the maximum power peak entry for that year and the minimum temperature entry for that year.
*/
def maxPowerPeaksAndMinTemperaturesByYear(data: LoadedData): Chunk[(Int, DailyPowerPeakWithTemperature, DailyPowerPeakWithTemperature)] =
Chunk
.fromIterable(
powerPeakTemperatureGroupedByYear(data)
.map((year, yearData) => {
val (maxPowerPeak, minTemperature) = maxPowerPeakAndMinTemperatureOfYear(yearData)
(year, maxPowerPeak, minTemperature)
})
)
.sortBy(_._1)

/** Calculates the Pearson correlation coefficient between the given power peaks and temperatures.
*
* @param data
* The loaded chunk of data containing daily power peaks with temperature information.
* @return
* The Pearson correlation coefficient between the given power peaks and temperatures.
*/
def temperatureAndPowerPeakPearsonCorrelation(data: Chunk[DailyPowerPeakWithTemperature]): Double =
val temperatures: Chunk[Temperature.Celsius] = data.map(line => line.meanTemperature)
val powerPeaks: Chunk[Power.MW] = data.map(line => line.powerPeak)
def temperatureAndPowerPeakPearsonCorrelation(data: LoadedData): Double =
val temperatures: Chunk[Temperature.Celsius] = data.dailyPowerPeakWithTemperature.map(line => line.meanTemperature)
val powerPeaks: Chunk[Power.MW] = data.dailyPowerPeakWithTemperature.map(line => line.powerPeak)
linearCorrelationCoefficient(powerPeaks, temperatures)

/** Retrieves the information about maximum power peak and minimum temperature entries for each year and formats it into a newline-separated string.
*
* @param data
* The loaded data containing daily power peak with temperature information.
* @return
* A formatted string containing information about maximum power peak and minimum temperature entries for each year, with each entry on a new line.
*/
def formatPowerPeakAndTemperature(yearsData: Chunk[(Int, DailyPowerPeakWithTemperature, DailyPowerPeakWithTemperature)], correlationCoef: Double): String = {
val title = "+-------------------------------------------------------------------------+\n" +
"| Case Study : Power and Temperature Summary |\n" +
"+-------------------------------------------------------------------------+\n" +
"| We want to know the maximum power peak and the minimum temperature for |\n" +
"| each year. |\n" +
"+-------------------------------------------------------------------------+\n"

val yearsSummaries = yearsData
.map((year, maxPowerEntry, minTemperatureEntry) =>
f"| Year $year |\n" +
"+-------------------------------------------------------------------------+\n" +
f"| Max Power Peak: ${maxPowerEntry.powerPeak}%10.2f MW on ${maxPowerEntry.date} |\n" +
f"| Min Temperature: ${minTemperatureEntry.meanTemperature}%10.2f C on ${minTemperatureEntry.date} |\n" +
"+-------------------------------------------------------------------------+\n".stripMargin.trim
)
.mkString("\n")

val pearsonCoefFormatted =
f"\n| Temperature And PowerPeak Pearson Correlation: $correlationCoef%5.2f |\n" +
"+-------------------------------------------------------------------------+\n"

val conclusion =
"| Final Conclusion |\n" +
"+-------------------------------------------------------------------------+\n" +
"| - The correlation coefficient indicates a strong enough correlation. |\n" +
"| - As daily temperatures decrease, daily power peak tends to increase. |\n" +
"| - People tend to use more electricity for heating purposes when |\n" +
"| temperatures fall |\n" +
"+-------------------------------------------------------------------------+\n"

title + yearsSummaries + pearsonCoefFormatted + conclusion
}
}

0 comments on commit 368029c

Please sign in to comment.