forums.silverfrost.com Forum Index forums.silverfrost.com
Welcome to the Silverfrost forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Compiler problem dealing with arrays of .NET booleans

 
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support
View previous topic :: View next topic  
Author Message
alex21



Joined: 20 Apr 2011
Posts: 65
Location: Australia

PostPosted: Mon Apr 13, 2015 6:51 am    Post subject: Compiler problem dealing with arrays of .NET booleans Reply with quote

Hello,

This has had me stumped for a while but I am now fairly certain it is either a problem with the compiler itself or the way I have configured my FORTRAN project.

But basically I have an array of .NET bools, I then pass them into the FORTRAN code where it seems to simply interpret them incorrectly when reading them from the .NET array.

I believe this has something to do with the varying number of bytes a bool will use when in an array as opposed to where a bool represents a single member. This StackOverflow question delves into it a bit: Why in .NET System.Boolean takes 4 byte?

Anyway I have done up a sample application to demonstrate what I am talking about which you can download from here:
[LINK REMOVED - SEE POST FURTHER DOWN FOR UPDATED VERSION]

Here is the FORTRAN code:
Code:

SUBROUTINE MapData(inputData, outputData)
    IMPLICIT NONE
    ASSEMBLY_INTERFACE(NAME="MapData")

    ! Declare params
    INTEGER :: i
    LOGICAL, DIMENSION(1:12) :: logicalData
    OBJECT("DataLibrary.FortranData"), INTENT(IN) :: inputData
    OBJECT("DataLibrary.FortranData"), INTENT(OUT) :: outputData

    ! Perform input mapping
    logicalData = .FALSE.
    DO i = 1, 12
        logicalData = inputData%MonthlyValues(i-1)
    END DO

    ! Perform output mapping
    outputData = NEW@("DataLibrary.FortranData")
    DO i = 1, 12
        outputData%MonthlyValues(i-1) = logicalData(i)
    END DO
END SUBROUTINE MapData


So basically the input array MonthlyValues should end up being exactly the same as the output array MonthlyValues. However this is not the case as logicalData will be filled with an odd mutation of values which can actually change between application runs and even adding break points seem to affect this behaviour...

However here is a screenshot of some sample output:


This is kind of causing me headaches with a bit of a schedule to keep so if anyone could suggest a work around that would be awesome, are there some settings I should try changing in my project configuration.

Thanks,
Alex.


Last edited by alex21 on Tue Apr 14, 2015 12:35 am; edited 1 time in total
Back to top
View user's profile Send private message MSN Messenger
PaulLaidler
Site Admin


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

PostPosted: Mon Apr 13, 2015 7:57 am    Post subject: Reply with quote

I don't have a quick answer to your query but you may need to make sure that your .NET implementation is "locked down" in memory. .NET problems can arise because of garbage collection and the resulting movement of objects in memory. DBK_LINKx.exe is designed to handle this for the Fortran but sometimes the programmer must handle this on the .NET side. You might be able to track memory position changes to test this (e.g. using LOC in Fortran, off hand I don't remember how to do this in C# etc.).
Back to top
View user's profile Send private message
alex21



Joined: 20 Apr 2011
Posts: 65
Location: Australia

PostPosted: Mon Apr 13, 2015 9:17 am    Post subject: Reply with quote

Hmmm I will have a look into this but I don't think it is the problem as other value type and object arrays seem to work just fine. In the actual application I am working on its maps a few hundred arrays and the only ones that do not work are boolean arrays.

Could this possibly be due to the nature of how booleans are stored in .NET as described in the StackOverflow question I linked to?

Quote:

A bool is actually only 1 byte, but alignment may cause 4 bytes to be used on a 32-bit platform, or even 8 bytes on a 64-bit platform. For example, the Nullable<bool> (aka bool?) type uses a full 32 or 64 bits—depending on platform—even though it's comprised of just two bools. EDIT: As pointed out by Jon Skeet, padding for alignment isn't always present. As an example, an array of Nullable<bool>s takes only 2 bytes per object instead of 4 or 8.
Back to top
View user's profile Send private message MSN Messenger
PaulLaidler
Site Admin


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

PostPosted: Mon Apr 13, 2015 11:50 am    Post subject: Reply with quote

On the Fortran side you can have logical*1, *2 or *4 (the default).
The kinds are 1,2 and 3 respectively.
Back to top
View user's profile Send private message
jalih



Joined: 30 Jul 2012
Posts: 190

PostPosted: Mon Apr 13, 2015 12:04 pm    Post subject: Re: Compiler problem dealing with arrays of .NET booleans Reply with quote

