00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "cddefines.h"
00011 #include "physconst.h"
00012 #include "iso.h"
00013 #include "extinc.h"
00014 #include "noexec.h"
00015 #include "ionbal.h"
00016 #include "hextra.h"
00017 #include "trace.h"
00018 #include "dense.h"
00019 #include "oxy.h"
00020 #include "prt.h"
00021 #include "heavy.h"
00022 #include "rfield.h"
00023 #include "phycon.h"
00024 #include "called.h"
00025 #include "hydrogenic.h"
00026 #include "timesc.h"
00027 #include "secondaries.h"
00028 #include "opacity.h"
00029 #include "thermal.h"
00030 #include "ipoint.h"
00031 #include "atmdat.h"
00032 #include "rt.h"
00033 #include "radius.h"
00034 #include "geometry.h"
00035 #include "grainvar.h"
00036 #include "continuum.h"
00037
00038
00039 static double aweigh[4]={-0.4305682,-0.1699905, 0.1699905, 0.4305682};
00040 static double fweigh[4]={ 0.1739274, 0.3260726, 0.3260726, 0.1739274};
00041
00042
00043 STATIC void conorm(void);
00044
00045
00046 STATIC double pintr(double penlo,
00047 double penhi);
00048
00049
00050 STATIC double qintr(double *qenlo,
00051 double *qenhi);
00052
00053
00054
00055 STATIC void sumcon(long int il,
00056 long int ih,
00057 realnum *q,
00058 realnum *p,
00059 realnum *panu);
00060
00061
00062 STATIC void extin(realnum *ex1ryd);
00063
00064
00065 STATIC void ptrcer(void);
00066
00067
00068
00069 int ContSetIntensity(void)
00070 {
00071 bool lgCheckOK;
00072
00073 long int i,
00074 ip,
00075 j,
00076 n;
00077
00078 realnum EdenHeav,
00079 ex1ryd,
00080 factor,
00081 occ1,
00082 p,
00083 p1,
00084 p2,
00085 p3,
00086 p4,
00087 p5,
00088 p6,
00089 p7,
00090 pgn,
00091 phe,
00092 pheii,
00093 qgn;
00094
00095 realnum xIoniz;
00096
00097 double HCaseBRecCoeff,
00098 wanu[4],
00099 alf,
00100 bet,
00101 fntest,
00102 fsum,
00103 ecrit,
00104 tcompr,
00105 tcomp,
00106 RatioIonizToRecomb,
00107 r3ov2;
00108
00109 double amean,
00110 amean2,
00111 amean3,
00112 peak,
00113 wfun[4];
00114
00115
00116 double frac_beam_time , frac_beam_time1;
00117
00118 double frac_beam_const , frac_beam_const1;
00119
00120 double frac_isotropic , frac_isotropic1;
00121
00122 long int nelem , ion;
00123
00124 DEBUG_ENTRY( "ContSetIntensity()" );
00125
00126
00127 if( trace.lgTrace )
00128 {
00129 fprintf( ioQQQ, " ContSetIntensity called.\n" );
00130 }
00131
00132
00133
00134 conorm();
00135
00136
00137
00138 factor = (realnum)(EN1RYD/PI4/FR1RYD/HNU3C2);
00139
00140
00141 lgCheckOK = true;
00142
00143 for( i=0; i < rfield.nupper; i++ )
00144 {
00145
00146 rfield.anu[i] = rfield.AnuOrg[i];
00147 rfield.ContBoltz[i] = 0.;
00148 fsum = 0.;
00149 amean = 0.;
00150 amean2 = 0.;
00151 amean3 = 0.;
00152 frac_beam_time = 0.;
00153 frac_beam_const = 0.;
00154 frac_isotropic = 0.;
00155
00156 for( j=0; j < 4; j++ )
00157 {
00158
00159 wanu[j] = rfield.anu[i] + rfield.widflx[i]*aweigh[j];
00160
00161
00162 wanu[j] = MAX2( wanu[j] , rfield.emm );
00163 wanu[j] = MIN2( wanu[j] , rfield.egamry );
00164
00165
00166
00167 if( i > 0 && i < rfield.nupper-1 )
00168 {
00169 wanu[j] = MAX2( wanu[j] , rfield.anu[i-1] + 0.5*rfield.widflx[i-1] );
00170 wanu[j] = MIN2( wanu[j] , rfield.anu[i+1] - 0.5*rfield.widflx[i+1] );
00171 }
00172
00173 wfun[j] = fweigh[j]*ffun(wanu[j] ,
00174 &frac_beam_time1 ,
00175 &frac_beam_const1 ,
00176 &frac_isotropic1 );
00177
00178
00179
00180 fsum += wfun[j];
00181 amean += wanu[j]*wfun[j];
00182 amean2 += wanu[j]*wanu[j]*wfun[j];
00183 amean3 += wanu[j]*wanu[j]*wanu[j]*wfun[j];
00184 frac_beam_time += fweigh[j]*frac_beam_time1;
00185 frac_beam_const += fweigh[j]*frac_beam_const1;
00186 frac_isotropic += fweigh[j]*frac_isotropic1;
00187 }
00188
00189 ASSERT( fabs( 1.-frac_beam_time-frac_beam_const-frac_isotropic)<
00190 10.*FLT_EPSILON);
00191
00192 if( fsum*rfield.widflx[i] > BIGFLOAT )
00193 {
00194 fprintf( ioQQQ, "\n Cannot continue. The continuum is far too intense.\n" );
00195 for( j=0; j < rfield.nspec; j++ )
00196 {
00197 if( (wfun[j]*rfield.widflx[i] > BIGFLOAT) && ( rfield.nspec > 1 ) )
00198 {
00199 fprintf( ioQQQ, " Problem is with source number %li\n", j );
00200 break;
00201 }
00202 }
00203 cdEXIT(EXIT_FAILURE);
00204 }
00205
00206 rfield.flux[i] = (realnum)(fsum*rfield.widflx[i]);
00207
00208
00209
00210 rfield.flux_beam_const[i] = rfield.flux[i] * (realnum)frac_beam_const;
00211 rfield.flux_beam_time[i] = rfield.flux[i] * (realnum)frac_beam_time;
00212 rfield.flux_isotropic[i] = rfield.flux[i] * (realnum)frac_isotropic;
00213
00214 if( rfield.flux[i] > 0. )
00215 {
00216
00217
00218 rfield.anu[i] = (realnum)(amean2/amean);
00219 rfield.anu2[i] = (realnum)(amean3/amean);
00220
00221 if( i > 0 && rfield.anu[i] <= rfield.anu[i-1] )
00222 {
00223
00224
00225
00226 rfield.anu[i] = rfield.anu[i-1]*(1.f+2.f*FLT_EPSILON);
00227 rfield.anu2[i] = pow2(rfield.anu[i]);
00228 }
00229 ASSERT( i==0 || rfield.anu[i] > rfield.anu[i-1] );
00230
00231 rfield.anulog[i] = (realnum)log10(rfield.anu[i]);
00232 }
00233
00234 else if( rfield.flux[i] == 0. )
00235 {
00236 rfield.anu2[i] = rfield.anu[i]*rfield.anu[i];
00237 rfield.anulog[i] = (realnum)log10(rfield.anu[i]);
00238 }
00239
00240 else
00241 {
00242 rfield.anu2[i] = rfield.anu[i]*rfield.anu[i];
00243 fprintf( ioQQQ, " negative continuum returned at%6ld%10.2e%10.2e\n",
00244 i, rfield.anu[i], rfield.flux[i] );
00245 lgCheckOK = false;
00246 }
00247 rfield.anu3[i] = rfield.anu2[i]*rfield.anu[i];
00248
00249 rfield.ConEmitReflec[i] = 0.;
00250 rfield.ConEmitOut[i] = 0.;
00251 rfield.convoc[i] = factor/rfield.widflx[i]/rfield.anu2[i];
00252
00253
00254 alf = 1./(1. + rfield.anu[i]*(1.1792e-4 + 7.084e-10*rfield.anu[i]));
00255 bet = 1. - alf*rfield.anu[i]*(1.1792e-4 + 2.*7.084e-10*rfield.anu[i])/
00256 4.;
00257 rfield.csigh[i] = (realnum)(alf*rfield.anu2[i]*3.858e-25);
00258 rfield.csigc[i] = (realnum)(alf*bet*rfield.anu[i]*3.858e-25);
00259 }
00260
00261
00262
00263
00264
00265
00266
00267 #if 0
00268
00269
00270 for( i=1; i<rfield.nupper-1; ++i )
00271 {
00272
00273 rfield.widflx[i] = ((rfield.anu[i+1] - rfield.anu[i]) + (rfield.anu[i] - rfield.anu[i-1]))/2.f;
00274 }
00275 #endif
00276
00277 if( !lgCheckOK )
00278 {
00279 ShowMe();
00280 cdEXIT(EXIT_FAILURE);
00281 }
00282
00283 if( trace.lgTrace && trace.lgComBug )
00284 {
00285 fprintf( ioQQQ, "\n\n Compton heating, cooling coefficients \n" );
00286 for( i=0; i < rfield.nupper; i += 2 )
00287 {
00288 fprintf( ioQQQ, "%6ld%10.2e%10.2e%10.2e", i, rfield.anu[i],
00289 rfield.csigh[i], rfield.csigc[i] );
00290 }
00291 fprintf( ioQQQ, "\n" );
00292 }
00293
00294
00295
00296 if( trace.lgPtrace )
00297 ptrcer();
00298
00299
00300 extin(&ex1ryd);
00301
00302
00303
00304 prt.ipeak = 1;
00305 peak = 0.;
00306
00307 for( i=iso.ipIsoLevNIonCon[ipH_LIKE][ipHYDROGEN][ipH1s]-1; i < rfield.nupper; i++ )
00308 {
00309 if( rfield.flux[i]*rfield.anu[i]/rfield.widflx[i] > (realnum)peak )
00310 {
00311
00312
00313
00314 prt.ipeak = i+1;
00315 peak = rfield.flux[i]*rfield.anu[i]/rfield.widflx[i];
00316 }
00317 }
00318
00319
00320
00321 peak = rfield.flux[prt.ipeak-1]/rfield.widflx[prt.ipeak-1]*
00322 rfield.anu2[prt.ipeak-1];
00323
00324
00325 if( trace.lgTrace )
00326 {
00327 fprintf( ioQQQ, " ContSetIntensity: The peak of the H-ion continuum is at %.3e Ryd - its value is %.2e\n",
00328 rfield.anu[prt.ipeak-1] , peak);
00329 }
00330
00331 if( peak > 1e38 )
00332 {
00333 fprintf( ioQQQ, " PROBLEM DISASTER The continuum is too intense to compute. Use a fainter continuum. (This is the nu*f_nu test)\n" );
00334 fprintf( ioQQQ, " Sorry.\n" );
00335 cdEXIT(EXIT_FAILURE);
00336 }
00337
00338
00339
00340
00341
00342 fntest = peak*rfield.FluxFaint;
00343 {
00344 enum {DEBUG_LOC=false};
00345
00346 if( DEBUG_LOC )
00347 {
00348 for( i=0; i<rfield.nupper; ++i )
00349 {
00350 fprintf(ioQQQ," consetintensityBUGGG\t%.2e\t%.2e\n" ,
00351 rfield.anu[i] , rfield.flux[i]/rfield.widflx[i] );
00352 }
00353 cdEXIT(EXIT_SUCCESS);
00354 }
00355 }
00356
00357 if( fntest > 0. )
00358 {
00359
00360
00361 i = rfield.nupper;
00362
00363
00364 while( i > prt.ipeak+3 &&
00365 rfield.flux[i-1]*rfield.anu2[i-1]/rfield.widflx[i-1] < (realnum)fntest )
00366 {
00367 --i;
00368 }
00369 }
00370 else
00371 {
00372
00373
00374
00375 i = iso.ipIsoLevNIonCon[ipH_LIKE][ipHYDROGEN][ipH1s]+3;
00376 }
00377
00378
00379
00380
00381
00382
00383
00384
00385 rfield.nflux = i;
00386
00387
00388
00389
00390 while( rfield.flux[rfield.nflux-1] < SMALLFLOAT && rfield.nflux > 1 )
00391 {
00392 --rfield.nflux;
00393 }
00394
00395 ++rfield.nflux;
00396
00397 if( rfield.nflux == 1 )
00398 {
00399 fprintf( ioQQQ, " PROBLEM DISASTER This incident continuum appears to have no radiation.\n" );
00400 fprintf( ioQQQ, " Sorry.\n" );
00401 cdEXIT(EXIT_FAILURE);
00402 }
00403
00404
00405
00406 rfield.nflux = MIN2( rfield.nupper-1 , rfield.nflux );
00407
00408
00409
00410 rfield.nfine = rfield.nfine_malloc;
00411 while( rfield.nfine > 0 && rfield.fine_anu[rfield.nfine-1] > rfield.anu[rfield.nflux-1] )
00412 {
00413 --rfield.nfine;
00414 }
00415
00416
00417 continuum.lgCon0 = false;
00418 ip = 0;
00419 for( i=0; i < rfield.nflux; i++ )
00420 {
00421 if( rfield.flux[i] == 0. )
00422 {
00423 if( called.lgTalk && !continuum.lgCon0 )
00424 {
00425 fprintf( ioQQQ, " NOTE Setcon: continuum has zero intensity starting at %11.4e Ryd.\n",
00426 rfield.anu[i] );
00427 continuum.lgCon0 = true;
00428 }
00429 ++ip;
00430 }
00431 }
00432
00433 if( continuum.lgCon0 && called.lgTalk )
00434 {
00435 fprintf( ioQQQ,
00436 "%6ld cells in the incident continuum have zero intensity. Problems???\n\n",
00437 ip );
00438 }
00439
00440
00441 lgCheckOK = true;
00442 for( i=1; i < rfield.nflux; i++ )
00443 {
00444 if( rfield.flux[i] < 0. )
00445 {
00446 fprintf( ioQQQ,
00447 " PROBLEM DISASTER Continuum has negative intensity at %.4e Ryd=%.2e %4.4s %4.4s\n",
00448 rfield.anu[i], rfield.flux[i], rfield.chLineLabel[i], rfield.chContLabel[i] );
00449 lgCheckOK = false;
00450 }
00451 else if( rfield.anu[i] <= rfield.anu[i-1] )
00452 {
00453 fprintf( ioQQQ,
00454 " PROBLEM DISASTER cont_setintensity - internal error - continuum energies not in increasing order: energies follow\n" );
00455 fprintf( ioQQQ,
00456 "%ld %e %ld %e %ld %e\n",
00457 i -1 , rfield.anu[i-1], i, rfield.anu[i], i +1, rfield.anu[i+1] );
00458 lgCheckOK = false;
00459 }
00460 }
00461
00462
00463 if( !lgCheckOK )
00464 {
00465 ShowMe();
00466 cdEXIT(EXIT_FAILURE);
00467 }
00468
00469
00470 if( rfield.anu[rfield.nflux-1] <= 190 )
00471 {
00472 ionbal.lgCompRecoil = false;
00473 }
00474
00475
00476
00477
00478 sumcon(1,iso.ipIsoLevNIonCon[ipH_LIKE][ipHYDROGEN][ipH2p]-1,&rfield.qrad,&prt.pradio,&p1);
00479
00480
00481 sumcon(iso.ipIsoLevNIonCon[ipH_LIKE][ipHYDROGEN][2],iso.ipIsoLevNIonCon[ipH_LIKE][ipHYDROGEN][ipH1s]-1,&rfield.qbal,&prt.pbal,&p1);
00482
00483
00484 sumcon(iso.ipIsoLevNIonCon[ipH_LIKE][ipHYDROGEN][ipH1s],
00485 iso.ipIsoLevNIonCon[ipHE_LIKE][ipHELIUM][0]-1,&prt.q,&p,&p2);
00486
00487
00488 sumcon(iso.ipIsoLevNIonCon[ipHE_LIKE][ipHELIUM][0],
00489 iso.ipIsoLevNIonCon[ipH_LIKE][1][ipH1s]-1,&rfield.qhe,&phe,&p3);
00490
00491
00492 sumcon(iso.ipIsoLevNIonCon[ipH_LIKE][1][ipH1s],opac.ipCKshell-1,&rfield.qheii,&pheii,&p4);
00493
00494
00495 sumcon( opac.ipCKshell , rfield.ipEnerGammaRay-1 , &prt.qx,
00496 &prt.xpow , &p5);
00497
00498
00499 sumcon(rfield.ipEnerGammaRay,rfield.nflux,&prt.qgam,&prt.GammaLumin, &p6);
00500
00501
00502 n = ipoint(7.35e5);
00503 sumcon(n,rfield.nflux,&qgn,&pgn,&p7);
00504 timesc.TimeErode = qgn;
00505
00506
00507 tcompr = (p1 + p2 + p3 + p4 + p5 + p6)/(prt.pradio + prt.pbal +
00508 p + phe + pheii + prt.xpow + prt.GammaLumin);
00509
00510 tcomp = tcompr/(4.*6.272e-6);
00511
00512 if( trace.lgTrace )
00513 {
00514 fprintf( ioQQQ,
00515 " mean photon energy=%10.3eR =%10.3eK low, high nu=%12.4e%12.4e\n",
00516 tcompr, tcomp, rfield.anu[0] - rfield.widflx[0]/2., rfield.anu[rfield.nflux-1] +
00517 rfield.widflx[rfield.nflux-1]/2. );
00518 }
00519
00520
00521 prt.powion = p + phe + pheii + prt.xpow + prt.GammaLumin;
00522
00523
00524 continuum.TotalLumin = prt.pradio + prt.powion + prt.pbal;
00525
00526
00527
00528
00529 continuum.totlsv = continuum.TotalLumin;
00530
00531
00532 rfield.qhtot = prt.q + rfield.qhe + rfield.qheii + prt.qx + prt.qgam;
00533
00534
00535 rfield.qtot = rfield.qhtot + rfield.qbal + rfield.qrad;
00536
00537 if( prt.powion <= 0. && called.lgTalk )
00538 {
00539 rfield.lgHionRad = true;
00540 fprintf( ioQQQ, " NOTE There is no hydrogen-ionizing radiation.\n" );
00541 fprintf( ioQQQ, " Was this intended?\n\n" );
00542
00543
00544 if( prt.pbal <=0. && called.lgTalk )
00545 {
00546 fprintf( ioQQQ, " NOTE There is no Balmer continuum radiation.<<<<\n" );
00547 fprintf( ioQQQ, " Was this intended?\n\n" );
00548 }
00549 }
00550
00551 else
00552 {
00553 rfield.lgHionRad = false;
00554 }
00555
00556
00557
00558 if( hextra.lgNeutrnHeatOn )
00559 {
00560
00561
00562 hextra.totneu = (realnum)(hextra.effneu*continuum.TotalLumin*
00563 pow((realnum)10.f,hextra.frcneu));
00564 }
00565 else
00566 {
00567 hextra.totneu = (realnum)0.;
00568 }
00569
00570
00571 phycon.TEnerDen = pow(continuum.TotalLumin/SPEEDLIGHT/7.56464e-15,0.25);
00572
00573
00574
00575 if( rfield.nspec==1 &&
00576 strcmp( rfield.chSpType[rfield.nspec-1], "BLACK" )==0 )
00577 {
00578
00579
00580
00581
00582
00583 if( phycon.TEnerDen > 1.0001f*rfield.slope[rfield.nspec-1] )
00584 {
00585 fprintf( ioQQQ,
00586 "\n WARNING: The energy density temperature (%g) is greater than the"
00587 " black body temperature (%g). This is unphysical.\n\n",
00588 phycon.TEnerDen , rfield.slope[rfield.nspec-1]);
00589 }
00590 }
00591
00592
00593 continuum.cn4861 = (realnum)(ffun(0.1875)*HPLANCK*FR1RYD*0.1875*0.1875);
00594 continuum.cn1216 = (realnum)(ffun(0.75)*HPLANCK*FR1RYD*0.75*0.75);
00595 continuum.sv4861 = continuum.cn4861;
00596 continuum.sv1216 = continuum.cn1216;
00597
00598 continuum.fluxv = (realnum)(ffun(0.1643)*HPLANCK*0.1643);
00599 continuum.fbeta = (realnum)(ffun(0.1875)*HPLANCK*0.1875*6.167e14);
00600
00601
00602
00603 prt.fx1ryd = (realnum)(ffun(1.000)*HPLANCK*ex1ryd*FR1RYD);
00604
00605
00606
00607
00608
00609 ecrit = POW2(rfield.anu[0]/2.729e-12);
00610
00611 if( dense.gas_phase[ipHYDROGEN]*1.2 > ecrit )
00612 {
00613 rfield.lgPlasNu = true;
00614 rfield.plsfrq = (realnum)(2.729e-12*sqrt(dense.gas_phase[ipHYDROGEN]*1.2));
00615 rfield.plsfrqmax = rfield.plsfrq;
00616 rfield.ipPlasma = ipoint(rfield.plsfrq);
00617
00618
00619 rfield.ipPlasmax = rfield.ipPlasma;
00620
00621
00622
00623
00624
00625 for( i=0; i < rfield.ipPlasma-1; i++ )
00626 {
00627
00628 rfield.ConRefIncid[i] = rfield.flux[i];
00629
00630 rfield.flux_beam_const[i] = 0.;
00631 rfield.flux_beam_time[i] = 0.;
00632 rfield.flux_isotropic[i] = 0.;
00633 rfield.flux[i] = rfield.flux_beam_const[i] + rfield.flux_beam_time[i] +
00634 rfield.flux_isotropic[i];
00635 }
00636 }
00637 else
00638 {
00639 rfield.lgPlasNu = false;
00640
00641
00642 rfield.ipPlasma = 1;
00643 rfield.plsfrqmax = 0.;
00644 rfield.plsfrq = 0.;
00645 }
00646
00647 if( rfield.ipPlasma > 1 && called.lgTalk )
00648 {
00649 fprintf( ioQQQ,
00650 " !The plasma frequency is %.2e Ryd. The incident continuum is set to 0 below this.\n",
00651 rfield.plsfrq );
00652 }
00653
00654 rfield.occmax = 0.;
00655 rfield.tbrmax = 0.;
00656 for( i=0; i < rfield.nupper; i++ )
00657 {
00658
00659 rfield.OccNumbIncidCont[i] = rfield.flux[i]*rfield.convoc[i];
00660 if( rfield.OccNumbIncidCont[i] > rfield.occmax )
00661 {
00662 rfield.occmax = rfield.OccNumbIncidCont[i];
00663 rfield.occmnu = rfield.anu[i];
00664 }
00665
00666 if( rfield.OccNumbIncidCont[i]*TE1RYD*rfield.anu[i] > rfield.tbrmax )
00667 {
00668 rfield.tbrmax = (realnum)(rfield.OccNumbIncidCont[i]*TE1RYD*rfield.anu[i]);
00669 rfield.tbrmnu = rfield.anu[i];
00670 }
00671
00672 rfield.flux_total_incident[i] = rfield.flux[i];
00673 rfield.flux_beam_const_save[i] = rfield.flux_beam_const[i];
00674 rfield.flux_time_beam_save[i] = rfield.flux_beam_time[i];
00675 rfield.flux_isotropic_save[i] = rfield.flux_isotropic[i];
00676
00677
00678
00679
00680
00681 }
00682
00683
00684
00685 if( rfield.tbrmax > 1e4 )
00686 {
00687 i = ipoint(rfield.tbrmnu)-1;
00688 while( i < rfield.nupper-1 && (rfield.OccNumbIncidCont[i]*TE1RYD*
00689 rfield.anu[i] > 1e4) )
00690 {
00691 ++i;
00692 }
00693 rfield.tbr4nu = rfield.anu[i];
00694 }
00695 else
00696 {
00697 rfield.tbr4nu = 0.;
00698 }
00699
00700
00701 if( rfield.occmax > 1. )
00702 {
00703 i = ipoint(rfield.occmnu)-1;
00704 while( i < rfield.nupper && (rfield.OccNumbIncidCont[i] > 1.) )
00705 {
00706 ++i;
00707 }
00708 rfield.occ1nu = rfield.anu[i];
00709 }
00710 else
00711 {
00712 rfield.occ1nu = 0.;
00713 }
00714
00715
00716
00717
00718
00719
00720
00721 if( (prt.powion + prt.pbal) < 1.8e-2 )
00722 {
00723
00724 rfield.lgHabing = true;
00725
00726 if( ((prt.powion + prt.pbal) < 1.8e-12) &&
00727
00728 (!thermal.lgTemperatureConstant) )
00729 {
00730 fprintf( ioQQQ, "\n >>>\n"
00731 " >>> NOTE The incident continuum is surprisingly faint.\n" );
00732 fprintf( ioQQQ,
00733 " >>> The total energy in the Balmer and Lyman continua is %.2e erg cm-2 s-1.\n"
00734 ,(prt.powion + prt.pbal));
00735 fprintf( ioQQQ, " >>> This is many orders of magnitude fainter than the ISM galactic background.\n" );
00736 fprintf( ioQQQ, " >>> This seems unphysical - please check that the continuum intensity has been properly set.\n" );
00737 fprintf( ioQQQ, " >>> YOU MAY BE MAKING A BIG MISTAKE!!\n >>>\n\n\n\n" );
00738 }
00739 }
00740
00741
00742 rfield.uh = (realnum)(rfield.qhtot/dense.gas_phase[ipHYDROGEN]/SPEEDLIGHT);
00743 rfield.uheii = (realnum)((rfield.qheii + prt.qx)/dense.gas_phase[ipHYDROGEN]/SPEEDLIGHT);
00744 if( rfield.uh > 1.e10 )
00745 {
00746 fprintf( ioQQQ, "\n >>>\n"
00747 " NOTE The incident continuum is surprisingly intense.\n" );
00748 fprintf( ioQQQ,
00749 " >>> The hydrogen ionization parameter is %.2e [dimensionless].\n"
00750 , rfield.uh );
00751 fprintf( ioQQQ, " This is many orders of magnitude brighter than commonly seen.\n" );
00752 fprintf( ioQQQ, " This seems unphysical - please check that the continuum intensity has been properly set.\n" );
00753 fprintf( ioQQQ, " YOU MAY BE MAKING A BIG MISTAKE!!\n >>>\n\n\n\n" );
00754 }
00755
00756
00757 if( thermal.ConstTemp > 0. )
00758 {
00759 phycon.te = thermal.ConstTemp;
00760 }
00761 else
00762 {
00763 if( rfield.uh > 0. )
00764 {
00765 phycon.te = (20000.+log10(rfield.uh)*5000.);
00766 phycon.te = MAX2(8000. , phycon.te );
00767 }
00768 else
00769 {
00770 phycon.te = 1000.;
00771 }
00772 }
00773
00774
00775 if( noexec.lgNoExec )
00776 return(0);
00777
00778
00779
00780
00781
00782
00783
00784 for( nelem=ipHYDROGEN; nelem<LIMELM; ++nelem )
00785 {
00786 for( ion=0; ion<nelem+1; ++ion )
00787 {
00788 secondaries.csupra[nelem][ion] =
00789 secondaries.SetCsupra + hextra.cryden*2e-9f;
00790 }
00791 }
00792
00793
00794
00795
00796
00797
00798
00799
00800 dense.xIonDense[ipHYDROGEN][0] = 0.;
00801 dense.xIonDense[ipHYDROGEN][1] = dense.gas_phase[ipHYDROGEN];
00802
00803 StatesElem[ipH_LIKE][ipHYDROGEN][ipH1s].Pop = 0.;
00804
00805
00806 double EdenExtraLocal = dense.EdenExtra +
00807
00808
00809 1e-7*dense.gas_phase[ipHYDROGEN];
00810 dense.eden = dense.xIonDense[ipHYDROGEN][1] + EdenExtraLocal;
00811
00812
00813 HCaseBRecCoeff = (-9.9765209 + 0.158607055*phycon.telogn[0] + 0.30112749*
00814 phycon.telogn[1] - 0.063969007*phycon.telogn[2] + 0.0012691546*
00815 phycon.telogn[3])/(1. + 0.035055422*phycon.telogn[0] -
00816 0.037621619*phycon.telogn[1] + 0.0076175048*phycon.telogn[2] -
00817 0.00023432613*phycon.telogn[3]);
00818 HCaseBRecCoeff = pow(10.,HCaseBRecCoeff)/phycon.te;
00819
00820 double CollIoniz = t_ADfA::Inst().coll_ion(1,1,phycon.te);
00821 double OtherIonization = rfield.qhtot*2e-18 + secondaries.csupra[ipHYDROGEN][0];
00822 double RatioIoniz =
00823 (CollIoniz*dense.eden+OtherIonization)/(HCaseBRecCoeff*dense.eden);
00824 if( RatioIoniz<1e-3 )
00825 {
00826
00827 dense.xIonDense[ipHYDROGEN][1] = (realnum)(
00828 dense.gas_phase[ipHYDROGEN]*RatioIoniz);
00829 dense.xIonDense[ipHYDROGEN][0] = dense.gas_phase[ipHYDROGEN] -
00830 dense.xIonDense[ipHYDROGEN][1];
00831 ASSERT( dense.xIonDense[ipHYDROGEN][0]>=0. &&
00832 dense.xIonDense[ipHYDROGEN][0]<=dense.gas_phase[ipHYDROGEN]);
00833 ASSERT( dense.xIonDense[ipHYDROGEN][1]>=0. &&
00834 dense.xIonDense[ipHYDROGEN][1]<dense.gas_phase[ipHYDROGEN]);
00835 }
00836 else if( RatioIoniz>1e3 )
00837 {
00838
00839 dense.xIonDense[ipHYDROGEN][0] = (realnum)(
00840 dense.gas_phase[ipHYDROGEN]/RatioIoniz);
00841 dense.xIonDense[ipHYDROGEN][1] = dense.gas_phase[ipHYDROGEN] -
00842 dense.xIonDense[ipHYDROGEN][0];
00843 ASSERT( dense.xIonDense[ipHYDROGEN][0]>=0. &&
00844 dense.xIonDense[ipHYDROGEN][0]<dense.gas_phase[ipHYDROGEN]);
00845 ASSERT( dense.xIonDense[ipHYDROGEN][1]>=0. &&
00846 dense.xIonDense[ipHYDROGEN][1]<=dense.gas_phase[ipHYDROGEN]);
00847 }
00848 else
00849 {
00850
00851 double alpha = HCaseBRecCoeff + CollIoniz ;
00852 double beta = HCaseBRecCoeff*EdenExtraLocal + OtherIonization -
00853 dense.gas_phase[ipHYDROGEN]*CollIoniz;
00854 double gamma = EdenExtraLocal*CollIoniz -
00855 dense.gas_phase[ipHYDROGEN]*(OtherIonization+EdenExtraLocal*CollIoniz);
00856
00857 double discriminant = POW2(beta) - 4.*alpha*gamma;
00858 if( discriminant <0 )
00859 {
00860
00861 fprintf(ioQQQ," DISASTER PROBLEM cont_initensity found negative discriminant.\n");
00862 TotalInsanity();
00863 }
00864
00865 dense.xIonDense[ipHYDROGEN][1] = (realnum)((-beta + sqrt(discriminant))/(2.*alpha));
00866 if( dense.xIonDense[ipHYDROGEN][1]> dense.gas_phase[ipHYDROGEN] )
00867 {
00868
00869 fprintf(ioQQQ," DISASTER PROBLEM cont_initensity found n(H+)>n(H).\n");
00870 TotalInsanity();
00871 }
00872 dense.xIonDense[ipHYDROGEN][0] = dense.gas_phase[ipHYDROGEN] -
00873 dense.xIonDense[ipHYDROGEN][1];
00874 if( dense.xIonDense[ipHYDROGEN][0]<= 0 )
00875 {
00876
00877 fprintf(ioQQQ," DISASTER PROBLEM cont_initensity found n(H0)<0.\n");
00878 TotalInsanity();
00879 }
00880 }
00881
00882 dense.eden = dense.xIonDense[ipHYDROGEN][1] + (realnum)EdenExtraLocal;
00883 if( dense.eden <= SMALLFLOAT )
00884 {
00885
00886 fprintf(ioQQQ,"\n PROBLEM DISASTER - this simulation has no source"
00887 " of ionization. The electron density is zero. Consider "
00888 "adding a source of ionization such as cosmic rays.\n\n");
00889 cdEXIT(EXIT_FAILURE);
00890 }
00891
00892 if( dense.xIonDense[ipHYDROGEN][1] > 1e-30 )
00893 {
00894 StatesElem[ipH_LIKE][ipHYDROGEN][ipH1s].Pop = dense.xIonDense[ipHYDROGEN][0]/dense.xIonDense[ipHYDROGEN][1];
00895 }
00896 else
00897 {
00898 StatesElem[ipH_LIKE][ipHYDROGEN][ipH1s].Pop = 0.;
00899 }
00900
00901
00902
00903
00904 hydro.lgHInducImp = false;
00905 for( i=ipH1s; i < iso.numLevels_max[ipH_LIKE][ipHYDROGEN]; i++ )
00906 {
00907 if( rfield.OccNumbIncidCont[iso.ipIsoLevNIonCon[ipH_LIKE][ipHYDROGEN][i]-1] > 0.01 )
00908 hydro.lgHInducImp = true;
00909 }
00910
00911
00912
00913
00914
00915
00916
00917
00918 if( dense.lgElmtOn[ipHELIUM] )
00919 {
00920
00921 xIoniz = (realnum)t_ADfA::Inst().coll_ion(2,2,phycon.te);
00922
00923 xIoniz = (realnum)(xIoniz*dense.eden + rfield.qhe*1e-18 + secondaries.csupra[ipHELIUM][1] );
00924 double RecTot = HCaseBRecCoeff*dense.eden;
00925 RatioIonizToRecomb = xIoniz/RecTot;
00926
00927
00928 xIoniz = (realnum)t_ADfA::Inst().coll_ion(2,1,phycon.te);
00929
00930 xIoniz = (realnum)(xIoniz*dense.eden + rfield.qheii*1e-18 + ionbal.CosRayIonRate );
00931
00932
00933 RecTot *= 4.;
00934 r3ov2 = xIoniz/RecTot;
00935
00936
00937 if( RatioIonizToRecomb > 0. )
00938 {
00939 dense.xIonDense[ipHELIUM][1] = (realnum)(dense.gas_phase[ipHELIUM]/(1./RatioIonizToRecomb + 1. + r3ov2));
00940 dense.xIonDense[ipHELIUM][0] = (realnum)(dense.xIonDense[ipHELIUM][1]/RatioIonizToRecomb);
00941 }
00942 else
00943 {
00944
00945 dense.xIonDense[ipHELIUM][1] = 0.;
00946 dense.xIonDense[ipHELIUM][0] = dense.gas_phase[ipHELIUM];
00947 }
00948
00949 dense.xIonDense[ipHELIUM][2] = (realnum)(dense.xIonDense[ipHELIUM][1]*r3ov2);
00950
00951 if( dense.xIonDense[ipHELIUM][2] > 1e-30 )
00952 {
00953 StatesElem[ipH_LIKE][1][ipH1s].Pop = dense.xIonDense[ipHELIUM][1]/dense.xIonDense[ipHELIUM][2];
00954 }
00955 else
00956 {
00957 StatesElem[ipH_LIKE][1][ipH1s].Pop = 0.;
00958 }
00959 }
00960 else
00961 {
00962
00963 dense.xIonDense[ipHELIUM][1] = 0.;
00964 dense.xIonDense[ipHELIUM][0] = 0.;
00965 dense.xIonDense[ipHELIUM][2] = 0.;
00966 StatesElem[ipH_LIKE][1][ipH1s].Pop = 0.;
00967 }
00968
00969
00970 dense.eden = dense.xIonDense[ipHYDROGEN][1] +
00971 dense.xIonDense[ipHELIUM][1] + 2.*dense.xIonDense[ipHELIUM][2];
00972
00973
00974 for( nelem=ipHYDROGEN; nelem < LIMELM; nelem++ )
00975 {
00976 if( dense.lgElmtOn[nelem] )
00977 {
00978 dense.IonLow[nelem] = 0;
00979
00980
00981
00982
00983
00984
00985 dense.IonHigh[nelem] = nelem + 1;
00986
00987
00988
00989
00990 if( dense.lgSetIoniz[nelem] )
00991 {
00992 while( dense.SetIoniz[nelem][dense.IonLow[nelem]] == 0. )
00993 ++dense.IonLow[nelem];
00994 while( dense.SetIoniz[nelem][dense.IonHigh[nelem]] == 0. )
00995 --dense.IonHigh[nelem];
00996 }
00997 }
00998 else
00999 {
01000
01001 dense.IonLow[nelem] = -1;
01002 dense.IonHigh[nelem] = -1;
01003 }
01004 }
01005
01006
01007
01008 EdenHeav = 0.;
01009 realnum atomFrac = dense.xIonDense[ipHYDROGEN][0]/dense.gas_phase[ipHYDROGEN];
01010 realnum firstIonFrac = dense.xIonDense[ipHYDROGEN][1]/dense.gas_phase[ipHYDROGEN];
01011 for( nelem=ipLITHIUM; nelem < LIMELM; nelem++ )
01012 {
01013 if( dense.lgElmtOn[nelem] )
01014 {
01015 dense.xIonDense[nelem][0] = dense.gas_phase[nelem] * atomFrac;
01016 dense.xIonDense[nelem][1] = dense.gas_phase[nelem] * firstIonFrac;
01017 EdenHeav += dense.xIonDense[nelem][1];
01018 }
01019 }
01020
01021
01022 dense.eden =
01023 dense.xIonDense[ipHYDROGEN][1] + dense.xIonDense[ipHELIUM][1] +
01024 2.*dense.xIonDense[ipHELIUM][2] + EdenHeav + dense.EdenExtra;
01025
01026 dense.eden = MAX2( SMALLFLOAT , dense.eden );
01027
01028 if( dense.EdenSet > 0. )
01029 {
01030 dense.eden = dense.EdenSet;
01031 }
01032
01033 dense.EdenHCorr = dense.eden;
01034
01035 if( dense.eden < 0. )
01036 {
01037 fprintf( ioQQQ, " PROBLEM DISASTER Negative electron density results in ContSetIntensity.\n" );
01038 fprintf( ioQQQ, "%10.2e%10.2e%10.2e%10.2e%10.2e%10.2e\n",
01039 dense.eden, dense.xIonDense[ipHYDROGEN][1], dense.xIonDense[ipHELIUM][1],
01040 dense.xIonDense[ipHELIUM][2], dense.gas_phase[ipCARBON], dense.EdenExtra );
01041 TotalInsanity();
01042 }
01043
01044 dense.EdenTrue = dense.eden;
01045
01046 if( trace.lgTrace )
01047 {
01048 fprintf( ioQQQ,
01049 " ContSetIntensity sets initial EDEN to %.4e, contributors H+=%.2e He+, ++= %.2e %.2e Heav %.2e extra %.2e\n",
01050 dense.eden ,
01051 dense.xIonDense[ipHYDROGEN][1],
01052 dense.xIonDense[ipHELIUM][1],
01053 2.*dense.xIonDense[ipHELIUM][2],
01054 EdenHeav,
01055 dense.EdenExtra);
01056 }
01057
01058
01059
01060
01061
01062 occ1 = (realnum)(prt.fx1ryd/HNU3C2/PI4/FR1RYD);
01063
01064
01065 if( occ1 > 1. )
01066 {
01067 rfield.lgOcc1Hi = true;
01068 }
01069 else
01070 {
01071 rfield.lgOcc1Hi = false;
01072 }
01073
01074 if( trace.lgTrace && trace.lgConBug )
01075 {
01076
01077 fprintf( ioQQQ, " H2,1=%5ld%5ld NX=%5ld IRC=%5ld\n",
01078 iso.ipIsoLevNIonCon[ipH_LIKE][ipHYDROGEN][2],
01079 iso.ipIsoLevNIonCon[ipH_LIKE][ipHYDROGEN][ipH1s],
01080 opac.ipCKshell,
01081 ionbal.ipCompRecoil[ipHYDROGEN][0] );
01082
01083 fprintf( ioQQQ, " CARBON" );
01084 for( i=0; i < 6; i++ )
01085 {
01086 fprintf( ioQQQ, "%5ld", Heavy.ipHeavy[ipCARBON][i] );
01087 }
01088 fprintf( ioQQQ, "\n" );
01089
01090 fprintf( ioQQQ, " OXY" );
01091 for( i=0; i < 8; i++ )
01092 {
01093 fprintf( ioQQQ, "%5ld", Heavy.ipHeavy[ipOXYGEN][i] );
01094 }
01095 fprintf( ioQQQ, "%5ld%5ld%5ld\n", opac.ipo3exc[0],
01096 oxy.i2d, oxy.i2p );
01097
01098 fprintf( ioQQQ,
01099 "\n\n PHOTONS PER CELL (NOT RYD)\n" );
01100 fprintf( ioQQQ,
01101 "\n\n nu, flux, wid, occ \n" );
01102 fprintf( ioQQQ,
01103 " " );
01104
01105 for( i=0; i < rfield.nflux; i++ )
01106 {
01107 fprintf( ioQQQ, "%4ld%10.2e%10.2e%10.2e%10.2e", i,
01108 rfield.anu[i], rfield.flux[i], rfield.widflx[i],
01109 rfield.OccNumbIncidCont[i] );
01110 }
01111 fprintf( ioQQQ, " \n" );
01112 }
01113
01114
01115
01116
01117 RT_OTS_Zero();
01118
01119
01120
01121 for( rfield.ipspec=0; rfield.ipspec < rfield.nspec; rfield.ipspec++ )
01122 {
01123 if( rfield.lgContMalloc[rfield.ipspec] )
01124 {
01125 free(rfield.tNuRyd[rfield.ipspec] );
01126 free(rfield.tslop[rfield.ipspec] );
01127 free(rfield.tFluxLog[rfield.ipspec] );
01128 rfield.lgContMalloc[rfield.ipspec] = false;
01129 }
01130 }
01131
01132 if( trace.lgTrace )
01133 {
01134 fprintf( ioQQQ, " ContSetIntensity returns, nflux=%5ld anu(nflux)=%11.4e eden=%10.2e\n",
01135 rfield.nflux, rfield.anu[rfield.nflux-1], dense.eden );
01136 }
01137
01138 return(0);
01139 }
01140
01141
01142 STATIC void sumcon(long int il,
01143 long int ih,
01144 realnum *q,
01145 realnum *p,
01146 realnum *panu)
01147 {
01148 long int i,
01149 iupper;
01150
01151 DEBUG_ENTRY( "sumcon()" );
01152
01153 *q = 0.;
01154 *p = 0.;
01155 *panu = 0.;
01156
01157
01158 iupper = MIN2(rfield.nflux,ih);
01159
01160
01161 for( i=il-1; i < iupper; i++ )
01162 {
01163
01164 *q += rfield.flux[i];
01165
01166
01167 *p += (realnum)(rfield.flux[i]*(rfield.anu[i]*EN1RYD));
01168
01169 *panu += (realnum)(rfield.flux[i]*(rfield.anu2[i]*EN1RYD));
01170 }
01171
01172 return;
01173 }
01174
01175
01176 STATIC void ptrcer(void)
01177 {
01178 char chCard[INPUT_LINE_LENGTH];
01179
01180 FILE * ioERRORS=NULL;
01181 bool lgEOL;
01182 char chKey;
01183 long int i,
01184 ipnt,
01185 j;
01186 double pnt,
01187 t1,
01188 t2;
01189
01190 DEBUG_ENTRY( "ptrcer()" );
01191
01192 fprintf( ioQQQ, " There are two ways to do this:\n");
01193 fprintf( ioQQQ, " do you want me to test all the pointers (enter y)\n");
01194 fprintf( ioQQQ, " or do you want to enter energies yourself? (enter n)\n" );
01195
01196 if( read_whole_line( chCard , (int)sizeof(chCard) , ioStdin ) == NULL )
01197 {
01198 fprintf( ioQQQ, " error getting input \n" );
01199 cdEXIT(EXIT_FAILURE);
01200 }
01201
01202
01203 chKey = chCard[0];
01204
01205 if( chKey == 'n' )
01206 {
01207
01208 fprintf( ioQQQ, " Enter energy (Ryd); 0 to stop; negative is log.\n" );
01209 pnt = 1.;
01210 while( pnt!=0. )
01211 {
01212 if( read_whole_line( chCard , (int)sizeof(chCard) , ioStdin ) == NULL )
01213 {
01214 fprintf( ioQQQ, " error getting input2 \n" );
01215 cdEXIT(EXIT_FAILURE);
01216 }
01217
01218 i = 1;
01219 pnt = FFmtRead(chCard,&i,INPUT_LINE_LENGTH,&lgEOL);
01220
01221
01222 if( lgEOL || pnt==0. )
01223 {
01224 break;
01225 }
01226
01227
01228 if( pnt < 0. )
01229 {
01230 pnt = pow(10.,pnt);
01231 }
01232
01233
01234 ipnt = ipoint(pnt);
01235 fprintf( ioQQQ, " Cell num%4ld center:%10.2e width:%10.2e low:%10.2e hi:%10.2e convoc:%10.2e\n",
01236 ipnt, rfield.anu[ipnt-1], rfield.widflx[ipnt-1],
01237 rfield.anu[ipnt-1] - rfield.widflx[ipnt-1]/2.,
01238 rfield.anu[ipnt-1] + rfield.widflx[ipnt-1]/2.,
01239 rfield.convoc[ipnt-1] );
01240 }
01241 }
01242
01243 else if( chKey == 'y' )
01244 {
01245
01246 if( rfield.anu[0] - rfield.widflx[0]/2.*0.9 < continuum.filbnd[0] )
01247 {
01248 fprintf( ioQQQ," ipoint would crash since lowest desired energy of %e ryd is below limit of %e\n",
01249 rfield.anu[0] - rfield.widflx[0]/2.*0.9 , continuum.filbnd[0] );
01250 fprintf( ioQQQ," width of cell is %e\n",rfield.widflx[0]);
01251 cdEXIT(EXIT_FAILURE);
01252 }
01253
01254 else if( rfield.anu[rfield.nflux-1] + rfield.widflx[rfield.nflux-1]/2.*0.9 >
01255 continuum.filbnd[continuum.nrange] )
01256 {
01257 fprintf( ioQQQ," ipoint would crash since highest desired energy of %e ryd is above limit of %e\n",
01258 rfield.anu[rfield.nflux-1] + rfield.widflx[rfield.nflux-1]/2.*0.9 ,
01259 continuum.filbnd[continuum.nrange-1] );
01260 fprintf( ioQQQ," width of cell is %e\n",rfield.widflx[rfield.nflux]);
01261 fprintf( ioQQQ," this, previous cells are %e %e\n",
01262 rfield.anu[rfield.nflux-1],rfield.anu[rfield.nflux-2]);
01263 cdEXIT(EXIT_FAILURE);
01264 }
01265
01266
01267 fprintf( ioQQQ, " errors output on errors.txt\n");
01268 fprintf( ioQQQ, " IP(cor),IP(fount),nu lower, upper of found, desired cell.\n" );
01269
01270
01271 ioERRORS = NULL;
01272 for( i=0; i < rfield.nflux-1; i++ )
01273 {
01274 t1 = rfield.anu[i] - rfield.widflx[i]/2.*0.9;
01275 t2 = rfield.anu[i] + rfield.widflx[i]/2.*0.9;
01276
01277 j = ipoint(t1);
01278 if( j != i+1 )
01279 {
01280
01281 if( ioERRORS == NULL )
01282 {
01283 ioERRORS = open_data( "errors.txt", "w", AS_LOCAL_ONLY );
01284 fprintf( ioQQQ," created errors.txt file with error summary\n");
01285 }
01286
01287 fprintf( ioQQQ, " Pointers do not agree for lower bound of cell%4ld, %e\n",
01288 i, rfield.anu[i]);
01289 fprintf( ioERRORS, " Pointers do not agree for lower bound of cell%4ld, %e\n",
01290 i, rfield.anu[i] );
01291 }
01292
01293 j = ipoint(t2);
01294 if( j != i+1 )
01295 {
01296
01297 if( ioERRORS == NULL )
01298 {
01299 ioERRORS = open_data( "errors.txt", "w", AS_LOCAL_ONLY );
01300 fprintf( ioQQQ," created errors.txt file with error summary\n");
01301 }
01302 fprintf( ioQQQ, " Pointers do not agree for upper bound of cell%4ld, %e\n",
01303 i , rfield.anu[i]);
01304 fprintf( ioERRORS, " Pointers do not agree for upper bound of cell%4ld, %e\n",
01305 i , rfield.anu[i]);
01306 }
01307
01308 }
01309 }
01310
01311 else
01312 {
01313 fprintf( ioQQQ, "I do not understand this key, sorry. %c\n", chKey );
01314 cdEXIT(EXIT_FAILURE);
01315 }
01316
01317 if( ioERRORS!=NULL )
01318 fclose( ioERRORS );
01319 cdEXIT(EXIT_FAILURE);
01320 }
01321
01322
01323 STATIC void extin(realnum *ex1ryd)
01324 {
01325 long int i,
01326 low;
01327 double absorb,
01328 factor;
01329
01330 DEBUG_ENTRY( "extin()" );
01331
01332
01333
01334
01335 if( extinc.excolm == 0. )
01336 {
01337 *ex1ryd = 1.;
01338 }
01339 else
01340 {
01341 absorb = 1. - extinc.exleak;
01342
01343
01344 factor = extinc.excolm*extinc.cnst_col2optdepth;
01345
01346 *ex1ryd = (realnum)(extinc.exleak + absorb*sexp(factor));
01347
01348 low = ipoint(extinc.exlow);
01349 for( i=low-1; i < rfield.nflux; i++ )
01350 {
01351 realnum extfactor = (realnum)(extinc.exleak + absorb*sexp(factor*
01352 (pow(rfield.anu[i],extinc.cnst_power))));
01353 rfield.flux_beam_const[i] *= extfactor;
01354 rfield.flux_beam_time[i] *= extfactor;
01355 rfield.flux_isotropic[i] *= extfactor;
01356 rfield.flux[i] = rfield.flux_beam_const[i] + rfield.flux_beam_time[i] +
01357 rfield.flux_isotropic[i];
01358 }
01359 }
01360 return;
01361 }
01362
01363
01364 STATIC void conorm(void)
01365 {
01366 long int i , nd;
01367 double xLog_radius_inner,
01368 diff,
01369 f,
01370 flx1,
01371 flx2,
01372 pentrd,
01373 qentrd;
01374
01375 DEBUG_ENTRY( "conorm()" );
01376
01377 xLog_radius_inner = log10(radius.Radius);
01378
01379
01380 for( i=0; i < rfield.nspec; i++ )
01381 {
01382 if( strcmp(rfield.chRSpec[i],"UNKN") == 0 )
01383 {
01384 fprintf( ioQQQ, " UNKN spectral normalization cannot happen.\n" );
01385 fprintf( ioQQQ, " conorm punts.\n" );
01386 cdEXIT(EXIT_FAILURE);
01387 }
01388
01389 else if( strcmp(rfield.chRSpec[i],"SQCM") != 0 &&
01390 strcmp(rfield.chRSpec[i],"4 PI") != 0 )
01391 {
01392 fprintf( ioQQQ, " chRSpec must be SQCM or 4 PI, and it was %4.4s. This cannot happen.\n",
01393 rfield.chRSpec[i] );
01394 fprintf( ioQQQ, " conorm punts.\n" );
01395 cdEXIT(EXIT_FAILURE);
01396 }
01397
01398
01399
01400
01401 if( strcmp(rfield.chSpType[i],"VOLK ") == 0 )
01402 {
01403
01404 ASSERT( rfield.AnuOrg[rfield.nupper-1]>0. );
01405
01406 diff = fabs(rfield.tNuRyd[i][rfield.nupper-1]-rfield.AnuOrg[rfield.nupper-1])/
01407 rfield.AnuOrg[rfield.nupper-1];
01408
01409
01410 if( diff > 10.*FLT_EPSILON )
01411 {
01412 if( continuum.ResolutionScaleFactor == 1. )
01413 {
01414 fprintf( ioQQQ, "%10.2e%10.2e\n", rfield.AnuOrg[rfield.nupper-1],
01415 rfield.tNuRyd[i][rfield.nupper-1] );
01416
01417 fprintf( ioQQQ,"conorm: The energy grid of the stellar atmosphere file does not agree with the grid in this version of the code.\n" );
01418 fprintf( ioQQQ,"A stellar atmosphere grid from an old version of the code is probably in place.\n" );
01419 fprintf( ioQQQ,"A grid for the current version of Cloudy must be generated and used.\n" );
01420 fprintf( ioQQQ,"This is done with the COMPILE STARS command.\n" );
01421 fprintf( ioQQQ,"Sorry.\n" );
01422
01423 cdEXIT(EXIT_FAILURE);
01424 }
01425 else
01426 {
01427 fprintf( ioQQQ,"\n\nThe continuum resolution has been chnaged with the SET CONTINUUM RESOLUTION command.\n" );
01428 fprintf( ioQQQ,"The compiled stellar continua are not consistent with this changed continuum.\n" );
01429 fprintf( ioQQQ,"Sorry.\n" );
01430 cdEXIT(EXIT_FAILURE);
01431 }
01432 }
01433 }
01434 }
01435
01436
01437
01438 for( nd=0; nd < gv.nBin; nd++ )
01439 {
01440 bool lgErrorFound = false;
01441
01442
01443 if( gv.bin[nd]->NFPCheck != rfield.nupper )
01444 {
01445 fprintf( ioQQQ,
01446 " conorm: expected:%ld found: %ld: number of frequency points in grains data do not match\n",
01447 rfield.nupper, gv.bin[nd]->NFPCheck );
01448 lgErrorFound = true;
01449 }
01450
01451
01452 ASSERT( rfield.AnuOrg[rfield.nupper-1]>0. );
01453
01454 diff = fabs( gv.bin[nd]->EnergyCheck - rfield.AnuOrg[rfield.nupper-1] )/
01455 rfield.AnuOrg[rfield.nupper-1];
01456
01457
01458
01459 if( diff > MAX2(10.*FLT_EPSILON,3.e-6f) )
01460 {
01461 fprintf( ioQQQ, "%14.6e%14.6e: frequencies of last grid point do not match\n",
01462 rfield.AnuOrg[rfield.nupper-1], gv.bin[nd]->EnergyCheck );
01463 lgErrorFound = true;
01464 }
01465
01466 if( lgErrorFound )
01467 {
01468 if( continuum.ResolutionScaleFactor == 1. )
01469 {
01470 fprintf( ioQQQ,"PROBLEM DISASTER conorm: The energy grid of the grain opacity file does not agree with the grid in this version of the code.\n" );
01471 fprintf( ioQQQ,"A compiled grain grid from an old version of the code is probably in place.\n" );
01472 fprintf( ioQQQ,"A grid for the current version of Cloudy must be generated and used.\n" );
01473 fprintf( ioQQQ,"This is done with the COMPILE ALL GRAINS command.\n" );
01474 fprintf( ioQQQ,"Sorry.\n" );
01475
01476 cdEXIT(EXIT_FAILURE);
01477 }
01478 else
01479 {
01480 fprintf( ioQQQ,"\n\nPROBLEM DISASTER The continuum resolution has been chnaged with the SET CONTINUUM RESOLUTION command.\n" );
01481 fprintf( ioQQQ,"The compiled grain opacities are not consistent with this changed continuum, so cannot be used.\n" );
01482 fprintf( ioQQQ,"Sorry.\n" );
01483
01484 cdEXIT(EXIT_FAILURE);
01485 }
01486 }
01487 }
01488
01489
01490
01491
01492 radius.pirsq = 0.;
01493 radius.lgPredLumin = false;
01494
01495
01496 for( i=0; i < rfield.nspec; i++ )
01497 {
01498 if( strcmp(rfield.chRSpec[i],"4 PI") == 0 )
01499 {
01500 radius.pirsq = (realnum)(1.0992099 + 2.*xLog_radius_inner);
01501 radius.lgPredLumin = true;
01502
01503 rfield.totpow[i] -= radius.pirsq;
01504
01505 if( trace.lgTrace )
01506 {
01507 fprintf( ioQQQ,
01508 " conorm converts continuum %ld from luminosity to intensity.\n",
01509 i );
01510 }
01511 }
01512 }
01513
01514
01515 if( radius.lgPredLumin && !radius.lgRadiusKnown )
01516 {
01517 fprintf(ioQQQ,"PROBLEM DISASTER conorm: - A continuum source was specified as a luminosity, but the inner radius of the cloud was not set.\n");
01518 fprintf(ioQQQ,"Please set an inner radius.\nSorry.\n");
01519 cdEXIT(EXIT_FAILURE);
01520 }
01521
01522
01523
01524 for( i=0; i < rfield.nspec; i++ )
01525 {
01526 if( strcmp(rfield.chSpNorm[i],"IONI") == 0 )
01527 {
01528
01529
01530 rfield.totpow[i] += log10(dense.gas_phase[ipHYDROGEN]) + log10(SPEEDLIGHT);
01531 strcpy( rfield.chSpNorm[i], "Q(H)" );
01532 if( trace.lgTrace )
01533 {
01534 fprintf( ioQQQ,
01535 " conorm converts continuum %ld from ionizat par to q(h).\n",
01536 i );
01537 }
01538 }
01539 }
01540
01541
01542 for( i=0; i < rfield.nspec; i++ )
01543 {
01544 if( strcmp(rfield.chSpNorm[i],"IONX") == 0 )
01545 {
01546
01547 rfield.totpow[i] += log10(dense.gas_phase[ipHYDROGEN]) - log10(PI4);
01548 strcpy( rfield.chSpNorm[i], "LUMI" );
01549 if( trace.lgTrace )
01550 {
01551 fprintf( ioQQQ, " conorm converts continuum%3ld from x-ray ionizat par to I.\n",
01552 i );
01553 }
01554 }
01555 }
01556
01557
01558 if( trace.lgTrace )
01559 {
01560 if( radius.lgPredLumin )
01561 {
01562 fprintf( ioQQQ, " Cloudy will predict lumin into 4pi\n" );
01563 }
01564 else
01565 {
01566 fprintf( ioQQQ, " Cloudy will do surface flux for lumin\n" );
01567 }
01568 }
01569
01570
01571
01572
01573 if( !radius.lgPredLumin )
01574 {
01575 geometry.covgeo = 1.;
01576 }
01577
01578
01579
01580 for( i=0; i < rfield.nspec; i++ )
01581 {
01582 rfield.ipspec = i;
01583
01584
01585 if( strcmp(rfield.chSpType[rfield.ipspec],"LASER") == 0 )
01586 {
01587 if( !( rfield.range[rfield.ipspec][0] < rfield.slope[rfield.ipspec] &&
01588 rfield.range[rfield.ipspec][1] > rfield.slope[rfield.ipspec]) )
01589 {
01590 fprintf(ioQQQ,"PROBLEM DISASTER, a continuum source is a laser at %f Ryd, but the intensity was specified over a range from %f to %f Ryd.\n",
01591 rfield.slope[rfield.ipspec],
01592 rfield.range[rfield.ipspec][0],
01593 rfield.range[rfield.ipspec][1]);
01594 fprintf(ioQQQ,"Please specify the continuum flux where the laser is active.\n");
01595 cdEXIT(EXIT_FAILURE);
01596 }
01597 }
01598
01599 if( trace.lgTrace )
01600 {
01601 long int jj;
01602 fprintf( ioQQQ, " conorm continuum number %ld is shape %s range is %.2e %.2e\n",
01603 i,
01604 rfield.chSpType[i],
01605 rfield.range[i][0],
01606 rfield.range[i][1] );
01607 fprintf( ioQQQ, "the continuum points follow\n");
01608 jj = 0;
01609 if( rfield.lgContMalloc[rfield.ipspec] )
01610 {
01611 while( rfield.tNuRyd[rfield.ipspec][jj] != 0. && jj < 100 )
01612 {
01613 fprintf( ioQQQ, "%li %e %e\n",
01614 jj ,
01615 rfield.tNuRyd[rfield.ipspec][jj],
01616 rfield.tslop[rfield.ipspec][jj] );
01617 ++jj;
01618 }
01619 }
01620 }
01621
01622 if( strcmp(rfield.chSpNorm[i],"RATI") == 0 )
01623 {
01624
01625
01626
01627 if( trace.lgTrace )
01628 {
01629 fprintf( ioQQQ, " conorm this is ratio to 1st con\n" );
01630 }
01631
01632
01633 if( i == 0 )
01634 {
01635 fprintf( ioQQQ, " I cant form a ratio if continuum is first source.\n" );
01636 cdEXIT(EXIT_FAILURE);
01637 }
01638
01639
01640 rfield.ipspec -= 1;
01641 flx1 = ffun1(rfield.range[i][0])*rfield.spfac[rfield.ipspec]*
01642 rfield.range[i][0];
01643
01644
01645 if( flx1 <= 0. )
01646 {
01647 fprintf( ioQQQ, " Previous continua were zero where ratio is desired.\n" );
01648 cdEXIT(EXIT_FAILURE);
01649 }
01650
01651
01652 rfield.ipspec += 1;
01653
01654
01655 flx1 *= rfield.totpow[i];
01656
01657
01658 flx2 = ffun1(rfield.range[i][1])*rfield.range[i][1];
01659
01660
01661 rfield.spfac[i] = flx1/flx2;
01662 if( trace.lgTrace )
01663 {
01664 fprintf( ioQQQ, " conorm ratio will set scale fac to%10.3e at%10.2e Ryd.\n",
01665 rfield.totpow[i], rfield.range[i][0] );
01666 }
01667 }
01668
01669 else if( strcmp(rfield.chSpNorm[i],"FLUX") == 0 )
01670 {
01671
01672
01673 f = ffun1(rfield.range[i][0]);
01674
01675
01676
01677 if( f<=0. )
01678 {
01679 fprintf( ioQQQ, "\n\n PROBLEM DISASTER\n The intensity of continuum source %ld is non-positive at the energy used to normalize it (%.3e Ryd). Something is seriously wrong.\n",
01680 i , rfield.range[i][0]);
01681
01682 if( strcmp(rfield.chSpType[i],"INTER") == 0 )
01683 fprintf( ioQQQ, " This continuum shape given by a table of points - check that the intensity is specified at an energy within the range of that table.\n");
01684 fprintf( ioQQQ, " Also check that the numbers used to specify the shape and intensity do not under or overflow on this cpu.\n\n");
01685
01686 cdEXIT(EXIT_FAILURE);
01687 }
01688
01689
01690 f = MAX2(1e-37,f);
01691 f = log10(f) + log10(rfield.range[i][0]*EN1RYD/FR1RYD);
01692
01693 f = rfield.totpow[i] - f;
01694
01695 if( f > 35. )
01696 {
01697 fprintf( ioQQQ, " PROBLEM DISASTER Continuum source %ld is too intense for this cpu - is it normalized correctly?\n",
01698 i );
01699 cdEXIT(EXIT_FAILURE);
01700 }
01701
01702 rfield.spfac[i] = pow(10.,f);
01703 if( trace.lgTrace )
01704 {
01705 fprintf( ioQQQ, " conorm will set log fnu to%10.3e at%10.2e Ryd. Factor=%11.4e\n",
01706 rfield.totpow[i], rfield.range[i][0], rfield.spfac[i] );
01707 }
01708 }
01709
01710 else if( strcmp(rfield.chSpNorm[i],"Q(H)") == 0 ||
01711 strcmp(rfield.chSpNorm[i],"PHI ") == 0 )
01712 {
01713
01714 if( trace.lgTrace )
01715 {
01716 fprintf( ioQQQ, " conorm calling qintr range=%11.3e %11.3e desired val is %11.3e\n",
01717 rfield.range[i][0],
01718 rfield.range[i][1] ,
01719 rfield.totpow[i]);
01720 }
01721
01722
01723
01724 qentrd = qintr(&rfield.range[i][0],&rfield.range[i][1]);
01725
01726
01727 diff = rfield.totpow[i] - qentrd;
01728
01729
01730
01731
01732 if( diff < -35. || diff > 35. )
01733 {
01734 fprintf( ioQQQ, " PROBLEM DISASTER Continuum source specified is too extreme.\n" );
01735 fprintf( ioQQQ,
01736 " The integral over the continuum shape gave (log) %.3e photons, and the command requested (log) %.3e.\n" ,
01737 qentrd , rfield.totpow[i]);
01738 fprintf( ioQQQ,
01739 " The difference in the log is %.3e.\n" ,
01740 diff );
01741 if( diff>0. )
01742 {
01743 fprintf( ioQQQ, " The continuum source is too bright.\n" );
01744 }
01745 else
01746 {
01747 fprintf( ioQQQ, " The continuum source is too faint.\n" );
01748 }
01749
01750 fprintf( ioQQQ, " The usual cause for this problem is an incorrect continuum intensity/luminosity or radius command.\n" );
01751 fprintf( ioQQQ, " There were a total of %li continuum shape commands entered - the problem is with number %li.\n",
01752 rfield.nspec , i+1 );
01753 cdEXIT(EXIT_FAILURE);
01754 }
01755
01756 else
01757 {
01758 rfield.spfac[i] = pow(10.,diff);
01759 }
01760
01761 if( trace.lgTrace )
01762 {
01763 fprintf( ioQQQ, " conorm finds Q over range from%11.4e-%11.4e Ryd, integral= %10.4e Factor=%11.4e\n",
01764 rfield.range[i][0],
01765 rfield.range[i][1],
01766 qentrd ,
01767 rfield.spfac[i] );
01768 }
01769 }
01770
01771 else if( strcmp(rfield.chSpNorm[i],"LUMI") == 0 )
01772 {
01773
01774
01775
01776 pentrd = pintr(rfield.range[i][0],rfield.range[i][1]) +
01777 log10(EN1RYD);
01778 f = rfield.totpow[i] - pentrd;
01779
01780
01781 if( f > 35. )
01782 {
01783 fprintf( ioQQQ, " PROBLEM DISASTER Continuum source %ld is too intense for this cpu - is it normalized correctly?\n",
01784 i );
01785 cdEXIT(EXIT_FAILURE);
01786 }
01787
01788 rfield.spfac[i] = pow(10.,f);
01789 if( trace.lgTrace )
01790 {
01791 fprintf( ioQQQ, " conorm finds luminosity range is %10.3e to %9.3e Ryd, factor is %11.4e\n",
01792 rfield.range[i][0], rfield.range[i][1],
01793 rfield.spfac[i] );
01794 }
01795 }
01796
01797 else
01798 {
01799 fprintf( ioQQQ, "PROBLEM DISASTER What chSpNorm label is this? =%s=\n", rfield.chSpNorm[i]);
01800 TotalInsanity();
01801 }
01802
01803
01804
01805 if( 1./rfield.spfac[i] == 0. || rfield.spfac[i] == 0. )
01806 {
01807 fprintf( ioQQQ, "PROBLEM DISASTER conorm finds infinite continuum scale factor.\n" );
01808 fprintf( ioQQQ, "The continuum is too intense to compute with this cpu.\n" );
01809 fprintf( ioQQQ, "Were the intensity and luminosity commands switched?\n" );
01810 fprintf( ioQQQ, "Sorry, but I cannot go on.\n" );
01811 cdEXIT(EXIT_FAILURE);
01812 }
01813 }
01814
01815
01816
01817
01818 radius.Conv2PrtInten = radius.pirsq;
01819
01820
01821 if( geometry.iEmissPower == 1 )
01822 {
01823 if( radius.lgPredLumin )
01824 {
01825
01826 radius.Conv2PrtInten -= (log10(2.) + xLog_radius_inner);
01827 }
01828 else if( !radius.lgPredLumin )
01829 {
01830
01831 fprintf( ioQQQ, "PROBLEM DISASTER conorm: Aperture slit specified, but not predicting luminosity.\n" );
01832 fprintf( ioQQQ, "conorm: Please specify an inner radius to determine L.\nSorry\n" );
01833 cdEXIT(EXIT_FAILURE);
01834 }
01835 }
01836 if( geometry.iEmissPower == 0 && radius.lgPredLumin)
01837 {
01838
01839 radius.Conv2PrtInten = log10(2.);
01840 }
01841
01842
01843 if( radius.distance > 0. && radius.lgRadiusKnown && prt.lgPrintFluxEarth )
01844 {
01845
01846
01847 radius.Conv2PrtInten -= log10( 4.*PI*POW2(radius.distance) );
01848 }
01849
01850
01851 if( prt.lgSurfaceBrightness )
01852 {
01853 if( radius.pirsq!= 0. )
01854 {
01855
01856 fprintf( ioQQQ, " PROBLEM DISASTER Sorry, but both luminosity and surface brightness have been requested for lines.\n" );
01857 fprintf( ioQQQ, " the PRINT LINE SURFACE BRIGHTNESS command can only be used when lines are predicted per unit cloud area.\n" );
01858 cdEXIT(EXIT_FAILURE);
01859 }
01860 if( prt.lgSurfaceBrightness_SR )
01861 {
01862
01863 radius.Conv2PrtInten -= log10( PI4 );
01864 }
01865 else
01866 {
01867
01868
01869
01870
01871 radius.Conv2PrtInten -= log10( PI4 *POW2( (360./(PI2)*3600.) ) );
01872 }
01873 }
01874 return;
01875 }
01876
01877
01878 STATIC double qintr(double *qenlo,
01879 double *qenhi)
01880 {
01881 long int i,
01882 ipHi,
01883 ipLo,
01884 j;
01885 double qintr_v,
01886 sum,
01887 wanu;
01888
01889 DEBUG_ENTRY( "qintr()" );
01890
01891
01892 sum = 0.;
01893
01894
01895
01896
01897 ipLo = ipoint(*qenlo);
01898 ipHi = ipoint(*qenhi);
01899
01900 for( i=ipLo-1; i < (ipHi - 1); i++ )
01901 {
01902
01903 for( j=0; j < 4; j++ )
01904 {
01905 wanu = rfield.anu[i] + rfield.widflx[i]*aweigh[j];
01906
01907
01908 wanu = MAX2( wanu , rfield.emm );
01909 wanu = MIN2( wanu , rfield.egamry );
01910 sum += fweigh[j]*ffun1(wanu)*rfield.widflx[i];
01911 }
01912 }
01913
01914 if( sum <= 0. )
01915 {
01916 fprintf( ioQQQ, " PROBLEM DISASTER Photon number sum in QINTR is %.3e\n",
01917 sum );
01918 fprintf( ioQQQ, " This source has no ionizing radiation, and the number of ionizing photons was specified.\n" );
01919 fprintf( ioQQQ, " This was continuum source number%3ld\n",
01920 rfield.ipspec );
01921 fprintf( ioQQQ, " Sorry, but I cannot go on. ANU and FLUX arrays follow. Enjoy.\n" );
01922 for( i=0; i < rfield.nupper; i++ )
01923 {
01924 fprintf( ioQQQ, "%.2e\t%.2e\n",
01925 rfield.anu[i],
01926 rfield.flux[i] );
01927 }
01928 cdEXIT(EXIT_FAILURE);
01929 }
01930 else
01931 {
01932 qintr_v = log10(sum);
01933 }
01934 return( qintr_v );
01935 }
01936
01937
01938
01939 STATIC double pintr(double penlo,
01940 double penhi)
01941 {
01942 long int i,
01943 j;
01944 double fsum,
01945 pintr_v,
01946 sum,
01947 wanu,
01948 wfun;
01949 long int ip1 , ip2;
01950
01951 DEBUG_ENTRY( "pintr()" );
01952
01953
01954
01955
01956 sum = 0.;
01957
01958
01959
01960
01961 ip1 = ipoint( penlo );
01962
01963 ip2 = ipoint( penhi );
01964
01965 for( i=ip1-1; i < ip2-1; i++ )
01966 {
01967 fsum = 0.;
01968 for( j=0; j < 4; j++ )
01969 {
01970 wanu = rfield.anu[i] + rfield.widflx[i]*aweigh[j];
01971
01972 wfun = fweigh[j]*ffun1(wanu)*wanu;
01973 fsum += wfun;
01974 }
01975 sum += fsum*rfield.widflx[i];
01976 }
01977
01978 if( sum > 0. )
01979 {
01980 pintr_v = log10(sum);
01981 }
01982 else
01983 {
01984 pintr_v = -38.;
01985 }
01986
01987 return( pintr_v );
01988 }