Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/main/java/org/gridsuite/filter/FilterLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@
package org.gridsuite.filter;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

/**
* @author Franck Lecuyer <franck.lecuyer at rte-france.com>
*/
public interface FilterLoader {
List<AbstractFilter> getFilters(List<UUID> uuids);

default Optional<AbstractFilter> getFilter(UUID uuid) {
return getFilters(List.of(uuid)).stream().findFirst();
}
}
25 changes: 25 additions & 0 deletions src/main/java/org/gridsuite/filter/api/FilterEvaluator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.gridsuite.filter.api;

import com.powsybl.iidm.network.Network;
import org.gridsuite.filter.api.dto.FiltersWithEquipmentTypes;
import org.gridsuite.filter.identifierlistfilter.FilteredIdentifiables;

/**
* Evaluates one or more filters against a given {@link Network}.
* <p>
* Implementations typically resolve the referenced filters (e.g., via a {@code FilterLoader})
* and return the resulting set of matching identifiables.
* </p>
*/
public interface FilterEvaluator {

/**
* Evaluates the provided filters for the given network.
*
* @param filtersWithEquipmentTypes the filters to evaluate along with their associated equipment types
* @param network the IIDM network used as the evaluation context
* @return the evaluation result containing the filtered identifiables and not found identifiables
* @throws NullPointerException if {@code filtersWithEquipmentTypes} or {@code network} is {@code null}
*/
FilteredIdentifiables evaluateFilters(FiltersWithEquipmentTypes filtersWithEquipmentTypes, Network network);
}
31 changes: 31 additions & 0 deletions src/main/java/org/gridsuite/filter/api/FilterEvaluatorFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.gridsuite.filter.api;

import org.gridsuite.filter.FilterLoader;
import org.gridsuite.filter.internal.DefaultFilterEvaluator;

import java.util.Objects;

