cgma
MCNPInput.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines