Exercise_3/0000755€í4H€L¨x 0000000000011462077762014660 5ustar tcluneNDC\domain usersExercise_3/3-A/0000755€í4H€L¨x 0000000000011462100062015154 5ustar tcluneNDC\domain usersExercise_3/3-A/GNUmakefile0000644€í4H€L¨x 0000000047011462060411017232 0ustar tcluneNDC\domain usersSRC_DIR = src TESTS_DIR = tests LIB_DIR = lib MOD_DIR = mod .PHONY= all all: $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ tests: all clean: $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ distclean: clean $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ rm -rf $(LIB_DIR) $(MOD_DIR) Exercise_3/3-A/src/0000755€í4H€L¨x 0000000000011462100106015742 5ustar tcluneNDC\domain usersExercise_3/3-A/src/GNUmakefile0000644€í4H€L¨x 0000000102311462060411020014 0ustar tcluneNDC\domain usersROOT_DIR = .. LIB_DIR = $(ROOT_DIR)/lib MOD_DIR = $(ROOT_DIR)/mod LIB = libinterpolator.a MOD = interpolator_mod.mod F90 ?= ifort F90FLAGS += -I. -I$(MOD_DIR) -I$(PFUNIT)/mod SRC = $(wildcard *.F90) OBJS = $(SRC:.F90=.o) .PHONY= all all: $(LIB) tests tests: mkdir -p $(LIB_DIR) mkdir -p $(MOD_DIR) cp $(LIB) $(LIB_DIR)/. cp $(MOD) $(MOD_DIR)/. $(LIB): $(OBJS) ar -cr $@ $? %.o:%.F90 $(F90) -c $(F90FLAGS) $< clean: $(RM) $(OBJS) $(LIB) $(RM) *.mod distclean: clean $(RM) $(LIB_DIR)/$(LIB) $(MOD_DIR)/$(MOD) Exercise_3/3-A/src/Interpolator_mod.F900000644€í4H€L¨x 0000000152111462065123021553 0ustar tcluneNDC\domain usersmodule Interpolator_mod implicit none private public :: Interpolator_type public :: newInterpolator public :: clean public :: getIntervalIndex type Interpolator_type private integer :: placeholder end type Interpolator_type interface clean module procedure cleanInterpolator end interface contains function newInterpolator(nodes) result(interpolator) type (Interpolator_type) :: interpolator real, intent(in) :: nodes(:) end function newInterpolator function getIntervalIndex(this, x) result(index) type (Interpolator_type), intent(in) :: this real, intent(in) :: x integer :: index index = 1 end function getIntervalIndex subroutine cleanInterpolator(this) type (Interpolator_type), intent(inout) :: this end subroutine cleanInterpolator end module Interpolator_mod Exercise_3/3-A/tests/0000755€í4H€L¨x 0000000000011462100106016315 5ustar tcluneNDC\domain usersExercise_3/3-A/tests/GNUmakefile0000644€í4H€L¨x 0000000130611462060411020373 0ustar tcluneNDC\domain users# Important: specify a serial PFUNIT installation. # Check for the PFUNIT environment variable ifndef PFUNIT $(error The environment variable "PFUNIT" must be given a value which is the \ path for the installation of pFUnit.) endif F90 ?= ifort FC = $(F90) ROOT_DIR = .. LIB_DIR = $(ROOT_DIR)/lib MOD_DIR = $(ROOT_DIR)/mod F90FLAGS = -I. -I$(MOD_DIR) PFUNIT_TEST_DIRECTORIES =. PFUNIT_LFLAGS = -L$(LIB_DIR) -linterpolator .PHONY: all clean distclean VPATH += ../src tests.x: libinterpolator.a %.o : %.F90 $(FC) -c $(F90FLAGS) $< all: tests clean: $(RM) *.o $(RM) *.mod $(RM) .pFUnitLog distclean: clean $(MAKE) pfunitdistclean export PFUNIT include $(PFUNIT)/include/pFUnit.makefile Exercise_3/3-A/tests/TestInterpolator_mod.F900000644€í4H€L¨x 0000000071411462066056022777 0ustar tcluneNDC\domain usersmodule TestInterpolator_mod use pFUnit use Interpolator_mod implicit none private public :: test_getIntervalIndex contains subroutine test_getIntervalIndex() type (Interpolator_type) :: interpolator real :: nodes(2) = (/ 0., 1. /) interpolator = newInterpolator(nodes) call assertEqual(1, getIntervalIndex(interpolator, 0.5)) call clean(interpolator) end subroutine test_getIntervalIndex end module TestInterpolator_mod Exercise_3/3-B/0000755€í4H€L¨x 0000000000011462100062015155 5ustar tcluneNDC\domain usersExercise_3/3-B/GNUmakefile0000644€í4H€L¨x 0000000047011462064252017242 0ustar tcluneNDC\domain usersSRC_DIR = src TESTS_DIR = tests LIB_DIR = lib MOD_DIR = mod .PHONY= all all: $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ tests: all clean: $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ distclean: clean $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ rm -rf $(LIB_DIR) $(MOD_DIR) Exercise_3/3-B/src/0000755€í4H€L¨x 0000000000011462100117015745 5ustar tcluneNDC\domain usersExercise_3/3-B/src/GNUmakefile0000644€í4H€L¨x 0000000102311462064252020024 0ustar tcluneNDC\domain usersROOT_DIR = .. LIB_DIR = $(ROOT_DIR)/lib MOD_DIR = $(ROOT_DIR)/mod LIB = libinterpolator.a MOD = interpolator_mod.mod F90 ?= ifort F90FLAGS += -I. -I$(MOD_DIR) -I$(PFUNIT)/mod SRC = $(wildcard *.F90) OBJS = $(SRC:.F90=.o) .PHONY= all all: $(LIB) tests tests: mkdir -p $(LIB_DIR) mkdir -p $(MOD_DIR) cp $(LIB) $(LIB_DIR)/. cp $(MOD) $(MOD_DIR)/. $(LIB): $(OBJS) ar -cr $@ $? %.o:%.F90 $(F90) -c $(F90FLAGS) $< clean: $(RM) $(OBJS) $(LIB) $(RM) *.mod distclean: clean $(RM) $(LIB_DIR)/$(LIB) $(MOD_DIR)/$(MOD) Exercise_3/3-B/src/Interpolator_mod.F900000644€í4H€L¨x 0000000221411462066434021562 0ustar tcluneNDC\domain usersmodule Interpolator_mod implicit none private public :: Interpolator_type public :: newInterpolator public :: clean public :: getIntervalIndex type Interpolator_type real, pointer :: nodes(:) end type Interpolator_type interface clean module procedure cleanInterpolator end interface contains function newInterpolator(nodes) result(interpolator) type (Interpolator_type) :: interpolator real, intent(in) :: nodes(:) allocate(interpolator%nodes(size(nodes))) interpolator%nodes = nodes end function newInterpolator function getIntervalIndex(this, x) result(index) type (Interpolator_type), intent(in) :: this real, intent(in) :: x integer :: index integer :: i integer, parameter :: NOT_FOUND = -1 index = NOT_FOUND do i = 1, size(this%nodes) - 1 if (this%nodes(i) <= x .and. x < this%nodes(i+1)) then index = i exit end if end do end function getIntervalIndex subroutine cleanInterpolator(this) type (Interpolator_type), intent(inout) :: this deallocate(this%nodes) end subroutine cleanInterpolator end module Interpolator_mod Exercise_3/3-B/tests/0000755€í4H€L¨x 0000000000011462100117016320 5ustar tcluneNDC\domain usersExercise_3/3-B/tests/GNUmakefile0000644€í4H€L¨x 0000000130611462066626020412 0ustar tcluneNDC\domain users# Important: specify a serial PFUNIT installation. # Check for the PFUNIT environment variable ifndef PFUNIT $(error The environment variable "PFUNIT" must be given a value which is the \ path for the installation of pFUnit.) endif F90 ?= ifort FC = $(F90) ROOT_DIR = .. LIB_DIR = $(ROOT_DIR)/lib MOD_DIR = $(ROOT_DIR)/mod F90FLAGS = -I. -I$(MOD_DIR) PFUNIT_TEST_DIRECTORIES =. PFUNIT_LFLAGS = -L$(LIB_DIR) -linterpolator .PHONY: all clean distclean VPATH += ../src tests.x: libinterpolator.a %.o : %.F90 $(FC) -c $(F90FLAGS) $< all: tests clean: $(RM) *.o $(RM) *.mod $(RM) .pFUnitLog distclean: clean $(MAKE) pfunitdistclean export PFUNIT include $(PFUNIT)/include/pFUnit.makefile Exercise_3/3-B/tests/TestInterpolator_mod.F900000644€í4H€L¨x 0000000176711462066517023013 0ustar tcluneNDC\domain usersmodule TestInterpolator_mod use pFUnit use Interpolator_mod implicit none private public :: test_getIntervalIndex public :: test_getIntervalIndexB contains subroutine test_getIntervalIndex() type (Interpolator_type) :: interpolator real :: nodes(2) = (/ 0., 1. /) interpolator = newInterpolator(nodes) call assertEqual(1, getIntervalIndex(interpolator, 0.5)) call clean(interpolator) end subroutine test_getIntervalIndex subroutine test_getIntervalIndexB() type (Interpolator_type) :: interpolator real :: nodes(4) = (/ 0., 2., 5., 6./) interpolator = newInterpolator(nodes) call assertEqual(1, getIntervalIndex(interpolator, 1.0), "x=1.0") call assertEqual(2, getIntervalIndex(interpolator, 3.0), "x=3.0") call assertEqual(2, getIntervalIndex(interpolator, 4.0), "x=4.0") call assertEqual(3, getIntervalIndex(interpolator, 5.0), "x=5.5") call clean(interpolator) end subroutine test_getIntervalIndexB end module TestInterpolator_mod Exercise_3/3-C/0000755€í4H€L¨x 0000000000011462100062015156 5ustar tcluneNDC\domain usersExercise_3/3-C/GNUmakefile0000644€í4H€L¨x 0000000047011462070114017235 0ustar tcluneNDC\domain usersSRC_DIR = src TESTS_DIR = tests LIB_DIR = lib MOD_DIR = mod .PHONY= all all: $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ tests: all clean: $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ distclean: clean $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ rm -rf $(LIB_DIR) $(MOD_DIR) Exercise_3/3-C/src/0000755€í4H€L¨x 0000000000011462100126015746 5ustar tcluneNDC\domain usersExercise_3/3-C/src/GNUmakefile0000644€í4H€L¨x 0000000102311462070114020017 0ustar tcluneNDC\domain usersROOT_DIR = .. LIB_DIR = $(ROOT_DIR)/lib MOD_DIR = $(ROOT_DIR)/mod LIB = libinterpolator.a MOD = interpolator_mod.mod F90 ?= ifort F90FLAGS += -I. -I$(MOD_DIR) -I$(PFUNIT)/mod SRC = $(wildcard *.F90) OBJS = $(SRC:.F90=.o) .PHONY= all all: $(LIB) tests tests: mkdir -p $(LIB_DIR) mkdir -p $(MOD_DIR) cp $(LIB) $(LIB_DIR)/. cp $(MOD) $(MOD_DIR)/. $(LIB): $(OBJS) ar -cr $@ $? %.o:%.F90 $(F90) -c $(F90FLAGS) $< clean: $(RM) $(OBJS) $(LIB) $(RM) *.mod distclean: clean $(RM) $(LIB_DIR)/$(LIB) $(MOD_DIR)/$(MOD) Exercise_3/3-C/src/Interpolator_mod.F900000644€í4H€L¨x 0000000235411462071051021557 0ustar tcluneNDC\domain usersmodule Interpolator_mod implicit none private public :: Interpolator_type public :: newInterpolator public :: clean public :: getIntervalIndex type Interpolator_type real, pointer :: nodes(:) end type Interpolator_type interface clean module procedure cleanInterpolator end interface contains function newInterpolator(nodes) result(interpolator) type (Interpolator_type) :: interpolator real, intent(in) :: nodes(:) allocate(interpolator%nodes(size(nodes))) interpolator%nodes = nodes end function newInterpolator function getIntervalIndex(this, x) result(index) use pFUnit, only: throw type (Interpolator_type), intent(in) :: this real, intent(in) :: x integer :: index integer :: i integer, parameter :: NOT_FOUND = -1 index = NOT_FOUND do i = 1, size(this%nodes) - 1 if (this%nodes(i) <= x .and. x < this%nodes(i+1)) then index = i exit end if end do if (index == NOT_FOUND) call throw('coordinate out-of-bounds') end function getIntervalIndex subroutine cleanInterpolator(this) type (Interpolator_type), intent(inout) :: this deallocate(this%nodes) end subroutine cleanInterpolator end module Interpolator_mod Exercise_3/3-C/tests/0000755€í4H€L¨x 0000000000011462100126016321 5ustar tcluneNDC\domain usersExercise_3/3-C/tests/GNUmakefile0000644€í4H€L¨x 0000000130611462070114020376 0ustar tcluneNDC\domain users# Important: specify a serial PFUNIT installation. # Check for the PFUNIT environment variable ifndef PFUNIT $(error The environment variable "PFUNIT" must be given a value which is the \ path for the installation of pFUnit.) endif F90 ?= ifort FC = $(F90) ROOT_DIR = .. LIB_DIR = $(ROOT_DIR)/lib MOD_DIR = $(ROOT_DIR)/mod F90FLAGS = -I. -I$(MOD_DIR) PFUNIT_TEST_DIRECTORIES =. PFUNIT_LFLAGS = -L$(LIB_DIR) -linterpolator .PHONY: all clean distclean VPATH += ../src tests.x: libinterpolator.a %.o : %.F90 $(FC) -c $(F90FLAGS) $< all: tests clean: $(RM) *.o $(RM) *.mod $(RM) .pFUnitLog distclean: clean $(MAKE) pfunitdistclean export PFUNIT include $(PFUNIT)/include/pFUnit.makefile Exercise_3/3-C/tests/TestInterpolator_mod.F900000644€í4H€L¨x 0000000267311462070777023014 0ustar tcluneNDC\domain usersmodule TestInterpolator_mod use pFUnit use Interpolator_mod implicit none private public :: test_getIntervalIndex public :: test_getIntervalIndexB public :: test_trapOutOfBounds contains subroutine test_getIntervalIndex() type (Interpolator_type) :: interpolator real :: nodes(2) = (/ 0., 1. /) interpolator = newInterpolator(nodes) call assertEqual(1, getIntervalIndex(interpolator, 0.5)) call clean(interpolator) end subroutine test_getIntervalIndex subroutine test_getIntervalIndexB() type (Interpolator_type) :: interpolator real :: nodes(4) = (/ 0., 2., 5., 6./) interpolator = newInterpolator(nodes) call assertEqual(1, getIntervalIndex(interpolator, 1.0), "x=1.0") call assertEqual(2, getIntervalIndex(interpolator, 3.0), "x=3.0") call assertEqual(2, getIntervalIndex(interpolator, 4.0), "x=4.0") call assertEqual(3, getIntervalIndex(interpolator, 5.0), "x=5.5") call clean(interpolator) end subroutine test_getIntervalIndexB subroutine test_TrapOutOfBounds() type (Interpolator_type) :: interpolator real :: nodes(2) = (/ 0., 1. /) integer :: index interpolator = newInterpolator(nodes) index = getIntervalIndex(interpolator, 2.0) if (.not. catch('coordinate out-of-bounds')) then call throw('Failed to trap out-of-bounds') end if call clean(interpolator) end subroutine test_TrapOutOfBounds end module TestInterpolator_mod Exercise_3/3-D/0000755€í4H€L¨x 0000000000011462100062015157 5ustar tcluneNDC\domain usersExercise_3/3-D/GNUmakefile0000644€í4H€L¨x 0000000047011462071073017243 0ustar tcluneNDC\domain usersSRC_DIR = src TESTS_DIR = tests LIB_DIR = lib MOD_DIR = mod .PHONY= all all: $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ tests: all clean: $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ distclean: clean $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ rm -rf $(LIB_DIR) $(MOD_DIR) Exercise_3/3-D/src/0000755€í4H€L¨x 0000000000011462100143015746 5ustar tcluneNDC\domain usersExercise_3/3-D/src/GNUmakefile0000644€í4H€L¨x 0000000102311462071073020025 0ustar tcluneNDC\domain usersROOT_DIR = .. LIB_DIR = $(ROOT_DIR)/lib MOD_DIR = $(ROOT_DIR)/mod LIB = libinterpolator.a MOD = interpolator_mod.mod F90 ?= ifort F90FLAGS += -I. -I$(MOD_DIR) -I$(PFUNIT)/mod SRC = $(wildcard *.F90) OBJS = $(SRC:.F90=.o) .PHONY= all all: $(LIB) tests tests: mkdir -p $(LIB_DIR) mkdir -p $(MOD_DIR) cp $(LIB) $(LIB_DIR)/. cp $(MOD) $(MOD_DIR)/. $(LIB): $(OBJS) ar -cr $@ $? %.o:%.F90 $(F90) -c $(F90FLAGS) $< clean: $(RM) $(OBJS) $(LIB) $(RM) *.mod distclean: clean $(RM) $(LIB_DIR)/$(LIB) $(MOD_DIR)/$(MOD) Exercise_3/3-D/src/Interpolator_mod.F900000644€í4H€L¨x 0000000272611462072672021575 0ustar tcluneNDC\domain usersmodule Interpolator_mod implicit none private public :: Interpolator_type public :: newInterpolator public :: clean public :: getIntervalIndex public :: computeWeight type Interpolator_type real, pointer :: nodes(:) end type Interpolator_type interface clean module procedure cleanInterpolator end interface contains function newInterpolator(nodes) result(interpolator) type (Interpolator_type) :: interpolator real, intent(in) :: nodes(:) allocate(interpolator%nodes(size(nodes))) interpolator%nodes = nodes end function newInterpolator function getIntervalIndex(this, x) result(index) use pFUnit, only: throw type (Interpolator_type), intent(in) :: this real, intent(in) :: x integer :: index integer :: i integer, parameter :: NOT_FOUND = -1 index = NOT_FOUND do i = 1, size(this%nodes) - 1 if (this%nodes(i) <= x .and. x < this%nodes(i+1)) then index = i exit end if end do if (index == NOT_FOUND) call throw('coordinate out-of-bounds') end function getIntervalIndex real function computeWeight(interval, x) result(w_1) real, intent(in) :: interval(2) real, intent(in) :: x w_1 = (interval(2) - x) / (interval(2) - interval(1)) end function computeWeight subroutine cleanInterpolator(this) type (Interpolator_type), intent(inout) :: this deallocate(this%nodes) end subroutine cleanInterpolator end module Interpolator_mod Exercise_3/3-D/tests/0000755€í4H€L¨x 0000000000011462100144016322 5ustar tcluneNDC\domain usersExercise_3/3-D/tests/GNUmakefile0000644€í4H€L¨x 0000000130611462071073020404 0ustar tcluneNDC\domain users# Important: specify a serial PFUNIT installation. # Check for the PFUNIT environment variable ifndef PFUNIT $(error The environment variable "PFUNIT" must be given a value which is the \ path for the installation of pFUnit.) endif F90 ?= ifort FC = $(F90) ROOT_DIR = .. LIB_DIR = $(ROOT_DIR)/lib MOD_DIR = $(ROOT_DIR)/mod F90FLAGS = -I. -I$(MOD_DIR) PFUNIT_TEST_DIRECTORIES =. PFUNIT_LFLAGS = -L$(LIB_DIR) -linterpolator .PHONY: all clean distclean VPATH += ../src tests.x: libinterpolator.a %.o : %.F90 $(FC) -c $(F90FLAGS) $< all: tests clean: $(RM) *.o $(RM) *.mod $(RM) .pFUnitLog distclean: clean $(MAKE) pfunitdistclean export PFUNIT include $(PFUNIT)/include/pFUnit.makefile Exercise_3/3-D/tests/TestInterpolator_mod.F900000644€í4H€L¨x 0000000344311462074032022775 0ustar tcluneNDC\domain usersmodule TestInterpolator_mod use pFUnit use Interpolator_mod implicit none private public :: test_getIntervalIndex public :: test_getIntervalIndexB public :: test_trapOutOfBounds public :: test_computeWeight contains subroutine test_getIntervalIndex() type (Interpolator_type) :: interpolator real :: nodes(2) = (/ 0., 1. /) interpolator = newInterpolator(nodes) call assertEqual(1, getIntervalIndex(interpolator, 0.5)) call clean(interpolator) end subroutine test_getIntervalIndex subroutine test_getIntervalIndexB() type (Interpolator_type) :: interpolator real :: nodes(4) = (/ 0., 2., 5., 6./) interpolator = newInterpolator(nodes) call assertEqual(1, getIntervalIndex(interpolator, 1.0), "x=1.0") call assertEqual(2, getIntervalIndex(interpolator, 3.0), "x=3.0") call assertEqual(2, getIntervalIndex(interpolator, 4.0), "x=4.0") call assertEqual(3, getIntervalIndex(interpolator, 5.0), "x=5.5") call clean(interpolator) end subroutine test_getIntervalIndexB subroutine test_TrapOutOfBounds() type (Interpolator_type) :: interpolator real :: nodes(2) = (/ 0., 1. /) integer :: index interpolator = newInterpolator(nodes) index = getIntervalIndex(interpolator, 2.0) if (.not. catch('coordinate out-of-bounds')) then call throw('Failed to trap out-of-bounds') end if call clean(interpolator) end subroutine test_TrapOutOfBounds subroutine test_computeWeight() call assertEqual(1.0, computeWeight([0.,1.], 0.0), 'x=0.0') call assertEqual(0.0, computeWeight([0.,1.], 1.0), 'x=1.0') call assertEqual(0.5, computeWeight([0.,1.], 0.5), 'x=0.5') call assertEqual(2./3, computeWeight([1.,4.], 2.), 'x=2.0') end subroutine test_computeWeight end module TestInterpolator_mod Exercise_3/3-E/0000755€í4H€L¨x 0000000000011462100062015160 5ustar tcluneNDC\domain usersExercise_3/3-E/GNUmakefile0000644€í4H€L¨x 0000000047011462073106017243 0ustar tcluneNDC\domain usersSRC_DIR = src TESTS_DIR = tests LIB_DIR = lib MOD_DIR = mod .PHONY= all all: $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ tests: all clean: $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ distclean: clean $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ rm -rf $(LIB_DIR) $(MOD_DIR) Exercise_3/3-E/src/0000755€í4H€L¨x 0000000000011462100150015745 5ustar tcluneNDC\domain usersExercise_3/3-E/src/GNUmakefile0000644€í4H€L¨x 0000000102311462073106020025 0ustar tcluneNDC\domain usersROOT_DIR = .. LIB_DIR = $(ROOT_DIR)/lib MOD_DIR = $(ROOT_DIR)/mod LIB = libinterpolator.a MOD = interpolator_mod.mod F90 ?= ifort F90FLAGS += -I. -I$(MOD_DIR) -I$(PFUNIT)/mod SRC = $(wildcard *.F90) OBJS = $(SRC:.F90=.o) .PHONY= all all: $(LIB) tests tests: mkdir -p $(LIB_DIR) mkdir -p $(MOD_DIR) cp $(LIB) $(LIB_DIR)/. cp $(MOD) $(MOD_DIR)/. $(LIB): $(OBJS) ar -cr $@ $? %.o:%.F90 $(F90) -c $(F90FLAGS) $< clean: $(RM) $(OBJS) $(LIB) $(RM) *.mod distclean: clean $(RM) $(LIB_DIR)/$(LIB) $(MOD_DIR)/$(MOD) Exercise_3/3-E/src/Interpolator_mod.F900000644€í4H€L¨x 0000000355511462075033021571 0ustar tcluneNDC\domain usersmodule Interpolator_mod implicit none private public :: Interpolator_type public :: newInterpolator public :: clean public :: getIntervalIndex public :: computeWeight public :: interpolate type Interpolator_type real, pointer :: nodes(:) end type Interpolator_type interface clean module procedure cleanInterpolator end interface contains function newInterpolator(nodes) result(interpolator) type (Interpolator_type) :: interpolator real, intent(in) :: nodes(:) allocate(interpolator%nodes(size(nodes))) interpolator%nodes = nodes end function newInterpolator function getIntervalIndex(this, x) result(index) use pFUnit, only: throw type (Interpolator_type), intent(in) :: this real, intent(in) :: x integer :: index integer :: i integer, parameter :: NOT_FOUND = -1 index = NOT_FOUND do i = 1, size(this%nodes) - 1 if (this%nodes(i) <= x .and. x < this%nodes(i+1)) then index = i exit end if end do if (index == NOT_FOUND) call throw('coordinate out-of-bounds') end function getIntervalIndex real function computeWeight(interval, x) result(w_1) real, intent(in) :: interval(2) real, intent(in) :: x w_1 = (interval(2) - x) / (interval(2) - interval(1)) end function computeWeight real function interpolate(this, data, x) result(y) type (Interpolator_type), intent(in) :: this real, intent(in) :: data(:) real, intent(in) :: x integer :: index real :: w1, w2 index = getIntervalIndex(this, x) w1 = computeWeight(this%nodes(index:index+1), x) w2 = 1-w1 y = w1 * data(index) + w2 * data(index+1) end function interpolate subroutine cleanInterpolator(this) type (Interpolator_type), intent(inout) :: this deallocate(this%nodes) end subroutine cleanInterpolator end module Interpolator_mod Exercise_3/3-E/tests/0000755€í4H€L¨x 0000000000011462100150016320 5ustar tcluneNDC\domain usersExercise_3/3-E/tests/GNUmakefile0000644€í4H€L¨x 0000000130611462073106020404 0ustar tcluneNDC\domain users# Important: specify a serial PFUNIT installation. # Check for the PFUNIT environment variable ifndef PFUNIT $(error The environment variable "PFUNIT" must be given a value which is the \ path for the installation of pFUnit.) endif F90 ?= ifort FC = $(F90) ROOT_DIR = .. LIB_DIR = $(ROOT_DIR)/lib MOD_DIR = $(ROOT_DIR)/mod F90FLAGS = -I. -I$(MOD_DIR) PFUNIT_TEST_DIRECTORIES =. PFUNIT_LFLAGS = -L$(LIB_DIR) -linterpolator .PHONY: all clean distclean VPATH += ../src tests.x: libinterpolator.a %.o : %.F90 $(FC) -c $(F90FLAGS) $< all: tests clean: $(RM) *.o $(RM) *.mod $(RM) .pFUnitLog distclean: clean $(MAKE) pfunitdistclean export PFUNIT include $(PFUNIT)/include/pFUnit.makefile Exercise_3/3-E/tests/TestInterpolator_mod.F900000644€í4H€L¨x 0000000564011462075066023007 0ustar tcluneNDC\domain usersmodule TestInterpolator_mod use pFUnit use Interpolator_mod implicit none private public :: test_getIntervalIndex public :: test_getIntervalIndexB public :: test_trapOutOfBounds public :: test_computeWeight public :: test_InterpolateConstant public :: test_InterpolateVarying contains subroutine test_getIntervalIndex() type (Interpolator_type) :: interpolator real :: nodes(2) = (/ 0., 1. /) interpolator = newInterpolator(nodes) call assertEqual(1, getIntervalIndex(interpolator, 0.5)) call clean(interpolator) end subroutine test_getIntervalIndex subroutine test_getIntervalIndexB() type (Interpolator_type) :: interpolator real :: nodes(4) = (/ 0., 2., 5., 6./) interpolator = newInterpolator(nodes) call assertEqual(1, getIntervalIndex(interpolator, 1.0), "x=1.0") call assertEqual(2, getIntervalIndex(interpolator, 3.0), "x=3.0") call assertEqual(2, getIntervalIndex(interpolator, 4.0), "x=4.0") call assertEqual(3, getIntervalIndex(interpolator, 5.0), "x=5.5") call clean(interpolator) end subroutine test_getIntervalIndexB subroutine test_TrapOutOfBounds() type (Interpolator_type) :: interpolator real :: nodes(2) = (/ 0., 1. /) integer :: index interpolator = newInterpolator(nodes) index = getIntervalIndex(interpolator, 2.0) if (.not. catch('coordinate out-of-bounds')) then call throw('Failed to trap out-of-bounds') end if call clean(interpolator) end subroutine test_TrapOutOfBounds subroutine test_computeWeight() call assertEqual(1.0, computeWeight([0.,1.], 0.0), 'x=0.0') call assertEqual(0.0, computeWeight([0.,1.], 1.0), 'x=1.0') call assertEqual(0.5, computeWeight([0.,1.], 0.5), 'x=0.5') call assertEqual(2./3, computeWeight([1.,4.], 2.), 'x=2.0') end subroutine test_computeWeight subroutine test_InterpolateConstant() type (Interpolator_type) :: interpolator real :: nodes(2) = [0., 1.] real :: yData(2) = [1., 1.] interpolator = newInterpolator(nodes) call assertEqual(1., interpolate(interpolator, yData, 0.0), 'x=0.0') call assertEqual(1., interpolate(interpolator, yData, 0.9), 'x=1.0') call assertEqual(1., interpolate(interpolator, yData, 0.5), 'x=0.5') end subroutine test_InterpolateConstant subroutine test_InterpolateVarying() type (Interpolator_type) :: interpolator real :: nodes(4) = [0., 1., 3., 4.] real :: yData(4) = [1., 2., 6., 6.] interpolator = newInterpolator(nodes) call assertEqual(1.0, interpolate(interpolator, yData, 0.0), 'x=1.0') call assertEqual(1.5, interpolate(interpolator, yData, 0.5), 'x=0.5') call assertEqual(2.0, interpolate(interpolator, yData, 1.0), 'x=1.0') call assertEqual(4.0, interpolate(interpolator, yData, 2.0), 'x=2.0') call assertEqual(6.0, interpolate(interpolator, yData, 3.5), 'x=3.5') end subroutine test_InterpolateVarying end module TestInterpolator_mod Exercise_3/3-F/0000755€í4H€L¨x 0000000000011462100062015161 5ustar tcluneNDC\domain usersExercise_3/3-F/GNUmakefile0000644€í4H€L¨x 0000000047011462075102017242 0ustar tcluneNDC\domain usersSRC_DIR = src TESTS_DIR = tests LIB_DIR = lib MOD_DIR = mod .PHONY= all all: $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ tests: all clean: $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ distclean: clean $(MAKE) -C $(SRC_DIR) $@ $(MAKE) -C $(TESTS_DIR) $@ rm -rf $(LIB_DIR) $(MOD_DIR) Exercise_3/3-F/src/0000755€í4H€L¨x 0000000000011462100160015747 5ustar tcluneNDC\domain usersExercise_3/3-F/src/GNUmakefile0000644€í4H€L¨x 0000000102311462075102020024 0ustar tcluneNDC\domain usersROOT_DIR = .. LIB_DIR = $(ROOT_DIR)/lib MOD_DIR = $(ROOT_DIR)/mod LIB = libinterpolator.a MOD = interpolator_mod.mod F90 ?= ifort F90FLAGS += -I. -I$(MOD_DIR) -I$(PFUNIT)/mod SRC = $(wildcard *.F90) OBJS = $(SRC:.F90=.o) .PHONY= all all: $(LIB) tests tests: mkdir -p $(LIB_DIR) mkdir -p $(MOD_DIR) cp $(LIB) $(LIB_DIR)/. cp $(MOD) $(MOD_DIR)/. $(LIB): $(OBJS) ar -cr $@ $? %.o:%.F90 $(F90) -c $(F90FLAGS) $< clean: $(RM) $(OBJS) $(LIB) $(RM) *.mod distclean: clean $(RM) $(LIB_DIR)/$(LIB) $(MOD_DIR)/$(MOD) Exercise_3/3-F/src/Interpolator_mod.F900000644€í4H€L¨x 0000000504311462077732021574 0ustar tcluneNDC\domain usersmodule Interpolator_mod implicit none private public :: Interpolator_type public :: newInterpolator public :: clean public :: getIntervalIndex public :: computeWeightLinear public :: computeWeightNearest public :: interpolate integer, parameter, public :: LINEAR = 1 integer, parameter, public :: NEAREST = 2 type Interpolator_type real, pointer :: nodes(:) integer :: method end type Interpolator_type interface clean module procedure cleanInterpolator end interface contains function newInterpolator(nodes, method) result(interpolator) type (Interpolator_type) :: interpolator real, intent(in) :: nodes(:) integer, intent(in) :: method allocate(interpolator%nodes(size(nodes))) interpolator%nodes = nodes interpolator%method = method ! save for later end function newInterpolator function getIntervalIndex(this, x) result(index) use pFUnit, only: throw type (Interpolator_type), intent(in) :: this real, intent(in) :: x integer :: index integer :: i integer, parameter :: NOT_FOUND = -1 index = NOT_FOUND do i = 1, size(this%nodes) - 1 if (this%nodes(i) <= x .and. x < this%nodes(i+1)) then index = i exit end if end do if (index == NOT_FOUND) call throw('coordinate out-of-bounds') end function getIntervalIndex real function computeWeightLinear(interval, x) result(w_1) real, intent(in) :: interval(2) real, intent(in) :: x w_1 = (interval(2) - x) / (interval(2) - interval(1)) end function computeWeightLinear real function computeWeightNearest(interval, x) result(w_1) real, intent(in) :: interval(2) real, intent(in) :: x real :: midpoint midpoint = (interval(1) + interval(2))/2 if (x < midpoint) then w_1 = 1.0 else w_1 = 0.0 end if end function computeWeightNearest real function interpolate(this, data, x) result(y) type (Interpolator_type), intent(in) :: this real, intent(in) :: data(:) real, intent(in) :: x integer :: index real :: w1, w2 index = getIntervalIndex(this, x) if (this%method == LINEAR) then w1 = computeWeightLinear(this%nodes(index:index+1), x) else w1 = computeWeightNearest(this%nodes(index:index+1), x) end if w2 = 1-w1 y = w1 * data(index) + w2 * data(index+1) end function interpolate subroutine cleanInterpolator(this) type (Interpolator_type), intent(inout) :: this deallocate(this%nodes) end subroutine cleanInterpolator end module Interpolator_mod Exercise_3/3-F/tests/0000755€í4H€L¨x 0000000000011462100160016322 5ustar tcluneNDC\domain usersExercise_3/3-F/tests/GNUmakefile0000644€í4H€L¨x 0000000130611462075102020403 0ustar tcluneNDC\domain users# Important: specify a serial PFUNIT installation. # Check for the PFUNIT environment variable ifndef PFUNIT $(error The environment variable "PFUNIT" must be given a value which is the \ path for the installation of pFUnit.) endif F90 ?= ifort FC = $(F90) ROOT_DIR = .. LIB_DIR = $(ROOT_DIR)/lib MOD_DIR = $(ROOT_DIR)/mod F90FLAGS = -I. -I$(MOD_DIR) PFUNIT_TEST_DIRECTORIES =. PFUNIT_LFLAGS = -L$(LIB_DIR) -linterpolator .PHONY: all clean distclean VPATH += ../src tests.x: libinterpolator.a %.o : %.F90 $(FC) -c $(F90FLAGS) $< all: tests clean: $(RM) *.o $(RM) *.mod $(RM) .pFUnitLog distclean: clean $(MAKE) pfunitdistclean export PFUNIT include $(PFUNIT)/include/pFUnit.makefile Exercise_3/3-F/tests/TestInterpolator_mod.F900000644€í4H€L¨x 0000001050711462077720023005 0ustar tcluneNDC\domain usersmodule TestInterpolator_mod use pFUnit use Interpolator_mod implicit none private public :: test_getIntervalIndex public :: test_getIntervalIndexB public :: test_trapOutOfBounds public :: test_computeWeightLinear public :: test_computeWeightNearest public :: test_InterpolateConstant public :: test_InterpolateVarying public :: test_InterpolateNearest contains subroutine test_getIntervalIndex() type (Interpolator_type) :: interpolator real :: nodes(2) = (/ 0., 1. /) interpolator = newInterpolator(nodes, LINEAR) call assertEqual(1, getIntervalIndex(interpolator, 0.5)) call clean(interpolator) end subroutine test_getIntervalIndex subroutine test_getIntervalIndexB() type (Interpolator_type) :: interpolator real :: nodes(4) = (/ 0., 2., 5., 6./) interpolator = newInterpolator(nodes, LINEAR) call assertEqual(1, getIntervalIndex(interpolator, 1.0), "x=1.0") call assertEqual(2, getIntervalIndex(interpolator, 3.0), "x=3.0") call assertEqual(2, getIntervalIndex(interpolator, 4.0), "x=4.0") call assertEqual(3, getIntervalIndex(interpolator, 5.0), "x=5.5") call clean(interpolator) end subroutine test_getIntervalIndexB subroutine test_TrapOutOfBounds() type (Interpolator_type) :: interpolator real :: nodes(2) = (/ 0., 1. /) integer :: index interpolator = newInterpolator(nodes, LINEAR) index = getIntervalIndex(interpolator, 2.0) if (.not. catch('coordinate out-of-bounds')) then call throw('Failed to trap out-of-bounds') end if call clean(interpolator) end subroutine test_TrapOutOfBounds subroutine test_computeWeightLinear() call assertEqual(1.0, computeWeightLinear([0.,1.], 0.0), 'x=0.0') call assertEqual(0.0, computeWeightLinear([0.,1.], 1.0), 'x=1.0') call assertEqual(0.5, computeWeightLinear([0.,1.], 0.5), 'x=0.5') call assertEqual(2./3, computeWeightLinear([1.,4.], 2.), 'x=2.0') end subroutine test_computeWeightLinear subroutine test_computeWeightNearest() call assertEqual(1.0, computeWeightNearest([0.,1.], 0.0), 'x=0.0') call assertEqual(1.0, computeWeightNearest([0.,1.], 0.4), 'x=0.4') call assertEqual(0.0, computeWeightNearest([0.,1.], 0.5), 'x=0.5') call assertEqual(0.0, computeWeightNearest([0.,1.], 0.6), 'x=0.6') call assertEqual(0.0, computeWeightNearest([0.,1.], 1.0), 'x=1.0') call assertEqual(1.0, computeWeightNearest([1.,4.], 2.), 'x=2.0') end subroutine test_computeWeightNearest subroutine test_InterpolateConstant() type (Interpolator_type) :: interpolator real :: nodes(2) = [0., 1.] real :: yData(2) = [1., 1.] interpolator = newInterpolator(nodes, LINEAR) call assertEqual(1., interpolate(interpolator, yData, 0.0), 'x=0.0') call assertEqual(1., interpolate(interpolator, yData, 0.9), 'x=1.0') call assertEqual(1., interpolate(interpolator, yData, 0.5), 'x=0.5') end subroutine test_InterpolateConstant subroutine test_InterpolateVarying() type (Interpolator_type) :: interpolator real :: nodes(4) = [0., 1., 3., 4.] real :: yData(4) = [1., 2., 6., 6.] interpolator = newInterpolator(nodes, LINEAR) call assertEqual(1.0, interpolate(interpolator, yData, 0.0), 'x=1.0') call assertEqual(1.5, interpolate(interpolator, yData, 0.5), 'x=0.5') call assertEqual(2.0, interpolate(interpolator, yData, 1.0), 'x=1.0') call assertEqual(4.0, interpolate(interpolator, yData, 2.0), 'x=2.0') call assertEqual(6.0, interpolate(interpolator, yData, 3.5), 'x=3.5') end subroutine test_InterpolateVarying subroutine test_InterpolateNearest() type (Interpolator_type) :: interpolator real :: nodes(4) = [0., 1., 3., 4.] real :: yData(4) = [1., 2., 6., 6.] interpolator = newInterpolator(nodes, NEAREST) call assertEqual(1.0, interpolate(interpolator, yData, 0.0), 'x=0.0') call assertEqual(1.0, interpolate(interpolator, yData, 0.4), 'x=0.4') call assertEqual(2.0, interpolate(interpolator, yData, 0.6), 'x=0.6') call assertEqual(2.0, interpolate(interpolator, yData, 1.5), 'x=1.5') call assertEqual(6.0, interpolate(interpolator, yData, 2.0), 'x=2.0') call assertEqual(6.0, interpolate(interpolator, yData, 2.5), 'x=2.5') call assertEqual(6.0, interpolate(interpolator, yData, 3.6), 'x=3.6') end subroutine test_InterpolateNearest end module TestInterpolator_mod Exercise_3/README0000644€í4H€L¨x 0000001560611462077762015550 0ustar tcluneNDC\domain usersExercise 3: Interpolator (Advanced) In this exercise we'll construct a routine for interpolating one-dimensional non-uniformly spaced data. Initially we will develop the capability for linear interpolation, but we will then add an option to use nearest-neighbor optimization. This exercise will also introduce how pFUnit can be used to test the portion of the application that checks for illegal input parameters. In anticipation that the requirements will be changing, we will use a more object-based approach for this exercise. I.e. we will use a derived data type to contain state information for our interpolator. In addition to the benefits of encapsulation, the object-based approach is friendly to TDD by enabling shorter argument lists. If you are unfamiliar with the F90 derived types, try not to worry. The basics are already in place in directory 3-A, and you will only need to do extensions. You can also try to pair with another attendee with relevant experience. ============ Step 3-A: ============ Change into directory ./Exercise_3/3-A. Examine the implementation, and verify that you can build and execute the one existing test. This test is using the function getIntervalIndex() which is intended to determine where which nodes points bracket a given interpolation point. At this point the implementation simply always returns "1" indicating that all points fall in the 1st interval. Clearly you need more tests. Add another similar test which has at least 3 nodal points and checks that the appropriate interval is returned depending on where the interpolation point is located. E.g. if our nodal points are {1,2,3} then x=1.5 should return 1 while x=2.7 should return 2. To pass the test, you will need to modify the constructor routine (newInterpolator) to save a copy of the nodes in the data structure for later reference. ============ Step 3-B: ============ (If you were not successful with step 3-A, you can continue on in the 3-B subdirectory.) Often with scientific software we are unconcerned with handling illegal input values - we just allow the code to crash. However, for certain common types of invalid input it can be useful to provide a more helpful error message and gentler exit than "segmentation fault". E.g. suppose a caller passes an interpolation point that is outside the domain specified by the nodes? Or what if the nodes are not monotonically increasing? In this step we will use the material from the slides to develop test that ensure the application properly traps out-of-bounds values. Write a new test that attempts to pass an interpolation point that is out-of-bounds and then checks (using catch()) that the situation was correctly diagnosed. Extend the implementation of getIntervalIndex() to pass the new test. ============ Step 3-C: ============ Now we want to develop a routine which computes the weight factors used for linear interpolation. I.e. if the nodal points are x_1 and x_2, and the interpolation point is x (with x_1 <= x < x_2) then we have: w_1 = (x_2 - x) / (x_2 - x_1) w_2 = (x - x_1) / (x_2 - x_1) = 1 - w_1 Create a test which uses simple data to exercise a routine called computeWeight(). The first argument is a length 2 array of the nodal points, and the second argument is the interpolation point. The function returns w_1. (If you are a more advanced user of F90, I recommend having the function return an array of 2 reals: w_1 and w_2.) Next, implement computeWeight() to check your results. Be sure to include test cases that include interpolation points located at nodal points. (We could also add checks for bounds here, but will skip it in the interests of time.) ============ Step 3-D: ============ Now we will develop the interpolation routine itself. Your interface should look like: interpolator = newInterpolator(nodes) y = interpolate(interpolator, data, x) Here "data" is an array of the same length as nodes that contains the y-values to be interpolated. With this interface we could interpolate multiple fields (e.g. U, V, T, P) that use the same underlying grid (nodes). Create the test "testInterpolateConstant()" using a simple set of nodes and constant values for data - e.g. 1.0. The interpolate() function should return the same constant value independent of x. Once you have the test compiling, implement the interpolate() function to always return 0.0, and verify that the test fails. Now, modify the interpolate() function to return 1.0 and verify that the test succeeds. Next, create a more complicated test "testIntepolateVarying()" with varying data. E.g. use nodes = {0, 2, 3}, data = {0, 2, 4}. You should have 1.0 = interpolate(interpolator, data, 1.0) 3.0 = interpolate(interpolator, data, 2.5) 2.0 = interpolate(interpolator, data, 2.0) Once the test compiles, extend the implementation of interpolate() to use getIntervalIndex() together with computeWeight() to perform the necessary interpolations. ============ Step 3-E: ============ Now you suddenly recall that the implementation is also supposed to support "nearest-neighbor" interpolation. Fortunately you realize that this only affects how w_1 and w_2 are computed. Each is either 0 or 1 depending on whether x is closer to one node or the other node that brackets the interval. E.g. for the interval [1,3], w_1 = 1.0 for x between 1 and 2, and w_1 = 0.0 for x between 2 and 3. (w_2 = 1 - w_1 as before.) We will use a technique known as "refactoring" to modify the existing implementation in very small steps to pave the way for the augmented functionality. The important thing is to get back to the state where all tests pass as quickly as possible. i) In Interpolator_mod.F90 declare two public integer parameters: integer, parameter, public :: LINEAR = 1 integer, parameter, public :: NEAREST = 2 ii) In the existing tests, insert LINEAR as a second argument to every call to newInterpolator(). The compilation should now fail, because of the mismatched interface. iii) Add a second argument for the implementation of newInterpolator(). It is unused for now, but should get the tests to pass. iv) Rename computeWeight() => computeWeightLinear() in the tests, and make the corresponding changes to the implementation to get the tests to pass again. v) Use TDD to develop an analogous routine computeWeightNearest(). Think about what convention to use for points halfway between nodes. vi) Add a new interpolation test that constructs the interpolator with NEAREST as the second argument and has correspondingly different results. The test should intitially fail because it is still using linear interpolation underneath. Now insert a conditional in the implementation of interpolate() to use the appropriate computeWeight function. Make the test pass. (Note - you will need to add another element to the derived type to save the value fo the type of interpolation.) Full solution is in directory 3-F.