F200x programs?

  • Follow


Does anyone know of any decently sized sample programs that exercise the 
new features in F200x?
-- 
JA
0
Reply john.spamtrap (12) 3/16/2012 3:49:50 PM

John Appleyard wrote:
> Does anyone know of any decently sized sample programs that exercise the
> new features in F200x?

I don't know what you mean by "decently sized", "sample programs", and 
which features do you have in mind for F200x. Ignoring trivial examples, 
the following comes into my mind - none probably really fits your needs:

- The examples to the book at http://www.cambridge.org/rouson
- PSBLAS: http://www.ce.uniroma2.it/psblas/ (version 3)
- ForTrilionos, http://trilinos.sandia.gov/packages/fortrilinos/
- Galacticus, http://sites.google.com/site/galacticusmodel/

All of those use Fortran 2003's OOP features. However, especially the 
last two are much too large to count as "decently sized sample 
programs". With sample programs, the question is always whether you 
search a hello-world style program or a real application, which uses 
many new features. For the latter, it will be difficult to find small, 
publicly available programs.

There are probably countless programs, which use very selected features. 
Looking at the program which I use primarily: it just uses namelists 
with allocatable namelist objects and noninteger initialization 
expressions, that are the only F2003 features; my auxiliar programs use, 
e.g., the "(*(g0))" edit descriptor features but also not more. Another 
one app uses some BIND(C) features. Or, for instance, Open MPI uses (at 
least on the MPIv3 branch and optionally) PROCEDURE, ASYNCHRONOUS, 
TYPE(*), and DIMENSION(..).

Tobias
0
Reply burnus (564) 3/16/2012 9:05:34 PM


On Saturday, March 17, 2012 12:49:50 AM UTC+9, John Appleyard wrote:
> Does anyone know of any decently sized sample programs that exercise the 
> new features in F200x?
> -- 
> JA

We would like to think that Appendix E of "Modern Fortran Explained" is just such an example (of OO-programming). It's available for downloading at ftp://ftp.numerical.rl.ac.uk/pub/MRandC/oo.f90.

Regards,

Mike Metcalf
0
Reply michaelmetcalf (810) 3/17/2012 3:31:50 AM

On 03/16/2012 09:31 PM, michaelmetcalf@compuserve.com wrote:

> We would like to think that Appendix E of "Modern Fortran Explained" is just such an example (of OO-programming).

I tried four compilers with this short program. All failed. xlf2003 came the closest:

% xlf2003 Metcalf_oo.f90
** anylist_m   === End of Compilation 1 ===
"Metcalf_oo.f90", line 273.18: 1514-668 (S) Dummy argument this of overridden binding print was 
declared without the INTENT(IN) attribute.  The corresponding dummy argument of overriding binding 
print must not be declared with the INTENT(IN) attribute.
** myitem_list_m   === End of Compilation 2 ===
"Metcalf_oo.f90", line 303.7: 1514-219 (S) Unable to access module symbol file for module 
myitem_list_m. Check path and file permissions of file. Use association not done for this module.
1501-511  Compilation failed for file Metcalf_oo.f90.


Andy
0
Reply mai1 (33) 3/17/2012 11:36:58 AM

The only two compilers to currently offer full conformance
to the Fortran 2003 standard are Cray and IBM.

We publish a table in Fortran Forum which has details
of the state of conformance of compilers to the
Fortran 2003 and 2008 standards.

http://www.fortranplus.co.uk/resources/compiler_table.pdf

As a point of interest from what i can remember you need
to add the following flags to the IBM compiler

   -qlanglvl=2003pure
   -qxlf2003=ploymorphic

to access full 2003 support.

The nag 5.3 compiler compiles and runs the Metcalf example.
this requires the -f2003 switch.

intel requires
   /stand:f03 or /std03.

gfortran requires
   -std=2003

ian chivers

On 17/03/2012 11:36, Andrew Mai wrote:
> On 03/16/2012 09:31 PM, michaelmetcalf@compuserve.com wrote:
>
>> We would like to think that Appendix E of "Modern Fortran Explained"
>> is just such an example (of OO-programming).
>
> I tried four compilers with this short program. All failed. xlf2003 came
> the closest:
>
> % xlf2003 Metcalf_oo.f90
> ** anylist_m === End of Compilation 1 ===
> "Metcalf_oo.f90", line 273.18: 1514-668 (S) Dummy argument this of
> overridden binding print was declared without the INTENT(IN) attribute.
> The corresponding dummy argument of overriding binding print must not be
> declared with the INTENT(IN) attribute.
> ** myitem_list_m === End of Compilation 2 ===
> "Metcalf_oo.f90", line 303.7: 1514-219 (S) Unable to access module
> symbol file for module myitem_list_m. Check path and file permissions of
> file. Use association not done for this module.
> 1501-511 Compilation failed for file Metcalf_oo.f90.
>
>
> Andy

0
Reply ian7009 (5) 3/17/2012 5:04:26 PM

On 3/16/2012 8:49 AM, John Appleyard wrote:
> Does anyone know of any decently sized sample programs that exercise the
> new features in F200x?

The programs in *Guide to Fortran 2003 Programming*
are available via a link from the home page at
www.fortran.com. Don't know if "decently sized"
means bigger than these ???

Lots of them don't use new features as this is an
introductory book, but there are a few. Perhaps
the most interesting implements a queue of objects
of extended derived type (various vehicles). I
think this ran correctly on the NAG compiler.

I have a nice coarray example (heat xfer on a plate)
that runs on four images. Works on Intel and Cray.

-- 
Walt Brainerd
0
Reply walt739 (18) 3/17/2012 8:47:02 PM

Hi Andrew

I took a quick look, and I believe XLF is correct in flagging the error. 
The following quotes and page numbers correspond to the 2010-11-24 draft of 
F2008.

4.5.7.3 Type-bound procedure overriding

Starting on line 7:

"The overriding and overridden type-bound procedures shall satisfy the 
following conditions.
....
- Dummy arguments that correspond by position shall have the same names and 
characteristics, except for the type of the passed-object dummy arguments."

12.3.2.2 Characteristics of dummy data objects

lines 17-18
"The characteristics of a dummy data object are its type, its type 
parameters (if any), its shape, its corank, its codimensions, its intent 
(5.3.10, 5.4.9), ..."

Since print has intent(in) in one type and no specified intent (same as 
intent(inout)) in the other, the program does not conform to the above 
rules.  That said, since the above are rules not constraints, compilers 
don't have to flag them.  (i.e. The onus is on the user to follow the above 
rules.)

Regards

Rafik

"Andrew Mai" <mai@ucar.edu> wrote in message 
news:4f647732$0$293$14726298@news.sunsite.dk...
> On 03/16/2012 09:31 PM, michaelmetcalf@compuserve.com wrote:
>
>> We would like to think that Appendix E of "Modern Fortran Explained" is 
>> just such an example (of OO-programming).
>
> I tried four compilers with this short program. All failed. xlf2003 came 
> the closest:
>
> % xlf2003 Metcalf_oo.f90
> ** anylist_m   === End of Compilation 1 ===
> "Metcalf_oo.f90", line 273.18: 1514-668 (S) Dummy argument this of 
> overridden binding print was declared without the INTENT(IN) attribute. 
> The corresponding dummy argument of overriding binding print must not be 
> declared with the INTENT(IN) attribute.
> ** myitem_list_m   === End of Compilation 2 ===
> "Metcalf_oo.f90", line 303.7: 1514-219 (S) Unable to access module symbol 
> file for module myitem_list_m. Check path and file permissions of file. 
> Use association not done for this module.
> 1501-511  Compilation failed for file Metcalf_oo.f90.
>
>
> Andy 


0
Reply nospam95 (822) 3/17/2012 10:08:36 PM

Rafik Zurob <nospam@hotmail.com> wrote:

(snip)
> Since print has intent(in) in one type and no specified intent 
> (same as intent(inout)) in the other, the program does not conform 
> to the above rules.  

Having no INTENT is similar to, but not the same as, INTENT(INOUT).

-- glen
0
Reply gah (12258) 3/17/2012 10:14:56 PM

glen herrmannsfeldt <gah@ugcs.caltech.edu> wrote:

> Rafik Zurob <nospam@hotmail.com> wrote:
> (snip)
> > Since print has intent(in) in one type and no specified intent 
> > (same as intent(inout)) in the other, the program does not conform 
> > to the above rules.  
> 
> Having no INTENT is similar to, but not the same as, INTENT(INOUT).

I am quite confident that Rafik knows that. (Not that I've ever
personally met him, but his level of expertise is obvious enough from
his posts).

Indeed, his knowledge of this is implied by the part of his posting that
you cited above insomuch as he notes that this is a disagreement that
means nonconformance in this case.

I suppose, though, that I might quite likely be misreading the intent
(no pun intended) of your post, as I seem to do often enough. It reads
to me as though you were pointing out a flaw in Rafik's argument. But
perhaps instead, you were just elaborating to other people a part of
Rafik's argument that you considered non-obvious.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/18/2012 1:04:37 AM

Richard Maine <nospam@see.signature> wrote:

(snip, I wrote)
>> Having no INTENT is similar to, but not the same as, INTENT(INOUT).

> I am quite confident that Rafik knows that. (Not that I've ever
> personally met him, but his level of expertise is obvious enough 
> from his posts).

Some names I see often enough to remember, but I didn't remember that
one.

> Indeed, his knowledge of this is implied by the part of his posting that
> you cited above insomuch as he notes that this is a disagreement that
> means nonconformance in this case.

> I suppose, though, that I might quite likely be misreading the intent
> (no pun intended) of your post, as I seem to do often enough. It reads
> to me as though you were pointing out a flaw in Rafik's argument. But
> perhaps instead, you were just elaborating to other people a part of
> Rafik's argument that you considered non-obvious.

Yes, the latter. 

For one, I snipped the rest as it wasn't needed for the reply.

Also, while it is reasonably obvious that matching INTENT should
be correct, it is slightly less obvious when a specific
INTENT and no INTENT should or should not work.

-- glen
0
Reply gah (12258) 3/18/2012 4:25:03 AM

Hi Glen

You're right about INTENT(INOUT) not being the same as not specifying
INTENT.  The standard is quite clear about that.  I was oversimplifying to
avoid going into too much detail (especially about effective arguments and
definability.)  The point is, the intent doesn't match.

> Also, while it is reasonably obvious that matching INTENT should
> be correct, it is slightly less obvious when a specific
> INTENT and no INTENT should or should not work.

I believe mixing INTENT with unspecified INTENT in this way is
non-conformant.  (Characteristics must match.  INTENT is a characteristic,
and as we discussed, not specifying INTENT is different from the three
explicit INTENTs.)

I think the standard has this rule to help compilers with polymorphic calls.
For example, let's say we have types "base" and "child", and that we have a
binding foo that takes one argument "x":

type base
contains
  procedure :: foo => foo_base
end type

type, extends(base) :: child
contains
  procedure :: foo => foo_child
end type

class(base), allocatable :: a
type(child) :: c
type(dt) x
allocate(child :: a)
call a%foo(x)
call c%foo(x)

For the compiler to optimally alias the a%foo(x) call above, and to perform
any needed finalization on x in the case of INTENT(OUT), it needs to know
the intent of argument "x".  The compiler does not necessarily know the
dynamic type of "a" at compile time.  So the best it can do is use the
interface for foo from "a"'s declared type or a parent of the declared type.
If specifying the INTENT of "x" in only one of foo_base and foo_child were
allowed, the calls to a%foo(x) and c%foo(x) might get different aliasing and
finalization.

