Skip to content

Commit

Permalink
CGMES export: output max number values as float, not double (#3044)
Browse files Browse the repository at this point in the history
* CGMES export: output max number values as float, not double
* Any value greater than Float.MAX_VALUE will be written as Float.MAX_VALUE

Signed-off-by: Luma <[email protected]>
(cherry picked from commit e6d3f33)
  • Loading branch information
zamarrenolm authored and olperr1 committed Jun 11, 2024
1 parent 470e341 commit 41bb687
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@ public static String format(double value) {

public static String format(double value, double defaultValue) {
// Always use scientific format for extreme values
if (value == Double.MAX_VALUE || value == -Double.MAX_VALUE) {
return scientificFormat(value, defaultValue);
if (value >= Float.MAX_VALUE || value <= -Float.MAX_VALUE) {
// CIMXML expects xsd:float values
float value1 = value >= Float.MAX_VALUE ? Float.MAX_VALUE : -Float.MAX_VALUE;
return scientificFormat(value1, defaultValue);
}
return DOUBLE_FORMAT.format(fixValue(value, defaultValue));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.powsybl.cgmes.conversion.test.export.issues;

import com.powsybl.cgmes.conversion.CgmesExport;
import com.powsybl.commons.test.AbstractSerDeTest;
import com.powsybl.iidm.network.*;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.nio.file.Files;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.junit.jupiter.api.Assertions.*;

class ExportNumberMaxValueTest extends AbstractSerDeTest {
@Test
void testTemporaryLimitWithoutValue() throws IOException {
// XIIDM may not define a value for a temporary limit,
// In that case it is assumed its value is Double.MAX_VALUE

// CIMXML uses xsd:float for floating point numbers,
// xsd:float is an IEEE single-precision 32-bit floating point type
// CGMES export writes Double.MAX_VALUEs as Float.MAX_VALUE

Network network = Network.create("temporary-limit-without-value", "manual");
network.newSubstation().setId("S0").add()
.newVoltageLevel().setId("VL0").setNominalV(100).setTopologyKind(TopologyKind.BUS_BREAKER).add()
.getBusBreakerView().newBus().setId("B0").add();
network.newSubstation().setId("S1").add()
.newVoltageLevel().setId("VL1").setNominalV(100).setTopologyKind(TopologyKind.BUS_BREAKER).add()
.getBusBreakerView().newBus().setId("B1").add();
Line line = network.newLine().setId("L01").setR(1.0).setX(10.0)
.setBus1("B0").setBus2("B1").add();
line.newCurrentLimits1()
.setPermanentLimit(2000)
.beginTemporaryLimit()
.setName("L300").setAcceptableDuration(300).setValue(3000)
.endTemporaryLimit()
.beginTemporaryLimit()
.setName("L120").setAcceptableDuration(120).setValue(6000)
.endTemporaryLimit()
.beginTemporaryLimit()
.setName("L0").setAcceptableDuration(60).setValue(Double.MAX_VALUE)
.endTemporaryLimit()
.add();

// Check that the value of the temporary limit for duration 60 has been kept as max value
assertEquals(Double.MAX_VALUE, line.getCurrentLimits1().orElseThrow().getTemporaryLimit(60).getValue());

// Export only EQ to CGMES and read the exported file
Properties exportParams = new Properties();
exportParams.put(CgmesExport.PROFILES, "EQ");
String basename = "net";
network.write("CGMES", exportParams, tmpDir.resolve(basename));
String eq = Files.readString(tmpDir.resolve(String.format("%s_EQ.xml", basename)));

// Look for the value of the temporary limit with acceptable duration 60
// We know exactly which identifier to look for
// Include multiple lines and non-greedy matches
Pattern tatl60Pattern = Pattern.compile("<cim:CurrentLimit rdf:ID=\"_L01_ACLS_T_1_CurrentLimit_OLV_TATL_60\">.*?<cim:CurrentLimit.value>(.*?)</cim:CurrentLimit.value>", Pattern.DOTALL);
Matcher tatl60Value = tatl60Pattern.matcher(eq);
assertTrue(tatl60Value.find());
// Read the value as a double
double value = Double.parseDouble(tatl60Value.group(1));

// Check that we have read a very big number,
// we can not compare exactly with Float.MAX_VALUE because it has not been written with enough precision
assertTrue(value > Float.MAX_VALUE / 10);
// And check that we have not written Double.MAX_VALUE
assertTrue(value < Double.MAX_VALUE / 10);
}
}

0 comments on commit 41bb687

Please sign in to comment.