Class: BTAPCosting
- Inherits:
-
Object
- Object
- BTAPCosting
- Defined in:
- lib/openstudio-standards/btap/costing/nv_costing.rb,
lib/openstudio-standards/btap/costing/dcv_costing.rb,
lib/openstudio-standards/btap/costing/shw_costing.rb,
lib/openstudio-standards/btap/costing/btap_costing.rb,
lib/openstudio-standards/btap/costing/envelope_costing.rb,
lib/openstudio-standards/btap/costing/lighting_costing.rb,
lib/openstudio-standards/btap/costing/pv_ground_costing.rb,
lib/openstudio-standards/btap/costing/ventilation_costing.rb,
lib/openstudio-standards/btap/costing/led_lighting_costing.rb,
lib/openstudio-standards/btap/costing/heating_cooling_costing.rb,
lib/openstudio-standards/btap/costing/daylighting_sensor_control_costing.rb
Instance Method Summary collapse
-
#add_costed_item(material_id:, quantity:, material_mult: 1.0, labour_mult: 1.0, equip_mult: 1.0, tags: []) ⇒ Object
This adds costed items to the array of cousted items which end up in btap_itmes.json.
- #add_floor_sys(hvac_floors:, tz_floor_sys:) ⇒ Object
-
#add_heat_cool_to_report(equipment_info:, heat_cool_cost:, al_eq_reporting_info:) ⇒ Object
This method collects air loop heating and cooling costing information into the al_eq_reporting_info hash.
- #add_tz_to_air_sys(air_system:, air_system_total:, air_system_totals:, floor_tz:) ⇒ Object
- #ahu_costing(model:, prototype_creator:, template_type:, mech_room:, roof_cent:, mech_sizing_info:, min_space:) ⇒ Object
-
#airloop_equipment_costing(airloop_equipment:, ahu_mult:, vent_tags: []) ⇒ Object
This method oversees the costing of heating and cooling equipment in an air loop.
- #assembly_cost(cost_info:, sheet_name:, column_1:, column_2:, quantity:, tags:) ⇒ Object
-
#boiler_costing(model, prototype_creator) ⇒ Object
————————————————————————————————– This function gets all costs associated with boilers (i.e., boilers, pumps, flues, electrical lines and boxes, fuel lines and distribution piping to zonal heating units) ————————————————————————————————–.
-
#chiller_costing(model, prototype_creator) ⇒ Object
————————————————————————————————– Chiller costing is similar to boiler costing above ————————————————————————————————–.
-
#compileZonalVRFFloors(vrfSystemFloors:, tzFloor:) ⇒ Object
This method takes information about a thermal zone served by a VRF system (tzFloor) and adds it to the collection of thermal zones also served by VRF systems on the same floor.
-
#coolingtower_costing(model, prototype_creator) ⇒ Object
———————————————————————————————- Cooling tower (i.e., chiller condensor loop cooling) costing ———————————————————————————————-.
-
#cost_ahu(sys_type:, airloop_flow_lps:, airloop_flow_cfm:, mech_sizing_info:, heating_fuel:, cooling_type:, airloop_name:, vent_tags: []) ⇒ Object
This method looks for an air handler in the ‘hvac_vent_ahu’ sheet of the costing spreadsheet.
- #cost_audit_all(model:, prototype_creator:, envelope_costing: true, lighting_costing: true, boilers_costing: true, chillers_costing: true, cooling_towers_costing: true, shw_costing: true, ventilation_costing: true, zone_system_costing: true, renewables_costing: true, template_type: nil) ⇒ Object
- #cost_audit_daylighting_sensor_control(model:, prototype_creator:) ⇒ Object
- #cost_audit_dcv(model:, prototype_creator:) ⇒ Object
- #cost_audit_envelope(model, prototype_creator) ⇒ Object
- #cost_audit_led_lighting(model:, prototype_creator:) ⇒ Object
- #cost_audit_lighting(model, prototype_creator) ⇒ Object
- #cost_audit_nv(model:, prototype_creator:) ⇒ Object
- #cost_audit_pv_ground(model, prototype_creator) ⇒ Object
-
#cost_ccashp_additional_components(ahu_mult:, heat_pump:, vent_tags: [], report_mult: 1.0) ⇒ Object
This method calculates the costs of CCASHP equipment beyond the coil cost and any backup heating costs.
- #cost_construction(construction, location, type = 'opaque') ⇒ Object
- #cost_heat_cool_equip(equipment_info:, vent_tags: [], report_mult: 1.0) ⇒ Object
-
#cost_list_items(btap_items:, custom_costing: nil, custCity: nil, custProvince: nil) ⇒ Object
This method takes the list of costed items in the building generated with the help of the above add_costed_item method and finds the costs for the list of items.
- #cost_shw_main(mech_room:, roof_cent:, min_space:) ⇒ Object
-
#costVRFCondenser(model:, maxHeightDiff:, regMat:, regLab:, regMatElec:, regLabElec:, roofHeight:) ⇒ Object
Costing for the VRF Condenser(s) and the wiring and piping conecting the Condenser(s) to the branch distributors on each floor of the building with thermal zones served by a VRF system.
-
#determine_ahu_htg_clg_fuel(heat_cap:, cool_cap:, heat_type:, cool_type:) ⇒ Object
This method determines the main heating fuel and cooling type used by an air handling unit (a given model’s air loop).
-
#distance(loc1, loc2) ⇒ Object
Enter in [latitude, longitude] for each loc and this method will return the distance.
-
#expandProvAbbrev(abbrev) ⇒ Object
This will expand the two letter province abbreviation to a full uppercase province name.
- #floor_vent_dist_cost(hvac_floors:, prototype_creator:, roof_cent:, mech_sizing_info:) ⇒ Object
- #gas_burner_cost(heating_fuel:, sys_type:, airloop_flow_cfm:, mech_sizing_info:, costed_ahu_info:, vent_tags: [], report_mult: 1.0) ⇒ Object
- #gen_hvac_info_by_floor(hvac_floors:, model:, prototype_creator:, airloop:, sys_type:, hrv_info:) ⇒ Object
- #generate_construction_cost_database_for_all_cities ⇒ Object
- #generate_construction_cost_database_for_city(city, province_state) ⇒ Object
-
#get_ahu_mult(loop_equip:) ⇒ Object
This method finds ahu with the largest supply air capacity based on the heating and cooling characteristics defined by loop_equip.
- #get_airloop_terminal_type(eq:) ⇒ Object
- #get_closest_cost_location(lat, long) ⇒ Object
- #get_comp_cost(cost_info:, vent_tags: [], report_mult: 1.0) ⇒ Object
- #get_cost_info(mat:, size: nil, unit: nil) ⇒ Object
- #get_duct_cost(cost_info:) ⇒ Object
- #get_fan_cap(fan:, model:) ⇒ Object
- #get_fixture_type_id(fixture_info:, sheet_name:, row_name_1:, row_name_2:, row_name_3:, column_search:) ⇒ Object
- #get_floor_trunk_cost(mech_table:, hvac_floor:, prototype_creator:, floor_trunk_dist_m:, fric_allow: 1) ⇒ Object
- #get_hrv_floor_trunk_cost(mech_table:, air_system:, floor_trunk_dist_m:) ⇒ Object
- #get_hrv_info(airloop:, model:) ⇒ Object
-
#get_HVAC_multiplier(materialLookup, materialSize) ⇒ Object
This method determines how many pieces of equipment are required to satisfy the required size if 1 piece is not enough.
- #get_line_eq(a:, b:, tol: 8) ⇒ Object
- #get_lowest_space(spaces:) ⇒ Object
-
#get_mech_costing(mech_name:, size:, terminal:, use_mult: true, vent_tags: [], report_mult: 1.0) ⇒ Object
This method gets the cost of a piece of equipment.
- #get_mech_table(mech_size_info:, table_name:) ⇒ Object
- #get_orient(p:, q:, r:, tol: 8) ⇒ Object
- #get_predominant_floor_space_type_area(hvac_floor:, prototype_creator:) ⇒ Object
- #get_regional_cost_factors(provinceState, city, material) ⇒ Object
- #get_shw_dist_cost(space:, roof_cent:) ⇒ Object
-
#get_SHW_vol_multiplier(materialLookup:, materialSize:, materialVol:) ⇒ Object
This method is a copy of get_HVAC_multiplier but searches for volume in the ‘Fuel’ column of the materials_hvac sheet.
- #get_space_floor_centroid(space:) ⇒ Object
-
#get_story_cent_to_edge(building_story:, prototype_creator:, target_cent:, tol: 8, full_length: false) ⇒ Object
This method finds the centroid of the ceiling line on a given story furthest from the specified point.
-
#get_vent_cost_data(equipment_info:) ⇒ Object
This method collects information related a piece of equipment from the ‘materials_hvac’ sheet in the costing spreadsheet.
-
#get_vent_mat_cost(mat_cost_info:, vent_tags: [], report_mult: 1.0) ⇒ Object
This method costs a piece of mechanical equipment.
-
#get_vent_system_mult(loop_equip:, mult_floor: nil) ⇒ Object
This method finds how many pieces of costed equipment are required to meet a given load if no one piece of costed equipment can do it.
- #getCost(materialType, materialHash, multiplier) ⇒ Object
- #getGeometryData(model, prototype_creator) ⇒ Object
- #getHeaderPipingDistributionCost(numAGFlrs, mechRmInBsmt, regional_material, regional_installation, reg_elec_mat, reg_elec_inst, pumpFlow, horz_dist, nom_flr_hght) ⇒ Object
-
#getHVACCost(name, materialLookup, materialSize, exactMatch = true) ⇒ Object
This method provides the material and labour cost for a required piece of equimpment.
-
#getHVACDBInfo(name:, materialLookup:, materialSize:, exactMatch: true) ⇒ Object
This method was originally part of getHVACCOST but was split out because in some cases the information from the materials_hvac sheet of the costing spreadsheet was required but not tho cost.
-
#getHVACMultiSizeDBInfo(name:, materialLookup:, materialCap:, materialCon:) ⇒ Object
This method was originally part of getHVACCOST but was split out because in some cases the information from the materials_hvac sheet of the costing spreadsheet was required but not tho cost.
- #getPerimDistPipingCost(zone, nom_flr_hght, regional_material, regional_installation) ⇒ Object
- #getPerimDistWiringCost(zone, nom_flr_hght, regional_material, regional_installation) ⇒ Object
-
#getSHWTankCost(name:, materialLookup:, materialSize:, tankVol:) ⇒ Object
Getting cost for SHW Tanks.
-
#getWallWithLargestArea(currFloor:) ⇒ Object
This method finds and returns the outside wall with the largest area on a given building story.
-
#getZonalVRFCosting(vrfSystemFloors:, model:, prototype_creator:, regMat:, regLab:, cumulCost:) ⇒ Object
Cost zonal VRF systems including zone equipment (ceiling units and associated tubing and wiring), floor equipment ( branch distributor on each floor), VRF system condenser (assumed one on rooftop and another every 50m), and piping and wiring linking the branch distributors to one another and to the condensers.
-
#getZonalVRFInfo(zone:, model:, prototype_creator:, zonalSys:, vrfSystemFloors:, regMat:, regLab:, numZones:) ⇒ Object
Get information on Zonal VRF System in a Thermal Zone.
-
#hrv_cost(hrv_info:, airloop:, vent_tags: [], report_mult: 1.0) ⇒ Object
This method consumes the following: hrv_info: (hash) Information about the modeled HRV.
- #hrv_duct_cost(prototype_creator:, roof_cent:, mech_sizing_info:, hvac_floors:) ⇒ Object
-
#initialize(costs_csv: nil, factors_csv: nil) ⇒ BTAPCosting
constructor
May be initialized with custom databases: costs_csv: Path to custom costing factors_csv: Path to custom localization factors.
-
#interpolate(x_y_array:, x2:, exterpolate_percentage_range: 30.0) ⇒ Object
Interpolate array of hashes that contain 2 values (key=rsi, data=cost).
- #line_int(line_seg:, line:, tol: 8) ⇒ Object
- #line_seg_int(linea:, lineb:, tol: 8) ⇒ Object
- #load_database ⇒ Object
- #mech_to_roof_cost(heat_type:, cool_type:, mech_room:, roof_cent:, rt_unit_num:) ⇒ Object
- #piping_cost(pipe_dist_m:, mech_sizing_info:, air_m3_per_s:, is_cool: false, vent_tags: [], report_mult: 1.0) ⇒ Object
- #point_on_line(p:, q:, r:, tol: 8) ⇒ Object
- #read_mech_sizing ⇒ Object
- #reheat_coil_costing(terminal:, tz_centroids:, model:, tz:, roof_cent:, tz_mult:, mech_sizing_info:, air_m3_per_s:, box_name:, vent_tags: [], report_mult: 1.0) ⇒ Object
- #reheat_recool_cost(airloop:, prototype_creator:, model:, roof_cent:, mech_sizing_info:, vent_tags: [], report_mult: 1.0) ⇒ Object
- #short_dist_point_and_line(point:, line:) ⇒ Object
-
#shw_costing(model, prototype_creator) ⇒ Object
————————————————————————————————– This function gets all costs associated with SHW/DHW (i.e., tanks, pumps, flues, piping and utility costs) ————————————————————————————————–.
- #shw_distribution_costing(model:, prototype_creator:) ⇒ Object
- #sort_tzs_by_air_system(hvac_floor:) ⇒ Object
- #tz_vent_dist_cost(hvac_floors:, mech_sizing_info:) ⇒ Object
- #validate_database ⇒ Object
- #vav_cost(terminal:, tz_centroids:, tz:, roof_cent:, mech_sizing_info:, air_flow_m3_per_s:, box_name:, vent_tags: [], report_mult: 1.0) ⇒ Object
-
#vent_assembly_cost(ids:, id_quants:, overall_mult: 1.0, vent_tags: [], report_mult: 1.0) ⇒ Object
This method tokes in: ids: The list of material ids to look for in the ‘material_id’ column of the materials_hvac sheet.
- #vent_box_elec_cost(cond_dist_m:, vent_tags: [], report_mult: 1.0) ⇒ Object
- #vent_trunk_duct_cost(tot_air_m3pers:, min_space:, roof_cent:, mech_sizing_info:, sys_1_4:) ⇒ Object
- #ventilation_costing(model, prototype_creator, template_type, mech_room, cond_spaces) ⇒ Object
-
#vsd_chiller_cost(primaryCap:) ⇒ Object
This method is for the calculation of VSD chiller cost.
-
#zonalsys_costing(model, prototype_creator, mech_room, cond_spaces) ⇒ Object
————————————————————————————————– This function gets all costs associated zonal heating and cooling systems (i.e., zonal units, pumps, flues & utility costs) ————————————————————————————————–.
Constructor Details
#initialize(costs_csv: nil, factors_csv: nil) ⇒ BTAPCosting
May be initialized with custom databases:
costs_csv: Path to custom costing
factors_csv: Path to custom localization factors
44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 44 def initialize(costs_csv: nil, factors_csv: nil) @cp = CommonPaths.instance @costing_database = CostingDatabase.instance # If the path for custom costing is defined, use custom costing. if (not costs_csv.nil?) and File.exist?(costs_csv) @cp.costs_path = costs_csv end # If the path for custom factors is defined, use custom factors. if (not factors_csv.nil?) and File.exist?(factors_csv) @cp.costs_local_factors_path = factors_csv end end |
Instance Method Details
#add_costed_item(material_id:, quantity:, material_mult: 1.0, labour_mult: 1.0, equip_mult: 1.0, tags: []) ⇒ Object
This adds costed items to the array of cousted items which end up in btap_itmes.json. Note that the array this method uses is created in the cost_audit_all method. The array is created with an initial element that contains the city and province whose localiazation factors are used for costing. The inputs are: id: (string) The costing database id for the item being costed. quantity: (float) The total amount of the item being costed in whatever units the item is costed in. This should
include all multiplier used to determine this cost (e.g. such as thermal_zone multipliers). As
an example, if 32 ft. of wire were required for a piece of equipment used in a thermal zone with
a multiplier of 10, the quantity would be 3.2 (32 ft. * 10 / 100 since wire is costed per
100 ft.).
material_mult: (float) The multiplier used to estimate the cost of an item from the base cost. For example, high
efficiency SHW tanks are estimated to cost 30% higher than regular SHW tanks so the cost of these
tanks are calculated by the cost * 1.3. Thus, the material_mult for high efficiency tanks
would be 1.3. This is defauted to 1.0 if it is not provided.
labour_mult: (float) Similar to material_mult only applied to labour costs. The labour_mult can be different than
the material_mult. This is defaulted to 1.0 if it is not provided.
equipment_mult: (float) Similar to material_mult and labour_mult only for equipment. This will always be 1.0 until
equipment costs are supported.
tags: (array of strings) This is an array which links the costed item to a component of the model that is being
costed. For example, a material_id related to a boiler pump might have tags like ["boiler", "pump"].
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 309 def add_costed_item(material_id:, quantity:, material_mult: 1.0, labour_mult: 1.0, equip_mult: 1.0, tags: []) # Do some error handling for the tags argument = [] if .kind_of?(String) = if .kind_of?(Array) # Validate the type of the arguments. if (.kind_of?(Array) == false) raise("The tags for the item #{material_id} were not properly defined. Please search for where the item is being added to the @cost_items hash via the add_costed_item method and correct the entry.") end if (material_id.kind_of?(String) == false) raise("The material_id for the item #{material_id} is not a string. Please search for where the item is being added to the @cost_items hash via the add_costed_item method and correct the entry.") end if (quantity.kind_of?(Float) == false) raise("The quantity for the item #{material_id} is not a float. Please search for where the item is being added to the @cost_items hash via the add_costed_item method and correct the entry.") end if (material_mult.kind_of?(Float) == false) raise("The material_mult for the item #{material_id} is not a float. Please search for where the item is being added to the @cost_items hash via the add_costed_item method and correct the entry.") end if (labour_mult.kind_of?(Float) == false) raise("The labour_mult for the item #{material_id} is not a float. Please search for where the item is being added to the @cost_items hash via the add_costed_item method and correct the entry.") end if (equip_mult.kind_of?(Float) == false) raise("The equip_mult for the item #{material_id} is not a float. Please search for where the item is being added to the @cost_items hash via the add_costed_item method and correct the entry.") end # Add the costed item to the output output hash. @cost_items['Items'] << { 'id' => material_id, 'quantity' => quantity, 'material_mult' => material_mult, 'labour_mult' => labour_mult, 'equipment_mult' => equip_mult, 'tags' => } end |
#add_floor_sys(hvac_floors:, tz_floor_sys:) ⇒ Object
1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1772 def add_floor_sys(hvac_floors:, tz_floor_sys:) if hvac_floors.empty? hvac_floors << { story_name: tz_floor_sys[:story_name], story: tz_floor_sys[:story], supply_air_m3ps: tz_floor_sys[:tz_floor_supp_air_m3ps], return_air_m3ps: tz_floor_sys[:tz_floor_ret_air_m3ps], tz_mult: tz_floor_sys[:tz_mult], tz_num: 1, floor_tz: [tz_floor_sys] } else found_story = false hvac_floors.each do |hvac_floor| if hvac_floor[:story_name].to_s.upcase == tz_floor_sys[:story_name].to_s.upcase hvac_floor[:supply_air_m3ps] += tz_floor_sys[:tz_floor_supp_air_m3ps] hvac_floor[:return_air_m3ps] += tz_floor_sys[:tz_floor_ret_air_m3ps] hvac_floor[:tz_mult] += tz_floor_sys[:tz_mult] hvac_floor[:tz_num] += 1 hvac_floor[:floor_tz] << tz_floor_sys found_story = true end end if found_story == false hvac_floors << { story_name: tz_floor_sys[:story_name], story: tz_floor_sys[:story], supply_air_m3ps: tz_floor_sys[:tz_floor_supp_air_m3ps], return_air_m3ps: tz_floor_sys[:tz_floor_ret_air_m3ps], tz_mult: tz_floor_sys[:tz_mult], tz_num: 1, floor_tz: [tz_floor_sys] } end end return hvac_floors end |
#add_heat_cool_to_report(equipment_info:, heat_cool_cost:, al_eq_reporting_info:) ⇒ Object
This method collects air loop heating and cooling costing information into the al_eq_reporting_info hash. This hash will be included in the ventilation costing report. It collects air loops by system type.
2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 2442 def add_heat_cool_to_report(equipment_info:, heat_cool_cost:, al_eq_reporting_info:) # If there is no air loop heating or cooling equipment casting information add it to the hash. if al_eq_reporting_info.empty? al_eq_reporting_info << { eq_category: equipment_info[:obj_type][3..-1], heating_fuel: equipment_info[:heating_fuel], cooling_type: equipment_info[:cooling_type], total_modeled_capacity_kw: equipment_info[:mech_capacity_kw].round(3), cost: heat_cool_cost.round(2) } else # look for an air loop with the appropriate system type. ahu_heat_cool = al_eq_reporting_info.select {|aloop| aloop[:eq_category] == equipment_info[:obj_type][3..-1] } # If air loops with that system type are present add a new one. if ahu_heat_cool.empty? al_eq_reporting_info << { eq_category: equipment_info[:obj_type][3..-1], heating_fuel: equipment_info[:heating_fuel], cooling_type: equipment_info[:cooling_type], total_modeled_capacity_kw: equipment_info[:mech_capacity_kw].round(3), cost: heat_cool_cost.round(2) } else # If there is an air loop with the appropriate system type add the capacity and cost to the hash. ahu_heat_cool[0][:total_modeled_capacity_kw] += equipment_info[:mech_capacity_kw].round(3) ahu_heat_cool[0][:cost] += heat_cool_cost.round(2) end end end |
#add_tz_to_air_sys(air_system:, air_system_total:, air_system_totals:, floor_tz:) ⇒ Object
2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 2287 def add_tz_to_air_sys(air_system:, air_system_total:, air_system_totals:, floor_tz:) if air_system_totals.empty? air_system_totals << { air_system: air_system[:air_sys], hrv_air_m3ps: air_system_total[:hrv_air_m3ps], dist_to_roof_m: air_system_total[:dist_to_roof_m], num_systems: air_system_total[:num_systems], hrv_info: air_system[:hrv_info], floor_tz: [floor_tz] } else curr_air_sys = air_system_totals.select {|air_sys| air_sys[:air_system] == air_system[:air_sys]} if curr_air_sys.empty? air_system_totals << { air_system: air_system[:air_sys], hrv_air_m3ps: air_system_total[:hrv_air_m3ps], dist_to_roof_m: air_system_total[:dist_to_roof_m], num_systems: air_system_total[:num_systems], hrv_info: air_system[:hrv_info], floor_tz: [floor_tz] } else curr_air_sys[0][:hrv_air_m3ps] += air_system_total[:hrv_air_m3ps] curr_air_sys[0][:dist_to_roof_m] = [curr_air_sys[0][:dist_to_roof_m], air_system_total[:dist_to_roof_m]].max curr_air_sys[0][:num_systems] += air_system_total[:num_systems] curr_air_sys[0][:floor_tz] << floor_tz end end return air_system_totals end |
#ahu_costing(model:, prototype_creator:, template_type:, mech_room:, roof_cent:, mech_sizing_info:, min_space:) ⇒ Object
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 25 def ahu_costing(model:, prototype_creator:, template_type:, mech_room:, roof_cent:, mech_sizing_info:, min_space:) ahu_cost = 0 hrv_total_cost = 0 heat_type = { 'HP' => 0, 'elec' => 0, 'Gas' => 0, 'HW' => 0, } cool_type = { 'DX' => 0, 'CHW' => 0, } rt_unit_num = 0 total_vent_flow_m3_per_s = 0 sys_1_4 = true hvac_floors = [] # Go through each air loop in the model and cost it model.getAirLoopHVACs.sort.each do |airloop| @airloop_info = nil airloop_name = airloop.nameString # Look for the system type from the name of the air loop sys_name_loc = airloop_name.to_s.upcase.index("SYS_") if sys_name_loc.nil? puts "The name of airloop #{airloop_name} does not start with a valid NECB system type described as \"Sys_\" and then an NECB system number." puts "Please rename the airloop appropriately or do not cost the ventilation system until ventilation costing can handle non-NECB ventilation systems." next else sys_type = airloop_name[(sys_name_loc+4)].to_i sys_type_real = sys_type # For costing, treat system types 1 and 4 the same (treat both as system 1) sys_type = 1 if sys_type == 4 next if sys_type == 2 end = [ "ventilation", airloop_name, "system #{sys_type_real}" ] rt_unit_num += 1 @airloop_info = {sys_type: sys_type} @airloop_info[:name] = airloop_name # Get the air loop supply airflow rate (used for sizing the ahu for costing) if airloop.isDesignSupplyAirFlowRateAutosized airloop_flow_m3_per_s = airloop.autosizedDesignSupplyAirFlowRate.to_f else airloop_flow_m3_per_s = airloop.designSupplyAirFlowRate.to_f end airloop_flow_cfm = (OpenStudio.convert(airloop_flow_m3_per_s, 'm^3/s', 'cfm').get) airloop_flow_lps = (OpenStudio.convert(airloop_flow_m3_per_s, 'm^3/s', 'L/s').get) total_vent_flow_m3_per_s += airloop_flow_m3_per_s # Set up hash to record heating and cooling capacities. If more than one heating or cooling source is present this will be used to determine which is predominant one since ahu costing is done based on one heating fuel and cooling type heat_cap = { 'HP' => 0, 'elec' => 0, 'Gas' => 0, 'HW' => 0, 'CCASHP' => 0 } cool_cap = { 'DX' => 0, 'CHW' => 0, } @airloop_info[:airloop_flow_m3_per_s] = airloop_flow_m3_per_s.round(3) total_heat_cool_cost = 0 airloop_equipment = [] #@airloop_info[:equipment_info] = [] # Find HRVs in the air loop so they can be costed if present hrv_info = get_hrv_info(airloop: airloop, model: model) # Sort through all of the supply components in the air loop and collect heating and cooling equipment airloop.supplyComponents.sort.each do |supplycomp| # Get the OS object type of the supply component obj_type = supplycomp.iddObjectType.valueName.to_s mech_capacity = 0 heating_fuel = 'none' cooling_type = 'none' adv_dx_clg_eqpt = false cat_search = nil # Based on the object type determine how to handle it. case obj_type # Determine what to do (if anything) with a piece of air loop heating/cooling equipment. Note the comment for the first type applies to the rest. when /OS_Coil_Heating_DX_VariableSpeed/ # Get the object and make sure it is cast correctly suppcomp = supplycomp.to_CoilHeatingDXVariableSpeed.get # Determine the size of the object if either autosized or manualy sized if suppcomp.isRatedHeatingCapacityAtSelectedNominalSpeedLevelAutosized mech_capacity = suppcomp.autosizedRatedHeatingCapacityAtSelectedNominalSpeedLevel.to_f/1000.0 else mech_capacity = suppcomp.ratedHeatingCapacityAtSelectedNominalSpeedLevel.to_f/1000.0 end # Determine from the name if it is a CCASHP if suppcomp.name.to_s.upcase.include?("CCASHP") # Set the heating equipment type (used to determine how to cost the equipment) heating_fuel = 'CCASHP' # Set the term used to search the 'hvac_costing' sheet in the costing spreadsheet to get costing information cat_search = 'coils' # Set the heating capacity (used to determine the predominant heating type for the air loop) heat_cap['CCASHP'] += mech_capacity else heating_fuel = 'HP' cat_search = 'ashp' heat_cap['HP'] += mech_capacity end when /OS_Coil_Heating_DX_SingleSpeed/ suppcomp = supplycomp.to_CoilHeatingDXSingleSpeed.get if suppcomp.isRatedTotalHeatingCapacityAutosized mech_capacity = suppcomp.autosizedRatedTotalHeatingCapacity.to_f/1000.0 else mech_capacity = suppcomp.ratedTotalHeatingCapacity.to_f/1000.0 end if suppcomp.name.to_s.upcase.include?("CCASHP") heating_fuel = 'CCASHP' # There is a separate method which costs additional CCASHP cost information. The 'coils' category is only # one of the pieces of equipment that goes into CCASHP costing. cat_search = 'coils' heat_cap['CCASHP'] += mech_capacity else heating_fuel = 'HP' cat_search = 'ashp' heat_cap['HP'] += mech_capacity end when 'OS_Coil_Heating_Electric' heating_fuel = 'elec' suppcomp = supplycomp.to_CoilHeatingElectric.get if suppcomp.isNominalCapacityAutosized mech_capacity = suppcomp.autosizedNominalCapacity.to_f/1000.0 else mech_capacity = suppcomp.nominalCapacity.to_f/1000.0 end cat_search = 'elecheat' heat_cap['elec'] += mech_capacity when /OS_Coil_Heating_Gas/ heating_fuel = 'Gas' suppcomp = supplycomp.to_CoilHeatingGas.get if suppcomp.isNominalCapacityAutosized mech_capacity = suppcomp.autosizedNominalCapacity.to_f/1000.0 else mech_capacity = suppcomp.nominalCapacity.to_f/1000.0 end cat_search = 'FurnaceGas' heat_cap['Gas'] += mech_capacity when /OS_Coil_Heating_Water/ heating_fuel = 'HW' suppcomp = supplycomp.to_CoilHeatingWater.get if suppcomp.isRatedCapacityAutosized mech_capacity = suppcomp.autosizedRatedCapacity.to_f/1000.0 else suppcomp.ratedCapacity.to_f/1000.0 end cat_search = 'coils' heat_cap['HW'] += mech_capacity when /OS_Coil_Cooling_DX_SingleSpeed/ suppcomp = supplycomp.to_CoilCoolingDXSingleSpeed.get if suppcomp.isRatedTotalCoolingCapacityAutosized mech_capacity = suppcomp.autosizedRatedTotalCoolingCapacity.to_f/1000.0 else mech_capacity = suppcomp.ratedTotalCoolingCapacity.to_f/1000.0 end if suppcomp.name.to_s.upcase.include?('DX-ADV') cooling_type = 'DX-adv' cat_search = 'coils' cool_cap['DX'] += mech_capacity else cooling_type = 'DX' cat_search = 'coils' cool_cap['DX'] += mech_capacity end when /OS_Coil_Cooling_DX_VariableSpeed/ suppcomp = supplycomp.to_CoilCoolingDXVariableSpeed.get if suppcomp.isGrossRatedTotalCoolingCapacityAtSelectedNominalSpeedLevelAutosized mech_capacity = suppcomp.autosizedGrossRatedTotalCoolingCapacityAtSelectedNominalSpeedLevel.to_f/1000.0 else mech_capacity = suppcomp.grossRatedTotalCoolingCapacityAtSelectedNominalSpeedLevel.to_f/1000.0 end if suppcomp.name.to_s.upcase.include?('DX-ADV') cooling_type = 'DX-adv' cat_search = 'coils' cool_cap['DX'] += mech_capacity else cooling_type = 'DX' cat_search = 'coils' cool_cap['DX'] += mech_capacity end when /Coil_Cooling_Water/ cooling_type = 'CHW' suppcomp = supplycomp.to_CoilCoolingWater.get mech_capacity = suppcomp.autosizedDesignCoilLoad.to_f/1000.0 cat_search = 'coils' cool_cap['CHW'] += mech_capacity when /OS_AirLoopHVAC_UnitaryHeatPump_AirToAir/ suppcomp = supplycomp.to_AirLoopHVACUnitaryHeatPumpAirToAir.get htg_coil = suppcomp.heatingCoil if htg_coil.to_CoilHeatingDXSingleSpeed.is_initialized htg_coil = htg_coil.to_CoilHeatingDXSingleSpeed.get if htg_coil.isRatedTotalHeatingCapacityAutosized mech_capacity = htg_coil.autosizedRatedTotalHeatingCapacity.to_f/1000.0 else mech_capacity = htg_coil.ratedTotalHeatingCapacity.to_f/1000.0 end heating_fuel = 'HP' cat_search = 'ashp' heat_cap['HP'] += mech_capacity end clg_coil = suppcomp.coolingCoil if clg_coil.to_CoilCoolingDXSingleSpeed.is_initialized clg_coil = clg_coil.to_CoilCoolingDXSingleSpeed.get if clg_coil.isRatedTotalCoolingCapacityAutosized mech_capacity = clg_coil.autosizedRatedTotalCoolingCapacity.to_f/1000.0 else mech_capacity = clg_coil.ratedTotalCoolingCapacity.to_f/1000.0 end cooling_type = 'DX' cat_search = 'coils' cool_cap['DX'] += mech_capacity end supp_htg_coil = suppcomp.supplementalHeatingCoil if supp_htg_coil.to_CoilHeatingElectric.is_initialized supp_htg_coil = supp_htg_coil.to_CoilHeatingElectric.get elsif supp_htg_coil.to_CoilHeatingGas.is_initialized supp_htg_coil = supp_htg_coil.to_CoilHeatingGas.get end if supp_htg_coil.isNominalCapacityAutosized mech_capacity = supp_htg_coil.autosizedNominalCapacity.to_f/1000.0 else mech_capacity = supp_htg_coil.nominalCapacity.to_f/1000.0 end if supp_htg_coil.class.name.include? 'CoilHeatingElectric' cat_search = 'elecheat' heat_cap['elec'] += mech_capacity elsif supp_htg_coil.class.name.include? 'CoilHeatingGas' cat_search = 'FurnaceGas' heat_cap['Gas'] += mech_capacity end end # This hash contains all of the pertinent information required for costing a piece of air loop heating/cooling equipment equipment_info = { sys_type: sys_type, obj_type: obj_type, supply_comp: supplycomp, heating_fuel: heating_fuel, cooling_type: cooling_type, adv_dx_clg_eqpt: adv_dx_clg_eqpt, mech_capacity_kw: mech_capacity, cat_search: cat_search } unless equipment_info[:mech_capacity_kw].to_f <= 0 # Add the piece of air loop equipment to an array for costing if the equipment does something (that is has a size larger than 0) airloop_equipment << equipment_info end end # Determine the predominant heating and cooling fuel type. ahu_heat_cool_info = determine_ahu_htg_clg_fuel(heat_cap: heat_cap, cool_cap: cool_cap, heat_type: heat_type, cool_type: cool_type) heat_type = ahu_heat_cool_info[:heat_type] cool_type = ahu_heat_cool_info[:cool_type] # Cost rooftop ventilation unit. costed_ahu_info = cost_ahu(sys_type: sys_type, airloop_flow_lps: airloop_flow_lps, airloop_flow_cfm: airloop_flow_cfm, mech_sizing_info: mech_sizing_info, heating_fuel: ahu_heat_cool_info[:heating_fuel], cooling_type: ahu_heat_cool_info[:cooling_type], airloop_name: airloop_name, vent_tags: ) # Get ventilation heating and cooling equipment costs. air_loop_equip_return_info = airloop_equipment_costing(airloop_equipment: airloop_equipment, ahu_mult: costed_ahu_info[:mult].to_f, vent_tags: ) # Get the air loop equipment reporting information from the air loop equipment costing method return hash al_eq_reporting_info = air_loop_equip_return_info[:al_eq_reporting_info] # Add the air loop equipment costing to the total air loop cost total_heat_cool_cost += air_loop_equip_return_info[:heat_cool_cost] # Determine information about thermal zones supplied by this air loop and sort it by building floor hvac_floors = gen_hvac_info_by_floor(hvac_floors: hvac_floors, model: model, prototype_creator: prototype_creator, airloop: airloop, sys_type: sys_type, hrv_info: hrv_info) sys_1_4 = false unless (sys_type == 1 || sys_type == 4) reheat_cost, reheat_array = reheat_recool_cost(airloop: airloop, prototype_creator: prototype_creator, model: model, roof_cent: roof_cent, mech_sizing_info: mech_sizing_info, vent_tags: , report_mult: 1.0) if hrv_info[:hrv_present] hrv_rep = hrv_cost(hrv_info: hrv_info, airloop: airloop, vent_tags: , report_mult: 1.0) hrv_total_cost += hrv_rep[:revised_hrv_cost].to_f else hrv_rep = {} end @airloop_info[:hrv] = hrv_rep ahu_cost += costed_ahu_info[:adjusted_base_ahu_cost] + reheat_cost + total_heat_cool_cost @airloop_info[:equipment_info] = al_eq_reporting_info @airloop_info[:reheat_recool] = reheat_array @costing_report['ventilation'].each {|key, value| value << @airloop_info if key.to_s == ('system_' + sys_type.to_s)} end if total_vent_flow_m3_per_s == 0 || total_vent_flow_m3_per_s.nil? puts "No ventilation system is present which can currently be costed." @costing_report['ventilation'] = { error: "No ventilation system is present which can currently be costed." } return 0 end @costing_report['ventilation'][:hrv_total_cost] = hrv_total_cost.round(2) mech_roof_cost, mech_roof_rep = mech_to_roof_cost(heat_type: heat_type, cool_type: cool_type, mech_room: mech_room, roof_cent: roof_cent, rt_unit_num: rt_unit_num) @costing_report['ventilation'][:mech_to_roof] = mech_roof_rep trunk_duct_cost, trunk_duct_info = vent_trunk_duct_cost(tot_air_m3pers: total_vent_flow_m3_per_s, min_space: min_space, roof_cent: roof_cent, mech_sizing_info: mech_sizing_info, sys_1_4: sys_1_4) @costing_report['ventilation'][:trunk_duct] << trunk_duct_info floor_dist_cost, build_floor_trunk_info = floor_vent_dist_cost(hvac_floors: hvac_floors, prototype_creator: prototype_creator, roof_cent: roof_cent, mech_sizing_info: mech_sizing_info) @costing_report['ventilation'][:floor_trunk_ducts] << build_floor_trunk_info tz_dist_cost, duct_dist_rep = tz_vent_dist_cost(hvac_floors: hvac_floors, mech_sizing_info: mech_sizing_info) @costing_report['ventilation'][:tz_distribution] << duct_dist_rep hrv_ducting_cost, hrv_ret_duct_report = hrv_duct_cost(prototype_creator: prototype_creator, roof_cent: roof_cent, mech_sizing_info: mech_sizing_info, hvac_floors: hvac_floors) @costing_report['ventilation'][:hrv_return_ducting] = hrv_ret_duct_report ahu_cost += tz_dist_cost + trunk_duct_cost + floor_dist_cost + hrv_ducting_cost + hrv_total_cost + mech_roof_cost return ahu_cost.round(2) end |
#airloop_equipment_costing(airloop_equipment:, ahu_mult:, vent_tags: []) ⇒ Object
This method oversees the costing of heating and cooling equipment in an air loop. It takes in: airloop_equipment: A hash containing all heating and cooling supply equipment in the air loop The method retruns the airloop_equip_return_info hash which contains: al_eq_reporting_info: A hash containing information that will be included in the ventilation costing report heat_cool_cost: The total cost of heating and cooling equipment in the air loop
2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 2479 def airloop_equipment_costing(airloop_equipment:, ahu_mult:, vent_tags: []) # Initialize return data ret_heat_cool_cost = 0 al_eq_reporting_info = [] ccashp_cost = 0 = .clone << "air loop equipment" # Look for a heat pump. Heat pump air loop equipment costing is treated differently. heat_pumps = airloop_equipment.select{|airloop_eq| airloop_eq[:heating_fuel].to_s.include?('HP')} unless heat_pumps.empty? cool_eq = airloop_equipment.select{|airloop_eq| airloop_eq[:cooling_type].to_s.include?("DX")} unless cool_eq.empty? heat_pumps[0][:mech_capacity_kw] = cool_eq[0][:mech_capacity_kw].to_f if cool_eq[0][:mech_capacity_kw].to_f > heat_pumps[0][:mech_capacity_kw].to_f heat_pumps[0][:cooling_type] = heat_pumps[0][:heating_fuel] airloop_equipment.delete_if{|data| data[:cooling_type].to_s.include?("DX")} end if heat_pumps[0][:heating_fuel].to_s == "CCASHP" ccashp_cost = cost_ccashp_additional_components(ahu_mult: ahu_mult, heat_pump: heat_pumps[0], vent_tags: ) end elec_eq = airloop_equipment.select{|airloop_eq| airloop_eq[:heating_fuel] == 'elec'} # If a backup electric heating coil is present look for a different item in the 'hvac_materials' costing sheet # than if the coil where part of an air loop without a heat pump. elec_eq.each do |el_eq| el_eq[:cat_search] = 'elecduct' end #airloop_equipment.select.with_index{|airloop_eq, index| airloop_eq[:cooling_type] == 'DX' || airloop_eq[:cooling_type] == 'CCASHP'} end # Cost all of the heating and cooling equipment in the air loop airloop_equipment.each do |airloop_eq| # Costing of air loop equipment should be done on a per air handler basis. Thus, divide the total capacity of the # piece of air loop equipment by the number of air handlers required. total_modeled_capacity = airloop_eq[:mech_capacity_kw].to_f airloop_eq[:mech_capacity_kw] = total_modeled_capacity / ahu_mult # Get ventilation heating and cooling equipment costs. heat_cool_cost = cost_heat_cool_equip(equipment_info: airloop_eq, vent_tags: , report_mult: ahu_mult) * ahu_mult heat_cool_cost += ccashp_cost if airloop_eq[:heating_fuel].to_s == "CCASHP" # Add the equipment cost to the total air loop equipment cost ret_heat_cool_cost += heat_cool_cost # Only the total modeled capacity of the piece of air loop equipment should be reported to the user rather than # the capacity per air handler. airloop_eq[:mech_capacity_kw] = total_modeled_capacity # Add the air loop hetaing/cooling equipment information to the total air loop heating/cooling equipment report hash al_eq_reporting_info = add_heat_cool_to_report(equipment_info: airloop_eq, heat_cool_cost: heat_cool_cost, al_eq_reporting_info: al_eq_reporting_info) end # Create the return hash and return it. airloop_equip_return_info = { al_eq_reporting_info: al_eq_reporting_info, heat_cool_cost: ret_heat_cool_cost } return airloop_equip_return_info end |
#assembly_cost(cost_info:, sheet_name:, column_1:, column_2:, quantity:, tags:) ⇒ Object
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 |
# File 'lib/openstudio-standards/btap/costing/pv_ground_costing.rb', line 626 def assembly_cost(cost_info:, sheet_name:, column_1:, column_2:, quantity:, tags:) #------------------------------------------------------------------------------------------------------------------- ### Step I: find mat_id mat_data = nil mat_data = @costing_database['raw'][sheet_name].select { |data| data[column_1].to_s.upcase == cost_info[:row_id_1].to_s.upcase and data[column_2].to_f.round(1) == cost_info[:row_id_2].to_f.round(1) }.first mat_id = mat_data['id'] material_adjust = mat_data['material_mult'] labour_adjust = mat_data['labour_mult'] material_adjust = 1.0 if material_adjust.nil? labour_adjust = 1.0 if labour_adjust.nil? #------------------------------------------------------------------------------------------------------------------- ### Step II: calculate unit cost mat_cost_info = @costing_database['costs'].select { |data| data['id'] == mat_id.to_s.upcase }.first regional_material, regional_installation, regional_equipment = get_regional_cost_factors(@costing_report["province_state"], @costing_report["city"], mat_cost_info) # puts "regional_material, regional_installation, regional_equipment #{regional_material}, #{regional_installation}, #{regional_equipment}" if mat_cost_info['baseCosts']['materialOpCost'].nil? cost_material = 0.0 else cost_material = mat_cost_info['baseCosts']['materialOpCost'] * (regional_material / 100.0) * material_adjust.to_f end if mat_cost_info['baseCosts']['laborOpCost'].nil? cost_labour = 0.0 else cost_labour = mat_cost_info['baseCosts']['laborOpCost'] * (regional_installation / 100.0) * labour_adjust.to_f end if mat_cost_info['baseCosts']['equipmentOpCost'].nil? cost_equipment = 0.0 else cost_equipment = mat_cost_info['baseCosts']['equipmentOpCost'] * (regional_equipment / 100.0) end cost_unit = cost_material + cost_labour + cost_equipment # puts "cost_unit is #{cost_unit}" #------------------------------------------------------------------------------------------------------------------- ### Step III: calculate total cost cost_total = cost_unit * quantity # puts "cost_total is #{cost_total}" #------------------------------------------------------------------------------------------------------------------- # Gather info for costed items output file unless mat_data['Material'].nil? << mat_data['Material'] end unless mat_data['description'].nil? << mat_data['description'] end if not .empty? add_costed_item(material_id: mat_id.to_s, quantity: quantity, material_mult: material_adjust.to_f, labour_mult: labour_adjust.to_f, equip_mult: 1.0, tags: ) end return cost_total end |
#boiler_costing(model, prototype_creator) ⇒ Object
This function gets all costs associated with boilers (i.e., boilers, pumps, flues, electrical lines and boxes, fuel lines and distribution piping to zonal heating units)
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 7 def boiler_costing(model, prototype_creator) #Global flag to determine if a GSHP is present @gshp_flag = false #Global flag to determine if a AWHP is present @awhp_flag = false totalCost = 0.0 # Get regional cost factors for this province and city materials_hvac = @costing_database["raw"]["materials_hvac"] hvac_material = materials_hvac.select {|data| data['Material'].to_s == "GasBoilers"}.first # Get any row from spreadsheet in case of region error regional_material, regional_installation = get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material) # Get regional electric cost factors for this province and city hvac_material = materials_hvac.select {|data| data['Material'].to_s.upcase == "BOX" && data['Size'].to_i == 1}.first reg_mat_elec, reg_lab_elec = get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material) # Store some geometry data for use below... util_dist, ht_roof, nom_flr_hght, horz_dist, numAGFlrs, mechRmInBsmt = getGeometryData(model, prototype_creator) template_type = prototype_creator.template plant_loop_info = {} plant_loop_info[:boilers] = [] plant_loop_info[:boilerpumps] = [] # Iterate through the plant loops to get boiler & pump data... model.getPlantLoops.each do |plant_loop| next unless (plant_loop.name.get.to_s.downcase == "hot water loop") || (plant_loop.name.get.to_s.downcase == "hw plantloop") plant_loop.supplyComponents.each do |supply_comp| if supply_comp.to_BoilerHotWater.is_initialized boiler = supply_comp.to_BoilerHotWater.get boiler_info = {} plant_loop_info[:boilers] << boiler_info boiler_info[:name] = boiler.name.get # 2020-09-01 CK Include efficiency for boiler upgrade costing boiler_info[:efficiency] = boiler.nominalThermalEfficiency.to_f if boiler.fuelType =~ /Electric/i boiler_info[:fueltype] = 'ElecBoilers' elsif boiler.fuelType =~ /NaturalGas/i boiler_info[:fueltype] = 'GasBoilers' #2020-09-01 CK Include modifications for condensing and pulse gas boilers if boiler_info[:efficiency] >= 0.827 && boiler_info[:efficiency] < 0.9 boiler_info[:fueltype] = "CondensingBoilers" elsif boiler_info[:efficiency] >= 0.9 boiler_info[:fueltype] = "PulseBoilers" end elsif boiler.fuelType =~ /Oil/i # Oil, FuelOil, FuelOil#2 boiler_info[:fueltype] = 'OilBoilers' end boiler_info[:nominal_capacity] = boiler.nominalCapacity.to_f / 1000 # kW elsif supply_comp.to_PumpConstantSpeed.is_initialized csPump = supply_comp.to_PumpConstantSpeed.get csPump_info = {} plant_loop_info[:boilerpumps] << csPump_info csPump_info[:name] = csPump.name.get if csPump.isRatedPowerConsumptionAutosized.to_bool csPumpSize = csPump.autosizedRatedPowerConsumption.to_f else csPumpSize = csPump.ratedPowerConsumption.to_f end csPump_info[:size] = csPumpSize.to_f # Watts if csPump.isRatedFlowRateAutosized.to_bool csPump_info[:water_flow_m3_per_s] = csPump.autosizedRatedFlowRate.to_f else csPump_info[:water_flow_m3_per_s] = csPump.ratedFlowRate.to_f end elsif supply_comp.to_PumpVariableSpeed.is_initialized vsPump = supply_comp.to_PumpVariableSpeed.get vsPump_info = {} plant_loop_info[:boilerpumps] << vsPump_info vsPump_info[:name] = vsPump.name.get if vsPump.isRatedPowerConsumptionAutosized.to_bool vsPumpSize = vsPump.autosizedRatedPowerConsumption.to_f else vsPumpSize = vsPump.ratedPowerConsumption.to_f end vsPump_info[:size] = vsPumpSize.to_f # Watts if vsPump.isRatedFlowRateAutosized.to_bool vsPump_info[:water_flow_m3_per_s] = vsPump.autosizedRatedFlowRate.to_f else vsPump_info[:water_flow_m3_per_s] = vsPump.ratedFlowRate.to_f end elsif supply_comp.to_HeatPumpWaterToWaterEquationFitHeating.is_initialized gshp = supply_comp.to_HeatPumpWaterToWaterEquationFitHeating.get gshp_info = {} gshp_info[:fueltype] = 'wshp' gshp_info[:name] = gshp.name.to_s if gshp.isRatedHeatingCapacityAutosized.to_bool gshp_info[:nominal_capacity] = gshp.autosizedRatedHeatingCapacity.to_f/1000.0 else gshp_info[:nominal_capacity] = gshp.ratedHeatingCapacity.to_f/1000.0 end plant_loop_info[:boilers] << gshp_info @gshp_flag = true elsif supply_comp.to_HeatPumpPlantLoopEIRHeating.is_initialized awhp = supply_comp.to_HeatPumpPlantLoopEIRHeating.get awhp_info = {} awhp_info[:fueltype] = 'Airtowaterhp' awhp_info[:name] = awhp.name.to_s if awhp.isReferenceCapacityAutosized.to_bool awhp_info[:nominal_capacity] = awhp.autosizedReferenceCapacity.to_f/1000.0 else awhp_info[:nominal_capacity] = awhp.referenceCapacity.to_f/1000.0 end plant_loop_info[:boilers] << awhp_info @awhp_flag = true end end end boilerCost = 0.0 ; thisBoilerCost = 0.0 ; flueCost = 0.0 ; utilCost = 0.0 ; fuelFittingCost = 0.0 numBoilers = 0 ; multiplier = 1.0 ; primaryFuel = ''; primaryCap = 0 ; backupBoiler = false # Get costs associated with each boiler plant_loop_info[:boilers].each do |boiler| # Get primary/secondary/backup boiler cost based on fuel type and capacity for each boiler # 06-Sep-2019 JTB: Added check for no 'Primary' or 'Secondary' label and assume primary. # This boiler prefix name seemed to disappear after the heat pump work was committed. numBoilers += 1 if boiler[:name] =~ /primary/i || (boiler[:name] !~ /primary/i && boiler[:name] !~ /secondary/ && numBoilers == 1) || (boiler[:fuel_type] == 'wshp') || (boiler[:fuel_type] == 'Airtowaterhp') primaryFuel = boiler[:fueltype] primaryCap = boiler[:nominal_capacity] matCost, labCost = getHVACCost(boiler[:name], boiler[:fueltype], boiler[:nominal_capacity], false) # 2020-09-02 CK: Assume condensing oil boilers cost twice as much as non-condensing oil boilers if boiler[:fueltype] == 'OilBoilers' && boiler[:efficiency] >= 0.9 thisBoilerCost = matCost * 2 * regional_material / 100.0 + labCost * regional_installation / 100.0 else thisBoilerCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 end # Flue and utility component costs (for gas and oil boilers only) # 2020-09-02 CK: Include pulse and condensing gas boilers to those with utility component costs if boiler[:fueltype] == 'GasBoilers' || boiler[:fueltype] == 'OilBoilers' || boiler[:fueltype] == 'CondensingBoilers' || boiler[:fueltype] == 'PulseBoilers' # Calculate flue costs once for all boilers since flues combined by header when multiple boilers # 6 inch diameter flue (#384) materialHash = get_cost_info(mat: 'Venting', size: '6') matCost, labCost = getCost('flue', materialHash, multiplier) flueVentCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 #6 inch elbow fitting (#386) materialHash = get_cost_info(mat: 'VentingElbow', size: '6') matCost, labCost = getCost('flue elbow', materialHash, multiplier) flueElbowCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # 6 inch top (#392) materialHash = get_cost_info(mat: 'VentingTop', size: '6') matCost, labCost = getCost('flue top', materialHash, multiplier) flueTopCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # Gas/Oil line piping cost per ft (#1) materialHash = get_cost_info(mat: 'GasLine', unit: 'L.F.') matCost, labCost = getCost('fuel line', materialHash, multiplier) fuelLineCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # Gas/Oil line fitting connection per boiler (#2) materialHash = get_cost_info(mat: 'GasLine', unit: 'each') matCost, labCost = getCost('fuel line fitting connection', materialHash, multiplier) fuelFittingCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # Header cost only non-zero if there is a secondary/backup gas/oil boiler headerCost = 0.0 else # Electric has no flue flueVentCost = 0.0 ; flueElbowCost = 0.0 ; flueTopCost = 0.0 ; headerCost = 0.0 end # Electric utility cost components (i.e., power lines). # Calculate utility cost for primary boiler only since multiple boilers use common utilities # elec 600V #14 wire /100 ft (#848) materialHash = get_cost_info(mat: 'Wiring', size: 14) matCost, labCost = getCost('electrical wire - 600V #14', materialHash, multiplier) elecWireCost = matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0 # 1 inch metal conduit (#851) materialHash = get_cost_info(mat: 'Conduit', unit: 'L.F.') matCost, labCost = getCost('1 inch metal conduit', materialHash, multiplier) = matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0 # 2020-09-02 CK Adding Condensing and Pulse boilers to those that need additional connections if boiler[:fueltype] == 'GasBoilers' || boiler[:fueltype] == 'CondensingBoilers' || boiler[:fueltype] == 'PulseBoilers' # Gas boilers require fuel line+valves+connectors and electrical conduit utilCost += (fuelLineCost + ) * util_dist + fuelFittingCost + elecWireCost * util_dist / 100 elsif boiler[:fueltype] == 'OilBoilers' # Oil boilers require fuel line+valves+connectors and electrical conduit # Oil filtering system (#4) materialHash = get_cost_info(mat: 'OilLine', unit: 'each') matCost, labCost = getCost('Oil filtering system', materialHash, multiplier) oilFilterCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # 2000 USG above ground tank (#5) materialHash = get_cost_info(mat: 'OilTanks', size: 2000) matCost, labCost = getCost('Oil tank (2000 USG)', materialHash, multiplier) oilTankCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 utilCost += (fuelLineCost + ) * util_dist + fuelFittingCost + elecWireCost * util_dist / 100 + oilFilterCost + oilTankCost elsif boiler[:fueltype].to_s.downcase == 'elecboilers' || boiler[:fueltype].to_s.downcase == 'wshp' # Electric boilers require only conduit utilCost += * util_dist + elecWireCost * util_dist / 100 elsif boiler[:fuel_type].to_s.downcase == 'airtowaterhp' # Add heating buffer tank for awhp materialHash = get_cost_info(mat: 'solartank', size: 450) matCost, labCost = getCost('solartank', materialHash, multiplier) utilCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 end elsif boiler[:name] =~ /secondary/i || numBoilers > 1 if boiler[:nominal_capacity] > 0.1 # A secondary boiler exists so use it for costing matCost, labCost = getHVACCost(boiler[:name], boiler[:fueltype], boiler[:nominal_capacity], false) # 2020-09-02 CK: Assume condensing oil boilers cost twice as much as non-condensing oil boilers if boiler[:fueltype] == 'OilBoilers' && boiler[:efficiency] >= 0.9 thisBoilerCost = matCost * 2 * regional_material / 100.0 + labCost * regional_installation / 100.0 else thisBoilerCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 end else # Use existing value of thisBoilerCost to represent a backup boiler! # This just doubles the cost of the primary boiler. # 2023-04-25: Leaving backup boiler in energy model but no longer costing. backupBoiler = false thisBoilerCost = 0.0 numBoilers -= 1 end # Flue costs set to zero if secondary boiler since already calculated in primary flueVentCost = 0.0; flueElbowCost = 0.0; flueTopCost = 0.0 # Check if need a flue header (i.e., there are both primary and secondary/backup boilers) if thisBoilerCost > 0.0 && ( (backupBoiler && primaryFuel != 'ElecBoilers') || (boiler[:fueltype] != 'ElecBoilers') || (boiler[:fueltype] != 'wshp') || (boiler[:fueltype] != 'Airtowaterhp')) # 6 inch diameter header (#384) materialHash = get_cost_info(mat: 'Venting', size: 6) matCost, labCost = getCost('flue header', materialHash, multiplier) headerVentCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 #6 inch elbow fitting for header (#386) materialHash = get_cost_info(mat: 'VentingElbow', size: 6) matCost, labCost = getCost('flue header elbow', materialHash, multiplier) headerElbowCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # Assume a header length of 20 ft and an elbow fitting for each boiler connected to the header headerCost = (headerVentCost * 20 + headerElbowCost) * numBoilers else headerCost = 0.0 end end boilerCost += thisBoilerCost flueCost += flueVentCost * ht_roof + flueElbowCost + flueTopCost + headerCost if numBoilers > 1 # Adjust utility cost for extra fuel line fitting cost utilCost += fuelFittingCost * (numBoilers - 1) end end # Boiler pump costs pumpCost = 0.0; pipingToPumpCost = 0.0; numPumps = 0; pumpName = ''; pumpSize = 0.0 ; pumpFlow = 0.0 plant_loop_info[:boilerpumps].each do |pump| numPumps += 1 # Cost variable and constant volume pumps the same (the difference is in extra cost for VFD controller) pumpSize = pump[:size]; pumpName = pump[:name] pumpFlow += pump[:water_flow_m3_per_s].to_f matCost, labCost = getHVACCost(pumpName, 'Pumps', pumpSize, false) pumpCost += matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 if pump[:name] =~ /variable/i # Cost the VFD controller for the variable pump matCost, labCost = getHVACCost(pumpName, 'VFD', pumpSize, false) pumpCost += matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0 end end if numBoilers > 1 && numPumps < 2 # Add pump costing for the backup boiler pump. pumpCost *= 2.0 numPumps = 2 # reset the number of pumps for piping costs below end # Double the pump costs to accomodate the costing of a backup pumps for each boiler! # No longer costing backup pumps. # pumpCost *= 2.0 # Boiler water piping to pumps cost: Add piping elbows, valves and insulation from the boiler(s) # to the pumps(s) assuming a pipe diameter of 1” and a distance of 10 ft per pump if numBoilers > 0 # 1 inch Steel pipe matCost, labCost = getHVACCost('1 inch steel pipe', 'SteelPipe', 1) pipingToPumpCost += 10.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 1 inch Steel pipe insulation matCost, labCost = getHVACCost('1 inch pipe insulation', 'PipeInsulation', 1) pipingToPumpCost += 10.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 1 inch Steel pipe elbow matCost, labCost = getHVACCost('1 inch steel pipe elbow', 'SteelPipeElbow', 1) pipingToPumpCost += 2.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 1 inch gate valves matCost, labCost = getHVACCost('1 inch gate valves', 'ValvesGate', 1) pipingToPumpCost += 1.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) end if numBoilers > 0 # Double pump piping cost to account for second boiler pipingToPumpCost *= numBoilers hdrDistributionCost = getHeaderPipingDistributionCost(numAGFlrs, mechRmInBsmt, regional_material, regional_installation, reg_mat_elec, reg_lab_elec, pumpFlow, horz_dist, nom_flr_hght) else pipingToPumpCost = 0 hdrDistributionCost = 0 end totalCost = boilerCost + flueCost + utilCost + pumpCost + pipingToPumpCost + hdrDistributionCost @costing_report['heating_and_cooling']['plant_equipment'] << { 'type' => 'boilers', 'nom_flr2flr_hght_ft' => nom_flr_hght.round(1), 'ht_roof_ft' => ht_roof.round(1), 'longest_distance_to_ext_ft' => horz_dist.round(1), 'wiring_and_gas_connections_distance_ft' => util_dist.round(1), 'equipment_cost' => boilerCost.round(0), 'flue_cost' => flueCost.round(0), 'wiring_and_gas_connections_cost' => utilCost.round(0), 'pump_cost' => pumpCost.round(0), 'piping_to_pump_cost' => pipingToPumpCost.round(0), 'header_distribution_cost' => hdrDistributionCost.round(0), 'total_cost' => totalCost.round(0) } puts "\nHVAC Boiler costing data successfully generated. Total boiler costs: $#{totalCost.round(0)}" return totalCost end |
#chiller_costing(model, prototype_creator) ⇒ Object
Chiller costing is similar to boiler costing above
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 354 def chiller_costing(model, prototype_creator) totalCost = 0.0 # Get regional cost factors for this province and city materials_hvac = @costing_database["raw"]["materials_hvac"] hvac_material = materials_hvac.select {|data| data['Material'].to_s == "GasBoilers"}.first # Get any row from spreadsheet in case of region error regional_material, regional_installation = get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material) # Get regional electric cost factors for this province and city hvac_material = materials_hvac.select {|data| data['Material'].to_s.upcase == "BOX" && data['Size'].to_i == 1}.first reg_mat_elec, reg_lab_elec = get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material) # Store some geometry data for use below... util_dist, ht_roof, nom_flr_hght, horz_dist, numAGFlrs, mechRmInBsmt = getGeometryData(model, prototype_creator) template_type = prototype_creator.template chillerCost = 0.0 ; thisChillerCost = 0.0 ; flueCost = 0.0 ; utilCost = 0.0 plant_loop_info = {} plant_loop_info[:chillers] = [] plant_loop_info[:chillerpumps] = [] awhp_chiller = false # Iterate through the plant loops to get chiller & pump data... model.getPlantLoops.each do |plant_loop| next unless (plant_loop.name.get.to_s.downcase == "chilled water loop") || (plant_loop.name.get.to_s.downcase == "chw plantloop") plant_loop.supplyComponents.each do |supply_comp| if supply_comp.to_ChillerElectricEIR.is_initialized #|| supply_comp.to_ChillerGasEIR.is_initialized chiller = supply_comp.to_ChillerElectricEIR.get chiller_info = {} plant_loop_info[:chillers] << chiller_info chiller_info[:name] = chiller.name.get if chiller_info[:name] =~ /WaterCooled/i if chiller_info[:name] =~ /Absorption/i chiller_info[:type] = 'HotAbsChiller' chiller_info[:fuel] = 'NaturalGas' elsif chiller_info[:name] =~ /Direct Gas/i chiller_info[:type] = 'GasAbsChiller' chiller_info[:fuel] = 'NaturalGas' elsif chiller_info[:name] =~ /Centrifugal/i chiller_info[:type] = 'CentChillerWater' chiller_info[:fuel] = 'Electric' elsif chiller_info[:name] =~ /Reciprocating/i chiller_info[:type] = 'RecChillerWater' chiller_info[:fuel] = 'Electric' elsif chiller_info[:name] =~ /Scroll/i chiller_info[:type] = 'ScrollChillerWater' chiller_info[:fuel] = 'Electric' elsif chiller_info[:name] =~ /Screw/i chiller_info[:type] = 'ScrewChillerWater' chiller_info[:fuel] = 'Electric' end elsif chiller_info[:name] =~ /AirCooled/i if chiller_info[:name] =~ /Reciprocating/i chiller_info[:type] = 'RecChillerAir' chiller_info[:fuel] = 'Electric' elsif chiller_info[:name] =~ /Scroll/i chiller_info[:type] = 'ScrollChillerAir' chiller_info[:fuel] = 'Electric' elsif chiller_info[:name] =~ /Screw/i chiller_info[:type] = 'ScrewChillerAir' chiller_info[:fuel] = 'Electric' elsif chiller_info[:name] =~ /DX/i chiller_info[:type] = 'DXChiller' chiller_info[:fuel] = 'Electric' end end chiller_info[:reference_capacity] = chiller.referenceCapacity.to_f / 1000 # kW elsif supply_comp.to_HeatPumpPlantLoopEIRCooling.is_initialized chiller = supply_comp.to_HeatPumpPlantLoopEIRCooling.get chiller_info = {} chiller_info[:name] = chiller.name.get chiller_info[:type] = 'Airtowaterhp' chiller_info[:fuel] = 'Electric' if chiller.isReferenceCapacityAutosized chiller_info[:reference_capacity] = chiller.autosizedReferenceCapacity.to_f / 1000 # kW else chiller_info[:reference_capacity] = chiller.referenceCapacity.to_f / 1000 # kW end awhp_chiller = true plant_loop_info[:chillers] << chiller_info elsif supply_comp.to_PumpConstantSpeed.is_initialized csPump = supply_comp.to_PumpConstantSpeed.get csPump_info = {} plant_loop_info[:chillerpumps] << csPump_info csPump_info[:name] = csPump.name.get if csPump.isRatedPowerConsumptionAutosized.to_bool csPumpSize = csPump.autosizedRatedPowerConsumption.to_f else csPumpSize = csPump.ratedPowerConsumption.to_f end csPump_info[:size] = csPumpSize.to_f # Watts if csPump.isRatedFlowRateAutosized.to_bool csPump_info[:water_flow_m3_per_s] = csPump.autosizedRatedFlowRate.to_f else csPump_info[:water_flow_m3_per_s] = csPump.ratedFlowRate.to_f end elsif supply_comp.to_PumpVariableSpeed.is_initialized vsPump = supply_comp.to_PumpVariableSpeed.get vsPump_info = {} plant_loop_info[:chillerpumps] << vsPump_info vsPump_info[:name] = vsPump.name.get if vsPump.isRatedPowerConsumptionAutosized.to_bool vsPumpSize = vsPump.autosizedRatedPowerConsumption.to_f else vsPumpSize = vsPump.ratedPowerConsumption.to_f end vsPump_info[:size] = vsPumpSize.to_f # Watts if vsPump.isRatedFlowRateAutosized.to_bool vsPump_info[:water_flow_m3_per_s] = vsPump.autosizedRatedFlowRate.to_f else vsPump_info[:water_flow_m3_per_s] = vsPump.ratedFlowRate.to_f end end end end # Get costs associated with each chiller numChillers = 0 ; multiplier = 1.0 primaryFuel = ''; primaryCap = 0 plant_loop_info[:chillers].each do |chiller| # Get primary/secondary/backup chiller cost based on type and capacity for each chiller # 06-Sep-2019 JTB: Added check for no 'Primary' or 'Secondary' label and assume primary. # This chiller prefix name seemed to disappear after the heat pump work was committed. numChillers += 1 if chiller[:type].to_s.downcase == 'airtowaterhp' primaryFuel = chiller[:fuel] primaryCap = chiller[:reference_capacity] #kW # Add cooling buffer tank for awhp materialHash = get_cost_info(mat: 'solartank', size: 450) matCost, labCost = getCost('solartank', materialHash, multiplier) #Costing for AWHP only buffer tank, AWHP included in boiler cost thisChillerCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # Include 2 expansion tanks for awhp materialHash = get_cost_info(mat: 'ExpansionTanks', size: 60) matCost, labCost = getCost('ExpansionTanks', materialHash, multiplier) #Costing for AWHP only buffer tank, AWHP included in boiler cost thisChillerCost += (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * 2 # Inclide glycol cost materalHash = get_cost_info(mat: 'glycol') matCost, labCost = getCost('solartank', materialHash, multiplier) #Costing for AWHP only buffer tank, AWHP included in boiler cost thisChillerCost += (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * 2 flueVentCost = 0.0 ; flueElbowCost = 0.0 ; flueTopCost = 0.0 ; headerCost = 0.0 elsif ((chiller[:name].to_s.downcase =~ /primary/i || (chiller[:name] !~ /primary/i && chiller[:name] !~ /secondary/i && numChillers == 1)) || (@gshp_flag)) primaryFuel = chiller[:fuel] primaryCap = chiller[:reference_capacity] #kW if not chiller[:name].include?("ChillerElectricEIR_VSDCentrifugalWaterChiller") matCost, labCost = getHVACCost(chiller[:name], chiller[:type], chiller[:reference_capacity], false) thisChillerCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 elsif chiller[:name].include?("ChillerElectricEIR_VSDCentrifugalWaterChiller") thisChillerCost = vsd_chiller_cost(primaryCap: primaryCap) end # Flue cost for gas (absorption) chillers! if chiller[:fuel] == 'NaturalGas' # Calculate flue costs once for all chillets since flues combined by header when multiple chillers # 6 inch diameter flue (#384) materialHash = get_cost_info(mat: 'Venting', size: 6) matCost, labCost = getCost('flue', materialHash, multiplier) flueVentCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 #6 inch elbow fitting (#386) materialHash = get_cost_info(mat: 'VentingElbow', size: 6) matCost, labCost = getCost('flue elbow', materialHash, multiplier) flueElbowCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # 6 inch top (#392) materialHash = get_cost_info(mat: 'VentingTop', size: 6) matCost, labCost = getCost('flue top', materialHash, multiplier) flueTopCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # Gas line piping cost per ft (#1) materialHash = get_cost_info(mat: 'GasLine', unit: 'L.F.') matCost, labCost = getCost('fuel line', materialHash, multiplier) fuelLineCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # Gas line fitting connection per boiler (#2) materialHash = get_cost_info(mat: 'GasLine', unit: 'each') matCost, labCost = getCost('fuel line fitting connection', materialHash, multiplier) fuelFittingCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # Header cost only non-zero if there is a secondary/backup gas/oil boiler headerCost = 0.0 else # Electric flueVentCost = 0.0 ; flueElbowCost = 0.0 ; flueTopCost = 0.0 ; headerCost = 0.0 end # Electric utility costs (i.e., power lines). # Calculate utility cost components for primary chiller only since multiple chillers use common utilities # elec 600V #14 wire /100 ft (#848) materialHash = get_cost_info(mat: 'Wiring', size: 14) matCost, labCost = getCost('electrical wire - 600V #14', materialHash, multiplier) elecWireCost = matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0 # 1 inch metal conduit (#851) materialHash = get_cost_info(mat: 'Conduit', unit: 'L.F.') matCost, labCost = getCost('1 inch metal conduit', materialHash, multiplier) = matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0 if chiller[:fuel] == 'NaturalGas' # Gas chillers require fuel line+valves+connectors and electrical conduit utilCost += (fuelLineCost + ) * util_dist + fuelFittingCost + elecWireCost * util_dist / 100 else # Electric # Electric chillers require only conduit utilCost += * util_dist + elecWireCost * util_dist / 100 end elsif (chiller[:name].to_s.downcase =~ /secondary/i || numChillers > 1) if chiller[:reference_capacity] <= 0.1 # Chiller cost is zero! thisChillerCost = 0.0 numChillers -= 1 else # A secondary chiller exists so use it for costing if not chiller[:name].include?("ChillerElectricEIR_VSDCentrifugalWaterChiller") matCost, labCost = getHVACCost(chiller[:name], chiller[:type], chiller[:reference_capacity], false) thisChillerCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 elsif chiller[:name].include?("ChillerElectricEIR_VSDCentrifugalWaterChiller") thisChillerCost = vsd_chiller_cost(primaryCap: primaryCap) end end # Flue costs set to zero if secondary chiler since already calculated in primary (if gas absorption) flueVentCost = 0.0; flueElbowCost = 0.0; flueTopCost = 0.0 # Check if need a flue header (i.e., both primary and secondary chillers are gas absorption) if thisChillerCost > 0.0 && primaryFuel == 'NaturalGas' && chiller[:fuel] == 'NaturalGas' # 6 inch diameter header (#384) materialHash = get_cost_info(mat: 'Venting', size: 6) matCost, labCost = getCost('flue header', materialHash, multiplier) headerVentCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 #6 inch elbow fitting for header (#386) materialHash = get_cost_info(mat: 'VentingElbow', size: 6) matCost, labCost = getCost('flue header elbow', materialHash, multiplier) headerElbowCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # Assume a header length of 20 ft and an elbow fitting for each boiler connected to the header headerCost = (headerVentCost * 20 + headerElbowCost) * numChillers else headerCost = 0.0 end end chillerCost += thisChillerCost flueCost += flueVentCost * ht_roof + flueElbowCost + flueTopCost + headerCost if numChillers > 1 && primaryFuel == 'NaturalGas' # Adjust utility cost for extra fuel line fitting cost utilCost += fuelFittingCost * (numChillers - 1) end if numChillers < 2 # Create a cost for a backup chiller by doubling cost of primary chiller # 2023-04-25: Although backup chillers may be modeled we are no longer counting them. #chillerCost *= 2.0 numChillers = 1 end end # Chiller pump costs pumpCost = 0.0; pipingToPumpCost = 0.0; numPumps = 0; pumpName = ''; pumpSize = 0.0 ; pumpFlow = 0.0 plant_loop_info[:chillerpumps].each do |pump| numPumps += 1 # Cost variable and constant volume pumps the same (the difference is in extra cost for VFD controller) pumpSize = pump[:size]; pumpName = pump[:name] pumpFlow += pump[:water_flow_m3_per_s].to_f matCost, labCost = getHVACCost(pumpName, 'Pumps', pumpSize, false) indpumpCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 if pump[:name] =~ /variable/i # Cost the VFD controller for the variable pump costed above matCost, labCost = getHVACCost(pumpName, 'VFD', pumpSize, false) indpumpCost += matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0 end if awhp_chiller pumpCost += indpumpCost * 2 else pumpCost += indpumpCost end end if (numChillers > 1 && numPumps < 2) # Add pump costing for additional chillers pumpCost *= 2.0 numPumps = 2 # reset the number of pumps for piping costs below numChillers = 2 end # Double the pump costs to accomodate the costing of backup pumps for each chiller! # No longer costing backup pump CK 2023-06-23 #pumpCost *= 2.0 # Chiller water piping cost: Add piping elbows, valves and insulation from the chiller(s) # to the pumps(s) assuming a pipe diameter of 1” and a distance of 10 ft per pump if numChillers > 0 # 1 inch Steel pipe matCost, labCost = getHVACCost('1 inch steel pipe', 'SteelPipe', 1) pipingToPumpCost = 10.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 1 inch Steel pipe insulation matCost, labCost = getHVACCost('1 inch pipe insulation', 'PipeInsulation', 1) pipingToPumpCost += 10.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 1 inch Steel pipe elbow matCost, labCost = getHVACCost('1 inch steel pipe elbow', 'SteelPipeElbow', 1) pipingToPumpCost += 2.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 1 inch gate valves matCost, labCost = getHVACCost('1 inch gate valves', 'ValvesGate', 1) pipingToPumpCost += 1.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) end if numChillers > 0 # Double pump piping cost to account for second chiller pipingToPumpCost *= 2 if awhp_chiller pipingToPumpCost *= numChillers hdrDistributionCost = getHeaderPipingDistributionCost(numAGFlrs, mechRmInBsmt, regional_material, regional_installation, reg_mat_elec, reg_lab_elec, pumpFlow, horz_dist, nom_flr_hght) else pipingToPumpCost = 0 hdrDistributionCost = 0 end totalCost = chillerCost + flueCost + utilCost + pumpCost + pipingToPumpCost + hdrDistributionCost @costing_report['heating_and_cooling']['plant_equipment'] << { 'type' => 'chillers', 'nom_flr2flr_hght_ft' => nom_flr_hght.round(1), 'ht_roof_ft' => ht_roof.round(1), 'longest_distance_to_ext_ft' => horz_dist.round(1), 'wiring_and_gas_connections_distance_ft' => util_dist.round(1), 'equipment_cost' => chillerCost.round(0), 'flue_cost' => flueCost.round(0), 'wiring_and_gas_connections_cost' => utilCost.round(0), 'pump_cost' => pumpCost.round(0), 'piping_to_pump_cost' => pipingToPumpCost.round(0), 'header_distribution_cost' => hdrDistributionCost.round(0), 'total_cost' => totalCost.round(0) } puts "\nHVAC Chiller costing data successfully generated. Total chiller costs: $#{totalCost.round(0)}" return totalCost end |
#compileZonalVRFFloors(vrfSystemFloors:, tzFloor:) ⇒ Object
This method takes information about a thermal zone served by a VRF system (tzFloor) and adds it to the collection of thermal zones also served by VRF systems on the same floor. The ultimate output (once all thermal zones are read) is an array of hashes. Each entry in the array represents a floor of the building. Each floor entry contains information about thermal zones served by VRF systems on that floor.
The information on the thermal zone served by a VRF system on a given floor is contained in tzFloor. The overall collection of thermal zone information by floors is contained in vrfSystemFloors. This method modifies vrfSystemFloors which is why that is an input and output for the method. Both tzFloor and vrfSystemFloors are described below: Input:
tzFloor = {
tzName(string): Name of the thermal zone.
tzFloorName(string): Name of the floor the thermal zone is on (or if the TZ is on multiple floors the
name of the current floor being looked at for the thermal zone).
tzFloorCeilingAream2(float): The ceiling area (m2) of the thermal zone on the given floor (this is for the
current thermal zone only and does not include multiples).
tzMult(float): The multiplier for the thermal zone (that is the thermal zone is modeled as tzMult number
of identical thermal zones).
tzSpaces(array): An array containing all of the space objects contained by the thermal zone on the given
floor.
tzSpaceMults(array): An array containing all of the multipliers for the spaces in tzSpaces (probably all the
same as tzMult but I added it anyway).
tzFloorArea_m2(float): The floor area (m2) of all of the spaces in the thermal zone on the given floor (this
is for the current thermal zone only and does not include multiples).
tzFloorCapkW(float): The capacity (kW) of the thermal zone VRF system for the current floor. It is the
highest of the heating and cooling capacities for the VRF system. It dose not include
multipliers and is only for the current floor. If the same thermal zone spans multiple
floors then this is the total copacity for the thermal zone times tzFloorArea_m2
divided by the total floor area for the thermal zone.
tzCentroid(array): This is an array containing three items. These items ore x, y and z coordinates of the
centroid of the current thermal zone on the current floor referenced to the global
origin for the building. The units are in m. Note that, depending on the shape of the
thermal zone on the current floor, the centroid may not actually lie in the thermal
zone (e.g. for an L shaped thermal zone the centroid may be outside the L).
vrfCeilMountInfo(hash): This is a hash containing the costing information, from the costing spreadsheet, for
the VRF ceiling mounts serving the thermal zone on the current floor. It is only
for the current floor and does not include tz multipliers.
vrfCeilMountCost(float): The cost of the VRF ceiling mounts serving the thermal zone on the current floor.
It is only for the current floor and does not include tz multipliers.
vrfSysContCost: The cost of the VRF system controllers that are associated with each VRF ceiling mount. It
is only for the current floor and does not include tz multipliers.
}
vrfSystemFloors = {
maxCeil(float): The height of the thermal zone served by a VRF system with the highest ceiling in the
building. This is referenced to the global origin for the building. The units are m.
lowCeil(float): The height of the thermal zone served by a VRF system with the lowest ceiling in the
building. This is referenced to the global origin for the building. The units are m.
vrfFloors(array): [
storyName(string): Name of the current floor (story).
buildStoryObj(Obj): The OpenStudio object associated with the current floor (story).
floorAream2: Total floor area (m2) of thermal zones on the current floor served by VRF systems. Does not
include multipliers.
floorCeillingAream2: The Total ceiling area (m2) of thermal zones on the current floor served by VRF
systems. Does not include multipliers.
floorTZs(array): An array containing each tzFloor hash described above for the current floor.
]
}
2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 2194 def compileZonalVRFFloors(vrfSystemFloors:, tzFloor:) # Check for the highest ceiling and lowest ceiling. vrfSystemFloors[:maxCeil] = tzFloor[:tzCentroid][2].to_f if tzFloor[:tzCentroid][2].to_f >= vrfSystemFloors[:maxCeil].to_f vrfSystemFloors[:lowCeil] = tzFloor[:tzCentroid][2].to_f if tzFloor[:tzCentroid][2].to_f <= vrfSystemFloors[:lowCeil].to_f # If this is the first time vrfSystemFloors has been used add a new floor and enter the information for tzFloor in # it. if vrfSystemFloors[:vrfFloors].empty? vrfSystemFloors[:vrfFloors] << { storyName: tzFloor[:tzFloorName], buildStoryObj: tzFloor[:tzSpaces][0].buildingStory.get, floorAream2: tzFloor[:tzFloorArea_m2], floorCeilingAream2: tzFloor[:tzFloorCeilingAream2], floorTZs: [tzFloor] } else # If vrfSystemFloors has been used check if the the floor that tzFloor is on has an entry already. vrfFloor = vrfSystemFloors[:vrfFloors].select{|sysFloor| sysFloor[:storyName].to_s.upcase == tzFloor[:tzFloorName].to_s.upcase} # If no entry has been made for the floor tzFloor is on then add a new floor and include the tzFloor info. if vrfFloor.empty? vrfSystemFloors[:vrfFloors] << { storyName: tzFloor[:tzFloorName], buildStoryObj: tzFloor[:tzSpaces][0].buildingStory.get, floorAream2: tzFloor[:tzFloorArea_m2], floorCeilingAream2: tzFloor[:tzFloorCeilingAream2], floorTZs: [tzFloor] } else # If the floor that tzFloor is on has already been made then adjust the floor information to include tzFloor. vrfFloor[0][:floorAream2] += tzFloor[:tzFloorArea_m2] vrfFloor[0][:floorCeilingAream2] += tzFloor[:tzFloorCeilingAream2] vrfFloor[0][:floorTZs] << tzFloor end end return vrfSystemFloors end |
#coolingtower_costing(model, prototype_creator) ⇒ Object
Cooling tower (i.e., chiller condensor loop cooling) costing
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 706 def coolingtower_costing(model, prototype_creator) totalCost = 0.0 # Get regional cost factors for this province and city materials_hvac = @costing_database["raw"]["materials_hvac"] hvac_material = materials_hvac.select {|data| data['Material'].to_s == "GasBoilers"}.first # Get any row from spreadsheet in case of region error regional_material, regional_installation = get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material) # Get regional electric cost factors for this province and city hvac_material = materials_hvac.select {|data| data['Material'].to_s.upcase == "BOX" && data['Size'].to_i == 1}.first reg_mat_elec, reg_lab_elec = get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material) # Store some geometry data for use below... util_dist, ht_roof, nom_flr_hght, horz_dist, numAGFlrs, mechRmInBsmt = getGeometryData(model, prototype_creator) template_type = prototype_creator.template cltowerCost = 0.0 thisClTowerCost = 0.0 utilCost = 0.0 plant_loop_info = {} plant_loop_info[:coolingtowers] = [] plant_loop_info[:coolingtowerpumps] = [] plant_loop_info[:groundloops] = [] cltowertype = 'cooling_towers' # Iterate through the plant loops to get cooling tower & pump data... model.getPlantLoops.each do |plant_loop| next unless (plant_loop.name.get.to_s =~ /Condenser Water Loop/i) || (plant_loop.name.get.to_s =~ /Condenser PlantLoop GLHX/i) plant_loop.supplyComponents.each do |supply_comp| if supply_comp.to_CoolingTowerSingleSpeed.is_initialized cltower = supply_comp.to_CoolingTowerSingleSpeed.get cltower_info = {} plant_loop_info[:coolingtowers] << cltower_info cltower_info[:name] = cltower.name.get cltower_info[:type] = 'ClgTwr' # Material lookup name cltower_info[:fanPoweratDesignAirFlowRate] = cltower.fanPoweratDesignAirFlowRate.to_f / 1000 # kW cltower_info[:capacity] = model.sqlFile().get().execAndReturnFirstDouble("SELECT Value FROM " + "TabularDataWithStrings WHERE ReportName='EquipmentSummary' AND ReportForString='Entire Facility' AND " + "TableName='Central Plant' AND ColumnName='Nominal Capacity' AND " + "RowName='#{cltower_info[:name].upcase}' ").to_f / 1000 # kW elsif supply_comp.to_PumpConstantSpeed.is_initialized csPump = supply_comp.to_PumpConstantSpeed.get csPump_info = {} plant_loop_info[:coolingtowerpumps] << csPump_info csPump_info[:name] = csPump.name.get if csPump.isRatedPowerConsumptionAutosized.to_bool csPumpSize = csPump.autosizedRatedPowerConsumption.to_f else csPumpSize = csPump.ratedPowerConsumption.to_f end csPump_info[:size] = csPumpSize.to_f # Watts elsif supply_comp.to_PumpVariableSpeed.is_initialized vsPump = supply_comp.to_PumpVariableSpeed.get vsPump_info = {} plant_loop_info[:coolingtowerpumps] << vsPump_info vsPump_info[:name] = vsPump.name.get if vsPump.isRatedPowerConsumptionAutosized.to_bool vsPumpSize = vsPump.autosizedRatedPowerConsumption.to_f else vsPumpSize = vsPump.ratedPowerConsumption.to_f end vsPump_info[:size] = vsPumpSize.to_f # Watts elsif supply_comp.to_DistrictHeating.is_initialized groundLoop = supply_comp.to_DistrictHeating.get groundLoop_info = {} groundLoop_info[:name] = groundLoop.name.to_s if groundLoop.isNominalCapacityAutosized.to_bool groundLoop_info[:nominal_capacity] = groundLoop.autosizedNominalCapacity.to_f/1000.0 else groundLoop_info[:nominal_capacity] = groundLoop.nominalCapacity.to_f/1000.0 end # Get flow rate to ground loop if plant_loop.isMaximumLoopFlowRateAutosized.to_bool groundLoop_info[:plant_loop_flow_rate_m3ps] = plant_loop.autosizedMaximumLoopFlowRate.to_f else groundLoop_info[:plant_loop_flow_rate_m3ps] = plant_loop.maximumLoopFlowRate.to_f end plant_loop_info[:groundloops] << groundLoop_info elsif supply_comp.to_DistrictCooling.is_initialized groundLoop = supply_comp.to_DistrictCooling.get groundLoop_info = {} groundLoop_info[:name] = groundLoop.name.to_s if groundLoop.isNominalCapacityAutosized.to_bool groundLoop_info[:nominal_capacity] = groundLoop.autosizedNominalCapacity.to_f/1000.0 else groundLoop_info[:nominal_capacity] = groundLoop.nominalCapacity.to_f/1000.0 end # Get flow rate to ground loop if plant_loop.isMaximumLoopFlowRateAutosized.to_bool groundLoop_info[:plant_loop_flow_rate_m3ps] = plant_loop.autosizedMaximumLoopFlowRate.to_f else groundLoop_info[:plant_loop_flow_rate_m3ps] = plant_loop.maximumLoopFlowRate.to_f end plant_loop_info[:groundloops] << groundLoop_info end end end # Get costs associated with each cooling tower numTowers = 0 ; multiplier = 1.0 plant_loop_info[:coolingtowers].each do |cltower| # Get cooling tower cost based on capacity numTowers += 1 if numTowers == 1 matCost, labCost = getHVACCost(cltower[:name], cltower[:type], cltower[:capacity], false) thisClTowerCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 else # Multiple cooling towers if cltower[:capacity] <= 0.1 # Cooling tower cost is zero! thisClTowerCost = 0.0 else # A second cooling tower exists so use it for costing matCost, labCost = getHVACCost(cltower[:name], cltower[:type], cltower[:capacity], false) thisClTowerCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 end end cltowerCost += thisClTowerCost # Electric utility costs (i.e., power lines) for cooling tower(s). # elec 600V #14 wire /100 ft (#848) materialHash = get_cost_info(mat: 'Wiring', size: 14) matCost, labCost = getCost('electrical wire - 600V #14', materialHash, multiplier) elecWireCost = matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0 # 1 inch metal conduit (#851) materialHash = get_cost_info(mat: 'Conduit', unit: 'L.F.') matCost, labCost = getCost('1 inch metal conduit', materialHash, multiplier) = matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0 utilCost += * (ht_roof + 20) + elecWireCost * (ht_roof + 20) / 100 end # Cooling Tower (condensor) pump costs pumpCost = 0.0; pipingCost = 0.0; numPumps = 0; pumpName = ''; pumpSize = 0.0 plant_loop_info[:coolingtowerpumps].each do |pump| numPumps += 1 # Cost variable and constant volume pumps the same (VFD controller added if variable) pumpSize = pump[:size]; pumpName = pump[:name] matCost, labCost = getHVACCost(pumpName, 'Pumps', pumpSize, false) pumpCost += matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 if pump[:name] =~ /variable/i # Cost the VFD controller for the variable pump costed above pumpSize = pump[:size]; pumpName = pump[:name] matCost, labCost = getHVACCost(pumpName, 'VFD', pumpSize, false) pumpCost += matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0 end end if numTowers > 1 && numPumps < 2 # Add pump costing for the backup pump. # 2023-04-25: Not including backup tower or pump costs # pumpCost *= 2.0 end # Double the pump costs to accomodate the costing of a backup pump(s)! # 2023-04-25 No longer including backup pumps #pumpCost *= 2.0 #numPumps = 2 # reset the number of pumps for piping costs below # Chiller water piping cost: Add piping elbows, valves and insulation from the chiller(s) # to the pumps(s) assuming a pipe diameter of 1” and a distance of 10 ft per pump if numTowers > 0 # 4 inch Steel pipe (vertical + horizontal) matCost, labCost = getHVACCost('4 inch steel pipe', 'SteelPipe', 4) pipingCost += (ht_roof * 2 + 10 * numPumps) * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 4 inch Steel pipe insulation (vertical + horizontal) matCost, labCost = getHVACCost('1 inch pipe insulation', 'PipeInsulation', 4) pipingCost += (ht_roof * 2 + 10 * numPumps) * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 4 inch Steel pipe elbow matCost, labCost = getHVACCost('4 inch steel pipe tee', 'SteelPipeTee', 4) pipingCost += 1.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 4 inch valves matCost, labCost = getHVACCost('4 inch BFly valves', 'ValvesBFly', 4) pipingCost += 1.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) end # Note: No extra costs for piping for backup condenser pump or multiple cooling towers. # Calculate GSHP ground loop cost and interior piping unless plant_loop_info[:groundloops].empty? # GSHP ground loop cost # Not applying localization because costs are currently national estimates only (2023-06-19) cltowertype = 'ground_loop' largest_loop = plant_loop_info[:groundloops].max_by { |groundloop| groundloop[:nominal_capacity] } nominal_capacity = largest_loop[:nominal_capacity].to_f matCost, labCost = getHVACCost('GSHP ground loop', 'gshp_ground_loop', '') cltowerCost = matCost * nominal_capacity # GSHP piping from building to bore field cost # Not applying localization because costs are currently national estimates only (2023-06-19) gshp_dist = 50 loop_flow = largest_loop[:plant_loop_flow_rate_m3ps] pipe_dia_mm = d = Math.sqrt(1.273*loop_flow/2.0)*1000 matCost, labCost = getHVACCost('GSHP outdoor piping cost', 'gshp_buried_pipe', pipe_dia_mm, false) pipingCost = matCost * gshp_dist # Interior piping cost # Get mechanical room lacotion (assume this is where the GSHP is) mech_room, cond_spaces = prototype_creator.find_mech_room(model) mech_centroid = mech_room["space_centroid"] # Determine the length to the largest exterior wall ground_spaces = [] pipe_dists = [] # Determine the exterior ground walls touching the ground # Get the spaces model.getSpaces.sort.each do |space| ground_surf = false # Get the surfaces for the space and determine if any are contacting the ground. If one is add it to the arroy # of spaces space.surfaces.sort.each do |surface| if surface.isGroundSurface ground_surf = true end end ground_spaces << space if ground_surf == true end # Go through all of the spaces contacting the ground ground_spaces.sort.each do |ground_space| # Go through all of the surfaces for the space and determine which are exterior or foundation walls ext_walls = ground_space.surfaces.select{ |surf| surf.surfaceType == 'Wall' && (surf.outsideBoundaryCondition == 'Outdoors' || surf.outsideBoundaryCondition == 'Foundation')} # Get the largest exterior wall and the distance to its centroid to the mech room centroid unless ext_walls.empty? ext_wall = ext_walls.max_by { |ext_wall| ext_wall.grossArea.to_f } pipe_dists << { wall: ext_wall, pipe_dist: ((ext_wall.centroid.x.to_f + ground_space.xOrigin.to_f - mech_centroid[0].to_f).abs + (ext_wall.centroid.y.to_f + ground_space.yOrigin.to_f - mech_centroid[1].to_f).abs + (ext_wall.centroid.z.to_f + ground_space.zOrigin.to_f - mech_centroid[2].to_f).abs) } end end # Find the shortest distance to the 3 largest walls and pick the shortest one largest_walls = pipe_dists.max_by(3) { |wall| wall[:wall].grossArea.to_f } pipe_dist = largest_walls.min_by { |wall| wall[:pipe_dist].to_f } pipe_dist_ft = (OpenStudio.convert(pipe_dist[:pipe_dist], 'm', 'ft').get) pipe_dia_mm = d = Math.sqrt(1.273*loop_flow/2.0)*1000 pipe_dia_inch = (OpenStudio.convert(pipe_dia_mm/1000, 'm', 'ft').get)*12.0 pipe_dia_inch = 8.0 if pipe_dia_inch >= 8.0 # Include localization foctors in interior piping and fixtures # Cost the interior pipe matCost, labCost = getHVACCost('GSHP indoor piping cost', 'SteelPipe', pipe_dia_inch, false) pipingCost += (matCost*regional_material + labCost*regional_installation)*pipe_dist_ft*2.0/100.0 # Cost the pipe insulation pipe_dia_inch = 4.0 if pipe_dia_inch > 4.0 matCost, labCost = getHVACCost('GSHP indoor pipe insulation', 'PipeInsulation', pipe_dia_inch, false) pipingCost += (matCost*regional_material + labCost*regional_installation)*pipe_dist_ft*2.0/100.0 # Cost 1 valve matCost, labCost = getHVACCost('GSHP indoor pipe valve', 'ValvesBig', 4.0) pipingCost += (matCost*regional_material + labCost*regional_installation)/100.0 # Cost 2 pipe tees matCost, labCost = getHVACCost('GSHP indoor pipe tees', 'SteelPipeTee', 4.0) pipingCost += (matCost*regional_material + labCost*regional_installation)*2.0/100.0 # Cost 8 pipe tees matCost, labCost = getHVACCost('GSHP indoor pipe elbows', 'SteelPipeElbow', 4.0) pipingCost += (matCost*regional_material + labCost*regional_installation)*8.0/100.0 end totalCost = cltowerCost + utilCost + pumpCost + pipingCost @costing_report['heating_and_cooling']['plant_equipment'] << { 'type' => cltowertype, 'nom_flr2flr_hght_ft' => nom_flr_hght.round(1), 'ht_roof_ft' => ht_roof.round(1), 'longest_distance_to_ext_ft' => horz_dist.round(1), 'wiring_and_gas_connections_distance_ft' => util_dist.round(1), 'equipment_cost' => cltowerCost.round(0), 'wiring_and_gas_connections_cost' => utilCost.round(0), 'pump_cost' => pumpCost.round(0), 'piping_cost' => pipingCost.round(0), 'total_cost' => totalCost.round(0) } puts "\nHVAC Cooling Tower costing data successfully generated. Total cooling tower costs: $#{totalCost.round(0)}" return totalCost end |
#cost_ahu(sys_type:, airloop_flow_lps:, airloop_flow_cfm:, mech_sizing_info:, heating_fuel:, cooling_type:, airloop_name:, vent_tags: []) ⇒ Object
This method looks for an air handler in the ‘hvac_vent_ahu’ sheet of the costing spreadsheet. The inputs it uses to find the air handler are: sys_type: HVAC system type (can handle NECB systems 1, 3, 4 or 6) airloop_flow_lps: Air loop design air flow rate (L/s) heating_fuel: The predominant heating fuel used by the air loop (HP, CCASHP, HW, Gas, Propane, Oil) cooling_type: The predominant cooling type used by the air loop (DX, HP, CCASHP, CHW) airloop_name: The name of the air loop (only used for error messages)
If no air handler with matching characteristics are found it assumes that all of the ones in the ‘hvac_vent_ahu’ ore too small. I then calls get_ahu_mult to find the largest air handler with the appropriate characteristics and finds how many of those are required to meet the load (see get_ahu_mult for more information). Once the appropriate air handler is selected from the ‘hvac_vent_ahu’ the method then reads the numbers in column K (id_layers) and column N (id_layers_quantity_multipliers). The numbers in ‘id_layers’ are indexes that match column A (material_id) in the ‘material_hvac’ costing spreadsheet sheet. The numbers in ‘id_layers_quantity_multipliers’ define how many pieces of equipment defined in the id_layer. The method then calls the ‘vent_assembly_cost’ method which takes the set of id_layers, the ‘id_layers_quantity_multipliers’ and the overall_mult. This costs each item in ‘id_layers’, multiplies the cost by the number in ‘id_layers_quantity_multipliers’ and multiplies everything by ‘overall_mult’. The returned cast is then multiplied by the number of air handlers present (mult) and returns the cost.
The method now also also includes the call to the ‘gas_burner_cost’ method to adjust for burner costs. It also includes the ahu size adjustement previously done in the main ‘ahu_costing’ method.
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 848 def cost_ahu(sys_type:, airloop_flow_lps:, airloop_flow_cfm:, mech_sizing_info:, heating_fuel:, cooling_type:, airloop_name:, vent_tags: []) # Assmue one air handler to start mult = 1.0 # Find an air handler in the 'hvac_vent_ahu' sheet that matches the system_type, air flow rate, heating type and # cooling type. ahu = @costing_database['raw']['hvac_vent_ahu'].select {|data| data['Sys_type'].to_f.round(0) == sys_type.to_f.round(0) and data['Supply_air'].to_f >= airloop_flow_lps and data['Htg'].to_s == heating_fuel and data['Clg'].to_s == cooling_type }.min_by{|info| info['Supply_air'].to_f} # If none are there assume that none had a big enough air flow rate. Create a data structure with the pertinent # air handler information. if ahu.nil? || ahu.empty? loop_equip = { sys_type: sys_type, heating_fuel: heating_fuel, cooling_type: cooling_type, airloop_flow_lps: airloop_flow_lps, airloop_name: airloop_name } # Find send the air handler information to the 'get_ahu_mult' method which returns the air handler information and # the number which will meet the supply air rate. ahu, mult, rev_airloop_flow_lps = get_ahu_mult(loop_equip: loop_equip) # If one air handler which meets the requirements is found then use that one. else rev_airloop_flow_lps = airloop_flow_lps end # set the number of air hondlers in @airloop_info which is included in the ventilation costing report. @airloop_info[:num_rooftop_units] = mult.to_i # Calculate the ahu cost modifier for systems other than the largest (recreation of modifier originally applied in # the 'ahu_costing' method). ahu['Supply_air'].to_f.round(0) == 15000 ? ahu_cost_mod = 1.0 : ahu_cost_mod = (rev_airloop_flow_lps/(ahu['Supply_air'].to_f)) # Get the 'id_layers' from the 'hvac_vent_ahu' sheet and put them into an array ids = ahu['id_layers'].to_s.split(',') # Get the quantity of each of the preceding 'id_layers'. To do this, get the 'id_layers_quantity_multipliers' # numbers from the 'hvac_vent_ahu' and convert them into an array id_quants = ahu['Id_layers_quantity_multipliers'].to_s.split(',') # Check that the number of ids is the same as the number of id_quants. If it isn't something is wrong and raise an # error. raise "The number of id_layers does not match the number of id_layer_quantity_multipliers in the hvac_vent_auh sheet of the costing spreadsheet. Please look for the air handler in the costing spreadsheet and check the appropriate columns. The air handler characteristics are: #{ahu}" if ids.size != id_quants.size # Get the overall_mult. This used to be used but does not seem to be used anymore. I left it in just in case # (probably a bad idea). overall_mult = ahu['material_mult'].to_f overall_mult = 1.0 if overall_mult == 0 # Create tags that will be added to the cost list output = .clone << heating_fuel << cooling_type << "Required Air Flow (L/s): #{airloop_flow_lps.to_f.round(2)}" << "Total AHU Air Flow with Multipliers(L/s): #{(ahu['Supply_air'].to_f*mult).to_f.round(2)}" << "AHU Equipment" # Cost the ids (multiplied by the number associated id_quants) and maltiply everything by the number of air handlers # (if one was too small). ind_ahu_cost = vent_assembly_cost(ids: ids, id_quants: id_quants, overall_mult: overall_mult, vent_tags: , report_mult: (overall_mult*ahu_cost_mod*mult)) # This is the total ahu cost without adjusting cost with airflow calc_ahu_cost = ind_ahu_cost*mult # Create the start of the return hash (done here because it is used in the 'gas_burner_cost' method) costed_ahu_info = { ahu: ahu, mult: mult, air_loop_flow_lps: airloop_flow_lps, ind_ahu_cost: ind_ahu_cost } .pop # Remove gas burner cost from ahu cost because it is accounted for in the heating and cooling equipment calculated later. << "AHU Cost Adjustment" ahu_mech_adj = gas_burner_cost(heating_fuel: heating_fuel, sys_type: sys_type, airloop_flow_cfm: airloop_flow_cfm, mech_sizing_info: mech_sizing_info, costed_ahu_info: costed_ahu_info, vent_tags: , report_mult: ahu_cost_mod) base_ahu_cost = calc_ahu_cost - ahu_mech_adj # Caclculate the adjusted ahu cost adj_ahu_cost = (ind_ahu_cost*mult- ahu_mech_adj)*ahu_cost_mod # Add costs to costing output @airloop_info[:ind_ahu_max_airflow_l_per_s] = ahu['Supply_air'].to_f.round(0) @airloop_info[:base_ahu_cost] = base_ahu_cost.round(2) @airloop_info[:revised_base_ahu_cost] = adj_ahu_cost.round(2) # Add ahu costs to return hash costed_ahu_info[:base_ahu_cost] = base_ahu_cost costed_ahu_info[:adjusted_base_ahu_cost] = adj_ahu_cost return costed_ahu_info end |
#cost_audit_all(model:, prototype_creator:, envelope_costing: true, lighting_costing: true, boilers_costing: true, chillers_costing: true, cooling_towers_costing: true, shw_costing: true, ventilation_costing: true, zone_system_costing: true, renewables_costing: true, template_type: nil) ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 91 def cost_audit_all(model:, prototype_creator:, envelope_costing: true, lighting_costing: true, boilers_costing: true, chillers_costing: true, cooling_towers_costing: true, shw_costing: true, ventilation_costing: true, zone_system_costing: true, renewables_costing: true, template_type: nil ) # Create a Hash to collect costing data. @costing_report = {} #Use closest city. closest_loc = get_closest_cost_location(model.getWeatherFile.latitude, model.getWeatherFile.longitude) @costing_report['city'] = closest_loc['city'] @costing_report['province_state'] = closest_loc['province_state'] # Create array to collect costed item information. First element is the costing location. @cost_items = { 'City' => closest_loc['city'], 'Province' => closest_loc['province_state'], 'Items' => [] } # Create a Hash in the hash for categories of costing. @costing_report['envelope'] = {} @costing_report['lighting'] = {} @costing_report['lighting']['daylighting_sensor_control'] = [] @costing_report['lighting']['led_lighting'] = [] @costing_report['heating_and_cooling'] = {} @costing_report['heating_and_cooling']['plant_equipment'] = [] @costing_report['heating_and_cooling']['zonal_systems'] = [] @costing_report['shw'] = {} @costing_report['ventilation'] = {} @costing_report['renewables'] = {} @costing_report['renewables']['pv'] = [] @costing_report['totals'] = {} # Check to see if standards building type and the number of stories has been defined. The former may be omitted in the future. if model.getBuilding.standardsBuildingType.empty? or model.getBuilding.standardsNumberOfAboveGroundStories.empty? raise("Building information is not complete, please ensure that the standardsBuildingType and standardsNumberOfAboveGroundStories are entered in the model. ") end # Find the mechanical room mech_room, cond_spaces = prototype_creator.find_mech_room(model) envCost = envelope_costing ? self.cost_audit_envelope(model, prototype_creator) : 0.0 lgtCost = lighting_costing ? self.cost_audit_lighting(model, prototype_creator) : 0.0 boilerCost = boilers_costing ? self.boiler_costing(model, prototype_creator) : 0.0 chillerCost = chillers_costing ? self.chiller_costing(model, prototype_creator) : 0.0 coolingTowerCost = cooling_towers_costing ? self.coolingtower_costing(model, prototype_creator) : 0.0 shwCost = shw_costing ? self.shw_costing(model, prototype_creator) : 0.0 ventCost = ventilation_costing ? self.ventilation_costing(model, prototype_creator,template_type, mech_room, cond_spaces) : 0.0 zonalSystemCost = zone_system_costing ? self.zonalsys_costing(model, prototype_creator, mech_room, cond_spaces) : 0.0 pvGroundCost = renewables_costing ? self.cost_audit_pv_ground(model, prototype_creator) : 0.0 thermalBridgingCost = 0.0 @costing_report["totals"] = { 'envelope' => envCost.round(0), 'thermal_bridging' => thermalBridgingCost.round(0), 'lighting' => lgtCost.round(0), 'heating_and_cooling' => (boilerCost + chillerCost + coolingTowerCost + zonalSystemCost).round(0), 'shw' => shwCost.round(0), 'ventilation' => ventCost.round(0), 'renewables' => pvGroundCost.round(0), 'grand_total' => (envCost + thermalBridgingCost + lgtCost + boilerCost + chillerCost + coolingTowerCost + shwCost + ventCost + zonalSystemCost + pvGroundCost).round(0) } return @costing_report, @cost_items end |
#cost_audit_daylighting_sensor_control(model:, prototype_creator:) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/openstudio-standards/btap/costing/daylighting_sensor_control_costing.rb', line 3 def cost_audit_daylighting_sensor_control(model:, prototype_creator:) @costing_report["lighting"]["daylighting_sensor_control"] = [] # NOTE: Number of daylighting sensors is based on how many a daylighted space needs sensors as per Mike Lubun's costing spec, rather than daylighting sensor control measure. standards_template = model.building.get.standardsTemplate.to_s if standards_template.include?('NECB') standards_template = standards_template.gsub(/(?<=\p{L})(?=\d)/, ' ') #insert a space between NECB and 2011/2015/2017 end #------------------------------------------------------------------------------------------------------------------- dsc_cost_total = 0.0 all_tz_primary_sidelighted_quatity = 0.0 all_tz_skylight_quatity = 0.0 #------------------------------------------------------------------------------------------------------------------- model.getThermalZones.sort.each do |tz| if tz.primaryDaylightingControl.is_initialized tz_cost_primary_sidelighted = 0.0 tz_cost_skylight = 0.0 tz_multiplier = tz.multiplier() daylight_spaces = [] primary_sidelighted_area_hash = {} daylighted_area_under_skylights_hash = {} primary_sidelighted_area = 0.0 daylighted_under_skylight_area = 0.0 tz_area = 0.0 tz_number_fixtures = 0.0 tz_primary_sidelighted_ratio_daylight_area = 0.0 tz_primary_sidelighted_number_fixtures = 0.0 tz_primary_sidelighted_number_sensors = 0.0 tz_skylights_ratio_daylight_area = 0.0 tz_skylights_number_fixtures = 0.0 tz_skylights_number_sensors = 0.0 if !tz.primaryDaylightingControl.get.name().empty? && tz.fractionofZoneControlledbyPrimaryDaylightingControl() > 0.00 tz.spaces().sort.each do |space| daylight_spaces << space end end #------------------------------------------------------------------------------------------------------------------- ##### Calculate tz_primary_sidelighted_area AND tz_daylighted_area_under_skylights. ##### The above two area values are required for the calculation of tz_primary_sidelighted_number_fixtures AND tz_skylights_number_fixtures daylight_spaces.sort.each do |daylight_space| # Go to the next space if the current space's space type is undefined. next if daylight_space.spaceType.get.name.to_s.downcase.include? "undefined" area_weighted_vt_handle = 0.0 window_area_sum = 0.0 skylight_area_weighted_vt_handle = 0.0 skylight_area_sum = 0.0 ##### Find lights_type in each daylight_space led_lights = 0 daylight_space_type = daylight_space.spaceType() daylight_space_type.get.lights.sort.each do |inst| daylight_space_lights_definition = inst.lightsDefinition daylight_space_lights_definition_name = daylight_space_lights_definition.name if daylight_space_lights_definition_name.to_s.include?('LED lighting') led_lights += 1 end end if (led_lights > 0) or (standards_template == 'NECB 2020') lights_type = 'LED' else lights_type = 'CFL' end ##### Find height of daylight_space max_space_height_m = 0.0 daylight_space.surfaces.sort.select { |surface| surface.surfaceType == 'Wall' }.each do |wall_surface| # Find the vertex with the max z value. vertex_with_max_height = wall_surface.vertices.max_by(&:z) # Replace max if this surface has something bigger. max_space_height_m = vertex_with_max_height.z if vertex_with_max_height.z > max_space_height_m end max_space_height_ft = (OpenStudio.convert(max_space_height_m, 'm', 'ft').get) #Convert height to ft ##### Find area, floor_surface, and floor_vertices of daylight_space floor_surface = nil floor_area = 0.0 floor_vertices = [] daylight_space.surfaces.sort.each do |surface| if surface.surfaceType == 'Floor' floor_surface = surface floor_area += surface.netArea floor_vertices << surface.vertices end end ##### COSTING-related step: Find fixture type that should be used in the daylight_space based on space_type, template, and lights_type search_fixture_type = { row_id_1: daylight_space.spaceType.get.standardsSpaceType.to_s, #space_type row_id_2: standards_template, row_id_3: lights_type } sheet_name = 'lighting_sets' if max_space_height_ft < 7.88 column_search = 'Fixture_type_less_than_7.88ft_ht' elsif max_space_height_ft >= 7.88 && max_space_height_ft < 15.75 column_search = 'Fixture_type_7.88_to_15.75ft_ht' else #i.e. max_space_height_ft >= 15.75ft_ht column_search = 'Fixture_type_greater_than_>15.75ft_ht' end row_search_1 = 'space_type' row_search_2 = 'template' row_search_3 = 'Type' fixture_type = get_fixture_type_id(fixture_info: search_fixture_type, sheet_name: sheet_name, row_name_1: row_search_1, row_name_2: row_search_2, row_name_3: row_search_3, column_search: column_search) ##### COSTING-related step: Find number_fixtures_per_1000_ft2 that should be considered in the daylight_space based on fixture_type search_fixtures_per_1000_ft2 = @costing_database['raw']['lighting'].select { |data| data['lighting_type_id'].to_f.round(1) == fixture_type.to_f.round(1) }.first if search_fixtures_per_1000_ft2.nil? puts("No data found for #{search_fixtures_per_1000_ft2}!") raise end number_fixtures_per_1000_ft2 = search_fixtures_per_1000_ft2['Fix_1000ft'].to_i ##### COSTING-related step: Calculate number_fixtures_space that should be considered in the daylight_space based on number_fixtures_per_1000_ft2 and area of daylight_space floor_area_ft2 = (OpenStudio.convert(floor_area, 'm^2', 'ft^2').get) #convert floor_area to ft2 number_fixtures_space = (floor_area_ft2 / 1000) * number_fixtures_per_1000_ft2 number_fixtures_space = number_fixtures_space.ceil tz_number_fixtures += number_fixtures_space #----------------------------------------------------------------------------------------------------------------- ############################## Calculate 'primary_sidelighted_area' of the thermal zone ########################## primary_sidelighted_area, area_weighted_vt_handle, window_area_sum = prototype_creator.get_parameters_sidelighting(daylight_space: daylight_space, floor_surface: floor_surface, floor_vertices: floor_vertices, floor_area: floor_area, primary_sidelighted_area: primary_sidelighted_area, area_weighted_vt_handle: area_weighted_vt_handle, window_area_sum: window_area_sum) primary_sidelighted_area_hash[daylight_space.name.to_s] = primary_sidelighted_area #----------------------------------------------------------------------------------------------------------------- ########################### Calculate 'daylighted_under_skylight_area' of the thermal zone ######################### ##### Loop through the surfaces of each daylight_space to calculate daylighted_area_under_skylights and skylight_effective_aperture for each daylight_space daylighted_under_skylight_area, skylight_area_weighted_vt_handle, skylight_area_sum = prototype_creator.get_parameters_skylight(daylight_space: daylight_space, skylight_area_weighted_vt_handle: skylight_area_weighted_vt_handle, skylight_area_sum: skylight_area_sum, daylighted_under_skylight_area: daylighted_under_skylight_area) daylighted_area_under_skylights_hash[daylight_space.name.to_s] = daylighted_under_skylight_area #----------------------------------------------------------------------------------------------------------------- tz_area += floor_area end #daylight_spaces.sort.each do |daylight_space| #------------------------------------------------------------------------------------------------------------------- # If no fixtures or daylighting is defined then go to the next thermal zone next if tz_number_fixtures.to_f == 0.0 || tz_primary_sidelighted_ratio_daylight_area.to_f.nan? ##### COSTING-related step: Calculate number of fixtures in thermal zones with window(s)------------------------------------------------- tz_primary_sidelighted_ratio_daylight_area = primary_sidelighted_area / tz_area tz_primary_sidelighted_number_fixtures = (tz_number_fixtures * tz_primary_sidelighted_ratio_daylight_area).ceil tz_primary_sidelighted_number_sensors = (tz_primary_sidelighted_number_fixtures / 4.0).ceil all_tz_primary_sidelighted_quatity += tz_primary_sidelighted_number_sensors * tz_multiplier if tz_primary_sidelighted_number_sensors > 0.0 = ['lighting', 'daylighting_sensor_control'] # cost of daylighting sensor quantity_tz_primary_sidelighted_daylighting_sensor = 1.0 * tz_primary_sidelighted_number_sensors * tz_multiplier search_tz_primary_sidelighted_daylighting_sensor = { row_id_1: 'Ea', row_id_2: 407 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_tz_primary_sidelighted_daylighting_sensor = assembly_cost(cost_info:search_tz_primary_sidelighted_daylighting_sensor, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_primary_sidelighted_daylighting_sensor, tags: ) # cost of wiring quantity_tz_primary_sidelighted_wiring = (30.0 / 100.0) * tz_primary_sidelighted_number_sensors * tz_multiplier search_tz_primary_sidelighted_wiring = { row_id_1: 'CLF', row_id_2: 10 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_tz_primary_sidelighted_wiring = assembly_cost(cost_info:search_tz_primary_sidelighted_wiring, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_primary_sidelighted_wiring, tags: ) # cost of pvc conduit quantity_tz_primary_sidelighted_pvc_conduit = 30.0 * tz_primary_sidelighted_number_sensors * tz_multiplier search_tz_primary_sidelighted_pvc_conduit = { row_id_1: 'LF', row_id_2: 17 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_tz_primary_sidelighted_pvc_conduit = assembly_cost(cost_info:search_tz_primary_sidelighted_pvc_conduit, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_primary_sidelighted_pvc_conduit, tags: ) # cost of box quantity_tz_primary_sidelighted_box = 1.0 * tz_primary_sidelighted_number_sensors * tz_multiplier search_tz_primary_sidelighted_box = { row_id_1: 'Ea', row_id_2: 14 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_tz_primary_sidelighted_box = assembly_cost(cost_info:search_tz_primary_sidelighted_box, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_primary_sidelighted_box, tags: ) # total cost for this zone tz_cost_primary_sidelighted = cost_tz_primary_sidelighted_daylighting_sensor + cost_tz_primary_sidelighted_wiring + cost_tz_primary_sidelighted_pvc_conduit + cost_tz_primary_sidelighted_box dsc_cost_total += tz_cost_primary_sidelighted end ##### COSTING-related step: Calculate number of fixtures in thermal zones with skylight(s)------------------------------------------------- tz_skylights_ratio_daylight_area = daylighted_under_skylight_area / tz_area tz_skylights_number_fixtures = (tz_number_fixtures * tz_skylights_ratio_daylight_area).ceil tz_skylights_number_sensors = (tz_skylights_number_fixtures / 4.0).ceil all_tz_skylight_quatity += tz_skylights_number_sensors * tz_multiplier if tz_skylights_number_sensors > 0.0 = ['lighting', 'daylighting_sensor_control'] # cost of daylighting sensor quantity_tz_skylights_daylighting_sensor = 1.0 * tz_skylights_number_sensors * tz_multiplier search_tz_skylights_daylighting_sensor = { row_id_1: 'Ea', row_id_2: 407 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_tz_skylights_daylighting_sensor = assembly_cost(cost_info:search_tz_skylights_daylighting_sensor, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_skylights_daylighting_sensor, tags: ) # cost of wiring quantity_tz_skylights_wiring = (30.0 / 100.0) * tz_skylights_number_sensors * tz_multiplier search_tz_skylights_wiring = { row_id_1: 'CLF', row_id_2: 10 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_tz_skylights_wiring = assembly_cost(cost_info:search_tz_skylights_wiring, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_skylights_wiring, tags: ) # cost of pvc conduit quantity_tz_skylights_pvc_conduit = 30.0 * tz_skylights_number_sensors * tz_multiplier search_tz_skylights_pvc_conduit = { row_id_1: 'LF', row_id_2: 17 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_tz_skylights_pvc_conduit = assembly_cost(cost_info:search_tz_skylights_pvc_conduit, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_skylights_pvc_conduit, tags: ) # cost of box quantity_tz_skylights_box = 1.0 * tz_skylights_number_sensors * tz_multiplier search_tz_skylights_box = { row_id_1: 'Ea', row_id_2: 14 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_tz_skylights_box = assembly_cost(cost_info:search_tz_skylights_box, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_skylights_box, tags: ) # total cost for this zone tz_cost_skylight = cost_tz_skylights_daylighting_sensor + cost_tz_skylights_wiring + cost_tz_skylights_pvc_conduit + cost_tz_skylights_box dsc_cost_total += tz_cost_skylight end ##### Gather information for reporting @costing_report["lighting"]["daylighting_sensor_control"] << { 'zone' => tz.name.to_s, 'zone_area' => tz_area, 'zone_multiplier' => tz_multiplier, 'number_of_fixtures_required_without_considering_daylighted_area_under_sidelighting_and_skylights' => tz_number_fixtures, 'primary_sidelighted_area' => primary_sidelighted_area, 'primary_sidelighted_number_fixtures' => tz_primary_sidelighted_number_fixtures, 'primary_sidelighted_number_sensors' => tz_primary_sidelighted_number_sensors, 'skylights_daylighted_area' => daylighted_under_skylight_area, 'skylights_number_fixtures' => tz_skylights_number_fixtures, 'skylights_number_sensors' => tz_skylights_number_sensors, 'daylighting_sensor_control_cost_for_this_zone' => tz_cost_primary_sidelighted + tz_cost_skylight } end #tz.primaryDaylightingControl.is_initialized end #model.getThermalZones.sort.each do |tz| #------------------------------------------------------------------------------------------------------------------- puts "\nDaylighting sensor controls costing data successfully generated. Total DSC costs: $#{dsc_cost_total.round(2)}" return dsc_cost_total end |
#cost_audit_dcv(model:, prototype_creator:) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/openstudio-standards/btap/costing/dcv_costing.rb', line 3 def cost_audit_dcv(model:, prototype_creator:) @costing_report['ventilation'][:demand_controlled_ventilation] = [] a = 0.0 # This is for reporting purposes. ##### Initialize cost of various parts of DCV dcv_cost_zone_occupancy = 0.0 dcv_cost_zone_co2 = 0.0 dcv_cost_box = 0.0 dcv_cost_vertical_conduit = 0.0 dcv_cost_roof = 0.0 dcv_cost_control = 0.0 dcv_cost_total = 0.0 ##### Get number of stories and nominal floor to floor height. ##### These inputs are required for the calculation of the length of conduit for each AirLoopHVAC. util_dist, ht_roof, nominal_flr2flr_height_ft, horizontal_dist, standards_number_of_stories, mechRmInBsmt = getGeometryData(model, prototype_creator) nominal_flr2flr_height_m = (OpenStudio.convert(nominal_flr2flr_height_ft, 'ft', 'm').get) number_of_dcv_controller_for_all_air_loops = 0 model.getAirLoopHVACs.sort.each do |air_loop| number_of_thermal_zones_served_by_air_loop = 0 number_floors_served_by_air_loop = 0 number_of_junction_boxes_for_air_loop = 0 ##### Step A: Calculate number of thermal zones and floors served by each AirLoopHVAC (air_loop) building_story_list = [] air_loop.thermalZones.sort.each do |thermal_zone| thermal_zone.spaces().sort.each do |space| building_story_list << space.buildingStory.get.name() end number_of_thermal_zones_served_by_air_loop += thermal_zone.multiplier() end building_story_list = building_story_list.uniq() number_floors_served_by_air_loop = building_story_list.length ##### Loop through AirLoopHVAC's supply nodes to: ##### (1) Find its AirLoopHVAC:OutdoorAirSystem using the supply node; ##### (2) Find Controller:OutdoorAir using AirLoopHVAC:OutdoorAirSystem; ##### (3) Get "Controller Mechanical Ventilation" from Controller:OutdoorAir. air_loop.supplyComponents.sort.each do |supply_component| ##### Find AirLoopHVAC:OutdoorAirSystem of AirLoopHVAC using the supply node. hvac_component = supply_component.to_AirLoopHVACOutdoorAirSystem if !hvac_component.empty? = ['ventilation', 'demand_controlled_ventilation'] ##### Find Controller:OutdoorAir using AirLoopHVAC:OutdoorAirSystem. hvac_component = hvac_component.get hvac_component_name = hvac_component.name() controller_outdoorair = hvac_component.getControllerOutdoorAir controller_outdoorair_name = controller_outdoorair.name() ##### Get "Controller Mechanical Ventilation" from Controller:OutdoorAir. controller_mechanical_ventilation = controller_outdoorair.controllerMechanicalVentilation controller_mechanical_ventilation_name = controller_mechanical_ventilation.name() ##### Check if "Demand Controlled Ventilation" is "Yes" in Controller:MechanicalVentilation depending on dcv_type. controller_mechanical_ventilation_demand_controlled_ventilation_status = controller_mechanical_ventilation.demandControlledVentilation controller_mechanical_ventilation_system_outdoor_air_method = controller_mechanical_ventilation.systemOutdoorAirMethod() if controller_mechanical_ventilation_demand_controlled_ventilation_status == true && (controller_mechanical_ventilation_system_outdoor_air_method == 'ZoneSum' || controller_mechanical_ventilation_system_outdoor_air_method == 'IndoorAirQualityProcedure') ##### Step B: Calculate costs of the installation of a single junction box for each floor within that AirLoopHVAC (air_loop) to accumulate the wiring quantity_ahu_floors_junction_box = 1.0 * number_floors_served_by_air_loop search_ahu_floors_junction_box = { row_id_1: 'Ea', row_id_2: 14 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' dcv_cost_box = assembly_cost(cost_info:search_ahu_floors_junction_box, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_ahu_floors_junction_box, tags: ) ##### Step C: Calculate costs of the installation of a single conduit that runs the entire height of the building for each AirLoopHVAC to accumulate the wiring quantity_ahu_vertical_wiring = 1.0/100.0 * standards_number_of_stories * nominal_flr2flr_height_ft search_ahu_vertical_wiring = { row_id_1: 'CLF', row_id_2: 10 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_ahu_vertical_wiring = assembly_cost(cost_info:search_ahu_vertical_wiring, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_ahu_vertical_wiring, tags: ) quantity_ahu_vertical_conduit = 1.0 * standards_number_of_stories * nominal_flr2flr_height_ft search_ahu_vertical_conduit = { row_id_1: 'LF', row_id_2: 13 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_ahu_vertical_conduit = assembly_cost(cost_info:search_ahu_vertical_conduit, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_ahu_vertical_conduit, tags: ) dcv_cost_vertical_conduit = cost_ahu_vertical_wiring + cost_ahu_vertical_conduit ##### Step D: Calculate the roof conduit and wiring for each AirLoopHVAC. quantity_ahu_roof_wiring = 20.0/100.0 search_ahu_roof_wiring = { row_id_1: 'CLF', row_id_2: 10 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_ahu_roof_wiring = assembly_cost(cost_info:search_ahu_roof_wiring, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_ahu_roof_wiring, tags: ) quantity_ahu_roof_conduit = 20.0 search_ahu_roof_conduit = { row_id_1: 'LF', row_id_2: 13 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_ahu_roof_conduit = assembly_cost(cost_info:search_ahu_roof_conduit, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_ahu_roof_conduit, tags: ) quantity_ahu_roof_junction_box = 1.0 search_ahu_roof_junction_box = { row_id_1: 'Ea', row_id_2: 14 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_ahu_roof_junction_box = assembly_cost(cost_info:search_ahu_roof_junction_box, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_ahu_roof_junction_box, tags: ) dcv_cost_roof = cost_ahu_roof_wiring + cost_ahu_roof_conduit + cost_ahu_roof_junction_box ##### Step E: Calculate DCV controller for each AirLoopHVAC. number_of_dcv_controller_for_all_air_loops += 1 quantity_ahu_contorller = 1.0 search_ahu_contorller = { row_id_1: 'Ea', row_id_2: 400 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' dcv_cost_control = assembly_cost(cost_info:search_ahu_contorller, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_ahu_contorller, tags: ) if controller_mechanical_ventilation_system_outdoor_air_method == 'ZoneSum' ##### Step F: Calculate total Cost for each AirLoopHVAC # Calculate occupancy sensor-related costs of each thermal zone served by each AirLoopHVAC (air_loop) quantity_tz_occupancy_sensor = 1.0 * number_of_thermal_zones_served_by_air_loop.to_f search_tz_occupancy_sensor = { row_id_1: 'Ea', row_id_2: 404 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_tz_occupancy_sensor = assembly_cost(cost_info:search_tz_occupancy_sensor, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_occupancy_sensor, tags: ) quantity_tz_occupancy_sensor_wiring = 30.0/100.0 * number_of_thermal_zones_served_by_air_loop.to_f search_tz_occupancy_sensor_wiring = { row_id_1: 'CLF', row_id_2: 10 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_tz_occupancy_sensor_wiring = assembly_cost(cost_info:search_tz_occupancy_sensor_wiring, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_occupancy_sensor_wiring, tags: ) quantity_tz_occupancy_sensor_pvc_conduit = 30.0 * number_of_thermal_zones_served_by_air_loop.to_f search_tz_occupancy_sensor_pvc_conduit = { row_id_1: 'LF', row_id_2: 17 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_tz_occupancy_sensor_pvc_conduit = assembly_cost(cost_info:search_tz_occupancy_sensor_pvc_conduit, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_occupancy_sensor_pvc_conduit, tags: ) dcv_cost_zone_occupancy = cost_tz_occupancy_sensor + cost_tz_occupancy_sensor_wiring + cost_tz_occupancy_sensor_pvc_conduit dcv_cost_total += dcv_cost_zone_occupancy + dcv_cost_box + dcv_cost_vertical_conduit + dcv_cost_roof + dcv_cost_control total_cost_for_air_loop = dcv_cost_zone_occupancy + dcv_cost_box + dcv_cost_vertical_conduit + dcv_cost_roof + dcv_cost_control elsif controller_mechanical_ventilation_system_outdoor_air_method == 'IndoorAirQualityProcedure' ##### Step F: Calculate total Cost for each AirLoopHVAC # Calculate CO2 sensor-related costs of each thermal zone served by each AirLoopHVAC (air_loop) quantity_tz_co2_sensor = 1.0 * number_of_thermal_zones_served_by_air_loop.to_f search_tz_co2_sensor = { row_id_1: nil, row_id_2: 1316 } sheet_name = 'materials_hvac' column_1 = nil column_2 = 'material_id' cost_tz_co2_sensor = assembly_cost(cost_info:search_tz_co2_sensor, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_co2_sensor, tags: ) quantity_tz_co2_sensor_wiring = 30.0/100.0 * number_of_thermal_zones_served_by_air_loop.to_f search_tz_co2_sensor_wiring = { row_id_1: 'CLF', row_id_2: 10 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_tz_co2_sensor_wiring = assembly_cost(cost_info:search_tz_co2_sensor_wiring, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_co2_sensor_wiring, tags: ) quantity_tz_co2_sensor_pvc_conduit = 30.0 * number_of_thermal_zones_served_by_air_loop.to_f search_tz_co2_sensor_pvc_conduit = { row_id_1: 'LF', row_id_2: 17 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' cost_tz_co2_sensor_pvc_conduit = assembly_cost(cost_info:search_tz_co2_sensor_pvc_conduit, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_tz_co2_sensor_pvc_conduit, tags: ) dcv_cost_zone_co2 = cost_tz_co2_sensor + cost_tz_co2_sensor_wiring + cost_tz_co2_sensor_pvc_conduit dcv_cost_total += dcv_cost_zone_co2 + dcv_cost_box + dcv_cost_vertical_conduit + dcv_cost_roof + dcv_cost_control total_cost_for_air_loop = dcv_cost_zone_co2 + dcv_cost_box + dcv_cost_vertical_conduit + dcv_cost_roof + dcv_cost_control end ##### Gather information for reporting @costing_report['ventilation'][:demand_controlled_ventilation] << { air_loop_name: air_loop.name().to_s, controller_Outdoor_air: controller_outdoorair_name.to_s, controller_mechanical_ventilation_name: controller_mechanical_ventilation_name.to_s, controller_mechanical_ventilation_demand_controlled_ventilation_status: controller_mechanical_ventilation_demand_controlled_ventilation_status.to_s, controller_mechanical_ventilation_system_outdoor_air_method: controller_mechanical_ventilation_system_outdoor_air_method.to_s, number_of_floors_served_by_air_loop: number_floors_served_by_air_loop.to_f, number_of_thermal_zones_served_by_air_loop: number_of_thermal_zones_served_by_air_loop.to_f, number_of_junction_boxes_for_air_loop: number_floors_served_by_air_loop.to_f, total_cost_for_air_loop: total_cost_for_air_loop.to_f.round(2) } a += 1.0 end # puts dcv_cost_total end #if !hvac_component.empty? end #air_loop.supplyComponents.each do |supply_component| end #model.getAirLoopHVACs.each do |air_loop| if a > 0.0 ###### Gather information for reporting @costing_report['ventilation'][:demand_controlled_ventilation] << { standards_number_of_building_stories: standards_number_of_stories.to_f, nominal_floor_to_floor_height: nominal_flr2flr_height_m.to_f.round(2), total_cost_for_all_dcvs: dcv_cost_total.to_f.round(2) } end puts "\nDemand-controlled ventilation costing data successfully generated. Total DCV costs: $#{dcv_cost_total.round(2)}" return dcv_cost_total end |
#cost_audit_envelope(model, prototype_creator) ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/openstudio-standards/btap/costing/envelope_costing.rb', line 12 def cost_audit_envelope(model, prototype_creator) # These are the only envelope costing items we are considering for envelopes.. costed_surfaces = [ "ExteriorWall", "ExteriorRoof", "ExteriorFloor", "ExteriorFixedWindow", "ExteriorOperableWindow", "ExteriorSkylight", "ExteriorTubularDaylightDiffuser", "ExteriorTubularDaylightDome", "ExteriorDoor", "ExteriorGlassDoor", "ExteriorOverheadDoor", "GroundContactWall", "GroundContactRoof", "GroundContactFloor" ] costed_surfaces.each do |surface_type| @costing_report["envelope"]["#{surface_type.underscore}_cost"] = 0.00 @costing_report["envelope"]["#{surface_type.underscore}_area_m2"] = 0.0 @costing_report["envelope"]["#{surface_type.underscore}_cost_per_m2"] = 0.00 end @costing_report["envelope"]["construction_costs"] = [] # Store number of stories. Required for envelope costing logic. num_of_above_ground_stories = model.getBuilding.standardsNumberOfAboveGroundStories.to_i template_type = prototype_creator.template closest_loc = get_closest_cost_location(model.getWeatherFile.latitude, model.getWeatherFile.longitude) generate_construction_cost_database_for_city(@costing_report["city"], @costing_report["province_state"]) totEnvCost = 0 # Iterate through the thermal zones. model.getThermalZones.sort.each do |zone| # Iterate through spaces. zone.spaces.sort.each do |space| # Get SpaceType defined for space.. if not defined it will skip the spacetype. May have to deal with Attic spaces. if space.spaceType.empty? or space.spaceType.get.standardsSpaceType.empty? or space.spaceType.get.standardsBuildingType.empty? raise ("standards Space type and building type is not defined for space:#{space.name.get}. Skipping this space for costing.") end # Get space type standard names. space_type = space.spaceType.get.standardsSpaceType building_type = space.spaceType.get.standardsBuildingType # Get standard constructions based on collected information (spacetype, no of stories, etc..) # This is a standard way to search a hash. construction_set = @costing_database['raw']['construction_sets'].select { |data| data['template'].to_s.gsub(/\s*/, '') == template_type and data['building_type'].to_s.downcase == building_type.to_s.downcase and data['space_type'].to_s.downcase == space_type.to_s.downcase and data['min_stories'].to_i <= num_of_above_ground_stories and data['max_stories'].to_i >= num_of_above_ground_stories }.first # Create Hash to store surfaces for this space by surface type surfaces = {} #Exterior exterior_surfaces = BTAP::Geometry::Surfaces::filter_by_boundary_condition(space.surfaces, "Outdoors") surfaces["ExteriorWall"] = BTAP::Geometry::Surfaces::filter_by_surface_types(exterior_surfaces, "Wall") surfaces["ExteriorRoof"] = BTAP::Geometry::Surfaces::filter_by_surface_types(exterior_surfaces, "RoofCeiling") surfaces["ExteriorFloor"] = BTAP::Geometry::Surfaces::filter_by_surface_types(exterior_surfaces, "Floor") # Exterior Subsurface exterior_subsurfaces = exterior_surfaces.flat_map(&:subSurfaces) surfaces["ExteriorFixedWindow"] = BTAP::Geometry::Surfaces::filter_subsurfaces_by_types(exterior_subsurfaces, ["FixedWindow"]) surfaces["ExteriorOperableWindow"] = BTAP::Geometry::Surfaces::filter_subsurfaces_by_types(exterior_subsurfaces, ["OperableWindow"]) surfaces["ExteriorSkylight"] = BTAP::Geometry::Surfaces::filter_subsurfaces_by_types(exterior_subsurfaces, ["Skylight"]) surfaces["ExteriorTubularDaylightDiffuser"] = BTAP::Geometry::Surfaces::filter_subsurfaces_by_types(exterior_subsurfaces, ["TubularDaylightDiffuser"]) surfaces["ExteriorTubularDaylightDome"] = BTAP::Geometry::Surfaces::filter_subsurfaces_by_types(exterior_subsurfaces, ["TubularDaylightDome"]) surfaces["ExteriorDoor"] = BTAP::Geometry::Surfaces::filter_subsurfaces_by_types(exterior_subsurfaces, ["Door"]) surfaces["ExteriorGlassDoor"] = BTAP::Geometry::Surfaces::filter_subsurfaces_by_types(exterior_subsurfaces, ["GlassDoor"]) surfaces["ExteriorOverheadDoor"] = BTAP::Geometry::Surfaces::filter_subsurfaces_by_types(exterior_subsurfaces, ["OverheadDoor"]) # Ground Surfaces ground_surfaces = BTAP::Geometry::Surfaces::filter_by_boundary_condition(space.surfaces, "Ground") ground_surfaces += BTAP::Geometry::Surfaces::filter_by_boundary_condition(space.surfaces, "Foundation") surfaces["GroundContactWall"] = BTAP::Geometry::Surfaces::filter_by_surface_types(ground_surfaces, "Wall") surfaces["GroundContactRoof"] = BTAP::Geometry::Surfaces::filter_by_surface_types(ground_surfaces, "RoofCeiling") surfaces["GroundContactFloor"] = BTAP::Geometry::Surfaces::filter_by_surface_types(ground_surfaces, "Floor") # Iterate through costed_surfaces.each do |surface_type| # Get Costs for this construction type. This will get the cost for the particular construction type # for all rsi levels for this location. This has been collected by the API costs data. Note that a space_type # of "- undefined -" will create a nil construction_set! if construction_set.nil? cost_range_hash = {} else cost_range_hash = @costing_database['constructions_costs'].select { |construction| construction['construction_type_name'] == construction_set[surface_type] && construction['province_state'] == @costing_report["province_state"] && construction['city'] == @costing_report["city"] } end # We don't need all the information, just the rsi and cost. However, for windows rsi = 1/u_w_per_m2_k surfaceIsGlazing = (surface_type == 'ExteriorFixedWindow' || surface_type == 'ExteriorOperableWindow' || surface_type == 'ExteriorSkylight' || surface_type == 'ExteriorTubularDaylightDiffuser' || surface_type == 'ExteriorTubularDaylightDome' || surface_type == 'ExteriorGlassDoor') if surfaceIsGlazing cost_range_array = cost_range_hash.map { |cost| [ (1.0 / cost['u_w_per_m2_k'].to_f), cost['total_cost_with_op'] ] } else cost_range_array = cost_range_hash.map { |cost| [ cost['rsi_k_m2_per_w'], cost['total_cost_with_op'] ] } end # Sorted based on rsi. cost_range_array.sort! { |a, b| a[0] <=> b[0] } # Iterate through actual surfaces in the model of surface_type. numSurfType = 0 surfaces[surface_type].sort.each do |surface| numSurfType = numSurfType + 1 # Get RSI of existing model surface (actually returns rsi for glazings too!). # Make an array of constructions to use with surfaces_get_conductance method which replaces the get_rsi # method rsi = 1 / (OpenstudioStandards::Constructions.construction_get_conductance(OpenStudio::Model::getConstructionByName(surface.model, surface.construction.get.name.to_s).get)) #Check to see if it is in range # Use the cost_range_array to interpolate the estimated cost for the given rsi. # Note that window costs in the API data use U-value, which was converted to rsi for cost_range_array above exterpolate_percentage_range = 30.0 cost = interpolate(x_y_array: cost_range_array, x2: rsi, exterpolate_percentage_range: exterpolate_percentage_range) # If the cost is nil, that means the rsi is out of range. Flag in the report. if cost.nil? if !cost_range_array.empty? notes = "Warning! RSI out of the range (#{'%.2f' % rsi}) or cost is 0!. Range for #{construction_set[surface_type]} is #{'%.2f' % cost_range_array.first[0]}-#{'%.2f' % cost_range_array.last[0]}." cost = 0.0 else notes = "No cost found for this! So Cost is set to 0.0!" cost = 0.0 end elsif cost.nan? raise("the values for cost and conductance for #{construction_set[surface_type]} cannot be interpolated...cannot create an equation of a line from #{cost_range_array.sort.uniq}. Check construction database and either eliminate the errant row, or set the x value to an appropriate number. ") else #Tell user if we are extrapolating outside of library. array = cost_range_array.sort { |a, b| a[0] <=> b[0] } if rsi < (array.first[0].to_f) || rsi > (array.last[0].to_f) notes = "RSI out of the range (#{'%.2f' % rsi}). Range for #{construction_set[surface_type]} is #{'%.2f' % cost_range_array.first[0]}-#{'%.2f' % cost_range_array.last[0]}.Using extrapolation up to +/-30% of library boundaries. " else notes = "OK" end end # Calculate SHGC/film cost film_cost = 0.0 if surfaceIsGlazing #Get SHGC from surface. shgc = OpenstudioStandards::Constructions.construction_get_solar_transmittance(surface.construction.get.to_Construction.get) # Get the closest value in materials_glazing sheet of SolarFilms. material_row = @costing_database["raw"]["materials_glazing"].select{ |row| row['material_type'] == 'Solarfilms' }.min_by {|row| (shgc.to_f - row['solar_heat_gain_coefficient'].to_f).abs} standard_film_cost = getCost(material_row['description'], material_row, 1.0) regional_factors = get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], material_row) # mult regional cost and sum costs. Zip adds the arrays together, map multiplies each row and divides by 100.0 since the regional factor is in percents. film_cost = standard_film_cost.zip(regional_factors).map{|cost,region_factor| cost * region_factor / 100.0}.inject(0, :+) end testSurfName = surface.name.to_s testSpaceName = space.name.to_s surfArea = surface.netArea * zone.multiplier surfAreaft = (OpenStudio.convert(surfArea, "m^2", "ft^2").get).to_f surfCost = (cost + film_cost) * surfAreaft totEnvCost = totEnvCost + surfCost name = "" # Bin the costing by construction standard type and rsi if construction_set.nil? name = "undefined space type_#{(1.0 / rsi).round(3)}" else name = "#{construction_set[surface_type]}" end row = @costing_report["envelope"]["construction_costs"].detect { |row| (row['name'] == name) && (row['conductance'].round(3) == ((1.0 / rsi).round(3))) } if row.nil? @costing_report["envelope"]["construction_costs"] << {'name' => name, 'conductance' => ((1.0 / rsi).round(3)), 'area' => (surfArea.round(2)), 'cost' => (surfCost.round(2)), 'cost_per_area' => (surfCost / surfArea).round(2), 'note' => "Surf ##{numSurfType}: #{notes}"} else # Not using += for @costing_report additions so that output can be properly rounded row['area'] = (row['area'] + surfArea).round(2) row['cost'] = (row['cost'] + surfCost).round(2) row['cost_per_area'] = ((row['cost'] / row['area']).to_f.round(2)) row['note'] += " / #{numSurfType}: #{notes}" end # Not using += for @costing_report additions so that output can be properly rounded @costing_report["envelope"]["#{surface_type.underscore}_cost"] = (@costing_report["envelope"]["#{surface_type.underscore}_cost"] + surfCost).round(2) @costing_report["envelope"]["#{surface_type.underscore}_area_m2"] = (@costing_report["envelope"]["#{surface_type.underscore}_area_m2"] + surfArea).round(2) @costing_report["envelope"]["#{surface_type.underscore}_cost_per_m2"] = (@costing_report["envelope"]["#{surface_type.underscore}_cost"] / @costing_report["envelope"]["#{surface_type.underscore}_area_m2"]).round(2) end # surfaces of surface type end # surface_type end # spaces end # thermalzone @costing_report["envelope"]['total_envelope_cost'] = totEnvCost.to_f.round(2) puts "\nEnvelope costing data successfully generated. Total envelope cost is $#{totEnvCost.to_f.round(2)}" return totEnvCost end |
#cost_audit_led_lighting(model:, prototype_creator:) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/openstudio-standards/btap/costing/led_lighting_costing.rb', line 3 def cost_audit_led_lighting(model:, prototype_creator:) a = 0 # This is for reporting purposes. standards_template = model.building.get.standardsTemplate.to_s if standards_template.include?('NECB') standards_template = standards_template.gsub(/(?<=\p{L})(?=\d)/, ' ') #insert a space between NECB and 2011/2015/2017 end # puts standards_template #------------------------------------------------------------------------------------------------------------------- led_cost_total = 0.0 #------------------------------------------------------------------------------------------------------------------- model.getSpaces.sort.each do |space| ##### Find height of the space max_space_height_m = 0.0 space.surfaces.sort.select { |surface| surface.surfaceType == 'Wall' }.each do |wall_surface| # Find the vertex with the max z value. vertex_with_max_height = wall_surface.vertices.max_by(&:z) # Replace max if this surface has something bigger. max_space_height_m = vertex_with_max_height.z if vertex_with_max_height.z > max_space_height_m end # puts "max_space_height_m - #{max_space_height_m}" max_space_height_ft = (OpenStudio.convert(max_space_height_m, 'm', 'ft').get) #Convert height to ft # puts "max_space_height_ft - #{max_space_height_ft}" ##### Find space's floor area floor_surface = nil floor_area_m2 = 0.0 floor_vertices = [] space.surfaces.sort.each do |surface| # puts floor_area_m2 if surface.surfaceType == 'Floor' floor_surface = surface floor_area_m2 += surface.netArea # puts floor_area_m2 end end floor_area_ft2 = (OpenStudio.convert(floor_area_m2, 'm^2', 'ft^2').get) #convert floor_area_m2 to ft2 # puts "floor_area_m2 - #{floor_area_m2}" # puts "floor_area_ft2 - #{floor_area_ft2}" ##### Find type of the space space_type = space.spaceType() # puts space_type.get space_type_name = space_type.get.standardsSpaceType # puts "space_type_name - #{space_type_name}" ##### Figure out if the space has LED lighting; and calculate its associated cost space_type.get.lights.sort.each do |light| space_lights_definition = light.lightsDefinition space_lights_definition_name = space_lights_definition.name # puts space_lights_definition_name if space_lights_definition_name.to_s.include?('LED lighting') led_cost_space = 0.0 ##### COSTING-related step: Find fixture type that should be used in the space based on space_type, template, and lights_type search_fixture_type = { row_id_1: space_type_name, row_id_2: standards_template, row_id_3: 'LED' } sheet_name = 'lighting_sets' if max_space_height_ft < 7.88 column_search = 'Fixture_type_less_than_7.88ft_ht' elsif max_space_height_ft >= 7.88 && max_space_height_ft < 15.75 column_search = 'Fixture_type_7.88_to_15.75ft_ht' else #i.e. max_space_height_ft >= 15.75ft_ht column_search = 'Fixture_type_greater_than_>15.75ft_ht' end row_search_1 = 'space_type' row_search_2 = 'template' row_search_3 = 'Type' fixture_type = get_fixture_type_id(fixture_info: search_fixture_type, sheet_name: sheet_name, row_name_1: row_search_1, row_name_2: row_search_2, row_name_3: row_search_3, column_search: column_search) # puts "fixture_type - #{fixture_type}" ##### COSTING-related step: Find 'id_layers' and 'Id_layers_quantity_multipliers' based on fixture_type; and calculate LED cost search_id_layers = @costing_database['raw']['lighting'].select { |data| data['lighting_type_id'].to_f.round(1) == fixture_type.to_f.round(1) }.first if search_id_layers.nil? puts("No data found for #{search_id_layers}!") raise end ids = search_id_layers['id_layers'].to_s.split(',') # puts "id_layers - #{ids}" search_id_layers_quantity_multipliers = @costing_database['raw']['lighting'].select { |data| data['lighting_type_id'].to_f.round(1) == fixture_type.to_f.round(1) }.first if search_id_layers_quantity_multipliers.nil? puts("No data found for #{search_id_layers_quantity_multipliers}!") raise end id_quants = search_id_layers_quantity_multipliers['Id_layers_quantity_multipliers'].to_s.split(',') # puts "id_layers_quantity_multipliers - #{id_quants}" overall_mult = 1.0 index_id_quant = 0.0 ids.each do |id| quantity_led = id_quants[index_id_quant].to_f * overall_mult * floor_area_ft2 # id_description_search = @costing_database['raw']['materials_lighting'].select { |data| # data['lighting_type_id'].to_f.round(1) == id.to_f.round(1) # }.first # id_description = id_description_search['description'] search_led = { row_id_1: nil, row_id_2: id } sheet_name = 'materials_lighting' column_1 = nil column_2 = 'lighting_type_id' = ['lighting', 'led_lighting'] led_costing = assembly_cost(cost_info:search_led, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_led, tags: ) led_cost_space += led_costing index_id_quant += 1.0 end led_cost_total += led_cost_space @costing_report["lighting"]["led_lighting"] << { 'space' => space.name.to_s, 'led_costing' => led_cost_space, } a += 1 end #if space_lights_definition_name.to_s.include?('LED lighting') end #space_type.get.lights.sort.each do |light| #------------------------------------------------------------------------------------------------------------------- end #model.getSpaces.sort.each do |space| #------------------------------------------------------------------------------------------------------------------- if a > 0 @costing_report["lighting"]["led_lighting"] << { 'total_cost' => led_cost_total } end puts "\nLED lighting costing data successfully generated. Total LED lighting costs: $#{led_cost_total.round(2)}" return led_cost_total end |
#cost_audit_lighting(model, prototype_creator) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/openstudio-standards/btap/costing/lighting_costing.rb', line 3 def cost_audit_lighting(model, prototype_creator) # Store number of stories. Required for envelope costing logic. num_of_above_ground_stories = model.getBuilding.standardsNumberOfAboveGroundStories.to_i template_type = prototype_creator.template closest_loc = get_closest_cost_location(model.getWeatherFile.latitude, model.getWeatherFile.longitude) generate_construction_cost_database_for_city(@costing_report["city"],@costing_report["province_state"]) totLgtCost = 0 # daylighting sensor control costing dsc_cost_total = cost_audit_daylighting_sensor_control(model: model, prototype_creator: prototype_creator) # led lighting costing led_cost_total = cost_audit_led_lighting(model: model, prototype_creator: prototype_creator) totLgtCost += dsc_cost_total # Iterate through the thermal zones. #Create Zonal report. @costing_report["lighting"]["fixture_report"] = [] @costing_report["lighting"]["space_report"] = [] model.getThermalZones.sort.each do |zone| # Iterate through spaces. spaceNum = 0 # Counting number of spaces for reporting total_with_region = 0 zone.spaces.sort.each do |space| spaceNum += 1 # Counting number of spaces for reporting # Get SpaceType defined for space.. if not defined it will skip the spacetype. May have to deal with Attic spaces. if space.spaceType.empty? or space.spaceType.get.standardsSpaceType.empty? or space.spaceType.get.standardsBuildingType.empty? raise ("standards Space type and building type is not defined for space:#{space.name.get}. Skipping this space for costing.") end # Get space type standard names. space_type = space.spaceType.get.standardsSpaceType building_type = space.spaceType.get.standardsBuildingType space_light = space.spaceType.get.lights space_has_no_light = space_light.empty? # Figure out what light_type is used in the building light_type = 'Nil' if space_has_no_light == false space.spaceType.get.lights.sort.each do |light| space_lights_definition = light.lightsDefinition space_lights_definition_name = space_lights_definition.name if space_lights_definition_name.to_s.include?('LED lighting') or template_type=='NECB2020' # Note: NECB2020's lights default is LED light_type = 'LED' else light_type = 'CFL' end end end # Get standard lighting sets based on collected information (spacetype, no of stories, etc..) if space_has_no_light == false lighting_set = @costing_database['raw']['lighting_sets'].detect {|data| data['template'].to_s.gsub(/\s*/, '') == template_type and data['building_type'].to_s.downcase == building_type.to_s.downcase and data['space_type'].to_s.downcase == space_type.to_s.downcase and data['Type'].to_s.downcase == light_type.to_s.downcase } else lighting_set = @costing_database['raw']['lighting_sets'].detect {|data| data['template'].to_s.gsub(/\s*/, '') == template_type and data['building_type'].to_s.downcase == building_type.to_s.downcase and data['space_type'].to_s.downcase == space_type.to_s.downcase } end # Determine average space height using space volume and floor area (convert to feet) ceilHgt, flrArea = 0 if space.floorArea > 0 ceilHgt = space.volume / space.floorArea ceilHgt = OpenStudio.convert(ceilHgt,"m","ft").get flrArea = OpenStudio.convert(space.floorArea,"m^2","ft^2").get end # Find Fixture type for this space ceiling height (ft) fixtureType = 'Nil' fixture_description = "" if lighting_set.nil? raise("Error: lighting_set empty for zone #{zone.name.to_s} and space type #{building_type} #{space_type.to_s}!") else if ceilHgt > 0 && ceilHgt < 7.88 fixtureType = lighting_set["Fixture_type_less_than_7.88ft_ht"] elsif ceilHgt >= 7.88 && ceilHgt <= 15.75 fixtureType = lighting_set["Fixture_type_7.88_to_15.75ft_ht"] elsif ceilHgt > 15.75 fixtureType = lighting_set["Fixture_type_greater_than_>15.75ft_ht"] end end # Costs are 0 for 'Nil' because no fixture type due to either zero floor area, zero ceiling height or a 'Nil' # setting for fixture type in lighting_sets sheet ("- undefined -" space) if fixtureType != 'Nil' # Get lighting type sets based on fixtureType lighting_type = @costing_database['raw']['lighting'].select {|lighting_layer_data| lighting_layer_data['lighting_type_id'].to_s == fixtureType.to_s }.first # Scan through layer IDs in id_layers field to get API data from materials_lighting sheet materials_lighting_database = @costing_database["raw"]["materials_lighting"] layer_type_IDs = [] layer_type_mult = [] layer_MaterialCost = 0 layer_LabourCost = 0 if lighting_type["id_layers"].empty? raise ("Lighting type layers list for lighting type ID #{fixtureType} is empty.") else layer_type_IDs = lighting_type["id_layers"].split(/\s*,\s*/) layer_type_mult = lighting_type["Id_layers_quantity_multipliers"].split(/\s*,\s*/) lighting_layers = layer_type_IDs.zip(layer_type_mult).to_h lighting_layers.each do |layer_id, layer_mult| # Note: The column in the spreadsheet labelled "lighting_type_id" is mislabelled and should # really be "lighting_type_layer_id" but left it as-is (below). lighting_material = materials_lighting_database.find do |data| data["lighting_type_id"].to_s == layer_id.to_s end if lighting_material.nil? puts "Lighting material error..could not find lighting material #{layer_id} in #{materials_lighting_database}" raise else costing_data = @costing_database['costs'].detect {|data| data['id'].to_s.upcase == lighting_material['id'].to_s.upcase} if costing_data.nil? puts "Lighting material id #{lighting_material['id']} not found in costing data. Skipping." raise else # Get cost information from lookup. material_cost = costing_data['baseCosts']['materialOpCost'].to_f * layer_mult.to_f * flrArea * zone.multiplier labour_cost = costing_data['baseCosts']['laborOpCost'].to_f * layer_mult.to_f * flrArea * zone.multiplier layer_MaterialCost += material_cost layer_LabourCost += labour_cost regional_material, regional_installation = get_regional_cost_factors(@costing_report["province_state"], @costing_report["city"], lighting_material) total_with_region = layer_MaterialCost * regional_material / 100.0 + layer_LabourCost * regional_installation / 100.0 # Gather info for costed items output file = ['lighting','necb_default'] add_costed_item(material_id: costing_data['id'], quantity: layer_mult.to_f * flrArea * zone.multiplier, material_mult: costing_data['material_mult'].to_f, labour_mult: costing_data['labour_mult'].to_f, equip_mult: 1.0, tags: ) end # costing_data Nil check end # lighting_material Nil check end # lighting layer ids loop totLgtCost += total_with_region fixture_description = lighting_type["description"] end # lighting layer ids check end # fixtureType Nil check zName = zone.name.to_s # Create Lighting space report. @costing_report["lighting"]["space_report"] << { 'space' => space.name.to_s, 'zone' => zone.name.to_s, 'building_type' =>space.spaceType.get.standardsBuildingType.to_s, 'space_type' => space.spaceType.get.standardsSpaceType.to_s, 'zone_multiplier' => space.multiplier, 'fixture_type' => fixtureType, 'fixture_desciption' => fixture_description, 'height_avg_ft' => ceilHgt.round(1), 'floor_area_ft2' => (flrArea * space.multiplier).round(1), 'cost' => total_with_region.round(2), 'cost_per_ft2' => (total_with_region / ( flrArea * space.multiplier )).round(2), 'note' => "" } # Create Lighting Zonal report. lighting_fixture_report = @costing_report["lighting"]["fixture_report"].detect {|fixture_report| fixture_report["fixture_type"] == fixtureType} unless lighting_fixture_report.nil? lighting_fixture_report['floor_area_ft2'] = (lighting_fixture_report['floor_area_ft2'] + (flrArea * space.multiplier)).round(1) lighting_fixture_report['cost'] = (lighting_fixture_report['cost'] + total_with_region).round(2) lighting_fixture_report['cost_per_ft2'] = (lighting_fixture_report['cost'] / lighting_fixture_report['floor_area_ft2']).round(2) lighting_fixture_report['spaces'] << space.name.get lighting_fixture_report['number_of_spaces'] = lighting_fixture_report['spaces'].size else @costing_report["lighting"]["fixture_report"] << { 'fixture_type' => fixtureType, 'fixture_description' => fixture_description, 'floor_area_ft2' => (flrArea * space.multiplier).round(1), 'cost' => total_with_region.round(2), 'cost_per_ft2' => (total_with_region / (flrArea * space.multiplier)).round(2), 'spaces' => [space.name.get], 'number_of_spaces' => 1 } end end # Spaces loop end # thermalzone loop @costing_report["lighting"]['total_lighting_cost'] = totLgtCost.round(2) puts "\nLighting costing data successfully generated. Total lighting cost is $#{totLgtCost.round(2)}" return totLgtCost end |
#cost_audit_nv(model:, prototype_creator:) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
# File 'lib/openstudio-standards/btap/costing/nv_costing.rb', line 3 def cost_audit_nv(model:, prototype_creator:) @costing_report['ventilation'][:natural_ventilation] = [] #TODO: expected results file will be updated once labour cost for zn controller, sensor, and usb are updated in costing database nv_total_cost = 0.0 nv_total_cost_tz = 0.0 nv_total_cost_ahu = 0.0 nv_airloop_vertical_conduit_hash = {} nv_airloop_vertical_conduit_wiring_hash = {} nv_airloop_vertical_conduit_box_hash = {} nv_airloop_roof_conduit_hash = {} nv_airloop_roof_wiring_hash = {} nv_airloop_roof_box_hash = {} nv_airloop_controller_hash = {} #----------------------------------------------------------------------------------------------------------------- ##### Get number of stories and nominal floor to floor height. ##### These inputs are required for the calculation of the length of conduit for each AirLoopHVAC ##### if any thermal zone served by that AirLoopHVAC has the potential for NV. util_dist, ht_roof, nominal_flr2flr_height_ft, horizontal_dist, standards_number_of_stories, mechRmInBsmt = getGeometryData(model, prototype_creator) #----------------------------------------------------------------------------------------------------------------- ##### Find which airloop serves the thermal zone thermal_zones_airloop_hash = {} model.getAirLoopHVACs.sort.each do |air_loop| # puts air_loop.name().to_s air_loop.thermalZones.sort.each do |thermal_zone| # puts thermal_zone.name().to_s thermal_zones_airloop_hash[thermal_zone.name.to_s] = air_loop.name.to_s end end # puts "thermal_zones_airloop_hash is #{thermal_zones_airloop_hash}" #----------------------------------------------------------------------------------------------------------------- ##### Loop through ZoneHVACEquipmentLists to see which thermal zone(s) has(have) been set to use NV where applicable. model.getZoneHVACEquipmentLists.sort.each do |zone_hvac_equipment_list| # puts "zone_hvac_equipment_list.name is #{zone_hvac_equipment_list.name}" nv_exist = 0.0 #this variable is to check the thermal zone has been set to use NV where applicable. (1.0: NV is allowed; 0.0: NV is not allowed) ### Loop through ZoneHVACEquipmentLists to see which thermal zone(s) has(have) ZoneVentilationWindandStackOpenArea hvac_equipment = zone_hvac_equipment_list.equipment for i in 0..hvac_equipment.length() unless hvac_equipment[i].nil? if hvac_equipment[i].to_ZoneVentilationWindandStackOpenArea.is_initialized nv_exist = 1.0 #this means that the thermal zone has NV. end end end # puts "Is NV allowed? #{nv_exist}" ### Loop through thermal zone's spaces to count how many spaces of them have windows to exterior if nv_exist == 1.0 = ['ventilation', 'natural_ventilation'] thermal_zone = zone_hvac_equipment_list.thermalZone thermal_zone_name = thermal_zone.name thermal_zone_multiplier = thermal_zone.multiplier() # puts "thermal_zone_name is #{thermal_zone.name}" ##### Find which airloop serves the thermal zone thermal_zone_sys = thermal_zones_airloop_hash[thermal_zone_name.to_s] # puts "thermal_zone_sys is #{thermal_zone_sys}" if !thermal_zone_sys.nil? ################################################## Step I: costing for each thermal zone ############################################################ ##### costing for each thermal zone: natural ventilation controller ------------------------------------------------------------------------------------------------------------------- quantity_tz_nv_controller = 1.0 * thermal_zone_multiplier # puts "quantity_tz_nv_controller is #{quantity_tz_nv_controller}" search_tz_nv_controller = { row_id_1: 'nat_vent_control', row_id_2: 1537 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' nv_costing_tz_nv_controller = assembly_cost(cost_info:search_tz_nv_controller, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_tz_nv_controller, tags: ) # puts "quantity_tz_nv_controller is #{quantity_tz_nv_controller}" # puts "nv_costing_tz_nv_controller is #{nv_costing_tz_nv_controller}" ##### costing for each thermal zone: natural ventilation sensor ------------------------------------------------------------------------------------------------------------------- quantity_tz_nv_sensor = 1.0 * thermal_zone_multiplier search_tz_nv_sensor = { row_id_1: 'nat_vent_sensor', row_id_2: 1538 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' nv_costing_tz_nv_sensor = assembly_cost(cost_info:search_tz_nv_sensor, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_tz_nv_sensor, tags: ) # puts "quantity_tz_nv_sensor is #{quantity_tz_nv_sensor}" # puts "nv_costing_tz_nv_sensor is #{nv_costing_tz_nv_sensor}" ##### costing for each thermal zone: natural ventilation USB ------------------------------------------------------------------------------------------------------------------- quantity_tz_nv_usb = 1.0 * thermal_zone_multiplier search_tz_nv_usb = { row_id_1: 'nat_vent_usb', row_id_2: 1539 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' nv_costing_tz_nv_usb = assembly_cost(cost_info:search_tz_nv_usb, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_tz_nv_usb, tags: ) # puts "quantity_tz_nv_usb is #{quantity_tz_nv_usb}" # puts "nv_costing_tz_nv_usb is #{nv_costing_tz_nv_usb}" ##### costing for each thermal zone: Tin_sensor_wiring ------------------------------------------------------------------------------------------------------------------- # Note: assuming distance of 30 ft to each thermal zone per floor # for each outdoor sensor (Tout and wind speed) and # Tin sensor to the natural ventilation controller, # total wiring is 90 ft in below equation. quantity_tz_Tin_sensor_wiring = (90.0/100.0) * thermal_zone_multiplier #unit: CLF (hundred linear feet) search_tz_Tin_sensor_wiring = { row_id_1: 'CLF', row_id_2: 10 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' nv_costing_tz_Tin_sensor_wiring = assembly_cost(cost_info:search_tz_Tin_sensor_wiring, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_tz_Tin_sensor_wiring, tags: ) # puts "quantity_tz_Tin_sensor_wiring is #{quantity_tz_Tin_sensor_wiring}" # puts "nv_costing_tz_Tin_sensor_wiring is #{nv_costing_tz_Tin_sensor_wiring}" ##### costing for each thermal zone: PVC_conduit ------------------------------------------------------------------------------------------------------------------- quantity_tz_Tin_sensor_conduit = 2.0 * 30.0 * thermal_zone_multiplier #unit: LF (linear feet) search_tz_Tin_sensor_conduit = { row_id_1: 'LF', row_id_2: 17 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' nv_costing_tz_Tin_sensor_conduit = assembly_cost(cost_info:search_tz_Tin_sensor_conduit, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_tz_Tin_sensor_conduit, tags: ) # puts "quantity_tz_Tin_sensor_conduit is #{quantity_tz_Tin_sensor_conduit}" # puts "nv_costing_tz_Tin_sensor_conduit is #{nv_costing_tz_Tin_sensor_conduit}" ##### costing for each thermal zone: junction box ------------------------------------------------------------------------------------------------------------------- quantity_tz_Tin_sensor_box = 1.0 * thermal_zone_multiplier #unit: Ea search_tz_Tin_sensor_box = { row_id_1: 'Ea', row_id_2: 14 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' nv_costing_tz_Tin_sensor_box = assembly_cost(cost_info:search_tz_Tin_sensor_box, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_tz_Tin_sensor_box, tags: ) # puts "quantity_tz_Tin_sensor_box is #{quantity_tz_Tin_sensor_box}" # puts "nv_costing_tz_Tin_sensor_box is #{nv_costing_tz_Tin_sensor_box}" ##### costing for each thermal zone: duct_damper_motor ------------------------------------------------------------------------------------------------------------------- # calculate how many dampers are needed, depending on the system type nv_a = ['sys_1', 'sys_2', 'sys_3', 'sys_4', 'sys_5', 'sys_7'] nv_b = ['sys_6'] nv_c = thermal_zone_sys if nv_a.any? { |s| nv_c.include? s} damper_mult = 1.0 elsif nv_b.any? { |s| nv_c.include? s} damper_mult = 2.0 end # puts "damper_mult is #{damper_mult}" quantity_tz_duct_damper_motor = 1.0 * damper_mult * thermal_zone_multiplier #unit: Ea search_tz_duct_damper_motor = { row_id_1: 'duct_damper_motor', row_id_2: 6 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'Size' nv_costing_tz_duct_damper_motor = assembly_cost(cost_info:search_tz_duct_damper_motor, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_tz_duct_damper_motor, tags: ) # puts "quantity_tz_duct_damper_motor is #{quantity_tz_duct_damper_motor}" # puts "nv_costing_tz_duct_damper_motor is #{nv_costing_tz_duct_damper_motor}" ##### costing for each thermal zone: duct_damper_wiring ------------------------------------------------------------------------------------------------------------------- quantity_tz_duct_damper_wiring = (30.0/100.0) * damper_mult * thermal_zone_multiplier #unit: CLF search_tz_duct_damper_wiring = { row_id_1: 'CLF', row_id_2: 10 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' nv_costing_tz_duct_damper_wiring = assembly_cost(cost_info:search_tz_duct_damper_wiring, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_tz_duct_damper_wiring, tags: ) # puts "quantity_tz_duct_damper_wiring is #{quantity_tz_duct_damper_wiring}" # puts "nv_costing_tz_duct_damper_wiring is #{nv_costing_tz_duct_damper_wiring}" ##### costing for each thermal zone: duct_damper_conduit ------------------------------------------------------------------------------------------------------------------- quantity_tz_duct_damper_conduit = 30.0 * damper_mult * thermal_zone_multiplier #unit: CLF search_tz_duct_damper_conduit = { row_id_1: 'LF', row_id_2: 17 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' nv_costing_tz_duct_damper_conduit = assembly_cost(cost_info:search_tz_duct_damper_conduit, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_tz_duct_damper_conduit, tags: ) # puts "quantity_tz_duct_damper_conduit is #{quantity_tz_duct_damper_conduit}" # puts "nv_costing_tz_duct_damper_conduit is #{nv_costing_tz_duct_damper_conduit}" ##### costing for each thermal zone: duct_damper_box ------------------------------------------------------------------------------------------------------------------- quantity_tz_duct_damper_box = 1.0 * damper_mult * thermal_zone_multiplier #unit: CLF search_tz_duct_damper_box = { row_id_1: 'Ea', row_id_2: 14 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' nv_costing_tz_duct_damper_box = assembly_cost(cost_info:search_tz_duct_damper_box, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_tz_duct_damper_box, tags: ) # puts "quantity_tz_duct_damper_box is #{quantity_tz_duct_damper_box}" # puts "nv_costing_tz_duct_damper_box is #{nv_costing_tz_duct_damper_box}" ################################################## Step II: costing for each AirLoopHVAC - Vertical Conduit ############################################################ ##### Note: This is completed twice for each AirLoopHVAC: # (1) for the wiring and conduit to the rooftop AHU # (2) for the wiring and conduit to the rooftop outdoor air temperature and wind speed sensors ##### costing for each AirLoopHVAC-VerticalConduit: a single conduit runs the entire height of the building ------------------------------------------------------------------------------------------------------------------- quantity_nv_vertical_conduit = 2.0 * nominal_flr2flr_height_ft * standards_number_of_stories search_nv_vertical_conduit = { row_id_1: 'LF', row_id_2: 13 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' if nv_airloop_vertical_conduit_hash.key?(thermal_zone_sys.to_s) == false nv_costing_vertical_conduit = assembly_cost(cost_info:search_nv_vertical_conduit, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_nv_vertical_conduit, tags: ) nv_airloop_vertical_conduit_hash[thermal_zone_sys.to_s] = nv_costing_vertical_conduit else nv_costing_vertical_conduit = 0.0 end # puts "quantity_nv_vertical_conduit is #{quantity_nv_vertical_conduit}" # puts "nv_costing_vertical_conduit is #{nv_costing_vertical_conduit}" ##### costing for each AirLoopHVAC-VerticalConduit: wiring ------------------------------------------------------------------------------------------------------------------- quantity_nv_vertical_conduit_wiring = 2.0 * nominal_flr2flr_height_ft * standards_number_of_stories / 100.0 search_nv_vertical_conduit_wiring = { row_id_1: 'CLF', row_id_2: 10 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' if nv_airloop_vertical_conduit_wiring_hash.key?(thermal_zone_sys.to_s) == false nv_costing_vertical_conduit_wiring = assembly_cost(cost_info:search_nv_vertical_conduit_wiring, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_nv_vertical_conduit_wiring, tags: ) nv_airloop_vertical_conduit_wiring_hash[thermal_zone_sys.to_s] = nv_costing_vertical_conduit_wiring else nv_costing_vertical_conduit_wiring = 0.0 end # puts "quantity_nv_vertical_conduit_wiring is #{quantity_nv_vertical_conduit_wiring}" # puts "nv_costing_vertical_conduit_wiring is #{nv_costing_vertical_conduit_wiring}" ##### costing for each AirLoopHVAC-VerticalConduit: box ------------------------------------------------------------------------------------------------------------------- quantity_nv_vertical_conduit_box = 2.0 * standards_number_of_stories search_nv_vertical_conduit_box = { row_id_1: 'Ea', row_id_2: 14 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' if nv_airloop_vertical_conduit_box_hash.key?(thermal_zone_sys.to_s) == false nv_costing_vertical_conduit_box = assembly_cost(cost_info:search_nv_vertical_conduit_box, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_nv_vertical_conduit_box, tags: ) nv_airloop_vertical_conduit_box_hash[thermal_zone_sys.to_s] = nv_costing_vertical_conduit_box else nv_costing_vertical_conduit_box = 0.0 end # puts "quantity_nv_vertical_conduit_box is #{quantity_nv_vertical_conduit_box}" # puts "nv_costing_vertical_conduit_box is #{nv_costing_vertical_conduit_box}" ################################################## Step III: costing for each AirLoopHVAC - Roof ############################################################ ##### costing for each AirLoopHVAC-Roof: conduit ------------------------------------------------------------------------------------------------------------------- quantity_nv_roof_conduit = 20.0 search_nv_roof_conduit = { row_id_1: 'LF', row_id_2: 13 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' if nv_airloop_roof_conduit_hash.key?(thermal_zone_sys.to_s) == false nv_costing_roof_conduit = assembly_cost(cost_info:search_nv_roof_conduit, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_nv_roof_conduit, tags: ) nv_airloop_roof_conduit_hash[thermal_zone_sys.to_s] = nv_costing_roof_conduit else nv_costing_roof_conduit = 0.0 end # puts "quantity_nv_roof_conduit is #{quantity_nv_roof_conduit}" # puts "nv_costing_roof_conduit is #{nv_costing_roof_conduit}" ##### costing for each AirLoopHVAC-Roof: wiring ------------------------------------------------------------------------------------------------------------------- quantity_nv_roof_wiring = 20.0 / 100.0 search_nv_roof_wiring = { row_id_1: 'CLF', row_id_2: 10 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' if nv_airloop_roof_wiring_hash.key?(thermal_zone_sys.to_s) == false nv_costing_roof_wiring = assembly_cost(cost_info:search_nv_roof_wiring, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_nv_roof_wiring, tags: ) nv_airloop_roof_wiring_hash[thermal_zone_sys.to_s] = nv_costing_roof_wiring else nv_costing_roof_wiring = 0.0 end # puts "quantity_nv_roof_wiring is #{quantity_nv_roof_wiring}" # puts "nv_costing_roof_wiring is #{nv_costing_roof_wiring}" ##### costing for each AirLoopHVAC-Roof: box ------------------------------------------------------------------------------------------------------------------- quantity_nv_roof_box = 1.0 search_nv_roof_box = { row_id_1: 'Ea', row_id_2: 14 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' if nv_airloop_roof_box_hash.key?(thermal_zone_sys.to_s) == false nv_costing_roof_box = assembly_cost(cost_info:search_nv_roof_box, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_nv_roof_box, tags: ) nv_airloop_roof_box_hash[thermal_zone_sys.to_s] = nv_costing_roof_box else nv_costing_roof_box = 0.0 end # puts "quantity_nv_roof_box is #{quantity_nv_roof_box}" # puts "nv_costing_roof_box is #{nv_costing_roof_box}" ################################################## Step IV: costing for each AirLoopHVAC - Controller ############################################################ quantity_nv_ahu_controller = 1.0 search_nv_ahu_controller = { row_id_1: 'Ea', row_id_2: 400 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' if nv_airloop_controller_hash.key?(thermal_zone_sys.to_s) == false nv_costing_ahu_controller = assembly_cost(cost_info:search_nv_ahu_controller, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_nv_ahu_controller, tags: ) nv_airloop_controller_hash[thermal_zone_sys.to_s] = nv_costing_ahu_controller else nv_costing_ahu_controller = 0.0 end # puts "quantity_nv_ahu_controller is #{quantity_nv_ahu_controller}" # puts "nv_costing_ahu_controller is #{nv_costing_ahu_controller}" ################################################## Step V: costing for each thermal zone (total); also all previous thermal zones including current thermal zone ############################################################ costing_for_each_ThermalZone = nv_costing_tz_nv_controller + nv_costing_tz_nv_sensor + nv_costing_tz_nv_usb + nv_costing_tz_Tin_sensor_wiring + nv_costing_tz_Tin_sensor_conduit + nv_costing_tz_Tin_sensor_box + nv_costing_tz_duct_damper_motor + nv_costing_tz_duct_damper_wiring + nv_costing_tz_duct_damper_conduit + nv_costing_tz_duct_damper_box # puts "costing_for_each_ThermalZone is #{costing_for_each_ThermalZone}" nv_total_cost_tz += costing_for_each_ThermalZone ################################################## Step VI: costing for each AirLoopHVAC - Total ############################################################ costing_for_each_AirLoopHVAC = nv_costing_vertical_conduit + nv_costing_vertical_conduit_wiring + nv_costing_vertical_conduit_box + nv_costing_roof_conduit + nv_costing_roof_wiring + nv_costing_roof_box + nv_costing_ahu_controller ##### Gather information for reporting @costing_report['ventilation'][:natural_ventilation] << { zone: thermal_zone_name.to_s, ahu_serves_the_zone: thermal_zone_sys, costing_for_the_zone: costing_for_each_ThermalZone, costing_for_the_ahu: costing_for_each_AirLoopHVAC } ######################################################################################################################################################## end #if !thermal_zone_sys.nil? end #if nv_exist == 1.0 end #model.getZoneHVACEquipmentLists.sort.each do |zone_hvac_equipment_list| ######################################################################################################################################################## # costing for all AirLoopHVACs if they serve at least one thermal zone with the potential for using NV nv_airloop_vertical_conduit_hash.each do |k, v| nv_total_cost_ahu += v end nv_airloop_vertical_conduit_wiring_hash.each do |k, v| nv_total_cost_ahu += v end nv_airloop_vertical_conduit_box_hash.each do |k, v| nv_total_cost_ahu += v end nv_airloop_roof_conduit_hash.each do |k, v| nv_total_cost_ahu += v end nv_airloop_roof_wiring_hash.each do |k, v| nv_total_cost_ahu += v end nv_airloop_roof_box_hash.each do |k, v| nv_total_cost_ahu += v end nv_airloop_controller_hash.each do |k, v| nv_total_cost_ahu += v end # puts "nv_total_cost_ahu is #{nv_total_cost_ahu}" ######################################################################################################################################################## ##### costing for the roof-top outdoor air temperature sensor and wind speed sensor if nv_total_cost_tz > 0.0 = ['ventilation', 'natural_ventilation'] ### roof-top outdoor air temperature sensor ---------------------------------------------------------------------------------------- quantity_nv_rooftop_sensor_Tout = 1.0 search_nv_rooftop_sensor_Tout = { row_id_1: 'Temperaturesensor', row_id_2: 1326 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' nv_costing_nv_rooftop_sensor_Tout = assembly_cost(cost_info:search_nv_rooftop_sensor_Tout, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_nv_rooftop_sensor_Tout, tags: ) # puts "nv_costing_nv_rooftop_sensor_Tout is #{nv_costing_nv_rooftop_sensor_Tout}" ### roof-top wind speed sensor ----------------------------------------------------------------------------------------------------- quantity_nv_rooftop_sensor_wind_speed = 1.0 search_nv_rooftop_sensor_wind_speed = { row_id_1: 'Ea', row_id_2: 407 } sheet_name = 'materials_lighting' column_1 = 'unit' column_2 = 'lighting_type_id' nv_costing_nv_rooftop_sensor_wind_speed = assembly_cost(cost_info:search_nv_rooftop_sensor_wind_speed, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_nv_rooftop_sensor_wind_speed, tags: ) # puts "nv_costing_nv_rooftop_sensor_wind_speed is #{nv_costing_nv_rooftop_sensor_wind_speed}" ### roof-top sensors ----------------------------------------------------------------------------------------------------- nv_total_cost_rooftop_sensors = nv_costing_nv_rooftop_sensor_Tout + nv_costing_nv_rooftop_sensor_wind_speed ######################################################################################################################################################## nv_total_cost = nv_total_cost_tz + nv_total_cost_ahu + nv_total_cost_rooftop_sensors ##### Gather information for reporting @costing_report['ventilation'][:natural_ventilation] << { costing_for_rooftop_sensors: nv_total_cost_rooftop_sensors, nv_total_cost: nv_total_cost } end puts "\nNatural ventilation costing data successfully generated. Total NV costs: $#{nv_total_cost.round(2)}" return nv_total_cost end |
#cost_audit_pv_ground(model, prototype_creator) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 |
# File 'lib/openstudio-standards/btap/costing/pv_ground_costing.rb', line 3 def cost_audit_pv_ground(model, prototype_creator) @costing_report['renewables']['pv'] = [] a = 0 # This is for reporting purposes. pv_ground_total_cost = 0.0 #------------------------------------------------------------------------------------------------------------------- # summary of all steps as per Mike Lubun's spec: # Step 2: costing of concrete base # Step 3: pv modules' racking costing # Step 4: pv module costing # Step 5: pv wiring costing # Step 6: pv inverter costing # Step 7: transformer costing # Step 8: circuit breakers costing # Step 9: circuit breaker fuses costing # Step 10: PV fuses costing # Step 11: disconnects costing # Step 12: total cost (sum of Step 2 to 11) #------------------------------------------------------------------------------------------------------------------- ##### Gather PV information from the model model.getGeneratorPVWattss.sort.each do |generator_PVWatt| = ['renewables','pv'] dc_system_capacity_w = generator_PVWatt.dcSystemCapacity() module_type = generator_PVWatt.moduleType() dc_system_capacity_kw = dc_system_capacity_w/1000 #----------------------------------------------------------------------------------------------------------------- ##### Step 2: costing of concrete base (#Note: steps' numbers are based on Mike Lubun's spec document) ### Step 2a: costing of concrete ### Step 2b: costing of excavation ### Step 2c: costing of concrete footing ### Step 2d: costing of backfill ### Step 2e: costing of compaction ### Step 2f: costing of underground electrical duct ### Step 2g: costing of grounding ### Step 2h: sum of 2a,b,c,d,e,f,g ### Step 2a: costing of concrete ------------------------------- quantity_concrete = 0.5 * dc_system_capacity_kw #unit: yd3 search_concrete_3000psi = { row_id_1: 'concrete', row_id_2: 3000.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'Size' pv_ground_costing_concrete = assembly_cost(cost_info:search_concrete_3000psi, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_concrete, tags: ) # puts "quantity_concrete is #{quantity_concrete}" # puts "pv_ground_costing_concrete is #{pv_ground_costing_concrete}" ### Step 2b: costing of excavation ------------------------------- quantity_excavation = 3.0 * dc_system_capacity_kw #unit: yd3 search_excavation = { row_id_1: 'Excavation_trench_4_6', row_id_2: 0.75 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'Size' pv_ground_costing_excavation = assembly_cost(cost_info:search_excavation, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_excavation, tags: ) # puts "quantity_excavation is #{quantity_excavation}" # puts "pv_ground_costing_excavation is #{pv_ground_costing_excavation}" ### Step 2c: costing of concrete footing ------------------------------- quantity_concrete_form = 1.0 * dc_system_capacity_kw #unit: each search_concrete_footing = { row_id_1: 'concreteforms', row_id_2: nil } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = nil pv_ground_concrete_footing = assembly_cost(cost_info:search_concrete_footing, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_concrete_form, tags: ) # puts "quantity_concrete_form is #{quantity_concrete_form}" # puts "pv_ground_concrete_footing is #{pv_ground_concrete_footing}" ### Step 2d: costing of backfill ------------------------------- quantity_backfill = 3.0 * dc_system_capacity_kw #unit: each search_backfill = { row_id_1: 'Backfill ', row_id_2: nil } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = nil pv_ground_backfill = assembly_cost(cost_info:search_backfill, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_backfill, tags: ) # puts "quantity_backfill is #{quantity_backfill}" # puts "pv_ground_backfill is #{pv_ground_backfill}" ### Step 2e: costing of compaction ------------------------------- quantity_compaction = 3.0 * dc_system_capacity_kw #unit: yd3 search_compaction = { row_id_1: 'Compaction_WalkBehind', row_id_2: 4.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'Size' pv_ground_compaction = assembly_cost(cost_info:search_compaction, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_compaction, tags: ) # puts "quantity_compaction is #{quantity_compaction}" # puts "pv_ground_compaction is #{pv_ground_compaction}" ### Step 2f: costing of underground electrical duct ------------------------------- quantity_underground_electrical_duct = 100.0 search_underground_electrical_duct = { row_id_1: 'groundconduit', row_id_2: 1470.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' pv_ground_underground_electrical_duct = assembly_cost(cost_info:search_underground_electrical_duct, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_underground_electrical_duct, tags: ) # puts "quantity_underground_electrical_duct is #{quantity_underground_electrical_duct}" # puts "pv_ground_underground_electrical_duct is #{pv_ground_underground_electrical_duct}" ### Step 2g: costing of grounding ------------------------------- # Step 2g-1: costing of ground rod quantity_grounding_ground_rod = 1.0 search_grounding_ground_rod = { row_id_1: 'Ground_Rod', row_id_2: 1356.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' pv_ground_grounding_ground_rod = assembly_cost(cost_info:search_grounding_ground_rod, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_grounding_ground_rod, tags: ) # puts "quantity_grounding_ground_rod is #{quantity_grounding_ground_rod}" # puts "pv_grounding_ground_rod is #{pv_ground_grounding_ground_rod}" # Step 2g-2: costing of exo weld quantity_grounding_exo_weld = 2.0 search_grounding_exo_weld = { row_id_1: 'Exo_weld', row_id_2: 1373.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' pv_ground_grounding_exo_weld = assembly_cost(cost_info:search_grounding_exo_weld, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_grounding_exo_weld, tags: ) # puts "quantity_grounding_exo_weld is #{quantity_grounding_exo_weld}" # puts "pv_grounding_exo_weld is #{pv_ground_grounding_exo_weld}" # Step 2g-3: costing of ground wire #4 quantity_grounding_ground_wire_4 = 100.0 / 100.0 search_grounding_ground_wire_4 = { row_id_1: 'Wire_copper_stranded', row_id_2: 1372.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' pv_ground_grounding_ground_wire_4 = assembly_cost(cost_info:search_grounding_ground_wire_4, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_grounding_ground_wire_4, tags: ) # puts "quantity_grounding_ground_wire_4 is #{quantity_grounding_ground_wire_4}" # puts "pv_grounding_ground_wire_4 is #{pv_ground_grounding_ground_wire_4}" # Step 2g-4: costing of ground wire #6 quantity_grounding_ground_wire_6 = 20.0 search_grounding_ground_wire_6 = { row_id_1: 'Wire_copper_solid', row_id_2: 1361.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' pv_ground_grounding_ground_wire_6 = assembly_cost(cost_info:search_grounding_ground_wire_6, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_grounding_ground_wire_6, tags: ) # puts "quantity_grounding_ground_wire_6 is #{quantity_grounding_ground_wire_6}" # puts "pv_grounding_ground_wire_6 is #{pv_ground_grounding_ground_wire_6}" # Step 2g-5: costing of wire brazing quantity_grounding_wire_brazing = 1.0 search_grounding_wire_brazing = { row_id_1: 'Brazed_connection', row_id_2: 1374.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' pv_ground_grounding_wire_brazing = assembly_cost(cost_info:search_grounding_wire_brazing, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity: quantity_grounding_wire_brazing, tags: ) # puts "quantity_grounding_wire_brazing is #{quantity_grounding_wire_brazing}" # puts "pv_grounding_wire_brazing is #{pv_ground_grounding_wire_brazing}" # total cost of grounding pv_ground_grounding = pv_ground_grounding_ground_rod + pv_ground_grounding_exo_weld + pv_ground_grounding_ground_wire_4 + pv_ground_grounding_ground_wire_6 + pv_ground_grounding_wire_brazing # puts "pv_ground_grounding is #{pv_ground_grounding}" ### Step 2h: sum of 2a,b,c,d,e,f,g ------------------------------ # calculate total cost of concrete base (2a + 2b + 2c + 2d + 2e + 2f + 2g) costing_of_concrete_base = pv_ground_costing_concrete + pv_ground_costing_excavation + pv_ground_concrete_footing + pv_ground_backfill + pv_ground_compaction + pv_ground_underground_electrical_duct + pv_ground_grounding # puts "costing_of_concrete_base is #{costing_of_concrete_base}" #----------------------------------------------------------------------------------------------------------------- ##### Step 3: pv modules' racking costing quantity_racking = dc_system_capacity_kw * 1.0 search_pv_racking = { row_id_1: 'pvgroundmount', row_id_2: 6.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'Size' pv_ground_racking = assembly_cost(cost_info:search_pv_racking, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_racking, tags: ) # puts "quantity_racking is #{quantity_racking}" # puts "pv_ground_racking is #{pv_ground_racking}" #----------------------------------------------------------------------------------------------------------------- ##### Step 4: pv module costing # Note: osm file does not show total area of PV panels; instead it shows the total wattage of PV panels. # So, for the calculation of number of PV panels, we have assumed that a specific module is being used based on # the module type that we can get from the osm file. In this way, we know the wattage of each PV panel; # so, we can calculate number of PV panels. if module_type == 'Standard' #As per Mike Lubun's comment, we assume using 'HES-160-36PV 26.6 x 58.3 x 1.38' as 'Standard' (i.e. 'poly'/'perc') row_id_1 = 'HES-160-36PV 26.6 x 58.3 x 1.38' row_id_2 = 160.0 #wattage of each module of 'HES-160-36PV 26.6 x 58.3 x 1.38' quantity_number_of_panels = dc_system_capacity_w / row_id_2 elsif module_type == 'Premium' #As per Mike Lubun's comment, we assume using 'Heliene 36HD 26.6 x 58.6 x 1.6' as 'Premium' (i.e. 'mono') row_id_1 = 'Heliene 36HD 26.6 x 58.6 x 1.6' row_id_2 = 160.0 #wattage of each module of 'Heliene 36HD 26.6 x 58.6 x 1.6' quantity_number_of_panels = dc_system_capacity_w / row_id_2 elsif module_type == 'ThinFilm' #As per Mike Lubun's comment, we assume using 'Powerfilm, Soltronic Semi-Flex with Sunpower cells, 21 x 44.5 x 0.08' as 'ThinFilm' (i.e. 'thin') row_id_1 = 'Powerfilm, Soltronic Semi-Flex with Sunpower cells, 21 x 44.5 x 0.08' row_id_2 = 100.0 #wattage of each module of 'Powerfilm, Soltronic Semi-Flex with Sunpower cells, 21 x 44.5 x 0.08' quantity_number_of_panels = dc_system_capacity_w / row_id_2 end search_pv_module = { row_id_1: row_id_1, row_id_2: row_id_2 } sheet_name = 'materials_hvac' column_1 = 'description' column_2 = 'Size' pv_ground_costing_pv_module = assembly_cost(cost_info:search_pv_module, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_number_of_panels, tags: ) # puts "quantity_number_of_panels is #{quantity_number_of_panels}" # puts "pv_ground_costing_pv_module is #{pv_ground_costing_pv_module}" #----------------------------------------------------------------------------------------------------------------- ##### Step 5: pv wiring costing # Step 5-1 quantity_wiring_wire = dc_system_capacity_kw * 1.0#unit: CLF (Hundred Linear Feet) search_pv_wire = { row_id_1: 'Wire_copper_stranded', row_id_2: 6.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'Size' pv_ground_wiring_wire = assembly_cost(cost_info:search_pv_wire, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_wiring_wire, tags: ) # puts "quantity_wiring_wire is #{quantity_wiring_wire}" # puts "pv_ground_wiring_wire is #{pv_ground_wiring_wire}" # Step 5-2 quantity_wiring_conduit = dc_system_capacity_kw * 27.0 #unit: LF search_pv_conduit = { row_id_1: 'Conduit', row_id_2: 851.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' pv_ground_wiring_conduit = assembly_cost(cost_info:search_pv_conduit, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_wiring_conduit, tags: ) # puts "quantity_wiring_conduit is #{quantity_wiring_conduit}" # puts "pv_ground_wiring_conduit is #{pv_ground_wiring_conduit}" pv_ground_wiring = pv_ground_wiring_wire + pv_ground_wiring_conduit # puts "pv_ground_wiring is #{pv_ground_wiring}" #----------------------------------------------------------------------------------------------------------------- ##### Step 6: pv inverter costing # Step 6-1: inverters themselves if dc_system_capacity_kw < 4.0 inverter_size = 3.0 inverter_multiplier = 1.0 elsif dc_system_capacity_kw == 4.0 inverter_size = 4.0 inverter_multiplier = 1.0 elsif dc_system_capacity_kw > 4.0 inverter_size = 4.0 inverter_multiplier = dc_system_capacity_kw / 4.0 inverter_multiplier = inverter_multiplier.ceil end # puts "inverter_multiplier is #{inverter_multiplier}" quantity_inverter_itself = inverter_multiplier.to_f search_pv_inverter_itself = { row_id_1: 'inverter24', row_id_2: inverter_size } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'Size' pv_ground_inverter_itself = assembly_cost(cost_info:search_pv_inverter_itself, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_inverter_itself, tags: ) # puts "quantity_inverter_itself is #{quantity_inverter_itself}" # puts "pv_ground_inverter_itself is #{pv_ground_inverter_itself}" # Step 6-2: inverters' boxes quantity_inverter_box = inverter_multiplier.to_f search_pv_inverter_box = { row_id_1: 'pvbox', row_id_2: 1135.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' pv_ground_inverter_box = assembly_cost(cost_info:search_pv_inverter_box, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_inverter_box, tags: ) # puts "quantity_inverter_box is #{quantity_inverter_box}" # puts "pv_ground_inverter_box is #{pv_ground_inverter_box}" pv_ground_inverter = pv_ground_inverter_itself + pv_ground_inverter_box # puts "pv_ground_inverter is #{pv_ground_inverter}" #----------------------------------------------------------------------------------------------------------------- ##### Step 7: transformer costing transformer_types = [1.0, 2.0, 3.0, 5.0, 7.5, 10.0, 15.0, 25.0, 37.5, 50.0, 75.0, 100.0, 167.0] #based on Mike Lubun's costing spreadsheet transformer_closet_to_pv_kw = transformer_types.sort_by { |item| (dc_system_capacity_kw-item).abs }.first(1) # puts "transformer_closet_to_pv_kw is #{transformer_closet_to_pv_kw}" if dc_system_capacity_kw <= 167.0 transformer_multiplier = 1.0 row_id_2 = transformer_closet_to_pv_kw[0] else #i.e. dc_system_capacity_kw > 167.0 transformer_multiplier = dc_system_capacity_kw / 167.0 transformer_multiplier = transformer_multiplier.ceil row_id_2 = 167.0 end # puts "transformer_multiplier is #{transformer_multiplier}" quantity_transformer = transformer_multiplier.to_f search_transformer = { row_id_1: 'Transformer_dry_low_voltage', row_id_2: row_id_2 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'Size' pv_ground_transformer = assembly_cost(cost_info:search_transformer, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_transformer, tags: ) # puts "quantity_transformer is #{quantity_transformer}" # puts "pv_ground_transformer is #{pv_ground_transformer}" #----------------------------------------------------------------------------------------------------------------- ##### Step 8: circuit breakers costing circuit_breaker240_types = [30.0, 60.0, 100.0, 200.0, 400.0, 600.0] circuit_breaker_amps = (dc_system_capacity_kw * 1000.0 * 1.5 / 24.0) * 1.25 # puts "circuit_breaker_amps is #{circuit_breaker_amps}" circuit_breaker_closet_to_pv_amps = circuit_breaker240_types.sort_by { |item| (circuit_breaker_amps-item).abs }.first(1) # puts "circuit_breaker_closet_to_pv_amps is #{circuit_breaker_closet_to_pv_amps}" if circuit_breaker_amps <= 600.0 circuit_breaker_multiplier = 1.0 row_id_2 = circuit_breaker_closet_to_pv_amps[0] else #i.e. circuit_breaker_amps > 600.0 circuit_breaker_multiplier = circuit_breaker_amps / 600.0 circuit_breaker_multiplier = circuit_breaker_multiplier.ceil row_id_2 = 600.0 end quantity_circuit_breakers = circuit_breaker_multiplier.to_f search_circuit_breakers = { row_id_1: 'Circuit_breaker240', row_id_2: row_id_2 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'Size' pv_ground_circuit_breakers = assembly_cost(cost_info:search_circuit_breakers, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_circuit_breakers, tags: ) # puts "quantity_circuit_breakers is #{quantity_circuit_breakers}" # puts "pv_ground_circuit_breakers is #{pv_ground_circuit_breakers}" #----------------------------------------------------------------------------------------------------------------- ##### Step 9: circuit breaker fuses costing circuit_breaker_fuse = circuit_breaker_amps circuit_breaker_fuse_250V_timedelay_types = [30.0, 5.0, 60.0, 100.0, 200.0, 400.0, 600.0] circuit_breaker_fuse_closet_to_pv_amps = circuit_breaker_fuse_250V_timedelay_types.sort_by { |item| (circuit_breaker_fuse-item).abs }.first(1) # puts "circuit_breaker_fuse_closet_to_pv_amps is #{circuit_breaker_fuse_closet_to_pv_amps}" if circuit_breaker_fuse <= 600.0 circuit_breaker_fuse_multiplier = 1.0 row_id_2 = circuit_breaker_fuse_closet_to_pv_amps[0] else #i.e. circuit_breaker_fuse > 600.0 circuit_breaker_fuse_multiplier = circuit_breaker_fuse / 600.0 circuit_breaker_fuse_multiplier = circuit_breaker_fuse_multiplier.ceil row_id_2 = 600.0 end quantity_circuit_breaker_fuses = circuit_breaker_fuse_multiplier.to_f search_circuit_breaker_fuses = { row_id_1: 'fuse_250V_timedelay', row_id_2: row_id_2 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'Size' pv_ground_circuit_breaker_fuses = assembly_cost(cost_info:search_circuit_breaker_fuses, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_circuit_breaker_fuses, tags: ) # puts "quantity_circuit_breaker_fuses is #{quantity_circuit_breaker_fuses}" # puts "pv_ground_circuit_breaker_fuses is #{pv_ground_circuit_breaker_fuses}" #----------------------------------------------------------------------------------------------------------------- ##### Step 10: PV fuses costing # Step 10-1: PV fuses quantity_pv_fuse_itself = (dc_system_capacity_kw * 1.0).ceil.to_f search_pv_fuse = { row_id_1: 'fuse_120V', row_id_2: 15.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'Size' pv_ground_pv_fuse_itself = assembly_cost(cost_info:search_pv_fuse, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_pv_fuse_itself, tags: ) # puts "quantity_pv_fuse_itself is #{quantity_pv_fuse_itself}" # puts "pv_ground_pv_fuse_itself is #{pv_ground_pv_fuse_itself}" # Step 10-2: PV combiner box quantity_pv_combiner_box = (dc_system_capacity_kw / 10.0).ceil.to_f search_pv_combiner_box = { row_id_1: 'pvcombinerbox', row_id_2: 1125.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' pv_ground_pv_combiner_box = assembly_cost(cost_info:search_pv_combiner_box, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_pv_combiner_box, tags: ) # puts "quantity_pv_combiner_box is #{quantity_pv_combiner_box}" # puts "pv_ground_pv_combiner_box is #{pv_ground_pv_combiner_box}" pv_ground_pv_fuses = pv_ground_pv_fuse_itself + pv_ground_pv_combiner_box # puts "pv_ground_pv_fuses is #{pv_ground_pv_fuses}" #----------------------------------------------------------------------------------------------------------------- ##### Step 11: disconnects costing quantity_disconnect_before_inverter = 1.0 search_disconnect_before_inverter = { row_id_1: 'Circuit_breaker240', row_id_2: 1403.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' pv_ground_disconnect_before_inverter = assembly_cost(cost_info:search_disconnect_before_inverter, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_disconnect_before_inverter, tags: ) # puts "quantity_disconnect_before_inverter is #{quantity_disconnect_before_inverter}" # puts "pv_ground_disconnect_before_inverter is #{pv_ground_disconnect_before_inverter}" quantity_disconnect_after_transformer = 1.0 search_disconnect_after_transformer = { row_id_1: 'Circuit_breaker240', row_id_2: 1407.0 } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'material_id' pv_ground_disconnect_after_transformer = assembly_cost(cost_info:search_disconnect_after_transformer, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_disconnect_after_transformer, tags: ) # puts "quantity_disconnect_after_transformer is #{quantity_disconnect_after_transformer}" # puts "pv_ground_disconnect_after_transformer is #{pv_ground_disconnect_after_transformer}" pv_ground_disconnects = pv_ground_disconnect_before_inverter + pv_ground_disconnect_after_transformer # puts "pv_ground_disconnects is #{pv_ground_disconnects}" #----------------------------------------------------------------------------------------------------------------- ##### Step 12: calculate total cost of the ground mount PV system (sum of steps 2 to 11) pv_ground_total_cost_handle = costing_of_concrete_base + pv_ground_racking + pv_ground_costing_pv_module + pv_ground_wiring + pv_ground_inverter + pv_ground_transformer + pv_ground_circuit_breakers + pv_ground_circuit_breaker_fuses + pv_ground_pv_fuses + pv_ground_disconnects pv_ground_total_cost += pv_ground_total_cost_handle # puts "pv_ground_total_cost_handle is #{pv_ground_total_cost_handle}" ##### Gather information for reporting @costing_report['renewables']['pv'] << { 'generator_PVWatt_name' => generator_PVWatt.name.to_s, 'costing_of_concrete_base' => costing_of_concrete_base, 'pv_ground_racking' => pv_ground_racking, 'pv_ground_costing_pv_module' => pv_ground_costing_pv_module, 'pv_ground_wiring' => pv_ground_wiring, 'pv_ground_inverter' => pv_ground_inverter, 'pv_ground_transformer' => pv_ground_transformer, 'pv_ground_circuit_breakers' => pv_ground_circuit_breakers, 'pv_ground_circuit_breaker_fuses' => pv_ground_circuit_breaker_fuses, 'pv_ground_pv_fuses' => pv_ground_pv_fuses, 'pv_ground_disconnects' => pv_ground_disconnects, 'the_generator_PVWatt_total_cost' => pv_ground_total_cost_handle } a += 1 end if a > 0 @costing_report['renewables']['pv'] << { 'pv_ground_total_cost' => pv_ground_total_cost } end puts "\nGround-mounted PV costing data successfully generated. Total PV costs: $#{pv_ground_total_cost.round(2)}" return pv_ground_total_cost end |
#cost_ccashp_additional_components(ahu_mult:, heat_pump:, vent_tags: [], report_mult: 1.0) ⇒ Object
This method calculates the costs of CCASHP equipment beyond the coil cost and any backup heating costs. It takes in ahu_mult: The number of air handlers required to meet the model air loop flow rate, cooling type, heating type and system type. heat_pumps: The heat pump hash for the ccashp which contains the OpenStudio heat pump object and the size of the heat pump in kW. The method uses a number of different costing methods to get equipment costs. The methods used depend on what best suits the costing. For example evaporator costing is found by size and material so the get_vent_cost_data method is most appropriate. Wiring has a material and size but the size should be an exact match so the get_comp_cost method is used. Finally, a number of pieces of equipment with no size are costed. The esiest way to cost these items was to refer to their ‘materials_hvac’ sheet ‘material_id’ column numbers and associated quantities and use the vent_assembly_cost method.
2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 2545 def cost_ccashp_additional_components(ahu_mult:, heat_pump:, vent_tags: [], report_mult: 1.0) = .clone # Initialize the ccashp additional equipment cost. ccashp_add_cost = 0 # Set a variable to represent the capacity of each heat pump per air handler cap = heat_pump[:mech_capacity_kw].to_f/ahu_mult # Set a variable to represent the capacity in tons of cooling (for costing the refrigerent line). # cap_tonc = (OpenStudio.convert(cap.to_f, 'kW', 'kBtu/hr').get)/12.0 # No longer needed but keeping for future reference # This variable holds the number of condensing units. cond_mult = 1.0 # An array of hashes containing the information required to cost the heat pump evaporator valve and condenser. ccashp_lrg_equips = [] ccashp_lrg_equips << { supply_comp: heat_pump[:supply_comp], mech_capacity_kw: cap, cat_search: "EV_valve" } ccashp_lrg_equips << { supply_comp: heat_pump[:supply_comp], mech_capacity_kw: cap, cat_search: "ccashp_condensor" } # Cost the heat pump evaporator valve and condenser. ccashp_lrg_equips.each do |ccashp_lrg_equip| equip_mult, cost_info = get_vent_cost_data(equipment_info: ccashp_lrg_equip) ccashp_add_cost += get_vent_mat_cost(mat_cost_info: cost_info, vent_tags: , report_mult: (report_mult*equip_mult*ahu_mult)) * equip_mult * ahu_mult # cond_mult is supposed to be the number of condensors there are. It is set to be the multiplier if one condensor # is not enough. It should be set to the number of condesors because the condensors should be the last item in # this loop to be costed. cond_mult = equip_mult end # Cost the wiring per heat pump condenser. Correcting to use 20 ft rather than 20 m. #ccashp_wiring_dist = (OpenStudio.convert(20, 'm', 'ft').get)/100.0 ccashp_add_equip = [ { mat: "Wiring", unit: "CLF", size: 10, mult: 0.2 * ahu_mult * cond_mult } ] # Get the Wiring costs. ccashp_add_cost += get_comp_cost(cost_info: ccashp_add_equip, vent_tags: ) # Set an array containing the equipment 'material_id' references to search in the costing spreadsheet # 'materials_hvac' sheet. ids = [ #1307, #Low Temperature Kit this belongs with the air handlers not the equipment 1295, # Remote Condensor Controller 1662, # Refrigerant tubing-large, 20' of 0.5" supply and 1-1/8" return 30, # 1.25" pipe insulation for refrigerant tubing 1415 # Safety Switch ] # Set the quantities associated with the above ids. Note that ahu_mult is included when getting the cost. id_quants = [ #1.0, cond_mult, cond_mult, cond_mult * 20 * 2, # 20' of supply and return pipe insulation for refrigerant tubing cond_mult ] # Get the costs for equipment in the ids with id_quants quantities above. ccashp_add_cost += vent_assembly_cost(ids: ids, id_quants: id_quants, overall_mult: ahu_mult, vent_tags: ) return ccashp_add_cost end |
#cost_construction(construction, location, type = 'opaque') ⇒ Object
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/openstudio-standards/btap/costing/envelope_costing.rb', line 231 def cost_construction(construction, location, type = 'opaque') material_layers = "material_#{type}_id_layers" material_id = "materials_#{type}_id" materials_database = @costing_database["raw"]["materials_#{type}"] total_with_op = 0.0 material_cost_pairs = [] construction[material_layers].split(',').reject { |c| c.empty? }.each do |material_index| material = materials_database.find { |data| data[material_id].to_s == material_index.to_s } if material.nil? puts "material error..could not find material #{material_index} in #{materials_database}" raise() else costing_data = @costing_database['costs'].detect { |data| data['id'].to_s.upcase == material['id'].to_s.upcase } if costing_data.nil? puts "This material id #{material['id']} was not found in the costing database. Skipping. This construction will be inaccurate. " raise() else regional_material, regional_installation = get_regional_cost_factors(location['province_state'], location['city'], material) # Get cost information from lookup. # Note that "glazing" types don't have a 'quantity' hash entry! # Don't need "and" below but using in-case this hash field is added in the future. if type == 'glazing' and material['quantity'].to_f == 0.0 material['quantity'] = '1.0' end material_cost = costing_data['baseCosts']['materialOpCost'].to_f * material['material_mult'].to_f labour_cost = costing_data['baseCosts']['laborOpCost'].to_f * material['labour_mult'].to_f equipment_cost = costing_data['baseCosts']['equipmentOpCost'].to_f layer_cost = (((material_cost * regional_material / 100.0) + (labour_cost * regional_installation / 100.0) + equipment_cost) * material['quantity'].to_f).round(2) material_cost_pairs << {material_id.to_s => material_index, 'cost' => layer_cost} total_with_op += layer_cost end end end new_construction = { 'province_state' => location['province_state'], 'city' => location['city'], "construction_type_name" => construction["construction_type_name"], 'description' => construction["description"], 'intended_surface_type' => construction["intended_surface_type"], 'standards_construction_type' => construction["standards_construction_type"], 'rsi_k_m2_per_w' => construction['rsi_k_m2_per_w'].to_f, 'zone' => construction['climate_zone'], 'fenestration_type' => construction['fenestration_type'], 'u_w_per_m2_k' => construction['u_w_per_m2_k'], 'materials' => material_cost_pairs, 'total_cost_with_op' => total_with_op} @costing_database['constructions_costs'] << new_construction end |
#cost_heat_cool_equip(equipment_info:, vent_tags: [], report_mult: 1.0) ⇒ Object
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 681 def cost_heat_cool_equip(equipment_info:, vent_tags: [], report_mult: 1.0) = .clone total_cost = 0 multiplier, heat_cool_cost_info = get_vent_cost_data(equipment_info: equipment_info) total_cost += (get_vent_mat_cost(mat_cost_info: heat_cool_cost_info, vent_tags: , report_mult: (report_mult*multiplier)))*multiplier if equipment_info[:cooling_type] == 'DX' || equipment_info[:cooling_type] == 'DX-adv' equipment_info[:cooling_type].include?("-adv") ? search_suff = "-adv" : search_suff = "" equipment_info[:cat_search] = "CondensingUnit" + search_suff << equipment_info[:cat_search] unless .empty? multiplier, heat_cool_cost_info = get_vent_cost_data(equipment_info: equipment_info) total_cost += get_vent_mat_cost(mat_cost_info: heat_cool_cost_info, vent_tags: , report_mult: (report_mult*multiplier))*multiplier << "piping" unless .empty? piping_search = [] piping_search << { mat: 'SteelPipe', unit: 'L.F.', size: 1.25, mult: 32.8 } piping_search << { mat: 'PipeInsulationsilica', unit: 'L.F.', size: 1.25, mult: 32.8 } piping_search << { mat: 'SteelPipeElbow', unit: 'each', size: 1.25, mult: 8 } total_cost += get_comp_cost(cost_info: piping_search, vent_tags: , report_mult: (report_mult*multiplier))*multiplier return total_cost end # This needs to be revised as currently the costing spreadsheet may not inculde heating and cooling coil costs in # the ahu definition sheet. This is commented out for now but will need to be revisited. See btap_tasks issue 156. =begin if equipment_info[:heating_fuel] == 'HP' if sys_type == 3 || sys_type == 6 # Remove the DX cooling unit for ashp in type 3 and 6 systems heat_cool_cost = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == 'DX' and data['Size'].to_f.round(8) >= equipment_info[:mech_capacity_kw].to_f }.first if heat_cool_cost.nil? heat_cool_cost, multiplier = get_vent_system_mult(loop_equip: equipment_info) end total_cost -= (get_vent_mat_cost(mat_cost_info: heat_cool_cost))*multiplier # Remove the heating coil for ashp in type 3 and 6 systems heat_cool_cost = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == 'COILS' and data['Size'].to_f.round(8) >= equipment_info[:mech_capacity_kw].to_f }.first if heat_cool_cost.nil? heat_cool_cost, multiplier = get_vent_system_mult(loop_equip: equipment_info) end total_cost -= (get_vent_mat_cost(mat_cost_info: heat_cool_cost))*multiplier puts 'hello' end # Add pre-heat for ashp in all cases # This needs to be refined as well. Only add the cost of an electric heat if a heater (presumably of any type) if # one is not already explicitly modeled in the air loop (and thus costed already as part of this method). This is # also part of btap_tasks issue 156. heat_cool_cost = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == 'ELECHEAT' and data['Size'].to_f.round(8) >= equipment_info[:mech_capacity_kw].to_f }.first if heat_cool_cost.nil? heat_cool_cost, multiplier = get_vent_system_mult(loop_equip: equipment_info) end total_cost += (get_vent_mat_cost(mat_cost_info: heat_cool_cost))*multiplier end =end return total_cost end |
#cost_list_items(btap_items:, custom_costing: nil, custCity: nil, custProvince: nil) ⇒ Object
This method takes the list of costed items in the building generated with the help of the above add_costed_item method and finds the costs for the list of items. It takes in: btap_items: (array of hashes) This array contains all the items that must be costed. The first element of the
array is:
{
City: (string) City used for cost lacalization factor
Province: (string) Province used for cost localization factor
}
The remaining arrays look like: {
id: (string) ID of the coested item in question.
quantity: (float) Amount of costed item (should include all multipliers except localization factors,
material_mult, labour_mult, equipment_mult).
material_mult: (float) Material multiplier from cost spreadsheet used mainly for higher performance equipment
(for example, regular and high performance boilers share the same id but high performance
boilers have a material_mult of around 1.3-that is they are estimated to be 1.3 times as
expensive as regular boilers).
labour_mult: (float) Same idea as material_mult only for labour (often this will be 1.0 even if material_mult
is something else).
equipment_mult: (float) Same idea as labour_mult only for equipment. It will always be 1.0 until equipment
costs are implemented in costing.
tags: (array of strings) An array of strings used to define what part of the building is being costed (e.g.
an component for a ccashp might have these tags: "Ventilation", "CCASHP", "ccashp_condensor")
}
custom_costing: (array of hashes) A custom costing database if you do not want to use the default one. This must
have the same format as that found by @costing_database['costs']
custCity: (string) A custom cost localization city if you do not want to use the one in the first item in the
btap_itmes hash.
custProvince: (string) A custom cost localization province if you do not want to use the one in the first item in
the btap_items hash.
The output of the method is a hash containing these summary costs:
costRetHash = {
envelope: (float) Building envelope costs (to 2 decimal places).
lighting: (float) Ligting costs (to 2 decimal places).
heating_and_cooling: (float) Heating and cooling costs (not related to ventilation) (to 2 decimal places).
shw: (float) Service hot water costs (to 2 decimal places).
ventilation: (float) Ventilation (including ventilation air heating and cooling) costs (to 2 decimal places).
grand_total: (float) Total costs (to 2 decimal places).
}
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 391 def cost_list_items(btap_items:, custom_costing: nil, custCity: nil, custProvince: nil) # Check if costing is for a custom city and province. If not use the city and province found in the first entry # of the array of costed items. if custCity.nil? || custProvince.nil? costCity = btap_items['City'].to_s costProvince = btap_items['Province'].to_s else costCity = custCity costProvince = custProvince end # Initialize cost counters totCost = 0.0 envCost = 0.0 lightCost = 0.0 heatCoolCost = 0.0 shwCost = 0.0 ventCost = 0.0 renewCost = 0.0 custom_costing.nil? ? costingDB = @costing_database['costs'] : costingDB = custom_costing btap_items['Items'].each do |costing_item| # Look for the costing information for the piece of equipment in the costing database. costing_data = costingDB.detect {|data| data['id'].to_s.upcase == costing_item['id'].to_s.upcase} # If no costing information is found then return an error. if costing_data.nil? raise "Error: no costing information available for material id #{costing_item['id']}!" elsif costing_data['baseCosts']['materialOpCost'].nil? && costing_data['baseCosts']['laborOpCost'].nil? #This is a stub for some work that needs to be done to account for equipment costing. For now this is zeroed out. # A similar test is done on reading the data from the database and collected in the error file when the # costing database is generated. raise "Error: costing information for material id #{costing_item['id']} is nil. Please check costing data." end costing_data['baseCosts']['equipmentOpCost'].nil? ? equip_base_cost = 0.0 : equip_base_cost = costing_data['baseCosts']['equipmentOpCost'].to_f costing_data['baseCosts']['materialOpCost'].nil? ? mat_base_cost = 0.0 : mat_base_cost = costing_data['baseCosts']['materialOpCost'].to_f costing_data['baseCosts']['laborOpCost'].nil? ? lab_base_cost = 0.0 : lab_base_cost = costing_data['baseCosts']['laborOpCost'].to_f # The costs from the costing database are US national average costs (for placeholder costs) or whatever is in the # 'province_state' and 'city' fields (for custom costs). These costs need to be adjusted to reflect the costs # expected in the location of interest. The 'get_regional_cost_factors' method finds the appropriate cost # adjustment factors. mat_mult, inst_mult, eq_mult = get_regional_cost_factors(costProvince, costCity, costing_item) if mat_mult.nil? || inst_mult.nil? raise("Error: no localization information available for material id #{costing_item['material_id']}!") end # Get any associated material or labour multiplier for the equipment present in the 'materials_hvac' sheet in the # costing spreadsheet. costing_item['material_mult'].to_f == 0 ? mat_quant = 1.0 : mat_quant = costing_item['material_mult'].to_f costing_item['labour_mult'].to_f == 0 ? lab_quant = 1.0 : lab_quant = costing_item['labour_mult'].to_f costing_item['equipment_mult'].to_f == 0 || costing_item['equipment_mult'].nil? ? eq_quant = 1.0 : eq_quant = costing_item['equipment_mult'].to_f # Calculate the adjusted material and labour costs. mat_cost = mat_base_cost*(mat_mult/100.0)*mat_quant lab_cost = lab_base_cost*(inst_mult/100.0)*lab_quant eq_cost = equip_base_cost*(eq_mult/100.0)*eq_quant # Calculate the total item cost. item_cost = (mat_cost + lab_cost + eq_cost)*(costing_item["quantity"].to_f) # Add cost to sub-type counters envCost += item_cost unless (costing_item['tags'].select{|data| data.to_s.upcase == "ENVELOPE"}).empty? lightCost += item_cost unless (costing_item['tags'].select{|data| data.to_s.upcase == "LIGHTING"}).empty? heatCoolCost += item_cost unless (costing_item['tags'].select{|data| data.to_s.upcase == "HEATING_COOLING"}).empty? shwCost += item_cost unless (costing_item['tags'].select{|data| data.to_s.upcase == "SHW"}).empty? ventCost += item_cost unless (costing_item['tags'].select{|data| data.to_s.upcase == "VENTILATION"}).empty? renewCost += item_cost unless (costing_item['tags'].select{|data| data.to_s.upcase == "RENEWABLES"}).empty? totCost += item_cost end # Create and return hash containing costing results costRetHash = { 'envelope' => envCost.round(2), 'lighting' => lightCost.round(2), 'heating_and_cooling' => heatCoolCost.round(2), 'shw' => shwCost.round(2), 'ventilation' => ventCost.round(2), 'renewables' => renewCost.round(2), 'grand_total' => totCost.round(2) } return costRetHash end |
#cost_shw_main(mech_room:, roof_cent:, min_space:) ⇒ Object
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 |
# File 'lib/openstudio-standards/btap/costing/shw_costing.rb', line 503 def cost_shw_main(mech_room:, roof_cent:, min_space:) shw_dist_search = [] building_height_m = (roof_cent[:roof_centroid][2] - min_space[:roof_cent][2]).abs mech_to_cent_dist_m = (roof_cent[:roof_centroid][0] - mech_room['space_centroid'][0]).abs + (roof_cent[:roof_centroid][1] - mech_room['space_centroid'][1]).abs #Twice the distance to account for supply and return shw piping. total_dist_m = 2*(building_height_m + mech_to_cent_dist_m) total_dist_ft = OpenStudio.convert(total_dist_m, 'm', 'ft').get shw_dist_search << { mat: 'CopperPipe', unit: 'L.F.', size: 0.75, mult: total_dist_ft } total_comp_cost = get_comp_cost(cost_info: shw_dist_search) return { length_m: total_dist_m, cost: total_comp_cost } end |
#costVRFCondenser(model:, maxHeightDiff:, regMat:, regLab:, regMatElec:, regLabElec:, roofHeight:) ⇒ Object
Costing for the VRF Condenser(s) and the wiring and piping conecting the Condenser(s) to the branch distributors on each floor of the building with thermal zones served by a VRF system.
Taking in: model(hash): OpenStudio building model maxHeightDiff(float, m): Difference between height of highest ceiling and ceiling of lowest space served by a VRF
system.
regMat(float): HVAC regional cost factor for material. regLab(float): HVAC regional cost factor for labour. RegMatElec(float): Electrical regional cost factor for material. RegLabElec(float): Electrical regional cost factor for labour.
Returns: Total VRF condensor cost (also adds information to @costing_report).
2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 2300 def costVRFCondenser(model:, maxHeightDiff:, regMat:, regLab:, regMatElec:, regLabElec:, roofHeight:) # VRF systems have a maximum height difference of 50m. If the height difference calculated above is greater than # 50m then determine how many VRF condensers are required (one every 50m) numVRFheight = 1.0 if maxHeightDiff > 50.0 (maxHeightDiff % 50.0).round(1) > 0.0 ? numVRFheight = (maxHeightDiff / 50.0).to_i.to_f + 1.0 : numVRFheight = (maxHeightDiff / 50.0).to_f.round(0) end # Get the VRF condenser and calculate the overall capacity as the largest of the heating or cooling capacities. vrfCond = model.getAirConditionerVariableRefrigerantFlows[0] if vrfCond.isGrossRatedHeatingCapacityAutosized.to_bool heatingCapkW = vrfCond.autosizedGrossRatedHeatingCapacity.to_f/1000.0 else heatingCapkW = vrfCond.grossRatedHeatingCapacity.to_f/1000.0 end if vrfCond.isGrossRatedTotalCoolingCapacityAutosized.to_bool coolingCapkW = vrfCond.autosizedGrossRatedTotalCoolingCapacity.to_f/1000.0 else coolingCapkW = vrfCond.grossRatedTotalCoolingCapacity.to_f/1000.0 end heatingCapkW >= coolingCapkW ? vrfCondCapkW = heatingCapkW : vrfCondCapkW = coolingCapkW # If more than one VRF condenser is present because of a large height difference then assume each VRF condenser will # serve the same fraction of the load. Divide the revised capacity as the original capacity divided by the number # of VRF condensers required to compensate for a height difference (the default is 1). modVRFCondCapkW = vrfCondCapkW / numVRFheight vrfCondInfo = getHVACDBInfo(name: "VRF Condenser Unit", materialLookup: "VRF-HP-HRV-Outdoor", materialSize: modVRFCondCapkW, exactMatch: false) vrfSizeMult = vrfCondInfo[:multiplier] vrfMat, vrfLab = getCost(vrfCondInfo[:name], vrfCondInfo[:hvac_material], vrfCondInfo[:multiplier]) vrfCondCost = (vrfMat * regMat + vrfLab * regLab) / 100 # Cost the refrigerant tubing (assume 20' of 0.5" supply and 1.0833" return tubing) # vrfCondSizeTon = (OpenStudio.convert(modVRFCondCapkW.to_f, 'kW', 'kBtu/hr').get)/12.0 refrigPipeMat, refrigPipeLab = getHVACCost("Refrigerant Piping", 'refrig-tubing-large', 20, true) refrigPipingCost = (refrigPipeMat * regMat + refrigPipeLab * regLab) / 100 # Cost insulation for tubing (assume 20' of 1.25" pipe insulation for both the supply and return refrigerant tubing) refrigInsMat, refrigInsLab = getHVACCost('Refrigerant Insulation', 'pipeinsulation', 1.25, true) refrigInsulationCost = (refrigInsMat * regMat + refrigInsLab * regLab) * 2 * 20 / 100 # Cost the wiring vrfWireMat, vrfWireLab = getHVACCost('VRF Wiring', 'wiring', 10, true) vrfWireLength = 20 vrfWiringCost = ((vrfWireMat*regMatElec + vrfWireLab*regLabElec)/100)*vrfWireLength/100 # Cost the Conduit vrfConduitMat, vrfConduitLab = getHVACCost('VRF Wiring Conduit', 'Conduit', nil, true) vrfConduitCost = ((vrfConduitMat*regMatElec + vrfConduitLab*regLabElec)/100)*vrfWireLength # Cost the disconnect vrfDiscMat, vrfDiscLab = getHVACCost('VRF Wiring Disconnect', 'Safety_switch', 60, true) vrfDiscCost = (vrfDiscMat*regMatElec + vrfDiscLab*regLabElec)/100 # Determine the Tubing and wiring between the branch distributors and the condenser unit on the roof. This cost is # included with the condenser cost since this is for the entire building and only depends on the distance between # the height difference between the lowest space served by a VRF system and the roof center height. It will be the # same cost even if there are several condensers because of height restrictions). # # Get the refrigerant tubing cost. Exterior refrigerant tubing is given in 10' lengths of 0.5" supply and 1-1/8" # return tubing. The tubing is assumed to run inside the building so no insulation or all-weather protection is # provided. buildRefrigTubingMat, buildRefrigTubingLab = getHVACCost("VRF Building Refrigerant Tubing", 'refrig-tubing-large', 10, true) # Get distance between lowest floor served by the VRF system and the roof in feet maxHeightDiffFt = OpenStudio.convert(maxHeightDiff, 'm', 'ft').get # Tubing cost divided by ten because tubing costing is provided in 10 ft rolls buildRefrigCost = ((buildRefrigTubingMat * regMat + buildRefrigTubingLab * regLab) / 100) * maxHeightDiffFt / 10.0 # Get the cost of condensate tubing for the whole building. A different height is used than the that for # refrigerant tubing since the condensate line must extend from the height of the roof (where the condenser is) to # the ground floor (if maxHeightDiff does not extend the entire building height) or basement ()if maxHeightDiff # includes a basement). buildCondMat, buildCondLab = getHVACCost('Building Condensate pipe', 'PEX_tubing', 0.5, true) buildCondCost = ((buildCondMat * regMat + buildCondLab * regLab) / 100) * maxHeightDiffFt # Get the wiring cost (note wiring comes in 100 ft lengths) buildWiringMat, buildWiringLab = getHVACCost('VRF Wiring', 'wiring', 10, true) buildWiringCost = ((buildWiringMat * regMatElec + buildWiringLab * regLabElec) / 100) * maxHeightDiffFt / 100.0 # Get the conduit cost buildConduitMat, buildConduitLab = getHVACCost("VRF Building Conduit", 'Conduit', nil, true) buildConduitCost = ((buildConduitMat * regMatElec + buildConduitLab * regLabElec) / 100) * maxHeightDiffFt # Find totals totalVRFCondCost = vrfCondCost * numVRFheight totalVRFPipingCost = (refrigPipingCost + refrigInsulationCost) * numVRFheight * vrfSizeMult + buildRefrigCost + buildCondCost totalVRFWiringCost = (vrfWiringCost + vrfConduitCost + vrfDiscCost) * numVRFheight * vrfSizeMult + buildWiringCost + buildConduitCost totalVRFEquipCost = totalVRFCondCost + totalVRFPipingCost + totalVRFWiringCost # Add to VRF Condenser cost report. I was not sure where to put this since it was really neither a plant unit or a # zonal unit. I guess it supplies several zones so that makes it plant equipment. @costing_report['heating_and_cooling']['plant_equipment'] << { 'type' => 'VRF Zonal System Condenser', 'nom_flr2flr_hght_ft' => 0.0, 'ht_roof_ft' => maxHeightDiffFt.round(1), 'longest_distance_to_ext_ft' => 0.0, 'wiring_and_gas_connections_distance_ft' => (vrfWireLength*numVRFheight*vrfSizeMult + maxHeightDiffFt).round(1), 'equipment_cost' => totalVRFCondCost.round(0), 'wiring_and_gas_connections_cost' => totalVRFWiringCost.round(0), 'pump_cost' => 0.00, 'piping_cost' => totalVRFPipingCost.round(0), 'total_cost' => totalVRFEquipCost.round(0) } return totalVRFEquipCost end |
#determine_ahu_htg_clg_fuel(heat_cap:, cool_cap:, heat_type:, cool_type:) ⇒ Object
This method determines the main heating fuel and cooling type used by an air handling unit (a given model’s air loop). The method also determines the ahu’s supplementary heating type (if any) if the primary heater is a heat pump. All capacities are in KW.
Inputs:
heat_cap: The capacity of heaters in the supply side of the air loop. This is used to determine the main heating
type used by the ahu. They can be the following types:
HP (Heat Pump)
elec (Electricity)
Gas
HW (Hot Water)
CCASHP (Cold Climate Air Source Heat Pump)
cool_cap: The capacity of cooling units in the supply side of the air loop. This is used to determine the main
cooling type used by the ahu. They can be the following types:
DX (Direct Expansion)
CHW (Chilled Water)
Note that HP and CCASHP are not inculded. If the the main heating type is a HP or CCASHP and the main
cooling type is DX then the the main cooling type will be reported as being the same as the main heating
type.
heat_type: This is a hash of counters used to determine what services (electrical lines, hot water pipes, chilled
water pipes, etc.) need to be run from the main mechanical room (where they are assumed to originate) to
the roof of the building (where the ahu's are located). The following tpes are used:
HP: Heat pump (also used for CCASHP, esentially just an electircal line is needed which is always
inculded anyway)
elec: Electricity (an electrical line is needed which is always inculded anyway)
Gas: Gas (a gas line is needed)
HW: Hot water (a hot water line is needed)
cool_type: This is the same as heat_type only for cooling. This is really just used to determine if a chilled water
line is needed since an electrical line is always inculded.
DX: Direct Exchange (also used for HP and CCASHP since only the defaul electrical line is needed)
CHW: Chilled water (a chilled water pipe is required)
Outputs: heat_cool_info: This is a hash that contains the return information which inculdes:
heating_fuel: The primary heating fuel used by the ahu (and supplemental heating fuel if used by a HP
or CCASHP). This is used when searching the 'hvac_vent_ahu' sheet in the costing
spreasheet when costing the ahu.
cooling_type: The primary cooling type used by the ahu. This is used when searching the
'hvac_vent_ahu' sheet in the costing spreadsheet when costing the ahu.
heat_type: See above (only counters adjusted)
cool_type: See above (only counters adjusted)
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 376 def determine_ahu_htg_clg_fuel(heat_cap:, cool_cap:, heat_type:, cool_type:) # Determine the predominant heating and cooling type by looking for the key associated with the largest value in the # heat_cap and cool_cap hashes. For heating it returns HP, elec, Gas, HW or CCASHP and for cooling it returns CHW # or DX. heating_fuel = heat_cap.max_by{|key, value| value}[0] cooling_type = cool_cap.max_by{|key, value| value}[0] # Increase the counter of the associated cooling type by 1 cool_type[cooling_type] += 1 # If a variety of heat pump (regular HP or CCASHP) is present then, for costing, it is assumed to be the primary # heating type for the ahu. if heat_cap['HP'] > 0 || heat_cap['CCASHP'] > 0 # Increase the heat_type counter for heat pump by 1. heat_type['HP'] += 1 # Get the capacities of just the HP and CCASHP. pri_hp_type = { 'HP' => heat_cap['HP'], 'CCASHP' => heat_cap['CCASHP'] } # Use the same technique for heating_fuel and cooling_type to determine which type of heat pump has the largest # capacity. This is used in the off chance that more than one heat pump type is present (I'm not even sure that # is possible in OpenStudio air loops but I include this little bit of edge case handling anyway). hp_type = pri_hp_type.max_by{|key, value| value}[0].to_s heating_fuel = hp_type # It is possible to heat your building with an ASHP and use chilled water to cool your building. I don't know why # you would do that but we can cost the ahu if you do. If the main cooling type is DX (which is highly likely # if you are heating your air loop with an ASHP) then the main cooling type is set to be the main heating type # of the air loop (either regular HP or fancy CCAHP). if cooling_type == 'DX' cooling_type = hp_type end # This determines if supplemental heating is used with your heat pump (very likely in most of Canada if you heat # with a HP). unless (heat_cap['elec'] == 0) && (heat_cap['Gas'] == 0) && (heat_cap['HW'] == 0) # Create a hash of just the fuel heating in the air loop and change the hash key to match what we will look for # in the hvac_vent_ahu sheet in the costing speadsheet hp_supp_cap = { '-e' => heat_cap['elec'], '-g' => heat_cap['Gas'], '-hw' => heat_cap['HW'], } # Look for the key (which is the fuel type) with the largest associated value (which is the capacity). hp_supp = hp_supp_cap.max_by{|key, value| value}[0].to_s # Increase the heat_type count for the associated supplement heat type. This is necessary since if gas heating # is used as supplemental heatnig for a heat pump then a gas line will be required between the mechanical room # and the roof. case hp_supp when '-e' heat_type['elec'] += 1 when '-g' heat_type['Gas'] += 1 when 'hw' heat_type['HW'] += 1 end end # Get the heating fuel by appending the supplementary heating type just determined (if any) to the heat pump type heating_fuel = hp_type heating_fuel += hp_supp unless hp_supp.nil? else # If you do not use a heat pump then increase the heat_type counter for whatever fuel you use to heat the air loop # by 1. heat_type[heating_fuel] += 1 end # Create the hash with the results and return it (I use a hash to return a bunch of results because it seems # cleaner). heat_cool_info = { heating_fuel: heating_fuel, cooling_type: cooling_type, heat_type: heat_type, cool_type: cool_type, } return heat_cool_info end |
#distance(loc1, loc2) ⇒ Object
Enter in [latitude, longitude] for each loc and this method will return the distance.
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 233 def distance(loc1, loc2) rad_per_deg = Math::PI / 180 # PI / 180 rkm = 6371 # Earth radius in kilometers rm = rkm * 1000 # Radius in meters dlat_rad = (loc2[0] - loc1[0]) * rad_per_deg # Delta, converted to rad dlon_rad = (loc2[1] - loc1[1]) * rad_per_deg lat1_rad, lon1_rad = loc1.map { |i| i * rad_per_deg } lat2_rad, lon2_rad = loc2.map { |i| i * rad_per_deg } a = Math.sin(dlat_rad / 2) ** 2 + Math.cos(lat1_rad) * Math.cos(lat2_rad) * Math.sin(dlon_rad / 2) ** 2 c = 2 * Math::atan2(Math::sqrt(a), Math::sqrt(1 - a)) rm * c # Delta in meters end |
#expandProvAbbrev(abbrev) ⇒ Object
This will expand the two letter province abbreviation to a full uppercase province name
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 263 def (abbrev) # Note that the proper abbreviation for Quebec is QC not PQ. However, we've used PQ in openstudio-standards! Hash provAbbrev = {"AB" => "ALBERTA", "BC" => "BRITISH COLUMBIA", "MB" => "MANITOBA", "NB" => "NEW BRUNSWICK", "NL" => "NEWFOUNDLAND AND LABRADOR", "NT" => "NORTHWEST TERRITORIES", "NS" => "NOVA SCOTIA", "NU" => "NUNAVUT", "ON" => "ONTARIO", "PE" => "PRINCE EDWARD ISLAND", "PQ" => "QUEBEC", "SK" => "SASKATCHEWAN", "YT" => "YUKON" } return provAbbrev[abbrev] end |
#floor_vent_dist_cost(hvac_floors:, prototype_creator:, roof_cent:, mech_sizing_info:) ⇒ Object
1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1810 def floor_vent_dist_cost(hvac_floors:, prototype_creator:, roof_cent:, mech_sizing_info:) floor_duct_cost = 0 build_floor_trunk_info = [] mech_table = get_mech_table(mech_size_info: mech_sizing_info, table_name: 'vel_prof') hvac_floors.each do |hvac_floor| next if hvac_floor[:tz_num] < 2 && hvac_floor[:floor_tz][0][:sys_type] == 3 tz_floor_mult = (hvac_floor[:tz_mult].to_f)/(hvac_floor[:tz_num].to_f) floor_trunk_line = get_story_cent_to_edge(building_story: hvac_floor[:story], prototype_creator: prototype_creator, target_cent: roof_cent[:roof_centroid], full_length: true) current_floor_duct_cost, floor_trunk_info = get_floor_trunk_cost(mech_table: mech_table, hvac_floor: hvac_floor, prototype_creator: prototype_creator, floor_trunk_dist_m: floor_trunk_line[:end_point][:line][:dist]) floor_duct_cost += current_floor_duct_cost*tz_floor_mult floor_trunk_info[:Floor] = hvac_floor[:story_name] floor_trunk_info[:Multiplier] = tz_floor_mult build_floor_trunk_info << floor_trunk_info end return floor_duct_cost, build_floor_trunk_info end |
#gas_burner_cost(heating_fuel:, sys_type:, airloop_flow_cfm:, mech_sizing_info:, costed_ahu_info:, vent_tags: [], report_mult: 1.0) ⇒ Object
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 795 def gas_burner_cost(heating_fuel:, sys_type:, airloop_flow_cfm:, mech_sizing_info:, costed_ahu_info:, vent_tags: [], report_mult: 1.0) ahu_airflow_lps = costed_ahu_info[:ahu]["Supply_air"].to_f report_mult_mod = report_mult*(-1.0) = .clone if (sys_type == 3 || sys_type == 6) return 0 mech_table = get_mech_table(mech_size_info: mech_sizing_info, table_name: 'ahu_airflow') coil_sizing_info = mech_table.select{|data| (data['ahu_airflow_range_lps'][0].to_f <= ahu_airflow_lps) && (data['ahu_airflow_range_lps'][1].to_f > ahu_airflow_lps) } if coil_sizing_info.empty? coil_sizing_kW = mech_table.max_by{|data| data['ahu_airflow_range_lps'][1]} else coil_sizing_kW = coil_sizing_info[0] end heating_kw = coil_sizing_kW['htg_coil_sizing_kW'].to_f cooling_kw = coil_sizing_kW['DX_coil_sizing_kW'].to_f heat_mech_eq_mult, heat_cost_info = get_vent_cost_data(equipment_info: {cat_search: 'coils', mech_capacity_kw: heating_kw}) cool_mech_eq_mult, cool_cost_info = get_vent_cost_data(equipment_info: {cat_search: 'coils', mech_capacity_kw: cooling_kw}) heating_coil_cost = heat_mech_eq_mult*get_vent_mat_cost(mat_cost_info: heat_cost_info, vent_tags: , report_mult: (report_mult_mod*heat_mech_eq_mult)) dx_coil_cost = cool_mech_eq_mult*get_vent_mat_cost(mat_cost_info: cool_cost_info, vent_tags: , report_mult: (report_mult_mod*cool_mech_eq_mult)) return heating_coil_cost + dx_coil_cost else if airloop_flow_cfm >= 1000 && airloop_flow_cfm <= 1500 mult, mech_info = get_vent_cost_data(equipment_info: {cat_search: 'DuctFurGasExt', mech_capacity_kw: 88}) return get_vent_mat_cost(mat_cost_info: mech_info, vent_tags: , report_mult: (report_mult_mod*mult))*mult elsif airloop_flow_cfm > 1500 mult, mech_info = get_vent_cost_data(equipment_info: {cat_search: 'DuctFurGasExt', mech_capacity_kw: 132}) return get_vent_mat_cost(mat_cost_info: mech_info, vent_tags: , report_mult: (report_mult_mod*mult))*mult end end return 0.0 end |
#gen_hvac_info_by_floor(hvac_floors:, model:, prototype_creator:, airloop:, sys_type:, hrv_info:) ⇒ Object
1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1720 def gen_hvac_info_by_floor(hvac_floors:, model:, prototype_creator:, airloop:, sys_type:, hrv_info:) airloop.thermalZones.sort.each do |tz| tz.equipment.sort.each do |eq| tz_mult = tz.multiplier.to_f terminal, box_name = get_airloop_terminal_type(eq: eq) next if terminal.nil? if terminal.isMaximumAirFlowRateAutosized.to_bool query = "SELECT Value FROM ComponentSizes WHERE CompName='#{eq.name.to_s.upcase}' AND Description='Design Size Maximum Air Flow Rate'" tz_air = model.sqlFile().get().execAndReturnFirstDouble(query).to_f/tz_mult else tz_air = terminal.maximumAirFlowRate.to_f/tz_mult end tz_cents = prototype_creator.thermal_zone_get_centroid_per_floor(tz) tz_cents.each do |tz_cent| story_floor_area = 0 tz_outdoor_air_m3ps = 0 tz_cent[:spaces].each do |space| # Note that space.floorArea gets the floor area for the space only and does not include a thermal zone multiplier. # Thus the outdoor air flow rate totaled here will be for only one thermal zone and will not include thermal zone multipliers. story_floor_area += space.floorArea.to_f outdoor_air_obj = space.designSpecificationOutdoorAir outdoor_air_obj.is_initialized ? outdoor_air_m3ps = (outdoor_air_obj.get.outdoorAirFlowperFloorArea)*(space.floorArea.to_f) : outdoor_air_m3ps = 0 tz_outdoor_air_m3ps += outdoor_air_m3ps end story_obj = tz_cent[:spaces][0].buildingStory.get floor_area_frac = (story_floor_area/tz.floorArea).round(2) tz_floor_air = floor_area_frac*tz_air (sys_type == 1 || sys_type == 4) ? tz_floor_return = 0 : tz_floor_return = tz_floor_air tz_floor_system = { story_name: tz_cent[:story_name], story: story_obj, sys_name: airloop.nameString, sys_type: sys_type, sys_info: airloop, tz: tz, tz_mult: tz_mult, terminal: terminal, floor_area_frac: floor_area_frac, tz_floor_area: story_floor_area, tz_floor_supp_air_m3ps: tz_floor_air, tz_floor_ret_air_m3ps: tz_floor_return, tz_floor_outdoor_air_m3ps: tz_outdoor_air_m3ps, hrv_info: hrv_info, tz_cent: tz_cent } hvac_floors = add_floor_sys(hvac_floors: hvac_floors, tz_floor_sys: tz_floor_system) end end end return hvac_floors end |
#generate_construction_cost_database_for_all_cities ⇒ Object
67 68 69 70 71 72 73 74 75 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 67 def generate_construction_cost_database_for_all_cities() result = Array.new @costing_database['raw']['locations'].each do |location| province_state = location["province_state"] city = location['city'] result.concat(generate_construction_cost_database_for_city(city, province_state)) end return result end |
#generate_construction_cost_database_for_city(city, province_state) ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 77 def generate_construction_cost_database_for_city(city, province_state) @costing_database['constructions_costs'] = Array.new puts "Costing for: #{province_state},#{city}" @costing_database["raw"]['constructions_opaque'].each do |construction| cost_construction(construction, {"province_state" => province_state, "city" => city}, 'opaque') end @costing_database["raw"]['constructions_glazing'].each do |construction| cost_construction(construction, {"province_state" => province_state, "city" => city}, 'glazing') end puts "#{@costing_database['constructions_costs'].size} Costed Constructions for #{province_state},#{city}." return @costing_database['constructions_costs'] end |
#get_ahu_mult(loop_equip:) ⇒ Object
This method finds ahu with the largest supply air capacity based on the heating and cooling characteristics defined by loop_equip. Loop_equip is a hash which includes: sys_type: the NECB HVAC system type (one of 1, 3, 4, or 6) heating_fuel: The predominant heating fuel cooling_type: The predominant cooling type airloop_flow_lps: The air loop flow rate (L/s) airloop_name: The name of the air loop (used in an error message)
If no air handler is found that meets the above requirements raise an error telling the user that something is wrong. If one or more air handlers are found choose the one with the larges ‘Supply_air’. This defines the largest air handler of the given type. Then divide the air loop air flow by the maximum air flow available. Round up and this number defines how many air handlers are required to meet the load.
In some cases, the air loop flow rate is only a little larger than that available by the largest air handler. For example, an air loop may have a flow rate of 16000 L/s but the largest available air handler is 15000 L/s. Rather than costing two 15000 L/s air handlers it would be cheaper to cost two 8000 L/s air handlers. To do this, the method divides the air_loop_flow_lps by the number of required air handlers. It then looks for air handlers which meet the required characteristics and revised air flow rate. If more than one are found it selects the smallest one available. It then returns this new air handler along with the raw number of air handlens (which may be a fraction) and the maximum number (which will be an integer).
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 568 def get_ahu_mult(loop_equip:) # Look for the largest air handler that matches the system type, heating fuel, and cooling type requirements ahu = @costing_database['raw']['hvac_vent_ahu'].select {|data| data['Sys_type'].to_f.round(0) == loop_equip[:sys_type].to_f.round(0) and data['Htg'].to_s.upcase == loop_equip[:heating_fuel].to_s.upcase and data['Clg'].to_s.upcase == loop_equip[:cooling_type].to_s.upcase }.max_by {|element| element['Supply_air'].to_f} # If none are found something has gone wrong. Tell the user. if ahu.nil? || ahu.empty? raise "Error: no ahu information available for equipment #{loop_equip[:airloop_name]}!" end # I probably don't need to check this but make sure that the air handler has a size larger than 0. if ahu['Supply_air'].to_f <= 0 raise "Error: #{loop_equip[:airloop_name]} has a size of 0 or less. Please check that the correct costing_database.json file is being used or check the costing spreadsheet!" end # Determine the number of air handlers to be the air loop flow rate divided by the maximum air handler size. This # will likely not be a whole number. mult = (loop_equip[:airloop_flow_lps].to_f) / (ahu['Supply_air'].to_f) # Since air handlers only come in integer numbers (half and air handler would not be too useful) round up to the # next whole number (the if statement is for the off chance that the required number ended up being an integer). mult > (mult.to_i).to_f.round(0) ? multiplier = (mult.to_i).to_f.round(0) + 1 : multiplier = mult.round(0) # Get the revised required air flow rate by dividing the air loop air flow by the number of air handlers rev_air_flow = loop_equip[:airloop_flow_lps].to_f / multiplier # Find air handlers that can meet that air flow and choose the smallest one that meets the requirement. rev_ahu = @costing_database['raw']['hvac_vent_ahu'].select {|data| data['Sys_type'].to_f.round(0) == loop_equip[:sys_type].to_f.round(0) and data['Htg'].to_s.upcase == loop_equip[:heating_fuel].to_s.upcase and data['Clg'].to_s.upcase == loop_equip[:cooling_type].to_s.upcase and data['Supply_air'].to_f >= rev_air_flow }.min_by{|info| info['Supply_air'].to_f} # If none are found something weird is happening so keep the one you already found. if rev_ahu.nil? || rev_ahu.empty? # Something weird happened, keep the ahu you found before. else ahu = rev_ahu end return ahu, multiplier, rev_air_flow end |
#get_airloop_terminal_type(eq:) ⇒ Object
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1075 def get_airloop_terminal_type(eq:) case eq.iddObject.name when /OS:AirTerminal:SingleDuct:ConstantVolume:Reheat/ terminal = eq.to_AirTerminalSingleDuctConstantVolumeReheat.get box_name = 'CVMixingBoxes' when /OS:AirTerminal:SingleDuct:VAV:NoReheat/ terminal = eq.to_AirTerminalSingleDuctVavNoReheat.get box_name = 'VAVFanMixingBoxesClg' when /OS:AirTerminal:SingleDuct:VAV:Reheat/ terminal = eq.to_AirTerminalSingleDuctVAVReheat.get box_name = 'VAVFanMixingBoxesHtg' when /OS:AirTerminal:SingleDuct:ConstantVolume:NoReheat/ terminal = eq.to_AirTerminalSingleDuctConstantVolumeNoReheat.get box_nam = nil else terminal = nil box_name = nil end return terminal, box_name end |
#get_closest_cost_location(lat, long) ⇒ Object
249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 249 def get_closest_cost_location(lat, long) dist = 1000000000000000000000.0 closest_loc = nil # province_state city latitude longitude source @costing_database['raw']['locations'].each do |location| if distance([lat, long], [location['latitude'].to_f, location['longitude'].to_f]) < dist closest_loc = location dist = distance([lat, long], [location['latitude'].to_f, location['longitude'].to_f]) end end return closest_loc end |
#get_comp_cost(cost_info:, vent_tags: [], report_mult: 1.0) ⇒ Object
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1282 def get_comp_cost(cost_info:, vent_tags: [], report_mult: 1.0) = .clone cost = 0 cost_info.each do |comp| comp_info = nil if comp[:unit].to_s == 'none' comp_info = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == comp[:mat].to_s.upcase and data['Size'].to_f.round(2) == comp[:size].to_f.round(2) }.first elsif comp[:size].to_f == 0 comp_info = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == comp[:mat].to_s.upcase and data['unit'].to_s.upcase == comp[:unit].to_s.upcase }.first else comp_info = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == comp[:mat].to_s.upcase and data['Size'].to_f.round(2) == comp[:size].to_f.round(2) and data['unit'].to_s.upcase == comp[:unit].to_s.upcase }.first end if comp_info.nil? puts("No data found for #{comp}!") raise end # report_mult included for cost list output. cost += get_vent_mat_cost(mat_cost_info: comp_info, vent_tags: , report_mult: (comp[:mult].to_f*report_mult))*(comp[:mult].to_f) end return cost end |
#get_cost_info(mat:, size: nil, unit: nil) ⇒ Object
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 |
# File 'lib/openstudio-standards/btap/costing/shw_costing.rb', line 675 def get_cost_info(mat:, size: nil, unit: nil) comp_info = nil if unit.nil? comp_info = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == mat.to_s.upcase and data['Size'].to_f.round(2) == size.to_f.round(2) }.first elsif size.nil? comp_info = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == mat.to_s.upcase and data['unit'].to_s.upcase == unit.to_s.upcase }.first elsif size.nil? && unit.nil? comp_info = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == mat.to_s.upcase }.first else comp_info = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == mat.to_s.upcase and data['Size'].to_f.round(2) == size.to_f.round(2) and data['unit'].to_s.upcase == unit.to_s.upcase }.first end if comp_info.nil? puts("No data found for material: #{mat}, size: #{size}, with unit: #{unit}") raise end return comp_info end |
#get_duct_cost(cost_info:) ⇒ Object
1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1904 def get_duct_cost(cost_info:) comp_info = nil comp_info_all = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == cost_info[:mat].to_s.upcase and data['Size'].to_f.round(1) >= cost_info[:size].to_f.round(1) and data['unit'].to_s.upcase == cost_info[:unit].to_s.upcase } if comp_info_all.nil? || comp_info_all.empty? max_size_info = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == cost_info[:mat].to_s.upcase } if max_size_info.nil? puts("No data found for #{cost_info}!") raise end comp_info = max_size_info.max_by {|element| element['Size'].to_f} elsif comp_info_all.size == 1 comp_info = comp_info_all[0] else comp_info = comp_info_all.min_by{|data| data['Size'].to_f} end cost = get_vent_mat_cost(mat_cost_info: comp_info)*cost_info[:mult].to_f return cost, comp_info end |
#get_fan_cap(fan:, model:) ⇒ Object
2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 2104 def get_fan_cap(fan:, model:) fan_type = fan.iddObjectType.valueName.to_s case fan_type when /OS_Fan_VariableVolume/ fan_obj = fan.to_FanVariableVolume.get if fan_obj.isMaximumFlowRateAutosized fan_cap_m3ps = fan_obj.autosizedMaximumFlowRate.to_f else fan_cap_m3ps = fan_obj.maximumFlowRate.to_f end when /OS_Fan_ConstantVolume/ fan_obj = fan.to_FanConstantVolume.get if fan_obj.isMaximumFlowRateAutosized fan_cap_m3ps = fan_obj.autosizedMaximumFlowRate.to_f else fan_cap_m3ps = fan_obj.maximumFlowRate.to_f end else fan_cap_m3ps = 0 end return fan_cap_m3ps end |
#get_fixture_type_id(fixture_info:, sheet_name:, row_name_1:, row_name_2:, row_name_3:, column_search:) ⇒ Object
339 340 341 342 343 344 345 346 347 348 349 350 351 |
# File 'lib/openstudio-standards/btap/costing/daylighting_sensor_control_costing.rb', line 339 def get_fixture_type_id(fixture_info:, sheet_name:, row_name_1:, row_name_2:, row_name_3:, column_search:) fixture_type = nil fixture_type = @costing_database['raw'][sheet_name].select { |data| data[row_name_1].to_s.upcase == fixture_info[:row_id_1].to_s.upcase and data[row_name_2].to_s.upcase == fixture_info[:row_id_2].to_s.upcase and data[row_name_3].to_s.upcase == fixture_info[:row_id_3].to_s.upcase }.first if fixture_type.nil? puts("No data found for #{fixture_type}!") raise end return fixture_type[column_search] end |
#get_floor_trunk_cost(mech_table:, hvac_floor:, prototype_creator:, floor_trunk_dist_m:, fric_allow: 1) ⇒ Object
1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1827 def get_floor_trunk_cost(mech_table:, hvac_floor:, prototype_creator:, floor_trunk_dist_m:, fric_allow: 1) floor_trunk_info = { Floor: '', Predominant_space_type: 0, SupplyDuctSize_in: 0, SupplyDuctLength_m: 0, ReturnDuctSize_in: 0, ReturnDuctLength_m: 0, TotalDuctCost: 0, Multiplier: 1 } floor_trunk_cost = 0 duct_comp_search = [] floor_trunk_dist = (OpenStudio.convert(floor_trunk_dist_m, 'm', 'ft').get) space_type = get_predominant_floor_space_type_area(hvac_floor: hvac_floor, prototype_creator: prototype_creator) floor_trunk_info[:Predominant_space_type] = space_type[:space_type] loor_vel_fpm = nil mech_table.each do |vel_prof| spc_type_name = nil spc_type_name = vel_prof['space_types'].select {|spc_type| spc_type.to_s.upcase == space_type[:space_type].to_s.upcase }.first floor_vel_fpm = vel_prof['vel_fpm'].to_f unless spc_type_name.nil? end floor_vel_fpm = mech_table[mech_table.size - 1]['vel_fpm'].to_f if floor_vel_fpm.nil? supply_flow_cfm = (OpenStudio.convert(hvac_floor[:supply_air_m3ps], 'm^3/s', 'cfm').get) sup_cross_in2 = ((supply_flow_cfm*fric_allow)/floor_vel_fpm)*144 sup_dia_in = 2*Math.sqrt(sup_cross_in2/Math::PI) duct_cost_search = { mat: 'Ductwork-S', unit: 'L.F.', size: sup_dia_in, mult: floor_trunk_dist } duct_cost, comp_info = get_duct_cost(cost_info: duct_cost_search) floor_trunk_info[:SupplyDuctSize_in] = sup_dia_in.round(2) floor_trunk_info[:SupplyDuctLength_m] = floor_trunk_dist_m.round(1) floor_trunk_cost += duct_cost sup_area_sqrft = (comp_info['Size'].to_f/12)*Math::PI*floor_trunk_dist duct_comp_search << { mat: 'Ductinsulation', unit: 'ft2', size: 1.5, mult: sup_area_sqrft } if hvac_floor[:return_air_m3ps] == hvac_floor[:supply_air_m3ps] floor_trunk_cost += duct_cost duct_comp_search[0][:mult] = sup_area_sqrft*2 floor_trunk_info[:ReturnDuctSize_in] = floor_trunk_info[:SupplyDuctSize_in] floor_trunk_info[:ReturnDuctLength_m] = floor_trunk_info[:SupplyDuctLength_m] elsif hvac_floor[:return_air_m3ps].to_f > 0 return_flow_cfm = (OpenStudio.convert(hvac_floor[:return_air_m3ps], 'm^3/s', 'cfm').get) ret_cross_in2 = ((return_flow_cfm*fric_allow)/floor_vel_fpm)*144 ret_dia_in = 2*Math.sqrt(ret_cross_in2/Math::PI) duct_cost_search = { mat: 'Ductwork-S', unit: 'L.F.', size: ret_dia_in, mult: floor_trunk_dist } duct_cost, comp_info = get_duct_cost(cost_info: duct_cost_search) floor_trunk_cost += duct_cost ret_area_sqrft = (comp_info['Size'].to_f/12)*Math::PI*floor_trunk_dist duct_comp_search << { mat: 'Ductinsulation', unit: 'ft2', size: 1.5, mult: ret_area_sqrft } floor_trunk_info[:ReturnDuctSize_in] = ret_dia_in.round(2) floor_trunk_info[:ReturnDuctLength_m] = floor_trunk_dist_m.round(1) end floor_trunk_cost += get_comp_cost(cost_info: duct_comp_search) floor_trunk_info[:TotalDuctCost] = floor_trunk_cost.round(2) return floor_trunk_cost, floor_trunk_info end |
#get_hrv_floor_trunk_cost(mech_table:, air_system:, floor_trunk_dist_m:) ⇒ Object
2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 2318 def get_hrv_floor_trunk_cost(mech_table:, air_system:, floor_trunk_dist_m:) return 0 if air_system[:sys_hrv_flow_m3ps].round(2) == 0.0 hrv_trunk_cost = 0 duct_comp_search = [] floor_trunk_dist = (OpenStudio.convert(floor_trunk_dist_m, 'm', 'ft').get) trunk_duct_sz = mech_table.select {|sz_range| air_system[:sys_hrv_flow_m3ps] > sz_range['max_flow_range_m3pers'][0] && air_system[:sys_hrv_flow_m3ps] <= sz_range['max_flow_range_m3pers'][1] } trunk_duct_sz << mech_table[mech_table.size-1] if trunk_duct_sz.empty? trunk_dia_in = (trunk_duct_sz[0]['duct_dia_inch']) duct_comp_search << { mat: 'Ductwork-S', unit: 'L.F.', size: trunk_dia_in, mult: floor_trunk_dist } trunk_area_sqrft = (trunk_dia_in.to_f/12)*Math::PI*floor_trunk_dist duct_comp_search << { mat: 'Ductinsulation', unit: 'ft2', size: 1.5, mult: trunk_area_sqrft } hrv_trunk_cost += get_comp_cost(cost_info: duct_comp_search) hrv_trunk_cost_rep = { duct_length_m: floor_trunk_dist_m.round(1), dia_in: trunk_dia_in.round(2), cost: hrv_trunk_cost.round(2) } return hrv_trunk_cost, hrv_trunk_cost_rep end |
#get_hrv_info(airloop:, model:) ⇒ Object
2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 2071 def get_hrv_info(airloop:, model:) hrv_present = false hrv_data = nil hrv_design_flow_m3ps = 0 airloop.oaComponents.each do |oaComp| if oaComp.iddObjectType.valueName.to_s == 'OS_HeatExchanger_AirToAir_SensibleAndLatent' hrv_present = true hrv_data = oaComp.to_HeatExchangerAirToAirSensibleAndLatent.get if hrv_data.isNominalSupplyAirFlowRateAutosized hrv_design_flow_m3ps = hrv_data.autosizedNominalSupplyAirFlowRate.to_f else hrv_design_flow_m3ps = hrv_data.nominalSupplyAirFlowRate.to_f end end end return { hrv_present: hrv_present, hrv_data: hrv_data, hrv_size_m3ps: hrv_design_flow_m3ps, supply_cap_m3ps: 0, return_cap_m3ps: 0 } unless hrv_present airloop.supplyFan.is_initialized ? supply_fan_cap = get_fan_cap(fan: airloop.supplyFan.get, model: model) : supply_fan_cap = 0 airloop.returnFan.is_initialized ? return_fan_cap = get_fan_cap(fan: airloop.returnFan.get, model: model) : return_fan_cap = 0 return { hrv_present: hrv_present, hrv_data: hrv_data, hrv_size_m3ps: hrv_design_flow_m3ps, supply_cap_m3ps: supply_fan_cap, return_cap_m3ps: return_fan_cap } end |
#get_HVAC_multiplier(materialLookup, materialSize) ⇒ Object
This method determines how many pieces of equipment are required to satisfy the required size if 1 piece is not enough. It takes in: materialLookup(String): The name to search for in the ‘Material’ column of the materials_hvac sheet of the costing
spreadsheet.
materialSize(Float): The size to search for in the ‘Size’ column of teh materials_hvac sheet of the costing
spreadsheet.
It returns: multiplier(Float): Number of materialLookup with the largest size required to meet the materialSize.
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 1004 def get_HVAC_multiplier(materialLookup, materialSize) multiplier = 1.0 materials_hvac = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == materialLookup.to_s.upcase } if materials_hvac.nil? puts("Error: no hvac information available for equipment #{materialLookup}!") raise elsif materials_hvac.empty? puts("Error: no hvac information available for equipment #{materialLookup}!") raise end materials_hvac.length == 1 ? max_size = materials_hvac[0] : max_size = materials_hvac.max_by {|d| d['Size'].to_f} if max_size['Size'].to_f <= 0 puts("Error: #{materialLookup} has a size of 0 or less. Please check that the correct costing_database.json file is being used or check the costing spreadsheet!") raise end mult = materialSize.to_f / (max_size['Size'].to_f) multiplier = (mult.to_i).to_f.round(0) + 1 # Use next largest integer for multiplier return multiplier.to_f end |
#get_line_eq(a:, b:, tol: 8) ⇒ Object
1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1515 def get_line_eq(a:, b:, tol: 8) if a[0].round(tol) == b[0].round(tol) and a[1].round(tol) == b[1].round(tol) return { slope: 0, int: 0, inf: true } elsif a[0].round(tol) == b[0].round(tol) return { slope: a[0].round(tol), int: 1, inf: true } else slope = (b[1].round(tol) - a[1].round(tol))/(b[0].round(tol) - a[0].round(tol)) int = a[1].round(tol) - (slope*a[0].round(tol)) end return { slope: slope, int: int, inf: false } end |
#get_lowest_space(spaces:) ⇒ Object
1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1666 def get_lowest_space(spaces:) cents = [] spaces.each do |space| test = space['space'] origin = [space['space'].xOrigin.to_f, space['space'].yOrigin.to_f, space['space'].zOrigin.to_f] space['space'].surfaces.each do |surface| if surface.surfaceType.to_s.upcase == 'ROOFCEILING' cents <<{ space: space['space'], roof_cent: [surface.centroid.x.to_f + origin[0], surface.centroid.y.to_f + origin[1], surface.centroid.z.to_f + origin[2]] } end end end min_space = cents.min_by{|cent| cent[:roof_cent][2]} return min_space end |
#get_mech_costing(mech_name:, size:, terminal:, use_mult: true, vent_tags: [], report_mult: 1.0) ⇒ Object
This method gets the cost of a piece of equipment. I takes the following in: mech_name: The category or type of equipment that is being searched for in the ‘Material’ column of the ‘materials_hvac’ sheet of the costing spreadsheet. size: The size of the piece of equipment being searched for. terminal: The openstudio object being costed (used to let the user know if there is an issue finding costing info). mult: A switch which is used to determine if you want to cost multiple pieces of equipment. If it is set to true (the default) then if a piece of equipment is too large to be costed, then multiple smaller pieces of equipment will be costed. If it is set to false, then only 1 of the largest piece of equipment will be costed.
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1180 def get_mech_costing(mech_name:, size:, terminal:, use_mult: true, vent_tags: [], report_mult: 1.0) = .clone # Turn the input into something that the get_vent_cost_data method can use. mech_info = { cat_search: mech_name, mech_capacity_kw: size, supply_component: terminal } # Get the costing information and multiplier (if the piece of equipment is too large) for the equipment. mech_mult, cost_info = get_vent_cost_data(equipment_info: mech_info) # Use only one piece of equipment if use_mult is set to false mech_mult = 1.0 unless use_mult # Return the total cost for the piece of equipment. return get_vent_mat_cost(mat_cost_info: cost_info, vent_tags: , report_mult: (mech_mult*report_mult))*mech_mult end |
#get_mech_table(mech_size_info:, table_name:) ⇒ Object
1314 1315 1316 1317 1318 1319 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1314 def get_mech_table(mech_size_info:, table_name:) table = mech_size_info.select {|hash| hash['component'].to_s.upcase == table_name.to_s.upcase }.first return table['table'] end |
#get_orient(p:, q:, r:, tol: 8) ⇒ Object
1651 1652 1653 1654 1655 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1651 def get_orient(p:, q:, r:, tol: 8) orient = (q[1].round(tol) - p[1].round(tol))*(r[0].round(tol) - q[0].round(tol)) - (q[0].round(tol) - p[0].round(tol))*(r[1].round(tol) - q[1].round(tol)) return 0 if orient == 0 orient > 0 ? (return 1) : (return 2) end |
#get_predominant_floor_space_type_area(hvac_floor:, prototype_creator:) ⇒ Object
1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1929 def get_predominant_floor_space_type_area(hvac_floor:, prototype_creator:) spaces = hvac_floor[:story].spaces space_list = [] space_mod = OpenstudioStandards::Space spaces.sort.each do |space| if (space_mod.space_cooled?(space) || space_mod.space_heated?(space)) && !space_mod.space_plenum?(space) space_type = space.spaceType.get.nameString[15..-1] if space_list.empty? space_list << { space_type: space_type, floor_area: space.floorArea } else new_space = nil space_list.each do |spc_lst| if space_type.upcase == spc_lst[:space_type] spc_lst[:floor_area] += space.floorArea else new_space = { space_type: space_type, floor_area: space.floorArea } end end unless new_space.nil? space_list << new_space end end end end max_space_type = space_list.max_by {|spc_lst| spc_lst[:floor_area]} return max_space_type end |
#get_regional_cost_factors(provinceState, city, material) ⇒ Object
167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 167 def get_regional_cost_factors(provinceState, city, material) @costing_database['localization_factors'].select { |code| code['province_state'] == provinceState && code['city'] == city }.each do |code| prefix_id = material['id'][0..1] prefix_stored = code['code_prefix'] if prefix_id == prefix_stored return code['material'], code['installation'], code['total'] end end error = [material, "Could not find regional adjustment factor for material used in #{city}, #{provinceState}."] @costing_database['db_errors'] << error unless @costing_database['db_errors'].include?(error) return 100.0, 100.0, 100.0 end |
#get_shw_dist_cost(space:, roof_cent:) ⇒ Object
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 |
# File 'lib/openstudio-standards/btap/costing/shw_costing.rb', line 485 def get_shw_dist_cost(space:, roof_cent:) shw_dist_search = [] space_cent = get_space_floor_centroid(space: space) dist_m = (roof_cent[:roof_centroid][0] - space_cent[:centroid][0]).abs + (roof_cent[:roof_centroid][1] - space_cent[:centroid][1]).abs dist_ft = OpenStudio.convert(dist_m, 'm', 'ft').get shw_dist_search << { mat: 'CopperPipe', unit: 'L.F.', size: 0.75, mult: dist_ft } total_comp_cost = get_comp_cost(cost_info: shw_dist_search) return { length_m: dist_m, cost: total_comp_cost } end |
#get_SHW_vol_multiplier(materialLookup:, materialSize:, materialVol:) ⇒ Object
This method is a copy of get_HVAC_multiplier but searches for volume in the ‘Fuel’ column of the materials_hvac sheet. The ‘Fuel’ column is where tank volume information is kept for electric and oil SHW tanks.
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 |
# File 'lib/openstudio-standards/btap/costing/shw_costing.rb', line 655 def get_SHW_vol_multiplier(materialLookup:, materialSize:, materialVol:) multiplier = 1.0 materials_hvac = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == materialLookup.to_s.upcase && data['Size'].to_f >= materialSize } if materials_hvac.nil? || materials_hvac.empty? puts("Error: no hvac information available for equipment #{materialLookup}!") raise end materials_hvac.length == 1 ? max_size = materials_hvac[0] : max_size = materials_hvac.max_by {|d| d['Fuel'].to_f} if max_size['Fuel'].to_f <= 0 puts("Error: #{materialLookup} has a volume of 0 or less. Please check that the correct costing_database.json file is being used or check the costing spreadsheet!") raise end mult = materialVol.to_f / (max_size['Fuel'].to_f) multiplier = (mult.to_i).to_f + 1.0 # Use next largest integer for multiplier return multiplier.to_f, max_size['Fuel'].to_f end |
#get_space_floor_centroid(space:) ⇒ Object
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 |
# File 'lib/openstudio-standards/btap/costing/shw_costing.rb', line 455 def get_space_floor_centroid(space:) # Determine the bottom surface of the space and calculate it's centroid. # Get the coordinates of the origin for the space (the coordinates of points in the space are relative to this). xOrigin = space.xOrigin yOrigin = space.yOrigin zOrigin = space.zOrigin # Get the surfaces for the space. space_surfaces = space.surfaces # Find the floor (aka the surface with the lowest centroid). min_surf = space_surfaces.min_by{|sp_surface| (sp_surface.centroid.z.to_f)} # The following is added to determine the overall floor centroid because some spaces have floors composed of more than one surface. floor_centroid = [0, 0, 0] space_surfaces.each do |sp_surface| if min_surf.centroid.z.to_f.round(8) == sp_surface.centroid.z.to_f.round(8) floor_centroid[0] = floor_centroid[0] + sp_surface.centroid.x.to_f*sp_surface.grossArea.to_f floor_centroid[1] = floor_centroid[1] + sp_surface.centroid.y.to_f*sp_surface.grossArea.to_f floor_centroid[2] = floor_centroid[2] + sp_surface.grossArea end end # Determine the floor centroid floor_centroid[0] = floor_centroid[0]/floor_centroid[2] floor_centroid[1] = floor_centroid[1]/floor_centroid[2] return { centroid: [floor_centroid[0] + xOrigin, floor_centroid[1] + yOrigin, min_surf.centroid.z.to_f + zOrigin], floor_area_m2: floor_centroid[2] } end |
#get_story_cent_to_edge(building_story:, prototype_creator:, target_cent:, tol: 8, full_length: false) ⇒ Object
This method finds the centroid of the ceiling line on a given story furthest from the specified point. It only takes into account ceilings that above conditioned spaces that are not plenums. A line can be defined between the supplied point (we’ll call it point O) and the ceiling line centroid furthest from that point(we’ll call it point A). We will call this line AO. If the full_length input argument is set to true the method will also return the point where line AO intercepts the ceiling line on the other side of the building. Note that the method only looks at x and y coordinates and ignores the z coordinate of the point you pass it. The method assumes that the ceilings of all of the spaces on the floor you pass it are flat so generally ignores their z components as well. This was done to avoid further complicating things with 3D geometry. If the ceilings of all of the spaces in the building story you pass the method are not flat it will still work but pretend as though the ceilings are flat by ignoring the z coordinate.
The method works by going through each space in the supplied building story and finding the ones which are conditioned (either heated or cooled) and which are not considered plenums. It then goes through the surfaces of the conditioned spaces and finds the ones which have an OpenStudio SurfaceType of ‘RoofCeiling’. It then goes through each point on that surface and makes lines going from the current point (CP) to the previous point (PP). It calculates the centroid (LC) of the line formed between PP and CP by averaging each coordinate of PP and CP. It then determines which LC is furthest from the supplied point (point O) and this becomes point A. Note that point A is not necessarily on the outside of a building since no checks are made on where line P lies in the building (only that it is on a RoofCeiling above a conditioned space that is not a plenum). For example in the LargeOffice building archetype point P generally lies on one of the short edges of the trapezoids forming the perimeter spaces. This is if this reference point (O) is the center of the building.
The inputs arguments are are: building_story: OpenStudio BuildingStory object. A building story defined in OpenStudio. prototype_creator: The Openstudio-standards object, containing all of the methods etc. in the nrcan branch of
Openstudio-standards.
target_cent: Array. The point you supply from which you want to find the furthest ceiling line centroid (point O
in the description above). This point should be a one dimensional array containing at least two
elements target_cent[0] = x, target_cent[1] = y. The array can have more points but they will be
ignored. This point should be inside the building.
tol: Float. The tolerence used by the method when rounding geometry (default is 8 digits after decimal). full_length: Boolean true/false
The switch which tells the method whether or not it should find, and supply, the point where line AO (
as defined above) intercepts the other side of the building. It is defaulted to false, meaning it
will only return points A and O. If it set to 'true' it will return the point where line AO
intercepts the other side of the building. It does this by going through all of the ceiling lines
in the specified building story and determining if any intercept line AO (let us call each intercepts
point C). It then runs through each intercept (point C) and determines which C makes line AOC the
longest.
The output is the following hash.
start_point: Hash. A hash which defines point A and provides a bunch of other information (see below),
mid_point: Hash. This is a hash containing the array defining the point you passed the method in the first
place.,
end_point: Hash. If full_length was set to true then this defines point C and provides a bunch of other
information (see below). If full_length was not set to false or undefined then this is set to nil.
The structure of the hashes start_point and end_point are identical. I will only define the hash start_point below noting differences for end_point.
start_point: {
space: OpenStudio Space object. The space that contains point A (or point C if in the end_point hash).,
surface: OpenStudio Surface object. The surface in space that contains point A (should have a RoofCeiling
SpaceType). In the case of the end_point hash this is the surface that contains point C.,
verts: Two dimmensional array. The points defining ':surface'. These points are in the building coordinate
system (rather than the space coordinate system). These points are ordered clockwise when viewed with the
surface normal pointed towards the viewer. The array would be structured as follows:
[1st point, 2nd point, ..., last point]. Each point is an array as follows: [x coord, y coord, z coord].
The points are in meters.,
line: Hash. A hash defining the line containing point A (point C if this is in the 'end_point' hash). See
definition below.
‘line’ has the identical structure in the start_point and end_point hashes. I will define it once but note any differences for when it is containing in the start_point and end_point hashes.
line:
verta: Array. The end point of the line containing point A (when in the start_point hash) or point C (when in
the end_point hash). It is formed as [x, y, z]. It is in the building coordinate system, in meters.
ventb: Array. The start point of the line containing point A (when in the start_point hash) or point C (when in
the end_point hash). It is formed as [x, y, z]. It is in the building coordinate system, in meters.
int: Array. If this is in the start_point hash then this is the centre of the line from vertb to verta. If this
is in the end_point hash then this is the intercept of the line AO with the line starting with vertb and
ending with verta. It is formed as [x, y, z]. It is in the building coordinate system, in meters. If in
the start_point hash then the z coordinate is the average of the z coordinates of verta and vertb. If in
the end_point hash then the z coordinate is calculated by first determining of the distance of the line
between vertb and verta when only using their x and y coordinates (we will call it the xy_dist). Then the
distance from just the x and y coordinates of ventb to the x and y coordinates (the only ones provided) of
point C is determined (we will call it the c_dist). The fraction c_dist/xy_dist is then found and added to
the z coordinate of ventb thus providing the z coordinate of point C.
i: Integer. The index of verta in the verts array.
ip: Integer. The index of vertb in the verts array.
dist: If in the start_point hash this is the distance between point A and point O using only the x and y
coordinates of the respective points. If in the end_point hash this is the distance between point A and
point C using only the x and y coordinates of the respective points. In meters.
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1410 def get_story_cent_to_edge(building_story:, prototype_creator:, target_cent:, tol: 8, full_length: false) ceiling_start = [] space_mod = OpenstudioStandards::Space building_story.spaces.sort.each do |space| if (space_mod.space_heated?(space) || space_mod.space_cooled?(space)) && !space_mod.space_plenum?(space) origin = [space.xOrigin.to_f, space.yOrigin.to_f, space.zOrigin.to_f] space.surfaces.each do |surface| if surface.surfaceType.to_s.upcase == 'ROOFCEILING' verts = surface.vertices dists = [] surf_verts = [] for index in 1..verts.length index == verts.length ? i = 0 : i = index i == 0 ? ip = verts.length - 1 : ip = i - 1 verta = [verts[i].x.to_f + origin[0], verts[i].y.to_f + origin[1], verts[i].z.to_f + origin[2]] vertb = [verts[ip].x.to_f + origin[0], verts[ip].y.to_f + origin[1], verts[ip].z.to_f + origin[2]] cent = [(verta[0] + vertb[0])/2.0 , (verta[1] + vertb[1])/2.0, (verta[2] + vertb[2])/2.0] dist = Math.sqrt((target_cent[0].to_f - cent[0])**2 + (target_cent[1].to_f - cent[1])**2) dists << { verta: verta, vertb: vertb, int: cent, i: i, ip: ip, dist: dist } surf_verts << vertb end max_dist = dists.max_by{|dist_el| dist_el[:dist].to_f} ceiling_start << { space: space, surface: surface, verts: surf_verts, line: max_dist } end end end end return nil if ceiling_start.empty? furthest_line = ceiling_start.max_by{|wall| wall[:line][:dist].to_f} return {start_point: furthest_line, mid_point: target_cent, end_point: nil} unless full_length x_dist_ref = (furthest_line[:line][:int][0].round(tol) - target_cent[0].round(tol)) x_dist_ref == 1 if x_dist_ref == 0 y_dist_ref = (furthest_line[:line][:int][1].round(tol) - target_cent[1].round(tol)) y_dist_ref == 1 if y_dist_ref == 0 x_side_ref = x_dist_ref/x_dist_ref.abs y_side_ref = y_dist_ref/y_dist_ref.abs linea_eq = get_line_eq(a: target_cent, b: furthest_line[:line][:int], tol: tol) ints = [] ceiling_start.each do |side| verts = side[:verts] for index in 1..(verts.length) index == verts.length ? i = 0 : i = index i == 0 ? ip = verts.length-1 : ip = i - 1 lineb = [verts[i], verts[ip]] int = line_int(line_seg: lineb, line: linea_eq, tol: tol) next if int.nil? x_dist = (int[0].round(tol) - target_cent[0].round(tol)) x_dist = 1 if x_dist == 0 y_dist = (int[1].round(tol) - target_cent[1].round(tol)) y_dist = 1 if y_dist == 0 x_side = x_dist/x_dist.abs y_side = y_dist/y_dist.abs next if x_side == x_side_ref && y_side == y_side_ref ceil_dist = Math.sqrt((furthest_line[:line][:int][0] - int[0])**2 + (furthest_line[:line][:int][1] - int[1])**2) int_dist = Math.sqrt((int[0] - verts[ip][0])**2 + (int[1] - verts[ip][1])**2) line_dist = Math.sqrt((verts[i][0] - verts[ip][0])**2 + (verts[i][1] - verts[ip][1])**2) z_coord = verts[ip][2] + ((verts[i][2] - verts[ip][2])*int_dist/line_dist) ints << { ceiling_info: side, line: lineb, int: [int[0], int[1], z_coord], i: i, ip: ip, dist: ceil_dist } end end return nil if ints.empty? end_wall = ints.max_by{|wall| wall[:dist].to_f} return { start_point: furthest_line, mid_point: target_cent, end_point: { space: end_wall[:ceiling_info][:space], surface: end_wall[:ceiling_info][:surface], verts: end_wall[:ceiling_info][:verts], line: { verta: end_wall[:line][0], vertb: end_wall[:line][1], int: end_wall[:int], i: end_wall[:i], ip: end_wall[:ip], dist: end_wall[:dist] }, } } end |
#get_vent_cost_data(equipment_info:) ⇒ Object
This method collects information related a piece of equipment from the ‘materials_hvac’ sheet in the costing spreadsheet. This information is then used to determine the cost of a piece of equipment. It takes in the equipment_info hash. This hash contains the following information: equipment_info = { cat_search: This is the category or type of mechanical equipment that is being costed. It is used to match items in the ‘Material’ column of the ‘materials_hvac’ sheet. mech_capacity_kw: This is the capacity of the piece of mechanical equipment being costed. Although it has kw in the name this is not always the case. It is compared against information in the ‘Size’ column of the ‘materials_hvac’ sheet. supply_comp: This is the OpenStudio object being costed. If there is an error this is used to tell which piece of the model had the issue.
The method tries to find the smallest piece of equipment that matches the equipment type and that can satisfy the capacity requirements. If it cannot find one then it then it assumes that the largest matching piece of equipment cannot meet the required capacity and tries to determine how many would be need to meet the required capacity. It then returns the information it found in the costing spreadsheet and the number of piece of equipment would be required (if applicable)
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 776 def get_vent_cost_data(equipment_info:) # Assume one piece of equipment is enough. multiplier = 1.0 # Find the smallest piece of equipment in 'materials_hvac' sheet that matches the equipment type and meets the # capacity requirement. heat_cool_cost_data = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == equipment_info[:cat_search].to_s.upcase and data['Size'].to_f.round(8) >= equipment_info[:mech_capacity_kw].to_f }.min_by{|heat_cool| heat_cool[:mech_capcity_kw].to_f} # If it cannot find any then assume the largest piece of equipment in the costing spreadsheet is too small and # figure out how many of a smaller piece of equipment are required and what the smaller piece of equipment would be. if heat_cool_cost_data.nil? || heat_cool_cost_data.empty? heat_cool_cost_data, multiplier = get_vent_system_mult(loop_equip: equipment_info) end # Return the number of equipment necessary and the informatino required to find the piece of equipment in the # costing database. return multiplier, heat_cool_cost_data end |
#get_vent_mat_cost(mat_cost_info:, vent_tags: [], report_mult: 1.0) ⇒ Object
This method costs a piece of mechanical equipment. The mat_cost_info is a hash that contains the information for the piece of equipment from the ‘materials_hvac’ sheet of the costing spreadsheet. It contains: material_id: An index sometimes used to refer to find a specific piece of equipment material: The type of equipment. description: A description of the piece of equipment. Size: The size of the piece of equipment (see units for the unit this is in). Fuel: Sometimes this is indicates the fuel type, sometimes it is an additional size criteria. source: The source to look for the costing information. This can be placeholder or custom. id: The unique id of the costing information associated with this piece of equipment. unit: The units of the given Size (can be one of many units). province_state: For custom costing data, this is the province or state that the costing data is given for (used to adjust the costing data so it can be used nationally). city: For custom costing data, this is the city that the costing data is given for (used to adjust the costing so it can be used nationally). year: The year the costing information is provided for (it should be the same for everything but some costs are only available in some years and not others). material_cost: The custom cost for material (e.g. the cost of a pipe). Not used for placeholder costs. labour_cost: The custom cost for labour (e.g. the labour to install the pipe). Not used for placeholder costs. equipment_cost: The custom cost of equipment required (e.g. the cost of any machinery required to install the pipe, often this is 0). This is not used for placeholder costs. material_op_factor: Ask Mike or Phylroy. Probably not for placeholder costs. labour_op_factor: Ask Mike or Phylroy. Probably not for placeholder costs. equipment_op_factor: Ask Mike or Phylroy. Probably not for placeholder costs. comments: comments. material_mult: A fixed multiplier to multiply the material cost by. labour_mult: A fixed multiplier to multiply the labour costs by. The method uses the id from ‘mat_cost_info’ to find costing information for the piece of equipment in the costing database. It then adjusts the material and equipment cost by the regional cost factor for the location the model is supposed to be in. The resulting adjusted equipment and material costs are then multiplied by any associated multipliers and the total amount is returned.
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 637 def get_vent_mat_cost(mat_cost_info:, vent_tags: [], report_mult: 1.0) =.clone if mat_cost_info.nil? raise("Error: no assembly information available for material!") end # Look for the costing information for the piece of equipment in the costing database. costing_data = @costing_database['costs'].detect {|data| data['id'].to_s.upcase == mat_cost_info['id'].to_s.upcase} # If no costing information is found then return an error. if costing_data.nil? raise "Error: no costing information available for material id #{mat_cost_info['id']}!" elsif costing_data['baseCosts']['materialOpCost'].nil? || costing_data['baseCosts']['laborOpCost'].nil? #This is a stub for some work that needs to be done to account for equipment costing. For now this is zeroed out. # A similar test is done on reading the data from the database and collected in the error file when the # costing database is generated. puts("Error: costing information for material id #{mat_cost_info['id']} is nil. Please check costing data.") return 0.0 end # The costs from the costing database are US national average costs (for placeholder costs) or whatever is in the # 'province_state' and 'city' fieleds (for custom costs). These costs need to be adjusted to reflect the costs # expected in the location of interest. The 'get_regional_cost_factors' method finds the appropriate cost # adjustment factors. mat_mult, inst_mult = get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], mat_cost_info) if mat_mult.nil? || inst_mult.nil? raise("Error: no localization information available for material id #{id}!") end # Get any associated material or labour multiplier for the equipment present in the 'materials_hvac' sheet in the # costing spreadsheet. mat_cost_info['material_mult'].to_f == 0 ? mat_quant = 1.0 : mat_quant = mat_cost_info['material_mult'].to_f mat_cost_info['labour_mult'].to_f == 0 ? lab_quant = 1.0 : lab_quant = mat_cost_info['labour_mult'].to_f # Calculate the adjusted material and labour costs. mat_cost = costing_data['baseCosts']['materialOpCost']*(mat_mult/100.0)*mat_quant lab_cost = costing_data['baseCosts']['laborOpCost']*(inst_mult/100.0)*lab_quant # Add information to report output if tags provided. unless .empty? << mat_cost_info['Material'].to_s << mat_cost_info['description'].to_s # Add support for equipment_multiplier (if used in the future). mat_cost_info['equipment_mult'].nil? || mat_cost_info['equipment_mult'].to_f == 0 ? equip_quant = 1.0 : equip_quant = mat_cost_info['equipment_mult'].to_f add_costed_item(material_id: mat_cost_info['id'], quantity: report_mult.to_f, material_mult: mat_quant, labour_mult: lab_quant, equip_mult: equip_quant, tags: ) end # Return the total. return (mat_cost+lab_cost) end |
#get_vent_system_mult(loop_equip:, mult_floor: nil) ⇒ Object
This method finds how many pieces of costed equipment are required to meet a given load if no one piece of costed equipment can do it. It takes in two hashes: mult_floor: This should probably be mult_ceiling. It is the maximum size of mechanical equipment that should be selected. This is used if you really want to make sure that a given piece of mechanical equipment does not exceed this size. It is normally not used. loop_equip: This hash must have the following information in it: cat_search: The category or type of the mechanical equipment that is being searched for in the ‘Material’ column of the ‘materials_hvac’ sheet in the costing spreadsheet. supply_comp: This is the oir loop supply component from the OpenStudio model. It is really just used to give a name in any error messages. mech_capacity: This is the capacity of the piece of the supply component being costed.
The method first looks for all of the items in the ‘materials_hvac’ sheet whose ‘Material’ match the ‘cat_search’ criteria. If none are found then something has gone wrong so an error is generated telling the user what happened. Assuming it found some items it then finds the largest one (or the largest one that does not exceed the mult_floor category). It then divides the mech_capacity by the size of the costed equipment it found to determine the minimum number of pieces of costed equipment meets the model equipment capacity (the multiplier). With this information it then rounds the multiplier to the next largest whole number and divides the modeled equipment capacity by this size to determine the revised size of equipment (this may be smaller than the largest piece of equipment). It then looks for the smallest piece of costed equipment that meets this requirement and returns the result.
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 506 def get_vent_system_mult(loop_equip:, mult_floor: nil) # Look for all of the equipment in the materials_hvac sheet that has a 'Material' that matches the cat_search # criteria. heat_cool_cost = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == loop_equip[:cat_search].to_s.upcase } # In some cases loop_equip[:supply_comp] may not be an object but a string. If this is the case then the string # should be given rather than a message that nameString does not exist. equip_name = loop_equip[:supply_comp].nameString rescue equip_name = loop_equip[:supply_comp].to_s # If it cannot find any then return an error telling the user what happened. This is likely the result of a # spelling mistake somewhere but it is something the user will have to deal with. if heat_cool_cost.nil? || heat_cool_cost.empty? raise "Error: no equipment could be found whose type matches the name #{loop_equip[:cat_search]} for the #{equip_name} air loop supply component!" end # Set the maximum size to be a really large number if it is not defined. mult_floor.nil? ? max_eq_size = 99999999999999999999.0 : max_eq_size = mult_floor.to_f # Find the largest piece of equipment that is smaller than the size ceiling. max_size = heat_cool_cost.select {|element| element['Size'].to_f <= max_eq_size}.max_by{|data| data['Size'].to_f} # If you cannot find any then the size ceiling is too small. Raise an error telling the user if max_size.nil? || max_size.empty? raise "Error no equipment of the type #{loop_equip[:cat_search]} could be found with a size less than #{max_eq_size} for the #{equip_name} air loop supply component!" end # Make sure the piece of equipment has a capacity larger than 0. if max_size['Size'].to_f <= 0 raise "Error: #{loop_equip[:cat_search]} has a size of 0 or less. Please check that the correct costing_database.json file is being used or check the costing spreadsheet!" end # Find the revised number of pieces of equipment and round to the next largest whole number. mult = (loop_equip[:mech_capacity_kw].to_f) / (max_size['Size'].to_f) # This is to handle the small possibility that the revised capacity is a whole number. mult > (mult.to_i).to_f.round(0) ? multiplier = (mult.to_i).to_f.round(0) + 1 : multiplier = mult.round(0) # Find the new capacity of the pieces of equipment new_cap = loop_equip[:mech_capacity_kw].to_f/multiplier.to_f # Find the smallest piece of costed equimpent that meets the new size requirement. return_equip = heat_cool_cost.select{|data| data['Size'].to_f >= new_cap}.min_by{|element| element['Size'.to_f]} # If no costed equipment can be found that matches this new size then something is wrong and use the largest piece # you found before. return_equip = max_size if (return_equip.nil? || return_equip.empty?) return return_equip, multiplier.to_f end |
#getCost(materialType, materialHash, multiplier) ⇒ Object
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 1123 def getCost(materialType, materialHash, multiplier) material_cost = 0.0 ; labour_cost = 0.0 costing_data = @costing_database['costs'].detect do |data| data['id'].to_s.upcase == materialHash['id'].to_s.upcase end if costing_data.nil? puts "HVAC #{materialType} with id #{materialHash['id']} not found in the costing database. Skipping." raise else # Get cost information from lookup. # Adjust for material and labour multiplier in costing spreadsheet 'materials_hvac' sheet 'material_mult' and # 'labour_mult' columns. (materialHash['material_mult'].nil?) || (materialHash['material_mult'].empty?) ? mat_mult = 1.0 : mat_mult = materialHash['material_mult'].to_f (materialHash['labour_mult'].nil?) || (materialHash['labour_mult'].empty?) ? lab_mult = 1.0 : lab_mult = materialHash['labour_mult'].to_f material_cost = costing_data['baseCosts']['materialOpCost'].to_f * multiplier * mat_mult labour_cost = costing_data['baseCosts']['laborOpCost'].to_f * multiplier * lab_mult end return material_cost, labour_cost end |
#getGeometryData(model, prototype_creator) ⇒ Object
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 1143 def getGeometryData(model, prototype_creator) num_of_above_ground_stories = model.getBuilding.standardsNumberOfAboveGroundStories.to_i space_mod = OpenstudioStandards::Space if model.building.get.nominalFloortoFloorHeight().empty? volume = model.building.get.airVolume() flrArea = 0.0 if model.building.get.conditionedFloorArea.empty? model.getThermalZones.sort.each do |tz| tz.spaces.sort.each do |tz_space| flrArea += tz_space.floorArea.to_f if ( (space_mod.space_cooled?(tz_space)) || (space_mod.space_heated?(tz_space)) ) end flrArea += tz.floorArea end else flrArea = model.building.get.conditionedFloorArea().get end nominal_flr2flr_height = 0.0 nominal_flr2flr_height = volume / flrArea unless flrArea <= 0.01 else nominal_flr2flr_height = model.building.get.nominalFloortoFloorHeight.get end # Location of mechanical room and utility distances for use below (space_centroid is an array # in mech_room hash containing the x,y and z coordinates of space centroid). Utility distance # uses the distance from the mech room centroid to the perimeter of the building. mech_room, cond_spaces = prototype_creator.find_mech_room(model) mech_room_story = nil target_cent = [mech_room['space_centroid'][0], mech_room['space_centroid'][1]] found = false model.getBuildingStorys.sort.each do |story| story.spaces.sort.each do |space| if space.nameString == mech_room['space_name'] mech_room_story = story found = true break end end break if found end distance_info_hash = get_story_cent_to_edge( building_story: mech_room_story, prototype_creator: prototype_creator, target_cent: target_cent, full_length: false ) horizontal_dist = distance_info_hash[:start_point][:line][:dist] # in metres ht_roof = 0.0 util_dist = 0.0 mechRmInBsmt = false if mech_room['space_centroid'][2] < 0 # Mechanical room is in the basement (z dimension is negative). mechRmInBsmt = true ht_roof = (num_of_above_ground_stories + 1) * nominal_flr2flr_height util_dist = nominal_flr2flr_height + horizontal_dist elsif mech_room['space_centroid'][2] == 0 # Mech room on ground floor ht_roof = num_of_above_ground_stories * nominal_flr2flr_height util_dist = horizontal_dist else # Mech room on some other floor ht_roof = (num_of_above_ground_stories - (mech_room['space_centroid'][2]/nominal_flr2flr_height).round(0)) * nominal_flr2flr_height util_dist = ht_roof + horizontal_dist end util_dist = OpenStudio.convert(util_dist,"m","ft").get nominal_flr2flr_height = OpenStudio.convert(nominal_flr2flr_height,"m","ft").get ht_roof = OpenStudio.convert(ht_roof,"m","ft").get horizontal_dist = OpenStudio.convert(horizontal_dist,"m","ft").get return util_dist, ht_roof, nominal_flr2flr_height, horizontal_dist, num_of_above_ground_stories, mechRmInBsmt end |
#getHeaderPipingDistributionCost(numAGFlrs, mechRmInBsmt, regional_material, regional_installation, reg_elec_mat, reg_elec_inst, pumpFlow, horz_dist, nom_flr_hght) ⇒ Object
1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 1713 def getHeaderPipingDistributionCost(numAGFlrs, mechRmInBsmt, regional_material, regional_installation, reg_elec_mat, reg_elec_inst, pumpFlow, horz_dist, nom_flr_hght) # Hot water central header piping distribution costs. Note that the piping distribution cost # of zone piping is done in the zonalsys_costing function # Central header piping Cost supHdrCost = 0; retHdrCost = 0 mechRmInBsmt ? numFlrs = numAGFlrs + 1 : numFlrs = numAGFlrs if numFlrs < 3 # Header pipe is same diameter as distribution pipes to zone floors supHdrLen = numFlrs * nom_flr_hght # 1.25 inch Steel pipe matCost, labCost = getHVACCost('Header 1.25 inch steel pipe', 'SteelPipe', 1.25) supHdrpipingCost = supHdrLen * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 1.25 inch Steel pipe insulation matCost, labCost = getHVACCost('Header 1.25 inch pipe insulation', 'PipeInsulation', 1.25) supHdrInsulCost = supHdrLen * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 1.25 inch gate valves matCost, labCost = getHVACCost('Header 1.25 inch gate valves', 'ValvesGate', 1.25) supHdrValvesCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 1.25 inch tee matCost, labCost = getHVACCost('Header 1.25 inch steel tee', 'SteelPipeTee', 1.25) supHdrTeeCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) supHdrCost = supHdrpipingCost + supHdrInsulCost + supHdrValvesCost + supHdrTeeCost retHdrCost = supHdrCost else # Greater than 3 floors (including basement) # Use pumpFlow to determine pipe size if pumpFlow <= 0.0001262 hdrPipeSize = 0.5 elsif pumpFlow > 0.0001262 && pumpFlow <= 0.0002524 hdrPipeSize = 0.75 elsif pumpFlow > 0.0002524 && pumpFlow <= 0.0005047 hdrPipeSize = 1.0 elsif pumpFlow > 0.0005047 && pumpFlow <= 0.0010090 hdrPipeSize = 1.25 elsif pumpFlow > 0.0010090 && pumpFlow <= 0.0015773 hdrPipeSize = 1.5 elsif pumpFlow > 0.0015773 && pumpFlow <= 0.0031545 hdrPipeSize = 2.0 elsif pumpFlow > 0.0031545 hdrPipeSize = 2.5 end hdrPipeLen = horz_dist + nom_flr_hght * numFlrs # Steel pipe matCost, labCost = getHVACCost("Header Steel Pipe - #{hdrPipeSize} inch", 'SteelPipe', hdrPipeSize) supHdrpipingCost = hdrPipeLen * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # Steel pipe insulation matCost, labCost = getHVACCost("Header Pipe Insulation - #{hdrPipeSize} inch", 'PipeInsulation', hdrPipeSize) supHdrInsulCost = hdrPipeLen * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # Gate valves matCost, labCost = getHVACCost("Header Gate Valves - #{hdrPipeSize} inch", 'ValvesGate', hdrPipeSize) supHdrValvesCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # Tee matCost, labCost = getHVACCost("Header Steel Tee - #{hdrPipeSize} inch", 'SteelPipeTee', hdrPipeSize) supHdrTeeCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) supHdrCost = supHdrpipingCost + supHdrInsulCost + supHdrValvesCost + supHdrTeeCost retHdrCost = supHdrCost end hdrPipeCost = supHdrCost + retHdrCost # Electrical header costs. Central electric header cost for zonal heatingunits hdrLen = numFlrs * nom_flr_hght # Conduit - only one spreadsheet entry matCost, labCost = getHVACCost('Header Metal conduit', 'Conduit', '') hdrConduitCost = hdrLen * (matCost * reg_elec_mat / 100.0 + labCost * reg_elec_inst / 100.0) # Wiring - size 10 matCost, labCost = getHVACCost('Header No 10 Wiring', 'Wiring', 10) hdrWireCost = hdrLen / 100 * (matCost * reg_elec_mat / 100.0 + labCost * reg_elec_inst / 100.0) # Box - size 4 matCost, labCost = getHVACCost('Header 4 inch deep Box', 'Box', 4) hdrBoxCost = numFlrs * (matCost * reg_elec_mat / 100.0 + labCost * reg_elec_inst / 100.0) elecHdrCost = hdrConduitCost + hdrWireCost + hdrBoxCost # Central gas header cost will be determined in zonalsys_costing function since # this cost depends on existence of at least one gas-fired unit heater in building. hdrDistributionCost = hdrPipeCost + elecHdrCost return hdrDistributionCost end |
#getHVACCost(name, materialLookup, materialSize, exactMatch = true) ⇒ Object
This method provides the material and labour cost for a required piece of equimpment. It takes in: name(String): The name of a piece of equipment. Is only used for error reporting and is not linked to anything
else.
materialLookup(String): The material type used to search hte ‘Material’ column of the materials_hvac sheet of the
costing spreadsheet.
materialSize(float): The size of the equipment in whichever units are required when searching the ‘Size’ column of
the costing spreadsheet.
exactMatch(true/false): A flag to indicate if the hvac equipment must match the size provided exactly or if the
size is a minimum equipment size.
It returns the material cost ond labor cost for the equipment including any multipliers.
1036 1037 1038 1039 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 1036 def getHVACCost(name, materialLookup, materialSize, exactMatch=true) eqCostInfo = getHVACDBInfo(name: name, materialLookup: materialLookup, materialSize: materialSize, exactMatch: exactMatch) return getCost(eqCostInfo[:name], eqCostInfo[:hvac_material], eqCostInfo[:multiplier]) end |
#getHVACDBInfo(name:, materialLookup:, materialSize:, exactMatch: true) ⇒ Object
This method was originally part of getHVACCOST but was split out because in some cases the information from the materials_hvac sheet of the costing spreadsheet was required but not tho cost. The method takes in: name(String): The name of a piece of equipment. Is only used for error reporting and is not linked to anything
else.
materialLookup(String): The material type used to search hte ‘Material’ column of the materials_hvac sheet of the
costing spreadsheet.
materialSize(float): The size of the equipment in whichever units are required when searching the ‘Size’ column of
the costing spreadsheet.
exactMatch(true/false): A flag to indicate if the hvac equipment must match the size provided exactly or if the
size is a minimum equipment size.
The method returns a hash with the following composition: { name(string): Same as above. hvac_material(hash): The costing spreadsheet information for the hvac equipment being searched for. multiplier(float): Default is 1. Will be higher if exactMatch is false, and no materialLookup could be found with
a large enough materialSize in the costing spreadsheet. In this case, it is assumed that several
pieced of equipment defined by hvact_material are used to satisfy the required materialSize.
The multiplier defines the number of hvac_material required to meet the materialSize
}
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 1062 def getHVACDBInfo(name:, materialLookup:, materialSize:, exactMatch: true) multiplier = 1.0 materials_hvac = @costing_database["raw"]["materials_hvac"] if materialSize == 'nil' || materialSize == '' || materialSize == nil # When materialSize is blank because there is only one row in the data sheet, the value is nil hvac_material = materials_hvac.select { |data| data['Material'].to_s.upcase == materialLookup.to_s.upcase }.first else if exactMatch hvac_material = materials_hvac.select {|data| data['Material'].to_s.upcase == materialLookup.to_s.upcase && data['Size'].to_f == materialSize }.first else hvac_material_info = materials_hvac.select {|data| data['Material'].to_s.upcase == materialLookup.to_s.upcase && data['Size'].to_f >= materialSize } if hvac_material_info.empty? hvac_material = nil elsif hvac_material_info.size == 1 hvac_material = hvac_material_info[0] else hvac_material = hvac_material_info.min_by{|data| data['Size'].to_f} end end end if hvac_material.nil? if exactMatch puts "HVAC material error! Could not find #{name} in materials_hvac!" raise else # There is no exact match in the costing spreadsheet so redo search for next largest size hvac_material = materials_hvac.select {|data| data['Material'].to_s.upcase == materialLookup.to_s.upcase && data['Size'].to_f >= materialSize.to_f }.min_by{|mat_info| mat_info['Size'].to_f} if hvac_material.nil? # The nominal capacity is greater than the maximum value in the API data for this boiler! # Lookup cost for a capacity divided by the multiple of req'd size/max size. multiplier = get_HVAC_multiplier( materialLookup, materialSize ) hvac_materials = materials_hvac.select {|data| data['Material'].to_s.upcase == materialLookup.to_s.upcase && data['Size'].to_f >= materialSize.to_f / multiplier.to_f } if hvac_materials.size == 0 puts "HVAC material error! Could not find next largest size for #{name} in #{materials_hvac}" raise elsif hvac_materials.size == 1 hvac_material = hvac_materials[0] else hvac_material = hvac_materials.min_by{|data| data['Size'].to_f} end end end end # Create the return hash. costDBInfo = { name: name, hvac_material: hvac_material, multiplier: multiplier } return costDBInfo end |
#getHVACMultiSizeDBInfo(name:, materialLookup:, materialCap:, materialCon:) ⇒ Object
This method was originally part of getHVACCOST but was split out because in some cases the information from the materials_hvac sheet of the costing spreadsheet was required but not tho cost. The method takes in: name(String): The name of a piece of equipment. Is only used for error reporting and is not linked to anything
else.
materialLookup(String): The material type used to search hte ‘Material’ column of the materials_hvac sheet of the
costing spreadsheet.
materialSize(float): The size of the equipment in whichever units are required when searching the ‘Size’ column of
the costing spreadsheet.
exactMatch(true/false): A flag to indicate if the hvac equipment must match the size provided exactly or if the
size is a minimum equipment size.
The method returns a hash with the following composition: { name(string): Same as above. hvac_material(hash): The costing spreadsheet information for the hvac equipment being searched for. multiplier(float): Default is 1. Will be higher if exactMatch is false, and no materialLookup could be found with
a large enough materialSize in the costing spreadsheet. In this case, it is assumed that several
pieced of equipment defined by hvact_material are used to satisfy the required materialSize.
The multiplier defines the number of hvac_material required to meet the materialSize
}
2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 2426 def getHVACMultiSizeDBInfo(name:, materialLookup:, materialCap:, materialCon:) multiplier = 1.0 numConLoops = 1.0 # Get the materials_hvac sheet info from the costing spreadsheet materials_hvac = @costing_database["raw"]["materials_hvac"] # Find material that meet the materialCon requirement hvac_material_con_info = materials_hvac.select {|data| data['Material'].to_s.upcase == materialLookup.to_s.upcase && data['Fuel'].to_f >= materialCon } hvac_material = [] unless hvac_material_con_info.empty? # If the materialCon criteria check if any of the selected material meet the mateterialCap criteria hvac_material_cap_info = hvac_material_con_info.select {|data| data['Size'].to_f >= materialCap} if hvac_material_cap_info.nil? || hvac_material_cap_info.empty? # If none do then select the material with the largest capacity that met the materialCon criteria hvac_material << hvac_material_con_info.max_by {|data| data['Size'].to_f} con_per_loop = hvac_material[0]['Fuel'].to_f else # If something met both the materialCon and materialCap then return a hash containing the material and other # information and we are done. hvac_material = hvac_material_cap_info.min_by {|data| data['Size'].to_f} ret_hash = { name: name, hvac_material: hvac_material, multiplier: 1 } return ret_hash end end if hvac_material.empty? # If no equipment met the materialCon criteria then find all with the material type we want hvac_material_info = materials_hvac.select {|data| data['Material'].to_s.upcase == materialLookup.to_s.upcase} # If you cannot find even the material type then something has gone very wrong. Stop everything and tell the user. raise "HVAC material error! Could not find next largest size for #{name} in the materials_hvac sheet of the costing spreadsheet of #{materialLookup} type." if hvac_material_info.empty? # Find the equipment with the largest 'Fuel' (this is what defines the materialCon options for this material type) hvac_material = hvac_material_info.max_by{|data| data['Fuel'].to_f} # Find the number of pieces of equipment will be needed to meet the materialCon requirement (((materialCon.to_f) % (hvac_material['Fuel'].to_f)).round(3) > 0.0) ? numConLoops = ((materialCon.to_f/(hvac_material['Fuel'].to_f)).to_i + 1).to_f.round(0) : numConLoops = (materialCon.to_f/(hvac_material['Fuel'].to_f)).round(0) # Revise the materialCon requirement now that several pieces of equipment are being used con_per_loop = materialCon / numConLoops # Find all the appropriate equipment in the costing spreadsheet that meet the revised materialCon requirement hvac_material = hvac_material_info.select{|data| data['Fuel'].to_f >= con_per_loop} end # Now that we have some equipment that meet the required materialCon requirement revise the materialCap requirement # in case multiple pieces of equipment were to meet the materialCon requirement. reqMatSize = materialCap/numConLoops # Of the equipment that met the (modified or original) materialCan requirement select the equipment the meets the # (modified or original) capacity requirement. material_cap = hvac_material.select{|data| data['Size'].to_f >= reqMatSize} if material_cap.empty? # If none of the selected materials meet the materialCap requirement find the one with the largest capacity largestMat = hvac_material.max_by{|data| data['Size'].to_f} maxAvailCap = largestMat['Size'].to_f # Find out how many are required to meet the materialCap requirement (reqMatSize%maxAvailCap).to_f.round(3) > 0 ? numCapLoops = (((reqMatSize/maxAvailCap).to_i) + 1).to_f.round(0) : numCapLoops = (reqMatSize/maxAvailCap).to_f.round(0) # Calculate how many pieces of equipment are now required to meet both the materialCon and materialCap # requirements totLoops = numConLoops*numCapLoops # Revise the materialCap and materialCon requirements to reflect that even more pieces of equipment will be used # to meet both requirements modMatCap = (materialCap / totLoops).to_f modMatCon = (materialCon / totLoops).to_f # Search for equipment that meet both the modMatCap and modMatCon criteria hvac_material_info = materials_hvac.select {|data| data['Material'].to_s.upcase == materialLookup.to_s.upcase} material_cap = hvac_material_info.select{|data| (data['Size'].to_f >= modMatCap) && (data['Fuel'].to_f >= modMatCon)} if material_cap.empty? # It should have gotten something. If it didn't then select the one with largest capacity and use that. ret_mat = largestMat else # Find the equipment with the smallest capacity that meets the requirement ret_mat = material_cap.min_by{|data| data['Size'].to_f} end else # If something now meets the materialCon and materialCap requirement select the one with the smallest capacity. totLoops = numConLoops ret_mat = material_cap.min_by{|data| data['Size'].to_f} end # If multiple branch distributors are required check if the last one can be smaller than the others and return that # in addition to the other branch distributors. if totLoops.round(0) > 1.0 # Check check the remaining size requirements for the last branch distributor (materialCon - (totLoops - 1.0)*(ret_mat['Fuel'].to_f)) > 0 ? redCon = (materialCon - (totLoops - 1.0)*(ret_mat['Fuel'].to_f)) : redCon = 0.0 (materialCap - (totLoops - 1.0)*(ret_mat['Size'].to_f)) > 0 ? redCap = (materialCap - (totLoops - 1.0)*(ret_mat['Size'].to_f)) : redCap = 0.0 # If either are greater than zero (as should be the case) then look for equipment that can meet the remaining # connection or capacity requipments. if (redCon > 0) || (redCap > 0) # Find material that meet the remaining connection and capacity requirements. hvac_material_red = materials_hvac.select {|data| data['Material'].to_s.upcase == materialLookup.to_s.upcase && data['Fuel'].to_f >= redCon && data['Size'].to_f >= redCap } if hvac_material_red.size == 0 # If no equipment could be found which meet the remaining connection and capacity requirements then return # the the number and type of equipment without adjust for a smaller final piece of equipment. red_ret_hash = nil else # If equipment could be found then select the one with the minimum number of connections. red_ret = hvac_material_red.min_by{|data| data['Fuel'].to_f} min_hvac_sel = hvac_material_red.select{|data| data['Fuel'].to_f == red_ret['Fuel'].to_f} # If more than one piece of equipment can meet the minimum connection requirement then select the one with the # minimum capacity requirement. if min_hvac_sel.size > 1 red_ret = min_hvac_sel.min_by{|data| data['Size'].to_f} end red_ret_hash = { red_ret_hash: red_ret, numCon: redCon, numCap: redCap } end end end # If multiple pieces of equipment are required to meet the connection and capacity requirements check if a smaller # piece of equipment was found to get the final remaining requirements. If one is found then adjust the multiplier # for the main equipment to be reduced by one and return the smaller remaining piece of equipment. red_ret_hash.nil? ? retLoops = totLoops : retLoops = totLoops - 1.0 # Create a hash with the results and return it. ret_hash = { name: name, hvac_material: ret_mat, multiplier: retLoops } return ret_hash, red_ret_hash end |
#getPerimDistPipingCost(zone, nom_flr_hght, regional_material, regional_installation) ⇒ Object
1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 1809 def getPerimDistPipingCost(zone, nom_flr_hght, regional_material, regional_installation) # Get perimeter distribution piping cost extWallArea = 0.0 perimPipingCost = 0.0 zone.spaces.sort.each do |space| if space.spaceType.empty? or space.spaceType.get.standardsSpaceType.empty? or space.spaceType.get.standardsBuildingType.empty? raise ("standards Space type and building type is not defined for space:#{space.name.get}. Skipping this space for costing.") end extWallArea += OpenStudio.convert(space.exteriorWallArea.to_f,"m^2","ft^2").get # sq.ft. end perimTotal = ( extWallArea / nom_flr_hght ) * zone.multiplier # 1.25 inch Steel pipe matCost, labCost = getHVACCost('Perimeter Distribution - 1.25 inch steel pipe', 'SteelPipe', 1.25) perimPipingCost = perimTotal * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 1.25 inch Steel pipe insulation matCost, labCost = getHVACCost('Perimeter Distribution - 1.25 inch pipe insulation', 'PipeInsulation', 1.25) perimPipingCost += perimTotal * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) return perimPipingCost end |
#getPerimDistWiringCost(zone, nom_flr_hght, regional_material, regional_installation) ⇒ Object
1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 1832 def getPerimDistWiringCost(zone, nom_flr_hght, regional_material, regional_installation) # Get perimeter distribution wiring cost extWallArea = 0.0 perimWiringCost = 0.0 zone.spaces.sort.each do |space| if space.spaceType.empty? or space.spaceType.get.standardsSpaceType.empty? or space.spaceType.get.standardsBuildingType.empty? raise ("standards Space type and building type is not defined for space:#{space.name.get}. Skipping this space for costing.") end extWallArea += OpenStudio.convert(space.exteriorWallArea.to_f,"m^2","ft^2").get # sq.ft. end perimTotal = ( extWallArea / nom_flr_hght ) * zone.multiplier # Conduit - only one spreadsheet entry matCost, labCost = getHVACCost('Perimeter Distribution - Metal conduit', 'Conduit', '') perimWiringCost = perimTotal * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # Wiring - size 10 matCost, labCost = getHVACCost('Perimeter Distribution - No 10 Wiring', 'Wiring', 10) perimWiringCost += perimTotal / 100 * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) return perimWiringCost end |
#getSHWTankCost(name:, materialLookup:, materialSize:, tankVol:) ⇒ Object
Getting cost for SHW Tanks. This method is different from the getHVACCost method used everywhere else in that it accepts a tank volume argument in addition to the tank capacity (materialSize in this case). This additional argument means that the method must search for a SHW tank heated with the right fuel that has a large enough capacity and volume.
IMPORTANT: This method assumes that when SHW tanks are retrieved from the model their capacity is checked against the capacities of costed tanks. If the modeled capacity is too large then it is costed as though multiple smaller tanks are present. Thus, this method assumes that anything passed to it will be small enough to be costed. This is another difference from the getHVACCost method which includes a call to get_HVAC_multiplier that checks if a costed item is too big and should be replaced by several smaller items.
Note that the multiplier is always set to 1.0 when claculating the cost. That is because the multiplier is applied to the cost in the main shw_costing method.
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 |
# File 'lib/openstudio-standards/btap/costing/shw_costing.rb', line 536 def getSHWTankCost(name:, materialLookup:, materialSize:, tankVol:) multiplier = 1.0 materials_hvac = @costing_database['raw']['materials_hvac'] # Get costing spreadsheet data for gas and oil fired mixed shw tanks if tankVol.nil? # If no tank volume is provided then only look at capacity. # Get all capacities hor that type of tank. hvac_materials = materials_hvac.select {|data| data['Material'].to_s == materialLookup.to_s && data['Size'].to_f >= materialSize.to_f } if hvac_materials.empty? # If no tanks have a big enough capacity then something is amiss and return an error (this should never happen # because tanks capacity should be checked before this method is called). puts "HVAC material error! Could not find next largest size for #{name} in #{materials_hvac}" raise elsif hvac_materials.size == 1 # Only one tank has an appropriate capacity find it's cost and return it. matCost, labCost = getCost(name, hvac_materials[0], 1.0) ret_hash = { matCost: matCost, labCost: labCost, multiplier: multiplier, Vol_USGal: tankVol, Cap_kW: hvac_materials[0]['Size'].to_f } return ret_hash else # More than one tank has a big enough capacity. Find the cost of the one with teh smallest capacity and return # it. hvac_material = hvac_materials.min_by {|data| data['Size'].to_f} matCost, labCost = getCost(name, hvac_material, 1.0) ret_hash = { matCost: matCost, labCost: labCost, multiplier: multiplier, Vol_USGal: tankVol, Cap_kW: hvac_material['Size'].to_f } return ret_hash end else # We need to find a tank with a big enough capacity and volume. # First see if a unique tank with a large enough capacity and volume exists hvac_materials = materials_hvac.select {|data| data['Material'].to_s == materialLookup.to_s && data['Size'].to_f >= materialSize.to_f && data['Fuel'].to_f >= tankVol } if hvac_materials.empty? # If none exists see if the tank volume is big enough. Note that tank capacity was checked earlier so capacity # should not be an issue. However, volume was not checked. It is possible that tanks with a big enough # capacity are in the costing database but not a big enough volume. # # Find the largest volume tank with a big enough capacity. Find out how many of those tanks are needed to # satisfy the volume requirement. multiplier, revVol = get_SHW_vol_multiplier(materialLookup: materialLookup, materialSize: materialSize, materialVol: tankVol) materialSize /= multiplier tankVol = revVol # Try again to get tanks with a large enough size and capacity hvac_materials = materials_hvac.select {|data| data['Material'].to_s == materialLookup.to_s && data['Size'].to_f >= materialSize.to_f && data['Fuel'].to_f >= tankVol } # You may notice that there is no handling for cases where there is more than one tank with a large enough # capacity and volume. There actually is, it is just a little further below. if hvac_materials.empty? puts "HVAC material error! Could not find a #{name} tank with a capacity >= #{materialSize} kW and a volume >= #{tankVol} US Gal in #{materials_hvac}" elsif hvac_materials.size == 1 matCost, labCost = getCost(name, hvac_materials[0], 1.0) ret_hash = { matCost: matCost, labCost: labCost, multiplier: multiplier, Vol_USGal: hvac_materials[0]['Fuel'].to_f, Cap_kW: hvac_materials[0]['Size'].to_f } return ret_hash end elsif hvac_materials.size == 1 matCost, labCost = getCost(name, hvac_materials[0], 1.0) ret_hash = { matCost: matCost, labCost: labCost, multiplier: multiplier, Vol_USGal: hvac_materials[0]['Fuel'].to_f, Cap_kW: hvac_materials[0]['Size'].to_f } return ret_hash end # If mare than one tank has a lorge enough capacity and volume then find the one with the smallest volume. hvac_materials_min_vol = hvac_materials.min_by {|data| data['Fuel'].to_f} if hvac_materials_min_vol.nil? # Well, something went horribly wrong. You should have gotten this far only if there were several tanks that # had a large enough capacity and volume. Now we can't find the smallest one. Not sure what happened but # whatever it was it is not good. puts "HVAC material error! Could not find a #{name} tank with a capacity >= #{materialSize} kW and a volume >= #{materialVol} US Gal in costing database." raise else # Find how many tanks have the lowest volume. hvac_materials_vol = hvac_materials.select {|data| data['Fuel'].to_f == hvac_materials_min_vol['Fuel'].to_f} if hvac_materials_vol.size == 1 hvac_material = hvac_materials_vol[0] else # If more than one tank as a small enough volume choose the one with the smallest capacity. hvac_material = hvac_materials_vol.min_by {|data| data['Size'].to_f} end matCost, labCost = getCost(name, hvac_material, 1.0) ret_hash = { matCost: matCost, labCost: labCost, multiplier: multiplier, Vol_USGal: hvac_material['Fuel'].to_f, Cap_kW: hvac_material['Size'].to_f } return ret_hash end end end |
#getWallWithLargestArea(currFloor:) ⇒ Object
This method finds and returns the outside wall with the largest area on a given building story. It takes in:
currFloor = {
storyName(string): Name of the current floor (story).
buildStoryObj(Obj): The OpenStudio object associated with the current floor (story).
floorAream2: Total floor area (m2) of thermal zones on the current floor served by VRF systems. Does not
include multipliers.
floorCeillingAream2: The Total ceiling area (m2) of thermal zones on the current floor served by VRF
systems. Does not include multipliers.
floorTZs(array): An array containing each tzFloor hash described above for the current floor.
}
It returns a hash containing the following: wallRetHash =
largestOutsideWallObj(OS Object): OpenStudio surface object with the largest gross area that has a 'wall'
surface type and an 'Outdoors' outside boundary condition.
wallCentObj(array of floats): OpenStudio point3d object containing the x, y, z coordinates of the wall above
wall's centroid. In local coordinate system.
wallCentOrigin(array of OS Objects): Coordinates of the local wall origin in the absolute building
coordinate system.
wallCent(array of floats): Coordinates of the wall's centroid in floats referenced to the building
coordinate system.
2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 2252 def getWallWithLargestArea(currFloor:) outsideWalls = [] # Get all the spaces associated with the building story floorSpaces = currFloor[:buildStoryObj].spaces # Cycle through each space associated with the building story. floorSpaces.each do |floorSpace| # Get the surfaces in the spcae which have a 'Wall' Surface Type and an 'Outdoors' outside boundary condition. spaceOutWalls = floorSpace.surfaces.select{|surf| surf.surfaceType.to_s.upcase == 'WALL' && ((surf.outsideBoundaryCondition.to_s.upcase == 'OUTDOORS') || (surf.outsideBoundaryCondition.to_s.upcase == 'GROUND') || (surf.outsideBoundaryCondition.to_s.upcase == 'FOUNDATION'))} # Add these surfaces to the array containing outdoor walls. spaceOutWalls.each{|outWall| outsideWalls << outWall} end # Find and return the outside wall object with the largest gross area. largestWall = outsideWalls.sort.max_by{|outWall| outWall.grossArea.to_f} largestWallSpace = largestWall.space.get largestWallSpaceOrigin = [ largestWallSpace.xOrigin, largestWallSpace.yOrigin, largestWallSpace.zOrigin ] wallCentObj = largestWall.centroid wallCent = [ wallCentObj.x.to_f + largestWallSpaceOrigin[0].to_f, wallCentObj.y.to_f + largestWallSpaceOrigin[1].to_f, wallCentObj.z.to_f + largestWallSpaceOrigin[2].to_f ] wallRetHash = { largestOutsideWallObj: largestWall, wallCentObj: wallCentObj, wallCentOrigin: largestWallSpaceOrigin, wallCent: wallCent } return wallRetHash end |
#getZonalVRFCosting(vrfSystemFloors:, model:, prototype_creator:, regMat:, regLab:, cumulCost:) ⇒ Object
Cost zonal VRF systems including zone equipment (ceiling units and associated tubing and wiring), floor equipment ( branch distributor on each floor), VRF system condenser (assumed one on rooftop and another every 50m), and piping and wiring linking the branch distributors to one another and to the condensers.
Takes in: vrfSystemFloors = {
maxCeil(float): The height of the thermal zone served by a VRF system with the highest ceiling in the
building. This is referenced to the global origin for the building. The units are m.
lowCeil(float): The height of the thermal zone served by a VRF system with the lowest ceiling in the
building. This is referenced to the global origin for the building. The units are m.
vrfFloors(array): [
storyName(string): Name of the current floor (story).
buildStoryObj(Obj): The OpenStudio object associated with the current floor (story).
floorAream2: Total floor area (m2) of thermal zones on the current floor served by VRF systems. Does not
include multipliers.
floorCeillingAream2: The Total ceiling area (m2) of thermal zones on the current floor served by VRF
systems. Does not include multipliers.
floorTZs(array): An array containing each tzFloor hash described above for the current floor.
]
}
model(hash): OpenStudio building model. prototype_creator(object): OpenStudio-Standards object for whichever version of NECB was used to create the model. regMat(float): HVAC regional cost factor for materiel. regLab(float): HVAC regional cost factor for labour. cumulCost(float): Cumulative zonal system cost.
Output(float): Total cost for VRF system. Also adds information to @costing_report for condenser(s), VRF zonal
systems, and branch distributors.
1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 1965 def getZonalVRFCosting(vrfSystemFloors:, model:, prototype_creator:, regMat:, regLab:, cumulCost:) # Include empty array in costing report for branch distributor costs on each floor @costing_report['heating_and_cooling']['floor_systems'] = [] total_cost = 0 vrfWireInfo = getHVACDBInfo(name: "VRF Wiring", materialLookup: "wiring", materialSize: 10, exactMatch: true) regMatElec, regLabElec = get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], vrfWireInfo[:hvac_material]) # Find the center of the highest roof roof_cent_info = prototype_creator.find_highest_roof_centre(model) roof_cent = roof_cent_info[:roof_centroid] # Find the distance between the highest roof and the ceiling of the lowest space served by a VRF system maxHeightDiff = (roof_cent[2] - vrfSystemFloors[:lowCeil]).to_f.round(8) # Find the roof height for the condenensate line cost. If the maxHeightDiff includes basement spaces use it, # otherwise use the height of the roof. maxHeightDiff > roof_cent[2].to_f.round(8) ? roofHeight = maxHeightDiff : roofHeight = roof_cent[2].to_f.round(8) # Get the condenser cost vrfCondenserCost = costVRFCondenser(model: model, maxHeightDiff: maxHeightDiff, regMat: regMat, regLab: regLab, regMatElec: regMatElec, regLabElec:regLabElec, roofHeight: roofHeight) total_cost += vrfCondenserCost vrfSystemFloors[:vrfFloors].each do |currFloor| vrfDistWallInfo = getWallWithLargestArea(currFloor: currFloor) vrfDistWallCent = vrfDistWallInfo[:wallCent] totalFloorCapkW = 0 totalFloorCeilUnits = 0 floorMults = [] currFloor[:floorTZs].each do |floorTZ| zoneWallLengthm = (vrfDistWallCent[0] - floorTZ[:tzCentroid][0]).abs + (vrfDistWallCent[1] - floorTZ[:tzCentroid][1]).abs zoneWallLengthft = (OpenStudio.convert(zoneWallLengthm, 'm', 'ft').get) elecLength = zoneWallLengthft + 10.0 * (floorTZ[:vrfCeilMountInfo][:multiplier] - 1) # Get the zone refrigerant tubing cost (tubing running from the ceiling units to the brancd distributers). A # Size of 50 is used for interior refrigerant tubing while 10 is used for the exterior tubing used between the # branch distributors and the condensers. zoneRefrigTubingMat, zoneRefrigTubingLab = getHVACCost("VRF Zone Refrigerant Tubing", 'Refrig-tubing', 50, true) # Refrigerant tubing comes in 50 ft rolls zoneRefrigTubingCost = ((zoneRefrigTubingMat * regMat + zoneRefrigTubingLab * regLab) / 100) * elecLength / 50.0 # Include condensate line tubing cost zoneCondTubingMat, zoneCondTubingLab = getHVACCost('VRF Zone Condensate Line Tubing', 'PEX_tubing', 0.5, true) zoneCondTubingCost = ((zoneCondTubingMat * regMat + zoneCondTubingLab * regLab) / 100) * elecLength # Include coupler cost for condensate line zoneCondCouplingMat, zoneCondCouplingLab = getHVACCost('VRF Zone Condensate Line Couplers', 'PVC_coupling', 0.5, true) zoneCondCouplingCost = ((zoneCondCouplingMat * regMat + zoneCondCouplingLab * regLab) / 100) * floorTZ[:vrfCeilMountInfo][:multiplier] # Include tee cost for condensate line zoneCondTeeMat, zoneCondTeeLab = getHVACCost('VRF Zone Condensate Line Tees', 'PVC_tee', 0.5, true) zoneCondTeeCost = ((zoneCondTeeMat * regMat + zoneCondTeeLab * regLab) / 100) * floorTZ[:vrfCeilMountInfo][:multiplier] # Total condensate line cost zoneCondLineCost = zoneCondTubingCost + zoneCondCouplingCost + zoneCondTeeCost # Get the wiring cost zoneWiringMat, zoneWiringLab = getCost(vrfWireInfo[:name], vrfWireInfo[:hvac_material], vrfWireInfo[:multiplier]) zoneWiringCost = ((zoneWiringMat*regMatElec + zoneWiringLab*regLabElec)/100)*elecLength/100 # Get the conduit cost zoneConduitMat, zoneConduitLab = getHVACCost("VRF Zone Conduit", 'Conduit', nil, true) zoneConduitCost = ((zoneConduitMat*regMatElec + zoneConduitLab*regLabElec)/100)*elecLength # Get the total cost totalZoneCost = (zoneRefrigTubingCost + zoneCondLineCost + zoneWiringCost + zoneConduitCost + floorTZ[:vrfCeilMountCost] + floorTZ[:vrfSysContCost])*floorTZ[:tzMult] total_cost += totalZoneCost cumulCost += total_cost # Add zonal cost to report @costing_report['heating_and_cooling']['zonal_systems'] << { 'systype' => 'zonalVRF', 'zone_number' => floorTZ[:tzNum], 'zone_name' => floorTZ[:tzName], 'zone_multiple' => floorTZ[:tzMult], 'heat_capacity(kW)' => floorTZ[:tzFloorCapkW].round(1), 'cool_capacity(kW)' => floorTZ[:tzFloorCapkW].round(1), 'heat_cost' => 0.00, 'cool_cost' => 0.00, 'heatcool_cost' => ((floorTZ[:vrfCeilMountCost] + floorTZ[:vrfSysContCost]) * floorTZ[:tzMult]).round(0), 'piping_cost' => ((zoneRefrigTubingCost + zoneCondLineCost) * floorTZ[:tzMult]).round(0), 'wiring_cost' => ((zoneWiringCost + zoneConduitCost) * floorTZ[:tzMult]).round(0), 'num_units' => floorTZ[:vrfCeilMountInfo][:multiplier], 'cummultive_zonal_cost' => cumulCost.round(0) } totalFloorCapkW += floorTZ[:tzFloorCapkW] totalFloorCeilUnits += floorTZ[:vrfCeilMountInfo][:multiplier] # Determine the distribution of thermal zone multipliers on the floor. For each thermal zone on the floor get # the multiplier. If the same multiplier is already in the arry then add 1 to the number of occurrences of that # multiplier. If the multiplier is not in the array then add the multiplier to the array with an occurrence of # one. if floorMults.empty? floorMults << { zoneMult: floorTZ[:tzMult], numMults: 1 } else numFloorMult = floorMults.select{|data| data[:zoneMult] == floorTZ[:tzMult]} if numFloorMult.empty? floorMults << { zoneMult: floorTZ[:tzMult], numMults: 1 } else numFloorMult[0][:numMults] += 1 end end end # Find the number of and type of branch distributors which meet the number of ceiling unit criteria and capacity # criteria. Costing for a separate, smaller, branch distributor may be returned if multiple branch distributors # are required to meet the connection or load requirements. In this case this smaller branch distributor will # meet any connection or capacity remaining from the main equipment*(multiplier - 1). In some cases most of the # requirements may be met by the (multiplier - 1)*equipment and a much smaller piece of equipment can be used for # the remaining requipments. vrfBranchDistInfo, vrfBranchDistInfoRed= getHVACMultiSizeDBInfo(name: 'VRF Branch Distributors', materialLookup: 'VRF-Solenoid', materialCap: totalFloorCapkW, materialCon: totalFloorCeilUnits) # Get the branch distributor cost vrfBranchDistMat, vrfBranchDistLab = getCost(vrfBranchDistInfo[:name], vrfBranchDistInfo[:hvac_material], vrfBranchDistInfo[:multiplier]) vrfBranchDistCost = (vrfBranchDistMat*regMat + vrfBranchDistLab*regLab)/100 # Using the distribution of zone multipliers on the floor find which appears most often. initMaxMult = floorMults.max_by{|data| data[:numMults]} # If several different zone multipliers appear the same number of times then choose the largest zone multiplier floorMultsMatch = floorMults.select{|data| data[:numMults] == initMaxMult[:numMults]} if floorMultsMatch.size > 1 maxMult = floorMultsMatch.max_by{|data| data[:zoneMult]}[:zoneMult] else maxMult = initMaxMult[:zoneMult] end # multiply the branch distributer cost by the floor multiplier totalVRFBranchDistCost = vrfBranchDistCost*maxMult # Add branch distributor cost to report @costing_report['heating_and_cooling']['floor_systems'] << { 'systype' => 'VRFBranchDistributor', 'floor_name' => currFloor[:storyName], 'floor_multiple' => maxMult, 'heat_capacity(kW)' => totalFloorCapkW.round(1), 'cool_capacity(kW)' => totalFloorCapkW.round(1), 'num_ceiling_units' => totalFloorCeilUnits, 'heatcool_cost' => totalVRFBranchDistCost.round(0), 'num_units' => vrfBranchDistInfo[:multiplier], 'total_floor_cost' => totalVRFBranchDistCost.round(0) } total_cost += totalVRFBranchDistCost # Check if a smaller piece of equipment was found to meet the requirements remaining after removing the # (multiplier-1) requirements. unless vrfBranchDistInfoRed.nil? # Get the branch distributor cost vrfBranchDistRedMat, vrfBranchDistRedLab = getCost(vrfBranchDistInfo[:name], vrfBranchDistInfoRed[:red_ret_hash], 1.0) vrfBranchDistRedCost = (vrfBranchDistRedMat*regMat + vrfBranchDistRedLab*regLab)/100 # multiply the branch distributer cost by the floor multiplier totalVRFBranchDistRedCost = vrfBranchDistRedCost*maxMult # Add branch distributor cost to report @costing_report['heating_and_cooling']['floor_systems'] << { 'systype' => 'VRFBranchDistributor', 'floor_name' => currFloor[:storyName], 'floor_multiple' => maxMult, 'heat_capacity(kW)' => vrfBranchDistInfoRed[:numCap].to_f.round(1), 'cool_capacity(kW)' => vrfBranchDistInfoRed[:numCap].to_f.round(1), 'num_ceiling_units' => vrfBranchDistInfoRed[:numCon].to_f.round(1), 'heatcool_cost' => totalVRFBranchDistRedCost.round(0), 'num_units' => 1.0, 'total_floor_cost' => totalVRFBranchDistRedCost.round(0) } total_cost += totalVRFBranchDistRedCost end end return total_cost end |
#getZonalVRFInfo(zone:, model:, prototype_creator:, zonalSys:, vrfSystemFloors:, regMat:, regLab:, numZones:) ⇒ Object
Get information on Zonal VRF System in a Thermal Zone
1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 1856 def getZonalVRFInfo(zone:, model:, prototype_creator:, zonalSys:, vrfSystemFloors:, regMat:, regLab:, numZones:) #Get heating and cooling coil objects heatingCoil = zonalSys.heatingCoil.get.to_CoilHeatingDXVariableRefrigerantFlow.get coolingCoil = zonalSys.coolingCoil.get.to_CoilCoolingDXVariableRefrigerantFlow.get # Get heating capacity if heatingCoil.isRatedTotalHeatingCapacityAutosized.to_bool heatingCapkW = heatingCoil.autosizedRatedTotalHeatingCapacity.to_f/1000.0 else heatingCapkW = (heatingCoil.ratedTotalHeatingCapacity).to_f/1000.0 end # Get cooling capacity if coolingCoil.isRatedTotalCoolingCapacityAutosized.to_bool coolingCapkW = coolingCoil.autosizedRatedTotalCoolingCapacity.to_f/1000.0 else coolingCapkW = coolingCoil.grossRatedTotalCoolingCapacityAtSelectedNominalSpeedLevel.to_f/1000.0 end # Get the multiplier for the thermal zone zoneMult = zone.multiplier # Set capacity to the highest of the heating or cooling capacity and adjust for the thermal zone multiplier heatingCapkW >= coolingCapkW ? totalCapkW = heatingCapkW/zoneMult : totalCapkW = coolingCapkW/zoneMult # Get the thermal zone (TZ) and collect information on: # The TZ name. # The TZ capacity. # The spaces associated with the TZ. # The floors the spaces occupy. # The total ceiling area and floor area for each floor the spaces occupy. # The centroid of all of the spaces on a given floor (this may be outside of the spaces for some geometries) # The building story names and objects associated with a thermal zone. # the ceiling and floor area of the spaces associated with it for each floor they occupy # The capacity of the TZ on a given floor (calculated at total capacity * floor area of TZ spaces on floor/total TZ floor area) # The VRF ceiling mounts required and associated cost # The VRF system controllers cost tzFloorsInfo = prototype_creator.thermal_zone_get_centroid_per_floor(zone) tzFloorsInfo.each do |tzFloor| tzStoryFloorArea_m2 = 0 tzSpaceMults = [] tzFloor[:spaces].each do |tz_space| tzStoryFloorArea_m2 += tz_space.floorArea.to_f tzSpaceMults << tz_space.multiplier.to_f end tzFloorCapkW = totalCapkW * tzStoryFloorArea_m2 / zone.floorArea.to_f # Get the VRF Ceiling mount information and cost vrfCeilMountInfo = getHVACDBInfo(name: "VRF Ceiling Mount", materialLookup: "VRF-CeilingMount", materialSize: tzFloorCapkW, exactMatch: false) # Get VRF Ceiling mount cost. material, labour = getCost(vrfCeilMountInfo[:name], vrfCeilMountInfo[:hvac_material], vrfCeilMountInfo[:multiplier]) # The multiplier (number of units required to meet the demand) is already included in the material and labour cost. vrfCeilMountCost = (material*regMat + labour*regLab) / 100.0 # Get the VRF System Controller Cost (for 1 controller) material, labour = getHVACCost("VRF System Controller", 'VRF-Sys-Controller', nil, true) # Since material and labour are for 1 controller the multiplier is added here. vrfSysContCost = (material * regMat + labour * regLab) * vrfCeilMountInfo[:multiplier] / 100.0 # Put the thermal zone information for the floor into a hash. tzFloorInfo = { tzName: zone.name.to_s, tzNum: numZones, tzFloorName: tzFloor[:story_name], tzFloorCeilingAream2: tzFloor[:ceiling_area], tzMult: zoneMult, tzSpaces: tzFloor[:spaces], tzSpaceMults: tzSpaceMults, tzFloorArea_m2: tzStoryFloorArea_m2, tzFloorCapkW: tzFloorCapkW, tzCentroid: tzFloor[:centroid], vrfCeilMountInfo: vrfCeilMountInfo, vrfCeilMountCost: vrfCeilMountCost, vrfSysContCost: vrfSysContCost } # Add the TZ information for the floor to a hash containing all of the thermal zones. vrfSystemFloors = compileZonalVRFFloors(vrfSystemFloors: vrfSystemFloors, tzFloor: tzFloorInfo) end return vrfSystemFloors end |
#hrv_cost(hrv_info:, airloop:, vent_tags: [], report_mult: 1.0) ⇒ Object
This method consumes the following: hrv_info: (hash) Information about the modeled HRV. airloop: (OpenStudio Object) The OpenStudio air loop object. vent_tags: (array of strings) Tags used to associate the costing output list with whichever component of the
building is being costed.
report_mult: (float) When recreating the cost of items from the costing output list this multiplier is used to
multiply the total of the localized material and labour costs.
2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 2376 def hrv_cost(hrv_info:, airloop:, vent_tags: [], report_mult: 1.0) = .clone << "ERV duct cost" hrv_cost_tot = 0 number_zones = 0 duct_comp_search = [] # Calculate the number of thermal zones served by the ERV airloop.thermalZones.each do |tz| number_zones += tz.multiplier end # Get additional ductwork costs duct_comp_search << { mat: 'Ductwork-Fitting', unit: 'each', size: 8, mult: number_zones } hrv_cost_tot += get_comp_cost(cost_info: duct_comp_search, vent_tags: , report_mult: report_mult) .pop # Get the return air fan cost (if applicable) hrv_info[:return_cap_m3ps] >= hrv_info[:hrv_size_m3ps] ? hrv_return_flow_m3ps = 0.0 : hrv_return_flow_m3ps = hrv_info[:hrv_size_m3ps] - hrv_info[:return_cap_m3ps] << "ERV return air fan" unless hrv_return_flow_m3ps.round(2) == 0 hrv_return_flow_cfm = (OpenStudio.convert(hrv_return_flow_m3ps, 'm^3/s', 'cfm').get) if hrv_return_flow_cfm < 800 hrv_cost_tot += get_mech_costing(mech_name: 'FansDD-LP', size: hrv_return_flow_cfm, terminal: hrv_info[:hrv_data], use_mult: true, vent_tags: , report_mult: report_mult) else hrv_cost_tot += get_mech_costing(mech_name: 'FansBelt', size: hrv_return_flow_cfm, terminal: hrv_info[:hrv_data], use_mult: true, vent_tags: , report_mult: report_mult) end end .pop << "ERV with adjustment factor" hrv_size_cfm = (OpenStudio.convert(hrv_info[:hrv_size_m3ps], 'm^3/s', 'cfm').get) # Turn the HRV information into something the 'get_vent_cost_data' method expects. hrv_requirements = { cat_search: 'ERV', mech_capacity_kw: hrv_size_cfm, # This key really should just be called mech_capacity since the units vary. supply_component: hrv_info[:hrv_data] } # Get the HRV costing information hrv_mult, hrv_cost_info = get_vent_cost_data(equipment_info: hrv_requirements) # Calculate the HRV cost adjustment factor hrv_cost_adj = hrv_size_cfm*hrv_mult/(hrv_cost_info['Size'].to_f) ind_hrv_cost = get_vent_mat_cost(mat_cost_info: hrv_cost_info, vent_tags: , report_mult: hrv_cost_adj) ind_hrv_cost_rep = hrv_cost_tot + ind_hrv_cost hrv_cost_tot += ind_hrv_cost*hrv_cost_adj hrv_rep = { hrv_type: (hrv_info[:hrv_data].iddObjectType.valueName.to_s)[3..-1], hrv_name: hrv_info[:hrv_data].nameString, hrv_size_m3ps: hrv_info[:hrv_size_m3ps].round(3), hrv_return_fan_size_m3ps: hrv_return_flow_m3ps.round(3), hrv_cost: ind_hrv_cost_rep.round(2), revised_hrv_cost: hrv_cost_tot.round(2) } return hrv_rep end |
#hrv_duct_cost(prototype_creator:, roof_cent:, mech_sizing_info:, hvac_floors:) ⇒ Object
2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 2127 def hrv_duct_cost(prototype_creator:, roof_cent:, mech_sizing_info:, hvac_floors:) hrv_cost_tot = 0 mech_table = get_mech_table(mech_size_info: mech_sizing_info, table_name: 'trunk') air_system_totals = [] hrv_dist_rep = [] hvac_floors.each_with_index do |hvac_floor, floor_index| hrv_dist_rep << { floor: hvac_floor[:story_name], air_systems: [] } floor_systems = sort_tzs_by_air_system(hvac_floor: hvac_floor) floor_systems.each_with_index do |air_system, air_index| next if air_system[:sys_hrv_flow_m3ps].round(2) == 0.0 || air_system[:hrv_info][:hrv_present] == false floor_trunk_line = nil floor_air_sys = { air_system: air_system[:air_sys].nameString, hrv: air_system[:hrv_info][:hrv_data].nameString, floor_mult: 1, hrv_ret_trunk: {}, tz_dist: [], } if air_system[:num_tz] > 1 sys_floor_mult = air_system[:tz_mult]/(air_system[:num_tz]) floor_trunk_line = get_story_cent_to_edge(building_story: hvac_floor[:story], prototype_creator: prototype_creator, target_cent: roof_cent[:roof_centroid], full_length: true) hrv_trunk_cost, floor_air_sys[:hrv_ret_trunk] = get_hrv_floor_trunk_cost(mech_table: mech_table, air_system: air_system, floor_trunk_dist_m: floor_trunk_line[:end_point][:line][:dist]) hrv_cost_tot += hrv_trunk_cost*sys_floor_mult floor_air_sys[:floor_mult] = sys_floor_mult end air_system[:floor_tz].each do |floor_tz| floor_tz[:tz_floor_ret_air_m3ps] >= floor_tz[:tz_floor_outdoor_air_m3ps] ? hrv_air = 0 : hrv_air = (floor_tz[:tz_floor_outdoor_air_m3ps] - floor_tz[:tz_floor_ret_air_m3ps]).abs next if hrv_air.round(2) == 0.0 air_system_total = { dist_to_roof_m: (roof_cent[:roof_centroid][2] - floor_tz[:tz_cent][:centroid][2]).abs, hrv_air_m3ps: hrv_air*floor_tz[:tz_mult], num_systems: floor_tz[:tz_mult] } if floor_trunk_line.nil? floor_duct_coords = [roof_cent[:roof_centroid][0] - floor_tz[:tz_cent][:centroid][0], roof_cent[:roof_centroid][1] - floor_tz[:tz_cent][:centroid][1], roof_cent[:roof_centroid][2] - floor_tz[:tz_cent][:centroid][2]] floor_duct_dist_m = floor_duct_coords[0].abs + floor_duct_coords[1].abs else line = { start: floor_trunk_line[:start_point][:line][:int], end: floor_trunk_line[:end_point][:line][:int] } floor_duct_dist_m = short_dist_point_and_line(point: floor_tz[:tz_cent][:centroid], line: line).abs if floor_duct_dist_m.nil? floor_duct_dist_m = (line[:start][0] - floor_tz[:tz_cent][:centroid][0]).abs + (line[:start][1] - floor_tz[:tz_cent][:centroid][1]).abs end end if floor_duct_dist_m.round(2) > 0.1 floor_duct_dist_ft = (OpenStudio.convert(floor_duct_dist_m, 'm', 'ft').get) branch_duct_sz = mech_table.select {|sz_range| hrv_air > sz_range['max_flow_range_m3pers'][0] && hrv_air <= sz_range['max_flow_range_m3pers'][1] } branch_duct_sz << mech_table[mech_table.size-1] if branch_duct_sz.empty? duct_comp_search = [] duct_dia_in = branch_duct_sz[0]['duct_dia_inch'] duct_surface_area = floor_duct_dist_ft*(duct_dia_in.to_f/12)*Math::PI duct_comp_search << { mat: 'Ductinsulation', unit: 'ft2', size: 1.5, mult: duct_surface_area } duct_comp_search << { mat: 'Ductwork-S', unit: 'L.F.', size: duct_dia_in, mult: floor_duct_dist_ft } hrv_branch_cost = get_comp_cost(cost_info: duct_comp_search) hrv_cost_tot += hrv_branch_cost*floor_tz[:tz_mult] floor_air_sys[:tz_dist] << { tz: floor_tz[:tz].nameString, tz_mult: floor_tz[:tz_mult], hrv_ret_dist_m: floor_duct_dist_m.round(1), hrv_ret_size_in: duct_dia_in.round(2), cost: hrv_branch_cost.round(2) } end air_system_totals = add_tz_to_air_sys(air_system: air_system, air_system_total: air_system_total, air_system_totals: air_system_totals, floor_tz: floor_tz) end hrv_dist_rep[floor_index][:air_systems] << floor_air_sys end end unless air_system_totals.empty? air_system_totals.each do |air_system| next if air_system[:hrv_air_m3ps].round(2) == 0 # In addition to distance from floor to roof add 20' of duct from roof centre to box main_trunk_dist_ft = (OpenStudio.convert(air_system[:dist_to_roof_m], 'm', 'ft').get) + 20 main_trunk_sz = mech_table.select {|sz_range| air_system[:hrv_air_m3ps] > sz_range['max_flow_range_m3pers'][0] && air_system[:hrv_air_m3ps] <= sz_range['max_flow_range_m3pers'][1] } main_trunk_sz << mech_table[mech_table.size-1] if main_trunk_sz.empty? duct_comp_search = [] duct_dia_in = main_trunk_sz[0]['duct_dia_inch'] duct_surf_area_ft2 = main_trunk_dist_ft*(duct_dia_in.to_f/12)*Math::PI duct_comp_search << { mat: 'Ductinsulation', unit: 'ft2', size: 1.5, mult: duct_surf_area_ft2 } duct_comp_search << { mat: 'Ductwork-S', unit: 'L.F.', size: duct_dia_in, mult: main_trunk_dist_ft } main_trunk_cost = get_comp_cost(cost_info: duct_comp_search) hrv_cost_tot += main_trunk_cost hrv_dist_rep << { air_system: air_system[:air_system].nameString, hrv: air_system[:hrv_info][:hrv_data].nameString, hrv_building_trunk_length_m: air_system[:dist_to_roof_m].round(1), hrv_building_trunk_dia_in: duct_dia_in.round(2), cost: main_trunk_cost.round(2) } end end return hrv_cost_tot, hrv_dist_rep end |
#interpolate(x_y_array:, x2:, exterpolate_percentage_range: 30.0) ⇒ Object
Interpolate array of hashes that contain 2 values (key=rsi, data=cost)
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 183 def interpolate(x_y_array:, x2:, exterpolate_percentage_range: 30.0) ratio_range = exterpolate_percentage_range / 100.0 array = x_y_array.uniq.sort { |a, b| a[0] <=> b[0] } #if there is only one...return what you got. if array.size == 1 return array.first[1].to_f end # Check if value x2 is within range of array for interpolation # Extrapolate when x2 is out-of-range by +/- 10% of end values. if array.empty? || x2 < ((1.0 - ratio_range) * array.first[0].to_f) || x2 > ((1.0 + ratio_range) * array.last[0].to_f) return nil elsif x2 < array.first[0].to_f # Extrapolate down using first and second cost value to this out-of-range input x_array = [array[0][0].to_f, array[1][0].to_f] y_array = [array[0][1].to_f, array[1][1].to_f] linear_model = SimpleLinearRegression.new(x_array, y_array) y2 = linear_model.y_intercept + linear_model.slope * x2 return y2 elsif x2 > array.last[0].to_f # Extrapolate up using second to last and last cost value to this out-of-range input x_array = [array[-2][0].to_f, array[-1][0].to_f] y_array = [array[-2][1].to_f, array[-1][1].to_f] linear_model = SimpleLinearRegression.new(x_array, y_array) y2 = linear_model.y_intercept + linear_model.slope * x2 return y2 else array.each_index do |counter| # skip last value. next if array[counter] == array.last x0 = array[counter][0] y0 = array[counter][1] x1 = array[counter + 1][0] y1 = array[counter + 1][1] # skip to next if x2 is not between x0 and x1 next if x2 < x0 || x2 > x1 # Do interpolation y2 = y0 # just in-case x0, x1 and x2 are identical! if (x1 - x0) > 0.0 y2 = y0.to_f + ((y1 - y0).to_f * (x2 - x0).to_f / (x1 - x0).to_f) end return y2 end end end |
#line_int(line_seg:, line:, tol: 8) ⇒ Object
1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1539 def line_int(line_seg:, line:, tol: 8) line[:inf] == true && line[:int] == 1 ? x_cross = line[:slope] : x_cross = nil if line_seg[0][0].round(tol) == line_seg[1][0].round(tol) && line_seg[0][1].round(tol) == line_seg[1][1].round(tol) if x_cross.nil? y_val = line[:slope]*line_seg[0][0] + line[:int] y_val.round(tol) == line_seg[0][1].round(tol) ? (return line_seg[0]) : (return nil) else x_cross.round(tol) == line_seg[0][0].round(tol) ? (return line_seg[0]) : (return nil) end elsif line_seg[0][0].round(tol) == line_seg[1][0] if x_cross.nil? y_val = line[:slope]*line_seg[0][0] + line[:int] if (line_seg[0][1].round(tol) >= y_val.round(tol) && y_val.round(tol) >= line_seg[1][1].round(tol)) || (line_seg[0][1].round(tol) <= y_val.round(tol) && y_val.round(tol) <= line_seg[1][1].round(tol)) return [line_seg[0][0] , y_val, line_seg[0][2]] else return nil end else if x_cross.round(tol) == line_seg[0][0] y_val = (line_seg[0][1] + line_seg[1][1])/2 return [line_seg[0][0] , y_val, line_seg[0][2]] else return nil end end end lineb = get_line_eq(a: line_seg[0], b: line_seg[1], tol: tol) if lineb[:slope].round(tol) == 0 && line[:slope].round(tol) == 0 if x_cross.nil? if lineb[:int].round(tol) == line[:int].round(tol) x_val = (line_seg[0][0] + line_seg[1][0])/2 return [x_val, lineb[:slope], line_seg[0][2]] else return nil end else if (line_seg[0][0].round(tol) <= x_cross.round(tol) && x_cross.round(tol) <= line_seg[1][0].round(tol)) || (line_seg[0][0].round(tol) >= x_cross.round(tol) && x_cross.round(tol) >= line_seg[1][0].round(tol)) [x_cross, lineb[:slope]] else return nil end end end unless x_cross.nil? if (line_seg[0][0].round(tol) <= x_cross.round(tol) && x_cross.round(tol) <= line_seg[1][0].round(tol)) || (line_seg[0][0].round(tol) >= x_cross.round(tol) && x_cross.round(tol) >= line_seg[1][0].round(tol)) y_val = lineb[:slope]*x_cross + lineb[:int] return [x_cross , y_val, line_seg[0][2]] else return nil end end if lineb[:inf] == true && lineb[:int] == 1 x_int = lineb[:slope] y_int = line[:slope].to_f*x_int + line[:int].to_f else x_int = (lineb[:int].to_f - line[:int].to_f)/(line[:slope].to_f - lineb[:slope].to_f) y_int = lineb[:slope].to_f*x_int + lineb[:int].to_f end if (line_seg[0][0].round(tol) <= x_int.round(tol) && x_int.round(tol) <= line_seg[1][0].round(tol)) || (line_seg[0][0].round(tol) >= x_int.round(tol) && x_int.round(tol) >= line_seg[1][0].round(tol)) if (line_seg[0][1].round(tol) >= y_int.round(tol) && y_int.round(tol) >= line_seg[1][1].round(tol)) || (line_seg[0][1].round(tol) <= y_int.round(tol) && y_int.round(tol) <= line_seg[1][1].round(tol)) return [x_int, y_int, line_seg[0][2]] end end return nil end |
#line_seg_int(linea:, lineb:, tol: 8) ⇒ Object
1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1610 def line_seg_int(linea:, lineb:, tol: 8) if linea[0][0].round(tol) == lineb[0][0].round(tol) && linea[0][1].round(tol) == lineb[0][1].round(tol) && linea[1][0].round(tol) == lineb[1][0].round(tol) && linea[1][1].round(tol) == lineb[1][1].round(tol) return [(linea[0][0] + linea[1][0])/2 , (linea[0][1] + linea[1][1])/2] elsif linea[0][0].round(tol) == linea[1][0].round(tol) && linea[0][1].round(tol) == linea[1][1].round(tol) return linea[0] elsif lineb[0][0].round(tol) == lineb[1][0].round(tol) && lineb[0][1].round(tol) == lineb[1][1].round(tol) return lineb[0] end o1 = get_orient(p: linea[0], q: linea[1], r: lineb[0], tol: tol) o2 = get_orient(p: linea[0], q: linea[1], r: lineb[1], tol: tol) o3 = get_orient(p: lineb[0], q: lineb[1], r: linea[0], tol: tol) o4 = get_orient(p: lineb[0], q: lineb[1], r: linea[1], tol: tol) int_sect = 0 int_sect = 1 if o1 != o2 && o3 != o4 return lineb[0] if o1 == 0 && point_on_line(p: linea[0], q: lineb[0], r: linea[1], tol: tol) return lineb[1] if o2 == 0 && point_on_line(p: linea[0], q: lineb[1], r: linea[1], tol: tol) return linea[0] if o3 == 0 && point_on_line(p: lineb[0], q: linea[0], r: lineb[1], tol: tol) return linea[1] if o4 == 0 && point_on_line(p: lineb[0], q: linea[1], r: lineb[1], tol: tol) return nil if int_sect == 0 eq_linea = get_line_eq(a: linea[0], b: linea[1], tol: tol) eq_lineb = get_line_eq(a: lineb[0], b: lineb[1], tol: tol) if eq_linea[:inf] == true && eq_linea[:slope].to_f == 1 x_int = linea[0][0] y_int = eq_lineb[:slope].to_f*x_int + eq_lineb[:int].to_f return [x_int, y_int] elsif eq_lineb[:inf] == true && eq_lineb[:slope].to_f == 1 x_int = lineb[0][0] y_int = eq_linea[:slope].to_f*x_int + eq_linea[:int].to_f return [x_int, y_int] else x_int = (eq_lineb[:int].to_f - eq_linea[:int].to_f) / (eq_linea[:slope].to_f - eq_lineb[:slope].to_f) y_int = eq_lineb[:slope].to_f*x_int + eq_lineb[:int].to_f return [x_int, y_int] end end |
#load_database ⇒ Object
59 60 61 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 59 def load_database() @costing_database.load_database end |
#mech_to_roof_cost(heat_type:, cool_type:, mech_room:, roof_cent:, rt_unit_num:) ⇒ Object
933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 933 def mech_to_roof_cost(heat_type:, cool_type:, mech_room:, roof_cent:, rt_unit_num:) mech_to_roof_rep = { Gas_Line_m: 0.0, HW_Line_m: 0.0, CHW_Line_m: 0.0, Elec_Line_m: 0.0, Total_cost: 0.0 } mech_dist = [(roof_cent[:roof_centroid][0] - mech_room['space_centroid'][0]), (roof_cent[:roof_centroid][1] - mech_room['space_centroid'][1]), (roof_cent[:roof_centroid][2] - mech_room['space_centroid'][2])] utility_dist = 0 ut_search = [] rt_roof_dist = OpenStudio.convert(10, 'm', 'ft').get mech_dist.each{|dist| utility_dist+= dist.abs} utility_dist = OpenStudio.convert(utility_dist, 'm', 'ft').get heat_type.each do |key, value| if value >= 1 case key when 'HP' next when 'elec' next when 'Gas' ut_search << { mat: 'GasLine', unit: 'L.F.', size: 0, mult: utility_dist + rt_roof_dist*value } heat_type['Gas'] = 0 mech_to_roof_rep[:Gas_Line_m] == (utility_dist + rt_roof_dist*value).round(1) when 'HW' ut_search << { mat: 'SteelPipe', unit: 'L.F.', size: 4, mult: 2*utility_dist + 2*rt_roof_dist*value } mech_to_roof_rep[:HW_Line_m] = (2*utility_dist + 2*rt_roof_dist*value).round(1) ut_search << { mat: 'PipeInsulation', unit: 'none', size: 4, mult: 2*utility_dist + 2*rt_roof_dist*value } ut_search << { mat: 'PipeJacket', unit: 'none', size: 4, mult: 2*utility_dist + 2*rt_roof_dist*value } end end end cool_type.each do |key, value| if value >= 1 case key when 'DX' next when 'CHW' ut_search << { mat: 'SteelPipe', unit: 'L.F.', size: 4, mult: 2*utility_dist + 2*rt_roof_dist*value } mech_to_roof_rep[:CHW_Line_m] = (2*utility_dist + 2*rt_roof_dist*value).round(1) ut_search << { mat: 'PipeInsulation', unit: 'none', size: 4, mult: 2*utility_dist + 2*rt_roof_dist*value } ut_search << { mat: 'PipeJacket', unit: 'none', size: 4, mult: 2*utility_dist + 2*rt_roof_dist*value } end end end mech_to_roof_rep[:Elec_Line_m] = (utility_dist + rt_unit_num*rt_roof_dist).round(1) ut_search << { mat: 'Wiring', unit: 'CLF', size: 10, mult: (utility_dist + rt_unit_num*rt_roof_dist)/100 } ut_search << { mat: 'Conduit', unit: 'L.F.', size: 0, mult: utility_dist + rt_unit_num*rt_roof_dist } total_comp_cost = get_comp_cost(cost_info: ut_search) mech_to_roof_rep[:Total_cost] = total_comp_cost.round(2) return total_comp_cost, mech_to_roof_rep end |
#piping_cost(pipe_dist_m:, mech_sizing_info:, air_m3_per_s:, is_cool: false, vent_tags: [], report_mult: 1.0) ⇒ Object
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1196 def piping_cost(pipe_dist_m:, mech_sizing_info:, air_m3_per_s:, is_cool: false, vent_tags: [], report_mult: 1.0) = .clone << "piping" unless .nil? pipe_dist = OpenStudio.convert(pipe_dist_m, 'm', 'ft').get air_flow = (OpenStudio.convert(air_m3_per_s, 'm^3/s', 'L/s').get) air_flow = 15000 if air_flow > 15000 mech_table = get_mech_table(mech_size_info: mech_sizing_info, table_name: 'piping') pipe_sz_info = mech_table.select {|pipe_choice| pipe_choice['ahu_airflow_range_Literpers'][0].to_f.round(0) < air_flow.round(0) and pipe_choice['ahu_airflow_range_Literpers'][1].to_f.round(0) >= air_flow.round(0) }.first pipe_dia = pipe_sz_info['heat_valve_pipe_dia_inch'].to_f.round(2) pipe_dia = pipe_sz_info['cool_valve_pipe_dia_inch'].to_f.round(2) if is_cool == true pipe_cost_search = [] pipe_cost_search << { mat: 'Steelpipe', unit: 'L.F.', size: pipe_dia, mult: 2*pipe_dist } pipe_cost_search << { mat: 'SteelPipeElbow', unit: 'none', size: pipe_dia, mult: 2 } pipe_cost_search << { mat: 'SteelPipeTee', unit: 'none', size: pipe_dia, mult: 2 } pipe_cost_search << { mat: 'SteelPipeTeeRed', unit: 'none', size: pipe_dia, mult: 2 } pipe_cost_search << { mat: 'SteelPipeRed', unit: 'none', size: pipe_dia, mult: 2 } pipe_dia > 3 ? pipe_dia_union = 3 : pipe_dia_union = pipe_dia pipe_cost_search << { mat: 'SteelPipeUnion', unit: 'none', size: pipe_dia_union, mult: 2 } return get_comp_cost(cost_info: pipe_cost_search, vent_tags: , report_mult: report_mult) end |
#point_on_line(p:, q:, r:, tol: 8) ⇒ Object
1657 1658 1659 1660 1661 1662 1663 1664 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1657 def point_on_line(p:, q:, r:, tol: 8) q[0].round(tol) <= [p[0].round(tol), r[0].round(tol)].max ? crita = true : crita = false q[0].round(tol) >= [p[0].round(tol), r[0].round(tol)].min ? critb = true : critb = false q[1].round(tol) <= [p[1].round(tol), r[1].round(tol)].max ? critc = true : critc = false q[1].round(tol) >= [p[1].round(tol), r[1].round(tol)].min ? critd = true : critd = false return true if crita && critb && critc && critd return false end |
#read_mech_sizing ⇒ Object
283 284 285 286 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 283 def read_mech_sizing() file = File.read(@cp.mech_sizing_data_file) return JSON.parse(file) end |
#reheat_coil_costing(terminal:, tz_centroids:, model:, tz:, roof_cent:, tz_mult:, mech_sizing_info:, air_m3_per_s:, box_name:, vent_tags: [], report_mult: 1.0) ⇒ Object
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1096 def reheat_coil_costing(terminal:, tz_centroids:, model:, tz:, roof_cent:, tz_mult:, mech_sizing_info:, air_m3_per_s:, box_name:, vent_tags: [], report_mult: 1.0) = .clone coil_mat = 'none' coil_cost = 0 coil = terminal.reheatCoil case coil.iddObject.name when /Water/ coil = coil.to_CoilHeatingWater.get if coil.isRatedCapacityAutosized capacity = coil.autosizedRatedCapacity.to_f/(1000.0*tz_mult) else capacity = coil.ratedCapacity.to_f/(1000.0*tz_mult) end coil_mat = 'Coils' << "water coil" unless .empty? when /Electric/ coil = coil.to_CoilHeatingElectric.get if coil.isNominalCapacityAutosized.to_bool capacity = (coil.autosizedNominalCapacity.to_f)/(1000.0*tz_mult) else capacity = (coil.nominalCapacity.to_f)/(1000.0*tz_mult) end coil_mat = 'ElecDuct' << "electric duct heater" unless .empty? end return 0, {size_kw: 0.0, air_flow_m3_per_s: 0.0, pipe_dist_m: 0.0, elect_dist_m: 0.0, num_units: 0} if coil_mat == 'none' pipe_length_m = 0 elect_length_m = 0 num_coils = 0 tz_centroids.sort.each do |tz_cent| << tz_cent[:story_name] story_floor_area = 0 num_coils += 1 tz_cent[:spaces].each { |space| story_floor_area += space.floorArea.to_f } floor_area_frac = (story_floor_area/tz.floorArea).round(2) floor_cap = floor_area_frac*capacity coil_cost += get_mech_costing(mech_name: coil_mat, size: floor_cap, terminal: terminal, vent_tags: , report_mult: report_mult) coil_cost += get_mech_costing(mech_name: box_name, size: floor_area_frac*(OpenStudio.convert(air_m3_per_s, 'm^3/s', 'cfm').get), terminal: terminal, vent_tags: , report_mult: report_mult) ut_dist = (tz_cent[:centroid][0].to_f - roof_cent[:roof_centroid][0].to_f).abs + (tz_cent[:centroid][1].to_f - roof_cent[:roof_centroid][1].to_f).abs if coil_mat == 'Coils' pipe_length_m += ut_dist coil_cost += piping_cost(pipe_dist_m: ut_dist, mech_sizing_info: mech_sizing_info, air_m3_per_s: air_m3_per_s, vent_tags: , report_mult: report_mult) end elect_length_m += ut_dist coil_cost += vent_box_elec_cost(cond_dist_m: ut_dist, vent_tags: , report_mult: report_mult) .pop() end box_info = {size_kw: capacity.round(3), air_flow_m3_per_s: air_m3_per_s.round(3), pipe_dist_m: pipe_length_m.round(1), elect_dist_m: elect_length_m.round(1), num_units: num_coils} return coil_cost, box_info end |
#reheat_recool_cost(airloop:, prototype_creator:, model:, roof_cent:, mech_sizing_info:, vent_tags: [], report_mult: 1.0) ⇒ Object
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1033 def reheat_recool_cost(airloop:, prototype_creator:, model:, roof_cent:, mech_sizing_info:, vent_tags: [], report_mult: 1.0) = .clone heat_cost = 0 out_reheat_array = [] airloop.thermalZones.sort.each do |thermalzone| tz_mult = thermalzone.multiplier.to_f thermalzone.equipment.sort.each do |eq| tz_eq_cost = 0 terminal, box_name = get_airloop_terminal_type(eq: eq) next if box_name.nil? if terminal.isMaximumAirFlowRateAutosized.to_bool query = "SELECT Value FROM ComponentSizes WHERE CompName='#{eq.name.to_s.upcase}' AND Description='Design Size Maximum Air Flow Rate'" air_m3_per_s = model.sqlFile().get().execAndReturnFirstDouble(query).to_f/tz_mult else air_m3_per_s = terminal.maximumAirFlowRate.to_f/tz_mult end tz_centroids = prototype_creator.thermal_zone_get_centroid_per_floor(thermalzone) << thermalzone.name.to_s if box_name == 'CVMixingBoxes' << "Contant Volume Mixing Box" unless .empty? tz_eq_cost, box_info = reheat_coil_costing(terminal: terminal, tz_centroids: tz_centroids, model: model, tz: thermalzone, roof_cent: roof_cent, tz_mult: tz_mult, mech_sizing_info: mech_sizing_info, air_m3_per_s: air_m3_per_s, box_name: box_name, vent_tags: , report_mult: (tz_mult*report_mult)) .pop() else << "VAV" unless .empty? tz_eq_cost, box_info = vav_cost(terminal: terminal, tz_centroids: tz_centroids, tz: thermalzone, roof_cent: roof_cent, mech_sizing_info: mech_sizing_info, air_flow_m3_per_s: air_m3_per_s, box_name: box_name, vent_tags: , report_mult: (tz_mult*report_mult)) .pop() end .pop() heat_cost += tz_mult*tz_eq_cost out_reheat_array << { terminal: (terminal.iddObjectType.valueName.to_s)[3..-1], zone_mult: tz_mult, box_type: box_name, box_name: terminal.nameString, unit_info: box_info, cost: tz_eq_cost.round(2) } end end return heat_cost, out_reheat_array end |
#short_dist_point_and_line(point:, line:) ⇒ Object
2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 2350 def short_dist_point_and_line(point:, line:) line_eq = get_line_eq(a: line[:start], b: line[:end]) if line_eq[:int] == 1 and line_eq[:inf] == true dist = point[0] - line_eq[:slope] elsif line_eq[:int] == 0 and line_eq[:inf] == true dist = nil else # Turn equation of line as: y = slope*x + intercept # into: a*x + b*y + c = 0 # a = slope, b = -1, c = intercept a = line_eq[:slope] b = -1 c = line_eq[:int] # Use dot product to get shortest distance from point to line dist = (a*point[0] + b*point[1] + c) / Math.sqrt(a**2 + b**2) end return dist end |
#shw_costing(model, prototype_creator) ⇒ Object
This function gets all costs associated with SHW/DHW (i.e., tanks, pumps, flues, piping and utility costs)
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/openstudio-standards/btap/costing/shw_costing.rb', line 7 def shw_costing(model, prototype_creator) @costing_report['shw'] = {} totalCost = 0.0 # Get regional cost factors for this province and city materials_hvac = @costing_database["raw"]["materials_hvac"] hvac_material = materials_hvac.select {|data| data['Material'].to_s == "WaterGas"}.first # Get any row from spreadsheet in case of region error regional_material, regional_installation = get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material) # Use wiring to get regional cost factors for electrical equipment such as conduit and VFDs hvac_material_elec = get_cost_info(mat: 'Wiring', size: 14, unit: nil) regional_material_elec, regional_installation_elec = get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material_elec) # Store some geometry data for use below... util_dist, ht_roof, nominal_flr2flr_height, horizontal_dist = getGeometryData(model, prototype_creator) template_type = prototype_creator.template plant_loop_info = {} plant_loop_info[:shwtanks] = [] plant_loop_info[:shwpumps] = [] hphw_tank_names = [] num_reg_gas_tanks = 0 num_reg_oil_tanks = 0 num_elec_tanks = 0 num_hphw_tanks = 0 num_high_eff_gas_tanks = 0 num_high_eff_oil_tanks = 0 # HPHW heaters are stored outside of the plant loop # Iterate through these first to determine if their are HPHW heaters model.getWaterHeaterHeatPumps.each do |hphw| if hphw.to_WaterHeaterHeatPump.is_initialized hphw_tank_name = hphw.tank.name.get hphw_tank_names << hphw_tank_name end end # Iterate through the plant loops to get shw tank & pump data... model.getPlantLoops.each do |plant_loop| next unless plant_loop.name.get.to_s =~ /Main Service Water Loop/i plant_loop.supplyComponents.each do |supply_comp| if supply_comp.to_WaterHeaterMixed.is_initialized tank = supply_comp.to_WaterHeaterMixed.get tank_info = {} plant_loop_info[:shwtanks] << tank_info tank_info[:name] = tank.name.get tank_info[:type] = "WaterHeater:Mixed" tank_info[:heater_thermal_efficiency] = tank.heaterThermalEfficiency.get unless tank.heaterThermalEfficiency.empty? tank_info[:heater_fuel_type] = tank.heaterFuelType tank_info[:nominal_capacity] = tank.heaterMaximumCapacity.to_f / 1000 # kW tank_info[:heater_volume_gal] = (OpenStudio.convert(tank.tankVolume.to_f, 'm^3', 'gal').get) tank_info[:eff_mult] = 1.0 if tank.heaterFuelType =~ /Electric/i # Check if the tank is associated with a HPHW heater if hphw_tank_names.include?(tank.name.get) tank_info[:heater_fuel_type] = 'HPHW_Heater' tank_info[:tank_mult] = get_HVAC_multiplier(tank_info[:heater_fuel_type], tank_info[:nominal_capacity]) tank_info[:nominal_capacity] /= tank_info[:tank_mult] tank_info[:heater_volume_gal] /= tank_info[:tank_mult] num_hphw_tanks += tank_info[:tank_mult] elsif !hphw_tank_names.include?(tank.name.get) tank_info[:heater_fuel_type] = 'WaterElec' tank_info[:tank_mult] = get_HVAC_multiplier(tank_info[:heater_fuel_type], tank_info[:nominal_capacity]) tank_info[:nominal_capacity] /= tank_info[:tank_mult] tank_info[:heater_volume_gal] /= tank_info[:tank_mult] num_elec_tanks += tank_info[:tank_mult] end elsif tank.heaterFuelType =~ /NaturalGas/i tank_info[:heater_fuel_type] = 'WaterGas' tank_info[:tank_mult] = get_HVAC_multiplier(tank_info[:heater_fuel_type], tank_info[:nominal_capacity]) tank_info[:nominal_capacity] /= tank_info[:tank_mult] tank_info[:heater_volume_gal] /= tank_info[:tank_mult] if tank_info[:heater_thermal_efficiency] >= 0.85 tank_info[:heater_fuel_type] = 'WaterGas_HE' tank_info[:eff_mult] = 1.3 num_high_eff_gas_tanks += tank_info[:tank_mult] else num_reg_gas_tanks += tank_info[:tank_mult] end elsif tank.heaterFuelType =~ /Oil/i # Oil, FuelOil, FuelOil#2 tank_info[:heater_fuel_type] = 'WaterOil' tank_info[:tank_mult] = get_HVAC_multiplier(tank_info[:heater_fuel_type], tank_info[:nominal_capacity]) tank_info[:nominal_capacity] /= tank_info[:tank_mult] tank_info[:heater_volume_gal] /= tank_info[:tank_mult] if tank_info[:heater_thermal_efficiency] >= 0.85 tank_info[:heater_fuel_type] = 'WaterOil_HE' tank_info[:eff_mult] = 1.3 num_high_eff_oil_tanks += tank_info[:tank_mult] else num_reg_oil_tanks += tank_info[:tank_mult] end end elsif supply_comp.to_PumpConstantSpeed.is_initialized csPump = supply_comp.to_PumpConstantSpeed.get csPump_info = {} plant_loop_info[:shwpumps] << csPump_info csPump_info[:name] = csPump.name.get if csPump.isRatedPowerConsumptionAutosized.to_bool csPumpSize = csPump.autosizedRatedPowerConsumption.to_f else csPumpSize = csPump.ratedPowerConsumption.to_f end csPump_info[:size] = csPumpSize.to_f # Watts elsif supply_comp.to_PumpVariableSpeed.is_initialized vsPump = supply_comp.to_PumpVariableSpeed.get vsPump_info = {} plant_loop_info[:shwpumps] << vsPump_info vsPump_info[:name] = vsPump.name.get if vsPump.isRatedPowerConsumptionAutosized.to_bool vsPumpSize = vsPump.autosizedRatedPowerConsumption.to_f else vsPumpSize = vsPump.ratedPowerConsumption.to_f end vsPump_info[:size] = vsPumpSize.to_f # Watts end end end # Get costs associated with each shw tank tankCost = 0.0 ; flueCost = 0.0 ; utilCost = 0.0 ; fuelFittingCost = 0.0; fuelLineCost = 0.0 multiplier = 1.0 ; primaryFuel = ''; primaryCap = 0 plant_loop_info[:shwtanks].each do |tank| # Get primary/secondary/backup tank cost based on fuel type and capacity for each tank #set to local variables. primaryFuel = tank[:heater_fuel_type] primaryCap = tank[:nominal_capacity].to_f heaterVolGal = tank[:heater_volume_gal].to_f #Get tank cost. if primaryFuel.include?("WaterGas") # For gas fired shw tanks we don't have to bother with volume. However, we have to accept a revised tank volume # which is there for electric and oil tanks even though we won't use it. shwTankCostInfo = getSHWTankCost(name: tank[:name], materialLookup: primaryFuel, materialSize: primaryCap, tankVol: nil) tank[:nominal_cacacity] = shwTankCostInfo[:Cap_kW] else # If the SHW tank is electric or oil need to find the cost for one with a large enough capacity and volume. If # no tanks have a large enough volume then get_SHWTankCost will find the tank with the largest volume and find # how many tanks of that size are needed (multiplier). Below, if this multiplier is larger than one then # the tank volume is adjusted to be the largest one that was found (by revVol) and the tank required capacity is # reduced by dividing by the multiplier. shwTankCostInfo = getSHWTankCost(name: tank[:name], materialLookup: primaryFuel, materialSize: primaryCap, tankVol: heaterVolGal) tank[:heater_volume_gal] = shwTankCostInfo[:Vol_USGal] tank[:nominal_capacity] = shwTankCostInfo[:Cap_kW] if shwTankCostInfo[:multiplier] > 1.0 if primaryFuel.include?("WaterElec") num_elec_tanks -= tank[:tank_mult] tank[:tank_mult] *= shwTankCostInfo[:multiplier] num_elec_tanks += tank[:tank_mult] elsif primaryFuel.include?("HPHW_Heater") num_hphw_tanks -= tank[:tank_mult] tank[:tank_mult] *= shwTankCostInfo[:multiplier] num_hphw_tanks += tank[:tank_mult] else if tank[:heater_thermal_efficiency] >= 0.85 num_high_eff_oil_tanks -= tank[:tank_mult] tank[:tank_mult] *= shwTankCostInfo[:multiplier] num_high_eff_oil_tanks += tank[:tank_mult] else num_reg_oil_tanks -= tank[:tank_mult] tank[:tank_mult] *= shwTankCostInfo[:multiplier] num_reg_oil_tanks += tank[:tank_mult] end end end end matCost = shwTankCostInfo[:matCost]*tank[:tank_mult].to_f labCost = shwTankCostInfo[:labCost]*tank[:tank_mult].to_f thisTankCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 tankCost += thisTankCost # Determine power venting costs for high efficiency tanks. Doing this here because tank multiplier and capacity # may have changed. if tank[:eff_mult] > 1.1 if shwTankCostInfo[:Cap_kW] < 200 # 1/8 hp power vent materialHash = materials_hvac.find {|data| data['Material'].to_s == 'Waterheater_power_vent' && data['Size'].to_s == '0.125'} matCost, labCost = getCost('1/8 hp power vent', materialHash, multiplier) flueCost += (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * tank[:tank_mult] else # 1/2 hp power vent materialHash = materials_hvac.find {|data| data['Material'].to_s == 'Waterheater_power_vent' && data['Size'].to_s == '0.5'} matCost, labCost = getCost('1/2 hp power vent', materialHash, multiplier) flueCost += (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * tank[:tank_mult] end end end numTanks = num_elec_tanks + num_hphw_tanks + num_reg_gas_tanks + num_high_eff_gas_tanks + num_reg_oil_tanks + num_high_eff_oil_tanks numFuelTanks = num_reg_gas_tanks + num_high_eff_gas_tanks + num_reg_oil_tanks + num_high_eff_oil_tanks if numTanks > 0 # Electric utility cost components (i.e., power lines). # elec 600V #14 wire /100 ft (#848) materialHash = get_cost_info(mat: 'Wiring', size: 14) matCost, labCost = getCost('electrical wire - 600V #14', materialHash, multiplier) elecWireCost = matCost * regional_material_elec / 100.0 + labCost * regional_installation_elec / 100.0 # 1 inch metal conduit (#851) materialHash = get_cost_info(mat: 'Conduit', unit: 'L.F.') matCost, labCost = getCost('1 inch metal conduit', materialHash, multiplier) = matCost * regional_material_elec / 100.0 + labCost * regional_installation_elec / 100.0 # Electric utility wire and conduit cost used by all tanks except HPHW utilCost += ( * util_dist + elecWireCost * util_dist / 100) * (numTanks - num_hphw_tanks) # Get costs condition on fuel types. if numFuelTanks> 0 numRegFuelTanks = num_reg_gas_tanks + num_reg_oil_tanks numHighEffFuelTanks = num_high_eff_gas_tanks + num_high_eff_oil_tanks # Gas/Oil line piping cost per ft (#1) materialHash = get_cost_info(mat: 'GasLine', unit: 'L.F.') matCost, labCost = getCost('fuel line', materialHash, multiplier) fuelLineCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # Gas/Oil line fitting connection per tank (#2) materialHash = get_cost_info(mat: 'GasLine', unit: 'each') matCost, labCost = getCost('fuel line fitting connection', materialHash, multiplier) fuelFittingCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 if numRegFuelTanks > 0 # Flue and utility component costs (for gas and oil tanks only) # Calculate flue costs once for all tanks since flues combined by header when multiple tanks # 6 inch diameter flue (#384) materialHash = get_cost_info(mat: 'Venting', size: 6) matCost, labCost = getCost('flue', materialHash, multiplier) flueVentCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 #6 inch elbow fitting (#386) materialHash = get_cost_info(mat: 'VentingElbow', size: 6) matCost, labCost = getCost('flue elbow', materialHash, multiplier) flueElbowCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # 6 inch top (#392) materialHash = get_cost_info(mat: 'VentingTop', size: 6) matCost, labCost = getCost('flue top', materialHash, multiplier) flueTopCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # Adding one regular flue if any regular efficiency shw tanks are present flueCost += flueVentCost * ht_roof + flueElbowCost + flueTopCost # Header cost only non-zero if there is a secondary/backup gas/oil tank if numRegFuelTanks > 1 # Check if need a flue header (i.e., there are both primary and secondary/backup tanks) # 6 inch diameter header (#384) materialHash = get_cost_info(mat: 'Venting', size: 6) matCost, labCost = getCost('flue header', materialHash, multiplier) headerVentCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 #6 inch elbow fitting for header (#386) materialHash = get_cost_info(mat: 'VentingElbow', size: 6) matCost, labCost = getCost('flue header elbow', materialHash, multiplier) headerElbowCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # Adding a regular tank header for every additional regular efficiency SHW tank present # Assume a header length of 20 ft and an elbow fitting for each tank connected to the header flueCost += (headerVentCost * 20 + headerElbowCost) * (numRegFuelTanks - 1) end end # If high efficiency fuel fired shw tanks are present add flues (1 per tank) if numHighEffFuelTanks > 0 #6 inch PVC pipe (#1327) materialHash = get_cost_info(mat: 'Vent_pvc', size: 6) matCost, labCost = getCost('flue', materialHash, multiplier) pvcFluePipe = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) #6 inch PVC Coupling (#1319) materialHash = get_cost_info(mat: 'Vent_pvc_coupling', size: 6) matCost, labCost = getCost('flue elbow', materialHash, multiplier) pvcFlueCoupling = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # 6 inch PVC elbow (#1329) materialHash = get_cost_info(mat: 'Vent_pvc_elbow', size: 6) matCost, labCost = getCost('flue top', materialHash, multiplier) pvcFlueElbow = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # Adding PVC flue costs for all high efficiency fuel fired SHW tanks flueCost += (pvcFluePipe * 20.0 + pvcFlueCoupling + pvcFlueElbow) * numHighEffFuelTanks end # If natural gas tanks are present include fuel line and connectors if (num_reg_gas_tanks + num_reg_gas_tanks) > 0 # Gas tanks require fuel line+valves+connectors utilCost += (fuelLineCost * util_dist + fuelFittingCost) * (num_reg_gas_tanks + num_high_eff_gas_tanks) elsif (num_reg_oil_tanks + num_high_eff_oil_tanks) > 0 # Oil tanks require fuel line+valves+connectors and electrical conduit # Oil filtering system (#4) materialHash = get_cost_info(mat: 'OilLine', unit: 'each') matCost, labCost = getCost('Oil filtering system', materialHash, multiplier) oilFilterCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 # 2000 USG above ground tank (#5) materialHash = get_cost_info(mat: 'OilTanks', size: 2000) matCost, labCost = getCost('Oil tank (2000 USG)', materialHash, multiplier) oilTankCost = matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 utilCost += (fuelLineCost * util_dist + fuelFittingCost) * (num_reg_oil_tanks + num_high_eff_oil_tanks) + oilFilterCost + oilTankCost end end end # Tank pump costs pumpCost = 0.0; pipingCost = 0.0; numPumps = 0; pumpName = ''; pumpSize = 0.0 plant_loop_info[:shwpumps].each do |pump| numPumps += 1 # Cost variable and constant volume pumps the same (the difference is in extra cost for VFD controller) pumpSize = pump[:size]; pumpName = pump[:name] matCost, labCost = getHVACCost(pumpName, 'Pumps', pumpSize, false) pumpCost += matCost * regional_material / 100.0 + labCost * regional_installation / 100.0 if pump[:name] =~ /variable/i # Cost the VFD controller for the variable pump costed above pumpSize = pump[:size]; pumpName = pump[:name] matCost, labCost = getHVACCost(pumpName, 'VFD', pumpSize, false) pumpCost += matCost * regional_material_elec / 100.0 + labCost * regional_installation_elec / 100.0 end end #if numTanks > 1 && numPumps < 2 # Add pump costing for the backup tank pump. # 2024-04-25: No longer including redundant costs. #pumpCost *= 2.0 #numPumps = 2 # reset the number of pumps for piping costs below #end # Double the pump costs to accomodate the costing of a backup pumps for each tank! # 2024-04-25: No longer including redundant casts. # pumpCost *= 2.0 # Tank water piping cost: Add piping elbows, valves and insulation from the tank(s) # to the pumps(s) assuming a pipe diameter of 1” and a distance of 10 ft per pump if numTanks > 0 # 1 inch Steel pipe matCost, labCost = getHVACCost('1 inch steel pipe', 'SteelPipe', 1) pipingCost += 10.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 1 inch Steel pipe insulation matCost, labCost = getHVACCost('1 inch pipe insulation', 'PipeInsulation', 1) pipingCost += 10.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 1 inch Steel pipe elbow matCost, labCost = getHVACCost('1 inch steel pipe elbow', 'SteelPipeElbow', 1) pipingCost += 2.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # 1 inch gate valves matCost, labCost = getHVACCost('1 inch gate valves', 'ValvesGate', 1) pipingCost += 1.0 * numPumps * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) end # 2023-04-25: Removing costing for redundant equipment and piping. #if numTanks > 1 # Double pump piping cost to account for second tank # pipingCost *= 2 #end # ckirney, 2019-04-12: shw_distribution_costing mostly completed however priorities have changed for now so # completion and testing will be delayed. Adding code to master for now but it will not be called until it is # ready. # distCost = shw_distribution_costing(model: model, prototype_creator: prototype_creator) totalCost = tankCost + flueCost + utilCost + pumpCost + pipingCost @costing_report['shw'] = { 'shw_nom_flr2flr_hght_ft' => nominal_flr2flr_height.round(1), 'shw_ht_roof' => ht_roof.round(1), 'shw_longest_distance_to_ext_ft' => horizontal_dist.round(1), 'shw_utility_distance_ft' => util_dist.round(1), 'shw_tanks' => tankCost.round(2), 'shw_num_of_modeled_tanks' => plant_loop_info[:shwtanks].size, 'num_elec_tanks' => num_elec_tanks, 'num_hphw_tanks' => num_hphw_tanks, 'shw_num_reg_eff_gas_tanks' => num_reg_gas_tanks, 'shw_num_high_eff_gas_tanks' => num_high_eff_gas_tanks, 'shw_num_reg_eff_oil_tanks' => num_reg_oil_tanks, 'shw_num_high_eff_oil_tanks' => num_high_eff_oil_tanks, 'shw_num_of_costed_tanks' => numTanks, 'shw_flues' => flueCost.round(2), 'shw_utilties' => utilCost.round(2), 'shw_pumps' => pumpCost.round(2), 'shw_num_of_pumps' => plant_loop_info[:shwpumps].size, 'shw_piping' => pipingCost.round(2), 'shw_total' => totalCost.round(2) } puts "\nHVAC SHW costing data successfully generated. Total shw costs: $#{totalCost.round(2)}" return totalCost end |
#shw_distribution_costing(model:, prototype_creator:) ⇒ Object
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
# File 'lib/openstudio-standards/btap/costing/shw_costing.rb', line 404 def shw_distribution_costing(model:, prototype_creator:) total_shw_dist_cost = 0 roof_cent = prototype_creator.find_highest_roof_centre(model) mech_room, cond_spaces = prototype_creator.find_mech_room(model) min_space = get_lowest_space(spaces: cond_spaces) mech_sizing_info = read_mech_sizing() shw_sp_types = get_mech_table(mech_size_info: mech_sizing_info, table_name: 'shw_space_types') excl_sp_types = get_mech_table(mech_size_info: mech_sizing_info, table_name: 'exclusive_shw_space_types') shw_main_cost = cost_shw_main(mech_room: mech_room, roof_cent: roof_cent, min_space: min_space) total_shw_dist_cost += shw_main_cost[:cost] #determine if space is wet: prototype_creator.is_an_necb_wet_space?(space) #Sort spaces by floor and conditioned spaces space_mod = OpenstudioStandards::Space model.getBuildingStorys.sort.each do |build_story| public_wash = false other_public_wash = false build_story.spaces.sort.each do |space| next unless (space_mod.space_heated?(space) || space_mod.space_cooled?(space)) && !space_mod.space_plenum?(space) sp_type_name = space.spaceType.get.nameString shw_neccesary = shw_sp_types.select {|table_sp_type| !/#{table_sp_type.upcase}/.match(sp_type_name.upcase).nil? } if shw_neccesary.empty? public_wash = true else shw_dist_cost = get_shw_dist_cost(space: space, roof_cent: roof_cent) total_shw_dist_cost += shw_dist_cost[:cost] public_shw = excl_sp_types.select {|ex_table_sp_type| !/#{ex_table_sp_type.upcase}/.match(sp_type_name.upcase).nil? } other_public_wash = true end end if public_wash == true && other_public_wash == false #Cost two shw piping to two washrooms in the center of the story. Assume each has 20 feet of supply and return #shw piping to the story center (10 feet supply, 10 feet return). dist_ft = 40 shw_dist_search = [] shw_dist_search << { mat: 'CopperPipe', unit: 'L.F.', size: 0.75, mult: dist_ft } washroom_shw_cost = get_comp_cost(cost_info: shw_dist_search) total_shw_dist_cost += washroom_shw_cost end end return total_shw_dist_cost end |
#sort_tzs_by_air_system(hvac_floor:) ⇒ Object
2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 2250 def sort_tzs_by_air_system(hvac_floor:) floor_systems = [] hvac_floor[:floor_tz].each do |floor_tz| air_sys = floor_tz[:sys_info] next if floor_tz[:hrv_info][:hrv_present] == false floor_tz[:tz_floor_ret_air_m3ps] >= floor_tz[:tz_floor_outdoor_air_m3ps] ? hrv_ret_air_m3ps = 0 : hrv_ret_air_m3ps = (floor_tz[:tz_floor_outdoor_air_m3ps] - floor_tz[:tz_floor_ret_air_m3ps]).abs if floor_systems.empty? floor_systems << { air_sys: air_sys, sys_hrv_flow_m3ps: hrv_ret_air_m3ps, num_tz: 1, tz_mult: floor_tz[:tz_mult], hrv_info: floor_tz[:hrv_info], floor_tz: [floor_tz] } else current_sys = floor_systems.select {|floor_sys| floor_sys[:air_sys] == air_sys} if current_sys.empty? floor_systems << { air_sys: air_sys, sys_hrv_flow_m3ps: hrv_ret_air_m3ps, num_tz: 1, tz_mult: floor_tz[:tz_mult], hrv_info: floor_tz[:hrv_info], floor_tz: [floor_tz] } else current_sys[0][:sys_hrv_flow_m3ps] += hrv_ret_air_m3ps current_sys[0][:num_tz] += 1 current_sys[0][:tz_mult] += floor_tz[:tz_mult] current_sys[0][:floor_tz] << floor_tz end end end return floor_systems end |
#tz_vent_dist_cost(hvac_floors:, mech_sizing_info:) ⇒ Object
1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1963 def tz_vent_dist_cost(hvac_floors:, mech_sizing_info:) dist_reporting = [] vent_dist_cost = 0 mech_table = get_mech_table(mech_size_info: mech_sizing_info, table_name: 'tz_dist_info') flexduct_table = get_mech_table(mech_size_info: mech_sizing_info, table_name: 'flex_duct') hvac_floors.each_with_index do |hvac_floor, index| dist_reporting << { Story: hvac_floor[:story_name], thermal_zones: [] } hvac_floor[:floor_tz].each do |floor_tz| floor_vent_cost = 0 airflow_m3ps = [] airflow_m3ps << floor_tz[:tz_floor_supp_air_m3ps]*floor_tz[:floor_area_frac] airflow_m3ps << floor_tz[:tz_floor_ret_air_m3ps]*floor_tz[:floor_area_frac] if floor_tz[:tz_floor_ret_air_m3ps].to_f.round(6) > 0.0 airflow_m3ps.each_with_index do |max_air_m3ps, flow_index| # Using max supply air flow rather than breathing zone outdoor airflow. Keep breathing zone outdoor airflow in # case we change our minds. # breathing_zone_outdoor_airflow_vbz= model.sqlFile().get().execAndReturnFirstDouble("SELECT Value FROM TabularDataWithStrings WHERE ReportName='Standard62.1Summary' AND ReportForString='Entire Facility' AND TableName='Zone Ventilation Parameters' AND ColumnName='Breathing Zone Outdoor Airflow - Vbz' AND Units='m3/s' AND RowName='#{tz.nameString.to_s.upcase}' ") # bz_outdoor_airflow_m3_s = breathing_zone_outdoor_airflow_vbz.get unless breathing_zone_outdoor_airflow_vbz.empty? tz_dist_sz = mech_table.select {|size_range| max_air_m3ps > size_range['airflow_m3ps'][0] && max_air_m3ps <= size_range['airflow_m3ps'][1] } if tz_dist_sz.empty? size_range = mech_table[mech_table.size - 1] diffusers = (max_air_m3ps/size_range["diffusers"]).round(0) tz_dist_sz << { "airflow_m3ps" => size_range['airflow_m3ps'], "diffusers" => diffusers, "ducting_lbs" => (diffusers*size_range["ducting_lbs"]).round(0), "duct_insulation_ft2" => (diffusers*size_range["duct_insulation_ft2"]).round(0), "flex_duct_ft" => (diffusers*size_range["flex_duct_ft"]).round(0) } elsif tz_dist_sz[0] == mech_table[mech_table.size - 1] diffusers = (max_air_m3ps/tz_dist_sz[0]['diffusers']).round(0) tz_dist_sz[0] = { "airflow_m3ps" => tz_dist_sz[0]['airflow_m3ps'], "diffusers" => diffusers, "ducting_lbs" => (diffusers*tz_dist_sz[0]['ducting_lbs']).round(0), "duct_insulation_ft2" => (diffusers*tz_dist_sz[0]['duct_insulation_ft2']).round(0), "flex_duct_ft" => (diffusers*tz_dist_sz[0]['flex_duct_ft']).round(0) } end duct_cost_search = [] duct_cost_search << { mat: 'Diffusers', unit: 'each', size: 36, mult: tz_dist_sz[0]['diffusers'] } if tz_dist_sz[0]["ducting_lbs"] < 200 duct_cost_search << { mat: 'Ductwork', unit: 'lb.', size: 199, mult: tz_dist_sz[0]['ducting_lbs'] } else duct_cost_search << { mat: 'Ductwork', unit: 'lb.', size: 200, mult: tz_dist_sz[0]['ducting_lbs'] } end duct_cost_search << { mat: 'DuctInsulation', unit: 'ft2', size: 1.5, mult: tz_dist_sz[0]['duct_insulation_ft2'] } floor_vent_cost = get_comp_cost(cost_info: duct_cost_search)*floor_tz[:tz_mult] flex_duct_sz = flexduct_table.select {|flex_duct| max_air_m3ps > flex_duct['airflow_m3ps'][0] && max_air_m3ps <= flex_duct['airflow_m3ps'][1] } flex_duct_sz << flexduct_table[flexduct_table.size-1] if flex_duct_sz.empty? duct_cost_search = { mat: 'Ductwork-M', unit: 'L.F.', size: flex_duct_sz[0]['diameter_in'], mult: tz_dist_sz[0]['flex_duct_ft'] } duct_cost, comp_info = get_duct_cost(cost_info: duct_cost_search) floor_vent_cost += duct_cost*floor_tz[:tz_mult] vent_dist_cost += floor_vent_cost if flow_index == 0 flow_dir = 'Supply' else flow_dir = 'Return' end dist_reporting[index][:thermal_zones] << { ThermalZone: floor_tz[:tz].nameString, ducting_direction: flow_dir, tz_mult: floor_tz[:tz_mult], airflow_m3ps: max_air_m3ps.round(3), num_diff: tz_dist_sz[0]['diffusers'], ducting_lbs: tz_dist_sz[0]['ducting_lbs'], duct_insulation_ft2: tz_dist_sz[0]['duct_insulation_ft2'], flex_duct_sz_in: flex_duct_sz[0]['diameter_in'], flex_duct_length_ft: tz_dist_sz[0]['flex_duct_ft'], cost: floor_vent_cost.round(2) } end end end return vent_dist_cost, dist_reporting end |
#validate_database ⇒ Object
63 64 65 |
# File 'lib/openstudio-standards/btap/costing/btap_costing.rb', line 63 def validate_database() @costing_database.validate_database end |
#vav_cost(terminal:, tz_centroids:, tz:, roof_cent:, mech_sizing_info:, air_flow_m3_per_s:, box_name:, vent_tags: [], report_mult: 1.0) ⇒ Object
1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1147 def vav_cost(terminal:, tz_centroids:, tz:, roof_cent:, mech_sizing_info:, air_flow_m3_per_s:, box_name:, vent_tags: [], report_mult: 1.0) cost = 0 pipe_length_m = 0 elect_length_m = 0 num_coils = 0 tz_centroids.sort.each do |tz_cent| = .clone << tz_cent[:story_name] unless .empty? num_coils += 1 story_floor_area = 0 tz_cent[:spaces].each { |space| story_floor_area += space.floorArea.to_f } floor_area_frac = (story_floor_area/tz.floorArea).round(2) cost += get_mech_costing(mech_name: box_name, size: floor_area_frac*(OpenStudio.convert(air_flow_m3_per_s, 'm^3/s', 'cfm').get), terminal: terminal, vent_tags: , report_mult: report_mult) ut_dist = (tz_cent[:centroid][0].to_f - roof_cent[:roof_centroid][0].to_f).abs + (tz_cent[:centroid][1].to_f - roof_cent[:roof_centroid][1].to_f).abs if /Htg/.match(box_name) pipe_length_m += ut_dist cost += piping_cost(pipe_dist_m: ut_dist, mech_sizing_info: mech_sizing_info, air_m3_per_s: floor_area_frac*air_flow_m3_per_s, vent_tags: , report_mult: report_mult) end elect_length_m += ut_dist cost += vent_box_elec_cost(cond_dist_m: ut_dist, vent_tags: , report_mult: report_mult) end box_info = {size_kw: 0.0, air_flow_m3_per_s: air_flow_m3_per_s.round(3), pipe_dist_m: pipe_length_m.round(1), elect_dist_m: elect_length_m.round(1), num_units: num_coils} return cost, box_info end |
#vent_assembly_cost(ids:, id_quants:, overall_mult: 1.0, vent_tags: [], report_mult: 1.0) ⇒ Object
This method tokes in: ids: The list of material ids to look for in the ‘material_id’ column of the materials_hvac sheet. The number of ids should match the number of id_quants (this is checked earlier). id_quants: The number of the piece of equipment defined by the ids above required. Like ids this should be an array taken from the ‘id_layers_quantity_multipliers’ column of the ‘hvac_vent_ahu’ sheet for the air handler that matches the required criteria. The number of ids should match the number of id_quants (this is checked earlier). overall_mult: An multiplier to apply to all ids and id_quants (I’m not sure if this is used anymore). This method cycles through each of the ids and searches for it in the ‘material_id’ column of the ‘material_hvac’ sheet in the costing spreadsheet. The equipment information found in the ‘materials_hvac’ is then costed. The cost is then multiplied by the associated id_quants. For example, if the ids contains 5 elements the method searches for each one. In our example, when we get ot the 4th element of the ids we multiply its associated cost by the 4th element of the id_quants array. The total cost is then summed and multiplied by the ‘overall_mult’ and returned.
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 464 def vent_assembly_cost(ids:, id_quants:, overall_mult: 1.0, vent_tags: [], report_mult: 1.0) = .clone total_cost = 0 # Cycle through each of the ids. The index is used to select the correct element of the id_quants array. ids.each_with_index do |id, index| # Get the equipment information from the costing spreadsheet's 'material_hvac' sheet whose 'material_id' matches # the id. mat_cost_info = @costing_database['raw']['materials_hvac'].select {|data| data['material_id'].to_f.round(0) == id.to_f.round(0) }.first # If it cannot find it there is an issue with either the 'materials_hvac' sheet or the 'hvac_vent_ahu' sheet which # the user has to deal with. if mat_cost_info.nil? raise "Error: no assembly information available for material id #{id}!" end # Get the cost for the piece of equipment, multiply it by the associated id_quants element and add to the total total_cost += get_vent_mat_cost(mat_cost_info: mat_cost_info, report_mult: (overall_mult*id_quants[index].to_f*report_mult), vent_tags: )*id_quants[index].to_f end # multiply the total by the overal_mult (which is probably always 1.0 now but I'm not sure) and return the cost. return (total_cost*overall_mult) end |
#vent_box_elec_cost(cond_dist_m:, vent_tags: [], report_mult: 1.0) ⇒ Object
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1250 def vent_box_elec_cost(cond_dist_m:, vent_tags: [], report_mult: 1.0) = .clone << "electrical" unless .empty? cond_dist = OpenStudio.convert(cond_dist_m, 'm', 'ft').get elec_cost_search = [] elec_cost_search << { mat: 'Wiring', unit: 'CLF', size: 14, mult: cond_dist/100 } elec_cost_search << { mat: 'Conduit', unit: 'L.F.', size: 0, mult: cond_dist } elec_cost_search << { mat: 'Box', unit: 'none', size: 4, mult: 1 } elec_cost_search << { mat: 'Box', unit: 'none', size: 1, mult: 1 } return get_comp_cost(cost_info: elec_cost_search, vent_tags: , report_mult: report_mult) end |
#vent_trunk_duct_cost(tot_air_m3pers:, min_space:, roof_cent:, mech_sizing_info:, sys_1_4:) ⇒ Object
1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 1684 def vent_trunk_duct_cost(tot_air_m3pers:, min_space:, roof_cent:, mech_sizing_info:, sys_1_4:) sys_1_4 ? overall_mult = 1 : overall_mult = 2 duct_cost_search = [] mech_table = get_mech_table(mech_size_info: mech_sizing_info, table_name: 'trunk') max_trunk_line = mech_table.max_by {|entry| entry['max_flow_range_m3pers'][0]} tot_air_m3pers = max_trunk_line['max_flow_range_m3pers'][0].to_f.round(2) if tot_air_m3pers.round(2) > max_trunk_line['max_flow_range_m3pers'][1].to_f.round(2) trunk_sz_info = mech_table.select {|trunk_choice| trunk_choice['max_flow_range_m3pers'][0].to_f.round(2) < tot_air_m3pers.round(2) and trunk_choice['max_flow_range_m3pers'][1].to_f.round(2) >= tot_air_m3pers.round(2) }.first duct_dia = trunk_sz_info['duct_dia_inch'] duct_length_m = (roof_cent[:roof_centroid][2].to_f - min_space[:roof_cent][2].to_f).abs duct_length = (OpenStudio.convert(duct_length_m, 'm', 'ft').get) duct_cost_search << { mat: 'Ductwork-S', unit: 'L.F.', size: duct_dia, mult: duct_length*overall_mult } duct_area = (duct_dia/12)*Math::PI*duct_length*overall_mult duct_cost_search << { mat: 'Ductinsulation', unit: 'ft2', size: 1.5, mult: duct_area } duct_cost = get_comp_cost(cost_info: duct_cost_search) trunk_duct_info = { DuctSize_in: duct_dia.round(1), DuctLength_m: duct_length_m.round(1), NumberRuns: overall_mult, DuctCost: duct_cost.round(2) } return duct_cost, trunk_duct_info end |
#ventilation_costing(model, prototype_creator, template_type, mech_room, cond_spaces) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/openstudio-standards/btap/costing/ventilation_costing.rb', line 2 def ventilation_costing(model, prototype_creator, template_type, mech_room, cond_spaces) # Set up reporting hash @costing_report['ventilation'] = {system_1: [], system_2: [], system_3: [], system_4: [], system_5: [], system_6: [], system_7: [], mech_to_roof: [], trunk_duct: [], floor_trunk_ducts: [], tz_distribution: [], hrv_return_ducting: [], natural_ventilation: [], demand_controlled_ventilation: []} # Get mechanical sizing for costing information from mech_sizing.json mech_sizing_info = read_mech_sizing() # Find the mechanical room in the model and conditioned spaces - moved to btap_costing.rb # mech_room, cond_spaces = prototype_creator.find_mech_room(model) # Find the center of the highest roof in the model (this will be surrounded by roof top mechancial equipment and is where utility lines will be sent) roof_cent = prototype_creator.find_highest_roof_centre(model) # Find the lowest space in the building (trunk duct runs from here to the highest space). min_space = get_lowest_space(spaces: cond_spaces) vent_cost = 0 # Start ventilation costing vent_cost += ahu_costing(model: model, prototype_creator: prototype_creator, template_type: template_type, mech_room: mech_room, roof_cent: roof_cent, mech_sizing_info: mech_sizing_info, min_space: min_space) # natural ventilation costing nv_total_cost = cost_audit_nv(model: model, prototype_creator: prototype_creator) # demand-controlled ventilation costing dcv_cost_total = cost_audit_dcv(model: model, prototype_creator: prototype_creator) # total ventilation cost vent_cost += nv_total_cost + dcv_cost_total return vent_cost end |
#vsd_chiller_cost(primaryCap:) ⇒ Object
This method is for the calculation of VSD chiller cost
2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 2552 def vsd_chiller_cost(primaryCap:) # Gather a list of VSD chillers that exist in the costing spreadsheet vsd_chiller_sizes = [] = @costing_database['raw']['materials_hvac'].select {|data| data['Material'].to_s.upcase == 'ChillerElectricEIR_VSDCentrifugalWaterChiller'.upcase } [0..-1].each do |a,b| a.each do |key,value| vsd_chiller_sizes << value.to_f if key=='Size' end end # Look for a VSD in the list of VSDs that has the closest size, and calculate its cost vsd_chiller_closet_to_current_kw = vsd_chiller_sizes.sort_by { |item| (primaryCap-item).abs }.first(1) quantity_chiller_electric_eir = 1.0 search_chiller_electric_eir = { row_id_1: 'ChillerElectricEIR_VSDCentrifugalWaterChiller', row_id_2: vsd_chiller_closet_to_current_kw[0].to_s } sheet_name = 'materials_hvac' column_1 = 'Material' column_2 = 'Size' = ['heating_and_cooling','plant_equipment','chiller'] thisChillerCost = assembly_cost(cost_info:search_chiller_electric_eir, sheet_name:sheet_name, column_1:column_1, column_2:column_2, quantity:quantity_chiller_electric_eir, tags: ) # puts "thisVSDChillerCost is #{thisChillerCost}" return thisChillerCost end |
#zonalsys_costing(model, prototype_creator, mech_room, cond_spaces) ⇒ Object
This function gets all costs associated zonal heating and cooling systems (i.e., zonal units, pumps, flues & utility costs)
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 |
# File 'lib/openstudio-standards/btap/costing/heating_cooling_costing.rb', line 1216 def zonalsys_costing(model, prototype_creator, mech_room, cond_spaces) totalCost = 0.0 # Get regional cost factors for this province and city materials_hvac = @costing_database["raw"]["materials_hvac"] hvac_material = materials_hvac.select {|data| data['Material'].to_s == "GasBoilers"}.first # Get any row from spreadsheet in case of region error regional_material, regional_installation = get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material) # Get regional electric cost factors for this province and city hvac_material = materials_hvac.select {|data| data['Material'].to_s.upcase == "BOX" && data['Size'].to_i == 1}.first reg_mat_elec, reg_lab_elec = get_regional_cost_factors(@costing_report['province_state'], @costing_report['city'], hvac_material) # Store some geometry data for use below... util_dist, ht_roof, nom_flr_hght, horz_dist, numAGFlrs, mechRmInBsmt = getGeometryData(model, prototype_creator) template_type = prototype_creator.template zone_loop_info = {} zone_loop_info[:zonesys] = [] numZones = 0; floorNumber = 0 vrfSystemFloors = { maxCeil: -9999999999999, lowCeil: 9999999999999, vrfFloors: [] } model.getThermalZones.sort.each do |zone| numZones += 1 zone.equipment.each do |equipment| obj_type = equipment.iddObjectType.valueName.to_s if equipment.to_ZoneHVACComponent.is_initialized # This is a zonal HVAC component zone_info = {} zone_loop_info[:zonesys] << zone_info # Get floor number from zone name string using regexp (Flr-N, where N is the storey number) zone_info[:zonename] = zone.name.get zone_info[:zonename].scan(/.*Flr-(\d+).*/) {|num| zone_info[:flrnum] = num[0].to_i} unless zone.isConditioned.empty? zone_info[:is_conditioned] = zone.isConditioned.get else zone_info[:is_conditioned] = 'N/A' puts "Warning: zone.isConditioned is empty for #{zone.name.get}!" end zone_info[:multiplier] = zone.multiplier # Get the zone ceiling height value from the sql file... query = "SELECT CeilingHeight FROM Zones WHERE ZoneName='#{zone_info[:zonename].upcase}'" ceilHeight = model.sqlFile().get().execAndReturnFirstDouble(query) zone_info[:ceilingheight] = OpenStudio.convert(ceilHeight.to_f,"m","ft").get # feet zone_info[:heatcost] = 0.0 zone_info[:coolcost] = 0.0 zone_info[:heatcoolcost] = 0.0 zone_info[:pipingcost] = 0.0 zone_info[:wiringcost] = 0.0 zone_info[:multiplier] = zone.multiplier zone_info[:sysname] = equipment.name.get # Get the heat capacity values from the sql file - ZoneSizes table... query = "SELECT UserDesLoad FROM ZoneSizes WHERE ZoneName='#{zone_info[:zonename].upcase}' AND LoadType='Heating'" heatCapVal = model.sqlFile().get().execAndReturnFirstDouble(query) zone_info[:heatcapacity] = heatCapVal.to_f / 1000.0 # Watts -> kW component = equipment.to_ZoneHVACComponent.get if component.to_ZoneHVACPackagedTerminalAirConditioner.is_initialized heating_coil_name = component.to_ZoneHVACPackagedTerminalAirConditioner.get.heatingCoil.name.to_s query = "SELECT Value FROM TabularDataWithStrings WHERE ReportName='CoilSizingDetails' AND RowName='#{heating_coil_name.upcase}' AND ColumnName='Coil Final Gross Total Capacity'" zone_info[:heatcapacity] = model.sqlFile.get.execAndReturnFirstDouble(query).to_f/1000.0 cooling_coil_name = component.to_ZoneHVACPackagedTerminalAirConditioner.get.coolingCoil.name.to_s query = "SELECT Value FROM TabularDataWithStrings WHERE ReportName='CoilSizingDetails' AND RowName='#{cooling_coil_name.upcase}' AND ColumnName='Coil Final Gross Total Capacity'" zone_info[:coolcapacity] = model.sqlFile.get.execAndReturnFirstDouble(query).to_f/1000.0 elsif component.to_ZoneHVACFourPipeFanCoil.is_initialized # 2PFC & 4PFC heating_coil_name = component.to_ZoneHVACFourPipeFanCoil.get.heatingCoil.name.to_s query = "SELECT Value FROM TabularDataWithStrings WHERE ReportName='CoilSizingDetails' AND RowName='#{heating_coil_name.upcase}' AND ColumnName='Coil Final Gross Total Capacity'" zone_info[:heatcapacity] = model.sqlFile.get.execAndReturnFirstDouble(query).to_f/1000.0 cooling_coil_name = component.to_ZoneHVACFourPipeFanCoil.get.coolingCoil.name.to_s query = "SELECT Value FROM TabularDataWithStrings WHERE ReportName='CoilSizingDetails' AND RowName='#{cooling_coil_name.upcase}' AND ColumnName='Coil Final Gross Total Capacity'" zone_info[:coolcapacity] = model.sqlFile.get.execAndReturnFirstDouble(query).to_f/1000.0 elsif component.to_ZoneHVACPackagedTerminalHeatPump.is_initialized heating_coil_name = component.to_ZoneHVACPackagedTerminalHeatPump.get.heatingCoil.name.to_s query = "SELECT Value FROM TabularDataWithStrings WHERE ReportName='CoilSizingDetails' AND RowName='#{heating_coil_name.upcase}' AND ColumnName='Coil Final Gross Total Capacity'" zone_info[:heatcapacity] = model.sqlFile.get.execAndReturnFirstDouble(query).to_f/1000.0 cooling_coil_name = component.to_ZoneHVACPackagedTerminalHeatPump.get.coolingCoil.name.to_s query = "SELECT Value FROM TabularDataWithStrings WHERE ReportName='CoilSizingDetails' AND RowName='#{cooling_coil_name.upcase}' AND ColumnName='Coil Final Gross Total Capacity'" zone_info[:coolcapacity] = model.sqlFile.get.execAndReturnFirstDouble(query).to_f/1000.0 elsif component.to_ZoneHVACTerminalUnitVariableRefrigerantFlow.is_initialized # Use separate method to get zonal VRF system info zonalSys = component.to_ZoneHVACTerminalUnitVariableRefrigerantFlow.get vrfSystemFloors = getZonalVRFInfo(zone: zone, model: model, prototype_creator: prototype_creator, zonalSys: zonalSys, vrfSystemFloors: vrfSystemFloors, regMat: regional_material, regLab: regional_installation, numZones: numZones) # When done, go to the next piece of equipment. Will do VRF costing once all thermal zones are # investigated. next else cooling_coil_name = 'nil' end unless (obj_type.to_s == 'OS_ZoneHVAC_FourPipeFanCoil') || (obj_type.to_s == 'OS_ZoneHVAC_PackagedTerminalHeatPump') || (obj_type.to_s == 'OS_ZoneHVAC_PackagedTerminalAirConditioner') # Get the cooling total capacity (sen+lat) value from the sql file - ComponentSizes table query = "SELECT Value FROM ComponentSizes WHERE CompName='#{cooling_coil_name.upcase}' AND Units='W'" coolCapVal = model.sqlFile().get().execAndReturnFirstDouble(query) zone_info[:coolcapacity] = coolCapVal.to_f / 1000.0 # Watts -> kW end if (zone_info[:sysname] =~ /Baseboard Convective Water/i) or (zone_info[:sysname] =~ /BaseboardConvectiveWater/i) zone_info[:systype] = 'HW' # HW convector length based on 0.425 kW/foot if zone_info[:heatcapacity] > 0 heatCapacity = zone_info[:heatcapacity] / zone.multiplier convLength = (heatCapacity / 0.425).round(0) # HW convector 1" copper core pipe cost matCost, labCost = getHVACCost(zone_info[:sysname], 'ConvectCopper', 1.25, true) convPipeCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * convLength # For each convector there will be a shut-off valve, 2 Tee connections and 2 elbows to # isolate the convector from the hot water loop distribution for servicing and balancing. # Hot water convectors are manufactured in maximum 8 ft lengths, therefore the number of # convectors per thermal zone is (rounded up to nearest integer): ratio = (convLength.to_f / 8.0).to_f numConvectors = (ratio - ratio.to_i) > 0.10 ? (ratio + 0.5).round(0) : ratio # Cost of valves: matCost, labCost = getHVACCost('1.25 inch gate valve', 'ValvesGate', 1.25, true) convValvesCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * numConvectors # Cost of tees: matCost, labCost = getHVACCost('1.25 inch copper tees', 'CopperPipeTee', 1.25, true) convTeesCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * 2 * numConvectors # Cost of elbows: matCost, labCost = getHVACCost('1.25 inch copper elbows', 'CopperPipeElbow', 1.25, true) convElbowsCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * 2 * numConvectors # Total convector cost for this zone (excluding distribution piping): convCost = (convPipeCost + convValvesCost + convTeesCost + convElbowsCost) * zone.multiplier zone_info[:heatcost] = convCost zone_info[:num_units] = numConvectors # Single pipe supply and return perimPipingCost = getPerimDistPipingCost(zone, nom_flr_hght, regional_material, regional_installation) zone_info[:pipingcost] = perimPipingCost totalCost += convCost + perimPipingCost end elsif (zone_info[:sysname]=~ /Baseboard Convective Electric/i) or (zone_info[:sysname]=~ /BaseboardConvectiveElectric/i) zone_info[:systype] = 'BB' # BB number based on 0.935 kW/unit if zone_info[:heatcapacity] > 0 heatCapacity = zone_info[:heatcapacity] / zone.multiplier ratio = (heatCapacity / 0.935).to_f numConvectors = (ratio - ratio.to_i) > 0.10 ? (ratio + 0.5).round(0) : ratio # BB electric convector unit cost (Just one in sheet) matCost, labCost = getHVACCost(zone_info[:sysname], 'ElectricBaseboard', 'nil', true) elecBBCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * numConvectors # For each baseboard there will be an electrical junction box matCost, labCost = getHVACCost('Electrical Outlet Box', 'Box', 1, true) elecBoxCost = (matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0) * numConvectors # Total electric basbeboard cost for this zone: elecConvCost = (elecBBCost + elecBoxCost) * zone.multiplier zone_info[:heatcost] = elecConvCost zone_info[:num_units] = numConvectors perimWiringCost = getPerimDistWiringCost(zone, nom_flr_hght, reg_mat_elec, reg_lab_elec) zone_info[:wiringcost] = perimWiringCost totalCost += elecConvCost + perimWiringCost end elsif (zone_info[:sysname] =~ /PTAC/i) || (obj_type.to_s == 'OS_ZoneHVAC_PackagedTerminalAirConditioner') zone_info[:systype] = 'PTAC' # Heating cost of PTAC is handled by Baseboard Convective Electric Heater entry in Equipment list! # Cooling cost of PTAC ... if zone_info[:coolcapacity] > 0 # DX cooling unit coolCapacity = zone_info[:coolcapacity] / zone.multiplier numUnits = get_HVAC_multiplier('PTAC', coolCapacity) # PTAC unit cost (Note that same numUnits multiple applied within getHVACCost()) matCost, labCost = getHVACCost(zone_info[:sysname], 'PTAC', coolCapacity, false) thePTACUnitCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # For each PTAC unit there will be an electrical junction box (wiring costed with distribution - not here) matCost, labCost = getHVACCost('Electrical Outlet Box', 'Box', 1, true) elecBoxCost = (matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0) * numUnits # Total PTAC cost for this zone (excluding distribution piping): thePTACCost = (thePTACUnitCost + elecBoxCost) * zone.multiplier zone_info[:coolcost] = thePTACCost zone_info[:num_units] = numUnits perimWiringCost = getPerimDistWiringCost(zone, nom_flr_hght, reg_mat_elec, reg_lab_elec) zone_info[:wiringcost] = perimWiringCost totalCost += thePTACCost + perimWiringCost end elsif (zone_info[:sysname] =~ /PTHP/i) || (obj_type.to_s =~ /OS_ZoneHVAC_PackagedTerminalHeatPump/) zone_info[:systype] = 'HP' # Cost of PTAC based on heating capacity... if zone_info[:heatcapacity] > 0 # DX heat pump unit capacityHPUnit = zone_info[:coolcapacity] > zone_info[:heatcapacity] ? zone_info[:coolcapacity] / zone.multiplier : zone_info[:heatcapacity] / zone.multiplier numUnits = get_HVAC_multiplier('ashp', capacityHPUnit) # HP unit cost (Note that same numUnits multiple applied within getHVACCost()) matCost, labCost = getHVACCost(zone_info[:sysname], 'ashp', capacityHPUnit, false) theHPUnitCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # For each HP unit there will be an electrical junction box (wiring costed with distribution - not here) matCost, labCost = getHVACCost('Electrical Outlet Box', 'Box', 1, true) elecBoxCost = (matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0) * numUnits # Total HP cost for this zone (excluding distribution piping): theHPCost = (theHPUnitCost + elecBoxCost) * zone.multiplier zone_info[:heatcoolcost] = theHPUnitCost zone_info[:num_units] = numUnits perimWiringCost = getPerimDistWiringCost(zone, nom_flr_hght, reg_mat_elec, reg_lab_elec) zone_info[:wiringcost] = perimWiringCost totalCost += theHPCost + perimWiringCost end elsif zone_info[:sysname] =~ /2-pipe Fan Coil/i zone_info[:sfurnaceystype] = '2FC' if zone_info[:heatcapacity] > 0 || zone_info[:coolcapacity] > 0 # Hot water heating and chilled water cooling type fan coil unit capacityFCUnit = zone_info[:coolcapacity] > zone_info[:heatcapacity] ? zone_info[:coolcapacity] / zone.multiplier : zone_info[:heatcapacity] / zone.multiplier numFCUnits = get_HVAC_multiplier('FanCoilHtgClgVent', capacityFCUnit) # 2PFC unit cost (Note that same numFCUnits multiple applied within getHVACCost()) matCost, labCost = getHVACCost(zone_info[:sysname], 'FanCoilHtgClgVent', capacityFCUnit, false) fcUnitCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # For each 2PFC unit there will be a shut-off valve, 2 Tee connections and 2 elbows to # isolate the convector from the hot water loop distribution for servicing and balancing. # Assumed unit piping is 1.25 inches in diameter. # Cost of valves: matCost, labCost = getHVACCost('1.25 inch gate valve', 'ValvesGate', 1.25, true) fcValvesCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * numFCUnits # Cost of tees: matCost, labCost = getHVACCost('1.25 inch copper tees', 'CopperPipeTee', 1.25, true) fcTeesCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * 2 * numFCUnits # Cost of elbows: matCost, labCost = getHVACCost('1.25 inch copper elbows', 'CopperPipeElbow', 1.25, true) fcElbowsCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * 2 * numFCUnits # For each 2PFC unit there will be an electrical junction box (wiring costed with distribution - not here) matCost, labCost = getHVACCost('Electrical Outlet Box', 'Box', 1, true) elecBoxCost = (matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0) * numFCUnits # Total 2PFC cost for this zone (excluding distribution piping): fcCost = (fcUnitCost + fcValvesCost + fcTeesCost + fcElbowsCost + elecBoxCost) * zone.multiplier zone_info[:heatcoolcost] = fcCost zone_info[:num_units] = numFCUnits # Cost for one set supply/return piping perimPipingCost = getPerimDistPipingCost(zone, nom_flr_hght, regional_material, regional_installation) zone_info[:pipingcost] = perimPipingCost perimWiringCost = getPerimDistWiringCost(zone, nom_flr_hght, reg_mat_elec, reg_lab_elec) zone_info[:wiringcost] = perimWiringCost totalCost += fcCost + perimPipingCost + perimWiringCost end elsif (zone_info[:sysname] =~ /4-pipe Fan Coil/i) || (obj_type =~ /OS_ZoneHVAC_FourPipeFanCoil/) zone_info[:systype] = '4FC' if (zone_info[:heatcapacity] > 0) || (zone_info[:coolcapacity] > 0) # Hot water heating and chilled water cooling type fan coil unit capacityFCUnit = zone_info[:coolcapacity] > zone_info[:heatcapacity] ? zone_info[:coolcapacity] / zone.multiplier : zone_info[:heatcapacity] / zone.multiplier numFCUnits = get_HVAC_multiplier('FanCoilHtgClgVent', capacityFCUnit) # 4PFC unit cost (Note that same numFCUnits multiple applied within getHVACCost()) matCost, labCost = getHVACCost(zone_info[:sysname], 'FanCoilHtgClgVent', capacityFCUnit, false) fcUnitCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # For each 4PFC unit there will be 2 shut-off valves, 4 Tee connections and 4 elbows to # isolate the convector from the hot water loop distribution for servicing and balancing. # Assumed unit piping is 1.25 inches in diameter. # Cost of valves: matCost, labCost = getHVACCost('1.25 inch gate valve', 'ValvesGate', 1.25, true) fcValvesCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * 2 * numFCUnits # Cost of tees: matCost, labCost = getHVACCost('1.25 inch copper tees', 'CopperPipeTee', 1.25, true) fcTeesCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * 4 * numFCUnits # Cost of elbows: matCost, labCost = getHVACCost('1.25 inch copper elbows', 'CopperPipeElbow', 1.25, true) fcElbowsCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * 4 * numFCUnits # For each 4PFC unit there will be an electrical junction box (wiring costed with distribution - not here) matCost, labCost = getHVACCost('Electrical Outlet Box', 'Box', 1, true) elecBoxCost = (matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0) * numFCUnits # Total 4PFC cost for this zone (excluding distribution piping): fcCost = (fcUnitCost + fcValvesCost + fcTeesCost + fcElbowsCost + elecBoxCost) * zone.multiplier zone_info[:heatcoolcost] = fcCost zone_info[:num_units] = numFCUnits # Cost for two sets supply/return piping perimPipingCost = 2 * getPerimDistPipingCost(zone, nom_flr_hght, regional_material, regional_installation) zone_info[:pipingcost] = perimPipingCost perimWiringCost = getPerimDistWiringCost(zone, nom_flr_hght, reg_mat_elec, reg_lab_elec) zone_info[:wiringcost] = perimWiringCost totalCost += fcCost + perimPipingCost + perimWiringCost end elsif zone_info[:sysname] =~ /Unit Heater/i || zone_info[:sysname] =~ /Unitary/i zone_info[:systype] = 'FUR' # Two types of unit heaters: electric and gas unitHeater = component.to_ZoneHVACUnitHeater.get heatCoil = unitHeater.heatingCoil if heatCoil.to_CoilHeatingGas.is_initialized # TODO: Need to test this! # The gas unit heaters are cabinet type with a burner and blower rather than the radiant type gasCoil = heatCoil.to_CoilHeatingGas.get if heatCoil.isNominalCapacityAutosized.to_bool zone_info[:heatcapacity] = gasCoil.autosizedNominalCapacity.to_f/1000.0 else zone_info[:heatcapacity] = gasCoil.nominalCapacity.to_f/1000.0 end if zone_info[:heatcapacity] > 0 heatCapacity = zone_info[:heatcapacity] / zone.multiplier numUnits = get_HVAC_multiplier('gasheater', heatCapacity) # Unit cost (Note that same unit multiple applied within getHVACCost()) matCost, labCost = getHVACCost(zone_info[:sysname], 'gasheater', heatCapacity, false) unitCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # For each unit heater there will be an electrical junction box (wiring costed with distribution - not here) matCost, labCost = getHVACCost('Electrical Outlet Box', 'Box', 1, true) elecBoxCost = (matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0) * numUnits # It is assumed that the gas unit heater(s) are located in the centre of this zone. An 8 in exhaust duct # must be costed from the unit heater to the exterior via the roof. The centroid of this zone: if zone_info[:flrnum] > 1 zoneCentroidToRoof_Ft = 10 + nom_flr_hght * zone_info[:flrnum] else zoneCentroidToRoof_Ft = 10 end matCost, labCost = getHVACCost('Unit heater exhaust duct', 'Ductwork-S', 8, true) exhaustductCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * zoneCentroidToRoof_Ft zone_info[:heatcost] = (unitCost + elecBoxCost + exhaustductCost) * zone.multiplier zone_info[:num_units] = numUnits # Cost of gas line header for zone. Header is located in the centre of this zone's floor mechRmInBsmt ? numFlrs = numAGFlrs + 1 : numFlrs = numAGFlrs hdrGasLen = numFlrs * nom_flr_hght # Gas line - first one in spreadsheet matCost, labCost = getHVACCost('Central header gas line', 'GasLine', '') hdrGasLineCost = hdrGasLen * (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # Cost of gas line from header (centre of flr) to unit heater (centre of zone) #centreOfFloor = get_story_cent_to_edge( building_story: zone_info[:flrnum], prototype_creator: prototype_creator, target_cent: target_cent, full_length: false ) #centreOfSpace = get_space_floor_centroid(space:) #gasLineLen = ABS(centreOfFloor - centreOfSpace) # Cost of wiring header for zone # Cost of wiring from header to unit heater totalCost += zone_info[:heatcost] + hdrGasLineCost end elsif heatCoil.to_CoilHeatingElectric.is_initialized # Electric Unit Heater elecCoil = heatCoil.to_CoilHeatingElectric.get if elecCoil.isNominalCapacityAutosized.to_bool zone_info[:heatcapacity] = elecCoil.autosizedNominalCapacity.to_f/1000.0 else zone_info[:heatcapacity] = elecCoil.nominalCapacity.to_f/1000.0 end if zone_info[:heatcapacity] > 0 heatCapacity = zone_info[:heatcapacity] / zone.multiplier numUnits = get_HVAC_multiplier('elecheat', heatCapacity) # Unit cost (Note that same unit multiple applied within getHVACCost()) matCost, labCost = getHVACCost(zone_info[:sysname], 'elecheat', heatCapacity, false) unitCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # For each unit heater there will be an electrical junction box (wiring costed with distribution - not here) matCost, labCost = getHVACCost('Electrical Outlet Box', 'Box', 1, true) elecBoxCost = (matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0) * numUnits zone_info[:heatcost] = (unitCost + elecBoxCost) * zone.multiplier zone_info[:num_units] = numUnits # Cost of wiring to electric unit heater totalCost += zone_info[:heatcost] end elsif heatCoil.to_CoilHeatingWater.is_initialized # Hot water unit heater waterCoil = heatCoil.to_CoilHeatingWater.get if waterCoil.isRatedCapacityAutosized.to_bool zone_info[:heatcapacity] = waterCoil.autosizedRatedCapacity.to_f/1000.0 else zone_info[:heatcapacity] = waterCoil.ratedCapacity.to_f/1000.0 end if zone_info[:heatcapacity] > 0 heatCapacity = zone_info[:heatcapacity] / zone.multiplier # Max capacity for hot water heater is 75300 Watts numUnits = get_HVAC_multiplier('hotwateruh', heatCapacity) matCost, labCost = getHVACCost(zone_info[:sysname], 'hotwateruh', heatCapacity, false) unitHtrCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # For each unit heater there will be a shut-off valve, 2 Tee connections and 2 elbows to # isolate the convector from the hot water loop distribution for servicing and balancing. # Cost of valves: matCost, labCost = getHVACCost('1.25 inch gate valve', 'ValvesGate', 1.25, true) unitHtrValvesCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * numUnits # Cost of tees: matCost, labCost = getHVACCost('1.25 inch copper tees', 'CopperPipeTee', 1.25, true) unitHtrTeesCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * 2 * numUnits # Cost of elbows: matCost, labCost = getHVACCost('1.25 inch copper elbows', 'CopperPipeElbow', 1.25, true) unitHtrElbowsCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) * 2 * numUnits # For each unit heater there will be an electrical junction box (wiring costed with distribution - not here) matCost, labCost = getHVACCost('Electrical Outlet Box', 'Box', 1, true) elecBoxCost = (matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0) * numUnits # Total convector cost for this zone (excluding distribution piping): unitHeaterCost = (unitHtrCost + unitHtrValvesCost + unitHtrTeesCost + unitHtrElbowsCost + elecBoxCost) * zone.multiplier zone_info[:heatcost] = unitHeaterCost zone_info[:num_units] = numUnits # Cost of distribution piping from header to unit heater totalCost += unitHeaterCost end end elsif zone_info[:sysname] =~ /WindowAC/i zone_info[:systype] = 'WinAC' # Cooling cost of WindowAC ... if cooling_coil_name == 'nil' # The cooling coil name doesn't exist so must use a different method to determine cooling # capacity for window AC units! query = "SELECT Value FROM ComponentSizes WHERE CompName='WindowAC' AND Units='W'" coolCapVal = model.sqlFile().get().execAndReturnFirstDouble(query) zone_info[:coolcapacity] = coolCapVal.to_f / 1000.0 # Watts -> kW end if zone_info[:coolcapacity] > 0 # DX cooling unit coolCapacity = zone_info[:coolcapacity] / zone.multiplier numUnits = get_HVAC_multiplier('WINAC', coolCapacity) # Window AC unit cost (Note that same numUnits multiple applied within getHVACCost()) matCost, labCost = getHVACCost(zone_info[:sysname], 'WINAC', coolCapacity, false) unitWinACCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # For each WinAC unit there will be an electrical junction box (wiring costed with distribution - not here) matCost, labCost = getHVACCost('Electrical Outlet Box', 'Box', 1, true) elecBoxCost = (matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0) * numUnits # Total WinAC cost for this zone: theWinACCost = (unitWinACCost + elecBoxCost) * zone.multiplier zone_info[:coolcost] = theWinACCost zone_info[:num_units] = numUnits totalCost += theWinACCost end elsif zone_info[:sysname] =~ /Split/i zone_info[:systype] = 'MiniSplit' # Cooling cost of Mini-split AC ... if cooling_coil_name == 'nil' # The cooling coil name doesn't exist so must use a different method to determine cooling # capacity for mini-spli units! query = "SELECT Value FROM ComponentSizes WHERE CompName='WindowAC' AND Units='W'" coolCapVal = model.sqlFile().get().execAndReturnFirstDouble(query) zone_info[:coolcapacity] = coolCapVal.to_f / 1000.0 # Watts -> kW end if zone_info[:coolcapacity] > 0 # Mini-splt cooling unit coolCapacity = zone_info[:coolcapacity] / zone.multiplier numUnits = get_HVAC_multiplier('SplitSZWall', coolCapacity) # PTAC unit cost (Note that same numUnits multiple applied within getHVACCost()) matCost, labCost = getHVACCost(zone_info[:sysname], 'PTAC', coolCapacity, false) theMiniSplitUnitCost = (matCost * regional_material / 100.0 + labCost * regional_installation / 100.0) # For each PTAC unit there will be an electrical junction box (wiring costed with distribution - not here) matCost, labCost = getHVACCost('Electrical Outlet Box', 'Box', 1, true) elecBoxCost = (matCost * reg_mat_elec / 100.0 + labCost * reg_lab_elec / 100.0) * numUnits # Total PTAC cost for this zone (excluding distribution piping): theMiniSplitCost = (theMiniSplitUnitCost + elecBoxCost) * zone.multiplier zone_info[:coolcost] = theMiniSplitCost zone_info[:num_units] = numUnits totalCost += theMiniSplitCost end end # Add information to zonal costing report. @costing_report['heating_and_cooling']['zonal_systems'] << { 'systype' => zone_info[:systype], 'zone_number' => numZones, 'zone_name' => zone_info[:zonename], 'zone_multiple' => zone_info[:multiplier], 'heat_capacity(kW)' => zone_info[:heatcapacity].round(1), 'cool_capacity(kW)' => zone_info[:coolcapacity].round(1), 'heat_cost' => zone_info[:heatcost].round(0), 'cool_cost' => zone_info[:coolcost].round(0), 'heatcool_cost' => zone_info[:heatcoolcost].round(0), 'piping_cost' => zone_info[:pipingcost].round(0), 'wiring_cost' => zone_info[:wiringcost].round(0), 'num_units' => zone_info[:num_units], 'cummultive_zonal_cost' => totalCost.round(0) } end # End of check of check of if zonal equipment exists end # End of equipment loop end # End of zone loop # Get cost of zonal vrf systems unless vrfSystemFloors[:vrfFloors].empty? totalCost += getZonalVRFCosting(vrfSystemFloors: vrfSystemFloors, model: model, prototype_creator: prototype_creator, regMat: regional_material, regLab: regional_installation, cumulCost: totalCost) end puts "\nZonal systems costing data successfully generated. Total zonal systems costs: $#{totalCost.round(0)}" return totalCost end |