Cloudy Globule

Entries up to 04 Oct 2004 are reformatted versions of ~/CLOUDY/Results-2004/README.sonic

19 May 2004
TODO
HOW PRESSURE CONVERGENCE WORKS IN CLOUDY
THE PROBLEM WITH STRONG D
20 May 2004
PROBLEM WITH PRESSURE FAILURES IN EARLY ZONES
21 May 2004
INVESTIGATION OF HOW THE VELOCITY GETS SET:
Proposal:
MORE TRANSSONIC MODELS
XA013*.in
22 May 2004
FURTHER CHANGES I HAVE MADE TO CLOUDY:
MORE IDEAS
24 May 2004
MORE SOURCE CHANGES:
CURRENT STATUS
GLOBULE MODELS
26 May 2004
STATUS OF GLOBULE MODELS
SOFTENING THE EFFECTS OF ADVECTION
04 Oct 2004
12 Nov 2004

19 May 2004

Attempts to get the transsonic models working.

ZS016.in starts off on the R-branch but has an explicit antishock set at a certain depth. I added the code for this to dynamics.c and parse_set.c as mirror images of the "set dynamic shock XXXX" code. The antishock is unphysical but the idea is that it should be a small jump. How it works is that the pressure solver is initially looking for a supersonic solution but after the antishock it switches over to looking for a subsonic solution.

I tried to choose the antishock depth to be the minimum in the velocity from a weak-R test. This works quite well for the first few iterations: the antishock occurs at the H i-front and is a jump of < 10% in the velocity. However, eventually the solution ends up hitting the sonic point before getting to the antishock depth - and there it stops with a pressure failure.

The ZX series have the problem that the antishock is too strong in the initial iterations (because I chose its position according to where it should be in the later iterations). As a result, the subsequent iterations develop an echo of the antishock that is one advection length downstream. Late, we get an echo of the echo, etc. As a result, it never converges. It might be better to have the antishock at a given Mach number, rather than a given radius. That way, it would happily do a weak-R solution for the first few iterations.

In theory, this should work with the "strongd" pressure model. In that case, it shouldn't be necessary to specify a depth at which the solver switches from the supersonic to subsonic branch - it should do it automatically when it fails to find a supersonic solution. At the moment this is not working beacause we get a pressure failure at the sonic point.

TODO

  1. Finesse the strongd logic so that code does not stop at the sonic point.
  2. Find a lower ionization parameter model that will run faster (also, don't go so deep on the neutral side). This is now done with the ZX series, which have phi(h) = 11 and stop at electron fraction of 0.03. They take about 15 minutes to do 30 iterations.
  3. At the moment the strongd pressure mode will try to get over regions that want to go through a sonic point before we have reached the maximum in c-squared (supposedly). This deals with one half of the ways that a trial solution can stray from the "true solution". Also needed is a way to force a solution that would naturally want to be weak-R to make a sonic jump at the right place. This would seem to require some way of telling when you had gone through a minumimum in the velocity and putting in a little antishock there. Having the antishock at some value of the isothermal Mach number (e.g., 1.05) could be a way of doing this.

HOW PRESSURE CONVERGENCE WORKS IN CLOUDY

ConvPresTempEdenIoniz() repeatedly calls PressureChange(), which calls lgConvPres() (in the same file). It exits the loop once conv.lgConvPres is TRUE (or it aborts or exceeds max iterations).

For the wind case, lgConvPres() calls DynaPresChngFactor() to calculate pressure_change_factor. This has branches for the subsonic and supersonic cases and uses the history of previous pressure evaluations from previous iterations.

Then lgConvPres() sets its return value and conv.lgConvPres to TRUE if pressure_change_factor is in range 1.0 +/- conv.PressureErrorAllowed. Otherwise, FALSE.

PressureChange() also sets conv.lgConvPres to the return value of lgConvPres(), which seems redundant...

Then PressureChange() returns FALSE if conv.lgConvPres is TRUE. Otherwise, it carries on to calculate some extra stuff (mainly to do with abundance fluctuations). The value of pressure_change_factor gets capped to some value, depending on conditions. Then it returns the value of lgChange, which looks like it will be TRUE in general.

THE PROBLEM WITH STRONG D

With the strongd or the antishock-by-mach pressure modes, then it is possible to hit a region where no pressure solution is possible for a while. There is some logic in DynaPresChngFactor() to detect this. However, it sets conv.lgConvPres to FALSE so that ConvPresTempEdenIoniz() sees it as a simple pressure failure. If this happens repeatedly, then it gives up and calls ConvFail("pres"), which see that the gas and ram pressures are nearly equal and so sets pressure.lgSonicPoint. When this flag is seen by lgEndFun(), it will stop the program. We need some way to indicate to ConvPresTempEdenIoniz() that we are in such a region and that it should just get over it and move on to the next zone.

Question is, do we want it to stop looking for a pressure solution immediately when this happens? Assuming yes, then I have added a new variable, pressure.lgStrongDLimbo, that gets set when this happens.

Actually, I've found a better way - we now have a new flag, pressure.lgSonicPointAbortOK, which is set to FALSE by the pressure modes that might want to go through the sonic point, thereby stopping lgEndFun() from ending it all. There may still be a use for lgStrongDLimbo, so I'll leave it in for now.

Things sort of work for a few iterations if I choose the right value of the various convergence tolerances, but it always falls over adter a bit. One problem is that the model I am doing is starting off very close to sonic.

20 May 2004

In most of the models, there are 3 maxima in c-squared:

  1. at the illuminated face
  2. at the He i-front
  3. at the H i-front

The third one is slightly higher than the other two, but not by much. This makes things difficult since any model that is close to making a sonic transition at the H i-front is also close to sonic at the illuminated face. This often causes pressure failures in the first few cells. Hence, it would be better to have a model where there was only one c-squared maximum. This is difficult to find. I have tried reducing the ionization parameter but this doesn't make much difference.

PROBLEM WITH PRESSURE FAILURES IN EARLY ZONES

Many weak-R models fail in similar ways. This seems to be due to the initial velocity being too close to sonic (but "close" can mean as much as a factor of 2). The symptoms are that the density in the first zone gets set to a much lower value than was specified in the init file. Then we get pressure failures a few zones further on. What can be causing this?

The target pressure that we should be aiming at in each zone seems to be pressure.PresTotlInit. This is set in various places, all with the same form:

     PresTotCurrent();
     ...
     pressure.PresTotlInit = pressure.<nop>PresTotlCurr;

pressurechange.c:84 iter_startend.c:200, in IterStart() conv_init_solution.c, various places in ConvInitSolution()

PresTotCurrent() simply evaluates the current pressure from all constituents.

Something must be going wrong somewhere, since it ought to be guaranteed that the density at the illuminated face is equal to the hden specified in the init file.

XA020 is an example of this failure mode.

Learnt new things about gdb: automatic display list. Discovered that problem lies in ConvInitSolution(), and is not at any of the places I had thought: there are other places where pressure.PresTotlInit is changed by the '*=', '/=' operators. So the problems seem to lie in the section after line 771 in conv_init_solution.c, where we are calling the pressure solver to try and get back to the original solution. This is obviously not working.

Even before the target pressure has changed at all, ConvPresTempEdenIoniz is failing to keep the density steady.

21 May 2004

Sent mail yesterday to Gary and Robin, querying the following code:

 
/* Subsonic case: pressure ^ with density ^ => increase density further */
/* Super "  case: pressure ^ with density v => decrease density further */

/* printf("Presmode %d flag %g factor %g\n",zonepresmode,(er-erp)*(dense.gas_phase[ipHYDROGEN]-dp),factor); */
if (zonepresmode == SUBSONIC && (er-erp)*(dense.gas_phase[ipHYDROGEN]-dp) < 0)
{				
	factor = 1+3*width;
}
else if (zonepresmode == SUPERSONIC && (er-erp)*(dense.gas_phase[ipHYDROGEN]-dp) > 0)
{
	factor = 1-3*width;
}

I originally thought that the code was in error, since it is doing the opposite of what it advertises in the comment. However, I now think that it is the comment that is wrong, and this code is actually trying to force the solution to the requested branch (supersonic/subsonic) in cases where dP/drho is opposite to what is expected for that branch.

The problem arises when it tries to do this on the first zone, since it ends up forcing down the density to insanely low values.

In principle, it should work:

If we want to be supersonic, then we ought to have dP/drho < 0 at constant mass flux. Hence, it is reasonable to suppose that if dP/drho > 0 then we are really subsonic and we need to decrease the density to push us into the supersonic regime. Could the problem be that the velocity is treated differently in the first zone and is not increasing as the density goes down?

INVESTIGATION OF HOW THE VELOCITY GETS SET:

Assuming plane-parallel (dynamics.FluxIndex == 0), then dynamics.FluxScale = wind.windv0, which is set from the initialization commands. The function DynaFlux() returns the value dynamics.FluxScale*struc.DenMass[0], and this seems to be the root of our problems: if the pressure solver pushes down the density in the first zone, then this will decrease DynaFlux(), which is used to set the velocity in PressTotCurrent() as

wind.windv = DynaFlux(radius.depth)/(phycon.xMassDensity); 

Actually, this is only done for nzone > 2, so wind.windv in the first zone always stays as wind.windv0, even if the density is going down. Not good. What is needed is to recalculate wind.windv inside the pressure solver, even if it is the first zone. For this to work, we also need that DynaFlux() does not use struc.DenMass[0] but rather the initial value of the density, as specified in the init file.

Proposal:

In PressTotCurrent() we set a new variable

phycon.xMassDensity0 = phycon.xMassDensity

but only if this has not been set before (do this by setting to -1.0 in zero.c)

Then we remove the test (nzone > 1) for resetting wind.windv and change DynaFlux() to use phycon.xMassDensity0 instead of struc.DenMass[0]

This seems to work!

MORE TRANSSONIC MODELS

XA013*.in

These are moderate ionization parameter models with phi(h)=11, hden=4. There is no well-defined He i-front so there is only one maximum in c-squared (other than the one at the illuminated face).

XA013.in has "set dynamics pressure mode supersonic" and does the typical weak-R thing. On the first iteration, the isothermal Mach number start off around 1.14, increases to 1.4 and then dips to about 1.24 at the i-front, before shooting up on the neutral side (I have "stop efrac -1.5", so it doesn't go very far). Subsequent iterations pull the i-front inwards a bit and the Mach number dips down further as the T-peak at the i-front gets sharper. By the 5th iteration or so, the Mach number hits unity, but since we have the supersonic pressure mode it bounces back again.

XA013A.in has an antishock set at M=1.05. This succeeds at forcing a transsonic solution after a few iterations. However, on the next iteration it switches back to a weak-R solution because the advected terms have changed enormously within one advection length downstream of where the sonic point was, depressing the sound speed there so that the Mach number no longer dips down enough. On further iterations, the solution recovers and goes sonic once again but the whole cycle repeats itself every 4 iterations.

XA013A2.in is similar but with the antishock set at M=1.01 and the convergence criteria tightened up. It behaves similarly.

22 May 2004

Next thing to try - it would be nice to reduce the initial velocity so that even the first iteration hits the sonic point in the i-front. This is not easy because c-squared is higher at the illuminated face than it is at the i-front. Perhaps it would work to run a static model through to the minimum in c-squared halfway through the ionized region. Then start a dynamic model with the transmitted continuum from that.

This doesn't work quite how I had hoped: the T in the model using the transmitted continuum (XB013) doesn't match with that from that of the constant pressure model (XA000P). Is this something to do with the diffuse field? This doesn't even work when I try and match one constant-gas-pressure model (XB000P) to another constant-gas-pressure model (XA000P).

Heating is basically H 1 and He 1. Cooling is a mixture of forbidden lines and 'Hp 0 0.0', whatever that is. The heating rate falls off with depth, which is presumably what drives the temperature change. Heating is significantly higher at the illuminated face of XB000P than it was at the back face XA000P, even though these are in theory the same place. The neutral fraction is also somewhat higher there, which would explain this. Maybe this is due to escaping lyman lines?

YES!! I have found the answer. I still can't get the temperatures to match up but it doesn't matter: if I use the "case b no photoionization" option (which stops Ly-a from escaping from the illuminated face and turns off photionization from excited states), then the temperature now increases monotonically towards the i-front. So, I don't need to mess around with the transmitted continuum any more.

On a side note, I don't understand why I don't get an equivalent result from just using the "sphere" command: in a closed geometry, each ly-a photon that escapes from the illuminated face should be exactly balanced by one coming in from the other side of the nebula, shouldn't it? UPDATE: it seems "sphere static" is what I wanted.

FURTHER CHANGES I HAVE MADE TO CLOUDY:

  1. Allow iteration to convergence even if case-b is turned on (but only for negative wind.windv0)
  2. Stop pressure failures from reducing radius.drad if either pressure.lgSonicPoint or pressure.lgStrongDLimbo are set.

MORE IDEAS

  1. In case of pressure failures at the sonic point, have the Mach number pegged at unity, rather than let the density and velocity wander about so much.
  2. Have the iterations vary the initial wind velocity in order to get the solution going through the sonic point.
  3. Have a user flag to turn on the new quadratic pressure solver. DONE

24 May 2004

MORE SOURCE CHANGES:

Added option "set dynamics pressure solver quadratic" to turn on the quadratic pressure solver via a flag dynamics.lgQuadPresSolver. Changes to dynamics.h, parse_set.c, dynamics.c (DynaZero() and DynaPresChngFactor())

CURRENT STATUS

Model XC014A2 goes transsonic on the first iteration. It is trying to go through the sonic point before the c-squared max has been reached, so it has a sequence of pressure failures before getting out the other side. The changes I have made to the zoning logic manage to stop radius.drad from getting too small during this, so we do manage to get out the other side. The quantity degree of pressure failure can be quantified as (P-P0)/P0, where P is the best pressure found (Pcurrent) and P0 is the target pressure (Pcorrect). This behaves quite nicely over the pressure-failure region, rising up to about 1%, then falling back as we come out the other side.

On the next iteration, we don't get a sonic point at all because all the mess around the sonic point has been advected back towards the star and causes a bunch of pressure failures before we even get near the sonic point. The c-squared maximum is all messed up and the solution follows the weak-r path.

What to do?

  1. Try and stop the velocity wandering all over the place in the pressure-fail region (Idea 0., above)

I had originally thought of trying to converge to Pgas=Pram if we fail to converge to Ptotl=Pcorrect. However, looking at the quadratic solver, it seems that it will look for a minimum in the P(rho) curve if it can't find a root, which is exactly what we need (clever Robin!)

  1. Try increasing the initial velocity so that the initial sonic transition occurs closer to the c-squared maximum

What happened?

Using the quadratic solver, we do indeed get a much better transition through the limbo around the sonic point: the velocity and density now vary more-or-less smoothly. However, we still get the problem that the next iteration goes weak-r on us.

GLOBULE MODELS

wind velocity -43 index -2 center 10000000000000000 no continuum 

Strangely, these seem to work. But I'm not sure mass flux is working correctly. They all converge on the 4th iteration. Not sure that advection is being turned on properly. ah, should be "wind advection ..."

26 May 2004

STATUS OF GLOBULE MODELS

I have a model that is designed to look like a Helix knot - XDglob6.in

The first iteration works, just about. I start out at a radius of 1.e17 cm with a density of 0.1 pcc, a 120,000 K black-body flux of Phi(H)=10**8.5, and a velocity of -64.35 km/s. The ionization front then occurs at a radius of about 1.e15 cm.

There is no csq-maximum but it goes through the sonic point anyway, which it is allowed to in spherical geometry. The sonic point is also at a very low value of H+ fraction - about 1%, although He+ is around 10%. Ne peaks a bit nearer the star, around x(H+) = 0.1, with a value of around 1.e3, but there is also an Ne peak on at the far-neutral boundary, which is worrying. This is where the hydrogen density shoots up to about 1.e6. This is shown in XDglob6-zoom.eps, which shows various physical variables in the region around the i-front.

I also did the optical line structure: XDglob6-lines.eps, although this is a bit meaningless since it is only the first iteration without advection. [O I] is very strong because of the low ionization fraction around the Ne peak. Ha emission is similar to [N II] on the ionized side, albeit 4 times weaker, and extends further in on the neutral side, with a silly sharp peak at the inner edge. [O III] is extremely weak, with a broad peak about 4 times farther out. He I is very concentrated on the neutral side and is still climbing at he inner edge

Gnuplot commands:

 
plot 'XDglob6.ovr' i 0 u (1.e17-$1):(10**($2-4)) t 'T/1.e4', \
 '' i 0 u (1.e17-$1):(10**($5-3)) t 'ne/1.e3', \
 '' i 0 u (1.e17-$1):(10**$8) t 'x(H+)', \
 '' i 0 u (1.e17-$1):(10**$10) t 'x(He+)', \
 '' i 0 u (1.e17-$1):(10**($5-$4)) t 'xe', \
 '' i 0 u (1.e17-$1):(10**($4-3)) t 'nh/1.e3', \
 'XDglob6.pre' i 0 u (1.e17-$1):(-$10/30.) t 'v/30', \
 '' i 0 u (1.e17-$1):(sqrt(3./5.)*$11/30.) t 'c/30', \
 '' i 0 u (1.e17-$1):(sqrt(3./5.)*sqrt($12/$6)*$11/30.) t 'alf/30'

plot 'XDglob6.lines' i 0 u (1.e17-$1):(5*$2) t 'ha x 5', \
 '' i 0 u (1.e17-$1):(8*$4) t 'he i x 8', \
 '' i 0 u (1.e17-$1):(2*$11) t 'n ii x 2', \
 '' i 0 u (1.e17-$1):14 t 'o i', \
 '' i 0 u (1.e17-$1):(50*$9) t 'o iii x 50'

The second iteration is a complete nonsense. The advection pushes down the temperature while we are still way out in the flow. T drops to zero before we get in to a radius of 5.e16, so the calculation stops. The third iteration is even worse and hardly gets started before T drops to zero. Then the fourth iteration, which has no real previous iteration to get the advection from, comes out like the first iteration again, and so it continues....

SOFTENING THE EFFECTS OF ADVECTION

Proposed changes to the way advection terms are added (DynaNewStep, DynaSaveLast, DynaIonize)

  1. Slowly ramp up the advection terms over several iterations for a fixed value of Dyn_dr - would this help with cases like the globule above?
  2. Smooth out the Old structure (e.g., convolve it with top-hat) before using it. The smoothing length would be a fraction of the advection length.

This could be done in DynaSaveLast, or would it make more sense to have a new function, which was called at the start of a new step?

Two options:

A. Convolution by FFT - order B. Just iterate over neighbours - order NM

where N is number of zones and M is number of neighbours (i.e., those zones within one smoothing length of each zone).

Option B would be a lot easier to code and will not be too inefficient if we do box smoothing, since smoothing length is a fraction of advection length, which in turn is a small fraction of total depth.

04 Oct 2004

An idea might be to restrict the models to one stopping criterion. As it is, where we have the possibility of stopping on either temperature or electron density then which one is operating is changing from one iteration to the next, which may be contributing to the flip-flops.

12 Nov 2004

With Torsten, I am looking at the globule models again with a view to do