SubstationImpl.java

/**
 * Copyright (c) 2016, All partners of the iTesla project (http://www.itesla-project.eu/consortium)
 * 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 http://mozilla.org/MPL/2.0/.
 * SPDX-License-Identifier: MPL-2.0
 */
package com.powsybl.iidm.network.impl;

import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.*;
import com.powsybl.commons.ref.Ref;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Stream;

/**
 *
 * @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
 */
class SubstationImpl extends AbstractIdentifiable<Substation> implements Substation {

    private Country country;

    private String tso;

    private final Ref<NetworkImpl> networkRef;
    private final Ref<SubnetworkImpl> subnetworkRef;

    private final Set<String> geographicalTags = new LinkedHashSet<>();

    private final Set<VoltageLevelExt> voltageLevels = new LinkedHashSet<>();

    private final Set<OverloadManagementSystemImpl> overloadManagementSystems = new LinkedHashSet<>();

    private boolean removed = false;

    SubstationImpl(String id, String name, boolean fictitious, Country country, String tso, Ref<NetworkImpl> networkRef, Ref<SubnetworkImpl> subnetworkRef) {
        super(id, name, fictitious);
        this.country = country;
        this.tso = tso;
        this.networkRef = networkRef;
        this.subnetworkRef = subnetworkRef;
    }

    Ref<SubnetworkImpl> getSubnetworkRef() {
        return subnetworkRef;
    }

    @Override
    public ContainerType getContainerType() {
        return ContainerType.SUBSTATION;
    }

    @Override
    public Optional<Country> getCountry() {
        return Optional.ofNullable(country);
    }

    @Override
    public Country getNullableCountry() {
        return country;
    }

    @Override
    public SubstationImpl setCountry(Country country) {
        String oldValue = Optional.ofNullable(this.country).map(Enum::toString).orElse("");
        this.country = country;
        getNetwork().getListeners().notifyUpdate(this, "country", oldValue, Optional.ofNullable(country).map(Enum::toString).orElse(""));
        return this;
    }

    @Override
    public String getTso() {
        return tso;
    }

    @Override
    public SubstationImpl setTso(String tso) {
        String oldValue = this.tso;
        this.tso = tso;
        getNetwork().getListeners().notifyUpdate(this, "tso", oldValue, tso);
        return this;
    }

    @Override
    public NetworkImpl getNetwork() {
        if (removed) {
            throw new PowsyblException("Cannot access network of removed substation " + id);
        }
        return networkRef.get();
    }

    protected Ref<NetworkImpl> getNetworkRef() {
        return networkRef;
    }

    @Override
    public Network getParentNetwork() {
        return Optional.ofNullable((Network) subnetworkRef.get()).orElse(getNetwork());
    }

    void addVoltageLevel(VoltageLevelExt voltageLevel) {
        voltageLevels.add(voltageLevel);
    }

    @Override
    public VoltageLevelAdderImpl newVoltageLevel() {
        return new VoltageLevelAdderImpl(this);
    }

    @Override
    public Iterable<VoltageLevel> getVoltageLevels() {
        return Collections.unmodifiableSet(voltageLevels);
    }

    @Override
    public Stream<VoltageLevel> getVoltageLevelStream() {
        return voltageLevels.stream().map(Function.identity());
    }

    @Override
    public TwoWindingsTransformerAdderImpl newTwoWindingsTransformer() {
        return new TwoWindingsTransformerAdderImpl(this);
    }

    @Override
    public TwoWindingsTransformerAdderImpl newTwoWindingsTransformer(TwoWindingsTransformer twoWindingsTransformer) {
        return new TwoWindingsTransformerAdderImpl(this, twoWindingsTransformer);
    }

    @Override
    public Iterable<TwoWindingsTransformer> getTwoWindingsTransformers() {
        return FluentIterable.from(voltageLevels)
                .transformAndConcat(vl -> vl.getConnectables(TwoWindingsTransformer.class))
                .toSet();
    }

    @Override
    public Stream<TwoWindingsTransformer> getTwoWindingsTransformerStream() {
        return voltageLevels.stream().flatMap(vl -> vl.getConnectableStream(TwoWindingsTransformer.class)).distinct();
    }

