Initial commit of the Fortran-90 version of the Fractal Realizer.
4 ! fractal generator adapted from algorithm MidPointFM2D in the
5 ! Science of Fractal Images, M.F. Barnsley, R. L. Devaney
6 ! B. B. Mandelbrot, H.-O. Peitgen, D. Saupe, and R. F. Voss
9 ! this program modified to combine multiple fractal topographies
10 ! then normalize them relative to each other,
11 ! and perform multiple horizontal slices
12 ! to obtain requested p values for each habitat
13 ! in a new synthetic realization of the landscape
23 integer(i4) :: P(maxN*maxN,0:maxsp+3)
24 real(r4) :: X(0:maxN,0:maxN)
25 real(r4) :: prob(0:maxsp)
28 integer(i4) :: igreatest
29 integer(i4) :: hslice(0:maxsp)
30 real(r4) :: elev(maxN*maxN)
31 real(r4) :: H(maxN,maxsp)
32 integer(i4) :: II(0:maxN,0:maxN)
33 integer(i4) :: kcnt(0:maxsp)
34 integer(i4) :: ties(maxsp)
40 real(r4) :: xmin, xmax, xmean, xss
45 integer(i4) :: maxlevel
46 integer(i4) :: numpainted
47 integer(i4) :: numtied
48 integer(i4) :: numblank
49 integer(i4) :: ihighest
50 integer(i4) :: ibiggest
54 integer(i4) :: isum, jsum
57 integer(i4) :: i, j, k, l, m ! loop indices
60 integer :: useed ! user seed value
61 integer :: rsize ! length of array of seeds
62 integer :: ierr ! error
63 integer, allocatable :: iseed(:) ! array of random number seeds
64 integer(i4) :: idispvec(0:maxN*maxN)
65 character (len=1) :: ans
66 character (len=28) :: maptitle
67 character (len=60) :: mapfile
68 character (len=10) :: mapcolor
69 character (len=40) :: fmt ! For dynamic format strings in gfortran
70 logical :: addition, wrap, gradient, slice, invert
71 logical :: grassout, xpmout, probout, vizout
72 logical :: constraint(0:maxsp)
74 ! write execution script for next run
75 open (9, file='input.scr',status='unknown')
78 ! enter random number seed
80 196 format (t10,'Do you want to enter a random number seed <Y>', &
81 /t12,' or use the system clock? [clock]')
84 if (ans .eq. 'Y' .or. ans .eq. 'y') then
86 197 format (a1,t20,"(enter seed or clock?)")
88 100 format (t10,'Enter random number seed ')
91 101 format (i12,t20,"(random number seed)")
93 21 useed = int(time8(),kind(useed))
94 if (useed .eq. 0) then
95 print *, "useed was zero."
99 298 format (t15,'Random number seed from system clock.'/)
100 write (9,29) ans, useed
101 29 format (a1,t20,"(random seed from clock = ",i12,")")
103 ! Set the random number seed
104 call random_seed(size=rsize)
105 allocate(iseed(rsize),stat=ierr)
107 print *,'Error allocating iseed(rsize)'
110 iseed(1:rsize) = useed
111 call random_seed(put=iseed)
114 1017 format (t15,'Random number seed = ',i12/)
118 512 format (t10,'Do you want to visualize', &
119 /t12, ' the synthetic landscape? <Y,N>')
123 57 format (a1,t20,"(visualize the landscape?)")
124 if (ans .eq. 'y' .or. ans .eq. 'Y') then
131 225 format (t10,'How many levels? (map is 2**levels on a side)')
136 numcells = (N+1)*(N+1)
137 if (N .gt. maxN) goto 1
138 write (9,102) maxlevel
139 102 format (i3,t20,"(Number of levels)")
142 114 format (t10,'Highest data category (excluding no-data)', &
143 /t12,' in the realized synthetic landscape?')
146 199 format (i3,t20,"(highest data category)")
149 232 format (t10,'Will you supply external probability maps', &
150 /t12,' for any of these categories?')
154 161 format (a1,t20,"(supply external prob maps?)")
157 constraint(j) = .false.
161 if (ans .eq. 'Y' .or. ans .eq. 'y') then
164 134 format (t10,'For how many categories in the synthetic', &
165 ' landscape',/t12,' will you supply external probability', &
168 write (9,189) isupply
169 189 format (i3,t20,"(number of external prob maps)")
173 216 format (t10,'Constrain which map category?')
176 799 format (i3,t20,"(constrain which category?)")
177 ! set constraint flag for this category
178 constraint(k) = .true.
181 220 format (t10,'Enter name of input map file (integer*4, ', &
182 /t12,' delimited by single spaces): ')
186 2030 format (t15,'Input map name: ',a60/)
187 write (9,231) mapfile
191 144 format (t10, 'Invert probabilities (i.e., DEM)? <Y,N>')
195 327 format (a1,t20,"(invert probabilities?)")
196 if (ans .eq. 'y' .or. ans .eq. 'Y') then
202 ! load constraint maps in proper column of P array
203 ! invert probabilities if necessary, i.e., a DEM
204 Call InputMap(mapfile,P,N,k,invert)
211 if (.not. constraint(iz)) then
214 159 format (t10,'Input value of H for level ',i3,', category ',i3)
217 write (9,155) H(i,iz), i, iz
218 155 format (f4.2,t20,"(value of H for level ",i2,&
219 ", category", i3,")")
220 if (H(i,iz) .lt. 0.0 .or. H(i,iz) .gt. 1.0) goto 118
229 116 format (t10,'Probability for habitat ',i3)
231 if (prob(i) .lt. 0.0) goto 115
232 if (prob(i) .gt. 1.0) goto 115
233 ssum = ssum + prob(i)
234 if (ssum .gt. 1.0000) then
235 print *, 'Total probability exceeds 1.0 - Re-enter'
236 ssum = ssum - prob(i)
239 write (9,151) prob(i), i
240 151 format (f6.5,t20,"(probability of habitat type", i2,")")
243 ! find greatest non-constraint p to make background
247 if (.not. constraint(i)) then
248 if (prob(i) .gt. ztemp) then
251 !print *, 'at i of ',i ,'new greatest is ', igreatest
256 ! zero category by difference
258 if (prob(0) .lt. 0.00001) prob(0) = 0.0
259 print *, 'prob(0) is ', prob(0)
261 ! print *, 'igreatest is ', igreatest
262 if (prob(0) .gt. prob(igreatest)) igreatest = 0
263 print *, 'Cat ', igreatest,' will be calculated by absence'
265 ! The Fractal Realizer assumes that the user-requested category
266 ! with the greatest coverage on the landscape (the highest requested p)
267 ! is the background or matrix category. In order to give the other
268 ! categories the greatest freedom for fractal tuning and to minimize
269 ! contention ties, this majority background color is computed by absence,
270 ! and all other categories are reclassed. Furthermore, categories which
271 ! are requested but for which the requested p = 0.0 are not actually
274 ! calculate reclassed categories
277 ! if (i .eq. igreatest) then
279 ! print *, 'Cat ', i,' reassigned to background'
282 ! if (prob(i) .eq. 0.0) then
283 ! print *, 'Cat ', i,' requested but not used - skipping'
287 ! ireclass(ihabs) = i
288 ! print *, 'cat ', i,' will now be cat ', ihabs
294 ! print 2002, ireclass(i), i, prob(ireclass(i))
295 !2002 format ('Original category ', i2, ' re-mapped to ', &
296 ! i2, ' with requested probability of ', f6.4)
300 212 format (t10,'Generate GRASS r.in.ascii file? <Y,N>')
304 27 format (a1,t20,"(generate GRASS input file?)")
305 if (ans .eq. 'y' .or. ans .eq. 'Y') then
312 122 format (t10,'Generate xpm file of synthetic landscape? <Y,N>')
316 124 format (a1,t20,"(xpm file of realized landscape?)")
317 if (ans .eq. 'y' .or. ans .eq. 'Y') then
324 322 format (t10,'Generate xpm file of fractal probability' &
325 ' landscapes? <Y,N>')
329 324 format (a1,t20,"(xpm file of probability landscapes?)")
330 if (ans .eq. 'y' .or. ans .eq. 'Y') then
336 ! *****************************************************************
337 ! fill P array with a separate fractal probability map
338 ! for each desired habitat in the landscape
340 if (constraint(iz)) goto 22
342 ! don't bother if igreatest or no cells requested of this category
343 if (prob(iz) .eq. 0.0 .or. iz .eq. igreatest) then
351 !102 format (t10,'Input the value for sigma')
355 103 format (t10,'Input the threshold for detection (xlow) ')
359 125 format (f12.6,t20,"(threshold for detection (xlow))")
360 if (xlow .eq. 0) xlow = -1e30
363 104 format (t10,'Wrap? <Y,N>')
367 198 format (a1,t20,"(wrap?)")
368 if (ans .eq. 'y' .or. ans .eq. 'Y') then
374 ! no gradient possible with wrap
377 106 format (t10,'Gradient? <Y,N>')
381 148 format (a1,t20,"(gradient?)")
382 if (ans .eq. 'y' .or. ans .eq. 'Y') then
386 1850 format (t10,'Gradient: Initial values for four map corners')
388 1851 format (t10,'Northeast? ')
390 print 1852, northeast
391 1852 format (5x,g12.6)
392 write (9,135) northeast
393 135 format (f12.6,t20,"(Gradient: northeast)")
396 1853 format (t10,'Southeast? ')
398 print 1852, southeast
399 write (9,136) southeast
400 136 format (f12.6,t20,"(Gradient: southeast)")
403 1854 format (t10,'Southwest? ')
405 print 1852, southwest
406 write (9,137) southwest
407 137 format (f12.6,t20,"(Gradient: southwest)")
410 1855 format (t10,'Northwest? ')
412 print 1852, northwest
413 write (9,138) northwest
414 138 format (f12.6,t20,"(Gradient: northwest)")
420 end if !wrap = .false.
423 !111 format (t10,'Slice into discrete habitats? <Y,N>')
426 ! if (ans .eq. 'y' .or. ans .eq. 'Y') then
435 ! 104 format (t10,'Addition <Y,N>?')
438 ! if (ans .eq. 'y' .or. ans .eq. 'Y') then
445 ! call 2d multi-fractal generator
446 print *,"Calling fractal generator for category ", iz
447 call mpfm2d(X, maxlevel, sigma, H, addition, wrap, gradient, iz)
449 print *, "fractal generated"
456 ! obtain xmin and xmax for range normalization
457 ! calculate initial raw statistics
461 if (X(i,j) .lt. xmin) xmin = X(i,j)
462 if (X(i,j) .gt. xmax) xmax = X(i,j)
463 ! xmean = xmean + X(i,j)
464 ! xss = xss + X(i,j)*X(i,j)
468 ! xmean = xmean / icnt
469 ! print 200, xmean, xss, xmin, xmax
470 !200 format (/t10,'Hfract Summary'/ &
471 ! t10,'Mean = ',g12.6 &
472 ! /t10,'Sum Sq. = ',g12.6 &
473 ! /t10,'Minimum = ',g12.6 &
474 ! /t10,'Maximum = ',g12.6)
476 ! rescale and normalize fractal map between 0 and 32767, inclusive
482 P(iv,iz) = ((X(i,j) - xmin)/range1) * 32767
485 ! write(10,*) P(iv,iz)
488 print*,'done normalizing now'
490 !c write GRASS ascii map
492 !791 format ('north: ',i4)
494 !792 format ('south: 0')
496 !793 format ('east: ',i4)
498 !794 format ('west: 0')
500 !795 format ('rows: ',i4)
502 !796 format ('cols: ',i4)
504 ! write(10,*) (P((i*(N+1))+j+1,iz), j=0,N)
507 ! end of iz loop over all landscape categories in synthetic map
510 ! **********************************************************************
512 ! ihabs fractal maps now installed in P matrix:
521 ! mtsplit =>|---------------|
533 ! itiedsplit =>|---------------|
539 ! numcells =>|_______________|
541 ! ihabs+1 column carries x-coord of cell
542 ! ihabs+2 column carries y-coord of cell
543 ! ihabs+3 column carries number of ties for this cell
546 ! initialize II array with background value for re-use as output map
549 ! set paint thresholds
550 print *,"Calculating paint thresholds"
551 do i = 0,ihabs ! over all map categories
553 !c don't bother if no cells requested of this cat
554 if (prob(i) .ne. 0.0) then
557 ! print *, "numcells is ", numcells
558 ! print *, "istart is ", istart
559 ! print *, "i is ", i
560 ! Call HeapSort(P,numcells,istart,i) ! sort P matrix by ith column
563 ! next category to be painted goes to single vector for sorting
569 ! call special vector version of Heapsort
571 Call HS2(idispvec,numcells+1,istart)
575 ! print *, i, k, idispvec(k)
578 ! set paint threshold for this map category
579 hslice(i) = idispvec(numcells - (int((prob(i) * numcells)+.499)))
580 ! for absolute constraint maps
581 if (hslice(i) .eq. 32767 .and. constraint(i)) hslice(i) = 32766
582 print *, "trying to assign ", int((prob(i) * numcells)+.499), &
583 " cells for category", i
584 jsum = jsum + int((prob(i) * numcells)+.499)
586 33 end do ! over all map categories
588 print*, 'trying to assign a total of', jsum,' cells of', numcells, &
591 !c set paint threshold for this map category
592 ! hslice(i) = P(numcells - (int((prob(i) * numcells)+.499)),i)
593 ! print *, "trying to assign ", int((prob(i) * numcells)+.499), &
594 ! " cells for category", i
595 ! end do ! over all map categories
597 ! dump hslice array for checking
598 print *, 'horizontal slices at these elevations:'
600 print *, i, hslice(i)
603 ! write XPM file of fractal probability terrain aspect
606 if (.not. (constraint(iz) .or. prob(iz) .eq. 0.0 .or. &
607 iz .eq. igreatest)) then
608 Call XPMRelief(P,iz,hslice(iz))
618 print *,"Beginning tie resolution process"
619 do l = 1, numcells ! start at top of P matrix
621 do j = 0, ihabs ! over all map categories
622 ! probably don't need to do this if prob(j) .eq. 0.0
623 if (.not. (prob(j) .eq. 0.0 .or. j .eq. igreatest)) then
625 ! if this cell is painted this category
626 if ( P(l,j) .gt. hslice(j) ) then
627 ! if ( P(l,j) .ge. hslice(j) ) then
629 ! count the multiple assignments
630 P(l,ihabs+3) = P(l,ihabs+3) + 1
632 ! find the winner category for this cell
633 ! winner category has the highest probability surface
634 if ( P(l,j) .gt. idummy ) then
636 idummy = P(l,ihighest)
639 end if ! this cell painted this category
642 end do ! over all map categories
643 ! print *, "highest for cell ", l," was category", ihighest
645 ! keep count of each type of cell for displacement into
647 ! if singly-painted or currently tied, paint outmap with ihighest
648 if ( P(l,ihabs+3) .eq. 1) then
649 ! paint this cell with the winning category
650 ! print *, "painting uncontested cell", P(l,ihabs+1), &
651 ! P(l,ihabs+2)," with cat", ihighest
653 numpainted = numpainted + 1
654 II( P(l,ihabs+1),P(l,ihabs+2) ) = ihighest
655 else if ( P(l,ihabs+3) .eq. 0) then
656 numblank = numblank + 1
658 numtied = numtied + 1
659 ! print *, "painting tied cell", P(l,ihabs+1),P(l,ihabs+2), &
660 ! " with winning cat", ihighest
661 II( P(l,ihabs+1),P(l,ihabs+2) ) = ihighest
666 ! at this point, II array has all winners and uncontested
669 ! sort P array into 3 sections by number of assignments
670 ! ascending sort results in empty, singly-painted, and
672 print *,"Preparing to sort ties for resolution"
674 ! sort by ties column
676 Call HeapSort(P,numcells,istart,ihabs+3)
677 ! print *, "got back from HeapSort"
679 ! calculate pointers to section breaks
681 itiedsplit = numblank + numpainted
685 print *, "numblank is ", numblank
686 print *, "numtied is ", numtied
687 print *, "itiedsplit is ", itiedsplit
688 print *, "numpainted is ", numpainted
689 print *, "mtresolved and mtsplit are ", mtresolved
691 if (numtied .gt. numblank) print*, 'WARNING: More tied cells', &
692 ' than leftover blank cells to use for tie resolution!'
694 ! sum multiwayness of ties and compare to number of empty cells
695 do m = itiedsplit+1, numcells
696 isum = isum + ( P(m,ihabs+3) - 1 )
698 print *, "sum of multiwayness of ties is ", isum
699 if (isum .gt. numblank) print *, 'Warning: cells are tied more', &
700 ' ways than there are blank cells to assign!'
704 ! sort ties into priority order for resolution
705 ! by calculating and sorting on summed elevation
706 ! for all tied categories
708 do m = itiedsplit+1, numcells ! over all tied
711 do k = 0, ihabs ! over all categories
713 ! probably not necessary if prob(k) .eq. 0
714 if (.not. (prob(k) .eq. 0.0 .or. k .eq. igreatest)) then
715 ! if this cell is painted this category
716 if ( P(m,k) .gt. hslice(k) ) then
717 ! if ( P(m,k) .ge. hslice(k) ) then
718 kount = kount + 1 ! number of ties for this cell
719 ties(kount) = k ! keep categories of ties
727 zmean = zmean + P(m,ties(k))
729 ! P(m,ihabs+3) = zmean/kount
730 ! try weighting priority by simple sum, not average
731 ! therefore, max sum = (ihabs-1) * 32767
732 ! rescale as proportion of 32767 for integer*4 array cell
733 P(m,ihabs+3) = zmean/(ihabs-1)
737 ! sort ties by mean priority
738 Call HeapSort(P,numtied,itiedsplit+1,ihabs+3)
740 ! save min and max tie priorities for gray levels in XPMTies
741 maxgray = P(numcells,ihabs+3)
742 print*, "maxgray is ", maxgray
744 ! generate xpm picture of tied cells
745 ! colored by priority gray shades
749 ! start at bottom of list (highest priority ties)
750 do m = numcells, itiedsplit+1, -1 ! over all tied
753 do k = 0, ihabs ! over all categories
755 ! probably not necessary if prob(k) .eq. 0
756 if (.not. (prob(k) .eq. 0.0 .or. k .eq. igreatest)) then
757 ! if this cell is painted this category
758 if ( P(m,k) .gt. hslice(k) ) then
759 ! if ( P(m,k) .ge. hslice(k) ) then
760 kount = kount + 1 ! number of ties for this cell
761 ties(kount) = k ! keep categories of ties
762 ! save most likely category for this cell
763 if ( P(m,k) .gt. idummy ) then
765 idummy = P(m,ihighest)
773 ! over all tied categories that are not the winner
774 ! (which has already been painted)
775 ! we need an empty cell -
776 ! search the empty cell list by this cat to find next
777 ! most likely available empty cell
779 ! empty cell list will be searched once for each tie category
780 ! except the winning category
782 ! print *, "deciding among ", kount, " ties for cell ", m
783 do k = 1, kount ! over all ties for this cell
784 if ( ties(k) .ne. ihighest ) then ! don't re-do the winner
785 ! print *, ties(k), " was a tied category for cell ", m
790 if (P(i,ties(k)) .gt. idummy) then
792 idummy = P(i,ties(k))
796 Call Interchange(P,ibiggest,mtresolved)
799 ! Call HeapSort(P,mtresolved,istart,ties(k))
801 ! now mtresolved points to highest
802 ! next available empty cell of category ties(k)
804 ! print *, "painting empty cell", mtresolved," at coords ", &
805 ! P(mtresolved,ihabs+1), P(mtresolved,ihabs+2)," with prob ", &
806 ! P(mtresolved,ties(k))," with cat", ties(k), &
807 ! " for tie at cell", m
808 II( P(mtresolved,ihabs+1),P(mtresolved,ihabs+2) ) = ties(k)
810 mtresolved = mtresolved - 1
813 992 end do ! over all ties for this cell
814 ! print *, "resolving ties at cell ", m
816 end do ! over all tied cells
818 !**********************************************************************
823 ! generate xpm picture of tied cells
824 ! colored by priority gray shades
825 ! and used blank cells colored in yellow
829 ! set background category and
830 ! perform summary of realized map
833 if (II(i,j) .eq. 32767) II(i,j) = igreatest
834 kcnt(II(i,j)) = kcnt(II(i,j)) + 1
835 ! write(12,*) II(i,j)
840 ! write GRASS ascii map
843 91 format ('north: ',i4)
845 92 format ('south: 0')
847 93 format ('east: ',i4)
849 94 format ('west: 0')
851 95 format ('rows: ',i4)
853 96 format ('cols: ',i4)
854 write(fmt,'("(",I0,"(i5,1x))")') j
856 ! write(10,47) (II(i,j), j=0,N)
857 write(10,fmt) (II(j,i), j=0,N)
858 ! write(10,47) (II(j,i), j=0,N)
859 !47 format (<j>(i5,1x))
863 ! write final map to xpm file
864 if (xpmout) Call XPMMap(N,II)
867 299 format (/t10,'Actual Map Summary:'/t12,'Habitat',5x, &
868 'P',3x,'Real Cells',3x,'Real P')
871 pfract = real(kcnt(i),kind(pfract)) / real(numcells,kind(pfract))
872 print 300, i, prob(i), kcnt(i), pfract
873 300 format (t10, i6, 4x, f6.5, 2x, i6, 2x, f6.5)
876 !**********************************************************************
878 ! visualize the synthetic landscape
881 ! print final map to screen
884 idispvec(j) = II(i,j)
886 ! print 199, (idispvec(j), j=0,N)
887 !199 format (<N+1>(i1, 1x))
890 ! print current state of P array
894 mapcolor = 'bobs.cmap\0'
895 maptitle = 'Fractal Landscape Realizer \0'
900 ! build display vector
901 ! make small maps more visible by repeating cells and lines
909 ! idispvec(k)=II(i,j)
912 ! end do ! repeating cells in this row
913 end do ! all cells in this row
916 ! if (irepeat .ge. 2) then
917 ! do jj = 1,irepeat-1
918 ! do kk = kstart, kend
919 ! idispvec(k) = idispvec(kk)
921 ! end do ! dup as many times as necessary
922 ! end do ! over all repeated lines
927 !c adjust rows and columns by multiplier
928 ! isize = (N+1) * irepeat
929 ! jsize = (N+1) * irepeat
930 ! print *, isize, jsize
931 ! ierr=DrawPixmap(ipixid, isize, jsize, idtype, idispvec,
932 ! ierr=DrawPixmap(ipixid,N+1,N+1,idtype,idispvec,idumm,mapcolor, &
934 ! print *,'ierr is', ierr
935 ! print *, 'done visualizing'
938 end if ! if visualizing landscape
941 ! end program MidPtFM2d