openstudio-extension 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -327,7 +327,8 @@ module OsLib_Geometry
327
327
  end
328
328
 
329
329
  # sort array by floor area, this hash will be altered to reduce floor area for each space type to 0
330
- space_types_running_count = space_types.sort_by { |k, v| v[:floor_area] }
330
+ #space_types_running_count = space_types.sort_by { |k, v| v[:floor_area] }
331
+ space_types_running_count = space_types
331
332
 
332
333
  # array entry for each story
333
334
  footprints = []
@@ -354,8 +355,10 @@ module OsLib_Geometry
354
355
 
355
356
  space_types_running_count.each do |space_type, space_type_hash|
356
357
  # next if floor area is full or space type is empty
357
- next if current_footprint_area >= target_footprint_area
358
- next if space_type_hash[:floor_area] <= 0.0
358
+
359
+ tol_value = 0.0001
360
+ next if current_footprint_area + tol_value >= target_footprint_area
361
+ next if space_type_hash[:floor_area] <= tol_value
359
362
 
360
363
  # special test for when total floor area is smaller than valid_bar_area_min, just make bar smaller that valid min and warn user
361
364
  if target_per_space_type[space_type] < valid_bar_area_min
@@ -367,20 +370,18 @@ module OsLib_Geometry
367
370
 
368
371
  # add entry for space type if it doesn't have one yet
369
372
  if !space_types_local_count.key?(space_type)
370
- space_types_local_count[space_type] = { floor_area: 0.0 }
373
+ if space_type_hash.has_key?(:children)
374
+ space_type = space_type_hash[:children][:default][:space_type] # will re-using space type create issue
375
+ space_types_local_count[space_type] = { floor_area: 0.0 }
376
+ space_types_local_count[space_type][:children] = space_type_hash[:children]
377
+ else
378
+ space_types_local_count[space_type] = { floor_area: 0.0 }
379
+ end
371
380
  end
372
381
 
373
382
  # if there is enough of this space type to fill rest of floor area
374
383
  remaining_in_footprint = target_footprint_area - current_footprint_area
375
- if space_type_hash[:floor_area] > remaining_in_footprint
376
-
377
- # add to local count for story and remove from running count from space type
378
- raw_footprint_area_used = remaining_in_footprint
379
-
380
- else
381
- # if not then use up the rest of the floor area and move on to next space type
382
- raw_footprint_area_used = space_type_hash[:floor_area]
383
- end
384
+ raw_footprint_area_used = [space_type_hash[:floor_area],remaining_in_footprint].min
384
385
 
385
386
  # add to local hash
386
387
  space_types_local_count[space_type][:floor_area] = raw_footprint_area_used / v[:multiplier].to_f
@@ -389,13 +390,13 @@ module OsLib_Geometry
389
390
  current_footprint_area += raw_footprint_area_used
390
391
  space_type_hash[:floor_area] -= raw_footprint_area_used
391
392
 
392
- # test if think slice left on current floor.
393
+ # test if think sliver left on current floor.
393
394
  # fix by moving smallest space type to next floor and and the same amount more of the sliver space type to this story
394
395
  raw_footprint_area_used < valid_bar_area_min && sliver_override == false ? (test_a = true) : (test_a = false)
395
396
 
396
397
  # test if what would be left of the current space type would result in a sliver on the next story.
397
398
  # fix by removing some of this space type so their is enough left for the next story, and replace the removed amount with the largest space type in the model
398
- (space_type_hash[:floor_area] < valid_bar_area_min) && (space_type_hash[:floor_area] > 0.0001) ? (test_b = true) : (test_b = false)
399
+ (space_type_hash[:floor_area] < valid_bar_area_min) && (space_type_hash[:floor_area] > tol_value) ? (test_b = true) : (test_b = false)
399
400
 
400
401
  # identify very small slices and re-arrange spaces to different stories to avoid this
401
402
  if test_a
@@ -422,6 +423,10 @@ module OsLib_Geometry
422
423
 
423
424
  # swap size
