Think of allocatable arrays like expandable luggage – you don’t know the exact size you’ll need until runtime, so you adjust the size dynamically. In scientific computing, problem sizes often depend on user input, file data, or computational requirements determined at runtime.
Learn dynamic memory with OpenACC, master ALLOCATE/DEALLOCATE patterns, understand variable-sized problems, and see the allocatable array lifecycle on host and device.
The Dynamic Memory Problem
Many scientific problems have unknown sizes at compile time:
Climate simulation: Grid size depends on resolution choice
Finite element: Mesh size based on geometry complexity
Machine learning: Dataset size varies by problem
Molecular dynamics: Number of particles from input file
Visual: Static vs Allocatable Arrays
Static Arrays (Fixed Size):
Program: integer, parameter :: n = 1000
real :: data(n) ← Fixed at compile time
Memory: [████████████████████████████] Always 1000 elements
Allocatable Arrays (Dynamic Size):
Program: integer :: n
real, allocatable :: data(:) ← Size determined at runtime
Runtime: n = get_problem_size()
allocate(data(n))
Memory: [████] or [████████████████] or [████████████████████████]
Size fits actual need!
Fortran Allocatable Array Basics
Declaration and Allocation
! Declaration - no memory allocated yet
real, allocatable :: dynamic_array(:)
integer, allocatable :: work_space(:, :)
! Allocation at runtime
integer :: problem_size, rows, cols
problem_size = 50000 ! From user input or computation
allocate(dynamic_array(problem_size))
rows = 200
cols = 300
allocate(work_space(rows, cols))
Deallocation
! Free memory when done
deallocate(dynamic_array)
deallocate(work_space)
Basic Allocatable Array with OpenACC
program basic_allocatable
implicit none
integer :: n, i
real, allocatable :: data(:), result(:)
write(*,*) 'Enter problem size:'
read(*,*) n
! Allocate arrays based on user input
allocate(data(n))
allocate(result(n))
! Initialize data
do i = 1, n
data(i) = real(i) * 0.5
end do
! OpenACC automatically handles allocatable array bounds
!$acc parallel loop copyin(data) copyout(result)
do i = 1, n
result(i) = sqrt(data(i)) * 2.0 + 1.0
end do
!$acc end parallel loop
write(*,*) 'Processed', n, 'elements'
write(*,*) 'Sample result:', result(n/2)
! Clean up
deallocate(data)
deallocate(result)
end program
Visual: Allocatable Array Lifecycle
Allocatable Array Lifecycle:
1. Declaration Phase:
Host: data(:) ← Not allocated (no memory)
GPU: ─ ← No corresponding memory
2. Allocation Phase:
Host: allocate(data(5000))
Host: [████████████████████████████] ← 5000 elements allocated
GPU: ─ ← Still no GPU memory
3. OpenACC Transfer Phase:
!$acc parallel loop copyin(data)
Host: [████████████████████████████]
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
GPU: [████████████████████████████] ← Auto-allocated with same size
4. Computation Phase:
GPU: [████████████████████████████] ← Processing on device
(OpenACC knows the correct size automatically)
5. Transfer Back Phase:
GPU: [████████████████████████████]
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
Host: [████████████████████████████] ← Results copied back
6. Deallocation Phase:
deallocate(data)
Host: ─ ← Memory freed
GPU: ─ ← GPU memory auto-freed
Problem-Size Dependent Allocation
program adaptive_sizing
implicit none
integer :: problem_type, n, i, j
real, allocatable :: matrix_a(:,:), matrix_b(:,:), result(:,:)
write(*,*) 'Select problem size:'
write(*,*) '1: Small (100x100)'
write(*,*) '2: Medium (500x500)'
write(*,*) '3: Large (2000x2000)'
read(*,*) problem_type
! Determine size based on problem type
select case(problem_type)
case(1)
n = 100
case(2)
n = 500
case(3)
n = 2000
case default
n = 100
end select
write(*,'(A,I0,A,I0)') 'Allocating ', n, '×', n, ' matrices'
! Allocate matrices of appropriate size
allocate(matrix_a(n, n))
allocate(matrix_b(n, n))
allocate(result(n, n))
! Initialize matrices
do j = 1, n
do i = 1, n
matrix_a(i, j) = real(i + j) * 0.01
matrix_b(i, j) = real(i * j) * 0.001
end do
end do
! Process with OpenACC - automatic size detection
!$acc parallel loop collapse(2) copyin(matrix_a, matrix_b) copyout(result)
do j = 1, n
do i = 1, n
result(i, j) = matrix_a(i, j) + matrix_b(i, j) * 2.0
end do
end do
!$acc end parallel loop
write(*,*) 'Computation complete'
write(*,*) 'Sample result:', result(n/2, n/2)
deallocate(matrix_a)
deallocate(matrix_b)
deallocate(result)
end program
File-Based Dynamic Allocation
program file_based_allocation
implicit none
integer :: n, i, iostat
real, allocatable :: input_data(:), processed_data(:)
! Read problem size from file header
open(10, file='problem_data.txt', status='old', iostat=iostat)
if (iostat /= 0) then
write(*,*) 'Creating sample data file...'
! Create sample file for demo
open(10, file='problem_data.txt', status='replace')
write(10,*) 7500 ! Problem size
do i = 1, 7500
write(10,*) sin(real(i) * 0.001) * 100.0
end do
close(10)
open(10, file='problem_data.txt', status='old')
end if
! Read size and allocate accordingly
read(10,*) n
write(*,'(A,I0,A)') 'File contains ', n, ' data points'
allocate(input_data(n))
allocate(processed_data(n))
! Read all data
do i = 1, n
read(10,*) input_data(i)
end do
close(10)
write(*,*) 'Data loaded, processing on GPU...'
! Process with OpenACC
!$acc parallel loop copyin(input_data) copyout(processed_data)
do i = 1, n
processed_data(i) = abs(input_data(i)) + sqrt(abs(input_data(i))) * 0.5
end do
!$acc end parallel loop
write(*,*) 'Processing complete'
write(*,*) 'First result:', processed_data(1)
write(*,*) 'Last result:', processed_data(n)
deallocate(input_data)
deallocate(processed_data)
end program
Allocatable Arrays in Data Regions
program allocatable_data_regions
implicit none
integer :: n, operation, i
real, allocatable :: work_array(:), temp_1(:), temp_2(:)
n = 10000
write(*,'(A,I0,A)') 'Working with ', n, ' element arrays'
! Allocate all working arrays
allocate(work_array(n))
allocate(temp_1(n))
allocate(temp_2(n))
! Initialize
do i = 1, n
work_array(i) = cos(real(i) * 0.001) * 50.0
end do
! Multiple operations in data region with allocatable arrays
!$acc data copy(work_array) create(temp_1, temp_2)
write(*,*) 'Performing multiple operations in data region...'
! Operation 1: Square and scale
!$acc parallel loop
do i = 1, n
temp_1(i) = work_array(i) * work_array(i) * 0.01
end do
!$acc end parallel loop
! Operation 2: Apply function
!$acc parallel loop
do i = 1, n
temp_2(i) = sqrt(abs(temp_1(i))) + 2.0
end do
!$acc end parallel loop
! Operation 3: Combine results back to work_array
!$acc parallel loop
do i = 1, n
work_array(i) = temp_1(i) + temp_2(i) * 0.5
end do
!$acc end parallel loop
write(*,*) '✓ All operations completed with arrays resident on GPU'
!$acc end data
write(*,*) 'Final result sample:', work_array(5000)
deallocate(work_array)
deallocate(temp_1)
deallocate(temp_2)
end program
Dynamic Reallocation Pattern
program dynamic_reallocation
implicit none
integer :: current_size, new_size, i
real, allocatable :: growing_array(:)
real :: growth_factor = 1.5
! Start with small array
current_size = 1000
allocate(growing_array(current_size))
! Initialize
do i = 1, current_size
growing_array(i) = real(i)
end do
write(*,'(A,I0)') 'Initial array size: ', current_size
! Process current array
!$acc parallel loop copy(growing_array)
do i = 1, current_size
growing_array(i) = growing_array(i) * 2.0 + 1.0
end do
!$acc end parallel loop
! Simulate need for larger array
new_size = int(current_size * growth_factor)
write(*,'(A,I0)') 'Reallocating to size: ', new_size
block
real :: temp_data(current_size)
! Save current data
temp_data = growing_array(1:current_size)
! Reallocate with new size
deallocate(growing_array)
allocate(growing_array(new_size))
! Restore existing data and initialize new elements
growing_array(1:current_size) = temp_data
do i = current_size + 1, new_size
growing_array(i) = real(i) * 0.5 ! Initialize new elements
end do
end block
current_size = new_size
! Process expanded array
!$acc parallel loop copy(growing_array)
do i = 1, current_size
growing_array(i) = sqrt(abs(growing_array(i)))
end do
!$acc end parallel loop
write(*,*) 'Array successfully expanded and processed'
write(*,*) 'Final size:', current_size
write(*,*) 'Sample values:', growing_array(1), growing_array(current_size)
deallocate(growing_array)
end program
Multi-dimensional Allocatable Arrays
program multidim_allocatable
implicit none
integer :: nx, ny, nz, i, j, k
real, allocatable :: field_3d(:,:,:), result_3d(:,:,:)
! Get dimensions from user or computation
nx = 50
ny = 60
nz = 40
write(*,'(A,I0,A,I0,A,I0,A)') 'Allocating 3D array: ', nx, '×', ny, '×', nz
allocate(field_3d(nx, ny, nz))
allocate(result_3d(nx, ny, nz))
! Initialize 3D field
do k = 1, nz
do j = 1, ny
do i = 1, nx
field_3d(i, j, k) = real(i + j + k) * 0.1
end do
end do
end do
! 3D processing with OpenACC
!$acc parallel loop collapse(3) copyin(field_3d) copyout(result_3d)
do k = 1, nz
do j = 1, ny
do i = 1, nx
result_3d(i, j, k) = field_3d(i, j, k) + &
sin(field_3d(i, j, k) * 0.1) * 10.0
end do
end do
end do
!$acc end parallel loop
write(*,*) '3D processing complete'
write(*,*) 'Center point result:', result_3d(nx/2, ny/2, nz/2)
deallocate(field_3d)
deallocate(result_3d)
end program
Error Handling with Allocatable Arrays
program safe_allocation
implicit none
integer :: n, alloc_status, i
real, allocatable :: safe_array(:)
character(len=100) :: error_msg
n = 100000000 ! Large size that might fail
write(*,'(A,I0,A)') 'Attempting to allocate ', n, ' elements'
allocate(safe_array(n), stat=alloc_status, errmsg=error_msg)
if (alloc_status /= 0) then
write(*,*) 'Allocation failed:', trim(error_msg)
write(*,*) 'Trying smaller size...'
n = n / 10 ! Try smaller size
allocate(safe_array(n), stat=alloc_status)
if (alloc_status /= 0) then
write(*,*) 'Still failed - using minimal size'
n = 1000
allocate(safe_array(n))
end if
end if
write(*,'(A,I0,A)') 'Successfully allocated ', n, ' elements'
! Initialize and process
do i = 1, n
safe_array(i) = real(i) * 0.001
end do
!$acc parallel loop copy(safe_array)
do i = 1, n
safe_array(i) = safe_array(i) * safe_array(i) + 1.0
end do
!$acc end parallel loop
write(*,*) 'Processing successful'
write(*,*) 'Sample result:', safe_array(min(1000, n))
if (allocated(safe_array)) then
deallocate(safe_array)
write(*,*) 'Memory properly deallocated'
end if
end program
Performance Considerations
Memory Allocation Overhead
Stack arrays (fixed): Near-zero allocation time
Allocatable arrays: Small overhead per allocation
Frequent reallocation: Performance cost - avoid if possible
Large allocations: May require memory defragmentation
Best Practices Table
Scenario | Recommendation | Reason |
---|---|---|
Known size range | Pre-allocate maximum size | Avoid reallocation overhead |
Unknown size | Allocate once, process in chunks | Balance memory and performance |
Growing arrays | Use growth factor (1.5x – 2x) | Reduce number of reallocations |
File-based | Read size first, allocate once | Single allocation is efficient |
Visual: OpenACC Automatic Size Detection
OpenACC with Allocatable Arrays:
Fortran Code:
integer :: n = 5000
real, allocatable :: data(:)
allocate(data(n))
OpenACC automatically knows:
┌─────────────────────────────────────────────────────────────┐
│ Array Information │
├─────────────────────────────────────────────────────────────┤
│ Name: data │
│ Lower bound: 1 (Fortran default) │
│ Upper bound: 5000 (from allocation) │
│ Size: 5000 elements (automatically computed) │
│ Memory needed: 20KB (5000 × 4 bytes per real) │
└─────────────────────────────────────────────────────────────┘
No need to specify bounds in data clauses:
✓ copyin(data) ← OpenACC uses full allocated size
✗ copyin(data(1:n)) ← Unnecessary (but valid)
Common Patterns
Pattern 1: User-Input Sizing
write(*,*) 'Enter problem size:'
read(*,*) n
allocate(arrays(n))
! Process with OpenACC
deallocate(arrays)
Pattern 2: File-Header Sizing
open(file='data.txt')
read(*,*) n ! First line contains size
allocate(data(n))
! Read and process data
close(file)
deallocate(data)
Pattern 3: Conditional Sizing
if (high_precision) then
allocate(data(large_size))
else
allocate(data(normal_size))
end if
Best Practices
✅ DO:
- Check allocation status for large arrays
- Deallocate arrays when finished
- Use allocatable arrays for unknown problem sizes
- Let OpenACC automatically detect array bounds
- Pre-allocate maximum expected size when possible
❌ DON’T:
- Forget to deallocate (memory leaks)
- Reallocate frequently in loops
- Assume allocation always succeeds
- Mix fixed and allocatable arrays unnecessarily
- Allocate inside parallel regions
Quick Reference
! Declaration:
real, allocatable :: array(:)
! Allocation:
allocate(array(size))
! OpenACC usage:
!$acc parallel loop copyin(array) copyout(result)
! OpenACC automatically knows array bounds
! Deallocation:
deallocate(array)
! Safety check:
if (allocated(array)) deallocate(array)
Quick Summary
=== Allocatable Arrays Concepts Summary ===
Fortran Allocatable Array Operations:
┌─────────────────────────┬────────────────────────────────────────────────┐
│ Operation │ Purpose │
├─────────────────────────┼────────────────────────────────────────────────┤
│ Declaration │ real, allocatable :: array(:) │
│ Allocation │ allocate(array(size)) │
│ Size Query │ size(array) or ubound(array,1) │
│ Status Check │ allocated(array) │
│ Deallocation │ deallocate(array) │
│ Error Handling │ allocate(array(n), stat=status) │
└─────────────────────────┴────────────────────────────────────────────────┘
OpenACC Automatic Size Detection:
┌─────────────────────────┬────────────────────────────────────────────────┐
│ Array Type │ OpenACC Behavior │
├─────────────────────────┼────────────────────────────────────────────────┤
│ Fixed Size │ array(1:100) - bounds known at compile time │
│ Allocatable 1D │ array(:) - bounds detected automatically │
│ Allocatable 2D │ matrix(:,:) - all dimensions auto-detected │
│ Allocatable 3D │ field(:,:,:) - full shape auto-detected │
│ Variable Bounds │ Works with any allocated size at runtime │
└─────────────────────────┴────────────────────────────────────────────────┘
Memory Allocation Patterns:
┌─────────────────────────┬────────────────────────────────────────────────┐
│ Scenario │ Best Practice │
├─────────────────────────┼────────────────────────────────────────────────┤
│ User Input Size │ Read size, allocate once, process │
│ File-based Size │ Read header, allocate based on data size │
│ Problem-dependent │ Calculate size, allocate appropriate arrays │
│ Multi-resolution │ Allocate different sizes for different levels │
│ Growing Arrays │ Reallocate with growth factor (1.5x - 2x) │
└─────────────────────────┴────────────────────────────────────────────────┘
Performance Characteristics:
┌─────────────────────────┬──────────────────┬──────────────────────────────┐
│ Array Type │ Allocation Cost │ OpenACC Transfer Efficiency │
├─────────────────────────┼──────────────────┼──────────────────────────────┤
│ Small arrays (<1MB) │ Negligible │ Fast │
│ Medium arrays (1-100MB) │ Small │ Good │
│ Large arrays (>100MB) │ Moderate │ Bandwidth-limited │
│ 3D arrays │ Higher │ Excellent with collapse(3) │
│ Frequent reallocation │ Expensive │ Avoid in performance code │
└─────────────────────────┴──────────────────┴──────────────────────────────┘
Common Allocatable Array Use Cases:
• Scientific simulations with problem-size input parameters
• File-based data processing with unknown data sizes
• Multi-grid methods with different resolution levels
• Adaptive mesh refinement (AMR) applications
• Monte Carlo simulations with varying sample sizes
• Image/signal processing with different image dimensions
• Finite element codes with mesh-dependent array sizes
Error Handling Best Practices:
┌─────────────────────────────────────────────────────────────────────────────┐
│ ! Safe allocation with error checking │
│ allocate(array(n), stat=alloc_status, errmsg=error_message) │
│ if (alloc_status /= 0) then │
│ write(*,*) 'Allocation failed:', trim(error_message) │
│ ! Handle error (reduce size, exit gracefully, etc.) │
│ end if │
│ │
│ ! Always check before deallocation │
│ if (allocated(array)) deallocate(array) │
└─────────────────────────────────────────────────────────────────────────────┘
OpenACC Data Clause Usage:
• copyin(allocatable_array) - Transfer full allocated array to device
• copyout(allocatable_array) - Transfer full allocated array from device
• copy(allocatable_array) - Bidirectional transfer of full array
• create(allocatable_array) - Allocate on device with same bounds
Advantages of Allocatable Arrays:
✓ Memory usage matches actual problem requirements
✓ Runtime flexibility for different problem sizes
✓ OpenACC handles bounds detection automatically
✓ Works seamlessly with data regions and async operations
✓ Perfect for scientific codes with variable parameters
✓ Enables efficient memory management in GPU applications
Example Code
Let us consider the following OpenACC code –
program allocatable_demo
! Demonstrates OpenACC with Fortran allocatable arrays
implicit none
integer :: problem_size, demo_choice, i, j, k
integer :: alloc_status, matrix_size, nx, ny, nz, work_size
real, allocatable :: dynamic_array(:), result_array(:)
real, allocatable :: matrix_work(:,:), matrix_result(:,:)
real, allocatable :: field_3d(:,:,:)
real, allocatable :: work_data(:), temp_result(:), final_output(:)
write(*,*) 'OpenACC with Fortran Allocatable Arrays'
write(*,*) '====================================='
write(*,*) ''
write(*,*) 'Demonstration 1: Basic Dynamic Allocation'
write(*,*) '(Array size determined at runtime)'
write(*,*) ''
! Get problem size from user simulation
problem_size = 8000 ! Simulating user input
write(*,'(A,I0,A)') 'Simulated user input: problem size = ', problem_size, ' elements'
! Allocate arrays dynamically
allocate(dynamic_array(problem_size), stat=alloc_status)
if (alloc_status /= 0) then
write(*,*) 'ERROR: Failed to allocate dynamic_array'
stop
end if
allocate(result_array(problem_size), stat=alloc_status)
if (alloc_status /= 0) then
write(*,*) 'ERROR: Failed to allocate result_array'
stop
end if
write(*,'(A,I0,A)') '✓ Successfully allocated arrays with ', problem_size, ' elements'
! Initialize with data
do i = 1, problem_size
dynamic_array(i) = sin(real(i) * 0.0001) * 100.0 + real(i) * 0.01
end do
write(*,*) 'Data initialized on host'
write(*,'(A,F8.4)') 'Sample input: ', dynamic_array(1000)
! Process with OpenACC - automatic size detection
!$acc parallel loop copyin(dynamic_array) copyout(result_array)
do i = 1, problem_size
result_array(i) = sqrt(abs(dynamic_array(i))) + dynamic_array(i) * 0.5
end do
!$acc end parallel loop
write(*,*) '✓ OpenACC processing complete'
write(*,'(A,F8.4)') 'Sample result: ', result_array(1000)
write(*,*) '✓ OpenACC automatically detected array bounds'
write(*,*) ''
! Deallocate first arrays
deallocate(dynamic_array)
deallocate(result_array)
write(*,*) '✓ Arrays deallocated'
write(*,*) ''
write(*,*) 'Demonstration 2: Problem-Size Dependent Allocation'
write(*,*) '(Different matrix sizes based on problem type)'
write(*,*) ''
! Simulate different problem types
demo_choice = 2 ! Simulating medium problem selection
select case(demo_choice)
case(1)
matrix_size = 200
write(*,*) 'Selected: Small problem (200×200 matrix)'
case(2)
matrix_size = 500
write(*,*) 'Selected: Medium problem (500×500 matrix)'
case(3)
matrix_size = 1000
write(*,*) 'Selected: Large problem (1000×1000 matrix)'
case default
matrix_size = 200
end select
! Allocate matrices of appropriate size
allocate(matrix_work(matrix_size, matrix_size))
allocate(matrix_result(matrix_size, matrix_size))
write(*,'(A,I0,A,I0,A)') '✓ Allocated ', matrix_size, '×', matrix_size, ' matrices'
! Initialize matrix
do j = 1, matrix_size
do i = 1, matrix_size
matrix_work(i, j) = real(i + j) * 0.001 + cos(real(i * j) * 0.0001)
end do
end do
write(*,*) 'Matrix initialized on host'
! Process matrix with OpenACC
!$acc parallel loop collapse(2) copyin(matrix_work) copyout(matrix_result)
do j = 1, matrix_size
do i = 1, matrix_size
matrix_result(i, j) = matrix_work(i, j) * matrix_work(i, j) + &
sin(matrix_work(i, j)) * 0.5
end do
end do
!$acc end parallel loop
write(*,*) '✓ Matrix processing complete'
write(*,'(A,F8.4)') 'Center element result: ', matrix_result(matrix_size/2, matrix_size/2)
write(*,*) '✓ OpenACC handled 2D allocatable array automatically'
write(*,*) ''
! Clean up matrices
deallocate(matrix_work)
deallocate(matrix_result)
write(*,*) 'Demonstration 3: 3D Allocatable Array Processing'
write(*,*) '(Scientific field simulation with dynamic dimensions)'
write(*,*) ''
! 3D field dimensions
nx = 40
ny = 50
nz = 30
write(*,'(A,I0,A,I0,A,I0,A)') 'Allocating 3D field: ', nx, '×', ny, '×', nz
allocate(field_3d(nx, ny, nz))
write(*,*) '✓ 3D array allocated successfully'
! Initialize 3D field
do k = 1, nz
do j = 1, ny
do i = 1, nx
field_3d(i, j, k) = real(i + j + k) * 0.01 + &
sin(real(i) * 0.1) * cos(real(j) * 0.1) * sin(real(k) * 0.1)
end do
end do
end do
write(*,*) '3D field initialized'
write(*,'(A,F8.4)') 'Sample field value: ', field_3d(20, 25, 15)
! Process 3D field with OpenACC
!$acc parallel loop collapse(3) copy(field_3d)
do k = 2, nz-1
do j = 2, ny-1
do i = 2, nx-1
! 3D smoothing operation (simple Laplacian)
field_3d(i, j, k) = 0.9 * field_3d(i, j, k) + 0.1 * ( &
field_3d(i-1, j, k) + field_3d(i+1, j, k) + &
field_3d(i, j-1, k) + field_3d(i, j+1, k) + &
field_3d(i, j, k-1) + field_3d(i, j, k+1)) / 6.0
end do
end do
end do
!$acc end parallel loop
write(*,*) '✓ 3D field smoothing complete'
write(*,'(A,F8.4)') 'Smoothed field value: ', field_3d(20, 25, 15)
write(*,*) '✓ OpenACC processed 3D allocatable array efficiently'
write(*,*) ''
deallocate(field_3d)
write(*,*) 'Demonstration 4: Allocatable Arrays in Data Regions'
write(*,*) '(Multiple operations with persistent allocatable arrays)'
write(*,*) ''
! Allocate working arrays
work_size = 12000
allocate(work_data(work_size))
allocate(temp_result(work_size))
allocate(final_output(work_size))
write(*,'(A,I0,A)') '✓ Allocated working arrays with ', work_size, ' elements'
! Initialize working data
do i = 1, work_size
work_data(i) = real(i) * 0.001 + cos(real(i) * 0.0005) * 10.0
end do
! Multiple operations in data region
!$acc data copyin(work_data) copyout(final_output) create(temp_result)
write(*,*) '→ Arrays transferred to GPU (allocatable bounds auto-detected)'
! Step 1: Initial processing
!$acc parallel loop
do i = 1, work_size
temp_result(i) = work_data(i) * work_data(i) * 0.01
end do
!$acc end parallel loop
write(*,*) '✓ Step 1 complete: squared and scaled'
! Step 2: Apply mathematical function
!$acc parallel loop
do i = 1, work_size
temp_result(i) = sqrt(abs(temp_result(i))) + exp(temp_result(i) * 0.001)
end do
!$acc end parallel loop
write(*,*) '✓ Step 2 complete: applied mathematical functions'
! Step 3: Final combination
!$acc parallel loop
do i = 1, work_size
final_output(i) = work_data(i) * 0.6 + temp_result(i) * 0.4
end do
!$acc end parallel loop
write(*,*) '✓ Step 3 complete: final combination'
write(*,*) '← Final results transferred back to host'
!$acc end data
write(*,'(A,F8.4)') 'Final processing result: ', final_output(6000)
write(*,*) '✓ All operations performed with arrays resident on GPU'
write(*,*) ''
! Clean up
deallocate(work_data)
deallocate(temp_result)
deallocate(final_output)
write(*,*) 'Key Benefits of Allocatable Arrays with OpenACC:'
write(*,*) '=============================================='
write(*,*) '• Problem size determined at runtime'
write(*,*) '• Memory usage optimized for actual needs'
write(*,*) '• OpenACC automatically detects array bounds'
write(*,*) '• No need to specify array sizes in data clauses'
write(*,*) '• Works seamlessly with 1D, 2D, and 3D arrays'
write(*,*) '• Perfect for file-based or user-input problem sizes'
write(*,*) ''
write(*,*) 'Memory Management:'
write(*,*) '• ALLOCATE creates arrays at runtime'
write(*,*) '• DEALLOCATE frees memory when finished'
write(*,*) '• Use STAT= to check allocation success'
write(*,*) '• OpenACC handles device memory automatically'
write(*,*) ''
write(*,*) 'Best Use Cases:'
write(*,*) '• Scientific simulations with variable problem sizes'
write(*,*) '• File-based data processing'
write(*,*) '• User-configurable problem parameters'
write(*,*) '• Multi-resolution computations'
write(*,*) '• Adaptive algorithms with growing data structures'
end program allocatable_demo
To compile this code –
nvfortran -acc -Minfo=accel -O2 allocatable_demo.f90 -o allocatable_demo
To execute this code –
./allocatable_demo
Sample output –
OpenACC with Fortran Allocatable Arrays
=====================================
Demonstration 1: Basic Dynamic Allocation
(Array size determined at runtime)
Simulated user input: problem size = 8000 elements
✓ Successfully allocated arrays with 8000 elements
Data initialized on host
Sample input: 19.9833
✓ OpenACC processing complete
Sample result: 14.4619
✓ OpenACC automatically detected array bounds
✓ Arrays deallocated
Demonstration 2: Problem-Size Dependent Allocation
(Different matrix sizes based on problem type)
Selected: Medium problem (500×500 matrix)
✓ Allocated 500×500 matrices
Matrix initialized on host
✓ Matrix processing complete
Center element result: 2.7471
✓ OpenACC handled 2D allocatable array automatically
Demonstration 3: 3D Allocatable Array Processing
(Scientific field simulation with dynamic dimensions)
Allocating 3D field: 40×50×30
✓ 3D array allocated successfully
3D field initialized
Sample field value: -0.1267
✓ 3D field smoothing complete
Smoothed field value: -0.1263
✓ OpenACC processed 3D allocatable array efficiently
Demonstration 4: Allocatable Arrays in Data Regions
(Multiple operations with persistent allocatable arrays)
✓ Allocated working arrays with 12000 elements
→ Arrays transferred to GPU (allocatable bounds auto-detected)
✓ Step 1 complete: squared and scaled
✓ Step 2 complete: applied mathematical functions
✓ Step 3 complete: final combination
← Final results transferred back to host
Final processing result: -1.7839
✓ All operations performed with arrays resident on GPU
Key Benefits of Allocatable Arrays with OpenACC:
==============================================
• Problem size determined at runtime
• Memory usage optimized for actual needs
• OpenACC automatically detects array bounds
• No need to specify array sizes in data clauses
• Works seamlessly with 1D, 2D, and 3D arrays
• Perfect for file-based or user-input problem sizes
Memory Management:
• ALLOCATE creates arrays at runtime
• DEALLOCATE frees memory when finished
• Use STAT= to check allocation success
• OpenACC handles device memory automatically
Best Use Cases:
• Scientific simulations with variable problem sizes
• File-based data processing
• User-configurable problem parameters
• Multi-resolution computations
• Adaptive algorithms with growing data structures
Click here to go back to OpenACC Fortran tutorials page.
References
- OpenACC Specification : https://www.openacc.org/specification