struct_utils 0.0.1__py3-none-any.whl
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.
- struct_utils/__init__.py +2 -0
- struct_utils/general_utils/__init__.py +2 -0
- struct_utils/general_utils/logprint.py +132 -0
- struct_utils/software_utils/__init__.py +3 -0
- struct_utils/software_utils/folder_structure_tree.py +24 -0
- struct_utils/structural_utils/NASA_TM_108378_fitting_factor.py +228 -0
- struct_utils/structural_utils/__init__.py +17 -0
- struct_utils/structural_utils/bolt_pattern_elastic_method.py +755 -0
- struct_utils/structural_utils/bolt_pattern_elastic_method_README.md +60 -0
- struct_utils/structural_utils/margin_table.py +306 -0
- struct_utils/structural_utils/shared_helpers.py +46 -0
- struct_utils-0.0.1.dist-info/METADATA +70 -0
- struct_utils-0.0.1.dist-info/RECORD +15 -0
- struct_utils-0.0.1.dist-info/WHEEL +4 -0
- struct_utils-0.0.1.dist-info/licenses/LICENSE.txt +21 -0
struct_utils/__init__.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
__all__ = ['setup_logging']
|
|
6
|
+
|
|
7
|
+
def logprint(
|
|
8
|
+
name: str = 'app',
|
|
9
|
+
*,
|
|
10
|
+
verbose: bool = False,
|
|
11
|
+
log_dir: str = '/tmp',
|
|
12
|
+
log_path: str | None = None,
|
|
13
|
+
file_level: int = logging.DEBUG,
|
|
14
|
+
console_level: int | None = None,
|
|
15
|
+
fmt: str = '%(asctime)s %(name)s %(levelname)-8s %(message)s',
|
|
16
|
+
datefmt: str = '%G%V_%u_%H_%M_%S',
|
|
17
|
+
) -> logging.Logger:
|
|
18
|
+
"""Configure and return a named logger.
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
name : str
|
|
23
|
+
Logger name (also used in the default filename).
|
|
24
|
+
verbose : bool
|
|
25
|
+
If True, add a StreamHandler so output also appears on the console.
|
|
26
|
+
log_dir : str
|
|
27
|
+
Directory for the auto-generated log file (default /tmp).
|
|
28
|
+
log_path : str | None
|
|
29
|
+
Explicit log file path. Overrides log_dir + auto-naming.
|
|
30
|
+
file_level : int
|
|
31
|
+
Minimum level written to the file (default DEBUG — capture everything).
|
|
32
|
+
console_level : int | None
|
|
33
|
+
Minimum level printed to console. Defaults to DEBUG if verbose,
|
|
34
|
+
but you can set e.g. logging.WARNING for quieter console output.
|
|
35
|
+
fmt : str
|
|
36
|
+
Log format string.
|
|
37
|
+
datefmt : str
|
|
38
|
+
Timestamp format for log lines.
|
|
39
|
+
|
|
40
|
+
Returns
|
|
41
|
+
-------
|
|
42
|
+
logging.Logger with an extra attribute `log_path` (pathlib.Path or None).
|
|
43
|
+
`log_path` is None when file logging failed and the logger fell back to
|
|
44
|
+
console-only output.
|
|
45
|
+
"""
|
|
46
|
+
logger = logging.getLogger(name)
|
|
47
|
+
|
|
48
|
+
# Avoid stacking duplicate handlers on repeated calls
|
|
49
|
+
if logger.handlers:
|
|
50
|
+
logger.log_path = getattr(logger, 'log_path', None)
|
|
51
|
+
return logger
|
|
52
|
+
|
|
53
|
+
logger.setLevel(logging.DEBUG) # let handlers decide what to pass
|
|
54
|
+
|
|
55
|
+
formatter = logging.Formatter(fmt, datefmt=datefmt)
|
|
56
|
+
|
|
57
|
+
# ── File handler (always attempted) ──────────────────────────
|
|
58
|
+
p = None
|
|
59
|
+
try:
|
|
60
|
+
if log_path is None:
|
|
61
|
+
ts = datetime.now().strftime('%Y%m%d_%H%M%S')
|
|
62
|
+
p = Path(log_dir) / f'{name}_{ts}.log'
|
|
63
|
+
else:
|
|
64
|
+
p = Path(log_path)
|
|
65
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
66
|
+
|
|
67
|
+
fh = logging.FileHandler(str(p), mode='w', encoding='utf-8')
|
|
68
|
+
fh.setLevel(file_level)
|
|
69
|
+
fh.setFormatter(formatter)
|
|
70
|
+
logger.addHandler(fh)
|
|
71
|
+
|
|
72
|
+
except Exception as exc:
|
|
73
|
+
# File logging unavailable (bad path, permissions, read-only fs, …)
|
|
74
|
+
# Add a fallback StreamHandler only if verbose hasn't already arranged one.
|
|
75
|
+
p = None
|
|
76
|
+
if not verbose:
|
|
77
|
+
verbose = True # let the normal console block below handle it
|
|
78
|
+
ch_fallback = logging.StreamHandler()
|
|
79
|
+
ch_fallback.setLevel(file_level)
|
|
80
|
+
ch_fallback.setFormatter(formatter)
|
|
81
|
+
logger.addHandler(ch_fallback)
|
|
82
|
+
logger.warning(
|
|
83
|
+
f'File logging unavailable ({exc}); falling back to console.'
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# ── Console handler (when verbose or after fallback) ─────────
|
|
87
|
+
if verbose:
|
|
88
|
+
ch = logging.StreamHandler()
|
|
89
|
+
ch.setLevel(console_level if console_level is not None else logging.DEBUG)
|
|
90
|
+
ch.setFormatter(formatter)
|
|
91
|
+
logger.addHandler(ch)
|
|
92
|
+
|
|
93
|
+
# Stash path on the logger for callers to reference (None if fallback)
|
|
94
|
+
logger.log_path = p
|
|
95
|
+
if p is not None:
|
|
96
|
+
logger.info(f'Log file: {p}')
|
|
97
|
+
|
|
98
|
+
return logger
|
|
99
|
+
"""
|
|
100
|
+
## EXAMPLE USAGE:
|
|
101
|
+
from shared_helpers import logprint
|
|
102
|
+
|
|
103
|
+
# Basic usage — file only
|
|
104
|
+
log = logprint('my_app', verbose=1)
|
|
105
|
+
log.debug('Starting up')
|
|
106
|
+
log.info('Processing data')
|
|
107
|
+
log.warning('Disk usage high')
|
|
108
|
+
log.error('Failed to connect')
|
|
109
|
+
|
|
110
|
+
# Verbose — also prints to console
|
|
111
|
+
log = logprint('my_app', verbose=True)
|
|
112
|
+
log.info('You will see this in terminal too')
|
|
113
|
+
|
|
114
|
+
# Custom log directory
|
|
115
|
+
log = logprint('my_app', log_dir='/var/log/myproject', verbose=True)
|
|
116
|
+
|
|
117
|
+
# Explicit path
|
|
118
|
+
log = logprint('my_app', log_path='/tmp/my_app_debug.log')
|
|
119
|
+
|
|
120
|
+
# Quieter console (only warnings+), but full debug to file
|
|
121
|
+
log = logprint(
|
|
122
|
+
'my_app',
|
|
123
|
+
verbose=True,
|
|
124
|
+
console_level=logging.WARNING,
|
|
125
|
+
file_level=logging.DEBUG,
|
|
126
|
+
)
|
|
127
|
+
log.debug('Goes to file only')
|
|
128
|
+
log.warning('Goes to both file and console')
|
|
129
|
+
|
|
130
|
+
# Access the log file path
|
|
131
|
+
log = logprint('pipeline', log_dir='/tmp/logs')
|
|
132
|
+
print(f'Logging to: {log.log_path}') """
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
def folder_structure_tree(path=Path("."), prefix=""):
|
|
4
|
+
r"""
|
|
5
|
+
#usage example:
|
|
6
|
+
location_to_map=Path(r"C:\Users\USER\Desktop")
|
|
7
|
+
print(location_to_map.resolve())
|
|
8
|
+
folder_structure_tree(location_to_map)
|
|
9
|
+
"""
|
|
10
|
+
entries = sorted(path.iterdir(), key=lambda e: (e.is_file(), e.name))
|
|
11
|
+
for i, entry in enumerate(entries):
|
|
12
|
+
connector = "└── " if i == len(entries) - 1 else "├── "
|
|
13
|
+
print(prefix + connector + entry.name)
|
|
14
|
+
if entry.is_dir():
|
|
15
|
+
extension = " " if i == len(entries) - 1 else "│ "
|
|
16
|
+
folder_structure_tree(entry, prefix + extension)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
## =============================================================================
|
|
2
|
+
##
|
|
3
|
+
#
|
|
4
|
+
## Reference:
|
|
5
|
+
## H. M. Lee, "Shear-Joint Capability Versus Bolt Clearance", NASA TM-108378 (1992).
|
|
6
|
+
## PDF: https://ntrs.nasa.gov/api/citations/19930003231/downloads/19930003231.pdf
|
|
7
|
+
## =============================================================================
|
|
8
|
+
"""
|
|
9
|
+
#assumes a single fastener needs to penetrate a single abutment by CL/2 to bring other fasteners in contact with the hole edge. For two plates, penetration is CL. Distribution between plates is a function of contact stiffness.
|
|
10
|
+
****************************************************************************Terms*********************************************************************************************
|
|
11
|
+
| Symbol | Description | Units | Notes / Physical Meaning |
|
|
12
|
+
| ---------------------- | ----------------------------------------------- | ----- | --------------------------------------------------------------------------------------- |
|
|
13
|
+
| D_b | Bolt shank diameter | in | Diameter of the fastener |
|
|
14
|
+
| D_h | Hole diameter in plate | in | D_h = D_b + CL |
|
|
15
|
+
| CL | Clearance | in | Gap between bolt and hole; free play that must be taken up |
|
|
16
|
+
| b | Hertzian contact width | in | Width of contact at the bolt/plate interface |
|
|
17
|
+
| b_i | Initial Hertzian width | in | Computed iteratively from initial trial shear V_i. |
|
|
18
|
+
| b_e | Hertzian width at full embedment | in | Assumed b_e=D_b in paper. Technically should be computed recursively for accuracy. |
|
|
19
|
+
| dy / ΔY | Deformation distance | in | Distance fastener must yield to take up clearance (eq. 4) |
|
|
20
|
+
| dy_e | ΔY at full embed (closing CL so others engage) | in | Distance needed for full embedment to start load sharing with other bolts |
|
|
21
|
+
| E_b | Modulus of elasticity of bolt | psi | Stiffness of the bolt material |
|
|
22
|
+
| v_b | Poisson's ratio of bolt | - | Typically ~0.3 for steel |
|
|
23
|
+
| E_h | Modulus of elasticity of abutment plate | psi | Governs Hertzian compliance (e.g., aluminum) |
|
|
24
|
+
| v_h | Poisson's ratio of abutment plate | - | Typically ~0.33 for aluminum |
|
|
25
|
+
| V_i | Initial trial shear | lbf | Arbitrary starting value to compute initial Hertzian width |
|
|
26
|
+
| V_e | Embedment shear | lbf | Shear to completely embed bolt into abutment (eq. 8) |
|
|
27
|
+
| V_CL_star | Clearance closure shear helper value. | lbf | Shear needed to take up bolt-hole clearance, not accounting for flange thicknesses |
|
|
28
|
+
| V_CL | Clearance closure shear adjusted for two plates | lbf | Shear needed to take up bolt-hole clearance, accounting for flange thickness |
|
|
29
|
+
| V_ult | Ultimate shear of bolt | lbf | Material shear limit of the bolt |
|
|
30
|
+
| bolt_limit_shear | Limit shear in fastener | lbf | Shear load of single fastener prior to accounting for clearance. |
|
|
31
|
+
| joint_limit_shear | Limit shear in fastener | lbf | Shear load of all fasteners (accounting for n) prior to accounting for clearance. |
|
|
32
|
+
| T1 | Thickness of abutment plate 1 | in | Used to scale V_CL for series plates |
|
|
33
|
+
| T2 | Thickness of abutment plate 2 | in | ^ |
|
|
34
|
+
| T_i | Arbitrary dy_e guess for V_CL_star calc | in | Used only in initial Hertz calculation (eq. 6); should not be used in final V_CL calc |
|
|
35
|
+
| n | Number of fasteners | - | Number of bolts in the joint |
|
|
36
|
+
| FOS | Factor of safety | - | Usually 1 in TM examples |
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
##---
|
|
41
|
+
##-Calculations
|
|
42
|
+
##-----
|
|
43
|
+
import math
|
|
44
|
+
|
|
45
|
+
#Material properties #E (lb/in^2), Poissons, F_su (psi).
|
|
46
|
+
steel_from_paper = [30.0e6, 0.30, 95e3]
|
|
47
|
+
aluminum_from_paper = [10.0e6, 0.33, 51e3] #F_SU for AL was never given.
|
|
48
|
+
|
|
49
|
+
MP35N_from_paper = [34.0e6, 0.34, 145e3]
|
|
50
|
+
metal_4130_from_paper = [30.0e6, 0.30, 0] #Guess? poorly documented in paper.
|
|
51
|
+
|
|
52
|
+
Inco_steel_AMS5662 = [29.4e6, 0.29, 125e3]
|
|
53
|
+
A286_steel_AMS5737 = [29.1e6, 0.31, 95e3]
|
|
54
|
+
titanium_AMS4928 = [16.9e6, 0.31, 95e3]
|
|
55
|
+
|
|
56
|
+
class_8_fastener = [30e6, 0.31, 85e3]
|
|
57
|
+
steel_A572_G50 = [30e6, 0.31, 50e3]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def NASA_TM_108378_fitting_factor (input_matrix): #input={D_b, CL, n, FOS, bolt_material, f1_mat, f2_mat, f1_thick, f2_thick, bolt_limit_shear}
|
|
61
|
+
"""
|
|
62
|
+
Programmatic implementation of NASA TM-108378 (https://ntrs.nasa.gov/api/citations/19930003231/downloads/19930003231.pdf). Validated output against NASA_TM_108378 table 5. Returns a knockdown for fitting factor due to hole clearance.
|
|
63
|
+
Warning: This calculator should only be used for assessing the strength of unshimmed bolted joints, with threads not in the shear plane. This calculator only assesses the increased shear load in the bolt, and does not assess flange health, tensile loading, or any other factors. If stacking more than two flanges, it is conservative to define a material with the maximum Poissons and maximum Youngs modulus in the stackup to define bounding properties. The thickness of that composite flange should be input as the sum of the constituent thicknesses.
|
|
64
|
+
Material input matrices are formatted as: [E, Poissons, F_su]. Inputs require consistent base units.
|
|
65
|
+
|
|
66
|
+
Example case:
|
|
67
|
+
|
|
68
|
+
input_matrix_validation2= { # Appendix D validation.
|
|
69
|
+
"D_b" : 0.375, # Units: Inches | LMC fastener diameter.
|
|
70
|
+
"CL" : 0.016, # Units: Inches | CL=D_h-D_b (diameter of hole ho minus diameter of bolt). Larger values of CL are conservative.
|
|
71
|
+
"n" : 4, # Units: Qty | Number of fasteners.
|
|
72
|
+
"FOS" : 1, # Usually = 1
|
|
73
|
+
"bolt_material" : [34.0e6, 0.34, 145e3], # See material names at top of sheet. Verify material spec aligns with your use.
|
|
74
|
+
"f1_mat" : [30.0e6, 0.30, 0], # ^
|
|
75
|
+
"f2_mat" : [30.0e6, 0.30, 0], # ^
|
|
76
|
+
"f1_thick" : 0.4, # Units: Inches | MMC thickness.
|
|
77
|
+
"f2_thick" : 0.375, # ^
|
|
78
|
+
"bolt_limit_shear" : 16014 # Units: lbf | Max nominal shear loading for a single fastener, accounting for peaking, do not enter fastener strength.
|
|
79
|
+
}
|
|
80
|
+
Output_clearanced_fitting_factor=NASA_TM_108378_fitting_factor(input_matrix_validation2)
|
|
81
|
+
|
|
82
|
+
"""
|
|
83
|
+
#--
|
|
84
|
+
## Inputs and trivial identities.
|
|
85
|
+
D_b = input_matrix["D_b"]
|
|
86
|
+
CL = input_matrix["CL"] #maximum distance the bolt can be from an edge of the hole.
|
|
87
|
+
D_h = D_b + CL #hole diameter
|
|
88
|
+
n = input_matrix["n"] #number of fasteners, more fasteners is a greater knockdown but log-ish impact.
|
|
89
|
+
FOS = input_matrix["FOS"]
|
|
90
|
+
bolt_material = input_matrix["bolt_material"]
|
|
91
|
+
F_su = bolt_material[2] #units psi, usually 60% of minimum tensile strength.
|
|
92
|
+
E_b = bolt_material[0]; poissons_b=bolt_material[1]
|
|
93
|
+
V_ult = 0.25 * (math.pi) * F_su * D_b**2
|
|
94
|
+
#--
|
|
95
|
+
## Flange properties.
|
|
96
|
+
f1_mat = input_matrix["f1_mat"]; f2_mat = input_matrix["f2_mat"]
|
|
97
|
+
T1 = input_matrix["f1_thick"]; T2 = input_matrix["f2_thick"]
|
|
98
|
+
E_h = max(f1_mat[0], f2_mat[0])
|
|
99
|
+
poissons_h = max(f1_mat[1], f2_mat[1])
|
|
100
|
+
#--
|
|
101
|
+
## Fastener properties.
|
|
102
|
+
try:
|
|
103
|
+
bolt_limit_shear=input_matrix["bolt_limit_shear"]
|
|
104
|
+
except: #unconservative assumption, useful when comparing results to paper.
|
|
105
|
+
bolt_limit_shear=V_ult
|
|
106
|
+
print('Assuming limit_shear=V_ult')
|
|
107
|
+
joint_limit_shear = n*bolt_limit_shear
|
|
108
|
+
|
|
109
|
+
#--
|
|
110
|
+
"""
|
|
111
|
+
note to self: looks like the paper used V_i/T in places that asked for V_i, and did not have T_i in the b_i equation.
|
|
112
|
+
Y_i is calculated the same as the paper, and sigma_e_max=0.798*sqrt(AG35/(Dh*Db/CL)/CE) where CE=(1-poissons_b**2)/E_b+(1-poissons_h**2)/E_h). This approach allows the V_CL* they calculate to represent shear force per unit length, which they can then adjust for T1 and T2. For the same inputs as Testcase2, the calc gives 1.163 for clearanced fitting factor and 18624 on adjusted load on fastener, and ultimate joint capability=53623, and original limit shear=64059 (through joint, n*single bolt limit). The limit shear is only used in the logic checks and factors calcs. Factors are calculated against joint limit shear, not fastener limit shear.
|
|
113
|
+
"""
|
|
114
|
+
## Arbitrary initial conditions for equations
|
|
115
|
+
V_i = 100 #arbitrary initial shear force to find initial deformation, will be used to compute V_e later. Changing this doesn't impact the final result.
|
|
116
|
+
T_i = max(T1,T2) #arbitrary initial thickness.
|
|
117
|
+
#--
|
|
118
|
+
## Main relevant equations from NASA TM-108378
|
|
119
|
+
def eq_4(b): #distance fastener has to yield to take up CL so other fasteners start to share loading, eq4.
|
|
120
|
+
dy = 0.5*((D_h**2-b**2)**(0.5)-(D_b**2-b**2)**(0.5)-CL)
|
|
121
|
+
return dy
|
|
122
|
+
def eq_6(V, T_i): #width of hertzian contact defined by hertzian equation, eq6.
|
|
123
|
+
b = 1.6*(((V*D_h*D_b)/(T_i*CL))*((1-poissons_b**2)/E_b+(1-poissons_h**2)/E_h))**(0.5)
|
|
124
|
+
return b
|
|
125
|
+
def eq_8(V_i, b_i): #shear to completely embed the bolt shank diameter in the AL abutment. Eq8.
|
|
126
|
+
V_e = V_i*(D_b/b_i)**2
|
|
127
|
+
return V_e
|
|
128
|
+
#--
|
|
129
|
+
## Actually solving the problem
|
|
130
|
+
b_i = eq_6(V_i, T_i) #width of initial hertzian contact.
|
|
131
|
+
dy_i = eq_4(b_i) #distance fastener has to yield to take up CL, eq4.
|
|
132
|
+
V_e = eq_8(V_i, b_i) #shear to completely embed the bolt shank diameter in the AL abutment. Eq8.
|
|
133
|
+
b_e = D_b #eq_6(V_e) #width of hertzian contact defined by hertzian equation, eq6. B_e as using V_embedded as input.
|
|
134
|
+
dy_e = eq_4(b_e) #distance fastener has to yield to take up CL, eq4.
|
|
135
|
+
V_CL_star = V_e * CL / (2 * dy_e) #last equation from figure 4. shear such that the initial Hertzian width leads to exactly the deformation needed to close the gap. Should be solved iteratively to avoid impacting the value of V_CL
|
|
136
|
+
V_CL = (V_CL_star / T_i) * (T1 * T2) / (T1 + T2) #equation from below figure 6. Paper poorly presents this equation, ignores T_i. It represents the force needed to close the gap. Applies if there are two abutment plates.
|
|
137
|
+
|
|
138
|
+
#--
|
|
139
|
+
## Debugging print statements:
|
|
140
|
+
for name, val in [("V_ult", V_ult),
|
|
141
|
+
#("b_i", b_i), ("dy_i", dy_i),("V_e", V_e), ("V_CL_star", V_CL_star), #arbitrary values given T_i and V_i
|
|
142
|
+
("dy_e", dy_e), ("V_CL", V_CL)]:
|
|
143
|
+
print(f"{name}: {val:.7f}", end="\n")
|
|
144
|
+
print() # final newline
|
|
145
|
+
#--
|
|
146
|
+
## Calculating Clearanced_fitting_factor
|
|
147
|
+
if joint_limit_shear<=V_CL:
|
|
148
|
+
Adjusted_load_on_fastener=joint_limit_shear #one fastener takes all the load as the shear doesn't close the gap
|
|
149
|
+
else:
|
|
150
|
+
Adjusted_load_on_fastener=V_CL+(joint_limit_shear-V_CL)/n #shear closes the gap, afterwards all load is shared evenly between the fasteners.
|
|
151
|
+
|
|
152
|
+
#Capability_perc1 = 1 - ((n-1)*FOS*V_CL)/(n * V_ult) #joint capability relative to no clearance design, found on P16. Lines up with appendix B.
|
|
153
|
+
#pei=-1.2695*10**9*CL**3+9.5361*10**7*CL**2+4.9919*10**5*CL-146.7 #appendix A
|
|
154
|
+
#Capability_perc2=1/(1-pei*((n-1)*FOS*T1*T2*D_b**2/((T1+T2)*n*V_ult))) #not giving me the correct answer for appendix B, eben when I get the right answer for V_CL
|
|
155
|
+
|
|
156
|
+
#--
|
|
157
|
+
## Logic checks and final print statements.
|
|
158
|
+
if bolt_limit_shear>V_ult: #errors if there is an input error and does not print any calculated values.
|
|
159
|
+
print("ERROR in inputs: bolt_limit_shear is greater than V_ult. \n bolt_limit_shear = ", bolt_limit_shear, "\n V_ult = ", V_ult)
|
|
160
|
+
else:
|
|
161
|
+
if Adjusted_load_on_fastener>V_ult/FOS:
|
|
162
|
+
print("Fastener potentially overloads (accounting for FOS provided). Adjusted_load_on_fastener > V_ult \n Adjusted_load_on_fastener = ", Adjusted_load_on_fastener, "\n V_ult = ", V_ult)
|
|
163
|
+
#--
|
|
164
|
+
if joint_limit_shear<=V_CL:
|
|
165
|
+
print("Clearanced fastener takes the whole load because joint_limit_shear < V_CL")
|
|
166
|
+
else:
|
|
167
|
+
print("Joint will engage all fasteners because joint_limit_shear > V_CL")
|
|
168
|
+
if V_ult/FOS<=V_CL: #we do not close the gap prior to reaching ult, so other fasteners never share the load.
|
|
169
|
+
Adjusted_joint_capability=V_ult/FOS
|
|
170
|
+
print("All load potentially goes through a single fastener, gap is not closed")
|
|
171
|
+
else:
|
|
172
|
+
Adjusted_joint_capability=(n*V_ult/FOS)-((n-1)*V_CL) #eq 12
|
|
173
|
+
print("All load potentially goes through a single fastener, gap is not closed")
|
|
174
|
+
rel_adjusted_joint_capability=Adjusted_joint_capability/(n*V_ult/FOS)
|
|
175
|
+
|
|
176
|
+
Clearanced_fitting_factor=Adjusted_load_on_fastener/(bolt_limit_shear) #does not account for all fitting factor, multiply this by your other fitting factor contributions.
|
|
177
|
+
|
|
178
|
+
#--
|
|
179
|
+
#if inputs are good, prints adjusted shear values:
|
|
180
|
+
print(f"Adjusted shear load on fastener: {Adjusted_load_on_fastener:.0f}")
|
|
181
|
+
print(f"Adjusted_joint_capability : {Adjusted_joint_capability:.0f}")
|
|
182
|
+
print(f"Joint capability relative to no clearance design: {rel_adjusted_joint_capability:.3f}")
|
|
183
|
+
print(f"Clearanced fitting factor (No FOS applied): {Clearanced_fitting_factor:.3f}")
|
|
184
|
+
|
|
185
|
+
return Clearanced_fitting_factor
|
|
186
|
+
#----------------------------------------------------------------------------
|
|
187
|
+
#### USER INPUTS->
|
|
188
|
+
#----------------------------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
"""
|
|
191
|
+
Program function: Programmatic implementation of NASA TM - 108378 (https://ntrs.nasa.gov/api/citations/19930003231/downloads/19930003231.pdf). Validated output against NASA_TM_108378 table 5. Returns a knockdown for fitting factor due to hole clearance.
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
Warning: This calculator should only be used for assessing the strength of unshimmed bolted joints, with threads not in the shear plane. This calculator only assesses the increased shear load in the bolt, and does not assess flange health, tensile loading, among other factors. If stacking more than two flanges, define a new material near the top of this script with the maximum poissons and maximum Youngs modulus in the stackup. The thickness of that composite flange should be input as the sum of the constituent thicknesses.
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
input_matrix_validation1= { # Table 5 validation.
|
|
198
|
+
"D_b" : 0.196, # Units: Inches | LMC fastener diameter.
|
|
199
|
+
"CL" : 0.02, # Units: Inches | CL=D_h-D_b (diameter of hole ho minus diameter of bolt). Larger values of CL are conservative.
|
|
200
|
+
"n" : 2, # Units: Qty | Number of fasteners.
|
|
201
|
+
"FOS" : 1, # Usually = 1
|
|
202
|
+
"bolt_material" : steel_from_paper, # See material names at top of sheet. Verify material spec aligns with your use.
|
|
203
|
+
"f1_mat" : aluminum_from_paper, # ^
|
|
204
|
+
"f2_mat" : aluminum_from_paper, # ^
|
|
205
|
+
"f1_thick" : 0.1, # Units: Inches | MMC thickness.
|
|
206
|
+
"f2_thick" : 0.1, # ^
|
|
207
|
+
"bolt_limit_shear" : 2100 # Units: lbf | Max nominal shear loading for a single fastener, accounting for peaking, do not enter fastener strength.
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
Output_clearanced_fitting_factor=NASA_TM_108378_fitting_factor(input_matrix_validation1)
|
|
211
|
+
|
|
212
|
+
input_matrix_validation2= { # Appendix D validation.
|
|
213
|
+
"D_b" : 0.375, # Units: Inches | LMC fastener diameter.
|
|
214
|
+
"CL" : 0.016, # Units: Inches | CL=D_h-D_b (diameter of hole ho minus diameter of bolt). Larger values of CL are conservative.
|
|
215
|
+
"n" : 4, # Units: Qty | Number of fasteners.
|
|
216
|
+
"FOS" : 1, # Usually = 1
|
|
217
|
+
"bolt_material" : MP35N_from_paper, # See material names at top of sheet. Verify material spec aligns with your use.
|
|
218
|
+
"f1_mat" : metal_4130_from_paper, # ^
|
|
219
|
+
"f2_mat" : metal_4130_from_paper, # ^
|
|
220
|
+
"f1_thick" : 0.4, # Units: Inches | MMC thickness.
|
|
221
|
+
"f2_thick" : 0.375, # ^
|
|
222
|
+
"bolt_limit_shear" : 16014 # Units: lbf | Max nominal shear loading for a single fastener, accounting for peaking, do not enter fastener strength.
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
Output_clearanced_fitting_factor=NASA_TM_108378_fitting_factor(input_matrix_validation2)
|
|
226
|
+
# To increase Conservatism, choose:
|
|
227
|
+
# min(D_b, bolt_limit_shear, bolt_material[2])
|
|
228
|
+
# max(n, CL, FOS, f1_thick, f2_thick, f2_mat[0:1], f2_mat[0:1], bolt_material[0:1])
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#this file controls the "API level imports"
|
|
2
|
+
#The double dot represents one level up in the folder hierarchy.
|
|
3
|
+
#The single dot represents the current package or directory.
|
|
4
|
+
from .bolt_pattern_elastic_method import (
|
|
5
|
+
Bolt,
|
|
6
|
+
AppliedLoad,
|
|
7
|
+
BoltResult,
|
|
8
|
+
BoltPatternAnalysis,
|
|
9
|
+
bolt_pattern_force_distribution,
|
|
10
|
+
plot_bolt_pattern_3d,
|
|
11
|
+
print_results,
|
|
12
|
+
)
|
|
13
|
+
from .margin_table import add_row, print_table
|
|
14
|
+
from .shared_helpers import von_mises
|
|
15
|
+
from .NASA_TM_108378_fitting_factor import NASA_TM_108378_fitting_factor
|
|
16
|
+
|
|
17
|
+
|