Update concrete-beam example, section placement, and README

- Longitudinal bars 4 #8 bottom / 2 #8 top; stirrups #3 @ 8 in.
- Move the section figure after Loads and Beam Demand.
- Add concrete-beam/README.md.
- Regenerate results.json, assets/beam-section.typ, and the PDF.

Note: the example-value tests (test_example_flexure,
test_reinforcement_geometry) are not updated for the new input and
currently fail.
This commit is contained in:
smillmorel 2026-09-21 19:35:38 -04:00
commit d90136d158
6 changed files with 508 additions and 470 deletions

29
concrete-beam/README.md Normal file
View file

@ -0,0 +1,29 @@
# Concrete Beam
Simple-span rectangular reinforced concrete beam, checked per ACI 318 for flexure, minimum steel, and concrete shear under a uniform gravity load (1.2D + 1.6L).
## Files
- `input.yaml` — geometry, loads, materials, and reinforcement; units are carried in the values.
- `calc.py` — computes the demands and capacities, writes `results.json`, and regenerates the cross-section figure.
- `beam_section.py` — renders the cross-section as native Typst (`assets/beam-section.typ`), drawn to a fixed schematic cover.
- `test_concrete_beam.py` — pytest checks of the demands, flexure, minimum steel, shear, reinforcement geometry, and the generated figure.
- `concrete-beam.typ` — report; compiles to `concrete-beam.pdf`.
`As` is derived from the provided bars (`n_bars`, `bar_size`).
## Usage
Edit `input.yaml`, then:
```sh
python3 calc.py # writes results.json and assets/beam-section.typ
python3 -m pytest # checks the calculation and the generated figure
typst compile concrete-beam.typ # builds concrete-beam.pdf
```
`calc.py` must be run before compiling so the figure matches the current inputs; the tests fail if `assets/beam-section.typ` is stale.
## Requirements
Python 3 with `pyyaml`, `pint`, `pytest`; Typst.

View file

@ -3,10 +3,12 @@
box(width: 180pt, height: 180pt)[
#place(dx: 48pt, dy: 28pt, rect(width: 76pt, height: 114pt, fill: rgb("#f2f2f2"), stroke: 1pt + black))
#place(dx: 58.5pt, dy: 38.5pt, rect(width: 55pt, height: 93pt, radius: 3pt, stroke: 2pt + black))
#place(dx: 59.5pt, dy: 124.6pt, circle(radius: 2.969pt, fill: black))
#place(dx: 106.6pt, dy: 124.6pt, circle(radius: 2.969pt, fill: black))
#place(dx: 59.5pt, dy: 39.5pt, circle(radius: 2.375pt, fill: black))
#place(dx: 107.8pt, dy: 39.5pt, circle(radius: 2.375pt, fill: black))
#place(dx: 59.5pt, dy: 121pt, circle(radius: 4.75pt, fill: black))
#place(dx: 74pt, dy: 121pt, circle(radius: 4.75pt, fill: black))
#place(dx: 88.5pt, dy: 121pt, circle(radius: 4.75pt, fill: black))
#place(dx: 103pt, dy: 121pt, circle(radius: 4.75pt, fill: black))
#place(dx: 59.5pt, dy: 39.5pt, circle(radius: 4.75pt, fill: black))
#place(dx: 103pt, dy: 39.5pt, circle(radius: 4.75pt, fill: black))
#place(line(start: (48pt, 158pt), end: (124pt, 158pt), stroke: 0.6pt + black))
#place(line(start: (48pt, 155pt), end: (48pt, 161pt), stroke: 0.6pt + black))
#place(line(start: (124pt, 155pt), end: (124pt, 161pt), stroke: 0.6pt + black))
@ -15,14 +17,14 @@
#place(line(start: (39pt, 28pt), end: (45pt, 28pt), stroke: 0.6pt + black))
#place(line(start: (39pt, 142pt), end: (45pt, 142pt), stroke: 0.6pt + black))
#place(dx: 0.5pt, dy: 82pt, text(size: 7pt)[$h = 12 " in"$])
#place(line(start: (110.1pt, 41.88pt), end: (129pt, 42pt), stroke: 0.5pt + rgb("#626b73")))
#place(dx: 108.6pt, dy: 40.38pt, circle(radius: 1.5pt, fill: black))
#place(dx: 132pt, dy: 37pt, text(size: 7pt, "(2) #4"))
#place(line(start: (107.8pt, 44.25pt), end: (129pt, 42pt), stroke: 0.5pt + rgb("#626b73")))
#place(dx: 106.2pt, dy: 42.75pt, circle(radius: 1.5pt, fill: black))
#place(dx: 132pt, dy: 37pt, text(size: 7pt, "(2) #8"))
#place(line(start: (113.5pt, 85pt), end: (129pt, 82pt), stroke: 0.5pt + rgb("#626b73")))
#place(dx: 112pt, dy: 83.5pt, circle(radius: 1.5pt, fill: black))
#place(dx: 132pt, dy: 77pt, text(size: 7pt, "#3 @ 6″"))
#place(line(start: (109.5pt, 127.5pt), end: (129pt, 128pt), stroke: 0.5pt + rgb("#626b73")))
#place(dx: 108pt, dy: 126pt, circle(radius: 1.5pt, fill: black))
#place(dx: 132pt, dy: 123pt, text(size: 7pt, "(2) #5"))
#place(dx: 132pt, dy: 77pt, text(size: 7pt, "#3 @ 8″"))
#place(line(start: (107.8pt, 125.8pt), end: (129pt, 128pt), stroke: 0.5pt + rgb("#626b73")))
#place(dx: 106.2pt, dy: 124.2pt, circle(radius: 1.5pt, fill: black))
#place(dx: 132pt, dy: 123pt, text(size: 7pt, "(4) #8"))
]
}

