Metadata-Version: 2.4
Name: csfpy
Version: 0.1.1
Summary: An Analytical Engine for Non-Prismatic Structural Members
Author: Giovanni Boscu
License: GPL-3.0
Project-URL: Homepage, https://github.com/giovanniboscu/continuous-section-field
Project-URL: Repository, https://github.com/giovanniboscu/continuous-section-field
Keywords: structural-mechanics,analytical-engine,non-prismatic-beams,civil-engineering
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: matplotlib
Requires-Dist: PyYAML>=6.0
Requires-Dist: openseespy
Provides-Extra: examples
Requires-Dist: pycba; extra == "examples"
Provides-Extra: sp
Requires-Dist: shapely; extra == "sp"
Requires-Dist: sectionproperties; extra == "sp"
Dynamic: license-file

## Continuous Section Field (CSF)
### Continuous sectional properties for non-prismatic members via independent geometry and weight fields

[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.19076181.svg)](https://doi.org/10.5281/zenodo.19076181)
![Python](https://img.shields.io/badge/python-3.8+-blue.svg)
![Math](https://img.shields.io/badge/Engine-Analytical_Mechanics-red.svg)
![Integration](https://img.shields.io/badge/Integration-Gaussian_Quadrature-green.svg)
![License](https://img.shields.io/github/license/giovanniboscu/continuous-section-field)
![Repo Size](https://img.shields.io/github/repo-size/giovanniboscu/continuous-section-field)



**[Key Features](#key-features)** • **[Installation & setup](#setup-environment-linux--windows)** • **[Worked Example](#worked-example-continuously-tapered-t-beam)** • **[Validation: Cylinder](#csf-numerical-validation-circular-hollow-section)** • **[Case Study: NREL 5-MW](#csf-validation--numerical-case-study-nrel-5-mw-reference-wind-turbine-tower)**

---

### Motivation 

CSF complements standard FEM workflows by offering a continuous ruled-solid representation for non-prismatic members. It allows for the direct evaluation of section-property fields, ensuring a smooth transition of stiffness parameters without the need for manual multi-segment discretization


It computes continuous section property fields - $A(z)$, $Ix(z)$, $Iy(z)$...  - for tapered and non-homogeneous members, exported as **CSV** and **YAML** for direct integration with any beam solver (OpenSees, SAP2000, and others) or section analysis tools (e.g. [sectionproperties](https://github.com/robbievanleeuwen/section-properties)).

<p align="center">          
<img src="https://github.com/giovanniboscu/continuous-section-field/blob/main/images/twist_tower.jpg" alt="morphing" width="55%">
</p>


![Twisted Tower CSF Analysis](https://github.com/giovanniboscu/continuous-section-field/tree/main/actions-examples/morphingtower)


---
## CSF accepts two input files: geometry.yaml (cross-section definition) and actions.yaml (post-processing pipeline).

geometry.yaml file 
```yaml
# geometry.yaml
# Defines the cross-sectional geometry of the structural member.
# - sections: end cross-sections (S0, S1) with polygon vertices at each z-station
# - polygons: 2D closed polygons (CCW vertex order) that compose each cross-section
# - weight_laws: longitudinal participation laws w(z) that scale each polygon's
#   contribution along the member axis (independent of geometric interpolation)

CSF:
  sections:
    S0:
      z: 0.0
      polygons:
        startsection:
          weight: 1.0
          vertices:
            - [-0.4, -0.4]
            - [0.4, -0.4]
            - [0.4, 0.4]
            - [-0.4, 0.4]
    S1:
      z: 10.0
      polygons:
        endsection:
          weight: 1.0
          vertices:
            - [-0.2, -0.2]
            - [0.2, -0.2]
            - [0.2, 0.2]
            - [-0.2, 0.2]
  weight_laws:
    # parabolic reduction: full section at base (z=0), 72% at mid-span, full at top (z=10)
  - 'startsection,endsection:1.0 - 0.28 * (1 - (z / 10.0)**2)'            
```
actions.yaml file

```yaml
# actions.yaml
# Defines the post-processing operations to run on the CSF model.
# - stations: named z-coordinate sets used as analysis points
# - actions: ordered list of operations (3D plots, section analysis, property export, etc.)

CSF_ACTIONS:
  stations:
    station_edge:
      - 0
      - 10
  actions:  
    - plot_volume_3d:
        params:
          title: "Not prismatic"          
    - plot_weight:
        output:
          - stdout
    - plot_properties:
        properties: [A,Ix,Iy,Ip]
    - plot_section_2d:
        stations:
          - station_edge
    - section_selected_analysis:
        stations:
          - station_edge
        properties: [A, Cx, Cy, Ix, Iy, Ixy, Ip, I1, I2, rx, ry, Wx, Wy]
                                   

```
then run 

**python3 -m csf.CSFActions geometry.yaml actions.yaml**

**This is a minimal working CSF model:** two sections, one polygon per section, one weight law, and automatic evaluation of the resulting continuous properties along the member axis.

[full actions list/](https://github.com/giovanniboscu/continuous-section-field/tree/main/actions-examples/rectangle)  Complete worked example covering all available actions on a tapered rectangular section


[Full Python API example - Tapered T-beam](#worked-example-continuously-tapered-t-beam)

---



CSF models a member as a continuous field along the axis `z`, combining:

- **Geometry field**: arbitrary polygonal sections at stations ( `S0`, `S1`) with interpolation for tapered / varying shapes.
- **Weight field**: per-polygon custom participation factor $w_i(z)$ along z that scales each region’s effective contribution (not self-weight). [see Ekofisk Jacket Platform - Foundation Piles](https://github.com/giovanniboscu/continuous-section-field/blob/main/actions-examples/ekofisk/README.md) for a localized corrosion case.



### [Conceptual Model](https://github.com/giovanniboscu/continuous-section-field/blob/main/docs/model/geometric_material_decomposition.md)



## Key Features

- **Polygon-based section representation (algebraic composition)**: The element is geometrically defined by its end cross-sections, each represented as an algebraic composition of 2D polygons; intermediate sections are generated from these definitions along z. Curved outlines (e.g., circular shells/towers) are represented through discretized polygons with user-selected vertex count.

- **Per-polygon longitudinal weight laws $w_i(z)$**: property contributions can vary along the member axis independently of geometric interpolation. Weight laws can be defined analytically or via lookup-based expressions.
  - > Weight expressions have access to `w0`, `w1` (weights at sections s0/s1) and distance functions `d(i,j)`, `di(i,j)`, `de(i,j)` between polygon points.
    > [Custom Weight Laws](https://github.com/giovanniboscu/continuous-section-field/blob/main/docs/CSFLongitudinally-varying-homogenization-user-guide.md) 
 
Section vertices can be generated from any CAD tool or script 
that can sample points along a curve and export their coordinates.


> **Geometric scope and limitations**  
> CSF is not a FEM solver: it provides a geometric formulation for non-prismatic members and returns sectional properties (and derived stiffness fields) for beam-based analysis or external solvers.  
> Curved outlines are handled by polygonal approximation (increase the number of sides to reach the desired accuracy).

---


### CSFStacked module (segmented `ContinuousSectionField` stacking)

CSFStacked is a container that stacks multiple `ContinuousSectionField` segments along the global `z` axis and dispatches any query `z -> correct segment`.  
It adds a practical layer on top of multiple CSF segments: junctions are handled deterministically and you can query sections/properties anywhere with a single global API (section(z), section_full_analysis(z))

---
## 🛠 Installation

### Option A — Install from PyPI (recommended)

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install csfpy
```

### Option B — Install directly from GitHub

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install git+https://github.com/giovanniboscu/continuous-section-field.git
```

### Option C — Clone the repository and install locally

```bash
git clone https://github.com/giovanniboscu/continuous-section-field.git
cd continuous-section-field
python3 -m venv .venv
source .venv/bin/activate
pip install .
```

### Option D — Local editable install (development)

```bash
git clone https://github.com/giovanniboscu/continuous-section-field.git
cd continuous-section-field
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
```

---

## Optional Features

Some tools require additional dependencies and are not installed by default.

### SectionProperties-based tools (`csf_sp`)

```bash
pip install "csfpy[sp]"
```

> `csf_sp` is an optional tool and depends on external libraries such as `shapely` and `sectionproperties`.

---

## Basic Usage

### Run the core YAML-driven workflow

> The paths `geometry.yaml` and `actions.yaml` are resolved relative to the current working directory.

```bash
python3 -m csf.CSFActions geometry.yaml actions.yaml
```

### Run a verified example from the repository

> This example requires the repository to be cloned locally (see Installation Option B or C).

```bash
cd actions-examples/rectangle/
mkdir -p out
python -m csf.CSFActions geometry.yaml actions.yaml
```

---

## Tested Examples

### Linux / macOS

```bash
python3 example/nrel_5mw_tower.py
python3 example/cylinder_withcheck.py
python3 example/csf_rotated_validation_benchmark.py

cd actions-examples/stell_degradated_model
mkdir -p out
python3 -m csf.CSFActions stell_degradated_model_s.yaml stell_degradated_model_action.yaml
```

---

### Windows

```powershell
git clone https://github.com/giovanniboscu/continuous-section-field.git
cd continuous-section-field

python -m venv venv
.\venv\Scripts\activate

pip install -e .

python .\example\nrel_5mw_tower.py
python .\example\cylinder_withcheck.py
python .\example\csf_rotated_validation_benchmark.py
python .\example\tsection_lab.py

cd actions-examples\stell_degradated_model
mkdir -p out
python -m csf.CSFActions stell_degradated_model_s.yaml stell_degradated_model_action.yaml
```

---

## Package Notes

- Distribution name for installation: `csfpy`
- Python import name: `csf`
- Repository directory used in the commands above: `continuous-section-field`

```python
import csf
```

---

## Cross-sectional properties 

Section properties (area, inertia) are computed from geometry as:

$$
\text{Property}(z) = \sum_k w_k \, \text{Property}_k(z)
$$




 ![twist_tower_props](https://github.com/user-attachments/assets/dba77c34-967a-42af-8762-18861901cb52)

 [CSF – Section Full Analysis Output](https://github.com/giovanniboscu/continuous-section-field/blob/main/docs/sections/sectionfullanalysis.md)
 

---

# CSF Numerical Validation: Circular Hollow Section
`examples/cylinder_withcheck.py`

<img width="520" height="509" alt="circletest" src="https://github.com/user-attachments/assets/b3384be1-0a35-4654-b39b-aae614703ad0" />

To verify the accuracy of the numerical engine, a validation test was performed using a **non-tapered hollow cylinder** (steel pipe). This allows for a direct comparison between the library's results (based on weighted polygons) and exact analytical formulas.

The test script `cylinder_withcheck.py` models a tower with a diameter of 4.935m and a thickness of 23mm using a 512-sided polygon. The results demonstrate that the polygonal approximation converges to the analytical solution with exceptional precision.

### Extended Validation Report
The following table reports the full output of the validation script, comparing **Theoretical (Analytical)** values with the **Numerical** results generated by the library.

| Structural Property                  | Sym    | Theoretical        | Numerical          | Error             | Unit |
|-------------------------------------|--------|--------------------|--------------------|-------------------|------|
| Net material cross-section          | A      | 3.54924572e-01     | 3.54915663e-01     | 0.0025%           | m²   |
| Horizontal center of mass           | Cx     | 0.00000000e+00     | 5.44816314e-15     | 5.45e-15 (abs)    | m    |
| Vertical center of mass             | Cy     | 0.00000000e+00     | -4.12383916e-14    | 4.12e-14 (abs)    | m    |
| Axial stiffness                     | EA     | 7.45341600e+10     | 7.45322893e+10     | 0.0025%           | N    |
| Bending stiffness about X           | EIxx   | 2.24797570e+11     | 2.24786286e+11     | 0.0050%           | N·m² |
| Bending stiffness about Y           | EIyy   | 2.24797570e+11     | 2.24786286e+11     | 0.0050%           | N·m² |
| Symmetry check (Ixy)                | Ixy    | 0.00000000e+00     | 3.45889405e-15     | 3.46e-15 (abs)    | m⁴   |
| Torsional stiffness constant        | J      | 2.14092924e+00     | 2.14082177e+00     | 0.0050%           | m⁴   |
| Torsional stiffness (GJ)            | GJ     | 1.72987083e+11     | 1.72978399e+11     | 0.0050%           | N·m² |
| Maximum bending stiffness           | EI_max | 2.24797570e+11     | 2.24786286e+11     | 0.0050%           | N·m² |
| Minimum bending stiffness           | EI_min | 2.24797570e+11     | 2.24786286e+11     | 0.0050%           | N·m² |
| Principal axis rotation             | Alpha  | 0.00000000e+00     | 0.00000000e+00     | 0.0000% (Iso)     | deg  |
| Buckling radius about X             | rx     | 1.73667329e+00     | 1.73665150e+00     | 0.0013%           | m    |
| Buckling radius about Y             | ry     | 1.73667329e+00     | 1.73665150e+00     | 0.0013%           | m    |
| First moment of area (Shear)        | Q      | 2.77471084e-01     | 2.77460637e-01     | 0.0038%           | m³   |
| Elastic Section Modulus             | W      | 4.33825580e-01     | 4.33803803e-01     | 0.0050%           | m³   |
| Mass per unit length                | m_lin  | 2.78615789e+03     | 2.78608796e+03     | 0.0025%           | kg/m |

**Total Calculated Tower Volume:** 31.041 m³  
**Total Calculated Tower Mass:**   243.676 t  

| Description          | Theoretical | Numerical | Error   | Unit |
|----------------------|-------------|-----------|---------|------|
| Total Tower Mass     | 244.067     | 244.061   | 0.0025% | t    |

  
## CSF Validation : Numerical Case Study: NREL 5-MW Reference Wind Turbine Tower

- NREL 5-MW reference turbine report:
  Jonkman, J., Butterfield, S., Musial, W., and Scott, G.  
  "Definition of a 5-MW Reference Wind Turbine for Offshore System Development,"  
  NREL/TP-500-38060, February 2009.
  - [Download PDF (NREL)](https://www.nrel.gov/docs/fy09osti/38060.pdf)
  - [OpenFAST documentation](https://openfast.readthedocs.io/en/main/)
  - [NREL wind research portal](https://www.nrel.gov/wind/)
    

## 512-sided polygons

[NREL 5-MW Tower — CSF Actions Example](https://github.com/giovanniboscu/continuous-section-field/tree/main/actions-examples/nrel_5mw)

> CSF is listed as a third-party tool in the [OpenFAST documentation](https://openfast.readthedocs.io/en/main/source/working.html#third-part-tools).

<img width="423" height="609" alt="NREL-5-MW" src="https://github.com/user-attachments/assets/712ec7c1-3b7c-4a99-aa7d-791dbbc6eb53" />

**CSF** computes continuous sectional properties along the tower height \(z\) - \(A(z)\), \(EI(z)\), \(GJ(z)\), etc. - compatible with OpenFAST ElastoDyn/SubDyn distributed property requirements and validated against NREL 5‑MW reference data.


The script `example/nrel_5mw_tower.py` is used to demonstrate the library's performance on complex, real-world structural members. A full-scale model of the **NREL 5-MW Reference Wind Turbine Tower** was implemented. The geometry and material properties strictly follow the technical report *"Definition of a 5-MW Reference Wind Turbine for Offshore System Development"* (NREL/TP-500-38060).

The following tables provide a side-by-side comparison between the **Numerical results generated by CSF** and the **official NREL reference data (Table 6-1 of the official PDF)**.

Density = 8500 kg/m3
### CSF Numerical Results (Generated Model)

| Elevation [m] | HtFract | TMassDen [kg/m] | TwFAStif [N·m²] | TwSSStif [N·m²] | TwGJStif [N·m²] | TwEAStif [N] | TwFAIner [kg·m] | TwSSIner [kg·m] |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| 0.00 | 0.000 | 5590.73 | 6.1431e+11 | 6.1431e+11 | 4.7273e+11 | 1.3812e+11 | 2.49e+04 | 2.49e+04 |
| 8.76 | 0.100 | 5232.30 | 5.3479e+11 | 5.3479e+11 | 4.1154e+11 | 1.2927e+11 | 2.16e+04 | 2.16e+04 |
| 17.52 | 0.200 | 4885.64 | 4.6324e+11 | 4.6324e+11 | 3.5648e+11 | 1.2070e+11 | 1.88e+04 | 1.88e+04 |
| 26.28 | 0.300 | 4550.76 | 3.9911e+11 | 3.9911e+11 | 3.0713e+11 | 1.1243e+11 | 1.62e+04 | 1.62e+04 |
| 35.04 | 0.400 | 4227.65 | 3.4187e+11 | 3.4187e+11 | 2.6307e+11 | 1.0445e+11 | 1.38e+04 | 1.38e+04 |
| 43.80 | 0.500 | 3916.31 | 2.9100e+11 | 2.9100e+11 | 2.2393e+11 | 9.6756e+10 | 1.18e+04 | 1.18e+04 |
| 52.56 | 0.600 | 3616.74 | 2.4601e+11 | 2.4601e+11 | 1.8931e+11 | 8.9355e+10 | 9.96e+03 | 9.96e+03 |
| 61.32 | 0.700 | 3328.95 | 2.0645e+11 | 2.0645e+11 | 1.5887e+11 | 8.2245e+10 | 8.36e+03 | 8.36e+03 |
| 70.08 | 0.800 | 3052.93 | 1.7184e+11 | 1.7184e+11 | 1.3224e+11 | 7.5425e+10 | 6.96e+03 | 6.96e+03 |
| 78.84 | 0.900 | 2788.68 | 1.4177e+11 | 1.4177e+11 | 1.0909e+11 | 6.8897e+10 | 5.74e+03 | 5.74e+03 |
| 87.60 | 1.000 | 2536.21 | 1.1581e+11 | 1.1581e+11 | 8.9122e+10 | 6.2659e+10 | 4.69e+03 | 4.69e+03 |


**Total Calculated Tower Volume:** 40.8634 m³  
**Total Calculated Tower Mass:**   347.339 t  
&nbsp;


| Elevation [m] | HtFract | TMassDen [kg/m] | TwFAStif [N·m²] | TwSSStif [N·m²] | TwGJStif [N·m²] | TwEAStif [N] | TwFAIner [kg·m] | TwSSIner [kg·m] |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| 0.00 | 0.000 | 5590.9 | 6.143e+11 | 6.143e+11 | 4.728e+11 | 1.381e+11 | 2.49e+04 | 2.49e+04 |
| 8.76 | 0.100 | 5232.4 | 5.348e+11 | 5.348e+11 | 4.116e+11 | 1.293e+11 | 2.16e+04 | 2.16e+04 |
| 17.52 | 0.200 | 4885.8 | 4.633e+11 | 4.633e+11 | 3.565e+11 | 1.207e+11 | 1.88e+04 | 1.88e+04 |
| 26.28 | 0.300 | 4550.9 | 3.991e+11 | 3.991e+11 | 3.071e+11 | 1.124e+11 | 1.62e+04 | 1.62e+04 |
| 35.04 | 0.400 | 4227.8 | 3.419e+11 | 3.419e+11 | 2.631e+11 | 1.044e+11 | 1.38e+04 | 1.38e+04 |
| 43.80 | 0.500 | 3916.4 | 2.910e+11 | 2.9100e+11 | 2.239e+11 | 9.676e+10 | 1.18e+04 | 1.18e+04 |
| 52.56 | 0.600 | 3616.8 | 2.460e+11 | 2.460e+11 | 1.893e+11 | 8.936e+10 | 9.96e+03 | 9.96e+03 |
| 61.32 | 0.700 | 3329.0 | 2.065e+11 | 2.065e+11 | 1.589e+11 | 8.225e+10 | 8.36e+03 | 8.36e+03 |
| 70.08 | 0.800 | 3053.0 | 1.718e+11 | 1.718e+11 | 1.322e+11 | 7.543e+10 | 6.96e+03 | 6.96e+03 |
| 78.84 | 0.900 | 2788.8 | 1.418e+11 | 1.418e+11 | 1.091e+11 | 6.890e+10 | 5.74e+03 | 5.74e+03 |
| 87.60 | 1.000 | 2536.3 | 1.158e+11 | 1.158e+11 | 8.913e+10 | 6.266e+10 | 4.69e+03 | 4.69e+03 |

**Total NREL 5-MW Ref. Mass:** 347.460 t

### Relative error (Generated − Reference) / Reference × 100

| Elevation [m] | HtFract | TMassDen [kg/m] | TwFAStif [N·m²] | TwSSStif [N·m²] | TwGJStif [N·m²] | TwEAStif [N] | TwFAIner [kg·m] | TwSSIner [kg·m] |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| 0.00% | 0.00% | 0.0030% | 0.0016% | 0.0016% | 0.0148% | 0.0145% | 0.00% | 0.00% |
| 0.00% | 0.00% | 0.0019% | 0.0019% | 0.0019% | 0.0146% | 0.0232% | 0.00% | 0.00% |
| 0.00% | 0.00% | 0.0033% | 0.0130% | 0.0130% | 0.0056% | 0.0000% | 0.00% | 0.00% |
| 0.00% | 0.00% | 0.0031% | 0.0025% | 0.0025% | 0.0098% | 0.0267% | 0.00% | 0.00% |
| 0.00% | 0.00% | 0.0035% | 0.0088% | 0.0088% | 0.0114% | 0.0479% | 0.00% | 0.00% |
| 0.00% | 0.00% | 0.0023% | 0.0000% | 0.0000% | 0.0134% | 0.0041% | 0.00% | 0.00% |
| 0.00% | 0.00% | 0.0017% | 0.0041% | 0.0041% | 0.0158% | 0.0056% | 0.00% | 0.00% |
| 0.00% | 0.00% | 0.0015% | 0.0242% | 0.0242% | 0.0189% | 0.0061% | 0.00% | 0.00% |
| 0.00% | 0.00% | 0.0023% | 0.0233% | 0.0233% | 0.0302% | 0.0066% | 0.00% | 0.00% |
| 0.00% | 0.00% | 0.0043% | 0.0212% | 0.0212% | 0.0092% | 0.0044% | 0.00% | 0.00% |
| 0.00% | 0.00% | 0.0035% | 0.0086% | 0.0086% | 0.0090% | 0.0016% | 0.00% | 0.00% |

## Validation Summary

- All discrepancies are **well below 0.05%**.
- Differences are attributable to **rounding and numerical precision**.
- The generated CSF tower properties **faithfully reproduce** the NREL 5-MW reference.


---

## Worked Example: Continuously Tapered T-Beam
This section demonstrates how to model a structural member where the geometry transitions smoothly between two different T-profiles.

<img width="456" height="469" alt="tsec3d" src="https://github.com/user-attachments/assets/03884190-0e15-43b4-a45d-b0ba9cacbbb7" />

<img width="503" height="464" alt="tsec2d" src="https://github.com/user-attachments/assets/a39e6e6e-afd1-43dd-b755-7299d211cd55" />

<details>
        
<summary>Click to expand the full T-Beam Python example</summary>

```python
# --- Core CSF imports used in this minimal example ---
from csf import (
    Pt, Polygon,integrate_volume,section_statical_moment_partial,section_properties, section_derived_properties,Section, ContinuousSectionField,Visualizer,
    section_full_analysis, section_print_analysis,section_full_analysis_keys
)
# ----------------------------------------------------------------------------------
# 1. DEFINE START SECTION (Z = 0)
# ----------------------------------------------------------------------------------
#   GUIDELINES FOR POLYGON CONSTRUCTION:
# - COUNTER-CLOCKWISE POLYGON
# - VERTICES ORDER: You MUST define vertices in COUNTER-CLOCKWISE (CCW) order.
#   This is MANDATORY for the Shoelace/Green's Theorem algorithm to compute a
#   POSITIVE Area and correct Moments of Inertia. Clockwise order will result
#   in negative area values and mathematically incorrect results.
# - WEIGHT: Use 1.0 for solid parts and 0 to define voids/holes.
# - The start section here is a T-shape composed of two non-overlapping polygons:
#   a "flange" (top horizontal) and a "web" (vertical stem).
# ----------------------------------------------------------------------------------

# Flange Definition: Rectangle from (-1, -0.2) to (1, 0.2)
# Order: Bottom-Left -> Bottom-Right -> Top-Right -> Top-Left (CCW)
poly0_start = Polygon(
    vertices=(Pt(-1, -0.2), Pt(1, -0.2), Pt(1, 0.2), Pt(-1, 0.2)),
    weight=1.0,
    name="flange",
)

# Web Definition: Rectangle from (-0.2, -1.0) to (0.2, 0.2)
# Order: Bottom-Left -> Bottom-Right -> Top-Right -> Top-Left (CCW)
poly1_start = Polygon(
    vertices=(Pt(-0.2, -1.0), Pt(0.2, -1.0), Pt(0.2, -0.2), Pt(-0.2, -0.2)),
    weight=1.0,
    name="web",
)

# ----------------------------------------------------------------------------------
# 2. DEFINE END SECTION (Z = 10)
# ----------------------------------------------------------------------------------
# GEOMETRIC CONSISTENCY:
# - To enable linear interpolation (tapering), the end section must contain the
#   same number of polygons with the same names as the start section.
# - The web depth here increases linearly from 1.0 down to 2.5 (negative Y direction),
#   creating a tapered profile along the longitudinal Z-axis.
# ----------------------------------------------------------------------------------

# Flange remains unchanged for this prismatic top part
poly0_end = Polygon(
    vertices=(Pt(-1, -0.2), Pt(1, -0.2), Pt(1, 0.2), Pt(-1, 0.2)),
    weight=1.0,
    name="flange",
)

# Web becomes deeper: Y-bottom moves from -1.0 to -2.5
# MAINTAIN CCW ORDER: Bottom-Left -> Bottom-Right -> Top-Right -> Top-Left
poly1_end = Polygon(
    vertices=(Pt(-0.2, -2.5), Pt(0.2, -2.5), Pt(0.2, -0.2), Pt(-0.2, -0.2)),
    weight=1.0,
    name="web",
)

# ----------------------------------------------------------------------------------
# 3. CREATE SECTIONS WITH Z-COORDINATES
# ----------------------------------------------------------------------------------
# Sections act as containers for polygons at a specific coordinate along the beam axis.
# All polygons defined at Z=0.0 are grouped into s0, and those at Z=10.0 into s1.
# ----------------------------------------------------------------------------------

s0 = Section(polygons=(poly0_start, poly1_start), z=0.0)
s1 = Section(polygons=(poly0_end, poly1_end), z=10.0)

# --------------------------------------------------------
# 4. INITIALIZE CONTINUOUS SECTION FIELD
# --------------------------------------------------------
# A linear interpolator is used to generate intermediate
# sections between Z = 0 and Z = 10.
field = ContinuousSectionField(section0=s0, section1=s1)

# --------------------------------------------------------
# 5. PRIMARY SECTION PROPERTIES (Z = 5.0)
# --------------------------------------------------------
# Properties are computed at mid-span.
sec_mid = field.section(5.0)
props = section_properties(sec_mid)

print("\n" + "="*40)
print("PRIMARY PROPERTIES AT Z=5.0 (Centroidal)")
print("="*40)
print(f"A:   {props['A']:.4f}      # Net Cross-Sectional Area")
print(f"Cx:  {props['Cx']:.4f}     # Horizontal Centroid location (Global X)")
print(f"Cy:  {props['Cy']:.4f}     # Vertical Centroid location (Global Y)")
print(f"Ix:  {props['Ix']:.4f}     # Second Moment of Area about Centroidal X-axis")
print(f"Iy:  {props['Iy']:.4f}     # Second Moment of Area about Centroidal Y-axis")
print(f"Ixy: {props['Ixy']:.4f}    # Product of Inertia (Measure of asymmetry)")

# 2. DERIVED PROPERTIES (Radius of Gyration, Principal Axes)
derived = section_derived_properties(props)
print("\n" + "-"*40)
print("DERIVED GEOMETRIC PROPERTIES")
print("-"*40)
print(f"rx:  {derived['rx']:.4f}     # Radius of Gyration about X (sqrt(Ix/A))")
print(f"ry:  {derived['ry']:.4f}     # Radius of Gyration about Y (sqrt(Iy/A))")
print(f"I1:  {derived['I1']:.4f}     # Maximum Principal Moment of Area")
print(f"I2:  {derived['I2']:.4f}     # Minimum Principal Moment of Area")
print(f"Deg: {derived['theta_deg']:.2f}°   # Principal Axis Rotation Angle")

# --------------------------------------------------------
# 7. STATICAL MOMENT OF AREA (Q)
# --------------------------------------------------------
# Computed at the neutral axis (y = Cy).
# Used in shear stress calculations.
Q_na = section_statical_moment_partial(sec_mid, y_cut=props['Cy'])
print("\n" + "-"*40)
print("SHEAR ANALYSIS PROPERTIES")
print("-"*40)
print(f"Q_na: {Q_na:.4f}    # First Moment of Area above Neutral Axis (for shear stress)")

# 8. VOLUMETRIC PROPERTIES
total_vol = integrate_volume(field,0,10)
print("\n" + "="*40)
print("GLOBAL FIELD PROPERTIES (3D)")
print("="*40)
print(f"Total Volume: {total_vol:.4f} # Total material volume of the ruled solid")

# Technical Explanation for the negative Cy
print("\n" + "-"*50)
print("TECHNICAL NOTE ON COORDINATES:")
print("-"*50)
print("The negative value for 'Cy' is physically correct.")
print("In this model, the flange is centered at y=0, while the web")
print("extends downwards (from y=0.2 to y=-1.0 at Z=0, and y=-2.5 at Z=10).")
print("Since the majority of the T-section's mass is located below the")
print("global X-axis (y=0), the centroid MUST have a negative Y-coordinate.")
print("This indicates the geometric center is below the drawing origin.")
print("-"*50)

# --------------------------------------------------------
# 9. VISUALIZATION
# --------------------------------------------------------
# - 2D section plot at Z = 5.0
# - 3D ruled solid visualization
viz = Visualizer(field)

# Generate 2D plot for the specified slice
viz.plot_section_2d(z=5.0)

# Generate 3D plot of the interpolated solid
# line_percent determines the density of the longitudinal ruled lines
viz.plot_volume_3d(line_percent=100.0, seed=1)

import matplotlib.pyplot as plt
plt.show()

```
</details>

---
### How to Cite this Library
<details>
<summary>Click for BibTeX citation</summary>

```bibtex
@software{boscu_continuous_2026,
  author = {Boscu, Giovanni},
  title = {Continuous Section Field (CSF): A geometric and mechanical engine for non-prismatic structural members},
  year = {2026},
  publisher = {Zenodo},
  version = {v2.0.0},
  doi = {10.5281/zenodo.19076181},
  url = {https://doi.org/10.5281/zenodo.19076181}
}
```
</details>

---
## License
This project is licensed under the **GNU General Public License v3.0** - see the [LICENSE](LICENSE) file for details.
