PyCBA 0.4.0__tar.gz → 0.4.2__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyCBA
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: Python Continuous Beam Analysis
5
5
  Author-email: Colin Caprani <colin.caprani@monash.edu>
6
6
  License: Apache 2.0
@@ -49,3 +49,4 @@ One of the main functions of `PyCBA` is that the basic analysis engine forms the
49
49
 
50
50
  - Influence line generation
51
51
  - Moving load analysis for bridges, targeted at bridge access assessments
52
+ - Load patterning and enveloping
@@ -14,3 +14,4 @@ One of the main functions of `PyCBA` is that the basic analysis engine forms the
14
14
 
15
15
  - Influence line generation
16
16
  - Moving load analysis for bridges, targeted at bridge access assessments
17
+ - Load patterning and enveloping
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyCBA
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: Python Continuous Beam Analysis
5
5
  Author-email: Colin Caprani <colin.caprani@monash.edu>
6
6
  License: Apache 2.0
@@ -49,3 +49,4 @@ One of the main functions of `PyCBA` is that the basic analysis engine forms the
49
49
 
50
50
  - Influence line generation
51
51
  - Moving load analysis for bridges, targeted at bridge access assessments
52
+ - Load patterning and enveloping
@@ -2,7 +2,7 @@
2
2
  PyCBA - Continuous Beam Analysis in Python
3
3
  """
4
4
 
5
- __version__ = "0.4.0"
5
+ __version__ = "0.4.2"
6
6
 
7
7
  from .analysis import *
8
8
  from .beam import *
@@ -219,6 +219,18 @@ class Beam:
219
219
  The number of restraints in the beam
220
220
  """
221
221
  return len(self._restraints)
222
+
223
+ @property
224
+ def no_fixed_restraints(self):
225
+ """
226
+ Returns the number of fixed restraints of the beam (fully-supported DOFs)
227
+
228
+ Returns
229
+ -------
230
+ no_fixed_restraints : int
231
+ The number of fixed restraints in the beam
232
+ """
233
+ return len(np.where(np.array(self._restraints)==-1)[0])
222
234
 
223
235
  @property
224
236
  def length(self):
@@ -121,18 +121,41 @@ class InfluenceLines:
121
121
  x = self.vResults[0].results.x
122
122
  dx = x[2] - x[1]
123
123
  idx = np.where(np.abs(x - poi) <= dx * 1e-6)[0][0]
124
- # find the nearest support to the poi
125
- idxr = (
126
- np.abs(np.cumsum(np.insert(self.ba.beam.mbr_lengths, 0, 0)) - poi)
127
- ).argmin()
124
+ #idx = np.abs(x - poi).argmin()
125
+
128
126
  npts = len(self.vResults)
129
127
  eta = np.zeros(npts)
128
+
129
+ #
130
+ # Getting the correct vertical reaction is tricky
131
+ # Should be relatively easy to extend to get moment reactions too.
132
+ #
133
+ # Get vector of the node locations
134
+ node_locations = np.cumsum(np.insert(self.ba.beam.mbr_lengths, 0, 0))
135
+ # The indices of the supported vertical DOFs wrt the node locations vector
136
+ vert_sup_dof_idx = np.where(np.array(self.ba._beam.restraints)[::2]==-1)[0]
137
+ # The locations then of these vertical supports
138
+ vert_sup_locs = node_locations[vert_sup_dof_idx]
139
+ # The index of the closest vertical support
140
+ closest_vert_sup_idx = np.abs(vert_sup_locs-poi).argmin()
141
+ # And its value
142
+ closest_vert_sup = vert_sup_locs[closest_vert_sup_idx]
143
+ # And now the indixe of this support in the node locations vector
144
+ node_idx = np.where(node_locations==closest_vert_sup)[0][0]
145
+ # And hence its index in the overall DOFs vector
146
+ dof_idx = 2*node_idx
147
+
148
+ # Now we must link the supported DOF to the index in the BeamAnalysis reactions vector
149
+ idx_mask = np.zeros_like(self.ba._beam.restraints)
150
+ idx_mask[np.where(np.array(self.ba._beam.restraints)==-1)] = np.arange(self.ba.beam.no_fixed_restraints)
151
+ # And finally the index of the vertical support nearest the POI in the reactions vector
152
+ vert_sup_idx = idx_mask[dof_idx]
130
153
 
131
154
  for i, res in enumerate(self.vResults):
132
155
  if load_effect == "V":
133
156
  eta[i] = res.results.V[idx]
134
157
  elif load_effect == "R":
135
- eta[i] = res.R[idxr]
158
+ eta[i] = res.R[vert_sup_idx]
136
159
  else:
137
160
  eta[i] = res.results.M[idx]
138
161
 
@@ -799,7 +799,7 @@ def parse_LM(LM: LoadMatrix) -> List[Load]:
799
799
  return loads
800
800
 
801
801
 
