Appearance
Usage
All examples use use vecfor which re-exports all precision variants and the Cartesian versors.
Importing and declaring vectors
fortran
use vecfor
implicit none
type(vector) :: v1, v2, v3 ! default 64-bit (R8P) precision
type(vector_R4P) :: vf ! 32-bit precision
type(vector_R16P) :: vq ! 128-bit precision (if compiler supports it)The module also exposes vector_R4P, vector_R8P, and vector_R16P for explicit precision control. All three sets of Cartesian versors are available:
fortran
v1 = ex ! [1, 0, 0] (64-bit versor)
v1 = ex_R4P ! [1, 0, 0] (32-bit versor)
v1 = ex_R16P ! [1, 0, 0] (128-bit versor)Standard arithmetic
Use ex, ey, ez (the Cartesian unit versors) and standard operators to build and combine vectors:
fortran
use vecfor
implicit none
type(vector) :: v1, v2
v1 = ex ! [1, 0, 0]
v2 = v1 + 2 ! [3, 2, 2] (scalar added to each component)
v2 = v1 - 2 ! [-1, -2, -2]
v2 = v1 / 2 ! [0.5, 0, 0]
v2 = v1 * 2 ! [2, 0, 0]
v2 = ey + ez ! [0, 1, 1]
v1 = v1 + v2 ! [1, 1, 1]All operators work with any supported numeric kind on either side:
fortran
use vecfor
use penf, only: R4P, I4P
implicit none
type(vector) :: v
v = ex * 2.0_R4P ! mix with 32-bit real scalar
v = 3_I4P * ey ! mix with 32-bit integer scalarVectorial calculus algebra
Cross product
fortran
use vecfor
implicit none
type(vector) :: v1, v2, cross
v1 = ex
v2 = ex + 2 * ey
cross = v1 .cross. v2 ! [0, 0, 2]Dot product
fortran
use vecfor
use penf, only: R8P
implicit none
type(vector) :: v1, v2
real(R8P) :: dot
v1 = ex
v2 = ex + 2 * ey
dot = v1 .dot. v2 ! 1.0 (ex · (ex + 2*ey) = 1)Parallel and orthogonal projections
fortran
use vecfor
implicit none
type(vector) :: v1, v2, parallel_comp, orthogonal_comp
v1 = 2 * ex
v2 = ex + ey
parallel_comp = v1 .paral. v2 ! component of v1 parallel to v2: [1, 1, 0]
orthogonal_comp = v1 .ortho. v2 ! component of v1 orthogonal to v2: [1, -1, 0]Norms and normalization
fortran
use vecfor
implicit none
type(vector) :: v
v = ex + 2 * ey + 3 * ez ! [1, 2, 3]
print *, v%sq_norm() ! 14.0
print *, sq_norm(v) ! 14.0 (stand-alone function)
print *, v%normL2() ! ~3.742
print *, normL2(v) ! ~3.742 (stand-alone function)
call v%normalize() ! normalize v in-place
! v is now [1/sqrt(14), 2/sqrt(14), 3/sqrt(14)]
v = ex + 2 * ey + 3 * ez
print *, normalized(v)%normL2() ! 1.0 (stand-alone: returns normalized copy)TIP
normalize() and normalized() handle the zero-vector gracefully — they return a zero vector instead of dividing by zero.
Face normals
VecFor computes the geometric normal to a triangular or quad face. The norm of the result equals the face area.
Triangle (3-point face)
1.----.2
\ |
\ |
\ |
\|
.3fortran
use vecfor
implicit none
type(vector) :: p1, p2, p3, normal
p1 = -ex + ey ! [-1, 1, 0]
p2 = ey ! [ 0, 1, 0]
p3 = -ey ! [ 0,-1, 0]
! Stand-alone function
normal = face_normal3(pt1=p1, pt2=p2, pt3=p3) ! [0, 0, -1]
! Type-bound method
call normal%face_normal3(pt1=p1, pt2=p2, pt3=p3) ! [0, 0, -1]
! With normalisation (unit normal)
call normal%face_normal3(norm='y', pt1=p1, pt2=p2, pt3=p3) ! [0, 0, -1]Quad (4-point face)
1.----------.2
| |
| |
4.----------.3fortran
use vecfor
implicit none
type(vector) :: p1, p2, p3, p4, normal
p1 = -ex + ey ! [-1, 1, 0]
p2 = ey ! [ 0, 1, 0]
p3 = -ey ! [ 0,-1, 0]
p4 = -ex - ey ! [-1,-1, 0]
normal = face_normal4(pt1=p1, pt2=p2, pt3=p3, pt4=p4) ! [0, 0, -2]
call normal%face_normal4(norm='y', pt1=p1, pt2=p2, pt3=p3, pt4=p4) ! [0, 0, -1]TIP
The norm of the face normal equals the face area. Pass norm='y' to get a unit normal instead.
Comparison operators
Vectors are compared by their L2 norm. The result is a logical scalar:
fortran
use vecfor
use penf, only: R8P, I4P
implicit none
type(vector) :: v1, v2
v1 = ex + 2 * ey + 3 * ez ! normL2 = sqrt(14) ~ 3.742
v2 = ex + ey + ez ! normL2 = sqrt(3) ~ 1.732
print *, v1 > v2 ! T
print *, v1 == v2 ! F
print *, v1 /= v2 ! T
print *, v1 < 1.0_R8P ! F (compare norm to scalar)
print *, 1_I4P < v1 ! TI/O
Formatted print
fortran
use vecfor
implicit none
type(vector) :: v
v = ex + 2 * ey + 3 * ez
call v%print ! Component x +1.000000000000000E+000
! Component y +2.000000000000000E+000
! Component z +3.000000000000000E+000File save and load
fortran
use vecfor
use penf, only: I4P
implicit none
type(vector) :: v
integer(I4P) :: unit
v = ex + 2 * ey + 3 * ez
! Sequential access
open(newunit=unit, file='vector.dat', form='unformatted')
call v%save(unit=unit)
close(unit)
open(newunit=unit, file='vector.dat', form='unformatted')
call v%load(unit=unit)
close(unit)
! Stream access
open(newunit=unit, file='vector.str', form='unformatted', access='stream')
call v%save(unit=unit)
close(unit)Quick reference — test program output
Running src/tests/simple.f90 produces the following output (abbreviated):
Assign vector1 = [1, 2, 3]
Assign vector2 = [-1, -2, -3]
vector1%sq_norm() = 14.0
vector1%normL2() = 3.7
normalized(vector1):
Component x +0.267261241912424E+000
Component y +0.534522483824849E+000
Component z +0.801783725737273E+000
vector1.dot.ex = 1.0
vector1.dot.ey = 2.0
vector1.dot.ez = 3.0
vector1.dot.vector2 = -14.0
vector1.cross.vector2:
Component x 0.000000000000000E+000
Component y 0.000000000000000E+000
Component z 0.000000000000000E+000
vector1.paral.vector2:
Component x +0.100000000000000E+001
Component y +0.200000000000000E+001
Component z +0.300000000000000E+001