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

com.powsybl.openloadflow.equations.EquationSystem Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2019, 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.openloadflow.equations;

import com.powsybl.commons.PowsyblException;
import com.powsybl.openloadflow.network.ElementType;
import com.powsybl.openloadflow.network.LfElement;
import com.powsybl.openloadflow.network.LfNetwork;
import org.apache.commons.lang3.tuple.Pair;

import java.io.IOException;
import java.io.StringWriter;
import java.io.UncheckedIOException;
import java.io.Writer;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Geoffroy Jamgotchian {@literal }
 */
public class EquationSystem & Quantity, E extends Enum & Quantity> {

    private final Map, Equation> equations = new HashMap<>();

    private final Map, List>> equationsByElement = new HashMap<>();

    private Map, List>> equationTermsByElement;

    private final List> listeners = new ArrayList<>();

    private final VariableSet variableSet;

    private final StateVector stateVector = new StateVector();

    private final EquationSystemIndex index;

    public EquationSystem() {
        this(new VariableSet<>());
    }

    public EquationSystem(VariableSet variableSet) {
        this.variableSet = Objects.requireNonNull(variableSet);
        index = new EquationSystemIndex<>(this);
    }

    public VariableSet getVariableSet() {
        return variableSet;
    }

    public Variable getVariable(int elementNum, V type) {
        return variableSet.getVariable(elementNum, type);
    }

    public StateVector getStateVector() {
        return stateVector;
    }

    public EquationSystemIndex getIndex() {
        return index;
    }

    public Collection> getEquations() {
        return equations.values();
    }

    private void indexTerm(EquationTerm equationTerm) {
        if (equationTermsByElement != null) {
            if (equationTerm.getElementType() != null && equationTerm.getElementNum() != -1) {
                Pair element = Pair.of(equationTerm.getElementType(), equationTerm.getElementNum());
                equationTermsByElement.computeIfAbsent(element, k -> new ArrayList<>())
                        .add(equationTerm);
            }
            for (EquationTerm child : equationTerm.getChildren()) {
                indexTerm(child);
            }
        }
    }

    private void indexAllTerms() {
        if (equationTermsByElement == null) {
            equationTermsByElement = new HashMap<>();
            for (var equation : equations.values()) {
                for (var term : equation.getTerms()) {
                    indexTerm(term);
                }
            }
        }
    }

    void addEquationTerm(EquationTerm equationTerm) {
        indexTerm(equationTerm);
        attach(equationTerm);
    }

    public List> getEquationTerms(ElementType elementType, int elementNum) {
        Objects.requireNonNull(elementType);
        indexAllTerms();
        Pair element = Pair.of(elementType, elementNum);
        return equationTermsByElement.getOrDefault(element, Collections.emptyList());
    }

    public > T getEquationTerm(ElementType elementType, int elementNum, Class clazz) {
        return getEquationTerms(elementType, elementNum)
                .stream()
                .filter(term -> clazz.isAssignableFrom(term.getClass()))
                .map(clazz::cast)
                .findFirst()
                .orElseThrow(() -> new PowsyblException("Equation term not found"));
    }

    public Equation createEquation(LfElement element, E type) {
        Objects.requireNonNull(element);
        Objects.requireNonNull(type);
        if (element.getType() != type.getElementType()) {
            throw new PowsyblException("Incorrect equation type: " + type);
        }
        Pair p = Pair.of(element.getNum(), type);
        Equation equation = equations.get(p);
        if (equation == null) {
            equation = addEquation(p)
                    .setActive(!element.isDisabled());
        }
        return equation;
    }

    public Equation createEquation(int num, E type) {
        Pair p = Pair.of(num, type);
        Equation equation = equations.get(p);
        if (equation == null) {
            equation = addEquation(p);
        }
        return equation;
    }

    public Optional> getEquation(int num, E type) {
        Pair p = Pair.of(num, type);
        return Optional.ofNullable(equations.get(p));
    }

