Viewing contents of file '../idllib/astron/contrib/varosi/vlibm/allpro/fractal_cloud.pro'
;+
; NAME:
; FRACTAL_CLOUD
; PURPOSE:
;
; Generate a fractal cloud as a density distribution map,
; returning a 3D array (1D or 2D if requested). The density map
; is generated by binning points generated by a randomn recursive
; fractal algorithm, as described by Elmegreen, 1997, ApJ 477: 196-203.
;
; CALLING:
;
; dens_map = Fractal_Cloud( NDIM=, NLEVELS=, NP_FACTOR=, LSCALE=, $
; SIZE_MAP=, /VERBOSE, /DISPLAY )
;
; KEYWORD INPUTS:
;
; NDIM = dimension of space in which to embed fractal, default is 3.
;
; NLEVELS = number of LEVELS in fractal heiarchy, no default, must give.
;
; NP_FACTOR = integer factor (>1) setting the number of random points
; generated at each new level around and replacing each single
; point of previous level, default is 12.
; Total number of random points generated = NP_FACTOR^NLEVELS.
;
; LSCALE = the spatial scale divisor from one level to next.
; The spatial extent of new NP_FACTOR random points at next level
; is decreased by divisor LSCALE from previous level,
; thus spatial scale at level N = LSCALE^(-N).
; Can be scalar or vector with NDIM elements, except
; in case of spherical symmetry only scalar is used. Default=3.
;
; SIZE_MAP = dimensions (resolution in pixels) of output density map,
; default is [128,128,128].
;
; /SPHERICAL : generate points with spherical symmetry instead of cubic.
;
; RADIUS_EXP = exponent applied to random radii, for /SPHERICAL case only,
; default = 1/3 (for uniform in 3D sphere).
;
; /SAVE_RS : save the currently generated random number sequences into
; IDL/XDR save files (in current directory) which can then be
; later restored and used to obtain the same fractal realization
; with different dimension (by changing LSCALE) or resolution.
;
; DIR_SAVED_RS = optional string specifying directory containing IDL/XDR
; save files in which previously generated random numbers are stored.
; For UNIX, must use a "/" character at then end of dir string.
;
; RANGE_XYZ = float array of dimensions (2,NDIM) specifying min-max
; range of each dimension for binning the points. Default range
; is a sphere which contains all points.
;
; /VERBOSE
; /DISPLAY
;
; KEYWORD OUTPUTS:
;
; RANGE_XYZ = min-max range used for each dimension in binning the points.
;
; DHISTOGRAM = histogram of the density map.
; AVG_DENS = average density of the cloud pixels/voxels, excluding ICM.
;
; OUTPUT:
; Function returns density distribution map,
; an integer array of the requested dimension and size.
;
; EXTERNAL CALLS:
; function Bin3D
; function Bin2D
; function Histo
; function VarType
; function trapez
; pro get_window
; pro tvs
; PROCEDURE:
; Use the uniform random number generator to make points at each Level,
; which are rescaled in a descending heirarchy, a modified version of
; the algorithm described by Elmegreen, 1997, ApJ 477: 196-203.
; The final NP_FACTOR^NLEVEL points are binned into a density map array,
; but not all at once, just one group at a time, looping over NP_FACTOR.
; HISTORY:
; Written: Frank Varosi, HSTX @ NASA/GSFC, 1997.
;-
function Fractal_Cloud, NDIM=Ndim, NLEVELS=NLev, NP_FACTOR=Npf, LSCALE=Lscale, $
DIR_SAVED_RS=dirseq, SPHERICAL=spheric, SIZE_MAP=nvox, $
VERBOSE=verbose, DISPLAY=display, LOG=minLog, $
DHISTOGRAM=dmh, AVG_DENS=avg_dens, RANGE_XYZ=rxyz, $
RADIUS_EXP=rexp, SAVE_RS=save_rs
if N_elements( NLev ) ne 1 then begin
print,"syntax: dens_map = Fractal_Cloud( NLEVEL=, NP_FACTOR=, LSCAL=,$"
print," NDIM=, SIZE_MAP=, /VERBOSE, /DISPLAY )"
return,0
endif
if N_elements( Npf ) ne 1 then Npf = 12
if N_elements( Ndim ) ne 1 then Ndim = 3
if keyword_set( spheric ) then begin
if N_elements( Lscale ) gt 1 then Lscale = Lscale(0)
if N_elements( Lscale ) ne 1 then Lscale = 3
if N_elements( rexp ) ne 1 then rexp = 1./3.
Ndim = 3
endif else begin
if N_elements( Lscale ) eq 1 then Lscale = replicate( Lscale, 3 )
if N_elements( Lscale ) LE 0 then Lscale = replicate( 3.0, 3 )
endelse
Lscale = float( Lscale )
slice = 0.01
if VarType( dirseq ) eq "STRING" then begin
restore, VERB=keyword_set( verbose ), dirseq + "RanSeq_L=1_k=00.idl"
szr = size( ranseq )
if szr(1) LT szr(2) then ranseq = transpose( ranseq )
szr = size( ranseq )
Npf = szr(1)
Ndim = szr(2)
if keyword_set( verbose ) then help, ranseq, Level
restrseq = 1
if keyword_set( spheric ) and (szr(2) ne 3) then begin
message,"need 3D ran.seq. for spherical option",/INFO
help, ranseq
return,0
endif
endif else begin
ranseq = randomu( seed, Npf, Ndim )
if keyword_set( save_rs ) then begin
Level = 1
save, ranseq, Level, FILE="RanSeq_L=1_k=00.idl",/VERB
endif
endelse
if keyword_set( spheric ) then begin
w = 2*ranseq(*,0)-1
c = sqrt( 1 - w*w )
a = !PI * (2*ranseq(*,1)-1)
xo = [ [ c * cos( a ) ],[ c * sin( a ) ],[ w ] ]
w=0 & c=0 & a=0
radii = ( ranseq(*,2)^rexp )/Lscale
for i=0,Ndim-1 do xo(*,i) = xo(*,i) * radii
endif else begin
xo = 2*( ranseq - 0.5 )
Lscale = Lscale(0:Ndim-1)
for i=0,Ndim-1 do xo(*,i) = xo(*,i)/Lscale(i)
endelse
if keyword_set( display ) then get_window,0,/show
D_cloud = aLog( Npf )/( total( aLog( Lscale ) )/N_elements( Lscale ) )
if keyword_set( verbose ) then begin
help, Npf, NLev, Ndim, rexp, D_cloud
print," Lscale:",Lscale
endif
for Lev = 2, NLev-1 do begin ;Loop over heirarchy of Levels:
szx = size( xo )
Nx = szx(1)
xn = fltarr( Nx, Npf, Ndim )
for k=0,Npf-1 do begin
if keyword_set( restrseq ) then begin
restore, dirseq + "RanSeq_L=" + strtrim( Lev, 2 ) $
+ "_k=" + strmid( strtrim( k+100, 2 ),1,2 ) + ".idl"
szr = size( ranseq )
if szr(1) LT szr(2) then ranseq = transpose( ranseq )
endif else begin
ranseq = randomu( seed, Nx, Ndim )
if keyword_set( save_rs ) then begin
Level = Lev
file = "RanSeq_L=" + strtrim( Level,2 )+"_k="+ $
strmid( strtrim( k+100, 2 ),1,2 )+".idl"
save, ranseq, Level, FILE=file
endif
endelse
if keyword_set( spheric ) then begin
w = 2*ranseq(*,0)-1
c = sqrt( 1 - w*w )
a = !PI * (2*ranseq(*,1)-1)
x = [ [ c * cos( a ) ],[ c * sin( a ) ],[ w ] ]
w=0 & c=0 & a=0
radii = ( ranseq(*,2)^rexp ) * Lscale^(-Lev)
for i=0,2 do x(*,i) = x(*,i) * radii
radii = 0
xn(*,k,*) = xo + x
x = 0
endif else for i=0,Ndim-1 do xn(*,k,i) = xo(*,i) + $
2*(ranseq(*,i) - 0.5) * Lscale(i)^(-Lev)
ranseq=0
endfor
xo = 0
xo = reform( xn, Nx*Npf, Ndim )
xn = 0
if keyword_set( verbose ) then help,Lev,xo
if keyword_set( display ) then begin
CASE Ndim OF
1: plot, hv, histo( xo, hv ), PS=10
2: plot, xo(*,0), xo(*,1), ps=3, XR=[-1,1], YR=[-1,1]
3: BEGIN
w = where( abs( xo(*,2) ) LE slice, nw )
if (nw GT 1) then plot, xo(w,0), xo(w,1), ps=3, $
XR=[-1,1], YR=[-1,1]
END
ENDCASE
empty
endif
endfor ;end Loop over Levels (except Last one).
radxo = max( vec_norm( reform( xo ) ) ) + min(Lscale)^(-Lev)
sz = size( rxyz )
if sz(0) ne 2 then begin
rxyz = fltarr( 2, Ndim )
for i=0,Ndim-1 do begin
rxyz(0,i) = min( xo(*,i), MAX=m )
rxyz(1,i) = m
endfor
if keyword_set( verbose ) then begin
print," range_xyz: "
print, rxyz
endif
for i=0,Ndim-1 do rxyz(*,i) = [-radxo,radxo]
endif
if keyword_set( verbose ) then begin
print," using range_xyz: "
print, rxyz
if sz(0) eq 2 then help, radxo
endif
if N_elements( nvox ) LE 0 then nvox = 128
if keyword_set( verbose ) then print," Nvox: ",nvox
xn = xo
for k=0,Npf-1 do begin ;Bin the final Level as points are generated:
if keyword_set( restrseq ) then begin
restore, dirseq + "RanSeq_L=" + strtrim( NLev, 2 ) $
+ "_k=" + strmid( strtrim( k+100, 2 ),1,2 ) + ".idl"
szr = size( ranseq )
if szr(1) LT szr(2) then ranseq = transpose( ranseq )
endif else begin
szx = size( xo )
ranseq = randomu( seed, szx(1), szx(2) )
if keyword_set( save_rs ) then begin
Level = NLev
file = "RanSeq_L=" + strtrim( Level,2 ) + "_k=" + $
strmid( strtrim( k+100, 2 ),1,2 ) + ".idl"
save, ranseq, Level, FILE=file
endif
endelse
if keyword_set( spheric ) then begin
w = 2*ranseq(*,0)-1
c = sqrt( 1 - w*w )
xn(*,2) = w
w = 0
a = !PI * (2*ranseq(*,1)-1)
xn(*,0) = c * cos( a )
xn(*,1) = c * sin( a )
c=0 & a=0
radii = ( ranseq(*,2)^rexp ) * Lscale^(-NLev)
for i=0,2 do xn(*,i) = xn(*,i) * radii
radii = 0
xn = xo + temporary( xn )
endif else for i=0,Ndim-1 do xn(*,i) = xo(*,i) + $
2*( ranseq(*,i)-0.5 )* Lscale(i)^(-NLev)
ranseq=0
CASE Ndim OF
3: dens_map = Bin3D( xn, NVOX=nvox, TYPE=2, VOXEL_DENS=dens_map, $
XRAN=rxyz(*,0), YRAN=rxyz(*,1), ZRAN=rxyz(*,2) )
2: dens_map = imagxy( xn, NPIX=nvox, TYPE=2, IMAGE_DENS=dens_map, $
XRAN=rxyz(*,0), YRAN=rxyz(*,1) )
1: BEGIN
if( k eq 0 ) then dens_map = Histo( xn, NBIN=nvox, $
MIN=rxyz(0), MAX=rxyz(1) ) $
else dens_map = dens_map + Histo( xn, NBIN=nvox, $
MIN=rxyz(0), MAX=rxyz(1) )
END
else: message,"NDIM = " + strtrim( Ndim, 2 ) + " not supported",/INFO
ENDCASE
if (k eq 0) and keyword_set( verbose ) then help,dens_map
if keyword_set( display ) or $
keyword_set( verbose ) or (k eq (Npf-1)) then begin
dmh = histogram( dens_map )
ff_icm = dmh(0)/total( dmh )
max_dens = N_elements( dmh )-1
hv = 1 + findgen( max_dens )
hd = dmh(1:*)
avg_dens = trapez( hd * hv, hv )/trapez( hd, hv )
if keyword_set( verbose ) then $
print, k, max_dens,"=max", avg_dens,"=avg", ff_icm,"=ff_icm", $
radxo - max( vec_norm( xn ) )
endif
if keyword_set( display ) then begin
CASE Ndim OF
3: BEGIN
for i=1,Ndim do begin
CASE i OF
1: image = reform( dens_map(nvox(0)/2,*,*) )
2: image = reform( dens_map(*,nvox(1)/2,*) )
3: image = dens_map(*,*,nvox(2)/2)
ENDCASE
get_window,i,/SHOW, XS=340, YS=256, $
XP=!DEVX-700, YP=!DEVY-290*i+55
tvs, image, LOG=minLog, COL=2,/ERAS
endfor
for i=1,Ndim do begin
get_window,10+i,/SHOW, XS=350, YS=256, $
XP=!DEVX-350, YP=!DEVY-290*i+55
tvs, total( dens_map, i ), COL=2, /ERAS, LOG=minLog
endfor
END
2: BEGIN
get_window,1,/SHOW, XS=640, YS=512
tvs, dens_map, COL=2, /ERAS, LOG=minLog
END
1: BEGIN
get_window,1,/SHOW
plot, dens_map, PS=10
END
else:
ENDCASE
get_window,0,/SHOW, XS=!DEVX-700, YS=!DEVX-700, $
XP=0, YP=!DEVY-!DEVX+700
plot, hv, hd > 0.1, /YTYPE, PS=10
oplot, hv, exp( -hv/avg_dens ) * hd(0) * exp(1/avg_dens),LINE=2
empty
endif
endfor
if keyword_set( verbose ) then begin
print," # points =", total( dens_map ), Long( Npf )^NLev
help, Npf, NLev, rexp
print," Lscale =",Lscale
cdmax = float( nvox(0) )^3
help, ff_icm, 1 - cdmax^((D_cloud/3)-1), D_cloud
endif
return, dens_map
end