Regards

Rafik
Visit the Fortran Cafe at http://ibm.com/rational/cafe


0
Reply nospam95 (822) 3/18/2012 8:57:44 AM

Walt Brainerd wrote:
> On 3/16/2012 8:49 AM, John Appleyard wrote:
>> Does anyone know of any decently sized sample programs that exercise the
>> new features in F200x?
> 
> The programs in *Guide to Fortran 2003 Programming*
> are available via a link from the home page at
> www.fortran.com. Don't know if "decently sized"
> means bigger than these ???
> 
> Lots of them don't use new features as this is an
> introductory book, but there are a few. Perhaps
> the most interesting implements a queue of objects
> of extended derived type (various vehicles). I
> think this ran correctly on the NAG compiler.
> 
> I have a nice coarray example (heat xfer on a plate)
> that runs on four images. Works on Intel and Cray.
> 
Hi Walt,

I am sorry to say that I haven't visited your site for a little while - 
nice main page :-)

Cheers

Paul
0
Reply paul.richard.thomas (132) 3/18/2012 10:51:42 AM

> gfortran requires
>   -std=2003

Dear Ian,

gfortran does not require -std=f2003 to compile f2003 programs. 
Selecting this option constrains the compiler to reject f2008 features 
and vendor extensions.

To answer the original question: The gfortran testsuite might be a 
source of some usable f2003 code. class_array_3.f03 and 
typebound_operator_9.f03 are testcases that come to mind.

Cheers

Paul
0
Reply paul.richard.thomas (132) 3/18/2012 3:19:53 PM

On 18/03/2012 15:19, Paul Thomas wrote:
>
>> gfortran requires
>> -std=2003
>
> Dear Ian,
>
> gfortran does not require -std=f2003 to compile f2003 programs.
> Selecting this option constrains the compiler to reject f2008 features
> and vendor extensions.
>
> To answer the original question: The gfortran testsuite might be a
> source of some usable f2003 code. class_array_3.f03 and
> typebound_operator_9.f03 are testcases that come to mind.
>
> Cheers
>
> Paul

Curious, as I thought that we couldn't get some of the examples in our 
latest book to compile without this option.

cheers

ian
0
Reply ian7009 (5) 3/18/2012 4:49:40 PM

On Sun, 18 Mar 2012 16:49:40 +0000, Ian Chivers wrote:

> On 18/03/2012 15:19, Paul Thomas wrote:
>>
>>> gfortran requires
>>> -std=2003
>>
>> Dear Ian,
>>
>> gfortran does not require -std=f2003 to compile f2003 programs.
>> Selecting this option constrains the compiler to reject f2008 features
>> and vendor extensions.
>>
>> To answer the original question: The gfortran testsuite might be a
>> source of some usable f2003 code. class_array_3.f03 and
>> typebound_operator_9.f03 are testcases that come to mind.
>>
>> Cheers
>>
>> Paul
> 
> Curious, as I thought that we couldn't get some of the examples in our 
> latest book to compile without this option.
> 

By default, gfortran without -std= will do its best to compile whatever
you throw at her.  If you need -std=f2003 to compile a piece of code,
this suggests that either gfortran has a bug (which is possible of course)
or you've hit an incompatibility between the Standards and/or a 
vendor extension.  Can you send an example of the problem you've
found to the fortran at gcc dot gnu dot org mailinglist.

-- 
steve
0
Reply sgk (132) 3/18/2012 5:55:22 PM

"John Appleyard" <john.spamtrap@polyhedron.com> wrote in message 
news:jjvneu$ikh$1@dont-email.me...

> Does anyone know of any decently sized sample programs that exercise the 
> new features in F200x?

F03GL does some C interop.

-- 
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


0
Reply not_valid (1681) 3/18/2012 7:04:05 PM

On Saturday, March 17, 2012 8:36:58 PM UTC+9, Andrew Mai wrote:
> On 03/16/2012 09:31 PM, michaelmetcalf@compuserve.com wrote:
> 
> > We would like to think that Appendix E of "Modern Fortran Explained" is just such an example (of OO-programming).
> 
> I tried four compilers with this short program. All failed. xlf2003 came the closest:
> 
> % xlf2003 Metcalf_oo.f90
> ** anylist_m   === End of Compilation 1 ===
> "Metcalf_oo.f90", line 273.18: 1514-668 (S) Dummy argument this of overridden binding print was 
> declared without the INTENT(IN) attribute.  The corresponding dummy argument of overriding binding 
> print must not be declared with the INTENT(IN) attribute.
> ** myitem_list_m   === End of Compilation 2 ===
> "Metcalf_oo.f90", line 303.7: 1514-219 (S) Unable to access module symbol file for module 
> myitem_list_m. Check path and file permissions of file. Use association not done for this module.
> 1501-511  Compilation failed for file Metcalf_oo.f90.
> 
Sorry for this error, which can be corrected by adding intent(in) to the line after subroutine print(this).

Regards,

Mike Metcalf
0
Reply michaelmetcalf (810) 3/19/2012 10:00:12 AM

Op vrijdag 16 maart 2012 16:49:50 UTC+1 schreef John Appleyard het volgende:
> Does anyone know of any decently sized sample programs that exercise the 
> new features in F200x?
> -- 
> JA

I have a whole bunch of sample programs, many of which use F2003 features,
though not all. I can send to you.

Regards,

Arjen
0
Reply arjen.markus895 (634) 3/19/2012 11:00:38 AM

On 3/19/2012 6:00 AM, michaelmetcalf@compuserve.com wrote:
> On Saturday, March 17, 2012 8:36:58 PM UTC+9, Andrew Mai wrote:
>> On 03/16/2012 09:31 PM, michaelmetcalf@compuserve.com wrote:
>>
>>> We would like to think that Appendix E of "Modern Fortran Explained" is just such an example (of OO-programming).
>>
>> I tried four compilers with this short program. All failed. xlf2003 came the closest:
>>
>> % xlf2003 Metcalf_oo.f90
>> ** anylist_m   === End of Compilation 1 ===
>> "Metcalf_oo.f90", line 273.18: 1514-668 (S) Dummy argument this of overridden binding print was
>> declared without the INTENT(IN) attribute.  The corresponding dummy argument of overriding binding
>> print must not be declared with the INTENT(IN) attribute.
>> ** myitem_list_m   === End of Compilation 2 ===
>> "Metcalf_oo.f90", line 303.7: 1514-219 (S) Unable to access module symbol file for module
>> myitem_list_m. Check path and file permissions of file. Use association not done for this module.
>> 1501-511  Compilation failed for file Metcalf_oo.f90.
>>
> Sorry for this error, which can be corrected by adding intent(in) to the line after subroutine print(this).
>

