Module: OpenstudioStandards::Refrigeration

Defined in:
lib/openstudio-standards/refrigeration/create_case.rb,
lib/openstudio-standards/refrigeration/information.rb,
lib/openstudio-standards/refrigeration/create_walkin.rb,
lib/openstudio-standards/refrigeration/create_compressor.rb,
lib/openstudio-standards/refrigeration/create_compressor_rack.rb,
lib/openstudio-standards/refrigeration/create_refrigeration_system.rb,
lib/openstudio-standards/refrigeration/create_typical_refrigeration.rb

Overview

The Refrigeration module provides methods to create, modify, and get information about refrigeration

Create Case collapse

Information collapse

Create Walkin collapse

Create Refrigeration Compressor collapse

Create Refrigeration Compressor Rack collapse

Create Refrigeration System collapse

Create Typical Refrigeration collapse

Class Method Details

.create_case(model, template: 'new', case_type: 'Vertical Open - All', case_length: nil, defrost_schedule: nil, defrost_start_hour: 0, dripdown_schedule: nil, thermal_zone: nil) ⇒ OpenStudio::Model::RefrigerationCase

Adds a refrigerated case to the model.

Parameters:

  • model (OpenStudio::Model::Model)

    OpenStudio model object

  • template (String) (defaults to: 'new')

    Technology or standards level, either ‘old’, ‘new’, or ‘advanced’

  • case_type (String) (defaults to: 'Vertical Open - All')

    The case type. See refrigeration_cases data for valid options under case_name.

  • case_length (String) (defaults to: nil)

    The case length in meters.

  • defrost_schedule (OpenStudio::Model::Schedule) (defaults to: nil)

    OpenStudio Schedule object with boolean values for the defrost schedule

  • defrost_start_hour (Double) (defaults to: 0)

    Start hour between 0 and 24 for. Used if defrost_schedule not specified.

  • dripdown_schedule (OpenStudio::Model::Schedule) (defaults to: nil)

    OpenStudio Schedule object with boolean values for the dripdown schedule

  • thermal_zone (OpenStudio::Model::ThermalZone) (defaults to: nil)

    Thermal zone with the case. If nil, will look up from the model.

Returns:

  • (OpenStudio::Model::RefrigerationCase)

    the refrigeration case



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
# File 'lib/openstudio-standards/refrigeration/create_case.rb', line 18

