MultipleNetworkPool.java

/*
 * Copyright (c) 2020, 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/.
 */
package com.powsybl.openrao.util;

import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.VariantManagerConstants;
import com.powsybl.iidm.serde.NetworkSerDe;
import com.powsybl.openrao.commons.OpenRaoException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.atomic.AtomicInteger;

import static com.powsybl.openrao.commons.logs.OpenRaoLoggerProvider.TECHNICAL_LOGS;

/**
 * @author Sebastien Murgey {@literal <sebastien.murgey at rte-france.com>}
 */
public class MultipleNetworkPool extends AbstractNetworkPool {

    private int networkNumberOfClones = 0;

    protected MultipleNetworkPool(Network network, String targetVariant, int parallelism, boolean initClones) {
        super(network, targetVariant, parallelism);
        if (initClones) {
            initClones(parallelism);
        }
    }

    @Override
    protected void cleanVariants(Network networkClone) {
        List<String> variantsToBeRemoved = networkClone.getVariantManager().getVariantIds().stream()
            .filter(variantId -> !variantId.equals(VariantManagerConstants.INITIAL_VARIANT_ID))
            .filter(variantId -> !variantId.equals(stateSaveVariant))
            .toList();
        variantsToBeRemoved.forEach(variantId -> networkClone.getVariantManager().removeVariant(variantId));
    }

    @Override
    public int getNetworkNumberOfClones() {
        // The number of clones includes the original network itself
        return networkNumberOfClones;
    }

    @Override
    public void initClones(int desiredNumberOfClones) {
        int requiredClones = Math.min(getParallelism(), desiredNumberOfClones);
        int clonesToAdd = requiredClones - networkNumberOfClones;

        if (clonesToAdd == 0) {
            return;
        }

        TECHNICAL_LOGS.debug("Filling network pool with {} new cop{} of network {} on variant {}", clonesToAdd, clonesToAdd == 1 ? "y" : "ies", network.getId(), targetVariant);

        String initialVariant = network.getVariantManager().getWorkingVariantId();
        network.getVariantManager().setWorkingVariant(targetVariant);

        AtomicInteger remainingClones = new AtomicInteger(requiredClones);
        List<ForkJoinTask<Network>> tasks = new ArrayList<>();
        try {
            for (int i = networkNumberOfClones; i < requiredClones; i++) {
                int finalI = i;
                tasks.add(this.submit(() -> createNetworkCopy(finalI, remainingClones)));
            }
            for (ForkJoinTask<Network> task : tasks) {
                try {
                    boolean isSuccess = networksQueue.offer(task.get());
                    if (!isSuccess) {
                        throw new OpenRaoException(String.format("Cannot offer copy n��'%d' in pool. Should not happen", networkNumberOfClones + 1));
                    } else {
                        networkNumberOfClones++;
                    }
                } catch (ExecutionException e) {
                    throw new OpenRaoException(e);
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        network.getVariantManager().setWorkingVariant(initialVariant);
    }

    private Network createNetworkCopy(int finalI, AtomicInteger remainingClones) {
        TECHNICAL_LOGS.debug("Copy n��{}", finalI + 1);
        Network copy = NetworkSerDe.copy(network);
        // The initial network working variant is VariantManagerConstants.INITIAL_VARIANT_ID
        // in cloned network, so we need to copy it again.
        copy.getVariantManager().cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, Arrays.asList(stateSaveVariant, workingVariant), true);
        remainingClones.decrementAndGet();
        return copy;
    }
}