afivo-streamer 1.1
1D/2D/3D streamer simulations with AMR
Loading...
Searching...
No Matches
m_table_data.f90
Go to the documentation of this file.
1!> Module with settings and routines for tabulated data
3 use m_types
4 use m_lookup_table
5
6 implicit none
7 private
8
9 integer, parameter :: dp = kind(0.0d0)
10
11 !> How large lookup tables should be
12 integer, public, protected :: table_size = 1000
13
14 !> Minimum field (Td) for lookup tables
15 real(dp), public, protected :: table_min_townsend = 0.0
16
17 !> Maximum field (Td) for lookup tables
18 real(dp), public, protected :: table_max_townsend = -1.0_dp
19
20 ! The maximum number of rows per entry
21 integer, parameter :: table_max_rows = 1500
22
23 ! Interpolation methods
24 integer, parameter :: interp_linear = 1
25 integer, parameter :: interp_cubic_spline = 2
26
27 integer :: input_interpolation = -1
28
29 !> X-spacing for lookup table
30 integer, public, protected :: table_xspacing = -1
31
32 ! Public methods
33 public :: table_data_initialize
34 public :: table_from_file
35 public :: table_set_column
36
37contains
38
39 !> Initialize this module
40 subroutine table_data_initialize(cfg)
41 use m_config
42 type(cfg_t), intent(inout) :: cfg
43 character(len=20) :: method
44
45 call cfg_add_get(cfg, "table_data%size", table_size, &
46 "Size of the lookup table for reaction rates")
47 call cfg_add_get(cfg, "table_data%min_townsend", table_min_townsend, &
48 "Minimal field (in Td) for the rate coeff. lookup table")
49 call cfg_add_get(cfg, "table_data%max_townsend", table_max_townsend, &
50 "Maximal field (Td) for lookup tables, < 0 means automatic")
51
52 method = "linear"
53 call cfg_add_get(cfg, "table_data%input_interpolation", method, &
54 "Input interpolation method (linear, cubic_spline)")
55 select case (method)
56 case ("linear")
57 input_interpolation = interp_linear
58 case ("cubic_spline")
59 input_interpolation = interp_cubic_spline
60 case default
61 error stop "invalid input_interpolation method"
62 end select
63
64 method = "linear"
65 call cfg_add_get(cfg, "table_data%xspacing", method, &
66 "x-spacing for lookup table (linear, quadratic)")
67 select case (method)
68 case ("linear")
69 table_xspacing = lt_xspacing_linear
70 case ("quadratic")
71 table_xspacing = lt_xspacing_quadratic
72 case default
73 error stop "invalid table_data%xspacing (linear, quadratic)"
74 end select
75
76 ! To remind users that there are multiple options
77 print *, "Spacing used for lookup tables: ", trim(method)
78
79 end subroutine table_data_initialize
80
81 !> Interpolate data and store in lookup table
82 subroutine table_set_column(tbl, i_col, x, y, max_err)
84 use m_lookup_table
85 type(lt_t), intent(inout) :: tbl !< Lookup table
86 integer, intent(in) :: i_col !< Index of column
87 real(dp), intent(in) :: x(:)
88 real(dp), intent(in) :: y(:)
89 real(dp), intent(out), optional :: max_err !< Estimate of maximal error
90 real(dp), allocatable :: y_table(:)
91 type(spline_t) :: spl
92
93 if (size(x) /= size(y)) error stop "size(x) /= size(y)"
94
95 select case (input_interpolation)
96 case (interp_linear)
97 call lt_set_col(tbl, i_col, x, y)
98 case (interp_cubic_spline)
99 ! Perform cubic spline interpolation
100 call spline_set_coeffs(x, y, size(x), spl)
101 y_table = spline_evaluate(tbl%x, spl)
102
103 if (minval(y) >= 0.0_dp) then
104 ! If original data is non-negative, ensure interpolated data is also
105 ! non-negative (important for e.g. rate coefficients)
106 y_table = max(0.0_dp, y_table)
107 end if
108
109 call lt_set_col_data(tbl, i_col, y_table)
110 case default
111 error stop "invalid input_interpolation"
112 end select
113
114 if (present(max_err)) then
115 ! Largest difference divided by maximum value of |y|
116 max_err = maxval(abs(y - lt_get_col(tbl, i_col, x)))/maxval(abs(y))
117 end if
118 end subroutine table_set_column
119
120 !> Routine to read in tabulated data from a file
121 subroutine table_from_file(file_name, data_name, x_data, y_data)
122 character(len=*), intent(in) :: file_name, data_name
123 real(dp), allocatable, intent(out) :: x_data(:), y_data(:)
124
125 ! Temporary variables
126 integer :: iostate, nl
127 integer :: n_rows
128 integer :: my_unit
129 character(LEN=40) :: line_fmt
130 character(LEN=string_len) :: line
131 real(dp) :: temp_table(2, table_max_rows)
132 real(dp) :: factor
133
134 nl = 0 ! Set the number of lines to 0
135
136 ! Set the line format to read, only depends on string_len currently
137 write(line_fmt, fmt = "(I6)") string_len
138 line_fmt = "(A" // trim(adjustl(line_fmt)) // ")"
139
140 ! Open 'file_name' (with error checking)
141 open(newunit=my_unit, file = trim(file_name), action = "read", &
142 err = 999, iostat = iostate, status="old")
143
144 ! Table format
145
146 ! table_name
147 ! FACTOR: 1.0 [optional: multiply with this factor]
148 ! [other lines]
149 ! ------------------ [at least 5 dashes]
150 ! xxx xxx [data in two column format]
151 ! ... ...
152 ! xxx xxx
153 ! ------------------
154
155 ! The outer DO loop, running until the end of the file is reached
156 do
157 ! Search for 'data_name' in the file
158 do
159 read(my_unit, fmt = line_fmt, err = 999, end = 888) line; nl = nl+1
160 if (line == data_name) exit
161 end do
162
163 factor = 1.0_dp
164
165 ! Now we can check whether there is a comment, while scanning lines until
166 ! dashes are found, which indicate the start of the data
167 do
168 read(my_unit, fmt = line_fmt, err = 999, end = 777) line; nl = nl+1
169 line = adjustl(line)
170 if ( line(1:5) == "-----" ) then
171 exit
172 else if (line(1:7) == "FACTOR:") then
173 read(line(8:), *) factor
174 else if (line(1:8) == "COMMENT:") then
175 continue
176 else
177 print *, "In file ", trim(file_name), " at line", nl
178 print *, trim(line)
179 error stop "Unknown statement in input file"
180 end if
181 end do
182
183 ! Read the data into a temporary array
184 n_rows = 0
185 do
186 read(my_unit, fmt = line_fmt, err = 999, end = 777) line; nl = nl+1
187 line = adjustl(line)
188 if ( line(1:5) == "-----" ) then
189 exit ! Dashes mark the end of the data
190 else if (trim(line) == "" .or. line(1:1) == "#") then
191 cycle ! Ignore whitespace or comments
192 else if (n_rows < table_max_rows) then
193 n_rows = n_rows + 1
194 read(line, fmt = *, err = 999, end = 777) temp_table(:, n_rows)
195 else
196 print *, "CS_read_file error: too many rows in ", &
197 file_name, " at line ", nl
198 end if
199 end do
200
201 ! Store the data in the actual table
202 if (allocated(x_data)) deallocate(x_data)
203 if (allocated(y_data)) deallocate(y_data)
204 allocate(x_data(n_rows))
205 allocate(y_data(n_rows))
206
207 x_data = temp_table(1, 1:n_rows)
208 y_data = factor * temp_table(2, 1:n_rows)
209
210 exit ! Done
211 end do
212
213 close(my_unit)
214 return
215
216777 continue ! If the end of the file is reached after finding data
217 print *, "table_from_file unexpectedly reached end of " // trim(file_name)
218 print *, "searching '" // trim(data_name) // "'"
219 call print_usage(file_name, data_name)
220 error stop
221
222888 continue ! If the end of the file is reached without finding data
223 print *, "table_from_file: no data in " // trim(file_name)
224 print *, "searching '" // trim(data_name) // "'"
225 call print_usage(file_name, data_name)
226 error stop
227
228999 continue ! If there was an input error, the routine will end here
229 print *, "table_from_file error at line", nl
230 print *, "ioState = ", iostate, " in ", trim(file_name)
231 print *, "searching '" // trim(data_name) // "'"
232 call print_usage(file_name, data_name)
233 error stop
234
235 contains
236
237 subroutine print_usage(file_name, data_name)
238 character(len=*), intent(in) :: file_name
239 character(len=*), intent(in) :: data_name
240
241 print *, ""
242 print *, "Expected a file '", trim(file_name), &
243 "' with the following structure:"
244 print *, trim(data_name)
245 print *, "FACTOR: 1.0 [optional: multiply with this factor]"
246 print *, "[other lines]"
247 print *, "------------------ [at least 5 dashes]"
248 print *, "xxx xxx [data in two column format]"
249 print *, "... ..."
250 print *, "xxx xxx"
251 print *, "------------------"
252 print *, ""
253 end subroutine print_usage
254
255 end subroutine table_from_file
256
257end module m_table_data
Module for cubic spline interpolation.
pure elemental real(dp) function, public spline_evaluate(u, spl)
subroutine, public spline_set_coeffs(x, y, n, spl)
Calculate coefficients for cubic spline interpolation.
Module with settings and routines for tabulated data.
subroutine, public table_data_initialize(cfg)
Initialize this module.
subroutine, public table_set_column(tbl, i_col, x, y, max_err)
Interpolate data and store in lookup table.
real(dp), public, protected table_max_townsend
Maximum field (Td) for lookup tables.
integer, public, protected table_xspacing
X-spacing for lookup table.
integer, public, protected table_size
How large lookup tables should be.
subroutine, public table_from_file(file_name, data_name, x_data, y_data)
Routine to read in tabulated data from a file.
real(dp), public, protected table_min_townsend
Minimum field (Td) for lookup tables.
Module with basic types.
Definition m_types.f90:2
integer, parameter string_len
Default length of strings.
Definition m_types.f90:22