def self.create_case(model,
                     template: 'new',
                     case_type: 'Vertical Open - All',
                     case_length: nil,
                     defrost_schedule: nil,
                     defrost_start_hour: 0,
                     dripdown_schedule: nil,
                     thermal_zone: nil)
  # get thermal zone if not provided

  if thermal_zone.nil?
    # Find the thermal zones most suited for holding the display cases

    thermal_zone = OpenstudioStandards::Refrigeration.refrigeration_case_zone(model)
    if thermal_zone.nil?
      OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', 'Attempted to add display cases to the model, but could find no thermal zone to put them into.')
      return nil
    end
  end

  # load refrigeration cases data

  cases_csv = "#{File.dirname(__FILE__)}/data/refrigerated_cases.csv"
  unless File.file?(cases_csv)
    OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Unable to find file: #{cases_csv}")
    return nil
  end
  cases_tbl = CSV.table(cases_csv, encoding: 'ISO8859-1:utf-8')
  cases_hsh = cases_tbl.map(&:to_hash)

  # get case properties

  case_properties = cases_hsh.select { |r| (r[:template] == template) && (r[:case_name] == case_type) }[0]

  if case_properties.nil?
    OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Unable to find case data for template #{template} case type #{case_type}.")
    return nil
  end

  # add case

  ref_case = OpenStudio::Model::RefrigerationCase.new(model, model.alwaysOnDiscreteSchedule)
  ref_case.setName(case_type)
  case_length_m = case_length.nil? ? case_properties[:unit_length] : case_length
  ref_case.setCaseLength(case_length_m)
  ref_case.setRatedTotalCoolingCapacityperUnitLength(case_properties[:rated_capacity])
  ref_case.setCaseOperatingTemperature(case_properties[:case_operating_temperature])
  ref_case.setDesignEvaporatorTemperatureorBrineInletTemperature(case_properties[:evaporator_temperature])
  ref_case.setRatedLatentHeatRatio(case_properties[:rated_latent_heat_ratio])
  ref_case.setRatedRuntimeFraction(case_properties[:rated_runtime_fraction])
  ref_case.setLatentCaseCreditCurveType(case_properties[:latent_case_credit_curve_type])
  # TODO: replace once curves are standardized

  std = Standard.build('90.1-2013')
  latent_case_credit_curve = std.model_add_curve(model, case_properties[:latent_case_credit_curve_name])
  ref_case.setLatentCaseCreditCurve(latent_case_credit_curve)
  ref_case.setStandardCaseFanPowerperUnitLength(case_properties[:fan_power])
  ref_case.setOperatingCaseFanPowerperUnitLength(case_properties[:fan_power])
  ref_case.setStandardCaseLightingPowerperUnitLength(case_properties[:lighting_power])
  ref_case.setInstalledCaseLightingPowerperUnitLength(case_properties[:lighting_power])
  ref_case.setCaseLightingSchedule(model.alwaysOnDiscreteSchedule)
  ref_case.setFractionofLightingEnergytoCase(case_properties[:fraction_of_lighting_energy_to_case]) unless case_properties[:fraction_of_lighting_energy_to_case].nil?
  ref_case.setCaseAntiSweatHeaterPowerperUnitLength(case_properties[:anti_sweat_power]) unless case_properties[:anti_sweat_power].nil?
  ref_case.setMinimumAntiSweatHeaterPowerperUnitLength(0.0)
  ref_case.setHumidityatZeroAntiSweatHeaterEnergy(0.0)
  ref_case.setAntiSweatHeaterControlType(case_properties[:anti_sweat_heater_control_type])
  ref_case.setFractionofAntiSweatHeaterEnergytoCase(case_properties[:fraction_of_anti_sweat_heater_energy_to_cases]) unless case_properties[:fraction_of_anti_sweat_heater_energy_to_cases].nil?
  ref_case.setCaseDefrostPowerperUnitLength(case_properties[:defrost_power]) unless case_properties[:defrost_power].nil?
  ref_case.setCaseDefrostType(case_properties[:defrost_type])
  ref_case.setDefrostEnergyCorrectionCurveType(case_properties[:defrost_energy_correction_curve_type]) unless case_properties[:defrost_energy_correction_curve_type].nil?
  unless case_properties[:defrost_energy_correction_curve_name].nil?
    # TODO: replace once curves are standardized

    defrost_correction_curve_name = std.model_add_curve(model, case_properties[:defrost_energy_correction_curve_name])
    ref_case.setDefrostEnergyCorrectionCurve(defrost_correction_curve_name)
  end
  ref_case.setUnderCaseHVACReturnAirFraction(0.0)
  ref_case.resetRefrigeratedCaseRestockingSchedule
  ref_case.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
  ref_case.setThermalZone(thermal_zone)
  ref_case.setRatedAmbientTemperature(OpenStudio.convert(75.0, 'F', 'C').get)

  # only add defrost schedules if not OffCycle

  unless case_properties[:defrost_type] == 'OffCycle'
    # defrost properties, default to one 45 minute defrost cycle per day followed by a 5 minute dripdown duration

    defrost_duration = case_properties[:defrost_duration].nil? ? 45 : case_properties[:defrost_duration]
    defrosts_per_day = case_properties[:defrosts_per_day].nil? ? 1 : case_properties[:defrosts_per_day]
    dripdown_duration = case_properties[:dripdown_duration].nil? ? 5 : case_properties[:dripdown_duration]

    # defrost hours are calculated from the start hour and number of defrosts per day

    defrost_interval = (24 / defrosts_per_day).floor
    defrost_hours = (1..defrosts_per_day).map { |i| defrost_start_hour + ((i - 1) * defrost_interval) }
    defrost_hours.map! { |hr| hr > 23 ? hr - 24 : hr }
    defrost_hours.sort!

    # Defrost schedule

    if defrost_schedule.nil?
      defrost_schedule = OpenStudio::Model::ScheduleRuleset.new(model)
      defrost_schedule.setName("#{ref_case.name} Defrost")
      defrost_schedule.defaultDaySchedule.setName("#{ref_case.name} Defrost Default")
      defrost_hours.each do |defrost_hour|
        defrost_schedule.defaultDaySchedule.addValue(OpenStudio::Time.new(0, defrost_hour, 0, 0), 0)
        defrost_schedule.defaultDaySchedule.addValue(OpenStudio::Time.new(0, defrost_hour, defrost_duration, 0), 1)
      end
      defrost_schedule.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0)
    else
      unless defrost_schedule.to_Schedule.is_initialized
        OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Input for defrost_schedule #{defrost_schedule} is not a valid OpenStudio::Model::Schedule object")
        return nil
      end
    end
    ref_case.setCaseDefrostSchedule(defrost_schedule)

    # Dripdown schedule, synced to occur after the defrost schedule

    if dripdown_schedule.nil?
      dripdown_schedule = OpenStudio::Model::ScheduleRuleset.new(model)
      dripdown_schedule.setName("#{ref_case.name} Dripdown")
      dripdown_schedule.defaultDaySchedule.setName("#{ref_case.name} Dripdown Default")
      defrost_hours.each do |defrost_hour|
        dripdown_hour = (defrost_duration + dripdown_duration) > 59 ? defrost_hour + 1 : defrost_hour
        dripdown_hour = dripdown_hour > 23 ? dripdown_hour - 24 : dripdown_hour
        dripdown_end_min = (defrost_duration + dripdown_duration) > 59 ? defrost_duration + dripdown_duration - 60 : defrost_duration + dripdown_duration
        dripdown_schedule.defaultDaySchedule.addValue(OpenStudio::Time.new(0, defrost_hour, defrost_duration, 0), 0)
        dripdown_schedule.defaultDaySchedule.addValue(OpenStudio::Time.new(0, dripdown_hour, dripdown_end_min, 0), 1)
      end
      dripdown_schedule.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0)
    else
      unless dripdown_schedule.to_Schedule.is_initialized
        OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Input for dripdown_schedule #{dripdown_schedule} is not a valid OpenStudio::Model::Schedule object")
        return nil
      end
    end
    ref_case.setCaseDefrostDripDownSchedule(dripdown_schedule)
  end

  # Case Credit Schedule

  case_credit_sch = OpenStudio::Model::ScheduleRuleset.new(model)
  case_credit_sch.setName("#{ref_case.name} Case Credit")
  case_credit_sch.defaultDaySchedule.setName("#{ref_case.name} Case Credit Default")
  case_credit_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 1.0)
  ref_case.setCaseCreditFractionSchedule(case_credit_sch)

  # reporting

  length_ft = OpenStudio.convert(ref_case.caseLength, 'm', 'ft').get
  cooling_capacity_w = ref_case.caseLength * ref_case.ratedTotalCoolingCapacityperUnitLength
  cooling_capacity_btu_per_hr = OpenStudio.convert(cooling_capacity_w, 'W', 'Btu/hr').get
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Refrigeration', "Added #{length_ft.round} ft display case called #{case_type} with a cooling capacity of #{cooling_capacity_btu_per_hr.round} Btu/hr to #{thermal_zone&.name}.")

  return ref_case
