tbd 3.4.4 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  # BSD 3-Clause License
2
2
  #
3
- # Copyright (c) 2022-2024, Denis Bourgeois
3
+ # Copyright (c) 2022-2025, Denis Bourgeois
4
4
  # All rights reserved.
5
5
  #
6
6
  # Redistribution and use in source and binary forms, with or without
@@ -102,9 +102,9 @@ module OSlg
102
102
  end
103
103
 
104
104
  ##
105
- # Returns whether current status is WARN.
105
+ # Returns whether current status is WARNING.
106
106
  #
107
- # @return [Bool] whether current log status is WARN
107
+ # @return [Bool] whether current log status is WARNING
108
108
  def warn?
109
109
  @@status == WARN
110
110
  end
@@ -159,19 +159,20 @@ module OSlg
159
159
  end
160
160
 
161
161
  ##
162
- # Converts object to String and trims if necessary.
162
+ # Converts object to String, trims if requested.
163
163
  #
164
164
  # @param txt [#to_s] a stringable object
165
- # @param length [#to_i] maximum return string length
165
+ # @param len [Numeric] requested maximum string length (optional)
166
166
  #
167
- # @return [String] a trimmed message string (empty unless stringable)
168
- def trim(txt = "", length = 60)
169
- length = 60 unless length.respond_to?(:to_i)
170
- length = length.to_i if length.respond_to?(:to_i)
167
+ # @return [String] a (trimmed) string (empty unless stringable)
168
+ def trim(txt = "", len = nil)
171
169
  return "" unless txt.respond_to?(:to_s)
172
170
 
173
171
  txt = txt.to_s.strip
174
- txt = txt[0...length] + " ..." if txt.length > length
172
+
173
+ if len.is_a?(Numeric)
174
+ txt = txt[0...len.to_i] + " ..." if txt.length > len.to_i
175
+ end
175
176
 
176
177
  txt
177
178
  end
@@ -193,21 +194,28 @@ module OSlg
193
194
  end
194
195
 
195
196
  ##
196
- # Logs a new entry, if provided arguments are valid.
197
+ # Logs a new entry. Overall log status is raised if new level is greater
198
+ # than current level (e.g. FATAL > ERROR). Candidate log entry is ignored and
199
+ # status remains unchanged if the new level cannot be converted to an integer,
200
+ # if not an OSlg constant (once converted), or if new level is below the
201
+ # current log level. Relies on OSlg method 'trim()': candidate log message is
202
+ # ignored and status unchanged if message is not a valid string.
197
203
  #
198
204
  # @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL
199
205
  # @param message [#to_s] user-provided log message
206
+ # @param len [Numeric] maximum log message length (optional)
200
207
  #
201
208
  # @example A user warning
202
209
  # log(WARN, "Surface area < 100cm2")
203
210
  #
204
211
  # @return [DEBUG, INFO, WARN, ERROR, FATAL] updated/current status
205
- def log(lvl = DEBUG, message = "")
212
+ def log(lvl = DEBUG, message = "", len = nil)
206
213
  return @@status unless lvl.respond_to?(:to_i)
207
214
  return @@status unless message.respond_to?(:to_s)
208
215
 
209
216
  lvl = lvl.to_i
210
- message = message.to_s
217
+ message = trim(message, len)
218
+ return @@status if message.empty?
211
219
  return @@status if lvl < DEBUG
212
220
  return @@status if lvl > FATAL
213
221
  return @@status if lvl < @@level
@@ -220,19 +228,24 @@ module OSlg
220
228
 
221
229
  ##
222
230
  # Logs template 'invalid object' message, if provided arguments are valid.
231
+ # Relies on OSlg method 'log()': first check out its own operation, exit
232
+ # conditions and module side effects. Candidate log entry is ignored and
233
+ # status remains unchanged if 'ord' cannot be converted to an integer.
234
+ # Argument 'ord' is ignored unless > 0.
223
235
  #
224
236
  # @param id [#to_s] 'invalid object' identifier
225
237
  # @param mth [#to_s] calling method identifier
226
238
  # @param ord [#to_i] calling method argument order number of obj (optional)
227
239
  # @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL (optional)
228
240
  # @param res what to return (optional)
241
+ # @param len [Numeric] maximum log message length (optional)
229
242
  #
