lodging 0.0.12 → 0.0.13
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +26 -0
- data/Gemfile +9 -0
- data/LICENSE-PREAMBLE +52 -0
- data/Rakefile +8 -0
- data/VERSION +1 -0
- data/certification_changelog.markdown +11 -0
- data/dot.rvmrc +9 -0
- data/features/lodging_committees.feature +356 -171
- data/features/lodging_impacts.feature +74 -0
- data/features/support/db/fixtures/census_divisions.csv +2 -0
- data/features/support/db/fixtures/climate_divisions.csv +2 -0
- data/features/support/db/fixtures/commercial_building_energy_consumption_survey_responses.csv +11 -0
- data/features/support/db/fixtures/countries.csv +4 -0
- data/features/support/db/fixtures/egrid_countries.csv +2 -0
- data/features/support/db/fixtures/egrid_regions.csv +2 -0
- data/features/support/db/fixtures/egrid_subregions.csv +3 -0
- data/features/support/db/fixtures/fuel_years.csv +2 -0
- data/features/support/db/fixtures/fuels.csv +4 -0
- data/features/support/db/fixtures/lodging_classes.csv +4 -0
- data/features/support/db/fixtures/lodging_properties.csv +5 -0
- data/features/support/db/fixtures/states.csv +2 -0
- data/features/support/db/fixtures/zip_codes.csv +4 -0
- data/features/support/env.rb +18 -1
- data/features/support/lodging_property.rb +26 -0
- data/{lib/test_support → features/support}/lodging_record.rb +1 -4
- data/lib/lodging.rb +1 -0
- data/lib/lodging/cbecs.rb +31 -0
- data/lib/lodging/characterization.rb +19 -3
- data/lib/lodging/data.rb +22 -8
- data/lib/lodging/impact_model.rb +544 -0
- data/lib/lodging/relationships.rb +3 -1
- data/lib/lodging/version.rb +5 -0
- data/lodging.gemspec +31 -0
- data/todo.txt +5 -0
- metadata +76 -119
- data/features/lodging_emissions.feature +0 -53
- data/lib/lodging/carbon_model.rb +0 -265
- data/lib/lodging/fallback.rb +0 -10
@@ -0,0 +1,74 @@
|
|
1
|
+
Feature: Lodging Emissions Calculations
|
2
|
+
The lodging model should generate correct emission calculations
|
3
|
+
|
4
|
+
Background:
|
5
|
+
Given a Lodging
|
6
|
+
|
7
|
+
Scenario: Calculations starting from nothing
|
8
|
+
Given a lodging has nothing
|
9
|
+
When impacts are calculated
|
10
|
+
Then the amount of "carbon" should be within "0.005" of "28.62"
|
11
|
+
|
12
|
+
Scenario Outline: Calculations starting from date
|
13
|
+
Given it has "date" of "<date>"
|
14
|
+
And it has "timeframe" of "<timeframe>"
|
15
|
+
When impacts are calculated
|
16
|
+
Then the amount of "carbon" should be within "0.005" of "<carbon>"
|
17
|
+
Examples:
|
18
|
+
| date | timeframe | carbon |
|
19
|
+
| 2011-01-15 | 2011-01-01/2012-01-01 | 28.62 |
|
20
|
+
| 2012-01-15 | 2011-01-01/2012-01-01 | 0.0 |
|
21
|
+
|
22
|
+
Scenario: Calculations starting from rooms and duration
|
23
|
+
Given it has "rooms" of "2"
|
24
|
+
And it has "duration" of "172800"
|
25
|
+
When impacts are calculated
|
26
|
+
Then the amount of "carbon" should be within "0.005" of "114.47"
|
27
|
+
|
28
|
+
Scenario Outline: Calculations from fuzzy inference based on country degree days
|
29
|
+
Given it has "rooms" of "2"
|
30
|
+
And it has "duration" of "172800"
|
31
|
+
And it has "country.iso_3166_code" of "<country>"
|
32
|
+
And it has "state.postal_abbreviation" of "<state>"
|
33
|
+
When impacts are calculated
|
34
|
+
Then the amount of "carbon" should be within "0.005" of "<carbon>"
|
35
|
+
Examples:
|
36
|
+
| country | state | carbon |
|
37
|
+
| VI | | 114.47 |
|
38
|
+
| GB | | 189.56 |
|
39
|
+
| US | | 131.28 |
|
40
|
+
| | CA | 131.28 |
|
41
|
+
|
42
|
+
Scenario Outline: Calculations from fuzzy inference
|
43
|
+
Given it has "rooms" of "2"
|
44
|
+
And it has "duration" of "172800"
|
45
|
+
And it has "property.northstar_id" of "<id>"
|
46
|
+
And it has "zip_code.name" of "<zip>"
|
47
|
+
And it has "city" of "<city>"
|
48
|
+
And it has "state.postal_abbreviation" of "<state>"
|
49
|
+
When impacts are calculated
|
50
|
+
Then the amount of "carbon" should be within "0.005" of "<carbon>"
|
51
|
+
Examples:
|
52
|
+
| id | zip | city | state | carbon | notes |
|
53
|
+
| 1 | 94122 | | | 86.85 | dd from climate divizion; fuzzy from property attributes |
|
54
|
+
| 1 | | San Francisco | CA | 122.33 | dd from country; fuzzy from property attributes |
|
55
|
+
| 2 | 94133 | | | 94.24 | dd from country; fuzzy from property attributes |
|
56
|
+
| 2 | | San Francisco | CA | 94.24 | dd from country; fuzzy from property attributes |
|
57
|
+
| 3 | 94014 | | | 128.13 | dd from country; fuzzy from property attributes |
|
58
|
+
|
59
|
+
Scenario: Calculations from all user inputs
|
60
|
+
Given it has "rooms" of "2"
|
61
|
+
And it has "duration" of "172800"
|
62
|
+
And it has "country.iso_3166_code" of "GB"
|
63
|
+
And it has "heating_degree_days" of "2700"
|
64
|
+
And it has "cooling_degree_days" of "100"
|
65
|
+
And it has "property_rooms" of "100"
|
66
|
+
And it has "floors" of "3"
|
67
|
+
And it has "construction_year" of "1993"
|
68
|
+
And it has "ac_coverage" of "0.5"
|
69
|
+
And it has "refrigerator_coverage" of "0.6"
|
70
|
+
And it has "hot_tubs" of "6"
|
71
|
+
And it has "indoor_pools" of "5"
|
72
|
+
And it has "outdoor_pools" of "5"
|
73
|
+
When impacts are calculated
|
74
|
+
Then the amount of "carbon" should be within "0.005" of "208.83"
|
@@ -0,0 +1,11 @@
|
|
1
|
+
id,heating_degree_days,cooling_degree_days,lodging_rooms,floors,construction_year,percent_cooled,natural_gas_per_room_night,fuel_oil_per_room_night,electricity_per_room_night,district_heat_per_room_night,weighting
|
2
|
+
1,5500,400,10,1,1967,1,0,1.9,12,0,1700
|
3
|
+
2,1500,1200,35,2,1988,0.6,0,0,14,0,420
|
4
|
+
3,200,2700,100,4,2000,1,1.2,0,34,0,125
|
5
|
+
4,2300,900,2,1,1992,1,0,0,23,0,1770
|
6
|
+
5,2300,700,1000,25,1986,1,11,0.015,120,0,135
|
7
|
+
6,3800,200,7,4,1881,0,0,0,9.2,0,1925
|
8
|
+
7,800,1700,125,3,2002,1,1.9,0,27,0,240
|
9
|
+
8,3300,400,10,2,1920,0,0,6.1,11,0,1925
|
10
|
+
9,1000,1700,14,2,1950,1,9.7,0,83,180,365
|
11
|
+
10,2400,800,450,25,1929,1,0.74,0.00092,41,97,120
|
@@ -0,0 +1,4 @@
|
|
1
|
+
iso_3166_code,iso_3166_alpha_3_code,heating_degree_days,cooling_degree_days,electricity_emission_factor,electricity_loss_factor,lodging_occupancy_rate,lodging_natural_gas_intensity,lodging_fuel_oil_intensity,lodging_electricity_intensity,lodging_district_heat_intensity
|
2
|
+
US,USA,2200,880,0.59000,0.06025,0.6,2.0,0.4,33.9,1.8
|
3
|
+
GB,GBR,2800,60,0.9,0.1,0.5,3.0,0.5,60.0,0.0
|
4
|
+
VI,VIR
|
@@ -0,0 +1,5 @@
|
|
1
|
+
northstar_id,name,city,locality,postcode,country_iso_3166_alpha_3_code,lodging_rooms,floors,construction_year,ac_coverage,lodging_class_name,fridge_coverage,mini_bar_coverage,hot_tubs,pools_indoor,pools_outdoor
|
2
|
+
1,Courtyard by Marriott,San Francisco,California,94122,USA,100,3,1993,0.5,Motel,0.5,0.6,6,6,6
|
3
|
+
2,Hilton San Francisco,San Francisco,California,94133,USA,50,2,2002,1,Hotel,0.5,,0,0,0
|
4
|
+
3,Pacific Inn,Daly City,California,94014,USA,25,,,,Inn,,0.5,1,1,1
|
5
|
+
4,,,,,,,,,,,0.6,0.5,5,5,5
|
data/features/support/env.rb
CHANGED
@@ -3,6 +3,23 @@ Bundler.setup
|
|
3
3
|
|
4
4
|
require 'cucumber'
|
5
5
|
require 'cucumber/formatter/unicode'
|
6
|
+
require 'rspec'
|
7
|
+
require 'rspec/expectations'
|
8
|
+
require 'cucumber/rspec/doubles'
|
9
|
+
|
10
|
+
require 'data_miner'
|
11
|
+
DataMiner.logger = Logger.new(nil)
|
6
12
|
|
7
13
|
require 'sniff'
|
8
|
-
|
14
|
+
|
15
|
+
# need to require this before initializing Sniff for LodgingProperty fixture to be loaded
|
16
|
+
require File.expand_path('../lodging_property', __FILE__)
|
17
|
+
|
18
|
+
Sniff.init File.join(File.dirname(__FILE__), '..', '..'),
|
19
|
+
:adapter => 'mysql2',
|
20
|
+
:database => 'test_lodging',
|
21
|
+
:username => 'root',
|
22
|
+
:password => 'password',
|
23
|
+
:earth => [:hospitality, :fuel, :locality],
|
24
|
+
:cucumber => true,
|
25
|
+
:logger => 'log/test_log.txt'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# LodgingProperty is defined in CM1 rather than Earth, so we need to define it here for testing
|
2
|
+
class LodgingProperty < ActiveRecord::Base
|
3
|
+
col :northstar_id
|
4
|
+
col :name
|
5
|
+
col :city
|
6
|
+
col :locality # state / province / etc.
|
7
|
+
col :postcode # zip code / postal code / etc.
|
8
|
+
col :country_iso_3166_alpha_3_code
|
9
|
+
col :chain_name
|
10
|
+
col :lodging_rooms, :type => :integer
|
11
|
+
col :floors, :type => :integer
|
12
|
+
col :construction_year, :type => :integer
|
13
|
+
col :lodging_class_name
|
14
|
+
col :ac_coverage, :type => :float
|
15
|
+
col :mini_bar_coverage, :type => :float
|
16
|
+
col :fridge_coverage, :type => :float
|
17
|
+
col :hot_tubs, :type => :float # float b/c fallback needs to be a float
|
18
|
+
col :pools_indoor, :type => :float # float b/c fallback needs to be a float
|
19
|
+
col :pools_outdoor, :type => :float # float b/c fallback needs to be a float
|
20
|
+
|
21
|
+
# based on LodgingProperty as of 2012-02-21
|
22
|
+
falls_back_on :fridge_coverage => 0.6,
|
23
|
+
:hot_tubs => 0.3,
|
24
|
+
:pools_indoor => 0.3,
|
25
|
+
:pools_outdoor => 0.6
|
26
|
+
end
|
data/lib/lodging.rb
CHANGED
@@ -3,5 +3,6 @@ require 'emitter'
|
|
3
3
|
module BrighterPlanet
|
4
4
|
module Lodging
|
5
5
|
extend BrighterPlanet::Emitter
|
6
|
+
scope 'The lodging emission estimate is the anthropogenic emissions from lodging room energy use. It includes CO2 emissions from direct fuel combustion and indirect fuel combustion to generate purchased electricity.'
|
6
7
|
end
|
7
8
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'fuzzy_infer'
|
2
|
+
|
3
|
+
class CommercialBuildingEnergyConsumptionSurveyResponse < ActiveRecord::Base
|
4
|
+
fuzzy_infer :target => [:natural_gas_per_room_night, :fuel_oil_per_room_night, :electricity_per_room_night, :district_heat_per_room_night], # list of columns that this model is designed to infer
|
5
|
+
:basis => [:heating_degree_days, :cooling_degree_days, :lodging_rooms, :floors, :construction_year, :percent_cooled], # list of columns that are believed to affect energy use (aka MU)
|
6
|
+
:sigma => "(STDDEV_SAMP(:column)/5)+(ABS(AVG(:column)-:value)/3)", # empirically determined formula (SQL!) that captures the desired sample size once all the weights are compiled, across the full range of possible mu values
|
7
|
+
:membership => :energy_use_membership, # name of instance method to be called on kernel
|
8
|
+
:weight => :weighting # (optional) a pre-existing row weighting, if any, provided by the dataset authors
|
9
|
+
|
10
|
+
# empirically determined formula that minimizes variance between real and predicted energy use
|
11
|
+
# SQL! - :heating_degree_days_n_w will be replaced with, for example, `tmp_table_9301293.hdd_normalized_weight`
|
12
|
+
def energy_use_membership(basis)
|
13
|
+
keys = basis.keys
|
14
|
+
|
15
|
+
unless keys.include?(:heating_degree_days) and keys.include?(:cooling_degree_days)
|
16
|
+
raise ArgumentError, "[lodging] Must provide at least :heating_degree_days and :cooling_degree_days"
|
17
|
+
end
|
18
|
+
|
19
|
+
formula = ['(POW(:heating_degree_days_n_w, 0.8) + POW(:cooling_degree_days_n_w, 0.8))']
|
20
|
+
if keys.include?(:lodging_rooms) and keys.include?(:floors)
|
21
|
+
formula << '(POW(:lodging_rooms_n_w, 0.8) + POW(:floors_n_w, 0.8))'
|
22
|
+
elsif keys.include? :lodging_rooms
|
23
|
+
formula << 'POW(:lodging_rooms_n_w, 0.8)'
|
24
|
+
elsif keys.include? :floors
|
25
|
+
formula << 'POW(:floors_n_w, 0.8)'
|
26
|
+
end
|
27
|
+
formula << 'POW(:percent_cooled_n_w, 0.8)' if keys.include?(:percent_cooled)
|
28
|
+
formula << 'POW(:construction_year_n_w, 0.8)' if keys.include?(:construction_year)
|
29
|
+
formula.join(' * ')
|
30
|
+
end
|
31
|
+
end
|
@@ -3,11 +3,27 @@ module BrighterPlanet
|
|
3
3
|
module Characterization
|
4
4
|
def self.included(base)
|
5
5
|
base.characterize do
|
6
|
-
has :
|
6
|
+
has :date
|
7
|
+
has :rooms
|
8
|
+
has :duration, :measures => :time
|
7
9
|
has :zip_code
|
10
|
+
has :city
|
8
11
|
has :state
|
9
|
-
has :
|
10
|
-
has :
|
12
|
+
has :country
|
13
|
+
has :lodging_class
|
14
|
+
has :heating_degree_days
|
15
|
+
has :cooling_degree_days
|
16
|
+
has :property do |prop|
|
17
|
+
prop.name
|
18
|
+
end
|
19
|
+
has :property_rooms
|
20
|
+
has :floors
|
21
|
+
has :construction_year
|
22
|
+
has :ac_coverage
|
23
|
+
has :refrigerator_coverage
|
24
|
+
has :hot_tubs
|
25
|
+
has :outdoor_pools
|
26
|
+
has :indoor_pools
|
11
27
|
end
|
12
28
|
end
|
13
29
|
end
|
data/lib/lodging/data.rb
CHANGED
@@ -2,16 +2,30 @@ module BrighterPlanet
|
|
2
2
|
module Lodging
|
3
3
|
module Data
|
4
4
|
def self.included(base)
|
5
|
+
base.col :date, :type => :date
|
6
|
+
base.col :rooms, :type => :integer
|
7
|
+
base.col :duration, :type => :integer
|
8
|
+
base.col :zip_code_name
|
9
|
+
base.col :city
|
10
|
+
base.col :state_postal_abbreviation
|
11
|
+
base.col :country_iso_3166_code
|
12
|
+
base.col :lodging_class_name
|
13
|
+
base.col :heating_degree_days, :type => :float
|
14
|
+
base.col :cooling_degree_days, :type => :float
|
15
|
+
base.col :property_northstar_id
|
16
|
+
base.col :property_rooms, :type => :integer
|
17
|
+
base.col :floors, :type => :integer
|
18
|
+
base.col :construction_year, :type => :integer
|
19
|
+
base.col :ac_coverage, :type => :float
|
20
|
+
base.col :refrigerator_coverage, :type => :float
|
21
|
+
base.col :hot_tubs, :type => :integer
|
22
|
+
base.col :outdoor_pools, :type => :integer
|
23
|
+
base.col :indoor_pools, :type => :integer
|
24
|
+
|
5
25
|
base.data_miner do
|
6
|
-
|
7
|
-
|
8
|
-
string 'zip_code_name'
|
9
|
-
string 'state_postal_abbreviation'
|
10
|
-
integer 'rooms'
|
11
|
-
integer 'duration'
|
26
|
+
process 'pull orphans' do
|
27
|
+
Fuel.run_data_miner!
|
12
28
|
end
|
13
|
-
|
14
|
-
process :run_data_miner_on_belongs_to_associations
|
15
29
|
end
|
16
30
|
end
|
17
31
|
end
|
@@ -0,0 +1,544 @@
|
|
1
|
+
# Copyright © 2010 Brighter Planet.
|
2
|
+
# See LICENSE for details.
|
3
|
+
# Contact Brighter Planet for dual-license arrangements.
|
4
|
+
|
5
|
+
## Lodging impact model
|
6
|
+
# This model is used by the [Brighter Planet](http://brighterplanet.com) [CM1 web service](http://carbon.brighterplanet.com) to calculate the impacts of a lodging (e.g. a hotel stay), such as energy use, greenhouse gas emissions, and water use.
|
7
|
+
|
8
|
+
##### Timeframe
|
9
|
+
# The model calculates impacts that occured during a particular time period (`timeframe`).
|
10
|
+
# For example if the `timeframe` is February 2010, a lodging that occurred (`date`) on February 15, 2010 will have impacts, but a lodging that occurred on January 31, 2010 will have zero impacts.
|
11
|
+
#
|
12
|
+
# The default `timeframe` is the current calendar year.
|
13
|
+
|
14
|
+
##### Calculations
|
15
|
+
# The final impacts are the result of the calculations below. These are performed in reverse order, starting with the last calculation listed and finishing with the greenhouse gas emissions calculation.
|
16
|
+
#
|
17
|
+
# Each calculation listing shows:
|
18
|
+
#
|
19
|
+
# * value returned (*units of measurement*)
|
20
|
+
# * description of the value
|
21
|
+
# * calculation methods, listed from most to least preferred
|
22
|
+
#
|
23
|
+
# Some methods use `values` returned by prior calculations. If any of these `values` are unknown the method is skipped.
|
24
|
+
# If all the methods for a calculation are skipped, the value the calculation would return is unknown.
|
25
|
+
|
26
|
+
##### Standard compliance
|
27
|
+
# When compliance with a particular standard is requested, all methods that do not comply with that standard are ignored.
|
28
|
+
# Thus any `values` a method needs will have been calculated using a compliant method or will be unknown.
|
29
|
+
# To see which standards a method complies with, look at the `:complies =>` section of the code in the right column.
|
30
|
+
#
|
31
|
+
# Client input complies with all standards.
|
32
|
+
|
33
|
+
##### Collaboration
|
34
|
+
# Contributions to this impact model are actively encouraged and warmly welcomed. This library includes a comprehensive test suite to ensure that your changes do not cause regressions. All changes should include test coverage for new functionality. Please see [sniff](https://github.com/brighterplanet/sniff#readme), our emitter testing framework, for more information.
|
35
|
+
require 'lodging/cbecs'
|
36
|
+
|
37
|
+
module BrighterPlanet
|
38
|
+
module Lodging
|
39
|
+
module ImpactModel
|
40
|
+
def self.included(base)
|
41
|
+
base.decide :impact, :with => :characteristics do
|
42
|
+
# * * *
|
43
|
+
|
44
|
+
#### Carbon (*kg CO<sub>2</sub>e*)
|
45
|
+
# *The lodging's total anthropogenic greenhouse gas emissions during `timeframe`.*
|
46
|
+
committee :carbon do
|
47
|
+
# Multiply `natural gas use` (*m<sup>3</sup>*) by natural gas' emission factor (*kg CO<sub>2</sub> / m<sup>3</sup>*) to give *kg CO<sub>2</sub>.*
|
48
|
+
# Multiply `fuel oil use` (*l*) by fuel oil's emission factor (*kg CO<sub>2</sub> / l*) to give *kg CO<sub>2</sub>.*
|
49
|
+
# Multiply `electricity use` (*kWh*) by `electricity emission factor` (*kg CO<sub>2</sub> / kWh*) to give *kg CO<sub>2</sub>.*
|
50
|
+
# Multiply `district heat use` (*MJ*) by district heat's emission factor` (*kg CO<sub>2</sub> / MJ*) to give *kg CO<sub>2</sub>.*
|
51
|
+
# Sum to give *kg CO<sub>2</sub>e.*
|
52
|
+
quorum 'from natural gas use, fuel oil use, electricity use, district heat use, and electricity emission factor', :needs => [:natural_gas_use, :fuel_oil_use, :electricity_use, :district_heat_use, :electricity_emission_factor],
|
53
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
54
|
+
characteristics[:natural_gas_use] * Fuel.find_by_name('Pipeline Natural Gas').co2_emission_factor +
|
55
|
+
characteristics[:fuel_oil_use] * Fuel.find_by_name('Residual Fuel Oil No. 6').co2_emission_factor +
|
56
|
+
characteristics[:electricity_use] * characteristics[:electricity_emission_factor] +
|
57
|
+
characteristics[:district_heat_use] * Fuel.find_by_name('District Heat').co2_emission_factor
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
#### Electricity emission factor (*kg CO<sub>2</sub>e / kWh*)
|
62
|
+
# *A greenhouse gas emission factor for electricity used by the lodging.*
|
63
|
+
committee :electricity_emission_factor do
|
64
|
+
# Multiply the `eGRID subregion` electricity emission factors by 1 minus the the subregion's eGRID region loss factor (to account for transmission and distribution losses) to give *kg CO<sub>2</sub>e / kWh*.
|
65
|
+
quorum 'from eGRID subregion', :needs => :egrid_subregion,
|
66
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
67
|
+
characteristics[:egrid_subregion].electricity_emission_factor / (1 - characteristics[:egrid_subregion].egrid_region.loss_factor)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Otherwise look up the `country` electricity emission factor (*kg CO<sub>2</sub>e / kWh*).
|
71
|
+
quorum 'from country', :needs => :country,
|
72
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
73
|
+
if (emission_factor = characteristics[:country].electricity_emission_factor).present? and (loss_factor = characteristics[:country].electricity_loss_factor).present?
|
74
|
+
emission_factor / (1 - loss_factor)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Otherwise use a global average electricity emission factor (*kg CO<sub>2</sub>e / kWh*).
|
79
|
+
quorum 'default',
|
80
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do
|
81
|
+
Country.fallback.electricity_emission_factor / (1 - Country.fallback.electricity_loss_factor)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
#### Natural gas use (*m<sup>3</sup>*)
|
86
|
+
# *The lodging's natural gas use during `timeframe`.*
|
87
|
+
committee :natural_gas_use do
|
88
|
+
# Multiply `room nights` (*room-nights*) by `natural gas intensity` (*m<sup>3</sup> / occupied room-night*) to give *m<sup>3</sup>*.
|
89
|
+
quorum 'from adjusted fuel intensities and room nights', :needs => [:adjusted_fuel_intensities, :room_nights],
|
90
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
91
|
+
characteristics[:room_nights] * characteristics[:adjusted_fuel_intensities][:natural_gas]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
#### Fuel oil use (*l*)
|
96
|
+
# *The lodging's fuel oil use during `timeframe`.*
|
97
|
+
committee :fuel_oil_use do
|
98
|
+
# Multiply `room nights` (*room-nights*) by `fuel oil intensity` (*l / occupied room-night*) to give *l*.
|
99
|
+
quorum 'from adjusted fuel intensities and room nights', :needs => [:adjusted_fuel_intensities, :room_nights],
|
100
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
101
|
+
characteristics[:room_nights] * characteristics[:adjusted_fuel_intensities][:fuel_oil]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
#### Electricity use (*kWh*)
|
106
|
+
# *The lodging's electricity use during `timeframe`.*
|
107
|
+
committee :electricity_use do
|
108
|
+
# Multiply `room nights` (*room-nights*) by `electricity intensity` (*kWh / occupied room-night*) to give *kWh*.
|
109
|
+
quorum 'from adjusted fuel intensities and room nights', :needs => [:adjusted_fuel_intensities, :room_nights],
|
110
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
111
|
+
characteristics[:room_nights] * characteristics[:adjusted_fuel_intensities][:electricity]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
#### District heat use (*MJ*)
|
116
|
+
# *The lodging's district heat use during `timeframe`.*
|
117
|
+
committee :district_heat_use do
|
118
|
+
# Multiply `room nights` (*room-nights*) by `district heat intensity` (*MJ / occupied room-night*) to give *MJ*.
|
119
|
+
quorum 'from adjusted fuel intensities and room nights', :needs => [:adjusted_fuel_intensities, :room_nights],
|
120
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
121
|
+
characteristics[:room_nights] * characteristics[:adjusted_fuel_intensities][:district_heat]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
#### Adjusted fuel intensities (*various*)
|
126
|
+
# *The lodging's use per occupied room night of a variety of fuels, adjusted by number of pools, mini-fridges, etc.*
|
127
|
+
#
|
128
|
+
# - Natural gas intensity: *m<sup>3</sup> / occupied room-night*
|
129
|
+
# - Fuel oil intensity: *l / occupied room-night*
|
130
|
+
# - Electricity intensity: *kWh / occupied room-night*
|
131
|
+
# - District heat intensity: *MJ / occupied room-night*
|
132
|
+
committee :adjusted_fuel_intensities do
|
133
|
+
# Adjust `fuel intensities` based on any amenity adjustments:
|
134
|
+
quorum 'from fuel intensities and amenity adjustments',
|
135
|
+
:needs => :fuel_intensities, :appreciates => [:indoor_pool_adjustment, :outdoor_pool_adjustment, :refrigerator_adjustment, :hot_tub_adjustment],
|
136
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
137
|
+
gas = Fuel.find_by_name('Pipeline Natural Gas')
|
138
|
+
oil = Fuel.find_by_name('Residual Fuel Oil No. 6')
|
139
|
+
|
140
|
+
# Duplicate the current intensities so we don't overwrite them.
|
141
|
+
intensities = characteristics[:fuel_intensities].dup
|
142
|
+
|
143
|
+
# TODO combine pool adjustments - so if we're below average in indoor but above in outdoor we don't accidentally subtract, get less than zero, discard some energy use, and then add energy back for outdoor pools
|
144
|
+
|
145
|
+
# Cycle through each adjustment...
|
146
|
+
characteristics.each do |characteristic, value|
|
147
|
+
unless characteristic == :fuel_intensities
|
148
|
+
value.each do |fuel, adjustment|
|
149
|
+
if fuel == :pool_energy
|
150
|
+
# If the adjustment relates to pool energy, convert natural gas and fuel oil inensities from physical units to energy units.
|
151
|
+
gas_energy = intensities[:natural_gas] * gas.energy_content
|
152
|
+
oil_energy = intensities[:fuel_oil] * oil.energy_content
|
153
|
+
|
154
|
+
# Apply the adjustment to natural gas intensity.
|
155
|
+
# If adjusted natural gas intensity reaches zero, apply any remaining adjustment to fuel oil intensity.
|
156
|
+
# If adjusted fuel oil intensity also reaches zero, discard any remaining adjustment.
|
157
|
+
if (gas_energy += adjustment) < 0.0
|
158
|
+
if (oil_energy += gas_energy) < 0.0
|
159
|
+
oil_energy = 0.0
|
160
|
+
end
|
161
|
+
gas_energy = 0
|
162
|
+
end
|
163
|
+
|
164
|
+
# Convert adjusted natural gas and fuel oil intensities from energy units back to physical units.
|
165
|
+
intensities[:natural_gas] = gas_energy / gas.energy_content
|
166
|
+
intensities[:fuel_oil] = oil_energy / oil.energy_content
|
167
|
+
# Otherwise apply the adjustment to the appropriate fuel intensity. If adjusted fuel intensity reaches zero, discard any remaining adjustment.
|
168
|
+
elsif (intensities[fuel] += adjustment) < 0.0
|
169
|
+
intensities[fuel] = 0.0
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
intensities
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
#### Outdoor pools adjustment (*MJ / occupied room-night*)
|
179
|
+
# *Adjusts the natural gas intensity based on the number of outdoor pools.*
|
180
|
+
committee :outdoor_pool_adjustment do
|
181
|
+
# Assume outdoor pool energy intensity of 329,917 *BTU / night* per [Energy Star](http://www.energystar.gov/ia/business/evaluate_performance/swimming_pool_tech_desc.pdf).
|
182
|
+
# Calculate the difference between `outdoor pools` and average outdoor pools.
|
183
|
+
# Multiply the difference by outdoor pool energy intensity (*MJ / night*) and divide by `property rooms` and `occupancy rate` to give *MJ / occupied room-night*.
|
184
|
+
quorum 'from outdoor pools, property rooms, and occupancy rate', :needs => [:outdoor_pools, :property_rooms, :occupancy_rate],
|
185
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
186
|
+
difference = characteristics[:outdoor_pools] - LodgingProperty.fallback.pools_outdoor
|
187
|
+
{ :pool_energy => difference * 329_917.btus.to(:megajoules) / characteristics[:property_rooms] / characteristics[:occupancy_rate] }
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
#### Indoor pools adjustment (*MJ / occupied room-night*)
|
192
|
+
# *Adjusts the natural gas intensity based on the number of indoor pools.*
|
193
|
+
committee :indoor_pool_adjustment do
|
194
|
+
# Assume indoor pool energy intensity of 2,770,942 *BTU / night* per [Energy Star](http://www.energystar.gov/ia/business/evaluate_performance/swimming_pool_tech_desc.pdf).
|
195
|
+
# Calculate the difference between `indoor pools` and average indoor pools.
|
196
|
+
# Multiply the difference by indoor pool energy intensity (*MJ / night*) and divide by `property rooms` and `occupancy rate` to give *MJ / occupied room-night*.
|
197
|
+
quorum 'from indoor pools, property rooms, and occupancy rate', :needs => [:indoor_pools, :property_rooms, :occupancy_rate],
|
198
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
199
|
+
difference = characteristics[:indoor_pools] - LodgingProperty.fallback.pools_indoor
|
200
|
+
{ :pool_energy => difference * 2_770_942.btus.to(:megajoules) / characteristics[:property_rooms] / characteristics[:occupancy_rate] }
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
#### Hot tub adjustment (*kWh / occupied room-night*)
|
205
|
+
# *Adjusts the electricity intensity based on the number of hot tubs.*
|
206
|
+
committee :hot_tub_adjustment do
|
207
|
+
# Calculate the difference between `hot tubs` and average hot tubs.
|
208
|
+
# Assume hot tub electricity intensity of 6.3 *kWh / night* per [LBL residential energy data sourcebook, p128](http://enduse.lbl.gov/info/LBNL-40297.pdf).
|
209
|
+
# Multiply the difference by the hot tub electricity intensity (*kWh / night*) and divide by `property rooms` and `occupancy rate` to give *kWh / occupied room-night*.
|
210
|
+
quorum 'from hot tubs, property rooms, and occupancy rate', :needs => [:hot_tubs, :property_rooms, :occupancy_rate],
|
211
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
212
|
+
difference = characteristics[:hot_tubs] - LodgingProperty.fallback.hot_tubs
|
213
|
+
{ :electricity => difference * 6.3 / characteristics[:property_rooms] / characteristics[:occupancy_rate] }
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
#### Refrigerator adjustment (*kWh / occupied room-night*)
|
218
|
+
# *Adjusts the electricity intensity based on refrigerator coverage.*
|
219
|
+
committee :refrigerator_adjustment do
|
220
|
+
# Calculate the difference between `refrigerator coverage` (*refrigerators / room*) and average refrigerator coverage (*refrigerators / room*).
|
221
|
+
# Assume an auto-defrost compact fridge electricity intensity of 1.18 *kWh / refrigerator night* per [Energy Star](http://www.energystar.gov/ia/business/bulk_purchasing/bpsavings_calc/Bulk_Purchasing_CompactRefrig_Sav_Calc.xls).
|
222
|
+
# Multiply the difference (*refrigerators / room*) by the refrigerator electricity intensity (*kWh / refrigerator night*) and divide by `occupancy rate` to give *kWh / occupied room-night*.
|
223
|
+
quorum 'from refrigerator coverage and occupancy rate', :needs => [:refrigerator_coverage, :occupancy_rate],
|
224
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
225
|
+
difference = characteristics[:refrigerator_coverage] - LodgingProperty.fallback.fridge_coverage
|
226
|
+
{ :electricity => (difference * 1.18 / characteristics[:occupancy_rate]) }
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
#### Fuel intensities (*various*)
|
231
|
+
# *The lodging's use per occupied room night of a variety of fuels.*
|
232
|
+
#
|
233
|
+
# - Natural gas intensity: *m<sup>3</sup> / occupied room-night*
|
234
|
+
# - Fuel oil intensity: *l / occupied room-night*
|
235
|
+
# - Electricity intensity: *kWh / occupied room-night*
|
236
|
+
# - District heat intensity: *MJ / occupied room-night*
|
237
|
+
committee :fuel_intensities do
|
238
|
+
# If we know `heating degree days` and `cooling degree days`, calculate fuel intensities from [CBECS 2003](http://data.brighterplanet.com/commercial_building_energy_consumption_survey_responses) data using fuzzy inference and adjust the inferred values based on `occupancy rate`.
|
239
|
+
quorum 'from degree days, occupancy rate, and user inputs', :needs => [:heating_degree_days, :cooling_degree_days, :occupancy_rate], :appreciates => [:property_rooms, :floors, :construction_year, :ac_coverage],
|
240
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
241
|
+
inputs = characteristics.to_hash.inject({}) do |memo, (characteristic, value)|
|
242
|
+
case characteristic
|
243
|
+
when :property_rooms
|
244
|
+
memo[:lodging_rooms] = value
|
245
|
+
when :ac_coverage
|
246
|
+
memo[:percent_cooled] = value
|
247
|
+
when :occupancy_rate
|
248
|
+
# Don't include `occupancy rate` in inputs to fuzzy inference
|
249
|
+
else
|
250
|
+
memo[characteristic] = value
|
251
|
+
end
|
252
|
+
memo
|
253
|
+
end
|
254
|
+
|
255
|
+
kernel = CommercialBuildingEnergyConsumptionSurveyResponse.new(inputs)
|
256
|
+
n, f, e, d = kernel.fuzzy_infer(:natural_gas_per_room_night, :fuel_oil_per_room_night, :electricity_per_room_night, :district_heat_per_room_night)
|
257
|
+
{
|
258
|
+
:natural_gas => n / characteristics[:occupancy_rate],
|
259
|
+
:fuel_oil => f / characteristics[:occupancy_rate],
|
260
|
+
:electricity => e / characteristics[:occupancy_rate],
|
261
|
+
:district_heat => d / characteristics[:occupancy_rate]
|
262
|
+
}
|
263
|
+
end
|
264
|
+
|
265
|
+
# Otherwise use global averages.
|
266
|
+
quorum 'default',
|
267
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
268
|
+
intensities = {
|
269
|
+
:natural_gas => Country.fallback.lodging_natural_gas_intensity,
|
270
|
+
:fuel_oil => Country.fallback.lodging_fuel_oil_intensity,
|
271
|
+
:electricity => Country.fallback.lodging_electricity_intensity,
|
272
|
+
:district_heat => Country.fallback.lodging_district_heat_intensity,
|
273
|
+
}
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
#### Occupancy rate
|
278
|
+
# *The percent of the proprety's rooms that are occupied on an average night.*
|
279
|
+
committee :occupancy_rate do
|
280
|
+
# Look up the `country` average lodging occupancy rate.
|
281
|
+
quorum 'from country', :needs => :country,
|
282
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
283
|
+
characteristics[:country].lodging_occupancy_rate
|
284
|
+
end
|
285
|
+
|
286
|
+
# Otherwise use a global average.
|
287
|
+
quorum 'default', :complies => [:ghg_protocol_scope_3, :iso, :tcr] do
|
288
|
+
Country.fallback.lodging_occupancy_rate
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
#### Outdoor pools
|
293
|
+
# *The number of outdoor pools.*
|
294
|
+
committee :outdoor_pools do
|
295
|
+
# Use client input, if available.
|
296
|
+
|
297
|
+
# Otherwise look up the `property` number of outdoor pools, but set a ceiling of 5 outdoor pools.
|
298
|
+
quorum 'from property', :needs => :property,
|
299
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
300
|
+
unless characteristics[:property].pools_outdoor.nil?
|
301
|
+
[characteristics[:property].pools_outdoor.to_f, 5].min
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
#### Indoor pools
|
307
|
+
# *The number of indoor pools.*
|
308
|
+
committee :indoor_pools do
|
309
|
+
# Use client input, if available.
|
310
|
+
|
311
|
+
# Otherwise look up the `property` number of indoor pools, but set a ceiling of 5 indoor pools.
|
312
|
+
quorum 'from property', :needs => :property,
|
313
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
314
|
+
unless characteristics[:property].pools_indoor.nil?
|
315
|
+
[characteristics[:property].pools_indoor.to_f, 5].min
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
#### Hot tubs
|
321
|
+
# *The number of hot tubs.*
|
322
|
+
committee :hot_tubs do
|
323
|
+
# Use client input, if available.
|
324
|
+
|
325
|
+
# Otherwise look up the `property` number of hot tubs.
|
326
|
+
quorum 'from property', :needs => :property,
|
327
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
328
|
+
characteristics[:property].hot_tubs
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
#### Refrigerator coverage
|
333
|
+
# *The percentage of property rooms that have refrigerators.*
|
334
|
+
committee :refrigerator_coverage do
|
335
|
+
# Use client input, if available.
|
336
|
+
# Otherwise take whichever is greater of the `property` refrigerator coverage and mini bar coverage.
|
337
|
+
quorum 'from property', :needs => :property,
|
338
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
339
|
+
if characteristics[:property].mini_bar_coverage || characteristics[:property].fridge_coverage
|
340
|
+
[characteristics[:property].mini_bar_coverage.to_f, characteristics[:property].fridge_coverage.to_f].max
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
#### A/C coverage
|
346
|
+
# *The percentage of property rooms that are air conditioned.*
|
347
|
+
committee :ac_coverage do
|
348
|
+
# Use client input, if available.
|
349
|
+
|
350
|
+
# Otherwise look up the `property` A/C coverage.
|
351
|
+
quorum 'from property', :needs => :property,
|
352
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
353
|
+
characteristics[:property].ac_coverage
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
#### Construction year
|
358
|
+
# *The year the property was built.*
|
359
|
+
committee :construction_year do
|
360
|
+
# Use client input, if available.
|
361
|
+
|
362
|
+
# Otherwise look up the year the `property` was built.
|
363
|
+
quorum 'from property', :needs => :property,
|
364
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
365
|
+
characteristics[:property].construction_year
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
#### Floors
|
370
|
+
# *The number of floors.*
|
371
|
+
committee :floors do
|
372
|
+
# Use client input, if available.
|
373
|
+
|
374
|
+
# Otherwise look up the `property` number of floors.
|
375
|
+
quorum 'from property', :needs => :property,
|
376
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
377
|
+
characteristics[:property].floors
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
#### Property rooms
|
382
|
+
# *The number of guest rooms in the property.*
|
383
|
+
committee :property_rooms do
|
384
|
+
# Use client input, if available.
|
385
|
+
|
386
|
+
# Otherwise look up the `property` number of rooms.
|
387
|
+
quorum 'from property', :needs => :property,
|
388
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
389
|
+
characteristics[:property].lodging_rooms
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
#### Property
|
394
|
+
# *The property where the stay occurred.*
|
395
|
+
#
|
396
|
+
# Use client input, if available
|
397
|
+
|
398
|
+
#### Heating degree days
|
399
|
+
# *The average number of annual heating degree days (base 18°C) at the lodging's location.*
|
400
|
+
committee :heating_degree_days do
|
401
|
+
# Use client input, if available
|
402
|
+
|
403
|
+
# Otherwise look up the `climate division` heating degree days.
|
404
|
+
quorum 'from climate division', :needs => :climate_division,
|
405
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
406
|
+
characteristics[:climate_division].heating_degree_days
|
407
|
+
end
|
408
|
+
|
409
|
+
# Otherwise look up the `country` heating degree days.
|
410
|
+
quorum 'from country', :needs => :country,
|
411
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
412
|
+
characteristics[:country].heating_degree_days
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
#### Cooling degree days
|
417
|
+
# *The average number of annual cooling degree days (base 18°C) at the lodging's location.*
|
418
|
+
committee :cooling_degree_days do
|
419
|
+
# Use client input, if available
|
420
|
+
|
421
|
+
# Otherwise look up the `climate division` cooling degree days.
|
422
|
+
quorum 'from climate division', :needs => :climate_division,
|
423
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
424
|
+
characteristics[:climate_division].cooling_degree_days
|
425
|
+
end
|
426
|
+
|
427
|
+
# Otherwise look up the `country` cooling degree days.
|
428
|
+
quorum 'from country', :needs => :country,
|
429
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
430
|
+
characteristics[:country].cooling_degree_days
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
#### eGRID subregion
|
435
|
+
# *The [eGRID subregion](http://data.brighterplanet.com/egrid_subregions).*
|
436
|
+
committee :egrid_subregion do
|
437
|
+
# Look up the `zip code` eGRID subregion.
|
438
|
+
quorum 'from zip code', :needs => :zip_code,
|
439
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
440
|
+
characteristics[:zip_code].egrid_subregion
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
#### Country
|
445
|
+
# *The [country](http://data.brighterplanet.com/countries).*
|
446
|
+
committee :country do
|
447
|
+
# Use client input, if available.
|
448
|
+
|
449
|
+
# Otherwise if state is defined then the country is the United States.
|
450
|
+
quorum 'from state', :needs => :state,
|
451
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
452
|
+
Country.united_states
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
#### State
|
457
|
+
# *The [US state](http://data.brighterplanet.com/states).*
|
458
|
+
committee :state do
|
459
|
+
# Use client input, if available.
|
460
|
+
|
461
|
+
# Otherwise look up the `zip code` state.
|
462
|
+
quorum 'from zip code', :needs => :zip_code,
|
463
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
464
|
+
characteristics[:zip_code].state
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
468
|
+
#### City
|
469
|
+
# *The city.*
|
470
|
+
committee :city do
|
471
|
+
# Use client input, if available.
|
472
|
+
|
473
|
+
# Otherwise look up the `zip code` description.
|
474
|
+
quorum 'from zip code', :needs => :zip_code,
|
475
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
476
|
+
characteristics[:zip_code].description
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
#### Climate division
|
481
|
+
# *The [US climate division](http://data.brighterplanet.com/climate_divisions).*
|
482
|
+
committee :climate_division do
|
483
|
+
# Look up the `zip code` climate division.
|
484
|
+
quorum 'from zip code', :needs => :zip_code,
|
485
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics|
|
486
|
+
characteristics[:zip_code].climate_division
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
#### Zip code
|
491
|
+
# *The [US zip code](http://data.brighterplanet.com/zip_codes).*
|
492
|
+
#
|
493
|
+
# Use client input, if available.
|
494
|
+
|
495
|
+
#### Room nights (*room-nights*)
|
496
|
+
# *The stay's room-nights that occurred during `timeframe`.*
|
497
|
+
committee :room_nights do
|
498
|
+
# If `date` falls within `timeframe`, divide `duration` (*seconds*) by 86,400 (*seconds / night*) and multiply by `rooms` to give *room-nights*.
|
499
|
+
# Otherwise `room nights` is zero.
|
500
|
+
quorum 'from rooms, duration, date, and timeframe', :needs => [:rooms, :duration, :date],
|
501
|
+
:complies => [:ghg_protocol_scope_3, :iso, :tcr] do |characteristics, timeframe|
|
502
|
+
date = characteristics[:date].is_a?(Date) ? characteristics[:date] : Date.parse(characteristics[:date].to_s)
|
503
|
+
timeframe.include?(date) ? characteristics[:duration] / 86400.0 * characteristics[:rooms] : 0
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
#### Duration (*seconds*)
|
508
|
+
# *The stay's duration.*
|
509
|
+
committee :duration do
|
510
|
+
# Use client input, if available.
|
511
|
+
|
512
|
+
# Otherwise use 86400 *seconds* (1 night).
|
513
|
+
quorum 'default' do
|
514
|
+
86400.0
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
#### Rooms
|
519
|
+
# *The number of rooms used.*
|
520
|
+
committee :rooms do
|
521
|
+
# Use client input, if available.
|
522
|
+
|
523
|
+
# Otherwise use 1 *room*.
|
524
|
+
quorum 'default' do
|
525
|
+
1
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
#### Date (*date*)
|
530
|
+
# *The day the stay occurred.*
|
531
|
+
committee :date do
|
532
|
+
# Use client input, if available.
|
533
|
+
|
534
|
+
# Otherwise use the first day of `timeframe`.
|
535
|
+
quorum 'from timeframe',
|
536
|
+
:complies => [:ghg_protocol_scope_3, :iso] do |characteristics, timeframe|
|
537
|
+
timeframe.from
|
538
|
+
end
|
539
|
+
end
|
540
|
+
end
|
541
|
+
end
|
542
|
+
end
|
543
|
+
end
|
544
|
+
end
|