Current ifort compiles (but doesn't run) oo.f90 with this correction.


-- 
Tim Prince
0
Reply tprince8714 (291) 3/19/2012 11:57:38 AM

On 3/17/2012 1:04 PM, Ian Chivers wrote:
> intel requires
>    /stand:f03 or /std03.

The /stand (or -std) switch in Intel Fortran does not affect which 
language features are supported - that is a standards diagnostic option 
only.  Perhaps you are thinking of /standard-semantics (or 
-standard-semantics), which changes default behaviors in some areas to 
conform to Fortran 2003.

I note that even with this option, Intel Fortran does not like Mike's 
source file.  I will look at this more closely.

-- 
Steve Lionel
Developer Products Division
Intel Corporation
Merrimack, NH

For email address, replace "invalid" with "com"

User communities for Intel Software Development Products
   http://software.intel.com/en-us/forums/
Intel Software Development Products Support
   http://software.intel.com/sites/support/
My Fortran blog
   http://www.intel.com/software/drfortran

Refer to http://software.intel.com/en-us/articles/optimization-notice 
for more information regarding performance and optimization choices in 
Intel software products.
0
Reply Steve.Lionel5921 (403) 3/19/2012 1:53:25 PM

Walt Brainerd wrote:
> I have a nice coarray example (heat xfer on a plate)
> that runs on four images. Works on Intel and Cray.

Walt, where is this coarray example?  I can't seem to find it in the 
TGZ, nor by searching the www site.  I'm interested because I'm starting 
to play with coarrays to see if it'll be suitable for parallelising a 
program of ours (and the more coarray examples I can find, the better).

Thanks, Tom
0
Reply none7518 (25) 3/19/2012 2:08:02 PM

Op maandag 19 maart 2012 15:08:02 UTC+1 schreef Tom Micevski het volgende:
> Walt Brainerd wrote:
> > I have a nice coarray example (heat xfer on a plate)
> > that runs on four images. Works on Intel and Cray.
> 
> Walt, where is this coarray example?  I can't seem to find it in the 
> TGZ, nor by searching the www site.  I'm interested because I'm starting 
> to play with coarrays to see if it'll be suitable for parallelising a 
> program of ours (and the more coarray examples I can find, the better).
> 
> Thanks, Tom

I have two coarray examples for you.

Regards,

Arjen
0
Reply arjen.markus895 (634) 3/19/2012 2:46:35 PM

On 3/19/2012 7:08 AM, Tom Micevski wrote:
> Walt Brainerd wrote:
>> I have a nice coarray example (heat xfer on a plate)
>> that runs on four images. Works on Intel and Cray.
>
> Walt, where is this coarray example? I can't seem to find it in the TGZ,
> nor by searching the www site. I'm interested because I'm starting to
> play with coarrays to see if it'll be suitable for parallelising a
> program of ours (and the more coarray examples I can find, the better).
>
> Thanks, Tom

Sorry, I didn't know if anybody would actually be interested.

It is now at http://www.fortran.com/heat4_caf.f90

We have Dick Hendrickson to thank for the one-image version,
especially the clever use of the pointers n, e, w, and s.
Any strangeness in the coarray stuff is strictly mine.

-- 
Walt Brainerd
0
Reply walt739 (18) 3/19/2012 7:02:18 PM

> I have a whole bunch of sample programs, many of which use F2003 features,
> though not all. I can send to you.
> 
> Regards,
> 
> Arjen

In that case then, Arjen, you might recognise the code below! The ! { dg 
....... } things are testsuite directives.

Cheers

Paul

[pault@localhost ~]# cat 
/svn/trunk/gcc/testsuite/gfortran.dg/typebound_operator_9.f03
! { dg-do run }
! { dg-add-options ieee }
! { dg-skip-if "Too big for local store" { spu-*-* } { "*" } { "" } }
!
!     Solve a diffusion problem using an object-oriented approach
!
!     Author: Arjen Markus (comp.lang.fortran)
!     This version: pault@gcc.gnu.org
!
!     Note:
!     (i) This could be turned into a more sophisticated program
!     using the techniques described in the chapter on
!     mathematical abstractions.
!     (That would allow the selection of the time integration
!     method in a transparent way)
!
!     (ii) The target procedures for process_p and source_p are
!     different to the typebound procedures for dynamic types
!     because the passed argument is not type(base_pde_object).
!
!     (iii) Two solutions are calculated, one with the procedure
!     pointers and the other with typebound procedures. The sums
!     of the solutions are compared.

!     (iv) The source is a delta function in the middle of the
!     mesh, whilst the process is quartic in the local value,
!     when it is positive.
!
! base_pde_objects --
!     Module to define the basic objects
!
module base_pde_objects
   implicit none
   type, abstract :: base_pde_object
! No data
     procedure(process_p), pointer, pass :: process_p
     procedure(source_p), pointer, pass  :: source_p
   contains
     procedure(process), deferred :: process
     procedure(source), deferred :: source
     procedure :: initialise
     procedure :: nabla2
     procedure :: print
     procedure(real_times_obj), pass(obj), deferred :: real_times_obj
     procedure(obj_plus_obj),              deferred :: obj_plus_obj
     procedure(obj_assign_obj),            deferred :: obj_assign_obj
     generic :: operator(*)    => real_times_obj
     generic :: operator(+)    => obj_plus_obj
     generic :: assignment(=)  => obj_assign_obj
   end type
   abstract interface
     function process_p (obj)
       import base_pde_object
       class(base_pde_object), intent(in)  :: obj
       class(base_pde_object), allocatable :: process_p
     end function process_p
   end interface
   abstract interface
     function source_p (obj, time)
       import base_pde_object
       class(base_pde_object), intent(in)  :: obj
       real, intent(in)                    :: time
       class(base_pde_object), allocatable :: source_p
     end function source_p
   end interface
   abstract interface
     function process (obj)
       import base_pde_object
       class(base_pde_object), intent(in)  :: obj
       class(base_pde_object), allocatable :: process
     end function process
   end interface
   abstract interface
     function source (obj, time)
       import base_pde_object
       class(base_pde_object), intent(in)  :: obj
       real, intent(in)                    :: time
       class(base_pde_object), allocatable :: source
     end function source
   end interface
   abstract interface
     function real_times_obj (factor, obj) result(newobj)
       import base_pde_object
       real, intent(in)                    :: factor
       class(base_pde_object), intent(in)  :: obj
       class(base_pde_object), allocatable :: newobj
     end function real_times_obj
   end interface
   abstract interface
     function obj_plus_obj (obj1, obj2) result(newobj)
       import base_pde_object
       class(base_pde_object), intent(in)  :: obj1
       class(base_pde_object), intent(in)  :: obj2
       class(base_pde_object), allocatable :: newobj
     end function obj_plus_obj
   end interface
   abstract interface
     subroutine obj_assign_obj (obj1, obj2)
       import base_pde_object
       class(base_pde_object), intent(inout)  :: obj1
       class(base_pde_object), intent(in)     :: obj2
     end subroutine obj_assign_obj
   end interface
contains
! print --
!     Print the concentration field
   subroutine print (obj)
     class(base_pde_object) :: obj
     ! Dummy
   end subroutine print
! initialise --
!     Initialise the concentration field using a specific function
   subroutine initialise (obj, funcxy)
     class(base_pde_object) :: obj
     interface
       real function funcxy (coords)
         real, dimension(:), intent(in) :: coords
       end function funcxy
     end interface
     ! Dummy
   end subroutine initialise
! nabla2 --
!     Determine the divergence
   function nabla2 (obj)
     class(base_pde_object), intent(in)  :: obj
     class(base_pde_object), allocatable :: nabla2
     ! Dummy
   end function nabla2
end module base_pde_objects
! cartesian_2d_objects --
!     PDE object on a 2D cartesian grid
!
module cartesian_2d_objects
   use base_pde_objects
   implicit none
   type, extends(base_pde_object) :: cartesian_2d_object
     real, dimension(:,:), allocatable :: c
     real                              :: dx
     real                              :: dy
   contains
     procedure            :: process       => process_cart2d
     procedure            :: source         => source_cart2d
     procedure            :: initialise     => initialise_cart2d
     procedure            :: nabla2         => nabla2_cart2d
     procedure            :: print          => print_cart2d
     procedure, pass(obj) :: real_times_obj => real_times_cart2d
     procedure            :: obj_plus_obj   => obj_plus_cart2d
     procedure            :: obj_assign_obj => obj_assign_cart2d
   end type cartesian_2d_object
   interface grid_definition
     module procedure grid_definition_cart2d
   end interface
contains
   function process_cart2d (obj)
     class(cartesian_2d_object), intent(in)  :: obj
     class(base_pde_object), allocatable :: process_cart2d
     allocate (process_cart2d,source = obj)
     select type (process_cart2d)
       type is (cartesian_2d_object)
         process_cart2d%c = -sign (obj%c, 1.0)*obj%c** 4
       class default
         call abort
     end select
   end function process_cart2d
   function process_cart2d_p (obj)
     class(base_pde_object), intent(in)  :: obj
     class(base_pde_object), allocatable :: process_cart2d_p
     allocate (process_cart2d_p,source = obj)
     select type (process_cart2d_p)
       type is (cartesian_2d_object)
         select type (obj)
           type is (cartesian_2d_object)
             process_cart2d_p%c = -sign (obj%c, 1.0)*obj%c** 4
         end select
       class default
         call abort
     end select
   end function process_cart2d_p
   function source_cart2d (obj, time)
     class(cartesian_2d_object), intent(in)  :: obj
     real, intent(in)                    :: time
     class(base_pde_object), allocatable :: source_cart2d
     integer :: m, n
     m = size (obj%c, 1)
     n = size (obj%c, 2)
     allocate (source_cart2d, source = obj)
     select type (source_cart2d)
       type is (cartesian_2d_object)
         if (allocated (source_cart2d%c)) deallocate (source_cart2d%c)
         allocate (source_cart2d%c(m, n))
         source_cart2d%c = 0.0
         if (time .lt. 5.0) source_cart2d%c(m/2, n/2) = 0.1
       class default
         call abort
     end select
   end function source_cart2d

   function source_cart2d_p (obj, time)
     class(base_pde_object), intent(in)  :: obj
     real, intent(in)                    :: time
     class(base_pde_object), allocatable :: source_cart2d_p
     integer :: m, n
     select type (obj)
       type is (cartesian_2d_object)
         m = size (obj%c, 1)
         n = size (obj%c, 2)
       class default
        call abort
     end select
     allocate (source_cart2d_p,source = obj)
     select type (source_cart2d_p)
       type is (cartesian_2d_object)
         if (allocated (source_cart2d_p%c)) deallocate (source_cart2d_p%c)
         allocate (source_cart2d_p%c(m,n))
         source_cart2d_p%c = 0.0
         if (time .lt. 5.0) source_cart2d_p%c(m/2, n/2) = 0.1
       class default
         call abort
     end select
   end function source_cart2d_p

! grid_definition --
!     Initialises the grid
!
   subroutine grid_definition_cart2d (obj, sizes, dims)
     class(base_pde_object), allocatable :: obj
     real, dimension(:)                  :: sizes
     integer, dimension(:)               :: dims
     allocate( cartesian_2d_object :: obj )
     select type (obj)
       type is (cartesian_2d_object)
         allocate (obj%c(dims(1), dims(2)))
         obj%c  = 0.0
         obj%dx = sizes(1)/dims(1)
         obj%dy = sizes(2)/dims(2)
       class default
         call abort
     end select
   end subroutine grid_definition_cart2d
! print_cart2d --
!     Print the concentration field to the screen
!
   subroutine print_cart2d (obj)
     class(cartesian_2d_object) :: obj
     character(len=20)          :: format
     write( format, '(a,i0,a)' ) '(', size(obj%c,1), 'f6.3)'
     write( *, format ) obj%c
   end subroutine print_cart2d
! initialise_cart2d --
!     Initialise the concentration field using a specific function
!
   subroutine initialise_cart2d (obj, funcxy)
     class(cartesian_2d_object) :: obj
     interface
       real function funcxy (coords)
         real, dimension(:), intent(in) :: coords
       end function funcxy
     end interface
     integer                    :: i, j
     real, dimension(2)         :: x
     obj%c = 0.0
     do j = 2,size (obj%c, 2)-1
       x(2) = obj%dy * (j-1)
       do i = 2,size (obj%c, 1)-1
         x(1) = obj%dx * (i-1)
         obj%c(i,j) = funcxy (x)
       enddo
     enddo
   end subroutine initialise_cart2d
! nabla2_cart2d
!     Determine the divergence
   function nabla2_cart2d (obj)
     class(cartesian_2d_object), intent(in)  :: obj
     class(base_pde_object), allocatable     :: nabla2_cart2d
     integer                                 :: m, n
     real                                    :: dx, dy
     m = size (obj%c, 1)
     n = size (obj%c, 2)
     dx = obj%dx
     dy = obj%dy
     allocate (cartesian_2d_object :: nabla2_cart2d)
     select type (nabla2_cart2d)
       type is (cartesian_2d_object)
         allocate (nabla2_cart2d%c(m,n))
         nabla2_cart2d%c = 0.0
         nabla2_cart2d%c(2:m-1,2:n-1) = &
           -(2.0 * obj%c(2:m-1,2:n-1) - obj%c(1:m-2,2:n-1) - 
obj%c(3:m,2:n-1)) / dx**2 &
           -(2.0 * obj%c(2:m-1,2:n-1) - obj%c(2:m-1,1:n-2) - 
obj%c(2:m-1,3:n)) / dy**2
       class default
         call abort
     end select
   end function nabla2_cart2d
   function real_times_cart2d (factor, obj) result(newobj)
     real, intent(in)                        :: factor
     class(cartesian_2d_object), intent(in)  :: obj
     class(base_pde_object), allocatable     :: newobj
     integer                                 :: m, n
     m = size (obj%c, 1)
     n = size (obj%c, 2)
     allocate (cartesian_2d_object :: newobj)
     select type (newobj)
       type is (cartesian_2d_object)
         allocate (newobj%c(m,n))
         newobj%c = factor * obj%c
       class default
         call abort
     end select
   end function real_times_cart2d
   function obj_plus_cart2d (obj1, obj2) result( newobj )
     class(cartesian_2d_object), intent(in)  :: obj1
     class(base_pde_object), intent(in)      :: obj2
     class(base_pde_object), allocatable     :: newobj
     integer                                 :: m, n
     m = size (obj1%c, 1)
     n = size (obj1%c, 2)
     allocate (cartesian_2d_object :: newobj)
     select type (newobj)
       type is (cartesian_2d_object)
         allocate (newobj%c(m,n))
           select type (obj2)
             type is (cartesian_2d_object)
               newobj%c = obj1%c + obj2%c
             class default
               call abort
           end select
       class default
         call abort
     end select
   end function obj_plus_cart2d
   subroutine obj_assign_cart2d (obj1, obj2)
     class(cartesian_2d_object), intent(inout) :: obj1
     class(base_pde_object), intent(in)        :: obj2
     select type (obj2)
       type is (cartesian_2d_object)
         obj1%c = obj2%c
       class default
         call abort
     end select
   end subroutine obj_assign_cart2d
end module cartesian_2d_objects
! define_pde_objects --
!     Module to bring all the PDE object types together
!
module define_pde_objects
   use base_pde_objects
   use cartesian_2d_objects
   implicit none
   interface grid_definition
     module procedure grid_definition_general
   end interface
contains
   subroutine grid_definition_general (obj, type, sizes, dims)
     class(base_pde_object), allocatable :: obj
     character(len=*)                    :: type
     real, dimension(:)                  :: sizes
     integer, dimension(:)               :: dims
     select case (type)
       case ("cartesian 2d")
         call grid_definition (obj, sizes, dims)
       case default
         write(*,*) 'Unknown grid type: ', trim (type)
         stop
     end select
   end subroutine grid_definition_general
end module define_pde_objects
! pde_specific --
!     Module holding the routines specific to the PDE that
!     we are solving
!
module pde_specific
   implicit none
contains
   real function patch (coords)
     real, dimension(:), intent(in) :: coords
     if (sum ((coords-[50.0,50.0])**2) < 40.0) then
       patch = 1.0
     else
       patch = 0.0
     endif
   end function patch
end module pde_specific
! test_pde_solver --
!     Small test program to demonstrate the usage
!
program test_pde_solver
   use define_pde_objects
   use pde_specific
   implicit none
   class(base_pde_object), allocatable :: solution, deriv
   integer                             :: i
   real                                :: time, dtime, diff, chksum(2)

   call simulation1     ! Use proc pointers for source and process 
define_pde_objects
   select type (solution)
     type is (cartesian_2d_object)
       deallocate (solution%c)
   end select
   select type (deriv)
     type is (cartesian_2d_object)
       deallocate (deriv%c)
   end select
   deallocate (solution, deriv)

   call simulation2     ! Use typebound procedures for source and process
   if (chksum(1) .ne. chksum(2)) call abort
   if ((chksum(1) - 0.881868720)**2 > 1e-4) call abort
contains
   subroutine simulation1
!
! Create the grid
!
     call grid_definition (solution, "cartesian 2d", [100.0, 100.0], 
[16, 16])
     call grid_definition (deriv,    "cartesian 2d", [100.0, 100.0], 
[16, 16])
!
! Initialise the concentration field
!
     call solution%initialise (patch)
!
! Set the procedure pointers
!
     solution%source_p => source_cart2d_p
     solution%process_p => process_cart2d_p
!
! Perform the integration - explicit method
!
     time  = 0.0
     dtime = 0.1
     diff =  5.0e-3

! Give the diffusion coefficient correct dimensions.
     select type (solution)
       type is (cartesian_2d_object)
         diff  = diff * solution%dx * solution%dy / dtime
     end select

!     write(*,*) 'Time: ', time, diff
!     call solution%print
     do i = 1,100
       deriv    =  solution%nabla2 ()
       solution = solution + diff * dtime * deriv + solution%source_p 
(time) + solution%process_p ()
!         if ( mod(i, 25) == 0 ) then
!             write(*,*)'Time: ', time
!             call solution%print
!         endif
     time = time + dtime
     enddo
!    write(*,*) 'End result 1: '
!    call solution%print
     select type (solution)
       type is (cartesian_2d_object)
         chksum(1) = sum (solution%c)
     end select
   end subroutine
   subroutine simulation2
!
! Create the grid
!
     call grid_definition (solution, "cartesian 2d", [100.0, 100.0], 
[16, 16])
     call grid_definition (deriv,    "cartesian 2d", [100.0, 100.0], 
[16, 16])
!
! Initialise the concentration field
!
     call solution%initialise (patch)
!
! Set the procedure pointers
!
     solution%source_p => source_cart2d_p
     solution%process_p => process_cart2d_p
!
! Perform the integration - explicit method
!
     time  = 0.0
     dtime = 0.1
     diff =  5.0e-3

! Give the diffusion coefficient correct dimensions.
     select type (solution)
       type is (cartesian_2d_object)
         diff  = diff * solution%dx * solution%dy / dtime
     end select

!     write(*,*) 'Time: ', time, diff
!     call solution%print
     do i = 1,100
       deriv    =  solution%nabla2 ()
       solution = solution + diff * dtime * deriv + solution%source 
(time) + solution%process ()
!         if ( mod(i, 25) == 0 ) then
!             write(*,*)'Time: ', time
!             call solution%print
!         endif
       time = time + dtime
     enddo
!    write(*,*) 'End result 2: '
!    call solution%print
     select type (solution)
       type is (cartesian_2d_object)
         chksum(2) = sum (solution%c)
     end select
   end subroutine
end program test_pde_solver
! { dg-final { cleanup-modules "pde_specific define_pde_objects 
cartesian_2d_objects base_pde_objects" } }



0
Reply paul.richard.thomas (132) 3/19/2012 7:56:28 PM

Arjen Markus wrote:
> Op maandag 19 maart 2012 15:08:02 UTC+1 schreef Tom Micevski het volgende:
>> Walt Brainerd wrote:
>>> I have a nice coarray example (heat xfer on a plate)
>>> that runs on four images. Works on Intel and Cray.
>>
>> Walt, where is this coarray example?  I can't seem to find it in the
>> TGZ, nor by searching the www site.  I'm interested because I'm starting
>> to play with coarrays to see if it'll be suitable for parallelising a
>> program of ours (and the more coarray examples I can find, the better).
>>
>> Thanks, Tom
>
> I have two coarray examples for you.

Thanks Arjen and Walt.

My email is: tom.micevski /at\ newcastle.edu.au

Tom
0
Reply none7518 (25) 3/19/2012 10:13:32 PM

Hi Paul,

indeed I do :).

Regards,

Arjen

On 2012-03-19 20:56, Paul Thomas wrote:
> 
>> I have a whole bunch of sample programs, many of which use F2003 
>> features,
>> though not all. I can send to you.
>>
>> Regards,
>>
>> Arjen
> 
> In that case then, Arjen, you might recognise the code below! The ! { dg 
> ...... } things are testsuite directives.
> 
> Cheers
> 
> Paul
> 
> [pault@localhost ~]# cat 
> /svn/trunk/gcc/testsuite/gfortran.dg/typebound_operator_9.f03
> ! { dg-do run }
> ! { dg-add-options ieee }
> ! { dg-skip-if "Too big for local store" { spu-*-* } { "*" } { "" } }
> !
> !     Solve a diffusion problem using an object-oriented approach
> !
> !     Author: Arjen Markus (comp.lang.fortran)
> !     This version: pault@gcc.gnu.org
> !
> !     Note:
> !     (i) This could be turned into a more sophisticated program
> !     using the techniques described in the chapter on
> !     mathematical abstractions.
> !     (That would allow the selection of the time integration
> !     method in a transparent way)
> !
> !     (ii) The target procedures for process_p and source_p are
> !     different to the typebound procedures for dynamic types
> !     because the passed argument is not type(base_pde_object).
> !
> !     (iii) Two solutions are calculated, one with the procedure
> !     pointers and the other with typebound procedures. The sums
> !     of the solutions are compared.
> 
> !     (iv) The source is a delta function in the middle of the
> !     mesh, whilst the process is quartic in the local value,
> !     when it is positive.
> !
> ! base_pde_objects --
> !     Module to define the basic objects
> !
> module base_pde_objects
>   implicit none
>   type, abstract :: base_pde_object
> ! No data
>     procedure(process_p), pointer, pass :: process_p
>     procedure(source_p), pointer, pass  :: source_p
>   contains
>     procedure(process), deferred :: process
>     procedure(source), deferred :: source
>     procedure :: initialise
>     procedure :: nabla2
>     procedure :: print
>     procedure(real_times_obj), pass(obj), deferred :: real_times_obj
>     procedure(obj_plus_obj),              deferred :: obj_plus_obj
>     procedure(obj_assign_obj),            deferred :: obj_assign_obj
>     generic :: operator(*)    => real_times_obj
>     generic :: operator(+)    => obj_plus_obj
>     generic :: assignment(=)  => obj_assign_obj
>   end type
>   abstract interface
>     function process_p (obj)
>       import base_pde_object
>       class(base_pde_object), intent(in)  :: obj
>       class(base_pde_object), allocatable :: process_p
>     end function process_p
>   end interface
>   abstract interface
>     function source_p (obj, time)
>       import base_pde_object
>       class(base_pde_object), intent(in)  :: obj
>       real, intent(in)                    :: time
>       class(base_pde_object), allocatable :: source_p
>     end function source_p
>   end interface
>   abstract interface
>     function process (obj)
>       import base_pde_object
>       class(base_pde_object), intent(in)  :: obj
>       class(base_pde_object), allocatable :: process
>     end function process
>   end interface
>   abstract interface
>     function source (obj, time)
>       import base_pde_object
>       class(base_pde_object), intent(in)  :: obj
>       real, intent(in)                    :: time
>       class(base_pde_object), allocatable :: source
>     end function source
>   end interface
>   abstract interface
>     function real_times_obj (factor, obj) result(newobj)
>       import base_pde_object
>       real, intent(in)                    :: factor
>       class(base_pde_object), intent(in)  :: obj
>       class(base_pde_object), allocatable :: newobj
>     end function real_times_obj
>   end interface
>   abstract interface
>     function obj_plus_obj (obj1, obj2) result(newobj)
>       import base_pde_object
>       class(base_pde_object), intent(in)  :: obj1
>       class(base_pde_object), intent(in)  :: obj2
>       class(base_pde_object), allocatable :: newobj
>     end function obj_plus_obj
>   end interface
>   abstract interface
>     subroutine obj_assign_obj (obj1, obj2)
>       import base_pde_object
>       class(base_pde_object), intent(inout)  :: obj1
>       class(base_pde_object), intent(in)     :: obj2
>     end subroutine obj_assign_obj
>   end interface
> contains
> ! print --
> !     Print the concentration field
>   subroutine print (obj)
>     class(base_pde_object) :: obj
>     ! Dummy
>   end subroutine print
> ! initialise --
> !     Initialise the concentration field using a specific function
>   subroutine initialise (obj, funcxy)
>     class(base_pde_object) :: obj
>     interface
>       real function funcxy (coords)
>         real, dimension(:), intent(in) :: coords
>       end function funcxy
>     end interface
>     ! Dummy
>   end subroutine initialise
> ! nabla2 --
> !     Determine the divergence
>   function nabla2 (obj)
>     class(base_pde_object), intent(in)  :: obj
>     class(base_pde_object), allocatable :: nabla2
>     ! Dummy
>   end function nabla2
> end module base_pde_objects
> ! cartesian_2d_objects --
> !     PDE object on a 2D cartesian grid
> !
> module cartesian_2d_objects
>   use base_pde_objects
>   implicit none
>   type, extends(base_pde_object) :: cartesian_2d_object
>     real, dimension(:,:), allocatable :: c
>     real                              :: dx
>     real                              :: dy
>   contains
>     procedure            :: process       => process_cart2d
>     procedure            :: source         => source_cart2d
>     procedure            :: initialise     => initialise_cart2d
>     procedure            :: nabla2         => nabla2_cart2d
>     procedure            :: print          => print_cart2d
>     procedure, pass(obj) :: real_times_obj => real_times_cart2d
>     procedure            :: obj_plus_obj   => obj_plus_cart2d
>     procedure            :: obj_assign_obj => obj_assign_cart2d
>   end type cartesian_2d_object
>   interface grid_definition
>     module procedure grid_definition_cart2d
>   end interface
> contains
>   function process_cart2d (obj)
>     class(cartesian_2d_object), intent(in)  :: obj
>     class(base_pde_object), allocatable :: process_cart2d
>     allocate (process_cart2d,source = obj)
>     select type (process_cart2d)
>       type is (cartesian_2d_object)
>         process_cart2d%c = -sign (obj%c, 1.0)*obj%c** 4
>       class default
>         call abort
>     end select
>   end function process_cart2d
>   function process_cart2d_p (obj)
>     class(base_pde_object), intent(in)  :: obj
>     class(base_pde_object), allocatable :: process_cart2d_p
>     allocate (process_cart2d_p,source = obj)
>     select type (process_cart2d_p)
>       type is (cartesian_2d_object)
>         select type (obj)
>           type is (cartesian_2d_object)
>             process_cart2d_p%c = -sign (obj%c, 1.0)*obj%c** 4
>         end select
>       class default
>         call abort
>     end select
>   end function process_cart2d_p
>   function source_cart2d (obj, time)
>     class(cartesian_2d_object), intent(in)  :: obj
>     real, intent(in)                    :: time
>     class(base_pde_object), allocatable :: source_cart2d
>     integer :: m, n
>     m = size (obj%c, 1)
>     n = size (obj%c, 2)
>     allocate (source_cart2d, source = obj)
>     select type (source_cart2d)
>       type is (cartesian_2d_object)
>         if (allocated (source_cart2d%c)) deallocate (source_cart2d%c)
>         allocate (source_cart2d%c(m, n))
>         source_cart2d%c = 0.0
>         if (time .lt. 5.0) source_cart2d%c(m/2, n/2) = 0.1
>       class default
>         call abort
>     end select
>   end function source_cart2d
> 
>   function source_cart2d_p (obj, time)
>     class(base_pde_object), intent(in)  :: obj
>     real, intent(in)                    :: time
>     class(base_pde_object), allocatable :: source_cart2d_p
>     integer :: m, n
>     select type (obj)
>       type is (cartesian_2d_object)
>         m = size (obj%c, 1)
>         n = size (obj%c, 2)
>       class default
>        call abort
>     end select
>     allocate (source_cart2d_p,source = obj)
>     select type (source_cart2d_p)
>       type is (cartesian_2d_object)
>         if (allocated (source_cart2d_p%c)) deallocate (source_cart2d_p%c)
>         allocate (source_cart2d_p%c(m,n))
>         source_cart2d_p%c = 0.0
>         if (time .lt. 5.0) source_cart2d_p%c(m/2, n/2) = 0.1
>       class default
>         call abort
>     end select
>   end function source_cart2d_p
> 
> ! grid_definition --
> !     Initialises the grid
> !
>   subroutine grid_definition_cart2d (obj, sizes, dims)
>     class(base_pde_object), allocatable :: obj
>     real, dimension(:)                  :: sizes
>     integer, dimension(:)               :: dims
>     allocate( cartesian_2d_object :: obj )
>     select type (obj)
>       type is (cartesian_2d_object)
>         allocate (obj%c(dims(1), dims(2)))
>         obj%c  = 0.0
>         obj%dx = sizes(1)/dims(1)
>         obj%dy = sizes(2)/dims(2)
>       class default
>         call abort
>     end select
>   end subroutine grid_definition_cart2d
> ! print_cart2d --
> !     Print the concentration field to the screen
> !
>   subroutine print_cart2d (obj)
>     class(cartesian_2d_object) :: obj
>     character(len=20)          :: format
>     write( format, '(a,i0,a)' ) '(', size(obj%c,1), 'f6.3)'
>     write( *, format ) obj%c
>   end subroutine print_cart2d
> ! initialise_cart2d --
> !     Initialise the concentration field using a specific function
> !
>   subroutine initialise_cart2d (obj, funcxy)
>     class(cartesian_2d_object) :: obj
>     interface
>       real function funcxy (coords)
>         real, dimension(:), intent(in) :: coords
>       end function funcxy
>     end interface
>     integer                    :: i, j
>     real, dimension(2)         :: x
>     obj%c = 0.0
>     do j = 2,size (obj%c, 2)-1
>       x(2) = obj%dy * (j-1)
>       do i = 2,size (obj%c, 1)-1
>         x(1) = obj%dx * (i-1)
>         obj%c(i,j) = funcxy (x)
>       enddo
>     enddo
>   end subroutine initialise_cart2d
> ! nabla2_cart2d
> !     Determine the divergence
>   function nabla2_cart2d (obj)
>     class(cartesian_2d_object), intent(in)  :: obj
>     class(base_pde_object), allocatable     :: nabla2_cart2d
>     integer                                 :: m, n
>     real                                    :: dx, dy
>     m = size (obj%c, 1)
>     n = size (obj%c, 2)
>     dx = obj%dx
>     dy = obj%dy
>     allocate (cartesian_2d_object :: nabla2_cart2d)
>     select type (nabla2_cart2d)
>       type is (cartesian_2d_object)
>         allocate (nabla2_cart2d%c(m,n))
>         nabla2_cart2d%c = 0.0
>         nabla2_cart2d%c(2:m-1,2:n-1) = &
>           -(2.0 * obj%c(2:m-1,2:n-1) - obj%c(1:m-2,2:n-1) - 
> obj%c(3:m,2:n-1)) / dx**2 &
>           -(2.0 * obj%c(2:m-1,2:n-1) - obj%c(2:m-1,1:n-2) - 
> obj%c(2:m-1,3:n)) / dy**2
>       class default
>         call abort
>     end select
>   end function nabla2_cart2d
>   function real_times_cart2d (factor, obj) result(newobj)
>     real, intent(in)                        :: factor
>     class(cartesian_2d_object), intent(in)  :: obj
>     class(base_pde_object), allocatable     :: newobj
>     integer                                 :: m, n
>     m = size (obj%c, 1)
>     n = size (obj%c, 2)
>     allocate (cartesian_2d_object :: newobj)
>     select type (newobj)
>       type is (cartesian_2d_object)
>         allocate (newobj%c(m,n))
>         newobj%c = factor * obj%c
>       class default
>         call abort
>     end select
>   end function real_times_cart2d
>   function obj_plus_cart2d (obj1, obj2) result( newobj )
>     class(cartesian_2d_object), intent(in)  :: obj1
>     class(base_pde_object), intent(in)      :: obj2
>     class(base_pde_object), allocatable     :: newobj
>     integer                                 :: m, n
>     m = size (obj1%c, 1)
>     n = size (obj1%c, 2)
>     allocate (cartesian_2d_object :: newobj)
>     select type (newobj)
>       type is (cartesian_2d_object)
>         allocate (newobj%c(m,n))
>           select type (obj2)
>             type is (cartesian_2d_object)
>               newobj%c = obj1%c + obj2%c
>             class default
>               call abort
>           end select
>       class default
>         call abort
>     end select
>   end function obj_plus_cart2d
>   subroutine obj_assign_cart2d (obj1, obj2)
>     class(cartesian_2d_object), intent(inout) :: obj1
>     class(base_pde_object), intent(in)        :: obj2
>     select type (obj2)
>       type is (cartesian_2d_object)
>         obj1%c = obj2%c
>       class default
>         call abort
>     end select
>   end subroutine obj_assign_cart2d
> end module cartesian_2d_objects
> ! define_pde_objects --
> !     Module to bring all the PDE object types together
> !
> module define_pde_objects
>   use base_pde_objects
>   use cartesian_2d_objects
>   implicit none
>   interface grid_definition
>     module procedure grid_definition_general
>   end interface
> contains
>   subroutine grid_definition_general (obj, type, sizes, dims)
>     class(base_pde_object), allocatable :: obj
>     character(len=*)                    :: type
>     real, dimension(:)                  :: sizes
>     integer, dimension(:)               :: dims
>     select case (type)
>       case ("cartesian 2d")
>         call grid_definition (obj, sizes, dims)
>       case default
>         write(*,*) 'Unknown grid type: ', trim (type)
>         stop
>     end select
>   end subroutine grid_definition_general
> end module define_pde_objects
> ! pde_specific --
> !     Module holding the routines specific to the PDE that
> !     we are solving
> !
> module pde_specific
>   implicit none
> contains
>   real function patch (coords)
>     real, dimension(:), intent(in) :: coords
>     if (sum ((coords-[50.0,50.0])**2) < 40.0) then
>       patch = 1.0
>     else
>       patch = 0.0
>     endif
>   end function patch
> end module pde_specific
> ! test_pde_solver --
> !     Small test program to demonstrate the usage
> !
> program test_pde_solver
>   use define_pde_objects
>   use pde_specific
>   implicit none
>   class(base_pde_object), allocatable :: solution, deriv
>   integer                             :: i
>   real                                :: time, dtime, diff, chksum(2)
> 
>   call simulation1     ! Use proc pointers for source and process 
> define_pde_objects
>   select type (solution)
>     type is (cartesian_2d_object)
>       deallocate (solution%c)
>   end select
>   select type (deriv)
>     type is (cartesian_2d_object)
>       deallocate (deriv%c)
>   end select
>   deallocate (solution, deriv)
> 
>   call simulation2     ! Use typebound procedures for source and process
>   if (chksum(1) .ne. chksum(2)) call abort
>   if ((chksum(1) - 0.881868720)**2 > 1e-4) call abort
> contains
>   subroutine simulation1
> !
> ! Create the grid
> !
>     call grid_definition (solution, "cartesian 2d", [100.0, 100.0], [16, 
> 16])
>     call grid_definition (deriv,    "cartesian 2d", [100.0, 100.0], [16, 
> 16])
> !
> ! Initialise the concentration field
> !
>     call solution%initialise (patch)
> !
> ! Set the procedure pointers
> !
>     solution%source_p => source_cart2d_p
>     solution%process_p => process_cart2d_p
> !
> ! Perform the integration - explicit method
> !
>     time  = 0.0
>     dtime = 0.1
>     diff =  5.0e-3
> 
> ! Give the diffusion coefficient correct dimensions.
>     select type (solution)
>       type is (cartesian_2d_object)
>         diff  = diff * solution%dx * solution%dy / dtime
>     end select
> 
> !     write(*,*) 'Time: ', time, diff
> !     call solution%print
>     do i = 1,100
>       deriv    =  solution%nabla2 ()
>       solution = solution + diff * dtime * deriv + solution%source_p 
> (time) + solution%process_p ()
> !         if ( mod(i, 25) == 0 ) then
> !             write(*,*)'Time: ', time
> !             call solution%print
> !         endif
>     time = time + dtime
>     enddo
> !    write(*,*) 'End result 1: '
> !    call solution%print
>     select type (solution)
>       type is (cartesian_2d_object)
>         chksum(1) = sum (solution%c)
>     end select
>   end subroutine
>   subroutine simulation2
> !
> ! Create the grid
> !
>     call grid_definition (solution, "cartesian 2d", [100.0, 100.0], [16, 
> 16])
>     call grid_definition (deriv,    "cartesian 2d", [100.0, 100.0], [16, 
> 16])
> !
> ! Initialise the concentration field
> !
>     call solution%initialise (patch)
> !
> ! Set the procedure pointers
> !
>     solution%source_p => source_cart2d_p
>     solution%process_p => process_cart2d_p
> !
> ! Perform the integration - explicit method
> !
>     time  = 0.0
>     dtime = 0.1
>     diff =  5.0e-3
> 
> ! Give the diffusion coefficient correct dimensions.
>     select type (solution)
>       type is (cartesian_2d_object)
>         diff  = diff * solution%dx * solution%dy / dtime
>     end select
> 
> !     write(*,*) 'Time: ', time, diff
> !     call solution%print
>     do i = 1,100
>       deriv    =  solution%nabla2 ()
>       solution = solution + diff * dtime * deriv + solution%source 
> (time) + solution%process ()
> !         if ( mod(i, 25) == 0 ) then
> !             write(*,*)'Time: ', time
> !             call solution%print
> !         endif
>       time = time + dtime
>     enddo
> !    write(*,*) 'End result 2: '
> !    call solution%print
>     select type (solution)
>       type is (cartesian_2d_object)
>         chksum(2) = sum (solution%c)
>     end select
>   end subroutine
> end program test_pde_solver
> ! { dg-final { cleanup-modules "pde_specific define_pde_objects 
> cartesian_2d_objects base_pde_objects" } }
> 
> 
> 
0
Reply arjen.markus895 (634) 3/20/2012 8:05:47 AM

On 17.03.12 22:14, glen herrmannsfeldt wrote:
> Rafik Zurob<nospam@hotmail.com>  wrote:
>
> (snip)
>> Since print has intent(in) in one type and no specified intent
>> (same as intent(inout)) in the other, the program does not conform
>> to the above rules.
>
> Having no INTENT is similar to, but not the same as, INTENT(INOUT).
>
> -- glen

Sorry for the digression, but: really? What's the difference? I'm surprised.

Paul
0
Reply paul.anton.letnes1 (77) 3/22/2012 12:44:10 PM

Paul Anton Letnes <paul.anton.letnes@nospam.gmail.kthxbai.com> wrote:

> On 17.03.12 22:14, glen herrmannsfeldt wrote:

> > Having no INTENT is similar to, but not the same as, INTENT(INOUT).

> Sorry for the digression, but: really? What's the difference? I'm surprised.

There are quite a few differences, actually. Having no INTENT is...
quirky, mostly because of compatibilty requirements with pre-f90 codes.

One of the major differences is that the actual argument for an
INTENT(INOUT) dummy is required to be definable. That's regardless of
whether anything in the subroutine actually ever tries to define the
dummy or not. Just having INTENT(INOUT) (or INTENT(OUT)) is sufficient
to trigger the requirement. Though not strictlt required by the
standard, you can reasonably expect compilers to diagnose the error of
having a non-definable actual argument for an intent(INOUT) dummy if
there is an explicit interface. The simplest and most common case of a
non-definable actual argument is a literal constant.

That, of course, is not at all the case for having no intent. After all,
all pre-f90 arguments had no intent, and literal constant actual
arguments were common. It was also reasonably common error to use a
literal constant actual argument and then illegally define the dummy.
That is illegal, (but also is often not diagnosed at compile time).

For an argument without intent, the rule is that the actual argument has
to be definable if the code actually defines the dummy. I might note
that this is a run-time rule (ok, not on those words) in that it applies
only if a particular execution of the subroutine does such definition of
the dummy. There could be code in the subroutine that potentially does a
redefinition, as long as that cpde was not executed for the particular
call. Yes, there were cases where the same argument was sometimes used
for input and sometimes used fo routput, depending on the value of some
other argument. That wasn't as rare as you might think; I've run into it
several times.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/22/2012 4:14:03 PM

In article <jkf6qq$geg$1@dont-email.me>,
 Paul Anton Letnes <paul.anton.letnes@nospam.gmail.kthxbai.com> 
 wrote:

> On 17.03.12 22:14, glen herrmannsfeldt wrote:
> > Rafik Zurob<nospam@hotmail.com>  wrote:
> >
> > (snip)
> >> Since print has intent(in) in one type and no specified intent
> >> (same as intent(inout)) in the other, the program does not conform
> >> to the above rules.
> >
> > Having no INTENT is similar to, but not the same as, INTENT(INOUT).
> >
> > -- glen
> 
> Sorry for the digression, but: really? What's the difference? I'm surprised.

This discussion is about object oriented features of the language, 
and I'm not familiar enough with those to answer the question in 
that context.

But in F90, the difference is that you can, for example, pass a 
constant actual argument to a dummy argument with no intent, but if 
you pass a constant actual argument to an INTENT(INOUT) dummy, the 
compiler will flag that as an error.  In the former case, the 
programmer must ensure that the argument is not modified, and the 
compiler cannot know when a violation might occur (e.g. when the 
caller and callee are compiled separately).  In the latter case, the 
INTENT declaration says that the input value is needed and that the 
value will be changed.  Either or both of those things don't 
necessarily have to happen of course, but that is what the INTENT 
says.  So in this case the compiler knows (at compile time) that it 
is an error to associate a constant with that dummy argument.  These 
same INTENT mismatches can be caught with, for example INTENT(IN) 
actual arguments that are associated with INTENT(INOUT) dummy 
arguments, and so on.  I think now there is a PROTECTED attribute 
for module variables that can be used to achieve this same kind of 
thing.

If you think about it, you realize that it is a really good thing to 
be able to declare INTENT like that.  It catches a lot of errors 
early in the code writing process that would not be noticed 
otherwise, particularly when the different parts of the code are 
written by different people.

$.02 -Ron Shepard
0
Reply ron-shepard (1197) 3/22/2012 4:27:41 PM

Richard Maine <nospam@see.signature> schrieb:

> For an argument without intent, the rule is that the actual argument has
> to be definable if the code actually defines the dummy.

Depending on the implementation, this could lead to funny results.

For example, using Fortran on MVS, you could do

      program main
      call bar(3)
      print *,3
      end

      subroutine bar(i)
      i = 42
      end

and it would print 42.

This was sometimes known as "variation of constants" or "variation of
parameters", and was a way to introduce hard-to-find bugs in your
programs.
0
Reply tkoenig1 (168) 3/22/2012 5:34:04 PM

Thomas Koenig <tkoenig@netcologne.de> wrote:
> Richard Maine <nospam@see.signature> schrieb:

>> For an argument without intent, the rule is that the 
>> actual argument has to be definable if the code 
>> actually defines the dummy.

> Depending on the implementation, this could lead to funny results.

> For example, using Fortran on MVS, you could do

>      program main
>      call bar(3)
>      print *,3
>      end

>      subroutine bar(i)
>      i = 42
>      end

> and it would print 42.

Which MVS compilers did this? I thought I tried it once with either
Fortran G or H and it didn't. But the OS/360 compilers didn't have
a PROGRAM statement, and didn't allow constants in the I/O list,
so this couldn't have been for them.

I believe some compilers used a different copy of the constant, 
such that it would only change the value in future calls to 
the same subroutine, but not other uses. 

I remember finding out that VAX Fortran stores constants in pages 
marked read-only, such that it can detect attempts to modify constants.

-- glen
0
Reply gah (12258) 3/22/2012 7:54:36 PM

Thomas Koenig <tkoenig@netcologne.de> wrote:

> Richard Maine <nospam@see.signature> schrieb:
> 
> > For an argument without intent, the rule is that the actual argument has
> > to be definable if the code actually defines the dummy.
> 
> Depending on the implementation, this could lead to funny results.
[example elided]
> This was sometimes known as "variation of constants" or "variation of
> parameters", and was a way to introduce hard-to-find bugs in your
> programs.

Yes, that's exactly what I was referring to when I said:

>> It was also reasonably common error to use a
>> literal constant actual argument and then illegally define the dummy.
>> That is illegal, (but also is often not diagnosed at compile time).

-- 
Richard Maine
email: last name at domain . net
domain: summer-triangle
0
Reply nospam47 (9742) 3/22/2012 8:52:53 PM

glen herrmannsfeldt <gah@ugcs.caltech.edu> schrieb:
> Thomas Koenig <tkoenig@netcologne.de> wrote:

>> For example, using Fortran on MVS, you could do
>
>>      program main
>>      call bar(3)
>>      print *,3
>>      end
>
>>      subroutine bar(i)
>>      i = 42
>>      end
>
>> and it would print 42.
>
> Which MVS compilers did this?

It was on MVS/ESA on a IBM 3090 in the late eighties/early
ninetees.  It was probably VS Fortran, but I don't know the version
any more. And it was a full F77 compiler with some extensions
(including END DO) and lower-case lettters for programs, so the
PROGRAM statement was included.

Modern compilers tend to put the constant into read-only memory,
so the program aborts in bar.  Not for all architectures, though.
0
Reply tkoenig1 (168) 3/23/2012 6:34:36 AM

On 22.03.12 17:34, Thomas Koenig wrote:
>        program main
>        call bar(3)
>        print *,3
>        end
>
>        subroutine bar(i)
>        i = 42
>        end

This was interesting. Richard; your reply looks formally spot-on, but 
sometimes a simple example can be very illuminating for the non-expert 
:) For instance, the expression 'defined' in this context was new to me.

My findings on gfortran 4.6.2 are:
% gfortran -Wall -fbounds-check tst.f90 && ./a.out
zsh: bus error  ./a.out

Adding
integer, intent(inout) :: i
gave a compiler warning (no error), but the same error occurs when 
running the code.

Paul
0
Reply paul.anton.letnes1 (77) 3/23/2012 9:33:39 AM

Nomen Nescio <nobody@dizum.com> wrote:

> Thomas Koenig <tkoenig@netcologne.de> wrote:
> 
[example of effects of illegally defining a dummy argument with a
literal constant actual]
> 
> Shouldn't all FORTRAN compilers do this? Isn't FORTRAN call-by-address?

No. And no.

There is no specification about what Fortran compilers "should" do for
such illegal code. Ideally, they would diagnose the error, but you
probbaly won't find many that do. In practice, quite a few different
behaviors are observed.

And no, Fortran has never specified call-by-address. Although it is a
common enough misconception. That never has been part of the standard.
To the contrary, the standard goes quite a lot out of its way to allow
multiple implementation choices; that is the only reason for some of the
requirements in the standard. It used to be a fairly common
implementation choice in some cases, but was never universal. Today,
there are cases that cannot be reasonably implemented using
call-by-address. If you code with the assumption that Fortran always
uses call-by-address, you are almost bound to write buggy code.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/24/2012 10:17:28 PM

In article <1khgvcx.p6fmxbkarremN%nospam@see.signature>,
 nospam@see.signature (Richard Maine) wrote:

> And no, Fortran has never specified call-by-address. Although it is a
> common enough misconception. That never has been part of the standard.
> To the contrary, the standard goes quite a lot out of its way to allow
> multiple implementation choices; that is the only reason for some of the
> requirements in the standard. It used to be a fairly common
> implementation choice in some cases, but was never universal. Today,
> there are cases that cannot be reasonably implemented using
> call-by-address. If you code with the assumption that Fortran always
> uses call-by-address, you are almost bound to write buggy code.

I took a numerical methods course in school, and we used the 
school's IBM 1401 after hours to do our homework. This was in 1973.  
It had the quirk that subroutine arguments were passed with 
copy-in/copy-out, while common block variables were referenced 
directly.  When we wrote a gaussian elimination code, our problems 
would work either way for problems up to about 20x20.  But for 
larger problems, only the common block version would work.  The 
reason is that the temporary copy that was made by the compiler for 
the subroutine call exhausted all of the available memory.  However, 
that machine was replaced the following year by an IBM 370, and all 
arguments appeared to be passed by address with that fortran 
compiler.

$.02 -Ron Shepard
0
Reply ron-shepard (1197) 3/25/2012 7:57:51 AM

Ron Shepard <ron-shepard@nospam.comcast.net> wrote:

(snip)
> I took a numerical methods course in school, and we used the 
> school's IBM 1401 after hours to do our homework. This was in 1973.  
> It had the quirk that subroutine arguments were passed with 
> copy-in/copy-out, while common block variables were referenced 
> directly.  When we wrote a gaussian elimination code, our problems 
> would work either way for problems up to about 20x20.  But for 
> larger problems, only the common block version would work.  The 
> reason is that the temporary copy that was made by the compiler for 
> the subroutine call exhausted all of the available memory.  However, 
> that machine was replaced the following year by an IBM 370, and all 
> arguments appeared to be passed by address with that fortran 
> compiler.

The OS/360 and related compilers pass scalers by value result 
(that is, copy-in/copy-out) but arrays by reference. 

It takes to S/360 instructions to do an indirect reference, but
only one to a local copy. Assuming you reference a variable more
than a few times, it is faster with a copy. 

I hadn't known about the 1401 copy-in/out for arrays before, but
maybe by OS/360 they figured out that it took too much space.
Also, with a little luck the optimizer can avoid the extra load
while traversing an array.

-- glen
0
Reply gah (12258) 3/25/2012 8:41:25 AM

Nomen Nescio <nobody@dizum.com> wrote:

> nospam@see.signature (Richard Maine) wrote:
> 
> > Nomen Nescio <nobody@dizum.com> wrote:
> > 
> > > Thomas Koenig <tkoenig@netcologne.de> wrote:
> > > 
> > [example of effects of illegally defining a dummy argument with a
> > literal constant actual]
> > > 
> > > Shouldn't all FORTRAN compilers do this? Isn't FORTRAN call-by-address?
> > 
> > No. And no.
> 
> Oh!
> 
> > There is no specification about what Fortran compilers "should" do for
> > such illegal code. Ideally, they would diagnose the error, but you
> > probbaly won't find many that do. In practice, quite a few different
> > behaviors are observed.
> 
> Why is this illegal? I can see it's probably a mistake, but illegal?

I apologize for my sloppy use of terminology. Perhaps I can claim as an
excuse that it is an extremely common misuse.

The strictly proper terminology would be something more along the line
of "nonstandard" or "in violation of the Fortran standard". The Fortran
standard is a voluntary standard and violating it does not generally
constitute a violation of law. In cases where it might be a violation of
some law, the legal aspects would be outside the scope of the standard
itself.

But it is extremely common usage, perhaps because "legal" and "illegal"
are so much shorter terms than the long-winded precise phrases. While
I'll apologize for the imprecise usage, I don't think I'll be so
apologetic as to stop doing it, unless I happen to end up testifying in
an actual court of law on Fortran matters. (Unlikely, but not completely
implausible).

Back then to the question of standard conformance, in case you were
asking about that instead of about my sloppy terminology. Yes, the
standard makes it unambigously clear that the code is in violation of
the standard. I'll not bother to drag out citations from the various
versions of the standard, as I don't consider it a subtle enough to be
worth the bother.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/25/2012 3:23:23 PM

On 2012-03-25, Richard Maine <nospam@see.signature> wrote:

> The Fortran
> standard is a voluntary standard and violating it does not generally
> constitute a violation of law.

*snarf*

This was the sound of your quote hitting the gcc bugzilla quip file.
0
Reply tkoenig1 (168) 3/25/2012 5:10:34 PM

Ron Shepard <ron-shepard@NOSPAM.comcast.net> wrote:

> I had to modify code like this:
> 
>    real a(10,10)
>    ...
>    call sub2(a(1,5))
>    call sub1(a(1,5))
>    ...
> 
> where sub1() and sub2() have the declarations
> 
>    subroutine sub1(a)
>    real a
>    call sub2(a)
>    ...
>    subroutine sub2(a)
>    real a(10)
>    ...

I had some code of my own like that once. It wasn't intentional on my
part. Just plain an error, but one that was caught by neither the
compilers or my testing. The code worked fine on the machines I was
using at the time. That code was in production use for quite a long time
until a user reported a compilation failure (with an f95 compiler that
was doing some argument compatibility checking for calls to procedures
in the same source file). It didn't take any time at all for me to spot
the problem... or to fix it.

> Once located, the problem was relatively easy to fix:
> 
>    subroutine sub1(a)
>    real a(1)
>    call sub2(a)

Well, that's the f66-ish fix. Not strictly standard conforming, but at
least "closer." Although the trick of dimensioning dummy arguments with
size (1) was ubiquitous in f66 code, to the extent that some compilers
even special-cased it (for bounds checking), the standard did not
actually allow exceeding the declared bound of 1. It would have been a
legal implementation to copy in/out the 1 element specified by the dummy
declaration. It's just that copy-in/copy-out was much more rare for
arrays than for scalars.

The f77 fix is to use a(*) instead of a(1); then it is actually standard
conforming.

> > If you have POWER hardware you can use the XL/Fortran which I have no doubt
> > is very good.
> 
> When Apple Macintoshes used PowerPC hardware, IBM had a very nice 
> f90 compiler. This was before gfortran, so there were only a few 
> f90/f95 compilers available at that time.  I'm guessing they sold 
> more copies of that compiler than any other fortran, before or 
> since.  But when Apple announced in 2005 that it was going to switch 
> to Intel hardware, IBM immediately stopped supporting their 
> compiler.  I've never really forgiven IBM for that marketing 
> decision to abandon its users.  Even now, I still feel bitter about 
> that betrayal.

I won't say I'm bitter, but I do recall being dissapointed. I had a beta
copy of the IBM f90 compiler for OS X. My general impression was that,
in spite of the beta label, it seemed a more "solid" compiler than many
that were alleging to be production releases. (There's the old joke of
asking how vendor X, for various values of X, spells "beta"; the answer,
of course, is "1.0").

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/25/2012 5:58:45 PM

Fritz Wuehler <fritz@spamexpire-201203.rodent.frell.theremailer.net>
wrote:

> dpb <none@non.net> wrote:
> 
> > Why would you write a Standard that allowed the modification of a 
> > literal constant (in reality any non-definable)????   Amongst other
> > things it would mean legal code wouldn't even run on all machines (those
> > that put the constant in protected memory as an example that abort on
> > the attempt).  That would be just silly.
> 
> I think you're blurring pretty clear lines of what's a standard and what's an
> implementation detail and what's a user errror. If you aren't, then by
> logical extension what you're saying....

> Futhermore, according to you, there is no need for protected memory as you
> call it. The compiler catches everything and all programmers write error
> free code....

I think you are extrapolating what dpb said without justification. He
didn't say anything particularly close to what you claimed (in the part
I elided) was a "logical extension." Indeed, I think your own arguments
well illustrate why it is not a "logical extension."

DPB mentioned a particular case of an error. It is a case that the
standard does prohibit. It is even pretty close to cases that today's
compilers do, in fact, catch at compile time. (Add an explicit
interface, perhaps by putting the subroutine in a module, and add an
appropriate INTENT declaration; you'll find most, perhaps even all
current compilers then catch the error).

No, it is not "logical" to extend that to there being no such thing as a
runtime error.

> In my world the compiler doesn't catch anything but syntax errors

Then your world is not that of the Fortran standard. As of f90, the
Fortran standard has a list of things that the compiler is required to
be able to catch. Yes, the majority of them are syntax errors, but quite
a few are not. In practice, quality of implementation dictates that
compilers go beyond the minimum diagnostic capability required by the
standard. All of today's compilers do so.

No, that does not "logically extend" to catching all errors at compile
time. The standard doesn't require that, compilers don't do it, and it
isn't practical or even possible.

> > AFAIK since the actual development of the Standard, IBM has written
> > compliant compilers (with extensions, sure, but compliant) consistent w/
> > the Standard at the time.
> 
> That is to misunderstand the way IBM works. They have never cared about
> standards except what you can derive from their doc. Any standards
> "compliance" was if what they designed and implemented became accepted into
> another standard.

I have personally talked and worked at length with multiple IBM people
that were on the Fortran standards committee over a few decades. Based
on that extensive first-person experience, I'd say that the
misunderstanding here was... um... somewhere else.

Without exception, all the IBM people I have talked to said that IBM was
embarassed by their response to the f77 standard, which they were
apparently slow to fully embrace, and had resolved to learn a lesson
from that and not be caught the same way again.

IBM has been very active in the Fortran standards process. By "very
active", I don't mean just that a representative attended meetings; the
representatives have been vocal, participative, and influential. Janice
Shepard used to be jokingly (and in a friendly way) referred to as the
Czarina for the strong direction she gave as head of the interpretations
subgroup. Like people, corporations also do change (albeit sometimes
slowly). Generalizing "the way IBM works" over multiple decades is
pretty much bound to lead to misunderstanding. The way IBM works now is
not the same as the way it worked in, say, the 1970's.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/25/2012 6:27:49 PM

Thomas Koenig <tkoenig@netcologne.de> wrote:

> On 2012-03-25, Richard Maine <nospam@see.signature> wrote:
> 
> > The Fortran
> > standard is a voluntary standard and violating it does not generally
> > constitute a violation of law.
> 
> *snarf*
> 
> This was the sound of your quote hitting the gcc bugzilla quip file.

Just so you know... it isn't at all original to me. I did paraphrase it
from memory, but I'm sure my paraphrasing is pretty close to
explanations I have heard from.... well, I'm afraid I forget the exact
sources. I'll just say that it is part of the lore.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/25/2012 6:31:17 PM

glen herrmannsfeldt <gah@ugcs.caltech.edu> wrote:

> There is an old Fortran trick that looks like:
> 
>       DATA PI/0.0/
>       IF(PI.EQ.0.) PI=4.*ATAN(1.0)
> 
> Note that it will always give the same result, even if it is
> reentered between the IF and the assignment. It might make some
> extra calls to ATAN, but the result is still correct.

Implementation details and reentrancy aside, that was not legal (ok, ok,
make that "standard conforming" instead of "legal") as shown prior to
f90. I'm not denying that it would probably work in most - perhaps even
all - environments, but it was not standard conforming.

Without the SAVE attribute, PI becomes undefined on return. The
reference to it in the IF test is then non-conforming on the second
invocation of the procedure.

Please note, Glen, because I know you tend to look a lot at
implementation issues, I am definitely not talking about whether an
implementation would likely work. I am talking only about whether it
conforms to the Fortran standard. Prior to f90, it did not (unless the
procedure is invoked no more than once or unless there is a SAVE
statement that is not shown in the example). F90 added "initialization
implies save". Ignoring the continual debate about whether or not that
was a good thing for f90 to have aded, it does make code like this
standard conforming in f90, even though it was not so in f77 or f66.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/25/2012 9:44:22 PM

On 3/25/2012 11:27 AM, Richard Maine wrote:

>
> Without exception, all the IBM people I have talked to said that IBM was
> embarassed by their response to the f77 standard, which they were
> apparently slow to fully embrace, and had resolved to learn a lesson
> from that and not be caught the same way again.
>


I agree with everything you say except the timing.

During the 1980s, the IBM representative to the standards
committee was there only to try to stop the adoption of
Fortran 90. After Fortran 90, what you say seems more
accurate.


-- 
Walt Brainerd
0
Reply walt739 (18) 3/25/2012 11:49:47 PM

Walt Brainerd <walt@swcp.com> wrote:

> On 3/25/2012 11:27 AM, Richard Maine wrote: 
> >
> > Without exception, all the IBM people I have talked to said that IBM was
> > embarassed by their response to the f77 standard, which they were
> > apparently slow to fully embrace, and had resolved to learn a lesson
> > from that and not be caught the same way again.
> >
> I agree with everything you say except the timing.
> 
> During the 1980s, the IBM representative to the standards
> committee was there only to try to stop the adoption of
> Fortran 90. After Fortran 90, what you say seems more
> accurate.

Yes, I agree that's so. I even personally saw the tail end of that
resistance to the f90 standard.

At the first X3J3 meeting I attended, before I was a member, I recall
skimming a draft of the ISO varying string proposal. It was a pretty
quick skim, as I was just skimming someone else's copy during a break
(everything was still on paper then, I didn't have my own copy, and it
was pretty big). I was pointedly looking for an issue I had problems
with in some of my own code. When the meeting reconvened after the
break, I commented on the floor that it seemed to me there was an
obvious problem because the sample code was full of ALLOCATE statements,
but had no DEALLOCATEs anywhere. My comment didn't generate any further
discussion on the floor, but at the next break, the IBM rep took me
aside and suggested that if I wanted to torpedo the varying string
proposal, I should just be quiet about that problem until it was too
late to fix it. I'm not sure why he thought I would want to torpedo the
proposal in the first place. It sure made it clear to me, though, that
he was pursuing a (not very well hidden) agenda.

But once f90 was adopted, things changed. For whatever reason, it became
pretty evident that, f90 now being the standard formally adopted by both
ISO and ANSI, even though IBM had opposed the adoption, they sure as
heck were going to get serious about implementing it.

So I agree that IBM was working against adoption of f90 in the 80's. But
that did not translate into being laggards at implementing in in the
90's.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/26/2012 12:19:16 AM

Richard Maine <nospam@see.signature> wrote:

(snip, I wrote)
>> There is an old Fortran trick that looks like:
>> 
>>       DATA PI/0.0/
>>       IF(PI.EQ.0.) PI=4.*ATAN(1.0)
 
>> Note that it will always give the same result, even if it is
>> reentered between the IF and the assignment. It might make some
>> extra calls to ATAN, but the result is still correct.

> Implementation details and reentrancy aside, that was not legal (ok, ok,
> make that "standard conforming" instead of "legal") as shown prior to
> f90. I'm not denying that it would probably work in most - perhaps even
> all - environments, but it was not standard conforming.

> Without the SAVE attribute, PI becomes undefined on return. The
> reference to it in the IF test is then non-conforming on the second
> invocation of the procedure.

Most likely it was done back to the F66 days, before SAVE, but...

> Please note, Glen, because I know you tend to look a lot at
> implementation issues, I am definitely not talking about whether an
> implementation would likely work. I am talking only about whether it
> conforms to the Fortran standard. Prior to f90, it did not (unless the
> procedure is invoked no more than once or unless there is a SAVE
> statement that is not shown in the example). 

When I wrote that, I was thinking of it in MAIN. But yes, for F77
and if not in MAIN, it should have the SAVE attribute.

> F90 added "initialization implies save". Ignoring the continual 
> debate about whether or not that was a good thing for f90 to 
> have aded, it does make code like this standard conforming in f90, 
> even though it was not so in f77 or f66.

There is a complication in the whole discussion, related to the
way IBM uses the linker for S/360 and descendants. It is used both
to generate load modules for execution, and also subroutine libraries.
That is, unlike most linkers, it knows how to read its own output.

So, reentrancy, and the RENT attribute, applies both to subroutine
libraries and the final load module. As far as I understand, there
is nothing in the standard regarding reentrancy of MAIN. 

The IBM Fortran G and H compilers, and I believe also VS Fortran,
use static storage for all variables, and also for register save
areas, including the return address. They fail pretty bad if you
actually do manage to reenter a routine, as the previous return
address is lost.

-- glen
0
Reply gah (12258) 3/26/2012 12:42:36 AM

glen herrmannsfeldt <gah@ugcs.caltech.edu> wrote:

> In the case of constant actual arguments, there is one simple
> solution that isn't discussed much. That is to pass a modifyable
> copy of the constant.

Fortran has that. See the VALUE attribute (as of f2003). That's exactly
what that attribute does. It is true that VALUE is specified as part of
the procedure interface and thus the copying happens consistently for
all actual arguments that become associated with that dummy. They all
get a modifiable copy.

What Fortran doesn't have is an inconsistent version that sometimes
passes a copy and sometimes passes the original, depending on the
properties of the original. I always found that inconsistency confusing.
And I would find it even more confusing if I started to contemplate the
details, such as what would happen if the actual argument was a
variable, but was not legally modifiable for any of many reasons, some
of which could be subtle and could vary depending on context not evident
at compile time. I suspect that if you tried to hack such behavior into
Fortran, you'd end up with 3 cases. 1) The case where you pass a
variable and it gets modified, 2) The case where you pass something
obviously not modifiable and you get a copy, and 3) The case where you
have a variable that isn't legally modifiable, but it gets modified
anyway, so the code just breaks.