424
425
  swap_size = valid_bar_area_min * 5 # currently equal to default perimeter zone depth of 15'
426
+ # this prevents too much area from being swapped resulting in a negative number for floor area
427
+ if swap_size > space_types_local_count[space_type][:floor_area] * v[:multiplier].to_f
428
+ swap_size = space_types_local_count[space_type][:floor_area] * v[:multiplier].to_f
429
+ end
425
430
 
426
431
  # adjust running count for current space type
427
432
  space_type_hash[:floor_area] += swap_size
@@ -445,12 +450,18 @@ module OsLib_Geometry
445
450
  end
446
451
 
447
452
  # sliced bar simple creates a single sliced bar for space types passed in
448
- # todo - look at length and width to adjust slicing direction
453
+ # look at length and width to adjust slicing direction
449
454
  def self.make_sliced_bar_simple_polygons(runner, space_types, length, width, footprint_origin = OpenStudio::Point3d.new(0, 0, 0), perimeter_zone_depth = OpenStudio.convert(15, 'ft', 'm').get)
450
455
  hash_of_point_vectors = {} # key is name, value is a hash, one item of which is polygon. Another could be space type
451
456
 
457
+ reverse_slice = false
458
+ if length < width
459
+ reverse_slice = true
460
+ #runner.registerInfo("reverse typical slice direction for bar because of aspect ratio less than 1.0.")
461
+ end
462
+
452
463
  # determine if core and perimeter zoning can be used
453
- if !(length > perimeter_zone_depth * 2.5 && width > perimeter_zone_depth * 2.5)
464
+ if !([length,width].min > perimeter_zone_depth * 2.5 && [length,width].min > perimeter_zone_depth * 2.5)
454
465
  perimeter_zone_depth = 0 # if any size is to small then just model floor as single zone, issue warning
455
466
  runner.registerWarning('Not modeling core and perimeter zones for some portion of the model.')
456
467
  end
@@ -461,6 +472,7 @@ module OsLib_Geometry
461
472
  # this represents the entire bar, not individual space type slices
462
473
  nw_point = OpenStudio::Point3d.new(x_delta, y_delta + width, z)
463
474
  sw_point = OpenStudio::Point3d.new(x_delta, y_delta, z)
475
+ se_point = OpenStudio::Point3d.new(x_delta + length, y_delta, z) # used when length is less than width
464
476
 
465
477
  # total building floor area to calculate ratios from space type floor areas
466
478
  total_floor_area = 0.0
@@ -470,7 +482,7 @@ module OsLib_Geometry
470
482
 
471
483
  # sort array by floor area but shift largest object to front
472
484
  space_types = space_types.sort_by { |k, v| v[:floor_area] }
473
- space_types.insert(0, space_types.delete_at(space_types.size - 1))
485
+ space_types.insert(0, space_types.delete_at(space_types.size - 1)) #.to_h
474
486
 
475
487
  # min and max bar end values
476
488
  min_bar_end_multiplier = 0.75
@@ -484,20 +496,20 @@ module OsLib_Geometry
484
496
  start_perimeter_width_deduction = 0.0
485
497
  end_perimeter_width_deduction = 0.0
486
498
  if space_type == space_types.first[0]
487
- if length * space_type_hash[:floor_area] / total_floor_area > max_bar_end_multiplier * perimeter_zone_depth
499
+ if [length,width].max * space_type_hash[:floor_area] / total_floor_area > max_bar_end_multiplier * perimeter_zone_depth
488
500
  start_perimeter_width_deduction = perimeter_zone_depth
489
501
  end
490
502
  # see if last space type is too small for perimeter. If it is then save some of this space type
491
- if length * space_types.last[1][:floor_area] / total_floor_area < perimeter_zone_depth * min_bar_end_multiplier
503
+ if [length,width].max * space_types.last[1][:floor_area] / total_floor_area < perimeter_zone_depth * min_bar_end_multiplier
492
504
  re_apply_largest_space_type_at_end = true
493
505
  end
494
506
  end
495
507
  if space_type == space_types.last[0]
