All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.powsybl.loadflow.json.LoadFlowResultDeserializer Maven / Gradle / Ivy

There is a newer version: 6.5.1
Show newest version
/**
 * Copyright (c) 2017, RTE (http://www.rte-france.com)
 * Copyright (c) 2023, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 * SPDX-License-Identifier: MPL-2.0
 */
package com.powsybl.loadflow.json;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.powsybl.commons.json.JsonUtil;
import com.powsybl.loadflow.LoadFlowResult;
import com.powsybl.loadflow.LoadFlowResultImpl;

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;

/**
 * @author Christian Biasuzzi {@literal }
 * @author Damien Jeandemange {@literal }
 */
public class LoadFlowResultDeserializer extends StdDeserializer {

    private static final String CONTEXT_NAME = "LoadFlowResult";
    public static final String UNEXPECTED_FIELD = "Unexpected field: ";

    LoadFlowResultDeserializer() {
        super(LoadFlowResult.class);
    }

    public LoadFlowResult.ComponentResult deserializeComponentResult(JsonParser parser, String version) throws IOException {
        Integer connectedComponentNum = null;
        Integer synchronousComponentNum = null;
        LoadFlowResult.ComponentResult.Status status = null;
        String statusText = null;
        Map metrics = Collections.emptyMap();
        Integer iterationCount = null;
        List slackBusResults = new ArrayList<>();
        String referenceBusId = null;
        String slackBusId = null;
        Double slackBusActivePowerMismatch = null;
        Double distributedActivePower = null;

        while (parser.nextToken() != JsonToken.END_OBJECT) {
            switch (parser.currentName()) {
                case "connectedComponentNum" -> {
                    JsonUtil.assertGreaterOrEqualThanReferenceVersion(LoadFlowResultDeserializer.class.getName(), parser.currentName(), version, "1.2");
                    parser.nextToken();
                    connectedComponentNum = parser.getValueAsInt();
                }
                case "synchronousComponentNum" -> {
                    JsonUtil.assertGreaterOrEqualThanReferenceVersion(LoadFlowResultDeserializer.class.getName(), parser.currentName(), version, "1.2");
                    parser.nextToken();
                    synchronousComponentNum = parser.getValueAsInt();
                }
                case "componentNum" -> {
                    JsonUtil.assertLessThanReferenceVersion(LoadFlowResultDeserializer.class.getName(), parser.currentName(), version, "1.2");
                    parser.nextToken();
                    synchronousComponentNum = parser.getValueAsInt();
                }
                case "status" -> {
                    parser.nextToken();
                    String tempStatus = parser.getValueAsString();
                    if (version.compareTo("1.4") < 0 && "SOLVER_FAILED".equals(tempStatus)) {
                        // SOLVER_FAILED removed in v1.4, translated to FAILED, information kept in statusText which didn't exist before v1.4
                        statusText = tempStatus;
                        tempStatus = LoadFlowResult.ComponentResult.Status.FAILED.name();
                    }
                    status = LoadFlowResult.ComponentResult.Status.valueOf(tempStatus);
                }
                case "statusText" -> {
                    JsonUtil.assertGreaterOrEqualThanReferenceVersion(CONTEXT_NAME, "Tag: statusText", version, "1.4");
                    parser.nextToken();
                    statusText = parser.getValueAsString();
                }
                case "metrics" -> {
                    JsonUtil.assertGreaterOrEqualThanReferenceVersion(CONTEXT_NAME, "Tag: metrics", version, "1.4");
                    parser.nextToken();
                    metrics = parser.readValueAs(HashMap.class);
                }
                case "iterationCount" -> {
                    parser.nextToken();
                    iterationCount = parser.getValueAsInt();
                }
                case "referenceBusId" -> {
                    JsonUtil.assertGreaterOrEqualThanReferenceVersion(CONTEXT_NAME, "Tag: referenceBusId", version, "1.4");
                    parser.nextToken();
                    referenceBusId = parser.getValueAsString();
                }
                case "slackBusResults" -> {
                    JsonUtil.assertGreaterOrEqualThanReferenceVersion(CONTEXT_NAME, "Tag: slackBusResults", version, "1.4");
                    parser.nextToken();
                    deserializeSlackBusResults(parser, slackBusResults);
                }
                case "slackBusId" -> {
                    JsonUtil.assertLessThanReferenceVersion(LoadFlowResultDeserializer.class.getName(), parser.currentName(), version, "1.4");
                    parser.nextToken();
                    slackBusId = parser.getValueAsString();
                }
                case "slackBusActivePowerMismatch" -> {
                    JsonUtil.assertLessThanReferenceVersion(LoadFlowResultDeserializer.class.getName(), parser.currentName(), version, "1.4");
                    parser.nextToken();
                    slackBusActivePowerMismatch = parser.getValueAsDouble();
                }
                case "distributedActivePower" -> {
                    JsonUtil.assertGreaterOrEqualThanReferenceVersion(LoadFlowResultDeserializer.class.getName(), parser.currentName(), version, "1.3");
                    parser.nextToken();
                    distributedActivePower = parser.getValueAsDouble();
                }
                default -> throw new IllegalStateException(UNEXPECTED_FIELD + parser.currentName());
            }
        }

        if (connectedComponentNum == null) {
            if (version.compareTo("1.2") < 0) {
                connectedComponentNum = 0;
            } else {
                throw new IllegalStateException("Connected component number field not found.");
            }
        }

        if (synchronousComponentNum == null) {
            throw new IllegalStateException("Synchronous component number field not found.");
        }
        if (iterationCount == null) {
            throw new IllegalStateException("Iteration count field not found.");
        }
        if (distributedActivePower == null) {
            if (version.compareTo("1.3") < 0) {
                distributedActivePower = Double.NaN;
            } else {
                throw new IllegalStateException("Distributed active power field not found.");
            }
        }
        if (version.compareTo("1.4") < 0) {
            if (slackBusId == null) {
                throw new IllegalStateException("Slack bus id field not found.");
            }
            if (slackBusActivePowerMismatch == null) {
                throw new IllegalStateException("Slack bus active power mismatch field not found.");
            }
            referenceBusId = slackBusId;
            slackBusResults = List.of(new LoadFlowResultImpl.SlackBusResultImpl(slackBusId, slackBusActivePowerMismatch));
        }

        return new LoadFlowResultImpl.ComponentResultImpl(
            connectedComponentNum, synchronousComponentNum,
            status, statusText, metrics, iterationCount,
            referenceBusId, slackBusResults, distributedActivePower
        );
    }

