energy_market 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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