www.mooseframework.org
ImageMesh.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 "ImageMesh.h"
11 #include "pcrecpp.h"
12 #include "MooseApp.h"
13 
14 #include <cstdlib> // std::system, mkstemp
15 #include <fstream>
16 
17 #include "libmesh/mesh_generation.h"
18 #include "libmesh/unstructured_mesh.h"
19 
20 registerMooseObject("MooseApp", ImageMesh);
21 
24 {
27  params.addClassDescription("Generated mesh with the aspect ratio of a given image stack.");
28 
29  // Add ImageMesh-specific params
30  params.addParam<bool>(
31  "scale_to_one", true, "Whether or not to scale the image so its max dimension is 1");
32  params.addRangeCheckedParam<Real>("cells_per_pixel",
33  1.0,
34  "cells_per_pixel<=1.0",
35  "The number of mesh cells per pixel, must be <=1 ");
36 
37  return params;
38 }
39 
41  : GeneratedMesh(parameters),
42  FileRangeBuilder(parameters),
43  _scale_to_one(getParam<bool>("scale_to_one")),
44  _cells_per_pixel(getParam<Real>("cells_per_pixel"))
45 {
46  // Failure is not an option
47  errorCheck();
48 }
49 
50 ImageMesh::ImageMesh(const ImageMesh & other_mesh)
51  : GeneratedMesh(other_mesh),
52  FileRangeBuilder(other_mesh.parameters()),
53  _scale_to_one(getParam<bool>("scale_to_one")),
54  _cells_per_pixel(getParam<Real>("cells_per_pixel"))
55 {
56 }
57 
58 std::unique_ptr<MooseMesh>
60 {
61  return std::make_unique<ImageMesh>(*this);
62 }
63 
64 void
66 {
67  // A list of filenames of length 1 means we are building a 2D mesh
68  if (_filenames.size() == 1)
70 
71  else
73 }
74 
75 void
76 ImageMesh::buildMesh3D(const std::vector<std::string> & filenames)
77 {
78  // If the user gave us a "stack" with 0 or 1 files in it, we can't
79  // really create a 3D Mesh from that
80  if (filenames.size() <= 1)
81  mooseError("ImageMesh error: Cannot create a 3D ImageMesh from an image stack with ",
82  filenames.size(),
83  " images.");
84 
85  // For each file in the stack, process it using the 'file' command.
86  // We want to be sure that all the images in the stack are the same
87  // size, for example...
88  int xpixels = 0, ypixels = 0, zpixels = filenames.size();
89 
90  // Take pixel info from the first image in the stack to determine the aspect ratio
91  GetPixelInfo(filenames[0], xpixels, ypixels);
92 
93  // TODO: Check that all images are the same aspect ratio and have
94  // the same number of pixels? ImageFunction does not currently do
95  // this...
96  // for (const auto & filename : filenames)
97  // {
98  // // Extract the number of pixels from the image using the file command
99  // GetPixelInfo(filename, xpixels, ypixels);
100  //
101  // // Moose::out << "Image " << filename << " has size: " << xpixels << " by " << ypixels <<
102  // std::endl;
103  // }
104 
105  // Use the number of x and y pixels and the number of images to
106  // determine the the x, y, and z dimensions of the mesh. We assume
107  // that there is 1 pixel in the z-direction for each image in the
108  // stack.
109 
110  // Set the maximum dimension to 1.0 while scaling the other
111  // directions to maintain the aspect ratio.
112  _xmax = xpixels;
113  _ymax = ypixels;
114  _zmax = zpixels;
115 
116  if (_scale_to_one)
117  {
119  _xmax /= max;
120  _ymax /= max;
121  _zmax /= max;
122  }
123 
124  // Compute the number of cells in the x and y direction based on
125  // the user's cells_per_pixel parameter. Note: we use ints here
126  // because the GeneratedMesh params object uses ints for these...
127  _nx = static_cast<int>(_cells_per_pixel * xpixels);
128  _ny = static_cast<int>(_cells_per_pixel * ypixels);
129  _nz = static_cast<int>(_cells_per_pixel * zpixels);
130 
131  // Actually build the Mesh
132  MeshTools::Generation::build_cube(dynamic_cast<UnstructuredMesh &>(getMesh()),
133  _nx,
134  _ny,
135  _nz,
136  /*xmin=*/0.,
137  /*xmax=*/_xmax,
138  /*ymin=*/0.,
139  /*ymax=*/_ymax,
140  /*zmin=*/0.,
141  /*zmax=*/_zmax,
142  HEX8);
143 }
144 
145 void
146 ImageMesh::buildMesh2D(const std::string & filename)
147 {
148  int xpixels = 0, ypixels = 0;
149 
150  // Extract the number of pixels from the image using the file command
151  GetPixelInfo(filename, xpixels, ypixels);
152 
153  // Set the maximum dimension to 1.0 while scaling the other
154  // direction to maintain the aspect ratio.
155  _xmax = xpixels;
156  _ymax = ypixels;
157 
158  if (_scale_to_one)
159  {
161  _xmax /= max;
162  _ymax /= max;
163  }
164 
165  // Compute the number of cells in the x and y direction based on
166  // the user's cells_per_pixel parameter. Note: we use ints here
167  // because the GeneratedMesh params object uses ints for these...
168  _nx = static_cast<int>(_cells_per_pixel * xpixels);
169  _ny = static_cast<int>(_cells_per_pixel * ypixels);
170 
171  // Actually build the Mesh
172  MeshTools::Generation::build_square(dynamic_cast<UnstructuredMesh &>(getMesh()),
173  _nx,
174  _ny,
175  /*xmin=*/0.,
176  /*xmax=*/_xmax,
177  /*ymin=*/0.,
178  /*ymax=*/_ymax,
179  QUAD4);
180 }
181 
182 void
183 ImageMesh::GetPixelInfo(std::string filename, int & xpixels, int & ypixels)
184 {
185  // For reporting possible error messages
186  std::string error_message = "";
187 
188  // A template for creating a temporary file.
189  char temp_file[] = "file_command_output.XXXXXX";
190 
191  // Use a do-loop so we can break out under various error conditions
192  // while still cleaning up temporary files. Basically use goto
193  // statements without actually using them.
194  do
195  {
196  // mkstemp is not in namespace std for whatever reason...
197  int fd = mkstemp(temp_file);
198 
199  // If mkstemp fails, we failed.
200  if (fd == -1)
201  {
202  error_message = "Error creating temporary file in ImageMesh::buildMesh()";
203  break;
204  }
205 
206  // Construct the command string
207  std::ostringstream command;
208  command << "file " << filename << " 2>/dev/null 1>" << temp_file;
209 
210  // Make the system call, catch the return code
211  int exit_status = std::system(command.str().c_str());
212 
213  // If the system command returned a non-zero status, we failed.
214  if (exit_status != 0)
215  {
216  error_message = "Error calling 'file' command in ImageMesh::buildMesh()";
217  break;
218  }
219 
220  // Open the file which contains the result of the system command
221  std::ifstream fin(temp_file);
222 
223  // Read the contents of the output file into a string
224  std::string command_result;
225  std::getline(fin, command_result);
226 
227  // A regular expression which matches "NNN x NNN" , i.e. any number
228  // of digits, a space, an 'x', a space, and any number of digits.
229  // The parentheses define capture groups which are stored into the
230  // xsize and ysize integers.
231  // Here's an example string:
232  // sixteenth_image001_cropped3_closing_298.png: PNG image data, 115 x 99, 16-bit/color RGB,
233  // non-interlaced
234  xpixels = 0, ypixels = 0;
235  pcrecpp::RE re("(\\d+) x (\\d+)");
236  re.PartialMatch(command_result, &xpixels, &ypixels);
237 
238  // Detect failure of the regex
239  if ((xpixels == 0) || (ypixels == 0))
240  {
241  error_message = "Regex failed to find a match in " + command_result;
242  break;
243  }
244  } while (false);
245 
246  // Remove the temporary file. This will still work even if the file was never created...
247  std::remove(temp_file);
248 
249  // Report and exit if there was an error
250  if (error_message != "")
251  mooseError(error_message);
252 }
void buildMesh3D(const std::vector< std::string > &filenames)
buildMesh() calls this helper function to build 3D ImageMeshes from stacks of images.
Definition: ImageMesh.C:76
ImageMesh(const InputParameters &parameters)
Definition: ImageMesh.C:40
HEX8
virtual std::unique_ptr< MooseMesh > safeClone() const override
A safer version of the clone() method that hands back an allocated object wrapped in a smart pointer...
Definition: ImageMesh.C:59
const std::vector< std::string > & filenames()
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
static InputParameters validParams()
auto max(const L &left, const R &right)
QUAD4
void buildMesh2D(const std::string &filename)
buildMesh() calls this helper function to build 2D ImageMeshes.
Definition: ImageMesh.C:146
Mesh generated from parameters.
Definition: GeneratedMesh.h:17
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition: MooseMesh.C:3198
virtual void buildMesh() override
Must be overridden by child classes.
Definition: ImageMesh.C:65
int mkstemp(char *tmpl)
unsigned int _ny
Definition: GeneratedMesh.h:40
To be called in the validParams functions of classes that need to operate on ranges of files...
unsigned int _nz
Definition: GeneratedMesh.h:40
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
registerMooseObject("MooseApp", ImageMesh)
const Real & _cells_per_pixel
A number <= 1.0 which determines the number of cells in the mesh per pixel in each direction...
Definition: ImageMesh.h:61
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump...
unsigned int _nx
Number of elements in x, y, z direction.
Definition: GeneratedMesh.h:40
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an option parameter and a documentation string to the InputParameters object...
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
const bool _scale_to_one
If true, forces the maximum width (height) of the mesh to be 1.0 while retaining the original aspect ...
Definition: ImageMesh.h:51
static InputParameters validParams()
Definition: ImageMesh.C:23
void GetPixelInfo(std::string filename, int &xpixels, int &ypixels)
Process a single image with the &#39;file&#39; command to find out the number of pixels in the x and y direct...
Definition: ImageMesh.C:183
A 2D GeneratedMesh where xmin, xmax, etc.
Definition: ImageMesh.h:18
std::vector< std::string > _filenames
static InputParameters validParams()
Definition: GeneratedMesh.C:26