lythosle 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lythosle-0.1.0/LICENSE +21 -0
- lythosle-0.1.0/MANIFEST.in +8 -0
- lythosle-0.1.0/PKG-INFO +291 -0
- lythosle-0.1.0/README.md +257 -0
- lythosle-0.1.0/docs/examples/homogeneous.json +56 -0
- lythosle-0.1.0/docs/examples/layered_water.json +129 -0
- lythosle-0.1.0/docs/examples/reinforced.json +108 -0
- lythosle-0.1.0/docs/examples/seismic.json +115 -0
- lythosle-0.1.0/docs/examples/soft_foundation.json +117 -0
- lythosle-0.1.0/docs/examples/tension_crack.json +82 -0
- lythosle-0.1.0/docs/model-format.md +125 -0
- lythosle-0.1.0/docs/theory.md +225 -0
- lythosle-0.1.0/lythosle/__init__.py +35 -0
- lythosle-0.1.0/lythosle/__main__.py +3 -0
- lythosle-0.1.0/lythosle/analysis.py +429 -0
- lythosle-0.1.0/lythosle/cli.py +173 -0
- lythosle-0.1.0/lythosle/examples.py +208 -0
- lythosle-0.1.0/lythosle/geometry.py +241 -0
- lythosle-0.1.0/lythosle/materials.py +135 -0
- lythosle-0.1.0/lythosle/methods.py +582 -0
- lythosle-0.1.0/lythosle/model.py +431 -0
- lythosle-0.1.0/lythosle/search.py +463 -0
- lythosle-0.1.0/lythosle/slices.py +369 -0
- lythosle-0.1.0/lythosle/web/__init__.py +10 -0
- lythosle-0.1.0/lythosle/web/api.py +108 -0
- lythosle-0.1.0/lythosle/web/app.py +69 -0
- lythosle-0.1.0/lythosle/web/server.py +125 -0
- lythosle-0.1.0/lythosle/web/static/app.js +991 -0
- lythosle-0.1.0/lythosle/web/static/fonts/inter-400-latin-ext.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts/inter-400-latin.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts/inter-500-latin-ext.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts/inter-500-latin.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts/inter-600-latin-ext.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts/inter-600-latin.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts/newsreader-400-latin-ext.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts/newsreader-400-latin.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts/newsreader-400i-latin-ext.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts/newsreader-400i-latin.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts/newsreader-500-latin-ext.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts/newsreader-500-latin.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts/newsreader-600-latin-ext.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts/newsreader-600-latin.woff2 +0 -0
- lythosle-0.1.0/lythosle/web/static/fonts.css +125 -0
- lythosle-0.1.0/lythosle/web/static/index.html +271 -0
- lythosle-0.1.0/lythosle/web/static/styles.css +456 -0
- lythosle-0.1.0/lythosle.egg-info/PKG-INFO +291 -0
- lythosle-0.1.0/lythosle.egg-info/SOURCES.txt +59 -0
- lythosle-0.1.0/lythosle.egg-info/dependency_links.txt +1 -0
- lythosle-0.1.0/lythosle.egg-info/entry_points.txt +2 -0
- lythosle-0.1.0/lythosle.egg-info/requires.txt +4 -0
- lythosle-0.1.0/lythosle.egg-info/top_level.txt +1 -0
- lythosle-0.1.0/main.py +57 -0
- lythosle-0.1.0/pyproject.toml +54 -0
- lythosle-0.1.0/setup.cfg +4 -0
- lythosle-0.1.0/tests/__init__.py +0 -0
- lythosle-0.1.0/tests/test_examples.py +55 -0
- lythosle-0.1.0/tests/test_geometry.py +87 -0
- lythosle-0.1.0/tests/test_methods.py +229 -0
- lythosle-0.1.0/tests/test_model.py +85 -0
- lythosle-0.1.0/tests/test_search.py +166 -0
- lythosle-0.1.0/tests/test_web.py +171 -0
lythosle-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lythosle contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
lythosle-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lythosle
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Limit equilibrium slope stability analysis with a browser front end
|
|
5
|
+
Author-email: Hasan Deniz Altuntaş <lythosfea@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/hdaltuntas/lythosle
|
|
8
|
+
Project-URL: Source, https://github.com/hdaltuntas/lythosle
|
|
9
|
+
Project-URL: Repository, https://github.com/hdaltuntas/lythosle
|
|
10
|
+
Project-URL: Issues, https://github.com/hdaltuntas/lythosle/issues
|
|
11
|
+
Project-URL: Documentation, https://github.com/hdaltuntas/lythosle/blob/main/docs/theory.md
|
|
12
|
+
Project-URL: Validation, https://github.com/hdaltuntas/lythosle/blob/main/README.md#validation
|
|
13
|
+
Keywords: geotechnical,slope stability,limit equilibrium,factor of safety,bishop,janbu,spencer,morgenstern-price,method of slices,civil engineering,geotechnics
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Intended Audience :: Education
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering
|
|
25
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
26
|
+
Classifier: Typing :: Typed
|
|
27
|
+
Requires-Python: >=3.9
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Provides-Extra: fastapi
|
|
31
|
+
Requires-Dist: fastapi>=0.100; extra == "fastapi"
|
|
32
|
+
Requires-Dist: uvicorn>=0.23; extra == "fastapi"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# Lythos LE
|
|
36
|
+
|
|
37
|
+
Limit equilibrium slope stability analysis in pure Python, with a browser front end.
|
|
38
|
+
|
|
39
|
+
Lythos LE computes the factor of safety of slopes and embankments with the method
|
|
40
|
+
of slices, the same class of analysis as Rocscience Slide or GeoStudio SLOPE/W.
|
|
41
|
+
It searches for the critical slip surface, reports every classical method on it,
|
|
42
|
+
and draws the section in the browser.
|
|
43
|
+
|
|
44
|
+
* **No dependencies.** The solver, the web server and the front end are standard
|
|
45
|
+
library and vanilla JavaScript. `python -m lythosle serve` works on a bare
|
|
46
|
+
Python 3.9+ install with nothing to pip install.
|
|
47
|
+
* **Eight methods**, from Fellenius to Morgenstern-Price, all built on one slice
|
|
48
|
+
formulation so the differences between them are the assumptions, not the code.
|
|
49
|
+
* **Validated** against closed-form solutions, Taylor's stability numbers and the
|
|
50
|
+
ACADS benchmark problem (see [Validation](#validation)).
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/hdaltuntas/lythosle
|
|
60
|
+
cd lythosle
|
|
61
|
+
|
|
62
|
+
python main.py # browser interface on http://127.0.0.1:8000
|
|
63
|
+
python main.py example # list the built-in examples
|
|
64
|
+
python main.py example homogeneous # run one and print the report
|
|
65
|
+
python -m unittest discover -s tests # run the test suite
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Nothing needs installing. `main.py` takes everything the CLI does and starts
|
|
69
|
+
the web interface when given nothing; `HOST` and `PORT` override the address,
|
|
70
|
+
so a host that sets `PORT` gets a server bound to every interface. The same
|
|
71
|
+
commands are available as `python -m lythosle …`, and `pip install -e .` adds a
|
|
72
|
+
`lythosle` command.
|
|
73
|
+
|
|
74
|
+
## What it does
|
|
75
|
+
|
|
76
|
+
| | |
|
|
77
|
+
|---|---|
|
|
78
|
+
| **Methods** | Ordinary (Fellenius), Bishop simplified, Janbu simplified and corrected, Corps of Engineers #1, Lowe-Karafiath, Spencer, Morgenstern-Price (half-sine, constant or trapezoidal interslice function) |
|
|
79
|
+
| **Surfaces** | Circular (grid-and-tangent search with adaptive box and refinement), a single specified circle, a user-defined non-circular surface, and non-circular optimisation from the critical circle |
|
|
80
|
+
| **Strength** | Effective stress (c', phi'), undrained (s<sub>u</sub>, optionally increasing linearly with depth), impenetrable and no-strength materials |
|
|
81
|
+
| **Groundwater** | Piezometric water table, per-material pore pressure ratio r<sub>u</sub>, separate saturated unit weights, ponded water on the slope |
|
|
82
|
+
| **Loading** | Surface surcharges, pseudo-static seismic coefficients k<sub>h</sub> and k<sub>v</sub>, reinforcement (nails, anchors, geosynthetics), tension cracks with optional water pressure |
|
|
83
|
+
| **Output** | Factor of safety per method, the critical surface, a full slice force table (CSV), the lambda-FS plot for Spencer/Morgenstern-Price, the search grid, JSON for everything |
|
|
84
|
+
|
|
85
|
+
## The three ways in
|
|
86
|
+
|
|
87
|
+
### Browser
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
python -m lythosle serve --port 8000 --open
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Build the geometry from a template or by typing coordinates, set up materials,
|
|
94
|
+
groundwater and loading in the sidebar, then **Run analysis** (or Ctrl/Cmd +
|
|
95
|
+
Enter). The section view shows the layers, the phreatic surface, the critical
|
|
96
|
+
surface with its centre of rotation, the search grid coloured by factor of
|
|
97
|
+
safety, the slices and the reinforcement. Results can be exported as SVG, CSV
|
|
98
|
+
and JSON. The interface follows the system light/dark setting; the toggle in
|
|
99
|
+
the header pins it.
|
|
100
|
+
|
|
101
|
+
`?example=layered_water` and `?theme=dark` work as URL parameters.
|
|
102
|
+
|
|
103
|
+
The interface follows Claude's design language: the ivory and charcoal
|
|
104
|
+
surfaces, the clay accent, sentence-case labels and a serif for the wordmark,
|
|
105
|
+
headings and prose. Claude's own faces (Styrene, Tiempos, Copernicus) are
|
|
106
|
+
licensed, so the stack asks for them first and falls back to Inter and
|
|
107
|
+
Newsreader, which are bundled in `lythosle/web/static/fonts/` — nothing is
|
|
108
|
+
fetched from a CDN at runtime, and the page looks the same offline.
|
|
109
|
+
|
|
110
|
+
If you prefer FastAPI, `uvicorn lythosle.web.app:app` serves exactly the same
|
|
111
|
+
API (`pip install fastapi uvicorn` first).
|
|
112
|
+
|
|
113
|
+
### Command line
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
lythosle analyze model.json --method bishop --method spencer \
|
|
117
|
+
--slices 60 --json result.json --csv slices.csv
|
|
118
|
+
lythosle example seismic --optimize
|
|
119
|
+
lythosle methods
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`analyze` takes either a bare model file or a `{"model": ..., "options": ...}`
|
|
123
|
+
file — which is exactly what the browser's **Download** button produces.
|
|
124
|
+
|
|
125
|
+
### Python
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from lythosle import SlopeModel, AnalysisOptions, analyze
|
|
129
|
+
|
|
130
|
+
model = SlopeModel.from_dict({
|
|
131
|
+
"profile": [[0, 0], [10, 0], [30, 10], [50, 10]],
|
|
132
|
+
"materials": [{"name": "fill", "unit_weight": 20, "cohesion": 3,
|
|
133
|
+
"friction_angle": 19.6}],
|
|
134
|
+
"layers": [{"material": "fill"}],
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
result = analyze(model, AnalysisOptions.from_dict({
|
|
138
|
+
"methods": ["bishop", "spencer"],
|
|
139
|
+
"n_slices": 60,
|
|
140
|
+
"search": {"nx": 16, "ny": 16, "n_tangent": 16, "refine_passes": 4},
|
|
141
|
+
}))
|
|
142
|
+
|
|
143
|
+
print(result.critical_fs) # 0.985
|
|
144
|
+
print(result.results["spencer"].lam) # interslice force ratio
|
|
145
|
+
print(result.text_report())
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Lower level pieces are available too:
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
from lythosle import build_slices, circular_surface, solve_all
|
|
152
|
+
|
|
153
|
+
surface = circular_surface(model.canonical(), xc=20, yc=30, radius=28)
|
|
154
|
+
mass = build_slices(model.canonical(), surface, n_slices=50)
|
|
155
|
+
print({k: v.fs for k, v in solve_all(mass).items()})
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Model format
|
|
159
|
+
|
|
160
|
+
Coordinates are `[x, y]` with `y` as elevation, in whatever consistent unit set
|
|
161
|
+
you use (kN/m³ and kPa, or pcf and psf). The full reference is in
|
|
162
|
+
[docs/model-format.md](docs/model-format.md); the short version:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"name": "Layered slope",
|
|
167
|
+
"units": "metric",
|
|
168
|
+
"profile": [[0, 0], [18, 0], [48, 15], [75, 15]],
|
|
169
|
+
"materials": [
|
|
170
|
+
{"name": "Fill", "unit_weight": 18, "sat_unit_weight": 19.5,
|
|
171
|
+
"cohesion": 5, "friction_angle": 26, "color": "#C4A883"},
|
|
172
|
+
{"name": "Clay", "unit_weight": 19, "strength_model": "undrained",
|
|
173
|
+
"su": 40, "su_gradient": 1.5, "su_datum": 0}
|
|
174
|
+
],
|
|
175
|
+
"layers": [
|
|
176
|
+
{"material": "Fill"},
|
|
177
|
+
{"material": "Clay", "boundary": [[0, -4], [75, 7]]}
|
|
178
|
+
],
|
|
179
|
+
"water_table": [[0, -2], [30, 3.5], [75, 9.5]],
|
|
180
|
+
"seismic": {"kh": 0.15, "kv": 0},
|
|
181
|
+
"surcharges": [{"x1": 50, "x2": 70, "pressure": 20}],
|
|
182
|
+
"supports": [{"name": "Nail 1", "x1": 14, "y1": 1.5,
|
|
183
|
+
"x2": 28, "y2": -0.2, "capacity": 40}],
|
|
184
|
+
"tension_crack": {"enabled": true, "depth": 3, "water_fill": 1.0}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Layers are listed from the top down. The first one starts at the ground
|
|
189
|
+
surface; each one below it carries the boundary that forms its top. Boundaries
|
|
190
|
+
and the water table are extended horizontally beyond their end points.
|
|
191
|
+
|
|
192
|
+
The slope may be drawn facing either way: the solver mirrors the model
|
|
193
|
+
internally so the crest is on the right, and mirrors every result back. Set
|
|
194
|
+
`"direction": "left" | "right"` in the options to analyse a chosen face of a
|
|
195
|
+
two-sided embankment.
|
|
196
|
+
|
|
197
|
+
## Formulation
|
|
198
|
+
|
|
199
|
+
Every method is built on the same slice equations, so the only differences are
|
|
200
|
+
which equilibrium conditions are satisfied and what is assumed about the
|
|
201
|
+
interslice forces `X = lambda * f(x) * E`:
|
|
202
|
+
|
|
203
|
+
| Method | Moment | Force | Interslice shear |
|
|
204
|
+
|---|---|---|---|
|
|
205
|
+
| Ordinary / Fellenius | yes | no | ignored entirely |
|
|
206
|
+
| Bishop simplified | yes | no | `X = 0` |
|
|
207
|
+
| Janbu simplified / corrected | no | yes | `X = 0` (corrected applies Janbu's `f0`) |
|
|
208
|
+
| Corps of Engineers #1 | no | yes | parallel to the entry-exit chord |
|
|
209
|
+
| Lowe-Karafiath | no | yes | average of ground and base inclination |
|
|
210
|
+
| Spencer | yes | yes | constant inclination, solved for |
|
|
211
|
+
| Morgenstern-Price | yes | yes | `f(x)` shape, `lambda` solved for |
|
|
212
|
+
|
|
213
|
+
The base normal force comes from vertical equilibrium of each slice,
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
N = [ W (1 + kv) + (X_right - X_left) - (c l - u l tan phi) sin(alpha) / F ] / m_alpha
|
|
217
|
+
m_alpha = cos(alpha) + sin(alpha) tan(phi) / F
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
and the factor of safety from moment equilibrium about the centre of rotation
|
|
221
|
+
or from horizontal force equilibrium of the whole mass. Spencer and
|
|
222
|
+
Morgenstern-Price iterate on `lambda` until the two agree — the crossing point
|
|
223
|
+
you can see on the lambda-FS plot in the interface.
|
|
224
|
+
|
|
225
|
+
The sign conventions, the treatment of pore pressure, seismic loads,
|
|
226
|
+
reinforcement, tension cracks, and the search algorithms are documented in
|
|
227
|
+
[docs/theory.md](docs/theory.md). Read it before trusting a number.
|
|
228
|
+
|
|
229
|
+
## Validation
|
|
230
|
+
|
|
231
|
+
`tests/test_methods.py` checks the solver against results that do not come from
|
|
232
|
+
this code:
|
|
233
|
+
|
|
234
|
+
| Check | Reference | Result |
|
|
235
|
+
|---|---|---|
|
|
236
|
+
| Circular arc in phi = 0 soil | direct integration of `c L R / M` | within 0.002 of the closed form; identical across Ordinary, Bishop, Spencer and Morgenstern-Price, as theory requires |
|
|
237
|
+
| Long planar surface | infinite slope, `FS = tan(phi')/tan(beta)` | within 1% for Bishop, Janbu, Spencer and Morgenstern-Price |
|
|
238
|
+
| Toe circles, phi = 0, beta = 53-75 deg | Taylor (1937) stability numbers | within 1.5% |
|
|
239
|
+
| ACADS problem 1(a) | published FS = 1.00 | Bishop 0.985, Spencer 0.984 |
|
|
240
|
+
| Mirrored geometry | the same slope drawn facing the other way | identical FS and lambda |
|
|
241
|
+
| Slice refinement | 20 to 200 slices | converges monotonically, < 0.002 change past 100 slices |
|
|
242
|
+
|
|
243
|
+
Method relationships are asserted as well: Ordinary is the most conservative,
|
|
244
|
+
Bishop sits within 2% of Spencer for circular surfaces, and Morgenstern-Price
|
|
245
|
+
needs a larger `lambda` than Spencer because the half-sine function averages
|
|
246
|
+
less than one.
|
|
247
|
+
|
|
248
|
+
## Limitations
|
|
249
|
+
|
|
250
|
+
Worth knowing before you use a number in anger:
|
|
251
|
+
|
|
252
|
+
* Two-dimensional analysis only, per unit width out of plane.
|
|
253
|
+
* The slice weight uses the mid-ordinate of each slice, so strongly curved
|
|
254
|
+
boundaries need more slices (the default 50 is enough for typical sections).
|
|
255
|
+
* Moment-only methods (Ordinary, Bishop) on a **non-circular** surface depend on
|
|
256
|
+
the choice of moment axis. The result is reported with a warning; use Spencer
|
|
257
|
+
or Morgenstern-Price for non-circular surfaces.
|
|
258
|
+
* Spencer and Morgenstern-Price have no solution when `Fm` and `Ff` never
|
|
259
|
+
intersect, which happens when reinforcement is large enough to satisfy force
|
|
260
|
+
equilibrium by itself. Lythos LE reports this as "no solution" with both
|
|
261
|
+
values rather than inventing a number.
|
|
262
|
+
* Reinforcement is applied as a known force at the intersection with the slip
|
|
263
|
+
surface. Pull-out capacity along the anchored length is not calculated for
|
|
264
|
+
you — put the design force in.
|
|
265
|
+
* Negative effective normal forces are clipped to zero (the usual practice),
|
|
266
|
+
and surfaces with a very small `m_alpha` are flagged as poorly conditioned.
|
|
267
|
+
* Probabilistic analysis, rapid drawdown, anisotropic strength and 3D effects
|
|
268
|
+
are not implemented.
|
|
269
|
+
|
|
270
|
+
## Project layout
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
main.py run the interface, or anything the CLI does
|
|
274
|
+
lythosle/
|
|
275
|
+
geometry.py polylines, intersections, polygon helpers
|
|
276
|
+
materials.py strength models
|
|
277
|
+
model.py geometry, stratigraphy, groundwater, loading, mirroring
|
|
278
|
+
slices.py slip surfaces and the slicing of the sliding mass
|
|
279
|
+
methods.py the eight limit equilibrium solvers
|
|
280
|
+
search.py grid-and-tangent search and non-circular optimisation
|
|
281
|
+
analysis.py the driver, reporting and drawing data
|
|
282
|
+
examples.py six worked examples
|
|
283
|
+
cli.py command line interface
|
|
284
|
+
web/ API, standard library server, optional FastAPI app, front end
|
|
285
|
+
tests/ 70 tests, ~60 s
|
|
286
|
+
docs/ theory, model format, exported example models
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Licence
|
|
290
|
+
|
|
291
|
+
MIT.
|
lythosle-0.1.0/README.md
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Lythos LE
|
|
2
|
+
|
|
3
|
+
Limit equilibrium slope stability analysis in pure Python, with a browser front end.
|
|
4
|
+
|
|
5
|
+
Lythos LE computes the factor of safety of slopes and embankments with the method
|
|
6
|
+
of slices, the same class of analysis as Rocscience Slide or GeoStudio SLOPE/W.
|
|
7
|
+
It searches for the critical slip surface, reports every classical method on it,
|
|
8
|
+
and draws the section in the browser.
|
|
9
|
+
|
|
10
|
+
* **No dependencies.** The solver, the web server and the front end are standard
|
|
11
|
+
library and vanilla JavaScript. `python -m lythosle serve` works on a bare
|
|
12
|
+
Python 3.9+ install with nothing to pip install.
|
|
13
|
+
* **Eight methods**, from Fellenius to Morgenstern-Price, all built on one slice
|
|
14
|
+
formulation so the differences between them are the assumptions, not the code.
|
|
15
|
+
* **Validated** against closed-form solutions, Taylor's stability numbers and the
|
|
16
|
+
ACADS benchmark problem (see [Validation](#validation)).
|
|
17
|
+
|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Quick start
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
git clone https://github.com/hdaltuntas/lythosle
|
|
26
|
+
cd lythosle
|
|
27
|
+
|
|
28
|
+
python main.py # browser interface on http://127.0.0.1:8000
|
|
29
|
+
python main.py example # list the built-in examples
|
|
30
|
+
python main.py example homogeneous # run one and print the report
|
|
31
|
+
python -m unittest discover -s tests # run the test suite
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Nothing needs installing. `main.py` takes everything the CLI does and starts
|
|
35
|
+
the web interface when given nothing; `HOST` and `PORT` override the address,
|
|
36
|
+
so a host that sets `PORT` gets a server bound to every interface. The same
|
|
37
|
+
commands are available as `python -m lythosle …`, and `pip install -e .` adds a
|
|
38
|
+
`lythosle` command.
|
|
39
|
+
|
|
40
|
+
## What it does
|
|
41
|
+
|
|
42
|
+
| | |
|
|
43
|
+
|---|---|
|
|
44
|
+
| **Methods** | Ordinary (Fellenius), Bishop simplified, Janbu simplified and corrected, Corps of Engineers #1, Lowe-Karafiath, Spencer, Morgenstern-Price (half-sine, constant or trapezoidal interslice function) |
|
|
45
|
+
| **Surfaces** | Circular (grid-and-tangent search with adaptive box and refinement), a single specified circle, a user-defined non-circular surface, and non-circular optimisation from the critical circle |
|
|
46
|
+
| **Strength** | Effective stress (c', phi'), undrained (s<sub>u</sub>, optionally increasing linearly with depth), impenetrable and no-strength materials |
|
|
47
|
+
| **Groundwater** | Piezometric water table, per-material pore pressure ratio r<sub>u</sub>, separate saturated unit weights, ponded water on the slope |
|
|
48
|
+
| **Loading** | Surface surcharges, pseudo-static seismic coefficients k<sub>h</sub> and k<sub>v</sub>, reinforcement (nails, anchors, geosynthetics), tension cracks with optional water pressure |
|
|
49
|
+
| **Output** | Factor of safety per method, the critical surface, a full slice force table (CSV), the lambda-FS plot for Spencer/Morgenstern-Price, the search grid, JSON for everything |
|
|
50
|
+
|
|
51
|
+
## The three ways in
|
|
52
|
+
|
|
53
|
+
### Browser
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
python -m lythosle serve --port 8000 --open
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Build the geometry from a template or by typing coordinates, set up materials,
|
|
60
|
+
groundwater and loading in the sidebar, then **Run analysis** (or Ctrl/Cmd +
|
|
61
|
+
Enter). The section view shows the layers, the phreatic surface, the critical
|
|
62
|
+
surface with its centre of rotation, the search grid coloured by factor of
|
|
63
|
+
safety, the slices and the reinforcement. Results can be exported as SVG, CSV
|
|
64
|
+
and JSON. The interface follows the system light/dark setting; the toggle in
|
|
65
|
+
the header pins it.
|
|
66
|
+
|
|
67
|
+
`?example=layered_water` and `?theme=dark` work as URL parameters.
|
|
68
|
+
|
|
69
|
+
The interface follows Claude's design language: the ivory and charcoal
|
|
70
|
+
surfaces, the clay accent, sentence-case labels and a serif for the wordmark,
|
|
71
|
+
headings and prose. Claude's own faces (Styrene, Tiempos, Copernicus) are
|
|
72
|
+
licensed, so the stack asks for them first and falls back to Inter and
|
|
73
|
+
Newsreader, which are bundled in `lythosle/web/static/fonts/` — nothing is
|
|
74
|
+
fetched from a CDN at runtime, and the page looks the same offline.
|
|
75
|
+
|
|
76
|
+
If you prefer FastAPI, `uvicorn lythosle.web.app:app` serves exactly the same
|
|
77
|
+
API (`pip install fastapi uvicorn` first).
|
|
78
|
+
|
|
79
|
+
### Command line
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
lythosle analyze model.json --method bishop --method spencer \
|
|
83
|
+
--slices 60 --json result.json --csv slices.csv
|
|
84
|
+
lythosle example seismic --optimize
|
|
85
|
+
lythosle methods
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`analyze` takes either a bare model file or a `{"model": ..., "options": ...}`
|
|
89
|
+
file — which is exactly what the browser's **Download** button produces.
|
|
90
|
+
|
|
91
|
+
### Python
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from lythosle import SlopeModel, AnalysisOptions, analyze
|
|
95
|
+
|
|
96
|
+
model = SlopeModel.from_dict({
|
|
97
|
+
"profile": [[0, 0], [10, 0], [30, 10], [50, 10]],
|
|
98
|
+
"materials": [{"name": "fill", "unit_weight": 20, "cohesion": 3,
|
|
99
|
+
"friction_angle": 19.6}],
|
|
100
|
+
"layers": [{"material": "fill"}],
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
result = analyze(model, AnalysisOptions.from_dict({
|
|
104
|
+
"methods": ["bishop", "spencer"],
|
|
105
|
+
"n_slices": 60,
|
|
106
|
+
"search": {"nx": 16, "ny": 16, "n_tangent": 16, "refine_passes": 4},
|
|
107
|
+
}))
|
|
108
|
+
|
|
109
|
+
print(result.critical_fs) # 0.985
|
|
110
|
+
print(result.results["spencer"].lam) # interslice force ratio
|
|
111
|
+
print(result.text_report())
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Lower level pieces are available too:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from lythosle import build_slices, circular_surface, solve_all
|
|
118
|
+
|
|
119
|
+
surface = circular_surface(model.canonical(), xc=20, yc=30, radius=28)
|
|
120
|
+
mass = build_slices(model.canonical(), surface, n_slices=50)
|
|
121
|
+
print({k: v.fs for k, v in solve_all(mass).items()})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Model format
|
|
125
|
+
|
|
126
|
+
Coordinates are `[x, y]` with `y` as elevation, in whatever consistent unit set
|
|
127
|
+
you use (kN/m³ and kPa, or pcf and psf). The full reference is in
|
|
128
|
+
[docs/model-format.md](docs/model-format.md); the short version:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"name": "Layered slope",
|
|
133
|
+
"units": "metric",
|
|
134
|
+
"profile": [[0, 0], [18, 0], [48, 15], [75, 15]],
|
|
135
|
+
"materials": [
|
|
136
|
+
{"name": "Fill", "unit_weight": 18, "sat_unit_weight": 19.5,
|
|
137
|
+
"cohesion": 5, "friction_angle": 26, "color": "#C4A883"},
|
|
138
|
+
{"name": "Clay", "unit_weight": 19, "strength_model": "undrained",
|
|
139
|
+
"su": 40, "su_gradient": 1.5, "su_datum": 0}
|
|
140
|
+
],
|
|
141
|
+
"layers": [
|
|
142
|
+
{"material": "Fill"},
|
|
143
|
+
{"material": "Clay", "boundary": [[0, -4], [75, 7]]}
|
|
144
|
+
],
|
|
145
|
+
"water_table": [[0, -2], [30, 3.5], [75, 9.5]],
|
|
146
|
+
"seismic": {"kh": 0.15, "kv": 0},
|
|
147
|
+
"surcharges": [{"x1": 50, "x2": 70, "pressure": 20}],
|
|
148
|
+
"supports": [{"name": "Nail 1", "x1": 14, "y1": 1.5,
|
|
149
|
+
"x2": 28, "y2": -0.2, "capacity": 40}],
|
|
150
|
+
"tension_crack": {"enabled": true, "depth": 3, "water_fill": 1.0}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Layers are listed from the top down. The first one starts at the ground
|
|
155
|
+
surface; each one below it carries the boundary that forms its top. Boundaries
|
|
156
|
+
and the water table are extended horizontally beyond their end points.
|
|
157
|
+
|
|
158
|
+
The slope may be drawn facing either way: the solver mirrors the model
|
|
159
|
+
internally so the crest is on the right, and mirrors every result back. Set
|
|
160
|
+
`"direction": "left" | "right"` in the options to analyse a chosen face of a
|
|
161
|
+
two-sided embankment.
|
|
162
|
+
|
|
163
|
+
## Formulation
|
|
164
|
+
|
|
165
|
+
Every method is built on the same slice equations, so the only differences are
|
|
166
|
+
which equilibrium conditions are satisfied and what is assumed about the
|
|
167
|
+
interslice forces `X = lambda * f(x) * E`:
|
|
168
|
+
|
|
169
|
+
| Method | Moment | Force | Interslice shear |
|
|
170
|
+
|---|---|---|---|
|
|
171
|
+
| Ordinary / Fellenius | yes | no | ignored entirely |
|
|
172
|
+
| Bishop simplified | yes | no | `X = 0` |
|
|
173
|
+
| Janbu simplified / corrected | no | yes | `X = 0` (corrected applies Janbu's `f0`) |
|
|
174
|
+
| Corps of Engineers #1 | no | yes | parallel to the entry-exit chord |
|
|
175
|
+
| Lowe-Karafiath | no | yes | average of ground and base inclination |
|
|
176
|
+
| Spencer | yes | yes | constant inclination, solved for |
|
|
177
|
+
| Morgenstern-Price | yes | yes | `f(x)` shape, `lambda` solved for |
|
|
178
|
+
|
|
179
|
+
The base normal force comes from vertical equilibrium of each slice,
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
N = [ W (1 + kv) + (X_right - X_left) - (c l - u l tan phi) sin(alpha) / F ] / m_alpha
|
|
183
|
+
m_alpha = cos(alpha) + sin(alpha) tan(phi) / F
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
and the factor of safety from moment equilibrium about the centre of rotation
|
|
187
|
+
or from horizontal force equilibrium of the whole mass. Spencer and
|
|
188
|
+
Morgenstern-Price iterate on `lambda` until the two agree — the crossing point
|
|
189
|
+
you can see on the lambda-FS plot in the interface.
|
|
190
|
+
|
|
191
|
+
The sign conventions, the treatment of pore pressure, seismic loads,
|
|
192
|
+
reinforcement, tension cracks, and the search algorithms are documented in
|
|
193
|
+
[docs/theory.md](docs/theory.md). Read it before trusting a number.
|
|
194
|
+
|
|
195
|
+
## Validation
|
|
196
|
+
|
|
197
|
+
`tests/test_methods.py` checks the solver against results that do not come from
|
|
198
|
+
this code:
|
|
199
|
+
|
|
200
|
+
| Check | Reference | Result |
|
|
201
|
+
|---|---|---|
|
|
202
|
+
| Circular arc in phi = 0 soil | direct integration of `c L R / M` | within 0.002 of the closed form; identical across Ordinary, Bishop, Spencer and Morgenstern-Price, as theory requires |
|
|
203
|
+
| Long planar surface | infinite slope, `FS = tan(phi')/tan(beta)` | within 1% for Bishop, Janbu, Spencer and Morgenstern-Price |
|
|
204
|
+
| Toe circles, phi = 0, beta = 53-75 deg | Taylor (1937) stability numbers | within 1.5% |
|
|
205
|
+
| ACADS problem 1(a) | published FS = 1.00 | Bishop 0.985, Spencer 0.984 |
|
|
206
|
+
| Mirrored geometry | the same slope drawn facing the other way | identical FS and lambda |
|
|
207
|
+
| Slice refinement | 20 to 200 slices | converges monotonically, < 0.002 change past 100 slices |
|
|
208
|
+
|
|
209
|
+
Method relationships are asserted as well: Ordinary is the most conservative,
|
|
210
|
+
Bishop sits within 2% of Spencer for circular surfaces, and Morgenstern-Price
|
|
211
|
+
needs a larger `lambda` than Spencer because the half-sine function averages
|
|
212
|
+
less than one.
|
|
213
|
+
|
|
214
|
+
## Limitations
|
|
215
|
+
|
|
216
|
+
Worth knowing before you use a number in anger:
|
|
217
|
+
|
|
218
|
+
* Two-dimensional analysis only, per unit width out of plane.
|
|
219
|
+
* The slice weight uses the mid-ordinate of each slice, so strongly curved
|
|
220
|
+
boundaries need more slices (the default 50 is enough for typical sections).
|
|
221
|
+
* Moment-only methods (Ordinary, Bishop) on a **non-circular** surface depend on
|
|
222
|
+
the choice of moment axis. The result is reported with a warning; use Spencer
|
|
223
|
+
or Morgenstern-Price for non-circular surfaces.
|
|
224
|
+
* Spencer and Morgenstern-Price have no solution when `Fm` and `Ff` never
|
|
225
|
+
intersect, which happens when reinforcement is large enough to satisfy force
|
|
226
|
+
equilibrium by itself. Lythos LE reports this as "no solution" with both
|
|
227
|
+
values rather than inventing a number.
|
|
228
|
+
* Reinforcement is applied as a known force at the intersection with the slip
|
|
229
|
+
surface. Pull-out capacity along the anchored length is not calculated for
|
|
230
|
+
you — put the design force in.
|
|
231
|
+
* Negative effective normal forces are clipped to zero (the usual practice),
|
|
232
|
+
and surfaces with a very small `m_alpha` are flagged as poorly conditioned.
|
|
233
|
+
* Probabilistic analysis, rapid drawdown, anisotropic strength and 3D effects
|
|
234
|
+
are not implemented.
|
|
235
|
+
|
|
236
|
+
## Project layout
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
main.py run the interface, or anything the CLI does
|
|
240
|
+
lythosle/
|
|
241
|
+
geometry.py polylines, intersections, polygon helpers
|
|
242
|
+
materials.py strength models
|
|
243
|
+
model.py geometry, stratigraphy, groundwater, loading, mirroring
|
|
244
|
+
slices.py slip surfaces and the slicing of the sliding mass
|
|
245
|
+
methods.py the eight limit equilibrium solvers
|
|
246
|
+
search.py grid-and-tangent search and non-circular optimisation
|
|
247
|
+
analysis.py the driver, reporting and drawing data
|
|
248
|
+
examples.py six worked examples
|
|
249
|
+
cli.py command line interface
|
|
250
|
+
web/ API, standard library server, optional FastAPI app, front end
|
|
251
|
+
tests/ 70 tests, ~60 s
|
|
252
|
+
docs/ theory, model format, exported example models
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Licence
|
|
256
|
+
|
|
257
|
+
MIT.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"model": {
|
|
3
|
+
"name": "Homogeneous slope",
|
|
4
|
+
"units": "metric",
|
|
5
|
+
"profile": [
|
|
6
|
+
[
|
|
7
|
+
0,
|
|
8
|
+
0
|
|
9
|
+
],
|
|
10
|
+
[
|
|
11
|
+
10,
|
|
12
|
+
0
|
|
13
|
+
],
|
|
14
|
+
[
|
|
15
|
+
30.0,
|
|
16
|
+
10
|
|
17
|
+
],
|
|
18
|
+
[
|
|
19
|
+
50.0,
|
|
20
|
+
10
|
|
21
|
+
]
|
|
22
|
+
],
|
|
23
|
+
"materials": [
|
|
24
|
+
{
|
|
25
|
+
"name": "Embankment fill",
|
|
26
|
+
"unit_weight": 20.0,
|
|
27
|
+
"cohesion": 3.0,
|
|
28
|
+
"friction_angle": 19.6,
|
|
29
|
+
"color": "#C4A883"
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"layers": [
|
|
33
|
+
{
|
|
34
|
+
"material": "Embankment fill"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"options": {
|
|
39
|
+
"methods": [
|
|
40
|
+
"ordinary",
|
|
41
|
+
"bishop",
|
|
42
|
+
"janbu_corrected",
|
|
43
|
+
"spencer",
|
|
44
|
+
"morgenstern_price"
|
|
45
|
+
],
|
|
46
|
+
"n_slices": 50,
|
|
47
|
+
"search": {
|
|
48
|
+
"mode": "auto",
|
|
49
|
+
"method": "bishop",
|
|
50
|
+
"nx": 14,
|
|
51
|
+
"ny": 14,
|
|
52
|
+
"n_tangent": 14,
|
|
53
|
+
"refine_passes": 3
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|