@enervance/insight-cim-model 0.0.369 → 0.0.370

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/analysis/analysis-neplan/contingency-analysis.neplan.westnetz.d.ts +67 -0
  2. package/dist/analysis/analysis-neplan/contingency-analysis.neplan.westnetz.js +615 -0
  3. package/dist/analysis/analysis-neplan/contingency-analysis.neplan.westnetz.js.map +1 -0
  4. package/dist/etl/etl-neplan/etl-neplan-csv.js +1 -1
  5. package/dist/etl/etl-neplan/etl-neplan-csv.js.map +1 -1
  6. package/dist/etl/etl-neplan/neplan-contingency-analysis.js +0 -3
  7. package/dist/etl/etl-neplan/neplan-contingency-analysis.js.map +1 -1
  8. package/dist/index.d.ts +2 -1
  9. package/dist/index.js +4 -4
  10. package/dist/index.js.map +1 -1
  11. package/dist/interfaces/model/core/IConnectivityNode.d.ts +2 -0
  12. package/dist/interfaces/model/core/IIdentifiedObject.d.ts +1 -0
  13. package/dist/model/assetinfo/SwitchInfo.d.ts +0 -2
  14. package/dist/model/assetinfo/SwitchInfo.js +1 -6
  15. package/dist/model/assetinfo/SwitchInfo.js.map +1 -1
  16. package/dist/model/core/ConnectivityNode.d.ts +3 -0
  17. package/dist/model/core/ConnectivityNode.js +9 -0
  18. package/dist/model/core/ConnectivityNode.js.map +1 -1
  19. package/dist/model/core/Equipment.d.ts +1 -1
  20. package/dist/model/core/Equipment.js +4 -1
  21. package/dist/model/core/Equipment.js.map +1 -1
  22. package/dist/model/core/EquipmentContainer.d.ts +1 -0
  23. package/dist/model/core/EquipmentContainer.js +3 -0
  24. package/dist/model/core/EquipmentContainer.js.map +1 -1
  25. package/dist/model/core/Feeder.d.ts +2 -1
  26. package/dist/model/core/Feeder.js +22 -1
  27. package/dist/model/core/Feeder.js.map +1 -1
  28. package/dist/model/core/PowerSystemResource.d.ts +1 -0
  29. package/dist/model/core/PowerSystemResource.js +13 -0
  30. package/dist/model/core/PowerSystemResource.js.map +1 -1
  31. package/dist/model/core/Substation.d.ts +1 -0
  32. package/dist/model/core/Substation.js +4 -0
  33. package/dist/model/core/Substation.js.map +1 -1
  34. package/dist/model/core/Terminal.js +3 -0
  35. package/dist/model/core/Terminal.js.map +1 -1
  36. package/dist/model/extensions/amprion/additionalassetvalue/AMPRIONAdditionalBayValue.js +1 -1
  37. package/dist/model/extensions/enervance/operations/EVTerminalAction.js +0 -1
  38. package/dist/model/extensions/enervance/operations/EVTerminalAction.js.map +1 -1
  39. package/dist/model/extensions/westnetz-neplan/core/WNFeeder.js.map +1 -1
  40. package/dist/model/extensions/westnetz-neplan/operations/WNOutage.js +1 -1
  41. package/dist/model/extensions/westnetz-neplan/operations/WNOutage.js.map +1 -1
  42. package/dist/model/operations/SwitchingPlan.js.map +1 -1
  43. package/dist/utils2/cim.model.utils.d.ts +7 -2
  44. package/dist/utils2/cim.model.utils.js +21 -2
  45. package/dist/utils2/cim.model.utils.js.map +1 -1
  46. package/package.json +1 -1
