structuraid_core 0.1.1

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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +38 -0
  4. data/CHANGELOG.md +5 -0
  5. data/CODE_OF_CONDUCT.md +84 -0
  6. data/Gemfile +2 -0
  7. data/Guardfile +5 -0
  8. data/LICENSE +21 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +37 -0
  11. data/Rakefile +12 -0
  12. data/lib/structuraid_core/db/base.rb +13 -0
  13. data/lib/structuraid_core/db/rebars.yml +36 -0
  14. data/lib/structuraid_core/design_codes/aci_318_19/rc/elastic_modulus.rb +17 -0
  15. data/lib/structuraid_core/design_codes/base.rb +15 -0
  16. data/lib/structuraid_core/design_codes/nsr_10/rc/elastic_modulus.rb +17 -0
  17. data/lib/structuraid_core/design_codes/resolver.rb +21 -0
  18. data/lib/structuraid_core/design_codes/schemas/empty_schema.rb +12 -0
  19. data/lib/structuraid_core/design_codes/schemas/rc/elastic_modulus_schema.rb +14 -0
  20. data/lib/structuraid_core/design_codes/utils/code_requirement.rb +39 -0
  21. data/lib/structuraid_core/design_codes/utils/schema_definition.rb +56 -0
  22. data/lib/structuraid_core/elements/base.rb +10 -0
  23. data/lib/structuraid_core/elements/column/base.rb +10 -0
  24. data/lib/structuraid_core/elements/column/rectangular.rb +16 -0
  25. data/lib/structuraid_core/elements/footing.rb +83 -0
  26. data/lib/structuraid_core/elements/reinforcement/base.rb +14 -0
  27. data/lib/structuraid_core/elements/reinforcement/rebar.rb +45 -0
  28. data/lib/structuraid_core/elements/reinforcement/rebar_hook.rb +18 -0
  29. data/lib/structuraid_core/elements/reinforcement/straight_longitudinal.rb +44 -0
  30. data/lib/structuraid_core/elements/reinforcement/straight_longitudinal_layer.rb +89 -0
  31. data/lib/structuraid_core/elements/reinforcement/utils/rebar_data.rb +14 -0
  32. data/lib/structuraid_core/engineering/analysis/footing/centric_isolated.rb +60 -0
  33. data/lib/structuraid_core/engineering/base.rb +10 -0
  34. data/lib/structuraid_core/engineering/locations/absolute.rb +19 -0
  35. data/lib/structuraid_core/engineering/locations/base.rb +11 -0
  36. data/lib/structuraid_core/engineering/locations/relative.rb +15 -0
  37. data/lib/structuraid_core/engineering/vector.rb +35 -0
  38. data/lib/structuraid_core/errors/base.rb +12 -0
  39. data/lib/structuraid_core/errors/design_codes/missing_param_error.rb +9 -0
  40. data/lib/structuraid_core/errors/design_codes/unknown_design_code_error.rb +11 -0
  41. data/lib/structuraid_core/errors/engineering/analysis/section_direction_error.rb +13 -0
  42. data/lib/structuraid_core/errors/reinforcement/empty_layers.rb +13 -0
  43. data/lib/structuraid_core/errors/reinforcement/invalid_distribution_direction.rb +13 -0
  44. data/lib/structuraid_core/loads/base.rb +9 -0
  45. data/lib/structuraid_core/loads/point_load.rb +13 -0
  46. data/lib/structuraid_core/loads/uniform_load.rb +15 -0
  47. data/lib/structuraid_core/materials/base.rb +10 -0
  48. data/lib/structuraid_core/materials/concrete.rb +13 -0
  49. data/lib/structuraid_core/materials/soil.rb +11 -0
  50. data/lib/structuraid_core/materials/steel.rb +14 -0
  51. data/lib/structuraid_core/version.rb +5 -0
  52. data/lib/structuraid_core.rb +14 -0
  53. data/sig/structuraid_core.rbs +4 -0
  54. data/structuraid_core.gemspec +50 -0
  55. metadata +212 -0
