Skip to content
Daniele Pala edited this page Nov 20, 2020 · 1 revision

Code architecture

CIMDraw is built using RiotJS components. There are four basic tags defined (plus other additional ones for additional functions, e.g. topology processing): the main app container, the tree, the diagram and the diagram controls. The structure of the application is shown in the following figure.

components.png

All of these components share the same reference to the underlying CIM model, and communicate via events.

The model

The model is the part of the application which handles the low level details of CIM manipulation and loading, and is composed by different JavaScript source files (not RiotJS components). These files can in principle be used independently from the CIMDraw application, and it is possible that in the future they will be put into a separate repository in order to easily allow their use into different programs. The main model object is the one returned by the cimModel() function, defined in the model.js file. To use this function just import the model.js file and associated dependencies:

<script src="https://cdn.jsdelivr.net/npm/@riotjs/observable@4.0.4/dist/observable.js"></script>
<script src="https://d3js.org/d3-collection.v1.min.js"></script>
<script src="https://d3js.org/d3-dispatch.v1.min.js"></script>
<script src="https://d3js.org/d3-dsv.v1.min.js"></script>
<script src="https://d3js.org/d3-request.v1.min.js"></script>
<script src="js/JSZip/jszip.min.js"></script>
<script src="js/schema.js"></script>
<script src="js/model.js"></script>
<script>
    const model = cimModel();
</script>

Each graphic component acts by querying the main model object for CIM objects and attributes, asking it to update things, and listening for events from it. The normal operation of the application is thus the following:

  • The user performs some action
  • The affected component takes the user's input and updates the model accordingly
  • The model updates the CIM data structures and fires some event to inform all the listeners about the modification
  • The components update the view based on the event they receive from the model

The events are generated by the model via the Riot Observable library and are the following:

  • setAttribute(object, attrName, value): generated by the setAttribute function and by other functions which may call it: getDiagramList, createObject, addToActiveDiagram, selectDiagram and updateActiveDiagram.
  • setEnum(object, enumName, value): generated by the setEnum function.
  • createObject(newElement): generated by the createObject function.
  • deleteObject(objUUID, objType): generated by the deleteObject and deleteFromDiagram functions.
  • deleteFromDiagram(objUUID): generated by the deleteFromDiagram function.
  • addToActiveDiagram(object): generated by the addToActiveDiagram and updateActiveDiagram functions.
  • updateActiveDiagram(object): generated by the updateActiveDiagram function.
  • addLink(source, linkName, target): generated when a new link is added to the CIM file. In particular, generated by the createObject, addToActiveDiagram and setLink functions.
  • removeLink(source, linkName, target): generated when a link is removed from the CIM file. In particular, generated by the removeLink, setLink and deleteObject functions.
  • createdDiagram: generated by the selectDiagram function if a new diagram has been created.
  • changedDiagram: generated by the selectDiagram function, even if no new diagram has been created.
  • setMode(mode): generated by the setMode function.

For example, to listen to the 'setAttribute' event:

const model = cimModel();
model.on("setAttribute", function(object, attrName, value) {
    // handle event
});

Model API reference