alex21 wrote:
Here is the FORTRAN code:
Code:

SUBROUTINE MapData(inputData, outputData)
    IMPLICIT NONE
    ASSEMBLY_INTERFACE(NAME="MapData")

    ! Declare params
    INTEGER :: i
    LOGICAL, DIMENSION(1:12) :: logicalData
    OBJECT("DataLibrary.FortranData"), INTENT(IN) :: inputData
    OBJECT("DataLibrary.FortranData"), INTENT(OUT) :: outputData

    ! Perform input mapping
    logicalData = .FALSE.
    DO i = 1, 12
        logicalData = inputData%MonthlyValues(i-1)
    END DO

    ! Perform output mapping
    outputData = NEW@("DataLibrary.FortranData")
    DO i = 1, 12
        outputData%MonthlyValues(i-1) = logicalData(i)
    END DO
END SUBROUTINE MapData


So basically the input array MonthlyValues should end up being exactly the same as the output array MonthlyValues. However this is not the case as logicalData will be filled with an odd mutation of values which can actually change between application runs and even adding break points seem to affect this behaviour...

There is probably an error in input mapping part of your code. Your statement seems to be missing array index.

It should probably be written as :
Code:

    ! Perform input mapping
    DO i = 1, 12
        logicalData(i) = inputData%MonthlyValues(i-1)
    END DO
Back to top
View user's profile Send private message
jalih



Joined: 30 Jul 2012
Posts: 190

PostPosted: Mon Apr 13, 2015 7:39 pm    Post subject: Reply with quote

Hi, i just tested this...

FTN95 compiler can properly convert logical data type into .NET framework System.Boolean data type. However, when you try to assign array of logical into array of System.Boolean you get a "System.IndexOutOfRangeException" exception.

Easy solution is to always use .NET System.Boolean data type instead of the Fortran logical data type.

So, change:
Code:

logical, dimension(0:4) :: logicalData

to:
Code:

object("System.Boolean[]") logicalData
logicalData = new@("System.Boolean[]",5)

Hope this helps...
Back to top
View user's profile Send private message
alex21



Joined: 20 Apr 2011
Posts: 65
Location: Australia

PostPosted: Mon Apr 13, 2015 11:48 pm    Post subject: Re: Compiler problem dealing with arrays of .NET booleans Reply with quote

jalih wrote:
alex21 wrote:
Here is the FORTRAN code:
Code:

SUBROUTINE MapData(inputData, outputData)
    IMPLICIT NONE
    ASSEMBLY_INTERFACE(NAME="MapData")

    ! Declare params
    INTEGER :: i
    LOGICAL, DIMENSION(1:12) :: logicalData
    OBJECT("DataLibrary.FortranData"), INTENT(IN) :: inputData
    OBJECT("DataLibrary.FortranData"), INTENT(OUT) :: outputData

    ! Perform input mapping
    logicalData = .FALSE.
    DO i = 1, 12
        logicalData = inputData%MonthlyValues(i-1)
    END DO

    ! Perform output mapping
    outputData = NEW@("DataLibrary.FortranData")
    DO i = 1, 12
        outputData%MonthlyValues(i-1) = logicalData(i)
    END DO
END SUBROUTINE MapData


So basically the input array MonthlyValues should end up being exactly the same as the output array MonthlyValues. However this is not the case as logicalData will be filled with an odd mutation of values which can actually change between application runs and even adding break points seem to affect this behaviour...

There is probably an error in input mapping part of your code. Your statement seems to be missing array index.

It should probably be written as :
Code:

    ! Perform input mapping
    DO i = 1, 12
        logicalData(i) = inputData%MonthlyValues(i-1)
    END DO


Indeed I completely missed that in the sample! The sample actually works fine with that mistake fixed... I am now going through my application code looking for the same mistake because the sample was producing the same kind of weirdness.

EDIT: Actually the output produced is now correct however the values in FORTRAN are still incorrect..... I will make another post to show this soon.
Back to top
View user's profile Send private message MSN Messenger
alex21



Joined: 20 Apr 2011
Posts: 65
Location: Australia

PostPosted: Tue Apr 14, 2015 12:10 am    Post subject: Re: Reply with quote

PaulLaidler wrote:
On the Fortran side you can have logical*1, *2 or *4 (the default).
The kinds are 1,2 and 3 respectively.


Yeah I tried using different LOGICAL kinds however it does not seem to affect the output.
Back to top
View user's profile Send private message MSN Messenger
alex21



Joined: 20 Apr 2011
Posts: 65
Location: Australia

PostPosted: Tue Apr 14, 2015 12:13 am    Post subject: Re: Reply with quote

