Skip to content

Commit f10db48

Browse files
Merge pull request #79 from ie3-institute/ck/#78-weatherSourceDefaultResolution
Adapt default resolution of weather source
2 parents ad824fc + 47530b3 commit f10db48

File tree

11 files changed

+320
-66
lines changed

11 files changed

+320
-66
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
- Re-organizing test resources into their respective packages [#105](https://github.com/ie3-institute/simona/issues/105)
1515
- BREAKING: Using snapshot version of PSDM
1616
- Simplified PrimaryServiceProxy due to changes in PSDM [#120](https://github.com/ie3-institute/simona/issues/120)
17+
- Improved handling of weights and their sum in determination of weather data [#173](https://github.com/ie3-institute/simona/issues/173)
1718

1819
### Fixed
1920
- Location of `vn_simona` test grid (was partially in Berlin and Dortmund)
2021
- Let `ParticipantAgent` die after failed registration with secondary services (prevents stuck simulation)
22+
- Fix default resolution of weather source wrapper [#78](https://github.com/ie3-institute/simona/issues/78)
2123

2224
[Unreleased]: https://github.com/ie3-institute/simona/compare/a14a093239f58fca9b2b974712686b33e5e5f939...HEAD

docs/uml/main/ParticipantModelling.puml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ package edu.ie3.edu.ie3.simona {
4141
}
4242
DateTime --|> SecondaryData
4343

44-
Class Weather{
45-
+ diffRad: Quantity[Irradiation]
46-
+ dirRad: Quantity[Irradiation]
44+
Class WeatherData{
45+
+ diffIrr: Quantity[Irradiation]
46+
+ dirIrr: Quantity[Irradiation]
4747
+ temp: Quantity[Temperature]
4848
+ windVel: Quantity[Speed]
4949
}

src/main/scala/edu/ie3/simona/agent/participant/pv/PVAgentFundamentals.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,8 @@ protected trait PVAgentFundamentals
230230
PVRelevantData(
231231
dateTime,
232232
tickInterval,
233-
weatherData.diffRad,
234-
weatherData.dirRad
233+
weatherData.diffIrr,
234+
weatherData.dirIrr
235235
)
236236

237237
val power = pvModel.calculatePower(

src/main/scala/edu/ie3/simona/ontology/messages/services/WeatherMessage.scala

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,21 @@ object WeatherMessage {
5656
) extends WeatherMessage
5757
with ProvisionMessage[WeatherData]
5858

59-
/** Hold entire weather result together
59+
/** Container class for the entirety of weather information at a certain point
60+
* in time and at a certain coordinate
61+
*
62+
* @param diffIrr
63+
* Diffuse irradiance on the horizontal pane
64+
* @param dirIrr
65+
* Direct irradiance on the horizontal pane
66+
* @param temp
67+
* Temperature
68+
* @param windVel
69+
* Wind velocity
6070
*/
6171
final case class WeatherData(
62-
diffRad: ComparableQuantity[Irradiance],
63-
dirRad: ComparableQuantity[Irradiance],
72+
diffIrr: ComparableQuantity[Irradiance],
73+
dirIrr: ComparableQuantity[Irradiance],
6474
temp: ComparableQuantity[Temperature],
6575
windVel: ComparableQuantity[Speed]
6676
) extends SecondaryData

src/main/scala/edu/ie3/simona/service/weather/WeatherSource.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ trait WeatherSource {
164164
}
165165
}
166166

167-
/** Determine the weights of each coordinate
167+
/** Determine the weights of each coordinate. It is ensured, that the entirety
168+
* of weights sum up to 1.0
168169
*
169170
* @param nearestCoordinates
170171
* Collection of nearest coordinates with their distances
@@ -522,9 +523,9 @@ object WeatherSource {
522523
): WeatherData = {
523524
WeatherData(
524525
weatherValue.getSolarIrradiance.getDiffuseIrradiance
525-
.orElse(EMPTY_WEATHER_DATA.diffRad),
526+
.orElse(EMPTY_WEATHER_DATA.diffIrr),
526527
weatherValue.getSolarIrradiance.getDirectIrradiance
527-
.orElse(EMPTY_WEATHER_DATA.dirRad),
528+
.orElse(EMPTY_WEATHER_DATA.dirIrr),
528529
weatherValue.getTemperature.getTemperature
529530
.orElse(EMPTY_WEATHER_DATA.temp),
530531
weatherValue.getWind.getVelocity.orElse(EMPTY_WEATHER_DATA.windVel)

src/main/scala/edu/ie3/simona/service/weather/WeatherSourceWrapper.scala

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import edu.ie3.datamodel.io.connectors.{
1313
SqlConnector
1414
}
1515
import edu.ie3.datamodel.io.factory.timeseries.{
16-
IconTimeBasedWeatherValueFactory,
17-
CosmoTimeBasedWeatherValueFactory
16+
CosmoTimeBasedWeatherValueFactory,
17+
IconTimeBasedWeatherValueFactory
1818
}
1919
import edu.ie3.datamodel.io.naming.FileNamingStrategy
2020
import edu.ie3.datamodel.io.source.couchbase.CouchbaseWeatherSource
@@ -45,7 +45,9 @@ import edu.ie3.simona.util.TickUtil
4545
import edu.ie3.simona.util.TickUtil.TickLong
4646
import edu.ie3.util.exceptions.EmptyQuantityException
4747
import edu.ie3.util.interval.ClosedInterval
48+
import edu.ie3.util.scala.DoubleUtils.ImplicitDouble
4849
import tech.units.indriya.quantity.Quantities
50+
import tech.units.indriya.unit.Units
4951

5052
import java.time.ZonedDateTime
5153
import javax.measure.Quantity
@@ -140,21 +142,21 @@ private[weather] final case class WeatherSourceWrapper private (
140142
)
141143

142144
/* Determine actual weights and contributions */
143-
val (diffRadContrib, diffRadWeight) = currentWeather.diffRad match {
144-
case EMPTY_WEATHER_DATA.diffRad => (EMPTY_WEATHER_DATA.diffRad, 0d)
145-
case nonEmptyDiffRad =>
145+
val (diffIrrContrib, diffIrrWeight) = currentWeather.diffIrr match {
146+
case EMPTY_WEATHER_DATA.diffIrr => (EMPTY_WEATHER_DATA.diffIrr, 0d)
147+
case nonEmptyDiffIrr =>
146148
calculateContrib(
147-
nonEmptyDiffRad,
149+
nonEmptyDiffIrr,
148150
weight,
149151
StandardUnits.SOLAR_IRRADIANCE,
150152
s"Diffuse solar irradiance not available at $point."
151153
)
152154
}
153-
val (dirRadContrib, dirRadWeight) = currentWeather.dirRad match {
154-
case EMPTY_WEATHER_DATA.dirRad => (EMPTY_WEATHER_DATA.dirRad, 0d)
155-
case nonEmptyDirRad =>
155+
val (dirIrrContrib, dirIrrWeight) = currentWeather.dirIrr match {
156+
case EMPTY_WEATHER_DATA.`dirIrr` => (EMPTY_WEATHER_DATA.dirIrr, 0d)
157+
case nonEmptyDirIrr =>
156158
calculateContrib(
157-
nonEmptyDirRad,
159+
nonEmptyDirIrr,
158160
weight,
159161
StandardUnits.SOLAR_IRRADIANCE,
160162
s"Direct solar irradiance not available at $point."
@@ -164,7 +166,7 @@ private[weather] final case class WeatherSourceWrapper private (
164166
case EMPTY_WEATHER_DATA.temp => (EMPTY_WEATHER_DATA.temp, 0d)
165167
case nonEmptyTemp =>
166168
calculateContrib(
167-
nonEmptyTemp,
169+
nonEmptyTemp.to(Units.KELVIN),
168170
weight,
169171
StandardUnits.TEMPERATURE,
170172
s"Temperature not available at $point."
@@ -184,29 +186,22 @@ private[weather] final case class WeatherSourceWrapper private (
184186
/* Sum up weight and contributions */
185187
(
186188
WeatherData(
187-
averagedWeather.diffRad.add(diffRadContrib),
188-
averagedWeather.dirRad.add(dirRadContrib),
189+
averagedWeather.diffIrr.add(diffIrrContrib),
190+
averagedWeather.dirIrr.add(dirIrrContrib),
189191
averagedWeather.temp.add(tempContrib),
190192
averagedWeather.windVel.add(windVelContrib)
191193
),
192194
currentWeightSum.add(
193-
diffRadWeight,
194-
dirRadWeight,
195+
diffIrrWeight,
196+
dirIrrWeight,
195197
tempWeight,
196198
windVelWeight
197199
)
198200
)
199201
} match {
200202
case (weatherData: WeatherData, weightSum: WeightSum) =>
201-
/* Divide by weight sum to correctly account for missing data. Change temperature scale back to absolute*/
202-
WeatherData(
203-
weatherData.diffRad.divide(weightSum.diffRad),
204-
weatherData.dirRad.divide(weightSum.dirRad),
205-
weatherData.temp.divide(weightSum.temp),
206-
weatherData.windVel.divide(weightSum.windVel)
207-
)
203+
weightSum.scale(weatherData)
208204
}
209-
210205
}
211206

212207
/** Determine an Array with all ticks between the request frame's start and
@@ -227,7 +222,7 @@ private[weather] final case class WeatherSourceWrapper private (
227222
}
228223

229224
private[weather] object WeatherSourceWrapper extends LazyLogging {
230-
private val DEFAULT_RESOLUTION = 360L
225+
private val DEFAULT_RESOLUTION = 3600L
231226

232227
def apply(
233228
csvSep: String,
@@ -363,26 +358,64 @@ private[weather] object WeatherSourceWrapper extends LazyLogging {
363358
)
364359
}
365360

361+
/** Simple container class to allow for accumulating determination of the sum
362+
* of weights for different weather properties for different locations
363+
* surrounding a given coordinate of interest
364+
*
365+
* @param diffIrr
366+
* Sum of weight for diffuse irradiance
367+
* @param dirIrr
368+
* Sum of weight for direct irradiance
369+
* @param temp
370+
* Sum of weight for temperature
371+
* @param windVel
372+
* Sum of weight for wind velocity
373+
*/
366374
final case class WeightSum(
367-
diffRad: Double,
368-
dirRad: Double,
375+
diffIrr: Double,
376+
dirIrr: Double,
369377
temp: Double,
370378
windVel: Double
371379
) {
372380
def add(
373-
diffRad: Double,
374-
dirRad: Double,
381+
diffIrr: Double,
382+
dirIrr: Double,
375383
temp: Double,
376384
windVel: Double
377385
): WeightSum =
378386
WeightSum(
379-
this.diffRad + diffRad,
380-
this.dirRad + dirRad,
387+
this.diffIrr + diffIrr,
388+
this.dirIrr + dirIrr,
381389
this.temp + temp,
382390
this.windVel + windVel
383391
)
392+
393+
/** Scale the given [[WeatherData]] by dividing by the sum of weights per
394+
* attribute of the weather data. If one of the weight sums is empty (and
395+
* thus a division by zero would happen) the defined "empty" information
396+
* for this attribute is returned.
397+
*
398+
* @param weatherData
399+
* Weighted and accumulated weather information
400+
* @return
401+
* Weighted weather information, which are divided by the sum of weights
402+
*/
403+
def scale(weatherData: WeatherData): WeatherData = weatherData match {
404+
case WeatherData(diffIrr, dirIrr, temp, windVel) =>
405+
implicit val precision: Double = 1e-3
406+
WeatherData(
407+
if (this.diffIrr !~= 0d) diffIrr.divide(this.diffIrr)
408+
else EMPTY_WEATHER_DATA.diffIrr,
409+
if (this.dirIrr !~= 0d) dirIrr.divide(this.dirIrr)
410+
else EMPTY_WEATHER_DATA.dirIrr,
411+
if (this.temp !~= 0d) temp.divide(this.temp)
412+
else EMPTY_WEATHER_DATA.temp,
413+
if (this.windVel !~= 0d) windVel.divide(this.windVel)
414+
else EMPTY_WEATHER_DATA.windVel
415+
)
416+
}
384417
}
385-
case object WeightSum {
418+
object WeightSum {
386419
val EMPTY_WEIGHT_SUM: WeightSum = WeightSum(0d, 0d, 0d, 0d)
387420
}
388421

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* © 2022. TU Dortmund University,
3+
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
4+
* Research group Distribution grid planning and operation
5+
*/
6+
7+
package edu.ie3.util.scala
8+
9+
@deprecated("Use implementation in power system utils package")
10+
object DoubleUtils {
11+
implicit class ImplicitDouble(d: Double) {
12+
def ~=(other: Double)(implicit precision: Double): Boolean =
13+
(d - other).abs <= precision
14+
def !~=(other: Double)(implicit precision: Double): Boolean =
15+
(d - other).abs > precision
16+
}
17+
}

src/test/groovy/edu/ie3/simona/model/participant/PVModelIT.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class PVModelIT extends Specification implements PVModelITHelper {
8888

8989
"build the needed data"
9090
WeatherMessage.WeatherData weather = modelToWeatherMap.get(modelId)
91-
PVModel.PVRelevantData neededData = new PVModel.PVRelevantData(dateTime,3600L, weather.diffRad() as ComparableQuantity<Irradiance>, weather.dirRad() as ComparableQuantity<Irradiance>)
91+
PVModel.PVRelevantData neededData = new PVModel.PVRelevantData(dateTime,3600L, weather.diffIrr() as ComparableQuantity<Irradiance>, weather.dirIrr() as ComparableQuantity<Irradiance>)
9292
ComparableQuantity<Dimensionless> voltage = getQuantity(1.414213562, PU)
9393

9494
"collect the results and calculate the difference between the provided results and the calculated ones"

src/test/scala/edu/ie3/simona/agent/participant/PVAgentModelCalculationSpec.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -585,8 +585,8 @@ class PVAgentModelCalculationSpec
585585
0L -> PVRelevantData(
586586
0L.toDateTime,
587587
3600L,
588-
weatherData.diffRad,
589-
weatherData.dirRad
588+
weatherData.diffIrr,
589+
weatherData.dirIrr
590590
)
591591
)
592592
}
@@ -737,8 +737,8 @@ class PVAgentModelCalculationSpec
737737
0L -> PVRelevantData(
738738
0L.toDateTime,
739739
3600L,
740-
weatherData.diffRad,
741-
weatherData.dirRad
740+
weatherData.diffIrr,
741+
weatherData.dirIrr
742742
)
743743
)
744744
}

src/test/scala/edu/ie3/simona/service/weather/SampleWeatherSourceSpec.scala

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,16 @@ class SampleWeatherSourceSpec
8383
val actual = source invokePrivate getWeatherPrivate(tick)
8484

8585
/* Units meet expectation */
86-
actual.diffRad.getUnit shouldBe StandardUnits.SOLAR_IRRADIANCE
87-
actual.dirRad.getUnit shouldBe StandardUnits.SOLAR_IRRADIANCE
86+
actual.diffIrr.getUnit shouldBe StandardUnits.SOLAR_IRRADIANCE
87+
actual.dirIrr.getUnit shouldBe StandardUnits.SOLAR_IRRADIANCE
8888
actual.temp.getUnit shouldBe StandardUnits.TEMPERATURE
8989
actual.windVel.getUnit shouldBe StandardUnits.WIND_VELOCITY
9090

9191
/* Values meet expectations */
92-
actual.diffRad should equalWithTolerance(
92+
actual.diffIrr should equalWithTolerance(
9393
Quantities.getQuantity(72.7656, StandardUnits.SOLAR_IRRADIANCE)
9494
)
95-
actual.dirRad should equalWithTolerance(
95+
actual.dirIrr should equalWithTolerance(
9696
Quantities.getQuantity(80.1172, StandardUnits.SOLAR_IRRADIANCE)
9797
)
9898
actual.windVel should equalWithTolerance(
@@ -108,14 +108,14 @@ class SampleWeatherSourceSpec
108108
WeightedCoordinates(Map(NodeInput.DEFAULT_GEO_POSITION -> 1d))
109109

110110
source.getWeather(tick, weightedCoordinates) match {
111-
case WeatherData(diffRad, dirRad, temp, windVel) =>
112-
diffRad.getUnit shouldBe StandardUnits.SOLAR_IRRADIANCE
113-
diffRad should equalWithTolerance(
111+
case WeatherData(diffIrr, dirIrr, temp, windVel) =>
112+
diffIrr.getUnit shouldBe StandardUnits.SOLAR_IRRADIANCE
113+
diffIrr should equalWithTolerance(
114114
Quantities.getQuantity(72.7656, StandardUnits.SOLAR_IRRADIANCE)
115115
)
116116

117-
dirRad.getUnit shouldBe StandardUnits.SOLAR_IRRADIANCE
118-
dirRad should equalWithTolerance(
117+
dirIrr.getUnit shouldBe StandardUnits.SOLAR_IRRADIANCE
118+
dirIrr should equalWithTolerance(
119119
Quantities.getQuantity(80.1172, StandardUnits.SOLAR_IRRADIANCE)
120120
)
121121

0 commit comments

Comments
 (0)