Skip to content

Commit 9b144e5

Browse files
authored
Implementing an Epsilon in Digital Filtering (#84)
* Implementing an Epsilon in Digital Filtering * add TU * Remove number pridicate and add comment * parse expression to double --------- Signed-off-by: TOURI ANIS <[email protected]>
1 parent e9022ae commit 9b144e5

File tree

3 files changed

+78
-29
lines changed

3 files changed

+78
-29
lines changed

src/main/java/org/gridsuite/shortcircuit/server/repositories/specifications/SpecificationUtils.java

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
package org.gridsuite.shortcircuit.server.repositories.specifications;
99

10+
import jakarta.persistence.criteria.Expression;
1011
import jakarta.persistence.criteria.Path;
1112
import jakarta.persistence.criteria.Root;
1213
import org.gridsuite.shortcircuit.server.dto.ResourceFilter;
@@ -45,16 +46,55 @@ public static <X> Specification<X> startsWith(String field, String value) {
4546
return (root, cq, cb) -> cb.like(cb.upper(getColumnPath(root, field)), EscapeCharacter.DEFAULT.escape(value).toUpperCase() + "%", EscapeCharacter.DEFAULT.getEscapeCharacter());
4647
}
4748

48-
public static <X> Specification<X> notEqual(String field, Double value) {
49-
return (root, cq, cb) -> cb.notEqual(getColumnPath(root, field), value);
49+
/**
50+
* Returns a specification where the field value is not equal within the given tolerance.
51+
*
52+
* @param <X> Entity type.
53+
* @param field Field name.
54+
* @param value Comparison value.
55+
* @param tolerance Tolerance range.
56+
* @return Specification of non-equality with tolerance.
57+
*/
58+
public static <X> Specification<X> notEqual(String field, Double value, Double tolerance) {
59+
return (root, cq, cb) -> {
60+
Expression<Double> doubleExpression = getColumnPath(root, field).as(Double.class);
61+
return cb.or(
62+
cb.greaterThan(doubleExpression, value + tolerance),
63+
cb.lessThan(doubleExpression, value - tolerance)
64+
);
65+
};
5066
}
5167

52-
public static <X> Specification<X> lessThanOrEqual(String field, Double value) {
53-
return (root, cq, cb) -> cb.lessThanOrEqualTo(getColumnPath(root, field), value);
68+
/**
69+
* Returns a specification where the field value is less than or equal to the value plus tolerance.
70+
*
71+
* @param <X> Entity type.
72+
* @param field Field name.
73+
* @param value Comparison value.
74+
* @param tolerance Tolerance range.
75+
* @return Specification of less than or equal with tolerance.
76+
*/
77+
public static <X> Specification<X> lessThanOrEqual(String field, Double value, Double tolerance) {
78+
return (root, cq, cb) -> {
79+
Expression<Double> doubleExpression = getColumnPath(root, field).as(Double.class);
80+
return cb.lessThanOrEqualTo(doubleExpression, value + tolerance);
81+
};
5482
}
5583

56-
public static <X> Specification<X> greaterThanOrEqual(String field, Double value) {
57-
return (root, cq, cb) -> cb.greaterThanOrEqualTo(getColumnPath(root, field), value);
84+
/**
85+
* Returns a specification where the field value is greater than or equal to the value minus tolerance.
86+
*
87+
* @param <X> Entity type.
88+
* @param field Field name.
89+
* @param value Comparison value.
90+
* @param tolerance Tolerance range.
91+
* @return Specification of greater than or equal with tolerance.
92+
*/
93+
public static <X> Specification<X> greaterThanOrEqual(String field, Double value, Double tolerance) {
94+
return (root, cq, cb) -> {
95+
Expression<Double> doubleExpression = getColumnPath(root, field).as(Double.class);
96+
return cb.greaterThanOrEqualTo(doubleExpression, value - tolerance);
97+
};
5898
}
5999

60100
public static <X> Specification<X> isNotEmpty(String field) {
@@ -116,21 +156,23 @@ private static <X> Specification<X> appendTextFilterToSpecification(Specificatio
116156

117157
@NotNull
118158
private static <X> Specification<X> appendNumberFilterToSpecification(Specification<X> specification, ResourceFilter resourceFilter) {
119-
Specification<X> completedSpecification = specification;
120-
121-
// We need to cast it as String before and use .valueOf to be able to works with integers
122-
Double value = Double.valueOf(resourceFilter.value().toString());
159+
final double tolerence = 0.00001; // tolerance for comparison
160+
String value = resourceFilter.value().toString();
161+
return createNumberPredicate(specification, resourceFilter, value, tolerence);
162+
}
123163

164+
private static <X> Specification<X> createNumberPredicate(Specification<X> specification, ResourceFilter resourceFilter, String value, double tolerance) {
165+
Specification<X> completedSpecification = specification;
166+
Double valueDouble = Double.valueOf(value);
124167
switch (resourceFilter.type()) {
125168
case NOT_EQUAL ->
126-
completedSpecification = completedSpecification.and(notEqual(resourceFilter.column(), value));
169+
completedSpecification = specification.and(notEqual(resourceFilter.column(), valueDouble, tolerance));
127170
case LESS_THAN_OR_EQUAL ->
128-
completedSpecification = completedSpecification.and(lessThanOrEqual(resourceFilter.column(), value));
171+
completedSpecification = specification.and(lessThanOrEqual(resourceFilter.column(), valueDouble, tolerance));
129172
case GREATER_THAN_OR_EQUAL ->
130-
completedSpecification = completedSpecification.and(greaterThanOrEqual(resourceFilter.column(), value));
173+
completedSpecification = specification.and(greaterThanOrEqual(resourceFilter.column(), valueDouble, tolerance));
131174
default -> throwBadFilterTypeException(resourceFilter.type(), resourceFilter.dataType());
132175
}
133-
134176
return completedSpecification;
135177
}
136178

@@ -159,7 +201,7 @@ private static <X, Y> Path<Y> getColumnPath(Root<X> root, String dotSeparatedFie
159201
}
160202

161203
// will be overloaded by Spring as InvalidDataAccessApiUsageException
162-
private static void throwBadFilterTypeException(ResourceFilter.Type filterType, ResourceFilter.DataType dataType) {
204+
private static void throwBadFilterTypeException(ResourceFilter.Type filterType, ResourceFilter.DataType dataType) throws IllegalArgumentException {
163205
throw new IllegalArgumentException("The filter type " + filterType + " is not supported with the data type " + dataType);
164206
}
165207
}

src/test/java/org/gridsuite/shortcircuit/server/repositories/FaultResultRepositoryTest.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -353,12 +353,7 @@ private Stream<Arguments> provideNotEqualFilters() {
353353
List.of(
354354
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.NOT_EQUAL, 47.3, "current"),
355355
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.NOT_EQUAL, 49.3, "current")),
356-
List.of(faultResultEntity1)),
357-
Arguments.of(
358-
resultMagnitudeEntity,
359-
List.of(
360-
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.NOT_EQUAL, 2, "nbLimitViolations")),
361-
List.of(faultResultEntity2))
356+
List.of(faultResultEntity1))
362357
);
363358
}
364359

src/test/java/org/gridsuite/shortcircuit/server/repositories/FeederResultRepositoryTest.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // improve tests speed as we only read DB
4949
class FeederResultRepositoryTest {
5050

51-
static final FeederResult FEEDER_RESULT_1 = new MagnitudeFeederResult("A_CONN_ID_1", 22.17);
51+
static final FeederResult FEEDER_RESULT_1 = new MagnitudeFeederResult("A_CONN_ID_1", 22.179775880774197);
5252
static final FeederResult FEEDER_RESULT_2 = new MagnitudeFeederResult("A_CONN_ID_2", 18.57);
5353
static final FeederResult FEEDER_RESULT_3 = new MagnitudeFeederResult("B_CONN_ID_3", 53.94);
5454
static final FeederResult FEEDER_RESULT_4 = new FortescueFeederResult("A_CONN_ID_4", new FortescueValue(45.328664779663086, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN));
@@ -261,7 +261,7 @@ private Stream<Arguments> provideNotEqualNestedFieldsFilters() {
261261
Arguments.of(
262262
resultFortescueEntity,
263263
List.of(
264-
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.NOT_EQUAL, 45.328664779663086, "fortescueCurrent.positiveMagnitude")),
264+
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.NOT_EQUAL, 45.32867, "fortescueCurrent.positiveMagnitude")),
265265
feederResultEntityFortescueList.stream().filter(feederResultEntity -> !((Double) feederResultEntity.getFortescueCurrent().getPositiveMagnitude()).equals(45.328664779663086)).toList()),
266266
Arguments.of(
267267
resultFortescueEntity,
@@ -284,8 +284,8 @@ private Stream<Arguments> provideLessThanOrEqualFilters() {
284284
Arguments.of(
285285
resultMagnitudeEntity,
286286
List.of(
287-
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.LESS_THAN_OR_EQUAL, 22.17, "current")),
288-
feederResultEntityMagnitudeList.stream().filter(feederResultEntity -> Double.compare(feederResultEntity.getCurrent(), 22.17) <= 0).toList()),
287+
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.LESS_THAN_OR_EQUAL, 22.17978, "current")),
288+
feederResultEntityMagnitudeList.stream().filter(feederResultEntity -> Double.compare(feederResultEntity.getCurrent(), 22.179775880774197) <= 0).toList()),
289289
Arguments.of(
290290
resultMagnitudeEntity,
291291
List.of(
@@ -301,7 +301,13 @@ private Stream<Arguments> provideLessThanOrEqualFilters() {
301301
List.of(
302302
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.LESS_THAN_OR_EQUAL, 22.17, "current"),
303303
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.LESS_THAN_OR_EQUAL, 53.94, "current")),
304-
feederResultEntityMagnitudeList.stream().filter(feederResultEntity -> Double.compare(feederResultEntity.getCurrent(), 22.17) <= 0).toList())
304+
feederResultEntityMagnitudeList.stream().filter(feederResultEntity -> Double.compare(feederResultEntity.getCurrent(), 22.17) <= 0).toList()),
305+
Arguments.of(
306+
resultMagnitudeEntity,
307+
List.of(
308+
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.LESS_THAN_OR_EQUAL, 22., "current"),
309+
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.LESS_THAN_OR_EQUAL, 53, "current")),
310+
feederResultEntityMagnitudeList.stream().filter(feederResultEntity -> Double.compare(feederResultEntity.getCurrent(), 22) <= 0).toList())
305311
);
306312
}
307313

@@ -310,8 +316,8 @@ private Stream<Arguments> provideGreaterThanOrEqualFilters() {
310316
Arguments.of(
311317
resultMagnitudeEntity,
312318
List.of(
313-
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.GREATER_THAN_OR_EQUAL, 22.17, "current")),
314-
feederResultEntityMagnitudeList.stream().filter(feederResultEntity -> Double.compare(feederResultEntity.getCurrent(), 22.17) >= 0).toList()),
319+
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.GREATER_THAN_OR_EQUAL, 22.17976, "current")),
320+
feederResultEntityMagnitudeList.stream().filter(feederResultEntity -> Double.compare(feederResultEntity.getCurrent(), 22.179775880774197) >= 0).toList()),
315321
Arguments.of(
316322
resultMagnitudeEntity,
317323
List.of(
@@ -327,7 +333,13 @@ private Stream<Arguments> provideGreaterThanOrEqualFilters() {
327333
List.of(
328334
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.GREATER_THAN_OR_EQUAL, 22.17, "current"),
329335
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.GREATER_THAN_OR_EQUAL, 53.94, "current")),
330-
feederResultEntityMagnitudeList.stream().filter(feederResultEntity -> Double.compare(feederResultEntity.getCurrent(), 53.94) >= 0).toList())
336+
feederResultEntityMagnitudeList.stream().filter(feederResultEntity -> Double.compare(feederResultEntity.getCurrent(), 53.94) >= 0).toList()),
337+
Arguments.of(
338+
resultMagnitudeEntity,
339+
List.of(
340+
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.GREATER_THAN_OR_EQUAL, 22, "current"),
341+
new ResourceFilter(ResourceFilter.DataType.NUMBER, ResourceFilter.Type.GREATER_THAN_OR_EQUAL, 53, "current")),
342+
feederResultEntityMagnitudeList.stream().filter(feederResultEntity -> Double.compare(feederResultEntity.getCurrent(), 53) >= 0).toList())
331343
);
332344
}
333345

0 commit comments

Comments
 (0)