-
Notifications
You must be signed in to change notification settings - Fork 6
Introducing primary data from SQL #98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
99fa1ee
ff30158
7c6f6f4
4ec37aa
1212567
c2b2cfb
8d41e16
882baa6
bf85357
57a4b6a
f996895
b7dcb41
ce1a756
8dcbc8c
0e885d5
880697f
dae690d
962e87d
dbc797d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,14 +7,17 @@ | |
package edu.ie3.simona.service.primary | ||
|
||
import akka.actor.{ActorRef, Props} | ||
import edu.ie3.datamodel.io.connectors.SqlConnector | ||
import edu.ie3.datamodel.io.csv.timeseries.ColumnScheme | ||
import edu.ie3.datamodel.io.factory.timeseries.TimeBasedSimpleValueFactory | ||
import edu.ie3.datamodel.io.naming.FileNamingStrategy | ||
import edu.ie3.datamodel.io.source.TimeSeriesSource | ||
import edu.ie3.datamodel.io.source.csv.CsvTimeSeriesSource | ||
import edu.ie3.datamodel.io.source.sql.SqlTimeSeriesSource | ||
import edu.ie3.datamodel.models.value.Value | ||
import edu.ie3.simona.agent.participant.data.Data.PrimaryData | ||
import edu.ie3.simona.agent.participant.data.Data.PrimaryData.RichValue | ||
import edu.ie3.simona.config.SimonaConfig.Simona.Input.Primary.SqlParams | ||
import edu.ie3.simona.exceptions.InitializationException | ||
import edu.ie3.simona.exceptions.WeatherServiceException.InvalidRegistrationRequestException | ||
import edu.ie3.simona.ontology.messages.SchedulerMessage | ||
|
@@ -24,11 +27,11 @@ import edu.ie3.simona.service.ServiceStateData.{ | |
InitializeServiceStateData, | ||
ServiceActivationBaseStateData | ||
} | ||
import edu.ie3.simona.service.{ServiceStateData, SimonaService} | ||
import edu.ie3.simona.service.primary.PrimaryServiceWorker.{ | ||
PrimaryServiceInitializedStateData, | ||
ProvidePrimaryDataMessage | ||
} | ||
import edu.ie3.simona.service.{ServiceStateData, SimonaService} | ||
import edu.ie3.simona.util.TickUtil.{RichZonedDateTime, TickLong} | ||
import edu.ie3.util.scala.collection.immutable.SortedDistinctSeq | ||
|
||
|
@@ -61,68 +64,94 @@ final case class PrimaryServiceWorker[V <: Value]( | |
PrimaryServiceInitializedStateData[V], | ||
Option[Seq[SchedulerMessage.ScheduleTriggerMessage]] | ||
) | ||
] = initServiceData match { | ||
case PrimaryServiceWorker.CsvInitPrimaryServiceStateData( | ||
timeSeriesUuid, | ||
simulationStart, | ||
csvSep, | ||
directoryPath, | ||
filePath, | ||
fileNamingStrategy, | ||
timePattern | ||
) => | ||
/* Got the right data. Attempt to set up a source and acquire information */ | ||
implicit val startDateTime: ZonedDateTime = simulationStart | ||
] = { | ||
(initServiceData match { | ||
case PrimaryServiceWorker.CsvInitPrimaryServiceStateData( | ||
timeSeriesUuid, | ||
simulationStart, | ||
csvSep, | ||
directoryPath, | ||
filePath, | ||
fileNamingStrategy, | ||
timePattern | ||
) => | ||
Try { | ||
/* Set up source and acquire information */ | ||
val factory = new TimeBasedSimpleValueFactory(valueClass, timePattern) | ||
val source = new CsvTimeSeriesSource( | ||
csvSep, | ||
directoryPath, | ||
fileNamingStrategy, | ||
timeSeriesUuid, | ||
filePath, | ||
valueClass, | ||
factory | ||
) | ||
(source, simulationStart) | ||
} | ||
case PrimaryServiceWorker.SqlInitPrimaryServiceStateData( | ||
sqlParams: SqlParams, | ||
timeSeriesUuid: UUID, | ||
simulationStart: ZonedDateTime | ||
) => | ||
Try { | ||
val factory = | ||
new TimeBasedSimpleValueFactory(valueClass, sqlParams.timePattern) | ||
|
||
Try { | ||
/* Set up source and acquire information */ | ||
val factory = new TimeBasedSimpleValueFactory(valueClass, timePattern) | ||
val source = new CsvTimeSeriesSource( | ||
csvSep, | ||
directoryPath, | ||
fileNamingStrategy, | ||
timeSeriesUuid, | ||
filePath, | ||
valueClass, | ||
factory | ||
) | ||
/* This seems not to be very efficient, but it is as efficient as possible. The getter method points to a | ||
* final attribute within the source implementation. */ | ||
sebastian-peter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
val (maybeNextTick, furtherActivationTicks) = SortedDistinctSeq( | ||
source.getTimeSeries.getEntries.asScala | ||
.filter { timeBasedValue => | ||
val dateTime = timeBasedValue.getTime | ||
dateTime.isEqual(simulationStart) || dateTime.isAfter( | ||
simulationStart | ||
) | ||
} | ||
.map(timeBasedValue => timeBasedValue.getTime.toTick) | ||
.toSeq | ||
.sorted | ||
).pop | ||
val sqlConnector = new SqlConnector( | ||
sqlParams.jdbcUrl, | ||
sqlParams.userName, | ||
sqlParams.password | ||
) | ||
|
||
/* Set up the state data and determine the next activation tick. */ | ||
val initializedStateData = | ||
PrimaryServiceInitializedStateData( | ||
maybeNextTick, | ||
furtherActivationTicks, | ||
simulationStart, | ||
source | ||
val source = new SqlTimeSeriesSource( | ||
sqlConnector, | ||
sqlParams.schemaName, | ||
sqlParams.tableName, | ||
sebastian-peter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
timeSeriesUuid, | ||
valueClass, | ||
factory | ||
) | ||
val triggerMessage = | ||
ServiceActivationBaseStateData.tickToScheduleTriggerMessages( | ||
maybeNextTick, | ||
self | ||
|
||
(source, simulationStart) | ||
} | ||
case unsupported => | ||
/* Got the wrong init data */ | ||
Failure( | ||
new InitializationException( | ||
s"Provided init data '${unsupported.getClass.getSimpleName}' for primary service are invalid!" | ||
) | ||
(initializedStateData, triggerMessage) | ||
} | ||
case unsupported => | ||
/* Got the wrong init data */ | ||
Failure( | ||
new InitializationException( | ||
s"Provided init data '${unsupported.getClass.getSimpleName}' for primary service are invalid!" | ||
) | ||
) | ||
}).map { case (source, simulationStart) => | ||
val (maybeNextTick, furtherActivationTicks) = SortedDistinctSeq( | ||
// Note: The whole data set is used here, which might be inefficient depending on the source implementation. | ||
sebastian-peter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
source.getTimeSeries.getEntries.asScala | ||
.filter { timeBasedValue => | ||
val dateTime = timeBasedValue.getTime | ||
dateTime.isEqual(simulationStart) || dateTime.isAfter( | ||
simulationStart | ||
) | ||
} | ||
.map(timeBasedValue => timeBasedValue.getTime.toTick) | ||
.toSeq | ||
.sorted | ||
).pop | ||
|
||
/* Set up the state data and determine the next activation tick. */ | ||
val initializedStateData = | ||
PrimaryServiceInitializedStateData( | ||
maybeNextTick, | ||
furtherActivationTicks, | ||
simulationStart, | ||
source | ||
) | ||
val triggerMessage = | ||
ServiceActivationBaseStateData.tickToScheduleTriggerMessages( | ||
maybeNextTick, | ||
self | ||
) | ||
(initializedStateData, triggerMessage) | ||
} | ||
} | ||
|
||
/** Handle a request to register for information from this service | ||
|
@@ -348,6 +377,22 @@ case object PrimaryServiceWorker { | |
timePattern: String | ||
) extends InitPrimaryServiceStateData | ||
|
||
/** Specific implementation of [[InitPrimaryServiceStateData]], if the source | ||
* to use utilizes an SQL database. | ||
* | ||
* @param sqlParams | ||
* Parameters regarding SQL connection and table selection | ||
* @param timeSeriesUuid | ||
* Unique identifier of the time series to read | ||
* @param simulationStart | ||
* Wall clock time of the beginning of simulation time | ||
*/ | ||
final case class SqlInitPrimaryServiceStateData( | ||
sqlParams: SqlParams, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A matter of taste, but I don't like handing over container classes aka. data structures. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well the sql params contain five fields, which would blow up this constructor. So I think it makes sense to use the config class here. |
||
override val timeSeriesUuid: UUID, | ||
override val simulationStart: ZonedDateTime | ||
) extends InitPrimaryServiceStateData | ||
|
||
/** Class carrying the state of a fully initialized [[PrimaryServiceWorker]] | ||
* | ||
* @param maybeNextActivationTick | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
CREATE TABLE public."its_p_9185b8c1-86ba-4a16-8dea-5ac898e8caa5" | ||
( | ||
time timestamp with time zone, | ||
p double precision, | ||
uuid uuid, | ||
CONSTRAINT its_p_pkey PRIMARY KEY (uuid) | ||
) | ||
WITH ( | ||
OIDS = FALSE | ||
) | ||
TABLESPACE pg_default; | ||
|
||
INSERT INTO | ||
public."its_p_9185b8c1-86ba-4a16-8dea-5ac898e8caa5" (uuid, time, p) | ||
VALUES | ||
('0245d599-9a5c-4c32-9613-5b755fac8ca0', '2020-01-01 00:00:00+0', 1000.0), | ||
sebastian-peter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
('a5e27652-9024-4a93-9d2a-590fbc3ab5a1', '2020-01-01 00:15:00+0', 1250.0); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
CREATE TABLE public."its_pqh_46be1e57-e4ed-4ef7-95f1-b2b321cb2047" | ||
( | ||
time timestamp with time zone, | ||
p double precision, | ||
q double precision, | ||
heat_demand double precision, | ||
uuid uuid, | ||
CONSTRAINT its_pqh_pkey PRIMARY KEY (uuid) | ||
) | ||
WITH ( | ||
OIDS = FALSE | ||
) | ||
TABLESPACE pg_default; | ||
|
||
INSERT INTO | ||
public."its_pqh_46be1e57-e4ed-4ef7-95f1-b2b321cb2047" (uuid, time, p, q, heat_demand) | ||
VALUES | ||
('661ac594-47f0-4442-8d82-bbeede5661f7', '2020-01-01 00:00:00+0', 1000.0, 329.0, 8.0), | ||
('5adcd6c5-a903-433f-b7b5-5fe669a3ed30', '2020-01-01 00:15:00+0', 1250.0, 411.0, 12.0); |
Uh oh!
There was an error while loading. Please reload this page.