tbd 3.2.0 → 3.2.2
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.
- checksums.yaml +4 -4
- data/README.md +3 -7
- data/Rakefile +8 -7
- data/lib/measures/tbd/measure.xml +24 -24
- data/lib/measures/tbd/resources/geo.rb +7 -3
- data/lib/measures/tbd/resources/model.rb +0 -6
- data/lib/measures/tbd/resources/psi.rb +4 -3
- data/lib/measures/tbd/resources/ua.rb +154 -145
- data/lib/measures/tbd/resources/version.rb +1 -1
- data/lib/tbd/geo.rb +7 -3
- data/lib/tbd/psi.rb +4 -3
- data/lib/tbd/ua.rb +154 -145
- data/lib/tbd/version.rb +1 -1
- data/lib/tbd.rb +8 -8
- metadata +3 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 858b576df6d2a7c00b547c1bcb86fcae917f441c236f012610309b5df96f2d19
         | 
| 4 | 
            +
              data.tar.gz: ee47f03ce21e7ef8d95968aa0d159a39875ca546c32b48c8f96d7779b1ef341d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 1d7d4ad54c0d8d06776b868037a717d8efc11d4f1e1290cbf972202bae04ef4e6e6ea21cf227a8405c508c1d31f1bbb9e5667a21af9186984b28eee19a5e4395
         | 
| 7 | 
            +
              data.tar.gz: eaae502337964abffe89643e4c1e6070f3a228db3ef6d87983f0cc7c9218f124e72eae6e502bd06ff7119fd594ed784d3f4232a3bd1ddb03c1d23f7bcce1c951
         | 
    
        data/README.md
    CHANGED
    
    | @@ -32,9 +32,7 @@ TBD is systematically tested against updated OpenStudio versions (since v3.0.0). | |
| 32 32 |  | 
| 33 33 | 
             
            ### Windows Installation
         | 
| 34 34 |  | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
            From the command line, check that the ruby installation returns the correct Ruby version:
         | 
| 35 | 
            +
            Either install Ruby using the [RubyInstaller](https://rubyinstaller.org/downloads/archives/) for [Ruby 2.7.2 (x64)](https://github.com/oneclick/rubyinstaller2/releases/tag/RubyInstaller-2.7.2-1/rubyinstaller-2.7.2-1-x64.exe), or preferably under [WSL2](https://gist.github.com/brgix/0d968d8f32c41f13300dc6769414df79). Run the following steps if going down the _RubyInstaller_ route. From the command line, check that the ruby installation returns the correct Ruby version:
         | 
| 38 36 | 
             
            ```
         | 
| 39 37 | 
             
            ruby -v
         | 
| 40 38 | 
             
            ```
         | 
| @@ -57,9 +55,6 @@ Verify your OpenStudio and Ruby configuration: | |
| 57 55 | 
             
            ruby -e "require 'openstudio'" -e "puts OpenStudio::Model::Model.new"
         | 
| 58 56 | 
             
            ```
         | 
| 59 57 |  | 
| 60 | 
            -
            `git clone` the TBD repo, then run basic tests to ensure the measure operates properly (see end of this README).
         | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 58 | 
             
            ### MacOS Installation
         | 
| 64 59 |  | 
| 65 60 | 
             
            MacOS already comes with Ruby, but likely not the right Ruby version for the desired OpenStudio measure development [environment](https://github.com/NREL/OpenStudio/wiki/OpenStudio-SDK-Version-Compatibility-Matrix). Instructions here show how to install Ruby v2.7.2 alongside MacOS's own Ruby version. Although no longer officially supported, instructions for an OpenStudio v2.9.1 setup is described [here](https://github.com/rd2/tbd/blob/master/v291_MacOS.md).
         | 
| @@ -117,8 +112,9 @@ cd ~/Documents/sandbox340 | |
| 117 112 | 
             
            ruby -e "require 'openstudio'" -e "puts OpenStudio::Model::Model.new"
         | 
| 118 113 | 
             
            ```
         | 
| 119 114 |  | 
| 120 | 
            -
             | 
| 115 | 
            +
            ## Clone TBD
         | 
| 121 116 |  | 
| 117 | 
            +
            Once done with either the Windows or MacOS setup, install the latest version of _git_ (e.g. through Homebrew), then ```git clone``` the TBD repo, e.g. under "sandbox340". Run the basic tests below to ensure the measure operates as expected.
         | 
| 122 118 |  | 
| 123 119 | 
             
            ## Complete list of test commands
         | 
| 124 120 |  | 
    
        data/Rakefile
    CHANGED
    
    | @@ -2,28 +2,29 @@ require "bundler/gem_tasks" | |
| 2 2 | 
             
            require "rspec/core/rake_task"
         | 
| 3 3 |  | 
| 4 4 | 
             
            RSpec::Core::RakeTask.new(:spec) do |t|
         | 
| 5 | 
            -
             | 
| 5 | 
            +
              t.rspec_opts = "--exclude-pattern \'spec/**/*suite_spec.rb\'"
         | 
| 6 6 | 
             
            end
         | 
| 7 7 |  | 
| 8 8 | 
             
            task default: :spec
         | 
| 9 9 |  | 
| 10 10 | 
             
            desc "Update Library Files"
         | 
| 11 11 | 
             
            task :libraries do
         | 
| 12 | 
            -
              puts "Updating Library Files"
         | 
| 12 | 
            +
              # puts "Updating Library Files"
         | 
| 13 13 |  | 
| 14 14 | 
             
              require "fileutils"
         | 
| 15 15 |  | 
| 16 16 | 
             
              libs  = ["topolys", "osut", "oslg", "tbd"]
         | 
| 17 17 | 
             
              files = {}
         | 
| 18 | 
            -
             | 
| 18 | 
            +
              
         | 
| 19 19 | 
             
              $:.each do |path|
         | 
| 20 20 | 
             
                libs.each do |l|
         | 
| 21 21 | 
             
                  next unless path.include?(l)
         | 
| 22 | 
            +
             | 
| 22 23 | 
             
                  files[l] = Dir.glob(File.join(path, "#{l}/*.rb"))
         | 
| 23 24 | 
             
                  files[l].delete_if { |f| f.include?("version.rb") }  unless l == "topolys"
         | 
| 24 | 
            -
                  puts "#{l} lib files:"
         | 
| 25 | 
            -
                  files[l].each { |lf| puts "... #{lf}" }
         | 
| 26 | 
            -
                  puts
         | 
| 25 | 
            +
                  # puts "#{l} lib files:"
         | 
| 26 | 
            +
                  # files[l].each { |lf| puts "... #{lf}" }
         | 
| 27 | 
            +
                  # puts
         | 
| 27 28 | 
             
                end
         | 
| 28 29 | 
             
              end
         | 
| 29 30 |  | 
| @@ -38,7 +39,7 @@ end | |
| 38 39 |  | 
| 39 40 | 
             
            desc "Update Measure"
         | 
| 40 41 | 
             
            task measure: [:libraries] do
         | 
| 41 | 
            -
              puts "Updating Measure"
         | 
| 42 | 
            +
              # puts "Updating Measure"
         | 
| 42 43 |  | 
| 43 44 | 
             
              require "openstudio"
         | 
| 44 45 | 
             
              require "open3"
         | 
| @@ -3,8 +3,8 @@ | |
| 3 3 | 
             
              <schema_version>3.0</schema_version>
         | 
| 4 4 | 
             
              <name>tbd_measure</name>
         | 
| 5 5 | 
             
              <uid>8890787b-8c25-4dc8-8641-b6be1b6c2357</uid>
         | 
| 6 | 
            -
              <version_id> | 
| 7 | 
            -
              <version_modified> | 
| 6 | 
            +
              <version_id>ca5db4f4-8624-4699-a544-609690a03d14</version_id>
         | 
| 7 | 
            +
              <version_modified>20230322T224647Z</version_modified>
         | 
| 8 8 | 
             
              <xml_checksum>99772807</xml_checksum>
         | 
| 9 9 | 
             
              <class_name>TBDMeasure</class_name>
         | 
| 10 10 | 
             
              <display_name>Thermal Bridging and Derating - TBD</display_name>
         | 
| @@ -388,18 +388,6 @@ | |
| 388 388 | 
             
                  <usage_type>resource</usage_type>
         | 
| 389 389 | 
             
                  <checksum>D80E9AE6</checksum>
         | 
| 390 390 | 
             
                </file>
         | 
| 391 | 
            -
                <file>
         | 
| 392 | 
            -
                  <filename>model.rb</filename>
         | 
| 393 | 
            -
                  <filetype>rb</filetype>
         | 
| 394 | 
            -
                  <usage_type>resource</usage_type>
         | 
| 395 | 
            -
                  <checksum>57ED37BF</checksum>
         | 
| 396 | 
            -
                </file>
         | 
| 397 | 
            -
                <file>
         | 
| 398 | 
            -
                  <filename>version.rb</filename>
         | 
| 399 | 
            -
                  <filetype>rb</filetype>
         | 
| 400 | 
            -
                  <usage_type>resource</usage_type>
         | 
| 401 | 
            -
                  <checksum>05CC939E</checksum>
         | 
| 402 | 
            -
                </file>
         | 
| 403 391 | 
             
                <file>
         | 
| 404 392 | 
             
                  <filename>LICENSE.md</filename>
         | 
| 405 393 | 
             
                  <filetype>md</filetype>
         | 
| @@ -442,28 +430,40 @@ | |
| 442 430 | 
             
                  <checksum>58ED6635</checksum>
         | 
| 443 431 | 
             
                </file>
         | 
| 444 432 | 
             
                <file>
         | 
| 445 | 
            -
                  <filename> | 
| 433 | 
            +
                  <filename>README.md</filename>
         | 
| 434 | 
            +
                  <filetype>md</filetype>
         | 
| 435 | 
            +
                  <usage_type>readme</usage_type>
         | 
| 436 | 
            +
                  <checksum>B836C43A</checksum>
         | 
| 437 | 
            +
                </file>
         | 
| 438 | 
            +
                <file>
         | 
| 439 | 
            +
                  <filename>psi.rb</filename>
         | 
| 446 440 | 
             
                  <filetype>rb</filetype>
         | 
| 447 441 | 
             
                  <usage_type>resource</usage_type>
         | 
| 448 | 
            -
                  <checksum> | 
| 442 | 
            +
                  <checksum>1045EF38</checksum>
         | 
| 449 443 | 
             
                </file>
         | 
| 450 444 | 
             
                <file>
         | 
| 451 | 
            -
                  <filename> | 
| 445 | 
            +
                  <filename>model.rb</filename>
         | 
| 452 446 | 
             
                  <filetype>rb</filetype>
         | 
| 453 447 | 
             
                  <usage_type>resource</usage_type>
         | 
| 454 | 
            -
                  <checksum> | 
| 448 | 
            +
                  <checksum>8E9A76C7</checksum>
         | 
| 455 449 | 
             
                </file>
         | 
| 456 450 | 
             
                <file>
         | 
| 457 | 
            -
                  <filename> | 
| 458 | 
            -
                  <filetype> | 
| 459 | 
            -
                  <usage_type> | 
| 460 | 
            -
                  <checksum> | 
| 451 | 
            +
                  <filename>version.rb</filename>
         | 
| 452 | 
            +
                  <filetype>rb</filetype>
         | 
| 453 | 
            +
                  <usage_type>resource</usage_type>
         | 
| 454 | 
            +
                  <checksum>A3BB982A</checksum>
         | 
| 461 455 | 
             
                </file>
         | 
| 462 456 | 
             
                <file>
         | 
| 463 | 
            -
                  <filename> | 
| 457 | 
            +
                  <filename>geo.rb</filename>
         | 
| 458 | 
            +
                  <filetype>rb</filetype>
         | 
| 459 | 
            +
                  <usage_type>resource</usage_type>
         | 
| 460 | 
            +
                  <checksum>8242FCEF</checksum>
         | 
| 461 | 
            +
                </file>
         | 
| 462 | 
            +
                <file>
         | 
| 463 | 
            +
                  <filename>ua.rb</filename>
         | 
| 464 464 | 
             
                  <filetype>rb</filetype>
         | 
| 465 465 | 
             
                  <usage_type>resource</usage_type>
         | 
| 466 | 
            -
                  <checksum> | 
| 466 | 
            +
                  <checksum>695F5AC2</checksum>
         | 
| 467 467 | 
             
                </file>
         | 
| 468 468 | 
             
              </files>
         | 
| 469 469 | 
             
            </measure>
         | 
| @@ -292,28 +292,31 @@ module TBD | |
| 292 292 |  | 
| 293 293 | 
             
                return mismatch("model", model, cl1, mth)          unless model.is_a?(cl1)
         | 
| 294 294 | 
             
                return mismatch("surface", surface, cl2, mth)      unless surface.is_a?(cl2)
         | 
| 295 | 
            -
             | 
| 296 | 
            -
                return nil unless validate(surface)
         | 
| 295 | 
            +
                return nil                                         unless validate(surface)
         | 
| 297 296 |  | 
| 298 297 | 
             
                nom    = surface.nameString
         | 
| 299 298 | 
             
                surf   = {}
         | 
| 300 299 | 
             
                subs   = {}
         | 
| 301 300 | 
             
                fd     = false
         | 
| 302 301 | 
             
                return   empty("'#{nom}' space", mth, ERR)           if surface.space.empty?
         | 
| 302 | 
            +
             | 
| 303 303 | 
             
                space  = surface.space.get
         | 
| 304 304 | 
             
                stype  = space.spaceType
         | 
| 305 305 | 
             
                story  = space.buildingStory
         | 
| 306 306 | 
             
                tr     = transforms(model, space)
         | 
| 307 307 | 
             
                return   invalid("'#{nom}' transform", mth, 0, FTL)  unless tr[:t] && tr[:r]
         | 
| 308 | 
            +
             | 
| 308 309 | 
             
                t      = tr[:t]
         | 
| 309 310 | 
             
                n      = trueNormal(surface, tr[:r])
         | 
| 310 311 | 
             
                return   invalid("'#{nom}' normal", mth, 0, FTL)     unless n
         | 
| 312 | 
            +
             | 
| 311 313 | 
             
                type   = surface.surfaceType.downcase
         | 
| 312 314 | 
             
                facing = surface.outsideBoundaryCondition
         | 
| 313 315 |  | 
| 314 316 | 
             
                if facing.downcase == "surface"
         | 
| 315 317 | 
             
                  empty = surface.adjacentSurface.empty?
         | 
| 316 | 
            -
                  return invalid("'#{nom}': adjacent surface", mth, 0, ERR) | 
| 318 | 
            +
                  return invalid("'#{nom}': adjacent surface", mth, 0, ERR) if empty
         | 
| 319 | 
            +
             | 
| 317 320 | 
             
                  facing = surface.adjacentSurface.get.nameString
         | 
| 318 321 | 
             
                end
         | 
| 319 322 |  | 
| @@ -350,6 +353,7 @@ module TBD | |
| 350 353 | 
             
                surf[:story      ] = story.get               unless story.empty?
         | 
| 351 354 | 
             
                surf[:n          ] = n
         | 
| 352 355 | 
             
                surf[:gross      ] = surface.grossArea
         | 
| 356 | 
            +
                surf[:filmRSI    ] = surface.filmResistance
         | 
| 353 357 |  | 
| 354 358 | 
             
                surface.subSurfaces.sort_by { |s| s.nameString }.each do |s|
         | 
| 355 359 | 
             
                  next unless validate(s)
         | 
| @@ -975,8 +975,9 @@ module TBD | |
| 975 975 | 
             
                    end
         | 
| 976 976 | 
             
                  end
         | 
| 977 977 |  | 
| 978 | 
            -
                   | 
| 979 | 
            -
                  surface[: | 
| 978 | 
            +
                  # Recover if valid setpoints.
         | 
| 979 | 
            +
                  surface[:heating] = heat[:spt] if heat && heat[:spt]
         | 
| 980 | 
            +
                  surface[:cooling] = cool[:spt] if cool && cool[:spt]
         | 
| 980 981 |  | 
| 981 982 | 
             
                  tbd[:surfaces][s.nameString] = surface
         | 
| 982 983 | 
             
                end                                            # (opaque) surfaces populated
         | 
| @@ -1486,7 +1487,7 @@ module TBD | |
| 1486 1487 |  | 
| 1487 1488 | 
             
                    edge[:surfaces].keys.each do |i|
         | 
| 1488 1489 | 
             
                      break     if is[:rimjoist] || is[:balcony]
         | 
| 1489 | 
            -
                      break unless deratables.size  | 
| 1490 | 
            +
                      break unless deratables.size > 0
         | 
| 1490 1491 | 
             
                      break     if floors.key?(id)
         | 
| 1491 1492 | 
             
                      next      if i == id
         | 
| 1492 1493 | 
             
                      next  unless floors.key?(i)
         | 
| @@ -39,13 +39,14 @@ module TBD | |
| 39 39 | 
             
                cl1 = OpenStudio::Model::Model
         | 
| 40 40 | 
             
                cl2 = OpenStudio::Model::LayeredConstruction
         | 
| 41 41 | 
             
                cl3 = Numeric
         | 
| 42 | 
            +
                cl4 = String
         | 
| 42 43 |  | 
| 43 | 
            -
                return mismatch("model", model, cl1, mth, DBG, res) | 
| 44 | 
            -
                return mismatch("id", | 
| 45 | 
            -
                return mismatch("lc", | 
| 46 | 
            -
                return mismatch("hloss", hloss, cl3, mth, DBG, res) | 
| 47 | 
            -
                return mismatch("film", | 
| 48 | 
            -
                return mismatch("Ut", | 
| 44 | 
            +
                return mismatch("model", model, cl1, mth, DBG, res) unless model.is_a?(cl1)
         | 
| 45 | 
            +
                return mismatch("id"   ,    id, cl4, mth, DBG, res) unless id.is_a?(cl4)
         | 
| 46 | 
            +
                return mismatch("lc"   ,    lc, cl2, mth, DBG, res) unless lc.is_a?(cl2)
         | 
| 47 | 
            +
                return mismatch("hloss", hloss, cl3, mth, DBG, res) unless hloss.is_a?(cl3)
         | 
| 48 | 
            +
                return mismatch("film" ,  film, cl3, mth, DBG, res) unless film.is_a?(cl3)
         | 
| 49 | 
            +
                return mismatch("Ut"   ,    ut, cl3, mth, DBG, res) unless ut.is_a?(cl3)
         | 
| 49 50 |  | 
| 50 51 | 
             
                loss        = 0.0                   # residual heatloss (not assigned) [W/K]
         | 
| 51 52 | 
             
                area        = lc.getNetArea
         | 
| @@ -54,12 +55,12 @@ module TBD | |
| 54 55 | 
             
                lyr[:index] = nil unless lyr[:index] >= 0
         | 
| 55 56 | 
             
                lyr[:index] = nil unless lyr[:index] < lc.layers.size
         | 
| 56 57 |  | 
| 57 | 
            -
                return invalid("'#{id}' layer index", mth, 0, ERR, res) | 
| 58 | 
            -
                return zero("'#{id}': heatloss", mth, | 
| 59 | 
            -
                return zero("'#{id}': films", mth, | 
| 60 | 
            -
                return zero("'#{id}': Ut", mth, | 
| 61 | 
            -
                return invalid("'#{id}': Ut", mth, 0, WRN, res) | 
| 62 | 
            -
                return zero("'#{id}': net area (m2)", mth, | 
| 58 | 
            +
                return invalid("'#{id}' layer index", mth, 0, ERR, res) unless lyr[:index]
         | 
| 59 | 
            +
                return zero("'#{id}': heatloss"     , mth,    WRN, res) unless hloss > TOL
         | 
| 60 | 
            +
                return zero("'#{id}': films"        , mth,    WRN, res) unless film  > TOL
         | 
| 61 | 
            +
                return zero("'#{id}': Ut"           , mth,    WRN, res) unless ut    > TOL
         | 
| 62 | 
            +
                return invalid("'#{id}': Ut"        , mth, 0, WRN, res) unless ut    < 5.678
         | 
| 63 | 
            +
                return zero("'#{id}': net area (m2)", mth,    ERR, res) unless area  > TOL
         | 
| 63 64 |  | 
| 64 65 | 
             
                # First, calculate initial layer RSi to initially meet Ut target.
         | 
| 65 66 | 
             
                rt     = 1 / ut                      #                target construction Rt
         | 
| @@ -76,7 +77,7 @@ module TBD | |
| 76 77 |  | 
| 77 78 | 
             
                if lyr[:type] == :massless
         | 
| 78 79 | 
             
                  m     = lc.getLayer(lyr[:index]).to_MasslessOpaqueMaterial
         | 
| 79 | 
            -
                  return  invalid("'#{id}' massless layer?", mth, 0) | 
| 80 | 
            +
                  return  invalid("'#{id}' massless layer?", mth, 0, DBG, res)   if m.empty?
         | 
| 80 81 |  | 
| 81 82 | 
             
                  m     = m.get.clone(model).to_MasslessOpaqueMaterial.get
         | 
| 82 83 | 
             
                          m.setName("#{id} uprated")
         | 
| @@ -85,7 +86,7 @@ module TBD | |
| 85 86 | 
             
                          m.setThermalResistance(new_r)
         | 
| 86 87 | 
             
                else # type == :standard
         | 
| 87 88 | 
             
                  m     = lc.getLayer(lyr[:index]).to_StandardOpaqueMaterial
         | 
| 88 | 
            -
                  return  invalid("'#{id}' standard layer?", mth, 0) | 
| 89 | 
            +
                  return  invalid("'#{id}' standard layer?", mth, 0, DBG, res)   if m.empty?
         | 
| 89 90 |  | 
| 90 91 | 
             
                  m     = m.get.clone(model).to_StandardOpaqueMaterial.get
         | 
| 91 92 | 
             
                          m.setName("#{id} uprated")
         | 
| @@ -141,11 +142,12 @@ module TBD | |
| 141 142 | 
             
                mth = "TBD::#{__callee__}"
         | 
| 142 143 | 
             
                cl1 = OpenStudio::Model::Model
         | 
| 143 144 | 
             
                cl2 = Hash
         | 
| 145 | 
            +
                cl3 = OpenStudio::Model::LayeredConstruction
         | 
| 144 146 | 
             
                a   = false
         | 
| 145 147 |  | 
| 146 | 
            -
                return mismatch("model", model, cl1, mth, DBG, a) | 
| 147 | 
            -
                return mismatch("surfaces", | 
| 148 | 
            -
                return mismatch("argh", model, cl1, mth, DBG, a) | 
| 148 | 
            +
                return mismatch("model"   , model, cl1, mth, DBG, a) unless model.is_a?(cl1)
         | 
| 149 | 
            +
                return mismatch("surfaces",     s, cl2, mth, DBG, a) unless s.is_a?(cl2)
         | 
| 150 | 
            +
                return mismatch("argh"    , model, cl1, mth, DBG, a) unless argh.is_a?(cl2)
         | 
| 149 151 |  | 
| 150 152 | 
             
                argh[:uprate_walls ] = false unless argh.key?(:uprate_walls )
         | 
| 151 153 | 
             
                argh[:uprate_roofs ] = false unless argh.key?(:uprate_roofs )
         | 
| @@ -168,11 +170,13 @@ module TBD | |
| 168 170 | 
             
                groups[:roof ][:op] = argh[:roof_option  ]
         | 
| 169 171 | 
             
                groups[:floor][:op] = argh[:floor_option ]
         | 
| 170 172 |  | 
| 171 | 
            -
                groups.each do | | 
| 173 | 
            +
                groups.each do |type, g|
         | 
| 172 174 | 
             
                  next unless g[:up]
         | 
| 173 175 | 
             
                  next unless g[:ut].is_a?(Numeric)
         | 
| 174 176 | 
             
                  next unless g[:ut] < 5.678
         | 
| 175 177 |  | 
| 178 | 
            +
                  typ  = type
         | 
| 179 | 
            +
                  typ  = :ceiling if typ == :roof # fix in future revision. TO-DO.
         | 
| 176 180 | 
             
                  coll = {}
         | 
| 177 181 | 
             
                  area = 0
         | 
| 178 182 | 
             
                  film = 100000000000000
         | 
| @@ -183,86 +187,81 @@ module TBD | |
| 183 187 | 
             
                         g[:op].downcase == "all floor constructions"
         | 
| 184 188 |  | 
| 185 189 | 
             
                  if g[:op].empty?
         | 
| 186 | 
            -
                    log(ERR, "Construction to uprate? (#{mth})")
         | 
| 190 | 
            +
                    log(ERR, "Construction (#{type}) to uprate? (#{mth})")
         | 
| 187 191 | 
             
                  elsif all
         | 
| 188 | 
            -
                     | 
| 189 | 
            -
                      next unless  | 
| 190 | 
            -
                      next unless  | 
| 191 | 
            -
                      next | 
| 192 | 
            -
                      next | 
| 193 | 
            -
             | 
| 194 | 
            -
                       | 
| 195 | 
            -
                       | 
| 196 | 
            -
             | 
| 197 | 
            -
                       | 
| 198 | 
            -
                       | 
| 199 | 
            -
             | 
| 192 | 
            +
                    s.each do |nom, surface|
         | 
| 193 | 
            +
                      next unless surface.key?(:deratable   )
         | 
| 194 | 
            +
                      next unless surface.key?(:type        )
         | 
| 195 | 
            +
                      next unless surface.key?(:construction)
         | 
| 196 | 
            +
                      next unless surface.key?(:filmRSI     )
         | 
| 197 | 
            +
                      next unless surface.key?(:index       )
         | 
| 198 | 
            +
                      next unless surface.key?(:ltype       )
         | 
| 199 | 
            +
                      next unless surface.key?(:r           )
         | 
| 200 | 
            +
                      next unless surface[:deratable   ]
         | 
| 201 | 
            +
                      next unless surface[:type        ] == typ
         | 
| 202 | 
            +
                      next unless surface[:construction].is_a?(cl3)
         | 
| 203 | 
            +
                      next     if surface[:index       ].nil?
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                      # Retain lowest surface film resistance (e.g. tilted surfaces).
         | 
| 206 | 
            +
                      c    = surface[:construction]
         | 
| 207 | 
            +
                      i    = c.nameString
         | 
| 208 | 
            +
                      aire = c.getNetArea
         | 
| 209 | 
            +
                      film = surface[:filmRSI] if surface[:filmRSI] < film
         | 
| 210 | 
            +
             | 
| 211 | 
            +
                      # Retain construction covering largest area. The following conditional
         | 
| 212 | 
            +
                      # is reliable UNLESS linked to other deratable surface types e.g. both
         | 
| 213 | 
            +
                      # floors AND walls (see "elsif lc" corrections below).
         | 
| 214 | 
            +
                      if aire > area
         | 
| 200 215 | 
             
                        lc   = c
         | 
| 216 | 
            +
                        area = aire
         | 
| 201 217 | 
             
                        id   = i
         | 
| 202 218 | 
             
                      end
         | 
| 203 219 |  | 
| 204 | 
            -
                       | 
| 205 | 
            -
                      nom | 
| 206 | 
            -
                      coll[i] = { area: c.getNetArea, lc: c, s: {} } unless coll.key?(i)
         | 
| 207 | 
            -
                      coll[i][:s][nom] = { a: sss.netArea } unless coll[i][:s].key?(nom)
         | 
| 220 | 
            +
                      coll[i]          = { area: aire, lc: c, s: {} } unless coll.key?(i)
         | 
| 221 | 
            +
                      coll[i][:s][nom] = { a: surface[:net] }  unless coll[i][:s].key?(nom)
         | 
| 208 222 | 
             
                    end
         | 
| 209 223 | 
             
                  else
         | 
| 210 224 | 
             
                    id = g[:op]
         | 
| 211 | 
            -
                     | 
| 212 | 
            -
             | 
| 213 | 
            -
                    if  | 
| 214 | 
            -
             | 
| 215 | 
            -
                     | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 218 | 
            -
             | 
| 219 | 
            -
             | 
| 220 | 
            -
             | 
| 221 | 
            -
             | 
| 222 | 
            -
             | 
| 223 | 
            -
             | 
| 224 | 
            -
             | 
| 225 | 
            -
             | 
| 226 | 
            -
             | 
| 227 | 
            -
             | 
| 228 | 
            -
             | 
| 229 | 
            -
             | 
| 230 | 
            -
             | 
| 231 | 
            -
             | 
| 232 | 
            -
             | 
| 233 | 
            -
             | 
| 234 | 
            -
             | 
| 235 | 
            -
             | 
| 236 | 
            -
             | 
| 237 | 
            -
                       | 
| 225 | 
            +
                    lc = model.getConstructionByName(id)
         | 
| 226 | 
            +
                    log(ERR, "Construction '#{id}'? (#{mth})")         if lc.empty?
         | 
| 227 | 
            +
                    next                                               if lc.empty?
         | 
| 228 | 
            +
             | 
| 229 | 
            +
                    lc = lc.get.to_LayeredConstruction
         | 
| 230 | 
            +
                    log(ERR, "'#{id}' layered construction? (#{mth})") if lc.empty?
         | 
| 231 | 
            +
                    next                                               if lc.empty?
         | 
| 232 | 
            +
             | 
| 233 | 
            +
                    lc       = lc.get
         | 
| 234 | 
            +
                    area     = lc.getNetArea
         | 
| 235 | 
            +
                    coll[id] = { area: area, lc: lc, s: {} }
         | 
| 236 | 
            +
             | 
| 237 | 
            +
                    s.each do |nom, surface|
         | 
| 238 | 
            +
                      next unless surface.key?(:deratable   )
         | 
| 239 | 
            +
                      next unless surface.key?(:type        )
         | 
| 240 | 
            +
                      next unless surface.key?(:construction)
         | 
| 241 | 
            +
                      next unless surface.key?(:filmRSI     )
         | 
| 242 | 
            +
                      next unless surface.key?(:index       )
         | 
| 243 | 
            +
                      next unless surface.key?(:ltype       )
         | 
| 244 | 
            +
                      next unless surface.key?(:r           )
         | 
| 245 | 
            +
                      next unless surface[:deratable   ]
         | 
| 246 | 
            +
                      next unless surface[:type        ] == typ
         | 
| 247 | 
            +
                      next unless surface[:construction].is_a?(cl3)
         | 
| 248 | 
            +
                      next     if surface[:index       ].nil?
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                      i = surface[:construction].nameString
         | 
| 251 | 
            +
                      next unless i == id
         | 
| 252 | 
            +
             | 
| 253 | 
            +
                      # Retain lowest surface film resistance (e.g. tilted surfaces).
         | 
| 254 | 
            +
                      film = surface[:filmRSI] if surface[:filmRSI] < film
         | 
| 255 | 
            +
             | 
| 256 | 
            +
                      coll[i][:s][nom] = { a: surface[:net] } unless coll[i][:s].key?(nom)
         | 
| 238 257 | 
             
                    end
         | 
| 239 258 | 
             
                  end
         | 
| 240 259 |  | 
| 241 260 | 
             
                  if coll.empty?
         | 
| 242 | 
            -
                    log(ERR, "No #{ | 
| 261 | 
            +
                    log(ERR, "No #{type} construction to uprate - skipping (#{mth})")
         | 
| 243 262 | 
             
                    next
         | 
| 244 | 
            -
                  elsif lc | 
| 245 | 
            -
                    #  | 
| 246 | 
            -
                    model.getSurfaces.each do |sss|
         | 
| 247 | 
            -
                      next if sss.construction.empty?
         | 
| 248 | 
            -
                      next if sss.construction.get.to_LayeredConstruction.empty?
         | 
| 249 | 
            -
                      c = sss.construction.get.to_LayeredConstruction.get
         | 
| 250 | 
            -
                      i = c.nameString
         | 
| 251 | 
            -
                      next unless coll.key?(i)
         | 
| 252 | 
            -
             | 
| 253 | 
            -
                      unless sss.surfaceType.downcase.include?(label.to_s)
         | 
| 254 | 
            -
                        log(ERR, "Uprating #{label.to_s}, not '#{sss.nameString}' (#{mth})")
         | 
| 255 | 
            -
                        cloned = c.clone(model).to_LayeredConstruction.get
         | 
| 256 | 
            -
                        cloned.setName("'#{i}' cloned")
         | 
| 257 | 
            -
                        sss.setConstruction(cloned)
         | 
| 258 | 
            -
                        ok = s.key?(sss.nameString)
         | 
| 259 | 
            -
                        s[sss.nameString][:construction] = cloned                      if ok
         | 
| 260 | 
            -
                        coll[i][:s].delete(sss.nameString)
         | 
| 261 | 
            -
                        coll[i][:area] = c.getNetArea
         | 
| 262 | 
            -
                        next
         | 
| 263 | 
            -
                      end
         | 
| 264 | 
            -
                    end
         | 
| 265 | 
            -
             | 
| 263 | 
            +
                  elsif lc
         | 
| 264 | 
            +
                    # Valid layered construction - good to uprate!
         | 
| 266 265 | 
             
                    lyr         = insulatingLayer(lc)
         | 
| 267 266 | 
             
                    lyr[:index] = nil unless lyr[:index].is_a?(Numeric)
         | 
| 268 267 | 
             
                    lyr[:index] = nil unless lyr[:index] >= 0
         | 
| @@ -270,64 +269,81 @@ module TBD | |
| 270 269 |  | 
| 271 270 | 
             
                    log(ERR, "Insulation index for '#{id}'? (#{mth})")    unless lyr[:index]
         | 
| 272 271 | 
             
                    next                                                  unless lyr[:index]
         | 
| 273 | 
            -
                    hloss = 0                    # sum of applicable psi & khi effects [W/K]
         | 
| 274 272 |  | 
| 275 | 
            -
                     | 
| 276 | 
            -
             | 
| 277 | 
            -
             | 
| 273 | 
            +
                    # Ensure lc is exclusively linked to deratable surfaces of right type.
         | 
| 274 | 
            +
                    # If not, assign new lc clone to non-targeted surfaces.
         | 
| 275 | 
            +
                    s.each do |nom, surface|
         | 
| 276 | 
            +
                      next unless surface.key?(:type        )
         | 
| 277 | 
            +
                      next unless surface.key?(:deratable   )
         | 
| 278 | 
            +
                      next unless surface.key?(:construction)
         | 
| 279 | 
            +
                      next unless surface[:construction].is_a?(cl3)
         | 
| 280 | 
            +
                      next unless surface[:construction] == lc
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                      ok = true
         | 
| 283 | 
            +
                      ok = false unless surface[:type     ] == typ
         | 
| 284 | 
            +
                      ok = false unless surface[:deratable]
         | 
| 285 | 
            +
                      ok = false unless coll.key?(id)
         | 
| 286 | 
            +
                      ok = false unless coll[id][:s].key?(nom)
         | 
| 287 | 
            +
             | 
| 288 | 
            +
                      unless ok
         | 
| 289 | 
            +
                        log(WRN, "Cloning '#{nom}' construction - not '#{id}' (#{mth})")
         | 
| 290 | 
            +
                        sss    = model.getSurfaceByName(nom)
         | 
| 291 | 
            +
                        next if sss.empty?
         | 
| 292 | 
            +
             | 
| 293 | 
            +
                        sss    = sss.get
         | 
| 294 | 
            +
                        cloned = lc.clone(model).to_LayeredConstruction.get
         | 
| 295 | 
            +
                        cloned.setName("#{nom} - cloned")
         | 
| 296 | 
            +
                        sss.setConstruction(cloned)
         | 
| 297 | 
            +
                        surface[:construction] = cloned
         | 
| 298 | 
            +
                        coll[id][:s].delete(nom)
         | 
| 299 | 
            +
                      end
         | 
| 300 | 
            +
                    end
         | 
| 301 | 
            +
             | 
| 302 | 
            +
                    hloss           = 0          # sum of applicable psi & khi effects [W/K]
         | 
| 278 303 |  | 
| 304 | 
            +
                    # Tally applicable psi + khi losses. Possible construction reassignment.
         | 
| 305 | 
            +
                    coll.each do |i, col|
         | 
| 279 306 | 
             
                      col[:s].keys.each do |nom|
         | 
| 280 307 | 
             
                        next unless s.key?(nom)
         | 
| 281 | 
            -
                        next unless s[nom].key?(:deratable   )
         | 
| 282 308 | 
             
                        next unless s[nom].key?(:construction)
         | 
| 283 309 | 
             
                        next unless s[nom].key?(:index       )
         | 
| 284 310 | 
             
                        next unless s[nom].key?(:ltype       )
         | 
| 285 311 | 
             
                        next unless s[nom].key?(:r           )
         | 
| 286 | 
            -
                        next unless s[nom].key?(:type        )
         | 
| 287 | 
            -
             | 
| 288 | 
            -
                        next unless s[nom][:deratable]
         | 
| 289 | 
            -
                        type = s[nom][:type].to_s.downcase
         | 
| 290 | 
            -
                        type = "roof" if type == "ceiling"
         | 
| 291 | 
            -
                        next unless type.include?(label.to_s)
         | 
| 292 312 |  | 
| 293 313 | 
             
                        # Tally applicable psi + khi.
         | 
| 294 | 
            -
                        hloss += s[nom][:heatloss] if s[nom].key?(:heatloss)
         | 
| 295 | 
            -
             | 
| 296 | 
            -
             | 
| 297 | 
            -
                         | 
| 298 | 
            -
             | 
| 299 | 
            -
             | 
| 300 | 
            -
                          sss = sss.get
         | 
| 301 | 
            -
             | 
| 302 | 
            -
                          if sss.isConstructionDefaulted
         | 
| 303 | 
            -
                            set = defaultConstructionSet(model, sss)
         | 
| 304 | 
            -
                            constructions = set.defaultExteriorSurfaceConstructions.get
         | 
| 305 | 
            -
             | 
| 306 | 
            -
                            case sss.surfaceType.downcase
         | 
| 307 | 
            -
                            when "roofceiling"
         | 
| 308 | 
            -
                              constructions.setRoofCeilingConstruction(lc)
         | 
| 309 | 
            -
                            when "floor"
         | 
| 310 | 
            -
                              constructions.setFloorConstruction(lc)
         | 
| 311 | 
            -
                            else
         | 
| 312 | 
            -
                              constructions.setWallConstruction(lc)
         | 
| 313 | 
            -
                            end
         | 
| 314 | 
            -
                          else
         | 
| 315 | 
            -
                            sss.setConstruction(lc)
         | 
| 316 | 
            -
                          end
         | 
| 314 | 
            +
                        hloss += s[nom][:heatloss    ] if s[nom].key?(:heatloss)
         | 
| 315 | 
            +
                        next  if s[nom][:construction] == lc
         | 
| 316 | 
            +
             | 
| 317 | 
            +
                        # Reassign construction unless referencing lc.
         | 
| 318 | 
            +
                        sss = model.getSurfaceByName(nom)
         | 
| 319 | 
            +
                        next if sss.empty?
         | 
| 317 320 |  | 
| 318 | 
            -
             | 
| 319 | 
            -
             | 
| 320 | 
            -
             | 
| 321 | 
            -
                           | 
| 321 | 
            +
                        sss = sss.get
         | 
| 322 | 
            +
             | 
| 323 | 
            +
                        if sss.isConstructionDefaulted
         | 
| 324 | 
            +
                          set = defaultConstructionSet(model, sss) # building? story?
         | 
| 325 | 
            +
                          constructions = set.defaultExteriorSurfaceConstructions
         | 
| 326 | 
            +
             | 
| 327 | 
            +
                          unless constructions.empty?
         | 
| 328 | 
            +
                            constructions = constructions.get
         | 
| 329 | 
            +
                            constructions.setWallConstruction(lc)        if typ == :wall
         | 
| 330 | 
            +
                            constructions.setFloorConstruction(lc)       if typ == :floor
         | 
| 331 | 
            +
                            constructions.setRoofCeilingConstruction(lc) if typ == :ceiling
         | 
| 332 | 
            +
                          end
         | 
| 333 | 
            +
                        else
         | 
| 334 | 
            +
                          sss.setConstruction(lc)
         | 
| 322 335 | 
             
                        end
         | 
| 336 | 
            +
             | 
| 337 | 
            +
                        s[nom][:construction] = lc                 # reset TBD attributes
         | 
| 338 | 
            +
                        s[nom][:index       ] = lyr[:index]
         | 
| 339 | 
            +
                        s[nom][:ltype       ] = lyr[:type ]
         | 
| 340 | 
            +
                        s[nom][:r           ] = lyr[:r    ]        # temporary
         | 
| 323 341 | 
             
                      end
         | 
| 324 342 | 
             
                    end
         | 
| 325 343 |  | 
| 326 344 | 
             
                    # Merge to ensure a single entry for coll Hash.
         | 
| 327 345 | 
             
                    coll.each do |i, col|
         | 
| 328 346 | 
             
                      next if i == id
         | 
| 329 | 
            -
                      next unless coll.key?(id)
         | 
| 330 | 
            -
                      coll[id][:area] += col[:area]
         | 
| 331 347 |  | 
| 332 348 | 
             
                      col[:s].each do |nom, sss|
         | 
| 333 349 | 
             
                        coll[id][:s][nom] = sss unless coll[id][:s].key?(nom)
         | 
| @@ -338,6 +354,8 @@ module TBD | |
| 338 354 | 
             
                    log(DBG, "Collection == 1? for '#{id}' (#{mth})")  unless coll.size == 1
         | 
| 339 355 | 
             
                    next                                               unless coll.size == 1
         | 
| 340 356 |  | 
| 357 | 
            +
                    area = lc.getNetArea
         | 
| 358 | 
            +
                    coll[id][:area] = area
         | 
| 341 359 | 
             
                    res = uo(model, lc, id, hloss, film, g[:ut])
         | 
| 342 360 | 
             
                    log(ERR, "Unable to uprate '#{id}' (#{mth})") unless res[:uo] && res[:m]
         | 
| 343 361 | 
             
                    next                                          unless res[:uo] && res[:m]
         | 
| @@ -347,27 +365,18 @@ module TBD | |
| 347 365 | 
             
                    # Loop through coll :s, and reset :r - likely modified by uo().
         | 
| 348 366 | 
             
                    coll.values.first[:s].keys.each do |nom|
         | 
| 349 367 | 
             
                      next unless s.key?(nom)
         | 
| 350 | 
            -
                      next unless s[nom].key?(: | 
| 351 | 
            -
                      next unless s[nom].key?(: | 
| 352 | 
            -
                      next unless s[nom].key?(: | 
| 353 | 
            -
                      next unless s[nom] | 
| 354 | 
            -
                      next unless s[nom] | 
| 355 | 
            -
             | 
| 356 | 
            -
                       | 
| 357 | 
            -
                      next unless s[nom][:construction] == lc
         | 
| 358 | 
            -
                      next unless s[nom][:index       ] == lyr[:index]
         | 
| 359 | 
            -
                      next unless s[nom][:ltype       ] == lyr[:type]
         | 
| 360 | 
            -
             | 
| 361 | 
            -
                      type = s[nom][:type].to_s.downcase
         | 
| 362 | 
            -
                      type = "roof" if type == "ceiling"
         | 
| 363 | 
            -
                      next unless type.include?(label.to_s)
         | 
| 364 | 
            -
                      next unless s[nom].key?(:r)
         | 
| 365 | 
            -
                      s[nom][:r] = lyr[:r]                                           # final
         | 
| 368 | 
            +
                      next unless s[nom].key?(:index)
         | 
| 369 | 
            +
                      next unless s[nom].key?(:ltype)
         | 
| 370 | 
            +
                      next unless s[nom].key?(:r    )
         | 
| 371 | 
            +
                      next unless s[nom][:index] == lyr[:index]
         | 
| 372 | 
            +
                      next unless s[nom][:ltype] == lyr[:type ]
         | 
| 373 | 
            +
             | 
| 374 | 
            +
                      s[nom][:r] = lyr[:r]  # uprated insulating RSi factor, before derating
         | 
| 366 375 | 
             
                    end
         | 
| 367 376 |  | 
| 368 | 
            -
                    argh[:wall_uo ] = res[:uo] if  | 
| 369 | 
            -
                    argh[:roof_uo ] = res[:uo] if  | 
| 370 | 
            -
                    argh[:floor_uo] = res[:uo] if  | 
| 377 | 
            +
                    argh[:wall_uo ] = res[:uo] if typ == :wall
         | 
| 378 | 
            +
                    argh[:roof_uo ] = res[:uo] if typ == :ceiling
         | 
| 379 | 
            +
                    argh[:floor_uo] = res[:uo] if typ == :floor
         | 
| 371 380 | 
             
                  else
         | 
| 372 381 | 
             
                    log(ERR, "Nilled construction to uprate - (#{mth})")
         | 
| 373 382 | 
             
                    return false
         | 
| @@ -920,7 +929,7 @@ module TBD | |
| 920 929 | 
             
                  model  = "* modèle : #{ua[:file]}"       if ua.key?(:file)  && lang == :fr
         | 
| 921 930 | 
             
                  model += " (v#{ua[:version]})"           if ua.key?(:version)
         | 
| 922 931 | 
             
                  report << model                      unless model.empty?
         | 
| 923 | 
            -
                  report << "* TBD : v3.2. | 
| 932 | 
            +
                  report << "* TBD : v3.2.2"
         | 
| 924 933 | 
             
                  report << "* date : #{ua[:date]}"
         | 
| 925 934 |  | 
| 926 935 | 
             
                  if lang == :en
         | 
    
        data/lib/tbd/geo.rb
    CHANGED
    
    | @@ -292,28 +292,31 @@ module TBD | |
| 292 292 |  | 
| 293 293 | 
             
                return mismatch("model", model, cl1, mth)          unless model.is_a?(cl1)
         | 
| 294 294 | 
             
                return mismatch("surface", surface, cl2, mth)      unless surface.is_a?(cl2)
         | 
| 295 | 
            -
             | 
| 296 | 
            -
                return nil unless validate(surface)
         | 
| 295 | 
            +
                return nil                                         unless validate(surface)
         | 
| 297 296 |  | 
| 298 297 | 
             
                nom    = surface.nameString
         | 
| 299 298 | 
             
                surf   = {}
         | 
| 300 299 | 
             
                subs   = {}
         | 
| 301 300 | 
             
                fd     = false
         | 
| 302 301 | 
             
                return   empty("'#{nom}' space", mth, ERR)           if surface.space.empty?
         | 
| 302 | 
            +
             | 
| 303 303 | 
             
                space  = surface.space.get
         | 
| 304 304 | 
             
                stype  = space.spaceType
         | 
| 305 305 | 
             
                story  = space.buildingStory
         | 
| 306 306 | 
             
                tr     = transforms(model, space)
         | 
| 307 307 | 
             
                return   invalid("'#{nom}' transform", mth, 0, FTL)  unless tr[:t] && tr[:r]
         | 
| 308 | 
            +
             | 
| 308 309 | 
             
                t      = tr[:t]
         | 
| 309 310 | 
             
                n      = trueNormal(surface, tr[:r])
         | 
| 310 311 | 
             
                return   invalid("'#{nom}' normal", mth, 0, FTL)     unless n
         | 
| 312 | 
            +
             | 
| 311 313 | 
             
                type   = surface.surfaceType.downcase
         | 
| 312 314 | 
             
                facing = surface.outsideBoundaryCondition
         | 
| 313 315 |  | 
| 314 316 | 
             
                if facing.downcase == "surface"
         | 
| 315 317 | 
             
                  empty = surface.adjacentSurface.empty?
         | 
| 316 | 
            -
                  return invalid("'#{nom}': adjacent surface", mth, 0, ERR) | 
| 318 | 
            +
                  return invalid("'#{nom}': adjacent surface", mth, 0, ERR) if empty
         | 
| 319 | 
            +
             | 
| 317 320 | 
             
                  facing = surface.adjacentSurface.get.nameString
         | 
| 318 321 | 
             
                end
         | 
| 319 322 |  | 
| @@ -350,6 +353,7 @@ module TBD | |
| 350 353 | 
             
                surf[:story      ] = story.get               unless story.empty?
         | 
| 351 354 | 
             
                surf[:n          ] = n
         | 
| 352 355 | 
             
                surf[:gross      ] = surface.grossArea
         | 
| 356 | 
            +
                surf[:filmRSI    ] = surface.filmResistance
         | 
| 353 357 |  | 
| 354 358 | 
             
                surface.subSurfaces.sort_by { |s| s.nameString }.each do |s|
         | 
| 355 359 | 
             
                  next unless validate(s)
         | 
    
        data/lib/tbd/psi.rb
    CHANGED
    
    | @@ -975,8 +975,9 @@ module TBD | |
| 975 975 | 
             
                    end
         | 
| 976 976 | 
             
                  end
         | 
| 977 977 |  | 
| 978 | 
            -
                   | 
| 979 | 
            -
                  surface[: | 
| 978 | 
            +
                  # Recover if valid setpoints.
         | 
| 979 | 
            +
                  surface[:heating] = heat[:spt] if heat && heat[:spt]
         | 
| 980 | 
            +
                  surface[:cooling] = cool[:spt] if cool && cool[:spt]
         | 
| 980 981 |  | 
| 981 982 | 
             
                  tbd[:surfaces][s.nameString] = surface
         | 
| 982 983 | 
             
                end                                            # (opaque) surfaces populated
         | 
| @@ -1486,7 +1487,7 @@ module TBD | |
| 1486 1487 |  | 
| 1487 1488 | 
             
                    edge[:surfaces].keys.each do |i|
         | 
| 1488 1489 | 
             
                      break     if is[:rimjoist] || is[:balcony]
         | 
| 1489 | 
            -
                      break unless deratables.size  | 
| 1490 | 
            +
                      break unless deratables.size > 0
         | 
| 1490 1491 | 
             
                      break     if floors.key?(id)
         | 
| 1491 1492 | 
             
                      next      if i == id
         | 
| 1492 1493 | 
             
                      next  unless floors.key?(i)
         | 
    
        data/lib/tbd/ua.rb
    CHANGED
    
    | @@ -39,13 +39,14 @@ module TBD | |
| 39 39 | 
             
                cl1 = OpenStudio::Model::Model
         | 
| 40 40 | 
             
                cl2 = OpenStudio::Model::LayeredConstruction
         | 
| 41 41 | 
             
                cl3 = Numeric
         | 
| 42 | 
            +
                cl4 = String
         | 
| 42 43 |  | 
| 43 | 
            -
                return mismatch("model", model, cl1, mth, DBG, res) | 
| 44 | 
            -
                return mismatch("id", | 
| 45 | 
            -
                return mismatch("lc", | 
| 46 | 
            -
                return mismatch("hloss", hloss, cl3, mth, DBG, res) | 
| 47 | 
            -
                return mismatch("film", | 
| 48 | 
            -
                return mismatch("Ut", | 
| 44 | 
            +
                return mismatch("model", model, cl1, mth, DBG, res) unless model.is_a?(cl1)
         | 
| 45 | 
            +
                return mismatch("id"   ,    id, cl4, mth, DBG, res) unless id.is_a?(cl4)
         | 
| 46 | 
            +
                return mismatch("lc"   ,    lc, cl2, mth, DBG, res) unless lc.is_a?(cl2)
         | 
| 47 | 
            +
                return mismatch("hloss", hloss, cl3, mth, DBG, res) unless hloss.is_a?(cl3)
         | 
| 48 | 
            +
                return mismatch("film" ,  film, cl3, mth, DBG, res) unless film.is_a?(cl3)
         | 
| 49 | 
            +
                return mismatch("Ut"   ,    ut, cl3, mth, DBG, res) unless ut.is_a?(cl3)
         | 
| 49 50 |  | 
| 50 51 | 
             
                loss        = 0.0                   # residual heatloss (not assigned) [W/K]
         | 
| 51 52 | 
             
                area        = lc.getNetArea
         | 
| @@ -54,12 +55,12 @@ module TBD | |
| 54 55 | 
             
                lyr[:index] = nil unless lyr[:index] >= 0
         | 
| 55 56 | 
             
                lyr[:index] = nil unless lyr[:index] < lc.layers.size
         | 
| 56 57 |  | 
| 57 | 
            -
                return invalid("'#{id}' layer index", mth, 0, ERR, res) | 
| 58 | 
            -
                return zero("'#{id}': heatloss", mth, | 
| 59 | 
            -
                return zero("'#{id}': films", mth, | 
| 60 | 
            -
                return zero("'#{id}': Ut", mth, | 
| 61 | 
            -
                return invalid("'#{id}': Ut", mth, 0, WRN, res) | 
| 62 | 
            -
                return zero("'#{id}': net area (m2)", mth, | 
| 58 | 
            +
                return invalid("'#{id}' layer index", mth, 0, ERR, res) unless lyr[:index]
         | 
| 59 | 
            +
                return zero("'#{id}': heatloss"     , mth,    WRN, res) unless hloss > TOL
         | 
| 60 | 
            +
                return zero("'#{id}': films"        , mth,    WRN, res) unless film  > TOL
         | 
| 61 | 
            +
                return zero("'#{id}': Ut"           , mth,    WRN, res) unless ut    > TOL
         | 
| 62 | 
            +
                return invalid("'#{id}': Ut"        , mth, 0, WRN, res) unless ut    < 5.678
         | 
| 63 | 
            +
                return zero("'#{id}': net area (m2)", mth,    ERR, res) unless area  > TOL
         | 
| 63 64 |  | 
| 64 65 | 
             
                # First, calculate initial layer RSi to initially meet Ut target.
         | 
| 65 66 | 
             
                rt     = 1 / ut                      #                target construction Rt
         | 
| @@ -76,7 +77,7 @@ module TBD | |
| 76 77 |  | 
| 77 78 | 
             
                if lyr[:type] == :massless
         | 
| 78 79 | 
             
                  m     = lc.getLayer(lyr[:index]).to_MasslessOpaqueMaterial
         | 
| 79 | 
            -
                  return  invalid("'#{id}' massless layer?", mth, 0) | 
| 80 | 
            +
                  return  invalid("'#{id}' massless layer?", mth, 0, DBG, res)   if m.empty?
         | 
| 80 81 |  | 
| 81 82 | 
             
                  m     = m.get.clone(model).to_MasslessOpaqueMaterial.get
         | 
| 82 83 | 
             
                          m.setName("#{id} uprated")
         | 
| @@ -85,7 +86,7 @@ module TBD | |
| 85 86 | 
             
                          m.setThermalResistance(new_r)
         | 
| 86 87 | 
             
                else # type == :standard
         | 
| 87 88 | 
             
                  m     = lc.getLayer(lyr[:index]).to_StandardOpaqueMaterial
         | 
| 88 | 
            -
                  return  invalid("'#{id}' standard layer?", mth, 0) | 
| 89 | 
            +
                  return  invalid("'#{id}' standard layer?", mth, 0, DBG, res)   if m.empty?
         | 
| 89 90 |  | 
| 90 91 | 
             
                  m     = m.get.clone(model).to_StandardOpaqueMaterial.get
         | 
| 91 92 | 
             
                          m.setName("#{id} uprated")
         | 
| @@ -141,11 +142,12 @@ module TBD | |
| 141 142 | 
             
                mth = "TBD::#{__callee__}"
         | 
| 142 143 | 
             
                cl1 = OpenStudio::Model::Model
         | 
| 143 144 | 
             
                cl2 = Hash
         | 
| 145 | 
            +
                cl3 = OpenStudio::Model::LayeredConstruction
         | 
| 144 146 | 
             
                a   = false
         | 
| 145 147 |  | 
| 146 | 
            -
                return mismatch("model", model, cl1, mth, DBG, a) | 
| 147 | 
            -
                return mismatch("surfaces", | 
| 148 | 
            -
                return mismatch("argh", model, cl1, mth, DBG, a) | 
| 148 | 
            +
                return mismatch("model"   , model, cl1, mth, DBG, a) unless model.is_a?(cl1)
         | 
| 149 | 
            +
                return mismatch("surfaces",     s, cl2, mth, DBG, a) unless s.is_a?(cl2)
         | 
| 150 | 
            +
                return mismatch("argh"    , model, cl1, mth, DBG, a) unless argh.is_a?(cl2)
         | 
| 149 151 |  | 
| 150 152 | 
             
                argh[:uprate_walls ] = false unless argh.key?(:uprate_walls )
         | 
| 151 153 | 
             
                argh[:uprate_roofs ] = false unless argh.key?(:uprate_roofs )
         | 
| @@ -168,11 +170,13 @@ module TBD | |
| 168 170 | 
             
                groups[:roof ][:op] = argh[:roof_option  ]
         | 
| 169 171 | 
             
                groups[:floor][:op] = argh[:floor_option ]
         | 
| 170 172 |  | 
| 171 | 
            -
                groups.each do | | 
| 173 | 
            +
                groups.each do |type, g|
         | 
| 172 174 | 
             
                  next unless g[:up]
         | 
| 173 175 | 
             
                  next unless g[:ut].is_a?(Numeric)
         | 
| 174 176 | 
             
                  next unless g[:ut] < 5.678
         | 
| 175 177 |  | 
| 178 | 
            +
                  typ  = type
         | 
| 179 | 
            +
                  typ  = :ceiling if typ == :roof # fix in future revision. TO-DO.
         | 
| 176 180 | 
             
                  coll = {}
         | 
| 177 181 | 
             
                  area = 0
         | 
| 178 182 | 
             
                  film = 100000000000000
         | 
| @@ -183,86 +187,81 @@ module TBD | |
| 183 187 | 
             
                         g[:op].downcase == "all floor constructions"
         | 
| 184 188 |  | 
| 185 189 | 
             
                  if g[:op].empty?
         | 
| 186 | 
            -
                    log(ERR, "Construction to uprate? (#{mth})")
         | 
| 190 | 
            +
                    log(ERR, "Construction (#{type}) to uprate? (#{mth})")
         | 
| 187 191 | 
             
                  elsif all
         | 
| 188 | 
            -
                     | 
| 189 | 
            -
                      next unless  | 
| 190 | 
            -
                      next unless  | 
| 191 | 
            -
                      next | 
| 192 | 
            -
                      next | 
| 193 | 
            -
             | 
| 194 | 
            -
                       | 
| 195 | 
            -
                       | 
| 196 | 
            -
             | 
| 197 | 
            -
                       | 
| 198 | 
            -
                       | 
| 199 | 
            -
             | 
| 192 | 
            +
                    s.each do |nom, surface|
         | 
| 193 | 
            +
                      next unless surface.key?(:deratable   )
         | 
| 194 | 
            +
                      next unless surface.key?(:type        )
         | 
| 195 | 
            +
                      next unless surface.key?(:construction)
         | 
| 196 | 
            +
                      next unless surface.key?(:filmRSI     )
         | 
| 197 | 
            +
                      next unless surface.key?(:index       )
         | 
| 198 | 
            +
                      next unless surface.key?(:ltype       )
         | 
| 199 | 
            +
                      next unless surface.key?(:r           )
         | 
| 200 | 
            +
                      next unless surface[:deratable   ]
         | 
| 201 | 
            +
                      next unless surface[:type        ] == typ
         | 
| 202 | 
            +
                      next unless surface[:construction].is_a?(cl3)
         | 
| 203 | 
            +
                      next     if surface[:index       ].nil?
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                      # Retain lowest surface film resistance (e.g. tilted surfaces).
         | 
| 206 | 
            +
                      c    = surface[:construction]
         | 
| 207 | 
            +
                      i    = c.nameString
         | 
| 208 | 
            +
                      aire = c.getNetArea
         | 
| 209 | 
            +
                      film = surface[:filmRSI] if surface[:filmRSI] < film
         | 
| 210 | 
            +
             | 
| 211 | 
            +
                      # Retain construction covering largest area. The following conditional
         | 
| 212 | 
            +
                      # is reliable UNLESS linked to other deratable surface types e.g. both
         | 
| 213 | 
            +
                      # floors AND walls (see "elsif lc" corrections below).
         | 
| 214 | 
            +
                      if aire > area
         | 
| 200 215 | 
             
                        lc   = c
         | 
| 216 | 
            +
                        area = aire
         | 
| 201 217 | 
             
                        id   = i
         | 
| 202 218 | 
             
                      end
         | 
| 203 219 |  | 
| 204 | 
            -
                       | 
| 205 | 
            -
                      nom | 
| 206 | 
            -
                      coll[i] = { area: c.getNetArea, lc: c, s: {} } unless coll.key?(i)
         | 
| 207 | 
            -
                      coll[i][:s][nom] = { a: sss.netArea } unless coll[i][:s].key?(nom)
         | 
| 220 | 
            +
                      coll[i]          = { area: aire, lc: c, s: {} } unless coll.key?(i)
         | 
| 221 | 
            +
                      coll[i][:s][nom] = { a: surface[:net] }  unless coll[i][:s].key?(nom)
         | 
| 208 222 | 
             
                    end
         | 
| 209 223 | 
             
                  else
         | 
| 210 224 | 
             
                    id = g[:op]
         | 
| 211 | 
            -
                     | 
| 212 | 
            -
             | 
| 213 | 
            -
                    if  | 
| 214 | 
            -
             | 
| 215 | 
            -
                     | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 218 | 
            -
             | 
| 219 | 
            -
             | 
| 220 | 
            -
             | 
| 221 | 
            -
             | 
| 222 | 
            -
             | 
| 223 | 
            -
             | 
| 224 | 
            -
             | 
| 225 | 
            -
             | 
| 226 | 
            -
             | 
| 227 | 
            -
             | 
| 228 | 
            -
             | 
| 229 | 
            -
             | 
| 230 | 
            -
             | 
| 231 | 
            -
             | 
| 232 | 
            -
             | 
| 233 | 
            -
             | 
| 234 | 
            -
             | 
| 235 | 
            -
             | 
| 236 | 
            -
             | 
| 237 | 
            -
                       | 
| 225 | 
            +
                    lc = model.getConstructionByName(id)
         | 
| 226 | 
            +
                    log(ERR, "Construction '#{id}'? (#{mth})")         if lc.empty?
         | 
| 227 | 
            +
                    next                                               if lc.empty?
         | 
| 228 | 
            +
             | 
| 229 | 
            +
                    lc = lc.get.to_LayeredConstruction
         | 
| 230 | 
            +
                    log(ERR, "'#{id}' layered construction? (#{mth})") if lc.empty?
         | 
| 231 | 
            +
                    next                                               if lc.empty?
         | 
| 232 | 
            +
             | 
| 233 | 
            +
                    lc       = lc.get
         | 
| 234 | 
            +
                    area     = lc.getNetArea
         | 
| 235 | 
            +
                    coll[id] = { area: area, lc: lc, s: {} }
         | 
| 236 | 
            +
             | 
| 237 | 
            +
                    s.each do |nom, surface|
         | 
| 238 | 
            +
                      next unless surface.key?(:deratable   )
         | 
| 239 | 
            +
                      next unless surface.key?(:type        )
         | 
| 240 | 
            +
                      next unless surface.key?(:construction)
         | 
| 241 | 
            +
                      next unless surface.key?(:filmRSI     )
         | 
| 242 | 
            +
                      next unless surface.key?(:index       )
         | 
| 243 | 
            +
                      next unless surface.key?(:ltype       )
         | 
| 244 | 
            +
                      next unless surface.key?(:r           )
         | 
| 245 | 
            +
                      next unless surface[:deratable   ]
         | 
| 246 | 
            +
                      next unless surface[:type        ] == typ
         | 
| 247 | 
            +
                      next unless surface[:construction].is_a?(cl3)
         | 
| 248 | 
            +
                      next     if surface[:index       ].nil?
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                      i = surface[:construction].nameString
         | 
| 251 | 
            +
                      next unless i == id
         | 
| 252 | 
            +
             | 
| 253 | 
            +
                      # Retain lowest surface film resistance (e.g. tilted surfaces).
         | 
| 254 | 
            +
                      film = surface[:filmRSI] if surface[:filmRSI] < film
         | 
| 255 | 
            +
             | 
| 256 | 
            +
                      coll[i][:s][nom] = { a: surface[:net] } unless coll[i][:s].key?(nom)
         | 
| 238 257 | 
             
                    end
         | 
| 239 258 | 
             
                  end
         | 
| 240 259 |  | 
| 241 260 | 
             
                  if coll.empty?
         | 
| 242 | 
            -
                    log(ERR, "No #{ | 
| 261 | 
            +
                    log(ERR, "No #{type} construction to uprate - skipping (#{mth})")
         | 
| 243 262 | 
             
                    next
         | 
| 244 | 
            -
                  elsif lc | 
| 245 | 
            -
                    #  | 
| 246 | 
            -
                    model.getSurfaces.each do |sss|
         | 
| 247 | 
            -
                      next if sss.construction.empty?
         | 
| 248 | 
            -
                      next if sss.construction.get.to_LayeredConstruction.empty?
         | 
| 249 | 
            -
                      c = sss.construction.get.to_LayeredConstruction.get
         | 
| 250 | 
            -
                      i = c.nameString
         | 
| 251 | 
            -
                      next unless coll.key?(i)
         | 
| 252 | 
            -
             | 
| 253 | 
            -
                      unless sss.surfaceType.downcase.include?(label.to_s)
         | 
| 254 | 
            -
                        log(ERR, "Uprating #{label.to_s}, not '#{sss.nameString}' (#{mth})")
         | 
| 255 | 
            -
                        cloned = c.clone(model).to_LayeredConstruction.get
         | 
| 256 | 
            -
                        cloned.setName("'#{i}' cloned")
         | 
| 257 | 
            -
                        sss.setConstruction(cloned)
         | 
| 258 | 
            -
                        ok = s.key?(sss.nameString)
         | 
| 259 | 
            -
                        s[sss.nameString][:construction] = cloned                      if ok
         | 
| 260 | 
            -
                        coll[i][:s].delete(sss.nameString)
         | 
| 261 | 
            -
                        coll[i][:area] = c.getNetArea
         | 
| 262 | 
            -
                        next
         | 
| 263 | 
            -
                      end
         | 
| 264 | 
            -
                    end
         | 
| 265 | 
            -
             | 
| 263 | 
            +
                  elsif lc
         | 
| 264 | 
            +
                    # Valid layered construction - good to uprate!
         | 
| 266 265 | 
             
                    lyr         = insulatingLayer(lc)
         | 
| 267 266 | 
             
                    lyr[:index] = nil unless lyr[:index].is_a?(Numeric)
         | 
| 268 267 | 
             
                    lyr[:index] = nil unless lyr[:index] >= 0
         | 
| @@ -270,64 +269,81 @@ module TBD | |
| 270 269 |  | 
| 271 270 | 
             
                    log(ERR, "Insulation index for '#{id}'? (#{mth})")    unless lyr[:index]
         | 
| 272 271 | 
             
                    next                                                  unless lyr[:index]
         | 
| 273 | 
            -
                    hloss = 0                    # sum of applicable psi & khi effects [W/K]
         | 
| 274 272 |  | 
| 275 | 
            -
                     | 
| 276 | 
            -
             | 
| 277 | 
            -
             | 
| 273 | 
            +
                    # Ensure lc is exclusively linked to deratable surfaces of right type.
         | 
| 274 | 
            +
                    # If not, assign new lc clone to non-targeted surfaces.
         | 
| 275 | 
            +
                    s.each do |nom, surface|
         | 
| 276 | 
            +
                      next unless surface.key?(:type        )
         | 
| 277 | 
            +
                      next unless surface.key?(:deratable   )
         | 
| 278 | 
            +
                      next unless surface.key?(:construction)
         | 
| 279 | 
            +
                      next unless surface[:construction].is_a?(cl3)
         | 
| 280 | 
            +
                      next unless surface[:construction] == lc
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                      ok = true
         | 
| 283 | 
            +
                      ok = false unless surface[:type     ] == typ
         | 
| 284 | 
            +
                      ok = false unless surface[:deratable]
         | 
| 285 | 
            +
                      ok = false unless coll.key?(id)
         | 
| 286 | 
            +
                      ok = false unless coll[id][:s].key?(nom)
         | 
| 287 | 
            +
             | 
| 288 | 
            +
                      unless ok
         | 
| 289 | 
            +
                        log(WRN, "Cloning '#{nom}' construction - not '#{id}' (#{mth})")
         | 
| 290 | 
            +
                        sss    = model.getSurfaceByName(nom)
         | 
| 291 | 
            +
                        next if sss.empty?
         | 
| 292 | 
            +
             | 
| 293 | 
            +
                        sss    = sss.get
         | 
| 294 | 
            +
                        cloned = lc.clone(model).to_LayeredConstruction.get
         | 
| 295 | 
            +
                        cloned.setName("#{nom} - cloned")
         | 
| 296 | 
            +
                        sss.setConstruction(cloned)
         | 
| 297 | 
            +
                        surface[:construction] = cloned
         | 
| 298 | 
            +
                        coll[id][:s].delete(nom)
         | 
| 299 | 
            +
                      end
         | 
| 300 | 
            +
                    end
         | 
| 301 | 
            +
             | 
| 302 | 
            +
                    hloss           = 0          # sum of applicable psi & khi effects [W/K]
         | 
| 278 303 |  | 
| 304 | 
            +
                    # Tally applicable psi + khi losses. Possible construction reassignment.
         | 
| 305 | 
            +
                    coll.each do |i, col|
         | 
| 279 306 | 
             
                      col[:s].keys.each do |nom|
         | 
| 280 307 | 
             
                        next unless s.key?(nom)
         | 
| 281 | 
            -
                        next unless s[nom].key?(:deratable   )
         | 
| 282 308 | 
             
                        next unless s[nom].key?(:construction)
         | 
| 283 309 | 
             
                        next unless s[nom].key?(:index       )
         | 
| 284 310 | 
             
                        next unless s[nom].key?(:ltype       )
         | 
| 285 311 | 
             
                        next unless s[nom].key?(:r           )
         | 
| 286 | 
            -
                        next unless s[nom].key?(:type        )
         | 
| 287 | 
            -
             | 
| 288 | 
            -
                        next unless s[nom][:deratable]
         | 
| 289 | 
            -
                        type = s[nom][:type].to_s.downcase
         | 
| 290 | 
            -
                        type = "roof" if type == "ceiling"
         | 
| 291 | 
            -
                        next unless type.include?(label.to_s)
         | 
| 292 312 |  | 
| 293 313 | 
             
                        # Tally applicable psi + khi.
         | 
| 294 | 
            -
                        hloss += s[nom][:heatloss] if s[nom].key?(:heatloss)
         | 
| 295 | 
            -
             | 
| 296 | 
            -
             | 
| 297 | 
            -
                         | 
| 298 | 
            -
             | 
| 299 | 
            -
             | 
| 300 | 
            -
                          sss = sss.get
         | 
| 301 | 
            -
             | 
| 302 | 
            -
                          if sss.isConstructionDefaulted
         | 
| 303 | 
            -
                            set = defaultConstructionSet(model, sss)
         | 
| 304 | 
            -
                            constructions = set.defaultExteriorSurfaceConstructions.get
         | 
| 305 | 
            -
             | 
| 306 | 
            -
                            case sss.surfaceType.downcase
         | 
| 307 | 
            -
                            when "roofceiling"
         | 
| 308 | 
            -
                              constructions.setRoofCeilingConstruction(lc)
         | 
| 309 | 
            -
                            when "floor"
         | 
| 310 | 
            -
                              constructions.setFloorConstruction(lc)
         | 
| 311 | 
            -
                            else
         | 
| 312 | 
            -
                              constructions.setWallConstruction(lc)
         | 
| 313 | 
            -
                            end
         | 
| 314 | 
            -
                          else
         | 
| 315 | 
            -
                            sss.setConstruction(lc)
         | 
| 316 | 
            -
                          end
         | 
| 314 | 
            +
                        hloss += s[nom][:heatloss    ] if s[nom].key?(:heatloss)
         | 
| 315 | 
            +
                        next  if s[nom][:construction] == lc
         | 
| 316 | 
            +
             | 
| 317 | 
            +
                        # Reassign construction unless referencing lc.
         | 
| 318 | 
            +
                        sss = model.getSurfaceByName(nom)
         | 
| 319 | 
            +
                        next if sss.empty?
         | 
| 317 320 |  | 
| 318 | 
            -
             | 
| 319 | 
            -
             | 
| 320 | 
            -
             | 
| 321 | 
            -
                           | 
| 321 | 
            +
                        sss = sss.get
         | 
| 322 | 
            +
             | 
| 323 | 
            +
                        if sss.isConstructionDefaulted
         | 
| 324 | 
            +
                          set = defaultConstructionSet(model, sss) # building? story?
         | 
| 325 | 
            +
                          constructions = set.defaultExteriorSurfaceConstructions
         | 
| 326 | 
            +
             | 
| 327 | 
            +
                          unless constructions.empty?
         | 
| 328 | 
            +
                            constructions = constructions.get
         | 
| 329 | 
            +
                            constructions.setWallConstruction(lc)        if typ == :wall
         | 
| 330 | 
            +
                            constructions.setFloorConstruction(lc)       if typ == :floor
         | 
| 331 | 
            +
                            constructions.setRoofCeilingConstruction(lc) if typ == :ceiling
         | 
| 332 | 
            +
                          end
         | 
| 333 | 
            +
                        else
         | 
| 334 | 
            +
                          sss.setConstruction(lc)
         | 
| 322 335 | 
             
                        end
         | 
| 336 | 
            +
             | 
| 337 | 
            +
                        s[nom][:construction] = lc                 # reset TBD attributes
         | 
| 338 | 
            +
                        s[nom][:index       ] = lyr[:index]
         | 
| 339 | 
            +
                        s[nom][:ltype       ] = lyr[:type ]
         | 
| 340 | 
            +
                        s[nom][:r           ] = lyr[:r    ]        # temporary
         | 
| 323 341 | 
             
                      end
         | 
| 324 342 | 
             
                    end
         | 
| 325 343 |  | 
| 326 344 | 
             
                    # Merge to ensure a single entry for coll Hash.
         | 
| 327 345 | 
             
                    coll.each do |i, col|
         | 
| 328 346 | 
             
                      next if i == id
         | 
| 329 | 
            -
                      next unless coll.key?(id)
         | 
| 330 | 
            -
                      coll[id][:area] += col[:area]
         | 
| 331 347 |  | 
| 332 348 | 
             
                      col[:s].each do |nom, sss|
         | 
| 333 349 | 
             
                        coll[id][:s][nom] = sss unless coll[id][:s].key?(nom)
         | 
| @@ -338,6 +354,8 @@ module TBD | |
| 338 354 | 
             
                    log(DBG, "Collection == 1? for '#{id}' (#{mth})")  unless coll.size == 1
         | 
| 339 355 | 
             
                    next                                               unless coll.size == 1
         | 
| 340 356 |  | 
| 357 | 
            +
                    area = lc.getNetArea
         | 
| 358 | 
            +
                    coll[id][:area] = area
         | 
| 341 359 | 
             
                    res = uo(model, lc, id, hloss, film, g[:ut])
         | 
| 342 360 | 
             
                    log(ERR, "Unable to uprate '#{id}' (#{mth})") unless res[:uo] && res[:m]
         | 
| 343 361 | 
             
                    next                                          unless res[:uo] && res[:m]
         | 
| @@ -347,27 +365,18 @@ module TBD | |
| 347 365 | 
             
                    # Loop through coll :s, and reset :r - likely modified by uo().
         | 
| 348 366 | 
             
                    coll.values.first[:s].keys.each do |nom|
         | 
| 349 367 | 
             
                      next unless s.key?(nom)
         | 
| 350 | 
            -
                      next unless s[nom].key?(: | 
| 351 | 
            -
                      next unless s[nom].key?(: | 
| 352 | 
            -
                      next unless s[nom].key?(: | 
| 353 | 
            -
                      next unless s[nom] | 
| 354 | 
            -
                      next unless s[nom] | 
| 355 | 
            -
             | 
| 356 | 
            -
                       | 
| 357 | 
            -
                      next unless s[nom][:construction] == lc
         | 
| 358 | 
            -
                      next unless s[nom][:index       ] == lyr[:index]
         | 
| 359 | 
            -
                      next unless s[nom][:ltype       ] == lyr[:type]
         | 
| 360 | 
            -
             | 
| 361 | 
            -
                      type = s[nom][:type].to_s.downcase
         | 
| 362 | 
            -
                      type = "roof" if type == "ceiling"
         | 
| 363 | 
            -
                      next unless type.include?(label.to_s)
         | 
| 364 | 
            -
                      next unless s[nom].key?(:r)
         | 
| 365 | 
            -
                      s[nom][:r] = lyr[:r]                                           # final
         | 
| 368 | 
            +
                      next unless s[nom].key?(:index)
         | 
| 369 | 
            +
                      next unless s[nom].key?(:ltype)
         | 
| 370 | 
            +
                      next unless s[nom].key?(:r    )
         | 
| 371 | 
            +
                      next unless s[nom][:index] == lyr[:index]
         | 
| 372 | 
            +
                      next unless s[nom][:ltype] == lyr[:type ]
         | 
| 373 | 
            +
             | 
| 374 | 
            +
                      s[nom][:r] = lyr[:r]  # uprated insulating RSi factor, before derating
         | 
| 366 375 | 
             
                    end
         | 
| 367 376 |  | 
| 368 | 
            -
                    argh[:wall_uo ] = res[:uo] if  | 
| 369 | 
            -
                    argh[:roof_uo ] = res[:uo] if  | 
| 370 | 
            -
                    argh[:floor_uo] = res[:uo] if  | 
| 377 | 
            +
                    argh[:wall_uo ] = res[:uo] if typ == :wall
         | 
| 378 | 
            +
                    argh[:roof_uo ] = res[:uo] if typ == :ceiling
         | 
| 379 | 
            +
                    argh[:floor_uo] = res[:uo] if typ == :floor
         | 
| 371 380 | 
             
                  else
         | 
| 372 381 | 
             
                    log(ERR, "Nilled construction to uprate - (#{mth})")
         | 
| 373 382 | 
             
                    return false
         | 
| @@ -920,7 +929,7 @@ module TBD | |
| 920 929 | 
             
                  model  = "* modèle : #{ua[:file]}"       if ua.key?(:file)  && lang == :fr
         | 
| 921 930 | 
             
                  model += " (v#{ua[:version]})"           if ua.key?(:version)
         | 
| 922 931 | 
             
                  report << model                      unless model.empty?
         | 
| 923 | 
            -
                  report << "* TBD : v3.2. | 
| 932 | 
            +
                  report << "* TBD : v3.2.2"
         | 
| 924 933 | 
             
                  report << "* date : #{ua[:date]}"
         | 
| 925 934 |  | 
| 926 935 | 
             
                  if lang == :en
         | 
    
        data/lib/tbd/version.rb
    CHANGED
    
    
    
        data/lib/tbd.rb
    CHANGED
    
    | @@ -26,38 +26,38 @@ begin | |
| 26 26 | 
             
              # Try to load from the Topolys gem.
         | 
| 27 27 | 
             
              require "topolys"
         | 
| 28 28 |  | 
| 29 | 
            -
              puts "... relying on the Topolys gem"
         | 
| 29 | 
            +
              # puts "... relying on the Topolys gem"
         | 
| 30 30 | 
             
            rescue LoadError
         | 
| 31 31 | 
             
              require_relative "topolys/model"
         | 
| 32 32 | 
             
              require_relative "topolys/geometry"
         | 
| 33 33 | 
             
              require_relative "topolys/transformation"
         | 
| 34 34 | 
             
              require_relative "topolys/version"
         | 
| 35 35 |  | 
| 36 | 
            -
              puts "... fallback to local Topolys files"
         | 
| 36 | 
            +
              # puts "... fallback to local Topolys files"
         | 
| 37 37 | 
             
            end
         | 
| 38 38 |  | 
| 39 39 | 
             
            begin
         | 
| 40 40 | 
             
              # Try to load from the OSlg gem.
         | 
| 41 41 | 
             
              require "oslg"
         | 
| 42 42 |  | 
| 43 | 
            -
              puts "... relying on the OSlg gem"
         | 
| 43 | 
            +
              # puts "... relying on the OSlg gem"
         | 
| 44 44 | 
             
            rescue LoadError
         | 
| 45 45 | 
             
              require_relative "oslg/oslog"
         | 
| 46 46 | 
             
              require_relative "osut/version"
         | 
| 47 47 |  | 
| 48 | 
            -
              puts "... fallback to local OSlg files"
         | 
| 48 | 
            +
              # puts "... fallback to local OSlg files"
         | 
| 49 49 | 
             
            end
         | 
| 50 50 |  | 
| 51 51 | 
             
            begin
         | 
| 52 52 | 
             
              # Try to load from the OSut gem.
         | 
| 53 53 | 
             
              require "osut"
         | 
| 54 54 |  | 
| 55 | 
            -
              puts "... relying on the OSut gem"
         | 
| 55 | 
            +
              # puts "... relying on the OSut gem"
         | 
| 56 56 | 
             
            rescue LoadError
         | 
| 57 57 | 
             
              require_relative "osut/utils"
         | 
| 58 58 | 
             
              require_relative "osut/version"
         | 
| 59 59 |  | 
| 60 | 
            -
              puts "... fallback to local OSut files"
         | 
| 60 | 
            +
              # puts "... fallback to local OSut files"
         | 
| 61 61 | 
             
            end
         | 
| 62 62 |  | 
| 63 63 | 
             
            begin
         | 
| @@ -67,14 +67,14 @@ begin | |
| 67 67 | 
             
              require "tbd/ua"
         | 
| 68 68 | 
             
              require "tbd/version"
         | 
| 69 69 |  | 
| 70 | 
            -
              puts "... relying on the TBD gem"
         | 
| 70 | 
            +
              # puts "... relying on the TBD gem"
         | 
| 71 71 | 
             
            rescue LoadError
         | 
| 72 72 | 
             
              require_relative "tbd/psi"
         | 
| 73 73 | 
             
              require_relative "tbd/geo"
         | 
| 74 74 | 
             
              require_relative "tbd/ua"
         | 
| 75 75 | 
             
              require_relative "tbd/version"
         | 
| 76 76 |  | 
| 77 | 
            -
              puts "... fallback to local TBD files"
         | 
| 77 | 
            +
              # puts "... fallback to local TBD files"
         | 
| 78 78 | 
             
            end
         | 
| 79 79 |  | 
| 80 80 | 
             
            module TBD
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: tbd
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 3.2. | 
| 4 | 
            +
              version: 3.2.2
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Denis Bourgeois & Dan Macumber
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023- | 
| 11 | 
            +
            date: 2023-03-23 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: topolys
         | 
| @@ -161,7 +161,7 @@ licenses: | |
| 161 161 | 
             
            - MIT
         | 
| 162 162 | 
             
            metadata:
         | 
| 163 163 | 
             
              homepage_uri: https://github.com/rd2/tbd
         | 
| 164 | 
            -
              source_code_uri: https://github.com/rd2/tbd/tree/v3.2. | 
| 164 | 
            +
              source_code_uri: https://github.com/rd2/tbd/tree/v3.2.2
         | 
| 165 165 | 
             
              bug_tracker_uri: https://github.com/rd2/tbd/issues
         | 
| 166 166 | 
             
            post_install_message:
         | 
| 167 167 | 
             
            rdoc_options: []
         |