EIRAM
atomic and molecular data in form of polynomial fits
eiram_cgi.f90
Go to the documentation of this file.
1 
40 
41 ! Copyright (c) 2016 Forschungszentrum Juelich GmbH
42 ! Markus Brenneis, Vladislav Kotov
43 !
44 ! This file is part of EIRAM.
45 !
46 ! EIRAM is free software: you can redistribute it and/or modify
47 ! it under the terms of the GNU General Public License as published by
48 ! the Free Software Foundation, either version 3 of the License, or
49 ! (at your option) any later version.
50 !
51 ! EIRAM is distributed in the hope that it will be useful,
52 ! but WITHOUT ANY WARRANTY; without even the implied warranty of
53 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54 ! GNU General Public License for more details.
55 !
56 ! You should have received a copy of the GNU General Public License
57 ! along with EIRAM. If not, see <http://www.gnu.org/licenses/>.
58 !
59 
60 program eiram_cgi
61 
62  use cgi_protocol
63  use eiram
64  implicit none
66  integer :: unit
68  type(dict_struct), pointer :: dict => null()
70  character(*), parameter :: HEADER = "Content-type: application/json; charset=utf-8"//char(10)//&
71  "Content-Disposition: attachment; filename=data.json"//char(10)
72 
73  logical, parameter :: DEBUG = .false.
74  integer, parameter :: DEBUG_UNIT = 0
75 
78  integer, parameter :: MAX_PARAM_LENGTH = 500
79  integer, parameter :: TMP_UNIT = 142
80  real(kind=EIRAM_DP) :: NEG_INF = -huge(1.d0)
81  character(MAX_PARAM_LENGTH) :: input = ""
82  character(MAX_PARAM_LENGTH), dimension(:), allocatable :: files, types, reactions, arg1s, arg2s
83  integer :: nFiles, nTypes, nReactions, nArg1s, nArg2s
84  integer :: i, err
85  real(kind=EIRAM_DP), dimension(:), allocatable :: xs, ys
86  real(kind=EIRAM_DP) :: epsfilter = 0d0
88  integer, parameter :: MAX_POINTS = 1000000
89 
90  open(tmp_unit, iostat=err, status='scratch', action='readwrite')
91  eiram_unit = tmp_unit
92  write(tmp_unit, *) "BEGIN OF LOG"
93  write(tmp_unit, *) "CGI: not initialized"
94 
95  call get_environment_variable("QUERY_STRING", input)
96  if(index(input, '=') == 0) then
98  end if
99 
100  call cgi_begin(output_no_header, dict, unit)
101 
102  call getcsvparameter(dict, "files", "no file names provided", files, nfiles)
103  call getcsvparameter(dict, "types", "no type names provided", types, ntypes)
104  call getcsvparameter(dict, "reactions", "no reaction indices provided", reactions, nreactions)
105  call getcsvparameter(dict, "arg1s", "no first arguments provided", arg1s, narg1s)
106  call getcsvparameter(dict, "arg2s", "no second arguments provided", arg2s, narg2s)
107  call cgi_get(dict, "epsfilter", epsfilter)
108 
109  if(debug) write(debug_unit, *) nfiles, files
110  if(debug) write(debug_unit, *) ntypes, types
111  if(debug) write(debug_unit, *) nreactions, reactions
112  if(debug) write(debug_unit, *) narg1s, arg1s
113  if(debug) write(debug_unit, *) narg2s, arg2s
114 
115  if(.not.all((/nfiles, ntypes, nreactions, narg1s/) == narg2s)) then
116  call cgi_error("esputr_cgi: all lists must have the same length")
117  end if
118 
119  write(unit, '(A)') header
120 
121  call initallfiles()
122  write(unit, '(A)'), "["
123  do i = 1, nfiles
124  if(i > 1) then
125  write(unit, '(A)'), ","
126  end if
127  call getpoints(files(i), types(i), reactions(i), arg1s(i), arg2s(i), xs, ys)
128  write(unit, '(A)') trim(pointstojsonstring(files(i), types(i), reactions(i), xs, ys))
129  deallocate(xs, ys)
130  end do
131  write(unit, '(A)'), "]"
132 
133  call eiram_deallocate(err)
134  call cgi_end()
135 
136  contains
137 
139  subroutine getpoints(fileName, reactionType, reactionIndex, arg1s_str, arg2s_str, xs, ys)
141  character(*), intent(in) :: fileName
143  character(*), intent(in) :: reactionType
145  character(*), intent(in) :: reactionIndex
147  character(*), intent(in) :: arg1s_str
150  character(*), intent(in) :: arg2s_str
152  real(kind=EIRAM_DP), allocatable, intent(out) :: xs(:)
154  real(kind=EIRAM_DP), allocatable, intent(out) :: ys(:)
155  real(kind=EIRAM_DP), allocatable :: ys0(:)
156  real(kind=EIRAM_DP), allocatable :: arg1s(:), arg2s(:)
157  logical,allocatable :: filterMask(:)
158  integer :: err,n,i,lastITaken
159 
160  intrinsic pack,size
161 
165 
166  err = 0
167 
168  call parsevector(arg1s_str, arg1s)
169  call parsevector(arg2s_str, arg2s)
170  if(size(arg2s) == 0 .or. size(arg1s) == 0) call cgi_error("esputr_cgi: invalid input vectors")
171 
172  if(arg2s(1) <= neg_inf) then
173  allocate(ys0(size(arg1s)), stat=err)
174  if(err /= 0) call cgi_error("esputr_cgi: memory allocation error"//getlastmessage())
175  call eiram_matlab_calc1(ys0,arg1s, size(arg1s), filename, reactiontype, reactionindex, err)
176  if(err /= 0) call cgi_error("esputr_cgi: error while calculating values"//getlastmessage())
177  else
178  allocate(ys0(size(arg2s)), stat=err)
179  if(err /= 0) call cgi_error("esputr_cgi: memory allocation error"//getlastmessage())
180  call eiram_matlab_calc2(ys0, arg1s(1), arg2s, 1, size(arg2s), filename, reactiontype, reactionindex, err)
181  if(err /= 0) call cgi_error("esputr_cgi: error while calculating values"//getlastmessage())
182  end if
183 
184  n=size(ys0)
185  allocate(filtermask(n),stat=err)
186  if(err /= 0) call cgi_error("esputr_cgi: memory allocation error"//getlastmessage())
187 
188  filtermask(1) = .true.
189  lastitaken = 1
190  do i = 2, n-1
191  filtermask(i) = abs(ys0(i)-ys0(lastitaken)) > .5*epsfilter*(abs(ys0(i))+abs(ys0(lastitaken)))
192  if(filtermask(i)) lastitaken = i
193  end do
194  filtermask(n) = .true.
195 
196  n=count(filtermask)
197  if(allocated(xs)) deallocate(xs)
198  if(allocated(ys)) deallocate(ys)
199  allocate(xs(n),ys(n),stat=err)
200  if(err /= 0) call cgi_error("esputr_cgi: memory allocation error"//getlastmessage())
201  if(arg2s(1) <= neg_inf) then
202  xs=pack(arg1s,filtermask)
203  else
204  xs=pack(arg2s,filtermask)
205  end if
206  ys=pack(ys0,filtermask)
207 
208  deallocate(arg1s,arg2s,filtermask,ys0)
209 
210  end subroutine getpoints
211 
213  function pointstojsonstring(fileName, reactionType, reactionIndex, xs, ys)
214  use json
216  character(*), intent(in) :: fileName
218  character(*), intent(in) :: reactionType
220  character(*), intent(in) :: reactionIndex
222  real(kind=EIRAM_DP), dimension(:), intent(in) :: xs
224  real(kind=EIRAM_DP), dimension(:), intent(in) :: ys
225  character(150+2*(14*size(xs)+2)) :: pointsToJsonString
226  integer :: c, l
227  pointstojsonstring(1:1) = "{"
228  c = 2
229 
230  pointstojsonstring(c:c+3) = '"x":'
231  c = c+4
232  write(pointstojsonstring(c:), '(A)') eiram_json_getarrayasjson(xs, l, 5)
233  c = c+l
234 
235  pointstojsonstring(c:c+4) = ',"y":'
236  c = c+5
237  write(pointstojsonstring(c:), '(A)') eiram_json_getarrayasjson(ys, l, 5)
238  c = c+l
239 
240  call eiram_json_writejsonstringproperty("file", filename, pointstojsonstring, c)
241  call eiram_json_writejsonstringproperty("type", reactiontype, pointstojsonstring, c)
242  call eiram_json_writejsonstringproperty("index", reactionindex, pointstojsonstring, c)
243 
244  pointstojsonstring(c:c) = "}"
245  c = c+1
246  end function pointstojsonstring
247 
249  subroutine getcsvparameter(dict, parameterName, errMsg, values, nValues)
251  type(dict_struct), pointer, intent(in) :: dict
253  character(*), intent(in) :: parameterName
255  character(*), intent(in) :: errMsg
257  character(MAX_PARAM_LENGTH), dimension(:), allocatable, intent(inout) :: values
259  integer, intent(out) :: nValues
260  character(DICT_VALUE_LENGTH) :: input = ""
261  call cgi_get(dict, parametername, input)
262  if(input == "") call cgi_error("esputr_cgi: "//errmsg)
263  call split(input, ",", values)
264  nvalues = size(values)
265  end subroutine
266 
268  subroutine sendavailablereactions()
269  integer :: err,i,N
270  type(eiram_data),allocatable :: REACTIONS(:)
271 
272  unit = 6
273 
274  call initallfiles()
275 
276  err=0
277  call eiram_create_image(reactions,err)
278  if(err /= 0) then
279  call cgi_error("esputr_cgi: cannot create the list of reactions")
280  return
281  end if
282 
283  n=size(reactions)
284  write(unit, '(A)') header
285  write(unit, '(A)') trim(getreactionsasjson(reactions,n,err))
286 
287  if(err /= 0) call cgi_error("eiram_cgi: error while getting combinations "//getlastmessage())
288 
289  do i=1,n
290  deallocate(reactions(i)%creac)
291  end do
292  deallocate(reactions)
293 
294  call eiram_deallocate(err)
295  call cgi_end()
296  end subroutine sendavailablereactions
297 
299  subroutine initallfiles()
300  call eiram_load("../data/", "H2VIBR", err)
301  if(err /= 0) call cgi_error("eiram_cgi: initialization from H2VIBR failed"//getlastmessage())
302  call eiram_load("../data/", "METHANE", err)
303  if(err /= 0) call cgi_error("eiram_cgi: initialization from METHANE failed"//getlastmessage())
304  call eiram_load("../data/", "AMJUEL", err)
305  if(err /= 0) call cgi_error("eiram_cgi: initialization from AMJUEL failed"//getlastmessage())
306  call eiram_load("../data/", "HYDHEL", err)
307  if(err /= 0) call cgi_error("eiram_cgi: initialization from HYDHEL failed"//getlastmessage())
308  end subroutine initallfiles
309 
311  character(DICT_VALUE_LENGTH*2) function getlastmessage()
313  backspace(tmp_unit, iostat=err)
314  backspace(tmp_unit, iostat=err)
315  read(tmp_unit, '(A)') getlastmessage(1:dict_value_length)
316  read(tmp_unit, '(A)') getlastmessage(len_trim(getlastmessage)+1:dict_value_length*2)
317  end function
318 
320  subroutine split(string, c, array)
322  character(*), intent(in) :: string
324  character(1), intent(in) :: c
325  character(MAX_PARAM_LENGTH), dimension(:), allocatable, intent(out) :: array
326  integer :: nSeps, i
327  character(DICT_VALUE_LENGTH) :: str
328  str = string
329  nseps = count(transfer(str, 'a', dict_value_length) == c)
330  allocate(array(nseps + 1))
331  if(c /= ',') then
332  do i=1, len(str)
333  if(str(i:i) == c) then
334  str(i:i) = ","
335  end if
336  end do
337  end if
338  read(str, *) array(1:nseps+1)
339  end subroutine split
340 
342  subroutine parsevector(strArr, realArr)
345  character(*), intent(in) :: strArr
346  real(kind=EIRAM_DP), dimension(:), allocatable, intent(out) :: realArr
347  character(MAX_PARAM_LENGTH), dimension(:), allocatable :: strArrSplit
348  real(kind=EIRAM_DP) :: start, delta, ende
349  integer :: i, err, nValues
350 
351  if(allocated(realarr)) deallocate(realarr)
352 
353  if(strarr == "-") then
354  allocate(realarr(1))
355  realarr(1) = neg_inf
356  return
357  end if
358 
359  if(allocated(strarrsplit)) deallocate(strarrsplit)
360  call split(strarr, ":", strarrsplit)
361  select case(size(strarrsplit))
362  case (1)
363  allocate(realarr(1))
364  read(strarrsplit(1), *, iostat=err) realarr(1)
365  if(err/=0) call cgi_error("esputr_cgi: invalid real value "//strarrsplit(1))
366  return
367  case (2)
368  read(strarrsplit(1), *, iostat=err) start
369  if(err/=0) call cgi_error("esputr_cgi: invalid real value "//strarrsplit(1))
370  read(strarrsplit(2), *, iostat=err) ende
371  if(err/=0) call cgi_error("esputr_cgi: invalid real value "//strarrsplit(2))
372  delta = 1d0
373  case (3)
374  read(strarrsplit(1), *, iostat=err) start
375  if(err/=0) call cgi_error("esputr_cgi: invalid real value "//strarrsplit(1))
376  read(strarrsplit(2), *, iostat=err) delta
377  if(err/=0) call cgi_error("esputr_cgi: invalid real value "//strarrsplit(2))
378  read(strarrsplit(3), *, iostat=err) ende
379  if(err/=0) call cgi_error("esputr_cgi: invalid real value "//strarrsplit(3))
380  case default
381  call cgi_error("esputr_cgi: invalid vector format "//strarr)
382  end select
383  nvalues = floor((ende-start)/delta) + 1
384  if(nvalues>max_points) then
385  call cgi_error("eiram_cgi: too many data points are requested")
386  end if
387  allocate(realarr(nvalues))
388  realarr = (/ ( start + i*delta, i = 0, nvalues-1 ) /)
389  end subroutine
390 
393  function getreactionsasjson(REACTIONS,N,err)
394  use json
395  character(1024*N) :: getReactionsAsJson
396  type(eiram_data),intent(in) :: REACTIONS(n)
397  integer,intent(in) :: N
398  character(EIRAM_FILE_NAME_LENGTH) :: lastFileName
399  character(EIRAM_TYPE_LENGTH) :: lastTypeName
400  integer, intent(out) :: err
401  integer :: r, c, l, m
402 
403  err=0
404 
405  lastfilename = ""
406  lasttypename = ""
407  getreactionsasjson(1:10) = '{"files":['
408  c = 11
409  foreachreaction: do r = 1, size(reactions)
410 
411  if(lastfilename /= reactions(r)%FILE) then
412  if(lastfilename /= "") then
413  getreactionsasjson(c:c+4) = "]}]},"
414  c = c+5
415  end if
416  lastfilename = reactions(r)%FILE
417  lasttypename = ""
418  getreactionsasjson(c:c+8) = '{"name":"'
419  c = c+9
420  getreactionsasjson(c:) = trim(reactions(r)%FILE)
421  c = c+len_trim(reactions(r)%FILE)
422  getreactionsasjson(c:c+10) = '","types":['
423  c = c+11
424  end if
425  if(lasttypename /= reactions(r)%TYPE) then
426  if(lasttypename /= "") then
427  getreactionsasjson(c:c+2) = "]},"
428  c = c+3
429  end if
430  lasttypename = reactions(r)%TYPE
431  getreactionsasjson(c:c+8) = '{"name":"'
432  c = c+9
433  getreactionsasjson(c:) = trim(reactions(r)%TYPE)
434  c = c+len_trim(reactions(r)%TYPE)
435  getreactionsasjson(c:c) = '"'
436  c = c+1
437 
438  call eiram_json_writejsonstringproperty("yUnit", reactions(r)%YUNITS, getreactionsasjson, c)
439  call eiram_json_writejsonstringproperty("yQuantity", reactions(r)%YQUANTITY, getreactionsasjson, c)
440 
441  getreactionsasjson(c:c+11) = ',"xUnits":["'
442  c = c+12
443  getreactionsasjson(c:) = reactions(r)%X1UNITS
444  c = c+len_trim(reactions(r)%X1UNITS)
445  if(reactions(r)%M > 0) then
446  getreactionsasjson(c:c+2) = '","'
447  c = c+3
448  getreactionsasjson(c:) = reactions(r)%X2UNITS
449  c = c+len_trim(reactions(r)%X2UNITS)
450  end if
451  getreactionsasjson(c:c+1) = '"]'
452  c = c+2
453 
454  getreactionsasjson(c:c+16) = ',"xQuantities":["'
455  c = c+17
456  getreactionsasjson(c:) = reactions(r)%X1QUANTITY
457  c = c+len_trim(reactions(r)%X1QUANTITY)
458  if(reactions(r)%M > 0) then
459  getreactionsasjson(c:c+2) = '","'
460  c = c+3
461  getreactionsasjson(c:) = reactions(r)%X2QUANTITY
462  c = c+len_trim(reactions(r)%X2QUANTITY)
463  end if
464  getreactionsasjson(c:c+1) = '"]'
465  c = c+2
466 
467  getreactionsasjson(c:c+4) = ',"n":'
468  c = c+5
469  write(getreactionsasjson(c:c+1), '(I2)') reactions(r)%N
470  c = c+2
471 
472  getreactionsasjson(c:c+4) = ',"m":'
473  c = c+5
474  write(getreactionsasjson(c:c+2), '(I2)') reactions(r)%M
475  c = c+2
476 
477  getreactionsasjson(c:c+13) = ',"reactions":['
478  c = c+14
479  else if(r > 1) then
480  getreactionsasjson(c:c) = ","
481  c = c+1
482  end if
483  getreactionsasjson(c:c) = "{"
484  c = c+1
485 
486  write(getreactionsasjson(c:c+7), '(A)') '"creac":'
487  c = c+8
488  if(allocated(reactions(r)%CREAC)) then
489  if(reactions(r)%M == 0) then
490  write(getreactionsasjson(c:), '(A)') eiram_json_getarrayasjson(reactions(r)%CREAC(:,0), l, 12)
491  c = c+l
492  else
493  write(getreactionsasjson(c:), '(A)') '['
494  c = c+1
495  do m = 0, reactions(r)%M
496  if(m > 0) then
497  getreactionsasjson(c:c) = ","
498  c = c+1
499  end if
500  write(getreactionsasjson(c:), '(A)') eiram_json_getarrayasjson(reactions(r)%CREAC(:,m), l, 12)
501  c = c+l
502  end do
503  write(getreactionsasjson(c:), '(A)') ']'
504  c = c+1
505  end if
506  else
507  write(getreactionsasjson(c:c+3), '(A)') "null"
508  c = c+4
509  end if
510 
511  call eiram_json_writejsonstringproperty("equation", reactions(r)%REACTION, getreactionsasjson, c)
512  call eiram_json_writejsonstringproperty("index", reactions(r)%INDEX, getreactionsasjson, c)
513 
514  getreactionsasjson(c:c+1) = "}"//char(10)
515  c = c+2
516 
517  end do foreachreaction
518 
519  getreactionsasjson(c:c+5) = "]}]}]}"
520  c = c + 6
521 
522  if(debug) print *, c, "/", len(getreactionsasjson), "chars written"
523  end function getreactionsasjson
524 
525 end program eiram_cgi
subroutine cgi_end
subroutine cgi_error(msg, template)
integer, public eiram_unit
Unit to which messages are written.
Definition: eiram.f90:112
integer, parameter output_no_header
subroutine, public eiram_load(filePath, fileName, err)
Initialization of the module from input files (data sets)
Definition: eiram.f90:206
subroutine, public eiram_deallocate(err)
Deallocate dynamic arrays used by this module.
Definition: eiram.f90:585
Definition: json.f90:26
subroutine getcsvparameter(dict, parameterName, errMsg, values, nValues)
Parse values of a comma separated CGI parameter.
Definition: eiram_cgi.f90:250
subroutine sendavailablereactions()
Send the list of all available reactions to the server.
Definition: eiram_cgi.f90:269
Data for one reaction.
Definition: eiram.f90:142
subroutine getpoints(fileName, reactionType, reactionIndex, arg1s_str, arg2s_str, xs, ys)
Calculate the points for the given reaction and arguments.
Definition: eiram_cgi.f90:140
subroutine cgi_begin(html, dict, luout)
subroutine initallfiles()
Initialize EIRAM with all available data.
Definition: eiram_cgi.f90:300
subroutine eiram_matlab_calc2(Y, X1, X2, M, N, fileName, reactionType, reactionIndex, err)
Binding for eiram_calc2 which has to be called from Matlab/Octave interface.
subroutine split(string, c, array)
Split one line into individual strings for each comma separated substring.
Definition: eiram_cgi.f90:321
subroutine, public eiram_json_writejsonstringproperty(name, value, jsonString, ind)
Write a pair of the JSON property-(string-)values into a string, including leading comma...
Definition: json.f90:94
character(1024 *n) function getreactionsasjson(REACTIONS, N, err)
Transfer reactions stored in the arrays REACTIONS into a string which represents a JSON (JavaScript O...
Definition: eiram_cgi.f90:394
subroutine parsevector(strArr, realArr)
Converts octave-like string vector representation into an array of reals.
Definition: eiram_cgi.f90:343
program eiram_cgi
Definition: eiram_cgi.f90:60
Definition: eiram.f90:96
subroutine, public eiram_create_image(data, err)
Create a copy (image) of the reactions array stored in the module.
Definition: eiram.f90:931
character(dict_value_length *2) function getlastmessage()
Return two last lines printed into the temporary output unit.
Definition: eiram_cgi.f90:312
subroutine eiram_matlab_calc1(Y, X, N, fileName, reactionType, reactionIndex, err)
Binding for eiram_calc1 which has to be called from Matlab/Octave interface.
integer, parameter dict_value_length
character(size(arr)*(itol+9)+2) function, public eiram_json_getarrayasjson(arr, length, itol)
Return a JSON array string (ie. "[…]") with the elements of the given array arr. ...
Definition: json.f90:36
character(150+2 *(14 *size(xs)+2)) function pointstojsonstring(fileName, reactionType, reactionIndex, xs, ys)
Return a string which represents a JSON object suitable for plotting of the given reaction data...
Definition: eiram_cgi.f90:214