/home66/gary/public_html/cloudy/c08_branch/source/conv_pres_temp_eden_ioniz.cpp

Go to the documentation of this file.
00001 /* This file is part of Cloudy and is copyright (C)1978-2008 by Gary J. Ferland and
00002  * others.  For conditions of distribution and use see copyright notice in license.txt */
00003 /*ConvPresTempEdenIoniz solve for current pressure, calls PressureChange, ConvTempEdenIonize,
00004  * called by cloudy */
00005 /*ConvFail handle conergece failure */
00006 #include "cddefines.h"
00007 #include "phycon.h"
00008 #include "rt.h"
00009 #include "dense.h"
00010 #include "pressure.h"
00011 #include "trace.h"
00012 #include "conv.h"
00013 #include "grainvar.h"
00014 #include "grains.h"
00015 
00016 /* the limit to the number of loops */
00017 /* >>chng 02 jun 13, from 40 to 50 */
00018 static const int LOOPMAX = 100;
00019 
00020 /*ConvPresTempEdenIoniz solve for current pressure, calls PressureChange, ConvTempEdenIoniz,
00021  * called by cloudy 
00022  * returns 0 if ok, 1 if disaster */
00023 int ConvPresTempEdenIoniz(void)
00024 {
00025         long int loop,
00026                 LoopMax=LOOPMAX;
00027         double 
00028                 hden_old ,
00029                 hden_chng_old ,
00030                 hden_chng,
00031                 /*pres_old ,*/
00032                 /*pres_chng_old ,*/
00033                 /*pres_chng,*/
00034                 /*old_slope,*/
00035                 /*rel_slope,*/
00036                 dP_chng_factor;
00037         bool lgPresOscil;
00038         long int nloop_pres_oscil;
00039         double TemperatureInitial;
00040 
00041         DEBUG_ENTRY( "ConvPresTempEdenIoniz()" );
00042 
00043         /* this will count number of times we call ConvBase in this zone,
00044          * counter is incremented there */
00045         conv.nPres2Ioniz = 0;
00046         loop = 0;
00047 
00048         /* this will be the limit, which we will increase if no oscillations occur */
00049         LoopMax = LOOPMAX;
00050         /* set the initial temperature to the current value, so we will know
00051          * if we are trying to jump over a thermal front */
00052         TemperatureInitial = phycon.te;
00053 
00054         /* this will be flag to check for pressure oscillations */
00055         lgPresOscil = false;
00056         /* this is loop where it happened */
00057         nloop_pres_oscil = 0;
00058         /* should still be true at end */
00059         conv.lgConvPops = true;
00060 
00061         /* we will use these to check whether hden oscillating - would need to decrease step size */
00062         hden_old = dense.gas_phase[ipHYDROGEN];
00063         hden_chng = 0.;
00064         /*pres_old = pressure.PresTotlCurr;*/
00065         /*pres_chng = 0.;*/
00066 
00067         /* this is dP_chng_factor 
00068          * cut in half when pressure error changes sign */
00069         dP_chng_factor = 1.;
00070         /*rel_slope = 0.;*/
00071 
00072         if( trace.nTrConvg>=1  )
00073         {
00074                 fprintf( ioQQQ, 
00075                         " ConvPresTempEdenIoniz1 entered, will call ConvIoniz to initialize\n");
00076         }
00077 
00078         /* converge the ionization first, so that we know where we are, and have
00079          * a valid foundation to begin the search */
00080         /* the true electron density dense.EdenTrue is set in eden_sum called by ConvBase */
00081 
00082         /* chng 02 dec 11 rjrw -- ConvIoniz => ConvTempEdenIoniz() here for consistency with inside loop */
00083         /* ConvIoniz; */
00084         if( ConvTempEdenIoniz() )
00085         {
00086 
00087                 return 1;
00088         }
00089 
00090         /* this evaluates current pressure, and returns whether or not 
00091          * it is within tolerance of correct pressure */
00092         conv.lgConvPres = false; /* lgConvPres(); */
00093 
00094         /* convergence trace at this level */
00095         if( trace.nTrConvg>=1  )
00096         {
00097                 fprintf( ioQQQ, 
00098                         " ConvPresTempEdenIoniz1 ConvIoniz found following converged: Pres;%c, Eden;%c, Temp;%c, Ion:%c Pops:%c\n", 
00099                         TorF(conv.lgConvPres) , 
00100                         TorF(lgConvEden() ),
00101                         TorF(lgConvTemp() ) ,
00102                         TorF(conv.lgConvIoniz) ,
00103                         TorF(conv.lgConvPops));
00104         }
00105 
00106         /* >>chng 01 apr 01, add test for at least 2 loops to get better pressure convergence */
00107         /* >>chng 01 oct 31, add test for number of times converged, for constant
00108          * pressure will get two valid solutions */
00109         /*while( (loop < LoopMax) && !(conv.lgConvPres  &&nPresConverged > 1) &&  !lgAbort )*/
00110         /* >>chng 02 dec 12, do not demand two constant pressure being valid - should not be
00111          * necessary if first one really is valid, and this caused unneeded second evaluation
00112          * in the constant density cases */
00113 
00114         /* trace convergence print at this level */
00115         if( trace.nTrConvg>=1  )
00116         {
00117                 fprintf( ioQQQ, 
00118                         "\n ConvPresTempEdenIoniz1 entering main pressure loop.\n");
00119         }
00120         while( (loop < LoopMax) && !conv.lgConvPres &&  !lgAbort )
00121         {
00122                 /* there can be a pressure or density oscillation early in the search - if not persistent
00123                  * ok to clear flag */
00124                 /* >>chng 01 aug 24, if large change in temperature allow lots more loops */
00125                 if( fabs( TemperatureInitial - phycon.te )/phycon.te > 0.3 )
00126                         LoopMax = 2*LOOPMAX;
00127                 /* if start of calculation and we are solving for set pressure,
00128                  * allow a lot more iterations */
00129                 if( nzone <= 1 && pressure.lgPressureInitialSpecified )
00130                         LoopMax = 10*LOOPMAX;
00131 
00132                 /* change current densities of all constituents if necessary, 
00133                  * PressureChange evaluates lgPresOK, true if pressure is now ok
00134                  * sets CurrentPressure and CorrectPressure */
00135                 hden_old = dense.gas_phase[ipHYDROGEN];
00136                 /*pres_old = pressure.PresTotlCurr;*/
00137 
00138                 /* this will evaluate current pressure, update the densities, 
00139                  * determine the wind velocity, and set conv.lgConvPres,
00140                  * return value is true if density was changed, false if no changes were necessary 
00141                  * if density changes then we must redo the temperature and ionization 
00142                  * PressureChange contains the logic that determines how to change the density to get
00143                  * the right pressure */
00144                 if( PressureChange( dP_chng_factor ) ) 
00145                 {
00146                         /* heating cooling balance while doing ionization,
00147                          * this is where the heavy lifting is done, this calls PresTotCurrent,
00148                          * which sets pressure.PresTotlCurr */
00149                         if( ConvTempEdenIoniz() )
00150                         {
00151                                 return 1;
00152                         }
00153                 }
00154 
00155                 /* if product of these two is negative then hden is oscillating */
00156                 hden_chng_old = hden_chng;
00157                 /*pres_chng_old = pres_chng;*/
00158                 hden_chng = dense.gas_phase[ipHYDROGEN] - hden_old;
00159                 if( fabs(hden_chng) < SMALLFLOAT )
00160                         hden_chng = sign( (double)SMALLFLOAT, hden_chng );
00161                 /*pres_chng = pressure.PresTotlCurr - pres_old;*/
00162                 /*old_slope = rel_slope;*/
00163                 /*rel_slope = (pres_chng/pressure.PresTotlCurr) / (hden_chng/dense.gas_phase[ipHYDROGEN]);*/
00164 
00165                 {
00166                         /*@-redef@*/
00167                         enum{DEBUG_LOC=false};
00168                         /*@+redef@*/
00169                         if( DEBUG_LOC && nzone > 150 && iteration > 1 )
00170                         {
00171                                 fprintf(ioQQQ,"%li\t%.2e\t%.2e\t%.2e\n", 
00172                                         nzone,
00173                                         pressure.PresTotlCurr, 
00174                                         pressure.PresTotlCorrect,
00175                                         (pressure.PresTotlCorrect - pressure.PresTotlCurr)*100./pressure.PresTotlCorrect
00176                                         );
00177                         }
00178                 }
00179 
00180                 /* check whether pressure is oscillating */
00181                 /* >>chng 02 may 31, add check on sign on hden changes */
00182                 /* >>chng 02 jun 05, add loop > 1 so that don't trigger off old vals that have
00183                  * not stabilized yet */
00184                 /* >>chng 04 dec 11, rm test of pressure changing, only check whether hden is changing
00185                  * very small changes in hden resulted in changes in pressure with some noise due to 
00186                  * finite precision in te solver - that makes very small oscillations that are not
00187                  * actually oscillations, only noise */
00188                 if( ( /*( pres_chng*pres_chng_old < 0. )||*/ ( hden_chng*hden_chng_old < 0. ) ) && 
00189                         loop > 1 )
00190                 {
00191                         /*fprintf(ioQQQ,"DEBUG\t%.2f\t%.2e\t%.2e\t%.2e\t%.2e\n",
00192                                 fnzone,pres_chng,pres_chng_old ,hden_chng,hden_chng_old);*/
00193                         /* the sign of the change in pressure has changed, so things
00194                          * are oscillating.  This would be a problem */
00195                         lgPresOscil = true;
00196                         nloop_pres_oscil = loop;
00197                         /* >>chng 04 dec 09, go to this factor becoming smaller every time oscillation occurs */
00198                         dP_chng_factor = MAX2(0.1 , dP_chng_factor * 0.75 );
00199                         /* dP_chng_factor is how pressure changes with density - pass this to
00200                          * changing routine if it is stable */
00201                         /* >>chng 04 dec 09, take average of old and new dP_chng_factor to avoid pressure
00202                          * failures in orion_hii_pdr_pp.in 
00203                         if( loop > 4 && old_slope*rel_slope > 0. )
00204                                 dP_chng_factor = (1.-FRACNEW)*dP_chng_factor + FRACNEW*rel_slope;*/
00205 
00206                         /*fprintf(ioQQQ,"oscilll %li %.2e %.2e %.2e %.2e dP_chng_factor %.2e\n", 
00207                                 loop ,
00208                                 pres_chng, 
00209                                 pres_chng_old,
00210                                 hden_chng , 
00211                                 hden_chng_old ,
00212                                 rel_slope);*/
00213                 }
00214 
00215                 /* convergence trace at this level */
00216                 if( trace.nTrConvg>=1  )
00217                 {
00218                         fprintf( ioQQQ, 
00219                                 " ConvPresTempEdenIoniz1 %.2f l:%3li nH:%.4e ne:%.4e PCurnt:%.4e PCorct:%.4e err:%6.3f%% dP/dn:%.2e Te:%.4e Osc:%c\n", 
00220                           fnzone,
00221                           loop, 
00222                           dense.gas_phase[ipHYDROGEN], 
00223                           dense.eden,
00224                           pressure.PresTotlCurr, 
00225                           pressure.PresTotlCorrect, 
00226                           /* this is percentage error */
00227                           100.*(pressure.PresTotlCurr - pressure.PresTotlCorrect )/pressure.PresTotlCorrect,
00228                           dP_chng_factor ,
00229                           phycon.te,
00230                           TorF(lgPresOscil)  );
00231                 }
00232 
00233                 /* increment loop counter */
00234                 ++loop;
00235 
00236                 /* there can be a pressure or density oscillation early in the search - if not persistent
00237                  * ok to clear flag 
00238                  * >>chng 04 sep 22, add this logic */
00239                 if( loop - nloop_pres_oscil > 4 )
00240                         lgPresOscil = false;
00241 
00242                 /* if we hit limit of loop, but no oscillations have happened, then we are
00243                  * making progress, and can keep going */
00244                 if( loop == LoopMax && !lgPresOscil )
00245                 {
00246                         LoopMax = MIN2( 100 , LoopMax*2 );
00247                 }
00248         }
00249 
00250         /* >>chng 04 jan 31, now that all of the physics is converged, determine grain drift velocity */
00251         if( gv.lgDustOn && gv.lgGrainPhysicsOn )
00252                 GrainDrift();
00253 
00254         /* >>chng 01 mar 14, all ConvFail one more time, no matter how
00255          * many failures occurred below.  Had been series of if, so multiple
00256          * calls per failure possible. */
00257         /* >>chng 04 au 07, only announce pres fail here,
00258          * we did not converge the pressure */
00259         if( !conv.lgConvIoniz )
00260                 ConvFail("ioni","");
00261         else if( !conv.lgConvEden )
00262                 ConvFail("eden","");
00263         else if( !conv.lgConvTemp )
00264                 ConvFail("temp","");
00265         else if( !conv.lgConvPres )
00266                 ConvFail("pres","");
00267 
00268         /* this is only a sanity check that the summed continua accurately reflect
00269          * all of the individual components.  Only include this when NDEBUG is not set,
00270          * we are in not debug compile */
00271 #       if !defined(NDEBUG)
00272         RT_OTS_ChkSum(0);
00273 #       endif
00274 
00275         return 0;
00276 }

Generated on Mon Feb 16 12:01:13 2009 for cloudy by  doxygen 1.4.7