Source code for mento.settings
from dataclasses import dataclass, field, fields
from typing import Any, ClassVar, Dict
from mento.units import mm, inch
# Sentinel to detect if user passed a value
_NOT_SET = object()
[docs]
@dataclass
class BeamSettings:
"""
Settings for beam design with separate metric and imperial defaults.
Can optionally be initialized with a `Concrete` material to determine the unit system.
Available Parameters with Default Values:
--------------------------------------
Unit system: "metric" or "imperial"
Metric Defaults:
- clear_spacing: 25 mm
- stirrup_diameter_ini: 8 mm
- vibrator_size: 30 mm
- layers_spacing: 25 mm
- max_diameter_diff: 5 mm
- minimum_longitudinal_diameter: 8 mm
- max_longitudinal_diameter: 32 mm
- max_bars_per_layer: 12
Imperial Defaults:
- clear_spacing: 1 inch
- stirrup_diameter_ini: 3/8 inch
- vibrator_size: 1.25 inch
- layers_spacing: 1 inch
- max_diameter_diff: 0.25 inch
- minimum_longitudinal_diameter: 3/8 inch
- max_longitudinal_diameter: 1.693 inch
- max_bars_per_layer: 12
"""
# Class-level default values (documented but not shown in hover)
_metric_defaults: ClassVar[Dict[str, Any]] = {
"clear_spacing": 25 * mm,
"stirrup_diameter_ini": 8 * mm,
"vibrator_size": 30 * mm,
"layers_spacing": 25 * mm,
"max_diameter_diff": 5 * mm,
"minimum_longitudinal_diameter": 8 * mm,
"max_longitudinal_diameter": 32 * mm,
"max_bars_per_layer": 12,
}
_imperial_defaults: ClassVar[Dict[str, Any]] = {
"clear_spacing": 1 * inch,
"stirrup_diameter_ini": 3 / 8 * inch,
"vibrator_size": 1.25 * inch,
"layers_spacing": 1 * inch,
"max_diameter_diff": 0.25 * inch,
"minimum_longitudinal_diameter": 3 / 8 * inch,
"max_longitudinal_diameter": 1.693 * inch,
"max_bars_per_layer": 12,
}
unit_system: str = "metric"
clear_spacing: Any = field(default=_NOT_SET)
stirrup_diameter_ini: Any = field(default=_NOT_SET)
vibrator_size: Any = field(default=_NOT_SET)
layers_spacing: Any = field(default=_NOT_SET)
max_diameter_diff: Any = field(default=_NOT_SET)
minimum_longitudinal_diameter: Any = field(default=_NOT_SET)
max_longitudinal_diameter: Any = field(default=_NOT_SET)
max_bars_per_layer: Any = field(default=_NOT_SET)
def __post_init__(self) -> None:
defaults = self._imperial_defaults if self.unit_system == "imperial" else self._metric_defaults
for f in fields(self):
if not f.init or f.name == "unit_system":
continue
current_value = getattr(self, f.name)
if current_value is _NOT_SET:
setattr(self, f.name, defaults[f.name])
if self.max_bars_per_layer < 1:
raise ValueError("max_bars_per_layer must be at least 1")
def __str__(self) -> str:
"""Returns only the current settings, excluding class defaults."""
settings_list = []
for name, value in vars(self).items():
# Skip private and special attributes, and the unit_system field
if not name.startswith("_") and name != "unit_system":
if hasattr(value, "magnitude") and hasattr(value, "units"): # It's a Quantity
settings_list.append(f"{name}: {value.magnitude:.2f} {value.units:~}")
else:
settings_list.append(f"{name}: {value}")
return "\n".join(settings_list)