00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "cddefines.h"
00012 #include "lines_service.h"
00013 #include "phycon.h"
00014 #include "dense.h"
00015 #include "rfield.h"
00016 #include "taulines.h"
00017 #include "iso.h"
00018 #include "trace.h"
00019 #include "hyperfine.h"
00020 #include "physconst.h"
00021
00022
00023
00024 void H21_cm_pops( void )
00025 {
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 double x,
00043 PopTot;
00044 double a32,a31,a41,a42,a21, occnu_lya ,
00045 rate12 , rate21 , pump12 , pump21 , coll12 , coll21,
00046 texc , occnu_lya_23 , occnu_lya_13,occnu_lya_24,occnu_lya_14, texc1, texc2;
00047 a31 = 2.08e8;
00048 a32 = 4.16e8;
00049 a41 = 4.16e8;
00050 a42 = 2.08e8;
00051
00052
00053
00054
00055 a21 = 2.85e-15;
00056
00057
00058
00059 a21 *= (HFLines[0].Emis->Pdest + HFLines[0].Emis->Pesc + HFLines[0].Emis->Pelec_esc);
00060
00061
00062
00063 occnu_lya = OccupationNumberLine( &Transitions[ipH_LIKE][ipHYDROGEN][ipH2p][ipH1s] ) *
00064 hyperfine.lgLya_pump_21cm;
00065
00066
00067 texc = TexcLine( &Transitions[ipH_LIKE][ipHYDROGEN][ipH2p][ipH1s] );
00068
00069 if( texc > 0. )
00070 {
00071
00072 texc1 = sexp(0.068/texc);
00073 texc2 = sexp(((82259.272-82258.907)*T1CM)/texc);
00074 }
00075 else
00076 {
00077 texc1 = 0.;
00078 texc2 = 0.;
00079 }
00080
00081
00082
00083
00084 occnu_lya_23 = occnu_lya;
00085 occnu_lya_13 = occnu_lya*texc1;
00086 occnu_lya_14 = occnu_lya_13*texc2;
00087 occnu_lya_24 = occnu_lya*texc2;
00088
00089
00090
00091 pump12 = HFLines[0].Emis->pump;
00092 pump21 = pump12 * HFLines[0].Lo->g / HFLines[0].Hi->g;
00093
00094
00095
00096
00097 coll12 = HFLines[0].Coll.cs*dense.cdsqte/HFLines[0].Lo->g*rfield.ContBoltz[HFLines[0].ipCont-1];
00098 coll21 = HFLines[0].Coll.cs*dense.cdsqte/HFLines[0].Hi->g;
00099
00100
00101
00102 rate12 =
00103
00104 coll12 +
00105
00106 pump12 +
00107
00108 3.*a31*occnu_lya_13 *a32/(a31+a32)+
00109
00110
00111 3.*a41*occnu_lya_14 *a42/(a41+a42);
00112
00113
00114
00115
00116
00117 rate21 =
00118
00119 coll21 +
00120
00121 pump21 +
00122
00123
00124 occnu_lya_23*a32 * a31/(a31+a32)+
00125 occnu_lya_24*a42*a41/(a41+a42);
00126
00127
00128 x = rate12 / SDIV(a21 + rate21);
00129
00130 PopTot = StatesElem[ipH_LIKE][ipHYDROGEN][ipH1s].Pop*dense.xIonDense[ipHYDROGEN][1];
00131
00132 HFLines[0].Hi->Pop = (x/(1.+x))* PopTot;
00133 HFLines[0].Lo->Pop = (1./(1.+x))* PopTot;
00134
00135
00136 HFLines[0].Emis->PopOpc = HFLines[0].Lo->Pop*((3*rate21- rate12) + 3*a21)/SDIV(3*(a21+ rate21));
00137
00138
00139 HFLines[0].Emis->phots = MAX2(0.,a21*HFLines[0].Hi->Pop);
00140
00141
00142 HFLines[0].Emis->xIntensity = HFLines[0].Emis->phots*HFLines[0].EnergyErg;
00143
00144
00145 HFLines[0].Emis->ColOvTot = coll12 / rate12;
00146
00147
00148 if( HFLines[0].Hi->Pop > SMALLFLOAT )
00149 {
00150 hyperfine.Tspin21cm = TexcLine( &HFLines[0] );
00151
00152
00153 if( hyperfine.Tspin21cm == 0. )
00154 hyperfine.Tspin21cm = phycon.te;
00155 }
00156 else
00157 {
00158 hyperfine.Tspin21cm = phycon.te;
00159 }
00160
00161 return;
00162 }
00163
00164
00165
00166 double H21cm_electron( double temp )
00167 {
00168 double hold;
00169 temp = MIN2(1e4 , temp );
00170
00171
00172
00173 hold = -9.607 + log10( sqrt(temp)) * sexp( pow(log10(temp) , 4.5 ) / 1800. );
00174 hold = pow(10.,hold );
00175 return( hold );
00176 }
00177
00178
00179
00180
00181
00182
00183 #if 0
00184 STATIC double h21_t_ge_20( double temp )
00185 {
00186 double y;
00187 double x1,
00188 teorginal = temp;
00189
00190 temp = MIN2( 1000.,temp );
00191 x1 =1.0/sqrt(temp);
00192 y =-21.70880995483007-13.76259674006133*x1;
00193 y = exp(y);
00194
00195
00196
00197
00198 if( teorginal > 1e3 )
00199 {
00200 y *= pow(teorginal/1e3 , 0.33 );
00201 }
00202
00203 return( y );
00204 }
00205
00206
00207 STATIC double h21_t_lt_20( double temp )
00208 {
00209 double y;
00210 double x1;
00211
00212
00213 temp = MAX2( 1., temp );
00214 x1 =temp*log(temp);
00215 y =9.720710314268267E-08+6.325515312006680E-08*x1;
00216 return(y*y);
00217 }
00218 #endif
00219
00220
00221
00222
00223
00224 STATIC double h21_t_ge_10( double temp )
00225 {
00226 double y;
00227 double x1,x2,x3,
00228 teorginal = temp;
00229
00230 temp = MIN2( 300., temp );
00231 x1 =temp;
00232 y =1.4341127e-9+9.4161077e-15*x1-9.2998995e-9/(log(x1))+6.9539411e-9/sqrt(x1)+1.7742293e-8*(log(x1))/pow(x1,2);
00233 if( teorginal > 300. )
00234 {
00235
00236 x3 = MIN2( 1000., teorginal );
00237 x2 =1.0/sqrt(x3);
00238 y =-21.70880995483007-13.76259674006133*x2;
00239 y = 1.236686*exp(y);
00240
00241 }
00242 if( teorginal > 1e3 )
00243 {
00244
00245 y *= pow(teorginal/1e3 , 0.33 );
00246 }
00247 return( y );
00248 }
00249
00250 STATIC double h21_t_lt_10( double temp )
00251 {
00252 double y;
00253 double x1;
00254
00255
00256 temp = MAX2(1., temp );
00257 x1 =temp;
00258 y =8.5622857e-10+2.331358e-11*x1+9.5640586e-11*pow((log(x1)),2)-4.6220869e-10*sqrt(x1)-4.1719545e-10/sqrt(x1);
00259 return(y);
00260 }
00261
00262
00263
00264
00265
00266 double H21cm_H_atom( double temp )
00267 {
00268 double hold;
00269 if( temp >= 10. )
00270 {
00271 hold = h21_t_ge_10( temp );
00272 }
00273 else
00274 {
00275 hold = h21_t_lt_10( temp );
00276 }
00277
00278 return hold;
00279 }
00280
00281
00282
00283 double H21cm_proton( double temp )
00284 {
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 double hold;
00308
00309
00310 temp = MAX2( 2. , temp );
00311 temp = MIN2( 2e4 , temp );
00312
00313
00314 double x1,x2,x3,x4;
00315 x1 = temp;
00316 x2 = temp*temp;
00317 x3 = sqrt(temp);
00318 x4 = log(temp)/temp;
00319 hold =9.588389834316704E-11 - 5.158891920816405E-14*x1
00320 +5.895348443553458E-19*x2 + 2.053049602324290E-11*x3
00321 +9.122617940315725E-10*x4;
00322
00323 return hold;
00324 }
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 typedef struct
00346 {
00347 double strengths[12];
00348 } Ion;
00349
00350 static Ion *Strengths;
00351
00352
00353 void HyperfineCreate(void)
00354 {
00355 FILE *ioDATA;
00356 char chLine[INPUT_LINE_LENGTH];
00357 bool lgEOL;
00358
00359 realnum spin, wavelength;
00360 long int i, j, mass, nelec, ion, nelem;
00361
00362 DEBUG_ENTRY( "HyperfineCreate()" );
00363
00364
00365
00366
00367
00368
00369
00370
00371 if( trace.lgTrace )
00372 fprintf( ioQQQ," Hyperfine opening hyperfine.dat:");
00373
00374 ioDATA = open_data( "hyperfine.dat", "r" );
00375
00376
00377 if( read_whole_line( chLine , (int)sizeof(chLine) , ioDATA ) == NULL )
00378 {
00379 fprintf( ioQQQ, " Hyperfine could not read first line of hyperfine.dat.\n");
00380 cdEXIT(EXIT_FAILURE);
00381 }
00382
00383
00384 nHFLines = 0;
00385 while( read_whole_line( chLine , (int)sizeof(chLine) , ioDATA ) != NULL )
00386 {
00387
00388
00389 if( chLine[0] != '#')
00390 ++nHFLines;
00391 }
00392
00393
00394 HFLines = (transition *)MALLOC( (size_t)(nHFLines)*sizeof(transition) );
00395
00396 for( i=0; i< nHFLines; ++i )
00397 {
00398 TransitionJunk( &HFLines[i] );
00399 HFLines[i].Hi = AddState2Stack();
00400 HFLines[i].Lo = AddState2Stack();
00401 HFLines[i].Emis = AddLine2Stack( true );
00402 }
00403
00404 Strengths = (Ion *)MALLOC( (size_t)(nHFLines)*sizeof(Ion) );
00405 hyperfine.HFLabundance = (realnum *)MALLOC( (size_t)(nHFLines)*sizeof(realnum) );
00406
00407
00408 if( fseek( ioDATA , 0 , SEEK_SET ) != 0 )
00409 {
00410 fprintf( ioQQQ, " Hyperfine could not rewind hyperfine.dat.\n");
00411 cdEXIT(EXIT_FAILURE);
00412 }
00413
00414
00415 if( read_whole_line( chLine , (int)sizeof(chLine) , ioDATA ) == NULL )
00416 {
00417 fprintf( ioQQQ, " Hyperfine could not read first line of hyperfine.dat.\n");
00418 cdEXIT(EXIT_FAILURE);
00419 }
00420
00421
00422 i = 1;
00423 nelem = (long)FFmtRead(chLine,&i,INPUT_LINE_LENGTH,&lgEOL);
00424 nelec = (long)FFmtRead(chLine,&i,INPUT_LINE_LENGTH,&lgEOL);
00425 ion = (long)FFmtRead(chLine,&i,INPUT_LINE_LENGTH,&lgEOL);
00426
00427 {
00428
00429 static int iYR=2, iMN=10, iDY=28;
00430 if( ( nelem != iYR ) || ( nelec != iMN ) || ( ion != iDY ) )
00431 {
00432 fprintf( ioQQQ,
00433 " Hyperfine: the version of hyperfine.dat in the data directory is not the current version.\n" );
00434 fprintf( ioQQQ,
00435 " I expected to find the number %i %i %i and got %li %li %li instead.\n" ,
00436 iYR, iMN , iDY ,
00437 nelem , nelec , ion );
00438 fprintf( ioQQQ, "Here is the line image:\n==%s==\n", chLine );
00439 cdEXIT(EXIT_FAILURE);
00440 }
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453 j = 0;
00454
00455 while( read_whole_line( chLine , (int)sizeof(chLine) , ioDATA ) != NULL )
00456 {
00457
00458
00459 if( chLine[0] != '#')
00460 {
00461 double Aul;
00462 ASSERT( j < nHFLines );
00463
00464 double help[3];
00465 sscanf(chLine, "%li%i%le%i%le%le%le%le%le%le%le%le%le%le%le%le%le%le%le",
00466 &mass,
00467 &HFLines[j].Hi->nelem,
00468 &help[0],
00469 &HFLines[j].Hi->IonStg,
00470 &help[1],
00471 &help[2],
00472 &Aul,
00473 &Strengths[j].strengths[0],
00474 &Strengths[j].strengths[1],
00475 &Strengths[j].strengths[2],
00476 &Strengths[j].strengths[3],
00477 &Strengths[j].strengths[4],
00478 &Strengths[j].strengths[5],
00479 &Strengths[j].strengths[6],
00480 &Strengths[j].strengths[7],
00481 &Strengths[j].strengths[8],
00482 &Strengths[j].strengths[9],
00483 &Strengths[j].strengths[10],
00484 &Strengths[j].strengths[11]);
00485 spin = (realnum)help[0];
00486 hyperfine.HFLabundance[j] = (realnum)help[1];
00487 wavelength = (realnum)help[2];
00488 HFLines[j].Emis->Aul = (realnum)Aul;
00489 HFLines[j].Hi->g = (realnum) (2*(spin + .5) + 1);
00490 HFLines[j].Lo->g = (realnum) (2*(spin - .5) + 1);
00491 HFLines[j].WLAng = wavelength * 1e8f;
00492 HFLines[j].EnergyWN = (realnum) (1. / wavelength);
00493 HFLines[j].Emis->gf = (realnum)(GetGF(HFLines[j].Emis->Aul, HFLines[j].EnergyWN, HFLines[j].Hi->g));
00494
00495
00496
00497 ASSERT(HFLines[j].Emis->gf > 0.);
00498
00499 j++;
00500 }
00501
00502 }
00503
00504
00505 fclose(ioDATA);
00506
00507 # if 0
00508
00509
00510 for(i = 0; i < nHFLines; i++)
00511 {
00512 N = dense.xIonDense[HFLines[i].Hi->nelem-1][HFLines[i].Hi->IonStg-1];
00513 Ne = dense.eden;
00514
00515 h = 6.626076e-27;
00516 c = 3e10;
00517 k = 1.380658e-16;
00518
00519 upsilon = HyperfineCS(i);
00520
00521 q21 = COLL_CONST * upsilon / (phycon.sqrte * HFLines[i].Hi->g);
00522
00523 q12 = HFLines[i].Hi->g/ HFLines[i].Lo->g * q21 * exp(-1 * h * c * HFLines[i].EnergyWN / (k * phycon.te));
00524
00525 x = Ne * q12 / (HFLines[i].Emis->Aul * (1 + Ne * q21 / HFLines[i].Aul));
00526 HFLines[i].xIntensity = N * HFLines[i].Emis->Aul * x / (1.0 + x) * h * c / (HFLines[i].WLAng / 1e8);
00527
00528 }
00529 # endif
00530
00531 return;
00532 }
00533
00534
00535
00536 double HyperfineCS( long i )
00537 {
00538
00539
00540 int j = 0;
00541 # define N_TE_TABLE 12
00542 double slope, upsilon, TemperatureTable[N_TE_TABLE] = {.1e6, .15e6, .25e6, .4e6, .6e6,
00543 1.0e6, 1.5e6, 2.5e6, 4e6, 6e6, 10e6, 15e6};
00544
00545 DEBUG_ENTRY( "HyperfineCS()" );
00546
00547
00548
00549 ASSERT( i >= 0. && i <= nHFLines );
00550
00551
00552
00553
00554
00555
00556
00557
00558 if( phycon.te <= TemperatureTable[0])
00559 {
00560
00561 upsilon = Strengths[i].strengths[0];
00562 }
00563 else if( phycon.te >= TemperatureTable[N_TE_TABLE-1])
00564 {
00565
00566 upsilon = Strengths[i].strengths[N_TE_TABLE-1];
00567 }
00568 else
00569 {
00570 j = 1;
00571
00572
00573
00574 while ( j < N_TE_TABLE && TemperatureTable[j] < phycon.te )
00575 j++;
00576
00577 ASSERT( j >= 0 && j < N_TE_TABLE);
00578 ASSERT( (TemperatureTable[j-1] <= phycon.te ) && (TemperatureTable[j] >= phycon.te) );
00579
00580 if( fp_equal( phycon.te, TemperatureTable[j] ) )
00581 {
00582 upsilon = Strengths[i].strengths[j];
00583 }
00584
00585 else if( phycon.te < TemperatureTable[j])
00586 {
00587 slope = (log10(Strengths[i].strengths[j-1]) - log10(Strengths[i].strengths[j])) /
00588 (log10(TemperatureTable[j-1]) - log10(TemperatureTable[j]));
00589
00590 upsilon = (log10((phycon.te)) - (log10(TemperatureTable[j-1])-6.))*slope + log10(Strengths[i].strengths[j-1]);
00591 upsilon = pow(10., upsilon);
00592 }
00593 else
00594 {
00595 upsilon = Strengths[i].strengths[j-1];
00596 }
00597 }
00598
00599 return upsilon;
00600 }