Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

How to loop over derived type contents and print out as textfile

awa5114
Beginner
1,637 Views

I am new to Fortran. I would like to develop a subroutine which prints assigned variable information to a large derived type in Fortran 95. To simplify, lets say we have a derived type declaration and assigmnent as follows:

type SubjectType
        character(20) :: genre
        character(20) :: maindude
end type SubjectType
    
type BookType
        character(20) :: title
        character(20) :: author
        type(SubjectType) :: subject 

end type Booktype
    
type(Booktype) :: Book
    
Book%title = "Harry Potter"
Book%author = "JK Rowling"
Book%subject%genre = "Fantasy"
Book%subject%maindude = "Ron Weasley"

I would like the output of my program to be a text file as follows:

Book%title, Harry Potter 

Book%author, JK Rowling 

Book%subject%genre, Fantasy 

Book%subject%maindude, Ron Weasley

In order to achieve this I believe this is what I need to do:

 - Determine Number of fields in the derived type at each level. For instance number of fields in the `Booktype` would be 3. Number of fields in `Booktype%SubjectType` would be 2.
 - Find a way to relate the field 'number' to the name of the field (perhaps using pointers?)
 - loop over all the field numbers and get their names and values.

My question here is twofold. First is my approach correct/will it lead to the intended result? Second How do I accomplish step 1 of this procedure. Namely, how do I get the number of fields in the derived type at each level?

0 Kudos
15 Replies
Arjen_Markus
Honored Contributor I
1,637 Views

Fortran does not provide this kind of introspection. You will have to program this specifically, though a quick-and-dirty solution is to use list-directed output - you would get a dump of the contents without the labels.

A feature that may help you though is the user-defined derived type I/O. Look it up in the reference manual. It may not prevent you from having to program it specifically for each derived type, but it does help in using it.

0 Kudos
mecej4
Honored Contributor III
1,637 Views

Just as you cannot ascertain the number of components in a user-defined type, you cannot ascertain the names of the components. Even for intrinsic type variables, you cannot find their names. In fact, unless you compile with debug-symbols requested, there are no variable names in an OBJ, EXE or DLL after compilation.

Take a look at the Namelist feature of old Fortran; it may do some of the things that you want, but it would be best to rethink your objectives in the light of what language features are available.

0 Kudos
awa5114
Beginner
1,637 Views

@Arjen Markus

I am trying to work the scripts in the following page https://software.intel.com/en-us/node/678729  to learn more about what you are saying

However not a single one of these examples will compile properly. I am getting  "Error in opening the compiled module file. Check INCLUDE PATHS". How do I make sure the declares modules are accessible by the main program?

@mecej4

How does one compile with debug symbols requested?

Regarding Namelist, I found the following definition online:

Namelist: specified a list of variables that can be referred to by one name for the purpose of performing input/output

However the user still needs to specify that list. I cannot specify the list. The types are enormous (over 200 fields not including subtypes). I need something more efficient. 

Unfortunately I need precisely these sorts of features. I am working with a large 3rd party program with several software versions built-in to the Intel Visual Fortran compiler. Derived types contain hundreds of fields. What I am trying to do is run similar models with different configurations to see how one configuation maps into the other. (Release vs Debug)

0 Kudos
Arjen_Markus
Honored Contributor I
1,637 Views

I tried one example program and it compiles without any problems. I simply opened a command prompt window and ran "ifort file.f90"

0 Kudos
awa5114
Beginner
1,637 Views

Ah... I cannot use the command prompt because I don't have administrative privileges on my computer. I am copying and pasting these into Microsoft Visual Studio. How would I get that to work?

0 Kudos
Arjen_Markus
Honored Contributor I
1,637 Views

Hm, are you sure you need _formatted_ I/O? You can dump a derived type to disk and read it back in without knowing its contents using unformatted, i.e. binary, I/O.

The only problem is that components with pointer or allocatable attributes hinder this simple scheme

0 Kudos
awa5114
Beginner
1,637 Views

How do you mean "dump a derived type to disk and read it back in"?

0 Kudos
Arjen_Markus
Honored Contributor I
1,637 Views

Well, using the command prompt is a quick-an-dirty way of running the compiler. You can also use Visual Studio for one-file projects. I find it a bit of overkill, but you seem to be limited that. That requires a bit of care.

Dumping a derived type:

type(my_type) :: var, var2

open( 10, file = 'dump.out', access = 'stream' )

write( 10 ) var

close( 10 )

open( 10, file = 'dump.out', access = 'stream' )

read( 10 ) var2

Just a simple example :)

 

0 Kudos
awa5114
Beginner
1,637 Views

@Arjen Markus

That is useful but quite crude. It is difficult to see the fact that the values "Ron Weasley" and "Fantasy" are really subtypes. In the dump file they appear to be at the same level as "Harry Potter" and "JK Rowling".

Regarding the names of the fields themselves can a similar dump be created? Because then I wouldn't necessarily care about the hierarchy so much anymore...

0 Kudos
Arjen_Markus
Honored Contributor I
1,637 Views

meej4 suggested using a namelist a possible solution. It does in fact print out the names of the components, but you will have to decide for yourself whether they are what you want. They are very flexible in one way, but rigid in another.

0 Kudos
awa5114
Beginner
1,637 Views

@Arjen Markus

Allright... yes. Namelist is good. It prints out both the labels and values to the output file. This is very close to what I need. Now what I would like to do is process that output prior to outputting to file. currently what I have is 

program main
    character(500) :: NamelistString
    type SubjectType
            character(20) :: genre
            character(20) :: maindude
    end type SubjectType
    
    type BookType
            character(20) :: title
            character(20) :: author
            type(SubjectType) :: subject 

    end type Booktype
    
    type(Booktype) :: Book
    
    Book%title = "Harry Potter"
    Book%author = "JK Rowling"
    Book%subject%genre = "Fantasy"
    Book%subject%maindude = "Ron Weasley"
    
    !open(10, file='dump.out', access = 'stream')
    !write(10) Book
    
    open(11, file = 'namelist.txt')
    
    namelist /mynamelist/ Book
    write(11, nml = mynamelist)
end program main

Which outputs the following to namelist.txt:

 &MYNAMELIST
 BOOK%TITLE   = Harry Potter        ,
 BOOK%AUTHOR  = JK Rowling          ,
 BOOK%SUBJECT%GENRE   = Fantasy             ,
 BOOK%SUBJECT%MAINDUDE        = Ron Weasley         
 /

This is very good but could use some cleanup, since the output is more like a CSV type format. I need to get rid of the preliminary text, those single quotes, that forward slash at the end, intermediate spaces and replace that equals sign with a comma.

I am assuming the first step would be to write the namelist output to a variable instead of directly to a file. I have set up a string variable called NamelistString and tried the following:

write(NamelistString, nml = mynamelist)

Although this compiles OK the program does not run to completion and aborts. What might be the root cause of this? Am I writing it to the variable wrong?

0 Kudos
FortranFan
Honored Contributor II
1,637 Views

Amine A. wrote:

... What might be the root cause of this? Am I writing it to the variable wrong?

You may note you are asking basic Fortran questions that are well-covered in books.  You may want to first review sources recommended here:

https://software.intel.com/en-us/blogs/2013/12/30/doctor-fortran-in-its-a-modern-fortran-world

and then come back with specific questions or issues.

If you do look into the sources at the above-mentioned Dr Fortran blog, review the section on "defined IO" that works with derived types in Fortran.  This is the feature that will allow you to do the things you state in this thread.

 

0 Kudos
awa5114
Beginner
1,637 Views

@FortranFan

Thanks. I will hit the books at some point. For now I am in an office context/environment so I'm more looking for quick and dirty (non-academic) solutions. I do appreciate the intent of your post, however.

0 Kudos
mecej4
Honored Contributor III
1,637 Views

Amine A. wrote:
 I cannot use the command prompt because I don't have administrative privileges on my computer.

On typical Windows PCs, opening a command prompt does not require privilege escalation. The CMD shortcut does have an optional "run as administrator" right-click option, but I use that option infrequently, and only when necessary.

0 Kudos
FortranFan
Honored Contributor II
1,637 Views

Amine A. wrote:

.. I'm more looking for quick and dirty (non-academic) solutions ..

@Amine A.,

If "quick and dirty" suffices for now, then

  1. simply try list-directed input/output of your derived types and see how far you can get; in the spirit of "quick and dirty", please stay away from components of ALLOCATABLE or POINTER attributes in the derived type though.  https://software.intel.com/en-us/fortran-compiler-18.0-developer-guide-and-reference-forms-of-i/o-statements
  2. If 1. above is insufficient, use the readily available material - all online, only a web-browser required! - and follow the examples to fit your needs: https://software.intel.com/en-us/fortran-compiler-18.0-developer-guide-and-reference-user-defined-derived-type-i/o

Good luck,

0 Kudos
Reply