Greetings,
I am trying to understand the SAVE attribute behavior a little bit better in the classical code bases. Basically, my confusion revolves around the scope of reverse communication.
To start with a simple and small example, we have a code that has 3 functions (apologies for not making a full program as I still don’t know what the best practice is). Here is something that I will fake by parroting what I am seeing.
subroutine entryfunc(a, b, c)
integer stage
save stage
stage = 0
if (stage .eq. 0) then
! inner1 sets stage to = 1
call inner1(a, b, c, stage)
! exit for reverse communication to do something with a,b,c
go to 100
else
! Second call to entryfunc should come here.
! because we set stage = 1
call inner2(a, b, c, stage)
! exit again for rev. com.
go to 100
endif
100 continue
return
end subroutine
This is basically the minimalized problem I have with a larger code base.
That is confusing me about ARPACK. This function repeatedly exits back to Python to compute matvecs and other necessary information. But saved variables should have lost their scope, in my ignorant opinion. However since this keeps on entering to the same program, something should be setting the state of all functions from scratch. Otherwise reverse communication would be pointless.
On the other hand, these classical software typically called by programs that are often named driver.f
or similar. Hence I suppose they hold the entire scope intact while repeatedly calling the bespoke entryfunc
. Because then entryfunc
and everything connected to it become a nested function call (I think!)
My curiosity is about when we interface from Python through f2py do we also acquire the entire scope just like a driver program such that everything else retains its value.
These lines are examples how we call the problem inside a while
loop when we solve ARPACK problems
The answer will determine whether I have to carry all saved variables of all subfunctions during reverse communication and then reset them in the next call or not since I rewrote all in C and I don’t have any driver function requirement but I just want to make sure I am not getting caught in another historical gotcha.
Concrete example
dgetv0 is called by various functions but you can follow the most obvious chain. dnaupd -> dnaup2 -> dgetv0
generates a random vector to start with then exits three levels up.
Now I know we have issues with the lack of control of randomization and we reported it years ago that did not lead to any fruition e.g., Arpack random generator cannot be seeded · Issue #218 · opencollab/arpack-ng · GitHub So that’s a separate concern but I just wanted to use an example. Because this is how the same seed is used across a full run. Otherwise it would generate the same random vectors all the time. So this gives me the impression that Python call is also a driver with its while loop.
This is one of the issues I fixed by yanking out the randomization parts to a separate level independent from the original ARPACK code so we can properly seed with modern NumPy Random C-API. But I just need to make sure that I understood the fortran parts correctly.
As always, thank you for your help.