kib-lap 0.5__cp313-cp313-win_amd64.whl → 0.7.7__cp313-cp313-win_amd64.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.
- KIB_LAP/Betonbau/TEST_Rectangular.py +21 -0
- KIB_LAP/Betonbau/beam_rectangular.py +4 -0
- KIB_LAP/FACHWERKEBEN/Elements.py +209 -0
- KIB_LAP/FACHWERKEBEN/InputData.py +118 -0
- KIB_LAP/FACHWERKEBEN/Iteration.py +967 -0
- KIB_LAP/FACHWERKEBEN/Materials.py +30 -0
- KIB_LAP/FACHWERKEBEN/Plotting.py +681 -0
- KIB_LAP/FACHWERKEBEN/__init__.py +4 -0
- KIB_LAP/FACHWERKEBEN/main.py +27 -0
- KIB_LAP/Plattentragwerke/PlateBendingKirchhoff.py +36 -29
- KIB_LAP/STABRAUM/InputData.py +13 -2
- KIB_LAP/STABRAUM/Output_Data.py +61 -0
- KIB_LAP/STABRAUM/Plotting.py +1453 -0
- KIB_LAP/STABRAUM/Programm.py +518 -1026
- KIB_LAP/STABRAUM/Steifigkeitsmatrix.py +338 -117
- KIB_LAP/STABRAUM/main.py +58 -0
- KIB_LAP/STABRAUM/results.py +37 -0
- KIB_LAP/Scheibe/Assemble_Stiffness.py +246 -0
- KIB_LAP/Scheibe/Element_Stiffness.py +362 -0
- KIB_LAP/Scheibe/Meshing.py +365 -0
- KIB_LAP/Scheibe/Output.py +34 -0
- KIB_LAP/Scheibe/Plotting.py +722 -0
- KIB_LAP/Scheibe/Shell_Calculation.py +523 -0
- KIB_LAP/Scheibe/Testing_Mesh.py +25 -0
- KIB_LAP/Scheibe/__init__.py +14 -0
- KIB_LAP/Scheibe/main.py +33 -0
- KIB_LAP/StabEbenRitz/Biegedrillknicken.py +757 -0
- KIB_LAP/StabEbenRitz/Biegedrillknicken_Trigeometry.py +328 -0
- KIB_LAP/StabEbenRitz/Querschnittswerte.py +527 -0
- KIB_LAP/StabEbenRitz/Stabberechnung_Klasse.py +868 -0
- KIB_LAP/plate_bending_cpp.cp313-win_amd64.pyd +0 -0
- KIB_LAP/plate_buckling_cpp.cp313-win_amd64.pyd +0 -0
- {kib_lap-0.5.dist-info → kib_lap-0.7.7.dist-info}/METADATA +1 -1
- {kib_lap-0.5.dist-info → kib_lap-0.7.7.dist-info}/RECORD +37 -19
- Examples/Cross_Section_Thin.py +0 -61
- KIB_LAP/Betonbau/Bemessung_Zust_II.py +0 -648
- KIB_LAP/Betonbau/Iterative_Design.py +0 -723
- KIB_LAP/Plattentragwerke/NumInte.cpp +0 -23
- KIB_LAP/Plattentragwerke/NumericalIntegration.cpp +0 -23
- KIB_LAP/Plattentragwerke/plate_bending_cpp.cp313-win_amd64.pyd +0 -0
- KIB_LAP/main.py +0 -2
- {Examples → KIB_LAP/StabEbenRitz}/__init__.py +0 -0
- {kib_lap-0.5.dist-info → kib_lap-0.7.7.dist-info}/WHEEL +0 -0
- {kib_lap-0.5.dist-info → kib_lap-0.7.7.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from beam_sub_section import *
|
|
2
|
+
from beam_rectangular import *
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
moment_ed = 1.00
|
|
6
|
+
normal_force_ed = 0
|
|
7
|
+
shear_force_ed = 0.5
|
|
8
|
+
effective_height = 0.55
|
|
9
|
+
effective_height_pressure = 0.05
|
|
10
|
+
elasticity_modulus_steel = 200000
|
|
11
|
+
|
|
12
|
+
Section_1 = BeamSubSection( moment_ed,
|
|
13
|
+
normal_force_ed,
|
|
14
|
+
shear_force_ed,
|
|
15
|
+
effective_height,
|
|
16
|
+
effective_height_pressure,
|
|
17
|
+
elasticity_modulus_steel)
|
|
18
|
+
|
|
19
|
+
BEAM = BeamRectangular(1,1.00,0.60)
|
|
20
|
+
BEAM.calculate_beam_section(Section_1 , 30, 500, 0.296)
|
|
21
|
+
BEAM.calculate_beam_section_without_shearreinforcement(Section_1 , 16.3e-4,30,500)
|
|
@@ -459,6 +459,10 @@ class BeamRectangular:
|
|
|
459
459
|
else:
|
|
460
460
|
print("Minimum reinforcement is dominant!")
|
|
461
461
|
print("Required bending reinforcement: ", np.around(Asmin, 3), "cm²")
|
|
462
|
+
print("CHECK")
|
|
463
|
+
print("Iteration steps: ", num_iter)
|
|
464
|
+
print("Conrete Force ", np.around(Fc_1 + Fc_2 + Fc_3, 3), "MN")
|
|
465
|
+
|
|
462
466
|
reinforcement = [float(Asmin), float(0.0)]
|
|
463
467
|
needed_reinforcement.append(reinforcement)
|
|
464
468
|
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# DEPENDENCIES
|
|
2
|
+
import copy # Allows us to create copies of objects in memory
|
|
3
|
+
import math # Math functionality
|
|
4
|
+
import numpy as np # Numpy for working with arrays
|
|
5
|
+
import matplotlib.pyplot as plt # Plotting functionality
|
|
6
|
+
import matplotlib.colors # For colormap functionality
|
|
7
|
+
import ipywidgets as widgets
|
|
8
|
+
from glob import glob # Allows check that file exists before import
|
|
9
|
+
from numpy import genfromtxt # For importing structure data from csv
|
|
10
|
+
import pandas as pd
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Rope_Elements_III:
|
|
14
|
+
def __init__(self, InputData):
|
|
15
|
+
print("Rope elements")
|
|
16
|
+
self.Inp = InputData
|
|
17
|
+
|
|
18
|
+
def calculateTransMatrix(self, posI, posJ):
|
|
19
|
+
"""
|
|
20
|
+
Takes in the position of node I and J and returns the transformation matrix for the member
|
|
21
|
+
This will to be recalculated as the structure deflects with each iteration
|
|
22
|
+
"""
|
|
23
|
+
T = np.zeros([2, 4])
|
|
24
|
+
ix = posI[0] # x-coord for node i
|
|
25
|
+
iy = posI[1] # y-coord for node i
|
|
26
|
+
jx = posJ[0] # x-coord for node j
|
|
27
|
+
jy = posJ[1] # y-coord for node j
|
|
28
|
+
|
|
29
|
+
dx = jx - ix # x-component of vector along member
|
|
30
|
+
dy = jy - iy # y-component of vector along member
|
|
31
|
+
length = math.sqrt(dx**2 + dy**2) # Magnitude of vector (length of member)
|
|
32
|
+
|
|
33
|
+
lp = dx / length
|
|
34
|
+
mp = dy / length
|
|
35
|
+
lq = -mp
|
|
36
|
+
mq = lp
|
|
37
|
+
|
|
38
|
+
T = np.array([[-lp, -mp, lp, mp], [-lq, -mq, lq, mq]])
|
|
39
|
+
|
|
40
|
+
return T
|
|
41
|
+
|
|
42
|
+
def buildElementStiffnessMatrix(self, n, UG, TMs, lengths, P0, E, Areas):
|
|
43
|
+
"""
|
|
44
|
+
Build element stiffness matrix based on current position and axial force
|
|
45
|
+
n = member index
|
|
46
|
+
UG = vector of global cumulative displacements
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
# Calculate 'new' positions of nodes using UG
|
|
50
|
+
node_i = self.Inp.members[n][0] # Node number for node i of this member
|
|
51
|
+
node_j = self.Inp.members[n][1] # Node number for node j of this member
|
|
52
|
+
|
|
53
|
+
# Index of DoF for this member
|
|
54
|
+
ia = 2 * node_i - 2 # horizontal DoF at node i of this member
|
|
55
|
+
ib = 2 * node_i - 1 # vertical DoF at node i of this member
|
|
56
|
+
ja = 2 * node_j - 2 # horizontal DoF at node j of this member
|
|
57
|
+
jb = 2 * node_j - 1 # vertical DoF at node j of this member
|
|
58
|
+
|
|
59
|
+
# Displacements
|
|
60
|
+
d_ix = UG[ia, 0]
|
|
61
|
+
d_iy = UG[ib, 0]
|
|
62
|
+
d_jx = UG[ja, 0]
|
|
63
|
+
d_jy = UG[jb, 0]
|
|
64
|
+
|
|
65
|
+
# Extract current version of transformation matrix [T]
|
|
66
|
+
TM = TMs[n, :, :]
|
|
67
|
+
|
|
68
|
+
# Calculate local displacements [u, v, w] using global cumulative displacements UG
|
|
69
|
+
localDisp = np.matmul(TM, np.array([[d_ix, d_iy, d_jx, d_jy]]).T)
|
|
70
|
+
u = localDisp[0].item()
|
|
71
|
+
v = localDisp[1].item()
|
|
72
|
+
|
|
73
|
+
# Calculate extension, e
|
|
74
|
+
Lo = lengths[n]
|
|
75
|
+
e = math.sqrt((Lo + u) ** 2 + v**2) - Lo
|
|
76
|
+
|
|
77
|
+
# Calculate matrix [AA]
|
|
78
|
+
a1 = (Lo + u) / (Lo + e)
|
|
79
|
+
a2 = v / (Lo + e)
|
|
80
|
+
AA = np.array([[a1, a2]])
|
|
81
|
+
|
|
82
|
+
# Calculate axial load, P
|
|
83
|
+
|
|
84
|
+
P = P0[n] + (E[n] * Areas[n] / Lo) * e
|
|
85
|
+
|
|
86
|
+
# Calculate matrix [d]
|
|
87
|
+
d11 = P * v**2
|
|
88
|
+
d12 = -P * v * (Lo + u)
|
|
89
|
+
d21 = -P * v * (Lo + u)
|
|
90
|
+
d22 = P * (Lo + u) ** 2
|
|
91
|
+
denominator = (Lo + e) ** 3
|
|
92
|
+
|
|
93
|
+
d = (1 / denominator) * np.array([[d11, d12], [d21, d22]])
|
|
94
|
+
|
|
95
|
+
# Calculate element stiffness matrix
|
|
96
|
+
|
|
97
|
+
NL = np.matrix((AA.T * (E[n] * Areas[n] / Lo) * AA) + d)
|
|
98
|
+
k = TM.T * NL * TM
|
|
99
|
+
|
|
100
|
+
# Return element stiffness matrix in quadrants
|
|
101
|
+
K11 = k[0:2, 0:2]
|
|
102
|
+
K12 = k[0:2, 2:4]
|
|
103
|
+
K21 = k[2:4, 0:2]
|
|
104
|
+
K22 = k[2:4, 2:4]
|
|
105
|
+
|
|
106
|
+
return [K11, K12, K21, K22]
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
import numpy as np
|
|
110
|
+
import math
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class BarElements_I:
|
|
114
|
+
"""
|
|
115
|
+
2D Bar/Truss element (Theorie I. Ordnung, small displacement).
|
|
116
|
+
2 DOF per node: ux, uy
|
|
117
|
+
|
|
118
|
+
- Uses UNDEFORMED geometry for transformation and stiffness (linear).
|
|
119
|
+
- Optional initial axial force P0 can be included in member force reporting,
|
|
120
|
+
but is NOT used as geometric stiffness here (Theorie I. Ordnung).
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
def __init__(self, InputData):
|
|
124
|
+
self.Inp = InputData
|
|
125
|
+
|
|
126
|
+
# Precompute direction cosines + lengths from undeformed geometry (constant)
|
|
127
|
+
self.L0 = np.zeros(len(self.Inp.members), dtype=float)
|
|
128
|
+
self.c = np.zeros(len(self.Inp.members), dtype=float)
|
|
129
|
+
self.s = np.zeros(len(self.Inp.members), dtype=float)
|
|
130
|
+
|
|
131
|
+
for n, (ni, nj) in enumerate(self.Inp.members):
|
|
132
|
+
ix, iy = self.Inp.nodes[ni - 1, 0], self.Inp.nodes[ni - 1, 1]
|
|
133
|
+
jx, jy = self.Inp.nodes[nj - 1, 0], self.Inp.nodes[nj - 1, 1]
|
|
134
|
+
dx, dy = (jx - ix), (jy - iy)
|
|
135
|
+
L = math.sqrt(dx * dx + dy * dy)
|
|
136
|
+
if L == 0.0:
|
|
137
|
+
raise ValueError(f"Bar element has zero length at member index {n} (nodes {ni}-{nj})")
|
|
138
|
+
|
|
139
|
+
self.L0[n] = L
|
|
140
|
+
self.c[n] = dx / L
|
|
141
|
+
self.s[n] = dy / L
|
|
142
|
+
|
|
143
|
+
def buildElementStiffnessMatrix(self, n, UG, TMs_unused, lengths_unused, P0, E, Areas):
|
|
144
|
+
"""
|
|
145
|
+
Returns [K11, K12, K21, K22] (each 2x2) in GLOBAL coordinates.
|
|
146
|
+
"""
|
|
147
|
+
L = self.L0[n]
|
|
148
|
+
EA = E[n] * Areas[n]
|
|
149
|
+
k0 = EA / L
|
|
150
|
+
|
|
151
|
+
c = self.c[n]
|
|
152
|
+
s = self.s[n]
|
|
153
|
+
|
|
154
|
+
# 4x4 global stiffness for 2D truss
|
|
155
|
+
k = k0 * np.array([
|
|
156
|
+
[ c*c, c*s, -c*c, -c*s],
|
|
157
|
+
[ c*s, s*s, -c*s, -s*s],
|
|
158
|
+
[-c*c, -c*s, c*c, c*s],
|
|
159
|
+
[-c*s, -s*s, c*s, s*s]
|
|
160
|
+
], dtype=float)
|
|
161
|
+
|
|
162
|
+
K11 = k[0:2, 0:2]
|
|
163
|
+
K12 = k[0:2, 2:4]
|
|
164
|
+
K21 = k[2:4, 0:2]
|
|
165
|
+
K22 = k[2:4, 2:4]
|
|
166
|
+
return [K11, K12, K21, K22]
|
|
167
|
+
|
|
168
|
+
def axial_force(self, n, UG, E, Areas, P0=None):
|
|
169
|
+
"""
|
|
170
|
+
Member axial force (tension +) from SMALL displacement theory:
|
|
171
|
+
N = (EA/L) * ( [-c -s c s] * u_e )
|
|
172
|
+
Optionally + P0[n] if you want to report pretension as part of N.
|
|
173
|
+
"""
|
|
174
|
+
ni, nj = self.Inp.members[n]
|
|
175
|
+
ia, ib = 2 * ni - 2, 2 * ni - 1
|
|
176
|
+
ja, jb = 2 * nj - 2, 2 * nj - 1
|
|
177
|
+
|
|
178
|
+
ue = np.array([UG[ia, 0], UG[ib, 0], UG[ja, 0], UG[jb, 0]], dtype=float)
|
|
179
|
+
|
|
180
|
+
c = self.c[n]
|
|
181
|
+
s = self.s[n]
|
|
182
|
+
L = self.L0[n]
|
|
183
|
+
EA = E[n] * Areas[n]
|
|
184
|
+
|
|
185
|
+
N = (EA / L) * (-c * ue[0] - s * ue[1] + c * ue[2] + s * ue[3])
|
|
186
|
+
|
|
187
|
+
if P0 is not None:
|
|
188
|
+
N = N + float(P0[n])
|
|
189
|
+
return float(N)
|
|
190
|
+
|
|
191
|
+
def internal_nodal_forces_global(self, n, UG, E, Areas, P0=None):
|
|
192
|
+
"""
|
|
193
|
+
Equivalent internal nodal force vector (4x1) in global coords:
|
|
194
|
+
f_int_e = N * [-c, -s, c, s]^T
|
|
195
|
+
"""
|
|
196
|
+
c = self.c[n]
|
|
197
|
+
s = self.s[n]
|
|
198
|
+
N = self.axial_force(n, UG, E, Areas, P0=P0)
|
|
199
|
+
|
|
200
|
+
f = N * np.array([[-c], [-s], [c], [s]], dtype=float)
|
|
201
|
+
return f
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class Rope_Elements_II:
|
|
206
|
+
def __init__(self):
|
|
207
|
+
print("Rope elements")
|
|
208
|
+
|
|
209
|
+
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# DEPENDENCIES
|
|
2
|
+
import copy # Allows us to create copies of objects in memory
|
|
3
|
+
import math # Math functionality
|
|
4
|
+
import numpy as np # Numpy for working with arrays
|
|
5
|
+
import matplotlib.pyplot as plt # Plotting functionality
|
|
6
|
+
import matplotlib.colors # For colormap functionality
|
|
7
|
+
import ipywidgets as widgets
|
|
8
|
+
from glob import glob # Allows check that file exists before import
|
|
9
|
+
from numpy import genfromtxt # For importing structure data from csv
|
|
10
|
+
import pandas as pd
|
|
11
|
+
|
|
12
|
+
class Input:
|
|
13
|
+
def __init__(self):
|
|
14
|
+
print("Input-Class")
|
|
15
|
+
self.NodalData()
|
|
16
|
+
self.EdgeData()
|
|
17
|
+
self.CableData()
|
|
18
|
+
self.RestraintData()
|
|
19
|
+
self.SpringData()
|
|
20
|
+
self.ForceData()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# =================================START OF DATA IMPORT================================
|
|
24
|
+
def NodalData(self):
|
|
25
|
+
# MANDATORY IMPORT: nodal coordinates
|
|
26
|
+
if glob("data/Vertices.csv"):
|
|
27
|
+
self.nodes = genfromtxt("data/Vertices.csv", delimiter=",")
|
|
28
|
+
print("1. 🟢 Vertices.csv imported")
|
|
29
|
+
else:
|
|
30
|
+
print("1. 🛑 STOP: Vertices.csv not found")
|
|
31
|
+
|
|
32
|
+
def EdgeData(self):
|
|
33
|
+
# MANDATORY IMPORT: member definitions
|
|
34
|
+
if glob("data/Edges.csv"):
|
|
35
|
+
self.members = genfromtxt("data/Edges.csv", delimiter=",")
|
|
36
|
+
self.members = np.int_(self.members)
|
|
37
|
+
self.nDoF = (
|
|
38
|
+
np.amax(self.members) * 2
|
|
39
|
+
) # Total number of degrees of freedom in the problem
|
|
40
|
+
print("2. 🟢 Edges.csv imported")
|
|
41
|
+
else:
|
|
42
|
+
print("2. 🛑 STOP: Edges.csv not found")
|
|
43
|
+
|
|
44
|
+
def RestraintData(self):
|
|
45
|
+
# Prüfen, ob die Datei existiert
|
|
46
|
+
if glob("data/Restraint-Data.csv"):
|
|
47
|
+
# CSV einlesen; da es sich um eine einzelne Spalte handelt, reicht der Standard
|
|
48
|
+
self.restraintData = genfromtxt("data/Restraint-Data.csv")
|
|
49
|
+
# Sicherstellen, dass die Daten mindestens ein 1D-Array sind
|
|
50
|
+
self.restraintData = np.atleast_1d(self.restraintData)
|
|
51
|
+
# In Integer umwandeln (falls als float gelesen)
|
|
52
|
+
self.restraintData = np.int_(self.restraintData)
|
|
53
|
+
# Daten flach machen (bei einer einzelnen Spalte ist das optional)
|
|
54
|
+
flatData = self.restraintData.flatten()
|
|
55
|
+
# 0-Werte entfernen (0 = kein Einspannen)
|
|
56
|
+
self.restrainedDoF = flatData[flatData != 0].tolist()
|
|
57
|
+
# Von den in der CSV angegebenen Freiheitsgraden (beginnend bei 1)
|
|
58
|
+
# zu Python-Index (beginnend bei 0) konvertieren
|
|
59
|
+
self.restrainedIndex = [x - 1 for x in self.restrainedDoF]
|
|
60
|
+
# Unbeschränkte Freiheitsgrade berechnen
|
|
61
|
+
self.freeDoF = np.delete(np.arange(0, self.nDoF), self.restrainedIndex)
|
|
62
|
+
print("3. 🟢 Restraint-Data.csv imported")
|
|
63
|
+
else:
|
|
64
|
+
print("3. 🛑 STOP: Restraint-Data.csv not found")
|
|
65
|
+
|
|
66
|
+
def SpringData(self):
|
|
67
|
+
if glob("data/springs.csv"):
|
|
68
|
+
# Annahme: Die erste Zeile enthält Header
|
|
69
|
+
df = pd.read_csv("data/springs.csv")
|
|
70
|
+
# Numerische Spalten
|
|
71
|
+
numeric_columns = ['no','Node', 'c_const[N/m]']
|
|
72
|
+
df_numeric = df[numeric_columns]
|
|
73
|
+
# Konvertiere das DataFrame zu einem NumPy-Array vom Typ int
|
|
74
|
+
self.springLocationData = df_numeric.to_numpy(dtype=int)
|
|
75
|
+
# Save the spring directions
|
|
76
|
+
self.SpringDirections = df['Dir'].to_numpy()
|
|
77
|
+
print("4. 🟢 springs.csv imported")
|
|
78
|
+
else:
|
|
79
|
+
self.forceLocationData = []
|
|
80
|
+
print("4. ⚠️ springs.csv not found")
|
|
81
|
+
|
|
82
|
+
def ForceData(self):
|
|
83
|
+
# OPTIONAL IMPORT: force location data
|
|
84
|
+
if glob("data/Force-Data.csv"):
|
|
85
|
+
# Annahme: Die erste Zeile enthält Header
|
|
86
|
+
df = pd.read_csv("data/Force-Data.csv")
|
|
87
|
+
|
|
88
|
+
# Wähle nur die numerischen Spalten aus (z.B. 'Node' und 'P[N]')
|
|
89
|
+
numeric_columns = ['Node', 'P[N]']
|
|
90
|
+
df_numeric = df[numeric_columns]
|
|
91
|
+
|
|
92
|
+
# Konvertiere das DataFrame zu einem NumPy-Array vom Typ int
|
|
93
|
+
self.forceLocationData = df_numeric.to_numpy(dtype=int)
|
|
94
|
+
|
|
95
|
+
# Bestimme die Anzahl der Dimensionen des Arrays
|
|
96
|
+
self.nForces = self.forceLocationData.ndim
|
|
97
|
+
|
|
98
|
+
# Falls das Array weniger als 2-dimensional ist, füge eine zusätzliche Dimension hinzu
|
|
99
|
+
if self.nForces < 2:
|
|
100
|
+
self.forceLocationData = np.expand_dims(self.forceLocationData, axis=0)
|
|
101
|
+
|
|
102
|
+
# (Optional) Verarbeite die 'Dir'-Spalte, falls benötigt
|
|
103
|
+
# Beispiel: Speichere die Richtungen separat
|
|
104
|
+
self.forceDirections = df['Dir'].to_numpy()
|
|
105
|
+
|
|
106
|
+
print("4. 🟢 Force-Data.csv imported")
|
|
107
|
+
else:
|
|
108
|
+
self.forceLocationData = []
|
|
109
|
+
print("4. ⚠️ Force-Data.csv not found")
|
|
110
|
+
|
|
111
|
+
def CableData(self):
|
|
112
|
+
#MANDATORY IMPORT: cable definitions
|
|
113
|
+
if glob('data/Cables.csv'):
|
|
114
|
+
self.cables = genfromtxt('data/Cables.csv', delimiter=',')
|
|
115
|
+
print('3. 🟢 Cables.csv imported')
|
|
116
|
+
else:
|
|
117
|
+
self.cables = []
|
|
118
|
+
print('3. 🛑 STOP: Cables.csv not found')
|