gov.pnnl.goss.gridappsd.configuration.GLDSimulationOutputConfigurationHandler.java Source code

Java tutorial

Introduction

Here is the source code for gov.pnnl.goss.gridappsd.configuration.GLDSimulationOutputConfigurationHandler.java

Source

/*******************************************************************************
 * Copyright  2017, Battelle Memorial Institute All rights reserved.
 * Battelle Memorial Institute (hereinafter Battelle) hereby grants permission to any person or entity 
 * lawfully obtaining a copy of this software and associated documentation files (hereinafter the 
 * Software) to redistribute and use the Software in source and binary forms, with or without modification. 
 * Such person or entity may use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 
 * the Software, and may permit others to do so, subject to the following conditions:
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the 
 * following disclaimers.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
 * the following disclaimer in the documentation and/or other materials provided with the distribution.
 * Other than as used herein, neither the name Battelle Memorial Institute or Battelle may be used in any 
 * form whatsoever without the express written consent of Battelle.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
 * BATTELLE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * General disclaimer for use with OSS licenses
 * 
 * This material was prepared as an account of work sponsored by an agency of the United States Government. 
 * Neither the United States Government nor the United States Department of Energy, nor Battelle, nor any 
 * of their employees, nor any jurisdiction or organization that has cooperated in the development of these 
 * materials, makes any warranty, express or implied, or assumes any legal liability or responsibility for 
 * the accuracy, completeness, or usefulness or any information, apparatus, product, software, or process 
 * disclosed, or represents that its use would not infringe privately owned rights.
 * 
 * Reference herein to any specific commercial product, process, or service by trade name, trademark, manufacturer, 
 * or otherwise does not necessarily constitute or imply its endorsement, recommendation, or favoring by the United 
 * States Government or any agency thereof, or Battelle Memorial Institute. The views and opinions of authors expressed 
 * herein do not necessarily state or reflect those of the United States Government or any agency thereof.
 * 
 * PACIFIC NORTHWEST NATIONAL LABORATORY operated by BATTELLE for the 
 * UNITED STATES DEPARTMENT OF ENERGY under Contract DE-AC05-76RL01830
 ******************************************************************************/
package gov.pnnl.goss.gridappsd.configuration;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import org.apache.felix.dm.annotation.api.Component;
import org.apache.felix.dm.annotation.api.ServiceDependency;
import org.apache.felix.dm.annotation.api.Start;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;

import gov.pnnl.goss.cim2glm.CIMImporter;
import gov.pnnl.goss.cim2glm.queryhandler.QueryHandler;
import gov.pnnl.goss.gridappsd.api.ConfigurationHandler;
import gov.pnnl.goss.gridappsd.api.ConfigurationManager;
import gov.pnnl.goss.gridappsd.api.LogManager;
import gov.pnnl.goss.gridappsd.api.PowergridModelDataManager;
import gov.pnnl.goss.gridappsd.api.SimulationManager;
import gov.pnnl.goss.gridappsd.data.handlers.BlazegraphQueryHandler;
import gov.pnnl.goss.gridappsd.dto.SimulationContext;
import gov.pnnl.goss.gridappsd.dto.LogMessage.LogLevel;
import gov.pnnl.goss.gridappsd.utils.GridAppsDConstants;
import pnnl.goss.core.Client;

@Component
public class GLDSimulationOutputConfigurationHandler extends BaseConfigurationHandler
        implements ConfigurationHandler {//implements ConfigurationManager{

    private static Logger log = LoggerFactory.getLogger(GLDSimulationOutputConfigurationHandler.class);
    Client client = null;

    @ServiceDependency
    private volatile ConfigurationManager configManager;
    @ServiceDependency
    private volatile SimulationManager simulationManager;
    @ServiceDependency
    private volatile PowergridModelDataManager powergridModelManager;
    @ServiceDependency
    volatile LogManager logManager;

    public static final String TYPENAME = "GridLAB-D Simulation Output";
    public static final String MODELID = "model_id";
    public static final String DICTIONARY_FILE = "dictionary_file";
    public static final String SIMULATIONID = "simulation_id";

    public GLDSimulationOutputConfigurationHandler() {
    }

    public GLDSimulationOutputConfigurationHandler(ConfigurationManager configManager,
            PowergridModelDataManager powergridModelManager, LogManager logManager) {
        this.configManager = configManager;
        this.powergridModelManager = powergridModelManager;
        this.logManager = logManager;
    }

    @Start
    public void start() {
        if (configManager != null) {
            configManager.registerConfigurationHandler(TYPENAME, this);
        } else {
            //TODO send log message and exception
            log.warn("No Config manager avilable for " + getClass());
        }

        if (powergridModelManager == null) {
            //TODO send log message and exception
        }
    }

    @Override
    public void generateConfig(Properties parameters, PrintWriter out, String processId, String username)
            throws Exception {
        logRunning("Generating simulation output configuration file using parameters: " + parameters, processId,
                username, logManager);
        File dictFile = null;
        String simulationId = GridAppsDConstants.getStringProperty(parameters, SIMULATIONID, null);
        File configFile = null;
        if (simulationId != null) {
            SimulationContext simulationContext = simulationManager.getSimulationContextForId(simulationId);
            if (simulationContext != null) {
                configFile = new File(simulationContext.getSimulationDir() + File.separator
                        + GLDAllConfigurationHandler.MEASUREMENTOUTPUTS_FILENAME);
                dictFile = new File(simulationContext.getSimulationDir() + File.separator
                        + GLDAllConfigurationHandler.DICTIONARY_FILENAME);
                //If the config file already has been created for this simulation then return it
                if (configFile.exists()) {
                    printFileToOutput(configFile, out);
                    logRunning("Dictionary GridLAB-D simulation outputs file for simulation " + simulationId
                            + " already exists.", processId, username, logManager);
                    return;
                }
            } else {
                logRunning("No simulation context found for simulation_id: " + simulationId, processId, username,
                        logManager, LogLevel.WARN);
            }
        }

        String modelId = GridAppsDConstants.getStringProperty(parameters, MODELID, null);
        if (modelId == null || modelId.trim().length() == 0) {
            logError("No " + MODELID + " parameter provided", processId, username, logManager);
            throw new Exception("Missing parameter " + MODELID);
        }

        //If passed in, use location of dictionary file, otherwise it will attempt to generate it
        String dictFilePath = GridAppsDConstants.getStringProperty(parameters, DICTIONARY_FILE, null);
        if (dictFilePath != null) {
            dictFile = new File(dictFilePath);
        }

        String bgHost = configManager.getConfigurationProperty(GridAppsDConstants.BLAZEGRAPH_HOST_PATH);
        if (bgHost == null || bgHost.trim().length() == 0) {
            bgHost = BlazegraphQueryHandler.DEFAULT_ENDPOINT;
        }

        Reader measurementFileReader;

        if (dictFile != null && dictFile.getName().length() > 0 && dictFile.exists()) {
            measurementFileReader = new FileReader(dictFile);
        } else {
            //TODO write a query handler that uses the built in powergrid model data manager that talks to blazegraph internally
            QueryHandler queryHandler = new BlazegraphQueryHandler(bgHost, logManager, processId, username);
            queryHandler.addFeederSelection(modelId);
            CIMImporter cimImporter = new CIMImporter();
            StringWriter dictionaryStringOutput = new StringWriter();
            PrintWriter dictionaryOutput = new PrintWriter(dictionaryStringOutput);

            cimImporter.generateDictionaryFile(queryHandler, dictionaryOutput);
            String dictOut = dictionaryStringOutput.toString();
            measurementFileReader = null;
            if (dictFile != null && dictFile.getName().length() > 0 && !dictFile.exists()) {
                FileWriter fw = new FileWriter(dictFile);
                fw.write(dictOut);
                fw.close();
            }
            measurementFileReader = new StringReader(dictOut);
        }

        String result = CreateGldPubs(measurementFileReader, processId, username);

        if (configFile != null) {
            FileWriter fw = new FileWriter(configFile);
            fw.write(result);
            fw.close();
        }
        //return result;
        out.write(result);
        out.flush();

        logRunning("Finished generating simulation output configuration file.", processId, username, logManager);

    }

    String CreateGldPubs(Reader measurementFileReader, String processId, String username)
            throws FileNotFoundException {
        String jsonObjStr = "";
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        JsonObject gldConfigObj = new JsonObject();
        //      JsonObject gldPublications = new JsonObject();

        try {
            JsonObject jsonObj = gson.fromJson(measurementFileReader, JsonObject.class);
            JsonArray feeders = (JsonArray) jsonObj.get("feeders");
            Iterator<JsonElement> iter = feeders.iterator();
            while (iter.hasNext()) {
                JsonObject feederInfo = (JsonObject) iter.next();
                JsonArray feederMeasurements = (JsonArray) feederInfo.get("measurements");
                Iterator<JsonElement> feederMeasurementsIter = feederMeasurements.iterator();
                Map<String, JsonArray> measurements = new HashMap<String, JsonArray>();
                while (feederMeasurementsIter.hasNext()) {
                    JsonObject feederMeasurement = (JsonObject) feederMeasurementsIter.next();
                    parseMeasurement(measurements, feederMeasurement);
                }
                for (Map.Entry<String, JsonArray> entry : measurements.entrySet()) {
                    gldConfigObj.add(entry.getKey(), entry.getValue());
                }
                measurements.clear();
            }
            //         gldConfigObj.add("publications", gldPublications);
            jsonObjStr = gson.toJson(gldConfigObj);

        } catch (JsonIOException e) {
            logError("Error while generating simulation output: " + e.getMessage(), processId, username,
                    logManager);
            throw e;
        } catch (JsonParseException e) {
            logError("Error while generating simulation output: " + e.getMessage(), processId, username,
                    logManager);
            throw e;
        }
        return jsonObjStr;
    }

    void parseMeasurement(Map<String, JsonArray> measurements, JsonObject measurement) throws JsonParseException {
        String objectName;
        String propertyName;
        String measurementType;
        String phases;
        String conductingEquipmentType;
        String conductingEquipmentName;
        String connectivityNode;
        if (!measurement.has("measurementType") || !measurement.has("phases")
                || !measurement.has("ConductingEquipment_type") || !measurement.has("ConductingEquipment_name")
                || !measurement.has("ConnectivityNode")) {
            throw new JsonParseException(
                    "CimMeasurementsToGldPubs::parseMeasurement: The JsonObject measurements must have the following keys: measurementType, phases, ConductingEquipment_type,ConductingEquipment_name, and ConnectivityNode.");
        }
        measurementType = measurement.get("measurementType").getAsString();
        phases = measurement.get("phases").getAsString();
        if (phases.equals("s1")) {
            phases = "1";
        } else if (phases.equals("s2")) {
            phases = "2";
        }
        conductingEquipmentType = measurement.get("name").getAsString();
        conductingEquipmentName = measurement.get("ConductingEquipment_name").getAsString();
        connectivityNode = measurement.get("ConnectivityNode").getAsString();
        if (conductingEquipmentType.contains("LinearShuntCompensator")) {
            if (measurementType.equals("VA")) {
                objectName = "cap_" + conductingEquipmentName;
                propertyName = "shunt_" + phases;
            } else if (measurementType.equals("Pos")) {
                objectName = "cap_" + conductingEquipmentName;
                propertyName = "switch" + phases;
            } else if (measurementType.equals("PNV")) {
                objectName = "cap_" + conductingEquipmentName;
                propertyName = "voltage_" + phases;
            } else {
                throw new JsonParseException(String.format(
                        "CimMeasurementsToGldPubs::parseMeasurement: The value of measurementType is not a valid type.\nValid types for LinearShuntCompensators are VA, Pos, and PNV.\nmeasurementType = %s.",
                        measurementType));
            }
        } else if (conductingEquipmentType.contains("PowerTransformer")) {
            if (measurementType.equals("VA")) {
                objectName = "xf_" + conductingEquipmentName;
                propertyName = "power_in_" + phases;
            } else if (measurementType.equals("PNV")) {
                objectName = connectivityNode;
                propertyName = "voltage_" + phases;
            } else if (measurementType.equals("A")) {
                objectName = "xf_" + conductingEquipmentName;
                propertyName = "current_in_" + phases;
            } else {
                throw new JsonParseException(String.format(
                        "CimMeasurementsToGldPubs::parseMeasurement: The value of measurementType is not a valid type.\nValid types for PowerTransformers are VA, PNV, and A.\nmeasurementType = %s.",
                        measurementType));
            }
        } else if (conductingEquipmentType.contains("RatioTapChanger")) {
            if (measurementType.equals("VA")) {
                objectName = "reg_" + conductingEquipmentName;
                propertyName = "power_in_" + phases;
            } else if (measurementType.equals("PNV")) {
                objectName = connectivityNode;
                propertyName = "voltage_" + phases;
            } else if (measurementType.equals("A")) {
                objectName = "reg_" + conductingEquipmentName;
                propertyName = "current_in_" + phases;
            } else if (measurementType.equals("Pos")) {
                objectName = "reg_" + conductingEquipmentName;
                propertyName = "tap_" + phases;
            } else if (measurementType.equals("PNV")) {
                objectName = connectivityNode;
                propertyName = "voltage_" + phases;
            } else if (measurementType.equals("A")) {
                objectName = "tx_" + conductingEquipmentName;
                propertyName = "current_out_" + phases;
            } else {
                throw new JsonParseException(String.format(
                        "CimMeasurementsToGldPubs::parseMeasurement: The value of measurementType is not a valid type.\nValid types for RatioTapChanger are VA, PNV, A, and Pos.\nmeasurementType = %s.",
                        measurementType));
            }
        } else if (conductingEquipmentType.contains("ACLineSegment")) {
            String prefix = "";
            if (phases.equals("1") || phases.equals("2")) {
                prefix = "tpx_";
            } else {
                prefix = "line_";
            }
            if (measurementType.equals("VA")) {
                objectName = prefix + conductingEquipmentName;
                propertyName = "power_in_" + phases;
            } else if (measurementType.equals("PNV")) {
                objectName = connectivityNode;
                propertyName = "voltage_" + phases;
            } else if (measurementType.equals("A")) {
                objectName = prefix + conductingEquipmentName;
                propertyName = "current_in_" + phases;
            } else {
                throw new JsonParseException(String.format(
                        "CimMeasurementsToGldPubs::parseMeasurement: The value of measurementType is not a valid type.\nValid types for ACLineSegments are VA, A, and PNV.\nmeasurementType = %s.",
                        measurementType));
            }
        } else if (conductingEquipmentType.contains("LoadBreakSwitch")) {
            if (measurementType.equals("VA")) {
                objectName = "swt_" + conductingEquipmentName;
                propertyName = "power_in_" + phases;
            } else if (measurementType.equals("PNV")) {
                objectName = connectivityNode;
                propertyName = "voltage_" + phases;
            } else if (measurementType.equals("A")) {
                objectName = "swt_" + conductingEquipmentName;
                propertyName = "current_in_" + phases;
            } else {
                throw new JsonParseException(String.format(
                        "CimMeasurementsToGldPubs::parseMeasurement: The value of measurementType is not a valid type.\nValid types for LoadBreakSwitch are VA, A, and PNV.\nmeasurementType = %s.",
                        measurementType));
            }
        } else if (conductingEquipmentType.contains("EnergyConsumer")) {
            if (measurementType.equals("VA")) {
                objectName = connectivityNode;
                propertyName = "measured_power_" + phases;
            } else if (measurementType.equals("PNV")) {
                objectName = connectivityNode;
                propertyName = "voltage_" + phases;
            } else if (measurementType.equals("A")) {
                objectName = connectivityNode;
                propertyName = "measured_current_" + phases;
            } else {
                throw new JsonParseException(String.format(
                        "CimMeasurementsToGldPubs::parseMeasurement: The value of measurementType is not a valid type.\nValid types for EnergyConsumer are VA, A, and PNV.\nmeasurementType = %s.",
                        measurementType));
            }
        } else if (conductingEquipmentType.contains("PowerElectronicsConnection")) {
            if (measurementType.equals("VA")) {
                objectName = connectivityNode;
                propertyName = "measured_power_" + phases;
            } else if (measurementType.equals("PNV")) {
                objectName = connectivityNode;
                propertyName = "voltage_" + phases;
            } else if (measurementType.equals("A")) {
                objectName = connectivityNode;
                propertyName = "measured_current_" + phases;
            } else {
                throw new JsonParseException(String.format(
                        "CimMeasurementsToGldPubs::parseMeasurement: The value of measurementType is not a valid type.\nValid types for PowerElectronicsConnection are VA, A, and PNV.\nmeasurementType = %s.",
                        measurementType));
            }
        } else {
            throw new JsonParseException(String.format(
                    "CimMeasurementsToGldPubs::parseMeasurement: The value of ConductingEquipment_type is not a recognized object type.\nValid types are ACLineSegment, LinearShuntCompesator, RatioTapChanger, LoadBreakSwitch, EnergyConsumer, PowerElectronicsConnection, and PowerTransformer.\nConductingEquipment_type = %s.",
                    conductingEquipmentType));

        }
        if (measurements.containsKey(objectName)) {
            measurements.get(objectName).add(new JsonPrimitive(propertyName));
        } else {
            JsonArray newMeasurements = new JsonArray();
            newMeasurements.add(new JsonPrimitive(propertyName));
            measurements.put(objectName, newMeasurements);
        }
    }
}