00001 /* This file is part of Cloudy and is copyright (C)1978-2008 by Gary J. Ferland and 00002 * others. For conditions of distribution and use see copyright notice in license.txt */ 00003 /*RT_line_static do line radiative transfer, 00004 * evaluates escape and destruction probability, 00005 * called by HydroPEsc, RT_line_all */ 00006 /* ND wind distinction is not here - that is done where optical depths are incremented 00007 * with line opacity - rt_line_one_tauinc and in line width for rad pressure, in 00008 * rt escprob */ 00009 #include "cddefines.h" 00010 #include "rfield.h" 00011 #include "doppvel.h" 00012 #include "dense.h" 00013 #include "opacity.h" 00014 #include "lines_service.h" 00015 #include "conv.h" 00016 #include "radius.h" 00017 #include "rt.h" 00018 #include "physconst.h" 00019 00020 /*RT_line_static do line radiative transfer, 00021 * called by RT_line_all */ 00022 STATIC void RT_line_static( 00023 /* the em line we will work on */ 00024 transition * t , 00025 /* when this is true do both esc and dest probs, 00026 * when falst, only dest probs */ 00027 bool lgDoEsc , 00028 /* this is option to not include line self shielding across this zone. 00029 * this can cause pump to depend on zone thickness, and leads to unstable 00030 * feedback in some models with the large H2 molecule, due to Solomon 00031 * process depending on zone thickness and level populations. */ 00032 bool lgShield_this_zone ); 00033 00034 /*RT_line_one do rt for emission line structure - calls RT_line_static or RT_line_wind */ 00035 void RT_line_one( 00036 /* the em line we will work on */ 00037 transition *t , 00038 /* when this is true do both esc and dest probs, 00039 * when falst, only dest probs */ 00040 bool lgDoEsc , 00041 /* if true then we want to update the fine opacity scale */ 00042 bool lgDoFine_opac_update , 00043 /* this is option to not include line self shielding across this zone. 00044 * this can cause pump to depend on zone thickness, and leads to unstable 00045 * feedback in some models with the large H2 molecule, due to Solomon 00046 * process depending on zone thickness and level populations. */ 00047 bool lgShield_this_zone ) 00048 { 00049 static long int nTau[100], 00050 n; 00051 00052 DEBUG_ENTRY( "RT_line_one()" ); 00053 00054 /*>>chng 06 apr 05, effects of simply returning upon call with no pop */ 00055 /* skip line transfer if requested with 'no line transfer' command, but never skip Lya */ 00056 if( (t->Lo->Pop<=SMALLFLOAT && conv.nTotalIoniz) || 00057 (!rfield.lgDoLineTrans && (t->Emis->iRedisFun != ipLY_A) ) ) 00058 { 00059 return; 00060 } 00061 00062 { 00063 /* option to keep track of population values during calls, 00064 * print out data to make histogram */ 00065 /*@-redef@*/ 00066 enum {DEBUG_LOC=false}; 00067 /*@+redef@*/ 00068 if( DEBUG_LOC ) 00069 { 00070 if( nzone==0 ) 00071 { 00072 for(n=0; n<100; ++n ) 00073 nTau[n] = 0; 00074 } 00075 if( t->Lo->Pop<=SMALLFLOAT ) 00076 n = 0; 00077 else 00078 n = (long)log10( t->Lo->Pop )+37; 00079 n = MIN2( n , 99 ); 00080 n = MAX2( n , 0 ); 00081 /*if( n==37 && nzone > 5 ) 00082 { 00083 fprintf(ioQQQ,"HIT\n"); 00084 }*/ 00085 ++nTau[n]; 00086 if( nzone > 183 ) 00087 { 00088 for(n=0; n<100; ++n ) 00089 fprintf(ioQQQ,"%li\t%li\n", n , nTau[n] ); 00090 cdEXIT(EXIT_SUCCESS); 00091 } 00092 } 00093 } 00094 00095 /* always call single routine */ 00096 RT_line_static( 00097 /* the line we will work on */ 00098 t , 00099 /* when this is true do both esc and dest probs, 00100 * when falst, only dest probs */ 00101 lgDoEsc , 00102 lgShield_this_zone); 00103 00104 /* this is line center frequency, including bulk motion of gas */ 00105 long int ipLineCenter = t->Emis->ipFine + rfield.ipFineConVelShift; 00106 00107 /* define fine opacity fine grid fine mesh */ 00108 /* rfield.lgOpacityFine flag set flast with no fine opacities command */ 00109 if( lgDoFine_opac_update && ipLineCenter >= 0 && t->Emis->PopOpc > 0. && 00110 ipLineCenter<rfield.nfine && rfield.lgOpacityFine ) 00111 { 00112 long int i; 00113 00114 /* number of fine opacity cells corresponding to one doppler width for current 00115 * temperature, velocity field, and nuclear mass, 00116 * rfield.fine_opac_velocity_width is width per cell, cm/s */ 00117 realnum cells_wide_1x = DoppVel.doppler[t->Hi->nelem-1]/rfield.fine_opac_velocity_width; 00118 00119 /* line center opacity - want realnum since will add to fine opacity array, 00120 * which is realnum */ 00121 realnum opac_line = (realnum)t->Emis->PopOpc * t->Emis->opacity / DoppVel.doppler[t->Hi->nelem-1]; 00122 00123 /* this is effective optical depth to this point. Do not work with line if this product 00124 * is substantially less than unity */ 00125 double dTauEffec = opac_line*radius.depth_x_fillfac; 00126 00127 /* this is line center for current velocity, which is measured 00128 * relative to illuminated face */ 00129 00130 /* use dTauEffec to choose whether line is important */ 00131 00132 if( dTauEffec > SMALLFLOAT ) 00133 { 00134 /* width of optically thick line, do 4x with exponential core, 00135 * must be at least one cell, but profile is symmetric */ 00136 long int nCells_core = (long)(cells_wide_1x*4.f+1.5f); 00137 realnum opacity; 00138 00139 /* core is symmetric - make sure both upper and lower bounds 00140 * are within continuum energy bin */ 00141 if( ipLineCenter - nCells_core < 1 ) 00142 nCells_core = ipLineCenter - 1; 00143 if( ipLineCenter + nCells_core > rfield.nfine ) 00144 nCells_core = ipLineCenter -rfield.nfine - 1; 00145 00146 /* want core to be at least one cell wide */ 00147 nCells_core = MAX2( 1 , nCells_core ); 00148 00149 /* line center itself, must not double count here */ 00150 rfield.fine_opac_zone[ipLineCenter] += opac_line; 00151 for( i=1; i<nCells_core; ++i ) 00152 { 00153 /* square of distance from line center in units of doppler width */ 00154 realnum xsq = POW2(i/cells_wide_1x); 00155 00156 /* the line opacity at that point, includes doppler core and damping wings */ 00157 opacity = opac_line*( sexp(xsq) + t->Emis->damp / MAX2(1.f,(1.772f*xsq)) ); 00158 00159 rfield.fine_opac_zone[ipLineCenter+i] += opacity; 00160 rfield.fine_opac_zone[ipLineCenter-i] += opacity; 00161 } 00162 00163 /* include damping wings if optical depth is large */ 00164 /* >>chng 04 mar 29, rewrite to use symmetry in two halves of line */ 00165 if( dTauEffec*t->Emis->damp/9. > 0.1 ) 00166 { 00167 /* do damping wings if very optically thick 00168 * this is number of cells to extend the damping wings - cells_wide is one dop width 00169 * 56.419 is 1 / (0.01 * sqrt pi) ) */ 00170 /* tests with th85orion, stopping at half -h2 point, showed that 0.01 was 00171 * needed for outer edge, given the definition of dTauEffec */ 00172 realnum x = (realnum)sqrt( dTauEffec * t->Emis->damp *56.419 ) * cells_wide_1x; 00173 long int nCells_damp; 00174 /* >>chng 04 mar 24, add test on size of x, which can exceed 00175 * limits of long in extreme optical depths */ 00176 if( x<LONG_MAX ) 00177 { 00178 nCells_damp = (long)x; 00179 00180 if( ipLineCenter-nCells_damp < 1 ) 00181 nCells_damp = ipLineCenter-1; 00182 00183 if( ipLineCenter+nCells_damp > rfield.nfine ) 00184 nCells_damp = rfield.nfine - ipLineCenter-1; 00185 } 00186 else 00187 { 00188 /* x was too big, just set to extreme range, which is 00189 * number of cells to nearest boundary */ 00190 nCells_damp = MIN2( rfield.nfine-ipLineCenter , ipLineCenter )-1; 00191 } 00192 00193 ASSERT( nCells_core>0 ); 00194 for( i=nCells_core; i<nCells_damp; ++i ) 00195 { 00196 /* distance from line center in doppler units */ 00197 realnum xsq = POW2(i/cells_wide_1x); 00198 /* term in denominator is x^2 */ 00199 opacity = opac_line*t->Emis->damp/(1.772f*xsq ); 00200 rfield.fine_opac_zone[ipLineCenter+i] += opacity; 00201 rfield.fine_opac_zone[ipLineCenter-i] += opacity; 00202 } 00203 } 00204 } 00205 } 00206 return; 00207 } 00208 00209 /*RT_line_static do line radiative transfer for static geometry */ 00210 STATIC void RT_line_static( 00211 /* the em line we will work on */ 00212 transition * t , 00213 /* when this is true do both esc and dest probs, 00214 * when false, only dest probs */ 00215 bool lgDoEsc , 00216 /* this is option to not include line self shielding across this zone. 00217 * this can cause pump to depend on zone thickness, and leads to unstable 00218 * feedback in some models with the large H2 molecule, due to Solomon 00219 * process depending on zone thickness and level populations. */ 00220 bool lgShield_this_zone ) 00221 { 00222 bool lgGoodTau; 00223 long int nelem; 00224 int nRedis = -1; 00225 00226 DEBUG_ENTRY( "RT_line_static()" ); 00227 00228 /* this is the routine that computes much of the radiative transfer 00229 * physics for lines for static case. */ 00230 00231 /*ASSERT( t->IonStg < LIMELM+4 );*/ 00232 /*ASSERT( t->nelem-1 < LIMELM+4 );*/ 00233 00234 /* >>chng 01 aug 18, do not evaluate if no population */ 00235 /* molecules are evaluated here, these must be valid */ 00236 /* >>chng 01 oct 25, add test for lgDoEsc, this is to make sure 00237 * that rates are evaluated at start of a new iteration */ 00238 if( dense.xIonDense[ t->Hi->nelem-1][t->Hi->IonStg-1] == 0. && !lgDoEsc ) 00239 { 00240 /* zero population, return after setting everything with side effects */ 00241 t->Emis->Pesc = 1.f; 00242 00243 /* inward escaping fraction */ 00244 t->Emis->FracInwd = 0.5; 00245 00246 /* pumping rate */ 00247 t->Emis->pump = 0.; 00248 00249 /* destruction probability */ 00250 t->Emis->Pdest = 0.; 00251 t->Emis->Pelec_esc = 0.; 00252 00253 return; 00254 } 00255 /* check that we don't have a runaway maser */ 00256 else if( t->Emis->TauIn < -30. ) 00257 { 00258 fprintf( ioQQQ, "PROBLEM RT_line_static called with large negative optical depth, zone %.2f, setting lgAbort true.\n", 00259 fnzone ); 00260 DumpLine(t); 00261 /* >>>chng 00 apr 23, return busted true instead of exit here, so that code will 00262 * not hang under MPI */ 00263 lgAbort = true; 00264 return; 00265 } 00266 00267 /* this checks if we have overrun the optical depth scale, 00268 * in which case the inward optical depth is greater than the 00269 * previous iteration's total optical depth. 00270 * We do not reevaluate escape probabilities if the optical depth 00271 * scale has been overrun due to huge bogus change in solution 00272 * that would result */ 00273 if( iteration == 1 || lgTauGood( t ) ) 00274 { 00275 lgGoodTau = true; 00276 } 00277 else 00278 { 00279 /* do not reevaluate escape probabilities if we have overrun 00280 * the optical depth scale */ 00281 lgGoodTau = false; 00282 } 00283 00284 /* atomic number of this element on the C scale*/ 00285 nelem = t->Hi->nelem-1; 00286 00287 /* damping constant for the line, save it */ 00288 t->Emis->damp = t->Emis->dampXvel / DoppVel.doppler[t->Hi->nelem-1]; 00289 /*if( t->damp <0. ) 00290 { 00291 fprintf(ioQQQ,"DEBUG hit it \n"); 00292 }*/ 00293 ASSERT( t->Emis->damp > 0. || 00294 (opac.lgCaseB && t->Emis->damp >= 0.) ); 00295 00296 /* static solution - which type of line will determine 00297 * which redistribution function */ 00298 /* iRedisFun == 1 - alpha resonance line, partial redistribution, 00299 * ipPRD == 1 */ 00300 if( t->Emis->iRedisFun == ipPRD ) 00301 { 00302 /* incomplete redistribution with wings */ 00303 if( lgDoEsc ) 00304 { 00305 if( lgGoodTau ) 00306 { 00307 t->Emis->Pesc = (realnum)esc_PRD( t->Emis->TauIn , t->Emis->TauTot , t->Emis->damp ); 00308 00309 /* inward escaping fraction */ 00310 t->Emis->FracInwd = rt.fracin; 00311 } 00312 } 00313 nRedis = ipDEST_INCOM; 00314 } 00315 00316 /* complete redistribution without wings - t->ipLnRedis is ipCRD == -1 */ 00317 else if( t->Emis->iRedisFun == ipCRD ) 00318 { 00319 if( lgDoEsc ) 00320 { 00321 if( lgGoodTau ) 00322 { 00323 /* >>chng 01 mar -6, escsub will call any of several esc prob routines, 00324 * depending of how core is set. We always want core-only for this option, 00325 * so call esca0k2(tau) directly */ 00326 t->Emis->Pesc = (realnum)esc_CRDcore( t->Emis->TauIn , t->Emis->TauTot ); 00327 00328 /* inward escaping fraction */ 00329 t->Emis->FracInwd = rt.fracin; 00330 } 00331 } 00332 nRedis = ipDEST_K2; 00333 } 00334 00335 /* chng 01 feb 27, add CRD with wings, = 2 */ 00336 else if( t->Emis->iRedisFun == ipCRDW ) 00337 { 00338 /* complete redistribution with damping wings */ 00339 if( lgDoEsc ) 00340 { 00341 if( lgGoodTau ) 00342 { 00343 t->Emis->Pesc = (realnum)esc_CRDwing( t->Emis->TauIn , t->Emis->TauTot , t->Emis->damp ); 00344 00345 /* inward escaping fraction */ 00346 t->Emis->FracInwd = rt.fracin; 00347 } 00348 } 00349 nRedis = ipDEST_K2; 00350 } 00351 00352 /* chng 03 may 14, special Lya case*/ 00353 else if( t->Emis->iRedisFun == ipLY_A ) 00354 { 00355 /* incomplete redistribution with wings, for special case of Lya 00356 * uses fits to Hummer & Kunasz numerical results 00357 * this routine is different because escape and dest probs 00358 * are evaluated together, so no test of lgDoEsc */ 00359 if( lgGoodTau ) 00360 { 00361 double dest , esin; 00362 00363 /* this will always evaluate escape prob, no matter what lgDoEsc is. 00364 * The destruction prob comes back as dest */ 00365 t->Emis->Pesc = (realnum)RTesc_lya(&esin , &dest , t->Emis->PopOpc , nelem); 00366 00367 /* this is current destruction rate */ 00368 t->Emis->Pdest = (realnum)dest; 00369 00370 /* this is fraction of line which is inward escaping */ 00371 t->Emis->FracInwd = rt.fracin; 00372 } 00373 } 00374 else 00375 { 00376 fprintf( ioQQQ, " RT_line_static called with redistribution function zero\n" ); 00377 ShowMe(); 00378 cdEXIT(EXIT_FAILURE); 00379 } 00380 00381 /* pumping by incident and diffuse continua */ 00382 /* >>chng 03 may 15, this block had been repeated all four times above, move down 00383 * here to use common code, only rt.wayin is defined above */ 00384 /* >>chng 03 may 17, do not evaluate when drad is zero, before first 00385 * zone thickness is established */ 00386 /* >>chng 06 nov 29, reordered if clauses, no point in doing bigger loop if "no induced" is on. */ 00387 /* option to kill induced processes */ 00388 if( !rfield.lgInducProcess ) 00389 { 00390 t->Emis->pump = 0.; 00391 } 00392 else if( (lgDoEsc || (t->Emis->iRedisFun == ipLY_A) ) ) 00393 { 00394 double dTau; 00395 double pumpsave = t->Emis->pump; 00396 double shield_continuum; 00397 00398 /* >>chng 04 apr 18, break out line continuum shielding into this function */ 00399 shield_continuum = RT_continuum_shield_fcn( t ); 00400 00401 /* continuum upward pumping rate, A gu/gl abs prob occnum 00402 * the "no induced" command causes continuum pumping to be set to 0 */ 00403 /*t->pump = t->Aul * t->gHi / t->gLo * rt.wayin **/ 00404 /* >>chng 05 feb 16, add outward diffuse emission */ 00405 /*t->pump = t->Aul * t->gHi / t->gLo * shield_continuum * 00406 rfield.OccNumbIncidCont[t->ipCont-1];*/ 00407 t->Emis->pump = t->Emis->Aul * t->Hi->g / t->Lo->g * shield_continuum *( 00408 rfield.OccNumbIncidCont[t->ipCont-1] + rfield.OccNumbContEmitOut[t->ipCont-1] ); 00409 00410 /* >>chng 99 dec 02, add correction for line optical depth across zone */ 00411 /* correction for attenuation within line across zone */ 00412 /* >>chng 99 mar 18, from 0 to 1e-8 in following to avoid underflow, 00413 * this caused an overestimate of pumping rates */ 00414 /* >>chng 00 dec 19, nova.in oscillated since correction factor was 00415 * very large across zones that were already very optically thick, dr changed, 00416 * causing feedback between ionization and thickness 00417 * the intention of this correction was to only apply when on the 00418 * verge of optically thick, 00419 * change lower bound on product t->dTau * radius.drad_x_fillfac to 1e-3 to avoid 00420 * constantly getting unity, also check on relative change optical depth/optical depth*/ 00421 /* this can drive oscillations in very neutral gas, as blr92.in, blr89.in 00422 * or nova.in, when higher lyman lines have produce 00423 * t->dTau * radius.drad_x_fillfac about unity, where small changes in 00424 * pump can change ionization, dTau, and hence pump */ 00425 /*if( t->dTau * radius.drad_x_fillfac > 1e-8 )*/ 00426 /* >>chng 02 jun 14, nova.in again - upper limit had been 10 - but 00427 * there were major jumps in heating rate at this point - increase 10 -> 1e10 00428 * not clear why there should be an upper limit at all, other than to save time? */ 00429 /* update dTau since affects pump rate */ 00430 /* >>chng 03 jun 18, include option to not shield across this zone */ 00431 /* >>chng 03 jul 19, add continuum opacity */ 00432 dTau = (t->Emis->PopOpc * t->Emis->opacity / DoppVel.doppler[nelem] + opac.opacity_abs[t->ipCont-1])* 00433 radius.drad_x_fillfac_mean; 00434 /* >>chng 04 mar 04, do not want to include maser action across this zone */ 00435 dTau = MIN2(1., dTau); 00436 /*if( 0 && lgShield_this_zone && dTau * radius.drad_x_fillfac > 1e-3 && dTau * radius.drad_x_fillfac < 1e10 )*/ 00437 /* >>chng 04 mar 04, use mean of past few zone thicknesses rather than 00438 * current zone thickness since this can induce wild oscillations, see 00439 * nova.in test case */ 00440 if( lgShield_this_zone && dTau > 1e-3 && dTau < 1e10 ) 00441 { 00442 /* during very first search dTau is -1e38*/ 00443 /* >>chng 04 mar 04, use mean, see above comment */ 00444 /*t->pump *= log(1. + dTau * radius.drad_x_fillfac ) / (dTau * radius.drad_x_fillfac);*/ 00445 t->Emis->pump *= log(1. + dTau ) / dTau; 00446 } 00447 00448 /* >>chng 00 Oct 03, add pumping by local diffuse continuum, 00449 * rfield.DiffPumpOn is unity unless process disabled by setting to 0 in parsedont.c 00450 * with no DIFFuse LINE PUMPing command */ 00451 if( dTau*rfield.DiffPumpOn > SMALLFLOAT ) 00452 { 00453 /* >>chng 02 mar 14, added brackets around scale*rfield.OccNumbDiffCont so 00454 * that smallest and largest number are multiplied first to prevent overflow, PvH */ 00455 double scale; 00456 if( iteration > 1 ) 00457 { 00458 if( lgGoodTau ) 00459 { 00460 /* >>chng 03 jul 19, add check for tau = 1 in continuum */ 00461 /* scale for tau = 1 in the continuum */ 00462 double scale_con = 1. / SDIV(opac.opacity_abs[t->ipCont-1]+opac.opacity_sct[t->ipCont-1]); 00463 /* inward looking depth, dTau is opacity in line, cm^-1, 00464 * so multiplying by this scale is same as dividing by opacity in 00465 * source function */ 00466 double scale_in = MIN3( 1./ dTau , radius.depth , scale_con); 00467 double scale_out = MIN3( 1./ dTau , radius.Depth2Go , scale_con ); 00468 t->Emis->pump += t->Emis->Aul * t->Hi->g / t->Lo->g * 0.5 *((scale_in+scale_out)* 00469 rfield.OccNumbDiffCont[t->ipCont-1]); 00470 } 00471 } 00472 else 00473 { 00474 /* >>chng 03 jul 19, add check for tau = 1 in continuum */ 00475 /* scale for tau = 1 in the continuum */ 00476 double scale_con = 1. / SDIV(opac.opacity_abs[t->ipCont-1]+opac.opacity_sct[t->ipCont-1]); 00477 /* first iteration, only inward looking depths really known */ 00478 scale = 1./ dTau; 00479 scale = MIN3( scale , radius.depth , scale_con ); 00480 t->Emis->pump += t->Emis->Aul * t->Hi->g / t->Lo->g * (scale* 00481 rfield.OccNumbDiffCont[t->ipCont-1]); 00482 } 00483 } 00484 /* this stop oscillations from developing in very deep blr models 00485 * like blr89 and blr98, but must not be applied too early since 00486 * line optical depths change greatly in first few zones */ 00487 if( nzone>50 ) 00488 t->Emis->pump = (pumpsave + t->Emis->pump) / 2.; 00489 } 00490 00491 00492 /* escape following scattering off an electron */ 00493 /* this is turned off with the no scattering escape command */ 00494 if( !rt.lgElecScatEscape ) 00495 { 00496 t->Emis->Pelec_esc = 0.; 00497 } 00498 else 00499 { 00500 /* in the transition structure PopOpc is the pop relative to the ion, 00501 * but has been converted to a physical population before this routine 00502 * was called. No need to convert here */ 00503 double opac_line = t->Emis->PopOpc * t->Emis->opacity/DoppVel.doppler[nelem]; 00504 00505 if( opac_line > SMALLFLOAT ) 00506 { 00507 /* the old escape probability */ 00508 double eesc_save = t->Emis->Pelec_esc; 00509 /* the opacity in electron scattering */ 00510 double es = dense.eden*6.65e-25; 00511 fixit(); // should we use total opacity here instead of opac_line? 00512 /* this is equation 5 of 00513 *>>refer line desp Netzer, H., Elitzur, M., & Ferland, G. J. 1985, ApJ, 299, 752*/ 00514 double opacity_ratio = es/(es+opac_line) * (1.-t->Emis->Pesc); 00515 /* keep total probability not more than 1. */ 00516 t->Emis->Pelec_esc = (realnum)opacity_ratio * MAX2(0.f,1.f-t->Emis->Pesc-t->Emis->Pdest); 00517 /*KLUDGE >>chng 03 feb 02 00518 * take mean of old and new if electron scattering escape */ 00519 if( !conv.lgSearch ) 00520 t->Emis->Pelec_esc = t->Emis->Pelec_esc*0.75f + (realnum)eesc_save*0.25f; 00521 } 00522 else 00523 t->Emis->Pelec_esc = 0.; 00524 } 00525 00526 /* >>>chng 99 dec 18, did not have the test for lgGoodTau, and so clobbered 00527 * dest prob when overrun */ 00528 /* only do this if not Lya special case, since dest prob already done */ 00529 if( lgGoodTau && t->Emis->iRedisFun!=ipLY_A && t->Emis->opacity > 0. ) 00530 { 00531 double DestSave = t->Emis->Pdest; 00532 t->Emis->Pdest = (realnum)RT_DestProb( 00533 /* the abundance of the species */ 00534 t->Emis->PopOpc, 00535 /* line center opacity in funny units (needs a vel) */ 00536 t->Emis->opacity, 00537 /* array index for line in continuum array, 00538 * on f not c scale */ 00539 t->ipCont, 00540 /* line width in velocity units */ 00541 DoppVel.doppler[nelem], 00542 /* escape probability */ 00543 t->Emis->Pesc, 00544 /* redistribution function */ 00545 nRedis); 00546 00547 /* >>chng 03 may 10, this had been 3/4 new + 1/4 old, but had to be combined 00548 ^ with half and half when this routine was called, to converge very high Z high U 00549 * quasar models. bring all these factors together here */ 00550 /*t->Pdest = 0.75f*t->Pdest + 0.25f * DestSave;*/ 00551 # define OLDFAC (0.625) 00552 if( nzone>1 ) 00553 t->Emis->Pdest = (realnum)((1.-OLDFAC)*t->Emis->Pdest + OLDFAC * DestSave); 00554 } 00555 00556 /* zero escape probability and pumping term if energy is below plasma frequency */ 00557 if( t->EnergyErg / EN1RYD < rfield.plsfrq ) 00558 { 00559 t->Emis->Pesc = 0.; 00560 t->Emis->Pdest = 0.; 00561 t->Emis->pump = 0.; 00562 } 00563 00564 return; 00565 } 00566 00567 #if 0 00568 /*RT_line_wind do line radiative transfer for wind geometry */ 00569 STATIC void RT_line_wind(transition * t , bool lgDoEsc); 00570 /*RT_line_wind do line radiative transfer for wind geometry */ 00571 STATIC void RT_line_wind(transition * t , bool lgDoEsc) 00572 { 00573 realnum velocity; 00574 00575 DEBUG_ENTRY( "RT_line_wind()" ); 00576 00577 /* 00578 * this is the routine that computes much of the radiative transfer 00579 * physics for lines in wind case. Lines diveded into two types, 00580 * high quality (level1) and lower quality (atom_level2) g-bar lines 00581 */ 00582 00583 /* >>chng 01 aug 18, do not evaluation if no population */ 00584 /* >>chng 01 oct 25, add test for lgDoEsc, this is to make sure 00585 * that rates are evaluated at start of a new iteration */ 00586 if( dense.xIonDense[ t->nelem-1][t->IonStg-1] == 0. && !lgDoEsc ) 00587 { 00588 /* zero population, return after setting everything with side effects */ 00589 t->Pesc = 1.f; 00590 00591 /* inward escaping fraction */ 00592 t->FracInwd = 0.5; 00593 00594 /* pumping rate */ 00595 t->pump = 0.; 00596 00597 /* destruction probability */ 00598 t->Pdest = 0.; 00599 t->Pelec_esc = 0.; 00600 return; 00601 } 00602 00603 /*confirm pops and cs ok */ 00604 ASSERT( t->ColOvTot <= 1. && t->ColOvTot >= 0. ); 00605 00606 /* t->nelem is atomic number of species */ 00607 ASSERT( t->nelem >= 1 && t->ipCont > 0 ); 00608 00609 /* line width, thermal + turbulence */ 00610 velocity = DoppVel.doppler[t->nelem-1]; 00611 00612 t->damp = 0.; 00613 00614 /* use only one-sided escape probabilities 00615 * get escape probability, this gets fractions too */ 00616 if( lgDoEsc ) 00617 { 00618 t->Pesc = esc_CRDwing_1side(t->TauIn,t->damp); 00619 00620 /* inward fraction */ 00621 t->FracInwd = 0.5; 00622 00623 /* continuum pumping */ 00624 if( rfield.lgInducProcess ) 00625 { 00626 /* >>chng 05 feb 16, include diffuse outward emission */ 00627 /*t->pump = t->Aul*t->gHi/t->gLo*t->Pesc* 00628 rfield.OccNumbIncidCont[t->ipCont-1];*/ 00629 t->pump = t->Aul*t->gHi/t->gLo*t->Pesc*( 00630 rfield.OccNumbIncidCont[t->ipCont-1] + rfield.OccNumbContEmitOut[t->ipCont-1]); 00631 } 00632 else 00633 { 00634 t->pump = 0.; 00635 } 00636 } 00637 00638 /* get destruction probability */ 00639 t->Pdest = 00640 RT_DestProb( 00641 t->PopOpc, 00642 /* its line absorption cross section */ 00643 t->opacity, 00644 /* index for line in continuum array, on f not c scale */ 00645 t->ipCont, 00646 velocity, 00647 t->Pesc, 00648 ipDEST_K2); 00651 return; 00652 } 00653 #endif 00654