end

.create_compressor(model, template: 'new', operation_type: 'MT') ⇒ OpenStudio::Model::RefrigerationCompressor

Adds a refrigeration system compressor to the model.

Parameters:

  • model (OpenStudio::Model::Model)

    OpenStudio model object

  • template (String) (defaults to: 'new')

    Technology or standards level, either ‘old’, ‘new’, or ‘advanced’

  • operation_type (String) (defaults to: 'MT')

    Temperature regime, either ‘MT’ Medium Temperature, or ‘LT’ Low Temperature

Returns:

  • (OpenStudio::Model::RefrigerationCompressor)

    the refrigeration compressor



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
# File 'lib/openstudio-standards/refrigeration/create_compressor.rb', line 13

def self.create_compressor(model,
                           template: 'new',
                           operation_type: 'MT')
  # load refrigeration compressor data

  compressors_csv = "#{File.dirname(__FILE__)}/data/refrigeration_compressors.csv"
  unless File.file?(compressors_csv)
    OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Unable to find file: #{compressors_csv}")
    return nil
  end
  compressors_tbl = CSV.table(compressors_csv, encoding: 'ISO8859-1:utf-8')
  compressors_hsh = compressors_tbl.map(&:to_hash)

  # get case properties

  compressor_properties = compressors_hsh.select { |r| (r[:template] == template) && (r[:operation_type] == operation_type) }

  if compressor_properties.nil?
    OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Unable to find compressor for template #{template} operation type #{operation_type}.")
    return nil
  end

  pc = compressor_properties.select { |r| r[:curve_type] == 'Power' }[0]
  cc = compressor_properties.select { |r| r[:curve_type] == 'Capacity' }[0]

  # TODO: replace with curve data once curves are refactored

  std = Standard.build('90.1-2013')

  # create power curve

  power_coeffs = []
  power_coeffs << pc[:coefficient1]
  power_coeffs << pc[:coefficient2]
  power_coeffs << pc[:coefficient3]
  power_coeffs << pc[:coefficient4]
  power_coeffs << pc[:coefficient5]
  power_coeffs << pc[:coefficient6]
  power_coeffs << pc[:coefficient7]
  power_coeffs << pc[:coefficient8]
  power_coeffs << pc[:coefficient9]
  power_coeffs << pc[:coefficient10]
  power_curve = std.create_curve_bicubic(model, power_coeffs, pc[:curve_name], pc[:min_val_x], pc[:max_val_x], pc[:min_val_y], pc[:max_val_y], nil, nil)

  # create capacity curve

  capacity_coeffs = []
  capacity_coeffs << cc[:coefficient1]
  capacity_coeffs << cc[:coefficient2]
  capacity_coeffs << cc[:coefficient3]
  capacity_coeffs << cc[:coefficient4]
  capacity_coeffs << cc[:coefficient5]
  capacity_coeffs << cc[:coefficient6]
  capacity_coeffs << cc[:coefficient7]
  capacity_coeffs << cc[:coefficient8]
  capacity_coeffs << cc[:coefficient9]
  capacity_coeffs << cc[:coefficient10]
  capacity_curve = std.create_curve_bicubic(model, capacity_coeffs, cc[:curve_name], cc[:min_val_x], cc[:max_val_x], cc[:min_val_y], cc[:max_val_y], nil, nil)

  # Make the compressor

  compressor = OpenStudio::Model::RefrigerationCompressor.new(model)
  compressor.setName("#{template} #{operation_type} Refrigeration Compressor")
  compressor.setRefrigerationCompressorPowerCurve(power_curve)
  compressor.setRefrigerationCompressorCapacityCurve(capacity_curve)

  OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Refrigeration', "Added refrigeration compressor #{compressor.name}.")

  return compressor
end

.create_compressor_rack(model, refrigeration_equipment, template: 'new') ⇒ OpenStudio::Model::RefrigerationCase

Adds a self contained refrigeration compressor rack for a case or walkin to the model.

Parameters:

  • model (OpenStudio::Model::Model)

    OpenStudio model object

  • refrigeration_equipment (OpenStudio::Model::ModelObject)

    A RefrigerationCase or RefrigerationWalkIn object

  • template (String) (defaults to: 'new')

    Technology or standards level, either ‘old’, ‘new’, or ‘advanced’

Returns:

  • (OpenStudio::Model::RefrigerationCase)

    the refrigeration case



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
# File 'lib/openstudio-standards/refrigeration/create_compressor_rack.rb', line 13

def self.create_compressor_rack(model, refrigeration_equipment,
                                template: 'new')
  # Add refrigeration system

  ref_rack = OpenStudio::Model::RefrigerationCompressorRack.new(model)
  ref_rack.setName('Self-Contained Refrigeration System')

  # Add refrigeration case or walkin to the rack

  if refrigeration_equipment.to_RefrigerationCase.is_initialized
    ref_case = refrigeration_equipment.to_RefrigerationCase.get
    rated_capacity_w = ref_case.ratedTotalCoolingCapacityperUnitLength * ref_case.caseLength
    ref_rack.addCase(ref_case)
    thermal_zone = ref_case.thermalZone.get
  elsif refrigeration_equipment.to_RefrigerationWalkIn.is_initialized
    ref_walkin = refrigeration_equipment.to_RefrigerationWalkIn.get
    rated_capacity_w = ref_walkin.ratedCoilCoolingCapacity
    ref_rack.addWalkin(ref_walkin)
    thermal_zone = ref_walkin.zoneBoundaryThermalZone.get
  end

  # set zone based on equipment zone

  ref_rack.setHeatRejectionLocation('Zone')
  ref_rack.setHeatRejectionZone(thermal_zone)
  ref_rack.setCondenserType('AirCooled')

  # @todo add cop and curves for compressor racks

  # ref_rack.setDesignCompressorRackCOP(Double)

  # ref_rack.setCompressorRackCOPFunctionofTemperatureCurve(&Curve)

  # ref_rack.setDesignCondenserFanPower(Double)

  # ref_rack.setCondenserFanPowerFunctionofTemperatureCurve(&Curve)


  OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Refrigeration', "Added compressor rack with capacity #{OpenStudio.convert(rated_capacity_w, 'W', 'Btu/hr').get.round} Btu/hr of load serving #{refrigeration_equipment.name}.")

  return ref_rack
