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 }