libMesh
meshid.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2017 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 // Open the mesh named in command line arguments,
20 // update ids of one or more of the following entries
21 // as prescribed on the command line:
22 // blocks, sidesets and nodesets
23 
24 #include <iostream>
25 #include <time.h> // time
26 #include <stdlib.h> // rand, srand
27 
28 #include "libmesh/libmesh_config.h"
29 #include "libmesh/libmesh_nullptr.h"
30 
31 #ifdef LIBMESH_HAVE_EXODUS_API
32 
33 #include "exodusII.h"
34 #include "exodusII_int.h"
35 #include "libmesh/getpot.h"
36 
37 #define EXODUS_DIM 0x8
38 #define BLOCKS 0x4
39 #define SIDES 0x2
40 #define NODES 0x1
41 
42 // Report error from NetCDF and exit
43 void handle_error(int error, std::string message);
44 
45 // Report error in input flags and exit
46 void usage_error(const char * progname);
47 
48 // Generate a random string, seed RNG with current time.
49 void gen_random_string(std::string & s, const int len);
50 
51 
52 
53 int main(int argc, char ** argv)
54 {
55  GetPot cl(argc, argv);
56 
57  // Command line parsing
58  if (!cl.search("--input"))
59  {
60  std::cerr << "No --input argument found!" << std::endl;
61  usage_error(argv[0]);
62  }
63  const char * meshname = cl.next("");
64 
65  if (!cl.search("--oldid"))
66  {
67  std::cerr << "No --oldid argument found!" << std::endl;
68  usage_error(argv[0]);
69  }
70  long oldid = cl.next(0);
71 
72  if (!cl.search("--newid"))
73  {
74  std::cerr << "No --newid argument found!" << std::endl;
75  usage_error(argv[0]);
76  }
77  long newid = cl.next(0);
78 
79  unsigned char flags = 0;
80  if (cl.search("--nodesetonly"))
81  flags |= NODES;
82  if (cl.search("--sidesetonly"))
83  flags |= SIDES;
84  if (cl.search("--blockonly"))
85  flags |= BLOCKS;
86  if (cl.search("--dim"))
87  flags |= EXODUS_DIM;
88 
89  // No command line flags were set, turn on NODES, SIDES, and BLOCKS
90  if (!flags)
91  flags = NODES | SIDES | BLOCKS; // ALL except EXODUS_DIM on
92 
93  // flags are exclusive
94  if (flags != NODES &&
95  flags != SIDES &&
96  flags != BLOCKS &&
97  flags != EXODUS_DIM &&
98  flags != (NODES | SIDES | BLOCKS))
99  {
100  std::cerr << "Only one of the following options may be active [--nodesetonly | --sidesetonly | --blockonly | --dim]!" << std::endl;
101  usage_error(argv[0]);
102  }
103 
104  // Processing
105  std::string var_name, dim_name;
106  int status;
107  int nc_id, var_id, dim_id;
108  size_t dim_len;
109 
110  status = nc_open (meshname, NC_WRITE, &nc_id);
111  if (status != NC_NOERR) handle_error(status, "Error while opening file.");
112 
113  for (unsigned char mask = 8; mask; mask/=2)
114  {
115  // These are char *'s #defined in exodusII_int.h
116  switch (flags & mask)
117  {
118  case BLOCKS:
119  dim_name = DIM_NUM_EL_BLK;
120  var_name = VAR_ID_EL_BLK;
121  break;
122  case SIDES:
123  dim_name = DIM_NUM_SS;
124  var_name = VAR_SS_IDS;
125  break;
126  case NODES:
127  dim_name = DIM_NUM_NS;
128  var_name = VAR_NS_IDS;
129  break;
130  case EXODUS_DIM:
131  dim_name = DIM_NUM_DIM;
132  // var_name not used for setting dimension
133  break;
134  default:
135  // We don't match this flag, so go to the next mask
136  continue;
137  }
138 
139  // Get the ID and length of the variable in question - stored in a dimension field
140  status = nc_inq_dimid (nc_id, dim_name.c_str(), &dim_id);
141  if (status != NC_NOERR) handle_error(status, "Error while inquiring about a dimension's ID.");
142 
143  status = nc_inq_dimlen (nc_id, dim_id, &dim_len);
144  if (status != NC_NOERR) handle_error(status, "Error while inquiring about a dimension's length.");
145 
146  if ((flags & mask) != EXODUS_DIM)
147  {
148  // Now get the variable values themselves
149  std::vector<long> var_vals(dim_len);
150 
151  status = nc_inq_varid (nc_id, var_name.c_str(), &var_id);
152  if (status != NC_NOERR) handle_error(status, "Error while inquiring about a variable's ID.");
153 
154  status = nc_get_var_long (nc_id, var_id, &var_vals[0]);
155  if (status != NC_NOERR) handle_error(status, "Error while retrieving a variable's values.");
156 
157  // Update the variable value specified on the command line
158  for (unsigned int i=0; i<dim_len; ++i)
159  if (var_vals[i] == oldid)
160  var_vals[i] = newid;
161 
162  // Save that value back to the NetCDF database
163  status = nc_put_var_long (nc_id, var_id, &var_vals[0]);
164  if (status != NC_NOERR) handle_error(status, "Error while writing a variable's values.");
165  }
166 
167  // Redefine the dimension
168  else
169  {
170  // The value stored in dim_len is actually the dimension?
171  if (dim_len == (size_t)oldid)
172  {
173  // Trying to change def's always raises
174  // Error -38: /* Operation not allowed in data mode */
175  // unless you are in "define" mode. So let's go there now.
176 
177  // Try to put the file into define mode
178  status = nc_redef(nc_id);
179  if (status != NC_NOERR) handle_error(status, "Error while putting file into define mode.");
180 
181  // Rename the "num_dim" dimension. Note: this will fail if there is already a dimension
182  // which has the name you are trying to use. This can happen, for example if you have already
183  // changed the dimension of this exodus file once using this very script. There appears
184  // to be no way to delete a dimension using basic NetCDF interfaces, so to workaround this
185  // we just rename it to an arbitrary unique string that Exodus will ignore.
186 
187  // Construct a string with 6 random alpha-numeric characters at the end.
188  std::string random_dim_name;
189  gen_random_string(random_dim_name, 6);
190  random_dim_name = std::string("ignored_num_dim_") + random_dim_name;
191 
192  // Rename the old dimension variable to our randomly-chosen name
193  status = nc_rename_dim(nc_id, dim_id, random_dim_name.c_str());
194  if (status != NC_NOERR) handle_error(status, "Error while trying to rename num_dim.");
195 
196  // Now define a new "num_dim" value of newid
197  int dummy=0;
198  status = nc_def_dim (nc_id, dim_name.c_str(), newid, &dummy);
199  if (status != NC_NOERR) handle_error(status, "Error while trying to define num_dim.");
200 
201  // Leave define mode
202  status = nc_enddef(nc_id);
203  if (status != NC_NOERR) handle_error(status, "Error while leaving define mode.");
204  }
205  }
206  } // end for
207 
208  // Write out the dataset
209  status = nc_close(nc_id);
210 
211  return (status != NC_NOERR);
212 }
213 
214 #else // LIBMESH_HAVE_EXODUS_API
215 
216 int main(int, char **)
217 {
218  std::cerr << "Error: meshid requires libMesh configured with --enable-exodus" << std::endl;
219 }
220 #endif // LIBMESH_HAVE_EXODUS_API
221 
222 
223 
224 void handle_error(int error, std::string message)
225 {
226  std::cout << "Error " << error << " occurred while working with the netCDF API" << std::endl;
227  std::cout << message << std::endl;
228 
229  exit(1);
230 }
231 
232 
233 
234 void usage_error(const char * progname)
235 {
236  std::cout << "Usage: " << progname
237  << " --input inputmesh --oldid <n> --newid <n> [--nodesetonly | --sidesetonly | --blockonly]"
238  << std::endl;
239  exit(1);
240 }
241 
242 
243 
244 void gen_random_string(std::string & s, const int len)
245 {
246  static const char alphanum[] =
247  "0123456789"
248  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
249  "abcdefghijklmnopqrstuvwxyz";
250 
251  // Seed the random number generator with the current time
252  srand( static_cast<unsigned>(time(libmesh_nullptr)) );
253 
254  s.resize(len);
255  for (int i = 0; i < len; ++i)
256  {
257  unsigned int alphai = static_cast<unsigned int>
258  (rand() / (RAND_MAX+1.0) * (sizeof(alphanum)-1));
259  s[i] = alphanum[alphai];
260  }
261 }
const class libmesh_nullptr_t libmesh_nullptr
int main(int argc, char **argv)
Definition: meshid.C:53
MPI_Status status
Status object for querying messages.
Definition: parallel.h:176
void gen_random_string(std::string &s, const int len)
Definition: meshid.C:244
void usage_error(const char *progname)
Definition: meshid.C:234
void handle_error(int error, std::string message)
Definition: meshid.C:224