xmlOutput.F90 18.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
MODULE m_xmlOutput

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!
!!!   XML output service routines
!!!
!!!   This module provides several subroutines that simplify the
!!!   generation of the out.xml file.
!!!                                         GM'16
!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

   IMPLICIT NONE

15
   PRIVATE
16 17 18 19 20
   INTEGER, SAVE :: currentElementIndex
   INTEGER, SAVE :: maxNumElements
   INTEGER, SAVE :: xmlOutputUnit
   CHARACTER(LEN= 40), ALLOCATABLE :: elementList(:)

Gregor Michalicek's avatar
Gregor Michalicek committed
21 22 23
   PUBLIC startXMLOutput, endXMLOutput
   PUBLIC writeXMLElementFormPoly, writeXMLElementPoly
   PUBLIC writeXMLElementForm, writeXMLElement
24 25 26
   PUBLIC openXMLElementFormPoly, openXMLElementPoly
   PUBLIC openXMLElementForm, openXMLElement
   PUBLIC openXMLElementNoAttributes, closeXMLElement
27
   PUBLIC getXMLOutputUnitNumber
28

29 30
   CONTAINS

31 32 33 34 35 36
   FUNCTION getXMLOutputUnitNumber()
      IMPLICIT NONE
      INTEGER getXMLOutputUnitNumber
      getXMLOutputUnitNumber = xmlOutputUnit
   END FUNCTION getXMLOutputUnitNumber

37
   SUBROUTINE startXMLOutput()
38

39 40
      USE m_constants

41
      IMPLICIT NONE
42

43 44 45 46
#ifdef CPP_MPI
      include "mpif.h"
      INTEGER::err,isize
#endif
47 48
      CHARACTER(LEN=8)  :: date
      CHARACTER(LEN=10) :: time
49
      CHARACTER(LEN=10)  :: zone
50
      CHARACTER(LEN=10) :: dateString
51
      CHARACTER(LEN=10)  :: timeString
52

53 54 55 56 57
      maxNumElements = 10
      ALLOCATE(elementList(maxNumElements))
      elementList = ''
      currentElementIndex = 0
      xmlOutputUnit = 53
58 59 60
      CALL DATE_AND_TIME(date,time,zone)
      WRITE(dateString,'(a4,a1,a2,a1,a2)') date(1:4),'/',date(5:6),'/',date(7:8)
      WRITE(timeString,'(a2,a1,a2,a1,a2)') time(1:2),':',time(3:4),':',time(5:6)
61 62 63
      OPEN (xmlOutputUnit,file='out.xml',form='formatted',status='unknown')
      WRITE (xmlOutputUnit,'(a)') '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
      WRITE (xmlOutputUnit,'(a)') '<fleurOutput fleurOutputVersion="0.27">'
64
      CALL writeXMLElement('programVersion',(/'version'/),(/version_const/))
65 66 67 68
#ifdef CPP_MPI
      CALL MPI_COMM_SIZE(MPI_COMM_WORLD,isize,err)
      CALL writeXMLElementPoly('parallelizationParameters',(/'mpiPEs'/),(/isize/))
#endif
69
      CALL writeXMLElement('startDateAndTime',(/'date','time','zone'/),(/dateString,timeString,zone/))
70 71 72
   END SUBROUTINE startXMLOutput

   SUBROUTINE endXMLOutput()
73

74
      IMPLICIT NONE
75 76 77

      CHARACTER(LEN=8)  :: date
      CHARACTER(LEN=10) :: time
78
      CHARACTER(LEN=10)  :: zone
79
      CHARACTER(LEN=10) :: dateString
80
      CHARACTER(LEN=10)  :: timeString
81

82 83 84 85
      DO WHILE (currentElementIndex.NE.0)
         CALL closeXMLElement(elementList(currentElementIndex))
      END DO
      DEALLOCATE(elementList)
86 87 88 89
      CALL DATE_AND_TIME(date,time,zone)
      WRITE(dateString,'(a4,a1,a2,a1,a2)') date(1:4),'/',date(5:6),'/',date(7:8)
      WRITE(timeString,'(a2,a1,a2,a1,a2)') time(1:2),':',time(3:4),':',time(5:6)
      CALL writeXMLElement('endDateAndTime',(/'date','time','zone'/),(/dateString,timeString,zone/))