496
- if length * space_type_hash[:floor_area] / total_floor_area > max_bar_end_multiplier * perimeter_zone_depth
508
+ if [length,width].max * space_type_hash[:floor_area] / total_floor_area > max_bar_end_multiplier * perimeter_zone_depth
497
509
  end_perimeter_width_deduction = perimeter_zone_depth
498
510
  end
499
511
  end
500
- non_end_adjusted_width = (length * space_type_hash[:floor_area] / total_floor_area) - start_perimeter_width_deduction - end_perimeter_width_deduction
512
+ non_end_adjusted_width = ([length,width].max * space_type_hash[:floor_area] / total_floor_area) - start_perimeter_width_deduction - end_perimeter_width_deduction
501
513
 
502
514
  # adjustment of end space type is too small and is replaced with largest space type
503
515
  if (space_type == space_types.first[0]) && re_apply_largest_space_type_at_end
@@ -506,69 +518,223 @@ module OsLib_Geometry
506
518
  end
507
519
  if (space_type == space_types.last[0]) && re_apply_largest_space_type_at_end
508
520
  end_perimeter_width_deduction = space_types.first[0]
521
+ end_b_flag = true
522
+ else
523
+ end_b_flag = false
509
524
  end
510
525
 
511
- # poulate data for core and perimeter of slice
526
+ # populate data for core and perimeter of slice
512
527
  section_hash_for_space_type = {}
513
528
  section_hash_for_space_type['end_a'] = start_perimeter_width_deduction
514
529
  section_hash_for_space_type[''] = non_end_adjusted_width
515
530
  section_hash_for_space_type['end_b'] = end_perimeter_width_deduction
516
531
 
532
+ # determine if this space+type is double loaded corridor, and if so what the perimeter zone depth should be based on building width
533
+ # look at reverse_slice to see if length or width should be used to determine perimeter depth
534
+ if space_type_hash.has_key?(:children)
535
+ core_ratio = space_type_hash[:children][:circ][:orig_ratio]
536
+ perim_ratio = space_type_hash[:children][:default][:orig_ratio]
537
+ core_ratio_adj = core_ratio / (core_ratio + perim_ratio)
538
+ perim_ratio_adj = perim_ratio / (core_ratio + perim_ratio)
539
+ core_space_type = space_type_hash[:children][:circ][:space_type]
540
+ perim_space_type = space_type_hash[:children][:default][:space_type]
541
+ if !reverse_slice
542
+ custom_cor_val = width * core_ratio_adj
543
+ custom_perim_val = (width - custom_cor_val)/2.0
544
+ else
545
+ custom_cor_val = length * core_ratio_adj
546
+ custom_perim_val = (length - custom_cor_val)/2.0
547
+ end
548
+ actual_perim = custom_perim_val
549
+ double_loaded_corridor = true
550
+ else
551
+ actual_perim = perimeter_zone_depth
552
+ double_loaded_corridor = false
553
+ end
554
+
555
+ # may overwrite
556
+ first_space_type_hash = space_types.first[1]
557
+ if end_b_flag && first_space_type_hash.has_key?(:children)
558
+ end_b_core_ratio = first_space_type_hash[:children][:circ][:orig_ratio]
559
+ end_b_perim_ratio = first_space_type_hash[:children][:default][:orig_ratio]
560
+ end_b_core_ratio_adj = end_b_core_ratio / (end_b_core_ratio + end_b_perim_ratio)
561
+ end_b_perim_ratio_adj = end_b_perim_ratio / (end_b_core_ratio + end_b_perim_ratio)
562
+ end_b_core_space_type = first_space_type_hash[:children][:circ][:space_type]
563
+ end_b_perim_space_type = first_space_type_hash[:children][:default][:space_type]
564
+ if !reverse_slice
565
+ end_b_custom_cor_val = width * end_b_core_ratio_adj
566
+ end_b_custom_perim_val = (width - end_b_custom_cor_val)/2.0
567
+ else
568
+ end_b_custom_cor_val = length * end_b_core_ratio_adj
569
+ end_b_custom_perim_val = (length - end_b_custom_cor_val)/2.0
570
+ end
571
+ end_b_actual_perim = end_b_custom_perim_val
572
+ end_b_double_loaded_corridor = true
573
+ else
574
+ end_b_actual_perim = perimeter_zone_depth
575
+ end_b_double_loaded_corridor = false
576
+ end
577
+
517
578
  # loop through sections for space type (main and possibly one or two end perimeter sections)
518
- section_hash_for_space_type.each do |k, width|
519
- if width.class.to_s == 'OpenStudio::Model::SpaceType' # confirm this
520
- space_type = width
579
+ section_hash_for_space_type.each do |k, slice|
580
+
581
+ # need to use different space type for end_b
582
+ if end_b_flag && k == "end_b" && space_types.first[1].has_key?(:children)
583
+ slice = space_types.first[0]
584
+ actual_perim = end_b_actual_perim
585
+ double_loaded_corridor = end_b_double_loaded_corridor
586
+ core_ratio = end_b_core_ratio
587
+ perim_ratio = end_b_perim_ratio
588
+ core_ratio_adj = end_b_core_ratio_adj
589
+ perim_ratio_adj = end_b_perim_ratio_adj
590
+ core_space_type = end_b_core_space_type
591
+ perim_space_type = end_b_perim_space_type
592
+ end
593
+
594
+ if slice.class.to_s == 'OpenStudio::Model::SpaceType' || slice.class.to_s == 'OpenStudio::Model::Building'
595
+ space_type = slice
521
596
  max_reduction = [perimeter_zone_depth, max_reduction].min
522
- width = max_reduction
597
+ slice = max_reduction
523
598
  end
524
- if width == 0
599
+ if slice == 0
525
600
  next
526
601
  end
527
602
 