802
- def add_LM(LM1: LoadMatrix, LM2: LoadMatrix):
802
+ def add_LM(LM1: LoadMatrix, LM2: LoadMatrix) -> LoadMatrix:
803
803
  """
804
804
  Adds two load matrices and returns the sum; this enables superposition
805
805
 
@@ -824,3 +824,35 @@ def add_LM(LM1: LoadMatrix, LM2: LoadMatrix):
824
824
  LM.append(load)
825
825
 
826
826
  return LM
827
+
828
+
829
+ def factor_LM(LM: LoadMatrix, gamma: float) -> LoadMatrix:
830
+ """
831
+ Applies a factor to the loads in a `LoadMatrix` object
832
+
833
+ Parameters
834
+ ----------
835
+ LM : LoadMatrix
836
+ The `LoadMatrix` object
837
+
838
+ gamma : float
839
+ A factor to apply to the load magnitudes
840
+
841
+ Returns
842
+ -------
843
+ LM : LoadMatrix
844
+ The factored `LoadMatrix` object
845
+ """
846
+ LMnew = []
847
+ for load in LM:
848
+ i_span = load[0]
849
+ l_type = load[1]
850
+ mag = gamma * load[2]
851
+ if l_type == 1: # UDL
852
+ LMnew.append([i_span, l_type, mag])
853
+ elif l_type == 2 or l_type == 4: # PL or ML
854
+ LMnew.append([i_span, l_type, mag, load[3]])
855
+ else: # PUDL
856
+ LMnew.append([i_span, l_type, mag, load[3], load[4]])
857
+
858
+ return LMnew
@@ -371,7 +371,7 @@ class Envelopes:
371
371
  raise ValueError("No results to display")
372
372
 
373
373
  L = self.x[-1]
374
-
374
+
375
375
  fig, axs = plt.subplots(2, 1, sharex=True, **kwargs)
376
376
 
377
377
  ax = axs[0]
@@ -389,7 +389,7 @@ class Envelopes:
389
389
  ax.grid()
390
390
  ax.set_ylabel("Shear Force (kN)")
391
391
  ax.set_xlabel("Distance along beam (m)")
392
-
392
+
393
393
  if each:
394
394
  for res in self.vResults:
395
395
  axs[0].plot(self.x, res.results.M, "r", lw=0.5)
@@ -227,36 +227,41 @@ def test_moment_load():
227
227
  d = beam_analysis.beam_results.D[[0, 2]]
228
228
  assert d == pytest.approx([0.0, 0.0])
229
229
 
230
+
230
231
  def test_envelopes():
231
- L = [6,4,6]
232
+ L = [6, 4, 6]
232
233
  EI = 30 * 10e9 * 1e-6
233
- R = [-1,0,-1,0,-1,0,-1,0]
234
+ R = [-1, 0, -1, 0, -1, 0, -1, 0]
234
235
  beam_analysis = cba.BeamAnalysis(L, EI, R)
235
-
236
- LMg = [[1,1,25,0,0],
237
- [2,1,25,0,0],
238
- [3,1,25,0,0]]
236
+
237
+ LMg = [[1, 1, 25, 0, 0], [2, 1, 25, 0, 0], [3, 1, 25, 0, 0]]
239
238
  γg_max = 1.4
240
239
  γg_min = 1.0
241
- LMq = [[1,1,10,0,0],
242
- [2,1,10,0,0],
243
- [3,1,10,0,0]]
240
+ LMq = [[1, 1, 10, 0, 0], [2, 1, 10, 0, 0], [3, 1, 10, 0, 0]]
244
241
  γq_max = 1.6
245
242
  γq_min = 0
246
-
243
+
247
244
  lp = cba.LoadPattern(beam_analysis)
248
- lp.set_dead_loads(LMgg_maxg_min)
249
- lp.set_live_loads(LMqq_maxq_min)
245
+ lp.set_dead_loads(LMg, γg_max, γg_min)
246
+ lp.set_live_loads(LMq, γq_max, γq_min)
250
247
  env = lp.analyze()
251
-
248
+
252
249
  m_locs = np.array([3, 6, 8, 10, 13])
253
250
  idx = [(np.abs(env.x - x)).argmin() for x in m_locs]
254
- assert np.allclose(env.Mmax[idx],np.array([163.79, 0, 11.75, 0, 163.79]),atol=1e-2)
255
- assert np.allclose(env.Mmin[idx],np.array([0, -163.38, -81.42, -163.38, 0]),atol=1e-2)
256
-
251
+ assert np.allclose(
252
+ env.Mmax[idx], np.array([163.79, 0, 11.75, 0, 163.79]), atol=1e-2
253
+ )
254
+ assert np.allclose(
255
+ env.Mmin[idx], np.array([0, -163.38, -81.42, -163.38, 0]), atol=1e-2
256
+ )
257
+
257
258
  n = beam_analysis.beam_results.npts
258
259
  nspans = beam_analysis.beam.no_spans
259
- Vmax = np.array([np.max(env.Vmax[i*(n+3):(i+1)*(n+3)]) for i in range(nspans)])
260
- assert np.allclose(Vmax,np.array([131.1, 123.94, 180.23]),atol=1e-2)
261
- Vmin = np.array([np.min(env.Vmin[i*(n+3):(i+1)*(n+3)]) for i in range(nspans)])
262
- assert np.allclose(Vmin,np.array([-180.23, -123.94, -131.10]),atol=1e-2)
260
+ Vmax = np.array(
261
+ [np.max(env.Vmax[i * (n + 3) : (i + 1) * (n + 3)]) for i in range(nspans)]
262
+ )
263
+ assert np.allclose(Vmax, np.array([131.1, 123.94, 180.23]), atol=1e-2)
264
+ Vmin = np.array(
265
+ [np.min(env.Vmin[i * (n + 3) : (i + 1) * (n + 3)]) for i in range(nspans)]
266
+ )
267
+ assert np.allclose(Vmin, np.array([-180.23, -123.94, -131.10]), atol=1e-2)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes