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

com.zepben.evolve.cim.iec61970.base.wires.PowerTransformer.kt Maven / Gradle / Ivy

There is a newer version: 0.24.0rc1
Show newest version
/*
 * Copyright 2020 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.cim.iec61970.base.wires

import com.zepben.evolve.cim.iec61968.assetinfo.PowerTransformerInfo
import com.zepben.evolve.cim.iec61968.infiec61968.infassetinfo.TransformerConstructionKind
import com.zepben.evolve.cim.iec61968.infiec61968.infassetinfo.TransformerFunctionKind
import com.zepben.evolve.cim.iec61970.base.core.BaseVoltage
import com.zepben.evolve.cim.iec61970.base.core.ConductingEquipment
import com.zepben.evolve.cim.iec61970.base.core.ConnectivityNode
import com.zepben.evolve.cim.iec61970.base.core.Terminal
import com.zepben.evolve.services.common.extensions.*

/**
 * An electrical device consisting of  two or more coupled windings, with or without a magnetic core, for introducing mutual coupling
 * between electric circuits. Transformers can be used to control voltage and phase shift (active power flow).
 *
 * A power transformer may be composed of separate transformer tanks that need not be identical.
 *
 * A power transformer can be modeled with or without tanks and is intended for use in both balanced and unbalanced representations. A
 * power transformer typically has two terminals, but may have one (grounding), three or more terminals.
 *
 * The inherited association ConductingEquipment.BaseVoltage should not be used.  The association from TransformerEnd to BaseVoltage
 * should be used instead.
 *
 * @property vectorGroup Vector group of the transformer for protective relaying, e.g., Dyn1. For unbalanced transformers, this may not be simply
 * determined from the constituent winding connections and phase angle displacements.
 *
 * The vectorGroup string consists of the following components in the order listed: high voltage winding connection, mid-voltage winding connection(for three
 * winding transformers), phase displacement clock number from 0 to 11,  low voltage winding connection phase displacement clock number from 0 to 11.
 * The winding connections are D(delta), Y(wye), YN(wye with neutral), Z(zigzag), ZN(zigzag with neutral), A(auto transformer). Upper case means the high
 * voltage, lower case mid or low.The high voltage winding always has clock position 0 and is not included in the vector group string.
 * Some examples: YNy0(two winding wye to wye with no phase displacement), YNd11(two winding wye to delta with 330 degrees phase displacement),
 * YNyn0d5(three winding transformer wye with neutral high voltage, wye with neutral mid-voltage and no phase displacement, delta low voltage with 150 degrees
 * displacement).
 *
 * Phase displacement is defined as the angular difference between the phasors representing the voltages between the neutral point(real or imaginary) and the
 * corresponding terminals of two windings, a positive sequence voltage system being applied to the high-voltage terminals, following each other in
 * alphabetical sequence if they are lettered, or in numerical sequence if they are numbered: the phasors are assumed to rotate in a counter-clockwise sense.
 *
 * @property primaryVoltage Holds the primary voltage value for a transformer.
 *
 * @property transformerUtilisation The fraction of the transformer’s normal capacity (nameplate rating) that is in use. It may be expressed as the result of
 * the calculation S/Sn, where S = Load on Transformer (in VA), Sn = Transformer Nameplate Rating (in VA). A value of NaN signifies the data is missing/unknown.
 *
 * @property constructionKind The construction kind of this transformer.
 *
 * @property function The function of this transformer.
 *
 * @property assetInfo Set of power transformer data, from an equipment library or data sheet. Note that when this is set to a [PowerTransformerInfo], the
 * corresponding [TransformerEnd]s cannot be associated directly with a [TransformerStarImpedance], as the existence of [assetInfo] indicates that impedance
 * values are calculated from the data sheet information.
 */
class PowerTransformer @JvmOverloads constructor(mRID: String = "") : ConductingEquipment(mRID) {

    val primaryVoltage: Int?
        get() = if (ends.isEmpty()) baseVoltage?.nominalVoltage else ends[0].baseVoltage?.nominalVoltage ?: ends[0].ratedU

    private var _powerTransformerEnds: MutableList? = null
    var vectorGroup: VectorGroup = VectorGroup.UNKNOWN
    var transformerUtilisation: Double? = null
    var constructionKind: TransformerConstructionKind = TransformerConstructionKind.unknown
    var function: TransformerFunctionKind = TransformerFunctionKind.other

    override var assetInfo: PowerTransformerInfo? = null
        set(value) {
            if (value != null) {
                val invalidEnds = ends.filter { it.starImpedance != null }
                require(invalidEnds.isEmpty()) {
                    "Unable to use ${value.typeNameAndMRID()} for ${typeNameAndMRID()} because the following associated ends have a direct link to a star impedance: ${invalidEnds.map { it.typeNameAndMRID() }}."
                }
            }
            field = value
        }

    /**
     * The PowerTransformerEnd's for this PowerTransformer. The returned collection is read only.
     */
    val ends: List get() = _powerTransformerEnds.asUnmodifiable()

    /**
     * Get the number of entries in the [PowerTransformerEnd] collection.
     */
    fun numEnds(): Int = _powerTransformerEnds?.size ?: 0