    public boolean hasEquation(int num, E type) {
        Pair p = Pair.of(num, type);
        return equations.containsKey(p);
    }

    private void deindexTerm(EquationTerm term) {
        if (term.getElementType() != null && term.getElementNum() != -1) {
            List> termsForThisElement = equationTermsByElement.get(Pair.of(term.getElementType(), term.getElementNum()));
            if (termsForThisElement != null) {
                termsForThisElement.remove(term);
            }
        }
        for (EquationTerm child : term.getChildren()) {
            deindexTerm(child);
        }
    }

    public Equation removeEquation(int num, E type) {
        Pair p = Pair.of(num, type);
        Equation equation = equations.remove(p);
        if (equation != null) {
            Pair element = Pair.of(type.getElementType(), num);
            equationsByElement.get(element).remove(equation);
            if (equationTermsByElement != null) {
                for (EquationTerm term : equation.getTerms()) {
                    deindexTerm(term);
                }
            }
            equation.setRemoved(); // to ensure it is not used anymore
            notifyEquationChange(equation, EquationEventType.EQUATION_REMOVED);
        }
        return equation;
    }

    private Equation addEquation(Pair p) {
        Equation equation = new Equation<>(p.getLeft(), p.getRight(), EquationSystem.this);
        equations.put(p, equation);
        Pair element = Pair.of(p.getRight().getElementType(), p.getLeft());
        equationsByElement.computeIfAbsent(element, k -> new ArrayList<>())
                .add(equation);
        notifyEquationChange(equation, EquationEventType.EQUATION_CREATED);
        return equation;
    }

    public List> getEquations(ElementType elementType, int elementNum) {
        Objects.requireNonNull(elementType);
        Pair element = Pair.of(elementType, elementNum);
        return equationsByElement.getOrDefault(element, Collections.emptyList());
    }

    public void attach(EquationTerm term) {
        Objects.requireNonNull(term);
        term.setStateVector(stateVector);
    }

    public List getRowNames(LfNetwork network) {
        return index.getSortedVariablesToFind().stream()
                .map(eq -> network.getBus(eq.getElementNum()).getId() + "/" + eq.getType())
                .collect(Collectors.toList());
    }

    public List getColumnNames(LfNetwork network) {
        return index.getSortedEquationsToSolve().stream()
                .map(v -> network.getBus(v.getElementNum()).getId() + "/" + v.getType())
                .collect(Collectors.toList());
    }

    public void addListener(EquationSystemListener listener) {
        Objects.requireNonNull(listener);
        listeners.add(listener);
    }

    public void removeListener(EquationSystemListener listener) {
        listeners.remove(listener);
    }

    void notifyEquationChange(Equation equation, EquationEventType eventType) {
        Objects.requireNonNull(equation);
        Objects.requireNonNull(eventType);
        listeners.forEach(listener -> listener.onEquationChange(equation, eventType));
    }

    void notifyEquationTermChange(EquationTerm term, EquationTermEventType eventType) {
        Objects.requireNonNull(term);
        Objects.requireNonNull(eventType);
        listeners.forEach(listener -> listener.onEquationTermChange(term, eventType));
    }

    public void write(Writer writer, boolean writeInactiveEquations) {
        try {
            for (Equation equation : equations.values().stream().sorted().collect(Collectors.toList())) {
                if (writeInactiveEquations || equation.isActive()) {
                    if (!equation.isActive()) {
                        writer.write("[ ");
                    }
                    equation.write(writer, writeInactiveEquations);
                    if (!equation.isActive()) {
                        writer.write(" ]");
                    }
                    writer.write(System.lineSeparator());
                }
            }
            writer.flush();
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public String writeToString(boolean writeInactiveEquations) {
        try (StringWriter writer = new StringWriter()) {
            write(writer, writeInactiveEquations);
            writer.flush();
            return writer.toString();
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public String writeToString() {
        return writeToString(false);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy