Laplace- heat flow in a temperature gradient

You are to imagine a square-section rod of material has been suddenly placed in a hot furnace. The heat flows inward, raising the temperature. At first only the surface is hot, but the heat 'soaks' in and it starts to look like the image here. Visually blues 'feel' cold, and reds 'feel' hot, so a colour coding used as here greatly improves your appreciation of what is happening.

At steel works, such a furnace is therefore referred to as a 'soaking pit', where the ingot is raised to a uniform temperature ready to pass through the rolling mill.

It is particularly important to reach a known, uniform temperature throughout, as the properties of steel ( iron +carbon +other metals like Ni, Cr & Mo) are very temperature-dependent.

It is easy programmatically to express a range of numbers with colours spread between two limiting colours, say from red to bloe, by using lines like-

' x has values from x.min to x.max
range =x.max -x.min
c  =int( 256 *(x -x.min) /x.range)
col$ =str$( c) +" 0 " +str$( 255 -c)
#w.g1 "color "; col$
These colour ranges are pretty limiting however. To represent temperature with a suitable colour-range is done here by using an existing colour-bar as a look-up table. You can choose any that you like off the 'net, or create your own. Scale its length to whatever colour/value resolution you want. Just use your favoured painting package to scale it to say 256x10, if to be used in this program. Thanks to KCDan for the method used, which works in LB or JB. If for LB-only I'd use the API method, but there is little speed penalty. I could of couse have read the colour pixel values directly out of the colour-range bitmap, but I needed to display it anyway to show the scaling used! It is also a slight problem done by direct-reading that there are different BMP formats with the data at different positions. I could alternatively have written a sub-program to generate a string of data statements representing the appropriate RGB string for LB to use. You can then copy/paste these data statements into a program, but this makes it rather long and inscrutable, especially if using 256 or more colours....

******* N.B. Reminder. Be sure that you save as a 24 bit bmp if reading data from it directly, or expecting to load it with 'loadbmp'. On my machine 32 bit bitmaps can cause crashes, and may be non-standard. ******

This is the one I used here-

And some others... --- ---
Notice it can be helpful to have a different colour- eg black- to show clearly values of zero, and the intermediate black lines can also help to read off values.

Others I sometimes use are created with graduation tools, or copied from published images. Multiple-repeat scales give finer visual resolution, but at the expense of making colour values not represent a unique temperature. It may also be worth doing a log transform, since temperature gradients are often exponential. This emphasises and exaggerates changes near the bottom of a scale, but compresses values higher on the scale.

These colour look-ups may of course be of different length, to suit your scale intervals. You can give the user the opportunity to choose the range of choice, and display it beside the graph.


To make more attractive animations, the program stores the intermediate stages and uses ImageMagick to make the animated GIF seen here. Even with a fast machine it often takes too long to develop if watched as it is generated. By saving images & playing back with your choice of time interval you get also the ability to display in a web browser.

By altering the starting conditions, you can model instead a slab heated only on one edge, or a slab with a heat source at the centre. Higher resolutions are of course easy to do. The 40x40 gives adequate resolution, and by saving images at minute intervals but playing the animation at one frame per second works nicely.

The same simulation can be mdified to represent spread of disease; diffusion of gases; etc.


The heat flow is governed by Laplace's equation, that the second-order differentials of temperature along the two axes must sum to zero. This simplifies here to each element, over a small time-step, adopting the average of its neighbour's temperatures.

This could be implemented by two nested for-next loops visiting all points systematically. This would however requuire a second temporary grid to hold the new values, since each cell has to refer to its PRESENT four neighbours, rather than UPDATED neighbours. Instead I found it easier to update cells at random, which also make the visual display more interesting during the calculation stage. It is still rather slow, so I save every 10 seconds and make the animation frame-by-frame be played back at say 1 frame per sec.

The program saves the whole LB window & reloads it, thus avoiding the big redraw & memory penalty, at the same time as it saves the part representing the slab. The ImageMagick lines are remmed out, since I used the command line for this page.


The program and images are available as a downloadable zip file. LB program only, in current version ( I hope to enhance it further), Unzip it to a suitable folder. You'll need to create an empty folder 'screens' in the folder because I carelssly left it out of the zip! Run the bas file in LB. Remember you can re-run with the lin rather than log selected, and that an animated gif is generated ONLY if you have ImageMagick installed. If not, rem out the relevant lines. A later version should have buttons and menus to more easily select log/lin; to allow visual selection of the colour range to use; and to call for an animation to be generated. I hope....


WindowWidth = 544
WindowHeight =660

nomainwin

