energy_market 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a226c96bc53007cdb23c9c9f1d3dd22207eecd39
4
+ data.tar.gz: 531b336f09b2c17860fbfe5c175bd14a7a3f10fc
5
+ SHA512:
6
+ metadata.gz: f9ec2c23c234e0663b8c4aeec61e039afaf61e7c168fa6e9a8cd72d5a18778ad9a937fadee99c5ff3bb10946be32fd6dc1bc5fff175fe5fef3a230e48cd379e7
7
+ data.tar.gz: 9d38e26e8e2bf449b38c40ff3bdaa279d584c8eefadf7f7d1b6af076e9e9ae2121abe1d674fa6e0300dc1dd570bdae0ba485a3a96a1982242d58d49233692fea
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in energy_market.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Iwan Buetti
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # EnergyMarket
2
+
3
+ [![Build Status](https://travis-ci.org/iwan/energy_market.png)](https://travis-ci.org/iwan/energy_market)
4
+ [![Code Climate](https://codeclimate.com/repos/52a049e813d637419e007ea3/badges/4494ed8a31e52b80f8d7/gpa.png)](https://codeclimate.com/repos/52a049e813d637419e007ea3/feed)
5
+
6
+ TODO: Write a gem description
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'energy_market'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install energy_market
21
+
22
+ ## Usage
23
+
24
+ TODO: Write usage instructions here
25
+
26
+ ## Contributing
27
+
28
+ 1. Fork it
29
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
30
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
31
+ 4. Push to the branch (`git push origin my-new-feature`)
32
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ end
7
+
8
+ desc "Run tests"
9
+ task :default => :test
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'energy_market/version'
5
+ require 'date' # used for get Date.today
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "energy_market"
9
+ spec.version = EnergyMarket::VERSION
10
+ spec.authors = ["Iwan Buetti"]
11
+ spec.email = ["iwan.buetti@gmail.com"]
12
+ spec.description = "No description"
13
+ spec.summary = "Collection of classes used for energy (electricity and gas) market monitoring and calculation"
14
+ spec.homepage = "https://github.com/iwan/energy_market"
15
+ spec.license = "MIT"
16
+ spec.date = Date.today.to_s
17
+
18
+ spec.files = `git ls-files`.split($/)
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+
26
+ spec.add_dependency('activesupport', '~> 3.2')
27
+ spec.add_dependency('tzinfo', '~> 0.3.29') # '~> 1.1.0'
28
+ end
@@ -0,0 +1,9 @@
1
+
2
+ module EnergyMarket
3
+
4
+
5
+
6
+
7
+ end
8
+
9
+
@@ -0,0 +1,29 @@
1
+ module EnergyMarket
2
+ module MyUtil
3
+
4
+ # Return the max value of the arguments
5
+ # Use: max_among(4,9) or max_among(4,9,-6,2)
6
+ def max_among(*arr)
7
+ return nil if arr.nil? || arr.empty?
8
+ arr = arr.first if arr.first.is_a?(Array)
9
+ arr.max
10
+ end
11
+
12
+ # Return the min value of the arguments
13
+ # Use: min_among(4,9) or min_among(4,9,-6,2)
14
+ def min_among(*arr)
15
+ return nil if arr.nil? || arr.empty?
16
+ arr = arr.first if arr.first.is_a?(Array)
17
+ arr.min
18
+ end
19
+ end
20
+
21
+ end
22
+
23
+ # include EnergyMarket::MyUtil
24
+
25
+ # puts max_among(3.4, 3, 2, 5.8)
26
+ # puts max_among()
27
+ # puts max_among nil
28
+
29
+ # puts max_among([3.4, 3, 2, 5.8])
@@ -0,0 +1,6 @@
1
+ module EnergyMarket
2
+
3
+ class ValuesArray < Array
4
+
5
+ end
6
+ end
@@ -0,0 +1,353 @@
1
+ require 'active_support/core_ext/time/zones'
2
+ require 'active_support/core_ext/time/calculations'
3
+ require 'active_support/core_ext/numeric/time'
4
+
5
+ module EnergyMarket
6
+
7
+ class Vector
8
+ include EnergyMarket::MyUtil
9
+
10
+ attr_reader :start_time, :v, :step
11
+ @@valid_units = [:hour, :day, :month, :year]
12
+
13
+
14
+ def initialize(start_time=nil, options={})
15
+ options = {:unit => :hour}.merge(options)
16
+ Time.zone = options[:zone] if options[:zone]
17
+
18
+ @start_time = floor_start_time(read_start_time(start_time), options[:unit])
19
+ empty_data
20
+ end
21
+
22
+
23
+ # Clone the current object
24
+ def clone
25
+ @v.nil? ? Vector.new(@start_time) : Vector.new(@start_time).data(@v.clone)
26
+ end
27
+
28
+
29
+ # Set the array of values. You can define the unit (granularity) of those data.
30
+ # By default the unit is :hour
31
+ def data(data, unit=:hour)
32
+ unit = unit.to_sym
33
+ data = [data] unless data.is_a? Array
34
+ empty_data
35
+ validate_unit unit
36
+ start_time = (@start_time.nil? ? nil : @start_time.clone)
37
+
38
+ # the values are always stored as hour values
39
+ if unit==:hour
40
+ @v = data
41
+ else
42
+ prev_value = start_time.send(unit)
43
+ data.each do |v|
44
+ while start_time.send(unit)==prev_value
45
+ @v << v
46
+ start_time+=1.hour
47
+ end
48
+ prev_value = start_time.send(unit)
49
+ end
50
+ end
51
+ self
52
+ end
53
+
54
+
55
+ def set_all_to(value)
56
+ @v = @v.map{|e| e=value}
57
+ end
58
+
59
+
60
+ # get the sum of the values
61
+ def sum(options = {})
62
+ if options[:values]
63
+ case options[:values]
64
+ when :positive, :not_negative
65
+ @v.inject(0.0){|total, n| total + (n>0.0 ? n : 0.0) }
66
+ when :negative, :not_positive
67
+ @v.inject(0.0){|total, n| total + (n<0.0 ? n : 0.0) }
68
+ when :zero
69
+ 0.0
70
+ when :all, :not_zero
71
+ sum_all_elements
72
+ else
73
+ raise ArgumentError, "Option not recognized"
74
+ end
75
+ else
76
+ sum_all_elements
77
+ end
78
+ end
79
+
80
+
81
+ # Count the values
82
+ def count(options = {})
83
+ return count_all_elements if !options[:values]
84
+ case options[:values]
85
+ when :positive
86
+ @v.count{|e| e>0.0}
87
+ when :negative
88
+ @v.count{|e| e<0.0}
89
+ when :not_positive
90
+ @v.count{|e| e<=0.0}
91
+ when :not_negative
92
+ @v.count{|e| e>=0.0}
93
+ when :not_zero
94
+ @v.count{|e| e!=0.0}
95
+ when :zero
96
+ @v.count{|e| e==0.0}
97
+ when :all
98
+ count_all_elements
99
+ else
100
+ raise ArgumentError, "Option not recognized"
101
+ end
102
+ end
103
+
104
+
105
+ # Return the mean of values
106
+ def mean(options = {})
107
+ c = count(options)
108
+ return nil if c.zero? # if the array is empty will be returned nil
109
+ sum(options) / c
110
+ end
111
+
112
+
113
+ def minimum_value
114
+ @v.compact.min
115
+ rescue
116
+ nil
117
+ end
118
+
119
+ def maximum_value
120
+ @v.compact.max
121
+ rescue
122
+ nil
123
+ end
124
+
125
+
126
+ def round!(ndigit=3)
127
+ @v.collect!{|e| e.nil? ? nil : e.round(ndigit)}
128
+ end
129
+
130
+
131
+ # Return an array with two objects:
132
+ # - an array of HourNumber element (one HourNumber for each hour). The hours are not necessarily consecutive
133
+ # - an array of values (float or integers) (one HourNumber for each hour). The hours are not necessarily consecutive
134
+ def xy_array(options={})
135
+
136
+ values=[]
137
+ if options[:values]
138
+ case options[:values]
139
+ when :positive
140
+ values = @v.collect{|v| v if v>0.0}
141
+ when :negative
142
+ values = @v.collect{|v| v if v<0.0}
143
+ when :not_positive
144
+ values = @v.collect{|v| v if v<=0.0}
145
+ when :not_negative
146
+ values = @v.collect{|v| v if v>=0.0}
147
+ when :not_zero
148
+ values = @v.collect{|v| v if v!=0.0}
149
+ when :zero
150
+ values = @v.collect{|v| v if v==0.0}
151
+ when :all
152
+ values = @v.clone
153
+ else
154
+ raise ArgumentError, "Option not recognized"
155
+ end
156
+ else
157
+ values = @v.clone
158
+ end
159
+ hn = Array.new(@v.size, @start_time)
160
+ @v.size.times do |i|
161
+ if values[i].nil?
162
+ hn[i] = nil
163
+ else
164
+ hn[i]+=i.hours
165
+ end
166
+ end
167
+ [hn.compact, values.compact]
168
+ end
169
+
170
+
171
+ def end_time
172
+ return nil if empty?
173
+ @start_time + (@v.size-1).hours
174
+ end
175
+
176
+ def empty?
177
+ @v.nil? || @v.empty?
178
+ end
179
+
180
+ def empty_data
181
+ @v = @start_time.nil? ? nil : ValuesArray.new
182
+ end
183
+
184
+ def aligned_with?(v)
185
+ self.start_time==v.start_time && @v.size==v.size
186
+ end
187
+
188
+ def align_with(v)
189
+ @start_time = v.start_time if @start_time.nil? # ====
190
+ s = [start_time, v.start_time].max
191
+ if end_time.nil? || v.end_time.nil? || s>(e = [end_time, v.end_time].min)
192
+ empty_data
193
+ else
194
+ data_ary(((s-start_time)/3600).to_i, 1+((e-s)/3600).to_i)
195
+ end
196
+ @start_time = s
197
+ end
198
+
199
+
200
+ def size
201
+ @v.size
202
+ end
203
+
204
+ def to_s
205
+ "Start time: #{@start_time}\nData (size: #{@v.size}):\n#{print_values}"
206
+ end
207
+
208
+ def print_values
209
+ start_time = @start_time - 1.hour
210
+ @v.collect{|v| "#{(start_time+=1.hour).strftime('%Y-%m-%d %H:%M %a')}\t#{v}" }.join("\n")
211
+ end
212
+
213
+ def until_the_end_of_the_year(fill_value=0.0)
214
+ t = Time.zone.parse("#{@start_time.year+1}-01-01")
215
+ hh = (t-@start_time)/( 60 * 60) # final size
216
+ @v += ValuesArray.new(hh-@v.size, fill_value) if hh>@v.size
217
+ self
218
+ end
219
+
220
+ def +(vec)
221
+ oper(vec, :+)
222
+ end
223
+
224
+ def -(vec)
225
+ oper(vec, :-)
226
+ end
227
+
228
+ def *(vec)
229
+ oper(vec, :*)
230
+ end
231
+
232
+ def /(vec)
233
+ oper(vec, :/)
234
+ end
235
+
236
+ # v1.max(v2) return a new obj where which element is the max between the elements of v1 and v2
237
+ # v2 can also be of type Numeric
238
+ def max(vec=0.0)
239
+ min_max(vec, :max_among)
240
+ end
241
+
242
+ def min(vec=0.0)
243
+ min_max(vec, :min_among)
244
+ end
245
+
246
+ def value(index)
247
+ @v[index]
248
+ end
249
+
250
+ def first_values(number)
251
+ @v[0,number]
252
+ end
253
+
254
+ def set_value(index, new_value)
255
+ @v[index]=new_value
256
+ end
257
+
258
+
259
+ private
260
+
261
+ def data_ary(start, length)
262
+ @v = @v[start, length]
263
+ end
264
+
265
+ def min_max(vec, method)
266
+ return self if vec.nil?
267
+ c = self.clone
268
+ if vec.is_a? Numeric # Fixnum or Float...
269
+ default_value = vec
270
+ else
271
+ c.align_with(vec)
272
+ end
273
+ c.size.times do |i|
274
+ c.set_value(i, self.send(method, c.value(i), default_value || vec.value(i)))
275
+ end
276
+ c
277
+ end
278
+
279
+
280
+ def oper(vec, op)
281
+ return self if vec.nil?
282
+
283
+ c = self.clone
284
+ if vec.is_a? Numeric # Fixnum or Float...
285
+ default_value = vec
286
+ else
287
+ c.align_with(vec)
288
+ end
289
+
290
+ c.data(Array.new(vec.size){[:+, :-].include?(op) ? 0.0 : 1.0}) if @v.nil?
291
+ c.size.times do |i|
292
+ c.set_value(i, c.value(i).to_f.send(op, (default_value || vec.value(i) || 0.0)))
293
+ end
294
+ c
295
+ end
296
+
297
+
298
+ def floor_start_time(t, unit=:hour)
299
+ return nil if t.nil?
300
+ case unit
301
+ # when :'15minutes'
302
+ # t = t - t.sec - (60 * (t.min % 15)) # floor to hour
303
+ when :hour
304
+ t = Time.zone.parse("#{t.year}-#{t.month}-#{t.day} #{t.hour}:00:00")
305
+ # t = t - t.sec - (60 * (t.min % 60)) # floor to hour
306
+ when :day
307
+ t = Time.zone.parse("#{t.year}-#{t.month}-#{t.day}")
308
+ when :month
309
+ t = Time.zone.parse("#{t.year}-#{t.month}-01")
310
+ when :year
311
+ t = Time.zone.parse("#{t.year}-01-01")
312
+ end
313
+ t
314
+ end
315
+
316
+
317
+ def read_start_time(start_time)
318
+ # start_time = Time.zone.now if start_time.nil? # ====
319
+ if start_time.is_a?(String)
320
+ start_time.gsub!("/", "-")
321
+ begin
322
+ start_time = Time.zone.parse(start_time)
323
+ rescue Exception => e
324
+ case start_time.size
325
+ when 2
326
+ start_time = Time.zone.parse("20#{start_time}-01-01")
327
+ when 4
328
+ start_time = Time.zone.parse("#{start_time}-01-01")
329
+ when 7
330
+ start_time = Time.zone.parse("#{start_time}-01")
331
+ else
332
+ raise ArgumentError, "Start time not valid"
333
+ end
334
+ end
335
+ end
336
+ start_time
337
+ end
338
+
339
+
340
+ def sum_all_elements
341
+ @v.inject(0.0){|total, n| total + (n||0.0) }
342
+ end
343
+
344
+ def count_all_elements
345
+ @v.size
346
+ end
347
+
348
+ def validate_unit(unit)
349
+ raise ArgumentError, "Time unit is not valid" if !@@valid_units.include? unit
350
+ end
351
+ end
352
+
353
+ end
@@ -0,0 +1,3 @@
1
+ module EnergyMarket
2
+ VERSION = "0.0.4"
3
+ end
@@ -0,0 +1,14 @@
1
+ # require "energy_market/version"
2
+ # require "energy_market/energy_market"
3
+
4
+ %w(
5
+ my_util
6
+ version
7
+ energy_market
8
+ vector
9
+ values_array
10
+ ).each { |file| require File.join(File.dirname(__FILE__), 'energy_market', file) }
11
+
12
+ module EnergyMarket
13
+ # Your code goes here...
14
+ end