load(file)
Loads a CIM file from the local filesystem. Returns a promise which resolves after loading the file. The input file can be a plain RDF/XML file or a zipped file, conforming to ENTSO-E format (i.e. the zipped file contains many XML files, one for each profile (EQ, DL, TP etc). The 'file' parameter can be a File object for the CIM network to be loaded or any other object with a 'name' property.

newFile(name) Creates a new empty file. Returns a promise which resolves after building the model object. For example, to create a new CIM file:

const model = cimModel();
const cimFilename = "new1";
model.newFile(cimFilename).then(function() {
    // do something
});

loadRemote(fileName)
Load a CIM file from a remote location. Returns a promise which resolves after loading the file. The input file must be a plain RDF/XML file. The 'fileName' parameter is the path of the file to be loaded, relative to the root address of the application. Therefore, a 'fileName' parameter such as '/test.xml' will load the file 'test.xml', which must be in the root path of the server serving the CIMDraw app.

save()
Serialize the current CIM file as a plain RDF/XML file. This function returns a string.

saveAsCGMES()
Serialize the current CIM file as an ENTSO-E CGMES zip file. This function returns a Promise of the generated zip file, which resolves when the zip file is ready.

const model = cimModel();
const cimFilename = "new1";
model.newFile(cimFilename).then(function() {
    const out = model.saveAsCGMES();
    out.then(function(content) {
        console.log(content);
    }).catch(function(reason) {
        console.log(reason);
    });
});

export()
Serialize the current diagram. This function always returns a string, even for ENTSO-E CGMES zip files.

getDiagramList()
Get a list of diagram names in the current CIM file. This is an array of strings, like ["diagram1", "diagram2].

getObjects(types)
Get the objects of a given type. This function doesn't filter by diagram, i.e. all the objects of the given type which are in the file are returned, even if they are not in the currently loaded diagram. The 'types' parameter must be an array of namespace qualified types, like ["cim:ACLineSegment", "cim:Breaker"]. The output is an object whose keys are the types and the values are the corresponding arrays, like {cim:ACLineSegment: [acline1, acline2], cim:Breaker: [breaker1]}. Each object returned is an Element.

getGraphicObjects(types)
Get the objects of a given type that have at least one DiagramObject in the current diagram. The 'types' parameter must be an array of namespace qualified types, like ["cim:ACLineSegment", "cim:Breaker"]. The output is an object whose keys are the types and the values are the corresponding arrays, like {cim:ACLineSegment: [acline1, acline2], cim:Breaker: [breaker1]}. Each object returned is an Element.

getNodes()
Get the nodes that belong to the current diagram. Depending on the mode of operation, they will be connectivity nodes or topological nodes.

getConnectors(types)
Get the connectors (busbars or junctions) that belong to the current diagram. The 'types' parameter must be an array of namespace qualified types, like ["cim:BusbarSection", "cim:Junction"]. The output is an object whose keys are the types and the values are the corresponding arrays, like {cim:BusbarSection: [bus1, bus2], cim:Junction: [junction1]}. Each object returned is an Element.

getLinkedObjects(types, linkName)
Get all the objects of the given types that either have at least a diagram object in the current diagram or are linked to some object which is in the current diagram via the given link. The 'types' parameter must be an array of namespace qualified types, like ["cim:Substation", "cim:Line"].The output is an object whose keys are the types and the values are the corresponding arrays, like {cim:Substation: [sub1, sub2], cim:Line: [line1]}. Each object returned is an Element. This function is useful for many CIM objects, like: Substations, Lines, Measurements, GeneratingUnits, RegulatingControls.

getTerminals(objects)
Get all the terminals of given objects. The 'objects' parameter must be an array of Elements.

getObject(uuid)
Get an object given its UUID. The 'uuid' parameter must be a string.

getAttributes(object)
Get all the attributes of a given object which are actually set.

getAttribute(object, attrName)
Get a specific attribute of a given object. If the attribute is not found the function returns undefined. The attribute name must be namespace qualified (e.g. "cim:ACDCTerminal.connected").

setAttribute(object, attrName, value)
Set a specific attribute of a given object. If it doesen't exists, it is created. The attribute name must be namespace qualified (e.g. "cim:ACDCTerminal.connected").

setEnum(object, enumName, value)
Set a specific enum of a given object. If it doesen't exists, it is created.

createObject(type, options)
Create an object of a given type. An optional second argument may contain an object with specific creation options: an "uuid" field can be passed in order to force the use of a specific UUID, a "windNum" option can be passed in order to specify the number of windings of a transformer (ignored for other objects), which defaults to 2, a "node" option can be passed when creating a BusbarSection in order to attach it to a specific node (otherwise, a new node will be automatically created and connected to the busbar).

deleteObject(object)
Delete an object: also, delete its terminals and graphic objects. Moreover, delete transformer windings and handle BusbarSections.

getNode(busbar)
Function to navigate busbar -> node. Depending on the mode of operation, it will be a connectivity node or a topological node.

getBusbar(node)
Function to navigate node -> busbar. Depending on the mode of operation, it must be a connectivity node or a topological node. It filters by diagram (i.e. the busbar or the connectivity node must be in the diagram).

deleteFromDiagram(object)
Delete an object from the current diagram.

addToActiveDiagram(object, lineData)
Add an object to the active diagram.

updateActiveDiagram(object, lineData)
Update the model based on new position data. This is based on the given object's x and y attributes as well as a 'lineData' array for extended objects: each element of the array must be an object with x and y keys, which are mapped to DiagramObjectPoints.

getLinks(object)
Get all the links of a given object which are actually set.

getLink(object, linkName)
Get a specific link of a given object. If the link is many-valued, it mey return more than one element.

getEnum(object, enumName)
Get a specific enum of a given object.

setLink(source, linkName, target)
Set a specific link of a given object. If a link with the same name already exists, it is removed.

removeLink(source, linkName, target)
Remove a specific link of a given object.

getTargets(sources, linkName)
Returns all the nodes connected with the given sources via the link 'linkName' (or the inverse, 'invLinkName').

getDiagramObjects([objects])
Get all the diagram objects in the current diagram. If an array of objects is given as argument, only the diagram objects associated to that objects are returned.

getEquipments(node)
Get the equipments in the current diagram associated to the given node. Depending on the mode of operation, it must be a connectivity node or a topological node.

selectDiagram(diagramName)
Selects a given diagram in the current CIM file. If the model doesn't contain the requested diagram, then a new one, with name 'diagramName', will be created.

clear()
Resets the model to its initial state.

ID(object)
Get the rdf:ID attribute of a given object, or null if not present.

Schema API reference

The main model objects contains a field called 'schema', which provides schema-related (CGMES) functions. The API is the following.

buildSchema()
Build initial schema data structures. Returns a promise which resolves successfully if all the schema files are loaded correctly.

getSchemaObject(type)
Get the (EQ) schema description of a given object, e.g. Breaker.

getSchemaEnumValues(attr)
Get the (EQ) schema enumeration values of a given attribute.

getSchemaEnumName(attr)
Get the enum name a given attribute. It is not limited to EQ schema.

getSchemaAttributes(type)
Get all the attributes associated to a given type. The type is without namespace, e.g. "Breaker". It is limited to EQ schema.

getSchemaAttribute(type, attrName)
Get a specific attribute associated to a given type. The type is without namespace, e.g. "Breaker". It is limited to EQ schema.

isEnum(attr)
Test if a given attribute is an enum. It is not limited to EQ schema.

getSchemaAttributeType(attr)
Get the type of a given attribute. It is not limited to EQ schema.

getSchemaLinks(type)
Get the (EQ) schema links for a given type.

isA(type, object)
Test weather an object is of a given type.

Clone this wiki locally