end

.create_refrigeration_system(model, refrigeration_equipment, template: 'new', operation_type: 'MT', refrigerant: 'R404a') ⇒ OpenStudio::Model::RefrigerationCase

Adds a refrigerated system to the model.

Parameters:

  • model (OpenStudio::Model::Model)

    OpenStudio model object

  • refrigeration_equipment (Array<OpenStudio::Model::ModelObject>)

    Array of RefrigerationCase and/or RefrigerationWalkIn objects

  • template (String) (defaults to: 'new')

    Technology or standards level, either ‘old’, ‘new’, or ‘advanced’

  • operation_type (String) (defaults to: 'MT')

    Temperature regime, either ‘MT’ Medium Temperature, or ‘LT’ Low Temperature

  • refrigerant (String) (defaults to: 'R404a')

    Refrigerant type.

Returns:

  • (OpenStudio::Model::RefrigerationCase)

    the refrigeration case



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
# File 'lib/openstudio-standards/refrigeration/create_refrigeration_system.rb', line 15

def self.create_refrigeration_system(model, refrigeration_equipment,
                                     template: 'new',
                                     operation_type: 'MT',
                                     refrigerant: 'R404a')
  # Add refrigeration system

  ref_system = OpenStudio::Model::RefrigerationSystem.new(model)
  ref_system.setName("#{operation_type} Refrigeration System")
  ref_system.setRefrigerationSystemWorkingFluidType(refrigerant)
  ref_system.setSuctionTemperatureControlType('ConstantSuctionTemperature')

  # Add equipment to the system and sum capacity.

  # Allowable equipment are refrigeration cases and walkins.

  rated_capacity_w = 0
  refrigeration_equipment.each do |ref_equip|
    if ref_equip.to_RefrigerationCase.is_initialized
      ref_case = ref_equip.to_RefrigerationCase.get
      rated_capacity_w += ref_case.ratedTotalCoolingCapacityperUnitLength * ref_case.caseLength
      ref_system.addCase(ref_case)
    elsif ref_equip.to_RefrigerationWalkIn.is_initialized
      ref_walkin = ref_equip.to_RefrigerationWalkIn.get
      rated_capacity_w += ref_walkin.ratedCoilCoolingCapacity
      ref_system.addWalkin(ref_walkin)
    end
  end

  # Calculate number of compressors

  rated_compressor_capacity_btu_per_hr = 60_000.0
  number_of_compressors = (rated_capacity_w / OpenStudio.convert(rated_compressor_capacity_btu_per_hr, 'Btu/h', 'W').get).ceil

  # add compressors

  (1..number_of_compressors).each do |compressor_number|
    compressor = OpenstudioStandards::Refrigeration.create_compressor(model,
                                                                      template: template,
                                                                      operation_type: operation_type)
    compressor.setName("#{ref_system.name} Compressor #{compressor_number}")
    ref_system.addCompressor(compressor)
  end
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Refrigeration', "Added #{number_of_compressors} compressors, each with a capacity of #{rated_compressor_capacity_btu_per_hr.round} Btu/hr to serve #{OpenStudio.convert(rated_capacity_w, 'W', 'Btu/hr').get.round} Btu/hr of case and walkin load.")

  # Heat rejection as a function of temperature

  heat_rejection_curve = OpenStudio::Model::CurveLinear.new(model)
  heat_rejection_curve.setName('Condenser Heat Rejection Function of Temperature')
  heat_rejection_curve.setCoefficient1Constant(0.0)
  heat_rejection_curve.setCoefficient2x(22000.0)
  heat_rejection_curve.setMinimumValueofx(-50.0)
  heat_rejection_curve.setMaximumValueofx(50.0)

  # Add condenser

  condenser = OpenStudio::Model::RefrigerationCondenserAirCooled.new(model)
  condenser.setRatedEffectiveTotalHeatRejectionRateCurve(heat_rejection_curve)
  condenser.setRatedSubcoolingTemperatureDifference(OpenStudio.convert(2.0, 'F', 'C').get)
  condenser.setMinimumFanAirFlowRatio(0.0)
  condenser.setRatedFanPower(0.04 * rated_capacity_w)
  condenser.setCondenserFanSpeedControlType('VariableSpeed')
  ref_system.setRefrigerationCondenser(condenser)

  return ref_system
end

.create_typical_refrigeration(model, template: 'new', separate_system_size_limit: 0.0) ⇒ Boolean

Adds typical refrigeration to a model

Parameters:

  • model (OpenStudio::Model::Model)

    OpenStudio model object

  • template (String) (defaults to: 'new')

    Technology or standards level, either ‘old’, ‘new’, or ‘advanced’

  • separate_system_size_limit (Float) (defaults to: 0.0)

    The area in square feet above which a refrigeration system will be split into multiple systems. Currently not used.

Returns:

  • (Boolean)

    returns true if successful, false if not



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
# File 'lib/openstudio-standards/refrigeration/create_typical_refrigeration.rb', line 13

