cgma
|
00001 #include "MCNPInput.hpp" 00002 #include "geometry.hpp" 00003 #include "options.hpp" 00004 00005 #include <stdexcept> 00006 #include <cassert> 00007 #include <iostream> 00008 #include <sstream> 00009 #include <cstdlib> 00010 00011 /****************** 00012 * IMPLEMENTATIONS OF DataRef 00013 ******************/ 00014 00015 template <class T> 00016 class CardRef : public DataRef<T>{ 00017 00018 protected: 00019 InputDeck& deck; 00020 DataCard::id_t key; 00021 00022 public: 00023 CardRef( InputDeck& deck_p, DataCard::kind kind, int ident ) : 00024 DataRef<T>(), deck(deck_p), key( std::make_pair( kind, ident ) ) 00025 {} 00026 00027 virtual const T& getData() const { 00028 DataCard* c = deck.lookup_data_card( key ); 00029 const T& ref = dynamic_cast< DataRef<T>* >(c)->getData(); 00030 return ref; 00031 } 00032 00033 virtual CardRef<T> * clone(){ 00034 return new CardRef<T>( *this ); 00035 } 00036 00037 const DataCard::id_t& getKey() const { return key; } 00038 00039 }; 00040 00041 /****************** 00042 * HELPER FUNCTIONS 00043 ******************/ 00044 00045 static void strlower( std::string& str ){ 00046 // convert to lowercase 00047 for(size_t i = 0; i < str.length(); ++i){ 00048 str[i] = tolower( str.at(i) ); 00049 } 00050 } 00051 00052 00053 static int makeint( const std::string& token ){ 00054 const char* str = token.c_str(); 00055 char* end; 00056 int ret = strtol(str, &end, 10); 00057 if( end != str+token.length() ){ 00058 std::cerr << "Warning: string [" << token << "] did not convert to int as expected." << std::endl; 00059 } 00060 return ret; 00061 } 00062 00063 static double makedouble( const std::string& token ){ 00064 std::string tmp = token; 00065 00066 // MCNP allows FORTRAN-style floating point values where the 'e' in the exponent is missing, 00067 // e.g. 1.23-45 means 1.23e-45. The following check inserts such a missing 'e' to avoid 00068 // confusing strtod(). 00069 size_t s_idx = tmp.find_last_of("+-"); 00070 if( s_idx != tmp.npos && s_idx > tmp.find_first_of("1234567890") && tmp.at(s_idx-1) != 'e' ){ 00071 tmp.insert( tmp.find_last_of("+-"), "e" ); 00072 if( OPT_DEBUG ) std::cout << "Formatting FORTRAN value: converted " << token << " to " << tmp << std::endl; 00073 } 00074 00075 const char* str = tmp.c_str(); 00076 char* end; 00077 double ret = strtod(str, &end); 00078 if( end != str+tmp.length() ){ 00079 std::cerr << "Warning: string [" << tmp << "] did not convert to double as expected." << std::endl; 00080 } 00081 return ret; 00082 } 00083 00085 static std::vector<double> makeTransformArgs( const token_list_t tokens ){ 00086 std::vector<double> args; 00087 for( token_list_t::const_iterator i = tokens.begin(); i!=tokens.end(); ++i){ 00088 00089 std::string token = *i; 00090 size_t idx; 00091 while( (idx = token.find_first_of("()")) != token.npos){ 00092 token.replace( idx, 1, "" ); // remove parentheses 00093 } 00094 if( token.find_first_of( "1234567890" ) != token.npos){ 00095 args.push_back( makedouble( token ) ); 00096 } 00097 else if( token.length() > 0) { 00098 std::cerr << "Warning: makeTransformArgs ignoring unrecognized input token [" << token << "]" << std::endl; 00099 } 00100 } 00101 return args; 00102 } 00103 00110 static DataRef<Transform>* parseTransform( InputDeck& deck, const token_list_t tokens, bool degree_format = false ){ 00111 00112 std::vector<double> args = makeTransformArgs( tokens ); 00113 if( args.size() == 1 ){ 00114 return new CardRef<Transform>( deck, DataCard::TR, static_cast<int>(args[0]) ); 00115 } 00116 else{ 00117 return new ImmediateRef<Transform>( Transform( args, degree_format ) ); 00118 } 00119 } 00120 00121 static DataRef<Transform>* parseTransform( InputDeck& deck, token_list_t::iterator& i, bool degree_format = false ){ 00122 00123 token_list_t args; 00124 std::string next_token = *i; 00125 00126 if( next_token.find("(") != next_token.npos ){ 00127 do{ 00128 args.push_back( next_token ); 00129 next_token = *(++i); 00130 } 00131 while( next_token.find(")") == next_token.npos ); 00132 } 00133 00134 args.push_back( next_token ); 00135 00136 return parseTransform( deck, args, degree_format ); 00137 } 00138 00139 static FillNode parseFillNode( InputDeck& deck, token_list_t::iterator& i, const token_list_t::iterator& end, bool degree_format = false ){ 00140 // simple fill. Format is n or n (transform). Transform may be either a TR card number 00141 // or an immediate transform 00142 00143 int n; // the filling universe 00144 DataRef<Transform>* t; 00145 bool has_transform = false; 00146 00147 std::string first_token = *i; 00148 size_t paren_idx = first_token.find("("); 00149 00150 std::string second_token; 00151 00152 if( paren_idx != first_token.npos ){ 00153 // first_token has an open paren 00154 std::string n_str(first_token, 0, paren_idx); 00155 n = makeint(n_str); 00156 00157 second_token = first_token.substr(paren_idx,first_token.npos); 00158 has_transform = true; 00159 } 00160 else{ 00161 n = makeint(first_token); 00162 00163 if( ++i != end ){ 00164 second_token = *i; 00165 if( second_token[0] == '(' ){ 00166 has_transform = true; 00167 } 00168 else{ 00169 // the next token didn't belong to this fill 00170 i--; 00171 } 00172 } 00173 else{ i--; } 00174 } 00175 00176 if( has_transform ){ 00177 token_list_t transform_tokens; 00178 std::string next_token = second_token; 00179 00180 while( next_token.find(")") == next_token.npos ){ 00181 transform_tokens.push_back(next_token); 00182 next_token = *(++i); 00183 } 00184 transform_tokens.push_back( next_token ); 00185 00186 t = parseTransform( deck, transform_tokens, degree_format ); 00187 00188 } 00189 else{ 00190 t = new NullRef<Transform>(); 00191 } 00192 00193 00194 if( n < 0 ){ 00195 n = -n; // TODO: handle negative universe numbers specially 00196 } 00197 00198 return FillNode (n, t ); 00199 } 00200 00201 static bool isblank( const std::string& line ){ 00202 return (line=="" || line.find_first_not_of(" ") == line.npos ); 00203 } 00204 00205 00206 template < class T > 00207 std::ostream& operator<<( std::ostream& out, const std::vector<T>& list ){ 00208 00209 out << "["; 00210 00211 for(typename std::vector<T>::const_iterator i = list.begin(); i!=list.end(); ++i){ 00212 out << *i << "|"; 00213 } 00214 00215 if(list.size() > 0) 00216 out << "\b"; // unless list was empty, backspace the last | character 00217 00218 out << "]"; 00219 return out; 00220 } 00221 00222 00223 00224 /****************** 00225 * CELL CARDS 00226 ******************/ 00227 00228 class CellCardImpl : public CellCard { 00229 00230 protected: 00231 static geom_list_entry_t make_geom_entry(geom_token_t t, int param = 0){ 00232 return std::make_pair(t, param); 00233 } 00234 00235 static bool is_num_token( geom_list_entry_t t ){ 00236 return t.first == CELLNUM || t.first == SURFNUM || t.first == MBODYFACET; 00237 } 00238 00239 static bool is_op_token( geom_list_entry_t t ){ 00240 return t.first == COMPLEMENT || t.first == UNION || t.first == INTERSECT; 00241 } 00242 00243 static int operator_priority( geom_list_entry_t t ){ 00244 switch(t.first){ 00245 case COMPLEMENT: return 3; 00246 case INTERSECT: return 2; 00247 case UNION: return 1; 00248 default: 00249 throw std::runtime_error("queried operator priority for a non-operator token"); 00250 } 00251 } 00252 00261 void retokenize_geometry( const token_list_t& tokens ){ 00262 for(token_list_t::const_iterator i = tokens.begin(); i!=tokens.end(); ++i){ 00263 const std::string& token = *i; 00264 00265 size_t j = 0; 00266 while( j < token.length() ){ 00267 00268 char cj = token.at(j); 00269 00270 switch(cj){ 00271 00272 // the following macro pushes an intersect token onto the geom list 00273 // if the end of that list indicates that one is needed 00274 #define IMPLICIT_INTERSECT() do{ \ 00275 if(geom.size()){ \ 00276 geom_list_entry_t &t = geom.at(geom.size()-1); \ 00277 if( is_num_token(t) || t.first == RPAREN ){ \ 00278 geom.push_back( make_geom_entry( INTERSECT ) ); \ 00279 }}} while(0) 00280 00281 case '(': 00282 IMPLICIT_INTERSECT(); 00283 geom.push_back(make_geom_entry(LPAREN)); j++; 00284 break; 00285 00286 case ')': 00287 geom.push_back(make_geom_entry(RPAREN)); j++; 00288 break; 00289 00290 case '#': 00291 IMPLICIT_INTERSECT(); 00292 geom.push_back(make_geom_entry(COMPLEMENT)); j++; 00293 break; 00294 00295 case ':': 00296 geom.push_back(make_geom_entry(UNION)); j++; 00297 break; 00298 00299 default: // a number 00300 // the number refers to a cell if the previous token is a complement 00301 bool is_cell = geom.size() && ((geom.at(geom.size()-1)).first == COMPLEMENT); 00302 IMPLICIT_INTERSECT(); 00303 assert(isdigit(cj) || cj == '+' || cj == '-' ); 00304 size_t end = token.find_first_not_of("1234567890-+.",j); 00305 assert(j != end); 00306 00307 std::string numstr( token, j, end-j ); 00308 const char* numstr_c = numstr.c_str(); 00309 char* p; 00310 int num = strtol( numstr_c, &p, 10 ); 00311 00312 if( *p == '.' ){ 00313 // This is a macrobody facet 00314 assert( !is_cell ); 00315 00316 int facet = strtol( p+1, NULL, 10 ); 00317 assert( facet > 0 && facet <= 8 ); 00318 00319 // storage of macrobody facets: multiply cell number by ten, add facet number 00320 num *= 10; 00321 // don't add a positive facet number to a negative cell numer 00322 num += (num > 0) ? facet : -facet; 00323 geom.push_back( make_geom_entry( MBODYFACET, num ) ); 00324 } 00325 else{ 00326 geom.push_back( make_geom_entry( is_cell ? CELLNUM : SURFNUM, num )); 00327 } 00328 00329 j += (end-j); 00330 break; 00331 #undef IMPLICIT_INTERSECT 00332 00333 } 00334 00335 } 00336 } 00337 00338 if( OPT_DEBUG ) std::cout << tokens << " -> " << geom << std::endl; 00339 00340 } 00341 00342 00349 void shunt_geometry( ){ 00350 geom_list_t geom_copy( geom ); 00351 geom.clear(); 00352 00353 geom_list_t stack; 00354 for(geom_list_t::iterator i = geom_copy.begin(); i!=geom_copy.end(); ++i){ 00355 geom_list_entry_t token = *i; 00356 if( is_num_token(token) ){ 00357 geom.push_back(token); 00358 } 00359 else if( is_op_token(token) ){ 00360 00361 while(stack.size()){ 00362 geom_list_entry_t& stack_top = stack.back(); 00363 if( is_op_token(stack_top) && operator_priority(stack_top) > operator_priority(token) ){ 00364 geom.push_back(stack_top); 00365 stack.pop_back(); 00366 } 00367 else{ 00368 break; 00369 } 00370 } 00371 stack.push_back(token); 00372 } 00373 else if( token.first == LPAREN ){ 00374 stack.push_back(token); 00375 } 00376 else if( token.first == RPAREN ){ 00377 while( stack.back().first != LPAREN ){ 00378 geom.push_back( stack.back() ); 00379 stack.pop_back(); 00380 } 00381 stack.pop_back(); // remove the LPAREN 00382 } 00383 } 00384 while( stack.size() ){ 00385 geom.push_back( stack.back() ); 00386 stack.pop_back(); 00387 } 00388 } 00389 00390 Vector3d latticeVectorHelper( Vector3d difference_along_normal, Vector3d v_dir ){ 00391 double length = difference_along_normal.length() / (difference_along_normal.normalize().dot(v_dir)); 00392 return v_dir * length; 00393 } 00394 00395 void setupLattice(){ 00396 00397 if( OPT_DEBUG ) std::cout << "Setting up lattice for cell " << ident << std::endl; 00398 00399 std::vector< std::pair<SurfaceCard*,bool> > surfaceCards; 00400 00401 for( geom_list_t::iterator i = geom.begin(); i!=geom.end(); ++i){ 00402 geom_list_entry_t entry = *i; 00403 if( entry.first == SURFNUM ){ 00404 SurfaceCard* surf = parent_deck.lookup_surface_card( std::abs(entry.second) ); 00405 assert(surf); 00406 surfaceCards.push_back( std::make_pair(surf, (entry.second>0) ) ); 00407 } 00408 } 00409 00410 int num_finite_dims = 0; 00411 Vector3d v1, v2, v3; 00412 00413 std::vector< std::pair<Vector3d, double> > planes; 00414 00415 if( surfaceCards.size() == 1 ){ 00416 planes = surfaceCards.at(0).first->getMacrobodyPlaneParams(); 00417 if( surfaceCards.at(0).second != false ){ 00418 std::cerr << "Warning: macrobody lattice with positive sense, will proceed as if it was negative."; 00419 } 00420 } 00421 else{ 00422 for( unsigned int i = 0; i < surfaceCards.size(); ++i){ 00423 planes.push_back( surfaceCards.at(i).first->getPlaneParams() ); 00424 if( surfaceCards.at(i).second == true ){ planes[i].first = -planes[i].first; } 00425 } 00426 } 00427 00428 if( OPT_DEBUG ){ 00429 for( unsigned int i = 0; i < planes.size(); ++i){ 00430 std::cout << " plane " << i << " normal = " << planes[i].first << " d = " << planes[i].second << std::endl; 00431 } 00432 } 00433 if( lat_type == HEXAHEDRAL ){ 00434 assert( planes.size() == 2 || planes.size() == 4 || planes.size() == 6 ); 00435 if( planes.size() == 2 ){ 00436 00437 num_finite_dims = 1; 00438 v1 = planes[0].first.normalize() * std::fabs( planes[0].second - planes[1].second ); 00439 00440 } 00441 else if( planes.size() == 4 ){ 00442 num_finite_dims = 2; 00443 00444 Vector3d v3 = planes[0].first.cross( planes[2].first ).normalize(); // infer a third (infinite) direction 00445 00446 // vector from planes[1] to planes[0] 00447 Vector3d xv = planes[0].first.normalize() * std::fabs( planes[0].second - planes[1].second ); 00448 00449 // direction of l.v1: cross product of normals planes[2] and v3 00450 Vector3d xv2 = planes[2].first.normalize().cross( v3 ).normalize(); 00451 v1 = latticeVectorHelper( xv, xv2 ); 00452 00453 Vector3d yv = planes[2].first.normalize() * std::fabs( planes[2].second - planes[3].second ); 00454 Vector3d yv2 = planes[0].first.normalize().cross( v3 ).normalize(); 00455 v2 = latticeVectorHelper( yv, yv2 ); 00456 00457 00458 } 00459 else{ // planes.size() == 6 00460 num_finite_dims = 3; 00461 00462 // vector from planes[1] to planes[0] 00463 Vector3d xv = planes[0].first.normalize() * std::fabs( planes[0].second - planes[1].second ); 00464 00465 // direction of v1: cross product of normals planes[2] and planes[4] 00466 Vector3d xv2 = planes[2].first.normalize().cross( planes[4].first.normalize() ).normalize(); 00467 v1 = latticeVectorHelper( xv, xv2 ); 00468 00469 Vector3d yv = planes[2].first.normalize() * std::fabs( planes[2].second - planes[3].second ); 00470 Vector3d yv2 = planes[0].first.normalize().cross( planes[4].first.normalize() ).normalize(); 00471 v2 = latticeVectorHelper( yv, yv2 ); 00472 00473 Vector3d zv = planes[4].first.normalize() * std::fabs( planes[4].second - planes[5].second ); 00474 Vector3d zv2 = planes[0].first.normalize().cross( planes[2].first.normalize() ).normalize(); 00475 v3 = latticeVectorHelper( zv, zv2 ); 00476 00477 } 00478 00479 } 00480 else if( lat_type == HEXAGONAL ){ 00481 assert( planes.size() == 6 || planes.size() == 8 ); 00482 00483 v3 = planes[0].first.cross( planes[2].first ).normalize(); // prism's primary axis 00484 00485 // vector from planes[1] to planes[0] 00486 Vector3d xv = planes[0].first.normalize() * std::fabs( planes[0].second - planes[1].second ); 00487 00488 // direction of l.v1: cross product of normals average(planes[2]+planes[4]) and v3 00489 // TODO: this averaging trick only works with regular hexagons... 00490 Vector3d xv2 = (planes[2].first.normalize()+planes[4].first.normalize()).normalize().cross( v3 ).normalize(); 00491 v1 = latticeVectorHelper( xv, xv2 ); 00492 00493 Vector3d yv = planes[2].first.normalize() * std::fabs( planes[2].second - planes[3].second ); 00494 Vector3d yv2 = (planes[1].first.normalize()+planes[4].first.normalize()).normalize().cross( v3 ).normalize(); 00495 v2 = latticeVectorHelper( yv, yv2 ); 00496 00497 00498 if( planes.size() == 6 ){ 00499 num_finite_dims = 2; 00500 00501 } 00502 else{ // planes.size() == 8 00503 num_finite_dims = 3; 00504 00505 Vector3d zv = planes[6].first.normalize() * std::fabs( planes[6].second - planes[7].second ); 00506 Vector3d zv2 = v3; 00507 v3 = latticeVectorHelper( zv, zv2 ); 00508 } 00509 } 00510 00511 if( OPT_DEBUG )std::cout << " dims " << num_finite_dims << " vectors " << v1 << v2 << v3 << std::endl; 00512 00513 Lattice l; 00514 if( fill->hasData() ){ 00515 l = Lattice( num_finite_dims, v1, v2, v3, fill->getData() ); 00516 } 00517 else{ 00518 FillNode n( this->universe ); 00519 l = Lattice( num_finite_dims, v1, v2, v3, n ); 00520 } 00521 00522 lattice = new ImmediateRef<Lattice>( l ); 00523 00524 00525 } 00526 00527 void makeData(){ 00528 00529 for( token_list_t::iterator i = data.begin(); i!=data.end(); ++i ){ 00530 00531 std::string token = *i; 00532 00533 if( token == "trcl" || token == "*trcl" ){ 00534 bool degree_format = (token[0] == '*'); 00535 00536 i++; 00537 trcl = parseTransform( parent_deck, i, degree_format ); 00538 00539 } // token == {*}trcl 00540 00541 else if( token == "u" ){ 00542 universe = makeint(*(++i)); 00543 } // token == "u" 00544 else if ( token == "lat" ){ 00545 int lat_designator = makeint(*(++i)); 00546 assert( lat_designator >= 0 && lat_designator <= 2 ); 00547 lat_type = static_cast<lattice_type_t>(lat_designator); 00548 if( OPT_DEBUG ) std::cout << "cell " << ident << " is lattice type " << lat_type << std::endl; 00549 } 00550 else if ( token == "mat" ){ 00551 material = makeint(*(++i)); 00552 } 00553 else if ( token == "rho" ){ 00554 rho = makedouble(*(++i)); 00555 } 00556 else if ( token.length() == 5 && token.substr(0,4) == "imp:" ){ 00557 double imp = makedouble(*(++i)); 00558 importances[token[4]] = imp; 00559 } 00560 else if( token == "fill" || token == "*fill" ){ 00561 00562 bool degree_format = (token[0] == '*'); 00563 00564 std::string next_token = *(++i); 00565 00566 // an explicit lattice grid exists if 00567 // * the next token contains a colon, or 00568 // * the token after it exists and starts with a colon 00569 bool explicit_grid = next_token.find(":") != next_token.npos; 00570 explicit_grid = explicit_grid || (i+1 != data.end() && (*(i+1)).at(0) == ':' ); 00571 00572 if( explicit_grid ){ 00573 00574 // convert the grid specifiers (x1:x2, y1:y2, z1:z2) into three spaceless strings for easier parsing 00575 std::string gridspec[3]; 00576 for( int dim = 0; dim < 3; ++dim ){ 00577 00578 std::string spec; 00579 00580 // add tokens to the spec string until it contains a colon but does not end with one 00581 do{ 00582 spec += *i; 00583 i++; 00584 } 00585 while( spec.find(":") == spec.npos || spec.at(spec.length()-1) == ':' ); 00586 00587 if(OPT_DEBUG) std::cout << "gridspec[" << dim << "]: " << spec << std::endl; 00588 gridspec[dim] = spec; 00589 00590 } 00591 00592 irange ranges[3]; 00593 const char* range_str; 00594 char *p; 00595 00596 int num_elements = 1; 00597 for( int dim = 0; dim < 3; ++dim ){ 00598 range_str = gridspec[dim].c_str(); 00599 ranges[dim].first = strtol(range_str, &p, 10); 00600 ranges[dim].second = strtol(p+1, NULL, 10); 00601 00602 if( ranges[dim].second != ranges[dim].first ){ 00603 num_elements *= ( ranges[dim].second - ranges[dim].first )+1; 00604 } 00605 00606 } 00607 00608 std::vector<FillNode> elements; 00609 for( int j = 0; j < num_elements; ++j ){ 00610 elements.push_back( parseFillNode( parent_deck, i, data.end(), degree_format ) ); 00611 i++; 00612 } 00613 i--; 00614 00615 fill = new ImmediateRef< Fill >( Fill( ranges[0], ranges[1], ranges[2], elements) ); 00616 00617 } 00618 else{ // no explicit grid; fill card is a single fill node 00619 FillNode filler = parseFillNode( parent_deck, i, data.end(), degree_format ); 00620 fill = new ImmediateRef< Fill >( Fill(filler) ); 00621 00622 } 00623 } // token == {*}fill 00624 } 00625 00626 // ensure data pointers are valid 00627 if( !trcl ) { 00628 trcl = new NullRef< Transform >(); 00629 } 00630 00631 if( !fill ){ 00632 fill = new NullRef< Fill > (); 00633 } 00634 00635 } 00636 00637 int ident; 00638 int material; 00639 double rho; // material density 00640 std::map<char, double> importances; 00641 00642 geom_list_t geom; 00643 token_list_t data; 00644 DataRef<Transform>* trcl; 00645 DataRef<Fill>* fill; 00646 int universe; 00647 00648 bool likenbut; 00649 int likeness_cell_n; 00650 00651 lattice_type_t lat_type; 00652 DataRef<Lattice> *lattice; 00653 00654 public: 00655 CellCardImpl( InputDeck& deck, const token_list_t& tokens ) : 00656 CellCard( deck ), trcl(NULL), fill(NULL), universe(0), likenbut(false), likeness_cell_n(0), 00657 lat_type(NONE), lattice(NULL) 00658 { 00659 00660 unsigned int idx = 0; 00661 00662 ident = makeint(tokens.at(idx++)); 00663 00664 if(tokens.at(idx) == "like"){ 00665 00666 idx++; 00667 likenbut = true; 00668 likeness_cell_n = makeint(tokens.at(idx++)); 00669 idx++; // skip the "but" token 00670 while(idx < tokens.size()){ 00671 data.push_back(tokens[idx++]); 00672 } 00673 return; 00674 } 00675 00676 material = makeint(tokens.at(idx++)); 00677 rho = 0.0; 00678 if(material != 0){ 00679 rho = makedouble(tokens.at(idx++)); // material density 00680 } 00681 00682 token_list_t temp_geom; 00683 00684 // while the tokens appear in geometry-specification syntax, store them into temporary list 00685 while(idx < tokens.size() && tokens.at(idx).find_first_of("1234567890:#-+()") == 0){ 00686 temp_geom.push_back(tokens[idx++]); 00687 } 00688 00689 // retokenize the geometry list, which follows a specialized syntax. 00690 retokenize_geometry( temp_geom ); 00691 shunt_geometry(); 00692 00693 // store the rest of the tokens into the data list 00694 while(idx < tokens.size()){ 00695 data.push_back(tokens[idx++]); 00696 } 00697 00698 makeData(); 00699 00700 } 00701 00702 ~CellCardImpl(){ 00703 if(trcl) 00704 delete trcl; 00705 if(fill) 00706 delete fill; 00707 if(lattice) 00708 delete lattice; 00709 } 00710 00711 virtual int getIdent() const{ return ident; } 00712 virtual const geom_list_t getGeom() const { return geom; } 00713 00714 virtual const DataRef<Transform>& getTrcl() const { return *trcl; } 00715 virtual int getUniverse() const { return universe; } 00716 00717 virtual bool hasFill() const { return fill && fill->hasData(); } 00718 virtual const Fill& getFill() const { 00719 if( fill && fill->hasData() ){ 00720 return fill->getData(); 00721 } 00722 throw std::runtime_error( "Called getFill() on an unfilled cell"); 00723 } 00724 00725 virtual bool isLattice() const { 00726 return lat_type != NONE; 00727 } 00728 00729 virtual lattice_type_t getLatticeType() const { 00730 return lat_type; 00731 } 00732 00733 virtual const Lattice& getLattice() const { 00734 if( lattice && lattice->hasData() ){ 00735 return lattice->getData(); 00736 } 00737 throw std::runtime_error( "Called getLattice() on a cell that hasn't got one" ); 00738 } 00739 00740 virtual int getMat() const { return material; } 00741 virtual double getRho() const { return rho; } 00742 virtual const std::map<char,double>& getImportances() const { return importances; } 00743 00744 virtual void print( std::ostream& s ) const{ 00745 s << "Cell " << ident << " geom " << geom << std::endl; 00746 } 00747 00748 protected: 00749 void finish(){ 00750 if( likenbut ){ 00751 CellCardImpl* host = dynamic_cast<CellCardImpl*>(parent_deck.lookup_cell_card( likeness_cell_n )); 00752 if(host->likenbut){ 00753 host->finish(); // infinite recursion if cells are circularly defined... but our users wouldn't do that, right? 00754 } 00755 geom = host->geom; 00756 universe = host->universe; 00757 lat_type = host->lat_type; 00758 material = host->material; 00759 rho = host->rho; 00760 importances = host->importances; 00761 00762 if( host->trcl->hasData()){ 00763 trcl = host->trcl->clone(); 00764 } 00765 if( host->hasFill()){ 00766 fill = host->fill->clone(); 00767 } 00768 if( host->isLattice()){ 00769 lattice = host->lattice->clone(); 00770 } 00771 makeData(); 00772 00773 likenbut = false; 00774 } 00775 00776 if( lat_type != NONE && lattice == NULL ){ 00777 setupLattice(); 00778 } 00779 00780 } 00781 00782 friend class InputDeck; 00783 }; 00784 00785 CellCard::CellCard( InputDeck& deck ) : 00786 Card(deck) 00787 {} 00788 00789 std::ostream& operator<<(std::ostream& str, const CellCard::geom_list_entry_t& t ){ 00790 switch(t.first){ 00791 case CellCard::LPAREN: str << "("; break; 00792 case CellCard::RPAREN: str << ")"; break; 00793 case CellCard::COMPLEMENT: str << "#"; break; 00794 case CellCard::UNION: str << ":"; break; 00795 case CellCard::INTERSECT: str << "*"; break; 00796 case CellCard::SURFNUM: str << t.second; break; 00797 case CellCard::CELLNUM: str << "c" << t.second; break; 00798 case CellCard::MBODYFACET: 00799 int cell = t.second / 10; 00800 int facet = abs(t.second) - (abs(cell)*10); 00801 str << cell << "." << facet; 00802 break; 00803 } 00804 return str; 00805 } 00806 00807 00808 00809 /****************** 00810 * SURFACE CARDS 00811 ******************/ 00812 00813 SurfaceCard::SurfaceCard( InputDeck& deck, const token_list_t tokens ): 00814 Card(deck) 00815 { 00816 size_t idx = 0; 00817 std::string token1 = tokens.at(idx++); 00818 if(token1.find_first_of("*+") != token1.npos){ 00819 std::cerr << "Warning: no special handling for reflecting or white-boundary surfaces" << std::endl; 00820 token1[0] = ' '; 00821 } 00822 ident = makeint(token1); 00823 00824 std::string token2 = tokens.at(idx++); 00825 if(token2.find_first_of("1234567890-") != 0){ 00826 //token2 is the mnemonic 00827 coord_xform = new NullRef<Transform>(); 00828 mnemonic = token2; 00829 } 00830 else{ 00831 // token2 is a coordinate transform identifier 00832 int tx_id = makeint(token2); 00833 00834 if( tx_id == 0 ){ 00835 std::cerr << "I don't think 0 is a valid surface transformation ID, so I'm ignoring it." << std::endl; 00836 coord_xform = new NullRef<Transform>(); 00837 } 00838 else if ( tx_id < 0 ){ 00839 // abs(tx_id) is the ID of surface with respect to which this surface is periodic. 00840 std::cerr << "Warning: surface " << ident << " periodic, but this program has no special handling for periodic surfaces"; 00841 } 00842 else{ // tx_id is positive and nonzero 00843 coord_xform = new CardRef<Transform>( deck, DataCard::TR, makeint(token2) ); 00844 } 00845 00846 mnemonic = tokens.at(idx++); 00847 00848 } 00849 00850 while( idx < tokens.size() ){ 00851 args.push_back( makedouble(tokens[idx++]) ); 00852 } 00853 00854 } 00855 00856 const DataRef<Transform>& SurfaceCard::getTransform() const { 00857 return *coord_xform; 00858 } 00859 00860 void SurfaceCard::print( std::ostream& s ) const { 00861 s << "Surface " << ident << " " << mnemonic << args; 00862 if( coord_xform->hasData() ){ 00863 // this ugly lookup returns the integer ID of the TR card 00864 s << " TR" << dynamic_cast<CardRef<Transform>*>(coord_xform)->getKey().second; 00865 } 00866 s << std::endl; 00867 } 00868 00869 std::pair<Vector3d,double> SurfaceCard::getPlaneParams() const { 00870 if(mnemonic == "px"){ 00871 return std::make_pair(Vector3d(1,0,0), args[0]); 00872 } 00873 else if(mnemonic == "py"){ 00874 return std::make_pair(Vector3d(0,1,0), args[0]); 00875 } 00876 else if(mnemonic == "pz"){ 00877 return std::make_pair(Vector3d(0,0,1), args[0]); 00878 } 00879 else if(mnemonic == "p"){ 00880 return std::make_pair(Vector3d( args ), args[3]/Vector3d(args).length()); 00881 } 00882 else{ 00883 throw std::runtime_error("Tried to get plane normal of non-plane surface!"); 00884 } 00885 } 00886 00887 std::vector< std::pair<Vector3d, double> > SurfaceCard::getMacrobodyPlaneParams() const { 00888 00889 std::vector< std::pair< Vector3d, double> > ret; 00890 if( mnemonic == "box" ){ 00891 Vector3d corner( args ); 00892 const Vector3d v[3] = {Vector3d(args,3), Vector3d(args,6), Vector3d(args,9)}; 00893 00894 // face order: v1 -v1 v2 -v2 v3 -v3 00895 for( int i = 0; i < 3; ++i ){ 00896 Vector3d p = corner + v[i]; 00897 ret.push_back( std::make_pair( v[i].normalize(), v[i].projection( p ).length() ) ); 00898 ret.push_back( std::make_pair( -v[i].normalize(), v[i].projection( p ).length()-v[i].length() ) ); 00899 } 00900 00901 } 00902 else if( mnemonic == "rpp" ){ 00903 Vector3d min( args.at(0), args.at(2), args.at(4) ); 00904 Vector3d max( args.at(1), args.at(3), args.at(5) ); 00905 00906 for( int i = 0; i < 3; ++i ){ 00907 Vector3d v; v.v[i] = 1; 00908 ret.push_back( std::make_pair( v.normalize(), max.v[i] )); 00909 ret.push_back( std::make_pair(-v.normalize(), min.v[i] )); 00910 } 00911 00912 } 00913 else if( mnemonic == "hex" || mnemonic == "rhp" ){ 00914 00915 Vector3d vertex( args ), height( args,3 ), RV( args, 6 ), SV, TV; 00916 if( args.size() == 9 ){ 00917 SV = RV.rotate_about(height, 60); TV = RV.rotate_about(height, 120); 00918 } 00919 else{ 00920 SV = Vector3d( args, 9 ); TV = Vector3d( args, 12 ); 00921 } 00922 00923 double len = RV.projection( vertex+RV ).length(); 00924 ret.push_back( std::make_pair( RV.normalize(), len ) ); 00925 ret.push_back( std::make_pair(-RV.normalize(), len - 2.0 * RV.length() )); 00926 00927 len = SV.projection( vertex+SV ).length(); 00928 ret.push_back( std::make_pair( SV.normalize(), len ) ); 00929 ret.push_back( std::make_pair(-SV.normalize(), len - 2.0 * SV.length() )); 00930 00931 len = TV.projection( vertex+TV ).length(); 00932 ret.push_back( std::make_pair( TV.normalize(), len ) ); 00933 ret.push_back( std::make_pair(-TV.normalize(), len - 2.0 * TV.length() )); 00934 00935 len = height.projection( vertex+height ).length(); 00936 ret.push_back( std::make_pair( height.normalize(), len ) ); 00937 ret.push_back( std::make_pair(-height.normalize(), len - height.length() )); 00938 00939 } 00940 else{ 00941 throw std::runtime_error("Tried to get macrobody plane normals of unsupported surface!" ); 00942 } 00943 return ret; 00944 } 00945 00946 00947 00948 /****************** 00949 * DATA CARDS 00950 ******************/ 00951 00952 00953 class TransformCard : public DataCard, public DataRef<Transform> { 00954 00955 protected: 00956 int ident; 00957 Transform trans; 00958 00959 public: 00960 TransformCard( InputDeck& deck, int ident_p, bool degree_format, const token_list_t& input ); 00961 00962 // const Transform& getTransform() const{ return trans; } 00963 const Transform& getData() const{ return trans; } 00964 TransformCard* clone(){ return new TransformCard(*this); } 00965 00966 virtual void print( std::ostream& str ); 00967 virtual kind getKind(){ return TR; } 00968 int getIdent() const{ return ident; } 00969 00970 }; 00971 00972 TransformCard::TransformCard( InputDeck& deck, int ident_p, bool degree_format, const token_list_t& input ): 00973 DataCard(deck), ident(ident_p), trans( Transform( makeTransformArgs( input ), degree_format ) ) 00974 {} 00975 00976 void TransformCard::print( std::ostream& str ){ 00977 str << "TR" << ident << ": "; 00978 trans.print(str); 00979 str << std::endl; 00980 } 00981 00982 00983 00984 /****************** 00985 * PARSING UTILITIES 00986 ******************/ 00987 00988 class InputDeck::LineExtractor{ 00989 00990 protected: 00991 std::istream& input; 00992 std::string next_line; 00993 bool has_next; 00994 int next_line_idx; 00995 00996 /* 00997 * Take note of the following, from mcnp5 manual page 1-3: 00998 * Tab characters in the input file are converted to one or more blanks, such that the character 00999 * following the tab will be positioned at the next tab stop. Tab stops are set every 8 characters, 01000 * i.e., 9, 17, 25, etc. The limit of input lines to 80 columns applies after tabs are expanded into blank 01001 * spaces. </snip> 01002 * I don't know whether this needs to be addressed to handle corner cases for line continuation, etc. 01003 * currently, it is not addressed. 01004 */ 01005 01006 void get_next(){ 01007 01008 bool comment; 01009 do{ 01010 01011 if(!std::getline(input, next_line)){ 01012 has_next = false; 01013 } 01014 else{ 01015 01016 comment = false; 01017 next_line_idx++; 01018 01019 // strip trailing carriage return, if any 01020 if(next_line.length() > 0 && *(next_line.rbegin()) == '\r') 01021 next_line.resize(next_line.size()-1); 01022 01023 // convert to lowercase 01024 strlower(next_line); 01025 01026 // Append a space, to catch blank comment lines (e.g. "c\n") that would otherwise not meet 01027 // the MCNP comment card spec ("a C anywhere in columns 1-5 followed by at least one blank.") 01028 // I have seen lines like "c\n" or " c\n" as complete comment cards in practice, so MCNP must 01029 // accept them. 01030 next_line.append(" "); 01031 01032 // We want to find "c " within the first five 01033 // columns, but not if the c has anything other than a space before it. 01034 size_t idx = next_line.find("c "); 01035 if( idx < 5 ){ 01036 if( idx == 0 || next_line.at(idx-1) == ' '){ 01037 comment = true; 01038 } 01039 } 01040 } 01041 } 01042 while( has_next && comment ); 01043 // iterate until next_line is not a comment line. 01044 01045 } 01046 01047 public: 01048 LineExtractor( std::istream& input_p ) : 01049 input(input_p), next_line("*NO INPUT*"), has_next(true), next_line_idx(0) 01050 { 01051 get_next(); 01052 } 01053 01054 const std::string& peekLine() const { 01055 if( has_next ) return next_line; 01056 else throw std::runtime_error("LineExtractor out of lines, cannot peekLine()."); 01057 } 01058 01059 const std::string& peekLine( int& lineno ) const { 01060 lineno = next_line_idx; 01061 return peekLine(); 01062 } 01063 01064 std::string takeLine() { 01065 if( has_next ){ 01066 std::string ret = next_line; 01067 get_next(); 01068 return ret; 01069 } 01070 else throw std::runtime_error("LineExtractor out of lines, cannot takeLine()."); 01071 } 01072 01073 std::string takeLine( int& lineno ){ 01074 lineno = next_line_idx; 01075 return takeLine(); 01076 } 01077 01078 bool hasLine() const{ 01079 return has_next; 01080 } 01081 01086 int getLineCount() const{ 01087 return next_line_idx; 01088 } 01089 01090 }; 01091 01098 void appendToTokenList( const std::string& token, token_list_t& tokens ){ 01099 if( token.find_first_of("123456789") == 0 && token.at(token.length()-1) == 'r' ){ 01100 // token starts with a number and ends with r: treat as repeat syntax. 01101 const char* string = token.c_str(); 01102 char* p; 01103 int num = strtol( string, &p, 10 ); 01104 if( (p - string) != static_cast<int>(token.length()) - 1 ){ 01105 // oops, this isn't repeat format after all 01106 tokens.push_back(token); 01107 return; 01108 } 01109 01110 if( OPT_DEBUG ) { std::cout << "Repeat syntax: " << token << " repeats " 01111 << tokens.back() << " " << num << " times." << std::endl; } 01112 01113 for( int i = 0; i < num; ++i){ 01114 const std::string& last_tok = tokens.back(); 01115 tokens.push_back( last_tok ); 01116 } 01117 } 01118 else{ 01119 tokens.push_back(token); 01120 } 01121 } 01122 01123 void tokenizeLine( std::string line, token_list_t& tokens, const char* extra_separators = "" ){ 01124 01125 // replace any occurances of the characters in extra_separators with spaces; 01126 // they will then act as token separators 01127 size_t found; 01128 01129 found = line.find_first_of(extra_separators); 01130 while (found!= line.npos ) 01131 { 01132 line[found] = ' '; 01133 found = line.find_first_of(extra_separators,found+1); 01134 } 01135 01136 std::stringstream str(line); 01137 while(str){ 01138 std::string t; 01139 str >> t; 01140 01141 // skip over $-style inline comments 01142 size_t idx; 01143 if((idx = t.find("$")) != t.npos){ 01144 if(idx > 0){ 01145 // this token had some data before the $ 01146 t.resize(idx); 01147 appendToTokenList( t, tokens ); 01148 } 01149 break; 01150 } 01151 01152 // if the token is nontrivial, save it 01153 // necessary because stringstream may return a "" at the end of lines. 01154 if(t.length() > 0) appendToTokenList( t, tokens ); 01155 } 01156 01157 } 01158 01159 /****************** 01160 * INPUT DECK 01161 ******************/ 01162 01163 InputDeck::~InputDeck(){ 01164 for(cell_card_list::iterator i = cells.begin(); i!=cells.end(); ++i){ 01165 delete *i; 01166 } 01167 cells.clear(); 01168 for(surface_card_list::iterator i = surfaces.begin(); i!=surfaces.end(); ++i){ 01169 delete *i; 01170 } 01171 surfaces.clear(); 01172 for(data_card_list::iterator i = datacards.begin(); i!=datacards.end(); ++i){ 01173 delete *i; 01174 } 01175 datacards.clear(); 01176 01177 } 01178 01179 /* handle line continuations: return true if the next line should be treated as part of 01180 * the current line */ 01181 bool InputDeck::do_line_continuation( LineExtractor& lines, token_list_t& token_buffer ){ 01182 01183 /* check for final character being & */ 01184 std::string last_token = token_buffer.at(token_buffer.size()-1); 01185 if( last_token.at(last_token.length()-1) == '&' ){ 01186 01187 if( last_token.length() == 1 ){ 01188 token_buffer.pop_back(); 01189 } 01190 else{ 01191 last_token.resize(last_token.length()-1); 01192 token_buffer.at(token_buffer.size()-1).swap( last_token ); 01193 } 01194 01195 return true; 01196 } 01197 /* check for next line beginning with five spaces */ 01198 else if( lines.hasLine() && lines.peekLine().find(" ") == 0){ 01199 /* but don't count it as a continuation if the line is entirely blank */ 01200 if( lines.peekLine().find_first_not_of(" \t\n") != std::string::npos ){ 01201 return true; 01202 } 01203 } 01204 01205 return false; 01206 } 01207 01208 void InputDeck::parseCells( LineExtractor& lines ){ 01209 01210 std::string line; 01211 token_list_t token_buffer; 01212 01213 while( !isblank(line = lines.takeLine()) ){ 01214 01215 tokenizeLine(line, token_buffer, "="); 01216 01217 if( do_line_continuation( lines, token_buffer ) ){ 01218 continue; 01219 } 01220 01221 if( OPT_DEBUG ) std::cout << "Creating cell with the following tokens:\n" << token_buffer << std::endl; 01222 CellCard* c = new CellCardImpl(*this, token_buffer); 01223 01224 if( OPT_VERBOSE ) c->print(std::cout); 01225 01226 this->cells.push_back(c); 01227 this->cell_map.insert( std::make_pair(c->getIdent(), c) ); 01228 01229 token_buffer.clear(); 01230 01231 } 01232 01233 01234 } 01235 01236 01237 01238 void InputDeck::parseTitle( LineExtractor& lines ){ 01239 01240 // FIXME: will break if the title line looks like a comment card. 01241 01242 int lineno; 01243 std::string topLine = lines.takeLine(lineno); 01244 if(topLine.find("message:") == 0){ 01245 if( OPT_VERBOSE ) std::cout << "Skipping MCNP file message block..." << std::endl; 01246 do{ 01247 // nothing 01248 } 01249 while( !isblank(lines.takeLine()) ) /*do nothing */; 01250 01251 topLine = lines.takeLine(lineno); 01252 } 01253 01254 if(topLine.find("continue") == 0){ 01255 std::cerr << "Warning: this looks like it might be a `continue-run' input file." << std::endl; 01256 std::cerr << " beware of trouble ahead!" << std::endl; 01257 } 01258 01259 std::cout << "The MCNP title card is: " << topLine << std::endl; 01260 //std::cout << " and occupies line " << lineno << std::endl; 01261 } 01262 01263 01264 01265 void InputDeck::parseSurfaces( LineExtractor& lines ){ 01266 std::string line; 01267 token_list_t token_buffer; 01268 01269 while( !isblank(line = lines.takeLine()) ){ 01270 01271 tokenizeLine(line, token_buffer ); 01272 01273 if( do_line_continuation( lines, token_buffer ) ){ 01274 continue; 01275 } 01276 01277 SurfaceCard* s = new SurfaceCard(*this, token_buffer); 01278 01279 if( OPT_VERBOSE) s->print(std::cout); 01280 01281 this->surfaces.push_back(s); 01282 this->surface_map.insert( std::make_pair(s->getIdent(), s) ); 01283 01284 token_buffer.clear(); 01285 01286 } 01287 } 01288 01289 void InputDeck::parseDataCards( LineExtractor& lines ){ 01290 01291 std::string line; 01292 token_list_t token_buffer; 01293 01294 while( lines.hasLine() && !isblank(line = lines.takeLine()) ){ 01295 01296 tokenizeLine(line, token_buffer ); 01297 01298 if( do_line_continuation( lines, token_buffer ) ){ 01299 continue; 01300 } 01301 else if( token_buffer.at(0) == "#" ){ 01302 std::cerr << "Vertical data card format not supported" << std::endl; 01303 std::cerr << "Data written in this format will be ignored." << std::endl; 01304 } 01305 01306 DataCard* d = NULL; 01307 DataCard::kind t = DataCard::OTHER; 01308 int ident = 0; 01309 01310 std::string cardname = token_buffer.at(0); 01311 token_buffer.erase( token_buffer.begin() ); 01312 01313 if( cardname.find("tr") == 0 || cardname.find("*tr") == 0 ){ 01314 01315 t = DataCard::TR; 01316 bool degree_format = false; 01317 if( cardname[0] == '*' ){ 01318 degree_format = true; 01319 cardname = cardname.substr( 1 ); // remove leading * 01320 } 01321 else if( cardname.find("*") == cardname.length()-1 ){ 01322 // although it's undocumented, apparently TRn* is a synonym for *TRn 01323 // (the manual uses this undocumented form in chapter 4) 01324 degree_format = true; 01325 cardname.resize( cardname.length() -1 ); // remove trailing * 01326 } 01327 01328 std::string id_string( cardname, 2 ); 01329 01330 // the id_string may be empty, indicating that n is missing from TRn. 01331 // examples from the manual indicate it should be assumed to be 1 01332 if( id_string == "" ){ 01333 ident = 1; 01334 } 01335 else{ 01336 ident = makeint( id_string ); 01337 } 01338 01339 d = new TransformCard( *this, ident, degree_format, token_buffer); 01340 } 01341 01342 if(d){ 01343 if( OPT_VERBOSE ){ d->print( std::cout ); } 01344 this->datacards.push_back(d); 01345 this->datacard_map.insert( std::make_pair( std::make_pair(t,ident), d) ); 01346 } 01347 01348 token_buffer.clear(); 01349 01350 } 01351 01352 } 01353 01354 InputDeck& InputDeck::build( std::istream& input){ 01355 01356 LineExtractor lines(input); 01357 01358 InputDeck* deck = new InputDeck(); 01359 01360 deck->parseTitle(lines); 01361 deck->parseCells(lines); 01362 deck->parseSurfaces(lines); 01363 deck->parseDataCards(lines); 01364 01365 01366 for( std::vector<CellCard*>::iterator i = deck->cells.begin(); i!=deck->cells.end(); ++i){ 01367 dynamic_cast<CellCardImpl*>(*i)->finish(); 01368 } 01369 01370 while(lines.hasLine()){ lines.takeLine(); } 01371 if( OPT_VERBOSE ) { std::cout << "Total lines read: " << lines.getLineCount() << std::endl; } 01372 01373 return *deck; 01374 } 01375 01376 InputDeck::cell_card_list InputDeck::getCellsOfUniverse( int universe ){ 01377 01378 cell_card_list ret; 01379 for( cell_card_list::iterator i = cells.begin(); i!=cells.end(); ++i){ 01380 CellCard* c = *i; 01381 if( std::abs(c->getUniverse()) == universe ){ 01382 ret.push_back( *i ); 01383 } 01384 } 01385 return ret; 01386 01387 } 01388 01389 01390 CellCard* InputDeck::lookup_cell_card(int ident){ 01391 assert( cell_map.find(ident) != cell_map.end() ); 01392 return (*cell_map.find(ident)).second; 01393 } 01394 01395 SurfaceCard* InputDeck::lookup_surface_card(int ident){ 01396 assert( surface_map.find(ident) != surface_map.end() ); 01397 return (*surface_map.find(ident)).second; 01398 } 01399 01400 DataCard* InputDeck::lookup_data_card( const DataCard::id_t& ident ){ 01401 assert( datacard_map.find(ident) != datacard_map.end() ); 01402 return (*datacard_map.find(ident)).second; 01403 }