00001
00002
00003
00004
00005
00014 #include "cddefines.h"
00015 #include "lines_service.h"
00016 #include "iso.h"
00017 #include "geometry.h"
00018 #include "h2.h"
00019 #include "mole.h"
00020 #include "hyperfine.h"
00021 #include "opacity.h"
00022 #include "dense.h"
00023 #include "heavy.h"
00024 #include "grainvar.h"
00025 #include "elementnames.h"
00026 #include "conv.h"
00027 #include "rfield.h"
00028 #include "dynamics.h"
00029 #include "thermal.h"
00030 #include "hmi.h"
00031 #include "coolheavy.h"
00032 #include "timesc.h"
00033 #include "doppvel.h"
00034 #include "stopcalc.h"
00035 #include "colden.h"
00036 #include "phycon.h"
00037 #include "rt.h"
00038 #include "trace.h"
00039 #include "wind.h"
00040 #include "punch.h"
00041 #include "taulines.h"
00042 #include "pressure.h"
00043 #include "iterations.h"
00044 #include "struc.h"
00045 #include "radius.h"
00046
00047 #if 0
00048
00049 STATIC void ChkRate(
00050
00051 long int nelem,
00052
00053 double *dDestRate,
00054
00055 double *DestRateOld,
00056 double *DestRateNew,
00057
00058 long int *istage);
00059 #endif
00060
00061
00062 STATIC void ContRate(double *freqm,
00063 double *opacm);
00064
00065
00066 STATIC void GrainRateDr(double *grfreqm,
00067 double *gropacm);
00068
00069
00070
00071 int radius_next(void)
00072 {
00073 char chLbl[11];
00074 bool lgDoPun;
00075
00076 long int level , ipStrong;
00077
00078 double thickness_total , drThickness , DepthToGo , AV_to_go;
00079 int mole_dr_change;
00080
00081 double DrGrainHeat,
00082 GlobDr,
00083 SaveOHIIoHI,
00084 SpecDr,
00085 Strong,
00086 TauDTau,
00087 TauInwd,
00088 drSolomon_BigH2 ,
00089 dEfrac,
00090 dHdStep,
00091 dRTaue,
00092 dTdStep,
00093 dnew,
00094 drConPres,
00095 drH2_heat_cool = 0. ,
00096 dH2_heat_cool = 0.,
00097 drH2_abund = 0. ,
00098 dr_mole_abund = 0.,
00099 dH2_abund=0.,
00100 dCO_abund=0.,
00101 drDepth,
00102 drDest,
00103 drEfrac,
00104 drFail,
00105 drFluc,
00106 drHMase,
00107 drHe1ovHe2,
00108 drHion,
00109 drInter,
00110 drLeiden_hack ,
00111 drLineHeat,
00112 drSphere,
00113 drTab,
00114 drdHdStep,
00115 drdTdStep,
00116 drThermalFront ,
00117 drmax,
00118 dVelRelative,
00119 fac2,
00120 factor,
00121 freqm,
00122 grfreqm=0.,
00123 gropacm=0.,
00124 hdnew,
00125 opacm,
00126 recom_dr_last_iter ,
00127 OldDR ,
00128 winddr,
00129 WindAccelDR,
00130 x;
00131
00132 double change_heavy_frac=-1. , change_heavy_frac_big , dr_change_heavy ,
00133 frac_change_heavy_frac_big, Efrac_old , Efrac_new;
00134 long int ichange_heavy_nelem=-1 , nelem , ion , ichange_heavy_ion=-1;
00135
00136 static double OHIIoHI,
00137 OldHeat = 0.,
00138 OldTe = 0.,
00139 OlddTdStep = 0.,
00140 OldH2Abund=0.,
00141 OldWindVelocity=0.,
00142 Old_He_atom_ov_ion = 0,
00143 Old_H2_heat_cool;
00144 static long int iteration_last=-1;
00145
00146 static double BigRadius = 1e30;
00147 bool lgFirstCall;
00148
00149 DEBUG_ENTRY( "radius_next()" );
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 if( (iteration != iteration_last) && (nzone==0) )
00174 {
00175
00176 iteration_last = iteration;
00177 lgFirstCall = true;
00178 }
00179 else
00180 lgFirstCall = false;
00181
00182 if( trace.lgTrace )
00183 {
00184 fprintf( ioQQQ, " radius_next called\n" );
00185 }
00186
00187
00188 OldDR = radius.drad;
00189
00190
00191
00192
00193 if( lgFirstCall )
00194 {
00195 if( dense.xIonDense[ipHYDROGEN][1] > 0. && dense.xIonDense[ipHYDROGEN][0] > 0. )
00196 {
00197 OHIIoHI = dense.xIonDense[ipHYDROGEN][1]/dense.xIonDense[ipHYDROGEN][0];
00198 }
00199 else
00200 {
00201 OHIIoHI = 0.;
00202 }
00203 SaveOHIIoHI = OHIIoHI;
00204 drHion = BigRadius;
00205
00206
00207 }
00208
00209 else if( (dense.xIonDense[ipHYDROGEN][1] > 0. && dense.xIonDense[ipHYDROGEN][0] > 0.) && OHIIoHI > 1e-15 )
00210 {
00211 double atomic_frac = (dense.xIonDense[ipHYDROGEN][1]/dense.xIonDense[ipHYDROGEN][0]);
00212
00213
00214 x = 1. - atomic_frac /OHIIoHI;
00215 if( atomic_frac > 0.05 && atomic_frac < 0.9 )
00216 {
00217
00218
00219
00220 drHion = radius.drad*MAX2( 0.2 , 0.05/MAX2(1e-10,x) );
00221 }
00222 else if( x > 0. )
00223 {
00224
00225
00226 drHion = radius.drad*MAX2( 0.2 , 0.2/MAX2(1e-10,x) );
00227 }
00228 else
00229 {
00230 drHion = BigRadius;
00231 }
00232 SaveOHIIoHI = OHIIoHI;
00233 OHIIoHI = dense.xIonDense[ipHYDROGEN][1]/dense.xIonDense[ipHYDROGEN][0];
00234 }
00235
00236 else
00237 {
00238 SaveOHIIoHI = OHIIoHI;
00239 if( dense.xIonDense[ipHYDROGEN][1] > 0. && dense.xIonDense[ipHYDROGEN][0] > 0. )
00240 {
00241 OHIIoHI = dense.xIonDense[ipHYDROGEN][1]/dense.xIonDense[ipHYDROGEN][0];
00242 }
00243 else
00244 {
00245 OHIIoHI = 0.;
00246 }
00247 drHion = BigRadius;
00248 }
00249
00250
00251
00252 if( rt.dTauMase < -0.01 )
00253 {
00254
00255
00256 drHMase = radius.drad*MAX2(0.1,-0.2/rt.dTauMase);
00257 }
00258 else
00259 {
00260 drHMase = BigRadius;
00261 }
00262
00263
00264 Old_He_atom_ov_ion = 0.;
00265 drHe1ovHe2 = BigRadius;
00266
00267
00268
00269
00270 dr_change_heavy = BigRadius;
00271 change_heavy_frac_big = -1.;
00272 frac_change_heavy_frac_big = -1.;
00273
00274 # define CHANGE_ION_HEAV 0.2f
00275 # define CHANGE_ION_HHE 0.15f
00276 if( nzone > 4 )
00277 {
00278 for( nelem=ipHYDROGEN; nelem<LIMELM; ++nelem )
00279 {
00280 if( dense.lgElmtOn[nelem] )
00281 {
00282 realnum change;
00283
00284
00285 realnum frac_limit;
00286 if( nelem<=ipHELIUM || nelem==ipCARBON )
00287 {
00288 frac_limit = 1e-4f;
00289 change = CHANGE_ION_HHE;
00290 }
00291 else
00292 {
00293
00294
00295 frac_limit = struc.dr_ionfrac_limit/2.f;
00296 change = CHANGE_ION_HEAV;
00297 }
00298
00299 for( ion=0; ion<=nelem+1; ++ion )
00300 {
00301 realnum abundnew = dense.xIonDense[nelem][ion]/SDIV( dense.gas_phase[nelem]);
00302 realnum abundold = struc.xIonDense[nelem][ion][nzone-3]/SDIV( struc.gas_phase[nelem][nzone-3]);
00303 if( abundnew > frac_limit && abundold > frac_limit )
00304 {
00305
00306
00307
00308 realnum abundolder = struc.xIonDense[nelem][ion][nzone-4]/SDIV( struc.gas_phase[nelem][nzone-4]);
00309 realnum abundoldest = struc.xIonDense[nelem][ion][nzone-5]/SDIV( struc.gas_phase[nelem][nzone-5]);
00310
00311
00312
00313 change_heavy_frac = fabs(abundnew-abundold)/MIN2(abundold,abundnew);
00314
00315 if( (change_heavy_frac > change) && (change_heavy_frac > change_heavy_frac_big) &&
00316
00317
00318 ((abundnew-abundold)>0.) &&
00319 ((abundold-abundolder)>0.) &&
00320 ((abundolder-abundoldest)>0.) )
00321 {
00322 ichange_heavy_nelem = nelem;
00323 ichange_heavy_ion = ion;
00324 change_heavy_frac_big = change_heavy_frac;
00325 frac_change_heavy_frac_big = abundnew;
00326
00327
00328
00329
00330
00331 dr_change_heavy = radius.drad * MAX2(0.25, change / change_heavy_frac );
00332 }
00333 }
00334 }
00335 }
00336 }
00337 }
00338
00339
00340
00341 if(!co.lgUMISTrates)
00342 {
00343
00344
00345
00346 drLeiden_hack = MAX2( 0.02 , 0.05*rfield.extin_mag_V_point) / SDIV( geometry.FillFac * rfield.opac_mag_V_point );
00347 }
00348 else
00349 {
00350 drLeiden_hack = BigRadius;
00351 }
00352
00353
00354
00355
00356
00357 if( nzone <= 1 || thermal.lgTemperatureConstant )
00358 {
00359 drdHdStep = BigRadius;
00360 dHdStep = FLT_MAX;
00361 }
00362 else
00363 {
00364 dHdStep = fabs(thermal.htot-OldHeat)/thermal.htot;
00365 if( dHdStep > 0. )
00366 {
00367 if( dense.gas_phase[ipHYDROGEN] >= 1e13 )
00368 {
00369
00370 drdHdStep = radius.drad*MAX2(0.8,0.075/dHdStep);
00371 }
00372 else if( dense.gas_phase[ipHYDROGEN] >= 1e11 )
00373 {
00374
00375 drdHdStep = radius.drad*MAX2(0.8,0.100/dHdStep);
00376 }
00377 else
00378 {
00379
00380
00381
00382
00383 drdHdStep = radius.drad*MAX2(0.8,0.15/dHdStep);
00384 }
00385 }
00386 else
00387 {
00388 drdHdStep = BigRadius;
00389 }
00390 }
00391 OldHeat = thermal.htot;
00392
00393
00394
00395 if( strcmp(dense.chDenseLaw,"CPRE") == 0 && pressure.lgContRadPresOn )
00396 {
00397 if( nzone > 2 && pressure.pinzon > 0. )
00398 {
00399
00400
00401
00402
00403
00404 drConPres = 0.05*pressure.PresTotlCurr/(wind.AccelTot*
00405 dense.xMassDensity*geometry.FillFac);
00406 }
00407 else
00408 {
00409 drConPres = BigRadius;
00410 }
00411 }
00412 else
00413 {
00414 drConPres = BigRadius;
00415 }
00416
00417
00418
00419
00420 if( nzone <= 1 )
00421 {
00422 drdTdStep = BigRadius;
00423 dTdStep = FLT_MAX;
00424 OlddTdStep = dTdStep;
00425 }
00426 else
00427 {
00428
00429 dTdStep = (phycon.te-OldTe)/phycon.te;
00430
00431
00432
00433
00434 x = conv.HeatCoolRelErrorAllowed*2.;
00435 x = MAX2( 0.01 , x );
00436 x = MIN2( 0.05 , x );
00437
00438 x = 0.03;
00439
00440
00441
00442 if( dTdStep*OlddTdStep > 0. )
00443 {
00444
00445
00446
00447
00448
00449 double absdt = fabs(dTdStep);
00450 drdTdStep = radius.drad*MAX2(0.5,x/absdt);
00451 }
00452 else
00453 {
00454 drdTdStep = BigRadius;
00455 }
00456 }
00457 OlddTdStep = dTdStep;
00458 OldTe = phycon.te;
00459
00460
00461
00462
00463
00464
00465 if( !thermal.lgTemperatureConstant && !dynamics.lgRecom )
00466 {
00467
00468
00469
00470 ContRate(&freqm,&opacm);
00471
00472
00473
00474
00475
00476
00477 drInter = 0.3/MAX2(1e-30,opacm*geometry.FillFac*geometry.DirectionalCosin);
00478 }
00479 else
00480 {
00481 drInter = BigRadius;
00482 freqm = 0.;
00483 opacm = 1.;
00484 }
00485
00486 # if 0
00487
00488
00489 ChkRate(ipCARBON,&dDRCarbon,&DestOldCarb, &DestNewCarb,&icarstag);
00490 ChkRate(ipNITROGEN,&dDRNitrogen,&DestOldNit, &DestNewNit,&initstag);
00491 ChkRate(ipOXYGEN,&dDROxygen,&DestOldOxy, &DestNewOxy,&ioxystag);
00492 ChkRate(ipIRON,&dDRIron,&DestOldIron, &DestNewIron,&iironstag);
00493
00494 dDestRate = MAX4(dDROxygen,dDRIron,dDRCarbon,dDRNitrogen);
00495
00496 if( fp_equal( dDRCarbon, dDestRate ) )
00497 {
00498 dDestRate = dDRCarbon;
00499 DestOld = DestOldCarb;
00500 DestNew = DestNewCarb;
00501 istage = icarstag;
00502 strcpy( chDestAtom, "Carbon " );
00503 }
00504
00505 else if( fp_equal( dDRNitrogen, dDestRate ) )
00506 {
00507 dDestRate = dDRNitrogen;
00508 DestOld = DestOldNit;
00509 DestNew = DestNewNit;
00510 istage = initstag;
00511 strcpy( chDestAtom, "Nitrogen" );
00512 }
00513
00514 else if( fp_equal( dDROxygen, dDestRate ) )
00515 {
00516 dDestRate = dDROxygen;
00517 DestOld = DestOldOxy;
00518 DestNew = DestNewOxy;
00519 strcpy( chDestAtom, "Oxygen " );
00520 istage = ioxystag;
00521 }
00522
00523 else if( fp_equal( dDRIron, dDestRate ) )
00524 {
00525 dDestRate = dDRIron;
00526 DestOld = DestOldIron;
00527 DestNew = DestNewIron;
00528 istage = iironstag;
00529 strcpy( chDestAtom, "Iron " );
00530 }
00531
00532 else
00533 {
00534 fprintf( ioQQQ, " insanity following ChkRate\n" );
00535 ShowMe();
00536 cdEXIT(EXIT_FAILURE);
00537 }
00538
00539
00540 if( dDestRate > 0. )
00541 {
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554 drDest = radius.drad*MAX2(0.5,0.20/dDestRate);
00555
00556 }
00557 else
00558 {
00559 drDest = BigRadius;
00560 }
00561 # endif
00562 drDest = BigRadius;
00563
00564
00565
00566
00567
00568
00569 if( wind.windv!=0. && !pressure.lgSonicPoint && !pressure.lgStrongDLimbo )
00570 {
00571 double v = fabs(wind.windv);
00572
00573 dVelRelative = fabs(wind.windv-OldWindVelocity)/
00574 MAX2(v,0.1*timesc.sound_speed_isothermal);
00575
00576 # define WIND_CHNG_VELOCITY_RELATIVE 0.01
00577
00578
00579
00580
00581 if( dVelRelative > WIND_CHNG_VELOCITY_RELATIVE && nzone>1 )
00582 {
00583
00584 double factor = WIND_CHNG_VELOCITY_RELATIVE / dVelRelative;
00585
00586 factor = MAX2(0.8 , factor );
00587 winddr = radius.drad * factor;
00588 }
00589 else
00590 {
00591 winddr = BigRadius;
00592 }
00593
00594
00595 WindAccelDR = BigRadius;
00596
00597
00598
00599 if( dynamics.lgAdvection && iteration > dynamics.n_initial_relax+1)
00600 {
00601
00602 winddr = MIN2( winddr , dynamics.dRad / 20. );
00603
00604
00605 dVelRelative = dynamics.dRad;
00606 }
00607 }
00608 else
00609 {
00610 winddr = BigRadius;
00611 WindAccelDR = BigRadius;
00612 dVelRelative = 0.;
00613 }
00614
00615 OldWindVelocity = wind.windv;
00616
00617
00618 if( strcmp(dense.chDenseLaw,"GLOB") == 0 )
00619 {
00620 # define DNGLOB 0.10
00621 if( radius.glbdst < 0. )
00622 {
00623 fprintf( ioQQQ, " Globule distance is negative, internal overflow has occured, sorry.\n" );
00624 fprintf( ioQQQ, " This is routine radius_next, GLBDST is%10.2e\n",
00625 radius.glbdst );
00626 cdEXIT(EXIT_FAILURE);
00627 }
00628 factor = radius.glbden*pow(radius.glbrad/radius.glbdst,radius.glbpow);
00629 fac2 = radius.glbden*pow(radius.glbrad/(radius.glbdst - (realnum)radius.drad),radius.glbpow);
00630 if( fac2/factor > 1. + DNGLOB )
00631 {
00632
00633 GlobDr = radius.drad*DNGLOB/(fac2/factor - 1.);
00634 }
00635 else
00636 {
00637 GlobDr = BigRadius;
00638 }
00639
00640 GlobDr = MIN2(GlobDr,radius.glbdst/20.);
00641 }
00642 else
00643 {
00644 GlobDr = BigRadius;
00645 }
00646
00647
00648 hdnew = 0.;
00649 if( strncmp( dense.chDenseLaw , "DLW" , 3) == 0 )
00650 {
00651
00652 if( strcmp(dense.chDenseLaw,"DLW1") == 0 )
00653 {
00654 hdnew = dense_fabden(radius.Radius+radius.drad,radius.depth+
00655 radius.drad);
00656 }
00657 else if( strcmp(dense.chDenseLaw,"DLW2") == 0 )
00658 {
00659 hdnew = dense_tabden(radius.Radius+radius.drad,radius.depth+
00660 radius.drad);
00661 }
00662 else
00663 {
00664 fprintf( ioQQQ, " dlw insanity in radius_next\n" );
00665 cdEXIT(EXIT_FAILURE);
00666 }
00667 drTab = fabs(hdnew-dense.gas_phase[ipHYDROGEN])/MAX2(hdnew,dense.gas_phase[ipHYDROGEN]);
00668 drTab = radius.drad*MAX2(0.2,0.10/MAX2(0.01,drTab));
00669 }
00670 else
00671 {
00672 drTab = BigRadius;
00673 }
00674
00675
00676
00677 if( strcmp(dense.chDenseLaw,"DLW1") == 0 )
00678 {
00679 dnew = fabs(dense_fabden(radius.Radius+radius.drad,radius.depth+
00680 radius.drad)/dense.gas_phase[ipHYDROGEN]-1.);
00681
00682 if( dnew == 0. )
00683 {
00684 SpecDr = radius.drad*3.;
00685 }
00686 else if( dnew/DNGLOB > 1.0 )
00687 {
00688 SpecDr = radius.drad/(dnew/DNGLOB);
00689 }
00690 else
00691 {
00692 SpecDr = BigRadius;
00693 }
00694 }
00695 else
00696 {
00697 SpecDr = BigRadius;
00698 }
00699
00700
00701
00702
00703
00704 if( thermal.heating[0][13]/thermal.htot > 0.2 )
00705 {
00706
00707
00708 GrainRateDr(&grfreqm,&gropacm);
00709 DrGrainHeat = 1.0/MAX2(1e-30,gropacm*geometry.FillFac*geometry.DirectionalCosin);
00710 }
00711 else
00712 {
00713 gropacm = 0.;
00714 grfreqm = 0.;
00715 DrGrainHeat = BigRadius;
00716 }
00717
00718
00719
00720
00721 if( thermal.heating[0][22]/thermal.htot > 0.2 )
00722 {
00723 FndLineHt(&level,&ipStrong,&Strong);
00724 if( Strong/thermal.htot > 0.1 )
00725 {
00726 if( level == 1 )
00727 {
00728
00729
00730
00731 TauInwd = TauLines[ipStrong].Emis->TauIn;
00732 TauDTau = TauLines[ipStrong].Emis->PopOpc * TauLines[ipStrong].Emis->opacity /
00733 DoppVel.doppler[TauLines[ipStrong].Hi->nelem-1];
00734 }
00735 else if( level == 2 )
00736 {
00737
00738
00739
00740
00741 TauInwd = TauLine2[ipStrong].Emis->TauIn;
00742 TauDTau = TauLine2[ipStrong].Emis->PopOpc * TauLine2[ipStrong].Emis->opacity /
00743 DoppVel.doppler[TauLine2[ipStrong].Hi->nelem-1];
00744 }
00745 else if( level == 3 )
00746 {
00747
00748
00749
00750
00751 TauInwd = C12O16Rotate[ipStrong].Emis->TauIn;
00752 TauDTau = C12O16Rotate[ipStrong].Emis->PopOpc * C12O16Rotate[ipStrong].Emis->opacity /
00753 DoppVel.doppler[C12O16Rotate[ipStrong].Hi->nelem-1];
00754 }
00755 else if( level == 4 )
00756 {
00757
00758
00759
00760
00761 TauInwd = C13O16Rotate[ipStrong].Emis->TauIn;
00762 TauDTau = C13O16Rotate[ipStrong].Emis->PopOpc * C13O16Rotate[ipStrong].Emis->opacity /
00763 DoppVel.doppler[C13O16Rotate[ipStrong].Hi->nelem-1];
00764 }
00765 else if( level == 5 )
00766 {
00767
00768
00769 TauInwd = HFLines[ipStrong].Emis->TauIn;
00770 TauDTau = HFLines[ipStrong].Emis->PopOpc * HFLines[ipStrong].Emis->opacity /
00771 DoppVel.doppler[HFLines[ipStrong].Hi->nelem-1];
00772 }
00773 else
00774 {
00775
00776 fprintf( ioQQQ, " PROBLEM radius_next Strong line heating set, but not level.\n" );
00777 TotalInsanity();
00778 }
00779
00780
00781
00782 if( TauDTau > 0. )
00783 {
00784 drLineHeat = MAX2(1.,TauInwd)*0.4/TauDTau;
00785 }
00786 else
00787 {
00788 drLineHeat = BigRadius;
00789 }
00790 }
00791 else
00792 {
00793 TauInwd = 0.;
00794 drLineHeat = BigRadius;
00795 ipStrong = 0;
00796 Strong = 0.;
00797 }
00798 }
00799 else
00800 {
00801 TauInwd = 0.;
00802 drLineHeat = BigRadius;
00803 ipStrong = 0;
00804 level = 0;
00805 Strong = 0.;
00806 }
00807
00808
00809
00810 drH2_heat_cool = BigRadius;
00811 if( lgFirstCall )
00812 {
00813 Old_H2_heat_cool = 0.;
00814 }
00815 else if( !thermal.lgTemperatureConstant )
00816 {
00817
00818
00819 double H2_heat_cool = (fabs(hmi.HeatH2Dexc_used)+fabs(hmi.HeatH2Dish_used)) / thermal.htot;
00820 if( H2_heat_cool > 0.1 )
00821 {
00822 dH2_heat_cool = fabs( H2_heat_cool - Old_H2_heat_cool );
00823 dH2_heat_cool = SDIV(dH2_heat_cool);
00824
00825
00826
00827 drH2_heat_cool = radius.drad*MAX2(0.5,0.05/dH2_heat_cool);
00828 }
00829 else
00830 {
00831 drH2_heat_cool = BigRadius;
00832 }
00833 }
00834 Old_H2_heat_cool = (fabs(hmi.HeatH2Dexc_used)+fabs(hmi.HeatH2Dish_used)) / thermal.htot;
00835
00836
00837
00838
00839 drH2_abund = BigRadius;
00840 dr_mole_abund = BigRadius;
00841 mole_dr_change = -1;
00842 if( nzone>=4 )
00843 {
00844
00845 double Old_H2_abund;
00846
00847 int i;
00848 Old_H2_abund = struc.H2_molec[ipMH2g][nzone-3] + struc.H2_molec[ipMH2s][nzone-3];
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859 if( 2.*hmi.H2_total/dense.gas_phase[ipHYDROGEN] > 1e-8 )
00860 {
00861 double fac = 0.2;
00862
00863 dH2_abund = 2.*fabs( hmi.H2_total - Old_H2_abund ) / hmi.H2_total;
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875 dH2_abund = SDIV(dH2_abund);
00876 drH2_abund = radius.drad*MAX2(0.2,fac/dH2_abund );
00877 }
00878 else
00879 {
00880 drH2_abund = BigRadius;
00881 }
00882
00883
00884
00885 dr_mole_abund = BigRadius;
00886
00887
00888 for(i=0; i<mole.num_comole_calc; ++i)
00889 {
00890 realnum abund,
00891 abund_limit;
00892 if( !dense.lgElmtOn[COmole[i]->nelem_hevmol] || COmole[i]->n_nuclei <= 1 )
00893 continue;
00894
00895
00896
00897
00898 abund = COmole[i]->hevmol/dense.gas_phase[COmole[i]->nelem_hevmol];
00899
00900
00901
00902
00903 if( COmole[i]->lgGas_Phase )
00904 {
00905 abund_limit = 1e-3f;
00906 }
00907 else
00908 {
00909
00910
00911 abund_limit = 1e-5f;
00912 }
00913
00914 if( abund > abund_limit )
00915 {
00916 double drmole_one, relative_change, relative_change_denom;
00917
00918
00919
00920 if( struc.CO_molec[i][nzone-3]>SMALLFLOAT )
00921 {
00922 relative_change_denom = MIN2( COmole[i]->hevmol , struc.CO_molec[i][nzone-3] );
00923 }
00924 else
00925 {
00926 relative_change_denom = COmole[i]->hevmol;
00927 }
00928
00929 relative_change =
00930
00931
00932 fabs( COmole[i]->hevmol - struc.CO_molec[i][nzone-3] ) / relative_change_denom;
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942 relative_change = SDIV(relative_change);
00943
00944
00945 if( relative_change > 1. )
00946 relative_change = 1./relative_change;
00947
00948
00949
00950
00951 drmole_one = radius.drad*MAX2(0.6,0.05/relative_change );
00952
00953 if( drmole_one < dr_mole_abund )
00954 {
00955
00956 dr_mole_abund = drmole_one;
00957 mole_dr_change = i;
00958 dCO_abund = relative_change;
00959 }
00960 }
00961 }
00962 }
00963
00964
00965 drSolomon_BigH2 = H2_DR();
00966
00967
00968
00969
00970
00971 if( nzone < 5 )
00972 {
00973
00974
00975
00976 drmax = 4.*radius.drad;
00977 }
00978 else
00979 {
00980 drmax = 1.3*radius.drad;
00981 }
00982
00983
00984
00985 # if 0
00986
00987 dr_ne_oscil = BigRadius;
00988 dr_te_oscil = BigRadius;
00989 if( nzone >= 11 )
00990 {
00991
00992
00993
00994 realnum errorHC = POW2(conv.HeatCoolRelErrorAllowed);
00995 realnum errorNe = (realnum)POW2(conv.EdenErrorAllowed );
00996 limit = nzone -2;
00997 ASSERT( limit < struc.nzlim );
00998 for( k=nzone - 10; k < limit; k++ )
00999 {
01000
01001
01002 if( (struc.testr[k-1] - struc.testr[k])/struc.testr[k]*
01003 (struc.testr[k] - struc.testr[k+1])/struc.testr[k] <
01004 -errorHC )
01005 {
01006 dr_te_oscil = radius.drad;
01007 }
01008
01009 if( (struc.ednstr[k-1] - struc.ednstr[k])/struc.ednstr[k]*
01010 (struc.ednstr[k] - struc.ednstr[k+1])/struc.ednstr[k] <
01011 -errorNe )
01012 {
01013
01014
01015 dr_ne_oscil = radius.drad;
01016 }
01017 }
01018 }
01019
01020
01021 dr_ne_oscil = BigRadius;
01022 dr_te_oscil = BigRadius;
01023 # endif
01024
01025
01026
01027
01028
01029 if( !conv.lgConvTemp )
01030 {
01031 drFail = radius.drad/2.;
01032 }
01033 else
01034 {
01035 drFail = BigRadius;
01036 }
01037
01038
01039
01040 recom_dr_last_iter = BigRadius;
01041 if( dynamics.lgStatic && dynamics.lgRecom )
01042 {
01043
01044 static long int nzone_recom = -1;
01045 if( nzone<=1 )
01046 {
01047
01048 nzone_recom = 0;
01049 }
01050 else if( radius.depth < struc.depth_last[struc.nzone_last-1] &&
01051 nzone_recom < struc.nzone_last )
01052 {
01053 ASSERT( nzone_recom>=0 && nzone_recom<struc.nzone_last );
01054
01055
01056
01057 while( struc.depth_last[nzone_recom] < radius.depth &&
01058 nzone_recom < struc.nzone_last-1 )
01059 ++nzone_recom;
01060 recom_dr_last_iter = struc.drad_last[nzone_recom]*3.;
01061 }
01062 else
01063 {
01064
01065 recom_dr_last_iter = BigRadius;
01066 }
01067 }
01068
01069
01070
01071
01072
01073 if( nzone > 2 )
01074 {
01075
01076 Efrac_old = struc.ednstr[nzone-3]/struc.gas_phase[ipHYDROGEN][nzone-3];
01077 Efrac_new = dense.eden/dense.gas_phase[ipHYDROGEN];
01078 dEfrac = fabs(Efrac_old-Efrac_new) / Efrac_new;
01079
01080 if( dEfrac > SMALLFLOAT )
01081 {
01082 double fac = 0.04;
01083
01084
01085
01086 if( dense.eden_from_metals > 0.5 )
01087 {
01088
01089
01090 fac = 0.04;
01091 }
01092
01093
01094
01095 else if( iso.RecomCollisFrac[ipH_LIKE][ipHYDROGEN] > 0.8 &&
01096 dense.xIonDense[ipHYDROGEN][1]/dense.gas_phase[ipHYDROGEN]>0.1 &&
01097 dense.xIonDense[ipHYDROGEN][1]/dense.gas_phase[ipHYDROGEN]<0.8 )
01098
01099 {
01100 fac = 0.02;
01101 }
01102
01103 drEfrac = radius.drad*MAX2(0.1,fac/dEfrac);
01104 }
01105 else
01106 {
01107 drEfrac = BigRadius;
01108 }
01109 }
01110 else
01111 {
01112 dEfrac = 0.;
01113 drEfrac = BigRadius;
01114 Efrac_old = 0.;
01115 Efrac_new = 0.;
01116 }
01117
01118
01119
01120
01121 if( nzone > 20 )
01122 {
01123
01124
01125 drDepth = radius.depth/10.;
01126 }
01127 else
01128 {
01129 drDepth = BigRadius;
01130 }
01131
01132
01133
01134 thickness_total = BigRadius;
01135 DepthToGo = BigRadius;
01136 if( StopCalc.HColStop < 5e29 )
01137 {
01138 double coleff = SDIV( dense.gas_phase[ipHYDROGEN]*geometry.FillFac);
01139 DepthToGo = MIN2(DepthToGo ,
01140 (StopCalc.HColStop-colden.colden[ipCOL_HTOT]) / coleff );
01141
01142 thickness_total = MIN2(thickness_total , StopCalc.HColStop / coleff );
01143 }
01144
01145 if( StopCalc.colpls < 5e29 )
01146 {
01147 double coleff = (double)SDIV( (dense.xIonDense[ipHYDROGEN][1])*geometry.FillFac);
01148 DepthToGo = MIN2(DepthToGo ,
01149 (StopCalc.colpls-colden.colden[ipCOL_Hp]) / coleff );
01150 thickness_total = MIN2(thickness_total , StopCalc.colpls / coleff );
01151 }
01152
01153 if( StopCalc.col_h2 < 5e29 )
01154 {
01155
01156 double coleff = (double)SDIV( hmi.H2_total*geometry.FillFac);
01157 DepthToGo = MIN2(DepthToGo ,
01158 (StopCalc.col_h2-colden.colden[ipCOL_H2g]-colden.colden[ipCOL_H2s]) / coleff );
01159 thickness_total = MIN2(thickness_total , StopCalc.col_h2 / coleff );
01160 }
01161
01162 if( StopCalc.col_h2_nut < 5e29 )
01163 {
01164
01165 double coleff = (double)SDIV( (2*hmi.H2_total+dense.xIonDense[ipHYDROGEN][1])*geometry.FillFac);
01166 DepthToGo = MIN2(DepthToGo ,
01167 (StopCalc.col_h2_nut-(2*(colden.colden[ipCOL_H2g]+colden.colden[ipCOL_H2s])+dense.xIonDense[ipHYDROGEN][1])) / coleff );
01168 thickness_total = MIN2(thickness_total , StopCalc.col_h2_nut / coleff );
01169 }
01170
01171 if( StopCalc.col_H0_ov_Tspin < 5e29 )
01172 {
01173
01174 double coleff = (double)SDIV( dense.xIonDense[ipHYDROGEN][0] / hyperfine.Tspin21cm*geometry.FillFac );
01175 DepthToGo = MIN2(DepthToGo ,
01176 (StopCalc.col_H0_ov_Tspin - colden.H0_ov_Tspin) / coleff );
01177 thickness_total = MIN2(thickness_total , StopCalc.col_H0_ov_Tspin / coleff );
01178 }
01179
01180 if( StopCalc.col_monoxco < 5e29 )
01181 {
01182
01183 double coleff = (double)SDIV( (findspecies("CO")->hevmol)*geometry.FillFac);
01184 DepthToGo = MIN2(DepthToGo ,
01185 (StopCalc.col_monoxco-findspecies("CO")->hevcol) / coleff );
01186 thickness_total = MIN2(thickness_total , StopCalc.col_monoxco / coleff );
01187 }
01188
01189 if( StopCalc.colnut < 5e29 )
01190 {
01191 double coleff = (double)SDIV( (dense.xIonDense[ipHYDROGEN][0])*geometry.FillFac);
01192 DepthToGo = MIN2(DepthToGo ,
01193 (StopCalc.colnut - colden.colden[ipCOL_H0]) / coleff );
01194 thickness_total = MIN2(thickness_total , StopCalc.colnut / coleff );
01195 }
01196
01197
01198 if( radius.router[iteration-1] < 5e29 )
01199 {
01200 thickness_total = MIN2(thickness_total , radius.router[iteration-1] );
01201 DepthToGo = MIN2(DepthToGo ,
01202 radius.router[iteration-1] - radius.depth );
01203 }
01204
01205
01206 if( StopCalc.iptnu != rfield.nupper )
01207 {
01208
01209 double dt = SDIV(opac.opacity_abs[StopCalc.iptnu-1]*geometry.FillFac);
01210 DepthToGo = MIN2(DepthToGo ,
01211 (StopCalc.tauend-opac.TauAbsGeo[0][StopCalc.iptnu-1])/dt);
01212 }
01213
01214
01215
01216 AV_to_go = BigRadius;
01217 if( rfield.opac_mag_V_extended > SMALLFLOAT && rfield.opac_mag_V_point>SMALLFLOAT )
01218 {
01219
01220
01221 double ave = log10(StopCalc.AV_extended - rfield.extin_mag_V_extended) -
01222 log10(rfield.opac_mag_V_extended);
01223 double avp = log10(StopCalc.AV_point - rfield.extin_mag_V_point) -
01224 log10(rfield.opac_mag_V_point);
01225 AV_to_go = MIN2( ave , avp );
01226 if( AV_to_go < 37. )
01227 {
01228 AV_to_go = pow(10., AV_to_go );
01229
01230
01231 AV_to_go *= 1.0001;
01232 }
01233 else
01234 AV_to_go = BigRadius;
01235
01236 }
01237
01238
01239
01240 if( DepthToGo <= 0. )
01241 {
01242 TotalInsanity();
01243 }
01244 else if( DepthToGo < BigRadius )
01245 {
01246
01247
01248
01249 drThickness = MIN2( thickness_total/10. , DepthToGo );
01250 }
01251 else
01252 {
01253 drThickness = BigRadius;
01254 }
01255
01256
01257
01258
01259
01260
01261
01262 drSphere = radius.Radius*0.04;
01263
01264
01265
01266 dRTaue = radius.drChange/(dense.eden*6.65e-25*geometry.FillFac);
01267
01268
01269 if( thermal.lgTemperatureConstant )
01270 dRTaue *= 3.;
01271
01272
01273 if( dense.flong != 0. )
01274 {
01275 drFluc = 0.628/2./dense.flong;
01276
01277
01278 drFluc /= 2.;
01279 }
01280 else
01281 {
01282 drFluc = BigRadius;
01283 }
01284
01285
01286
01287
01288 if( strcmp(dense.chDenseLaw,"SINE") == 0 && dense.lgDenFlucOn )
01289 {
01290 drdHdStep = BigRadius;
01291 }
01292
01293
01294
01295
01296
01297 radius.drNext = MIN2( MIN4( drmax, drInter, drLineHeat, winddr ),
01298 MIN4( drFluc, GlobDr, DrGrainHeat, dr_change_heavy ) );
01299 radius.drNext = MIN2( MIN4( radius.drNext, SpecDr, drFail, WindAccelDR ),
01300 MIN3( drSphere, radius.sdrmax, dRTaue ) );
01301 radius.drNext = MIN3( MIN3( radius.drNext, drDest, drdTdStep ),
01302 MIN3( drdHdStep, drConPres, drTab ),
01303 MIN3( drSolomon_BigH2, drLeiden_hack, recom_dr_last_iter ) );
01304 radius.drNext = MIN3( MIN4( radius.drNext, drHion, drDepth, dr_mole_abund ),
01305 MIN4( AV_to_go, drEfrac, drHMase, drThickness ),
01306 MIN3( drHe1ovHe2, drH2_heat_cool, drH2_abund ) );
01307
01308
01309
01310
01311
01312
01313
01314
01315 if( nzone <= 1 && radius.drNext > OldDR )
01316 {
01317 radius.drNext = OldDR;
01318 }
01319
01322
01323
01324 if( !conv.lgConvPres || !conv.lgConvTemp )
01325 {
01326 radius.drNext = radius.drad;
01327 }
01328
01329
01330
01331
01332
01333
01334
01335 drThermalFront = BigRadius;
01336
01337 if( nzone >=5 && !dynamics.lgStatic )
01338 {
01339
01340
01341 if( phycon.te > 200. && phycon.te < 3000. &&
01342
01343
01344 (struc.testr[nzone-3] - phycon.te)/phycon.te > 0.02 &&
01345 (struc.testr[nzone-4] - phycon.te)/phycon.te > 0.02 &&
01346 (struc.testr[nzone-5] - phycon.te)/phycon.te > 0.02 )
01347 {
01348
01349
01350 drThermalFront = radius.drad * 0.91;
01351 radius.drNext = drThermalFront;
01352 }
01353 }
01354
01355
01356 if( radius.drNext <= 0. )
01357 {
01358 fprintf( ioQQQ, " radius_next finds insane drNext:%10.2e\n",
01359 radius.drNext );
01360 fprintf( ioQQQ, " all drs follow:%10.2e%10.2e%10.2e%10.2e\n all drs follow:%10.2e%10.2e%10.2e%10.2e%10.2e\n all drs follow:%10.2e%10.2e%10.2e%10.2e\n",
01361 drmax, drInter, drLineHeat, winddr, drFluc, GlobDr, SpecDr,
01362 drFail, drSphere, radius.sdrmax, dRTaue,
01363 OldH2Abund, drDepth );
01364 cdEXIT(EXIT_FAILURE);
01365 }
01366
01367
01368 if( radius.drNext < radius.sdrmin )
01369 {
01370 radius.drNext = radius.sdrmin;
01371 }
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386 if( ((strcmp(dense.chDenseLaw,"DLW1") != 0 &&
01387 strcmp(dense.chDenseLaw ,"GLOB") != 0) )&&
01388
01389
01390
01391 (dense.flong == 0.) &&
01392
01393 radius.drNext != DepthToGo )
01394 {
01395
01396
01397
01398
01399
01400
01401 if( radius.drNext* radius.Radius/radius.rinner *
01402
01403
01404 dense.gas_phase[ipHYDROGEN] <
01405 radius.drMinimum )
01406 {
01407 radius.drNext = radius.drMinimum/ dense.gas_phase[ipHYDROGEN];
01408
01409
01410 radius.lgDrMinUsed = true;
01411
01412 lgAbort = true;
01413
01414
01415 --nzone;
01416 fprintf( ioQQQ,
01417 "\n DISASTER PROBLEM radius_next finds dr too small and aborts. "
01418 "This is zone %ld iteration %ld. The thickness was %.2e\n",
01419 nzone,
01420 iteration,
01421 radius.drNext);
01422 fprintf( ioQQQ,
01423 " If this simulation seems reasonable you can override this limit "
01424 "with the command SET DRMIN %.2e\n\n",
01425 radius.drNext*2);
01426
01427 lgAbort = true;
01428 return 1;
01429 }
01430 }
01431
01432
01433 const double Z = 1.0001;
01434
01435
01436
01437
01438
01439 double drOuterRadius = (radius.router[iteration-1]-radius.depth)*Z;
01440 radius.drNext = min(radius.drNext,drOuterRadius);
01441
01442
01443 fixit();
01444 if( radius.drNext < 0. )
01445 {
01446 radius.lgDrNeg = true;
01447 }
01448 else
01449 {
01450 radius.lgDrNeg = false;
01451 }
01452
01453
01454 if( fp_equal( radius.drNext, drHMase ) )
01455 {
01456 rt.lgMaserSetDR = true;
01457 }
01458
01459
01460
01461
01462 if( punch.lgDROn )
01463 {
01464 if( punch.lgDRPLst )
01465 {
01466
01467 if( iterations.lgLastIt )
01468 {
01469 lgDoPun = true;
01470 }
01471 else
01472 {
01473 lgDoPun = false;
01474 }
01475 }
01476 else
01477 {
01478 lgDoPun = true;
01479 }
01480 }
01481 else
01482 {
01483 lgDoPun = false;
01484 }
01485 if( (trace.lgTrace && trace.lgDrBug) || lgDoPun )
01486 {
01487 if( !conv.lgConvTemp && nzone > 0 )
01488 {
01489 fprintf( punch.ipDRout, "#>>>> A temperature failure occured.\n" );
01490 }
01491 if( !conv.lgConvPres && nzone > 0 )
01492 {
01493 fprintf( punch.ipDRout, "#>>>> A pressure failure occured.\n" );
01494 }
01495
01496
01497 fprintf( punch.ipDRout , "%ld\t%.5e\t%.3e\t%.3e\t", nzone, radius.depth, radius.drNext, radius.Depth2Go );
01498
01499
01500 if( fp_equal( radius.drNext, drLineHeat ) )
01501 {
01502 if( level == 1 )
01503 {
01504 strcpy( chLbl, chLineLbl(&TauLines[ipStrong]) );
01505 fprintf( punch.ipDRout, "level 1 line heating,%10.10s TauIn%10.2e%10.2e%10.2e\n",
01506 chLbl, TauInwd, TauLines[ipStrong].Emis->pump,
01507 TauLines[ipStrong].Emis->Pesc );
01508 }
01509 else if( level == 2 )
01510 {
01511 strcpy( chLbl, chLineLbl(&TauLine2[ipStrong]));
01512 fprintf( punch.ipDRout, "level 2 line heating,%10.10s TauIn%10.2e%10.2e%10.2e\n",
01513 chLbl, TauInwd, TauLine2[ipStrong].Emis->pump,
01514 TauLine2[ipStrong].Emis->Pesc );
01515 }
01516 else
01517 {
01518 fprintf( ioQQQ, " insanity pr line heat\n" );
01519 cdEXIT(EXIT_FAILURE);
01520 }
01521 }
01522
01523 else if( fp_equal( radius.drNext, drDepth ) )
01524 {
01525 fprintf( punch.ipDRout, "relative depth\n");
01526 }
01527
01528 else if( fp_equal( radius.drNext, drThermalFront ) )
01529 {
01530 fprintf( punch.ipDRout, "thermal front logic\n");
01531 }
01532
01533 else if( fp_equal( radius.drNext, dr_change_heavy ) )
01534 {
01535 ASSERT( ichange_heavy_nelem < LIMELM+3 );
01536 fprintf( punch.ipDRout,
01537 "change in ionization, element %s ion (C scale) %li rel change %.2e ion frac %.2e\n",
01538 elementnames.chElementName[ichange_heavy_nelem],
01539 ichange_heavy_ion ,
01540 change_heavy_frac_big ,
01541 frac_change_heavy_frac_big);
01542 }
01543
01544 else if( fp_equal( radius.drNext, drThickness ) )
01545 {
01546 fprintf( punch.ipDRout, "depth to go\n");
01547 }
01548
01549 else if( fp_equal( radius.drNext, AV_to_go ) )
01550 {
01551 fprintf( punch.ipDRout, "A_V to go\n");
01552 }
01553
01554 else if( fp_equal( radius.drNext, drTab ) )
01555 {
01556 fprintf( punch.ipDRout, "spec den law, new old den%10.2e%10.2e\n",
01557 hdnew, dense.gas_phase[ipHYDROGEN] );
01558 }
01559
01560 else if( fp_equal( radius.drNext, drHMase ) )
01561 {
01562 fprintf( punch.ipDRout, "H maser dTauMase=%10.2e %li %li %li %li\n",
01563 rt.dTauMase,
01564 rt.mas_species,
01565 rt.mas_ion,
01566 rt.mas_hi,
01567 rt.mas_lo );
01568 }
01569
01570 else if( fp_equal( radius.drNext, drHe1ovHe2 ) )
01571 {
01572
01573 fprintf( punch.ipDRout, "change in He0/He+ ionization, ratio %.2e\n",
01574 Old_He_atom_ov_ion );
01575 }
01576
01577 else if( fp_equal( radius.drNext, drH2_heat_cool ) )
01578 {
01579
01580 fprintf( punch.ipDRout, "change in H2 heating/cooling, d(c,h)/H %.2e\n",
01581 dH2_heat_cool );
01582 }
01583
01584 else if( fp_equal( radius.drNext, drH2_abund ) )
01585 {
01586
01587 fprintf( punch.ipDRout, "change in H2 abundance, d(H2)/H %.2e\n",
01588 dH2_abund );
01589 }
01590
01591 else if( fp_equal( radius.drNext, dr_mole_abund ) )
01592 {
01593
01594 fprintf( punch.ipDRout, "change in heav ele mole abundance, d(mole)/elem %.2e mole=%i=%s\n",
01595 dCO_abund , mole_dr_change , COmole[mole_dr_change]->label);
01596 }
01597
01598 else if( fp_equal( radius.drNext, drSolomon_BigH2 ) )
01599 {
01600
01601 fprintf( punch.ipDRout, "change in big H2 Solomon rate line opt depth\n");
01602 }
01603
01604 else if( fp_equal( radius.drNext, recom_dr_last_iter ) )
01605 {
01606
01607 fprintf( punch.ipDRout, "previous iteration recom logic\n");
01608 }
01609
01610 else if( fp_equal( radius.drNext, drHion ) )
01611 {
01612 fprintf( punch.ipDRout, "change in H ionization fm to%11.3e%11.3e\n",
01613 SaveOHIIoHI, OHIIoHI );
01614 }
01615
01616 else if( fp_equal( radius.drNext, drEfrac ) )
01617 {
01618 fprintf( punch.ipDRout,
01619 "change in elec den, rel chng:%11.3e, cur %11.3e old=%11.3e\n",
01620 dEfrac , Efrac_old , Efrac_new );
01621 }
01622
01623 else if( fp_equal( radius.drNext, drdHdStep ) )
01624 {
01625 fprintf( punch.ipDRout,
01626 "change in heating; current %10.3e delta=%10.3e\n",
01627 thermal.htot, dHdStep );
01628 }
01629
01630 else if( fp_equal( radius.drNext, drLeiden_hack ) )
01631 {
01632 fprintf( punch.ipDRout,
01633 "Leiden hack\n" );
01634 }
01635
01636 else if( fp_equal( radius.drNext, drConPres ) )
01637 {
01638 fprintf( punch.ipDRout, "change in con accel\n" );
01639 }
01640
01641 else if( fp_equal( radius.drNext, drdTdStep ) )
01642 {
01643 fprintf( punch.ipDRout,
01644 "change in temperature; current= %10.3e, dT/T= %.3f\n",
01645 phycon.te, dTdStep );
01646 }
01647
01648 else if( fp_equal( radius.drNext, radius.sdrmin ) )
01649 {
01650 fprintf( punch.ipDRout, "sdrmin\n" );
01651 }
01652
01653 else if( fp_equal( radius.drNext, radius.sdrmax ) )
01654 {
01655 fprintf( punch.ipDRout, "sdrmax\n" );
01656 }
01657
01658 else if( fp_equal( radius.drNext, drSphere ) )
01659 {
01660 fprintf( punch.ipDRout, "sphericity\n" );
01661 }
01662
01663 else if( fp_equal( radius.drNext, dRTaue ) )
01664 {
01665 fprintf( punch.ipDRout,
01666 "optical depth to electron scattering\n" );
01667 }
01668
01669 else if( fp_equal( radius.drNext, drFail ) )
01670 {
01671 fprintf( punch.ipDRout,
01672 "temperature failure.\n" );
01673 }
01674
01675 else if( fp_equal( radius.drNext, drmax ) )
01676 {
01677 fprintf( punch.ipDRout,
01678 "DRMAX; nu opc dr=%10.2e%10.2e%10.2e\n",
01679 freqm, opacm, radius.drChange/
01680 SDIV(opacm) );
01681 }
01682
01683 else if( fp_equal( radius.drNext, drInter ) )
01684 {
01685 fprintf( punch.ipDRout,
01686 "cont inter nu=%10.2e opac=%10.2e\n",
01687 freqm, opacm );
01688 }
01689
01690 else if( fp_equal( radius.drNext, DrGrainHeat ) )
01691 {
01692
01693 fprintf( punch.ipDRout,
01694 "grain heating nu=%10.2e opac=%10.2e\n",
01695 grfreqm, gropacm );
01696 }
01697
01698 else if( fp_equal( radius.drNext, winddr ) )
01699 {
01700 fprintf( punch.ipDRout,
01701 "Wind, dVelRelative=%.3e windv=%.3e\n",
01702 dVelRelative ,
01703 wind.windv);
01704 }
01705
01706 else if( fp_equal( radius.drNext, drFluc ) )
01707 {
01708 fprintf( punch.ipDRout,
01709 "density fluctuations\n" );
01710 }
01711
01712 else if( fp_equal( radius.drNext, GlobDr ) )
01713 {
01714 fprintf( punch.ipDRout,
01715 "GLOB law new dr=%10.2e HDEN=%10.2e\n",
01716 GlobDr,
01717 dense.gas_phase[ipHYDROGEN] );
01718 }
01719
01720 else if( fp_equal( radius.drNext, SpecDr ) )
01721 {
01722 fprintf( punch.ipDRout,
01723 "special law new dr=%10.2e HDEN=%10.2e\n",
01724 SpecDr,
01725 dense.gas_phase[ipHYDROGEN] );
01726 }
01727
01728 else if( fp_equal( radius.drNext, OldDR ) )
01729 {
01730 fprintf( punch.ipDRout, "old DR.\n" );
01731 }
01732
01733 else if( fp_equal( radius.drNext, drOuterRadius ) )
01734 {
01735 fprintf( punch.ipDRout, "outer radius.\n" );
01736 }
01737
01738 else
01739 {
01740 fprintf( punch.ipDRout,
01741 " %4ld radius_next keys from insanity %10.2e\n",
01742 nzone, radius.drNext );
01743
01744 fprintf( ioQQQ,
01745 " %4ld radius_next keys from insanity %10.2e\n",
01746 nzone, radius.drNext );
01747 cdEXIT(EXIT_FAILURE);
01748 }
01749
01750
01751 }
01752
01753 ASSERT( radius.drNext > 0. );
01754
01755 if( trace.lgTrace )
01756 {
01757 fprintf( ioQQQ, " radius_next chooses next drad drNext=%.4e; this drad was%12.4e\n",
01758 radius.drNext, radius.drad );
01759 }
01760
01761 return 0;
01762 }
01763
01764
01765 STATIC void ContRate(double *freqm,
01766 double *opacm)
01767 {
01768 long int i,
01769 ipHi,
01770 iplow,
01771 limit;
01772 double FreqH,
01773 Freq_nonIonizing,
01774 Opac_Hion,
01775 Opac_nonIonizing,
01776 Rate_max_Hion,
01777 Rate_max_nonIonizing;
01778
01779 DEBUG_ENTRY( "ContRate()" );
01780
01781
01782
01783
01784
01785
01786 Rate_max_nonIonizing = 0.;
01787 Freq_nonIonizing = 0.;
01788 Opac_nonIonizing = 0.;
01789
01790
01791 *opacm = -1.;
01792 *freqm = -1.;
01793
01794
01795
01796 if( dense.lgElmtOn[ipCARBON] )
01797 {
01798
01799 ipHi = Heavy.ipHeavy[ipCARBON][0] - 1;
01800 }
01801 else
01802 {
01803
01804 ipHi = iso.ipIsoLevNIonCon[ipH_LIKE][ipHYDROGEN][ipH2s]-1;
01805 }
01806
01807
01808 for( i=rfield.ipPlasma; i < ipHi; i++ )
01809 {
01810
01811
01812 if( rfield.anu[i]*rfield.flux[i]/rfield.widflx[i]*(opac.opacity_abs[i] -
01813 gv.dstab[i]*dense.gas_phase[ipHYDROGEN]) > Rate_max_nonIonizing )
01814 {
01815 Rate_max_nonIonizing = rfield.anu[i]*rfield.flux[i]/rfield.widflx[i]*
01816 (opac.opacity_abs[i] - gv.dstab[i]*dense.gas_phase[ipHYDROGEN]);
01817 Freq_nonIonizing = rfield.anu[i];
01818 Opac_nonIonizing = opac.opacity_abs[i] - gv.dstab[i]*dense.gas_phase[ipHYDROGEN];
01819 }
01820 }
01821
01822
01823
01824
01825 if( CoolHeavy.brems_heat_total/thermal.htot > 0.05 )
01826 {
01827
01828
01829 iplow = MAX2(1 , rfield.ipEnergyBremsThin );
01830 }
01831 else
01832 {
01833
01834
01835 iplow = ipHi;
01836 }
01837
01838 iplow = MAX2( rfield.ipPlasma , iplow );
01839
01840
01841 limit = MIN2(rfield.nflux,iso.ipIsoLevNIonCon[ipH_LIKE][ipHYDROGEN][ipH1s]-1);
01842 for( i=iplow; i < limit; i++ )
01843 {
01844 if( rfield.anu[i]*rfield.flux[i]/rfield.widflx[i]*(opac.opacity_abs[i] -
01845 gv.dstab[i]*dense.gas_phase[ipHYDROGEN]) > Rate_max_nonIonizing )
01846 {
01847 Rate_max_nonIonizing = rfield.anu[i]*rfield.flux[i]/rfield.widflx[i]*
01848 (opac.opacity_abs[i] - gv.dstab[i]*dense.gas_phase[ipHYDROGEN]);
01849 Freq_nonIonizing = rfield.anu[i];
01850 Opac_nonIonizing = opac.opacity_abs[i] - gv.dstab[i]*dense.gas_phase[ipHYDROGEN];
01851 }
01852 }
01853
01854
01855 Rate_max_Hion = 0.;
01856 Opac_Hion = 0.;
01857 FreqH = 0.;
01858
01859
01860 for( i=iso.ipIsoLevNIonCon[ipH_LIKE][ipHYDROGEN][ipH1s]-1; i < rfield.nflux; i++ )
01861 {
01862 if( rfield.anu[i]*rfield.flux[i]/rfield.widflx[i]*(opac.opacity_abs[i] -
01863 gv.dstab[i]*dense.gas_phase[ipHYDROGEN]) > Rate_max_Hion )
01864 {
01865
01866 Rate_max_Hion = rfield.anu[i]*rfield.flux[i]/rfield.widflx[i]*
01867 (opac.opacity_abs[i] - gv.dstab[i]*dense.gas_phase[ipHYDROGEN]);
01868 FreqH = rfield.anu[i];
01869 Opac_Hion = opac.opacity_abs[i] - gv.dstab[i]*dense.gas_phase[ipHYDROGEN];
01870 }
01871 }
01872
01873
01874 if( Rate_max_nonIonizing < 1e-30 && Opac_Hion > SMALLFLOAT )
01875 {
01876
01877 *opacm = Opac_Hion;
01878 *freqm = FreqH;
01879 }
01880
01881
01882 else if( Opac_Hion > Opac_nonIonizing && Rate_max_Hion/Rate_max_nonIonizing > 1e-10 && Opac_Hion > SMALLFLOAT )
01883 {
01884
01885 *opacm = Opac_Hion;
01886 *freqm = FreqH;
01887 }
01888 else
01889 {
01890
01891 *opacm = Opac_nonIonizing;
01892 *freqm = Freq_nonIonizing;
01893 }
01894
01895 # if 0
01896
01897
01898
01899
01900
01901 if( gv.lgDustOn && gv.lgGrainPhysicsOn )
01902 {
01903 double fluxGrainPeak = -1.;
01904 long int ipGrainPeak = -1;
01905 long int ipGrainPeak2 = -1;
01906
01907 i = 0;
01908 while( rfield.anu[i] < 0.0912 && i < (rfield.nflux-2) )
01909 {
01910
01911
01912 if( gv.GrainEmission[i]*rfield.anu[i]*opac.opacity_abs[i] > fluxGrainPeak )
01913 {
01914 ipGrainPeak = i;
01915 fluxGrainPeak = gv.GrainEmission[i]*rfield.anu[i]*opac.opacity_abs[i];
01916 }
01917 ++i;
01918 }
01919 ASSERT( fluxGrainPeak>=0. && ipGrainPeak >=0 );
01920
01921
01922
01923
01924
01925
01926
01927 i = ipGrainPeak;
01928
01929
01930
01931
01932 if( fluxGrainPeak > 0. )
01933 {
01934 while( rfield.anu[i] < 0.0912 && i < (rfield.nflux-2) )
01935 {
01936
01937 if( gv.GrainEmission[i]*rfield.anu[i]*opac.opacity_abs[i] > 0.05*fluxGrainPeak )
01938 {
01939
01940 ipGrainPeak2 = i;
01941 }
01942 ++i;
01943 }
01944 ASSERT( ipGrainPeak2>=0 );
01945
01946
01947 if( opac.opacity_abs[ipGrainPeak2] > *opacm )
01948 {
01949
01950 *opacm = opac.opacity_abs[ipGrainPeak2]*10.;
01951 *freqm = rfield.anu[ipGrainPeak2];
01952
01953
01954 }
01955 }
01956 }
01957 # endif
01958
01959 {
01960
01961 enum {DEBUG_LOC=false};
01962 if( DEBUG_LOC )
01963 {
01964 fprintf(ioQQQ,"conratedebug \t%.2e\t%.2e\t%.2e\t%.2e\t%.2e\t%.2e\t%.2e\t%.2e\n",
01965 Rate_max_nonIonizing,Freq_nonIonizing,Opac_nonIonizing,
01966 Rate_max_Hion,FreqH ,Opac_Hion,*freqm,*opacm
01967 );
01968
01969 }
01970 }
01971
01972
01973
01974
01975
01976
01977 ASSERT( *opacm >= 0. && *freqm >= 0. );
01978 return;
01979 }
01980
01981
01982 STATIC void GrainRateDr(double *grfreqm,
01983 double *gropacm)
01984 {
01985 long int i,
01986 iplow;
01987 double xMax;
01988
01989 DEBUG_ENTRY( "GrainRateDr()" );
01990
01991
01992
01993
01994
01995
01996
01997
01998 if( CoolHeavy.brems_heat_total/thermal.htot > 0.05 )
01999 {
02000
02001
02002 iplow = MAX2(1 , rfield.ipEnergyBremsThin );
02003 }
02004 else
02005 {
02006
02007
02008 if( dense.lgElmtOn[ipCARBON] )
02009 {
02010
02011 iplow = Heavy.ipHeavy[ipCARBON][0];
02012 }
02013 else
02014 {
02015
02016 iplow = iso.ipIsoLevNIonCon[ipH_LIKE][ipHYDROGEN][ipH2s];
02017 }
02018
02019 }
02020
02021 xMax = -1.;
02022
02023 for( i=iplow-1; i < Heavy.ipHeavy[ipHYDROGEN][0]; i++ )
02024 {
02025 if( rfield.anu[i]*rfield.flux[i]/rfield.widflx[i]*opac.opacity_abs[i] > xMax )
02026 {
02027 xMax = rfield.anu[i]*rfield.flux[i]/rfield.widflx[i]*
02028 opac.opacity_abs[i];
02029 *grfreqm = rfield.anu[i];
02030 *gropacm = opac.opacity_abs[i];
02031 }
02032 }
02033
02034
02035 if( dense.lgElmtOn[ipHELIUM] )
02036 {
02037 for( i=Heavy.ipHeavy[ipHYDROGEN][0]-1; i < Heavy.ipHeavy[ipHELIUM][1]; i++ )
02038 {
02039 if( rfield.anu[i]*rfield.flux[i]/rfield.widflx[i]*opac.opacity_abs[i] > xMax )
02040 {
02041 xMax = rfield.anu[i]*rfield.flux[i]/rfield.widflx[i]*
02042 opac.opacity_abs[i];
02043 *grfreqm = rfield.anu[i];
02044 *gropacm = opac.opacity_abs[i];
02045 }
02046 }
02047 }
02048
02049
02050
02051 if( xMax <= 0. )
02052 {
02053 *gropacm = 0.;
02054 *grfreqm = 0.;
02055 }
02056 return;
02057 }
02058
02059 #undef WIND_CHNG_VELOCITY_RELATIVE
02060
02061 #if 0
02062
02063 STATIC void ChkRate(
02064
02065 long int nelem,
02066
02067 double *dDestRate,
02068
02069 double *DestRateOld,
02070 double *DestRateNew,
02071
02072 long int *istage)
02073 {
02074 long int i;
02075
02076 double average,
02077 dDest;
02078
02079 static double OldDest[LIMELM][LIMELM];
02080
02081 DEBUG_ENTRY( "ChkRate()" );
02082
02083
02084 if( !dense.lgElmtOn[nelem] )
02085 {
02086 *dDestRate = 1e-3;
02087 *DestRateOld = 1e-3;
02088 *DestRateNew = 1e-3;
02089 *istage = 0;
02090 return;
02091 }
02092
02093
02094
02095 *istage = 1;
02096 *dDestRate = 0.;
02097 *DestRateOld = 0.;
02098 *DestRateNew = 0.;
02099 *dDestRate = 0.;
02100
02101 if( nzone <= 1 )
02102 {
02103 for( i=0; i < nelem+1; i++ )
02104 {
02105 OldDest[nelem][i] = ionbal.RateIonizTot[nelem][i];
02106 }
02107 }
02108
02109 else if( dense.xIonDense[nelem][0]/dense.gas_phase[nelem] < 0.9 )
02110 {
02111
02112 for( i=0; i < (nelem); i++ )
02113 {
02114
02115
02116
02117 if( ((dense.xIonDense[nelem][i]/dense.gas_phase[nelem] > 0.01 &&
02118 dense.xIonDense[nelem][i]/dense.gas_phase[nelem] < 0.9) &&
02119 dense.xIonDense[nelem][i+1]/dense.gas_phase[nelem] > .05) &&
02120 OldDest[nelem][i] > 0. )
02121 {
02122
02123
02124
02125 if( ionbal.RateIonizTot[nelem][i] <= 0. )
02126 {
02127 fprintf( ioQQQ, " ChkRate gets insane destruction rate for ion%4ld%4ld%10.2e\n",
02128 nelem+1, i, ionbal.RateIonizTot[nelem][i] );
02129 cdEXIT(EXIT_FAILURE);
02130 }
02131
02132
02133
02134
02135
02136 average = (OldDest[nelem][i] + ionbal.RateIonizTot[nelem][i])* 0.5;
02137
02138 dDest = (OldDest[nelem][i] - ionbal.RateIonizTot[nelem][i])/ average;
02139
02140
02141 if( *dDestRate < dDest )
02142 {
02143
02144 *dDestRate = dDest;
02145 *istage = i+1;
02146 *DestRateOld = OldDest[nelem][i];
02147 *DestRateNew = ionbal.RateIonizTot[nelem][i];
02148 }
02149
02150 }
02151 OldDest[nelem][i] = ionbal.RateIonizTot[nelem][i];
02152 }
02153 }
02154 return;
02155 }
02156 #endif