Perhaps case 3 can't come up in the PL/I that you like to draw analogies
from. But it sure could in Fortran. That's part of the problem of
leaning too heavily on such analogies. The differences between the
languages are deep enough that it is often hard to pull out isolated
features and translate them. If you try to hard, you end up with a lot
of special case rules to plaster over the differences.

Back when I did some programming in PL/I, this is exactly one of the
areas where I'd occasionally write buggy code. I'd be trying to modify
the original, but accidentally end up modifying only a local copy. I'm
sure that I was making naive user errors, but I'm also sure I wasn't the
only person doing so. I've become fond of making it quite explicit when
I am working with a local copy; the VALUE attribute does that.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/26/2012 9:29:35 PM

Richard Maine <nospam@see.signature> wrote:

(snip, I wrote)
>> In the case of constant actual arguments, there is one simple
>> solution that isn't discussed much. That is to pass a modifyable
>> copy of the constant.

(snip on VALUE attribute)

> What Fortran doesn't have is an inconsistent version that sometimes
> passes a copy and sometimes passes the original, depending on the
> properties of the original. I always found that inconsistency confusing.
> And I would find it even more confusing if I started to contemplate the
> details, such as what would happen if the actual argument was a
> variable, but was not legally modifiable for any of many reasons, some
> of which could be subtle and could vary depending on context not evident
> at compile time. 

I forget whether you are allowed to modify DO variables, but that
could be one case. 

> I suspect that if you tried to hack such behavior into
> Fortran, you'd end up with 3 cases. 1) The case where you pass a
> variable and it gets modified, 2) The case where you pass something
> obviously not modifiable and you get a copy, and 3) The case where you
> have a variable that isn't legally modifiable, but it gets modified
> anyway, so the code just breaks.

Maybe breaks less often, but yes it could still break.
I don't know how often actual modified constants happen in real code.
It can be darn hard to debug, though.

> Perhaps case 3 can't come up in the PL/I that you like to draw analogies
> from. But it sure could in Fortran. That's part of the problem of
> leaning too heavily on such analogies. The differences between the
> languages are deep enough that it is often hard to pull out isolated
> features and translate them. If you try to hard, you end up with a lot
> of special case rules to plaster over the differences.

It probably can, though I might not come up with a case. In the two
obvious cases, constants and expressions, it should be easy enough
to see. I learned about this PL/I feature about the same time I 
learned about Fortran constant modification. I don't remember any
actual modified constants in my programs, but I do remember the
VAX read-only constant being detected in one.

> Back when I did some programming in PL/I, this is exactly one of the
> areas where I'd occasionally write buggy code. I'd be trying to modify
> the original, but accidentally end up modifying only a local copy. I'm
> sure that I was making naive user errors, but I'm also sure I wasn't the
> only person doing so. I've become fond of making it quite explicit when
> I am working with a local copy; the VALUE attribute does that.

