DATA Statement issue : Not enough variables - fortran

I'm facing difficulties to figure out why my code is giving me this error
error 281 - Not enough variables in DATA statement
I am using the latest Silverfrost on Windows 8. The relevant piece of my module is,
...
INTEGER, parameter :: maxExampleTypes = 5
TYPE ExampleInfo
CHARACTER (len=50) :: ExDeckName
INTEGER A(maxExampleTypes)
INTEGER ExUnits
ENDTYPE ExampleInfo
TYPE(ExampleInfo) :: Example(10)
DATA Example(1)%ExDeckName/'test.dck'/
DATA Example(1)%A/1,2,3,4,5/
...
Curiously, when I only specify one variable for A with
DATA Example(1)%A/1/
the error disappears.
Have you got any idea where it could come from?

I would never use the DATA statement in modern Fortran. Try
...
INTEGER, parameter :: maxExampleTypes = 5
TYPE ExampleInfo
CHARACTER (len=50) :: ExDeckName
INTEGER :: A(maxExampleTypes)
INTEGER :: ExUnits
ENDTYPE ExampleInfo
TYPE(ExampleInfo) :: Example(10)
Example(1)%ExDeckName = 'test.dck'
Example(1)%A = (/ 1,2,3,4,5 /)
...
If the values are supposed to be default values, put them into the type declaration:
...
INTEGER, parameter :: maxExampleTypes = 5
TYPE ExampleInfo
CHARACTER (len=50) :: ExDeckName = 'test.dck'
INTEGER :: A(maxExampleTypes) = (/ 1,2,3,4,5 /)
INTEGER :: ExUnits
ENDTYPE ExampleInfo
TYPE(ExampleInfo) :: Example(10)
...
Sample test program:
module testmod
implicit none
INTEGER, parameter :: maxExampleTypes = 5
! Type with default values
TYPE ExampleInfo
CHARACTER (len=50) :: ExDeckName = 'test.dck'
INTEGER :: A(maxExampleTypes)= (/ 1,2,3,4,5 /)
INTEGER :: ExUnits
ENDTYPE ExampleInfo
contains
subroutine init_ExampleInfo(array)
implicit none
type(ExampleInfo), intent(out):: array(:)
integer :: i
do i=1,size(array)
array(i)%ExDeckName = 'test.dck'
array(i)%A = (/ 1,2,3,4,5 /)
enddo
end subroutine
end module
program test
use testmod
implicit none
TYPE(ExampleInfo) :: Example(10)
! Initialize manually
! call init_ExampleInfo(Example)
write(*,*) Example(1)%ExDeckName, Example(1)%A
! Set new values
Example(1)%ExDeckName = 'test2.dck'
Example(1)%A = (/ 5,4,3,2,1 /)
write(*,*) Example(1)%ExDeckName, Example(1)%A
end program

Related

Errors #6259, #7715, #6355, #6303 in defining Derived Type specific assignment/operator procedures

First of all, Hi to everyone ! Wish you all a good starting week :)
In enhancing (as well as simplifying some syntax) a previously developed Derived Type, I was (and some still) encountering some errors as in the title specification (NOTE: for details about full messages and their cause, please read the comment lines in the code below :) ).
Among them, the ones I was not understand the most (of the why I am getting them) are error #6355: This binary operation is invalid for this data type. for the operator(==), and error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. for the assignment(=).
Here is an example of source code (NOTE: in order to reproduce those errors, comment out the type-bound procedure part, and uncomment out the two interface bodies):
module MPolicyMod
implicit none
private
public :: MPolicy
type, public :: MPolicy_t
real(kind = 8) :: delta_fI_fct_
real(kind = 8) :: delta_fJ_fct_
real(kind = 8) :: interp_I_fct_
real(kind = 8) :: interp_J_fct_
integer :: id_pol_
contains
generic :: assignment(=) => MPolicy_fromPol_sub, MPolicy_fromID_sub
procedure, private, pass :: MPolicy_fromID_sub, MPolicy_fromPol_sub
generic :: operator(==) => MPolicy_isID
procedure, pass, private :: MPolicy_isID
end type MPolicy_t
integer, public, parameter :: MPolicy_NULL = 0
integer, public, parameter :: MPolicy_DEF = 1
integer, public, parameter :: MPolicy_CONST = 2
interface MPolicy_t
module procedure MPolicy_constructor_integer
module procedure MPolicy_constructor_real
module procedure MPolicy_fromID
end interface
! interface assignment(=)
! module procedure MPolicy_fromPol_sub
! module procedure MPolicy_fromID_sub
! end interface assignment(=)
! interface operator(==)
! module procedure MPolicy_isID
! end interface operator(==)
contains
!> Main default constructor.
function MPolicy_constructor_real(dfi, dfj, interpi, interpj, id) result(pol)
real(kind = 8), intent(in) :: dfi, dfj, interpi, interpj
integer, intent(in) :: id
type(MPolicy_t) :: pol
print *, ' Default constructor (as compiler)...'
pol%delta_fI_fct_ = dfi
pol%delta_fJ_fct_ = dfj
pol%interp_I_fct_ = interpi
pol%interp_J_fct_ = interpj
pol%id_pol_ = id
end function MPolicy_constructor_real
function MPolicy_constructor_integer(dfi, dfj, interpi, interpj, id) result(pol)
integer, intent(in) :: dfi, dfj, interpi, interpj, id
type(MPolicy_t) :: pol
print *, ' Default constructor (integer version)...'
pol = MPolicy_t(real(dfi, 8), &
real(dfj, 8), &
real(interpi, 8), &
real(interpj, 8), id)
end function
function MPolicy_fromID(id) result(pol)
integer, intent(in) :: id
type(MPolicy_t) :: pol
print *, ' Constructor from ID...'
select case (id)
case (MPolicy_NULL)
return
case (MPolicy_DEF)
pol = MPolicy_t(2, 2, 2, 2, MPolicy_DEF)
case (MPolicy_CONST)
pol = MPolicy_t(1, 1, 1, 1, MPolicy_CONST)
case default
block
character(len=3) :: fmt
write(fmt, '(i)'), id
stop ' [ERROR] Unknow policy identifier "id"= '//fmt
end block
end select
end function MPolicy_fromID
subroutine MPolicy_fromPol_sub(lhs, rhs)
class(MPolicy_t), intent(in) :: rhs
class(MPolicy_t), intent(out) :: lhs
lhs%delta_fI_fct_ = rhs%delta_fI_fct_
lhs%delta_fJ_fct_ = rhs%delta_fJ_fct_
lhs%interp_I_fct_ = rhs%interp_I_fct_
lhs%interp_J_fct_ = rhs%interp_J_fct_
lhs%id_pol_ = rhs%id_pol_
end subroutine MPolicy_fromPol_sub
subroutine MPolicy_fromID_sub(lhs, rhs)
class(MPolicy_t), intent(out) :: lhs
integer, intent(in) :: rhs
lhs = MPolicy_t(rhs)
end subroutine MPolicy_fromID_sub
function MPolicy(mpol) result(pol)
integer :: mpol
type(MPolicy_t) :: pol
pol = MPolicy_t(mpol)
end function MPolicy
pure function MPolicy_isID(pol, id) result(isID)
class(MPolicy_t), intent(in) :: pol
integer, intent(in) :: id
logical :: isID
isID = pol%id_pol_ == id
end function MPolicy_isID
end module
Example program:
program test
use MPolicyMod
implicit none
! ! NOTE: generates
! ! error #6259: This array or function or substring is invalid in constant expressions. [MPOLICYMOD^MPOLICY_FROMID]
! ! error #7715: Replacing invalid structure constructor by integer 1. [<NULL_STRING>]
! type(MPolicy_t) :: pol = MPolicy_t(MPolicy_NULL)
type(MPolicy_t) :: pol
! =========================================================================
print *, pol
pol = MPolicy_t(MPolicy_NULL)
print *, pol
! ! NOTE: generates (without TYPE-BOUND specification)
! ! error #6355: This binary operation is invalid for this data type.
print *, pol == MPolicy_NULL
pol = MPolicy_t(1, 1, 1, 1, 2)
print *, pol
! ! NOTE: generates (without TYPE-BOUND specification)
! ! error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands.
pol = MPolicy_DEF
print *, pol
end program test
Then, after reading through the ISO Fortran Standard 2003 Draft document, at Section 4.5.4 Type-bound procedures, Rule R452 states that we could specify assignment(=) as a generic-spec, in a generic-binding type of proc-binding-stmt. There I realised I was missing the type-bound specifications for those operator/assignment procedures.
Why, then, only the interface body was not enough to make it work?
After this, I also wonder why the initialisation statement type(MPolicy_t) :: pol = MPolicy_t(MPolicy_NULL) generates errors #6259 and #7715.
For that, I still didn't search by my own. But if you come with an asnwer before I might find (hopefully) an explanation, it's always good to have constructive as well as polite discussions with You all.
I now go back to my searching. Have a nice day :)

How to choose a desired code for a Subroutine among various options during the start of a run

Let's say I want to perform an operation in my main program (in Fortran). And lets say that operation is finding minimum number in a 1D array. I wish to do so by passing the array into the call subroutine and the subroutine will print the minimum value on the screen. There are different ways or algorithms to find minimum value in an array. Lets say I have 100 different methods: Method1, Method2..... Method100. Now I want to try using each one of these methods separately (I don't want to try all of them at once, but one method in each run). I don't want to create 100 different subroutines and change the code every time to decide which one to call, rather I want to mention in the input file which one I want to choose. So basically, the computer has to read the input file (to know which method to use) and perform the task using the specified method amongst different methods available.
I can write a Subroutine dump all the methods into that subroutine and put an IF condition to choose among various methods. But IF conditions are in efficient particularly on GPUs, I want to know the most efficient way of doing this.
MAIN PROGRAM
INTEGER Method !will be read from input file
Array = [12,5,3,4,1,7,4,3]
call print_Minimum(Array)
END PROGRAM
SUBROUTINE print_Minimum(Array)
IF (METHOD == 1)
<method 1 code>
ELSE IF (METHOD == 2)
<method 2 code>
:
:
:
:
ELSE IF (METHOD == 100)
<method100 code>
END IF
END SUBROUTINE
Thanks in advance.
This is probably best done using a function pointer and/or functions as arguments.
You can set a function pointer to a certain function and do this in your nested ifs and you can pass functions as arguments.
Both methods are implemented in the following example.
module minimum_mod
implicit none
private
public :: get_min_t, naive_min, time_min_function
abstract interface
integer pure function get_min_t(X)
integer, intent(in) :: X(:)
end function
end interface
contains
subroutine time_min_function(f, X)
procedure(get_min_t) :: f
integer, intent(in) :: X(:)
integer :: res
res = f(X)
write(*, *) res
end subroutine
integer pure function naive_min(X)
integer, intent(in) :: X(:)
integer :: i
naive_min = huge(naive_min)
do i = 1, size(X)
naive_min = min(naive_min, X(i))
end do
end function
end module
program time_min_finders
use minimum_mod, only: get_min_t, naive_min, time_min_function
implicit none
integer, parameter :: test_set(5) = [1, 10, 3, 5, 7]
procedure(get_min_t), pointer :: f
f => naive_min
call time_min_function(f, test_set)
end program
PS: Note that you can now do all the timinig logic inside time_min_function.
You can create an array of a derived type that contains a function pointer, effectively an array of function pointers. Then in principle you could initialize the function pointers to point at all of your test functions so that you could refer to each function by its index without having to test with a SELECT CASE of IF block: this is the typical Fortran way. However, either I've got the syntax for initialization wrong or my old version of gfortran just isn't capable, so I had to initialize one at a time. Sigh.
module minfuncs
implicit none
abstract interface
function func(array)
integer, intent(in) :: array(:)
integer func
end function func
end interface
type func_node
procedure(func), NOPASS, pointer :: f
end type func_node
! type(func_node) :: method(5) = [func_node(min_1),func_node(min_2), &
! func_node(min_3),func_node(min_4),func_node(min_5)]
contains
function min_1(array)
integer, intent(in) :: array(:)
integer min_1
integer i
min_1 = array(1)
do i = 2, size(array)
min_1 = min(min_1,array(i))
end do
end function min_1
function min_2(array)
integer, intent(in) :: array(:)
integer min_2
integer i
min_2 = array(1)
do i = 8, size(array), 7
min_2 = min(min_2,array(i-6),array(i-5),array(i-4), &
array(i-3),array(i-2),array(i-1),array(i))
end do
do i = i-6, size(array)
min_2 = min(min_2, array(i))
end do
end function min_2
function min_3(array)
integer, intent(in) :: array(:)
integer min_3
integer i
min_3 = array(1)
do i = 2, size(array)
min_3 = min_3-dim(min_3,array(i))
end do
end function min_3
function min_4(array)
integer, intent(in) :: array(:)
integer min_4
integer ymm(8)
integer i
if(size(array) >= 8) then
ymm = array(1:8)
do i = 16, size(array), 8
ymm = min(ymm,array(i-7:i))
end do
min_4 = minval([ymm,array(i-7:size(array))])
else
min_4 = minval(array)
end if
end function min_4
function min_5(array)
integer, intent(in) :: array(:)
integer min_5
min_5 = minval(array)
end function min_5
end module minfuncs
program test
use minfuncs
implicit none
integer, parameter :: N = 75
integer i
integer :: A(N) = modulo(5*[(i,i=1,N)]**2,163)
! type(func_node) :: method(5) = [func_node(min_1),func_node(min_2), &
! func_node(min_3),func_node(min_4),func_node(min_5)]
type(func_node) method(5)
method(1)%f => min_1
method(2)%f => min_2
method(3)%f => min_3
method(4)%f => min_4
method(5)%f => min_5
do i = 1, size(method)
write(*,*) method(i)%f(A)
end do
end program test
Output:
2
2
2
2
2

Polymorphic dummy allocatable argument

I have three functions that to the same thing but for different dummy argument types: flip, flipLogical and flipInt. Their very code is actually exactly the same! There is another function, called flip3D, which is only for real dummy arguments, that calls flip from its inside. This is the way that everything is working right now:
function flip(data)
real, dimension(:,:), intent(in) :: data
real, dimension(:,:), allocatable :: flip
integer :: m, n, i
m = size(data,1)
n = size(data,2)
allocate(flip(m,n))
do i=1,m
flip(m-i+1,:) = data(i,:)
end do
end function flip
function flipLogical(data)
logical, dimension(:,:), intent(in) :: data
logical, dimension(:,:), allocatable :: flipLogical
integer :: m, n, i
m = size(data,1)
n = size(data,2)
allocate(flipLogical(m,n))
do i=1,m
flipLogical(m-i+1,:) = data(i,:)
end do
end function flipLogical
function flipInt(data)
integer, dimension(:,:), intent(in) :: data
integer, dimension(:,:), allocatable :: flipInt
integer :: m, n, i
m = size(data,1)
n = size(data,2)
allocate(flipInt(m,n))
do i=1,m
flipInt(m-i+1,:) = data(i,:)
end do
end function flipInt
function flip3D(data)
real, dimension(:,:,:), intent(in) :: data
real, dimension(:,:,:), allocatable :: flip3D
integer :: m, n, o, j
m = size(data, 1)
n = size(data, 2)
o = size(data, 3)
allocate(flip3D(n, m, o))
do j = 1, o
flip3D(:,:,j) = flip(data(:,:,j))
end do
end function flip3D
Although this is working just fine, it is terrible ugly. I want to have a polymorphic function flip which just works for any type and that I can call from flip3D providing a real variable as dummy argument. I'm trying something like that:
function flip(data)
class(*), dimension(:,:), intent(in) :: data
class(*), dimension(:,:), allocatable :: flip
integer :: m, n, i
m = size(data,1)
n = size(data,2)
allocate(flip(m,n), mold=data)
do i=1,m
flip(m-i+1,:) = data(i,:)
end do
end function flip
but then I receive the errors
script.f90:698:7:
flip(m-i+1,:) = data(i,:)
1 Error: Nonallocatable variable must not be polymorphic in intrinsic assignment at (1) - check that there is a matching specific subroutine for '=' operator
script.f90:714:23:
flip3D(:,:,j) = flip(data(:,:,j))
1 Error: Can't convert CLASS(*) to REAL(4) at (1)
I would have done this with a generic function implemented via a template but note that
function flip(data)
class(*), dimension(:,:), intent(in) :: data
class(*), dimension(:,:), allocatable :: flip
integer :: i
flip = data([(i,i=m,1,-1)],:)
end function flip
compiles with gfortran.
EDIT: Given the template file flip.i90:
function Qflip(Qdata)
dimension Qdata(:,:)
intent(in) Qdata
dimension Qflip(size(Qdata,1),size(Qdata,2))
integer i
do i = 1, size(Qdata,1)
Qflip(size(Qdata,1)-i+1,:) = Qdata(i,:)
end do
end function Qflip
We can compile flip.f90:
module real_mod
implicit real(Q)
private
public flip
interface flip
module procedure Qflip
end interface flip
contains
include 'flip.i90'
end module real_mod
module Logical_mod
implicit Logical(Q)
private
public flip
interface flip
module procedure Qflip
end interface flip
contains
include 'flip.i90'
end module Logical_mod
module Int_mod
implicit integer(Q)
private
public flip
interface flip
module procedure Qflip
end interface flip
contains
include 'flip.i90'
end module Int_mod
module flip_mod
use real_mod
use Logical_mod
use Int_mod
end module flip_mod
program flipmeoff
use flip_mod
implicit none
real :: R(3,3) = reshape([ &
1, 2, 3, &
4, 5, 6, &
7, 8, 9],shape(R),order=[2,1])
Logical :: L(3,3) = reshape([ &
.TRUE., .TRUE., .FALSE., &
.FALSE., .TRUE., .FALSE., &
.FALSE., .FALSE., .TRUE.],shape(L),order=[2,1])
integer :: I(3,3) = reshape([ &
1, 2, 3, &
4, 5, 6, &
7, 8, 9],shape(I),order=[2,1])
write(*,'(3(f3.1:1x))') transpose(R)
write(*,'()')
write(*,'(3(f3.1:1x))') transpose(flip(R))
write(*,'()')
write(*,'(3(L1:1x))') transpose(L)
write(*,'()')
write(*,'(3(L1:1x))') transpose(flip(L))
write(*,'()')
write(*,'(3(i1:1x))') transpose(I)
write(*,'()')
write(*,'(3(i1:1x))') transpose(flip(I))
end program flipmeoff
And produce output:
1.0 2.0 3.0
4.0 5.0 6.0
7.0 8.0 9.0
7.0 8.0 9.0
4.0 5.0 6.0
1.0 2.0 3.0
T T F
F T F
F F T
F F T
F T F
T T F
1 2 3
4 5 6
7 8 9
7 8 9
4 5 6
1 2 3
It's unfortunate that Fortran doesn't allow you to rename intrinsic types like you can derived types. The consequence is that template files that can be used with intrinsic types have to use implicit typing.

Can't replace Fortran real variables by double precision variables or more precision

I am using a known code (CAMB) which generates values like this :
k(h/Mpc) Pk/s8^2(Mpc/h)^3
5.2781500000e-06 1.9477400000e+01
5.5479700000e-06 2.0432300000e+01
5.8315700000e-06 2.1434000000e+01
6.1296700000e-06 2.2484700000e+01
6.4430100000e-06 2.3587000000e+01
6.7723700000e-06 2.4743400000e+01
7.1185600000e-06 2.5956400000e+01
7.4824500000e-06 2.7228900000e+01
7.8649500000e-06 2.8563800000e+01
8.2669900000e-06 2.9964100000e+01
I would like to get more precision on the generated values, like this :
k(h/Mpc) Pk/s8^2(Mpc/h)^3
5.3594794736e-06 1.8529569626e+01
5.6332442000e-06 1.9437295914e+01
5.9209928622e-06 2.0389484405e+01
6.2234403231e-06 2.1388326645e+01
6.5413364609e-06 2.2436098099e+01
6.8754711720e-06 2.3535198212e+01
7.2266739153e-06 2.4688137054e+01
7.5958159869e-06 2.5897554398e+01
7.9838137026e-06 2.7166225433e+01
8.3916311269e-06 2.8497039795e+01
8.8202796178e-06 2.9893053055e+01
9.2708232842e-06 3.1357446670e+01
9.7443817140e-06 3.2893573761e+01
Here the section of code that produces the data :
I tried to do the following modifications in the declarations of variables at the beginning of code above :
1)First try :
!Export files of total matter power spectra in h^{-1} Mpc units, against k/h.
Type(MatterTransferData), intent(in) :: MTrans
Type(CAMBdata) :: State
character(LEN=Ini_max_string_len), intent(IN) :: FileNames(*)
character(LEN=name_tag_len) :: columns(3)
integer itf, i, unit
integer points
! Added : way of declaring double precision
integer, parameter :: wp = selected_real_kind(15,307)
real(wp), dimension(:,:), allocatable :: outpower
but it doesn't compile :
real(wp), dimension(:,:), allocatable :: outpower
1
Error: Symbol ‘wp’ at (1) has no IMPLICIT type
../results.f90:3660:25:
allocate(outpower(points,ncol))
1
Error: Allocate-object at (1) is neither a data pointer nor an allocatable variable
../results.f90:3676:16:
outpower(:,1) = exp(PK_data%matpower(:,1))
1
Error: Unclassifiable statement at (1)
../results.f90:3679:20:
outpower(:,3) = exp(PK_data%vvpower(:,1))
1
Error: Unclassifiable statement at (1)
compilation terminated due to -fmax-errors=4.
make[1]: *** [results.o] Error 1
make: *** [camb] Error 2
2) Also, I tried :
!Export files of total matter power spectra in h^{-1} Mpc units, against k/h.
Type(MatterTransferData), intent(in) :: MTrans
Type(CAMBdata) :: State
character(LEN=Ini_max_string_len), intent(IN) :: FileNames(*)
character(LEN=name_tag_len) :: columns(3)
integer itf, i, unit
integer points
! Added : way of declaring double precision
double precision, dimension(:,:), allocatable :: outpower
but same thing, no compilation succeeded
call Transfer_GetMatterPowerS(State, MTrans, outpower(1,1), itf, minkh,dlnkh, points)
1
Error: Type mismatch in argument ‘outpower’ at (1); passed REAL(8) to REAL(4)
make[1]: *** [results.o] Error 1
make: *** [camb] Error 2
UPDATE 1:
with -fmax-errors=1, I get the following :
call Transfer_GetMatterPowerS(State, MTrans, outpower(1,1), itf, minkh,dlnkh, points)
1
Error: Type mismatch in argument ‘outpower’ at (1); passed REAL(8) to REAL(4)
compilation terminated due to -fmax-errors=1.
Except the solution given by #Steve with compilation option -freal-4-real-8, isn't really there another solution that I could include directly into code, i.e the section that I have given ?
UPDATE 2: here below the 3 relevant subroutines Transfer_GetMatterPowerS , Transfer_GetMatterPowerData and Transfer_SaveMatterPower that produces the error when trying to get double precision :
subroutine Transfer_GetMatterPowerS(State, MTrans, outpower, itf, minkh, dlnkh, npoints, var1, var2)
class(CAMBdata) :: state
Type(MatterTransferData), intent(in) :: MTrans
integer, intent(in) :: itf, npoints
integer, intent(in), optional :: var1, var2
real, intent(out) :: outpower(*)
real, intent(in) :: minkh, dlnkh
real(dl) :: outpowerd(npoints)
real(dl):: minkhd, dlnkhd
minkhd = minkh; dlnkhd = dlnkh
call Transfer_GetMatterPowerD(State, MTrans, outpowerd, itf, minkhd, dlnkhd, npoints,var1, var2)
outpower(1:npoints) = outpowerd(1:npoints)
end subroutine Transfer_GetMatterPowerS
subroutine Transfer_GetMatterPowerData(State, MTrans, PK_data, itf_only, var1, var2)
!Does *NOT* include non-linear corrections
!Get total matter power spectrum in units of (h Mpc^{-1})^3 ready for interpolation.
!Here there definition is < Delta^2(x) > = 1/(2 pi)^3 int d^3k P_k(k)
!We are assuming that Cls are generated so any baryonic wiggles are well sampled and that matter power
!spectrum is generated to beyond the CMB k_max
class(CAMBdata) :: State
Type(MatterTransferData), intent(in) :: MTrans
Type(MatterPowerData) :: PK_data
integer, intent(in), optional :: itf_only
integer, intent(in), optional :: var1, var2
double precision :: h, kh, k, power
integer :: ik, nz, itf, itf_start, itf_end, s1, s2
s1 = PresentDefault (transfer_power_var, var1)
s2 = PresentDefault (transfer_power_var, var2)
if (present(itf_only)) then
itf_start=itf_only
itf_end = itf_only
nz = 1
else
itf_start=1
nz= size(MTrans%TransferData,3)
itf_end = nz
end if
PK_data%num_k = MTrans%num_q_trans
PK_Data%num_z = nz
allocate(PK_data%matpower(PK_data%num_k,nz))
allocate(PK_data%ddmat(PK_data%num_k,nz))
allocate(PK_data%nonlin_ratio(PK_data%num_k,nz))
allocate(PK_data%log_kh(PK_data%num_k))
allocate(PK_data%redshifts(nz))
PK_data%redshifts = State%Transfer_Redshifts(itf_start:itf_end)
h = State%CP%H0/100
do ik=1,MTrans%num_q_trans
kh = MTrans%TransferData(Transfer_kh,ik,1)
k = kh*h
PK_data%log_kh(ik) = log(kh)
power = State%CP%InitPower%ScalarPower(k)
if (global_error_flag/=0) then
call MatterPowerdata_Free(PK_data)
return
end if
do itf = 1, nz
PK_data%matpower(ik,itf) = &
log(MTrans%TransferData(s1,ik,itf_start+itf-1)*&
MTrans%TransferData(s2,ik,itf_start+itf-1)*k &
*const_pi*const_twopi*h**3*power)
end do
end do
call MatterPowerdata_getsplines(PK_data)
end subroutine Transfer_GetMatterPowerData
subroutine Transfer_SaveMatterPower(MTrans, State,FileNames, all21cm)
use constants
!Export files of total matter power spectra in h^{-1} Mpc units, against k/h.
Type(MatterTransferData), intent(in) :: MTrans
Type(CAMBdata) :: State
character(LEN=Ini_max_string_len), intent(IN) :: FileNames(*)
character(LEN=name_tag_len) :: columns(3)
integer itf, i, unit
integer points
! Added : way of declaring double precision
!integer, parameter :: wp = selected_real_kind(15,307)
!real(wp), dimension(:,:), allocatable :: outpower
double precision, dimension(:,:), allocatable :: outpower
real minkh,dlnkh
Type(MatterPowerData) :: PK_data
integer ncol
logical, intent(in), optional :: all21cm
logical all21
!JD 08/13 Changes in here to PK arrays and variables
integer itf_PK
all21 = DefaultFalse(all21cm)
if (all21) then
ncol = 3
else
ncol = 1
end if
do itf=1, State%CP%Transfer%PK_num_redshifts
if (FileNames(itf) /= '') then
if (.not. transfer_interp_matterpower ) then
itf_PK = State%PK_redshifts_index(itf)
points = MTrans%num_q_trans
allocate(outpower(points,ncol))
!Sources
if (all21) then
call Transfer_Get21cmPowerData(MTrans, State, PK_data, itf_PK)
else
call Transfer_GetMatterPowerData(State, MTrans, PK_data, itf_PK)
!JD 08/13 for nonlinear lensing of CMB + LSS compatibility
!Changed (CP%NonLinear/=NonLinear_None) to CP%NonLinear/=NonLinear_none .and. CP%NonLinear/=NonLinear_Lens)
if(State%CP%NonLinear/=NonLinear_none .and. State%CP%NonLinear/=NonLinear_Lens) then
call State%CP%NonLinearModel%GetNonLinRatios(State, PK_data)
PK_data%matpower = PK_data%matpower + 2*log(PK_data%nonlin_ratio)
call MatterPowerdata_getsplines(PK_data)
end if
end if
outpower(:,1) = exp(PK_data%matpower(:,1))
!Sources
if (all21) then
outpower(:,3) = exp(PK_data%vvpower(:,1))
outpower(:,2) = exp(PK_data%vdpower(:,1))
outpower(:,1) = outpower(:,1)/1d10*const_pi*const_twopi/MTrans%TransferData(Transfer_kh,:,1)**3
outpower(:,2) = outpower(:,2)/1d10*const_pi*const_twopi/MTrans%TransferData(Transfer_kh,:,1)**3
outpower(:,3) = outpower(:,3)/1d10*const_pi*const_twopi/MTrans%TransferData(Transfer_kh,:,1)**3
end if
call MatterPowerdata_Free(PK_Data)
columns = ['P ', 'P_vd','P_vv']
unit = open_file_header(FileNames(itf), 'k/h', columns(:ncol), 15)
do i=1,points
write (unit, '(*(E15.6))') MTrans%TransferData(Transfer_kh,i,1),outpower(i,:)
end do
close(unit)
else
if (all21) stop 'Transfer_SaveMatterPower: if output all assume not interpolated'
minkh = 1e-4
dlnkh = 0.02
points = log(MTrans%TransferData(Transfer_kh,MTrans%num_q_trans,itf)/minkh)/dlnkh+1
! dlnkh = log(MTrans%TransferData(Transfer_kh,MTrans%num_q_trans,itf)/minkh)/(points-0.999)
allocate(outpower(points,1))
call Transfer_GetMatterPowerS(State, MTrans, outpower(1,1), itf, minkh,dlnkh, points)
columns(1) = 'P'
unit = open_file_header(FileNames(itf), 'k/h', columns(:1), 15)
do i=1,points
write (unit, '(*(E15.6))') minkh*exp((i-1)*dlnkh),outpower(i,1)
end do
close(unit)
end if
deallocate(outpower)
end if
end do
end subroutine Transfer_SaveMatterPower

Reading characters array from a text file and convert it to an integer parameter

I have a large text file like this:
!species #Oxygen
ind_CO 1.0
ind_CO2 2.0
ind_CH4 0.0
ind_O3 3.0
but in my code the characters (ind_CO, ind_CO2, etc) are declared like this:
INTEGER, PARAMETER :: ind_CO2 = 1
INTEGER, PARAMETER :: ind_CH4 = 2
INTEGER, PARAMETER :: ind_O3 = 3
INTEGER, PARAMETER :: ind_CO = 4
And the concentration of each species is calculated as C(ind_). So I want
to calculate the product of C(ind_)*(#Oxygen) for each one. That is, I would like to relate the data of text file and those of code. I tried something like this:
program
implicit none
INTEGER, PARAMETER :: ind_CO2 = 1
INTEGER, PARAMETER :: ind_CH4 = 2
INTEGER, PARAMETER :: ind_O3 = 3
INTEGER, PARAMETER :: ind_CO = 4
REAL :: C(4) ! Concentration for each Compound
REAL :: numO ! Number of Oxygens
REAL :: ANS(4) ! To Calculate
INTEGER :: err
CHARACTER :: species*11
open (unit=15, file="data.txt", status='old',access='sequential', form='formatted', action='read' )
err=0
do
read (15, *,IOSTAT=err) species, numO
if (err==-1) exit
! I don 't know if it is possible to convert a character to an integer
! parameter in such a way that the index of the matrix corresponds to
! the right compound
ANS(species) = C(species)*numO
write (*, *) species, numO, ANS(species)
enddo
close(15)
end program
I know it is not correct, but my idea is to insert at the matrix C the name that is saved for each compound at the beginning of the code.
So I would like to ask you if it is possible to read or convert these characters and relate them to the declared parameters.
In fortran there is no intrinsic way to map symbol names to character strings. The simplest approach here is to simply store your species names as a character array and use a loop to find the matching name for the string you read from the file.
implicit none
integer :: i
integer, parameter :: nspecies=4
character(len=11),dimension(nspecies) :: species= &
['ind_CO2','ind_CH4','ind_O3','ind_CO']
character(len=11) :: input
input='ind_CH4' ! from file
do i = 1,nspecies
if ( input .eq. species(i) )exit
enddo
if ( i.gt.nspecies )then
write(*,*)'error ',input,' not found'
else
write(*,*)'read input is ',i,trim(species(i))
endif
end