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