10 integer,
parameter :: dp = kind(1.0d0)
30 logical :: extrapolate_above
33 real(dp),
allocatable :: x(:)
34 real(dp),
allocatable :: cols_rows(:, :)
35 real(dp),
allocatable :: rows_cols(:, :)
40 integer :: n_points(2)
42 integer :: xspacing(2)
44 real(dp) :: inv_fac(2)
45 real(dp),
allocatable :: x1(:)
46 real(dp),
allocatable :: x2(:)
47 real(dp),
allocatable :: rows_cols(:, :, :)
64 real(dp) :: low_frac(2)
105 real(dp),
intent(in) :: list(:)
106 real(dp),
intent(in) :: val
109 do ix = 1,
size(list)
110 if (list(ix) >= val)
exit
117 real(dp),
intent(in) :: list(:)
118 real(dp),
intent(in) :: val
119 integer :: ix, i_min, i_max, i_middle
124 do while (i_min < i_max)
126 i_middle = i_min + ishft(i_max - i_min, -1)
128 if (list(i_middle) >= val)
then
136 if (val > list(ix)) ix =
size(list) + 1
143 real(dp),
intent(in) :: list(:)
144 real(dp),
intent(in) :: val
146 integer,
parameter :: binary_search_limit = 40
148 if (
size(list) < binary_search_limit)
then
162 real(dp),
intent(in) :: x_list(:), y_list(:)
163 real(dp),
intent(in) :: x_value
164 real(dp),
intent(out) :: y_value
166 integer :: ix, imin, imax
172 if (x_value <= x_list(imin))
then
173 y_value = y_list(imin)
174 else if (x_value >= x_list(imax))
then
175 y_value = y_list(imax)
178 temp = (x_value - x_list(ix-1)) / (x_list(ix) - x_list(ix-1))
179 y_value = (1 - temp) * y_list(ix-1) + temp * y_list(ix)
186 function lt_create(x_min, x_max, n_points, n_cols, xspacing, &
187 extrapolate_above)
result(my_lt)
188 real(dp),
intent(in) :: x_min
189 real(dp),
intent(in) :: x_max
190 integer,
intent(in) :: n_points
191 integer,
intent(in) :: n_cols
192 integer,
intent(in),
optional :: xspacing
194 logical,
intent(in),
optional :: extrapolate_above
197 if (x_max <= x_min) error stop
"x_max should be > x_min"
198 if (n_points <= 1) error stop
"n_points should be bigger than 1"
200 my_lt%n_points = n_points
201 my_lt%n_cols = n_cols
204 if (
present(xspacing)) my_lt%xspacing = xspacing
205 my_lt%extrapolate_above = .false.
206 if (
present(extrapolate_above)) my_lt%extrapolate_above = extrapolate_above
208 allocate(my_lt%x(n_points))
209 call table_set_x(n_points, my_lt%xspacing, x_min, x_max, &
210 my_lt%x, my_lt%inv_fac)
212 allocate(my_lt%cols_rows(n_cols, n_points))
213 allocate(my_lt%rows_cols(n_points, n_cols))
218 subroutine table_set_x(n_points, xspacing, x_min, x_max, x, inv_fac)
219 integer,
intent(in) :: n_points
220 integer,
intent(in) :: xspacing
221 real(dp),
intent(in) :: x_min, x_max
222 real(dp),
intent(out) :: x(n_points)
223 real(dp),
intent(out) :: inv_fac
225 select case (xspacing)
227 inv_fac = (n_points - 1)/(x_max - x_min)
229 inv_fac = (n_points - 1.0_dp)**2/(x_max - x_min)
231 inv_fac = (n_points - 1.0_dp)**3/(x_max - x_min)
233 error stop
"Unknown spacing"
236 x = get_x(x_min, x_max, n_points, xspacing)
237 end subroutine table_set_x
241 real(dp),
intent(in) :: in_x(:), in_y(:), new_x(:)
242 real(dp) :: out_yy(size(new_x))
246 if (n < 2) error stop
"size(in_x) < 2"
247 if (
size(in_x) /=
size(in_y)) error stop
"in_x and in_y not of same size"
248 if (minval(in_x(2:) - in_x(1:n-1)) <= 0) &
249 error stop
"in_x should strictly increase"
251 do ix = 1,
size(new_x)
258 type(
lt_t),
intent(inout) :: my_lt
259 integer,
intent(in) :: col_ix
260 real(dp),
intent(in) :: x(:), y(:)
262 if (col_ix < 0 .or. col_ix > my_lt%n_cols) &
263 error stop
"should have 1 <= col_ix <= n_cols"
266 my_lt%rows_cols(:, col_ix) = my_lt%cols_rows(col_ix, :)
271 type(
lt_t),
intent(inout) :: my_lt
272 integer,
intent(in) :: col_ix
273 real(dp),
intent(in) :: y(:)
275 if (col_ix < 0 .or. col_ix > my_lt%n_cols) &
276 error stop
"should have 1 <= col_ix <= n_cols"
277 if (
size(y) /= my_lt%n_points) error stop
"size(y) /= number of rows"
279 my_lt%cols_rows(col_ix, :) = y
280 my_lt%rows_cols(:, col_ix) = y
285 type(
lt_t),
intent(inout) :: my_lt
286 real(dp),
intent(in) :: x(:), y(:)
287 type(
lt_t) :: temp_lt
290 deallocate(my_lt%cols_rows)
291 deallocate(my_lt%rows_cols)
292 allocate(my_lt%rows_cols(my_lt%n_points, my_lt%n_cols+1))
293 allocate(my_lt%cols_rows(my_lt%n_cols+1, my_lt%n_points))
295 my_lt%cols_rows(1:my_lt%n_cols, :) = temp_lt%cols_rows
296 my_lt%rows_cols(:, 1:my_lt%n_cols) = temp_lt%rows_cols
297 my_lt%n_cols = my_lt%n_cols + 1
299 my_lt%rows_cols(:, my_lt%n_cols) = my_lt%cols_rows(my_lt%n_cols, :)
303 pure function get_x(x_min, x_max, n_points, xspacing)
result(x)
304 real(dp),
intent(in) :: x_min, x_max
305 integer,
intent(in) :: n_points, xspacing
306 real(dp) :: x(n_points), tmp
309 tmp = 1.0_dp / (n_points-1)
311 select case (xspacing)
318 x(ix) = ((ix-1) * tmp)**2
322 x(ix) = ((ix-1) * tmp)**3
326 x = x_min + x * (x_max - x_min)
331 type(
lt_t),
intent(in) :: my_lt
332 real(dp),
intent(in) :: x
335 real(dp),
parameter :: one_third = 1/3.0_dp
337 frac = (x - my_lt%x_min) * my_lt%inv_fac
339 select case (my_lt%xspacing)
341 if (frac > 0) frac = sqrt(frac)
343 if (frac > 0) frac = frac**one_third
350 else if (frac >= my_lt%n_points - 1)
then
351 my_loc%low_ix = my_lt%n_points - 1
352 if (my_lt%extrapolate_above)
then
353 my_loc%low_frac = my_loc%low_ix - frac
358 my_loc%low_ix = ceiling(frac)
359 my_loc%low_frac = my_loc%low_ix - frac
366 type(
lt_t),
intent(in) :: my_lt
367 real(dp),
intent(in) :: x
368 real(dp) :: col_values(my_lt%n_cols)
376 elemental function lt_get_col(my_lt, col_ix, x)
result(col_value)
377 type(
lt_t),
intent(in) :: my_lt
378 integer,
intent(in) :: col_ix
379 real(dp),
intent(in) :: x
380 real(dp) :: col_value
389 type(
lt_t),
intent(in) :: my_lt
391 real(dp) :: col_values(my_lt%n_cols)
393 col_values = loc%low_frac * my_lt%cols_rows(:, loc%low_ix) + &
394 (1-loc%low_frac) * my_lt%cols_rows(:, loc%low_ix+1)
399 type(
lt_t),
intent(in) :: my_lt
400 integer,
intent(in) :: col_ix
402 real(dp) :: col_value
404 col_value = loc%low_frac * my_lt%rows_cols(loc%low_ix, col_ix) + &
405 (1-loc%low_frac) * my_lt%rows_cols(loc%low_ix+1, col_ix)
410 type(
lt_t),
intent(in) :: my_lt
411 character(len=*),
intent(in) :: filename
414 open(newunit=my_unit, file=trim(filename), form=
'UNFORMATTED', &
415 access=
'STREAM', status=
'REPLACE')
416 write(my_unit) my_lt%n_points, my_lt%n_cols
417 write(my_unit) my_lt%x_min, my_lt%inv_fac, my_lt%xspacing
418 write(my_unit) my_lt%x, my_lt%cols_rows
424 type(
lt_t),
intent(inout) :: my_lt
425 character(len=*),
intent(in) :: filename
428 open(newunit=my_unit, file=trim(filename), form=
'UNFORMATTED', &
429 access=
'STREAM', status=
'OLD')
430 read(my_unit) my_lt%n_points, my_lt%n_cols
431 read(my_unit) my_lt%x_min, my_lt%inv_fac, my_lt%xspacing
433 allocate(my_lt%x(my_lt%n_points))
434 allocate(my_lt%cols_rows(my_lt%n_cols, my_lt%n_points))
435 allocate(my_lt%rows_cols(my_lt%n_points, my_lt%n_cols))
437 read(my_unit) my_lt%x, my_lt%cols_rows
438 my_lt%rows_cols = transpose(my_lt%cols_rows)
446 function lt2_create(x_min, x_max, n_points, n_cols, xspacing)
result(my_lt)
447 real(dp),
intent(in) :: x_min(2)
448 real(dp),
intent(in) :: x_max(2)
449 integer,
intent(in) :: n_points(2)
450 integer,
intent(in) :: n_cols
451 integer,
intent(in),
optional :: xspacing(2)
454 if (any(x_max <= x_min)) stop
"LT2_create error: x_max <= x_min"
455 if (any(n_points <= 1)) stop
"LT2_create error: n_points <= 1"
457 my_lt%n_points = n_points
458 my_lt%n_cols = n_cols
461 if (
present(xspacing)) my_lt%xspacing = xspacing
463 allocate(my_lt%x1(n_points(1)))
464 allocate(my_lt%x2(n_points(2)))
466 call table_set_x(n_points(1), my_lt%xspacing(1), x_min(1), x_max(1), &
467 my_lt%x1, my_lt%inv_fac(1))
468 call table_set_x(n_points(2), my_lt%xspacing(2), x_min(2), x_max(2), &
469 my_lt%x2, my_lt%inv_fac(2))
471 allocate(my_lt%rows_cols(n_points(1), n_points(2), n_cols))
477 type(
lt2_t),
intent(inout) :: my_lt
478 integer,
intent(in) :: col_ix
479 real(dp),
intent(in) :: x1(:), x2(:), y(:, :)
480 real(dp),
allocatable :: tmp(:, :)
483 allocate(tmp(my_lt%n_points(1),
size(x2)))
491 do ix = 1, my_lt%n_points(1)
492 my_lt%rows_cols(ix, :, col_ix) = &
499 type(
lt2_t),
intent(inout) :: my_lt
500 integer,
intent(in) :: col_ix
501 real(dp),
intent(in) :: y(:, :)
503 if (col_ix < 0 .or. col_ix > my_lt%n_cols) &
504 error stop
"should have 1 <= col_ix <= n_cols"
505 if (any(shape(y) /= my_lt%n_points)) error stop
"shape(y) /= n_points"
507 my_lt%rows_cols(:, :, col_ix) = y
512 type(
lt2_t),
intent(in) :: my_lt
513 real(dp),
intent(in) :: x1, x2
517 frac = ([x1, x2] - my_lt%x_min) * my_lt%inv_fac
518 my_loc%low_ix = ceiling(frac)
519 my_loc%low_frac = my_loc%low_ix - frac
522 where (my_loc%low_ix < 1)
527 where (my_loc%low_ix >= my_lt%n_points - 1)
528 my_loc%low_ix = my_lt%n_points - 1
534 pure function lt2_get_col(my_lt, col_ix, x1, x2)
result(col_value)
535 type(
lt2_t),
intent(in) :: my_lt
536 integer,
intent(in) :: col_ix
537 real(dp),
intent(in) :: x1, x2
538 real(dp) :: col_value
547 type(
lt2_t),
intent(in) :: my_lt
548 integer,
intent(in) :: col_ix
552 real(dp) :: col_value
555 w(1, 1) = loc%low_frac(1) * loc%low_frac(2)
556 w(2, 1) = (1 - loc%low_frac(1)) * loc%low_frac(2)
557 w(1, 2) = loc%low_frac(1) * (1 - loc%low_frac(2))
558 w(2, 2) = (1 - loc%low_frac(1)) * (1 - loc%low_frac(2))
561 col_value = sum(w * my_lt%rows_cols(ix(1):ix(1)+1, &
562 ix(2):ix(2)+1, col_ix))
A Fortran 90 module for creating lookup tables. These tables can be used to efficiently interpolate o...
subroutine, public lt_set_col(my_lt, col_ix, x, y)
Fill the column with index col_ix after linearly interpolating.
pure integer function, public find_index_bsearch(list, val)
Binary search of sorted list for the smallest ix such that list(ix) >= val. On failure,...
pure real(dp) function, public lt2_get_col(my_lt, col_ix, x1, x2)
Get the value of a single column at x.
subroutine, public lt2_set_col(my_lt, col_ix, x1, x2, y)
Fill the column with index col_ix using linearly interpolated data.
type(lt_t) function, public lt_create(x_min, x_max, n_points, n_cols, xspacing, extrapolate_above)
This function returns a new lookup table.
elemental real(dp) function, public lt_get_col_at_loc(my_lt, col_ix, loc)
Get the value of a single column at a location.
subroutine, public lt_from_file(my_lt, filename)
Read the lookup table from file (in binary, potentially unportable)
pure real(dp) function, public lt2_get_col_at_loc(my_lt, col_ix, loc)
Get the value of a single column at a location.
pure real(dp) function, dimension(my_lt%n_cols), public lt_get_mcol(my_lt, x)
Get the values of all columns at x.
pure real(dp) function, dimension(my_lt%n_cols), public lt_get_mcol_at_loc(my_lt, loc)
Get the values of all columns at a location.
subroutine, public lt_add_col(my_lt, x, y)
Add a new column by linearly interpolating the (x, y) data.
elemental type(lt2_loc_t) function, public lt2_get_loc(my_lt, x1, x2)
Get a location in the lookup table.
real(dp) function, dimension(size(new_x)), public lt_get_spaced_data(in_x, in_y, new_x)
Linearly interpolate the (x, y) input data to the new_x coordinates.
subroutine, public lt_set_col_data(my_lt, col_ix, y)
Fill the column with index col_ix with y data.
elemental real(dp) function, public lt_get_col(my_lt, col_ix, x)
Get the value of a single column at x.
subroutine, public lt2_set_col_data(my_lt, col_ix, y)
Fill the column with index col_ix with y data.
pure subroutine, public lt_lin_interp_list(x_list, y_list, x_value, y_value)
Compute by use of linear interpolation the value in the middle.
integer, parameter, public lt_xspacing_cubic
integer, parameter, public lt_xspacing_linear
pure integer function, public find_index_adaptive(list, val)
Adaptive search (combination of linear and binary search) of sorted list for the smallest ix such tha...
integer, parameter, public lt_xspacing_quadratic
subroutine, public lt_to_file(my_lt, filename)
Write the lookup table to file (in binary, potentially unportable)
type(lt2_t) function, public lt2_create(x_min, x_max, n_points, n_cols, xspacing)
This function returns a new lookup table.
elemental type(lt_loc_t) function, public lt_get_loc(my_lt, x)
Get a location in the lookup table.
pure integer function, public find_index_linear(list, val)
Linear search of sorted list for the smallest ix such that list(ix) >= val. On failure,...
Type to indicate a location in a 2D lookup table.
The 2D lookup table type.
Type to indicate a location in the lookup table, which can be used to speed up multiple lookups of di...
The lookup table type. There can be one or more columns, for which values can be looked up for a give...