528
- ne_point = nw_point + OpenStudio::Vector3d.new(width, 0, 0)
529
- se_point = sw_point + OpenStudio::Vector3d.new(width, 0, 0)
530
-
531
- if perimeter_zone_depth > 0
532
- polygon_a = OpenStudio::Point3dVector.new
533
- polygon_a << sw_point
534
- polygon_a << sw_point + OpenStudio::Vector3d.new(0, perimeter_zone_depth, 0)
535
- polygon_a << se_point + OpenStudio::Vector3d.new(0, perimeter_zone_depth, 0)
536
- polygon_a << se_point
537
- hash_of_point_vectors["#{space_type.name} A #{k}"] = {}
538
- hash_of_point_vectors["#{space_type.name} A #{k}"][:space_type] = space_type
539
- hash_of_point_vectors["#{space_type.name} A #{k}"][:polygon] = polygon_a
540
-
541
- polygon_b = OpenStudio::Point3dVector.new
542
- polygon_b << sw_point + OpenStudio::Vector3d.new(0, perimeter_zone_depth, 0)
543
- polygon_b << nw_point + OpenStudio::Vector3d.new(0, - perimeter_zone_depth, 0)
544
- polygon_b << ne_point + OpenStudio::Vector3d.new(0, - perimeter_zone_depth, 0)
545
- polygon_b << se_point + OpenStudio::Vector3d.new(0, perimeter_zone_depth, 0)
546
- hash_of_point_vectors["#{space_type.name} B #{k}"] = {}
547
- hash_of_point_vectors["#{space_type.name} B #{k}"][:space_type] = space_type
548
- hash_of_point_vectors["#{space_type.name} B #{k}"][:polygon] = polygon_b
549
-
550
- polygon_c = OpenStudio::Point3dVector.new
551
- polygon_c << nw_point + OpenStudio::Vector3d.new(0, - perimeter_zone_depth, 0)
552
- polygon_c << nw_point
553
- polygon_c << ne_point
554
- polygon_c << ne_point + OpenStudio::Vector3d.new(0, - perimeter_zone_depth, 0)
555
- hash_of_point_vectors["#{space_type.name} C #{k}"] = {}
556
- hash_of_point_vectors["#{space_type.name} C #{k}"][:space_type] = space_type
557
- hash_of_point_vectors["#{space_type.name} C #{k}"][:polygon] = polygon_c
603
+ if !reverse_slice
604
+
605
+ ne_point = nw_point + OpenStudio::Vector3d.new(slice, 0, 0)
606
+ se_point = sw_point + OpenStudio::Vector3d.new(slice, 0, 0)
607
+
608
+ if actual_perim > 0 && (actual_perim * 2.0) < width
609
+ polygon_a = OpenStudio::Point3dVector.new
610
+ polygon_a << sw_point
611
+ polygon_a << sw_point + OpenStudio::Vector3d.new(0, actual_perim, 0)
612
+ polygon_a << se_point + OpenStudio::Vector3d.new(0, actual_perim, 0)
613
+ polygon_a << se_point
614
+ if double_loaded_corridor
615
+ hash_of_point_vectors["#{perim_space_type.name} A #{k}"] = {}
616
+ hash_of_point_vectors["#{perim_space_type.name} A #{k}"][:space_type] = perim_space_type
617
+ hash_of_point_vectors["#{perim_space_type.name} A #{k}"][:polygon] = polygon_a
618
+ else
619
+ hash_of_point_vectors["#{space_type.name} A #{k}"] = {}
620
+ hash_of_point_vectors["#{space_type.name} A #{k}"][:space_type] = space_type
621
+ hash_of_point_vectors["#{space_type.name} A #{k}"][:polygon] = polygon_a
622
+ end
623
+
624
+ polygon_b = OpenStudio::Point3dVector.new
625
+ polygon_b << sw_point + OpenStudio::Vector3d.new(0, actual_perim, 0)
626
+ polygon_b << nw_point + OpenStudio::Vector3d.new(0, - actual_perim, 0)
627
+ polygon_b << ne_point + OpenStudio::Vector3d.new(0, - actual_perim, 0)
628
+ polygon_b << se_point + OpenStudio::Vector3d.new(0, actual_perim, 0)
629
+ if double_loaded_corridor
630
+ hash_of_point_vectors["#{core_space_type.name} B #{k}"] = {}
631
+ hash_of_point_vectors["#{core_space_type.name} B #{k}"][:space_type] = core_space_type
632
+ hash_of_point_vectors["#{core_space_type.name} B #{k}"][:polygon] = polygon_b
633
+ else
634
+ hash_of_point_vectors["#{space_type.name} B #{k}"] = {}
635
+ hash_of_point_vectors["#{space_type.name} B #{k}"][:space_type] = space_type
636
+ hash_of_point_vectors["#{space_type.name} B #{k}"][:polygon] = polygon_b
637
+ end
638
+
639
+ polygon_c = OpenStudio::Point3dVector.new
640
+ polygon_c << nw_point + OpenStudio::Vector3d.new(0, - actual_perim, 0)
641
+ polygon_c << nw_point
642
+ polygon_c << ne_point
643
+ polygon_c << ne_point + OpenStudio::Vector3d.new(0, - actual_perim, 0)
644
+ if double_loaded_corridor
645
+ hash_of_point_vectors["#{perim_space_type.name} C #{k}"] = {}
646
+ hash_of_point_vectors["#{perim_space_type.name} C #{k}"][:space_type] = perim_space_type
647
+ hash_of_point_vectors["#{perim_space_type.name} C #{k}"][:polygon] = polygon_c
648
+ else
649
+ hash_of_point_vectors["#{space_type.name} C #{k}"] = {}
650
+ hash_of_point_vectors["#{space_type.name} C #{k}"][:space_type] = space_type
651
+ hash_of_point_vectors["#{space_type.name} C #{k}"][:polygon] = polygon_c
652
+ end
653
+ else
654
+ polygon_a = OpenStudio::Point3dVector.new
655
+ polygon_a << sw_point
656
+ polygon_a << nw_point
657
+ polygon_a << ne_point
658
+ polygon_a << se_point
659
+ hash_of_point_vectors["#{space_type.name} #{k}"] = {}
660
+ hash_of_point_vectors["#{space_type.name} #{k}"][:space_type] = space_type
661
+ hash_of_point_vectors["#{space_type.name} #{k}"][:polygon] = polygon_a
662
+ end
663
+
664
+ # update west points
665
+ nw_point = ne_point
666
+ sw_point = se_point
667
+
558
668
  else