    @Override
    public int getTwoWindingsTransformerCount() {
        return Ints.checkedCast(getTwoWindingsTransformerStream()
                .count());
    }

    @Override
    public ThreeWindingsTransformerAdderImpl newThreeWindingsTransformer() {
        return new ThreeWindingsTransformerAdderImpl(this);
    }

    @Override
    public Iterable<ThreeWindingsTransformer> getThreeWindingsTransformers() {
        return FluentIterable.from(voltageLevels)
                .transformAndConcat(vl -> vl.getConnectables(ThreeWindingsTransformer.class))
                .toSet();
    }

    @Override
    public Stream<ThreeWindingsTransformer> getThreeWindingsTransformerStream() {
        return voltageLevels.stream().flatMap(vl -> vl.getConnectableStream(ThreeWindingsTransformer.class)).distinct();
    }

    @Override
    public int getThreeWindingsTransformerCount() {
        return Ints.checkedCast(getThreeWindingsTransformerStream()
                .count());
    }

    void addOverloadManagementSystem(OverloadManagementSystemImpl overloadManagementSystem) {
        overloadManagementSystems.add(overloadManagementSystem);
    }

    @Override
    public OverloadManagementSystemAdderImpl newOverloadManagementSystem() {
        return new OverloadManagementSystemAdderImpl(this);
    }

    @Override
    public Iterable<OverloadManagementSystem> getOverloadManagementSystems() {
        return Collections.unmodifiableSet(overloadManagementSystems);
    }

    @Override
    public Stream<OverloadManagementSystem> getOverloadManagementSystemStream() {
        return overloadManagementSystems.stream().map(Function.identity());
    }

    @Override
    public int getOverloadManagementSystemCount() {
        return Ints.checkedCast(getOverloadManagementSystemStream().count());
    }

    @Override
    public Set<String> getGeographicalTags() {
        return Collections.unmodifiableSet(geographicalTags);
    }

    @Override
    public Substation addGeographicalTag(String tag) {
        if (tag == null) {
            throw new ValidationException(this, "geographical tag is null");
        }
        Set<String> oldGeographicalTags = new LinkedHashSet<>(geographicalTags);
        if (geographicalTags.add(tag)) {
            getNetwork().getListeners().notifyUpdate(this, "geographicalTags", oldGeographicalTags, geographicalTags);
        }
        return this;
    }

    @Override
    protected String getTypeDescription() {
        return "Substation";
    }

    @Override
    public void remove() {
        Substations.checkRemovability(this);

        NetworkImpl network = getNetwork();
        network.getListeners().notifyBeforeRemoval(this);

        Set<VoltageLevelExt> vls = new HashSet<>(voltageLevels);
        for (VoltageLevelExt vl : vls) {
            // Remove all branches, transformers and HVDC lines
            List<Connectable> connectables = Lists.newArrayList(vl.getConnectables());
            for (Connectable connectable : connectables) {
                IdentifiableType type = connectable.getType();
                if (VoltageLevels.MULTIPLE_TERMINALS_CONNECTABLE_TYPES.contains(type)) {
                    connectable.remove();
                } else if (type == IdentifiableType.HVDC_CONVERTER_STATION) {
                    HvdcLine hvdcLine = getNetwork().getHvdcLine((HvdcConverterStation) connectable);
                    if (hvdcLine != null) {
                        hvdcLine.remove();
                    }
                }
            }

            // Then remove the voltage level (bus, switches and injections) from the network
            vl.remove();
        }

        // Remove the overload management systems
        removeOverloadManagementSystems();

        // Remove this substation from the network
        network.getIndex().remove(this);

        network.getListeners().notifyAfterRemoval(id);
        removed = true;
    }

    void removeOverloadManagementSystems() {
        overloadManagementSystems.forEach(OverloadManagementSystem::remove);
    }

    void remove(OverloadManagementSystemImpl overloadManagementSystem) {
        Objects.requireNonNull(overloadManagementSystem);
        overloadManagementSystems.remove(overloadManagementSystem);
    }

    void remove(VoltageLevelExt voltageLevelExt) {
        Objects.requireNonNull(voltageLevelExt);
        voltageLevels.remove(voltageLevelExt);
    }
}