230
243
  # @example An invalid argument, logging a FATAL error, returning FALSE
231
244
  # return invalid("area", "sum", 0, FATAL, false) if area > 1000000
232
245
  #
233
246
  # @return user-provided object
234
247
  # @return [nil] if user hasn't provided an object to return
235
- def invalid(id = "", mth = "", ord = 0, lvl = DEBUG, res = nil)
248
+ def invalid(id = "", mth = "", ord = 0, lvl = DEBUG, res = nil, len = nil)
236
249
  return res unless id.respond_to?(:to_s)
237
250
  return res unless mth.respond_to?(:to_s)
238
251
  return res unless ord.respond_to?(:to_i)
@@ -250,7 +263,7 @@ module OSlg
250
263
  msg = "Invalid '#{id}' "
251
264
  msg += "arg ##{ord} " if ord > 0
252
265
  msg += "(#{mth})"
253
- log(lvl, msg)
266
+ log(lvl, msg, len)
254
267
 
255
268
  res
256
269
  end
@@ -266,13 +279,14 @@ module OSlg
266
279
  # @param mth [#to_s] calling method identifier (optional)
267
280
  # @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL (optional)
268
281
  # @param res what to return (optional)
282
+ # @param len [Numeric] maximum log message length (optional)
269
283
  #
270
284
  # @example A mismatched argument instance/class
271
285
  # mismatch("area", area, Float, "sum") unless area.is_a?(Numeric)
272
286
  #
273
287
  # @return user-provided object
274
288
  # @return [nil] if user hasn't provided an object to return
275
- def mismatch(id = "", obj = nil, cl = nil, mth = "", lvl = DEBUG, res = nil)
289
+ def mismatch(id = "", obj = nil, cl = nil, mth = "", lvl = DEBUG, res = nil, len = nil)
276
290
  return res unless id.respond_to?(:to_s)
277
291
  return res unless mth.respond_to?(:to_s)
278
292
  return res unless cl.is_a?(Class)
@@ -287,7 +301,7 @@ module OSlg
287
301
  return res if lvl < DEBUG
288
302
  return res if lvl > FATAL
289
303
 
290
- log(lvl, "'#{id}' #{obj.class}? expecting #{cl} (#{mth})")
304
+ log(lvl, "'#{id}' #{obj.class}? expecting #{cl} (#{mth})", len)
291
305
 
292
306
  res
293
307
  end
@@ -302,13 +316,14 @@ module OSlg
302
316
  # @param mth [#to_s] calling method identifier
303
317
  # @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL (optional)
304
318
  # @param res what to return (optional)
319
+ # @param len [Numeric] maximum log message length (optional)
305
320
  #
306
321
  # @example A missing Hash key
307
322
  # hashkey("floor area", floor, :area, "sum") unless floor.key?(:area)
308
323
  #
309
324
  # @return user-provided object
310
325
  # @return [nil] if user hasn't provided an object to return
311
- def hashkey(id = "", hsh = {}, key = "", mth = "", lvl = DEBUG, res = nil)
326
+ def hashkey(id = "", hsh = {}, key = "", mth = "", lvl = DEBUG, res = nil, len = nil)
312
327
  return res unless id.respond_to?(:to_s)
313
328
  return res unless hsh.is_a?(Hash)
314
329
  return res if hsh.key?(key)
@@ -323,7 +338,7 @@ module OSlg
323
338
  return res if lvl < DEBUG
324
339
  return res if lvl > FATAL
325
340
 
326
- log(lvl, "Missing '#{key}' key in '#{id}' Hash (#{mth})")
341
+ log(lvl, "Missing '#{key}' key in '#{id}' Hash (#{mth})", len)
327
342
 
328
343
  res
329
344
  end
@@ -335,13 +350,14 @@ module OSlg
335
350
  # @param mth [#to_s] calling method identifier
336
351
  # @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL (optional)
337
352
  # @param res what to return (optional)
353
+ # @param len [Numeric] maximum log message length (optional)
338
354
  #
339
355
  # @example An uninitialized variable, logging an ERROR, returning FALSE
340
356
  # empty("zone", "conditioned?", FATAL, false) if space.thermalZone.empty?
341
357
  #
342
358
  # @return user-provided object
343
359
  # @return [nil] if user hasn't provided an object to return
344
- def empty(id = "", mth = "", lvl = DEBUG, res = nil)
360
+ def empty(id = "", mth = "", lvl = DEBUG, res = nil, len = nil)
345
361
  return res unless id.respond_to?(:to_s)
346
362
  return res unless mth.respond_to?(:to_s)
347
363
  return res unless lvl.respond_to?(:to_i)
@@ -354,7 +370,7 @@ module OSlg
354
370
  return res if lvl < DEBUG
355
371
  return res if lvl > FATAL
356
372
 
357
- log(lvl, "Empty '#{id}' (#{mth})")
373
+ log(lvl, "Empty '#{id}' (#{mth})", len)
358
374
 
359
375
  res
360
376
  end
@@ -366,13 +382,14 @@ module OSlg
366
382
  # @param mth [#to_s] calling method identifier
367
383
  # @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL (optional)
368
384
  # @param res what to return (optional)
385
+ # @param len [Numeric] maximum log message length (optional)
369
386
  #
370
387
  # @example A near-zero variable
371
388
  # zero("floor area", "sum") if floor[:area].abs < TOL
372
389
  #
373
390
  # @return user-provided object
374
391
  # @return [nil] if user hasn't provided an object to return
375
- def zero(id = "", mth = "", lvl = DEBUG, res = nil)
392
+ def zero(id = "", mth = "", lvl = DEBUG, res = nil, len = nil)
376
393
  return res unless id.respond_to?(:to_s)
377
394
  return res unless mth.respond_to?(:to_s)
378
395
  return res unless lvl.respond_to?(:to_i)
@@ -386,7 +403,7 @@ module OSlg
386
403
  return res if lvl < DEBUG
387
404
  return res if lvl > FATAL
388
405
 
389
- log(lvl, "Zero '#{id}' (#{mth})")
406
+ log(lvl, "Zero '#{id}' (#{mth})", len)
390
407
 
391
408
  res
392
409
  end
@@ -398,13 +415,14 @@ module OSlg
398
415
  # @param mth [String] calling method identifier
399
416
  # @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional)
400
417
  # @param res [Object] what to return (optional)
418
+ # @param len [Numeric] maximum log message length (optional)
401
419
  #
402
420
  # @example A negative variable
403
421
  # negative("floor area", "sum") if floor[:area] < 0
404
422
  #
405
423
  # @return user-provided object
406
424
  # @return [nil] if user hasn't provided an object to return
407
- def negative(id = "", mth = "", lvl = DEBUG, res = nil)
425
+ def negative(id = "", mth = "", lvl = DEBUG, res = nil, len = nil)
408
426
  return res unless id.respond_to?(:to_s)
409
427
  return res unless mth.respond_to?(:to_s)
410
428
  return res unless lvl.respond_to?(:to_i)
@@ -417,7 +435,7 @@ module OSlg
417
435
  return res if lvl < DEBUG
418
436
  return res if lvl > FATAL
419
437
 
420
- log(lvl, "Negative '#{id}' (#{mth})")
438
+ log(lvl, "Negative '#{id}' (#{mth})", len)
421
439
 
422
440
  res
423
441
  end
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
  #
3
- # Copyright (c) 2020-2024 Denis Bourgeois & Dan Macumber
3
+ # Copyright (c) 2020-2025 Denis Bourgeois & Dan Macumber
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the "Software"), to deal
@@ -1355,103 +1355,103 @@ module TBD
1355
1355
  ##
1356
1356
  # Thermally derates insulating material within construction.
1357
1357
  #
1358
- # @param id [#to_s] surface identifier
1358
+ # @param id [#to_sym] surface identifier
1359
1359
  # @param [Hash] s TBD surface parameters
1360
- # @option s [#to_f] :heatloss heat loss from major thermal bridging, in W/K
1361
- # @option s [#to_f] :net surface net area, in m2
1360
+ # @option s [Numeric] :heatloss heat loss from major thermal bridging, in W/K
1361
+ # @option s [Numeric] :net surface net area, in m2
1362
1362
  # @option s [:massless, :standard] :ltype indexed layer type
1363
- # @option s [#to_i] :index deratable construction layer index
1364
- # @option s [#to_f] :r deratable layer Rsi-factor, in m2•K/W
1363
+ # @option s [Integer] :index deratable construction layer index
1364
+ # @option s [Numeric] :r deratable layer Rsi-factor, in m2•K/W
1365
1365
  # @param lc [OpenStudio::Model::LayeredConstruction] a layered construction
