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)
|