Copies are also made when the attributes don't agree. If you pass a
fixed point variable to a (known to the compiler) floating point dummy,
a modifiable temporary is created. Compilers I knew gave a warning
for that case, but it might be that it could be turned off.
If you pass a float binary(52) to a float binary(53), it should
also pass a copy, though the physical representation is likely
the same. That is one case that I am not sure about.

I suppose Fortran compilers could give warnings for all constant
arguments, but that would be tiring pretty fast. 

-- glen
0
Reply gah (12258) 3/26/2012 10:10:41 PM

glen herrmannsfeldt <gah@ugcs.caltech.edu> wrote:

> Richard Maine <nospam@see.signature> wrote:
> 
> (snip, I wrote)
> >> In the case of constant actual arguments, there is one simple
> >> solution that isn't discussed much. That is to pass a modifyable
> >> copy of the constant.

> > What Fortran doesn't have is an inconsistent version that sometimes
> > passes a copy and sometimes passes the original, depending on the
> > properties of the original. I always found that inconsistency confusing.
> > And I would find it even more confusing if I started to contemplate the
> > details, such as what would happen if the actual argument was a
> > variable, but was not legally modifiable for any of many reasons, some
> > of which could be subtle and could vary depending on context not evident
> > at compile time. 
> 
> I forget whether you are allowed to modify DO variables, but that
> could be one case. 

