From c7563cc56232e0652455c252a1f90bf6e53a57fc Mon Sep 17 00:00:00 2001 From: Momchil Minkov Date: Mon, 27 Jan 2025 15:17:29 +0100 Subject: [PATCH] Update error handling in webapi, and Heat->HeatCharge in message --- .../tcad/data/monitor_data/charge.py | 4 +-- tidy3d/web/api/webapi.py | 25 ++++++++++--- tidy3d/web/core/constants.py | 1 + tidy3d/web/core/task_core.py | 35 ++++++++++++++++--- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/tidy3d/components/tcad/data/monitor_data/charge.py b/tidy3d/components/tcad/data/monitor_data/charge.py index c5d29b356d..42b4a21e12 100644 --- a/tidy3d/components/tcad/data/monitor_data/charge.py +++ b/tidy3d/components/tcad/data/monitor_data/charge.py @@ -41,8 +41,8 @@ class SteadyPotentialData(HeatChargeMonitorData): potential: FieldDataset = pd.Field( None, - title="Voltage series", - description="Contains the voltages.", + title="Electric potential series", + description="Contains the electric potential series.", ) @property diff --git a/tidy3d/web/api/webapi.py b/tidy3d/web/api/webapi.py index 39bec5fcae..691a1fc818 100644 --- a/tidy3d/web/api/webapi.py +++ b/tidy3d/web/api/webapi.py @@ -1,6 +1,8 @@ """Provides lowest level, user-facing interface to server.""" +import json import os +import tempfile import time from datetime import datetime, timedelta from typing import Callable, Dict, List @@ -46,7 +48,7 @@ BETA_TASK_TYPES = ["HEAT", "EME"] # map task_type to solver name for display -SOLVER_NAME = {"FDTD": "FDTD", "HEAT": "Heat", "MODE_SOLVER": "Mode", "EME": "EME"} +SOLVER_NAME = {"FDTD": "FDTD", "HEAT": "HeatCharge", "MODE_SOLVER": "Mode", "EME": "EME"} def _get_url(task_id: str) -> str: @@ -405,10 +407,19 @@ def get_status(task_id) -> str: if status == "visualize": return "success" if status == "error": - raise WebError( - f"Error running task {task_id}! Use 'web.download_log(task_id)' to " - "download and examine the solver log, and/or contact customer support for help." - ) + try: + # Try to obtain the error message + task = SimulationTask(taskId=task_id) + with tempfile.NamedTemporaryFile(suffix=".json") as tmp_file: + task.get_error_json(to_file=tmp_file.name) + with open(tmp_file.name) as f: + error_content = json.load(f) + error_msg = error_content["msg"] + except Exception: + # If the error message could not be obtained, raise a generic error message + error_msg = "Error message could not be obtained, please contact customer support." + + raise WebError(f"Error running task {task_id}! {error_msg}") return status @@ -547,6 +558,10 @@ def monitor_preprocess() -> None: perc_done, _ = get_run_info(task_id) new_description = "solver progress" progress.update(pbar_pd, completed=100, refresh=True, description=new_description) + else: + while get_status(task_id) == "running": + perc_done, _ = get_run_info(task_id) + time.sleep(1.0) else: # non-verbose case, just keep checking until status is not running or perc_done >= 100 diff --git a/tidy3d/web/core/constants.py b/tidy3d/web/core/constants.py index 6243e02f9e..edadf62445 100644 --- a/tidy3d/web/core/constants.py +++ b/tidy3d/web/core/constants.py @@ -28,3 +28,4 @@ SIM_FILE_HDF5_GZ = "simulation.hdf5.gz" MODE_FILE_HDF5_GZ = "mode_solver.hdf5.gz" MODE_DATA_HDF5_GZ = "output/mode_solver_data.hdf5.gz" +SIM_ERROR_FILE = "output/tidy3d_error.json" diff --git a/tidy3d/web/core/task_core.py b/tidy3d/web/core/task_core.py index 137b5b1afc..2ed95e7535 100644 --- a/tidy3d/web/core/task_core.py +++ b/tidy3d/web/core/task_core.py @@ -14,7 +14,7 @@ from . import http_util from .cache import FOLDER_CACHE -from .constants import SIM_FILE_HDF5_GZ, SIM_LOG_FILE, SIMULATION_DATA_HDF5_GZ +from .constants import SIM_ERROR_FILE, SIM_FILE_HDF5_GZ, SIM_LOG_FILE, SIMULATION_DATA_HDF5_GZ from .core_config import get_logger_console from .environment import Env from .exceptions import WebError @@ -292,7 +292,7 @@ def get_simulation_json(self, to_file: str, verbose: bool = True) -> pathlib.Pat Parameters ---------- to_file: str - save file to path. + Save file to path. verbose: bool = True Whether to display progress bars. @@ -469,7 +469,7 @@ def get_sim_data_hdf5( Parameters ---------- to_file: str - save file to path. + Save file to path. verbose: bool = True Whether to display progress bars. progress_callback : Callable[[float], None] = None @@ -526,7 +526,7 @@ def get_simulation_hdf5( Parameters ---------- to_file: str - save file to path. + Save file to path. verbose: bool = True Whether to display progress bars. progress_callback : Callable[[float], None] = None @@ -576,7 +576,7 @@ def get_log( Parameters ---------- to_file: str - save file to path. + Save file to path. verbose: bool = True Whether to display progress bars. progress_callback : Callable[[float], None] = None @@ -599,6 +599,31 @@ def get_log( progress_callback=progress_callback, ) + def get_error_json(self, to_file: str, verbose: bool = True) -> pathlib.Path: + """Get error json file for a :class:`.Simulation` from server. + + Parameters + ---------- + to_file: str + Save file to path. + verbose: bool = True + Whether to display progress bars. + + Returns + ------- + path: pathlib.Path + Path to saved file. + """ + if not self.task_id: + raise WebError("Expected field 'task_id' is unset.") + + return download_file( + self.task_id, + SIM_ERROR_FILE, + to_file=to_file, + verbose=verbose, + ) + def abort(self): """Abort current task from server.""" if not self.task_id: