-
Notifications
You must be signed in to change notification settings - Fork 0
/
pldiffus.c
423 lines (417 loc) · 13.5 KB
/
pldiffus.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
#include "include.h"
/******************************/
/* Diffusion related routines */
/******************************/
/*****************************************************************************
*** * * * * * * * * * * * * ***
*** * * * * * * D I F F U S E ( ) * * * * * * ***
*** * * * * * * * * ***
*****************************************************************************
*
* Subroutine: diffuse()
*
* Arguments: none
*
* Return value: none
*
* Action: Implements intercellular diffusion of gas using a
* modified von Neumann law. Essentially it is assumed
* that gas can diffuse through that part of a cell-cell
* arc which is not covered by a Plateau border.
*
* The rate of diffusion is determined by `diffuserate'
* and this is scaled to give a rate of diffusion
* proportional to `Abar' (the average area per cell).
* This means that cell areas change by a certain
* percentage per step.
*
* NB: This routine is very simple but it doesn't do
* everything it needs to do. In particular when cells
* get very small as a consequence of diffusion, problems
* occur (which are not solved in the current program).
* This subroutine has not been used much...
*
*****************************************************************************/
void diffuse()
{
short i, ii, j, c1, c2;
REAL abar, da, dt, x1, y1, x2, y2, p1, p2;
REAL carclen();
void vnbrxy();
abar=boxwid*boxhgt/((REAL) nc);
dt=diffuserate*abar;
for (ii=0; ii<nv; ii++) {
i=vlist[ii];
j=vnbr[i][0];
if (j>i) {
x1=vx[i]; y1=vy[i];
vnbrxy(i,0,&x2,&y2);
p1=cp[c1=cadj[i][1]]; p2=cp[c2=cadj[i][2]];
da=dt*(p1-p2)*carclen(x1,y1,x2,y2,p1,p2);
darea[c2] += da; darea[c1] -= da;
}
}
tfoam += dt;
}
/*****************************************************************************
*** * * * * * * * * * * * * ***
*** * * * * * M A K E F R A C T I O N ( ) * * * * * ***
*** * * * * * * * * ***
*****************************************************************************
*
* Subroutine: makefraction(REAL phi0, boolean plotflag)
*
* Arguments: phi0 = target value for the new area fraction `phi'
* plotflag = TRUE selects plotting at each iteration
*
* Return value: none
*
* Action: This routine changes the area fraction of a wet foam
* until it reaches the target fraction `phi0' (which
* may be either greater or lesser than the existing
* fraction `phi'). Since the initialisation routines
* can only generate foams with very small Plateau
* borders (i.e. `phi' close to 0.99) this subroutine
* is crucially important for generating wetter foams.
*
* However there is currently a serious bug in this
* algorithm which means that it does not cope well with
* very wet foams (this ought to be fixed soon).
*
* The outline of the algorithm is straightforward and
* goes as follows:
* (i) Firstly choose a step size `dphi' by which the
* current area fraction will be changed (we do not want
* to change `phi' all in one go).
* (ii) Then change the target areas of all the cells so
* as to match the new area fraction.
* (iii) Call `phirelax(phi)' so as to change the
* geometry of the network to match the new area fraction.
* The routine `phirelax()' works by changing the
* curvature of the border arcs (thereby changing the
* areas of adjacent cells by a small amount).
* (iv) Then equilibrate the vertices of the network by
* calling `equil()' (which works by imposing the
* condition that arcs match up smoothly).
* (v) Iterate until the target area fraction `phi0'
* is reached.
*
*****************************************************************************/
void makefraction(phi0, plotflag)
REAL phi0;
boolean plotflag;
{
short i, ii, j;
REAL phi, dphi, atot;
REAL equil();
void foamplot(), setconstants(), phirelax();
#ifdef IRIS
void zoom();
#endif
/*
* Calculate `atot' which is what the total area of gas *ought* to be
* at present (even though geometrically the network may have cells which
* are slightly the wrong size).
*
* Note that `darea[i]' records the difference between the area which a
* cell `i' *ought* to have, and the area which (geometrically) it actually
* contains.
*/
atot=0.0;
for (ii=0; ii<nc; ii++) {
i=clist[ii];
atot += carea[i]+darea[i];
}
for (ii=0; ii<nbub; ii++) {
i=bublist[ii];
atot += carea[i]+darea[i];
}
phi=(atot)/(boxwid*boxhgt);
/*
* Down to business...
*/
if (phi>phi0) {
/*
* Case 1: Shrink the area fraction down to `phi0'...
*/
/*
* Aim to change the area fraction in steps `dphi' which
* must not be overly large (because `phirelax()' cannot
* cope with large steps).
*/
dphi=(1.0-phi)*PHIFRACTION;
if (fabs(phi-phi0)<fabs(dphi)) dphi=phi-phi0;
while (fabs(dphi/phi) > areasup) {
/* Note: areasup = `negligibly small area' */
/*
* Change the target areas of all the cells and recalculate
* `atot' and `phi' ( = current target for area fraction)
*/
atot=0.0;
for (ii=0; ii<nc; ii++) {
i=clist[ii];
darea[i] -= (carea[i]+darea[i])*dphi/phi;
atot += carea[i]+darea[i];
}
for (ii=0; ii<nbub; ii++) {
i=bublist[ii];
darea[i] -= (carea[i]+darea[i])*dphi/phi;
atot += carea[i]+darea[i];
}
phi=(atot)/(boxwid*boxhgt);
/*
* Actually change the area fraction of the network
* (by tweaking the curvature of the Plateau border arcs)
*
* ...and do it to a pretty high degree of accuracy (i.e. the parameter
* `areasup' is very small [or certainly ought to be] ) otherwise
* the equilibration would bomb out.
*/
phirelax(phi);
/*
* Call `equil()' to relax the position of the vertices...
*/
j=0;
while (equil(0)>equilsup && ((REAL) j)<smaxiter) {
setconstants();
if (plotflag) {
#ifdef IRIS
zoom();
#endif
foamplot(0,0);
}
j++;
}
/*
* Get a new step size `dphi' before continuing the loop...
*/
dphi=(1.0-phi)*PHIFRACTION;
if (fabs(phi-phi0)<fabs(dphi)) dphi=phi-phi0;
}
}
else {
/*
* Case 2: Increase the area fraction up to `phi0'...
*/
/*
* Aim to change the area fraction in steps `dphi' which
* must not be overly large (because `phirelax()' cannot
* cope with large steps).
*/
dphi=(1.0-phi)*PHIFRACTION;
if (fabs(phi-phi0)<fabs(dphi)) dphi=phi0-phi;
while (fabs(dphi/phi) > areasup) {
/*
* Change the target areas of all the cells and recalculate
* `atot' and `phi' ( = current target for area fraction)
*/
atot=0.0;
for (ii=0; ii<nc; ii++) {
i=clist[ii];
darea[i] += (carea[i]+darea[i])*dphi/phi;
atot += carea[i]+darea[i];
}
for (ii=0; ii<nbub; ii++) {
i=bublist[ii];
darea[i] += (carea[i]+darea[i])*dphi/phi;
atot += carea[i]+darea[i];
}
phi=(atot)/(boxwid*boxhgt);
/*
* Actually change the area fraction of the network
* (by tweaking the curvature of the Plateau border arcs)
*
* ...and do it to a pretty high degree of accuracy (i.e. the parameter
* `areasup' is very small [or certainly ought to be] ) otherwise
* the equilibration would bomb out.
*/
phirelax(phi);
/*
* Call `equil()' to relax the position of the vertices...
*/
j=0;
while (equil(0)>equilsup && ((REAL) j)<smaxiter) {
setconstants();
if (plotflag) {
#ifdef IRIS
zoom();
#endif
foamplot(0,0);
}
j++;
}
/*
* Get a new step size `dphi' before continuing the loop...
*/
dphi=(1.0-phi)*PHIFRACTION;
if (fabs(phi-phi0)<fabs(dphi)) dphi=phi0-phi;
}
}
}
/*****************************************************************************
*** * * * * * * * * * * * * ***
*** * * * * * *P H I R E L A X ( ) * * * * * * ***
*** * * * * * * * * ***
*****************************************************************************
*
* Subroutine: phirelax(REAL phi)
*
* Arguments: phi = target value of the area fraction
*
* Return value: none
*
* Action: Relax the network till it reaches a volume fraction
* given by the target value `phi' (this is a bit of a
* misnomer since the network is not terribly relaxed by
* the end of this routine).
*
* It operates by changing the pressure of the Plateau
* borders, thereby effectively changing the area in the
* cells. Note that since the cell areas are changed
* merely by tweaking the curvature of the Plateau border
* arcs, this routine is only able to change `phi' by a
* fairly small amount.
*
*****************************************************************************/
void phirelax(phi)
REAL phi;
{
short i, ii, b;
REAL phi1, phi2, dphi, dphidbp, delp, delp2, dbp, r;
boolean found[MBORD], arcbrk;
void incbp(), bordpop();
REAL phifn(), fsign(), bordarea();
delp=pressuredelta; delp2=delp/2.0;
dphi=phi-phifn();
/*
* Essentially this loop tries to alter the area fraction
* so that it equals `phi'. It does this by calculating
* the derivative \delta\phi / \delta bp and using this to
* guess an amount by which the border pressure (= bp) must
* be changed.
*
* It's a wee bit crude (in fact for *large* Plateau borders it is not all
* that successful either --> significant bug (I promise I'll fix it!) )
*/
while (fabs(dphi/phi) > areasup) {
incbp(-delp2); phi1=phifn();
incbp(delp); phi2=phifn();
incbp(-delp2);
/* Possibly include damping for this step =0.5? */
dphidbp=0.5*(phi2-phi1)/delp;
dbp= PHIDAMP*dphi/dphidbp;
if (fabs(dbp)>fabs(0.1*bpav)) dbp=fsign(dbp)*fabs(0.1*bpav);
incbp(dbp);
dphi=phi-phifn();
}
/* correct the bubble areas */
for (ii=0; ii<nbub; ii++) {
i=bublist[ii];
r=BRADIUS(cp[i],bpav);
carea[i]= PI*r*r; darea[i]=0.0;
}
/* correct the border areas */
for (i=0; i<onb; i++) found[i]=FALSE;
for (ii=0; ii<nb; ii++) {
i=vlist[ii];
if (!found[b=cadj[i][0]]) {
found[b]=TRUE;
barea[b]=bordarea(i,&arcbrk);
if (arcbrk) {
bordpop(i,pressuredelta/2.0);
barea[b]=bordarea(i,&arcbrk);
}
}
}
/* ...but don't worry about correcting the cell areas,
* that business is taken care of in the routine `makefraction()'
*/
}
/*****************************************************************************
*** * * * * * * * * * * * * ***
*** * * * * * * I N C B P ( ) * * * * * * ***
*** * * * * * * * * ***
*****************************************************************************
*
* Subroutine: incbp(REAL dbp)
*
* Arguments: dbp = increment to the Plateau border pressure
*
* Return value: none
*
* Action: Increments the Plateau border pressure by an amount
* `dbp'.
*
*****************************************************************************/
void incbp(dbp)
REAL dbp;
{
short i, ii;
for (ii=0; ii<nb; ii++) {
i=blist[ii];
bp[i] += dbp;
}
bpav += dbp;
/*
* This is a tricky point:
*
* In order to avoid implementing isolated bubbles, the program allows
* single sided cells to exist (i.e. the cells are almost a complete circle)
* which just `kiss' their neighbours. These cells are *not* able to change
* their curvature in reaction to a change in Plateau border pressure so
* their internal pressure has to track changes in Plateau border pressure.
*/
for (ii=0; ii<nc; ii++) {
i=clist[ii];
if (ncsides[i]==1) cp[i] += dbp;
}
}
/*****************************************************************************
*** * * * * * * * * * * * * ***
*** * * * * * * P H I F N ( ) * * * * * * ***
*** * * * * * * * * ***
*****************************************************************************
*
* Subroutine: REAL phifn()
*
* Arguments: none
*
* Return value: Returns the area fraction \phi as calculated explicitly
*
* Action: (same as return value)
*
*****************************************************************************/
REAL phifn()
{
short i, ii, k, c;
REAL atot, r, cellarea(), acell;
boolean found[MCELL], arcbrk;
void cellpop();
/*
* Calculate the area fraction by adding together the areas of all of the
* cells (calculated explicitly) and then dividing by the total area of the
* network (which is given by boxwid*boxhgt).
*/
atot=0.0;
for (ii=0; ii<nc; ii++) { found[ii]=FALSE; }
for (ii=0; ii<nv; ii++) {
i=vlist[ii];
for (k=1; k<3; k++) {
if (!found[c=cadj[i][k]]) {
found[c]=TRUE;
acell=cellarea(i,k,&arcbrk);
if (arcbrk) {
cellpop(i,k,pressuredelta);
acell=cellarea(i,k,&arcbrk);
}
atot += acell;
}
}
}
for (ii=0; ii<nbub; ii++) {
i=bublist[ii];
r=BRADIUS(cp[i],bpav);
atot += PI*r*r;
}
return (atot/(boxwid*boxhgt));
}