bcl 0.1.7 → 0.1.8

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.
@@ -1,479 +0,0 @@
1
- ######################################################################
2
- # Copyright (c) 2008-2013, Alliance for Sustainable Energy.
3
- # All rights reserved.
4
- #
5
- # This library is free software; you can redistribute it and/or
6
- # modify it under the terms of the GNU Lesser General Public
7
- # License as published by the Free Software Foundation; either
8
- # version 2.1 of the License, or (at your option) any later version.
9
- #
10
- # This library is distributed in the hope that it will be useful,
11
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
- # Lesser General Public License for more details.
14
- #
15
- # You should have received a copy of the GNU Lesser General Public
16
- # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
- ######################################################################
19
-
20
- # Provides programmatic access to the component.xsd schema needed for
21
- # generating the component information that will be uploaded to
22
- # the Building Component Library.
23
-
24
- require 'rubygems'
25
-
26
- require 'pathname'
27
- require 'csv'
28
- require 'builder' #gem install builder (creates xml files)
29
- require 'uuid' # gem install uuid
30
- require 'fileutils'
31
-
32
- require 'bcl/TarBall'
33
-
34
- module BCL
35
-
36
- SCHEMA_LOCATION = "component.xsd"
37
-
38
- ProvStruct = Struct.new(:author, :datetime, :comment)
39
- TagsStruct = Struct.new(:descriptor)
40
- AttrStruct = Struct.new(:name, :value, :datatype, :units)
41
- FileStruct = Struct.new(:version_software_program, :version_id, :fqp_file, :filename, :filetype)
42
- #cost_type is an enumeration (not enforced) of installation, material, operations and maintenance,
43
- #variable operations and maintenance, salvage
44
- CostStruct = Struct.new(:cost_name, :cost_type, :category, :value, :interval,
45
- :interval_units, :year, :location, :units, :currency, :source,
46
- :reference_component_name, :reference_component_id)
47
- ObjectStruct = Struct.new(:obj_type, :obj_instance)
48
-
49
- class Component
50
- attr_accessor :name
51
- attr_accessor :uid
52
- attr_accessor :comp_version_id
53
- attr_accessor :description
54
- attr_accessor :comment
55
- attr_accessor :fidelity_level
56
- attr_accessor :source_manufacturer
57
- attr_accessor :source_model
58
- attr_accessor :source_serial_no
59
- attr_accessor :source_year
60
- attr_accessor :source_url
61
- attr_accessor :tags
62
- attr_accessor :provenance
63
- attr_accessor :attributes
64
- attr_accessor :files
65
- attr_accessor :costs
66
- attr_accessor :objects
67
-
68
- public
69
-
70
- #the save path is where the component will be saved
71
- def initialize(save_path)
72
- @name = "" #this is also a unique identifier to the component...
73
- @uid = UUID.new.generate
74
- @comp_version_id = UUID.new.generate
75
- @description = ""
76
- @comment = ""
77
- @fidelity_level = 0 #restricted to level_1 to level_5
78
- @source_manufacturer = ""
79
- @source_model = ""
80
- @source_serial_no = ""
81
- @source_year = ""
82
- @source_url = ""
83
-
84
- #these items have multiple instances
85
- @provenance = []
86
- @tags = []
87
- @attributes = []
88
- @files = []
89
- @costs = []
90
- @objects = [] #container for saving the idf/osm snippets
91
-
92
- @path = save_path
93
-
94
- #puts "[ComponentXml] " + @path
95
- #need to hit a webservice to validate which tags and attributes are
96
- #available (including units?)
97
-
98
- #todo: validate against master taxonomy
99
- end
100
-
101
- def open_component(filename)
102
- read_component_xml(filename)
103
- end
104
-
105
- # savefile, save the component xml along with
106
- # the files that have been added to the object
107
- def save_tar_gz(delete_files = true)
108
- current_d = Dir.pwd
109
- paths = []
110
-
111
- save_component_xml
112
-
113
- paths << "./component.xml"
114
-
115
- #copy over the files to the directory
116
- @files.each do |file|
117
- src_path = Pathname.new(file.fqp_file)
118
- dest_path = Pathname.new("#{resolve_path}/#{file.filename}")
119
- if File.exists?(src_path)
120
- if src_path == dest_path
121
- #do nothing, file is already where it needs to be
122
- else
123
- #move the file where it needs to go
124
- FileUtils.cp(src_path, dest_path)
125
- end
126
- else
127
- puts "#{src_path} -> File does not exist"
128
- end
129
- paths << "./#{file.filename}"
130
- end
131
-
132
- #take all the files and tar.gz them -- name the file the same as
133
- #the directory
134
-
135
- Dir.chdir("#{resolve_path}")
136
- destination = "#{@name.gsub(" ","_").gsub("/","_").gsub("-","_").gsub("___","_").gsub("__","_").gsub("in.","in").gsub(",","").strip}.tar.gz"
137
-
138
- File.delete(destination) if File.exists?(destination)
139
-
140
- BCL.tarball(destination, paths)
141
-
142
- Dir.chdir(current_d)
143
-
144
- if (delete_files)
145
- @files.each do |file|
146
- if File.exists?(File.dirname(file.fqp_file))
147
- puts "[ComponentXml] Deleting: #{File.dirname(file.fqp_file)}"
148
- FileUtils.rm_rf(File.dirname(file.fqp_file))
149
- end
150
- end
151
- end
152
-
153
- #puts "[ComponentXml] " + Dir.pwd
154
- end
155
-
156
- def add_provenance(author, datetime, comment)
157
- prov = ProvStruct.new
158
- prov.author = author
159
- prov.datetime = datetime
160
- prov.comment = comment
161
-
162
- @provenance << prov
163
- end
164
-
165
- def add_tag(tag_name)
166
- tag = TagsStruct.new
167
- tag.descriptor = tag_name
168
-
169
- @tags << tag
170
- end
171
-
172
- def add_attribute(name, value, units, datatype = nil)
173
- attr = AttrStruct.new
174
- attr.name = name
175
- attr.value = value
176
-
177
- if !datatype.nil?
178
- attr.datatype = datatype
179
- else
180
- attr.datatype = get_datatype(value)
181
- end
182
- attr.units = units
183
-
184
- @attributes << attr
185
- end
186
-
187
- def add_file(version_sp, version_id, fqp_file, filename, filetype)
188
- fs = FileStruct.new
189
- fs.version_software_program = version_sp
190
- fs.version_id = version_id
191
- fs.fqp_file = fqp_file
192
- fs.filename = filename
193
- fs.filetype = filetype
194
-
195
- @files << fs
196
- end
197
-
198
-
199
- def add_cost(cost_name, cost_type, category, value, units, interval, interval_units, year, location, currency,
200
- source, reference_component_name, reference_component_id)
201
- cs = CostStruct.new
202
- cs.cost_name = cost_name
203
- cs.cost_type = cost_type
204
- cs.category = category
205
- cs.value = value
206
- cs.interval = interval
207
- cs.interval_units = interval_units
208
- cs.year = year
209
- cs.location = location
210
- cs.units = units
211
- cs.currency = currency
212
- cs.source = source
213
- cs.reference_component_name = reference_component_name
214
- cs.reference_component_id = reference_component_id
215
-
216
- @costs << cs
217
- end
218
-
219
- def add_object(object_type, object_instance)
220
- ob = ObjectStruct.new
221
- ob.obj_type = object_type
222
- ob.obj_instance = object_instance
223
-
224
- @objects << ob
225
- end
226
-
227
- def resolve_path
228
- FileUtils.mkdir_p(@path) unless File.directory?(@path)
229
- new_path = "#{@path}/#{name.gsub(" ","_").gsub("/","_").gsub("-","_").gsub("___","_").gsub("__","_").gsub("in.","in").gsub(",","").strip}"
230
- FileUtils.mkdir_p(new_path) unless File.directory?(new_path)
231
- result = new_path
232
- end
233
-
234
- def osm_resolve_path
235
- FileUtils.mkdir_p(@path) unless File.directory?(@path)
236
- new_path = "#{@path}/osm_#{name.gsub(" ","_").gsub("/","_").gsub("-","_").gsub("___","_").gsub("__","_").gsub("in.","in").gsub(",","").strip}"
237
- FileUtils.mkdir_p(new_path) unless File.directory?(new_path)
238
- result = new_path
239
- end
240
-
241
- def osc_resolve_path
242
- FileUtils.mkdir_p(@path) unless File.directory?(@path)
243
- new_path = "#{@path}/osc_#{name.gsub(" ","_").gsub("/","_").gsub("-","_").gsub("___","_").gsub("__","_").gsub("in.","in").gsub(",","").strip}"
244
- FileUtils.mkdir_p(new_path) unless File.directory?(new_path)
245
- result = new_path
246
- end
247
-
248
- def resolve_component_path(component_type)
249
- FileUtils.mkdir_p(@path) unless File.directory?(@path)
250
- new_path = @path + '/OpenStudio'
251
- FileUtils.mkdir_p(new_path) unless File.directory?(new_path)
252
- new_path = new_path + "/#{component_type}"
253
- FileUtils.mkdir_p(new_path) unless File.directory?(new_path)
254
- return new_path
255
- end
256
-
257
- def tmp_resolve_path
258
- FileUtils.mkdir_p(@path) unless File.directory?(@path)
259
- new_path = "#{@path}/tmp_#{name.gsub(" ","_").gsub("/","_").gsub("-","_").gsub("___","_").gsub("__","_").gsub("in.","in").gsub(",","").strip}"
260
- FileUtils.mkdir_p(new_path) unless File.directory?(new_path)
261
- result = new_path
262
- end
263
-
264
-
265
- def create_os_component(osobj)
266
- osobj.getCostLineItems.each do |os|
267
- @costs.each do |cost|
268
- #figure out costs for constructions
269
- os.setMaterialCost(cost.value.to_f) if cost.category == "material"
270
- if cost.category == "installation"
271
- os.setInstallationCost(cost.value.to_f)
272
- os.setExpectedLife(cost.interval.to_i)
273
- end
274
- os.setFixedOM(cost.value.to_f) if cost.category == "operations and maintenance"
275
- os.setVariableOM(cost.value.to_f) if cost.category == "variable operations and maintenance"
276
- os.setSalvageCost(cost.value.to_f) if cost.category == "salvage"
277
- end
278
- end
279
- newcomp = osobj.createComponent
280
-
281
- cd = newcomp.componentData
282
- cd.setDescription(@description)
283
- cd.setFidelityLevel(@fidelity_level)
284
-
285
- at = newcomp.componentData.componentDataAttributes
286
- @attributes.each do |attrib|
287
- if (attrib.value.to_s != "") and (attrib.name.to_s != "")
288
- if attrib.units != ""
289
- at.addAttribute(tc(attrib.name), attrib.value, attrib.units)
290
- else
291
- at.addAttribute(tc(attrib.name), attrib.value)
292
- end
293
- end
294
- end
295
-
296
- tg = newcomp.componentData.componentDataTags
297
- comp_tag = ""
298
- @tags.each do |tag|
299
- tg.addTag(tc(tag.descriptor))
300
- if (tag.descriptor != "energyplus") and (tag.descriptor != "construction")
301
- #create a map of component tags to directories
302
- comp_tag = tag.descriptor
303
- if comp_tag == "interior wall"
304
- comp_tag = "interiorwalls"
305
- elsif comp_tag == "exterior wall"
306
- comp_tag = "exteriorwalls"
307
- elsif comp_tag == "exterior slab"
308
- comp_tag = "exteriorslabs"
309
- elsif comp_tag == "exposed floor"
310
- comp_tag = "exposedfloors"
311
- elsif comp_tag == "attic floor"
312
- comp_tag = "atticfloors"
313
- elsif comp_tag == "roof"
314
- comp_tag = "roofs"
315
- elsif comp_tag == "door"
316
- comp_tag = "doors"
317
- elsif comp_tag == "skylight"
318
- comp_tag = "skylights"
319
- elsif comp_tag == "window"
320
- comp_tag = "windows"
321
- end
322
- puts comp_tag
323
- end
324
- end
325
-
326
- return newcomp
327
- end
328
-
329
- def save_component_xml(dir_path = resolve_path)
330
- xmlfile = File.new(dir_path + '/component.xml', 'w')
331
- comp_xml = Builder::XmlMarkup.new(:target => xmlfile, :indent=>2)
332
-
333
- #setup the xml file
334
- comp_xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
335
- comp_xml.component("xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
336
- "xsi:noNamespaceSchemaLocation"=>"#{SCHEMA_LOCATION}") {
337
- comp_xml.name @name
338
- comp_xml.uid @uid
339
- comp_xml.version_id @comp_version_id
340
- comp_xml.description @description if @description != ""
341
- comp_xml.comment @comment if @comment != ""
342
- comp_xml.fidelity_level @fidelity_level
343
-
344
- comp_xml.provenances {
345
- @provenance.each do |prov|
346
- comp_xml.provenance {
347
- comp_xml.author prov.author
348
- comp_xml.datetime prov.datetime
349
- comp_xml.comment prov.comment
350
- }
351
- end
352
- }
353
-
354
- comp_xml.tags {
355
- @tags.each do |tag|
356
- comp_xml.tag tag.descriptor
357
- end
358
- }
359
-
360
- comp_xml.attributes {
361
- @attributes.each do |attrib|
362
- if (attrib.value.to_s != "") and (attrib.name.to_s != "") then
363
- comp_xml.attribute {
364
- comp_xml.name attrib.name
365
- comp_xml.value attrib.value
366
- comp_xml.datatype attrib.datatype
367
- comp_xml.units attrib.units if attrib.units != ""
368
- }
369
- end
370
- end
371
- }
372
-
373
- comp_xml.source {
374
- comp_xml.manufacturer @source_manufacturer if @source_manufacturer != ""
375
- comp_xml.model @source_model if @source_model != ""
376
- comp_xml.serial_no @source_serial_no if @source_serial_no != ""
377
- comp_xml.year @source_year if @source_year != ""
378
- comp_xml.url @source_url if @source_url != ""
379
- }
380
-
381
- if not @files.nil?
382
- comp_xml.files {
383
- @files.each do |file|
384
- comp_xml.file {
385
- comp_xml.version {
386
- comp_xml.software_program file.version_software_program
387
- comp_xml.identifier file.version_id
388
- }
389
-
390
- comp_xml.filename file.filename
391
- comp_xml.filetype file.filetype
392
- }
393
- end
394
- }
395
- end
396
-
397
- #check if we should write out costs, don't write if all values are 0 or nil
398
- #DLM: schema always expects costs
399
- write_costs = true
400
- #if not @costs.nil?
401
- # @costs.each do |cost|
402
- # if (cost.value.nil?) && (not cost.value == 0)
403
- # write_costs = true
404
- # break
405
- # end
406
- # end
407
- #end
408
-
409
- if write_costs
410
- comp_xml.costs {
411
- @costs.each do |cost|
412
- comp_xml.cost {
413
- comp_xml.instance_name cost.cost_name
414
- comp_xml.cost_type cost.cost_type
415
- comp_xml.category cost.category
416
- comp_xml.value cost.value
417
- comp_xml.units cost.units if cost.units != ""
418
- comp_xml.interval cost.interval if cost.interval != ""
419
- comp_xml.interval_units cost.interval_units if cost.interval_units != ""
420
- comp_xml.year cost.year if cost.year != ""
421
- comp_xml.currency cost.currency if cost.currency != ""
422
- comp_xml.source cost.source if cost.source != ""
423
- comp_xml.reference_component_name cost.reference_component_name if cost.reference_component_name != ""
424
- comp_xml.reference_component_id cost.reference_component_id if cost.reference_component_id != ""
425
- }
426
- end
427
- }
428
- end
429
-
430
- }
431
-
432
- xmlfile.close
433
- end
434
-
435
- def get_attribute(attribute_name)
436
- result = nil
437
- @attributes.each do |attr|
438
- if attr.name == attribute_name
439
- result = attr
440
- end
441
- end
442
-
443
- result
444
-
445
- end
446
-
447
- #return the title case of the string
448
- def tc(input)
449
- val = input.gsub(/\b\w/){$&.upcase}
450
- if val.downcase == "energyplus"
451
- val = "EnergyPlus"
452
- end
453
- return val
454
- end
455
-
456
- private
457
-
458
- def get_datatype(input_value)
459
- dt = 'undefined'
460
-
461
- # simple method to test if the input_value is a string, float, or integer.
462
- # First convert the value back to a string for testing (in case it was passed as a float/integer)
463
- test = input_value.to_s
464
- input_value = test.match('\.').nil? ? Integer(test) : Float(test) rescue test.to_s
465
-
466
- if input_value.is_a?(Fixnum) || input_value.is_a?(Bignum)
467
- dt = "int"
468
- elsif input_value.is_a?(Float)
469
- dt = "float"
470
- else
471
- dt = "string"
472
- end
473
-
474
- dt
475
- end
476
-
477
- end
478
-
479
- end # module BCL
@@ -1,94 +0,0 @@
1
- ######################################################################
2
- # Copyright (c) 2008-2013, Alliance for Sustainable Energy.
3
- # All rights reserved.
4
- #
5
- # This library is free software; you can redistribute it and/or
6
- # modify it under the terms of the GNU Lesser General Public
7
- # License as published by the Free Software Foundation; either
8
- # version 2.1 of the License, or (at your option) any later version.
9
- #
10
- # This library is distributed in the hope that it will be useful,
11
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
- # Lesser General Public License for more details.
14
- #
15
- # You should have received a copy of the GNU Lesser General Public
16
- # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
- ######################################################################
19
-
20
- require 'rubygems'
21
- require 'pathname'
22
- require 'fileutils'
23
- require 'enumerator'
24
-
25
- require 'bcl/TarBall'
26
-
27
- module BCL
28
- module_function
29
-
30
- def gather_components(component_dir)
31
- #store the starting directory
32
- current_dir = Dir.pwd
33
-
34
- #an array to hold reporting info about the batches
35
- gather_components_report = []
36
-
37
- #go to the directory containing the components
38
- Dir.chdir(component_dir)
39
-
40
- #delete old gather files first
41
- gather_dest_base = "components.tar.gz"
42
- #File.delete("./gather/" + gather_dest_base) if File.exists?("./0gather/" + gather_dest_base)
43
-
44
- #copy all the components' tar.gz files into a single directory
45
- targzs = Pathname.glob("./**/*.tar.gz")
46
- targzs.each do |targz|
47
- destination = "./0gather/#{File.basename(targz.to_s)}"
48
- puts "copying #{targz.to_s} to #{destination}"
49
- Dir.mkdir("./0gather") unless File.directory?("./0gather") #named so it will be at top of directory list
50
- File.delete(destination) if File.exists?(destination)
51
- FileUtils.cp(targz.to_s, destination)
52
- end
53
-
54
- #go into that directory
55
- Dir.chdir("./0gather")
56
-
57
- #get a list of all the tar.gz files in the new directory
58
- targzs = Pathname.glob("*.tar.gz")
59
-
60
- #report the total number of components in the directory
61
- gather_components_report << "Total components = #{targzs.length}"
62
-
63
- #define an iterator to keep track of the number of batches
64
- batch_num = 0
65
-
66
- #package all the tar.gzs in the directory into a few master tar.gz files of 1000 components or less
67
- targzs.each_slice(1000) do |batch|
68
-
69
- gather_components_report << " batch #{batch_num} contains #{batch.length} components"
70
-
71
- #put all the paths in the batch into an array
72
- paths = []
73
- batch.each do |targz|
74
- paths << File.basename(targz.to_s)
75
- end
76
-
77
- #path where the batch tarball is going
78
- gather_dest = "0_#{batch_num}_#{gather_dest_base}" #prefix to move to top of directory
79
-
80
- #tar up the batch
81
- tarball(gather_dest, paths)
82
-
83
- batch_num += 1
84
- end
85
-
86
- #report out
87
- puts gather_components_report
88
-
89
- #change back to the directory where we started
90
- Dir.chdir(current_dir)
91
-
92
- end
93
-
94
- end # module BCL
@@ -1,116 +0,0 @@
1
- ######################################################################
2
- # Copyright (c) 2008-2013, Alliance for Sustainable Energy.
3
- # All rights reserved.
4
- #
5
- # This library is free software; you can redistribute it and/or
6
- # modify it under the terms of the GNU Lesser General Public
7
- # License as published by the Free Software Foundation; either
8
- # version 2.1 of the License, or (at your option) any later version.
9
- #
10
- # This library is distributed in the hope that it will be useful,
11
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
- # Lesser General Public License for more details.
14
- #
15
- # You should have received a copy of the GNU Lesser General Public
16
- # License along with this library; if not, write to the Free Software
17
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
- ######################################################################
19
-
20
- #Mongo Record to Component
21
- require 'rubygems'
22
- require 'bcl/ComponentXml'
23
-
24
- module BCL
25
-
26
- class MongoToComponent
27
- attr_accessor :component
28
- attr_accessor :error_message
29
-
30
- def initialize(record)
31
- @component = nil
32
- @error_message = ""
33
-
34
- if record.has_key? "general"
35
- @component = BCL::Component.new('tmp')
36
- general = record["general"]
37
-
38
- #add uid/vid
39
- if record.has_key? "unique_id"
40
- component.uid = record["unique_id"]
41
- else
42
- @error_message = "Invalid Mongo record: no unique_id"
43
- end
44
- if record.has_key? "version_id"
45
- component.comp_version_id = record["version_id"]
46
- else
47
- @error_message = "Invalid Mongo record: no version_id"
48
- end
49
-
50
- #add general info
51
- if general.has_key? "name"
52
- component.name = general["name"]
53
- end
54
- if general.has_key? "description"
55
- @component.description = general["description"]
56
- end
57
- if general.has_key? "fidelity_level"
58
- @component.fidelity_level = general["fidelity_level"]
59
- end
60
- if general.has_key? "source_manufacturer"
61
- @component.source_manufacturer = general["source_manufacturer"]
62
- end
63
- if general.has_key? "source_url"
64
- @component.source_url = general["source_url"]
65
- end
66
-
67
- #add tags
68
- if general.has_key? "tags"
69
- tags = general["tags"]
70
- tags.each do |name,value|
71
- @component.add_tag(value)
72
- end
73
- end
74
-
75
- #add attributes
76
- if general.has_key? "attributes"
77
- attribute_container = general["attributes"]
78
- attribute_container.each do |a,attributes|
79
- #attributes iterator is an array of hashes
80
- #NOTE: double check this...could be old messed-up structure?
81
- attributes.each do |attribute|
82
- name = ""
83
- units = ""
84
- value = ""
85
- datatype = ""
86
- if attribute.has_key? "name"
87
- name = attribute["name"]
88
- end
89
- if attribute.has_key? "value"
90
- value = attribute["value"]
91
- end
92
- if attribute.has_key? "units"
93
- units = attribute["units"]
94
- end
95
- @component.add_attribute(name, value, units)
96
-
97
- #TODO: eventually find a way to validate the datatype in record with datatype in component
98
- end
99
- end
100
- end
101
-
102
- #todo: add provenance
103
-
104
- else
105
- @error_message = "Invalid Mongo record: no 'general' section"
106
- end
107
- #set component to NIL if there were errors
108
- if !@error_message == nil
109
- @component = nil
110
- end
111
- end
112
-
113
- end
114
-
115
- end # module BCL
116
-