RemoteReactivePowerControlImpl.java

/**
 * Copyright (c) 2021, RTE (http://www.rte-france.com)
 * 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.extensions;

import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.util.trove.TBooleanArrayList;
import com.powsybl.iidm.network.Generator;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.Terminal;
import com.powsybl.iidm.network.extensions.RemoteReactivePowerControl;
import com.powsybl.iidm.network.impl.AbstractMultiVariantIdentifiableExtension;
import com.powsybl.iidm.network.impl.TerminalExt;
import gnu.trove.list.array.TDoubleArrayList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;

/**
 * @author Bertrand Rix {@literal <bertrand.rix at artelys.com>}
 */
public class RemoteReactivePowerControlImpl extends AbstractMultiVariantIdentifiableExtension<Generator> implements RemoteReactivePowerControl {

    private static final Logger LOGGER = LoggerFactory.getLogger(RemoteReactivePowerControlImpl.class);

    private final TDoubleArrayList targetQ;

    private Terminal regulatingTerminal;

    private final TBooleanArrayList enabled;

    public RemoteReactivePowerControlImpl(Generator generator, double targetQ, Terminal regulatingTerminal, boolean enabled) {
        super(generator);
        int variantArraySize = getVariantManagerHolder().getVariantManager().getVariantArraySize();
        this.targetQ = new TDoubleArrayList();
        this.regulatingTerminal = Objects.requireNonNull(regulatingTerminal);
        this.enabled = new TBooleanArrayList(variantArraySize);
        for (int i = 0; i < variantArraySize; i++) {
            this.targetQ.add(targetQ);
            this.enabled.add(enabled);
        }
        if (regulatingTerminal.getVoltageLevel().getParentNetwork() != getExtendable().getParentNetwork()) {
            throw new PowsyblException("Regulating terminal is not in the right Network ("
                    + regulatingTerminal.getVoltageLevel().getParentNetwork().getId() + " instead of "
                    + getExtendable().getParentNetwork().getId() + ")");
        }
        ((TerminalExt) regulatingTerminal).getReferrerManager().register(this);
    }

    @Override
    public double getTargetQ() {
        return targetQ.get(getVariantIndex());
    }

    @Override
    public RemoteReactivePowerControl setTargetQ(double targetQ) {
        this.targetQ.set(getVariantIndex(), targetQ);
        return this;
    }

    @Override
    public RemoteReactivePowerControl setEnabled(boolean enabled) {
        this.enabled.set(getVariantIndex(), enabled);
        return this;
    }

    @Override
    public Terminal getRegulatingTerminal() {
        return regulatingTerminal;
    }

    @Override
    public RemoteReactivePowerControl setRegulatingTerminal(Terminal regulatingTerminal) {
        Objects.requireNonNull(regulatingTerminal);
        checkRegulatingTerminal(regulatingTerminal, getExtendable().getTerminal().getVoltageLevel().getNetwork());
        this.regulatingTerminal = regulatingTerminal;
        return this;
    }

    private static void checkRegulatingTerminal(Terminal regulatingTerminal, Network network) {
        if (regulatingTerminal != null && regulatingTerminal.getVoltageLevel().getNetwork() != network) {
            throw new PowsyblException("regulating terminal is not part of the same network");
        }
    }

    @Override
    public boolean isEnabled() {
        return enabled.get(getVariantIndex());
    }

    @Override
    public void extendVariantArraySize(int initVariantArraySize, int number, int sourceIndex) {
        enabled.ensureCapacity(enabled.size() + number);
        targetQ.ensureCapacity(targetQ.size() + number);
        for (int i = 0; i < number; ++i) {
            enabled.add(enabled.get(sourceIndex));
            targetQ.add(targetQ.get(sourceIndex));
        }
    }

    @Override
    public void reduceVariantArraySize(int number) {
        enabled.remove(enabled.size() - number, number);
        targetQ.remove(targetQ.size() - number, number);
    }

    @Override
    public void deleteVariantArrayElement(int index) {
        // Does nothing
    }

    @Override
    public void allocateVariantArrayElement(int[] indexes, int sourceIndex) {
        for (int index : indexes) {
            targetQ.set(index, targetQ.get(sourceIndex));
            enabled.set(index, enabled.get(sourceIndex));
        }
    }

    @Override
    public void onReferencedRemoval(Terminal removedTerminal) {
        // we cannot set regulating terminal to null because otherwise extension won't be consistent anymore
        // we cannot also as for voltage regulation fallback to a local terminal
        // so we just remove the extension
        LOGGER.warn("Remove 'RemoteReactivePowerControl' extension of generator '{}', because its regulating terminal has been removed",
                getExtendable().getId());
        getExtendable().removeExtension(RemoteReactivePowerControl.class);
    }

    @Override
    public void onReferencedReplacement(Terminal oldReferenced, Terminal newReferenced) {
        if (regulatingTerminal == oldReferenced) {
            regulatingTerminal = newReferenced;
        }
    }

    @Override
    public void cleanup() {
        if (regulatingTerminal != null) {
            ((TerminalExt) regulatingTerminal).getReferrerManager().unregister(this);
        }
    }
}