Skip to content

Commit 35adbb2

Browse files
committed
MAINT: Attempt to improve progressbar
1 parent b41832d commit 35adbb2

6 files changed

Lines changed: 51 additions & 33 deletions

File tree

src/porepy/models/model_runner.py

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212

1313
import porepy as pp
1414
from porepy.models.solution_strategy import SolutionStrategy
15-
from porepy.time.time_step_status import TimeStepperStatusFailure
15+
from porepy.time.time_step_status import (
16+
TimeStepperStatusFailure,
17+
TimeStepperStatusSuccess,
18+
)
1619
from porepy.time.time_stepper import TimeStepper
1720
from porepy.utils.ui_and_logging import DummyProgressBar
1821
from porepy.utils.ui_and_logging import (
@@ -219,6 +222,7 @@ def init_time_progressbar(self) -> None:
219222
use_progress_bar = (
220223
self.params.get("progressbars", False) and self._is_time_dependent
221224
)
225+
use_progress_bar = True
222226
if use_progress_bar and progressbar_class is DummyProgressBar:
223227
logger.warning(
224228
"Progress bars are requested, but `tqdm` is not installed. The time"
@@ -232,26 +236,22 @@ def init_time_progressbar(self) -> None:
232236
self.params.update({"_nl_progress_bar_position": 1})
233237

234238
if use_progress_bar:
235-
# Create a time bar of length of expected number of time steps, estimated
236-
# from the initial time step size.
237-
# NOTE: Adaptive time stepping updates the bar proportionally if step sizes
238-
# change from initial time step size.
239-
expected_time_steps: int = int(
240-
np.round(
241-
(
242-
self.model.time_manager.schedule[-1]
243-
- self.model.time_manager.schedule[0]
244-
)
245-
/ self.model.time_manager.dt
246-
)
247-
)
239+
# Create a time bar of length of expected simulation time.
240+
241+
# Creating a custom format string. Difference from the default: it converts
242+
# the simulation time (done/total) to the a scientific format with :.1e.
243+
l_bar = "{desc}: {percentage:3.0f}%|"
244+
r_bar = "| {n:.1e}/{total:.1e} [{elapsed}<{remaining}, {rate_fmt}{postfix}]"
245+
bar_format = l_bar + "{bar}" + r_bar
248246

249247
# NOTE: If tqdm is not installed, this returns a DummyProgressBar instance.
250248
self.time_progressbar = progressbar_class(
251-
range(expected_time_steps),
249+
total=self.model.time_manager.schedule[-1],
252250
desc="Time loop",
253251
position=0,
254252
dynamic_ncols=True,
253+
bar_format=bar_format,
254+
postfix=self._progressbar_postfix(),
255255
)
256256
else:
257257
self.time_progressbar = DummyProgressBar()
@@ -295,13 +295,17 @@ def _run_time_dependent(self) -> ModelRunnerStatus:
295295

296296
with logging_redirect_tqdm([logging.root]):
297297
while not self.model.time_manager.final_time_reached():
298+
# Update the progressbar before the time step.
299+
self.time_progressbar.set_postfix_str(self._progressbar_postfix())
300+
298301
# Perform the time step.
299302
time_step_status = self.time_stepper.perform_time_step(
300303
self.model, self.solver
301304
)
302305

303-
# Progressbar update.
304-
self.update_time_progressbar()
306+
# Update the progressbar after the time step.
307+
if isinstance(time_step_status, TimeStepperStatusSuccess):
308+
self.time_progressbar.update(n=time_step_status.dt)
305309

306310
# Abort simulation if time step was stopped.
307311
match time_step_status:
@@ -314,15 +318,6 @@ def _run_time_dependent(self) -> ModelRunnerStatus:
314318
return ModelRunnerStatusSuccess()
315319
return ModelRunnerStatusFailure("Final time was not reached.")
316320

317-
def update_time_progressbar(self) -> None:
318-
"""Update the time progressbar with the current time and time step size."""
319-
self.time_progressbar.set_postfix_str(
320-
f"Time step size {self.model.time_manager.dt:.2e}"
321-
)
322-
self.time_progressbar.update(
323-
n=np.round(
324-
self.model.time_manager.time
325-
/ self.model.time_manager.time_final
326-
* self.time_progressbar.total
327-
)
328-
)
321+
def _progressbar_postfix(self) -> str:
322+
"""Formats a progressbar postfix string with dt."""
323+
return f"Δt={self.model.time_manager.dt:.1e}"

src/porepy/time/time_step_status.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ def serialize(self) -> str:
6262
class TimeStepperStatusSuccess(TimeStepperStatus):
6363
"""The TimeStepper made a time step successfully."""
6464

65+
dt: float
66+
"""Simulation time step magnitude."""
67+
time: float
68+
"""Simulation time at the end of the time step (t0 + dt)."""
69+
6570
nonlinear_solver_status: NonlinearSolverStatusConverged
6671
"""Nonlinear solver status that caused the time step success."""
6772

src/porepy/time/time_stepper.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,13 @@ def _compute_next_time_step(
152152
# The problem is time-dependent and linear.
153153
num_iterations = 1
154154

155+
current_dt = self.time_manager.dt
156+
new_time = self.time_manager.time
155157
self.time_manager.compute_time_step(iterations=num_iterations)
156158
return TimeStepperStatusSuccess(
157-
nonlinear_solver_status=nonlinear_solver_status
159+
dt=current_dt,
160+
time=new_time,
161+
nonlinear_solver_status=nonlinear_solver_status,
158162
)
159163

160164
elif isinstance(nonlinear_solver_status, NonlinearSolverStatusFailed):

tests/numerics/nonlinear/test_nonlinear_solvers.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@
3333
def time_step_success() -> TimeStepperStatusSuccess:
3434
"""Create a successful time-step status for statistics tests."""
3535
return TimeStepperStatusSuccess(
36+
time=1.0,
37+
dt=0.5,
3638
nonlinear_solver_status=NonlinearSolverStatusConverged(
3739
convergence_statuses=ConvergenceStatusCollection(),
3840
divergence_statuses=ConvergenceStatusCollection(),
39-
)
41+
),
4042
)
4143

4244

tests/time/test_time_stepper.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,3 +805,14 @@ def test_solve_failure_time_dependent_statistics(statistics_path: Path):
805805
}
806806

807807
assert DeepDiff(data, reference_data) == {}
808+
809+
810+
if __name__ == "__main__":
811+
test_model_time_step_control(
812+
{
813+
"num_nonlinear_iterations": [8, 8, 8, 8, 8, 8],
814+
"time_step_converged": [True, True, True, True, True, True],
815+
"exported_dt_expected": [1, 0.4, 0.16, 0.1, 0.1, 0.1],
816+
"schedule_end": 1.86,
817+
},
818+
)

tests/viz/test_solver_statistics.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from porepy.numerics.nonlinear.convergence_check import (
1212
ConvergenceInfoCollection,
1313
ConvergenceInfoHistory,
14-
ConvergenceStatus,
1514
ConvergenceStatusCollection,
1615
ConvergenceStatusHistory,
1716
)
@@ -76,7 +75,9 @@ def time_stepper_status(
7675
if status == "converged":
7776
solver_status = nonlinear_solver_status(status)
7877
assert isinstance(solver_status, NonlinearSolverStatusConverged)
79-
return TimeStepperStatusSuccess(nonlinear_solver_status=solver_status)
78+
return TimeStepperStatusSuccess(
79+
time=1.0, dt=0.5, nonlinear_solver_status=solver_status
80+
)
8081
elif status == "continue_iterating":
8182
return TimeStepperStatusContinueIterating(
8283
attempt=0, nonlinear_solver_status=nonlinear_solver_status("failed")

0 commit comments

Comments
 (0)