Skip to content

5. Writing the results ​

The results of a solver can be large: solver does not build them in memory, it streams them with an xml_writer, element by element.

f90
program solver
!< Tutorial, chapter 5: writing the results.
use foxy
implicit none
type(xml_writer)   :: results
integer(I4P)       :: iostat, step, i
character(len=256) :: iomsg

call results%open(filename='results.xml', iostat=iostat, iomsg=iomsg)
call results%declaration(encoding='UTF-8')
call results%start('results')
call results%attribute('case', 'cavity')
call results%attribute('steps', 500_I4P)
do step=100, 500, 200
   call results%start('snapshot')
   call results%attribute('step', step)
   call results%attribute('time', real(step, R8P)*1.0e-3_R8P, fmt='(F5.3)')
   call results%start('residual')
   call results%text('converged & stable')
   call results%end('residual')
   call results%start('pressure')
   call results%attribute('format', 'ascii')
   call results%text([(100.0_R8P/real(i*step, R8P), i=1, 3)], fmt='(F6.3)')   ! a list of numbers
   call results%end('pressure')
   call results%end('snapshot')
enddo
call results%comment(' 3 snapshots ')
call results%close(iostat=iostat, iomsg=iomsg)           ! closes the open elements, reports the first error
print '(A,I0)', 'results.xml written, iostat = ', iostat
endprogram solver
  • open(filename=) creates the file; open(unit=) writes to a unit you opened with access='stream', form='unformatted' (close leaves it open); open() writes to memory, read back with string().
  • declaration(encoding=) writes <?xml version="1.0" encoding="UTF-8"?>: the writer writes UTF-8, so no other encoding is accepted.
  • start(name) opens an element; its start tag stays open for attribute calls until its first content. Attributes take characters (escaped), integers and reals (both with an optional fmt), logicals, and lists of numbers.
  • text writes escaped character data, or a number, a logical or a list of numbers (here with fmt=; without it, reals get the shortest text that reads back exactly); raw writes characters as they are (base64, pre-formatted data) and can be called many times for one element; comment, cdata and pi write the other markup.
  • end(name) closes the innermost element (the name is checked); close closes all of them and the file (a file it opened itself).
  • Errors are sticky: the first one is kept, the following calls do nothing, close returns it. A misuse (an invalid name, a duplicate attribute, end with nothing open) is XML_MALFORMED; without iostat, close stops the program on it, so no error is lost.

Running it ​

$ solver
results.xml written, iostat = 0
$ cat results.xml
<?xml version="1.0" encoding="UTF-8"?>
<results case="cavity" steps="500">
  <snapshot step="100" time="0.100">
    <residual>converged &amp; stable</residual>
    <pressure format="ascii">1.000 0.500 0.333</pressure>
  </snapshot>
  <snapshot step="300" time="0.300">
    <residual>converged &amp; stable</residual>
    <pressure format="ascii">0.333 0.167 0.111</pressure>
  </snapshot>
  <snapshot step="500" time="0.500">
    <residual>converged &amp; stable</residual>
    <pressure format="ascii">0.200 0.100 0.067</pressure>
  </snapshot>
  <!-- 3 snapshots -->
</results>

What you learned

xml_writer streams a document of any size, with layout, escaping and well-formedness checks. Reference: Writing.

Next: 6. Large outputs: the index.