1
2 #include "moab/ParallelComm.hpp"
3 #include "MBParallelConventions.h"
4 #include "moab/Core.hpp"
5 #include "Coupler.hpp"
6 #include "moab_mpi.h"
7 #include "ElemUtil.hpp"
8 #include "TestUtil.hpp"
9
10
11 #include <iostream>
12 #include <iomanip>
13 #include <sstream>
14 #include <cassert>
15
16 using namespace moab;
17
18
31
32
33 void print_usage()
34 {
35 std::cerr << "Usage: ";
36 std::cerr << "mbcoupler_test -meshes <source_mesh> <target_mesh> -itag <interp_tag> [-gnorm "
37 "<gnorm_tag>] [-ssnorm <ssnorm_tag> <ssnorm_selection>] [-ropts <roptions>] "
38 "[-outfile <out_file> [-wopts <woptions>]] [-dbgout [<dbg_file>]]"
39 << std::endl;
40 std::cerr << " -meshes" << std::endl;
41 std::cerr << " Read in mesh files <source_mesh> and <target_mesh>." << std::endl;
42 std::cerr << " -itag" << std::endl;
43 std::cerr << " Interpolate tag <interp_tag> from source mesh to target mesh." << std::endl;
44 std::cerr << " -gnorm" << std::endl;
45 std::cerr << " Normalize the value of tag <gnorm_tag> over then entire mesh and save to" << std::endl;
46 std::cerr << " tag \"<gnorm_tag>_normf\" on the mesh set. Do this for all meshes." << std::endl;
47 std::cerr << " -ssnorm" << std::endl;
48 std::cerr << " Normalize the value of tag <ssnorm_tag> over subsets of a mesh and save to" << std::endl;
49 std::cerr << " tag \"<ssnorm_tag>_normf\" on the Entity Set for each subset. Subsets "
50 "are selected"
51 << std::endl;
52 std::cerr << " using criteria in <ssnorm_selection>. Do this for all meshes." << std::endl;
53 std::cerr << " -ropts" << std::endl;
54 std::cerr << " Read in the mesh files using options in <roptions>." << std::endl;
55 std::cerr << " -outfile" << std::endl;
56 std::cerr << " Write out target mesh to <out_file>." << std::endl;
57 std::cerr << " -wopts" << std::endl;
58 std::cerr << " Write out mesh files using options in <woptions>." << std::endl;
59 std::cerr << " -dbgout" << std::endl;
60 std::cerr << " Write stdout and stderr streams to the file \'<dbg_file>.txt\'." << std::endl;
61 std::cerr << " -eps" << std::endl;
62 std::cerr << " epsilon" << std::endl;
63 std::cerr << " -meth <method> (0=CONSTANT, 1=LINEAR_FE, 2=QUADRATIC_FE, 3=SPECTRAL, 4=SPHERICAL)" << std::endl;
64 }
65
66 #ifdef MOAB_HAVE_HDF5
67
68 ErrorCode get_file_options( int argc,
69 char** argv,
70 int nprocs,
71 int rank,
72 std::vector< std::string >& meshFiles,
73 Coupler::Method& method,
74 std::string& interpTag,
75 std::string& gNormTag,
76 std::string& ssNormTag,
77 std::vector< const char* >& ssTagNames,
78 std::vector< const char* >& ssTagValues,
79 std::string& readOpts,
80 std::string& outFile,
81 std::string& writeOpts,
82 std::string& dbgFile,
83 bool& help,
84 double& epsilon );
85
86 ErrorCode report_iface_ents( Interface* mbImpl, std::vector< ParallelComm* >& pcs, bool print_results );
87
88 ErrorCode test_interpolation( Interface* mbImpl,
89 Coupler::Method method,
90 std::string& interpTag,
91 std::string& gNormTag,
92 std::string& ssNormTag,
93 std::vector< const char* >& ssTagNames,
94 std::vector< const char* >& ssTagValues,
95 EntityHandle* roots,
96 std::vector< ParallelComm* >& pcs,
97 double& instant_time,
98 double& pointloc_time,
99 double& interp_time,
100 double& gnorm_time,
101 double& ssnorm_time,
102 double& toler );
103
104 void reduceMax( double& v )
105 {
106 double buf;
107
108 MPI_Barrier( MPI_COMM_WORLD );
109 MPI_Allreduce( &v, &buf, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD );
110
111 v = buf;
112 }
113
114 int main( int argc, char** argv )
115 {
116
117 int ierr = MPI_Init( &argc, &argv );
118 assert( MPI_SUCCESS == ierr );
119
120 std::vector< const char* > ssTagNames, ssTagValues;
121 std::vector< std::string > meshFiles;
122 std::string interpTag, gNormTag, ssNormTag, readOpts, outFile, writeOpts, dbgFile;
123 Coupler::Method method = Coupler::CONSTANT;
124
125 ErrorCode result;
126 bool help = false;
127 double toler = 5.e-10;
128 int nprocs, rank;
129 ierr = MPI_Comm_size( MPI_COMM_WORLD, &nprocs );
130 assert( MPI_SUCCESS == ierr );
131 ierr = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
132 assert( MPI_SUCCESS == ierr );
133
134 result = get_file_options( argc, argv, nprocs, rank, meshFiles, method, interpTag, gNormTag, ssNormTag, ssTagNames,
135 ssTagValues, readOpts, outFile, writeOpts, dbgFile, help, toler );
136
137 if( result != MB_SUCCESS || help )
138 {
139 print_usage();
140 ierr = MPI_Finalize();
141 return ierr;
142 }
143
144
145 if( !dbgFile.empty() )
146 {
147 std::stringstream dfname;
148 dfname << dbgFile << rank << ".txt";
149 if( !std::freopen( dfname.str().c_str(), "a", stdout ) ) return -1;
150 if( !std::freopen( dfname.str().c_str(), "a", stderr ) ) return -1;
151 }
152
153
154 Interface* mbImpl = new( std::nothrow ) Core();
155 if( NULL == mbImpl ) return 1;
156
157
158 std::vector< ParallelComm* > pcs( meshFiles.size() );
159
160
161
162 EntityHandle* roots = (EntityHandle*)malloc( sizeof( EntityHandle ) * meshFiles.size() );
163
164 for( unsigned int i = 0; i < meshFiles.size(); i++ )
165 {
166 pcs[i] = new ParallelComm( mbImpl, MPI_COMM_WORLD );
167 int index = pcs[i]->get_id();
168 std::string newReadopts;
169 std::ostringstream extraOpt;
170 extraOpt << ";PARALLEL_COMM=" << index;
171 newReadopts = readOpts + extraOpt.str();
172
173 result = mbImpl->create_meshset( MESHSET_SET, roots[i] );MB_CHK_ERR( result );
174
175 result = mbImpl->load_file( meshFiles[i].c_str(), &roots[i], newReadopts.c_str() );MB_CHK_ERR( result );
176
177
178 }
179
180 result = report_iface_ents( mbImpl, pcs, true );MB_CHK_ERR( result );
181
182 double instant_time = 0.0, pointloc_time = 0.0, interp_time = 0.0, gnorm_time = 0.0, ssnorm_time = 0.0;
183
184
185 result = test_interpolation( mbImpl, method, interpTag, gNormTag, ssNormTag, ssTagNames, ssTagValues, roots, pcs,
186 instant_time, pointloc_time, interp_time, gnorm_time, ssnorm_time, toler );MB_CHK_ERR( result );
187
188 reduceMax( instant_time );
189 reduceMax( pointloc_time );
190 reduceMax( interp_time );
191
192 if( 0 == rank )
193 printf( "\nMax time : %g %g %g (inst loc interp -- %d procs)\n", instant_time, pointloc_time, interp_time,
194 nprocs );
195
196
197 if( !outFile.empty() )
198 {
199 Range partSets;
200
201 partSets.insert( (EntityHandle)roots[1] );
202 std::string newwriteOpts;
203 std::ostringstream extraOpt;
204 if( nprocs > 1 ) extraOpt << ";PARALLEL_COMM=" << 1;
205 newwriteOpts = writeOpts + extraOpt.str();
206 result = mbImpl->write_file( outFile.c_str(), NULL, newwriteOpts.c_str(), partSets );MB_CHK_ERR( result );
207 if( 0 == rank )
208 {
209 std::cout << "Wrote " << outFile << std::endl;
210 std::cout << "mbcoupler_test complete." << std::endl;
211 }
212 }
213
214 free( roots );
215
216 for( unsigned int i = 0; i < meshFiles.size(); i++ )
217 delete pcs[i];
218
219 delete mbImpl;
220
221 ierr = MPI_Finalize();
222 assert( MPI_SUCCESS == ierr );
223 return 0;
224 }
225
226 ErrorCode report_iface_ents( Interface* mbImpl, std::vector< ParallelComm* >& pcs, const bool print_results )
227 {
228 Range iface_ents[6];
229 ErrorCode result = MB_SUCCESS, tmp_result;
230
231
232 for( unsigned int p = 0; p < pcs.size(); p++ )
233 {
234 for( int i = 0; i < 4; i++ )
235 {
236 tmp_result = pcs[p]->get_iface_entities( -1, i, iface_ents[i] );
237
238 if( MB_SUCCESS != tmp_result )
239 {
240 std::cerr << "get_iface_entities returned error on proc " << pcs[p]->proc_config().proc_rank()
241 << "; message: " << std::endl;
242 std::string last_error;
243 result = mbImpl->get_last_error( last_error );
244 if( last_error.empty() )
245 std::cerr << "(none)" << std::endl;
246 else
247 std::cerr << last_error << std::endl;
248 result = tmp_result;
249 }
250 if( 0 != i ) iface_ents[4].merge( iface_ents[i] );
251 }
252 }
253
254
255 result = mbImpl->get_adjacencies( iface_ents[4], 0, false, iface_ents[5], Interface::UNION );MB_CHK_ERR( result );
256
257 int rank;
258 MPI_Comm_rank( MPI_COMM_WORLD, &rank );
259
260 if( print_results || iface_ents[0].size() != iface_ents[5].size() )
261 {
262 std::cerr << "Proc " << rank << " iface entities: " << std::endl;
263 for( int i = 0; i < 4; i++ )
264 std::cerr << " " << iface_ents[i].size() << " " << i << "d iface entities." << std::endl;
265 std::cerr << " (" << iface_ents[5].size() << " verts adj to other iface ents)" << std::endl;
266 }
267
268 return result;
269 }
270
271
272
273 bool check_for_flag( const char* str )
274 {
275 if( '-' == str[0] )
276 return true;
277 else
278 return false;
279 }
280
281
282 ErrorCode get_file_options( int argc,
283 char** argv,
284 int nprocs,
285 int rank,
286 std::vector< std::string >& meshFiles,
287 Coupler::Method& method,
288 std::string& interpTag,
289 std::string& gNormTag,
290 std::string& ssNormTag,
291 std::vector< const char* >& ssTagNames,
292 std::vector< const char* >& ssTagValues,
293 std::string& readOpts,
294 std::string& outFile,
295 std::string& writeOpts,
296 std::string& dbgFile,
297 bool& help,
298 double& epsilon )
299 {
300
301
302 gNormTag = "";
303 ssNormTag = "";
304 readOpts = ( nprocs > 1 ? "PARALLEL=READ_PART;PARTITION=PARALLEL_PARTITION;PARTITION_DISTRIBUTE;"
305 "PARALLEL_RESOLVE_SHARED_ENTS;PARALLEL_GHOSTS=3.0.1;CPUTIME"
306 : "PARALLEL=READ_PART;PARTITION=PARALLEL_PARTITION;PARTITION_DISTRIBUTE;"
307 "PARALLEL_RESOLVE_SHARED_ENTS;CPUTIME" );
308 outFile = "";
309 writeOpts = ( nprocs > 1 ? "PARALLEL=WRITE_PART;CPUTIME" : "" );
310 dbgFile = "";
311 std::string defaultDbgFile = argv[0];
312
313
314 bool haveMeshes = false;
315 bool haveInterpTag = false;
316
317
318 int npos = 1;
319
320 if( argc > 1 && argv[1] == std::string( "-h" ) )
321 {
322 help = true;
323 return MB_SUCCESS;
324 }
325
326 while( npos < argc )
327 {
328 if( argv[npos] == std::string( "-meshes" ) )
329 {
330
331 npos++;
332 int numFiles = 2;
333 meshFiles.resize( numFiles );
334 for( int i = 0; i < numFiles; i++ )
335 {
336 if( ( npos < argc ) && ( !check_for_flag( argv[npos] ) ) )
337 meshFiles[i] = argv[npos++];
338 else
339 {
340 std::cerr << " ERROR - missing correct number of mesh filenames" << std::endl;
341 return MB_FAILURE;
342 }
343 }
344
345 haveMeshes = true;
346 }
347 else if( argv[npos] == std::string( "-itag" ) )
348 {
349
350 npos++;
351 if( ( npos < argc ) && ( !check_for_flag( argv[npos] ) ) )
352 interpTag = argv[npos++];
353 else
354 {
355 std::cerr << " ERROR - missing <interp_tag>" << std::endl;
356 return MB_FAILURE;
357 }
358
359 haveInterpTag = true;
360 }
361 else if( argv[npos] == std::string( "-meth" ) )
362 {
363
364 npos++;
365 if( argv[npos][0] == '0' )
366 method = Coupler::CONSTANT;
367 else if( argv[npos][0] == '1' )
368 method = Coupler::LINEAR_FE;
369 else if( argv[npos][0] == '2' )
370 method = Coupler::QUADRATIC_FE;
371 else if( argv[npos][0] == '3' )
372 method = Coupler::SPECTRAL;
373 else if( argv[npos][0] == '4' )
374 method = Coupler::SPHERICAL;
375 else
376 {
377 std::cerr << " ERROR - unrecognized method number " << method << std::endl;
378 return MB_FAILURE;
379 }
380 npos++;
381 }
382 else if( argv[npos] == std::string( "-eps" ) )
383 {
384
385 npos++;
386 if( ( npos < argc ) && ( !check_for_flag( argv[npos] ) ) )
387 epsilon = atof( argv[npos++] );
388 else
389 {
390 std::cerr << " ERROR - missing <epsilon>" << std::endl;
391 return MB_FAILURE;
392 }
393 }
394 else if( argv[npos] == std::string( "-gnorm" ) )
395 {
396
397 npos++;
398 if( ( npos < argc ) && ( !check_for_flag( argv[npos] ) ) )
399 gNormTag = argv[npos++];
400 else
401 {
402 std::cerr << " ERROR - missing <gnorm_tag>" << std::endl;
403 return MB_FAILURE;
404 }
405 }
406 else if( argv[npos] == std::string( "-ssnorm" ) )
407 {
408
409 npos++;
410 if( ( npos < argc ) && ( !check_for_flag( argv[npos] ) ) )
411 ssNormTag = argv[npos++];
412 else
413 {
414 std::cerr << " ERROR - missing <ssnorm_tag>" << std::endl;
415 return MB_FAILURE;
416 }
417
418 if( ( npos < argc ) && ( !check_for_flag( argv[npos] ) ) )
419 {
420 char* opts = argv[npos++];
421 char sep1[1] = { ';' };
422 char sep2[1] = { '=' };
423 bool end_vals_seen = false;
424 std::vector< char* > tmpTagOpts;
425
426
427 for( char* i = strtok( opts, sep1 ); i; i = strtok( 0, sep1 ) )
428 tmpTagOpts.push_back( i );
429
430
431 for( unsigned int j = 0; j < tmpTagOpts.size(); j++ )
432 {
433 char* e = strtok( tmpTagOpts[j], sep2 );
434 ssTagNames.push_back( e );
435 e = strtok( 0, sep2 );
436 if( e != NULL )
437 {
438
439 if( end_vals_seen )
440 {
441
442 std::cerr << " ERROR - new value seen after end of values in "
443 "<ssnorm_selection>"
444 << std::endl;
445 return MB_FAILURE;
446 }
447
448 int* valp = new int;
449 *valp = atoi( e );
450 ssTagValues.push_back( (const char*)valp );
451 }
452 else
453 {
454
455 end_vals_seen = true;
456 ssTagValues.push_back( (const char*)0 );
457 }
458 }
459 }
460 else
461 {
462 std::cerr << " ERROR - missing <ssnorm_selection>" << std::endl;
463 return MB_FAILURE;
464 }
465 }
466 else if( argv[npos] == std::string( "-ropts" ) )
467 {
468
469 npos++;
470 if( ( npos < argc ) && ( !check_for_flag( argv[npos] ) ) )
471 readOpts = argv[npos++];
472 else
473 {
474 std::cerr << " ERROR - missing <roptions>" << std::endl;
475 return MB_FAILURE;
476 }
477 }
478 else if( argv[npos] == std::string( "-outfile" ) )
479 {
480
481 npos++;
482 if( ( npos < argc ) && ( !check_for_flag( argv[npos] ) ) )
483 outFile = argv[npos++];
484 else
485 {
486 std::cerr << " ERROR - missing <out_file>" << std::endl;
487 return MB_FAILURE;
488 }
489 }
490 else if( argv[npos] == std::string( "-wopts" ) )
491 {
492
493 npos++;
494 if( ( npos < argc ) && ( !check_for_flag( argv[npos] ) ) )
495 writeOpts = argv[npos++];
496 else
497 {
498 std::cerr << " ERROR - missing <woptions>" << std::endl;
499 return MB_FAILURE;
500 }
501 }
502 else if( argv[npos] == std::string( "-dbgout" ) )
503 {
504
505
506 npos++;
507 if( ( npos < argc ) && ( !check_for_flag( argv[npos] ) ) )
508 dbgFile = argv[npos++];
509 else
510 dbgFile = defaultDbgFile;
511 }
512 else
513 {
514
515 std::cerr << " ERROR - Unrecognized parameter:" << argv[npos] << std::endl;
516 std::cerr << " Skipping..." << std::endl;
517 npos++;
518 }
519 }
520
521 if( !haveMeshes )
522 {
523 meshFiles.resize( 2 );
524 meshFiles[0] = std::string( TestDir + "unittest/64bricks_1khex.h5m" );
525 meshFiles[1] = std::string( TestDir + "unittest/64bricks_12ktet.h5m" );
526 if( 0 == rank )
527 std::cout << "Mesh files not entered; using default files " << meshFiles[0] << " and " << meshFiles[1]
528 << std::endl;
529 }
530
531 if( !haveInterpTag )
532 {
533 interpTag = "vertex_field";
534 std::cout << "Interpolation field name not given, using default of " << interpTag << std::endl;
535 }
536
537 #ifdef MOAB_HAVE_HDF5
538 if( 1 == argc )
539 {
540 std::stringstream dfname;
541 dfname << "dum" << nprocs << ".h5m";
542 outFile = dfname.str();
543 if( 0 == rank ) std::cout << "No arguments given; using output file " << outFile << std::endl;
544 }
545 #endif
546
547 return MB_SUCCESS;
548 }
549
550
551
552 ErrorCode test_interpolation( Interface* mbImpl,
553 Coupler::Method method,
554 std::string& interpTag,
555 std::string& gNormTag,
556 std::string& ssNormTag,
557 std::vector< const char* >& ssTagNames,
558 std::vector< const char* >& ssTagValues,
559 EntityHandle* roots,
560 std::vector< ParallelComm* >& pcs,
561 double& instant_time,
562 double& pointloc_time,
563 double& interp_time,
564 double& gnorm_time,
565 double& ssnorm_time,
566 double& toler )
567 {
568 assert( method >= Coupler::CONSTANT && method <= Coupler::SPHERICAL );
569
570
571 Range src_elems, targ_elems, targ_verts;
572 ErrorCode result = pcs[0]->get_part_entities( src_elems, 3 );MB_CHK_ERR( result );
573
574 double start_time = MPI_Wtime();
575
576
577 Coupler mbc( mbImpl, pcs[0], src_elems, 0, false );
578 if( Coupler::SPHERICAL == method ) mbc.set_spherical();
579 mbc.initialize_tree();
580
581
582 bool specSou = false, specTar = false;
583 result = mbc.initialize_spectral_elements( roots[0], roots[1], specSou, specTar );
584
585 instant_time = MPI_Wtime();
586
587
588
589
590 std::vector< double > vpos;
591 int numPointsOfInterest = 0;
592 if( !specTar )
593 {
594 Range tmp_verts;
595
596
597 result = pcs[1]->get_part_entities( targ_elems, 3 );MB_CHK_ERR( result );
598 if( Coupler::SPHERICAL == method ) result = pcs[1]->get_part_entities( targ_elems, 2 );MB_CHK_ERR( result );
599 if( Coupler::CONSTANT == method )
600 targ_verts = targ_elems;
601 else
602 result = mbImpl->get_adjacencies( targ_elems, 0, false, targ_verts, Interface::UNION );MB_CHK_ERR( result );
603
604
605 result = pcs[1]->get_pstatus_entities( 0, PSTATUS_NOT_OWNED, tmp_verts );MB_CHK_ERR( result );
606 targ_verts = subtract( targ_verts, tmp_verts );
607
608 numPointsOfInterest = (int)targ_verts.size();
609 vpos.resize( 3 * targ_verts.size() );
610 result = mbImpl->get_coords( targ_verts, &vpos[0] );MB_CHK_ERR( result );
611
612 std::cout << "rank " << pcs[0]->proc_config().proc_rank() << " points of interest: " << numPointsOfInterest
613 << "\n";
614 result = mbc.locate_points( &vpos[0], numPointsOfInterest, 0, toler );MB_CHK_ERR( result );
615 }
616 else
617 {
618
619
620
621 result = pcs[1]->get_part_entities( targ_elems, 3 );MB_CHK_ERR( result );
622 result = mbc.get_gl_points_on_elements( targ_elems, vpos, numPointsOfInterest );MB_CHK_ERR( result );
623 std::cout << "rank " << pcs[0]->proc_config().proc_rank() << " points of interest: " << numPointsOfInterest
624 << "\n";
625 }
626
627 pointloc_time = MPI_Wtime();
628
629
630 std::vector< double > field( numPointsOfInterest );
631
632 result = mbc.interpolate( method, interpTag, &field[0] );MB_CHK_ERR( result );
633
634 interp_time = MPI_Wtime();
635
636
637 if( !gNormTag.empty() )
638 {
639
640 result = mbc.normalize_mesh( roots[0], gNormTag.c_str(), Coupler::VOLUME, 4 );MB_CHK_ERR( result );
641
642
643 result = mbc.normalize_mesh( roots[1], gNormTag.c_str(), Coupler::VOLUME, 4 );MB_CHK_ERR( result );
644 }
645
646 gnorm_time = MPI_Wtime();
647
648
649
650 if( !ssNormTag.empty() )
651 {
652
653 result = mbc.normalize_subset( roots[0], ssNormTag.c_str(), &ssTagNames[0], ssTagNames.size(), &ssTagValues[0],
654 Coupler::VOLUME, 4 );MB_CHK_ERR( result );
655
656 result = mbc.normalize_subset( roots[1], ssNormTag.c_str(), &ssTagNames[0], ssTagNames.size(), &ssTagValues[0],
657 Coupler::VOLUME, 4 );MB_CHK_ERR( result );
658 }
659
660 ssnorm_time = MPI_Wtime();
661
662 ssnorm_time -= gnorm_time;
663 gnorm_time -= interp_time;
664 interp_time -= pointloc_time;
665 pointloc_time -= instant_time;
666 instant_time -= start_time;
667
668
669 if( specSou )
670 {
671
672 Tag tag;
673 std::string newtag = interpTag + "_TAR";
674 result = mbImpl->tag_get_handle( newtag.c_str(), 1, MB_TYPE_DOUBLE, tag, MB_TAG_CREAT | MB_TAG_DENSE );MB_CHK_ERR( result );
675 result = mbImpl->tag_set_data( tag, targ_verts, &field[0] );MB_CHK_ERR( result );
676 }
677 else
678 {
679 if( !specTar )
680 {
681
682 Tag tag;
683 result = mbImpl->tag_get_handle( interpTag.c_str(), 1, MB_TYPE_DOUBLE, tag );MB_CHK_ERR( result );
684 result = mbImpl->tag_set_data( tag, targ_verts, &field[0] );MB_CHK_ERR( result );
685 }
686 else
687 {
688
689
690
691
692
693
694 int ntot = numPointsOfInterest / targ_elems.size();
695 Tag tag;
696 std::string newtag = interpTag + "_TAR";
697 result = mbImpl->tag_get_handle( newtag.c_str(), ntot, MB_TYPE_DOUBLE, tag, MB_TAG_CREAT | MB_TAG_DENSE );MB_CHK_ERR( result );
698 result = mbImpl->tag_set_data( tag, targ_elems, &field[0] );MB_CHK_ERR( result );
699 }
700 }
701
702
703 return MB_SUCCESS;
704 }
705
706 #else
707
708 int main( int , char** )
709 {
710 print_usage();
711 return 0;
712 }
713
714 #endif