I was thinking of cases like

  call sub(x,x)
....
   subroutine sub(y,z)
      call sub2(y)
      write (*,*) z
   end
   
The dummy argument y is not modifiable in sub when sub is called as
shown, but it might be modifiable in other calls to sub. You have to
look outside of sub to know, and with separate compilation, you have to
look at code that might not yet even be written when sub is being
compiled.

> > Back when I did some programming in PL/I, this is exactly one of the
> > areas where I'd occasionally write buggy code. I'd be trying to modify
> > the original, but accidentally end up modifying only a local copy. I'm
> > sure that I was making naive user errors, but I'm also sure I wasn't the
> > only person doing so. I've become fond of making it quite explicit when
> > I am working with a local copy; the VALUE attribute does that.
> 
> Copies are also made when the attributes don't agree. If you pass a
> fixed point variable to a (known to the compiler) floating point dummy,
> a modifiable temporary is created. Compilers I knew gave a warning
> for that case, but it might be that it could be turned off.

Might well have been something like that hapening to me. We are talking,
let's see, about 40 years ago, so my memory of the details is pretty
vague. Plus I was a newbie at the time and I'm sure I made lots of
errors that I'd now consider "obvious".

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/26/2012 10:27:06 PM

Richard Maine <nospam@see.signature> wrote:

(snip)
> Might well have been something like that hapening to me. We are talking,
> let's see, about 40 years ago, so my memory of the details is pretty
> vague. Plus I was a newbie at the time and I'm sure I made lots of
> errors that I'd now consider "obvious".

I was remembering while reading the survey questions that it
will be 40 years in May since I started learning Fortran.
(One choice was 40 years or more.)

-- glen
0
Reply gah (12258) 3/27/2012 1:32:59 AM

On 3/26/2012 8:32 PM, glen herrmannsfeldt wrote:
> Richard Maine<nospam@see.signature>  wrote:
>
> (snip)
>> Might well have been something like that hapening to me. We are talking,
>> let's see, about 40 years ago, so my memory of the details is pretty
>> vague. Plus I was a newbie at the time and I'm sure I made lots of
>> errors that I'd now consider "obvious".
>
> I was remembering while reading the survey questions that it
> will be 40 years in May since I started learning Fortran.
> (One choice was 40 years or more.)

Ooooh, now you've gone and done it.  I had tried to forget it will be 
the 50th anniversary of my first introduction next fall...

I guess in at least some ways that's good... :)

--
0
Reply none1568 (6642) 3/27/2012 1:48:26 AM

dpb <none@non.net> wrote:

> On 3/26/2012 8:32 PM, glen herrmannsfeldt wrote:
> > Richard Maine<nospam@see.signature>  wrote:

> >> Might well have been something like that hapening to me. We are talking,
> >> let's see, about 40 years ago, so my memory of the details is pretty
> >> vague. Plus I was a newbie at the time and I'm sure I made lots of
> >> errors that I'd now consider "obvious".
> >
> > I was remembering while reading the survey questions that it
> > will be 40 years in May since I started learning Fortran.
> > (One choice was 40 years or more.)
> 
> Ooooh, now you've gone and done it.  I had tried to forget it will be
> the 50th anniversary of my first introduction next fall...

I've been doing Fortran for 44 years. The PL/I was a few years later
(and didn't last very long).

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/27/2012 2:49:37 AM

Um, let's see... yes 52.3 years in my case.


0
Reply tbwright1 (218) 3/27/2012 10:03:56 PM

52 Replies
64 Views

(page loaded in 0.382 seconds)


Reply: