From 08b39f9221d23d4e28771af393adf1a08651b306 Mon Sep 17 00:00:00 2001 From: timronan Date: Fri, 11 Sep 2020 16:45:17 -0700 Subject: [PATCH 1/2] Add rule 407 to address issue 117. Update documentation for rules 407, 321, 322. --- docs/tests.md | 4 +- .../iris/dmc/station/RuleEngineRegistry.java | 6 + .../InstrumentUnitsStageCondition.java | 160 ++++++++++++++++++ src/test/resources/{F4_321.xml => F1_407.xml} | 0 src/test/resources/F2_407.xml | 120 +++++++++++++ 5 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 src/main/java/edu/iris/dmc/station/conditions/InstrumentUnitsStageCondition.java rename src/test/resources/{F4_321.xml => F1_407.xml} (100%) create mode 100644 src/test/resources/F2_407.xml diff --git a/docs/tests.md b/docs/tests.md index b1172bb..5eb7d32 100644 --- a/docs/tests.md +++ b/docs/tests.md @@ -66,7 +66,8 @@ DICTIONARY: External reference, such as the units name list | | **`Channel Time Errors`** |||| | 310 | Channel:startDate must be included and must occur before Channel:endDate if included.
Channel:startDate must be **INCLUDED AND** < Channel:endDate **IF INCLUDED**
|Error||[F1_310](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F1_310.xml), [F2_310](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F2_310.xml)|[PASS](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/Validator_Pass.xml)| | 320 | If Channel:Code[2]==(H | L | M | N) THEN Channel:Azimuth and Channel:Dip must be included. |Error|[C1](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel), [C2](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel)| [F1_320](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F1_320.xml)|[PASS](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/Validator_Pass.xml)| -| 321 |If Channel:Code[2] == (H | L | M | N) then Stage[1]:InputUnit must equal *m/s* AND Stage[Last]:OutputUnits must equal count*|WARNING|[C1](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel), [C2](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel)| [F1_321](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F1_320.xml)|[PASS](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/Validator_Pass.xml)| +| 321 |If Channel:Code[2] == (H | L) then Stage[1]:InputUnit must equal ?m/s AND Stage[Last]:OutputUnits must equal count?|WARNING|[C1](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel), [C2](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel)| [F1_321](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resource/F1_321.xml)[F2_321](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F2_321.xml)|[PASS](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/Validator_Pass.xml)| +| 322 |If Channel:Code[2] == (N) then Stage[1]:InputUnit must equal ?m/s**2 AND Stage[Last]:OutputUnits must equal count?|WARNING|[C1](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel), [C2](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel)| [F1_322](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resource/F1_322.xml)[F2_322](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F2_322.xml)|[PASS](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/Validator_Pass.xml)| |||||| | | **`Channel Orientation Errors`** |||| | 332 |If Channel:Code[LAST]==N then Channel:Azimuth must be assigned (>=355.0 or <=5.0) or (>=175.0 and <=185.0) and Channel:Dip must be assigned (>=-5 AND <=5.0). |Warning|[C1](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel), [C2](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel)|[F1_332](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F1_332.xml)|[PASS](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/Validator_Pass.xml), [P1_332](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/P1_332.xml), [P2_332](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/P2_332.xml), [P3_332](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/P3_332.xml), [P4_332](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/P4_332.xml)| @@ -81,6 +82,7 @@ DICTIONARY: External reference, such as the units name list | 404 | If Stage[N]:PolesZeros:PzTransferFunctionType:Digital or Stage[N]:FIR or Stage[N]:Coefficients:CfTransferFunctionType:DIGITAL are included then Stage[N] must include Stage[N]:Decimation and Stage[N]:StageGain elements.|Error|[C1](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel), [C2](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel)|[F1_404](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F1_404.xml), [F2_404](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F2_404.xml), [F3_404](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F3_404.xml), [F4_404](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F4_404.xml)|[PASS](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/Validator_Pass.xml), [P1_404](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/P1_404.xml)| | 405 | Stage:ResponseList cannot be the only stage included in a response.
**IF** Stage[1] == Stage:ResponseList **THEN LENGTH**(Stage)>1 **AND** Stage[N] != Stage:ResponseList must be **INCLUDED**
|Error|[C1](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel), [C2](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel)|[F1_405](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F1_405.xml)|[PASS](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/Validator_Pass.xml), [P1_405](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/P1_405.xml)| | 406 | Stage[LAST]::OutputUnits:Name must be assigned count.
Stage[LAST]::OutputUnits:Name must be **ASSIGNED** count.
|Error|[C1](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel), [C2](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel)|[F1_406](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F1_406.xml)|[PASS](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/Validator_Pass.xml)| +| 407 | (InstrumentSensitivity:InputUnits:Name must equal Stage[1]:InputUnits:Name and InstrumentSensitivity:OutputUnits:Name must equal Stage[last]:OutputUnits:Name) or (InstrumentPolynomial:InputUnits:Name must equal Stage[1]:InputUnits:Name and InstrumentPolynomial:OutputUnits:Name must equal Stage[last]:OutputUnits:Name) |Error|[C1](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel), [C2](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel)|[F1_407](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F1_407.xml)[F2_407](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F2_407.xml)|[PASS](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/Validator_Pass.xml)| |||||| | | **`ResponseType and StageGain Errors`** |||| | 410 | If InstrumentSensitivity is included then InstrumentSensitivity:Value must be assigned a double > 0.0.
**IF** InstrumentSensitivity is **INCLUDED THEN** InstrumentSensitivity:Value must be **INCLUDED AND ASSIGNED** > 0.0
|Error|[C1](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel), [C2](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#channel), [R1](https://github.com/iris-edu/StationXML-Validator/wiki/Restrictions#response)|[F1_410](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F1_410.xml), [F2_410](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/F2_410.xml)|[PASS](https://github.com/iris-edu/StationXML-Validator/blob/master/src/test/resources/Validator_Pass.xml)| diff --git a/src/main/java/edu/iris/dmc/station/RuleEngineRegistry.java b/src/main/java/edu/iris/dmc/station/RuleEngineRegistry.java index b7a5159..386f048 100644 --- a/src/main/java/edu/iris/dmc/station/RuleEngineRegistry.java +++ b/src/main/java/edu/iris/dmc/station/RuleEngineRegistry.java @@ -29,6 +29,7 @@ import edu.iris.dmc.station.conditions.FrequencyCondition; import edu.iris.dmc.station.conditions.InstrumentCodeUnitsCondition; import edu.iris.dmc.station.conditions.InstrumentSensitivityCondition; +import edu.iris.dmc.station.conditions.InstrumentUnitsStageCondition; import edu.iris.dmc.station.conditions.LastStageUnitCondition; import edu.iris.dmc.station.conditions.LocationCodeCondition; import edu.iris.dmc.station.conditions.MissingDecimationCondition; @@ -231,6 +232,11 @@ private void defaultResponseRules(Set s) { "Stage[LAST]::OutputUnits:Name must be assigned count(s)", restrictions), Response.class); } + if (!s.contains(407)) { + add(407, new InstrumentUnitsStageCondition(true, + "InstrumentSensitivity:InputUnits:Name must equal Stage[1]:InputUnits:Name AND InstrumentSensitivity:OutputUnits:Name must equal Stage[last]:OutputUnits:Name OR InstrumentPolynomial:InputUnits:Name must equal Stage[1]:InputUnits:Name AND InstrumentPolynomial:OutputUnits:Name must equal Stage[last]:OutputUnits:Name", + restrictions), Response.class); + } if (!s.contains(410)) { add(410, new EmptySensitivityCondition(true, "If InstrumentSensitivity is included then InstrumentSensitivity:Value must be assigned a double > 0.0 ", new ChannelCodeRestriction(), new ChannelTypeRestriction(), new ResponsePolynomialRestriction()), diff --git a/src/main/java/edu/iris/dmc/station/conditions/InstrumentUnitsStageCondition.java b/src/main/java/edu/iris/dmc/station/conditions/InstrumentUnitsStageCondition.java new file mode 100644 index 0000000..eaa99aa --- /dev/null +++ b/src/main/java/edu/iris/dmc/station/conditions/InstrumentUnitsStageCondition.java @@ -0,0 +1,160 @@ +package edu.iris.dmc.station.conditions; + +import edu.iris.dmc.fdsn.station.model.Channel; +import edu.iris.dmc.fdsn.station.model.Network; +import edu.iris.dmc.fdsn.station.model.Response; +import edu.iris.dmc.fdsn.station.model.ResponseStage; +import edu.iris.dmc.fdsn.station.model.Station; +import edu.iris.dmc.station.exceptions.StationxmlException; +import edu.iris.dmc.station.restrictions.Restriction; +import edu.iris.dmc.station.rules.Message; +import edu.iris.dmc.station.rules.NestedMessage; +import edu.iris.dmc.station.rules.Result; + +public class InstrumentUnitsStageCondition extends ChannelRestrictedCondition { + private Restriction[] restrictions; + + public InstrumentUnitsStageCondition(boolean required, String description, Restriction[] restrictions) { + super(required, description); + this.restrictions = restrictions; + } + + @Override + public Message evaluate(Network network) { + throw new IllegalArgumentException("Not supported!"); + } + + @Override + public Message evaluate(Station station) { + throw new IllegalArgumentException("Not supported!"); + } + + @Override + public Message evaluate(Channel channel) { + if (channel == null) { + return Result.success(); + } + return this.evaluate(channel, channel.getResponse()); + } + + @Override + public Message evaluate(Channel channel, Response response) { + if (isRestricted(channel)) { + return Result.success(); + } + if (this.required) { + if (response == null) { + return Result.error("expected response but was null"); + } + } + NestedMessage nestedMessage = new NestedMessage(); + boolean returnmessage = false; + String inputUnit =""; + String code = channel.getCode(); + try { + if(channel.getResponse().getStage().size()==0) { + throw new StationxmlException("Response is missing from input StationXML"); + } + ResponseStage stage1 = channel.getResponse().getStage().get(0); + if(stage1.getCoefficients() != null) { + inputUnit = stage1.getCoefficients().getInputUnits().getName(); + }else if(stage1.getPolesZeros() != null){ + inputUnit = stage1.getPolesZeros().getInputUnits().getName(); + }else if(stage1.getResponseList() != null){ + inputUnit = stage1.getResponseList().getInputUnits().getName(); + }else if(stage1.getFIR()!=null) { + inputUnit = stage1.getFIR().getInputUnits().getName(); + }else if(stage1.getPolynomial()!= null){ + inputUnit = stage1.getPolynomial().getInputUnits().getName(); + }else { + return Result.success(); + } + for (Restriction r : this.restrictions) { + if (r.qualifies(channel)) { + return Result.success(); + } + } + int lastindex = channel.getResponse().getStage().size()-1; + ResponseStage stagelast = channel.getResponse().getStage().get(lastindex); + String outputUnit =""; + if(stagelast.getCoefficients() != null) { + outputUnit = stagelast.getCoefficients().getOutputUnits().getName(); + }else if(stagelast.getPolesZeros() != null){ + outputUnit = stagelast.getPolesZeros().getOutputUnits().getName(); + }else if(stagelast.getResponseList() != null){ + outputUnit = stagelast.getResponseList().getOutputUnits().getName(); + }else if(stagelast.getFIR()!=null) { + outputUnit = stagelast.getFIR().getOutputUnits().getName(); + }else if(stagelast.getPolynomial()!= null){ + outputUnit = stagelast.getPolynomial().getOutputUnits().getName(); + }else { + return Result.success(); + } + + + if (channel.getResponse().getInstrumentSensitivity() != null) { + String instrumentInputUnit = channel.getResponse(). + getInstrumentSensitivity().getInputUnits().getName(); + String instrumentOutputUnit = channel.getResponse(). + getInstrumentSensitivity().getOutputUnits().getName(); + if(!inputUnit.equalsIgnoreCase(instrumentInputUnit)){ + nestedMessage.add(Result.error("InsturmentSensitivity input " + + "units "+ instrumentInputUnit+" must equal Stage[01] input " + + "units "+ inputUnit)); + returnmessage=true; + } + if(!outputUnit.equalsIgnoreCase(instrumentOutputUnit)){ + if (lastindex+1 < 10 ) { + nestedMessage.add(Result.error("InsturmentSensitivity output " + + "units "+ instrumentOutputUnit+" must equal Stage[" + +String.format("%02d",(lastindex+1))+"] output units "+ outputUnit)); + returnmessage=true; + }else { + nestedMessage.add(Result.error("InsturmentSensitivity output " + + "units "+ instrumentOutputUnit+" must equal Stage[" + +(lastindex+1)+"] output units "+ outputUnit)); + returnmessage=true; + } + } + + }else{ + String instrumentInputUnit = channel.getResponse(). + getInstrumentPolynomial().getInputUnits().getName(); + String instrumentOutputUnit = channel.getResponse(). + getInstrumentPolynomial().getOutputUnits().getName(); + if(!inputUnit.equalsIgnoreCase(instrumentInputUnit)){ + nestedMessage.add(Result.error("InsturmentPolynomial input " + + "units "+ instrumentInputUnit+" must equal Stage[01] input " + + "units "+ inputUnit)); + returnmessage=true; + } + if(!outputUnit.equalsIgnoreCase(instrumentOutputUnit)){ + if (lastindex+1 < 10 ) { + nestedMessage.add(Result.error("InsturmentPolynomial output " + + "units "+ instrumentOutputUnit+" must equal Stage[" + +String.format("%02d",(lastindex+1))+"] output units "+ outputUnit)); + returnmessage=true; + }else { + nestedMessage.add(Result.error("InsturmentPolynomial output " + + "units "+ instrumentOutputUnit+" must equal Stage[" + +(lastindex+1)+"] output units "+ outputUnit)); + returnmessage=true; + } + } + + } + + + }catch(Exception e) { + + } + if(returnmessage==true) { + return nestedMessage; + }else { + return Result.success(); + } + } + +} + + diff --git a/src/test/resources/F4_321.xml b/src/test/resources/F1_407.xml similarity index 100% rename from src/test/resources/F4_321.xml rename to src/test/resources/F1_407.xml diff --git a/src/test/resources/F2_407.xml b/src/test/resources/F2_407.xml new file mode 100644 index 0000000..b9ae7e5 --- /dev/null +++ b/src/test/resources/F2_407.xml @@ -0,0 +1,120 @@ + + + IRIS-DMC + IRIS-DMC + IRIS WEB SERVICE: fdsnws-station | version: 1.1.33 + http://service.iris.edu/fdsnws/station/1/query?net=QI&sta=VPASS&cha=BDF&starttime=2018-08-06T00:00:01&level=response&format=xml&includecomments=true&nodata=404 + 2018-08-06T20:17:16 + + [IRIS DMC] Station XML Validator Passing Test File + 1 + 1 + + 47.66157 + -122.31332 + 225.879999 + + Synthetic Test File, IRIS DMC, USA, 218 2018, Tim Ronan + + 2018-08-06T00:00:00 + 1 + 1 + + 47.66157 + -122.31332 + 225.879999 + 0 + 0 + CONTINUOUS + GEOPHYSICAL + 2E01 + 0E00 + + V + Volts + + + GEM (Infrasound), 0.2-50 Hz, 0.4 V/Pa-null + + + + + CELSIUS + TEMPERATURE in Degrees Celsius + + + CELSIUS + DIGITAL UNIT in Counts + + MACLAURIN + 0.01 + 0.01 + 0.01 + 0.0 + 0.5 + 242.846 + 0.0 + 0.227191 + 1.0 + 1.79296E-5 + 2.0 + -2.34014E-9 + 3.0 + + + + + VOLT + EMF in Volts + + + COUNTS + DIGITAL UNIT in Counts + + DIGITAL + + + 1.0 + 1 + 0 + 0.0 + 0.0 + + + 1.0 + 1.0 + + + + + + COUNTS + DIGITAL UNIT in Counts + + + Taber + DIGITAL UNIT in Counts + + DIGITAL + 0.25 + 0.25 + 0.25 + 0.25 + + + 1.0 + 4 + 0 + 0.0 + 0.0 + + + 1.0 + 1.0 + + + + + + + From fd22203acb9a6ad5bddb1757d937e608749d77fc Mon Sep 17 00:00:00 2001 From: timronan Date: Mon, 14 Sep 2020 17:14:36 -0700 Subject: [PATCH 2/2] Add a test case for condition 407. --- .../station/conditions/Condition407Test.java | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/test/java/edu/iris/dmc/station/conditions/Condition407Test.java diff --git a/src/test/java/edu/iris/dmc/station/conditions/Condition407Test.java b/src/test/java/edu/iris/dmc/station/conditions/Condition407Test.java new file mode 100644 index 0000000..cb20ee4 --- /dev/null +++ b/src/test/java/edu/iris/dmc/station/conditions/Condition407Test.java @@ -0,0 +1,92 @@ +package edu.iris.dmc.station.conditions; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.InputStream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import edu.iris.dmc.DocumentMarshaller; +import edu.iris.dmc.fdsn.station.model.Channel; +import edu.iris.dmc.fdsn.station.model.FDSNStationXML; +import edu.iris.dmc.fdsn.station.model.Network; +import edu.iris.dmc.fdsn.station.model.Station; +import edu.iris.dmc.station.RuleEngineServiceTest; +import edu.iris.dmc.station.restrictions.ChannelCodeRestriction; +import edu.iris.dmc.station.restrictions.ChannelTypeRestriction; +import edu.iris.dmc.station.restrictions.Restriction; +import edu.iris.dmc.station.rules.Message; +import edu.iris.dmc.station.rules.NestedMessage; + +public class Condition407Test { + + private FDSNStationXML theDocument; + + @BeforeEach + public void init() throws Exception { + + } + + @Test + public void sensitivityfail() throws Exception { + try (InputStream is = RuleEngineServiceTest.class.getClassLoader().getResourceAsStream("F1_407.xml")) { + theDocument = DocumentMarshaller.unmarshal(is); + + Network n = theDocument.getNetwork().get(0); + Station s = n.getStations().get(0); + Channel c = s.getChannels().get(0); + Restriction[] restrictions = new Restriction[] { new ChannelCodeRestriction(), new ChannelTypeRestriction() }; + + InstrumentUnitsStageCondition condition = new InstrumentUnitsStageCondition(true, "", restrictions); + Message result = condition.evaluate(c); + NestedMessage nestedMessage=(NestedMessage)result; + + assertTrue(nestedMessage.getNestedMessages().get(0).getDescription().contains("InsturmentSensitivity input units Kg/s must equal Stage[01] input units m/s**2")); + assertTrue(nestedMessage.getNestedMessages().get(1).getDescription().contains("InsturmentSensitivity output units COUNTS must equal Stage[12] output units m/s")); + + } + + } + + @Test + public void polynomialfail() throws Exception { + try (InputStream is = RuleEngineServiceTest.class.getClassLoader().getResourceAsStream("F2_407.xml")) { + theDocument = DocumentMarshaller.unmarshal(is); + + Network n = theDocument.getNetwork().get(0); + Station s = n.getStations().get(0); + Channel c = s.getChannels().get(0); + Restriction[] restrictions = new Restriction[] { new ChannelCodeRestriction(), new ChannelTypeRestriction() }; + + InstrumentUnitsStageCondition condition = new InstrumentUnitsStageCondition(true, "", restrictions); + Message result = condition.evaluate(c); + NestedMessage nestedMessage=(NestedMessage)result; + + assertTrue(nestedMessage.getNestedMessages().get(0).getDescription().contains("InsturmentPolynomial input units CELSIUS must equal Stage[01] input units VOLT" + + "")); + + } + + } + + @Test + public void pass() throws Exception { + try (InputStream is = RuleEngineServiceTest.class.getClassLoader().getResourceAsStream("pass.xml")) { + theDocument = DocumentMarshaller.unmarshal(is); + + Network n = theDocument.getNetwork().get(0); + Station s = n.getStations().get(0); + Channel c = s.getChannels().get(0); + Restriction[] restrictions = new Restriction[] { new ChannelCodeRestriction(), new ChannelTypeRestriction() }; + + + InstrumentUnitsStageCondition condition = new InstrumentUnitsStageCondition(true, "", restrictions); + + Message result = condition.evaluate(c); + assertTrue(result instanceof edu.iris.dmc.station.rules.Success); + } + + } +} +