All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.zepben.evolve.services.network.tracing.feeder.AssignToLvFeeders.kt Maven / Gradle / Ivy

There is a newer version: 0.24.0rc1
Show newest version
/*
 * Copyright 2022 Zeppelin Bend Pty Ltd
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

package com.zepben.evolve.services.network.tracing.feeder

import com.zepben.evolve.cim.iec61970.base.auxiliaryequipment.AuxiliaryEquipment
import com.zepben.evolve.cim.iec61970.base.core.ConductingEquipment
import com.zepben.evolve.cim.iec61970.base.core.Equipment
import com.zepben.evolve.cim.iec61970.base.core.Terminal
import com.zepben.evolve.cim.iec61970.base.wires.ProtectedSwitch
import com.zepben.evolve.cim.iec61970.infiec61970.feeder.LvFeeder
import com.zepben.evolve.services.network.NetworkService
import com.zepben.evolve.services.network.tracing.traversals.BasicTraversal

/**
 * Convenience class that provides methods for assigning LV feeders on a [NetworkService].
 * Requires that a Feeder have a normalHeadTerminal with associated ConductingEquipment.
 * This class is backed by a [BasicTraversal].
 */
class AssignToLvFeeders {

    private val normalTraversal = AssociatedTerminalTrace.newNormalTrace()
    private val currentTraversal = AssociatedTerminalTrace.newCurrentTrace()
    private lateinit var activeLvFeeder: LvFeeder

    fun run(network: NetworkService) {
        val terminalToAuxEquipment = network.sequenceOf()
            .filter { it.terminal != null }
            .groupBy { it.terminal!!.mRID }

        val lvFeederStartPoints = network.sequenceOf()
            .mapNotNull { lvFeeder ->
                lvFeeder.normalHeadTerminal?.conductingEquipment?.also { headEquipment ->
                    headEquipment.normalFeeders.forEach { feeder ->
                        feeder.addNormalEnergizedLvFeeder(lvFeeder)
                        lvFeeder.addNormalEnergizingFeeder(feeder)
                    }
                }
            }
            .toSet()

        configureStepActions(normalTraversal, terminalToAuxEquipment)
        configureStepActions(currentTraversal, terminalToAuxEquipment)

        configureStopConditions(normalTraversal, lvFeederStartPoints)
        configureStopConditions(currentTraversal, lvFeederStartPoints)

        network.sequenceOf().forEach(::run)
    }

    private fun run(lvFeeder: LvFeeder) {
        activeLvFeeder = lvFeeder

        val headTerminal = lvFeeder.normalHeadTerminal ?: return

        run(normalTraversal, headTerminal)
        run(currentTraversal, headTerminal)
    }

    private fun run(traversal: BasicTraversal, headTerminal: Terminal) {
        traversal.reset()

        traversal.tracker.visit(headTerminal)
        traversal.applyStepActions(headTerminal, false)
        AssociatedTerminalTrace.queueAssociated(traversal, headTerminal)

        traversal.run()
    }

    private fun configureStepActions(traversal: BasicTraversal, terminalToAuxEquipment: Map>) {
        traversal.clearStepActions()
        normalTraversal.addStepAction(processNormal(terminalToAuxEquipment))
        currentTraversal.addStepAction(processCurrent(terminalToAuxEquipment))
    }

    private fun configureStopConditions(traversal: BasicTraversal, lvFeederStartPoints: Set) {
        traversal.clearStopConditions()
        traversal.addStopCondition(reachedEquipment(lvFeederStartPoints))
        traversal.addStopCondition(reachedHv)
    }

    private val reachedEquipment: (Set) -> (Terminal) -> Boolean = { { terminal: Terminal -> it.contains(terminal.conductingEquipment) } }

    private val reachedHv: (Terminal) -> Boolean = { terminal ->
        terminal.conductingEquipment?.baseVoltage?.let { it.nominalVoltage >= 1000 } ?: false
    }

    private fun processNormal(terminalToAuxEquipment: Map>): (Terminal, Boolean) -> Unit =
        { terminal, isStopping ->
            process(
                terminal,
                { eq, feeder ->
                    eq.addContainer(feeder)
                    // Handle classes extending Equipment
                    when (eq) {
                        is ProtectedSwitch ->
                            eq.relayFunctions.flatMap { it.schemes }.mapNotNull { it.system }.forEach { system ->
                                system.addContainer(feeder)
                            }
                    }
                },
                { feeder, eq ->
                    feeder.addEquipment(eq)
                    // Handle classes extending Equipment
                    when (eq) {
                        is ProtectedSwitch ->
                            eq.relayFunctions.flatMap { it.schemes }.mapNotNull { it.system }.forEach { system ->
                                feeder.addEquipment(system)
                            }
                    }
                },
                isStopping,
                terminalToAuxEquipment
            )
        }

    private fun processCurrent(terminalToAuxEquipment: Map>): (Terminal, Boolean) -> Unit =
        { terminal, isStopping ->
            process(
                terminal,
                { eq, feeder ->
                    eq.addCurrentContainer(feeder)
                    // Handle classes extending Equipment
                    when (eq) {
                        is ProtectedSwitch ->
                            eq.relayFunctions.flatMap { it.schemes }.mapNotNull { it.system }.forEach { system ->
                                system.addContainer(feeder)
                            }
                    }
                },
                { feeder, eq ->
                    feeder.addCurrentEquipment(eq)
                    // Handle classes extending Equipment
                    when (eq) {
                        is ProtectedSwitch ->
                            eq.relayFunctions.flatMap { it.schemes }.mapNotNull { it.system }.forEach { system ->
                                feeder.addCurrentEquipment(system)
                            }
                    }
                },
                isStopping,
                terminalToAuxEquipment
            )
        }

    private fun process(
        terminal: Terminal,
        assignLvFeederToEquipment: (Equipment, LvFeeder) -> Unit,
        assignEquipmentToLvFeeder: (LvFeeder, Equipment) -> Unit,
        isStopping: Boolean,
        terminalToAuxEquipment: Map>
    ) {
        if (isStopping && reachedHv(terminal))
            return

        terminalToAuxEquipment[terminal.mRID]?.forEach {
            assignLvFeederToEquipment(it, activeLvFeeder)
            assignEquipmentToLvFeeder(activeLvFeeder, it)
        }

        terminal.conductingEquipment?.let {
            assignLvFeederToEquipment(it, activeLvFeeder)
            assignEquipmentToLvFeeder(activeLvFeeder, it)
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy