ADLongwell-usgs-waterdata 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ 0.0.1 - Welcomed into the world, screaming and crying.
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2008 Aaron Longwell, Chris Tenbrink
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,12 @@
1
+ History.txt
2
+ init.rb
3
+ Manifest.txt
4
+ License.txt
5
+ README.txt
6
+ Rakefile
7
+ lib/usgs.rb
8
+ lib/usgs/gauge.rb
9
+ lib/usgs/water_data.rb
10
+ spec/gauge_spec.rb
11
+ spec/spec_helper.rb
12
+ spec/waterdata_spec.rb
@@ -0,0 +1,3 @@
1
+ README.txt
2
+
3
+ The usgs-waterdata library is a tool for obtaining real-time and statistical river flow data from the United States Geological Survey's National Water Information System. It will fetch a list of all rivers for which gauge data exists along with the gauges on that river. For a particular gauge, the library will obtain the latest flow, the mean flow on all days for which data exists, and long-term statistical flow data.
@@ -0,0 +1,12 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/usgs.rb'
6
+
7
+ Hoe.new('usgs-waterdata', USGS::VERSION) do |p|
8
+ # p.rubyforge_name = 'usgs-waterdata' # if different than lowercase project name
9
+ # p.developer('FIX', 'FIX@example.com')
10
+ end
11
+
12
+ # vim: syntax=Ruby
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ # Placeholder
@@ -0,0 +1,7 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require 'usgs/water_data'
3
+ require 'usgs/gauge'
4
+
5
+ module USGS
6
+ VERSION = '0.0.1'
7
+ end
@@ -0,0 +1,149 @@
1
+ module USGS
2
+
3
+ require 'open-uri'
4
+ require 'date'
5
+
6
+ class Gauge
7
+
8
+ attr_reader :site_number
9
+
10
+ def initialize( site_number )
11
+ @site_number = site_number
12
+ end
13
+
14
+ # Determine the most recent instantaneous flow in CFS for this guage
15
+ def latest_flow
16
+ url = "http://waterdata.usgs.gov/nwis/uv?cb_00060=on&format=rdb&period=1&site_no=#{@site_number}"
17
+ flow = 0
18
+ open(url).each do |line|
19
+ next if line =~ /^#/
20
+ next if line =~ /^5/
21
+ next if line =~ /^agency/
22
+
23
+ fields = line.split(/\t/)
24
+ flow = fields[3]
25
+ end
26
+ flow
27
+ end
28
+
29
+ # todo: use lambda (or a similar construct) to minimize repetitive code
30
+
31
+ # Returns a 2-dimensional array of the statistical mean flows for this
32
+ # gauge on days for which data exists, sorted by date.
33
+ def get_statistical_mean_flows
34
+ populate_statistical_data if @statistical_mean_flows.nil? or @statistical_mean_flows.empty?
35
+ @statistical_mean_flows
36
+ end
37
+
38
+ # Returns a 2-dimensional array of the statistical median flows for this
39
+ # gauge on days for which data exists, sorted by date.
40
+ def get_statistical_median_flows
41
+ populate_statistical_data if @statistical_median_flows.nil? or @statistical_median_flows.empty?
42
+ @statistical_median_flows
43
+ end
44
+
45
+ # Returns a 2-dimensional array of the statistical 80th percentile flows for this
46
+ # gauge on days for which data exists, sorted by date.
47
+ def get_statistical_percentile80_flows
48
+ populate_statistical_data if @statistical_percentile80_flows.nil? or @statistical_percentile80_flows.empty?
49
+ @statistical_percentile80_flows
50
+ end
51
+
52
+ # Returns a 2-dimensional array of the statistical 20th percentile flows for this
53
+ # gauge on days for which data exists, sorted by date.
54
+ def get_statistical_percentile20_flows
55
+ populate_statistical_data if @statistical_percentile20_flows.nil? or @statistical_percentile20_flows.empty?
56
+ @statistical_percentile20_flows
57
+ end
58
+
59
+ # Returns a 2-dimensional array of the daily mean flows for this
60
+ # gauge on days for which data exists, sorted by date.
61
+ def get_daily_mean_flows
62
+ populate_daily_data if @daily_mean_flows.nil? or @daily_mean_flows.empty?
63
+ @daily_mean_flows
64
+ end
65
+
66
+ private
67
+
68
+ # Populate daily data for a gauge from the USGS site
69
+ def populate_daily_data
70
+ url = "http://waterdata.usgs.gov/nwis/dv?site_no=#{@site_number}&cb_00060=on&begin_date=1880-01-01&format=rdb"
71
+ mean_flows_hash = {}
72
+ open(url).each do |line|
73
+ next if line =~ /^#/
74
+ next if line =~ /^5/
75
+ next if line =~ /^agency/
76
+
77
+ field_array = line.split(/\t/)
78
+ date_array = field_array[2].split('-')
79
+ date = Date.new(date_array[0].to_i, date_array[1].to_i, date_array[2].to_i)
80
+ mean = field_array[3]
81
+ mean_flows_hash[date] = mean
82
+ end
83
+ @daily_mean_flows = mean_flows_hash.sort
84
+ end
85
+
86
+ # Populate statistical data for a gauge from the USGS site
87
+ def populate_statistical_data
88
+ url = "http://waterdata.usgs.gov/id/nwis/dvstat/?site_no=#{@site_number}&por_#{@site_number}_2=1155369,00060,2,0000-01-01,9999-01-01&start_dt=0000-01-01&end_dt=9999-01-01&format=rdb&date_format=YYYY-MM-DD"
89
+
90
+ field_map = {
91
+ 'agency' => 0,
92
+ 'site' => 1,
93
+ 'parameter' => 2,
94
+ 'dd_nu' => 3,
95
+ 'month_nu' => 4,
96
+ 'day_nu' => 5,
97
+ 'begin_yr' => 6,
98
+ 'end_yr' => 7,
99
+ 'count_nu' => 8,
100
+ 'max_va_yr' => 9,
101
+ 'max_va' => 10,
102
+ 'min_va_yr' => 11,
103
+ 'min_va' => 12,
104
+ 'mean_va' => 13,
105
+ 'p05_va' => 14, # 05 percentile of daily mean values for this day.
106
+ 'p10_va' => 15, # 10 percentile of daily mean values for this day.
107
+ 'p20_va' => 16, # 20 percentile of daily mean values for this day.
108
+ 'p25_va' => 17, # 25 percentile of daily mean values for this day.
109
+ 'p50_va' => 18, # 50 percentile (median) of daily mean values for this day.
110
+ 'p75_va' => 19, # 75 percentile of daily mean values for this day.
111
+ 'p80_va' => 20, # 80 percentile of daily mean values for this day.
112
+ 'p90_va' => 21, # 90 percentile of daily mean values for this day.
113
+ 'p95_va' => 22 # 95 percentile of daily mean values for this day.
114
+ }
115
+
116
+ mean_flows_hash = {}
117
+ median_flows_hash = {}
118
+ percentile20_flows_hash = {}
119
+ percentile80_flows_hash = {}
120
+ open(url).each do |line|
121
+ next if line =~ /^#/
122
+ next if line =~ /^5/
123
+ next if line =~ /^agency/
124
+ next if line =~ /^\s/
125
+
126
+ field_array = line.split(/\t/)
127
+ month = field_array[field_map['month_nu']]
128
+ day = field_array[field_map['day_nu']]
129
+ mean = field_array[field_map['mean_va']]
130
+ median = field_array[field_map['p50_va']]
131
+ percentile20 = field_array[field_map['p20_va']]
132
+ percentile80 = field_array[field_map['p80_va']]
133
+
134
+ d = Date.new(1500, month.to_i, day.to_i)
135
+ mean_flows_hash[d] = mean
136
+ median_flows_hash[d] = median
137
+ percentile20_flows_hash[d] = percentile20
138
+ percentile80_flows_hash[d] = percentile80
139
+ end
140
+
141
+ @statistical_mean_flows = mean_flows_hash.sort
142
+ @statistical_median_flows = median_flows_hash.sort
143
+ @statistical_percentile20_flows = percentile20_flows_hash.sort
144
+ @statistical_percentile80_flows = percentile80_flows_hash.sort
145
+ end
146
+ end
147
+ end
148
+
149
+
@@ -0,0 +1,66 @@
1
+ module USGS
2
+ class WaterData
3
+
4
+ class << self
5
+
6
+ def us_rivers
7
+ states = %w{al ar az ca co ct dc de fl ga hi ia id il in ks ky la ma md me mi mn mo ms mt nc nd ne nh nj nm nv ny oh ok or pa ri sc sd tn tx ut va vt wa wi wv wy}
8
+ state_rivers = {}
9
+ states.each do |state|
10
+ STDOUT.write("#{state} ") # REMOVE THIS REMOVE THIS REMOVE THIS
11
+ STDOUT.flush
12
+ state_rivers[state] = rivers_in_state(state)
13
+ end
14
+ state_rivers
15
+ end
16
+
17
+
18
+ def rivers_in_state(st)
19
+ require 'open-uri'
20
+
21
+ url = "http://waterdata.usgs.gov/#{st}/nwis/current/?type=flow&format=rdb"
22
+ rivers = {}
23
+
24
+ open(url).each do |line|
25
+ next if line =~ /^#/
26
+ next if line =~ /^5/
27
+ next if line =~ /^agency/
28
+
29
+ fields = line.split(/\t/)
30
+ station_name = fields[2]
31
+ name_parts = station_name.split(/\b([A-Z]+ OF|ABV|AT|NR|NEAR|DS OF|US OF|ABOVE|BELOW|BEL|BL|BLW|AB|ABV)\b/i)
32
+ river_name = clean_river_name(name_parts[0])
33
+
34
+ rivers[river_name] ||= []
35
+ rivers[river_name] << fields[1]
36
+ end
37
+
38
+ rivers
39
+ end
40
+
41
+
42
+ # Given a river name from the USGS site, a clean and
43
+ # normalized river name is returned.
44
+ #
45
+ def clean_river_name(river_name)
46
+ val = river_name.strip.downcase.gsub(/\b('?[a-z])/) { $1.capitalize }
47
+ val.gsub!(/d'?\s*alene/i, "d'Alene")
48
+ val.gsub!(/[^A-Za-z' ]/, '')
49
+ val.gsub!(/\bSf\b/, 'South Fork')
50
+ val.gsub!(/\bMf\b/, 'Middle Fork')
51
+ val.gsub!(/\bNf\b/, 'North Fork')
52
+ val.gsub!(/\bDiv\b/, 'Diversion')
53
+ val.gsub!(/\bCrk?\b/, 'Creek')
54
+ val.gsub!(/\bC\b/, 'Creek')
55
+ val.gsub!(/\bR\b/, 'River')
56
+ val.gsub!(/\bBra?(nch)?\b/, 'Branch')
57
+ val.gsub!(/\bRvr\b/, 'River')
58
+ val.gsub!(/\bTrib\b/, 'Tributary')
59
+ val.gsub!(/\bSprngs\b/, 'Springs')
60
+ val
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,51 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
2
+
3
+ describe USGS::Gauge do
4
+
5
+ it 'should get mean flow data for a river' do
6
+ gauge = USGS::Gauge.new(13336500)
7
+ mean_flow = gauge.get_statistical_mean_flows
8
+ mean_flow.each do |record|
9
+ puts "Mean flow for the Selway River on #{record[0].strftime("%d %b")} is #{record[1]} CFS"
10
+ end
11
+ end
12
+
13
+ it 'should get median flow data for a river' do
14
+ gauge = USGS::Gauge.new(13336500)
15
+ median_flow = gauge.get_statistical_median_flows
16
+ median_flow.each do |record|
17
+ puts "Median flow for the Selway River on #{record[0].strftime("%d %b")} is #{record[1]} CFS"
18
+ end
19
+ end
20
+
21
+ it 'should get 80th percentile flow data for a river' do
22
+ gauge = USGS::Gauge.new(13336500)
23
+ percentile80_flow = gauge.get_statistical_percentile80_flows
24
+ percentile80_flow.each do |record|
25
+ puts "80th percentile flow for the Selway River on #{record[0].strftime("%d %b")} is #{record[1]} CFS"
26
+ end
27
+ end
28
+
29
+ it 'should get 20th percentile flow data for a river' do
30
+ gauge = USGS::Gauge.new(13336500)
31
+ percentile20_flow = gauge.get_statistical_percentile20_flows
32
+ percentile20_flow.each do |record|
33
+ puts "20th percentile flow for the Selway River on #{record[0].strftime("%d %b")} is #{record[1]} CFS"
34
+ end
35
+ end
36
+
37
+ it 'should get daily mean flows for a river' do
38
+ gauge = USGS::Gauge.new(13336500)
39
+ daily_mean_flows = gauge.get_daily_mean_flows
40
+ daily_mean_flows.each do |record|
41
+ puts "Daily mean flow for the Selway River on #{record[0].strftime("%d %b %Y")} is #{record[1]} CFS"
42
+ end
43
+ end
44
+
45
+ it 'should get the current flow for a river' do
46
+ gauge = USGS::Gauge.new(13336500)
47
+ puts "Latest flow for the Selway River is #{gauge.latest_flow} CFS"
48
+ end
49
+
50
+ end
51
+
@@ -0,0 +1,2 @@
1
+ require 'spec'
2
+ require File.dirname(__FILE__) + '/../lib/usgs'
@@ -0,0 +1,15 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
2
+
3
+ describe USGS::WaterData do
4
+
5
+ it 'should retrieve data' do
6
+ USGS::WaterData.us_rivers.each do |state, rivers|
7
+ puts "#{state}"
8
+ puts '-' * 60
9
+ rivers.each do |river_name, gauge_ids|
10
+ puts " * #{river_name} => #{gauge_ids.join(', ')}"
11
+ end
12
+ end
13
+ end
14
+
15
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ADLongwell-usgs-waterdata
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Aaron Longwell
8
+ - Chris Tenbrink
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2008-10-16 00:00:00 -07:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: A library for obtaining statistical and real-time flows from the Unite States Geological Survey's National Water Information System
18
+ email: ctenbrink@gmail.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files:
24
+ - History.txt
25
+ - Manifest.txt
26
+ - README.txt
27
+ files:
28
+ - History.txt
29
+ - init.rb
30
+ - Manifest.txt
31
+ - License.txt
32
+ - README.txt
33
+ - Rakefile
34
+ - lib/usgs.rb
35
+ - lib/usgs/gauge.rb
36
+ - lib/usgs/water_data.rb
37
+ has_rdoc: true
38
+ homepage: http://github.com/ADLongwell/usgs-waterdata
39
+ post_install_message:
40
+ rdoc_options:
41
+ - --main
42
+ - README.txt
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ requirements: []
58
+
59
+ rubyforge_project:
60
+ rubygems_version: 1.2.0
61
+ signing_key:
62
+ specification_version: 2
63
+ summary: Library for obtaining river flow data.
64
+ test_files:
65
+ - spec/gauge_spec.rb
66
+ - spec/spec_helper.rb
67
+ - spec/waterdata_spec.rb