jalih wrote:
Hi, i just tested this...

FTN95 compiler can properly convert logical data type into .NET framework System.Boolean data type. However, when you try to assign array of logical into array of System.Boolean you get a "System.IndexOutOfRangeException" exception.

Easy solution is to always use .NET System.Boolean data type instead of the Fortran logical data type.

So, change:
Code:

logical, dimension(0:4) :: logicalData

to:
Code:

object("System.Boolean[]") logicalData
logicalData = new@("System.Boolean[]",5)

Hope this helps...


Due to the restrictions on me for the FORTRAN project I am working with, I am unable to use .NET types in the actual simulation code this is why it needs to be mapped to the variables that the simulation code is already using.

However I do not get a System.IndexOutOfRangeException because I am mapping one index at a time? and taking 1 from the .NET array index to account for zero-based vs counting number-based indexes.
Back to top
View user's profile Send private message MSN Messenger
alex21



Joined: 20 Apr 2011
Posts: 65
Location: Australia

PostPosted: Tue Apr 14, 2015 12:45 am    Post subject: Reply with quote

After a bit more messing around I am again starting to think this is a Silverfrost problem, as pointed out by jalih there was a mistake in my original sample application, after fixing this it actually started to behave a bit stranger.

Basically the values mapped into the FORTRAN are interpreted incorrectly in the FORTRAN, however if these values are not manipulated in the FORTRAN mapping them back to .NET objects actually yields the same values that were mapped into the FORTRAN.

So if you try to use the values in the FORTRAN code they seem to be interpreted like this:


Also here is the updated sample application and a snippet of the updated FORTRAN code for those who do not want to download it:
Code:

SUBROUTINE MapData(inputData, outputData)
    IMPLICIT NONE
    ASSEMBLY_INTERFACE(NAME="MapData")

    ! Declare params
    INTEGER :: i
    LOGICAL, DIMENSION(1:12) :: logicalData
    OBJECT("DataLibrary.FortranData"), INTENT(IN) :: inputData
    OBJECT("DataLibrary.FortranData"), INTENT(OUT) :: outputData

    ! Map .NET methods
    ASSEMBLY_EXTERNAL("DataLibrary.FortranData.LogMessage") :: LogMessage
    ASSEMBLY_EXTERNAL("DataLibrary.FortranData.LogBool") :: LogBool

    ! Perform input mapping
    logicalData = .FALSE.
    DO i = 1, 12
        logicalData(i) = inputData%MonthlyValues(i-1)
    END DO

    ! Display FORTRAN interpretation
    CALL LogMessage(inputData, "FORTRAN Values")
    DO i = 1, 12
        CALL LogBool(inputData, logicalData(i))
    END DO
    CALL LogMessage(inputData, "")

    ! Perform output mapping
    outputData = NEW@("DataLibrary.FortranData")
    DO i = 1, 12
        outputData%MonthlyValues(i-1) = logicalData(i)
    END DO
END SUBROUTINE MapData


Currently I am thinking I might simply wrap my boolean arrays in another array which converts them to integers of 0 or 1, as the FORTRAN seems to interpret these fine.

Thanks,
Alex.
Back to top
View user's profile Send private message MSN Messenger
alex21



Joined: 20 Apr 2011
Posts: 65
Location: Australia

PostPosted: Fri Jun 21, 2019 5:50 am    Post subject: Reply with quote

Also this is still an issue for me, the sample application I provided is no longer available but I am willing to build another to demonstrate this issue again for further investigation. I am 90% sure it is because booleans use a different number of bytes in a .NET array if certain conditions are met, whatever is converting byte representations between LOGICAL and System.Boolean needs to account for this.
Back to top
View user's profile Send private message MSN Messenger
John-Silver



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

PostPosted: Mon Jun 24, 2019 12:45 am    Post subject: Reply with quote

Quote:
, the sample application I provided is no longer available


??????
_________________
''Computers (HAL and MARVIN excepted) are incredibly rigid. They question nothing. Especially input data.Human beings are incredibly trusting of computers and don't check input data. Together cocking up even the simplest calculation ... Smile "
Back to top
View user's profile Send private message
alex21



Joined: 20 Apr 2011
Posts: 65
Location: Australia

PostPosted: Mon Jun 24, 2019 1:09 am    Post subject: Re: Reply with quote

John-Silver wrote:
Quote:
, the sample application I provided is no longer available


??????


It was available at the time of posting, but I did not maintain the dropbox account so it was deleted years ago. Robert has the latest example of some other issues in a sample I put on github more recently.
Back to top
View user's profile Send private message MSN Messenger
Display posts from previous:   
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group