b2api
B2000++ API Reference Manual, VERSION 4.6
 
Loading...
Searching...
No Matches
b2beam_cross_sections.H
1//---------------------------------------------------------------------------
2// b2beam_cross_sections.H --
3//
4// Compute pre-defined shape beam section properties
5//
6// Authors: S. Merazzi, templates Th. Ludwig
7//
8// Copyright (c) 2016, 2017, 2023
9// SMR Engineering & Development SA
10// 2502 Bienne, Switzerland
11//
12// All Rights Reserved. Proprietary source code. The contents of
13// this file may not be disclosed to third parties, copied or
14// duplicated in any form, in whole or in part, without the prior
15// written permission of SMR.
16//---------------------------------------------------------------------------
17
18#ifndef _B2_BEAM_CROSS_SECTIONS_
19#define _B2_BEAM_CROSS_SECTIONS_
20
21#include <algorithm>
22#include <cmath>
23#include <iomanip>
24#include <iostream>
25#include <limits>
26#include <string>
27#include <tuple>
28#include <vector>
29
30#include "utils/b2linear_algebra.H"
31#include "utils/b2rtable.H"
32
33namespace {
34
35template <typename T>
36T pow2(const T& v) {
37 return v * v;
38}
39
40template <typename T>
41T pow3(const T& v) {
42 return v * v * v;
43}
44
45template <typename T>
46T pow4(const T& v) {
47 const T vv = v * v;
48 return vv * vv;
49}
50
51} // namespace
52
53namespace b2000 {
54
100// Thin-walled sections: A point of a "thin" line strip.
101template <typename T>
102class Point {
103public:
104 T y; // y-coordinate with respect to (0,0)
105 T z; // z-coordinate with respect to (0,0)
106 T t; // Thickness at point
107 Point(const T& y_, const T& z_, const T& t_) : y(y_), z(z_), t(t_) {}
108 void print(const std::string& s) { std::cout << s << y << " " << z << " " << t << std::endl; };
109};
110
111// // Thin-walled sections: Line strip (contains points).
112template <typename T>
113class LineStrip {
114public:
115 std::vector<Point<T>> points; // Points of line strip
116 std::string connection; // "open", "closed"
117 // add here dict for density etc...
118 LineStrip() { connection = "open"; }
119 LineStrip(const std::string& s) { connection = s; }
120 void append(const Point<T>& p) { points.push_back(p); };
121 void print(void) {
122 int k = 0;
123 std::cout << "LineStrip, n. of points=" << size() << ", connection=" << connection
124 << std::endl;
125 for (auto i : points) {
126 auto s = "Point " + std::to_string(k) + ": ";
127 i.print(s);
128 k++;
129 }
130 };
131 const int size(void) { return (int)points.size(); };
132};
133
134// // Thin-walled sections: LineStrips contains all LineStrip
135template <typename T>
136class LineStrips {
137public:
138 std::vector<LineStrip<T>> linestrips;
139 LineStrips() {} // All LineStrips
140 void append(const LineStrip<T>& ls) { linestrips.push_back(ls); };
141 void print(void) {
142 std::cout << "LineStrips, n. of Line Strips=" << size() << std::endl;
143 for (auto i : linestrips) { i.print(); }
144 };
145 void print(int ind) {
146 std::cout << "LineStrip " << ind << ":" << std::endl;
147 linestrips[ind].print();
148 };
149 const int size(void) { return (int)linestrips.size(); };
150};
151
152template <typename T>
153class BeamCrossSection {
154public:
155 BeamCrossSection()
156 : has(false),
157 swapyz(false),
158 ymin(+std::numeric_limits<T>::max()),
159 ymax(std::numeric_limits<T>::lowest()),
160 zmin(+std::numeric_limits<T>::max()),
161 zmax(std::numeric_limits<T>::lowest()),
162 yc(0),
163 zc(0),
164 ys(0),
165 zs(0),
166 A(0),
167 It(0),
168 Iyy(0),
169 Izz(0),
170 Iyz(0),
171 I1(0),
172 I2(0),
173 K1(1),
174 K2(1),
175 theta(0),
176 Wt(+std::numeric_limits<T>::max()),
177 nseg(10) {}
178
179 const std::string& get_title() const { return title; }
180
181 // void add_line_strip(const LineStrip& s) { segments.push_back(s); }
182
183 void add_stress_point(const T& y, const T& z) {
184 int i = spoints.size1();
185 spoints.resize(i + 1, 2);
186 spoints(i, 0) = y;
187 spoints(i, 1) = z;
188 }
189
190 // Computes area moments and centroid of arbitrary thin-walled section
191 // composed of segments (y, z, dy, dz, angle)
192 void compute_area_moments() {
193 // Compute area and centroid coordinates.
194 A = yc = zc = T(0);
195 has = false;
196 for (auto linestrip : linestrips.linestrips) {
197 for (int k = 0; k != linestrip.size() - 1; ++k) {
198 // mean thickness
199 const T t = T(0.5) * (linestrip.points[k].t + linestrip.points[k + 1].t);
200 // std::cerr << "Linestrip " << k <<": t=" << t << std::endl;
201 // Compute delta-centroid
202 T c[2] = {
203 linestrip.points[k + 1].y - linestrip.points[k].y,
204 linestrip.points[k + 1].z - linestrip.points[k].z}; // direction
205 T ab = (std::sqrt(c[0] * c[0] + c[1] * c[1])); // length
206 // std::cerr << "ab=" << ab << std::endl;
207 T yyc = T(0.5) * (linestrip.points[k + 1].y + linestrip.points[k].y);
208 T zzc = T(0.5) * (linestrip.points[k + 1].z + linestrip.points[k].z);
209 // std::cerr << "yyc=" << yyc << " zzc=" << zzc << std::endl;
210 T darea = ab * t;
211 // std::cerr << "darea=" << darea << std::endl;
212 yc += yyc * darea;
213 zc += zzc * darea;
214 A += darea;
215 }
216 }
217 // if (std::abs(A) < std::numeric_limits<T>::epsilon())
218 // Exception() << "Cross section area (" << A << ") is zero or "nearly zero." << THROW;
219 yc /= A;
220 zc /= A;
221
222 // Compute inertia moments at centroid
223 ymin = +std::numeric_limits<T>::max();
224 ymax = std::numeric_limits<T>::lowest();
225 zmin = +std::numeric_limits<T>::max();
226 zmax = std::numeric_limits<T>::lowest();
227 It = Iyy = Izz = Iyz = K1 = K2 = T(0);
228 T tmax = std::numeric_limits<T>::lowest();
229 for (auto linestrip : linestrips.linestrips) {
230 // std::cerr << "---Linestrip " << std::endl;
231 for (int k = 0; k != linestrip.size() - 1; ++k) {
232 // mean thickness
233 const T t = T(0.5) * (linestrip.points[k].t + linestrip.points[k + 1].t);
234 // std::cerr << "t=" << t << std::endl;
235 // Compute delta-centroid
236 T c[2] = {
237 linestrip.points[k + 1].y - linestrip.points[k].y,
238 linestrip.points[k + 1].z - linestrip.points[k].z};
239 // std::cerr << "c[0]=" << c[0] << " c[1]=" << c[1] << std::endl;
240 T seglength = (std::sqrt(c[0] * c[0] + c[1] * c[1])); // length
241 // std::cerr << "seglength=" << seglength << std::endl;
242 T yyc = T(0.5) * (linestrip.points[k + 1].y + linestrip.points[k].y) - yc;
243 T zzc = T(0.5) * (linestrip.points[k + 1].z + linestrip.points[k].z) - zc;
244 // std::cerr << "yyc=" << yyc << " zzc=" << zzc << std::endl;
245 T darea = seglength * t;
246 // // Inertia moments of rectangle about its centroid.
247 T Iyyp = seglength * pow3(t) / T(12);
248 T Izzp = t * pow3(seglength) / T(12);
249 // std::cerr << "Iyyp=" << Iyyp << " Izzp=" << Izzp << std::endl;
250 T alfa = std::atan2(c[1], c[0]);
251 // // Rotate
252 T c2 = std::cos(2. * alfa);
253 T s2 = std::sin(2. * alfa);
254 // std::cerr << "alfa=" << alfa<< " cos=" << c2<< " sin=" << s2 << std::endl;
255 T p = T(0.5) * (Iyyp + Izzp);
256 T m = T(0.5) * (Iyyp - Izzp);
257 T Iyypp = p + m * c2;
258 T Izzpp = p - m * c2;
259 T Iyzpp = -m * s2;
260 // std::cerr << "Iyypp=" << Iyypp+ zzc * zzc * darea << " Izzpp=" << Izzpp + yyc *
261 // yyc * darea << " Iyzpp=" << Iyzpp + yyc * zzc * darea << std::endl;
262 // // Compute at centroid
263 Iyy += Iyypp + zzc * zzc * darea;
264 Izz += Izzpp + yyc * yyc * darea;
265 Iyz += Iyzpp + yyc * zzc * darea;
266 if (linestrip.connection == "open") {
267 // Torsional moment: Bredts' formula
268 It += seglength * pow3(t) * T(0.3333333333333333);
269 tmax = std::max(tmax, t);
270 Wt = It / tmax;
271 }
272 ymin = std::min(ymin, linestrip.points[k].y - yc);
273 ymin = std::min(ymin, linestrip.points[k + 1].y - yc);
274 zmin = std::min(zmin, linestrip.points[k].z - zc);
275 zmin = std::min(zmin, linestrip.points[k + 1].z - zc);
276
277 ymax = std::max(ymax, linestrip.points[k].y - yc);
278 ymax = std::max(ymax, linestrip.points[k + 1].y - yc);
279 zmax = std::max(zmax, linestrip.points[k].z - zc);
280 zmax = std::max(zmax, linestrip.points[k + 1].z - zc);
281 }
282 }
283 if (std::abs(Iyz) > std::numeric_limits<T>::epsilon() * std::abs(Iyy)
284 && std::abs(Iyz) > std::numeric_limits<T>::epsilon() * std::abs(Izz)) {
285 const T pi = std::acos(T(-1));
286 theta = T(90) * std::atan(2. * Iyz / (-Iyy + Izz)) / pi;
287 } else {
288 theta = T(0);
289 }
290 // principal moments
291 T a = T(0.5) * (Iyy + Izz);
292 T b = std::sqrt(pow2(T(0.5) * (Iyy - Izz)) + pow2(Iyz));
293 I1 = a + b;
294 I2 = a - b;
295
296 // Shear center = centroid by default (not (yet) computed
297 // here. Modified in shape dependent code.
298 ys = yc;
299 zs = zc;
300 has = true;
301 }
302
303 // Generates a LineSegment of a straight line from a to b with
304 // thickness t. Return area of segment.
305 T add_line_straight(const T ya, const T za, const T yb, const T zb, const T& t) {
306 LineStrip<T> ls;
307 ls.append(Point<T>(ya, za, t));
308 ls.append(Point<T>(yb, zb, t));
309 linestrips.append(ls);
310 T c[2] = {yb - ya, zb - za}; // direction
311 T ab = (std::sqrt(c[0] * c[0] + c[1] * c[1])); // length
312 return t * std::sqrt(c[0] * c[0] + c[1] * c[1]);
313 }
314
315 void print(const std::string& text) {
316 std::cout << "*****************************************************************************"
317 << std::endl
318 << "Cross section properties ";
319 if (text.size() > 0) { std::cout << "\"" << text << "\""; }
320 std::cout << std::endl
321 << "*****************************************************************************"
322 << std::endl
323 << std::endl;
324 std::cout << "Shape=\"" << shape << "\"" << std::endl
325 << "length unit=\"" << length_unit << "\"" << std::endl
326 << std::setprecision(std::numeric_limits<double>::digits10 + 1) << std::scientific
327 << "yc=" << yc << " zc=" << zc << std::endl
328 << "ys=" << ys << " zs=" << zs << std::endl
329 << "A=" << A << std::endl
330 << "Iyy=" << Iyy << std::endl
331 << "Izz=" << Izz << std::endl
332 << "Iyz=" << Iyz << std::endl
333 << "It=" << It << std::endl
334 << "Wt=" << Wt << std::endl
335 << "theta=" << theta << std::endl
336 << "I1=" << I1 << std::endl
337 << "I2=" << I2 << std::endl
338 << "K1=" << K1 << std::endl
339 << "K2=" << K2 << std::endl
340 << "ymin=" << ymin << " ymax=" << ymax << std::endl
341 << "zmin=" << zmin << " zmax=" << zmax << std::endl
342 << std::endl;
343
344 if (spoints.size1() > 0) {
345 std::cout << "Stress points y, z:" << std::endl;
346 for (int row = 0; row < spoints.size1(); ++row) {
347 for (int col = 0; col < 2; ++col) { std::cout << spoints(row, col) << " "; }
348 std::cout << std::endl;
349 }
350 }
351 }
352
353 void add_properties(RTable& keys) {
354 keys.set("ymin", ymin);
355 keys.set("ymax", ymax);
356 keys.set("zmin", zmin);
357 keys.set("zmax", zmax);
358 keys.set("yc", yc);
359 keys.set("zc", zc);
360 keys.set("ys", ys);
361 keys.set("zs", zs);
362 keys.set("A", A);
363 keys.set("It", It);
364 keys.set("Iyy", Iyy);
365 keys.set("Izz", Izz);
366 keys.set("Iyz", Iyz);
367 keys.set("I1", I1);
368 keys.set("I2", I2);
369 keys.set("K1", K1);
370 keys.set("K2", K2);
371 keys.set("theta", theta);
372 keys.set("Wt", Wt);
373 keys.set("length_unit", length_unit);
374 if (spoints.size1() > 0) {
375 std::vector<T> points;
376 points.reserve(spoints.size1() * spoints.size2());
377 for (int row = 0; row < spoints.size1(); ++row) {
378 points.push_back(spoints(row, 0));
379 points.push_back(spoints(row, 1));
380 }
381 keys.set("SPOINTS", points);
382 }
383 }
384
385 void doswap() {
386 std::swap(Iyy, Izz);
387 std::swap(I1, I2);
388 std::swap(K1, K2);
389 std::swap(yc, zc);
390 std::swap(ys, zs);
391 std::swap(ymin, zmin);
392 std::swap(ymax, zmax);
393 }
394
395 // Update stress y, z point coordinates with respect to centroid.
396 void update_stress_points() {
397 for (int row = 0; row < spoints.size1(); ++row) {
398 spoints(row, 0) -= yc;
399 spoints(row, 1) -= zc;
400 }
401 }
402
403protected:
404 std::string title;
405 std::string shape;
406 std::string geometry; // Type of section: "open", "closed"
407 LineStrips<T> linestrips;
408 bool has; // Set to true if section proerties are defined
409 bool swapyz; // Set to 1 if y and z axes parameters have to be swapped
410
411public:
412 T ymin; // minmax with respect to centroid if applicable
413 T ymax;
414 T zmin;
415 T zmax;
416 T yc; // centroid
417 T zc;
418 T ys; // Shear center
419 T zs;
420 T A; // Area
421 T It; // Torsion moment
422 T Iyy; // Inertia (area) moments
423 T Izz;
424 T Iyz;
425 T I1; // Major pricipal moment
426 T I2; // Minor pricipal moment
427 T K1;
428 T K2; // Shear correction factors
429 T theta; // Angle to principal y axis
430 T Wt; // Torsional resistance moment
431 std::string length_unit;
432 // Stress evaluation points (y,z)
433 // b2linalg::Matrix<T, b2linalg::Mrectangle> spoints;
434 b2000::b2linalg::Matrix<T, b2000::b2linalg::Mrectangle> spoints;
435 int nseg = 10;
436};
437
438// Computes bar (rectangle) section properties with respect to centroid.
439template <typename T>
440class BeamCrossSectionBar : public BeamCrossSection<T> {
441private:
442 T width_;
443 T height_;
444
445public:
446 void compute_properties(const T& width, const T& height, const bool swap) {
447 width_ = width;
448 height_ = height;
449 this->nseg = 0; // Not used (analytical)
450 this->shape = "Bar";
451 this->geometry = "closed";
452 this->swapyz = swap;
453 this->A = height_ * width_;
454 this->Iyy = width_ * pow3(height_) / T(12);
455 this->Izz = height_ * pow3(width_) / T(12);
456 this->ymax = T(0.5) * width_;
457 this->ymin = -this->ymax;
458 this->zmax = T(0.5) * height_;
459 this->zmin = -this->zmax;
460 // const T K = 10 * (1 + nu) / (12 + 1 * nu);
461 this->K1 = this->K2 = T(5) / T(6);
462 // Roark
463 T a = width_;
464 T b = height_;
465 if (width_ >= height_) {
466 this->I1 = this->Izz;
467 this->I2 = this->Iyy;
468 this->theta = std::acos(T(-1)) * T(.5);
469 } else {
470 this->I1 = this->Iyy;
471 this->I2 = this->Izz;
472 this->theta = 0;
473 std::swap(a, b);
474 }
475 this->It =
476 a * pow3(b) * (T(1) / T(3) - T(0.21) * b / a * (T(1) - pow4(b) / (T(12) * pow4(a))));
477 // From Roark and Young
478 // if (dstd::swap(1 < d2)
479 // std::swap(d1, d2);
480 // const T J = d1 * std::pow(d2, 3) * (1.0 / 3 - 0.21 * d2 / d1 * (1 - std::pow(d2 / d1, 4)
481 // / 12));
482 // self.Wt = ?? # must be calculated by pp
483
484 // Add stress points
485 this->add_stress_point(this->ymax, this->zmax);
486 this->add_stress_point(this->ymax, this->zmin);
487 this->add_stress_point(this->ymin, this->zmin);
488 this->add_stress_point(this->ymin, this->zmax);
489
490 if (this->swapyz) { this->doswap(); }
491 }
492
493 void load(const RTable& keys) {
494 width_ = keys.get<T>("D1");
495 height_ = keys.get<T>("D2");
496 const bool s = keys.get_bool("SWAP", false);
497 compute_properties(width_, height_, s);
498 }
499};
500
501// Computes box cross section properties with respect to centroid.
502template <typename T>
503class BeamCrossSectionBox : public BeamCrossSection<T> {
504private:
505 T width_; // D1 (width of box)
506 T height_; // D2(height of box)
507 T tflange_; // D3 (thickness of horizontal walls along y)
508 T tweb_; // D4 (thickness of vertical walls along z)
509
510public:
511 void compute_properties(
512 const T& width, const T& height, const T& tflange, const T& tweb, const bool swap) {
513 width_ = width;
514 height_ = height;
515 tflange_ = tflange;
516 tweb_ = tweb;
517 this->shape = "Box";
518 this->geometry = "closed";
519 this->swapyz = swap;
520 this->nseg = 1;
521 this->A = height_ * width_ - (height_ - T(2) * tflange) * (width_ - T(2) * tflange);
522 this->Iyy = width_ * pow3(height_) / T(12)
523 - (width_ - T(2) * tweb_) * pow3(height_ - T(2) * tflange_) / T(12);
524 this->Izz = height_ * pow3(width_) / T(12)
525 - (height_ - T(2) * tflange_) * pow3(width_ - T(2) * tweb_) / T(12);
526 // It=2.*tflange*tweb*(width_-tweb)**2*(h-tflange)**2/(width_*tweb+h*tflange-tweb**2-tflange**2);
527 T A1 = T(2) * height_ * tweb_;
528 T A2 = T(2) * width_ * tflange_;
529 if (width_ >= height_) {
530 this->I1 = this->Izz;
531 this->I2 = this->Iyy;
532 this->theta = T(.5) * std::acos(T(-1));
533 } else {
534 this->I1 = this->Iyy;
535 this->I2 = this->Izz;
536 }
537 this->K1 = A2 / this->A;
538 this->K2 = A1 / this->A;
539 // Torsion: Zweite Bredt'sche Formel
540 T ww = width_ - tweb_;
541 T hh = height_ - tflange_;
542 T Am = ww * hh;
543 this->It = 4. * Am * Am / (2. * (ww / tflange_ + hh / tweb_));
544 this->Wt = 2. * Am * tweb_;
545
546 this->add_stress_point(this->ymax, this->zmax);
547 this->add_stress_point(this->ymax, this->zmin);
548 this->add_stress_point(this->ymin, this->zmin);
549 this->add_stress_point(this->ymin, this->zmax);
550
551 if (this->swapyz) { this->doswap(); }
552 }
553
554 void load(const RTable& keys) {
555 width_ = keys.get<T>("D1");
556 height_ = keys.get<T>("D2");
557 tflange_ = keys.get<T>("D3");
558 tweb_ = keys.get<T>("D4");
559 const bool s = keys.get_bool("SWAP", false);
560 compute_properties(width_, height_, tflange_, tweb_, s);
561 }
562};
563
564// Computes C cross section properties with respect to centroid.
565template <typename T>
566class BeamCrossSectionC : public BeamCrossSection<T> {
567private:
568 T width_; // D1 (profile flange width)
569 T height_; // D2 (profile web height)
570 T tweb_; // D3 (web thickness)
571 T tflange_; // D4 (thickness of flanges)
572
573public:
574 void compute_properties(
575 const T& width, const T& height, const T& tweb, const T& tflange, const bool swap) {
576 width_ = width; // d1
577 height_ = height; // d2
578 tweb_ = tweb; // d3
579 tflange_ = tflange; // d4;
580 this->shape = "C";
581 this->geometry = "open";
582 this->swapyz = swap;
583 this->nseg = 1;
584 T a[2];
585 T b[2];
586 T z1 = T(0.5) * tflange_;
587 T z2 = height_ - z1;
588 // Lower flange
589 T A1 = this->add_line_straight(tweb_, z1, width_, z1, tflange);
590 // Upper flange
591 T A2 = this->add_line_straight(tweb_, z2, width_, z2, tflange_);
592 // Web
593 T tweb2 = T(0.5) * tweb_;
594 T A3 = this->add_line_straight(tweb2, T(0), tweb2, height_, tweb_);
595 this->compute_area_moments();
596
597 // Update numerically (thin walled) computed values
598
599 // Add shear center (thin-walled) analytically!
600 this->ys = -pow2((width_ - T(0.5) * tweb_)) * tflange_
601 / (T(2.) * (width_ - T(0.5) * tweb_) * tflange_
602 + (height_ - tflange_) * tweb_ / T(3));
603 this->ys -= this->yc; // update for centroid origin
604 this->zs = T(0);
605
606 this->K2 = height_ * tweb_ / this->A;
607 this->K1 = 2. * width_ * tflange_ / this->A;
608
609 // Add stress points
610 this->add_stress_point(this->ymax, this->zmax);
611 this->add_stress_point(this->ymax, this->zmin);
612 this->add_stress_point(this->ymin, this->zmin);
613 this->add_stress_point(this->ymin, this->zmax);
614
615 if (this->swapyz) { this->doswap(); }
616 }
617
618 void load(const RTable& keys) {
619 width_ = keys.get<T>("D1");
620 height_ = keys.get<T>("D2");
621 tweb_ = keys.get<T>("D3");
622 tflange_ = keys.get<T>("D4");
623 const bool s = keys.get_bool("SWAP", false);
624 compute_properties(width_, height_, tweb_, tflange_, s);
625 }
626};
627
628// Computes I cross section properties with respect to centroid.
629template <typename T>
630class BeamCrossSectionI : public BeamCrossSection<T> {
631private:
632 T height_;
633 T width1_;
634 T width2_;
635 T tweb_;
636 T tflange1_;
637 T tflange2_;
638
639public:
640 void compute_properties(
641 const T& height, const T& width1, const T& width2, const T& tweb, const T& tflange1,
642 const T& tflange2, const bool swap) {
643 height_ = height; // Total height of profile (=web height)
644 width1_ = width1; // Width of lower flange
645 width2_ = width2; // Width of upper flange
646 tweb_ = tweb; // Thickness of web
647 tflange1_ = tflange1; // Thickness of lower flange
648 tflange2_ = tflange2; // Thickness of upper flange
649 this->swapyz = swap;
650 this->shape = "I";
651 this->geometry = "open";
652 this->nseg = 1;
653 // Lower flange
654 T y = T(0.5) * width1_;
655 T z = T(0.5) * (height_ - tflange1_);
656 T A1 = this->add_line_straight(-y, -z, y, -z, tflange1_);
657 // Upper flange
658 y = T(0.5) * width2_;
659 z = T(0.5) * (height_ - tflange2_);
660 T A2 = this->add_line_straight(-y, z, y, z, tflange2_);
661 // web
662 T A3 = this->add_line_straight(
663 T(0), -T(0.5) * height_ + tflange1_, T(0), T(0.5) * height_ - tflange2_, tweb_);
664 this->compute_area_moments();
665
666 this->K1 = (A1 + A2) / this->A;
667 this->K2 = A3 / this->A;
668
669 // Add stress points
670 this->add_stress_point(this->ymax, this->zmax);
671 this->add_stress_point(this->ymin, this->zmax);
672 this->add_stress_point(this->ymin, this->zmin);
673 this->add_stress_point(this->ymax, this->zmin);
674
675 if (this->swapyz) { this->doswap(); }
676 }
677
678 void load(const RTable& keys) {
679 height_ = keys.get<T>("D1");
680 width1_ = keys.get<T>("D2");
681 width2_ = keys.get<T>("D3");
682 tweb_ = keys.get<T>("D4");
683 tflange1_ = keys.get<T>("D5");
684 tflange2_ = keys.get<T>("D6");
685 const bool s = keys.get_bool("SWAP", false);
686 compute_properties(height_, width1_, width2_, tweb_, tflange1_, tflange2_, s);
687 }
688};
689
690// Computes L cross section properties with respect to centroid.
691template <typename T>
692class BeamCrossSectionL : public BeamCrossSection<T> {
693private:
694 T width_;
695 T height_;
696 T tflange_;
697 T tweb_;
698
699public:
700 void compute_properties(
701 const T& width, const T& height, const T& tflange, const T& tweb, const bool swap) {
702 width_ = width; // D1
703 height_ = height; // D2
704 tflange_ = tflange; // D3
705 tweb_ = tweb; // D4
706 this->shape = "L";
707 this->geometry = "open";
708 this->swapyz = swap;
709 this->nseg = 1;
710 T a[2];
711 T b[2];
712
713 // Web
714 T tweb2 = T(0.5) * tweb_;
715 T A1 = this->add_line_straight(tweb2, T(0), tweb2, height_, tweb_);
716 // Flange
717 T tflange2 = T(0.5) * tflange_;
718 T A2 = this->add_line_straight(tweb_, tflange2, width_, tflange2, tflange_);
719 this->compute_area_moments();
720
721 // shear center from Roark table 8.12: Thin walled ey=ez=0
722 this->ys = tweb2 - this->yc;
723 this->zs = tflange2 - this->zc;
724
725 this->K1 = A2 / this->A;
726 this->K2 = A1 / this->A;
727 // Stress points in definition system: (0,0) in lower left corner of L)
728 this->add_stress_point(tweb_, height_);
729 this->add_stress_point(width_, T(0));
730 this->add_stress_point(T(0), T(0));
731 this->add_stress_point(T(0), height_);
732 this->update_stress_points(); // Correct for Centroid
733 if (this->swapyz) { this->doswap(); }
734 }
735
736 void load(const RTable& keys) {
737 width_ = keys.get<T>("D1");
738 height_ = keys.get<T>("D2");
739 tflange_ = keys.get<T>("D3");
740 tweb_ = keys.get<T>("D4");
741 const bool s = keys.get_bool("SWAP", false);
742 compute_properties(width_, height_, tflange_, tweb_, s);
743 }
744};
745// Computes upside down T shape cross section properties with respect to centroid.
746template <typename T>
747class BeamCrossSectionT2 : public BeamCrossSection<T> {
748private:
749 T width_;
750 T height_;
751 T tflange_;
752 T tweb_;
753
754public:
755 void compute_properties(
756 const T& width, const T& height, const T& tflange, const T& tweb, const bool swap) {
757 width_ = width; // D1
758 height_ = height; // D2
759 tflange_ = tflange; // D3
760 tweb_ = tweb; // D4
761 this->shape = "T2";
762 this->geometry = "open";
763 this->swapyz = swap;
764 this->nseg = 1;
765 T a[2];
766 T b[2];
767
768 // Web
769 T tweb2 = T(0.5) * tweb_;
770 T A1 = this->add_line_straight(T(0), tflange_, T(0), height_, tweb_);
771 // Flange
772 T w2 = T(0.5) * width_;
773 T tflange2 = T(0.5) * tflange_;
774 T A2 = this->add_line_straight(-w2, tflange2, w2, tflange2, tflange_);
775 this->compute_area_moments();
776
777 // shear center from Roark table 8.12: Thin walled ey=ez=0
778 T t2 = height_ - tweb_;
779 this->ys = T(0);
780 this->zs = -this->zc + tflange2
781 + 0.5 * (tflange_ + t2) / (T(1) + pow3(width_) * tflange_ / (pow3(tweb_) * t2));
782
783 this->K1 = A2 / this->A;
784 this->K2 = A1 / this->A;
785 // Stress points in definition system: (0,0) in lower left corner of L
786 this->add_stress_point(tflange2, height_);
787 this->add_stress_point(w2, T(0));
788 this->add_stress_point(-w2, T(0));
789 this->add_stress_point(-tflange2, height_);
790 this->update_stress_points(); // Correct for Centroid
791 if (this->swapyz) { this->doswap(); }
792 }
793
794 void load(const RTable& keys) {
795 width_ = keys.get<T>("D1");
796 height_ = keys.get<T>("D2");
797 tflange_ = keys.get<T>("D3");
798 tweb_ = keys.get<T>("D4");
799 const bool s = keys.get_bool("SWAP", false);
800 compute_properties(width_, height_, tflange_, tweb_, s);
801 }
802};
803
804// Computes circular tube section properties with respect to centroid.
805template <typename T>
806class BeamCrossSectionTube : public BeamCrossSection<T> {
807private:
808 T r_; // D1 outer radius
809 T ri_; // D2 inner radius
810
811public:
812 void compute_properties(const T& r, const T& ri, const bool swap) {
813 r_ = r;
814 ri_ = ri;
815 if (real(r_) < std::numeric_limits<T>::epsilon()) {
816 Exception() << "Tube cross section: radius (" << r_ << ") <= 0" << THROW;
817 }
818 if (ri_ >= r_) { Exception() << "Tube cross section: inner radius is >= radius" << THROW; }
819 this->nseg = 0; // Not used (analytical)
820 this->shape = "CircularTube";
821 this->geometry = "closed";
822 this->swapyz = swap;
823 if (ri_ < std::numeric_limits<T>::epsilon()) { ri_ = 0; }
824 const T pi = T(M_PI); // std::acos(T(-1));
825 this->A = pi * (r_ * r_ - ri_ * ri_);
826 this->Iyy = this->Izz = this->I1 = this->I2 = T(0.25) * pi * (pow4(r_) - pow4(ri_));
827 this->ymax = this->zmax = r;
828 this->ymin = this->zmin = -r;
829 this->K1 = this->K2 = 0.9;
830 this->It = T(2.0) * this->Iyy;
831 this->Wt = this->It / r_;
832 // Add stress points
833 T delta = T(0.125) * pi;
834 T phi = 0.0;
835 for (int i = 0; i < 16; i++) {
836 this->add_stress_point(r_ * std::cos(phi), r_ * std::sin(phi));
837 phi += delta;
838 }
839 // not needed if (swapyz) doswap();
840 }
841
842 void load(const RTable& keys) {
843 r_ = keys.get<T>("D1");
844 ri_ = keys.get<T>("D2", T(0));
845 compute_properties(r_, ri_, false);
846 }
847};
848
849// Computes rod section properties with respect to centroid. Is not
850// used, because properties (B2000++ MDL property option) are not
851// (yet) supported by Rx.S (rod) elements. Rx.S elements take mid and
852// area instead.
853
854template <typename T>
855class BeamCrossSectionRod : public BeamCrossSection<T> {
856public:
857 void compute_properties(const T& r) {
858 if (real(r) < std::numeric_limits<T>::epsilon()) {
859 Exception() << "Rod cross section radius (" << r << ") is <= 0" << THROW;
860 }
861 this->shape = "Rod";
862 this->geometry = "closed";
863 this->A = r * r * T(M_PI);
864 // All other properties are undefined (rod element!)
865 }
866
867 void load(const RTable& keys) {
868 const double area = keys.get<T>("D1");
869 compute_properties(area);
870 }
871};
872
873} // namespace b2000
874
875#endif // _B2_BEAM_CROSS_SECTIONS_
#define THROW
Definition b2exception.H:198
Definition b2beam_cross_sections.H:102
Contains the base classes for implementing Finite Elements.
Definition b2boundary_condition.H:32