graphicbox #w.gb1, 20,  20, 500, 580

open "Laplace solution- slab heated at sides." for graphics_nsb_nf as #w

#w        "trapclose [quit]"

#w.gb1    "down ; fill lightgray"
loadbmp   "scr", "repeat.bmp"
#w.gb1    "drawbmp scr 110 20"
unloadbmp "scr"

#w.gb1 "up ; goto 45 125 ; down ; color black ; backcolor black ; boxfilled 435 515"
#w.gb1 "backcolor lightgray ; font courier_new 15 bold"

#w.gb1 "up ; goto 104 15 ; down"
#w.gb1 "\Hot . . . . . . . Cold"
#w.gb1 "up ; goto 104 50 ; down"
#w.gb1 "\.200 . 100 . 40 . 20 log scale."

#w.gb1 "up ; goto  94 74 ; down"
#w.gb1 "\255 . . .120 . . . 10 lin scale."

#w.gb1 "place 74 68 ; backcolor yellow ; circlefilled 6"

#w.gb1 "flush"

dim slab1( 40, 40)
dim colour$( 255)

global n: n =0

call getColValues
call boundary

timer 100, saveBmp

#w.gb1 "size 7"

for i =1 to 1000000
    x.rand =int( 41 *rnd( 1))
    y.rand =int( 41 *rnd( 1))

    if x.rand <>0 and x.rand <>40 and y.rand <>0 and y.rand <>40 then
        average =0
        average =average +slab1( x.rand -1, y.rand) +slab1( x.rand +1, y.rand) +slab1( x.rand, y.rand -1) +slab1( x.rand, y.rand +1)
        average =int( average /4)
        slab1( x.rand, y.rand) =average
    end if
    #w.gb1 "color "; colour$( int( 45 *( log( 1 +slab1( x.rand, y.rand)))))
    #w.gb1 "set "; 40 +x.rand *10; " "; 520 -y.rand *10
    scan
next i

timer 0

IM$ ="convert +matte -resize 205x205 -delay 200 screens\*.bmp anim.gif"
print IM$
'run "cmd.exe /c "; chr$( 34); IM$; chr$( 34), HIDE
        '   Give it 30 seconds to execute (may not be enough for large images)
'timer 30000, [on]
'    wait
'[on]
'    timer 0
wait

end

sub saveBmp
    timer 0
    #w.gb1     "getbmp sca  0   0 500 580"
    #w.gb1     "getbmp sc  35 115 410 410"
    name$      ="screens\slab1side" +right$( "000" +str$( n), 3) +".bmp"
    bmpsave    "sc", name$
    n =n +1
    timer 30000, saveBmp
    #w.gb1 "cls"
    #w.gb1     "drawbmp sca 0 0"
    unloadbmp  "sc"
    unloadbmp "sca"
end sub

Function KCGetPixel$( x, y)                             'x, y = window coordinates     Thanks KCDan!!
        #w.gb1,  "Getbmp pixel ";    110 +x; " "; 22 +y; " 1 1"      'A 1x1 bitmap, contains exactly 1 pixel
        #w.gb1 "color white ; set "; 110 +x; " "; 25 +y
        Bmpsave "pixel", "kcGetPixelData.datkc"         'Save that one pixel as a temporary bmp file
        Open "kcGetPixelData.datkc" for Binary as #kc   'Open that one pixel bmp file as a binary file
            Seek #kc, 66                                'Blue Info
            b =Asc( Input$( #kc, 1))                    'Blue
            Seek #kc, 67                                'Green Info
            g =Asc( Input$( #kc, 1))                    'Green
            Seek #kc, 68                                'Red Info
            r =Asc( Input$( #kc, 1))    'Red
        Close #kc
        Kill "kcGetPixelData.datkc"                     'Delete the temporary bmp file
        KCGetPixel$ =r; " "; g; " "; b                  'Place the values in a string
        'print KCGetPixel$
End Function

sub getColValues
    for v =1 to 256
        colour$( v -1) =KCGetPixel$( 256 -v, 5)
     next v
end sub


sub boundary
    for i =0 to 40
        slab1( i,  0) =255
        slab1( i, 40) =255
        slab1( 0,  i) =255
        slab1( 40, i) =255
    next i

    #w.gb1 "size 7"
    for x =0 to 40
        for y =0 to 40
            #w.gb1 "color "; colour$( int( 45 *( log( 1 +slab1( x, y)))))
            #w.gb1 "set "; 40 +x *10; " "; 520 -y *10
        next y
    next x
    call saveBmp
end sub

[quit]
close #w
end