program main !****************************************************************************** ! !! LCVT_DATASET computes a Latinized centroidal Voronoi Tessellation dataset. ! ! Discussion: ! ! The program is meant to be used interactively, or with ! a simple script file. ! ! Interaction is done through a series of keyword-driven commands. ! ! The list of commands can be gotten by typing "HELP". ! ! Briefly the user needs to specify the following: ! ! * The spatial dimension M ! (this step may be omitted if the initial points are read from a file) ! ! M = 2 ! ! * The number of points N ! (this step may be omitted if the initial points are read from a file) ! ! N = 100 ! ! * How the initial points are chosen: ! ! INITIALIZE file_name ! read the initial points from a file. ! (this implicitly sets the spatial dimension M ! and the number of points N) ! INITIALIZE RANDOM ! initialize with N points in M dimensions, ! generated by RANDOM_NUMBER (Fortran90 intrinsic); ! INITIALIZE UNIFORM ! initialize with N points in M dimensions, generated by UNIFORM; ! INITIALIZE HALTON ! initialize with N points in M dimensions, generated by HALTON; ! INITIALIZE GRID ! initialize with N points in M dimensions, generated by GRID; ! ! * How the sampling is done: ! ! SAMPLE = RANDOM ! generate sample points using RANDOM_NUMBER; ! SAMPLE = UNIFORM ! generate sample points using UNIFORM; ! SAMPLE = HALTON ! generate sample points using HALTON; ! SAMPLE = GRID ! generate sample points using GRID; ! ! * The number of sampling points to use: ! ! SAMPLE_NUM = 200000 ! ! * The number of CVT iterations to carry out. ! ! CVT_IT = 50 ! ! * The number of Latin Hypercube iterations to carry out. ! ! LATIN_IT = 5 ! ! In the most common case, the user might have a set of data points ! in a file, to be used as a starting point for the CVT iteration. ! ! Currently, the program assumes that the region is contained in ! the unit square. A subroutine allows the user to specify ! the exact description of the region (which could be a circle ! or a more complicated shape). Since this subroutine is included ! in the body of the code, the user must access the routine, ! modify it, and recompile to effect a change. ! ! Example: ! ! A reasonable set of input commands might be: ! ! # lcvt_01.inp ! # ! echo ! ! initialize data.txt ! print ! ! sample = uniform ! ! sample_num = 5000 ! cvt_it = 100 ! latin_it = 5 ! iterate ! print ! ! sample_num = 20000 ! cvt_it = 5 ! latin_it = 5 ! iterate ! print ! ! writelatin lcvt_01.txt ! quit ! ! Modified: ! ! 09 August 2005 ! ! Author: ! ! John Burkardt ! ! Parameters: ! ! real ( kind = 8 ) CELL_GENERATOR(M,N), the Voronoi cell generators ! of the Voronoi tessellation, as approximated by the CVT algorithm. This ! is the output quantity of most interest. ! ! integer ( kind = 4 ) CVT_IT, the number of iterations used in the Centroidal ! Voronoi Tesselation calculation. The default value is 10. ! ! integer ( kind = 4 ) LATIN_IT, the number of Latin hypercube iterations to carry out. ! This defaults to 5. ! ! integer ( kind = 4 ) M, the spatial dimension. ! ! integer ( kind = 4 ) N, the number of Voronoi cells to generate. ! ! integer ( kind = 4 ) SAMPLE_FUNCTION_CVT, specifies how the region is sampled: ! -1, the sampling function is RANDOM_NUMBER (Fortran90 intrinsic), ! 0, the sampling function is UNIFORM, ! 1, the sampling function is HALTON, ! 2, the sampling function is GRID. ! ! integer ( kind = 4 ) SAMPLE_FUNCTION_INIT, specifies how the initial ! generators are chosen: ! -1, the initialization function is RANDOM_NUMBER (Fortran90 intrinsic), ! 0, the initialization function is UNIFORM, ! 1, the initialization function is HALTON, ! 2, the initialization function is GRID, ! 3, the initial values are read in from a file. ! ! integer ( kind = 4 ) SAMPLE_NUM_CVT, the number of sampling points used on ! each CVT iteration. A typical value is 5000 * N. ! ! integer ( kind = 4 ) SEED, determines how to initialize the random number routine. ! If SEED is zero, then RANDOM_INITIALIZE will make up a seed ! from the current real time clock reading. ! If SEED is nonzero, then a reproducible sequence of random numbers ! defined by SEED will be chosen. ! By default, SEED initially has a value chosen by RANDOM_INITIALIZE, ! but the user can reset SEED at any time. ! implicit none real ( kind = 8 ), allocatable, dimension ( :, : ) :: cell_generator real ( kind = 8 ) change_l2 character ( len = 80 ) command character ( len = 80 ) command_cap integer ( kind = 4 ) cvt real ( kind = 8 ) cvt_energy real ( kind = 8 ), allocatable, dimension ( :, : ) :: cvt_generator integer ( kind = 4 ) :: cvt_it = 10 logical :: echo = .false. character ( len = 80 ) :: generator_file_in_name character ( len = 80 ) :: generator_file_out_name integer ( kind = 4 ) ierror integer ( kind = 4 ) j integer ( kind = 4 ) last integer ( kind = 4 ) latin real ( kind = 8 ) latin_energy integer ( kind = 4 ) :: latin_it = 5 integer ( kind = 4 ) m integer ( kind = 4 ) n logical reset integer ( kind = 4 ) :: sample_function_cvt = 0 integer ( kind = 4 ) :: sample_function_init = 0 integer ( kind = 4 ) sample_num_init integer ( kind = 4 ) :: sample_num_cvt = 10000 logical s_eqi integer ( kind = 4 ) seed integer ( kind = 4 ) seed_start integer ( kind = 4 ) :: step = 0 ! ! Print introduction and options. ! call timestamp ( ) write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'LCVT_DATASET (FORTRAN90 version)' write ( *, '(a)' ) ' Create "Latinized" CVT datasets.' write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' "CVT" stands for Centroidal Voronoi Tessellation.' write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' A CVT is defined by a region in M dimensions,' write ( *, '(a)' ) ' for which we have determined a set of N GENERATORS,' write ( *, '(a)' ) ' such that the generators are also the centroids' write ( *, '(a)' ) ' of the Voronoi regions they define.' write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' A "latinized" CVT starts with a CVT, and then' write ( *, '(a)' ) ' "gently" shifts the points so that they have the' write ( *, '(a)' ) ' Latin hypercube property, that is, the projections' write ( *, '(a)' ) ' of the shifted generators onto each coordinate' write ( *, '(a)' ) ' axis are evenly spaced.' write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Datasets like (1,1,1), (2,2,2), (3,3,3) ...' write ( *, '(a)' ) ' are very uninteresting examples of Latin hypercubes.' write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' We are hoping, by starting from a CVT, to guarantee' write ( *, '(a)' ) ' that the Latinized dataset has good dispersion ' write ( *, '(a)' ) ' in M dimensions, not just in each 1D projection!' ! ! Get a default starting seed. ! call get_seed ( seed_start ) seed = seed_start command = ' ' do if ( command(1:1) == '#' ) then else write ( *, '(a,$)' ) ':>' end if read ( *, '(a)' ) command command_cap = command call s_cap ( command_cap ) call s_blank_delete ( command_cap ) if ( echo .or. command(1:1) == '#' ) then write ( *, '(a)' ) trim ( command ) end if if ( len_trim ( command ) == 0 ) then cycle end if if ( command(1:1) == '#' ) then cycle end if if ( command_cap(1:6) == 'CVT_IT' ) then if ( command_cap(7:7) == '=' ) then call s_to_i ( command_cap(8:), cvt_it, ierror, last ) else if ( 0 < len_trim ( command_cap(7:) ) ) then call s_to_i ( command_cap(7:), cvt_it, ierror, last ) else write ( *, '(a)' ) ' ' write ( *, '(a)' ) & ' Enter CVT_IT, the number of CVT iterations.' read ( *, * ) cvt_it end if write ( *, '(a,i12)' ) ' CVT_IT = ', cvt_it else if ( command_cap(1:4) == 'ECHO' ) then echo = .true. write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'Command echo has been enabled.' else if ( command_cap(1:1) == 'M' ) then if ( command_cap(2:2) == '=' ) then call s_to_i ( command_cap(3:), m, ierror, last ) else write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Enter M, the spatial dimension.' read ( *, * ) m end if if ( allocated ( cell_generator ) ) then deallocate ( cell_generator ) end if if ( allocated ( cvt_generator ) ) then deallocate ( cvt_generator ) end if if ( 0 < n ) then allocate ( cell_generator(1:m,1:n) ) allocate ( cvt_generator(1:m,1:n) ) end if else if ( command_cap(1:6) == 'NOECHO' ) then echo = .false. write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'Command echo has been disabled.' else if ( command_cap(1:14) == 'INITIALIZEGRID' .or. & ( command_cap(1:15) == 'INITIALIZE=GRID' ) ) then sample_function_init = 2 step = 0 reset = .true. sample_num_init = n call region_sampler ( m, n, sample_num_init, & cell_generator, sample_function_init, reset, seed ) write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' The generators were initialized by GRID.' else if ( command_cap(1:16) == 'INITIALIZEHALTON' .or. & command_cap(1:17) == 'INITIALIZE=HALTON' ) then sample_function_init = 1 step = 0 reset = .true. sample_num_init = n call region_sampler ( m, n, sample_num_init, & cell_generator, sample_function_init, reset, seed ) write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' The generators were initialized by HALTON.' else if ( command_cap(1:16) == 'INITIALIZERANDOM' .or. & command_cap(1:17) == 'INITIALIZE=RANDOM' ) then sample_function_init = -1 step = 0 reset = .true. sample_num_init = n call region_sampler ( m, n, sample_num_init, & cell_generator, sample_function_init, reset, seed ) write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' The generators were initialized by RANDOM_NUMBER.' else if ( command_cap(1:17) == 'INITIALIZEUNIFORM' .or. & command_cap(1:18) == 'INITIALIZE=UNIFORM' ) then sample_function_init = 0 step = 0 reset = .true. sample_num_init = n call region_sampler ( m, n, sample_num_init, & cell_generator, sample_function_init, reset, seed ) write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' The generators were initialized by UNIFORM.' else if ( command_cap(1:1) == 'H' ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'HELP!' write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' M = value' write ( *, '(a)' ) ' Set the number of spatial dimensions.' write ( *, '(a)' ) ' N = value' write ( *, '(a)' ) ' Set the number of generators.' write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' ECHO' write ( *, '(a)' ) ' Turn command echo on.' write ( *, '(a)' ) ' HELP' write ( *, '(a)' ) ' Print this command list.' write ( *, '(a)' ) ' INITIALIZE GRID' write ( *, '(a)' ) ' Initializing function is GRID.' write ( *, '(a)' ) ' INITIALIZE HALTON' write ( *, '(a)' ) ' Initializing function is HALTON.' write ( *, '(a)' ) ' INITIALIZE RANDOM' write ( *, '(a)' ) ' Initializing function is RANDOM_NUMBER.' write ( *, '(a)' ) ' INITIALIZE UNIFORM' write ( *, '(a)' ) ' Initializing function is UNIFORM.' write ( *, '(a)' ) ' ITERATE n' write ( *, '(a)' ) ' Carry out N (more) iterations.' write ( *, '(a)' ) ' LATIN_IT = n' write ( *, '(a)' ) ' Specify the number of Latin hypercube iterations.' write ( *, '(a)' ) ' NOECHO' write ( *, '(a)' ) ' Cease command echo.' write ( *, '(a)' ) ' PRINT' write ( *, '(a)' ) ' Print problem parameters.' write ( *, '(a)' ) ' QUIT' write ( *, '(a)' ) ' Terminate execution.' write ( *, '(a)' ) ' READ = filename' write ( *, '(a)' ) ' Generators are initialized from a file.' write ( *, '(a)' ) ' (Automatically sets M and N.)' write ( *, '(a)' ) ' SAMPLE = GRID' write ( *, '(a)' ) ' Sampling function is GRID.' write ( *, '(a)' ) ' SAMPLE = HALTON' write ( *, '(a)' ) ' Sampling function is HALTON' write ( *, '(a)' ) ' SAMPLE = RANDOM' write ( *, '(a)' ) ' Sampling function is RANDOM_NUMBER.' write ( *, '(a)' ) ' SAMPLE = UNIFORM' write ( *, '(a)' ) ' Sampling function is UNIFORM.' write ( *, '(a)' ) ' SAMPLE_NUM = value' write ( *, '(a)' ) ' Set the number of CVT iteration sampling points.' write ( *, '(a)' ) ' SEED = value' write ( *, '(a)' ) ' Specify the random number seed.' write ( *, '(a)' ) ' WRITECVT filename' write ( *, '(a)' ) ' Write CVT generators to file.' write ( *, '(a)' ) ' WRITELATIN filename' write ( *, '(a)' ) ' Write Latinized CVT generators to file.' else if ( command_cap(1:7) == 'ITERATE' ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Step CVT Latinized CVT' write ( *, '(a)' ) ' Energy Energy' write ( *, '(a)' ) ' ' do latin = 1, latin_it do cvt = 1, cvt_it call cvt_iteration ( m, n, cell_generator, sample_num_cvt, & sample_function_cvt, seed, change_l2 ) end do ! ! Save a copy of the final CVT, in case the user wants to see it. ! cvt_generator(1:m,1:n) = cell_generator(1:m,1:n) call cluster_energy ( m, n, cell_generator, sample_num_cvt, & sample_function_cvt, seed, cvt_energy ) call dtable_latinize ( m, n, cell_generator ) call cluster_energy ( m, n, cell_generator, sample_num_cvt, & sample_function_cvt, seed, latin_energy ) write ( *, '(i4,2f10.6)' ) latin, cvt_energy, latin_energy end do else if ( command_cap(1:8) == 'LATIN_IT' ) then if ( command_cap(9:9) == '=' ) then call s_to_i ( command_cap(10:), latin_it, ierror, last ) else if ( 0 < len_trim ( command_cap(9:) ) ) then call s_to_i ( command_cap(9:), latin_it, ierror, last ) else write ( *, '(a)' ) ' ' write ( *, '(a)' ) & ' Enter LATIN_IT, the number of Latin hypercube iterations.' read ( *, * ) latin_it end if write ( *, '(a,i12)' ) ' LATIN_IT = ', latin_it ! ! Need to list "N" after "NOECHO" to avoid ambiguity. ! else if ( command_cap(1:1) == 'N' ) then if ( command_cap(2:2) == '=' ) then call s_to_i ( command_cap(3:), n, ierror, last ) else write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Enter N, the number of generators.' read ( *, * ) n end if if ( allocated ( cell_generator ) ) then deallocate ( cell_generator ) end if if ( allocated ( cvt_generator ) ) then deallocate ( cvt_generator ) end if if ( 0 < m ) then allocate ( cell_generator(1:m,1:n) ) allocate ( cvt_generator(1:m,1:n) ) end if else if ( command_cap == 'PRINT' ) then call param_print ( m, n, cvt_it, latin_it, seed, seed_start, & sample_function_cvt, sample_function_init, sample_num_cvt ) write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Current cell generators:' write ( *, '(a)' ) ' ' do j = 1, n write ( *, * ) j, cell_generator(1:m,j) end do else if ( command_cap(1:1) == 'Q' ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' QUIT requested.' if ( allocated ( cell_generator ) ) then deallocate ( cell_generator ) end if if ( allocated ( cvt_generator ) ) then deallocate ( cvt_generator ) end if write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'LCVT_DATASET:' write ( *, '(a)' ) ' Normal end of execution.' exit else if ( s_eqi ( command(1:4), 'READ' ) ) then generator_file_in_name = command(5:) generator_file_in_name = adjustl ( generator_file_in_name ) if ( generator_file_in_name(1:1) == '=' ) then generator_file_in_name(1:1) = ' ' generator_file_in_name = adjustl ( generator_file_in_name ) else if ( len_trim ( generator_file_in_name ) == 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Enter the generator file name.' read ( *, '(a)' ) generator_file_in_name end if sample_function_init = 3 step = 0 call file_column_count ( generator_file_in_name, m ) call file_row_count ( generator_file_in_name, n ) if ( allocated ( cell_generator ) ) then deallocate ( cell_generator ) end if if ( allocated ( cvt_generator ) ) then deallocate ( cvt_generator ) end if allocate ( cell_generator(1:m,1:n) ) allocate ( cvt_generator(1:m,1:n) ) call dtable_data_read ( generator_file_in_name, m, n, cell_generator ) else if ( command_cap(1:11) == 'SAMPLE_GRID' ) then sample_function_cvt = 2 write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' The region will be sampled using a fixed grid.' else if ( command_cap(1:10) == 'SAMPLE_NUM' ) then if ( command_cap(11:11) == '=' ) then call s_to_i ( command_cap(12:), sample_num_cvt, ierror, last ) else if ( 0 < len_trim ( command_cap(11:) ) ) then call s_to_i ( command_cap(11:), sample_num_cvt, ierror, last ) else write ( *, '(a)' ) ' ' write ( *, '(a)' ) & ' Enter SAMPLE_NUM, the number of CVT sampling points.' read ( *, * ) sample_num_cvt end if write ( *, '(a,i12)' ) ' SAMPLE_NUM = ', sample_num_cvt else if ( command_cap(1:6) == 'SAMPLE' ) then if ( command_cap(7:7) == '=' ) then if ( command_cap(8:13) == 'RANDOM' ) then sample_function_cvt = -1 else if ( command_cap(8:14) == 'UNIFORM' ) then sample_function_cvt = 0 else if ( command_cap(8:13) == 'HALTON' ) then sample_function_cvt = 1 else if ( command_cap(8:11) == 'GRID' ) then sample_function_cvt = 2 end if else if ( 0 < len_trim ( command_cap(7:) ) ) then if ( command_cap(7:12) == 'RANDOM' ) then sample_function_cvt = -1 else if ( command_cap(7:13) == 'UNIFORM' ) then sample_function_cvt = 0 else if ( command_cap(7:12) == 'HALTON' ) then sample_function_cvt = 1 else if ( command_cap(7:10) == 'GRID' ) then sample_function_cvt = 2 end if else write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Enter SAMPLE:' write ( *, '(a)' ) ' -1: RANDOM_NUMBER (Fortran90 intrinsic);' write ( *, '(a)' ) ' 0: UNIFORM;' write ( *, '(a)' ) ' 1: HALTON;' write ( *, '(a)' ) ' 2: GRID;' read ( *, * ) sample_function_cvt end if if ( sample_function_cvt == -1 ) then write ( *, '(a)' ) & ' Sampling function is RANDOM_NUMBER (Fortran90 intrinsic).' else if ( sample_function_cvt == 0 ) then write ( *, '(a)' ) ' Sampling function is UNIFORM.' else if ( sample_function_cvt == 1 ) then write ( *, '(a)' ) ' Sampling function is HALTON.' else if ( sample_function_cvt == 2 ) then write ( *, '(a)' ) ' Sampling function is GRID.' end if else if ( command_cap(1:4) == 'SEED' ) then if ( command_cap(5:5) == '=' ) then call s_to_i ( command_cap(6:), seed, ierror, last ) else if ( 0 < len_trim ( command_cap(5:) ) ) then call s_to_i ( command_cap(5:), seed, ierror, last ) else write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Enter SEED, the initial random number seed.' read ( *, * ) seed end if write ( *, '(a,i12)' ) ' SEED = ', seed seed_start = seed else if ( s_eqi ( command(1:8), 'WRITECVT' ) ) then generator_file_out_name = command(9:) generator_file_out_name = adjustl ( generator_file_out_name ) if ( generator_file_out_name(1:1) == '=' ) then generator_file_out_name(1:1) = ' ' generator_file_out_name = adjustl ( generator_file_out_name ) else if ( len_trim ( generator_file_out_name ) == 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Enter the CVT generator file name.' read ( *, '(a)' ) generator_file_out_name end if if ( len_trim ( generator_file_out_name ) == 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'Enter the CVT generator file name:' read ( *, '(a)' ) generator_file_out_name end if call cvt_write ( m, n, seed_start, sample_function_init, & generator_file_in_name, sample_function_cvt, sample_num_cvt, & cvt_it, cvt_energy, cvt_generator, generator_file_out_name ) write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' The CVT generators were written to "' & // trim ( generator_file_out_name ) // '".' else if ( s_eqi ( command(1:10), 'WRITELATIN' ) ) then generator_file_out_name = command(11:) generator_file_out_name = adjustl ( generator_file_out_name ) if ( generator_file_out_name(1:1) == '=' ) then generator_file_out_name(1:1) = ' ' generator_file_out_name = adjustl ( generator_file_out_name ) else if ( len_trim ( generator_file_out_name ) == 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Enter the Latinized CVT generator file name.' read ( *, '(a)' ) generator_file_out_name end if if ( len_trim ( generator_file_out_name ) == 0 ) then write ( *, '(a)' ) ' ' write ( *, '(a)' ) 'Enter the Latinized CVT generator file name:' read ( *, '(a)' ) generator_file_out_name end if call lcvt_write ( m, n, seed_start, sample_function_init, & generator_file_in_name, sample_function_cvt, sample_num_cvt, & cvt_it, cvt_energy, latin_it, latin_energy, & cell_generator, generator_file_out_name ) write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' The Latin CVT generators were written to "' & // trim ( generator_file_out_name ) // '".' else write ( *, '(a)' ) ' ' write ( *, '(a)' ) ' Your input command was not recognized!' write ( *, '(a)' ) ' If ECHO is on, we will terminate.' if ( echo ) then exit end if end if end do write ( *, '(a)' ) ' ' call timestamp ( ) stop end