From dad43607244693c25f293985f99920bfff452c94 Mon Sep 17 00:00:00 2001 From: Derrick Oswald Date: Wed, 1 Nov 2017 17:41:18 +0100 Subject: [PATCH] implement export all GridLAB files --- .../ninecode/cim/cimweb/FileOperations.scala | 4 +- .../ch/ninecode/cim/cimweb/GridLAB.scala | 284 ++++++++++++++++-- .../cim/cimweb/GridLABExportFunction.scala | 2 +- .../cim/cimweb/GridLABSimulateFunction.scala | 11 +- CIMWeb/src/main/webapp/js/cimexport.js | 149 +++++---- CIMWeb/src/main/webapp/js/cimsimulate.js | 14 +- .../ninecode/export/ExportGLMGenerator.scala | 67 +++-- 7 files changed, 414 insertions(+), 117 deletions(-) diff --git a/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/FileOperations.scala b/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/FileOperations.scala index 10553a574..c7a8882db 100644 --- a/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/FileOperations.scala +++ b/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/FileOperations.scala @@ -41,11 +41,11 @@ class FileOperations extends RESTful @Produces (Array (MediaType.APPLICATION_JSON)) def getFile ( @DefaultValue ("false") @MatrixParam ("debug") debug: String): Response = - getFile ("", "false", debug) + getFile ("/", "false", debug) @GET @Path ("{path:[^;]*}") - @Produces (Array (MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, "application/zip")) + @Produces (Array (MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_OCTET_STREAM, "text/plain", "text/csv", "application/zip")) def getFile ( @PathParam ("path") path: String, @DefaultValue ("false") @MatrixParam ("zip") zip: String, diff --git a/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/GridLAB.scala b/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/GridLAB.scala index b51159cbc..b78de115d 100644 --- a/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/GridLAB.scala +++ b/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/GridLAB.scala @@ -1,20 +1,28 @@ package ch.ninecode.cim.cimweb +import java.io.ByteArrayOutputStream +import java.io.StringReader +import java.nio.charset.StandardCharsets import java.util.logging.Logger +import java.util.zip.ZipEntry +import java.util.zip.ZipOutputStream import javax.ejb.Stateless import javax.json.Json +import javax.json.JsonException import javax.json.JsonObject -import javax.json.JsonStructure +import javax.resource.ResourceException +import javax.resource.cci.Connection import javax.ws.rs.GET import javax.ws.rs.POST import javax.ws.rs.core.MediaType import javax.ws.rs.Path import javax.ws.rs.PathParam import javax.ws.rs.Produces -import javax.resource.ResourceException +import javax.ws.rs.DefaultValue +import javax.ws.rs.MatrixParam import javax.ws.rs.core.Response -import scala.collection.JavaConversions._ +import scala.collection.JavaConverters._ import ch.ninecode.cim.connector.CIMFunction import ch.ninecode.cim.connector.CIMInteractionSpec @@ -28,46 +36,264 @@ class GridLAB extends RESTful import GridLAB._ // get a righteous string for a glm filename - def glm_name (simulation: String): String = + def base_name (simulation: String): String = { val index = simulation.lastIndexOf ("/") - val suffix = if (simulation.endsWith (".json")) simulation.length - 4 else simulation.length - (if (-1 == index) simulation.substring (0, suffix) else simulation.substring (index + 1, suffix)) + ".glm" + val suffix = if (simulation.endsWith (".json")) simulation.length - 5 else simulation.length + if (-1 == index) simulation.substring (0, suffix) else simulation.substring (index + 1, suffix) + } + + // get a righteous string for a glm filename + def glm_name (simulation: String): String = + { + base_name (simulation) + ".glm" + } + + // get a righteous string for a zip filename + def zip_name (simulation: String): String = + { + base_name (simulation) + ".zip" + } + + def create (connection: Connection, simulation: String): String = + { + val spec: CIMInteractionSpec = new CIMInteractionSpecImpl + spec.setFunctionName (CIMInteractionSpec.EXECUTE_CIM_FUNCTION) + val input = getInputRecord ("input record containing the function to run") + // set up the function with parameters + val gridlab = GridLABExportFunction (simulation) + input.asInstanceOf[map].put (CIMFunction.FUNCTION, gridlab) + val interaction = connection.createInteraction + val output = interaction.execute (spec, input) + if (null == output) + throw new ResourceException ("null is not a MappedRecord") + else + if (!output.getClass.isAssignableFrom (classOf [CIMMappedRecord])) + throw new ResourceException ("object of class %s is not a MappedRecord".format (output.getClass.toGenericString)) + else + { + val record = output.asInstanceOf [CIMMappedRecord] + record.get (CIMFunction.RESULT).asInstanceOf [String] + } + } + + def get (connection: Connection, file: String): String = + { + val spec: CIMInteractionSpec = new CIMInteractionSpecImpl + spec.setFunctionName (CIMInteractionSpec.EXECUTE_CIM_FUNCTION) + val input = getInputRecord ("input record containing the function to run") + val function = GetFileFunction (file) + input.asInstanceOf[map].put (CIMFunction.FUNCTION, function) + val interaction = connection.createInteraction + val output = interaction.execute (spec, input) + val record = output.asInstanceOf [CIMMappedRecord] + val xml = record.get (CIMFunction.RESULT).asInstanceOf [String] + interaction.close () + if (xml.startsWith ("File does not exist:")) + null + else + xml + } + + case class GatherOptions ( + sim: Boolean, // include simulation + cim: Boolean, // include CIM file + in: Boolean, // include input files + out: Boolean, // include output files + all: Boolean // include everything + ) + { + def gather: Boolean = sim || cim || in || out || all + } + + def gather (connection: Connection, simulation: String, options: GatherOptions): Array[Byte] = + { + // get the simulation json file + val json = get (connection, simulation) + if (null != json) + // parse it + try + Json.createReader (new StringReader (json)).readObject match + { + case details: JsonObject ⇒ + + // get the simulation root directory + val sim = if (-1 == simulation.lastIndexOf ("/")) simulation else simulation.substring (simulation.lastIndexOf ("/") + 1) + val sim_root = simulation.substring (0, simulation.length - sim.length) + + // get the gridlab root directory + val glm_file = details.getString ("glm") + if (null == glm_file) + return Array () + val last = glm_file.lastIndexOf ("/") + val (root, name) = if (-1 == last) + (simulation.substring (0, simulation.length - sim.length), glm_file) // assumed relative to simulation file + else + { + val name = glm_file.substring (last + 1) + val second_last = glm_file.lastIndexOf ("/", last - 1) + if (-1 == second_last) + ("", name) + else + (glm_file.substring (second_last + 1, glm_file.length - name.length), name) + } + + // build the zip file + val bos = new ByteArrayOutputStream () + val zos = new ZipOutputStream (bos) + zos.setLevel (9) + + // store the glm + val glm = get (connection, sim_root + root + name) + if (null == glm) + return Array () + else + { + zos.putNextEntry (new ZipEntry (root + name)) + val data = glm.getBytes (StandardCharsets.UTF_8) + zos.write (data, 0, data.length) + } + + // store the simulation + if (options.sim || options.all) + { + zos.putNextEntry (new ZipEntry (root + sim)) + val data = json.getBytes (StandardCharsets.UTF_8) + zos.write (data, 0, data.length) + } + + // store the CIM file + val cim = details.getString ("cim") + if ((null != cim ) && (options.cim || options.all)) + { + val guts = get (connection, cim) + if (null != guts) + { + val name = if (-1 == cim.lastIndexOf ("/")) cim else cim.substring (cim.lastIndexOf ("/") + 1) + zos.putNextEntry (new ZipEntry (root + name)) + val data = guts.getBytes (StandardCharsets.UTF_8) + zos.write (data, 0, data.length) + } + } + + var dirs: Array[String] = Array() + + // store the players + val players = details.getJsonArray ("players") + if (null != players) + { + for (element: JsonObject ← players.getValuesAs (classOf[JsonObject]).asScala) // ToDo: more robust checking + { + val player_file = element.getString ("file", "") + val player_name = if (-1 == player_file.lastIndexOf ("/")) player_file else player_file.substring (player_file.lastIndexOf ("/") + 1) + if (options.in || options.all) + { + val player = get (connection, sim_root + root + player_file) + if (null != player) + { + zos.putNextEntry (new ZipEntry (root + player_file)) + val data = player.getBytes (StandardCharsets.UTF_8) + zos.write (data, 0, data.length) + } + } + else + { + val dir = player_file.substring (0, player_file.length - player_name.length) + if (dir != "" && !dirs.contains (dir)) + { + zos.putNextEntry (new ZipEntry (root + dir)) + dirs = dirs :+ dir + } + } + } + } + + // store the recorders + val recorders = details.getJsonArray ("recorders") + if (null != recorders) + { + for (element: JsonObject ← recorders.getValuesAs (classOf[JsonObject]).asScala) // ToDo: more robust checking + { + val recorder_file = element.getString ("file", "") + val recorder_name = if (-1 == recorder_file.lastIndexOf ("/")) recorder_file else recorder_file.substring (recorder_file.lastIndexOf ("/") + 1) + if (options.out || options.all) + { + val recorder = get (connection, sim_root + root + recorder_file) + if (null != recorder) + { + zos.putNextEntry (new ZipEntry (root + recorder_file)) + val data = recorder.getBytes (StandardCharsets.UTF_8) + zos.write (data, 0, data.length) + } + } + else + { + val dir = recorder_file.substring (0, recorder_file.length - recorder_name.length) + if (dir != "" && !dirs.contains (dir)) + { + zos.putNextEntry (new ZipEntry (root + dir)) + dirs = dirs :+ dir + } + } + } + } + + // seal the zip file + zos.finish () + zos.close () + bos.toByteArray + case _ ⇒ Array() + } + catch + { + case je: JsonException ⇒ Array() + } + else + Array() } @GET @Path ("{simulation:[^;]*}") - @Produces (Array (MediaType.APPLICATION_JSON)) + @Produces (Array (MediaType.APPLICATION_JSON, "application/zip")) def export ( - @PathParam ("simulation") simulation: String // the name of the JSON simulation file on HDFS - ): Response = + @PathParam ("simulation") simulation: String, // the name of the JSON simulation file on HDFS + @DefaultValue ("false") @MatrixParam ("sim") sim: String, + @DefaultValue ("false") @MatrixParam ("cim") cim: String, + @DefaultValue ("false") @MatrixParam ("in") in: String, + @DefaultValue ("false") @MatrixParam ("out") out: String, + @DefaultValue ("false") @MatrixParam ("all") all: String + ): Response = { - _Logger.info ("gridlab %s".format (simulation)) + _Logger.info ("gridlab %s;all=%s".format (simulation, all)) val ret = new RESTfulJSONResult val connection = getConnection (ret) val response: Response = if (null != connection) try { - val spec: CIMInteractionSpec = new CIMInteractionSpecImpl - spec.setFunctionName (CIMInteractionSpec.EXECUTE_CIM_FUNCTION) - val input = getInputRecord ("input record containing the function to run") - // set up the function with parameters - val gridlab = GridLABExportFunction (if (simulation.startsWith ("/")) simulation else "/" + simulation) - input.asInstanceOf[map].put (CIMFunction.FUNCTION, gridlab) - val interaction = connection.createInteraction - val output = interaction.execute (spec, input) - if (null == output) - throw new ResourceException ("null is not a MappedRecord") - else - if (!output.getClass.isAssignableFrom (classOf [CIMMappedRecord])) - throw new ResourceException ("object of class %s is not a MappedRecord".format (output.getClass.toGenericString)) - else - { - val record = output.asInstanceOf [CIMMappedRecord] - Response.ok (record.get (CIMFunction.RESULT).asInstanceOf [String], MediaType.APPLICATION_OCTET_STREAM) - .header ("content-disposition", "attachment; filename=%s".format (glm_name (simulation))) + val sim = if (simulation.startsWith ("/")) simulation else "/" + simulation + val options = GatherOptions ( + sim = try { sim.toBoolean } catch { case _: Throwable => false }, + cim = try { cim.toBoolean } catch { case _: Throwable => false }, + in = try { in.toBoolean } catch { case _: Throwable => false }, + out = try { out.toBoolean } catch { case _: Throwable => false }, + all = try { all.toBoolean } catch { case _: Throwable => false }) + if (options.gather) + { + val zip = gather (connection, sim, options) + if (zip.length > 0) + Response.ok (zip, "application/zip") + .header ("content-disposition", "attachment; filename=%s".format (zip_name (simulation))) .build - } + else + Response.serverError ().entity ("zip construction failed").build + } + else + { + val glm = create (connection, sim) + Response.ok (glm, MediaType.APPLICATION_OCTET_STREAM) + .header ("content-disposition", "attachment; filename=%s".format (glm_name (simulation))) + .build + } } catch { diff --git a/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/GridLABExportFunction.scala b/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/GridLABExportFunction.scala index a3a27071e..dd8c495ce 100644 --- a/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/GridLABExportFunction.scala +++ b/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/GridLABExportFunction.scala @@ -258,7 +258,7 @@ case class GridLABExportFunction (simulation: String) extends CIMWebFunction else { val buffer = for (element: JsonObject ← array.getValuesAs (classOf[JsonObject]).asScala) // ToDo: more robust checking - yield Player (element.getString ("name", ""), element.getString ("parent", ""), element.getString ("player", "")) + yield Player (element.getString ("name", ""), element.getString ("parent", ""), element.getString ("file", "")) buffer.toArray } } diff --git a/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/GridLABSimulateFunction.scala b/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/GridLABSimulateFunction.scala index b34a8a6af..2c8f85667 100644 --- a/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/GridLABSimulateFunction.scala +++ b/CIMWeb/src/main/scala/ch/ninecode/cim/cimweb/GridLABSimulateFunction.scala @@ -6,6 +6,8 @@ import javax.json.JsonException import javax.json.JsonObject import javax.json.JsonStructure +import scala.collection.JavaConverters._ + import org.apache.hadoop.fs.Path import org.apache.hadoop.io.Text import org.apache.spark.rdd.RDD @@ -13,7 +15,6 @@ import org.apache.spark.sql.SparkSession import ch.ninecode.cim.cimweb.RESTfulJSONResult.OK import ch.ninecode.cim.cimweb.RESTfulJSONResult.FAIL - import ch.ninecode.cim.connector.CIMFunction.Return /** @@ -120,6 +121,14 @@ case class GridLABSimulateFunction (simulation: String) extends CIMWebFunction { val workdir_path = glm.substring (0, index1 + 1) val file = glm.substring (index1 + 1, index2) + // erase all the recorder files + val recorders = details.getJsonArray ("recorders") + val root = glm.substring (0, index2 + 1) + for (element: JsonObject ← recorders.getValuesAs (classOf[JsonObject]).asScala) // ToDo: more robust checking + { + val recorder_file = element.getString ("file", "") + hdfs.delete (new Path (root, recorder_file), false) + } val message = solve (workdir_path, spark.sparkContext.parallelize (Array (file))) if (message == "") new RESTfulJSONResult (OK, "gridlab simulation ran").getJSON diff --git a/CIMWeb/src/main/webapp/js/cimexport.js b/CIMWeb/src/main/webapp/js/cimexport.js index 72447d7cc..31c4ac389 100644 --- a/CIMWeb/src/main/webapp/js/cimexport.js +++ b/CIMWeb/src/main/webapp/js/cimexport.js @@ -18,52 +18,6 @@ define // Data about existing simulations schema { stations: [string], simulations: [string] } var TheChoices; - /** - * @summary Call the gridlab RESTful service. - * @description Invokes the server side gridlab function. - * @param {string} simulation - the simulation file name. - * @function exportSimulation - * @memberOf module:cimexport - */ - function exportSimulation (simulation, callback) - { - var url; - var xmlhttp; - - simulation = simulation.startsWith ("/") ? simulation : "/" + simulation; - url = util.home () + "cim/gridlab" + simulation; - xmlhttp = util.createCORSRequest ("GET", url); - xmlhttp.onreadystatechange = function () - { - if (4 == xmlhttp.readyState) - if (200 == xmlhttp.status || 201 == xmlhttp.status || 202 == xmlhttp.status) - callback (xmlhttp.responseText); - else - alert ("status: " + xmlhttp.status); - }; - xmlhttp.send (); - } - - /** - * @summary Execute an export. - * @description Gets the user's input and generates the .glm for the simulation. - * @function do_export - * @memberOf module:cimexport - */ - function do_export () - { - var station_directory = document.getElementById ("station_directory").value; - if (("undefined" != typeof (station_directory)) && ("" != station_directory)) - { - var simulation_file = document.getElementById ("simulation_file").value; - if (("undefined" != typeof (simulation_file)) && ("" != simulation_file)) - { - var simulation = "/" + station_directory + "/" + simulation_file + ".json"; - exportSimulation (simulation, function (data) { document.getElementById ("glm").innerHTML = "
\n" +  data + "
"; } ); - } - } - } - function render () { var export_template = @@ -93,8 +47,63 @@ define " \n" + " \n" + "
\n" + + "
All
\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
Simulation
\n" + "
\n" + - " \n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
CIM
\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
Input
\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
Output
\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + " Export\n" + "
\n" + "
\n" + " \n" + @@ -110,7 +119,13 @@ define ); document.getElementById ("main").innerHTML = text; document.getElementById ("station_directory").onchange = select_station; - document.getElementById ("do_export").onclick = do_export; + document.getElementById ("simulation_file").onchange = set_do_export_url; + document.getElementById ("export_option_all").onchange = set_do_export_url; + document.getElementById ("export_option_sim").onchange = set_do_export_url; + document.getElementById ("export_option_cim").onchange = set_do_export_url; + document.getElementById ("export_option_in").onchange = set_do_export_url; + document.getElementById ("export_option_out").onchange = set_do_export_url; + set_do_export_url (); } function stripJson (file) @@ -118,7 +133,7 @@ define return (file.endsWith (".json") ? file.substring (0, file.length - 5) : file); } - function select_station () + function select_station (event) { var station = document.getElementById ("station_directory").value; if (("undefined" != typeof (station)) && ("" != station)) @@ -131,6 +146,39 @@ define ); } + function set_do_export_url (event) + { + var station_directory = document.getElementById ("station_directory").value; + var simulation_file = document.getElementById ("simulation_file").value; + var options = ""; + if (document.getElementById ("export_option_all").checked) + { + document.getElementById ("export_option_sim").setAttribute ("disabled", "disabled"); + document.getElementById ("export_option_cim").setAttribute ("disabled", "disabled"); + document.getElementById ("export_option_in").setAttribute ("disabled", "disabled"); + document.getElementById ("export_option_out").setAttribute ("disabled", "disabled"); + options = ";all=true"; + } + else + { + document.getElementById ("export_option_sim").removeAttribute ("disabled"); + document.getElementById ("export_option_cim").removeAttribute ("disabled"); + document.getElementById ("export_option_in").removeAttribute ("disabled"); + document.getElementById ("export_option_out").removeAttribute ("disabled"); + if (document.getElementById ("export_option_sim").checked) + options = options + ";sim=true"; + if (document.getElementById ("export_option_cim").checked) + options = options + ";cim=true"; + if (document.getElementById ("export_option_in").checked) + options = options + ";in=true"; + if (document.getElementById ("export_option_out").checked) + options = options + ";out=true"; + } + var simulation = "/" + station_directory + "/" + simulation_file + ".json" + options; + url = util.home () + "cim/gridlab" + simulation; + document.getElementById ("do_export").setAttribute ("href", url); + } + /** * @summary Render the export page. * @description Uses mustache to create HTML DOM elements that display the export options. @@ -152,8 +200,7 @@ define return ( { - initialize: initialize, - exportSimulation: exportSimulation + initialize: initialize } ); } diff --git a/CIMWeb/src/main/webapp/js/cimsimulate.js b/CIMWeb/src/main/webapp/js/cimsimulate.js index b8661bff9..654cab3c5 100644 --- a/CIMWeb/src/main/webapp/js/cimsimulate.js +++ b/CIMWeb/src/main/webapp/js/cimsimulate.js @@ -106,7 +106,7 @@ define // "parent": "HAS2987_fuse_topo", // "property": "constant_power", // "unit": "Watt", - // "player": "input_data/HAS2987.csv" + // "file": "input_data/HAS2987.csv" // }, // ... // ], @@ -405,11 +405,11 @@ define var house = row.parent.substring (0, row.parent.indexOf ("_")); var match = choice.files.filter (function (x) { return (x.house == house); }); if (0 != match.length) - row.player = match[0].file; + row.file = match[0].file; else { row.fake = true; - row.player = choice.files[getRandomInt (0, choice.files.length)].file; + row.file = choice.files[getRandomInt (0, choice.files.length)].file; } return (row); } @@ -420,13 +420,13 @@ define players.forEach ( function (pl) { - var name = "input_data/" + (pl.fake ? "fake_" : "") + pl.player.substring (pl.player.lastIndexOf ("/") + 1); + var name = "input_data/" + (pl.fake ? "fake_" : "") + pl.file.substring (pl.file.lastIndexOf ("/") + 1); var target = "/" + getStation () + "/" + getName () + "/" + name; - generate_file (pl.player, target, choice.phi, + generate_file (pl.file, target, choice.phi, function (response) { if (response.status == "OK") - pl.player = name; + pl.file = name; else alert ("message: " + (response.message ? response.message : "") + " error: " + (response.error ? response.error : "")); todo = todo - 1; @@ -679,7 +679,7 @@ define " \n" + "
\n" + " \n" + - " \n" + + " \n" + " Enter a user facing description for the simulation - used for drop down choice title.\n" + "
\n" + "
\n" + diff --git a/GridLAB-D/src/main/scala/ch/ninecode/export/ExportGLMGenerator.scala b/GridLAB-D/src/main/scala/ch/ninecode/export/ExportGLMGenerator.scala index b60a70832..b1b1c6175 100644 --- a/GridLAB-D/src/main/scala/ch/ninecode/export/ExportGLMGenerator.scala +++ b/GridLAB-D/src/main/scala/ch/ninecode/export/ExportGLMGenerator.scala @@ -3,6 +3,7 @@ package ch.ninecode.export import java.text.SimpleDateFormat import java.util.Calendar +import ch.ninecode.esl.PowerFeedingNode import ch.ninecode.gl._ import ch.ninecode.esl.Trafokreis @@ -34,12 +35,24 @@ extends // the swing node is the low voltage pin override def swing_nodes: Iterable[GLMNode] = List (SwingNode (trafokreis.transformers.node1, trafokreis.transformers.v1, trafokreis.transformers.transformer_name)) - override def nodes: Iterable[GLMNode] = trafokreis.nodes + override def nodes: Iterable[GLMNode] = + { + val swings = swing_nodes.map (_.id).toArray + trafokreis.nodes.filter (x => !swings.contains (x.id)).++: ( + Array ( + PowerFeedingNode ( + trafokreis.transformers.node0, + trafokreis.transformers.v0, + null, + 0.0, + Double.PositiveInfinity, + false))) + } override def emit_node (node: GLMNode): String = { super.emit_node (node) + - (if (name.startsWith ("HAS")) + (if (node.id.startsWith ("HAS")) { generate_recorder (node) + generate_load (node) @@ -59,7 +72,7 @@ extends " object recorder\n" + " {\n" + " name \"" + edge.id + "_current_recorder\";\n" + - " parent \"" + edge.id + "_line\";\n" + + " parent \"" + edge.id + "\";\n" + " property " + ( if (one_phase) "current_in_A.real,current_in_A.imag" else "current_in_A.real,current_in_A.imag,current_in_B.real,current_in_B.imag,current_in_C.real,current_in_C.imag") + ";\n" + " interval 300;\n" + " file \"output_data/" + edge.id + "_current.csv\";\n" + @@ -68,7 +81,7 @@ extends " object recorder\n" + " {\n" + " name \"" + edge.id + "_power_recorder\";\n" + - " parent \"" + edge.id + "_line\";\n" + + " parent \"" + edge.id + "\";\n" + " property " + ( if (one_phase) "power_in_A.real,power_in_A.imag" else "power_in_A.real,power_in_A.imag,power_in_B.real,power_in_B.imag,power_in_C.real,power_in_C.imag") + ";\n" + " interval 300;\n" + " file \"output_data/" + edge.id + "_power.csv\";\n" + @@ -77,7 +90,7 @@ extends " object recorder\n" + " {\n" + " name \"" + edge.id + "_losses_recorder\";\n" + - " parent \"" + edge.id + "_line\";\n" + + " parent \"" + edge.id + "\";\n" + " property " + ( if (one_phase) "power_losses_A.real,power_losses_A.imag" else "power_losses_A.real,power_losses_A.imag,power_losses_B.real,power_losses_B.imag,power_losses_C.real,power_losses_C.imag") + ";\n" + " interval 300;\n" + " file \"output_data/" + edge.id + "_losses.csv\";\n" + @@ -148,7 +161,8 @@ extends " property " + ( if (one_phase) "measured_power_A.real,measured_power_A.imag" else "measured_power_A.real,measured_power_A.imag,measured_power_B.real,measured_power_B.imag,measured_power_C.real,measured_power_C.imag") + ";\n" + " interval 300;\n" + " file \"output_data/" + trafo + "_power.csv\";\n" + - " };\n" + " };\n" + + "\n" } override def emit_transformer (transformer: TransformerSet): String = @@ -166,28 +180,28 @@ extends " property " + ( if (one_phase) "current_in_A.real,current_in_A.imag" else "current_in_A.real,current_in_A.imag,current_in_B.real,current_in_B.imag,current_in_C.real,current_in_C.imag") + ";\n" + " interval 300;\n" + " file \"output_data/" + name + "_current.csv\";\n" + + " };\n" + + "\n" + + " object recorder\n" + + " {\n" + + " name \"" + name + "_power_recorder\";\n" + + " parent \"" + name + "\";\n" + + " property " + ( if (one_phase) "power_in_A.real,power_in_A.imag" else "power_in_A.real,power_in_A.imag,power_in_B.real,power_in_B.imag,power_in_C.real,power_in_C.imag") + ";\n" + + " interval 300;\n" + + " file \"output_data/" + name + "_power.csv\";\n" + + " };\n" + + "\n" + + " object recorder\n" + + " {\n" + + " name \"" + name + "_losses_recorder\";\n" + + " parent \"" + name + "\";\n" + + " property " + ( if (one_phase) "power_losses_A.real,power_losses_A.imag" else "power_losses_A.real,power_losses_A.imag,power_losses_B.real,power_losses_B.imag,power_losses_C.real,power_losses_C.imag") + ";\n" + + " interval 300;\n" + + " file \"output_data/" + name + "_losses.csv\";\n" + " };\n" else "" - ) + - "\n" + - " object recorder\n" + - " {\n" + - " name \"" + name + "_power_recorder\";\n" + - " parent \"" + name + "\";\n" + - " property " + ( if (one_phase) "power_in_A.real,power_in_A.imag" else "power_in_A.real,power_in_A.imag,power_in_B.real,power_in_B.imag,power_in_C.real,power_in_C.imag") + ";\n" + - " interval 300;\n" + - " file \"output_data/" + name + "_power.csv\";\n" + - " };\n" + - "\n" + - " object recorder\n" + - " {\n" + - " name \"" + name + "_losses_recorder\";\n" + - " parent \"" + name + "\";\n" + - " property " + ( if (one_phase) "power_losses_A.real,power_losses_A.imag" else "power_losses_A.real,power_losses_A.imag,power_losses_B.real,power_losses_B.imag,power_losses_C.real,power_losses_C.imag") + ";\n" + - " interval 300;\n" + - " file \"output_data/" + name + "_losses.csv\";\n" + - " };\n" + ) } def generate_recorder (node: GLMNode): String = @@ -215,7 +229,8 @@ extends " property " + ( if (one_phase) "power_A.real,power_A.imag" else "power_A.real,power_A.imag,power_B.real,power_B.imag,power_C.real,power_C.imag") + ";\n" + " interval 300;\n" + " file \"output_data/" + node.id + "_power.csv\";\n" + - " };\n" + " };\n" + + "\n" else "" }