    /**
     * Get a [PowerTransformerEnd] of this [PowerTransformer] by its [PowerTransformerEnd.mRID]
     *
     * @param mRID the mRID of the required [PowerTransformerEnd]
     * @return The [PowerTransformerEnd] with the specified [mRID] if it exists, otherwise null
     */
    fun getEnd(mRID: String): PowerTransformerEnd? = _powerTransformerEnds.getByMRID(mRID)

    /**
     * Get a [PowerTransformerEnd] of this [PowerTransformer] by its [PowerTransformerEnd.endNumber]
     *
     * @param endNumber the end number of the required [PowerTransformerEnd]
     * @return The [PowerTransformerEnd] with the specified [endNumber] if it exists, otherwise null
     */
    fun getEnd(endNumber: Int): PowerTransformerEnd? = _powerTransformerEnds?.firstOrNull { it.endNumber == endNumber }

    /**
     * Get a [PowerTransformerEnd] of this [PowerTransformer] by its [PowerTransformerEnd.terminal]
     *
     * @param terminal the terminal of the required [PowerTransformerEnd]
     * @return The [PowerTransformerEnd] with the specified [terminal] if it exists, otherwise null
     */
    fun getEnd(terminal: Terminal): PowerTransformerEnd? = _powerTransformerEnds?.firstOrNull { it.terminal == terminal }

    /**
     * Get a [PowerTransformerEnd] of this [PowerTransformer] by its [Terminal] [ConnectivityNode].
     *
     * @param connectivityNode the [ConnectivityNode] of the required [PowerTransformerEnd]
     * @return The [PowerTransformerEnd] with the specified [Terminal] if it exists, otherwise null
     */
    fun getEnd(connectivityNode: ConnectivityNode): PowerTransformerEnd? =
        _powerTransformerEnds?.firstOrNull { it.terminal?.connectivityNode == connectivityNode }

    /**
     * Get [BaseVoltage] of [PowerTransformerEnd] by its end number.
     *
     * @param endNumber the end number of the required [PowerTransformerEnd]
     * @return The [BaseVoltage] of the [PowerTransformerEnd] with the specified 'endNumber' if it exists, otherwise null
     */
    fun getBaseVoltage(endNumber: Int): BaseVoltage? = getEnd(endNumber)?.baseVoltage

    /**
     * Get [BaseVoltage] of [PowerTransformerEnd] by its [Terminal].
     *
     * @param terminal the [Terminal] of the required [PowerTransformerEnd]
     * @return The [BaseVoltage] of the [PowerTransformerEnd] with the specified 'terminal' if it exists, otherwise null
     */
    fun getBaseVoltage(terminal: Terminal): BaseVoltage? = getEnd(terminal)?.baseVoltage

    /**
     * Get [BaseVoltage] of [PowerTransformerEnd] by its [ConnectivityNode].
     *
     * @param connectivityNode the [ConnectivityNode] of the required [PowerTransformerEnd]
     * @return The [BaseVoltage] of the [PowerTransformerEnd] with the specified 'connectivityNode' if it exists, otherwise null
     */
    fun getBaseVoltage(connectivityNode: ConnectivityNode): BaseVoltage? = getEnd(connectivityNode)?.baseVoltage

    /**
     * Add a [PowerTransformerEnd] to this [PowerTransformer]
     *
     * If [PowerTransformerEnd.endNumber] is 0 [end] will receive an endNumber of [numEnds] + 1 when added.
     * @throws IllegalStateException if the [PowerTransformerEnd] references another [PowerTransformer] or if a [PowerTransformerEnd] with
     *         the same endNumber already exists.
     * @return This [PowerTransformer] for fluent use
     */
    fun addEnd(end: PowerTransformerEnd): PowerTransformer {
        if (validateEnd(end)) return this

        if (end.endNumber == 0)
            end.endNumber = numEnds() + 1

        require(getEnd(end.endNumber) == null) { "Unable to add ${end.typeNameAndMRID()} to ${typeNameAndMRID()}. A ${getEnd(end.endNumber)!!.typeNameAndMRID()} already exists with endNumber ${end.endNumber}." }

        _powerTransformerEnds = _powerTransformerEnds ?: mutableListOf()
        _powerTransformerEnds!!.add(end)
        _powerTransformerEnds!!.sortBy { it.endNumber }

        return this
    }

    fun removeEnd(end: PowerTransformerEnd): Boolean {
        val ret = _powerTransformerEnds.safeRemove(end)
        if (_powerTransformerEnds.isNullOrEmpty()) _powerTransformerEnds = null
        return ret
    }

    fun clearEnds(): PowerTransformer {
        _powerTransformerEnds = null
        return this
    }

    private fun validateEnd(end: PowerTransformerEnd): Boolean {
        if (validateReference(end, ::getEnd, "A PowerTransformerEnd"))
            return true

        if (end.powerTransformer == null)
            end.powerTransformer = this

        require(end.powerTransformer === this) {
            "${end.typeNameAndMRID()} `powerTransformer` property references ${end.powerTransformer!!.typeNameAndMRID()}, expected ${typeNameAndMRID()}."
        }
        return false
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy