00001
00002
00003
00004
00005 #include "cddefines.h"
00006 #include "taulines.h"
00007 #include "dense.h"
00008 #include "hmi.h"
00009 #include "conv.h"
00010 #include "phycon.h"
00011 #include "trace.h"
00012 #include "thermal.h"
00013 #include "called.h"
00014 #include "hcmap.h"
00015 #include "coolheavy.h"
00016 #include "mole.h"
00017 #include "mole_co_priv.h"
00018
00019
00020 static bool lgMoleZeroed=true;
00021
00022
00023 static double h2lim;
00024
00025
00026
00027 static const double COTOLER_MOLAV = 0.10;
00028
00029
00030 static const int CODEBUG = 0;
00031
00032
00033 static const int LUPMAX_CODRIV = 100;
00034
00035
00036
00037 STATIC bool lgMolecAver(
00038
00039
00040 const char chJob[10] ,
00041 char *chReason );
00042
00043
00044 void CO_drive(void)
00045 {
00046 bool lgNegPop,
00047 lgZerPop,
00048 lgFirstTry;
00049 long int i;
00050 bool lgConverged;
00051
00052 long int loop;
00053 long int nelem , ion;
00054
00055
00056
00057 char chReason[100];
00058
00059
00060 DEBUG_ENTRY( "CO_drive()" );
00061
00062
00063
00064 if( hmi.lgNoH2Mole )
00065 {
00066
00067 h2lim = 0.;
00068 }
00069 else
00070 {
00071
00072
00073
00074
00075 h2lim = 1e-15;
00076
00077
00078
00079
00080
00081 h2lim = 1e-12;
00082 }
00083
00084
00085
00086
00087
00088
00089 co.lgCODoCalc = true;
00090
00091 if( phycon.te > 20000. )
00092 co.lgCODoCalc = false;
00093
00094
00095 if( co.lgNoCOMole )
00096 co.lgCODoCalc = false;
00097
00098
00099 if( dense.lgElmtOn[ipCARBON]*dense.lgElmtOn[ipOXYGEN] == 0 )
00100 co.lgCODoCalc = false;
00101
00102
00103
00104 if( dense.IonLow[ipCARBON]>0 || dense.IonLow[ipOXYGEN]>0 )
00105 co.lgCODoCalc = false;
00106
00107
00108 if( iteration!=co.iteration_co &&
00109 hmi.H2_total/dense.gas_phase[ipHYDROGEN] < h2lim )
00110 co.lgCODoCalc = false;
00111
00112
00113
00114
00115 if( dense.xIonDense[ipHYDROGEN][1] / dense.gas_phase[ipHYDROGEN] > 0.5 )
00116 co.lgCODoCalc = false;
00117
00118 if( dense.lgElmtOn[ipSILICON] )
00119 {
00120
00121
00122
00123 if( dense.xIonDense[ipSILICON][0]/dense.gas_phase[ipSILICON] < 1e-15 )
00124 co.lgCODoCalc = false;
00125 }
00126
00127
00128
00129 if( !co.lgCODoCalc )
00130 {
00131
00132
00133 struct COmole_rate_s *rate;
00134
00135 mole.xMoleChTrRate[ipSILICON][1][0] = 0.;
00136 rate = CO_findrate_s("Si+,Fe=>Si,Fe+");
00137 mole.xMoleChTrRate[ipSILICON][1][0] += (realnum)(rate->rk*rate->rate_species[1]->hevmol);
00138 rate = CO_findrate_s("Si+,Mg=>Si,Mg+");
00139 mole.xMoleChTrRate[ipSILICON][1][0] += (realnum)(rate->rk*rate->rate_species[1]->hevmol);
00140
00141 mole.xMoleChTrRate[ipSULPHUR][1][0] = 0.;
00142 rate = CO_findrate_s("S+,Fe=>S,Fe+");
00143 mole.xMoleChTrRate[ipSULPHUR][1][0] += (realnum)(rate->rk*rate->rate_species[1]->hevmol);
00144 rate = CO_findrate_s("S+,Mg=>S,Mg+");
00145 mole.xMoleChTrRate[ipSULPHUR][1][0] += (realnum)(rate->rk*rate->rate_species[1]->hevmol);
00146
00147 mole.xMoleChTrRate[ipCARBON][1][0] = 0.;
00148 rate = CO_findrate_s("C+,Fe=>C,Fe+");
00149 mole.xMoleChTrRate[ipCARBON][1][0] += (realnum)(rate->rk*rate->rate_species[1]->hevmol);
00150 rate = CO_findrate_s("C+,Mg=>C,Mg+");
00151 mole.xMoleChTrRate[ipCARBON][1][0] += (realnum)(rate->rk*rate->rate_species[1]->hevmol);
00152
00153 #if 0
00154 mole.xMoleChTrRate[ipSILICON][1][0] = (realnum)(dense.xIonDense[ipMAGNESIUM][0]*
00155 COmole_rate[ipR_SiP_Mg_Si_MgP].rk +
00156 dense.xIonDense[ipIRON][0]*COmole_rate[ipR_SiP_Fe_Si_FeP].rk);
00157
00158 mole.xMoleChTrRate[ipSULPHUR][1][0] = (realnum)(dense.xIonDense[ipMAGNESIUM][0]*
00159 COmole_rate[ipR_SP_Mg_S_MgP].rk +
00160 dense.xIonDense[ipIRON][0]*COmole_rate[ipR_SP_Fe_S_FeP].rk);
00161
00162 mole.xMoleChTrRate[ipCARBON][1][0] = (realnum)(dense.xIonDense[ipMAGNESIUM][0]*
00163 COmole_rate[ipR_CP_Mg_C_MgP].rk +
00164 dense.xIonDense[ipIRON][0]*COmole_rate[ipR_CP_Fe_C_FeP].rk);
00165 #endif
00166
00167
00168 if( !lgMoleZeroed )
00169 {
00170 lgMoleZeroed = true;
00171 for( i=0; i<mole.num_comole_calc; ++i )
00172 {
00173 COmole[i]->hevmol = 0.;
00174 }
00175
00176 thermal.heating[0][9] = 0.;
00177
00178 CoolHeavy.C12O16Rot = 0.;
00179 CoolHeavy.dC12O16Rot = 0.;
00180 CoolHeavy.C13O16Rot = 0.;
00181 CoolHeavy.dC13O16Rot = 0.;
00182 co.CODissHeat = 0.;
00183
00185 for( i=0; i < nCORotate; i++ )
00186 {
00187 C12O16Rotate[i].Lo->Pop = 0.;
00188 C13O16Rotate[i].Lo->Pop = 0.;
00189
00190 C12O16Rotate[i].Hi->Pop = 0.;
00191 C13O16Rotate[i].Hi->Pop = 0.;
00192
00193 C12O16Rotate[i].Emis->PopOpc = 0.;
00194 C13O16Rotate[i].Emis->PopOpc = 0.;
00195
00196 C12O16Rotate[i].Coll.cool = 0.;
00197 C12O16Rotate[i].Coll.heat = 0.;
00198 C13O16Rotate[i].Coll.cool = 0.;
00199 C13O16Rotate[i].Coll.heat = 0.;
00200
00201 C12O16Rotate[i].Emis->xIntensity = 0.;
00202 C13O16Rotate[i].Emis->xIntensity = 0.;
00203
00204 C12O16Rotate[i].Emis->phots = 0.;
00205 C13O16Rotate[i].Emis->phots = 0.;
00206 }
00207 for( nelem=ipLITHIUM; nelem<LIMELM; ++nelem )
00208 {
00209 for( ion=0; ion<nelem+2; ++ion )
00210 {
00211 mole.source[nelem][ion] = 0.;
00212 mole.sink[nelem][ion] = 0.;
00213 }
00214 }
00215 }
00216
00217 if( trace.nTrConvg>=4 )
00218 {
00219
00220 fprintf( ioQQQ,
00221 " CO_drive4 do not evaluate CO chemistry.\n");
00222 }
00223 return;
00224 }
00225
00226 CO_update_species_cache();
00227
00228
00229 CO_update_rks();
00230
00231
00232 loop = 0;
00233 lgNegPop = false;
00234 lgConverged = lgMolecAver("SETUP",chReason);
00235 do
00236 {
00237
00238 if( trace.nTrConvg>=5 )
00239 {
00240
00241 fprintf( ioQQQ,
00242 " CO_drive5 CO chemistry loop %li chReason %s.\n" , loop, chReason );
00243 }
00244
00245
00246 CO_solve(&lgNegPop,&lgZerPop );
00247
00248
00249 lgConverged = lgMolecAver("AVER",chReason);
00250 if( CODEBUG )
00251 fprintf(ioQQQ,"codrivbug %.2f %li Neg?:%c\tZero?:%c\tOH new\t%.3e\tCO\t%.3e\tTe\t%.3e\tH2/H\t%.2e\n",
00252 fnzone ,
00253 loop ,
00254 TorF(lgNegPop) ,
00255 TorF(lgZerPop) ,
00256 findspecies("OH")->hevmol ,
00257 findspecies("CO")->hevmol/SDIV(dense.gas_phase[ipCARBON]),
00258 phycon.te,
00259 hmi.H2_total/dense.gas_phase[ipHYDROGEN]);
00260
00261 ++loop;
00262 } while (
00263
00264
00265 (loop < LUPMAX_CODRIV) && !lgConverged );
00266
00267
00268 lgMoleZeroed = false;
00269
00270
00271 if( loop == LUPMAX_CODRIV)
00272 {
00273 conv.lgConvIoniz = false;
00274 strcpy( conv.chConvIoniz, "CO con1" );
00275 if( CODEBUG )
00276 fprintf(ioQQQ,"CO_drive not converged\n");
00277 }
00278
00279
00280
00281
00282 lgFirstTry = (nzone==co.co_nzone && iteration==co.iteration_co);
00283
00284
00285 if( lgNegPop )
00286 {
00287 if( conv.lgSearch && (hmi.H2_total/dense.gas_phase[ipHYDROGEN] <h2lim) &&
00288 (iteration==1) )
00289 {
00290
00291
00292
00293
00294
00295
00296 CO_zero();
00297 }
00298 else
00299 {
00300 if( called.lgTalk && !lgFirstTry )
00301 {
00302 conv.lgConvPops = false;
00303 fprintf( ioQQQ,
00304 " PROBLEM CO_drive failed to converge1 due to negative pops, zone=%.2f, CO/C=%.2e OH/C=%.2e H2/H=%.2e\n",
00305 fnzone,
00306 findspecies("CO")->hevmol/SDIV(dense.gas_phase[ipCARBON]),
00307 findspecies("OH")->hevmol/SDIV(dense.gas_phase[ipCARBON]),
00308 hmi.H2_total/dense.gas_phase[ipHYDROGEN]);
00309 ConvFail( "pops" , "CO" );
00310 }
00311 }
00312 }
00313
00314
00315 else if( loop == LUPMAX_CODRIV )
00316 {
00317
00318 if( called.lgTalk && !lgFirstTry )
00319 {
00320 conv.lgConvPops = false;
00321 fprintf( ioQQQ,
00322 " PROBLEM CO_drive failed to converge2 in %li iter, zone=%.2f, CO/C=%.2e negpop?%1c reason:%s\n",
00323 loop,
00324 fnzone,
00325 findspecies("CO")->hevmol/SDIV(dense.gas_phase[ipCARBON]),
00326 TorF(lgNegPop) ,
00327 chReason);
00328 ConvFail( "pops" , "CO" );
00329 }
00330 }
00331
00332
00333 ASSERT(conv.lgSearch || findspecies("CO")->hevmol/SDIV(dense.gas_phase[ipCARBON]) <= 1.01 ||
00334
00335 loop == LUPMAX_CODRIV );
00336
00337
00338
00339
00340
00341
00342 if(0) {
00343 double sum_ion , sum_mol;
00344 sum_ion = dense.xIonDense[ipCARBON][0] + dense.xIonDense[ipCARBON][1];
00345 sum_mol = findspecies("C")->hevmol + findspecies("C+")->hevmol;
00346 if( fabs(sum_ion-sum_mol)/SDIV(sum_mol) > 1e-2 )
00347 {
00348
00349
00350
00351 conv.lgConvIoniz = false;
00352 strcpy( conv.chConvIoniz, "CO con2" );
00353 conv.BadConvIoniz[0] = sum_ion;
00354 conv.BadConvIoniz[1] = sum_mol;
00355 if( CODEBUG )
00356 fprintf(ioQQQ,"CO_drive not converged\n");
00357 }
00358 sum_ion = dense.xIonDense[ipOXYGEN][0] + dense.xIonDense[ipOXYGEN][1];
00359 sum_mol = findspecies("O")->hevmol + findspecies("O+")->hevmol;
00360 if( fabs(sum_ion-sum_mol)/SDIV(sum_mol) > 1e-2 )
00361 {
00362
00363
00364
00365 conv.lgConvIoniz = false;
00366 strcpy( conv.chConvIoniz, "CO con3" );
00367 conv.BadConvIoniz[0] = sum_ion;
00368 conv.BadConvIoniz[1] = sum_mol;
00369 if( CODEBUG )
00370 fprintf(ioQQQ,"CO_drive not converged\n");
00371 }
00372 }
00373 return;
00374 }
00375
00376 STATIC bool lgMolecAver(
00377
00378
00379 const char chJob[10] ,
00380 char *chReason )
00381 {
00382 long int i;
00383 bool lgReturn;
00384
00385 static realnum hden_save_prev_call;
00386 double conv_fac;
00387 struct chem_element_s *element;
00388
00389 DEBUG_ENTRY( "lgMolecAver()" );
00390 const bool DEBUG_MOLECAVER = false;
00391
00392
00393 strcpy( chReason , "none given" );
00394
00395
00396 if( strcmp( "SETUP" , chJob ) == 0 )
00397 {
00398 static realnum hden_save_prev_iter;
00399
00400
00401
00402
00403
00404
00405 if( iteration!=co.iteration_co &&
00406 hmi.H2_total/dense.gas_phase[ipHYDROGEN] < h2lim )
00407 {
00408
00409 lgReturn = true;
00410 return lgReturn;
00411 }
00412
00413 else if( co.iteration_co < 0 || lgMoleZeroed )
00414 {
00415
00416
00417
00418
00419
00420
00421
00422 if( !hcmap.lgMapBeingDone || lgMoleZeroed )
00423 {
00424 for( i=0; i < mole.num_comole_calc; i++ )
00425 {
00426 COmole[i]->hevmol = dense.xIonDense[ipCARBON][0]*COmole[i]->pdr_mole_co;
00427 COmole[i]->co_save = COmole[i]->hevmol;
00428 }
00429 }
00430
00431
00432 ASSERT( dense.xIonDense[ipCARBON][0]>SMALLFLOAT );
00433
00434
00435 for(i=0;i<mole.num_elements;i++) {
00436 element = chem_element[i];
00437 COmole[element->ipMl]->hevmol = dense.xIonDense[element->ipCl][0];
00438 COmole[element->ipMlP]->hevmol = dense.xIonDense[element->ipCl][1];
00439 }
00440
00441
00442 co.iteration_co = iteration;
00443 co.co_nzone = nzone;
00444
00445
00446
00447
00448 hden_save_prev_iter = dense.gas_phase[ipHYDROGEN];
00449 hden_save_prev_call = dense.gas_phase[ipHYDROGEN];
00450
00451 if( DEBUG_MOLECAVER )
00452 fprintf(ioQQQ," DEBUG lgMolecAver iteration %li zone %li zeroing since very first call. H2/H=%.2e\n",
00453 iteration,nzone,hmi.H2_total/dense.gas_phase[ipHYDROGEN]);
00454 }
00455 else if( iteration > co.iteration_co )
00456 {
00457 realnum ratio = dense.gas_phase[ipHYDROGEN] / hden_save_prev_iter;
00458
00459
00460
00461 for( i=0; i < mole.num_comole_calc; i++ )
00462 {
00463 COmole[i]->hevmol = COmole[i]->hev_reinit*ratio;
00464 COmole[i]->co_save = COmole[i]->hev_reinit*ratio;
00465 }
00466
00467 co.iteration_co = iteration;
00468 co.co_nzone = nzone;
00469
00470 if( DEBUG_MOLECAVER )
00471 fprintf(ioQQQ," DEBUG lgMolecAver iteration %li zone %li resetting since first call on new iteration. H2/H=%.2e\n",
00472 iteration,
00473 nzone,
00474 hmi.H2_total/dense.gas_phase[ipHYDROGEN]);
00475 }
00476 else if( iteration == co.iteration_co && nzone==co.co_nzone+1 )
00477 {
00478
00479
00480 for( i=0; i < mole.num_comole_calc; i++ )
00481 {
00482 COmole[i]->hev_reinit = COmole[i]->hevmol;
00483 }
00484
00485 co.co_nzone = -2;
00486 hden_save_prev_iter = dense.gas_phase[ipHYDROGEN];
00487 hden_save_prev_call = dense.gas_phase[ipHYDROGEN];
00488
00489 if( DEBUG_MOLECAVER )
00490 fprintf(ioQQQ,"DEBUG lgMolecAver iteration %li zone %li second zone on new iteration, saving reset.\n", iteration,nzone);
00491 }
00492
00493
00494 lgReturn = true;
00495 }
00496
00497 else if( strcmp( "AVER" , chJob ) == 0 )
00498 {
00499
00500
00501
00502 realnum oldoh = findspecies("OH")->co_save;
00503 lgReturn = true;
00504
00505
00506
00507
00508 for( i=0; i < mole.num_comole_calc; i++ )
00509 {
00510
00511
00512 realnum damper = 0.2f;
00513
00514
00515
00516
00517 COmole[i]->co_save *= dense.gas_phase[ipHYDROGEN] / hden_save_prev_call;
00518
00519
00520
00521 if( COmole[i]->co_save< SMALLFLOAT )
00522 {
00523 COmole[i]->co_save = COmole[i]->hevmol;
00524 }
00525 else
00526 {
00527
00528
00529
00530 double ratio = (double)COmole[i]->hevmol/(double)COmole[i]->co_save;
00531 ASSERT( COmole[i]->co_save>0. && COmole[i]->hevmol>=0. );
00532 if( fabs(ratio-1.) < 1.5 ||
00533 fabs(ratio-1.) > 0.66 )
00534 {
00535
00536 COmole[i]->hevmol = COmole[i]->hevmol*(1.f - damper) +
00537 COmole[i]->co_save*damper;
00538 }
00539 else
00540 {
00541
00542 COmole[i]->hevmol = (realnum)pow(10. ,
00543 (log10(COmole[i]->hevmol) + log10(COmole[i]->co_save))/2. );
00544 }
00545 COmole[i]->co_save = COmole[i]->hevmol;
00546 }
00547 }
00548
00549 hden_save_prev_call = dense.gas_phase[ipHYDROGEN];
00550
00551
00552
00553 if( oldoh/SDIV(dense.gas_phase[ipOXYGEN]) < 1e-10 )
00554 conv_fac = 3.;
00555 else
00556 conv_fac = 1.;
00557
00558 if(fabs(oldoh/SDIV(findspecies("OH")->hevmol)-1.) < COTOLER_MOLAV*conv_fac )
00559 {
00560 lgReturn = true;
00561 }
00562 else
00563 {
00564
00565 lgReturn = false;
00566 sprintf( chReason , "OH change from %.3e to %.3e",
00567 oldoh ,
00568 findspecies("OH")->hevmol);
00569 }
00570 }
00571 else
00572 TotalInsanity();
00573
00574
00575 if( findspecies("CO")->hevmol/SDIV(dense.gas_phase[ipCARBON]) > 1.+FLT_EPSILON )
00576 {
00577 lgReturn = false;
00578 sprintf( chReason , "CO/C >1, value is %e",
00579 findspecies("CO")->hevmol/SDIV(dense.gas_phase[ipCARBON]) );
00580 }
00581
00582 if( (trace.lgTrace && trace.lgTr_CO_Mole) || DEBUG_MOLECAVER )
00583 {
00584 fprintf( ioQQQ, " DEBUG lgMolecAver converged? %c" ,TorF(lgReturn) );
00585 fprintf( ioQQQ, " CO/C=%9.1e", findspecies("CO")->hevmol/SDIV(dense.gas_phase[ipCARBON]) );
00586 fprintf( ioQQQ, " OH/O=%9.1e", findspecies("OH")->hevmol/SDIV(dense.gas_phase[ipOXYGEN]) );
00587 fprintf( ioQQQ, "\n" );
00588 }
00589
00590 return lgReturn;
00591 }