Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_scalar_field_1d.F90
Go to the documentation of this file.
1 !------------------------------------------------------------------------------
2 ! SELALIB
3 !------------------------------------------------------------------------------
4 !
5 ! MODULE: sll_scalar_field_1d
6 !
9 !
10 ! DESCRIPTION:
11 !
23 !
24 ! REVISION HISTORY:
25 ! DD Mmm YYYY - Initial Version
26 ! TODO_dd_mmm_yyyy - TODO_describe_appropriate_changes - TODO_name
27 !------------------------------------------------------------------------------
29 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
30 #include "sll_assert.h"
31 #include "sll_memory.h"
32 #include "sll_working_precision.h"
33 
34  use sll_m_cartesian_meshes, only: &
36 
37  use sll_m_interpolators_1d_base, only: &
39 
40  use sll_m_scalar_field_1d_base, only: &
42 
43  implicit none
44 
45  public :: &
50 
51  private
52 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
53 
55  procedure(one_var_parametrizable_function), pointer, nopass :: func
56  procedure(one_var_parametrizable_function), pointer, nopass :: first_derivative
57  sll_real64, dimension(:), pointer :: params
58  character(len=64) :: name
59  ! sll_int32 :: plot_counter
60  sll_int32 :: bc_left
61  sll_int32 :: bc_right
62  type(sll_t_cartesian_mesh_1d), pointer :: mesh
63  ! allows to decide if the user put the derivative of the analiytic function: func
64  logical :: present_derivative
65  contains
66  procedure, pass(field) :: init => initialize_scalar_field_1d_analytic
67  procedure, pass(field) :: get_cartesian_mesh => &
69  procedure, pass(field) :: value_at_point => value_at_pt_analytic_1d
70  procedure, pass(field) :: value_at_indices => value_at_index_analytic_1d
71  procedure, pass(field) :: derivative_value_at_point => &
73  procedure, pass(field) :: derivative_value_at_indices => &
75  procedure, pass(field) :: set_field_data => set_field_data_analytic_1d
76  procedure, pass(field) :: update_interpolation_coefficients => &
78  procedure, pass(field) :: write_to_file => write_to_file_analytic_1d
79  procedure, pass(field) :: delete => delete_field_1d_analytic
81 
83  sll_real64, dimension(:), pointer :: values
84  !sll_real64, dimension(:,:), pointer :: coeff_spline
85  !sll_int32 :: sz_coeff1
86  !sll_int32 :: sz_coeff2
87  character(len=64) :: name
88  ! sll_int32 :: plot_counter
89  class(sll_c_interpolator_1d), pointer :: interp_1d !!! a implementer
90  sll_real64, dimension(:), pointer :: point
91  !sll_real64, dimension(:,:), pointer :: point2d
92  sll_int32 :: bc_left
93  sll_int32 :: bc_right
94  type(sll_t_cartesian_mesh_1d), pointer :: mesh
95  contains
96  procedure, pass(field) :: init => initialize_scalar_field_1d_discrete
97  procedure, pass(field) :: get_cartesian_mesh => &
99  procedure, pass(field) :: value_at_point => value_at_pt_discrete_1d
100  procedure, pass(field) :: value_at_indices => value_at_index_discrete_1d
101  procedure, pass(field) :: derivative_value_at_point => &
103  procedure, pass(field) :: derivative_value_at_indices => &
105  procedure, pass(field) :: set_field_data => set_field_data_discrete_1d
106  procedure, pass(field) :: update_interpolation_coefficients => &
108  procedure, pass(field) :: write_to_file => write_to_file_discrete_1d
109  procedure, pass(field) :: delete => delete_field_1d_discrete
111 
112  abstract interface
113  function one_var_parametrizable_function(eta, params)
115  sll_real64 :: one_var_parametrizable_function
116  sll_real64, intent(in) :: eta
117  sll_real64, dimension(:), intent(in), optional :: params
119  end interface
120 
121  interface delete
123  end interface delete
124 
125 contains ! *****************************************************************
126 
127  ! **************************************************************************
128  !
129  ! ANALYTIC CASE
130  !
131  ! **************************************************************************
132 
133  function value_at_pt_analytic_1d(field, eta)
134  class(sll_t_scalar_field_1d_analytic), intent(inout) :: field
135  sll_real64, intent(in) :: eta
136  sll_real64 :: value_at_pt_analytic_1d
137  value_at_pt_analytic_1d = field%func(eta, field%params)
138  end function value_at_pt_analytic_1d
139 
140  function value_at_index_analytic_1d(field, i)
141  class(sll_t_scalar_field_1d_analytic), intent(inout) :: field
142  sll_int32, intent(in) :: i
143  sll_real64 :: eta
144  sll_real64 :: value_at_index_analytic_1d
145  eta = field%mesh%eta_min + real(i - 1, f64)*field%mesh%delta_eta
146  value_at_index_analytic_1d = field%func(eta, field%params)
147  end function value_at_index_analytic_1d
148 
150  class(sll_t_scalar_field_1d_analytic), intent(inout) :: field
151  sll_real64, intent(in) :: eta
153 
154  if (field%present_derivative) then
156  field%first_derivative(eta, field%params)
157  else
158  print *, ' first derivative is not given in the initialization'
159  end if
160 
162 
164  class(sll_t_scalar_field_1d_analytic), intent(inout) :: field
165  sll_int32, intent(in) :: i
166  sll_real64 :: eta
168 
169  eta = field%mesh%eta_min + real(i - 1, f64)*field%mesh%delta_eta
170 
171  if (field%present_derivative) then
173  field%first_derivative(eta, field%params)
174  else
175  print *, ' first derivative is not given in the initialization'
176  end if
177 
179 
181  func, &
182  field_name, &
183  bc_left, &
184  bc_right, &
185  mesh, &
186  func_params, &
187  first_derivative) result(obj)
188 
189  type(sll_t_scalar_field_1d_analytic), pointer :: obj
190  procedure(one_var_parametrizable_function) :: func
191  procedure(one_var_parametrizable_function), optional :: first_derivative
192  character(len=*), intent(in) :: field_name
193  sll_real64, dimension(:), intent(in), optional, target :: func_params
194  sll_int32, intent(in) :: bc_left
195  sll_int32, intent(in) :: bc_right
196  sll_int32 :: ierr
197  type(sll_t_cartesian_mesh_1d), pointer :: mesh
198 
199  sll_allocate(obj, ierr)
200  call obj%init( &
201  func, &
202  field_name, &
203  bc_left, &
204  bc_right, &
205  mesh, &
206  func_params, &
207  first_derivative)
209 
210  subroutine set_field_data_analytic_1d(field, values)
211  class(sll_t_scalar_field_1d_analytic), intent(inout) :: field
212  sll_real64, dimension(:), intent(in) :: values
213  print *, 'WARNING: set_field_data_analytic_1d(): it is useless to ', &
214  'call this function on an analytic scalar field.'
215  print *, field%bc_left*values(1)
216  end subroutine set_field_data_analytic_1d
217 
219  class(sll_t_scalar_field_1d_analytic), intent(inout) :: field
220  print *, 'WARNING: update_interpolation_coefficients_1d_analytic(): ', &
221  ' it is useless to call this function on an analytic scalar field.'
222  print *, field%bc_left
223  end subroutine update_interp_coeffs_1d_analytic
224 
225  subroutine delete_field_1d_analytic(field)
226  class(sll_t_scalar_field_1d_analytic), intent(inout) :: field
227  ! nothing internal do deallocate, just nullify pointers. Can't call
228  ! delete on them because the field does not 'own' these data.
229  !print*, associated(field%func)
230  !print*, associated(field%params)
231  nullify (field%func)
232  !nullify(field%params) !not associated
233  end subroutine delete_field_1d_analytic
234 
235  ! For those cases in which handling pointers to field structures is not
236  ! convenient, we offer the following initialization.
238  field, &
239  func, &
240  field_name, &
241  bc_left, &
242  bc_right, &
243  mesh, &
244  func_params, &
245  first_derivative)
246 
247  class(sll_t_scalar_field_1d_analytic), intent(out) :: field
248  procedure(one_var_parametrizable_function) :: func
249  procedure(one_var_parametrizable_function), optional :: first_derivative
250  character(len=*), intent(in) :: field_name
251  sll_real64, dimension(:), intent(in), optional, target :: func_params
252  type(sll_t_cartesian_mesh_1d), pointer :: mesh
253 
254  sll_int32, intent(in) :: bc_left
255  sll_int32, intent(in) :: bc_right
256 
257  field%func => func
258  if (present(func_params)) then
259  field%params => func_params
260  else
261  ! Allocate an empty array in order to avoid passing a non associated
262  ! pointer to 'func', which has a non-pointer array dummy argument.
263  ! Note that ifort segfaults without the following line!
264  ! [YG - 06.10.2015]
265  allocate (field%params(0))
266  end if
267  field%name = trim(field_name)
268  field%bc_left = bc_left
269  field%bc_right = bc_right
270  field%mesh => mesh
271  if (present(first_derivative)) then
272  field%first_derivative => first_derivative
273  field%present_derivative = .true.
274  end if
276 
277  ! The following pair of subroutines are tricky. We want them as general
278  ! services by the fields, hence we need this subroutine interface, yet
279  ! we would also like a flexibility in how the derivatives are computed.
280  ! A general interpolator interface would cover most of the cases, maybe
281  ! all. It could be that a finite difference scheme would also work, if
282  ! we ignore some of the interpolator services, like the ability to return
283  ! values anywhere instead of at the nodes.
284  ! For now, this interface would permit to have multiple implementations.
285 !!$ subroutine compute_eta1_derivative_on_col( field2d, ith_col, deriv_out )
286 !!$ type(scalar_field_2d), intent(in) :: field2d
287 !!$ sll_int32, intent(in) :: ith_col
288 !!$ sll_real64, dimension(:),intent(out) :: deriv_out
289 !!$ end subroutine compute_eta1_derivative_on_col
290 
291  function get_cartesian_mesh_1d_analytic(field) result(res)
292  class(sll_t_scalar_field_1d_analytic), intent(in) :: field
293  type(sll_t_cartesian_mesh_1d), pointer :: res
294  res => field%mesh
295  end function get_cartesian_mesh_1d_analytic
296 
297  subroutine write_to_file_analytic_1d(field, tag)
298  class(sll_t_scalar_field_1d_analytic), intent(inout) :: field
299  sll_int32, intent(in) :: tag
300  sll_int32 :: nptsx
301  sll_real64, dimension(:), allocatable :: xcoords
302  sll_real64, dimension(:), allocatable :: values
303  sll_real64 :: eta
304  sll_int32 :: i
305  sll_int32 :: ierr
306  ! print*, 'passed'
307  ! use the logical mesh information to find out the extent of the
308  ! domain and allocate the arrays for the plotter.
309  !mesh => field%get_cartesian_mesh()
310  !print*, 'passed'
311  nptsx = field%mesh%num_cells + 1
312 
313  !print*, 'passed',nptsx
314  sll_allocate(xcoords(nptsx), ierr)
315  sll_allocate(values(nptsx), ierr)
316  ! print*, 'passed'
317  ! Fill the arrays with the needed information.
318  do i = 1, nptsx
319  eta = field%mesh%eta_min + (i - 1)*field%mesh%delta_eta
320  xcoords(i) = eta
321  values(i) = field%value_at_point(eta)*tag
322  end do
323 
324  print *, 'not implemented sll_gnuplot_curv_1d'
325 !!$ call sll_gnuplot_curv_1d( & ! a implementer
326 !!$ nptsx, &
327 !!$ xcoords, &
328 !!$ values, &
329 !!$ trim(field%name), &
330 !!$ tag, &
331 !!$ ierr )
332 
333  sll_deallocate_array(xcoords, ierr)
334  sll_deallocate_array(values, ierr)
335  end subroutine write_to_file_analytic_1d
336 
337  ! **************************************************************************
338  !
339  ! DISCRETE CASE
340  !
341  ! **************************************************************************
342 
344  ! array_1d, &
345  field_name, &
346  interpolator_1d, &
347  bc_left, &
348  bc_right, &
349  mesh, &
350  point_1d, &
351  sz_point) result(obj)
352 
353  type(sll_t_scalar_field_1d_discrete), pointer :: obj
354 ! sll_real64, dimension(:), intent(in), target :: array_1d
355  character(len=*), intent(in) :: field_name
356  class(sll_c_interpolator_1d), target :: interpolator_1d ! a implementer
357  type(sll_t_cartesian_mesh_1d), pointer :: mesh
358  sll_real64, dimension(:), optional :: point_1d
359  sll_int32, optional :: sz_point
360  ! sll_real64, dimension(:,:), optional :: point2d
361  sll_int32, intent(in) :: bc_left
362  sll_int32, intent(in) :: bc_right
363  sll_int32 :: ierr
364 
365  sll_allocate(obj, ierr)
366  call obj%init( &
367  ! array_1d, &
368  field_name, &
369  interpolator_1d, &
370  bc_left, &
371  bc_right, &
372  mesh, &
373  point_1d, &
374  sz_point)
376 
378  field, &
379  ! array_1d, &
380  field_name, &
381  interpolator_1d, &
382  bc_left, &
383  bc_right, &
384  mesh, &
385  point_1d, &
386  sz_point)
387 
388  class(sll_t_scalar_field_1d_discrete) :: field
389  ! sll_real64, dimension(:), intent(in), target :: array_1d
390  character(len=*), intent(in) :: field_name
391  class(sll_c_interpolator_1d), target :: interpolator_1d
392  type(sll_t_cartesian_mesh_1d), pointer :: mesh
393  sll_real64, dimension(:), optional :: point_1d
394  sll_int32, optional :: sz_point
395  sll_int32, intent(in) :: bc_left
396  sll_int32, intent(in) :: bc_right
397  sll_int32 :: ierr
398 
399  ! field%values => array_1d
400  field%interp_1d => interpolator_1d
401  ! field%mesh%written = .false.
402  field%name = trim(field_name)
403  field%bc_left = bc_left
404  field%bc_right = bc_right
405  field%mesh => mesh
406 
407  !SLL_ALLOCATE(point(sz_point),ierr)
408  sll_allocate(field%values(field%mesh%num_cells + 1), ierr)
409 
410 !!$ if ( present( point_1d) .and. present(sz_point)) then
411 !!$ print*, ' not implemented yet in initialize_scalar_field_1d_discrete'
412 !!$ stop
413 !!$ end if
414 !!$ if ( present( point_1d) .and. .not. present(sz_point)) then
415 !!$ print*, ' problem presence of point_1d and not the size in '
416 !!$ print*, 'initialize_scalar_field_1d_discrete'
417 !!$ stop
418 !!$ end if
419 
420 !!$ call field%interp_1d%compute_interpolants( & ! a implementer
421 !!$ array_1d, &
422 !!$ point_1d, &
423 !!$ sz_point )
424 
425  return
426  sll_assert(present(point_1d))
427  sll_assert(present(sz_point))
428 
430 
431  subroutine set_field_data_discrete_1d(field, values)
432  class(sll_t_scalar_field_1d_discrete), intent(inout) :: field
433  sll_real64, dimension(:), intent(in) :: values
434  if (size(field%values, 1) .ne. size(values, 1)) then
435  print *, 'WARNING, set_field_data_discrete_1d(), passed array ', &
436  'is not of the size originally declared for this field.'
437  end if
438  field%values(:) = values(:)
439  end subroutine set_field_data_discrete_1d
440 
441  ! need to do something about deallocating the field proper, when allocated
442  ! in the heap...
443  subroutine delete_field_1d_discrete(field)
444  class(sll_t_scalar_field_1d_discrete), intent(inout) :: field
445  ! just nullify pointers, nothing to deallocate that this object owns.
446  !print*, associated(field%values)
447  !print*, associated(field%interp_1d)
448  !print*, associated(field%point)
449 
450  nullify (field%values)
451  nullify (field%interp_1d)
452  !nullify(field%point) !not associated
453  end subroutine delete_field_1d_discrete
454 
456  class(sll_t_scalar_field_1d_discrete), intent(inout) :: field
457  call field%interp_1d%compute_interpolants(field%values)
458  end subroutine update_interp_coeffs_1d_discrete
459 
460  function get_cartesian_mesh_1d_discrete(field) result(res)
461  class(sll_t_scalar_field_1d_discrete), intent(in) :: field
462  type(sll_t_cartesian_mesh_1d), pointer :: res
463  res => field%mesh
464  end function get_cartesian_mesh_1d_discrete
465 
466  function value_at_pt_discrete_1d(field, eta)
467  class(sll_t_scalar_field_1d_discrete), intent(inout) :: field
468  sll_real64, intent(in) :: eta
469  sll_real64 :: value_at_pt_discrete_1d
470 
471  value_at_pt_discrete_1d = field%interp_1d%interpolate_from_interpolant_value(eta)
472  end function value_at_pt_discrete_1d
473 
474  function value_at_index_discrete_1d(field, i)
475  class(sll_t_scalar_field_1d_discrete), intent(inout) :: field
476  sll_int32, intent(in) :: i
477  sll_real64 :: eta
478  sll_real64 :: value_at_index_discrete_1d
479  eta = field%mesh%eta_min + real(i - 1, f64)*field%mesh%delta_eta
480  value_at_index_discrete_1d = field%interp_1d%interpolate_from_interpolant_value(eta)
481  end function value_at_index_discrete_1d
482 
484  class(sll_t_scalar_field_1d_discrete), intent(inout) :: field
485  sll_real64, intent(in) :: eta
487 
489  field%interp_1d%interpolate_from_interpolant_derivative_eta1(eta)
491 
493  class(sll_t_scalar_field_1d_discrete), intent(inout) :: field
494  sll_int32, intent(in) :: i
495  sll_real64 :: eta
497  eta = field%mesh%eta_min + real(i - 1, f64)*field%mesh%delta_eta
499  field%interp_1d%interpolate_from_interpolant_derivative_eta1(eta)
501 
502  subroutine write_to_file_discrete_1d(field, tag)
503  class(sll_t_scalar_field_1d_discrete), intent(inout) :: field
504  sll_int32, intent(in) :: tag
505  sll_int32 :: nptsx
506  sll_real64, dimension(:), allocatable :: xcoords
507  sll_real64, dimension(:), allocatable :: values
508  sll_real64 :: eta
509  type(sll_t_cartesian_mesh_1d), pointer :: mesh
510  sll_int32 :: i
511  sll_int32 :: ierr
512 
513  ! use the logical mesh information to find out the extent of the
514  ! domain and allocate the arrays for the plotter.
515  mesh => field%get_cartesian_mesh()
516  nptsx = mesh%num_cells + 1
517 
518  sll_allocate(xcoords(nptsx), ierr)
519  sll_allocate(values(nptsx), ierr)
520 
521  ! Fill the arrays with the needed information.
522  do i = 1, nptsx
523  eta = mesh%eta_min + (i - 1)*mesh%delta_eta
524  xcoords(i) = eta!field%x(eta)
525  values(i) = field%value_at_point(eta)*tag
526  end do
527 
528  print *, 'not implement the sll_gnuplot_curv_1d '
529 !!$ call sll_gnuplot_curv_1d( &
530 !!$ nptsx, &
531 !!$ xcoords, &
532 !!$ values, &
533 !!$ trim(field%name), &
534 !!$ tag, &
535 !!$ ierr )
536 
537  sll_deallocate_array(xcoords, ierr)
538  sll_deallocate_array(values, ierr)
539  end subroutine write_to_file_discrete_1d
540 
541 end module sll_m_scalar_field_1d
Cartesian mesh basic types.
Module for 1D interpolation and reconstruction.
Implements the geometry and mesh descriptor types.
subroutine set_field_data_analytic_1d(field, values)
subroutine delete_field_1d_discrete(field)
type(sll_t_scalar_field_1d_discrete) function, pointer, public sll_f_new_scalar_field_1d_discrete(field_name, interpolator_1d, bc_left, bc_right, mesh, point_1d, sz_point)
type(sll_t_scalar_field_1d_analytic) function, pointer, public sll_f_new_scalar_field_1d_analytic(func, field_name, bc_left, bc_right, mesh, func_params, first_derivative)
real(kind=f64) function value_at_pt_analytic_1d(field, eta)
real(kind=f64) function derivative_value_at_pt_analytic_1d(field, eta)
type(sll_t_cartesian_mesh_1d) function, pointer get_cartesian_mesh_1d_analytic(field)
subroutine update_interp_coeffs_1d_discrete(field)
function value_at_index_discrete_1d(field, i)
type(sll_t_cartesian_mesh_1d) function, pointer get_cartesian_mesh_1d_discrete(field)
subroutine update_interp_coeffs_1d_analytic(field)
subroutine write_to_file_discrete_1d(field, tag)
subroutine delete_field_1d_analytic(field)
subroutine set_field_data_discrete_1d(field, values)
subroutine initialize_scalar_field_1d_analytic(field, func, field_name, bc_left, bc_right, mesh, func_params, first_derivative)
function derivative_value_at_index_discrete_1d(field, i)
subroutine write_to_file_analytic_1d(field, tag)
subroutine initialize_scalar_field_1d_discrete(field, field_name, interpolator_1d, bc_left, bc_right, mesh, point_1d, sz_point)
real(kind=f64) function value_at_index_analytic_1d(field, i)
function derivative_value_at_pt_discrete_1d(field, eta)
real(kind=f64) function derivative_value_at_index_analytic_1d(field, i)
function value_at_pt_discrete_1d(field, eta)
Module to select the kind parameter.
Abstract class for 1D interpolation and reconstruction.
    Report Typos and Errors