18#ifndef _B2_BEAM_CROSS_SECTIONS_
19#define _B2_BEAM_CROSS_SECTIONS_
30#include "utils/b2linear_algebra.H"
31#include "utils/b2rtable.H"
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; };
115 std::vector<Point<T>> points;
116 std::string connection;
118 LineStrip() { connection =
"open"; }
119 LineStrip(
const std::string& s) { connection = s; }
120 void append(
const Point<T>& p) { points.push_back(p); };
123 std::cout <<
"LineStrip, n. of points=" << size() <<
", connection=" << connection
125 for (
auto i : points) {
126 auto s =
"Point " + std::to_string(k) +
": ";
131 const int size(
void) {
return (
int)points.size(); };
138 std::vector<LineStrip<T>> linestrips;
140 void append(
const LineStrip<T>& ls) { linestrips.push_back(ls); };
142 std::cout <<
"LineStrips, n. of Line Strips=" << size() << std::endl;
143 for (
auto i : linestrips) { i.print(); }
145 void print(
int ind) {
146 std::cout <<
"LineStrip " << ind <<
":" << std::endl;
147 linestrips[ind].print();
149 const int size(
void) {
return (
int)linestrips.size(); };
153class BeamCrossSection {
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()),
176 Wt(+std::numeric_limits<T>::max()),
179 const std::string& get_title()
const {
return title; }
183 void add_stress_point(
const T& y,
const T& z) {
184 int i = spoints.size1();
185 spoints.resize(i + 1, 2);
192 void compute_area_moments() {
196 for (
auto linestrip : linestrips.linestrips) {
197 for (
int k = 0; k != linestrip.size() - 1; ++k) {
199 const T t = T(0.5) * (linestrip.points[k].t + linestrip.points[k + 1].t);
203 linestrip.points[k + 1].y - linestrip.points[k].y,
204 linestrip.points[k + 1].z - linestrip.points[k].z};
205 T ab = (std::sqrt(c[0] * c[0] + c[1] * c[1]));
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);
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) {
231 for (
int k = 0; k != linestrip.size() - 1; ++k) {
233 const T t = T(0.5) * (linestrip.points[k].t + linestrip.points[k + 1].t);
237 linestrip.points[k + 1].y - linestrip.points[k].y,
238 linestrip.points[k + 1].z - linestrip.points[k].z};
240 T seglength = (std::sqrt(c[0] * c[0] + c[1] * c[1]));
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;
245 T darea = seglength * t;
247 T Iyyp = seglength * pow3(t) / T(12);
248 T Izzp = t * pow3(seglength) / T(12);
250 T alfa = std::atan2(c[1], c[0]);
252 T c2 = std::cos(2. * alfa);
253 T s2 = std::sin(2. * alfa);
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;
263 Iyy += Iyypp + zzc * zzc * darea;
264 Izz += Izzpp + yyc * yyc * darea;
265 Iyz += Iyzpp + yyc * zzc * darea;
266 if (linestrip.connection ==
"open") {
268 It += seglength * pow3(t) * T(0.3333333333333333);
269 tmax = std::max(tmax, t);
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);
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);
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;
291 T a = T(0.5) * (Iyy + Izz);
292 T b = std::sqrt(pow2(T(0.5) * (Iyy - Izz)) + pow2(Iyz));
305 T add_line_straight(
const T ya,
const T za,
const T yb,
const T zb,
const T& t) {
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};
311 T ab = (std::sqrt(c[0] * c[0] + c[1] * c[1]));
312 return t * std::sqrt(c[0] * c[0] + c[1] * c[1]);
315 void print(
const std::string& text) {
316 std::cout <<
"*****************************************************************************"
318 <<
"Cross section properties ";
319 if (text.size() > 0) { std::cout <<
"\"" << text <<
"\""; }
320 std::cout << std::endl
321 <<
"*****************************************************************************"
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
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;
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);
364 keys.set(
"Iyy", Iyy);
365 keys.set(
"Izz", Izz);
366 keys.set(
"Iyz", Iyz);
371 keys.set(
"theta", theta);
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));
381 keys.set(
"SPOINTS", points);
391 std::swap(ymin, zmin);
392 std::swap(ymax, zmax);
396 void update_stress_points() {
397 for (
int row = 0; row < spoints.size1(); ++row) {
398 spoints(row, 0) -= yc;
399 spoints(row, 1) -= zc;
406 std::string geometry;
407 LineStrips<T> linestrips;
431 std::string length_unit;
434 b2000::b2linalg::Matrix<T, b2000::b2linalg::Mrectangle> spoints;
440class BeamCrossSectionBar :
public BeamCrossSection<T> {
446 void compute_properties(
const T& width,
const T& height,
const bool swap) {
451 this->geometry =
"closed";
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;
461 this->K1 = this->K2 = T(5) / T(6);
465 if (width_ >= height_) {
466 this->I1 = this->Izz;
467 this->I2 = this->Iyy;
468 this->theta = std::acos(T(-1)) * T(.5);
470 this->I1 = this->Iyy;
471 this->I2 = this->Izz;
476 a * pow3(b) * (T(1) / T(3) - T(0.21) * b / a * (T(1) - pow4(b) / (T(12) * pow4(a))));
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);
490 if (this->swapyz) { this->doswap(); }
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);
503class BeamCrossSectionBox :
public BeamCrossSection<T> {
511 void compute_properties(
512 const T& width,
const T& height,
const T& tflange,
const T& tweb,
const bool swap) {
518 this->geometry =
"closed";
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);
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));
534 this->I1 = this->Iyy;
535 this->I2 = this->Izz;
537 this->K1 = A2 / this->A;
538 this->K2 = A1 / this->A;
540 T ww = width_ - tweb_;
541 T hh = height_ - tflange_;
543 this->It = 4. * Am * Am / (2. * (ww / tflange_ + hh / tweb_));
544 this->Wt = 2. * Am * tweb_;
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);
551 if (this->swapyz) { this->doswap(); }
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);
566class BeamCrossSectionC :
public BeamCrossSection<T> {
574 void compute_properties(
575 const T& width,
const T& height,
const T& tweb,
const T& tflange,
const bool swap) {
581 this->geometry =
"open";
586 T z1 = T(0.5) * tflange_;
589 T A1 = this->add_line_straight(tweb_, z1, width_, z1, tflange);
591 T A2 = this->add_line_straight(tweb_, z2, width_, z2, tflange_);
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();
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;
606 this->K2 = height_ * tweb_ / this->A;
607 this->K1 = 2. * width_ * tflange_ / this->A;
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);
615 if (this->swapyz) { this->doswap(); }
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);
630class BeamCrossSectionI :
public BeamCrossSection<T> {
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) {
647 tflange1_ = tflange1;
648 tflange2_ = tflange2;
651 this->geometry =
"open";
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_);
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_);
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();
666 this->K1 = (A1 + A2) / this->A;
667 this->K2 = A3 / this->A;
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);
675 if (this->swapyz) { this->doswap(); }
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);
692class BeamCrossSectionL :
public BeamCrossSection<T> {
700 void compute_properties(
701 const T& width,
const T& height,
const T& tflange,
const T& tweb,
const bool swap) {
707 this->geometry =
"open";
714 T tweb2 = T(0.5) * tweb_;
715 T A1 = this->add_line_straight(tweb2, T(0), tweb2, height_, tweb_);
717 T tflange2 = T(0.5) * tflange_;
718 T A2 = this->add_line_straight(tweb_, tflange2, width_, tflange2, tflange_);
719 this->compute_area_moments();
722 this->ys = tweb2 - this->yc;
723 this->zs = tflange2 - this->zc;
725 this->K1 = A2 / this->A;
726 this->K2 = A1 / this->A;
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();
733 if (this->swapyz) { this->doswap(); }
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);
747class BeamCrossSectionT2 :
public BeamCrossSection<T> {
755 void compute_properties(
756 const T& width,
const T& height,
const T& tflange,
const T& tweb,
const bool swap) {
762 this->geometry =
"open";
769 T tweb2 = T(0.5) * tweb_;
770 T A1 = this->add_line_straight(T(0), tflange_, T(0), height_, tweb_);
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();
778 T t2 = height_ - tweb_;
780 this->zs = -this->zc + tflange2
781 + 0.5 * (tflange_ + t2) / (T(1) + pow3(width_) * tflange_ / (pow3(tweb_) * t2));
783 this->K1 = A2 / this->A;
784 this->K2 = A1 / this->A;
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();
791 if (this->swapyz) { this->doswap(); }
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);
806class BeamCrossSectionTube :
public BeamCrossSection<T> {
812 void compute_properties(
const T& r,
const T& ri,
const bool swap) {
815 if (real(r_) < std::numeric_limits<T>::epsilon()) {
816 Exception() <<
"Tube cross section: radius (" << r_ <<
") <= 0" <<
THROW;
818 if (ri_ >= r_) { Exception() <<
"Tube cross section: inner radius is >= radius" <<
THROW; }
820 this->shape =
"CircularTube";
821 this->geometry =
"closed";
823 if (ri_ < std::numeric_limits<T>::epsilon()) { ri_ = 0; }
824 const T pi = T(M_PI);
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_;
833 T delta = T(0.125) * pi;
835 for (
int i = 0; i < 16; i++) {
836 this->add_stress_point(r_ * std::cos(phi), r_ * std::sin(phi));
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);
855class BeamCrossSectionRod :
public BeamCrossSection<T> {
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;
862 this->geometry =
"closed";
863 this->A = r * r * T(M_PI);
867 void load(
const RTable& keys) {
868 const double area = keys.get<T>(
"D1");
869 compute_properties(area);
#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