Getting Started
This guide will help you get started with PIC in your Fortran projects.
Basic Usage
PIC provides an umbrella module that exposes all functionality:
program my_program
use pic
implicit none
! Your code here
end program my_program
For finer control, import specific modules:
program my_program
use pic_types, only: default_int, dp
use pic_strings, only: to_string
use pic_logger, only: log_info
implicit none
! Your code here
end program my_program
Types and Kinds
PIC uses portable kind definitions. Always use these instead of literal kinds to ensure your code compiles on all compilers.
use pic_types, only: default_int, sp, dp, qp, int32, int64
! Portable integer (32 or 64-bit depending on build config)
integer(default_int) :: n
! Fixed-width integers
integer(int32) :: i32
integer(int64) :: i64
! Floating point kinds
real(sp) :: single_val ! Single precision (32-bit)
real(dp) :: double_val ! Double precision (64-bit)
real(qp) :: quad_val ! Quad precision (128-bit)
Warning
Never use bare integer or integer(4) / integer(8) / real(8).
These lead to portability issues across compilers. Always use PIC’s kind definitions.
Why Default Integer Matters
Many legacy Fortran codes compile with flags like -fdefault-integer-8 to make all integers 64-bit. This causes problems when interfacing with other codes.
PIC solves this by providing default_int which can be toggled at compile time without compiler flags:
# Build with 32-bit default integers (default)
cmake -B build
# Build with 64-bit default integers
cmake -B build -DPIC_DEFAULT_INT8=ON
String Operations
PIC provides a dynamic string type and string utilities:
use pic_string_type, only: string_type
use pic_strings, only: to_string, to_lower, to_upper, starts_with, ends_with
type(string_type) :: s
character(len=:), allocatable :: str
! Convert numbers to strings
str = to_string(42) ! "42"
str = to_string(3.14159_dp) ! "3.14159..."
str = to_string(.true.) ! "T"
! Case conversion
str = to_lower("HELLO WORLD") ! "hello world"
str = to_upper("hello world") ! "HELLO WORLD"
! String queries
if (starts_with("hello.f90", "hello")) then
print *, "Starts with hello"
end if
Logging
PIC includes a logging system with severity levels:
use pic_logger
! Different severity levels
call log_debug("Detailed debug information")
call log_info("Starting computation...")
call log_warning("Memory usage is high")
call log_error("Failed to open file")
Output example:
[INFO] Starting computation...
[WARNING] Memory usage is high
[ERROR] Failed to open file
Pure Logger
For use in pure procedures, use pic_pure_logger:
use pic_pure_logger
pure function compute(x) result(y)
real(dp), intent(in) :: x
real(dp) :: y
character(len=256) :: msg
! Pure logging (deferred output)
call pure_log_info("Computing...", msg)
y = x * 2.0_dp
end function compute
Timer
Measure execution time with high-resolution timers:
use pic_timer
use pic_types, only: dp
type(timer_type) :: t
real(dp) :: elapsed
call t%start()
! ... your computation ...
call t%stop()
elapsed = t%elapsed()
print '(A,F10.3,A)', "Elapsed time: ", elapsed, " seconds"
Array Operations
PIC provides array utilities with optional OpenMP parallelization:
use pic_array, only: fill_vector, fill_matrix
use pic_types, only: dp
real(dp) :: vec(1000)
real(dp) :: mat(100, 100)
! Fill arrays with values
call fill_vector(vec, 0.0_dp)
call fill_matrix(mat, 1.0_dp)
! Enable threaded filling (requires PIC_ENABLE_OMP)
call fill_vector(vec, 0.0_dp, threaded=.true.)
Sorting
Sorting routines that work on all compilers (unlike stdlib which may fail on some):
use pic_sorting
use pic_types, only: dp
real(dp) :: arr(100)
integer(default_int) :: indices(100)
! Sort in place
call sort(arr)
! Get sorted indices
call argsort(arr, indices)
Hash Functions
FNV-1a 32-bit hash implementation:
use pic_hash_32bit, only: fnv1a_hash
use pic_types, only: int32
integer(int32) :: hash_val
character(len=*), parameter :: key = "my_key"
hash_val = fnv1a_hash(key)
Complete Example
Here’s a complete example showing multiple PIC features:
program pic_demo
use pic
implicit none
type(timer_type) :: timer
real(dp) :: data(1000), elapsed
integer(default_int) :: i
! Start timing
call timer%start()
! Initialize array
call fill_vector(data, 0.0_dp)
do i = 1, size(data)
data(i) = real(i, dp)
end do
! Sort the data
call sort(data)
! Stop timing
call timer%stop()
elapsed = timer%elapsed()
! Log results
call log_info("Sorted " // to_string(size(data)) // " elements")
call log_info("Time: " // to_string(elapsed) // " seconds")
end program pic_demo
Next Steps
Explore the Features page for a complete module reference
Check the API documentation for detailed interfaces
See the examples repository for more use cases