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%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?
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.
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.
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?
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)
I tried one example program and it compiles without any problems. I simply opened a command prompt window and ran "ifort file.f90"
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?
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
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 :)
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...
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.
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:
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?
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:
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.
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.
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.
Amine A. wrote:
.. I'm more looking for quick and dirty (non-academic) solutions ..
If "quick and dirty" suffices for now, then