def self.create_typical_refrigeration(model,
                                      template: 'new',
                                      separate_system_size_limit: 0.0)
  # get refrigeration equipment list based on space types and area

  ref_equip_list = OpenstudioStandards::Refrigeration.typical_refrigeration_equipment_list(model)

  if ref_equip_list[:cases].empty? && ref_equip_list[:walkins].empty?
    OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Refrigeration', 'The model space types do not typical have refrigeration cases or walkins. No refrigeration system will be added.')
    return true
  end

  # Find the thermal zones most suited for holding the display cases

  unless ref_equip_list[:cases].empty?
    thermal_zone_case = OpenstudioStandards::Refrigeration.refrigeration_case_zone(model)
    if thermal_zone_case.nil?
      OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', 'Attempted to add display cases to the model, but could find no thermal zone to put them into.')
      return false
    end
  end

  # create cases

  medium_temperature_cases = []
  low_temperature_cases = []
  ref_equip_list[:cases].each_with_index do |ref_case, index|
    case_ = OpenstudioStandards::Refrigeration.create_case(model,
                                                           template: template,
                                                           case_type: ref_case[:case_type],
                                                           case_length: ref_case[:length],
                                                           defrost_start_hour: index,
                                                           thermal_zone: thermal_zone_case)
    if case_.caseOperatingTemperature > -3.0
      medium_temperature_cases << case_
    else
      low_temperature_cases << case_
    end
  end

  # Find the thermal zones most suited for holding the walkins

  unless ref_equip_list[:walkins].empty?
    thermal_zone_walkin = OpenstudioStandards::Refrigeration.refrigeration_walkin_zone(model)
    if thermal_zone_walkin.nil?
      OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', 'Attempted to add walkins to the model, but could find no thermal zone to put them into.')
      return false
    end
  end

  # create walkins

  medium_temperature_walkins = []
  low_temperature_walkins = []
  ref_equip_list[:walkins].each_with_index do |walkin, index|
    ref_walkin = OpenstudioStandards::Refrigeration.create_walkin(model,
                                                                  name: walkin[:walkin_name],
                                                                  template: template,
                                                                  walkin_type: walkin[:walkin_type],
                                                                  defrost_start_hour: index,
                                                                  thermal_zone: thermal_zone_walkin)
    if ref_walkin.operatingTemperature > -3.0
      medium_temperature_walkins << ref_walkin
    else
      low_temperature_walkins << ref_walkin
    end
  end

  # @todo Disable self-contained refrigeration units until we have efficiency data and cases and walkins can connect to those systems and simulate correctly.

  # refrigeration_space_type_area = OpenStudio.convert(model.getBuilding.floorArea, 'm^2', 'ft^2').get

  # if refrigeration_space_type_area < separate_system_size_limit

  #   # each case is self-contained

  #   medium_temperature_cases.each { |ref_equip| OpenstudioStandards::Refrigeration.create_compressor_rack(model, ref_equip, template: template) }

  #   low_temperature_cases.each { |ref_equip| OpenstudioStandards::Refrigeration.create_compressor_rack(model, ref_equip, template: template) }


  #   # each walkin gets its own refrigeration system

  #   medium_temperature_walkins.each { |ref_equip| OpenstudioStandards::Refrigeration.create_refrigeration_system(model, [ref_equip], template: template, operation_type: 'MT') }

  #   low_temperature_walkins.each { |ref_equip| OpenstudioStandards::Refrigeration.create_refrigeration_system(model, [ref_equip], template: template, operation_type: 'LT') }

  # else

  medium_temperature_equip = medium_temperature_cases + medium_temperature_walkins
  OpenstudioStandards::Refrigeration.create_refrigeration_system(model, medium_temperature_equip,
                                                                 template: template,
                                                                 operation_type: 'MT')
  low_temperature_equip = low_temperature_cases + low_temperature_walkins
  OpenstudioStandards::Refrigeration.create_refrigeration_system(model, low_temperature_equip,
                                                                 template: template,
                                                                 operation_type: 'LT')
  # end


  return true
end

.create_walkin(model, name: nil, template: 'new', walkin_type: 'Walk-in Cooler - 120SF with no glass door', defrost_schedule: nil, defrost_start_hour: 0, dripdown_schedule: nil, thermal_zone: nil) ⇒ OpenStudio::Model::RefrigerationWalkIn

Adds a refrigerated walkin to the model.

Parameters:

  • model (OpenStudio::Model::Model)

    OpenStudio model object

  • name (String) (defaults to: nil)

    Name of the refrigeration walkin

  • template (String) (defaults to: 'new')

    Technology or standards level, either ‘old’, ‘new’, or ‘advanced’

  • walkin_type (String) (defaults to: 'Walk-in Cooler - 120SF with no glass door')

    The walkin type. See refrigeration_walkins data for valid options under walkin_type.

  • defrost_schedule (OpenStudio::Model::Schedule) (defaults to: nil)

    OpenStudio Schedule object with boolean values for the defrost schedule

  • defrost_start_hour (Double) (defaults to: 0)

    Start hour between 0 and 24 for. Used if defrost_schedule not specified.

  • dripdown_schedule (OpenStudio::Model::Schedule) (defaults to: nil)

    OpenStudio Schedule object with boolean values for the dripdown schedule

  • thermal_zone (OpenStudio::Model::ThermalZone) (defaults to: nil)

    Thermal zone with the walkin. If nil, will look up from the model.

Returns:

  • (OpenStudio::Model::RefrigerationWalkIn)

    the refrigeration walkin



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
# File 'lib/openstudio-standards/refrigeration/create_walkin.rb', line 18

