Настоящий интерактивный блокнот реализует нормативный инженерный селектор материалов и расчетные процедуры согласно требованиям нормативной базы РФ:
import sys
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
import ipywidgets as widgets
from IPython.display import HTML, Markdown, clear_output, display
project_dir = Path.cwd()
if str(project_dir) not in sys.path:
sys.path.insert(0, str(project_dir))
from sp63_materials import (
Concrete,
Rebar,
list_concrete_grades,
list_rebar_grades,
)
print("Модуль sp63_materials успешно загружен.")
Сжатие отображается отрицательными деформациями и напряжениями, растяжение — положительными. Для каждой кривой подписываются именно те узлы, которые возвращает выбранная нормативная модель.
w_concrete_type = widgets.Dropdown(
options=[
("Тяжелый", "heavy"),
("Мелкозернистый", "fine_grained"),
("Легкий", "light"),
("Поризованный", "porous"),
("Ячеистый", "cellular"),
("Напрягающий", "tensioning"),
],
value="heavy",
description="Вид бетона:",
style={"description_width": "150px"},
layout=widgets.Layout(width="98%"),
)
w_concrete_grade = widgets.Dropdown(
options=list_concrete_grades(),
value="B25",
description="Класс бетона:",
style={"description_width": "150px"},
layout=widgets.Layout(width="98%"),
)
w_humidity = widgets.Dropdown(
options=[
("Сухая (< 40 %)", "<40%"),
("Нормальная (40–75 %)", "40-75%"),
("Повышенная (> 75 %)", ">75%"),
],
value="40-75%",
description="Влажность среды:",
style={"description_width": "150px"},
layout=widgets.Layout(width="98%"),
)
w_density = widgets.BoundedFloatText(
value=2400.0,
min=1.0,
max=4000.0,
description="Плотность, кг/м³:",
style={"description_width": "150px"},
layout=widgets.Layout(width="98%"),
)
w_cellular_humidity = widgets.FloatSlider(
value=25.0,
min=0.0,
max=100.0,
step=1.0,
description="Влажность ячеистого, %:",
style={"description_width": "150px"},
layout=widgets.Layout(width="98%"),
)
w_curing = widgets.Dropdown(
options=[("Естественное", None), ("Тепловлажностное", "steam")],
value=None,
description="Условия твердения:",
style={"description_width": "150px"},
layout=widgets.Layout(width="98%"),
)
w_long_term = widgets.Checkbox(
value=True,
description="Длительное действие нагрузки",
indent=False,
)
w_gamma_b2 = widgets.FloatSlider(
value=1.0, min=0.1, max=1.0, step=0.01,
description="γb2:", style={"description_width": "150px"},
)
w_gamma_b3 = widgets.FloatSlider(
value=1.0, min=0.1, max=1.0, step=0.01,
description="γb3:", style={"description_width": "150px"},
)
w_gamma_b4 = widgets.FloatSlider(
value=1.0, min=0.1, max=1.0, step=0.01,
description="γb4:", style={"description_width": "150px"},
)
w_gamma_b5 = widgets.FloatSlider(
value=1.0, min=0.1, max=1.0, step=0.01,
description="γb5:", style={"description_width": "150px"},
)
w_diag_model = widgets.RadioButtons(
options=[
("Двухлинейная, 6.1.21", "bilinear"),
("Трехлинейная, 6.1.20", "trilinear"),
("Нелинейная, приложение Г", "nonlinear"),
],
value="nonlinear",
description="Модель бетона:",
style={"description_width": "150px"},
)
w_rebar_grade = widgets.Dropdown(
options=list_rebar_grades(),
value="A500",
description="Класс арматуры:",
style={"description_width": "150px"},
)
w_rebar_model = widgets.Dropdown(
options=[
("Автоматически по 6.2.13", "auto"),
("Двухлинейная", "bilinear"),
("Трехлинейная", "trilinear"),
],
value="auto",
description="Модель арматуры:",
style={"description_width": "150px"},
)
out_panel = widgets.Output()
def _set_limits(axis, eps):
low, high = float(np.min(eps)), float(np.max(eps))
span = max(high - low, 1e-6)
axis.set_xlim(low - 0.08 * span, high + 0.08 * span)
def _plot_named_points(axis, points, color):
for index, (label, (epsilon, sigma)) in enumerate(points.items()):
x_value = epsilon * 1000.0
axis.scatter([x_value], [sigma], color=color, s=26, zorder=5)
offset = (6, 8 if index % 2 == 0 else -16)
axis.annotate(
label,
xy=(x_value, sigma),
xytext=offset,
textcoords="offset points",
fontsize=8,
color=color,
arrowprops={"arrowstyle": "-", "color": color, "lw": 0.8},
)
def _concrete_diagram(concrete, state):
selected_model = w_diag_model.value
if selected_model == "nonlinear":
eps, sig = concrete.get_diagram(
model="nonlinear", state=state, n_points=160, signed=True
)
points = concrete.get_diagram_points(
model="nonlinear", state=state, signed=True
)
else:
eps, sig = concrete.get_diagram(
model=selected_model, state=state, n_points=160, signed=True
)
points = concrete.get_diagram_points(
model=selected_model, state=state, signed=True
)
return eps, sig, points
def update_view(*_):
with out_panel:
clear_output(wait=True)
try:
concrete = Concrete(
grade=w_concrete_grade.value,
concrete_type=w_concrete_type.value,
humidity=w_humidity.value,
long_term=w_long_term.value,
gamma_b2=w_gamma_b2.value,
gamma_b3=w_gamma_b3.value,
gamma_b4=w_gamma_b4.value,
gamma_b5=w_gamma_b5.value,
density=w_density.value,
curing=w_curing.value,
cellular_humidity_percent=w_cellular_humidity.value,
)
rebar = Rebar(
grade=w_rebar_grade.value,
long_term=w_long_term.value,
)
eps_c, sig_c, points_c = _concrete_diagram(concrete, "compression")
eps_t, sig_t, points_t = _concrete_diagram(concrete, "tension")
eps_s, sig_s = rebar.get_diagram(
model=w_rebar_model.value,
state="tension",
n_points=160,
signed=True,
)
points_s = rebar.get_diagram_points(
model=w_rebar_model.value, state="tension", signed=True
)
except ValueError as error:
display(Markdown(f"**Параметры требуют уточнения:** `{error}`"))
return
fig, (ax_c, ax_t, ax_s) = plt.subplots(
1, 3, figsize=(17, 5.2), dpi=110, constrained_layout=True
)
ax_c.plot(eps_c * 1000.0, sig_c, color="#1f77b4", lw=2.2)
_plot_named_points(ax_c, points_c, "#d62728")
ax_c.set_title(f"Бетон {concrete.grade}: сжатие")
ax_c.set_xlabel("ε, ‰ (укорочение со знаком −)")
ax_c.set_ylabel("σ, МПа")
_set_limits(ax_c, eps_c * 1000.0)
ax_t.plot(eps_t * 1000.0, sig_t, color="#2ca02c", lw=2.2)
_plot_named_points(ax_t, points_t, "#d62728")
ax_t.set_title(f"Бетон {concrete.grade}: растяжение")
ax_t.set_xlabel("ε, ‰ (удлинение со знаком +)")
ax_t.set_ylabel("σ, МПа")
_set_limits(ax_t, eps_t * 1000.0)
ax_s.plot(eps_s * 1000.0, sig_s, color="#ff7f0e", lw=2.2)
_plot_named_points(ax_s, points_s, "#9467bd")
ax_s.set_title(f"Арматура {rebar.grade}: {w_rebar_model.value}")
ax_s.set_xlabel("ε, ‰")
ax_s.set_ylabel("σ, МПа")
_set_limits(ax_s, eps_s * 1000.0)
for axis in (ax_c, ax_t, ax_s):
axis.grid(True, linestyle=":", alpha=0.6)
axis.axhline(0.0, color="black", lw=0.7, alpha=0.5)
axis.axvline(0.0, color="black", lw=0.7, alpha=0.5)
plt.show()
display(HTML(concrete.to_html()))
display(HTML(rebar.to_html()))
controls = [
w_concrete_type, w_concrete_grade, w_humidity, w_density,
w_cellular_humidity, w_curing, w_long_term, w_gamma_b2,
w_gamma_b3, w_gamma_b4, w_gamma_b5, w_diag_model,
w_rebar_grade, w_rebar_model,
]
for widget in controls:
widget.observe(update_view, names="value")
concrete_box = widgets.VBox(
[
widgets.HTML("<b>Параметры бетона</b>"),
w_concrete_type, w_concrete_grade, w_humidity, w_density,
w_cellular_humidity, w_curing, w_long_term,
w_gamma_b2, w_gamma_b3, w_gamma_b4, w_gamma_b5, w_diag_model,
],
layout=widgets.Layout(border="1px solid #ddd", padding="10px"),
)
rebar_box = widgets.VBox(
[widgets.HTML("<b>Параметры арматуры</b>"), w_rebar_grade, w_rebar_model],
layout=widgets.Layout(border="1px solid #ddd", padding="10px"),
)
display(widgets.HBox([concrete_box, rebar_box]))
display(out_panel)
update_view()
В данном разделе выполнен нормативный верификационный расчет прямоугольного изгибаемого железобетонного элемента:
# Статический рендер по умолчанию: сохраняется и при nbconvert,
# даже если интерактивные Output-виджеты не сериализуются.
demo_concrete = Concrete("B25", long_term=True)
demo_rebar = Rebar("A500")
demo_fig, demo_axes = plt.subplots(
1, 3, figsize=(17, 5.2), dpi=110, constrained_layout=True
)
for axis, state, title, color in [
(demo_axes[0], "compression", "Бетон B25: сжатие", "#1f77b4"),
(demo_axes[1], "tension", "Бетон B25: растяжение", "#2ca02c"),
]:
eps, sig = demo_concrete.get_diagram(
model="nonlinear", state=state, n_points=160, signed=True
)
points = demo_concrete.get_diagram_points(
model="nonlinear", state=state, signed=True
)
axis.plot(eps * 1000.0, sig, color=color, lw=2.2)
_plot_named_points(axis, points, "#d62728")
axis.set_title(title)
axis.set_xlabel("ε, ‰")
axis.set_ylabel("σ, МПа")
axis.grid(True, linestyle=":", alpha=0.6)
axis.axhline(0.0, color="black", lw=0.7, alpha=0.5)
axis.axvline(0.0, color="black", lw=0.7, alpha=0.5)
_set_limits(axis, eps * 1000.0)
eps, sig = demo_rebar.get_diagram(
model="auto", state="tension", n_points=160, signed=True
)
points = demo_rebar.get_diagram_points(
model="auto", state="tension", signed=True
)
demo_axes[2].plot(eps * 1000.0, sig, color="#ff7f0e", lw=2.2)
_plot_named_points(demo_axes[2], points, "#9467bd")
demo_axes[2].set_title("Арматура A500: auto")
demo_axes[2].set_xlabel("ε, ‰")
demo_axes[2].set_ylabel("σ, МПа")
demo_axes[2].grid(True, linestyle=":", alpha=0.6)
demo_axes[2].axhline(0.0, color="black", lw=0.7, alpha=0.5)
demo_axes[2].axvline(0.0, color="black", lw=0.7, alpha=0.5)
_set_limits(demo_axes[2], eps * 1000.0)
plt.show()
display(HTML(demo_concrete.to_html()))
display(HTML(demo_rebar.to_html()))
concrete_example = Concrete("B25", long_term=True)
rebar_example = Rebar("A500")
# 1. Геометрические параметры балки
b = 300.0 # ширина сечения, мм
h = 600.0 # полная высота сечения, мм
a = 40.0 # расстояние от растянутой грани до центра тяжести арматуры, мм
h0 = h - a # рабочая высота сечения, мм
L = 6.0 # расчетный пролет балки, м
# 2. Нагрузки и внутренние расчетные усилия (СП 20.13330.2016)
q = 55.0 # расчетная погонная нагрузка, кН/м
M_Ed = q * L**2 / 8.0 # расчетный изгибающий момент в пролете, кН·м
Q_Ed = q * L / 2.0 # расчетная поперечная сила на опоре, кН
# 3. Характеристики продольной арматуры (3 шт. диаметром 25 мм)
n_bars = 3
d_bar = 25.0
As = n_bars * np.pi * (d_bar ** 2) / 4.0 # площадь продольной арматуры, мм²
Rs = rebar_example.Rs # расчетное сопротивление, МПа
Es = rebar_example.Es # модуль упругости, МПа
# 4. Характеристики бетона
Rb = concrete_example.Rb # расчетное сопротивление бетона сжатию, МПа
Rbt = concrete_example.Rbt # расчетное сопротивление бетона растяжению, МПа
Eb = concrete_example.Eb # начальный модуль упругости, МПа
# 5. Граничная относительная высота сжатой зоны по п. 8.1.9 (СП 63.13330.2018)
# Формула (8.1): xi_R = 0.8 / (1 + eps_s,el / eps_b,2)
eps_s_el = Rs / Es
eps_b2 = 0.0035 # предельная деформация сжатого бетона при кратковременном сжатии
xi_R = 0.8 / (1.0 + eps_s_el / eps_b2)
x_R = xi_R * h0
# 6. Расчет прочности по нормальным сечениям (п. 8.1.8)
# Из условия равновесия продольных сил sum(N) = 0: Rb * b * x = Rs * As
x = (Rs * As) / (Rb * b)
xi = x / h0
# Предельный изгибающий момент сечения (формула 8.5):
# Mult = Rb * b * x * (h0 - 0.5 * x)
Mult = Rb * b * x * (h0 - 0.5 * x) / 1e6 # кН·м
k_bend = M_Ed / Mult
# 7. Расчет поперечной арматуры (пп. 8.1.31-8.1.34)
# Хомуты 2 ветви d = 8 мм класса А500, шаг s = 150 мм
n_legs = 2
d_sw = 8.0
s_sw = 150.0 # шаг хомутов на приопорном участке, мм
Asw = n_legs * np.pi * (d_sw ** 2) / 4.0 # площадь поперечной арматуры одного шага, мм²
Rsw = rebar_example.Rsw if rebar_example.Rsw is not None else 300.0 # МПа
# Проверка сжатой полосы между наклонными трещинами (п. 8.1.31):
# Q <= 0.3 * phi_w1 * phi_b1 * Rb * b * h0
phi_b1_shear = 0.3
Q_max_strip = phi_b1_shear * Rb * b * h0 / 1e3 # кН
k_shear_strip = Q_Ed / Q_max_strip
# Проверка прочности наклонного сечения по наклонной трещине (п. 8.1.32-8.1.34):
# Интенсивность хомутов: q_sw = Rsw * Asw / s_sw (Н/мм = кН/м)
q_sw = Rsw * Asw / s_sw
phi_b2 = 1.5
phi_b3 = 0.5
Mb = phi_b2 * Rbt * b * (h0 ** 2) / 1e6 # кН·м
# Невыгоднейшая длина проекции наклонной трещины c:
c_opt = np.sqrt(Mb / (q_sw / 1e3)) * 1e3 # мм
c_proj = float(np.clip(c_opt, h0, 2.0 * h0))
# Усилие в бетоне:
Qb = (Mb / (c_proj / 1e3))
Qb_min = phi_b3 * Rbt * b * h0 / 1e3
Qb = max(Qb, Qb_min)
# Усилие в хомутах:
Qsw = 0.75 * q_sw * (c_proj / 1e3)
# Полная поперечная несущая способность:
Q_ult = Qb + Qsw
k_shear_crack = Q_Ed / Q_ult
# 8. Вывод отчета
print("=" * 78)
print(f"РАСЧЕТ ЖЕЛЕЗОБЕТОННОЙ БАЛКИ {b:.0f}x{h:.0f} мм ПО СП 63.13330.2018")
print("=" * 78)
print(f"Материалы: Бетон {concrete_example.grade} (Rb = {Rb:.2f} МПа, Rbt = {Rbt:.3f} МПа, Eb = {Eb:.0f} МПа)")
print(f" Арматура {rebar_example.grade} ({n_bars} d{d_bar:.0f}, As = {As:.1f} мм², Rs = {Rs:.0f} МПа)")
print("-" * 78)
print(f"1. Сжатая зона бетона: x = {x:.1f} мм; xi = {xi:.3f} <= xi_R = {xi_R:.3f} (x_R = {x_R:.1f} мм) -> OK")
print(f"2. Прочность по изгибу: M_Ed = {M_Ed:.2f} кН·м <= Mult = {Mult:.2f} кН·м (К_и = {k_bend*100:.1f}%) -> OK")
print(f"3. Сжатая полоса бетона: Q_Ed = {Q_Ed:.2f} кН <= Q_max = {Q_max_strip:.2f} кН (К_и = {k_shear_strip*100:.1f}%) -> OK")
print(f"4. Наклонная трещина: Q_Ed = {Q_Ed:.2f} кН <= Q_ult = {Q_ult:.2f} кН (К_и = {k_shear_crack*100:.1f}%) -> OK")
print("=" * 78)
# Формирование HTML-таблицы результатов
html_report = f"""
<div style="border: 1px solid #1f77b4; border-radius: 8px; padding: 16px; margin: 15px 0; background: #fdfdfd; font-family: sans-serif;">
<h3 style="color: #1f77b4; margin-top: 0; margin-bottom: 12px;">Сводные результаты расчета балки по СП 63.13330.2018</h3>
<p style="margin-bottom: 8px;"><strong>Сечение:</strong> {b:.0f}×{h:.0f} мм, пролет <em>L</em> = {L:.1f} м, защитный слой <em>a</em> = {a:.0f} мм (<em>h</em><sub>0</sub> = {h0:.0f} мм)</p>
<p style="margin-bottom: 12px;"><strong>Материалы:</strong> Бетон <strong>{concrete_example.grade}</strong> (<em>R<sub>b</sub></em> = {Rb:.2f} МПа), Арматура <strong>{rebar_example.grade}</strong> (3∅{d_bar:.0f}, <em>A<sub>s</sub></em> = {As:.1f} мм², <em>R<sub>s</sub></em> = {Rs:.0f} МПа)</p>
<table style="width: 100%; border-collapse: collapse; font-size: 14px; text-align: left;">
<thead>
<tr style="background: #eef3f8; border-bottom: 2px solid #1f77b4;">
<th style="padding: 8px;">Проверка по СП 63</th>
<th style="padding: 8px; text-align: center;">Формула СП 63</th>
<th style="padding: 8px; text-align: right;">Расчетное значение</th>
<th style="padding: 8px; text-align: right;">Предельное значение</th>
<th style="padding: 8px; text-align: center;">К<sub>исп</sub></th>
<th style="padding: 8px; text-align: center;">Статус</th>
</tr>
</thead>
<tbody>
<tr style="border-bottom: 1px solid #e0e0e0;">
<td style="padding: 8px;">Граничная высота сжатой зоны бетона</td>
<td style="padding: 8px; text-align: center;">п. 8.1.9, ф. (8.1)</td>
<td style="padding: 8px; text-align: right;">ξ = {xi:.3f} (x = {x:.1f} мм)</td>
<td style="padding: 8px; text-align: right;">ξ<sub>R</sub> = {xi_R:.3f} (x<sub>R</sub> = {x_R:.1f} мм)</td>
<td style="padding: 8px; text-align: center;">{xi/xi_R:.1%}</td>
<td style="padding: 8px; text-align: center; color: #2ca02c; font-weight: bold;">✅ Пластичное разрушение</td>
</tr>
<tr style="border-bottom: 1px solid #e0e0e0;">
<td style="padding: 8px;">Прочность нормального сечения при изгибе</td>
<td style="padding: 8px; text-align: center;">п. 8.1.8, ф. (8.5)</td>
<td style="padding: 8px; text-align: right;"><em>M<sub>Ed</sub></em> = {M_Ed:.2f} кН·м</td>
<td style="padding: 8px; text-align: right;"><em>M<sub>ult</sub></em> = {Mult:.2f} кН·м</td>
<td style="padding: 8px; text-align: center;">{k_bend:.1%}</td>
<td style="padding: 8px; text-align: center; color: #2ca02c; font-weight: bold;">✅ Прочность обеспечена</td>
</tr>
<tr style="border-bottom: 1px solid #e0e0e0;">
<td style="padding: 8px;">Сжатая полоса бетона между трещинами</td>
<td style="padding: 8px; text-align: center;">п. 8.1.31, ф. (8.55)</td>
<td style="padding: 8px; text-align: right;"><em>Q<sub>Ed</sub></em> = {Q_Ed:.2f} кН</td>
<td style="padding: 8px; text-align: right;"><em>Q<sub>max</sub></em> = {Q_max_strip:.2f} кН</td>
<td style="padding: 8px; text-align: center;">{k_shear_strip:.1%}</td>
<td style="padding: 8px; text-align: center; color: #2ca02c; font-weight: bold;">✅ Полоса устойчива</td>
</tr>
<tr>
<td style="padding: 8px;">Прочность по наклонной трещине (хомуты 2∅8 s150)</td>
<td style="padding: 8px; text-align: center;">п. 8.1.32, ф. (8.56)</td>
<td style="padding: 8px; text-align: right;"><em>Q<sub>Ed</sub></em> = {Q_Ed:.2f} кН</td>
<td style="padding: 8px; text-align: right;"><em>Q<sub>ult</sub></em> = {Q_ult:.2f} кН (<em>Q<sub>b</sub></em>={Qb:.1f}, <em>Q<sub>sw</sub></em>={Qsw:.1f})</td>
<td style="padding: 8px; text-align: center;">{k_shear_crack:.1%}</td>
<td style="padding: 8px; text-align: center; color: #2ca02c; font-weight: bold;">✅ Прочность обеспечена</td>
</tr>
</tbody>
</table>
</div>
"""
display(HTML(html_report))