559
- polygon_a = OpenStudio::Point3dVector.new
560
- polygon_a << sw_point
561
- polygon_a << nw_point
562
- polygon_a << ne_point
563
- polygon_a << se_point
564
- hash_of_point_vectors["#{space_type.name} #{k}"] = {}
565
- hash_of_point_vectors["#{space_type.name} #{k}"][:space_type] = space_type
566
- hash_of_point_vectors["#{space_type.name} #{k}"][:polygon] = polygon_a
567
- end
568
669
 
569
- # update west points
570
- nw_point = ne_point
571
- sw_point = se_point
670
+ # create_bar at 90 degrees if aspect ration is less than 1.0
671
+ # typical order (sw,nw,ne,se)
672
+ # order used here (se,sw,nw,ne)
673
+
674
+ nw_point = sw_point + OpenStudio::Vector3d.new(0, slice, 0)
675
+ ne_point = se_point + OpenStudio::Vector3d.new(0, slice, 0)
676
+
677
+ if actual_perim > 0 && (actual_perim * 2.0) < length
678
+ polygon_a = OpenStudio::Point3dVector.new
679
+ polygon_a << se_point
680
+ polygon_a << se_point + OpenStudio::Vector3d.new(- actual_perim, 0, 0)
681
+ polygon_a << ne_point + OpenStudio::Vector3d.new(- actual_perim, 0, 0)
682
+ polygon_a << ne_point
683
+ if double_loaded_corridor
684
+ hash_of_point_vectors["#{perim_space_type.name} A #{k}"] = {}
685
+ hash_of_point_vectors["#{perim_space_type.name} A #{k}"][:space_type] = perim_space_type
686
+ hash_of_point_vectors["#{perim_space_type.name} A #{k}"][:polygon] = polygon_a
687
+ else
688
+ hash_of_point_vectors["#{space_type.name} A #{k}"] = {}
689
+ hash_of_point_vectors["#{space_type.name} A #{k}"][:space_type] = space_type
690
+ hash_of_point_vectors["#{space_type.name} A #{k}"][:polygon] = polygon_a
691
+ end
692
+
693
+ polygon_b = OpenStudio::Point3dVector.new
694
+ polygon_b << se_point + OpenStudio::Vector3d.new(- actual_perim, 0, 0)
695
+ polygon_b << sw_point + OpenStudio::Vector3d.new(actual_perim, 0, 0)
696
+ polygon_b << nw_point + OpenStudio::Vector3d.new(actual_perim, 0, 0)
697
+ polygon_b << ne_point + OpenStudio::Vector3d.new(- actual_perim, 0, 0)
698
+ if double_loaded_corridor
699
+ hash_of_point_vectors["#{core_space_type.name} B #{k}"] = {}
700
+ hash_of_point_vectors["#{core_space_type.name} B #{k}"][:space_type] = core_space_type
701
+ hash_of_point_vectors["#{core_space_type.name} B #{k}"][:polygon] = polygon_b
702
+ else
703
+ hash_of_point_vectors["#{space_type.name} B #{k}"] = {}
704
+ hash_of_point_vectors["#{space_type.name} B #{k}"][:space_type] = space_type
705
+ hash_of_point_vectors["#{space_type.name} B #{k}"][:polygon] = polygon_b
706
+ end
707
+
708
+ polygon_c = OpenStudio::Point3dVector.new
709
+ polygon_c << sw_point + OpenStudio::Vector3d.new(actual_perim, 0, 0)
710
+ polygon_c << sw_point
711
+ polygon_c << nw_point
712
+ polygon_c << nw_point + OpenStudio::Vector3d.new(actual_perim, 0, 0)
713
+ if double_loaded_corridor
714
+ hash_of_point_vectors["#{perim_space_type.name} C #{k}"] = {}
715
+ hash_of_point_vectors["#{perim_space_type.name} C #{k}"][:space_type] = perim_space_type
716
+ hash_of_point_vectors["#{perim_space_type.name} C #{k}"][:polygon] = polygon_c
717
+ else
718
+ hash_of_point_vectors["#{space_type.name} C #{k}"] = {}
719
+ hash_of_point_vectors["#{space_type.name} C #{k}"][:space_type] = space_type
720
+ hash_of_point_vectors["#{space_type.name} C #{k}"][:polygon] = polygon_c
721
+ end
722
+ else
723
+ polygon_a = OpenStudio::Point3dVector.new
724
+ polygon_a << se_point
725
+ polygon_a << sw_point
726
+ polygon_a << nw_point
727
+ polygon_a << ne_point
728
+ hash_of_point_vectors["#{space_type.name} #{k}"] = {}
729
+ hash_of_point_vectors["#{space_type.name} #{k}"][:space_type] = space_type
730
+ hash_of_point_vectors["#{space_type.name} #{k}"][:polygon] = polygon_a
731
+ end
732
+
733
+ # update west points
734
+ sw_point = nw_point
735
+ se_point = ne_point
736
+
737
+ end
572
738
  end
573
739
  end
574
740
 
@@ -592,13 +758,24 @@ module OsLib_Geometry
592
758
  end
593
759
  end
594
760
 
761
+ # hash of new spaces (only change boundary conditions for these)
762
+ new_spaces = []
763
+
595
764
  # loop through story_hash and polygons to generate all of the spaces
596
765
  story_hash.each_with_index do |(story_name, story_data), index|
597
- # make new story
598
- story = OpenStudio::Model::BuildingStory.new(model)
599
- story.setNominalFloortoFloorHeight(story_data[:space_height]) # not used for anything
600
- story.setNominalZCoordinate (story_data[:space_origin_z]) # not used for anything
601
- story.setName("Story #{story_name}")
766
+ # make new story unless story at requested height already exists.
767
+ story = nil
768
+ model.getBuildingStorys.each do |ext_story|
769
+ if (ext_story.nominalZCoordinate.to_f - story_data[:space_origin_z].to_f).abs < 0.01
770
+ story = ext_story
771
+ end
772
+ end
773
+ if story.nil?
774
+ story = OpenStudio::Model::BuildingStory.new(model)
775
+ story.setNominalFloortoFloorHeight(story_data[:space_height]) # not used for anything
776
+ story.setNominalZCoordinate (story_data[:space_origin_z]) # not used for anything
777
+ story.setName("Story #{story_name}")
778
+ end
602
779
 
603
780
  # multiplier values for adjacent stories to be altered below as needed
604
781
  multiplier_story_above = 1
@@ -647,6 +824,7 @@ module OsLib_Geometry
647
824
 
648
825
  # make space
649
826
  space = OsLib_Geometry.makeSpaceFromPolygon(model, space_data[:polygon].first, space_data[:polygon], options)
827
+ new_spaces << space
650
828
 
651
829
  # set z origin to proper position
652
830
  space.setZOrigin(story_data[:space_origin_z])
@@ -676,7 +854,7 @@ module OsLib_Geometry
676
854
  # any changes to wall boundary conditions will be handled by same code that calls this method.
677
855
  # this method doesn't need to know about basements and party walls.
678
856
 
679
- return model
857
+ return new_spaces
680
858
  end
681
859
 
682
860
  # add def to create a space from input, optionally take a name, space type, story and thermal zone.
@@ -714,7 +892,7 @@ module OsLib_Geometry
714
892
  space.setName(options['name'])
715
893
  end
716
894
 
717
- if !options['spaceType'].nil?
895
+ if !options['spaceType'].nil? && options['spaceType'].class.to_s == 'OpenStudio::Model::SpaceType'
718
896
  space.setSpaceType(options['spaceType'])
719
897
  end
720
898