Skip to content
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

Serialize sensitivity #50

Merged
merged 2 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@
<version>2023.3.3</version>
</dependency>

<!-- Force sensitivity analysis api one version higher. Can probably be removed in next powsybl-starter release -->
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-sensitivity-analysis-api</artifactId>
<version>6.1.0</version>
</dependency>

<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-server-core-jvm</artifactId>
Expand Down
11 changes: 10 additions & 1 deletion src/main/ApiDataModels.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.github.statnett.loadflowservice

import com.powsybl.iidm.network.Network
import com.powsybl.security.SecurityAnalysisResult
import com.powsybl.sensitivity.SensitivityAnalysisResult
import kotlinx.serialization.Serializable

/**
Expand Down Expand Up @@ -69,4 +70,12 @@ data class LoadFlowServiceSecurityAnalysisResult(
@Serializable(with = SecurityAnalysisResultSerializer::class)
val securityAnalysisResult: SecurityAnalysisResult,
val report: String
) : ComputationResult()
) : ComputationResult()


@Serializable
data class LoadFlowServiceSensitivityAnalysisResult(
@Serializable(with = SensitivityAnalysisResultSerializer::class)
val sensitivityAnalysisResult: SensitivityAnalysisResult,
val report: String
): ComputationResult()
16 changes: 9 additions & 7 deletions src/main/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,15 @@ fun Application.module() {

sensParamCnt.parameters.setLoadFlowParameters(loadParamCnt.parameters)
val network = networkFromFirstFile(files)
val result = runSensitivityAnalysis(
network,
sensFactorCnt.factors,
sensParamCnt.parameters,
contingencyCnt.contingencies
)
call.respondText(result, ContentType.Application.Json, HttpStatusCode.OK)
val result = createTask(taskManager) {
runSensitivityAnalysis(
network,
sensFactorCnt.factors,
sensParamCnt.parameters,
contingencyCnt.contingencies
)
}
call.respond(result)
}

post("/security-analysis") {
Expand Down
22 changes: 22 additions & 0 deletions src/main/JavaSerializers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package com.github.statnett.loadflowservice
import com.fasterxml.jackson.databind.ObjectMapper
import com.powsybl.security.SecurityAnalysisResult
import com.powsybl.security.json.SecurityAnalysisJsonModule
import com.powsybl.sensitivity.SensitivityAnalysisResult
import com.powsybl.sensitivity.json.SensitivityJsonModule
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
Expand All @@ -29,4 +31,24 @@ object SecurityAnalysisResultSerializer : KSerializer<SecurityAnalysisResult> {
val string = decoder.decodeString()
return mapper.readValue(string, SecurityAnalysisResult::class.java)
}
}

object SensitivityAnalysisResultSerializer: KSerializer<SensitivityAnalysisResult> {
private val mapper = ObjectMapper()

init {
mapper.registerModule(SensitivityJsonModule())
}

override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("sensitivity-analysis-result", PrimitiveKind.STRING)

override fun serialize(encoder: Encoder, value: SensitivityAnalysisResult) {
val string = mapper.writeValueAsString(value)
encoder.encodeString(string)
}

override fun deserialize(decoder: Decoder): SensitivityAnalysisResult {
val string = decoder.decodeString()
return mapper.readValue(string, SensitivityAnalysisResult::class.java)
}
}
29 changes: 9 additions & 20 deletions src/main/Solver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.powsybl.security.monitor.StateMonitor
import com.powsybl.security.strategy.OperatorStrategy
import com.powsybl.sensitivity.*
import io.github.oshai.kotlinlogging.KotlinLogging
import kotlinx.serialization.Serializable
import java.io.ByteArrayOutputStream
import java.io.StringWriter

Expand Down Expand Up @@ -112,44 +113,32 @@ fun solve(
)
}


fun runSensitivityAnalysis(
network: Network,
factors: List<SensitivityFactor>,
params: SensitivityAnalysisParameters,
contingenciesList: ContingencyList
): String {
): LoadFlowServiceSensitivityAnalysisResult {
val reporter = ReporterModel("sensitivity", "")
val variableSets: List<SensitivityVariableSet> = listOf()
val contingencies = contingenciesList.getContingencies(network)
val factorReader = SensitivityFactorModelReader(factors, network)

val factory = JsonUtil.createJsonFactory()
val writer = StringWriter()
val jsonGenerator = factory.createGenerator(writer)
jsonGenerator.writeStartObject()
jsonGenerator.writeFieldName("sensitivity-results")
val resultWriter = SensitivityResultJsonWriter(jsonGenerator, contingencies)

SensitivityAnalysis.run(

val result = SensitivityAnalysis.run(
network,
network.variantManager.workingVariantId,
factorReader,
resultWriter,
factors,
contingencies,
variableSets,
params,
LocalComputationManager.getDefault(),
reporter
)
// Close the nested array created by Powsybl
jsonGenerator.writeEndArray()
jsonGenerator.writeEndArray()

// Add run report to the JSON
jsonGenerator.writeStringField("report", reporterToString(reporter))
jsonGenerator.writeEndObject()
jsonGenerator.close()
return writer.toString()
return LoadFlowServiceSensitivityAnalysisResult(
result, reporterToString(reporter)
)
}

fun runSecurityAnalysis(
Expand Down
15 changes: 10 additions & 5 deletions src/test/AppTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -310,16 +310,21 @@ class ApplicationTest {
formData = sensitivityFormData.formData(config)
)
assertEquals(HttpStatusCode.OK, response.status)
val body = response.bodyAsText()

val taskInfo = Json.decodeFromString<TaskInfo>(response.body())

val runResult = retryOnError(50, 10) {
client.get(taskInfo.resultUrl)
}
assertEquals(HttpStatusCode.OK, runResult.status)

val result = json.decodeFromString<LoadFlowServiceSensitivityAnalysisResult>(runResult.body())

// There are two contingencies so when we have contingencies there should be three results
// Otherwise one
val numRes = if (config.withContingencies) 3 else 1

val regex = Regex(""""sensitivity-results":\[\[(.*)]]""")
val match = regex.find(body)!!
val content = match.groupValues[1]
assertEquals(numRes, content.count { c -> c == '{' })
assertEquals(numRes, result.sensitivityAnalysisResult.values.size)
}
}
}
Expand Down
Loading