Skip to content

Commit

Permalink
Merge pull request #25503 from dschwen/progress_output_22906
Browse files Browse the repository at this point in the history
Add progress bar output
  • Loading branch information
dschwen authored Sep 24, 2023
2 parents 4d57066 + 85c3576 commit 94e0642
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 64 deletions.
19 changes: 19 additions & 0 deletions framework/doc/content/source/outputs/ProgressOutput.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Progress

!syntax description /Outputs/Progress

## Overview

The Progress output displays an ASCII art progress bar at the end of each timestep, visualizing the amount of simulation time that has passed vs. the total simulation time. It requires the use of a transient executioner along with predetermined start and end times. The width of the bar widget can be specified using the [!param](/Outputs/Progress/progress_bar_width) parameter. If omitted the value of the `MOOSE_PPS_WIDTH` environment variable is queried. If that variable is not set the terminal window width is queried (with a fallback value of 132 chars).

```
+-Progress (full.i)--------------------------------+
|#########################.........................|
+--------------------------------------------------+
```

!syntax parameters /Outputs/Progress

!syntax inputs /Outputs/Progress

!syntax children /Outputs/Progress
13 changes: 10 additions & 3 deletions framework/include/executioners/Transient.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class Transient : public Executioner
/**
* Get the current time.
*/
virtual Real getTime() { return _time; };
virtual Real getTime() const { return _time; };

/**
* Get the current target time
Expand Down Expand Up @@ -120,6 +120,7 @@ class Transient : public Executioner
* @return Pointer to the time stepper for this Executioner
*/
TimeStepper * getTimeStepper() { return _time_stepper; }
const TimeStepper * getTimeStepper() const { return _time_stepper; }

/**
* Set the timestepper to use.
Expand All @@ -143,7 +144,7 @@ class Transient : public Executioner
* Get the time scheme used
* @return MooseEnum with the time scheme
*/
Moose::TimeIntegratorType getTimeScheme() { return _time_scheme; }
Moose::TimeIntegratorType getTimeScheme() const { return _time_scheme; }

/**
* Get the set of sync times
Expand All @@ -167,12 +168,18 @@ class Transient : public Executioner
* Return the start time
* @return The start time
*/
Real getStartTime() { return _start_time; }
Real getStartTime() const { return _start_time; }

/**
* Get the end time
* @return The end time
*/
Real getEndTime() const { return _end_time; }

/**
* Get a modifiable reference to the end time
* @return The end time
*/
Real & endTime() { return _end_time; }

/**
Expand Down
36 changes: 36 additions & 0 deletions framework/include/outputs/ProgressOutput.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#pragma once

#include "Output.h"

class Transient;

/**
* Output a simulation time progress bar on the console
*/
class ProgressOutput : public Output
{
public:
static InputParameters validParams();

ProgressOutput(const InputParameters & parameters);

protected:
void output() override;

const Transient * const _transient_executioner;

/// display input file name in the progress bar title
const bool _use_filename;

/// total length of the progress bar
const unsigned int _length;
};
5 changes: 0 additions & 5 deletions framework/include/utils/FormattedTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,6 @@ class FormattedTable
std::vector<std::string>::iterator & col_begin,
std::vector<std::string>::iterator & col_end) const;

/**
* Returns the width of the terminal using sys/ioctl
*/
unsigned short getTermWidth(bool use_environment) const;

/**
* Data structure for the console table:
* The first part of the pair tracks the independent variable (normally time) and is associated
Expand Down
5 changes: 5 additions & 0 deletions framework/include/utils/MooseUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ std::string baseName(const std::string & name);
*/
std::string hostname();

/**
* Returns the width of the terminal using sys/ioctl
*/
unsigned short getTermWidth(bool use_environment);

/**
* @returns A cleaner representation of the c++ type \p cpp_type.
*/
Expand Down
4 changes: 4 additions & 0 deletions framework/src/actions/CommonOutputAction.C
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ CommonOutputAction::validParams()
"Output the scalar and postprocessor results using the default settings for GNUPlot output");
params.addParam<bool>(
"solution_history", false, "Print a solution history file (.slh) using the default settings");
params.addParam<bool>("progress", false, "Print a progress bar");
params.addParam<bool>("dofmap", false, "Create the dof map .json output file");
params.addParam<bool>("controls", false, "Enable the screen output of Control systems.");

Expand Down Expand Up @@ -220,6 +221,9 @@ CommonOutputAction::act()
if (getParam<bool>("solution_history"))
create("SolutionHistory");

if (getParam<bool>("progress"))
create("Progress");

if (getParam<bool>("dofmap"))
create("DOFMap");

Expand Down
68 changes: 68 additions & 0 deletions framework/src/outputs/ProgressOutput.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "ProgressOutput.h"
#include "Transient.h"

registerMooseObjectAliased("MooseApp", ProgressOutput, "Progress");

InputParameters
ProgressOutput::validParams()
{
auto params = Output::validParams();
params.addClassDescription("Output a simulation time progress bar on the console.");
params.set<ExecFlagEnum>("execute_on") = {EXEC_TIMESTEP_END};
params.addParam<bool>(
"use_filename", true, "Put the input filename into the title of the progress bar");
params.addParam<unsigned int>(
"progress_bar_width",
"Explicitly specify the bar width. If omitted the MOOSE_PPS_WIDTH environment variable or, "
"if not set, the terminal width is queried.");
return params;
}

ProgressOutput::ProgressOutput(const InputParameters & parameters)
: Output(parameters),
_transient_executioner(dynamic_cast<Transient *>(_app.getExecutioner())),
_use_filename(getParam<bool>("use_filename")),
_length(isParamValid("progress_bar_width") ? getParam<unsigned int>("progress_bar_width")
: MooseUtils::getTermWidth(true) - 2)
{
}

void
ProgressOutput::output()
{
if (_transient_executioner == nullptr || _current_execute_flag != EXEC_TIMESTEP_END)
return;

const auto passed = _transient_executioner->getTime() - _transient_executioner->getStartTime();
const auto total = _transient_executioner->getEndTime() - _transient_executioner->getStartTime();
if (total == 0)
return;

// length of filled portion
const auto progress = std::round((passed * _length) / total);

// title string
std::string title = name();
if (_use_filename)
title += " (" + getMooseApp().getFileName() + ')';
if (title.length() >= _length - 1)
title = title.substr(0, _length - 4) + "...";

// top line
Moose::out << "+-" << title << std::string(_length - 1 - title.length(), '-') << "+\n";

// bar
Moose::out << '|' << std::string(progress, '#') << std::string(_length - progress, '.') << "|\n";

// bottom line
Moose::out << '+' << std::string(_length, '-') << "+\n";
}
58 changes: 2 additions & 56 deletions framework/src/utils/FormattedTable.C
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@
#include <iomanip>
#include <iterator>

// Used for terminal width
#ifndef __WIN32__
#include <sys/ioctl.h>
#endif
#include <cstdlib>

const unsigned short FormattedTable::_column_width = 15;
const unsigned short FormattedTable::_min_pps_width = 40;

Expand Down Expand Up @@ -258,9 +252,9 @@ FormattedTable::printTable(std::ostream & out,
unsigned short term_width;

if (suggested_term_width == "ENVIRONMENT")
term_width = getTermWidth(true);
term_width = MooseUtils::getTermWidth(true);
else if (suggested_term_width == "AUTO")
term_width = getTermWidth(false);
term_width = MooseUtils::getTermWidth(false);
else
term_width = MooseUtils::stringToInteger(suggested_term_width);

Expand Down Expand Up @@ -583,54 +577,6 @@ FormattedTable::fillEmptyValues()
std::dynamic_pointer_cast<TableValueBase>(std::make_shared<TableValue<char>>('0'));
}

unsigned short
FormattedTable::getTermWidth(bool use_environment) const
{
#ifndef __WIN32__
struct winsize w;
#else
struct
{
unsigned short ws_col;
} w;
#endif
/**
* Initialize the value we intend to populate just in case
* the system call fails
*/
w.ws_col = std::numeric_limits<unsigned short>::max();

if (use_environment)
{
char * pps_width = std::getenv("MOOSE_PPS_WIDTH");
if (pps_width != NULL)
{
std::stringstream ss(pps_width);
ss >> w.ws_col;
}
}
// Default to AUTO if no environment variable was set
if (w.ws_col == std::numeric_limits<unsigned short>::max())
{
#ifndef __WIN32__
try
{
ioctl(0, TIOCGWINSZ, &w);
}
catch (...)
#endif
{
}
}

// Something bad happened, make sure we have a sane value
// 132 seems good for medium sized screens, and is available as a GNOME preset
if (w.ws_col == std::numeric_limits<unsigned short>::max())
w.ws_col = 132;

return w.ws_col;
}

MooseEnum
FormattedTable::getWidthModes()
{
Expand Down
51 changes: 51 additions & 0 deletions framework/src/utils/MooseUtils.C
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <istream>
#include <iterator>
#include <ctime>
#include <cstdlib>

// System includes
#include <sys/stat.h>
Expand All @@ -46,6 +47,8 @@
#include <windows.h>
#include <winbase.h>
#include <fileapi.h>
#else
#include <sys/ioctl.h>
#endif

namespace MooseUtils
Expand Down Expand Up @@ -649,6 +652,54 @@ hostname()
return hostname;
}

unsigned short
getTermWidth(bool use_environment)
{
#ifndef __WIN32__
struct winsize w;
#else
struct
{
unsigned short ws_col;
} w;
#endif
/**
* Initialize the value we intend to populate just in case
* the system call fails
*/
w.ws_col = std::numeric_limits<unsigned short>::max();

if (use_environment)
{
char * pps_width = std::getenv("MOOSE_PPS_WIDTH");
if (pps_width != NULL)
{
std::stringstream ss(pps_width);
ss >> w.ws_col;
}
}
// Default to AUTO if no environment variable was set
if (w.ws_col == std::numeric_limits<unsigned short>::max())
{
#ifndef __WIN32__
try
{
ioctl(0, TIOCGWINSZ, &w);
}
catch (...)
#endif
{
}
}

// Something bad happened, make sure we have a sane value
// 132 seems good for medium sized screens, and is available as a GNOME preset
if (w.ws_col == std::numeric_limits<unsigned short>::max())
w.ws_col = 132;

return w.ws_col;
}

void
MaterialPropertyStorageDump(
const HashMap<const libMesh::Elem *, HashMap<unsigned int, MaterialProperties>> & props)
Expand Down
27 changes: 27 additions & 0 deletions test/tests/outputs/progress/common.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[Mesh]
[gen]
type = GeneratedMeshGenerator
dim = 1
[]
[]

[Variables]
[u]
[]
[]

[Problem]
solve = false
kernel_coverage_check = false
[]

[Executioner]
type = Transient
start_time = 10
end_time = 20
dt = 5
[]

[Outputs]
progress = true
[]
Loading

0 comments on commit 94e0642

Please sign in to comment.