def self.create_walkin(model,
                       name: nil,
                       template: 'new',
                       walkin_type: 'Walk-in Cooler - 120SF with no glass door',
                       defrost_schedule: nil,
                       defrost_start_hour: 0,
                       dripdown_schedule: nil,
                       thermal_zone: nil)
  # get thermal zone if not provided

  if thermal_zone.nil?
    # Find the thermal zones most suited for holding the walkin

    thermal_zone = OpenstudioStandards::Refrigeration.refrigeration_walkin_zone(model)
    if thermal_zone.nil?
      OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', 'Attempted to add walkins to the model, but could find no thermal zone to put them into.')
      return nil
    end
  end

  # load refrigeration walkin data

  walkins_csv = "#{File.dirname(__FILE__)}/data/refrigerated_walkins.csv"
  unless File.file?(walkins_csv)
    OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Unable to find file: #{walkins_csv}")
    return nil
  end
  walkins_tbl = CSV.table(walkins_csv, encoding: 'ISO8859-1:utf-8')
  walkins_hsh = walkins_tbl.map(&:to_hash)

  # get walkin properties

  walkins_properties = walkins_hsh.select { |r| (r[:template] == template) && (r[:walkin_name] == walkin_type) }
  if walkins_properties.empty?
    OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Unable to find walkin properties for walkin #{template} #{walkin_type}.")
    return nil
  end
  walkins_properties = walkins_properties[0]

  if name.nil?
    name = "#{walkin_type} #{template}"
  end

  # add walkin

  ref_walkin = OpenStudio::Model::RefrigerationWalkIn.new(model, model.alwaysOnDiscreteSchedule)
  ref_walkin.setName(name)
  ref_walkin.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
  ref_walkin.setRatedCoilCoolingCapacity(walkins_properties[:rated_capacity])
  ref_walkin.setOperatingTemperature(walkins_properties[:operating_temperature])
  ref_walkin.setRatedCoolingSourceTemperature(walkins_properties[:rated_cooling_source_temperature])
  ref_walkin.setRatedTotalHeatingPower(walkins_properties[:rated_total_heating_power])
  ref_walkin.setRatedCirculationFanPower(0.0)
  ref_walkin.setRatedCoolingCoilFanPower(walkins_properties[:rated_cooling_fan_power])
  ref_walkin.setRatedTotalLightingPower(walkins_properties[:lighting_power])
  ref_walkin.setLightingSchedule(model.alwaysOnDiscreteSchedule)
  ref_walkin.setDefrostType(walkins_properties[:defrost_type])
  ref_walkin.setDefrostControlType(walkins_properties[:defrost_control_type])
  ref_walkin.setDefrostPower(walkins_properties[:defrost_power])
  ref_walkin.setTemperatureTerminationDefrostFractiontoIce(walkins_properties[:temperature_termination_defrost_fraction_to_ice])
  ref_walkin.setInsulatedFloorSurfaceArea(walkins_properties[:insulated_floor_area])
  ref_walkin.setInsulatedFloorUValue(walkins_properties[:insulated_floor_uvalue])
  ref_walkin.setZoneBoundaryTotalInsulatedSurfaceAreaFacingZone(walkins_properties[:total_insulatedsurface_area_facing_zone])
  ref_walkin.setZoneBoundaryInsulatedSurfaceUValueFacingZone(walkins_properties[:insulated_surface_uvalue_facing_zone])
  ref_walkin.setZoneBoundaryAreaofGlassReachInDoorsFacingZone(walkins_properties[:area_of_glass_reachin_doors_facing_zone])
  ref_walkin.setZoneBoundaryGlassReachInDoorUValueFacingZone(walkins_properties[:reachin_door_uvalue]) unless walkins_properties[:reachin_door_uvalue].nil?
  ref_walkin.setZoneBoundaryAreaofStockingDoorsFacingZone(walkins_properties[:area_of_stocking_doors_facing_zone])
  ref_walkin.setZoneBoundaryHeightofStockingDoorsFacingZone(walkins_properties[:height_of_stocking_doors_facing_zone])
  # replace with glass height property when added

  ref_walkin.setZoneBoundaryHeightofGlassReachInDoorsFacingZone(walkins_properties[:height_of_stocking_doors_facing_zone])
  ref_walkin.setZoneBoundaryStockingDoorUValueFacingZone(walkins_properties[:stocking_door_u])
  ref_walkin.zoneBoundaries.each { |zb| zb.setStockingDoorOpeningProtectionTypeFacingZone(walkins_properties[:stocking_door_opening_protection]) }
  ref_walkin.setZoneBoundaryThermalZone(thermal_zone)

  # only add defrost schedules if not OffCycle

  unless walkins_properties[:defrost_type] == 'OffCycle'
    # defrost properties, default to two 45 minute defrost cycles per day followed by a 5 minute dripdown duration

    defrost_duration = walkins_properties[:defrost_duration].nil? ? 45 : walkins_properties[:defrost_duration]
    defrosts_per_day = walkins_properties[:defrosts_per_day].nil? ? 2 : walkins_properties[:defrosts_per_day]
    dripdown_duration = walkins_properties[:dripdown_duration].nil? ? 5 : walkins_properties[:dripdown_duration]

    # defrost hours are calculated from the start hour and number of defrosts per day

    defrost_interval = (24 / defrosts_per_day).floor
    defrost_hours = (1..defrosts_per_day).map { |i| defrost_start_hour + ((i - 1) * defrost_interval) }
    defrost_hours.map! { |hr| hr > 23 ? hr - 24 : hr }
    defrost_hours.sort!

    # Defrost schedule

    if defrost_schedule.nil?
      defrost_schedule = OpenStudio::Model::ScheduleRuleset.new(model)
      defrost_schedule.setName("#{ref_walkin.name} Defrost")
      defrost_schedule.defaultDaySchedule.setName("#{ref_walkin.name} Defrost Default")
      defrost_hours.each do |defrost_hour|
        defrost_schedule.defaultDaySchedule.addValue(OpenStudio::Time.new(0, defrost_hour, 0, 0), 0)
        defrost_schedule.defaultDaySchedule.addValue(OpenStudio::Time.new(0, defrost_hour, defrost_duration, 0), 1)
      end
      defrost_schedule.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0)
    else
      unless defrost_schedule.to_Schedule.is_initialized
        OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Input for defrost_schedule #{defrost_schedule} is not a valid OpenStudio::Model::Schedule object")
        return nil
      end
    end
    ref_walkin.setDefrostSchedule(defrost_schedule)

    # Dripdown schedule, synced with defrost schedule

    if dripdown_schedule.nil?
      dripdown_schedule = OpenStudio::Model::ScheduleRuleset.new(model)
      dripdown_schedule.setName("#{ref_walkin.name} Dripdown")
      dripdown_schedule.defaultDaySchedule.setName("#{ref_walkin.name} Dripdown Default")
      defrost_hours.each do |defrost_hour|
        dripdown_hour = (defrost_duration + dripdown_duration) > 59 ? defrost_hour + 1 : defrost_hour
        dripdown_hour = dripdown_hour > 23 ? dripdown_hour - 24 : dripdown_hour
        dripdown_end_min = (defrost_duration + dripdown_duration) > 59 ? defrost_duration + dripdown_duration - 60 : defrost_duration + dripdown_duration
        dripdown_schedule.defaultDaySchedule.addValue(OpenStudio::Time.new(0, defrost_hour, defrost_duration, 0), 0)
        dripdown_schedule.defaultDaySchedule.addValue(OpenStudio::Time.new(0, dripdown_hour, dripdown_end_min, 0), 1)
      end
      dripdown_schedule.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), 0)
    else
      unless dripdown_schedule.to_Schedule.is_initialized
        OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Input for dripdown_schedule #{dripdown_schedule} is not a valid OpenStudio::Model::Schedule object")
        return nil
      end
    end
    ref_walkin.setDefrostDripDownSchedule(dripdown_schedule)
  end

  # stocking schedule

  # ref_walkin.setRestockingSchedule(model.alwaysOffDiscreteSchedule)

  ref_walkin.setZoneBoundaryStockingDoorOpeningScheduleFacingZone(model.alwaysOffDiscreteSchedule)

  insulated_floor_area_ft2 = OpenStudio.convert(walkins_properties[:insulated_floor_area], 'm^2', 'ft^2').get
  rated_cooling_capacity_btu_per_hr = OpenStudio.convert(walkins_properties[:rated_capacity], 'W', 'Btu/hr').get
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Refrigeration', "Added #{insulated_floor_area_ft2.round} ft2 walkin called #{walkin_type} with a capacity of #{rated_cooling_capacity_btu_per_hr.round} Btu/hr to #{thermal_zone&.name}.")

  return ref_walkin
end

.refrigeration_case_zone(model) ⇒ OpenStudio::Model::ThermalZone

Find the thermal zone that is best for adding refrigerated display cases into. First, check for space types that typically have refrigeration. Fall back to largest zone in the model if no typical space types are found.

Parameters:

  • model (OpenStudio::Model::Model)

    OpenStudio model object

Returns:

  • (OpenStudio::Model::ThermalZone)

    returns a thermal zone if found, nil if not.



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
# File 'lib/openstudio-standards/refrigeration/information.rb', line 13

def self.refrigeration_case_zone(model)
  # load refrigeration cases data

  cases_csv = "#{File.dirname(__FILE__)}/data/typical_refrigerated_cases.csv"
  unless File.file?(cases_csv)
    OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Unable to find file: #{cases_csv}")
    return nil
  end
  cases_tbl = CSV.table(cases_csv, encoding: 'ISO8859-1:utf-8')
  cases_hsh = cases_tbl.map(&:to_hash)

  # Look for one of the space types that would typically have refrigeration

  display_case_zone = nil
  display_case_zone_area_m2 = 0.0
  model.getThermalZones.each do |zone|
    space_type = OpenstudioStandards::ThermalZone.thermal_zone_get_space_type(zone)
    next if space_type.empty?

    space_type = space_type.get
    next if space_type.standardsSpaceType.empty?
    next if space_type.standardsBuildingType.empty?

    stds_spc_type = space_type.standardsSpaceType.get
    stds_bldg_type = space_type.standardsBuildingType.get
    cases = cases_hsh.select { |r| (r[:building_type] == stds_bldg_type) && (r[:space_type] == stds_spc_type) }
    unless cases.empty?
      if zone.floorArea > display_case_zone_area_m2
        display_case_zone = zone
        display_case_zone_area_m2 = zone.floorArea
      end
    end
  end

  unless display_case_zone.nil?
    OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Refrigeration', "Display case zone is #{display_case_zone.name}, the largest zone with a space type typical for display cases.")
    return display_case_zone
  end

  # If no typical space type was found, choose the largest zone in the model.

  display_case_zone = nil
  display_case_zone_area_m2 = 0
  model.getThermalZones.each do |zone|
    if zone.floorArea > display_case_zone_area_m2
      display_case_zone = zone
      display_case_zone_area_m2 = zone.floorArea
    end
  end

  unless display_case_zone.nil?
    OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Refrigeration', "No space types typical for display cases were found, so the display cases will be placed in #{display_case_zone.name}, the largest zone.")
    return display_case_zone
  end

  return display_case_zone
end

.refrigeration_walkin_zone(model) ⇒ OpenStudio::Model::ThermalZone

Find the thermal zone that is best for adding refrigerated walkins into. First, check for space types that typically have refrigeration. Fall back to largest zone in the model if no typical space types are found.

Parameters:

  • model (OpenStudio::Model::Model)

    OpenStudio model object

Returns:

  • (OpenStudio::Model::ThermalZone)

    returns a thermal zone if found, nil if not.



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
# File 'lib/openstudio-standards/refrigeration/information.rb', line 74

def self.refrigeration_walkin_zone(model)
  # load refrigeration walkin data

  walkins_csv = "#{File.dirname(__FILE__)}/data/typical_refrigerated_walkins.csv"
  unless File.file?(walkins_csv)
    OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Unable to find file: #{walkins_csv}")
    return nil
  end
  walkins_tbl = CSV.table(walkins_csv, encoding: 'ISO8859-1:utf-8')
  walkins_hsh = walkins_tbl.map(&:to_hash)

  # Look for one of the space types that would typically have walkins

  walkin_zone = nil
  walkin_zone_area_m2 = 0.0
  model.getThermalZones.each do |zone|
    space_type = OpenstudioStandards::ThermalZone.thermal_zone_get_space_type(zone)
    next if space_type.empty?

    space_type = space_type.get
    next if space_type.standardsSpaceType.empty?
    next if space_type.standardsBuildingType.empty?

    stds_spc_type = space_type.standardsSpaceType.get
    stds_bldg_type = space_type.standardsBuildingType.get
    walkins = walkins_hsh.select { |r| (r[:building_type] == stds_bldg_type) && (r[:space_type] == stds_spc_type) }
    unless walkins.empty?
      if zone.floorArea > walkin_zone_area_m2
        walkin_zone = zone
        walkin_zone_area_m2 = zone.floorArea
      end
    end
  end

  unless walkin_zone.nil?
    OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Refrigeration', "Walkin zone is #{walkin_zone.name}, the largest zone with a space type typical for walkins.")
    return walkin_zone
  end

  # If no typical space type was found,

  # choose the largest zone in the model.

  walkin_zone = nil
  walkin_zone_area_m2 = 0
  model.getThermalZones.each do |zone|
    if zone.floorArea > walkin_zone_area_m2
      walkin_zone = zone
      walkin_zone_area_m2 = zone.floorArea
    end
  end

  unless walkin_zone.nil?
    OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Refrigeration', "No space types typical for walkins were found, so the walkins will be placed in #{walkin_zone.name}, the largest zone.")
    return walkin_zone
  end

  return walkin_zone
end

.typical_refrigeration_equipment_list(model) ⇒ Hash

Returns the typical refrigeration equipment in a model based on space types

Parameters:

  • model (OpenStudio::Model::Model)

    OpenStudio model object

Returns:

  • (Hash)

    Hash of refrigeration case lengths and walkin area



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
# File 'lib/openstudio-standards/refrigeration/create_typical_refrigeration.rb', line 104

def self.typical_refrigeration_equipment_list(model)
  # load refrigeration cases data

  cases_csv = "#{File.dirname(__FILE__)}/data/typical_refrigerated_cases.csv"
  unless File.file?(cases_csv)
    OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Unable to find file: #{cases_csv}")
    return false
  end
  cases_tbl = CSV.table(cases_csv, encoding: 'ISO8859-1:utf-8')
  cases_hsh = cases_tbl.map(&:to_hash)

  # load refrigeration walkin data

  walkins_csv = "#{File.dirname(__FILE__)}/data/typical_refrigerated_walkins.csv"
  unless File.file?(walkins_csv)
    OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Refrigeration', "Unable to find file: #{walkins_csv}")
    return false
  end
  walkins_tbl = CSV.table(walkins_csv, encoding: 'ISO8859-1:utf-8')
  walkins_hsh = walkins_tbl.map(&:to_hash)

  # loop through space types to get collection of cases and walkins

  cases_list = []
  walkins_list = []
  model.getSpaceTypes.sort.each do |space_type|
    total_space_floor_area_m2 = space_type.floorArea
    total_space_floor_area_ft2 = OpenStudio.convert(total_space_floor_area_m2, 'm^2', 'ft^2').get

    next unless space_type.standardsSpaceType.is_initialized
    next unless space_type.standardsBuildingType.is_initialized

    standards_space_type = space_type.standardsSpaceType.get
    standards_building_type = space_type.standardsBuildingType.get

    # create list of cases

    ref_cases = cases_hsh.select { |hash| (hash[:space_type] == standards_space_type) && (hash[:building_type] == standards_building_type) }
    ref_cases.each do |ref_case|
      length_modifier = total_space_floor_area_ft2 / ref_case[:reference_space_type_area_ft2]
      case_length = OpenStudio.convert(ref_case[:length_ft] * length_modifier, 'ft', 'm').get
      cases_list << { case_type: ref_case[:case_type], length: case_length }
    end

    # create list of walkins

    ref_walkins = walkins_hsh.select { |hash| (hash[:space_type] == standards_space_type) && (hash[:building_type] == standards_building_type) }
    ref_walkins.each do |ref_walkin|
      area_modifier = total_space_floor_area_ft2 / ref_walkin[:reference_space_type_area_ft2]
      # round to the nearest 120 ft2, with a minimum size of 80 ft2 and maximum size of 480 ft2

      walkin_size_ft2 = (120.0 * ((ref_walkin[:size_ft2] * area_modifier) / 120.0).round).clamp(80.0, 480.0).to_int
      walkin_lookup_name = "#{ref_walkin[:walkin_type]} - #{walkin_size_ft2}SF"
      walkin_lookup_name = "#{walkin_lookup_name} with no glass door" if walkin_lookup_name.include? 'Cooler'
      walkins_list << { walkin_name: ref_walkin[:walkin_name], walkin_type: walkin_lookup_name }
    end
  end

  equipment_list = {
    cases: cases_list,
    walkins: walkins_list
  }

  return equipment_list
end