File diff suppressed because it is too large Load diff

View file

@ -38,13 +38,6 @@ Simple-span rectangular beam under uniform gravity load. Numbers come from `calc
caption: [#n.span ft simply supported beam, #n.bw in × #n.h in rectangular section.],
)
== Section and Reinforcement
#align(right, block(width: 2.5in, figure(
beam-section(),
caption: [Beam cross-section],
)))
== Loads and Beam Demand
#calcline([$L = #n.span " ft"$], [Simple span])
@ -65,6 +58,13 @@ Simple-span rectangular beam under uniform gravity load. Numbers come from `calc
[Support shear],
)
== Section and Reinforcement
#align(right, block(width: 2.5in, figure(
beam-section(),
caption: [Beam cross-section],
)))
== Flexural Strength
#calcline([$b_w = #n.bw " in"$], [Beam width])

View file

@ -31,12 +31,12 @@ cover: "1.5 in"
# Stirrup bar number (#3).
stirrup_size: 3
# Stirrup spacing along the span, on center.
stirrup_spacing: "6 in"
stirrup_spacing: "8 in"
# Bottom (tension) longitudinal bar number (#5).
bar_size: 5
bar_size: 8
# Number of bottom longitudinal bars.
n_bars: 2
n_bars: 4
# Top (hanger) longitudinal bar number (#4).
top_bar_size: 4
top_bar_size: 8
# Number of top hanger bars.
n_top_bars: 2

View file

@ -19,35 +19,35 @@
"d": 9.5,
"fc": 3.0,
"fy": 60.0,
"As": 0.613592,
"a": 1.804683,
"et": 0.010423,
"phi": 0.9,
"Mn": 26.377285,
"phiMn": 23.739557,
"As": 3.141593,
"a": 9.239978,
"et": -0.000378,
"phi": 0.65,
"Mn": 76.65503,
"phiMn": 49.82577,
"As_min": 0.253333,
"Vc": 8.325383,
"phiVc": 6.244037,
"cover": 1.5,
"stirrup_size": 3,
"stirrup_spacing": 6.0,
"stirrup_spacing": 8.0,
"stirrup_db": 0.375,
"bar_size": 5,
"n_bars": 2,
"bar_db": 0.625,
"top_bar_size": 4,
"bar_size": 8,
"n_bars": 4,
"bar_db": 1.0,
"top_bar_size": 8,
"n_top_bars": 2,
"top_bar_db": 0.5
"top_bar_db": 1.0
},
"checks": {
"flexure": {
"demand": 23.44,
"capacity": 23.739557,
"capacity": 49.82577,
"ok": true
},
"minimum_steel": {
"demand": 0.253333,
"capacity": 0.613592,
"capacity": 3.141593,
"ok": true
},
"shear": {