@@ -0,0 +1,615 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContingencyAnalysisNeplanWestnetz = void 0;
4
+ const Switch_1 = require("../../model/wires/Switch.js");
5
+ const ExternalNetworkInjection_1 = require("../../model/wires/ExternalNetworkInjection.js");
6
+ const common_utils_1 = require("../../utils2/common.utils.js");
7
+ const ACLineSegment_1 = require("../../model/wires/ACLineSegment.js");
8
+ const EVSwitchingPlanKind_1 = require("../../model/extensions/enervance/operations/EVSwitchingPlanKind.js");
9
+ const WNConnectivityNode_1 = require("../../model/extensions/westnetz-neplan/core/WNConnectivityNode.js");
10
+ const WNOutage_1 = require("../../model/extensions/westnetz-neplan/operations/WNOutage.js");
11
+ const ConductingEquipment_1 = require("../../model/core/ConductingEquipment.js");
12
+ const EVTerminal_1 = require("../../model/extensions/enervance/core/EVTerminal.js");
13
+ const WNFaultConnectivityNode_1 = require("../../model/extensions/westnetz-neplan/faults/WNFaultConnectivityNode.js");
14
+ const neplan_contingency_analysis_1 = require("../../etl/etl-neplan/neplan-contingency-analysis.js");
15
+ const SwitchActionKind_1 = require("../../model/operations/SwitchActionKind.js");
16
+ const sparql_utils_1 = require("../../util/sparql/sparql-utils.js");
17
+ const WNSwitchTypeKind_1 = require("../../model/extensions/westnetz-neplan/core/WNSwitchTypeKind.js");
18
+ const EnergySource_1 = require("../../model/wires/EnergySource.js");
19
+ const EnergyConsumer_1 = require("../../model/wires/EnergyConsumer.js");
20
+ class ContingencyAnalysisNeplanWestnetz {
21
+ static performContingencyAnalysis(modelContainer) {
22
+ var _a, _b, _c;
23
+ const insertSPARQL = new Array;
24
+ for (const feeder of modelContainer.feeders.values()) {
25
+ const wnFeeder = feeder;
26
+ /** relevante Ausfälle
27
+ * 1 Ausfall des ersten ConnectivityNodes im Abgang
28
+ * 2 Alle ConnectivityNodes mit drei und mehr ACLineSegments */
29
+ const outageNodes = (_a = Array.from(feeder.normalHeadTerminal.values())) === null || _a === void 0 ? void 0 : _a.map(it => it.connectivityNode);
30
+ for (const cn of wnFeeder.normalEnergizedConnectivityNodes.values()) {
31
+ // Muffen sind für N-1-Betrachtung nicht relevant
32
+ // if (cn.getType() === CimAssetAliasNames.Muffe) continue;
33
+ const connectedACLineSegments = Array.from(cn.terminals.values())
34
+ .filter(t => t.isClosed() && t.conductingEquipment instanceof ACLineSegment_1.ACLineSegment)
35
+ .length;
36
+ /** ab 3 ACLineSegments ist der Knoten für die Ausfallanalyse relevant */
37
+ if (connectedACLineSegments >= 3)
38
+ outageNodes.push(cn);
39
+ }
40
+ const resupplyResults = ContingencyAnalysisNeplanWestnetz.findRessuplySwitchingActions(outageNodes, modelContainer);
41
+ for (const resupplyResult of resupplyResults.values()) {
42
+ // Ausfall
43
+ const outageNode = (_b = resupplyResult.find(it => it.faultConnectivityNode)) === null || _b === void 0 ? void 0 : _b.faultConnectivityNode;
44
+ // Freischaltungsmaßnahme
45
+ const deenergizedAction = (_c = resupplyResult.find(it => it.deenergizedActions)) === null || _c === void 0 ? void 0 : _c.deenergizedActions;
46
+ // Schaltmaßnahmen mit vollständiger Wiederversorgung
47
+ const fullyResuppliedActions = resupplyResult.filter(it => !it.cycle && it.resupplyType === EVSwitchingPlanKind_1.EVSwitchingPlanKind.fullyResupply);
48
+ // Schaltmaßnahmen mit partieller Wiederversorgung
49
+ const partiallyResuppliedActions = resupplyResult.filter(it => !it.cycle && it.resupplyType === EVSwitchingPlanKind_1.EVSwitchingPlanKind.partiallyResupply);
50
+ console.log(`Ausfall ${outageNode.getUUID()} | ${outageNode.name}\n
51
+ \tSchaltmaßnahmen mit vollständiger Wiederversorgung: ${fullyResuppliedActions.length}\n
52
+ \tSchaltmaßnahmen mit partieller Wiederversorgung: ${partiallyResuppliedActions.length}`);
53
+ if (fullyResuppliedActions.length === 0)
54
+ continue;
55
+ /** Ausfallschaltmaßnahme anlegen */
56
+ const faultCN = outageNode;
57
+ for (const fullyResuppliedAction of fullyResuppliedActions) {
58
+ const outageNew = new WNOutage_1.WNOutage(common_utils_1.CommonUtils.generateUUID(), `Ausfall-${faultCN.name}`, `${wnFeeder.shortName}`, '', wnFeeder.baseIRI);
59
+ modelContainer.addOutage(outageNew);
60
+ insertSPARQL.push(outageNew.createNewStatementSPARQL());
61
+ /** Equipments */
62
+ for (const object of wnFeeder.additionalGroupedEquipment.values()) {
63
+ if (object instanceof ConductingEquipment_1.ConductingEquipment) {
64
+ insertSPARQL.push(outageNew.addOutageIsolationEquipment(object));
65
+ }
66
+ else if (object instanceof WNConnectivityNode_1.WNConnectivityNode) {
67
+ insertSPARQL.push(outageNew.addOutageIsolationConnectivityNodes(object));
68
+ }
69
+ else if (object instanceof EVTerminal_1.EVTerminal) {
70
+ // TBD
71
+ }
72
+ }
73
+ /** WNConnectivityNodes */
74
+ for (const object of wnFeeder.normalEnergizedConnectivityNodes.values()) {
75
+ insertSPARQL.push(outageNew.addOutageIsolationConnectivityNodes(object));
76
+ }
77
+ /** Fault */
78
+ const cnFaultNew = new WNFaultConnectivityNode_1.WNFaultConnectivityNode(common_utils_1.CommonUtils.generateUUID(), `${faultCN.name}`, '', '', wnFeeder.baseIRI);
79
+ modelContainer.addCustomFault(cnFaultNew);
80
+ insertSPARQL.push(cnFaultNew.createNewStatementSPARQL());
81
+ insertSPARQL.push(cnFaultNew.setConnectivityNode(faultCN));
82
+ insertSPARQL.push(cnFaultNew.setOutage(outageNew));
83
+ /** SwitchingPlan de-energise*/
84
+ const switchingPlanDeEnergise = (0, neplan_contingency_analysis_1.createSwitchingPlan)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltmaßnahme-Ausfall`, -1, 'de-energise', outageNew, insertSPARQL);
85
+ modelContainer.addSwitchingPlan(switchingPlanDeEnergise);
86
+ /** SwitchingAction de-energise*/
87
+ const switchingActionDeEnergise = (0, neplan_contingency_analysis_1.createTerminalAction)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltung-Ausfall`, SwitchActionKind_1.SwitchActionKind.open, switchingPlanDeEnergise, insertSPARQL);
88
+ modelContainer.addSwitchingAction(switchingActionDeEnergise);
89
+ /** Alle Terminals zur Freischaltung des Ausfallknotens */
90
+ for (const terminal of fullyResuppliedAction.deenergizedActions) {
91
+ // insertSPARQL.push(switchingActionDeEnergise.addTerminal(terminal as EVTerminal));
92
+ }
93
+ /** SwitchingPlan restore*/
94
+ const switchingPlanRestore = (0, neplan_contingency_analysis_1.createSwitchingPlan)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltmaßnahme-Restore`, 0, 'restore', outageNew, insertSPARQL);
95
+ modelContainer.addSwitchingPlan(switchingPlanRestore);
96
+ /** SwitchingAction re-energise*/
97
+ const switchingActionRestore = (0, neplan_contingency_analysis_1.createTerminalAction)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltung-Restore`, SwitchActionKind_1.SwitchActionKind.close, switchingPlanRestore, insertSPARQL);
98
+ modelContainer.addSwitchingAction(switchingActionRestore);
99
+ /** Alle terminals des Ausfallknotens */
100
+ for (const terminal of fullyResuppliedAction.deenergizedActions) {
101
+ //insertSPARQL.push(switchingActionRestore.addTerminal(terminal as EVTerminal));
102
+ }
103
+ /** Wiederversorgungsmaßnahmen */
104
+ for (let i = 0; i < fullyResuppliedAction.switchElements.length; i++) {
105
+ const switchAction = fullyResuppliedAction.switchElements[i];
106
+ /** SwitchingPlan restore*/
107
+ const switchingPlanRestore = (0, neplan_contingency_analysis_1.createSwitchingPlan)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltmaßnahme-Restore`, (i + 1), 'energise', outageNew, insertSPARQL);
108
+ insertSPARQL.push(switchingPlanRestore.setKind(fullyResuppliedAction.resupplyType));
109
+ modelContainer.addSwitchingPlan(switchingPlanRestore);
110
+ /** Switch-Element */
111
+ if (switchAction.swtch) {
112
+ const switchingActionRestore = (0, neplan_contingency_analysis_1.createSwitchAction)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltung-Restore`, SwitchActionKind_1.SwitchActionKind.close, switchingPlanRestore, insertSPARQL);
113
+ modelContainer.addSwitchingAction(switchingActionRestore);
114
+ insertSPARQL.push(switchingActionRestore.setSwitch(switchAction.swtch));
115
+ }
116
+ /** Switch-Element */
117
+ for (const terminal of switchAction.terminals) {
118
+ const switchingActionRestore = (0, neplan_contingency_analysis_1.createTerminalAction)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltung-Restore`, SwitchActionKind_1.SwitchActionKind.close, switchingPlanRestore, insertSPARQL);
119
+ modelContainer.addSwitchingAction(switchingActionRestore);
120
+ insertSPARQL.push(switchingActionRestore.addTerminal(terminal));
121
+ }
122
+ }
123
+ }
124
+ }
125
+ }
126
+ const length = insertSPARQL.length;
127
+ const graphURI = modelContainer.getGraphURI();
128
+ return length === 0 ? [] : [
129
+ `
130
+ PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
131
+ PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
132
+ PREFIX entsoe: <http://entsoe.eu/CIM/SchemaExtension/3/1#>
133
+ PREFIX westnetzneplan: <http://westnetzneplan.de/CIM/Extensions#>
134
+ PREFIX enervance: <http://enervance.com/CIM/Extensions#>
135
+ ${(0, sparql_utils_1.getInsertDataPartStatement)(graphURI, insertSPARQL)}
136
+ `
137
+ ];
138
+ }
139
+ static findRessuplySwitchingActions(outageConnectivityNodes, baseModel) {
140
+ var _a, _b, _c;
141
+ const evaluatedResupplyActions = new Map();
142
+ const terminals = (Array.from(baseModel.terminals.values()));
143
+ const allCNs = (Array.from(baseModel.connectivityNodes.values()));
144
+ const externalNetworkInjections = (Array.from(baseModel.externalNetworkInjections.values()));
145
+ const switches = [...baseModel.switches.values(), ...baseModel.loadBreakSwitches.values(), ...baseModel.disconnectors.values(), ...baseModel.breakers.values()];
146
+ for (const faultConnectivityNode of outageConnectivityNodes) {
147
+ //const changedTerminalsUUIDs = this.findDeenergiseSwitchingActionWithPaths(faultConnectivityNode as WNConnectivityNode);
148
+ const changedTerminals = this.findDeenergiseSwitchingAction2(faultConnectivityNode);
149
+ const changedPath = this.findDeenergiseSwitchingActionWithPaths(faultConnectivityNode);
150
+ const deeenrgizedTerminalUUIDs = new Array();
151
+ const deeenrgizedCn = new Array(faultConnectivityNode);
152
+ changedPath.forEach(it => {
153
+ var _a;
154
+ if (it.type === 'ViaSwitch') {
155
+ it.switchInstance.open = !it.switchInstance.open;
156
+ deeenrgizedTerminalUUIDs.push(...Array.from(it.switchInstance.terminals.values()).map(it => it.getUUID()));
157
+ deeenrgizedCn.push(...Array.from(it.switchInstance.terminals.values()).map(it => it === null || it === void 0 ? void 0 : it.connectivityNode));
158
+ }
159
+ if (it.type === 'ViaSchaltbarerNode') {
160
+ it.terminal.connected = !it.terminal.connected;
161
+ deeenrgizedTerminalUUIDs.push(it.terminal.getUUID());
162
+ deeenrgizedCn.push((_a = it.terminal) === null || _a === void 0 ? void 0 : _a.connectivityNode);
163
+ }
164
+ });
165
+ const failedSubstation = faultConnectivityNode.getSubstation();
166
+ const feederHeadNode = ((_a = failedSubstation.getPsrType()) === null || _a === void 0 ? void 0 : _a.getName()) === 'Umspannanlage';
167
+ // 1. CNs der ausgefallenen Station ignorieren
168
+ const failedCNs = feederHeadNode ? [faultConnectivityNode] : allCNs.filter(cn => cn.getSubstation().getUUID() === failedSubstation.getUUID());
169
+ const failedFeeder = feederHeadNode ? (_c = (_b = Array.from(faultConnectivityNode.terminals.values()).find(it => { var _a; return (_a = it.conductingEquipment) === null || _a === void 0 ? void 0 : _a.getAdditionalEquipmentContainer(); })) === null || _b === void 0 ? void 0 : _b.conductingEquipment) === null || _c === void 0 ? void 0 : _c.getAdditionalEquipmentContainer() : failedSubstation.getNormalEnergizingFeeder();
170
+ // CNs der Ortsnetzstationen (nicht Umspannanlage, nicht failed)
171
+ const candidateCNs = allCNs.filter(cn => {
172
+ var _a, _b;
173
+ return (((_a = cn.getSubstation().getPsrType()) === null || _a === void 0 ? void 0 : _a.getName()) !== 'Umspannanlage' && // alle CNs von Umspannanlagen
174
+ cn.getSubstation().getUUID() !== failedSubstation.getUUID()) && // alle CNs der ausgefallenen ONS
175
+ ((_b = cn.getSubstation()) === null || _b === void 0 ? void 0 : _b.getNormalEnergizingFeeder()); // Substation muss einen Abgang besitzen
176
+ });
177
+ // 3. Suche nach CNs, die spannungslos sind
178
+ const disconnectedCNs = candidateCNs.filter(cn => !ContingencyAnalysisNeplanWestnetz.isNodeSupplied(cn, terminals.filter(t => !failedCNs.includes(t.connectivityNode)), switches, externalNetworkInjections));
179
+ const openTerminals = ContingencyAnalysisNeplanWestnetz.findOpenedTerminalsToOtherFeeders(deeenrgizedCn, deeenrgizedTerminalUUIDs, failedFeeder, baseModel);
180
+ const openSwitches = ContingencyAnalysisNeplanWestnetz.findOpenedSwitchesToOtherFeeders(deeenrgizedCn, failedFeeder, baseModel);
181
+ const possibleActions = [...openTerminals, ...openSwitches];
182
+ // 4. Finde alle Kombinationen (1er, 2er, 3er etc.)
183
+ const combinations = ContingencyAnalysisNeplanWestnetz.buildSupplyCombinations(possibleActions).filter(set => set.length > 0);
184
+ const results = [];
185
+ const resupplyResults = new Array();
186
+ for (const combo of combinations) {
187
+ // Schaltzustand anwenden
188
+ const s = new Array();
189
+ for (const c of combo) {
190
+ c.terminals.forEach(it => s.push(it.name));
191
+ }
192
+ ContingencyAnalysisNeplanWestnetz.applySwitchCombination(combo);
193
+ // Abgang auf Zyklen prüfen
194
+ const cycle = ContingencyAnalysisNeplanWestnetz.hasCycleInFeeder(failedFeeder, terminals, switches);
195
+ const resupplyResult = {
196
+ uuid: common_utils_1.CommonUtils.generateUUID(),
197
+ faultConnectivityNode: faultConnectivityNode,
198
+ deenergizedActions: changedTerminals,
199
+ cycle: cycle,
200
+ switchElements: combo,
201
+ deenergezedConnectivityNodes: disconnectedCNs,
202
+ resuppledConnectivityNodes: new Array(),
203
+ resupplyType: EVSwitchingPlanKind_1.EVSwitchingPlanKind.noResupply
204
+ };
205
+ resupplyResults.push(resupplyResult);
206
+ for (const cn of disconnectedCNs) {
207
+ const reachable = ContingencyAnalysisNeplanWestnetz.isNodeSupplied(cn, terminals, switches, externalNetworkInjections);
208
+ if (reachable) {
209
+ resupplyResult.resuppledConnectivityNodes.push(cn);
210
+ results.push({ restoredCN: cn, actions: combo });
211
+ }
212
+ }
213
+ // resupplyType
214
+ if (resupplyResult.deenergezedConnectivityNodes.length === resupplyResult.resuppledConnectivityNodes.length) {
215
+ resupplyResult.resupplyType = EVSwitchingPlanKind_1.EVSwitchingPlanKind.fullyResupply;
216
+ }
217
+ else if (resupplyResult.resuppledConnectivityNodes.length > 0) {
218
+ resupplyResult.resupplyType = EVSwitchingPlanKind_1.EVSwitchingPlanKind.partiallyResupply;
219
+ }
220
+ // Schaltzustand rückgängig machen
221
+ ContingencyAnalysisNeplanWestnetz.applySwitchCombination(combo);
222
+ console.log(`${combinations.indexOf(combo) + 1} ${s.join(' ')}
223
+ \n cycle ${cycle}
224
+ \n resupplyResult ${resupplyResult.resupplyType}
225
+ \n ${resupplyResult.resuppledConnectivityNodes.map(it => it.name).join(' -> ')}`);
226
+ console.log();
227
+ }
228
+ // Schaltzustand wiederherstellen
229
+ changedTerminals.forEach(it => {
230
+ if (it.type === 'ViaSwitch') {
231
+ it.switchInstance.open = !it.switchInstance.open;
232
+ }
233
+ if (it.type === 'ViaSchaltbarerNode') {
234
+ it.terminal.connected = !it.terminal.connected;
235
+ }
236
+ });
237
+ evaluatedResupplyActions.set(faultConnectivityNode.getUUID(), resupplyResults);
238
+ }
239
+ return evaluatedResupplyActions;
240
+ }
241
+ static hasCycleInFeeder(feeder, terminals, switches) {
242
+ // 1. Relevante ACLineSegment-Terminals filtern
243
+ const relevantTerminals = terminals.filter(t => {
244
+ var _a, _b, _c;
245
+ return ((_c = (_b = (_a = t.getConnectivityNode()) === null || _a === void 0 ? void 0 : _a.getSubstation()) === null || _b === void 0 ? void 0 : _b.getPsrType()) === null || _c === void 0 ? void 0 : _c.getName()) !== "Umspannanlage" &&
246
+ t.connected &&
247
+ (t.conductingEquipment instanceof ACLineSegment_1.ACLineSegment || t.conductingEquipment instanceof Switch_1.Switch);
248
+ });
249
+ // 2. Geschlossene Switches mit einem Feeder
250
+ const closedSwitches = switches.filter(sw => !sw.open && (sw === null || sw === void 0 ? void 0 : sw.getAdditionalEquipmentContainer()));
251
+ // 3. Union-Find Struktur für ConnectivityNodes (Komponentenbildung über Switches)
252
+ const parent = new Map();
253
+ function find(u) {
254
+ if (!parent.has(u))
255
+ parent.set(u, u);
256
+ if (parent.get(u) === u)
257
+ return u;
258
+ const root = find(parent.get(u));
259
+ parent.set(u, root); // Pfadkompression
260
+ return root;
261
+ }
262
+ function union(u, v) {
263
+ const rootU = find(u);
264
+ const rootV = find(v);
265
+ if (rootU !== rootV) {
266
+ parent.set(rootU, rootV);
267
+ // parent.set(rootV, rootU);
268
+ }
269
+ }
270
+ // 4. Union aller über Switches verbundenen ConnectivityNodes
271
+ for (const sw of closedSwitches) {
272
+ const swTerminals = terminals.filter(t => {
273
+ var _a;
274
+ return ((_a = t.conductingEquipment) === null || _a === void 0 ? void 0 : _a.getUUID()) === (sw === null || sw === void 0 ? void 0 : sw.getUUID()) &&
275
+ t.connected;
276
+ });
277
+ if (swTerminals.length === 2) {
278
+ const [a, b] = swTerminals.map(t => { var _a; return (_a = t.getConnectivityNode()) === null || _a === void 0 ? void 0 : _a.getUUID(); });
279
+ union(a, b);
280
+ }
281
+ }
282
+ // 5. Adjazenzliste basierend auf den "komprimierten" Knoten
283
+ const adjacency = new Map();
284
+ function addEdgeCompressed(a, b) {
285
+ const u = find(a);
286
+ const v = find(b);
287
+ if (u === v)
288
+ return; // kein echter Kantenübergang, gleiches Cluster
289
+ if (!adjacency.has(u))
290
+ adjacency.set(u, new Set());
291
+ if (!adjacency.has(v))
292
+ adjacency.set(v, new Set());
293
+ adjacency.get(u).add(v);
294
+ adjacency.get(v).add(u);
295
+ }
296
+ // 6. ACLineSegment-Verbindungen hinzufügen
297
+ const switchFeeders = closedSwitches.map(it => it.getAdditionalEquipmentContainer());
298
+ const feeders = new Set([feeder, ...switchFeeders]);
299
+ for (const feeder of feeders) {
300
+ for (const eq of feeder.getAdditionalGroupedEquipments().values()) {
301
+ if (!(eq instanceof ACLineSegment_1.ACLineSegment || eq instanceof Switch_1.Switch))
302
+ continue;
303
+ const lineTerminals = relevantTerminals.filter(t => { var _a; return ((_a = t.conductingEquipment) === null || _a === void 0 ? void 0 : _a.getUUID()) === (eq === null || eq === void 0 ? void 0 : eq.getUUID()); });
304
+ if (lineTerminals.length === 2) {
305
+ const [a, b] = lineTerminals.map(t => { var _a; return (_a = t.connectivityNode) === null || _a === void 0 ? void 0 : _a.getUUID(); });
306
+ addEdgeCompressed(a, b);
307
+ }
308
+ }
309
+ }
310
+ // 7. DFS-Zyklusprüfung auf dem komprimierten Graph
311
+ const visited = new Set();
312
+ function dfs(node, parent) {
313
+ visited.add(node);
314
+ for (const neighbor of adjacency.get(node) || []) {
315
+ if (neighbor === parent)
316
+ continue;
317
+ if (visited.has(neighbor))
318
+ return true;
319
+ if (dfs(neighbor, node))
320
+ return true;
321
+ }
322
+ return false;
323
+ }
324
+ for (const node of adjacency.keys()) {
325
+ if (!visited.has(node)) {
326
+ if (dfs(node, null))
327
+ return true;
328
+ }
329
+ }
330
+ return false;
331
+ }
332
+ static buildSupplyCombinations(arr) {
333
+ const result = [];
334
+ const n = arr.length;
335
+ const max = 1 << n;
336
+ for (let i = 1; i < max; i++) {
337
+ const subset = [];
338
+ for (let j = 0; j < n; j++) {
339
+ if ((i & (1 << j)) !== 0) {
340
+ subset.push(arr[j]);
341
+ }
342
+ }
343
+ result.push(subset);
344
+ }
345
+ return result;
346
+ }
347
+ static disconnectTerminals(faultConnectivityNode) {
348
+ const changedTerminals = new Array();
349
+ for (const terminal of faultConnectivityNode.terminals.values()) {
350
+ if (terminal.connected) {
351
+ terminal.connected = false;
352
+ changedTerminals.push(terminal);
353
+ }
354
+ }
355
+ return changedTerminals;
356
+ }
357
+ static applySwitchCombination(switchElements) {
358
+ for (const switchElement of switchElements) {
359
+ for (const terminal of switchElement.terminals) {
360
+ terminal.connected = !terminal.connected;
361
+ }
362
+ if (switchElement.swtch)
363
+ switchElement.swtch.open = !switchElement.swtch.open;
364
+ }
365
+ }
366
+ static isNodeSupplied(startNode, terminals, switches, externalInjections) {
367
+ var _a, _b;
368
+ const visitedCN = new Set();
369
+ const visitedEquipments = new Set();
370
+ const equipmentIsOpen = new Set();
371
+ for (const sw of switches) {
372
+ if (sw.open)
373
+ equipmentIsOpen.add(sw.getUUID());
374
+ }
375
+ const cnToTerminals = new Map();
376
+ for (const t of terminals) {
377
+ if (!(t === null || t === void 0 ? void 0 : t.connected))
378
+ continue;
379
+ if (!(t === null || t === void 0 ? void 0 : t.connectivityNode))
380
+ continue;
381
+ const cnUUID = (_a = t.connectivityNode) === null || _a === void 0 ? void 0 : _a.getUUID();
382
+ if (!cnToTerminals.has(cnUUID))
383
+ cnToTerminals.set(cnUUID, []);
384
+ cnToTerminals.get(cnUUID).push(t);
385
+ }
386
+ const stack = [startNode];
387
+ while (stack.length > 0) {
388
+ const currentCN = stack.pop();
389
+ const currentId = currentCN.getUUID();
390
+ if (visitedCN.has(currentId))
391
+ continue;
392
+ visitedCN.add(currentId);
393
+ const cnTerminals = (_b = cnToTerminals.get(currentId)) !== null && _b !== void 0 ? _b : [];
394
+ for (const terminal of cnTerminals) {
395
+ if (!(terminal === null || terminal === void 0 ? void 0 : terminal.conductingEquipment))
396
+ continue;
397
+ const eq = terminal.conductingEquipment;
398
+ const eqId = eq.getUUID();
399
+ if (equipmentIsOpen.has(eqId))
400
+ continue;
401
+ if (visitedEquipments.has(eqId))
402
+ continue;
403
+ visitedEquipments.add(eqId);
404
+ // Prüfe: Ist das Equipment ein ExternalNetworkInjection?
405
+ if (eq instanceof ExternalNetworkInjection_1.ExternalNetworkInjection) {
406
+ const isExternalNetworkInjection = externalInjections.some(ext => ext.getUUID() === eq.getUUID());
407
+ if (isExternalNetworkInjection)
408
+ return true;
409
+ }
410
+ // Traverse zu anderen Terminals
411
+ for (const otherTerminal of eq.terminals.values()) {
412
+ if (otherTerminal.getUUID() === terminal.getUUID())
413
+ continue;
414
+ if (!(otherTerminal === null || otherTerminal === void 0 ? void 0 : otherTerminal.connected))
415
+ continue;
416
+ if (!(otherTerminal === null || otherTerminal === void 0 ? void 0 : otherTerminal.connectivityNode))
417
+ continue;
418
+ const nextCN = otherTerminal.connectivityNode;
419
+ const nextId = nextCN.getUUID();
420
+ if (!visitedCN.has(nextId) && !stack.includes(nextCN)) {
421
+ stack.push(nextCN);
422
+ }
423
+ }
424
+ }
425
+ }
426
+ return false;
427
+ }
428
+ static findOpenedSwitchesToOtherFeeders(failedConnectivityNodes, failedFeeder, baseModel) {
429
+ var _a, _b;
430
+ const results = new Array();
431
+ // Relevante Switches finden
432
+ const switches = [...baseModel.switches.values(), ...baseModel.loadBreakSwitches.values(), ...baseModel.disconnectors.values(), ...baseModel.breakers.values()];
433
+ for (const swtch of switches) {
434
+ // Nur nicht verbundene Switsches
435
+ if (!swtch.open)
436
+ continue;
437
+ const ceFeeder = swtch.getAdditionalEquipmentContainer();
438
+ const switchTerminals = (_a = Array.from(swtch.terminals.values())) === null || _a === void 0 ? void 0 : _a.filter(it => it.connectivityNode && !failedConnectivityNodes.includes(it.connectivityNode));
439
+ // sind an der Switch-Kombination ACLineSegments von anderen Abgängen angeschlossen
440
+ const switchConnectivityNodes = switchTerminals.map(it => it.connectivityNode);
441
+ const cnFeeders = switchTerminals.map(it => { var _a, _b; return (_b = (_a = it.connectivityNode.getSubstation()) === null || _a === void 0 ? void 0 : _a.getNormalEnergizingFeeder()) === null || _b === void 0 ? void 0 : _b.getUUID(); });
442
+ const switchConductingEquipments = (_b = switchConnectivityNodes.map(it => {
443
+ return Array.from(it.terminals.values()).map(it => it.conductingEquipment);
444
+ })) === null || _b === void 0 ? void 0 : _b.flat();
445
+ cnFeeders.push(...switchConductingEquipments.map(it => { var _a; return (_a = it.getAdditionalEquipmentContainer()) === null || _a === void 0 ? void 0 : _a.getUUID(); }));
446
+ if ((ceFeeder === null || ceFeeder === void 0 ? void 0 : ceFeeder.getUUID()) !== failedFeeder.getUUID() && !cnFeeders.includes(failedFeeder.getUUID()))
447
+ continue;
448
+ results.push({
449
+ swtch,
450
+ terminals: Array.from(swtch.terminals.values()).filter(it => !it.connected)
451
+ });
452
+ }
453
+ return results;
454
+ }
455
+ static findOpenedTerminalsToOtherFeeders(connectivityNodes, deeenrgizedTerminalUUIDs, failedFeeder, baseModel) {
456
+ var _a, _b, _c;
457
+ // Relevante Terminals finden
458
+ const results = new Array();
459
+ for (const terminal of baseModel.terminals.values()) {
460
+ // Nur nicht verbundene Terminals
461
+ if (terminal.connected)
462
+ continue;
463
+ if (deeenrgizedTerminalUUIDs.includes(terminal.getUUID()))
464
+ continue;
465
+ // Verbundungen zu Switches werden übersprungen
466
+ if (!terminal.conductingEquipment || !terminal.connectivityNode)
467
+ continue;
468
+ if (terminal.conductingEquipment instanceof Switch_1.Switch)
469
+ continue;
470
+ if (terminal.conductingEquipment instanceof EnergySource_1.EnergySource)
471
+ continue;
472
+ if (terminal.conductingEquipment instanceof EnergyConsumer_1.EnergyConsumer)
473
+ continue;
474
+ if (connectivityNodes.includes(terminal.connectivityNode))
475
+ continue;
476
+ if (terminal.getUUID() === '254a082a-c503-4c19-911b-9766edeac3b5') {
477
+ console.log();
478
+ }
479
+ // Nur Terminals, die eine Verbindung zum Feeder des betrachteten ConnectivityNodes
480
+ const ceFeeder = (_a = terminal.conductingEquipment) === null || _a === void 0 ? void 0 : _a.getAdditionalEquipmentContainer();
481
+ const cnFeeder = (_c = (_b = terminal.connectivityNode) === null || _b === void 0 ? void 0 : _b.getSubstation()) === null || _c === void 0 ? void 0 : _c.getNormalEnergizingFeeder();
482
+ if ((ceFeeder === null || ceFeeder === void 0 ? void 0 : ceFeeder.getUUID()) !== failedFeeder.getUUID() && (cnFeeder === null || cnFeeder === void 0 ? void 0 : cnFeeder.getUUID()) !== failedFeeder.getUUID())
483
+ continue;
484
+ results.push({
485
+ swtch: null,
486
+ terminals: new Array(terminal)
487
+ });
488
+ }
489
+ return results;
490
+ }
491
+ static findDeenergiseSwitchingAction2(failedNode) {
492
+ const visitedNodes = new Set();
493
+ const toVisit = [failedNode];
494
+ const result = [];
495
+ while (toVisit.length > 0) {
496
+ const currentNode = toVisit.pop();
497
+ if (visitedNodes.has(currentNode.getUUID()))
498
+ continue;
499
+ visitedNodes.add(currentNode.getUUID());
500
+ if (currentNode.switchable === WNSwitchTypeKind_1.WNSwitchTypeKind.S || currentNode.switchable === WNSwitchTypeKind_1.WNSwitchTypeKind.E) {
501
+ // Schaltbarer Node gefunden → ViaSchaltbarerNode über Terminal einfügen
502
+ for (const terminal of currentNode.terminals.values()) {
503
+ result.push({ type: 'ViaSchaltbarerNode', terminal: terminal });
504
+ }
505
+ continue; // keine weitere Traversierung notwendig
506
+ }
507
+ for (const terminal of currentNode.terminals.values()) {
508
+ const equipment = terminal === null || terminal === void 0 ? void 0 : terminal.conductingEquipment;
509
+ if (!equipment)
510
+ continue;
511
+ if (equipment instanceof Switch_1.Switch) {
512
+ result.push({ type: 'ViaSwitch', switchInstance: equipment });
513
+ continue; // Switch → Ende dieses Pfads
514
+ }
515
+ for (const otherTerminal of equipment.terminals.values()) {
516
+ if (otherTerminal === terminal)
517
+ continue;
518
+ const nextNode = otherTerminal === null || otherTerminal === void 0 ? void 0 : otherTerminal.connectivityNode;
519
+ if (!nextNode)
520
+ continue;
521
+ if (!visitedNodes.has(nextNode.getUUID())) {
522
+ toVisit.push(nextNode);
523
+ }
524
+ }
525
+ }
526
+ }
527
+ return result;
528
+ }
529
+ static findDeenergiseSwitchingActionWithPaths(failedNode) {
530
+ const visitedNodes = new Set();
531
+ const visitedSwitches = new Set(); // Zum Filtern doppelter Switches
532
+ const visitedSchaltbareNodes = new Set(); // Zum Filtern doppelter schaltbarer Nodes
533
+ const toVisit = [
534
+ { node: failedNode, path: [{ node: failedNode }] }
535
+ ];
536
+ const result = [];
537
+ while (toVisit.length > 0) {
538
+ const { node: currentNode, path } = toVisit.pop();
539
+ const nodeId = currentNode.getUUID();
540
+ if (visitedNodes.has(nodeId))
541
+ continue;
542
+ visitedNodes.add(nodeId);
543
+ const lastStep = path[path.length - 1];
544
+ const lastEquipment = lastStep === null || lastStep === void 0 ? void 0 : lastStep.equipment;
545
+ // Prüfe auf schaltbaren Node
546
+ if ((currentNode.switchable === WNSwitchTypeKind_1.WNSwitchTypeKind.S || currentNode.switchable === WNSwitchTypeKind_1.WNSwitchTypeKind.E) &&
547
+ !visitedSchaltbareNodes.has(nodeId)) {
548
+ visitedSchaltbareNodes.add(nodeId);
549
+ let matchedTerminal;
550
+ // Finde den Terminal, der mit dem letzten Equipment verbunden ist
551
+ if (lastEquipment) {
552
+ for (const terminal of currentNode.terminals.values()) {
553
+ if (terminal.conductingEquipment === lastEquipment) {
554
+ matchedTerminal = terminal;
555
+ break;
556
+ }
557
+ }
558
+ }
559
+ // Fallback: irgendein Terminal (z. B. Startpunkt ist schaltbar)
560
+ if (!matchedTerminal && currentNode.terminals.size > 0) {
561
+ matchedTerminal = currentNode.terminals.values().next().value;
562
+ }
563
+ if (matchedTerminal) {
564
+ result.push({
565
+ type: 'ViaSchaltbarerNode',
566
+ terminal: matchedTerminal,
567
+ path: [...path]
568
+ });
569
+ }
570
+ continue;
571
+ }
572
+ for (const terminal of currentNode.terminals.values()) {
573
+ const equipment = terminal === null || terminal === void 0 ? void 0 : terminal.conductingEquipment;
574
+ if (!equipment)
575
+ continue;
576
+ // Switch behandeln (aber nur einmal pro UUID)
577
+ if (equipment instanceof Switch_1.Switch) {
578
+ const switchId = equipment.getUUID();
579
+ if (!visitedSwitches.has(switchId)) {
580
+ visitedSwitches.add(switchId);
581
+ result.push({
582
+ type: 'ViaSwitch',
583
+ switchInstance: equipment,
584
+ path: [...path, { node: currentNode, equipment }]
585
+ });
586
+ }
587
+ continue; // Stop bei Switch
588
+ }
589
+ // Weiter durch anderes Equipment
590
+ for (const otherTerminal of equipment.terminals.values()) {
591
+ if (otherTerminal === terminal)
592
+ continue;
593
+ const nextNode = otherTerminal === null || otherTerminal === void 0 ? void 0 : otherTerminal.connectivityNode;
594
+ if (!nextNode || visitedNodes.has(nextNode.getUUID()))
595
+ continue;
596
+ toVisit.push({
597
+ node: nextNode,
598
+ path: [...path, { node: currentNode, equipment }]
599
+ });
600
+ }
601
+ }
602
+ }
603
+ return result;
604
+ }
605
+ static findWithSmallestDeenergizedNodes(arr) {
606
+ if (arr.length === 0)
607
+ return [];
608
+ // Finde die kleinste Länge
609
+ const maxLength = Math.max(...arr.map(item => item.resuppledConnectivityNodes.length));
610
+ // Filtere alle Objekte, die genau diese Länge haben
611
+ return arr.filter(item => !item.cycle && item.resuppledConnectivityNodes.length === maxLength);
612
+ }
613
+ }
614
+ exports.ContingencyAnalysisNeplanWestnetz = ContingencyAnalysisNeplanWestnetz;
615
+ //# sourceMappingURL=contingency-analysis.neplan.westnetz.js.map