@enervance/insight-cim-model 0.0.448 → 0.0.455

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.
@@ -1,27 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
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
4
  const ACLineSegment_1 = require("../../model/wires/ACLineSegment.js");
8
5
  const EVSwitchingPlanKind_1 = require("../../model/extensions/enervance/operations/EVSwitchingPlanKind.js");
9
6
  const WNConnectivityNode_1 = require("../../model/extensions/westnetz-neplan/core/WNConnectivityNode.js");
10
7
  const WNOutage_1 = require("../../model/extensions/westnetz-neplan/operations/WNOutage.js");
8
+ const common_utils_1 = require("../../utils2/common.utils.js");
11
9
  const ConductingEquipment_1 = require("../../model/core/ConductingEquipment.js");
12
10
  const EVTerminal_1 = require("../../model/extensions/enervance/core/EVTerminal.js");
13
11
  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");
12
+ const etl_neplan_contingency_analysis_1 = require("../../etl/etl-neplan/etl-neplan-contingency-analysis.js");
15
13
  const SwitchActionKind_1 = require("../../model/operations/SwitchActionKind.js");
14
+ const neplan_contingency_analysis_1 = require("../../etl/etl-neplan/neplan-contingency-analysis.js");
16
15
  const sparql_utils_1 = require("../../util/sparql/sparql-utils.js");
16
+ const ExternalNetworkInjection_1 = require("../../model/wires/ExternalNetworkInjection.js");
17
+ const Switch_1 = require("../../model/wires/Switch.js");
18
+ const WNSwitchTypeKind_1 = require("../../model/extensions/westnetz-neplan/core/WNSwitchTypeKind.js");
17
19
  const EnergySource_1 = require("../../model/wires/EnergySource.js");
18
20
  const EnergyConsumer_1 = require("../../model/wires/EnergyConsumer.js");