    public LoadFlowResult.SlackBusResult deserializeSlackBusResult(JsonParser parser) throws IOException {
        String id = null;
        Double activePowerMismatch = null;

        while (parser.nextToken() != JsonToken.END_OBJECT) {
            switch (parser.currentName()) {
                case "id" -> {
                    parser.nextToken();
                    id = parser.getValueAsString();
                }
                case "activePowerMismatch" -> {
                    parser.nextToken();
                    activePowerMismatch = parser.getValueAsDouble();
                }
                default -> throw new IllegalStateException(UNEXPECTED_FIELD + parser.currentName());
            }
        }

        if (id == null) {
            throw new IllegalStateException("Slack bus result: id field not found.");
        }
        if (activePowerMismatch == null) {
            throw new IllegalStateException("Slack bus result: active power mismatch field not found.");
        }

        return new LoadFlowResultImpl.SlackBusResultImpl(id, activePowerMismatch);
    }

    public void deserializeComponentResults(JsonParser parser, List componentResults, String version) throws IOException {
        while (parser.nextToken() != JsonToken.END_ARRAY) {
            componentResults.add(deserializeComponentResult(parser, version));
        }
    }

    public void deserializeSlackBusResults(JsonParser parser, List slackBusResults) throws IOException {
        while (parser.nextToken() != JsonToken.END_ARRAY) {
            slackBusResults.add(deserializeSlackBusResult(parser));
        }
    }

    @Override
    public LoadFlowResult deserialize(JsonParser parser, DeserializationContext ctx) throws IOException {
        String version = null;
        Boolean ok = null;
        Map metrics = null;
        String log = null;
        List componentResults = new ArrayList<>();

        while (parser.nextToken() != JsonToken.END_OBJECT) {
            switch (parser.currentName()) {
                case "version" -> {
                    parser.nextToken();
                    version = parser.getValueAsString();
                }
                case "isOK" -> {
                    parser.nextToken();
                    ok = parser.readValueAs(Boolean.class);
                }
                case "metrics" -> {
                    parser.nextToken();
                    metrics = parser.readValueAs(HashMap.class);
                }
                case "componentResults" -> {
                    JsonUtil.assertGreaterThanReferenceVersion(CONTEXT_NAME, "Tag: componentResults", version, "1.0");
                    parser.nextToken();
                    deserializeComponentResults(parser, componentResults, version);
                }
                default -> throw new IllegalStateException(UNEXPECTED_FIELD + parser.currentName());
            }
        }

        if (ok == null) {
            throw new IllegalStateException("Ok field not found");
        }

        return new LoadFlowResultImpl(ok, metrics, log, componentResults);
    }

    public static LoadFlowResult read(InputStream is) throws IOException {
        Objects.requireNonNull(is);
        ObjectMapper objectMapper = JsonUtil.createObjectMapper();
        objectMapper.registerModule(new LoadFlowResultJsonModule());
        return objectMapper.readValue(is, LoadFlowResult.class);
    }

    public static LoadFlowResult read(Path jsonFile) {
        Objects.requireNonNull(jsonFile);
        try (InputStream is = Files.newInputStream(jsonFile)) {
            return read(is);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy