00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "distrib_base.hpp"
00039 #include "messaging.hpp"
00040 #include "endl_formats.hpp"
00041 #include "endl_precision.hpp"
00042
00043 extern ENDLClass ENDL;
00044
00045
00046
00047
00048 void distrib_base::print()
00049 {
00050 cout.setf(ios::scientific,ios::floatfield);
00051
00052 cout << "E_in: " << ENDL.data( E_in() ) << endl;
00053 cout << "weight: " << weight << endl;
00054 dd_list::print();
00055 }
00056
00057
00058 void distrib_base::thicken( )
00059 {
00060
00061 dd_list::iterator last = end();
00062 --last;
00063 thicken( begin(), last );
00064 }
00065
00066
00067
00068
00069 void distrib_base::thicken( dd_list::iterator first,
00070 dd_list::iterator last )
00071 {
00072 int Max_List_Size = static_cast<int>( Global.Value("max_list_size") );
00073 double abs_tol;
00074 double biggest = 0.0;
00075
00076
00077 dd_list::iterator this_link;
00078 for(this_link = first; this_link != last; ++this_link)
00079 {
00080 if(abs(this_link->y) > biggest)
00081 {
00082 biggest = abs(this_link->y);
00083 }
00084 }
00085
00086 if( biggest == 0.0 )
00087 {
00088 return;
00089 }
00090 abs_tol = cut_off*biggest;
00091
00092 double E_mid;
00093 double p_mid;
00094 double true_p;
00095
00096 dd_link new_link;
00097
00098
00099
00100
00101
00102
00103 for(this_link = first; this_link != last; ++this_link)
00104 {
00105 dd_list::iterator next_link = this_link;
00106 ++next_link;
00107
00108 for(;;)
00109 {
00110
00111 double local_eps = ENDL_EPSILON( this_link->E_out() );
00112 if( next_link->E_out() - this_link->E_out() < local_eps )
00113 {
00114 break;
00115 }
00116
00117
00118 E_mid = 0.5*(this_link->E_out() + next_link->E_out());
00119
00120
00121 dd_link test_link(this_link->x, this_link->y);
00122 p_mid = linlin_interp(E_mid, test_link, *next_link);
00123
00124 true_p = f(E_mid);
00125
00126
00127 if(abs(p_mid - true_p) < tol_1d*abs(true_p) ||
00128 abs(p_mid - true_p) < abs_tol )
00129 {
00130 break;
00131 }
00132 else
00133 {
00134
00135 new_link = dd_link(E_mid, true_p);
00136 insert(next_link, new_link);
00137 --next_link;
00138 }
00139
00140 if( size() >= Max_List_Size )
00141 {
00142 print();
00143 SevereError("distrib_base::thicken",pastenum("got ",
00144 Max_List_Size)+" links in 1-d thicken routine");
00145 }
00146 }
00147 }
00148 }
00149
00150
00151
00152
00153 double distrib_base::get_norm()
00154 {
00155 dd_list::iterator link = begin();
00156
00157 double norm = 0.0;
00158 double last_E = link->E_out();
00159 double last_P = link->y;
00160 double next_E;
00161 double next_P;
00162
00163
00164 if (empty())
00165 {
00166 Warning("distrib_base::get_norm",
00167 "Can't get norm with no elements in distrib_base!");
00168 return 0.0;
00169 }
00170
00171
00172 if (size()==1)
00173 {
00174 Warning("distrib_base::get_norm", "Only one element in distrib_base!");
00175 return link->y;
00176 }
00177
00178
00179 for(++link; link != end(); ++link)
00180 {
00181
00182 next_E = link->E_out();
00183 next_P = link->y;
00184
00185
00186 norm += 0.5*(next_P + last_P)*(next_E - last_E);
00187
00188
00189 last_E = next_E;
00190 last_P = next_P;
00191 }
00192
00193 return norm;
00194 }
00195
00196
00197
00198 void distrib_base::renorm()
00199 {
00200 double norm = get_norm();
00201 dd_list::iterator link = begin();
00202
00203
00204 if(norm == 0.0)
00205 {
00206 Warning("distrib_base::renorm",pastenum("Zero norm in renorm routine for E_in: ",E_in( )));
00207
00208 link->y = 1.0;
00209 max_P = 1.0;
00210 }
00211 else
00212 {
00213
00214 max_P = 0.0;
00215 for( ; link != end(); ++link)
00216 {
00217 link->y /= norm;
00218 if( link->y > max_P )
00219 {
00220 max_P = link->y;
00221 }
00222 }
00223 }
00224 }
00225
00226
00227
00228 void distrib_base::renorm(double Norm)
00229 {
00230
00231 if(Norm == 0.0)
00232 {
00233 SevereError("distrib_base::renorm(double Norm)","Zero norm in renorm(double Norm) routine");
00234 }
00235
00236 *this *= 1.0/Norm;
00237 }
00238
00239
00240
00241 void distrib_base::get_bins()
00242 {
00243
00244 double Norm = get_norm( );
00245 if( Norm <= 0.0 )
00246 {
00247 print( );
00248 SevereError("distrib_base::get_bins","zero norm");
00249 }
00250 double d_prob = Norm/num_bins;
00251 double cum_prob = 0.0;
00252
00253 double prev_x = begin()->x;
00254 double prev_y = begin()->y;
00255 equi_prob.push_back( prev_x );
00256
00257 dd_list::iterator link = begin();
00258 ++link;
00259 double next_x = link->x;
00260 double next_y = link->y;
00261
00262
00263 for(int j = 1; j < num_bins; ++j)
00264 {
00265 double target = j*d_prob;
00266 double trapezoid = 0.5*(next_y + prev_y)*(next_x - prev_x);
00267 while(cum_prob + trapezoid < target)
00268 {
00269 cum_prob += trapezoid;
00270 prev_x = next_x;
00271 prev_y = next_y;
00272 ++link;
00273 if(link == end())
00274 {
00275 SevereError("distrib_base::get_bins","failure in get_bins");
00276 }
00277 next_x = link->x;
00278 next_y = link->y;
00279 trapezoid = 0.5*(next_y + prev_y)*(next_x - prev_x);
00280 }
00281
00282
00283
00284
00285
00286 double slope = (next_y - prev_y)/(next_x - prev_x);
00287 equi_prob.push_back( prev_x + 2*( target - cum_prob )/
00288 ( prev_y + sqrt( prev_y*prev_y + 2*slope*( target - cum_prob ) ) ) );
00289 }
00290
00291 link = end();
00292 --link;
00293 equi_prob.push_back( link->x );
00294 }
00295
00296
00297
00298
00299
00300 void distrib_base::mirror()
00301 {
00302
00303 reverse();
00304
00305
00306 for(dd_list::iterator link = begin(); link != end(); ++link)
00307 {
00308 link->mu() *=-1.0;
00309 }
00310 }
00311
00312
00313
00314 void distrib_base::widen_delta( )
00315 {
00316 dd_list::iterator next_link;
00317 dd_list::iterator prev_link;
00318 dd_list::iterator link = begin();
00319
00320
00321 if( ( size( ) == 1 ) && ( begin()->y == 0.0 ) ){
00322 begin()->y = 1.0;
00323 }
00324
00325
00326 for(; link != end( ); link = next_link)
00327 {
00328 next_link = link;
00329 ++next_link;
00330 prev_link = link;
00331 --prev_link;
00332
00333
00334 if( link->y > 0.0)
00335 {
00336
00337 double dE_L = ( link == begin( ) ) ? link->E_out() :
00338 link->E_out() - prev_link->E_out();
00339
00340
00341
00342 double dE = 0.5*DELTA_WIDTH( link->E_out() );
00343
00344 if( dE_L <= dE )
00345 {
00346 SevereError("distrib_base::widen_delta",
00347 pastenum("Spikes out of order left at ",link->E_out()));
00348 }
00349
00350
00351 dd_link new_link = dd_link(link->E_out() - dE, 0.0);
00352 insert(link, new_link);
00353 ++prev_link;
00354
00355 double dE_R = ( next_link == end( ) ) ? link->E_out( ) :
00356 next_link->E_out( ) - link->E_out( );
00357
00358 if( dE_R <= 0.0 )
00359 {
00360 SevereError("distrib_base::widen_delta",
00361 pastenum("Spikes out of order right at ",link->E_out()));
00362 }
00363
00364
00365 while( ( dE_R <= 3*dE ) && ( next_link != end( ) ) )
00366 {
00367
00368 next_link->y += link->y;
00369 erase( link );
00370 link = next_link;
00371 ++next_link;
00372 if( next_link == end( ) )
00373 {
00374 break;
00375 }
00376 else
00377 {
00378 dE_R = next_link->E_out( ) - link->E_out( );
00379 }
00380 }
00381
00382
00383 new_link = dd_link(link->E_out() + dE, 0.0);
00384 insert(next_link, new_link);
00385
00386
00387 dE = link->E_out( ) + dE - prev_link->E_out( );
00388
00389
00390 link->y /= dE/2;
00391
00392 }
00393 }
00394 }
00395
00396
00397
00398 void distrib_base::list_interp(double e_in, distrib_base& left_list,
00399 distrib_base& right_list)
00400 {
00401 Warning("","You are using distrib_base::list_interp, not a good idea");
00402 if(!empty())
00403 {
00404 SevereError("distrib_base::list_interp",
00405 "Trying to fill a distrib_base which has already been made");
00406 }
00407 double alpha = (e_in - left_list.E_in())/
00408 (right_list.E_in() - left_list.E_in());
00409 if((alpha <= 0.0) || (alpha >= 1.0))
00410 {
00411 SevereError("distrib_base::list_interp","Attempt to extrapolate");
00412 }
00413 E_in() = e_in;
00414
00415
00416 for(int j = 0; j <= num_bins; ++j)
00417 {
00418 equi_prob.push_back( (1.0 - alpha)*left_list.equi_prob[j] +
00419 alpha*right_list.equi_prob[j] );
00420 }
00421
00422 double dp = 1.0/num_bins;
00423 for(int j = 0; j < num_bins; ++j)
00424 {
00425 double dE = equi_prob[j+1] - equi_prob[j];
00426 if(dE == 0.0) SevereError("distrib_base::list_interp"," dE = 0");
00427 dd_link new_link = dd_link(equi_prob[j], dp/dE);
00428 insert(end(), new_link);
00429 new_link.x = equi_prob[j+1];
00430 insert(end(), new_link);
00431 }
00432 widen_jumps();
00433 }
00434
00435
00436
00437 bool distrib_base::check_equiprob(distrib_base& left_list,
00438 distrib_base& right_list, double tol_2d)
00439 {
00440 bool is_OK = true;
00441
00442 double E_max = equi_prob[num_bins];
00443
00444
00445 double alpha = (E_in() - left_list.E_in())/
00446 (right_list.E_in() - left_list.E_in());
00447 if((alpha <= 0.0) || (alpha >= 1.0))
00448 {
00449 SevereError("distrib_base::check_equiprob","bad interpolation encountered");
00450 }
00451 for(int j = 0; j <= num_bins; ++j)
00452 {
00453
00454 double average = (1.0 - alpha)*left_list.equi_prob[j] +
00455 alpha*right_list.equi_prob[j];
00456 if(abs(equi_prob[j] - average) > tol_2d*E_max)
00457 {
00458 is_OK = false;
00459 }
00460 }
00461 return is_OK;
00462 }
00463
00464
00465
00466
00467
00468
00469
00470
00471 bool distrib_base::check_interp_2d(double tol_2d, double cut_off_2d)
00472 {
00473 SevereError("distrib_base::check_interp_2d",
00474 "Write code in distrib_base for checking unit-based interpolation");
00475 return false;
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591 }