Skip to content

Commit 5e0aac9

Browse files
committed
Release 1, Published on NPM
1 parent 558098f commit 5e0aac9

7 files changed

+129
-113
lines changed

README.md

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# CWMS Data Quality
2+
_A JavaScript Library for determining Corps Water Management System (CMWS) Timeseries Quality client-side_
3+
4+
5+
## Getting Started ☑
6+
1. Install the CWMS-Data-Quality Package
7+
1. Using [**NPM**](https://www.npmjs.com/package/cwms-data-quality) (with nodejs installed):
8+
In your terminal run:
9+
`npm install cwms-data-quality`
10+
11+
2. **Manually**:
12+
a. Download [index.min.mjs](https://github.com/krowvin/CWMS-Data-Quality/blob/master/index.mjs) and rename it to
13+
cwms-data-quality.mjs
14+
2. Import/include the JS Module in your HTML file:
15+
```<script src="../index.min.mjs" type="module" async defer></script>```
16+
(_optionally_): Start with the [example/default.html](https://github.com/krowvin/CWMS-Data-Quality/blob/master/example/index.html) file
17+
18+
19+
## Per the HEC Documentation:
20+
21+
### Data Quality Rules :
22+
23+
1. Unless the Screened bit is set, no other bits can be set.
24+
25+
2. Unused bits (22, 24, 27-31, 32+) must be reset (zero).
26+
27+
3. The Okay, Missing, Questioned and Rejected bits are mutually
28+
exclusive.
29+
30+
4. No replacement cause or replacement method bits can be set unless
31+
the changed (different) bit is also set, and if the changed (different)
32+
bit is set, one of the cause bits and one of the replacement
33+
method bits must be set.
34+
35+
5. Replacement Cause integer is in range 0..4.
36+
37+
6. Replacement Method integer is in range 0..4
38+
39+
7. The Test Failed bits are not mutually exclusive (multiple tests can be
40+
marked as failed).
41+
42+
43+
### Bit Mappings :
44+
Little Endian i.e. 31....0
45+
46+
3 2 1
47+
2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1
48+
49+
P - - - - - T T T T T T T T T T T M M M M C C C D R R V V V V S
50+
| <---------+---------> <--+--> <-+-> | <+> <--+--> |
51+
| | | | | | | +------Screened T/F
52+
| | | | | | +-----------Validity Flags
53+
| | | | | +--------------Value Range Integer
54+
| | | | +-------------------Different T/F
55+
| | | +---------------Replacement Cause Integer
56+
| | +---------------------Replacement Method Integer
57+
| +-------------------------------------------Test Failed Flags
58+
+-------------------------------------------------------------------Protected T/F
59+
60+
61+
### If you see any issues please report them! [⚠ Report Issues ⚠](https://github.com/krowvin/CWMS-Data-Quality/issues)
62+
63+
64+
65+
### Dev Notes:
66+
**NOTE**: _Ensure you have NodeJS installed and in your system path_
67+
1. Run the test script, which compares the module against the precomputed CSV file in `resources`:
68+
`npm run test`
69+
2. Run the build script, which minifies the js file with:
70+
`npm run build`
71+
3. Package the script for release:
72+
1. NPM:
73+
`npm publish`
74+
2. Github:
75+
`npm pack`

index.min.mjs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default class QualityTx{constructor(){this.elementData=new Int32Array(32);this.size=0;this.SCREENED_BIT=1;this.OKAY_BIT=2;this.MISSING_BIT=3;this.QUESTION_BIT=4;this.REJECT_BIT=5;this.RANGE_OF_VALUE_BIT0=6;this.RANGE_OF_VALUE_BIT1=7;this.VALUE_DIFFERS_BIT=8;this.HOW_REVISED_BIT0=9;this.HOW_REVISED_BIT1=10;this.HOW_REVISED_BIT2=11;this.REPLACE_METHOD_BIT0=12;this.REPLACE_METHOD_BIT1=13;this.REPLACE_METHOD_BIT2=14;this.REPLACE_METHOD_BIT3=15;this.ABSOLUTEMAGNITUDE_BIT=16;this.CONSTANTVALUE_BIT=17;this.RATEOFCHANGE_BIT=18;this.RELATIVEMAGNITUDE_BIT=19;this.DURATIONMAGNITUDE_BIT=20;this.NEGATIVEINCREMENTAL_BIT=21;this.NOT_DEFINED_BIT0=22;this.GAGELIST_BIT=23;this.NOT_DEFINED_BIT1=24;this.USER_DEFINED_TEST_BIT=25;this.DISTRIBUTIONTEST_BIT=26;this.RESERVED_BIT0=27;this.RESERVED_BIT1=28;this.RESERVED_BIT2=29;this.RESERVED_BIT3=30;this.RESERVED_BIT4=31;this.PROTECTED_BIT=32;this.MASK=[1,2,4,8,16,32,64,128]}_getElementAt(elementIndex){if(elementIndex>this.size||elementIndex<0)throw new RangeError("Index of: "+elementIndex+" Out of range[0 - "+this.size);let byteIndex=elementIndex*4;let bytes=new Uint8Array(4);for(let i=0;i<4;i++)bytes.push(this.elementData[byteIndex+i]);return bytes}_getIntegerAt(elementIndex){let bytes=getElementAt(elementIndex);let i0=bytes[0]&255;let i1=bytes[1]&255;let i2=bytes[2]&255;let i3=bytes[3]&255;return i3|i2<<8|i1<<16|i0<<24}_getInteger(bytes){let i0=bytes[0]&255;let i1=bytes[1]&255;let i2=bytes[2]&255;let i3=bytes[3]&255;return i3|i2<<8|i1<<16|i0<<24}_isQualityClear(bytes){return this._getInteger(bytes)==0}_isScreened(elementIndex){return this._isBitSet(elementIndex,1)}_isNotScreened(elementIndex){return this._isBitClear(elementIndex,1)}_isBitClear(elementIndex,bitPosition){return!this._isBitSet(elementIndex,bitPosition)}_isBitSet(elementIndex,bitPosition){if(typeof elementIndex=="object"){let bytes=elementIndex;let targetByte=Math.floor((32-bitPosition)/8);let targetBit=(bitPosition-1)%8;let base=bytes[targetByte];let result=base&this.MASK[targetBit];return result!=0}else{if(elementIndex>this.size||elementIndex<0)throw new RangeError("Index of: "+elementIndex+" Out of range[0 - "+this.size+"]");let bytes=this._getElementAt(elementIndex);return this._isBitSet(bytes,bitPosition)}}_isRange1(bytes){if(this._isBitSet(bytes,6)&&this._isBitClear(bytes,7))return true;return false}_isRange2(bytes){if(this._isBitClear(bytes,6)&&this._isBitSet(bytes,7))return true;return false}_isRange3(bytes){if(this._isBitSet(bytes,6)&&this._isBitSet(bytes,7))return true;return false}_isDifferentValue(bytes){return this._isBitSet(bytes,8)}_isRevisedAutomatically(bytes){if(this._isBitSet(bytes,9)&&this._isBitClear(bytes,10)&&this._isBitClear(bytes,11))return true;return false}_isRevisedInteractively(bytes){if(this._isBitClear(bytes,9)&&this._isBitSet(bytes,10)&&this._isBitClear(bytes,11))return true;return false}_isRevisedManually(bytes){if(this._isBitSet(bytes,9)&&this._isBitSet(bytes,10)&&this._isBitClear(bytes,11))return true;return false}_isRevisedToOriginalAccepted(bytes){if(this._isBitClear(bytes,9)&&this._isBitClear(bytes,10)&&this._isBitSet(bytes,11))return true;return false}_isReplaceLinearInterpolation(bytes){if(this._isBitSet(bytes,12)&&this._isBitClear(bytes,13)&&this._isBitClear(bytes,14)&&this._isBitClear(bytes,15))return true;return false}_isReplaceManualChange(bytes){if(this._isBitClear(bytes,12)&&this._isBitSet(bytes,13)&&this._isBitClear(bytes,14)&&this._isBitClear(bytes,15))return true;return false}_isReplaceWithMissing(bytes){if(this._isBitSet(bytes,12)&&this._isBitSet(bytes,13)&&this._isBitClear(bytes,14)&&this._isBitClear(bytes,15))return true;return false}_isReplaceGraphicalChange(bytes){if(this._isBitClear(bytes,12)&&this._isBitClear(bytes,13)&&this._isBitSet(bytes,14)&&this._isBitClear(bytes,15))return true;return false}_getValidity(bytes){if(this._isBitSet(bytes,2))return"OKAY";if(this._isBitSet(bytes,3))return"MISSING";if(this._isBitSet(bytes,4))return"QUESTIONABLE";if(this._isBitSet(bytes,5))return"REJECTED";return"UNKNOWN"}_getRange(bytes){if(this._isRange1(bytes))return"RANGE_1";if(this._isRange2(bytes))return"RANGE_2";if(this._isRange3(bytes))return"RANGE_3";return"NO_RANGE"}_getReplaceCause(bytes){if(this._isRevisedAutomatically(bytes))return"AUTOMATIC";if(this._isRevisedInteractively(bytes))return"INTERACTIVE";if(this._isRevisedManually(bytes))return"MANUAL";if(this._isRevisedToOriginalAccepted(bytes))return"RESTORED";return"NONE"}_getReplaceMethod(bytes){if(this._isReplaceLinearInterpolation(bytes))return"LIN_INTERP";if(this._isReplaceManualChange(bytes))return"EXPLICIT";if(this._isReplaceWithMissing(bytes))return"MISSING";if(this._isReplaceGraphicalChange(bytes))return"GRAPHICAL";return"NONE"}_getTestFailed(bytes){let failed=[];if(this._isBitSet(bytes,16))failed.push("ABSOLUTE_VALUE");if(this._isBitSet(bytes,17))failed.push("CONSTANT_VALUE");if(this._isBitSet(bytes,18))failed.push("RATE_OF_CHANGE");if(this._isBitSet(bytes,19))failed.push("RELATIVE_VALUE");if(this._isBitSet(bytes,20))failed.push("DURATION_VALUE");if(this._isBitSet(bytes,21))failed.push("NEG_INCREMENT");if(this._isBitSet(bytes,23))failed.push("SKIP_LIST");if(this._isBitSet(bytes,25))failed.push("USER_DEFINED");if(this._isBitSet(bytes,26))failed.push("DISTRIBUTION");return failed.length?failed.join("+"):"NONE"}getStringDescription(intQuality,columns=false){let bytes=new Uint8Array(4);bytes[3]=intQuality&255;bytes[2]=intQuality>>8&255;bytes[1]=intQuality>>16&255;bytes[0]=intQuality>>24&255;if(columns){return{QUALITY_CODE:intQuality,SCREENED_ID:this._isScreened(bytes)?"SCREENED":"UNSCREENED",VALIDITY_ID:this._getValidity(bytes),RANGE_ID:this._getRange(bytes),CHANGED_ID:this._isDifferentValue(bytes)?"MODIFIED":"ORIGINAL",REPL_CAUSE_ID:this._getReplaceCause(bytes),REPL_METHOD_ID:this._getReplaceMethod(bytes),TEST_FAILED_ID:this._getTestFailed(bytes),PROTECTED:this._isBitSet(bytes,32)?"PROTECTED":"UNPROTECTED"}}if(this._isQualityClear(bytes))return"Quality is undetermined";let sb=[];if(this._isScreened(bytes)){sb.push("Screened")}else{sb.push("Not Screened?")}if(this._isBitSet(bytes,2)){if(sb.length>0)sb.push(", ");sb.push("Passed tests OK")}if(this._isBitSet(bytes,3)){if(sb.length>0)sb.push(", ");sb.push("Set to Missing")}if(this._isBitSet(bytes,4)){if(sb.length>0)sb.push(", ");sb.push("Questionable Quality")}if(this._isBitSet(bytes,5)){if(sb.length>0)sb.push(", ");sb.push("Rejected Quality")}if(this._isRange1(bytes)){if(sb.length>0)sb.push("\n");sb.push("Value is between first and second range limit")}if(this._isRange2(bytes)){if(sb.length>0)sb.push("\n");sb.push("Value is between second and third range limit")}if(this._isRange3(bytes)){if(sb.length>0)sb.push("\n");sb.push("Value is above third range limit")}if(this._isDifferentValue(bytes)){if(sb.length>0)sb.push("\n");sb.push("Current value is different from original value")}if(this._isRevisedAutomatically(bytes)){if(sb.length>0)sb.push("\n");sb.push("Revised automatically by DATCHK or other Process")}if(this._isRevisedInteractively(bytes)){if(sb.length>0)sb.push("\n");sb.push("Revised interactively with DATVUE or CWMS Verification Editor")}if(this._isRevisedManually(bytes)){if(sb.length>0)sb.push("\n");sb.push("Manual entry with DATVUE or CWMS Verification Editor")}if(this._isRevisedToOriginalAccepted(bytes)){if(sb.length>0)sb.push("\n");sb.push("Original value accepted in DATVUE or CWMS Verification Editor")}if(this._isReplaceLinearInterpolation(bytes)){if(sb.length>0)sb.push("\n");sb.push("Replacement method: linear interpolation")}if(this._isReplaceManualChange(bytes)){if(sb.length>0)sb.push("\n");sb.push("Replacement method: manual change")}if(this._isReplaceWithMissing(bytes)){if(sb.length>0)sb.push("\n");sb.push("Replacement method: replace with missing value")}if(this._isReplaceGraphicalChange(bytes)){if(sb.length>0)sb.push("\n");sb.push("Replacement method: graphical change")}if(this._isBitSet(bytes,16)){if(sb.length>0)sb.push("\n");sb.push("Failed Test: Absolute Magnitude")}if(this._isBitSet(bytes,17)){if(sb.length>0)sb.push("\n");sb.push("Failed Test: Constant Value")}if(this._isBitSet(bytes,18)){if(sb.length>0)sb.push("\n");sb.push("Failed Test: Rate-of-change")}if(this._isBitSet(bytes,19)){if(sb.length>0)sb.push("\n");sb.push("Failed Test: Relative Magnitude")}if(this._isBitSet(bytes,20)){if(sb.length>0)sb.push("\n");sb.push("Failed Test: Duration-magnitude")}if(this._isBitSet(bytes,21)){if(sb.length>0)sb.push("\n");sb.push("Failed Test: Negative Incremental Value")}if(this._isBitSet(bytes,23)){if(sb.length>0)sb.push("\n");sb.push("Failed Test: On GAGE list as faulty gage")}if(this._isBitSet(bytes,25)){if(sb.length>0)sb.push("\n");sb.push("Failed Test: User-defined Test")}if(this._isBitSet(bytes,26)){if(sb.length>0)sb.push("\n");sb.push("Failed Test: Distribution Test")}if(this._isBitSet(bytes,32)){if(sb.length>0)sb.push("\n");sb.push("PROTECTED from change or replacement")}return sb.toString()}}

package-lock.json

+45-75
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
{
22
"type": "module",
3-
"dependencies": {
4-
},
53
"name": "cwms-data-quality",
6-
"version": "1.0.0",
4+
"version": "1.0.1",
75
"description": "A JavaScript implementation of the CWMS QualityTx class. Enables working with Time Series Quality integers. Can help in determining the screening, validity, value range, revision, replacement cause, replacement method, tests failing, and protection of a given Timeseries Quality Code. Created for use with CDA. ",
86
"main": "index.js",
97
"directories": {
@@ -15,9 +13,13 @@
1513
"url": "https://github.com/krowvin/cwms-data-quality.git",
1614
"directory": "packages/cwms-data-quality"
1715
},
18-
"devDependencies": {},
16+
"devDependencies": {
17+
"csv-parse": "^5.3.6",
18+
"uglify-js": "^3.17.4"
19+
},
1920
"scripts": {
20-
"test": "./tests/test.js"
21+
"test": "node tests/test.js",
22+
"build": "uglifyjs index.mjs -o index.min.mjs"
2123
},
2224
"keywords": [
2325
"cwms",
@@ -34,6 +36,6 @@
3436
"author": "Charles Graham <charlie@krowvin.com> (https://krowvin.com)",
3537
"contributors": [
3638
"Charles Graham <charlie@krowvin.com> (https://krowvin.com)"
37-
],
39+
],
3840
"license": "MIT"
3941
}
File renamed without changes.

tests/compare.js

-19
This file was deleted.

tests/package.json

-13
This file was deleted.

0 commit comments

Comments
 (0)