90 91 92 93
      WRITE (xmlOutputUnit,'(a)') '</fleurOutput>'
      CLOSE(xmlOutputUnit)
   END SUBROUTINE endXMLOutput

Gregor Michalicek's avatar
Gregor Michalicek committed
94
   SUBROUTINE writeXMLElementFormPoly(elementName,attributeNames,attributeValues,lengths,contentList)
95 96 97

      IMPLICIT NONE

Gregor Michalicek's avatar
Gregor Michalicek committed
98 99 100 101 102
      CHARACTER(LEN=*), INTENT(IN)           :: elementName
      CHARACTER(LEN=*), INTENT(IN)           :: attributeNames(:)
      CLASS(*),         INTENT(IN)           :: attributeValues(:)
      INTEGER,          INTENT(IN)           :: lengths(:,:)
      CLASS(*),         INTENT(IN), OPTIONAL :: contentList(:)
103 104 105 106 107 108

      CHARACTER(LEN= 30), ALLOCATABLE :: charAttributeValues(:)
      CHARACTER(LEN= 30), ALLOCATABLE :: charContentList(:)
      INTEGER                         :: i

      ALLOCATE(charAttributeValues(SIZE(attributeValues)))
Gregor Michalicek's avatar
Gregor Michalicek committed
109 110 111
      IF (PRESENT(contentList)) THEN
         ALLOCATE(charContentList(SIZE(contentList)))
      END IF
112 113 114 115 116 117

      charAttributeValues = ''
      charContentList = ''

      DO i = 1, SIZE(attributeValues)
         SELECT TYPE (attributeValues)
118
           TYPE IS(INTEGER)
119
               WRITE(charAttributeValues(i),'(i0)') attributeValues(i)
120
            TYPE IS(REAL)
121
               WRITE(charAttributeValues(i),'(f19.10)') attributeValues(i)
122
            TYPE IS(LOGICAL)
123
               WRITE(charAttributeValues(i),'(l1)') attributeValues(i)
124
#ifndef __PGI
125
            TYPE IS(CHARACTER(LEN=*))
126
               WRITE(charAttributeValues(i),'(a)') TRIM(ADJUSTL(attributeValues(i)))
127 128
            CLASS DEFAULT
               STOP 'Type of attributeValues not allowed'
129
#endif
130 131 132
         END SELECT
      END DO

Gregor Michalicek's avatar
Gregor Michalicek committed
133 134 135 136
      IF (PRESENT(contentList)) THEN
         DO i = 1, SIZE(contentList)
            SELECT TYPE(contentList)
               TYPE IS(INTEGER)
137
                  WRITE(charContentList(i),'(i0)') contentList(i)
Gregor Michalicek's avatar
Gregor Michalicek committed
138
               TYPE IS(REAL)
139
                  WRITE(charContentList(i),'(f19.10)') contentList(i)
Gregor Michalicek's avatar
Gregor Michalicek committed
140
               TYPE IS(LOGICAL)
141
                  WRITE(charContentList(i),'(l1)') contentList(i)
142
#ifndef __PGI
143
               TYPE IS(CHARACTER(LEN=*))
144
                  WRITE(charContentList(i),'(a)') TRIM(ADJUSTL(contentList(i)))
Gregor Michalicek's avatar
Gregor Michalicek committed
145 146
               CLASS DEFAULT
                  STOP 'Type of contentList not allowed'
147
#endif
Gregor Michalicek's avatar
Gregor Michalicek committed
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
            END SELECT
         END DO
         CALL writeXMLElementForm(elementName,attributeNames,charAttributeValues,lengths,charContentList)
         DEALLOCATE(charContentList,charAttributeValues)
      ELSE
         CALL writeXMLElementForm(elementName,attributeNames,charAttributeValues,lengths)
      END IF

   END SUBROUTINE writeXMLElementFormPoly

   SUBROUTINE writeXMLElementPoly(elementName,attributeNames,attributeValues,contentList)

      IMPLICIT NONE

      CHARACTER(LEN=*), INTENT(IN)           :: elementName
      CHARACTER(LEN=*), INTENT(IN)           :: attributeNames(:)
      CLASS(*),         INTENT(IN)           :: attributeValues(:)
      CLASS(*),         INTENT(IN), OPTIONAL :: contentList(:)
166

Gregor Michalicek's avatar
Gregor Michalicek committed
167 168
      INTEGER, ALLOCATABLE :: lengths(:,:)
      INTEGER              :: contentListSize
169

Gregor Michalicek's avatar
Gregor Michalicek committed
170 171 172 173 174 175 176 177 178
      contentListSize = 0
      IF (PRESENT(contentList)) THEN
         contentListSize = SIZE(contentList)
      END IF

      ALLOCATE(lengths(MAX(SIZE(attributeNames),contentListSize),3))
      lengths = 0
      CALL writeXMLElementFormPoly(elementName,attributeNames,attributeValues,lengths,contentList)
      DEALLOCATE(lengths)
179

180 181
   END SUBROUTINE writeXMLElementPoly

Gregor Michalicek's avatar
Gregor Michalicek committed
182
   SUBROUTINE writeXMLElementForm(elementName,attributeNames,attributeValues,lengths,contentList)
183 184 185

      IMPLICIT NONE

Gregor Michalicek's avatar
Gregor Michalicek committed
186 187 188 189 190
      CHARACTER(LEN=*), INTENT(IN)           :: elementName
      CHARACTER(LEN=*), INTENT(IN)           :: attributeNames(:)
      CHARACTER(LEN=*), INTENT(IN)           :: attributeValues(:)
      INTEGER,          INTENT(IN)           :: lengths(:,:)
      CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: contentList(:)
191 192

      CHARACTER(LEN=200), ALLOCATABLE :: contentLineList(:)
Gregor Michalicek's avatar
Gregor Michalicek committed
193 194
      INTEGER, ALLOCATABLE            :: bigLengths(:,:)
      INTEGER :: i, j, contentLineLength, contentLineListSize
195 196
      CHARACTER(LEN=70)               :: format
      CHARACTER(LEN=200)              :: outputString
197
      INTEGER                         :: contentListSize, overallListSize, numContentLineChars
Gregor Michalicek's avatar
Gregor Michalicek committed
198
      INTEGER                         :: lengthsShape(2)
199 200 201 202 203 204

      IF(SIZE(attributeNames).NE.SIZE(attributeValues)) THEN
         WRITE(*,*) 'attributeNames', attributeNames
         WRITE(*,*) 'attributeValues', attributeValues
         STOP 'ERROR: SIZE(attributeNames).NE.SIZE(attributeValues)'
      END IF
Gregor Michalicek's avatar
Gregor Michalicek committed
205 206 207 208 209

      lengthsShape = SHAPE(lengths)
      contentListSize = 0
      IF (PRESENT(contentList)) THEN
         contentListSize = SIZE(contentList)
210
      END IF
Gregor Michalicek's avatar
Gregor Michalicek committed
211 212 213 214 215 216 217 218 219
      overallListSize = MAX(SIZE(attributeNames),contentListSize)
      ALLOCATE(bigLengths(overallListSize,2))
      bigLengths = 0
      DO j = 1, 2
         DO i = 1, MIN(overallListSize,lengthsShape(1))
            bigLengths(i,j) = lengths(i,j)
         END DO
      END DO

220 221
      outputString = '<'//TRIM(ADJUSTL(elementName))
      DO i = 1, SIZE(attributeNames)
Gregor Michalicek's avatar
Gregor Michalicek committed
222 223 224 225 226 227 228
         WRITE(format,'(a)') "(a,a,a"
         IF (bigLengths(i,1).GT.0) WRITE(format,'(a,i0)') TRIM(ADJUSTL(format)),bigLengths(i,1)
         WRITE(format,'(a,a)') TRIM(ADJUSTL(format)),",a,a"
         IF (bigLengths(i,2).GT.0) WRITE(format,'(a,i0)') TRIM(ADJUSTL(format)),bigLengths(i,2)
         WRITE(format,'(a,a)') TRIM(ADJUSTL(format)),",a)"
         WRITE(outputString,format) TRIM(ADJUSTL(outputString)), ' ', TRIM(ADJUSTL(attributeNames(i))),&
                                    '="', TRIM(ADJUSTL(attributeValues(i))), '"'
229
      END DO
230
      WRITE(format,'(a,i0,a)') "(a",3*(currentElementIndex+1),",a)"
Gregor Michalicek's avatar
Gregor Michalicek committed
231 232 233 234 235 236 237 238 239
      IF (PRESENT(contentList)) THEN
         contentLineLength = 5 ! At most 5 data elements per line
         contentLineListSize = SIZE(contentList) / contentLineLength
         IF(contentLineListSize*contentLineLength.NE.SIZE(contentList)) THEN
            contentLineListSize = contentLineListSize + 1
         END IF
         ALLOCATE(contentLineList(contentLineListSize))
         CALL fillContentLineList(contentList,contentLineList,contentLineLength)
         IF(SIZE(contentLineList).LE.1) THEN
240 241
            outputString = TRIM(ADJUSTL(outputString))//'>'//contentLineList(1)//'</'//&
                 TRIM(ADJUSTL(elementName))//'>'
Gregor Michalicek's avatar
Gregor Michalicek committed
242 243 244
         ELSE
            outputString = TRIM(ADJUSTL(outputString))//'>'
         END IF
245
         WRITE(xmlOutputUnit,format) ' ', TRIM(ADJUSTL(outputString))
Gregor Michalicek's avatar
Gregor Michalicek committed
246 247
         IF(SIZE(contentLineList).GT.1) THEN
            DO i = 1, SIZE(contentLineList)
248 249 250 251 252 253 254
               IF (i.EQ.SIZE(contentLineList)) THEN
                  numContentLineChars = 20*MOD(SIZE(contentList),contentLineLength)
                  IF(numContentLineChars.EQ.0) numContentLineChars = 20 * contentLineLength
                  WRITE(format,'(a,i0,a,i0,a)') "(a",3*(currentElementIndex+2),",a",numContentLineChars,")"
               ELSE
                  WRITE(format,'(a,i0,a)') "(a",3*(currentElementIndex+2),",a100)"
               END IF
Gregor Michalicek's avatar
Gregor Michalicek committed
255 256 257 258 259 260 261 262 263 264 265
               WRITE(xmlOutputUnit,format) ' ', TRIM(ADJUSTL(contentLineList(i)))
            END DO
            WRITE(format,'(a,i0,a)') "(a",3*(currentElementIndex+1),",a)"
            outputString = '</'//TRIM(ADJUSTL(elementName))//'>'
            WRITE(xmlOutputUnit,format) ' ', TRIM(ADJUSTL(outputString))
         END IF
      ELSE
         outputString = TRIM(ADJUSTL(outputString))//'/>'
         WRITE(xmlOutputUnit,format) ' ', TRIM(ADJUSTL(outputString))
      END IF
      DEALLOCATE (bigLengths)
266

Gregor Michalicek's avatar
Gregor Michalicek committed
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
   END SUBROUTINE writeXMLElementForm

   SUBROUTINE writeXMLElement(elementName,attributeNames,attributeValues,contentList)

      IMPLICIT NONE

      CHARACTER(LEN=*), INTENT(IN)           :: elementName
      CHARACTER(LEN=*), INTENT(IN)           :: attributeNames(:)
      CHARACTER(LEN=*), INTENT(IN)           :: attributeValues(:)
      CHARACTER(LEN=*), INTENT(IN), OPTIONAL :: contentList(:)

      INTEGER, ALLOCATABLE :: lengths(:,:)
      INTEGER              :: contentListSize

      contentListSize = 0
      IF (PRESENT(contentList)) THEN
         contentListSize = SIZE(contentList)
284
      END IF
Gregor Michalicek's avatar
Gregor Michalicek committed
285 286 287 288 289

      ALLOCATE(lengths(MAX(SIZE(attributeNames),contentListSize),2))
      lengths = 0
      CALL writeXMLElementForm(elementName,attributeNames,attributeValues,lengths,contentList)
      DEALLOCATE(lengths)
290

291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
   END SUBROUTINE writeXMLElement

   SUBROUTINE fillContentLineList(contentList,contentLineList,contentLineLength)

      IMPLICIT NONE

      CHARACTER(LEN= 30), INTENT(IN)    :: contentList(:)
      CHARACTER(LEN=200), INTENT(INOUT) :: contentLineList(:)
      INTEGER,            INTENT(IN)    :: contentLineLength
      INTEGER :: i, j

      contentLineList = ''
      DO i = 1, SIZE(contentLineList)
         DO j = 1, contentLineLength
            IF((i-1)*contentLineLength+j.GT.SIZE(contentList)) THEN
               RETURN
            END IF
308 309
            WRITE(contentLineList(i),'(a,a20)') TRIM(ADJUSTL(contentLineList(i))),&
                        TRIM(ADJUSTL(contentList((i-1)*contentLineLength+j)))
310 311 312 313 314 315 316 317
         END DO
      END DO
   END SUBROUTINE fillContentLineList

   SUBROUTINE openXMLElementPoly(elementName,attributeNames,attributeValues)

      IMPLICIT NONE

318 319 320
      CHARACTER(LEN=*)             :: elementName
      CHARACTER(LEN=*), INTENT(IN) :: attributeNames(:)
      CLASS(*),         INTENT(IN) :: attributeValues(:)
321

322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
      INTEGER, ALLOCATABLE :: lengths(:,:)

      ALLOCATE(lengths(SIZE(attributeNames),2))
      lengths = 0
      CALL openXMLElementFormPoly(elementName,attributeNames,attributeValues,lengths)
      DEALLOCATE(lengths)

   END SUBROUTINE openXMLElementPoly

   SUBROUTINE openXMLElementFormPoly(elementName,attributeNames,attributeValues,lengths)

      IMPLICIT NONE

      CHARACTER(LEN=*)             :: elementName
      CHARACTER(LEN=*), INTENT(IN) :: attributeNames(:)
      CLASS(*),         INTENT(IN) :: attributeValues(:)
      INTEGER,          INTENT(IN) :: lengths(:,:)

340 341 342 343 344 345 346 347 348 349
      CHARACTER(LEN= 30), ALLOCATABLE :: charAttributeValues(:)
      INTEGER                         :: i

      ALLOCATE(charAttributeValues(SIZE(attributeValues)))

      charAttributeValues = ''

      DO i = 1, SIZE(attributeValues)
         SELECT TYPE (attributeValues)
            TYPE IS(INTEGER)
350
               WRITE(charAttributeValues(i),'(i0)') attributeValues(i)
351
            TYPE IS(REAL)
352
               WRITE(charAttributeValues(i),'(f19.10)') attributeValues(i)
353
            TYPE IS(LOGICAL)
354
               WRITE(charAttributeValues(i),'(l1)') attributeValues(i)
355
#ifndef __PGI
356
            TYPE IS(CHARACTER(LEN=*))
357
               WRITE(charAttributeValues(i),'(a)') TRIM(ADJUSTL(attributeValues(i)))
358 359
            CLASS DEFAULT
               STOP 'Type of attributeValues not allowed'
360
#endif
361 362 363
         END SELECT
      END DO

364
      CALL openXMLElementForm(elementName,attributeNames,charAttributeValues,lengths)
365 366
      DEALLOCATE(charAttributeValues)

367
   END SUBROUTINE openXMLElementFormPoly
368

369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
   SUBROUTINE openXMLElementNoAttributes(elementName)

      IMPLICIT NONE

      CHARACTER(LEN=*)             :: elementName

      INTEGER :: i
      CHARACTER(LEN=70)  :: format
      CHARACTER(LEN=200) :: openingString

      IF(currentElementIndex.EQ.maxNumElements) THEN
         WRITE(*,*) 'elementName', TRIM(ADJUSTL(elementName))
         STOP 'ERROR: xml hierarchy too deep!'
      END IF
      currentElementIndex = currentElementIndex + 1
      elementList(currentElementIndex) = TRIM(ADJUSTL(elementName))
      openingString = '<'//TRIM(ADJUSTL(elementName))//'>'
      WRITE(format,'(a,i0,a)') "(a",3*currentElementIndex,",a)"
      WRITE(xmlOutputUnit,format) ' ', TRIM(ADJUSTL(openingString))
388

389 390
   END SUBROUTINE openXMLElementNoAttributes

391 392 393 394
   SUBROUTINE openXMLElement(elementName,attributeNames,attributeValues)

      IMPLICIT NONE

395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
      CHARACTER(LEN=*), INTENT(IN)           :: elementName
      CHARACTER(LEN=*), INTENT(IN)           :: attributeNames(:)
      CHARACTER(LEN=*), INTENT(IN)           :: attributeValues(:)

      INTEGER, ALLOCATABLE :: lengths(:,:)

      ALLOCATE(lengths(SIZE(attributeNames),2))
      lengths = 0
      CALL openXMLElementForm(elementName,attributeNames,attributeValues,lengths)
      DEALLOCATE(lengths)

   END SUBROUTINE

   SUBROUTINE openXMLElementForm(elementName,attributeNames,attributeValues,lengths)

      IMPLICIT NONE

412 413 414
      CHARACTER(LEN=*)             :: elementName
      CHARACTER(LEN=*), INTENT(IN) :: attributeNames(:)
      CHARACTER(LEN=*), INTENT(IN) :: attributeValues(:)
