forums.silverfrost.com
Welcome to the Silverfrost forums

Author Message
Kenneth_Smith

Joined: 18 May 2012
Posts: 190
Location: Glasgow, Scotland.

Posted: Fri Aug 25, 2017 1:15 pm    Post subject: Query setting whole array to single value

In the program below, there is a call back function line_to_gnd_cb.

Part of the calculation involves setting all the values of the complex array I_012 to the same value. I've implemented this three different ways.

 Code: do i = 1, 3       i_012(i) = v1_init/ ( sum(z) + zf )     end do

 Code: z_local = v1_init/ ( sum(z) + zf )     i_012 = z_local

 Code: i_012 = v1_init/ ( sum(z) + zf )

The third implementation causes the program to crash and I'm curious to know if this is a bug or non standard code?

Thanks
Ken
Kenneth_Smith

Joined: 18 May 2012
Posts: 190
Location: Glasgow, Scotland.

Posted: Fri Aug 25, 2017 1:17 pm    Post subject:

Main code

 Code: module fault implicit none private public :: build_gui complex(kind=2) :: z(1:3) real(kind=2)    :: z1_r = 0.01d0, z1_i = 1.d0, z2_r = 0.01d0, z2_i = 1.d0, z0_r = 0.01d0, z0_i = 1.d0 complex(kind=2) :: v1_init real(kind=2)    :: v1_init_r = 1.d0, v1_init_i = 0.d0 complex(kind=2) :: zf real(kind=2)    :: zf_r = 0.d0, zf_i = 0.d0 complex(kind=2) :: i_abc(1:3), i_012(1:3), v_abc(1:3), v_012(1:3) complex(kind=2) :: i_fault contains   subroutine build_gui   include   integer i    i = update_z_cb()    i = update_v1_init_cb()    i = update_zf_cb()    i = winio@('%ws&','Input data')    i = winio@('%nl%3.6ob&')    i = winio@('%ws&','Seq.')    i = winio@('%cb&')    i = winio@('%ws&','Re')    i = winio@('%cb&')    i = winio@('%ws&','Im')    i = winio@('%cb&')    i = winio@('%ws&','Z1 [pu]')    i = winio@('%cb&')    i = winio@('%^rf&', z1_r, update_z_cb)    i = winio@('%cb&')    i = winio@('%^rf&', z1_i, update_z_cb)    i = winio@('%cb&')    i = winio@('%ws&','Z2 [pu]')    i = winio@('%cb&')    i = winio@('%^rf&', z2_r, update_z_cb)    i = winio@('%cb&')    i = winio@('%^rf&', z2_i, update_z_cb)    i = winio@('%cb&')    i = winio@('%ws&','Z0 [pu]')    i = winio@('%cb&')    i = winio@('%^rf&', z0_r, update_z_cb)    i = winio@('%cb&')    i = winio@('%^rf&', z0_i, update_z_cb)    i = winio@('%cb&')    i = winio@('%ws&','V1 [pu]')    i = winio@('%cb&')    i = winio@('%^rf&', v1_init_r, update_v1_init_cb)    i = winio@('%cb&')    i = winio@('%^rf&', v1_init_i, update_v1_init_cb)    i = winio@('%cb&')    i = winio@('%ws&','Zf [pu]')    i = winio@('%cb&')    i = winio@('%^rf&', zf_r, update_zf_cb)    i = winio@('%cb&')    i = winio@('%^rf&', zf_i, update_zf_cb)    i = winio@('%cb&')        i = winio@('%nl%^tt[L to G]',line_to_gnd_cb)         end subroutine build_gui   integer function update_z_cb()     z(1) = cmplx(z0_r,z0_i)     z(2) = cmplx(z1_r,z1_i)     z(3) = cmplx(z2_r,z2_i)     update_z_cb=1   end function update_z_cb   integer function update_v1_init_cb()     v1_init = cmplx(v1_init_r,v1_init_i)     update_v1_init_cb = 1   end function update_v1_init_cb     integer function update_zf_cb()     zf = cmplx(zf_r, zf_i)     update_zf_cb = 1   end function update_zf_cb   integer function line_to_gnd_cb()   integer i   complex(kind=2) z_local     !   This works:-        do i = 1, 3       i_012(i) = v1_init/ ( sum(z) + zf )     end do !   This works:- !    z_local = v1_init/ ( sum(z) + zf ) !    i_012 = z_local !   This does not work:-    !    i_012 = v1_init/ ( sum(z) + zf )     i_fault = sum(i_012)         write(6,*) abs(i_fault)     line_to_gnd_cb = 1   end function line_to_gnd_cb     end module fault program fault_analysis use fault implicit none   call build_gui end program fault_analysis
PaulLaidler

Joined: 21 Feb 2005
Posts: 5599
Location: Salford, UK

 Posted: Fri Aug 25, 2017 9:35 pm    Post subject: At first sight the code looks OK so the compiler has probably failed to implement the code correctly. The different approaches are roughly equivalent and each one calculates sum(z) three times when once would be enough. If you were to calculate and save sum(z) first, then you would probably be OK either way.
Kenneth_Smith

Joined: 18 May 2012
Posts: 190
Location: Glasgow, Scotland.

 Posted: Fri Aug 25, 2017 10:42 pm    Post subject: Thanks Paul, Interesting to know that the 3rd method actually calculates the SUM term three times - I had not appreciated that. And the third method was the one I implemented first - caught out trying to do some quick and dirty coding - again Ken
PaulLaidler

Joined: 21 Feb 2005
Posts: 5599
Location: Salford, UK

Posted: Sat Aug 26, 2017 7:12 am    Post subject:

This turns out to be a bug relating to COMPLEX arrays and SUM. I have made a note that it needs fixing.

Here is a cut down demonstration...

 Code: integer,parameter::k=2 complex(kind=k) :: zz(1:3),z(1:3) z = 1.0d0 zz = sum(z) print*, zz end
LitusSaxonicum

Joined: 23 Aug 2005
Posts: 1878
Location: Yateley, Hants, UK

 Posted: Sat Aug 26, 2017 12:30 pm    Post subject: I found it interesting, but unsurprising, that SUM(Z) is computed three times. Presumably it is only calculated once if /OPTIMISE is used, because (from FTN95.CHM) there is: "Loop invariant motion. This means that any calculations which are constant with respect to the loop variable may be moved, so that they are performed once and for all on entry to the loop." "Elimination of common subexpressions across statements." My questions are 'Does the right hand side (in this case) count as a common subexpression?', 'Is an assignment of an expression to an array an implicit loop?' and 'Does including a function like SUM inhibit the optimisation?' Notwithstanding the advice that manual precalculation of common subexpressions is unnecessary, I have always done it when I have recognised the case. Hence, where FTN95.CHM states: "In most cases, common sub-expressions are evaluated only once. Thus the following code could not be improved by the prior assignment TEMP=X*Y: Z = (X*Y)/(1.0+X*Y)" I would probably precalculate X*Y out of force of habit (on the advice of Kreitzberg & Schneiderman, 1972, which predates a lot of optimising compilers). Paul's suggestion of precalculation goes against the FTN95.CHM advice, but would be rational if the advice on common subexpressions in FTN95.CHM observed that the process is hampered if functions are involved - again, I think it is fair to say that it should be possible to work out which are safe and which are not, so RANDOM@ is clearly not safe, SUM ought to be. I can't imagine that one feels the benefit of summing three variables once instead of three times, but in the general case, my habit is likely to prove advantageous, and only very slightly worse than achieved by the optimiser. Or am I wrong? As a postscript, it seems to me that common subexpression replacement is so obvious and side-effect free that perhaps it should be done as a matter of course and not just when /OPT is used? Eddie
PaulLaidler

Joined: 21 Feb 2005
Posts: 5599
Location: Salford, UK

 Posted: Mon Aug 28, 2017 8:24 am    Post subject: The above cut-down demo program also fails when /opt is applied so evidently SUM is not optimised (at least in this situation). The documentation states that calculations "may" be removed. This is not guaranteed. As to what counts as a common subexpression, I don't have any further information above that found in the documentation but here are some of my random thoughts on optimisation. 1) It is rarely an issue that one needs to be concerned about. 2) Run times are not just dependent on code efficiency (amount of RAM, type of video driver, antivirus software, connection to the Internet, type and speed of the CPU). 3) Personally I aim to write efficient code and to avoid depending on the optimiser but this is, more often than not, a matter of professional pride; but it does tend to make the code easier to read and maintain. 4) When the speed of execution becomes critical... a) FTN95 has a /TIMING option that provides information on the CPU time spent in each subroutine (so you can see where best to focus on optimising the code). b) The next release of 64 bit FTN95 will have a /PROFILE option that reports how many times each line is executed (again to show where best to optimise). c) The FTN95 option /EXPLIST provides the assembler code so you can work out how the compiler has translated your code. If you are really desperate you can write sections of the code in assembler. I hope that this helps without raising further questions.
LitusSaxonicum

Joined: 23 Aug 2005
Posts: 1878
Location: Yateley, Hants, UK

 Posted: Mon Aug 28, 2017 8:46 am    Post subject: Paul, That's an excellent explanation, for which I am grateful. Eddie
John-Silver

Joined: 30 Jul 2013
Posts: 959
Location: Aerospace Valley

 Posted: Mon Aug 28, 2017 10:40 pm    Post subject: The best optimiser is the idiot on the end of the keyboard. Simply becasue he knows what he has done !
 Display posts from previous: All Posts1 Day7 Days2 Weeks1 Month3 Months6 Months1 Year Oldest FirstNewest First
 All times are GMT + 1 Hour Page 1 of 1