00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "cddefines.h"
00010 #include "hmi.h"
00011 #include "thermal.h"
00012 #include "iso.h"
00013 #include "hydrogenic.h"
00014 #include "colden.h"
00015 #include "h2.h"
00016 #include "pressure.h"
00017 #include "dense.h"
00018 #include "trace.h"
00019 #include "phycon.h"
00020 #include "conv.h"
00021
00022
00023
00024
00025
00026
00027 static const int LIMDEF = 60;
00028
00029
00030 STATIC double CoolHeatError( double temp );
00031
00032
00033 STATIC double TeBrent(
00034 double x1,
00035 double x2);
00036
00037
00038 STATIC void MakeDeriv(
00039
00040 const char *job,
00041
00042 double *DerivNumer);
00043
00044
00045 STATIC void PutHetCol(double te,
00046 double htot,
00047 double ctot);
00048
00049
00050
00051
00052 int ConvTempEdenIoniz( void )
00053 {
00054 char chDEType;
00055 long int limtry,
00056 nTemperature_loop;
00057
00058 double CoolMHeat=0.,
00059 Damper,
00060 dtl,
00061 fneut;
00062 int kase;
00063 double DerivNumer;
00064 static double OldCmHdT = 0.;
00065 long int nTemp_oscil;
00066
00067
00068 double dCoolmHeatdT;
00069
00070 DEBUG_ENTRY( "ConvTempEdenIoniz()" );
00071
00072
00073
00074
00075
00076 if( trace.lgTrace )
00077 {
00078 fprintf( ioQQQ, "\n ConvTempEdenIoniz called\n" );
00079 }
00080 if( trace.nTrConvg>=2 )
00081 {
00082 fprintf( ioQQQ, " ConvTempEdenIoniz1 called. Te:%.4e Htot:%11.4e Ctot:%11.4e error:%9.1e%%, eden=%11.4e\n",
00083 phycon.te, thermal.htot, thermal.ctot, (thermal.htot - thermal.ctot)*
00084 100./MAX2(1e-36,thermal.htot), dense.eden );
00085 }
00086
00087 if( strcmp( conv.chSolverTemp , "new" ) == 0 )
00088 {
00089
00090 double t1 , t2 ,
00091 error1 , error2;
00092 double TeNew;
00093 double factor = 1.02;
00094
00095 t1 = phycon.te;
00096 error1 = CoolHeatError( t1 );
00097 t2 = t1 * factor;
00098 error2 = CoolHeatError( t2 );
00099 TeNew = TeBrent( t1 , t2 );
00100 fprintf(ioQQQ , "DEBUG new temp solver error1 %.2e error2 %.2e TeNew %.2e\n",
00101 error1 , error2 , TeNew );
00102 }
00103
00104 else if( strcmp( conv.chSolverTemp , "simple") == 0 )
00105 {
00106
00107
00108
00109
00110 conv.lgTOscl = false;
00111
00112 conv.lgOscilOTS = false;
00113
00114
00115 Damper = 1.;
00116
00117
00118
00119 if( nzone < 1 )
00120 {
00121 conv.lgCmHOsc = false;
00122 }
00123
00124
00125 MakeDeriv("zero",&DerivNumer);
00126
00127
00128 limtry = LIMDEF;
00129
00130
00131 dtl = 0.;
00132
00133
00134
00135
00136 nTemperature_loop = 0;
00137 nTemp_oscil = 0;
00138
00139
00140 thermal.dTemper = 1e-3f*phycon.te;
00141
00142
00143
00144 while ( true )
00145 {
00146
00147
00148
00149
00150
00151
00152 if( ConvEdenIoniz() )
00153 {
00154 return 1;
00155 }
00156 PresTotCurrent();
00157
00158
00159 CoolMHeat = thermal.ctot - thermal.htot;
00160
00161
00162
00163
00164
00165 if( thermal.lgTemperatureConstant )
00166 {
00167
00168 CoolMHeat = 0.;
00169 }
00170
00171 if( thermal.lgTLaw )
00172 {
00173 double TeNew = phycon.te;
00174
00175 if( thermal.lgTeBD96 )
00176 {
00177
00178 TeNew = thermal.T0BD96 / (1.f + thermal.SigmaBD96 * colden.colden[ipCOL_HTOT] );
00179 }
00180 else if( thermal.lgTeSN99 )
00181 {
00182
00183
00184
00185 TeNew = thermal.T0SN99 /
00186
00187 (realnum)(1.f + 9.*pow(2.*hmi.H2_total/dense.gas_phase[ipHYDROGEN], 4.) );
00188 }
00189 else
00190 TotalInsanity();
00191
00192 TempChange(TeNew ,false);
00193 }
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205 if( (lgConvTemp() )
00206 && conv.lgConvIoniz )
00207 {
00208
00209 if( trace.lgTrace )
00210 fprintf( ioQQQ, " ConvTempEdenIoniz returns ok.\n" );
00211
00212
00213
00214
00215
00216 if( thermal.dCooldT < 0. )
00217 {
00218 thermal.lgUnstable = true;
00219 }
00220 else
00221 {
00222 thermal.lgUnstable = false;
00223 }
00224
00225
00226 thermal.thist = (realnum)MAX2(phycon.te,thermal.thist);
00227 thermal.tlowst = (realnum)MIN2(phycon.te,thermal.tlowst);
00228
00229
00230 conv.lgConvTemp = true;
00231
00232 if( trace.nTrConvg>=2 )
00233 {
00234 fprintf( ioQQQ, " ConvTempEdenIoniz2 converged. Te:%11.4e Htot:%11.4e Ctot:%11.4e error:%9.1e%%, eden=%11.4e\n",
00235 phycon.te, thermal.htot, thermal.ctot, (thermal.htot - thermal.ctot)*
00236 100./MAX2(1e-36,thermal.htot), dense.eden );
00237 }
00238
00239
00240
00241
00242
00243 return 0;
00244 }
00245 else if(nTemperature_loop >= limtry || lgAbort )
00246 {
00247
00248
00249
00250
00251 if( nTemperature_loop == LIMDEF && !conv.lgTOscl &&
00252 conv.lgConvIoniz )
00253 {
00254
00255
00256
00257 limtry = LIMDEF*4;
00258 if( trace.nTrConvg>2 )
00259 {
00260 fprintf( ioQQQ, " ConvTempEdenIoniz9 increases limtry to%3ld\n",
00261 limtry );
00262 }
00263 }
00264 else
00265 {
00266
00267 break;
00268 }
00269 }
00270
00271
00272 MakeDeriv("incr",&DerivNumer);
00273
00274
00275 PutHetCol(phycon.te,thermal.htot,thermal.ctot);
00276
00277
00278
00279
00280
00281 if( !conv.lgConvEden )
00282 {
00283
00284
00285 CoolMHeat = 0.;
00286 if( trace.nTrConvg>=2 )
00287 {
00288 fprintf( ioQQQ,
00289 " ConvTempEdenIoniz3 breaks since lgConvEden returns failed electron density.\n");
00290 }
00291 break;
00292 }
00293
00294
00295 if( nzone < 1 )
00296 {
00297
00298 OldCmHdT = thermal.ctot/phycon.te;
00299 }
00300
00301 # define USENUMER false
00302 if( USENUMER )
00303 {
00304 dCoolmHeatdT = DerivNumer;
00305 chDEType = 'n';
00306 }
00307 else if( phycon.te < 1e4 && thermal.dCooldT < 0. )
00308 {
00309
00310
00311 dCoolmHeatdT = (double)(thermal.htot)/phycon.te*2.;
00312 chDEType = 'd';
00313 }
00314 else
00315 {
00316
00317
00318 dCoolmHeatdT = thermal.dCooldT - thermal.dHeatdT;
00319 chDEType = 'a';
00320 }
00321
00322
00323
00324 if( OldCmHdT*dCoolmHeatdT < 0. )
00325 {
00326 conv.lgCmHOsc = true;
00327
00328
00329
00330
00331
00332 dCoolmHeatdT = thermal.ctot/phycon.te;
00333 chDEType = 'o';
00334 }
00335 OldCmHdT = dCoolmHeatdT;
00336
00337
00338
00339 thermal.dTemper = (realnum)(CoolMHeat/dCoolmHeatdT);
00340 kase = 0;
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 if( dtl*thermal.dTemper < 0. && nTemperature_loop > 3)
00353 {
00354 conv.lgTOscl = true;
00355
00356
00357
00358 Damper *= 0.5;
00359 nTemp_oscil = nTemperature_loop;
00360 }
00361 else if( Damper < 1. && nTemperature_loop-nTemp_oscil > 10 )
00362 {
00363
00364
00365
00366 conv.lgTOscl = false;
00367 if( !((nTemperature_loop-nTemp_oscil)%5) )
00368 Damper = MIN2( 1., Damper*1.5 );
00369 }
00370
00371
00372
00373
00374 fneut = (dense.xIonDense[ipHYDROGEN][0] + 2.*hmi.H2_total)/dense.gas_phase[ipHYDROGEN];
00375
00376
00377
00378
00379
00380
00381
00382 if( 0 && h2.lgH2ON && fabs(hmi.HeatH2Dexc_BigH2)/thermal.ctot > conv.HeatCoolRelErrorAllowed )
00383 {
00384
00385
00386
00387
00388
00389
00390 double absdt = fabs(thermal.dTemper);
00391 thermal.dTemper = (sign(MIN2(absdt,0.0025*phycon.te),
00392 thermal.dTemper));
00393 kase = 1;
00394 }
00395 else if( fneut > 0.08 && hydro.lgHColionImp )
00396 {
00397
00398
00399 double absdt = fabs(thermal.dTemper);
00400 thermal.dTemper = (sign(MIN2(absdt,0.005*phycon.te),
00401 thermal.dTemper));
00402 kase = 2;
00403 }
00404 # if 0
00405
00406
00407 else if( 0 && nTemperature_loop <= 3)
00408 {
00409
00410
00411 double absdt = fabs(thermal.dTemper);
00412 thermal.dTemper = (sign(MIN2(absdt,0.002*phycon.te),
00413 thermal.dTemper));
00414 kase = 3;
00415 }
00416 # endif
00417 else
00418 {
00419
00420
00421 double absdt = fabs(thermal.dTemper);
00422 thermal.dTemper = (sign(MIN2(absdt,0.02*phycon.te),
00423 thermal.dTemper));
00424 kase = 4;
00425 }
00426
00427
00428
00429
00430
00431 if( 0 && h2.lgH2ON && fabs(thermal.dTemper)/ phycon.te > 0.01 )
00432 {
00433 double absdt = fabs(thermal.dTemper);
00434 thermal.dTemper = (sign(MIN2(absdt,0.01*phycon.te),
00435 thermal.dTemper));
00436 kase = 5;
00437 }
00438
00439
00440
00441
00442
00443
00444
00445 if( dense.xIonDense[ipHYDROGEN][1]/dense.gas_phase[ipHYDROGEN] < 0.9 &&
00446
00447 dense.xIonDense[ipHYDROGEN][1]/dense.gas_phase[ipHYDROGEN] > 0.01 )
00448 {
00449 if( iso.RecomCollisFrac[ipH_LIKE][ipHYDROGEN] > 0.8 )
00450
00451
00452
00453
00454 {
00455 double absdt = fabs(thermal.dTemper);
00456
00457
00458
00459
00460
00461
00462
00463
00464 thermal.dTemper = (sign(MIN2(absdt,0.001*
00465 phycon.te),thermal.dTemper));
00466 kase = 6;
00467 }
00468 }
00469
00470
00471 thermal.dTemper *= Damper;
00472
00473
00474
00475 if( fabs(thermal.dTemper)/phycon.te <10.*DBL_EPSILON )
00476 {
00477 kase = 7;
00478 thermal.dTemper = (sign( 10.*DBL_EPSILON*phycon.te , thermal.dTemper));
00479 }
00480
00481
00482 dtl = thermal.dTemper;
00483
00484
00485 if( !thermal.lgTLaw )
00486 {
00487
00488 TempChange(phycon.te - thermal.dTemper , false);
00489 }
00490
00491 if( trace.nTrConvg>=2 )
00492 {
00493 fprintf( ioQQQ,
00494 " ConvTempEdenIoniz4 a %4li T:%.4e dt:%10.2e%7.2f%% C:%10.2e H:%10.2e"
00495 " CoolMHeat/h:%7.2f%% dC-H/dT:%.2e kase:%i%c damp%.2f\n",
00496 nTemperature_loop,
00497 phycon.te,
00498 thermal.dTemper,
00499 thermal.dTemper/(phycon.te+thermal.dTemper)*100,
00500 thermal.ctot,
00501 thermal.htot,
00502 CoolMHeat/MIN2(thermal.ctot , thermal.htot )*100. ,
00503 dCoolmHeatdT,
00504 kase,
00505
00506 chDEType,
00507 Damper);
00508
00509
00510 }
00511
00512 if( trace.lgTrace )
00513 {
00514 fprintf( ioQQQ,
00515 " ConvTempEdenIoniz TE:%.5e dT%.3e HTOT:%.5e CTOT:%.5e dCoolmHeatdT:%c%.4e C-H%.4e HDEN%.2e kase %i\n",
00516 phycon.te,
00517 thermal.dTemper,
00518 thermal.htot,
00519 thermal.ctot,
00520 chDEType,
00521 dCoolmHeatdT,
00522 CoolMHeat,
00523 dense.gas_phase[ipHYDROGEN],
00524 kase );
00525 }
00526
00527
00528 ++nTemperature_loop;
00529 }
00530
00531
00532
00533
00534 if( fabs(CoolMHeat/thermal.htot ) > conv.HeatCoolRelErrorAllowed )
00535 {
00536 conv.lgConvTemp = false;
00537 if( trace.nTrConvg>=2 )
00538 {
00539 fprintf( ioQQQ, " ConvTempEdenIoniz7 fell through loop, heating cooling not converged, setting conv.lgConvTemp = false\n");
00540 }
00541 }
00542 else
00543 {
00544
00545
00546 conv.lgConvTemp = true;
00547 if( trace.nTrConvg>=2 )
00548 {
00549 fprintf( ioQQQ, " ConvTempEdenIoniz8 fell through loop, heating cooling is converged (ion not?), setting conv.lgConvTemp = true\n");
00550 }
00551 }
00552 }
00553 else
00554 {
00555 fprintf( ioQQQ, "ConvTempEdenIoniz finds insane solver%s \n" , conv.chSolverTemp );
00556 ShowMe();
00557 cdEXIT(EXIT_FAILURE);
00558 }
00559 return 0;
00560 }
00561
00562
00563 STATIC void MakeDeriv(
00564 const char *job,
00565 double *DerivNumer)
00566 {
00567 static long int nstore;
00568 static double OldTe , OldCool , OldHeat;
00569
00570 DEBUG_ENTRY( "MakeDeriv()" );
00571
00572 if( strcmp(job,"zero") == 0 )
00573 {
00574 nstore = 0;
00575 OldTe = 0.;
00576 OldCool = 0.;
00577 OldHeat = 0.;
00578 }
00579
00580 else if( strcmp(job,"incr") == 0 )
00581 {
00582
00583 if( nstore > 0 && !thermal.lgTemperatureConstant && fabs(phycon.te - OldTe)>SMALLFLOAT )
00584 {
00585
00586 double dCdT = (thermal.ctot - OldCool)/(phycon.te - OldTe);
00587 double dHdT = (thermal.htot - OldHeat)/(phycon.te - OldTe);
00588 *DerivNumer = dCdT - dHdT;
00589 # if 0
00590 fprintf(ioQQQ,"derivderiv\t%li\t%.2e\t%.2e\t%.2e\t%.2e\t%.2e\t%.2e\n",
00591 nzone, dCdT , thermal.dCooldT ,
00592 thermal.ctot , OldCool,phycon.te , OldTe
00593 );
00594 # endif
00595 }
00596
00597 else
00598 {
00599
00600 *DerivNumer = 0.;
00601 }
00602
00603 OldTe = phycon.te;
00604 OldCool = thermal.ctot;
00605 OldHeat = thermal.htot;
00606 ++ nstore;
00607 }
00608
00609 else
00610 {
00611 fprintf( ioQQQ, " MakeDeriv called with insane job=%4.4s\n",
00612 job );
00613 cdEXIT(EXIT_FAILURE);
00614 }
00615 return;
00616 }
00617
00618
00619 STATIC void PutHetCol(double te,
00620 double htot,
00621 double ctot)
00622 {
00623
00624 DEBUG_ENTRY( "PutHetCol()" );
00625
00626 if( nzone == 0 )
00627 {
00628
00629 thermal.ipGrid = 0;
00630 }
00631 else
00632 {
00633 if( thermal.ipGrid >= NGRID )
00634 thermal.ipGrid = 0;
00635
00636 ASSERT( thermal.ipGrid >= 0 );
00637 ASSERT( thermal.ipGrid < NGRID );
00638 ASSERT( nzone>=0 );
00639
00640 thermal.TeGrid[thermal.ipGrid] = (realnum)te;
00641 thermal.HtGrid[thermal.ipGrid] = (realnum)htot;
00642 thermal.ClGrid[thermal.ipGrid] = (realnum)ctot;
00643 thermal.nZonGrid[thermal.ipGrid] = nzone;
00644
00645 ++thermal.ipGrid;
00646 }
00647 return;
00648 }
00649
00650
00651 STATIC double CoolHeatError( double temp )
00652 {
00653 DEBUG_ENTRY( "CoolHeatError()" );
00654
00655 TempChange(temp , false);
00656
00657
00658
00659
00660 if( ConvEdenIoniz() )
00661 lgAbort = true;
00662
00663
00664
00665
00666 PresTotCurrent();
00667
00668
00669 PutHetCol(phycon.te,thermal.htot,thermal.ctot);
00670 return thermal.ctot - thermal.htot;
00671 }
00672
00673
00674 #define ITERMAX 100
00675
00676 STATIC double TeBrent(
00677 double x1,
00678 double x2)
00679 {
00680 long int iter;
00681 double c,
00682 d,
00683 e,
00684 fx1,
00685 fx2,
00686 fc,
00687 p,
00688 q,
00689 r,
00690 s,
00691 xm;
00692
00693 DEBUG_ENTRY( "TeBrent()" );
00694
00695
00696
00697
00698
00699 fx1 = CoolHeatError(x1);
00700 fx2 = CoolHeatError(x2);
00701
00702 if( fx1*fx2 > 0. )
00703 {
00704
00705 fprintf( ioQQQ, " TeBrent called without proper bracket - this is impossible\n" );
00706 fprintf( ioQQQ, " Sorry.\n" );
00707 cdEXIT(EXIT_FAILURE);
00708 }
00709
00710
00711 c = x2;
00712 fc = fx2;
00713 iter = 0;
00714
00715 e = DBL_MAX;
00716 d = DBL_MAX;
00717 while( iter < ITERMAX )
00718 {
00719 if( (fx2 > 0. && fc > 0.) || (fx2 < 0. && fc < 0.) )
00720 {
00721 c = x1;
00722 fc = fx1;
00723 d = x2 - x1;
00724 e = d;
00725 }
00726 if( fabs(fc) < fabs(fx2) )
00727 {
00728 x1 = x2;
00729 x2 = c;
00730 c = x1;
00731 fx1 = fx2;
00732 fx2 = fc;
00733 fc = fx1;
00734 }
00735
00736 xm = .5*(c - x2);
00737
00738
00739 if( fabs(xm) <= thermal.htot*conv.HeatCoolRelErrorAllowed || fx2 == 0. )
00740 break;
00741
00742 if( fabs(e) >= thermal.htot*conv.HeatCoolRelErrorAllowed && fabs(fx1) > fabs(fx2) )
00743 {
00744 double aa , bb;
00745 s = fx2/fx1;
00746 if( fp_equal( x1, c ) )
00747 {
00748 p = 2.*xm*s;
00749 q = 1. - s;
00750 }
00751 else
00752 {
00753 q = fx1/fc;
00754 r = fx2/fc;
00755 p = s*(2.*xm*q*(q - r) - (x2 - x1)*(r - 1.));
00756 q = (q - 1.)*(r - 1.)*(s - 1.);
00757 }
00758 if( p > 0. )
00759 q = -q;
00760
00761 p = fabs(p);
00762 aa = fabs(thermal.htot*conv.HeatCoolRelErrorAllowed*q);
00763 bb = fabs(e*q);
00764 if( 2.*p < MIN2(3.*xm*q-aa,bb) )
00765 {
00766 e = d;
00767 d = p/q;
00768 }
00769 else
00770 {
00771 d = xm;
00772 e = d;
00773 }
00774 }
00775 else
00776 {
00777 d = xm;
00778 e = d;
00779 }
00780 x1 = x2;
00781 fx1 = fx2;
00782 if( fabs(d) > thermal.htot*conv.HeatCoolRelErrorAllowed )
00783 {
00784 x2 += d;
00785 }
00786 else
00787 {
00788 x2 += sign(thermal.htot*conv.HeatCoolRelErrorAllowed,xm);
00789 }
00790 fx2 = CoolHeatError(x2);
00791
00792 ++iter;
00793 }
00794
00795
00796
00797 if( iter == ITERMAX )
00798 {
00799
00800 fprintf( ioQQQ, " TeBrent did not converge in %i iterations\n",ITERMAX );
00801 fprintf( ioQQQ, " Sorry.\n" );
00802 cdEXIT(EXIT_FAILURE);
00803 }
00804 return( x2 );
00805
00806 }
00807
00808
00809 bool lgConvTemp(void)
00810 {
00811 bool lgRet;
00812 DEBUG_ENTRY( "lgConvTemp()" );
00813
00814
00815 if( fabs(thermal.htot - thermal.ctot)/thermal.htot <= conv.HeatCoolRelErrorAllowed ||
00816 thermal.lgTemperatureConstant || phycon.te <= phycon.TEMP_LIMIT_LOW )
00817 {
00818
00819
00820
00821 lgRet = true;
00822 conv.lgConvTemp = true;
00823 }
00824 else
00825 {
00826
00827 lgRet = false;
00828 conv.lgConvTemp = false;
00829 }
00830 return lgRet;
00831 }