415
      INTEGER,          INTENT(IN) :: lengths(:,:)
416 417 418 419

      CHARACTER(LEN=70)  :: format
      CHARACTER(LEN=200) :: openingString

420 421 422 423 424
      INTEGER, ALLOCATABLE            :: bigLengths(:,:)
      INTEGER                         :: i, j
      INTEGER                         :: overallListSize
      INTEGER                         :: lengthsShape(2)

425 426 427 428 429 430 431 432 433 434 435 436
      IF(SIZE(attributeNames).NE.SIZE(attributeValues)) THEN
         WRITE(*,*) 'elementName', TRIM(ADJUSTL(elementName))
         WRITE(*,*) 'attributeNames', attributeNames
         WRITE(*,*) 'attributeValues', attributeValues
         STOP 'ERROR: SIZE(attributeNames).NE.SIZE(attributeValues)'
      END IF
      IF(currentElementIndex.EQ.maxNumElements) THEN
         WRITE(*,*) 'elementName', TRIM(ADJUSTL(elementName))
         WRITE(*,*) 'attributeNames', attributeNames
         WRITE(*,*) 'attributeValues', attributeValues
         STOP 'ERROR: xml hierarchy too deep!'
      END IF
437 438 439 440 441 442 443 444 445 446 447

      lengthsShape = SHAPE(lengths)
      overallListSize = SIZE(attributeNames)
      ALLOCATE(bigLengths(overallListSize,2))
      bigLengths = 0
      DO j = 1, 2
         DO i = 1, MIN(overallListSize,lengthsShape(1))
            bigLengths(i,j) = lengths(i,j)
         END DO
      END DO

448 449
      openingString = '<'//TRIM(ADJUSTL(elementName))
      DO i = 1, SIZE(attributeNames)
450 451 452 453 454 455 456
         WRITE(format,'(a)') "(a,a,a"
         IF (bigLengths(i,1).GT.0) WRITE(format,'(a,i0)') TRIM(ADJUSTL(format)),bigLengths(i,1)
         WRITE(format,'(a,a)') TRIM(ADJUSTL(format)),",a,a"
         IF (bigLengths(i,2).GT.0) WRITE(format,'(a,i0)') TRIM(ADJUSTL(format)),bigLengths(i,2)
         WRITE(format,'(a,a)') TRIM(ADJUSTL(format)),",a)"
         WRITE(openingString,format) TRIM(ADJUSTL(openingString)), ' ', TRIM(ADJUSTL(attributeNames(i))),&
                                    '="', TRIM(ADJUSTL(attributeValues(i))), '"'
457 458
      END DO
      openingString = TRIM(ADJUSTL(openingString))//'>'
459 460 461

      currentElementIndex = currentElementIndex + 1
      elementList(currentElementIndex) = TRIM(ADJUSTL(elementName))
462
      WRITE(format,'(a,i0,a)') "(a",3*currentElementIndex,",a)"
463
      WRITE(xmlOutputUnit,format) ' ', TRIM(ADJUSTL(openingString))
464 465 466
      DEALLOCATE (bigLengths)

   END SUBROUTINE openXMLElementForm
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481

   SUBROUTINE closeXMLElement(elementName)

      IMPLICIT NONE

      CHARACTER(LEN=*), INTENT(IN) :: elementName
      INTEGER :: i
      CHARACTER(LEN=70) :: format
      CHARACTER(LEN=70) :: closingString

      IF(TRIM(ADJUSTL(elementList(currentElementIndex))).NE.TRIM(ADJUSTL(elementName))) THEN
         WRITE(*,*) 'elementList(currentElementIndex):', TRIM(ADJUSTL(elementList(currentElementIndex)))
         WRITE(*,*) 'elementName', TRIM(ADJUSTL(elementName))
         STOP 'ERROR: Closing xml element inconsistency!'
      END IF
482 483
      closingString = '</'//TRIM(ADJUSTL(elementName))//'>'
      WRITE(format,'(a,i0,a)') "(a",3*currentElementIndex,",a)"
484 485
      WRITE(xmlOutputUnit,format) ' ', TRIM(ADJUSTL(closingString))
      currentElementIndex = currentElementIndex - 1
486

487 488 489
   END SUBROUTINE closeXMLElement

END MODULE m_xmlOutput