Skip to content

Commit 39674da

Browse files
committed
Update comparison bsuiness logic
1 parent fbe7ad3 commit 39674da

File tree

3 files changed

+114
-15
lines changed

3 files changed

+114
-15
lines changed

app/save-and-restore/util/src/main/java/org/phoebus/saveandrestore/util/SnapshotUtil.java

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.phoebus.saveandrestore.util;
22

3+
import org.epics.vtype.VNumber;
34
import org.epics.vtype.VType;
45
import org.phoebus.applications.saveandrestore.model.CompareResult;
56
import org.phoebus.applications.saveandrestore.model.ConfigPv;
@@ -39,8 +40,6 @@ public class SnapshotUtil {
3940

4041
private final int connectionTimeout = Preferences.connectionTimeout;
4142

42-
private final int writeTimeout = Preferences.writeTimeout;
43-
4443
private final ExecutorService executorService = Executors.newCachedThreadPool();
4544

4645
public SnapshotUtil() {
@@ -277,14 +276,15 @@ public void release() {
277276
/**
278277
* Performs comparison between PV values to determine equality. The idea is to generate a return value mimicking
279278
* the save-and-restore snapshot view, i.e. to show both stored and live values, plus an indication of equality.
280-
* The comparison algorithm is the same as employed by the snapshot view.
279+
* Caller must specify a {@link PvCompareMode} to indicate if the provided <code>tolerance</code> should be used
280+
* as relative or absolute tolerance.
281281
*
282282
* @param savedSnapshotItems A list if {@link SnapshotItem}s as pulled from a stored snapshot.
283-
* @param tolerance A tolerance (must be >=0) value used in the comparison. Comparisons use the tolerance
284-
* value for a relative comparison.
283+
* @param tolerance A tolerance (must be >=0) value used in the comparison.
284+
* @param comparisonMode Determines if comparison is relative or absolute.
285285
* @return A list of {@link CompareResult}s, one for each {@link SnapshotItem} in the provided input. Note though that
286286
* if the comparison evaluates to equal, then the actual live and stored value are not added to the {@link CompareResult}
287-
* objects in order to avoid handling/transferring potentially large amounts of data.
287+
* objects in order to avoid handling/transferring potentially large amounts of data (e.g. large arrays).
288288
*/
289289
public List<CompareResult> comparePvs(final List<SnapshotItem> savedSnapshotItems,
290290
double tolerance,
@@ -305,13 +305,28 @@ public List<CompareResult> comparePvs(final List<SnapshotItem> savedSnapshotItem
305305
if (liveSnapshotItem == null) {
306306
throw new RuntimeException("Unable to match stored PV " + savedItem.getConfigPv().getPvName() + " in list of live PVs");
307307
}
308-
VType storedValue = savedItem.getValue();
308+
VType storedValue = savedItem.getValue(); // Always PV name field, even if read-back PV is specified
309309
VType liveValue = liveSnapshotItem.getValue();
310-
Threshold<Number> threshold = new Threshold<>(tolerance);
310+
VType readbackValue = liveSnapshotItem.getReadbackValue();
311+
312+
// Apply reference selection algorithm
313+
VType referenceValue = getReferenceValue(liveValue, readbackValue, skipReadback);
314+
315+
double finalTolerance = tolerance;
316+
// For relative tolerance and scalar types, compute an absolute tolerance
317+
// since this is what Utilities.areValuesEqual expects.
318+
if(tolerance > 0 &&
319+
referenceValue instanceof VNumber &&
320+
VTypeHelper.toDouble(referenceValue) != 0 &&
321+
comparisonMode.equals(PvCompareMode.RELATIVE)){
322+
finalTolerance = VTypeHelper.toDouble(referenceValue) * tolerance;
323+
}
324+
325+
Threshold<Number> threshold = new Threshold<>(finalTolerance);
311326
boolean equal = Utilities.areValuesEqual(storedValue, liveValue, Optional.of(threshold));
312327
CompareResult compareResult = new CompareResult(savedItem.getConfigPv().getPvName(),
313328
equal,
314-
PvCompareMode.RELATIVE,
329+
comparisonMode,
315330
tolerance,
316331
equal ? null : storedValue, // Do not add potentially large amounts of data if comparison shows equal
317332
equal ? null : liveValue, // Do not add potentially large amounts of data if comparison shows equal
@@ -321,4 +336,11 @@ public List<CompareResult> comparePvs(final List<SnapshotItem> savedSnapshotItem
321336

322337
return compareResults;
323338
}
339+
340+
private VType getReferenceValue(final VType liveValue, final VType liveReadbackValue, final boolean skipReadback){
341+
if(skipReadback){
342+
return liveValue;
343+
}
344+
return liveReadbackValue != null ? liveReadbackValue : liveValue;
345+
}
324346
}

app/save-and-restore/util/src/test/java/org/phoebus/saveandrestore/util/SnapshotUtilTest.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,66 @@ public void testComparePvs(){
127127
assertThrows(RuntimeException.class, () -> snapshotUtil.comparePvs(null, -77, PvCompareMode.ABSOLUTE, false));
128128

129129
}
130+
131+
@Test
132+
public void testComparePvsRelative(){
133+
ConfigPv configPv1 = new ConfigPv();
134+
configPv1.setPvName("loc://x(42.0)");
135+
ConfigPv configPv2 = new ConfigPv();
136+
configPv2.setPvName("loc://y(771.0)");
137+
138+
SnapshotItem snapshotItem1 = new SnapshotItem();
139+
snapshotItem1.setConfigPv(configPv1);
140+
snapshotItem1.setValue(VDouble.of(42.0, Alarm.none(), Time.now(), Display.none()));
141+
SnapshotItem snapshotItem2 = new SnapshotItem();
142+
snapshotItem2.setConfigPv(configPv2);
143+
snapshotItem2.setValue(VDouble.of(771.0, Alarm.none(), Time.now(), Display.none()));
144+
145+
List<CompareResult> compareResults = snapshotUtil.comparePvs(List.of(snapshotItem1, snapshotItem2), 0.0, PvCompareMode.RELATIVE, false);
146+
147+
assertTrue(compareResults.get(0).isEqual());
148+
assertTrue(compareResults.get(1).isEqual());
149+
150+
snapshotItem1.setValue(VDouble.of(43.0, Alarm.none(), Time.now(), Display.none()));
151+
snapshotItem2.setValue(VDouble.of(771.0, Alarm.none(), Time.now(), Display.none()));
152+
153+
compareResults = snapshotUtil.comparePvs(List.of(snapshotItem1, snapshotItem2), 0.0, PvCompareMode.RELATIVE, false);
154+
155+
assertFalse(compareResults.get(0).isEqual());
156+
assertNotNull(compareResults.get(0).getStoredValue());
157+
assertNotNull(compareResults.get(0).getLiveValue());
158+
assertTrue(compareResults.get(1).isEqual());
159+
assertNull(compareResults.get(1).getStoredValue());
160+
assertNull(compareResults.get(1).getLiveValue());
161+
162+
snapshotItem1.setValue(VDouble.of(43.0, Alarm.none(), Time.now(), Display.none()));
163+
snapshotItem2.setValue(VDouble.of(999.0, Alarm.none(), Time.now(), Display.none()));
164+
165+
compareResults = snapshotUtil.comparePvs(List.of(snapshotItem1, snapshotItem2), 0.1, PvCompareMode.RELATIVE, false);
166+
167+
assertTrue(compareResults.get(0).isEqual());
168+
assertFalse(compareResults.get(1).isEqual());
169+
170+
assertThrows(RuntimeException.class, () -> snapshotUtil.comparePvs(null, -77, PvCompareMode.RELATIVE, false));
171+
172+
}
173+
174+
@Test
175+
public void testComparePvsWithReadbacks() {
176+
ConfigPv configPv1 = new ConfigPv();
177+
configPv1.setPvName("loc://x(42.0)");
178+
configPv1.setReadbackPvName("loc://xx(43.0)");
179+
180+
SnapshotItem snapshotItem1 = new SnapshotItem();
181+
snapshotItem1.setConfigPv(configPv1);
182+
snapshotItem1.setValue(VDouble.of(42.0, Alarm.none(), Time.now(), Display.none()));
183+
snapshotItem1.setReadbackValue(VDouble.of(50.0, Alarm.none(), Time.now(), Display.none()));
184+
185+
List<CompareResult> compareResults = snapshotUtil.comparePvs(List.of(snapshotItem1), 8.0, PvCompareMode.ABSOLUTE, false);
186+
assertTrue(compareResults.get(0).isEqual());
187+
188+
compareResults = snapshotUtil.comparePvs(List.of(snapshotItem1), 9.0, PvCompareMode.ABSOLUTE, false);
189+
assertFalse(compareResults.get(0).isEqual());
190+
191+
}
130192
}

services/save-and-restore/doc/index.rst

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -858,21 +858,36 @@ from an existing node rather than providing them explicitly. It returns the same
858858
Compare Endpoint
859859
----------------
860860

861-
**.../compare/{uniqueId}[?tolerance=<tolerance_value>]**
861+
**.../compare/{uniqueId}[?tolerance=<tolerance_value>&comparisonMode=<ABSOLUTE|RELATIVE>&skipReadback=<true|false>]**
862862

863863
Method: GET
864864

865-
The path variable ``{uniqueId}`` must identify an existing snapshot or composite snapshot. The ``tolerance`` query parameter is
866-
optional and defaults to zero. If specified it must be >= 0.
865+
The path variable ``{uniqueId}`` must identify an existing snapshot or composite snapshot.
867866

868-
This endpoint can be used to compare stored snapshot values to live values for each set-point PV in the snapshot.
869-
Comparisons are performed in the same manner as in the client UI, i.e.:
867+
The ``tolerance`` query parameter is optional and defaults to zero. If specified it must be >= 0.
868+
The ``comparisonMode`` query parameter is optional and defaults to ``ABSOLUTE``.
869+
The ``skipReadback`` query parameter is optional and defaults to ``false``.
870870

871-
* Scalar PVs are compared using the the optional relative tolerance, or compared using zero tolerance.
871+
This endpoint can be used to compare stored snapshot values to live values for each set-point PV in the snapshot. The
872+
reference value for the comparison is always the one corresponding to the ``PV Name`` column in the configuration.
873+
874+
Comparisons are performed like so:
875+
876+
* Scalar PVs are compared using the tolerance and comparison mode (absolute or relative), or compared using zero tolerance.
872877
* Array PVs are compared element wise, always using zero tolerance. Arrays must be of equal length.
873878
* Table PVs are compared element wise, always using zero tolerance. Tables must be of same dimensions, and data types must match between columns.
874879
* Enum PVs are compared using zero tolerance.
875880

881+
In addition, the ``comparisonMode`` and ``skipReadback`` together with the presence of a read-back PV value is used to
882+
determine which values to compare:
883+
* If a read-back PV name has been specified it's live value is compare to the stored value.
884+
* If a read-back PV name has not been specified, or if ``skipReadback`` is ``true``, then the live value of ``PV Name``
885+
is used to compare to the stored value.
886+
* Comparison mode=ABSOLUTE (default) will apply absolute delta comparison.
887+
* Comparison mode=RELATIVE will apply relative comparison.
888+
* If an item in the configuration specifies a tolerance of zero, then a tolerance value specified in the API
889+
call will be ignored.
890+
876891
Return value: a list of comparison results, one for each PV in the snapshot, e.g.:
877892

878893
.. code-block:: JSON

0 commit comments

Comments
 (0)