(git:e7e05ae)
reference_manager.F
Go to the documentation of this file.
1 !--------------------------------------------------------------------------------------------------!
2 ! CP2K: A general program to perform molecular dynamics simulations !
3 ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 ! !
5 ! SPDX-License-Identifier: GPL-2.0-or-later !
6 !--------------------------------------------------------------------------------------------------!
7 
8 ! **************************************************************************************************
9 !> \brief provides a uniform framework to add references to CP2K
10 !> cite and output these
11 !> \note
12 !> references need to be input using the ISI citation format, because it is
13 !> uniform, easy to parse, and can be exported for example from web of science
14 !> furthermore, it can be easily converted to and from using the bibutils tools
15 !> a collection of easy to use conversion programs that can be found at
16 !> http://www.scripps.edu/~cdputnam/software/bibutils/
17 !> by Chris Putnam
18 !>
19 !> see thebibliography.F on how to add references easily
20 !> \par History
21 !> 08.2007 [Joost VandeVondele]
22 !> \author Joost VandeVondele
23 ! **************************************************************************************************
25  USE kinds, ONLY: default_string_length
26  USE message_passing, ONLY: mp_para_env_type
27  USE string_utilities, ONLY: uppercase
28  USE util, ONLY: sort
29 #include "../base/base_uses.f90"
30 
31  IMPLICIT NONE
32 
35 
36  INTEGER, PUBLIC, PARAMETER :: print_format_isi = 101, &
37  print_format_journal = 102, &
38  print_format_html = 103
39 
40  PRIVATE
41 
42  CHARACTER(len=*), PARAMETER, PRIVATE :: modulen = 'reference_manager'
43 
44  ! maximum number of reference that can be added
45  INTEGER, PARAMETER :: max_reference = 1024
46 
47  ! storage of a reference
48  INTEGER, PARAMETER :: doi_length = 128
49  INTEGER, PARAMETER :: isi_length = 128
50 
51  ! the way we store a reference, should remain fully private
52 ! **************************************************************************************************
53  TYPE reference_type
54  PRIVATE
55  ! the reference in a format as returned by the web of science
56  CHARACTER(LEN=ISI_length), DIMENSION(:), POINTER :: isi_record => null()
57  ! the doi only, i.e. without "https://doi.org/"
58  CHARACTER(LEN=doi_length) :: doi = ""
59  ! has this reference been cited in the program run
60  LOGICAL :: is_cited = .false.
61  ! this is a citation key for output in the reference lists
62  CHARACTER(LEN=ISI_length) :: citation_key = ""
63  END TYPE reference_type
64 
65  ! useful to build arrays
66 ! **************************************************************************************************
67  TYPE reference_p_type
68  TYPE(reference_type), POINTER :: ref => null()
69  END TYPE
70 
71  ! thebibliography
72  INTEGER, SAVE :: nbib = 0
73  TYPE(reference_p_type), DIMENSION(max_reference) :: thebib
74 
75  PUBLIC :: add_reference, & ! use this one only in bibliography.F
76  remove_all_references, & ! use only in f77_interface.F
77  get_citation_key ! a string key describing the reference (e.g. Kohn1965b)
78 
79 CONTAINS
80 
81 ! **************************************************************************************************
82 !> \brief marks a given reference as cited.
83 !> \param key citation key as returned from add_reference
84 !> \par History
85 !> XX.2007 created [ ]
86 ! **************************************************************************************************
87  SUBROUTINE cite_reference(key)
88  INTEGER, INTENT(IN) :: key
89 
90  IF (key < 1 .OR. key > max_reference) cpabort("citation key out of range")
91 
92  ! set as cited
93  thebib(key)%ref%is_cited = .true.
94 
95  END SUBROUTINE
96 
97 ! **************************************************************************************************
98 !> \brief Checks for each reference if any mpi-rank has marked it for citation.
99 !> \param para_env ...
100 !> \par History
101 !> 12.2013 created [Ole Schuett]
102 ! **************************************************************************************************
103  SUBROUTINE collect_citations_from_ranks(para_env)
104  TYPE(mp_para_env_type), INTENT(IN) :: para_env
105 
106  INTEGER :: i, t
107 
108  DO i = 1, nbib
109  t = 0
110  IF (thebib(i)%ref%is_cited) t = 1
111  CALL para_env%max(t)
112  thebib(i)%ref%is_cited = (t == 1)
113  END DO
114 
115  END SUBROUTINE collect_citations_from_ranks
116 
117 ! **************************************************************************************************
118 !> \brief add a reference to the bibliography
119 !> \param key output, this handle is needed to cite this reference later
120 !> \param ISI_record ...
121 !> \param DOI ...
122 !> \par History
123 !> 08.2007 created [Joost VandeVondele]
124 !> \note
125 !> - see bibliography.F for it use.
126 !> - the ISI record is space sensitive, in particular the first three characters need to be blank
127 !> or contain a key indicating the record type. See the header of this file for tools
128 !> that can convert e.g. bibtex or endnote files to the ISI format
129 !> - DOI: provide the DOI without a link. The link will be automatically created as needed.
130 ! **************************************************************************************************
131  SUBROUTINE add_reference(key, ISI_record, DOI)
132  INTEGER, INTENT(OUT) :: key
133  CHARACTER(LEN=*), DIMENSION(:), INTENT(IN) :: isi_record
134  CHARACTER(LEN=*), INTENT(IN) :: doi
135 
136  CHARACTER :: tmp
137  CHARACTER(LEN=ISI_length) :: author, citation_key, key_a, key_b, year
138  INTEGER :: commaloc, i, ires, line, match, mylen, &
139  nlines
140 
141  IF (nbib + 1 > max_reference) cpabort("increase max_reference")
142  nbib = nbib + 1
143  key = nbib
144 
145  ! initialize reference to zero
146  ALLOCATE (thebib(key)%ref)
147  NULLIFY (thebib(key)%ref%ISI_record)
148  thebib(key)%ref%DOI = ""
149  thebib(key)%ref%is_cited = .false.
150 
151  ! Assign DOI
152  thebib(key)%ref%DOI = doi
153 
154  ! Assign ISI_record
155  nlines = SIZE(isi_record, 1)
156  ALLOCATE (thebib(key)%ref%ISI_record(nlines))
157  thebib(key)%ref%ISI_record = isi_record
158 
159  ! construct a citation_key
160  line = 1
161  author = get_next_author(thebib(key)%ref%ISI_record, line)
162  commaloc = index(author, ',')
163  IF (commaloc .GT. 0) author = author(1:commaloc - 1)
164  cpassert(len_trim(author) > 0)
165  year = get_year(thebib(key)%ref%ISI_record)
166  cpassert(len_trim(year) == 4)
167  citation_key = trim(author)//trim(year)
168 
169  ! avoid special characters in names, just remove them
170  mylen = len_trim(citation_key)
171  ires = 0
172  DO i = 1, mylen
173  IF (index("0123456789thequickbrownfoxjumpsoverthelazydogTHEQUICKBROWNFOXJUMPSOVERTHELAZYDOG", citation_key(i:i)) .NE. 0) THEN
174  ires = ires + 1
175  tmp = citation_key(i:i)
176  citation_key(ires:ires) = tmp
177  END IF
178  END DO
179  citation_key(ires + 1:) = ""
180  cpassert(len_trim(citation_key) > 4) ! At least one character of the author should be left.
181 
182  ! avoid duplicates, search through the list for matches (case-insensitive)
183  mylen = len_trim(citation_key)
184  key_a = citation_key(1:mylen)
185  CALL uppercase(key_a)
186  match = 0
187  DO i = 1, nbib - 1
188  key_b = thebib(i)%ref%citation_key(1:mylen)
189  CALL uppercase(key_b)
190  IF (key_a == key_b) match = match + 1
191  END DO
192  IF (match > 0) citation_key = citation_key(1:mylen)//char(ichar('a') + match)
193 
194  ! finally store it
195  thebib(key)%ref%citation_key = citation_key
196 
197  END SUBROUTINE add_reference
198 
199 ! **************************************************************************************************
200 !> \brief deallocate the bibliography
201 !> \par History
202 !> 08.2007 Joost VandeVondele [ ]
203 ! **************************************************************************************************
205  INTEGER :: i
206 
207  DO i = 1, nbib
208  IF (ASSOCIATED(thebib(i)%ref%ISI_record)) DEALLOCATE (thebib(i)%ref%ISI_record)
209  thebib(i)%ref%DOI = ""
210 
211  DEALLOCATE (thebib(i)%ref)
212  END DO
213  END SUBROUTINE remove_all_references
214 !****f* reference_manager/print_all_references *
215 
216 ! **************************************************************************************************
217 !> \brief printout of all references in a specific format
218 !> optionally printing only those that are actually cited
219 !> during program execution
220 !> \param cited_only print only those marked as cited
221 !> \param sorted sort entries most recent first according to the date,
222 !> otherways sort with respect to key
223 !> \param FORMAT see module parameters print_format_XXXXXXXXX
224 !> \param unit ...
225 !> \param list optionally, output a sub-list only
226 !> \par History
227 !> 08.2007 Joost VandeVondele [ ]
228 ! **************************************************************************************************
229  SUBROUTINE print_all_references(cited_only, sorted, FORMAT, unit, list)
230  LOGICAL, INTENT(IN) :: cited_only, sorted
231  INTEGER, INTENT(IN) :: format, unit
232  INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: list
233 
234  INTEGER :: i, irecord, nref
235  INTEGER, ALLOCATABLE, DIMENSION(:) :: indx, irank, ival
236 
237 ! we'll sort the references wrt to the publication year
238 ! the most recent first, publications without a year get last
239 
240  IF (PRESENT(list)) THEN
241  nref = SIZE(list)
242  ELSE
243  nref = nbib
244  END IF
245 
246  ALLOCATE (ival(nref))
247  ALLOCATE (irank(nref))
248  ALLOCATE (indx(nref))
249 
250  IF (PRESENT(list)) THEN
251  indx(:) = list
252  ELSE
253  DO i = 1, nref
254  indx(i) = i
255  END DO
256  END IF
257 
258  DO i = 1, nref
259  irank(i) = i
260  END DO
261 
262  IF (sorted) THEN
263  DO i = 1, nref
264  ival(i) = -get_epoch(thebib(indx(i))%ref%ISI_record)
265  END DO
266  ELSE
267  DO i = 1, nref
268  ival(i) = indx(i)
269  END DO
270  END IF
271  CALL sort(ival, nref, irank)
272 
273  SELECT CASE (format)
274  CASE (print_format_isi)
275  CASE (print_format_journal)
276  WRITE (unit, '(A)') ""
277  CASE (print_format_html)
278  WRITE (unit, '(A)') '<TABLE border="1">'
279  CASE DEFAULT
280  cpabort("print_reference: wrong format")
281  END SELECT
282 
283  DO i = 1, nref
284  irecord = indx(irank(i))
285  IF (.NOT. cited_only .OR. thebib(irecord)%ref%is_cited) THEN
286  SELECT CASE (format)
287  CASE (print_format_isi)
288  CASE (print_format_journal)
289  CASE (print_format_html)
290  WRITE (unit, '(A)') "<TR><TD>"//'['//trim(thebib(irecord)%ref%citation_key)//']'//"</TD><TD>"
291  CASE DEFAULT
292  cpabort("print_reference: wrong format")
293  END SELECT
294 
295  CALL print_reference(irecord, FORMAT, unit)
296 
297  SELECT CASE (format)
298  CASE (print_format_isi)
299  CASE (print_format_journal)
300  WRITE (unit, '(A)') ""
301  CASE (print_format_html)
302  WRITE (unit, '(A)') '</TD></TR>'
303  CASE DEFAULT
304  cpabort("print_reference: wrong format")
305  END SELECT
306  END IF
307  END DO
308  IF (FORMAT .EQ. print_format_html) THEN
309  WRITE (unit, '(A)') "</TABLE>"
310  END IF
311 
312  END SUBROUTINE print_all_references
313 !****f* reference_manager/print_reference *
314 
315 ! **************************************************************************************************
316 !> \brief printout of a specified reference to a given unit in a selectable format
317 !> \param key as returned from add_reference
318 !> \param FORMAT see module parameters print_format_XXXXXXXXX
319 !> \param unit ...
320 !> \par History
321 !> 08.2007 Joost VandeVondele [ ]
322 ! **************************************************************************************************
323  SUBROUTINE print_reference(key, FORMAT, unit)
324  INTEGER, INTENT(IN) :: key, format, unit
325 
326  INTEGER :: i
327 
328  IF (key < 1 .OR. key > max_reference) cpabort("citation key out of range")
329 
330  SELECT CASE (format)
331  CASE (print_format_isi)
332  DO i = 1, SIZE(thebib(key)%ref%ISI_record)
333  WRITE (unit, '(T2,A)') trim(thebib(key)%ref%ISI_record(i))
334  END DO
335  CASE (print_format_journal)
336  CALL print_reference_journal(key, unit)
337  CASE (print_format_html)
338  CALL print_reference_html(key, unit)
339  CASE DEFAULT
340  cpabort("print_reference: wrong format")
341  END SELECT
342  END SUBROUTINE print_reference
343 
344 ! **************************************************************************************************
345 !> \brief prints a reference in a journal style citation format,
346 !> adding also a DOI link, which is convenient
347 !> \param key ...
348 !> \param unit ...
349 !> \par History
350 !> 08.2007 created [Joost VandeVondele]
351 ! **************************************************************************************************
352  SUBROUTINE print_reference_journal(key, unit)
353  INTEGER, INTENT(IN) :: key, unit
354 
355  CHARACTER(LEN=4*ISI_length) :: journal
356  CHARACTER(LEN=ISI_length) :: author, title
357  INTEGER :: iauthor, ipos_line, ititle, line
358 
359 ! write the author list
360 
361  WRITE (unit, '(T2,A)', advance="NO") ""
362  line = 1; iauthor = 0; ipos_line = 2
363  author = get_next_author(thebib(key)%ref%ISI_record, line)
364  DO WHILE (author .NE. "")
365  iauthor = iauthor + 1
366  IF (ipos_line + len_trim(author) > 71) THEN
367  WRITE (unit, '(A)') ";"
368  WRITE (unit, '(T2,A)', advance="NO") ""
369  ipos_line = 2
370  ELSE
371  IF (iauthor .NE. 1) WRITE (unit, '(A)', advance="NO") "; "
372  ipos_line = ipos_line + 2
373  END IF
374  WRITE (unit, '(A)', advance="NO") trim(author)
375  ipos_line = ipos_line + len_trim(author)
376  author = get_next_author(thebib(key)%ref%ISI_record, line)
377  END DO
378  IF (iauthor > 0) THEN
379  WRITE (unit, '(A)', advance="NO") ". "
380  ipos_line = ipos_line + 2
381  END IF
382 
383  ! Journal, volume (issue), pages (year).
384  journal = trim(get_source(thebib(key)%ref%ISI_record))
385  IF (get_volume(thebib(key)%ref%ISI_record) .NE. "") THEN
386  journal = trim(journal)//", "//get_volume(thebib(key)%ref%ISI_record)
387  IF (get_issue(thebib(key)%ref%ISI_record) .NE. "") THEN
388  journal = trim(journal)//" ("//trim(get_issue(thebib(key)%ref%ISI_record))//")"
389  END IF
390  END IF
391  journal = trim(journal)//", "//get_pages(thebib(key)%ref%ISI_record)
392  IF (get_year(thebib(key)%ref%ISI_record) .NE. "") THEN
393  journal = trim(journal)//" ("//trim(get_year(thebib(key)%ref%ISI_record))//")."
394  END IF
395  IF (ipos_line + len_trim(journal) > 71) THEN
396  WRITE (unit, '(A)') ""
397  WRITE (unit, '(T2,A)', advance="NO") ""
398  ipos_line = 2
399  END IF
400  IF (ipos_line + len_trim(journal) > 71) THEN
401  WRITE (unit, '(A)') trim(journal(1:69))
402  WRITE (unit, '(A)', advance="NO") trim(journal(69:))
403  ELSE
404  WRITE (unit, '(A)', advance="NO") trim(journal)
405  END IF
406 
407  WRITE (unit, '(T2,A)') ""
408  ! Title
409  line = 1; ititle = 0
410  title = get_next_title(thebib(key)%ref%ISI_record, line)
411  DO WHILE (title .NE. "")
412  ititle = ititle + 1
413  IF (ititle .NE. 1) WRITE (unit, '(A)') ""
414  WRITE (unit, '(T2,A)', advance="NO") trim(title)
415  title = get_next_title(thebib(key)%ref%ISI_record, line)
416  END DO
417  IF (ititle > 0) WRITE (unit, '(A)') "."
418 
419  ! DOI
420  IF (thebib(key)%ref%DOI .NE. "") THEN
421  WRITE (unit, '(T2,A)') "https://doi.org/"//trim(thebib(key)%ref%DOI)
422  END IF
423 
424  END SUBROUTINE print_reference_journal
425 
426 ! **************************************************************************************************
427 !> \brief prints a reference in a journal style citation format,
428 !> adding 'beautifying' html tags, and a link to the journal
429 !> using the DOI
430 !> \param key ...
431 !> \param unit ...
432 !> \par History
433 !> 08.2007 created [Joost VandeVondele]
434 ! **************************************************************************************************
435  SUBROUTINE print_reference_html(key, unit)
436  INTEGER, INTENT(IN) :: key, unit
437 
438  CHARACTER(LEN=ISI_length) :: author, title
439  CHARACTER(LEN=ISI_length*4) :: journal
440  INTEGER :: iauthor, ititle, line
441 
442 ! write the author list
443 
444  WRITE (unit, '(T2,A,I0,A)', advance="NO") '<A NAME="reference_', key, '">'
445  line = 1; iauthor = 0
446  author = get_next_author(thebib(key)%ref%ISI_record, line)
447  DO WHILE (author .NE. "")
448  iauthor = iauthor + 1
449  IF (iauthor .NE. 1) WRITE (unit, '(A)', advance="NO") "; "
450  WRITE (unit, '(A)', advance="NO") trim(author)
451  author = get_next_author(thebib(key)%ref%ISI_record, line)
452  END DO
453  IF (iauthor > 0) WRITE (unit, '(A)') ".<br>"
454 
455  ! DOI
456  IF (thebib(key)%ref%DOI .NE. "") THEN
457  WRITE (unit, '(T2,A)', advance="NO") '<A HREF="https://doi.org/'//trim(thebib(key)%ref%DOI)//'">'
458  END IF
459  ! Journal, volume (issue), pages (year).
460  journal = trim(get_source(thebib(key)%ref%ISI_record))
461  IF (get_volume(thebib(key)%ref%ISI_record) .NE. "") THEN
462  journal = trim(journal)//", "//get_volume(thebib(key)%ref%ISI_record)
463  IF (get_issue(thebib(key)%ref%ISI_record) .NE. "") THEN
464  journal = trim(journal)//" ("//trim(get_issue(thebib(key)%ref%ISI_record))//")"
465  END IF
466  END IF
467  journal = trim(journal)//", "//get_pages(thebib(key)%ref%ISI_record)
468  IF (get_year(thebib(key)%ref%ISI_record) .NE. "") THEN
469  journal = trim(journal)//" ("//trim(get_year(thebib(key)%ref%ISI_record))//")."
470  END IF
471  WRITE (unit, '(A)', advance="NO") trim(journal)
472  IF (thebib(key)%ref%DOI .NE. "") THEN
473  WRITE (unit, '(A)', advance="NO") '</A>'
474  END IF
475  WRITE (unit, '(A)') "</A><br>"
476 
477  ! Title
478  line = 1; ititle = 0
479  title = get_next_title(thebib(key)%ref%ISI_record, line)
480  DO WHILE (title .NE. "")
481  ititle = ititle + 1
482  IF (ititle .NE. 1) WRITE (unit, '(A)') ""
483  WRITE (unit, '(T2,A)', advance="NO") trim(title)
484  title = get_next_title(thebib(key)%ref%ISI_record, line)
485  END DO
486  IF (ititle > 0) WRITE (unit, '(A)') "."
487 
488  END SUBROUTINE print_reference_html
489 
490 ! **************************************************************************************************
491 !> \brief returns the corresponding fields from an ISI record.
492 !> returns an empty string if the field can not be found
493 !> iline_start should be initialized to 1 to obtain the first matching entry
494 !> on return it is updated, so that successive calls give successive fields
495 !> \param ISI_record ...
496 !> \param iline_start ...
497 !> \return ...
498 !> \par History
499 !> 08.2007 created [Joost VandeVondele]
500 ! **************************************************************************************************
501  FUNCTION get_next_author(ISI_record, iline_start) RESULT(res)
502  CHARACTER(LEN=ISI_length), DIMENSION(:), &
503  INTENT(IN) :: isi_record
504  INTEGER, INTENT(INOUT) :: iline_start
505  CHARACTER(LEN=ISI_length) :: res
506 
507  INTEGER :: i, n
508  LOGICAL :: in_au_section
509 
510  res = ""
511  in_au_section = .false.
512  n = SIZE(isi_record, 1)
513  IF (iline_start > n) RETURN
514  line_loop: DO i = 1, n
515  IF (isi_record(i) (1:3) == "AU ") in_au_section = .true.
516  IF (in_au_section .AND. (isi_record(i) (1:3) /= "AU " .AND. isi_record(i) (1:3) /= " ")) in_au_section = .false.
517  IF (in_au_section) THEN
518  IF (i >= iline_start) THEN
519  iline_start = i + 1
520  res = isi_record(i) (4:)
521  EXIT line_loop
522  END IF
523  END IF
524  END DO line_loop
525 
526  ! We might want to fixup the initials, adding a dot after each of them
527 
528  END FUNCTION get_next_author
529 
530 ! **************************************************************************************************
531 !> \brief ...
532 !> \param ISI_record ...
533 !> \param iline_start ...
534 !> \return ...
535 ! **************************************************************************************************
536  FUNCTION get_next_title(ISI_record, iline_start) RESULT(res)
537  CHARACTER(LEN=ISI_length), DIMENSION(:), &
538  INTENT(IN) :: isi_record
539  INTEGER, INTENT(INOUT) :: iline_start
540  CHARACTER(LEN=ISI_length) :: res
541 
542  INTEGER :: i, n
543  LOGICAL :: in_ti_section
544 
545  res = ""
546 
547  in_ti_section = .false.
548  n = SIZE(isi_record, 1)
549  IF (iline_start > n) RETURN
550  line_loop: DO i = 1, n
551  IF (isi_record(i) (1:3) == "TI ") in_ti_section = .true.
552  IF (in_ti_section .AND. (isi_record(i) (1:3) /= "TI " .AND. isi_record(i) (1:3) /= " ")) in_ti_section = .false.
553  IF (in_ti_section) THEN
554  IF (i >= iline_start) THEN
555  iline_start = i + 1
556  res = isi_record(i) (4:)
557  EXIT line_loop
558  END IF
559  END IF
560  END DO line_loop
561 
562  END FUNCTION get_next_title
563 
564 ! **************************************************************************************************
565 !> \brief ...
566 !> \param ISI_record ...
567 !> \return ...
568 ! **************************************************************************************************
569  PURE FUNCTION get_source(ISI_record) RESULT(res)
570  CHARACTER(LEN=ISI_length), DIMENSION(:), &
571  INTENT(IN) :: isi_record
572  CHARACTER(LEN=4*ISI_length) :: res
573 
574  INTEGER :: i, j, n
575 
576  n = SIZE(isi_record, 1)
577  res = ""
578  DO i = 1, n
579  IF (isi_record(i) (1:3) == "SO ") THEN
580  res = isi_record(i) (4:)
581  DO j = i + 1, n
582  IF (isi_record(j) (1:3) == " ") THEN
583  res = trim(res)//" "//isi_record(j) (4:)
584  ELSE
585  EXIT
586  END IF
587  END DO
588  EXIT
589  END IF
590  END DO
591  END FUNCTION get_source
592 
593 ! **************************************************************************************************
594 !> \brief ...
595 !> \param ISI_record ...
596 !> \return ...
597 ! **************************************************************************************************
598  PURE FUNCTION get_year(ISI_record) RESULT(res)
599  CHARACTER(LEN=ISI_length), DIMENSION(:), &
600  INTENT(IN) :: isi_record
601  CHARACTER(LEN=ISI_length) :: res
602 
603  INTEGER :: i, n
604 
605  n = SIZE(isi_record, 1)
606  res = ""
607  DO i = 1, n
608  IF (isi_record(i) (1:3) == "PY ") res = isi_record(i) (4:)
609  END DO
610  END FUNCTION get_year
611 
612 ! **************************************************************************************************
613 !> \brief ...
614 !> \param ISI_record ...
615 !> \return ...
616 ! **************************************************************************************************
617  PURE FUNCTION get_month(ISI_record) RESULT(res)
618  CHARACTER(LEN=ISI_length), DIMENSION(:), &
619  INTENT(IN) :: isi_record
620  CHARACTER(LEN=ISI_length) :: res
621 
622  INTEGER :: i, n
623 
624  n = SIZE(isi_record, 1)
625  res = ""
626  DO i = 1, n
627  IF (isi_record(i) (1:3) == "PD ") res = isi_record(i) (4:6)
628  END DO
629  END FUNCTION get_month
630 
631 ! **************************************************************************************************
632 !> \brief ...
633 !> \param ISI_record ...
634 !> \return ...
635 ! **************************************************************************************************
636  PURE FUNCTION get_day(ISI_record) RESULT(res)
637  CHARACTER(LEN=ISI_length), DIMENSION(:), &
638  INTENT(IN) :: isi_record
639  CHARACTER(LEN=ISI_length) :: res
640 
641  INTEGER :: d, i, n
642 
643  n = SIZE(isi_record, 1)
644  res = ""
645  DO i = 1, n
646  IF (isi_record(i) (1:3) == "PD ") res = isi_record(i) (7:)
647  END DO
648  ! PD can be e.g. OCT-NOV or OCT or OCT 27
649  ! if res can't be read as an integer, it is not a day, and we bail out
650  READ (res, *, err=998, END=998) d
651  ! if the day is not in the expected range, we assume it is a parse error
652  IF (d < 0 .OR. d > 31) res = ""
653  RETURN
654 998 CONTINUE
655  res = ""
656  END FUNCTION get_day
657 
658 ! **************************************************************************************************
659 !> \brief ...
660 !> \param ISI_record ...
661 !> \return ...
662 ! **************************************************************************************************
663  PURE FUNCTION get_volume(ISI_record) RESULT(res)
664  CHARACTER(LEN=ISI_length), DIMENSION(:), &
665  INTENT(IN) :: isi_record
666  CHARACTER(LEN=ISI_length) :: res
667 
668  INTEGER :: i, n
669 
670  n = SIZE(isi_record, 1)
671  res = ""
672  DO i = 1, n
673  IF (isi_record(i) (1:3) == "VL ") res = isi_record(i) (4:)
674  END DO
675  END FUNCTION get_volume
676 
677 ! **************************************************************************************************
678 !> \brief ...
679 !> \param ISI_record ...
680 !> \return ...
681 ! **************************************************************************************************
682  PURE FUNCTION get_issue(ISI_record) RESULT(res)
683  CHARACTER(LEN=ISI_length), DIMENSION(:), &
684  INTENT(IN) :: isi_record
685  CHARACTER(LEN=ISI_length) :: res
686 
687  INTEGER :: i, n
688 
689  n = SIZE(isi_record, 1)
690  res = ""
691  DO i = 1, n
692  IF (isi_record(i) (1:3) == "IS ") res = isi_record(i) (4:)
693  END DO
694  END FUNCTION get_issue
695 
696 ! **************************************************************************************************
697 !> \brief ...
698 !> \param ISI_record ...
699 !> \return ...
700 ! **************************************************************************************************
701  PURE FUNCTION get_pages(ISI_record) RESULT(res)
702  CHARACTER(LEN=ISI_length), DIMENSION(:), &
703  INTENT(IN) :: isi_record
704  CHARACTER(LEN=ISI_length) :: res
705 
706  CHARACTER(LEN=ISI_length) :: ar, bp, ep
707  INTEGER :: i, n
708 
709  n = SIZE(isi_record, 1)
710  res = ""
711  bp = ""
712  ep = ""
713  ar = ""
714 
715  DO i = 1, n
716  IF (isi_record(i) (1:3) == "BP ") bp = isi_record(i) (4:)
717  IF (isi_record(i) (1:3) == "EP ") ep = isi_record(i) (4:)
718  IF (isi_record(i) (1:3) == "AR ") ar = isi_record(i) (4:)
719  END DO
720  IF (bp .NE. "") THEN
721  res = bp
722  IF (ep .NE. "") res = trim(res)//"-"//ep
723  END IF
724  IF (res .EQ. "" .AND. ar .NE. "") res = ar
725  END FUNCTION get_pages
726 
727 ! **************************************************************************************************
728 !> \brief ...
729 !> \param key ...
730 !> \return ...
731 ! **************************************************************************************************
732  PURE FUNCTION get_citation_key(key) RESULT(res)
733  INTEGER, INTENT(IN) :: key
734  CHARACTER(LEN=default_string_length) :: res
735 
736  res = thebib(key)%ref%citation_key
737  END FUNCTION get_citation_key
738 
739 !
740 ! This returns something epoch like, but can only be used to order the records
741 ! missing years, months, days are implied zero(1900)
742 !
743 ! **************************************************************************************************
744 !> \brief ...
745 !> \param ISI_record ...
746 !> \return ...
747 ! **************************************************************************************************
748  PURE FUNCTION get_epoch(ISI_record) RESULT(res)
749  CHARACTER(LEN=ISI_length), DIMENSION(:), &
750  INTENT(IN) :: isi_record
751  INTEGER :: res
752 
753  CHARACTER(LEN=ISI_length) :: tmp
754  INTEGER :: day, istat, month, year
755 
756 ! read year
757 
758  tmp = get_year(isi_record)
759  READ (tmp, *, iostat=istat) year
760  IF (istat .NE. 0) year = 1900
761 
762  ! read day
763  tmp = get_day(isi_record)
764  READ (tmp, *, iostat=istat) day
765  IF (istat .NE. 0) day = 0
766 
767  ! read month
768  tmp = get_month(isi_record)
769  SELECT CASE (tmp)
770  CASE ("JAN")
771  month = 1
772  CASE ("FEB")
773  month = 2
774  CASE ("MAR")
775  month = 3
776  CASE ("APR")
777  month = 4
778  CASE ("MAY")
779  month = 5
780  CASE ("JUN")
781  month = 6
782  CASE ("JUL")
783  month = 7
784  CASE ("AUG")
785  month = 8
786  CASE ("SEP")
787  month = 9
788  CASE ("OCT")
789  month = 10
790  CASE ("NOV")
791  month = 11
792  CASE ("DEC")
793  month = 12
794  CASE DEFAULT
795  month = 0
796  END SELECT
797 
798  res = day + 31*month + 12*31*(year - 1900)
799 
800  END FUNCTION get_epoch
801 
802 END MODULE reference_manager
Defines the basic variable types.
Definition: kinds.F:23
integer, parameter, public default_string_length
Definition: kinds.F:57
An array-based list which grows on demand. When the internal array is full, a new array of twice the ...
Definition: list.F:24
Interface to the message passing library MPI.
provides a uniform framework to add references to CP2K cite and output these
pure character(len=default_string_length) function, public get_citation_key(key)
...
subroutine, public print_all_references(cited_only, sorted, FORMAT, unit, list)
printout of all references in a specific format optionally printing only those that are actually cite...
subroutine, public remove_all_references()
deallocate the bibliography
subroutine, public add_reference(key, ISI_record, DOI)
add a reference to the bibliography
subroutine, public collect_citations_from_ranks(para_env)
Checks for each reference if any mpi-rank has marked it for citation.
subroutine, public cite_reference(key)
marks a given reference as cited.
subroutine, public print_reference(key, FORMAT, unit)
printout of a specified reference to a given unit in a selectable format
integer, parameter, public print_format_journal
integer, parameter, public print_format_html
integer, parameter, public print_format_isi
Utilities for string manipulations.
elemental subroutine, public uppercase(string)
Convert all lower case characters in a string to upper case.
All kind of helpful little routines.
Definition: util.F:14