diff --git a/E03_StabSection/E03_StabSection_Router_WhatIf.py b/E03_StabSection/E03_StabSection_Router_WhatIf.py index 85ae4723f..8519d8cb6 100644 --- a/E03_StabSection/E03_StabSection_Router_WhatIf.py +++ b/E03_StabSection/E03_StabSection_Router_WhatIf.py @@ -18,7 +18,7 @@ import math import time from pathlib import Path from typing import Any, Literal -from functools import lru_cache +from functools import lru_cache, partial from uuid import UUID from fastapi import APIRouter, HTTPException @@ -100,6 +100,7 @@ def _context(root: Path, station_key: str) -> dict[str, Any]: walls = walls_mod.walls_of(entry) if walls: kw["walls"] = walls + kw["groundwater_for"] = partial(ground_model.station_groundwater, ground) return { "ground": ground, "plan": plan, diff --git a/E03_StabSection/E03_StabSection_Worker.py b/E03_StabSection/E03_StabSection_Worker.py index 72d43a14b..e69e100f4 100644 --- a/E03_StabSection/E03_StabSection_Worker.py +++ b/E03_StabSection/E03_StabSection_Worker.py @@ -13,10 +13,12 @@ import json import logging import sys from concurrent.futures import ProcessPoolExecutor, as_completed +from functools import partial from pathlib import Path from typing import Any, Callable from common_util.common_util_derived_store import write_derived +from E02_StabGround.E02_StabGround_Model import station_groundwater from E03_StabSection.E03_StabSection_Engine_Station import analyze_station KIND_STATION = "stab2d_station" @@ -29,6 +31,8 @@ def _analyze( kw = {**kwargs, "layers": item["layers"], "ground": [tuple(p) for p in item["ground"]]} if item.get("walls"): kw["walls"] = item["walls"] + if conditions_ground is not None: + kw["groundwater_for"] = partial(station_groundwater, conditions_ground) return analyze_station(item["cross"], item["design"], **kw) diff --git a/resources/help/E02/00_설명서.md b/resources/help/E02/00_설명서.md index 385338eda..84ec7adfd 100644 --- a/resources/help/E02/00_설명서.md +++ b/resources/help/E02/00_설명서.md @@ -46,5 +46,5 @@ - 측점의 B06 지반 · B06 토층 두께는 복사본 값이라 화면에서 고칠 수 없음 — 바꾸려면 구간 덮어쓰기를 쓸 것. - 저장 뒤 E03 에서 [해석]을 다시 누르면 값이 바뀐 측점만 다시 계산함. - 기준안전율 표의 「단기」 줄 · 「쌓기(연약지반)」 칸은 값만 보관함 — 지금 2D 해석 판정은 건기 · 우기 · 지진 시의 깎기 · 쌓기 칸만 씀. -- 우기 지하수 규칙(KDS 기본 외 갈래 포함)은 지금 E03 횡단 그림의 수위선에 반영됨. 안전율 계산은 아직 모든 측점을 「공사 뒤 지표까지 포화」로 셈 — 고른 갈래의 계산 반영은 준비 중. +- 지하수 규칙(건기 · 우기 갈래 넷)은 E03 안전율 계산과 횡단 그림의 수위선에 함께 반영됨. 규칙을 바꾸면 E03 에서 다시 [해석]. - 칸 뜻 · 범위는 「칸 뜻」, 근거 · 수식은 「쓰인 방법과 근거」, 확정 안 된 값 목록은 「사용자 확정 전 값」 항목에 있음. diff --git a/resources/help/E02/20_쓰인_방법과_근거.md b/resources/help/E02/20_쓰인_방법과_근거.md index eb8f3ee94..b1588938f 100644 --- a/resources/help/E02/20_쓰인_방법과_근거.md +++ b/resources/help/E02/20_쓰인_방법과_근거.md @@ -34,7 +34,7 @@ 4. **사용자 수위선** — 구간마다 점(offset · 지표 아래 깊이)을 이은 선. 점 사이는 곧은 선. 덮지 않은 측점은 KDS 기본 규칙. - 건기 · 지진 시는 「건기 지하수」 규칙(기본 없음)을 씀. -- 지금 E03 안전율 계산은 우기를 모든 측점 「공사 뒤 지표까지 포화」로 셈 — 위 규칙은 횡단 그림의 수위선에만 반영됨(계산 반영은 준비 중). 포화는 가장 불리한 쪽 가정임. +- 위 규칙은 E03 안전율 계산과 횡단 그림의 수위선에 같이 반영됨. 지표까지 포화는 가장 불리한 쪽 가정임. ## 노면 하중 diff --git a/resources/help/E02/30_사용자_확정_전_값.md b/resources/help/E02/30_사용자_확정_전_값.md index 631fd941c..a05dce992 100644 --- a/resources/help/E02/30_사용자_확정_전_값.md +++ b/resources/help/E02/30_사용자_확정_전_값.md @@ -54,5 +54,5 @@ ## 계산에 아직 안 들어간 값 -- 우기 규칙(KDS 기본의 암반 ½ · 깊이 비율 · r_u · 사용자 수위선)은 지금 E03 횡단 그림의 수위선에만 보임. 안전율 계산은 모든 측점을 「공사 뒤 지표까지 포화」로 셈 — 계산 반영은 준비 중. +- 우기 규칙(KDS 기본의 암반 ½ · 깊이 비율 · r_u · 사용자 수위선)은 E03 안전율 계산과 횡단 그림의 수위선에 같이 쓰임. 3D(E04)는 따로 「지표까지 포화」 한 가지. - 기준안전율 「단기」 줄 · 「쌓기(연약지반)」 칸은 2D 판정에 아직 안 쓰임. diff --git a/resources/help/E03/00_설명서.md b/resources/help/E03/00_설명서.md index a4407ce83..4b6d17eb2 100644 --- a/resources/help/E03/00_설명서.md +++ b/resources/help/E03/00_설명서.md @@ -61,7 +61,7 @@ - **문헌 추정치 · 현장 시험 없음**: 지반 값이 문헌 대표값이라 안전율은 설계 검토용 참고값임. 현장 조사 값으로 바꿔 다시 해석할 것. - 해석은 서버가 함 · 화면은 결과만 보임. 같은 입력이면 다시 셈하지 않음. -- 우기 계산 = 지금은 모든 측점 「공사 뒤 지표까지 포화」. E02 에서 고른 우기 규칙은 횡단 그림의 지하수위 점선에만 반영됨(계산 반영은 준비 중). r_u 를 골랐으면 그림 아래에 「지하수 = 간극수압비 r_u …」 글만 보임. +- 지하수 = E02 에서 고른 규칙(건기 · 우기 갈래 넷)을 안전율 계산과 지하수위 점선에 같이 씀. r_u 를 골랐으면 수위선 없이 그림 아래에 「지하수 = 간극수압비 r_u …」 글만 보임. - 탐색 범위 = 노면 반대쪽 끝 ~ 비탈 끝 바깥 (5 m 와 비탈 높이 2 배 중 큰 값)까지 — 설계 비탈을 지나는 면만 봄. 노선 밖 자연 비탈 전체 붕괴는 광역 위험(E07) 몫. - 깊이 0.3 m 미만으로 겉만 긁는 면은 붕괴로 보지 않음. - 벽은 아주 단단한 물체로 넣어 활동면이 벽을 지나지 않음 — 벽 자체 안정은 보강 검토의 「벽 외적 안정」으로 봄. diff --git a/resources/help/E03/20_쓰인_방법과_근거.md b/resources/help/E03/20_쓰인_방법과_근거.md index b3d132a89..dc9900c8f 100644 --- a/resources/help/E03/20_쓰인_방법과_근거.md +++ b/resources/help/E03/20_쓰인_방법과_근거.md @@ -41,9 +41,9 @@ | 조건 | 지하수 · 하중 | 기준안전율(E02 기본 · 깎기 / 쌓기) | | --- | --- | --- | -| 건기 | 지하수 없음 | 1.5 / 1.5 | -| 우기 | 지금은 모든 측점 공사 뒤 지표까지 포화 | 1.2 / 1.3 | -| 지진(E02 에서 켰을 때) | 건기 수위 + 수평지진계수 kh | 1.1 / 1.1 | +| 건기 | E02 건기 지하수 규칙(기본 없음) | 1.5 / 1.5 | +| 우기 | E02 우기 규칙(KDS 기본 = 토사 · 풍화암 지표 포화 · 암반 비탈 높이 ½) | 1.2 / 1.3 | +| 지진(E02 에서 켰을 때) | E02 건기 지하수 규칙 + 수평지진계수 kh | 1.1 / 1.1 | - 기준 = KDS 11 70 05 표 4.3-1 · 4.3-2 · 4.3-3(지식DB 04 §2). 값은 E02 에서 바꿀 수 있음. - 좌 · 우 비탈을 따로 셈 — 깎기 = 산 쪽에서 노면 쪽으로 미끄러짐 · 쌓기 = 노면에서 바깥쪽으로 미끄러짐. @@ -75,7 +75,7 @@ - 지반 값 = 문헌 추정치 · 현장 시험 없음. - 2D 해석이라 비탈 양옆이 붙잡아 주는 효과(끝단 효과)는 빠짐 — 3D 해석(E04) 몫. -- 우기는 지표까지 포화로 셈(가장 불리한 쪽). E02 우기 규칙 갈래(암반 ½ · 깊이 비율 · r_u · 수위선)의 계산 반영은 준비 중. +- 우기 지하수는 E02 규칙대로(KDS 기본 · 깊이 비율 · r_u · 수위선) — 지표까지 포화는 가장 불리한 쪽. - 강우 침투 해석(시간에 따른 수위 변화) · 인장균열은 넣지 않음. - 암반 절리를 따라 미끄러지는 평면 · 쐐기 파괴는 암반 해석(E06) 몫. - 네일 · 앵커 보강 가정은 준비 중. diff --git a/resources/tester/test_532_5_e03_seam.py b/resources/tester/test_532_5_e03_seam.py index 4dd5b86f2..1749aef57 100644 --- a/resources/tester/test_532_5_e03_seam.py +++ b/resources/tester/test_532_5_e03_seam.py @@ -261,3 +261,42 @@ def test_result2d_지배_비탈_기준_대비(): assert view.governing_row(row)["verdict_overall"] == "ok" bare = {**row, "cases": {"dry": {"left": {"fs": 1.4, "required": None}}}} assert view.governing_row(bare)["side"] is None and view.governing_row(bare)["fs_min"] == 1.22 + + +def _wet_fs(project, key: str) -> tuple[float, float]: + _analyze() + assert router._JOBS[PID]["error"] is None + rows = asyncio.run(router.result2d(UUID(PID), USER))["stations"] + fs = next(r["fs_by_condition"] for r in rows if r["key"] == key) + return fs["dry"], fs["wet"] + + +def test_지하수_갈래_넷이_안전율을_바꿈(project, monkeypatch): + """일꾼이 E02 지하수 갈래를 엔진에 넘김 — 갈래마다 우기 안전율이 다름 · KDS 기본 = 전과 같음.""" + _analyze() + rows = asyncio.run(router.result2d(UUID(PID), USER))["stations"] + key = next(r["key"] for r in rows if r["key"] != WALL_KEY) + chainage = next(r["chainage_m"] for r in rows if r["key"] == key) + base = router._ground(project) + + def run(**water) -> tuple[float, float]: + ground = json.loads(json.dumps(base)) + ground["groundwater"].update(water) + _save_ground(project, ground) + return _wet_fs(project, key) + + # 전 = 일꾼이 모형 기본(우기 지표 포화 · 건기 없음)을 그대로 씀 + with monkeypatch.context() as patch: + patch.setattr(worker, "station_groundwater", lambda _g, _c, model: model["groundwater"]) + legacy = run(wet_mode="kds") + kds = run(wet_mode="kds") + half = run(wet_mode="depth_ratio", depth_ratio=0.5) + ru = run(wet_mode="ru", ru=0.3) + line = run( + wet_mode="line", lines=[{"from_m": 0, "to_m": 1e6, "points": [[-20.0, 4.0], [20.0, 4.0]]}] + ) + rock = ground_model._face_water(base, chainage) == "rock" + assert kds == (half if rock else legacy) # KDS 기본 = 토사 지표 포화(전과 같음) · 암반 ½ + assert half[1] > legacy[1] and line[1] > legacy[1] # 수위가 내려가면 안전율 오름 + assert ru[1] != legacy[1] and len({round(v[1], 3) for v in (legacy, half, ru, line)}) == 4 + assert legacy[0] == kds[0] == half[0] == ru[0] == line[0] # 건기는 우기 갈래와 무관