- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have a large set of code that has "global" arrays in it. These arrays are arguments to many different SUBROUTINEs in the code. I would like to create a module (or two or three) which make these global arrays PRIVATE but provide accessors to these arrays. As right-hand side (RHS) arguments it is simple to create something in the module like
MODULE GLB INTEGER, PARAMETER :: F = SELECTED_REAL_KIND(12, 100) REAL (KIND = F), DIMENSION(:, :, :), ALLOCATABLE, PRIVATE :: A_LOCAL CONTAINS REAL (KIND = F) FUNCTION A(I, J, K) INTEGER, INTENT(IN) :: I, J, K IF (ALLOCATED(A_LOCAL)) THEN A = A_LOCAL(I, J, K) ELSE A = 0.0_F END IF END FUNCTION A END MODULE GLB
so that all existing RHS references to the A array in the code would be replaced by
USE GLB, ONLY : A
without changing any code lines. Might there be a way to replace left-hand side (LHS) uses of the array A, as in
A(I, J, K) = 42.0_F
with some construct, sort of like the VB Property Let construct with multiple input arguments?
The answer here can easily be no, in which case I will need to track down all LHS uses and replace them with calls to a SUBROUTINE within MODULE GLB like
SUBROUTINE SET_A(I, J, K, A_VALUE) INTEGER, INTENT(IN) ::: I, J, K REAL (KIND = F), INTENT(IN) :: A_VALUE IF (.NOT. ALLOCATED(A_LOCAL)) THEN ALLOCATE(A_LOCAL(I_SIZE, J_SIZE, K_SIZE) A_LOCAL = 0.0_F END IF A_LOCAL(I, J, K) = A_VALUE END SUBROUTINE
Thanks in advance.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The answer to the question, which asks about "Fortran", is "Yes". But, there's a "but".
Fortran 2008 permits a function reference with a data pointer result to appear on the left hand side of an assignment statement. For example:
MODULE m IMPLICIT NONE INTEGER, TARGET :: local_a(4) PUBLIC :: A PUBLIC :: B CONTAINS FUNCTION A(i) INTEGER, INTENT(IN) :: i INTEGER, POINTER :: A ! Remap the index just for giggles. A => local_a(MOD(i,4)+1) END FUNCTION A SUBROUTINE B PRINT "(*(I0,:,','))", local_a END SUBROUTINE B END MODULE m PROGRAM ptr_left_hand_side USE m IMPLICIT NONE INTEGER :: i DO i = 1, 4 A(i) = i END DO CALL B END PROGRAM ptr_left_hand_side
The above would be expected to print 4,1,2,3.
The "but" is that ifort current release and current beta don't support this Fortran 2008 feature.
:(
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If you intend on making the array private, then shouldn't you require an GET_A function?
I know you do not want to rewrite the rhs (or lhs).
What is the reasoning why you do not want A public?
Is it to protect against index out of range? (and return 0.0 when so). Note that your SET_A subroutine does not check/protect for index out of range.
Is it to auto allocate? Allocation can be done in a once only init routine.
Or, at the top of each of your routines that access A (and other such routines)
CALL YourINIT(A, iMAX, jMAX, kMAX)
When A is not allocated, it is allocated to those sizes and initialized.
When A is allocated AND any extents are less than those specified, A gets reshaped.
When A is allocated AND all extents are .GE. the maxes do nothing.
This will permit the lhs and rhs in source to remain the same, yet provide some protection (assuming you know the max values to be subsequently used).
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The reasoning behind this effort lies in several factors:
1) There are at least one hundred allocatable arrays currently allocated / deallocated in a driver routine which are then passed down the line to other routines Yes, the idea was to use an initialize routine for these arrays and index them appropriately without bounds checking. This is done currently by making most access DO loop driven with the indices being between bounds. As an example, one called routine currently has 400+ arguments.
2) The need for some arrays extends beyond routines which currently have them as arguments. Rather than tacking more arguments onto these routines, the use of accessors could satisfy the need. Again, there is considerable legacy in using the code, but code development has become unwieldy with the current structure.
3) The use of a few, but not all, of these arrays is "update". Often the update of these arrays in the design is part of other code segments. For example, there is a "model geometry" set of arrays. Many of these, once initialized, never change. Others, although they have the characteristics of model geometry, will change at every time step due to certain criteria. It is this second set of data that is the concern here. The idea of code maintenance and development was based on keeping the arrays PRIVATE and manipulating using accessors, much like a traditional class structure. That way I can be assured that data is changing only when I want it to change (specific calls). This data integrity is currently managed with INTENT clauses in the routines, but the largest routines mostly have INTENT(INOUT) which gives me little help in determining where data is changing.
4) Much of the use of the arrays is encased presently in fixed source form. Prefixing each array name with "GET_" will most likely cause a great deal more continuation lines (there are a good deal already), making the code even more unreadable.
I am assuming the LHS use of the arrays will require building SET_A routines. I think this will be a small price to pay in the refactoring and general cleanup of the code. I will of course need to be very specific in the documentation of "A" and its relatives.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The answer to the question, which asks about "Fortran", is "Yes". But, there's a "but".
Fortran 2008 permits a function reference with a data pointer result to appear on the left hand side of an assignment statement. For example:
MODULE m IMPLICIT NONE INTEGER, TARGET :: local_a(4) PUBLIC :: A PUBLIC :: B CONTAINS FUNCTION A(i) INTEGER, INTENT(IN) :: i INTEGER, POINTER :: A ! Remap the index just for giggles. A => local_a(MOD(i,4)+1) END FUNCTION A SUBROUTINE B PRINT "(*(I0,:,','))", local_a END SUBROUTINE B END MODULE m PROGRAM ptr_left_hand_side USE m IMPLICIT NONE INTEGER :: i DO i = 1, 4 A(i) = i END DO CALL B END PROGRAM ptr_left_hand_side
The above would be expected to print 4,1,2,3.
The "but" is that ifort current release and current beta don't support this Fortran 2008 feature.
:(
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks, IanH.
I had thought there might be a way, but I was focused on "defined assignment" which was not yielding anything. It is unfortunate that this feature has yet to be implemented, but I will make use of the CALL SET_A syntax. At present I am only maneuvering through a small subset of the arrays which should make this development effort approachable.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If you can arrange for 'A' always to have been initialized when it is used you could declare it as 'public, protected'. That will give you read-only access without having to create 'get' accessors. Of course that doesn't help with 'set'. Just a thought.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page