diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..1a1bdfd74 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,124 @@ +on: + push: + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 8 + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'adopt' + - name: Build with Gradle + run: ./gradlew export + +# - uses: actions/upload-artifact@v2 +# with: +# name: gridappsd-artifact +# path: gov.pnnl.goss.gridappsd/generated/distributions/executable/run.bnd.jar +# +# push: +# runs-on: ubuntu-latest +# name: Build and push the docker container +# needs: build +# steps: +# - uses: actions/checkout@v2 +# +# - uses: actions/download-artifact@v2 +# with: +# name: gridappsd-artifact + + - name: Checking environment + env: + DOCKER_IMAGE_NAME: ${{ secrets.DOCKER_IMAGE_NAME }} + run: | + if [ "x${{ env.DOCKER_IMAGE_NAME }}" == "x" ]; then + echo "Error: missing DOCKER_IMAGE_NAME" + exit 1 + fi + + - name: Log in to docker + run: | + if [ -n "${{ secrets.DOCKER_USERNAME }}" -a -n "${{ secrets.DOCKER_TOKEN }}" ]; then + + echo " " + echo "Connecting to docker" + echo "${{ secrets.DOCKER_TOKEN }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin + status=$? + if [ $status -ne 0 ]; then + echo "Error: status $status" + exit 1 + fi + fi + + - name: Build the image + env: + DOCKER_IMAGE_NAME: ${{ secrets.DOCKER_IMAGE_NAME }} + if: env.DOCKER_IMAGE_NAME != null + run: | + TAG="${GITHUB_REF#refs/heads/}" + TAG="${TAG#refs/tags/}" + TAG="${TAG//\//_}" + ORG=`echo "${{ secrets.DOCKER_PROJECT }}" | tr '[:upper:]' '[:lower:]'` + ORG="${ORG:-gridappsd}" + ORG="${ORG:+${ORG}/}" + IMAGE="${ORG}${{ env.DOCKER_IMAGE_NAME }}" + TIMESTAMP=`date +'%y%m%d%H'` + GITHASH=`git log -1 --pretty=format:"%h"` + BUILD_VERSION="${TIMESTAMP}_${GITHASH}${BRANCH:+:$TAG}" + echo "BUILD_VERSION $BUILD_VERSION" + echo "TAG ${IMAGE}:${TIMESTAMP}_${GITHASH}" + docker build --build-arg VERSION="${TAG}" --build-arg TIMESTAMP="${BUILD_VERSION}" -t ${IMAGE}:${TIMESTAMP}_${GITHASH} . + status=$? + if [ $status -ne 0 ]; then + echo "Error: status $status" + exit 1 + fi + + - name: Push the image + env: + DOCKER_IMAGE_NAME: ${{ secrets.DOCKER_IMAGE_NAME }} + if: env.DOCKER_IMAGE_NAME != null + run: | + TAG="${GITHUB_REF#refs/heads/}" + TAG="${TAG#refs/tags/}" + TAG="${TAG//\//_}" + ORG=`echo "${{ secrets.DOCKER_PROJECT }}" | tr '[:upper:]' '[:lower:]'` + ORG="${ORG:-gridappsd}" + ORG="${ORG:+${ORG}/}" + IMAGE="${ORG}${{ env.DOCKER_IMAGE_NAME }}" + if [ -n "${{ secrets.DOCKER_USERNAME }}" -a -n "${{ secrets.DOCKER_TOKEN }}" ]; then + + if [ -n "$TAG" -a -n "$ORG" ]; then + # Get the built container name + CONTAINER=`docker images --format "{{.Repository}}:{{.Tag}}" ${IMAGE}` + + echo "docker push ${CONTAINER}" + docker push "${CONTAINER}" + status=$? + if [ $status -ne 0 ]; then + echo "Error: status $status" + exit 1 + fi + + echo "docker tag ${CONTAINER} ${IMAGE}:$TAG" + docker tag ${CONTAINER} ${IMAGE}:$TAG + status=$? + if [ $status -ne 0 ]; then + echo "Error: status $status" + exit 1 + fi + + echo "docker push ${IMAGE}:$TAG" + docker push ${IMAGE}:$TAG + status=$? + if [ $status -ne 0 ]; then + echo "Error: status $status" + exit 1 + fi + fi + + fi diff --git a/.travis.yml b/.travis.yml index acf02c94c..24ac35bf9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,8 +25,8 @@ services: # prepare the machine before any code # installation scripts before_install: - - './.travis/main.sh' +# - './.travis/main.sh' script: - - './gradlew export' - - './.travis/build-docker.sh' +# - './gradlew export' +# - './.travis/build-docker.sh' diff --git a/Dockerfile b/Dockerfile index f2ad234b0..56ffb3ebe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,11 @@ -ARG GRIDAPPSD_BASE_VERSION=:master +ARG GRIDAPPSD_BASE_VERSION=:develop FROM gridappsd/gridappsd_base${GRIDAPPSD_BASE_VERSION} ARG TIMESTAMP -# Get the gridappsd-python from the proper repository -RUN cd ${TEMP_DIR} \ - && git clone https://github.com/GRIDAPPSD/gridappsd-python -b develop \ - && cd gridappsd-python \ - && pip3 install -r requirements.txt \ - && pip3 install . \ - && rm -rf /root/.cache/pip/wheels - # Get the gridappsd-sensor-simulator from the proper repository -RUN cd ${TEMP_DIR} \ +RUN if [ ! -d ${TEMP_DIR} ]; then mkdir ${TEMP_DIR}; fi \ + && cd ${TEMP_DIR} \ && git clone https://github.com/GRIDAPPSD/gridappsd-sensor-simulator -b develop \ && cd gridappsd-sensor-simulator \ && pip3 install -r requirements.txt \ @@ -20,34 +13,82 @@ RUN cd ${TEMP_DIR} \ && rm .git -rf \ && cp -r * /gridappsd/services/gridappsd-sensor-simulator \ && cp /gridappsd/services/gridappsd-sensor-simulator/sensor_simulator.config /gridappsd/services/ \ - && rm -rf /root/.cache/pip/wheels + && rm -rf /root/.cache/pip/wheels \ + && cd \ + && rm -rf ${TEMP_DIR} # Get the gridappsd-voltage-violation from the proper repository -RUN cd ${TEMP_DIR} \ +RUN mkdir ${TEMP_DIR} \ + && cd ${TEMP_DIR} \ && git clone https://github.com/GRIDAPPSD/gridappsd-voltage-violation -b develop \ && cd gridappsd-voltage-violation \ && mkdir -p /gridappsd/services/gridappsd-voltage-violation \ && rm .git -rf \ && cp -r * /gridappsd/services/gridappsd-voltage-violation \ - && cp /gridappsd/services/gridappsd-voltage-violation/voltage-violation.config /gridappsd/services/ + && cp /gridappsd/services/gridappsd-voltage-violation/voltage-violation.config /gridappsd/services/ \ + && cd \ + && rm -rf ${TEMP_DIR} # Get the gridappsd-dnp3 from the proper repository -RUN cd ${TEMP_DIR} \ +RUN mkdir ${TEMP_DIR} \ + && cd ${TEMP_DIR} \ && git clone https://github.com/GRIDAPPSD/gridappsd-dnp3 -b develop \ && cd gridappsd-dnp3 \ && mkdir -p /gridappsd/services/gridappsd-dnp3 \ && rm .git -rf \ && cp -r dnp3/* /gridappsd/services/gridappsd-dnp3 \ - && cp /gridappsd/services/gridappsd-dnp3/dnp3.config /gridappsd/services/ + && cp /gridappsd/services/gridappsd-dnp3/dnp3.config /gridappsd/services/ \ + && cd \ + && rm -rf ${TEMP_DIR} # Get the gridappsd-alarms from the proper repository -RUN cd ${TEMP_DIR} \ +RUN mkdir ${TEMP_DIR} \ + && cd ${TEMP_DIR} \ && git clone https://github.com/GRIDAPPSD/gridappsd-alarms -b develop \ && cd gridappsd-alarms \ && mkdir -p /gridappsd/services/gridappsd-alarms \ && rm .git -rf \ && cp -r * /gridappsd/services/gridappsd-alarms \ - && cp /gridappsd/services/gridappsd-alarms/gridappsd-alarms.config /gridappsd/services/ + && cp /gridappsd/services/gridappsd-alarms/gridappsd-alarms.config /gridappsd/services/ \ + && cd \ + && rm -rf ${TEMP_DIR} + +# Get the topology-processor from the proper repository +RUN mkdir ${TEMP_DIR} \ + && cd ${TEMP_DIR} \ + && git clone https://github.com/GRIDAPPSD/topology-processor -b main gridappsd-topology-background-service\ + && cd gridappsd-topology-background-service/ \ + && mkdir -p /gridappsd/services/gridappsd-topology-background-service \ + && rm .git -rf \ + && cp -r * /gridappsd/services/gridappsd-topology-background-service \ + && cp /gridappsd/services/gridappsd-topology-background-service/topo_background.config /gridappsd/services/ \ + && cd \ + && rm -rf ${TEMP_DIR} + +# Get the gridappsd-toolbox from the proper repository +RUN mkdir ${TEMP_DIR} \ + && cd ${TEMP_DIR} \ + && git clone https://github.com/GRIDAPPSD/gridappsd-toolbox -b main \ + && cd gridappsd-toolbox \ + && mkdir -p /gridappsd/services/gridappsd-toolbox \ + && rm .git -rf \ + && cp -r * /gridappsd/services/gridappsd-toolbox \ + && cp /gridappsd/services/gridappsd-toolbox/static-ybus/gridappsd-static-ybus-service.config /gridappsd/services/ \ + && cp /gridappsd/services/gridappsd-toolbox/dynamic-ybus/gridappsd-dynamic-ybus-service.config /gridappsd/services/ \ + && cd \ + && rm -rf ${TEMP_DIR} + +# Get the gridapspd-distributed-ybus-service from the proper repository +RUN mkdir ${TEMP_DIR} \ + && cd ${TEMP_DIR} \ + && git clone https://github.com/GRIDAPPSD/gridappsd-distributed-static-ybus-service.git -b main \ + && cd gridappsd-distributed-static-ybus-service \ + && mkdir -p /gridappsd/services/gridappsd-distributed-static-ybus-service \ + && rm .git -rf \ + && cp -r * /gridappsd/services/gridappsd-distributed-static-ybus-service \ + && cp /gridappsd/services/gridappsd-distributed-static-ybus-service/gridappsd-distributed-static-ybus-service.config /gridappsd/services/ \ + && cd \ + && rm -rf ${TEMP_DIR} # Copy initial applications and services into the container. # @@ -81,7 +122,7 @@ RUN chmod +x /usr/local/bin/opendsscmd && \ # before executing this script. COPY ./gov.pnnl.goss.gridappsd/generated/distributions/executable/run.bnd.jar /gridappsd/lib/run.bnd.jar -RUN pip install -r /gridappsd/requirements.txt && \ +RUN pip install --pre -r /gridappsd/requirements.txt && \ pip install -r /gridappsd/services/fncsgossbridge/requirements.txt && \ rm -rf /root/.cache/pip/wheels diff --git a/build-docker.sh b/build-docker.sh index 5d504d142..67376f990 100755 --- a/build-docker.sh +++ b/build-docker.sh @@ -5,4 +5,4 @@ rm -rf gov.pnnl.goss/gridappsd/generated #copy built jar to docker echo "copying run.bnd.jar into container" -docker cp gov.pnnl.goss.gridappsd/generated/distributions/executable/run.bnd.jar gridappsddocker_gridappsd_1:/gridappsd/lib/run.bnd.jar +docker cp gov.pnnl.goss.gridappsd/generated/distributions/executable/run.bnd.jar gridappsd:/gridappsd/lib/run.bnd.jar diff --git a/build-gridappsd-container b/build-gridappsd-container index 89b0af39c..3f842ca03 100755 --- a/build-gridappsd-container +++ b/build-gridappsd-container @@ -1,7 +1,67 @@ -docker pull gridappsd/gridappsd_base:master +#!/usr/bin/env python3 -./gradlew clean -rm -rf gov.pnnl.goss/gridappsd/generated -./gradlew export +""" +Script for building the gridappsd container. -docker build --no-cache --network=host -t gridappsd:local . +This script pulls the gridappsd_base docker image, cleans the project, exports the project, and builds the gridappsd container. + +Usage: + python build-gridappsd-container [--output_version ] + +Arguments: + base_version (str): The version of the gridappsd_base docker image. + output_version (str, optional): The output tag version for local development. Default is "local". + +Example: + python build-gridappsd-container.py 2.3.0 --output_version 2.3.1 + +""" + +import argparse +import subprocess +import shutil + + +def execute(cmd: str | list[str]): + """ + Executes a command in the shell and prints the output. + + Args: + cmd (str | list[str]): The command to execute. If a string, it will be split into a list of arguments. + + Raises: + subprocess.CalledProcessError: If the command returns a non-zero exit code. + + """ + if isinstance(cmd, str): + cmd = cmd.split(" ") + + with subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True) as p: + for line in iter(p.stdout.readline, ""): + if line.strip(): + print(line.strip()) + + p.wait() + if p.returncode: + raise subprocess.CalledProcessError(p.returncode, cmd=" ".join(cmd)) + + + +if __name__ == '__main__': + + parser = argparse.ArgumentParser() + + parser.add_argument("base_version", + help="The gridappsd_base docker image version") + parser.add_argument("--output_version", default="local", + help="The output tag version for local development") + + opts = parser.parse_args() + + base_version = opts.base_version + + execute(f"docker pull gridappsd/gridappsd_base:{opts.base_version}") + execute("./gradlew clean") + shutil.rmtree("gov.pnnl.goss/gridappsd/generated", ignore_errors=True) + execute("./gradlew export") + execute(f"docker build --build-arg GRIDAPPSD_BASE_VERSION=:{opts.base_version} --no-cache --network=host -t gridappsd:{opts.output_version} .") diff --git a/cnf/release/gov.pnnl.goss.gridappsd.gridappsd.api/gov.pnnl.goss.gridappsd.gridappsd.api-2.0.0.jar b/cnf/release/gov.pnnl.goss.gridappsd.gridappsd.api/gov.pnnl.goss.gridappsd.gridappsd.api-2.0.0.jar new file mode 100644 index 000000000..9ce59bff2 Binary files /dev/null and b/cnf/release/gov.pnnl.goss.gridappsd.gridappsd.api/gov.pnnl.goss.gridappsd.gridappsd.api-2.0.0.jar differ diff --git a/cnf/release/gov.pnnl.goss.gridappsd.gridappsd/gov.pnnl.goss.gridappsd.gridappsd-1.0.0.jar b/cnf/release/gov.pnnl.goss.gridappsd.gridappsd/gov.pnnl.goss.gridappsd.gridappsd-1.0.0.jar new file mode 100644 index 000000000..61624fe2c Binary files /dev/null and b/cnf/release/gov.pnnl.goss.gridappsd.gridappsd/gov.pnnl.goss.gridappsd.gridappsd-1.0.0.jar differ diff --git a/entrypoint.sh b/entrypoint.sh index ca3a5c413..6374fd248 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -11,9 +11,14 @@ if [ "$1" = "gridappsd" ]; then sudo pip install -q --disable-pip-version-check -r $reqfile done - # Run tail -f /dev/null to keep the container running and waiting for connection - echo "[Entrypoint] Waiting for connection" - tail -f /dev/null + + if [ "${AUTOSTART:-0}" != "0" ]; then + /gridappsd/run-gridappsd.sh + else + # Run tail -f /dev/null to keep the container running and waiting for connection + echo "[Entrypoint] Waiting for connection" + tail -f /dev/null + fi elif [ "$1" = "version" -o "$1" = "-v" -o "$1" = "--version" ]; then echo -n "version: " cat /gridappsd/dockerbuildversion.txt diff --git a/gov.pnnl.goss.gridappsd/bnd.bnd b/gov.pnnl.goss.gridappsd/bnd.bnd index 5e24e9dfc..faf585408 100644 --- a/gov.pnnl.goss.gridappsd/bnd.bnd +++ b/gov.pnnl.goss.gridappsd/bnd.bnd @@ -29,13 +29,18 @@ osgi.enroute.base.api,\ org.mockito.mockito-all,\ httpcore,\ - cimhub.lib;version=0.2.4,\ + cimhub.lib;version=2.0.3,\ httpclient,\ com.bigdata.rdf,\ - proven-client;version=0.3,\ - proven-message;version=0.4,\ - com.nimbusds.nimbus-jose-jwt-dependencies - + org.glassfish.jersey.core.jersey-client;version=2.26,\ + org.glassfish.jersey.core.jersey-common;version=2.26,\ + org.glassfish.jersey.media.jersey-media-json-jackson;version=2.26.0,\ + proven-client;version=0.2.5,\ + proven-message;version=0.5,\ + com.nimbusds.nimbus-jose-jwt-dependencies,\ + org.apache.servicemix.bundles.poi;version=3.17,\ + org.apache.commons.commons-collections4;version=4.4 + -plugin org.apache.felix.dm.annotation.plugin.bnd.AnnotationPlugin;log=debug -sub: *.bnd diff --git a/gov.pnnl.goss.gridappsd/conf/org.ops4j.pax.logging.cfg b/gov.pnnl.goss.gridappsd/conf/org.ops4j.pax.logging.cfg index fb1e198dc..33da97c7a 100644 --- a/gov.pnnl.goss.gridappsd/conf/org.ops4j.pax.logging.cfg +++ b/gov.pnnl.goss.gridappsd/conf/org.ops4j.pax.logging.cfg @@ -28,3 +28,5 @@ log4j.additivity.org.apache.activemq = false log4j.logger.org.apache.http = WARN, file log4j.additivity.org.apache.http = false +log4j.category.pnnl.goss.core.security = WARN, file + diff --git a/gov.pnnl.goss.gridappsd/conf/pnnl.goss.gridappsd.cfg b/gov.pnnl.goss.gridappsd/conf/pnnl.goss.gridappsd.cfg index d530fe550..b6443883b 100644 --- a/gov.pnnl.goss.gridappsd/conf/pnnl.goss.gridappsd.cfg +++ b/gov.pnnl.goss.gridappsd/conf/pnnl.goss.gridappsd.cfg @@ -5,7 +5,7 @@ fncs.bridge.path = ./scripts/goss_fncs_bridge.py applications.path = /gridappsd/applications services.path = /gridappsd/services # Requires no / -blazegraph.ns.path = http://localhost:8889/bigdata/namespace/kb/sparql +blazegraph.ns.path = urn:uuid: # Uses docker composed blazegraph host here. Note this is not the # external address, but from inside one of the containers on the @@ -27,3 +27,12 @@ proven.write.path = http://proven:8080/hybrid/rest/v1/repository/addBulkTimeSeri # external address, but from inside one of the containers on the # docker-compose default network. proven.query.path = http://proven:8080/hybrid/rest/v1/repository/provenMessage + +# Uses docker composed proven host here. Note this is not the +# external address, but from inside one of the containers on the +# docker-compose default network. +proven.advanced_query.path = http://proven:8080/hybrid/rest/v1/repository/getAdvancedTsQuery + + +# Power grid model MRID for deployed Field Bus +field.model.mrid = 49AD8E07-3BF9-A4E2-CB8F-C3722F837B62 diff --git a/gov.pnnl.goss.gridappsd/gridappsd.api.bnd b/gov.pnnl.goss.gridappsd/gridappsd.api.bnd index 7f82d90bc..33a8574d4 100644 --- a/gov.pnnl.goss.gridappsd/gridappsd.api.bnd +++ b/gov.pnnl.goss.gridappsd/gridappsd.api.bnd @@ -1,6 +1,8 @@ -Bundle-Version: 1.0.0.${tstamp} +Bundle-Version: 2.0.0.${tstamp} Export-Package: \ + gov.pnnl.goss.gridappsd.dto.field,\ gov.pnnl.goss.gridappsd.api,\ gov.pnnl.goss.gridappsd.dto,\ - gov.pnnl.goss.gridappsd.dto.events + gov.pnnl.goss.gridappsd.dto.events,\ + gov.pnnl.goss.gridappsd.dto.field Private-Package: gov.pnnl.goss.gridappsd.data.conversion \ No newline at end of file diff --git a/gov.pnnl.goss.gridappsd/gridappsd.bnd b/gov.pnnl.goss.gridappsd/gridappsd.bnd index 00bd17c1c..85568d6b1 100644 --- a/gov.pnnl.goss.gridappsd/gridappsd.bnd +++ b/gov.pnnl.goss.gridappsd/gridappsd.bnd @@ -1,4 +1,4 @@ -Bundle-Version: 0.0.1.${tstamp} +Bundle-Version: 1.0.0.${tstamp} Private-Package: \ gov.pnnl.goss.gridappsd.configuration,\ @@ -13,7 +13,8 @@ Private-Package: \ gov.pnnl.goss.gridappsd.log,\ gov.pnnl.goss.gridappsd.app,\ gov.pnnl.goss.gridappsd.service,\ - gov.pnnl.goss.gridappsd.testmanager + gov.pnnl.goss.gridappsd.testmanager,\ + gov.pnnl.goss.gridappsd.distributed Export-Package: \ gov.pnnl.goss.gridappsd.dto,\ gov.pnnl.goss.gridappsd.api diff --git a/gov.pnnl.goss.gridappsd/run.bnd.bndrun b/gov.pnnl.goss.gridappsd/run.bnd.bndrun index bd11bbf65..dd2a50791 100644 --- a/gov.pnnl.goss.gridappsd/run.bnd.bndrun +++ b/gov.pnnl.goss.gridappsd/run.bnd.bndrun @@ -76,25 +76,25 @@ httpcore,\ httpclient,\ xml-apis,\ - cimhub.lib;version=0.2.4,\ + cimhub.lib;version=2.0.3,\ org.eclipse.jetty.aggregate.jetty-all-server;version=7.6.9,\ com.bigdata.rdf,\ - proven-message;version=0.4,\ - proven-client;version=0.3,\ + proven-message;version=0.5,\ + proven-client;version=0.2.5,\ javax.ws.rs-api,\ org.apache.commons.codec,\ shacl,\ com.hazelcast,\ - org.glassfish.jersey.core.jersey-client,\ + org.glassfish.jersey.core.jersey-client;version=2.26,\ javax.annotation-api;version=1.2.0,\ javax.inject;version=1.0.0,\ org.glassfish.jersey.bundles.repackaged.jersey-guava,\ org.glassfish.hk2.api;version=2.4.0,\ aopalliance,\ org.glassfish.hk2.utils;version=2.5.0,\ - org.glassfish.jersey.core.jersey-common,\ + org.glassfish.jersey.core.jersey-common;version=2.26,\ org.glassfish.hk2.osgi-resource-locator,\ - org.glassfish.jersey.media.jersey-media-json-jackson;version=2.18.0,\ + org.glassfish.jersey.media.jersey-media-json-jackson;version=2.26.0,\ com.fasterxml.jackson.module.jackson-module-jaxb-annotations,\ org.glassfish.jersey.ext.jersey-entity-filtering,\ com.google.guava;version=14.0.0,\ @@ -107,9 +107,9 @@ org.apache.felix.http.servlet-api,\ com.fasterxml.jackson.jaxrs.jackson-jaxrs-base,\ javax.ws.rs.jsr311-api,\ - javax.ws.rs-api - - + org.apache.servicemix.bundles.poi;version=3.17,\ + org.apache.commons.commons-collections4;version=4.4 + # Add broker name to the properties defined in shared.runprops -runproperties: ${shared.runprops},\ diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/api/FieldBusManager.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/api/FieldBusManager.java new file mode 100644 index 000000000..b4a434ac2 --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/api/FieldBusManager.java @@ -0,0 +1,11 @@ +package gov.pnnl.goss.gridappsd.api; + +import java.io.Serializable; + +public interface FieldBusManager { + + public Serializable handleRequest(String requestQueue, Serializable request); + + public String getFieldModelMrid(); + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/api/SimulationManager.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/api/SimulationManager.java index 5c94e29cc..5bede57ab 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/api/SimulationManager.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/api/SimulationManager.java @@ -41,6 +41,7 @@ import java.util.Map; +import gov.pnnl.goss.gridappsd.dto.PowerSystemConfig; import gov.pnnl.goss.gridappsd.dto.SimulationConfig; import gov.pnnl.goss.gridappsd.dto.SimulationContext; @@ -58,7 +59,7 @@ public interface SimulationManager { * @param simulationFile * @param simulationConfig Map simulationContext */ - void startSimulation(String simulationId, SimulationConfig simulationConfig, SimulationContext simContext, Map simulationContext); + void startSimulation(String simulationId, SimulationConfig simulationConfig, SimulationContext simContext, Map simulationContext, PowerSystemConfig powerSystemConfig); SimulationContext getSimulationContextForId(String simulationId); @@ -68,4 +69,6 @@ public interface SimulationManager { void resumeSimulation(String simulationId); + int assignSimulationPort(String simulationId) throws Exception; + } diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/api/package-info.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/api/package-info.java index 2f5c6629f..22a26c022 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/api/package-info.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/api/package-info.java @@ -37,5 +37,5 @@ * PACIFIC NORTHWEST NATIONAL LABORATORY operated by BATTELLE for the * UNITED STATES DEPARTMENT OF ENERGY under Contract DE-AC05-76RL01830 ******************************************************************************/ -@aQute.bnd.annotation.Version("1.0.0") +@aQute.bnd.annotation.Version("2.0.0") package gov.pnnl.goss.gridappsd.api; diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/DSSAllConfigurationHandler.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/DSSAllConfigurationHandler.java index 2a353632c..71fa2bbe7 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/DSSAllConfigurationHandler.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/DSSAllConfigurationHandler.java @@ -57,6 +57,7 @@ import java.io.File; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Properties; import org.apache.felix.dm.annotation.api.Component; @@ -227,12 +228,14 @@ public void generateConfig(Properties parameters, PrintWriter out, String proces boolean bHaveEventGen = true; //TODO add climate - + String fEarth = "carson"; //values "deri", "carson", or "fullcarson". This only matters for OpenDSS, which uses "deri" by default. However, "carson" gives the best match to GridLAB-D + int iManualFile = 0; //values 1 to reference manual pre-edits, 2 for post-edits, 3 for both edits in exported + boolean bUseProfiles = true; //true to use players, schedules and shapes //cimhub utility uses CIMImporter cimImporter = new CIMImporter(); CIMQuerySetter qs = new CIMQuerySetter(); - cimImporter.start(queryHandler, qs, CONFIGTARGET, fRoot, scheduleName, loadScale, bWantSched, bWantZip, bWantRandomFractions, useHouses, zFraction, iFraction, pFraction, bHaveEventGen, modelState, false); - + cimImporter.start(queryHandler, qs, CONFIGTARGET, fRoot, scheduleName, loadScale, bWantSched, bWantZip, bWantRandomFractions, useHouses, zFraction, iFraction, pFraction, bHaveEventGen, modelState, false, fEarth, iManualFile, bUseProfiles); + logManager.info(ProcessStatus.RUNNING, processId, "Finished generating all DSS configuration files."); diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/DSSBaseConfigurationHandler.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/DSSBaseConfigurationHandler.java index 037c3c43e..978748d31 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/DSSBaseConfigurationHandler.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/DSSBaseConfigurationHandler.java @@ -200,17 +200,18 @@ public void generateConfig(Properties parameters, PrintWriter out, String proces //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); - + String fEarth = "carson"; //values "deri", "carson", or "fullcarson". This only matters for OpenDSS, which uses "deri" by default. However, "carson" gives the best match to GridLAB-D + boolean bUseProfiles = true; //true to use players, schedules and shapes CIMImporter cimImporter = new CIMImporter(); //If the simulation info is available also write to file if(configFile!=null){ cimImporter.generateDSSFile(queryHandler, new PrintWriter(new FileWriter(configFile)), new PrintWriter(new FileWriter(idFile)), buscoords, guids, loadScale, - bWantSched, null, bWantZip, zFraction, iFraction, pFraction); + bWantSched, null, bWantZip, zFraction, iFraction, pFraction, fEarth, bUseProfiles); //config was written to base file, so return that printFileToOutput(configFile, out); } else { PrintWriter idFileWriter = new PrintWriter(new StringWriter()); - cimImporter.generateDSSFile(queryHandler, out, idFileWriter, buscoords, guids, loadScale, bWantSched, null, bWantZip, zFraction, iFraction, pFraction); + cimImporter.generateDSSFile(queryHandler, out, idFileWriter, buscoords, guids, loadScale, bWantSched, null, bWantZip, zFraction, iFraction, pFraction, fEarth, bUseProfiles); idFileWriter.close(); } logManager.info(ProcessStatus.RUNNING, processId, "Finished generating DSS Base configuration file."); diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDAllConfigurationHandler.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDAllConfigurationHandler.java index 5ab76798e..f5a9e4d86 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDAllConfigurationHandler.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDAllConfigurationHandler.java @@ -40,11 +40,16 @@ package gov.pnnl.goss.gridappsd.configuration; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; +import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Properties; @@ -53,6 +58,13 @@ import org.apache.felix.dm.annotation.api.Start; import org.apache.jena.query.QuerySolution; import org.apache.jena.query.ResultSet; + +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,6 +86,7 @@ import gov.pnnl.goss.gridappsd.data.handlers.BlazegraphQueryHandler; import gov.pnnl.goss.gridappsd.dto.LogMessage.ProcessStatus; import gov.pnnl.goss.gridappsd.dto.RequestTimeseriesData; +import gov.pnnl.goss.gridappsd.dto.RequestTimeseriesDataBasic; import gov.pnnl.goss.gridappsd.utils.GridAppsDConstants; import pnnl.goss.core.Client; import pnnl.goss.core.DataResponse; @@ -117,7 +130,11 @@ public class GLDAllConfigurationHandler extends BaseConfigurationHandler impleme public static final String STARTTIME_FILTER = "startTime"; public static final String ENDTIME_FILTER = "endTime"; public static final String MODEL_STATE = "model_state"; + public static final String SIMULATOR = "simulator"; + public static final String SEPARATED_LOADS_FILE = "separated_loads_file"; public static final int TIMEFILTER_YEAR = 2013; + public static final String RUN_REALTIME = "run_realtime"; + public static final String TIMESTEP = "timestep"; // public static final String CONFIGTARGET = "glm"; public static final String CONFIGTARGET = "both"; //will build files for both glm and dss @@ -162,6 +179,7 @@ public void start(){ public void generateConfig(Properties parameters, PrintWriter out, String processId, String username) throws Exception { boolean bWantZip = true; boolean bWantSched = false; + List separateLoads = new ArrayList(); logManager.info(ProcessStatus.RUNNING,processId,"Generating all GridLAB-D configuration files using parameters: "+parameters); @@ -242,17 +260,29 @@ public void generateConfig(Properties parameters, PrintWriter out, String proces boolean useClimate = true;//GridAppsDConstants.getBooleanProperty(parameters, USECLIMATE, false); boolean bHaveEventGen = true; - + + String separatedLoadsFile = GridAppsDConstants.getStringProperty(parameters, SEPARATED_LOADS_FILE, null); + String simulator = GridAppsDConstants.getStringProperty(parameters, SIMULATOR, null); + //TODO parse xlsx spreadsheet specified in separatedLoadsFile + if(separatedLoadsFile!=null && simulator.equalsIgnoreCase("ochre")) { + separateLoads = getSeparatedLoadNames(separatedLoadsFile); + } else if(separatedLoadsFile==null && simulator.equalsIgnoreCase("ochre")) { + logManager.error(ProcessStatus.ERROR,processId,"No "+SEPARATED_LOADS_FILE+" parameter provided"); + throw new Exception("Missing parameter "+SEPARATED_LOADS_FILE); + } + String fEarth = "carson"; //values "deri", "carson", or "fullcarson". This only matters for OpenDSS, which uses "deri" by default. However, "carson" gives the best match to GridLAB-D + int iManualFile = 0; //values 1 to reference manual pre-edits, 2 for post-edits, 3 for both edits in exported + boolean bUseProfiles = true; //true to use players, schedules and shapes //cimhub utility uses CIMImporter cimImporter = new CIMImporter(); CIMQuerySetter qs = new CIMQuerySetter(); - cimImporter.start(queryHandler, qs, CONFIGTARGET, fRoot, scheduleName, loadScale, bWantSched, bWantZip, bWantRandomFractions, useHouses, zFraction, iFraction, pFraction, bHaveEventGen, modelState, false); + cimImporter.start(queryHandler, qs, CONFIGTARGET, fRoot, scheduleName, loadScale, bWantSched, bWantZip, bWantRandomFractions, useHouses, zFraction, iFraction, pFraction, -1, bHaveEventGen, modelState, false, fEarth, iManualFile, bUseProfiles, separateLoads); String tempDataPath = dir.getAbsolutePath(); //If use climate, then generate gridlabd weather data file try { if(useClimate){ - RequestTimeseriesData weatherRequest = new RequestTimeseriesData(); + RequestTimeseriesDataBasic weatherRequest = new RequestTimeseriesDataBasic(); weatherRequest.setQueryMeasurement("weather"); weatherRequest.setResponseFormat(ProvenWeatherToGridlabdWeatherConverter.OUTPUT_FORMAT); Map queryFilter = new HashMap(); @@ -328,6 +358,7 @@ protected void generateStartupFile(Properties parameters, String tempDataPath, P String gldInterface = GridAppsDConstants.getStringProperty(parameters, GridAppsDConstants.GRIDLABD_INTERFACE, GridAppsDConstants.GRIDLABD_INTERFACE_FNCS); + String simulator = GridAppsDConstants.getStringProperty(parameters, SIMULATOR, null); String simulationBrokerHost = GridAppsDConstants.getStringProperty(parameters, SIMULATIONBROKERHOST, null); if(simulationBrokerHost==null || simulationBrokerHost.trim().length()==0){ @@ -360,7 +391,9 @@ protected void generateStartupFile(Properties parameters, String tempDataPath, P throw new Exception("Missing parameter "+SIMULATIONID); } String scheduleName = GridAppsDConstants.getStringProperty(parameters, SCHEDULENAME, null); - + + boolean run_realtime = GridAppsDConstants.getBooleanProperty(parameters, RUN_REALTIME, true); + double nominalv = 0; try{ @@ -430,8 +463,13 @@ protected void generateStartupFile(Properties parameters, String tempDataPath, P if(GridAppsDConstants.GRIDLABD_INTERFACE_HELICS.equals(gldInterface)){ startupFileWriter.println("object helics_msg {"); - startupFileWriter.println(" name "+simulationID+";"); - startupFileWriter.println(" message_type JSON;"); + startupFileWriter.println(" name "+modelId+";"); + if(simulator.equalsIgnoreCase("gridlab-d")) + startupFileWriter.println(" message_type JSON;"); + if(run_realtime) + startupFileWriter.println(" publish_period 3;"); + else + startupFileWriter.println(" publish_period 60;"); startupFileWriter.println(" configure model_outputs.json;"); startupFileWriter.println("}"); @@ -445,10 +483,13 @@ protected void generateStartupFile(Properties parameters, String tempDataPath, P } startupFileWriter.println("object recorder {"); - startupFileWriter.println(" parent "+simulationID+";"); + startupFileWriter.println(" parent "+modelId+";"); startupFileWriter.println(" property message_type;"); - startupFileWriter.println(" file "+simulationID+".csv;"); - startupFileWriter.println(" interval 1;"); + startupFileWriter.println(" file "+modelId+".csv;"); + if(run_realtime) + startupFileWriter.println(" interval 1;"); + else + startupFileWriter.println(" interval 60;"); startupFileWriter.println("}"); /*startupFileWriter.println("object multi_recorder {"); startupFileWriter.println(" parent "+simulationName+";"); @@ -464,7 +505,11 @@ protected void generateStartupFile(Properties parameters, String tempDataPath, P startupFileWriter.println(" eventgen_object external_event_handler;"); startupFileWriter.println(" output_filename fault_check_output.txt;"); startupFileWriter.println(" strictly_radial FALSE;"); - startupFileWriter.println(" grid_association TRUE;"); + //TODO: Remove if condition and set grid_association to TRUE once issue with GridLAB-D is resolved + if(modelId.equals("_5DB4FA23-623B-4DBE-BA59-B99ECF44DABA")) + startupFileWriter.println(" grid_association FALSE;"); + else + startupFileWriter.println(" grid_association TRUE;"); startupFileWriter.println("}"); startupFileWriter.println("object eventgen {"); startupFileWriter.println(" name external_event_handler;"); @@ -503,5 +548,39 @@ protected void generateStartupFile(Properties parameters, String tempDataPath, P } + private List getSeparatedLoadNames(String fileName) { + + List loadNames = new ArrayList(); + boolean isHeader = true; + + try { + FileInputStream fis = new FileInputStream(fileName); + Workbook workbook = null; + if(fileName.toLowerCase().endsWith("xlsx")){ + workbook = new XSSFWorkbook(fis); + }else if(fileName.toLowerCase().endsWith("xls")){ + workbook = new HSSFWorkbook(fis); + } + + Sheet sheet = workbook.getSheetAt(0); + Iterator rowIterator = sheet.iterator(); + while (rowIterator.hasNext()) + { + + Row row = rowIterator.next(); + if(!isHeader){ + loadNames.add(row.getCell(5).getStringCellValue()); + System.out.println(row.getCell(5).getStringCellValue()); + } + isHeader=false; + } + fis.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + + return loadNames; + } } diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDBaseConfigurationHandler.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDBaseConfigurationHandler.java index 5b9bba99a..780253e3a 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDBaseConfigurationHandler.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDBaseConfigurationHandler.java @@ -177,7 +177,7 @@ public void generateConfig(Properties parameters, PrintWriter out, String proces queryHandler.addFeederSelection(modelId); boolean useHouses = GridAppsDConstants.getBooleanProperty(parameters, USEHOUSES, false); - + boolean bUseProfiles = true; //bUseProfiles true to use players, schedules and shapes boolean bHaveEventGen = true; CIMImporter cimImporter = new CIMImporter(); @@ -185,9 +185,9 @@ public void generateConfig(Properties parameters, PrintWriter out, String proces //If the simulation info is available also write to file if(configFile!=null){ - cimImporter.generateGLMFile(queryHandler, qs, new PrintWriter(new FileWriter(configFile)), scheduleName, loadScale, bWantSched, bWantZip, bWantRandomFractions, useHouses, zFraction, iFraction, pFraction, bHaveEventGen); + cimImporter.generateGLMFile(queryHandler, qs, new PrintWriter(new FileWriter(configFile)), scheduleName, loadScale, bWantSched, bWantZip, bWantRandomFractions, useHouses, zFraction, iFraction, pFraction, bHaveEventGen, bUseProfiles); } else { - cimImporter.generateGLMFile(queryHandler, qs, out, scheduleName, loadScale, bWantSched, bWantZip, bWantRandomFractions, useHouses,zFraction, iFraction, pFraction, bHaveEventGen); + cimImporter.generateGLMFile(queryHandler, qs, out, scheduleName, loadScale, bWantSched, bWantZip, bWantRandomFractions, useHouses,zFraction, iFraction, pFraction, bHaveEventGen, bUseProfiles); } if(configFile!=null){ //config was written to file, so return that diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDSimulationOutputConfigurationHandler.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDSimulationOutputConfigurationHandler.java index aaaec70dc..6cf2af61a 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDSimulationOutputConfigurationHandler.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDSimulationOutputConfigurationHandler.java @@ -106,13 +106,25 @@ public class GLDSimulationOutputConfigurationHandler extends BaseConfigurationHa public static final String SIMULATIONBROKERPORT = "simulation_broker_port"; - public static final String HELICS_PREFIX = "{\"name\": \"PROCESS_ID\",\"log_level\": 3," - + "\"period\": 1.0,\"broker\": \"BROKER_LOCATION:BROKER_PORT\",\"endpoints\": [{\"name\": \"helics_input\"," - + "\"global\": false,\"type\": \"string\", " - + "\"info\": \"This is the endpoint which recieves CIM commands from the HELICS GOSS bridge.\"}," - + "{\"name\": \"helics_output\",\"global\": false,\"type\": \"string\", " - + "\"destination\": \"HELICS_GOSS_Bridge_PROCESS_ID/helics_output\", \"info\": \""; - public static final String HELICS_SUFFIX = "\"}]}"; + public static final String HELICS_PREFIX = "{\n" + + "\t\"name\": \"MODEL_ID\",\n" + + "\t\"log_level\": \"DATA\",\n" + + "\t\"period\": 1.0,\n" + + "\t\"broker\": \"BROKER_LOCATION:BROKER_PORT\",\n" + + "\t\"endpoints\": [\n" + + "\t\t{\n" + + "\t\t\t\"name\": \"helics_input\",\n" + + "\t\t\t\"global\": false,\n" + + "\t\t\t\"type\": \"string\",\n" + + "\t\t\t\"info\": \"This is the endpoint which recieves CIM commands from the HELICS GOSS bridge.\"\n" + + "\t\t},\n" + + "\t\t{\n" + + "\t\t\t\"name\": \"helics_output\",\n" + + "\t\t\t\"global\": false,\n" + + "\t\t\t\"type\": \"string\",\n" + + "\t\t\t\"destination\": \"HELICS_GOSS_Bridge_PROCESS_ID/helics_output\",\n" + + "\t\t\t\"info\": "; + public static final String HELICS_SUFFIX = "\t\t}\n\t]\n}"; public GLDSimulationOutputConfigurationHandler() { } @@ -237,9 +249,8 @@ public void generateConfig(Properties parameters, PrintWriter out, String proces String brokerPort = String.valueOf(simulationBrokerPort); String HELICS_PREFIX1 = HELICS_PREFIX.replaceAll("BROKER_LOCATION", brokerLocation); String HELICS_PREFIX2 = HELICS_PREFIX1.replaceAll("BROKER_PORT", brokerPort); - result = HELICS_PREFIX2.replaceAll("PROCESS_ID", processId) - +result.replaceAll("\"", "\\\\\"").replaceAll("\n","")+ - HELICS_SUFFIX; + result = HELICS_PREFIX2.replaceAll("PROCESS_ID", processId).replaceAll("MODEL_ID", modelId) + + result.replaceAll(" ", "\t\t\t\t\t").replaceAll(" ", "\t\t\t\t").replaceAll("}", "\t\t\t}\n") + HELICS_SUFFIX; } if(configFile!=null){ @@ -333,7 +344,7 @@ void parseMeasurement(Map measurements, JsonObject measuremen } 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")) { + } else if (conductingEquipmentType.contains("PowerTransformer") || conductingEquipmentType.contains("TransformerTank")) { if(measurementType.equals("VA")) { objectName = conductingEquipmentName; propertyName = "power_in_" + phases; @@ -344,7 +355,7 @@ void parseMeasurement(Map measurements, JsonObject measuremen objectName = 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)); + throw new JsonParseException(String.format("CimMeasurementsToGldPubs::parseMeasurement: The value of measurementType is not a valid type.\nValid types for PowerTransformers and TransformerTanks are VA, PNV, and A.\nmeasurementType = %s.",measurementType)); } } else if (conductingEquipmentType.contains("RatioTapChanger")) { if(measurementType.equals("VA")) { @@ -454,7 +465,7 @@ void parseMeasurement(Map measurements, JsonObject measuremen throw new JsonParseException(String.format("CimMeasurementsToGldPubs::parseMeasurement: The value of measurementType is not a valid type.\nValid types for SynchronousMachine 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)); + 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, TransformerTank, and PowerTransformer.\nConductingEquipment_type = %s.",conductingEquipmentType)); } if(measurements.containsKey(objectName)) { diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDZiploadScheduleConfigurationHandler.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDZiploadScheduleConfigurationHandler.java index 20f8e173a..33436a24a 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDZiploadScheduleConfigurationHandler.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/GLDZiploadScheduleConfigurationHandler.java @@ -49,6 +49,7 @@ import gov.pnnl.goss.gridappsd.dto.LogMessage.LogLevel; import gov.pnnl.goss.gridappsd.dto.LogMessage.ProcessStatus; import gov.pnnl.goss.gridappsd.dto.RequestTimeseriesData; +import gov.pnnl.goss.gridappsd.dto.RequestTimeseriesDataBasic; import gov.pnnl.goss.gridappsd.utils.GridAppsDConstants; import java.io.File; @@ -164,7 +165,7 @@ public void generateConfig(Properties parameters, PrintWriter out, logManager.error(ProcessStatus.ERROR, simulationID,"Simulation ID not a valid "+simulationID+", defaulting to "+simId); } - RequestTimeseriesData request = new RequestTimeseriesData(); + RequestTimeseriesDataBasic request = new RequestTimeseriesDataBasic(); request.setQueryMeasurement(loadprofile); request.setResponseFormat(ProvenLoadScheduleToGridlabdLoadScheduleConverter.OUTPUT_FORMAT); Map queryFilter = new HashMap(); diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/OchreAllConfigurationHandler.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/OchreAllConfigurationHandler.java index 2e578421f..de24b7b87 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/OchreAllConfigurationHandler.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/OchreAllConfigurationHandler.java @@ -42,6 +42,7 @@ import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; +import java.util.Date; import java.util.Properties; import org.apache.felix.dm.annotation.api.Component; @@ -89,6 +90,7 @@ public class OchreAllConfigurationHandler extends BaseConfigurationHandler imple public static final String CONFIG_FILENAME = "ochre_helics_config.json"; public static final String SIMULATIONBROKERHOST = "simulation_broker_host"; public static final String SIMULATIONBROKERPORT = "simulation_broker_port"; + public static final String MODEL_ID = "model_id"; public OchreAllConfigurationHandler() { } @@ -138,11 +140,26 @@ public void generateConfig(Properties parameters, PrintWriter out, String proces logManager.error(ProcessStatus.ERROR,processId,"No "+SIMULATIONBROKERPORT+" parameter provided"); throw new Exception("Missing parameter "+SIMULATIONBROKERPORT); } - + + String model_id = GridAppsDConstants.getStringProperty(parameters, MODEL_ID, null); + if(model_id==null || model_id.trim().length()==0){ + logManager.error(ProcessStatus.ERROR,processId,"No "+MODEL_ID+" parameter provided"); + throw new Exception("Missing parameter "+MODEL_ID); + } + + String separated_loads_file = GridAppsDConstants.getStringProperty(parameters, GLDAllConfigurationHandler.SEPARATED_LOADS_FILE, null); + if(separated_loads_file==null || separated_loads_file.trim().length()==0){ + logManager.error(ProcessStatus.ERROR,processId,"No "+GLDAllConfigurationHandler.SEPARATED_LOADS_FILE+" parameter provided"); + throw new Exception("Missing parameter "+GLDAllConfigurationHandler.SEPARATED_LOADS_FILE); + } + + + try{ File tmpDir = new File(tempDataPath); RunCommandLine.runCommand("cp -r /gridappsd/services/gridappsd-ochre/inputs/ "+tempDataPath); RunCommandLine.runCommand("cp -r /gridappsd/services/gridappsd-ochre/agents/ "+tempDataPath); + simulationBrokerHost = "localhost"; RunCommandLine.runCommand("python /gridappsd/services/gridappsd-ochre/bin/make_config_file.py "+ @@ -150,15 +167,17 @@ public void generateConfig(Properties parameters, PrintWriter out, String proces tempDataPath+" "+ CONFIG_FILENAME+" "+ simulationBrokerPort+" "+ - processId); + processId+" "+ + model_id+ " "+ + separated_loads_file); logManager.info(ProcessStatus.RUNNING, processId, "python /gridappsd/services/gridappsd-ochre/bin/make_config_file.py "+ simulationBrokerHost+" "+ tempDataPath+" "+ CONFIG_FILENAME+" "+ simulationBrokerPort+" "+ - processId); - - RunCommandLine.runCommand("cp "+tempDataPath+"/inputs/gridlabd/IEEE-13/gld_helics_config.json "+tempDataPath); + processId+" "+ + model_id+" "+ + separated_loads_file); }catch(Exception e){ log.warn("Could not create OCHRE HELICS config file"); diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/VnomExportConfigurationHandler.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/VnomExportConfigurationHandler.java index 8e83a9bf6..dedd5715e 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/VnomExportConfigurationHandler.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/VnomExportConfigurationHandler.java @@ -1,217 +1,249 @@ -/******************************************************************************* - * 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 gov.pnnl.goss.gridappsd.api.ConfigurationHandler; -import gov.pnnl.goss.gridappsd.api.ConfigurationManager; -import gov.pnnl.goss.gridappsd.api.DataManager; -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.dto.LogMessage; -import gov.pnnl.goss.gridappsd.dto.LogMessage.LogLevel; -import gov.pnnl.goss.gridappsd.dto.LogMessage.ProcessStatus; -import gov.pnnl.goss.gridappsd.dto.SimulationContext; -import gov.pnnl.goss.gridappsd.dto.YBusExportResponse; -import gov.pnnl.goss.gridappsd.utils.GridAppsDConstants; - -import java.io.File; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.List; -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; - - -@Component -public class VnomExportConfigurationHandler implements ConfigurationHandler { - - private static Logger log = LoggerFactory.getLogger(VnomExportConfigurationHandler.class); - - @ServiceDependency - private volatile ConfigurationManager configManager; - - @ServiceDependency - private volatile SimulationManager simulationManager; - - @ServiceDependency - private volatile DataManager dataManager; - - @ServiceDependency - private volatile PowergridModelDataManager powergridModelManager; - - @ServiceDependency - volatile LogManager logManager; - - public static final String TYPENAME = "Vnom Export"; - public static final String SIMULATIONID = "simulation_id"; - - public VnomExportConfigurationHandler() { - } - - public VnomExportConfigurationHandler(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()); - } - } - - @Override - public void generateConfig(Properties parameters, PrintWriter out, String processId, String username) throws Exception { - - - String simulationId = parameters.getProperty(SIMULATIONID); - - if(simulationId==null) - throw new Exception("Simulation Id not provided in request paramters."); - - SimulationContext simulationContext = simulationManager.getSimulationContextForId(simulationId); - - if(simulationContext==null) - throw new Exception("Simulation context not found for simulation_id = "+simulationId); - - parameters.put("i_fraction", Double.toString(simulationContext.getRequest().getSimulation_config().getModel_creation_config().getiFraction())); - parameters.put("z_fraction", Double.toString(simulationContext.getRequest().getSimulation_config().getModel_creation_config().getzFraction())); - parameters.put("p_fraction", Double.toString(simulationContext.getRequest().getSimulation_config().getModel_creation_config().getpFraction())); - parameters.put("load_scaling_factor", Double.toString(simulationContext.getRequest().getSimulation_config().getModel_creation_config().getLoadScalingFactor())); - parameters.put("schedule_name", simulationContext.getRequest().getSimulation_config().getModel_creation_config().getScheduleName()); - parameters.put("model_id", simulationContext.getRequest().getPower_system_config().getLine_name()); - parameters.put("directory",simulationContext.getSimulationDir()); - parameters.put("simulation_start_time",simulationContext.getRequest().getSimulation_config().getStart_time()); - parameters.put("simulation_duration",simulationContext.getRequest().getSimulation_config().getDuration()); - - File simulationDir = new File(simulationContext.getSimulationDir()); - File commandFile = new File(simulationDir,"opendsscmdInput.txt"); - File dssBaseFile = new File(simulationDir,"model_base.dss"); - - - for(Object key: parameters.keySet().toArray()){ - log.debug(key.toString() + " = "+ parameters.getProperty(key.toString())); - } - - logManager.debug(ProcessStatus.RUNNING, simulationId, "Generating DSS base file"); - - //Create DSS base file - PrintWriter basePrintWriter = new PrintWriter(new StringWriter()); - DSSAllConfigurationHandler baseConfigurationHandler = new DSSAllConfigurationHandler(logManager,simulationManager,configManager); - baseConfigurationHandler.generateConfig(parameters, basePrintWriter, simulationId, username); - - if(!dssBaseFile.exists()) - throw new Exception("Error: Could not create DSS base file to export Vnom matrix"); - - logManager.debug(ProcessStatus.RUNNING, simulationId,"Finished generating DSS base file"); - - logManager.debug(ProcessStatus.RUNNING, simulationId,"Generating commands file for opendsscmd"); - - //Create file with commands for opendsscmd - PrintWriter fileWriter = new PrintWriter(commandFile); - fileWriter.println("redirect model_base.dss"); - // transformer winding ratios must be consistent with base voltages for state estimation - // regulators should be at tap 0; in case LDC is active, we can not use a no-load solution - fileWriter.println("batchedit transformer..* wdg=2 tap=1"); - fileWriter.println("batchedit regcontrol..* enabled=false"); - // remove isource injections from the Y matrix - fileWriter.println("batchedit isource..* enabled=false"); - // ensure that the voltage source is set to 1.0 per-unit - fileWriter.println("batchedit vsource..* pu=1.0"); - // remove PC elements from the Y matrix on solve - fileWriter.println("batchedit load..* enabled=false"); - fileWriter.println("batchedit generator..* enabled=false"); - fileWriter.println("batchedit pvsystem..* enabled=false"); - fileWriter.println("batchedit storage..* enabled=false"); - fileWriter.println("batchedit capacitor..* enabled=false"); - // solve the system in unloaded condition with regulator taps locked - fileWriter.println("solve"); - fileWriter.println("export voltages base_voltages.csv"); - fileWriter.flush(); - fileWriter.close(); - - logManager.debug(ProcessStatus.RUNNING, simulationId, "Finished generating commands file for opendsscmd"); - - logManager.debug(ProcessStatus.RUNNING, simulationId, "Generating Y Bus matrix"); - - ProcessBuilder processServiceBuilder = new ProcessBuilder(); - processServiceBuilder.directory(simulationDir); - List commands = new ArrayList(); - commands.add("opendsscmd"); - commands.add(commandFile.getName()); - - processServiceBuilder.command(new ArrayList<>(Arrays.asList("opendsscmd", commandFile.getName()))); - processServiceBuilder.redirectErrorStream(true); - processServiceBuilder.redirectOutput(); - Process process = processServiceBuilder.start(); - process.waitFor(); - - - YBusExportResponse response = new YBusExportResponse(); - - File vnomPath = new File(simulationDir.getAbsolutePath()+File.separator+"base_voltages.csv"); - - response.setVnom(Files.readAllLines(Paths.get(vnomPath.getPath()))); - - logManager.debug(ProcessStatus.RUNNING, simulationId, "Finished generating Vnom export"); - - out.print(response); - - - } - - - -} +/******************************************************************************* + * 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 gov.pnnl.goss.gridappsd.api.ConfigurationHandler; +import gov.pnnl.goss.gridappsd.api.ConfigurationManager; +import gov.pnnl.goss.gridappsd.api.DataManager; +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.dto.LogMessage; +import gov.pnnl.goss.gridappsd.dto.LogMessage.LogLevel; +import gov.pnnl.goss.gridappsd.dto.LogMessage.ProcessStatus; +import gov.pnnl.goss.gridappsd.dto.SimulationContext; +import gov.pnnl.goss.gridappsd.dto.YBusExportResponse; +import gov.pnnl.goss.gridappsd.utils.GridAppsDConstants; + +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +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; + + +@Component +public class VnomExportConfigurationHandler implements ConfigurationHandler { + + private static Logger log = LoggerFactory.getLogger(VnomExportConfigurationHandler.class); + + @ServiceDependency + private volatile ConfigurationManager configManager; + + @ServiceDependency + private volatile SimulationManager simulationManager; + + @ServiceDependency + private volatile DataManager dataManager; + + @ServiceDependency + private volatile PowergridModelDataManager powergridModelManager; + + @ServiceDependency + volatile LogManager logManager; + + public static final String TYPENAME = "Vnom Export"; + public static final String SIMULATIONID = "simulation_id"; + public static final String DIRECTORY = "directory"; + public static final String MODELID = "model_id"; + public static final String ZFRACTION = "z_fraction"; + public static final String IFRACTION = "i_fraction"; + public static final String PFRACTION = "p_fraction"; + public static final String SCHEDULENAME = "schedule_name"; + public static final String LOADSCALINGFACTOR = "load_scaling_factor"; + + public VnomExportConfigurationHandler() { + } + + public VnomExportConfigurationHandler(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()); + } + } + + @Override + public void generateConfig(Properties parameters, PrintWriter out, String processId, String username) throws Exception { + + + String simulationId = parameters.getProperty(SIMULATIONID); + + String modelId = null; + File simulationDir = null; + + if(simulationId!=null) { + + SimulationContext simulationContext = simulationManager.getSimulationContextForId(simulationId); + + + parameters.put("i_fraction", Double.toString(simulationContext.getRequest().getSimulation_config().getModel_creation_config().getiFraction())); + parameters.put("z_fraction", Double.toString(simulationContext.getRequest().getSimulation_config().getModel_creation_config().getzFraction())); + parameters.put("p_fraction", Double.toString(simulationContext.getRequest().getSimulation_config().getModel_creation_config().getpFraction())); + parameters.put("load_scaling_factor", Double.toString(simulationContext.getRequest().getSimulation_config().getModel_creation_config().getLoadScalingFactor())); + parameters.put("schedule_name", simulationContext.getRequest().getSimulation_config().getModel_creation_config().getScheduleName()); + parameters.put("model_id", simulationContext.getRequest().getPower_system_config().getLine_name()); + parameters.put("directory",simulationContext.getSimulationDir()); + parameters.put("simulation_start_time",simulationContext.getRequest().getSimulation_config().getStart_time()); + parameters.put("simulation_duration",simulationContext.getRequest().getSimulation_config().getDuration()); + + simulationDir = new File(simulationContext.getSimulationDir()); + + + + + } + else { + modelId = GridAppsDConstants.getStringProperty(parameters, MODELID, null); + + simulationId = processId; + + if(modelId==null) + throw new Exception("Model Id or simulation Id not provided in request parameters."); + + simulationDir = new File(configManager.getConfigurationProperty(GridAppsDConstants.GRIDAPPSD_TEMP_PATH),"models/"+modelId); + + parameters.put("i_fraction", GridAppsDConstants.getDoubleProperty(parameters, IFRACTION, 0)); + parameters.put("z_fraction", GridAppsDConstants.getDoubleProperty(parameters, ZFRACTION, 0)); + parameters.put("p_fraction", GridAppsDConstants.getDoubleProperty(parameters, PFRACTION, 0)); + parameters.put("load_scaling_factor", GridAppsDConstants.getDoubleProperty(parameters, LOADSCALINGFACTOR, 1)); + parameters.put("schedule_name", GridAppsDConstants.getStringProperty(parameters, SCHEDULENAME, "")); + parameters.put("model_id", modelId); + parameters.put("directory",simulationDir); + + } + + + File commandFile = new File(simulationDir,"opendsscmdInput.txt"); + File dssBaseFile = new File(simulationDir,"model_base.dss"); + + for(Object key: parameters.keySet().toArray()){ + log.debug(key.toString() + " = "+ parameters.getProperty(key.toString())); + } + + logManager.debug(ProcessStatus.RUNNING, simulationId, "Generating DSS base file"); + + //Create DSS base file + PrintWriter basePrintWriter = new PrintWriter(new StringWriter()); + DSSAllConfigurationHandler baseConfigurationHandler = new DSSAllConfigurationHandler(logManager,simulationManager,configManager); + baseConfigurationHandler.generateConfig(parameters, basePrintWriter, simulationId, username); + + if(!dssBaseFile.exists()) + throw new Exception("Error: Could not create DSS base file to export Vnom matrix"); + + logManager.debug(ProcessStatus.RUNNING, simulationId,"Finished generating DSS base file"); + + logManager.debug(ProcessStatus.RUNNING, simulationId,"Generating commands file for opendsscmd"); + + //Create file with commands for opendsscmd + PrintWriter fileWriter = new PrintWriter(commandFile); + fileWriter.println("redirect model_base.dss"); + // transformer winding ratios must be consistent with base voltages for state estimation + // regulators should be at tap 0; in case LDC is active, we can not use a no-load solution + fileWriter.println("batchedit transformer..* wdg=2 tap=1"); + fileWriter.println("batchedit regcontrol..* enabled=false"); + // remove isource injections from the Y matrix + fileWriter.println("batchedit isource..* enabled=false"); + // ensure that the voltage source is set to 1.0 per-unit + fileWriter.println("batchedit vsource..* pu=1.0"); + // remove PC elements from the Y matrix on solve + fileWriter.println("batchedit load..* enabled=false"); + fileWriter.println("batchedit generator..* enabled=false"); + fileWriter.println("batchedit pvsystem..* enabled=false"); + fileWriter.println("batchedit storage..* enabled=false"); + fileWriter.println("batchedit capacitor..* enabled=false"); + // solve the system in unloaded condition with regulator taps locked + fileWriter.println("solve"); + fileWriter.println("export voltages base_voltages.csv"); + fileWriter.flush(); + fileWriter.close(); + + logManager.debug(ProcessStatus.RUNNING, simulationId, "Finished generating commands file for opendsscmd"); + + logManager.debug(ProcessStatus.RUNNING, simulationId, "Generating Y Bus matrix"); + + ProcessBuilder processServiceBuilder = new ProcessBuilder(); + processServiceBuilder.directory(simulationDir); + List commands = new ArrayList(); + commands.add("opendsscmd"); + commands.add(commandFile.getName()); + + processServiceBuilder.command(new ArrayList<>(Arrays.asList("opendsscmd", commandFile.getName()))); + processServiceBuilder.redirectErrorStream(true); + processServiceBuilder.redirectOutput(); + Process process = processServiceBuilder.start(); + process.waitFor(); + + + YBusExportResponse response = new YBusExportResponse(); + + File vnomPath = new File(simulationDir.getAbsolutePath()+File.separator+"base_voltages.csv"); + + response.setVnom(Files.readAllLines(Paths.get(vnomPath.getPath()))); + + logManager.debug(ProcessStatus.RUNNING, simulationId, "Finished generating Vnom export"); + + out.print(response); + + + } + + + +}*/ diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/YBusExportConfigurationHandler.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/YBusExportConfigurationHandler.java index cea131af9..f35f2d7fd 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/YBusExportConfigurationHandler.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/configuration/YBusExportConfigurationHandler.java @@ -37,7 +37,7 @@ * 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; +/*package gov.pnnl.goss.gridappsd.configuration; import java.io.File; import java.io.PrintWriter; @@ -254,4 +254,4 @@ public void generateConfig(Properties parameters, PrintWriter out, String proces } -} +}*/ diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/data/BGPowergridModelDataManagerImpl.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/data/BGPowergridModelDataManagerImpl.java index 43c4a5e12..27fba4428 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/data/BGPowergridModelDataManagerImpl.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/data/BGPowergridModelDataManagerImpl.java @@ -46,6 +46,7 @@ import gov.pnnl.goss.gridappsd.api.LogManager; import gov.pnnl.goss.gridappsd.api.PowergridModelDataManager; import gov.pnnl.goss.gridappsd.data.handlers.BlazegraphQueryHandler; +import gov.pnnl.goss.gridappsd.log.LogManagerImpl; import gov.pnnl.goss.gridappsd.utils.GridAppsDConstants; import pnnl.goss.core.ClientFactory; @@ -54,6 +55,7 @@ public class BGPowergridModelDataManagerImpl implements PowergridModelDataManage final String nsCIM = "http://iec.ch/TC57/CIM100#"; final String nsRDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; final String nsXSD = "http://www.w3.org/2001/XMLSchema#"; + final String feederProperty = "http://iec.ch/TC57/CIM100#Feeder.NormalEnergizingSubstation"; final String RDF_TYPE = nsRDF+"type"; final String RDF_RESOURCE = "rdf:resource"; final String RDF_ID = "rdf:ID"; @@ -133,10 +135,11 @@ public static void main(String[] args){ // " ?pxf c:IdentifiedObject.name ?key"+ // "} GROUP BY ?key ORDER BY ?key"; // BGPowergridModelDataManagerImpl bg = new BGPowergridModelDataManagerImpl("http://localhost:9999/blazegraph/namespace/kb/sparql"); -// BGPowergridModelDataManagerImpl bg = new BGPowergridModelDataManagerImpl("http://192.168.99.100:8889/bigdata/namespace/kb/sparql"); - BGPowergridModelDataManagerImpl bg = new BGPowergridModelDataManagerImpl("http://localhost:8889/bigdata/namespace/kb/sparql"); +// BGPowergridModelDataManagerImpl bg = new BGPowergridModelDataManagerImpl("http://192.168.99.100:8889/bigdata/namespace/kb/sparql"); + BGPowergridModelDataManagerImpl bg = new BGPowergridModelDataManagerImpl("urn:uuid"); + bg.logManager = new LogManagerImpl(); - bg.endpointNSURL = "http://localhost:8889/bigdata/namespace/kb/sparql"; + bg.endpointNSURL = "urn:uuid"; try { // String query = "select ?s ?p ?o where {?s r:type c:ConnectivityNode. ?s ?p ?o}"; // System.out.println(bg.query("ieee13", query, "JSON")); @@ -145,8 +148,9 @@ public static void main(String[] args){ // System.out.println(bg.queryObjectTypes("_4F76A5F9-271D-9EB8-5E31-AA362D86F2C3", "JSON", "12345", "user")); System.out.println(bg.queryModelNameList("12345", "user")); long start = new Date().getTime(); - String model = bg.queryModel("_4F76A5F9-271D-9EB8-5E31-AA362D86F2C3", "", "", "XML", "12345", "user"); -// String model = bg.queryModel("_503D6E20-F499-4CC7-8051-971E23D0BF79", "", "", "XML", "12345", "user"); + String model = bg.queryModel("5B816B93-7A5F-B64C-8460-47C17D6E4B0F", "", "", "XML", "12345", "user"); +// String model = bg.queryModel("4F76A5F9-271D-9EB8-5E31-AA362D86F2C3", "", "", "XML", "12345", "user"); +// String model = bg.queryModel("503D6E20-F499-4CC7-8051-971E23D0BF79", "", "", "XML", "12345", "user"); FileOutputStream fout = new FileOutputStream(new File("xml_new_full.xml")); @@ -159,23 +163,23 @@ public static void main(String[] args){ // System.out.println(bg.queryModelNames("XML")); // System.out.println(bg.queryModelNamesAndIds("XML", "12345", "user")); -// System.out.println(bg.queryObjectIds("JSON", "_4F76A5F9-271D-9EB8-5E31-AA362D86F2C3", "LoadBreakSwitch", "12345", "user")); +// System.out.println(bg.queryObjectIds("JSON", "4F76A5F9-271D-9EB8-5E31-AA362D86F2C3", "LoadBreakSwitch", "12345", "user")); //test with both object id and type -// System.out.println(bg.queryObjectDictByType("JSON", "_C1C3E687-6FFD-C753-582B-632A27E28507", "LinearShuntCompensator", "_EF2FF8C1-A6A6-4771-ADDD-A371AD929D5B", "12345", "user")); //ieee123 +// System.out.println(bg.queryObjectDictByType("JSON", "C1C3E687-6FFD-C753-582B-632A27E28507", "LinearShuntCompensator", "_EF2FF8C1-A6A6-4771-ADDD-A371AD929D5B", "12345", "user")); //ieee123 //test with only object id -// System.out.println(bg.queryObjectDictByType("JSON", "_C1C3E687-6FFD-C753-582B-632A27E28507", null, "_EF2FF8C1-A6A6-4771-ADDD-A371AD929D5B", "12345", "user")); //ieee123 +// System.out.println(bg.queryObjectDictByType("JSON", "C1C3E687-6FFD-C753-582B-632A27E28507", null, "_EF2FF8C1-A6A6-4771-ADDD-A371AD929D5B", "12345", "user")); //ieee123 //test with only object type -// System.out.println(bg.queryObjectDictByType("JSON", "_C1C3E687-6FFD-C753-582B-632A27E28507", "LinearShuntCompensator", null, "12345", "user")); //ieee123 +// System.out.println(bg.queryObjectDictByType("JSON", "C1C3E687-6FFD-C753-582B-632A27E28507", "LinearShuntCompensator", null, "12345", "user")); //ieee123 //test with neither object or type, should fail // try{ -// System.out.println(bg.queryObjectDictByType("JSON", "_C1C3E687-6FFD-C753-582B-632A27E28507", null, null, "12345", "user")); //ieee123 +// System.out.println(bg.queryObjectDictByType("JSON", "C1C3E687-6FFD-C753-582B-632A27E28507", null, null, "12345", "user")); //ieee123 // }catch (Exception e) { // System.out.println("Expected error "+e.getMessage()); // // TODO: handle exception // } - // System.out.println(bg.queryObjectDictByType("JSON", "_4F76A5F9-271D-9EB8-5E31-AA362D86F2C3", "LinearShuntCompensator", null, "12345", "user")); //ieee8500 -// System.out.println(bg.queryMeasurementDictByObject("JSON", "_4F76A5F9-271D-9EB8-5E31-AA362D86F2C3", null, "_7A02B3B0-2746-EB24-45A5-C3FBA8ACB88E", "12345", "user")); -// System.out.println(bg.queryMeasurementDictByObject("JSON", "_4F76A5F9-271D-9EB8-5E31-AA362D86F2C3", "LinearShuntCompensator", null, "12345", "user")); + // System.out.println(bg.queryObjectDictByType("JSON", "4F76A5F9-271D-9EB8-5E31-AA362D86F2C3", "LinearShuntCompensator", null, "12345", "user")); //ieee8500 +// System.out.println(bg.queryMeasurementDictByObject("JSON", "4F76A5F9-271D-9EB8-5E31-AA362D86F2C3", null, "_7A02B3B0-2746-EB24-45A5-C3FBA8ACB88E", "12345", "user")); +// System.out.println(bg.queryMeasurementDictByObject("JSON", "4F76A5F9-271D-9EB8-5E31-AA362D86F2C3", "LinearShuntCompensator", null, "12345", "user")); // System.out.println } catch (Exception e) { @@ -287,10 +291,29 @@ public List queryObjectTypeList(String modelId, String processId, String @Override public String queryModel(String modelId, String objectType, String filter, String resultFormat, String processId, String username) throws Exception { String result = null; - ResultSet rs = queryModelResultSet(modelId, objectType, filter, processId, username, true); + HashSet alreadySeen = new HashSet(); Queue newIds = new PriorityQueue(); List results = new ArrayList(); + BlazegraphQueryHandler queryHandler = new BlazegraphQueryHandler(getEndpointURL(modelId), logManager, processId, username); + String baseUrl = getEndpointNS(null); + + //Add initial ids of incoming links + String intitialIdQuery = "CONSTRUCT {?s ?p ?o} WHERE { { ?s ?p ?o . VALUES ?o { <"+getEndpointNS(modelId)+"> }}}"; + newIds.add(getEndpointNS(modelId)); + ResultSet rs = queryHandler.construct(intitialIdQuery); + while(rs.hasNext()){ + QuerySolution qs = rs.nextSolution(); + String subjectUri = qs.getResource(SUBJECT).getURI(); + String propertyName = qs.getResource(PREDICATE).getURI(); + if (!alreadySeen.contains(subjectUri) && !newIds.contains(subjectUri) && !RDF_TYPE.equals(propertyName) && subjectUri.startsWith(baseUrl)){ + newIds.add(subjectUri); + + + } + } + +// rs = queryModelResultSet(modelId, objectType, filter, processId, username, true); //Tracks which subjects have been seen already and follows links to pull information on those that haven't been included yet while(rs.hasNext() || newIds.size()>0){ @@ -307,7 +330,7 @@ public String queryModel(String modelId, String objectType, String filter, Strin } else { Resource resource = qs.getResource(OBJECT); value = resource.toString(); - if(!alreadySeen.contains(value) && !newIds.contains(value)){ + if(!alreadySeen.contains(value) && !newIds.contains(value) && value.startsWith(baseUrl) && !feederProperty.equals(propertyName)){ newIds.add(value); } } @@ -320,23 +343,40 @@ public String queryModel(String modelId, String objectType, String filter, Strin BGResult r = new BGResult(subject, propertyName, value); results.add(r); } + if(newIds.size()>0){ //build query with new ids - String newIdQuery = "CONSTRUCT {?s ?p ?o} WHERE { "; - + String newOutgoingIdQuery = "CONSTRUCT {?s ?p ?o} WHERE { "; + String newIncomingIdQuery = "CONSTRUCT {?s ?p ?o} WHERE { "; for(int i=0;i<100 && newIds.size()>0; i++){ String id = newIds.poll(); - newIdQuery = newIdQuery+"{ ?s ?p ?o . VALUES ?s { <"+id+"> }} UNION"; + + newOutgoingIdQuery = newOutgoingIdQuery+"{ ?s ?p ?o . VALUES ?s { <"+id+"> }} UNION"; + newIncomingIdQuery = newIncomingIdQuery+"{ ?s ?p ?o . VALUES ?o { <"+id+"> }} UNION"; if(!alreadySeen.contains(id)) { alreadySeen.add(id); } } - newIdQuery = newIdQuery.substring(0,newIdQuery.length()-6); - newIdQuery = newIdQuery+" }"; + newOutgoingIdQuery = newOutgoingIdQuery.substring(0,newOutgoingIdQuery.length()-6); + newOutgoingIdQuery = newOutgoingIdQuery+" }"; + newIncomingIdQuery = newIncomingIdQuery.substring(0,newIncomingIdQuery.length()-6); + newIncomingIdQuery = newIncomingIdQuery+" }"; + + //Get ids for the incoming links + rs = queryHandler.construct(newIncomingIdQuery); + while(rs.hasNext()){ + QuerySolution qs = rs.nextSolution(); + String subjectUri = qs.getResource(SUBJECT).getURI(); + String propertyName = qs.getResource(PREDICATE).getURI(); - BlazegraphQueryHandler queryHandler = new BlazegraphQueryHandler(getEndpointURL(modelId), logManager, processId, username); - rs = queryHandler.construct(newIdQuery); + if (!alreadySeen.contains(subjectUri) && !newIds.contains(subjectUri) && !RDF_TYPE.equals(propertyName) && !feederProperty.equals(propertyName) && subjectUri.startsWith(baseUrl)){ + newIds.add(subjectUri); + } + } + + + rs = queryHandler.construct(newOutgoingIdQuery); @@ -693,7 +733,12 @@ protected String resultSetToJson(ResultSet rs){ HashMap resultObjects = new HashMap(); while( rs.hasNext()) { QuerySolution qs = rs.nextSolution(); - String subject = qs.getResource(SUBJECT).getLocalName(); + String subject = qs.getResource(SUBJECT).toString(); + if(!subject.contains("urn:uuid")){ + subject = qs.getResource(SUBJECT).getLocalName(); + } else { + subject = subject.substring(subject.lastIndexOf(':')+1); + } JsonObject obj = new JsonObject(); if(resultObjects.containsKey(subject)){ obj = resultObjects.get(subject); @@ -938,7 +983,7 @@ public void putModel(String modelId, String model, String inputFormat, String pr private String getEndpointNS(String modelId){ if(modelId!=null) { - return endpointNSURL+"#"+modelId; + return endpointNSURL+modelId; } return endpointNSURL; } diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/data/ProvenTimeSeriesDataManagerImpl.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/data/ProvenTimeSeriesDataManagerImpl.java index a5bcc2a65..623f43695 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/data/ProvenTimeSeriesDataManagerImpl.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/data/ProvenTimeSeriesDataManagerImpl.java @@ -13,6 +13,9 @@ import org.apache.http.auth.UsernamePasswordCredentials; import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import gov.pnnl.goss.gridappsd.api.AppManager; import gov.pnnl.goss.gridappsd.api.ConfigurationManager; @@ -25,6 +28,8 @@ import gov.pnnl.goss.gridappsd.data.conversion.DataFormatConverter; import gov.pnnl.goss.gridappsd.dto.LogMessage.ProcessStatus; import gov.pnnl.goss.gridappsd.dto.RequestTimeseriesData; +import gov.pnnl.goss.gridappsd.dto.RequestTimeseriesDataAdvanced; +import gov.pnnl.goss.gridappsd.dto.RequestTimeseriesDataBasic; import gov.pnnl.goss.gridappsd.dto.SimulationContext; import gov.pnnl.goss.gridappsd.dto.TimeSeriesEntryResult; import gov.pnnl.goss.gridappsd.utils.GridAppsDConstants; @@ -73,6 +78,7 @@ public class ProvenTimeSeriesDataManagerImpl implements TimeseriesDataManager, D Gson gson = new Gson(); String provenUri = null; String provenQueryUri = null; + String provenAdvancedQueryUri = null; String provenWriteUri = null; ProvenProducer provenQueryProducer = new ProvenProducer(); @@ -90,9 +96,16 @@ public void start(){ provenUri = configManager.getConfigurationProperty(GridAppsDConstants.PROVEN_PATH); provenWriteUri = configManager.getConfigurationProperty(GridAppsDConstants.PROVEN_WRITE_PATH); provenQueryUri = configManager.getConfigurationProperty(GridAppsDConstants.PROVEN_QUERY_PATH); + provenAdvancedQueryUri = configManager.getConfigurationProperty(GridAppsDConstants.PROVEN_ADVANCED_QUERY_PATH); provenQueryProducer.restProducer(provenQueryUri, null, null); provenWriteProducer.restProducer(provenWriteUri, null, null); + try { + this.subscribeAndStoreDataFromTopic("/topic/goss.gridappsd.*.output", null, null, null); + } catch (Exception e) { + e.printStackTrace(); + } + } @@ -106,7 +119,20 @@ public Serializable handle(Serializable requestContent, String processId, return query((RequestTimeseriesData)requestContent); } else if(requestContent instanceof String){ - RequestTimeseriesData timeSeriesRequest = RequestTimeseriesData.parse((String)requestContent); + //First try to parse the query as the new format, if that fails try the old + RequestTimeseriesData timeSeriesRequest; + try{ + timeSeriesRequest = RequestTimeseriesDataAdvanced.parse((String)requestContent); + }catch (Exception e) { + // TODO: handle exception + try{ + timeSeriesRequest = RequestTimeseriesDataBasic.parse((String)requestContent); + }catch (Exception e2) { + throw new Exception("Failed to parse time series data request"); + } + } + + return query(timeSeriesRequest); } @@ -116,9 +142,17 @@ else if(requestContent instanceof String){ @Override public Serializable query(RequestTimeseriesData requestTimeseriesData) throws Exception { - provenQueryProducer.restProducer(provenQueryUri, null, null); - provenQueryProducer.setMessageInfo("GridAPPSD", "QUERY", this.getClass().getSimpleName(), keywords); - ProvenResponse response = provenQueryProducer.sendMessage(requestTimeseriesData.toString(), requestId); + ProvenResponse response = null; + + if(requestTimeseriesData instanceof RequestTimeseriesDataAdvanced){ + provenQueryProducer.restProducer(provenAdvancedQueryUri, null, null); + provenQueryProducer.setMessageInfo("GridAPPSD", "QUERY", this.getClass().getSimpleName(), keywords); + response = provenQueryProducer.getAdvancedTsQuery(requestTimeseriesData.toString(), requestId); + }else { + provenQueryProducer.restProducer(provenQueryUri, null, null); + provenQueryProducer.setMessageInfo("GridAPPSD", "QUERY", this.getClass().getSimpleName(), keywords); + response = provenQueryProducer.sendMessage(requestTimeseriesData.toString(), requestId); + } TimeSeriesEntryResult result = TimeSeriesEntryResult.parse(response.data.toString()); if(result.getData().size()==0) return null; @@ -171,9 +205,28 @@ private void subscribeAndStoreDataFromTopic(String topic, String appOrServiceid, inputClient.subscribe(topic, new GossResponseEvent() { @Override public void onMessage(Serializable message) { - DataResponse event = (DataResponse)message; - try{ - provenWriteProducer.sendBulkMessage(event.getData().toString(), appOrServiceid, instanceId, simulationId, new Date().getTime()); + DataResponse event = (DataResponse)message; + for(String str : event.getDestination().split(".")){ + System.out.println(str); + } + //String appOrServiceid = event.getDestination().split("[.]")[2]; + try{ + //TODO: Remove if block once changes made in proven cluster to get measurement name from datatype + if(appOrServiceid==null){ + JsonParser parser = new JsonParser(); + JsonElement data = parser.parse(event.getData().toString()); + if (data.isJsonObject()) { + JsonObject dataObj = data.getAsJsonObject(); + if(dataObj.get("datatype")!=null){ + String datatype = dataObj.get("datatype").getAsString(); + if(datatype!=null) + provenWriteProducer.sendBulkMessage(event.getData().toString(), datatype, instanceId, simulationId, new Date().getTime()); + } + } + } + else{ + provenWriteProducer.sendBulkMessage(event.getData().toString(), appOrServiceid, instanceId, simulationId, new Date().getTime()); + } }catch(Exception e){ StringWriter sw = new StringWriter(); diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/data/handlers/CIMDataRDFToGLM.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/data/handlers/CIMDataRDFToGLM.java index 0d14e284c..8943e1ceb 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/data/handlers/CIMDataRDFToGLM.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/data/handlers/CIMDataRDFToGLM.java @@ -1100,7 +1100,7 @@ static String GetRegulatorData (Model mdl, Resource rXf, String name, String xfG } buf.append ("}\n"); - buf.append ("object regulator {\n name \"reg_" + name + "\";\n"); + buf.append ("object regulator {\n name \"xf_" + name + "\";\n"); buf.append (" from \"" + bus1 + "\";\n"); buf.append (" to \"" + bus2 + "\";\n"); buf.append (" phases " + phs + ";\n"); diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/distributed/FieldBusManagerImpl.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/distributed/FieldBusManagerImpl.java new file mode 100644 index 000000000..81a1f4d0d --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/distributed/FieldBusManagerImpl.java @@ -0,0 +1,363 @@ +package gov.pnnl.goss.gridappsd.distributed; + +import java.io.FileReader; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.felix.dm.annotation.api.Component; +import org.apache.felix.dm.annotation.api.ConfigurationDependency; +import org.apache.felix.dm.annotation.api.ServiceDependency; +import org.apache.felix.dm.annotation.api.Start; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.UsernamePasswordCredentials; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import gov.pnnl.goss.gridappsd.api.FieldBusManager; +import gov.pnnl.goss.gridappsd.api.LogManager; +import gov.pnnl.goss.gridappsd.api.ServiceManager; +import gov.pnnl.goss.gridappsd.dto.LogMessage.ProcessStatus; +import gov.pnnl.goss.gridappsd.dto.ServiceInfo; +import gov.pnnl.goss.gridappsd.dto.field.FieldObject; +import gov.pnnl.goss.gridappsd.dto.field.NormalEnergizedFeeder; +import gov.pnnl.goss.gridappsd.dto.field.RequestField; +import gov.pnnl.goss.gridappsd.dto.field.Root; +import gov.pnnl.goss.gridappsd.dto.field.SecondaryArea; +import gov.pnnl.goss.gridappsd.dto.field.Substation; +import gov.pnnl.goss.gridappsd.dto.field.SwitchArea; +import gov.pnnl.goss.gridappsd.utils.GridAppsDConstants; +import pnnl.goss.core.Client; +import pnnl.goss.core.Client.PROTOCOL; +import pnnl.goss.core.ClientFactory; +import pnnl.goss.core.DataResponse; +import pnnl.goss.core.GossResponseEvent; +import pnnl.goss.core.Request.RESPONSE_FORMAT; +import pnnl.goss.core.security.SecurityConfig; + +@Component +public class FieldBusManagerImpl implements FieldBusManager { + + private static final String CONFIG_PID = "pnnl.goss.gridappsd"; + private Dictionary configurationProperties; + + String topology_reponse; + String topicPrefix = "goss.gridappsd.process.request.field"; + + @ServiceDependency + ClientFactory clientFactory; + + @ServiceDependency + private volatile ServiceManager serviceManager; + + @ServiceDependency + private volatile LogManager logManager; + + private volatile TopologyRequestProcess topology; + + @ServiceDependency + SecurityConfig securityConfig; + + Client client; + + Map> messageBus_measIds_map = new HashMap>(); + //Map measId_messageBus_map = new HashMap(); + + String fieldModelId = null; + + // FileWriter writer = null; + + public FieldBusManagerImpl() { + System.out.println("Starting FieldBusManager"); + } + + @Start + public void start() { + + try { + + Credentials credentials = new UsernamePasswordCredentials(securityConfig.getManagerUser(), + securityConfig.getManagerPassword()); + client = clientFactory.create(PROTOCOL.STOMP, credentials, true); + + ServiceInfo serviceInfo = serviceManager.getService("gridappsd-topology-background-service"); + if (serviceInfo == null) { + logManager.warn(ProcessStatus.RUNNING, null, + "Topology deamon service is not available. Stopping FieldBusManager."); + return; + } + + fieldModelId = getFieldModelMrid(); + if (fieldModelId == null) { + logManager.warn(ProcessStatus.RUNNING, null, + "Field model mrid is not available. Stopping FieldBusManager. " + + "Check conf/pnnl.goss.gridappsd.cfg file and add field.model.mrid key with value of deployed field model mrid. "); + return; + } + + topology = new TopologyRequestProcess(fieldModelId, client); + topology.start(); + + this.publishDeviceOutput(); + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + @Override + public Serializable handleRequest(String request_queue, Serializable request) { + + RequestField requestField = RequestField.parse(request.toString()); + + if (requestField.request_type.equals("get_context")) { + + if (requestField.areaId == null) + return topology.root.DistributionArea; + else{ + for (Substation substation : topology.root.DistributionArea.Substations){ + if (requestField.areaId.equalsIgnoreCase(substation.id)) + return substation; + + for(NormalEnergizedFeeder feeder : substation.NormalEnergizedFeeder){ + if (requestField.areaId.equalsIgnoreCase(feeder.id)) + return feeder.FeederArea; + + for(SwitchArea switchArea : feeder.FeederArea.SwitchAreas){ + if (requestField.areaId.equalsIgnoreCase(switchArea.id)) + return switchArea; + + for(SecondaryArea secondaryArea : switchArea.SecondaryAreas){ + if (requestField.areaId.equalsIgnoreCase(secondaryArea.id)) + return secondaryArea; + } + } + } + } + } + } + else if (requestField.request_type.equals("is_initilized")) { + + JsonObject obj = new JsonObject(); + + try { + if (topology.root.DistributionArea != null){ + obj.addProperty("initialized",true); + } + else{ + obj.addProperty("initialized",false); + } + }catch(NullPointerException e){ + obj.addProperty("initialized",false); + return obj.toString(); + } + + return obj.toString(); + } + else if(requestField.request_type.equals("start_publishing")){ + + for (Substation substation : topology.root.DistributionArea.Substations){ + String topic = "goss.gridappsd.field."+(substation.id).trim().toUpperCase(); + client.publish(topic, requestField.toString()); + } + + return "Publishing Started"; + } + + return null; + } + + public void publishDeviceOutput() { + + client.subscribe(GridAppsDConstants.topic_simulationOutput + ".>", new GossResponseEvent() { + + @Override + public void onMessage(Serializable response) { + + DataResponse event = (DataResponse) response; + String simulationId = event.getDestination().substring(event.getDestination().lastIndexOf(".") + 1, + event.getDestination().length()); + String simOutputStr = event.getData().toString(); + JsonObject simOutputJsonObj = null; + + JsonParser parser = new JsonParser(); + JsonElement simOutputObject = parser.parse(simOutputStr); + + if (simOutputObject.isJsonObject()) { + simOutputJsonObj = simOutputObject.getAsJsonObject(); + } + + JsonObject tempObj = simOutputJsonObj.getAsJsonObject("message"); + Map expectedOutputMap = tempObj.getAsJsonObject("Measurements").entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue())); + + try { + + for (String measurementMrid : expectedOutputMap.keySet()) { + + String messageBusId = null; + if (topology.measId_messageBus_map.get(measurementMrid) != null) { + messageBusId = "goss.gridappsd.field.simulation.output." + simulationId + "." + + topology.measId_messageBus_map.get(measurementMrid); + } else { + messageBusId = "goss.gridappsd.field.simulation.output." + simulationId + "." + + topology.root.DistributionArea.Substations.get(0).NormalEnergizedFeeder.get(0).id; + } + + JsonObject obj = new JsonObject(); + obj.add(measurementMrid, expectedOutputMap.get(measurementMrid)); + + client.publish(messageBusId, obj.toString()); + + } + + } catch (Exception e1) { + e1.printStackTrace(); + } + + + } + + }); + + } + + @ConfigurationDependency(pid = CONFIG_PID) + public synchronized void updated(Dictionary config) { + this.configurationProperties = config; + } + + public String getFieldModelMrid() { + if (this.configurationProperties != null) { + Object value = this.configurationProperties.get("field.model.mrid"); + if (value != null) + return value.toString(); + } + return null; + } + +} + +class TopologyRequest implements Serializable { + + private static final long serialVersionUID = 4279262793871885409L; + + String requestType = "GET_DISTRIBUTED_AREAS"; + String mRID = null; + String resultFormat = "JSON"; + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + +} + +class TopologyRequestProcess extends Thread { + + String fieldModelMrid; + Client client; + Root root = null; + Map> messageBus_measIds_map = new HashMap>(); + Map measId_messageBus_map = new HashMap(); + + public TopologyRequestProcess(String fieldModelMrid, Client client) { + this.fieldModelMrid = fieldModelMrid; + this.client = client; + } + + @Override + public void run() { + try { + + String topologyRequestTopic = "goss.gridappsd.request.data.cimtopology"; + Gson gson = new Gson(); + TopologyRequest request = new TopologyRequest(); + request.mRID = fieldModelMrid; + + Serializable topoResponse = client.getResponse(request.toString(), topologyRequestTopic, + RESPONSE_FORMAT.JSON); + int attempt = 1; + if (topoResponse == null && attempt < 6) { + // May have to wait for Topology processor to initialize + topoResponse = client.getResponse(request.toString(), topologyRequestTopic, + RESPONSE_FORMAT.JSON); + Thread.sleep(1000); + attempt++; + } + if (topoResponse != null && (topoResponse instanceof DataResponse)) { + String str = ((DataResponse) topoResponse).getData().toString(); + root = gson.fromJson(str, Root.class); + } else { + root = gson.fromJson(topoResponse.toString(), Root.class); + } + + /* + * feederList = root.feeders; if(root == null || feederList == null + * || feederList.size() == 0){ throw new + * Exception("No Feeder available to create field message bus"); } + */ + + //NormalEnergizedFeeder feeder = root.DistributionArea.Substations.get(0).NormalEnergizedFeeder.get(0); + + + /*feeder.message_bus_id = feeder.id; + + int switch_area_index = 0; + for (SwitchArea switchArea : feeder.FeederArea.SwitchAreas) { + switchArea.message_bus_id = feeder.id + "." + switch_area_index; + int secondary_area_index = 0; + for (SecondaryArea secondaryArea : switchArea.SecondaryAreas) { + secondaryArea.message_bus_id = feeder.id + "." + switch_area_index + "." + + secondary_area_index; + secondary_area_index++; + } + switch_area_index++; + }*/ + + this.getFieldMeasurementIds(fieldModelMrid); + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + public void getFieldMeasurementIds(String fieldModelMrid) { + + try{ + for (Substation substation : root.DistributionArea.Substations){ + + for(NormalEnergizedFeeder feeder : substation.NormalEnergizedFeeder){ + messageBus_measIds_map.put(feeder.id, feeder.FeederArea.Measurements); + + for(SwitchArea switchArea : feeder.FeederArea.SwitchAreas){ + messageBus_measIds_map.put(switchArea.id, switchArea.Measurements); + + for(SecondaryArea secondaryArea : switchArea.SecondaryAreas){ + messageBus_measIds_map.put(secondaryArea.id, secondaryArea.Measurements); + } + } + } + } + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/ModelCreationConfig.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/ModelCreationConfig.java index 7e8428da8..fd22b29c8 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/ModelCreationConfig.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/ModelCreationConfig.java @@ -64,6 +64,7 @@ public class ModelCreationConfig implements Serializable{ public boolean randomize_zipload_fractions = false; // should randomize the zipload fraction values (eg. z, i, p_fractions) public boolean use_houses = false; public ModelState model_state; + public String separated_loads_file; // option xslx file containing loads names that will be modeled separate from the main powerflow simulator. @@ -159,6 +160,12 @@ public ModelState getModel_state() { public void setModel_state(ModelState model_state) { this.model_state = model_state; } + public String getSeparateLoadsFile() { + return separated_loads_file; + } + public void setSeparateLoadsFile(String fileName) { + this.separated_loads_file = fileName; + } public static ModelCreationConfig parse(String jsonString){ Gson gson = new Gson(); diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/PlatformStatus.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/PlatformStatus.java index 4643313fc..e77b0ee84 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/PlatformStatus.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/PlatformStatus.java @@ -11,6 +11,7 @@ public class PlatformStatus implements Serializable{ List services; List appInstances; List serviceInstances; + String fieldModelMrid; public PlatformStatus() {} @@ -50,5 +51,9 @@ public List getServiceInstances() { public void setServiceInstances(List serviceInstances) { this.serviceInstances = serviceInstances; } + public void setField(String fieldModelMrid) { + this.fieldModelMrid = fieldModelMrid; + + } } diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/PowerSystemConfig.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/PowerSystemConfig.java index ae9816252..d57726fdb 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/PowerSystemConfig.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/PowerSystemConfig.java @@ -44,8 +44,10 @@ import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; -// TODO change to be a dto rather than full implementation of getters and setters. public class PowerSystemConfig implements Serializable { + + private static final long serialVersionUID = 1L; + public PowerSystemConfig(){ } public PowerSystemConfig(String GeographicalRegion_name, @@ -61,6 +63,8 @@ public PowerSystemConfig(String GeographicalRegion_name, public String GeographicalRegion_name; public String Line_name; + + public SimulatorConfig simulator_config; public String getSubGeographicalRegion_name() { return SubGeographicalRegion_name; @@ -92,6 +96,13 @@ public String toString() { return gson.toJson(this); } + public SimulatorConfig getSimulator_config() { + return simulator_config; + } + + public void setSimulator_config(SimulatorConfig simulator_config) { + this.simulator_config = simulator_config; + } public static PowerSystemConfig parse(String jsonString){ Gson gson = new Gson(); diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestPlatformStatus.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestPlatformStatus.java index 55d68ea47..6a1e292f8 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestPlatformStatus.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestPlatformStatus.java @@ -12,6 +12,7 @@ public class RequestPlatformStatus implements Serializable { boolean services = false; boolean appInstances = false; boolean serviceInstances = false; + boolean field = false; public boolean isApplications() { return applications; @@ -37,15 +38,22 @@ public boolean isServiceInstances() { public void setServiceInstances(boolean serviceInstances) { this.serviceInstances = serviceInstances; } + public boolean isField() { + return field; + } + public void setField(boolean field) { + this.field = field; + } public static RequestPlatformStatus parse(String jsonString){ Gson gson = new Gson(); RequestPlatformStatus obj = gson.fromJson(jsonString, RequestPlatformStatus.class); - if(!obj.appInstances & !obj.services & !obj.applications & !obj.serviceInstances){ + if(!obj.appInstances & !obj.services & !obj.applications & !obj.serviceInstances & !obj.field){ obj.applications = true; obj.services = true; obj.appInstances = true; obj.serviceInstances = true; + obj.field = true; } return obj; } diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestSimulation.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestSimulation.java index 897da55f5..bc8e880bf 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestSimulation.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestSimulation.java @@ -45,6 +45,8 @@ import gov.pnnl.goss.gridappsd.dto.events.ScheduledCommandEvent; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import com.google.gson.Gson; @@ -59,7 +61,7 @@ public enum SimulationRequestType { NEW, PAUSE, RESUME, STOP } - public PowerSystemConfig power_system_config; + public List power_system_configs; public SimulationConfig simulation_config; @@ -77,17 +79,17 @@ public RequestSimulation(){ } - public RequestSimulation(PowerSystemConfig power_system_config, SimulationConfig simulation_config){ - this.power_system_config = power_system_config; + public RequestSimulation(List power_system_configs, SimulationConfig simulation_config){ + this.power_system_configs = power_system_configs; this.simulation_config = simulation_config; } - public PowerSystemConfig getPower_system_config() { - return power_system_config; + public List getPower_system_config() { + return power_system_configs; } - public void setPower_system_config(PowerSystemConfig power_system_config) { - this.power_system_config = power_system_config; + public void setPower_system_config(List power_system_configs) { + this.power_system_configs = power_system_configs; } public SimulationConfig getSimulation_config() { @@ -148,7 +150,7 @@ public static RequestSimulation parse(String jsonString){ gsonBuilder.setPrettyPrinting(); Gson gson = gsonBuilder.create(); RequestSimulation obj = gson.fromJson(jsonString, RequestSimulation.class); - if(obj.power_system_config==null) + if(obj.power_system_configs==null) throw new JsonSyntaxException("Expected attribute power_system_config not found"); if(obj.test_config!=null){ for(Event event : obj.getTest_config().getEvents()){ @@ -160,4 +162,6 @@ public static RequestSimulation parse(String jsonString){ } return obj; } -} + + } + diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestTimeseriesData.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestTimeseriesData.java index 93c0cf83c..8113855f0 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestTimeseriesData.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestTimeseriesData.java @@ -1,25 +1,15 @@ package gov.pnnl.goss.gridappsd.dto; -import java.io.IOException; - -//import gov.pnnl.goss.gridappsd.api.TimeseriesDataManager.ResultFormat; import java.io.Serializable; -import java.util.Map; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; -import com.google.gson.JsonSyntaxException; -public class RequestTimeseriesData implements Serializable { +public abstract class RequestTimeseriesData implements Serializable { private static final long serialVersionUID = -820277813503252519L; String queryMeasurement; - Map queryFilter; - //ResultFormat responseFormat = ResultFormat.JSON; String responseFormat ="JSON"; private String queryType = "time-series"; int simulationYear; @@ -33,13 +23,6 @@ public void setQueryMeasurement(String queryMeasurement) { this.queryMeasurement = queryMeasurement; } - public Map getQueryFilter() { - return queryFilter; - } - - public void setQueryFilter(Map queryFilter) { - this.queryFilter = queryFilter; - } public String getResponseFormat() { return responseFormat; @@ -64,6 +47,14 @@ public String getOriginalFormat() { public void setOriginalFormat(String originalFormat) { this.originalFormat = originalFormat; } + + public String getQueryType() { + return queryType; + } + + public void setQueryType(String queryType) { + this.queryType = queryType; + } @Override public String toString() { @@ -71,22 +62,6 @@ public String toString() { return gson.toJson(this); } - public static RequestTimeseriesData parse(String jsonString){ - ObjectMapper objectMapper = new ObjectMapper(); - RequestTimeseriesData obj = null; - try { - obj = objectMapper.readValue(jsonString, RequestTimeseriesData.class); - } catch (JsonParseException e) { - e.printStackTrace(); - } catch (JsonMappingException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - if(obj.queryMeasurement.equals("simulation")) - if(obj.queryFilter==null || !obj.queryFilter.containsKey("simulation_id")) - throw new JsonSyntaxException("Expected filter simulation_id not found."); - return obj; - } + } diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestTimeseriesDataAdvanced.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestTimeseriesDataAdvanced.java new file mode 100644 index 000000000..9f44f5923 --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestTimeseriesDataAdvanced.java @@ -0,0 +1,92 @@ +package gov.pnnl.goss.gridappsd.dto; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.exception.ExceptionUtils; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +public class RequestTimeseriesDataAdvanced extends RequestTimeseriesData { + + private static final long serialVersionUID = -820277813503252512L; + + List queryFilter = new ArrayList(); + + List selectCriteria = new ArrayList(); + Integer last; + Integer first; + + public List getQueryFilter() { + return queryFilter; + } + + public void setQueryFilter(List advancedQueryFilter) { + this.queryFilter = advancedQueryFilter; + } + + + + public List getSelectCriteria() { + return selectCriteria; + } + public void setSelectCriteria(List selectCriteria) { + this.selectCriteria = selectCriteria; + } + + + public Integer getLast() { + return last; + } + + public void setLast(Integer last) { + this.last = last; + } + + public Integer getFirst() { + return first; + } + + public void setFirst(Integer first) { + this.first = first; + } + + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + + public static RequestTimeseriesDataAdvanced parse(String jsonString){ + ObjectMapper objectMapper = new ObjectMapper(); + RequestTimeseriesDataAdvanced obj = null; + String error = ""; + try { + obj = objectMapper.readValue(jsonString, RequestTimeseriesDataAdvanced.class); + } catch (JsonParseException e) { + error = ExceptionUtils.getStackTrace(e); + } catch (JsonMappingException e) { + error = ExceptionUtils.getStackTrace(e); + } catch (IOException e) { + error = ExceptionUtils.getStackTrace(e); + } + if(obj==null){ + throw new JsonSyntaxException("Request time series data request could not be parsed: "+error); + } + +// if(obj!=null && obj.queryMeasurement.equals("simulation")){ + //if(obj.queryFilter==null || !obj.queryFilter.containsKey("simulation_id")) + // throw new JsonSyntaxException("Expected filter simulation_id not found."); + //TODO iterate through and look for key = simulation_id + return obj; + } + + + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestTimeseriesDataBasic.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestTimeseriesDataBasic.java new file mode 100644 index 000000000..497a09f86 --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/RequestTimeseriesDataBasic.java @@ -0,0 +1,57 @@ +package gov.pnnl.goss.gridappsd.dto; + +import java.io.IOException; +import java.util.Map; + +import org.apache.commons.lang3.exception.ExceptionUtils; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +public class RequestTimeseriesDataBasic extends RequestTimeseriesData { + + private static final long serialVersionUID = -820277813503252513L; + + Map queryFilter; + + public Map getQueryFilter() { + return queryFilter; + } + + public void setQueryFilter(Map queryFilter) { + this.queryFilter = queryFilter; + } + + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + + public static RequestTimeseriesDataBasic parse(String jsonString){ + ObjectMapper objectMapper = new ObjectMapper(); + RequestTimeseriesDataBasic obj = null; + String error = ""; + try { + obj = objectMapper.readValue(jsonString, RequestTimeseriesDataBasic.class); + } catch (JsonParseException e) { + error = ExceptionUtils.getStackTrace(e); + } catch (JsonMappingException e) { + error = ExceptionUtils.getStackTrace(e); + } catch (IOException e) { + error = ExceptionUtils.getStackTrace(e); + } + if(obj==null){ + throw new JsonSyntaxException("Request time series data request could not be parsed: "+error); + } +// if(obj!=null && obj.queryMeasurement.equals("simulation")) +// if(obj.queryFilter==null || !obj.queryFilter.containsKey("simulation_id")) +// throw new JsonSyntaxException("Expected filter simulation_id not found."); + return obj; + } + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/ServiceInfo.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/ServiceInfo.java index b6254d4e2..f9be190a7 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/ServiceInfo.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/ServiceInfo.java @@ -1,194 +1,208 @@ -/******************************************************************************* - * Copyright (c) 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.dto; - - -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.List; - -import com.google.gson.Gson; -import com.google.gson.JsonSyntaxException; - -public class ServiceInfo implements Serializable { - - public enum ServiceType { - PYTHON, JAVA, WEB, EXE - } - - - String id; - String description; - String creator; - List input_topics; - List output_topics; - List static_args; - String execution_path; - HashMap user_input; - ServiceType type; - boolean launch_on_startup; - List service_dependencies; - boolean multiple_instances; - List environmentVariables; - - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getCreator() { - return creator; - } - - public void setCreator(String creator) { - this.creator = creator; - } - - public List getInput_topics() { - return input_topics; - } - - public void setInput_topics(List input_topics) { - this.input_topics = input_topics; - } - - public List getOutput_topics() { - return output_topics; - } - - public void setOutput_topics(List output_topics) { - this.output_topics = output_topics; - } - - public List getStatic_args() { - return static_args; - } - - public void setStatic_args(List static_args) { - this.static_args = static_args; - } - - public String getExecution_path() { - return execution_path; - } - - public void setExecution_path(String execution_path) { - this.execution_path = execution_path; - } - - - - public ServiceType getType() { - return type; - } - - public void setType(ServiceType type) { - this.type = type; - } - - public boolean isLaunch_on_startup() { - return launch_on_startup; - } - - public void setLaunch_on_startup(boolean launch_on_startup) { - this.launch_on_startup = launch_on_startup; - } - - public List getService_dependencies() { - return service_dependencies; - } - - public void setService_dependencies(List service_dependencies) { - this.service_dependencies = service_dependencies; - } - - public boolean isMultiple_instances() { - return multiple_instances; - } - - public void setMultiple_instances(boolean multiple_instances) { - this.multiple_instances = multiple_instances; - } - - public List getEnvironmentVariables() { - return environmentVariables; - } - - public void setEnvironmentVariables(List environmentVariables) { - this.environmentVariables = environmentVariables; - } - - @Override - public String toString() { - Gson gson = new Gson(); - return gson.toJson(this); - } - - public static ServiceInfo parse(String jsonString){ - Gson gson = new Gson(); - ServiceInfo obj = gson.fromJson(jsonString, ServiceInfo.class); - if(obj.id==null) - throw new JsonSyntaxException("Expected attribute service_id not found"); - return obj; - } - - public static void main(String[] args) throws IOException{ - - File test = new File("test.config"); - System.out.println(ServiceInfo.parse(new String(Files.readAllBytes(Paths.get(test.getAbsolutePath()))))); - } - -} +/******************************************************************************* + * Copyright (c) 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.dto; + + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +public class ServiceInfo implements Serializable { + + public enum ServiceType { + PYTHON, JAVA, WEB, EXE + } + + public enum ServiceCategory { + SIMULATOR, COSIMULATOR, SERVICE + } + + + String id; + String description; + String creator; + List input_topics; + List output_topics; + List static_args; + String execution_path; + HashMap user_input; + ServiceType type; + boolean launch_on_startup; + List service_dependencies; + boolean multiple_instances; + List environmentVariables; + ServiceCategory category = ServiceCategory.SERVICE; + + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCreator() { + return creator; + } + + public void setCreator(String creator) { + this.creator = creator; + } + + public List getInput_topics() { + return input_topics; + } + + public void setInput_topics(List input_topics) { + this.input_topics = input_topics; + } + + public List getOutput_topics() { + return output_topics; + } + + public void setOutput_topics(List output_topics) { + this.output_topics = output_topics; + } + + public List getStatic_args() { + return static_args; + } + + public void setStatic_args(List static_args) { + this.static_args = static_args; + } + + public String getExecution_path() { + return execution_path; + } + + public void setExecution_path(String execution_path) { + this.execution_path = execution_path; + } + + + + public ServiceType getType() { + return type; + } + + public void setType(ServiceType type) { + this.type = type; + } + + public boolean isLaunch_on_startup() { + return launch_on_startup; + } + + public void setLaunch_on_startup(boolean launch_on_startup) { + this.launch_on_startup = launch_on_startup; + } + + public List getService_dependencies() { + return service_dependencies; + } + + public void setService_dependencies(List service_dependencies) { + this.service_dependencies = service_dependencies; + } + + public boolean isMultiple_instances() { + return multiple_instances; + } + + public void setMultiple_instances(boolean multiple_instances) { + this.multiple_instances = multiple_instances; + } + + public List getEnvironmentVariables() { + return environmentVariables; + } + + public void setEnvironmentVariables(List environmentVariables) { + this.environmentVariables = environmentVariables; + } + + public ServiceCategory getCatagory() { + return category; + } + + public void setCatagory(ServiceCategory catagory) { + this.category = catagory; + } + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + + public static ServiceInfo parse(String jsonString){ + Gson gson = new Gson(); + ServiceInfo obj = gson.fromJson(jsonString, ServiceInfo.class); + if(obj.id==null) + throw new JsonSyntaxException("Expected attribute service_id not found"); + return obj; + } + + public static void main(String[] args) throws IOException{ + + File test = new File("../services/ochre.config"); + System.out.println(ServiceInfo.parse(new String(Files.readAllBytes(Paths.get(test.getAbsolutePath()))))); + } + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/ServiceInstance.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/ServiceInstance.java index 4c8b018b2..8a5a9e2d4 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/ServiceInstance.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/ServiceInstance.java @@ -52,7 +52,7 @@ public class ServiceInstance implements Serializable{ ServiceInfo servcie_info; HashMap runtime_options; String simulation_id; - Process process; + transient Process process; public ServiceInstance(String instance_id, ServiceInfo servcie_info, HashMap runtime_options, String simulation_id, Process process){ diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/SimulationConfig.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/SimulationConfig.java index 17b1f3dc1..69d832b8c 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/SimulationConfig.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/SimulationConfig.java @@ -40,6 +40,8 @@ package gov.pnnl.goss.gridappsd.dto; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; @@ -50,40 +52,31 @@ public class SimulationConfig implements Serializable { public static final int DEFAULT_SIMULATION_BROKER_PORT = 5570; public static final String DEFAULT_SIMULATION_BROKER_LOCATION = "127.0.0.1"; - - //eg, forward backward sweeper - public String power_flow_solver_method; + //how long the simulation should last (in seconds), default 1 day public int duration = 86400; //simulation id (auto-generated by process manager) public String simulation_id; //user friendly name for the simulation public String simulation_name; - //?? - public String simulator; //time that you want the simulation to start, expected epoch time public long start_time; //Slow simulator down to realtime if true. If false it will run as fast as the simulator allows public boolean run_realtime = true; - - //eg "simulation_output": [{"name":"objectname", "properties": ["prop1","prop2"]},{"name":"object2name","properties":["prop1","prop2"]}] - public SimulationOutput simulation_output = new SimulationOutput(); - - public ModelCreationConfig model_creation_config = new ModelCreationConfig(); - //the port number that the fncs_broker will be operating under + //instruct simulation to pause automatically after publishing measurements if true. + public boolean pause_after_measurements = false; + + //the port number that the helics_broker will be operating under public int simulation_broker_port = DEFAULT_SIMULATION_BROKER_PORT; - //the ip location for the fncs_broker + //the ip location for the helics_broker public String simulation_broker_location = DEFAULT_SIMULATION_BROKER_LOCATION; + + //public List simulator_configs = new ArrayList(); - public String getPower_flow_solver_method() { - return power_flow_solver_method; - } - public void setPower_flow_solver_method(String power_flow_solver_method) { - this.power_flow_solver_method = power_flow_solver_method; - } + public int getDuration() { return duration; } @@ -103,18 +96,26 @@ public String getSimulation_name() { public void setSimulation_name(String simulation_name) { this.simulation_name = simulation_name; } - public String getSimulator() { - return simulator; - } - public void setSimulator(String simulator) { - this.simulator = simulator; - } public long getStart_time() { return start_time; } public void setStart_time(long start_time) { this.start_time = start_time; } + + public boolean isRun_realtime() { + return run_realtime; + } + public void setRun_realtime(boolean run_realtime) { + this.run_realtime = run_realtime; + } + + public boolean isPause_after_measurements() { + return pause_after_measurements; + } + public void setPause_after_measurements(boolean pause_after_measurements) { + this.pause_after_measurements = pause_after_measurements; + } public int getSimulation_broker_port() { return simulation_broker_port; } @@ -127,44 +128,18 @@ public String getSimulation_broker_location() { public void setSimulation_broker_location(String simulation_broker_location) { this.simulation_broker_location = simulation_broker_location; } - - - //TODO change this to more detailed object about output??? maybe not needed -// public String[] output_object_mrid; - //Default output, json message per timestep - - //getting rid of this for now, only 1 simulation at once -// public String[] simulator_name; - - public boolean isRun_realtime() { - return run_realtime; + /*public void addSimulatorConfig(SimulatorConfig simulatorConfig) { + if (simulatorConfig != null) { + this.simulator_configs.add(simulatorConfig); + } } - public void setRun_realtime(boolean run_realtime) { - this.run_realtime = run_realtime; + public List getSimulator_configs() { + return simulator_configs; } - - public SimulationOutput getSimulation_output() { - return simulation_output; - } - public void setSimulation_output(SimulationOutput simulation_output) { - this.simulation_output = simulation_output; - } - public ModelCreationConfig getModel_creation_config() { - return model_creation_config; - } - public void setModel_creation_config(ModelCreationConfig modelCreationConfig) { - this.model_creation_config = modelCreationConfig; - } - // @Override -// public String toString() { -// return "ClassPojo [power_flow_solver_method = " -// + power_flow_solver_method + ", duration = " + duration -// + ", simulation_name = " + simulation_name + ", simulator = " -// + simulator + ", start_time = " + start_time -// + ", simulator = " + simulator + "]"; -// } - - + public void setSimulator_configs(List simulator_configs) { + this.simulator_configs = simulator_configs; + }*/ + @Override public String toString() { Gson gson = new Gson(); diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/SimulationContext.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/SimulationContext.java index a4990d662..63e18fb5a 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/SimulationContext.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/SimulationContext.java @@ -12,9 +12,9 @@ public class SimulationContext implements Serializable { public String simulationHost = "127.0.0.1"; public int simulationPort; public String simulationDir; - public String startupFile; + //public String startupFile; public RequestSimulation request; - public String simulatorPath; + //public String simulatorPath; public List appInstanceIds; public List serviceInstanceIds; public String simulationUser; @@ -52,13 +52,13 @@ public void setSimulationDir(String simulationDir) { this.simulationDir = simulationDir; } - public String getStartupFile() { + /*public String getStartupFile() { return startupFile; } public void setStartupFile(String startupFile) { this.startupFile = startupFile; - } + }*/ public RequestSimulation getRequest() { return request; @@ -68,13 +68,13 @@ public void setRequest(RequestSimulation request) { this.request = request; } - public String getSimulatorPath() { + /*public String getSimulatorPath() { return simulatorPath; } public void setSimulatorPath(String simulatorPath) { this.simulatorPath = simulatorPath; - } + }*/ public List getAppInstanceIds() { return appInstanceIds; diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/SimulatorConfig.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/SimulatorConfig.java new file mode 100644 index 000000000..97cd07e4e --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/SimulatorConfig.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * 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.dto; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + + +public class SimulatorConfig implements Serializable { + private static final long serialVersionUID = -2995486912804104569L; + + //eg, forward backward sweeper + public String power_flow_solver_method; + //the name of the simulator that will be used to run the simulation, e.g. GridLAB-D, OpenDSS, etc. + public String simulator; + + //eg "simulation_output": [{"name":"objectname", "properties": ["prop1","prop2"]},{"name":"object2name","properties":["prop1","prop2"]}] + public SimulationOutput simulation_output = new SimulationOutput(); + + public ModelCreationConfig model_creation_config = new ModelCreationConfig(); + + //temp working folder for simulation files + public String simulation_work_dir; + + public String getPower_flow_solver_method() { + return power_flow_solver_method; + } + public void setPower_flow_solver_method(String power_flow_solver_method) { + this.power_flow_solver_method = power_flow_solver_method; + } + + public String getSimulator() { + return simulator; + } + public void setSimulator(String simulator) { + this.simulator = simulator; + } + + public SimulationOutput getSimulation_output() { + return simulation_output; + } + public void setSimulation_output(SimulationOutput simulation_output) { + this.simulation_output = simulation_output; + } + public ModelCreationConfig getModel_creation_config() { + return model_creation_config; + } + public void setModel_creation_config(ModelCreationConfig model_creation_config) { + this.model_creation_config = model_creation_config; + } + public String getSimulation_work_dir() { + return simulation_work_dir; + } + public void setSimulation_work_dir(String simulation_work_dir) { + this.simulation_work_dir = simulation_work_dir; + } + + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + + public static SimulatorConfig parse(String jsonString){ + Gson gson = new Gson(); + SimulatorConfig obj = gson.fromJson(jsonString, SimulatorConfig.class); + if(obj.simulator==null) + throw new JsonSyntaxException("Expected attribute simulator not found"); + return obj; + } +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/DistributionArea.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/DistributionArea.java new file mode 100644 index 000000000..fd5ea70e2 --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/DistributionArea.java @@ -0,0 +1,27 @@ +package gov.pnnl.goss.gridappsd.dto.field; + +import java.io.Serializable; +import java.util.ArrayList; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class DistributionArea implements Serializable { + + private static final long serialVersionUID = 1L; + + @SerializedName("@id") + public String id; + + @SerializedName("@type") + public String type; + + public ArrayList Substations; + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/FeederArea.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/FeederArea.java new file mode 100644 index 000000000..a8708752f --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/FeederArea.java @@ -0,0 +1,32 @@ +package gov.pnnl.goss.gridappsd.dto.field; + +import java.io.Serializable; +import java.util.ArrayList; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class FeederArea implements Serializable { + + private static final long serialVersionUID = 1L; + + @SerializedName("@id") + public String id; + + @SerializedName("@type") + public String type; + + public ArrayList BoundaryTerminals; + public ArrayList AddressableEquipment; + public ArrayList UnaddressableEquipment; + public ArrayList Measurements; + public ArrayList SwitchAreas; + + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/FieldObject.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/FieldObject.java new file mode 100644 index 000000000..85c2d3d98 --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/FieldObject.java @@ -0,0 +1,17 @@ +package gov.pnnl.goss.gridappsd.dto.field; + +import java.io.Serializable; + +import com.google.gson.annotations.SerializedName; + +public class FieldObject implements Serializable { + + private static final long serialVersionUID = 1L; + + @SerializedName("@id") + public String id; + + @SerializedName("@type") + public String type; + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/NormalEnergizedFeeder.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/NormalEnergizedFeeder.java new file mode 100644 index 000000000..0f562f188 --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/NormalEnergizedFeeder.java @@ -0,0 +1,28 @@ +package gov.pnnl.goss.gridappsd.dto.field; + +import java.io.Serializable; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class NormalEnergizedFeeder implements Serializable { + + private static final long serialVersionUID = 1L; + + @SerializedName("@id") + public String id; + + @SerializedName("@type") + public String type; + + public FeederArea FeederArea; + + //public String message_bus_id; + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/RequestField.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/RequestField.java new file mode 100644 index 000000000..9289d1cca --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/RequestField.java @@ -0,0 +1,31 @@ +package gov.pnnl.goss.gridappsd.dto.field; + +import java.io.Serializable; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +public class RequestField implements Serializable { + + private static final long serialVersionUID = 3088063820447700212L; + + public String request_type = null; + public String areaId = null; + public String start_time = null; + public String end_time = null; + public int interval_seconds = 15; + + + public static RequestField parse(String jsonString) throws JsonSyntaxException { + Gson gson = new Gson(); + RequestField obj = gson.fromJson(jsonString, RequestField.class); + return obj; + } + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/RequestFieldContext.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/RequestFieldContext.java new file mode 100644 index 000000000..899dba2a8 --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/RequestFieldContext.java @@ -0,0 +1,27 @@ +package gov.pnnl.goss.gridappsd.dto.field; + +import java.io.Serializable; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +public class RequestFieldContext implements Serializable { + + private static final long serialVersionUID = -8105887994597368008L; + + public String modelId; + public String areaId = null; + + public static RequestFieldContext parse(String jsonString) throws JsonSyntaxException { + Gson gson = new Gson(); + RequestFieldContext obj = gson.fromJson(jsonString, RequestFieldContext.class); + return obj; + } + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/Root.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/Root.java new file mode 100644 index 000000000..4ee2b560c --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/Root.java @@ -0,0 +1,19 @@ +package gov.pnnl.goss.gridappsd.dto.field; + +import java.io.Serializable; + +import com.google.gson.Gson; + +public class Root implements Serializable { + + private static final long serialVersionUID = 1L; + + public DistributionArea DistributionArea; + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/SecondaryArea.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/SecondaryArea.java new file mode 100644 index 000000000..63dce2180 --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/SecondaryArea.java @@ -0,0 +1,34 @@ +package gov.pnnl.goss.gridappsd.dto.field; + +import java.io.Serializable; +import java.util.ArrayList; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class SecondaryArea implements Serializable { + + private static final long serialVersionUID = 1L; + + @SerializedName("@id") + public String id; + + @SerializedName("@type") + public String type; + + public FieldObject switchArea; + + public ArrayList BoundaryTerminals; + public ArrayList AddressableEquipment; + public ArrayList UnaddressableEquipment; + public ArrayList Measurements; + + //public String message_bus_id; + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/Substation.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/Substation.java new file mode 100644 index 000000000..090aaf6f4 --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/Substation.java @@ -0,0 +1,29 @@ +package gov.pnnl.goss.gridappsd.dto.field; + +import java.io.Serializable; +import java.util.ArrayList; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class Substation implements Serializable { + + private static final long serialVersionUID = 1L; + + @SerializedName("@id") + public String id; + + @SerializedName("@type") + public String type; + + public ArrayList NormalEnergizedFeeder; + + //public String message_bus_id; + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/SwitchArea.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/SwitchArea.java new file mode 100644 index 000000000..8e434f637 --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/SwitchArea.java @@ -0,0 +1,35 @@ +package gov.pnnl.goss.gridappsd.dto.field; + +import java.io.Serializable; +import java.util.ArrayList; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +public class SwitchArea implements Serializable { + + private static final long serialVersionUID = 1L; + + @SerializedName("@id") + public String id; + + @SerializedName("@type") + public String type; + + public FieldObject feederArea; + + public ArrayList BoundaryTerminals; + public ArrayList AddressableEquipment; + public ArrayList UnaddressableEquipment; + public ArrayList Measurements; + public ArrayList SecondaryAreas; + + //public String message_bus_id; + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + +} diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/package-info.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/package-info.java new file mode 100644 index 000000000..d264eeef1 --- /dev/null +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/field/package-info.java @@ -0,0 +1,2 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +package gov.pnnl.goss.gridappsd.dto.field; diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/package-info.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/package-info.java index 91115ab7e..204323afa 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/package-info.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/dto/package-info.java @@ -37,5 +37,5 @@ * PACIFIC NORTHWEST NATIONAL LABORATORY operated by BATTELLE for the * UNITED STATES DEPARTMENT OF ENERGY under Contract DE-AC05-76RL01830 ******************************************************************************/ -@aQute.bnd.annotation.Version("1.0.0") +@aQute.bnd.annotation.Version("2.0.0") package gov.pnnl.goss.gridappsd.dto; diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/log/LogManagerImpl.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/log/LogManagerImpl.java index 417b03073..cb0afce79 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/log/LogManagerImpl.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/log/LogManagerImpl.java @@ -239,7 +239,7 @@ public void fatal(ProcessStatus processStatus, String processId, String message) public void setProcessType(String processId, String process_type) { String source = Thread.currentThread().getStackTrace()[2].getClassName(); - this.log(ProcessStatus.RUNNING, processId, "New process id generated with new process type", LogLevel.INFO, source, process_type); + this.log(ProcessStatus.RUNNING, processId, "New process id generated with new process type: "+process_type, LogLevel.INFO, source, process_type); } public void logMessageFromSource(ProcessStatus processStatus, String processId, String message, String source, LogLevel logLevel) { diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/process/ProcessEvent.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/process/ProcessEvent.java index e482e6b8e..d09a62408 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/process/ProcessEvent.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/process/ProcessEvent.java @@ -42,6 +42,7 @@ import gov.pnnl.goss.gridappsd.api.AppManager; import gov.pnnl.goss.gridappsd.api.ConfigurationManager; import gov.pnnl.goss.gridappsd.api.DataManager; +import gov.pnnl.goss.gridappsd.api.FieldBusManager; import gov.pnnl.goss.gridappsd.api.LogManager; import gov.pnnl.goss.gridappsd.api.ServiceManager; import gov.pnnl.goss.gridappsd.api.SimulationManager; @@ -76,11 +77,15 @@ import javax.jms.Destination; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; + import pnnl.goss.core.Client; import pnnl.goss.core.DataError; import pnnl.goss.core.DataResponse; import pnnl.goss.core.GossResponseEvent; import pnnl.goss.core.Response; +import pnnl.goss.core.Request.RESPONSE_FORMAT; import pnnl.goss.core.security.JWTAuthenticationToken; import pnnl.goss.core.security.SecurityConfig; @@ -118,13 +123,15 @@ public class ProcessEvent implements GossResponseEvent { DataManager dataManager; TestManager testManager; SecurityConfig securityConfig; + FieldBusManager fieldBusManager; public ProcessEvent(ProcessManagerImpl processManager, Client client, ProcessNewSimulationRequest newSimulationProcess, ConfigurationManager configurationManager, SimulationManager simulationManager, AppManager appManager, LogManager logManager, ServiceManager serviceManager, - DataManager dataManager, TestManager testManager, SecurityConfig securityConfig){ + DataManager dataManager, TestManager testManager, SecurityConfig securityConfig, + FieldBusManager fieldBusManager){ this.client = client; this.processManger = processManager; this.newSimulationProcess = newSimulationProcess; @@ -136,6 +143,7 @@ public ProcessEvent(ProcessManagerImpl processManager, this.dataManager = dataManager; this.testManager = testManager; this.securityConfig = securityConfig; + this.fieldBusManager = fieldBusManager; } @@ -217,7 +225,7 @@ public void onMessage(Serializable message) { client.publish(event.getReplyDestination(), response); //TODO also verify that we have the correct sub-configurations as part of the request //newSimulationProcess.process(configurationManager, simulationManager, processId, event, event.getData(), appManager, serviceManager); - newSimulationProcess.process(configurationManager, simulationManager, processId, simRequest,processManger.assignSimulationPort(processId), appManager,serviceManager, testManager, dataManager, username); + newSimulationProcess.process(configurationManager, simulationManager, processId, simRequest, appManager,serviceManager, testManager, dataManager, username); } else if (simRequest.simulation_request_type.equals(SimulationRequestType.PAUSE)) { //if pause simulationManager.pauseSimulation(simRequest.getSimulation_id()); } else if (simRequest.simulation_request_type.equals(SimulationRequestType.RESUME)) { //if play @@ -328,7 +336,9 @@ public void onMessage(Serializable message) { } - } else if(event.getDestination().contains(GridAppsDConstants.topic_requestPlatformStatus)){ + } + + else if(event.getDestination().contains(GridAppsDConstants.topic_requestPlatformStatus)){ RequestPlatformStatus request = RequestPlatformStatus.parse(event.getData().toString()); PlatformStatus platformStatus = new PlatformStatus(); @@ -340,6 +350,8 @@ public void onMessage(Serializable message) { platformStatus.setAppInstances(appManager.listRunningApps()); if(request.isServiceInstances()) platformStatus.setServiceInstances(serviceManager.listRunningServices()); + if(request.isField()) + platformStatus.setField(fieldBusManager.getFieldModelMrid()); client.publish(event.getReplyDestination(), platformStatus); } else if (event.getDestination().contains(GridAppsDConstants.topic_requestMyRoles)){ @@ -348,6 +360,13 @@ public void onMessage(Serializable message) { RoleList roleListResult = new RoleList(); roleListResult.setRoles(roles); sendData(client, event.getReplyDestination(), roleListResult.toString(), processId, username, null); + } + + else if(event.getDestination().contains(GridAppsDConstants.topic_requestField)){ + + String data = fieldBusManager.handleRequest(event.getDestination(),event.getData()).toString(); + sendData(client, event.getReplyDestination(), data, processId, username, RESPONSE_FORMAT.JSON.toString()); + } }catch(Exception e ){ StringWriter sw = new StringWriter(); @@ -367,6 +386,13 @@ private void sendData(Client client, Destination replyDestination, Serializable } if(responseFormat == null || responseFormat.equals("JSON")) { + try{ + new JSONObject(data.toString()); + } + catch(JSONException e){ + data = data.toString().replace("\"", "\\\""); + data = "\""+data+"\""; + } String r = "{\"data\":"+data+",\"responseComplete\":true,\"id\":\""+processId+"\"}"; client.publish(replyDestination, r); } diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/process/ProcessManagerImpl.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/process/ProcessManagerImpl.java index 214d82e4e..c80b868b4 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/process/ProcessManagerImpl.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/process/ProcessManagerImpl.java @@ -53,6 +53,7 @@ import gov.pnnl.goss.gridappsd.api.AppManager; import gov.pnnl.goss.gridappsd.api.ConfigurationManager; import gov.pnnl.goss.gridappsd.api.DataManager; +import gov.pnnl.goss.gridappsd.api.FieldBusManager; import gov.pnnl.goss.gridappsd.api.LogManager; import gov.pnnl.goss.gridappsd.api.ProcessManager; import gov.pnnl.goss.gridappsd.api.RoleManager; @@ -106,15 +107,14 @@ public class ProcessManagerImpl implements ProcessManager { @ServiceDependency private volatile TestManager testManager; + @ServiceDependency + private volatile FieldBusManager fieldBusManager; + // @ServiceDependency // private volatile RoleManager roleManager; ProcessNewSimulationRequest newSimulationProcess = null; - private Hashtable simulationPorts = new Hashtable(); - - private Random randPort = new Random(); - public ProcessManagerImpl(){} public ProcessManagerImpl(ClientFactory clientFactory, ConfigurationManager configurationManager, @@ -122,7 +122,8 @@ public ProcessManagerImpl(ClientFactory clientFactory, LogManager logManager, AppManager appManager, ProcessNewSimulationRequest newSimulationProcess, - TestManager testManager){ + TestManager testManager, + FieldBusManager fieldBusManager){ this.clientFactory = clientFactory; this.configurationManager = configurationManager; this.simulationManager = simulationManager; @@ -130,6 +131,7 @@ public ProcessManagerImpl(ClientFactory clientFactory, this.newSimulationProcess = newSimulationProcess; this.logManager = logManager; this.testManager = testManager; + this.fieldBusManager = fieldBusManager; } @@ -168,7 +170,7 @@ public void start(){ client.subscribe(GridAppsDConstants.topic_process_prefix+".>", new ProcessEvent(this, - client, newSimulationProcess, configurationManager, simulationManager, appManager, logManager, serviceManager, dataManager, testManager, securityConfig)); + client, newSimulationProcess, configurationManager, simulationManager, appManager, logManager, serviceManager, dataManager, testManager, securityConfig, fieldBusManager)); } catch(Exception e){ e.printStackTrace(); @@ -185,22 +187,4 @@ static String generateProcessId(){ return Integer.toString(Math.abs(new Random().nextInt())); } - public int assignSimulationPort(String simulationId) throws Exception { - Integer simIdKey = new Integer(simulationId); - if (!simulationPorts.containsKey(simIdKey)) { - int tempPort = 49152 + randPort.nextInt(16384); - AtomicInteger tempPortObj = new AtomicInteger(tempPort); - while (simulationPorts.containsValue(tempPortObj)) { - int newTempPort = 49152 + randPort.nextInt(16384); - tempPortObj.set(newTempPort); - } - simulationPorts.put(simIdKey, tempPortObj); - return tempPortObj.get(); - //TODO: test host:port is available - } else { - throw new Exception("The simulation id already exists. This indicates that the simulation id is part of a" - + "simulation in progress."); - } - } - } diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/process/ProcessNewSimulationRequest.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/process/ProcessNewSimulationRequest.java index e94010b9c..e41e38a70 100755 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/process/ProcessNewSimulationRequest.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/process/ProcessNewSimulationRequest.java @@ -40,16 +40,24 @@ package gov.pnnl.goss.gridappsd.process; import java.io.File; +import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + import com.google.gson.Gson; import gov.pnnl.goss.gridappsd.api.AppManager; @@ -66,13 +74,14 @@ import gov.pnnl.goss.gridappsd.dto.ApplicationObject; import gov.pnnl.goss.gridappsd.dto.LogMessage.ProcessStatus; import gov.pnnl.goss.gridappsd.dto.ModelCreationConfig; +import gov.pnnl.goss.gridappsd.dto.PowerSystemConfig; import gov.pnnl.goss.gridappsd.dto.RequestSimulation; import gov.pnnl.goss.gridappsd.dto.ServiceConfig; import gov.pnnl.goss.gridappsd.dto.ServiceInfo; -import gov.pnnl.goss.gridappsd.dto.SimulationConfig; import gov.pnnl.goss.gridappsd.dto.SimulationContext; import gov.pnnl.goss.gridappsd.dto.SimulationOutput; import gov.pnnl.goss.gridappsd.dto.SimulationOutputObject; +import gov.pnnl.goss.gridappsd.dto.SimulatorConfig; import gov.pnnl.goss.gridappsd.utils.GridAppsDConstants; import pnnl.goss.core.DataResponse; import pnnl.goss.core.security.SecurityConfig; @@ -95,62 +104,78 @@ public void process(ConfigurationManager configurationManager, DataResponse event, RequestSimulation simRequest, AppManager appManager, ServiceManager serviceManager, TestManager testManager, DataManager dataManager, String username) { + process(configurationManager, simulationManager, simulationId, simRequest, - SimulationConfig.DEFAULT_SIMULATION_BROKER_PORT, appManager, - serviceManager, testManager, dataManager, username); + appManager,serviceManager, testManager, dataManager, username); } public void process(ConfigurationManager configurationManager, SimulationManager simulationManager, String simulationId, - RequestSimulation simRequest, int simulationPort, AppManager appManager, + RequestSimulation simRequest, AppManager appManager, ServiceManager serviceManager, TestManager testManager,DataManager dataManager, String username) { try { - simRequest.simulation_config.setSimulation_broker_port(simulationPort); - logManager.info(ProcessStatus.RUNNING, simulationId, "Parsed config " + simRequest); + //1. check if simulation request is valid + logManager.info(ProcessStatus.RUNNING, simulationId, "Parsed simulation request: " + simRequest); if (simRequest == null || simRequest.getPower_system_config() == null || simRequest.getSimulation_config() == null) { - logManager.info(ProcessStatus.RUNNING, simulationId, "No simulation file returned for request "+ simRequest); - throw new RuntimeException("Invalid configuration received"); + logManager.info(ProcessStatus.RUNNING, simulationId, "Invalid simulation request received "+ simRequest); + throw new RuntimeException("Invalid simulation request received"); } - // make request to configuration Manager to get power grid model - // file locations and names - logManager.info(ProcessStatus.RUNNING, simulationId,"Creating simulation and power grid model files for simulation Id "+simulationId); - - -// StringWriter simulationConfigDirOut = new StringWriter(); -// File simulationFile = configurationManager.getSimulationFile( -// simulationId, config); -// String simulationConfigDir = simulationConfigDirOut.toString(); - String simulationConfigDir = configurationManager.getConfigurationProperty(GridAppsDConstants.GRIDAPPSD_TEMP_PATH); - if (simulationConfigDir == null || simulationConfigDir.trim().length()==0) { - logManager.error(ProcessStatus.ERROR, simulationId, "No simulation file returned for request "+ simRequest); - throw new Exception("No simulation file returned for request " - + simRequest); + //2. Create simulation working folders for each model in power system config as /tmp/simulationId/modelId + logManager.info(ProcessStatus.RUNNING, simulationId,"Creating simulation working folders for simulation Id "+simulationId); + String tmpWorkingDir = configurationManager.getConfigurationProperty(GridAppsDConstants.GRIDAPPSD_TEMP_PATH); + if (tmpWorkingDir == null || tmpWorkingDir.trim().length()==0) { + logManager.error(ProcessStatus.ERROR, simulationId, "GRIDAPPSD_TEMP_PATH not configured correectly "); + throw new Exception("GRIDAPPSD_TEMP_PATH not configured correectly"); } - if(!simulationConfigDir.endsWith(File.separator)){ - simulationConfigDir = simulationConfigDir+File.separator; + if(!tmpWorkingDir.endsWith(File.separator)){ + tmpWorkingDir = tmpWorkingDir+File.separator; } - simulationConfigDir = simulationConfigDir+simulationId+File.separator; - File tempDataPathDir = new File(simulationConfigDir); - if(!tempDataPathDir.exists()){ - tempDataPathDir.mkdirs(); + + //Create simulation working directory + File simulationWorkingDir = new File(tmpWorkingDir+simulationId); + if(!simulationWorkingDir.exists()){ + simulationWorkingDir.mkdirs(); + } + + //Create model working directories for each model in request + for(PowerSystemConfig powerSystemConfig : simRequest.power_system_configs){ + SimulatorConfig simulatorConfig = powerSystemConfig.simulator_config; + File modelWorkingDir = new File(simulationWorkingDir,powerSystemConfig.getLine_name()); + simulatorConfig.simulation_work_dir = modelWorkingDir.getAbsolutePath(); + if(!modelWorkingDir.exists()){ + modelWorkingDir.mkdirs(); + } } + + //3. Assign a port for simulation broker + simRequest.simulation_config.simulation_broker_port = simulationManager.assignSimulationPort(simulationId); + + + + //4. Set up simulation context that will be passed to managers, services and apps + Map simulationContext = new HashMap(); + simulationContext.put("request",simRequest); + simulationContext.put("simulationId",simulationId); + simulationContext.put("simulationHost","127.0.0.1"); + simulationContext.put("simulationPort",simRequest.simulation_config.simulation_broker_port); + simulationContext.put("simulationDir",simulationWorkingDir); SimulationContext simContext = new SimulationContext(); simContext.setRequest(simRequest); simContext.simulationId = simulationId; - simContext.simulationPort = simulationPort; - simContext.simulationDir = tempDataPathDir.getAbsolutePath(); - if(simRequest.getSimulation_config().getSimulator().equals("GridLAB-D")) + simContext.simulationPort = simRequest.simulation_config.simulation_broker_port; + simContext.simulationDir = simulationWorkingDir.getAbsolutePath(); + /*if(simRequest.getSimulation_config().getSimulator_configs().getSimulator().equals("GridLAB-D")) simContext.startupFile = tempDataPathDir.getAbsolutePath()+File.separator+"model_startup.glm"; else if(simRequest.getSimulation_config().getSimulator().equals("OCHRE")) - simContext.startupFile = tempDataPathDir.getAbsolutePath()+File.separator+"ochre_helics_config.json"; + simContext.startupFile = tempDataPathDir.getAbsolutePath()+File.separator+"ochre_helics_config.json";*/ simContext.simulationUser = username; - try{ + /*(try{ simContext.simulatorPath = serviceManager.getService(simRequest.getSimulation_config().getSimulator()).getExecution_path(); }catch(NullPointerException e){ if(serviceManager.getService(simRequest.getSimulation_config().getSimulator()) == null){ @@ -159,71 +184,92 @@ else if(simRequest.getSimulation_config().getSimulator().equals("OCHRE")) logManager.error(ProcessStatus.ERROR, simulationId,"Cannot find execution path for service ="+simRequest.getSimulation_config().getSimulator()); } e.printStackTrace(); - } + }*/ - + //5. Check GridLAB-D interface to use fncs or helics String gldInterface = null; ServiceInfo gldService = serviceManager.getService("GridLAB-D"); if(gldService!=null){ List deps = gldService.getService_dependencies(); gldInterface = GridAppsDConstants.getGLDInterface(deps); - } - - int numFederates = 2; - String simulator = simRequest.getSimulation_config().getSimulator(); - //generate config files for requested simulator - //if requested simulator is opendss - if(simulator.equalsIgnoreCase(DSSAllConfigurationHandler.CONFIGTARGET)){ - Properties simulationParams = generateSimulationParameters(simRequest); - simulationParams.put(DSSAllConfigurationHandler.SIMULATIONID, simulationId); - simulationParams.put(DSSAllConfigurationHandler.DIRECTORY, tempDataPathDir.getAbsolutePath()); - if(gldInterface!=null){ - simulationParams.put(GridAppsDConstants.GRIDLABD_INTERFACE, gldInterface); - } - configurationManager.generateConfiguration(DSSAllConfigurationHandler.TYPENAME, simulationParams, new PrintWriter(new StringWriter()), simulationId, username); } - else if(simulator.equalsIgnoreCase(OchreAllConfigurationHandler.TYPENAME)){ - numFederates = 42; - Properties simulationParams = generateSimulationParameters(simRequest); - simulationParams.put(DSSAllConfigurationHandler.SIMULATIONID, simulationId); - simulationParams.put(DSSAllConfigurationHandler.DIRECTORY, tempDataPathDir.getAbsolutePath()); - if(gldInterface!=null){ - simulationParams.put(GridAppsDConstants.GRIDLABD_INTERFACE, gldInterface); + + //6. Generate configuration files for the requested simulator + + + int numFederates = simRequest.power_system_configs.size()+1; + + for(PowerSystemConfig powerSystemConfig : simRequest.power_system_configs){ + + logManager.info(ProcessStatus.RUNNING, simulationId,"Creating simulation and power grid model files for simulation Id "+simulationId+" and model id "+powerSystemConfig.Line_name); + SimulatorConfig simulatorConfig = powerSystemConfig.simulator_config; + + String simulator = simulatorConfig.getSimulator(); + + //generate config files for requested simulator + //if requested simulator is opendss + if(simulator.equalsIgnoreCase(DSSAllConfigurationHandler.CONFIGTARGET)){ + Properties simulationParams = generateSimulationParameters(simRequest, powerSystemConfig); + simulationParams.put(DSSAllConfigurationHandler.SIMULATIONID, simulationId); + simulationParams.put(DSSAllConfigurationHandler.DIRECTORY, simulatorConfig.getSimulation_work_dir()); + if(gldInterface!=null){ + simulationParams.put(GridAppsDConstants.GRIDLABD_INTERFACE, gldInterface); + } + configurationManager.generateConfiguration(DSSAllConfigurationHandler.TYPENAME, simulationParams, new PrintWriter(new StringWriter()), simulationId, username); } - configurationManager.generateConfiguration(GLDAllConfigurationHandler.TYPENAME, simulationParams, new PrintWriter(new StringWriter()), simulationId, username); - configurationManager.generateConfiguration(OchreAllConfigurationHandler.TYPENAME, simulationParams, new PrintWriter(new StringWriter()), simulationId, username); - } - else { //otherwise use gridlabd - Properties simulationParams = generateSimulationParameters(simRequest); - simulationParams.put(GLDAllConfigurationHandler.SIMULATIONID, simulationId); - simulationParams.put(GLDAllConfigurationHandler.DIRECTORY, tempDataPathDir.getAbsolutePath()); - if(gldInterface!=null){ - simulationParams.put(GridAppsDConstants.GRIDLABD_INTERFACE, gldInterface); + else if(simulator.equalsIgnoreCase(OchreAllConfigurationHandler.TYPENAME)){ + Properties simulationParams = generateSimulationParameters(simRequest, powerSystemConfig); + simulationParams.put(DSSAllConfigurationHandler.SIMULATIONID, simulationId); + simulationParams.put(DSSAllConfigurationHandler.DIRECTORY, simulatorConfig.getSimulation_work_dir()); + + if(simulatorConfig.model_creation_config.separated_loads_file!=null){ + numFederates = getSeparatedLoadNames(simulatorConfig.model_creation_config.separated_loads_file).size()+numFederates; + simulationParams.put(GLDAllConfigurationHandler.SEPARATED_LOADS_FILE, simulatorConfig.model_creation_config.separated_loads_file); + } + else{ + logManager.error(ProcessStatus.ERROR,simulationId,"No "+GLDAllConfigurationHandler.SEPARATED_LOADS_FILE+" parameter provided"); + throw new Exception("Missing parameter "+GLDAllConfigurationHandler.SEPARATED_LOADS_FILE); + } + + + + if(gldInterface!=null){ + simulationParams.put(GridAppsDConstants.GRIDLABD_INTERFACE, gldInterface); + } + configurationManager.generateConfiguration(GLDAllConfigurationHandler.TYPENAME, simulationParams, new PrintWriter(new StringWriter()), simulationId, username); + configurationManager.generateConfiguration(OchreAllConfigurationHandler.TYPENAME, simulationParams, new PrintWriter(new StringWriter()), simulationId, username); } - configurationManager.generateConfiguration(GLDAllConfigurationHandler.TYPENAME, simulationParams, new PrintWriter(new StringWriter()), simulationId, username); + else { //otherwise use gridlabd + Properties simulationParams = generateSimulationParameters(simRequest, powerSystemConfig); + simulationParams.put(GLDAllConfigurationHandler.SIMULATIONID, simulationId); + simulationParams.put(GLDAllConfigurationHandler.DIRECTORY, simulatorConfig.getSimulation_work_dir()); + if(gldInterface!=null){ + simulationParams.put(GridAppsDConstants.GRIDLABD_INTERFACE, gldInterface); + } + configurationManager.generateConfiguration(GLDAllConfigurationHandler.TYPENAME, simulationParams, new PrintWriter(new StringWriter()), simulationId, username); + } + + logManager.debug(ProcessStatus.RUNNING, simulationId, "Simulation and power grid model files generated for simulation Id for model id "+powerSystemConfig.Line_name); + } + - logManager.debug(ProcessStatus.RUNNING, simulationId, "Simulation and power grid model files generated for simulation Id "); + // Start Apps and Services - Map simulationContext = new HashMap(); - simulationContext.put("request",simRequest); - simulationContext.put("simulationId",simulationId); - simulationContext.put("simulationHost","127.0.0.1"); - simulationContext.put("simulationPort",simulationPort); - simulationContext.put("simulationDir",simulationConfigDir); simulationContext.put("numFederates",numFederates); - - if(simRequest.getSimulation_config().getSimulator().equals("GridLAB-D")) + simContext.numFederates = numFederates; + + /*if(simRequest.getSimulation_config().getSimulator().equals("GridLAB-D")) simulationContext.put("simulationFile",tempDataPathDir.getAbsolutePath()+File.separator+"model_startup.glm"); else if(simRequest.getSimulation_config().getSimulator().equals("OCHRE")) - simulationContext.put("simulationFile",tempDataPathDir.getAbsolutePath()+File.separator+"ochre_helics_config.json"); + simulationContext.put("simulationFile",tempDataPathDir.getAbsolutePath()+File.separator+"ochre_helics_config.json");*/ simulationContext.put("logLevel", logManager.getLogLevel()); simulationContext.put("username", securityConfig.getManagerUser()); simulationContext.put("password", securityConfig.getManagerPassword()); - try{ + /*try{ simulationContext.put("simulatorPath",serviceManager.getService(simRequest.getSimulation_config().getSimulator()).getExecution_path()); }catch(NullPointerException e){ if(serviceManager.getService(simRequest.getSimulation_config().getSimulator()) == null){ @@ -232,14 +278,14 @@ else if(simRequest.getSimulation_config().getSimulator().equals("OCHRE")) logManager.error(ProcessStatus.ERROR, simulationId,"Cannot find execution path for service ="+simRequest.getSimulation_config().getSimulator()); } e.printStackTrace(); - } + }*/ List connectServiceInstanceIds = new ArrayList(); List connectServiceIds = new ArrayList(); List connectedAppInstanceIds = new ArrayList(); logManager.info(ProcessStatus.RUNNING, simulationId, "Service configs "+simRequest.service_configs); if (simRequest.service_configs == null) { - logManager.warn(ProcessStatus.RUNNING, simulationId, "No services found in request ="+simRequest.getSimulation_config().getSimulator()); + logManager.warn(ProcessStatus.RUNNING, simulationId, "No services found in simulation request ="+simRequest.simulation_id); } else{ for(ServiceConfig serviceConfig : simRequest.service_configs){ @@ -256,7 +302,7 @@ else if(simRequest.getSimulation_config().getSimulator().equals("OCHRE")) if (simRequest.application_config == null) { - logManager.warn(ProcessStatus.RUNNING, simulationId, "No applications found in request ="+simRequest.getSimulation_config().getSimulator()); + logManager.warn(ProcessStatus.RUNNING, simulationId, "No applications found in simulation request ="+simRequest.simulation_id); } else { for (ApplicationObject app : simRequest.application_config @@ -296,12 +342,15 @@ else if(simRequest.getSimulation_config().getSimulator().equals("OCHRE")) simContext.serviceInstanceIds = connectServiceInstanceIds; simContext.appInstanceIds = connectedAppInstanceIds; - ServiceInfo simulationServiceInfo = serviceManager.getService(simRequest.getSimulation_config().simulator); - List serviceDependencies = simulationServiceInfo.getService_dependencies(); - for(String service : serviceDependencies) { - String serviceInstanceId = serviceManager.startServiceForSimultion(service, null, simulationContext); - if(serviceInstanceId!=null) - simContext.addServiceInstanceIds(serviceInstanceId); + + for(PowerSystemConfig powerSystemConfig: simRequest.power_system_configs){ + ServiceInfo simulationServiceInfo = serviceManager.getService(powerSystemConfig.simulator_config.simulator); + List serviceDependencies = simulationServiceInfo.getService_dependencies(); + for(String service : serviceDependencies) { + String serviceInstanceId = serviceManager.startServiceForSimultion(service, null, simulationContext); + if(serviceInstanceId!=null) + simContext.addServiceInstanceIds(serviceInstanceId); + } } dataManager.processDataRequest(simContext, "timeseries", simulationId, null, username); @@ -310,9 +359,11 @@ else if(simRequest.getSimulation_config().getSimulator().equals("OCHRE")) testManager.handleTestRequest(simRequest.getTest_config(), simContext); // start simulation - logManager.debug(ProcessStatus.RUNNING, simulationId,"Starting simulation for id " + simulationId); - simulationManager.startSimulation(simulationId, simRequest.getSimulation_config(),simContext, simulationContext); - logManager.info(ProcessStatus.RUNNING, simulationId,"Started simulation for id " + simulationId); + for(PowerSystemConfig powerSystemConfig : simRequest.power_system_configs){ + logManager.debug(ProcessStatus.RUNNING, simulationId,"Starting simulation for simulation id " + simulationId+" and model id "+powerSystemConfig.Line_name); + simulationManager.startSimulation(simulationId, simRequest.getSimulation_config(),simContext, simulationContext, powerSystemConfig); + logManager.info(ProcessStatus.RUNNING, simulationId,"Started simulation for id " + simulationId+" and model id "+powerSystemConfig.Line_name); + } } catch (Exception e) { @@ -327,13 +378,13 @@ else if(simRequest.getSimulation_config().getSimulator().equals("OCHRE")) } - Properties generateSimulationParameters(RequestSimulation requestSimulation){ + Properties generateSimulationParameters(RequestSimulation requestSimulation, PowerSystemConfig powerSystemConfig){ Properties params = new Properties(); //TODO where to get feeder id? - params.put(GLDAllConfigurationHandler.MODELID, requestSimulation.power_system_config.Line_name); + params.put(GLDAllConfigurationHandler.MODELID, powerSystemConfig.Line_name); - ModelCreationConfig modelConfig = requestSimulation.getSimulation_config().model_creation_config; + ModelCreationConfig modelConfig = powerSystemConfig.simulator_config.model_creation_config; double zFraction = modelConfig.z_fraction; double iFraction = modelConfig.i_fraction; double pFraction = modelConfig.p_fraction; @@ -353,7 +404,7 @@ Properties generateSimulationParameters(RequestSimulation requestSimulation){ params.put(GLDAllConfigurationHandler.SCHEDULENAME, ""); } params.put(GLDAllConfigurationHandler.SIMULATIONNAME, requestSimulation.getSimulation_config().simulation_name); - params.put(GLDAllConfigurationHandler.SOLVERMETHOD, requestSimulation.getSimulation_config().power_flow_solver_method); + params.put(GLDAllConfigurationHandler.SOLVERMETHOD, powerSystemConfig.simulator_config.power_flow_solver_method); params.put(GLDAllConfigurationHandler.SIMULATIONBROKERHOST, requestSimulation.getSimulation_config().getSimulation_broker_location()); params.put(GLDAllConfigurationHandler.SIMULATIONBROKERPORT, new Integer(requestSimulation.getSimulation_config().getSimulation_broker_port()).toString()); @@ -365,8 +416,52 @@ Properties generateSimulationParameters(RequestSimulation requestSimulation){ Gson gson = new Gson(); params.put(GLDAllConfigurationHandler.MODEL_STATE, gson.toJson(modelConfig.getModel_state())); } + + params.put(GLDAllConfigurationHandler.SIMULATOR, powerSystemConfig.simulator_config.simulator); + params.put(GLDAllConfigurationHandler.RUN_REALTIME, requestSimulation.getSimulation_config().run_realtime); + + if(modelConfig.separated_loads_file!=null){ + params.put(GLDAllConfigurationHandler.SEPARATED_LOADS_FILE, modelConfig.separated_loads_file); + } else { + params.put(GLDAllConfigurationHandler.SEPARATED_LOADS_FILE, ""); + } return params; } + + private List getSeparatedLoadNames(String fileName) { + + List loadNames = new ArrayList(); + boolean isHeader = true; + + try { + FileInputStream fis = new FileInputStream(fileName); + Workbook workbook = null; + if(fileName.toLowerCase().endsWith("xlsx")){ + workbook = new XSSFWorkbook(fis); + }else if(fileName.toLowerCase().endsWith("xls")){ + workbook = new HSSFWorkbook(fis); + } + + Sheet sheet = workbook.getSheetAt(0); + Iterator rowIterator = sheet.iterator(); + while (rowIterator.hasNext()) + { + + Row row = rowIterator.next(); + if(!isHeader){ + loadNames.add(row.getCell(5).getStringCellValue()); + System.out.println(row.getCell(5).getStringCellValue()); + } + isHeader=false; + } + fis.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + + return loadNames; + } /** @@ -411,4 +506,5 @@ protected void generateConfigFile(File configFile , SimulationOutput simulationO e.printStackTrace(); } } + } diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/service/ServiceManagerImpl.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/service/ServiceManagerImpl.java index 27640fca8..2c2fcb600 100755 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/service/ServiceManagerImpl.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/service/ServiceManagerImpl.java @@ -138,7 +138,6 @@ public void start(){ protected void scanForServices(){ //Get directory for services from the config File serviceConfigDir = getServiceConfigDirectory(); - //for each service found, parse the [service].config file to create serviceinfo object and add to services map File[] serviceconfigFiles = serviceConfigDir.listFiles(new FileFilter() { @@ -153,6 +152,9 @@ public boolean accept(File pathname) { for(File serviceConfigFile: serviceconfigFiles){ ServiceInfo serviceInfo = parseServiceInfo(serviceConfigFile); services.put(serviceInfo.getId(), serviceInfo); + if(serviceInfo.isLaunch_on_startup()){ + startService(serviceInfo.getId(), null); + } } } @@ -238,7 +240,11 @@ public String startService(String serviceId, @Override public String startServiceForSimultion(String serviceId, HashMap runtimeOptions, Map simulationContext) { - String simulationId = simulationContext.get("simulationId").toString(); + String simulationId = null; + + if(simulationContext!=null && simulationContext.get("simulationId")!=null){ + simulationId = simulationContext.get("simulationId").toString(); + } String instanceId = serviceId+"-"+new Date().getTime(); @@ -251,6 +257,12 @@ public String startServiceForSimultion(String serviceId, HashMap throw new RuntimeException("Service not found: "+serviceId); } + + if(simulationId!=null && serviceInfo.isLaunch_on_startup()){ + logManager.warn(ProcessStatus.RUNNING, simulationId, serviceId + " service is already running and multiple instances are not allowed"); + return null; + } + // are multiple allowed? if not check to see if it is already running, if it is then send warning message if(!serviceInfo.isMultiple_instances() && listRunningServices(serviceId, simulationId).size()>0){ logManager.warn(ProcessStatus.RUNNING, simulationId, serviceId + " service is already running and multiple instances are not allowed for single simulation"); @@ -282,9 +294,10 @@ public String startServiceForSimultion(String serviceId, HashMap } envVars.put(envVar.getEnvName(), value); } - envVars.put("GRIDAPPSD_USER", simulationContext.get("username").toString()); - envVars.put("GRIDAPPSD_PASSWORD", simulationContext.get("password").toString()); - envVars.put("GRIDAPPSD_LOG_LEVEL", simulationContext.get("logLevel").toString()); + envVars.put("GRIDAPPSD_USER", securityConfig.getManagerUser()); + envVars.put("GRIDAPPSD_PASSWORD", securityConfig.getManagerPassword()); + envVars.put("GRIDAPPSD_LOG_LEVEL",logManager.getLogLevel().toString()); + //add executation command @@ -303,6 +316,11 @@ public String startServiceForSimultion(String serviceId, HashMap } } } + else{ + if(staticArg.contains("(field_model_mrid")){ + staticArg = staticArg.replace("(field_model_mrid)",this.getFieldModelMrid()); + } + } commands.add(staticArg); } } @@ -320,7 +338,7 @@ public String startServiceForSimultion(String serviceId, HashMap if(serviceDirectory.exists()) processServiceBuilder.directory(serviceDirectory); processServiceBuilder.redirectErrorStream(true); - processServiceBuilder.redirectOutput(); + processServiceBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT); logManager.info(ProcessStatus.RUNNING, simulationId, "Starting service with command "+ String.join(" ",commands)); process = processServiceBuilder.start(); @@ -332,7 +350,7 @@ public String startServiceForSimultion(String serviceId, HashMap if(serviceDirectory.exists()) processServiceBuilder.directory(serviceDirectory); processServiceBuilder.redirectErrorStream(true); - processServiceBuilder.redirectOutput(); + processServiceBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT); logManager.info(ProcessStatus.RUNNING, simulationId, "Starting service with command "+ String.join(" ",commands)); process = processServiceBuilder.start(); @@ -343,7 +361,7 @@ public String startServiceForSimultion(String serviceId, HashMap if(serviceDirectory.exists()) processServiceBuilder.directory(serviceDirectory); processServiceBuilder.redirectErrorStream(true); - processServiceBuilder.redirectOutput(); + processServiceBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT); logManager.info(ProcessStatus.RUNNING, simulationId, "Starting service with command "+ String.join(" ",commands)); process = processServiceBuilder.start(); @@ -404,8 +422,6 @@ public List listRunningServices(String serviceId, String simula if(instance.getService_info().getId().equals(serviceId)){ if(simulationId!=null && instance.getSimulation_id().equals(simulationId)) result.add(instance); - else - result.add(instance); } } return result; @@ -473,6 +489,15 @@ public void run() { }.start(); } + public String getFieldModelMrid() { + if (this.configurationProperties != null) { + Object value = this.configurationProperties.get("field.model.mrid"); + if (value != null) + return value.toString(); + } + return null; + } + diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/simulation/SimulationManagerImpl.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/simulation/SimulationManagerImpl.java index d8e28fbf0..659c2d6a5 100755 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/simulation/SimulationManagerImpl.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/simulation/SimulationManagerImpl.java @@ -41,8 +41,11 @@ import java.util.Date; import java.util.HashMap; +import java.util.Hashtable; import java.util.List; import java.util.Map; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.felix.dm.annotation.api.Component; import org.apache.felix.dm.annotation.api.ServiceDependency; @@ -59,6 +62,7 @@ import gov.pnnl.goss.gridappsd.dto.LogMessage; import gov.pnnl.goss.gridappsd.dto.LogMessage.LogLevel; import gov.pnnl.goss.gridappsd.dto.LogMessage.ProcessStatus; +import gov.pnnl.goss.gridappsd.dto.PowerSystemConfig; import gov.pnnl.goss.gridappsd.dto.ServiceInfo; import gov.pnnl.goss.gridappsd.dto.SimulationConfig; import gov.pnnl.goss.gridappsd.dto.SimulationContext; @@ -104,6 +108,11 @@ public class SimulationManagerImpl implements SimulationManager{ private Map simContexts = new HashMap(); // private Map simProcesses = new HashMap(); + + private Hashtable simulationPorts = new Hashtable(); + + private Random randPort = new Random(); + public SimulationManagerImpl(){ } @@ -129,7 +138,7 @@ public void start() throws Exception{ * @param simulationFile */ @Override - public void startSimulation(String simulationId, SimulationConfig simulationConfig, SimulationContext simContext, Map simulationContext){ + public void startSimulation(String simulationId, SimulationConfig simulationConfig, SimulationContext simContext, Map simulationContext, PowerSystemConfig powerSystemConfig){ //TODO: remove simulationContext parameter after refactoring service manager try { @@ -141,7 +150,7 @@ public void startSimulation(String simulationId, SimulationConfig simulationConf simContexts.put(simContext.getSimulationId(), simContext); SimulationProcess simProc = new SimulationProcess(simContext, serviceManager, - simulationConfig, simulationId, logManager, appManager, client, securityConfig, simulationContext); + simulationConfig, simulationId, logManager, appManager, client, securityConfig, simulationContext, powerSystemConfig); // simProcesses.put(simContext.getSimulationId(), simProc); simProc.start(); } @@ -158,7 +167,7 @@ public void resumeSimulation(String simulationId){ } @Override public void endSimulation(String simulationId){ - client.publish(GridAppsDConstants.topic_COSIM_input, "{\"command\": \"stop\"}"); + client.publish(GridAppsDConstants.topic_COSIM_input+"."+simulationId, "{\"command\": \"stop\"}"); } @@ -186,6 +195,23 @@ public Map getSimContexts() { public SimulationContext getSimulationContextForId(String simulationId){ return this.simContexts.get(simulationId); } - - -} + + public int assignSimulationPort(String simulationId) throws Exception { + Integer simIdKey = new Integer(simulationId); + if (!simulationPorts.containsKey(simIdKey)) { + int tempPort = 49152 + randPort.nextInt(16384); + AtomicInteger tempPortObj = new AtomicInteger(tempPort); + while (simulationPorts.containsValue(tempPortObj)) { + int newTempPort = 49152 + randPort.nextInt(16384); + tempPortObj.set(newTempPort); + } + simulationPorts.put(simIdKey, tempPortObj); + return tempPortObj.get(); + //TODO: test host:port is available + } else { + throw new Exception("The simulation id already exists. This indicates that the simulation id is part of a" + + "simulation in progress."); + } + } + +} \ No newline at end of file diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/simulation/SimulationProcess.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/simulation/SimulationProcess.java index 043954a43..bc53f5769 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/simulation/SimulationProcess.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/simulation/SimulationProcess.java @@ -1,27 +1,11 @@ package gov.pnnl.goss.gridappsd.simulation; -import gov.pnnl.goss.gridappsd.api.AppManager; -import gov.pnnl.goss.gridappsd.api.LogManager; -import gov.pnnl.goss.gridappsd.api.ServiceManager; -import gov.pnnl.goss.gridappsd.configuration.GLDAllConfigurationHandler; -import gov.pnnl.goss.gridappsd.configuration.OchreAllConfigurationHandler; -import gov.pnnl.goss.gridappsd.dto.FncsBridgeResponse; -import gov.pnnl.goss.gridappsd.dto.LogMessage; -import gov.pnnl.goss.gridappsd.dto.ServiceInfo; -import gov.pnnl.goss.gridappsd.dto.LogMessage.LogLevel; -import gov.pnnl.goss.gridappsd.dto.LogMessage.ProcessStatus; -import gov.pnnl.goss.gridappsd.dto.SimulationConfig; -import gov.pnnl.goss.gridappsd.dto.SimulationContext; -import gov.pnnl.goss.gridappsd.utils.GridAppsDConstants; -import gov.pnnl.goss.gridappsd.utils.RunCommandLine; - import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.Serializable; import java.util.ArrayList; -import java.util.Date; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -30,13 +14,26 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.gson.Gson; + +import gov.pnnl.goss.gridappsd.api.AppManager; +import gov.pnnl.goss.gridappsd.api.LogManager; +import gov.pnnl.goss.gridappsd.api.ServiceManager; +import gov.pnnl.goss.gridappsd.configuration.GLDAllConfigurationHandler; +import gov.pnnl.goss.gridappsd.configuration.OchreAllConfigurationHandler; +import gov.pnnl.goss.gridappsd.dto.FncsBridgeResponse; +import gov.pnnl.goss.gridappsd.dto.LogMessage.ProcessStatus; +import gov.pnnl.goss.gridappsd.dto.PowerSystemConfig; +import gov.pnnl.goss.gridappsd.dto.ServiceInfo; +import gov.pnnl.goss.gridappsd.dto.SimulationConfig; +import gov.pnnl.goss.gridappsd.dto.SimulationContext; +import gov.pnnl.goss.gridappsd.utils.GridAppsDConstants; +import gov.pnnl.goss.gridappsd.utils.RunCommandLine; import pnnl.goss.core.Client; import pnnl.goss.core.DataResponse; import pnnl.goss.core.GossResponseEvent; import pnnl.goss.core.security.SecurityConfig; -import com.google.gson.Gson; - public class SimulationProcess extends Thread { private static Logger log = LoggerFactory.getLogger(SimulationProcess.class); private static String gridlabdConstant = "GridLAB-D"; @@ -69,10 +66,12 @@ class SimulationTracker { Client client; SecurityConfig securityConfig; Map simulationContex; + PowerSystemConfig powerSystemConfig; public SimulationProcess(SimulationContext simContext, ServiceManager serviceManager, SimulationConfig simulationConfig, String simulationId, LogManager logManager, - AppManager appManager, Client client, SecurityConfig securityConfig, Map simulationContex){ + AppManager appManager, Client client, SecurityConfig securityConfig, + Map simulationContex, PowerSystemConfig powerSystemConfig){ this.simContext = simContext; this.serviceManager = serviceManager; this.simulationConfig = simulationConfig; @@ -82,6 +81,7 @@ public SimulationProcess(SimulationContext simContext, ServiceManager serviceMan this.client = client; this.securityConfig = securityConfig; this.simulationContex = simulationContex; + this.powerSystemConfig = powerSystemConfig; } @@ -93,8 +93,17 @@ public void run() { InitializedTracker isInitialized = new InitializedTracker(); SimulationTracker isFinished = new SimulationTracker(); try{ - - File simulationFile = new File(simContext.getStartupFile()); + + String simulator = powerSystemConfig.simulator_config.simulator; + String simulatorPath = serviceManager.getService(powerSystemConfig.simulator_config.getSimulator()).getExecution_path(); + String simulatorWorkingDir = powerSystemConfig.simulator_config.getSimulation_work_dir(); + + File simulationFile = null; + if(simulator.equals("GridLAB-D")) + simulationFile = new File(simulatorWorkingDir+File.separator+"model_startup.glm"); + else if(simulator.equals("OCHRE")) + simulationFile = new File(simulatorWorkingDir+File.separator+"ochre_helics_config.json"); + //if(simulationConfig!=null && simulationConfig.model_creation_config!=null && simulationConfig.model_creation_config.schedule_name!=null && simulationConfig.model_creation_config.schedule_name.trim().length()>0){ File serviceDir = serviceManager.getServiceConfigDirectory(); @@ -114,13 +123,13 @@ public void run() { ProcessBuilder simulatorBuilder = new ProcessBuilder(); List commands = new ArrayList(); - if(simulationConfig.getSimulator().equals(OchreAllConfigurationHandler.TYPENAME)){ - simContext.setNumFederates(42); - logManager.info(ProcessStatus.RUNNING, simulationId, "Setting num federates "); - + if(simulator.equals(OchreAllConfigurationHandler.TYPENAME)){ + + //Start gridlabd // simulationContext.put("simulationFile",tempDataPathDir.getAbsolutePath()+File.separator+"model_startup.glm"); - File gldStartupFile = new File(simContext.simulationDir+File.separator+"inputs"+File.separator+"gridlabd"+File.separator+"IEEE-13"+File.separator+"IEEE-13_Houses.glm"); + //File gldStartupFile = new File(simContext.simulationDir+File.separator+"inputs"+File.separator+"gridlabd"+File.separator+"IEEE-13"+File.separator+"IEEE-13_Houses.glm"); + File gldStartupFile = new File(simulatorWorkingDir+File.separator+"model_startup.glm"); String gldSimulatorPath = serviceManager.getService(gridlabdConstant).getExecution_path(); // commands.add(simContext.getSimulatorPath()); commands.add(gldSimulatorPath); @@ -139,8 +148,8 @@ public void run() { //Start ochre commands = new ArrayList(); - commands.add(simContext.getSimulatorPath()); - ServiceInfo serviceInfo = serviceManager.getService(simulationConfig.getSimulator()); + commands.add(simulatorPath); + ServiceInfo serviceInfo = serviceManager.getService(simulator); List staticArgsList = serviceInfo.getStatic_args(); for(String staticArg : staticArgsList) { if(staticArg!=null){ @@ -160,12 +169,12 @@ public void run() { logManager.info(ProcessStatus.RUNNING, simulationId, "Command for ochre ready "+String.join(" ",commands)); } - else if(simulationConfig.getSimulator().equals(gridlabdConstant)){ - commands.add(simContext.getSimulatorPath()); + else if(powerSystemConfig.simulator_config.getSimulator().equals(gridlabdConstant)){ + commands.add(simulatorPath); commands.add(simulationFile.getAbsolutePath()); simulatorBuilder.command(commands); } else { - log.warn("No known simulator: "+simulationConfig.getSimulator()); + log.warn("No known simulator: "+simulator); } simulatorBuilder.redirectErrorStream(true); simulatorBuilder.redirectOutput(); @@ -181,11 +190,11 @@ else if(simulationConfig.getSimulator().equals(gridlabdConstant)){ //TODO: check if GridLAB-D is started correctly and send publish simulation status accordingly - logManager.info(ProcessStatus.RUNNING, simulationId, simulationConfig.getSimulator()+" simulator started"); + logManager.info(ProcessStatus.RUNNING, simulationId, simulator+" simulator started"); //Subscribe to fncs-goss-bridge output topic GossFncsResponseEvent gossFncsResponseEvent = new GossFncsResponseEvent(logManager, isInitialized, isFinished, simulationId); - client.subscribe(GridAppsDConstants.topic_COSIM_output, gossFncsResponseEvent); + client.subscribe("/topic/"+GridAppsDConstants.topic_COSIM_output+"."+simulationId, gossFncsResponseEvent); logManager.info(ProcessStatus.RUNNING, simulationId, "Checking if co-simulation is initialized, currently "+isInitialized.isInited); @@ -195,7 +204,7 @@ else if(simulationConfig.getSimulator().equals(gridlabdConstant)){ //TODO add limiting how long it checks for initialized, or cancel if the fncs process exits //This call would return true/false for initialization and simulation output of time step 0. - client.publish(GridAppsDConstants.topic_COSIM_input, "{\"command\": \"isInitialized\"}"); + client.publish(GridAppsDConstants.topic_COSIM_input+"."+simulationId, "{\"command\": \"isInitialized\"}"); initAttempts++; Thread.sleep(1000); @@ -216,7 +225,7 @@ else if(simulationConfig.getSimulator().equals(gridlabdConstant)){ } //call to stop the simulation - client.publish(GridAppsDConstants.topic_COSIM_input, "{\"command\": \"stop\"}"); + client.publish(GridAppsDConstants.topic_COSIM_input+"."+simulationId, "{\"command\": \"stop\"}"); logManager.info(ProcessStatus.COMPLETE, simulationId, "Simulation "+simulationId+" complete"); } catch(Exception e){ @@ -250,7 +259,7 @@ private void startSimulation(GossFncsResponseEvent gossEvent, SimulationConfig s // Send the start simulation command to the fncsgossbridge so that it runs it's time loop to move the fncs simulation forward logManager.debug(ProcessStatus.RUNNING, simulationId, "Sending start simulation to bridge."); String message = "{\"command\": \"StartSimulation\"}"; - client.publish(GridAppsDConstants.topic_COSIM_input, message); + client.publish(GridAppsDConstants.topic_COSIM_input+"."+simulationId, message); } private void watch(final Process process, String processName) { diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/testmanager/HistoricalComparison.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/testmanager/HistoricalComparison.java index ed89e5933..b8c727e20 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/testmanager/HistoricalComparison.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/testmanager/HistoricalComparison.java @@ -17,6 +17,7 @@ import gov.pnnl.goss.gridappsd.api.DataManager; import gov.pnnl.goss.gridappsd.dto.RequestTimeseriesData; +import gov.pnnl.goss.gridappsd.dto.RequestTimeseriesDataBasic; import gov.pnnl.goss.gridappsd.dto.TestConfig; import pnnl.goss.core.Client; @@ -91,7 +92,7 @@ public String timeSeriesQuery(String simulationId, String hasMrid, queryFilter = new HashMap(); queryFilter.put("simulation_id", simulationId); - RequestTimeseriesData request = new RequestTimeseriesData(); + RequestTimeseriesDataBasic request = new RequestTimeseriesDataBasic(); request.setSimulationYear(0); request.setQueryMeasurement("simulation"); request.setQueryFilter(queryFilter); diff --git a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/utils/GridAppsDConstants.java b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/utils/GridAppsDConstants.java index 707228671..5c0f58844 100644 --- a/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/utils/GridAppsDConstants.java +++ b/gov.pnnl.goss.gridappsd/src/gov/pnnl/goss/gridappsd/utils/GridAppsDConstants.java @@ -72,6 +72,7 @@ public class GridAppsDConstants { public static final String topic_requestSimulationStatus = topic_process_prefix+".request.status.simulation"; public static final String topic_requestPlatformStatus = topic_process_prefix+".request.status.platform"; public static final String topic_requestMyRoles = topic_process_prefix+".request.roles"; + public static final String topic_requestField = topic_process_prefix+".request.field"; // Remote Application topics public static final String topic_remoteapp_prefix = topic_prefix+".remoteapp"; @@ -88,6 +89,10 @@ public class GridAppsDConstants { public static final String topic_platformLog = topic_prefix+".platform.log"; + + //Field Request Topics + public static final String topic_requestFieldContext = topic_process_prefix+".request.field.context"; + //App Request Topics public static final String topic_app_register = topic_requestApp+".register"; public static final String topic_app_list = topic_requestApp+".list"; @@ -156,6 +161,7 @@ public class GridAppsDConstants { public static final String PROVEN_PATH = "proven.path"; public static final String PROVEN_WRITE_PATH = "proven.write.path"; public static final String PROVEN_QUERY_PATH = "proven.query.path"; + public static final String PROVEN_ADVANCED_QUERY_PATH = "proven.advanced_query.path"; public static final SimpleDateFormat SDF_SIMULATION_REQUEST = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss"); public static final SimpleDateFormat SDF_GLM_CLOCK = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); diff --git a/gov.pnnl.goss.gridappsd/test/gov/pnnl/goss/gridappsd/ProcessEventTests.java b/gov.pnnl.goss.gridappsd/test/gov/pnnl/goss/gridappsd/ProcessEventTests.java index 12eb36988..70d522119 100644 --- a/gov.pnnl.goss.gridappsd/test/gov/pnnl/goss/gridappsd/ProcessEventTests.java +++ b/gov.pnnl.goss.gridappsd/test/gov/pnnl/goss/gridappsd/ProcessEventTests.java @@ -42,6 +42,7 @@ import gov.pnnl.goss.gridappsd.api.AppManager; import gov.pnnl.goss.gridappsd.api.ConfigurationManager; import gov.pnnl.goss.gridappsd.api.DataManager; +import gov.pnnl.goss.gridappsd.api.FieldBusManager; import gov.pnnl.goss.gridappsd.api.LogDataManager; import gov.pnnl.goss.gridappsd.api.LogManager; import gov.pnnl.goss.gridappsd.api.RoleManager; @@ -98,6 +99,8 @@ public class ProcessEventTests { TestManager testManager; @Mock SecurityConfig securityConfig; + @Mock + FieldBusManager fieldBusManager; @Captor ArgumentCaptor argCaptor; @@ -116,7 +119,7 @@ public void testWhen_RequestPGQueryRequestSent() throws ParseException{ DataManager dataManager = new DataManagerImpl(clientFactory, logManager); ProcessEvent pe = new ProcessEvent(processManager, client, - newSimulationProcess, configurationManager, simulationManager, appManager, logManager, serviceManager, dataManager, testManager, securityConfig); + newSimulationProcess, configurationManager, simulationManager, appManager, logManager, serviceManager, dataManager, testManager, securityConfig, fieldBusManager); PowergridModelDataRequest pgDataRequest = new PowergridModelDataRequest(); String queryString = "select ?line_name ?subregion_name ?region_name WHERE {?line rdf:type cim:Line."+ @@ -147,7 +150,7 @@ public void testWhen_RequestPGQueryObjectTypesRequestSent() throws ParseExceptio DataManager dataManager = new DataManagerImpl(clientFactory, logManager); ProcessEvent pe = new ProcessEvent(processManager, client, - newSimulationProcess, configurationManager, simulationManager, appManager, logManager, serviceManager, dataManager, testManager, securityConfig); + newSimulationProcess, configurationManager, simulationManager, appManager, logManager, serviceManager, dataManager, testManager, securityConfig, fieldBusManager); PowergridModelDataRequest pgDataRequest = new PowergridModelDataRequest(); @@ -171,7 +174,7 @@ public void testWhen_RequestPGQueryModelNamesRequestSent() throws ParseException DataManager dataManager = new DataManagerImpl(clientFactory, logManager); ProcessEvent pe = new ProcessEvent(processManager, client, - newSimulationProcess, configurationManager, simulationManager, appManager, logManager, serviceManager, dataManager, testManager, securityConfig); + newSimulationProcess, configurationManager, simulationManager, appManager, logManager, serviceManager, dataManager, testManager, securityConfig, fieldBusManager); PowergridModelDataRequest pgDataRequest = new PowergridModelDataRequest(); diff --git a/gov.pnnl.goss.gridappsd/test/gov/pnnl/goss/gridappsd/ProcessManagerComponentTests.java b/gov.pnnl.goss.gridappsd/test/gov/pnnl/goss/gridappsd/ProcessManagerComponentTests.java index c915db643..30a743f30 100644 --- a/gov.pnnl.goss.gridappsd/test/gov/pnnl/goss/gridappsd/ProcessManagerComponentTests.java +++ b/gov.pnnl.goss.gridappsd/test/gov/pnnl/goss/gridappsd/ProcessManagerComponentTests.java @@ -43,6 +43,7 @@ import static org.junit.Assert.assertNotNull; import gov.pnnl.goss.gridappsd.api.AppManager; import gov.pnnl.goss.gridappsd.api.ConfigurationManager; +import gov.pnnl.goss.gridappsd.api.FieldBusManager; import gov.pnnl.goss.gridappsd.api.LogManager; import gov.pnnl.goss.gridappsd.api.SimulationManager; import gov.pnnl.goss.gridappsd.api.TestManager; @@ -102,6 +103,9 @@ public class ProcessManagerComponentTests { @Captor ArgumentCaptor argCaptorLogMessage; + + @Mock + FieldBusManager fieldBusManager; @@ -232,7 +236,7 @@ public void simIdPublishedWhen_messageSent(){ ProcessManagerImpl processManager = new ProcessManagerImpl( clientFactory, configurationManager, simulationManager, - logManager, appManager, newSimulationProcess, testManager); + logManager, appManager, newSimulationProcess, testManager, fieldBusManager); processManager.start(); Mockito.verify(client).subscribe(Mockito.anyString(), gossResponseEventArgCaptor.capture()); @@ -320,7 +324,7 @@ public void processStartedWhen_simulationTopicSent(){ ProcessManagerImpl processManager = new ProcessManagerImpl( clientFactory, configurationManager, simulationManager, - logManager, appManager, newSimulationProcess, testManager); + logManager, appManager, newSimulationProcess, testManager,fieldBusManager); processManager.start(); Mockito.verify(client).subscribe(Mockito.anyString(), gossResponseEventArgCaptor.capture()); diff --git a/gov.pnnl.goss.gridappsd/test/gov/pnnl/goss/gridappsd/TestManagerComponentTest.java b/gov.pnnl.goss.gridappsd/test/gov/pnnl/goss/gridappsd/TestManagerComponentTest.java index 09e7d1284..c8535f296 100644 --- a/gov.pnnl.goss.gridappsd/test/gov/pnnl/goss/gridappsd/TestManagerComponentTest.java +++ b/gov.pnnl.goss.gridappsd/test/gov/pnnl/goss/gridappsd/TestManagerComponentTest.java @@ -37,6 +37,7 @@ import gov.pnnl.goss.gridappsd.dto.LogMessage.LogLevel; import gov.pnnl.goss.gridappsd.dto.LogMessage.ProcessStatus; import gov.pnnl.goss.gridappsd.dto.RequestTimeseriesData; +import gov.pnnl.goss.gridappsd.dto.RequestTimeseriesDataBasic; import gov.pnnl.goss.gridappsd.dto.TestConfig; //import gov.pnnl.goss.gridappsd.dto.TestConfiguration; //import gov.pnnl.goss.gridappsd.dto.TestScript; @@ -206,7 +207,7 @@ public void proven(){ ProvenTimeSeriesDataManagerImpl provenTimeSeriesDataManager = new ProvenTimeSeriesDataManagerImpl(); - RequestTimeseriesData request = new RequestTimeseriesData(); + RequestTimeseriesDataBasic request = new RequestTimeseriesDataBasic(); HashMap queryFilter = new HashMap (); queryFilter.put("hasSimulationId", "145774843"); request.setQueryMeasurement("simulation"); diff --git a/opendss/opendsscmd b/opendss/opendsscmd index 131b0c7a0..a36120bf1 100755 Binary files a/opendss/opendsscmd and b/opendss/opendsscmd differ diff --git a/output_message.json b/output_message.json new file mode 100644 index 000000000..5e6c3a73d --- /dev/null +++ b/output_message.json @@ -0,0 +1 @@ +{"feeders": {"feeder_id": "_49AD8E07-3BF9-A4E2-CB8F-C3722F837B62", "addressable_equipment": ["_52DE9189-20DC-4C73-BDEE-E960FE1F9493", "_CE5D0651-676B-4AF3-8D67-41BF1B33E30C", "_43EF8365-F932-409B-A51E-FBED3F6DFFAA", "_43EF8365-F932-409B-A51E-FBED3F6DFFAA", "_2858B6C2-0886-4269-884C-06FA8B887319", "_517413CB-6977-46FA-8911-C82332E42884", "_CE5D0651-676B-4AF3-8D67-41BF1B33E30C", "_517413CB-6977-46FA-8911-C82332E42884", "_2858B6C2-0886-4269-884C-06FA8B887319"], "unaddressable_equipment": ["_44FC5A86-A099-45B8-B847-F685C5027AFB", "_B6363F07-B1BC-420B-AA4C-A34BB8F05827", "_E2E0FC64-8D45-4C55-BDB9-EAB827A46FBC", "_7c6f94c1-1419-4582-ab2d-a0b11772c26b", "_b393e719-0981-4498-9d96-07f1be7de009", "_f11a9ad9-5b68-483b-b52f-dd4af07bb77d", "_44FC5A86-A099-45B8-B847-F685C5027AFB", "_B6363F07-B1BC-420B-AA4C-A34BB8F05827", "_E2E0FC64-8D45-4C55-BDB9-EAB827A46FBC", "_A04CDFB1-E951-4FC4-8882-0323CD70AE3C", "_44FC5A86-A099-45B8-B847-F685C5027AFB", "_B6363F07-B1BC-420B-AA4C-A34BB8F05827", "_E2E0FC64-8D45-4C55-BDB9-EAB827A46FBC", "_5ad9e784-5b6c-4f2c-bc4d-1ccc31cfd96b", "_8dc4079e-6bbb-491d-9f4c-0c240228b647", "_fc4adc62-5608-467f-aab7-75893b574998", "_5d00b173-726b-4f64-b93e-c60648276c66", "_8d72f997-ba3e-4954-91b6-62fc3304d165", "_f782d376-467f-46bc-a0f5-3f500d6570aa", "_0a2f7676-f619-405b-bb80-8f51f4d7a25f", "_9f4bef6c-c68d-42a9-ade6-206a8b365ce9", "_c16593db-3c64-4504-9387-17f19f558549", "_44FC5A86-A099-45B8-B847-F685C5027AFB", "_B6363F07-B1BC-420B-AA4C-A34BB8F05827", "_E2E0FC64-8D45-4C55-BDB9-EAB827A46FBC", "_FBE26B35-13AB-457D-9795-DF58B28E309D", "_1C6781A2-5B9D-4525-8A9B-F9B32C4C4AC0", "_A04CDFB1-E951-4FC4-8882-0323CD70AE3C", "_198ca97f-d307-4fe7-8a79-5caa1c3e45d0", "_907b4408-7271-4407-9e38-3d019dc1bc68", "_cc70103a-126e-4ec1-8583-12412dd8195d", "_27897da2-d7e1-438c-a6e4-4b3cfe8e79fa", "_d92644c9-5bd2-4312-8e31-3bec6510e646", "_dad6dd20-9bfc-4bd9-b76e-2e0fd3b0d5ba", "_7ca7c18c-3861-47bf-82cf-5a72d618b18a", "_80ef10f9-3f4f-4fd2-8262-caedf7442fda", "_cd64f70b-91d8-460b-af28-688e9709f319", "_0cbdf98b-b5e4-4bc3-93d6-08db08947794", "_0f4457a6-a3cb-42b0-a06c-b31d5c7a17ff", "_bc165aa6-347d-4551-8abf-016044675a6f", "_65599f7e-3e93-4456-a2b1-bba7a46337b6", "_6bb8ef03-ec84-421f-8d28-cd1a3813e614", "_FBE26B35-13AB-457D-9795-DF58B28E309D", "_8b6bd68f-c84d-45e1-91b9-b0406fbaa3b1", "_d56a4982-0c80-45d0-8cb8-c24097138b63", "_d638fbbc-9b85-416e-87b8-37c9785e1611", "_1C6781A2-5B9D-4525-8A9B-F9B32C4C4AC0", "_0BBD0EA3-F665-465B-86FD-FC8B8466AD53", "_c7c58261-4885-46ee-beb9-c94c6c29451f", "_98a81464-d7b6-4044-9b48-a92e179884dc", "_d8ea43c7-2107-4975-9ddb-4279628daf18", "_2d9ed148-d492-4e7d-b9af-81a407e74a59", "_4e30ae83-418c-4cfb-99eb-5572e00b4ec4", "_d23fd30b-e3f9-4a43-b3c4-2f2697dba851", "_0BBD0EA3-F665-465B-86FD-FC8B8466AD53", "_7a436400-3a77-4eaf-bb04-ef7954fcbdd9", "_5f1dfa9f-e754-471d-9c74-c1a9441e95a3", "_84f75532-a514-4355-bf0e-2f8d82c736ae", "_e1b4fd36-01d0-4d7d-9223-2279911fe8c3", "_1E6B5C97-C4E8-4CED-B9A5-6E69F389DA93", "_5500424b-9931-4f09-a22b-d24a47517920", "_bd95505f-3f55-43d2-b8b2-2c97b2c86603", "_f3001cb9-4c00-45ab-a73f-537be73f583c", "_37fc9b9a-0bc9-4417-8214-52afc237735f", "_697532b4-9520-4de4-80e9-2b6a77c8a089", "_d9e22ddd-f4f2-426c-911d-cf08ff5cc9a0", "_1E6B5C97-C4E8-4CED-B9A5-6E69F389DA93", "_5ae00771-adeb-4ee2-92a3-7c991c579ce1", "_77cf5e05-b332-4203-937a-53f58b4f4585", "_247f50ee-6bc5-4588-bdf1-9b480e09840e", "_5842f2db-ad93-494a-a372-c8e83e637147", "_87c273f2-8e55-4169-adeb-2df020776c06", "_919d79f9-9719-492b-bf8b-46cffc7579ad", "_9d580686-9c5d-42a6-9e0b-ef08c7d80256", "_ab19de32-3fad-4654-b546-6b785b2d65e3", "_51037d29-941b-4e9f-ae86-99dd37bb2c9d", "_54e2019e-e234-4dbb-85d6-227b245040ae", "_48720b2c-7908-4f18-a80d-f7f7f4099753", "_683bbf2f-7ea6-45c6-805e-5e4b7f5000a2", "_0ab88ca4-fb60-4a67-8f77-5f15af245b64", "_25938754-4fe8-4621-9414-7d519bc9fde3", "_78116a30-9d83-4715-a9d2-dda61687a0b9", "_7cc37959-2a82-4911-8a23-8ad09378c85c", "_cd76b30b-8e1c-45fb-b03a-79847254ead8", "_d057e1e2-71ad-4293-b89e-e9e9e84a2522", "_f0af2090-d2aa-40fb-8878-45d75c4ae59f", "_07b694ae-bde0-431c-a740-362a9f476949", "_c3a9b1e7-7a52-4fa5-a199-1fd6035abc21", "_d2d52e14-2111-486e-a59a-d8c5b5f7bf92", "_8E180773-2A9B-4136-BC9A-132A52C8E276", "_0fe87976-0177-42f3-817b-b468225220b2", "_2d31c620-a2f9-4f84-9102-9a8fe574ab6b", "_8E180773-2A9B-4136-BC9A-132A52C8E276", "_fad827c5-f344-498e-ab39-29883d4c6bb6", "_7a84c113-d427-4802-a769-b6edc48451c7", "_162b4555-f748-4829-8e71-bbbecf4e4bcb", "_eb606875-f620-4c4e-b559-cd587ba0ecf8", "_6c08f0e8-eb6f-4261-a3f6-3aa9d1e99c75", "_7060D0BB-B30D-4932-8FA1-40820A0FC4D0", "_3e3bdc6c-d985-4659-9cb7-82ea8212ba4f", "_59c9a186-c0a8-4f85-a524-d6ef0d27700a", "_5c9a17db-6f03-4626-9464-41d3a5ddeb15", "_d3a28545-dbfd-4cc4-9f3a-52e2ff130d93", "_8007b83e-40fa-4e87-9df7-a1097dc3b3e7", "_2abd660f-3dc2-4611-95a0-9adebae7fe3b", "_387c6bab-0a0a-4c90-9b19-73a902ab1e28", "_4da919f1-762f-4755-b674-5faccf3faec6", "_7060D0BB-B30D-4932-8FA1-40820A0FC4D0", "_30c1c7d3-284e-4455-a398-6becc3bbc419", "_c3753e40-e1c9-4900-83ff-93e50887c281", "_0a2d1460-0def-479a-9f66-a7963a5619de", "_a5edf08d-b163-4ff1-a145-bf8267fed689", "_b0a947d6-9890-4c7e-a5dd-11fce0760768", "_21e0ccb4-f0d0-43bd-bc70-06447e050e41", "_4e068301-03a3-43ee-8709-744b2f4c8158", "_6e809a5d-d7dd-4c35-882c-3f20b6da557a", "_874dae15-637c-4c9e-bee1-d859ac3acf12", "_306f6f7f-bf58-40e0-9343-62de5f7d9bce", "_5e3ded69-b21a-4850-bc90-ebe5bf7ef970", "_4db89787-187e-4855-ae11-5e10ebf69b00", "_615d912b-7ece-44e7-9bbe-d9a8d8b41e4a", "_c4b054eb-540c-44fd-9113-388d682ede70", "_ff45d777-d004-498c-8ad9-cea09c4f91d2", "_ABF53597-A808-422A-B7EE-552F24D83A5F", "_7cdb4378-79d9-4b6b-96c1-f3b55cbbc40d", "_7d0172fb-0d05-4d30-bb80-4cb3619271f4", "_f6662bb7-67f0-452f-ab3a-e430723626e1", "_def62366-746e-4fcb-b3ee-ebebb90d72d4", "_df6e0f8d-1af3-49f2-803b-454c93b19773", "_e87a1d11-7eaf-4535-9745-1e1a8e6b8e11", "_ABF53597-A808-422A-B7EE-552F24D83A5F", "_45395C84-F20A-4F5A-977F-B80348256421", "_17A934C7-1510-481F-BAD7-189058957FF1", "_5105857b-b776-4824-99fa-a324fac89dec", "_e4712e37-525d-43f4-b880-d126a4d9c603", "_aeb839c8-9228-4fff-a538-d2699191aa2b", "_bcdf5a28-bce3-46e6-91a2-8eb3781605eb", "_d054a67b-8e35-4b2a-bd32-6cbfbde656a6", "_502fa582-ba5f-496f-882a-260d909a9b9f", "_198ea415-1a31-4d0e-b31d-950e31a1346a", "_53cfe1f2-0064-46d6-bc8a-54c08992ec95", "_67214379-2364-4d28-9025-10eb7a90cff4", "_b59a587c-fd11-41ad-9172-f83d78d54ac3", "_d11aff18-688e-45f0-82c2-a277fa1b97c0", "_14aae74c-674a-4d1e-a911-4779136ff0ba", "_17A934C7-1510-481F-BAD7-189058957FF1", "_3ad2ed0c-59fd-4663-a2cf-0b8e08c40061", "_ee47f9b3-eb23-4134-9d66-63055155dc27", "_3dbf1b7a-905f-41de-8ab2-e5451623e69e", "_628087e8-502d-444f-a014-fb11514fa82c", "_95407ba3-6edf-43ec-b6c1-e3283b916f63", "_e55a4c7a-c006-4596-b658-e23bc771b5cb", "_c462ff83-15a8-4e0d-9708-f64f41a6a8ce", "_3ff8a15e-f522-47bc-9ca4-0e06c3d58ef0", "_5332bdb4-b316-4166-a37f-8531db278687", "_25b08cbe-ee08-4787-bb32-3e87c660b679", "_a19c2246-4854-45e4-be1e-0169686dfe65", "_4c491539-dfc1-4fda-9841-3bf10348e2fa", "_e92f7019-68ec-4ee5-8fc6-e66580f24794", "_D34B0D01-B082-4081-A3CC-B68B9B8313A4", "_4C04F838-62AA-475E-AEFA-A63B7C889C13", "_45395C84-F20A-4F5A-977F-B80348256421", "_4812ecc5-53dd-4f8e-8375-74ee2c2b3edd", "_70cb7d70-edc3-4223-a9c1-d99be8bc8c52", "_e77eeaf8-7c47-49f7-b932-5fc89b8b628c", "_08175e8f-b762-4c9b-92c4-07f369f69bd4", "_617f766c-5379-49e5-a036-9442f73698aa", "_ffc4a375-69d5-4c91-aa0a-54e4735d30ba", "_1f8096d5-8e7e-4292-bb96-98b5c2efefbc", "_5544e071-22c3-4c7f-b15c-98aac3edfa6f", "_7fcfa7bd-f93a-4f03-8111-43b8851cb078", "_0f5150f9-f959-4f7b-a661-d80afe862e58", "_35a3ba96-f644-4144-b955-1bc959c2311b", "_c8a56420-f87b-4ce4-ac38-ba431ecfcdb2", "_63abd794-ccfc-467d-aa2a-b99c7a0b636a", "_f3d3c954-605b-4a20-b1d9-18d69b5ca3fb", "_813c727c-973e-4185-8bcb-482d7b01eaba", "_90b9792b-e126-4aa2-832e-c99ac3702516", "_e8b9bcff-5105-4f74-8b85-adf530750445", "_0c27bd24-120f-40b2-b0dd-e7cc58e7ebc7", "_142ea530-f364-4dd9-887d-390c4aca512e", "_569f6c28-79d6-4192-a238-1294a899cee3", "_4C04F838-62AA-475E-AEFA-A63B7C889C13", "_881b2079-132d-42b6-a2e4-3d9a954199fc", "_aaa5a1e5-ddd2-4324-b1d7-0b2d1b251f32", "_c549a164-fcff-4b13-9c64-5173fb43994f", "_D34B0D01-B082-4081-A3CC-B68B9B8313A4", "_ABF877D7-DAC2-4BF0-AB58-9A8A02E92EB3", "_a4da4cea-b5b0-4f42-af2e-33ed8aa9e9dd", "_c0b0b188-ad4a-4be3-90c1-2fbb1f507a15", "_357b3424-9587-4839-8d63-e6818f43cecb", "_2f50b72c-d10f-4197-b2b9-e7268bc7c6d9", "_488bdd39-7f23-4aff-bff0-66abe4c7e2a7", "_ABF877D7-DAC2-4BF0-AB58-9A8A02E92EB3", "_6f1c625b-7fe9-4020-9ba6-4e7293c01771", "_6593c292-7c82-482f-99ab-61094ffc214a", "_7d0b45c3-8aaf-4d87-8bf7-7e9b8433b384", "_259E820F-B4AF-4E1A-8271-687534EDAECC", "_40f101aa-e9f1-45ee-ba01-f743fc956e64", "_6aba464f-3217-4e5f-b725-6b1a37aa225f", "_daaf1a85-7aad-4cb6-8fd3-13390711fdfb", "_416e0482-8b0b-4255-baf0-830e9910d377", "_7d30fc85-4e4f-40f7-82e1-04313602ddbd", "_f2560013-e260-44af-80f9-3cc218d9ef19", "_259E820F-B4AF-4E1A-8271-687534EDAECC", "_c5545620-2c8c-42ff-b59d-33cd7e02b8e5", "_dda6be90-3cd1-4a27-a691-3f95aa4e4e13", "_f3cc955e-8013-447a-848e-4c7af516cb34", "_7bbbda89-9830-472c-82bc-4e4f599369bb", "_a870a258-34be-46b8-a4de-faee32275a9a", "_bc0d2bad-2c6b-4266-8c47-b32a536288f0", "_259E820F-B4AF-4E1A-8271-687534EDAECC", "_0c48c74a-ceee-4c99-bd73-28079561ca7a", "_3c60208a-8ef8-483c-828b-30ee42d402dc", "_43f80e34-281e-4baa-8aba-d931a9a3ab87", "_40ac2899-1d2a-469f-a14a-1e14ea29d172", "_8e7f04ee-a032-4128-838e-a3442a1c3026", "_ab18a8e1-f023-4f9e-bf02-c75bf05164df", "_9f5cb9c4-71d6-4f2b-9dc1-26c7e9f84410", "_aec42b89-f3c0-47e9-b21a-82736b2a1149", "_baccfd49-ec98-4380-8be9-d242dc8611f3", "_95b3fb0f-6430-4679-a3f5-5bf37515620d", "_ca50f7c2-b14c-405a-941b-fe2acba3419a", "_f5412896-9ac0-44d9-8a67-4ab020a3f0d3"], "connectivity_node": ["_04984C4D-CC29-477A-9AF4-61AC7D74F16F", "_A8A25B50-3AE3-4A31-A18B-B3FA13397ED3", "_7BEDDADD-0A14-429F-8601-9EA8B892CA6E"], "switch_areas": [{"boundary_switches": ["_52DE9189-20DC-4C73-BDEE-E960FE1F9493", "_CE5D0651-676B-4AF3-8D67-41BF1B33E30C", "_43EF8365-F932-409B-A51E-FBED3F6DFFAA"], "addressable_equipment": ["_67B57539-590B-4158-9CBB-9DBA2FE6C1F0"], "unaddressable_equipment": ["_44FC5A86-A099-45B8-B847-F685C5027AFB", "_B6363F07-B1BC-420B-AA4C-A34BB8F05827", "_E2E0FC64-8D45-4C55-BDB9-EAB827A46FBC", "_7c6f94c1-1419-4582-ab2d-a0b11772c26b", "_b393e719-0981-4498-9d96-07f1be7de009", "_f11a9ad9-5b68-483b-b52f-dd4af07bb77d", "_44FC5A86-A099-45B8-B847-F685C5027AFB", "_B6363F07-B1BC-420B-AA4C-A34BB8F05827", "_E2E0FC64-8D45-4C55-BDB9-EAB827A46FBC", "_A04CDFB1-E951-4FC4-8882-0323CD70AE3C", "_44FC5A86-A099-45B8-B847-F685C5027AFB", "_B6363F07-B1BC-420B-AA4C-A34BB8F05827", "_E2E0FC64-8D45-4C55-BDB9-EAB827A46FBC", "_5ad9e784-5b6c-4f2c-bc4d-1ccc31cfd96b", "_8dc4079e-6bbb-491d-9f4c-0c240228b647", "_fc4adc62-5608-467f-aab7-75893b574998", "_5d00b173-726b-4f64-b93e-c60648276c66", "_8d72f997-ba3e-4954-91b6-62fc3304d165", "_f782d376-467f-46bc-a0f5-3f500d6570aa", "_0a2f7676-f619-405b-bb80-8f51f4d7a25f", "_9f4bef6c-c68d-42a9-ade6-206a8b365ce9", "_c16593db-3c64-4504-9387-17f19f558549", "_44FC5A86-A099-45B8-B847-F685C5027AFB", "_B6363F07-B1BC-420B-AA4C-A34BB8F05827", "_E2E0FC64-8D45-4C55-BDB9-EAB827A46FBC", "_FBE26B35-13AB-457D-9795-DF58B28E309D", "_1C6781A2-5B9D-4525-8A9B-F9B32C4C4AC0", "_A04CDFB1-E951-4FC4-8882-0323CD70AE3C", "_198ca97f-d307-4fe7-8a79-5caa1c3e45d0", "_907b4408-7271-4407-9e38-3d019dc1bc68", "_cc70103a-126e-4ec1-8583-12412dd8195d", "_27897da2-d7e1-438c-a6e4-4b3cfe8e79fa", "_d92644c9-5bd2-4312-8e31-3bec6510e646", "_dad6dd20-9bfc-4bd9-b76e-2e0fd3b0d5ba", "_7ca7c18c-3861-47bf-82cf-5a72d618b18a", "_80ef10f9-3f4f-4fd2-8262-caedf7442fda", "_cd64f70b-91d8-460b-af28-688e9709f319", "_0cbdf98b-b5e4-4bc3-93d6-08db08947794", "_0f4457a6-a3cb-42b0-a06c-b31d5c7a17ff", "_bc165aa6-347d-4551-8abf-016044675a6f", "_65599f7e-3e93-4456-a2b1-bba7a46337b6", "_6bb8ef03-ec84-421f-8d28-cd1a3813e614", "_FBE26B35-13AB-457D-9795-DF58B28E309D", "_8b6bd68f-c84d-45e1-91b9-b0406fbaa3b1", "_d56a4982-0c80-45d0-8cb8-c24097138b63", "_d638fbbc-9b85-416e-87b8-37c9785e1611", "_1C6781A2-5B9D-4525-8A9B-F9B32C4C4AC0", "_0BBD0EA3-F665-465B-86FD-FC8B8466AD53", "_c7c58261-4885-46ee-beb9-c94c6c29451f", "_98a81464-d7b6-4044-9b48-a92e179884dc", "_d8ea43c7-2107-4975-9ddb-4279628daf18", "_2d9ed148-d492-4e7d-b9af-81a407e74a59", "_4e30ae83-418c-4cfb-99eb-5572e00b4ec4", "_d23fd30b-e3f9-4a43-b3c4-2f2697dba851", "_0BBD0EA3-F665-465B-86FD-FC8B8466AD53", "_7a436400-3a77-4eaf-bb04-ef7954fcbdd9", "_5f1dfa9f-e754-471d-9c74-c1a9441e95a3", "_84f75532-a514-4355-bf0e-2f8d82c736ae", "_e1b4fd36-01d0-4d7d-9223-2279911fe8c3"], "connectivity_node": ["brkr", "rg60", "632", "633", "645", "646"], "secondary_areas": []}, {"boundary_switches": ["_43EF8365-F932-409B-A51E-FBED3F6DFFAA"], "addressable_equipment": [], "unaddressable_equipment": ["_1E6B5C97-C4E8-4CED-B9A5-6E69F389DA93", "_5500424b-9931-4f09-a22b-d24a47517920", "_bd95505f-3f55-43d2-b8b2-2c97b2c86603", "_f3001cb9-4c00-45ab-a73f-537be73f583c", "_37fc9b9a-0bc9-4417-8214-52afc237735f", "_697532b4-9520-4de4-80e9-2b6a77c8a089", "_d9e22ddd-f4f2-426c-911d-cf08ff5cc9a0", "_1E6B5C97-C4E8-4CED-B9A5-6E69F389DA93", "_5ae00771-adeb-4ee2-92a3-7c991c579ce1", "_77cf5e05-b332-4203-937a-53f58b4f4585", "_247f50ee-6bc5-4588-bdf1-9b480e09840e", "_5842f2db-ad93-494a-a372-c8e83e637147", "_87c273f2-8e55-4169-adeb-2df020776c06", "_919d79f9-9719-492b-bf8b-46cffc7579ad", "_9d580686-9c5d-42a6-9e0b-ef08c7d80256", "_ab19de32-3fad-4654-b546-6b785b2d65e3", "_51037d29-941b-4e9f-ae86-99dd37bb2c9d", "_54e2019e-e234-4dbb-85d6-227b245040ae", "_48720b2c-7908-4f18-a80d-f7f7f4099753", "_683bbf2f-7ea6-45c6-805e-5e4b7f5000a2", "_0ab88ca4-fb60-4a67-8f77-5f15af245b64", "_25938754-4fe8-4621-9414-7d519bc9fde3", "_78116a30-9d83-4715-a9d2-dda61687a0b9", "_7cc37959-2a82-4911-8a23-8ad09378c85c", "_cd76b30b-8e1c-45fb-b03a-79847254ead8", "_d057e1e2-71ad-4293-b89e-e9e9e84a2522", "_f0af2090-d2aa-40fb-8878-45d75c4ae59f", "_07b694ae-bde0-431c-a740-362a9f476949", "_c3a9b1e7-7a52-4fa5-a199-1fd6035abc21", "_d2d52e14-2111-486e-a59a-d8c5b5f7bf92"], "connectivity_node": ["xf1"], "secondary_areas": [{"distribution_transformer": ["_1E6B5C97-C4E8-4CED-B9A5-6E69F389DA93"], "addressable_equipment": ["_D2E930A7-B136-4ACA-A996-8DB5C60AADF3", "_7B671984-4C56-4FF1-9733-B4B6FCA5F2AA", "_B21C5599-1D00-4FCF-904B-58D9D4CAC49A", "_C39149DE-3451-4D33-B4C2-B1E6C6FC9AAB", "_3B2021A7-4BFC-418D-9C20-BD6838E52CF8"], "unaddressable_equipment": ["_5ae00771-adeb-4ee2-92a3-7c991c579ce1", "_77cf5e05-b332-4203-937a-53f58b4f4585", "_247f50ee-6bc5-4588-bdf1-9b480e09840e", "_5842f2db-ad93-494a-a372-c8e83e637147", "_87c273f2-8e55-4169-adeb-2df020776c06", "_919d79f9-9719-492b-bf8b-46cffc7579ad", "_9d580686-9c5d-42a6-9e0b-ef08c7d80256", "_ab19de32-3fad-4654-b546-6b785b2d65e3", "_51037d29-941b-4e9f-ae86-99dd37bb2c9d", "_54e2019e-e234-4dbb-85d6-227b245040ae", "_48720b2c-7908-4f18-a80d-f7f7f4099753", "_683bbf2f-7ea6-45c6-805e-5e4b7f5000a2", "_0ab88ca4-fb60-4a67-8f77-5f15af245b64", "_25938754-4fe8-4621-9414-7d519bc9fde3", "_78116a30-9d83-4715-a9d2-dda61687a0b9", "_7cc37959-2a82-4911-8a23-8ad09378c85c", "_cd76b30b-8e1c-45fb-b03a-79847254ead8", "_d057e1e2-71ad-4293-b89e-e9e9e84a2522", "_f0af2090-d2aa-40fb-8878-45d75c4ae59f", "_07b694ae-bde0-431c-a740-362a9f476949", "_c3a9b1e7-7a52-4fa5-a199-1fd6035abc21", "_d2d52e14-2111-486e-a59a-d8c5b5f7bf92"], "connectivity_node": ["_0DCC57AF-F4FA-457D-BB24-2EFDA9865A1A"]}]}, {"boundary_switches": ["_2858B6C2-0886-4269-884C-06FA8B887319"], "addressable_equipment": ["_9D725810-BFD6-44C6-961A-2BC027F6FC95"], "unaddressable_equipment": ["_8E180773-2A9B-4136-BC9A-132A52C8E276", "_0fe87976-0177-42f3-817b-b468225220b2", "_2d31c620-a2f9-4f84-9102-9a8fe574ab6b", "_8E180773-2A9B-4136-BC9A-132A52C8E276", "_fad827c5-f344-498e-ab39-29883d4c6bb6", "_7a84c113-d427-4802-a769-b6edc48451c7", "_162b4555-f748-4829-8e71-bbbecf4e4bcb", "_eb606875-f620-4c4e-b559-cd587ba0ecf8", "_6c08f0e8-eb6f-4261-a3f6-3aa9d1e99c75"], "connectivity_node": ["tap", "611"], "secondary_areas": []}, {"boundary_switches": ["_517413CB-6977-46FA-8911-C82332E42884"], "addressable_equipment": ["_A9DE8829-58CB-4750-B2A2-672846A89753"], "unaddressable_equipment": ["_7060D0BB-B30D-4932-8FA1-40820A0FC4D0", "_3e3bdc6c-d985-4659-9cb7-82ea8212ba4f", "_59c9a186-c0a8-4f85-a524-d6ef0d27700a", "_5c9a17db-6f03-4626-9464-41d3a5ddeb15", "_d3a28545-dbfd-4cc4-9f3a-52e2ff130d93", "_8007b83e-40fa-4e87-9df7-a1097dc3b3e7", "_2abd660f-3dc2-4611-95a0-9adebae7fe3b", "_387c6bab-0a0a-4c90-9b19-73a902ab1e28", "_4da919f1-762f-4755-b674-5faccf3faec6", "_7060D0BB-B30D-4932-8FA1-40820A0FC4D0", "_30c1c7d3-284e-4455-a398-6becc3bbc419", "_c3753e40-e1c9-4900-83ff-93e50887c281", "_0a2d1460-0def-479a-9f66-a7963a5619de", "_a5edf08d-b163-4ff1-a145-bf8267fed689", "_b0a947d6-9890-4c7e-a5dd-11fce0760768", "_21e0ccb4-f0d0-43bd-bc70-06447e050e41", "_4e068301-03a3-43ee-8709-744b2f4c8158", "_6e809a5d-d7dd-4c35-882c-3f20b6da557a", "_874dae15-637c-4c9e-bee1-d859ac3acf12", "_306f6f7f-bf58-40e0-9343-62de5f7d9bce", "_5e3ded69-b21a-4850-bc90-ebe5bf7ef970", "_4db89787-187e-4855-ae11-5e10ebf69b00", "_615d912b-7ece-44e7-9bbe-d9a8d8b41e4a", "_c4b054eb-540c-44fd-9113-388d682ede70", "_ff45d777-d004-498c-8ad9-cea09c4f91d2"], "connectivity_node": ["692", "675"], "secondary_areas": []}, {"boundary_switches": ["_CE5D0651-676B-4AF3-8D67-41BF1B33E30C", "_517413CB-6977-46FA-8911-C82332E42884", "_2858B6C2-0886-4269-884C-06FA8B887319"], "addressable_equipment": [], "unaddressable_equipment": ["_ABF53597-A808-422A-B7EE-552F24D83A5F", "_7cdb4378-79d9-4b6b-96c1-f3b55cbbc40d", "_7d0172fb-0d05-4d30-bb80-4cb3619271f4", "_f6662bb7-67f0-452f-ab3a-e430723626e1", "_def62366-746e-4fcb-b3ee-ebebb90d72d4", "_df6e0f8d-1af3-49f2-803b-454c93b19773", "_e87a1d11-7eaf-4535-9745-1e1a8e6b8e11", "_ABF53597-A808-422A-B7EE-552F24D83A5F", "_45395C84-F20A-4F5A-977F-B80348256421", "_17A934C7-1510-481F-BAD7-189058957FF1", "_5105857b-b776-4824-99fa-a324fac89dec", "_e4712e37-525d-43f4-b880-d126a4d9c603", "_aeb839c8-9228-4fff-a538-d2699191aa2b", "_bcdf5a28-bce3-46e6-91a2-8eb3781605eb", "_d054a67b-8e35-4b2a-bd32-6cbfbde656a6", "_502fa582-ba5f-496f-882a-260d909a9b9f", "_198ea415-1a31-4d0e-b31d-950e31a1346a", "_53cfe1f2-0064-46d6-bc8a-54c08992ec95", "_67214379-2364-4d28-9025-10eb7a90cff4", "_b59a587c-fd11-41ad-9172-f83d78d54ac3", "_d11aff18-688e-45f0-82c2-a277fa1b97c0", "_14aae74c-674a-4d1e-a911-4779136ff0ba", "_17A934C7-1510-481F-BAD7-189058957FF1", "_3ad2ed0c-59fd-4663-a2cf-0b8e08c40061", "_ee47f9b3-eb23-4134-9d66-63055155dc27", "_3dbf1b7a-905f-41de-8ab2-e5451623e69e", "_628087e8-502d-444f-a014-fb11514fa82c", "_95407ba3-6edf-43ec-b6c1-e3283b916f63", "_e55a4c7a-c006-4596-b658-e23bc771b5cb", "_c462ff83-15a8-4e0d-9708-f64f41a6a8ce", "_3ff8a15e-f522-47bc-9ca4-0e06c3d58ef0", "_5332bdb4-b316-4166-a37f-8531db278687", "_25b08cbe-ee08-4787-bb32-3e87c660b679", "_a19c2246-4854-45e4-be1e-0169686dfe65", "_4c491539-dfc1-4fda-9841-3bf10348e2fa", "_e92f7019-68ec-4ee5-8fc6-e66580f24794", "_D34B0D01-B082-4081-A3CC-B68B9B8313A4", "_4C04F838-62AA-475E-AEFA-A63B7C889C13", "_45395C84-F20A-4F5A-977F-B80348256421", "_4812ecc5-53dd-4f8e-8375-74ee2c2b3edd", "_70cb7d70-edc3-4223-a9c1-d99be8bc8c52", "_e77eeaf8-7c47-49f7-b932-5fc89b8b628c", "_08175e8f-b762-4c9b-92c4-07f369f69bd4", "_617f766c-5379-49e5-a036-9442f73698aa", "_ffc4a375-69d5-4c91-aa0a-54e4735d30ba", "_1f8096d5-8e7e-4292-bb96-98b5c2efefbc", "_5544e071-22c3-4c7f-b15c-98aac3edfa6f", "_7fcfa7bd-f93a-4f03-8111-43b8851cb078", "_0f5150f9-f959-4f7b-a661-d80afe862e58", "_35a3ba96-f644-4144-b955-1bc959c2311b", "_c8a56420-f87b-4ce4-ac38-ba431ecfcdb2", "_63abd794-ccfc-467d-aa2a-b99c7a0b636a", "_f3d3c954-605b-4a20-b1d9-18d69b5ca3fb", "_813c727c-973e-4185-8bcb-482d7b01eaba", "_90b9792b-e126-4aa2-832e-c99ac3702516", "_e8b9bcff-5105-4f74-8b85-adf530750445", "_0c27bd24-120f-40b2-b0dd-e7cc58e7ebc7", "_142ea530-f364-4dd9-887d-390c4aca512e", "_569f6c28-79d6-4192-a238-1294a899cee3", "_4C04F838-62AA-475E-AEFA-A63B7C889C13", "_881b2079-132d-42b6-a2e4-3d9a954199fc", "_aaa5a1e5-ddd2-4324-b1d7-0b2d1b251f32", "_c549a164-fcff-4b13-9c64-5173fb43994f", "_D34B0D01-B082-4081-A3CC-B68B9B8313A4", "_ABF877D7-DAC2-4BF0-AB58-9A8A02E92EB3", "_a4da4cea-b5b0-4f42-af2e-33ed8aa9e9dd", "_c0b0b188-ad4a-4be3-90c1-2fbb1f507a15", "_357b3424-9587-4839-8d63-e6818f43cecb", "_2f50b72c-d10f-4197-b2b9-e7268bc7c6d9", "_488bdd39-7f23-4aff-bff0-66abe4c7e2a7", "_ABF877D7-DAC2-4BF0-AB58-9A8A02E92EB3", "_6f1c625b-7fe9-4020-9ba6-4e7293c01771", "_6593c292-7c82-482f-99ab-61094ffc214a", "_7d0b45c3-8aaf-4d87-8bf7-7e9b8433b384"], "connectivity_node": ["mid", "670", "671", "680", "684", "652"], "secondary_areas": [{"distribution_transformer": ["_17A934C7-1510-481F-BAD7-189058957FF1"], "addressable_equipment": ["_CEC0FC3A-0FD1-4F1C-9C51-7D9BEF4D8222", "_682AB7A9-4FBF-4204-BDE1-27EAB3425DA0", "_32F02D2B-EE6E-4D3F-8486-1B5CAEF70204"], "unaddressable_equipment": ["_3ad2ed0c-59fd-4663-a2cf-0b8e08c40061", "_ee47f9b3-eb23-4134-9d66-63055155dc27", "_3dbf1b7a-905f-41de-8ab2-e5451623e69e", "_628087e8-502d-444f-a014-fb11514fa82c", "_95407ba3-6edf-43ec-b6c1-e3283b916f63", "_e55a4c7a-c006-4596-b658-e23bc771b5cb", "_c462ff83-15a8-4e0d-9708-f64f41a6a8ce", "_3ff8a15e-f522-47bc-9ca4-0e06c3d58ef0", "_5332bdb4-b316-4166-a37f-8531db278687", "_25b08cbe-ee08-4787-bb32-3e87c660b679", "_a19c2246-4854-45e4-be1e-0169686dfe65", "_4c491539-dfc1-4fda-9841-3bf10348e2fa", "_e92f7019-68ec-4ee5-8fc6-e66580f24794"], "connectivity_node": ["_0A98A62D-7642-4F03-8317-A8605CBDBA37"]}]}]}} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 0da85c19d..93ec936b7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,6 @@ # Base requirements to work with the message bus and debugging # of python applications. -remote_pdb==1.2.0 -durable-rules==0.33.125 +remote_pdb +durable-rules +gridappsd-python +gridappsd-field-bus diff --git a/run-gridappsd.sh b/run-gridappsd.sh index a0eee2911..061324c89 100755 --- a/run-gridappsd.sh +++ b/run-gridappsd.sh @@ -22,10 +22,15 @@ if [ -d /gridappsd/log ]; then /bin/rm -rf /gridappsd/log/* 2 > /dev/null fi +JAVA_OPTIONS="" +if [ "${AUTOSTART:-0}" != "0" ]; then + JAVA_OPTIONS=" -Dgosh.args=--nointeractive " +fi + # If the DEBUG environmental variable is set and is not 0 # then expose the port for remote debugging. if [ "${DEBUG:-0}" != "0" ]; then - java -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -jar lib/run.bnd.jar + java ${JAVA_OPTIONS} -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n -jar lib/run.bnd.jar else - java -jar lib/run.bnd.jar + java ${JAVA_OPTIONS} -jar lib/run.bnd.jar fi diff --git a/services/GridLAB-D.config b/services/GridLAB-D.config index d1bc15181..ba15a9b80 100644 --- a/services/GridLAB-D.config +++ b/services/GridLAB-D.config @@ -10,5 +10,6 @@ "launch_on_startup": "false", "service_dependencies": ["helics","helicsgossbridge","gridappsd-alarms","gridappsd-voltage-violation"], "multiple_instances": false, - "environmentVariables":[] + "environmentVariables":[], + "category": "SIMULATOR" } diff --git a/services/context_manager.config b/services/context_manager.config new file mode 100644 index 000000000..65bcd7c68 --- /dev/null +++ b/services/context_manager.config @@ -0,0 +1,14 @@ +{ + "id": "context_manager", + "description": "GridAPPS-D Context Manager for distributed applications/agents", + "creator": "PNNL", + "inputs": [], + "outputs": [], + "static_args": [], + "execution_path": "context_manager", + "type": "EXE", + "launch_on_startup": "true", + "prereqs": ["gridappsd-topology-daemon"], + "multiple_instances": "false", + "environmentVariables": [{"envName":"GRIDAPPSD_APPLICATION_ID","envValue":"context_manager"}] +} diff --git a/services/helics.config b/services/helics.config index 071d5e697..7e81aa9e3 100644 --- a/services/helics.config +++ b/services/helics.config @@ -4,7 +4,7 @@ "creator": "PNNL", "inputs": [], "outputs": [], - "static_args": ["-f","(numFederates)","--port=(simulationPort)","--loglevel=3"], + "static_args": ["-f","(numFederates)","--port=(simulationPort)","--loglevel=DATA"], "execution_path": "helics_broker", "type": "EXE", "launch_on_startup": "false", diff --git a/services/helicsgossbridge/service/helics_goss_bridge.py b/services/helicsgossbridge/service/helics_goss_bridge.py index ef11ba248..301a0b994 100644 --- a/services/helicsgossbridge/service/helics_goss_bridge.py +++ b/services/helicsgossbridge/service/helics_goss_bridge.py @@ -44,7 +44,9 @@ import argparse import cmath +from copy import deepcopy from datetime import datetime +from enum import IntEnum import gzip import inspect import json @@ -60,10 +62,15 @@ import sqlite3 import sys import time +from pathlib import Path +import cimgraph.data_profile.cimhub_2023 as cim import helics import yaml +from cimgraph import utils as cimUtils +from cimgraph.databases import GridappsdConnection, BlazegraphConnection +from cimgraph.models import FeederModel, GraphModel from gridappsd import GridAPPSD, utils, topics logConfig = { @@ -104,6 +111,17 @@ #logging.config.dictConfig(logConfig) #log = logging.getLogger(__name__) +class RegulatingControlModeKind(IntEnum): + voltage = 0 + activePower = 1 + reactivePower = 2 + currentFlow = 3 + admittance = 4 + timeScheduled = 5 + temperature = 6 + powerFactor = 7 + + class HelicsGossBridge(object): ''' ClassDocs @@ -115,7 +133,7 @@ class HelicsGossBridge(object): _helics_configuration = {} _helics_federate = None _is_initialized = False - _simulation_manager_input_topic = 'goss.gridappsd.cosim.output' + _simulation_manager_input_topic = '/topic/goss.gridappsd.cosim.output' _simulation_command_queue = Queue() _start_simulation = False _filter_all_commands = False @@ -129,8 +147,20 @@ class HelicsGossBridge(object): _pause_simulation_at = -1 _object_property_to_measurement_id = None _object_mrid_to_name = None - _model_mrid = None + _dbConnection = None + _graphModels = None + _model_mrids = [] _difference_attribute_map = { + "RegulatingControl.enabled" : { + "capacitor" : { + "property" : ["control"], + "prefix" : "cap_" + }, + "regulator" : { + "property" : ["Control"], + "prefix" : "rcon_" + } + }, "RegulatingControl.mode" : { "capacitor" : { "property" : ["control"], @@ -220,7 +250,7 @@ class HelicsGossBridge(object): "TapChanger.step" : { "regulator" : { "property" : ["tap_{}"], - "prefix" : "reg_" + "prefix" : "xf_" } }, "TapChanger.lineDropCompensation" : { @@ -232,7 +262,6 @@ class HelicsGossBridge(object): "TapChanger.lineDropR" : { "regulator" : { "property" : ["compensator_r_setting_{}"], - "prefix" : "rcon_" } }, @@ -260,12 +289,14 @@ def __init__(self, simulation_id, broker_port, simulation_request): self._simulation_id = simulation_id self._broker_port = broker_port self._simulation_request = simulation_request + self._generate_cimgraph_models() + # build GLD property names to CIM mrid map + self._create_cim_object_map() # register with GridAPPS-D self._register_with_goss() # register with HELICS self._register_with_helics() - # build GLD property names to CIM mrid map - self._create_cim_object_map() + def get_simulation_id(self): @@ -393,14 +424,16 @@ def on_message(self, headers, msg): message['response'] = str(self._is_initialized) t_now = datetime.utcnow() message['timestamp'] = int(time.mktime(t_now.timetuple())) - self._gad_connection.send(self._simulation_manager_input_topic , json.dumps(message)) + self._gad_connection.send(self._simulation_manager_input_topic+"."+self._simulation_id , + json.dumps(message)) elif json_msg.get('command', '') == 'update': json_msg['input']["time_received"] = time.perf_counter() message['command'] = 'update' if self._filter_all_commands == False: self._simulation_command_queue.put(json.dumps(json_msg['input'])) elif json_msg.get('command', '') == 'StartSimulation': - self._gad_connection.send_simulation_status('STARTED', f"Simulation {self._simulation_id} has started.", 'INFO') + self._gad_connection.send_simulation_status('STARTED', f"Simulation {self._simulation_id} has started.", + 'INFO') if self._start_simulation == False: self._start_simulation = True elif json_msg.get('command', '') == 'CommOutage': @@ -444,7 +477,10 @@ def on_message(self, headers, msg): elif json_msg.get('command', '') == 'pause': if self._pause_simulation == True: log.warning('Pause command received but the simulation is already paused.') - self._gad_connection.send_simulation_status('PAUSED', 'Pause command received but the simulation is already paused.', 'WARN') + self._gad_connection.send_simulation_status('PAUSED', + 'Pause command received but the simulation is already ' + 'paused.', + 'WARN') else: self._pause_simulation = True log.info('The simulation has paused.') @@ -452,7 +488,10 @@ def on_message(self, headers, msg): elif json_msg.get('command', '') == 'resume': if self._pause_simulation == False: log.warning('Resume command received but the simulation is already running.') - self._gad_connection.send_simulation_status('RUNNING', 'Resume command received but the simulation is already running.', 'WARN') + self._gad_connection.send_simulation_status('RUNNING', + 'Resume command received but the simulation is already ' + 'running.', + 'WARN') else: self._pause_simulation = False log.info('The simulation has resumed.') @@ -460,24 +499,29 @@ def on_message(self, headers, msg): elif json_msg.get('command', '') == 'resumePauseAt': if self._pause_simulation == False: log.warning('The resumePauseAt command was received but the simulation is already running.') - self._gad_connection.send_simulation_status('RUNNING', 'The resumePauseAt command was received but the simulation is already running.', 'WARN') + self._gad_connection.send_simulation_status('RUNNING', + 'The resumePauseAt command was received but the ' + 'simulation is already running.', + 'WARN') else: self._pause_simulation = False log.info('The simulation has resumed.') self._gad_connection.send_simulation_status('RUNNING', 'The simulation has resumed.', 'INFO') - self._pause_simulation_at = self._simulation_time + json_msg.get('input', {}).get('pauseIn',-1) + self._pause_simulation_at = self._simulation_time + json_msg.get('input', {}).get('pauseIn',-1) elif json_msg.get('command', '') == '': log.warning('The message received did not have a command key. Ignoring malformed message.') - self._gad_connection.send_simulation_status('RUNNING', 'The message received did not have a command key. Ignoring malformed message.', 'WARN') + self._gad_connection.send_simulation_status('RUNNING', + 'The message received did not have a command key. Ignoring ' + 'malformed message.', + 'WARN') except Exception as e: - message_str = 'Error in processing command message:\n{}.\nError:\n{}'.format(msg,traceback.format_exc()) + message_str = f'Error in processing command message:\n{msg}.\nError:\n{traceback.format_exc()}' log.error(message_str) self._gad_connection.send_simulation_status('ERROR', message_str, 'ERROR') self._stop_simulation = True if federate_state == 2: helics.helicsFederateGlobalError(self._helics_federate, 1, message_str) - self._close_helics_connection() - + self._close_helics_connection() def on_error(self, headers, message): @@ -491,37 +535,26 @@ def on_error(self, headers, message): def on_disconnected(self): self._stop_simulation = True - helics.helicsFederateGlobalError(self._helics_federate, 1, "HelicsGossBridge instance lost connection to GOSS bus.") + helics.helicsFederateGlobalError(self._helics_federate, + 1, + "HelicsGossBridge instance lost connection to GOSS bus.") self._close_helics_connection() + def run_simulation(self): simulation_output_topic = topics.simulation_output_topic(self._simulation_id) - run_realtime = self._simulation_request.get("simulation_config",{}).get("run_realtime",1) - simulation_length = self._simulation_request.get("simulation_config",{}).get("duration",0) - simulation_start = self._simulation_request.get("simulation_config",{}).get("start_time",0) - # New archiving variables set here - # Once the simulation_config is sent directly from the ui, then we can use these, - # Until then you can change the archive to have a default value for either the - # archive or the db_archive. These will be off by default as is the current - # setup. - make_db_archive = self._simulation_request.get("simulation_config",{}).get("make_db_archive", False) - make_archive = self._simulation_request.get("simulation_config",{}).get("make_archive", False) - only_archive = self._simulation_request.get("simulation_config",{}).get("only_archive", False) - archive_db_file = None - if make_db_archive: - archive_db_file = "/tmp/gridappsd_tmp/{}/archive.sqlite".format(self._simulation_id) - archive_file = None - if make_archive: - archive_file = "/tmp/gridappsd_tmp/{}/archive.tar.gz".format(self._simulation_id) - targz_file = None + message_str = 'Running simulation for simulation_request:' \ + f'{json.dumps(self._simulation_request, indent=4, sort_keys=True)}' + log.debug(message_str) + self._gad_connection.send_simulation_status('RUNNING', message_str, 'INFO') + run_realtime = self._simulation_request.get("simulation_config",{}).get("run_realtime", 1) + simulation_length = self._simulation_request.get("simulation_config", {}).get("duration", 0) + simulation_start = self._simulation_request.get("simulation_config", {}).get("start_time", 0) + pause_after_measurements = \ + self._simulation_request.get("simulation_config", {}).get("pause_after_measurements", False) try: - if archive_file: - targz_file = gzip.open(archive_file, "wb") - if archive_db_file: - create_db_connection(archive_db_file) message = {} message['command'] = 'nextTimeStep' - measurement_message_count = 0 simulation_run_time_start = time.perf_counter() for current_time in range(simulation_length): if self._stop_simulation == True: @@ -529,34 +562,30 @@ def run_simulation(self): begin_time_step = time.perf_counter() federate_state = helics.helicsFederateGetState(self._helics_federate) if federate_state == 4: - self._gad_connection.send_simulation_status("ERROR",f"The HELICS co-simulation for simulation {self._simulation_id} entered an error state for some unknown reason.", "ERROR") - log.error(f"The HELICS co-simulation for simulation {self._simulation_id} entered an error state for some unknown reason.") - raise RuntimeError(f"The HELICS co-simulation for simulation {self._simulation_id} entered an error state for some unknown reason.") + self._gad_connection.send_simulation_status("ERROR", + "The HELICS co-simulation for simulation " + f"{self._simulation_id} entered an error state for " + "some unknown reason.", + "ERROR") + log.error(f"The HELICS co-simulation for simulation {self._simulation_id} entered an error state " + "for some unknown reason.") + raise RuntimeError(f"The HELICS co-simulation for simulation {self._simulation_id} entered an " + "error state for some unknown reason.") self._simulation_time = current_time if self._stop_simulation == True: if federate_state == 2: - helics.helicsFederateGlobalError(self._helics_federate, 1, "Stopping the simulation prematurely at operator's request!") + helics.helicsFederateGlobalError(self._helics_federate, + 1, + "Stopping the simulation prematurely at operator's request!") break - self._gad_connection.send("goss.gridappsd.cosim.timestamp.{}".format(self._simulation_id), json.dumps({"timestamp": current_time + simulation_start})) + self._gad_connection.send(f"goss.gridappsd.cosim.timestamp.{self._simulation_id}", + json.dumps({"timestamp": current_time + simulation_start})) #forward messages from HELICS to GOSS if self._filter_all_measurements == False: - message['output'] = self._get_helics_bus_messages(self._measurement_filter) + message['output'] = self._get_helics_bus_messages(self._measurement_filter, + pause_after_measurements) else: message['output'] = {} - response_msg = json.dumps(message['output'], indent=4, sort_keys=True) - - if message['output']!={}: - measurement_message_count += 1 - log.debug("measurement message recieved at timestep {}.".format(current_time)) - if not only_archive: - self._gad_connection.send(simulation_output_topic, response_msg) - if archive_db_file: - ts = message['output']['message']['timestamp'] - meas = message['output']['message']['measurements'] - log.debug("Passing timestamp {ts} to write_db_archive".format(ts=ts)) - write_db_archive(ts, meas) - if targz_file: - targz_file.write((response_msg+"\n").encode('utf-8')) if self._simulation_time == self._pause_simulation_at: self._pause_simulation = True log.info('The simulation has paused.') @@ -573,7 +602,8 @@ def run_simulation(self): if run_realtime == True: sleep_time = 1 - time.perf_counter() + begin_time_step if sleep_time < 0: - warn_message = f"Simulation {self._simulation_id} is running slower than real time!!!. Time step took {1.0 - sleep_time} seconds to execute" + warn_message = f"Simulation {self._simulation_id} is running slower than real time!!!. Time " \ + f"step took {1.0 - sleep_time} seconds to execute" log.warning(warn_message) self._gad_connection.send_simulation_status('RUNNING', warn_message, 'WARN') else: @@ -586,25 +616,13 @@ def run_simulation(self): self._simulation_time = current_time + 1 else: self._simulation_time = current_time - self._gad_connection.send("goss.gridappsd.cosim.timestamp.{}".format(self._simulation_id), json.dumps({"timestamp": self._simulation_time + simulation_start})) + self._gad_connection.send(f"goss.gridappsd.cosim.timestamp.{self._simulation_id}", + json.dumps({"timestamp": self._simulation_time + simulation_start})) #forward messages from HELICS to GOSS if self._filter_all_measurements == False: message['output'] = self._get_helics_bus_messages(self._measurement_filter) else: message['output'] = {} - response_msg = json.dumps(message['output'], indent=4, sort_keys=True) - if message['output']!={}: - measurement_message_count += 1 - log.debug("measurement message recieved at end of simulation.".format(current_time)) - if not only_archive: - self._gad_connection.send(simulation_output_topic, response_msg) - if archive_db_file: - ts = message['output']['message']['timestamp'] - meas = message['output']['message']['measurements'] - log.debug("Passing timestamp {ts} to write_db_archive".format(ts=ts)) - write_db_archive(ts, meas) - if targz_file: - targz_file.write((response_msg+"\n").encode('utf-8')) if not self._stop_simulation: if federate_state == 2: helics.helicsFederateFinalize(self._helics_federate) @@ -613,12 +631,13 @@ def run_simulation(self): log.debug(f"Simulation finished in {time.perf_counter() - simulation_run_time_start} seconds.") message['command'] = 'simulationFinished' del message['output'] - self._gad_connection.send(self._simulation_manager_input_topic, json.dumps(message)) - log.info('Simulation {} has finished.'.format(self._simulation_id)) - self._gad_connection.send_simulation_status('COMPLETE', 'Simulation {} has finished.'.format(self._simulation_id), 'INFO') - log.debug("total measurement messages recieved {}".format(measurement_message_count)) + self._gad_connection.send(self._simulation_manager_input_topic+"."+self._simulation_id, json.dumps(message)) + log.info(f'Simulation {self._simulation_id} has finished.') + self._gad_connection.send_simulation_status('COMPLETE', + f'Simulation {self._simulation_id} has finished.', + 'INFO') except Exception as e: - message_str = 'Error in run simulation {}'.format(traceback.format_exc()) + message_str = f'Error in run simulation {traceback.format_exc()}' log.error(message_str) self._gad_connection.send_simulation_status('ERROR', message_str, 'ERROR') self._simulation_finished = True @@ -627,18 +646,18 @@ def run_simulation(self): self._close_helics_connection() finally: if self._stop_simulation: - helics.helicsFederateGlobalError(self._helics_federate, 1, "Stopping the simulation prematurely at operator's request!") + helics.helicsFederateGlobalError(self._helics_federate, + 1, + "Stopping the simulation prematurely at operator's request!") self._close_helics_connection() - if targz_file: - targz_file.close() - def _register_with_goss(self): + def _register_with_goss(self): try: self._gad_connection = GridAPPSD(self._simulation_id) log.debug("Successfully registered with the GridAPPS-D platform.") self._gad_connection.subscribe(topics.simulation_input_topic(self._simulation_id), self.on_message) - self._gad_connection.subscribe("/topic/goss.gridappsd.cosim.input", self.on_message) + self._gad_connection.subscribe("/topic/goss.gridappsd.cosim.input."+self._simulation_id, self.on_message) except Exception as e: log.error("An error occurred when trying to register with the GridAPPS-D platform!", exc_info=True) @@ -646,15 +665,16 @@ def _register_with_goss(self): def _register_with_helics(self): try: self._helics_configuration = { - "name": "HELICS_GOSS_Bridge_{}".format(self._simulation_id), + "name": f"HELICS_GOSS_Bridge_{self._simulation_id}", "period": 1.0, - "log_level": 7, - "broker": "127.0.0.1:{}".format(self._broker_port), + "coreinit": f"-logfile HELICS_GOSS_Bridge_{self._simulation_id}.log", + "log_level": "DATA", + "broker": f"127.0.0.1:{self._broker_port}", "endpoints": [ { "name": "helics_input", "global": False, - "destination": "{}/helics_input".format(self._simulation_id), + "destination": f"{self._simulation_id}/helics_input", "type": "string", "info": "This is the endpoint which sends CIM attribute commands to the GridLAB-D simulator." }, @@ -668,23 +688,27 @@ def _register_with_helics(self): } self._helics_federate = helics.helicsCreateMessageFederateFromConfig(json.dumps(self._helics_configuration)) helics.helicsFederateEnterExecutingMode(self._helics_federate) - log.debug("Successfully registered with the HELICS broker.") + log.debug("Successfully registered with the HELICS broker.") except Exception as e: - err_msg = "An error occurred when trying to register with the HELICS broker!{}".format(traceback.format_exc()) + err_msg = f"An error occurred when trying to register with the HELICS broker!{traceback.format_exc()}" log.error(err_msg, exc_info=True) self._gad_connection.send_simulation_status("ERROR", err_msg, "ERROR") def _close_helics_connection(self): - helics.helicsFederateFree(self._helics_federate) + helics.helicsFederateDisconnect(self._helics_federate) helics.helicsCloseLibrary() def _get_gld_object_name(self, object_mrid): prefix = "" - stored_object = self._object_mrid_to_name.get(object_mrid) + for k in self._object_mrid_to_name.keys(): + stored_object = self._object_mrid_to_name[k].get(object_mrid) + if stored_object is not None: + break if stored_object == None: - cim_object_dict = self._gad_connection.query_object_dictionary(model_id=self._model_mrid, object_id=object_mrid) + cim_object_dict = self._gad_connection.query_object_dictionary(model_id=self._model_mrid, + object_id=object_mrid) object_base_name = (cim_object_dict.get("data",[]))[0].get("IdentifiedObject.name","") object_type = (cim_object_dict.get("data",[]))[0].get("type","") if object_type == "LinearShuntCompensator": @@ -696,7 +720,7 @@ def _get_gld_object_name(self, object_mrid): elif object_type in ["LoadBreakSwitch","Recloser","Breaker"]: prefix = "sw_" elif object_type == "RatioTapChanger": - prefix = "reg_" + prefix = "xf_" else: object_base_name = stored_object.get("name","") prefix = stored_object.get("prefix","") @@ -719,19 +743,19 @@ def _publish_to_helics_bus(self, goss_message, command_filter): ValueError() """ publish_to_helics_bus_start = time.perf_counter() - message_str = 'translating following message for HELICS simulation '+str(self._simulation_id)+' '+str(goss_message) + message_str = f'translating following message for HELICS simulation {self._simulation_id} {goss_message}' log.debug(message_str) self._gad_connection.send_simulation_status('RUNNING', message_str, 'DEBUG') - if self._simulation_id == None or self._simulation_id == '' or type(self._simulation_id) != str: + if self._simulation_id == None or self._simulation_id == '' or not isinstance(self._simulation_id, str): raise ValueError( 'simulation_id must be a nonempty string.\n' - + 'simulation_id = {0}.\n'.format(self._simulation_id) - + 'simulation_id type = {0}.'.format(type(self._simulation_id))) - if goss_message == None or goss_message == '' or type(goss_message) != str: + + f'simulation_id = {self._simulation_id}.\n' + + f'simulation_id type = {type(self._simulation_id)}.') + if goss_message == None or goss_message == '' or not isinstance(goss_message,str): raise ValueError( 'goss_message must be a nonempty string.\n' - + 'goss_message = {0}.\n'.format(goss_message) - + 'goss_message type = {}.'.format(type(goss_message))) + + f'goss_message = {goss_message}.\n' + + f'goss_message type = {type(goss_message)}.') federate_state = helics.helicsFederateGetState(self._helics_federate) if federate_state != 2: raise RuntimeError( @@ -739,16 +763,19 @@ def _publish_to_helics_bus(self, goss_message, command_filter): + ' to the HELICS message bus.') try: test_goss_message_format = yaml.safe_load(goss_message) - if type(test_goss_message_format) != dict: + if not isinstance(test_goss_message_format, dict): raise ValueError( 'goss_message is not a json formatted string of a python dictionary.' - + '\ngoss_message = {0}'.format(goss_message)) + + f'\ngoss_message = {goss_message}') helics_input_endpoint = helics.helicsFederateGetEndpoint(self._helics_federate, "helics_input") - helics_input_message = {"{}".format(self._simulation_id) : {}} - helics_input_message["{}".format(self._simulation_id)]["external_event_handler"] = {} + helics_input_message = {} + model_faults = {} + for k in self._object_mrid_to_name.keys(): + helics_input_message[k] = {"external_event_handler": {}} + model_faults[k] = [] forward_differences_list = test_goss_message_format["message"]["forward_differences"] reverse_differences_list = test_goss_message_format["message"]["reverse_differences"] - fault_list = [] + modelMrid = None for x in forward_differences_list: command_pair = { "objectMRID": x.get("object", ""), @@ -756,170 +783,240 @@ def _publish_to_helics_bus(self, goss_message, command_filter): } if x.get("attribute", "") != "IdentifiedObject.Fault": if command_pair not in command_filter: - object_name = (self._object_mrid_to_name.get(x.get("object",{}),{})).get("name") - object_phases = (self._object_mrid_to_name.get(x.get("object",{}),{})).get("phases") - object_total_phases = (self._object_mrid_to_name.get(x.get("object",{}),{})).get("total_phases") - object_type = (self._object_mrid_to_name.get(x.get("object",{}),{})).get("type") - object_name_prefix = ((self._difference_attribute_map.get(x.get("attribute",{}),{})).get(object_type,{})).get("prefix") + for k in self._object_mrid_to_name.keys(): + object_name = (self._object_mrid_to_name[k].get(x.get("object",""),{})).get("name") + object_phases = (self._object_mrid_to_name[k].get(x.get("object",""),{})).get("phases") + object_total_phases = (self._object_mrid_to_name[k].get(x.get("object",""),{})).get("total_phases") + object_type = (self._object_mrid_to_name[k].get(x.get("object",""),{})).get("type") + if object_name is not None: + modelMrid = k + break + object_name_prefix = ((self._difference_attribute_map.get(x.get("attribute", ""), + {})).get(object_type, + {})).get("prefix") cim_attribute = x.get("attribute") - object_property_list = ((self._difference_attribute_map.get(x.get("attribute",{}),{})).get(object_type,{})).get("property") - phase_in_property = ((self._difference_attribute_map.get(x.get("attribute",{}),{})).get(object_type,{})).get("phase_sensitive",False) - if object_name == None or object_phases == None or object_total_phases == None or object_type == None or object_name_prefix == None or cim_attribute == None or object_property_list == None: - parsed_result = { - "object_name":object_name, - "object_phases":object_phases, - "object_total_phases":object_total_phases, - "object_type":object_type, - "object_name_prefix":object_name_prefix, - "cim_attribute":cim_attribute, - "object_property_list":object_property_list - } - raise RuntimeError("Forward difference command cannot be parsed correctly one or more of attributes needed was None.\ndifference:{}\nparsed result:{}".format(json.dumps(x,indent=4,sort_keys=True),json.dumps(parsed_result,indent=4,sort_keys=True))) - if (object_name_prefix + object_name) not in helics_input_message["{}".format(self._simulation_id)].keys(): - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name] = {} - if cim_attribute == "RegulatingControl.mode": - val = int(x.get("value")) - if val == 0: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0]] = "VOLT" - if val == 1: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0]] = "MANUAL" - elif val == 2: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0]] = "VAR" - elif val == 3: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0]] = "CURRENT" - else: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0]] = "MANUAL" - log.warning("Unsupported capacitor control mode requested. The only supported control modes for capacitors are voltage, VAr, volt/VAr, and current. Setting control mode to MANUAL.") - self._gad_connection.send_simulation_status("RUNNING", "Unsupported capacitor control mode requested. The only supported control modes for capacitors are voltage, VAr, volt/VAr, and current. Setting control mode to MANUAL.","WARN") - elif cim_attribute == "RegulatingControl.targetDeadband": - for y in self._difference_attribute_map[cim_attribute][object_type]["property"]: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][y] = float(x.get("value")) - elif cim_attribute == "RegulatingControl.targetValue": - for y in self._difference_attribute_map[cim_attribute][object_type]["property"]: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][y] = float(x.get("value")) - elif cim_attribute == "RotatingMachine.p": - for y in object_phases: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0].format(y)] = float(x.get("value"))/3.0 - elif cim_attribute == "RotatingMachine.q": - for y in object_phases: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0].format(y)] = float(x.get("value"))/3.0 - elif cim_attribute == "ShuntCompensator.aVRDelay": - for y in self._difference_attribute_map[cim_attribute][object_type]["property"]: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][y] = float(x.get("value")) - elif cim_attribute == "ShuntCompensator.sections": - if int(x.get("value")) == 1: - val = "CLOSED" - else: - val = "OPEN" - for y in object_phases: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0].format(y)] = "{}".format(val) - elif cim_attribute == "Switch.open": - if int(x.get("value")) == 1: - val = "OPEN" + object_property_list = ((self._difference_attribute_map.get(x.get("attribute", ""), + {})).get(object_type, + {})).get("property") + if cim_attribute != "Ochre.command": + if object_name == None or object_phases == None or object_total_phases == None \ + or object_type == None or object_name_prefix == None or cim_attribute == None \ + or object_property_list == None: + parsed_result = { + "object_name":object_name, + "object_phases":object_phases, + "object_total_phases":object_total_phases, + "object_type":object_type, + "object_name_prefix":object_name_prefix, + "cim_attribute":cim_attribute, + "object_property_list":object_property_list + } + raise RuntimeError("Forward difference command cannot be parsed correctly one or more " + "of attributes needed was None.\ndifference:" + f"{json.dumps(x,indent=4,sort_keys=True)}\nparsed result:" + f"{json.dumps(parsed_result,indent=4,sort_keys=True)}") + if (object_name_prefix + object_name) not in helics_input_message[modelMrid].keys(): + helics_input_message[modelMrid][object_name_prefix + object_name] = {} + if cim_attribute == "RegulatingControl.mode": + try: + val = RegulatingControlModeKind(int(x.get("value"))) + except: + val = RegulatingControlModeKind[x.get("value", + "").replace("RegulatingControlModeKind.", + "", + 1)] + if val == RegulatingControlModeKind.voltage: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0]] = \ + "VOLT" + elif val == RegulatingControlModeKind.reactivePower: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0]] = \ + "VAR" + elif val == RegulatingControlModeKind.currentFlow: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0]] = \ + "CURRENT" + else: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0]] = \ + "MANUAL" + warnStr = "Unsupported capacitor control mode requested. The only supported " \ + "control modes for capacitors are RegulatingControlModeKind.voltage: " \ + "0, RegulatingControlModeKind.reactivePower: 2, and " \ + "RegulatingControlModeKind.currentFlow: 3.\nSetting control mode to " \ + f"MANUAL.\nThe invalid control mode was {x.get('value')}" + log.warning(warnStr) + self._gad_connection.send_simulation_status("RUNNING", warnStr, "WARN") + elif cim_attribute == "RegulatingControl.enabled": + val = x.get("value") + if val == False: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0]] = \ + "MANUAL" + elif cim_attribute == "RegulatingControl.targetDeadband": + for y in self._difference_attribute_map[cim_attribute][object_type]["property"]: + helics_input_message[modelMrid][object_name_prefix + object_name][y] = float(x.get("value")) + elif cim_attribute == "RegulatingControl.targetValue": + for y in self._difference_attribute_map[cim_attribute][object_type]["property"]: + helics_input_message[modelMrid][object_name_prefix + object_name][y] = float(x.get("value")) + elif cim_attribute == "RotatingMachine.p": + for y in object_phases: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0].format(y)] = float(x.get("value"))/3.0 + elif cim_attribute == "RotatingMachine.q": + for y in object_phases: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0].format(y)] = float(x.get("value"))/3.0 + elif cim_attribute == "ShuntCompensator.aVRDelay": + for y in self._difference_attribute_map[cim_attribute][object_type]["property"]: + helics_input_message[modelMrid][object_name_prefix + object_name][y] = float(x.get("value")) + elif cim_attribute == "ShuntCompensator.sections": + if int(x.get("value")) == 1: + val = "CLOSED" + else: + val = "OPEN" + for y in object_phases: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0].format(y)] = f"{val}" + elif cim_attribute == "Switch.open": + if int(x.get("value")) == 1: + val = "OPEN" + else: + val = "CLOSED" + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0]] = \ + f"{val}" + elif cim_attribute == "TapChanger.initialDelay": + for y in object_property_list: + helics_input_message[modelMrid][object_name_prefix + object_name][y] = float(x.get("value")) + elif cim_attribute == "TapChanger.step": + for y in object_phases: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0].format(y)] = int(x.get("value")) + elif cim_attribute == "TapChanger.lineDropCompensation": + if int(x.get("value")) == 1: + val = "LINE_DROP_COMP" + else: + val = "MANUAL" + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0]] = \ + f"{val}" + elif cim_attribute == "TapChanger.lineDropR": + for y in object_phases: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0].format(y)] = float(x.get("value")) + elif cim_attribute == "TapChanger.lineDropX": + for y in object_phases: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0].format(y)] = float(x.get("value")) + elif cim_attribute == "PowerElectronicsConnection.p": + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0]] = \ + float(x.get("value")) + elif cim_attribute == "PowerElectronicsConnection.q": + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0]] = \ + float(x.get("value")) + elif cim_attribute == "EnergyConsumer.p": + phase_count = len(object_phases) + if "s1" in object_phases: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0].format("1")] = float(x.get("value"))/2.0 + if "s2" in object_phases: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0].format("2")] = float(x.get("value"))/2.0 + if "A" in object_phases: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0].format("A")] = float(x.get("value"))/phase_count + if "B" in object_phases: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0].format("B")] = float(x.get("value"))/phase_count + if "C" in object_phases: + helics_input_message[modelMrid][object_name_prefix + object_name][object_property_list[0].format("C")] = float(x.get("value"))/phase_count else: - val = "CLOSED" - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0]] = "{}".format(val) - elif cim_attribute == "TapChanger.initialDelay": - for y in object_property_list: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][y] = float(x.get("value")) - elif cim_attribute == "TapChanger.step": - for y in object_phases: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0].format(y)] = int(x.get("value")) - elif cim_attribute == "TapChanger.lineDropCompensation": - if int(x.get("value")) == 1: - val = "LINE_DROP_COMP" - else: - val = "MANUAL" - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0]] = "{}".format(val) - elif cim_attribute == "TapChanger.lineDropR": - for y in object_phases: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0].format(y)] = float(x.get("value")) - elif cim_attribute == "TapChanger.lineDropX": - for y in object_phases: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0].format(y)] = float(x.get("value")) - elif cim_attribute == "PowerElectronicsConnection.p": - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0]] = float(x.get("value")) - elif cim_attribute == "PowerElectronicsConnection.q": - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0]] = float(x.get("value")) - elif cim_attribute == "EnergyConsumer.p": - phase_count = len(object_phases) - if "s1" in object_phases: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0].format("1")] = float(x.get("value"))/2.0 - if "s2" in object_phases: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0].format("2")] = float(x.get("value"))/2.0 - if "A" in object_phases: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0].format("A")] = float(x.get("value"))/phase_count - if "B" in object_phases: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0].format("B")] = float(x.get("value"))/phase_count - if "C" in object_phases: - helics_input_message["{}".format(self._simulation_id)][object_name_prefix + object_name][object_property_list[0].format("C")] = float(x.get("value"))/phase_count + warnStr = f"Attribute, {cim_attribute}, is not a supported attribute in the " \ + "simulator at this current time. ignoring difference." + log.warning(warnStr) + self._gad_connection.send_simulation_status("RUNNING", warnStr, "WARN") else: - log.warning("Attribute, {}, is not a supported attribute in the simulator at this current time. ignoring difference.".format(cim_attribute)) - self._gad_connection.send_simulation_status("RUNNING", "Attribute, {}, is not a supported attribute in the simulator at this current time. ignoring difference.".format(cim_attribute), "WARN") + if federate_state == 2: + val = x.get("value") + house_id = x.get("object") + default_destination = helics.helicsEndpointGetDefaultDestination(helics_input_endpoint) + ochre_destination = f"{house_id}/command_input" + helics.helicsEndpointSetDefaultDestination(helics_input_endpoint, ochre_destination) + infoStr = f"Sending the following message to {ochre_destination}. {val}" + log.info(infoStr) + self._gad_connection.send_simulation_status("RUNNING", infoStr,"INFO") + helics_msg = helics.helicsFederateCreateMessageObject(self._helics_federate) + helics.helicsMessageSetString(helics_msg, val) + helics.helicsEndpointSendMessage(helics_input_endpoint, helics_msg) + helics.helicsEndpointSetDefaultDestination(helics_input_endpoint, default_destination) else: fault_val_dict = {} fault_val_dict["name"] = x.get("object","") - fault_object_mrid = (x.get("value",{})).get("ObjectMRID","") + fault_object_mrid = (x.get("value",{})).get("ObjectMRID","") + modelMrid = _getEquipmentContainer(fault_object_mrid) + if modelMrid is None: + raise RuntimeError(f"The cim object identified by mRID {fault_object_mrid} has no equipment " + "container defined!") fault_val_dict["fault_object"] = self._get_gld_object_name(fault_object_mrid) phases = (x.get("value",{})).get("PhaseCode","") fault_kind_type = (x.get("value",{})).get("PhaseConnectedFaultKind","") fault_type = "" if fault_kind_type == "lineToGround": - fault_type = "SLG-{}".format(phases) + fault_type = f"SLG-{phases}" elif fault_kind_type == "lineToLine": if len(phases) == 3: fault_type = "TLL" else: - fault_type = "LL-{}".format(phases) + fault_type = f"LL-{phases}" elif fault_kind_type == "lineToLineToGround": if len(phases) == 3: fault_type = "TLG" else: - fault_type = "DLG-{}".format(phases) + fault_type = f"DLG-{phases}" elif fault_kind_type == "lineOpen": if len(phases) == 3: fault_type = "OC3" elif len(phases) == 2: - fault_type = "OC2-{}".format(phases) + fault_type = f"OC2-{phases}" else: - fault_type = "OC-{}".format(phases) + fault_type = f"OC-{phases}" fault_val_dict["type"] = fault_type - fault_list.append(fault_val_dict) + model_faults[modelMrid].append(fault_val_dict) for x in reverse_differences_list: if x.get("attribute", "") == "IdentifiedObject.Fault": fault_val_dict = {} fault_val_dict["name"] = x.get("object", "") - fault_list.append(fault_val_dict) - if len(fault_list) != 0: - helics_input_message["{}".format(self._simulation_id)]["external_event_handler"]["external_fault_event"] = json.dumps(fault_list) - goss_message_converted = json.dumps(helics_input_message, indent=4, sort_keys=True) - log.info("Sending the following message to the simulator. {}".format(goss_message_converted)) - self._gad_connection.send_simulation_status("RUNNING", "Sending the following message to the simulator. {}".format(goss_message_converted),"INFO") - if federate_state == 2 and helics_input_message["{}".format(self._simulation_id)] != {}: - helics_msg = helics.helicsFederateCreateMessageObject(self._helics_federate) - helics.helicsMessageSetString(helics_msg, goss_message_converted) - helics.helicsEndpointSendMessage(helics_input_endpoint, helics_msg) - publish_to_helics_bus_finish = time.perf_counter() - publish_to_helics_profile = { - "time_between_receipt_of_message_and_processing": publish_to_helics_bus_start - test_goss_message_format.get("time_received",publish_to_helics_bus_start), - "time_messege_processing": publish_to_helics_bus_finish - publish_to_helics_bus_start, - "total_time": publish_to_helics_bus_finish - test_goss_message_format.get("time_received",publish_to_helics_bus_start) - } - log.debug(f"Message Processing Profile: {json.dumps(publish_to_helics_profile, indent=4, sort_keys=True)}") + objMrid = x.get("value", {}).get("ObjectMRID", "") + modelMrid = _getEquipmentContainer(objMrid) + model_faults[modelMrid].append(fault_val_dict) + for modelId, fault_list in model_faults.items(): + if len(fault_list) != 0: + helics_input_message[modelId]["external_event_handler"]["external_fault_event"] = json.dumps(fault_list) + if helics_input_message[modelId]["external_event_handler"] == {}: + del helics_input_message[modelId]["external_event_handler"] + for modelId in helics_input_message.keys(): + if len(helics_input_message[modelId]) > 0: + goss_message_converted = json.dumps(helics_input_message[modelId], indent=4, sort_keys=True) + infoStr = f"Sending the following message to federate {modelId}: {goss_message_converted}" + log.info(infoStr) + self._gad_connection.send_simulation_status("RUNNING", infoStr, "INFO") + if federate_state == 2 and helics_input_message != {}: + helics_msg = helics.helicsEndpointCreateMessage(helics_input_endpoint) + helics.helicsMessageSetDestination(helics_msg, f"{modelId}/helics_input") + helics.helicsMessageSetString(helics_msg, goss_message_converted) + helics.helicsEndpointSendMessage(helics_input_endpoint, helics_msg) + helics.helicsMessageFree(helics_msg) + publish_to_helics_bus_finish = time.perf_counter() + publish_to_helics_profile = { + "time_between_receipt_of_message_and_processing": publish_to_helics_bus_start \ + - test_goss_message_format.get("time_received",publish_to_helics_bus_start), + "time_messege_processing": publish_to_helics_bus_finish - publish_to_helics_bus_start, + "total_time": publish_to_helics_bus_finish - test_goss_message_format.get("time_received", + publish_to_helics_bus_start) + } + log.debug(f"Message Processing Profile: {json.dumps(publish_to_helics_profile, indent=4, sort_keys=True)}") except ValueError as ve: raise ValueError(ve) except Exception as ex: - err_msg = "An error occured while trying to translate the update message received\n{}".format(traceback.format_exc()) + err_msg = "An error occured while trying to translate the update message received\n" \ + f"{traceback.format_exc()}" self._gad_connection.send_simulation_status("ERROR",err_msg,"ERROR") raise RuntimeError(err_msg) - def _get_helics_bus_messages(self, measurement_filter): + def _get_helics_bus_messages(self, measurement_filter, pause_after_measurements = False): """ retrieve the measurment dictionary from the HELICS message bus Function arguments: measurement_filter -- Type: list. Description: The list of measurement id's to filter from the simulator output. + pause_after_measurements -- Type: bool. Description: boolean for automatically pausing the simulation after + publishing measurements. Function returns: helics_output -- Type: string. Description: The json structured output from the simulation. If no output was sent from the simulation then @@ -931,152 +1028,186 @@ def _get_helics_bus_messages(self, measurement_filter): objectName = "" objectType = "" propertyValue = "" + phases = "" get_helics_bus_messages_start = time.perf_counter() try: helics_message = None if self._simulation_id == None or self._simulation_id == '' or type(self._simulation_id) != str: raise ValueError( 'simulation_id must be a nonempty string.\n' - + 'simulation_id = {0}'.format(self._simulation_id)) + + f'simulation_id = {self._simulation_id}') helics_output_endpoint = helics.helicsFederateGetEndpoint(self._helics_federate, "helics_output") has_message = helics.helicsEndpointHasMessage(helics_output_endpoint) + pending_message_count = helics.helicsEndpointPendingMessageCount(helics_output_endpoint) if has_message: - message_str = 'helics_output has a message' + message_str = f'helics_output has {pending_message_count} messages' else: message_str = 'helics_output has no messages' log.debug(message_str) self._gad_connection.send_simulation_status('RUNNING', message_str, 'DEBUG') + cim_output = {} if has_message: t_now = datetime.utcnow() + current_time = int(time.mktime(t_now.timetuple())) cim_measurements_dict = { "simulation_id": self._simulation_id, "message" : { - "timestamp" : int(time.mktime(t_now.timetuple())), + "timestamp" : current_time, "measurements" : {} } } - helics_message = helics.helicsEndpointGetMessageObject(helics_output_endpoint) - helics_output = helics.helicsMessageGetString(helics_message) - helics_output_dict = json.loads(helics_output) - - sim_dict = helics_output_dict.get(self._simulation_id, None) - if sim_dict != None: - simulation_time = int(sim_dict.get("globals",{}).get("clock", 0)) - if simulation_time != 0: - cim_measurements_dict["message"]["timestamp"] = simulation_time - for x in self._object_property_to_measurement_id.keys(): - objectName = x - gld_properties_dict = sim_dict.get(x,None) - if gld_properties_dict == None: - err_msg = "All measurements for object {} are missing from the simulator output.".format(x) - log.warning(err_msg) - self._gad_connection.send_simulation_status('RUNNING', err_msg, 'WARN') - else: - for y in self._object_property_to_measurement_id.get(x,[]): - measurement = {} - property_name = y["property"] - propertyName = property_name - if y["measurement_mrid"] not in measurement_filter: - measurement["measurement_mrid"] = y["measurement_mrid"] - phases = y["phases"] - conducting_equipment_type_str = y["conducting_equipment_type"] - prop_val_str = gld_properties_dict.get(property_name, None) - propertyValue = prop_val_str - objectType = conducting_equipment_type_str - if prop_val_str == None: - err_msg = "{} measurement for object {} is missing from the simulator output.".format(property_name, x) - log.warning(err_msg) - self._gad_connection.send_simulation_status('RUNNING', err_msg, 'WARN') - else: - val_str = str(prop_val_str).split(" ")[0] - conducting_equipment_type = str(conducting_equipment_type_str).split("_")[0] - if conducting_equipment_type == "LinearShuntCompensator": - if property_name in ["voltage_"+phases]: - val = complex(val_str) - (mag,ang_rad) = cmath.polar(val) - ang_deg = math.degrees(ang_rad) - measurement["magnitude"] = mag - measurement["angle"] = ang_deg - elif property_name in ["shunt_"+phases]: - # Need voltage value and switch status to compute the reactive power - prop_val_str = gld_properties_dict.get("voltage_"+phases, None) - val_strVolt = str(prop_val_str).split(" ")[0] - valVolt = complex(val_strVolt) - (magV,ang_radV) = cmath.polar(valVolt) - prop_val_str = gld_properties_dict.get("switch"+phases, None) - val_str_switch = str(prop_val_str).split(" ")[0] - status = 1 - if val_str_switch == "OPEN": - status = 0 - val = complex(val_str) - (mag,ang_rad) = cmath.polar(val) - ang_deg = math.degrees(ang_rad) - measurement["magnitude"] = mag * magV * magV * status - measurement["angle"] = ang_deg - else: - if val_str == "OPEN": - measurement["value"] = 0 + for x in range(pending_message_count): + helics_message = helics.helicsEndpointGetMessage(helics_output_endpoint) + helics_output = helics.helicsMessageGetString(helics_message) + helics_message_source = helics.helicsMessageGetSource(helics_message) + if "status" in helics_message_source: + ochre_simulation_output_topic = "/topic/goss.gridappsd.simulation.ochre.output." \ + f"{self._simulation_id}" + log.debug(f"ochre measurement message recieved at timestep {current_time}.") + self._gad_connection.send(ochre_simulation_output_topic, helics_output) + else: + federateMrid = helics_message_source.split("/")[0] + helics_output_dict = json.loads(helics_output) + + sim_dict = helics_output_dict.get(federateMrid, None) + if sim_dict == None: + sim_dict = helics_output_dict + simulation_time = int(sim_dict.get("globals",{}).get("clock", 0)) + if simulation_time != 0: + cim_measurements_dict["message"]["timestamp"] = simulation_time + for x in self._object_property_to_measurement_id[federateMrid].keys(): + objectName = x + gld_properties_dict = sim_dict.get(x,None) + if gld_properties_dict == None: + err_msg = f"All measurements for object {x} are missing from the simulator output." + log.warning(err_msg) + self._gad_connection.send_simulation_status('RUNNING', err_msg, 'WARN') + else: + for y in self._object_property_to_measurement_id[federateMrid].get(x,[]): + measurement = {} + property_name = y["property"] + propertyName = property_name + if y["measurement_mrid"] not in measurement_filter: + measurement["measurement_mrid"] = y["measurement_mrid"] + phases = y["phases"] + # conducting_equipment_type = type(y["power_system_resource"]).__name__ + conducting_equipment_type_str = y["conducting_equipment_type"] + prop_val_str = gld_properties_dict.get(property_name, None) + propertyValue = prop_val_str + objectType = conducting_equipment_type_str + if prop_val_str == None: + err_msg = f"{property_name} measurement for object {x} is missing from " \ + "the simulator output." + log.warning(err_msg) + self._gad_connection.send_simulation_status('RUNNING', err_msg, 'WARN') + else: + val_str = str(prop_val_str).split(" ")[0] + conducting_equipment_type = str(conducting_equipment_type_str).split("_")[0] + if conducting_equipment_type == "LinearShuntCompensator": + if property_name in ["voltage_"+phases]: + val = complex(val_str) + (mag,ang_rad) = cmath.polar(val) + ang_deg = math.degrees(ang_rad) + measurement["magnitude"] = mag + measurement["angle"] = ang_deg + elif property_name in ["shunt_"+phases]: + # Need voltage value and switch status to compute the reactive power + prop_val_str = gld_properties_dict.get("voltage_"+phases, None) + val_strVolt = str(prop_val_str).split(" ")[0] + valVolt = complex(val_strVolt) + (magV,ang_radV) = cmath.polar(valVolt) + prop_val_str = gld_properties_dict.get("switch"+phases, None) + val_str_switch = str(prop_val_str).split(" ")[0] + status = 1 + if val_str_switch == "OPEN": + status = 0 + val = complex(val_str) + (mag,ang_rad) = cmath.polar(val) + ang_deg = math.degrees(ang_rad) + measurement["magnitude"] = mag * magV * magV * status + measurement["angle"] = ang_deg else: - measurement["value"] = 1 - elif conducting_equipment_type == "PowerTransformer": - if property_name in ["power_in_"+phases,"voltage_"+phases,"current_in_"+phases]: - val = complex(val_str) - (mag,ang_rad) = cmath.polar(val) - ang_deg = math.degrees(ang_rad) - measurement["magnitude"] = mag - measurement["angle"] = ang_deg - else: - measurement["value"] = int(val_str) - elif conducting_equipment_type in ["ACLineSegment","EnergyConsumer","PowerElectronicsConnection","SynchronousMachine"]: - if property_name == "state_of_charge": - measurement["value"] = float(val_str)*100.0 - else: - val = complex(val_str) - (mag,ang_rad) = cmath.polar(val) - ang_deg = math.degrees(ang_rad) - measurement["magnitude"] = mag - measurement["angle"] = ang_deg - elif conducting_equipment_type in ["LoadBreakSwitch", "Recloser", "Breaker"]: - if property_name in ["power_in_"+phases,"voltage_"+phases,"current_in_"+phases]: - val = complex(val_str) - (mag,ang_rad) = cmath.polar(val) - ang_deg = math.degrees(ang_rad) - measurement["magnitude"] = mag - measurement["angle"] = ang_deg - else: - if val_str == "OPEN": - measurement["value"] = 0 + if val_str == "OPEN": + measurement["value"] = 0 + else: + measurement["value"] = 1 + elif conducting_equipment_type in ["PowerTransformer","TransformerTank"]: + if property_name in ["power_in_"+phases, + "voltage_"+phases, + "current_in_"+phases]: + val = complex(val_str) + (mag,ang_rad) = cmath.polar(val) + ang_deg = math.degrees(ang_rad) + measurement["magnitude"] = mag + measurement["angle"] = ang_deg + else: + measurement["value"] = int(val_str) + elif conducting_equipment_type in ["ACLineSegment", + "EnergyConsumer", + "PowerElectronicsConnection", + "SynchronousMachine"]: + if property_name == "state_of_charge": + measurement["value"] = float(val_str)*100.0 + else: + val = complex(val_str) + (mag,ang_rad) = cmath.polar(val) + ang_deg = math.degrees(ang_rad) + measurement["magnitude"] = mag + measurement["angle"] = ang_deg + elif conducting_equipment_type in ["LoadBreakSwitch", + "Recloser", + "Breaker"]: + if property_name in ["power_in_"+phases, + "voltage_"+phases, + "current_in_"+phases]: + val = complex(val_str) + (mag,ang_rad) = cmath.polar(val) + ang_deg = math.degrees(ang_rad) + measurement["magnitude"] = mag + measurement["angle"] = ang_deg + else: + if val_str == "OPEN": + measurement["value"] = 0 + else: + measurement["value"] = 1 + elif conducting_equipment_type == "RatioTapChanger": + if property_name in ["power_in_"+phases, + "voltage_"+phases, + "current_in_"+phases]: + val = complex(val_str) + (mag,ang_rad) = cmath.polar(val) + ang_deg = math.degrees(ang_rad) + measurement["magnitude"] = mag + measurement["angle"] = ang_deg else: - measurement["value"] = 1 - elif conducting_equipment_type == "RatioTapChanger": - if property_name in ["power_in_"+phases,"voltage_"+phases,"current_in_"+phases]: - val = complex(val_str) - (mag,ang_rad) = cmath.polar(val) - ang_deg = math.degrees(ang_rad) - measurement["magnitude"] = mag - measurement["angle"] = ang_deg + measurement["value"] = int(val_str) else: - measurement["value"] = int(val_str) - else: - log.warning("{} is not a recognized conducting equipment type.".format(conducting_equipment_type)) - self._gad_connection.send_simulation_status('RUNNING', conducting_equipment_type+" not recognized", 'WARN') - raise RuntimeError("{} is not a recognized conducting equipment type.".format(conducting_equipment_type)) - # Should it raise runtime? - # change to be a dictionary rather than an array - cim_measurements_dict['message']["measurements"][measurement["measurement_mrid"]] = measurement - cim_output = cim_measurements_dict - else: - err_msg = "The message recieved from the simulator did not have the simulation id as a key in the json message." - log.error(err_msg) - self._gad_connection.send_simulation_status('ERROR', err_msg, 'ERROR') - raise RuntimeError(err_msg) - log.debug(f"Message from simulation processing time: {time.perf_counter() - get_helics_bus_messages_start}.") - return cim_output + warnStr = f"{conducting_equipment_type} is not a recognized " \ + "conducting equipment type." + log.warning(warnStr) + self._gad_connection.send_simulation_status('RUNNING', warnStr, 'WARN') + raise RuntimeError(warnStr) + # Should it raise runtime? + # change to be a dictionary rather than an array + cim_measurements_dict['message']["measurements"][measurement["measurement_mrid"]] = measurement + cim_output = cim_measurements_dict + log.debug(f"measurement message recieved at timestep {current_time}.") + self._gad_connection.send(topics.simulation_output_topic(self._simulation_id), + json.dumps(cim_output, indent=4, sort_keys=True)) + if pause_after_measurements: + self._pause_simulation = True + debugStr = "Simulation paused automatically after publishing measurements." + log.debug(debugStr) + self._gad_connection.send_simulation_status('PAUSED', debugStr, 'INFO') + log.debug("Message from simulation processing time: " + f"{time.perf_counter() - get_helics_bus_messages_start}.") + return {} except ValueError as ve: - raise RuntimeError("{}.\nObject Name: {}\nObject Type: {}\nProperty Name: {}\n Property Value{}".format(str(ve), objectName, objectType, propertyName, propertyValue)) + raise RuntimeError(f"{str(ve)}.\nObject Name: {objectName}\nObject Type: {objectType}\nProperty Name: " + f"{propertyName}\nProperty Value: {propertyValue}\nCIM Measurement Phases: {phases}") except Exception as e: - message_str = 'Error on get HELICS Bus Messages for '+str(self._simulation_id)+' '+str(traceback.format_exc()) + message_str = f'Error on get HELICS Bus Messages for {self._simulation_id} {traceback.format_exc()}' log.error(message_str) self._gad_connection.send_simulation_status('ERROR', message_str, 'ERROR') return {} @@ -1096,17 +1227,16 @@ def _done_with_time_step(self, current_time): """ done_with_time_step_start = time.perf_counter() try: - if current_time == None or type(current_time) != int: + if current_time == None or not isinstance(current_time, int): raise ValueError( 'current_time must be an integer.\n' - + 'current_time = {0}'.format(current_time)) + + f'current_time = {current_time}') time_request = float(current_time + 1) time_approved = helics.helicsFederateRequestTime(self._helics_federate, time_request) if time_approved != time_request: raise RuntimeError( 'The time approved from helics_broker is not the time requested.\n' - + 'time_request = {0}.\ntime_approved = {1}'.format(time_request, - time_approved)) + + f'time_request = {time_request}.\ntime_approved = {time_approved}') log.debug(f"done_with_time_step took {time.perf_counter() - done_with_time_step_start} seconds to finish.") except Exception as e: message_str = 'Error in HELICS time request '+str(traceback.format_exc()) @@ -1114,264 +1244,635 @@ def _done_with_time_step(self, current_time): self._gad_connection.send_simulation_status('ERROR', message_str, 'ERROR') - def _create_cim_object_map(self,map_file=None): - if map_file == None: - map_file="/tmp/gridappsd_tmp/{}/model_dict.json".format(self._simulation_id) + def _create_cim_object_map(self, map_file_dir: Path = None): + self._object_property_to_measurement_id = {} + self._object_mrid_to_name = {} + try: - with open(map_file, "r", encoding="utf-8") as file_input_stream: - file_dict = json.load(file_input_stream) - feeders = file_dict.get("feeders",[]) - self._object_property_to_measurement_id = {} - self._object_mrid_to_name = {} - for x in feeders: - self._model_mrid = x.get("mRID","") - measurements = x.get("measurements",[]) - capacitors = x.get("capacitors",[]) - regulators = x.get("regulators",[]) - switches = x.get("switches",[]) - batteries = x.get("batteries", []) - solarpanels = x.get("solarpanels",[]) - synchronousMachines = x.get("synchronousmachines", []) - breakers = x.get("breakers", []) - reclosers = x.get("reclosers", []) - energy_consumers = x.get("energyconsumers", []) - #TODO: add more object types to handle - for y in measurements: - measurement_type = y.get("measurementType") - phases = y.get("phases") - if phases == "s1": - phases = "1" - elif phases == "s2": - phases = "2" - conducting_equipment_type = y.get("name") - conducting_equipment_name = y.get("SimObject") - connectivity_node = y.get("ConnectivityNode") - measurement_mrid = y.get("mRID") - if "LinearShuntCompensator" in conducting_equipment_type: - if measurement_type == "VA": - object_name = conducting_equipment_name; - property_name = "shunt_" + phases; - elif measurement_type == "Pos": - object_name = conducting_equipment_name; - property_name = "switch" + phases; - elif measurement_type == "PNV": - object_name = conducting_equipment_name; - property_name = "voltage_" + phases; - else: - raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid type.\nValid types for LinearShuntCompensators are VA, Pos, and PNV.\nmeasurement_type = {}.".format(measurement_type)) - elif "PowerTransformer" in conducting_equipment_type: - if measurement_type == "VA": - object_name = conducting_equipment_name; - property_name = "power_in_" + phases; - elif measurement_type == "PNV": - object_name = connectivity_node; - property_name = "voltage_" + phases; - elif measurement_type == "A": - object_name = conducting_equipment_name; - property_name = "current_in_" + phases; - else: - raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid type.\nValid types for PowerTransformer are VA, PNV, and A.\nmeasurement_type = {}.".format(measurement_type)) - elif "RatioTapChanger" in conducting_equipment_type: - if measurement_type == "VA": - object_name = conducting_equipment_name; - property_name = "power_in_" + phases; - elif measurement_type == "PNV": - object_name = connectivity_node; - property_name = "voltage_" + phases; - elif measurement_type == "Pos": - object_name = conducting_equipment_name; - property_name = "tap_" + phases; - elif measurement_type == "A": - object_name = conducting_equipment_name; - property_name = "current_in_" + phases; - else: - raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid type.\nValid types for RatioTapChanger are VA, PNV, Pos, and A.\nmeasurement_type = {}.".format(measurement_type)) - elif "ACLineSegment" in conducting_equipment_type: - if measurement_type == "VA": - object_name = conducting_equipment_name; - if phases == "1": - property_name = "power_in_A" - elif phases == "2": - property_name = "power_in_B" + for modelMrid, graphModel in self._graphModels["distributionModels"].items(): + map_file_dir = f"/tmp/gridappsd_tmp/{self._simulation_id}/{modelMrid}/model_dict.json" + with open(map_file_dir, "r", encoding="utf-8") as file_input_stream: + file_dict = json.load(file_input_stream) + feeders = file_dict.get("feeders", []) + self._object_property_to_measurement_id[modelMrid] = {} + self._object_mrid_to_name[modelMrid] = {} + for x in feeders: + self._model_mrid = x.get("mRID","") + measurements = x.get("measurements",[]) + capacitors = x.get("capacitors",[]) + regulators = x.get("regulators",[]) + switches = x.get("switches",[]) + batteries = x.get("batteries", []) + solarpanels = x.get("solarpanels",[]) + synchronousMachines = x.get("synchronousmachines", []) + breakers = x.get("breakers", []) + reclosers = x.get("reclosers", []) + energy_consumers = x.get("energyconsumers", []) + #TODO: add more object types to handle + for y in measurements: + measurement_type = y.get("measurementType") + phases = y.get("phases") + if phases == "s1": + phases = "1" + elif phases == "s2": + phases = "2" + conducting_equipment_type = y.get("name") + conducting_equipment_name = y.get("SimObject") + connectivity_node = y.get("ConnectivityNode") + measurement_mrid = y.get("mRID") + if "LinearShuntCompensator" in conducting_equipment_type: + if measurement_type == "VA": + object_name = conducting_equipment_name; + property_name = "shunt_" + phases; + elif measurement_type == "Pos": + object_name = conducting_equipment_name; + property_name = "switch" + phases; + elif measurement_type == "PNV": + object_name = conducting_equipment_name; + property_name = "voltage_" + phases; else: - property_name = "power_in_" + phases - elif measurement_type == "PNV": - object_name = connectivity_node; - property_name = "voltage_" + phases; - elif measurement_type == "A": - object_name = conducting_equipment_name; - if phases == "1": - property_name = "current_in_A" - elif phases == "2": - property_name = "current_in_B" + raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + "type.\nValid types for LinearShuntCompensators are VA, Pos, and PNV.\n" + f"measurement_type = {measurement_type}.") + elif "PowerTransformer" in conducting_equipment_type \ + or "TransformerTank" in conducting_equipment_type: + if measurement_type == "VA": + object_name = conducting_equipment_name; + property_name = "power_in_" + phases; + elif measurement_type == "PNV": + object_name = connectivity_node; + property_name = "voltage_" + phases; + elif measurement_type == "A": + object_name = conducting_equipment_name; + property_name = "current_in_" + phases; else: - property_name = "current_in_" + phases - else: - raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid type.\nValid types for ACLineSegment are VA, PNV, and A.\nmeasurement_type = {}.".format(measurement_type)) - elif "LoadBreakSwitch" in conducting_equipment_type or "Recloser" in conducting_equipment_type or "Breaker" in conducting_equipment_type: - if measurement_type == "VA": - object_name = conducting_equipment_name; - property_name = "power_in_" + phases; - elif measurement_type == "PNV": - object_name = connectivity_node; - property_name = "voltage_" + phases; - elif measurement_type == "Pos": - object_name = conducting_equipment_name - property_name = "status" - elif measurement_type == "A": - object_name = conducting_equipment_name; - property_name = "current_in_" + phases; - else: - raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid type.\nValid types for LoadBreakSwitch are VA, PNV, and A.\nmeasurement_type = {}.".format(measurement_type)) - elif "EnergyConsumer" in conducting_equipment_type: - if measurement_type == "VA": - object_name = conducting_equipment_name; - if phases in ["1","2"]: - property_name = "indiv_measured_power_" + phases; + raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + "type.\nValid types for PowerTransformer and TransformerTank are VA, " + f"PNV, and A.\nmeasurement_type = {measurement_type}.") + elif "RatioTapChanger" in conducting_equipment_type: + if measurement_type == "VA": + object_name = conducting_equipment_name; + property_name = "power_in_" + phases; + elif measurement_type == "PNV": + object_name = connectivity_node; + property_name = "voltage_" + phases; + elif measurement_type == "Pos": + object_name = conducting_equipment_name; + property_name = "tap_" + phases; + elif measurement_type == "A": + object_name = conducting_equipment_name; + property_name = "current_in_" + phases; else: - property_name = "measured_power_" + phases; - elif measurement_type == "PNV": - object_name = connectivity_node; - property_name = "voltage_" + phases; - elif measurement_type == "A": - object_name = connectivity_node; - property_name = "measured_current_" + phases; - else: - raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid type.\nValid types for EnergyConsumer are VA, A, and PNV.\nmeasurement_type = %s.".format(measurement_type)) - elif "PowerElectronicsConnection" in conducting_equipment_type: - if measurement_type == "VA": - object_name = conducting_equipment_name; - if phases in ["1","2"]: - property_name = "indiv_measured_power_" + phases; + raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + "type.\nValid types for RatioTapChanger are VA, PNV, Pos, and A.\n" + f"measurement_type = {measurement_type}.") + elif "ACLineSegment" in conducting_equipment_type: + if measurement_type == "VA": + object_name = conducting_equipment_name; + if phases == "1": + property_name = "power_in_A" + elif phases == "2": + property_name = "power_in_B" + else: + property_name = "power_in_" + phases + elif measurement_type == "PNV": + object_name = connectivity_node; + property_name = "voltage_" + phases; + elif measurement_type == "A": + object_name = conducting_equipment_name; + if phases == "1": + property_name = "current_in_A" + elif phases == "2": + property_name = "current_in_B" + else: + property_name = "current_in_" + phases + else: + raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + "type.\nValid types for ACLineSegment are VA, PNV, and A.\n" + f"measurement_type = {measurement_type}.") + elif "LoadBreakSwitch" in conducting_equipment_type \ + or "Recloser" in conducting_equipment_type \ + or "Breaker" in conducting_equipment_type: + if measurement_type == "VA": + object_name = conducting_equipment_name; + property_name = "power_in_" + phases; + elif measurement_type == "PNV": + object_name = connectivity_node; + property_name = "voltage_" + phases; + elif measurement_type == "Pos": + object_name = conducting_equipment_name + property_name = "status" + elif measurement_type == "A": + object_name = conducting_equipment_name; + property_name = "current_in_" + phases; + else: + raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + "type.\nValid types for LoadBreakSwitch are VA, PNV, and A.\n" + f"measurement_type = {measurement_type}.") + elif "EnergyConsumer" in conducting_equipment_type: + if measurement_type == "VA": + object_name = conducting_equipment_name; + if phases in ["1","2"]: + property_name = "indiv_measured_power_" + phases; + else: + property_name = "measured_power_" + phases; + elif measurement_type == "PNV": + object_name = connectivity_node; + property_name = "voltage_" + phases; + elif measurement_type == "A": + object_name = connectivity_node; + property_name = "measured_current_" + phases; else: + raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + "type.\nValid types for EnergyConsumer are VA, A, and PNV.\n" + f"measurement_type = {measurement_type}.") + elif "PowerElectronicsConnection" in conducting_equipment_type: + if measurement_type == "VA": + object_name = conducting_equipment_name; + if phases in ["1","2"]: + property_name = "indiv_measured_power_" + phases; + else: + property_name = "measured_power_" + phases; + elif measurement_type == "PNV": + object_name = conducting_equipment_name; + property_name = "voltage_" + phases; + elif measurement_type == "A": + object_name = conducting_equipment_name; + property_name = "measured_current_" + phases; + elif measurement_type == "SoC": + object_name = conducting_equipment_name + property_name = "state_of_charge" + else: + raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + "type.\nValid types for PowerElectronicsConnection are VA, A, SoC, and " + f"PNV.\nmeasurement_type = {measurement_type}") + elif "SynchronousMachine" in conducting_equipment_type: + if measurement_type == "VA": + object_name = conducting_equipment_name; property_name = "measured_power_" + phases; - elif measurement_type == "PNV": - object_name = conducting_equipment_name; - property_name = "voltage_" + phases; - elif measurement_type == "A": - object_name = conducting_equipment_name; - property_name = "measured_current_" + phases; - elif measurement_type == "SoC": - object_name = conducting_equipment_name - property_name = "state_of_charge" - else: - raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid type.\nValid types for PowerElectronicsConnection are VA, A, SoC, and PNV.\nmeasurement_type = %s.".format(measurement_type)) - elif "SynchronousMachine" in conducting_equipment_type: - if measurement_type == "VA": - object_name = conducting_equipment_name; - property_name = "measured_power_" + phases; - elif measurement_type == "PNV": - object_name = connectivity_node; - property_name = "voltage_" + phases; - elif measurement_type == "A": - object_name = connectivity_node; - property_name = "measured_current_" + phases; + elif measurement_type == "PNV": + object_name = connectivity_node; + property_name = "voltage_" + phases; + elif measurement_type == "A": + object_name = connectivity_node; + property_name = "measured_current_" + phases; + else: + raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + "type.\nValid types for SynchronousMachine are VA, A, and PNV.\n" + f"measurement_type = {measurement_type}.") else: - raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid type.\nValid types for SynchronousMachine are VA, A, and PNV.\nmeasurement_type = %s.".format(measurement_type)) - else: - raise RuntimeError("_create_cim_object_map: The value of conducting_equipment_type is not a valid type.\nValid types for conducting_equipment_type are ACLineSegment, LinearShuntCompesator, LoadBreakSwitch, PowerElectronicsConnection, EnergyConsumer, RatioTapChanger, and PowerTransformer.\nconducting_equipment_type = {}.".format(conducting_equipment_type)) + raise RuntimeError("_create_cim_object_map: The value of conducting_equipment_type is not a " + "valid type.\nValid types for conducting_equipment_type are ACLineSegment, " + "LinearShuntCompesator, LoadBreakSwitch, PowerElectronicsConnection, " + "EnergyConsumer, RatioTapChanger, and PowerTransformer.\n" + f"conducting_equipment_type = {conducting_equipment_type}.") - property_dict = { - "property" : property_name, - "conducting_equipment_type" : conducting_equipment_type, - "measurement_mrid" : measurement_mrid, - "phases" : phases - } - if object_name in self._object_property_to_measurement_id.keys(): - self._object_property_to_measurement_id[object_name].append(property_dict) - else: - self._object_property_to_measurement_id[object_name] = [] - self._object_property_to_measurement_id[object_name].append(property_dict) - for y in capacitors: - self._object_mrid_to_name[y.get("mRID")] = { - "name" : y.get("name"), - "phases" : y.get("phases"), - "total_phases" : y.get("phases"), - "type" : "capacitor", - "prefix" : "cap_" - } - for y in regulators: - object_mrids = y.get("mRID",[]) - object_name = y.get("bankName") - object_phases = y.get("endPhase",[]) - for z in range(len(object_mrids)): - self._object_mrid_to_name[object_mrids[z]] = { - "name" : object_name, - "phases" : object_phases[z], - "total_phases" : "".join(object_phases), - "type" : "regulator", - "prefix" : "reg_" + property_dict = { + "property" : property_name, + "conducting_equipment_type" : conducting_equipment_type, + "measurement_mrid" : measurement_mrid, + "phases" : phases } - for y in switches: - self._object_mrid_to_name[y.get("mRID")] = { - "name" : y.get("name"), - "phases" : y.get("phases"), - "total_phases" : y.get("phases"), - "type" : "switch", - "prefix" : "sw_" - } - for y in solarpanels: - self._object_mrid_to_name[y.get("mRID")] = { - "name" : y.get("name"), - "phases" : y.get("phases"), - "total_phases" : y.get("phases"), - "type" : "pv", - "prefix" : "pv_" - } - for y in batteries: - self._object_mrid_to_name[y.get("mRID")] = { - "name" : y.get("name"), - "phases" : y.get("phases"), - "total_phases" : y.get("phases"), - "type" : "battery", - "prefix" : "batt_" - } - for y in synchronousMachines: - self._object_mrid_to_name[y.get("mRID")] = { - "name" : y.get("name"), - "phases" : y.get("phases"), - "total_phases" : y.get("phases"), - "type" : "diesel_dg", - "prefix" : "dg_" - } - for y in breakers: - self._object_mrid_to_name[y.get("mRID")] = { - "name" : y.get("name"), - "phases" : y.get("phases"), - "total_phases" : y.get("phases"), - "type" : "switch", - "prefix" : "sw_" - } - for y in reclosers: - self._object_mrid_to_name[y.get("mRID")] = { - "name" : y.get("name"), - "phases" : y.get("phases"), - "total_phases" : y.get("phases"), - "type" : "recloser", - "prefix" : "sw_" - } - for y in energy_consumers: - self._object_mrid_to_name[y.get("mRID")] = { - "name" : y.get("name"), - "phases" : y.get("phases"), - "total_phases" : y.get("phases"), - "prefix" : "ld_" - } - if "s1" in self._object_mrid_to_name[y.get("mRID")]["phases"] or "s2" in self._object_mrid_to_name[y.get("mRID")]["phases"]: - self._object_mrid_to_name[y.get("mRID")]["type"] = "triplex_load" - else: - self._object_mrid_to_name[y.get("mRID")]["type"] = "load" + if object_name in self._object_property_to_measurement_id[modelMrid].keys(): + self._object_property_to_measurement_id[modelMrid][object_name].append(property_dict) + else: + self._object_property_to_measurement_id[modelMrid][object_name] = [] + self._object_property_to_measurement_id[modelMrid][object_name].append(property_dict) + for y in capacitors: + self._object_mrid_to_name[modelMrid][y.get("mRID")] = { + "name" : y.get("name"), + "phases" : y.get("phases"), + "total_phases" : y.get("phases"), + "type" : "capacitor", + "prefix" : "cap_" + } + for y in regulators: + object_mrids = y.get("mRIDs",[]) + object_name = y.get("bankName") + object_phases = y.get("endPhases",[]) + for z in range(len(object_mrids)): + self._object_mrid_to_name[modelMrid][object_mrids[z]] = { + "name" : object_name, + "phases" : object_phases[z], + "total_phases" : "".join(object_phases), + "type" : "regulator", + "prefix" : "xf_" + } + for y in switches: + self._object_mrid_to_name[modelMrid][y.get("mRID")] = { + "name" : y.get("name"), + "phases" : y.get("phases"), + "total_phases" : y.get("phases"), + "type" : "switch", + "prefix" : "sw_" + } + for y in solarpanels: + self._object_mrid_to_name[modelMrid][y.get("mRID")] = { + "name" : y.get("name"), + "phases" : y.get("phases"), + "total_phases" : y.get("phases"), + "type" : "pv", + "prefix" : "pv_" + } + for y in batteries: + self._object_mrid_to_name[modelMrid][y.get("mRID")] = { + "name" : y.get("name"), + "phases" : y.get("phases"), + "total_phases" : y.get("phases"), + "type" : "battery", + "prefix" : "batt_" + } + for y in synchronousMachines: + self._object_mrid_to_name[modelMrid][y.get("mRID")] = { + "name" : y.get("name"), + "phases" : y.get("phases"), + "total_phases" : y.get("phases"), + "type" : "diesel_dg", + "prefix" : "dg_" + } + for y in breakers: + self._object_mrid_to_name[modelMrid][y.get("mRID")] = { + "name" : y.get("name"), + "phases" : y.get("phases"), + "total_phases" : y.get("phases"), + "type" : "switch", + "prefix" : "sw_" + } + for y in reclosers: + self._object_mrid_to_name[modelMrid][y.get("mRID")] = { + "name" : y.get("name"), + "phases" : y.get("phases"), + "total_phases" : y.get("phases"), + "type" : "recloser", + "prefix" : "sw_" + } + for y in energy_consumers: + self._object_mrid_to_name[modelMrid][y.get("mRID")] = { + "name" : y.get("name"), + "phases" : y.get("phases"), + "total_phases" : y.get("phases"), + "prefix" : "ld_" + } + if "s1" in self._object_mrid_to_name[modelMrid][y.get("mRID")]["phases"] \ + or "s2" in self._object_mrid_to_name[modelMrid][y.get("mRID")]["phases"]: + self._object_mrid_to_name[modelMrid][y.get("mRID")]["type"] = "triplex_load" + else: + self._object_mrid_to_name[modelMrid][y.get("mRID")]["type"] = "load" + # measurements = {} + # measurements.update(graphModel.graph.get(cim.Analog, {})) + # measurements.update(graphModel.graph.get(cim.Discrete, {})) + # capacitors = graphModel.graph.get(cim.LinearShuntCompensator, {}) + # xfmrs = graphModel.graph.get(cim.PowerTransformer, {}) + # regulators = [] + # for xfmr in xfmrs.values(): + # isRegulator = False + # for powerTransformerEnd in xfmr.PowerTransformerEnd: + # if powerTransformerEnd.RatioTapChanger: + # isRegulator = True + # break + # for transformerTank in xfmr.TransformerTanks: + # for transformerEnd in transformerTank.TransformerTankEnds: + # if transformerEnd.RatioTapChanger: + # isRegulator = True + # break + # if isRegulator: + # break + # if isRegulator: + # regulators.append(xfmr) + # switches = {} + # switches.update(graphModel.graph.get(cim.LoadBreakSwitch,{})) + # switches.update(graphModel.graph.get(cim.Breaker,{})) + # switches.update(graphModel.graph.get(cim.Recloser,{})) + # inverters = graphModel.graph.get(cim.PowerElectronicsConnection, {}) + # batteries = {} + # solarpanels = {} + # for objId, obj in inverters.items(): + # if isinstance(obj.PowerElectronicsUnit[0], cim.BatteryUnit): + # batteries[objId] = obj + # elif isinstance(obj.PowerElectronicsUnit[0], cim.PhotovoltaicUnit): + # solarpanels[objId] = obj + # synchronousMachines = graphModel.graph.get(cim.SynchronousMachine, {}) + # energy_consumers = graphModel.graph.get(cim.EnergyConsumer, {}) + # #TODO: add more object types to handle + # for objMrid, obj in measurements.items(): + # measurement_type = obj.measurementType + # phases = obj.phases.value + # if phases == "s1": + # phases = "1" + # elif phases == "s2": + # phases = "2" + # powerSystemResource = obj.PowerSystemResource + # terminal = obj.Terminal + # if isinstance(powerSystemResource, cim.LinearShuntCompensator): + # if measurement_type == "VA": + # object_name = f"cap_{powerSystemResource.name}" + # property_name = "shunt_" + phases + # elif measurement_type == "Pos": + # object_name = f"cap_{powerSystemResource.name}" + # property_name = "switch" + phases + # elif measurement_type == "PNV": + # object_name = terminal.ConnectivityNode.name + # property_name = "voltage_" + phases + # else: + # raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + # "type.\nValid types for LinearShuntCompensators are VA, Pos, and PNV.\n" + # f"measurement_type = {measurement_type}.") + # elif isinstance(powerSystemResource, cim.PowerTransformer): + # if measurement_type == "VA": + # object_name = f"xf_{powerSystemResource.name}" + # property_name = "power_in_" + phases + # elif measurement_type == "PNV": + # object_name = terminal.ConnectivityNode.name + # property_name = "voltage_" + phases + # elif measurement_type == "A": + # object_name = f"xf_{powerSystemResource.name}" + # property_name = "current_in_" + phases + # elif measurement_type == "Pos" and powerSystemResource in regulators: + # object_name = f"xf_{powerSystemResource.name}" + # property_name = "tap_" + phases + # else: + # raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + # "type.\nValid types for PowerTransformer are VA, PNV, A, and Pos.\n" + # f"measurement_type = {measurement_type}.") + # elif isinstance(powerSystemResource, cim.ACLineSegment): + # if measurement_type == "VA": + # object_name = f"line_{powerSystemResource.name}" + # if phases == "1": + # property_name = "power_in_A" + # elif phases == "2": + # property_name = "power_in_B" + # else: + # property_name = "power_in_" + phases + # elif measurement_type == "PNV": + # object_name = terminal.ConnectivityNode.name + # property_name = "voltage_" + phases + # elif measurement_type == "A": + # object_name = f"line_{powerSystemResource.name}" + # if phases == "1": + # property_name = "current_in_A" + # elif phases == "2": + # property_name = "current_in_B" + # else: + # property_name = "current_in_" + phases + # else: + # raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + # "type.\nValid types for ACLineSegment are VA, PNV, and A.\n" + # f"measurement_type = {measurement_type}.") + # elif isinstance(powerSystemResource, (cim.Breaker, cim.LoadBreakSwitch, cim.Recloser)): + # if measurement_type == "VA": + # object_name = f"swt_{powerSystemResource.name}" + # property_name = "power_in_" + phases + # elif measurement_type == "PNV": + # object_name = terminal.ConnectivityNode.name + # property_name = "voltage_" + phases + # elif measurement_type == "Pos": + # object_name = f"swt_{powerSystemResource.name}" + # property_name = "status" + # elif measurement_type == "A": + # object_name = f"swt_{powerSystemResource.name}" + # property_name = "current_in_" + phases + # else: + # raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + # "type.\nValid types for LoadBreakSwitch are VA, PNV, and A.\n" + # f"measurement_type = {measurement_type}.") + # elif isinstance(powerSystemResource, cim.EnergyConsumer): + # if measurement_type == "VA": + # object_name = f"ld_{powerSystemResource.name}" + # if phases in ["1","2"]: + # property_name = "indiv_measured_power_" + phases + # else: + # property_name = "measured_power_" + phases + # elif measurement_type == "PNV": + # object_name = terminal.ConnectivityNode.name + # property_name = "voltage_" + phases + # elif measurement_type == "A": + # object_name = terminal.ConnectivityNode.name + # property_name = "measured_current_" + phases + # else: + # raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + # "type.\nValid types for EnergyConsumer are VA, A, and PNV.\n" + # f"measurement_type = {measurement_type}.") + # elif isinstance(powerSystemResource, cim.PowerElectronicsConnection): + # if isinstance(powerSystemResource.PowerElectronicsUnit[0], cim.PhotovoltaicUnit): + # suffix = "_pvmtr" + # elif isinstance(powerSystemResource.PowerElectronicsUnit[0], cim.BatteryUnit): + # suffix = "_stmtr" + # else: + # continue + # if measurement_type == "VA": + # object_name = f"{terminal.ConnectivityNode.name}{suffix}" + # if phases in ["1","2"]: + # property_name = "indiv_measured_power_" + phases + # else: + # property_name = "measured_power_" + phases + # elif measurement_type == "PNV": + # object_name = f"{terminal.ConnectivityNode.name}{suffix}" + # property_name = "voltage_" + phases + # elif measurement_type == "A": + # object_name = f"{terminal.ConnectivityNode.name}{suffix}" + # property_name = "measured_current_" + phases + # elif measurement_type == "SoC": + # object_name = f"bat_{powerSystemResource.PowerElectronicsUnit[0].name}" + # property_name = "state_of_charge" + # else: + # raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + # "type.\nValid types for PowerElectronicsConnection are VA, A, SoC, and " + # f"PNV.\nmeasurement_type = {measurement_type}") + # elif isinstance(powerSystemResource, cim.SynchronousMachine): + # if measurement_type == "VA": + # object_name = terminal.ConnectivityNode.name + # property_name = "measured_power_" + phases + # elif measurement_type == "PNV": + # object_name = terminal.ConnectivityNode.name + # property_name = "voltage_" + phases + # elif measurement_type == "A": + # object_name = terminal.ConnectivityNode.name + # property_name = "measured_current_" + phases + # else: + # raise RuntimeError("_create_cim_object_map: The value of measurement_type is not a valid " + # "type.\nValid types for SynchronousMachine are VA, A, and PNV.\n" + # f"measurement_type = {measurement_type}.") + # else: + # raise RuntimeError("_create_cim_object_map: The PowerSystemResource of the measurement is not " + # "a supported class type.\nValid types are ACLineSegment, " + # "LinearShuntCompesator, LoadBreakSwitch, PowerElectronicsConnection, " + # "EnergyConsumer, RatioTapChanger, PowerTransformer, and SynchronousMachine." + # f"\npowerSystemResource = {type(powerSystemResource)}.") + + # property_dict = { + # "property" : property_name, + # "power_system_resource" : powerSystemResource, + # "measurement_mrid" : obj.mRID, + # "phases" : phases + # } + # if object_name in self._object_property_to_measurement_id[modelMrid].keys(): + # self._object_property_to_measurement_id[modelMrid][object_name].append(property_dict) + # else: + # self._object_property_to_measurement_id[modelMrid][object_name] = [] + # self._object_property_to_measurement_id[modelMrid][object_name].append(property_dict) + # for obj in capacitors.values(): + # self._object_mrid_to_name[modelMrid][obj.mRID] = { + # "name" : f"{obj.name}", + # "phases" : getEqPhases(obj), + # "total_phases" : getEqPhases(obj), + # "type" : "capacitor", + # "prefix" : "cap_" + # } + # for y in regulators: + # object_mrids = [] + # object_name = y.name + # object_phases = [] + # for powerTransformerEnd in y.PowerTransformerEnd: + # if powerTransformerEnd.RatioTapChanger: + # self._object_mrid_to_name[modelMrid][powerTransformerEnd.RatioTapChanger.mRID] = { + # "name" : object_name, + # "phases" : "ABC", + # "total_phases" : "ABC", + # "type" : "regulator", + # "prefix" : "xf_" + # } + # for transformerTank in y.TransformerTanks: + # for tankEnd in transformerTank.TransformerTankEnds: + # if tankEnd.RatioTapChanger: + # object_mrids.append(tankEnd.RatioTapChanger.mRID) + # object_phases.append(tankEnd.orderedPhases.value) + # for z in range(len(object_mrids)): + # sortedPhases = deepcopy(object_phases) + # sortedPhases.sort() + # self._object_mrid_to_name[modelMrid][object_mrids[z]] = { + # "name" : object_name, + # "phases" : object_phases[z], + # "total_phases" : "".join(sortedPhases), + # "type" : "regulator", + # "prefix" : "xf_" + # } + # for obj in switches.values(): + # self._object_mrid_to_name[modelMrid][obj.mRID] = { + # "name" : obj.name, + # "phases" : getEqPhases(obj), + # "total_phases" : getEqPhases(obj), + # "type" : "switch", + # "prefix" : "sw_" + # } + # for obj in solarpanels.values(): + # self._object_mrid_to_name[modelMrid][obj.mRID] = { + # "name" : obj.name, + # "phases" : getEqPhases(obj), + # "total_phases" : getEqPhases(obj), + # "type" : "pv", + # "prefix" : "inv_pv_" + # } + # for obj in batteries.values(): + # self._object_mrid_to_name[modelMrid][obj.mRID] = { + # "name" : obj.name, + # "phases" : getEqPhases(obj), + # "total_phases" : getEqPhases(obj), + # "type" : "battery", + # "prefix" : "inv_bat_" + # } + # for obj in synchronousMachines.values(): + # self._object_mrid_to_name[modelMrid][obj.mRID] = { + # "name" : obj.name, + # "phases" : "ABC", + # "total_phases" : "ABC", + # "type" : "diesel_dg", + # "prefix" : "dg_" + # } + # for obj in energy_consumers.values(): + # self._object_mrid_to_name[modelMrid][obj.mRID] = { + # "name" : obj.name, + # "phases" : getEqPhases(obj), + # "total_phases" : getEqPhases(obj), + # "prefix" : "ld_" + # } + # if "s1" in self._object_mrid_to_name[modelMrid][obj.mRID]["phases"] \ + # or "s2" in self._object_mrid_to_name[modelMrid][obj.mRID]["phases"]: + # self._object_mrid_to_name[modelMrid][obj.mRID]["type"] = "triplex_load" + # else: + # self._object_mrid_to_name[modelMrid][obj.mRID]["type"] = "load" except Exception as e: - log.error("The measurement map file, {}, couldn't be translated.\nError:{}".format(map_file, traceback.format_exc())) - self._gad_connection.send_simulation_status('STARTED', "The measurement map file, {}, couldn't be translated.\nError:{}".format(map_file, traceback.format_exc()), 'ERROR') - - + errStr = f"The cim object map couldn't be created.\nError:{traceback.format_exc()}" + print(errStr) + log.error(errStr) + self._gad_connection.send_simulation_status('STARTED', errStr, 'ERROR') + + + def _generate_cimgraph_models(self): + os.environ['CIMG_CIM_PROFILE'] = 'cimhub_2023' + os.environ['CIMG_URL'] = 'http://blazegraph:8080/bigdata/namespace/kb/sparql' + os.environ['CIMG_DATABASE'] = 'powergridmodel' + os.environ['CIMG_HOST'] = 'localhost' + os.environ['CIMG_PORT'] = '61613' + os.environ['CIMG_USERNAME'] = 'system' + os.environ['CIMG_PASSWORD'] = 'manager' + os.environ['CIMG_NAMESPACE'] = 'http://iec.ch/TC57/CIM100#' + os.environ['CIMG_IEC61970_301'] = '8' + os.environ['CIMG_USE_UNITS'] = 'False' + self._dbConnection = BlazegraphConnection() + self._graphModels = {"distributionModels": {}, "transmissionModels": {}} + for powerSystemConfig in self._simulation_request.get("power_system_configs", []): + modelContainer = self._dbConnection.get_object(mRID=powerSystemConfig["Line_name"]) + if isinstance(modelContainer, cim.Feeder): + self._graphModels["distributionModels"][powerSystemConfig["Line_name"]] = FeederModel( + connection=self._dbConnection, + container=modelContainer, + distributed=False) + cimUtils.get_all_data(self._graphModels["distributionModels"][powerSystemConfig["Line_name"]]) + +def getEqPhases(cimObj: cim.PowerSystemResource) -> str: + if not isinstance(cimObj, cim.PowerSystemResource): + raise TypeError("Argument cimObj is not a child class of cim.PowerSystemResource. cimObj is of type " + f"{type(cimObj)}") + phases = [] + phaseStr = "" + if isinstance(cimObj, cim.LinearShuntCompensator): + for linearShuntCompensatorPhase in cimObj.ShuntCompensatorPhase: + if linearShuntCompensatorPhase.phase != cim.SinglePhaseKind.N: + phases.append(linearShuntCompensatorPhase.phase.value) + if len(phases) == 0: + phases = ["A", "B", "C"] + elif isinstance(cimObj, cim.Switch): + for switchPhase in cimObj.SwitchPhase: + if switchPhase.phaseSide1 != cim.SinglePhaseKind.N: + phases.append(switchPhase.phaseSide1.value) + if len(phases) == 0: + phases = ["A", "B", "C"] + elif isinstance(cimObj, cim.PowerElectronicsConnection): + for powerElectronicsPhase in cimObj.PowerElectronicsConnectionPhases: + if powerElectronicsPhase.phase != cim.SinglePhaseKind.N: + phases.append(powerElectronicsPhase.phase.value) + if len(phases) == 0: + phases = ["A", "B", "C"] + elif isinstance(cimObj, cim.EnergyConsumer): + for energyConsumerPhase in cimObj.EnergyConsumerPhase: + if energyConsumerPhase.phase != cim.SinglePhaseKind.N: + phases.append(energyConsumerPhase.phase.value) + if len(phases) == 0: + phases = ["A", "B", "C"] + else: + raise TypeError("The class type of cimObj is not supported by getEqPhases yet. cimObj is of type " + f"{type(cimObj)}") + phases.sort() + phaseStr = "".join(phases) + return phaseStr + + +def _getEquipmentContainer(cimMrid: str, dbConnection: BlazegraphConnection): + cimObj = dbConnection.get_object(cimMrid) + equipmentContainer = None + eqContainerMrid = None + if isinstance(cimObj, cim.Equipment): + equipmentContainer = cimObj.EquipmentContainer + if isinstance(equipmentContainer, cim.Feeder): + eqContainerMrid = equipmentContainer.mRID + return eqContainerMrid + + def _main(simulation_id, broker_port, simulation_request): os.environ["GRIDAPPSD_APPLICATION_ID"] = "helics_goss_bridge.py" bridge = HelicsGossBridge(simulation_id, broker_port, simulation_request) simulation_started = False simulation_stopped = False - timout = 0 while not simulation_stopped: sim_is_initialized = bridge.get_is_initialized() start_sim = bridge.get_start_simulation() diff --git a/services/ochre.config b/services/ochre.config index 3604dddbf..097a96fda 100644 --- a/services/ochre.config +++ b/services/ochre.config @@ -10,5 +10,6 @@ "launch_on_startup": "false", "service_dependencies": ["helics","helicsgossbridge","gridappsd-alarms","gridappsd-voltage-violation"], "multiple_instances": false, - "environmentVariables":[] + "environmentVariables":[], + "category":"SIMULATOR" }