diff --git a/__pycache__/settle_prediction_steps_main.cpython-310.pyc b/__pycache__/settle_prediction_steps_main.cpython-310.pyc index 0c2154e..d93938c 100644 Binary files a/__pycache__/settle_prediction_steps_main.cpython-310.pyc and b/__pycache__/settle_prediction_steps_main.cpython-310.pyc differ diff --git a/controller.py b/controller.py index 312d239..ab74f4a 100644 --- a/controller.py +++ b/controller.py @@ -100,7 +100,12 @@ def settlement_prediction(business_code, cons_code): final_step_predict_percent=90, additional_predict_percent=300, asaoka_interval=3)) - + + # 결과가 None이면 DB 저장을 건너뛰고 종료 (시스템 crash 방지) + if results is None: + print(f"[Python Log] [Skip] {cons_code}: 유효한 예측 결과가 없어 DB 저장을 중단합니다.") + return + # prediction method code # 1: original hyperbolic method (쌍곡선법) # 2: nonlinear hyperbolic method (비선형 쌍곡선법) diff --git a/settle_prediction_steps_main.py b/settle_prediction_steps_main.py index 83bc389..b04dde3 100644 --- a/settle_prediction_steps_main.py +++ b/settle_prediction_steps_main.py @@ -290,69 +290,78 @@ def run_settle_prediction(point_name, np_time, np_surcharge, np_settlement, # 초기 침하량에 대한 침하량 조정 sm_hyper = sm_hyper - s0_hyper + # ========================================================= + # 데이터 유효성 검사 및 예측 거부 로직 + # ========================================================= + # 분석이 완전히 불가능한 경우를 체크합니다. + is_invalid = np.any(settle < 0) or np.max(sm_hyper) <= 0 + + if is_invalid: + print(f"[Python Log] [Error] {point_name}: 누적침하량이 유효하지 않아 기본 예측으로 대체합니다.") + # 실패 시 시스템이 멈추지 않도록 마지막 계측값을 그대로 유지하는 배열을 생성합니다. + dummy_sp = np.full_like(time_hyper, settle[-1]) + dummy_sp_asaoka = np.full_like(time_hyper, settle[-1]) + dummy_sp_step = np.full_like(time[step_start_index[0]:], settle[-1]) + + # None 대신 모든 결과 리스트를 반환하여 controller.py의 에러를 방지합니다. + return [time_hyper, dummy_sp, # Original + time_hyper, dummy_sp, # Nonlinear + time_hyper, dummy_sp, # Weighted + time_hyper, dummy_sp_asaoka, # Asaoka + time[step_start_index[0]:], dummy_sp_step] # Step Loading + + # 계수 변수 기본값 초기화 (데이터 부족 시에도 UnboundLocalError 방지) + x_hyper_nonlinear = np.array([1.0, 1.0]) + x_hyper_weight_nonlinear = np.array([1.0, 1.0]) + x_hyper_original = np.array([1.0, 1.0]) + # 회귀분석 시행 (비선형 쌍곡선) - x0 = np.ones(2) - res_lsq_hyper_nonlinear = least_squares(fun_hyper_nonlinear, x0, - args=(tm_hyper, sm_hyper)) + #x0 = np.ones(2) + # res_lsq_hyper_nonlinear = least_squares(fun_hyper_nonlinear, x0, + # args=(tm_hyper, sm_hyper)) # 비선형 쌍곡선 법 계수 저장 및 출력 - x_hyper_nonlinear = res_lsq_hyper_nonlinear.x + #x_hyper_nonlinear = res_lsq_hyper_nonlinear.x + + if len(tm_hyper) >= 2: + try: + res_lsq = least_squares(fun_hyper_nonlinear, x_hyper_nonlinear, args=(tm_hyper, sm_hyper)) # 결과가 나올 때만 + x_hyper_nonlinear = res_lsq.x # 값을 업데이트 + except Exception as e: + print(f"[Warning] ... failed: {e}") # 실패하면 초기값(1.0) 유지 # 가중 비선형 쌍곡선 가중치 산정 # 시간 합계가 0인 경우(데이터 부족 등) 0으로 나누는 에러 방지 + # 가중 비선형 쌍곡선법 (Weighted Nonlinear) sum_tm = np.sum(tm_hyper) - if sum_tm == 0: - weight = np.ones_like(tm_hyper) # 가중치를 모두 1로 설정 - else: + if sum_tm > 0 and len(tm_hyper) >= 2: weight = tm_hyper / sum_tm + try: + # 두 번째 인자인 'x_hyper_weight_nonlinear'가 반드시 포함되어야 함 + res_lsq = least_squares(fun_hyper_weight_nonlinear, x_hyper_weight_nonlinear, args=(tm_hyper, sm_hyper, weight)) + x_hyper_weight_nonlinear = res_lsq.x + except Exception as e: + print(f"[Warning] Weighted Nonlinear Hyperbolic failed for {point_name}: {e}") - # 회귀분석 시행 (가중 비선형 쌍곡선) - x0 = np.ones(2) - res_lsq_hyper_weight_nonlinear = least_squares(fun_hyper_weight_nonlinear, x0, - args=(tm_hyper, sm_hyper, weight)) - # 비선형 쌍곡선 법 계수 저장 및 출력 - x_hyper_weight_nonlinear = res_lsq_hyper_weight_nonlinear.x - - # 회귀분석 시행 (기존 쌍곡선법) - (0, 0)에 해당하는 초기 데이터를 제외하고 회귀분석 실시 - x0 = np.ones(2) - # [로그 추가] 입력 데이터의 상태를 확인 - print(f"[LOG] {point_name} - tm_hyper size: {len(tm_hyper)}, sm_hyper contains zero: {np.any(sm_hyper == 0)}") - if np.any(sm_hyper <= 0): - print(f"[LOG] Problematic sm_hyper values: {sm_hyper[sm_hyper <= 0]}") - - # 1. 침하량이 0보다 큰 유효한 데이터만 필터링 (0으로 나누기 근본적 방지) + # 기존 쌍곡선법 (Original Hyperbolic) valid_indices = np.where(sm_hyper > 0)[0] - - # 2. 필터링된 데이터가 최소 2개 이상인지 확인 (회귀분석을 위한 최소 조건) if len(valid_indices) >= 2: tm_hyper_valid = tm_hyper[valid_indices] sm_hyper_valid = sm_hyper[valid_indices] - - # (0, 0) 제외 로직이 이미 필터링에 포함되어 있으므로 [1:] 없이 수행 가능 - x0 = np.ones(2) try: - res_lsq_hyper_original = least_squares(fun_hyper_original, x0, - args=(tm_hyper_valid, sm_hyper_valid)) - x_hyper_original = res_lsq_hyper_original.x - except ValueError as e: - print(f"[Warning] Optimization failed for Original Hyperbolic: {e}") - x_hyper_original = np.ones(2) * 0.001 # 실패 시 기본값 세팅 + # 초기값으로 np.array([1.0, 1.0])을 직접 전달 + res_lsq = least_squares(fun_hyper_original, np.array([1.0, 1.0]), args=(tm_hyper_valid, sm_hyper_valid)) + x_hyper_original = res_lsq.x + except Exception as e: + print(f"[Warning] Original Hyperbolic failed for {point_name}: {e}") + x_hyper_original = np.array([0.001, 0.001]) else: - # 데이터가 부족할 경우 에러 대신 기본값이나 알림 처리 print(f"[Warning] {point_name}: Not enough valid settlement data (>0) for Original Hyperbolic.") - x_hyper_original = np.ones(2) * 0.001 - - # 기존 쌍곡선 법 계수 저장 및 출력 - x_hyper_original = res_lsq_hyper_original.x + x_hyper_original = np.array([0.001, 0.001]) - # 현재 단계 예측 침하량 산정 (침하 예측 끝까지) - sp_hyper_nonlinear = generate_data_hyper(x_hyper_nonlinear, time_hyper) - sp_hyper_weight_nonlinear = generate_data_hyper(x_hyper_weight_nonlinear, time_hyper) - sp_hyper_original = generate_data_hyper(x_hyper_original, time_hyper) - - # 예측 침하량 산정 - sp_hyper_nonlinear = sp_hyper_nonlinear + s0_hyper - sp_hyper_weight_nonlinear = sp_hyper_weight_nonlinear + s0_hyper - sp_hyper_original = sp_hyper_original + s0_hyper + # 최종 예측값 산정 + sp_hyper_nonlinear = generate_data_hyper(x_hyper_nonlinear, time_hyper) + s0_hyper + sp_hyper_weight_nonlinear = generate_data_hyper(x_hyper_weight_nonlinear, time_hyper) + s0_hyper + sp_hyper_original = generate_data_hyper(x_hyper_original, time_hyper) + s0_hyper time_hyper = time_hyper + t0_hyper # ===============================