00001
00002
00003
00004 #include "cddefines.h"
00005
00006 #ifdef EPS
00007 # undef EPS
00008 #endif
00009 #define EPS 1.00001
00010 #include "lines.h"
00011 #include "mole.h"
00012 #include "conv.h"
00013 #include "rfield.h"
00014 #include "iterations.h"
00015 #include "trace.h"
00016 #include "dense.h"
00017 #include "colden.h"
00018 #include "taulines.h"
00019 #include "hmi.h"
00020 #include "prt.h"
00021 #include "phycon.h"
00022 #include "geometry.h"
00023 #include "stopcalc.h"
00024 #include "opacity.h"
00025 #include "thermal.h"
00026 #include "cooling.h"
00027 #include "predcont.h"
00028 #include "pressure.h"
00029 #include "radius.h"
00030 #include "called.h"
00031 #include "wind.h"
00032 #include "hcmap.h"
00033
00034
00035 STATIC void dmpary(void);
00036
00037 int iter_end_check(void)
00038 {
00039 bool lgDone,
00040 lgEndFun_v,
00041 lgPrinted;
00042 long int i;
00043 double oxy_in_grains;
00044
00045 DEBUG_ENTRY( "iter_end_check()" );
00046
00047
00048
00049
00050 oxy_in_grains = 0.0f;
00051 for(i=0;i<mole.num_comole_calc;++i)
00052 {
00053
00054 oxy_in_grains += (1 - COmole[i]->lgGas_Phase)*COmole[i]->hevmol*COmole[i]->nElem[ipOXYGEN];
00055 }
00056
00057
00058
00059
00060 if( trace.lgTrace )
00061 {
00062 fprintf( ioQQQ, " iter_end_check called, zone %li.\n" , nzone);
00063 }
00064 ASSERT( hcmap.MapZone >= 00 || !conv.lgSearch );
00065
00066
00067 if( nzone == 0 )
00068 {
00069 lgEndFun_v = false;
00070
00071 if( trace.lgTrace )
00072 {
00073 fprintf( ioQQQ, " iter_end_check returns, doing nothing since zone 0.\n" );
00074 }
00075 return( lgEndFun_v );
00076 }
00077
00078
00079 if( (nzone >= trace.nznbug && iteration >= trace.npsbug) && trace.lgTrOvrd )
00080 {
00081 if( trace.nTrConvg==0 )
00082 {
00083 geometry.nprint = 1;
00084 trace.lgTrace = true;
00085 }
00086 else
00087
00088
00089 trace.nTrConvg = abs( trace.nTrConvg );
00090 }
00091
00092
00093 if( prt.lgPrtStart && prt.nstart == nzone )
00094 {
00095 called.lgTalk = cpu.lgMPI_talk();
00096 }
00097
00098
00099 lgDone = false;
00100
00101
00102 conv.lgBadStop = false;
00103
00104
00105
00106
00107 if( phycon.te < StopCalc.TeFloor )
00108 {
00109 thermal.lgTemperatureConstant = true;
00110 thermal.ConstTemp = (realnum)StopCalc.TeFloor;
00111 phycon.te = thermal.ConstTemp;
00112 TempChange(thermal.ConstTemp , false);
00113 TotalInsanity();
00114 }
00115
00116
00117
00118 if( (pressure.lgPres_radiation_ON && pressure.pbeta > 1.0) &&
00119 (strcmp(dense.chDenseLaw ,"CPRE") == 0) &&
00120
00121 (iterations.lgLastIt||(pressure.pbeta>1000.)) &&
00122
00123
00124
00125 (pressure.lgRadPresAbortOK||(pressure.pbeta>1000.)) )
00126 {
00127
00128 if( called.lgTalk )
00129 {
00130 fprintf( ioQQQ, "\n STOP since P(rad)/P(gas)=%7.3f >1.0\n",
00131 pressure.pbeta );
00132
00133 fprintf( ioQQQ, " Line contributors to radiation pressure follows:\n" );
00134 PrtLinePres(ioQQQ);
00135 }
00136 lgDone = true;
00137 conv.lgBadStop = true;
00138 strncpy( StopCalc.chReasonStop, "of radiation pressure.", sizeof(StopCalc.chReasonStop) );
00139 }
00140
00141
00142 if( radius.drad_x_fillfac*radius.r1r0sq > BIGFLOAT/10.)
00143 {
00144
00145 lgDone = true;
00146 strncpy( StopCalc.chReasonStop, "volume too large for this cpu.", sizeof(StopCalc.chReasonStop) );
00147 }
00148
00149
00150 else if( !wind.lgVelPos && wind.lgBallistic() )
00151 {
00152
00153 lgDone = true;
00154 strncpy( StopCalc.chReasonStop, "wind veloc too small.", sizeof(StopCalc.chReasonStop) );
00155 }
00156
00157 else if( !wind.lgStatic() && fabs(wind.windv) < StopCalc.StopVelocity )
00158 {
00159
00160 lgDone = true;
00161 strncpy( StopCalc.chReasonStop, "wind V too small.", sizeof(StopCalc.chReasonStop) );
00162 }
00163
00164 else if( (StopCalc.nTotalIonizStop>0) && conv.nTotalIoniz> StopCalc.nTotalIonizStop )
00165 {
00166
00167
00168 lgDone = true;
00169 strncpy( StopCalc.chReasonStop, "nTotalIonizStop reached.", sizeof(StopCalc.chReasonStop) );
00170 }
00171
00172
00173 else if( StopCalc.lgStop21cm && (HFLines[0].Emis->TauCon >= StopCalc.tauend) )
00174 {
00175 lgDone = true;
00176 strncpy( StopCalc.chReasonStop, "21 cm optical depth.", sizeof(StopCalc.chReasonStop) );
00177 }
00178
00179 else if( rfield.extin_mag_V_extended >= StopCalc.AV_extended )
00180 {
00181
00182 lgDone = true;
00183 strncpy( StopCalc.chReasonStop, "A_V reached.", sizeof(StopCalc.chReasonStop) );
00184 }
00185
00186 else if( rfield.extin_mag_V_point >= StopCalc.AV_point )
00187 {
00188
00189 lgDone = true;
00190 strncpy( StopCalc.chReasonStop, "A_V reached.", sizeof(StopCalc.chReasonStop) );
00191 }
00192
00193 else if( StopCalc.xMass!=0. &&
00194 log10(SDIV(dense.xMassTotal))+1.0992099+ 2.*log10(radius.rinner) >= StopCalc.xMass )
00195 {
00196
00197 lgDone = true;
00198 strncpy( StopCalc.chReasonStop, "mass reached.", sizeof(StopCalc.chReasonStop) );
00199 }
00200
00201
00202
00203
00204 else if( pressure.lgSonicPoint && pressure.lgSonicPointAbortOK )
00205 {
00206
00207 lgDone = true;
00208 strncpy( StopCalc.chReasonStop, "sonic point reached.", sizeof(StopCalc.chReasonStop) );
00209 }
00210
00211 else if( dense.EdenTrue==0 )
00212 {
00213
00214 conv.lgBadStop = true;
00215 lgDone = true;
00216 strncpy( StopCalc.chReasonStop, "zero electron density.", sizeof(StopCalc.chReasonStop) );
00217 }
00218
00219 else if( radius.lgdR2Small )
00220 {
00221 lgDone = true;
00222 conv.lgBadStop = true;
00223 strncpy( StopCalc.chReasonStop, "DR small rel to thick.", sizeof(StopCalc.chReasonStop) );
00224 }
00225
00226 else if( dense.eden < StopCalc.StopElecDensity )
00227 {
00228 lgDone = true;
00229 strncpy( StopCalc.chReasonStop, "lowest EDEN reached.", sizeof(StopCalc.chReasonStop) );
00230 }
00231
00232 else if( dense.eden/dense.gas_phase[ipHYDROGEN] < StopCalc.StopElecFrac )
00233 {
00234 lgDone = true;
00235 strncpy( StopCalc.chReasonStop, "low electron fraction.", sizeof(StopCalc.chReasonStop) );
00236 }
00237
00238
00239
00240
00241 else if( dense.lgElmtOn[ipOXYGEN] &&
00242 (oxy_in_grains/MAX2(SMALLFLOAT,dense.gas_phase[ipOXYGEN])) > StopCalc.StopDepleteFrac )
00243 {
00244 lgDone = true;
00245 strncpy( StopCalc.chReasonStop, "freeze out fraction.", sizeof(StopCalc.chReasonStop) );
00246 }
00247
00248
00249 else if( 2.*hmi.H2_total/dense.gas_phase[ipHYDROGEN] > StopCalc.StopH2MoleFrac )
00250 {
00251 lgDone = true;
00252 strncpy( StopCalc.chReasonStop, "large H_2/H fraction.", sizeof(StopCalc.chReasonStop) );
00253 }
00254
00255 else if( dense.xIonDense[ipHYDROGEN][1]/dense.gas_phase[ipHYDROGEN] <
00256 StopCalc.StopHPlusFrac )
00257 {
00258 lgDone = true;
00259 strncpy( StopCalc.chReasonStop, "low H_+/H fraction.", sizeof(StopCalc.chReasonStop) );
00260 }
00261
00262 else if( radius.lgDrMinUsed )
00263 {
00264
00265 conv.lgBadStop = true;
00266 lgDone = true;
00267 strncpy( StopCalc.chReasonStop, "DRAD small- set DRMIN.", sizeof(StopCalc.chReasonStop) );
00268 }
00269
00270 else if( radius.depth >= radius.StopThickness[iteration-1]/EPS )
00271 {
00272 lgDone = true;
00273 strncpy( StopCalc.chReasonStop, "outer radius reached.", sizeof(StopCalc.chReasonStop) );
00274 }
00275
00276 else if( StopCalc.iptnu >= 0 &&
00277 opac.TauAbsGeo[0][StopCalc.iptnu-1] >= StopCalc.tauend/EPS )
00278 {
00279 lgDone = true;
00280 strncpy( StopCalc.chReasonStop, "optical depth reached.", sizeof(StopCalc.chReasonStop) );
00281 }
00282
00283 else if( StopCalc.lgStopSpeciesColumn &&
00284 findspecies( StopCalc.chSpeciesColumn )->hevcol >= StopCalc.col_species/EPS )
00285 {
00286
00287 lgDone = true;
00288 sprintf( StopCalc.chReasonStop, "%s column dens reached.", StopCalc.chSpeciesColumn );
00289
00290 }
00291
00292 else if( colden.colden[ipCOL_HTOT] >= StopCalc.HColStop/EPS )
00293 {
00294
00295 lgDone = true;
00296 strncpy( StopCalc.chReasonStop, "H column dens reached.", sizeof(StopCalc.chReasonStop) );
00297 }
00298
00299 else if( colden.colden[ipCOL_Hp] >= StopCalc.colpls/EPS )
00300 {
00301 lgDone = true;
00302 strncpy( StopCalc.chReasonStop, "H+ column dens reached.", sizeof(StopCalc.chReasonStop) );
00303 }
00304
00305 else if( (colden.colden[ipCOL_H2g]+colden.colden[ipCOL_H2s]) >= StopCalc.col_h2/EPS )
00306 {
00307
00308 lgDone = true;
00309 strncpy( StopCalc.chReasonStop, "H2 column dens reached.", sizeof(StopCalc.chReasonStop) );
00310 }
00311
00312 else if( (2.*(colden.colden[ipCOL_H2g]+colden.colden[ipCOL_H2s]) + colden.colden[ipCOL_H0]) >= StopCalc.col_h2_nut/EPS )
00313 {
00314
00315 lgDone = true;
00316 strncpy( StopCalc.chReasonStop, "H2+H0 column dens reached.", sizeof(StopCalc.chReasonStop) );
00317 }
00318
00319 else if( colden.H0_ov_Tspin >= StopCalc.col_H0_ov_Tspin/EPS )
00320 {
00321
00322 lgDone = true;
00323 strncpy( StopCalc.chReasonStop, "N(H0)/Tspin column dens reached.", sizeof(StopCalc.chReasonStop) );
00324 }
00325
00326 else if( findspecies("CO")->hevcol >= StopCalc.col_monoxco/EPS )
00327 {
00328
00329 lgDone = true;
00330 strncpy( StopCalc.chReasonStop, "CO column dens reached.", sizeof(StopCalc.chReasonStop) );
00331 }
00332
00333 else if( colden.colden[ipCOL_H0] >= StopCalc.colnut/EPS )
00334 {
00335 lgDone = true;
00336 strncpy( StopCalc.chReasonStop, "H0 column dens reached.", sizeof(StopCalc.chReasonStop) );
00337 }
00338
00339
00340
00341 else if( hmi.lgNoH2Mole &&
00342 ( (colden.colden[ipCOL_H0]+2.*(colden.colden[ipCOL_H2g]+colden.colden[ipCOL_H2s])) >= StopCalc.colnut/EPS) )
00343 {
00344 lgDone = true;
00345 strncpy( StopCalc.chReasonStop, "H0-H0+H2 column dens reached.", sizeof(StopCalc.chReasonStop) );
00346 }
00347
00348 else if( phycon.te > StopCalc.TempHiStopZone )
00349 {
00350 lgDone = true;
00351 strncpy( StopCalc.chReasonStop, "highest Te reached.", sizeof(StopCalc.chReasonStop) );
00352 }
00353
00354 else if( phycon.te < StopCalc.TempLoStopZone )
00355 {
00356 lgDone = true;
00357 strncpy( StopCalc.chReasonStop, "lowest Te reached.", sizeof(StopCalc.chReasonStop) );
00358 }
00359
00360 else if( nzone >= geometry.nend[iteration-1] )
00361 {
00362 lgDone = true;
00363 geometry.lgZoneTrp = true;
00364 strncpy( StopCalc.chReasonStop, "NZONE reached.", sizeof(StopCalc.chReasonStop) );
00365 }
00366
00367
00368
00369 else if( StopCalc.nstpl > 0 || StopCalc.ContIndex.size() > 0 )
00370 {
00371
00372
00373 for( i=0; i < StopCalc.nstpl; i++ )
00374 {
00375
00376 if( LineSv[StopCalc.ipStopLin2[i]].SumLine[StopCalc.nEmergent[i]] > 0. )
00377 {
00378 char chString[10];
00379 if( LineSv[StopCalc.ipStopLin1[i]].SumLine[StopCalc.nEmergent[i]]/
00380 LineSv[StopCalc.ipStopLin2[i]].SumLine[StopCalc.nEmergent[i]] >
00381 StopCalc.stpint[i] )
00382 {
00383 lgDone = true;
00384 sprt_wl( chString , StopCalc.StopLineWl1[i] );
00385 sprintf( StopCalc.chReasonStop, "line %s %s reached",
00386 StopCalc.chStopLabel1[i] , chString );
00387 }
00388 }
00389 }
00390
00391 for( size_t k=0; k < StopCalc.ContIndex.size(); ++k )
00392 {
00393
00394 long ind = t_PredCont::Inst().offset() + 4*StopCalc.ContIndex[k];
00395 double nFnu_model = LineSv[ind].SumLine[0]*pow(10.,radius.Conv2PrtInten);
00396 if( nFnu_model >= StopCalc.ContNFnu[k].get("erg/s/cm2") )
00397 {
00398 char chTemp[10];
00399 lgDone = true;
00400 sprt_wl( chTemp, LineSv[ind].wavelength );
00401 sprintf( StopCalc.chReasonStop, "flux %s %s reached",
00402 LineSv[ind].chALab, chTemp );
00403 }
00404 }
00405 }
00406
00407 else if( radius.drNext <= 0. )
00408 {
00409
00410 if( called.lgTalk )
00411 {
00412 fprintf( ioQQQ, " drNext=%10.2e STOP\n", radius.drNext );
00413 }
00414 lgDone = true;
00415 conv.lgBadStop = true;
00416 strncpy( StopCalc.chReasonStop, "internal error - DRAD.", sizeof(StopCalc.chReasonStop) );
00417 ShowMe();
00418 cdEXIT(EXIT_FAILURE);
00419 }
00420
00421 else if( lgAbort )
00422 {
00423
00424 conv.lgBadStop = true;
00425 lgDone = true;
00426 strncpy( StopCalc.chReasonStop, "calculation aborted.", sizeof(StopCalc.chReasonStop) );
00427 }
00428
00429 lgPrinted = false;
00430 if( lgDone )
00431 {
00432
00433 lgEndFun_v = true;
00434 PrtZone();
00435 lgPrinted = true;
00436 }
00437
00438 else
00439 {
00440
00441
00442 if( ((nzone/geometry.nprint)*geometry.nprint == nzone ||
00443 nzone == 1) || trace.nTrConvg )
00444 {
00445 PrtZone();
00446 lgPrinted = true;
00447 }
00448
00449 lgEndFun_v = false;
00450 }
00451
00452
00453 if( prt.nzdump == nzone || prt.nzdump == 0 )
00454 dmpary();
00455
00456
00457
00458
00459
00460 if( !hcmap.lgMapDone && (hcmap.MapZone == 0 || nzone == hcmap.MapZone) )
00461 {
00462
00463 if( !lgPrinted )
00464 {
00465 PrtZone();
00466 }
00467
00468
00469 hcmap.lgMapBeingDone = true;
00470
00471
00472
00473 if( ioMAP != NULL )
00474 map_do(ioMAP, " map");
00475 else
00476 map_do(ioQQQ, " map");
00477
00478
00479 lgEndFun_v = true;
00480 strncpy( StopCalc.chReasonStop, "MAP command used-stop.", sizeof(StopCalc.chReasonStop) );
00481
00482
00483
00484 iterations.itermx = 0;
00485
00486
00487 StopCalc.chReasonStop[sizeof(StopCalc.chReasonStop)-1] = '\0';
00488
00489 if( trace.lgTrace )
00490 {
00491 fprintf( ioQQQ, " iter_end_check returns after map.\n" );
00492 }
00493 return( lgEndFun_v );
00494 }
00495
00496 if( lgEndFun_v && prt.lgOnlyZone )
00497 {
00498 cdEXIT(EXIT_FAILURE);
00499 }
00500
00501
00502
00503
00504 if( strlen( StopCalc.chReasonStop ) >= nCHREASONSTOP-1 )
00505 TotalInsanity();
00506
00507 if( trace.lgTrace )
00508 {
00509 fprintf( ioQQQ, " iter_end_check bottom return.\n" );
00510 }
00511 return( lgEndFun_v );
00512 }
00513
00514 #ifdef EPS
00515 # undef EPS
00516 #endif
00517 #define EPS 0.005
00518
00519 STATIC void dmpary(void)
00520 {
00521 long int i;
00522 realnum ratio;
00523
00524 DEBUG_ENTRY( "dmpary()" );
00525
00526 fprintf( ioQQQ,
00527 " This is a print out of the cooling array for zone number %3ld\n",
00528 nzone );
00529
00530 fprintf( ioQQQ,
00531 " The total heating was HTOT=%10.2e erg/s/cm3, the total cooling was CTOT=%10.2e, and the temperature was%10.3eK.\n",
00532 thermal.htot, thermal.ctot, phycon.te );
00533
00534 fprintf( ioQQQ,
00535 " All coolants greater than%6.2f%% of the total will be printed.\n",
00536 EPS*100. );
00537
00538
00539 coolpr(ioQQQ,"ZERO",1,0.,"ZERO");
00540 for( i=0; i < thermal.ncltot; i++ )
00541 {
00542 ratio = (realnum)(thermal.cooling[i]/thermal.ctot);
00543 if( fabs(ratio) > EPS )
00544 {
00545 coolpr(ioQQQ,(char*)thermal.chClntLab[i],thermal.collam[i],
00546 ratio,"DOIT");
00547 }
00548
00549 ratio = (realnum)(thermal.heatnt[i]/thermal.ctot);
00550 if( fabs(ratio) > EPS )
00551 {
00552 coolpr(ioQQQ,(char*)thermal.chClntLab[i],thermal.collam[i],
00553 ratio,"DOIT");
00554 }
00555 }
00556 coolpr(ioQQQ,"DONE",1,0.,"DONE");
00557 return;
00558 }