Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members | Related Pages

list_1d.cpp

Go to the documentation of this file.
00001 /*
00002  * ******** fete: From ENDF To ENDL *********
00003  * 
00004  * Copyright (c) 2006, The Regents of the University of California. 
00005  * All rights reserved.
00006  * 
00007  * Produced at the Lawrence Livermore National Laboratory. 
00008  * Written by David A. Brown, Gerry Hedstrom, Tony Hill
00009  * 
00010  * This file is part of fete v1.0  (UCRL-CODE-218718)
00011  * 
00012  * Please read the COPYING file for "Our Notice and GNU General 
00013  * Public License" in the root of this software distribution.  
00014  * 
00015  * This program is free software; you can redistribute it and/or modify 
00016  * it under the terms of the GNU General Public License (as published by 
00017  * the Free Software Foundation) version 2, dated June 1991. 
00018  * 
00019  * This program is distributed in the hope that it will be useful, 
00020  * but WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF 
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms 
00022  * and conditions of the GNU General Public License for more details. 
00023  * 
00024  * You should have received a copy of the GNU General Public License along 
00025  * with this program; if not, write to the Free Software Foundation, Inc., 
00026  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
00027  * 
00028  * $Revision: 1868 $
00029  * $Date: 2006-05-15 12:21:47 -0700 (Mon, 15 May 2006) $
00030  * $Author: dbrown $
00031  * $Id: list_1d.cpp 1868 2006-05-15 19:21:47Z dbrown $
00032  * 
00033  * ******** fete: From ENDF To ENDL *********
00034  */
00035 
00036 // implementation of the one_d_list class
00037 
00038 #include "list_1d.hpp"
00039 #include "math_util.hpp"
00040 #include "global_params.hpp"
00041 #include "record_types.hpp"   // used in read_data
00042 #include "messaging.hpp"
00043 #include "endl_precision.hpp"
00044 #include "endl_formats.hpp"
00045 
00046 extern GlobalParameterClass Global;
00047 extern ENDLClass ENDL;
00048 
00049 #define IS_ODD(n)  ((n) & 1)
00050 #define IS_EVEN(n) (!(IS_ODD(n)))
00051 #define ENDL_FIELD_WIDTH     ENDL_DATA_PRECISION+7
00052 
00053 using namespace std;
00054 
00055 // *********** dd_list::interpolation functions ******
00056 // -------------------- dd_list::interp ----------------
00057 double dd_list::interp(double E, dd_link& left_link,
00058   dd_link& right_link, int Interp_Type)
00059 {
00060 
00061   if( Interp_Type == 1 ) // histogram
00062   {
00063     return hist_interp( E, left_link, right_link );
00064   }
00065   else if( ( Interp_Type == 2 ) ||     // lin-lin
00066            ( Interp_Type == -7 ) )     // expanded to lin-lin
00067   {
00068     return linlin_interp( E, left_link, right_link );
00069   }
00070   else if( Interp_Type == 3 ) // log-lin
00071   {
00072     return loglin_interp( E, left_link, right_link );
00073   }
00074   else if( Interp_Type == 4 ) // lin-log
00075   {
00076     return linlog_interp( E, left_link, right_link );
00077   }
00078   else if( Interp_Type == 5 ) // log-log
00079   {
00080     return loglog_interp( E, left_link, right_link );
00081   }
00082   else
00083   {
00084     Unimplemented("dd_list::interp",
00085         pastenum("Implement dd_list::interp 1 for Interp_Type: ",Interp_Type));
00086   }
00087   return -1; // should not get here
00088 }
00089 // -------------------- dd_list::hist_interp ----------------
00090 double dd_list::hist_interp( double E, dd_link& left_link,
00091     dd_link& right_link )
00092 // perform histogram interpolation
00093 {
00094   // check for improper input
00095   if( (E < left_link.x) || (E > right_link.x) ||
00096        (right_link.x < left_link.x) )
00097   {
00098     SevereError("dd_list::hist_interp","improper input in hist_interp 1");
00099   }
00100 
00101   return left_link.y;
00102 }
00103 // -------------------- dd_list::linlin_interp --------------
00104 double dd_list::linlin_interp( double E, dd_link& left_link,
00105     dd_link& right_link )
00106 {
00107   double E_diff = right_link.E_out() - left_link.E_out();
00108 
00109   // check for division by 0
00110   if(E_diff == 0.0)
00111   {
00112     Warning("dd_list::linlin_interp","attempted division by 0 in linlin_interp 1");
00113     return (left_link.y+right_link.y)/2.0;
00114   }
00115 
00116   double alpha = (E - left_link.E_out())/E_diff;
00117 
00118   // check for extrapolation
00119   if((alpha < 0.0) || (alpha > 1.0))
00120   {
00121     Warning("dd_list::linlin_interp",
00122         pastenum("extrapolation in linlin_interp: alpha=",alpha)
00123         +pastenum(" at E=",E));
00124   }
00125 
00126   return (alpha*right_link.y +
00127     (1.0 - alpha)*left_link.y);
00128 }
00129 // -------------------- dd_list::loglin_interp --------------
00130 double dd_list::loglin_interp( double E, dd_link& left_link,
00131     dd_link& right_link )
00132 // interpolation for y = a + b*log(x/x_0)
00133 {
00134   double x_ratio = right_link.x / left_link.x;
00135 
00136   // check for division by 0 and bad logarithm
00137   if( (x_ratio <= 0.0) || (x_ratio == 1.0) )
00138   {
00139     SevereError("dd_list::loglin_interp",
00140         pastenum("bad x_ratio in loglin_interp 1: ",x_ratio));
00141   }
00142 
00143   double b = ( right_link.y - left_link.y ) / log( x_ratio );
00144 
00145   // check for extrapolation
00146   if( ( (E > left_link.x) && (E > right_link.x) ) ||
00147       ( (E < left_link.x) && (E < right_link.x) ) )
00148   {
00149     SevereError("dd_list::loglin_interp",
00150         "extrapolation in loglin_interp 1");
00151   }
00152 
00153   return ( left_link.y + b*log( E / left_link.x ) );
00154 }
00155 // -------------------- dd_list::linlog_interp ------------------
00156 double dd_list::linlog_interp( double E, dd_link& left_link,
00157     dd_link& right_link )
00158 // interpolation for log(y) = log(y_0) + b*(x - x_0)
00159 {
00160   // check for proper inputs
00161   if( (left_link.y <= 0.0) || (right_link.y <= 0.0) ||
00162       (left_link.x == right_link.x) )
00163   {
00164     SevereError("dd_list::linlog_interp",
00165         "Bad inputs to linlog_interp 1 ");
00166   }
00167 
00168   double b = log( right_link.y / left_link.y ) /
00169     ( right_link.x - left_link.x );
00170 
00171   // check for extrapolation
00172   if( ( (E > left_link.x) && (E > right_link.x) ) ||
00173       ( (E < left_link.x) && (E < right_link.x) ) )
00174   {
00175     SevereError("dd_list::linlog_interp",
00176         "extrapolation in linlog_interp 1");
00177   }
00178 
00179   return ( left_link.y * exp( b * ( E - right_link.x ) ) );
00180 }
00181 // -------------------- dd_list::loglog_interp -------------------
00182 double dd_list::loglog_interp( double E, dd_link& left_link,
00183     dd_link& right_link )
00184 // interpolation for log(y) = log(y_0) + b*log(x/x_0)
00185 {
00186   if( (right_link.y <= 0.0) || (left_link.y <= 0.0) ||
00187       (right_link.x <= 0.0) || (left_link.x <= 0.0) ||
00188       (right_link.x == left_link.x) )
00189   {
00190     SevereError("dd_list::loglog_interp",
00191         "Bad inputs to loglog_interp 1 ");
00192   }
00193 
00194   double b = log( right_link.y / left_link.y ) /
00195     log( right_link.x / left_link.x );
00196 
00197   // check for extrapolation
00198   if( ( (E > left_link.x) && (E > right_link.x) ) ||
00199       ( (E < left_link.x) && (E < right_link.x) ) )
00200   {
00201     SevereError("dd_list::loglog_interp",
00202         "extrapolation in loglog_interp 1");
00203   }
00204 
00205   return ( left_link.y * exp( b*log( E / left_link.x ) ) );
00206 }
00207 
00208 // ***************************************************
00209 //              dd_list::zeroin function
00210 // ***************************************************
00211 double dd_list::zeroin(double (*func)(double, double), 
00212           double target,
00213           dd_link& BB, 
00214           dd_link& CC,
00215               double alpha, 
00216           double tol)
00217 // find a root of func(x, alpha) = target
00218 // between BB and CC.
00219 // Return the root with accuracy of tol + 4*EPS*|root|
00220 
00221 /* This routine is a translation from the Brent zeroin
00222  * from netlib.  The original is available by e-mail:
00223  *   e-mail: netlib@ornl.gov
00224  *   subject: send zeroin from go
00225 */
00226 {
00227   //Stash the original 1d_links
00228   dd_link B = BB;
00229   dd_link C = CC;
00230 
00231   const int MAX_ITER = 100;  // the maximum number of tries
00232 
00233   double rel_tol;     // bound on relative error
00234   double diff_cb;   // (c - b)/2
00235   double new_width; // |diff_cb|
00236 
00237   double num;    // fraction for the secant rule
00238   double denom;
00239 
00240   int num_poor = 0;  // how many poor improvements
00241 
00242   // use a reasonable tolerance
00243   double use_tol = (tol < EPS) ? EPS : tol;
00244 
00245   // the current interval
00246   double old_width = abs(C.x - B.x);
00247 
00248   // shift by the target
00249   B.y -= target;
00250   C.y -= target;
00251 
00252   // worse error
00253   double worse = (abs(B.y) < abs(C.y)) ? abs(C.y) : abs(B.y);
00254 
00255   // the oldest estimate
00256   dd_link A = C;
00257 
00258   for(int count = 0; count < MAX_ITER; ++count)
00259   {
00260     // make B be the best estimate so far
00261     if(abs(C.y) < abs(B.y))
00262     {
00263       A = B;
00264       B = C;
00265       C = A;
00266     }
00267 
00268     // how close are we?
00269     diff_cb = 0.5*(C.x - B.x);
00270     new_width = abs(diff_cb);
00271     rel_tol = use_tol*abs(B.x) + EPS;
00272     if(new_width <= rel_tol)
00273     {
00274       if(B.y*C.y > 0.0)
00275       {
00276     SevereError("dd_list::zeroin","No root found" );
00277       }
00278       else if(abs(B.y) > worse)
00279       {
00280     SevereError("dd_list::zeroin","This looks like a pole.");
00281       }
00282       else
00283       {
00284     return B.x;
00285       }
00286     }
00287 
00288     // set up the secant iteration
00289     num = (B.x - A.x)*B.y;
00290     denom = A.y - B.y;
00291 
00292     // arrange so that num >= 0
00293     if(num < 0.0)
00294     {
00295       num *= -1;
00296       denom *= -1;
00297     }
00298 
00299     // save the best so far
00300     A = B;
00301 
00302     // have we had too many poor ones?
00303     ++num_poor;
00304     if((num_poor >= 4) && (8.0*new_width < old_width))
00305     {
00306       num_poor = 0;
00307       old_width = new_width;
00308     }
00309 
00310     // which type of iteration?
00311     if(num_poor >= 4)
00312     {
00313       B.x = 0.5*(C.x + B.x);
00314     }
00315     else if(num < abs(denom)*rel_tol)
00316     {
00317       // too small a change
00318       B.x += (diff_cb > 0.0) ? rel_tol : -rel_tol;
00319     }
00320     else if(num < denom*diff_cb)
00321     {
00322       // secant rule if x between B and (C + B)/2
00323       B.x += num/denom;
00324     }
00325     else
00326     {
00327       // bisection
00328       B.x = 0.5*(C.x + B.x);
00329     }
00330 
00331     // the new function value
00332     B.y = func(B.x, alpha) - target;
00333 
00334     // did we hit it?
00335     if(B.y == 0.0)
00336     {
00337       return B.x;
00338     }
00339 
00340     // which old point do we keep?
00341     if(B.y*C.y > 0.0)
00342     {
00343       C = A;
00344     }
00345     //    cout << B.x << "  " << B.y << endl;
00346   }
00347 
00348   // if we got here, there were too many iterations
00349   Warning("dd_list::zeroin","Too many iterations in zeroin");
00350   return B.x;  //However, we MUST return something or exit()?
00351 }
00352 
00353 // *********** dd_list class ***********************
00354 // ----------- dd_list::unit_base -----------------
00355 void dd_list::unit_base( )
00356 // map the energies to 0 <= E' <= 1
00357 {
00358   dd_list::iterator link = begin( );  // the first link
00359   dd_list::iterator last_link = end( );
00360   --last_link;
00361     
00362   // save the minimum and maximum outgoing energies
00363   min_E_out = link->E_out( );  // lowest energy
00364   max_E_out = last_link->E_out( );  // highest
00365     
00366   double scale = max_E_out - min_E_out;  // energy range
00367     
00368   // loop through the list
00369   for( ; link != end( ); ++link )
00370   {
00371     // scale this link
00372     link->E_out( ) = ( link->E_out( ) - min_E_out )/scale;
00373   }
00374 }
00375 // ----------- dd_list::rescale -----------------
00376 void dd_list::rescale( )
00377 // map the energies from 0 <= E' <= 1 to  min_E_out <= E' <= max_E_out
00378 {
00379   double scale = max_E_out - min_E_out;  // energy range
00380     
00381   // loop through the list
00382   for(dd_list::iterator link = begin( ); link != end( ); ++link)
00383   {
00384     // scale this link
00385     link->E_out( ) = min_E_out + scale*link->E_out( );
00386   }
00387 }
00388 // ----------- dd_list::read_data -----------------
00389 void dd_list::read_data( ifstream& inFile, int NP, double x_factor,
00390   double y_factor )
00391 // read in the weight for this model and scale by (x_factor, y_factor)
00392 {
00393 string linebuff;
00394 string strbuff;
00395 dd_link XYdata;  // for links in our lists
00396 
00397 for( int iNP=0; iNP < NP; iNP++ ) //Loop over NP data pairs
00398   {
00399     int iP=iNP % 3;  //There are 3 pairs per line
00400     if ( iP == 0 )
00401     {
00402       getline( inFile, linebuff); //Read in new line
00403     }
00404     strbuff = linebuff.substr(iP*22, 22); //Grab the right pair
00405     read_dd(&strbuff, &XYdata.x, &XYdata.y );
00406     // convert to MeV
00407     XYdata.x *= x_factor;
00408     XYdata.y *= y_factor;
00409     insert(end(), XYdata);
00410   }
00411 }
00412 // ----------- dd_list::print -----------------
00413 void dd_list::print()
00414 // to print the list
00415 {
00416   cout.setf(ios::scientific,ios::floatfield);
00417 
00418   // loop through the list
00419   for(dd_list::iterator link = begin(); link != end();
00420     ++link)
00421   {
00422     cout << ENDL.data( link->x, link->y ) << endl;
00423   }
00424   cout << endl;
00425 }
00426 
00427 // ----------- dd_list::needs_widening ------------
00428 //! Tests if data actually needs jump widening
00429 bool dd_list::needs_widening( )
00430 {
00431   dd_list::iterator itr = begin();
00432   double last_x=itr->x;
00433   ++itr;
00434   for(; itr!=end(); ++itr)
00435   {
00436     if (itr->x >= last_x+ENDL_EPSILON(last_x)) return true;
00437   }
00438   return false;
00439 }
00440 
00441 // ----------- dd_list::widen_jumps ------------
00442 //! shift duplicate x-values in the list
00443 void dd_list::widen_jumps( double cluster_min )
00444 {
00445   // scale dE by the smoother used for histograms
00446   double local_eps, jump_width;
00447 
00448   // container to hold links to elements we need to widen
00449   dd_list::iterator cluster_start = begin();
00450   dd_list::iterator cluster_end = begin();
00451   dd_list::iterator this_link = begin();
00452   int cluster_size=1;
00453 
00454   for( ++this_link; this_link != end( ); ++this_link )
00455   {
00456     // get the local energy epsilon (smallest dE can see in output file)
00457     local_eps = ENDL_EPSILON( cluster_start->x );
00458     jump_width = ENDL_JUMP_WIDTH( cluster_start->x );
00459 
00460     // this_link is too close to the cluster_end, so add it to the cluster
00461     if( abs( this_link->x - cluster_end->x ) <= local_eps )
00462     {
00463       cluster_end = this_link;
00464       ++cluster_size;
00465     }
00466     // this_link is far from the cluster_end, so let's process the cluster
00467     else 
00468     {
00469       if ( cluster_size > 1 ) 
00470         widen_cluster( cluster_start, cluster_end, cluster_size, jump_width, cluster_min );
00471       // clear the clusters
00472       cluster_start = ++cluster_end;
00473       cluster_size  = 1;
00474     }
00475   }
00476   // process the last cluster since doesn't get processed otherwise
00477   if ( cluster_size > 1 ) 
00478     widen_cluster( cluster_start, cluster_end, cluster_size, jump_width, cluster_min );
00479 }
00480 
00481 // ----------- dd_list::widen_cluster ------------
00482 //! Utility code used by widen_jumps
00483 void dd_list::widen_cluster( dd_list::iterator cluster_start, 
00484   dd_list::iterator cluster_end, int cluster_size, double jump_width, double cluster_min )
00485 {
00486 
00487   if( ( cluster_size == 1 ) || ( cluster_start==cluster_end ) ) return;
00488   if ( cluster_size>4 ) 
00489   {
00490     Warning("dd_list::widen_cluster",pastenum("Found ",cluster_size)+
00491       pastenum(" links in a cluster, check ENDL_EPSILON and ENDL_JUMP_WIDTH values or the data is broken at x=",
00492       cluster_start->x));
00493     return;
00494   }
00495 
00496   if ( cluster_start->x <= cluster_min+jump_width )
00497   {
00498     dd_list::iterator cluster_middle = cluster_start; 
00499     for (int ijump = 1; ijump<=cluster_size; ++ijump)
00500     {
00501       ++cluster_middle; 
00502       cluster_middle->x += static_cast<double>(ijump)*jump_width;
00503     }
00504   }
00505   else
00506   {
00507     switch (cluster_size)
00508     {
00509       case 2:
00510         cluster_start->x -= 0.5*jump_width;
00511         cluster_end->x   += 0.5*jump_width;
00512         break;
00513       case 3:
00514         cluster_start->x -= jump_width;
00515         cluster_end->x   += jump_width;
00516         break;
00517       case 4:
00518         {
00519         dd_list::iterator cluster_left = cluster_start;
00520         dd_list::iterator cluster_right = cluster_end;
00521         ++cluster_left;--cluster_right;
00522         cluster_start->x -= 1.5*jump_width;
00523         cluster_left->x  -= 0.5*jump_width;
00524         cluster_right->x += 0.5*jump_width;
00525         cluster_end->x   += 1.5*jump_width;
00526         }
00527         break;
00528       default:
00529         Warning("dd_list::widen_cluster",pastenum("Found ",cluster_size)+
00530         pastenum(" links in a cluster, check ENDL_EPSILON and ENDL_JUMP_WIDTH values or the data is broken at x=",
00531         cluster_start->x)); 
00532         return;
00533     }
00534   }
00535 }
00536 
00537 // ----------- dd_list::thinit -----------------
00538 void dd_list::thinit()
00539 // thin the list to within tolerance: tol
00540 {
00541   // declare pointers to the test links
00542   dd_list::iterator left_link;
00543   dd_list::iterator mid_link;
00544   dd_list::iterator right_link;
00545   dd_list::iterator all_done;
00546   bool thin_ok;  // for test on 1 link
00547   bool do_thin;  // thin OK at this level
00548   bool prev_thin;  // thin OK at the previous level
00549   const double cut_off = Global.Value("cut_off_1d"); // don't impose accuracy below this value
00550   const double tol_1d = Global.Value("tol_1d");  // accuracy of linear interpolation
00551 
00552   //  quit at the last valid link
00553   all_done = end();
00554   --all_done;
00555 
00556   // set the noise level
00557   double noise = 0.0;
00558   // don't use it for delta functions
00559   if( ( ENDL.F != 12 ) || ( ENDL.F != 13 ) )
00560   {
00561     for(left_link = begin(); left_link != all_done; ++left_link)
00562     {
00563       if(abs(left_link->y) > noise)
00564       {
00565         noise = abs(left_link->y);
00566       }
00567     }
00568     noise *= cut_off;
00569   }
00570 
00571   // loop through the list of left-hand anchors
00572   for(left_link = begin(); left_link != all_done; ++left_link)
00573   {
00574     // make sure that we have data to check
00575     mid_link = left_link;
00576     ++mid_link;
00577     right_link = mid_link;
00578     ++right_link;
00579     if((mid_link == end()) || (right_link == end()))
00580     {
00581       return;  // no more data
00582     }
00583 
00584     // the default is no thinning
00585     prev_thin = false;
00586 
00587     // how long a span may we delete?
00588     for( ; right_link != end(); ++right_link)
00589     {
00590       // the default is don't delete links at this level
00591       do_thin = false;
00592 
00593       // check all of the intermediate links
00594       mid_link = left_link;
00595       for(++mid_link; mid_link != right_link; ++mid_link)
00596       {
00597         thin_ok = check_interp(left_link, mid_link, right_link,
00598           tol_1d, noise);
00599         if(thin_ok)
00600         {
00601           // at least one deletion is possible
00602           do_thin = true;
00603         }
00604         else
00605         {
00606           // this section fails
00607           do_thin = false;
00608           break;
00609         }
00610       }
00611 
00612       // did they all pass?
00613       if(do_thin)
00614       {
00615         prev_thin = true;
00616       }
00617       else
00618       {
00619         break;
00620       }
00621     }
00622 
00623     dd_list::iterator left_next = left_link;
00624     ++left_next;
00625     dd_list::iterator right_prev = right_link;
00626     --right_prev;
00627 
00628     if((prev_thin) && (!do_thin))
00629     {
00630       // deletion is not allowed here but it is OK at the previous level
00631       erase(left_next, right_prev);
00632     }
00633     else if((do_thin) && (right_link == end()) &&
00634       (mid_link == all_done))
00635     {
00636       // we are at the end and all links passed
00637       erase(left_next, mid_link);
00638     }
00639   }
00640 }
00641 // -------------------- dd_list::copy ----------------
00642 void dd_list::copy( dd_list& list_2 )
00643 // Copy one list into another
00644 {
00645   // loop through list_2
00646   for( dd_list::iterator link_ptr = list_2.begin();
00647     link_ptr != list_2.end(); ++link_ptr )
00648   {
00649     dd_link new_link = dd_link( link_ptr->x, link_ptr->y );
00650     insert( end(), new_link );
00651   }
00652   tag = list_2.tag;
00653 }
00654 // ----------- dd_list::chop ------------
00655 void dd_list::chop( double max_E )
00656 // Cuts off links with x-value exceeding max_E
00657 {
00658   dd_list::iterator list_ptr = begin( );
00659   double dE = ENDL_EPSILON( max_E );
00660 
00661   // Make sure list starts below max_E
00662   if( begin( )->x  > max_E )
00663   {
00664     SevereError( "dd_list::chop", "all energies too big" );
00665   }
00666 
00667   // Find the first link with incident energy too big
00668   for( ; list_ptr != end( ); ++list_ptr )
00669   {
00670     if( list_ptr->x >= max_E + dE )
00671     {
00672       break;
00673     }
00674   }
00675   
00676   // Move the last link to max_E, then erase all the links above it
00677   if( list_ptr != end( ) )
00678   {
00679     list_ptr->y = evaluate(max_E);
00680     list_ptr->x = max_E; 
00681     ++list_ptr;
00682     if( list_ptr != end( ) ) erase( list_ptr, end( ) );
00683   }
00684   
00685 }
00686 // ------------------------- write_endl -----------------
00687 //! ENDL file writing function
00688 void dd_list::write_endl( int I )
00689 {
00690   if( !ENDL.write_file ) return;
00691 
00692   // chop off the energies that we don't use
00693   // for 2-column data the first entry is the incident energy
00694   chop( ENDL.Max_E_in );
00695 
00696   ENDL.set_I_number(I);
00697 
00698   fstream endl_file;
00699   string file_name = ENDL.file_name;
00700 
00701   if(empty())
00702   {
00703     Warning("dd_list::write_endl","The file "+file_name+" is empty.");
00704     return;
00705   }
00706 
00707   if ( ENDL.new_file() )
00708   {
00709     endl_file.open(file_name.c_str(),ios::out);
00710     Info("dd_list::write_endl","Opening ENDL file "+file_name);
00711   }
00712   else
00713   {
00714     endl_file.open(file_name.c_str(),ios::out|ios::app);
00715     Info("dd_list::write_endl","Appending ENDL file "+file_name);
00716   }
00717 
00718   //Write out the header information
00719   endl_file<<ENDL.header_line_1<<"\n";
00720   endl_file<<ENDL.header_line_2<<"\n";
00721   endl_file.setf(ios::scientific,ios::floatfield);
00722   
00723 
00724   // check for & fix double value of x, except for cross sections
00725   double old_x = -2.0;
00726   bool list_needs_widening=false;
00727   for(dd_list::iterator link = begin(); link != end(); ++link)
00728   {
00729     if( (link->x == old_x) && (ENDL.F != 3) )
00730     {
00731       Warning("dd_list::write_endl",
00732         pastenum("Widening the jump in dd_list at: ",old_x)+
00733         pastenum(" x: " ,old_x));
00734       list_needs_widening=true;
00735     }
00736     old_x = link->x;
00737   }
00738   if (list_needs_widening) widen_jumps();
00739 
00740   //Loop through the data and write to file
00741   for(dd_list::iterator link = begin(); link != end(); ++link)
00742   {
00743     endl_file<<ENDL.data( link->x, link->y )<<endl;
00744   }
00745 
00746   //Put on end of file/section line into output file
00747   endl_file<<ENDL.eof_line<<endl;
00748   
00749   //Finally, we close the output file
00750   Info("dd_list::write_endl","Closing ENDL file "+file_name);
00751   endl_file.close();
00752 }
00753 
00754 // ----------- dd_list::operator+= ------------
00755 dd_list& dd_list::operator+=(dd_list& list_2)
00756 {
00757   // ensure that the x-values are identical
00758   fill_in_lists( *this, list_2 );
00759 
00760   // now go through the lists
00761   dd_list::iterator L1 = begin();
00762   dd_list::iterator L2 = list_2.begin();
00763   for( ; L1 != end(); ++L1, ++L2 )
00764   {
00765     L1->y += L2->y;
00766   }
00767 
00768   return *this;
00769 }
00770 
00771 // ----------- dd_list::line_sum ------------
00772 dd_list& dd_list::line_sum( dd_list& list_2, double tol )
00773 {
00774   dd_link new_link;  // for creating new links
00775   dd_list::iterator L1 = begin();
00776   dd_list::iterator L2 = list_2.begin();
00777   double E1 = L1->x;
00778   double E2 = L2->x;
00779   bool L1_done = empty( );  // have we finished the first list?
00780 
00781   // go through the lists
00782   for( ; L2 != list_2.end( ); )
00783   {
00784     if( L1_done || ( E2 < ( 1.0 - tol )*E1 ) )
00785     {
00786       new_link.x = E2;
00787       new_link.y = L2->y;
00788       insert( L1, new_link);
00789       ++L2;
00790       E2 = L2->x;
00791     }
00792     else if( !L1_done )
00793     {
00794       if( E1 < ( 1.0 - tol )*E2 )
00795       {
00796         ++L1;
00797         E1 = L1->x;
00798       }
00799       else   //  E1 == E2
00800       {
00801         L1->y += L2->y;
00802         ++L1;
00803         ++L2;
00804         E1 = L1->x;
00805         E2 = L2->x;
00806       }
00807       if( L1 == end( ) )
00808       {
00809         L1_done = true;
00810       }
00811     }
00812   }
00813 
00814   return *this;
00815 }
00816 
00817 // ----------- dd_list::join_lines ------------
00818 //! If two adjacent lines have the same frequency, this routine adds
00819 //! their intensities.
00820 void dd_list::join_lines( )
00821 {
00822   if( size( ) < 2 ){
00823     return;
00824   }
00825   dd_list::iterator this_ptr = begin();
00826   dd_list::iterator next_ptr = this_ptr;
00827   ++next_ptr;
00828   for(  ; this_ptr != end( ); this_ptr = next_ptr, ++next_ptr )
00829   {
00830     if( this_ptr->x == next_ptr->x )
00831     {
00832       next_ptr->y += this_ptr->y;
00833       erase( this_ptr );
00834     }
00835   }
00836 }
00837 
00838 // ----------- dd_list::operator*= ------------
00839 dd_list& dd_list::operator*=(double X)
00840 {
00841   for(dd_list::iterator L1 = begin(); L1 != end(); ++L1 )
00842   {
00843     L1->y *= X;
00844   }
00845   return *this;
00846 }
00847 
00848 // ----------- dd_list::operator*= ------------
00849 dd_list& dd_list::operator*=(dd_list& list_2)
00850 {
00851   for( dd_list::iterator itr = begin() ; itr != end(); ++itr )
00852   {
00853     itr->y *= list_2.evaluate( itr->x );
00854   }
00855 
00856   return *this;
00857 }
00858 
00859 // ----------- dd_list::operator/= ------------
00860 dd_list& dd_list::operator/=(dd_list& list_2)
00861 {
00862   double y;
00863   for( dd_list::iterator itr = begin() ; itr != end(); ++itr )
00864   {
00865     y = list_2.evaluate( itr->x ); 
00866     if ( y == 0.0 ) 
00867     {
00868       if ( itr->y != 0.0 )
00869         Warning("dd_list::operator/=","division by 0 in operator /=");
00870       itr->y = 0;
00871     }
00872     else
00873     {
00874       itr->y /= y;
00875     }
00876   }
00877 
00878   return *this;
00879 }
00880 
00881 // ----------- dd_list::find_next -----------------
00882 //! Find the link with the next larger x-value
00883 dd_list::iterator dd_list::find_next( double X )
00884 {
00885   if( empty( ) )
00886   {
00887     return end( );
00888   }
00889 
00890   dd_list::iterator next_link;
00891   for( next_link = begin( ); next_link != end( ); ++next_link )
00892   {
00893     if( next_link->x >= X )
00894     {
00895       return next_link;
00896     }
00897   }
00898 
00899   // we didn't find it
00900   return end( );
00901 }
00902 
00903 // ----------- dd_list::evaluate -----------------
00904 //! Find the y-value corresponding to this x using lin-lin interpolation
00905 double dd_list::evaluate( double X )
00906 {
00907   if( empty( ) )
00908   {
00909     SevereError("dd_list::evaluate",
00910         "Attempt to use evaluate on an empty list");
00911   }
00912 
00913   // find the first bigger gamma energy
00914   dd_list::iterator next_link = find_next( X );
00915 
00916   if( ( next_link == begin( ) ) && ( next_link->x != X ) )
00917   {
00918     Warning("dd_list::evaluate",
00919         pastenum("Attempt to evaluate below the first link, x=",X));
00920     return next_link->y;
00921   }
00922   else if( next_link == end( ) )
00923   {
00924     Warning("dd_list::evaluate",
00925         pastenum("Attempt to evaluate past the last link, x=",X));
00926     return (--next_link)->y;
00927   }
00928 
00929   if (next_link->x == X)
00930   {
00931     return next_link->y;
00932   }
00933   else
00934   {
00935     dd_list::iterator prev_link = next_link;
00936     --prev_link;
00937     return linlin_interp( X, *prev_link, *next_link );
00938   }
00939 }
00940 
00941 // ----------- dd_list::check_interp -----------------
00942 //! check the accuracy of linear interpolation
00943 //! Ignore values below the noise.
00944 bool dd_list::check_interp(dd_list::iterator left_link,
00945     dd_list::iterator mid_link,
00946     dd_list::iterator right_link, double tol, double noise)
00947 {
00948   // the interpolated probability
00949   double P_interp = linlin_interp( mid_link->E_out(), *left_link, 
00950     *right_link );
00951 
00952   return ( ( abs(P_interp - mid_link->y) < tol*mid_link->y ) ||
00953            ( ( abs(left_link->y) <= noise ) &&
00954              ( abs(mid_link->y) <= noise ) &&
00955              ( abs(right_link->y) <= noise ) ) );
00956 }
00957 
00958 // ----------- dd_list::expand_interp -----------------
00959 //! Expand the list to permit linear-linear interpolation
00960 void dd_list::expand_interp( double Max_E )
00961 {
00962   if(INT[0] == -7)
00963   {
00964     //    SevereError("dd_list::expand_interp","expand_interp called twice");
00965     return;
00966   }
00967 
00968   dd_list::iterator left_link = begin();
00969 
00970   for(int count = 1; count <= NBT.size(); ++count)
00971   {
00972     // pointer to the end of this segment
00973     dd_list::iterator right_link;
00974     if(count == NBT.size())
00975     {
00976       right_link = end();
00977       --right_link;
00978     }
00979     else
00980     {
00981       int j = NBT[count] - NBT[count-1];
00982 
00983       // get the corresponding link
00984       right_link = left_link;
00985       for(int k = 0; k < j; ++k)
00986       {
00987         ++right_link;
00988       }
00989     }
00990     // convert to lin-lin
00991     switch(INT[count-1])
00992     {
00993     case 1: // histogram
00994       Hist_2_LinLin(left_link, right_link, Max_E);
00995       break;
00996     case 2: // lin-lin
00997       break;
00998     case 5: // log-log
00999       LogLog_2_LinLin(left_link, right_link);
01000       break;
01001     default:
01002       Unimplemented("dd_list::expand_interp",
01003         pastenum("Implement interpolation model ",INT[count-1]));
01004     }
01005     // save for the next set
01006     left_link = right_link;
01007   }
01008   // flag to ensure that we don't do this twice on the same data
01009   INT[0] = -7;
01010 } 
01011 
01012 // ----------- dd_list::expand_interp -----------------
01013 //! This version is used for gammas, in which LEP is the interpolation type
01014 //! for use with the gamma energy
01015 void dd_list::expand_interp( int LEP, double Max_E )
01016 {
01017   if ( LEP == 2 ) // lin-lin
01018   {
01019   }
01020   else if ( LEP == 1 ) // histogram
01021   {
01022     dd_list::iterator data_ptr = begin( );
01023 
01024     // We could be finished already
01025     if( data_ptr == end( ) )
01026     {
01027       return;
01028     }
01029 
01030     // loop through the list
01031     dd_list::iterator prev_ptr = data_ptr;
01032     ++data_ptr;
01033     dd_list::iterator next_ptr = data_ptr;
01034     ++next_ptr;
01035     for(  ; data_ptr != end( );
01036         prev_ptr = data_ptr, data_ptr = next_ptr, ++next_ptr )
01037     {
01038       if( prev_ptr->y != data_ptr->y )
01039       {
01040         // how wide the jump
01041         double dE_L = data_ptr->x - prev_ptr->x;
01042         double dE_R = ( next_ptr == end( ) ) ? data_ptr->x :
01043           next_ptr->x - data_ptr->x;
01044         double dE = ( dE_L < dE_R ) ? dE_L : dE_R;
01045 
01046         if(dE <= 0.0)
01047         {
01048           SevereError("dd_list::expand_interp","bad histogram data");
01049         }
01050 
01051         // set smoothing dE to be smallest dE we can see in output file
01052         dE = ENDL_EPSILON( data_ptr->x );
01053 
01054         if( data_ptr->x < Max_E - dE )
01055         {
01056           dd_link new_link;
01057           insert( data_ptr, new_link );
01058           dd_list::iterator new_ptr = data_ptr;
01059           --new_ptr;  //  points to the new link
01060 
01061           new_ptr->x = data_ptr->x - dE;
01062           data_ptr->x += dE;
01063           new_ptr->y = prev_ptr->y;
01064         }
01065         else
01066         {
01067           data_ptr->x = Max_E;
01068           data_ptr->y = prev_ptr->y;
01069           erase( next_ptr, end( ) );
01070           break;
01071         }
01072       }
01073     }
01074   }
01075   else
01076   {
01077     Unimplemented("dd_list::expand_interp( int LEP, double Max_E )",
01078         pastenum("Implement interpolation type: ",LEP));
01079   }
01080 } 
01081 
01082 // ----------- dd_list::Hist_2_LinLin -----------------
01083 //! Expand histogram data to linear-linear between the two consecutive links.
01084 //! If we need a jump, insert a new link
01085 void dd_list::Hist_2_LinLin( dd_list::iterator left_link, double Max_E )
01086 {
01087   if ( left_link == end() ) SevereError( "dd_list::Hist_2_LinLin",
01088     "Trying to expand links, but starting link == end()!");
01089 
01090   dd_link new_link;  // for making new links
01091 
01092   dd_list::iterator jump_link = left_link;
01093   ++jump_link;
01094 
01095   // special treatment of the end of the list
01096   if( jump_link == end( ) )
01097   {
01098     if(left_link->x < Max_E)
01099     {
01100       // add a final link
01101       new_link.x = Max_E;
01102       new_link.y = left_link->y;
01103       insert( jump_link, new_link );
01104     }
01105   }
01106   else
01107   {
01108     // is there a jump?
01109     if( jump_link->y != left_link->y )
01110     {
01111       // make a new link
01112       dd_list::iterator right_link;
01113       right_link = jump_link;
01114       ++right_link;
01115       double dE_L = jump_link->x - left_link->x;
01116       double dE_R = ( right_link == end( ) ) ? jump_link->x :
01117         right_link->x - jump_link->x;
01118       double dE = ( dE_L < dE_R ) ? dE_L : dE_R;
01119 
01120       // set width of jump to be smallest dE we can see in output file
01121       double dEmin = ENDL_EPSILON( jump_link->x );
01122 
01123       if( dE < 0.0 )
01124       {
01125         SevereError("dd_list::Hist_2_LinLin","energies out of order");
01126       }
01127 
01128       // the original x-values may be too close to see in the output file
01129       if( dE_R <= dEmin )
01130       {
01131         jump_link->x = right_link->x - dEmin;
01132         jump_link->y = left_link->y;
01133       }
01134       else if( dE > dEmin )
01135       {
01136         // add a link
01137         new_link.x = jump_link->x - dEmin;
01138         new_link.y = left_link->y;
01139         insert( jump_link, new_link );
01140         jump_link->x += dEmin;
01141       }
01142     }
01143   }
01144 }
01145 
01146 // ----------- dd_list::Hist_2_LinLin -----------------
01147 //! Expand histogram data to linear-linear between the two links
01148 //! first_link and last_link.
01149 void dd_list::Hist_2_LinLin( dd_list::iterator first_link,
01150   dd_list::iterator last_link, double Max_E )
01151 {
01152   dd_list::iterator next_link = first_link;
01153   ++next_link;
01154   for ( dd_list::iterator this_link = first_link; this_link != last_link;
01155     this_link = next_link, ++next_link )
01156   {
01157     if( this_link == end( ) )
01158     {
01159       SevereError("dd_list::Hist_2_LinLin","bad link");
01160     }
01161     Hist_2_LinLin( this_link, Max_E );
01162   }
01163 }
01164 
01165 // ----------- dd_list::LogLog_2_LinLin -----------------
01166 //! Expand the log-log data to linear-linear between the two 
01167 //! consecutive links.
01168 void dd_list::LogLog_2_LinLin(dd_list::iterator left_link)
01169 {
01170   double tol = Global.Value("log_log_tol");
01171 
01172   dd_list::iterator right_link = left_link;
01173   ++right_link;
01174   int num_add; // the number of intermediate links to add
01175 
01176   // Make sure that x values are positive
01177   if ( left_link->x <= 0.0 || right_link->x <= 0.0 )
01178   {
01179     SevereError("dd_list::LogLog_2_LinLin","x must be larger than zero!");
01180   }
01181   // Make sure that y values are positive
01182   if ( left_link->y <= 0.0 || right_link->y <= 0.0 )
01183   {
01184     SevereError("dd_list::LogLog_2_LinLin","y must be larger than zero!");
01185   }
01186   // Make sure these links are ordered
01187   if ( left_link->x > right_link->x )
01188   {
01189     SevereError("dd_list::LogLog_2_LinLin","x values not ascending!");
01190   }
01191 
01192   // Calculate slope of loglog
01193   double alpha = log(right_link->y/left_link->y)/
01194     log(right_link->x/left_link->x); 
01195 
01196   // we may not need to add intermediate links
01197   double xi = right_link->x/left_link->x;
01198   double maxE = maxE_loglog( xi, alpha );
01199   if(maxE <= tol)
01200   {
01201     num_add = 0;
01202   }
01203   else
01204   {
01205     // dummy links for zeroin
01206     dd_link low_link = dd_link(1.0, 0.0);  // low estimate for xi
01207     dd_link high_link = dd_link(xi, maxE); // high estimate for xi
01208 
01209     // A Taylor series often gives a better estimate
01210     double delta = sqrt(8.0*tol/abs(alpha*(alpha - 1.0)));
01211     if(1.0 + delta < xi)
01212     {
01213       maxE = maxE_loglog( 1.0 + delta, alpha );
01214       if(maxE < tol)
01215       {
01216       // this is a lower bound
01217         low_link.x = 1.0 + delta;
01218         low_link.y = maxE;
01219       }
01220       else
01221       {
01222         // this is an upper bound
01223         high_link.x = 1.0 + delta;
01224         high_link.y = maxE;
01225       }
01226     }
01227     // get the ideal interval
01228     xi = zeroin(&maxE_loglog, tol, low_link, high_link, alpha, 0.00001);
01229 
01230     num_add = static_cast<int>
01231       (floor(log(right_link->x/left_link->x)/log(xi)));
01232 
01233     // add the intermediate links
01234     double eta = pow(right_link->x/left_link->x, 1.0/(num_add + 1.0));
01235     double eta_alpha = pow(eta, alpha);
01236     double x = left_link->x;
01237     double y = left_link->y;
01238     for(int count = 0; count < num_add; ++count)
01239     {
01240       x *= eta;
01241       y *= eta_alpha;
01242       dd_link link;
01243       link.x = x;
01244       link.y = y;
01245       insert(right_link, link);
01246     }
01247   }
01248 }
01249 
01250 // ----------- dd_list::LogLog_2_LinLin -----------------
01251 //! Expand the log-log data to linear-linear between the two links
01252 //! first_link and last_link.
01253 void dd_list::LogLog_2_LinLin(dd_list::iterator first_link,
01254   dd_list::iterator last_link)
01255 {
01256   dd_list::iterator next_link = first_link;
01257   ++next_link;
01258   for (dd_list::iterator this_link = first_link; this_link != last_link;
01259     this_link = next_link, ++next_link)
01260   {
01261     if((this_link == 0) || (this_link == end()))
01262     {
01263       SevereError("dd_list::LogLog_2_LinLin"," bad link");
01264     }
01265     LogLog_2_LinLin(this_link);
01266   }
01267 }
01268 
01269 // ---------------- fill_in_lists -------------------------
01270 //! This routine fills in to ensure that the x-values in list_1 and
01271 //! list_2 are the same.
01272 void fill_in_lists( dd_list& list_1, dd_list& list_2 )
01273 {
01274   if( list_1.empty( ) || list_2.empty( ) )
01275   {
01276     cout << "list_1\n";
01277     list_1.print( );
01278     cout << "list_2\n";
01279     list_2.print( );
01280     SevereError("fill_in_lists","attempt to fill in an empty 1d list");
01281   }
01282 
01283   // widen any jumps
01284   list_1.widen_jumps( );
01285   list_2.widen_jumps( );
01286 
01287   // pad the start with zeros if necessary
01288   dd_list::iterator L1 = list_1.begin( );
01289   dd_list::iterator L2 = list_2.begin( );
01290 
01291   double E1 = L1->x;
01292   double E2 = L2->x;
01293 
01294   if( E1 < E2 )
01295   {
01296     list_2.pad_head( E1 );
01297   }
01298   else if( E2 < E1 )
01299   {
01300     list_1.pad_head( E2 );
01301   }
01302 
01303   // pad the tail with zeros if necessary
01304   L1 = list_1.end( );
01305   L2 = list_2.end( );
01306   --L1;
01307   --L2;
01308 
01309   E1 = L1->x;
01310   E2 = L2->x;
01311 
01312   if( E1 > E2 )
01313   {
01314     list_2.pad_tail( E1 );
01315   }
01316   else if( E2 > E1 )
01317   {
01318     list_1.pad_tail( E2 );
01319   }
01320 
01321   // make a list of the common E_in values
01322   list< double > E_in_list;
01323   list_1.collect_E_in( E_in_list );
01324   list_2.collect_E_in( E_in_list );
01325 
01326   // sort the list
01327   E_in_list.sort( );
01328 
01329   // remove duplicates
01330   E_in_list.unique( );
01331   list_1.unique( );
01332   list_2.unique( );
01333 
01334   // fill each list with values from E_in_list
01335   list_1.fill_with( E_in_list );
01336   list_2.fill_with( E_in_list );
01337 }
01338 
01339 // ----------- dd_list::collect_E_in ------------
01340 //! Append to E_in_list the incident energies in this list
01341 void dd_list::collect_E_in( list< double >& E_in_list )
01342 {
01343   for( dd_list::iterator this_E = begin( ); this_E != end( );
01344        ++this_E )
01345   {
01346     double E_in = this_E->E_in( );
01347     E_in_list.push_back( E_in );
01348   }
01349 }
01350 
01351 // ----------- dd_list::pad_head ------------
01352 //! insert zero links from E0 to the head
01353 void dd_list::pad_head( double E0 )
01354 {
01355   dd_link new_link;  // for creating new links
01356 
01357   double first_E = begin( )->x;
01358   // smallest dE can see in output file
01359   double dE = ENDL_EPSILON( first_E );
01360 
01361   // insert a jump if needed
01362   new_link.y = 0.0;
01363   if( ( begin( )->y != 0.0 ) && ( first_E - E0 > dE ) )
01364   {
01365     new_link.x = first_E - dE;
01366     push_front( new_link );
01367   }
01368 
01369   // insert a new head
01370   new_link.x = E0;
01371   push_front( new_link );
01372 }
01373 
01374 // ----------- dd_list::pad_tail ------------
01375 //! insert zero links from the tail to E0
01376 void dd_list::pad_tail( double E0 )
01377 {
01378   dd_link new_link;  // for creating new links
01379   dd_list::iterator L = end( );
01380   --L;
01381   double last_E = L->x;
01382   // smallest dE can see in output file
01383   double dE = ENDL_EPSILON( last_E );
01384 
01385   // insert a jump if needed
01386   new_link.y = 0.0;
01387   if( ( L->y != 0.0 ) && ( E0 - last_E > dE ) )
01388   {
01389     new_link.x = last_E + dE;
01390     push_back( new_link );
01391   }
01392 
01393   // insert a new tail
01394   new_link.x = E0;
01395   push_back( new_link );
01396 }
01397 
01398 // ----------- dd_list::unique ------------
01399 //! remove duplicate energies, overrides list<>::unique()
01400 void dd_list::unique( )
01401 {
01402   dd_list::iterator this_link = begin( );
01403   dd_list::iterator prev_link = this_link;
01404   double local_epsilon;
01405 
01406   for( ++this_link; this_link != end( );
01407        prev_link = this_link, ++this_link )
01408   {
01409     if( abs(this_link->x - prev_link->x) == local_epsilon )
01410     {
01411       this_link->y = (this_link->y + prev_link->y)/2.0;
01412       erase( prev_link );
01413     }
01414   }
01415 }
01416 
01417 // ----------- dd_list::fill_with ------------
01418 //! make sure that there are links for each energy in E_in_list
01419 void dd_list::fill_with( list< double >& E_in_list )
01420 {
01421   dd_list::iterator this_link = begin( );
01422   dd_list::iterator prev_link = this_link;
01423 
01424   // go through the E_in_list
01425   for( list< double >::iterator E_in_ptr = E_in_list.begin( ); 
01426        E_in_ptr != E_in_list.end( ); ++E_in_ptr )
01427   {
01428     double E_in = *E_in_ptr;
01429 
01430     // if there is a node here, just go on to the next
01431     if( this_link->x == E_in )
01432     {
01433       prev_link = this_link;
01434       ++this_link;
01435     }
01436     else
01437     {
01438       // interpolate and make a new link
01439       dd_link new_link;  // for creating new links
01440       new_link.x = E_in;
01441       new_link.y = linlin_interp( E_in, *prev_link, *this_link );
01442       insert( this_link, new_link );
01443     }
01444   }
01445 }

Generated on Thu Sep 7 10:30:05 2006 for fete -- From ENDFB6 To ENDL by doxygen 1.3.4