1366
1366
  #
1367
- # @return [OpenStudio::Model::Material] derated (cloned) material
1367
+ # @return [OpenStudio::Model::OpaqueMaterial] derated (cloned) material
1368
1368
  # @return [nil] if invalid input (see logs)
1369
1369
  def derate(id = "", s = {}, lc = nil)
1370
1370
  mth = "TBD::#{__callee__}"
1371
1371
  m = nil
1372
- id = trim(id)
1373
1372
  kys = [:heatloss, :net, :ltype, :index, :r]
1374
- ck1 = s.is_a?(Hash)
1375
- ck2 = lc.is_a?(OpenStudio::Model::LayeredConstruction)
1376
- return mismatch("id" , id, cl6, mth) if id.empty?
1377
- return mismatch("#{id} surface" , s , cl1, mth) unless ck1
1378
- return mismatch("#{id} construction", lc, cl2, mth) unless ck2
1373
+ cl = OpenStudio::Model::LayeredConstruction
1374
+ return mismatch("lc", lc, cl, mth) unless lc.respond_to?(NS)
1375
+ return mismatch("id", id, String, mth) unless id.respond_to?(:to_sym)
1376
+
1377
+ id = trim(id)
1378
+ nom = lc.nameString
1379
+ return invalid("id", mth, 1) if id.empty?
1380
+ return mismatch(nom, lc, cl, mth) unless lc.is_a?(cl)
1381
+ return mismatch("#{nom} surface", s, Hash, mth) unless s.is_a?(Hash)
1382
+
1383
+ if nom.downcase.include?(" tbd")
1384
+ log(WRN, "Won't derate '#{nom}': tagged as derated (#{mth})")
1385
+ return m
1386
+ end
1379
1387
 
1380
1388
  kys.each do |k|
1381
1389
  tag = "#{id} #{k}"
1382
- return hashkey(tag, s, k, mth, ERR) unless s.key?(k)
1390
+ return hashkey(tag, s, k, mth) unless s.key?(k)
1383
1391
 
1384
1392
  case k
1385
- when :heatloss
1386
- return mismatch(tag, s[k], Numeric, mth) unless s[k].respond_to?(:to_f)
1387
- return zero(tag, mth, WRN) if s[k].to_f.abs < 0.001
1388
- when :net, :r
1389
- return mismatch(tag, s[k], Numeric, mth) unless s[k].respond_to?(:to_f)
1390
- return negative(tag, mth, 2, ERR) if s[k].to_f < 0
1391
- return zero(tag, mth, WRN) if s[k].to_f.abs < 0.001
1392
- when :index
1393
- return mismatch(tag, s[k], Numeric, mth) unless s[k].respond_to?(:to_i)
1394
- return negative(tag, mth, 2, ERR) if s[k].to_f < 0
1395
- else # :ltype
1393
+ when :ltype
1396
1394
  next if [:massless, :standard].include?(s[k])
1397
- return invalid(tag, mth, 2, ERR)
1398
- end
1399
- end
1395
+ return invalid(tag, mth, 2)
1396
+ when :index
1397
+ return mismatch(tag, s[k], Integer, mth) unless s[k].is_a?(Integer)
1398
+ return invalid(tag, mth, 2) unless s[k].between?(0, lc.numLayers - 1)
1399
+ else
1400
+ return mismatch(tag, s[k], Numeric, mth) unless s[k].is_a?(Numeric)
1401
+ next if k == :heatloss
1400
1402
 
1401
- if lc.nameString.downcase.include?(" tbd")
1402
- log(WRN, "Won't derate '#{id}': tagged as derated (#{mth})")
1403
- return m
1403
+ return negative(tag, mth, 2) if s[k] < 0
1404
+ return zero(tag, mth) if s[k].abs < 0.001
1405
+ end
1404
1406
  end
1405
1407
 
1406
1408
  model = lc.model
1407
- ltype = s[:ltype ]
1408
- index = s[:index ].to_i
1409
- net = s[:net ].to_f
1410
- r = s[:r ].to_f
1411
- u = s[:heatloss].to_f / net
1409
+ ltype = s[:ltype]
1410
+ index = s[:index]
1411
+ net = s[:net]
1412
+ r = s[:r]
1413
+ u = s[:heatloss] / net
1412
1414
  loss = 0
