Skip to content

Commit

Permalink
Add progress output (idaholab#22906)
Browse files Browse the repository at this point in the history
  • Loading branch information
dschwen committed Sep 18, 2023
1 parent 83eb82b commit 90705a2
Show file tree
Hide file tree
Showing 11 changed files with 260 additions and 61 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 an 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/DOFMap

!syntax inputs /Outputs/DOFMap

!syntax children /Outputs/DOFMap
33 changes: 33 additions & 0 deletions framework/include/outputs/ProgressOutput.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//* 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;

class ProgressOutput : public Output
{
public:
static InputParameters validParams();

ProgressOutput(const InputParameters & parameters);

protected:
void output() override;

Transient * _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
70 changes: 70 additions & 0 deletions framework/src/outputs/ProgressOutput.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//* 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 "ProgressOutput.h"
#include "Transient.h"

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

InputParameters
ProgressOutput::validParams()
{
auto params = Output::validParams();
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 are 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 ||
!_transient)
return;

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

// length of filled portion
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
[]
30 changes: 30 additions & 0 deletions test/tests/outputs/progress/full.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[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]
type = Progress
progress_bar_width = 50
[]
[]
19 changes: 19 additions & 0 deletions test/tests/outputs/progress/tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[Tests]
issues = '#22906'
design = ProgressOutput.md
[full]
type = RunApp
input = 'full.i'
expect_out = "\+-Progress \(.*\)-*\+\n\|#########################.........................\|\n\+--------------------------------------------------\+"
requirement = "The system shall support printing a progress bar that indicates the fraction of total simulation time passed."
[]
[common]
type = RunApp
input = 'common.i'
expect_out = '\+-progress \(.*\)-*\+'
requirement = "The system shall support using a shortcut to set up a progress bar output."
[]
[]



0 comments on commit 90705a2

Please sign in to comment.