0

I need to count number of lines in each block and count number of blocks in order to read it properly afterwards. Can anybody suggest a sample piece of code in Fortran?

My input file goes like this:

# Section 1 at 50%    (Name of the block and its number and value)

1 2 3                 (Three numbers in line with random number of lines)

...

1 2 3

# Section 2 at 100% (And then again Name of the block)

1 2 3... 

and so on.

The code goes below. It works fine with 1 set of data, but when it meets " # " again it just stops providing data only about one section. Can not jump to another section:

  integer IS, NOSEC, count

    double precision SPAN

    character(LEN=100):: NAME, NAME2, AT

    real whatever

 101   read (10,*,iostat=ios) NAME, NAME2, IS, AT, SPAN

       if (ios/=0) go to 200

       write(6,*) IS, SPAN

       count = 0

  102         read(10,*,iostat=ios) whatever

       if (ios/=0) go to 101

       count = count + 1

       write(6,*) whatever

       go to 102

200      write(6,*) 'Section span =', SPAN

So the first loop (101) suppose to read parameters of the Block and second (102) counts the number of lines in block with 'ncount' as the only parameter which is needed. However, when after 102 it suppose to jump back to 101 to start a new block, it just goes to 200 instead (printing results of the operation), which means it couldn't read the data about second block.

Slava_le
  • 13
  • 3
  • 3
    Welcome. Be sure to take the [tour] and read [ask]. Have you tried anything? Which problems did you encounter when you tried to solve this problem yourself? Show us code you have and any problems you have with that code. – Vladimir F Героям слава Oct 03 '17 at 17:36
  • character(LEN=100):: NAME, NAME2, AT real whatever, span open (10, file='RK1_profile.curve') 101 read (10,*) NAME, NAME2, IS, AT, SPAN if (ios/=0) go to 200 write(6,*) SPAN(IS), IS count = 1 102 read(10,*,iostat=ios) whatever count = count + 1 write(6,*) whatever go to 102 if (ios/=0) exit 200 close(10) – Slava_le Oct 04 '17 at 11:52
  • can not edit code in this comment window... – Slava_le Oct 04 '17 at 11:52
  • Use the [edit] below the post to edit your question. – Vladimir F Героям слава Oct 04 '17 at 12:19
  • please have a look at the code, thanks – Slava_le Oct 04 '17 at 13:45
  • Show us also how are your variables declared. And please show the actual code. Variable named `whatever` looks suspicious. Is it really named like that? – Vladimir F Героям слава Oct 04 '17 at 13:49
  • It is really named like that (found in https://stackoverflow.com/questions/26066854/finding-number-of-lines-of-a-data-file-using-command-line) – Slava_le Oct 04 '17 at 13:56
  • Just for clarity: (1) do the comment lines start with either `'#Section` or `'# Section` (i.e., one space may exist before `Section`)? (2) blank lines may also exist between comment lines and data lines? (3) no blank lines between concecutive data lines? – roygvib Oct 04 '17 at 14:55
  • I would highly encourage you to strike "go to" from your programing vocabulary. Look up "do while" , "exit" and "cycle" and try re-doing this. Note also your attempt to read a mix of strings and numbers may not fail (as you seem to expect) when encountering a line with just numbers -- it will simply read the numbers as strings. – agentp Oct 04 '17 at 16:57
  • to roygvib: (1) The comment line goes like: # Section (the space between # and Section). But it is not just a comment, it contains important data (e.g. No of Section). (2) between data line and next comment line there is a blank line (not always though) (3) between concecutive data lines there's no blank lines. – Slava_le Oct 04 '17 at 17:27

1 Answers1

0

Let's say your file contains two valid types of lines:

  • Block headers which begin with '#, and
  • Data lines which begin with a digit 0 through 9

Let's add further conditions:

  • Leading whitespace is ignored,
  • Lines which don't match the first two patterns are considered comments and are ignored
  • Comment lines do not terminate a block; blocks are only terminated when a new block is found or the end of the file is reached,
  • Data lines must follow a block header (the first non-comment line in a file must be a block header),
  • Blocks may be empty, and
  • Files may contain no blocks

You want to know the number of blocks and how many data lines are in each block but you don't know how many blocks there might be. A simple dynamic data structure will help with record-keeping. The number of blocks may be counted with just an integer, but a singly-linked list with nodes containing a block ID, a data line count, and a pointer to the next node will gracefully handle an arbitrarily large blob of data. Create a head node with ID = 0, a data line count of 0, and the pointer nullify()'d.

The Fortran Wiki has a pile of references on singly-linked lists: http://fortranwiki.org/fortran/show/Linked+list

Since the parsing is simple (e.g. no backtracking), you can process each line as it is read. Iterate over the lines in the file, use adjustl() to dispose of leading whitespace, then check the first two characters: if they are '#, increment your block counter by one and add a new node to the list and set its ID to the value of the block counter (1), and process the next line.

Aside: I have a simple character function called munch() which is just trim(adjustl()). Great for stripping whitespace off both ends of a string. It doesn't quite act like Perl's chop() or chomp() and Fortran's trim() is more of an rtrim() so munch() was the next best name.

If the line doesn't match a block header, check if the first character is a digit; index('0123456789', line(1:1)) is greater than zero if the the first character of line is a digit, otherwise it returns 0. Increment the data line count in the head node of the linked list and go on to process the next line.

Note that if the block count is zero, this is an error condition; write out a friendly "Data line seen before block header" error message with the last line read and (ideally) the line number in the file. It takes a little more effort but it's worth it from the user's standpoint, especially if you're the main user.

Otherwise if the line isn't a block header or a data line, process the next line.

Eventually you'll hit the end of the file and you'll be left with the block counter and a linked list that has at least one node. Depending on how you want to use this data later, you can dynamically allocate an array of integers the length of the block counter, then transfer the data line count from the linked list to the array. Then you can deallocate the linked list and get direct access to the data line count for any block because the block index matches the array index.

I use a similar technique for reading arbitrarily long lists of data. The singly-linked list is extremely simple to code and it avoids the irritation of having to reallocate and expand a dynamic array. But once the amount of data is known, I carve out a dynamic array the exact size I need and copy the data from the linked list so I can have fast access to the data instead of needing to walk the list all the time.

Since Fortran doesn't have a standard library worth mentioning, I also use a variant of this technique with an insertion sort to simultaneously read and sort data.

So sorry, no code but enough to get you started. Defining your file format is key; once you do that, the parser almost writes itself. It also makes you think about exceptional conditions: data before block header, how you want to treat whitespace and unrecognized input, etc. Having this clearly written down is incredibly helpful if you're planning on sharing data; the Fortran world is littered with poorly-documented custom data file formats. Please don't add to the wreckage...

Finally, if you're really ambitious/insane, you could write this as a recursive routine and make your functional programming friends' heads explode. :)

arclight
  • 1,608
  • 1
  • 15
  • 19
  • 2
    *The singly-linked list is extremely simple to code* but not as simple, methinks, as reading the file once to figure out the number of blocks and the number of lines in each block, rewinding, allocating some arrays, then reading it again. I struggle to think this answer provides good advice to someone as (apparently) clueless as OP. – High Performance Mark Oct 04 '17 at 07:37
  • Exactly! I do understand the logic which is relatively simple. All I need is how to write actual syntax since I've never done any programming and all these 'read' operators and all kind of 'ios', 'iostat' and others just make me mad as some of them are simply don't work, others doing it in a strange way. I use Force 2.0 to do it, so may be some of the tutorials are not aplicable. – Slava_le Oct 04 '17 at 10:03