From: Friedrich on
Hello everyone,

I'm learning a little bit about organization in fortran,
and was wondering, if I could trouble you for a bit of answers on some
questions - well, ... advice more, actually. The answers I'll find in
a manual, but good experience is hard to come by.

The structure of most of my programs (f77 mostly with some f90 newer
features) is the main program plus subroutines and functions. No
modules, just main program and lot of subroutines (but there are
rather a lot of them).

If I wished to make, for ease of use, a number of functions for unit
conversion (you know, feet to meters, horsepower to kW and so on) what
would be the best way to put it so it gets as little in the way in the
main program.

I thought of the below, but I cannot know will I have any problems
with this concept in larger programs. My intent is to use these
functions almost like intrinsics, in my main program and functions and
subroutines.

So far I've mostly relied on parameters and then multiplying where
needed, but that gets.

I would be grateful, if anyone could put down a quick word of advice.

Kind regards,
Friedrich

module helpful
implicit none

contains
!-------------------------------------------------------------------------------
real function degrees(radians)
implicit none

real, intent(in) :: radians

degrees = (360./(2.*3.141592654)) * radians
end function degrees
!-------------------------------------------------------------------------------
real function radians(degrees)
implicit none

real, intent(in) :: degrees

radians = ((2.*3.141592654)/360.) * degrees
end function radians
!-------------------------------------------------------------------------------
end module helpful

program test_both_functions
use helpful
implicit none

real :: degs = 30.
write(*,'("sin(30) should be = ",f5.2)')sin(radians(degs))

call bla1(sin(radians(degs)))

write(*,'("End of program test_both_functions")')
end program test_both_functions

subroutine bla1(number)
real, intent(in) :: number
write(*,'("sin(30) should be = ",f5.2)')number
end subroutine bla1
From: Arjan on
Getting organized is a good thing!

Like you use "IMPLICIT NONE" to allow for trapping undeclared
variables, I would use "PRIVATE" to ensure that only your own
exceptions are passed to the outside world via a PUBLIC statement. See
sample code below.

Then, I would define some code-words for real-valued variables, e.g.
"Float", or "R8Kind", see below, to allow for easy switching from one
precision to another. Use these types in all further programs,
modules, functions and routines.

For the names of the conversion routines I would use something like
"deg2rad", showing the units of both input and output, and not just
"Radians". Furthermore, I would advise to give your parameters names
that make sense. I guess that in your code 3.141592654 refers to Pi?
Better define Pi once and for all for all of your code and never think
of typing in decimals of it ever again! Suppose you have something
cyclic going on and after years of running you have used 3.141592654
in one subroutine and 3.14159265 in another. The last digit might
wrench your work!

In your sample code, there are still many arithmetic operations. Smart
compilers will replace these by a single multiplication factor. Still
I think I would define such a single multiplication factor myself and
use that in my function.

Good luck!


Arjan


MODULE LibUseful
!
! Useful functions and other stuff
!
! Enforce explicit declarations:
!
IMPLICIT NONE
!
! Principally everything is LOCAL...
!
PRIVATE
!
! ... except for the following [this is the line where you list all
that
! should be known to programs and modules that USE this module]:
!
PUBLIC :: Float,R8Kind,Pi,Deg2Rad,Rad2Deg,...
!
! From now on only use "REAL(float)" for reals
!
! Number of bytes associated with 6 digits precision:
!
INTEGER,PARAMETER :: Float = SELECTED_REAL_KIND(p=6)
!
! The number of bytes associated with 15 digits precision
!
INTEGER,PARAMETER :: R8Kind = SELECTED_REAL_KIND(p=15)
!
! And why on earth does FORTRAN not have PI ?????
!
REAL(Float),PARAMETER :: Pi =
3.1415926535897932384626433832795_Float
!
! Below this line you'll get the real implementations
!
CONTAINS

REAL(Float) FUNCTION Deg2Rad(x)
!
! Convert degrees to radians
!
REAL(Float), INTENT(IN) :: x
REAL(Float), PARAMETER :: c = Pi/180._Float
Deg2Rad = c*x
END FUNCTION Deg2Rad


REAL(Float) FUNCTION Rad2Deg(x)
!
! Convert radians to degrees
!
REAL(Float), INTENT(IN) :: x
REAL(Float), PARAMETER :: c = 180._Float/Pi
Rad2Deg = c*x
END FUNCTION Rad2Deg

From: Dave Flower on
On Jun 19, 11:10 pm, Friedrich <friedrich.schwa...(a)wahoo.with.a.y.com>
wrote:
> Hello everyone,
>
> I'm learning a little bit about organization in fortran,
> and was wondering, if I could trouble you for a bit of answers on some
> questions - well, ... advice more, actually. The answers I'll find in
> a manual, but good experience is hard to come by.
>
> The structure of most of my programs (f77 mostly with some f90 newer
> features) is the main program plus subroutines and functions. No
> modules, just main program and lot of subroutines (but there are
> rather a lot of them).
>
> If I wished to make, for ease of use, a number of functions for unit
> conversion (you know, feet to meters, horsepower to kW and so on) what
> would be the best way to put it so it gets as little in the way in the
> main program.
>
> I thought of the below, but I cannot know will I have any problems
> with this concept in larger programs. My intent is to use these
> functions almost like intrinsics, in my main program and functions and
> subroutines.
>
> So far I've mostly relied on parameters and then multiplying where
> needed, but that gets.
>
> I would be grateful, if anyone could put down a quick word of advice.
>
> Kind regards,
> Friedrich
>
> module helpful
> implicit none
>
> contains
> !--------------------------------------------------------------------------­-----
> real function degrees(radians)
> implicit none
>
> real, intent(in) :: radians
>
> degrees = (360./(2.*3.141592654)) * radians
> end function degrees
> !--------------------------------------------------------------------------­-----
> real function radians(degrees)
> implicit none
>
> real, intent(in) :: degrees
>
> radians = ((2.*3.141592654)/360.) * degrees
> end function radians
> !--------------------------------------------------------------------------­-----
> end module helpful
>
> program test_both_functions
> use helpful
> implicit none
>
> real :: degs = 30.
> write(*,'("sin(30) should be = ",f5.2)')sin(radians(degs))
>
> call bla1(sin(radians(degs)))
>
> write(*,'("End of program test_both_functions")')
> end program test_both_functions
>
> subroutine bla1(number)
> real, intent(in) :: number
> write(*,'("sin(30) should be = ",f5.2)')number
> end subroutine bla1

Might I suggest a naming convention that worked well in practice. Add
a suffix so that variables take the form:

Angle_Deg

So that we may write code of the form:

Angle_Rad = RadPDeg ( Angle_Deg )

(The 'P' isn short for Per)

The advantage of this system is that it is very easy to check. (LHS-
Rad;RHS:(Rad/Deg).Rad=Rad)

Dave Flower
From: Paul van Delst on
Also, I would recommend making these sorts of simple, but very useful, procedures
ELEMENTAL. I know the OP only mentioned f90, but he should be using at least f95 (if not
f2003 if fully-compliant compilers *ever* become widely available).

cheers,

paulv

Arjan wrote:
> Getting organized is a good thing!
>
> Like you use "IMPLICIT NONE" to allow for trapping undeclared
> variables, I would use "PRIVATE" to ensure that only your own
> exceptions are passed to the outside world via a PUBLIC statement. See
> sample code below.
>
> Then, I would define some code-words for real-valued variables, e.g.
> "Float", or "R8Kind", see below, to allow for easy switching from one
> precision to another. Use these types in all further programs,
> modules, functions and routines.
>
> For the names of the conversion routines I would use something like
> "deg2rad", showing the units of both input and output, and not just
> "Radians". Furthermore, I would advise to give your parameters names
> that make sense. I guess that in your code 3.141592654 refers to Pi?
> Better define Pi once and for all for all of your code and never think
> of typing in decimals of it ever again! Suppose you have something
> cyclic going on and after years of running you have used 3.141592654
> in one subroutine and 3.14159265 in another. The last digit might
> wrench your work!
>
> In your sample code, there are still many arithmetic operations. Smart
> compilers will replace these by a single multiplication factor. Still
> I think I would define such a single multiplication factor myself and
> use that in my function.
>
> Good luck!
>
>
> Arjan
>
>
> MODULE LibUseful
> !
> ! Useful functions and other stuff
> !
> ! Enforce explicit declarations:
> !
> IMPLICIT NONE
> !
> ! Principally everything is LOCAL...
> !
> PRIVATE
> !
> ! ... except for the following [this is the line where you list all
> that
> ! should be known to programs and modules that USE this module]:
> !
> PUBLIC :: Float,R8Kind,Pi,Deg2Rad,Rad2Deg,...
> !
> ! From now on only use "REAL(float)" for reals
> !
> ! Number of bytes associated with 6 digits precision:
> !
> INTEGER,PARAMETER :: Float = SELECTED_REAL_KIND(p=6)
> !
> ! The number of bytes associated with 15 digits precision
> !
> INTEGER,PARAMETER :: R8Kind = SELECTED_REAL_KIND(p=15)
> !
> ! And why on earth does FORTRAN not have PI ?????
> !
> REAL(Float),PARAMETER :: Pi =
> 3.1415926535897932384626433832795_Float
> !
> ! Below this line you'll get the real implementations
> !
> CONTAINS
>
> REAL(Float) FUNCTION Deg2Rad(x)
> !
> ! Convert degrees to radians
> !
> REAL(Float), INTENT(IN) :: x
> REAL(Float), PARAMETER :: c = Pi/180._Float
> Deg2Rad = c*x
> END FUNCTION Deg2Rad
>
>
> REAL(Float) FUNCTION Rad2Deg(x)
> !
> ! Convert radians to degrees
> !
> REAL(Float), INTENT(IN) :: x
> REAL(Float), PARAMETER :: c = 180._Float/Pi
> Rad2Deg = c*x
> END FUNCTION Rad2Deg
>