@@ -0,0 +1,45 @@
1
+ module StructuraidCore
2
+ module Elements
3
+ module Reinforcement
4
+ class Rebar < Base
5
+ include Utils::RebarData
6
+
7
+ attr_reader :start_hook, :end_hook, :diameter, :number, :material
8
+
9
+ def initialize(number:, material:)
10
+ @start_hook = nil
11
+ @end_hook = nil
12
+ @number = number
13
+ @material = material
14
+ @diameter = find_standard_diameter(rebar_number: number)
15
+ end
16
+
17
+ def area
18
+ rebar_area = Math::PI * (diameter**2) / 4
19
+ rebar_area.to_f
20
+ end
21
+
22
+ def perimeter
23
+ rebar_perimeter = Math::PI * diameter
24
+ rebar_perimeter.to_f
25
+ end
26
+
27
+ def add_start_hook(hook)
28
+ @start_hook = hook
29
+ end
30
+
31
+ def add_end_hook(hook)
32
+ @end_hook = hook
33
+ end
34
+
35
+ def delete_start_hook
36
+ @start_hook = nil
37
+ end
38
+
39
+ def delete_end_hook
40
+ @end_hook = nil
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,18 @@
1
+ module StructuraidCore
2
+ module Elements
3
+ module Reinforcement
4
+ class RebarHook < Base
5
+ include Utils::RebarData
6
+
7
+ attr_reader :angle
8
+
9
+ def initialize(number:, material:)
10
+ @angle = nil
11
+ @number = number
12
+ @material = material
13
+ @diameter = find_standard_diameter(rebar_number: number)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,44 @@
1
+ module StructuraidCore
2
+ module Elements
3
+ module Reinforcement
4
+ class StraightLongitudinal < Base
5
+ attr_reader :layers
6
+
7
+ def initialize(distribution_direction:, above_middle: false)
8
+ @above_middle = above_middle
9
+ @layers = []
10
+ @distribution_direction = distribution_direction
11
+ end
12
+
13
+ def add_layer(start_location:, end_location:, amount_of_rebars:, rebar:)
14
+ new_layer = Elements::Reinforcement::StraightLongitudinalLayer.new(
15
+ start_location:,
16
+ end_location:,
17
+ amount_of_rebars:,
18
+ rebar:,
19
+ distribution_direction: @distribution_direction
20
+ )
21
+
22
+ new_layer.reposition(above_middle: @above_middle)
23
+ @layers << new_layer
24
+
25
+ new_layer
26
+ end
27
+
28
+ def centroid_height
29
+ return inertia / area unless @layers.empty?
30
+
31
+ raise Elements::Reinforcement::EmptyLayers, "can't complete centroid height calculation"
32
+ end
33
+
34
+ def area
35
+ @layers.map(&:area).reduce(:+)
36
+ end
37
+
38
+ def inertia
39
+ @layers.map(&:inertia).reduce(:+)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,89 @@
1
+ module StructuraidCore
2
+ module Elements
3
+ module Reinforcement
4
+ class StraightLongitudinalLayer < Base
5
+ attr_reader :rebar, :amount_of_rebars
6
+
7
+ VALID_DIRECTIONS = %i[length_1 length_2 length_3].freeze
8
+
9
+ def initialize(
10
+ start_location:,
11
+ end_location:,
12
+ amount_of_rebars:,
13
+ rebar:,
14
+ distribution_direction:
15
+ )
16
+ if VALID_DIRECTIONS.none?(distribution_direction)
17
+ raise Elements::Reinforcement::InvalidDistributionDirection.new(distribution_direction, VALID_DIRECTIONS)
18
+ end
19
+
20
+ @start_location = start_location
21
+ @end_location = end_location
22
+ @amount_of_rebars = amount_of_rebars
23
+ @rebar = rebar
24
+ @distribution_direction = distribution_direction
25
+ end
26
+
27
+ def modify_rebar_configuration(
28
+ amount_of_new_rebars:,
29
+ new_rebar:,
30
+ above_middle:
31
+ )
32
+
33
+ offset = (diameter - new_rebar.diameter) / 2
34
+ offset *= -1 unless above_middle
35
+
36
+ @amount_of_rebars = amount_of_new_rebars
37
+ @rebar = new_rebar
38
+
39
+ reposition(above_middle:, offset:)
40
+ @rebar
41
+ end
42
+
43
+ def reposition(above_middle:, offset: nil)
44
+ offset ||= 0.5 * diameter
45
+
46
+ [@start_location, @end_location].each do |location|
47
+ location.value_3 = above_middle ? location.value_3 - offset : location.value_3 + offset
48
+ end
49
+ end
50
+
51
+ def area
52
+ @amount_of_rebars * @rebar.area
53
+ end
54
+
55
+ def inertia
56
+ area * centroid_height
57
+ end
58
+
59
+ def centroid_height
60
+ @start_location.value_3
61
+ end
62
+
63
+ def diameter
64
+ @rebar.diameter
65
+ end
66
+
67
+ def length
68
+ vector = length_vector
69
+
70
+ vector.value_x = 0 if @distribution_direction == :length_1
71
+ vector.value_y = 0 if @distribution_direction == :length_2
72
+ vector.value_z = 0 if @distribution_direction == :length_3
73
+
74
+ vector.magnitude
75
+ end
76
+
77
+ private
78
+
79
+ def length_vector
80
+ Engineering::Vector.new(
81
+ value_x: @end_location.value_1 - @start_location.value_1,
82
+ value_y: @end_location.value_2 - @start_location.value_2,
83
+ value_z: @end_location.value_3 - @start_location.value_3
84
+ )
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,14 @@
1
+ module StructuraidCore
2
+ module Elements
3
+ module Reinforcement
4
+ module Utils
5
+ module RebarData
6
+ def find_standard_diameter(rebar_number:)
7
+ standard_rebar_data = DB::Base.find_standard_rebar(number: rebar_number)
8
+ standard_rebar_data['diameter'].to_f
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,60 @@
1
+ module StructuraidCore
2
+ module Engineering
3
+ module Analysis
4
+ module Footing
5
+ class CentricIsolated
6
+ ORTHOGONALITIES = %i[length_1 length_2].freeze
7
+
8
+ def initialize(footing:, load_from_column:, section_direction:)
9
+ if ORTHOGONALITIES.none?(section_direction)
10
+ raise Engineering::Analysis::SectionDirectionError.new(section_direction, ORTHOGONALITIES)
11
+ end
12
+
13
+ @footing = footing
14
+ @load_from_column = load_from_column
15
+ @section_direction = section_direction
16
+ end
17
+
18
+ def solicitation_load
19
+ solicitation * orthogonal_length
20
+ end
21
+
22
+ def max_shear_solicitation
23
+ solicitation_load * section_length
24
+ end
25
+
26
+ def shear_solicitation_at(distance_from_footing_center:)
27
+ footing_section_length = section_length
28
+
29
+ solicitation_load * (footing_section_length - distance_from_footing_center)
30
+ end
31
+
32
+ def bending_solicitation
33
+ 0.25 * max_shear_solicitation * section_length
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :footing, :load_from_column, :section_direction
39
+
40
+ def section_length
41
+ footing.public_send(section_direction)
42
+ end
43
+
44
+ def orthogonal_length
45
+ footing.public_send(orthogonal_direction)
46
+ end
47
+
48
+ def solicitation
49
+ load_from_column.value / footing.horizontal_area
50
+ end
51
+
52
+ def orthogonal_direction
53
+ orthogonal = ORTHOGONALITIES - [section_direction]
54
+ orthogonal.last
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,10 @@
1
+ module StructuraidCore
2
+ module Engineering
3
+ class Base
4
+ end
5
+ end
6
+ end
7
+
8
+ require_relative 'vector'
9
+ require_relative 'analysis/footing/centric_isolated'
10
+ require_relative 'locations/base'
@@ -0,0 +1,19 @@
1
+ module StructuraidCore
2
+ module Engineering
3
+ module Locations
4
+ class Absolute < Base
5
+ attr_accessor :value_x, :value_y, :value_z
6
+
7
+ def initialize(value_x:, value_y:, value_z:)
8
+ @value_x = value_x.to_f
9
+ @value_y = value_y.to_f
10
+ @value_z = value_z.to_f
11
+ end
12
+
13
+ def to_a
14
+ [@value_x, @value_y, @value_z]
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ module StructuraidCore
2
+ module Engineering
3
+ module Locations
4
+ class Base
5
+ end
6
+ end
7
+ end
8
+ end
9
+
10
+ require_relative 'absolute'
11
+ require_relative 'relative'
@@ -0,0 +1,15 @@
1
+ module StructuraidCore
2
+ module Engineering
3
+ module Locations
4
+ class Relative < Base
5
+ attr_accessor :value_1, :value_2, :value_3
6
+
7
+ def initialize(value_1:, value_2:, value_3:)
8
+ @value_1 = value_1.to_f
9
+ @value_2 = value_2.to_f
10
+ @value_3 = value_3.to_f
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,35 @@
1
+ module StructuraidCore
2
+ module Engineering
3
+ class Vector < Base
4
+ attr_accessor :value_x, :value_y, :value_z
5
+
6
+ def self.with_value(value:, direction:)
7
+ new(
8
+ value_x: value.to_f * direction[0],
9
+ value_y: value.to_f * direction[1],
10
+ value_z: value.to_f * direction[2]
11
+ )
12
+ end
13
+
14
+ def initialize(value_x:, value_y:, value_z:)
15
+ @value_x = value_x.to_f
16
+ @value_y = value_y.to_f
17
+ @value_z = value_z.to_f
18
+ end
19
+
20
+ def magnitude
21
+ Math.sqrt(value_x**2 + value_y**2 + value_z**2)
22
+ end
23
+
24
+ def direction
25
+ vector_magnitude = magnitude
26
+
27
+ [
28
+ @value_x / vector_magnitude,
29
+ @value_y / vector_magnitude,
30
+ @value_z / vector_magnitude
31
+ ]
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,12 @@
1
+ module StructuraidCore
2
+ module Errors
3
+ class Base < StandardError
4
+ end
5
+ end
6
+ end
7
+
8
+ require_relative 'design_codes/missing_param_error'
9
+ require_relative 'design_codes/unknown_design_code_error'
10
+ require_relative 'engineering/analysis/section_direction_error'
11
+ require_relative 'reinforcement/empty_layers'
12
+ require_relative 'reinforcement/invalid_distribution_direction'
@@ -0,0 +1,9 @@
1
+ module StructuraidCore
2
+ module DesignCodes
3
+ class MissingParamError < StandardError
4
+ def initialize(param)
5
+ super("#{param} param is required")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module StructuraidCore
2
+ module DesignCodes
3
+ class UnknownDesignCodeError < StandardError
4
+ def initialize(code_name)
5
+ message = "Design code #{code_name} is unknown. Must select one of #{DesignCodes::Resolver::CODES_NAMESPACES}"
6
+
7
+ super(message)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module StructuraidCore
2
+ module Engineering
3
+ module Analysis
4
+ class SectionDirectionError < StandardError
5
+ def initialize(section_direction, valid_options)
6
+ message = "#{section_direction} is not a valid direction, should one of #{valid_options}"
7
+
8
+ super(message)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module StructuraidCore
2
+ module Elements
3
+ module Reinforcement
4
+ class EmptyLayers < StandardError
5
+ def initialize(complement)
6
+ message = "There are no layers #{complement}"
7
+
8
+ super(message)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module StructuraidCore
2
+ module Elements
3
+ module Reinforcement
4
+ class InvalidDistributionDirection < StandardError
5
+ def initialize(distribution_direction, valid_directions)
6
+ message = "#{distribution_direction} is not a valid direction, should one of #{valid_directions}"
7
+
8
+ super(message)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module StructuraidCore
2
+ module Loads
3
+ class Base
4
+ end
5
+ end
6
+ end
7
+
8
+ require_relative 'point_load'
9
+ require_relative 'uniform_load'
@@ -0,0 +1,13 @@
1
+ module StructuraidCore
2
+ module Loads
3
+ class PointLoad < Base
4
+ attr_accessor :value
5
+ attr_reader :location
6
+
7
+ def initialize(value:, location:)
8
+ @value = value.to_f
9
+ @location = location
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ module StructuraidCore
2
+ module Loads
3
+ class UniformLoad < Base
4
+ attr_accessor :start_value, :end_value
5
+ attr_reader :start_location
6
+
7
+ def initialize(start_value:, end_value:, start_location:, end_location:)
8
+ @start_value = start_value.to_f
9
+ @end_value = end_value.to_f
10
+ @start_location = start_location
11
+ @end_location = end_location
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ module StructuraidCore
2
+ module Materials
3
+ class Base
4
+ end
5
+ end
6
+ end
7
+
8
+ require_relative 'concrete'
9
+ require_relative 'soil'
10
+ require_relative 'steel'
@@ -0,0 +1,13 @@
1
+ module StructuraidCore
2
+ module Materials
3
+ class Concrete < Base
4
+ attr_reader :elastic_module, :design_compression_strength, :specific_weight
5
+
6
+ def initialize(elastic_module:, design_compression_strength:, specific_weight:)
7
+ @elastic_module = elastic_module.to_f
8
+ @design_compression_strength = design_compression_strength.to_f
9
+ @specific_weight = specific_weight.to_f
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module StructuraidCore
2
+ module Materials
3
+ class Soil < Base
4
+ attr_reader :bearing_capacity
5
+
6
+ def initialize(bearing_capacity:)
7
+ @bearing_capacity = bearing_capacity.to_f
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module StructuraidCore
2
+ module Materials
3
+ class Steel < Base
4
+ DEFAULT_ELASTIC_MODULE = 200_000
5
+
6
+ attr_reader :elastic_module, :yield_stress
7
+
8
+ def initialize(yield_stress:, elastic_module: DEFAULT_ELASTIC_MODULE)
9
+ @elastic_module = elastic_module.to_f
10
+ @yield_stress = yield_stress.to_f
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StructuraidCore
4
+ VERSION = '0.1.1'
5
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'structuraid_core/version'
4
+
5
+ module StructuraidCore
6
+ end
7
+
8
+ require_relative 'structuraid_core/db/base'
9
+ require_relative 'structuraid_core/errors/base'
10
+ require_relative 'structuraid_core/design_codes/base'
11
+ require_relative 'structuraid_core/loads/base'
12
+ require_relative 'structuraid_core/materials/base'
13
+ require_relative 'structuraid_core/engineering/base'
14
+ require_relative 'structuraid_core/elements/base'
@@ -0,0 +1,4 @@
1
+ module StructuraidCore
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/structuraid_core/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'structuraid_core'
7
+ spec.version = StructuraidCore::VERSION
8
+ spec.authors = ['Pradaing']
9
+ spec.email = ['engineering@pradic.co']
10
+
11
+ spec.summary = 'Gem with core utilities and functionality to design building structures'
12
+
13
+ description = <<-DESCRIPTION
14
+ structuraid_core is a gem that offers a set of functionalities to assist in the design building structures.
15
+ DESCRIPTION
16
+ spec.description = description.strip
17
+
18
+ spec.homepage = 'https://github.com/PradaIng/structuraid-core'
19
+ spec.license = 'MIT'
20
+ spec.required_ruby_version = '>= 3.1.2'
21
+
22
+ # spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
23
+ spec.metadata['homepage_uri'] = spec.homepage
24
+ spec.metadata['source_code_uri'] = spec.homepage
25
+ spec.metadata['changelog_uri'] = 'https://github.com/PradaIng/structuraid-core/blob/main/CHANGELOG.md'
26
+
27
+ # Specify which files should be added to the gem when it is released.
28
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
29
+ spec.files = Dir.chdir(__dir__) do
30
+ `git ls-files -z`.split("\x0").reject do |f|
31
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
32
+ end
33
+ end
34
+ spec.bindir = 'exe'
35
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
36
+ spec.require_paths = ['lib']
37
+
38
+ spec.add_development_dependency 'byebug', '~> 11.1.3'
39
+ spec.add_development_dependency 'guard-rspec', '~> 4.7.3'
40
+ spec.add_development_dependency 'rspec', '~> 3.11.0'
41
+ spec.add_development_dependency 'rubocop', '~> 1.41.1'
42
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.16.0'
43
+ spec.add_development_dependency 'simplecov', '~> 0.22.0'
44
+
45
+ spec.add_dependency 'rake', '~> 13.0.6'
46
+ spec.add_dependency 'require_all', '~> 3.0.0'
47
+
48
+ # For more information and examples about making a new gem, check out our
49
+ # guide at: https://bundler.io/guides/creating_gem.html
50
+ end