![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /**
00002 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
00003 * storing and accessing finite element mesh data.
00004 *
00005 * Copyright 2004 Sandia Corporation. Under the terms of Contract
00006 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
00007 * retains certain rights in this software.
00008 *
00009 * This library is free software; you can redistribute it and/or
00010 * modify it under the terms of the GNU Lesser General Public
00011 * License as published by the Free Software Foundation; either
00012 * version 2.1 of the License, or (at your option) any later version.
00013 *
00014 */
00015
00016 #include "ReadMCNP5.hpp"
00017 #include "moab/Interface.hpp"
00018 #include "moab/ReadUtilIface.hpp"
00019 #include "Internals.hpp" // For MB_START_ID
00020 #include "moab/Range.hpp"
00021 #include "moab/FileOptions.hpp"
00022 #include "moab/Util.hpp"
00023
00024 #include
00025 #include
00026 #include
00027 #include
00028 #include
00029 #include
00030 #include
00031
00032 namespace moab
00033 {
00034
00035 // Parameters
00036 const double ReadMCNP5::PI = 3.141592653589793;
00037 const double ReadMCNP5::C2PI = 0.1591549430918954;
00038 const double ReadMCNP5::CPI = 0.3183098861837907;
00039
00040 ReaderIface* ReadMCNP5::factory( Interface* iface )
00041 {
00042 return new ReadMCNP5( iface );
00043 }
00044
00045 // Constructor
00046 ReadMCNP5::ReadMCNP5( Interface* impl ) : MBI( impl ), fileIDTag( NULL ), nodeId( 0 ), elemId( 0 )
00047 {
00048 assert( NULL != impl );
00049 MBI->query_interface( readMeshIface );
00050 assert( NULL != readMeshIface );
00051 }
00052
00053 // Destructor
00054 ReadMCNP5::~ReadMCNP5()
00055 {
00056 if( readMeshIface )
00057 {
00058 MBI->release_interface( readMeshIface );
00059 readMeshIface = 0;
00060 }
00061 }
00062
00063 ErrorCode ReadMCNP5::read_tag_values( const char* /* file_name */,
00064 const char* /* tag_name */,
00065 const FileOptions& /* opts */,
00066 std::vector< int >& /* tag_values_out */,
00067 const SubsetList* /* subset_list */ )
00068 {
00069 return MB_NOT_IMPLEMENTED;
00070 }
00071
00072 // Load the file as called by the Interface function
00073 ErrorCode ReadMCNP5::load_file( const char* filename,
00074 const EntityHandle* input_meshset,
00075 const FileOptions& options,
00076 const ReaderIface::SubsetList* subset_list,
00077 const Tag* file_id_tag )
00078 {
00079 // At this time there is no support for reading a subset of the file
00080 if( subset_list )
00081 {
00082 MB_SET_ERR( MB_UNSUPPORTED_OPERATION, "Reading subset of files not supported for meshtal" );
00083 }
00084
00085 nodeId = elemId = 0;
00086 fileIDTag = file_id_tag;
00087
00088 // Average several meshtal files if the AVERAGE_TALLY option is given.
00089 // In this case, the integer value is the number of files to average.
00090 // If averaging, the filename passed to load_file is assumed to be the
00091 // root filename. The files are indexed as "root_filename""index".meshtal.
00092 // Indices start with 1.
00093 int n_files;
00094 bool average = false;
00095 ErrorCode result;
00096 if( MB_SUCCESS == options.get_int_option( "AVERAGE_TALLY", n_files ) )
00097 {
00098 // Read the first file (but do not average -> can't average a single file)
00099 result = load_one_file( filename, input_meshset, options, average );
00100 if( MB_SUCCESS != result ) return result;
00101
00102 // Get the root filename
00103 std::string root_filename( filename );
00104 int length = root_filename.length();
00105 root_filename.erase( length - sizeof( ".meshtal" ) );
00106
00107 // Average the first file with the rest of the files
00108 average = true;
00109 for( int i = 2; i <= n_files; i++ )
00110 {
00111 std::stringstream index;
00112 index << i;
00113 std::string subsequent_filename = root_filename + index.str() + ".meshtal";
00114 result = load_one_file( subsequent_filename.c_str(), input_meshset, options, average );
00115 if( MB_SUCCESS != result ) return result;
00116 }
00117
00118 // If not averaging, read a single file
00119 }
00120 else
00121 {
00122 result = load_one_file( filename, input_meshset, options, average );
00123 if( MB_SUCCESS != result ) return result;
00124 }
00125
00126 return MB_SUCCESS;
00127 }
00128
00129 // This actually reads the file. It creates the mesh elements unless
00130 // the file is being averaged with a pre-existing mesh.
00131 ErrorCode ReadMCNP5::load_one_file( const char* fname,
00132 const EntityHandle* input_meshset,
00133 const FileOptions& options,
00134 const bool average )
00135 {
00136 bool debug = false;
00137 if( debug ) std::cout << "begin ReadMCNP5::load_one_file" << std::endl;
00138
00139 ErrorCode result;
00140 std::fstream file;
00141 file.open( fname, std::fstream::in );
00142 char line[10000];
00143
00144 // Create tags
00145 Tag date_and_time_tag, title_tag, nps_tag, tally_number_tag, tally_comment_tag, tally_particle_tag,
00146 tally_coord_sys_tag, tally_tag, error_tag;
00147
00148 result = create_tags( date_and_time_tag, title_tag, nps_tag, tally_number_tag, tally_comment_tag,
00149 tally_particle_tag, tally_coord_sys_tag, tally_tag, error_tag );
00150 if( MB_SUCCESS != result ) return result;
00151
00152 // ******************************************************************
00153 // This info exists only at the top of each meshtal file
00154 // ******************************************************************
00155
00156 // Define characteristics of the entire file
00157 char date_and_time[100] = "";
00158 char title[100] = "";
00159 // This file's number of particles
00160 unsigned long int nps;
00161 // Sum of this file's and existing file's nps for averaging
00162 unsigned long int new_nps;
00163
00164 // Read the file header
00165 result = read_file_header( file, debug, date_and_time, title, nps );
00166 if( MB_SUCCESS != result ) return result;
00167
00168 // Blank line
00169 file.getline( line, 10000 );
00170
00171 // Everything stored in the file being read will be in the input_meshset.
00172 // If this is being saved in MOAB, set header tags
00173 if( !average && 0 != input_meshset )
00174 {
00175 result = set_header_tags( *input_meshset, date_and_time, title, nps, date_and_time_tag, title_tag, nps_tag );
00176 if( MB_SUCCESS != result ) return result;
00177 }
00178
00179 // ******************************************************************
00180 // This info is repeated for each tally in the meshtal file.
00181 // ******************************************************************
00182
00183 // If averaging, nps will hold the sum of particles simulated in both tallies.
00184 while( !file.eof() )
00185 {
00186 // Define characteristics of this tally
00187 unsigned int tally_number;
00188 char tally_comment[100] = "";
00189 particle tally_particle;
00190 coordinate_system tally_coord_sys;
00191 std::vector< double > planes[3];
00192 unsigned int n_chopped_x0_planes;
00193 unsigned int n_chopped_x2_planes;
00194
00195 // Read tally header
00196 result = read_tally_header( file, debug, tally_number, tally_comment, tally_particle );
00197 if( MB_SUCCESS != result ) return result;
00198
00199 // Blank line
00200 file.getline( line, 10000 );
00201 std::string l = line;
00202 // if this string is present then skip the following blank line
00203 if( std::string::npos != l.find( "This mesh tally is modified by a dose response function." ) )
00204 {
00205 file.getline( line, 10000 );
00206 }
00207
00208 // Read mesh planes
00209 result = read_mesh_planes( file, debug, planes, tally_coord_sys );
00210 if( MB_SUCCESS != result ) return result;
00211
00212 // Get energy boundaries
00213 file.getline( line, 10000 );
00214 std::string a = line;
00215 if( debug ) std::cout << "Energy bin boundaries:=| " << a << std::endl;
00216
00217 // Blank
00218 file.getline( line, 10000 );
00219
00220 // Column headers
00221 file.getline( line, 10000 );
00222
00223 // If using cylindrical mesh, it may be necessary to chop off the last theta element.
00224 // We chop off the last theta plane because the elements will be wrong and skew up
00225 // the tree building code. This is
00226 // because the hex elements are a linear approximation to the cylindrical elements.
00227 // Chopping off the last plane is problem-dependent, and due to MCNP5's mandate
00228 // that the cylindrical mesh must span 360 degrees.
00229 if( CYLINDRICAL == tally_coord_sys && MB_SUCCESS == options.get_null_option( "REMOVE_LAST_AZIMUTHAL_PLANE" ) )
00230 {
00231 planes[2].pop_back();
00232 n_chopped_x2_planes = 1;
00233 if( debug ) std::cout << "remove last cylindrical plane option found" << std::endl;
00234 }
00235 else
00236 {
00237 n_chopped_x2_planes = 0;
00238 }
00239
00240 // If using cylindrical mesh, it may be necessary to chop off the first radial element.
00241 // These elements extend from the axis and often do not cover areas of interest. For
00242 // example, if the mesh was meant to cover r=390-400, the first layer will go from
00243 // 0-390 and serve as incorrect source elements for interpolation.
00244 if( CYLINDRICAL == tally_coord_sys && MB_SUCCESS == options.get_null_option( "REMOVE_FIRST_RADIAL_PLANE" ) )
00245 {
00246 std::vector< double >::iterator front = planes[0].begin();
00247 planes[0].erase( front );
00248 n_chopped_x0_planes = 1;
00249 if( debug ) std::cout << "remove first radial plane option found" << std::endl;
00250 }
00251 else
00252 {
00253 n_chopped_x0_planes = 0;
00254 }
00255
00256 // Read the values and errors of each element from the file.
00257 // Do not read values that are chopped off.
00258 unsigned int n_elements = ( planes[0].size() - 1 ) * ( planes[1].size() - 1 ) * ( planes[2].size() - 1 );
00259 double* values = new double[n_elements];
00260 double* errors = new double[n_elements];
00261 result = read_element_values_and_errors( file, debug, planes, n_chopped_x0_planes, n_chopped_x2_planes,
00262 tally_particle, values, errors );
00263 if( MB_SUCCESS != result ) return result;
00264
00265 // Blank line
00266 file.getline( line, 10000 );
00267
00268 // ****************************************************************
00269 // This tally has been read. If it is not being averaged, build tags,
00270 // vertices and elements. If it is being averaged, average the data
00271 // with a tally already existing in the MOAB instance.
00272 // ****************************************************************
00273 if( !average )
00274 {
00275 EntityHandle tally_meshset;
00276 result = MBI->create_meshset( MESHSET_SET, tally_meshset );
00277 if( MB_SUCCESS != result ) return result;
00278
00279 // Set tags on the tally
00280 result = set_tally_tags( tally_meshset, tally_number, tally_comment, tally_particle, tally_coord_sys,
00281 tally_number_tag, tally_comment_tag, tally_particle_tag, tally_coord_sys_tag );
00282 if( MB_SUCCESS != result ) return result;
00283
00284 // The only info needed to build elements is the mesh plane boundaries.
00285 // Build vertices...
00286 EntityHandle start_vert = 0;
00287 result = create_vertices( planes, debug, start_vert, tally_coord_sys, tally_meshset );
00288 if( MB_SUCCESS != result ) return result;
00289
00290 // Build elements and tag them with tally values and errors, then add
00291 // them to the tally_meshset.
00292 result = create_elements( debug, planes, n_chopped_x0_planes, n_chopped_x2_planes, start_vert, values,
00293 errors, tally_tag, error_tag, tally_meshset, tally_coord_sys );
00294 if( MB_SUCCESS != result ) return result;
00295
00296 // Add this tally's meshset to the output meshset
00297 if( debug ) std::cout << "not averaging tally" << std::endl;
00298
00299 // Average the tally values, then delete stuff that was created
00300 }
00301 else
00302 {
00303 if( debug ) std::cout << "averaging tally" << std::endl;
00304 result = average_with_existing_tally( debug, new_nps, nps, tally_number, tally_number_tag, nps_tag,
00305 tally_tag, error_tag, values, errors, n_elements );
00306 if( MB_SUCCESS != result ) return result;
00307 }
00308
00309 // Clean up
00310 delete[] values;
00311 delete[] errors;
00312 }
00313
00314 // If we are averaging, delete the remainder of this file's information.
00315 // Add the new nps to the existing file's nps if we are averaging.
00316 // This is calculated during every tally averaging but only used after the last one.
00317 if( average )
00318 {
00319 Range matching_nps_sets;
00320 result = MBI->get_entities_by_type_and_tag( 0, MBENTITYSET, &nps_tag, 0, 1, matching_nps_sets );
00321 if( MB_SUCCESS != result ) return result;
00322 if( debug ) std::cout << "number of matching nps meshsets=" << matching_nps_sets.size() << std::endl;
00323 assert( 1 == matching_nps_sets.size() );
00324 result = MBI->tag_set_data( nps_tag, matching_nps_sets, &new_nps );
00325 if( MB_SUCCESS != result ) return result;
00326
00327 // If this file is not being averaged, return the output meshset.
00328 }
00329
00330 file.close();
00331 return MB_SUCCESS;
00332 }
00333
00334 // create tags needed for this reader
00335 ErrorCode ReadMCNP5::create_tags( Tag& date_and_time_tag,
00336 Tag& title_tag,
00337 Tag& nps_tag,
00338 Tag& tally_number_tag,
00339 Tag& tally_comment_tag,
00340 Tag& tally_particle_tag,
00341 Tag& tally_coord_sys_tag,
00342 Tag& tally_tag,
00343 Tag& error_tag )
00344 {
00345 ErrorCode result;
00346 result = MBI->tag_get_handle( "DATE_AND_TIME_TAG", 100, MB_TYPE_OPAQUE, date_and_time_tag,
00347 MB_TAG_SPARSE | MB_TAG_CREAT );
00348 if( MB_SUCCESS != result ) return result;
00349 result = MBI->tag_get_handle( "TITLE_TAG", 100, MB_TYPE_OPAQUE, title_tag, MB_TAG_SPARSE | MB_TAG_CREAT );
00350 if( MB_SUCCESS != result ) return result;
00351 result = MBI->tag_get_handle( "NPS_TAG", sizeof( unsigned long int ), MB_TYPE_OPAQUE, nps_tag,
00352 MB_TAG_SPARSE | MB_TAG_CREAT );
00353 if( MB_SUCCESS != result ) return result;
00354 result =
00355 MBI->tag_get_handle( "TALLY_NUMBER_TAG", 1, MB_TYPE_INTEGER, tally_number_tag, MB_TAG_SPARSE | MB_TAG_CREAT );
00356 if( MB_SUCCESS != result ) return result;
00357 result = MBI->tag_get_handle( "TALLY_COMMENT_TAG", 100, MB_TYPE_OPAQUE, tally_comment_tag,
00358 MB_TAG_SPARSE | MB_TAG_CREAT );
00359 if( MB_SUCCESS != result ) return result;
00360 result = MBI->tag_get_handle( "TALLY_PARTICLE_TAG", sizeof( particle ), MB_TYPE_OPAQUE, tally_particle_tag,
00361 MB_TAG_SPARSE | MB_TAG_CREAT );
00362 if( MB_SUCCESS != result ) return result;
00363 result = MBI->tag_get_handle( "TALLY_COORD_SYS_TAG", sizeof( coordinate_system ), MB_TYPE_OPAQUE,
00364 tally_coord_sys_tag, MB_TAG_SPARSE | MB_TAG_CREAT );
00365 if( MB_SUCCESS != result ) return result;
00366 result = MBI->tag_get_handle( "TALLY_TAG", 1, MB_TYPE_DOUBLE, tally_tag, MB_TAG_DENSE | MB_TAG_CREAT );
00367 if( MB_SUCCESS != result ) return result;
00368 result = MBI->tag_get_handle( "ERROR_TAG", 1, MB_TYPE_DOUBLE, error_tag, MB_TAG_DENSE | MB_TAG_CREAT );
00369 if( MB_SUCCESS != result ) return result;
00370
00371 return MB_SUCCESS;
00372 }
00373
00374 ErrorCode ReadMCNP5::read_file_header( std::fstream& file,
00375 bool debug,
00376 char date_and_time[100],
00377 char title[100],
00378 unsigned long int& nps )
00379 {
00380 // Get simulation date and time
00381 // mcnp version 5 ld=11242008 probid = 03/23/09 13:38:56
00382 char line[100];
00383 file.getline( line, 100 );
00384 date_and_time = line;
00385 if( debug ) std::cout << "date_and_time=| " << date_and_time << std::endl;
00386
00387 // Get simulation title
00388 // iter Module 4
00389 file.getline( line, 100 );
00390 title = line;
00391 if( debug ) std::cout << "title=| " << title << std::endl;
00392
00393 // Get number of histories
00394 // Number of histories used for normalizing tallies = 50000000.00
00395 file.getline( line, 100 );
00396 std::string a = line;
00397 std::string::size_type b = a.find( "Number of histories used for normalizing tallies =" );
00398 if( std::string::npos != b )
00399 {
00400 std::istringstream nps_ss(
00401 a.substr( b + sizeof( "Number of histories used for normalizing tallies =" ), 100 ) );
00402 nps_ss >> nps;
00403 if( debug ) std::cout << "nps=| " << nps << std::endl;
00404 }
00405 else
00406 return MB_FAILURE;
00407
00408 return MB_SUCCESS;
00409 }
00410
00411 ErrorCode ReadMCNP5::set_header_tags( EntityHandle output_meshset,
00412 char date_and_time[100],
00413 char title[100],
00414 unsigned long int nps,
00415 Tag data_and_time_tag,
00416 Tag title_tag,
00417 Tag nps_tag )
00418 {
00419 ErrorCode result;
00420 result = MBI->tag_set_data( data_and_time_tag, &output_meshset, 1, &date_and_time );
00421 if( MB_SUCCESS != result ) return result;
00422 result = MBI->tag_set_data( title_tag, &output_meshset, 1, &title );
00423 if( MB_SUCCESS != result ) return result;
00424 result = MBI->tag_set_data( nps_tag, &output_meshset, 1, &nps );
00425 if( MB_SUCCESS != result ) return result;
00426
00427 return MB_SUCCESS;
00428 }
00429
00430 ErrorCode ReadMCNP5::read_tally_header( std::fstream& file,
00431 bool debug,
00432 unsigned int& tally_number,
00433 char tally_comment[100],
00434 particle& tally_particle )
00435 {
00436 // Get tally number
00437 // Mesh Tally Number 104
00438 ErrorCode result;
00439 char line[100];
00440 file.getline( line, 100 );
00441 std::string a = line;
00442 std::string::size_type b = a.find( "Mesh Tally Number" );
00443 if( std::string::npos != b )
00444 {
00445 std::istringstream tally_number_ss( a.substr( b + sizeof( "Mesh Tally Number" ), 100 ) );
00446 tally_number_ss >> tally_number;
00447 if( debug ) std::cout << "tally_number=| " << tally_number << std::endl;
00448 }
00449 else
00450 {
00451 std::cout << "tally number not found" << std::endl;
00452 return MB_FAILURE;
00453 }
00454
00455 // Next get the tally comment (optional) and particle type
00456 // 3mm neutron heating in Be (W/cc)
00457 // This is a neutron mesh tally.
00458 // std::string tally_comment;
00459
00460 // Get tally particle
00461 file.getline( line, 100 );
00462 a = line;
00463 result = get_tally_particle( a, debug, tally_particle );
00464 if( MB_FAILURE == result )
00465 {
00466 // If this line does not specify the particle type, then it is a tally comment.
00467 // Get the comment, then get the particle type from the next line.
00468 tally_comment = line;
00469 file.getline( line, 100 );
00470 a = line;
00471 result = get_tally_particle( a, debug, tally_particle );
00472 if( MB_SUCCESS != result ) return result;
00473 }
00474 if( debug ) std::cout << "tally_comment=| " << tally_comment << std::endl;
00475
00476 return MB_SUCCESS;
00477 }
00478
00479 ErrorCode ReadMCNP5::get_tally_particle( std::string a, bool debug, particle& tally_particle )
00480 {
00481 if( std::string::npos != a.find( "This is a neutron mesh tally." ) )
00482 {
00483 tally_particle = NEUTRON;
00484 }
00485 else if( std::string::npos != a.find( "This is a photon mesh tally." ) )
00486 {
00487 tally_particle = PHOTON;
00488 }
00489 else if( std::string::npos != a.find( "This is an electron mesh tally." ) )
00490 {
00491 tally_particle = ELECTRON;
00492 }
00493 else
00494 return MB_FAILURE;
00495
00496 if( debug ) std::cout << "tally_particle=| " << tally_particle << std::endl;
00497
00498 return MB_SUCCESS;
00499 }
00500
00501 ErrorCode ReadMCNP5::read_mesh_planes( std::fstream& file,
00502 bool debug,
00503 std::vector< double > planes[3],
00504 coordinate_system& coord_sys )
00505 {
00506 // Tally bin boundaries:
00507 ErrorCode result;
00508 char line[10000];
00509 file.getline( line, 10000 );
00510 std::string a = line;
00511 if( std::string::npos == a.find( "Tally bin boundaries:" ) ) return MB_FAILURE;
00512
00513 // Decide what coordinate system the tally is using
00514 // first check for Cylindrical coordinates:
00515 file.getline( line, 10000 );
00516 a = line;
00517 std::string::size_type b = a.find( "Cylinder origin at" );
00518 if( std::string::npos != b )
00519 {
00520 coord_sys = CYLINDRICAL;
00521 if( debug ) std::cout << "origin, axis, direction=| " << a << std::endl;
00522 std::istringstream ss( a.substr( b + sizeof( "Cylinder origin at" ), 10000 ) );
00523 // The meshtal file does not contain sufficient information to transform
00524 // the particle. Although origin, axs, and vec is needed only origin and
00525 // axs appear in the meshtal file. Why was vec omitted?.
00526 // get origin (not used)
00527 // Cylinder origin at 0.00E+00 0.00E+00 0.00E+00,
00528 // axis in 0.000E+00 0.000E+00 1.000E+00 direction
00529 double origin[3];
00530 if( debug ) std::cout << "origin=| ";
00531 for( int i = 0; i < 3; i++ )
00532 {
00533 ss >> origin[i];
00534 if( debug ) std::cout << origin[i] << " ";
00535 }
00536 if( debug ) std::cout << std::endl;
00537 int length_of_string = 10;
00538 ss.ignore( length_of_string, ' ' );
00539 ss.ignore( length_of_string, ' ' );
00540 ss.ignore( length_of_string, ' ' );
00541 // Get axis (not used)
00542 double axis[3];
00543 if( debug ) std::cout << "axis=| ";
00544 for( int i = 0; i < 3; i++ )
00545 {
00546 ss >> axis[i];
00547 if( debug ) std::cout << axis[i] << " ";
00548 }
00549 if( debug ) std::cout << std::endl;
00550 file.getline( line, 10000 );
00551 a = line;
00552
00553 // Get r planes
00554 if( debug ) std::cout << "R direction:=| ";
00555 b = a.find( "R direction:" );
00556 if( std::string::npos != b )
00557 {
00558 std::istringstream ss2( a.substr( b + sizeof( "R direction" ), 10000 ) );
00559 result = get_mesh_plane( ss2, debug, planes[0] );
00560 if( MB_SUCCESS != result ) return result;
00561 }
00562 else
00563 return MB_FAILURE;
00564
00565 // Get z planes
00566 file.getline( line, 10000 );
00567 a = line;
00568 if( debug ) std::cout << "Z direction:=| ";
00569 b = a.find( "Z direction:" );
00570 if( std::string::npos != b )
00571 {
00572 std::istringstream ss2( a.substr( b + sizeof( "Z direction" ), 10000 ) );
00573 result = get_mesh_plane( ss2, debug, planes[1] );
00574 if( MB_SUCCESS != result ) return result;
00575 }
00576 else
00577 return MB_FAILURE;
00578
00579 // Get theta planes
00580 file.getline( line, 10000 );
00581 a = line;
00582 if( debug ) std::cout << "Theta direction:=| ";
00583 b = a.find( "Theta direction (revolutions):" );
00584 if( std::string::npos != b )
00585 {
00586 std::istringstream ss2( a.substr( b + sizeof( "Theta direction (revolutions):" ), 10000 ) );
00587 result = get_mesh_plane( ss2, debug, planes[2] );
00588 if( MB_SUCCESS != result ) return result;
00589 }
00590 else
00591 return MB_FAILURE;
00592
00593 // Cartesian coordinate system:
00594 }
00595 else if( std::string::npos != a.find( "X direction:" ) )
00596 {
00597 coord_sys = CARTESIAN;
00598 // Get x planes
00599 if( debug ) std::cout << "X direction:=| ";
00600 b = a.find( "X direction:" );
00601 if( std::string::npos != b )
00602 {
00603 std::istringstream ss2( a.substr( b + sizeof( "X direction" ), 10000 ) );
00604 result = get_mesh_plane( ss2, debug, planes[0] );
00605 if( MB_SUCCESS != result ) return result;
00606 }
00607 else
00608 return MB_FAILURE;
00609
00610 // Get y planes
00611 file.getline( line, 10000 );
00612 a = line;
00613 if( debug ) std::cout << "Y direction:=| ";
00614 b = a.find( "Y direction:" );
00615 if( std::string::npos != b )
00616 {
00617 std::istringstream ss2( a.substr( b + sizeof( "Y direction" ), 10000 ) );
00618 result = get_mesh_plane( ss2, debug, planes[1] );
00619 if( MB_SUCCESS != result ) return result;
00620 }
00621 else
00622 return MB_FAILURE;
00623
00624 // Get z planes
00625 file.getline( line, 10000 );
00626 a = line;
00627 if( debug ) std::cout << "Z direction:=| ";
00628 b = a.find( "Z direction:" );
00629 if( std::string::npos != b )
00630 {
00631 std::istringstream ss2( a.substr( b + sizeof( "Z direction" ), 10000 ) );
00632 result = get_mesh_plane( ss2, debug, planes[2] );
00633 if( MB_SUCCESS != result ) return result;
00634 }
00635 else
00636 return MB_FAILURE;
00637
00638 // Spherical coordinate system not yet implemented:
00639 }
00640 else
00641 return MB_FAILURE;
00642
00643 return MB_SUCCESS;
00644 }
00645
00646 // Given a stringstream, return a vector of values in the string.
00647 ErrorCode ReadMCNP5::get_mesh_plane( std::istringstream& ss, bool debug, std::vector< double >& plane )
00648 {
00649 double value;
00650 plane.clear();
00651 while( !ss.eof() )
00652 {
00653 ss >> value;
00654 plane.push_back( value );
00655 if( debug ) std::cout << value << " ";
00656 }
00657 if( debug ) std::cout << std::endl;
00658
00659 return MB_SUCCESS;
00660 }
00661
00662 ErrorCode ReadMCNP5::read_element_values_and_errors( std::fstream& file,
00663 bool /* debug */,
00664 std::vector< double > planes[3],
00665 unsigned int n_chopped_x0_planes,
00666 unsigned int n_chopped_x2_planes,
00667 particle tally_particle,
00668 double values[],
00669 double errors[] )
00670 {
00671 unsigned int index = 0;
00672 // Need to read every line in the file, even if we chop off some elements
00673 for( unsigned int i = 0; i < planes[0].size() - 1 + n_chopped_x0_planes; i++ )
00674 {
00675 for( unsigned int j = 0; j < planes[1].size() - 1; j++ )
00676 {
00677 for( unsigned int k = 0; k < planes[2].size() - 1 + n_chopped_x2_planes; k++ )
00678 {
00679 char line[100];
00680 file.getline( line, 100 );
00681 // If this element has been chopped off, skip it
00682 if( i < n_chopped_x0_planes ) continue;
00683 if( k >= planes[2].size() - 1 && k < planes[2].size() - 1 + n_chopped_x2_planes ) continue;
00684 std::string a = line;
00685 std::stringstream ss( a );
00686 double centroid[3];
00687 double energy;
00688 // For some reason, photon tallies print the energy in the first column
00689 if( PHOTON == tally_particle ) ss >> energy;
00690 // The centroid is not used in this reader
00691 ss >> centroid[0];
00692 ss >> centroid[1];
00693 ss >> centroid[2];
00694 // Only the tally values and errors are used
00695 ss >> values[index];
00696 ss >> errors[index];
00697
00698 // Make sure that input data is good
00699 if( !Util::is_finite( errors[index] ) )
00700 {
00701 std::cerr << "found nan error while reading file" << std::endl;
00702 errors[index] = 1.0;
00703 }
00704 if( !Util::is_finite( values[index] ) )
00705 {
00706 std::cerr << "found nan value while reading file" << std::endl;
00707 values[index] = 0.0;
00708 }
00709
00710 index++;
00711 }
00712 }
00713 }
00714
00715 return MB_SUCCESS;
00716 }
00717
00718 ErrorCode ReadMCNP5::set_tally_tags( EntityHandle tally_meshset,
00719 unsigned int tally_number,
00720 char tally_comment[100],
00721 particle tally_particle,
00722 coordinate_system tally_coord_sys,
00723 Tag tally_number_tag,
00724 Tag tally_comment_tag,
00725 Tag tally_particle_tag,
00726 Tag tally_coord_sys_tag )
00727 {
00728 ErrorCode result;
00729 result = MBI->tag_set_data( tally_number_tag, &tally_meshset, 1, &tally_number );
00730 if( MB_SUCCESS != result ) return result;
00731 result = MBI->tag_set_data( tally_comment_tag, &tally_meshset, 1, &tally_comment );
00732 if( MB_SUCCESS != result ) return result;
00733 result = MBI->tag_set_data( tally_particle_tag, &tally_meshset, 1, &tally_particle );
00734 if( MB_SUCCESS != result ) return result;
00735 result = MBI->tag_set_data( tally_coord_sys_tag, &tally_meshset, 1, &tally_coord_sys );
00736 if( MB_SUCCESS != result ) return result;
00737
00738 return MB_SUCCESS;
00739 }
00740
00741 ErrorCode ReadMCNP5::create_vertices( std::vector< double > planes[3],
00742 bool debug,
00743 EntityHandle& start_vert,
00744 coordinate_system coord_sys,
00745 EntityHandle tally_meshset )
00746 {
00747 // The only info needed to build elements is the mesh plane boundaries.
00748 ErrorCode result;
00749 int n_verts = planes[0].size() * planes[1].size() * planes[2].size();
00750 if( debug ) std::cout << "n_verts=" << n_verts << std::endl;
00751 std::vector< double* > coord_arrays( 3 );
00752 result = readMeshIface->get_node_coords( 3, n_verts, MB_START_ID, start_vert, coord_arrays );
00753 if( MB_SUCCESS != result ) return result;
00754 assert( 0 != start_vert ); // Check for NULL
00755
00756 for( unsigned int k = 0; k < planes[2].size(); k++ )
00757 {
00758 for( unsigned int j = 0; j < planes[1].size(); j++ )
00759 {
00760 for( unsigned int i = 0; i < planes[0].size(); i++ )
00761 {
00762 unsigned int idx = ( k * planes[0].size() * planes[1].size() + j * planes[0].size() + i );
00763 double in[3], out[3];
00764
00765 in[0] = planes[0][i];
00766 in[1] = planes[1][j];
00767 in[2] = planes[2][k];
00768 result = transform_point_to_cartesian( in, out, coord_sys );
00769 if( MB_SUCCESS != result ) return result;
00770
00771 // Cppcheck warning (false positive): variable coord_arrays is assigned a value that
00772 // is never used
00773 coord_arrays[0][idx] = out[0];
00774 coord_arrays[1][idx] = out[1];
00775 coord_arrays[2][idx] = out[2];
00776 }
00777 }
00778 }
00779 Range vert_range( start_vert, start_vert + n_verts - 1 );
00780 result = MBI->add_entities( tally_meshset, vert_range );
00781 if( MB_SUCCESS != result ) return result;
00782
00783 if( fileIDTag )
00784 {
00785 result = readMeshIface->assign_ids( *fileIDTag, vert_range, nodeId );
00786 if( MB_SUCCESS != result ) return result;
00787 nodeId += vert_range.size();
00788 }
00789
00790 return MB_SUCCESS;
00791 }
00792
00793 ErrorCode ReadMCNP5::create_elements( bool debug,
00794 std::vector< double > planes[3],
00795 unsigned int /*n_chopped_x0_planes*/,
00796 unsigned int /*n_chopped_x2_planes*/,
00797 EntityHandle start_vert,
00798 double* values,
00799 double* errors,
00800 Tag tally_tag,
00801 Tag error_tag,
00802 EntityHandle tally_meshset,
00803 coordinate_system tally_coord_sys )
00804 {
00805 ErrorCode result;
00806 unsigned int index;
00807 EntityHandle start_element = 0;
00808 unsigned int n_elements = ( planes[0].size() - 1 ) * ( planes[1].size() - 1 ) * ( planes[2].size() - 1 );
00809 EntityHandle* connect;
00810 result = readMeshIface->get_element_connect( n_elements, 8, MBHEX, MB_START_ID, start_element, connect );
00811 if( MB_SUCCESS != result ) return result;
00812 assert( 0 != start_element ); // Check for NULL
00813
00814 unsigned int counter = 0;
00815 for( unsigned int i = 0; i < planes[0].size() - 1; i++ )
00816 {
00817 for( unsigned int j = 0; j < planes[1].size() - 1; j++ )
00818 {
00819 for( unsigned int k = 0; k < planes[2].size() - 1; k++ )
00820 {
00821 index = start_vert + i + j * planes[0].size() + k * planes[0].size() * planes[1].size();
00822 // For rectangular mesh, the file prints: x y z
00823 // z changes the fastest and x changes the slowest.
00824 // This means that the connectivity ordering is not consistent between
00825 // rectangular and cylindrical mesh.
00826 if( CARTESIAN == tally_coord_sys )
00827 {
00828 connect[0] = index;
00829 connect[1] = index + 1;
00830 connect[2] = index + 1 + planes[0].size();
00831 connect[3] = index + planes[0].size();
00832 connect[4] = index + planes[0].size() * planes[1].size();
00833 connect[5] = index + 1 + planes[0].size() * planes[1].size();
00834 connect[6] = index + 1 + planes[0].size() + planes[0].size() * planes[1].size();
00835 connect[7] = index + planes[0].size() + planes[0].size() * planes[1].size();
00836 // For cylindrical mesh, the file prints: r z theta
00837 // Theta changes the fastest and r changes the slowest.
00838 }
00839 else if( CYLINDRICAL == tally_coord_sys )
00840 {
00841 connect[0] = index;
00842 connect[1] = index + 1;
00843 connect[2] = index + 1 + planes[0].size() * planes[1].size();
00844 connect[3] = index + planes[0].size() * planes[1].size();
00845 connect[4] = index + planes[0].size();
00846 connect[5] = index + 1 + planes[0].size();
00847 connect[6] = index + 1 + planes[0].size() + planes[0].size() * planes[1].size();
00848 connect[7] = index + planes[0].size() + planes[0].size() * planes[1].size();
00849 }
00850 else
00851 return MB_NOT_IMPLEMENTED;
00852
00853 connect += 8;
00854 counter++;
00855 }
00856 }
00857 }
00858 if( counter != n_elements ) std::cout << "counter=" << counter << " n_elements=" << n_elements << std::endl;
00859
00860 Range element_range( start_element, start_element + n_elements - 1 );
00861 result = MBI->tag_set_data( tally_tag, element_range, values );
00862 if( MB_SUCCESS != result ) return result;
00863 result = MBI->tag_set_data( error_tag, element_range, errors );
00864 if( MB_SUCCESS != result ) return result;
00865
00866 // Add the elements to the tally set
00867 result = MBI->add_entities( tally_meshset, element_range );
00868 if( MB_SUCCESS != result ) return result;
00869 if( debug ) std::cout << "Read " << n_elements << " elements from tally." << std::endl;
00870
00871 if( fileIDTag )
00872 {
00873 result = readMeshIface->assign_ids( *fileIDTag, element_range, elemId );
00874 if( MB_SUCCESS != result ) return result;
00875 elemId += element_range.size();
00876 }
00877
00878 return MB_SUCCESS;
00879 }
00880
00881 // Average a tally that was recently read in with one that already exists in
00882 // the interface. Only the existing values will be updated.
00883 ErrorCode ReadMCNP5::average_with_existing_tally( bool debug,
00884 unsigned long int& new_nps,
00885 unsigned long int nps1,
00886 unsigned int tally_number,
00887 Tag tally_number_tag,
00888 Tag nps_tag,
00889 Tag tally_tag,
00890 Tag error_tag,
00891 double* values1,
00892 double* errors1,
00893 unsigned int n_elements )
00894 {
00895 // Get the tally number
00896 ErrorCode result;
00897
00898 // Match the tally number with one from the existing meshtal file
00899 Range matching_tally_number_sets;
00900 const void* const tally_number_val[] = { &tally_number };
00901 result = MBI->get_entities_by_type_and_tag( 0, MBENTITYSET, &tally_number_tag, tally_number_val, 1,
00902 matching_tally_number_sets );
00903 if( MB_SUCCESS != result ) return result;
00904 if( debug ) std::cout << "number of matching meshsets=" << matching_tally_number_sets.size() << std::endl;
00905 assert( 1 == matching_tally_number_sets.size() );
00906
00907 // Identify which of the meshsets is existing
00908 EntityHandle existing_meshset;
00909 existing_meshset = matching_tally_number_sets.front();
00910
00911 // Get the existing elements from the set
00912 Range existing_elements;
00913 result = MBI->get_entities_by_type( existing_meshset, MBHEX, existing_elements );
00914 if( MB_SUCCESS != result ) return result;
00915 assert( existing_elements.size() == n_elements );
00916
00917 // Get the nps of the existing and new tally
00918 unsigned long int nps0;
00919 Range sets_with_this_tag;
00920 result = MBI->get_entities_by_type_and_tag( 0, MBENTITYSET, &nps_tag, 0, 1, sets_with_this_tag );
00921 if( MB_SUCCESS != result ) return result;
00922 if( debug ) std::cout << "number of nps sets=" << sets_with_this_tag.size() << std::endl;
00923 assert( 1 == sets_with_this_tag.size() );
00924 result = MBI->tag_get_data( nps_tag, &sets_with_this_tag.front(), 1, &nps0 );
00925 if( MB_SUCCESS != result ) return result;
00926 if( debug ) std::cout << "nps0=" << nps0 << " nps1=" << nps1 << std::endl;
00927 new_nps = nps0 + nps1;
00928
00929 // Get tally values from the existing elements
00930 double* values0 = new double[existing_elements.size()];
00931 double* errors0 = new double[existing_elements.size()];
00932 result = MBI->tag_get_data( tally_tag, existing_elements, values0 );
00933 if( MB_SUCCESS != result )
00934 {
00935 delete[] values0;
00936 delete[] errors0;
00937 return result;
00938 }
00939 result = MBI->tag_get_data( error_tag, existing_elements, errors0 );
00940 if( MB_SUCCESS != result )
00941 {
00942 delete[] values0;
00943 delete[] errors0;
00944 return result;
00945 }
00946
00947 // Average the values and errors
00948 result = average_tally_values( nps0, nps1, values0, values1, errors0, errors1, n_elements );
00949 if( MB_SUCCESS != result )
00950 {
00951 delete[] values0;
00952 delete[] errors0;
00953 return result;
00954 }
00955
00956 // Set the averaged information back onto the existing elements
00957 result = MBI->tag_set_data( tally_tag, existing_elements, values0 );
00958 if( MB_SUCCESS != result )
00959 {
00960 delete[] values0;
00961 delete[] errors0;
00962 return result;
00963 }
00964 result = MBI->tag_set_data( error_tag, existing_elements, errors0 );
00965 if( MB_SUCCESS != result )
00966 {
00967 delete[] values0;
00968 delete[] errors0;
00969 return result;
00970 }
00971
00972 // Cleanup
00973 delete[] values0;
00974 delete[] errors0;
00975
00976 return MB_SUCCESS;
00977 }
00978
00979 ErrorCode ReadMCNP5::transform_point_to_cartesian( double* in, double* out, coordinate_system coord_sys )
00980 {
00981 // Transform coordinate system
00982 switch( coord_sys )
00983 {
00984 case CARTESIAN:
00985 out[0] = in[0]; // x
00986 out[1] = in[1]; // y
00987 out[2] = in[2]; // z
00988 break;
00989 // theta is in rotations
00990 case CYLINDRICAL:
00991 out[0] = in[0] * cos( 2 * PI * in[2] ); // x
00992 out[1] = in[0] * sin( 2 * PI * in[2] ); // y
00993 out[2] = in[1]; // z
00994 break;
00995 case SPHERICAL:
00996 return MB_NOT_IMPLEMENTED;
00997 default:
00998 return MB_NOT_IMPLEMENTED;
00999 }
01000
01001 return MB_SUCCESS;
01002 }
01003
01004 // Average two tally values and their error. Return average values in the
01005 // place of first tally values.
01006 ErrorCode ReadMCNP5::average_tally_values( const unsigned long int nps0,
01007 const unsigned long int nps1,
01008 double* values0,
01009 const double* values1,
01010 double* errors0,
01011 const double* errors1,
01012 const unsigned long int n_values )
01013 {
01014 for( unsigned long int i = 0; i < n_values; i++ )
01015 {
01016 // std::cout << " values0=" << values0[i] << " values1=" << values1[i]
01017 // << " errors0=" << errors0[i] << " errors1=" << errors1[i]
01018 // << " nps0=" << nps0 << " nps1=" << nps1 << std::endl;
01019 errors0[i] = sqrt( pow( values0[i] * errors0[i] * nps0, 2 ) + pow( values1[i] * errors1[i] * nps1, 2 ) ) /
01020 ( values0[i] * nps0 + values1[i] * nps1 );
01021
01022 // It is possible to introduce nans if the values are zero.
01023 if( !Util::is_finite( errors0[i] ) ) errors0[i] = 1.0;
01024
01025 values0[i] = ( values0[i] * nps0 + values1[i] * nps1 ) / ( nps0 + nps1 );
01026
01027 // std::cout << " values0=" << values0[i] << " errors0=" << errors0[i] << std::endl;
01028 }
01029 // REMEMBER TO UPDATE NPS0 = NPS0 + NPS1 after this
01030
01031 return MB_SUCCESS;
01032 }
01033
01034 } // namespace moab