Architecture
System Overview
StructEngine-v2 is a full-stack web application for IS code-compliant structural engineering calculations. The system follows a calculator pattern architecture where each calculator is a self-contained module implementing the BaseCalculator interface.
Tech Stack:
Backend: FastAPI (Python 3.11) with Pydantic for validation
Frontend: Vue.js 3 with TypeScript
Documentation: Sphinx with autodoc and napoleon
Standards: IS 456:2000 (Concrete), IS 800:2007 (Steel), IS 875:1987 (Loads), IS 1893 (Seismic)
—
Module Structure
graph TD
A[FastAPI App] --> B[Calculator Router]
B --> C[Analysis Module]
B --> D[Concrete Module]
B --> E[Steel Module]
C --> F[Section Properties]
C --> G[Beam Analysis]
D --> H[Beam Design]
D --> I[Column Design]
D --> J[Slab Design]
D --> K[Crack Width]
D --> L[Footings]
E --> M[Base Plate]
E --> N[Steel Column]
E --> O[Purlin Design]
E --> P[Gantry Girder]
style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#bbf,stroke:#333,stroke-width:2px
style C fill:#bfb,stroke:#333,stroke-width:2px
style D fill:#fbf,stroke:#333,stroke-width:2px
style E fill:#ffb,stroke:#333,stroke-width:2px
Module Organization:
api/app/calculators/
├── base.py # BaseCalculator interface
├── analysis/
│ ├── section_properties.py # Geometric properties
│ └── beam_analysis.py # Deflection, moments, shear
├── concrete/ # IS 456:2000
│ ├── conc_beam_design.py
│ ├── conc_column_design.py
│ ├── slab_design.py
│ ├── crack_width.py
│ └── footing_types/
└── steel/ # IS 800:2007
├── base_plate.py
├── steel_column.py
├── purlin_design.py
└── gantry_girder.py
—
Calculation Flow
sequenceDiagram
participant Client
participant FastAPI
participant Router
participant Calculator
participant Pydantic
participant ISCode
Client->>FastAPI: POST /api/calculators/{type}/calculate
FastAPI->>Router: Route to calculator
Router->>Pydantic: Validate input schema
Pydantic->>Calculator: Pass validated inputs
Calculator->>ISCode: Apply IS code checks
ISCode->>Calculator: Return compliance status
Calculator->>Pydantic: Create output schema
Pydantic->>FastAPI: Validated output
FastAPI->>Client: JSON response
Request/Response Pattern:
Client request with calculator inputs (JSON)
Pydantic validation ensures type safety and constraints
Calculator.calculate() performs IS code-compliant calculations
IS code checks validate against clause requirements
Pydantic output structures results with IS references
JSON response returns to client
—
Design Patterns
### 1. Strategy Pattern
Used in Column Design for short vs. long column calculations:
class ColumnDesignStrategy:
"""Strategy interface for column design."""
def calculate_slenderness_moment(
self,
geometry: ColumnGeometry,
factored_axial_load: float,
effective_length: float,
depth_or_width: float
) -> float:
raise NotImplementedError
class ShortColumnStrategy(ColumnDesignStrategy):
"""Short columns: slenderness moment = 0"""
def calculate_slenderness_moment(...) -> float:
return 0.0
class LongColumnStrategy(ColumnDesignStrategy):
"""Long columns: IS 456 Clause 39.7.1"""
def calculate_slenderness_moment(...) -> float:
return (P × L²) / (2000 × D × 1000)
### 2. Parameter Objects (Dataclasses)
Group related inputs to reduce function complexity:
from dataclasses import dataclass
@dataclass
class ColumnGeometry:
"""Parameter object for column geometry."""
width: float # B (mm)
depth: float # D (mm)
unsupported_length_x: float
unsupported_length_y: float
clear_cover: float
main_bar_dia: float
tie_dia: float
@dataclass
class MaterialProperties:
"""Parameter object for material properties."""
fck: float # Concrete grade (N/mm²)
fy: float # Steel grade (N/mm²)
### 3. Method Extraction
Keep cyclomatic complexity < 10 per method:
class BeamDesignCalculator(BaseCalculator):
def calculate(self, inputs: dict) -> dict:
# High-level orchestration
geometry = self._extract_geometry(inputs)
loads = self._calculate_loads(geometry, inputs)
moments = self._calculate_moments(loads)
steel = self._design_steel(moments, geometry)
shear = self._design_shear(loads, geometry, steel)
return self._create_output(geometry, steel, shear)
def _extract_geometry(self, inputs: dict) -> Geometry:
"""Single-purpose method."""
pass
def _calculate_loads(self, geometry: Geometry, inputs: dict) -> Loads:
"""Single-purpose method."""
pass
—
IS Code Integration
### IS Code Reference Format
All calculators reference IS codes in docstrings:
def calculate_flexural_strength(self, d: float, Ast: float, fck: float, fy: float) -> float:
"""
Calculate ultimate moment capacity per IS 456:2000 Clause 38.1.
Args:
d: Effective depth (mm)
Ast: Area of tension steel (mm²)
fck: Characteristic compressive strength of concrete (N/mm²)
fy: Yield strength of steel (N/mm²)
Returns:
Ultimate moment capacity (kN-m)
References:
IS 456:2000 Clause 38.1 - Assumptions for flexure
IS 456:2000 Clause G-1.1 - Stress-strain curve for concrete
"""
pass
### IS Code Clause Mapping
IS 456:2000 (Concrete):
Clause 26.5.1.1: Flexural design
Clause 26.5.1.6: Shear design
Clause 39.4: Column axial capacity
Clause 39.7.1: Slenderness effects
Clause 35.3: Crack width limits
IS 800:2007 (Steel):
Clause 7.4.3: Base plate bearing
Clause 8.2: Column buckling
Clause 8.7: Lateral-torsional buckling
Table 2: Section classification
IS 875:1987 (Loads):
Part 1: Dead loads
Part 2: Live loads
Part 3: Wind loads
### Where IS Code Checks Are Implemented
Input validation: Pydantic Field constraints ensure IS code limits
Material properties: Grade mappings (M25, Fe415) from IS codes
Calculation methods: Direct implementation of IS code formulas
Output validation: Capacity ratios, safety factors per IS codes
Remarks: Warnings if design violates IS code limits
—
Type Safety and Validation
### Strict Type Hints
All functions use type hints per Agent.md guidelines:
from typing import Dict, List, Tuple, Optional
def analyze_beam(
span: float,
loads: List[float],
material: str
) -> Dict[str, float]:
"""Type hints are mandatory."""
pass
### Pydantic Validation
Input/output schemas enforce constraints:
class BeamDesignInput(BaseModel):
width: float = Field(..., gt=0, le=2000, description="Width in mm")
concrete_grade: str = Field(..., regex="^M(15|20|25|30|35|40|45|50)$")
steel_grade: str = Field(..., regex="^Fe(250|415|500|550)$")
—
Adding IS Code References
Step 1: Identify applicable IS code clause
Step 2: Add reference to docstring:
def check_deflection(self, span: float, deflection: float) -> bool:
"""
Check deflection limits per IS 456:2000 Clause 23.2.
Limit: span/250 for general structures.
"""
pass
Step 3: Implement formula from IS code:
limit = span / 250 # IS 456:2000 Clause 23.2(a)
return deflection <= limit
Step 4: Add to output remarks:
if not deflection_ok:
remarks.append("Deflection exceeds IS 456:2000 Clause 23.2 limits")
—
Testing Architecture
### Unit Tests
Test individual calculator methods:
def test_flexural_capacity():
calc = BeamDesignCalculator()
result = calc._calculate_flexural_capacity(
d=450, Ast=1256, fck=25, fy=415
)
assert result > 0
### Integration Tests
Test full calculate() flow:
def test_beam_design_full():
calc = BeamDesignCalculator()
result = calc.calculate({
"width": 300,
"depth": 500,
# ... full inputs
})
assert result["status"] == "PASS"
### API Tests
Test FastAPI endpoints:
def test_beam_design_endpoint(client):
response = client.post(
"/api/calculators/beam_design/calculate",
json={...}
)
assert response.status_code == 200
—
Performance Considerations
Caching: Material property lookups cached
Vectorization: NumPy used for section analysis
Profiling: interrogate enforces 80%+ docstring coverage
Type checking: mypy runs in pre-commit hooks
—
Next Steps
Review Getting Started for development setup
Follow Tutorials for practical examples
Explore Calculators API for complete API docs
Reference IS codes in
docs/references/