1413
- de_u = 1 / r + u # derated U
1414
- de_r = 1 / de_u # derated R
1415
+ de_u = 1 / r + u # derated insulating material U
1416
+ de_r = 1 / de_u # derated insulating material R
1415
1417
 
1416
1418
  if ltype == :massless
1417
- m = lc.getLayer(index).to_MasslessOpaqueMaterial
1419
+ m = lc.getLayer(index).to_MasslessOpaqueMaterial
1418
1420
  return invalid("#{id} massless layer?", mth, 0) if m.empty?
1419
- m = m.get
1420
- up = ""
1421
- up = "uprated " if m.nameString.downcase.include?(" uprated")
1422
- m = m.clone(model).to_MasslessOpaqueMaterial.get
1423
- m.setName("#{id} #{up}m tbd")
1424
- de_r = 0.001 unless de_r > 0.001
1425
- loss = (de_u - 1 / de_r) * net unless de_r > 0.001
1426
- m.setThermalResistance(de_r)
1421
+
1422
+ m = m.get
1423
+ up = m.nameString.downcase.include?(" uprated") ? "uprated " : ""
1424
+ m = m.clone(model).to_MasslessOpaqueMaterial.get
1425
+ m.setName("#{id} #{up}m tbd")
1426
+
1427
+ de_r = RMIN unless de_r > RMIN
1428
+ loss = (de_u - 1 / de_r) * net unless de_r > RMIN
1429
+
1430
+ unless m.setThermalResistance(de_r)
1431
+ return invalid("Can't derate #{id}: RSi#{de_r.round(2)}", mth)
1432
+ end
1427
1433
  else
1428
- m = lc.getLayer(index).to_StandardOpaqueMaterial
1434
+ m = lc.getLayer(index).to_StandardOpaqueMaterial
1429
1435
  return invalid("#{id} standard layer?", mth, 0) if m.empty?
1430
- m = m.get
1431
- up = ""
1432
- up = "uprated " if m.nameString.downcase.include?(" uprated")
1433
- m = m.clone(model).to_StandardOpaqueMaterial.get
1434
- m.setName("#{id} #{up}m tbd")
1435
- k = m.thermalConductivity
1436
-
1437
- if de_r > 0.001
1438
- d = de_r * k
1439
-
1440
- unless d > 0.003
1441
- d = 0.003
1442
- k = d / de_r
1443
- k = 3 unless k < 3
1444
- loss = (de_u - k / d) * net unless k < 3
1445
- end
1446
- else # de_r < 0.001 m2•K/W
1447
- d = 0.001 * k
1448
- d = 0.003 unless d > 0.003
1449
- k = d / 0.001 unless d > 0.003
1450
- loss = (de_u - k / d) * net
1436
+
1437
+ m = m.get
1438
+ up = m.nameString.downcase.include?(" uprated") ? "uprated " : ""
1439
+ m = m.clone(model).to_StandardOpaqueMaterial.get
1440
+ m.setName("#{id} #{up}m tbd")
1441
+
1442
+ d = m.thickness
1443
+ k = (d / de_r).clamp(KMIN, KMAX)
1444
+ d = (k * de_r).clamp(DMIN, DMAX)
1445
+
1446
+ loss = (de_u - k / d) * net unless d / k > RMIN
1447
+
1448
+ unless m.setThermalConductivity(k)
1449
+ return invalid("Can't derate #{id}: K#{k.round(3)}", mth)
1451
1450
  end
1452
1451
 
1453
- m.setThickness(d)
1454
- m.setThermalConductivity(k)
1452
+ unless m.setThickness(d)
1453
+ return invalid("Can't derate #{id}: #{(d*1000).to_i}mm", mth)
1454
+ end
1455
1455
  end
1456
1456
 
1457
1457
  if m && loss > TOL
@@ -1941,14 +1941,38 @@ module TBD
1941
1941
  ids = windows.keys + doors.keys + skylights.keys
1942
1942
  end
1943
1943
 
1944
- unless ids.include?(i)
1945
- log(ERR, "Orphaned subsurface #{i} (mth)")
1944
+ adj = nil
1945
+
1946
+ unless ids.include?(i) # adjacent sub surface?
1947
+ sb = model.getSubSurfaceByName(i)
1948
+
1949
+ if sb.empty?
1950
+ log(DBG, "Orphaned subsurface #{i} (#{mth})?")
1951
+ else
1952
+ sb = sb.get
1953
+ adj = sb.adjacentSubSurface
1954
+
1955
+ if adj.empty?
1956
+ log(DBG, "Orphaned sub #{i} (#{mth})?")
1957
+ end
1958
+ end
1959
+
1946
1960
  next
1947
1961
  end
1948
1962
 
1949
- window = windows.key?(i) ? windows[i] : {}
1950
- door = doors.key?(i) ? doors[i] : {}
1951
- skylight = skylights.key?(i) ? skylights[i] : {}
1963
+ if adj
1964
+ window = windows.key?(i) ? windows[i] : {}
1965
+ door = doors.key?(i) ? doors[i] : {}
1966
+ skylight = skylights.key?(i) ? skylights[i] : {}
1967
+ else
1968
+ window = windows.key?(i) ? windows[i] : {}
1969
+ door = doors.key?(i) ? doors[i] : {}
1970
+ skylight = skylights.key?(i) ? skylights[i] : {}
1971
+ end
1972
+
1973
+ # window = windows.key?(i) ? windows[i] : {}
1974
+ # door = doors.key?(i) ? doors[i] : {}
1975
+ # skylight = skylights.key?(i) ? skylights[i] : {}
1952
1976
 
1953
1977
  sub = window unless window.empty?
1954
1978
  sub = door unless door.empty?
@@ -2939,12 +2963,12 @@ module TBD
2939
2963
  up = argh[:uprate_walls] || argh[:uprate_roofs] || argh[:uprate_floors]
2940
2964
  uprate(model, tbd[:surfaces], argh) if up
2941
2965
 
2942
- # Derated (cloned) constructions are unique to each deratable surface.
2943
- # Unique construction names are prefixed with the surface name,
2944
- # and suffixed with " tbd", indicating that the construction is
2945
- # henceforth thermally derated. The " tbd" expression is also key in
2946
- # avoiding inadvertent derating - TBD will not derate constructions
2947
- # (or rather layered materials) having " tbd" in their OpenStudio name.
2966
+ # A derated (cloned) construction and (cloned) insulating layer are unique
2967
+ # to each deratable surface. Unique construction and material names are
2968
+ # prefixed with the surface name, and suffixed with " tbd", indicating that
2969
+ # the construction is henceforth thermally derated. The " tbd" expression
2970
+ # is also key in avoiding inadvertent sequential derating - TBD will not
2971
+ # derate a construction/material pair having " tbd" in their OpenStudio name.
2948
2972
  tbd[:surfaces].each do |id, surface|
2949
2973
  next unless surface.key?(:construction)
2950
2974
  next unless surface.key?(:index)
@@ -3138,9 +3162,9 @@ module TBD
3138
3162
  argh[:uprate_walls ] = false unless argh.key?(:uprate_walls )
3139
3163
  argh[:uprate_roofs ] = false unless argh.key?(:uprate_roofs )
3140
3164
  argh[:uprate_floors] = false unless argh.key?(:uprate_floors)
3141
- argh[:wall_ut ] = 5.678 unless argh.key?(:wall_ut )
3142
- argh[:roof_ut ] = 5.678 unless argh.key?(:roof_ut )
3143
- argh[:floor_ut ] = 5.678 unless argh.key?(:floor_ut )
3165
+ argh[:wall_ut ] = UMAX unless argh.key?(:wall_ut )
3166
+ argh[:roof_ut ] = UMAX unless argh.key?(:roof_ut )
3167
+ argh[:floor_ut ] = UMAX unless argh.key?(:floor_ut )
3144
3168
  argh[:wall_option ] = "" unless argh.key?(:wall_option )
3145
3169
  argh[:roof_option ] = "" unless argh.key?(:roof_option )
3146
3170
  argh[:floor_option ] = "" unless argh.key?(:floor_option )
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
  #
3
- # Copyright (c) 2020-2024 Denis Bourgeois & Dan Macumber
3
+ # Copyright (c) 2020-2025 Denis Bourgeois & Dan Macumber
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the "Software"), to deal