/**
* Factory for creating {@link FilterEvaluator} instances.
* <p>
* This is a simple construction utility that wires the default implementation
* ({@link DefaultFilterEvaluator}) with the required dependencies.
* </p>
*/
public final class FilterEvaluatorFactory {
private FilterEvaluatorFactory() {
throw new IllegalStateException("Should not initialize an utility class");
}

/**
* Creates a {@link FilterEvaluator} using the provided {@link FilterLoader}.
*
* @param filterLoader loader used to resolve and load filters during evaluation
* @return a {@link FilterEvaluator} instance
* @throws NullPointerException if {@code filterLoader} is {@code null}
*/
public static FilterEvaluator create(FilterLoader filterLoader) {
Objects.requireNonNull(filterLoader, "Filter loader is not provided while creating filter evaluator");
return new DefaultFilterEvaluator(filterLoader);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Copyright (c) 2025, 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 org.gridsuite.filter.api.dto;

import com.powsybl.iidm.network.IdentifiableType;

import java.util.Set;
import java.util.UUID;

/**
* Store a list of equipment types for a given filter ID
*
* @author Florent MILLOT <florent.millot@rte-france.com>
*/
public record EquipmentTypesByFilterId(UUID filterId, Set<IdentifiableType> equipmentTypes) {
}
42 changes: 42 additions & 0 deletions src/main/java/org/gridsuite/filter/api/dto/FilterAttributes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* 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/.
*/

package org.gridsuite.filter.api.dto;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import org.gridsuite.filter.IFilterAttributes;
import org.gridsuite.filter.utils.EquipmentType;
import org.gridsuite.filter.utils.FilterType;

import java.util.Date;
import java.util.UUID;

/**
* @author Jacques Borsenberger <jacques.borsenberger at rte-france.com>
*/

@Getter
@Setter
@NoArgsConstructor
@SuperBuilder
public class FilterAttributes implements IFilterAttributes {
UUID id;
Date modificationDate;
FilterType type;
EquipmentType equipmentType;
String name;

public FilterAttributes(FilterMetadata filterMetadata, FilterType type, EquipmentType equipmentType) {
id = filterMetadata.getId();
modificationDate = filterMetadata.getModificationDate();
this.type = type;
this.equipmentType = equipmentType;
}
}
17 changes: 17 additions & 0 deletions src/main/java/org/gridsuite/filter/api/dto/FilterMetadata.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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/.
*/

package org.gridsuite.filter.api.dto;

/**
* @author Jacques Borsenberger <jacques.borsenberger at rte-france.com>
*/
public interface FilterMetadata {
java.util.UUID getId();

java.util.Date getModificationDate();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright (c) 2025, 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 org.gridsuite.filter.api.dto;

import java.util.List;

/**
* Store a list of filters and the equipment types that are associated with.
*
* @author Florent MILLOT <florent.millot@rte-france.com>
*/
public record FiltersWithEquipmentTypes(List<FilterAttributes> filters,
List<EquipmentTypesByFilterId> selectedEquipmentTypesByFilter) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.gridsuite.filter.internal;

import com.powsybl.iidm.network.Network;
import org.gridsuite.filter.FilterLoader;
import org.gridsuite.filter.api.FilterEvaluator;
import org.gridsuite.filter.api.dto.FiltersWithEquipmentTypes;
import org.gridsuite.filter.identifierlistfilter.FilteredIdentifiables;
import org.gridsuite.filter.utils.FilterServiceUtils;

/**
* Default {@link FilterEvaluator} implementation.
* <p>
* Delegates the evaluation to {@link FilterServiceUtils} and uses the provided {@link FilterLoader}
* to resolve and load the filters required by the evaluation request.
* </p>
*/
public class DefaultFilterEvaluator implements FilterEvaluator {

private final FilterLoader filterLoader;

/**
* Creates an evaluator using the given filter loader.
*
* @param filterLoader loader used to resolve and load filters during evaluation
*/
public DefaultFilterEvaluator(FilterLoader filterLoader) {
this.filterLoader = filterLoader;
}

/**
* {@inheritDoc}
*/
@Override
public FilteredIdentifiables evaluateFilters(FiltersWithEquipmentTypes filtersWithEquipmentTypes, Network network) {
return FilterServiceUtils.evaluateFiltersWithEquipmentTypes(filtersWithEquipmentTypes, network, filterLoader);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/**
* Copyright (c) 2025, 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 org.gridsuite.filter.internal.utils;

import com.powsybl.iidm.network.IdentifiableType;
import org.gridsuite.filter.expertfilter.ExpertFilter;
import org.gridsuite.filter.expertfilter.expertrule.AbstractExpertRule;
import org.gridsuite.filter.expertfilter.expertrule.CombinatorExpertRule;
import org.gridsuite.filter.expertfilter.expertrule.StringExpertRule;
import org.gridsuite.filter.utils.EquipmentType;
import org.gridsuite.filter.utils.expertfilter.CombinatorType;
import org.gridsuite.filter.utils.expertfilter.FieldType;
import org.gridsuite.filter.utils.expertfilter.OperatorType;

import java.util.List;
import java.util.Set;

import static org.gridsuite.filter.utils.expertfilter.FieldType.*;

/**
* Sometimes, when we apply a filter on a substation or voltage level,
* we actually want the equipments related to these substations or voltage levels.
* This class is used to build these special filters,
* and we can specify which equipment types we are interested into.
* PS : We could have used a mix of expert filters with the operator IS_PART_OF
* but in this case we also need the notFoundIds of the original filter,
* which is not possible because it is different equipment types.
* @author Florent MILLOT <florent.millot at rte-france.com>
*/
public final class FilterWithEquipmentTypesUtils {

private FilterWithEquipmentTypesUtils() {
// Utility class
}

/**
* Create one filter for each equipment type we want to retrieve from a previous filter result.
* @param filterEquipmentType the equipment type of the original filter (substation or voltage level)
* @param filteredEquipmentIDs the filtered equipment IDs of the original filter
* @param subEquipmentTypes the equipment types we want to collect from the original filter result (so the equipments related to filteredEquipmentIDs)
* @return the list of filters
*/
public static List<ExpertFilter> createFiltersForSubEquipments(EquipmentType filterEquipmentType, Set<String> filteredEquipmentIDs, Set<IdentifiableType> subEquipmentTypes) {
return switch (filterEquipmentType) {
case SUBSTATION -> subEquipmentTypes.stream().map(identifiableType -> new ExpertFilter(
null,
null,
EquipmentType.valueOf(identifiableType.name()),
createSubstationRuleByEquipmentType(identifiableType, filteredEquipmentIDs))).toList();
case VOLTAGE_LEVEL -> subEquipmentTypes.stream().map(identifiableType -> new ExpertFilter(
null,
null,
EquipmentType.valueOf(identifiableType.name()),
createVoltageLevelRuleByEquipmentType(identifiableType, filteredEquipmentIDs))).toList();
default ->
throw new UnsupportedOperationException("Unsupported filter equipment type " + filterEquipmentType
+ " : we can only filter sub equipments from substation and voltage level");
};
}

public static AbstractExpertRule createSubstationRuleByEquipmentType(IdentifiableType equipmentType, Set<String> substationIds) {
return switch (equipmentType) {
case LOAD, GENERATOR, SHUNT_COMPENSATOR, STATIC_VAR_COMPENSATOR, BUSBAR_SECTION, BATTERY,
DANGLING_LINE, TWO_WINDINGS_TRANSFORMER, THREE_WINDINGS_TRANSFORMER -> createRuleWithOneField(substationIds, SUBSTATION_ID);
case LINE, HVDC_LINE -> createRuleWithTwoFields(substationIds, SUBSTATION_ID_1, SUBSTATION_ID_2);
default -> throw new UnsupportedOperationException("Unsupported equipment type " + equipmentType);
};
}

public static AbstractExpertRule createVoltageLevelRuleByEquipmentType(IdentifiableType equipmentType, Set<String> voltageLevelIds) {
return switch (equipmentType) {
case LOAD, GENERATOR, SHUNT_COMPENSATOR, STATIC_VAR_COMPENSATOR, BUSBAR_SECTION, BATTERY,
DANGLING_LINE -> createRuleWithOneField(voltageLevelIds, VOLTAGE_LEVEL_ID);
case LINE, HVDC_LINE, TWO_WINDINGS_TRANSFORMER -> createRuleWithTwoFields(voltageLevelIds, VOLTAGE_LEVEL_ID_1, VOLTAGE_LEVEL_ID_2);
case THREE_WINDINGS_TRANSFORMER -> createRuleWithThreeFields(voltageLevelIds, VOLTAGE_LEVEL_ID_1, VOLTAGE_LEVEL_ID_2, VOLTAGE_LEVEL_ID_3);
default -> throw new UnsupportedOperationException("Unsupported equipment type " + equipmentType);
};
}

public static AbstractExpertRule createRuleWithOneField(Set<String> equipmentIds, FieldType field) {
return StringExpertRule.builder()
.operator(OperatorType.IN).field(field)
.values(equipmentIds).build();
}

public static AbstractExpertRule createRuleWithTwoFields(Set<String> equipmentIds, FieldType field1, FieldType field2) {
StringExpertRule rule1 = StringExpertRule.builder()
.operator(OperatorType.IN).field(field1)
.values(equipmentIds).build();
StringExpertRule rule2 = StringExpertRule.builder()
.operator(OperatorType.IN).field(field2)
.values(equipmentIds).build();
return CombinatorExpertRule.builder().combinator(CombinatorType.OR).rules(List.of(rule1, rule2)).build();
}

public static AbstractExpertRule createRuleWithThreeFields(Set<String> equipmentIds, FieldType field1, FieldType field2, FieldType field3) {
StringExpertRule rule1 = StringExpertRule.builder()
.operator(OperatorType.IN).field(field1)
.values(equipmentIds).build();
StringExpertRule rule2 = StringExpertRule.builder()
.operator(OperatorType.IN).field(field2)
.values(equipmentIds).build();
StringExpertRule rule3 = StringExpertRule.builder()
.operator(OperatorType.IN).field(field3)
.values(equipmentIds).build();
return CombinatorExpertRule.builder().combinator(CombinatorType.OR).rules(List.of(rule1, rule2, rule3)).build();
}
}

21 changes: 7 additions & 14 deletions src/main/java/org/gridsuite/filter/utils/FilterServiceUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@

import com.powsybl.iidm.network.IdentifiableType;
import com.powsybl.iidm.network.Network;
import org.gridsuite.filter.*;
import org.gridsuite.filter.AbstractFilter;
import org.gridsuite.filter.FilterLoader;
import org.gridsuite.filter.api.dto.EquipmentTypesByFilterId;
import org.gridsuite.filter.api.dto.FilterAttributes;
import org.gridsuite.filter.api.dto.FiltersWithEquipmentTypes;
import org.gridsuite.filter.expertfilter.ExpertFilter;
import org.gridsuite.filter.identifierlistfilter.*;
import org.gridsuite.filter.internal.utils.FilterWithEquipmentTypesUtils;

import java.util.*;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -40,18 +45,6 @@ public static List<IdentifiableAttributes> getIdentifiableAttributes(AbstractFil
}
}

public static List<FilterEquipments> getFilterEquipmentsFromUuid(Network network, List<UUID> uuids, FilterLoader filterLoader) {
return getFilterEquipmentsFromUuid(network, uuids, filterLoader, Set.of());
}

public static List<FilterEquipments> getFilterEquipmentsFromUuid(Network network, List<UUID> uuids, FilterLoader filterLoader, Set<FilterType> filterTypesToExclude) {
List<AbstractFilter> filters = filterLoader.getFilters(uuids);
return filters.stream()
.filter(filter -> filter != null && !filterTypesToExclude.contains(filter.getType()))
.map(filter -> filter.toFilterEquipments(FilterServiceUtils.getIdentifiableAttributes(filter, network, filterLoader)))
.toList();
}

public static List<FilterEquipments> getFilterEquipmentsFromUuid(Network network, UUID uuid, FilterLoader filterLoader) {
List<AbstractFilter> filters = filterLoader.getFilters(List.of(uuid));
return filters.stream()
Expand Down Expand Up @@ -90,7 +83,7 @@ public static FilteredIdentifiables evaluateFiltersWithEquipmentTypes(FiltersWit
+ " : substation and voltage level filters should contain an equipment types list")
);

// This list is the result of the original filter and so necessarily contais a list of IDs of substations or voltage levels
// This list is the result of the original filter and so necessarily contains a list of IDs of substations or voltage levels
Set<String> filteredEquipmentIds = filteredIdentifiables.equipmentIds().stream().map(IdentifiableAttributes::getId).collect(Collectors.toSet());
List<ExpertFilter> filters = FilterWithEquipmentTypesUtils.createFiltersForSubEquipments(filterEquipmentType,
filteredEquipmentIds,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

package org.gridsuite.filter.utils;
package org.gridsuite.filter.internal.utils;

import com.powsybl.iidm.network.IdentifiableType;
import org.gridsuite.filter.expertfilter.ExpertFilter;
import org.gridsuite.filter.expertfilter.expertrule.AbstractExpertRule;
import org.gridsuite.filter.expertfilter.expertrule.CombinatorExpertRule;
import org.gridsuite.filter.expertfilter.expertrule.StringExpertRule;
import org.gridsuite.filter.utils.EquipmentType;
import org.gridsuite.filter.utils.expertfilter.CombinatorType;
import org.gridsuite.filter.utils.expertfilter.FieldType;
import org.gridsuite.filter.utils.expertfilter.OperatorType;
Expand Down
Loading