12 use fftw_mod, only : c_double_complex, c_ptr, fftw_backward, fftw_forward, fftw_estimate, fftw_plan_many_dft_r2c, &
13 fftw_plan_many_dft_c2r, fftw_execute_dft_c2r, fftw_execute_dft_r2c, fftw_destroy_plan
14 use mpi
, only : mpi_double_complex, mpi_int, mpi_comm_self
23 integer :: my_pencil_size(3), process_decomposition_layout(3), my_process_location(3), dim
24 integer,
dimension(:),
allocatable :: send_sizes, send_offsets, recv_sizes, recv_offsets
25 integer,
dimension(:,:),
allocatable :: recv_dims, send_dims
37 complex(C_DOUBLE_COMPLEX),
dimension(:,:,:),
contiguous,
pointer ::
buffer1,
buffer2 53 integer,
intent(out) :: my_y_start, my_x_start
54 integer :: initialise_pencil_fft(3)
56 integer :: ierr, y_distinct_sizes(current_state%parallel%dim_sizes(
y_index)), &
57 x_distinct_sizes(current_state%parallel%dim_sizes(
x_index))
62 if (current_state%parallel%dim_sizes(
y_index) .gt. 1 .and. current_state%parallel%dim_sizes(
x_index) .gt. 1)
then 63 call mpi_cart_sub(current_state%parallel%neighbour_comm, (/1,0/),
dim_y_comm, ierr)
64 call mpi_cart_sub(current_state%parallel%neighbour_comm, (/0,1/),
dim_x_comm, ierr)
66 call mpi_allgather(current_state%local_grid%size(
y_index), 1, mpi_int, y_distinct_sizes, 1, mpi_int,
dim_y_comm, ierr)
67 call mpi_allgather(current_state%local_grid%size(
x_index), 1, mpi_int, x_distinct_sizes, 1, mpi_int,
dim_x_comm, ierr)
68 else if (current_state%parallel%dim_sizes(
y_index) .gt. 1)
then 69 dim_y_comm=current_state%parallel%monc_communicator
71 call mpi_allgather(current_state%local_grid%size(
y_index), 1, mpi_int, y_distinct_sizes, 1, mpi_int,
dim_y_comm, ierr)
72 x_distinct_sizes=current_state%local_grid%size(
x_index)
73 else if (current_state%parallel%dim_sizes(
x_index) .gt. 1)
then 75 dim_x_comm=current_state%parallel%monc_communicator
76 y_distinct_sizes=current_state%local_grid%size(
y_index)
77 call mpi_allgather(current_state%local_grid%size(
x_index), 1, mpi_int, x_distinct_sizes, 1, mpi_int,
dim_x_comm, ierr)
81 y_distinct_sizes=current_state%local_grid%size(
y_index)
82 x_distinct_sizes=current_state%local_grid%size(
x_index)
93 integer,
intent(in) :: monc_communicator
116 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(inout) :: source_data
117 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(out) :: target_data
139 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(in) :: source_data
140 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(out) :: target_data
175 integer,
dimension(:),
intent(in) :: y_distinct_sizes, x_distinct_sizes
198 y_distinct_sizes,
backward, (/ -1 /))
215 type(
pencil_transposition) function create_transposition(global_grid, existing_transposition, new_pencil_dim,&
216 process_dim_sizes, direction, extended_dimensions)
219 integer,
dimension(:),
intent(in) :: process_dim_sizes
220 integer,
intent(in) :: new_pencil_dim, direction, extended_dimensions(:)
223 new_pencil_dim, existing_transposition%dim, existing_transposition%process_decomposition_layout)
226 existing_transposition%dim, existing_transposition%my_process_location)
228 create_transposition%my_pencil_size=
determine_pencil_size(new_pencil_dim, create_transposition%process_decomposition_layout,&
229 create_transposition%my_process_location, existing_transposition, global_grid, extended_dimensions)
231 allocate(create_transposition%send_dims(3, create_transposition%process_decomposition_layout(existing_transposition%dim)), &
232 create_transposition%recv_dims(3, create_transposition%process_decomposition_layout(existing_transposition%dim)))
235 existing_transposition%my_pencil_size, create_transposition%process_decomposition_layout, &
236 global_grid, extended_dimensions, create_transposition%send_dims)
238 create_transposition%my_pencil_size, create_transposition%process_decomposition_layout, create_transposition%recv_dims)
241 existing_transposition%process_decomposition_layout, global_grid, extended_dimensions, create_transposition%recv_dims)
243 existing_transposition%my_pencil_size, existing_transposition%process_decomposition_layout, &
244 create_transposition%send_dims)
247 allocate(create_transposition%send_sizes(
size(create_transposition%send_dims, 2)), &
248 create_transposition%send_offsets(
size(create_transposition%send_sizes)), &
249 create_transposition%recv_sizes(
size(create_transposition%recv_dims, 2)), &
250 create_transposition%recv_offsets(
size(create_transposition%recv_sizes)))
257 create_transposition%dim=new_pencil_dim
267 type(model_state_type),
target,
intent(inout) :: current_state
268 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(inout) :: source_data
269 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(out) :: real_buffer
270 complex(C_DOUBLE_COMPLEX),
dimension(:,:,:),
contiguous,
pointer,
intent(out) :: buffer
289 type(model_state_type),
target,
intent(inout) :: current_state
290 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(inout) :: source_data
291 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(out) :: real_buffer
292 complex(C_DOUBLE_COMPLEX),
dimension(:,:,:),
contiguous,
pointer,
intent(out) :: buffer
310 type(model_state_type),
target,
intent(inout) :: current_state
311 complex(C_DOUBLE_COMPLEX),
dimension(:,:,:),
contiguous,
pointer,
intent(out) :: buffer2
312 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(inout) :: buffer1, buffer3
332 type(model_state_type),
target,
intent(inout) :: current_state
333 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(inout) :: source_data
334 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(out) :: real_buffer
335 complex(C_DOUBLE_COMPLEX),
dimension(:,:,:),
contiguous,
pointer,
intent(out) :: buffer
357 subroutine transpose_to_pencil(transposition_description, source_dims, communicator, direction, source_data, target_data)
359 integer,
intent(in) :: source_dims(3), communicator, direction
360 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(in) :: source_data
361 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(out) :: target_data
364 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
allocatable :: real_temp
365 real(kind=DEFAULT_PRECISION),
dimension(:),
allocatable :: real_temp2
368 allocate(real_temp(
size(source_data,3),
size(source_data,2),
size(source_data,1)), &
369 real_temp2(product(transposition_description%my_pencil_size)+1))
373 call mpi_alltoallv(real_temp, transposition_description%send_sizes, transposition_description%send_offsets, &
374 precision_type, real_temp2, transposition_description%recv_sizes, transposition_description%recv_offsets, &
375 precision_type, communicator, ierr)
376 call contiguise_data(transposition_description, (/source_dims(3), source_dims(2), source_dims(1)/), direction, &
377 source_real_buffer=real_temp2, target_real_buffer=target_data)
378 deallocate(real_temp, real_temp2)
389 subroutine contiguise_data(transposition_description, source_dims, direction, source_real_buffer, target_real_buffer)
390 integer,
intent(in) :: source_dims(3), direction
392 real(kind=DEFAULT_PRECISION),
dimension(:),
intent(in) :: source_real_buffer
393 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(out) :: target_real_buffer
395 integer :: number_blocks, i, j, k, n, index_prefix, index_prefix_dim, block_offset, source_index
397 number_blocks=
size(transposition_description%recv_sizes)
400 index_prefix_dim=merge(2,1, direction ==
forward)
403 index_prefix=index_prefix+transposition_description%recv_dims(source_dims(index_prefix_dim), i-1)
404 block_offset=block_offset+transposition_description%recv_sizes(i-1)
407 do j=1, transposition_description%recv_dims(source_dims(3), i)
408 do k=1, transposition_description%recv_dims(source_dims(1), i)
409 do n=1, transposition_description%recv_dims(source_dims(2), i)
410 source_index=block_offset+(j-1)* transposition_description%recv_dims(source_dims(1), i)* &
411 transposition_description%recv_dims(source_dims(2), i)+ (n-1)* &
412 transposition_description%recv_dims(source_dims(1), i)+k
414 target_real_buffer(index_prefix+n, k, j)=source_real_buffer(source_index)
416 target_real_buffer(index_prefix+k, j, n)=source_real_buffer(source_index)
430 subroutine perform_r2c_fft(source_data, transformed_data, row_size, num_rows, plan_id)
431 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
contiguous,
pointer,
intent(inout) :: source_data
432 complex(C_DOUBLE_COMPLEX),
dimension(:,:,:),
contiguous,
pointer,
intent(inout) :: transformed_data
433 integer,
intent(in) :: row_size, num_rows, plan_id
436 fftw_plan(plan_id) = fftw_plan_many_dft_r2c(1, (/row_size/), num_rows, source_data, (/row_size/), 1, row_size, &
437 transformed_data, (/row_size/), 1, row_size/2+1, fftw_estimate)
440 call fftw_execute_dft_r2c(
fftw_plan(plan_id), source_data, transformed_data)
449 subroutine perform_c2r_fft(source_data, transformed_data, row_size, num_rows, plan_id)
450 complex(C_DOUBLE_COMPLEX),
dimension(:,:,:),
contiguous,
pointer,
intent(inout) :: source_data
451 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
contiguous,
pointer,
intent(inout) :: transformed_data
452 integer,
intent(in) :: row_size, num_rows, plan_id
457 fftw_plan(plan_id) = fftw_plan_many_dft_c2r(1, (/row_size/), num_rows, source_data, (/row_size/2+1/), 1, row_size/2+1, &
458 transformed_data, (/row_size/), 1, row_size, fftw_estimate)
461 call fftw_execute_dft_c2r(
fftw_plan(plan_id), source_data, transformed_data)
469 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(in) :: real_source
470 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(out) :: real_target
474 do i=1,
size(real_source,2)
475 real_target(:,i,:)=transpose(real_source(:,i,:))
489 global_grid, extended_dimensions, specific_sizes_per_dim)
490 integer,
intent(in) :: existing_pencil_dim, existing_pencil_size(:), new_pencil_procs_per_dim(:), extended_dimensions(:)
491 type(global_grid_type),
intent(inout) :: global_grid
492 integer,
dimension(:,:),
intent(inout) :: specific_sizes_per_dim
494 integer :: i, split_size, split_remainder, j, s
497 if (i == existing_pencil_dim)
then 498 s=global_grid%size(i)
500 split_size = s / new_pencil_procs_per_dim(i)
501 split_remainder = s - split_size * new_pencil_procs_per_dim(i)
502 do j=1,new_pencil_procs_per_dim(existing_pencil_dim)
503 specific_sizes_per_dim(i,j)=merge(split_size+1, split_size, j .le. split_remainder)
506 specific_sizes_per_dim(i,:) = existing_pencil_size(i)
514 integer,
intent(in) :: source_sizes(:)
515 integer,
dimension(:),
intent(inout) :: determined_offsets
519 determined_offsets(1)=0
520 do i=2,
size(source_sizes)
521 determined_offsets(i)=determined_offsets(i-1)+source_sizes(i-1)
532 integer,
intent(in) :: new_pencil_dim, existing_pencil_dim, existing_pencil_procs(3)
533 integer :: determine_pencil_process_dimensions(3)
538 if (i == new_pencil_dim)
then 539 determine_pencil_process_dimensions(i)=1
540 else if (i == existing_pencil_dim)
then 541 determine_pencil_process_dimensions(i)=existing_pencil_procs(new_pencil_dim)
543 determine_pencil_process_dimensions(i)=existing_pencil_procs(i)
554 integer,
intent(in) :: new_pencil_dim, existing_pencil_dim, existing_locations(3)
555 integer :: determine_my_pencil_location(3)
560 if (i == new_pencil_dim)
then 561 determine_my_pencil_location(i)=1
562 else if (i == existing_pencil_dim)
then 563 determine_my_pencil_location(i)=existing_locations(new_pencil_dim)
565 determine_my_pencil_location(i)=existing_locations(i)
574 integer,
dimension(:,:),
intent(in) :: dims
575 integer,
dimension(:),
intent(inout) :: concatenated_dim_sizes
580 concatenated_dim_sizes(i)=product(dims(:,i))
593 my_pencil_size, pencil_processes_per_dim, specific_sizes_per_dim)
594 integer,
intent(in) :: new_pencil_dim, existing_pencil_dim, proc_sizes(:), my_pencil_size(:), pencil_processes_per_dim(:)
595 integer,
dimension(:,:),
intent(inout) :: specific_sizes_per_dim
599 do i=1,pencil_processes_per_dim(existing_pencil_dim)
601 if (j==new_pencil_dim)
then 602 specific_sizes_per_dim(j, i)=proc_sizes(i)
604 specific_sizes_per_dim(j, i)=my_pencil_size(j)
614 type(model_state_type),
intent(inout) :: current_state
632 function determine_pencil_size(new_pencil_dim, pencil_process_layout, my_pencil_location, existing_transposition,&
633 global_grid, extended_dimensions)
636 integer,
intent(in) :: new_pencil_dim, pencil_process_layout(3), my_pencil_location(3), extended_dimensions(:)
637 type(global_grid_type),
intent(inout) :: global_grid
638 integer :: determine_pencil_size(3)
640 integer :: i, split_size, split_remainder, s
643 if (i == new_pencil_dim)
then 646 determine_pencil_size(i)=(global_grid%size(new_pencil_dim)/2+1)*2
648 determine_pencil_size(i)=global_grid%size(new_pencil_dim)
650 else if (i == existing_transposition%dim)
then 651 s=global_grid%size(i)
654 split_size=s/pencil_process_layout(i)
655 split_remainder=s - split_size * pencil_process_layout(i)
656 determine_pencil_size(i)=merge(split_size+1, split_size, my_pencil_location(i)+1 .le. split_remainder)
658 determine_pencil_size(i)=existing_transposition%my_pencil_size(i)
668 integer,
intent(in) :: dimension, extended_dimensions(:)
671 do i=1,
size(extended_dimensions)
672 if (extended_dimensions(i) == dimension)
then 685 integer,
dimension(:),
intent(in) :: process_dim_sizes
686 integer,
dimension(size(process_dim_sizes)) :: normal_to_extended_process_dim_sizes
688 integer :: temp_total, split_size, remainder
690 temp_total=(sum(process_dim_sizes) /2 + 1) * 2
691 split_size=temp_total/
size(process_dim_sizes)
692 remainder=temp_total - split_size*
size(process_dim_sizes)
694 normal_to_extended_process_dim_sizes=split_size
695 normal_to_extended_process_dim_sizes(1:remainder)=split_size+1
705 complex(C_DOUBLE_COMPLEX),
dimension(:,:,:),
intent(in) :: complex_data
706 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(out) :: real_data
710 do i=1,
size(real_data,3)
711 do j=1,
size(real_data,2)
712 do k=1,
size(real_data,1),2
713 real_data(k,j,i)=
real(real(complex_data((k+1)/2,j,i)), kind=default_precision)
714 real_data(k+1,j,i)=
real(aimag(complex_data((k+1)/2,j,i)), kind=default_precision)
727 real(kind=DEFAULT_PRECISION),
dimension(:,:,:),
intent(in) :: real_data
728 complex(C_DOUBLE_COMPLEX),
dimension(:,:,:),
contiguous,
pointer,
intent(out) :: complex_data
732 complex_data=cmplx(0.0d0, 0.0d0, kind=c_double_complex)
734 do i=1,
size(real_data,3)
735 do j=1,
size(real_data,2)
736 do k=1,
size(real_data,1),2
737 complex_data((k+1)/2,j,i)=cmplx(real_data(k,j,i), real_data(k+1,j,i), kind=c_double_complex)
752 type(model_state_type),
intent(inout) :: current_state
753 integer,
intent(in) :: dimension
755 integer complex_size, distributed_size, remainder, larger_nums, smaller_nums
757 complex_size=(current_state%global_grid%size(dimension)/2+1)*2
758 distributed_size=complex_size / current_state%parallel%dim_sizes(dimension)
759 remainder=complex_size - distributed_size * current_state%parallel%dim_sizes(dimension)
760 larger_nums=min(remainder, current_state%parallel%my_coords(dimension))
761 smaller_nums=current_state%parallel%my_coords(dimension)-remainder
762 deduce_my_global_start=((distributed_size+1)*larger_nums + merge(distributed_size*smaller_nums, 0, smaller_nums .gt. 0)) + 1
Wrapper around the FFTW3 bindings. This will privatise by default all of FFTW3 apart from the calls t...
integer function, dimension(3) determine_pencil_size(new_pencil_dim, pencil_process_layout, my_pencil_location, existing_transposition, global_grid, extended_dimensions)
Deduces the size of my (local) pencil based upon the new decomposition. This depends heavily on the c...
integer, public precision_type
subroutine contiguise_data(transposition_description, source_dims, direction, source_real_buffer, target_real_buffer)
Contiguises from c,b,a to b,c,a (forwards) or c,a,b (backwards) where these are defined by the source...
subroutine determine_my_process_sizes_per_dim(existing_pencil_dim, existing_pencil_size, new_pencil_procs_per_dim, global_grid, extended_dimensions, specific_sizes_per_dim)
Determines the number of elements to on my process per dimension which either need to be sent to (for...
type(pencil_transposition) function create_transposition(global_grid, existing_transposition, new_pencil_dim, process_dim_sizes, direction, extended_dimensions)
Creates a specific pencil transposition description. It is maybe more a decomposition description...
real(kind=default_precision), dimension(:,:,:), pointer, contiguous fft_in_x_buffer
real(kind=default_precision), dimension(:,:,:), pointer, contiguous fft_in_y_buffer
subroutine rearrange_data_for_sending(real_source, real_target)
Rearranges data for sending, transposing a,b,c into c,b,a . This is done as alltoall splits on dimens...
type(pencil_transposition) y_from_z_2_transposition
logical function is_extended_dimension(dimension, extended_dimensions)
Determines whether or not the specific dimension is in the list of extended dimensions.
integer function deduce_my_global_start(current_state, dimension)
Determines my global start coordinate in Fourier space. This is required for cos y and cos x calculat...
subroutine, public finalise_pencil_fft(monc_communicator)
Cleans up allocated buffer memory.
complex(c_double_complex), dimension(:,:,:), pointer, contiguous buffer2
integer, parameter, public default_precision
MPI communication type which we use for the prognostic and calculation data.
integer, parameter, public z_index
Grid index parameters.
type(pencil_transposition) y_from_x_transposition
Contains common definitions for the data and datatypes used by MONC.
The ModelState which represents the current state of a run.
integer dim_x_comm
Communicators for each dimension.
subroutine concatenate_dimension_sizes(dims, concatenated_dim_sizes)
Concatenates sizes in multiple dimensions for each target process (in a row or column) into a product...
real(kind=default_precision), dimension(:,:,:), pointer, contiguous real_buffer3
subroutine determine_matching_process_dimensions(new_pencil_dim, existing_pencil_dim, proc_sizes, my_pencil_size, pencil_processes_per_dim, specific_sizes_per_dim)
Determines the sizes per dimension on the matching process either to receive from (forward transposit...
type(pencil_transposition) x_from_y_transposition
type(c_ptr), dimension(4) fftw_plan
integer function, dimension(size(process_dim_sizes)) normal_to_extended_process_dim_sizes(process_dim_sizes)
Transforms real process dimension sizes into their real after FFT complex->real transformation. The way this works is that it goes from n to (n/2+1)*2 numbers which is distributed amongst the processes deterministically.
subroutine, public perform_forward_3dfft(current_state, source_data, target_data)
Performs a forward 3D FFT and currently results in target data which is the X, Z, Y oriented pencil N...
integer function, dimension(3), public initialise_pencil_fft(current_state, my_y_start, my_x_start)
Initialises the pencil FFT functionality, this will create the transposition structures needed...
type(pencil_transposition) y_from_z_transposition
subroutine perform_c2r_fft(source_data, transformed_data, row_size, num_rows, plan_id)
Performs the complex to real (backwards) FFT.
subroutine initialise_transpositions(current_state, y_distinct_sizes, x_distinct_sizes)
Initialises the pencil transpositions, from a pencil in one dimension to that in another.
subroutine initialise_buffers()
Initialises memory for the buffers used in the FFT.
real(kind=default_precision), dimension(:,:,:), pointer, contiguous real_buffer2
Describes a specific pencil transposition, from one pencil decomposition to another.
subroutine transpose_and_backward_fft_in_y(current_state, source_data, buffer, real_buffer)
Performs the backwards FFT in Y and then transposes to Z pencil. The FFT requires complex numbers whi...
integer, parameter backward
Transposition directions.
type(pencil_transposition) z_from_y_transposition
type(pencil_transposition) z_from_y_2_transposition
subroutine transpose_and_forward_fft_in_x(current_state, buffer1, buffer2, buffer3)
Performs the transposition and forward FFT in the x dimension. After the FFT the complex space is con...
real(kind=default_precision), dimension(:,:,:), pointer, contiguous real_buffer1
type(pencil_transposition) function create_initial_transposition_description(current_state)
Creates an initial transposition representation of the Z pencil that MONC is normally decomposed in...
subroutine, public perform_backwards_3dfft(current_state, source_data, target_data)
Performs a backwards 3D FFT and currently results in target data which is the X, Z, Y oriented pencil Note that the source_data here takes no account for the halo, it is up to caller to exclude this. This does no FFT in Z, but transposes to Y, does FFT in Y, then transposes to X and performs an FFT in that dimension. Pencil decomposition is used which has already been set up.
subroutine transpose_to_pencil(transposition_description, source_dims, communicator, direction, source_data, target_data)
Transposes globally to a new pencil decomposition. This goes from the source dimensions a...
subroutine convert_real_to_complex(real_data, complex_data)
Converts reals into their complex representation, this is called for backwards FFTs as we need to fee...
complex(c_double_complex), dimension(:,:,:), pointer, contiguous buffer1
This Pencil FFT performs 3D forward and backwards FFTs using pencil decomposition. It uses FFTW for the actual FFT kernel and this module contains all the data decomposition around this. There is no FFT required in Z, so this performs FFTs in Y and X (in that order forward and reversed backwards.) The data decomposition is the complex aspect, there is the concept of forward and backwards transformations. Forward transformations will go from pencil Z to Y to X and the backwards transformations undo these, so go from X to Y to Z. Note that we use quite a lot of buffer space here, this could be cut down if Y=X dimensions so some optimisation on memory could be done there in that case.
Functionality to support the different types of grid and abstraction between global grids and local o...
type(pencil_transposition) x_from_y_2_transposition
subroutine determine_offsets_from_size(source_sizes, determined_offsets)
Simple helper function to deduce send or receive offsets from the sizes.
integer function, dimension(3) determine_pencil_process_dimensions(new_pencil_dim, existing_pencil_dim, existing_pencil_procs)
Determines the number of processes in each dimension for the target decomposition. This depends heavily on the existing decomposition, as we basically contiguise our pencil dimension and decompose the existing pencil dimension. The third dimension remains unchanged.
integer function, dimension(3) determine_my_pencil_location(new_pencil_dim, existing_pencil_dim, existing_locations)
Determines my location for each dimension in the new pencil decomposition. I.e. which block I am oper...
subroutine transpose_and_backward_fft_in_x(current_state, source_data, buffer, real_buffer)
Performs the backwards FFT in X and then transposes to Y pencil. The FFT requires complex numbers whi...
type(pencil_transposition) y_from_x_2_transposition
subroutine transpose_and_forward_fft_in_y(current_state, source_data, buffer, real_buffer)
Performs the transposition and forward FFT in the y dimension then converts back to real numbers...
The model state which represents the current state of a run.
integer, parameter, public y_index
subroutine perform_r2c_fft(source_data, transformed_data, row_size, num_rows, plan_id)
Actually performs a forward real to complex FFT.
integer, parameter forward
logical, dimension(4) fftw_plan_initialised
integer, parameter, public x_index
subroutine convert_complex_to_real(complex_data, real_data)
Converts complex representation to its real data counterpart and is called after each forward FFT...