00001
00002
00003
00004
00005
00006 #include "cddefines.h"
00007 #include "physconst.h"
00008 #include "trace.h"
00009 #include "struc.h"
00010 #include "rfield.h"
00011 #include "mole.h"
00012 #include "dense.h"
00013 #include "stopcalc.h"
00014 #include "heavy.h"
00015 #include "wind.h"
00016 #include "geometry.h"
00017 #include "thermal.h"
00018 #include "radius.h"
00019 #include "phycon.h"
00020 #include "pressure.h"
00021 #include "conv.h"
00022
00023
00024 static double dCoolNetDTOld = 0;
00025
00026 static double OxyInGrains , FracMoleMax;
00027
00028
00029
00030
00031
00032
00033 STATIC bool lgCoolHeatCheckConverge(
00034 double *CoolNet )
00035 {
00036 static double HeatOld=-1. , CoolOld=-1.;
00037 DEBUG_ENTRY( "lgCoolHeatCheckConverge()" );
00038
00039 double HeatChange = thermal.htot - HeatOld;
00040 double CoolChange = thermal.ctot - CoolOld;
00041
00042
00043 double HeatCoolMax = MAX2( thermal.htot , thermal.ctot );
00044
00045
00046
00047 double HeatRelChange = fabs(HeatChange)/SDIV( HeatCoolMax );
00048 double CoolRelChange = fabs(CoolChange)/SDIV( HeatCoolMax );
00049 bool lgConverged = true;
00050 if( MAX2( HeatRelChange , CoolRelChange ) > conv.HeatCoolRelErrorAllowed )
00051 lgConverged = false;
00052
00053 *CoolNet = thermal.ctot - thermal.htot;
00054
00055 HeatOld = thermal.htot;
00056 CoolOld = thermal.ctot;
00057 return lgConverged;
00058 }
00059
00060
00061 STATIC bool lgCoolNetConverge(
00062 double *CoolNet ,
00063 double *dCoolNetDT )
00064 {
00065 const long int LOOP_MAX=20;
00066 long int loop = 0;
00067 bool lgConvergeCoolHeat = false;
00068
00069 DEBUG_ENTRY( "lgCoolNetConverge()" );
00070
00071 while( loop < LOOP_MAX && !lgConvergeCoolHeat && !lgAbort )
00072 {
00073 if( ConvEdenIoniz() )
00074 {
00075
00076 lgAbort = true;
00077 }
00078 lgConvergeCoolHeat = lgCoolHeatCheckConverge( CoolNet );
00079 if( trace.lgTrace || trace.nTrConvg>=3 )
00080 fprintf(ioQQQ," lgCoolNetConverge %li calls to ConvEdenIoniz, converged? %c\n",
00081 loop , TorF( lgConvergeCoolHeat ) );
00082 ++loop;
00083 }
00084
00085 if( thermal.ConstTemp > 0 )
00086 {
00087
00088
00089 *CoolNet = phycon.te - thermal.ConstTemp;
00090 *dCoolNetDT = 1.f;
00091 }
00092 else if( phycon.te < 4000.f )
00093 {
00094
00095
00096
00097
00098
00099 *dCoolNetDT = thermal.ctot / phycon.te;
00100 }
00101 else if( thermal.htot / thermal.ctot > 2.f )
00102 {
00103
00104
00105
00106 *dCoolNetDT = thermal.ctot / phycon.te;
00107 }
00108 else
00109 {
00110 *dCoolNetDT = thermal.dCooldT - thermal.dHeatdT;
00111 if( dCoolNetDTOld * *dCoolNetDT < 0. )
00112 {
00113
00114 *dCoolNetDT = *CoolNet / phycon.te;
00115 fprintf(ioQQQ,"PROBLEM CoolNet derivative oscillating in initial solution \n");
00116 }
00117 }
00118 return lgConvergeCoolHeat;
00119 }
00120
00121
00122 STATIC void ChemImportance( void )
00123 {
00124 long int i;
00125
00126 DEBUG_ENTRY( "ChemImportance()" );
00127
00128 FracMoleMax = 0.;
00129 long int ipMax = -1;
00130 for( i=0; i<mole.num_comole_calc; ++i )
00131 {
00132
00133 if( dense.lgElmtOn[COmole[i]->nelem_hevmol] && COmole[i]->n_nuclei>1 )
00134 {
00135 realnum frac = COmole[i]->hevmol / SDIV(dense.gas_phase[COmole[i]->nelem_hevmol]);
00136 frac *= (realnum) COmole[i]->nElem[COmole[i]->nelem_hevmol];
00137 if( frac > FracMoleMax )
00138 {
00139
00140 FracMoleMax = frac;
00141 ipMax = i;
00142 }
00143 }
00144 }
00145
00146
00147 OxyInGrains = 0;
00148 for(i=0;i<mole.num_comole_calc;++i)
00149 {
00150 OxyInGrains += (1 - COmole[i]->lgGas_Phase)*COmole[i]->hevmol*COmole[i]->nElem[ipOXYGEN];
00151 }
00152
00153 OxyInGrains /= SDIV(dense.gas_phase[ipOXYGEN]);
00154
00155 {
00156
00157 enum {DEBUG_LOC=false};
00158 if( DEBUG_LOC )
00159 {
00160 fprintf(ioQQQ,"DEBUG fraction molecular %.2e species %li O ices %.2e\n" ,
00161 FracMoleMax , ipMax ,OxyInGrains );
00162 }
00163 }
00164
00165 return;
00166 }
00167
00168 double FindTempChangeFactor(void)
00169 {
00170 double TeChangeFactor;
00171
00172 DEBUG_ENTRY( "FindTempChangeFactor()" );
00173
00174
00175
00176
00177
00178
00179
00180 ChemImportance();
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 if( OxyInGrains > 0.99 )
00193 {
00194 TeChangeFactor = 0.999;
00195 }
00196 else if( OxyInGrains > 0.9 )
00197 {
00198 TeChangeFactor = 0.99;
00199 }
00200
00201 else if( phycon.te < 5. ||
00202
00203 OxyInGrains > 0.1 )
00204 {
00205 TeChangeFactor = 0.97;
00206 }
00207
00208 else if( phycon.te < 20. || FracMoleMax > 0.1 )
00209 {
00210
00211
00212 TeChangeFactor = 0.95;
00213 }
00214 else
00215 {
00216
00217 TeChangeFactor = 0.8;
00218 }
00219 return TeChangeFactor;
00220 }
00221
00222
00223 int ConvInitSolution(void)
00224 {
00225 long int i,
00226 ionlup,
00227 nelem ,
00228 nflux_old,
00229 nelem_reflux ,
00230 ion_reflux;
00231
00232 bool lgConvergeCoolHeat;
00233
00234 double
00235 TeChangeFactor,
00236 TeBoundLow,
00237 TeBoundHigh;
00238
00239 DEBUG_ENTRY( "ConvInitSolution()" );
00240
00241
00242 set_NaN( TeBoundLow );
00243 set_NaN( TeBoundHigh );
00244
00245
00246 conv.nPres2Ioniz = 0;
00247
00248
00249
00250 conv.nTotalIoniz = 0;
00251
00252 conv.lgOscilOTS = false;
00253
00254 lgAbort = false;
00255 dense.lgEdenBad = false;
00256 dense.nzEdenBad = 0;
00257
00258
00259 conv.BigEdenError = 0.;
00260 conv.AverEdenError = 0.;
00261 conv.BigHeatCoolError = 0.;
00262 conv.AverHeatCoolError = 0.;
00263 conv.BigPressError = 0.;
00264 conv.AverPressError = 0.;
00265
00266
00267 if( fp_equal( radius.sdrmin, radius.sdrmax ) )
00268 {
00269 radius.drad = MIN2( radius.sdrmax , radius.drad );
00270 radius.drad_x_fillfac = radius.drad * geometry.FillFac;
00271 }
00272
00273
00274
00275
00276
00277 ASSERT( dense.xIonDense[ipHYDROGEN][0] >0 && dense.xIonDense[ipHYDROGEN][1]>= 0.);
00278
00279 if( trace.nTrConvg )
00280 {
00281 fprintf( ioQQQ, "\nConvInitSolution entered \n" );
00282 }
00283
00284
00285
00286
00287
00288
00289 if( iteration != 1 )
00290 {
00291
00292 if( trace.lgTrace || trace.nTrConvg )
00293 {
00294 fprintf( ioQQQ, " ConvInitSolution called, ITER=%2ld resetting Te to %10.2e\n",
00295 iteration, struc.testr[0] );
00296 }
00297
00298 if( trace.lgTrace || trace.nTrConvg )
00299 {
00300 fprintf( ioQQQ, " search set true\n" );
00301 }
00302
00303
00304
00305
00306 conv.lgSearch = true;
00307
00308
00309
00310
00311 TempChange( struc.testr[0] , false);
00312
00313
00314
00315 PresTotCurrent();
00316
00317
00318 if( ConvPresTempEdenIoniz() )
00319 {
00320
00321 lgAbort = true;
00322 return(1);
00323 }
00324
00325 if( trace.lgTrace || trace.nTrConvg )
00326 {
00327 fprintf( ioQQQ, " ========================================================================================================================\n");
00328 fprintf( ioQQQ, " ConvInitSolution: search set false 2 Te=%.3e========================================================================================\n" , phycon.te);
00329 fprintf( ioQQQ, " ========================================================================================================================\n");
00330 }
00331 conv.lgSearch = false;
00332
00333
00334 if( ConvTempEdenIoniz() )
00335 {
00336
00337 lgAbort = true;
00338 return(1);
00339 }
00340
00341
00342
00343 PresTotCurrent();
00344 }
00345
00346 else
00347 {
00348
00349
00350
00351
00352
00353
00354
00355 conv.lgSearch = true;
00356
00357 if( trace.lgTrace )
00358 {
00359 fprintf( ioQQQ, " ConvInitSolution called, new temperature.\n" );
00360 }
00361
00362
00363 TeBoundLow = phycon.TEMP_LIMIT_LOW/1.001;
00364
00365
00366
00367
00368 TeBoundLow = MAX2( TeBoundLow , StopCalc.TeFloor );
00369
00370
00371
00372
00373 TeBoundHigh = phycon.TEMP_LIMIT_HIGH/1.2;
00374
00375
00376
00377 double TeFirst;
00378 if( thermal.ConstTemp > 0 )
00379 {
00380
00381
00382
00383 TeFirst = MAX2( 4000. , thermal.ConstTemp );
00384
00385 }
00386 else if( thermal.lgTeHigh )
00387 {
00388
00389 TeFirst = 1e6;
00390 }
00391 else
00392 {
00393
00394 TeFirst = 4000.;
00395 }
00396 TempChange(TeFirst , false);
00397 if( trace.lgTrace || trace.nTrConvg>=2 )
00398 fprintf(ioQQQ,"ConvInitSolution doing initial solution with temp=%.2e\n",
00399 phycon.te);
00400
00401
00402 PresTotCurrent();
00403
00404 thermal.htot = 1.;
00405 thermal.ctot = 1.;
00406
00407
00408
00409
00410 double CoolNet=0, dCoolNetDT=0;
00411
00412 lgConvergeCoolHeat = false;
00413 for( ionlup=0; ionlup<2; ++ionlup )
00414 {
00415 if( trace.lgTrace || trace.nTrConvg>=2 )
00416 fprintf( ioQQQ, "ConvInitSolution calling lgCoolNetConverge "
00417 "initial setup %li with Te=%.3e C=%.2e H=%.2e d(C-H)/dT %.3e\n",
00418 ionlup,phycon.te , thermal.ctot , thermal.htot,dCoolNetDT );
00419
00420 dCoolNetDTOld = 0.;
00421 lgConvergeCoolHeat = lgCoolNetConverge( &CoolNet , &dCoolNetDT );
00422 if( lgAbort )
00423 break;
00424
00425
00426
00427
00428 radius_first();
00429 }
00430 if( !lgConvergeCoolHeat )
00431 fprintf(ioQQQ," PROBLEM ConvInitSolution did not converge the heating-cooling during initial search.\n");
00432
00433 if( lgAbort )
00434 {
00435
00436 fprintf( ioQQQ, " DISASTER PROBLEM ConvInitSolution: Search for "
00437 "initial conditions aborted - lgAbort set true.\n" );
00438 ShowMe();
00439
00440 return(1);
00441 }
00442
00443
00444
00445 if( thermal.ConstTemp<=0 )
00446 dCoolNetDT = thermal.ctot / phycon.te;
00447 bool lgConvergedLoop = false;
00448 long int LoopThermal = 0;
00449
00450
00451
00452 const long int LIMIT_THERMAL_LOOP=300;
00453 double CoolMHeatSave=-1. , TempSave=-1. , TeNew=-1.,CoolSave=-1;
00454 while( !lgConvergedLoop && LoopThermal < LIMIT_THERMAL_LOOP )
00455 {
00456
00457 CoolMHeatSave = CoolNet;
00458 dCoolNetDTOld = dCoolNetDT;
00459 CoolSave = thermal.ctot;
00460 TempSave = phycon.te;
00461
00462
00463 TeChangeFactor = FindTempChangeFactor();
00464 ASSERT( TeChangeFactor>0. && TeChangeFactor< 1. );
00465
00466 TeNew = phycon.te - CoolNet / dCoolNetDT;
00467
00468 TeNew = MAX2( phycon.te*TeChangeFactor , TeNew );
00469 TeNew = MIN2( phycon.te/TeChangeFactor , TeNew );
00470
00471 TempChange(TeNew , true);
00472 lgConvergeCoolHeat = lgCoolNetConverge( &CoolNet , & dCoolNetDT );
00473
00474 if( trace.lgTrace || trace.nTrConvg>=2 )
00475 fprintf(ioQQQ,"ConvInitSolution %4li TeNnew=%.3e "
00476 "TeChangeFactor=%.3e Cnet/H=%.2e dCnet/dT=%10.2e Ne=%.3e"
00477 " Ograins %.2e FracMoleMax %.2e\n",
00478 LoopThermal , TeNew , TeChangeFactor ,
00479 CoolNet/SDIV(thermal.htot) , dCoolNetDT,
00480 dense.eden , OxyInGrains , FracMoleMax );
00481 if( lgAbort )
00482 {
00483
00484 fprintf( ioQQQ, " Search for initial conditions aborted - "
00485 "lgAbort set true, lgConvergeCoolHeat=%c.\n",
00486 TorF(lgConvergeCoolHeat) );
00487
00488 return(1);
00489 }
00490
00491
00492
00493
00494
00495 if( fabs(CoolNet)< SMALLDOUBLE )
00496
00497 lgConvergedLoop = true;
00498 else if( (CoolNet/fabs(CoolNet))*(CoolMHeatSave/fabs(CoolMHeatSave)) <= 0)
00499
00500 lgConvergedLoop = true;
00501 else if( fabs(CoolNet)/MAX2( thermal.ctot , thermal.htot ) <conv.HeatCoolRelErrorAllowed*10. )
00502 lgConvergedLoop = true;
00503 else if( phycon.te <= TeBoundLow || phycon.te>=TeBoundHigh)
00504 lgConvergedLoop = true;
00505 ++LoopThermal;
00506 }
00507
00508 if( !lgConvergedLoop )
00509 fprintf(ioQQQ,"PROBLEM ConvInitSolution: temperature solution not "
00510 "found in initial search, final Te=%.2e\n",
00511 phycon.te );
00512
00513
00514
00515
00516 if( thermal.ConstTemp<=0 &&
00517 ! fp_equal( TempSave , phycon.te ) )
00518 {
00519 if( trace.lgTrace || trace.nTrConvg>=2 )
00520 fprintf(ioQQQ," Change in sign of C-H found, Te brackets %.3e "
00521 "%.3e Cool brackets %.3e %.3e ",
00522 TempSave , phycon.te , CoolMHeatSave , CoolNet);
00523
00524
00525 double alpha = log(thermal.ctot/CoolSave) / log( phycon.te/TempSave);
00526 if( fabs(alpha) < SMALLFLOAT )
00527
00528 TeNew = phycon.te;
00529 else
00530 {
00531
00532 if( thermal.ctot<0. || thermal.htot<0. )
00533 TotalInsanity();
00534 double Alog = log( thermal.ctot ) - alpha * log( phycon.te );
00535
00536 double TeLn = (log( thermal.htot ) - Alog) / alpha ;
00537
00538
00539 if( TeLn < log( MIN2(phycon.te , TempSave )) )
00540 TeNew = MIN2(phycon.te , TempSave );
00541 else if( TeLn > log( MAX2(phycon.te , TempSave )) )
00542 TeNew = MAX2(phycon.te , TempSave );
00543 else
00544 TeNew = pow( EE , TeLn );
00545 }
00546
00547 ASSERT( TeNew>=MIN2 ( TempSave , phycon.te ) ||
00548 TeNew<=MAX2 ( TempSave , phycon.te ));
00549
00550 if( trace.lgTrace || trace.nTrConvg>=2 )
00551 fprintf(ioQQQ," interpolating to Te %.3e \n\n",
00552 TeNew);
00553
00554
00555 TempChange(TeNew , true);
00556 }
00557
00558 if( ConvTempEdenIoniz() )
00559 {
00560
00561 lgAbort = true;
00562 return(1);
00563 }
00564
00565
00566 PresTotCurrent();
00567
00568 if( trace.lgTrace || trace.nTrConvg )
00569 {
00570 fprintf( ioQQQ, "\nConvInitSolution: end 1st iteration search phase "
00571 "finding Te=%.3e\n\n" , phycon.te);
00572 }
00573 conv.lgSearch = false;
00574
00575 if( trace.lgTrace )
00576 {
00577 fprintf( ioQQQ, " ConvInitSolution return, TE:%10.2e==================\n",
00578 phycon.te );
00579 }
00580 }
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594 if( iteration==1 || dense.lgDenseInitConstant )
00595 {
00596 double PresNew = pressure.PresTotlCurr;
00597
00598
00599 if( pressure.lgPressureInitialSpecified )
00600
00601 PresNew = pressure.PressureInitialSpecified;
00602 if( trace.lgTrace )
00603 {
00604 fprintf( ioQQQ,
00605 " PresTotCurrent 1st zn old values of PresTotlInit:%.3e"
00606 " to %.3e \n",
00607 pressure.PresTotlInit,
00608 PresNew);
00609 }
00610
00611 pressure.PresTotlInit = PresNew;
00612 }
00613
00614
00615
00616 ConvPresTempEdenIoniz();
00617
00618
00619
00620
00621 conv.nPres2Ioniz = 0;
00622
00623 dense.lgEdenBad = false;
00624 dense.nzEdenBad = 0;
00625
00626
00627
00628 conv.nTotalIoniz_start = conv.nTotalIoniz;
00629
00630
00631
00632 conv.BigEdenError = 0.;
00633 conv.AverEdenError = 0.;
00634 conv.BigHeatCoolError = 0.;
00635 conv.AverHeatCoolError = 0.;
00636 conv.BigPressError = 0.;
00637 conv.AverPressError = 0.;
00638
00639
00640 if( iteration == 1 )
00641 {
00642
00643
00644 struc.testr[0] = (realnum)phycon.te;
00645
00646 struc.hden[0] = dense.gas_phase[ipHYDROGEN];
00647
00648 struc.DenParticles[0] = dense.pden;
00649 struc.heatstr[0] = thermal.htot;
00650 struc.coolstr[0] = thermal.ctot;
00651 struc.volstr[0] = (realnum)radius.dVeff;
00652 struc.drad_x_fillfac[0] = (realnum)radius.drad_x_fillfac;
00653 struc.histr[0] = dense.xIonDense[ipHYDROGEN][0];
00654 struc.hiistr[0] = dense.xIonDense[ipHYDROGEN][1];
00655 struc.ednstr[0] = (realnum)dense.eden;
00656 struc.o3str[0] = dense.xIonDense[ipOXYGEN][2];
00657 struc.DenMass[0] = dense.xMassDensity;
00658 struc.drad[0] = (realnum)radius.drad;
00659 }
00660
00661
00662
00663
00664
00665
00666
00667
00668 nflux_old = rfield.nflux;
00669 nelem_reflux = -1;
00670 ion_reflux = -1;
00671 for( nelem=2; nelem < LIMELM; nelem++ )
00672 {
00673
00674 for( i=0; i < nelem; i++ )
00675 {
00676 if( dense.xIonDense[nelem][i+1] > 0. )
00677 {
00678 if( Heavy.ipHeavy[nelem][i] > rfield.nflux )
00679 {
00680 rfield.nflux = Heavy.ipHeavy[nelem][i];
00681 nelem_reflux = nelem;
00682 ion_reflux = i;
00683 }
00684 }
00685 }
00686 }
00687
00688
00689
00690 if( nflux_old != rfield.nflux )
00691 {
00692
00693 rfield_opac_zero( nflux_old-1 , rfield.nflux );
00694
00695
00696
00697
00698
00699 PresTotCurrent();
00700
00701
00702 if( ConvBase(1) )
00703 {
00704
00705 lgAbort = true;
00706 return( 1 );
00707 }
00708
00709
00710 if( trace.lgTrace )
00711 {
00712 fprintf(ioQQQ," nflux updated from %li to %li, anu from %g to %g \n",
00713 nflux_old , rfield.nflux ,
00714 rfield.anu[nflux_old] , rfield.anu[rfield.nflux] );
00715 fprintf(ioQQQ," caused by element %li ion %li \n",
00716 nelem_reflux ,ion_reflux );
00717 }
00718 }
00719
00720
00721
00722 if( (strcmp(dense.chDenseLaw,"WIND") == 0) && wind.windv < 0. )
00723 {
00724
00725
00726
00727 # define PCHNG 0.98
00728
00729 if( ConvPresTempEdenIoniz() )
00730 {
00731
00732 lgAbort = true;
00733 return(1);
00734 }
00735
00736 pressure.PresTotlInit *= PCHNG;
00737 if( ConvPresTempEdenIoniz() )
00738 {
00739
00740 lgAbort = true;
00741 return(1);
00742 }
00743
00744 pressure.PresTotlInit /= PCHNG;
00745 if( ConvPresTempEdenIoniz() )
00746 {
00747
00748 lgAbort = true;
00749 return(1);
00750 }
00751
00752 # undef PCHNG
00753 }
00754
00755 return( lgAbort );
00756 }