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