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