| 70 | | /* h2lim is smallest ratio of H2/HDEN for which we will |
| 71 | | * even try to invert heavy element network */ |
| 72 | | /* this limit is important since the co molecular network is first turned |
| 73 | | * on when this is hit. It's conservation law will only ever include the |
| 74 | | * initial O, O+, and C, C+, so must not start before nearly all |
| 75 | | * C and O is in these forms */ |
| 76 | | h2lim = 1e-15; |
| 77 | | /* >>chng 05 jul 15, from 1e-15 to 1e-12, see whether results are stable, |
| 78 | | * this does include CO in the H+ zone in orion_hii_pdr |
| 79 | | * a problem is that, during search phase, the first temp is 4000K and the |
| 80 | | * H2 abundance is larger than it will be at the illuminated face. try to |
| 81 | | * avoid turning H2 on too soon */ |
| 82 | | h2lim = 1e-12; |
| 83 | | |
| 84 | | if( conv.nTotalIoniz==0 && iteration==0 ) |
| 85 | | { |
| 86 | | /* we should have an H0 soln at this point |
| 87 | | -- all species for network will be sourced from ionization solvers |
| 88 | | in mole_update_species_cache below */ |
| 89 | | ASSERT( dense.xIonDense[ipHYDROGEN][0]>SMALLFLOAT ); |
| 90 | | } |
| 91 | | |
| 94 | | if( 1 ) |
| 95 | | { |
| 96 | | /* do we need to zero out the arrays and vars? */ |
| 97 | | if( !lgMoleZeroed ) |
| 98 | | for( i=0; i<mole.num_calc; ++i ) |
| 99 | | { |
| 100 | | COmole[i]->hevmol = 0.; |
| 101 | | } |
| 102 | | |
| | 59 | mole_null_results(); |
| | 60 | |
| | 61 | MolecSetup(); |
| | 62 | |
| | 63 | mole_update_species_cache(); /* Update densities of species controlled outside the chemical network */ |
| | 64 | |
| | 65 | mole_update_rks(); |
| | 66 | |
| | 67 | solomon_assumed = hmi.H2_Solomon_dissoc_rate_used_H2g/SDIV(hmi.H2_rate_destroy); |
| | 68 | |
| | 69 | error = mole_solve(); |
| | 70 | |
| | 71 | lgConverged = (error < MOLETOLER); |
| | 72 | if( lgConverged && h2.lgH2ON && hmi.lgBigH2_evaluated && hmi.lgH2_Chemistry_BigH2 ) |
| | 73 | { |
| | 74 | /* >>chng 05 mar 11, go from "total" to H2g for solomon rate */ |
| | 75 | if( fabs( solomon_assumed - hmi.H2_Solomon_dissoc_rate_BigH2_H2g/SDIV(hmi.H2_rate_destroy) ) > |
| | 76 | conv.EdenErrorAllowed/5.) |
| | 77 | { |
| | 78 | lgConverged = false; |
| | 79 | } |
| | 80 | } |
| | 81 | |
| | 82 | mole_effects(); |
| | 83 | |
| | 84 | return; |
| | 85 | } |
| | 86 | |
| | 87 | STATIC void MolecSetup(void) |
| | 88 | { |
| | 89 | long int i; |
| | 90 | /* this will be used to rescale old saved abundances in constant pressure model */ |
| | 91 | static realnum hden_save_prev_call; |
| | 92 | const bool DEBUG_MOLECAVER = false; |
| | 93 | |
| | 94 | DEBUG_ENTRY( "MolecSetup()" ); |
| | 95 | |
| | 96 | /* mole_Init set this to -2 when code initialized, so negative |
| | 97 | * number shows very first call in this model */ |
| | 98 | /* >>chng 05 jul 15, do not init if we have never evaluated CO in this iteration |
| | 99 | * and we are below limit where it should be evaluated */ |
| | 100 | if( mole.iteration < 0 || lgMoleZeroed ) |
| | 101 | { |
| | 102 | |
| | 103 | /* very first attempt at ever obtaining a solution - |
| | 104 | * called one time per model since co.iteration_co set negative |
| | 105 | * when cdInit called */ |
| | 106 | |
| | 107 | /* >>chng 05 jun 24, during map phase do not reset molecules to zero |
| | 108 | * since we probably have a better estimate right now */ |
| | 109 | |
| | 110 | /* we should have a neutral carbon solution at this point */ |
| | 111 | //ASSERT( !dense.lgElmtOn[ipCARBON] || dense.xIonDense[ipCARBON][0]>SMALLFLOAT ); |
| | 112 | |
| | 113 | /* set iteration flag */ |
| | 114 | mole.iteration = iteration; |
| | 115 | mole.nzone = nzone; |
| | 116 | |
| | 117 | /* for constant pressure models when molecules are reset on second |
| | 118 | * and higher iterations, total density will be different, so |
| | 119 | * must take this into account when abundances are reset */ |
| | 120 | hden_save_prev_call = dense.gas_phase[ipHYDROGEN]; |
| | 121 | |
| | 122 | if( DEBUG_MOLECAVER ) |
| | 123 | fprintf(ioQQQ," DEBUG MolecSetup iteration %li zone %li zeroing since very first call. H2/H=%.2e\n", |
| | 124 | iteration,nzone,hmi.H2_total/dense.gas_phase[ipHYDROGEN]); |
| | 125 | } |
| | 126 | else if( iteration > mole.iteration ) |
| | 127 | { |
| | 128 | realnum ratio = dense.gas_phase[ipHYDROGEN] / hden_save_prev_call; |
| | 129 | |
| | 130 | /* this is first call on new iteration, reset |
| | 131 | * to first initial abundances from previous iteration */ |
| | 132 | for( i=0; i < mole.num_calc; i++ ) |
| | 133 | { |
| | 134 | COmole[i]->hevmol = COmole[i]->hev_reinit*ratio; |
| | 135 | } |
| | 136 | |
| | 137 | mole.iteration = iteration; |
| | 138 | mole.nzone = nzone; |
| | 139 | |
| | 140 | if( DEBUG_MOLECAVER ) |
| | 141 | fprintf(ioQQQ," DEBUG MolecSetup iteration %li zone %li resetting since first call on new iteration. H2/H=%.2e\n", |
| | 142 | iteration, |
| | 143 | nzone, |
| | 144 | hmi.H2_total/dense.gas_phase[ipHYDROGEN]); |
| | 145 | } |
| | 146 | else if( iteration == mole.iteration && nzone==mole.nzone+1 ) |
| | 147 | { |
| | 148 | /* this branch, second zone with solution, so save previous |
| | 149 | * zone's solution to reset things in next iteration */ |
| | 150 | for( i=0; i < mole.num_calc; i++ ) |
| | 151 | { |
| | 152 | COmole[i]->hev_reinit = (realnum) COmole[i]->hevmol; |
| | 153 | } |
| | 154 | |
| | 155 | mole.nzone = -2; |
| | 156 | hden_save_prev_call = dense.gas_phase[ipHYDROGEN]; |
| | 157 | |
| | 158 | if( DEBUG_MOLECAVER ) |
| | 159 | fprintf(ioQQQ,"DEBUG MolecSetup iteration %li zone %li second zone on new iteration, saving reset.\n", iteration,nzone); |
| | 160 | } |
| | 161 | |
| | 162 | return; |
| | 163 | } |
| | 164 | |
| | 165 | static void mole_null_results(void) |
| | 166 | { |
| | 167 | DEBUG_ENTRY( "mole_null_results()" ); |
| | 168 | /* these are heavy - heavy charge transfer rate that will still be needed |
| | 169 | * for recombination of Si+, S+, and C+ */ |
| | 170 | long int nelem , ion, i; |
| | 171 | |
| | 172 | /* heating due to CO photodissociation */ |
| | 173 | /* do we need to zero out the arrays and vars? */ |
| | 174 | if( !lgMoleZeroed ) |
| | 175 | { |
| 136 | | } |
| 137 | | |
| 138 | | MolecSetup(chReason); |
| 139 | | |
| 140 | | mole_update_species_cache(); /* Update densities of species controlled outside the chemical network */ |
| 141 | | |
| 142 | | mole_update_rks(); |
| 143 | | |
| 144 | | solomon_assumed = hmi.H2_Solomon_dissoc_rate_used_H2g/SDIV(hmi.H2_rate_destroy); |
| 145 | | |
| 146 | | /* this flag is used to stop calculation due to negative abundances */ |
| 147 | | lgNegPop = false; |
| 148 | | |
| 149 | | error = mole_solve(&lgNegPop,&lgZerPop ); |
| 150 | | |
| 151 | | lgConverged = (error < COTOLER); |
| 152 | | if( lgConverged && h2.lgH2ON && hmi.lgBigH2_evaluated && hmi.lgH2_Chemistry_BigH2 ) |
| 153 | | { |
| 154 | | /* >>chng 05 mar 11, go from "total" to H2g for solomon rate */ |
| 155 | | if( fabs( solomon_assumed - hmi.H2_Solomon_dissoc_rate_BigH2_H2g/SDIV(hmi.H2_rate_destroy) ) > |
| 156 | | conv.EdenErrorAllowed/5.) |
| 157 | | { |
| 158 | | lgConverged = false; |
| 159 | | } |
| 160 | | } |
| 161 | | if( CODEBUG ) |
| 162 | | fprintf(ioQQQ,"codrivbug %.2f Neg?:%c\tZero?:%c\tOH new\t%.3e\tCO\t%.3e\tTe\t%.3e\tH2/H\t%.2e\n", |
| 163 | | fnzone , |
| 164 | | TorF(lgNegPop) , |
| 165 | | TorF(lgZerPop) , |
| 166 | | findspecies("OH")->hevmol , |
| 167 | | findspecies("CO")->hevmol/SDIV(dense.gas_phase[ipCARBON]), |
| 168 | | phycon.te, |
| 169 | | hmi.H2_total/dense.gas_phase[ipHYDROGEN]); |
| 170 | | |
| 171 | | mole_effects(); |
| 172 | | mole_h_rate_diagnostics(); |
| 173 | | |
| 174 | | /* say that we have found a solution before */ |
| 175 | | /* lgMoleZeroed = false; */ |
| 176 | | |
| 177 | | /* this flag says whether this is the first zone we are trying |
| 178 | | * to converge the molecules - there will be problems during initial |
| 179 | | * search so do not print anything in this case */ |
| 180 | | lgFirstTry = (nzone==mole.nzone && iteration==mole.iteration); |
| 181 | | |
| 182 | | /* did the molecule network have negative pops? */ |
| 183 | | if( lgNegPop ) |
| 184 | | { |
| 185 | | if( conv.lgSearch && (hmi.H2_total/dense.gas_phase[ipHYDROGEN] <h2lim) && |
| 186 | | (iteration==1) ) |
| 187 | | { |
| 188 | | /* we are in search phase during the first iteration, |
| 189 | | * and the H2/H ratio has fallen |
| 190 | | * substantially below the threshold for solving the CO network. |
| 191 | | * Turn it off */ |
| 192 | | /* >> chng 07 jan 10 rjrw: this was mole_Init(), but the comment suggests |
| 193 | | * it should really be mole_zero */ |
| 194 | | mole_zero(); |
| 195 | | } |
| 196 | | else |
| 197 | | { |
| 198 | | if( called.lgTalk && !lgFirstTry ) |
| 199 | | { |
| 200 | | conv.lgConvPops = false; |
| 201 | | fprintf( ioQQQ, |
| 202 | | " PROBLEM mole_drive failed to converge1 due to negative pops, zone=%.2f, CO/C=%.2e OH/C=%.2e H2/H=%.2e\n", |
| 203 | | fnzone, |
| 204 | | findspecies("CO")->hevmol/SDIV(dense.gas_phase[ipCARBON]), |
| 205 | | findspecies("OH")->hevmol/SDIV(dense.gas_phase[ipCARBON]), |
| 206 | | hmi.H2_total/dense.gas_phase[ipHYDROGEN]); |
| 207 | | ConvFail( "pops" , "CO" ); |
| 208 | | } |
| 209 | | } |
| 210 | | } |
| 211 | | |
| 212 | | |
| 213 | | /* make sure we have not used more than all the CO */ |
| 214 | | ASSERT(conv.lgSearch || findspecies("CO")->hevmol/SDIV(dense.gas_phase[ipCARBON]) <= 1.01 ); |
| 215 | | /*fprintf(ioQQQ,"ratioo o\t%c\t%.2f\t%f\n", TorF(conv.lgSearch), |
| 216 | | fnzone , co.hevmol[ipCO]/dense.gas_phase[ipCARBON] );*/ |
| 217 | | |
| 218 | | /* these are the elements whose converge we check */ |
| 219 | | /* this is a self consistency check, for converged solution */ |
| 220 | | /* >>chng 04 dec 02, this test is turn back on - don't know why it was turned off */ |
| 221 | | if(0) { |
| 222 | | double sum_ion , sum_mol; |
| 223 | | sum_ion = dense.xIonDense[ipCARBON][0] + dense.xIonDense[ipCARBON][1]; |
| 224 | | sum_mol = findspecies("C")->hevmol + findspecies("C+")->hevmol; |
| 225 | | if( fabs(sum_ion-sum_mol)/SDIV(sum_mol) > 1e-2 ) |
| 226 | | { |
| 227 | | /*fprintf(ioQQQ, |
| 228 | | "non conservation element %li zone %.2f sum_ion %.3e sum_mol %.3e\n", |
| 229 | | 5, fnzone, sum_ion , sum_mol);*/ |
| 230 | | conv.lgConvIoniz = false; |
| 231 | | strcpy( conv.chConvIoniz, "CO con2" ); |
| 232 | | conv.BadConvIoniz[0] = sum_ion; |
| 233 | | conv.BadConvIoniz[1] = sum_mol; |
| 234 | | if( CODEBUG ) |
| 235 | | fprintf(ioQQQ,"mole_drive not converged\n"); |
| 236 | | } |
| 237 | | sum_ion = dense.xIonDense[ipOXYGEN][0] + dense.xIonDense[ipOXYGEN][1]; |
| 238 | | sum_mol = findspecies("O")->hevmol + findspecies("O+")->hevmol; |
| 239 | | if( fabs(sum_ion-sum_mol)/SDIV(sum_mol) > 1e-2 ) |
| 240 | | { |
| 241 | | /*fprintf(ioQQQ, |
| 242 | | "non conservation element %li zone %.2f sum_ion %.3e sum_mol %.3e\n", |
| 243 | | 7, fnzone, sum_ion , sum_mol);*/ |
| 244 | | conv.lgConvIoniz = false; |
| 245 | | strcpy( conv.chConvIoniz, "CO con3" ); |
| 246 | | conv.BadConvIoniz[0] = sum_ion; |
| 247 | | conv.BadConvIoniz[1] = sum_mol; |
| 248 | | if( CODEBUG ) |
| 249 | | fprintf(ioQQQ,"mole_drive not converged\n"); |
| 250 | | } |
| 251 | | } |
| 252 | | return; |
| 253 | | } |
| 254 | | |
| 255 | | STATIC void MolecSetup( |
| 256 | | char *chReason ) |
| 257 | | { |
| 258 | | long int i; |
| 259 | | /* this will be used to rescale old saved abundances in constant pressure model */ |
| 260 | | static realnum hden_save_prev_call; |
| 261 | | const bool DEBUG_MOLECAVER = false; |
| 262 | | |
| 263 | | DEBUG_ENTRY( "MolecSetup()" ); |
| 264 | | |
| 265 | | /* this will become reason not converged */ |
| 266 | | strcpy( chReason , "none given" ); |
| 267 | | |
| 268 | | |
| 269 | | /* mole_Init set this to -2 when code initialized, so negative |
| 270 | | * number shows very first call in this model */ |
| 271 | | |