Project 6
Modify your bird_data
type from
Project 5 to make it a class. Make all the methods private.
You may use the same file_utils.f90 and sorters.f90 as before.
You may find that you need to declare your allocatable bird_list array to be of type class
.
Sample solution
module bird_dat
implicit none
type bird_data
character(len=50) :: species
integer, dimension(:), allocatable :: obs
contains
procedure:: init=>constructor
procedure:: stats
procedure:: minmax
end type bird_data
private constructor, stats, minmax
contains
subroutine constructor(bird,species,dat)
class(bird_data), intent(inout) :: bird
character(len=50), intent(in) :: species
integer, dimension(:), intent(in) :: dat
bird%species=species
allocate(bird%obs(size(dat)))
bird%obs=dat
end subroutine
subroutine stats(bird,mean,std)
class(bird_data), intent(inout) :: bird
real, intent(out) :: mean,std
real :: mu2
mean=sum(bird%obs)/float(size(bird%obs))
mu2=(sum(bird%obs)/float(size(bird%obs)))**2
std=sqrt(sum(bird%obs**2-(mu2))/float(size(bird%obs)))
end subroutine
subroutine minmax(bird,years,min_val,max_val,min_year,max_year)
class(bird_data), intent(inout) :: bird
integer, dimension(:), intent(in) :: years
real, intent(out) :: min_val,max_val
integer, intent(out) :: min_year, max_year
min_val=minval(bird%obs)
max_val=maxval(bird%obs)
min_year=years(minloc(bird%obs,1))
max_year=years(maxloc(bird%obs,1))
end subroutine
end module
program bird_obs
use bird_dat
use sorters
implicit none
!******************************************************************
!Mean observations, standard deviation, max and min of a set of
!bird observations
!Author: Katherine Holcomb
!Changelog: Initial version 2015-03-4
!******************************************************************
class(bird_data),dimension (:), allocatable :: bird_list
real, dimension(:), allocatable :: means,stds,oldmeans
character(len=50) :: filename
character(len=50) :: species,my_species,lc_species
integer :: n, nargs, nbirds
logical :: found_it
real :: std,mean,min_val,max_val
integer :: min_year, max_year
integer, dimension(:),allocatable :: years, pvec
interface
subroutine read_data(bird_list,filename,years)
use bird_dat
use file_utils
implicit none
class(bird_data), dimension(:),allocatable, intent(out) :: bird_list
character(len=*), intent(in) :: filename
integer, dimension(:),allocatable, intent(out) :: years
end subroutine
end interface
nargs=command_argument_count()
if ( nargs .ne. 2 ) then
stop "Usage: <file> species"
else
call get_command_argument(1,filename)
call get_command_argument(2,my_species)
endif
call read_data(bird_list,filename,years)
nbirds=size(bird_list)
found_it=.false.
allocate(means(nbirds),stds(nbirds))
do n=1,nbirds
call bird_list(n)%stats(means(n),stds(n))
if (my_species==bird_list(n)%species) then
mean=means(n)
std=stds(n)
call bird_list(n)%minmax(years,min_val,max_val,min_year,max_year)
found_it=.true.
endif
enddo
if (found_it) then
write(*,*) "Statistics for "//my_species
write(*,'(a,f8.2)',advance='no') "The minimum value of observations is:",min_val
write(*,'(a,i5)') " in year",min_year
write(*,'(a,f8.2)',advance='no') "The maximum value of observations is:",max_val
write(*,'(a,i5)') " in year",max_year
write(*,'(a,f0.2)') "The mean value of the observations is:",mean
write(*,'(a,f0.2)') "The standard deviation of the observations is:",std
else
write(*,*) "Requested species not found in the data file."
endif
allocate(pvec(nbirds))
allocate(oldmeans(size(means)))
oldmeans=means
call pshellsort(means,pvec,nbirds)
write(*,*)
write(*,*) 'The 10 most common birds are'
do n=nbirds,nbirds-9,-1
write(*,'(a,f8.2)') bird_list(pvec(n))%species(1:len_trim(species)),oldmeans(pvec(n))
enddo
End program
subroutine read_data(bird_list,filename,years)
use bird_dat
use file_utils
implicit none
class(bird_data),dimension(:), allocatable, intent(out) :: bird_list
character(len=*), intent(in) :: filename
integer, dimension(:), allocatable, intent(out) :: years
integer, dimension(:), allocatable :: obs
integer, parameter :: nobs=47
character(len=6),dimension(nobs) :: cyears
integer :: inunit
integer :: nheaders,nbirds
character(len=50) :: species
character(len=1024) :: line
character(len=:),dimension(:),allocatable :: line_vals
integer :: num_vals
integer :: n
inunit=open_file(filename,'r')
if (inunit .ne. 0) then
open(unit=inunit,file=filename)
else
stop "Unable to open specified data file."
endif
nheaders=3
nbirds=count_records(inunit,nheaders)
allocate(bird_list(nbirds))
allocate(years(nobs))
read(inunit,*) species,cyears(:)
do n=1,nobs
read(cyears(n),'(i4)') years(n)
enddo
allocate(obs(nobs))
do n=1,nbirds
read(inunit,*) species, obs
call bird_list(n)%init(species,obs)
end do
end subroutine read_data