diff --git a/E03_StabSection/E03_StabSection_Types.py b/E03_StabSection/E03_StabSection_Types.py new file mode 100644 index 000000000..adfa50720 --- /dev/null +++ b/E03_StabSection/E03_StabSection_Types.py @@ -0,0 +1,124 @@ +"""E 안정성평가 공용 꼴 — 2D(E03) · 3D(E04) 해석이 같은 입력 꼴을 씀. + +단위: 단위중량 kN/m³ · 점착력 · 하중 kPa · 내부마찰각 ° · 좌표 m. +E04 가 이 파일을 그대로 import — 이름 · 열쇠를 바꾸지 않음. +""" + +from typing import Literal, TypedDict + +GAMMA_W = 9.81 # 물 단위중량 kN/m³ + + +class Material(TypedDict): + id: str + name: str + gamma_t: float # 습윤 단위중량 (지하수위 위) + gamma_sat: float # 포화 단위중량 (지하수위 아래) + c: float # 유효 점착력 + phi: float # 유효 내부마찰각 + + +class Groundwater(TypedDict, total=False): + mode: Literal["none", "ru", "line"] + ru: float # mode="ru" — 간극수압비 u = ru · γ·h + line: list[list[float]] # mode="line" — 지하수위선 [[x, z], …] (2D) · x 오름차순 + + +class Surcharge(TypedDict): + x0: float + x1: float + q: float # 연직 등분포 kPa + + +# 요구서 345 6장 기본값(사용자가 E02 에서 바꿈) — 사전조사 후보의 보수 쪽. +DEFAULT_MATERIALS: list[Material] = [ + { + "id": "weathered_soil", + "name": "풍화토", + "gamma_t": 18.0, + "gamma_sat": 19.0, + "c": 15.0, + "phi": 30.0, + }, + { + "id": "weathered_rock", + "name": "풍화암", + "gamma_t": 20.0, + "gamma_sat": 21.0, + "c": 30.0, + "phi": 33.0, + }, + { + "id": "soft_rock", + "name": "연암", + "gamma_t": 24.0, + "gamma_sat": 24.5, + "c": 150.0, + "phi": 35.0, + }, + { + "id": "hard_rock", + "name": "경암", + "gamma_t": 26.0, + "gamma_sat": 26.0, + "c": 300.0, + "phi": 40.0, + }, + {"id": "fill", "name": "성토", "gamma_t": 18.0, "gamma_sat": 19.0, "c": 10.0, "phi": 25.0}, + { + "id": "colluvium", + "name": "붕적토", + "gamma_t": 17.5, + "gamma_sat": 18.5, + "c": 5.0, + "phi": 27.0, + }, +] + +DEFAULT_ROAD_SURCHARGE_KPA = 10.0 # 노면 하중 기본 + + +def material(raw: dict) -> Material: + """밖에서 온 물성 한 줄을 꼴에 맞춤 — 빠진 γsat 는 γt · 음수 · 범위 밖은 오류.""" + gamma_t = float(raw["gamma_t"]) + gamma_sat = float(raw.get("gamma_sat", gamma_t)) + c = float(raw["c"]) + phi = float(raw["phi"]) + if gamma_t <= 0 or gamma_sat <= 0 or c < 0 or not 0 <= phi < 90: + raise ValueError(f"물성 범위 밖: {raw}") + return { + "id": str(raw["id"]), + "name": str(raw.get("name", raw["id"])), + "gamma_t": gamma_t, + "gamma_sat": gamma_sat, + "c": c, + "phi": phi, + } + + +def groundwater(raw: dict | None) -> Groundwater: + """지하수 꼴 맞춤 — 없으면 none · line 은 x 오름차순으로 정렬.""" + if not raw or raw.get("mode", "none") == "none": + return {"mode": "none"} + mode = raw["mode"] + if mode == "ru": + ru = float(raw.get("ru", 0.0)) + if not 0 <= ru < 1: + raise ValueError(f"r_u 범위 밖: {ru}") + return {"mode": "ru", "ru": ru} + if mode == "line": + line = sorted([float(x), float(z)] for x, z in raw["line"]) + if len(line) < 2: + raise ValueError("지하수위선 점이 둘 미만") + return {"mode": "line", "line": line} + raise ValueError(f"지하수 mode 모름: {mode}") + + +def surcharges(raw: list[dict] | None) -> list[Surcharge]: + """상재하중 꼴 맞춤 — x0 < x1 로 정렬 · 길이 0 은 버림.""" + out: list[Surcharge] = [] + for item in raw or []: + x0, x1 = sorted((float(item["x0"]), float(item["x1"]))) + if x1 > x0: + out.append({"x0": x0, "x1": x1, "q": float(item["q"])}) + return out