LCOV - code coverage report
Current view: top level - src/utils - FileRangeBuilder.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 61 78 78.2 %
Date: 2025-07-17 01:28:37 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "FileRangeBuilder.h"
      11             : 
      12             : // MOOSE includes
      13             : #include "InputParameters.h"
      14             : 
      15             : #include "libmesh/int_range.h"
      16             : #include "pcrecpp.h"
      17             : #include "tinydir.h"
      18             : 
      19             : InputParameters
      20       57935 : FileRangeBuilder::validParams()
      21             : {
      22       57935 :   InputParameters params = emptyInputParameters();
      23       57935 :   params.addParam<FileName>("file",
      24             :                             "Name of single image file to extract mesh parameters from.  "
      25             :                             "If provided, a 2D mesh is created.");
      26       57935 :   params.addParam<FileNameNoExtension>("file_base",
      27             :                                        "Image file base to open, use this option when "
      28             :                                        "a stack of images must be read (ignored if "
      29             :                                        "'file' is given)");
      30       57935 :   params.addParam<std::vector<unsigned int>>(
      31             :       "file_range",
      32             :       "Range of images to analyze, used with 'file_base' (ignored if 'file' is given)");
      33       57935 :   params.addParam<std::string>("file_suffix", "Suffix of the file to open, e.g. 'png'");
      34       57935 :   return params;
      35           0 : }
      36             : 
      37         453 : FileRangeBuilder::FileRangeBuilder(const InputParameters & params) : _status(0)
      38             : {
      39         453 :   bool has_file = params.isParamValid("file"), has_file_base = params.isParamValid("file_base"),
      40         453 :        has_file_range = params.isParamValid("file_range"),
      41         453 :        has_file_suffix = params.isParamValid("file_suffix");
      42             : 
      43             :   // Variables to be (possibly) used below...
      44         453 :   std::string file;
      45         453 :   std::string file_base;
      46         453 :   std::vector<unsigned int> file_range;
      47             : 
      48         453 :   if (has_file)
      49             :   {
      50         119 :     file = params.get<FileName>("file");
      51             : 
      52             :     // Set the file_suffix parameter in the passed-in params object based on the input filename
      53         119 :     _file_suffix = file.substr(file.find_last_of(".") + 1);
      54             :   }
      55         453 :   if (has_file_base)
      56         308 :     file_base = params.get<FileNameNoExtension>("file_base");
      57         453 :   if (has_file_range)
      58         271 :     file_range = params.get<std::vector<unsigned int>>("file_range");
      59         453 :   if (has_file_suffix)
      60         308 :     _file_suffix = params.get<std::string>("file_suffix");
      61             : 
      62             :   // Check that the combination of params provided is valid
      63             : 
      64             :   // 1.) Provided both a filename and a file base
      65         453 :   if (has_file && has_file_base)
      66             :   {
      67           0 :     _status = 1;
      68           0 :     return;
      69             :   }
      70             : 
      71             :   // 2.) Provided neither a filename nor a file base
      72         453 :   if (!has_file && !has_file_base)
      73             :   {
      74          26 :     _status = 2;
      75          26 :     return;
      76             :   }
      77             : 
      78             :   // 3.) Provided a file base but not a suffix
      79         427 :   if (has_file_base && !has_file_suffix)
      80             :   {
      81           0 :     _status = 3;
      82           0 :     return;
      83             :   }
      84             : 
      85             :   // 4.) Provided a filename and a range, warn that the range will be ignored.
      86         427 :   if (has_file && has_file_range)
      87           0 :     mooseWarning("Warning: file_range was ignored since a filename was provided.");
      88             : 
      89             :   // 5.) Provided a file_base but not a file_range, we'll create one
      90         427 :   if (has_file_base && !has_file_range)
      91             :   {
      92          37 :     file_range.push_back(0);
      93          37 :     file_range.push_back(std::numeric_limits<unsigned int>::max());
      94             :   }
      95             : 
      96             :   // 6.) Provided a file_range with a single entry, so repeat it for
      97             :   // them.  This signifies a single image (i.e. 2D Mesh) is to be
      98             :   // used.
      99         427 :   if (has_file_range && file_range.size() == 1)
     100         258 :     file_range.push_back(file_range[0]);
     101             : 
     102             :   // 7.) Provided a file_range with too many entries, print a
     103             :   // warning and truncate the extra values.
     104         427 :   if (has_file_range && file_range.size() != 2)
     105             :   {
     106           0 :     mooseWarning("A maximum of two values are allowed in the file_range, extra values truncated.");
     107           0 :     file_range.resize(2);
     108             :   }
     109             : 
     110             :   // Make sure that the range is in ascending order
     111         427 :   std::sort(file_range.begin(), file_range.end());
     112             : 
     113             :   // Build up the filenames parameter, and inject it into the InputParameters object
     114         427 :   if (has_file)
     115         119 :     _filenames.push_back(file);
     116             : 
     117         308 :   else if (has_file_base)
     118             :   {
     119             :     // Separate the file base from the path
     120         308 :     std::pair<std::string, std::string> split_file = MooseUtils::splitFileName(file_base);
     121             : 
     122             :     // Create directory object
     123         308 :     tinydir_dir dir;
     124         308 :     tinydir_open_sorted(&dir, split_file.first.c_str());
     125             : 
     126             :     // This regex will capture the file_base and any number of digits when used with FullMatch()
     127         308 :     std::ostringstream oss;
     128         308 :     oss << "(" << split_file.second << ".*?(\\d+))\\..*";
     129         308 :     pcrecpp::RE file_base_and_num_regex(oss.str());
     130             : 
     131             :     // Loop through the files in the directory
     132        7004 :     for (const auto i : make_range(dir.n_files))
     133             :     {
     134             :       // Update the current file
     135             :       tinydir_file file;
     136        6696 :       tinydir_readfile_n(&dir, &file, i);
     137             : 
     138             :       // Store the file if it has proper extension as in numeric range
     139        6696 :       if (!file.is_dir && MooseUtils::hasExtension(file.name, _file_suffix))
     140             :       {
     141        5960 :         std::string the_base;
     142        5960 :         unsigned int file_num = 0;
     143        5960 :         file_base_and_num_regex.FullMatch(file.name, &the_base, &file_num);
     144             : 
     145        5960 :         if (!the_base.empty() && file_num >= file_range[0] && file_num <= file_range[1])
     146        1066 :           _filenames.push_back(split_file.first + "/" + file.name);
     147        5960 :       }
     148             :     }
     149         308 :     tinydir_close(&dir);
     150         308 :   }
     151             : 
     152             :   else
     153           0 :     mooseError("We'll never get here!");
     154             : 
     155             :   // If we made it here, there were no errors
     156         505 : }
     157             : 
     158             : void
     159          36 : FileRangeBuilder::errorCheck()
     160             : {
     161          36 :   switch (_status)
     162             :   {
     163          36 :     case 0:
     164          36 :       return;
     165           0 :     case 1:
     166           0 :       mooseError("Cannot provide both file and file_base parameters");
     167             :       break;
     168           0 :     case 2:
     169           0 :       mooseError("You must provide a valid value for either the 'file' parameter or the "
     170             :                  "'file_base' parameter.");
     171             :       break;
     172           0 :     case 3:
     173           0 :       mooseError(
     174             :           "If you provide a 'file_base', you must also provide a valid 'file_suffix', e.g. 'png'.");
     175             :       break;
     176           0 :     default:
     177           0 :       mooseError("Unknown error code!");
     178             :   }
     179             : }

Generated by: LCOV version 1.14