19
21
  class ContingencyAnalysisNeplanWestnetz {
20
22
  static performContingencyAnalysis(modelContainer) {
21
23
  var _a, _b, _c;
22
24
  const insertSPARQL = new Array;
25
+ const report = new Array();
26
+ report.push(`Netz ${modelContainer.modelsContainer.graphUri}`);
23
27
  for (const feeder of modelContainer.feeders.values()) {
24
28
  const wnFeeder = feeder;
29
+ report.push(`Starte mit Feeder ${wnFeeder.name}`);
25
30
  /** relevante Ausfälle
26
31
  * 1 Ausfall des ersten ConnectivityNodes im Abgang
27
32
  * 2 Alle ConnectivityNodes mit drei und mehr ACLineSegments */
@@ -40,72 +45,92 @@ class ContingencyAnalysisNeplanWestnetz {
40
45
  for (const resupplyResult of resupplyResults.values()) {
41
46
  // Ausfall
42
47
  const outageNode = (_b = resupplyResult.find(it => it.faultConnectivityNode)) === null || _b === void 0 ? void 0 : _b.faultConnectivityNode;
48
+ if (outageNode === undefined) {
49
+ continue;
50
+ }
43
51
  // Freischaltungsmaßnahme
44
52
  const deenergizedAction = (_c = resupplyResult.find(it => it.deenergizedActions)) === null || _c === void 0 ? void 0 : _c.deenergizedActions;
53
+ // Schaltmaßnahmen ohne Zyklen
54
+ const resupplyActionsWithoudCycles = resupplyResult.filter(it => !it.cycle);
45
55
  // Schaltmaßnahmen mit vollständiger Wiederversorgung
46
- const fullyResuppliedActions = resupplyResult.filter(it => !it.cycle && it.resupplyType === EVSwitchingPlanKind_1.EVSwitchingPlanKind.fullyResupply);
56
+ const fullyResuppliedActions = resupplyActionsWithoudCycles.filter(it => it.resupplyType === EVSwitchingPlanKind_1.EVSwitchingPlanKind.fullyResupply);
47
57
  // Schaltmaßnahmen mit partieller Wiederversorgung
48
- const partiallyResuppliedActions = resupplyResult.filter(it => !it.cycle && it.resupplyType === EVSwitchingPlanKind_1.EVSwitchingPlanKind.partiallyResupply);
49
- console.log(`Ausfall ${outageNode.getUUID()} | ${outageNode.name}\n
58
+ const partiallyResuppliedActionsAll = resupplyActionsWithoudCycles.filter(it => it.resupplyType === EVSwitchingPlanKind_1.EVSwitchingPlanKind.partiallyResupply);
59
+ const partiallyResuppliedActions = ContingencyAnalysisNeplanWestnetz.findWithSmallestDeenergizedNodes(partiallyResuppliedActionsAll);
60
+ report.push(`Ausfall ${outageNode.getUUID()} | ${outageNode.name}\n
50
61
  \tSchaltmaßnahmen mit vollständiger Wiederversorgung: ${fullyResuppliedActions.length}\n
51
62
  \tSchaltmaßnahmen mit partieller Wiederversorgung: ${partiallyResuppliedActions.length}`);
52
- if (fullyResuppliedActions.length === 0)
63
+ const actions = fullyResuppliedActions.length ? fullyResuppliedActions : partiallyResuppliedActions;
64
+ if (actions.length === 0)
53
65
  continue;
54
66
  /** Ausfallschaltmaßnahme anlegen */
55
67
  const faultCN = outageNode;
56
- for (const fullyResuppliedAction of fullyResuppliedActions) {
57
- const outageNew = new WNOutage_1.WNOutage(common_utils_1.CommonUtils.generateUUID(), `Ausfall-${faultCN.name}`, `${wnFeeder.shortName}`, '', wnFeeder.baseIRI);
58
- modelContainer.addOutage(outageNew);
59
- insertSPARQL.push(outageNew.createNewStatementSPARQL());
60
- /** Equipments */
61
- for (const object of wnFeeder.additionalGroupedEquipment.values()) {
62
- if (object instanceof ConductingEquipment_1.ConductingEquipment) {
63
- insertSPARQL.push(outageNew.addOutageIsolationEquipment(object));
64
- }
65
- else if (object instanceof WNConnectivityNode_1.WNConnectivityNode) {
66
- insertSPARQL.push(outageNew.addOutageIsolationConnectivityNodes(object));
67
- }
68
- else if (object instanceof EVTerminal_1.EVTerminal) {
69
- // TBD
70
- }
68
+ const outageNew = new WNOutage_1.WNOutage(common_utils_1.CommonUtils.generateUUID(), `Ausfall-${faultCN.name}`, `${wnFeeder.shortName}`, '', wnFeeder.baseIRI);
69
+ modelContainer.addOutage(outageNew);
70
+ insertSPARQL.push(outageNew.createNewStatementSPARQL());
71
+ /** Equipments */
72
+ for (const object of wnFeeder.additionalGroupedEquipment.values()) {
73
+ if (object instanceof ConductingEquipment_1.ConductingEquipment) {
74
+ insertSPARQL.push(outageNew.addOutageIsolationEquipment(object));
71
75
  }
72
- /** WNConnectivityNodes */
73
- for (const object of wnFeeder.normalEnergizedConnectivityNodes.values()) {
76
+ else if (object instanceof WNConnectivityNode_1.WNConnectivityNode) {
74
77
  insertSPARQL.push(outageNew.addOutageIsolationConnectivityNodes(object));
75
78
  }
76
- /** Fault */
77
- const cnFaultNew = new WNFaultConnectivityNode_1.WNFaultConnectivityNode(common_utils_1.CommonUtils.generateUUID(), `${faultCN.name}`, '', '', wnFeeder.baseIRI);
78
- modelContainer.addCustomFault(cnFaultNew);
79
- insertSPARQL.push(cnFaultNew.createNewStatementSPARQL());
80
- insertSPARQL.push(cnFaultNew.setConnectivityNode(faultCN));
81
- insertSPARQL.push(cnFaultNew.setOutage(outageNew));
82
- /** SwitchingPlan de-energise*/
83
- const switchingPlanDeEnergise = (0, neplan_contingency_analysis_1.createSwitchingPlan)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltmaßnahme-Ausfall`, -1, 'de-energise', outageNew, insertSPARQL);
84
- modelContainer.addSwitchingPlan(switchingPlanDeEnergise);
85
- /** SwitchingAction de-energise*/
86
- const switchingActionDeEnergise = (0, neplan_contingency_analysis_1.createTerminalAction)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltung-Ausfall`, SwitchActionKind_1.SwitchActionKind.open, switchingPlanDeEnergise, insertSPARQL);
87
- modelContainer.addSwitchingAction(switchingActionDeEnergise);
88
- /** Alle Terminals zur Freischaltung des Ausfallknotens */
89
- for (const terminal of fullyResuppliedAction.deenergizedActions) {
90
- // insertSPARQL.push(switchingActionDeEnergise.addTerminal(terminal as EVTerminal));
79
+ else if (object instanceof EVTerminal_1.EVTerminal) {
80
+ // TBD
81
+ }
82
+ }
83
+ /** WNConnectivityNodes */
84
+ for (const object of wnFeeder.normalEnergizedConnectivityNodes.values()) {
85
+ insertSPARQL.push(outageNew.addOutageIsolationConnectivityNodes(object));
86
+ }
87
+ /** Fault */
88
+ const cnFaultNew = new WNFaultConnectivityNode_1.WNFaultConnectivityNode(common_utils_1.CommonUtils.generateUUID(), `${faultCN.name}`, '', '', wnFeeder.baseIRI);
89
+ modelContainer.addCustomFault(cnFaultNew);
90
+ insertSPARQL.push(cnFaultNew.createNewStatementSPARQL());
91
+ insertSPARQL.push(cnFaultNew.setConnectivityNode(faultCN));
92
+ insertSPARQL.push(cnFaultNew.setOutage(outageNew));
93
+ /** SwitchingPlan de-energise*/
94
+ const switchingPlanDeEnergise = (0, etl_neplan_contingency_analysis_1.createSwitchingPlan)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltmaßnahme-Ausfall`, -1, 'de-energise', outageNew, insertSPARQL);
95
+ modelContainer.addSwitchingPlan(switchingPlanDeEnergise);
96
+ /** SwitchingActions de-energise*/
97
+ const switchingActionDeEnergise = (0, etl_neplan_contingency_analysis_1.createTerminalAction)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Ausfall Freischaltung`, SwitchActionKind_1.SwitchActionKind.open, switchingPlanDeEnergise, insertSPARQL);
98
+ modelContainer.addSwitchingAction(switchingActionDeEnergise);
99
+ for (const switchElement of deenergizedAction) {
100
+ if (switchElement.type === 'ViaSwitch') {
101
+ // TODO
102
+ }
103
+ else if (switchElement.type === 'ViaSchaltbarerNode') {
104
+ insertSPARQL.push(switchingActionDeEnergise.addTerminal(switchElement.terminal));
105
+ }
106
+ }
107
+ /** SwitchingPlan re-energise*/
108
+ const switchingPlanRestore = (0, etl_neplan_contingency_analysis_1.createSwitchingPlan)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltmaßnahme-Restore`, '0', 're-energise', outageNew, insertSPARQL);
109
+ modelContainer.addSwitchingPlan(switchingPlanRestore);
110
+ /** SwitchingAction re-energise*/
111
+ const switchingActionRestore = (0, etl_neplan_contingency_analysis_1.createTerminalAction)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltmaßnahme-Restore`, SwitchActionKind_1.SwitchActionKind.close, switchingPlanRestore, insertSPARQL);
112
+ modelContainer.addSwitchingAction(switchingActionRestore);
113
+ for (const switchElement of deenergizedAction) {
114
+ if (switchElement.type === 'ViaSwitch') {
115
+ // TODO
116
+ }
117
+ else if (switchElement.type === 'ViaSchaltbarerNode') {
118
+ insertSPARQL.push(switchingActionRestore.addTerminal(switchElement.terminal));
119
+ }
120
+ }
121
+ for (let i = 0; i < actions.length; i++) {
122
+ const action = actions[i];
123
+ // Bei partieller Wiederversorgung wird zunächst max 2 Maßahmen berücksichtigt.
124
+ if (action.resupplyType === EVSwitchingPlanKind_1.EVSwitchingPlanKind.partiallyResupply) {
125
+ if (i > 3)
126
+ continue;
91
127
  }
92
128
  /** SwitchingPlan restore*/
93
- const switchingPlanRestore = (0, neplan_contingency_analysis_1.createSwitchingPlan)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltmaßnahme-Restore`, 0, 'restore', outageNew, insertSPARQL);
129
+ const switchingPlanRestore = (0, etl_neplan_contingency_analysis_1.createSwitchingPlan)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltmaßnahme-Restore`, (i + 1), 'energise', outageNew, insertSPARQL);
130
+ insertSPARQL.push(switchingPlanRestore.setKind(action.resupplyType));
94
131
  modelContainer.addSwitchingPlan(switchingPlanRestore);
95
- /** SwitchingAction re-energise*/
96
- const switchingActionRestore = (0, neplan_contingency_analysis_1.createTerminalAction)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltung-Restore`, SwitchActionKind_1.SwitchActionKind.close, switchingPlanRestore, insertSPARQL);
97
- modelContainer.addSwitchingAction(switchingActionRestore);
98
- /** Alle terminals des Ausfallknotens */
99
- for (const terminal of fullyResuppliedAction.deenergizedActions) {
100
- //insertSPARQL.push(switchingActionRestore.addTerminal(terminal as EVTerminal));
101
- }
102
132
  /** Wiederversorgungsmaßnahmen */
103
- for (let i = 0; i < fullyResuppliedAction.switchElements.length; i++) {
104
- const switchAction = fullyResuppliedAction.switchElements[i];
105
- /** SwitchingPlan restore*/
106
- const switchingPlanRestore = (0, neplan_contingency_analysis_1.createSwitchingPlan)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltmaßnahme-Restore`, (i + 1), 'energise', outageNew, insertSPARQL);
107
- insertSPARQL.push(switchingPlanRestore.setKind(fullyResuppliedAction.resupplyType));
108
- modelContainer.addSwitchingPlan(switchingPlanRestore);
133
+ for (const switchAction of action.switchElements) {
109
134
  /** Switch-Element */
110
135
  if (switchAction.swtch) {
111
136
  const switchingActionRestore = (0, neplan_contingency_analysis_1.createSwitchAction)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltung-Restore`, SwitchActionKind_1.SwitchActionKind.close, switchingPlanRestore, insertSPARQL);
@@ -114,7 +139,7 @@ class ContingencyAnalysisNeplanWestnetz {
114
139
  }
115
140
  /** Switch-Element */
116
141
  for (const terminal of switchAction.terminals) {
117
- const switchingActionRestore = (0, neplan_contingency_analysis_1.createTerminalAction)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltung-Restore`, SwitchActionKind_1.SwitchActionKind.close, switchingPlanRestore, insertSPARQL);
142
+ const switchingActionRestore = (0, etl_neplan_contingency_analysis_1.createTerminalAction)(common_utils_1.CommonUtils.generateUUID(), wnFeeder.baseIRI, `Schaltung-Restore`, SwitchActionKind_1.SwitchActionKind.close, switchingPlanRestore, insertSPARQL);
118
143
  modelContainer.addSwitchingAction(switchingActionRestore);
119
144
  insertSPARQL.push(switchingActionRestore.addTerminal(terminal));
120
145
  }
@@ -124,7 +149,7 @@ class ContingencyAnalysisNeplanWestnetz {
124
149
  }
125
150
  const length = insertSPARQL.length;
126
151
  const graphURI = modelContainer.getGraphURI();
127
- return length === 0 ? [] : [
152
+ const sparql = length === 0 ? [] : [
128
153
  `
129
154
  PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
130
155
  PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
@@ -134,9 +159,10 @@ class ContingencyAnalysisNeplanWestnetz {
134
159
  ${(0, sparql_utils_1.getInsertDataPartStatement)(graphURI, insertSPARQL)}
135
160
  `
136
161
  ];
162
+ return { sparql: sparql, report: report };
137
163
  }
138
164
  static findRessuplySwitchingActions(outageConnectivityNodes, baseModel) {
139
- var _a, _b, _c;
165
+ var _a, _b, _c, _d;
140
166
  const evaluatedResupplyActions = new Map();
141
167
  const terminals = (Array.from(baseModel.terminals.values()));
142
168
  const allCNs = (Array.from(baseModel.connectivityNodes.values()));
@@ -149,31 +175,35 @@ class ContingencyAnalysisNeplanWestnetz {
149
175
  changedPath.forEach(it => {
150
176
  var _a;
151
177
  if (it.type === 'ViaSwitch') {
152
- it.switchInstance.open = !it.switchInstance.open;
153
178
  deeenrgizedTerminalUUIDs.push(...Array.from(it.switchInstance.terminals.values()).map(it => it.getUUID()));
154
179
  deeenrgizedCn.push(...Array.from(it.switchInstance.terminals.values()).map(it => it === null || it === void 0 ? void 0 : it.connectivityNode));
155
180
  }
156
181
  if (it.type === 'ViaSchaltbarerNode') {
157
- it.terminal.connected = !it.terminal.connected;
158
182
  deeenrgizedTerminalUUIDs.push(it.terminal.getUUID());
159
183
  deeenrgizedCn.push((_a = it.terminal) === null || _a === void 0 ? void 0 : _a.connectivityNode);
160
184
  }
161
185
  });
186
+ // Fehler elektrisch isolieren
187
+ this.invertSwitchStates(changedPath);
162
188
  const failedSubstation = faultConnectivityNode.getSubstation();
163
189
  const feederHeadNode = ((_a = failedSubstation.getPsrType()) === null || _a === void 0 ? void 0 : _a.getName()) === 'Umspannanlage';
164
190
  // 1. CNs der ausgefallenen Station ignorieren
165
191
  const failedCNs = feederHeadNode ? [faultConnectivityNode] : allCNs.filter(cn => cn.getSubstation().getUUID() === failedSubstation.getUUID());
166
192
  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();
193
+ if (!failedFeeder) {
194
+ console.log(`faultCN ${faultConnectivityNode.getName()} | ${faultConnectivityNode.description} hat keinen Feeder`);
195
+ continue;
196
+ }
167
197
  // CNs der Ortsnetzstationen (nicht Umspannanlage, nicht failed)
168
198
  const candidateCNs = allCNs.filter(cn => {
169
199
  var _a, _b;
170
200
  return (((_a = cn.getSubstation().getPsrType()) === null || _a === void 0 ? void 0 : _a.getName()) !== 'Umspannanlage' && // alle CNs von Umspannanlagen
171
201
  cn.getSubstation().getUUID() !== failedSubstation.getUUID()) && // alle CNs der ausgefallenen ONS
172
- ((_b = cn.getSubstation()) === null || _b === void 0 ? void 0 : _b.getNormalEnergizingFeeder()); // Substation muss einen Abgang besitzen
202
+ ((_b = cn.getSubstation()) === null || _b === void 0 ? void 0 : _b.getNormalEnergizingFeeder()) && // Substation muss einen Abgang besitzen
203
+ (cn === null || cn === void 0 ? void 0 : cn.additionalConnectivityNodeContainer); // Substation muss einen Abgang besitzen
173
204
  });
174
205
  // 3. Suche nach CNs, die spannungslos sind
175
- const failedFeederCNs = candidateCNs.filter(cn => { var _a, _b; return ((_b = (_a = cn === null || cn === void 0 ? void 0 : cn.getSubstation()) === null || _a === void 0 ? void 0 : _a.getNormalEnergizingFeeder()) === null || _b === void 0 ? void 0 : _b.getUUID()) === failedFeeder.getUUID(); });
176
- const disconnectedCNs = failedFeederCNs.filter(cn => !ContingencyAnalysisNeplanWestnetz.isNodeSupplied(cn, terminals.filter(t => !failedCNs.includes(t.connectivityNode)), switches, externalNetworkInjections));
206
+ const disconnectedCNs = candidateCNs.filter(cn => !ContingencyAnalysisNeplanWestnetz.isNodeSupplied(cn, terminals.filter(t => !failedCNs.includes(t.connectivityNode)), switches, externalNetworkInjections));
177
207
  const openTerminals = ContingencyAnalysisNeplanWestnetz.findOpenedTerminalsToOtherFeeders(deeenrgizedCn, deeenrgizedTerminalUUIDs, failedFeeder, baseModel);
178
208
  const openSwitches = ContingencyAnalysisNeplanWestnetz.findOpenedSwitchesToOtherFeeders(deeenrgizedCn, failedFeeder, baseModel);
179
209
  const possibleActions = [...openTerminals, ...openSwitches];
@@ -182,18 +212,30 @@ class ContingencyAnalysisNeplanWestnetz {
182
212
  const results = [];
183
213
  const resupplyResults = new Array();
184
214
  for (const combo of combinations) {
215
+ const involvedFeeder = new Array();
216
+ console.log(`Prüfe Combo ${combinations.indexOf(combo)}`);
217
+ for (const combination of combo) {
218
+ console.log('\tinvolved CNs');
219
+ combination.terminals.forEach(t => { var _a; return console.log(`\t\t${(_a = t.connectivityNode) === null || _a === void 0 ? void 0 : _a.getUUID()}`); });
220
+ console.log('\tinvolved Switches', (_d = combination.swtch) === null || _d === void 0 ? void 0 : _d.getUUID(), switches.find(it => { var _a; return it.getUUID() === ((_a = combination.swtch) === null || _a === void 0 ? void 0 : _a.getUUID()); }) !== undefined);
221
+ console.log('\tinvolved Feeder');
222
+ combination.feeders.forEach(feeder => console.log(`\t\t${feeder.name}`));
223
+ involvedFeeder.push(...combination.feeders.filter(it => it));
224
+ }
185
225
  const isUseful = ContingencyAnalysisNeplanWestnetz.isSwitchCombinationUseful(combo, disconnectedCNs, terminals, switches, externalNetworkInjections);
226
+ console.log(`\tisUseful ${isUseful}`);
186
227
  if (!isUseful)
187
228
  continue;
188
229
  // Schaltzustand anwenden
189
- const switchNames = new Array();
230
+ const s = new Array();
190
231
  for (const c of combo) {
191
- c.terminals.forEach(it => switchNames.push(it.name));
232
+ c.terminals.forEach(it => s.push(it.name));
192
233
  }
193
- // hier die Kombinationen einzeln anwenden und auf sinnhaftigkeit prüfen.
234
+ // const involvedFeeder: Array<Feeder> = this.getFeedersFromCombo(failedFeeder, combo);
235
+ // Die Maßnahmen einzeln anwenden, um wirksamkeit zu prüfen
194
236
  ContingencyAnalysisNeplanWestnetz.applySwitchCombination(combo);
195
237
  // Abgang auf Zyklen prüfen
196
- const cycle = ContingencyAnalysisNeplanWestnetz.hasCycleInFeeder(failedFeeder, terminals, switches);
238
+ const cycle = ContingencyAnalysisNeplanWestnetz.hasCycleInFeeder(involvedFeeder, terminals, switches);
197
239
  const resupplyResult = {
198
240
  uuid: common_utils_1.CommonUtils.generateUUID(),
199
241
  faultConnectivityNode: faultConnectivityNode,
@@ -219,37 +261,39 @@ class ContingencyAnalysisNeplanWestnetz {
219
261
  else if (resupplyResult.resuppledConnectivityNodes.length > 0) {
220
262
  resupplyResult.resupplyType = EVSwitchingPlanKind_1.EVSwitchingPlanKind.partiallyResupply;
221
263
  }
264
+ const resuppledConnectivityNodesUUID = resupplyResult.resuppledConnectivityNodes.map(it => it.getUUID());
265
+ resupplyResult.deenergezedConnectivityNodes.forEach(it => {
266
+ if (!resuppledConnectivityNodesUUID.includes(it.getUUID()))
267
+ console.log(it.getUUID());
268
+ });
222
269
  // Schaltzustand rückgängig machen
223
270
  ContingencyAnalysisNeplanWestnetz.applySwitchCombination(combo);
224
- console.log(`${combinations.indexOf(combo) + 1} ${switchNames.join(' ')}
225
- \n cycle ${cycle}
226
- \n resupplyResult ${resupplyResult.resupplyType}
227
- \n ${resupplyResult.resuppledConnectivityNodes.map(it => it.name).join(' -> ')}`);
228
- console.log();
271
+ /* console.log(`${combinations.indexOf(combo) + 1} ${s.join(' ')}
272
+ \n cycle ${cycle}
273
+ \n resupplyResult ${resupplyResult.resupplyType}
274
+ \n ${resupplyResult.resuppledConnectivityNodes.map(it => it.name).join(' -> ')}`);
275
+ console.log()*/
229
276
  }
230
277
  // Schaltzustand wiederherstellen
231
- changedPath.forEach(it => {
232
- if (it.type === 'ViaSwitch') {
233
- it.switchInstance.open = !it.switchInstance.open;
234
- }
235
- if (it.type === 'ViaSchaltbarerNode') {
236
- it.terminal.connected = !it.terminal.connected;
237
- }
238
- });
278
+ this.invertSwitchStates(changedPath);
239
279
  evaluatedResupplyActions.set(faultConnectivityNode.getUUID(), resupplyResults);
240
280
  }
241
281
  return evaluatedResupplyActions;
242
282
  }
243
- static hasCycleInFeeder(feeder, terminals, switches) {
283
+ static hasCycleInFeeder(involvedFeeders, allTerminals, allSwitches) {
284
+ var _a;
285
+ const feederUUID = (_a = involvedFeeders.map(it => it.getUUID())) === null || _a === void 0 ? void 0 : _a.filter(it => it);
244
286
  // 1. Relevante ACLineSegment-Terminals filtern
245
- const relevantTerminals = terminals.filter(t => {
287
+ const feederTerminals = allTerminals.filter(it => { var _a, _b; return feederUUID.includes((_b = (_a = it.connectivityNode) === null || _a === void 0 ? void 0 : _a.additionalConnectivityNodeContainer) === null || _b === void 0 ? void 0 : _b.getUUID()) && it.connected; });
288
+ const relevantTerminals = feederTerminals.filter(t => {
246
289
  var _a, _b, _c;
247
290
  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" &&
248
- t.connected &&
249
291
  (t.conductingEquipment instanceof ACLineSegment_1.ACLineSegment || t.conductingEquipment instanceof Switch_1.Switch);
250
292
  });
251
293
  // 2. Geschlossene Switches mit einem Feeder
252
- const closedSwitches = switches.filter(sw => !sw.open && (sw === null || sw === void 0 ? void 0 : sw.getAdditionalEquipmentContainer()));
294
+ const aaa = allSwitches.find(it => it.getUUID() === 'ad29f120-a6c0-4577-9adf-af7562b289f6');
295
+ const closedSwitches = allSwitches.filter(sw => !sw.open);
296
+ const bbb = closedSwitches.find(it => it.getUUID() === 'ad29f120-a6c0-4577-9adf-af7562b289f6');
253
297
  // 3. Union-Find Struktur für ConnectivityNodes (Komponentenbildung über Switches)
254
298
  const parent = new Map();
255
299
  function find(u) {
@@ -269,19 +313,26 @@ class ContingencyAnalysisNeplanWestnetz {
269
313
  // parent.set(rootV, rootU);
270
314
  }
271
315
  }
316
+ const switchFeedersArray = new Array;
272
317
  // 4. Union aller über Switches verbundenen ConnectivityNodes
273
318
  for (const sw of closedSwitches) {
274
- const swTerminals = terminals.filter(t => {
275
- var _a;
319
+ if (sw.getUUID() === 'ad29f120-a6c0-4577-9adf-af7562b289f6') {
320
+ console.log();
321
+ }
322
+ const swTerminals = allTerminals.filter(t => {
323
+ var _a, _b, _c;
276
324
  return ((_a = t.conductingEquipment) === null || _a === void 0 ? void 0 : _a.getUUID()) === (sw === null || sw === void 0 ? void 0 : sw.getUUID()) &&
277
- t.connected;
325
+ t.connected &&
326
+ feederUUID.includes((_c = (_b = t.connectivityNode) === null || _b === void 0 ? void 0 : _b.additionalConnectivityNodeContainer) === null || _c === void 0 ? void 0 : _c.getUUID());
278
327
  });
279
328
  if (swTerminals.length === 2) {
280
329
  const [a, b] = swTerminals.map(t => { var _a; return (_a = t.getConnectivityNode()) === null || _a === void 0 ? void 0 : _a.getUUID(); });
330
+ console.log('union', sw.getUUID(), a, b);
281
331
  union(a, b);
332
+ switchFeedersArray.push(...swTerminals.map(it => { var _a; return (_a = it.connectivityNode) === null || _a === void 0 ? void 0 : _a.additionalConnectivityNodeContainer; }));
282
333
  }
283
334
  }
284
- // 5. Adjazenzliste basierend auf den "komprimierten" Knoten
335
+ // 5. Adjazenzmatrix basierend auf den "komprimierten" Knoten
285
336
  const adjacency = new Map();
286
337
  function addEdgeCompressed(a, b) {
287
338
  const u = find(a);
@@ -296,8 +347,9 @@ class ContingencyAnalysisNeplanWestnetz {
296
347
  adjacency.get(v).add(u);
297
348
  }
298
349
  // 6. ACLineSegment-Verbindungen hinzufügen
299
- const switchFeeders = closedSwitches.map(it => it.getAdditionalEquipmentContainer());
300
- const feeders = new Set([feeder, ...switchFeeders]);
350
+ //const switchFeeders = closedSwitches.map(it => it.getAdditionalEquipmentContainer()) as Array<Feeder>;
351
+ const switchFeeders = switchFeedersArray.filter(t => t);
352
+ const feeders = new Set([...involvedFeeders, ...switchFeeders]);
301
353
  for (const feeder of feeders) {
302
354
  for (const eq of feeder.getAdditionalGroupedEquipments().values()) {
303
355
  if (!(eq instanceof ACLineSegment_1.ACLineSegment || eq instanceof Switch_1.Switch))
@@ -355,7 +407,7 @@ class ContingencyAnalysisNeplanWestnetz {
355
407
  switchElement.swtch.open = !switchElement.swtch.open;
356
408
  }
357
409
  }
358
- static isNodeSupplied(startNode, terminals, switches, externalNetworkInjections) {
410
+ static isNodeSupplied(startNode, terminals, switches, externalInjections) {
359
411
  var _a, _b;
360
412
  const visitedCN = new Set();
361
413
  const visitedEquipments = new Set();
@@ -395,7 +447,7 @@ class ContingencyAnalysisNeplanWestnetz {
395
447
  visitedEquipments.add(eqId);
396
448
  // Prüfe: Ist das Equipment ein ExternalNetworkInjection?
397
449
  if (eq instanceof ExternalNetworkInjection_1.ExternalNetworkInjection) {
398
- const isExternalNetworkInjection = externalNetworkInjections.some(ext => ext.getUUID() === eq.getUUID());
450
+ const isExternalNetworkInjection = externalInjections.some(ext => ext.getUUID() === eq.getUUID());
399
451
  if (isExternalNetworkInjection)
400
452
  return true;
401
453
  }
@@ -418,7 +470,7 @@ class ContingencyAnalysisNeplanWestnetz {
418
470
  return false;
419
471
  }
420
472
  static findOpenedSwitchesToOtherFeeders(failedConnectivityNodes, failedFeeder, baseModel) {
421
- var _a, _b;
473
+ var _a;
422
474
  const results = new Array();
423
475
  // Relevante Switches finden
424
476
  const switches = [...baseModel.switches.values(), ...baseModel.loadBreakSwitches.values(), ...baseModel.disconnectors.values(), ...baseModel.breakers.values()];
@@ -426,26 +478,33 @@ class ContingencyAnalysisNeplanWestnetz {
426
478
  // Nur nicht verbundene Switsches
427
479
  if (!swtch.open)
428
480
  continue;
429
- const ceFeeder = swtch.getAdditionalEquipmentContainer();
430
481
  const switchTerminals = (_a = Array.from(swtch.terminals.values())) === null || _a === void 0 ? void 0 : _a.filter(it => it.connectivityNode && !failedConnectivityNodes.includes(it.connectivityNode));
431
482
  // sind an der Switch-Kombination ACLineSegments von anderen Abgängen angeschlossen
432
483
  const switchConnectivityNodes = switchTerminals.map(it => it.connectivityNode);
433
- const cnFeeders = switchTerminals.map(it => { var _a, _b, _c; return (_c = (_b = (_a = it.connectivityNode) === null || _a === void 0 ? void 0 : _a.getSubstation()) === null || _b === void 0 ? void 0 : _b.getNormalEnergizingFeeder()) === null || _c === void 0 ? void 0 : _c.getUUID(); });
434
- const switchConductingEquipments = (_b = switchConnectivityNodes.map(it => {
484
+ const feeder = switchConnectivityNodes.map(it => { var _a; return (_a = it.additionalConnectivityNodeContainer) === null || _a === void 0 ? void 0 : _a.getUUID(); }).filter(it => it);
485
+ // Wenn Feederanzahl < 2 ist, dann ist mind. einer ConnectivityNode spannungslos
486
+ if (feeder.length < 2)
487
+ continue;
488
+ const switchConductingEquipments2dArray = switchConnectivityNodes.map(it => {
435
489
  return Array.from(it.terminals.values()).map(it => it.conductingEquipment);
436
- })) === null || _b === void 0 ? void 0 : _b.flat();
437
- cnFeeders.push(...switchConductingEquipments.map(it => { var _a; return (_a = it.getAdditionalEquipmentContainer()) === null || _a === void 0 ? void 0 : _a.getUUID(); }));
438
- if ((ceFeeder === null || ceFeeder === void 0 ? void 0 : ceFeeder.getUUID()) !== failedFeeder.getUUID() && !cnFeeders.includes(failedFeeder.getUUID()))
490
+ });
491
+ // in ein eindimensionales Array überführen
492
+ const flattenSwitchConductingEquipments = switchConductingEquipments2dArray === null || switchConductingEquipments2dArray === void 0 ? void 0 : switchConductingEquipments2dArray.flat();
493
+ // Datenfehler filtern -> Terminal hat kein conductingEquipment und ist keinem Abgang zugeordnet
494
+ const switchConductingEquipments = flattenSwitchConductingEquipments === null || flattenSwitchConductingEquipments === void 0 ? void 0 : flattenSwitchConductingEquipments.filter(it => it && it.getAdditionalEquipmentContainer());
495
+ if ( /*ceFeeder?.getUUID() !== failedFeeder.getUUID() &&*/!feeder.includes(failedFeeder.getUUID()))
439
496
  continue;
497
+ const feeders = feeder.map(it => baseModel.getFeeder(it));
440
498
  results.push({
441
499
  swtch,
442
- terminals: Array.from(swtch.terminals.values()).filter(it => !it.connected)
500
+ terminals: Array.from(swtch.terminals.values()).filter(it => !it.connected),
501
+ feeders
443
502
  });
444
503
  }
445
504
  return results;
446
505
  }
447
506
  static findOpenedTerminalsToOtherFeeders(connectivityNodes, deeenrgizedTerminalUUIDs, failedFeeder, baseModel) {
448
- var _a, _b, _c;
507
+ var _a, _b;
449
508
  // Relevante Terminals finden
450
509
  const results = new Array();
451
510
  for (const terminal of baseModel.terminals.values()) {
@@ -454,25 +513,31 @@ class ContingencyAnalysisNeplanWestnetz {
454
513
  continue;
455
514
  if (deeenrgizedTerminalUUIDs.includes(terminal.getUUID()))
456
515
  continue;
457
- // Verbundungen zu Switches werden übersprungen
458
516
  if (!terminal.conductingEquipment || !terminal.connectivityNode)
459
517
  continue;
518
+ // Verbundungen zu Switches werden übersprungen
460
519
  if (terminal.conductingEquipment instanceof Switch_1.Switch)
461
520
  continue;
521
+ // Verbundungen zu Switches Lasten und Einspeisern werden übersprungen
462
522
  if (terminal.conductingEquipment instanceof EnergySource_1.EnergySource)
463
523
  continue;
464
524
  if (terminal.conductingEquipment instanceof EnergyConsumer_1.EnergyConsumer)
465
525
  continue;
466
526
  if (connectivityNodes.includes(terminal.connectivityNode))
467
527
  continue;
468
- // Nur Terminals, die eine Verbindung zum Feeder des betrachteten ConnectivityNodes
528
+ const connectivityNode = terminal.connectivityNode;
529
+ // Nur Terminals mit einer Verbindung zum Feeder des betrachteten ConnectivityNodes, um offene Trennstellen zwischen anderen Abgängen zu ignorieren
469
530
  const ceFeeder = (_a = terminal.conductingEquipment) === null || _a === void 0 ? void 0 : _a.getAdditionalEquipmentContainer();
470
- const cnFeeder = (_c = (_b = terminal.connectivityNode) === null || _b === void 0 ? void 0 : _b.getSubstation()) === null || _c === void 0 ? void 0 : _c.getNormalEnergizingFeeder();
531
+ const cnFeeder = (_b = connectivityNode.getSubstation()) === null || _b === void 0 ? void 0 : _b.getNormalEnergizingFeeder();
471
532
  if ((ceFeeder === null || ceFeeder === void 0 ? void 0 : ceFeeder.getUUID()) !== failedFeeder.getUUID() && (cnFeeder === null || cnFeeder === void 0 ? void 0 : cnFeeder.getUUID()) !== failedFeeder.getUUID())
472
533
  continue;
534
+ // Offene Trennstellen zu Objekten ohne Feeder werden nicht betrachtet, da spannungslose Querverbindungen zu anderen UAs
535
+ if (!ceFeeder || !cnFeeder)
536
+ continue;
473
537
  results.push({
474
538
  swtch: null,
475
- terminals: new Array(terminal)
539
+ terminals: new Array(terminal),
540
+ feeders: [ceFeeder, cnFeeder]
476
541
  });
477
542
  }
478
543
  return results;
@@ -494,30 +559,30 @@ class ContingencyAnalysisNeplanWestnetz {
494
559
  const lastStep = path[path.length - 1];
495
560
  const lastEquipment = lastStep === null || lastStep === void 0 ? void 0 : lastStep.equipment;
496
561
  // Prüfe auf schaltbaren Node
497
- if ((currentNode.isSwitchableAtAll()) && !visitedSchaltbareNodes.has(nodeId)) {
562
+ if ((currentNode.switchable === WNSwitchTypeKind_1.WNSwitchTypeKind.S || currentNode.switchable === WNSwitchTypeKind_1.WNSwitchTypeKind.E) && !visitedSchaltbareNodes.has(nodeId)) {
498
563
  visitedSchaltbareNodes.add(nodeId);
499
- let matchedTerminal;
564
+ const matchedTerminals = new Array();
500
565
  // Finde den Terminal, der mit dem letzten Equipment verbunden ist
501
- for (const terminal of currentNode.terminals.values()) {
502
- if (lastEquipment && terminal.conductingEquipment === lastEquipment) {
503
- matchedTerminal = terminal;
504
- break;
566
+ if (lastEquipment) {
567
+ for (const terminal of currentNode.terminals.values()) {
568
+ if (terminal.conductingEquipment === lastEquipment) {
569
+ matchedTerminals.push(terminal);
570
+ break;
571
+ }
505
572
  }
506
573
  }
507
- // Fallback: irgendein Terminal (z.B. Startpunkt ist schaltbar)
508
- if (!matchedTerminal && currentNode.terminals.size > 0) {
574
+ else {
575
+ // Ausfallknoten ist schaltbar - füge alle Terminals zur Maßnahme hinzu
509
576
  for (const terminal of currentNode.terminals.values()) {
510
- result.push({
511
- type: 'ViaSchaltbarerNode',
512
- terminal: terminal,
513
- path: [...path]
514
- });
577
+ if (terminal.conductingEquipment !== undefined) {
578
+ matchedTerminals.push(terminal);
579
+ }
515
580
  }
516
581
  }
517
- else {
582
+ for (const terminal of matchedTerminals) {
518
583
  result.push({
519
584
  type: 'ViaSchaltbarerNode',
520
- terminal: matchedTerminal,
585
+ terminal: terminal,
521
586
  path: [...path]
522
587
  });
523
588
  }
@@ -556,6 +621,16 @@ class ContingencyAnalysisNeplanWestnetz {
556
621
  }
557
622
  return result;
558
623
  }
624
+ static invertSwitchStates(obj) {
625
+ obj.forEach(it => {
626
+ if (it.type === 'ViaSwitch') {
627
+ it.switchInstance.open = !it.switchInstance.open;
628
+ }
629
+ if (it.type === 'ViaSchaltbarerNode') {
630
+ it.terminal.connected = !it.terminal.connected;
631
+ }
632
+ });
633
+ }
559
634
  static findWithSmallestDeenergizedNodes(arr) {
560
635
  if (arr.length === 0)
561
636
  return [];
@@ -564,38 +639,69 @@ class ContingencyAnalysisNeplanWestnetz {
564
639
  // Filtere alle Objekte, die genau diese Länge haben
565
640
  return arr.filter(item => !item.cycle && item.resuppledConnectivityNodes.length === maxLength);
566
641
  }
642
+ /** Funktion zur Entnahme n-Elemente aus einem beliebig langen Array
643
+ * @param arr Array mit Objekten
644
+ * @param max Anzahl der zu entnehmenden Objekte aus dem Array */
645
+ /*
646
+ public static getFeedersFromCombo(failedFeeder: Feeder, combos: Array<ICombination>): Array<Feeder> {
647
+ const feederSet = new Set<Feeder>();
648
+ feederSet.add(failedFeeder);
649
+ for (const combo of combos) {
650
+
651
+ combo.terminals.forEach(it => feederSet.add(it.getConnectivityNode().getSubstation()?.getNormalEnergizingFeeder()));
652
+ combo.swtch?.terminals.forEach(it => feederSet.add((it.getConnectivityNode() as ConnectivityNode)?.getSubstation()?.getNormalEnergizingFeeder()));
653
+ }
654
+
655
+ return Array.from(feederSet).filter(it => it !== undefined);
656
+ }
657
+ */
567
658
  static isSwitchCombinationUseful(combo, disconnectedCNs, terminals, switches, externalNetworkInjections) {
568
659
  const resuppliedNodes = new Set();
569
660
  const processedSwitches = new Array();
570
661
  const processedTerminals = new Array();
662
+ let useful = true;
571
663
  for (const switchElement of combo) {
572
664
  for (const terminal of switchElement.terminals) {
573
665
  terminal.connected = !terminal.connected;
666
+ }
667
+ if (switchElement.swtch) {
668
+ switchElement.swtch.open = !switchElement.swtch.open;
669
+ }
670
+ for (const terminal of switchElement.terminals) {
671
+ // terminal.connected = !terminal.connected;
574
672
  processedTerminals.push(terminal);
575
673
  const reachableNodes = ContingencyAnalysisNeplanWestnetz.getSuppliedNodes(disconnectedCNs, terminals, switches, externalNetworkInjections);
576
674
  if (reachableNodes.size === 0)
577
- return false;
675
+ useful = false;
578
676
  if (!ContingencyAnalysisNeplanWestnetz.setContainsElement(resuppliedNodes, reachableNodes)) {
579
- ContingencyAnalysisNeplanWestnetz.resetSwitchStates(processedTerminals, processedSwitches);
580
- return false;
677
+ // ContingencyAnalysisNeplanWestnetz.resetSwitchStates(processedTerminals, processedSwitches);
678
+ useful = false;
581
679
  }
582
680
  reachableNodes.forEach(it => resuppliedNodes.add(it));
681
+ // terminal.connected = !terminal.connected;
583
682
  }
584
683
  if (switchElement.swtch) {
585
- switchElement.swtch.open = !switchElement.swtch.open;
684
+ //switchElement.swtch.open = !switchElement.swtch.open;
586
685
  processedSwitches.push(switchElement.swtch);
587
686
  const reachableNodes = ContingencyAnalysisNeplanWestnetz.getSuppliedNodes(disconnectedCNs, terminals, switches, externalNetworkInjections);
588
687
  if (reachableNodes.size === 0)
589
- return false;
688
+ useful = false;
590
689
  if (!ContingencyAnalysisNeplanWestnetz.setContainsElement(resuppliedNodes, reachableNodes)) {
591
- ContingencyAnalysisNeplanWestnetz.resetSwitchStates(processedTerminals, processedSwitches);
592
- return false;
690
+ // ContingencyAnalysisNeplanWestnetz.resetSwitchStates(processedTerminals, processedSwitches);
691
+ useful = false;
593
692
  }
594
693
  reachableNodes.forEach(it => resuppliedNodes.add(it));
694
+ // switchElement.swtch.open = !switchElement.swtch.open;
695
+ }
696
+ for (const terminal of switchElement.terminals) {
697
+ terminal.connected = !terminal.connected;
698
+ }
699
+ if (switchElement.swtch) {
700
+ switchElement.swtch.open = !switchElement.swtch.open;
595
701
  }
596
702
  }
597
- ContingencyAnalysisNeplanWestnetz.resetSwitchStates(processedTerminals, processedSwitches);
598
- return true;
703
+ //ContingencyAnalysisNeplanWestnetz.resetSwitchStates(processedTerminals, processedSwitches);
704
+ return useful;
599
705
  }
600
706
  static setContainsElement(resuppledNodes, reachableNodes) {
601
707
  const resuppliedMrids = new Set([...resuppledNodes].map(o => o.mrid));